1*260e9a87SYuri Pankov /* $Id: mdoc_validate.c,v 1.283 2015/02/23 13:55:55 schwarze Exp $ */
295c635efSGarrett D'Amore /*
3698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4*260e9a87SYuri Pankov * Copyright (c) 2010-2015 Ingo Schwarze <schwarze@openbsd.org>
5*260e9a87SYuri Pankov * Copyright (c) 2010 Joerg Sonnenberger <joerg@netbsd.org>
695c635efSGarrett D'Amore *
795c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
895c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
995c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies.
1095c635efSGarrett D'Amore *
1195c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1295c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1395c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1495c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1595c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1695c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1795c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1895c635efSGarrett D'Amore */
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore
21*260e9a87SYuri Pankov #include <sys/types.h>
2295c635efSGarrett D'Amore #ifndef OSNAME
2395c635efSGarrett D'Amore #include <sys/utsname.h>
2495c635efSGarrett D'Amore #endif
2595c635efSGarrett D'Amore
2695c635efSGarrett D'Amore #include <assert.h>
2795c635efSGarrett D'Amore #include <ctype.h>
2895c635efSGarrett D'Amore #include <limits.h>
2995c635efSGarrett D'Amore #include <stdio.h>
3095c635efSGarrett D'Amore #include <stdlib.h>
3195c635efSGarrett D'Amore #include <string.h>
3295c635efSGarrett D'Amore #include <time.h>
3395c635efSGarrett D'Amore
3495c635efSGarrett D'Amore #include "mdoc.h"
3595c635efSGarrett D'Amore #include "mandoc.h"
36*260e9a87SYuri Pankov #include "mandoc_aux.h"
3795c635efSGarrett D'Amore #include "libmdoc.h"
3895c635efSGarrett D'Amore #include "libmandoc.h"
3995c635efSGarrett D'Amore
4095c635efSGarrett D'Amore /* FIXME: .Bl -diag can't have non-text children in HEAD. */
4195c635efSGarrett D'Amore
4295c635efSGarrett D'Amore #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
4395c635efSGarrett D'Amore #define POST_ARGS struct mdoc *mdoc
4495c635efSGarrett D'Amore
4595c635efSGarrett D'Amore enum check_ineq {
4695c635efSGarrett D'Amore CHECK_LT,
4795c635efSGarrett D'Amore CHECK_GT,
4895c635efSGarrett D'Amore CHECK_EQ
4995c635efSGarrett D'Amore };
5095c635efSGarrett D'Amore
51*260e9a87SYuri Pankov typedef void (*v_pre)(PRE_ARGS);
52*260e9a87SYuri Pankov typedef void (*v_post)(POST_ARGS);
5395c635efSGarrett D'Amore
5495c635efSGarrett D'Amore struct valids {
55*260e9a87SYuri Pankov v_pre pre;
56*260e9a87SYuri Pankov v_post post;
5795c635efSGarrett D'Amore };
5895c635efSGarrett D'Amore
5995c635efSGarrett D'Amore static void check_text(struct mdoc *, int, int, char *);
6095c635efSGarrett D'Amore static void check_argv(struct mdoc *,
6195c635efSGarrett D'Amore struct mdoc_node *, struct mdoc_argv *);
6295c635efSGarrett D'Amore static void check_args(struct mdoc *, struct mdoc_node *);
63*260e9a87SYuri Pankov static int child_an(const struct mdoc_node *);
6495c635efSGarrett D'Amore static enum mdoc_sec a2sec(const char *);
6595c635efSGarrett D'Amore static size_t macro2len(enum mdoct);
66*260e9a87SYuri Pankov static void rewrite_macro2len(char **);
6795c635efSGarrett D'Amore
68*260e9a87SYuri Pankov static void post_an(POST_ARGS);
69*260e9a87SYuri Pankov static void post_at(POST_ARGS);
70*260e9a87SYuri Pankov static void post_bf(POST_ARGS);
71*260e9a87SYuri Pankov static void post_bk(POST_ARGS);
72*260e9a87SYuri Pankov static void post_bl(POST_ARGS);
73*260e9a87SYuri Pankov static void post_bl_block(POST_ARGS);
74*260e9a87SYuri Pankov static void post_bl_block_tag(POST_ARGS);
75*260e9a87SYuri Pankov static void post_bl_head(POST_ARGS);
76*260e9a87SYuri Pankov static void post_bx(POST_ARGS);
77*260e9a87SYuri Pankov static void post_d1(POST_ARGS);
78*260e9a87SYuri Pankov static void post_defaults(POST_ARGS);
79*260e9a87SYuri Pankov static void post_dd(POST_ARGS);
80*260e9a87SYuri Pankov static void post_dt(POST_ARGS);
81*260e9a87SYuri Pankov static void post_en(POST_ARGS);
82*260e9a87SYuri Pankov static void post_es(POST_ARGS);
83*260e9a87SYuri Pankov static void post_eoln(POST_ARGS);
84*260e9a87SYuri Pankov static void post_ex(POST_ARGS);
85*260e9a87SYuri Pankov static void post_fa(POST_ARGS);
86*260e9a87SYuri Pankov static void post_fn(POST_ARGS);
87*260e9a87SYuri Pankov static void post_fname(POST_ARGS);
88*260e9a87SYuri Pankov static void post_fo(POST_ARGS);
89*260e9a87SYuri Pankov static void post_hyph(POST_ARGS);
90*260e9a87SYuri Pankov static void post_ignpar(POST_ARGS);
91*260e9a87SYuri Pankov static void post_it(POST_ARGS);
92*260e9a87SYuri Pankov static void post_lb(POST_ARGS);
93*260e9a87SYuri Pankov static void post_literal(POST_ARGS);
94*260e9a87SYuri Pankov static void post_nd(POST_ARGS);
95*260e9a87SYuri Pankov static void post_nm(POST_ARGS);
96*260e9a87SYuri Pankov static void post_ns(POST_ARGS);
97*260e9a87SYuri Pankov static void post_os(POST_ARGS);
98*260e9a87SYuri Pankov static void post_par(POST_ARGS);
99*260e9a87SYuri Pankov static void post_root(POST_ARGS);
100*260e9a87SYuri Pankov static void post_rs(POST_ARGS);
101*260e9a87SYuri Pankov static void post_sh(POST_ARGS);
102*260e9a87SYuri Pankov static void post_sh_head(POST_ARGS);
103*260e9a87SYuri Pankov static void post_sh_name(POST_ARGS);
104*260e9a87SYuri Pankov static void post_sh_see_also(POST_ARGS);
105*260e9a87SYuri Pankov static void post_sh_authors(POST_ARGS);
106*260e9a87SYuri Pankov static void post_sm(POST_ARGS);
107*260e9a87SYuri Pankov static void post_st(POST_ARGS);
108*260e9a87SYuri Pankov static void post_vt(POST_ARGS);
10995c635efSGarrett D'Amore
110*260e9a87SYuri Pankov static void pre_an(PRE_ARGS);
111*260e9a87SYuri Pankov static void pre_bd(PRE_ARGS);
112*260e9a87SYuri Pankov static void pre_bl(PRE_ARGS);
113*260e9a87SYuri Pankov static void pre_dd(PRE_ARGS);
114*260e9a87SYuri Pankov static void pre_display(PRE_ARGS);
115*260e9a87SYuri Pankov static void pre_dt(PRE_ARGS);
116*260e9a87SYuri Pankov static void pre_literal(PRE_ARGS);
117*260e9a87SYuri Pankov static void pre_obsolete(PRE_ARGS);
118*260e9a87SYuri Pankov static void pre_os(PRE_ARGS);
119*260e9a87SYuri Pankov static void pre_par(PRE_ARGS);
120*260e9a87SYuri Pankov static void pre_std(PRE_ARGS);
12195c635efSGarrett D'Amore
12295c635efSGarrett D'Amore static const struct valids mdoc_valids[MDOC_MAX] = {
12395c635efSGarrett D'Amore { NULL, NULL }, /* Ap */
124*260e9a87SYuri Pankov { pre_dd, post_dd }, /* Dd */
125*260e9a87SYuri Pankov { pre_dt, post_dt }, /* Dt */
126*260e9a87SYuri Pankov { pre_os, post_os }, /* Os */
127*260e9a87SYuri Pankov { NULL, post_sh }, /* Sh */
128*260e9a87SYuri Pankov { NULL, post_ignpar }, /* Ss */
129*260e9a87SYuri Pankov { pre_par, post_par }, /* Pp */
130*260e9a87SYuri Pankov { pre_display, post_d1 }, /* D1 */
131*260e9a87SYuri Pankov { pre_literal, post_literal }, /* Dl */
132*260e9a87SYuri Pankov { pre_bd, post_literal }, /* Bd */
13395c635efSGarrett D'Amore { NULL, NULL }, /* Ed */
134*260e9a87SYuri Pankov { pre_bl, post_bl }, /* Bl */
13595c635efSGarrett D'Amore { NULL, NULL }, /* El */
136*260e9a87SYuri Pankov { pre_par, post_it }, /* It */
13795c635efSGarrett D'Amore { NULL, NULL }, /* Ad */
138*260e9a87SYuri Pankov { pre_an, post_an }, /* An */
139*260e9a87SYuri Pankov { NULL, post_defaults }, /* Ar */
14095c635efSGarrett D'Amore { NULL, NULL }, /* Cd */
14195c635efSGarrett D'Amore { NULL, NULL }, /* Cm */
14295c635efSGarrett D'Amore { NULL, NULL }, /* Dv */
143698f87a4SGarrett D'Amore { NULL, NULL }, /* Er */
14495c635efSGarrett D'Amore { NULL, NULL }, /* Ev */
145*260e9a87SYuri Pankov { pre_std, post_ex }, /* Ex */
146*260e9a87SYuri Pankov { NULL, post_fa }, /* Fa */
147*260e9a87SYuri Pankov { NULL, NULL }, /* Fd */
14895c635efSGarrett D'Amore { NULL, NULL }, /* Fl */
149*260e9a87SYuri Pankov { NULL, post_fn }, /* Fn */
15095c635efSGarrett D'Amore { NULL, NULL }, /* Ft */
15195c635efSGarrett D'Amore { NULL, NULL }, /* Ic */
152*260e9a87SYuri Pankov { NULL, NULL }, /* In */
153*260e9a87SYuri Pankov { NULL, post_defaults }, /* Li */
154*260e9a87SYuri Pankov { NULL, post_nd }, /* Nd */
155*260e9a87SYuri Pankov { NULL, post_nm }, /* Nm */
15695c635efSGarrett D'Amore { NULL, NULL }, /* Op */
157*260e9a87SYuri Pankov { pre_obsolete, NULL }, /* Ot */
158*260e9a87SYuri Pankov { NULL, post_defaults }, /* Pa */
159*260e9a87SYuri Pankov { pre_std, NULL }, /* Rv */
160*260e9a87SYuri Pankov { NULL, post_st }, /* St */
16195c635efSGarrett D'Amore { NULL, NULL }, /* Va */
162*260e9a87SYuri Pankov { NULL, post_vt }, /* Vt */
163*260e9a87SYuri Pankov { NULL, NULL }, /* Xr */
164*260e9a87SYuri Pankov { NULL, NULL }, /* %A */
165*260e9a87SYuri Pankov { NULL, post_hyph }, /* %B */ /* FIXME: can be used outside Rs/Re. */
166*260e9a87SYuri Pankov { NULL, NULL }, /* %D */
167*260e9a87SYuri Pankov { NULL, NULL }, /* %I */
168*260e9a87SYuri Pankov { NULL, NULL }, /* %J */
169*260e9a87SYuri Pankov { NULL, post_hyph }, /* %N */
170*260e9a87SYuri Pankov { NULL, post_hyph }, /* %O */
171*260e9a87SYuri Pankov { NULL, NULL }, /* %P */
172*260e9a87SYuri Pankov { NULL, post_hyph }, /* %R */
173*260e9a87SYuri Pankov { NULL, post_hyph }, /* %T */ /* FIXME: can be used outside Rs/Re. */
174*260e9a87SYuri Pankov { NULL, NULL }, /* %V */
17595c635efSGarrett D'Amore { NULL, NULL }, /* Ac */
17695c635efSGarrett D'Amore { NULL, NULL }, /* Ao */
17795c635efSGarrett D'Amore { NULL, NULL }, /* Aq */
178*260e9a87SYuri Pankov { NULL, post_at }, /* At */
17995c635efSGarrett D'Amore { NULL, NULL }, /* Bc */
180*260e9a87SYuri Pankov { NULL, post_bf }, /* Bf */
18195c635efSGarrett D'Amore { NULL, NULL }, /* Bo */
18295c635efSGarrett D'Amore { NULL, NULL }, /* Bq */
18395c635efSGarrett D'Amore { NULL, NULL }, /* Bsx */
184*260e9a87SYuri Pankov { NULL, post_bx }, /* Bx */
185*260e9a87SYuri Pankov { pre_obsolete, NULL }, /* Db */
18695c635efSGarrett D'Amore { NULL, NULL }, /* Dc */
18795c635efSGarrett D'Amore { NULL, NULL }, /* Do */
18895c635efSGarrett D'Amore { NULL, NULL }, /* Dq */
18995c635efSGarrett D'Amore { NULL, NULL }, /* Ec */
19095c635efSGarrett D'Amore { NULL, NULL }, /* Ef */
19195c635efSGarrett D'Amore { NULL, NULL }, /* Em */
19295c635efSGarrett D'Amore { NULL, NULL }, /* Eo */
19395c635efSGarrett D'Amore { NULL, NULL }, /* Fx */
19495c635efSGarrett D'Amore { NULL, NULL }, /* Ms */
195*260e9a87SYuri Pankov { NULL, NULL }, /* No */
196*260e9a87SYuri Pankov { NULL, post_ns }, /* Ns */
19795c635efSGarrett D'Amore { NULL, NULL }, /* Nx */
19895c635efSGarrett D'Amore { NULL, NULL }, /* Ox */
19995c635efSGarrett D'Amore { NULL, NULL }, /* Pc */
200*260e9a87SYuri Pankov { NULL, NULL }, /* Pf */
20195c635efSGarrett D'Amore { NULL, NULL }, /* Po */
20295c635efSGarrett D'Amore { NULL, NULL }, /* Pq */
20395c635efSGarrett D'Amore { NULL, NULL }, /* Qc */
20495c635efSGarrett D'Amore { NULL, NULL }, /* Ql */
20595c635efSGarrett D'Amore { NULL, NULL }, /* Qo */
20695c635efSGarrett D'Amore { NULL, NULL }, /* Qq */
20795c635efSGarrett D'Amore { NULL, NULL }, /* Re */
208*260e9a87SYuri Pankov { NULL, post_rs }, /* Rs */
20995c635efSGarrett D'Amore { NULL, NULL }, /* Sc */
21095c635efSGarrett D'Amore { NULL, NULL }, /* So */
21195c635efSGarrett D'Amore { NULL, NULL }, /* Sq */
212*260e9a87SYuri Pankov { NULL, post_sm }, /* Sm */
213*260e9a87SYuri Pankov { NULL, post_hyph }, /* Sx */
21495c635efSGarrett D'Amore { NULL, NULL }, /* Sy */
21595c635efSGarrett D'Amore { NULL, NULL }, /* Tn */
21695c635efSGarrett D'Amore { NULL, NULL }, /* Ux */
21795c635efSGarrett D'Amore { NULL, NULL }, /* Xc */
21895c635efSGarrett D'Amore { NULL, NULL }, /* Xo */
219*260e9a87SYuri Pankov { NULL, post_fo }, /* Fo */
22095c635efSGarrett D'Amore { NULL, NULL }, /* Fc */
22195c635efSGarrett D'Amore { NULL, NULL }, /* Oo */
22295c635efSGarrett D'Amore { NULL, NULL }, /* Oc */
223*260e9a87SYuri Pankov { NULL, post_bk }, /* Bk */
22495c635efSGarrett D'Amore { NULL, NULL }, /* Ek */
225*260e9a87SYuri Pankov { NULL, post_eoln }, /* Bt */
22695c635efSGarrett D'Amore { NULL, NULL }, /* Hf */
227*260e9a87SYuri Pankov { pre_obsolete, NULL }, /* Fr */
228*260e9a87SYuri Pankov { NULL, post_eoln }, /* Ud */
229*260e9a87SYuri Pankov { NULL, post_lb }, /* Lb */
230*260e9a87SYuri Pankov { pre_par, post_par }, /* Lp */
23195c635efSGarrett D'Amore { NULL, NULL }, /* Lk */
232*260e9a87SYuri Pankov { NULL, post_defaults }, /* Mt */
23395c635efSGarrett D'Amore { NULL, NULL }, /* Brq */
23495c635efSGarrett D'Amore { NULL, NULL }, /* Bro */
23595c635efSGarrett D'Amore { NULL, NULL }, /* Brc */
236*260e9a87SYuri Pankov { NULL, NULL }, /* %C */
237*260e9a87SYuri Pankov { pre_obsolete, post_es }, /* Es */
238*260e9a87SYuri Pankov { pre_obsolete, post_en }, /* En */
23995c635efSGarrett D'Amore { NULL, NULL }, /* Dx */
240*260e9a87SYuri Pankov { NULL, NULL }, /* %Q */
241*260e9a87SYuri Pankov { NULL, post_par }, /* br */
242*260e9a87SYuri Pankov { NULL, post_par }, /* sp */
243*260e9a87SYuri Pankov { NULL, NULL }, /* %U */
24495c635efSGarrett D'Amore { NULL, NULL }, /* Ta */
245*260e9a87SYuri Pankov { NULL, NULL }, /* ll */
24695c635efSGarrett D'Amore };
24795c635efSGarrett D'Amore
24895c635efSGarrett D'Amore #define RSORD_MAX 14 /* Number of `Rs' blocks. */
24995c635efSGarrett D'Amore
25095c635efSGarrett D'Amore static const enum mdoct rsord[RSORD_MAX] = {
25195c635efSGarrett D'Amore MDOC__A,
25295c635efSGarrett D'Amore MDOC__T,
25395c635efSGarrett D'Amore MDOC__B,
25495c635efSGarrett D'Amore MDOC__I,
25595c635efSGarrett D'Amore MDOC__J,
25695c635efSGarrett D'Amore MDOC__R,
25795c635efSGarrett D'Amore MDOC__N,
25895c635efSGarrett D'Amore MDOC__V,
259698f87a4SGarrett D'Amore MDOC__U,
26095c635efSGarrett D'Amore MDOC__P,
26195c635efSGarrett D'Amore MDOC__Q,
26295c635efSGarrett D'Amore MDOC__C,
263698f87a4SGarrett D'Amore MDOC__D,
264698f87a4SGarrett D'Amore MDOC__O
26595c635efSGarrett D'Amore };
26695c635efSGarrett D'Amore
26795c635efSGarrett D'Amore static const char * const secnames[SEC__MAX] = {
26895c635efSGarrett D'Amore NULL,
26995c635efSGarrett D'Amore "NAME",
27095c635efSGarrett D'Amore "LIBRARY",
27195c635efSGarrett D'Amore "SYNOPSIS",
27295c635efSGarrett D'Amore "DESCRIPTION",
273*260e9a87SYuri Pankov "CONTEXT",
27495c635efSGarrett D'Amore "IMPLEMENTATION NOTES",
27595c635efSGarrett D'Amore "RETURN VALUES",
27695c635efSGarrett D'Amore "ENVIRONMENT",
27795c635efSGarrett D'Amore "FILES",
27895c635efSGarrett D'Amore "EXIT STATUS",
27995c635efSGarrett D'Amore "EXAMPLES",
28095c635efSGarrett D'Amore "DIAGNOSTICS",
28195c635efSGarrett D'Amore "COMPATIBILITY",
28295c635efSGarrett D'Amore "ERRORS",
28395c635efSGarrett D'Amore "SEE ALSO",
28495c635efSGarrett D'Amore "STANDARDS",
28595c635efSGarrett D'Amore "HISTORY",
28695c635efSGarrett D'Amore "AUTHORS",
28795c635efSGarrett D'Amore "CAVEATS",
28895c635efSGarrett D'Amore "BUGS",
28995c635efSGarrett D'Amore "SECURITY CONSIDERATIONS",
29095c635efSGarrett D'Amore NULL
29195c635efSGarrett D'Amore };
29295c635efSGarrett D'Amore
293*260e9a87SYuri Pankov
294*260e9a87SYuri Pankov void
mdoc_valid_pre(struct mdoc * mdoc,struct mdoc_node * n)29595c635efSGarrett D'Amore mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
29695c635efSGarrett D'Amore {
297*260e9a87SYuri Pankov v_pre p;
29895c635efSGarrett D'Amore
29995c635efSGarrett D'Amore switch (n->type) {
300*260e9a87SYuri Pankov case MDOC_TEXT:
301*260e9a87SYuri Pankov if (n->sec != SEC_SYNOPSIS || n->parent->tok != MDOC_Fd)
302*260e9a87SYuri Pankov check_text(mdoc, n->line, n->pos, n->string);
30395c635efSGarrett D'Amore /* FALLTHROUGH */
304*260e9a87SYuri Pankov case MDOC_TBL:
30595c635efSGarrett D'Amore /* FALLTHROUGH */
306*260e9a87SYuri Pankov case MDOC_EQN:
30795c635efSGarrett D'Amore /* FALLTHROUGH */
308*260e9a87SYuri Pankov case MDOC_ROOT:
309*260e9a87SYuri Pankov return;
31095c635efSGarrett D'Amore default:
31195c635efSGarrett D'Amore break;
31295c635efSGarrett D'Amore }
31395c635efSGarrett D'Amore
31495c635efSGarrett D'Amore check_args(mdoc, n);
315*260e9a87SYuri Pankov p = mdoc_valids[n->tok].pre;
316*260e9a87SYuri Pankov if (*p)
317*260e9a87SYuri Pankov (*p)(mdoc, n);
31895c635efSGarrett D'Amore }
31995c635efSGarrett D'Amore
320*260e9a87SYuri Pankov void
mdoc_valid_post(struct mdoc * mdoc)32195c635efSGarrett D'Amore mdoc_valid_post(struct mdoc *mdoc)
32295c635efSGarrett D'Amore {
323*260e9a87SYuri Pankov struct mdoc_node *n;
324*260e9a87SYuri Pankov v_post p;
32595c635efSGarrett D'Amore
326*260e9a87SYuri Pankov n = mdoc->last;
327*260e9a87SYuri Pankov if (n->flags & MDOC_VALID)
328*260e9a87SYuri Pankov return;
329*260e9a87SYuri Pankov n->flags |= MDOC_VALID | MDOC_ENDED;
33095c635efSGarrett D'Amore
331*260e9a87SYuri Pankov switch (n->type) {
332*260e9a87SYuri Pankov case MDOC_TEXT:
33395c635efSGarrett D'Amore /* FALLTHROUGH */
334*260e9a87SYuri Pankov case MDOC_EQN:
33595c635efSGarrett D'Amore /* FALLTHROUGH */
336*260e9a87SYuri Pankov case MDOC_TBL:
33795c635efSGarrett D'Amore break;
338*260e9a87SYuri Pankov case MDOC_ROOT:
339*260e9a87SYuri Pankov post_root(mdoc);
34095c635efSGarrett D'Amore break;
34195c635efSGarrett D'Amore default:
342*260e9a87SYuri Pankov
343*260e9a87SYuri Pankov /*
344*260e9a87SYuri Pankov * Closing delimiters are not special at the
345*260e9a87SYuri Pankov * beginning of a block, opening delimiters
346*260e9a87SYuri Pankov * are not special at the end.
347*260e9a87SYuri Pankov */
348*260e9a87SYuri Pankov
349*260e9a87SYuri Pankov if (n->child != NULL)
350*260e9a87SYuri Pankov n->child->flags &= ~MDOC_DELIMC;
351*260e9a87SYuri Pankov if (n->last != NULL)
352*260e9a87SYuri Pankov n->last->flags &= ~MDOC_DELIMO;
353*260e9a87SYuri Pankov
354*260e9a87SYuri Pankov /* Call the macro's postprocessor. */
355*260e9a87SYuri Pankov
356*260e9a87SYuri Pankov p = mdoc_valids[n->tok].post;
357*260e9a87SYuri Pankov if (*p)
358*260e9a87SYuri Pankov (*p)(mdoc);
359*260e9a87SYuri Pankov break;
36095c635efSGarrett D'Amore }
36195c635efSGarrett D'Amore }
36295c635efSGarrett D'Amore
36395c635efSGarrett D'Amore static void
check_args(struct mdoc * mdoc,struct mdoc_node * n)364698f87a4SGarrett D'Amore check_args(struct mdoc *mdoc, struct mdoc_node *n)
36595c635efSGarrett D'Amore {
36695c635efSGarrett D'Amore int i;
36795c635efSGarrett D'Amore
36895c635efSGarrett D'Amore if (NULL == n->args)
36995c635efSGarrett D'Amore return;
37095c635efSGarrett D'Amore
37195c635efSGarrett D'Amore assert(n->args->argc);
37295c635efSGarrett D'Amore for (i = 0; i < (int)n->args->argc; i++)
373698f87a4SGarrett D'Amore check_argv(mdoc, n, &n->args->argv[i]);
37495c635efSGarrett D'Amore }
37595c635efSGarrett D'Amore
37695c635efSGarrett D'Amore static void
check_argv(struct mdoc * mdoc,struct mdoc_node * n,struct mdoc_argv * v)377698f87a4SGarrett D'Amore check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
37895c635efSGarrett D'Amore {
37995c635efSGarrett D'Amore int i;
38095c635efSGarrett D'Amore
38195c635efSGarrett D'Amore for (i = 0; i < (int)v->sz; i++)
382698f87a4SGarrett D'Amore check_text(mdoc, v->line, v->pos, v->value[i]);
38395c635efSGarrett D'Amore }
38495c635efSGarrett D'Amore
38595c635efSGarrett D'Amore static void
check_text(struct mdoc * mdoc,int ln,int pos,char * p)386698f87a4SGarrett D'Amore check_text(struct mdoc *mdoc, int ln, int pos, char *p)
38795c635efSGarrett D'Amore {
38895c635efSGarrett D'Amore char *cp;
38995c635efSGarrett D'Amore
390698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags)
39195c635efSGarrett D'Amore return;
39295c635efSGarrett D'Amore
39395c635efSGarrett D'Amore for (cp = p; NULL != (p = strchr(p, '\t')); p++)
394*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FI_TAB, mdoc->parse,
395*260e9a87SYuri Pankov ln, pos + (int)(p - cp), NULL);
39695c635efSGarrett D'Amore }
39795c635efSGarrett D'Amore
398*260e9a87SYuri Pankov static void
pre_display(PRE_ARGS)39995c635efSGarrett D'Amore pre_display(PRE_ARGS)
40095c635efSGarrett D'Amore {
40195c635efSGarrett D'Amore struct mdoc_node *node;
40295c635efSGarrett D'Amore
40395c635efSGarrett D'Amore if (MDOC_BLOCK != n->type)
404*260e9a87SYuri Pankov return;
40595c635efSGarrett D'Amore
40695c635efSGarrett D'Amore for (node = mdoc->last->parent; node; node = node->parent)
40795c635efSGarrett D'Amore if (MDOC_BLOCK == node->type)
40895c635efSGarrett D'Amore if (MDOC_Bd == node->tok)
40995c635efSGarrett D'Amore break;
41095c635efSGarrett D'Amore
41195c635efSGarrett D'Amore if (node)
412*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BD_NEST,
413*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos,
414*260e9a87SYuri Pankov "%s in Bd", mdoc_macronames[n->tok]);
41595c635efSGarrett D'Amore }
41695c635efSGarrett D'Amore
417*260e9a87SYuri Pankov static void
pre_bl(PRE_ARGS)41895c635efSGarrett D'Amore pre_bl(PRE_ARGS)
41995c635efSGarrett D'Amore {
420*260e9a87SYuri Pankov struct mdoc_argv *argv, *wa;
421*260e9a87SYuri Pankov int i;
422*260e9a87SYuri Pankov enum mdocargt mdoclt;
42395c635efSGarrett D'Amore enum mdoc_list lt;
42495c635efSGarrett D'Amore
425*260e9a87SYuri Pankov if (n->type != MDOC_BLOCK)
426*260e9a87SYuri Pankov return;
42795c635efSGarrett D'Amore
42895c635efSGarrett D'Amore /*
42995c635efSGarrett D'Amore * First figure out which kind of list to use: bind ourselves to
43095c635efSGarrett D'Amore * the first mentioned list type and warn about any remaining
43195c635efSGarrett D'Amore * ones. If we find no list type, we default to LIST_item.
43295c635efSGarrett D'Amore */
43395c635efSGarrett D'Amore
434*260e9a87SYuri Pankov wa = (n->args == NULL) ? NULL : n->args->argv;
435*260e9a87SYuri Pankov mdoclt = MDOC_ARG_MAX;
43695c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) {
437*260e9a87SYuri Pankov argv = n->args->argv + i;
43895c635efSGarrett D'Amore lt = LIST__NONE;
439*260e9a87SYuri Pankov switch (argv->arg) {
44095c635efSGarrett D'Amore /* Set list types. */
441*260e9a87SYuri Pankov case MDOC_Bullet:
44295c635efSGarrett D'Amore lt = LIST_bullet;
44395c635efSGarrett D'Amore break;
444*260e9a87SYuri Pankov case MDOC_Dash:
44595c635efSGarrett D'Amore lt = LIST_dash;
44695c635efSGarrett D'Amore break;
447*260e9a87SYuri Pankov case MDOC_Enum:
44895c635efSGarrett D'Amore lt = LIST_enum;
44995c635efSGarrett D'Amore break;
450*260e9a87SYuri Pankov case MDOC_Hyphen:
45195c635efSGarrett D'Amore lt = LIST_hyphen;
45295c635efSGarrett D'Amore break;
453*260e9a87SYuri Pankov case MDOC_Item:
45495c635efSGarrett D'Amore lt = LIST_item;
45595c635efSGarrett D'Amore break;
456*260e9a87SYuri Pankov case MDOC_Tag:
45795c635efSGarrett D'Amore lt = LIST_tag;
45895c635efSGarrett D'Amore break;
459*260e9a87SYuri Pankov case MDOC_Diag:
46095c635efSGarrett D'Amore lt = LIST_diag;
46195c635efSGarrett D'Amore break;
462*260e9a87SYuri Pankov case MDOC_Hang:
46395c635efSGarrett D'Amore lt = LIST_hang;
46495c635efSGarrett D'Amore break;
465*260e9a87SYuri Pankov case MDOC_Ohang:
46695c635efSGarrett D'Amore lt = LIST_ohang;
46795c635efSGarrett D'Amore break;
468*260e9a87SYuri Pankov case MDOC_Inset:
46995c635efSGarrett D'Amore lt = LIST_inset;
47095c635efSGarrett D'Amore break;
471*260e9a87SYuri Pankov case MDOC_Column:
47295c635efSGarrett D'Amore lt = LIST_column;
47395c635efSGarrett D'Amore break;
47495c635efSGarrett D'Amore /* Set list arguments. */
475*260e9a87SYuri Pankov case MDOC_Compact:
476*260e9a87SYuri Pankov if (n->norm->Bl.comp)
477*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_REP,
478*260e9a87SYuri Pankov mdoc->parse, argv->line,
479*260e9a87SYuri Pankov argv->pos, "Bl -compact");
480*260e9a87SYuri Pankov n->norm->Bl.comp = 1;
48195c635efSGarrett D'Amore break;
482*260e9a87SYuri Pankov case MDOC_Width:
483*260e9a87SYuri Pankov wa = argv;
484*260e9a87SYuri Pankov if (0 == argv->sz) {
485*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY,
486*260e9a87SYuri Pankov mdoc->parse, argv->line,
487*260e9a87SYuri Pankov argv->pos, "Bl -width");
488*260e9a87SYuri Pankov n->norm->Bl.width = "0n";
48995c635efSGarrett D'Amore break;
49095c635efSGarrett D'Amore }
491*260e9a87SYuri Pankov if (NULL != n->norm->Bl.width)
492*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP,
493*260e9a87SYuri Pankov mdoc->parse, argv->line,
494*260e9a87SYuri Pankov argv->pos, "Bl -width %s",
495*260e9a87SYuri Pankov argv->value[0]);
496*260e9a87SYuri Pankov rewrite_macro2len(argv->value);
497*260e9a87SYuri Pankov n->norm->Bl.width = argv->value[0];
49895c635efSGarrett D'Amore break;
499*260e9a87SYuri Pankov case MDOC_Offset:
500*260e9a87SYuri Pankov if (0 == argv->sz) {
501*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY,
502*260e9a87SYuri Pankov mdoc->parse, argv->line,
503*260e9a87SYuri Pankov argv->pos, "Bl -offset");
50495c635efSGarrett D'Amore break;
50595c635efSGarrett D'Amore }
506*260e9a87SYuri Pankov if (NULL != n->norm->Bl.offs)
507*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP,
508*260e9a87SYuri Pankov mdoc->parse, argv->line,
509*260e9a87SYuri Pankov argv->pos, "Bl -offset %s",
510*260e9a87SYuri Pankov argv->value[0]);
511*260e9a87SYuri Pankov rewrite_macro2len(argv->value);
512*260e9a87SYuri Pankov n->norm->Bl.offs = argv->value[0];
51395c635efSGarrett D'Amore break;
51495c635efSGarrett D'Amore default:
51595c635efSGarrett D'Amore continue;
51695c635efSGarrett D'Amore }
517*260e9a87SYuri Pankov if (LIST__NONE == lt)
518*260e9a87SYuri Pankov continue;
519*260e9a87SYuri Pankov mdoclt = argv->arg;
52095c635efSGarrett D'Amore
52195c635efSGarrett D'Amore /* Check: multiple list types. */
52295c635efSGarrett D'Amore
523*260e9a87SYuri Pankov if (LIST__NONE != n->norm->Bl.type) {
524*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_REP,
525*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos,
526*260e9a87SYuri Pankov "Bl -%s", mdoc_argnames[argv->arg]);
527*260e9a87SYuri Pankov continue;
52895c635efSGarrett D'Amore }
52995c635efSGarrett D'Amore
53095c635efSGarrett D'Amore /* The list type should come first. */
53195c635efSGarrett D'Amore
53295c635efSGarrett D'Amore if (n->norm->Bl.width ||
53395c635efSGarrett D'Amore n->norm->Bl.offs ||
53495c635efSGarrett D'Amore n->norm->Bl.comp)
535*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_LATETYPE,
536*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Bl -%s",
537*260e9a87SYuri Pankov mdoc_argnames[n->args->argv[0].arg]);
53895c635efSGarrett D'Amore
539*260e9a87SYuri Pankov n->norm->Bl.type = lt;
540*260e9a87SYuri Pankov if (LIST_column == lt) {
541*260e9a87SYuri Pankov n->norm->Bl.ncols = argv->sz;
542*260e9a87SYuri Pankov n->norm->Bl.cols = (void *)argv->value;
543*260e9a87SYuri Pankov }
54495c635efSGarrett D'Amore }
54595c635efSGarrett D'Amore
54695c635efSGarrett D'Amore /* Allow lists to default to LIST_item. */
54795c635efSGarrett D'Amore
54895c635efSGarrett D'Amore if (LIST__NONE == n->norm->Bl.type) {
549*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_NOTYPE, mdoc->parse,
550*260e9a87SYuri Pankov n->line, n->pos, "Bl");
55195c635efSGarrett D'Amore n->norm->Bl.type = LIST_item;
55295c635efSGarrett D'Amore }
55395c635efSGarrett D'Amore
55495c635efSGarrett D'Amore /*
55595c635efSGarrett D'Amore * Validate the width field. Some list types don't need width
55695c635efSGarrett D'Amore * types and should be warned about them. Others should have it
557698f87a4SGarrett D'Amore * and must also be warned. Yet others have a default and need
558698f87a4SGarrett D'Amore * no warning.
55995c635efSGarrett D'Amore */
56095c635efSGarrett D'Amore
56195c635efSGarrett D'Amore switch (n->norm->Bl.type) {
562*260e9a87SYuri Pankov case LIST_tag:
563698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width)
564*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_NOWIDTH, mdoc->parse,
565*260e9a87SYuri Pankov n->line, n->pos, "Bl -tag");
56695c635efSGarrett D'Amore break;
567*260e9a87SYuri Pankov case LIST_column:
56895c635efSGarrett D'Amore /* FALLTHROUGH */
569*260e9a87SYuri Pankov case LIST_diag:
57095c635efSGarrett D'Amore /* FALLTHROUGH */
571*260e9a87SYuri Pankov case LIST_ohang:
57295c635efSGarrett D'Amore /* FALLTHROUGH */
573*260e9a87SYuri Pankov case LIST_inset:
57495c635efSGarrett D'Amore /* FALLTHROUGH */
575*260e9a87SYuri Pankov case LIST_item:
57695c635efSGarrett D'Amore if (n->norm->Bl.width)
577*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_SKIPW, mdoc->parse,
578*260e9a87SYuri Pankov wa->line, wa->pos, "Bl -%s",
579*260e9a87SYuri Pankov mdoc_argnames[mdoclt]);
58095c635efSGarrett D'Amore break;
581*260e9a87SYuri Pankov case LIST_bullet:
582698f87a4SGarrett D'Amore /* FALLTHROUGH */
583*260e9a87SYuri Pankov case LIST_dash:
584698f87a4SGarrett D'Amore /* FALLTHROUGH */
585*260e9a87SYuri Pankov case LIST_hyphen:
586698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width)
587698f87a4SGarrett D'Amore n->norm->Bl.width = "2n";
588698f87a4SGarrett D'Amore break;
589*260e9a87SYuri Pankov case LIST_enum:
590698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width)
591698f87a4SGarrett D'Amore n->norm->Bl.width = "3n";
592698f87a4SGarrett D'Amore break;
59395c635efSGarrett D'Amore default:
59495c635efSGarrett D'Amore break;
59595c635efSGarrett D'Amore }
596*260e9a87SYuri Pankov pre_par(mdoc, n);
59795c635efSGarrett D'Amore }
59895c635efSGarrett D'Amore
599*260e9a87SYuri Pankov static void
pre_bd(PRE_ARGS)60095c635efSGarrett D'Amore pre_bd(PRE_ARGS)
60195c635efSGarrett D'Amore {
602*260e9a87SYuri Pankov struct mdoc_argv *argv;
603*260e9a87SYuri Pankov int i;
60495c635efSGarrett D'Amore enum mdoc_disp dt;
60595c635efSGarrett D'Amore
606*260e9a87SYuri Pankov pre_literal(mdoc, n);
60795c635efSGarrett D'Amore
608*260e9a87SYuri Pankov if (n->type != MDOC_BLOCK)
609*260e9a87SYuri Pankov return;
61095c635efSGarrett D'Amore
61195c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) {
612*260e9a87SYuri Pankov argv = n->args->argv + i;
61395c635efSGarrett D'Amore dt = DISP__NONE;
61495c635efSGarrett D'Amore
615*260e9a87SYuri Pankov switch (argv->arg) {
616*260e9a87SYuri Pankov case MDOC_Centred:
617*260e9a87SYuri Pankov dt = DISP_centered;
61895c635efSGarrett D'Amore break;
619*260e9a87SYuri Pankov case MDOC_Ragged:
62095c635efSGarrett D'Amore dt = DISP_ragged;
62195c635efSGarrett D'Amore break;
622*260e9a87SYuri Pankov case MDOC_Unfilled:
62395c635efSGarrett D'Amore dt = DISP_unfilled;
62495c635efSGarrett D'Amore break;
625*260e9a87SYuri Pankov case MDOC_Filled:
62695c635efSGarrett D'Amore dt = DISP_filled;
62795c635efSGarrett D'Amore break;
628*260e9a87SYuri Pankov case MDOC_Literal:
62995c635efSGarrett D'Amore dt = DISP_literal;
63095c635efSGarrett D'Amore break;
631*260e9a87SYuri Pankov case MDOC_File:
632*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BD_FILE, mdoc->parse,
633*260e9a87SYuri Pankov n->line, n->pos, NULL);
634*260e9a87SYuri Pankov break;
635*260e9a87SYuri Pankov case MDOC_Offset:
636*260e9a87SYuri Pankov if (0 == argv->sz) {
637*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_EMPTY,
638*260e9a87SYuri Pankov mdoc->parse, argv->line,
639*260e9a87SYuri Pankov argv->pos, "Bd -offset");
64095c635efSGarrett D'Amore break;
64195c635efSGarrett D'Amore }
642*260e9a87SYuri Pankov if (NULL != n->norm->Bd.offs)
643*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_REP,
644*260e9a87SYuri Pankov mdoc->parse, argv->line,
645*260e9a87SYuri Pankov argv->pos, "Bd -offset %s",
646*260e9a87SYuri Pankov argv->value[0]);
647*260e9a87SYuri Pankov rewrite_macro2len(argv->value);
648*260e9a87SYuri Pankov n->norm->Bd.offs = argv->value[0];
64995c635efSGarrett D'Amore break;
650*260e9a87SYuri Pankov case MDOC_Compact:
651*260e9a87SYuri Pankov if (n->norm->Bd.comp)
652*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_REP,
653*260e9a87SYuri Pankov mdoc->parse, argv->line,
654*260e9a87SYuri Pankov argv->pos, "Bd -compact");
655*260e9a87SYuri Pankov n->norm->Bd.comp = 1;
65695c635efSGarrett D'Amore break;
65795c635efSGarrett D'Amore default:
65895c635efSGarrett D'Amore abort();
65995c635efSGarrett D'Amore /* NOTREACHED */
66095c635efSGarrett D'Amore }
661*260e9a87SYuri Pankov if (DISP__NONE == dt)
662*260e9a87SYuri Pankov continue;
66395c635efSGarrett D'Amore
664*260e9a87SYuri Pankov if (DISP__NONE == n->norm->Bd.type)
66595c635efSGarrett D'Amore n->norm->Bd.type = dt;
666*260e9a87SYuri Pankov else
667*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BD_REP,
668*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos,
669*260e9a87SYuri Pankov "Bd -%s", mdoc_argnames[argv->arg]);
67095c635efSGarrett D'Amore }
67195c635efSGarrett D'Amore
67295c635efSGarrett D'Amore if (DISP__NONE == n->norm->Bd.type) {
673*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BD_NOTYPE, mdoc->parse,
674*260e9a87SYuri Pankov n->line, n->pos, "Bd");
67595c635efSGarrett D'Amore n->norm->Bd.type = DISP_ragged;
67695c635efSGarrett D'Amore }
677*260e9a87SYuri Pankov pre_par(mdoc, n);
67895c635efSGarrett D'Amore }
67995c635efSGarrett D'Amore
680*260e9a87SYuri Pankov static void
pre_an(PRE_ARGS)68195c635efSGarrett D'Amore pre_an(PRE_ARGS)
68295c635efSGarrett D'Amore {
683*260e9a87SYuri Pankov struct mdoc_argv *argv;
684*260e9a87SYuri Pankov size_t i;
68595c635efSGarrett D'Amore
686*260e9a87SYuri Pankov if (n->args == NULL)
687*260e9a87SYuri Pankov return;
68895c635efSGarrett D'Amore
689*260e9a87SYuri Pankov for (i = 1; i < n->args->argc; i++) {
690*260e9a87SYuri Pankov argv = n->args->argv + i;
691*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_AN_REP,
692*260e9a87SYuri Pankov mdoc->parse, argv->line, argv->pos,
693*260e9a87SYuri Pankov "An -%s", mdoc_argnames[argv->arg]);
694*260e9a87SYuri Pankov }
69595c635efSGarrett D'Amore
696*260e9a87SYuri Pankov argv = n->args->argv;
697*260e9a87SYuri Pankov if (argv->arg == MDOC_Split)
69895c635efSGarrett D'Amore n->norm->An.auth = AUTH_split;
699*260e9a87SYuri Pankov else if (argv->arg == MDOC_Nosplit)
70095c635efSGarrett D'Amore n->norm->An.auth = AUTH_nosplit;
70195c635efSGarrett D'Amore else
70295c635efSGarrett D'Amore abort();
70395c635efSGarrett D'Amore }
70495c635efSGarrett D'Amore
705*260e9a87SYuri Pankov static void
pre_std(PRE_ARGS)70695c635efSGarrett D'Amore pre_std(PRE_ARGS)
70795c635efSGarrett D'Amore {
70895c635efSGarrett D'Amore
70995c635efSGarrett D'Amore if (n->args && 1 == n->args->argc)
71095c635efSGarrett D'Amore if (MDOC_Std == n->args->argv[0].arg)
711*260e9a87SYuri Pankov return;
71295c635efSGarrett D'Amore
713*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_STD, mdoc->parse,
714*260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]);
71595c635efSGarrett D'Amore }
71695c635efSGarrett D'Amore
717*260e9a87SYuri Pankov static void
pre_obsolete(PRE_ARGS)718*260e9a87SYuri Pankov pre_obsolete(PRE_ARGS)
719*260e9a87SYuri Pankov {
720*260e9a87SYuri Pankov
721*260e9a87SYuri Pankov if (MDOC_ELEM == n->type || MDOC_BLOCK == n->type)
722*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_OBS, mdoc->parse,
723*260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]);
724*260e9a87SYuri Pankov }
725*260e9a87SYuri Pankov
726*260e9a87SYuri Pankov static void
pre_dt(PRE_ARGS)72795c635efSGarrett D'Amore pre_dt(PRE_ARGS)
72895c635efSGarrett D'Amore {
72995c635efSGarrett D'Amore
730*260e9a87SYuri Pankov if (mdoc->meta.title != NULL)
731*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
732*260e9a87SYuri Pankov n->line, n->pos, "Dt");
733*260e9a87SYuri Pankov else if (mdoc->meta.os != NULL)
734*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
735*260e9a87SYuri Pankov n->line, n->pos, "Dt after Os");
73695c635efSGarrett D'Amore }
73795c635efSGarrett D'Amore
738*260e9a87SYuri Pankov static void
pre_os(PRE_ARGS)73995c635efSGarrett D'Amore pre_os(PRE_ARGS)
74095c635efSGarrett D'Amore {
74195c635efSGarrett D'Amore
742*260e9a87SYuri Pankov if (mdoc->meta.os != NULL)
743*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
744*260e9a87SYuri Pankov n->line, n->pos, "Os");
745*260e9a87SYuri Pankov else if (mdoc->flags & MDOC_PBODY)
746*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
747*260e9a87SYuri Pankov n->line, n->pos, "Os");
74895c635efSGarrett D'Amore }
74995c635efSGarrett D'Amore
750*260e9a87SYuri Pankov static void
pre_dd(PRE_ARGS)75195c635efSGarrett D'Amore pre_dd(PRE_ARGS)
75295c635efSGarrett D'Amore {
75395c635efSGarrett D'Amore
754*260e9a87SYuri Pankov if (mdoc->meta.date != NULL)
755*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_REP, mdoc->parse,
756*260e9a87SYuri Pankov n->line, n->pos, "Dd");
757*260e9a87SYuri Pankov else if (mdoc->flags & MDOC_PBODY)
758*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_LATE, mdoc->parse,
759*260e9a87SYuri Pankov n->line, n->pos, "Dd");
760*260e9a87SYuri Pankov else if (mdoc->meta.title != NULL)
761*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
762*260e9a87SYuri Pankov n->line, n->pos, "Dd after Dt");
763*260e9a87SYuri Pankov else if (mdoc->meta.os != NULL)
764*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PROLOG_ORDER, mdoc->parse,
765*260e9a87SYuri Pankov n->line, n->pos, "Dd after Os");
76695c635efSGarrett D'Amore }
76795c635efSGarrett D'Amore
768*260e9a87SYuri Pankov static void
post_bf(POST_ARGS)76995c635efSGarrett D'Amore post_bf(POST_ARGS)
77095c635efSGarrett D'Amore {
771*260e9a87SYuri Pankov struct mdoc_node *np, *nch;
77295c635efSGarrett D'Amore enum mdocargt arg;
77395c635efSGarrett D'Amore
77495c635efSGarrett D'Amore /*
77595c635efSGarrett D'Amore * Unlike other data pointers, these are "housed" by the HEAD
77695c635efSGarrett D'Amore * element, which contains the goods.
77795c635efSGarrett D'Amore */
77895c635efSGarrett D'Amore
77995c635efSGarrett D'Amore np = mdoc->last;
780*260e9a87SYuri Pankov if (MDOC_HEAD != np->type)
781*260e9a87SYuri Pankov return;
782*260e9a87SYuri Pankov
78395c635efSGarrett D'Amore assert(MDOC_BLOCK == np->parent->type);
78495c635efSGarrett D'Amore assert(MDOC_Bf == np->parent->tok);
78595c635efSGarrett D'Amore
786*260e9a87SYuri Pankov /* Check the number of arguments. */
78795c635efSGarrett D'Amore
788*260e9a87SYuri Pankov nch = np->child;
789*260e9a87SYuri Pankov if (NULL == np->parent->args) {
790*260e9a87SYuri Pankov if (NULL == nch) {
791*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BF_NOFONT, mdoc->parse,
792*260e9a87SYuri Pankov np->line, np->pos, "Bf");
793*260e9a87SYuri Pankov return;
79495c635efSGarrett D'Amore }
795*260e9a87SYuri Pankov nch = nch->next;
796*260e9a87SYuri Pankov }
797*260e9a87SYuri Pankov if (NULL != nch)
798*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
799*260e9a87SYuri Pankov nch->line, nch->pos, "Bf ... %s", nch->string);
80095c635efSGarrett D'Amore
80195c635efSGarrett D'Amore /* Extract argument into data. */
80295c635efSGarrett D'Amore
80395c635efSGarrett D'Amore if (np->parent->args) {
80495c635efSGarrett D'Amore arg = np->parent->args->argv[0].arg;
80595c635efSGarrett D'Amore if (MDOC_Emphasis == arg)
80695c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em;
80795c635efSGarrett D'Amore else if (MDOC_Literal == arg)
80895c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li;
80995c635efSGarrett D'Amore else if (MDOC_Symbolic == arg)
81095c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy;
81195c635efSGarrett D'Amore else
81295c635efSGarrett D'Amore abort();
813*260e9a87SYuri Pankov return;
81495c635efSGarrett D'Amore }
81595c635efSGarrett D'Amore
81695c635efSGarrett D'Amore /* Extract parameter into data. */
81795c635efSGarrett D'Amore
81895c635efSGarrett D'Amore if (0 == strcmp(np->child->string, "Em"))
81995c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em;
82095c635efSGarrett D'Amore else if (0 == strcmp(np->child->string, "Li"))
82195c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li;
82295c635efSGarrett D'Amore else if (0 == strcmp(np->child->string, "Sy"))
82395c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy;
82495c635efSGarrett D'Amore else
825*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BF_BADFONT, mdoc->parse,
826*260e9a87SYuri Pankov np->child->line, np->child->pos,
827*260e9a87SYuri Pankov "Bf %s", np->child->string);
82895c635efSGarrett D'Amore }
82995c635efSGarrett D'Amore
830*260e9a87SYuri Pankov static void
post_lb(POST_ARGS)83195c635efSGarrett D'Amore post_lb(POST_ARGS)
83295c635efSGarrett D'Amore {
833*260e9a87SYuri Pankov struct mdoc_node *n;
834*260e9a87SYuri Pankov const char *stdlibname;
835*260e9a87SYuri Pankov char *libname;
83695c635efSGarrett D'Amore
837*260e9a87SYuri Pankov n = mdoc->last->child;
838*260e9a87SYuri Pankov assert(MDOC_TEXT == n->type);
83995c635efSGarrett D'Amore
840*260e9a87SYuri Pankov if (NULL == (stdlibname = mdoc_a2lib(n->string)))
841*260e9a87SYuri Pankov mandoc_asprintf(&libname,
842*260e9a87SYuri Pankov "library \\(Lq%s\\(Rq", n->string);
843*260e9a87SYuri Pankov else
844*260e9a87SYuri Pankov libname = mandoc_strdup(stdlibname);
84595c635efSGarrett D'Amore
846*260e9a87SYuri Pankov free(n->string);
847*260e9a87SYuri Pankov n->string = libname;
84895c635efSGarrett D'Amore }
84995c635efSGarrett D'Amore
850*260e9a87SYuri Pankov static void
post_eoln(POST_ARGS)85195c635efSGarrett D'Amore post_eoln(POST_ARGS)
85295c635efSGarrett D'Amore {
853*260e9a87SYuri Pankov const struct mdoc_node *n;
85495c635efSGarrett D'Amore
855*260e9a87SYuri Pankov n = mdoc->last;
856*260e9a87SYuri Pankov if (n->child)
857*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP,
858*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos,
859*260e9a87SYuri Pankov "%s %s", mdoc_macronames[n->tok],
860*260e9a87SYuri Pankov n->child->string);
86195c635efSGarrett D'Amore }
86295c635efSGarrett D'Amore
863*260e9a87SYuri Pankov static void
post_fname(POST_ARGS)864*260e9a87SYuri Pankov post_fname(POST_ARGS)
865*260e9a87SYuri Pankov {
866*260e9a87SYuri Pankov const struct mdoc_node *n;
867*260e9a87SYuri Pankov const char *cp;
868*260e9a87SYuri Pankov size_t pos;
86995c635efSGarrett D'Amore
870*260e9a87SYuri Pankov n = mdoc->last->child;
871*260e9a87SYuri Pankov pos = strcspn(n->string, "()");
872*260e9a87SYuri Pankov cp = n->string + pos;
873*260e9a87SYuri Pankov if ( ! (cp[0] == '\0' || (cp[0] == '(' && cp[1] == '*')))
874*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FN_PAREN, mdoc->parse,
875*260e9a87SYuri Pankov n->line, n->pos + pos, n->string);
876*260e9a87SYuri Pankov }
877*260e9a87SYuri Pankov
878*260e9a87SYuri Pankov static void
post_fn(POST_ARGS)879*260e9a87SYuri Pankov post_fn(POST_ARGS)
880*260e9a87SYuri Pankov {
881*260e9a87SYuri Pankov
882*260e9a87SYuri Pankov post_fname(mdoc);
883*260e9a87SYuri Pankov post_fa(mdoc);
884*260e9a87SYuri Pankov }
885*260e9a87SYuri Pankov
886*260e9a87SYuri Pankov static void
post_fo(POST_ARGS)887*260e9a87SYuri Pankov post_fo(POST_ARGS)
888*260e9a87SYuri Pankov {
889*260e9a87SYuri Pankov const struct mdoc_node *n;
890*260e9a87SYuri Pankov
891*260e9a87SYuri Pankov n = mdoc->last;
892*260e9a87SYuri Pankov
893*260e9a87SYuri Pankov if (n->type != MDOC_HEAD)
894*260e9a87SYuri Pankov return;
895*260e9a87SYuri Pankov
896*260e9a87SYuri Pankov if (n->child == NULL) {
897*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FO_NOHEAD, mdoc->parse,
898*260e9a87SYuri Pankov n->line, n->pos, "Fo");
899*260e9a87SYuri Pankov return;
900*260e9a87SYuri Pankov }
901*260e9a87SYuri Pankov if (n->child != n->last) {
902*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
903*260e9a87SYuri Pankov n->child->next->line, n->child->next->pos,
904*260e9a87SYuri Pankov "Fo ... %s", n->child->next->string);
905*260e9a87SYuri Pankov while (n->child != n->last)
906*260e9a87SYuri Pankov mdoc_node_delete(mdoc, n->last);
907*260e9a87SYuri Pankov }
908*260e9a87SYuri Pankov
909*260e9a87SYuri Pankov post_fname(mdoc);
910*260e9a87SYuri Pankov }
911*260e9a87SYuri Pankov
912*260e9a87SYuri Pankov static void
post_fa(POST_ARGS)913*260e9a87SYuri Pankov post_fa(POST_ARGS)
914*260e9a87SYuri Pankov {
915*260e9a87SYuri Pankov const struct mdoc_node *n;
916*260e9a87SYuri Pankov const char *cp;
917*260e9a87SYuri Pankov
918*260e9a87SYuri Pankov for (n = mdoc->last->child; n != NULL; n = n->next) {
919*260e9a87SYuri Pankov for (cp = n->string; *cp != '\0'; cp++) {
920*260e9a87SYuri Pankov /* Ignore callbacks and alterations. */
921*260e9a87SYuri Pankov if (*cp == '(' || *cp == '{')
922*260e9a87SYuri Pankov break;
923*260e9a87SYuri Pankov if (*cp != ',')
924*260e9a87SYuri Pankov continue;
925*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_FA_COMMA, mdoc->parse,
926*260e9a87SYuri Pankov n->line, n->pos + (cp - n->string),
927*260e9a87SYuri Pankov n->string);
928*260e9a87SYuri Pankov break;
929*260e9a87SYuri Pankov }
930*260e9a87SYuri Pankov }
931*260e9a87SYuri Pankov }
932*260e9a87SYuri Pankov
933*260e9a87SYuri Pankov static void
post_vt(POST_ARGS)93495c635efSGarrett D'Amore post_vt(POST_ARGS)
93595c635efSGarrett D'Amore {
93695c635efSGarrett D'Amore const struct mdoc_node *n;
93795c635efSGarrett D'Amore
93895c635efSGarrett D'Amore /*
93995c635efSGarrett D'Amore * The Vt macro comes in both ELEM and BLOCK form, both of which
94095c635efSGarrett D'Amore * have different syntaxes (yet more context-sensitive
94195c635efSGarrett D'Amore * behaviour). ELEM types must have a child, which is already
94295c635efSGarrett D'Amore * guaranteed by the in_line parsing routine; BLOCK types,
94395c635efSGarrett D'Amore * specifically the BODY, should only have TEXT children.
94495c635efSGarrett D'Amore */
94595c635efSGarrett D'Amore
94695c635efSGarrett D'Amore if (MDOC_BODY != mdoc->last->type)
947*260e9a87SYuri Pankov return;
94895c635efSGarrett D'Amore
94995c635efSGarrett D'Amore for (n = mdoc->last->child; n; n = n->next)
95095c635efSGarrett D'Amore if (MDOC_TEXT != n->type)
951*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_VT_CHILD, mdoc->parse,
952*260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]);
95395c635efSGarrett D'Amore }
95495c635efSGarrett D'Amore
955*260e9a87SYuri Pankov static void
post_nm(POST_ARGS)95695c635efSGarrett D'Amore post_nm(POST_ARGS)
95795c635efSGarrett D'Amore {
958*260e9a87SYuri Pankov struct mdoc_node *n;
959*260e9a87SYuri Pankov
960*260e9a87SYuri Pankov n = mdoc->last;
961*260e9a87SYuri Pankov
962*260e9a87SYuri Pankov if (n->last != NULL &&
963*260e9a87SYuri Pankov (n->last->tok == MDOC_Pp ||
964*260e9a87SYuri Pankov n->last->tok == MDOC_Lp))
965*260e9a87SYuri Pankov mdoc_node_relink(mdoc, n->last);
96695c635efSGarrett D'Amore
967698f87a4SGarrett D'Amore if (NULL != mdoc->meta.name)
968*260e9a87SYuri Pankov return;
96995c635efSGarrett D'Amore
970*260e9a87SYuri Pankov mdoc_deroff(&mdoc->meta.name, n);
97195c635efSGarrett D'Amore
972*260e9a87SYuri Pankov if (NULL == mdoc->meta.name)
973*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NM_NONAME, mdoc->parse,
974*260e9a87SYuri Pankov n->line, n->pos, "Nm");
97595c635efSGarrett D'Amore }
97695c635efSGarrett D'Amore
977*260e9a87SYuri Pankov static void
post_nd(POST_ARGS)978*260e9a87SYuri Pankov post_nd(POST_ARGS)
979*260e9a87SYuri Pankov {
980*260e9a87SYuri Pankov struct mdoc_node *n;
981*260e9a87SYuri Pankov
982*260e9a87SYuri Pankov n = mdoc->last;
983*260e9a87SYuri Pankov
984*260e9a87SYuri Pankov if (n->type != MDOC_BODY)
985*260e9a87SYuri Pankov return;
986*260e9a87SYuri Pankov
987*260e9a87SYuri Pankov if (n->child == NULL)
988*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ND_EMPTY, mdoc->parse,
989*260e9a87SYuri Pankov n->line, n->pos, "Nd");
990*260e9a87SYuri Pankov
991*260e9a87SYuri Pankov post_hyph(mdoc);
992*260e9a87SYuri Pankov }
993*260e9a87SYuri Pankov
994*260e9a87SYuri Pankov static void
post_d1(POST_ARGS)995*260e9a87SYuri Pankov post_d1(POST_ARGS)
996*260e9a87SYuri Pankov {
997*260e9a87SYuri Pankov struct mdoc_node *n;
998*260e9a87SYuri Pankov
999*260e9a87SYuri Pankov n = mdoc->last;
1000*260e9a87SYuri Pankov
1001*260e9a87SYuri Pankov if (n->type != MDOC_BODY)
1002*260e9a87SYuri Pankov return;
1003*260e9a87SYuri Pankov
1004*260e9a87SYuri Pankov if (n->child == NULL)
1005*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
1006*260e9a87SYuri Pankov n->line, n->pos, "D1");
1007*260e9a87SYuri Pankov
1008*260e9a87SYuri Pankov post_hyph(mdoc);
1009*260e9a87SYuri Pankov }
1010*260e9a87SYuri Pankov
1011*260e9a87SYuri Pankov static void
post_literal(POST_ARGS)101295c635efSGarrett D'Amore post_literal(POST_ARGS)
101395c635efSGarrett D'Amore {
1014*260e9a87SYuri Pankov struct mdoc_node *n;
101595c635efSGarrett D'Amore
1016*260e9a87SYuri Pankov n = mdoc->last;
101795c635efSGarrett D'Amore
1018*260e9a87SYuri Pankov if (n->type != MDOC_BODY)
1019*260e9a87SYuri Pankov return;
1020*260e9a87SYuri Pankov
1021*260e9a87SYuri Pankov if (n->child == NULL)
1022*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
1023*260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]);
1024*260e9a87SYuri Pankov
1025*260e9a87SYuri Pankov if (n->tok == MDOC_Bd &&
1026*260e9a87SYuri Pankov n->norm->Bd.type != DISP_literal &&
1027*260e9a87SYuri Pankov n->norm->Bd.type != DISP_unfilled)
1028*260e9a87SYuri Pankov return;
1029*260e9a87SYuri Pankov
103095c635efSGarrett D'Amore mdoc->flags &= ~MDOC_LITERAL;
103195c635efSGarrett D'Amore }
103295c635efSGarrett D'Amore
1033*260e9a87SYuri Pankov static void
post_defaults(POST_ARGS)103495c635efSGarrett D'Amore post_defaults(POST_ARGS)
103595c635efSGarrett D'Amore {
103695c635efSGarrett D'Amore struct mdoc_node *nn;
103795c635efSGarrett D'Amore
103895c635efSGarrett D'Amore /*
103995c635efSGarrett D'Amore * The `Ar' defaults to "file ..." if no value is provided as an
104095c635efSGarrett D'Amore * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
104195c635efSGarrett D'Amore * gets an empty string.
104295c635efSGarrett D'Amore */
104395c635efSGarrett D'Amore
104495c635efSGarrett D'Amore if (mdoc->last->child)
1045*260e9a87SYuri Pankov return;
104695c635efSGarrett D'Amore
104795c635efSGarrett D'Amore nn = mdoc->last;
104895c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
104995c635efSGarrett D'Amore
105095c635efSGarrett D'Amore switch (nn->tok) {
1051*260e9a87SYuri Pankov case MDOC_Ar:
1052*260e9a87SYuri Pankov mdoc_word_alloc(mdoc, nn->line, nn->pos, "file");
1053*260e9a87SYuri Pankov mdoc_word_alloc(mdoc, nn->line, nn->pos, "...");
105495c635efSGarrett D'Amore break;
1055*260e9a87SYuri Pankov case MDOC_Pa:
105695c635efSGarrett D'Amore /* FALLTHROUGH */
1057*260e9a87SYuri Pankov case MDOC_Mt:
1058*260e9a87SYuri Pankov mdoc_word_alloc(mdoc, nn->line, nn->pos, "~");
105995c635efSGarrett D'Amore break;
106095c635efSGarrett D'Amore default:
106195c635efSGarrett D'Amore abort();
106295c635efSGarrett D'Amore /* NOTREACHED */
106395c635efSGarrett D'Amore }
106495c635efSGarrett D'Amore mdoc->last = nn;
106595c635efSGarrett D'Amore }
106695c635efSGarrett D'Amore
1067*260e9a87SYuri Pankov static void
post_at(POST_ARGS)106895c635efSGarrett D'Amore post_at(POST_ARGS)
106995c635efSGarrett D'Amore {
1070*260e9a87SYuri Pankov struct mdoc_node *n;
1071*260e9a87SYuri Pankov const char *std_att;
1072*260e9a87SYuri Pankov char *att;
1073*260e9a87SYuri Pankov
1074*260e9a87SYuri Pankov n = mdoc->last;
1075*260e9a87SYuri Pankov if (n->child == NULL) {
1076*260e9a87SYuri Pankov mdoc->next = MDOC_NEXT_CHILD;
1077*260e9a87SYuri Pankov mdoc_word_alloc(mdoc, n->line, n->pos, "AT&T UNIX");
1078*260e9a87SYuri Pankov mdoc->last = n;
1079*260e9a87SYuri Pankov return;
1080*260e9a87SYuri Pankov }
108195c635efSGarrett D'Amore
108295c635efSGarrett D'Amore /*
108395c635efSGarrett D'Amore * If we have a child, look it up in the standard keys. If a
108495c635efSGarrett D'Amore * key exist, use that instead of the child; if it doesn't,
108595c635efSGarrett D'Amore * prefix "AT&T UNIX " to the existing data.
108695c635efSGarrett D'Amore */
108795c635efSGarrett D'Amore
1088*260e9a87SYuri Pankov n = n->child;
1089*260e9a87SYuri Pankov assert(MDOC_TEXT == n->type);
1090*260e9a87SYuri Pankov if (NULL == (std_att = mdoc_a2att(n->string))) {
1091*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_AT_BAD, mdoc->parse,
1092*260e9a87SYuri Pankov n->line, n->pos, "At %s", n->string);
1093*260e9a87SYuri Pankov mandoc_asprintf(&att, "AT&T UNIX %s", n->string);
1094*260e9a87SYuri Pankov } else
1095*260e9a87SYuri Pankov att = mandoc_strdup(std_att);
109695c635efSGarrett D'Amore
1097*260e9a87SYuri Pankov free(n->string);
1098*260e9a87SYuri Pankov n->string = att;
109995c635efSGarrett D'Amore }
110095c635efSGarrett D'Amore
1101*260e9a87SYuri Pankov static void
post_an(POST_ARGS)110295c635efSGarrett D'Amore post_an(POST_ARGS)
110395c635efSGarrett D'Amore {
1104*260e9a87SYuri Pankov struct mdoc_node *np, *nch;
110595c635efSGarrett D'Amore
110695c635efSGarrett D'Amore np = mdoc->last;
1107*260e9a87SYuri Pankov nch = np->child;
1108*260e9a87SYuri Pankov if (np->norm->An.auth == AUTH__NONE) {
1109*260e9a87SYuri Pankov if (nch == NULL)
1110*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_MACRO_EMPTY, mdoc->parse,
1111*260e9a87SYuri Pankov np->line, np->pos, "An");
1112*260e9a87SYuri Pankov } else if (nch != NULL)
1113*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1114*260e9a87SYuri Pankov nch->line, nch->pos, "An ... %s", nch->string);
111595c635efSGarrett D'Amore }
111695c635efSGarrett D'Amore
1117*260e9a87SYuri Pankov static void
post_en(POST_ARGS)1118*260e9a87SYuri Pankov post_en(POST_ARGS)
1119*260e9a87SYuri Pankov {
112095c635efSGarrett D'Amore
1121*260e9a87SYuri Pankov if (MDOC_BLOCK == mdoc->last->type)
1122*260e9a87SYuri Pankov mdoc->last->norm->Es = mdoc->last_es;
1123*260e9a87SYuri Pankov }
1124*260e9a87SYuri Pankov
1125*260e9a87SYuri Pankov static void
post_es(POST_ARGS)1126*260e9a87SYuri Pankov post_es(POST_ARGS)
1127*260e9a87SYuri Pankov {
1128*260e9a87SYuri Pankov
1129*260e9a87SYuri Pankov mdoc->last_es = mdoc->last;
1130*260e9a87SYuri Pankov }
1131*260e9a87SYuri Pankov
1132*260e9a87SYuri Pankov static void
post_it(POST_ARGS)113395c635efSGarrett D'Amore post_it(POST_ARGS)
113495c635efSGarrett D'Amore {
113595c635efSGarrett D'Amore int i, cols;
113695c635efSGarrett D'Amore enum mdoc_list lt;
1137*260e9a87SYuri Pankov struct mdoc_node *nbl, *nit, *nch;
113895c635efSGarrett D'Amore
1139*260e9a87SYuri Pankov nit = mdoc->last;
1140*260e9a87SYuri Pankov if (nit->type != MDOC_BLOCK)
1141*260e9a87SYuri Pankov return;
114295c635efSGarrett D'Amore
1143*260e9a87SYuri Pankov nbl = nit->parent->parent;
1144*260e9a87SYuri Pankov lt = nbl->norm->Bl.type;
114595c635efSGarrett D'Amore
114695c635efSGarrett D'Amore switch (lt) {
1147*260e9a87SYuri Pankov case LIST_tag:
1148*260e9a87SYuri Pankov /* FALLTHROUGH */
1149*260e9a87SYuri Pankov case LIST_hang:
1150*260e9a87SYuri Pankov /* FALLTHROUGH */
1151*260e9a87SYuri Pankov case LIST_ohang:
1152*260e9a87SYuri Pankov /* FALLTHROUGH */
1153*260e9a87SYuri Pankov case LIST_inset:
1154*260e9a87SYuri Pankov /* FALLTHROUGH */
1155*260e9a87SYuri Pankov case LIST_diag:
1156*260e9a87SYuri Pankov if (nit->head->child == NULL)
1157*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_IT_NOHEAD,
1158*260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos,
1159*260e9a87SYuri Pankov "Bl -%s It",
1160*260e9a87SYuri Pankov mdoc_argnames[nbl->args->argv[0].arg]);
116195c635efSGarrett D'Amore break;
1162*260e9a87SYuri Pankov case LIST_bullet:
1163*260e9a87SYuri Pankov /* FALLTHROUGH */
1164*260e9a87SYuri Pankov case LIST_dash:
1165*260e9a87SYuri Pankov /* FALLTHROUGH */
1166*260e9a87SYuri Pankov case LIST_enum:
1167*260e9a87SYuri Pankov /* FALLTHROUGH */
1168*260e9a87SYuri Pankov case LIST_hyphen:
1169*260e9a87SYuri Pankov if (nit->body == NULL || nit->body->child == NULL)
1170*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_IT_NOBODY,
1171*260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos,
1172*260e9a87SYuri Pankov "Bl -%s It",
1173*260e9a87SYuri Pankov mdoc_argnames[nbl->args->argv[0].arg]);
1174*260e9a87SYuri Pankov /* FALLTHROUGH */
1175*260e9a87SYuri Pankov case LIST_item:
1176*260e9a87SYuri Pankov if (nit->head->child != NULL)
1177*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP,
1178*260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos,
1179*260e9a87SYuri Pankov "It %s", nit->head->child->string);
118095c635efSGarrett D'Amore break;
1181*260e9a87SYuri Pankov case LIST_column:
1182*260e9a87SYuri Pankov cols = (int)nbl->norm->Bl.ncols;
118395c635efSGarrett D'Amore
1184*260e9a87SYuri Pankov assert(nit->head->child == NULL);
118595c635efSGarrett D'Amore
1186*260e9a87SYuri Pankov for (i = 0, nch = nit->child; nch; nch = nch->next)
1187*260e9a87SYuri Pankov if (nch->type == MDOC_BODY)
118895c635efSGarrett D'Amore i++;
118995c635efSGarrett D'Amore
1190*260e9a87SYuri Pankov if (i < cols || i > cols + 1)
1191*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_BL_COL,
1192*260e9a87SYuri Pankov mdoc->parse, nit->line, nit->pos,
1193*260e9a87SYuri Pankov "%d columns, %d cells", cols, i);
119495c635efSGarrett D'Amore break;
119595c635efSGarrett D'Amore default:
1196*260e9a87SYuri Pankov abort();
1197*260e9a87SYuri Pankov }
119895c635efSGarrett D'Amore }
119995c635efSGarrett D'Amore
1200*260e9a87SYuri Pankov static void
post_bl_block(POST_ARGS)120195c635efSGarrett D'Amore post_bl_block(POST_ARGS)
120295c635efSGarrett D'Amore {
1203698f87a4SGarrett D'Amore struct mdoc_node *n, *ni, *nc;
120495c635efSGarrett D'Amore
120595c635efSGarrett D'Amore /*
120695c635efSGarrett D'Amore * These are fairly complicated, so we've broken them into two
120795c635efSGarrett D'Amore * functions. post_bl_block_tag() is called when a -tag is
120895c635efSGarrett D'Amore * specified, but no -width (it must be guessed). The second
120995c635efSGarrett D'Amore * when a -width is specified (macro indicators must be
121095c635efSGarrett D'Amore * rewritten into real lengths).
121195c635efSGarrett D'Amore */
121295c635efSGarrett D'Amore
121395c635efSGarrett D'Amore n = mdoc->last;
121495c635efSGarrett D'Amore
121595c635efSGarrett D'Amore if (LIST_tag == n->norm->Bl.type &&
121695c635efSGarrett D'Amore NULL == n->norm->Bl.width) {
1217*260e9a87SYuri Pankov post_bl_block_tag(mdoc);
121895c635efSGarrett D'Amore assert(n->norm->Bl.width);
1219698f87a4SGarrett D'Amore }
1220698f87a4SGarrett D'Amore
1221698f87a4SGarrett D'Amore for (ni = n->body->child; ni; ni = ni->next) {
1222698f87a4SGarrett D'Amore if (NULL == ni->body)
1223698f87a4SGarrett D'Amore continue;
1224698f87a4SGarrett D'Amore nc = ni->body->last;
1225698f87a4SGarrett D'Amore while (NULL != nc) {
1226698f87a4SGarrett D'Amore switch (nc->tok) {
1227*260e9a87SYuri Pankov case MDOC_Pp:
1228698f87a4SGarrett D'Amore /* FALLTHROUGH */
1229*260e9a87SYuri Pankov case MDOC_Lp:
1230698f87a4SGarrett D'Amore /* FALLTHROUGH */
1231*260e9a87SYuri Pankov case MDOC_br:
1232698f87a4SGarrett D'Amore break;
1233698f87a4SGarrett D'Amore default:
1234698f87a4SGarrett D'Amore nc = NULL;
1235698f87a4SGarrett D'Amore continue;
1236698f87a4SGarrett D'Amore }
1237698f87a4SGarrett D'Amore if (NULL == ni->next) {
1238*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_PAR_MOVE,
1239*260e9a87SYuri Pankov mdoc->parse, nc->line, nc->pos,
1240*260e9a87SYuri Pankov mdoc_macronames[nc->tok]);
1241*260e9a87SYuri Pankov mdoc_node_relink(mdoc, nc);
1242698f87a4SGarrett D'Amore } else if (0 == n->norm->Bl.comp &&
1243698f87a4SGarrett D'Amore LIST_column != n->norm->Bl.type) {
1244*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP,
1245*260e9a87SYuri Pankov mdoc->parse, nc->line, nc->pos,
1246*260e9a87SYuri Pankov "%s before It",
1247*260e9a87SYuri Pankov mdoc_macronames[nc->tok]);
1248698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, nc);
1249698f87a4SGarrett D'Amore } else
1250698f87a4SGarrett D'Amore break;
1251698f87a4SGarrett D'Amore nc = ni->body->last;
1252698f87a4SGarrett D'Amore }
1253698f87a4SGarrett D'Amore }
125495c635efSGarrett D'Amore }
125595c635efSGarrett D'Amore
125695c635efSGarrett D'Amore /*
1257*260e9a87SYuri Pankov * If the argument of -offset or -width is a macro,
1258*260e9a87SYuri Pankov * replace it with the associated default width.
125995c635efSGarrett D'Amore */
1260*260e9a87SYuri Pankov void
rewrite_macro2len(char ** arg)1261*260e9a87SYuri Pankov rewrite_macro2len(char **arg)
1262*260e9a87SYuri Pankov {
1263*260e9a87SYuri Pankov size_t width;
1264*260e9a87SYuri Pankov enum mdoct tok;
126595c635efSGarrett D'Amore
1266*260e9a87SYuri Pankov if (*arg == NULL)
1267*260e9a87SYuri Pankov return;
1268*260e9a87SYuri Pankov else if ( ! strcmp(*arg, "Ds"))
126995c635efSGarrett D'Amore width = 6;
1270*260e9a87SYuri Pankov else if ((tok = mdoc_hash_find(*arg)) == MDOC_MAX)
1271*260e9a87SYuri Pankov return;
1272*260e9a87SYuri Pankov else
1273*260e9a87SYuri Pankov width = macro2len(tok);
1274*260e9a87SYuri Pankov
1275*260e9a87SYuri Pankov free(*arg);
1276*260e9a87SYuri Pankov mandoc_asprintf(arg, "%zun", width);
127795c635efSGarrett D'Amore }
127895c635efSGarrett D'Amore
1279*260e9a87SYuri Pankov static void
post_bl_block_tag(POST_ARGS)128095c635efSGarrett D'Amore post_bl_block_tag(POST_ARGS)
128195c635efSGarrett D'Amore {
128295c635efSGarrett D'Amore struct mdoc_node *n, *nn;
128395c635efSGarrett D'Amore size_t sz, ssz;
128495c635efSGarrett D'Amore int i;
1285*260e9a87SYuri Pankov char buf[24];
128695c635efSGarrett D'Amore
128795c635efSGarrett D'Amore /*
128895c635efSGarrett D'Amore * Calculate the -width for a `Bl -tag' list if it hasn't been
128995c635efSGarrett D'Amore * provided. Uses the first head macro. NOTE AGAIN: this is
129095c635efSGarrett D'Amore * ONLY if the -width argument has NOT been provided. See
1291*260e9a87SYuri Pankov * rewrite_macro2len() for converting the -width string.
129295c635efSGarrett D'Amore */
129395c635efSGarrett D'Amore
129495c635efSGarrett D'Amore sz = 10;
129595c635efSGarrett D'Amore n = mdoc->last;
129695c635efSGarrett D'Amore
129795c635efSGarrett D'Amore for (nn = n->body->child; nn; nn = nn->next) {
129895c635efSGarrett D'Amore if (MDOC_It != nn->tok)
129995c635efSGarrett D'Amore continue;
130095c635efSGarrett D'Amore
130195c635efSGarrett D'Amore assert(MDOC_BLOCK == nn->type);
130295c635efSGarrett D'Amore nn = nn->head->child;
130395c635efSGarrett D'Amore
130495c635efSGarrett D'Amore if (nn == NULL)
130595c635efSGarrett D'Amore break;
130695c635efSGarrett D'Amore
130795c635efSGarrett D'Amore if (MDOC_TEXT == nn->type) {
130895c635efSGarrett D'Amore sz = strlen(nn->string) + 1;
130995c635efSGarrett D'Amore break;
131095c635efSGarrett D'Amore }
131195c635efSGarrett D'Amore
131295c635efSGarrett D'Amore if (0 != (ssz = macro2len(nn->tok)))
131395c635efSGarrett D'Amore sz = ssz;
131495c635efSGarrett D'Amore
131595c635efSGarrett D'Amore break;
131695c635efSGarrett D'Amore }
131795c635efSGarrett D'Amore
131895c635efSGarrett D'Amore /* Defaults to ten ens. */
131995c635efSGarrett D'Amore
1320*260e9a87SYuri Pankov (void)snprintf(buf, sizeof(buf), "%un", (unsigned int)sz);
132195c635efSGarrett D'Amore
132295c635efSGarrett D'Amore /*
132395c635efSGarrett D'Amore * We have to dynamically add this to the macro's argument list.
132495c635efSGarrett D'Amore * We're guaranteed that a MDOC_Width doesn't already exist.
132595c635efSGarrett D'Amore */
132695c635efSGarrett D'Amore
132795c635efSGarrett D'Amore assert(n->args);
132895c635efSGarrett D'Amore i = (int)(n->args->argc)++;
132995c635efSGarrett D'Amore
1330*260e9a87SYuri Pankov n->args->argv = mandoc_reallocarray(n->args->argv,
1331*260e9a87SYuri Pankov n->args->argc, sizeof(struct mdoc_argv));
133295c635efSGarrett D'Amore
133395c635efSGarrett D'Amore n->args->argv[i].arg = MDOC_Width;
133495c635efSGarrett D'Amore n->args->argv[i].line = n->line;
133595c635efSGarrett D'Amore n->args->argv[i].pos = n->pos;
133695c635efSGarrett D'Amore n->args->argv[i].sz = 1;
133795c635efSGarrett D'Amore n->args->argv[i].value = mandoc_malloc(sizeof(char *));
133895c635efSGarrett D'Amore n->args->argv[i].value[0] = mandoc_strdup(buf);
133995c635efSGarrett D'Amore
134095c635efSGarrett D'Amore /* Set our width! */
134195c635efSGarrett D'Amore n->norm->Bl.width = n->args->argv[i].value[0];
134295c635efSGarrett D'Amore }
134395c635efSGarrett D'Amore
1344*260e9a87SYuri Pankov static void
post_bl_head(POST_ARGS)134595c635efSGarrett D'Amore post_bl_head(POST_ARGS)
134695c635efSGarrett D'Amore {
1347*260e9a87SYuri Pankov struct mdoc_node *nbl, *nh, *nch, *nnext;
1348*260e9a87SYuri Pankov struct mdoc_argv *argv;
134995c635efSGarrett D'Amore int i, j;
135095c635efSGarrett D'Amore
1351*260e9a87SYuri Pankov nh = mdoc->last;
1352*260e9a87SYuri Pankov
1353*260e9a87SYuri Pankov if (nh->norm->Bl.type != LIST_column) {
1354*260e9a87SYuri Pankov if ((nch = nh->child) == NULL)
1355*260e9a87SYuri Pankov return;
1356*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
1357*260e9a87SYuri Pankov nch->line, nch->pos, "Bl ... %s", nch->string);
1358*260e9a87SYuri Pankov while (nch != NULL) {
1359*260e9a87SYuri Pankov mdoc_node_delete(mdoc, nch);
1360*260e9a87SYuri Pankov nch = nh->child;
1361*260e9a87SYuri Pankov }
1362*260e9a87SYuri Pankov return;
1363*260e9a87SYuri Pankov }
136495c635efSGarrett D'Amore
136595c635efSGarrett D'Amore /*
1366*260e9a87SYuri Pankov * Append old-style lists, where the column width specifiers
136795c635efSGarrett D'Amore * trail as macro parameters, to the new-style ("normal-form")
136895c635efSGarrett D'Amore * lists where they're argument values following -column.
136995c635efSGarrett D'Amore */
137095c635efSGarrett D'Amore
1371*260e9a87SYuri Pankov if (nh->child == NULL)
1372*260e9a87SYuri Pankov return;
137395c635efSGarrett D'Amore
1374*260e9a87SYuri Pankov nbl = nh->parent;
1375*260e9a87SYuri Pankov for (j = 0; j < (int)nbl->args->argc; j++)
1376*260e9a87SYuri Pankov if (nbl->args->argv[j].arg == MDOC_Column)
137795c635efSGarrett D'Amore break;
137895c635efSGarrett D'Amore
1379*260e9a87SYuri Pankov assert(j < (int)nbl->args->argc);
138095c635efSGarrett D'Amore
138195c635efSGarrett D'Amore /*
138295c635efSGarrett D'Amore * Accommodate for new-style groff column syntax. Shuffle the
138395c635efSGarrett D'Amore * child nodes, all of which must be TEXT, as arguments for the
138495c635efSGarrett D'Amore * column field. Then, delete the head children.
138595c635efSGarrett D'Amore */
138695c635efSGarrett D'Amore
1387*260e9a87SYuri Pankov argv = nbl->args->argv + j;
1388*260e9a87SYuri Pankov i = argv->sz;
1389*260e9a87SYuri Pankov argv->sz += nh->nchild;
1390*260e9a87SYuri Pankov argv->value = mandoc_reallocarray(argv->value,
1391*260e9a87SYuri Pankov argv->sz, sizeof(char *));
139295c635efSGarrett D'Amore
1393*260e9a87SYuri Pankov nh->norm->Bl.ncols = argv->sz;
1394*260e9a87SYuri Pankov nh->norm->Bl.cols = (void *)argv->value;
139595c635efSGarrett D'Amore
1396*260e9a87SYuri Pankov for (nch = nh->child; nch != NULL; nch = nnext) {
1397*260e9a87SYuri Pankov argv->value[i++] = nch->string;
1398*260e9a87SYuri Pankov nch->string = NULL;
1399*260e9a87SYuri Pankov nnext = nch->next;
1400*260e9a87SYuri Pankov mdoc_node_delete(NULL, nch);
1401*260e9a87SYuri Pankov }
1402*260e9a87SYuri Pankov nh->nchild = 0;
1403*260e9a87SYuri Pankov nh->child = NULL;
140495c635efSGarrett D'Amore }
140595c635efSGarrett D'Amore
1406*260e9a87SYuri Pankov static void
post_bl(POST_ARGS)140795c635efSGarrett D'Amore post_bl(POST_ARGS)
140895c635efSGarrett D'Amore {
1409698f87a4SGarrett D'Amore struct mdoc_node *nparent, *nprev; /* of the Bl block */
1410698f87a4SGarrett D'Amore struct mdoc_node *nblock, *nbody; /* of the Bl */
1411698f87a4SGarrett D'Amore struct mdoc_node *nchild, *nnext; /* of the Bl body */
141295c635efSGarrett D'Amore
1413698f87a4SGarrett D'Amore nbody = mdoc->last;
1414698f87a4SGarrett D'Amore switch (nbody->type) {
1415*260e9a87SYuri Pankov case MDOC_BLOCK:
1416*260e9a87SYuri Pankov post_bl_block(mdoc);
1417*260e9a87SYuri Pankov return;
1418*260e9a87SYuri Pankov case MDOC_HEAD:
1419*260e9a87SYuri Pankov post_bl_head(mdoc);
1420*260e9a87SYuri Pankov return;
1421*260e9a87SYuri Pankov case MDOC_BODY:
142295c635efSGarrett D'Amore break;
1423698f87a4SGarrett D'Amore default:
1424*260e9a87SYuri Pankov return;
142595c635efSGarrett D'Amore }
142695c635efSGarrett D'Amore
1427698f87a4SGarrett D'Amore nchild = nbody->child;
1428*260e9a87SYuri Pankov if (nchild == NULL) {
1429*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY, mdoc->parse,
1430*260e9a87SYuri Pankov nbody->line, nbody->pos, "Bl");
1431*260e9a87SYuri Pankov return;
1432*260e9a87SYuri Pankov }
1433*260e9a87SYuri Pankov while (nchild != NULL) {
1434*260e9a87SYuri Pankov if (nchild->tok == MDOC_It ||
1435*260e9a87SYuri Pankov (nchild->tok == MDOC_Sm &&
1436*260e9a87SYuri Pankov nchild->next != NULL &&
1437*260e9a87SYuri Pankov nchild->next->tok == MDOC_It)) {
1438698f87a4SGarrett D'Amore nchild = nchild->next;
1439698f87a4SGarrett D'Amore continue;
1440698f87a4SGarrett D'Amore }
1441698f87a4SGarrett D'Amore
1442*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BL_MOVE, mdoc->parse,
1443*260e9a87SYuri Pankov nchild->line, nchild->pos,
1444*260e9a87SYuri Pankov mdoc_macronames[nchild->tok]);
1445698f87a4SGarrett D'Amore
1446698f87a4SGarrett D'Amore /*
1447698f87a4SGarrett D'Amore * Move the node out of the Bl block.
1448698f87a4SGarrett D'Amore * First, collect all required node pointers.
1449698f87a4SGarrett D'Amore */
1450698f87a4SGarrett D'Amore
1451698f87a4SGarrett D'Amore nblock = nbody->parent;
1452698f87a4SGarrett D'Amore nprev = nblock->prev;
1453698f87a4SGarrett D'Amore nparent = nblock->parent;
1454698f87a4SGarrett D'Amore nnext = nchild->next;
1455698f87a4SGarrett D'Amore
1456698f87a4SGarrett D'Amore /*
1457698f87a4SGarrett D'Amore * Unlink this child.
1458698f87a4SGarrett D'Amore */
1459698f87a4SGarrett D'Amore
1460698f87a4SGarrett D'Amore assert(NULL == nchild->prev);
1461698f87a4SGarrett D'Amore if (0 == --nbody->nchild) {
1462698f87a4SGarrett D'Amore nbody->child = NULL;
1463698f87a4SGarrett D'Amore nbody->last = NULL;
1464698f87a4SGarrett D'Amore assert(NULL == nnext);
1465698f87a4SGarrett D'Amore } else {
1466698f87a4SGarrett D'Amore nbody->child = nnext;
1467698f87a4SGarrett D'Amore nnext->prev = NULL;
1468698f87a4SGarrett D'Amore }
1469698f87a4SGarrett D'Amore
1470698f87a4SGarrett D'Amore /*
1471698f87a4SGarrett D'Amore * Relink this child.
1472698f87a4SGarrett D'Amore */
1473698f87a4SGarrett D'Amore
1474698f87a4SGarrett D'Amore nchild->parent = nparent;
1475698f87a4SGarrett D'Amore nchild->prev = nprev;
1476698f87a4SGarrett D'Amore nchild->next = nblock;
1477698f87a4SGarrett D'Amore
1478698f87a4SGarrett D'Amore nblock->prev = nchild;
1479698f87a4SGarrett D'Amore nparent->nchild++;
1480698f87a4SGarrett D'Amore if (NULL == nprev)
1481698f87a4SGarrett D'Amore nparent->child = nchild;
1482698f87a4SGarrett D'Amore else
1483698f87a4SGarrett D'Amore nprev->next = nchild;
1484698f87a4SGarrett D'Amore
1485698f87a4SGarrett D'Amore nchild = nnext;
148695c635efSGarrett D'Amore }
148795c635efSGarrett D'Amore }
148895c635efSGarrett D'Amore
1489*260e9a87SYuri Pankov static void
post_bk(POST_ARGS)1490*260e9a87SYuri Pankov post_bk(POST_ARGS)
149195c635efSGarrett D'Amore {
149295c635efSGarrett D'Amore struct mdoc_node *n;
149395c635efSGarrett D'Amore
1494*260e9a87SYuri Pankov n = mdoc->last;
149595c635efSGarrett D'Amore
1496*260e9a87SYuri Pankov if (n->type == MDOC_BLOCK && n->body->child == NULL) {
1497*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_EMPTY,
1498*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Bk");
1499*260e9a87SYuri Pankov mdoc_node_delete(mdoc, n);
1500*260e9a87SYuri Pankov }
150195c635efSGarrett D'Amore }
150295c635efSGarrett D'Amore
1503*260e9a87SYuri Pankov static void
post_sm(struct mdoc * mdoc)1504*260e9a87SYuri Pankov post_sm(struct mdoc *mdoc)
1505*260e9a87SYuri Pankov {
1506*260e9a87SYuri Pankov struct mdoc_node *nch;
1507*260e9a87SYuri Pankov
1508*260e9a87SYuri Pankov nch = mdoc->last->child;
1509*260e9a87SYuri Pankov
1510*260e9a87SYuri Pankov if (nch == NULL) {
1511*260e9a87SYuri Pankov mdoc->flags ^= MDOC_SMOFF;
1512*260e9a87SYuri Pankov return;
1513*260e9a87SYuri Pankov }
1514*260e9a87SYuri Pankov
1515*260e9a87SYuri Pankov assert(nch->type == MDOC_TEXT);
1516*260e9a87SYuri Pankov
1517*260e9a87SYuri Pankov if ( ! strcmp(nch->string, "on")) {
1518*260e9a87SYuri Pankov mdoc->flags &= ~MDOC_SMOFF;
1519*260e9a87SYuri Pankov return;
1520*260e9a87SYuri Pankov }
1521*260e9a87SYuri Pankov if ( ! strcmp(nch->string, "off")) {
1522*260e9a87SYuri Pankov mdoc->flags |= MDOC_SMOFF;
1523*260e9a87SYuri Pankov return;
1524*260e9a87SYuri Pankov }
1525*260e9a87SYuri Pankov
1526*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SM_BAD,
1527*260e9a87SYuri Pankov mdoc->parse, nch->line, nch->pos,
1528*260e9a87SYuri Pankov "%s %s", mdoc_macronames[mdoc->last->tok], nch->string);
1529*260e9a87SYuri Pankov mdoc_node_relink(mdoc, nch);
1530*260e9a87SYuri Pankov return;
1531*260e9a87SYuri Pankov }
1532*260e9a87SYuri Pankov
1533*260e9a87SYuri Pankov static void
post_root(POST_ARGS)1534*260e9a87SYuri Pankov post_root(POST_ARGS)
1535*260e9a87SYuri Pankov {
1536*260e9a87SYuri Pankov struct mdoc_node *n;
1537*260e9a87SYuri Pankov
1538*260e9a87SYuri Pankov /* Add missing prologue data. */
1539*260e9a87SYuri Pankov
1540*260e9a87SYuri Pankov if (mdoc->meta.date == NULL)
1541*260e9a87SYuri Pankov mdoc->meta.date = mdoc->quick ?
1542*260e9a87SYuri Pankov mandoc_strdup("") :
1543*260e9a87SYuri Pankov mandoc_normdate(mdoc->parse, NULL, 0, 0);
1544*260e9a87SYuri Pankov
1545*260e9a87SYuri Pankov if (mdoc->meta.title == NULL) {
1546*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DT_NOTITLE,
1547*260e9a87SYuri Pankov mdoc->parse, 0, 0, "EOF");
1548*260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup("UNTITLED");
1549*260e9a87SYuri Pankov }
1550*260e9a87SYuri Pankov
1551*260e9a87SYuri Pankov if (mdoc->meta.vol == NULL)
1552*260e9a87SYuri Pankov mdoc->meta.vol = mandoc_strdup("LOCAL");
1553*260e9a87SYuri Pankov
1554*260e9a87SYuri Pankov if (mdoc->meta.os == NULL) {
1555*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_OS_MISSING,
1556*260e9a87SYuri Pankov mdoc->parse, 0, 0, NULL);
1557*260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup("");
1558*260e9a87SYuri Pankov }
155995c635efSGarrett D'Amore
156095c635efSGarrett D'Amore /* Check that we begin with a proper `Sh'. */
156195c635efSGarrett D'Amore
1562*260e9a87SYuri Pankov n = mdoc->first->child;
1563*260e9a87SYuri Pankov while (n != NULL && mdoc_macros[n->tok].flags & MDOC_PROLOGUE)
1564*260e9a87SYuri Pankov n = n->next;
1565*260e9a87SYuri Pankov
1566*260e9a87SYuri Pankov if (n == NULL)
1567*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DOC_EMPTY, mdoc->parse, 0, 0, NULL);
1568*260e9a87SYuri Pankov else if (n->tok != MDOC_Sh)
1569*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_SEC_BEFORE, mdoc->parse,
1570*260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]);
157195c635efSGarrett D'Amore }
157295c635efSGarrett D'Amore
1573*260e9a87SYuri Pankov static void
post_st(POST_ARGS)157495c635efSGarrett D'Amore post_st(POST_ARGS)
157595c635efSGarrett D'Amore {
1576*260e9a87SYuri Pankov struct mdoc_node *n, *nch;
157795c635efSGarrett D'Amore const char *p;
157895c635efSGarrett D'Amore
1579*260e9a87SYuri Pankov n = mdoc->last;
1580*260e9a87SYuri Pankov nch = n->child;
158195c635efSGarrett D'Amore
1582*260e9a87SYuri Pankov assert(MDOC_TEXT == nch->type);
158395c635efSGarrett D'Amore
1584*260e9a87SYuri Pankov if (NULL == (p = mdoc_a2st(nch->string))) {
1585*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ST_BAD, mdoc->parse,
1586*260e9a87SYuri Pankov nch->line, nch->pos, "St %s", nch->string);
1587*260e9a87SYuri Pankov mdoc_node_delete(mdoc, n);
158895c635efSGarrett D'Amore } else {
1589*260e9a87SYuri Pankov free(nch->string);
1590*260e9a87SYuri Pankov nch->string = mandoc_strdup(p);
1591*260e9a87SYuri Pankov }
159295c635efSGarrett D'Amore }
159395c635efSGarrett D'Amore
1594*260e9a87SYuri Pankov static void
post_rs(POST_ARGS)159595c635efSGarrett D'Amore post_rs(POST_ARGS)
159695c635efSGarrett D'Amore {
1597*260e9a87SYuri Pankov struct mdoc_node *np, *nch, *next, *prev;
159895c635efSGarrett D'Amore int i, j;
159995c635efSGarrett D'Amore
1600*260e9a87SYuri Pankov np = mdoc->last;
1601*260e9a87SYuri Pankov
1602*260e9a87SYuri Pankov if (np->type != MDOC_BODY)
1603*260e9a87SYuri Pankov return;
1604*260e9a87SYuri Pankov
1605*260e9a87SYuri Pankov if (np->child == NULL) {
1606*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_RS_EMPTY, mdoc->parse,
1607*260e9a87SYuri Pankov np->line, np->pos, "Rs");
1608*260e9a87SYuri Pankov return;
160995c635efSGarrett D'Amore }
161095c635efSGarrett D'Amore
161195c635efSGarrett D'Amore /*
161295c635efSGarrett D'Amore * The full `Rs' block needs special handling to order the
161395c635efSGarrett D'Amore * sub-elements according to `rsord'. Pick through each element
1614*260e9a87SYuri Pankov * and correctly order it. This is an insertion sort.
161595c635efSGarrett D'Amore */
161695c635efSGarrett D'Amore
161795c635efSGarrett D'Amore next = NULL;
1618*260e9a87SYuri Pankov for (nch = np->child->next; nch != NULL; nch = next) {
1619*260e9a87SYuri Pankov /* Determine order number of this child. */
162095c635efSGarrett D'Amore for (i = 0; i < RSORD_MAX; i++)
1621*260e9a87SYuri Pankov if (rsord[i] == nch->tok)
162295c635efSGarrett D'Amore break;
162395c635efSGarrett D'Amore
1624*260e9a87SYuri Pankov if (i == RSORD_MAX) {
1625*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_RS_BAD,
1626*260e9a87SYuri Pankov mdoc->parse, nch->line, nch->pos,
1627*260e9a87SYuri Pankov mdoc_macronames[nch->tok]);
1628*260e9a87SYuri Pankov i = -1;
1629*260e9a87SYuri Pankov } else if (nch->tok == MDOC__J || nch->tok == MDOC__B)
1630*260e9a87SYuri Pankov np->norm->Rs.quote_T++;
1631*260e9a87SYuri Pankov
163295c635efSGarrett D'Amore /*
1633*260e9a87SYuri Pankov * Remove this child from the chain. This somewhat
163495c635efSGarrett D'Amore * repeats mdoc_node_unlink(), but since we're
163595c635efSGarrett D'Amore * just re-ordering, there's no need for the
163695c635efSGarrett D'Amore * full unlink process.
163795c635efSGarrett D'Amore */
163895c635efSGarrett D'Amore
1639*260e9a87SYuri Pankov if ((next = nch->next) != NULL)
1640*260e9a87SYuri Pankov next->prev = nch->prev;
164195c635efSGarrett D'Amore
1642*260e9a87SYuri Pankov if ((prev = nch->prev) != NULL)
1643*260e9a87SYuri Pankov prev->next = nch->next;
164495c635efSGarrett D'Amore
1645*260e9a87SYuri Pankov nch->prev = nch->next = NULL;
164695c635efSGarrett D'Amore
164795c635efSGarrett D'Amore /*
164895c635efSGarrett D'Amore * Scan back until we reach a node that's
1649*260e9a87SYuri Pankov * to be ordered before this child.
165095c635efSGarrett D'Amore */
165195c635efSGarrett D'Amore
165295c635efSGarrett D'Amore for ( ; prev ; prev = prev->prev) {
165395c635efSGarrett D'Amore /* Determine order of `prev'. */
165495c635efSGarrett D'Amore for (j = 0; j < RSORD_MAX; j++)
165595c635efSGarrett D'Amore if (rsord[j] == prev->tok)
165695c635efSGarrett D'Amore break;
1657*260e9a87SYuri Pankov if (j == RSORD_MAX)
1658*260e9a87SYuri Pankov j = -1;
165995c635efSGarrett D'Amore
166095c635efSGarrett D'Amore if (j <= i)
166195c635efSGarrett D'Amore break;
166295c635efSGarrett D'Amore }
166395c635efSGarrett D'Amore
166495c635efSGarrett D'Amore /*
1665*260e9a87SYuri Pankov * Set this child back into its correct place
1666*260e9a87SYuri Pankov * in front of the `prev' node.
166795c635efSGarrett D'Amore */
166895c635efSGarrett D'Amore
1669*260e9a87SYuri Pankov nch->prev = prev;
167095c635efSGarrett D'Amore
1671*260e9a87SYuri Pankov if (prev == NULL) {
1672*260e9a87SYuri Pankov np->child->prev = nch;
1673*260e9a87SYuri Pankov nch->next = np->child;
1674*260e9a87SYuri Pankov np->child = nch;
167595c635efSGarrett D'Amore } else {
1676*260e9a87SYuri Pankov if (prev->next)
1677*260e9a87SYuri Pankov prev->next->prev = nch;
1678*260e9a87SYuri Pankov nch->next = prev->next;
1679*260e9a87SYuri Pankov prev->next = nch;
168095c635efSGarrett D'Amore }
168195c635efSGarrett D'Amore }
168295c635efSGarrett D'Amore }
168395c635efSGarrett D'Amore
1684698f87a4SGarrett D'Amore /*
1685698f87a4SGarrett D'Amore * For some arguments of some macros,
1686698f87a4SGarrett D'Amore * convert all breakable hyphens into ASCII_HYPH.
1687698f87a4SGarrett D'Amore */
1688*260e9a87SYuri Pankov static void
post_hyph(POST_ARGS)1689698f87a4SGarrett D'Amore post_hyph(POST_ARGS)
1690698f87a4SGarrett D'Amore {
1691*260e9a87SYuri Pankov struct mdoc_node *nch;
1692698f87a4SGarrett D'Amore char *cp;
1693698f87a4SGarrett D'Amore
1694*260e9a87SYuri Pankov for (nch = mdoc->last->child; nch != NULL; nch = nch->next) {
1695*260e9a87SYuri Pankov if (nch->type != MDOC_TEXT)
1696698f87a4SGarrett D'Amore continue;
1697698f87a4SGarrett D'Amore cp = nch->string;
1698*260e9a87SYuri Pankov if (*cp == '\0')
1699698f87a4SGarrett D'Amore continue;
1700*260e9a87SYuri Pankov while (*(++cp) != '\0')
1701*260e9a87SYuri Pankov if (*cp == '-' &&
1702698f87a4SGarrett D'Amore isalpha((unsigned char)cp[-1]) &&
1703698f87a4SGarrett D'Amore isalpha((unsigned char)cp[1]))
1704698f87a4SGarrett D'Amore *cp = ASCII_HYPH;
1705698f87a4SGarrett D'Amore }
1706698f87a4SGarrett D'Amore }
1707698f87a4SGarrett D'Amore
1708*260e9a87SYuri Pankov static void
post_ns(POST_ARGS)170995c635efSGarrett D'Amore post_ns(POST_ARGS)
171095c635efSGarrett D'Amore {
171195c635efSGarrett D'Amore
171295c635efSGarrett D'Amore if (MDOC_LINE & mdoc->last->flags)
1713*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NS_SKIP, mdoc->parse,
1714*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL);
171595c635efSGarrett D'Amore }
171695c635efSGarrett D'Amore
1717*260e9a87SYuri Pankov static void
post_sh(POST_ARGS)171895c635efSGarrett D'Amore post_sh(POST_ARGS)
171995c635efSGarrett D'Amore {
172095c635efSGarrett D'Amore
1721*260e9a87SYuri Pankov post_ignpar(mdoc);
172295c635efSGarrett D'Amore
1723*260e9a87SYuri Pankov switch (mdoc->last->type) {
1724*260e9a87SYuri Pankov case MDOC_HEAD:
1725*260e9a87SYuri Pankov post_sh_head(mdoc);
1726*260e9a87SYuri Pankov break;
1727*260e9a87SYuri Pankov case MDOC_BODY:
1728*260e9a87SYuri Pankov switch (mdoc->lastsec) {
1729*260e9a87SYuri Pankov case SEC_NAME:
1730*260e9a87SYuri Pankov post_sh_name(mdoc);
1731*260e9a87SYuri Pankov break;
1732*260e9a87SYuri Pankov case SEC_SEE_ALSO:
1733*260e9a87SYuri Pankov post_sh_see_also(mdoc);
1734*260e9a87SYuri Pankov break;
1735*260e9a87SYuri Pankov case SEC_AUTHORS:
1736*260e9a87SYuri Pankov post_sh_authors(mdoc);
1737*260e9a87SYuri Pankov break;
1738*260e9a87SYuri Pankov default:
1739*260e9a87SYuri Pankov break;
1740*260e9a87SYuri Pankov }
1741*260e9a87SYuri Pankov break;
1742*260e9a87SYuri Pankov default:
1743*260e9a87SYuri Pankov break;
1744*260e9a87SYuri Pankov }
174595c635efSGarrett D'Amore }
174695c635efSGarrett D'Amore
1747*260e9a87SYuri Pankov static void
post_sh_name(POST_ARGS)1748*260e9a87SYuri Pankov post_sh_name(POST_ARGS)
174995c635efSGarrett D'Amore {
175095c635efSGarrett D'Amore struct mdoc_node *n;
1751*260e9a87SYuri Pankov int hasnm, hasnd;
175295c635efSGarrett D'Amore
1753*260e9a87SYuri Pankov hasnm = hasnd = 0;
175495c635efSGarrett D'Amore
1755*260e9a87SYuri Pankov for (n = mdoc->last->child; n != NULL; n = n->next) {
1756*260e9a87SYuri Pankov switch (n->tok) {
1757*260e9a87SYuri Pankov case MDOC_Nm:
1758*260e9a87SYuri Pankov hasnm = 1;
1759*260e9a87SYuri Pankov break;
1760*260e9a87SYuri Pankov case MDOC_Nd:
1761*260e9a87SYuri Pankov hasnd = 1;
1762*260e9a87SYuri Pankov if (n->next != NULL)
1763*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_ND,
1764*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, NULL);
1765*260e9a87SYuri Pankov break;
1766*260e9a87SYuri Pankov case MDOC_MAX:
1767*260e9a87SYuri Pankov if (hasnm)
1768*260e9a87SYuri Pankov break;
1769*260e9a87SYuri Pankov /* FALLTHROUGH */
1770*260e9a87SYuri Pankov default:
1771*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_BAD, mdoc->parse,
1772*260e9a87SYuri Pankov n->line, n->pos, mdoc_macronames[n->tok]);
1773*260e9a87SYuri Pankov break;
1774*260e9a87SYuri Pankov }
177595c635efSGarrett D'Amore }
177695c635efSGarrett D'Amore
1777*260e9a87SYuri Pankov if ( ! hasnm)
1778*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_NONM, mdoc->parse,
1779*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL);
1780*260e9a87SYuri Pankov if ( ! hasnd)
1781*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_NAMESEC_NOND, mdoc->parse,
1782*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL);
178395c635efSGarrett D'Amore }
178495c635efSGarrett D'Amore
1785*260e9a87SYuri Pankov static void
post_sh_see_also(POST_ARGS)1786*260e9a87SYuri Pankov post_sh_see_also(POST_ARGS)
1787*260e9a87SYuri Pankov {
1788*260e9a87SYuri Pankov const struct mdoc_node *n;
1789*260e9a87SYuri Pankov const char *name, *sec;
1790*260e9a87SYuri Pankov const char *lastname, *lastsec, *lastpunct;
1791*260e9a87SYuri Pankov int cmp;
179295c635efSGarrett D'Amore
1793*260e9a87SYuri Pankov n = mdoc->last->child;
1794*260e9a87SYuri Pankov lastname = lastsec = lastpunct = NULL;
1795*260e9a87SYuri Pankov while (n != NULL) {
1796*260e9a87SYuri Pankov if (n->tok != MDOC_Xr || n->nchild < 2)
1797*260e9a87SYuri Pankov break;
1798*260e9a87SYuri Pankov
1799*260e9a87SYuri Pankov /* Process one .Xr node. */
1800*260e9a87SYuri Pankov
1801*260e9a87SYuri Pankov name = n->child->string;
1802*260e9a87SYuri Pankov sec = n->child->next->string;
1803*260e9a87SYuri Pankov if (lastsec != NULL) {
1804*260e9a87SYuri Pankov if (lastpunct[0] != ',' || lastpunct[1] != '\0')
1805*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_PUNCT,
1806*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos,
1807*260e9a87SYuri Pankov "%s before %s(%s)", lastpunct,
1808*260e9a87SYuri Pankov name, sec);
1809*260e9a87SYuri Pankov cmp = strcmp(lastsec, sec);
1810*260e9a87SYuri Pankov if (cmp > 0)
1811*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_ORDER,
1812*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos,
1813*260e9a87SYuri Pankov "%s(%s) after %s(%s)", name,
1814*260e9a87SYuri Pankov sec, lastname, lastsec);
1815*260e9a87SYuri Pankov else if (cmp == 0 &&
1816*260e9a87SYuri Pankov strcasecmp(lastname, name) > 0)
1817*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_ORDER,
1818*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos,
1819*260e9a87SYuri Pankov "%s after %s", name, lastname);
1820*260e9a87SYuri Pankov }
1821*260e9a87SYuri Pankov lastname = name;
1822*260e9a87SYuri Pankov lastsec = sec;
1823*260e9a87SYuri Pankov
1824*260e9a87SYuri Pankov /* Process the following node. */
1825*260e9a87SYuri Pankov
1826*260e9a87SYuri Pankov n = n->next;
1827*260e9a87SYuri Pankov if (n == NULL)
1828*260e9a87SYuri Pankov break;
1829*260e9a87SYuri Pankov if (n->tok == MDOC_Xr) {
1830*260e9a87SYuri Pankov lastpunct = "none";
1831*260e9a87SYuri Pankov continue;
1832*260e9a87SYuri Pankov }
1833*260e9a87SYuri Pankov if (n->type != MDOC_TEXT)
1834*260e9a87SYuri Pankov break;
1835*260e9a87SYuri Pankov for (name = n->string; *name != '\0'; name++)
1836*260e9a87SYuri Pankov if (isalpha((const unsigned char)*name))
1837*260e9a87SYuri Pankov return;
1838*260e9a87SYuri Pankov lastpunct = n->string;
1839*260e9a87SYuri Pankov if (n->next == NULL)
1840*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_XR_PUNCT, mdoc->parse,
1841*260e9a87SYuri Pankov n->line, n->pos, "%s after %s(%s)",
1842*260e9a87SYuri Pankov lastpunct, lastname, lastsec);
1843*260e9a87SYuri Pankov n = n->next;
1844*260e9a87SYuri Pankov }
184595c635efSGarrett D'Amore }
184695c635efSGarrett D'Amore
184795c635efSGarrett D'Amore static int
child_an(const struct mdoc_node * n)1848*260e9a87SYuri Pankov child_an(const struct mdoc_node *n)
1849*260e9a87SYuri Pankov {
1850*260e9a87SYuri Pankov
1851*260e9a87SYuri Pankov for (n = n->child; n != NULL; n = n->next)
1852*260e9a87SYuri Pankov if ((n->tok == MDOC_An && n->nchild) || child_an(n))
1853*260e9a87SYuri Pankov return(1);
1854*260e9a87SYuri Pankov return(0);
1855*260e9a87SYuri Pankov }
1856*260e9a87SYuri Pankov
1857*260e9a87SYuri Pankov static void
post_sh_authors(POST_ARGS)1858*260e9a87SYuri Pankov post_sh_authors(POST_ARGS)
1859*260e9a87SYuri Pankov {
1860*260e9a87SYuri Pankov
1861*260e9a87SYuri Pankov if ( ! child_an(mdoc->last))
1862*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_AN_MISSING, mdoc->parse,
1863*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos, NULL);
1864*260e9a87SYuri Pankov }
1865*260e9a87SYuri Pankov
1866*260e9a87SYuri Pankov static void
post_sh_head(POST_ARGS)186795c635efSGarrett D'Amore post_sh_head(POST_ARGS)
186895c635efSGarrett D'Amore {
186995c635efSGarrett D'Amore struct mdoc_node *n;
1870*260e9a87SYuri Pankov const char *goodsec;
1871*260e9a87SYuri Pankov char *secname;
187295c635efSGarrett D'Amore enum mdoc_sec sec;
187395c635efSGarrett D'Amore
187495c635efSGarrett D'Amore /*
187595c635efSGarrett D'Amore * Process a new section. Sections are either "named" or
187695c635efSGarrett D'Amore * "custom". Custom sections are user-defined, while named ones
187795c635efSGarrett D'Amore * follow a conventional order and may only appear in certain
187895c635efSGarrett D'Amore * manual sections.
187995c635efSGarrett D'Amore */
188095c635efSGarrett D'Amore
1881*260e9a87SYuri Pankov secname = NULL;
188295c635efSGarrett D'Amore sec = SEC_CUSTOM;
1883*260e9a87SYuri Pankov mdoc_deroff(&secname, mdoc->last);
1884*260e9a87SYuri Pankov sec = NULL == secname ? SEC_CUSTOM : a2sec(secname);
188595c635efSGarrett D'Amore
188695c635efSGarrett D'Amore /* The NAME should be first. */
188795c635efSGarrett D'Amore
188895c635efSGarrett D'Amore if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1889*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_NAMESEC_FIRST, mdoc->parse,
1890*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos,
1891*260e9a87SYuri Pankov "Sh %s", secname);
189295c635efSGarrett D'Amore
189395c635efSGarrett D'Amore /* The SYNOPSIS gets special attention in other areas. */
189495c635efSGarrett D'Amore
1895698f87a4SGarrett D'Amore if (SEC_SYNOPSIS == sec) {
1896698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 1, '=');
189795c635efSGarrett D'Amore mdoc->flags |= MDOC_SYNOPSIS;
1898698f87a4SGarrett D'Amore } else {
1899698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 0, '=');
190095c635efSGarrett D'Amore mdoc->flags &= ~MDOC_SYNOPSIS;
1901698f87a4SGarrett D'Amore }
190295c635efSGarrett D'Amore
190395c635efSGarrett D'Amore /* Mark our last section. */
190495c635efSGarrett D'Amore
190595c635efSGarrett D'Amore mdoc->lastsec = sec;
190695c635efSGarrett D'Amore
190795c635efSGarrett D'Amore /*
190895c635efSGarrett D'Amore * Set the section attribute for the current HEAD, for its
190995c635efSGarrett D'Amore * parent BLOCK, and for the HEAD children; the latter can
191095c635efSGarrett D'Amore * only be TEXT nodes, so no recursion is needed.
191195c635efSGarrett D'Amore * For other blocks and elements, including .Sh BODY, this is
191295c635efSGarrett D'Amore * done when allocating the node data structures, but for .Sh
191395c635efSGarrett D'Amore * BLOCK and HEAD, the section is still unknown at that time.
191495c635efSGarrett D'Amore */
191595c635efSGarrett D'Amore
191695c635efSGarrett D'Amore mdoc->last->parent->sec = sec;
191795c635efSGarrett D'Amore mdoc->last->sec = sec;
191895c635efSGarrett D'Amore for (n = mdoc->last->child; n; n = n->next)
191995c635efSGarrett D'Amore n->sec = sec;
192095c635efSGarrett D'Amore
192195c635efSGarrett D'Amore /* We don't care about custom sections after this. */
192295c635efSGarrett D'Amore
1923*260e9a87SYuri Pankov if (SEC_CUSTOM == sec) {
1924*260e9a87SYuri Pankov free(secname);
1925*260e9a87SYuri Pankov return;
1926*260e9a87SYuri Pankov }
192795c635efSGarrett D'Amore
192895c635efSGarrett D'Amore /*
192995c635efSGarrett D'Amore * Check whether our non-custom section is being repeated or is
193095c635efSGarrett D'Amore * out of order.
193195c635efSGarrett D'Amore */
193295c635efSGarrett D'Amore
193395c635efSGarrett D'Amore if (sec == mdoc->lastnamed)
1934*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_REP, mdoc->parse,
1935*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos,
1936*260e9a87SYuri Pankov "Sh %s", secname);
193795c635efSGarrett D'Amore
193895c635efSGarrett D'Amore if (sec < mdoc->lastnamed)
1939*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_ORDER, mdoc->parse,
1940*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos,
1941*260e9a87SYuri Pankov "Sh %s", secname);
194295c635efSGarrett D'Amore
194395c635efSGarrett D'Amore /* Mark the last named section. */
194495c635efSGarrett D'Amore
194595c635efSGarrett D'Amore mdoc->lastnamed = sec;
194695c635efSGarrett D'Amore
194795c635efSGarrett D'Amore /* Check particular section/manual conventions. */
194895c635efSGarrett D'Amore
1949*260e9a87SYuri Pankov if (mdoc->meta.msec == NULL) {
1950*260e9a87SYuri Pankov free(secname);
1951*260e9a87SYuri Pankov return;
1952*260e9a87SYuri Pankov }
195395c635efSGarrett D'Amore
1954*260e9a87SYuri Pankov goodsec = NULL;
195595c635efSGarrett D'Amore switch (sec) {
1956*260e9a87SYuri Pankov case SEC_ERRORS:
1957*260e9a87SYuri Pankov if (*mdoc->meta.msec == '4')
1958*260e9a87SYuri Pankov break;
1959*260e9a87SYuri Pankov goodsec = "2, 3, 4, 9";
196095c635efSGarrett D'Amore /* FALLTHROUGH */
1961*260e9a87SYuri Pankov case SEC_RETURN_VALUES:
196295c635efSGarrett D'Amore /* FALLTHROUGH */
1963*260e9a87SYuri Pankov case SEC_LIBRARY:
196495c635efSGarrett D'Amore if (*mdoc->meta.msec == '2')
196595c635efSGarrett D'Amore break;
196695c635efSGarrett D'Amore if (*mdoc->meta.msec == '3')
196795c635efSGarrett D'Amore break;
1968*260e9a87SYuri Pankov if (NULL == goodsec)
1969*260e9a87SYuri Pankov goodsec = "2, 3, 9";
1970*260e9a87SYuri Pankov /* FALLTHROUGH */
1971*260e9a87SYuri Pankov case SEC_CONTEXT:
197295c635efSGarrett D'Amore if (*mdoc->meta.msec == '9')
197395c635efSGarrett D'Amore break;
1974*260e9a87SYuri Pankov if (NULL == goodsec)
1975*260e9a87SYuri Pankov goodsec = "9";
1976*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_SEC_MSEC, mdoc->parse,
1977*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos,
1978*260e9a87SYuri Pankov "Sh %s for %s only", secname, goodsec);
197995c635efSGarrett D'Amore break;
198095c635efSGarrett D'Amore default:
198195c635efSGarrett D'Amore break;
198295c635efSGarrett D'Amore }
1983*260e9a87SYuri Pankov free(secname);
198495c635efSGarrett D'Amore }
198595c635efSGarrett D'Amore
1986*260e9a87SYuri Pankov static void
post_ignpar(POST_ARGS)198795c635efSGarrett D'Amore post_ignpar(POST_ARGS)
198895c635efSGarrett D'Amore {
198995c635efSGarrett D'Amore struct mdoc_node *np;
199095c635efSGarrett D'Amore
1991*260e9a87SYuri Pankov switch (mdoc->last->type) {
1992*260e9a87SYuri Pankov case MDOC_HEAD:
1993*260e9a87SYuri Pankov post_hyph(mdoc);
1994*260e9a87SYuri Pankov return;
1995*260e9a87SYuri Pankov case MDOC_BODY:
1996*260e9a87SYuri Pankov break;
1997*260e9a87SYuri Pankov default:
1998*260e9a87SYuri Pankov return;
1999*260e9a87SYuri Pankov }
200095c635efSGarrett D'Amore
200195c635efSGarrett D'Amore if (NULL != (np = mdoc->last->child))
200295c635efSGarrett D'Amore if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2003*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP,
2004*260e9a87SYuri Pankov mdoc->parse, np->line, np->pos,
2005*260e9a87SYuri Pankov "%s after %s", mdoc_macronames[np->tok],
2006*260e9a87SYuri Pankov mdoc_macronames[mdoc->last->tok]);
200795c635efSGarrett D'Amore mdoc_node_delete(mdoc, np);
200895c635efSGarrett D'Amore }
200995c635efSGarrett D'Amore
201095c635efSGarrett D'Amore if (NULL != (np = mdoc->last->last))
201195c635efSGarrett D'Amore if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2012*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2013*260e9a87SYuri Pankov np->line, np->pos, "%s at the end of %s",
2014*260e9a87SYuri Pankov mdoc_macronames[np->tok],
2015*260e9a87SYuri Pankov mdoc_macronames[mdoc->last->tok]);
201695c635efSGarrett D'Amore mdoc_node_delete(mdoc, np);
201795c635efSGarrett D'Amore }
201895c635efSGarrett D'Amore }
201995c635efSGarrett D'Amore
2020*260e9a87SYuri Pankov static void
pre_par(PRE_ARGS)202195c635efSGarrett D'Amore pre_par(PRE_ARGS)
202295c635efSGarrett D'Amore {
202395c635efSGarrett D'Amore
202495c635efSGarrett D'Amore if (NULL == mdoc->last)
2025*260e9a87SYuri Pankov return;
202695c635efSGarrett D'Amore if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2027*260e9a87SYuri Pankov return;
202895c635efSGarrett D'Amore
202995c635efSGarrett D'Amore /*
203095c635efSGarrett D'Amore * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
203195c635efSGarrett D'Amore * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
203295c635efSGarrett D'Amore */
203395c635efSGarrett D'Amore
2034698f87a4SGarrett D'Amore if (MDOC_Pp != mdoc->last->tok &&
2035698f87a4SGarrett D'Amore MDOC_Lp != mdoc->last->tok &&
2036698f87a4SGarrett D'Amore MDOC_br != mdoc->last->tok)
2037*260e9a87SYuri Pankov return;
203895c635efSGarrett D'Amore if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2039*260e9a87SYuri Pankov return;
204095c635efSGarrett D'Amore if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2041*260e9a87SYuri Pankov return;
204295c635efSGarrett D'Amore if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2043*260e9a87SYuri Pankov return;
204495c635efSGarrett D'Amore
2045*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2046*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos,
2047*260e9a87SYuri Pankov "%s before %s", mdoc_macronames[mdoc->last->tok],
2048*260e9a87SYuri Pankov mdoc_macronames[n->tok]);
204995c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last);
205095c635efSGarrett D'Amore }
205195c635efSGarrett D'Amore
2052*260e9a87SYuri Pankov static void
post_par(POST_ARGS)2053698f87a4SGarrett D'Amore post_par(POST_ARGS)
2054698f87a4SGarrett D'Amore {
2055*260e9a87SYuri Pankov struct mdoc_node *np;
2056698f87a4SGarrett D'Amore
2057*260e9a87SYuri Pankov np = mdoc->last;
2058698f87a4SGarrett D'Amore
2059*260e9a87SYuri Pankov if (np->tok == MDOC_sp) {
2060*260e9a87SYuri Pankov if (np->nchild > 1)
2061*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
2062*260e9a87SYuri Pankov np->child->next->line, np->child->next->pos,
2063*260e9a87SYuri Pankov "sp ... %s", np->child->next->string);
2064*260e9a87SYuri Pankov } else if (np->child != NULL)
2065*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP,
2066*260e9a87SYuri Pankov mdoc->parse, np->line, np->pos, "%s %s",
2067*260e9a87SYuri Pankov mdoc_macronames[np->tok], np->child->string);
2068*260e9a87SYuri Pankov
2069*260e9a87SYuri Pankov if (NULL == (np = mdoc->last->prev)) {
2070*260e9a87SYuri Pankov np = mdoc->last->parent;
2071*260e9a87SYuri Pankov if (MDOC_Sh != np->tok && MDOC_Ss != np->tok)
2072*260e9a87SYuri Pankov return;
2073*260e9a87SYuri Pankov } else if (MDOC_Pp != np->tok && MDOC_Lp != np->tok &&
2074698f87a4SGarrett D'Amore (MDOC_br != mdoc->last->tok ||
2075*260e9a87SYuri Pankov (MDOC_sp != np->tok && MDOC_br != np->tok)))
2076*260e9a87SYuri Pankov return;
2077698f87a4SGarrett D'Amore
2078*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_PAR_SKIP, mdoc->parse,
2079*260e9a87SYuri Pankov mdoc->last->line, mdoc->last->pos,
2080*260e9a87SYuri Pankov "%s after %s", mdoc_macronames[mdoc->last->tok],
2081*260e9a87SYuri Pankov mdoc_macronames[np->tok]);
2082698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last);
2083698f87a4SGarrett D'Amore }
2084698f87a4SGarrett D'Amore
2085*260e9a87SYuri Pankov static void
pre_literal(PRE_ARGS)208695c635efSGarrett D'Amore pre_literal(PRE_ARGS)
208795c635efSGarrett D'Amore {
208895c635efSGarrett D'Amore
2089*260e9a87SYuri Pankov pre_display(mdoc, n);
2090*260e9a87SYuri Pankov
209195c635efSGarrett D'Amore if (MDOC_BODY != n->type)
2092*260e9a87SYuri Pankov return;
209395c635efSGarrett D'Amore
209495c635efSGarrett D'Amore /*
209595c635efSGarrett D'Amore * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
209695c635efSGarrett D'Amore * -unfilled' macros set MDOC_LITERAL on entrance to the body.
209795c635efSGarrett D'Amore */
209895c635efSGarrett D'Amore
209995c635efSGarrett D'Amore switch (n->tok) {
2100*260e9a87SYuri Pankov case MDOC_Dl:
210195c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL;
210295c635efSGarrett D'Amore break;
2103*260e9a87SYuri Pankov case MDOC_Bd:
210495c635efSGarrett D'Amore if (DISP_literal == n->norm->Bd.type)
210595c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL;
210695c635efSGarrett D'Amore if (DISP_unfilled == n->norm->Bd.type)
210795c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL;
210895c635efSGarrett D'Amore break;
210995c635efSGarrett D'Amore default:
211095c635efSGarrett D'Amore abort();
211195c635efSGarrett D'Amore /* NOTREACHED */
211295c635efSGarrett D'Amore }
211395c635efSGarrett D'Amore }
211495c635efSGarrett D'Amore
2115*260e9a87SYuri Pankov static void
post_dd(POST_ARGS)211695c635efSGarrett D'Amore post_dd(POST_ARGS)
211795c635efSGarrett D'Amore {
211895c635efSGarrett D'Amore struct mdoc_node *n;
2119*260e9a87SYuri Pankov char *datestr;
212095c635efSGarrett D'Amore
212195c635efSGarrett D'Amore if (mdoc->meta.date)
212295c635efSGarrett D'Amore free(mdoc->meta.date);
212395c635efSGarrett D'Amore
212495c635efSGarrett D'Amore n = mdoc->last;
212595c635efSGarrett D'Amore if (NULL == n->child || '\0' == n->child->string[0]) {
2126*260e9a87SYuri Pankov mdoc->meta.date = mdoc->quick ? mandoc_strdup("") :
2127*260e9a87SYuri Pankov mandoc_normdate(mdoc->parse, NULL, n->line, n->pos);
2128*260e9a87SYuri Pankov goto out;
212995c635efSGarrett D'Amore }
213095c635efSGarrett D'Amore
2131*260e9a87SYuri Pankov datestr = NULL;
2132*260e9a87SYuri Pankov mdoc_deroff(&datestr, n);
2133*260e9a87SYuri Pankov if (mdoc->quick)
2134*260e9a87SYuri Pankov mdoc->meta.date = datestr;
2135*260e9a87SYuri Pankov else {
2136*260e9a87SYuri Pankov mdoc->meta.date = mandoc_normdate(mdoc->parse,
2137*260e9a87SYuri Pankov datestr, n->line, n->pos);
2138*260e9a87SYuri Pankov free(datestr);
2139*260e9a87SYuri Pankov }
2140*260e9a87SYuri Pankov out:
2141*260e9a87SYuri Pankov mdoc_node_delete(mdoc, n);
214295c635efSGarrett D'Amore }
214395c635efSGarrett D'Amore
2144*260e9a87SYuri Pankov static void
post_dt(POST_ARGS)214595c635efSGarrett D'Amore post_dt(POST_ARGS)
214695c635efSGarrett D'Amore {
214795c635efSGarrett D'Amore struct mdoc_node *nn, *n;
214895c635efSGarrett D'Amore const char *cp;
214995c635efSGarrett D'Amore char *p;
215095c635efSGarrett D'Amore
215195c635efSGarrett D'Amore n = mdoc->last;
215295c635efSGarrett D'Amore
215395c635efSGarrett D'Amore free(mdoc->meta.title);
2154*260e9a87SYuri Pankov free(mdoc->meta.msec);
215595c635efSGarrett D'Amore free(mdoc->meta.vol);
215695c635efSGarrett D'Amore free(mdoc->meta.arch);
215795c635efSGarrett D'Amore
2158*260e9a87SYuri Pankov mdoc->meta.title = NULL;
2159*260e9a87SYuri Pankov mdoc->meta.msec = NULL;
2160*260e9a87SYuri Pankov mdoc->meta.vol = NULL;
2161*260e9a87SYuri Pankov mdoc->meta.arch = NULL;
216295c635efSGarrett D'Amore
2163*260e9a87SYuri Pankov /* Mandatory first argument: title. */
216495c635efSGarrett D'Amore
2165*260e9a87SYuri Pankov nn = n->child;
2166*260e9a87SYuri Pankov if (nn == NULL || *nn->string == '\0') {
2167*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_DT_NOTITLE,
2168*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos, "Dt");
2169*260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup("UNTITLED");
2170*260e9a87SYuri Pankov } else {
2171*260e9a87SYuri Pankov mdoc->meta.title = mandoc_strdup(nn->string);
217295c635efSGarrett D'Amore
2173*260e9a87SYuri Pankov /* Check that all characters are uppercase. */
2174*260e9a87SYuri Pankov
2175*260e9a87SYuri Pankov for (p = nn->string; *p != '\0'; p++)
2176*260e9a87SYuri Pankov if (islower((unsigned char)*p)) {
2177*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_TITLE_CASE,
2178*260e9a87SYuri Pankov mdoc->parse, nn->line,
2179*260e9a87SYuri Pankov nn->pos + (p - nn->string),
2180*260e9a87SYuri Pankov "Dt %s", nn->string);
218195c635efSGarrett D'Amore break;
218295c635efSGarrett D'Amore }
218395c635efSGarrett D'Amore }
218495c635efSGarrett D'Amore
2185*260e9a87SYuri Pankov /* Mandatory second argument: section.�*/
218695c635efSGarrett D'Amore
2187*260e9a87SYuri Pankov if (nn != NULL)
2188*260e9a87SYuri Pankov nn = nn->next;
218995c635efSGarrett D'Amore
2190*260e9a87SYuri Pankov if (nn == NULL) {
2191*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_MSEC_MISSING,
2192*260e9a87SYuri Pankov mdoc->parse, n->line, n->pos,
2193*260e9a87SYuri Pankov "Dt %s", mdoc->meta.title);
219495c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL");
2195*260e9a87SYuri Pankov goto out; /* msec and arch remain NULL. */
219695c635efSGarrett D'Amore }
219795c635efSGarrett D'Amore
2198*260e9a87SYuri Pankov mdoc->meta.msec = mandoc_strdup(nn->string);
2199*260e9a87SYuri Pankov
2200*260e9a87SYuri Pankov /* Infer volume title from section number. */
220195c635efSGarrett D'Amore
220295c635efSGarrett D'Amore cp = mandoc_a2msec(nn->string);
2203*260e9a87SYuri Pankov if (cp == NULL) {
2204*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_MSEC_BAD, mdoc->parse,
2205*260e9a87SYuri Pankov nn->line, nn->pos, "Dt ... %s", nn->string);
220695c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(nn->string);
220795c635efSGarrett D'Amore } else
2208*260e9a87SYuri Pankov mdoc->meta.vol = mandoc_strdup(cp);
2209*260e9a87SYuri Pankov
2210*260e9a87SYuri Pankov /* Optional third argument: architecture. */
2211*260e9a87SYuri Pankov
2212*260e9a87SYuri Pankov if ((nn = nn->next) == NULL)
2213*260e9a87SYuri Pankov goto out;
2214*260e9a87SYuri Pankov
2215*260e9a87SYuri Pankov for (p = nn->string; *p != '\0'; p++)
2216*260e9a87SYuri Pankov *p = tolower((unsigned char)*p);
2217*260e9a87SYuri Pankov mdoc->meta.arch = mandoc_strdup(nn->string);
2218*260e9a87SYuri Pankov
2219*260e9a87SYuri Pankov /* Ignore fourth and later arguments. */
2220*260e9a87SYuri Pankov
2221*260e9a87SYuri Pankov if ((nn = nn->next) != NULL)
2222*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_EXCESS, mdoc->parse,
2223*260e9a87SYuri Pankov nn->line, nn->pos, "Dt ... %s", nn->string);
2224*260e9a87SYuri Pankov
2225*260e9a87SYuri Pankov out:
2226*260e9a87SYuri Pankov mdoc_node_delete(mdoc, n);
222795c635efSGarrett D'Amore }
222895c635efSGarrett D'Amore
2229*260e9a87SYuri Pankov static void
post_bx(POST_ARGS)223095c635efSGarrett D'Amore post_bx(POST_ARGS)
223195c635efSGarrett D'Amore {
223295c635efSGarrett D'Amore struct mdoc_node *n;
223395c635efSGarrett D'Amore
223495c635efSGarrett D'Amore /*
223595c635efSGarrett D'Amore * Make `Bx's second argument always start with an uppercase
223695c635efSGarrett D'Amore * letter. Groff checks if it's an "accepted" term, but we just
223795c635efSGarrett D'Amore * uppercase blindly.
223895c635efSGarrett D'Amore */
223995c635efSGarrett D'Amore
224095c635efSGarrett D'Amore n = mdoc->last->child;
224195c635efSGarrett D'Amore if (n && NULL != (n = n->next))
2242*260e9a87SYuri Pankov *n->string = (char)toupper((unsigned char)*n->string);
224395c635efSGarrett D'Amore }
224495c635efSGarrett D'Amore
2245*260e9a87SYuri Pankov static void
post_os(POST_ARGS)224695c635efSGarrett D'Amore post_os(POST_ARGS)
224795c635efSGarrett D'Amore {
224895c635efSGarrett D'Amore #ifndef OSNAME
224995c635efSGarrett D'Amore struct utsname utsname;
2250*260e9a87SYuri Pankov static char *defbuf;
225195c635efSGarrett D'Amore #endif
2252*260e9a87SYuri Pankov struct mdoc_node *n;
225395c635efSGarrett D'Amore
225495c635efSGarrett D'Amore n = mdoc->last;
225595c635efSGarrett D'Amore
225695c635efSGarrett D'Amore /*
2257698f87a4SGarrett D'Amore * Set the operating system by way of the `Os' macro.
2258698f87a4SGarrett D'Amore * The order of precedence is:
2259698f87a4SGarrett D'Amore * 1. the argument of the `Os' macro, unless empty
2260698f87a4SGarrett D'Amore * 2. the -Ios=foo command line argument, if provided
2261698f87a4SGarrett D'Amore * 3. -DOSNAME="\"foo\"", if provided during compilation
2262698f87a4SGarrett D'Amore * 4. "sysname release" from uname(3)
226395c635efSGarrett D'Amore */
226495c635efSGarrett D'Amore
226595c635efSGarrett D'Amore free(mdoc->meta.os);
2266*260e9a87SYuri Pankov mdoc->meta.os = NULL;
2267*260e9a87SYuri Pankov mdoc_deroff(&mdoc->meta.os, n);
2268*260e9a87SYuri Pankov if (mdoc->meta.os)
2269*260e9a87SYuri Pankov goto out;
227095c635efSGarrett D'Amore
2271698f87a4SGarrett D'Amore if (mdoc->defos) {
2272698f87a4SGarrett D'Amore mdoc->meta.os = mandoc_strdup(mdoc->defos);
2273*260e9a87SYuri Pankov goto out;
2274698f87a4SGarrett D'Amore }
2275*260e9a87SYuri Pankov
227695c635efSGarrett D'Amore #ifdef OSNAME
2277*260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(OSNAME);
227895c635efSGarrett D'Amore #else /*!OSNAME */
2279*260e9a87SYuri Pankov if (NULL == defbuf) {
228095c635efSGarrett D'Amore if (-1 == uname(&utsname)) {
2281*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_OS_UNAME, mdoc->parse,
2282*260e9a87SYuri Pankov n->line, n->pos, "Os");
2283*260e9a87SYuri Pankov defbuf = mandoc_strdup("UNKNOWN");
2284*260e9a87SYuri Pankov } else
2285*260e9a87SYuri Pankov mandoc_asprintf(&defbuf, "%s %s",
2286*260e9a87SYuri Pankov utsname.sysname, utsname.release);
228795c635efSGarrett D'Amore }
2288*260e9a87SYuri Pankov mdoc->meta.os = mandoc_strdup(defbuf);
228995c635efSGarrett D'Amore #endif /*!OSNAME*/
2290*260e9a87SYuri Pankov
2291*260e9a87SYuri Pankov out:
2292*260e9a87SYuri Pankov mdoc_node_delete(mdoc, n);
229395c635efSGarrett D'Amore }
229495c635efSGarrett D'Amore
2295*260e9a87SYuri Pankov /*
2296*260e9a87SYuri Pankov * If no argument is provided,
2297*260e9a87SYuri Pankov * fill in the name of the current manual page.
2298*260e9a87SYuri Pankov */
2299*260e9a87SYuri Pankov static void
post_ex(POST_ARGS)2300*260e9a87SYuri Pankov post_ex(POST_ARGS)
230195c635efSGarrett D'Amore {
2302*260e9a87SYuri Pankov struct mdoc_node *n;
230395c635efSGarrett D'Amore
230495c635efSGarrett D'Amore n = mdoc->last;
230595c635efSGarrett D'Amore
230695c635efSGarrett D'Amore if (n->child)
2307*260e9a87SYuri Pankov return;
230895c635efSGarrett D'Amore
2309*260e9a87SYuri Pankov if (mdoc->meta.name == NULL) {
2310*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_EX_NONAME, mdoc->parse,
2311*260e9a87SYuri Pankov n->line, n->pos, "Ex");
2312*260e9a87SYuri Pankov return;
2313*260e9a87SYuri Pankov }
231495c635efSGarrett D'Amore
231595c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
2316*260e9a87SYuri Pankov mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name);
2317*260e9a87SYuri Pankov mdoc->last = n;
231895c635efSGarrett D'Amore }
231995c635efSGarrett D'Amore
232095c635efSGarrett D'Amore static enum mdoc_sec
a2sec(const char * p)232195c635efSGarrett D'Amore a2sec(const char *p)
232295c635efSGarrett D'Amore {
232395c635efSGarrett D'Amore int i;
232495c635efSGarrett D'Amore
232595c635efSGarrett D'Amore for (i = 0; i < (int)SEC__MAX; i++)
232695c635efSGarrett D'Amore if (secnames[i] && 0 == strcmp(p, secnames[i]))
232795c635efSGarrett D'Amore return((enum mdoc_sec)i);
232895c635efSGarrett D'Amore
232995c635efSGarrett D'Amore return(SEC_CUSTOM);
233095c635efSGarrett D'Amore }
233195c635efSGarrett D'Amore
233295c635efSGarrett D'Amore static size_t
macro2len(enum mdoct macro)233395c635efSGarrett D'Amore macro2len(enum mdoct macro)
233495c635efSGarrett D'Amore {
233595c635efSGarrett D'Amore
233695c635efSGarrett D'Amore switch (macro) {
2337*260e9a87SYuri Pankov case MDOC_Ad:
233895c635efSGarrett D'Amore return(12);
2339*260e9a87SYuri Pankov case MDOC_Ao:
234095c635efSGarrett D'Amore return(12);
2341*260e9a87SYuri Pankov case MDOC_An:
234295c635efSGarrett D'Amore return(12);
2343*260e9a87SYuri Pankov case MDOC_Aq:
234495c635efSGarrett D'Amore return(12);
2345*260e9a87SYuri Pankov case MDOC_Ar:
234695c635efSGarrett D'Amore return(12);
2347*260e9a87SYuri Pankov case MDOC_Bo:
234895c635efSGarrett D'Amore return(12);
2349*260e9a87SYuri Pankov case MDOC_Bq:
235095c635efSGarrett D'Amore return(12);
2351*260e9a87SYuri Pankov case MDOC_Cd:
235295c635efSGarrett D'Amore return(12);
2353*260e9a87SYuri Pankov case MDOC_Cm:
235495c635efSGarrett D'Amore return(10);
2355*260e9a87SYuri Pankov case MDOC_Do:
235695c635efSGarrett D'Amore return(10);
2357*260e9a87SYuri Pankov case MDOC_Dq:
235895c635efSGarrett D'Amore return(12);
2359*260e9a87SYuri Pankov case MDOC_Dv:
236095c635efSGarrett D'Amore return(12);
2361*260e9a87SYuri Pankov case MDOC_Eo:
236295c635efSGarrett D'Amore return(12);
2363*260e9a87SYuri Pankov case MDOC_Em:
236495c635efSGarrett D'Amore return(10);
2365*260e9a87SYuri Pankov case MDOC_Er:
236695c635efSGarrett D'Amore return(17);
2367*260e9a87SYuri Pankov case MDOC_Ev:
236895c635efSGarrett D'Amore return(15);
2369*260e9a87SYuri Pankov case MDOC_Fa:
237095c635efSGarrett D'Amore return(12);
2371*260e9a87SYuri Pankov case MDOC_Fl:
237295c635efSGarrett D'Amore return(10);
2373*260e9a87SYuri Pankov case MDOC_Fo:
237495c635efSGarrett D'Amore return(16);
2375*260e9a87SYuri Pankov case MDOC_Fn:
237695c635efSGarrett D'Amore return(16);
2377*260e9a87SYuri Pankov case MDOC_Ic:
237895c635efSGarrett D'Amore return(10);
2379*260e9a87SYuri Pankov case MDOC_Li:
238095c635efSGarrett D'Amore return(16);
2381*260e9a87SYuri Pankov case MDOC_Ms:
238295c635efSGarrett D'Amore return(6);
2383*260e9a87SYuri Pankov case MDOC_Nm:
238495c635efSGarrett D'Amore return(10);
2385*260e9a87SYuri Pankov case MDOC_No:
238695c635efSGarrett D'Amore return(12);
2387*260e9a87SYuri Pankov case MDOC_Oo:
238895c635efSGarrett D'Amore return(10);
2389*260e9a87SYuri Pankov case MDOC_Op:
239095c635efSGarrett D'Amore return(14);
2391*260e9a87SYuri Pankov case MDOC_Pa:
239295c635efSGarrett D'Amore return(32);
2393*260e9a87SYuri Pankov case MDOC_Pf:
239495c635efSGarrett D'Amore return(12);
2395*260e9a87SYuri Pankov case MDOC_Po:
239695c635efSGarrett D'Amore return(12);
2397*260e9a87SYuri Pankov case MDOC_Pq:
239895c635efSGarrett D'Amore return(12);
2399*260e9a87SYuri Pankov case MDOC_Ql:
240095c635efSGarrett D'Amore return(16);
2401*260e9a87SYuri Pankov case MDOC_Qo:
240295c635efSGarrett D'Amore return(12);
2403*260e9a87SYuri Pankov case MDOC_So:
240495c635efSGarrett D'Amore return(12);
2405*260e9a87SYuri Pankov case MDOC_Sq:
240695c635efSGarrett D'Amore return(12);
2407*260e9a87SYuri Pankov case MDOC_Sy:
240895c635efSGarrett D'Amore return(6);
2409*260e9a87SYuri Pankov case MDOC_Sx:
241095c635efSGarrett D'Amore return(16);
2411*260e9a87SYuri Pankov case MDOC_Tn:
241295c635efSGarrett D'Amore return(10);
2413*260e9a87SYuri Pankov case MDOC_Va:
241495c635efSGarrett D'Amore return(12);
2415*260e9a87SYuri Pankov case MDOC_Vt:
241695c635efSGarrett D'Amore return(12);
2417*260e9a87SYuri Pankov case MDOC_Xr:
241895c635efSGarrett D'Amore return(10);
241995c635efSGarrett D'Amore default:
242095c635efSGarrett D'Amore break;
242195c635efSGarrett D'Amore };
242295c635efSGarrett D'Amore return(0);
242395c635efSGarrett D'Amore }
2424