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