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