]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
e43e00df0323996115b193bd2cf4236add2a6734
[mandoc.git] / mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.222 2014/07/02 19:55:10 schwarze Exp $ */
2 /*
3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2014 Ingo Schwarze <schwarze@openbsd.org>
5 * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #ifndef OSNAME
24 #include <sys/utsname.h>
25 #endif
26
27 #include <sys/types.h>
28
29 #include <assert.h>
30 #include <ctype.h>
31 #include <limits.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <time.h>
36
37 #include "mdoc.h"
38 #include "mandoc.h"
39 #include "mandoc_aux.h"
40 #include "libmdoc.h"
41 #include "libmandoc.h"
42
43 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
44
45 #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
46 #define POST_ARGS struct mdoc *mdoc
47
48 enum check_ineq {
49 CHECK_LT,
50 CHECK_GT,
51 CHECK_EQ
52 };
53
54 enum check_lvl {
55 CHECK_WARN,
56 CHECK_ERROR,
57 };
58
59 typedef int (*v_pre)(PRE_ARGS);
60 typedef int (*v_post)(POST_ARGS);
61
62 struct valids {
63 v_pre *pre;
64 v_post *post;
65 };
66
67 static int check_count(struct mdoc *, enum mdoc_type,
68 enum check_lvl, enum check_ineq, int);
69 static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type);
70 static void check_text(struct mdoc *, int, int, char *);
71 static void check_argv(struct mdoc *,
72 struct mdoc_node *, struct mdoc_argv *);
73 static void check_args(struct mdoc *, struct mdoc_node *);
74 static enum mdoc_sec a2sec(const char *);
75 static size_t macro2len(enum mdoct);
76
77 static int ebool(POST_ARGS);
78 static int berr_ge1(POST_ARGS);
79 static int bwarn_ge1(POST_ARGS);
80 static int ewarn_eq0(POST_ARGS);
81 static int ewarn_eq1(POST_ARGS);
82 static int ewarn_ge1(POST_ARGS);
83 static int ewarn_le1(POST_ARGS);
84 static int hwarn_eq0(POST_ARGS);
85 static int hwarn_eq1(POST_ARGS);
86 static int hwarn_ge1(POST_ARGS);
87 static int hwarn_le1(POST_ARGS);
88
89 static int post_an(POST_ARGS);
90 static int post_at(POST_ARGS);
91 static int post_bf(POST_ARGS);
92 static int post_bl(POST_ARGS);
93 static int post_bl_block(POST_ARGS);
94 static int post_bl_block_width(POST_ARGS);
95 static int post_bl_block_tag(POST_ARGS);
96 static int post_bl_head(POST_ARGS);
97 static int post_bx(POST_ARGS);
98 static int post_defaults(POST_ARGS);
99 static int post_dd(POST_ARGS);
100 static int post_dt(POST_ARGS);
101 static int post_en(POST_ARGS);
102 static int post_es(POST_ARGS);
103 static int post_eoln(POST_ARGS);
104 static int post_hyph(POST_ARGS);
105 static int post_ignpar(POST_ARGS);
106 static int post_it(POST_ARGS);
107 static int post_lb(POST_ARGS);
108 static int post_literal(POST_ARGS);
109 static int post_nm(POST_ARGS);
110 static int post_ns(POST_ARGS);
111 static int post_os(POST_ARGS);
112 static int post_par(POST_ARGS);
113 static int post_prol(POST_ARGS);
114 static int post_root(POST_ARGS);
115 static int post_rs(POST_ARGS);
116 static int post_sh(POST_ARGS);
117 static int post_sh_body(POST_ARGS);
118 static int post_sh_head(POST_ARGS);
119 static int post_st(POST_ARGS);
120 static int post_std(POST_ARGS);
121 static int post_vt(POST_ARGS);
122 static int pre_an(PRE_ARGS);
123 static int pre_bd(PRE_ARGS);
124 static int pre_bl(PRE_ARGS);
125 static int pre_dd(PRE_ARGS);
126 static int pre_display(PRE_ARGS);
127 static int pre_dt(PRE_ARGS);
128 static int pre_it(PRE_ARGS);
129 static int pre_literal(PRE_ARGS);
130 static int pre_obsolete(PRE_ARGS);
131 static int pre_os(PRE_ARGS);
132 static int pre_par(PRE_ARGS);
133 static int pre_sh(PRE_ARGS);
134 static int pre_ss(PRE_ARGS);
135 static int pre_std(PRE_ARGS);
136
137 static v_post posts_an[] = { post_an, NULL };
138 static v_post posts_at[] = { post_at, post_defaults, NULL };
139 static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
140 static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
141 static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
142 static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
143 static v_post posts_bx[] = { post_bx, NULL };
144 static v_post posts_bool[] = { ebool, NULL };
145 static v_post posts_eoln[] = { post_eoln, NULL };
146 static v_post posts_defaults[] = { post_defaults, NULL };
147 static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL };
148 static v_post posts_dd[] = { post_dd, post_prol, NULL };
149 static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
150 static v_post posts_dt[] = { post_dt, post_prol, NULL };
151 static v_post posts_en[] = { post_en, NULL };
152 static v_post posts_es[] = { post_es, NULL };
153 static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
154 static v_post posts_hyph[] = { post_hyph, NULL };
155 static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL };
156 static v_post posts_it[] = { post_it, NULL };
157 static v_post posts_lb[] = { post_lb, NULL };
158 static v_post posts_nd[] = { berr_ge1, post_hyph, NULL };
159 static v_post posts_nm[] = { post_nm, NULL };
160 static v_post posts_notext[] = { ewarn_eq0, NULL };
161 static v_post posts_ns[] = { post_ns, NULL };
162 static v_post posts_os[] = { post_os, post_prol, NULL };
163 static v_post posts_pp[] = { post_par, ewarn_eq0, NULL };
164 static v_post posts_rs[] = { post_rs, NULL };
165 static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL };
166 static v_post posts_sp[] = { post_par, ewarn_le1, NULL };
167 static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL };
168 static v_post posts_st[] = { post_st, NULL };
169 static v_post posts_std[] = { post_std, NULL };
170 static v_post posts_text[] = { ewarn_ge1, NULL };
171 static v_post posts_text1[] = { ewarn_eq1, NULL };
172 static v_post posts_vt[] = { post_vt, NULL };
173 static v_pre pres_an[] = { pre_an, NULL };
174 static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
175 static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
176 static v_pre pres_d1[] = { pre_display, NULL };
177 static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
178 static v_pre pres_dd[] = { pre_dd, NULL };
179 static v_pre pres_dt[] = { pre_dt, NULL };
180 static v_pre pres_it[] = { pre_it, pre_par, NULL };
181 static v_pre pres_obsolete[] = { pre_obsolete, NULL };
182 static v_pre pres_os[] = { pre_os, NULL };
183 static v_pre pres_pp[] = { pre_par, NULL };
184 static v_pre pres_sh[] = { pre_sh, NULL };
185 static v_pre pres_ss[] = { pre_ss, NULL };
186 static v_pre pres_std[] = { pre_std, NULL };
187
188 static const struct valids mdoc_valids[MDOC_MAX] = {
189 { NULL, NULL }, /* Ap */
190 { pres_dd, posts_dd }, /* Dd */
191 { pres_dt, posts_dt }, /* Dt */
192 { pres_os, posts_os }, /* Os */
193 { pres_sh, posts_sh }, /* Sh */
194 { pres_ss, posts_ss }, /* Ss */
195 { pres_pp, posts_pp }, /* Pp */
196 { pres_d1, posts_d1 }, /* D1 */
197 { pres_dl, posts_dl }, /* Dl */
198 { pres_bd, posts_bd }, /* Bd */
199 { NULL, NULL }, /* Ed */
200 { pres_bl, posts_bl }, /* Bl */
201 { NULL, NULL }, /* El */
202 { pres_it, posts_it }, /* It */
203 { NULL, NULL }, /* Ad */
204 { pres_an, posts_an }, /* An */
205 { NULL, posts_defaults }, /* Ar */
206 { NULL, NULL }, /* Cd */
207 { NULL, NULL }, /* Cm */
208 { NULL, NULL }, /* Dv */
209 { NULL, NULL }, /* Er */
210 { NULL, NULL }, /* Ev */
211 { pres_std, posts_std }, /* Ex */
212 { NULL, NULL }, /* Fa */
213 { NULL, posts_text }, /* Fd */
214 { NULL, NULL }, /* Fl */
215 { NULL, NULL }, /* Fn */
216 { NULL, NULL }, /* Ft */
217 { NULL, NULL }, /* Ic */
218 { NULL, posts_text1 }, /* In */
219 { NULL, posts_defaults }, /* Li */
220 { NULL, posts_nd }, /* Nd */
221 { NULL, posts_nm }, /* Nm */
222 { NULL, NULL }, /* Op */
223 { pres_obsolete, NULL }, /* Ot */
224 { NULL, posts_defaults }, /* Pa */
225 { pres_std, posts_std }, /* Rv */
226 { NULL, posts_st }, /* St */
227 { NULL, NULL }, /* Va */
228 { NULL, posts_vt }, /* Vt */
229 { NULL, posts_text }, /* Xr */
230 { NULL, posts_text }, /* %A */
231 { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
232 { NULL, posts_text }, /* %D */
233 { NULL, posts_text }, /* %I */
234 { NULL, posts_text }, /* %J */
235 { NULL, posts_hyphtext }, /* %N */
236 { NULL, posts_hyphtext }, /* %O */
237 { NULL, posts_text }, /* %P */
238 { NULL, posts_hyphtext }, /* %R */
239 { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
240 { NULL, posts_text }, /* %V */
241 { NULL, NULL }, /* Ac */
242 { NULL, NULL }, /* Ao */
243 { NULL, NULL }, /* Aq */
244 { NULL, posts_at }, /* At */
245 { NULL, NULL }, /* Bc */
246 { NULL, posts_bf }, /* Bf */
247 { NULL, NULL }, /* Bo */
248 { NULL, NULL }, /* Bq */
249 { NULL, NULL }, /* Bsx */
250 { NULL, posts_bx }, /* Bx */
251 { NULL, posts_bool }, /* Db */
252 { NULL, NULL }, /* Dc */
253 { NULL, NULL }, /* Do */
254 { NULL, NULL }, /* Dq */
255 { NULL, NULL }, /* Ec */
256 { NULL, NULL }, /* Ef */
257 { NULL, NULL }, /* Em */
258 { NULL, NULL }, /* Eo */
259 { NULL, NULL }, /* Fx */
260 { NULL, NULL }, /* Ms */
261 { NULL, posts_notext }, /* No */
262 { NULL, posts_ns }, /* Ns */
263 { NULL, NULL }, /* Nx */
264 { NULL, NULL }, /* Ox */
265 { NULL, NULL }, /* Pc */
266 { NULL, posts_text1 }, /* Pf */
267 { NULL, NULL }, /* Po */
268 { NULL, NULL }, /* Pq */
269 { NULL, NULL }, /* Qc */
270 { NULL, NULL }, /* Ql */
271 { NULL, NULL }, /* Qo */
272 { NULL, NULL }, /* Qq */
273 { NULL, NULL }, /* Re */
274 { NULL, posts_rs }, /* Rs */
275 { NULL, NULL }, /* Sc */
276 { NULL, NULL }, /* So */
277 { NULL, NULL }, /* Sq */
278 { NULL, posts_bool }, /* Sm */
279 { NULL, posts_hyph }, /* Sx */
280 { NULL, NULL }, /* Sy */
281 { NULL, NULL }, /* Tn */
282 { NULL, NULL }, /* Ux */
283 { NULL, NULL }, /* Xc */
284 { NULL, NULL }, /* Xo */
285 { NULL, posts_fo }, /* Fo */
286 { NULL, NULL }, /* Fc */
287 { NULL, NULL }, /* Oo */
288 { NULL, NULL }, /* Oc */
289 { NULL, posts_bk }, /* Bk */
290 { NULL, NULL }, /* Ek */
291 { NULL, posts_eoln }, /* Bt */
292 { NULL, NULL }, /* Hf */
293 { pres_obsolete, NULL }, /* Fr */
294 { NULL, posts_eoln }, /* Ud */
295 { NULL, posts_lb }, /* Lb */
296 { pres_pp, posts_pp }, /* Lp */
297 { NULL, NULL }, /* Lk */
298 { NULL, posts_defaults }, /* Mt */
299 { NULL, NULL }, /* Brq */
300 { NULL, NULL }, /* Bro */
301 { NULL, NULL }, /* Brc */
302 { NULL, posts_text }, /* %C */
303 { pres_obsolete, posts_es }, /* Es */
304 { pres_obsolete, posts_en }, /* En */
305 { NULL, NULL }, /* Dx */
306 { NULL, posts_text }, /* %Q */
307 { NULL, posts_pp }, /* br */
308 { NULL, posts_sp }, /* sp */
309 { NULL, posts_text1 }, /* %U */
310 { NULL, NULL }, /* Ta */
311 { NULL, NULL }, /* ll */
312 };
313
314 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
315
316 static const enum mdoct rsord[RSORD_MAX] = {
317 MDOC__A,
318 MDOC__T,
319 MDOC__B,
320 MDOC__I,
321 MDOC__J,
322 MDOC__R,
323 MDOC__N,
324 MDOC__V,
325 MDOC__U,
326 MDOC__P,
327 MDOC__Q,
328 MDOC__C,
329 MDOC__D,
330 MDOC__O
331 };
332
333 static const char * const secnames[SEC__MAX] = {
334 NULL,
335 "NAME",
336 "LIBRARY",
337 "SYNOPSIS",
338 "DESCRIPTION",
339 "CONTEXT",
340 "IMPLEMENTATION NOTES",
341 "RETURN VALUES",
342 "ENVIRONMENT",
343 "FILES",
344 "EXIT STATUS",
345 "EXAMPLES",
346 "DIAGNOSTICS",
347 "COMPATIBILITY",
348 "ERRORS",
349 "SEE ALSO",
350 "STANDARDS",
351 "HISTORY",
352 "AUTHORS",
353 "CAVEATS",
354 "BUGS",
355 "SECURITY CONSIDERATIONS",
356 NULL
357 };
358
359
360 int
361 mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
362 {
363 v_pre *p;
364 int line, pos;
365 char *tp;
366
367 switch (n->type) {
368 case MDOC_TEXT:
369 tp = n->string;
370 line = n->line;
371 pos = n->pos;
372 check_text(mdoc, line, pos, tp);
373 /* FALLTHROUGH */
374 case MDOC_TBL:
375 /* FALLTHROUGH */
376 case MDOC_EQN:
377 /* FALLTHROUGH */
378 case MDOC_ROOT:
379 return(1);
380 default:
381 break;
382 }
383
384 check_args(mdoc, n);
385
386 if (NULL == mdoc_valids[n->tok].pre)
387 return(1);
388 for (p = mdoc_valids[n->tok].pre; *p; p++)
389 if ( ! (*p)(mdoc, n))
390 return(0);
391 return(1);
392 }
393
394 int
395 mdoc_valid_post(struct mdoc *mdoc)
396 {
397 v_post *p;
398
399 if (MDOC_VALID & mdoc->last->flags)
400 return(1);
401 mdoc->last->flags |= MDOC_VALID;
402
403 switch (mdoc->last->type) {
404 case MDOC_TEXT:
405 /* FALLTHROUGH */
406 case MDOC_EQN:
407 /* FALLTHROUGH */
408 case MDOC_TBL:
409 return(1);
410 case MDOC_ROOT:
411 return(post_root(mdoc));
412 default:
413 break;
414 }
415
416 if (NULL == mdoc_valids[mdoc->last->tok].post)
417 return(1);
418 for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
419 if ( ! (*p)(mdoc))
420 return(0);
421
422 return(1);
423 }
424
425 static int
426 check_count(struct mdoc *mdoc, enum mdoc_type type,
427 enum check_lvl lvl, enum check_ineq ineq, int val)
428 {
429 const char *p;
430 enum mandocerr t;
431
432 if (mdoc->last->type != type)
433 return(1);
434
435 switch (ineq) {
436 case CHECK_LT:
437 p = "less than ";
438 if (mdoc->last->nchild < val)
439 return(1);
440 break;
441 case CHECK_GT:
442 p = "more than ";
443 if (mdoc->last->nchild > val)
444 return(1);
445 break;
446 case CHECK_EQ:
447 p = "";
448 if (val == mdoc->last->nchild)
449 return(1);
450 break;
451 default:
452 abort();
453 /* NOTREACHED */
454 }
455
456 t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
457 mandoc_vmsg(t, mdoc->parse, mdoc->last->line,
458 mdoc->last->pos, "want %s%d children (have %d)",
459 p, val, mdoc->last->nchild);
460 return(1);
461 }
462
463 static int
464 berr_ge1(POST_ARGS)
465 {
466
467 return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
468 }
469
470 static int
471 bwarn_ge1(POST_ARGS)
472 {
473 return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
474 }
475
476 static int
477 ewarn_eq0(POST_ARGS)
478 {
479 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
480 }
481
482 static int
483 ewarn_eq1(POST_ARGS)
484 {
485 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1));
486 }
487
488 static int
489 ewarn_ge1(POST_ARGS)
490 {
491 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
492 }
493
494 static int
495 ewarn_le1(POST_ARGS)
496 {
497 return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2));
498 }
499
500 static int
501 hwarn_eq0(POST_ARGS)
502 {
503 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0));
504 }
505
506 static int
507 hwarn_eq1(POST_ARGS)
508 {
509 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
510 }
511
512 static int
513 hwarn_ge1(POST_ARGS)
514 {
515 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
516 }
517
518 static int
519 hwarn_le1(POST_ARGS)
520 {
521 return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
522 }
523
524 static void
525 check_args(struct mdoc *mdoc, struct mdoc_node *n)
526 {
527 int i;
528
529 if (NULL == n->args)
530 return;
531
532 assert(n->args->argc);
533 for (i = 0; i < (int)n->args->argc; i++)
534 check_argv(mdoc, n, &n->args->argv[i]);
535 }
536
537 static void
538 check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
539 {
540 int i;
541
542 for (i = 0; i < (int)v->sz; i++)
543 check_text(mdoc, v->line, v->pos, v->value[i]);
544
545 /* FIXME: move to post_std(). */
546
547 if (MDOC_Std == v->arg)
548 if ( ! (v->sz || mdoc->meta.name))
549 mdoc_nmsg(mdoc, n, MANDOCERR_NONAME);
550 }
551
552 static void
553 check_text(struct mdoc *mdoc, int ln, int pos, char *p)
554 {
555 char *cp;
556
557 if (MDOC_LITERAL & mdoc->flags)
558 return;
559
560 for (cp = p; NULL != (p = strchr(p, '\t')); p++)
561 mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
562 }
563
564 static int
565 check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
566 {
567
568 assert(n->parent);
569 if ((MDOC_ROOT == t || tok == n->parent->tok) &&
570 (t == n->parent->type))
571 return(1);
572
573 mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse,
574 n->line, n->pos, "want parent %s",
575 MDOC_ROOT == t ? "<root>" : mdoc_macronames[tok]);
576 return(0);
577 }
578
579
580 static int
581 pre_display(PRE_ARGS)
582 {
583 struct mdoc_node *node;
584
585 if (MDOC_BLOCK != n->type)
586 return(1);
587
588 for (node = mdoc->last->parent; node; node = node->parent)
589 if (MDOC_BLOCK == node->type)
590 if (MDOC_Bd == node->tok)
591 break;
592
593 if (node)
594 mandoc_vmsg(MANDOCERR_BD_NEST,
595 mdoc->parse, n->line, n->pos,
596 "%s in Bd", mdoc_macronames[n->tok]);
597
598 return(1);
599 }
600
601 static int
602 pre_bl(PRE_ARGS)
603 {
604 int i, comp, dup;
605 const char *offs, *width;
606 enum mdoc_list lt;
607 struct mdoc_node *np;
608
609 if (MDOC_BLOCK != n->type) {
610 if (ENDBODY_NOT != n->end) {
611 assert(n->pending);
612 np = n->pending->parent;
613 } else
614 np = n->parent;
615
616 assert(np);
617 assert(MDOC_BLOCK == np->type);
618 assert(MDOC_Bl == np->tok);
619 return(1);
620 }
621
622 /*
623 * First figure out which kind of list to use: bind ourselves to
624 * the first mentioned list type and warn about any remaining
625 * ones. If we find no list type, we default to LIST_item.
626 */
627
628 for (i = 0; n->args && i < (int)n->args->argc; i++) {
629 lt = LIST__NONE;
630 dup = comp = 0;
631 width = offs = NULL;
632 switch (n->args->argv[i].arg) {
633 /* Set list types. */
634 case MDOC_Bullet:
635 lt = LIST_bullet;
636 break;
637 case MDOC_Dash:
638 lt = LIST_dash;
639 break;
640 case MDOC_Enum:
641 lt = LIST_enum;
642 break;
643 case MDOC_Hyphen:
644 lt = LIST_hyphen;
645 break;
646 case MDOC_Item:
647 lt = LIST_item;
648 break;
649 case MDOC_Tag:
650 lt = LIST_tag;
651 break;
652 case MDOC_Diag:
653 lt = LIST_diag;
654 break;
655 case MDOC_Hang:
656 lt = LIST_hang;
657 break;
658 case MDOC_Ohang:
659 lt = LIST_ohang;
660 break;
661 case MDOC_Inset:
662 lt = LIST_inset;
663 break;
664 case MDOC_Column:
665 lt = LIST_column;
666 break;
667 /* Set list arguments. */
668 case MDOC_Compact:
669 dup = n->norm->Bl.comp;
670 comp = 1;
671 break;
672 case MDOC_Width:
673 /* NB: this can be empty! */
674 if (n->args->argv[i].sz) {
675 width = n->args->argv[i].value[0];
676 dup = (NULL != n->norm->Bl.width);
677 break;
678 }
679 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
680 break;
681 case MDOC_Offset:
682 /* NB: this can be empty! */
683 if (n->args->argv[i].sz) {
684 offs = n->args->argv[i].value[0];
685 dup = (NULL != n->norm->Bl.offs);
686 break;
687 }
688 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
689 break;
690 default:
691 continue;
692 }
693
694 /* Check: duplicate auxiliary arguments. */
695
696 if (dup)
697 mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
698
699 if (comp && ! dup)
700 n->norm->Bl.comp = comp;
701 if (offs && ! dup)
702 n->norm->Bl.offs = offs;
703 if (width && ! dup)
704 n->norm->Bl.width = width;
705
706 /* Check: multiple list types. */
707
708 if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE)
709 mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP);
710
711 /* Assign list type. */
712
713 if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) {
714 n->norm->Bl.type = lt;
715 /* Set column information, too. */
716 if (LIST_column == lt) {
717 n->norm->Bl.ncols =
718 n->args->argv[i].sz;
719 n->norm->Bl.cols = (void *)
720 n->args->argv[i].value;
721 }
722 }
723
724 /* The list type should come first. */
725
726 if (n->norm->Bl.type == LIST__NONE)
727 if (n->norm->Bl.width ||
728 n->norm->Bl.offs ||
729 n->norm->Bl.comp)
730 mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
731
732 continue;
733 }
734
735 /* Allow lists to default to LIST_item. */
736
737 if (LIST__NONE == n->norm->Bl.type) {
738 mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
739 n->norm->Bl.type = LIST_item;
740 }
741
742 /*
743 * Validate the width field. Some list types don't need width
744 * types and should be warned about them. Others should have it
745 * and must also be warned. Yet others have a default and need
746 * no warning.
747 */
748
749 switch (n->norm->Bl.type) {
750 case LIST_tag:
751 if (NULL == n->norm->Bl.width)
752 mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
753 break;
754 case LIST_column:
755 /* FALLTHROUGH */
756 case LIST_diag:
757 /* FALLTHROUGH */
758 case LIST_ohang:
759 /* FALLTHROUGH */
760 case LIST_inset:
761 /* FALLTHROUGH */
762 case LIST_item:
763 if (n->norm->Bl.width)
764 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
765 break;
766 case LIST_bullet:
767 /* FALLTHROUGH */
768 case LIST_dash:
769 /* FALLTHROUGH */
770 case LIST_hyphen:
771 if (NULL == n->norm->Bl.width)
772 n->norm->Bl.width = "2n";
773 break;
774 case LIST_enum:
775 if (NULL == n->norm->Bl.width)
776 n->norm->Bl.width = "3n";
777 break;
778 default:
779 break;
780 }
781
782 return(1);
783 }
784
785 static int
786 pre_bd(PRE_ARGS)
787 {
788 int i, dup, comp;
789 enum mdoc_disp dt;
790 const char *offs;
791 struct mdoc_node *np;
792
793 if (MDOC_BLOCK != n->type) {
794 if (ENDBODY_NOT != n->end) {
795 assert(n->pending);
796 np = n->pending->parent;
797 } else
798 np = n->parent;
799
800 assert(np);
801 assert(MDOC_BLOCK == np->type);
802 assert(MDOC_Bd == np->tok);
803 return(1);
804 }
805
806 for (i = 0; n->args && i < (int)n->args->argc; i++) {
807 dt = DISP__NONE;
808 dup = comp = 0;
809 offs = NULL;
810
811 switch (n->args->argv[i].arg) {
812 case MDOC_Centred:
813 dt = DISP_centred;
814 break;
815 case MDOC_Ragged:
816 dt = DISP_ragged;
817 break;
818 case MDOC_Unfilled:
819 dt = DISP_unfilled;
820 break;
821 case MDOC_Filled:
822 dt = DISP_filled;
823 break;
824 case MDOC_Literal:
825 dt = DISP_literal;
826 break;
827 case MDOC_File:
828 mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
829 return(0);
830 case MDOC_Offset:
831 /* NB: this can be empty! */
832 if (n->args->argv[i].sz) {
833 offs = n->args->argv[i].value[0];
834 dup = (NULL != n->norm->Bd.offs);
835 break;
836 }
837 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
838 break;
839 case MDOC_Compact:
840 comp = 1;
841 dup = n->norm->Bd.comp;
842 break;
843 default:
844 abort();
845 /* NOTREACHED */
846 }
847
848 /* Check whether we have duplicates. */
849
850 if (dup)
851 mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
852
853 /* Make our auxiliary assignments. */
854
855 if (offs && ! dup)
856 n->norm->Bd.offs = offs;
857 if (comp && ! dup)
858 n->norm->Bd.comp = comp;
859
860 /* Check whether a type has already been assigned. */
861
862 if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
863 mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
864
865 /* Make our type assignment. */
866
867 if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
868 n->norm->Bd.type = dt;
869 }
870
871 if (DISP__NONE == n->norm->Bd.type) {
872 mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
873 n->norm->Bd.type = DISP_ragged;
874 }
875
876 return(1);
877 }
878
879 static int
880 pre_ss(PRE_ARGS)
881 {
882
883 if (MDOC_BLOCK != n->type)
884 return(1);
885 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
886 }
887
888 static int
889 pre_sh(PRE_ARGS)
890 {
891
892 if (MDOC_BLOCK != n->type)
893 return(1);
894 return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
895 }
896
897 static int
898 pre_it(PRE_ARGS)
899 {
900
901 if (MDOC_BLOCK != n->type)
902 return(1);
903
904 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
905 }
906
907 static int
908 pre_an(PRE_ARGS)
909 {
910 int i;
911
912 if (NULL == n->args)
913 return(1);
914
915 for (i = 1; i < (int)n->args->argc; i++)
916 mdoc_pmsg(mdoc, n->args->argv[i].line,
917 n->args->argv[i].pos, MANDOCERR_IGNARGV);
918
919 if (MDOC_Split == n->args->argv[0].arg)
920 n->norm->An.auth = AUTH_split;
921 else if (MDOC_Nosplit == n->args->argv[0].arg)
922 n->norm->An.auth = AUTH_nosplit;
923 else
924 abort();
925
926 return(1);
927 }
928
929 static int
930 pre_std(PRE_ARGS)
931 {
932
933 if (n->args && 1 == n->args->argc)
934 if (MDOC_Std == n->args->argv[0].arg)
935 return(1);
936
937 mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV);
938 return(1);
939 }
940
941 static int
942 pre_obsolete(PRE_ARGS)
943 {
944
945 if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type)
946 mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
947 n->line, n->pos, mdoc_macronames[n->tok]);
948 return(1);
949 }
950
951 static int
952 pre_dt(PRE_ARGS)
953 {
954
955 if (NULL == mdoc->meta.date || mdoc->meta.os)
956 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
957 n->line, n->pos, "Dt");
958
959 if (mdoc->meta.title)
960 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
961 n->line, n->pos, "Dt");
962
963 return(1);
964 }
965
966 static int
967 pre_os(PRE_ARGS)
968 {
969
970 if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
971 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
972 n->line, n->pos, "Os");
973
974 if (mdoc->meta.os)
975 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
976 n->line, n->pos, "Os");
977
978 return(1);
979 }
980
981 static int
982 pre_dd(PRE_ARGS)
983 {
984
985 if (mdoc->meta.title || mdoc->meta.os)
986 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
987 n->line, n->pos, "Dd");
988
989 if (mdoc->meta.date)
990 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
991 n->line, n->pos, "Dd");
992
993 return(1);
994 }
995
996 static int
997 post_bf(POST_ARGS)
998 {
999 struct mdoc_node *np;
1000 enum mdocargt arg;
1001
1002 /*
1003 * Unlike other data pointers, these are "housed" by the HEAD
1004 * element, which contains the goods.
1005 */
1006
1007 if (MDOC_HEAD != mdoc->last->type) {
1008 if (ENDBODY_NOT != mdoc->last->end) {
1009 assert(mdoc->last->pending);
1010 np = mdoc->last->pending->parent->head;
1011 } else if (MDOC_BLOCK != mdoc->last->type) {
1012 np = mdoc->last->parent->head;
1013 } else
1014 np = mdoc->last->head;
1015
1016 assert(np);
1017 assert(MDOC_HEAD == np->type);
1018 assert(MDOC_Bf == np->tok);
1019 return(1);
1020 }
1021
1022 np = mdoc->last;
1023 assert(MDOC_BLOCK == np->parent->type);
1024 assert(MDOC_Bf == np->parent->tok);
1025
1026 /*
1027 * Cannot have both argument and parameter.
1028 * If neither is specified, let it through with a warning.
1029 */
1030
1031 if (np->parent->args && np->child) {
1032 mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
1033 return(0);
1034 } else if (NULL == np->parent->args && NULL == np->child) {
1035 mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1036 return(1);
1037 }
1038
1039 /* Extract argument into data. */
1040
1041 if (np->parent->args) {
1042 arg = np->parent->args->argv[0].arg;
1043 if (MDOC_Emphasis == arg)
1044 np->norm->Bf.font = FONT_Em;
1045 else if (MDOC_Literal == arg)
1046 np->norm->Bf.font = FONT_Li;
1047 else if (MDOC_Symbolic == arg)
1048 np->norm->Bf.font = FONT_Sy;
1049 else
1050 abort();
1051 return(1);
1052 }
1053
1054 /* Extract parameter into data. */
1055
1056 if (0 == strcmp(np->child->string, "Em"))
1057 np->norm->Bf.font = FONT_Em;
1058 else if (0 == strcmp(np->child->string, "Li"))
1059 np->norm->Bf.font = FONT_Li;
1060 else if (0 == strcmp(np->child->string, "Sy"))
1061 np->norm->Bf.font = FONT_Sy;
1062 else
1063 mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1064
1065 return(1);
1066 }
1067
1068 static int
1069 post_lb(POST_ARGS)
1070 {
1071 struct mdoc_node *n;
1072 const char *stdlibname;
1073 char *libname;
1074
1075 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1076
1077 n = mdoc->last->child;
1078
1079 assert(n);
1080 assert(MDOC_TEXT == n->type);
1081
1082 if (NULL == (stdlibname = mdoc_a2lib(n->string)))
1083 mandoc_asprintf(&libname,
1084 "library \\(lq%s\\(rq", n->string);
1085 else
1086 libname = mandoc_strdup(stdlibname);
1087
1088 free(n->string);
1089 n->string = libname;
1090 return(1);
1091 }
1092
1093 static int
1094 post_eoln(POST_ARGS)
1095 {
1096
1097 if (mdoc->last->child)
1098 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1099 return(1);
1100 }
1101
1102 static int
1103 post_vt(POST_ARGS)
1104 {
1105 const struct mdoc_node *n;
1106
1107 /*
1108 * The Vt macro comes in both ELEM and BLOCK form, both of which
1109 * have different syntaxes (yet more context-sensitive
1110 * behaviour). ELEM types must have a child, which is already
1111 * guaranteed by the in_line parsing routine; BLOCK types,
1112 * specifically the BODY, should only have TEXT children.
1113 */
1114
1115 if (MDOC_BODY != mdoc->last->type)
1116 return(1);
1117
1118 for (n = mdoc->last->child; n; n = n->next)
1119 if (MDOC_TEXT != n->type)
1120 mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse,
1121 n->line, n->pos, mdoc_macronames[n->tok]);
1122
1123 return(1);
1124 }
1125
1126 static int
1127 post_nm(POST_ARGS)
1128 {
1129
1130 if (NULL != mdoc->meta.name)
1131 return(1);
1132
1133 mdoc_deroff(&mdoc->meta.name, mdoc->last);
1134
1135 if (NULL == mdoc->meta.name) {
1136 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1137 mdoc->meta.name = mandoc_strdup("UNKNOWN");
1138 }
1139 return(1);
1140 }
1141
1142 static int
1143 post_literal(POST_ARGS)
1144 {
1145
1146 /*
1147 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1148 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1149 * this in literal mode, but it doesn't hurt to just switch it
1150 * off in general since displays can't be nested.
1151 */
1152
1153 if (MDOC_BODY == mdoc->last->type)
1154 mdoc->flags &= ~MDOC_LITERAL;
1155
1156 return(1);
1157 }
1158
1159 static int
1160 post_defaults(POST_ARGS)
1161 {
1162 struct mdoc_node *nn;
1163
1164 /*
1165 * The `Ar' defaults to "file ..." if no value is provided as an
1166 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1167 * gets an empty string.
1168 */
1169
1170 if (mdoc->last->child)
1171 return(1);
1172
1173 nn = mdoc->last;
1174 mdoc->next = MDOC_NEXT_CHILD;
1175
1176 switch (nn->tok) {
1177 case MDOC_Ar:
1178 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
1179 return(0);
1180 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
1181 return(0);
1182 break;
1183 case MDOC_At:
1184 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T"))
1185 return(0);
1186 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX"))
1187 return(0);
1188 break;
1189 case MDOC_Li:
1190 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
1191 return(0);
1192 break;
1193 case MDOC_Pa:
1194 /* FALLTHROUGH */
1195 case MDOC_Mt:
1196 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
1197 return(0);
1198 break;
1199 default:
1200 abort();
1201 /* NOTREACHED */
1202 }
1203
1204 mdoc->last = nn;
1205 return(1);
1206 }
1207
1208 static int
1209 post_at(POST_ARGS)
1210 {
1211 struct mdoc_node *n;
1212 const char *std_att;
1213 char *att;
1214
1215 /*
1216 * If we have a child, look it up in the standard keys. If a
1217 * key exist, use that instead of the child; if it doesn't,
1218 * prefix "AT&T UNIX " to the existing data.
1219 */
1220
1221 if (NULL == (n = mdoc->last->child))
1222 return(1);
1223
1224 assert(MDOC_TEXT == n->type);
1225 if (NULL == (std_att = mdoc_a2att(n->string))) {
1226 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
1227 mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
1228 } else
1229 att = mandoc_strdup(std_att);
1230
1231 free(n->string);
1232 n->string = att;
1233 return(1);
1234 }
1235
1236 static int
1237 post_an(POST_ARGS)
1238 {
1239 struct mdoc_node *np;
1240
1241 np = mdoc->last;
1242 if (AUTH__NONE == np->norm->An.auth) {
1243 if (0 == np->child)
1244 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
1245 } else if (np->child)
1246 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
1247
1248 return(1);
1249 }
1250
1251 static int
1252 post_en(POST_ARGS)
1253 {
1254
1255 if (MDOC_BLOCK == mdoc->last->type)
1256 mdoc->last->norm->Es = mdoc->last_es;
1257 return(1);
1258 }
1259
1260 static int
1261 post_es(POST_ARGS)
1262 {
1263
1264 mdoc->last_es = mdoc->last;
1265 return(1);
1266 }
1267
1268 static int
1269 post_it(POST_ARGS)
1270 {
1271 int i, cols;
1272 enum mdoc_list lt;
1273 struct mdoc_node *n, *c;
1274 enum mandocerr er;
1275
1276 if (MDOC_BLOCK != mdoc->last->type)
1277 return(1);
1278
1279 n = mdoc->last->parent->parent;
1280 lt = n->norm->Bl.type;
1281
1282 if (LIST__NONE == lt) {
1283 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
1284 return(1);
1285 }
1286
1287 switch (lt) {
1288 case LIST_tag:
1289 if (mdoc->last->head->child)
1290 break;
1291 /* FIXME: give this a dummy value. */
1292 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1293 break;
1294 case LIST_hang:
1295 /* FALLTHROUGH */
1296 case LIST_ohang:
1297 /* FALLTHROUGH */
1298 case LIST_inset:
1299 /* FALLTHROUGH */
1300 case LIST_diag:
1301 if (NULL == mdoc->last->head->child)
1302 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1303 break;
1304 case LIST_bullet:
1305 /* FALLTHROUGH */
1306 case LIST_dash:
1307 /* FALLTHROUGH */
1308 case LIST_enum:
1309 /* FALLTHROUGH */
1310 case LIST_hyphen:
1311 if (NULL == mdoc->last->body->child)
1312 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1313 /* FALLTHROUGH */
1314 case LIST_item:
1315 if (mdoc->last->head->child)
1316 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1317 break;
1318 case LIST_column:
1319 cols = (int)n->norm->Bl.ncols;
1320
1321 assert(NULL == mdoc->last->head->child);
1322
1323 if (NULL == mdoc->last->body->child)
1324 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1325
1326 for (i = 0, c = mdoc->last->child; c; c = c->next)
1327 if (MDOC_BODY == c->type)
1328 i++;
1329
1330 if (i < cols)
1331 er = MANDOCERR_ARGCOUNT;
1332 else if (i == cols || i == cols + 1)
1333 break;
1334 else
1335 er = MANDOCERR_SYNTARGCOUNT;
1336
1337 mandoc_vmsg(er, mdoc->parse,
1338 mdoc->last->line, mdoc->last->pos,
1339 "columns == %d (have %d)", cols, i);
1340 return(MANDOCERR_ARGCOUNT == er);
1341 default:
1342 break;
1343 }
1344
1345 return(1);
1346 }
1347
1348 static int
1349 post_bl_block(POST_ARGS)
1350 {
1351 struct mdoc_node *n, *ni, *nc;
1352
1353 /*
1354 * These are fairly complicated, so we've broken them into two
1355 * functions. post_bl_block_tag() is called when a -tag is
1356 * specified, but no -width (it must be guessed). The second
1357 * when a -width is specified (macro indicators must be
1358 * rewritten into real lengths).
1359 */
1360
1361 n = mdoc->last;
1362
1363 if (LIST_tag == n->norm->Bl.type &&
1364 NULL == n->norm->Bl.width) {
1365 if ( ! post_bl_block_tag(mdoc))
1366 return(0);
1367 assert(n->norm->Bl.width);
1368 } else if (NULL != n->norm->Bl.width) {
1369 if ( ! post_bl_block_width(mdoc))
1370 return(0);
1371 assert(n->norm->Bl.width);
1372 }
1373
1374 for (ni = n->body->child; ni; ni = ni->next) {
1375 if (NULL == ni->body)
1376 continue;
1377 nc = ni->body->last;
1378 while (NULL != nc) {
1379 switch (nc->tok) {
1380 case MDOC_Pp:
1381 /* FALLTHROUGH */
1382 case MDOC_Lp:
1383 /* FALLTHROUGH */
1384 case MDOC_br:
1385 break;
1386 default:
1387 nc = NULL;
1388 continue;
1389 }
1390 if (NULL == ni->next) {
1391 mandoc_msg(MANDOCERR_PAR_MOVE,
1392 mdoc->parse, nc->line, nc->pos,
1393 mdoc_macronames[nc->tok]);
1394 if ( ! mdoc_node_relink(mdoc, nc))
1395 return(0);
1396 } else if (0 == n->norm->Bl.comp &&
1397 LIST_column != n->norm->Bl.type) {
1398 mandoc_vmsg(MANDOCERR_PAR_SKIP,
1399 mdoc->parse, nc->line, nc->pos,
1400 "%s before It",
1401 mdoc_macronames[nc->tok]);
1402 mdoc_node_delete(mdoc, nc);
1403 } else
1404 break;
1405 nc = ni->body->last;
1406 }
1407 }
1408 return(1);
1409 }
1410
1411 static int
1412 post_bl_block_width(POST_ARGS)
1413 {
1414 size_t width;
1415 int i;
1416 enum mdoct tok;
1417 struct mdoc_node *n;
1418 char buf[24];
1419
1420 n = mdoc->last;
1421
1422 /*
1423 * Calculate the real width of a list from the -width string,
1424 * which may contain a macro (with a known default width), a
1425 * literal string, or a scaling width.
1426 *
1427 * If the value to -width is a macro, then we re-write it to be
1428 * the macro's width as set in share/tmac/mdoc/doc-common.
1429 */
1430
1431 if (0 == strcmp(n->norm->Bl.width, "Ds"))
1432 width = 6;
1433 else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
1434 return(1);
1435 else if (0 == (width = macro2len(tok))) {
1436 mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
1437 return(1);
1438 }
1439
1440 /* The value already exists: free and reallocate it. */
1441
1442 assert(n->args);
1443
1444 for (i = 0; i < (int)n->args->argc; i++)
1445 if (MDOC_Width == n->args->argv[i].arg)
1446 break;
1447
1448 assert(i < (int)n->args->argc);
1449
1450 (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)width);
1451 free(n->args->argv[i].value[0]);
1452 n->args->argv[i].value[0] = mandoc_strdup(buf);
1453
1454 /* Set our width! */
1455 n->norm->Bl.width = n->args->argv[i].value[0];
1456 return(1);
1457 }
1458
1459 static int
1460 post_bl_block_tag(POST_ARGS)
1461 {
1462 struct mdoc_node *n, *nn;
1463 size_t sz, ssz;
1464 int i;
1465 char buf[24];
1466
1467 /*
1468 * Calculate the -width for a `Bl -tag' list if it hasn't been
1469 * provided. Uses the first head macro. NOTE AGAIN: this is
1470 * ONLY if the -width argument has NOT been provided. See
1471 * post_bl_block_width() for converting the -width string.
1472 */
1473
1474 sz = 10;
1475 n = mdoc->last;
1476
1477 for (nn = n->body->child; nn; nn = nn->next) {
1478 if (MDOC_It != nn->tok)
1479 continue;
1480
1481 assert(MDOC_BLOCK == nn->type);
1482 nn = nn->head->child;
1483
1484 if (nn == NULL)
1485 break;
1486
1487 if (MDOC_TEXT == nn->type) {
1488 sz = strlen(nn->string) + 1;
1489 break;
1490 }
1491
1492 if (0 != (ssz = macro2len(nn->tok)))
1493 sz = ssz;
1494
1495 break;
1496 }
1497
1498 /* Defaults to ten ens. */
1499
1500 (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
1501
1502 /*
1503 * We have to dynamically add this to the macro's argument list.
1504 * We're guaranteed that a MDOC_Width doesn't already exist.
1505 */
1506
1507 assert(n->args);
1508 i = (int)(n->args->argc)++;
1509
1510 n->args->argv = mandoc_reallocarray(n->args->argv,
1511 n->args->argc, sizeof(struct mdoc_argv));
1512
1513 n->args->argv[i].arg = MDOC_Width;
1514 n->args->argv[i].line = n->line;
1515 n->args->argv[i].pos = n->pos;
1516 n->args->argv[i].sz = 1;
1517 n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1518 n->args->argv[i].value[0] = mandoc_strdup(buf);
1519
1520 /* Set our width! */
1521 n->norm->Bl.width = n->args->argv[i].value[0];
1522 return(1);
1523 }
1524
1525 static int
1526 post_bl_head(POST_ARGS)
1527 {
1528 struct mdoc_node *np, *nn, *nnp;
1529 int i, j;
1530
1531 if (LIST_column != mdoc->last->norm->Bl.type)
1532 /* FIXME: this should be ERROR class... */
1533 return(hwarn_eq0(mdoc));
1534
1535 /*
1536 * Convert old-style lists, where the column width specifiers
1537 * trail as macro parameters, to the new-style ("normal-form")
1538 * lists where they're argument values following -column.
1539 */
1540
1541 /* First, disallow both types and allow normal-form. */
1542
1543 /*
1544 * TODO: technically, we can accept both and just merge the two
1545 * lists, but I'll leave that for another day.
1546 */
1547
1548 if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
1549 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
1550 return(0);
1551 } else if (NULL == mdoc->last->child)
1552 return(1);
1553
1554 np = mdoc->last->parent;
1555 assert(np->args);
1556
1557 for (j = 0; j < (int)np->args->argc; j++)
1558 if (MDOC_Column == np->args->argv[j].arg)
1559 break;
1560
1561 assert(j < (int)np->args->argc);
1562 assert(0 == np->args->argv[j].sz);
1563
1564 /*
1565 * Accommodate for new-style groff column syntax. Shuffle the
1566 * child nodes, all of which must be TEXT, as arguments for the
1567 * column field. Then, delete the head children.
1568 */
1569
1570 np->args->argv[j].sz = (size_t)mdoc->last->nchild;
1571 np->args->argv[j].value = mandoc_reallocarray(NULL,
1572 (size_t)mdoc->last->nchild, sizeof(char *));
1573
1574 mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
1575 mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1576
1577 for (i = 0, nn = mdoc->last->child; nn; i++) {
1578 np->args->argv[j].value[i] = nn->string;
1579 nn->string = NULL;
1580 nnp = nn;
1581 nn = nn->next;
1582 mdoc_node_delete(NULL, nnp);
1583 }
1584
1585 mdoc->last->nchild = 0;
1586 mdoc->last->child = NULL;
1587
1588 return(1);
1589 }
1590
1591 static int
1592 post_bl(POST_ARGS)
1593 {
1594 struct mdoc_node *nparent, *nprev; /* of the Bl block */
1595 struct mdoc_node *nblock, *nbody; /* of the Bl */
1596 struct mdoc_node *nchild, *nnext; /* of the Bl body */
1597
1598 nbody = mdoc->last;
1599 switch (nbody->type) {
1600 case MDOC_BLOCK:
1601 return(post_bl_block(mdoc));
1602 case MDOC_HEAD:
1603 return(post_bl_head(mdoc));
1604 case MDOC_BODY:
1605 break;
1606 default:
1607 return(1);
1608 }
1609
1610 nchild = nbody->child;
1611 while (NULL != nchild) {
1612 if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
1613 nchild = nchild->next;
1614 continue;
1615 }
1616
1617 mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
1618 nchild->line, nchild->pos,
1619 mdoc_macronames[nchild->tok]);
1620
1621 /*
1622 * Move the node out of the Bl block.
1623 * First, collect all required node pointers.
1624 */
1625
1626 nblock = nbody->parent;
1627 nprev = nblock->prev;
1628 nparent = nblock->parent;
1629 nnext = nchild->next;
1630
1631 /*
1632 * Unlink this child.
1633 */
1634
1635 assert(NULL == nchild->prev);
1636 if (0 == --nbody->nchild) {
1637 nbody->child = NULL;
1638 nbody->last = NULL;
1639 assert(NULL == nnext);
1640 } else {
1641 nbody->child = nnext;
1642 nnext->prev = NULL;
1643 }
1644
1645 /*
1646 * Relink this child.
1647 */
1648
1649 nchild->parent = nparent;
1650 nchild->prev = nprev;
1651 nchild->next = nblock;
1652
1653 nblock->prev = nchild;
1654 nparent->nchild++;
1655 if (NULL == nprev)
1656 nparent->child = nchild;
1657 else
1658 nprev->next = nchild;
1659
1660 nchild = nnext;
1661 }
1662
1663 return(1);
1664 }
1665
1666 static int
1667 ebool(struct mdoc *mdoc)
1668 {
1669
1670 if (NULL == mdoc->last->child) {
1671 if (MDOC_Sm == mdoc->last->tok)
1672 mdoc->flags ^= MDOC_SMOFF;
1673 return(1);
1674 }
1675
1676 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2);
1677
1678 assert(MDOC_TEXT == mdoc->last->child->type);
1679
1680 if (0 == strcmp(mdoc->last->child->string, "on")) {
1681 if (MDOC_Sm == mdoc->last->tok)
1682 mdoc->flags &= ~MDOC_SMOFF;
1683 return(1);
1684 }
1685 if (0 == strcmp(mdoc->last->child->string, "off")) {
1686 if (MDOC_Sm == mdoc->last->tok)
1687 mdoc->flags |= MDOC_SMOFF;
1688 return(1);
1689 }
1690
1691 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1692 return(1);
1693 }
1694
1695 static int
1696 post_root(POST_ARGS)
1697 {
1698 int ret;
1699 struct mdoc_node *n;
1700
1701 ret = 1;
1702
1703 /* Check that we have a finished prologue. */
1704
1705 if ( ! (MDOC_PBODY & mdoc->flags)) {
1706 ret = 0;
1707 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1708 }
1709
1710 n = mdoc->first;
1711 assert(n);
1712
1713 /* Check that we begin with a proper `Sh'. */
1714
1715 if (NULL == n->child)
1716 mdoc_nmsg(mdoc, n, MANDOCERR_DOC_EMPTY);
1717 else if (MDOC_Sh != n->child->tok)
1718 mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
1719 n->child->line, n->child->pos,
1720 mdoc_macronames[n->child->tok]);
1721
1722 return(ret);
1723 }
1724
1725 static int
1726 post_st(POST_ARGS)
1727 {
1728 struct mdoc_node *ch;
1729 const char *p;
1730
1731 if (NULL == (ch = mdoc->last->child)) {
1732 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1733 mdoc_node_delete(mdoc, mdoc->last);
1734 return(1);
1735 }
1736
1737 assert(MDOC_TEXT == ch->type);
1738
1739 if (NULL == (p = mdoc_a2st(ch->string))) {
1740 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
1741 mdoc_node_delete(mdoc, mdoc->last);
1742 } else {
1743 free(ch->string);
1744 ch->string = mandoc_strdup(p);
1745 }
1746
1747 return(1);
1748 }
1749
1750 static int
1751 post_rs(POST_ARGS)
1752 {
1753 struct mdoc_node *nn, *next, *prev;
1754 int i, j;
1755
1756 switch (mdoc->last->type) {
1757 case MDOC_HEAD:
1758 check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
1759 return(1);
1760 case MDOC_BODY:
1761 if (mdoc->last->child)
1762 break;
1763 check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
1764 return(1);
1765 default:
1766 return(1);
1767 }
1768
1769 /*
1770 * Make sure only certain types of nodes are allowed within the
1771 * the `Rs' body. Delete offending nodes and raise a warning.
1772 * Do this before re-ordering for the sake of clarity.
1773 */
1774
1775 next = NULL;
1776 for (nn = mdoc->last->child; nn; nn = next) {
1777 for (i = 0; i < RSORD_MAX; i++)
1778 if (nn->tok == rsord[i])
1779 break;
1780
1781 if (i < RSORD_MAX) {
1782 if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
1783 mdoc->last->norm->Rs.quote_T++;
1784 next = nn->next;
1785 continue;
1786 }
1787
1788 next = nn->next;
1789 mandoc_msg(MANDOCERR_RS_SKIP, mdoc->parse,
1790 nn->line, nn->pos, mdoc_macronames[nn->tok]);
1791 mdoc_node_delete(mdoc, nn);
1792 }
1793
1794 /*
1795 * Nothing to sort if only invalid nodes were found
1796 * inside the `Rs' body.
1797 */
1798
1799 if (NULL == mdoc->last->child)
1800 return(1);
1801
1802 /*
1803 * The full `Rs' block needs special handling to order the
1804 * sub-elements according to `rsord'. Pick through each element
1805 * and correctly order it. This is a insertion sort.
1806 */
1807
1808 next = NULL;
1809 for (nn = mdoc->last->child->next; nn; nn = next) {
1810 /* Determine order of `nn'. */
1811 for (i = 0; i < RSORD_MAX; i++)
1812 if (rsord[i] == nn->tok)
1813 break;
1814
1815 /*
1816 * Remove `nn' from the chain. This somewhat
1817 * repeats mdoc_node_unlink(), but since we're
1818 * just re-ordering, there's no need for the
1819 * full unlink process.
1820 */
1821
1822 if (NULL != (next = nn->next))
1823 next->prev = nn->prev;
1824
1825 if (NULL != (prev = nn->prev))
1826 prev->next = nn->next;
1827
1828 nn->prev = nn->next = NULL;
1829
1830 /*
1831 * Scan back until we reach a node that's
1832 * ordered before `nn'.
1833 */
1834
1835 for ( ; prev ; prev = prev->prev) {
1836 /* Determine order of `prev'. */
1837 for (j = 0; j < RSORD_MAX; j++)
1838 if (rsord[j] == prev->tok)
1839 break;
1840
1841 if (j <= i)
1842 break;
1843 }
1844
1845 /*
1846 * Set `nn' back into its correct place in front
1847 * of the `prev' node.
1848 */
1849
1850 nn->prev = prev;
1851
1852 if (prev) {
1853 if (prev->next)
1854 prev->next->prev = nn;
1855 nn->next = prev->next;
1856 prev->next = nn;
1857 } else {
1858 mdoc->last->child->prev = nn;
1859 nn->next = mdoc->last->child;
1860 mdoc->last->child = nn;
1861 }
1862 }
1863
1864 return(1);
1865 }
1866
1867 /*
1868 * For some arguments of some macros,
1869 * convert all breakable hyphens into ASCII_HYPH.
1870 */
1871 static int
1872 post_hyph(POST_ARGS)
1873 {
1874 struct mdoc_node *n, *nch;
1875 char *cp;
1876
1877 n = mdoc->last;
1878 switch (n->type) {
1879 case MDOC_HEAD:
1880 if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
1881 break;
1882 return(1);
1883 case MDOC_BODY:
1884 if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
1885 break;
1886 return(1);
1887 case MDOC_ELEM:
1888 break;
1889 default:
1890 return(1);
1891 }
1892
1893 for (nch = n->child; nch; nch = nch->next) {
1894 if (MDOC_TEXT != nch->type)
1895 continue;
1896 cp = nch->string;
1897 if ('\0' == *cp)
1898 continue;
1899 while ('\0' != *(++cp))
1900 if ('-' == *cp &&
1901 isalpha((unsigned char)cp[-1]) &&
1902 isalpha((unsigned char)cp[1]))
1903 *cp = ASCII_HYPH;
1904 }
1905 return(1);
1906 }
1907
1908 static int
1909 post_ns(POST_ARGS)
1910 {
1911
1912 if (MDOC_LINE & mdoc->last->flags)
1913 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NS_SKIP);
1914 return(1);
1915 }
1916
1917 static int
1918 post_sh(POST_ARGS)
1919 {
1920
1921 if (MDOC_HEAD == mdoc->last->type)
1922 return(post_sh_head(mdoc));
1923 if (MDOC_BODY == mdoc->last->type)
1924 return(post_sh_body(mdoc));
1925
1926 return(1);
1927 }
1928
1929 static int
1930 post_sh_body(POST_ARGS)
1931 {
1932 struct mdoc_node *n;
1933
1934 if (SEC_NAME != mdoc->lastsec)
1935 return(1);
1936
1937 /*
1938 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1939 * macros (can have multiple `Nm' and one `Nd'). Note that the
1940 * children of the BODY declaration can also be "text".
1941 */
1942
1943 if (NULL == (n = mdoc->last->child)) {
1944 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1945 mdoc->last->line, mdoc->last->pos, "empty");
1946 return(1);
1947 }
1948
1949 for ( ; n && n->next; n = n->next) {
1950 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1951 continue;
1952 if (MDOC_TEXT == n->type)
1953 continue;
1954 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1955 n->line, n->pos, mdoc_macronames[n->tok]);
1956 }
1957
1958 assert(n);
1959 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1960 return(1);
1961
1962 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1963 n->line, n->pos, mdoc_macronames[n->tok]);
1964 return(1);
1965 }
1966
1967 static int
1968 post_sh_head(POST_ARGS)
1969 {
1970 struct mdoc_node *n;
1971 const char *goodsec;
1972 char *secname;
1973 enum mdoc_sec sec;
1974
1975 /*
1976 * Process a new section. Sections are either "named" or
1977 * "custom". Custom sections are user-defined, while named ones
1978 * follow a conventional order and may only appear in certain
1979 * manual sections.
1980 */
1981
1982 secname = NULL;
1983 sec = SEC_CUSTOM;
1984 mdoc_deroff(&secname, mdoc->last);
1985 sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
1986
1987 /* The NAME should be first. */
1988
1989 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1990 mandoc_msg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
1991 mdoc->last->line, mdoc->last->pos, secname);
1992
1993 /* The SYNOPSIS gets special attention in other areas. */
1994
1995 if (SEC_SYNOPSIS == sec) {
1996 roff_setreg(mdoc->roff, "nS", 1, '=');
1997 mdoc->flags |= MDOC_SYNOPSIS;
1998 } else {
1999 roff_setreg(mdoc->roff, "nS", 0, '=');
2000 mdoc->flags &= ~MDOC_SYNOPSIS;
2001 }
2002
2003 /* Mark our last section. */
2004
2005 mdoc->lastsec = sec;
2006
2007 /*
2008 * Set the section attribute for the current HEAD, for its
2009 * parent BLOCK, and for the HEAD children; the latter can
2010 * only be TEXT nodes, so no recursion is needed.
2011 * For other blocks and elements, including .Sh BODY, this is
2012 * done when allocating the node data structures, but for .Sh
2013 * BLOCK and HEAD, the section is still unknown at that time.
2014 */
2015
2016 mdoc->last->parent->sec = sec;
2017 mdoc->last->sec = sec;
2018 for (n = mdoc->last->child; n; n = n->next)
2019 n->sec = sec;
2020
2021 /* We don't care about custom sections after this. */
2022
2023 if (SEC_CUSTOM == sec) {
2024 free(secname);
2025 return(1);
2026 }
2027
2028 /*
2029 * Check whether our non-custom section is being repeated or is
2030 * out of order.
2031 */
2032
2033 if (sec == mdoc->lastnamed)
2034 mandoc_msg(MANDOCERR_SEC_REP, mdoc->parse,
2035 mdoc->last->line, mdoc->last->pos, secname);
2036
2037 if (sec < mdoc->lastnamed)
2038 mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->parse,
2039 mdoc->last->line, mdoc->last->pos, secname);
2040
2041 /* Mark the last named section. */
2042
2043 mdoc->lastnamed = sec;
2044
2045 /* Check particular section/manual conventions. */
2046
2047 assert(mdoc->meta.msec);
2048
2049 goodsec = NULL;
2050 switch (sec) {
2051 case SEC_ERRORS:
2052 if (*mdoc->meta.msec == '4')
2053 break;
2054 goodsec = "2, 3, 4, 9";
2055 /* FALLTHROUGH */
2056 case SEC_RETURN_VALUES:
2057 /* FALLTHROUGH */
2058 case SEC_LIBRARY:
2059 if (*mdoc->meta.msec == '2')
2060 break;
2061 if (*mdoc->meta.msec == '3')
2062 break;
2063 if (NULL == goodsec)
2064 goodsec = "2, 3, 9";
2065 /* FALLTHROUGH */
2066 case SEC_CONTEXT:
2067 if (*mdoc->meta.msec == '9')
2068 break;
2069 if (NULL == goodsec)
2070 goodsec = "9";
2071 mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
2072 mdoc->last->line, mdoc->last->pos,
2073 "%s for %s only", secname, goodsec);
2074 break;
2075 default:
2076 break;
2077 }
2078
2079 free(secname);
2080 return(1);
2081 }
2082
2083 static int
2084 post_ignpar(POST_ARGS)
2085 {
2086 struct mdoc_node *np;
2087
2088 if (MDOC_BODY != mdoc->last->type)
2089 return(1);
2090
2091 if (NULL != (np = mdoc->last->child))
2092 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2093 mandoc_vmsg(MANDOCERR_PAR_SKIP,
2094 mdoc->parse, np->line, np->pos,
2095 "%s after %s", mdoc_macronames[np->tok],
2096 mdoc_macronames[mdoc->last->tok]);
2097 mdoc_node_delete(mdoc, np);
2098 }
2099
2100 if (NULL != (np = mdoc->last->last))
2101 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2102 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2103 np->line, np->pos, "%s at the end of %s",
2104 mdoc_macronames[np->tok],
2105 mdoc_macronames[mdoc->last->tok]);
2106 mdoc_node_delete(mdoc, np);
2107 }
2108
2109 return(1);
2110 }
2111
2112 static int
2113 pre_par(PRE_ARGS)
2114 {
2115
2116 if (NULL == mdoc->last)
2117 return(1);
2118 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2119 return(1);
2120
2121 /*
2122 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2123 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2124 */
2125
2126 if (MDOC_Pp != mdoc->last->tok &&
2127 MDOC_Lp != mdoc->last->tok &&
2128 MDOC_br != mdoc->last->tok)
2129 return(1);
2130 if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2131 return(1);
2132 if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2133 return(1);
2134 if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2135 return(1);
2136
2137 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2138 mdoc->last->line, mdoc->last->pos,
2139 "%s before %s", mdoc_macronames[mdoc->last->tok],
2140 mdoc_macronames[n->tok]);
2141 mdoc_node_delete(mdoc, mdoc->last);
2142 return(1);
2143 }
2144
2145 static int
2146 post_par(POST_ARGS)
2147 {
2148 struct mdoc_node *np;
2149
2150 if (MDOC_ELEM != mdoc->last->type &&
2151 MDOC_BLOCK != mdoc->last->type)
2152 return(1);
2153
2154 if (NULL == (np = mdoc->last->prev)) {
2155 np = mdoc->last->parent;
2156 if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
2157 return(1);
2158 } else {
2159 if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
2160 (MDOC_br != mdoc->last->tok ||
2161 (MDOC_sp != np->tok && MDOC_br != np->tok)))
2162 return(1);
2163 }
2164
2165 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2166 mdoc->last->line, mdoc->last->pos,
2167 "%s after %s", mdoc_macronames[mdoc->last->tok],
2168 mdoc_macronames[np->tok]);
2169 mdoc_node_delete(mdoc, mdoc->last);
2170 return(1);
2171 }
2172
2173 static int
2174 pre_literal(PRE_ARGS)
2175 {
2176
2177 if (MDOC_BODY != n->type)
2178 return(1);
2179
2180 /*
2181 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2182 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2183 */
2184
2185 switch (n->tok) {
2186 case MDOC_Dl:
2187 mdoc->flags |= MDOC_LITERAL;
2188 break;
2189 case MDOC_Bd:
2190 if (DISP_literal == n->norm->Bd.type)
2191 mdoc->flags |= MDOC_LITERAL;
2192 if (DISP_unfilled == n->norm->Bd.type)
2193 mdoc->flags |= MDOC_LITERAL;
2194 break;
2195 default:
2196 abort();
2197 /* NOTREACHED */
2198 }
2199
2200 return(1);
2201 }
2202
2203 static int
2204 post_dd(POST_ARGS)
2205 {
2206 struct mdoc_node *n;
2207 char *datestr;
2208
2209 if (mdoc->meta.date)
2210 free(mdoc->meta.date);
2211
2212 n = mdoc->last;
2213 if (NULL == n->child || '\0' == n->child->string[0]) {
2214 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
2215 mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
2216 return(1);
2217 }
2218
2219 datestr = NULL;
2220 mdoc_deroff(&datestr, n);
2221 if (mdoc->quick)
2222 mdoc->meta.date = datestr;
2223 else {
2224 mdoc->meta.date = mandoc_normdate(mdoc->parse,
2225 datestr, n->line, n->pos);
2226 free(datestr);
2227 }
2228 return(1);
2229 }
2230
2231 static int
2232 post_dt(POST_ARGS)
2233 {
2234 struct mdoc_node *nn, *n;
2235 const char *cp;
2236 char *p;
2237
2238 n = mdoc->last;
2239
2240 if (mdoc->meta.title)
2241 free(mdoc->meta.title);
2242 if (mdoc->meta.vol)
2243 free(mdoc->meta.vol);
2244 if (mdoc->meta.arch)
2245 free(mdoc->meta.arch);
2246
2247 mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
2248
2249 /* First check that all characters are uppercase. */
2250
2251 if (NULL != (nn = n->child))
2252 for (p = nn->string; *p; p++) {
2253 if (toupper((unsigned char)*p) == *p)
2254 continue;
2255 mandoc_msg(MANDOCERR_TITLE_CASE,
2256 mdoc->parse, nn->line,
2257 nn->pos + (p - nn->string),
2258 nn->string);
2259 break;
2260 }
2261
2262 /* Handles: `.Dt'
2263 * title = unknown, volume = local, msec = 0, arch = NULL
2264 */
2265
2266 if (NULL == (nn = n->child)) {
2267 /* XXX: make these macro values. */
2268 /* FIXME: warn about missing values. */
2269 mdoc->meta.title = mandoc_strdup("UNKNOWN");
2270 mdoc->meta.vol = mandoc_strdup("LOCAL");
2271 mdoc->meta.msec = mandoc_strdup("1");
2272 return(1);
2273 }
2274
2275 /* Handles: `.Dt TITLE'
2276 * title = TITLE, volume = local, msec = 0, arch = NULL
2277 */
2278
2279 mdoc->meta.title = mandoc_strdup(
2280 '\0' == nn->string[0] ? "UNKNOWN" : nn->string);
2281
2282 if (NULL == (nn = nn->next)) {
2283 /* FIXME: warn about missing msec. */
2284 /* XXX: make this a macro value. */
2285 mdoc->meta.vol = mandoc_strdup("LOCAL");
2286 mdoc->meta.msec = mandoc_strdup("1");
2287 return(1);
2288 }
2289
2290 /* Handles: `.Dt TITLE SEC'
2291 * title = TITLE,
2292 * volume = SEC is msec ? format(msec) : SEC,
2293 * msec = SEC is msec ? atoi(msec) : 0,
2294 * arch = NULL
2295 */
2296
2297 cp = mandoc_a2msec(nn->string);
2298 if (cp) {
2299 mdoc->meta.vol = mandoc_strdup(cp);
2300 mdoc->meta.msec = mandoc_strdup(nn->string);
2301 } else {
2302 mandoc_msg(MANDOCERR_MSEC_BAD, mdoc->parse,
2303 nn->line, nn->pos, nn->string);
2304 mdoc->meta.vol = mandoc_strdup(nn->string);
2305 mdoc->meta.msec = mandoc_strdup(nn->string);
2306 }
2307
2308 if (NULL == (nn = nn->next))
2309 return(1);
2310
2311 /* Handles: `.Dt TITLE SEC VOL'
2312 * title = TITLE,
2313 * volume = VOL is vol ? format(VOL) :
2314 * VOL is arch ? format(arch) :
2315 * VOL
2316 */
2317
2318 cp = mdoc_a2vol(nn->string);
2319 if (cp) {
2320 free(mdoc->meta.vol);
2321 mdoc->meta.vol = mandoc_strdup(cp);
2322 } else {
2323 cp = mdoc_a2arch(nn->string);
2324 if (NULL == cp) {
2325 mandoc_msg(MANDOCERR_ARCH_BAD, mdoc->parse,
2326 nn->line, nn->pos, nn->string);
2327 free(mdoc->meta.vol);
2328 mdoc->meta.vol = mandoc_strdup(nn->string);
2329 } else
2330 mdoc->meta.arch = mandoc_strdup(cp);
2331 }
2332
2333 /* Ignore any subsequent parameters... */
2334 /* FIXME: warn about subsequent parameters. */
2335
2336 return(1);
2337 }
2338
2339 static int
2340 post_prol(POST_ARGS)
2341 {
2342 /*
2343 * Remove prologue macros from the document after they're
2344 * processed. The final document uses mdoc_meta for these
2345 * values and discards the originals.
2346 */
2347
2348 mdoc_node_delete(mdoc, mdoc->last);
2349 if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
2350 mdoc->flags |= MDOC_PBODY;
2351
2352 return(1);
2353 }
2354
2355 static int
2356 post_bx(POST_ARGS)
2357 {
2358 struct mdoc_node *n;
2359
2360 /*
2361 * Make `Bx's second argument always start with an uppercase
2362 * letter. Groff checks if it's an "accepted" term, but we just
2363 * uppercase blindly.
2364 */
2365
2366 n = mdoc->last->child;
2367 if (n && NULL != (n = n->next))
2368 *n->string = (char)toupper((unsigned char)*n->string);
2369
2370 return(1);
2371 }
2372
2373 static int
2374 post_os(POST_ARGS)
2375 {
2376 #ifndef OSNAME
2377 struct utsname utsname;
2378 static char *defbuf;
2379 #endif
2380 struct mdoc_node *n;
2381
2382 n = mdoc->last;
2383
2384 /*
2385 * Set the operating system by way of the `Os' macro.
2386 * The order of precedence is:
2387 * 1. the argument of the `Os' macro, unless empty
2388 * 2. the -Ios=foo command line argument, if provided
2389 * 3. -DOSNAME="\"foo\"", if provided during compilation
2390 * 4. "sysname release" from uname(3)
2391 */
2392
2393 free(mdoc->meta.os);
2394 mdoc->meta.os = NULL;
2395 mdoc_deroff(&mdoc->meta.os, n);
2396 if (mdoc->meta.os)
2397 return(1);
2398
2399 if (mdoc->defos) {
2400 mdoc->meta.os = mandoc_strdup(mdoc->defos);
2401 return(1);
2402 }
2403
2404 #ifdef OSNAME
2405 mdoc->meta.os = mandoc_strdup(OSNAME);
2406 #else /*!OSNAME */
2407 if (NULL == defbuf) {
2408 if (-1 == uname(&utsname)) {
2409 mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2410 defbuf = mandoc_strdup("UNKNOWN");
2411 } else
2412 mandoc_asprintf(&defbuf, "%s %s",
2413 utsname.sysname, utsname.release);
2414 }
2415 mdoc->meta.os = mandoc_strdup(defbuf);
2416 #endif /*!OSNAME*/
2417 return(1);
2418 }
2419
2420 static int
2421 post_std(POST_ARGS)
2422 {
2423 struct mdoc_node *nn, *n;
2424
2425 n = mdoc->last;
2426
2427 /*
2428 * Macros accepting `-std' as an argument have the name of the
2429 * current document (`Nm') filled in as the argument if it's not
2430 * provided.
2431 */
2432
2433 if (n->child)
2434 return(1);
2435
2436 if (NULL == mdoc->meta.name)
2437 return(1);
2438
2439 nn = n;
2440 mdoc->next = MDOC_NEXT_CHILD;
2441
2442 if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2443 return(0);
2444
2445 mdoc->last = nn;
2446 return(1);
2447 }
2448
2449 static enum mdoc_sec
2450 a2sec(const char *p)
2451 {
2452 int i;
2453
2454 for (i = 0; i < (int)SEC__MAX; i++)
2455 if (secnames[i] && 0 == strcmp(p, secnames[i]))
2456 return((enum mdoc_sec)i);
2457
2458 return(SEC_CUSTOM);
2459 }
2460
2461 static size_t
2462 macro2len(enum mdoct macro)
2463 {
2464
2465 switch (macro) {
2466 case MDOC_Ad:
2467 return(12);
2468 case MDOC_Ao:
2469 return(12);
2470 case MDOC_An:
2471 return(12);
2472 case MDOC_Aq:
2473 return(12);
2474 case MDOC_Ar:
2475 return(12);
2476 case MDOC_Bo:
2477 return(12);
2478 case MDOC_Bq:
2479 return(12);
2480 case MDOC_Cd:
2481 return(12);
2482 case MDOC_Cm:
2483 return(10);
2484 case MDOC_Do:
2485 return(10);
2486 case MDOC_Dq:
2487 return(12);
2488 case MDOC_Dv:
2489 return(12);
2490 case MDOC_Eo:
2491 return(12);
2492 case MDOC_Em:
2493 return(10);
2494 case MDOC_Er:
2495 return(17);
2496 case MDOC_Ev:
2497 return(15);
2498 case MDOC_Fa:
2499 return(12);
2500 case MDOC_Fl:
2501 return(10);
2502 case MDOC_Fo:
2503 return(16);
2504 case MDOC_Fn:
2505 return(16);
2506 case MDOC_Ic:
2507 return(10);
2508 case MDOC_Li:
2509 return(16);
2510 case MDOC_Ms:
2511 return(6);
2512 case MDOC_Nm:
2513 return(10);
2514 case MDOC_No:
2515 return(12);
2516 case MDOC_Oo:
2517 return(10);
2518 case MDOC_Op:
2519 return(14);
2520 case MDOC_Pa:
2521 return(32);
2522 case MDOC_Pf:
2523 return(12);
2524 case MDOC_Po:
2525 return(12);
2526 case MDOC_Pq:
2527 return(12);
2528 case MDOC_Ql:
2529 return(16);
2530 case MDOC_Qo:
2531 return(12);
2532 case MDOC_So:
2533 return(12);
2534 case MDOC_Sq:
2535 return(12);
2536 case MDOC_Sy:
2537 return(6);
2538 case MDOC_Sx:
2539 return(16);
2540 case MDOC_Tn:
2541 return(10);
2542 case MDOC_Va:
2543 return(12);
2544 case MDOC_Vt:
2545 return(12);
2546 case MDOC_Xr:
2547 return(10);
2548 default:
2549 break;
2550 };
2551 return(0);
2552 }