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