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