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