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