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