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