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