]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
52bd51b2f8205b40c62ac2b8a974c15238b4b91f
[mandoc.git] / mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.221 2014/07/02 13:10:45 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 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1672 mdoc_node_delete(mdoc, mdoc->last);
1673 return(1);
1674 }
1675 check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1676
1677 assert(MDOC_TEXT == mdoc->last->child->type);
1678
1679 if (0 == strcmp(mdoc->last->child->string, "on")) {
1680 if (MDOC_Sm == mdoc->last->tok)
1681 mdoc->flags &= ~MDOC_SMOFF;
1682 return(1);
1683 }
1684 if (0 == strcmp(mdoc->last->child->string, "off")) {
1685 if (MDOC_Sm == mdoc->last->tok)
1686 mdoc->flags |= MDOC_SMOFF;
1687 return(1);
1688 }
1689
1690 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1691 return(1);
1692 }
1693
1694 static int
1695 post_root(POST_ARGS)
1696 {
1697 int ret;
1698 struct mdoc_node *n;
1699
1700 ret = 1;
1701
1702 /* Check that we have a finished prologue. */
1703
1704 if ( ! (MDOC_PBODY & mdoc->flags)) {
1705 ret = 0;
1706 mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1707 }
1708
1709 n = mdoc->first;
1710 assert(n);
1711
1712 /* Check that we begin with a proper `Sh'. */
1713
1714 if (NULL == n->child)
1715 mdoc_nmsg(mdoc, n, MANDOCERR_DOC_EMPTY);
1716 else if (MDOC_Sh != n->child->tok)
1717 mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
1718 n->child->line, n->child->pos,
1719 mdoc_macronames[n->child->tok]);
1720
1721 return(ret);
1722 }
1723
1724 static int
1725 post_st(POST_ARGS)
1726 {
1727 struct mdoc_node *ch;
1728 const char *p;
1729
1730 if (NULL == (ch = mdoc->last->child)) {
1731 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1732 mdoc_node_delete(mdoc, mdoc->last);
1733 return(1);
1734 }
1735
1736 assert(MDOC_TEXT == ch->type);
1737
1738 if (NULL == (p = mdoc_a2st(ch->string))) {
1739 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
1740 mdoc_node_delete(mdoc, mdoc->last);
1741 } else {
1742 free(ch->string);
1743 ch->string = mandoc_strdup(p);
1744 }
1745
1746 return(1);
1747 }
1748
1749 static int
1750 post_rs(POST_ARGS)
1751 {
1752 struct mdoc_node *nn, *next, *prev;
1753 int i, j;
1754
1755 switch (mdoc->last->type) {
1756 case MDOC_HEAD:
1757 check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
1758 return(1);
1759 case MDOC_BODY:
1760 if (mdoc->last->child)
1761 break;
1762 check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
1763 return(1);
1764 default:
1765 return(1);
1766 }
1767
1768 /*
1769 * Make sure only certain types of nodes are allowed within the
1770 * the `Rs' body. Delete offending nodes and raise a warning.
1771 * Do this before re-ordering for the sake of clarity.
1772 */
1773
1774 next = NULL;
1775 for (nn = mdoc->last->child; nn; nn = next) {
1776 for (i = 0; i < RSORD_MAX; i++)
1777 if (nn->tok == rsord[i])
1778 break;
1779
1780 if (i < RSORD_MAX) {
1781 if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
1782 mdoc->last->norm->Rs.quote_T++;
1783 next = nn->next;
1784 continue;
1785 }
1786
1787 next = nn->next;
1788 mandoc_msg(MANDOCERR_RS_SKIP, mdoc->parse,
1789 nn->line, nn->pos, mdoc_macronames[nn->tok]);
1790 mdoc_node_delete(mdoc, nn);
1791 }
1792
1793 /*
1794 * Nothing to sort if only invalid nodes were found
1795 * inside the `Rs' body.
1796 */
1797
1798 if (NULL == mdoc->last->child)
1799 return(1);
1800
1801 /*
1802 * The full `Rs' block needs special handling to order the
1803 * sub-elements according to `rsord'. Pick through each element
1804 * and correctly order it. This is a insertion sort.
1805 */
1806
1807 next = NULL;
1808 for (nn = mdoc->last->child->next; nn; nn = next) {
1809 /* Determine order of `nn'. */
1810 for (i = 0; i < RSORD_MAX; i++)
1811 if (rsord[i] == nn->tok)
1812 break;
1813
1814 /*
1815 * Remove `nn' from the chain. This somewhat
1816 * repeats mdoc_node_unlink(), but since we're
1817 * just re-ordering, there's no need for the
1818 * full unlink process.
1819 */
1820
1821 if (NULL != (next = nn->next))
1822 next->prev = nn->prev;
1823
1824 if (NULL != (prev = nn->prev))
1825 prev->next = nn->next;
1826
1827 nn->prev = nn->next = NULL;
1828
1829 /*
1830 * Scan back until we reach a node that's
1831 * ordered before `nn'.
1832 */
1833
1834 for ( ; prev ; prev = prev->prev) {
1835 /* Determine order of `prev'. */
1836 for (j = 0; j < RSORD_MAX; j++)
1837 if (rsord[j] == prev->tok)
1838 break;
1839
1840 if (j <= i)
1841 break;
1842 }
1843
1844 /*
1845 * Set `nn' back into its correct place in front
1846 * of the `prev' node.
1847 */
1848
1849 nn->prev = prev;
1850
1851 if (prev) {
1852 if (prev->next)
1853 prev->next->prev = nn;
1854 nn->next = prev->next;
1855 prev->next = nn;
1856 } else {
1857 mdoc->last->child->prev = nn;
1858 nn->next = mdoc->last->child;
1859 mdoc->last->child = nn;
1860 }
1861 }
1862
1863 return(1);
1864 }
1865
1866 /*
1867 * For some arguments of some macros,
1868 * convert all breakable hyphens into ASCII_HYPH.
1869 */
1870 static int
1871 post_hyph(POST_ARGS)
1872 {
1873 struct mdoc_node *n, *nch;
1874 char *cp;
1875
1876 n = mdoc->last;
1877 switch (n->type) {
1878 case MDOC_HEAD:
1879 if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
1880 break;
1881 return(1);
1882 case MDOC_BODY:
1883 if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
1884 break;
1885 return(1);
1886 case MDOC_ELEM:
1887 break;
1888 default:
1889 return(1);
1890 }
1891
1892 for (nch = n->child; nch; nch = nch->next) {
1893 if (MDOC_TEXT != nch->type)
1894 continue;
1895 cp = nch->string;
1896 if ('\0' == *cp)
1897 continue;
1898 while ('\0' != *(++cp))
1899 if ('-' == *cp &&
1900 isalpha((unsigned char)cp[-1]) &&
1901 isalpha((unsigned char)cp[1]))
1902 *cp = ASCII_HYPH;
1903 }
1904 return(1);
1905 }
1906
1907 static int
1908 post_ns(POST_ARGS)
1909 {
1910
1911 if (MDOC_LINE & mdoc->last->flags)
1912 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NS_SKIP);
1913 return(1);
1914 }
1915
1916 static int
1917 post_sh(POST_ARGS)
1918 {
1919
1920 if (MDOC_HEAD == mdoc->last->type)
1921 return(post_sh_head(mdoc));
1922 if (MDOC_BODY == mdoc->last->type)
1923 return(post_sh_body(mdoc));
1924
1925 return(1);
1926 }
1927
1928 static int
1929 post_sh_body(POST_ARGS)
1930 {
1931 struct mdoc_node *n;
1932
1933 if (SEC_NAME != mdoc->lastsec)
1934 return(1);
1935
1936 /*
1937 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1938 * macros (can have multiple `Nm' and one `Nd'). Note that the
1939 * children of the BODY declaration can also be "text".
1940 */
1941
1942 if (NULL == (n = mdoc->last->child)) {
1943 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1944 mdoc->last->line, mdoc->last->pos, "empty");
1945 return(1);
1946 }
1947
1948 for ( ; n && n->next; n = n->next) {
1949 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1950 continue;
1951 if (MDOC_TEXT == n->type)
1952 continue;
1953 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1954 n->line, n->pos, mdoc_macronames[n->tok]);
1955 }
1956
1957 assert(n);
1958 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1959 return(1);
1960
1961 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1962 n->line, n->pos, mdoc_macronames[n->tok]);
1963 return(1);
1964 }
1965
1966 static int
1967 post_sh_head(POST_ARGS)
1968 {
1969 struct mdoc_node *n;
1970 const char *goodsec;
1971 char *secname;
1972 enum mdoc_sec sec;
1973
1974 /*
1975 * Process a new section. Sections are either "named" or
1976 * "custom". Custom sections are user-defined, while named ones
1977 * follow a conventional order and may only appear in certain
1978 * manual sections.
1979 */
1980
1981 secname = NULL;
1982 sec = SEC_CUSTOM;
1983 mdoc_deroff(&secname, mdoc->last);
1984 sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
1985
1986 /* The NAME should be first. */
1987
1988 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1989 mandoc_msg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
1990 mdoc->last->line, mdoc->last->pos, secname);
1991
1992 /* The SYNOPSIS gets special attention in other areas. */
1993
1994 if (SEC_SYNOPSIS == sec) {
1995 roff_setreg(mdoc->roff, "nS", 1, '=');
1996 mdoc->flags |= MDOC_SYNOPSIS;
1997 } else {
1998 roff_setreg(mdoc->roff, "nS", 0, '=');
1999 mdoc->flags &= ~MDOC_SYNOPSIS;
2000 }
2001
2002 /* Mark our last section. */
2003
2004 mdoc->lastsec = sec;
2005
2006 /*
2007 * Set the section attribute for the current HEAD, for its
2008 * parent BLOCK, and for the HEAD children; the latter can
2009 * only be TEXT nodes, so no recursion is needed.
2010 * For other blocks and elements, including .Sh BODY, this is
2011 * done when allocating the node data structures, but for .Sh
2012 * BLOCK and HEAD, the section is still unknown at that time.
2013 */
2014
2015 mdoc->last->parent->sec = sec;
2016 mdoc->last->sec = sec;
2017 for (n = mdoc->last->child; n; n = n->next)
2018 n->sec = sec;
2019
2020 /* We don't care about custom sections after this. */
2021
2022 if (SEC_CUSTOM == sec) {
2023 free(secname);
2024 return(1);
2025 }
2026
2027 /*
2028 * Check whether our non-custom section is being repeated or is
2029 * out of order.
2030 */
2031
2032 if (sec == mdoc->lastnamed)
2033 mandoc_msg(MANDOCERR_SEC_REP, mdoc->parse,
2034 mdoc->last->line, mdoc->last->pos, secname);
2035
2036 if (sec < mdoc->lastnamed)
2037 mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->parse,
2038 mdoc->last->line, mdoc->last->pos, secname);
2039
2040 /* Mark the last named section. */
2041
2042 mdoc->lastnamed = sec;
2043
2044 /* Check particular section/manual conventions. */
2045
2046 assert(mdoc->meta.msec);
2047
2048 goodsec = NULL;
2049 switch (sec) {
2050 case SEC_ERRORS:
2051 if (*mdoc->meta.msec == '4')
2052 break;
2053 goodsec = "2, 3, 4, 9";
2054 /* FALLTHROUGH */
2055 case SEC_RETURN_VALUES:
2056 /* FALLTHROUGH */
2057 case SEC_LIBRARY:
2058 if (*mdoc->meta.msec == '2')
2059 break;
2060 if (*mdoc->meta.msec == '3')
2061 break;
2062 if (NULL == goodsec)
2063 goodsec = "2, 3, 9";
2064 /* FALLTHROUGH */
2065 case SEC_CONTEXT:
2066 if (*mdoc->meta.msec == '9')
2067 break;
2068 if (NULL == goodsec)
2069 goodsec = "9";
2070 mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
2071 mdoc->last->line, mdoc->last->pos,
2072 "%s for %s only", secname, goodsec);
2073 break;
2074 default:
2075 break;
2076 }
2077
2078 free(secname);
2079 return(1);
2080 }
2081
2082 static int
2083 post_ignpar(POST_ARGS)
2084 {
2085 struct mdoc_node *np;
2086
2087 if (MDOC_BODY != mdoc->last->type)
2088 return(1);
2089
2090 if (NULL != (np = mdoc->last->child))
2091 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2092 mandoc_vmsg(MANDOCERR_PAR_SKIP,
2093 mdoc->parse, np->line, np->pos,
2094 "%s after %s", mdoc_macronames[np->tok],
2095 mdoc_macronames[mdoc->last->tok]);
2096 mdoc_node_delete(mdoc, np);
2097 }
2098
2099 if (NULL != (np = mdoc->last->last))
2100 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2101 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2102 np->line, np->pos, "%s at the end of %s",
2103 mdoc_macronames[np->tok],
2104 mdoc_macronames[mdoc->last->tok]);
2105 mdoc_node_delete(mdoc, np);
2106 }
2107
2108 return(1);
2109 }
2110
2111 static int
2112 pre_par(PRE_ARGS)
2113 {
2114
2115 if (NULL == mdoc->last)
2116 return(1);
2117 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2118 return(1);
2119
2120 /*
2121 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2122 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2123 */
2124
2125 if (MDOC_Pp != mdoc->last->tok &&
2126 MDOC_Lp != mdoc->last->tok &&
2127 MDOC_br != mdoc->last->tok)
2128 return(1);
2129 if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2130 return(1);
2131 if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2132 return(1);
2133 if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2134 return(1);
2135
2136 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2137 mdoc->last->line, mdoc->last->pos,
2138 "%s before %s", mdoc_macronames[mdoc->last->tok],
2139 mdoc_macronames[n->tok]);
2140 mdoc_node_delete(mdoc, mdoc->last);
2141 return(1);
2142 }
2143
2144 static int
2145 post_par(POST_ARGS)
2146 {
2147 struct mdoc_node *np;
2148
2149 if (MDOC_ELEM != mdoc->last->type &&
2150 MDOC_BLOCK != mdoc->last->type)
2151 return(1);
2152
2153 if (NULL == (np = mdoc->last->prev)) {
2154 np = mdoc->last->parent;
2155 if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
2156 return(1);
2157 } else {
2158 if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
2159 (MDOC_br != mdoc->last->tok ||
2160 (MDOC_sp != np->tok && MDOC_br != np->tok)))
2161 return(1);
2162 }
2163
2164 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2165 mdoc->last->line, mdoc->last->pos,
2166 "%s after %s", mdoc_macronames[mdoc->last->tok],
2167 mdoc_macronames[np->tok]);
2168 mdoc_node_delete(mdoc, mdoc->last);
2169 return(1);
2170 }
2171
2172 static int
2173 pre_literal(PRE_ARGS)
2174 {
2175
2176 if (MDOC_BODY != n->type)
2177 return(1);
2178
2179 /*
2180 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2181 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2182 */
2183
2184 switch (n->tok) {
2185 case MDOC_Dl:
2186 mdoc->flags |= MDOC_LITERAL;
2187 break;
2188 case MDOC_Bd:
2189 if (DISP_literal == n->norm->Bd.type)
2190 mdoc->flags |= MDOC_LITERAL;
2191 if (DISP_unfilled == n->norm->Bd.type)
2192 mdoc->flags |= MDOC_LITERAL;
2193 break;
2194 default:
2195 abort();
2196 /* NOTREACHED */
2197 }
2198
2199 return(1);
2200 }
2201
2202 static int
2203 post_dd(POST_ARGS)
2204 {
2205 struct mdoc_node *n;
2206 char *datestr;
2207
2208 if (mdoc->meta.date)
2209 free(mdoc->meta.date);
2210
2211 n = mdoc->last;
2212 if (NULL == n->child || '\0' == n->child->string[0]) {
2213 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
2214 mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
2215 return(1);
2216 }
2217
2218 datestr = NULL;
2219 mdoc_deroff(&datestr, n);
2220 if (mdoc->quick)
2221 mdoc->meta.date = datestr;
2222 else {
2223 mdoc->meta.date = mandoc_normdate(mdoc->parse,
2224 datestr, n->line, n->pos);
2225 free(datestr);
2226 }
2227 return(1);
2228 }
2229
2230 static int
2231 post_dt(POST_ARGS)
2232 {
2233 struct mdoc_node *nn, *n;
2234 const char *cp;
2235 char *p;
2236
2237 n = mdoc->last;
2238
2239 if (mdoc->meta.title)
2240 free(mdoc->meta.title);
2241 if (mdoc->meta.vol)
2242 free(mdoc->meta.vol);
2243 if (mdoc->meta.arch)
2244 free(mdoc->meta.arch);
2245
2246 mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
2247
2248 /* First check that all characters are uppercase. */
2249
2250 if (NULL != (nn = n->child))
2251 for (p = nn->string; *p; p++) {
2252 if (toupper((unsigned char)*p) == *p)
2253 continue;
2254 mandoc_msg(MANDOCERR_TITLE_CASE,
2255 mdoc->parse, nn->line,
2256 nn->pos + (p - nn->string),
2257 nn->string);
2258 break;
2259 }
2260
2261 /* Handles: `.Dt'
2262 * title = unknown, volume = local, msec = 0, arch = NULL
2263 */
2264
2265 if (NULL == (nn = n->child)) {
2266 /* XXX: make these macro values. */
2267 /* FIXME: warn about missing values. */
2268 mdoc->meta.title = mandoc_strdup("UNKNOWN");
2269 mdoc->meta.vol = mandoc_strdup("LOCAL");
2270 mdoc->meta.msec = mandoc_strdup("1");
2271 return(1);
2272 }
2273
2274 /* Handles: `.Dt TITLE'
2275 * title = TITLE, volume = local, msec = 0, arch = NULL
2276 */
2277
2278 mdoc->meta.title = mandoc_strdup(
2279 '\0' == nn->string[0] ? "UNKNOWN" : nn->string);
2280
2281 if (NULL == (nn = nn->next)) {
2282 /* FIXME: warn about missing msec. */
2283 /* XXX: make this a macro value. */
2284 mdoc->meta.vol = mandoc_strdup("LOCAL");
2285 mdoc->meta.msec = mandoc_strdup("1");
2286 return(1);
2287 }
2288
2289 /* Handles: `.Dt TITLE SEC'
2290 * title = TITLE,
2291 * volume = SEC is msec ? format(msec) : SEC,
2292 * msec = SEC is msec ? atoi(msec) : 0,
2293 * arch = NULL
2294 */
2295
2296 cp = mandoc_a2msec(nn->string);
2297 if (cp) {
2298 mdoc->meta.vol = mandoc_strdup(cp);
2299 mdoc->meta.msec = mandoc_strdup(nn->string);
2300 } else {
2301 mandoc_msg(MANDOCERR_MSEC_BAD, mdoc->parse,
2302 nn->line, nn->pos, nn->string);
2303 mdoc->meta.vol = mandoc_strdup(nn->string);
2304 mdoc->meta.msec = mandoc_strdup(nn->string);
2305 }
2306
2307 if (NULL == (nn = nn->next))
2308 return(1);
2309
2310 /* Handles: `.Dt TITLE SEC VOL'
2311 * title = TITLE,
2312 * volume = VOL is vol ? format(VOL) :
2313 * VOL is arch ? format(arch) :
2314 * VOL
2315 */
2316
2317 cp = mdoc_a2vol(nn->string);
2318 if (cp) {
2319 free(mdoc->meta.vol);
2320 mdoc->meta.vol = mandoc_strdup(cp);
2321 } else {
2322 cp = mdoc_a2arch(nn->string);
2323 if (NULL == cp) {
2324 mandoc_msg(MANDOCERR_ARCH_BAD, mdoc->parse,
2325 nn->line, nn->pos, nn->string);
2326 free(mdoc->meta.vol);
2327 mdoc->meta.vol = mandoc_strdup(nn->string);
2328 } else
2329 mdoc->meta.arch = mandoc_strdup(cp);
2330 }
2331
2332 /* Ignore any subsequent parameters... */
2333 /* FIXME: warn about subsequent parameters. */
2334
2335 return(1);
2336 }
2337
2338 static int
2339 post_prol(POST_ARGS)
2340 {
2341 /*
2342 * Remove prologue macros from the document after they're
2343 * processed. The final document uses mdoc_meta for these
2344 * values and discards the originals.
2345 */
2346
2347 mdoc_node_delete(mdoc, mdoc->last);
2348 if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
2349 mdoc->flags |= MDOC_PBODY;
2350
2351 return(1);
2352 }
2353
2354 static int
2355 post_bx(POST_ARGS)
2356 {
2357 struct mdoc_node *n;
2358
2359 /*
2360 * Make `Bx's second argument always start with an uppercase
2361 * letter. Groff checks if it's an "accepted" term, but we just
2362 * uppercase blindly.
2363 */
2364
2365 n = mdoc->last->child;
2366 if (n && NULL != (n = n->next))
2367 *n->string = (char)toupper((unsigned char)*n->string);
2368
2369 return(1);
2370 }
2371
2372 static int
2373 post_os(POST_ARGS)
2374 {
2375 #ifndef OSNAME
2376 struct utsname utsname;
2377 static char *defbuf;
2378 #endif
2379 struct mdoc_node *n;
2380
2381 n = mdoc->last;
2382
2383 /*
2384 * Set the operating system by way of the `Os' macro.
2385 * The order of precedence is:
2386 * 1. the argument of the `Os' macro, unless empty
2387 * 2. the -Ios=foo command line argument, if provided
2388 * 3. -DOSNAME="\"foo\"", if provided during compilation
2389 * 4. "sysname release" from uname(3)
2390 */
2391
2392 free(mdoc->meta.os);
2393 mdoc->meta.os = NULL;
2394 mdoc_deroff(&mdoc->meta.os, n);
2395 if (mdoc->meta.os)
2396 return(1);
2397
2398 if (mdoc->defos) {
2399 mdoc->meta.os = mandoc_strdup(mdoc->defos);
2400 return(1);
2401 }
2402
2403 #ifdef OSNAME
2404 mdoc->meta.os = mandoc_strdup(OSNAME);
2405 #else /*!OSNAME */
2406 if (NULL == defbuf) {
2407 if (-1 == uname(&utsname)) {
2408 mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2409 defbuf = mandoc_strdup("UNKNOWN");
2410 } else
2411 mandoc_asprintf(&defbuf, "%s %s",
2412 utsname.sysname, utsname.release);
2413 }
2414 mdoc->meta.os = mandoc_strdup(defbuf);
2415 #endif /*!OSNAME*/
2416 return(1);
2417 }
2418
2419 static int
2420 post_std(POST_ARGS)
2421 {
2422 struct mdoc_node *nn, *n;
2423
2424 n = mdoc->last;
2425
2426 /*
2427 * Macros accepting `-std' as an argument have the name of the
2428 * current document (`Nm') filled in as the argument if it's not
2429 * provided.
2430 */
2431
2432 if (n->child)
2433 return(1);
2434
2435 if (NULL == mdoc->meta.name)
2436 return(1);
2437
2438 nn = n;
2439 mdoc->next = MDOC_NEXT_CHILD;
2440
2441 if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2442 return(0);
2443
2444 mdoc->last = nn;
2445 return(1);
2446 }
2447
2448 static enum mdoc_sec
2449 a2sec(const char *p)
2450 {
2451 int i;
2452
2453 for (i = 0; i < (int)SEC__MAX; i++)
2454 if (secnames[i] && 0 == strcmp(p, secnames[i]))
2455 return((enum mdoc_sec)i);
2456
2457 return(SEC_CUSTOM);
2458 }
2459
2460 static size_t
2461 macro2len(enum mdoct macro)
2462 {
2463
2464 switch (macro) {
2465 case MDOC_Ad:
2466 return(12);
2467 case MDOC_Ao:
2468 return(12);
2469 case MDOC_An:
2470 return(12);
2471 case MDOC_Aq:
2472 return(12);
2473 case MDOC_Ar:
2474 return(12);
2475 case MDOC_Bo:
2476 return(12);
2477 case MDOC_Bq:
2478 return(12);
2479 case MDOC_Cd:
2480 return(12);
2481 case MDOC_Cm:
2482 return(10);
2483 case MDOC_Do:
2484 return(10);
2485 case MDOC_Dq:
2486 return(12);
2487 case MDOC_Dv:
2488 return(12);
2489 case MDOC_Eo:
2490 return(12);
2491 case MDOC_Em:
2492 return(10);
2493 case MDOC_Er:
2494 return(17);
2495 case MDOC_Ev:
2496 return(15);
2497 case MDOC_Fa:
2498 return(12);
2499 case MDOC_Fl:
2500 return(10);
2501 case MDOC_Fo:
2502 return(16);
2503 case MDOC_Fn:
2504 return(16);
2505 case MDOC_Ic:
2506 return(10);
2507 case MDOC_Li:
2508 return(16);
2509 case MDOC_Ms:
2510 return(6);
2511 case MDOC_Nm:
2512 return(10);
2513 case MDOC_No:
2514 return(12);
2515 case MDOC_Oo:
2516 return(10);
2517 case MDOC_Op:
2518 return(14);
2519 case MDOC_Pa:
2520 return(32);
2521 case MDOC_Pf:
2522 return(12);
2523 case MDOC_Po:
2524 return(12);
2525 case MDOC_Pq:
2526 return(12);
2527 case MDOC_Ql:
2528 return(16);
2529 case MDOC_Qo:
2530 return(12);
2531 case MDOC_So:
2532 return(12);
2533 case MDOC_Sq:
2534 return(12);
2535 case MDOC_Sy:
2536 return(6);
2537 case MDOC_Sx:
2538 return(16);
2539 case MDOC_Tn:
2540 return(10);
2541 case MDOC_Va:
2542 return(12);
2543 case MDOC_Vt:
2544 return(12);
2545 case MDOC_Xr:
2546 return(10);
2547 default:
2548 break;
2549 };
2550 return(0);
2551 }