]> git.cameronkatri.com Git - mandoc.git/blob - mdoc_validate.c
Clean up messages related to plain text and to escape sequences.
[mandoc.git] / mdoc_validate.c
1 /* $Id: mdoc_validate.c,v 1.229 2014/07/06 19:09:00 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 * Make sure only certain types of nodes are allowed within the
1772 * the `Rs' body. Delete offending nodes and raise a warning.
1773 * Do this before re-ordering for the sake of clarity.
1774 */
1775
1776 next = NULL;
1777 for (nn = mdoc->last->child; nn; nn = next) {
1778 for (i = 0; i < RSORD_MAX; i++)
1779 if (nn->tok == rsord[i])
1780 break;
1781
1782 if (i < RSORD_MAX) {
1783 if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
1784 mdoc->last->norm->Rs.quote_T++;
1785 next = nn->next;
1786 continue;
1787 }
1788
1789 next = nn->next;
1790 mandoc_msg(MANDOCERR_RS_SKIP, mdoc->parse,
1791 nn->line, nn->pos, mdoc_macronames[nn->tok]);
1792 mdoc_node_delete(mdoc, nn);
1793 }
1794
1795 /*
1796 * Nothing to sort if only invalid nodes were found
1797 * inside the `Rs' body.
1798 */
1799
1800 if (NULL == mdoc->last->child)
1801 return(1);
1802
1803 /*
1804 * The full `Rs' block needs special handling to order the
1805 * sub-elements according to `rsord'. Pick through each element
1806 * and correctly order it. This is a insertion sort.
1807 */
1808
1809 next = NULL;
1810 for (nn = mdoc->last->child->next; nn; nn = next) {
1811 /* Determine order of `nn'. */
1812 for (i = 0; i < RSORD_MAX; i++)
1813 if (rsord[i] == nn->tok)
1814 break;
1815
1816 /*
1817 * Remove `nn' from the chain. This somewhat
1818 * repeats mdoc_node_unlink(), but since we're
1819 * just re-ordering, there's no need for the
1820 * full unlink process.
1821 */
1822
1823 if (NULL != (next = nn->next))
1824 next->prev = nn->prev;
1825
1826 if (NULL != (prev = nn->prev))
1827 prev->next = nn->next;
1828
1829 nn->prev = nn->next = NULL;
1830
1831 /*
1832 * Scan back until we reach a node that's
1833 * ordered before `nn'.
1834 */
1835
1836 for ( ; prev ; prev = prev->prev) {
1837 /* Determine order of `prev'. */
1838 for (j = 0; j < RSORD_MAX; j++)
1839 if (rsord[j] == prev->tok)
1840 break;
1841
1842 if (j <= i)
1843 break;
1844 }
1845
1846 /*
1847 * Set `nn' back into its correct place in front
1848 * of the `prev' node.
1849 */
1850
1851 nn->prev = prev;
1852
1853 if (prev) {
1854 if (prev->next)
1855 prev->next->prev = nn;
1856 nn->next = prev->next;
1857 prev->next = nn;
1858 } else {
1859 mdoc->last->child->prev = nn;
1860 nn->next = mdoc->last->child;
1861 mdoc->last->child = nn;
1862 }
1863 }
1864
1865 return(1);
1866 }
1867
1868 /*
1869 * For some arguments of some macros,
1870 * convert all breakable hyphens into ASCII_HYPH.
1871 */
1872 static int
1873 post_hyph(POST_ARGS)
1874 {
1875 struct mdoc_node *n, *nch;
1876 char *cp;
1877
1878 n = mdoc->last;
1879 switch (n->type) {
1880 case MDOC_HEAD:
1881 if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
1882 break;
1883 return(1);
1884 case MDOC_BODY:
1885 if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
1886 break;
1887 return(1);
1888 case MDOC_ELEM:
1889 break;
1890 default:
1891 return(1);
1892 }
1893
1894 for (nch = n->child; nch; nch = nch->next) {
1895 if (MDOC_TEXT != nch->type)
1896 continue;
1897 cp = nch->string;
1898 if ('\0' == *cp)
1899 continue;
1900 while ('\0' != *(++cp))
1901 if ('-' == *cp &&
1902 isalpha((unsigned char)cp[-1]) &&
1903 isalpha((unsigned char)cp[1]))
1904 *cp = ASCII_HYPH;
1905 }
1906 return(1);
1907 }
1908
1909 static int
1910 post_ns(POST_ARGS)
1911 {
1912
1913 if (MDOC_LINE & mdoc->last->flags)
1914 mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NS_SKIP);
1915 return(1);
1916 }
1917
1918 static int
1919 post_sh(POST_ARGS)
1920 {
1921
1922 if (MDOC_HEAD == mdoc->last->type)
1923 return(post_sh_head(mdoc));
1924 if (MDOC_BODY == mdoc->last->type)
1925 return(post_sh_body(mdoc));
1926
1927 return(1);
1928 }
1929
1930 static int
1931 post_sh_body(POST_ARGS)
1932 {
1933 struct mdoc_node *n;
1934
1935 if (SEC_NAME != mdoc->lastsec)
1936 return(1);
1937
1938 /*
1939 * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1940 * macros (can have multiple `Nm' and one `Nd'). Note that the
1941 * children of the BODY declaration can also be "text".
1942 */
1943
1944 if (NULL == (n = mdoc->last->child)) {
1945 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1946 mdoc->last->line, mdoc->last->pos, "empty");
1947 return(1);
1948 }
1949
1950 for ( ; n && n->next; n = n->next) {
1951 if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1952 continue;
1953 if (MDOC_TEXT == n->type)
1954 continue;
1955 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1956 n->line, n->pos, mdoc_macronames[n->tok]);
1957 }
1958
1959 assert(n);
1960 if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1961 return(1);
1962
1963 mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1964 n->line, n->pos, mdoc_macronames[n->tok]);
1965 return(1);
1966 }
1967
1968 static int
1969 post_sh_head(POST_ARGS)
1970 {
1971 struct mdoc_node *n;
1972 const char *goodsec;
1973 char *secname;
1974 enum mdoc_sec sec;
1975
1976 /*
1977 * Process a new section. Sections are either "named" or
1978 * "custom". Custom sections are user-defined, while named ones
1979 * follow a conventional order and may only appear in certain
1980 * manual sections.
1981 */
1982
1983 secname = NULL;
1984 sec = SEC_CUSTOM;
1985 mdoc_deroff(&secname, mdoc->last);
1986 sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
1987
1988 /* The NAME should be first. */
1989
1990 if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1991 mandoc_msg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
1992 mdoc->last->line, mdoc->last->pos, secname);
1993
1994 /* The SYNOPSIS gets special attention in other areas. */
1995
1996 if (SEC_SYNOPSIS == sec) {
1997 roff_setreg(mdoc->roff, "nS", 1, '=');
1998 mdoc->flags |= MDOC_SYNOPSIS;
1999 } else {
2000 roff_setreg(mdoc->roff, "nS", 0, '=');
2001 mdoc->flags &= ~MDOC_SYNOPSIS;
2002 }
2003
2004 /* Mark our last section. */
2005
2006 mdoc->lastsec = sec;
2007
2008 /*
2009 * Set the section attribute for the current HEAD, for its
2010 * parent BLOCK, and for the HEAD children; the latter can
2011 * only be TEXT nodes, so no recursion is needed.
2012 * For other blocks and elements, including .Sh BODY, this is
2013 * done when allocating the node data structures, but for .Sh
2014 * BLOCK and HEAD, the section is still unknown at that time.
2015 */
2016
2017 mdoc->last->parent->sec = sec;
2018 mdoc->last->sec = sec;
2019 for (n = mdoc->last->child; n; n = n->next)
2020 n->sec = sec;
2021
2022 /* We don't care about custom sections after this. */
2023
2024 if (SEC_CUSTOM == sec) {
2025 free(secname);
2026 return(1);
2027 }
2028
2029 /*
2030 * Check whether our non-custom section is being repeated or is
2031 * out of order.
2032 */
2033
2034 if (sec == mdoc->lastnamed)
2035 mandoc_msg(MANDOCERR_SEC_REP, mdoc->parse,
2036 mdoc->last->line, mdoc->last->pos, secname);
2037
2038 if (sec < mdoc->lastnamed)
2039 mandoc_msg(MANDOCERR_SEC_ORDER, mdoc->parse,
2040 mdoc->last->line, mdoc->last->pos, secname);
2041
2042 /* Mark the last named section. */
2043
2044 mdoc->lastnamed = sec;
2045
2046 /* Check particular section/manual conventions. */
2047
2048 assert(mdoc->meta.msec);
2049
2050 goodsec = NULL;
2051 switch (sec) {
2052 case SEC_ERRORS:
2053 if (*mdoc->meta.msec == '4')
2054 break;
2055 goodsec = "2, 3, 4, 9";
2056 /* FALLTHROUGH */
2057 case SEC_RETURN_VALUES:
2058 /* FALLTHROUGH */
2059 case SEC_LIBRARY:
2060 if (*mdoc->meta.msec == '2')
2061 break;
2062 if (*mdoc->meta.msec == '3')
2063 break;
2064 if (NULL == goodsec)
2065 goodsec = "2, 3, 9";
2066 /* FALLTHROUGH */
2067 case SEC_CONTEXT:
2068 if (*mdoc->meta.msec == '9')
2069 break;
2070 if (NULL == goodsec)
2071 goodsec = "9";
2072 mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
2073 mdoc->last->line, mdoc->last->pos,
2074 "%s for %s only", secname, goodsec);
2075 break;
2076 default:
2077 break;
2078 }
2079
2080 free(secname);
2081 return(1);
2082 }
2083
2084 static int
2085 post_ignpar(POST_ARGS)
2086 {
2087 struct mdoc_node *np;
2088
2089 if (MDOC_BODY != mdoc->last->type)
2090 return(1);
2091
2092 if (NULL != (np = mdoc->last->child))
2093 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2094 mandoc_vmsg(MANDOCERR_PAR_SKIP,
2095 mdoc->parse, np->line, np->pos,
2096 "%s after %s", mdoc_macronames[np->tok],
2097 mdoc_macronames[mdoc->last->tok]);
2098 mdoc_node_delete(mdoc, np);
2099 }
2100
2101 if (NULL != (np = mdoc->last->last))
2102 if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2103 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2104 np->line, np->pos, "%s at the end of %s",
2105 mdoc_macronames[np->tok],
2106 mdoc_macronames[mdoc->last->tok]);
2107 mdoc_node_delete(mdoc, np);
2108 }
2109
2110 return(1);
2111 }
2112
2113 static int
2114 pre_par(PRE_ARGS)
2115 {
2116
2117 if (NULL == mdoc->last)
2118 return(1);
2119 if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2120 return(1);
2121
2122 /*
2123 * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2124 * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2125 */
2126
2127 if (MDOC_Pp != mdoc->last->tok &&
2128 MDOC_Lp != mdoc->last->tok &&
2129 MDOC_br != mdoc->last->tok)
2130 return(1);
2131 if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2132 return(1);
2133 if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2134 return(1);
2135 if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2136 return(1);
2137
2138 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2139 mdoc->last->line, mdoc->last->pos,
2140 "%s before %s", mdoc_macronames[mdoc->last->tok],
2141 mdoc_macronames[n->tok]);
2142 mdoc_node_delete(mdoc, mdoc->last);
2143 return(1);
2144 }
2145
2146 static int
2147 post_par(POST_ARGS)
2148 {
2149 struct mdoc_node *np;
2150
2151 if (MDOC_ELEM != mdoc->last->type &&
2152 MDOC_BLOCK != mdoc->last->type)
2153 return(1);
2154
2155 if (NULL == (np = mdoc->last->prev)) {
2156 np = mdoc->last->parent;
2157 if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
2158 return(1);
2159 } else {
2160 if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
2161 (MDOC_br != mdoc->last->tok ||
2162 (MDOC_sp != np->tok && MDOC_br != np->tok)))
2163 return(1);
2164 }
2165
2166 mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2167 mdoc->last->line, mdoc->last->pos,
2168 "%s after %s", mdoc_macronames[mdoc->last->tok],
2169 mdoc_macronames[np->tok]);
2170 mdoc_node_delete(mdoc, mdoc->last);
2171 return(1);
2172 }
2173
2174 static int
2175 pre_literal(PRE_ARGS)
2176 {
2177
2178 if (MDOC_BODY != n->type)
2179 return(1);
2180
2181 /*
2182 * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2183 * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2184 */
2185
2186 switch (n->tok) {
2187 case MDOC_Dl:
2188 mdoc->flags |= MDOC_LITERAL;
2189 break;
2190 case MDOC_Bd:
2191 if (DISP_literal == n->norm->Bd.type)
2192 mdoc->flags |= MDOC_LITERAL;
2193 if (DISP_unfilled == n->norm->Bd.type)
2194 mdoc->flags |= MDOC_LITERAL;
2195 break;
2196 default:
2197 abort();
2198 /* NOTREACHED */
2199 }
2200
2201 return(1);
2202 }
2203
2204 static int
2205 post_dd(POST_ARGS)
2206 {
2207 struct mdoc_node *n;
2208 char *datestr;
2209
2210 if (mdoc->meta.date)
2211 free(mdoc->meta.date);
2212
2213 n = mdoc->last;
2214 if (NULL == n->child || '\0' == n->child->string[0]) {
2215 mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
2216 mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
2217 return(1);
2218 }
2219
2220 datestr = NULL;
2221 mdoc_deroff(&datestr, n);
2222 if (mdoc->quick)
2223 mdoc->meta.date = datestr;
2224 else {
2225 mdoc->meta.date = mandoc_normdate(mdoc->parse,
2226 datestr, n->line, n->pos);
2227 free(datestr);
2228 }
2229 return(1);
2230 }
2231
2232 static int
2233 post_dt(POST_ARGS)
2234 {
2235 struct mdoc_node *nn, *n;
2236 const char *cp;
2237 char *p;
2238
2239 n = mdoc->last;
2240
2241 if (mdoc->meta.title)
2242 free(mdoc->meta.title);
2243 if (mdoc->meta.vol)
2244 free(mdoc->meta.vol);
2245 if (mdoc->meta.arch)
2246 free(mdoc->meta.arch);
2247
2248 mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
2249
2250 /* First check that all characters are uppercase. */
2251
2252 if (NULL != (nn = n->child))
2253 for (p = nn->string; *p; p++) {
2254 if (toupper((unsigned char)*p) == *p)
2255 continue;
2256 mandoc_msg(MANDOCERR_TITLE_CASE,
2257 mdoc->parse, nn->line,
2258 nn->pos + (p - nn->string),
2259 nn->string);
2260 break;
2261 }
2262
2263 /* Handles: `.Dt'
2264 * title = unknown, volume = local, msec = 0, arch = NULL
2265 */
2266
2267 if (NULL == (nn = n->child)) {
2268 /* XXX: make these macro values. */
2269 /* FIXME: warn about missing values. */
2270 mdoc->meta.title = mandoc_strdup("UNKNOWN");
2271 mdoc->meta.vol = mandoc_strdup("LOCAL");
2272 mdoc->meta.msec = mandoc_strdup("1");
2273 return(1);
2274 }
2275
2276 /* Handles: `.Dt TITLE'
2277 * title = TITLE, volume = local, msec = 0, arch = NULL
2278 */
2279
2280 mdoc->meta.title = mandoc_strdup(
2281 '\0' == nn->string[0] ? "UNKNOWN" : nn->string);
2282
2283 if (NULL == (nn = nn->next)) {
2284 /* FIXME: warn about missing msec. */
2285 /* XXX: make this a macro value. */
2286 mdoc->meta.vol = mandoc_strdup("LOCAL");
2287 mdoc->meta.msec = mandoc_strdup("1");
2288 return(1);
2289 }
2290
2291 /* Handles: `.Dt TITLE SEC'
2292 * title = TITLE,
2293 * volume = SEC is msec ? format(msec) : SEC,
2294 * msec = SEC is msec ? atoi(msec) : 0,
2295 * arch = NULL
2296 */
2297
2298 cp = mandoc_a2msec(nn->string);
2299 if (cp) {
2300 mdoc->meta.vol = mandoc_strdup(cp);
2301 mdoc->meta.msec = mandoc_strdup(nn->string);
2302 } else {
2303 mandoc_msg(MANDOCERR_MSEC_BAD, mdoc->parse,
2304 nn->line, nn->pos, nn->string);
2305 mdoc->meta.vol = mandoc_strdup(nn->string);
2306 mdoc->meta.msec = mandoc_strdup(nn->string);
2307 }
2308
2309 if (NULL == (nn = nn->next))
2310 return(1);
2311
2312 /* Handles: `.Dt TITLE SEC VOL'
2313 * title = TITLE,
2314 * volume = VOL is vol ? format(VOL) :
2315 * VOL is arch ? format(arch) :
2316 * VOL
2317 */
2318
2319 cp = mdoc_a2vol(nn->string);
2320 if (cp) {
2321 free(mdoc->meta.vol);
2322 mdoc->meta.vol = mandoc_strdup(cp);
2323 } else {
2324 cp = mdoc_a2arch(nn->string);
2325 if (NULL == cp) {
2326 mandoc_msg(MANDOCERR_ARCH_BAD, mdoc->parse,
2327 nn->line, nn->pos, nn->string);
2328 free(mdoc->meta.vol);
2329 mdoc->meta.vol = mandoc_strdup(nn->string);
2330 } else
2331 mdoc->meta.arch = mandoc_strdup(cp);
2332 }
2333
2334 /* Ignore any subsequent parameters... */
2335 /* FIXME: warn about subsequent parameters. */
2336
2337 return(1);
2338 }
2339
2340 static int
2341 post_prol(POST_ARGS)
2342 {
2343 /*
2344 * Remove prologue macros from the document after they're
2345 * processed. The final document uses mdoc_meta for these
2346 * values and discards the originals.
2347 */
2348
2349 mdoc_node_delete(mdoc, mdoc->last);
2350 if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
2351 mdoc->flags |= MDOC_PBODY;
2352
2353 return(1);
2354 }
2355
2356 static int
2357 post_bx(POST_ARGS)
2358 {
2359 struct mdoc_node *n;
2360
2361 /*
2362 * Make `Bx's second argument always start with an uppercase
2363 * letter. Groff checks if it's an "accepted" term, but we just
2364 * uppercase blindly.
2365 */
2366
2367 n = mdoc->last->child;
2368 if (n && NULL != (n = n->next))
2369 *n->string = (char)toupper((unsigned char)*n->string);
2370
2371 return(1);
2372 }
2373
2374 static int
2375 post_os(POST_ARGS)
2376 {
2377 #ifndef OSNAME
2378 struct utsname utsname;
2379 static char *defbuf;
2380 #endif
2381 struct mdoc_node *n;
2382
2383 n = mdoc->last;
2384
2385 /*
2386 * Set the operating system by way of the `Os' macro.
2387 * The order of precedence is:
2388 * 1. the argument of the `Os' macro, unless empty
2389 * 2. the -Ios=foo command line argument, if provided
2390 * 3. -DOSNAME="\"foo\"", if provided during compilation
2391 * 4. "sysname release" from uname(3)
2392 */
2393
2394 free(mdoc->meta.os);
2395 mdoc->meta.os = NULL;
2396 mdoc_deroff(&mdoc->meta.os, n);
2397 if (mdoc->meta.os)
2398 return(1);
2399
2400 if (mdoc->defos) {
2401 mdoc->meta.os = mandoc_strdup(mdoc->defos);
2402 return(1);
2403 }
2404
2405 #ifdef OSNAME
2406 mdoc->meta.os = mandoc_strdup(OSNAME);
2407 #else /*!OSNAME */
2408 if (NULL == defbuf) {
2409 if (-1 == uname(&utsname)) {
2410 mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2411 defbuf = mandoc_strdup("UNKNOWN");
2412 } else
2413 mandoc_asprintf(&defbuf, "%s %s",
2414 utsname.sysname, utsname.release);
2415 }
2416 mdoc->meta.os = mandoc_strdup(defbuf);
2417 #endif /*!OSNAME*/
2418 return(1);
2419 }
2420
2421 static int
2422 post_std(POST_ARGS)
2423 {
2424 struct mdoc_node *nn, *n;
2425
2426 n = mdoc->last;
2427
2428 /*
2429 * Macros accepting `-std' as an argument have the name of the
2430 * current document (`Nm') filled in as the argument if it's not
2431 * provided.
2432 */
2433
2434 if (n->child)
2435 return(1);
2436
2437 if (NULL == mdoc->meta.name)
2438 return(1);
2439
2440 nn = n;
2441 mdoc->next = MDOC_NEXT_CHILD;
2442
2443 if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2444 return(0);
2445
2446 mdoc->last = nn;
2447 return(1);
2448 }
2449
2450 static enum mdoc_sec
2451 a2sec(const char *p)
2452 {
2453 int i;
2454
2455 for (i = 0; i < (int)SEC__MAX; i++)
2456 if (secnames[i] && 0 == strcmp(p, secnames[i]))
2457 return((enum mdoc_sec)i);
2458
2459 return(SEC_CUSTOM);
2460 }
2461
2462 static size_t
2463 macro2len(enum mdoct macro)
2464 {
2465
2466 switch (macro) {
2467 case MDOC_Ad:
2468 return(12);
2469 case MDOC_Ao:
2470 return(12);
2471 case MDOC_An:
2472 return(12);
2473 case MDOC_Aq:
2474 return(12);
2475 case MDOC_Ar:
2476 return(12);
2477 case MDOC_Bo:
2478 return(12);
2479 case MDOC_Bq:
2480 return(12);
2481 case MDOC_Cd:
2482 return(12);
2483 case MDOC_Cm:
2484 return(10);
2485 case MDOC_Do:
2486 return(10);
2487 case MDOC_Dq:
2488 return(12);
2489 case MDOC_Dv:
2490 return(12);
2491 case MDOC_Eo:
2492 return(12);
2493 case MDOC_Em:
2494 return(10);
2495 case MDOC_Er:
2496 return(17);
2497 case MDOC_Ev:
2498 return(15);
2499 case MDOC_Fa:
2500 return(12);
2501 case MDOC_Fl:
2502 return(10);
2503 case MDOC_Fo:
2504 return(16);
2505 case MDOC_Fn:
2506 return(16);
2507 case MDOC_Ic:
2508 return(10);
2509 case MDOC_Li:
2510 return(16);
2511 case MDOC_Ms:
2512 return(6);
2513 case MDOC_Nm:
2514 return(10);
2515 case MDOC_No:
2516 return(12);
2517 case MDOC_Oo:
2518 return(10);
2519 case MDOC_Op:
2520 return(14);
2521 case MDOC_Pa:
2522 return(32);
2523 case MDOC_Pf:
2524 return(12);
2525 case MDOC_Po:
2526 return(12);
2527 case MDOC_Pq:
2528 return(12);
2529 case MDOC_Ql:
2530 return(16);
2531 case MDOC_Qo:
2532 return(12);
2533 case MDOC_So:
2534 return(12);
2535 case MDOC_Sq:
2536 return(12);
2537 case MDOC_Sy:
2538 return(6);
2539 case MDOC_Sx:
2540 return(16);
2541 case MDOC_Tn:
2542 return(10);
2543 case MDOC_Va:
2544 return(12);
2545 case MDOC_Vt:
2546 return(12);
2547 case MDOC_Xr:
2548 return(10);
2549 default:
2550 break;
2551 };
2552 return(0);
2553 }