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