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