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