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