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