]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
4beb2196ca8fa579b14008d0c4bd1fff59a7ec35
[mandoc.git] / mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.223 2014/07/02 20:19:11 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 mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
731
732 continue;
733 }
734
735 /* Allow lists to default to LIST_item. */
736
737 if (LIST__NONE == n->norm->Bl.type) {
738 mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
739 n->norm->Bl.type = LIST_item;
740 }
741
742 /*
743 * Validate the width field. Some list types don't need width
744 * types and should be warned about them. Others should have it
745 * and must also be warned. Yet others have a default and need
746 * no warning.
747 */
748
749 switch (n->norm->Bl.type) {
750 case LIST_tag:
751 if (NULL == n->norm->Bl.width)
752 mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
753 break;
754 case LIST_column:
755 /* FALLTHROUGH */
756 case LIST_diag:
757 /* FALLTHROUGH */
758 case LIST_ohang:
759 /* FALLTHROUGH */
760 case LIST_inset:
761 /* FALLTHROUGH */
762 case LIST_item:
763 if (n->norm->Bl.width)
764 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
765 break;
766 case LIST_bullet:
767 /* FALLTHROUGH */
768 case LIST_dash:
769 /* FALLTHROUGH */
770 case LIST_hyphen:
771 if (NULL == n->norm->Bl.width)
772 n->norm->Bl.width = "2n";
773 break;
774 case LIST_enum:
775 if (NULL == n->norm->Bl.width)
776 n->norm->Bl.width = "3n";
777 break;
778 default:
779 break;
780 }
781
782 return(1);
783 }
784
785 static int
786 pre_bd(PRE_ARGS)
787 {
788 int i, dup, comp;
789 enum mdoc_disp dt;
790 const char *offs;
791 struct mdoc_node *np;
792
793 if (MDOC_BLOCK != n->type) {
794 if (ENDBODY_NOT != n->end) {
795 assert(n->pending);
796 np = n->pending->parent;
797 } else
798 np = n->parent;
799
800 assert(np);
801 assert(MDOC_BLOCK == np->type);
802 assert(MDOC_Bd == np->tok);
803 return(1);
804 }
805
806 for (i = 0; n->args && i < (int)n->args->argc; i++) {
807 dt = DISP__NONE;
808 dup = comp = 0;
809 offs = NULL;
810
811 switch (n->args->argv[i].arg) {
812 case MDOC_Centred:
813 dt = DISP_centred;
814 break;
815 case MDOC_Ragged:
816 dt = DISP_ragged;
817 break;
818 case MDOC_Unfilled:
819 dt = DISP_unfilled;
820 break;
821 case MDOC_Filled:
822 dt = DISP_filled;
823 break;
824 case MDOC_Literal:
825 dt = DISP_literal;
826 break;
827 case MDOC_File:
828 mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
829 return(0);
830 case MDOC_Offset:
831 /* NB: this can be empty! */
832 if (n->args->argv[i].sz) {
833 offs = n->args->argv[i].value[0];
834 dup = (NULL != n->norm->Bd.offs);
835 break;
836 }
837 mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
838 break;
839 case MDOC_Compact:
840 comp = 1;
841 dup = n->norm->Bd.comp;
842 break;
843 default:
844 abort();
845 /* NOTREACHED */
846 }
847
848 /* Check whether we have duplicates. */
849
850 if (dup)
851 mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
852
853 /* Make our auxiliary assignments. */
854
855 if (offs && ! dup)
856 n->norm->Bd.offs = offs;
857 if (comp && ! dup)
858 n->norm->Bd.comp = comp;
859
860 /* Check whether a type has already been assigned. */
861
862 if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
863 mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
864
865 /* Make our type assignment. */
866
867 if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
868 n->norm->Bd.type = dt;
869 }
870
871 if (DISP__NONE == n->norm->Bd.type) {
872 mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
873 n->norm->Bd.type = DISP_ragged;
874 }
875
876 return(1);
877 }
878
879 static int
880 pre_ss(PRE_ARGS)
881 {
882
883 if (MDOC_BLOCK != n->type)
884 return(1);
885 return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
886 }
887
888 static int
889 pre_sh(PRE_ARGS)
890 {
891
892 if (MDOC_BLOCK != n->type)
893 return(1);
894 return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
895 }
896
897 static int
898 pre_it(PRE_ARGS)
899 {
900
901 if (MDOC_BLOCK != n->type)
902 return(1);
903
904 return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
905 }
906
907 static int
908 pre_an(PRE_ARGS)
909 {
910 int i;
911
912 if (NULL == n->args)
913 return(1);
914
915 for (i = 1; i < (int)n->args->argc; i++)
916 mdoc_pmsg(mdoc, n->args->argv[i].line,
917 n->args->argv[i].pos, MANDOCERR_IGNARGV);
918
919 if (MDOC_Split == n->args->argv[0].arg)
920 n->norm->An.auth = AUTH_split;
921 else if (MDOC_Nosplit == n->args->argv[0].arg)
922 n->norm->An.auth = AUTH_nosplit;
923 else
924 abort();
925
926 return(1);
927 }
928
929 static int
930 pre_std(PRE_ARGS)
931 {
932
933 if (n->args && 1 == n->args->argc)
934 if (MDOC_Std == n->args->argv[0].arg)
935 return(1);
936
937 mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV);
938 return(1);
939 }
940
941 static int
942 pre_obsolete(PRE_ARGS)
943 {
944
945 if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type)
946 mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
947 n->line, n->pos, mdoc_macronames[n->tok]);
948 return(1);
949 }
950
951 static int
952 pre_dt(PRE_ARGS)
953 {
954
955 if (NULL == mdoc->meta.date || mdoc->meta.os)
956 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
957 n->line, n->pos, "Dt");
958
959 if (mdoc->meta.title)
960 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
961 n->line, n->pos, "Dt");
962
963 return(1);
964 }
965
966 static int
967 pre_os(PRE_ARGS)
968 {
969
970 if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
971 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
972 n->line, n->pos, "Os");
973
974 if (mdoc->meta.os)
975 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
976 n->line, n->pos, "Os");
977
978 return(1);
979 }
980
981 static int
982 pre_dd(PRE_ARGS)
983 {
984
985 if (mdoc->meta.title || mdoc->meta.os)
986 mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
987 n->line, n->pos, "Dd");
988
989 if (mdoc->meta.date)
990 mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
991 n->line, n->pos, "Dd");
992
993 return(1);
994 }
995
996 static int
997 post_bf(POST_ARGS)
998 {
999 struct mdoc_node *np;
1000 enum mdocargt arg;
1001
1002 /*
1003 * Unlike other data pointers, these are "housed" by the HEAD
1004 * element, which contains the goods.
1005 */
1006
1007 if (MDOC_HEAD != mdoc->last->type) {
1008 if (ENDBODY_NOT != mdoc->last->end) {
1009 assert(mdoc->last->pending);
1010 np = mdoc->last->pending->parent->head;
1011 } else if (MDOC_BLOCK != mdoc->last->type) {
1012 np = mdoc->last->parent->head;
1013 } else
1014 np = mdoc->last->head;
1015
1016 assert(np);
1017 assert(MDOC_HEAD == np->type);
1018 assert(MDOC_Bf == np->tok);
1019 return(1);
1020 }
1021
1022 np = mdoc->last;
1023 assert(MDOC_BLOCK == np->parent->type);
1024 assert(MDOC_Bf == np->parent->tok);
1025
1026 /*
1027 * Cannot have both argument and parameter.
1028 * If neither is specified, let it through with a warning.
1029 */
1030
1031 if (np->parent->args && np->child) {
1032 mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
1033 return(0);
1034 } else if (NULL == np->parent->args && NULL == np->child) {
1035 mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1036 return(1);
1037 }
1038
1039 /* Extract argument into data. */
1040
1041 if (np->parent->args) {
1042 arg = np->parent->args->argv[0].arg;
1043 if (MDOC_Emphasis == arg)
1044 np->norm->Bf.font = FONT_Em;
1045 else if (MDOC_Literal == arg)
1046 np->norm->Bf.font = FONT_Li;
1047 else if (MDOC_Symbolic == arg)
1048 np->norm->Bf.font = FONT_Sy;
1049 else
1050 abort();
1051 return(1);
1052 }
1053
1054 /* Extract parameter into data. */
1055
1056 if (0 == strcmp(np->child->string, "Em"))
1057 np->norm->Bf.font = FONT_Em;
1058 else if (0 == strcmp(np->child->string, "Li"))
1059 np->norm->Bf.font = FONT_Li;
1060 else if (0 == strcmp(np->child->string, "Sy"))
1061 np->norm->Bf.font = FONT_Sy;
1062 else
1063 mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1064
1065 return(1);
1066 }
1067
1068 static int
1069 post_lb(POST_ARGS)
1070 {
1071 struct mdoc_node *n;
1072 const char *stdlibname;
1073 char *libname;
1074
1075 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1076
1077 n = mdoc->last->child;
1078
1079 assert(n);
1080 assert(MDOC_TEXT == n->type);
1081
1082 if (NULL == (stdlibname = mdoc_a2lib(n->string)))
1083 mandoc_asprintf(&libname,
1084 "library \\(lq%s\\(rq", n->string);
1085 else
1086 libname = mandoc_strdup(stdlibname);
1087
1088 free(n->string);
1089 n->string = libname;
1090 return(1);
1091 }
1092
1093 static int
1094 post_eoln(POST_ARGS)
1095 {
1096
1097 if (mdoc->last->child)
1098 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1099 return(1);
1100 }
1101
1102 static int
1103 post_vt(POST_ARGS)
1104 {
1105 const struct mdoc_node *n;
1106
1107 /*
1108 * The Vt macro comes in both ELEM and BLOCK form, both of which
1109 * have different syntaxes (yet more context-sensitive
1110 * behaviour). ELEM types must have a child, which is already
1111 * guaranteed by the in_line parsing routine; BLOCK types,
1112 * specifically the BODY, should only have TEXT children.
1113 */
1114
1115 if (MDOC_BODY != mdoc->last->type)
1116 return(1);
1117
1118 for (n = mdoc->last->child; n; n = n->next)
1119 if (MDOC_TEXT != n->type)
1120 mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse,
1121 n->line, n->pos, mdoc_macronames[n->tok]);
1122
1123 return(1);
1124 }
1125
1126 static int
1127 post_nm(POST_ARGS)
1128 {
1129
1130 if (NULL != mdoc->meta.name)
1131 return(1);
1132
1133 mdoc_deroff(&mdoc->meta.name, mdoc->last);
1134
1135 if (NULL == mdoc->meta.name) {
1136 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1137 mdoc->meta.name = mandoc_strdup("UNKNOWN");
1138 }
1139 return(1);
1140 }
1141
1142 static int
1143 post_literal(POST_ARGS)
1144 {
1145
1146 /*
1147 * The `Dl' (note "el" not "one") and `Bd' macros unset the
1148 * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1149 * this in literal mode, but it doesn't hurt to just switch it
1150 * off in general since displays can't be nested.
1151 */
1152
1153 if (MDOC_BODY == mdoc->last->type)
1154 mdoc->flags &= ~MDOC_LITERAL;
1155
1156 return(1);
1157 }
1158
1159 static int
1160 post_defaults(POST_ARGS)
1161 {
1162 struct mdoc_node *nn;
1163
1164 /*
1165 * The `Ar' defaults to "file ..." if no value is provided as an
1166 * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1167 * gets an empty string.
1168 */
1169
1170 if (mdoc->last->child)
1171 return(1);
1172
1173 nn = mdoc->last;
1174 mdoc->next = MDOC_NEXT_CHILD;
1175
1176 switch (nn->tok) {
1177 case MDOC_Ar:
1178 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
1179 return(0);
1180 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
1181 return(0);
1182 break;
1183 case MDOC_At:
1184 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T"))
1185 return(0);
1186 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX"))
1187 return(0);
1188 break;
1189 case MDOC_Li:
1190 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
1191 return(0);
1192 break;
1193 case MDOC_Pa:
1194 /* FALLTHROUGH */
1195 case MDOC_Mt:
1196 if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
1197 return(0);
1198 break;
1199 default:
1200 abort();
1201 /* NOTREACHED */
1202 }
1203
1204 mdoc->last = nn;
1205 return(1);
1206 }
1207
1208 static int
1209 post_at(POST_ARGS)
1210 {
1211 struct mdoc_node *n;
1212 const char *std_att;
1213 char *att;
1214
1215 /*
1216 * If we have a child, look it up in the standard keys. If a
1217 * key exist, use that instead of the child; if it doesn't,
1218 * prefix "AT&T UNIX " to the existing data.
1219 */
1220
1221 if (NULL == (n = mdoc->last->child))
1222 return(1);
1223
1224 assert(MDOC_TEXT == n->type);
1225 if (NULL == (std_att = mdoc_a2att(n->string))) {
1226 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
1227 mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
1228 } else
1229 att = mandoc_strdup(std_att);
1230
1231 free(n->string);
1232 n->string = att;
1233 return(1);
1234 }
1235
1236 static int
1237 post_an(POST_ARGS)
1238 {
1239 struct mdoc_node *np;
1240
1241 np = mdoc->last;
1242 if (AUTH__NONE == np->norm->An.auth) {
1243 if (0 == np->child)
1244 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
1245 } else if (np->child)
1246 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
1247
1248 return(1);
1249 }
1250
1251 static int
1252 post_en(POST_ARGS)
1253 {
1254
1255 if (MDOC_BLOCK == mdoc->last->type)
1256 mdoc->last->norm->Es = mdoc->last_es;
1257 return(1);
1258 }
1259
1260 static int
1261 post_es(POST_ARGS)
1262 {
1263
1264 mdoc->last_es = mdoc->last;
1265 return(1);
1266 }
1267
1268 static int
1269 post_it(POST_ARGS)
1270 {
1271 int i, cols;
1272 enum mdoc_list lt;
1273 struct mdoc_node *n, *c;
1274 enum mandocerr er;
1275
1276 if (MDOC_BLOCK != mdoc->last->type)
1277 return(1);
1278
1279 n = mdoc->last->parent->parent;
1280 lt = n->norm->Bl.type;
1281
1282 if (LIST__NONE == lt) {
1283 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
1284 return(1);
1285 }
1286
1287 switch (lt) {
1288 case LIST_tag:
1289 if (mdoc->last->head->child)
1290 break;
1291 /* FIXME: give this a dummy value. */
1292 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1293 break;
1294 case LIST_hang:
1295 /* FALLTHROUGH */
1296 case LIST_ohang:
1297 /* FALLTHROUGH */
1298 case LIST_inset:
1299 /* FALLTHROUGH */
1300 case LIST_diag:
1301 if (NULL == mdoc->last->head->child)
1302 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1303 break;
1304 case LIST_bullet:
1305 /* FALLTHROUGH */
1306 case LIST_dash:
1307 /* FALLTHROUGH */
1308 case LIST_enum:
1309 /* FALLTHROUGH */
1310 case LIST_hyphen:
1311 if (NULL == mdoc->last->body->child)
1312 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1313 /* FALLTHROUGH */
1314 case LIST_item:
1315 if (mdoc->last->head->child)
1316 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1317 break;
1318 case LIST_column:
1319 cols = (int)n->norm->Bl.ncols;
1320
1321 assert(NULL == mdoc->last->head->child);
1322
1323 if (NULL == mdoc->last->body->child)
1324 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1325
1326 for (i = 0, c = mdoc->last->child; c; c = c->next)
1327 if (MDOC_BODY == c->type)
1328 i++;
1329
1330 if (i < cols)
1331 er = MANDOCERR_ARGCOUNT;
1332 else if (i == cols || i == cols + 1)
1333 break;
1334 else
1335 er = MANDOCERR_SYNTARGCOUNT;
1336
1337 mandoc_vmsg(er, mdoc->parse,
1338 mdoc->last->line, mdoc->last->pos,
1339 "columns == %d (have %d)", cols, i);
1340 return(MANDOCERR_ARGCOUNT == er);
1341 default:
1342 break;
1343 }
1344
1345 return(1);
1346 }
1347
1348 static int
1349 post_bl_block(POST_ARGS)
1350 {
1351 struct mdoc_node *n, *ni, *nc;
1352
1353 /*
1354 * These are fairly complicated, so we've broken them into two
1355 * functions. post_bl_block_tag() is called when a -tag is
1356 * specified, but no -width (it must be guessed). The second
1357 * when a -width is specified (macro indicators must be
1358 * rewritten into real lengths).
1359 */
1360
1361 n = mdoc->last;
1362
1363 if (LIST_tag == n->norm->Bl.type &&
1364 NULL == n->norm->Bl.width) {
1365 if ( ! post_bl_block_tag(mdoc))
1366 return(0);
1367 assert(n->norm->Bl.width);
1368 } else if (NULL != n->norm->Bl.width) {
1369 if ( ! post_bl_block_width(mdoc))
1370 return(0);
1371 assert(n->norm->Bl.width);
1372 }
1373
1374 for (ni = n->body->child; ni; ni = ni->next) {
1375 if (NULL == ni->body)
1376 continue;
1377 nc = ni->body->last;
1378 while (NULL != nc) {
1379 switch (nc->tok) {
1380 case MDOC_Pp:
1381 /* FALLTHROUGH */
1382 case MDOC_Lp:
1383 /* FALLTHROUGH */
1384 case MDOC_br:
1385 break;
1386 default:
1387 nc = NULL;
1388 continue;
1389 }
1390 if (NULL == ni->next) {
1391 mandoc_msg(MANDOCERR_PAR_MOVE,
1392 mdoc->parse, nc->line, nc->pos,
1393 mdoc_macronames[nc->tok]);
1394 if ( ! mdoc_node_relink(mdoc, nc))
1395 return(0);
1396 } else if (0 == n->norm->Bl.comp &&
1397 LIST_column != n->norm->Bl.type) {
1398 mandoc_vmsg(MANDOCERR_PAR_SKIP,
1399 mdoc->parse, nc->line, nc->pos,
1400 "%s before It",
1401 mdoc_macronames[nc->tok]);
1402 mdoc_node_delete(mdoc, nc);
1403 } else
1404 break;
1405 nc = ni->body->last;
1406 }
1407 }
1408 return(1);
1409 }
1410
1411 static int
1412 post_bl_block_width(POST_ARGS)
1413 {
1414 size_t width;
1415 int i;
1416 enum mdoct tok;
1417 struct mdoc_node *n;
1418 char buf[24];
1419
1420 n = mdoc->last;
1421
1422 /*
1423 * Calculate the real width of a list from the -width string,
1424 * which may contain a macro (with a known default width), a
1425 * literal string, or a scaling width.
1426 *
1427 * If the value to -width is a macro, then we re-write it to be
1428 * the macro's width as set in share/tmac/mdoc/doc-common.
1429 */
1430
1431 if (0 == strcmp(n->norm->Bl.width, "Ds"))
1432 width = 6;
1433 else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
1434 return(1);
1435 else if (0 == (width = macro2len(tok))) {
1436 mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
1437 return(1);
1438 }
1439
1440 /* The value already exists: free and reallocate it. */
1441
1442 assert(n->args);
1443
1444 for (i = 0; i < (int)n->args->argc; i++)
1445 if (MDOC_Width == n->args->argv[i].arg)
1446 break;
1447
1448 assert(i < (int)n->args->argc);
1449
1450 (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)width);
1451 free(n->args->argv[i].value[0]);
1452 n->args->argv[i].value[0] = mandoc_strdup(buf);
1453
1454 /* Set our width! */
1455 n->norm->Bl.width = n->args->argv[i].value[0];
1456 return(1);
1457 }
1458
1459 static int
1460 post_bl_block_tag(POST_ARGS)
1461 {
1462 struct mdoc_node *n, *nn;
1463 size_t sz, ssz;
1464 int i;
1465 char buf[24];
1466
1467 /*
1468 * Calculate the -width for a `Bl -tag' list if it hasn't been
1469 * provided. Uses the first head macro. NOTE AGAIN: this is
1470 * ONLY if the -width argument has NOT been provided. See
1471 * post_bl_block_width() for converting the -width string.
1472 */
1473
1474 sz = 10;
1475 n = mdoc->last;
1476
1477 for (nn = n->body->child; nn; nn = nn->next) {
1478 if (MDOC_It != nn->tok)
1479 continue;
1480
1481 assert(MDOC_BLOCK == nn->type);
1482 nn = nn->head->child;
1483
1484 if (nn == NULL)
1485 break;
1486
1487 if (MDOC_TEXT == nn->type) {
1488 sz = strlen(nn->string) + 1;
1489 break;
1490 }
1491
1492 if (0 != (ssz = macro2len(nn->tok)))
1493 sz = ssz;
1494
1495 break;
1496 }
1497
1498 /* Defaults to ten ens. */
1499
1500 (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
1501
1502 /*
1503 * We have to dynamically add this to the macro's argument list.
1504 * We're guaranteed that a MDOC_Width doesn't already exist.
1505 */
1506
1507 assert(n->args);
1508 i = (int)(n->args->argc)++;
1509
1510 n->args->argv = mandoc_reallocarray(n->args->argv,
1511 n->args->argc, sizeof(struct mdoc_argv));
1512
1513 n->args->argv[i].arg = MDOC_Width;
1514 n->args->argv[i].line = n->line;
1515 n->args->argv[i].pos = n->pos;
1516 n->args->argv[i].sz = 1;
1517 n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1518 n->args->argv[i].value[0] = mandoc_strdup(buf);
1519
1520 /* Set our width! */
1521 n->norm->Bl.width = n->args->argv[i].value[0];
1522 return(1);
1523 }
1524
1525 static int
1526 post_bl_head(POST_ARGS)
1527 {
1528 struct mdoc_node *np, *nn, *nnp;
1529 int i, j;
1530
1531 if (LIST_column != mdoc->last->norm->Bl.type)
1532 /* FIXME: this should be ERROR class... */
1533 return(hwarn_eq0(mdoc));
1534
1535 /*
1536 * Convert old-style lists, where the column width specifiers
1537 * trail as macro parameters, to the new-style ("normal-form")
1538 * lists where they're argument values following -column.
1539 */
1540
1541 /* First, disallow both types and allow normal-form. */
1542
1543 /*
1544 * TODO: technically, we can accept both and just merge the two
1545 * lists, but I'll leave that for another day.
1546 */
1547
1548 if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
1549 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
1550 return(0);
1551 } else if (NULL == mdoc->last->child)
1552 return(1);
1553
1554 np = mdoc->last->parent;
1555 assert(np->args);
1556
1557 for (j = 0; j < (int)np->args->argc; j++)
1558 if (MDOC_Column == np->args->argv[j].arg)
1559 break;
1560
1561 assert(j < (int)np->args->argc);
1562 assert(0 == np->args->argv[j].sz);
1563
1564 /*
1565 * Accommodate for new-style groff column syntax. Shuffle the
1566 * child nodes, all of which must be TEXT, as arguments for the
1567 * column field. Then, delete the head children.
1568 */
1569
1570 np->args->argv[j].sz = (size_t)mdoc->last->nchild;
1571 np->args->argv[j].value = mandoc_reallocarray(NULL,
1572 (size_t)mdoc->last->nchild, sizeof(char *));
1573
1574 mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
1575 mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1576
1577 for (i = 0, nn = mdoc->last->child; nn; i++) {
1578 np->args->argv[j].value[i] = nn->string;
1579 nn->string = NULL;
1580 nnp = nn;
1581 nn = nn->next;
1582 mdoc_node_delete(NULL, nnp);
1583 }
1584
1585 mdoc->last->nchild = 0;
1586 mdoc->last->child = NULL;
1587
1588 return(1);
1589 }
1590
1591 static int
1592 post_bl(POST_ARGS)
1593 {
1594 struct mdoc_node *nparent, *nprev; /* of the Bl block */
1595 struct mdoc_node *nblock, *nbody; /* of the Bl */
1596 struct mdoc_node *nchild, *nnext; /* of the Bl body */
1597
1598 nbody = mdoc->last;
1599 switch (nbody->type) {
1600 case MDOC_BLOCK:
1601 return(post_bl_block(mdoc));
1602 case MDOC_HEAD:
1603 return(post_bl_head(mdoc));
1604 case MDOC_BODY:
1605 break;
1606 default:
1607 return(1);
1608 }
1609
1610 nchild = nbody->child;
1611 while (NULL != nchild) {
1612 if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
1613 nchild = nchild->next;
1614 continue;
1615 }
1616
1617 mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
1618 nchild->line, nchild->pos,
1619 mdoc_macronames[nchild->tok]);
1620
1621 /*
1622 * Move the node out of the Bl block.
1623 * First, collect all required node pointers.
1624 */
1625
1626 nblock = nbody->parent;
1627 nprev = nblock->prev;
1628 nparent = nblock->parent;
1629 nnext = nchild->next;
1630
1631 /*
1632 * Unlink this child.
1633 */
1634
1635 assert(NULL == nchild->prev);
1636 if (0 == --nbody->nchild) {
1637 nbody->child = NULL;
1638 nbody->last = NULL;
1639 assert(NULL == nnext);
1640 } else {
1641 nbody->child = nnext;
1642 nnext->prev = NULL;
1643 }
1644
1645 /*
1646 * Relink this child.
1647 */
1648
1649 nchild->parent = nparent;
1650 nchild->prev = nprev;
1651 nchild->next = nblock;
1652
1653 nblock->prev = nchild;
1654 nparent->nchild++;
1655 if (NULL == nprev)
1656 nparent->child = nchild;
1657 else
1658 nprev->next = nchild;
1659
1660 nchild = nnext;
1661 }
1662
1663 return(1);
1664 }
1665
1666 static int
1667 ebool(struct mdoc *mdoc)
1668 {
1669
1670 if (NULL == mdoc->last->child) {
1671 if (MDOC_Sm == mdoc->last->tok)
1672 mdoc->flags ^= MDOC_SMOFF;
1673 return(1);
1674 }
1675
1676 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2);
1677
1678 assert(MDOC_TEXT == mdoc->last->child->type);
1679
1680 if (0 == strcmp(mdoc->last->child->string, "on")) {
1681 if (MDOC_Sm == mdoc->last->tok)
1682 mdoc->flags &= ~MDOC_SMOFF;
1683 return(1);
1684 }
1685 if (0 == strcmp(mdoc->last->child->string, "off")) {
1686 if (MDOC_Sm == mdoc->last->tok)
1687 mdoc->flags |= MDOC_SMOFF;
1688 return(1);
1689 }
1690
1691 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1692 return(1);
1693 }
1694
1695 static int
1696 post_root(POST_ARGS)
1697 {
1698 int ret;
1699 struct mdoc_node *n;
1700
1701 ret = 1;
1702
1703 /* Check that we have a finished prologue. */
1704
1705 if ( ! (MDOC_PBODY & mdoc->flags)) {
1706 ret = 0;
1707 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1708 }
1709
1710 n = mdoc->first;
1711 assert(n);
1712
1713 /* Check that we begin with a proper `Sh'. */
1714
1715 if (NULL == n->child)
1716 mdoc_nmsg(mdoc, n, MANDOCERR_DOC_EMPTY);
1717 else if (MDOC_Sh != n->child->tok)
1718 mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
1719 n->child->line, n->child->pos,
1720 mdoc_macronames[n->child->tok]);
1721
1722 return(ret);
1723 }
1724
1725 static int
1726 post_st(POST_ARGS)
1727 {
1728 struct mdoc_node *ch;
1729 const char *p;
1730
1731 if (NULL == (ch = mdoc->last->child)) {
1732 mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
1733 mdoc->last->line, mdoc->last->pos,
1734 mdoc_macronames[mdoc->last->tok]);
1735 mdoc_node_delete(mdoc, mdoc->last);
1736 return(1);
1737 }
1738
1739 assert(MDOC_TEXT == ch->type);
1740
1741 if (NULL == (p = mdoc_a2st(ch->string))) {
1742 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
1743 mdoc_node_delete(mdoc, mdoc->last);
1744 } else {
1745 free(ch->string);
1746 ch->string = mandoc_strdup(p);
1747 }
1748
1749 return(1);
1750 }
1751
1752 static int
1753 post_rs(POST_ARGS)
1754 {
1755 struct mdoc_node *nn, *next, *prev;
1756 int i, j;
1757
1758 switch (mdoc->last->type) {
1759 case MDOC_HEAD:
1760 check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
1761 return(1);
1762 case MDOC_BODY:
1763 if (mdoc->last->child)
1764 break;
1765 check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
1766 return(1);
1767 default:
1768 return(1);
1769 }
1770
1771 /*
1772 * Make sure only certain types of nodes are allowed within the
1773 * the `Rs' body. Delete offending nodes and raise a warning.
1774 * Do this before re-ordering for the sake of clarity.
1775 */
1776
1777 next = NULL;
1778 for (nn = mdoc->last->child; nn; nn = next) {
1779 for (i = 0; i < RSORD_MAX; i++)
1780 if (nn->tok == rsord[i])
1781 break;
1782
1783 if (i < RSORD_MAX) {
1784 if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
1785 mdoc->last->norm->Rs.quote_T++;
1786 next = nn->next;
1787 continue;
1788 }
1789
1790 next = nn->next;
1791 mandoc_msg(MANDOCERR_RS_SKIP, mdoc->parse,
1792 nn->line, nn->pos, mdoc_macronames[nn->tok]);
1793 mdoc_node_delete(mdoc, nn);
1794 }
1795
1796 /*
1797 * Nothing to sort if only invalid nodes were found
1798 * inside the `Rs' body.
1799 */
1800
1801 if (NULL == mdoc->last->child)
1802 return(1);
1803
1804 /*
1805 * The full `Rs' block needs special handling to order the
1806 * sub-elements according to `rsord'. Pick through each element
1807 * and correctly order it. This is a insertion sort.
1808 */
1809
1810 next = NULL;
1811 for (nn = mdoc->last->child->next; nn; nn = next) {
1812 /* Determine order of `nn'. */
1813 for (i = 0; i < RSORD_MAX; i++)
1814 if (rsord[i] == nn->tok)
1815 break;
1816
1817 /*
1818 * Remove `nn' from the chain. This somewhat
1819 * repeats mdoc_node_unlink(), but since we're
1820 * just re-ordering, there's no need for the
1821 * full unlink process.
1822 */
1823
1824 if (NULL != (next = nn->next))
1825 next->prev = nn->prev;
1826
1827 if (NULL != (prev = nn->prev))
1828 prev->next = nn->next;
1829
1830 nn->prev = nn->next = NULL;
1831
1832 /*
1833 * Scan back until we reach a node that's
1834 * ordered before `nn'.
1835 */
1836
1837 for ( ; prev ; prev = prev->prev) {
1838 /* Determine order of `prev'. */
1839 for (j = 0; j < RSORD_MAX; j++)
1840 if (rsord[j] == prev->tok)
1841 break;
1842
1843 if (j <= i)
1844 break;
1845 }
1846
1847 /*
1848 * Set `nn' back into its correct place in front
1849 * of the `prev' node.
1850 */
1851
1852 nn->prev = prev;
1853
1854 if (prev) {
1855 if (prev->next)
1856 prev->next->prev = nn;
1857 nn->next = prev->next;
1858 prev->next = nn;
1859 } else {
1860 mdoc->last->child->prev = nn;
1861 nn->next = mdoc->last->child;
1862 mdoc->last->child = nn;
1863 }
1864 }
1865
1866 return(1);
1867 }
1868
1869 /*
1870 * For some arguments of some macros,
1871 * convert all breakable hyphens into ASCII_HYPH.
1872 */
1873 static int
1874 post_hyph(POST_ARGS)
1875 {
1876 struct mdoc_node *n, *nch;
1877 char *cp;
1878
1879 n = mdoc->last;
1880 switch (n->type) {
1881 case MDOC_HEAD:
1882 if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
1883 break;
1884 return(1);
1885 case MDOC_BODY:
1886 if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
1887 break;
1888 return(1);
1889 case MDOC_ELEM:
1890 break;
1891 default:
1892 return(1);
1893 }
1894
1895 for (nch = n->child; nch; nch = nch->next) {
1896 if (MDOC_TEXT != nch->type)
1897 continue;
1898 cp = nch->string;
1899 if ('\0' == *cp)
1900 continue;
1901 while ('\0' != *(++cp))
1902 if ('-' == *cp &&
1903 isalpha((unsigned char)cp[-1]) &&
1904 isalpha((unsigned char)cp[1]))
1905 *cp = ASCII_HYPH;
1906 }
1907 return(1);
1908 }
1909
1910 static int
1911 post_ns(POST_ARGS)
1912 {
1913
1914 if (MDOC_LINE & mdoc->last->flags)
1915 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NS_SKIP);
1916 return(1);
1917 }
1918
1919 static int
1920 post_sh(POST_ARGS)
1921 {
1922
1923 if (MDOC_HEAD == mdoc->last->type)
1924 return(post_sh_head(mdoc));
1925 if (MDOC_BODY == mdoc->last->type)
1926 return(post_sh_body(mdoc));
1927
1928 return(1);
1929 }
1930
1931 static int
1932 post_sh_body(POST_ARGS)
1933 {
1934 struct mdoc_node *n;
1935
1936 if (SEC_NAME != mdoc->lastsec)
1937 return(1);
1938
1939 /*
1940 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1941 * macros (can have multiple `Nm' and one `Nd'). Note that the
1942 * children of the BODY declaration can also be "text".
1943 */
1944
1945 if (NULL == (n = mdoc->last->child)) {
1946 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1947 mdoc->last->line, mdoc->last->pos, "empty");
1948 return(1);
1949 }
1950
1951 for ( ; n && n->next; n = n->next) {
1952 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1953 continue;
1954 if (MDOC_TEXT == n->type)
1955 continue;
1956 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1957 n->line, n->pos, mdoc_macronames[n->tok]);
1958 }
1959
1960 assert(n);
1961 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1962 return(1);
1963
1964 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1965 n->line, n->pos, mdoc_macronames[n->tok]);
1966 return(1);
1967 }
1968
1969 static int
1970 post_sh_head(POST_ARGS)
1971 {
1972 struct mdoc_node *n;
1973 const char *goodsec;
1974 char *secname;
1975 enum mdoc_sec sec;
1976
1977 /*
1978 * Process a new section. Sections are either "named" or
1979 * "custom". Custom sections are user-defined, while named ones
1980 * follow a conventional order and may only appear in certain
1981 * manual sections.
1982 */
1983
1984 secname = NULL;
1985 sec = SEC_CUSTOM;
1986 mdoc_deroff(&secname, mdoc->last);
1987 sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
1988
1989 /* The NAME should be first. */
1990
1991 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1992 mandoc_msg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
1993 mdoc->last->line, mdoc->last->pos, secname);
1994
1995 /* The SYNOPSIS gets special attention in other areas. */
1996
1997 if (SEC_SYNOPSIS == sec) {
1998 roff_setreg(mdoc->roff, "nS", 1, '=');
1999 mdoc->flags |= MDOC_SYNOPSIS;
2000 } else {
2001 roff_setreg(mdoc->roff, "nS", 0, '=');
2002 mdoc->flags &= ~MDOC_SYNOPSIS;
2003 }
2004
2005 /* Mark our last section. */
2006
2007 mdoc->lastsec = sec;
2008
2009 /*
2010 * Set the section attribute for the current HEAD, for its
2011 * parent BLOCK, and for the HEAD children; the latter can
2012 * only be TEXT nodes, so no recursion is needed.
2013 * For other blocks and elements, including .Sh BODY, this is
2014 * done when allocating the node data structures, but for .Sh
2015 * BLOCK and HEAD, the section is still unknown at that time.
2016 */
2017
2018 mdoc->last->parent->sec = sec;
2019 mdoc->last->sec = sec;
2020 for (n = mdoc->last->child; n; n = n->next)
2021 n->sec = sec;
2022
2023 /* We don't care about custom sections after this. */
2024
2025 if (SEC_CUSTOM == sec) {
2026 free(secname);
2027 return(1);
2028 }
2029
2030 /*
2031 * Check whether our non-custom section is being repeated or is
2032 * out of order.
2033 */
2034
2035 if (sec == mdoc->lastnamed)
2036 mandoc_msg(MANDOCERR_SEC_REP, mdoc->parse,
2037 mdoc->last->line, mdoc->last->pos, secname);
2038
2039 if (sec < mdoc->lastnamed)
2040 mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->parse,
2041 mdoc->last->line, mdoc->last->pos, secname);
2042
2043 /* Mark the last named section. */
2044
2045 mdoc->lastnamed = sec;
2046
2047 /* Check particular section/manual conventions. */
2048
2049 assert(mdoc->meta.msec);
2050
2051 goodsec = NULL;
2052 switch (sec) {
2053 case SEC_ERRORS:
2054 if (*mdoc->meta.msec == '4')
2055 break;
2056 goodsec = "2, 3, 4, 9";
2057 /* FALLTHROUGH */
2058 case SEC_RETURN_VALUES:
2059 /* FALLTHROUGH */
2060 case SEC_LIBRARY:
2061 if (*mdoc->meta.msec == '2')
2062 break;
2063 if (*mdoc->meta.msec == '3')
2064 break;
2065 if (NULL == goodsec)
2066 goodsec = "2, 3, 9";
2067 /* FALLTHROUGH */
2068 case SEC_CONTEXT:
2069 if (*mdoc->meta.msec == '9')
2070 break;
2071 if (NULL == goodsec)
2072 goodsec = "9";
2073 mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
2074 mdoc->last->line, mdoc->last->pos,
2075 "%s for %s only", secname, goodsec);
2076 break;
2077 default:
2078 break;
2079 }
2080
2081 free(secname);
2082 return(1);
2083 }
2084
2085 static int
2086 post_ignpar(POST_ARGS)
2087 {
2088 struct mdoc_node *np;
2089
2090 if (MDOC_BODY != mdoc->last->type)
2091 return(1);
2092
2093 if (NULL != (np = mdoc->last->child))
2094 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2095 mandoc_vmsg(MANDOCERR_PAR_SKIP,
2096 mdoc->parse, np->line, np->pos,
2097 "%s after %s", mdoc_macronames[np->tok],
2098 mdoc_macronames[mdoc->last->tok]);
2099 mdoc_node_delete(mdoc, np);
2100 }
2101
2102 if (NULL != (np = mdoc->last->last))
2103 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2104 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2105 np->line, np->pos, "%s at the end of %s",
2106 mdoc_macronames[np->tok],
2107 mdoc_macronames[mdoc->last->tok]);
2108 mdoc_node_delete(mdoc, np);
2109 }
2110
2111 return(1);
2112 }
2113
2114 static int
2115 pre_par(PRE_ARGS)
2116 {
2117
2118 if (NULL == mdoc->last)
2119 return(1);
2120 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2121 return(1);
2122
2123 /*
2124 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2125 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2126 */
2127
2128 if (MDOC_Pp != mdoc->last->tok &&
2129 MDOC_Lp != mdoc->last->tok &&
2130 MDOC_br != mdoc->last->tok)
2131 return(1);
2132 if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2133 return(1);
2134 if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2135 return(1);
2136 if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2137 return(1);
2138
2139 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2140 mdoc->last->line, mdoc->last->pos,
2141 "%s before %s", mdoc_macronames[mdoc->last->tok],
2142 mdoc_macronames[n->tok]);
2143 mdoc_node_delete(mdoc, mdoc->last);
2144 return(1);
2145 }
2146
2147 static int
2148 post_par(POST_ARGS)
2149 {
2150 struct mdoc_node *np;
2151
2152 if (MDOC_ELEM != mdoc->last->type &&
2153 MDOC_BLOCK != mdoc->last->type)
2154 return(1);
2155
2156 if (NULL == (np = mdoc->last->prev)) {
2157 np = mdoc->last->parent;
2158 if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
2159 return(1);
2160 } else {
2161 if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
2162 (MDOC_br != mdoc->last->tok ||
2163 (MDOC_sp != np->tok && MDOC_br != np->tok)))
2164 return(1);
2165 }
2166
2167 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2168 mdoc->last->line, mdoc->last->pos,
2169 "%s after %s", mdoc_macronames[mdoc->last->tok],
2170 mdoc_macronames[np->tok]);
2171 mdoc_node_delete(mdoc, mdoc->last);
2172 return(1);
2173 }
2174
2175 static int
2176 pre_literal(PRE_ARGS)
2177 {
2178
2179 if (MDOC_BODY != n->type)
2180 return(1);
2181
2182 /*
2183 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2184 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2185 */
2186
2187 switch (n->tok) {
2188 case MDOC_Dl:
2189 mdoc->flags |= MDOC_LITERAL;
2190 break;
2191 case MDOC_Bd:
2192 if (DISP_literal == n->norm->Bd.type)
2193 mdoc->flags |= MDOC_LITERAL;
2194 if (DISP_unfilled == n->norm->Bd.type)
2195 mdoc->flags |= MDOC_LITERAL;
2196 break;
2197 default:
2198 abort();
2199 /* NOTREACHED */
2200 }
2201
2202 return(1);
2203 }
2204
2205 static int
2206 post_dd(POST_ARGS)
2207 {
2208 struct mdoc_node *n;
2209 char *datestr;
2210
2211 if (mdoc->meta.date)
2212 free(mdoc->meta.date);
2213
2214 n = mdoc->last;
2215 if (NULL == n->child || '\0' == n->child->string[0]) {
2216 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
2217 mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
2218 return(1);
2219 }
2220
2221 datestr = NULL;
2222 mdoc_deroff(&datestr, n);
2223 if (mdoc->quick)
2224 mdoc->meta.date = datestr;
2225 else {
2226 mdoc->meta.date = mandoc_normdate(mdoc->parse,
2227 datestr, n->line, n->pos);
2228 free(datestr);
2229 }
2230 return(1);
2231 }
2232
2233 static int
2234 post_dt(POST_ARGS)
2235 {
2236 struct mdoc_node *nn, *n;
2237 const char *cp;
2238 char *p;
2239
2240 n = mdoc->last;
2241
2242 if (mdoc->meta.title)
2243 free(mdoc->meta.title);
2244 if (mdoc->meta.vol)
2245 free(mdoc->meta.vol);
2246 if (mdoc->meta.arch)
2247 free(mdoc->meta.arch);
2248
2249 mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
2250
2251 /* First check that all characters are uppercase. */
2252
2253 if (NULL != (nn = n->child))
2254 for (p = nn->string; *p; p++) {
2255 if (toupper((unsigned char)*p) == *p)
2256 continue;
2257 mandoc_msg(MANDOCERR_TITLE_CASE,
2258 mdoc->parse, nn->line,
2259 nn->pos + (p - nn->string),
2260 nn->string);
2261 break;
2262 }
2263
2264 /* Handles: `.Dt'
2265 * title = unknown, volume = local, msec = 0, arch = NULL
2266 */
2267
2268 if (NULL == (nn = n->child)) {
2269 /* XXX: make these macro values. */
2270 /* FIXME: warn about missing values. */
2271 mdoc->meta.title = mandoc_strdup("UNKNOWN");
2272 mdoc->meta.vol = mandoc_strdup("LOCAL");
2273 mdoc->meta.msec = mandoc_strdup("1");
2274 return(1);
2275 }
2276
2277 /* Handles: `.Dt TITLE'
2278 * title = TITLE, volume = local, msec = 0, arch = NULL
2279 */
2280
2281 mdoc->meta.title = mandoc_strdup(
2282 '\0' == nn->string[0] ? "UNKNOWN" : nn->string);
2283
2284 if (NULL == (nn = nn->next)) {
2285 /* FIXME: warn about missing msec. */
2286 /* XXX: make this a macro value. */
2287 mdoc->meta.vol = mandoc_strdup("LOCAL");
2288 mdoc->meta.msec = mandoc_strdup("1");
2289 return(1);
2290 }
2291
2292 /* Handles: `.Dt TITLE SEC'
2293 * title = TITLE,
2294 * volume = SEC is msec ? format(msec) : SEC,
2295 * msec = SEC is msec ? atoi(msec) : 0,
2296 * arch = NULL
2297 */
2298
2299 cp = mandoc_a2msec(nn->string);
2300 if (cp) {
2301 mdoc->meta.vol = mandoc_strdup(cp);
2302 mdoc->meta.msec = mandoc_strdup(nn->string);
2303 } else {
2304 mandoc_msg(MANDOCERR_MSEC_BAD, mdoc->parse,
2305 nn->line, nn->pos, nn->string);
2306 mdoc->meta.vol = mandoc_strdup(nn->string);
2307 mdoc->meta.msec = mandoc_strdup(nn->string);
2308 }
2309
2310 if (NULL == (nn = nn->next))
2311 return(1);
2312
2313 /* Handles: `.Dt TITLE SEC VOL'
2314 * title = TITLE,
2315 * volume = VOL is vol ? format(VOL) :
2316 * VOL is arch ? format(arch) :
2317 * VOL
2318 */
2319
2320 cp = mdoc_a2vol(nn->string);
2321 if (cp) {
2322 free(mdoc->meta.vol);
2323 mdoc->meta.vol = mandoc_strdup(cp);
2324 } else {
2325 cp = mdoc_a2arch(nn->string);
2326 if (NULL == cp) {
2327 mandoc_msg(MANDOCERR_ARCH_BAD, mdoc->parse,
2328 nn->line, nn->pos, nn->string);
2329 free(mdoc->meta.vol);
2330 mdoc->meta.vol = mandoc_strdup(nn->string);
2331 } else
2332 mdoc->meta.arch = mandoc_strdup(cp);
2333 }
2334
2335 /* Ignore any subsequent parameters... */
2336 /* FIXME: warn about subsequent parameters. */
2337
2338 return(1);
2339 }
2340
2341 static int
2342 post_prol(POST_ARGS)
2343 {
2344 /*
2345 * Remove prologue macros from the document after they're
2346 * processed. The final document uses mdoc_meta for these
2347 * values and discards the originals.
2348 */
2349
2350 mdoc_node_delete(mdoc, mdoc->last);
2351 if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
2352 mdoc->flags |= MDOC_PBODY;
2353
2354 return(1);
2355 }
2356
2357 static int
2358 post_bx(POST_ARGS)
2359 {
2360 struct mdoc_node *n;
2361
2362 /*
2363 * Make `Bx's second argument always start with an uppercase
2364 * letter. Groff checks if it's an "accepted" term, but we just
2365 * uppercase blindly.
2366 */
2367
2368 n = mdoc->last->child;
2369 if (n && NULL != (n = n->next))
2370 *n->string = (char)toupper((unsigned char)*n->string);
2371
2372 return(1);
2373 }
2374
2375 static int
2376 post_os(POST_ARGS)
2377 {
2378 #ifndef OSNAME
2379 struct utsname utsname;
2380 static char *defbuf;
2381 #endif
2382 struct mdoc_node *n;
2383
2384 n = mdoc->last;
2385
2386 /*
2387 * Set the operating system by way of the `Os' macro.
2388 * The order of precedence is:
2389 * 1. the argument of the `Os' macro, unless empty
2390 * 2. the -Ios=foo command line argument, if provided
2391 * 3. -DOSNAME="\"foo\"", if provided during compilation
2392 * 4. "sysname release" from uname(3)
2393 */
2394
2395 free(mdoc->meta.os);
2396 mdoc->meta.os = NULL;
2397 mdoc_deroff(&mdoc->meta.os, n);
2398 if (mdoc->meta.os)
2399 return(1);
2400
2401 if (mdoc->defos) {
2402 mdoc->meta.os = mandoc_strdup(mdoc->defos);
2403 return(1);
2404 }
2405
2406 #ifdef OSNAME
2407 mdoc->meta.os = mandoc_strdup(OSNAME);
2408 #else /*!OSNAME */
2409 if (NULL == defbuf) {
2410 if (-1 == uname(&utsname)) {
2411 mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2412 defbuf = mandoc_strdup("UNKNOWN");
2413 } else
2414 mandoc_asprintf(&defbuf, "%s %s",
2415 utsname.sysname, utsname.release);
2416 }
2417 mdoc->meta.os = mandoc_strdup(defbuf);
2418 #endif /*!OSNAME*/
2419 return(1);
2420 }
2421
2422 static int
2423 post_std(POST_ARGS)
2424 {
2425 struct mdoc_node *nn, *n;
2426
2427 n = mdoc->last;
2428
2429 /*
2430 * Macros accepting `-std' as an argument have the name of the
2431 * current document (`Nm') filled in as the argument if it's not
2432 * provided.
2433 */
2434
2435 if (n->child)
2436 return(1);
2437
2438 if (NULL == mdoc->meta.name)
2439 return(1);
2440
2441 nn = n;
2442 mdoc->next = MDOC_NEXT_CHILD;
2443
2444 if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2445 return(0);
2446
2447 mdoc->last = nn;
2448 return(1);
2449 }
2450
2451 static enum mdoc_sec
2452 a2sec(const char *p)
2453 {
2454 int i;
2455
2456 for (i = 0; i < (int)SEC__MAX; i++)
2457 if (secnames[i] && 0 == strcmp(p, secnames[i]))
2458 return((enum mdoc_sec)i);
2459
2460 return(SEC_CUSTOM);
2461 }
2462
2463 static size_t
2464 macro2len(enum mdoct macro)
2465 {
2466
2467 switch (macro) {
2468 case MDOC_Ad:
2469 return(12);
2470 case MDOC_Ao:
2471 return(12);
2472 case MDOC_An:
2473 return(12);
2474 case MDOC_Aq:
2475 return(12);
2476 case MDOC_Ar:
2477 return(12);
2478 case MDOC_Bo:
2479 return(12);
2480 case MDOC_Bq:
2481 return(12);
2482 case MDOC_Cd:
2483 return(12);
2484 case MDOC_Cm:
2485 return(10);
2486 case MDOC_Do:
2487 return(10);
2488 case MDOC_Dq:
2489 return(12);
2490 case MDOC_Dv:
2491 return(12);
2492 case MDOC_Eo:
2493 return(12);
2494 case MDOC_Em:
2495 return(10);
2496 case MDOC_Er:
2497 return(17);
2498 case MDOC_Ev:
2499 return(15);
2500 case MDOC_Fa:
2501 return(12);
2502 case MDOC_Fl:
2503 return(10);
2504 case MDOC_Fo:
2505 return(16);
2506 case MDOC_Fn:
2507 return(16);
2508 case MDOC_Ic:
2509 return(10);
2510 case MDOC_Li:
2511 return(16);
2512 case MDOC_Ms:
2513 return(6);
2514 case MDOC_Nm:
2515 return(10);
2516 case MDOC_No:
2517 return(12);
2518 case MDOC_Oo:
2519 return(10);
2520 case MDOC_Op:
2521 return(14);
2522 case MDOC_Pa:
2523 return(32);
2524 case MDOC_Pf:
2525 return(12);
2526 case MDOC_Po:
2527 return(12);
2528 case MDOC_Pq:
2529 return(12);
2530 case MDOC_Ql:
2531 return(16);
2532 case MDOC_Qo:
2533 return(12);
2534 case MDOC_So:
2535 return(12);
2536 case MDOC_Sq:
2537 return(12);
2538 case MDOC_Sy:
2539 return(6);
2540 case MDOC_Sx:
2541 return(16);
2542 case MDOC_Tn:
2543 return(10);
2544 case MDOC_Va:
2545 return(12);
2546 case MDOC_Vt:
2547 return(12);
2548 case MDOC_Xr:
2549 return(10);
2550 default:
2551 break;
2552 };
2553 return(0);
2554 }