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