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