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