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