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