]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
document the semantics of operation keywords
[mandoc.git] / mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.251 2014/10/11 21:34:04 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 size_t pos;
1009
1010 n = mdoc->last->child;
1011 pos = strcspn(n->string, "()");
1012 if (n->string[pos] != '\0')
1013 mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
1014 n->line, n->pos + pos, n->string);
1015 return(1);
1016 }
1017
1018 static int
1019 post_fn(POST_ARGS)
1020 {
1021
1022 post_fname(mdoc);
1023 post_fa(mdoc);
1024 return(1);
1025 }
1026
1027 static int
1028 post_fo(POST_ARGS)
1029 {
1030
1031 hwarn_eq1(mdoc);
1032 bwarn_ge1(mdoc);
1033 if (mdoc->last->type == MDOC_HEAD && mdoc->last->nchild)
1034 post_fname(mdoc);
1035 return(1);
1036 }
1037
1038 static int
1039 post_fa(POST_ARGS)
1040 {
1041 const struct mdoc_node *n;
1042 const char *cp;
1043
1044 for (n = mdoc->last->child; n != NULL; n = n->next) {
1045 for (cp = n->string; *cp != '\0'; cp++) {
1046 /* Ignore callbacks and alterations. */
1047 if (*cp == '(' || *cp == '{')
1048 break;
1049 if (*cp != ',')
1050 continue;
1051 mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
1052 n->line, n->pos + (cp - n->string),
1053 n->string);
1054 break;
1055 }
1056 }
1057 return(1);
1058 }
1059
1060 static int
1061 post_vt(POST_ARGS)
1062 {
1063 const struct mdoc_node *n;
1064
1065 /*
1066 * The Vt macro comes in both ELEM and BLOCK form, both of which
1067 * have different syntaxes (yet more context-sensitive
1068 * behaviour). ELEM types must have a child, which is already
1069 * guaranteed by the in_line parsing routine; BLOCK types,
1070 * specifically the BODY, should only have TEXT children.
1071 */
1072
1073 if (MDOC_BODY != mdoc->last->type)
1074 return(1);
1075
1076 for (n = mdoc->last->child; n; n = n->next)
1077 if (MDOC_TEXT != n->type)
1078 mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse,
1079 n->line, n->pos, mdoc_macronames[n->tok]);
1080
1081 return(1);
1082 }
1083
1084 static int
1085 post_nm(POST_ARGS)
1086 {
1087
1088 if (NULL != mdoc->meta.name)
1089 return(1);
1090
1091 mdoc_deroff(&mdoc->meta.name, mdoc->last);
1092
1093 if (NULL == mdoc->meta.name)
1094 mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
1095 mdoc->last->line, mdoc->last->pos, "Nm");
1096 return(1);
1097 }
1098
1099 static int
1100 post_nd(POST_ARGS)
1101 {
1102
1103 berr_ge1(mdoc);
1104 return(post_hyph(mdoc));
1105 }
1106
1107 static int
1108 post_d1(POST_ARGS)
1109 {
1110
1111 bwarn_ge1(mdoc);
1112 return(post_hyph(mdoc));
1113 }
1114
1115 static int
1116 post_literal(POST_ARGS)
1117 {
1118
1119 if (mdoc->last->tok == MDOC_Bd)
1120 hwarn_eq0(mdoc);
1121 bwarn_ge1(mdoc);
1122
1123 /*
1124 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1125 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1126 * this in literal mode, but it doesn't hurt to just switch it
1127 * off in general since displays can't be nested.
1128 */
1129
1130 if (MDOC_BODY == mdoc->last->type)
1131 mdoc->flags &= ~MDOC_LITERAL;
1132
1133 return(1);
1134 }
1135
1136 static int
1137 post_defaults(POST_ARGS)
1138 {
1139 struct mdoc_node *nn;
1140
1141 /*
1142 * The `Ar' defaults to "file ..." if no value is provided as an
1143 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1144 * gets an empty string.
1145 */
1146
1147 if (mdoc->last->child)
1148 return(1);
1149
1150 nn = mdoc->last;
1151 mdoc->next = MDOC_NEXT_CHILD;
1152
1153 switch (nn->tok) {
1154 case MDOC_Ar:
1155 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
1156 return(0);
1157 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
1158 return(0);
1159 break;
1160 case MDOC_Li:
1161 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
1162 return(0);
1163 break;
1164 case MDOC_Pa:
1165 /* FALLTHROUGH */
1166 case MDOC_Mt:
1167 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
1168 return(0);
1169 break;
1170 default:
1171 abort();
1172 /* NOTREACHED */
1173 }
1174
1175 mdoc->last = nn;
1176 return(1);
1177 }
1178
1179 static int
1180 post_at(POST_ARGS)
1181 {
1182 struct mdoc_node *n;
1183 const char *std_att;
1184 char *att;
1185
1186 n = mdoc->last;
1187 if (n->child == NULL) {
1188 mdoc->next = MDOC_NEXT_CHILD;
1189 if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX"))
1190 return(0);
1191 mdoc->last = n;
1192 return(1);
1193 }
1194
1195 /*
1196 * If we have a child, look it up in the standard keys. If a
1197 * key exist, use that instead of the child; if it doesn't,
1198 * prefix "AT&T UNIX " to the existing data.
1199 */
1200
1201 n = n->child;
1202 assert(MDOC_TEXT == n->type);
1203 if (NULL == (std_att = mdoc_a2att(n->string))) {
1204 mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
1205 n->line, n->pos, "At %s", n->string);
1206 mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
1207 } else
1208 att = mandoc_strdup(std_att);
1209
1210 free(n->string);
1211 n->string = att;
1212 return(1);
1213 }
1214
1215 static int
1216 post_an(POST_ARGS)
1217 {
1218 struct mdoc_node *np;
1219
1220 np = mdoc->last;
1221 if (AUTH__NONE == np->norm->An.auth) {
1222 if (0 == np->child)
1223 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
1224 } else if (np->child)
1225 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
1226
1227 return(1);
1228 }
1229
1230 static int
1231 post_en(POST_ARGS)
1232 {
1233
1234 if (MDOC_BLOCK == mdoc->last->type)
1235 mdoc->last->norm->Es = mdoc->last_es;
1236 return(1);
1237 }
1238
1239 static int
1240 post_es(POST_ARGS)
1241 {
1242
1243 mdoc->last_es = mdoc->last;
1244 return(1);
1245 }
1246
1247 static int
1248 post_it(POST_ARGS)
1249 {
1250 int i, cols;
1251 enum mdoc_list lt;
1252 struct mdoc_node *nbl, *nit, *nch;
1253
1254 nit = mdoc->last;
1255 if (MDOC_BLOCK != nit->type)
1256 return(1);
1257
1258 nbl = nit->parent->parent;
1259 lt = nbl->norm->Bl.type;
1260
1261 switch (lt) {
1262 case LIST_tag:
1263 /* FALLTHROUGH */
1264 case LIST_hang:
1265 /* FALLTHROUGH */
1266 case LIST_ohang:
1267 /* FALLTHROUGH */
1268 case LIST_inset:
1269 /* FALLTHROUGH */
1270 case LIST_diag:
1271 if (NULL == nit->head->child)
1272 mandoc_vmsg(MANDOCERR_IT_NOHEAD,
1273 mdoc->parse, nit->line, nit->pos,
1274 "Bl -%s It",
1275 mdoc_argnames[nbl->args->argv[0].arg]);
1276 break;
1277 case LIST_bullet:
1278 /* FALLTHROUGH */
1279 case LIST_dash:
1280 /* FALLTHROUGH */
1281 case LIST_enum:
1282 /* FALLTHROUGH */
1283 case LIST_hyphen:
1284 if (NULL == nit->body->child)
1285 mandoc_vmsg(MANDOCERR_IT_NOBODY,
1286 mdoc->parse, nit->line, nit->pos,
1287 "Bl -%s It",
1288 mdoc_argnames[nbl->args->argv[0].arg]);
1289 /* FALLTHROUGH */
1290 case LIST_item:
1291 if (NULL != nit->head->child)
1292 mandoc_vmsg(MANDOCERR_ARG_SKIP,
1293 mdoc->parse, nit->line, nit->pos,
1294 "It %s", nit->head->child->string);
1295 break;
1296 case LIST_column:
1297 cols = (int)nbl->norm->Bl.ncols;
1298
1299 assert(NULL == nit->head->child);
1300
1301 for (i = 0, nch = nit->child; nch; nch = nch->next)
1302 if (MDOC_BODY == nch->type)
1303 i++;
1304
1305 if (i < cols || i > cols + 1)
1306 mandoc_vmsg(MANDOCERR_ARGCOUNT,
1307 mdoc->parse, nit->line, nit->pos,
1308 "columns == %d (have %d)", cols, i);
1309 break;
1310 default:
1311 abort();
1312 }
1313
1314 return(1);
1315 }
1316
1317 static int
1318 post_bl_block(POST_ARGS)
1319 {
1320 struct mdoc_node *n, *ni, *nc;
1321
1322 /*
1323 * These are fairly complicated, so we've broken them into two
1324 * functions. post_bl_block_tag() is called when a -tag is
1325 * specified, but no -width (it must be guessed). The second
1326 * when a -width is specified (macro indicators must be
1327 * rewritten into real lengths).
1328 */
1329
1330 n = mdoc->last;
1331
1332 if (LIST_tag == n->norm->Bl.type &&
1333 NULL == n->norm->Bl.width) {
1334 if ( ! post_bl_block_tag(mdoc))
1335 return(0);
1336 assert(n->norm->Bl.width);
1337 } else if (NULL != n->norm->Bl.width) {
1338 if ( ! post_bl_block_width(mdoc))
1339 return(0);
1340 assert(n->norm->Bl.width);
1341 }
1342
1343 for (ni = n->body->child; ni; ni = ni->next) {
1344 if (NULL == ni->body)
1345 continue;
1346 nc = ni->body->last;
1347 while (NULL != nc) {
1348 switch (nc->tok) {
1349 case MDOC_Pp:
1350 /* FALLTHROUGH */
1351 case MDOC_Lp:
1352 /* FALLTHROUGH */
1353 case MDOC_br:
1354 break;
1355 default:
1356 nc = NULL;
1357 continue;
1358 }
1359 if (NULL == ni->next) {
1360 mandoc_msg(MANDOCERR_PAR_MOVE,
1361 mdoc->parse, nc->line, nc->pos,
1362 mdoc_macronames[nc->tok]);
1363 if ( ! mdoc_node_relink(mdoc, nc))
1364 return(0);
1365 } else if (0 == n->norm->Bl.comp &&
1366 LIST_column != n->norm->Bl.type) {
1367 mandoc_vmsg(MANDOCERR_PAR_SKIP,
1368 mdoc->parse, nc->line, nc->pos,
1369 "%s before It",
1370 mdoc_macronames[nc->tok]);
1371 mdoc_node_delete(mdoc, nc);
1372 } else
1373 break;
1374 nc = ni->body->last;
1375 }
1376 }
1377 return(1);
1378 }
1379
1380 static int
1381 post_bl_block_width(POST_ARGS)
1382 {
1383 size_t width;
1384 int i;
1385 enum mdoct tok;
1386 struct mdoc_node *n;
1387 char buf[24];
1388
1389 n = mdoc->last;
1390
1391 /*
1392 * Calculate the real width of a list from the -width string,
1393 * which may contain a macro (with a known default width), a
1394 * literal string, or a scaling width.
1395 *
1396 * If the value to -width is a macro, then we re-write it to be
1397 * the macro's width as set in share/tmac/mdoc/doc-common.
1398 */
1399
1400 if (0 == strcmp(n->norm->Bl.width, "Ds"))
1401 width = 6;
1402 else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
1403 return(1);
1404 else
1405 width = macro2len(tok);
1406
1407 /* The value already exists: free and reallocate it. */
1408
1409 assert(n->args);
1410
1411 for (i = 0; i < (int)n->args->argc; i++)
1412 if (MDOC_Width == n->args->argv[i].arg)
1413 break;
1414
1415 assert(i < (int)n->args->argc);
1416
1417 (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)width);
1418 free(n->args->argv[i].value[0]);
1419 n->args->argv[i].value[0] = mandoc_strdup(buf);
1420
1421 /* Set our width! */
1422 n->norm->Bl.width = n->args->argv[i].value[0];
1423 return(1);
1424 }
1425
1426 static int
1427 post_bl_block_tag(POST_ARGS)
1428 {
1429 struct mdoc_node *n, *nn;
1430 size_t sz, ssz;
1431 int i;
1432 char buf[24];
1433
1434 /*
1435 * Calculate the -width for a `Bl -tag' list if it hasn't been
1436 * provided. Uses the first head macro. NOTE AGAIN: this is
1437 * ONLY if the -width argument has NOT been provided. See
1438 * post_bl_block_width() for converting the -width string.
1439 */
1440
1441 sz = 10;
1442 n = mdoc->last;
1443
1444 for (nn = n->body->child; nn; nn = nn->next) {
1445 if (MDOC_It != nn->tok)
1446 continue;
1447
1448 assert(MDOC_BLOCK == nn->type);
1449 nn = nn->head->child;
1450
1451 if (nn == NULL)
1452 break;
1453
1454 if (MDOC_TEXT == nn->type) {
1455 sz = strlen(nn->string) + 1;
1456 break;
1457 }
1458
1459 if (0 != (ssz = macro2len(nn->tok)))
1460 sz = ssz;
1461
1462 break;
1463 }
1464
1465 /* Defaults to ten ens. */
1466
1467 (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
1468
1469 /*
1470 * We have to dynamically add this to the macro's argument list.
1471 * We're guaranteed that a MDOC_Width doesn't already exist.
1472 */
1473
1474 assert(n->args);
1475 i = (int)(n->args->argc)++;
1476
1477 n->args->argv = mandoc_reallocarray(n->args->argv,
1478 n->args->argc, sizeof(struct mdoc_argv));
1479
1480 n->args->argv[i].arg = MDOC_Width;
1481 n->args->argv[i].line = n->line;
1482 n->args->argv[i].pos = n->pos;
1483 n->args->argv[i].sz = 1;
1484 n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1485 n->args->argv[i].value[0] = mandoc_strdup(buf);
1486
1487 /* Set our width! */
1488 n->norm->Bl.width = n->args->argv[i].value[0];
1489 return(1);
1490 }
1491
1492 static int
1493 post_bl_head(POST_ARGS)
1494 {
1495 struct mdoc_node *np, *nn, *nnp;
1496 struct mdoc_argv *argv;
1497 int i, j;
1498
1499 if (LIST_column != mdoc->last->norm->Bl.type)
1500 /* FIXME: this should be ERROR class... */
1501 return(hwarn_eq0(mdoc));
1502
1503 /*
1504 * Append old-style lists, where the column width specifiers
1505 * trail as macro parameters, to the new-style ("normal-form")
1506 * lists where they're argument values following -column.
1507 */
1508
1509 if (mdoc->last->child == NULL)
1510 return(1);
1511
1512 np = mdoc->last->parent;
1513 assert(np->args);
1514
1515 for (j = 0; j < (int)np->args->argc; j++)
1516 if (MDOC_Column == np->args->argv[j].arg)
1517 break;
1518
1519 assert(j < (int)np->args->argc);
1520
1521 /*
1522 * Accommodate for new-style groff column syntax. Shuffle the
1523 * child nodes, all of which must be TEXT, as arguments for the
1524 * column field. Then, delete the head children.
1525 */
1526
1527 argv = np->args->argv + j;
1528 i = argv->sz;
1529 argv->sz += mdoc->last->nchild;
1530 argv->value = mandoc_reallocarray(argv->value,
1531 argv->sz, sizeof(char *));
1532
1533 mdoc->last->norm->Bl.ncols = argv->sz;
1534 mdoc->last->norm->Bl.cols = (void *)argv->value;
1535
1536 for (nn = mdoc->last->child; nn; i++) {
1537 argv->value[i] = nn->string;
1538 nn->string = NULL;
1539 nnp = nn;
1540 nn = nn->next;
1541 mdoc_node_delete(NULL, nnp);
1542 }
1543
1544 mdoc->last->nchild = 0;
1545 mdoc->last->child = NULL;
1546
1547 return(1);
1548 }
1549
1550 static int
1551 post_bl(POST_ARGS)
1552 {
1553 struct mdoc_node *nparent, *nprev; /* of the Bl block */
1554 struct mdoc_node *nblock, *nbody; /* of the Bl */
1555 struct mdoc_node *nchild, *nnext; /* of the Bl body */
1556
1557 nbody = mdoc->last;
1558 switch (nbody->type) {
1559 case MDOC_BLOCK:
1560 return(post_bl_block(mdoc));
1561 case MDOC_HEAD:
1562 return(post_bl_head(mdoc));
1563 case MDOC_BODY:
1564 break;
1565 default:
1566 return(1);
1567 }
1568
1569 bwarn_ge1(mdoc);
1570
1571 nchild = nbody->child;
1572 while (NULL != nchild) {
1573 if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
1574 nchild = nchild->next;
1575 continue;
1576 }
1577
1578 mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
1579 nchild->line, nchild->pos,
1580 mdoc_macronames[nchild->tok]);
1581
1582 /*
1583 * Move the node out of the Bl block.
1584 * First, collect all required node pointers.
1585 */
1586
1587 nblock = nbody->parent;
1588 nprev = nblock->prev;
1589 nparent = nblock->parent;
1590 nnext = nchild->next;
1591
1592 /*
1593 * Unlink this child.
1594 */
1595
1596 assert(NULL == nchild->prev);
1597 if (0 == --nbody->nchild) {
1598 nbody->child = NULL;
1599 nbody->last = NULL;
1600 assert(NULL == nnext);
1601 } else {
1602 nbody->child = nnext;
1603 nnext->prev = NULL;
1604 }
1605
1606 /*
1607 * Relink this child.
1608 */
1609
1610 nchild->parent = nparent;
1611 nchild->prev = nprev;
1612 nchild->next = nblock;
1613
1614 nblock->prev = nchild;
1615 nparent->nchild++;
1616 if (NULL == nprev)
1617 nparent->child = nchild;
1618 else
1619 nprev->next = nchild;
1620
1621 nchild = nnext;
1622 }
1623
1624 return(1);
1625 }
1626
1627 static int
1628 post_bk(POST_ARGS)
1629 {
1630
1631 hwarn_eq0(mdoc);
1632 bwarn_ge1(mdoc);
1633 return(1);
1634 }
1635
1636 static int
1637 ebool(struct mdoc *mdoc)
1638 {
1639 struct mdoc_node *nch;
1640 enum mdoct tok;
1641
1642 tok = mdoc->last->tok;
1643 nch = mdoc->last->child;
1644
1645 if (NULL == nch) {
1646 if (MDOC_Sm == tok)
1647 mdoc->flags ^= MDOC_SMOFF;
1648 return(1);
1649 }
1650
1651 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2);
1652
1653 assert(MDOC_TEXT == nch->type);
1654
1655 if (0 == strcmp(nch->string, "on")) {
1656 if (MDOC_Sm == tok)
1657 mdoc->flags &= ~MDOC_SMOFF;
1658 return(1);
1659 }
1660 if (0 == strcmp(nch->string, "off")) {
1661 if (MDOC_Sm == tok)
1662 mdoc->flags |= MDOC_SMOFF;
1663 return(1);
1664 }
1665
1666 mandoc_vmsg(MANDOCERR_SM_BAD,
1667 mdoc->parse, nch->line, nch->pos,
1668 "%s %s", mdoc_macronames[tok], nch->string);
1669 return(mdoc_node_relink(mdoc, nch));
1670 }
1671
1672 static int
1673 post_root(POST_ARGS)
1674 {
1675 struct mdoc_node *n;
1676
1677 /* Add missing prologue data. */
1678
1679 if (mdoc->meta.date == NULL)
1680 mdoc->meta.date = mdoc->quick ?
1681 mandoc_strdup("") :
1682 mandoc_normdate(mdoc->parse, NULL, 0, 0);
1683
1684 if (mdoc->meta.title == NULL) {
1685 mandoc_msg(MANDOCERR_DT_NOTITLE,
1686 mdoc->parse, 0, 0, "EOF");
1687 mdoc->meta.title = mandoc_strdup("UNTITLED");
1688 }
1689
1690 if (mdoc->meta.vol == NULL)
1691 mdoc->meta.vol = mandoc_strdup("LOCAL");
1692
1693 if (mdoc->meta.os == NULL) {
1694 mandoc_msg(MANDOCERR_OS_MISSING,
1695 mdoc->parse, 0, 0, NULL);
1696 mdoc->meta.os = mandoc_strdup("");
1697 }
1698
1699 /* Check that we begin with a proper `Sh'. */
1700
1701 n = mdoc->first->child;
1702 while (n != NULL && mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
1703 n = n->next;
1704
1705 if (n == NULL)
1706 mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
1707 else if (n->tok != MDOC_Sh)
1708 mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
1709 n->line, n->pos, mdoc_macronames[n->tok]);
1710
1711 return(1);
1712 }
1713
1714 static int
1715 post_st(POST_ARGS)
1716 {
1717 struct mdoc_node *n, *nch;
1718 const char *p;
1719
1720 n = mdoc->last;
1721 nch = n->child;
1722
1723 if (NULL == nch) {
1724 mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
1725 n->line, n->pos, mdoc_macronames[n->tok]);
1726 mdoc_node_delete(mdoc, n);
1727 return(1);
1728 }
1729
1730 assert(MDOC_TEXT == nch->type);
1731
1732 if (NULL == (p = mdoc_a2st(nch->string))) {
1733 mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
1734 nch->line, nch->pos, "St %s", nch->string);
1735 mdoc_node_delete(mdoc, n);
1736 } else {
1737 free(nch->string);
1738 nch->string = mandoc_strdup(p);
1739 }
1740
1741 return(1);
1742 }
1743
1744 static int
1745 post_rs(POST_ARGS)
1746 {
1747 struct mdoc_node *nn, *next, *prev;
1748 int i, j;
1749
1750 switch (mdoc->last->type) {
1751 case MDOC_HEAD:
1752 check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
1753 return(1);
1754 case MDOC_BODY:
1755 if (mdoc->last->child)
1756 break;
1757 check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
1758 return(1);
1759 default:
1760 return(1);
1761 }
1762
1763 /*
1764 * The full `Rs' block needs special handling to order the
1765 * sub-elements according to `rsord'. Pick through each element
1766 * and correctly order it. This is an insertion sort.
1767 */
1768
1769 next = NULL;
1770 for (nn = mdoc->last->child->next; nn; nn = next) {
1771 /* Determine order of `nn'. */
1772 for (i = 0; i < RSORD_MAX; i++)
1773 if (rsord[i] == nn->tok)
1774 break;
1775
1776 if (i == RSORD_MAX) {
1777 mandoc_msg(MANDOCERR_RS_BAD,
1778 mdoc->parse, nn->line, nn->pos,
1779 mdoc_macronames[nn->tok]);
1780 i = -1;
1781 } else if (MDOC__J == nn->tok || MDOC__B == nn->tok)
1782 mdoc->last->norm->Rs.quote_T++;
1783
1784 /*
1785 * Remove `nn' from the chain. This somewhat
1786 * repeats mdoc_node_unlink(), but since we're
1787 * just re-ordering, there's no need for the
1788 * full unlink process.
1789 */
1790
1791 if (NULL != (next = nn->next))
1792 next->prev = nn->prev;
1793
1794 if (NULL != (prev = nn->prev))
1795 prev->next = nn->next;
1796
1797 nn->prev = nn->next = NULL;
1798
1799 /*
1800 * Scan back until we reach a node that's
1801 * ordered before `nn'.
1802 */
1803
1804 for ( ; prev ; prev = prev->prev) {
1805 /* Determine order of `prev'. */
1806 for (j = 0; j < RSORD_MAX; j++)
1807 if (rsord[j] == prev->tok)
1808 break;
1809 if (j == RSORD_MAX)
1810 j = -1;
1811
1812 if (j <= i)
1813 break;
1814 }
1815
1816 /*
1817 * Set `nn' back into its correct place in front
1818 * of the `prev' node.
1819 */
1820
1821 nn->prev = prev;
1822
1823 if (prev) {
1824 if (prev->next)
1825 prev->next->prev = nn;
1826 nn->next = prev->next;
1827 prev->next = nn;
1828 } else {
1829 mdoc->last->child->prev = nn;
1830 nn->next = mdoc->last->child;
1831 mdoc->last->child = nn;
1832 }
1833 }
1834
1835 return(1);
1836 }
1837
1838 /*
1839 * For some arguments of some macros,
1840 * convert all breakable hyphens into ASCII_HYPH.
1841 */
1842 static int
1843 post_hyph(POST_ARGS)
1844 {
1845 struct mdoc_node *n, *nch;
1846 char *cp;
1847
1848 n = mdoc->last;
1849 switch (n->type) {
1850 case MDOC_HEAD:
1851 if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
1852 break;
1853 return(1);
1854 case MDOC_BODY:
1855 if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
1856 break;
1857 return(1);
1858 case MDOC_ELEM:
1859 break;
1860 default:
1861 return(1);
1862 }
1863
1864 for (nch = n->child; nch; nch = nch->next) {
1865 if (MDOC_TEXT != nch->type)
1866 continue;
1867 cp = nch->string;
1868 if ('\0' == *cp)
1869 continue;
1870 while ('\0' != *(++cp))
1871 if ('-' == *cp &&
1872 isalpha((unsigned char)cp[-1]) &&
1873 isalpha((unsigned char)cp[1]))
1874 *cp = ASCII_HYPH;
1875 }
1876 return(1);
1877 }
1878
1879 static int
1880 post_hyphtext(POST_ARGS)
1881 {
1882
1883 ewarn_ge1(mdoc);
1884 return(post_hyph(mdoc));
1885 }
1886
1887 static int
1888 post_ns(POST_ARGS)
1889 {
1890
1891 if (MDOC_LINE & mdoc->last->flags)
1892 mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
1893 mdoc->last->line, mdoc->last->pos, NULL);
1894 return(1);
1895 }
1896
1897 static int
1898 post_sh(POST_ARGS)
1899 {
1900
1901 post_ignpar(mdoc);
1902
1903 switch (mdoc->last->type) {
1904 case MDOC_HEAD:
1905 return(post_sh_head(mdoc));
1906 case MDOC_BODY:
1907 switch (mdoc->lastsec) {
1908 case SEC_NAME:
1909 return(post_sh_name(mdoc));
1910 case SEC_SEE_ALSO:
1911 return(post_sh_see_also(mdoc));
1912 case SEC_AUTHORS:
1913 return(post_sh_authors(mdoc));
1914 default:
1915 break;
1916 }
1917 break;
1918 default:
1919 break;
1920 }
1921
1922 return(1);
1923 }
1924
1925 static int
1926 post_sh_name(POST_ARGS)
1927 {
1928 struct mdoc_node *n;
1929
1930 /*
1931 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1932 * macros (can have multiple `Nm' and one `Nd'). Note that the
1933 * children of the BODY declaration can also be "text".
1934 */
1935
1936 if (NULL == (n = mdoc->last->child)) {
1937 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1938 mdoc->last->line, mdoc->last->pos, "empty");
1939 return(1);
1940 }
1941
1942 for ( ; n && n->next; n = n->next) {
1943 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1944 continue;
1945 if (MDOC_TEXT == n->type)
1946 continue;
1947 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1948 n->line, n->pos, mdoc_macronames[n->tok]);
1949 }
1950
1951 assert(n);
1952 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1953 return(1);
1954
1955 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1956 n->line, n->pos, mdoc_macronames[n->tok]);
1957 return(1);
1958 }
1959
1960 static int
1961 post_sh_see_also(POST_ARGS)
1962 {
1963 const struct mdoc_node *n;
1964 const char *name, *sec;
1965 const char *lastname, *lastsec, *lastpunct;
1966 int cmp;
1967
1968 n = mdoc->last->child;
1969 lastname = lastsec = lastpunct = NULL;
1970 while (n != NULL) {
1971 if (n->tok != MDOC_Xr || n->nchild < 2)
1972 break;
1973
1974 /* Process one .Xr node. */
1975
1976 name = n->child->string;
1977 sec = n->child->next->string;
1978 if (lastsec != NULL) {
1979 if (lastpunct[0] != ',' || lastpunct[1] != '\0')
1980 mandoc_vmsg(MANDOCERR_XR_PUNCT,
1981 mdoc->parse, n->line, n->pos,
1982 "%s before %s(%s)", lastpunct,
1983 name, sec);
1984 cmp = strcmp(lastsec, sec);
1985 if (cmp > 0)
1986 mandoc_vmsg(MANDOCERR_XR_ORDER,
1987 mdoc->parse, n->line, n->pos,
1988 "%s(%s) after %s(%s)", name,
1989 sec, lastname, lastsec);
1990 else if (cmp == 0 && strcmp(lastname, name) > 0)
1991 mandoc_vmsg(MANDOCERR_XR_ORDER,
1992 mdoc->parse, n->line, n->pos,
1993 "%s after %s", name, lastname);
1994 }
1995 lastname = name;
1996 lastsec = sec;
1997
1998 /* Process the following node. */
1999
2000 n = n->next;
2001 if (n == NULL)
2002 break;
2003 if (n->tok == MDOC_Xr) {
2004 lastpunct = "none";
2005 continue;
2006 }
2007 if (n->type != MDOC_TEXT)
2008 break;
2009 for (name = n->string; *name != '\0'; name++)
2010 if (isalpha((const unsigned char)*name))
2011 return(1);
2012 lastpunct = n->string;
2013 if (n->next == NULL)
2014 mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
2015 n->line, n->pos, "%s after %s(%s)",
2016 lastpunct, lastname, lastsec);
2017 n = n->next;
2018 }
2019 return(1);
2020 }
2021
2022 static int
2023 child_an(const struct mdoc_node *n)
2024 {
2025
2026 for (n = n->child; n != NULL; n = n->next)
2027 if ((n->tok == MDOC_An && n->nchild) || child_an(n))
2028 return(1);
2029 return(0);
2030 }
2031
2032 static int
2033 post_sh_authors(POST_ARGS)
2034 {
2035
2036 if ( ! child_an(mdoc->last))
2037 mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
2038 mdoc->last->line, mdoc->last->pos, NULL);
2039 return(1);
2040 }
2041
2042 static int
2043 post_sh_head(POST_ARGS)
2044 {
2045 struct mdoc_node *n;
2046 const char *goodsec;
2047 char *secname;
2048 enum mdoc_sec sec;
2049
2050 /*
2051 * Process a new section. Sections are either "named" or
2052 * "custom". Custom sections are user-defined, while named ones
2053 * follow a conventional order and may only appear in certain
2054 * manual sections.
2055 */
2056
2057 secname = NULL;
2058 sec = SEC_CUSTOM;
2059 mdoc_deroff(&secname, mdoc->last);
2060 sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
2061
2062 /* The NAME should be first. */
2063
2064 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
2065 mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
2066 mdoc->last->line, mdoc->last->pos,
2067 "Sh %s", secname);
2068
2069 /* The SYNOPSIS gets special attention in other areas. */
2070
2071 if (SEC_SYNOPSIS == sec) {
2072 roff_setreg(mdoc->roff, "nS", 1, '=');
2073 mdoc->flags |= MDOC_SYNOPSIS;
2074 } else {
2075 roff_setreg(mdoc->roff, "nS", 0, '=');
2076 mdoc->flags &= ~MDOC_SYNOPSIS;
2077 }
2078
2079 /* Mark our last section. */
2080
2081 mdoc->lastsec = sec;
2082
2083 /*
2084 * Set the section attribute for the current HEAD, for its
2085 * parent BLOCK, and for the HEAD children; the latter can
2086 * only be TEXT nodes, so no recursion is needed.
2087 * For other blocks and elements, including .Sh BODY, this is
2088 * done when allocating the node data structures, but for .Sh
2089 * BLOCK and HEAD, the section is still unknown at that time.
2090 */
2091
2092 mdoc->last->parent->sec = sec;
2093 mdoc->last->sec = sec;
2094 for (n = mdoc->last->child; n; n = n->next)
2095 n->sec = sec;
2096
2097 /* We don't care about custom sections after this. */
2098
2099 if (SEC_CUSTOM == sec) {
2100 free(secname);
2101 return(1);
2102 }
2103
2104 /*
2105 * Check whether our non-custom section is being repeated or is
2106 * out of order.
2107 */
2108
2109 if (sec == mdoc->lastnamed)
2110 mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
2111 mdoc->last->line, mdoc->last->pos,
2112 "Sh %s", secname);
2113
2114 if (sec < mdoc->lastnamed)
2115 mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
2116 mdoc->last->line, mdoc->last->pos,
2117 "Sh %s", secname);
2118
2119 /* Mark the last named section. */
2120
2121 mdoc->lastnamed = sec;
2122
2123 /* Check particular section/manual conventions. */
2124
2125 if (mdoc->meta.msec == NULL) {
2126 free(secname);
2127 return(1);
2128 }
2129
2130 goodsec = NULL;
2131 switch (sec) {
2132 case SEC_ERRORS:
2133 if (*mdoc->meta.msec == '4')
2134 break;
2135 goodsec = "2, 3, 4, 9";
2136 /* FALLTHROUGH */
2137 case SEC_RETURN_VALUES:
2138 /* FALLTHROUGH */
2139 case SEC_LIBRARY:
2140 if (*mdoc->meta.msec == '2')
2141 break;
2142 if (*mdoc->meta.msec == '3')
2143 break;
2144 if (NULL == goodsec)
2145 goodsec = "2, 3, 9";
2146 /* FALLTHROUGH */
2147 case SEC_CONTEXT:
2148 if (*mdoc->meta.msec == '9')
2149 break;
2150 if (NULL == goodsec)
2151 goodsec = "9";
2152 mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
2153 mdoc->last->line, mdoc->last->pos,
2154 "Sh %s for %s only", secname, goodsec);
2155 break;
2156 default:
2157 break;
2158 }
2159
2160 free(secname);
2161 return(1);
2162 }
2163
2164 static int
2165 post_ignpar(POST_ARGS)
2166 {
2167 struct mdoc_node *np;
2168
2169 hwarn_ge1(mdoc);
2170 post_hyph(mdoc);
2171
2172 if (MDOC_BODY != mdoc->last->type)
2173 return(1);
2174
2175 if (NULL != (np = mdoc->last->child))
2176 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2177 mandoc_vmsg(MANDOCERR_PAR_SKIP,
2178 mdoc->parse, np->line, np->pos,
2179 "%s after %s", mdoc_macronames[np->tok],
2180 mdoc_macronames[mdoc->last->tok]);
2181 mdoc_node_delete(mdoc, np);
2182 }
2183
2184 if (NULL != (np = mdoc->last->last))
2185 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2186 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2187 np->line, np->pos, "%s at the end of %s",
2188 mdoc_macronames[np->tok],
2189 mdoc_macronames[mdoc->last->tok]);
2190 mdoc_node_delete(mdoc, np);
2191 }
2192
2193 return(1);
2194 }
2195
2196 static int
2197 pre_par(PRE_ARGS)
2198 {
2199
2200 if (NULL == mdoc->last)
2201 return(1);
2202 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2203 return(1);
2204
2205 /*
2206 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2207 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2208 */
2209
2210 if (MDOC_Pp != mdoc->last->tok &&
2211 MDOC_Lp != mdoc->last->tok &&
2212 MDOC_br != mdoc->last->tok)
2213 return(1);
2214 if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2215 return(1);
2216 if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2217 return(1);
2218 if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2219 return(1);
2220
2221 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2222 mdoc->last->line, mdoc->last->pos,
2223 "%s before %s", mdoc_macronames[mdoc->last->tok],
2224 mdoc_macronames[n->tok]);
2225 mdoc_node_delete(mdoc, mdoc->last);
2226 return(1);
2227 }
2228
2229 static int
2230 post_par(POST_ARGS)
2231 {
2232 struct mdoc_node *np;
2233
2234 if (mdoc->last->tok == MDOC_sp)
2235 ewarn_le1(mdoc);
2236 else
2237 ewarn_eq0(mdoc);
2238
2239 if (MDOC_ELEM != mdoc->last->type &&
2240 MDOC_BLOCK != mdoc->last->type)
2241 return(1);
2242
2243 if (NULL == (np = mdoc->last->prev)) {
2244 np = mdoc->last->parent;
2245 if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
2246 return(1);
2247 } else {
2248 if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
2249 (MDOC_br != mdoc->last->tok ||
2250 (MDOC_sp != np->tok && MDOC_br != np->tok)))
2251 return(1);
2252 }
2253
2254 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2255 mdoc->last->line, mdoc->last->pos,
2256 "%s after %s", mdoc_macronames[mdoc->last->tok],
2257 mdoc_macronames[np->tok]);
2258 mdoc_node_delete(mdoc, mdoc->last);
2259 return(1);
2260 }
2261
2262 static int
2263 pre_literal(PRE_ARGS)
2264 {
2265
2266 pre_display(mdoc, n);
2267
2268 if (MDOC_BODY != n->type)
2269 return(1);
2270
2271 /*
2272 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2273 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2274 */
2275
2276 switch (n->tok) {
2277 case MDOC_Dl:
2278 mdoc->flags |= MDOC_LITERAL;
2279 break;
2280 case MDOC_Bd:
2281 if (DISP_literal == n->norm->Bd.type)
2282 mdoc->flags |= MDOC_LITERAL;
2283 if (DISP_unfilled == n->norm->Bd.type)
2284 mdoc->flags |= MDOC_LITERAL;
2285 break;
2286 default:
2287 abort();
2288 /* NOTREACHED */
2289 }
2290
2291 return(1);
2292 }
2293
2294 static int
2295 post_dd(POST_ARGS)
2296 {
2297 struct mdoc_node *n;
2298 char *datestr;
2299
2300 if (mdoc->meta.date)
2301 free(mdoc->meta.date);
2302
2303 n = mdoc->last;
2304 if (NULL == n->child || '\0' == n->child->string[0]) {
2305 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
2306 mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
2307 goto out;
2308 }
2309
2310 datestr = NULL;
2311 mdoc_deroff(&datestr, n);
2312 if (mdoc->quick)
2313 mdoc->meta.date = datestr;
2314 else {
2315 mdoc->meta.date = mandoc_normdate(mdoc->parse,
2316 datestr, n->line, n->pos);
2317 free(datestr);
2318 }
2319 out:
2320 mdoc_node_delete(mdoc, n);
2321 return(1);
2322 }
2323
2324 static int
2325 post_dt(POST_ARGS)
2326 {
2327 struct mdoc_node *nn, *n;
2328 const char *cp;
2329 char *p;
2330
2331 n = mdoc->last;
2332
2333 free(mdoc->meta.title);
2334 free(mdoc->meta.msec);
2335 free(mdoc->meta.vol);
2336 free(mdoc->meta.arch);
2337
2338 mdoc->meta.title = NULL;
2339 mdoc->meta.msec = NULL;
2340 mdoc->meta.vol = NULL;
2341 mdoc->meta.arch = NULL;
2342
2343 /* First check that all characters are uppercase. */
2344
2345 if (NULL != (nn = n->child))
2346 for (p = nn->string; *p; p++) {
2347 if (toupper((unsigned char)*p) == *p)
2348 continue;
2349 mandoc_vmsg(MANDOCERR_TITLE_CASE,
2350 mdoc->parse, nn->line,
2351 nn->pos + (p - nn->string),
2352 "Dt %s", nn->string);
2353 break;
2354 }
2355
2356 /* No argument: msec and arch remain NULL. */
2357
2358 if (NULL == (nn = n->child)) {
2359 mandoc_msg(MANDOCERR_DT_NOTITLE,
2360 mdoc->parse, n->line, n->pos, "Dt");
2361 mdoc->meta.title = mandoc_strdup("UNTITLED");
2362 mdoc->meta.vol = mandoc_strdup("LOCAL");
2363 goto out;
2364 }
2365
2366 /* One argument: msec and arch remain NULL. */
2367
2368 mdoc->meta.title = mandoc_strdup(
2369 '\0' == nn->string[0] ? "UNTITLED" : nn->string);
2370
2371 if (NULL == (nn = nn->next)) {
2372 mandoc_vmsg(MANDOCERR_MSEC_MISSING,
2373 mdoc->parse, n->line, n->pos,
2374 "Dt %s", mdoc->meta.title);
2375 mdoc->meta.vol = mandoc_strdup("LOCAL");
2376 goto out;
2377 }
2378
2379 /* Handles: `.Dt TITLE SEC'
2380 * title = TITLE,
2381 * volume = SEC is msec ? format(msec) : SEC,
2382 * msec = SEC is msec ? atoi(msec) : 0,
2383 * arch = NULL
2384 */
2385
2386 cp = mandoc_a2msec(nn->string);
2387 if (cp) {
2388 mdoc->meta.vol = mandoc_strdup(cp);
2389 mdoc->meta.msec = mandoc_strdup(nn->string);
2390 } else {
2391 mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
2392 nn->line, nn->pos, "Dt ... %s", nn->string);
2393 mdoc->meta.vol = mandoc_strdup(nn->string);
2394 mdoc->meta.msec = mandoc_strdup(nn->string);
2395 }
2396
2397 if (NULL == (nn = nn->next))
2398 goto out;
2399
2400 /* Handles: `.Dt TITLE SEC VOL'
2401 * title = TITLE,
2402 * volume = VOL is vol ? format(VOL) :
2403 * VOL is arch ? format(arch) :
2404 * VOL
2405 */
2406
2407 cp = mdoc_a2vol(nn->string);
2408 if (cp) {
2409 free(mdoc->meta.vol);
2410 mdoc->meta.vol = mandoc_strdup(cp);
2411 } else {
2412 cp = mdoc_a2arch(nn->string);
2413 if (NULL == cp) {
2414 mandoc_vmsg(MANDOCERR_ARCH_BAD, mdoc->parse,
2415 nn->line, nn->pos, "Dt ... %s", nn->string);
2416 free(mdoc->meta.vol);
2417 mdoc->meta.vol = mandoc_strdup(nn->string);
2418 } else
2419 mdoc->meta.arch = mandoc_strdup(cp);
2420 }
2421
2422 /* Ignore any subsequent parameters... */
2423 /* FIXME: warn about subsequent parameters. */
2424 out:
2425 mdoc_node_delete(mdoc, n);
2426 return(1);
2427 }
2428
2429 static int
2430 post_bx(POST_ARGS)
2431 {
2432 struct mdoc_node *n;
2433
2434 /*
2435 * Make `Bx's second argument always start with an uppercase
2436 * letter. Groff checks if it's an "accepted" term, but we just
2437 * uppercase blindly.
2438 */
2439
2440 n = mdoc->last->child;
2441 if (n && NULL != (n = n->next))
2442 *n->string = (char)toupper((unsigned char)*n->string);
2443
2444 return(1);
2445 }
2446
2447 static int
2448 post_os(POST_ARGS)
2449 {
2450 #ifndef OSNAME
2451 struct utsname utsname;
2452 static char *defbuf;
2453 #endif
2454 struct mdoc_node *n;
2455
2456 n = mdoc->last;
2457
2458 /*
2459 * Set the operating system by way of the `Os' macro.
2460 * The order of precedence is:
2461 * 1. the argument of the `Os' macro, unless empty
2462 * 2. the -Ios=foo command line argument, if provided
2463 * 3. -DOSNAME="\"foo\"", if provided during compilation
2464 * 4. "sysname release" from uname(3)
2465 */
2466
2467 free(mdoc->meta.os);
2468 mdoc->meta.os = NULL;
2469 mdoc_deroff(&mdoc->meta.os, n);
2470 if (mdoc->meta.os)
2471 goto out;
2472
2473 if (mdoc->defos) {
2474 mdoc->meta.os = mandoc_strdup(mdoc->defos);
2475 goto out;
2476 }
2477
2478 #ifdef OSNAME
2479 mdoc->meta.os = mandoc_strdup(OSNAME);
2480 #else /*!OSNAME */
2481 if (NULL == defbuf) {
2482 if (-1 == uname(&utsname)) {
2483 mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
2484 n->line, n->pos, "Os");
2485 defbuf = mandoc_strdup("UNKNOWN");
2486 } else
2487 mandoc_asprintf(&defbuf, "%s %s",
2488 utsname.sysname, utsname.release);
2489 }
2490 mdoc->meta.os = mandoc_strdup(defbuf);
2491 #endif /*!OSNAME*/
2492
2493 out:
2494 mdoc_node_delete(mdoc, n);
2495 return(1);
2496 }
2497
2498 /*
2499 * If no argument is provided,
2500 * fill in the name of the current manual page.
2501 */
2502 static int
2503 post_ex(POST_ARGS)
2504 {
2505 struct mdoc_node *n;
2506
2507 n = mdoc->last;
2508
2509 if (n->child)
2510 return(1);
2511
2512 if (mdoc->meta.name == NULL) {
2513 mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
2514 n->line, n->pos, "Ex");
2515 return(1);
2516 }
2517
2518 mdoc->next = MDOC_NEXT_CHILD;
2519
2520 if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2521 return(0);
2522
2523 mdoc->last = n;
2524 return(1);
2525 }
2526
2527 static enum mdoc_sec
2528 a2sec(const char *p)
2529 {
2530 int i;
2531
2532 for (i = 0; i < (int)SEC__MAX; i++)
2533 if (secnames[i] && 0 == strcmp(p, secnames[i]))
2534 return((enum mdoc_sec)i);
2535
2536 return(SEC_CUSTOM);
2537 }
2538
2539 static size_t
2540 macro2len(enum mdoct macro)
2541 {
2542
2543 switch (macro) {
2544 case MDOC_Ad:
2545 return(12);
2546 case MDOC_Ao:
2547 return(12);
2548 case MDOC_An:
2549 return(12);
2550 case MDOC_Aq:
2551 return(12);
2552 case MDOC_Ar:
2553 return(12);
2554 case MDOC_Bo:
2555 return(12);
2556 case MDOC_Bq:
2557 return(12);
2558 case MDOC_Cd:
2559 return(12);
2560 case MDOC_Cm:
2561 return(10);
2562 case MDOC_Do:
2563 return(10);
2564 case MDOC_Dq:
2565 return(12);
2566 case MDOC_Dv:
2567 return(12);
2568 case MDOC_Eo:
2569 return(12);
2570 case MDOC_Em:
2571 return(10);
2572 case MDOC_Er:
2573 return(17);
2574 case MDOC_Ev:
2575 return(15);
2576 case MDOC_Fa:
2577 return(12);
2578 case MDOC_Fl:
2579 return(10);
2580 case MDOC_Fo:
2581 return(16);
2582 case MDOC_Fn:
2583 return(16);
2584 case MDOC_Ic:
2585 return(10);
2586 case MDOC_Li:
2587 return(16);
2588 case MDOC_Ms:
2589 return(6);
2590 case MDOC_Nm:
2591 return(10);
2592 case MDOC_No:
2593 return(12);
2594 case MDOC_Oo:
2595 return(10);
2596 case MDOC_Op:
2597 return(14);
2598 case MDOC_Pa:
2599 return(32);
2600 case MDOC_Pf:
2601 return(12);
2602 case MDOC_Po:
2603 return(12);
2604 case MDOC_Pq:
2605 return(12);
2606 case MDOC_Ql:
2607 return(16);
2608 case MDOC_Qo:
2609 return(12);
2610 case MDOC_So:
2611 return(12);
2612 case MDOC_Sq:
2613 return(12);
2614 case MDOC_Sy:
2615 return(6);
2616 case MDOC_Sx:
2617 return(16);
2618 case MDOC_Tn:
2619 return(10);
2620 case MDOC_Va:
2621 return(12);
2622 case MDOC_Vt:
2623 return(12);
2624 case MDOC_Xr:
2625 return(10);
2626 default:
2627 break;
2628 };
2629 return(0);
2630 }