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