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