10a6a1f1dSLionel Sambuc /* Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp */
2d65f6f70SBen Gras /*
30a6a1f1dSLionel Sambuc * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
40a6a1f1dSLionel Sambuc * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
5d65f6f70SBen Gras *
6d65f6f70SBen Gras * Permission to use, copy, modify, and distribute this software for any
7d65f6f70SBen Gras * purpose with or without fee is hereby granted, provided that the above
8d65f6f70SBen Gras * copyright notice and this permission notice appear in all copies.
9d65f6f70SBen Gras *
10d65f6f70SBen Gras * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11d65f6f70SBen Gras * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12d65f6f70SBen Gras * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13d65f6f70SBen Gras * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14d65f6f70SBen Gras * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15d65f6f70SBen Gras * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16d65f6f70SBen Gras * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17d65f6f70SBen Gras */
18d65f6f70SBen Gras #ifdef HAVE_CONFIG_H
19d65f6f70SBen Gras #include "config.h"
20d65f6f70SBen Gras #endif
21d65f6f70SBen Gras
22d65f6f70SBen Gras #ifndef OSNAME
23d65f6f70SBen Gras #include <sys/utsname.h>
24d65f6f70SBen Gras #endif
25d65f6f70SBen Gras
26d65f6f70SBen Gras #include <sys/types.h>
27d65f6f70SBen Gras
28d65f6f70SBen Gras #include <assert.h>
29d65f6f70SBen Gras #include <ctype.h>
30d65f6f70SBen Gras #include <limits.h>
31d65f6f70SBen Gras #include <stdio.h>
32d65f6f70SBen Gras #include <stdlib.h>
33d65f6f70SBen Gras #include <string.h>
34d65f6f70SBen Gras #include <time.h>
35d65f6f70SBen Gras
3692395e9cSLionel Sambuc #include "mdoc.h"
37d65f6f70SBen Gras #include "mandoc.h"
38d65f6f70SBen Gras #include "libmdoc.h"
39d65f6f70SBen Gras #include "libmandoc.h"
40d65f6f70SBen Gras
41d65f6f70SBen Gras /* FIXME: .Bl -diag can't have non-text children in HEAD. */
42d65f6f70SBen Gras
43d65f6f70SBen Gras #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
44d65f6f70SBen Gras #define POST_ARGS struct mdoc *mdoc
45d65f6f70SBen Gras
46d65f6f70SBen Gras #define NUMSIZ 32
47d65f6f70SBen Gras #define DATESIZE 32
48d65f6f70SBen Gras
49d65f6f70SBen Gras enum check_ineq {
50d65f6f70SBen Gras CHECK_LT,
51d65f6f70SBen Gras CHECK_GT,
52d65f6f70SBen Gras CHECK_EQ
53d65f6f70SBen Gras };
54d65f6f70SBen Gras
55d65f6f70SBen Gras enum check_lvl {
56d65f6f70SBen Gras CHECK_WARN,
57d65f6f70SBen Gras CHECK_ERROR,
58d65f6f70SBen Gras };
59d65f6f70SBen Gras
60d65f6f70SBen Gras typedef int (*v_pre)(PRE_ARGS);
61d65f6f70SBen Gras typedef int (*v_post)(POST_ARGS);
62d65f6f70SBen Gras
63d65f6f70SBen Gras struct valids {
64d65f6f70SBen Gras v_pre *pre;
65d65f6f70SBen Gras v_post *post;
66d65f6f70SBen Gras };
67d65f6f70SBen Gras
68d65f6f70SBen Gras static int check_count(struct mdoc *, enum mdoc_type,
69d65f6f70SBen Gras enum check_lvl, enum check_ineq, int);
70d65f6f70SBen Gras static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type);
71d65f6f70SBen Gras static void check_text(struct mdoc *, int, int, char *);
72d65f6f70SBen Gras static void check_argv(struct mdoc *,
73d65f6f70SBen Gras struct mdoc_node *, struct mdoc_argv *);
74d65f6f70SBen Gras static void check_args(struct mdoc *, struct mdoc_node *);
7592395e9cSLionel Sambuc static int concat(char *, const struct mdoc_node *, size_t);
7692395e9cSLionel Sambuc static enum mdoc_sec a2sec(const char *);
7792395e9cSLionel Sambuc static size_t macro2len(enum mdoct);
78d65f6f70SBen Gras
79d65f6f70SBen Gras static int ebool(POST_ARGS);
80d65f6f70SBen Gras static int berr_ge1(POST_ARGS);
81d65f6f70SBen Gras static int bwarn_ge1(POST_ARGS);
82d65f6f70SBen Gras static int ewarn_eq0(POST_ARGS);
83d65f6f70SBen Gras static int ewarn_eq1(POST_ARGS);
84d65f6f70SBen Gras static int ewarn_ge1(POST_ARGS);
85d65f6f70SBen Gras static int ewarn_le1(POST_ARGS);
86d65f6f70SBen Gras static int hwarn_eq0(POST_ARGS);
87d65f6f70SBen Gras static int hwarn_eq1(POST_ARGS);
88d65f6f70SBen Gras static int hwarn_ge1(POST_ARGS);
89d65f6f70SBen Gras static int hwarn_le1(POST_ARGS);
90d65f6f70SBen Gras
91d65f6f70SBen Gras static int post_an(POST_ARGS);
92d65f6f70SBen Gras static int post_at(POST_ARGS);
93d65f6f70SBen Gras static int post_bf(POST_ARGS);
94d65f6f70SBen Gras static int post_bl(POST_ARGS);
95d65f6f70SBen Gras static int post_bl_block(POST_ARGS);
96d65f6f70SBen Gras static int post_bl_block_width(POST_ARGS);
97d65f6f70SBen Gras static int post_bl_block_tag(POST_ARGS);
98d65f6f70SBen Gras static int post_bl_head(POST_ARGS);
9992395e9cSLionel Sambuc static int post_bx(POST_ARGS);
1000a6a1f1dSLionel Sambuc static int post_defaults(POST_ARGS);
101d65f6f70SBen Gras static int post_dd(POST_ARGS);
102d65f6f70SBen Gras static int post_dt(POST_ARGS);
103d65f6f70SBen Gras static int post_eoln(POST_ARGS);
1040a6a1f1dSLionel Sambuc static int post_hyph(POST_ARGS);
1050a6a1f1dSLionel Sambuc static int post_ignpar(POST_ARGS);
106d65f6f70SBen Gras static int post_it(POST_ARGS);
107d65f6f70SBen Gras static int post_lb(POST_ARGS);
1080a6a1f1dSLionel Sambuc static int post_literal(POST_ARGS);
109d65f6f70SBen Gras static int post_nm(POST_ARGS);
11092395e9cSLionel Sambuc static int post_ns(POST_ARGS);
111d65f6f70SBen Gras static int post_os(POST_ARGS);
1120a6a1f1dSLionel Sambuc static int post_par(POST_ARGS);
113d65f6f70SBen Gras static int post_prol(POST_ARGS);
114d65f6f70SBen Gras static int post_root(POST_ARGS);
115d65f6f70SBen Gras static int post_rs(POST_ARGS);
116d65f6f70SBen Gras static int post_sh(POST_ARGS);
117d65f6f70SBen Gras static int post_sh_body(POST_ARGS);
118d65f6f70SBen Gras static int post_sh_head(POST_ARGS);
119d65f6f70SBen Gras static int post_st(POST_ARGS);
120d65f6f70SBen Gras static int post_std(POST_ARGS);
121d65f6f70SBen Gras static int post_vt(POST_ARGS);
122d65f6f70SBen Gras static int pre_an(PRE_ARGS);
123d65f6f70SBen Gras static int pre_bd(PRE_ARGS);
124d65f6f70SBen Gras static int pre_bl(PRE_ARGS);
125d65f6f70SBen Gras static int pre_dd(PRE_ARGS);
126d65f6f70SBen Gras static int pre_display(PRE_ARGS);
127d65f6f70SBen Gras static int pre_dt(PRE_ARGS);
128d65f6f70SBen Gras static int pre_it(PRE_ARGS);
129d65f6f70SBen Gras static int pre_literal(PRE_ARGS);
130d65f6f70SBen Gras static int pre_os(PRE_ARGS);
131d65f6f70SBen Gras static int pre_par(PRE_ARGS);
132d65f6f70SBen Gras static int pre_sh(PRE_ARGS);
133d65f6f70SBen Gras static int pre_ss(PRE_ARGS);
134d65f6f70SBen Gras static int pre_std(PRE_ARGS);
135d65f6f70SBen Gras
136d65f6f70SBen Gras static v_post posts_an[] = { post_an, NULL };
137d65f6f70SBen Gras static v_post posts_at[] = { post_at, post_defaults, NULL };
138d65f6f70SBen Gras static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
139d65f6f70SBen Gras static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
140d65f6f70SBen Gras static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
141d65f6f70SBen Gras static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
14292395e9cSLionel Sambuc static v_post posts_bx[] = { post_bx, NULL };
143d65f6f70SBen Gras static v_post posts_bool[] = { ebool, NULL };
144d65f6f70SBen Gras static v_post posts_eoln[] = { post_eoln, NULL };
145d65f6f70SBen Gras static v_post posts_defaults[] = { post_defaults, NULL };
1460a6a1f1dSLionel Sambuc static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL };
14792395e9cSLionel Sambuc static v_post posts_dd[] = { post_dd, post_prol, NULL };
148d65f6f70SBen Gras static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
149d65f6f70SBen Gras static v_post posts_dt[] = { post_dt, post_prol, NULL };
150d65f6f70SBen Gras static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
1510a6a1f1dSLionel Sambuc static v_post posts_hyph[] = { post_hyph, NULL };
1520a6a1f1dSLionel Sambuc static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL };
153d65f6f70SBen Gras static v_post posts_it[] = { post_it, NULL };
154d65f6f70SBen Gras static v_post posts_lb[] = { post_lb, NULL };
1550a6a1f1dSLionel Sambuc static v_post posts_nd[] = { berr_ge1, post_hyph, NULL };
156d65f6f70SBen Gras static v_post posts_nm[] = { post_nm, NULL };
157d65f6f70SBen Gras static v_post posts_notext[] = { ewarn_eq0, NULL };
15892395e9cSLionel Sambuc static v_post posts_ns[] = { post_ns, NULL };
159d65f6f70SBen Gras static v_post posts_os[] = { post_os, post_prol, NULL };
1600a6a1f1dSLionel Sambuc static v_post posts_pp[] = { post_par, ewarn_eq0, NULL };
161d65f6f70SBen Gras static v_post posts_rs[] = { post_rs, NULL };
1620a6a1f1dSLionel Sambuc static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL };
1630a6a1f1dSLionel Sambuc static v_post posts_sp[] = { post_par, ewarn_le1, NULL };
1640a6a1f1dSLionel Sambuc static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL };
165d65f6f70SBen Gras static v_post posts_st[] = { post_st, NULL };
166d65f6f70SBen Gras static v_post posts_std[] = { post_std, NULL };
16792395e9cSLionel Sambuc static v_post posts_text[] = { ewarn_ge1, NULL };
168d65f6f70SBen Gras static v_post posts_text1[] = { ewarn_eq1, NULL };
169d65f6f70SBen Gras static v_post posts_vt[] = { post_vt, NULL };
170d65f6f70SBen Gras static v_pre pres_an[] = { pre_an, NULL };
171d65f6f70SBen Gras static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
172d65f6f70SBen Gras static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
173d65f6f70SBen Gras static v_pre pres_d1[] = { pre_display, NULL };
174d65f6f70SBen Gras static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
175d65f6f70SBen Gras static v_pre pres_dd[] = { pre_dd, NULL };
176d65f6f70SBen Gras static v_pre pres_dt[] = { pre_dt, NULL };
177d65f6f70SBen Gras static v_pre pres_it[] = { pre_it, pre_par, NULL };
178d65f6f70SBen Gras static v_pre pres_os[] = { pre_os, NULL };
179d65f6f70SBen Gras static v_pre pres_pp[] = { pre_par, NULL };
180d65f6f70SBen Gras static v_pre pres_sh[] = { pre_sh, NULL };
181d65f6f70SBen Gras static v_pre pres_ss[] = { pre_ss, NULL };
182d65f6f70SBen Gras static v_pre pres_std[] = { pre_std, NULL };
183d65f6f70SBen Gras
18492395e9cSLionel Sambuc static const struct valids mdoc_valids[MDOC_MAX] = {
185d65f6f70SBen Gras { NULL, NULL }, /* Ap */
186d65f6f70SBen Gras { pres_dd, posts_dd }, /* Dd */
187d65f6f70SBen Gras { pres_dt, posts_dt }, /* Dt */
188d65f6f70SBen Gras { pres_os, posts_os }, /* Os */
189d65f6f70SBen Gras { pres_sh, posts_sh }, /* Sh */
190d65f6f70SBen Gras { pres_ss, posts_ss }, /* Ss */
1910a6a1f1dSLionel Sambuc { pres_pp, posts_pp }, /* Pp */
1920a6a1f1dSLionel Sambuc { pres_d1, posts_d1 }, /* D1 */
193d65f6f70SBen Gras { pres_dl, posts_dl }, /* Dl */
194d65f6f70SBen Gras { pres_bd, posts_bd }, /* Bd */
195d65f6f70SBen Gras { NULL, NULL }, /* Ed */
196d65f6f70SBen Gras { pres_bl, posts_bl }, /* Bl */
197d65f6f70SBen Gras { NULL, NULL }, /* El */
198d65f6f70SBen Gras { pres_it, posts_it }, /* It */
19992395e9cSLionel Sambuc { NULL, NULL }, /* Ad */
200d65f6f70SBen Gras { pres_an, posts_an }, /* An */
201d65f6f70SBen Gras { NULL, posts_defaults }, /* Ar */
20292395e9cSLionel Sambuc { NULL, NULL }, /* Cd */
203d65f6f70SBen Gras { NULL, NULL }, /* Cm */
204d65f6f70SBen Gras { NULL, NULL }, /* Dv */
2050a6a1f1dSLionel Sambuc { NULL, NULL }, /* Er */
206d65f6f70SBen Gras { NULL, NULL }, /* Ev */
207d65f6f70SBen Gras { pres_std, posts_std }, /* Ex */
208d65f6f70SBen Gras { NULL, NULL }, /* Fa */
2090a6a1f1dSLionel Sambuc { NULL, posts_text }, /* Fd */
210d65f6f70SBen Gras { NULL, NULL }, /* Fl */
21192395e9cSLionel Sambuc { NULL, NULL }, /* Fn */
21292395e9cSLionel Sambuc { NULL, NULL }, /* Ft */
21392395e9cSLionel Sambuc { NULL, NULL }, /* Ic */
214d65f6f70SBen Gras { NULL, posts_text1 }, /* In */
215d65f6f70SBen Gras { NULL, posts_defaults }, /* Li */
216d65f6f70SBen Gras { NULL, posts_nd }, /* Nd */
217d65f6f70SBen Gras { NULL, posts_nm }, /* Nm */
218d65f6f70SBen Gras { NULL, NULL }, /* Op */
219d65f6f70SBen Gras { NULL, NULL }, /* Ot */
220d65f6f70SBen Gras { NULL, posts_defaults }, /* Pa */
221d65f6f70SBen Gras { pres_std, posts_std }, /* Rv */
222d65f6f70SBen Gras { NULL, posts_st }, /* St */
223d65f6f70SBen Gras { NULL, NULL }, /* Va */
224d65f6f70SBen Gras { NULL, posts_vt }, /* Vt */
22592395e9cSLionel Sambuc { NULL, posts_text }, /* Xr */
226d65f6f70SBen Gras { NULL, posts_text }, /* %A */
2270a6a1f1dSLionel Sambuc { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
22892395e9cSLionel Sambuc { NULL, posts_text }, /* %D */
229d65f6f70SBen Gras { NULL, posts_text }, /* %I */
230d65f6f70SBen Gras { NULL, posts_text }, /* %J */
2310a6a1f1dSLionel Sambuc { NULL, posts_hyphtext }, /* %N */
2320a6a1f1dSLionel Sambuc { NULL, posts_hyphtext }, /* %O */
233d65f6f70SBen Gras { NULL, posts_text }, /* %P */
2340a6a1f1dSLionel Sambuc { NULL, posts_hyphtext }, /* %R */
2350a6a1f1dSLionel Sambuc { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
236d65f6f70SBen Gras { NULL, posts_text }, /* %V */
237d65f6f70SBen Gras { NULL, NULL }, /* Ac */
238d65f6f70SBen Gras { NULL, NULL }, /* Ao */
239d65f6f70SBen Gras { NULL, NULL }, /* Aq */
240d65f6f70SBen Gras { NULL, posts_at }, /* At */
241d65f6f70SBen Gras { NULL, NULL }, /* Bc */
242d65f6f70SBen Gras { NULL, posts_bf }, /* Bf */
243d65f6f70SBen Gras { NULL, NULL }, /* Bo */
244d65f6f70SBen Gras { NULL, NULL }, /* Bq */
245d65f6f70SBen Gras { NULL, NULL }, /* Bsx */
24692395e9cSLionel Sambuc { NULL, posts_bx }, /* Bx */
247d65f6f70SBen Gras { NULL, posts_bool }, /* Db */
248d65f6f70SBen Gras { NULL, NULL }, /* Dc */
249d65f6f70SBen Gras { NULL, NULL }, /* Do */
250d65f6f70SBen Gras { NULL, NULL }, /* Dq */
251d65f6f70SBen Gras { NULL, NULL }, /* Ec */
252d65f6f70SBen Gras { NULL, NULL }, /* Ef */
253d65f6f70SBen Gras { NULL, NULL }, /* Em */
254d65f6f70SBen Gras { NULL, NULL }, /* Eo */
255d65f6f70SBen Gras { NULL, NULL }, /* Fx */
25692395e9cSLionel Sambuc { NULL, NULL }, /* Ms */
257d65f6f70SBen Gras { NULL, posts_notext }, /* No */
25892395e9cSLionel Sambuc { NULL, posts_ns }, /* Ns */
259d65f6f70SBen Gras { NULL, NULL }, /* Nx */
260d65f6f70SBen Gras { NULL, NULL }, /* Ox */
261d65f6f70SBen Gras { NULL, NULL }, /* Pc */
262d65f6f70SBen Gras { NULL, posts_text1 }, /* Pf */
263d65f6f70SBen Gras { NULL, NULL }, /* Po */
264d65f6f70SBen Gras { NULL, NULL }, /* Pq */
265d65f6f70SBen Gras { NULL, NULL }, /* Qc */
266d65f6f70SBen Gras { NULL, NULL }, /* Ql */
267d65f6f70SBen Gras { NULL, NULL }, /* Qo */
268d65f6f70SBen Gras { NULL, NULL }, /* Qq */
269d65f6f70SBen Gras { NULL, NULL }, /* Re */
270d65f6f70SBen Gras { NULL, posts_rs }, /* Rs */
271d65f6f70SBen Gras { NULL, NULL }, /* Sc */
272d65f6f70SBen Gras { NULL, NULL }, /* So */
273d65f6f70SBen Gras { NULL, NULL }, /* Sq */
274d65f6f70SBen Gras { NULL, posts_bool }, /* Sm */
2750a6a1f1dSLionel Sambuc { NULL, posts_hyph }, /* Sx */
27692395e9cSLionel Sambuc { NULL, NULL }, /* Sy */
27792395e9cSLionel Sambuc { NULL, NULL }, /* Tn */
278d65f6f70SBen Gras { NULL, NULL }, /* Ux */
279d65f6f70SBen Gras { NULL, NULL }, /* Xc */
280d65f6f70SBen Gras { NULL, NULL }, /* Xo */
281d65f6f70SBen Gras { NULL, posts_fo }, /* Fo */
282d65f6f70SBen Gras { NULL, NULL }, /* Fc */
283d65f6f70SBen Gras { NULL, NULL }, /* Oo */
284d65f6f70SBen Gras { NULL, NULL }, /* Oc */
285d65f6f70SBen Gras { NULL, posts_bk }, /* Bk */
286d65f6f70SBen Gras { NULL, NULL }, /* Ek */
287d65f6f70SBen Gras { NULL, posts_eoln }, /* Bt */
288d65f6f70SBen Gras { NULL, NULL }, /* Hf */
289d65f6f70SBen Gras { NULL, NULL }, /* Fr */
290d65f6f70SBen Gras { NULL, posts_eoln }, /* Ud */
291d65f6f70SBen Gras { NULL, posts_lb }, /* Lb */
2920a6a1f1dSLionel Sambuc { pres_pp, posts_pp }, /* Lp */
29392395e9cSLionel Sambuc { NULL, NULL }, /* Lk */
294d65f6f70SBen Gras { NULL, posts_defaults }, /* Mt */
295d65f6f70SBen Gras { NULL, NULL }, /* Brq */
296d65f6f70SBen Gras { NULL, NULL }, /* Bro */
297d65f6f70SBen Gras { NULL, NULL }, /* Brc */
298d65f6f70SBen Gras { NULL, posts_text }, /* %C */
299d65f6f70SBen Gras { NULL, NULL }, /* Es */
300d65f6f70SBen Gras { NULL, NULL }, /* En */
301d65f6f70SBen Gras { NULL, NULL }, /* Dx */
302d65f6f70SBen Gras { NULL, posts_text }, /* %Q */
3030a6a1f1dSLionel Sambuc { NULL, posts_pp }, /* br */
3040a6a1f1dSLionel Sambuc { NULL, posts_sp }, /* sp */
305d65f6f70SBen Gras { NULL, posts_text1 }, /* %U */
306d65f6f70SBen Gras { NULL, NULL }, /* Ta */
307d65f6f70SBen Gras };
308d65f6f70SBen Gras
309d65f6f70SBen Gras #define RSORD_MAX 14 /* Number of `Rs' blocks. */
310d65f6f70SBen Gras
311d65f6f70SBen Gras static const enum mdoct rsord[RSORD_MAX] = {
312d65f6f70SBen Gras MDOC__A,
313d65f6f70SBen Gras MDOC__T,
314d65f6f70SBen Gras MDOC__B,
315d65f6f70SBen Gras MDOC__I,
316d65f6f70SBen Gras MDOC__J,
317d65f6f70SBen Gras MDOC__R,
318d65f6f70SBen Gras MDOC__N,
319d65f6f70SBen Gras MDOC__V,
3200a6a1f1dSLionel Sambuc MDOC__U,
321d65f6f70SBen Gras MDOC__P,
322d65f6f70SBen Gras MDOC__Q,
323d65f6f70SBen Gras MDOC__C,
3240a6a1f1dSLionel Sambuc MDOC__D,
3250a6a1f1dSLionel Sambuc MDOC__O
326d65f6f70SBen Gras };
327d65f6f70SBen Gras
32892395e9cSLionel Sambuc static const char * const secnames[SEC__MAX] = {
32992395e9cSLionel Sambuc NULL,
33092395e9cSLionel Sambuc "NAME",
33192395e9cSLionel Sambuc "LIBRARY",
33292395e9cSLionel Sambuc "SYNOPSIS",
33392395e9cSLionel Sambuc "DESCRIPTION",
33492395e9cSLionel Sambuc "IMPLEMENTATION NOTES",
33592395e9cSLionel Sambuc "RETURN VALUES",
33692395e9cSLionel Sambuc "ENVIRONMENT",
33792395e9cSLionel Sambuc "FILES",
33892395e9cSLionel Sambuc "EXIT STATUS",
33992395e9cSLionel Sambuc "EXAMPLES",
34092395e9cSLionel Sambuc "DIAGNOSTICS",
34192395e9cSLionel Sambuc "COMPATIBILITY",
34292395e9cSLionel Sambuc "ERRORS",
34392395e9cSLionel Sambuc "SEE ALSO",
34492395e9cSLionel Sambuc "STANDARDS",
34592395e9cSLionel Sambuc "HISTORY",
34692395e9cSLionel Sambuc "AUTHORS",
34792395e9cSLionel Sambuc "CAVEATS",
34892395e9cSLionel Sambuc "BUGS",
34992395e9cSLionel Sambuc "SECURITY CONSIDERATIONS",
35092395e9cSLionel Sambuc NULL
35192395e9cSLionel Sambuc };
352d65f6f70SBen Gras
353d65f6f70SBen Gras int
mdoc_valid_pre(struct mdoc * mdoc,struct mdoc_node * n)354d65f6f70SBen Gras mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
355d65f6f70SBen Gras {
356d65f6f70SBen Gras v_pre *p;
357d65f6f70SBen Gras int line, pos;
358d65f6f70SBen Gras char *tp;
359d65f6f70SBen Gras
360d65f6f70SBen Gras switch (n->type) {
361d65f6f70SBen Gras case (MDOC_TEXT):
362d65f6f70SBen Gras tp = n->string;
363d65f6f70SBen Gras line = n->line;
364d65f6f70SBen Gras pos = n->pos;
365d65f6f70SBen Gras check_text(mdoc, line, pos, tp);
366d65f6f70SBen Gras /* FALLTHROUGH */
367d65f6f70SBen Gras case (MDOC_TBL):
368d65f6f70SBen Gras /* FALLTHROUGH */
36992395e9cSLionel Sambuc case (MDOC_EQN):
37092395e9cSLionel Sambuc /* FALLTHROUGH */
371d65f6f70SBen Gras case (MDOC_ROOT):
372d65f6f70SBen Gras return(1);
373d65f6f70SBen Gras default:
374d65f6f70SBen Gras break;
375d65f6f70SBen Gras }
376d65f6f70SBen Gras
377d65f6f70SBen Gras check_args(mdoc, n);
378d65f6f70SBen Gras
379d65f6f70SBen Gras if (NULL == mdoc_valids[n->tok].pre)
380d65f6f70SBen Gras return(1);
381d65f6f70SBen Gras for (p = mdoc_valids[n->tok].pre; *p; p++)
382d65f6f70SBen Gras if ( ! (*p)(mdoc, n))
383d65f6f70SBen Gras return(0);
384d65f6f70SBen Gras return(1);
385d65f6f70SBen Gras }
386d65f6f70SBen Gras
387d65f6f70SBen Gras
388d65f6f70SBen Gras int
mdoc_valid_post(struct mdoc * mdoc)389d65f6f70SBen Gras mdoc_valid_post(struct mdoc *mdoc)
390d65f6f70SBen Gras {
391d65f6f70SBen Gras v_post *p;
392d65f6f70SBen Gras
393d65f6f70SBen Gras if (MDOC_VALID & mdoc->last->flags)
394d65f6f70SBen Gras return(1);
395d65f6f70SBen Gras mdoc->last->flags |= MDOC_VALID;
396d65f6f70SBen Gras
397d65f6f70SBen Gras switch (mdoc->last->type) {
398d65f6f70SBen Gras case (MDOC_TEXT):
399d65f6f70SBen Gras /* FALLTHROUGH */
40092395e9cSLionel Sambuc case (MDOC_EQN):
40192395e9cSLionel Sambuc /* FALLTHROUGH */
402d65f6f70SBen Gras case (MDOC_TBL):
403d65f6f70SBen Gras return(1);
404d65f6f70SBen Gras case (MDOC_ROOT):
405d65f6f70SBen Gras return(post_root(mdoc));
406d65f6f70SBen Gras default:
407d65f6f70SBen Gras break;
408d65f6f70SBen Gras }
409d65f6f70SBen Gras
410d65f6f70SBen Gras if (NULL == mdoc_valids[mdoc->last->tok].post)
411d65f6f70SBen Gras return(1);
412d65f6f70SBen Gras for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
413d65f6f70SBen Gras if ( ! (*p)(mdoc))
414d65f6f70SBen Gras return(0);
415d65f6f70SBen Gras
416d65f6f70SBen Gras return(1);
417d65f6f70SBen Gras }
418d65f6f70SBen Gras
419d65f6f70SBen Gras static int
check_count(struct mdoc * mdoc,enum mdoc_type type,enum check_lvl lvl,enum check_ineq ineq,int val)4200a6a1f1dSLionel Sambuc check_count(struct mdoc *mdoc, enum mdoc_type type,
421d65f6f70SBen Gras enum check_lvl lvl, enum check_ineq ineq, int val)
422d65f6f70SBen Gras {
423d65f6f70SBen Gras const char *p;
424d65f6f70SBen Gras enum mandocerr t;
425d65f6f70SBen Gras
4260a6a1f1dSLionel Sambuc if (mdoc->last->type != type)
427d65f6f70SBen Gras return(1);
428d65f6f70SBen Gras
429d65f6f70SBen Gras switch (ineq) {
430d65f6f70SBen Gras case (CHECK_LT):
431d65f6f70SBen Gras p = "less than ";
4320a6a1f1dSLionel Sambuc if (mdoc->last->nchild < val)
433d65f6f70SBen Gras return(1);
434d65f6f70SBen Gras break;
435d65f6f70SBen Gras case (CHECK_GT):
436d65f6f70SBen Gras p = "more than ";
4370a6a1f1dSLionel Sambuc if (mdoc->last->nchild > val)
438d65f6f70SBen Gras return(1);
439d65f6f70SBen Gras break;
440d65f6f70SBen Gras case (CHECK_EQ):
441d65f6f70SBen Gras p = "";
4420a6a1f1dSLionel Sambuc if (val == mdoc->last->nchild)
443d65f6f70SBen Gras return(1);
444d65f6f70SBen Gras break;
445d65f6f70SBen Gras default:
446d65f6f70SBen Gras abort();
447d65f6f70SBen Gras /* NOTREACHED */
448d65f6f70SBen Gras }
449d65f6f70SBen Gras
450d65f6f70SBen Gras t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
4510a6a1f1dSLionel Sambuc mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos,
452d65f6f70SBen Gras "want %s%d children (have %d)",
4530a6a1f1dSLionel Sambuc p, val, mdoc->last->nchild);
45492395e9cSLionel Sambuc return(1);
455d65f6f70SBen Gras }
456d65f6f70SBen Gras
457d65f6f70SBen Gras static int
berr_ge1(POST_ARGS)458d65f6f70SBen Gras berr_ge1(POST_ARGS)
459d65f6f70SBen Gras {
460d65f6f70SBen Gras
461d65f6f70SBen Gras return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
462d65f6f70SBen Gras }
463d65f6f70SBen Gras
464d65f6f70SBen Gras static int
bwarn_ge1(POST_ARGS)465d65f6f70SBen Gras bwarn_ge1(POST_ARGS)
466d65f6f70SBen Gras {
467d65f6f70SBen Gras return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
468d65f6f70SBen Gras }
469d65f6f70SBen Gras
470d65f6f70SBen Gras static int
ewarn_eq0(POST_ARGS)471d65f6f70SBen Gras ewarn_eq0(POST_ARGS)
472d65f6f70SBen Gras {
473d65f6f70SBen Gras return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
474d65f6f70SBen Gras }
475d65f6f70SBen Gras
476d65f6f70SBen Gras static int
ewarn_eq1(POST_ARGS)477d65f6f70SBen Gras ewarn_eq1(POST_ARGS)
478d65f6f70SBen Gras {
479d65f6f70SBen Gras return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1));
480d65f6f70SBen Gras }
481d65f6f70SBen Gras
482d65f6f70SBen Gras static int
ewarn_ge1(POST_ARGS)483d65f6f70SBen Gras ewarn_ge1(POST_ARGS)
484d65f6f70SBen Gras {
485d65f6f70SBen Gras return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
486d65f6f70SBen Gras }
487d65f6f70SBen Gras
488d65f6f70SBen Gras static int
ewarn_le1(POST_ARGS)489d65f6f70SBen Gras ewarn_le1(POST_ARGS)
490d65f6f70SBen Gras {
491d65f6f70SBen Gras return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2));
492d65f6f70SBen Gras }
493d65f6f70SBen Gras
494d65f6f70SBen Gras static int
hwarn_eq0(POST_ARGS)495d65f6f70SBen Gras hwarn_eq0(POST_ARGS)
496d65f6f70SBen Gras {
497d65f6f70SBen Gras return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0));
498d65f6f70SBen Gras }
499d65f6f70SBen Gras
500d65f6f70SBen Gras static int
hwarn_eq1(POST_ARGS)501d65f6f70SBen Gras hwarn_eq1(POST_ARGS)
502d65f6f70SBen Gras {
503d65f6f70SBen Gras return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
504d65f6f70SBen Gras }
505d65f6f70SBen Gras
506d65f6f70SBen Gras static int
hwarn_ge1(POST_ARGS)507d65f6f70SBen Gras hwarn_ge1(POST_ARGS)
508d65f6f70SBen Gras {
509d65f6f70SBen Gras return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
510d65f6f70SBen Gras }
511d65f6f70SBen Gras
512d65f6f70SBen Gras static int
hwarn_le1(POST_ARGS)513d65f6f70SBen Gras hwarn_le1(POST_ARGS)
514d65f6f70SBen Gras {
515d65f6f70SBen Gras return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
516d65f6f70SBen Gras }
517d65f6f70SBen Gras
518d65f6f70SBen Gras static void
check_args(struct mdoc * mdoc,struct mdoc_node * n)5190a6a1f1dSLionel Sambuc check_args(struct mdoc *mdoc, struct mdoc_node *n)
520d65f6f70SBen Gras {
521d65f6f70SBen Gras int i;
522d65f6f70SBen Gras
523d65f6f70SBen Gras if (NULL == n->args)
524d65f6f70SBen Gras return;
525d65f6f70SBen Gras
526d65f6f70SBen Gras assert(n->args->argc);
527d65f6f70SBen Gras for (i = 0; i < (int)n->args->argc; i++)
5280a6a1f1dSLionel Sambuc check_argv(mdoc, n, &n->args->argv[i]);
529d65f6f70SBen Gras }
530d65f6f70SBen Gras
531d65f6f70SBen Gras static void
check_argv(struct mdoc * mdoc,struct mdoc_node * n,struct mdoc_argv * v)5320a6a1f1dSLionel Sambuc check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
533d65f6f70SBen Gras {
534d65f6f70SBen Gras int i;
535d65f6f70SBen Gras
536d65f6f70SBen Gras for (i = 0; i < (int)v->sz; i++)
5370a6a1f1dSLionel Sambuc check_text(mdoc, v->line, v->pos, v->value[i]);
538d65f6f70SBen Gras
539d65f6f70SBen Gras /* FIXME: move to post_std(). */
540d65f6f70SBen Gras
541d65f6f70SBen Gras if (MDOC_Std == v->arg)
5420a6a1f1dSLionel Sambuc if ( ! (v->sz || mdoc->meta.name))
5430a6a1f1dSLionel Sambuc mdoc_nmsg(mdoc, n, MANDOCERR_NONAME);
544d65f6f70SBen Gras }
545d65f6f70SBen Gras
546d65f6f70SBen Gras static void
check_text(struct mdoc * mdoc,int ln,int pos,char * p)5470a6a1f1dSLionel Sambuc check_text(struct mdoc *mdoc, int ln, int pos, char *p)
548d65f6f70SBen Gras {
54992395e9cSLionel Sambuc char *cp;
550d65f6f70SBen Gras
5510a6a1f1dSLionel Sambuc if (MDOC_LITERAL & mdoc->flags)
55292395e9cSLionel Sambuc return;
553d65f6f70SBen Gras
55492395e9cSLionel Sambuc for (cp = p; NULL != (p = strchr(p, '\t')); p++)
5550a6a1f1dSLionel Sambuc mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
556d65f6f70SBen Gras }
557d65f6f70SBen Gras
558d65f6f70SBen Gras static int
check_parent(PRE_ARGS,enum mdoct tok,enum mdoc_type t)559d65f6f70SBen Gras check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
560d65f6f70SBen Gras {
561d65f6f70SBen Gras
562d65f6f70SBen Gras assert(n->parent);
563d65f6f70SBen Gras if ((MDOC_ROOT == t || tok == n->parent->tok) &&
564d65f6f70SBen Gras (t == n->parent->type))
565d65f6f70SBen Gras return(1);
566d65f6f70SBen Gras
56792395e9cSLionel Sambuc mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
56892395e9cSLionel Sambuc n->pos, "want parent %s", MDOC_ROOT == t ?
56992395e9cSLionel Sambuc "<root>" : mdoc_macronames[tok]);
570d65f6f70SBen Gras return(0);
571d65f6f70SBen Gras }
572d65f6f70SBen Gras
573d65f6f70SBen Gras
574d65f6f70SBen Gras static int
pre_display(PRE_ARGS)575d65f6f70SBen Gras pre_display(PRE_ARGS)
576d65f6f70SBen Gras {
577d65f6f70SBen Gras struct mdoc_node *node;
578d65f6f70SBen Gras
579d65f6f70SBen Gras if (MDOC_BLOCK != n->type)
580d65f6f70SBen Gras return(1);
581d65f6f70SBen Gras
582d65f6f70SBen Gras for (node = mdoc->last->parent; node; node = node->parent)
583d65f6f70SBen Gras if (MDOC_BLOCK == node->type)
584d65f6f70SBen Gras if (MDOC_Bd == node->tok)
585d65f6f70SBen Gras break;
586d65f6f70SBen Gras
587d65f6f70SBen Gras if (node)
588d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP);
589d65f6f70SBen Gras
590d65f6f70SBen Gras return(1);
591d65f6f70SBen Gras }
592d65f6f70SBen Gras
593d65f6f70SBen Gras
594d65f6f70SBen Gras static int
pre_bl(PRE_ARGS)595d65f6f70SBen Gras pre_bl(PRE_ARGS)
596d65f6f70SBen Gras {
597d65f6f70SBen Gras int i, comp, dup;
598d65f6f70SBen Gras const char *offs, *width;
599d65f6f70SBen Gras enum mdoc_list lt;
600*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
601d65f6f70SBen Gras struct mdoc_node *np;
602*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
603d65f6f70SBen Gras
604d65f6f70SBen Gras if (MDOC_BLOCK != n->type) {
605*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
606d65f6f70SBen Gras if (ENDBODY_NOT != n->end) {
607d65f6f70SBen Gras assert(n->pending);
608d65f6f70SBen Gras np = n->pending->parent;
609d65f6f70SBen Gras } else
610d65f6f70SBen Gras np = n->parent;
611d65f6f70SBen Gras
612d65f6f70SBen Gras assert(np);
613d65f6f70SBen Gras assert(MDOC_BLOCK == np->type);
614d65f6f70SBen Gras assert(MDOC_Bl == np->tok);
615*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
616d65f6f70SBen Gras return(1);
617d65f6f70SBen Gras }
618d65f6f70SBen Gras
619d65f6f70SBen Gras /*
620d65f6f70SBen Gras * First figure out which kind of list to use: bind ourselves to
621d65f6f70SBen Gras * the first mentioned list type and warn about any remaining
622d65f6f70SBen Gras * ones. If we find no list type, we default to LIST_item.
623d65f6f70SBen Gras */
624d65f6f70SBen Gras
625d65f6f70SBen Gras /* LINTED */
626d65f6f70SBen Gras for (i = 0; n->args && i < (int)n->args->argc; i++) {
627d65f6f70SBen Gras lt = LIST__NONE;
628d65f6f70SBen Gras dup = comp = 0;
629d65f6f70SBen Gras width = offs = NULL;
630d65f6f70SBen Gras switch (n->args->argv[i].arg) {
631d65f6f70SBen Gras /* Set list types. */
632d65f6f70SBen Gras case (MDOC_Bullet):
633d65f6f70SBen Gras lt = LIST_bullet;
634d65f6f70SBen Gras break;
635d65f6f70SBen Gras case (MDOC_Dash):
636d65f6f70SBen Gras lt = LIST_dash;
637d65f6f70SBen Gras break;
638d65f6f70SBen Gras case (MDOC_Enum):
639d65f6f70SBen Gras lt = LIST_enum;
640d65f6f70SBen Gras break;
641d65f6f70SBen Gras case (MDOC_Hyphen):
642d65f6f70SBen Gras lt = LIST_hyphen;
643d65f6f70SBen Gras break;
644d65f6f70SBen Gras case (MDOC_Item):
645d65f6f70SBen Gras lt = LIST_item;
646d65f6f70SBen Gras break;
647d65f6f70SBen Gras case (MDOC_Tag):
648d65f6f70SBen Gras lt = LIST_tag;
649d65f6f70SBen Gras break;
650d65f6f70SBen Gras case (MDOC_Diag):
651d65f6f70SBen Gras lt = LIST_diag;
652d65f6f70SBen Gras break;
653d65f6f70SBen Gras case (MDOC_Hang):
654d65f6f70SBen Gras lt = LIST_hang;
655d65f6f70SBen Gras break;
656d65f6f70SBen Gras case (MDOC_Ohang):
657d65f6f70SBen Gras lt = LIST_ohang;
658d65f6f70SBen Gras break;
659d65f6f70SBen Gras case (MDOC_Inset):
660d65f6f70SBen Gras lt = LIST_inset;
661d65f6f70SBen Gras break;
662d65f6f70SBen Gras case (MDOC_Column):
663d65f6f70SBen Gras lt = LIST_column;
664d65f6f70SBen Gras break;
665d65f6f70SBen Gras /* Set list arguments. */
666d65f6f70SBen Gras case (MDOC_Compact):
667d65f6f70SBen Gras dup = n->norm->Bl.comp;
668d65f6f70SBen Gras comp = 1;
669d65f6f70SBen Gras break;
670d65f6f70SBen Gras case (MDOC_Width):
67184d9c625SLionel Sambuc /* NB: this can be empty! */
67284d9c625SLionel Sambuc if (n->args->argv[i].sz) {
673d65f6f70SBen Gras width = n->args->argv[i].value[0];
67484d9c625SLionel Sambuc dup = (NULL != n->norm->Bl.width);
67584d9c625SLionel Sambuc break;
67684d9c625SLionel Sambuc }
67784d9c625SLionel Sambuc mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
678d65f6f70SBen Gras break;
679d65f6f70SBen Gras case (MDOC_Offset):
680d65f6f70SBen Gras /* NB: this can be empty! */
681d65f6f70SBen Gras if (n->args->argv[i].sz) {
682d65f6f70SBen Gras offs = n->args->argv[i].value[0];
683d65f6f70SBen Gras dup = (NULL != n->norm->Bl.offs);
684d65f6f70SBen Gras break;
685d65f6f70SBen Gras }
686d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
687d65f6f70SBen Gras break;
688d65f6f70SBen Gras default:
689d65f6f70SBen Gras continue;
690d65f6f70SBen Gras }
691d65f6f70SBen Gras
692d65f6f70SBen Gras /* Check: duplicate auxiliary arguments. */
693d65f6f70SBen Gras
694d65f6f70SBen Gras if (dup)
695d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
696d65f6f70SBen Gras
697d65f6f70SBen Gras if (comp && ! dup)
698d65f6f70SBen Gras n->norm->Bl.comp = comp;
699d65f6f70SBen Gras if (offs && ! dup)
700d65f6f70SBen Gras n->norm->Bl.offs = offs;
701d65f6f70SBen Gras if (width && ! dup)
702d65f6f70SBen Gras n->norm->Bl.width = width;
703d65f6f70SBen Gras
704d65f6f70SBen Gras /* Check: multiple list types. */
705d65f6f70SBen Gras
706d65f6f70SBen Gras if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE)
707d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP);
708d65f6f70SBen Gras
709d65f6f70SBen Gras /* Assign list type. */
710d65f6f70SBen Gras
711d65f6f70SBen Gras if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) {
712d65f6f70SBen Gras n->norm->Bl.type = lt;
713d65f6f70SBen Gras /* Set column information, too. */
714d65f6f70SBen Gras if (LIST_column == lt) {
715d65f6f70SBen Gras n->norm->Bl.ncols =
716d65f6f70SBen Gras n->args->argv[i].sz;
71792395e9cSLionel Sambuc n->norm->Bl.cols = (void *)
718d65f6f70SBen Gras n->args->argv[i].value;
719d65f6f70SBen Gras }
720d65f6f70SBen Gras }
721d65f6f70SBen Gras
722d65f6f70SBen Gras /* The list type should come first. */
723d65f6f70SBen Gras
724d65f6f70SBen Gras if (n->norm->Bl.type == LIST__NONE)
725d65f6f70SBen Gras if (n->norm->Bl.width ||
726d65f6f70SBen Gras n->norm->Bl.offs ||
727d65f6f70SBen Gras n->norm->Bl.comp)
728d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
729d65f6f70SBen Gras
730d65f6f70SBen Gras continue;
731d65f6f70SBen Gras }
732d65f6f70SBen Gras
733d65f6f70SBen Gras /* Allow lists to default to LIST_item. */
734d65f6f70SBen Gras
735d65f6f70SBen Gras if (LIST__NONE == n->norm->Bl.type) {
736d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
737d65f6f70SBen Gras n->norm->Bl.type = LIST_item;
738d65f6f70SBen Gras }
739d65f6f70SBen Gras
740d65f6f70SBen Gras /*
741d65f6f70SBen Gras * Validate the width field. Some list types don't need width
742d65f6f70SBen Gras * types and should be warned about them. Others should have it
7430a6a1f1dSLionel Sambuc * and must also be warned. Yet others have a default and need
7440a6a1f1dSLionel Sambuc * no warning.
745d65f6f70SBen Gras */
746d65f6f70SBen Gras
747d65f6f70SBen Gras switch (n->norm->Bl.type) {
748d65f6f70SBen Gras case (LIST_tag):
7490a6a1f1dSLionel Sambuc if (NULL == n->norm->Bl.width)
750d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
751d65f6f70SBen Gras break;
752d65f6f70SBen Gras case (LIST_column):
753d65f6f70SBen Gras /* FALLTHROUGH */
754d65f6f70SBen Gras case (LIST_diag):
755d65f6f70SBen Gras /* FALLTHROUGH */
756d65f6f70SBen Gras case (LIST_ohang):
757d65f6f70SBen Gras /* FALLTHROUGH */
758d65f6f70SBen Gras case (LIST_inset):
759d65f6f70SBen Gras /* FALLTHROUGH */
760d65f6f70SBen Gras case (LIST_item):
761d65f6f70SBen Gras if (n->norm->Bl.width)
762d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
763d65f6f70SBen Gras break;
7640a6a1f1dSLionel Sambuc case (LIST_bullet):
7650a6a1f1dSLionel Sambuc /* FALLTHROUGH */
7660a6a1f1dSLionel Sambuc case (LIST_dash):
7670a6a1f1dSLionel Sambuc /* FALLTHROUGH */
7680a6a1f1dSLionel Sambuc case (LIST_hyphen):
7690a6a1f1dSLionel Sambuc if (NULL == n->norm->Bl.width)
7700a6a1f1dSLionel Sambuc n->norm->Bl.width = "2n";
7710a6a1f1dSLionel Sambuc break;
7720a6a1f1dSLionel Sambuc case (LIST_enum):
7730a6a1f1dSLionel Sambuc if (NULL == n->norm->Bl.width)
7740a6a1f1dSLionel Sambuc n->norm->Bl.width = "3n";
7750a6a1f1dSLionel Sambuc break;
776d65f6f70SBen Gras default:
777d65f6f70SBen Gras break;
778d65f6f70SBen Gras }
779d65f6f70SBen Gras
780d65f6f70SBen Gras return(1);
781d65f6f70SBen Gras }
782d65f6f70SBen Gras
783d65f6f70SBen Gras
784d65f6f70SBen Gras static int
pre_bd(PRE_ARGS)785d65f6f70SBen Gras pre_bd(PRE_ARGS)
786d65f6f70SBen Gras {
787d65f6f70SBen Gras int i, dup, comp;
788d65f6f70SBen Gras enum mdoc_disp dt;
789d65f6f70SBen Gras const char *offs;
790*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
791d65f6f70SBen Gras struct mdoc_node *np;
792*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
793d65f6f70SBen Gras
794d65f6f70SBen Gras if (MDOC_BLOCK != n->type) {
795*e1cdaee1SLionel Sambuc #if !defined(NDEBUG) && defined(__minix)
796d65f6f70SBen Gras if (ENDBODY_NOT != n->end) {
797d65f6f70SBen Gras assert(n->pending);
798d65f6f70SBen Gras np = n->pending->parent;
799d65f6f70SBen Gras } else
800d65f6f70SBen Gras np = n->parent;
801d65f6f70SBen Gras
802d65f6f70SBen Gras assert(np);
803d65f6f70SBen Gras assert(MDOC_BLOCK == np->type);
804d65f6f70SBen Gras assert(MDOC_Bd == np->tok);
805*e1cdaee1SLionel Sambuc #endif /* !defined(NDEBUG) && defined(__minix) */
806d65f6f70SBen Gras return(1);
807d65f6f70SBen Gras }
808d65f6f70SBen Gras
809d65f6f70SBen Gras /* LINTED */
810d65f6f70SBen Gras for (i = 0; n->args && i < (int)n->args->argc; i++) {
811d65f6f70SBen Gras dt = DISP__NONE;
812d65f6f70SBen Gras dup = comp = 0;
813d65f6f70SBen Gras offs = NULL;
814d65f6f70SBen Gras
815d65f6f70SBen Gras switch (n->args->argv[i].arg) {
816d65f6f70SBen Gras case (MDOC_Centred):
817d65f6f70SBen Gras dt = DISP_centred;
818d65f6f70SBen Gras break;
819d65f6f70SBen Gras case (MDOC_Ragged):
820d65f6f70SBen Gras dt = DISP_ragged;
821d65f6f70SBen Gras break;
822d65f6f70SBen Gras case (MDOC_Unfilled):
823d65f6f70SBen Gras dt = DISP_unfilled;
824d65f6f70SBen Gras break;
825d65f6f70SBen Gras case (MDOC_Filled):
826d65f6f70SBen Gras dt = DISP_filled;
827d65f6f70SBen Gras break;
828d65f6f70SBen Gras case (MDOC_Literal):
829d65f6f70SBen Gras dt = DISP_literal;
830d65f6f70SBen Gras break;
831d65f6f70SBen Gras case (MDOC_File):
832d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
833d65f6f70SBen Gras return(0);
834d65f6f70SBen Gras case (MDOC_Offset):
835d65f6f70SBen Gras /* NB: this can be empty! */
836d65f6f70SBen Gras if (n->args->argv[i].sz) {
837d65f6f70SBen Gras offs = n->args->argv[i].value[0];
838d65f6f70SBen Gras dup = (NULL != n->norm->Bd.offs);
839d65f6f70SBen Gras break;
840d65f6f70SBen Gras }
841d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
842d65f6f70SBen Gras break;
843d65f6f70SBen Gras case (MDOC_Compact):
844d65f6f70SBen Gras comp = 1;
845d65f6f70SBen Gras dup = n->norm->Bd.comp;
846d65f6f70SBen Gras break;
847d65f6f70SBen Gras default:
848d65f6f70SBen Gras abort();
849d65f6f70SBen Gras /* NOTREACHED */
850d65f6f70SBen Gras }
851d65f6f70SBen Gras
852d65f6f70SBen Gras /* Check whether we have duplicates. */
853d65f6f70SBen Gras
854d65f6f70SBen Gras if (dup)
855d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
856d65f6f70SBen Gras
857d65f6f70SBen Gras /* Make our auxiliary assignments. */
858d65f6f70SBen Gras
859d65f6f70SBen Gras if (offs && ! dup)
860d65f6f70SBen Gras n->norm->Bd.offs = offs;
861d65f6f70SBen Gras if (comp && ! dup)
862d65f6f70SBen Gras n->norm->Bd.comp = comp;
863d65f6f70SBen Gras
864d65f6f70SBen Gras /* Check whether a type has already been assigned. */
865d65f6f70SBen Gras
866d65f6f70SBen Gras if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
867d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
868d65f6f70SBen Gras
869d65f6f70SBen Gras /* Make our type assignment. */
870d65f6f70SBen Gras
871d65f6f70SBen Gras if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
872d65f6f70SBen Gras n->norm->Bd.type = dt;
873d65f6f70SBen Gras }
874d65f6f70SBen Gras
875d65f6f70SBen Gras if (DISP__NONE == n->norm->Bd.type) {
876d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
877d65f6f70SBen Gras n->norm->Bd.type = DISP_ragged;
878d65f6f70SBen Gras }
879d65f6f70SBen Gras
880d65f6f70SBen Gras return(1);
881d65f6f70SBen Gras }
882d65f6f70SBen Gras
883d65f6f70SBen Gras
884d65f6f70SBen Gras static int
pre_ss(PRE_ARGS)885d65f6f70SBen Gras pre_ss(PRE_ARGS)
886d65f6f70SBen Gras {
887d65f6f70SBen Gras
888d65f6f70SBen Gras if (MDOC_BLOCK != n->type)
889d65f6f70SBen Gras return(1);
890d65f6f70SBen Gras return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
891d65f6f70SBen Gras }
892d65f6f70SBen Gras
893d65f6f70SBen Gras
894d65f6f70SBen Gras static int
pre_sh(PRE_ARGS)895d65f6f70SBen Gras pre_sh(PRE_ARGS)
896d65f6f70SBen Gras {
897d65f6f70SBen Gras
898d65f6f70SBen Gras if (MDOC_BLOCK != n->type)
899d65f6f70SBen Gras return(1);
900d65f6f70SBen Gras return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
901d65f6f70SBen Gras }
902d65f6f70SBen Gras
903d65f6f70SBen Gras
904d65f6f70SBen Gras static int
pre_it(PRE_ARGS)905d65f6f70SBen Gras pre_it(PRE_ARGS)
906d65f6f70SBen Gras {
907d65f6f70SBen Gras
908d65f6f70SBen Gras if (MDOC_BLOCK != n->type)
909d65f6f70SBen Gras return(1);
910d65f6f70SBen Gras
911d65f6f70SBen Gras return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
912d65f6f70SBen Gras }
913d65f6f70SBen Gras
914d65f6f70SBen Gras
915d65f6f70SBen Gras static int
pre_an(PRE_ARGS)916d65f6f70SBen Gras pre_an(PRE_ARGS)
917d65f6f70SBen Gras {
918d65f6f70SBen Gras int i;
919d65f6f70SBen Gras
920d65f6f70SBen Gras if (NULL == n->args)
921d65f6f70SBen Gras return(1);
922d65f6f70SBen Gras
923d65f6f70SBen Gras for (i = 1; i < (int)n->args->argc; i++)
924d65f6f70SBen Gras mdoc_pmsg(mdoc, n->args->argv[i].line,
925d65f6f70SBen Gras n->args->argv[i].pos, MANDOCERR_IGNARGV);
926d65f6f70SBen Gras
927d65f6f70SBen Gras if (MDOC_Split == n->args->argv[0].arg)
928d65f6f70SBen Gras n->norm->An.auth = AUTH_split;
929d65f6f70SBen Gras else if (MDOC_Nosplit == n->args->argv[0].arg)
930d65f6f70SBen Gras n->norm->An.auth = AUTH_nosplit;
931d65f6f70SBen Gras else
932d65f6f70SBen Gras abort();
933d65f6f70SBen Gras
934d65f6f70SBen Gras return(1);
935d65f6f70SBen Gras }
936d65f6f70SBen Gras
937d65f6f70SBen Gras static int
pre_std(PRE_ARGS)938d65f6f70SBen Gras pre_std(PRE_ARGS)
939d65f6f70SBen Gras {
940d65f6f70SBen Gras
941d65f6f70SBen Gras if (n->args && 1 == n->args->argc)
942d65f6f70SBen Gras if (MDOC_Std == n->args->argv[0].arg)
943d65f6f70SBen Gras return(1);
944d65f6f70SBen Gras
945d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV);
946d65f6f70SBen Gras return(1);
947d65f6f70SBen Gras }
948d65f6f70SBen Gras
949d65f6f70SBen Gras static int
pre_dt(PRE_ARGS)950d65f6f70SBen Gras pre_dt(PRE_ARGS)
951d65f6f70SBen Gras {
952d65f6f70SBen Gras
95392395e9cSLionel Sambuc if (NULL == mdoc->meta.date || mdoc->meta.os)
954d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
955d65f6f70SBen Gras
956d65f6f70SBen Gras if (mdoc->meta.title)
957d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
958d65f6f70SBen Gras
959d65f6f70SBen Gras return(1);
960d65f6f70SBen Gras }
961d65f6f70SBen Gras
962d65f6f70SBen Gras static int
pre_os(PRE_ARGS)963d65f6f70SBen Gras pre_os(PRE_ARGS)
964d65f6f70SBen Gras {
965d65f6f70SBen Gras
96692395e9cSLionel Sambuc if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
967d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
968d65f6f70SBen Gras
969d65f6f70SBen Gras if (mdoc->meta.os)
970d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
971d65f6f70SBen Gras
972d65f6f70SBen Gras return(1);
973d65f6f70SBen Gras }
974d65f6f70SBen Gras
975d65f6f70SBen Gras static int
pre_dd(PRE_ARGS)976d65f6f70SBen Gras pre_dd(PRE_ARGS)
977d65f6f70SBen Gras {
978d65f6f70SBen Gras
979d65f6f70SBen Gras if (mdoc->meta.title || mdoc->meta.os)
980d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
981d65f6f70SBen Gras
982d65f6f70SBen Gras if (mdoc->meta.date)
983d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
984d65f6f70SBen Gras
985d65f6f70SBen Gras return(1);
986d65f6f70SBen Gras }
987d65f6f70SBen Gras
988d65f6f70SBen Gras
989d65f6f70SBen Gras static int
post_bf(POST_ARGS)990d65f6f70SBen Gras post_bf(POST_ARGS)
991d65f6f70SBen Gras {
992d65f6f70SBen Gras struct mdoc_node *np;
993d65f6f70SBen Gras enum mdocargt arg;
994d65f6f70SBen Gras
995d65f6f70SBen Gras /*
996d65f6f70SBen Gras * Unlike other data pointers, these are "housed" by the HEAD
997d65f6f70SBen Gras * element, which contains the goods.
998d65f6f70SBen Gras */
999d65f6f70SBen Gras
1000d65f6f70SBen Gras if (MDOC_HEAD != mdoc->last->type) {
1001d65f6f70SBen Gras if (ENDBODY_NOT != mdoc->last->end) {
1002d65f6f70SBen Gras assert(mdoc->last->pending);
1003d65f6f70SBen Gras np = mdoc->last->pending->parent->head;
1004d65f6f70SBen Gras } else if (MDOC_BLOCK != mdoc->last->type) {
1005d65f6f70SBen Gras np = mdoc->last->parent->head;
1006d65f6f70SBen Gras } else
1007d65f6f70SBen Gras np = mdoc->last->head;
1008d65f6f70SBen Gras
1009d65f6f70SBen Gras assert(np);
1010d65f6f70SBen Gras assert(MDOC_HEAD == np->type);
1011d65f6f70SBen Gras assert(MDOC_Bf == np->tok);
1012d65f6f70SBen Gras return(1);
1013d65f6f70SBen Gras }
1014d65f6f70SBen Gras
1015d65f6f70SBen Gras np = mdoc->last;
1016d65f6f70SBen Gras assert(MDOC_BLOCK == np->parent->type);
1017d65f6f70SBen Gras assert(MDOC_Bf == np->parent->tok);
1018d65f6f70SBen Gras
1019d65f6f70SBen Gras /*
1020d65f6f70SBen Gras * Cannot have both argument and parameter.
1021d65f6f70SBen Gras * If neither is specified, let it through with a warning.
1022d65f6f70SBen Gras */
1023d65f6f70SBen Gras
1024d65f6f70SBen Gras if (np->parent->args && np->child) {
1025d65f6f70SBen Gras mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
1026d65f6f70SBen Gras return(0);
1027d65f6f70SBen Gras } else if (NULL == np->parent->args && NULL == np->child) {
1028d65f6f70SBen Gras mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1029d65f6f70SBen Gras return(1);
1030d65f6f70SBen Gras }
1031d65f6f70SBen Gras
1032d65f6f70SBen Gras /* Extract argument into data. */
1033d65f6f70SBen Gras
1034d65f6f70SBen Gras if (np->parent->args) {
1035d65f6f70SBen Gras arg = np->parent->args->argv[0].arg;
1036d65f6f70SBen Gras if (MDOC_Emphasis == arg)
1037d65f6f70SBen Gras np->norm->Bf.font = FONT_Em;
1038d65f6f70SBen Gras else if (MDOC_Literal == arg)
1039d65f6f70SBen Gras np->norm->Bf.font = FONT_Li;
1040d65f6f70SBen Gras else if (MDOC_Symbolic == arg)
1041d65f6f70SBen Gras np->norm->Bf.font = FONT_Sy;
1042d65f6f70SBen Gras else
1043d65f6f70SBen Gras abort();
1044d65f6f70SBen Gras return(1);
1045d65f6f70SBen Gras }
1046d65f6f70SBen Gras
1047d65f6f70SBen Gras /* Extract parameter into data. */
1048d65f6f70SBen Gras
1049d65f6f70SBen Gras if (0 == strcmp(np->child->string, "Em"))
1050d65f6f70SBen Gras np->norm->Bf.font = FONT_Em;
1051d65f6f70SBen Gras else if (0 == strcmp(np->child->string, "Li"))
1052d65f6f70SBen Gras np->norm->Bf.font = FONT_Li;
1053d65f6f70SBen Gras else if (0 == strcmp(np->child->string, "Sy"))
1054d65f6f70SBen Gras np->norm->Bf.font = FONT_Sy;
1055d65f6f70SBen Gras else
1056d65f6f70SBen Gras mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
1057d65f6f70SBen Gras
1058d65f6f70SBen Gras return(1);
1059d65f6f70SBen Gras }
1060d65f6f70SBen Gras
1061d65f6f70SBen Gras static int
post_lb(POST_ARGS)1062d65f6f70SBen Gras post_lb(POST_ARGS)
1063d65f6f70SBen Gras {
1064d65f6f70SBen Gras const char *p;
1065d65f6f70SBen Gras char *buf;
1066d65f6f70SBen Gras size_t sz;
1067d65f6f70SBen Gras
1068d65f6f70SBen Gras check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1069d65f6f70SBen Gras
1070d65f6f70SBen Gras assert(mdoc->last->child);
1071d65f6f70SBen Gras assert(MDOC_TEXT == mdoc->last->child->type);
1072d65f6f70SBen Gras
1073d65f6f70SBen Gras p = mdoc_a2lib(mdoc->last->child->string);
1074d65f6f70SBen Gras
1075d65f6f70SBen Gras /* If lookup ok, replace with table value. */
1076d65f6f70SBen Gras
1077d65f6f70SBen Gras if (p) {
1078d65f6f70SBen Gras free(mdoc->last->child->string);
1079d65f6f70SBen Gras mdoc->last->child->string = mandoc_strdup(p);
1080d65f6f70SBen Gras return(1);
1081d65f6f70SBen Gras }
1082d65f6f70SBen Gras
1083d65f6f70SBen Gras /* If not, use "library ``xxxx''. */
1084d65f6f70SBen Gras
1085d65f6f70SBen Gras sz = strlen(mdoc->last->child->string) +
1086d65f6f70SBen Gras 2 + strlen("\\(lqlibrary\\(rq");
1087d65f6f70SBen Gras buf = mandoc_malloc(sz);
1088d65f6f70SBen Gras snprintf(buf, sz, "library \\(lq%s\\(rq",
1089d65f6f70SBen Gras mdoc->last->child->string);
1090d65f6f70SBen Gras free(mdoc->last->child->string);
1091d65f6f70SBen Gras mdoc->last->child->string = buf;
1092d65f6f70SBen Gras return(1);
1093d65f6f70SBen Gras }
1094d65f6f70SBen Gras
1095d65f6f70SBen Gras static int
post_eoln(POST_ARGS)1096d65f6f70SBen Gras post_eoln(POST_ARGS)
1097d65f6f70SBen Gras {
1098d65f6f70SBen Gras
1099d65f6f70SBen Gras if (mdoc->last->child)
1100d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1101d65f6f70SBen Gras return(1);
1102d65f6f70SBen Gras }
1103d65f6f70SBen Gras
1104d65f6f70SBen Gras
1105d65f6f70SBen Gras static int
post_vt(POST_ARGS)1106d65f6f70SBen Gras post_vt(POST_ARGS)
1107d65f6f70SBen Gras {
1108d65f6f70SBen Gras const struct mdoc_node *n;
1109d65f6f70SBen Gras
1110d65f6f70SBen Gras /*
1111d65f6f70SBen Gras * The Vt macro comes in both ELEM and BLOCK form, both of which
1112d65f6f70SBen Gras * have different syntaxes (yet more context-sensitive
111392395e9cSLionel Sambuc * behaviour). ELEM types must have a child, which is already
111492395e9cSLionel Sambuc * guaranteed by the in_line parsing routine; BLOCK types,
1115d65f6f70SBen Gras * specifically the BODY, should only have TEXT children.
1116d65f6f70SBen Gras */
1117d65f6f70SBen Gras
1118d65f6f70SBen Gras if (MDOC_BODY != mdoc->last->type)
1119d65f6f70SBen Gras return(1);
1120d65f6f70SBen Gras
1121d65f6f70SBen Gras for (n = mdoc->last->child; n; n = n->next)
1122d65f6f70SBen Gras if (MDOC_TEXT != n->type)
1123d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
1124d65f6f70SBen Gras
1125d65f6f70SBen Gras return(1);
1126d65f6f70SBen Gras }
1127d65f6f70SBen Gras
1128d65f6f70SBen Gras
1129d65f6f70SBen Gras static int
post_nm(POST_ARGS)1130d65f6f70SBen Gras post_nm(POST_ARGS)
1131d65f6f70SBen Gras {
1132d65f6f70SBen Gras char buf[BUFSIZ];
113392395e9cSLionel Sambuc int c;
1134d65f6f70SBen Gras
11350a6a1f1dSLionel Sambuc if (NULL != mdoc->meta.name)
1136d65f6f70SBen Gras return(1);
1137d65f6f70SBen Gras
11380a6a1f1dSLionel Sambuc /* Try to use our children for setting the meta name. */
1139d65f6f70SBen Gras
11400a6a1f1dSLionel Sambuc if (NULL != mdoc->last->child) {
114192395e9cSLionel Sambuc buf[0] = '\0';
11420a6a1f1dSLionel Sambuc c = concat(buf, mdoc->last->child, BUFSIZ);
11430a6a1f1dSLionel Sambuc } else
11440a6a1f1dSLionel Sambuc c = 0;
11450a6a1f1dSLionel Sambuc
11460a6a1f1dSLionel Sambuc switch (c) {
11470a6a1f1dSLionel Sambuc case (-1):
114892395e9cSLionel Sambuc mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1149d65f6f70SBen Gras return(0);
11500a6a1f1dSLionel Sambuc case (0):
11510a6a1f1dSLionel Sambuc mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
11520a6a1f1dSLionel Sambuc mdoc->meta.name = mandoc_strdup("UNKNOWN");
11530a6a1f1dSLionel Sambuc break;
11540a6a1f1dSLionel Sambuc default:
1155d65f6f70SBen Gras mdoc->meta.name = mandoc_strdup(buf);
11560a6a1f1dSLionel Sambuc break;
11570a6a1f1dSLionel Sambuc }
1158d65f6f70SBen Gras return(1);
1159d65f6f70SBen Gras }
1160d65f6f70SBen Gras
1161d65f6f70SBen Gras static int
post_literal(POST_ARGS)1162d65f6f70SBen Gras post_literal(POST_ARGS)
1163d65f6f70SBen Gras {
1164d65f6f70SBen Gras
1165d65f6f70SBen Gras /*
1166d65f6f70SBen Gras * The `Dl' (note "el" not "one") and `Bd' macros unset the
1167d65f6f70SBen Gras * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
1168d65f6f70SBen Gras * this in literal mode, but it doesn't hurt to just switch it
1169d65f6f70SBen Gras * off in general since displays can't be nested.
1170d65f6f70SBen Gras */
1171d65f6f70SBen Gras
1172d65f6f70SBen Gras if (MDOC_BODY == mdoc->last->type)
1173d65f6f70SBen Gras mdoc->flags &= ~MDOC_LITERAL;
1174d65f6f70SBen Gras
1175d65f6f70SBen Gras return(1);
1176d65f6f70SBen Gras }
1177d65f6f70SBen Gras
1178d65f6f70SBen Gras static int
post_defaults(POST_ARGS)1179d65f6f70SBen Gras post_defaults(POST_ARGS)
1180d65f6f70SBen Gras {
1181d65f6f70SBen Gras struct mdoc_node *nn;
1182d65f6f70SBen Gras
1183d65f6f70SBen Gras /*
1184d65f6f70SBen Gras * The `Ar' defaults to "file ..." if no value is provided as an
1185d65f6f70SBen Gras * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
1186d65f6f70SBen Gras * gets an empty string.
1187d65f6f70SBen Gras */
1188d65f6f70SBen Gras
1189d65f6f70SBen Gras if (mdoc->last->child)
1190d65f6f70SBen Gras return(1);
1191d65f6f70SBen Gras
1192d65f6f70SBen Gras nn = mdoc->last;
1193d65f6f70SBen Gras mdoc->next = MDOC_NEXT_CHILD;
1194d65f6f70SBen Gras
1195d65f6f70SBen Gras switch (nn->tok) {
1196d65f6f70SBen Gras case (MDOC_Ar):
1197d65f6f70SBen Gras if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
1198d65f6f70SBen Gras return(0);
1199d65f6f70SBen Gras if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
1200d65f6f70SBen Gras return(0);
1201d65f6f70SBen Gras break;
1202d65f6f70SBen Gras case (MDOC_At):
1203d65f6f70SBen Gras if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T"))
1204d65f6f70SBen Gras return(0);
1205d65f6f70SBen Gras if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX"))
1206d65f6f70SBen Gras return(0);
1207d65f6f70SBen Gras break;
1208d65f6f70SBen Gras case (MDOC_Li):
1209d65f6f70SBen Gras if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
1210d65f6f70SBen Gras return(0);
1211d65f6f70SBen Gras break;
1212d65f6f70SBen Gras case (MDOC_Pa):
1213d65f6f70SBen Gras /* FALLTHROUGH */
1214d65f6f70SBen Gras case (MDOC_Mt):
1215d65f6f70SBen Gras if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
1216d65f6f70SBen Gras return(0);
1217d65f6f70SBen Gras break;
1218d65f6f70SBen Gras default:
1219d65f6f70SBen Gras abort();
1220d65f6f70SBen Gras /* NOTREACHED */
1221d65f6f70SBen Gras }
1222d65f6f70SBen Gras
1223d65f6f70SBen Gras mdoc->last = nn;
1224d65f6f70SBen Gras return(1);
1225d65f6f70SBen Gras }
1226d65f6f70SBen Gras
1227d65f6f70SBen Gras static int
post_at(POST_ARGS)1228d65f6f70SBen Gras post_at(POST_ARGS)
1229d65f6f70SBen Gras {
1230d65f6f70SBen Gras const char *p, *q;
1231d65f6f70SBen Gras char *buf;
1232d65f6f70SBen Gras size_t sz;
1233d65f6f70SBen Gras
1234d65f6f70SBen Gras /*
1235d65f6f70SBen Gras * If we have a child, look it up in the standard keys. If a
1236d65f6f70SBen Gras * key exist, use that instead of the child; if it doesn't,
1237d65f6f70SBen Gras * prefix "AT&T UNIX " to the existing data.
1238d65f6f70SBen Gras */
1239d65f6f70SBen Gras
1240d65f6f70SBen Gras if (NULL == mdoc->last->child)
1241d65f6f70SBen Gras return(1);
1242d65f6f70SBen Gras
1243d65f6f70SBen Gras assert(MDOC_TEXT == mdoc->last->child->type);
1244d65f6f70SBen Gras p = mdoc_a2att(mdoc->last->child->string);
1245d65f6f70SBen Gras
1246d65f6f70SBen Gras if (p) {
1247d65f6f70SBen Gras free(mdoc->last->child->string);
1248d65f6f70SBen Gras mdoc->last->child->string = mandoc_strdup(p);
1249d65f6f70SBen Gras } else {
1250d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
1251d65f6f70SBen Gras p = "AT&T UNIX ";
1252d65f6f70SBen Gras q = mdoc->last->child->string;
1253d65f6f70SBen Gras sz = strlen(p) + strlen(q) + 1;
1254d65f6f70SBen Gras buf = mandoc_malloc(sz);
1255d65f6f70SBen Gras strlcpy(buf, p, sz);
1256d65f6f70SBen Gras strlcat(buf, q, sz);
1257d65f6f70SBen Gras free(mdoc->last->child->string);
1258d65f6f70SBen Gras mdoc->last->child->string = buf;
1259d65f6f70SBen Gras }
1260d65f6f70SBen Gras
1261d65f6f70SBen Gras return(1);
1262d65f6f70SBen Gras }
1263d65f6f70SBen Gras
1264d65f6f70SBen Gras static int
post_an(POST_ARGS)1265d65f6f70SBen Gras post_an(POST_ARGS)
1266d65f6f70SBen Gras {
1267d65f6f70SBen Gras struct mdoc_node *np;
1268d65f6f70SBen Gras
1269d65f6f70SBen Gras np = mdoc->last;
127092395e9cSLionel Sambuc if (AUTH__NONE == np->norm->An.auth) {
127192395e9cSLionel Sambuc if (0 == np->child)
127292395e9cSLionel Sambuc check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
127392395e9cSLionel Sambuc } else if (np->child)
1274d65f6f70SBen Gras check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
1275d65f6f70SBen Gras
1276d65f6f70SBen Gras return(1);
1277d65f6f70SBen Gras }
1278d65f6f70SBen Gras
1279d65f6f70SBen Gras
1280d65f6f70SBen Gras static int
post_it(POST_ARGS)1281d65f6f70SBen Gras post_it(POST_ARGS)
1282d65f6f70SBen Gras {
128392395e9cSLionel Sambuc int i, cols;
1284d65f6f70SBen Gras enum mdoc_list lt;
1285d65f6f70SBen Gras struct mdoc_node *n, *c;
1286d65f6f70SBen Gras enum mandocerr er;
1287d65f6f70SBen Gras
1288d65f6f70SBen Gras if (MDOC_BLOCK != mdoc->last->type)
1289d65f6f70SBen Gras return(1);
1290d65f6f70SBen Gras
1291d65f6f70SBen Gras n = mdoc->last->parent->parent;
1292d65f6f70SBen Gras lt = n->norm->Bl.type;
1293d65f6f70SBen Gras
1294d65f6f70SBen Gras if (LIST__NONE == lt) {
1295d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
1296d65f6f70SBen Gras return(1);
1297d65f6f70SBen Gras }
1298d65f6f70SBen Gras
1299d65f6f70SBen Gras switch (lt) {
1300d65f6f70SBen Gras case (LIST_tag):
1301d65f6f70SBen Gras if (mdoc->last->head->child)
1302d65f6f70SBen Gras break;
1303d65f6f70SBen Gras /* FIXME: give this a dummy value. */
1304d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1305d65f6f70SBen Gras break;
1306d65f6f70SBen Gras case (LIST_hang):
1307d65f6f70SBen Gras /* FALLTHROUGH */
1308d65f6f70SBen Gras case (LIST_ohang):
1309d65f6f70SBen Gras /* FALLTHROUGH */
1310d65f6f70SBen Gras case (LIST_inset):
1311d65f6f70SBen Gras /* FALLTHROUGH */
1312d65f6f70SBen Gras case (LIST_diag):
1313d65f6f70SBen Gras if (NULL == mdoc->last->head->child)
1314d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
1315d65f6f70SBen Gras break;
1316d65f6f70SBen Gras case (LIST_bullet):
1317d65f6f70SBen Gras /* FALLTHROUGH */
1318d65f6f70SBen Gras case (LIST_dash):
1319d65f6f70SBen Gras /* FALLTHROUGH */
1320d65f6f70SBen Gras case (LIST_enum):
1321d65f6f70SBen Gras /* FALLTHROUGH */
1322d65f6f70SBen Gras case (LIST_hyphen):
1323d65f6f70SBen Gras if (NULL == mdoc->last->body->child)
1324d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1325d65f6f70SBen Gras /* FALLTHROUGH */
1326d65f6f70SBen Gras case (LIST_item):
1327d65f6f70SBen Gras if (mdoc->last->head->child)
1328d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
1329d65f6f70SBen Gras break;
1330d65f6f70SBen Gras case (LIST_column):
1331d65f6f70SBen Gras cols = (int)n->norm->Bl.ncols;
1332d65f6f70SBen Gras
1333d65f6f70SBen Gras assert(NULL == mdoc->last->head->child);
1334d65f6f70SBen Gras
1335d65f6f70SBen Gras if (NULL == mdoc->last->body->child)
1336d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
1337d65f6f70SBen Gras
1338d65f6f70SBen Gras for (i = 0, c = mdoc->last->child; c; c = c->next)
1339d65f6f70SBen Gras if (MDOC_BODY == c->type)
1340d65f6f70SBen Gras i++;
1341d65f6f70SBen Gras
1342d65f6f70SBen Gras if (i < cols)
1343d65f6f70SBen Gras er = MANDOCERR_ARGCOUNT;
1344d65f6f70SBen Gras else if (i == cols || i == cols + 1)
1345d65f6f70SBen Gras break;
1346d65f6f70SBen Gras else
1347d65f6f70SBen Gras er = MANDOCERR_SYNTARGCOUNT;
1348d65f6f70SBen Gras
134992395e9cSLionel Sambuc mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
135092395e9cSLionel Sambuc mdoc->last->pos,
1351d65f6f70SBen Gras "columns == %d (have %d)", cols, i);
135292395e9cSLionel Sambuc return(MANDOCERR_ARGCOUNT == er);
1353d65f6f70SBen Gras default:
1354d65f6f70SBen Gras break;
1355d65f6f70SBen Gras }
1356d65f6f70SBen Gras
1357d65f6f70SBen Gras return(1);
1358d65f6f70SBen Gras }
1359d65f6f70SBen Gras
1360d65f6f70SBen Gras static int
post_bl_block(POST_ARGS)1361d65f6f70SBen Gras post_bl_block(POST_ARGS)
1362d65f6f70SBen Gras {
13630a6a1f1dSLionel Sambuc struct mdoc_node *n, *ni, *nc;
1364d65f6f70SBen Gras
1365d65f6f70SBen Gras /*
1366d65f6f70SBen Gras * These are fairly complicated, so we've broken them into two
1367d65f6f70SBen Gras * functions. post_bl_block_tag() is called when a -tag is
1368d65f6f70SBen Gras * specified, but no -width (it must be guessed). The second
1369d65f6f70SBen Gras * when a -width is specified (macro indicators must be
1370d65f6f70SBen Gras * rewritten into real lengths).
1371d65f6f70SBen Gras */
1372d65f6f70SBen Gras
1373d65f6f70SBen Gras n = mdoc->last;
1374d65f6f70SBen Gras
1375d65f6f70SBen Gras if (LIST_tag == n->norm->Bl.type &&
1376d65f6f70SBen Gras NULL == n->norm->Bl.width) {
1377d65f6f70SBen Gras if ( ! post_bl_block_tag(mdoc))
1378d65f6f70SBen Gras return(0);
13790a6a1f1dSLionel Sambuc assert(n->norm->Bl.width);
1380d65f6f70SBen Gras } else if (NULL != n->norm->Bl.width) {
1381d65f6f70SBen Gras if ( ! post_bl_block_width(mdoc))
1382d65f6f70SBen Gras return(0);
1383d65f6f70SBen Gras assert(n->norm->Bl.width);
13840a6a1f1dSLionel Sambuc }
13850a6a1f1dSLionel Sambuc
13860a6a1f1dSLionel Sambuc for (ni = n->body->child; ni; ni = ni->next) {
13870a6a1f1dSLionel Sambuc if (NULL == ni->body)
13880a6a1f1dSLionel Sambuc continue;
13890a6a1f1dSLionel Sambuc nc = ni->body->last;
13900a6a1f1dSLionel Sambuc while (NULL != nc) {
13910a6a1f1dSLionel Sambuc switch (nc->tok) {
13920a6a1f1dSLionel Sambuc case (MDOC_Pp):
13930a6a1f1dSLionel Sambuc /* FALLTHROUGH */
13940a6a1f1dSLionel Sambuc case (MDOC_Lp):
13950a6a1f1dSLionel Sambuc /* FALLTHROUGH */
13960a6a1f1dSLionel Sambuc case (MDOC_br):
13970a6a1f1dSLionel Sambuc break;
13980a6a1f1dSLionel Sambuc default:
13990a6a1f1dSLionel Sambuc nc = NULL;
14000a6a1f1dSLionel Sambuc continue;
14010a6a1f1dSLionel Sambuc }
14020a6a1f1dSLionel Sambuc if (NULL == ni->next) {
14030a6a1f1dSLionel Sambuc mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR);
14040a6a1f1dSLionel Sambuc if ( ! mdoc_node_relink(mdoc, nc))
14050a6a1f1dSLionel Sambuc return(0);
14060a6a1f1dSLionel Sambuc } else if (0 == n->norm->Bl.comp &&
14070a6a1f1dSLionel Sambuc LIST_column != n->norm->Bl.type) {
14080a6a1f1dSLionel Sambuc mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR);
14090a6a1f1dSLionel Sambuc mdoc_node_delete(mdoc, nc);
14100a6a1f1dSLionel Sambuc } else
14110a6a1f1dSLionel Sambuc break;
14120a6a1f1dSLionel Sambuc nc = ni->body->last;
14130a6a1f1dSLionel Sambuc }
14140a6a1f1dSLionel Sambuc }
1415d65f6f70SBen Gras return(1);
1416d65f6f70SBen Gras }
1417d65f6f70SBen Gras
1418d65f6f70SBen Gras static int
post_bl_block_width(POST_ARGS)1419d65f6f70SBen Gras post_bl_block_width(POST_ARGS)
1420d65f6f70SBen Gras {
1421d65f6f70SBen Gras size_t width;
1422d65f6f70SBen Gras int i;
1423d65f6f70SBen Gras enum mdoct tok;
1424d65f6f70SBen Gras struct mdoc_node *n;
1425d65f6f70SBen Gras char buf[NUMSIZ];
1426d65f6f70SBen Gras
1427d65f6f70SBen Gras n = mdoc->last;
1428d65f6f70SBen Gras
1429d65f6f70SBen Gras /*
1430d65f6f70SBen Gras * Calculate the real width of a list from the -width string,
1431d65f6f70SBen Gras * which may contain a macro (with a known default width), a
1432d65f6f70SBen Gras * literal string, or a scaling width.
1433d65f6f70SBen Gras *
1434d65f6f70SBen Gras * If the value to -width is a macro, then we re-write it to be
1435d65f6f70SBen Gras * the macro's width as set in share/tmac/mdoc/doc-common.
1436d65f6f70SBen Gras */
1437d65f6f70SBen Gras
1438d65f6f70SBen Gras if (0 == strcmp(n->norm->Bl.width, "Ds"))
1439d65f6f70SBen Gras width = 6;
1440d65f6f70SBen Gras else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
1441d65f6f70SBen Gras return(1);
144292395e9cSLionel Sambuc else if (0 == (width = macro2len(tok))) {
1443d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
1444d65f6f70SBen Gras return(1);
1445d65f6f70SBen Gras }
1446d65f6f70SBen Gras
1447d65f6f70SBen Gras /* The value already exists: free and reallocate it. */
1448d65f6f70SBen Gras
1449d65f6f70SBen Gras assert(n->args);
1450d65f6f70SBen Gras
1451d65f6f70SBen Gras for (i = 0; i < (int)n->args->argc; i++)
1452d65f6f70SBen Gras if (MDOC_Width == n->args->argv[i].arg)
1453d65f6f70SBen Gras break;
1454d65f6f70SBen Gras
1455d65f6f70SBen Gras assert(i < (int)n->args->argc);
1456d65f6f70SBen Gras
145792395e9cSLionel Sambuc snprintf(buf, NUMSIZ, "%un", (unsigned int)width);
1458d65f6f70SBen Gras free(n->args->argv[i].value[0]);
1459d65f6f70SBen Gras n->args->argv[i].value[0] = mandoc_strdup(buf);
1460d65f6f70SBen Gras
1461d65f6f70SBen Gras /* Set our width! */
1462d65f6f70SBen Gras n->norm->Bl.width = n->args->argv[i].value[0];
1463d65f6f70SBen Gras return(1);
1464d65f6f70SBen Gras }
1465d65f6f70SBen Gras
1466d65f6f70SBen Gras static int
post_bl_block_tag(POST_ARGS)1467d65f6f70SBen Gras post_bl_block_tag(POST_ARGS)
1468d65f6f70SBen Gras {
1469d65f6f70SBen Gras struct mdoc_node *n, *nn;
1470d65f6f70SBen Gras size_t sz, ssz;
1471d65f6f70SBen Gras int i;
1472d65f6f70SBen Gras char buf[NUMSIZ];
1473d65f6f70SBen Gras
1474d65f6f70SBen Gras /*
1475d65f6f70SBen Gras * Calculate the -width for a `Bl -tag' list if it hasn't been
1476d65f6f70SBen Gras * provided. Uses the first head macro. NOTE AGAIN: this is
1477d65f6f70SBen Gras * ONLY if the -width argument has NOT been provided. See
1478d65f6f70SBen Gras * post_bl_block_width() for converting the -width string.
1479d65f6f70SBen Gras */
1480d65f6f70SBen Gras
1481d65f6f70SBen Gras sz = 10;
1482d65f6f70SBen Gras n = mdoc->last;
1483d65f6f70SBen Gras
1484d65f6f70SBen Gras for (nn = n->body->child; nn; nn = nn->next) {
1485d65f6f70SBen Gras if (MDOC_It != nn->tok)
1486d65f6f70SBen Gras continue;
1487d65f6f70SBen Gras
1488d65f6f70SBen Gras assert(MDOC_BLOCK == nn->type);
1489d65f6f70SBen Gras nn = nn->head->child;
1490d65f6f70SBen Gras
1491d65f6f70SBen Gras if (nn == NULL)
1492d65f6f70SBen Gras break;
1493d65f6f70SBen Gras
1494d65f6f70SBen Gras if (MDOC_TEXT == nn->type) {
1495d65f6f70SBen Gras sz = strlen(nn->string) + 1;
1496d65f6f70SBen Gras break;
1497d65f6f70SBen Gras }
1498d65f6f70SBen Gras
149992395e9cSLionel Sambuc if (0 != (ssz = macro2len(nn->tok)))
1500d65f6f70SBen Gras sz = ssz;
1501d65f6f70SBen Gras
1502d65f6f70SBen Gras break;
1503d65f6f70SBen Gras }
1504d65f6f70SBen Gras
1505d65f6f70SBen Gras /* Defaults to ten ens. */
1506d65f6f70SBen Gras
150792395e9cSLionel Sambuc snprintf(buf, NUMSIZ, "%un", (unsigned int)sz);
1508d65f6f70SBen Gras
1509d65f6f70SBen Gras /*
1510d65f6f70SBen Gras * We have to dynamically add this to the macro's argument list.
1511d65f6f70SBen Gras * We're guaranteed that a MDOC_Width doesn't already exist.
1512d65f6f70SBen Gras */
1513d65f6f70SBen Gras
1514d65f6f70SBen Gras assert(n->args);
1515d65f6f70SBen Gras i = (int)(n->args->argc)++;
1516d65f6f70SBen Gras
1517d65f6f70SBen Gras n->args->argv = mandoc_realloc(n->args->argv,
1518d65f6f70SBen Gras n->args->argc * sizeof(struct mdoc_argv));
1519d65f6f70SBen Gras
1520d65f6f70SBen Gras n->args->argv[i].arg = MDOC_Width;
1521d65f6f70SBen Gras n->args->argv[i].line = n->line;
1522d65f6f70SBen Gras n->args->argv[i].pos = n->pos;
1523d65f6f70SBen Gras n->args->argv[i].sz = 1;
1524d65f6f70SBen Gras n->args->argv[i].value = mandoc_malloc(sizeof(char *));
1525d65f6f70SBen Gras n->args->argv[i].value[0] = mandoc_strdup(buf);
1526d65f6f70SBen Gras
1527d65f6f70SBen Gras /* Set our width! */
1528d65f6f70SBen Gras n->norm->Bl.width = n->args->argv[i].value[0];
1529d65f6f70SBen Gras return(1);
1530d65f6f70SBen Gras }
1531d65f6f70SBen Gras
1532d65f6f70SBen Gras
1533d65f6f70SBen Gras static int
post_bl_head(POST_ARGS)1534d65f6f70SBen Gras post_bl_head(POST_ARGS)
1535d65f6f70SBen Gras {
1536d65f6f70SBen Gras struct mdoc_node *np, *nn, *nnp;
1537d65f6f70SBen Gras int i, j;
1538d65f6f70SBen Gras
1539d65f6f70SBen Gras if (LIST_column != mdoc->last->norm->Bl.type)
1540d65f6f70SBen Gras /* FIXME: this should be ERROR class... */
1541d65f6f70SBen Gras return(hwarn_eq0(mdoc));
1542d65f6f70SBen Gras
1543d65f6f70SBen Gras /*
1544d65f6f70SBen Gras * Convert old-style lists, where the column width specifiers
1545d65f6f70SBen Gras * trail as macro parameters, to the new-style ("normal-form")
1546d65f6f70SBen Gras * lists where they're argument values following -column.
1547d65f6f70SBen Gras */
1548d65f6f70SBen Gras
1549d65f6f70SBen Gras /* First, disallow both types and allow normal-form. */
1550d65f6f70SBen Gras
1551d65f6f70SBen Gras /*
1552d65f6f70SBen Gras * TODO: technically, we can accept both and just merge the two
1553d65f6f70SBen Gras * lists, but I'll leave that for another day.
1554d65f6f70SBen Gras */
1555d65f6f70SBen Gras
1556d65f6f70SBen Gras if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
1557d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
1558d65f6f70SBen Gras return(0);
1559d65f6f70SBen Gras } else if (NULL == mdoc->last->child)
1560d65f6f70SBen Gras return(1);
1561d65f6f70SBen Gras
1562d65f6f70SBen Gras np = mdoc->last->parent;
1563d65f6f70SBen Gras assert(np->args);
1564d65f6f70SBen Gras
1565d65f6f70SBen Gras for (j = 0; j < (int)np->args->argc; j++)
1566d65f6f70SBen Gras if (MDOC_Column == np->args->argv[j].arg)
1567d65f6f70SBen Gras break;
1568d65f6f70SBen Gras
1569d65f6f70SBen Gras assert(j < (int)np->args->argc);
1570d65f6f70SBen Gras assert(0 == np->args->argv[j].sz);
1571d65f6f70SBen Gras
1572d65f6f70SBen Gras /*
157392395e9cSLionel Sambuc * Accommodate for new-style groff column syntax. Shuffle the
1574d65f6f70SBen Gras * child nodes, all of which must be TEXT, as arguments for the
1575d65f6f70SBen Gras * column field. Then, delete the head children.
1576d65f6f70SBen Gras */
1577d65f6f70SBen Gras
1578d65f6f70SBen Gras np->args->argv[j].sz = (size_t)mdoc->last->nchild;
1579d65f6f70SBen Gras np->args->argv[j].value = mandoc_malloc
1580d65f6f70SBen Gras ((size_t)mdoc->last->nchild * sizeof(char *));
1581d65f6f70SBen Gras
1582d65f6f70SBen Gras mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
158392395e9cSLionel Sambuc mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
1584d65f6f70SBen Gras
1585d65f6f70SBen Gras for (i = 0, nn = mdoc->last->child; nn; i++) {
1586d65f6f70SBen Gras np->args->argv[j].value[i] = nn->string;
1587d65f6f70SBen Gras nn->string = NULL;
1588d65f6f70SBen Gras nnp = nn;
1589d65f6f70SBen Gras nn = nn->next;
1590d65f6f70SBen Gras mdoc_node_delete(NULL, nnp);
1591d65f6f70SBen Gras }
1592d65f6f70SBen Gras
1593d65f6f70SBen Gras mdoc->last->nchild = 0;
1594d65f6f70SBen Gras mdoc->last->child = NULL;
1595d65f6f70SBen Gras
1596d65f6f70SBen Gras return(1);
1597d65f6f70SBen Gras }
1598d65f6f70SBen Gras
1599d65f6f70SBen Gras static int
post_bl(POST_ARGS)1600d65f6f70SBen Gras post_bl(POST_ARGS)
1601d65f6f70SBen Gras {
16020a6a1f1dSLionel Sambuc struct mdoc_node *nparent, *nprev; /* of the Bl block */
16030a6a1f1dSLionel Sambuc struct mdoc_node *nblock, *nbody; /* of the Bl */
16040a6a1f1dSLionel Sambuc struct mdoc_node *nchild, *nnext; /* of the Bl body */
1605d65f6f70SBen Gras
16060a6a1f1dSLionel Sambuc nbody = mdoc->last;
16070a6a1f1dSLionel Sambuc switch (nbody->type) {
16080a6a1f1dSLionel Sambuc case (MDOC_BLOCK):
1609d65f6f70SBen Gras return(post_bl_block(mdoc));
16100a6a1f1dSLionel Sambuc case (MDOC_HEAD):
16110a6a1f1dSLionel Sambuc return(post_bl_head(mdoc));
16120a6a1f1dSLionel Sambuc case (MDOC_BODY):
1613d65f6f70SBen Gras break;
16140a6a1f1dSLionel Sambuc default:
16150a6a1f1dSLionel Sambuc return(1);
1616d65f6f70SBen Gras }
1617d65f6f70SBen Gras
16180a6a1f1dSLionel Sambuc nchild = nbody->child;
16190a6a1f1dSLionel Sambuc while (NULL != nchild) {
16200a6a1f1dSLionel Sambuc if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
16210a6a1f1dSLionel Sambuc nchild = nchild->next;
16220a6a1f1dSLionel Sambuc continue;
16230a6a1f1dSLionel Sambuc }
16240a6a1f1dSLionel Sambuc
16250a6a1f1dSLionel Sambuc mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
16260a6a1f1dSLionel Sambuc
16270a6a1f1dSLionel Sambuc /*
16280a6a1f1dSLionel Sambuc * Move the node out of the Bl block.
16290a6a1f1dSLionel Sambuc * First, collect all required node pointers.
16300a6a1f1dSLionel Sambuc */
16310a6a1f1dSLionel Sambuc
16320a6a1f1dSLionel Sambuc nblock = nbody->parent;
16330a6a1f1dSLionel Sambuc nprev = nblock->prev;
16340a6a1f1dSLionel Sambuc nparent = nblock->parent;
16350a6a1f1dSLionel Sambuc nnext = nchild->next;
16360a6a1f1dSLionel Sambuc
16370a6a1f1dSLionel Sambuc /*
16380a6a1f1dSLionel Sambuc * Unlink this child.
16390a6a1f1dSLionel Sambuc */
16400a6a1f1dSLionel Sambuc
16410a6a1f1dSLionel Sambuc assert(NULL == nchild->prev);
16420a6a1f1dSLionel Sambuc if (0 == --nbody->nchild) {
16430a6a1f1dSLionel Sambuc nbody->child = NULL;
16440a6a1f1dSLionel Sambuc nbody->last = NULL;
16450a6a1f1dSLionel Sambuc assert(NULL == nnext);
16460a6a1f1dSLionel Sambuc } else {
16470a6a1f1dSLionel Sambuc nbody->child = nnext;
16480a6a1f1dSLionel Sambuc nnext->prev = NULL;
16490a6a1f1dSLionel Sambuc }
16500a6a1f1dSLionel Sambuc
16510a6a1f1dSLionel Sambuc /*
16520a6a1f1dSLionel Sambuc * Relink this child.
16530a6a1f1dSLionel Sambuc */
16540a6a1f1dSLionel Sambuc
16550a6a1f1dSLionel Sambuc nchild->parent = nparent;
16560a6a1f1dSLionel Sambuc nchild->prev = nprev;
16570a6a1f1dSLionel Sambuc nchild->next = nblock;
16580a6a1f1dSLionel Sambuc
16590a6a1f1dSLionel Sambuc nblock->prev = nchild;
16600a6a1f1dSLionel Sambuc nparent->nchild++;
16610a6a1f1dSLionel Sambuc if (NULL == nprev)
16620a6a1f1dSLionel Sambuc nparent->child = nchild;
16630a6a1f1dSLionel Sambuc else
16640a6a1f1dSLionel Sambuc nprev->next = nchild;
16650a6a1f1dSLionel Sambuc
16660a6a1f1dSLionel Sambuc nchild = nnext;
1667d65f6f70SBen Gras }
1668d65f6f70SBen Gras
1669d65f6f70SBen Gras return(1);
1670d65f6f70SBen Gras }
1671d65f6f70SBen Gras
1672d65f6f70SBen Gras static int
ebool(struct mdoc * mdoc)1673d65f6f70SBen Gras ebool(struct mdoc *mdoc)
1674d65f6f70SBen Gras {
1675d65f6f70SBen Gras
1676d65f6f70SBen Gras if (NULL == mdoc->last->child) {
1677d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1678d65f6f70SBen Gras mdoc_node_delete(mdoc, mdoc->last);
1679d65f6f70SBen Gras return(1);
1680d65f6f70SBen Gras }
1681d65f6f70SBen Gras check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
1682d65f6f70SBen Gras
1683d65f6f70SBen Gras assert(MDOC_TEXT == mdoc->last->child->type);
1684d65f6f70SBen Gras
16850a6a1f1dSLionel Sambuc if (0 == strcmp(mdoc->last->child->string, "on")) {
16860a6a1f1dSLionel Sambuc if (MDOC_Sm == mdoc->last->tok)
16870a6a1f1dSLionel Sambuc mdoc->flags &= ~MDOC_SMOFF;
1688d65f6f70SBen Gras return(1);
16890a6a1f1dSLionel Sambuc }
16900a6a1f1dSLionel Sambuc if (0 == strcmp(mdoc->last->child->string, "off")) {
16910a6a1f1dSLionel Sambuc if (MDOC_Sm == mdoc->last->tok)
16920a6a1f1dSLionel Sambuc mdoc->flags |= MDOC_SMOFF;
1693d65f6f70SBen Gras return(1);
16940a6a1f1dSLionel Sambuc }
1695d65f6f70SBen Gras
1696d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
1697d65f6f70SBen Gras return(1);
1698d65f6f70SBen Gras }
1699d65f6f70SBen Gras
1700d65f6f70SBen Gras static int
post_root(POST_ARGS)1701d65f6f70SBen Gras post_root(POST_ARGS)
1702d65f6f70SBen Gras {
1703d65f6f70SBen Gras int erc;
1704d65f6f70SBen Gras struct mdoc_node *n;
1705d65f6f70SBen Gras
1706d65f6f70SBen Gras erc = 0;
1707d65f6f70SBen Gras
1708d65f6f70SBen Gras /* Check that we have a finished prologue. */
1709d65f6f70SBen Gras
1710d65f6f70SBen Gras if ( ! (MDOC_PBODY & mdoc->flags)) {
1711d65f6f70SBen Gras erc++;
1712d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
1713d65f6f70SBen Gras }
1714d65f6f70SBen Gras
1715d65f6f70SBen Gras n = mdoc->first;
1716d65f6f70SBen Gras assert(n);
1717d65f6f70SBen Gras
1718d65f6f70SBen Gras /* Check that we begin with a proper `Sh'. */
1719d65f6f70SBen Gras
1720d65f6f70SBen Gras if (NULL == n->child) {
1721d65f6f70SBen Gras erc++;
1722d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
1723d65f6f70SBen Gras } else if (MDOC_BLOCK != n->child->type ||
1724d65f6f70SBen Gras MDOC_Sh != n->child->tok) {
1725d65f6f70SBen Gras erc++;
1726d65f6f70SBen Gras /* Can this be lifted? See rxdebug.1 for example. */
1727d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
1728d65f6f70SBen Gras }
1729d65f6f70SBen Gras
1730d65f6f70SBen Gras return(erc ? 0 : 1);
1731d65f6f70SBen Gras }
1732d65f6f70SBen Gras
1733d65f6f70SBen Gras static int
post_st(POST_ARGS)1734d65f6f70SBen Gras post_st(POST_ARGS)
1735d65f6f70SBen Gras {
1736d65f6f70SBen Gras struct mdoc_node *ch;
1737d65f6f70SBen Gras const char *p;
1738d65f6f70SBen Gras
1739d65f6f70SBen Gras if (NULL == (ch = mdoc->last->child)) {
1740d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
1741d65f6f70SBen Gras mdoc_node_delete(mdoc, mdoc->last);
1742d65f6f70SBen Gras return(1);
1743d65f6f70SBen Gras }
1744d65f6f70SBen Gras
1745d65f6f70SBen Gras assert(MDOC_TEXT == ch->type);
1746d65f6f70SBen Gras
1747d65f6f70SBen Gras if (NULL == (p = mdoc_a2st(ch->string))) {
1748d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
1749d65f6f70SBen Gras mdoc_node_delete(mdoc, mdoc->last);
1750d65f6f70SBen Gras } else {
1751d65f6f70SBen Gras free(ch->string);
1752d65f6f70SBen Gras ch->string = mandoc_strdup(p);
1753d65f6f70SBen Gras }
1754d65f6f70SBen Gras
1755d65f6f70SBen Gras return(1);
1756d65f6f70SBen Gras }
1757d65f6f70SBen Gras
1758d65f6f70SBen Gras static int
post_rs(POST_ARGS)1759d65f6f70SBen Gras post_rs(POST_ARGS)
1760d65f6f70SBen Gras {
1761d65f6f70SBen Gras struct mdoc_node *nn, *next, *prev;
1762d65f6f70SBen Gras int i, j;
1763d65f6f70SBen Gras
1764d65f6f70SBen Gras switch (mdoc->last->type) {
1765d65f6f70SBen Gras case (MDOC_HEAD):
1766d65f6f70SBen Gras check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
1767d65f6f70SBen Gras return(1);
1768d65f6f70SBen Gras case (MDOC_BODY):
1769d65f6f70SBen Gras if (mdoc->last->child)
1770d65f6f70SBen Gras break;
1771d65f6f70SBen Gras check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
1772d65f6f70SBen Gras return(1);
1773d65f6f70SBen Gras default:
1774d65f6f70SBen Gras return(1);
1775d65f6f70SBen Gras }
1776d65f6f70SBen Gras
1777d65f6f70SBen Gras /*
1778d65f6f70SBen Gras * Make sure only certain types of nodes are allowed within the
1779d65f6f70SBen Gras * the `Rs' body. Delete offending nodes and raise a warning.
1780d65f6f70SBen Gras * Do this before re-ordering for the sake of clarity.
1781d65f6f70SBen Gras */
1782d65f6f70SBen Gras
1783d65f6f70SBen Gras next = NULL;
1784d65f6f70SBen Gras for (nn = mdoc->last->child; nn; nn = next) {
1785d65f6f70SBen Gras for (i = 0; i < RSORD_MAX; i++)
1786d65f6f70SBen Gras if (nn->tok == rsord[i])
1787d65f6f70SBen Gras break;
1788d65f6f70SBen Gras
1789d65f6f70SBen Gras if (i < RSORD_MAX) {
179092395e9cSLionel Sambuc if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
179192395e9cSLionel Sambuc mdoc->last->norm->Rs.quote_T++;
1792d65f6f70SBen Gras next = nn->next;
1793d65f6f70SBen Gras continue;
1794d65f6f70SBen Gras }
1795d65f6f70SBen Gras
1796d65f6f70SBen Gras next = nn->next;
1797d65f6f70SBen Gras mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD);
1798d65f6f70SBen Gras mdoc_node_delete(mdoc, nn);
1799d65f6f70SBen Gras }
1800d65f6f70SBen Gras
1801d65f6f70SBen Gras /*
180292395e9cSLionel Sambuc * Nothing to sort if only invalid nodes were found
180392395e9cSLionel Sambuc * inside the `Rs' body.
180492395e9cSLionel Sambuc */
180592395e9cSLionel Sambuc
180692395e9cSLionel Sambuc if (NULL == mdoc->last->child)
180792395e9cSLionel Sambuc return(1);
180892395e9cSLionel Sambuc
180992395e9cSLionel Sambuc /*
1810d65f6f70SBen Gras * The full `Rs' block needs special handling to order the
1811d65f6f70SBen Gras * sub-elements according to `rsord'. Pick through each element
1812d65f6f70SBen Gras * and correctly order it. This is a insertion sort.
1813d65f6f70SBen Gras */
1814d65f6f70SBen Gras
1815d65f6f70SBen Gras next = NULL;
1816d65f6f70SBen Gras for (nn = mdoc->last->child->next; nn; nn = next) {
1817d65f6f70SBen Gras /* Determine order of `nn'. */
1818d65f6f70SBen Gras for (i = 0; i < RSORD_MAX; i++)
1819d65f6f70SBen Gras if (rsord[i] == nn->tok)
1820d65f6f70SBen Gras break;
1821d65f6f70SBen Gras
1822d65f6f70SBen Gras /*
1823d65f6f70SBen Gras * Remove `nn' from the chain. This somewhat
1824d65f6f70SBen Gras * repeats mdoc_node_unlink(), but since we're
1825d65f6f70SBen Gras * just re-ordering, there's no need for the
1826d65f6f70SBen Gras * full unlink process.
1827d65f6f70SBen Gras */
1828d65f6f70SBen Gras
1829d65f6f70SBen Gras if (NULL != (next = nn->next))
1830d65f6f70SBen Gras next->prev = nn->prev;
1831d65f6f70SBen Gras
1832d65f6f70SBen Gras if (NULL != (prev = nn->prev))
1833d65f6f70SBen Gras prev->next = nn->next;
1834d65f6f70SBen Gras
1835d65f6f70SBen Gras nn->prev = nn->next = NULL;
1836d65f6f70SBen Gras
1837d65f6f70SBen Gras /*
1838d65f6f70SBen Gras * Scan back until we reach a node that's
1839d65f6f70SBen Gras * ordered before `nn'.
1840d65f6f70SBen Gras */
1841d65f6f70SBen Gras
1842d65f6f70SBen Gras for ( ; prev ; prev = prev->prev) {
1843d65f6f70SBen Gras /* Determine order of `prev'. */
1844d65f6f70SBen Gras for (j = 0; j < RSORD_MAX; j++)
1845d65f6f70SBen Gras if (rsord[j] == prev->tok)
1846d65f6f70SBen Gras break;
1847d65f6f70SBen Gras
1848d65f6f70SBen Gras if (j <= i)
1849d65f6f70SBen Gras break;
1850d65f6f70SBen Gras }
1851d65f6f70SBen Gras
1852d65f6f70SBen Gras /*
1853d65f6f70SBen Gras * Set `nn' back into its correct place in front
1854d65f6f70SBen Gras * of the `prev' node.
1855d65f6f70SBen Gras */
1856d65f6f70SBen Gras
1857d65f6f70SBen Gras nn->prev = prev;
1858d65f6f70SBen Gras
1859d65f6f70SBen Gras if (prev) {
1860d65f6f70SBen Gras if (prev->next)
1861d65f6f70SBen Gras prev->next->prev = nn;
1862d65f6f70SBen Gras nn->next = prev->next;
1863d65f6f70SBen Gras prev->next = nn;
1864d65f6f70SBen Gras } else {
1865d65f6f70SBen Gras mdoc->last->child->prev = nn;
1866d65f6f70SBen Gras nn->next = mdoc->last->child;
1867d65f6f70SBen Gras mdoc->last->child = nn;
1868d65f6f70SBen Gras }
1869d65f6f70SBen Gras }
1870d65f6f70SBen Gras
1871d65f6f70SBen Gras return(1);
1872d65f6f70SBen Gras }
1873d65f6f70SBen Gras
18740a6a1f1dSLionel Sambuc /*
18750a6a1f1dSLionel Sambuc * For some arguments of some macros,
18760a6a1f1dSLionel Sambuc * convert all breakable hyphens into ASCII_HYPH.
18770a6a1f1dSLionel Sambuc */
18780a6a1f1dSLionel Sambuc static int
post_hyph(POST_ARGS)18790a6a1f1dSLionel Sambuc post_hyph(POST_ARGS)
18800a6a1f1dSLionel Sambuc {
18810a6a1f1dSLionel Sambuc struct mdoc_node *n, *nch;
18820a6a1f1dSLionel Sambuc char *cp;
18830a6a1f1dSLionel Sambuc
18840a6a1f1dSLionel Sambuc n = mdoc->last;
18850a6a1f1dSLionel Sambuc switch (n->type) {
18860a6a1f1dSLionel Sambuc case (MDOC_HEAD):
18870a6a1f1dSLionel Sambuc if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
18880a6a1f1dSLionel Sambuc break;
18890a6a1f1dSLionel Sambuc return(1);
18900a6a1f1dSLionel Sambuc case (MDOC_BODY):
18910a6a1f1dSLionel Sambuc if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
18920a6a1f1dSLionel Sambuc break;
18930a6a1f1dSLionel Sambuc return(1);
18940a6a1f1dSLionel Sambuc case (MDOC_ELEM):
18950a6a1f1dSLionel Sambuc break;
18960a6a1f1dSLionel Sambuc default:
18970a6a1f1dSLionel Sambuc return(1);
18980a6a1f1dSLionel Sambuc }
18990a6a1f1dSLionel Sambuc
19000a6a1f1dSLionel Sambuc for (nch = n->child; nch; nch = nch->next) {
19010a6a1f1dSLionel Sambuc if (MDOC_TEXT != nch->type)
19020a6a1f1dSLionel Sambuc continue;
19030a6a1f1dSLionel Sambuc cp = nch->string;
19040a6a1f1dSLionel Sambuc if (3 > strnlen(cp, 3))
19050a6a1f1dSLionel Sambuc continue;
19060a6a1f1dSLionel Sambuc while ('\0' != *(++cp))
19070a6a1f1dSLionel Sambuc if ('-' == *cp &&
19080a6a1f1dSLionel Sambuc isalpha((unsigned char)cp[-1]) &&
19090a6a1f1dSLionel Sambuc isalpha((unsigned char)cp[1]))
19100a6a1f1dSLionel Sambuc *cp = ASCII_HYPH;
19110a6a1f1dSLionel Sambuc }
19120a6a1f1dSLionel Sambuc return(1);
19130a6a1f1dSLionel Sambuc }
19140a6a1f1dSLionel Sambuc
1915d65f6f70SBen Gras static int
post_ns(POST_ARGS)191692395e9cSLionel Sambuc post_ns(POST_ARGS)
191792395e9cSLionel Sambuc {
191892395e9cSLionel Sambuc
191992395e9cSLionel Sambuc if (MDOC_LINE & mdoc->last->flags)
192092395e9cSLionel Sambuc mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
192192395e9cSLionel Sambuc return(1);
192292395e9cSLionel Sambuc }
192392395e9cSLionel Sambuc
192492395e9cSLionel Sambuc static int
post_sh(POST_ARGS)1925d65f6f70SBen Gras post_sh(POST_ARGS)
1926d65f6f70SBen Gras {
1927d65f6f70SBen Gras
1928d65f6f70SBen Gras if (MDOC_HEAD == mdoc->last->type)
1929d65f6f70SBen Gras return(post_sh_head(mdoc));
1930d65f6f70SBen Gras if (MDOC_BODY == mdoc->last->type)
1931d65f6f70SBen Gras return(post_sh_body(mdoc));
1932d65f6f70SBen Gras
1933d65f6f70SBen Gras return(1);
1934d65f6f70SBen Gras }
1935d65f6f70SBen Gras
1936d65f6f70SBen Gras static int
post_sh_body(POST_ARGS)1937d65f6f70SBen Gras post_sh_body(POST_ARGS)
1938d65f6f70SBen Gras {
1939d65f6f70SBen Gras struct mdoc_node *n;
1940d65f6f70SBen Gras
1941d65f6f70SBen Gras if (SEC_NAME != mdoc->lastsec)
1942d65f6f70SBen Gras return(1);
1943d65f6f70SBen Gras
1944d65f6f70SBen Gras /*
1945d65f6f70SBen Gras * Warn if the NAME section doesn't contain the `Nm' and `Nd'
1946d65f6f70SBen Gras * macros (can have multiple `Nm' and one `Nd'). Note that the
1947d65f6f70SBen Gras * children of the BODY declaration can also be "text".
1948d65f6f70SBen Gras */
1949d65f6f70SBen Gras
1950d65f6f70SBen Gras if (NULL == (n = mdoc->last->child)) {
1951d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1952d65f6f70SBen Gras return(1);
1953d65f6f70SBen Gras }
1954d65f6f70SBen Gras
1955d65f6f70SBen Gras for ( ; n && n->next; n = n->next) {
1956d65f6f70SBen Gras if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
1957d65f6f70SBen Gras continue;
1958d65f6f70SBen Gras if (MDOC_TEXT == n->type)
1959d65f6f70SBen Gras continue;
1960d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1961d65f6f70SBen Gras }
1962d65f6f70SBen Gras
1963d65f6f70SBen Gras assert(n);
1964d65f6f70SBen Gras if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
1965d65f6f70SBen Gras return(1);
1966d65f6f70SBen Gras
1967d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
1968d65f6f70SBen Gras return(1);
1969d65f6f70SBen Gras }
1970d65f6f70SBen Gras
1971d65f6f70SBen Gras static int
post_sh_head(POST_ARGS)1972d65f6f70SBen Gras post_sh_head(POST_ARGS)
1973d65f6f70SBen Gras {
1974d65f6f70SBen Gras char buf[BUFSIZ];
197592395e9cSLionel Sambuc struct mdoc_node *n;
1976d65f6f70SBen Gras enum mdoc_sec sec;
197792395e9cSLionel Sambuc int c;
1978d65f6f70SBen Gras
1979d65f6f70SBen Gras /*
1980d65f6f70SBen Gras * Process a new section. Sections are either "named" or
1981d65f6f70SBen Gras * "custom". Custom sections are user-defined, while named ones
1982d65f6f70SBen Gras * follow a conventional order and may only appear in certain
1983d65f6f70SBen Gras * manual sections.
1984d65f6f70SBen Gras */
1985d65f6f70SBen Gras
198692395e9cSLionel Sambuc sec = SEC_CUSTOM;
198792395e9cSLionel Sambuc buf[0] = '\0';
198892395e9cSLionel Sambuc if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
198992395e9cSLionel Sambuc mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
1990d65f6f70SBen Gras return(0);
199192395e9cSLionel Sambuc } else if (1 == c)
199292395e9cSLionel Sambuc sec = a2sec(buf);
1993d65f6f70SBen Gras
1994d65f6f70SBen Gras /* The NAME should be first. */
1995d65f6f70SBen Gras
1996d65f6f70SBen Gras if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
1997d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
1998d65f6f70SBen Gras
1999d65f6f70SBen Gras /* The SYNOPSIS gets special attention in other areas. */
2000d65f6f70SBen Gras
20010a6a1f1dSLionel Sambuc if (SEC_SYNOPSIS == sec) {
20020a6a1f1dSLionel Sambuc roff_setreg(mdoc->roff, "nS", 1, '=');
2003d65f6f70SBen Gras mdoc->flags |= MDOC_SYNOPSIS;
20040a6a1f1dSLionel Sambuc } else {
20050a6a1f1dSLionel Sambuc roff_setreg(mdoc->roff, "nS", 0, '=');
2006d65f6f70SBen Gras mdoc->flags &= ~MDOC_SYNOPSIS;
20070a6a1f1dSLionel Sambuc }
2008d65f6f70SBen Gras
2009d65f6f70SBen Gras /* Mark our last section. */
2010d65f6f70SBen Gras
2011d65f6f70SBen Gras mdoc->lastsec = sec;
2012d65f6f70SBen Gras
201392395e9cSLionel Sambuc /*
201492395e9cSLionel Sambuc * Set the section attribute for the current HEAD, for its
201592395e9cSLionel Sambuc * parent BLOCK, and for the HEAD children; the latter can
201692395e9cSLionel Sambuc * only be TEXT nodes, so no recursion is needed.
201792395e9cSLionel Sambuc * For other blocks and elements, including .Sh BODY, this is
201892395e9cSLionel Sambuc * done when allocating the node data structures, but for .Sh
201992395e9cSLionel Sambuc * BLOCK and HEAD, the section is still unknown at that time.
202092395e9cSLionel Sambuc */
202192395e9cSLionel Sambuc
202292395e9cSLionel Sambuc mdoc->last->parent->sec = sec;
202392395e9cSLionel Sambuc mdoc->last->sec = sec;
202492395e9cSLionel Sambuc for (n = mdoc->last->child; n; n = n->next)
202592395e9cSLionel Sambuc n->sec = sec;
202692395e9cSLionel Sambuc
2027d65f6f70SBen Gras /* We don't care about custom sections after this. */
2028d65f6f70SBen Gras
2029d65f6f70SBen Gras if (SEC_CUSTOM == sec)
2030d65f6f70SBen Gras return(1);
2031d65f6f70SBen Gras
2032d65f6f70SBen Gras /*
2033d65f6f70SBen Gras * Check whether our non-custom section is being repeated or is
2034d65f6f70SBen Gras * out of order.
2035d65f6f70SBen Gras */
2036d65f6f70SBen Gras
2037d65f6f70SBen Gras if (sec == mdoc->lastnamed)
2038d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP);
2039d65f6f70SBen Gras
2040d65f6f70SBen Gras if (sec < mdoc->lastnamed)
2041d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO);
2042d65f6f70SBen Gras
2043d65f6f70SBen Gras /* Mark the last named section. */
2044d65f6f70SBen Gras
2045d65f6f70SBen Gras mdoc->lastnamed = sec;
2046d65f6f70SBen Gras
2047d65f6f70SBen Gras /* Check particular section/manual conventions. */
2048d65f6f70SBen Gras
2049d65f6f70SBen Gras assert(mdoc->meta.msec);
2050d65f6f70SBen Gras
2051d65f6f70SBen Gras switch (sec) {
2052d65f6f70SBen Gras case (SEC_RETURN_VALUES):
2053d65f6f70SBen Gras /* FALLTHROUGH */
2054d65f6f70SBen Gras case (SEC_ERRORS):
2055d65f6f70SBen Gras /* FALLTHROUGH */
2056d65f6f70SBen Gras case (SEC_LIBRARY):
2057d65f6f70SBen Gras if (*mdoc->meta.msec == '2')
2058d65f6f70SBen Gras break;
2059d65f6f70SBen Gras if (*mdoc->meta.msec == '3')
2060d65f6f70SBen Gras break;
2061d65f6f70SBen Gras if (*mdoc->meta.msec == '9')
2062d65f6f70SBen Gras break;
20630a6a1f1dSLionel Sambuc mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse,
20640a6a1f1dSLionel Sambuc mdoc->last->line, mdoc->last->pos, buf);
2065d65f6f70SBen Gras break;
2066d65f6f70SBen Gras default:
2067d65f6f70SBen Gras break;
2068d65f6f70SBen Gras }
2069d65f6f70SBen Gras
2070d65f6f70SBen Gras return(1);
2071d65f6f70SBen Gras }
2072d65f6f70SBen Gras
2073d65f6f70SBen Gras static int
post_ignpar(POST_ARGS)2074d65f6f70SBen Gras post_ignpar(POST_ARGS)
2075d65f6f70SBen Gras {
2076d65f6f70SBen Gras struct mdoc_node *np;
2077d65f6f70SBen Gras
2078d65f6f70SBen Gras if (MDOC_BODY != mdoc->last->type)
2079d65f6f70SBen Gras return(1);
2080d65f6f70SBen Gras
2081d65f6f70SBen Gras if (NULL != (np = mdoc->last->child))
2082d65f6f70SBen Gras if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2083d65f6f70SBen Gras mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
2084d65f6f70SBen Gras mdoc_node_delete(mdoc, np);
2085d65f6f70SBen Gras }
2086d65f6f70SBen Gras
2087d65f6f70SBen Gras if (NULL != (np = mdoc->last->last))
2088d65f6f70SBen Gras if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
2089d65f6f70SBen Gras mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
2090d65f6f70SBen Gras mdoc_node_delete(mdoc, np);
2091d65f6f70SBen Gras }
2092d65f6f70SBen Gras
2093d65f6f70SBen Gras return(1);
2094d65f6f70SBen Gras }
2095d65f6f70SBen Gras
2096d65f6f70SBen Gras static int
pre_par(PRE_ARGS)2097d65f6f70SBen Gras pre_par(PRE_ARGS)
2098d65f6f70SBen Gras {
2099d65f6f70SBen Gras
2100d65f6f70SBen Gras if (NULL == mdoc->last)
2101d65f6f70SBen Gras return(1);
2102d65f6f70SBen Gras if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
2103d65f6f70SBen Gras return(1);
2104d65f6f70SBen Gras
2105d65f6f70SBen Gras /*
2106d65f6f70SBen Gras * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
2107d65f6f70SBen Gras * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
2108d65f6f70SBen Gras */
2109d65f6f70SBen Gras
21100a6a1f1dSLionel Sambuc if (MDOC_Pp != mdoc->last->tok &&
21110a6a1f1dSLionel Sambuc MDOC_Lp != mdoc->last->tok &&
21120a6a1f1dSLionel Sambuc MDOC_br != mdoc->last->tok)
2113d65f6f70SBen Gras return(1);
2114d65f6f70SBen Gras if (MDOC_Bl == n->tok && n->norm->Bl.comp)
2115d65f6f70SBen Gras return(1);
2116d65f6f70SBen Gras if (MDOC_Bd == n->tok && n->norm->Bd.comp)
2117d65f6f70SBen Gras return(1);
2118d65f6f70SBen Gras if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
2119d65f6f70SBen Gras return(1);
2120d65f6f70SBen Gras
2121d65f6f70SBen Gras mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
2122d65f6f70SBen Gras mdoc_node_delete(mdoc, mdoc->last);
2123d65f6f70SBen Gras return(1);
2124d65f6f70SBen Gras }
2125d65f6f70SBen Gras
2126d65f6f70SBen Gras static int
post_par(POST_ARGS)21270a6a1f1dSLionel Sambuc post_par(POST_ARGS)
21280a6a1f1dSLionel Sambuc {
21290a6a1f1dSLionel Sambuc
21300a6a1f1dSLionel Sambuc if (MDOC_ELEM != mdoc->last->type &&
21310a6a1f1dSLionel Sambuc MDOC_BLOCK != mdoc->last->type)
21320a6a1f1dSLionel Sambuc return(1);
21330a6a1f1dSLionel Sambuc
21340a6a1f1dSLionel Sambuc if (NULL == mdoc->last->prev) {
21350a6a1f1dSLionel Sambuc if (MDOC_Sh != mdoc->last->parent->tok &&
21360a6a1f1dSLionel Sambuc MDOC_Ss != mdoc->last->parent->tok)
21370a6a1f1dSLionel Sambuc return(1);
21380a6a1f1dSLionel Sambuc } else {
21390a6a1f1dSLionel Sambuc if (MDOC_Pp != mdoc->last->prev->tok &&
21400a6a1f1dSLionel Sambuc MDOC_Lp != mdoc->last->prev->tok &&
21410a6a1f1dSLionel Sambuc (MDOC_br != mdoc->last->tok ||
21420a6a1f1dSLionel Sambuc (MDOC_sp != mdoc->last->prev->tok &&
21430a6a1f1dSLionel Sambuc MDOC_br != mdoc->last->prev->tok)))
21440a6a1f1dSLionel Sambuc return(1);
21450a6a1f1dSLionel Sambuc }
21460a6a1f1dSLionel Sambuc
21470a6a1f1dSLionel Sambuc mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
21480a6a1f1dSLionel Sambuc mdoc_node_delete(mdoc, mdoc->last);
21490a6a1f1dSLionel Sambuc return(1);
21500a6a1f1dSLionel Sambuc }
21510a6a1f1dSLionel Sambuc
21520a6a1f1dSLionel Sambuc static int
pre_literal(PRE_ARGS)2153d65f6f70SBen Gras pre_literal(PRE_ARGS)
2154d65f6f70SBen Gras {
2155d65f6f70SBen Gras
2156d65f6f70SBen Gras if (MDOC_BODY != n->type)
2157d65f6f70SBen Gras return(1);
2158d65f6f70SBen Gras
2159d65f6f70SBen Gras /*
2160d65f6f70SBen Gras * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
2161d65f6f70SBen Gras * -unfilled' macros set MDOC_LITERAL on entrance to the body.
2162d65f6f70SBen Gras */
2163d65f6f70SBen Gras
2164d65f6f70SBen Gras switch (n->tok) {
2165d65f6f70SBen Gras case (MDOC_Dl):
2166d65f6f70SBen Gras mdoc->flags |= MDOC_LITERAL;
2167d65f6f70SBen Gras break;
2168d65f6f70SBen Gras case (MDOC_Bd):
2169d65f6f70SBen Gras if (DISP_literal == n->norm->Bd.type)
2170d65f6f70SBen Gras mdoc->flags |= MDOC_LITERAL;
2171d65f6f70SBen Gras if (DISP_unfilled == n->norm->Bd.type)
2172d65f6f70SBen Gras mdoc->flags |= MDOC_LITERAL;
2173d65f6f70SBen Gras break;
2174d65f6f70SBen Gras default:
2175d65f6f70SBen Gras abort();
2176d65f6f70SBen Gras /* NOTREACHED */
2177d65f6f70SBen Gras }
2178d65f6f70SBen Gras
2179d65f6f70SBen Gras return(1);
2180d65f6f70SBen Gras }
2181d65f6f70SBen Gras
2182d65f6f70SBen Gras static int
post_dd(POST_ARGS)2183d65f6f70SBen Gras post_dd(POST_ARGS)
2184d65f6f70SBen Gras {
2185d65f6f70SBen Gras char buf[DATESIZE];
2186d65f6f70SBen Gras struct mdoc_node *n;
218792395e9cSLionel Sambuc int c;
218892395e9cSLionel Sambuc
218992395e9cSLionel Sambuc if (mdoc->meta.date)
219092395e9cSLionel Sambuc free(mdoc->meta.date);
2191d65f6f70SBen Gras
2192d65f6f70SBen Gras n = mdoc->last;
219392395e9cSLionel Sambuc if (NULL == n->child || '\0' == n->child->string[0]) {
219492395e9cSLionel Sambuc mdoc->meta.date = mandoc_normdate
219592395e9cSLionel Sambuc (mdoc->parse, NULL, n->line, n->pos);
2196d65f6f70SBen Gras return(1);
2197d65f6f70SBen Gras }
2198d65f6f70SBen Gras
219992395e9cSLionel Sambuc buf[0] = '\0';
220092395e9cSLionel Sambuc if (-1 == (c = concat(buf, n->child, DATESIZE))) {
220192395e9cSLionel Sambuc mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2202d65f6f70SBen Gras return(0);
2203d65f6f70SBen Gras }
2204d65f6f70SBen Gras
220592395e9cSLionel Sambuc assert(c);
220692395e9cSLionel Sambuc mdoc->meta.date = mandoc_normdate
220792395e9cSLionel Sambuc (mdoc->parse, buf, n->line, n->pos);
220892395e9cSLionel Sambuc
2209d65f6f70SBen Gras return(1);
2210d65f6f70SBen Gras }
2211d65f6f70SBen Gras
2212d65f6f70SBen Gras static int
post_dt(POST_ARGS)2213d65f6f70SBen Gras post_dt(POST_ARGS)
2214d65f6f70SBen Gras {
2215d65f6f70SBen Gras struct mdoc_node *nn, *n;
2216d65f6f70SBen Gras const char *cp;
2217d65f6f70SBen Gras char *p;
2218d65f6f70SBen Gras
2219d65f6f70SBen Gras n = mdoc->last;
2220d65f6f70SBen Gras
2221d65f6f70SBen Gras if (mdoc->meta.title)
2222d65f6f70SBen Gras free(mdoc->meta.title);
2223d65f6f70SBen Gras if (mdoc->meta.vol)
2224d65f6f70SBen Gras free(mdoc->meta.vol);
2225d65f6f70SBen Gras if (mdoc->meta.arch)
2226d65f6f70SBen Gras free(mdoc->meta.arch);
2227d65f6f70SBen Gras
2228d65f6f70SBen Gras mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
2229d65f6f70SBen Gras
2230d65f6f70SBen Gras /* First make all characters uppercase. */
2231d65f6f70SBen Gras
2232d65f6f70SBen Gras if (NULL != (nn = n->child))
2233d65f6f70SBen Gras for (p = nn->string; *p; p++) {
223492395e9cSLionel Sambuc if (toupper((unsigned char)*p) == *p)
2235d65f6f70SBen Gras continue;
2236d65f6f70SBen Gras
2237d65f6f70SBen Gras /*
2238d65f6f70SBen Gras * FIXME: don't be lazy: have this make all
2239d65f6f70SBen Gras * characters be uppercase and just warn once.
2240d65f6f70SBen Gras */
2241d65f6f70SBen Gras mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE);
2242d65f6f70SBen Gras break;
2243d65f6f70SBen Gras }
2244d65f6f70SBen Gras
2245d65f6f70SBen Gras /* Handles: `.Dt'
2246d65f6f70SBen Gras * --> title = unknown, volume = local, msec = 0, arch = NULL
2247d65f6f70SBen Gras */
2248d65f6f70SBen Gras
2249d65f6f70SBen Gras if (NULL == (nn = n->child)) {
2250d65f6f70SBen Gras /* XXX: make these macro values. */
2251d65f6f70SBen Gras /* FIXME: warn about missing values. */
2252d65f6f70SBen Gras mdoc->meta.title = mandoc_strdup("UNKNOWN");
2253d65f6f70SBen Gras mdoc->meta.vol = mandoc_strdup("LOCAL");
2254d65f6f70SBen Gras mdoc->meta.msec = mandoc_strdup("1");
2255d65f6f70SBen Gras return(1);
2256d65f6f70SBen Gras }
2257d65f6f70SBen Gras
2258d65f6f70SBen Gras /* Handles: `.Dt TITLE'
2259d65f6f70SBen Gras * --> title = TITLE, volume = local, msec = 0, arch = NULL
2260d65f6f70SBen Gras */
2261d65f6f70SBen Gras
2262d65f6f70SBen Gras mdoc->meta.title = mandoc_strdup
2263d65f6f70SBen Gras ('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
2264d65f6f70SBen Gras
2265d65f6f70SBen Gras if (NULL == (nn = nn->next)) {
2266d65f6f70SBen Gras /* FIXME: warn about missing msec. */
2267d65f6f70SBen Gras /* XXX: make this a macro value. */
2268d65f6f70SBen Gras mdoc->meta.vol = mandoc_strdup("LOCAL");
2269d65f6f70SBen Gras mdoc->meta.msec = mandoc_strdup("1");
2270d65f6f70SBen Gras return(1);
2271d65f6f70SBen Gras }
2272d65f6f70SBen Gras
2273d65f6f70SBen Gras /* Handles: `.Dt TITLE SEC'
2274d65f6f70SBen Gras * --> title = TITLE, volume = SEC is msec ?
2275d65f6f70SBen Gras * format(msec) : SEC,
2276d65f6f70SBen Gras * msec = SEC is msec ? atoi(msec) : 0,
2277d65f6f70SBen Gras * arch = NULL
2278d65f6f70SBen Gras */
2279d65f6f70SBen Gras
228092395e9cSLionel Sambuc cp = mandoc_a2msec(nn->string);
2281d65f6f70SBen Gras if (cp) {
2282d65f6f70SBen Gras mdoc->meta.vol = mandoc_strdup(cp);
2283d65f6f70SBen Gras mdoc->meta.msec = mandoc_strdup(nn->string);
2284d65f6f70SBen Gras } else {
2285d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
2286d65f6f70SBen Gras mdoc->meta.vol = mandoc_strdup(nn->string);
2287d65f6f70SBen Gras mdoc->meta.msec = mandoc_strdup(nn->string);
2288d65f6f70SBen Gras }
2289d65f6f70SBen Gras
2290d65f6f70SBen Gras if (NULL == (nn = nn->next))
2291d65f6f70SBen Gras return(1);
2292d65f6f70SBen Gras
2293d65f6f70SBen Gras /* Handles: `.Dt TITLE SEC VOL'
2294d65f6f70SBen Gras * --> title = TITLE, volume = VOL is vol ?
2295d65f6f70SBen Gras * format(VOL) :
2296d65f6f70SBen Gras * VOL is arch ? format(arch) :
2297d65f6f70SBen Gras * VOL
2298d65f6f70SBen Gras */
2299d65f6f70SBen Gras
2300d65f6f70SBen Gras cp = mdoc_a2vol(nn->string);
2301d65f6f70SBen Gras if (cp) {
2302d65f6f70SBen Gras free(mdoc->meta.vol);
2303d65f6f70SBen Gras mdoc->meta.vol = mandoc_strdup(cp);
2304d65f6f70SBen Gras } else {
2305d65f6f70SBen Gras cp = mdoc_a2arch(nn->string);
2306d65f6f70SBen Gras if (NULL == cp) {
23070a6a1f1dSLionel Sambuc mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH);
2308d65f6f70SBen Gras free(mdoc->meta.vol);
2309d65f6f70SBen Gras mdoc->meta.vol = mandoc_strdup(nn->string);
2310d65f6f70SBen Gras } else
2311d65f6f70SBen Gras mdoc->meta.arch = mandoc_strdup(cp);
2312d65f6f70SBen Gras }
2313d65f6f70SBen Gras
2314d65f6f70SBen Gras /* Ignore any subsequent parameters... */
2315d65f6f70SBen Gras /* FIXME: warn about subsequent parameters. */
2316d65f6f70SBen Gras
2317d65f6f70SBen Gras return(1);
2318d65f6f70SBen Gras }
2319d65f6f70SBen Gras
2320d65f6f70SBen Gras static int
post_prol(POST_ARGS)2321d65f6f70SBen Gras post_prol(POST_ARGS)
2322d65f6f70SBen Gras {
2323d65f6f70SBen Gras /*
2324d65f6f70SBen Gras * Remove prologue macros from the document after they're
2325d65f6f70SBen Gras * processed. The final document uses mdoc_meta for these
2326d65f6f70SBen Gras * values and discards the originals.
2327d65f6f70SBen Gras */
2328d65f6f70SBen Gras
2329d65f6f70SBen Gras mdoc_node_delete(mdoc, mdoc->last);
2330d65f6f70SBen Gras if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
2331d65f6f70SBen Gras mdoc->flags |= MDOC_PBODY;
2332d65f6f70SBen Gras
2333d65f6f70SBen Gras return(1);
2334d65f6f70SBen Gras }
2335d65f6f70SBen Gras
2336d65f6f70SBen Gras static int
post_bx(POST_ARGS)233792395e9cSLionel Sambuc post_bx(POST_ARGS)
233892395e9cSLionel Sambuc {
233992395e9cSLionel Sambuc struct mdoc_node *n;
234092395e9cSLionel Sambuc
234192395e9cSLionel Sambuc /*
234292395e9cSLionel Sambuc * Make `Bx's second argument always start with an uppercase
234392395e9cSLionel Sambuc * letter. Groff checks if it's an "accepted" term, but we just
234492395e9cSLionel Sambuc * uppercase blindly.
234592395e9cSLionel Sambuc */
234692395e9cSLionel Sambuc
234792395e9cSLionel Sambuc n = mdoc->last->child;
234892395e9cSLionel Sambuc if (n && NULL != (n = n->next))
234992395e9cSLionel Sambuc *n->string = (char)toupper
235092395e9cSLionel Sambuc ((unsigned char)*n->string);
235192395e9cSLionel Sambuc
235292395e9cSLionel Sambuc return(1);
235392395e9cSLionel Sambuc }
235492395e9cSLionel Sambuc
235592395e9cSLionel Sambuc static int
post_os(POST_ARGS)2356d65f6f70SBen Gras post_os(POST_ARGS)
2357d65f6f70SBen Gras {
2358d65f6f70SBen Gras struct mdoc_node *n;
2359d65f6f70SBen Gras char buf[BUFSIZ];
236092395e9cSLionel Sambuc int c;
2361d65f6f70SBen Gras #ifndef OSNAME
2362d65f6f70SBen Gras struct utsname utsname;
2363d65f6f70SBen Gras #endif
2364d65f6f70SBen Gras
2365d65f6f70SBen Gras n = mdoc->last;
2366d65f6f70SBen Gras
2367d65f6f70SBen Gras /*
23680a6a1f1dSLionel Sambuc * Set the operating system by way of the `Os' macro.
23690a6a1f1dSLionel Sambuc * The order of precedence is:
23700a6a1f1dSLionel Sambuc * 1. the argument of the `Os' macro, unless empty
23710a6a1f1dSLionel Sambuc * 2. the -Ios=foo command line argument, if provided
23720a6a1f1dSLionel Sambuc * 3. -DOSNAME="\"foo\"", if provided during compilation
23730a6a1f1dSLionel Sambuc * 4. "sysname release" from uname(3)
2374d65f6f70SBen Gras */
2375d65f6f70SBen Gras
2376d65f6f70SBen Gras free(mdoc->meta.os);
2377d65f6f70SBen Gras
237892395e9cSLionel Sambuc buf[0] = '\0';
237992395e9cSLionel Sambuc if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
238092395e9cSLionel Sambuc mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
2381d65f6f70SBen Gras return(0);
238292395e9cSLionel Sambuc }
238392395e9cSLionel Sambuc
238492395e9cSLionel Sambuc assert(c);
2385d65f6f70SBen Gras
2386d65f6f70SBen Gras if ('\0' == buf[0]) {
23870a6a1f1dSLionel Sambuc if (mdoc->defos) {
23880a6a1f1dSLionel Sambuc mdoc->meta.os = mandoc_strdup(mdoc->defos);
23890a6a1f1dSLionel Sambuc return(1);
23900a6a1f1dSLionel Sambuc }
2391d65f6f70SBen Gras #ifdef OSNAME
2392d65f6f70SBen Gras if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
2393d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2394d65f6f70SBen Gras return(0);
2395d65f6f70SBen Gras }
2396d65f6f70SBen Gras #else /*!OSNAME */
239792395e9cSLionel Sambuc if (-1 == uname(&utsname)) {
2398d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
2399d65f6f70SBen Gras mdoc->meta.os = mandoc_strdup("UNKNOWN");
2400d65f6f70SBen Gras return(post_prol(mdoc));
2401d65f6f70SBen Gras }
2402d65f6f70SBen Gras
2403d65f6f70SBen Gras if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
2404d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2405d65f6f70SBen Gras return(0);
2406d65f6f70SBen Gras }
2407d65f6f70SBen Gras if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
2408d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2409d65f6f70SBen Gras return(0);
2410d65f6f70SBen Gras }
2411d65f6f70SBen Gras if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
2412d65f6f70SBen Gras mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
2413d65f6f70SBen Gras return(0);
2414d65f6f70SBen Gras }
2415d65f6f70SBen Gras #endif /*!OSNAME*/
2416d65f6f70SBen Gras }
2417d65f6f70SBen Gras
2418d65f6f70SBen Gras mdoc->meta.os = mandoc_strdup(buf);
2419d65f6f70SBen Gras return(1);
2420d65f6f70SBen Gras }
2421d65f6f70SBen Gras
2422d65f6f70SBen Gras static int
post_std(POST_ARGS)2423d65f6f70SBen Gras post_std(POST_ARGS)
2424d65f6f70SBen Gras {
2425d65f6f70SBen Gras struct mdoc_node *nn, *n;
2426d65f6f70SBen Gras
2427d65f6f70SBen Gras n = mdoc->last;
2428d65f6f70SBen Gras
2429d65f6f70SBen Gras /*
2430d65f6f70SBen Gras * Macros accepting `-std' as an argument have the name of the
2431d65f6f70SBen Gras * current document (`Nm') filled in as the argument if it's not
2432d65f6f70SBen Gras * provided.
2433d65f6f70SBen Gras */
2434d65f6f70SBen Gras
2435d65f6f70SBen Gras if (n->child)
2436d65f6f70SBen Gras return(1);
2437d65f6f70SBen Gras
2438d65f6f70SBen Gras if (NULL == mdoc->meta.name)
2439d65f6f70SBen Gras return(1);
2440d65f6f70SBen Gras
2441d65f6f70SBen Gras nn = n;
2442d65f6f70SBen Gras mdoc->next = MDOC_NEXT_CHILD;
2443d65f6f70SBen Gras
2444d65f6f70SBen Gras if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
2445d65f6f70SBen Gras return(0);
2446d65f6f70SBen Gras
2447d65f6f70SBen Gras mdoc->last = nn;
2448d65f6f70SBen Gras return(1);
2449d65f6f70SBen Gras }
2450d65f6f70SBen Gras
245192395e9cSLionel Sambuc /*
245292395e9cSLionel Sambuc * Concatenate a node, stopping at the first non-text.
245392395e9cSLionel Sambuc * Concatenation is separated by a single whitespace.
245492395e9cSLionel Sambuc * Returns -1 on fatal (string overrun) error, 0 if child nodes were
245592395e9cSLionel Sambuc * encountered, 1 otherwise.
245692395e9cSLionel Sambuc */
2457d65f6f70SBen Gras static int
concat(char * p,const struct mdoc_node * n,size_t sz)245892395e9cSLionel Sambuc concat(char *p, const struct mdoc_node *n, size_t sz)
2459d65f6f70SBen Gras {
2460d65f6f70SBen Gras
246192395e9cSLionel Sambuc for ( ; NULL != n; n = n->next) {
246292395e9cSLionel Sambuc if (MDOC_TEXT != n->type)
2463d65f6f70SBen Gras return(0);
246492395e9cSLionel Sambuc if ('\0' != p[0] && strlcat(p, " ", sz) >= sz)
246592395e9cSLionel Sambuc return(-1);
246692395e9cSLionel Sambuc if (strlcat(p, n->string, sz) >= sz)
246792395e9cSLionel Sambuc return(-1);
246892395e9cSLionel Sambuc concat(p, n->child, sz);
2469d65f6f70SBen Gras }
2470d65f6f70SBen Gras
2471d65f6f70SBen Gras return(1);
2472d65f6f70SBen Gras }
2473d65f6f70SBen Gras
247492395e9cSLionel Sambuc static enum mdoc_sec
a2sec(const char * p)247592395e9cSLionel Sambuc a2sec(const char *p)
247692395e9cSLionel Sambuc {
247792395e9cSLionel Sambuc int i;
247892395e9cSLionel Sambuc
247992395e9cSLionel Sambuc for (i = 0; i < (int)SEC__MAX; i++)
248092395e9cSLionel Sambuc if (secnames[i] && 0 == strcmp(p, secnames[i]))
248192395e9cSLionel Sambuc return((enum mdoc_sec)i);
248292395e9cSLionel Sambuc
248392395e9cSLionel Sambuc return(SEC_CUSTOM);
248492395e9cSLionel Sambuc }
248592395e9cSLionel Sambuc
248692395e9cSLionel Sambuc static size_t
macro2len(enum mdoct macro)248792395e9cSLionel Sambuc macro2len(enum mdoct macro)
248892395e9cSLionel Sambuc {
248992395e9cSLionel Sambuc
249092395e9cSLionel Sambuc switch (macro) {
249192395e9cSLionel Sambuc case(MDOC_Ad):
249292395e9cSLionel Sambuc return(12);
249392395e9cSLionel Sambuc case(MDOC_Ao):
249492395e9cSLionel Sambuc return(12);
249592395e9cSLionel Sambuc case(MDOC_An):
249692395e9cSLionel Sambuc return(12);
249792395e9cSLionel Sambuc case(MDOC_Aq):
249892395e9cSLionel Sambuc return(12);
249992395e9cSLionel Sambuc case(MDOC_Ar):
250092395e9cSLionel Sambuc return(12);
250192395e9cSLionel Sambuc case(MDOC_Bo):
250292395e9cSLionel Sambuc return(12);
250392395e9cSLionel Sambuc case(MDOC_Bq):
250492395e9cSLionel Sambuc return(12);
250592395e9cSLionel Sambuc case(MDOC_Cd):
250692395e9cSLionel Sambuc return(12);
250792395e9cSLionel Sambuc case(MDOC_Cm):
250892395e9cSLionel Sambuc return(10);
250992395e9cSLionel Sambuc case(MDOC_Do):
251092395e9cSLionel Sambuc return(10);
251192395e9cSLionel Sambuc case(MDOC_Dq):
251292395e9cSLionel Sambuc return(12);
251392395e9cSLionel Sambuc case(MDOC_Dv):
251492395e9cSLionel Sambuc return(12);
251592395e9cSLionel Sambuc case(MDOC_Eo):
251692395e9cSLionel Sambuc return(12);
251792395e9cSLionel Sambuc case(MDOC_Em):
251892395e9cSLionel Sambuc return(10);
251992395e9cSLionel Sambuc case(MDOC_Er):
252092395e9cSLionel Sambuc return(17);
252192395e9cSLionel Sambuc case(MDOC_Ev):
252292395e9cSLionel Sambuc return(15);
252392395e9cSLionel Sambuc case(MDOC_Fa):
252492395e9cSLionel Sambuc return(12);
252592395e9cSLionel Sambuc case(MDOC_Fl):
252692395e9cSLionel Sambuc return(10);
252792395e9cSLionel Sambuc case(MDOC_Fo):
252892395e9cSLionel Sambuc return(16);
252992395e9cSLionel Sambuc case(MDOC_Fn):
253092395e9cSLionel Sambuc return(16);
253192395e9cSLionel Sambuc case(MDOC_Ic):
253292395e9cSLionel Sambuc return(10);
253392395e9cSLionel Sambuc case(MDOC_Li):
253492395e9cSLionel Sambuc return(16);
253592395e9cSLionel Sambuc case(MDOC_Ms):
253692395e9cSLionel Sambuc return(6);
253792395e9cSLionel Sambuc case(MDOC_Nm):
253892395e9cSLionel Sambuc return(10);
253992395e9cSLionel Sambuc case(MDOC_No):
254092395e9cSLionel Sambuc return(12);
254192395e9cSLionel Sambuc case(MDOC_Oo):
254292395e9cSLionel Sambuc return(10);
254392395e9cSLionel Sambuc case(MDOC_Op):
254492395e9cSLionel Sambuc return(14);
254592395e9cSLionel Sambuc case(MDOC_Pa):
254692395e9cSLionel Sambuc return(32);
254792395e9cSLionel Sambuc case(MDOC_Pf):
254892395e9cSLionel Sambuc return(12);
254992395e9cSLionel Sambuc case(MDOC_Po):
255092395e9cSLionel Sambuc return(12);
255192395e9cSLionel Sambuc case(MDOC_Pq):
255292395e9cSLionel Sambuc return(12);
255392395e9cSLionel Sambuc case(MDOC_Ql):
255492395e9cSLionel Sambuc return(16);
255592395e9cSLionel Sambuc case(MDOC_Qo):
255692395e9cSLionel Sambuc return(12);
255792395e9cSLionel Sambuc case(MDOC_So):
255892395e9cSLionel Sambuc return(12);
255992395e9cSLionel Sambuc case(MDOC_Sq):
256092395e9cSLionel Sambuc return(12);
256192395e9cSLionel Sambuc case(MDOC_Sy):
256292395e9cSLionel Sambuc return(6);
256392395e9cSLionel Sambuc case(MDOC_Sx):
256492395e9cSLionel Sambuc return(16);
256592395e9cSLionel Sambuc case(MDOC_Tn):
256692395e9cSLionel Sambuc return(10);
256792395e9cSLionel Sambuc case(MDOC_Va):
256892395e9cSLionel Sambuc return(12);
256992395e9cSLionel Sambuc case(MDOC_Vt):
257092395e9cSLionel Sambuc return(12);
257192395e9cSLionel Sambuc case(MDOC_Xr):
257292395e9cSLionel Sambuc return(10);
257392395e9cSLionel Sambuc default:
257492395e9cSLionel Sambuc break;
257592395e9cSLionel Sambuc };
257692395e9cSLionel Sambuc return(0);
257792395e9cSLionel Sambuc }
2578