8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / mandoc / mdoc_validate.c
blobe369349c8a35722d8f851c3eff53299985f6d0a2
1 /* $Id: mdoc_validate.c,v 1.301 2016/01/08 17:48:09 schwarze Exp $ */
2 /*
3 * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4 * Copyright (c) 2010-2016 Ingo Schwarze <schwarze@openbsd.org>
5 * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
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.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS 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.
19 #include "config.h"
21 #include <sys/types.h>
22 #ifndef OSNAME
23 #include <sys/utsname.h>
24 #endif
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>
34 #include "mandoc_aux.h"
35 #include "mandoc.h"
36 #include "roff.h"
37 #include "mdoc.h"
38 #include "libmandoc.h"
39 #include "roff_int.h"
40 #include "libmdoc.h"
42 /* FIXME: .Bl -diag can't have non-text children in HEAD. */
44 #define POST_ARGS struct roff_man *mdoc
46 enum check_ineq {
47 CHECK_LT,
48 CHECK_GT,
49 CHECK_EQ
52 typedef void (*v_post)(POST_ARGS);
54 static void check_text(struct roff_man *, int, int, char *);
55 static void check_argv(struct roff_man *,
56 struct roff_node *, struct mdoc_argv *);
57 static void check_args(struct roff_man *, struct roff_node *);
58 static int child_an(const struct roff_node *);
59 static size_t macro2len(int);
60 static void rewrite_macro2len(char **);
62 static void post_an(POST_ARGS);
63 static void post_an_norm(POST_ARGS);
64 static void post_at(POST_ARGS);
65 static void post_bd(POST_ARGS);
66 static void post_bf(POST_ARGS);
67 static void post_bk(POST_ARGS);
68 static void post_bl(POST_ARGS);
69 static void post_bl_block(POST_ARGS);
70 static void post_bl_block_tag(POST_ARGS);
71 static void post_bl_head(POST_ARGS);
72 static void post_bl_norm(POST_ARGS);
73 static void post_bx(POST_ARGS);
74 static void post_defaults(POST_ARGS);
75 static void post_display(POST_ARGS);
76 static void post_dd(POST_ARGS);
77 static void post_dt(POST_ARGS);
78 static void post_en(POST_ARGS);
79 static void post_es(POST_ARGS);
80 static void post_eoln(POST_ARGS);
81 static void post_ex(POST_ARGS);
82 static void post_fa(POST_ARGS);
83 static void post_fn(POST_ARGS);
84 static void post_fname(POST_ARGS);
85 static void post_fo(POST_ARGS);
86 static void post_hyph(POST_ARGS);
87 static void post_ignpar(POST_ARGS);
88 static void post_it(POST_ARGS);
89 static void post_lb(POST_ARGS);
90 static void post_nd(POST_ARGS);
91 static void post_nm(POST_ARGS);
92 static void post_ns(POST_ARGS);
93 static void post_obsolete(POST_ARGS);
94 static void post_os(POST_ARGS);
95 static void post_par(POST_ARGS);
96 static void post_prevpar(POST_ARGS);
97 static void post_root(POST_ARGS);
98 static void post_rs(POST_ARGS);
99 static void post_sh(POST_ARGS);
100 static void post_sh_head(POST_ARGS);
101 static void post_sh_name(POST_ARGS);
102 static void post_sh_see_also(POST_ARGS);
103 static void post_sh_authors(POST_ARGS);
104 static void post_sm(POST_ARGS);
105 static void post_st(POST_ARGS);
106 static void post_std(POST_ARGS);
108 static v_post mdoc_valids[MDOC_MAX] = {
109 NULL, /* Ap */
110 post_dd, /* Dd */
111 post_dt, /* Dt */
112 post_os, /* Os */
113 post_sh, /* Sh */
114 post_ignpar, /* Ss */
115 post_par, /* Pp */
116 post_display, /* D1 */
117 post_display, /* Dl */
118 post_display, /* Bd */
119 NULL, /* Ed */
120 post_bl, /* Bl */
121 NULL, /* El */
122 post_it, /* It */
123 NULL, /* Ad */
124 post_an, /* An */
125 post_defaults, /* Ar */
126 NULL, /* Cd */
127 NULL, /* Cm */
128 NULL, /* Dv */
129 NULL, /* Er */
130 NULL, /* Ev */
131 post_ex, /* Ex */
132 post_fa, /* Fa */
133 NULL, /* Fd */
134 NULL, /* Fl */
135 post_fn, /* Fn */
136 NULL, /* Ft */
137 NULL, /* Ic */
138 NULL, /* In */
139 post_defaults, /* Li */
140 post_nd, /* Nd */
141 post_nm, /* Nm */
142 NULL, /* Op */
143 post_obsolete, /* Ot */
144 post_defaults, /* Pa */
145 post_std, /* Rv */
146 post_st, /* St */
147 NULL, /* Va */
148 NULL, /* Vt */
149 NULL, /* Xr */
150 NULL, /* %A */
151 post_hyph, /* %B */ /* FIXME: can be used outside Rs/Re. */
152 NULL, /* %D */
153 NULL, /* %I */
154 NULL, /* %J */
155 post_hyph, /* %N */
156 post_hyph, /* %O */
157 NULL, /* %P */
158 post_hyph, /* %R */
159 post_hyph, /* %T */ /* FIXME: can be used outside Rs/Re. */
160 NULL, /* %V */
161 NULL, /* Ac */
162 NULL, /* Ao */
163 NULL, /* Aq */
164 post_at, /* At */
165 NULL, /* Bc */
166 post_bf, /* Bf */
167 NULL, /* Bo */
168 NULL, /* Bq */
169 NULL, /* Bsx */
170 post_bx, /* Bx */
171 post_obsolete, /* Db */
172 NULL, /* Dc */
173 NULL, /* Do */
174 NULL, /* Dq */
175 NULL, /* Ec */
176 NULL, /* Ef */
177 NULL, /* Em */
178 NULL, /* Eo */
179 NULL, /* Fx */
180 NULL, /* Ms */
181 NULL, /* No */
182 post_ns, /* Ns */
183 NULL, /* Nx */
184 NULL, /* Ox */
185 NULL, /* Pc */
186 NULL, /* Pf */
187 NULL, /* Po */
188 NULL, /* Pq */
189 NULL, /* Qc */
190 NULL, /* Ql */
191 NULL, /* Qo */
192 NULL, /* Qq */
193 NULL, /* Re */
194 post_rs, /* Rs */
195 NULL, /* Sc */
196 NULL, /* So */
197 NULL, /* Sq */
198 post_sm, /* Sm */
199 post_hyph, /* Sx */
200 NULL, /* Sy */
201 NULL, /* Tn */
202 NULL, /* Ux */
203 NULL, /* Xc */
204 NULL, /* Xo */
205 post_fo, /* Fo */
206 NULL, /* Fc */
207 NULL, /* Oo */
208 NULL, /* Oc */
209 post_bk, /* Bk */
210 NULL, /* Ek */
211 post_eoln, /* Bt */
212 NULL, /* Hf */
213 post_obsolete, /* Fr */
214 post_eoln, /* Ud */
215 post_lb, /* Lb */
216 post_par, /* Lp */
217 NULL, /* Lk */
218 post_defaults, /* Mt */
219 NULL, /* Brq */
220 NULL, /* Bro */
221 NULL, /* Brc */
222 NULL, /* %C */
223 post_es, /* Es */
224 post_en, /* En */
225 NULL, /* Dx */
226 NULL, /* %Q */
227 post_par, /* br */
228 post_par, /* sp */
229 NULL, /* %U */
230 NULL, /* Ta */
231 NULL, /* ll */
234 #define RSORD_MAX 14 /* Number of `Rs' blocks. */
236 static const int rsord[RSORD_MAX] = {
237 MDOC__A,
238 MDOC__T,
239 MDOC__B,
240 MDOC__I,
241 MDOC__J,
242 MDOC__R,
243 MDOC__N,
244 MDOC__V,
245 MDOC__U,
246 MDOC__P,
247 MDOC__Q,
248 MDOC__C,
249 MDOC__D,
250 MDOC__O
253 static const char * const secnames[SEC__MAX] = {
254 NULL,
255 "NAME",
256 "LIBRARY",
257 "SYNOPSIS",
258 "DESCRIPTION",
259 "CONTEXT",
260 "IMPLEMENTATION NOTES",
261 "RETURN VALUES",
262 "ENVIRONMENT",
263 "FILES",
264 "EXIT STATUS",
265 "EXAMPLES",
266 "DIAGNOSTICS",
267 "COMPATIBILITY",
268 "ERRORS",
269 "SEE ALSO",
270 "STANDARDS",
271 "HISTORY",
272 "AUTHORS",
273 "CAVEATS",
274 "BUGS",
275 "SECURITY CONSIDERATIONS",
276 NULL
280 void
281 mdoc_node_validate(struct roff_man *mdoc)
283 struct roff_node *n;
284 v_post *p;
286 n = mdoc->last;
287 mdoc->last = mdoc->last->child;
288 while (mdoc->last != NULL) {
289 mdoc_node_validate(mdoc);
290 if (mdoc->last == n)
291 mdoc->last = mdoc->last->child;
292 else
293 mdoc->last = mdoc->last->next;
296 mdoc->last = n;
297 mdoc->next = ROFF_NEXT_SIBLING;
298 switch (n->type) {
299 case ROFFT_TEXT:
300 if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd)
301 check_text(mdoc, n->line, n->pos, n->string);
302 break;
303 case ROFFT_EQN:
304 case ROFFT_TBL:
305 break;
306 case ROFFT_ROOT:
307 post_root(mdoc);
308 break;
309 default:
310 check_args(mdoc, mdoc->last);
313 * Closing delimiters are not special at the
314 * beginning of a block, opening delimiters
315 * are not special at the end.
318 if (n->child != NULL)
319 n->child->flags &= ~MDOC_DELIMC;
320 if (n->last != NULL)
321 n->last->flags &= ~MDOC_DELIMO;
323 /* Call the macro's postprocessor. */
325 p = mdoc_valids + n->tok;
326 if (*p)
327 (*p)(mdoc);
328 if (mdoc->last == n)
329 mdoc_state(mdoc, n);
330 break;
334 static void
335 check_args(struct roff_man *mdoc, struct roff_node *n)
337 int i;
339 if (NULL == n->args)
340 return;
342 assert(n->args->argc);
343 for (i = 0; i < (int)n->args->argc; i++)
344 check_argv(mdoc, n, &n->args->argv[i]);
347 static void
348 check_argv(struct roff_man *mdoc, struct roff_node *n, struct mdoc_argv *v)
350 int i;
352 for (i = 0; i < (int)v->sz; i++)
353 check_text(mdoc, v->line, v->pos, v->value[i]);
356 static void
357 check_text(struct roff_man *mdoc, int ln, int pos, char *p)
359 char *cp;
361 if (MDOC_LITERAL & mdoc->flags)
362 return;
364 for (cp = p; NULL != (p = strchr(p, '\t')); p++)
365 mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse,
366 ln, pos + (int)(p - cp), NULL);
369 static void
370 post_bl_norm(POST_ARGS)
372 struct roff_node *n;
373 struct mdoc_argv *argv, *wa;
374 int i;
375 enum mdocargt mdoclt;
376 enum mdoc_list lt;
378 n = mdoc->last->parent;
379 n->norm->Bl.type = LIST__NONE;
382 * First figure out which kind of list to use: bind ourselves to
383 * the first mentioned list type and warn about any remaining
384 * ones. If we find no list type, we default to LIST_item.
387 wa = (n->args == NULL) ? NULL : n->args->argv;
388 mdoclt = MDOC_ARG_MAX;
389 for (i = 0; n->args && i < (int)n->args->argc; i++) {
390 argv = n->args->argv + i;
391 lt = LIST__NONE;
392 switch (argv->arg) {
393 /* Set list types. */
394 case MDOC_Bullet:
395 lt = LIST_bullet;
396 break;
397 case MDOC_Dash:
398 lt = LIST_dash;
399 break;
400 case MDOC_Enum:
401 lt = LIST_enum;
402 break;
403 case MDOC_Hyphen:
404 lt = LIST_hyphen;
405 break;
406 case MDOC_Item:
407 lt = LIST_item;
408 break;
409 case MDOC_Tag:
410 lt = LIST_tag;
411 break;
412 case MDOC_Diag:
413 lt = LIST_diag;
414 break;
415 case MDOC_Hang:
416 lt = LIST_hang;
417 break;
418 case MDOC_Ohang:
419 lt = LIST_ohang;
420 break;
421 case MDOC_Inset:
422 lt = LIST_inset;
423 break;
424 case MDOC_Column:
425 lt = LIST_column;
426 break;
427 /* Set list arguments. */
428 case MDOC_Compact:
429 if (n->norm->Bl.comp)
430 mandoc_msg(MANDOCERR_ARG_REP,
431 mdoc->parse, argv->line,
432 argv->pos, "Bl -compact");
433 n->norm->Bl.comp = 1;
434 break;
435 case MDOC_Width:
436 wa = argv;
437 if (0 == argv->sz) {
438 mandoc_msg(MANDOCERR_ARG_EMPTY,
439 mdoc->parse, argv->line,
440 argv->pos, "Bl -width");
441 n->norm->Bl.width = "0n";
442 break;
444 if (NULL != n->norm->Bl.width)
445 mandoc_vmsg(MANDOCERR_ARG_REP,
446 mdoc->parse, argv->line,
447 argv->pos, "Bl -width %s",
448 argv->value[0]);
449 rewrite_macro2len(argv->value);
450 n->norm->Bl.width = argv->value[0];
451 break;
452 case MDOC_Offset:
453 if (0 == argv->sz) {
454 mandoc_msg(MANDOCERR_ARG_EMPTY,
455 mdoc->parse, argv->line,
456 argv->pos, "Bl -offset");
457 break;
459 if (NULL != n->norm->Bl.offs)
460 mandoc_vmsg(MANDOCERR_ARG_REP,
461 mdoc->parse, argv->line,
462 argv->pos, "Bl -offset %s",
463 argv->value[0]);
464 rewrite_macro2len(argv->value);
465 n->norm->Bl.offs = argv->value[0];
466 break;
467 default:
468 continue;
470 if (LIST__NONE == lt)
471 continue;
472 mdoclt = argv->arg;
474 /* Check: multiple list types. */
476 if (LIST__NONE != n->norm->Bl.type) {
477 mandoc_vmsg(MANDOCERR_BL_REP,
478 mdoc->parse, n->line, n->pos,
479 "Bl -%s", mdoc_argnames[argv->arg]);
480 continue;
483 /* The list type should come first. */
485 if (n->norm->Bl.width ||
486 n->norm->Bl.offs ||
487 n->norm->Bl.comp)
488 mandoc_vmsg(MANDOCERR_BL_LATETYPE,
489 mdoc->parse, n->line, n->pos, "Bl -%s",
490 mdoc_argnames[n->args->argv[0].arg]);
492 n->norm->Bl.type = lt;
493 if (LIST_column == lt) {
494 n->norm->Bl.ncols = argv->sz;
495 n->norm->Bl.cols = (void *)argv->value;
499 /* Allow lists to default to LIST_item. */
501 if (LIST__NONE == n->norm->Bl.type) {
502 mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse,
503 n->line, n->pos, "Bl");
504 n->norm->Bl.type = LIST_item;
508 * Validate the width field. Some list types don't need width
509 * types and should be warned about them. Others should have it
510 * and must also be warned. Yet others have a default and need
511 * no warning.
514 switch (n->norm->Bl.type) {
515 case LIST_tag:
516 if (NULL == n->norm->Bl.width)
517 mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse,
518 n->line, n->pos, "Bl -tag");
519 break;
520 case LIST_column:
521 case LIST_diag:
522 case LIST_ohang:
523 case LIST_inset:
524 case LIST_item:
525 if (n->norm->Bl.width)
526 mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse,
527 wa->line, wa->pos, "Bl -%s",
528 mdoc_argnames[mdoclt]);
529 break;
530 case LIST_bullet:
531 case LIST_dash:
532 case LIST_hyphen:
533 if (NULL == n->norm->Bl.width)
534 n->norm->Bl.width = "2n";
535 break;
536 case LIST_enum:
537 if (NULL == n->norm->Bl.width)
538 n->norm->Bl.width = "3n";
539 break;
540 default:
541 break;
545 static void
546 post_bd(POST_ARGS)
548 struct roff_node *n;
549 struct mdoc_argv *argv;
550 int i;
551 enum mdoc_disp dt;
553 n = mdoc->last;
554 for (i = 0; n->args && i < (int)n->args->argc; i++) {
555 argv = n->args->argv + i;
556 dt = DISP__NONE;
558 switch (argv->arg) {
559 case MDOC_Centred:
560 dt = DISP_centered;
561 break;
562 case MDOC_Ragged:
563 dt = DISP_ragged;
564 break;
565 case MDOC_Unfilled:
566 dt = DISP_unfilled;
567 break;
568 case MDOC_Filled:
569 dt = DISP_filled;
570 break;
571 case MDOC_Literal:
572 dt = DISP_literal;
573 break;
574 case MDOC_File:
575 mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse,
576 n->line, n->pos, NULL);
577 break;
578 case MDOC_Offset:
579 if (0 == argv->sz) {
580 mandoc_msg(MANDOCERR_ARG_EMPTY,
581 mdoc->parse, argv->line,
582 argv->pos, "Bd -offset");
583 break;
585 if (NULL != n->norm->Bd.offs)
586 mandoc_vmsg(MANDOCERR_ARG_REP,
587 mdoc->parse, argv->line,
588 argv->pos, "Bd -offset %s",
589 argv->value[0]);
590 rewrite_macro2len(argv->value);
591 n->norm->Bd.offs = argv->value[0];
592 break;
593 case MDOC_Compact:
594 if (n->norm->Bd.comp)
595 mandoc_msg(MANDOCERR_ARG_REP,
596 mdoc->parse, argv->line,
597 argv->pos, "Bd -compact");
598 n->norm->Bd.comp = 1;
599 break;
600 default:
601 abort();
603 if (DISP__NONE == dt)
604 continue;
606 if (DISP__NONE == n->norm->Bd.type)
607 n->norm->Bd.type = dt;
608 else
609 mandoc_vmsg(MANDOCERR_BD_REP,
610 mdoc->parse, n->line, n->pos,
611 "Bd -%s", mdoc_argnames[argv->arg]);
614 if (DISP__NONE == n->norm->Bd.type) {
615 mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse,
616 n->line, n->pos, "Bd");
617 n->norm->Bd.type = DISP_ragged;
621 static void
622 post_an_norm(POST_ARGS)
624 struct roff_node *n;
625 struct mdoc_argv *argv;
626 size_t i;
628 n = mdoc->last;
629 if (n->args == NULL)
630 return;
632 for (i = 1; i < n->args->argc; i++) {
633 argv = n->args->argv + i;
634 mandoc_vmsg(MANDOCERR_AN_REP,
635 mdoc->parse, argv->line, argv->pos,
636 "An -%s", mdoc_argnames[argv->arg]);
639 argv = n->args->argv;
640 if (argv->arg == MDOC_Split)
641 n->norm->An.auth = AUTH_split;
642 else if (argv->arg == MDOC_Nosplit)
643 n->norm->An.auth = AUTH_nosplit;
644 else
645 abort();
648 static void
649 post_std(POST_ARGS)
651 struct roff_node *n;
653 n = mdoc->last;
654 if (n->args && n->args->argc == 1)
655 if (n->args->argv[0].arg == MDOC_Std)
656 return;
658 mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
659 n->line, n->pos, mdoc_macronames[n->tok]);
662 static void
663 post_obsolete(POST_ARGS)
665 struct roff_node *n;
667 n = mdoc->last;
668 if (n->type == ROFFT_ELEM || n->type == ROFFT_BLOCK)
669 mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
670 n->line, n->pos, mdoc_macronames[n->tok]);
673 static void
674 post_bf(POST_ARGS)
676 struct roff_node *np, *nch;
679 * Unlike other data pointers, these are "housed" by the HEAD
680 * element, which contains the goods.
683 np = mdoc->last;
684 if (np->type != ROFFT_HEAD)
685 return;
687 assert(np->parent->type == ROFFT_BLOCK);
688 assert(np->parent->tok == MDOC_Bf);
690 /* Check the number of arguments. */
692 nch = np->child;
693 if (np->parent->args == NULL) {
694 if (nch == NULL) {
695 mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse,
696 np->line, np->pos, "Bf");
697 return;
699 nch = nch->next;
701 if (nch != NULL)
702 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
703 nch->line, nch->pos, "Bf ... %s", nch->string);
705 /* Extract argument into data. */
707 if (np->parent->args != NULL) {
708 switch (np->parent->args->argv[0].arg) {
709 case MDOC_Emphasis:
710 np->norm->Bf.font = FONT_Em;
711 break;
712 case MDOC_Literal:
713 np->norm->Bf.font = FONT_Li;
714 break;
715 case MDOC_Symbolic:
716 np->norm->Bf.font = FONT_Sy;
717 break;
718 default:
719 abort();
721 return;
724 /* Extract parameter into data. */
726 if ( ! strcmp(np->child->string, "Em"))
727 np->norm->Bf.font = FONT_Em;
728 else if ( ! strcmp(np->child->string, "Li"))
729 np->norm->Bf.font = FONT_Li;
730 else if ( ! strcmp(np->child->string, "Sy"))
731 np->norm->Bf.font = FONT_Sy;
732 else
733 mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse,
734 np->child->line, np->child->pos,
735 "Bf %s", np->child->string);
738 static void
739 post_lb(POST_ARGS)
741 struct roff_node *n;
742 const char *stdlibname;
743 char *libname;
745 n = mdoc->last->child;
746 assert(n->type == ROFFT_TEXT);
748 if (NULL == (stdlibname = mdoc_a2lib(n->string)))
749 mandoc_asprintf(&libname,
750 "library \\(Lq%s\\(Rq", n->string);
751 else
752 libname = mandoc_strdup(stdlibname);
754 free(n->string);
755 n->string = libname;
758 static void
759 post_eoln(POST_ARGS)
761 const struct roff_node *n;
763 n = mdoc->last;
764 if (n->child != NULL)
765 mandoc_vmsg(MANDOCERR_ARG_SKIP,
766 mdoc->parse, n->line, n->pos,
767 "%s %s", mdoc_macronames[n->tok],
768 n->child->string);
771 static void
772 post_fname(POST_ARGS)
774 const struct roff_node *n;
775 const char *cp;
776 size_t pos;
778 n = mdoc->last->child;
779 pos = strcspn(n->string, "()");
780 cp = n->string + pos;
781 if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
782 mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
783 n->line, n->pos + pos, n->string);
786 static void
787 post_fn(POST_ARGS)
790 post_fname(mdoc);
791 post_fa(mdoc);
794 static void
795 post_fo(POST_ARGS)
797 const struct roff_node *n;
799 n = mdoc->last;
801 if (n->type != ROFFT_HEAD)
802 return;
804 if (n->child == NULL) {
805 mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse,
806 n->line, n->pos, "Fo");
807 return;
809 if (n->child != n->last) {
810 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
811 n->child->next->line, n->child->next->pos,
812 "Fo ... %s", n->child->next->string);
813 while (n->child != n->last)
814 roff_node_delete(mdoc, n->last);
817 post_fname(mdoc);
820 static void
821 post_fa(POST_ARGS)
823 const struct roff_node *n;
824 const char *cp;
826 for (n = mdoc->last->child; n != NULL; n = n->next) {
827 for (cp = n->string; *cp != '\0'; cp++) {
828 /* Ignore callbacks and alterations. */
829 if (*cp == '(' || *cp == '{')
830 break;
831 if (*cp != ',')
832 continue;
833 mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
834 n->line, n->pos + (cp - n->string),
835 n->string);
836 break;
841 static void
842 post_nm(POST_ARGS)
844 struct roff_node *n;
846 n = mdoc->last;
848 if (n->last != NULL &&
849 (n->last->tok == MDOC_Pp ||
850 n->last->tok == MDOC_Lp))
851 mdoc_node_relink(mdoc, n->last);
853 if (mdoc->meta.name != NULL)
854 return;
856 deroff(&mdoc->meta.name, n);
858 if (mdoc->meta.name == NULL)
859 mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
860 n->line, n->pos, "Nm");
863 static void
864 post_nd(POST_ARGS)
866 struct roff_node *n;
868 n = mdoc->last;
870 if (n->type != ROFFT_BODY)
871 return;
873 if (n->child == NULL)
874 mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
875 n->line, n->pos, "Nd");
877 post_hyph(mdoc);
880 static void
881 post_display(POST_ARGS)
883 struct roff_node *n, *np;
885 n = mdoc->last;
886 switch (n->type) {
887 case ROFFT_BODY:
888 if (n->end != ENDBODY_NOT)
889 break;
890 if (n->child == NULL)
891 mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
892 n->line, n->pos, mdoc_macronames[n->tok]);
893 else if (n->tok == MDOC_D1)
894 post_hyph(mdoc);
895 break;
896 case ROFFT_BLOCK:
897 if (n->tok == MDOC_Bd) {
898 if (n->args == NULL) {
899 mandoc_msg(MANDOCERR_BD_NOARG,
900 mdoc->parse, n->line, n->pos, "Bd");
901 mdoc->next = ROFF_NEXT_SIBLING;
902 while (n->body->child != NULL)
903 mdoc_node_relink(mdoc,
904 n->body->child);
905 roff_node_delete(mdoc, n);
906 break;
908 post_bd(mdoc);
909 post_prevpar(mdoc);
911 for (np = n->parent; np != NULL; np = np->parent) {
912 if (np->type == ROFFT_BLOCK && np->tok == MDOC_Bd) {
913 mandoc_vmsg(MANDOCERR_BD_NEST,
914 mdoc->parse, n->line, n->pos,
915 "%s in Bd", mdoc_macronames[n->tok]);
916 break;
919 break;
920 default:
921 break;
925 static void
926 post_defaults(POST_ARGS)
928 struct roff_node *nn;
931 * The `Ar' defaults to "file ..." if no value is provided as an
932 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
933 * gets an empty string.
936 if (mdoc->last->child != NULL)
937 return;
939 nn = mdoc->last;
941 switch (nn->tok) {
942 case MDOC_Ar:
943 mdoc->next = ROFF_NEXT_CHILD;
944 roff_word_alloc(mdoc, nn->line, nn->pos, "file");
945 roff_word_alloc(mdoc, nn->line, nn->pos, "...");
946 break;
947 case MDOC_Pa:
948 case MDOC_Mt:
949 mdoc->next = ROFF_NEXT_CHILD;
950 roff_word_alloc(mdoc, nn->line, nn->pos, "~");
951 break;
952 default:
953 abort();
955 mdoc->last = nn;
958 static void
959 post_at(POST_ARGS)
961 struct roff_node *n;
962 const char *std_att;
963 char *att;
965 n = mdoc->last;
966 if (n->child == NULL) {
967 mdoc->next = ROFF_NEXT_CHILD;
968 roff_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX");
969 mdoc->last = n;
970 return;
974 * If we have a child, look it up in the standard keys. If a
975 * key exist, use that instead of the child; if it doesn't,
976 * prefix "AT&T UNIX " to the existing data.
979 n = n->child;
980 assert(n->type == ROFFT_TEXT);
981 if ((std_att = mdoc_a2att(n->string)) == NULL) {
982 mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
983 n->line, n->pos, "At %s", n->string);
984 mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
985 } else
986 att = mandoc_strdup(std_att);
988 free(n->string);
989 n->string = att;
992 static void
993 post_an(POST_ARGS)
995 struct roff_node *np, *nch;
997 post_an_norm(mdoc);
999 np = mdoc->last;
1000 nch = np->child;
1001 if (np->norm->An.auth == AUTH__NONE) {
1002 if (nch == NULL)
1003 mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
1004 np->line, np->pos, "An");
1005 } else if (nch != NULL)
1006 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1007 nch->line, nch->pos, "An ... %s", nch->string);
1010 static void
1011 post_en(POST_ARGS)
1014 post_obsolete(mdoc);
1015 if (mdoc->last->type == ROFFT_BLOCK)
1016 mdoc->last->norm->Es = mdoc->last_es;
1019 static void
1020 post_es(POST_ARGS)
1023 post_obsolete(mdoc);
1024 mdoc->last_es = mdoc->last;
1027 static void
1028 post_it(POST_ARGS)
1030 struct roff_node *nbl, *nit, *nch;
1031 int i, cols;
1032 enum mdoc_list lt;
1034 post_prevpar(mdoc);
1036 nit = mdoc->last;
1037 if (nit->type != ROFFT_BLOCK)
1038 return;
1040 nbl = nit->parent->parent;
1041 lt = nbl->norm->Bl.type;
1043 switch (lt) {
1044 case LIST_tag:
1045 case LIST_hang:
1046 case LIST_ohang:
1047 case LIST_inset:
1048 case LIST_diag:
1049 if (nit->head->child == NULL)
1050 mandoc_vmsg(MANDOCERR_IT_NOHEAD,
1051 mdoc->parse, nit->line, nit->pos,
1052 "Bl -%s It",
1053 mdoc_argnames[nbl->args->argv[0].arg]);
1054 break;
1055 case LIST_bullet:
1056 case LIST_dash:
1057 case LIST_enum:
1058 case LIST_hyphen:
1059 if (nit->body == NULL || nit->body->child == NULL)
1060 mandoc_vmsg(MANDOCERR_IT_NOBODY,
1061 mdoc->parse, nit->line, nit->pos,
1062 "Bl -%s It",
1063 mdoc_argnames[nbl->args->argv[0].arg]);
1064 /* FALLTHROUGH */
1065 case LIST_item:
1066 if (nit->head->child != NULL)
1067 mandoc_vmsg(MANDOCERR_ARG_SKIP,
1068 mdoc->parse, nit->line, nit->pos,
1069 "It %s", nit->head->child->string);
1070 break;
1071 case LIST_column:
1072 cols = (int)nbl->norm->Bl.ncols;
1074 assert(nit->head->child == NULL);
1076 i = 0;
1077 for (nch = nit->child; nch != NULL; nch = nch->next)
1078 if (nch->type == ROFFT_BODY)
1079 i++;
1081 if (i < cols || i > cols + 1)
1082 mandoc_vmsg(MANDOCERR_BL_COL,
1083 mdoc->parse, nit->line, nit->pos,
1084 "%d columns, %d cells", cols, i);
1085 break;
1086 default:
1087 abort();
1091 static void
1092 post_bl_block(POST_ARGS)
1094 struct roff_node *n, *ni, *nc;
1096 post_prevpar(mdoc);
1099 * These are fairly complicated, so we've broken them into two
1100 * functions. post_bl_block_tag() is called when a -tag is
1101 * specified, but no -width (it must be guessed). The second
1102 * when a -width is specified (macro indicators must be
1103 * rewritten into real lengths).
1106 n = mdoc->last;
1108 if (n->norm->Bl.type == LIST_tag &&
1109 n->norm->Bl.width == NULL) {
1110 post_bl_block_tag(mdoc);
1111 assert(n->norm->Bl.width != NULL);
1114 for (ni = n->body->child; ni != NULL; ni = ni->next) {
1115 if (ni->body == NULL)
1116 continue;
1117 nc = ni->body->last;
1118 while (nc != NULL) {
1119 switch (nc->tok) {
1120 case MDOC_Pp:
1121 case MDOC_Lp:
1122 case MDOC_br:
1123 break;
1124 default:
1125 nc = NULL;
1126 continue;
1128 if (ni->next == NULL) {
1129 mandoc_msg(MANDOCERR_PAR_MOVE,
1130 mdoc->parse, nc->line, nc->pos,
1131 mdoc_macronames[nc->tok]);
1132 mdoc_node_relink(mdoc, nc);
1133 } else if (n->norm->Bl.comp == 0 &&
1134 n->norm->Bl.type != LIST_column) {
1135 mandoc_vmsg(MANDOCERR_PAR_SKIP,
1136 mdoc->parse, nc->line, nc->pos,
1137 "%s before It",
1138 mdoc_macronames[nc->tok]);
1139 roff_node_delete(mdoc, nc);
1140 } else
1141 break;
1142 nc = ni->body->last;
1148 * If the argument of -offset or -width is a macro,
1149 * replace it with the associated default width.
1151 void
1152 rewrite_macro2len(char **arg)
1154 size_t width;
1155 int tok;
1157 if (*arg == NULL)
1158 return;
1159 else if ( ! strcmp(*arg, "Ds"))
1160 width = 6;
1161 else if ((tok = mdoc_hash_find(*arg)) == TOKEN_NONE)
1162 return;
1163 else
1164 width = macro2len(tok);
1166 free(*arg);
1167 mandoc_asprintf(arg, "%zun", width);
1170 static void
1171 post_bl_block_tag(POST_ARGS)
1173 struct roff_node *n, *nn;
1174 size_t sz, ssz;
1175 int i;
1176 char buf[24];
1179 * Calculate the -width for a `Bl -tag' list if it hasn't been
1180 * provided. Uses the first head macro. NOTE AGAIN: this is
1181 * ONLY if the -width argument has NOT been provided. See
1182 * rewrite_macro2len() for converting the -width string.
1185 sz = 10;
1186 n = mdoc->last;
1188 for (nn = n->body->child; nn != NULL; nn = nn->next) {
1189 if (nn->tok != MDOC_It)
1190 continue;
1192 assert(nn->type == ROFFT_BLOCK);
1193 nn = nn->head->child;
1195 if (nn == NULL)
1196 break;
1198 if (nn->type == ROFFT_TEXT) {
1199 sz = strlen(nn->string) + 1;
1200 break;
1203 if (0 != (ssz = macro2len(nn->tok)))
1204 sz = ssz;
1206 break;
1209 /* Defaults to ten ens. */
1211 (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
1214 * We have to dynamically add this to the macro's argument list.
1215 * We're guaranteed that a MDOC_Width doesn't already exist.
1218 assert(n->args != NULL);
1219 i = (int)(n->args->argc)++;
1221 n->args->argv = mandoc_reallocarray(n->args->argv,
1222 n->args->argc, sizeof(struct mdoc_argv));
1224 n->args->argv[i].arg = MDOC_Width;
1225 n->args->argv[i].line = n->line;
1226 n->args->argv[i].pos = n->pos;
1227 n->args->argv[i].sz = 1;
1228 n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1229 n->args->argv[i].value[0] = mandoc_strdup(buf);
1231 /* Set our width! */
1232 n->norm->Bl.width = n->args->argv[i].value[0];
1235 static void
1236 post_bl_head(POST_ARGS)
1238 struct roff_node *nbl, *nh, *nch, *nnext;
1239 struct mdoc_argv *argv;
1240 int i, j;
1242 post_bl_norm(mdoc);
1244 nh = mdoc->last;
1245 if (nh->norm->Bl.type != LIST_column) {
1246 if ((nch = nh->child) == NULL)
1247 return;
1248 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1249 nch->line, nch->pos, "Bl ... %s", nch->string);
1250 while (nch != NULL) {
1251 roff_node_delete(mdoc, nch);
1252 nch = nh->child;
1254 return;
1258 * Append old-style lists, where the column width specifiers
1259 * trail as macro parameters, to the new-style ("normal-form")
1260 * lists where they're argument values following -column.
1263 if (nh->child == NULL)
1264 return;
1266 nbl = nh->parent;
1267 for (j = 0; j < (int)nbl->args->argc; j++)
1268 if (nbl->args->argv[j].arg == MDOC_Column)
1269 break;
1271 assert(j < (int)nbl->args->argc);
1274 * Accommodate for new-style groff column syntax. Shuffle the
1275 * child nodes, all of which must be TEXT, as arguments for the
1276 * column field. Then, delete the head children.
1279 argv = nbl->args->argv + j;
1280 i = argv->sz;
1281 for (nch = nh->child; nch != NULL; nch = nch->next)
1282 argv->sz++;
1283 argv->value = mandoc_reallocarray(argv->value,
1284 argv->sz, sizeof(char *));
1286 nh->norm->Bl.ncols = argv->sz;
1287 nh->norm->Bl.cols = (void *)argv->value;
1289 for (nch = nh->child; nch != NULL; nch = nnext) {
1290 argv->value[i++] = nch->string;
1291 nch->string = NULL;
1292 nnext = nch->next;
1293 roff_node_delete(NULL, nch);
1295 nh->child = NULL;
1298 static void
1299 post_bl(POST_ARGS)
1301 struct roff_node *nparent, *nprev; /* of the Bl block */
1302 struct roff_node *nblock, *nbody; /* of the Bl */
1303 struct roff_node *nchild, *nnext; /* of the Bl body */
1305 nbody = mdoc->last;
1306 switch (nbody->type) {
1307 case ROFFT_BLOCK:
1308 post_bl_block(mdoc);
1309 return;
1310 case ROFFT_HEAD:
1311 post_bl_head(mdoc);
1312 return;
1313 case ROFFT_BODY:
1314 break;
1315 default:
1316 return;
1318 if (nbody->end != ENDBODY_NOT)
1319 return;
1321 nchild = nbody->child;
1322 if (nchild == NULL) {
1323 mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
1324 nbody->line, nbody->pos, "Bl");
1325 return;
1327 while (nchild != NULL) {
1328 if (nchild->tok == MDOC_It ||
1329 (nchild->tok == MDOC_Sm &&
1330 nchild->next != NULL &&
1331 nchild->next->tok == MDOC_It)) {
1332 nchild = nchild->next;
1333 continue;
1336 mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
1337 nchild->line, nchild->pos,
1338 mdoc_macronames[nchild->tok]);
1341 * Move the node out of the Bl block.
1342 * First, collect all required node pointers.
1345 nblock = nbody->parent;
1346 nprev = nblock->prev;
1347 nparent = nblock->parent;
1348 nnext = nchild->next;
1351 * Unlink this child.
1354 assert(nchild->prev == NULL);
1355 nbody->child = nnext;
1356 if (nnext == NULL)
1357 nbody->last = NULL;
1358 else
1359 nnext->prev = NULL;
1362 * Relink this child.
1365 nchild->parent = nparent;
1366 nchild->prev = nprev;
1367 nchild->next = nblock;
1369 nblock->prev = nchild;
1370 if (nprev == NULL)
1371 nparent->child = nchild;
1372 else
1373 nprev->next = nchild;
1375 nchild = nnext;
1379 static void
1380 post_bk(POST_ARGS)
1382 struct roff_node *n;
1384 n = mdoc->last;
1386 if (n->type == ROFFT_BLOCK && n->body->child == NULL) {
1387 mandoc_msg(MANDOCERR_BLK_EMPTY,
1388 mdoc->parse, n->line, n->pos, "Bk");
1389 roff_node_delete(mdoc, n);
1393 static void
1394 post_sm(POST_ARGS)
1396 struct roff_node *nch;
1398 nch = mdoc->last->child;
1400 if (nch == NULL) {
1401 mdoc->flags ^= MDOC_SMOFF;
1402 return;
1405 assert(nch->type == ROFFT_TEXT);
1407 if ( ! strcmp(nch->string, "on")) {
1408 mdoc->flags &= ~MDOC_SMOFF;
1409 return;
1411 if ( ! strcmp(nch->string, "off")) {
1412 mdoc->flags |= MDOC_SMOFF;
1413 return;
1416 mandoc_vmsg(MANDOCERR_SM_BAD,
1417 mdoc->parse, nch->line, nch->pos,
1418 "%s %s", mdoc_macronames[mdoc->last->tok], nch->string);
1419 mdoc_node_relink(mdoc, nch);
1420 return;
1423 static void
1424 post_root(POST_ARGS)
1426 struct roff_node *n;
1428 /* Add missing prologue data. */
1430 if (mdoc->meta.date == NULL)
1431 mdoc->meta.date = mdoc->quick ?
1432 mandoc_strdup("") :
1433 mandoc_normdate(mdoc->parse, NULL, 0, 0);
1435 if (mdoc->meta.title == NULL) {
1436 mandoc_msg(MANDOCERR_DT_NOTITLE,
1437 mdoc->parse, 0, 0, "EOF");
1438 mdoc->meta.title = mandoc_strdup("UNTITLED");
1441 if (mdoc->meta.vol == NULL)
1442 mdoc->meta.vol = mandoc_strdup("LOCAL");
1444 if (mdoc->meta.os == NULL) {
1445 mandoc_msg(MANDOCERR_OS_MISSING,
1446 mdoc->parse, 0, 0, NULL);
1447 mdoc->meta.os = mandoc_strdup("");
1450 /* Check that we begin with a proper `Sh'. */
1452 n = mdoc->first->child;
1453 while (n != NULL && n->tok != TOKEN_NONE &&
1454 mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
1455 n = n->next;
1457 if (n == NULL)
1458 mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
1459 else if (n->tok != MDOC_Sh)
1460 mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
1461 n->line, n->pos, mdoc_macronames[n->tok]);
1464 static void
1465 post_st(POST_ARGS)
1467 struct roff_node *n, *nch;
1468 const char *p;
1470 n = mdoc->last;
1471 nch = n->child;
1473 assert(nch->type == ROFFT_TEXT);
1475 if ((p = mdoc_a2st(nch->string)) == NULL) {
1476 mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
1477 nch->line, nch->pos, "St %s", nch->string);
1478 roff_node_delete(mdoc, n);
1479 } else {
1480 free(nch->string);
1481 nch->string = mandoc_strdup(p);
1485 static void
1486 post_rs(POST_ARGS)
1488 struct roff_node *np, *nch, *next, *prev;
1489 int i, j;
1491 np = mdoc->last;
1493 if (np->type != ROFFT_BODY)
1494 return;
1496 if (np->child == NULL) {
1497 mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse,
1498 np->line, np->pos, "Rs");
1499 return;
1503 * The full `Rs' block needs special handling to order the
1504 * sub-elements according to `rsord'. Pick through each element
1505 * and correctly order it. This is an insertion sort.
1508 next = NULL;
1509 for (nch = np->child->next; nch != NULL; nch = next) {
1510 /* Determine order number of this child. */
1511 for (i = 0; i < RSORD_MAX; i++)
1512 if (rsord[i] == nch->tok)
1513 break;
1515 if (i == RSORD_MAX) {
1516 mandoc_msg(MANDOCERR_RS_BAD,
1517 mdoc->parse, nch->line, nch->pos,
1518 mdoc_macronames[nch->tok]);
1519 i = -1;
1520 } else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
1521 np->norm->Rs.quote_T++;
1524 * Remove this child from the chain. This somewhat
1525 * repeats roff_node_unlink(), but since we're
1526 * just re-ordering, there's no need for the
1527 * full unlink process.
1530 if ((next = nch->next) != NULL)
1531 next->prev = nch->prev;
1533 if ((prev = nch->prev) != NULL)
1534 prev->next = nch->next;
1536 nch->prev = nch->next = NULL;
1539 * Scan back until we reach a node that's
1540 * to be ordered before this child.
1543 for ( ; prev ; prev = prev->prev) {
1544 /* Determine order of `prev'. */
1545 for (j = 0; j < RSORD_MAX; j++)
1546 if (rsord[j] == prev->tok)
1547 break;
1548 if (j == RSORD_MAX)
1549 j = -1;
1551 if (j <= i)
1552 break;
1556 * Set this child back into its correct place
1557 * in front of the `prev' node.
1560 nch->prev = prev;
1562 if (prev == NULL) {
1563 np->child->prev = nch;
1564 nch->next = np->child;
1565 np->child = nch;
1566 } else {
1567 if (prev->next)
1568 prev->next->prev = nch;
1569 nch->next = prev->next;
1570 prev->next = nch;
1576 * For some arguments of some macros,
1577 * convert all breakable hyphens into ASCII_HYPH.
1579 static void
1580 post_hyph(POST_ARGS)
1582 struct roff_node *nch;
1583 char *cp;
1585 for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
1586 if (nch->type != ROFFT_TEXT)
1587 continue;
1588 cp = nch->string;
1589 if (*cp == '\0')
1590 continue;
1591 while (*(++cp) != '\0')
1592 if (*cp == '-' &&
1593 isalpha((unsigned char)cp[-1]) &&
1594 isalpha((unsigned char)cp[1]))
1595 *cp = ASCII_HYPH;
1599 static void
1600 post_ns(POST_ARGS)
1603 if (mdoc->last->flags & MDOC_LINE)
1604 mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
1605 mdoc->last->line, mdoc->last->pos, NULL);
1608 static void
1609 post_sh(POST_ARGS)
1612 post_ignpar(mdoc);
1614 switch (mdoc->last->type) {
1615 case ROFFT_HEAD:
1616 post_sh_head(mdoc);
1617 break;
1618 case ROFFT_BODY:
1619 switch (mdoc->lastsec) {
1620 case SEC_NAME:
1621 post_sh_name(mdoc);
1622 break;
1623 case SEC_SEE_ALSO:
1624 post_sh_see_also(mdoc);
1625 break;
1626 case SEC_AUTHORS:
1627 post_sh_authors(mdoc);
1628 break;
1629 default:
1630 break;
1632 break;
1633 default:
1634 break;
1638 static void
1639 post_sh_name(POST_ARGS)
1641 struct roff_node *n;
1642 int hasnm, hasnd;
1644 hasnm = hasnd = 0;
1646 for (n = mdoc->last->child; n != NULL; n = n->next) {
1647 switch (n->tok) {
1648 case MDOC_Nm:
1649 hasnm = 1;
1650 break;
1651 case MDOC_Nd:
1652 hasnd = 1;
1653 if (n->next != NULL)
1654 mandoc_msg(MANDOCERR_NAMESEC_ND,
1655 mdoc->parse, n->line, n->pos, NULL);
1656 break;
1657 case TOKEN_NONE:
1658 if (hasnm)
1659 break;
1660 /* FALLTHROUGH */
1661 default:
1662 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1663 n->line, n->pos, mdoc_macronames[n->tok]);
1664 break;
1668 if ( ! hasnm)
1669 mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
1670 mdoc->last->line, mdoc->last->pos, NULL);
1671 if ( ! hasnd)
1672 mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
1673 mdoc->last->line, mdoc->last->pos, NULL);
1676 static void
1677 post_sh_see_also(POST_ARGS)
1679 const struct roff_node *n;
1680 const char *name, *sec;
1681 const char *lastname, *lastsec, *lastpunct;
1682 int cmp;
1684 n = mdoc->last->child;
1685 lastname = lastsec = lastpunct = NULL;
1686 while (n != NULL) {
1687 if (n->tok != MDOC_Xr ||
1688 n->child == NULL ||
1689 n->child->next == NULL)
1690 break;
1692 /* Process one .Xr node. */
1694 name = n->child->string;
1695 sec = n->child->next->string;
1696 if (lastsec != NULL) {
1697 if (lastpunct[0] != ',' || lastpunct[1] != '\0')
1698 mandoc_vmsg(MANDOCERR_XR_PUNCT,
1699 mdoc->parse, n->line, n->pos,
1700 "%s before %s(%s)", lastpunct,
1701 name, sec);
1702 cmp = strcmp(lastsec, sec);
1703 if (cmp > 0)
1704 mandoc_vmsg(MANDOCERR_XR_ORDER,
1705 mdoc->parse, n->line, n->pos,
1706 "%s(%s) after %s(%s)", name,
1707 sec, lastname, lastsec);
1708 else if (cmp == 0 &&
1709 strcasecmp(lastname, name) > 0)
1710 mandoc_vmsg(MANDOCERR_XR_ORDER,
1711 mdoc->parse, n->line, n->pos,
1712 "%s after %s", name, lastname);
1714 lastname = name;
1715 lastsec = sec;
1717 /* Process the following node. */
1719 n = n->next;
1720 if (n == NULL)
1721 break;
1722 if (n->tok == MDOC_Xr) {
1723 lastpunct = "none";
1724 continue;
1726 if (n->type != ROFFT_TEXT)
1727 break;
1728 for (name = n->string; *name != '\0'; name++)
1729 if (isalpha((const unsigned char)*name))
1730 return;
1731 lastpunct = n->string;
1732 if (n->next == NULL)
1733 mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
1734 n->line, n->pos, "%s after %s(%s)",
1735 lastpunct, lastname, lastsec);
1736 n = n->next;
1740 static int
1741 child_an(const struct roff_node *n)
1744 for (n = n->child; n != NULL; n = n->next)
1745 if ((n->tok == MDOC_An && n->child != NULL) || child_an(n))
1746 return 1;
1747 return 0;
1750 static void
1751 post_sh_authors(POST_ARGS)
1754 if ( ! child_an(mdoc->last))
1755 mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
1756 mdoc->last->line, mdoc->last->pos, NULL);
1759 static void
1760 post_sh_head(POST_ARGS)
1762 const char *goodsec;
1763 enum roff_sec sec;
1766 * Process a new section. Sections are either "named" or
1767 * "custom". Custom sections are user-defined, while named ones
1768 * follow a conventional order and may only appear in certain
1769 * manual sections.
1772 sec = mdoc->last->sec;
1774 /* The NAME should be first. */
1776 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1777 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
1778 mdoc->last->line, mdoc->last->pos,
1779 "Sh %s", secnames[sec]);
1781 /* The SYNOPSIS gets special attention in other areas. */
1783 if (sec == SEC_SYNOPSIS) {
1784 roff_setreg(mdoc->roff, "nS", 1, '=');
1785 mdoc->flags |= MDOC_SYNOPSIS;
1786 } else {
1787 roff_setreg(mdoc->roff, "nS", 0, '=');
1788 mdoc->flags &= ~MDOC_SYNOPSIS;
1791 /* Mark our last section. */
1793 mdoc->lastsec = sec;
1795 /* We don't care about custom sections after this. */
1797 if (sec == SEC_CUSTOM)
1798 return;
1801 * Check whether our non-custom section is being repeated or is
1802 * out of order.
1805 if (sec == mdoc->lastnamed)
1806 mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
1807 mdoc->last->line, mdoc->last->pos,
1808 "Sh %s", secnames[sec]);
1810 if (sec < mdoc->lastnamed)
1811 mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
1812 mdoc->last->line, mdoc->last->pos,
1813 "Sh %s", secnames[sec]);
1815 /* Mark the last named section. */
1817 mdoc->lastnamed = sec;
1819 /* Check particular section/manual conventions. */
1821 if (mdoc->meta.msec == NULL)
1822 return;
1824 goodsec = NULL;
1825 switch (sec) {
1826 case SEC_ERRORS:
1827 if (*mdoc->meta.msec == '4')
1828 break;
1829 goodsec = "2, 3, 4, 9";
1830 /* FALLTHROUGH */
1831 case SEC_RETURN_VALUES:
1832 case SEC_LIBRARY:
1833 if (*mdoc->meta.msec == '2')
1834 break;
1835 if (*mdoc->meta.msec == '3')
1836 break;
1837 if (NULL == goodsec)
1838 goodsec = "2, 3, 9";
1839 /* FALLTHROUGH */
1840 case SEC_CONTEXT:
1841 if (*mdoc->meta.msec == '9')
1842 break;
1843 if (NULL == goodsec)
1844 goodsec = "9";
1845 mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
1846 mdoc->last->line, mdoc->last->pos,
1847 "Sh %s for %s only", secnames[sec], goodsec);
1848 break;
1849 default:
1850 break;
1854 static void
1855 post_ignpar(POST_ARGS)
1857 struct roff_node *np;
1859 switch (mdoc->last->type) {
1860 case ROFFT_HEAD:
1861 post_hyph(mdoc);
1862 return;
1863 case ROFFT_BODY:
1864 break;
1865 default:
1866 return;
1869 if ((np = mdoc->last->child) != NULL)
1870 if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
1871 mandoc_vmsg(MANDOCERR_PAR_SKIP,
1872 mdoc->parse, np->line, np->pos,
1873 "%s after %s", mdoc_macronames[np->tok],
1874 mdoc_macronames[mdoc->last->tok]);
1875 roff_node_delete(mdoc, np);
1878 if ((np = mdoc->last->last) != NULL)
1879 if (np->tok == MDOC_Pp || np->tok == MDOC_Lp) {
1880 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
1881 np->line, np->pos, "%s at the end of %s",
1882 mdoc_macronames[np->tok],
1883 mdoc_macronames[mdoc->last->tok]);
1884 roff_node_delete(mdoc, np);
1888 static void
1889 post_prevpar(POST_ARGS)
1891 struct roff_node *n;
1893 n = mdoc->last;
1894 if (NULL == n->prev)
1895 return;
1896 if (n->type != ROFFT_ELEM && n->type != ROFFT_BLOCK)
1897 return;
1900 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
1901 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
1904 if (n->prev->tok != MDOC_Pp &&
1905 n->prev->tok != MDOC_Lp &&
1906 n->prev->tok != MDOC_br)
1907 return;
1908 if (n->tok == MDOC_Bl && n->norm->Bl.comp)
1909 return;
1910 if (n->tok == MDOC_Bd && n->norm->Bd.comp)
1911 return;
1912 if (n->tok == MDOC_It && n->parent->norm->Bl.comp)
1913 return;
1915 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
1916 n->prev->line, n->prev->pos,
1917 "%s before %s", mdoc_macronames[n->prev->tok],
1918 mdoc_macronames[n->tok]);
1919 roff_node_delete(mdoc, n->prev);
1922 static void
1923 post_par(POST_ARGS)
1925 struct roff_node *np;
1927 np = mdoc->last;
1928 if (np->tok != MDOC_br && np->tok != MDOC_sp)
1929 post_prevpar(mdoc);
1931 if (np->tok == MDOC_sp) {
1932 if (np->child != NULL && np->child->next != NULL)
1933 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1934 np->child->next->line, np->child->next->pos,
1935 "sp ... %s", np->child->next->string);
1936 } else if (np->child != NULL)
1937 mandoc_vmsg(MANDOCERR_ARG_SKIP,
1938 mdoc->parse, np->line, np->pos, "%s %s",
1939 mdoc_macronames[np->tok], np->child->string);
1941 if ((np = mdoc->last->prev) == NULL) {
1942 np = mdoc->last->parent;
1943 if (np->tok != MDOC_Sh && np->tok != MDOC_Ss)
1944 return;
1945 } else if (np->tok != MDOC_Pp && np->tok != MDOC_Lp &&
1946 (mdoc->last->tok != MDOC_br ||
1947 (np->tok != MDOC_sp && np->tok != MDOC_br)))
1948 return;
1950 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
1951 mdoc->last->line, mdoc->last->pos,
1952 "%s after %s", mdoc_macronames[mdoc->last->tok],
1953 mdoc_macronames[np->tok]);
1954 roff_node_delete(mdoc, mdoc->last);
1957 static void
1958 post_dd(POST_ARGS)
1960 struct roff_node *n;
1961 char *datestr;
1963 n = mdoc->last;
1964 if (mdoc->meta.date != NULL) {
1965 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
1966 n->line, n->pos, "Dd");
1967 free(mdoc->meta.date);
1968 } else if (mdoc->flags & MDOC_PBODY)
1969 mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
1970 n->line, n->pos, "Dd");
1971 else if (mdoc->meta.title != NULL)
1972 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
1973 n->line, n->pos, "Dd after Dt");
1974 else if (mdoc->meta.os != NULL)
1975 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
1976 n->line, n->pos, "Dd after Os");
1978 if (n->child == NULL || n->child->string[0] == '\0') {
1979 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
1980 mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
1981 goto out;
1984 datestr = NULL;
1985 deroff(&datestr, n);
1986 if (mdoc->quick)
1987 mdoc->meta.date = datestr;
1988 else {
1989 mdoc->meta.date = mandoc_normdate(mdoc->parse,
1990 datestr, n->line, n->pos);
1991 free(datestr);
1993 out:
1994 roff_node_delete(mdoc, n);
1997 static void
1998 post_dt(POST_ARGS)
2000 struct roff_node *nn, *n;
2001 const char *cp;
2002 char *p;
2004 n = mdoc->last;
2005 if (mdoc->flags & MDOC_PBODY) {
2006 mandoc_msg(MANDOCERR_DT_LATE, mdoc->parse,
2007 n->line, n->pos, "Dt");
2008 goto out;
2011 if (mdoc->meta.title != NULL)
2012 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
2013 n->line, n->pos, "Dt");
2014 else if (mdoc->meta.os != NULL)
2015 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
2016 n->line, n->pos, "Dt after Os");
2018 free(mdoc->meta.title);
2019 free(mdoc->meta.msec);
2020 free(mdoc->meta.vol);
2021 free(mdoc->meta.arch);
2023 mdoc->meta.title = NULL;
2024 mdoc->meta.msec = NULL;
2025 mdoc->meta.vol = NULL;
2026 mdoc->meta.arch = NULL;
2028 /* Mandatory first argument: title. */
2030 nn = n->child;
2031 if (nn == NULL || *nn->string == '\0') {
2032 mandoc_msg(MANDOCERR_DT_NOTITLE,
2033 mdoc->parse, n->line, n->pos, "Dt");
2034 mdoc->meta.title = mandoc_strdup("UNTITLED");
2035 } else {
2036 mdoc->meta.title = mandoc_strdup(nn->string);
2038 /* Check that all characters are uppercase. */
2040 for (p = nn->string; *p != '\0'; p++)
2041 if (islower((unsigned char)*p)) {
2042 mandoc_vmsg(MANDOCERR_TITLE_CASE,
2043 mdoc->parse, nn->line,
2044 nn->pos + (p - nn->string),
2045 "Dt %s", nn->string);
2046 break;
2050 /* Mandatory second argument: section. */
2052 if (nn != NULL)
2053 nn = nn->next;
2055 if (nn == NULL) {
2056 mandoc_vmsg(MANDOCERR_MSEC_MISSING,
2057 mdoc->parse, n->line, n->pos,
2058 "Dt %s", mdoc->meta.title);
2059 mdoc->meta.vol = mandoc_strdup("LOCAL");
2060 goto out; /* msec and arch remain NULL. */
2063 mdoc->meta.msec = mandoc_strdup(nn->string);
2065 /* Infer volume title from section number. */
2067 cp = mandoc_a2msec(nn->string);
2068 if (cp == NULL) {
2069 mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
2070 nn->line, nn->pos, "Dt ... %s", nn->string);
2071 mdoc->meta.vol = mandoc_strdup(nn->string);
2072 } else
2073 mdoc->meta.vol = mandoc_strdup(cp);
2075 /* Optional third argument: architecture. */
2077 if ((nn = nn->next) == NULL)
2078 goto out;
2080 for (p = nn->string; *p != '\0'; p++)
2081 *p = tolower((unsigned char)*p);
2082 mdoc->meta.arch = mandoc_strdup(nn->string);
2084 /* Ignore fourth and later arguments. */
2086 if ((nn = nn->next) != NULL)
2087 mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
2088 nn->line, nn->pos, "Dt ... %s", nn->string);
2090 out:
2091 roff_node_delete(mdoc, n);
2094 static void
2095 post_bx(POST_ARGS)
2097 struct roff_node *n;
2100 * Make `Bx's second argument always start with an uppercase
2101 * letter. Groff checks if it's an "accepted" term, but we just
2102 * uppercase blindly.
2105 if ((n = mdoc->last->child) != NULL && (n = n->next) != NULL)
2106 *n->string = (char)toupper((unsigned char)*n->string);
2109 static void
2110 post_os(POST_ARGS)
2112 #ifndef OSNAME
2113 struct utsname utsname;
2114 static char *defbuf;
2115 #endif
2116 struct roff_node *n;
2118 n = mdoc->last;
2119 if (mdoc->meta.os != NULL)
2120 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
2121 n->line, n->pos, "Os");
2122 else if (mdoc->flags & MDOC_PBODY)
2123 mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
2124 n->line, n->pos, "Os");
2127 * Set the operating system by way of the `Os' macro.
2128 * The order of precedence is:
2129 * 1. the argument of the `Os' macro, unless empty
2130 * 2. the -Ios=foo command line argument, if provided
2131 * 3. -DOSNAME="\"foo\"", if provided during compilation
2132 * 4. "sysname release" from uname(3)
2135 free(mdoc->meta.os);
2136 mdoc->meta.os = NULL;
2137 deroff(&mdoc->meta.os, n);
2138 if (mdoc->meta.os)
2139 goto out;
2141 if (mdoc->defos) {
2142 mdoc->meta.os = mandoc_strdup(mdoc->defos);
2143 goto out;
2146 #ifdef OSNAME
2147 mdoc->meta.os = mandoc_strdup(OSNAME);
2148 #else /*!OSNAME */
2149 if (defbuf == NULL) {
2150 if (uname(&utsname) == -1) {
2151 mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
2152 n->line, n->pos, "Os");
2153 defbuf = mandoc_strdup("UNKNOWN");
2154 } else
2155 mandoc_asprintf(&defbuf, "%s %s",
2156 utsname.sysname, utsname.release);
2158 mdoc->meta.os = mandoc_strdup(defbuf);
2159 #endif /*!OSNAME*/
2161 out:
2162 roff_node_delete(mdoc, n);
2166 * If no argument is provided,
2167 * fill in the name of the current manual page.
2169 static void
2170 post_ex(POST_ARGS)
2172 struct roff_node *n;
2174 post_std(mdoc);
2176 n = mdoc->last;
2177 if (n->child != NULL)
2178 return;
2180 if (mdoc->meta.name == NULL) {
2181 mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
2182 n->line, n->pos, "Ex");
2183 return;
2186 mdoc->next = ROFF_NEXT_CHILD;
2187 roff_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
2188 mdoc->last = n;
2191 enum roff_sec
2192 mdoc_a2sec(const char *p)
2194 int i;
2196 for (i = 0; i < (int)SEC__MAX; i++)
2197 if (secnames[i] && 0 == strcmp(p, secnames[i]))
2198 return (enum roff_sec)i;
2200 return SEC_CUSTOM;
2203 static size_t
2204 macro2len(int macro)
2207 switch (macro) {
2208 case MDOC_Ad:
2209 return 12;
2210 case MDOC_Ao:
2211 return 12;
2212 case MDOC_An:
2213 return 12;
2214 case MDOC_Aq:
2215 return 12;
2216 case MDOC_Ar:
2217 return 12;
2218 case MDOC_Bo:
2219 return 12;
2220 case MDOC_Bq:
2221 return 12;
2222 case MDOC_Cd:
2223 return 12;
2224 case MDOC_Cm:
2225 return 10;
2226 case MDOC_Do:
2227 return 10;
2228 case MDOC_Dq:
2229 return 12;
2230 case MDOC_Dv:
2231 return 12;
2232 case MDOC_Eo:
2233 return 12;
2234 case MDOC_Em:
2235 return 10;
2236 case MDOC_Er:
2237 return 17;
2238 case MDOC_Ev:
2239 return 15;
2240 case MDOC_Fa:
2241 return 12;
2242 case MDOC_Fl:
2243 return 10;
2244 case MDOC_Fo:
2245 return 16;
2246 case MDOC_Fn:
2247 return 16;
2248 case MDOC_Ic:
2249 return 10;
2250 case MDOC_Li:
2251 return 16;
2252 case MDOC_Ms:
2253 return 6;
2254 case MDOC_Nm:
2255 return 10;
2256 case MDOC_No:
2257 return 12;
2258 case MDOC_Oo:
2259 return 10;
2260 case MDOC_Op:
2261 return 14;
2262 case MDOC_Pa:
2263 return 32;
2264 case MDOC_Pf:
2265 return 12;
2266 case MDOC_Po:
2267 return 12;
2268 case MDOC_Pq:
2269 return 12;
2270 case MDOC_Ql:
2271 return 16;
2272 case MDOC_Qo:
2273 return 12;
2274 case MDOC_So:
2275 return 12;
2276 case MDOC_Sq:
2277 return 12;
2278 case MDOC_Sy:
2279 return 6;
2280 case MDOC_Sx:
2281 return 16;
2282 case MDOC_Tn:
2283 return 10;
2284 case MDOC_Va:
2285 return 12;
2286 case MDOC_Vt:
2287 return 12;
2288 case MDOC_Xr:
2289 return 10;
2290 default:
2291 break;
2293 return 0;