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