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