1*698f87a4SGarrett D'Amore /* $Id: mdoc_validate.c,v 1.198 2013/12/15 21:23:52 schwarze Exp $ */
295c635efSGarrett D'Amore /*
3*698f87a4SGarrett D'Amore * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
4*698f87a4SGarrett D'Amore * Copyright (c) 2010, 2011, 2012, 2013 Ingo Schwarze <schwarze@openbsd.org>
595c635efSGarrett D'Amore *
695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any
795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above
895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies.
995c635efSGarrett D'Amore *
1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1795c635efSGarrett D'Amore */
1895c635efSGarrett D'Amore #ifdef HAVE_CONFIG_H
1995c635efSGarrett D'Amore #include "config.h"
2095c635efSGarrett D'Amore #endif
2195c635efSGarrett D'Amore
2295c635efSGarrett D'Amore #ifndef OSNAME
2395c635efSGarrett D'Amore #include <sys/utsname.h>
2495c635efSGarrett D'Amore #endif
2595c635efSGarrett D'Amore
2695c635efSGarrett D'Amore #include <sys/types.h>
2795c635efSGarrett D'Amore
2895c635efSGarrett D'Amore #include <assert.h>
2995c635efSGarrett D'Amore #include <ctype.h>
3095c635efSGarrett D'Amore #include <limits.h>
3195c635efSGarrett D'Amore #include <stdio.h>
3295c635efSGarrett D'Amore #include <stdlib.h>
3395c635efSGarrett D'Amore #include <string.h>
3495c635efSGarrett D'Amore #include <time.h>
3595c635efSGarrett D'Amore
3695c635efSGarrett D'Amore #include "mdoc.h"
3795c635efSGarrett D'Amore #include "mandoc.h"
3895c635efSGarrett D'Amore #include "libmdoc.h"
3995c635efSGarrett D'Amore #include "libmandoc.h"
4095c635efSGarrett D'Amore
4195c635efSGarrett D'Amore /* FIXME: .Bl -diag can't have non-text children in HEAD. */
4295c635efSGarrett D'Amore
4395c635efSGarrett D'Amore #define PRE_ARGS struct mdoc *mdoc, struct mdoc_node *n
4495c635efSGarrett D'Amore #define POST_ARGS struct mdoc *mdoc
4595c635efSGarrett D'Amore
4695c635efSGarrett D'Amore #define NUMSIZ 32
4795c635efSGarrett D'Amore #define DATESIZE 32
4895c635efSGarrett D'Amore
4995c635efSGarrett D'Amore enum check_ineq {
5095c635efSGarrett D'Amore CHECK_LT,
5195c635efSGarrett D'Amore CHECK_GT,
5295c635efSGarrett D'Amore CHECK_EQ
5395c635efSGarrett D'Amore };
5495c635efSGarrett D'Amore
5595c635efSGarrett D'Amore enum check_lvl {
5695c635efSGarrett D'Amore CHECK_WARN,
5795c635efSGarrett D'Amore CHECK_ERROR,
5895c635efSGarrett D'Amore };
5995c635efSGarrett D'Amore
6095c635efSGarrett D'Amore typedef int (*v_pre)(PRE_ARGS);
6195c635efSGarrett D'Amore typedef int (*v_post)(POST_ARGS);
6295c635efSGarrett D'Amore
6395c635efSGarrett D'Amore struct valids {
6495c635efSGarrett D'Amore v_pre *pre;
6595c635efSGarrett D'Amore v_post *post;
6695c635efSGarrett D'Amore };
6795c635efSGarrett D'Amore
6895c635efSGarrett D'Amore static int check_count(struct mdoc *, enum mdoc_type,
6995c635efSGarrett D'Amore enum check_lvl, enum check_ineq, int);
7095c635efSGarrett D'Amore static int check_parent(PRE_ARGS, enum mdoct, enum mdoc_type);
7195c635efSGarrett D'Amore static void check_text(struct mdoc *, int, int, char *);
7295c635efSGarrett D'Amore static void check_argv(struct mdoc *,
7395c635efSGarrett D'Amore struct mdoc_node *, struct mdoc_argv *);
7495c635efSGarrett D'Amore static void check_args(struct mdoc *, struct mdoc_node *);
7595c635efSGarrett D'Amore static int concat(char *, const struct mdoc_node *, size_t);
7695c635efSGarrett D'Amore static enum mdoc_sec a2sec(const char *);
7795c635efSGarrett D'Amore static size_t macro2len(enum mdoct);
7895c635efSGarrett D'Amore
7995c635efSGarrett D'Amore static int ebool(POST_ARGS);
8095c635efSGarrett D'Amore static int berr_ge1(POST_ARGS);
8195c635efSGarrett D'Amore static int bwarn_ge1(POST_ARGS);
8295c635efSGarrett D'Amore static int ewarn_eq0(POST_ARGS);
8395c635efSGarrett D'Amore static int ewarn_eq1(POST_ARGS);
8495c635efSGarrett D'Amore static int ewarn_ge1(POST_ARGS);
8595c635efSGarrett D'Amore static int ewarn_le1(POST_ARGS);
8695c635efSGarrett D'Amore static int hwarn_eq0(POST_ARGS);
8795c635efSGarrett D'Amore static int hwarn_eq1(POST_ARGS);
8895c635efSGarrett D'Amore static int hwarn_ge1(POST_ARGS);
8995c635efSGarrett D'Amore static int hwarn_le1(POST_ARGS);
9095c635efSGarrett D'Amore
9195c635efSGarrett D'Amore static int post_an(POST_ARGS);
9295c635efSGarrett D'Amore static int post_at(POST_ARGS);
9395c635efSGarrett D'Amore static int post_bf(POST_ARGS);
9495c635efSGarrett D'Amore static int post_bl(POST_ARGS);
9595c635efSGarrett D'Amore static int post_bl_block(POST_ARGS);
9695c635efSGarrett D'Amore static int post_bl_block_width(POST_ARGS);
9795c635efSGarrett D'Amore static int post_bl_block_tag(POST_ARGS);
9895c635efSGarrett D'Amore static int post_bl_head(POST_ARGS);
9995c635efSGarrett D'Amore static int post_bx(POST_ARGS);
100*698f87a4SGarrett D'Amore static int post_defaults(POST_ARGS);
10195c635efSGarrett D'Amore static int post_dd(POST_ARGS);
10295c635efSGarrett D'Amore static int post_dt(POST_ARGS);
10395c635efSGarrett D'Amore static int post_eoln(POST_ARGS);
104*698f87a4SGarrett D'Amore static int post_hyph(POST_ARGS);
105*698f87a4SGarrett D'Amore static int post_ignpar(POST_ARGS);
10695c635efSGarrett D'Amore static int post_it(POST_ARGS);
10795c635efSGarrett D'Amore static int post_lb(POST_ARGS);
108*698f87a4SGarrett D'Amore static int post_literal(POST_ARGS);
10995c635efSGarrett D'Amore static int post_nm(POST_ARGS);
11095c635efSGarrett D'Amore static int post_ns(POST_ARGS);
11195c635efSGarrett D'Amore static int post_os(POST_ARGS);
112*698f87a4SGarrett D'Amore static int post_par(POST_ARGS);
11395c635efSGarrett D'Amore static int post_prol(POST_ARGS);
11495c635efSGarrett D'Amore static int post_root(POST_ARGS);
11595c635efSGarrett D'Amore static int post_rs(POST_ARGS);
11695c635efSGarrett D'Amore static int post_sh(POST_ARGS);
11795c635efSGarrett D'Amore static int post_sh_body(POST_ARGS);
11895c635efSGarrett D'Amore static int post_sh_head(POST_ARGS);
11995c635efSGarrett D'Amore static int post_st(POST_ARGS);
12095c635efSGarrett D'Amore static int post_std(POST_ARGS);
12195c635efSGarrett D'Amore static int post_vt(POST_ARGS);
12295c635efSGarrett D'Amore static int pre_an(PRE_ARGS);
12395c635efSGarrett D'Amore static int pre_bd(PRE_ARGS);
12495c635efSGarrett D'Amore static int pre_bl(PRE_ARGS);
12595c635efSGarrett D'Amore static int pre_dd(PRE_ARGS);
12695c635efSGarrett D'Amore static int pre_display(PRE_ARGS);
12795c635efSGarrett D'Amore static int pre_dt(PRE_ARGS);
12895c635efSGarrett D'Amore static int pre_it(PRE_ARGS);
12995c635efSGarrett D'Amore static int pre_literal(PRE_ARGS);
13095c635efSGarrett D'Amore static int pre_os(PRE_ARGS);
13195c635efSGarrett D'Amore static int pre_par(PRE_ARGS);
13295c635efSGarrett D'Amore static int pre_sh(PRE_ARGS);
13395c635efSGarrett D'Amore static int pre_ss(PRE_ARGS);
13495c635efSGarrett D'Amore static int pre_std(PRE_ARGS);
13595c635efSGarrett D'Amore
13695c635efSGarrett D'Amore static v_post posts_an[] = { post_an, NULL };
13795c635efSGarrett D'Amore static v_post posts_at[] = { post_at, post_defaults, NULL };
13895c635efSGarrett D'Amore static v_post posts_bd[] = { post_literal, hwarn_eq0, bwarn_ge1, NULL };
13995c635efSGarrett D'Amore static v_post posts_bf[] = { hwarn_le1, post_bf, NULL };
14095c635efSGarrett D'Amore static v_post posts_bk[] = { hwarn_eq0, bwarn_ge1, NULL };
14195c635efSGarrett D'Amore static v_post posts_bl[] = { bwarn_ge1, post_bl, NULL };
14295c635efSGarrett D'Amore static v_post posts_bx[] = { post_bx, NULL };
14395c635efSGarrett D'Amore static v_post posts_bool[] = { ebool, NULL };
14495c635efSGarrett D'Amore static v_post posts_eoln[] = { post_eoln, NULL };
14595c635efSGarrett D'Amore static v_post posts_defaults[] = { post_defaults, NULL };
146*698f87a4SGarrett D'Amore static v_post posts_d1[] = { bwarn_ge1, post_hyph, NULL };
14795c635efSGarrett D'Amore static v_post posts_dd[] = { post_dd, post_prol, NULL };
14895c635efSGarrett D'Amore static v_post posts_dl[] = { post_literal, bwarn_ge1, NULL };
14995c635efSGarrett D'Amore static v_post posts_dt[] = { post_dt, post_prol, NULL };
15095c635efSGarrett D'Amore static v_post posts_fo[] = { hwarn_eq1, bwarn_ge1, NULL };
151*698f87a4SGarrett D'Amore static v_post posts_hyph[] = { post_hyph, NULL };
152*698f87a4SGarrett D'Amore static v_post posts_hyphtext[] = { ewarn_ge1, post_hyph, NULL };
15395c635efSGarrett D'Amore static v_post posts_it[] = { post_it, NULL };
15495c635efSGarrett D'Amore static v_post posts_lb[] = { post_lb, NULL };
155*698f87a4SGarrett D'Amore static v_post posts_nd[] = { berr_ge1, post_hyph, NULL };
15695c635efSGarrett D'Amore static v_post posts_nm[] = { post_nm, NULL };
15795c635efSGarrett D'Amore static v_post posts_notext[] = { ewarn_eq0, NULL };
15895c635efSGarrett D'Amore static v_post posts_ns[] = { post_ns, NULL };
15995c635efSGarrett D'Amore static v_post posts_os[] = { post_os, post_prol, NULL };
160*698f87a4SGarrett D'Amore static v_post posts_pp[] = { post_par, ewarn_eq0, NULL };
16195c635efSGarrett D'Amore static v_post posts_rs[] = { post_rs, NULL };
162*698f87a4SGarrett D'Amore static v_post posts_sh[] = { post_ignpar,hwarn_ge1,post_sh,post_hyph,NULL };
163*698f87a4SGarrett D'Amore static v_post posts_sp[] = { post_par, ewarn_le1, NULL };
164*698f87a4SGarrett D'Amore static v_post posts_ss[] = { post_ignpar, hwarn_ge1, post_hyph, NULL };
16595c635efSGarrett D'Amore static v_post posts_st[] = { post_st, NULL };
16695c635efSGarrett D'Amore static v_post posts_std[] = { post_std, NULL };
16795c635efSGarrett D'Amore static v_post posts_text[] = { ewarn_ge1, NULL };
16895c635efSGarrett D'Amore static v_post posts_text1[] = { ewarn_eq1, NULL };
16995c635efSGarrett D'Amore static v_post posts_vt[] = { post_vt, NULL };
17095c635efSGarrett D'Amore static v_pre pres_an[] = { pre_an, NULL };
17195c635efSGarrett D'Amore static v_pre pres_bd[] = { pre_display, pre_bd, pre_literal, pre_par, NULL };
17295c635efSGarrett D'Amore static v_pre pres_bl[] = { pre_bl, pre_par, NULL };
17395c635efSGarrett D'Amore static v_pre pres_d1[] = { pre_display, NULL };
17495c635efSGarrett D'Amore static v_pre pres_dl[] = { pre_literal, pre_display, NULL };
17595c635efSGarrett D'Amore static v_pre pres_dd[] = { pre_dd, NULL };
17695c635efSGarrett D'Amore static v_pre pres_dt[] = { pre_dt, NULL };
17795c635efSGarrett D'Amore static v_pre pres_it[] = { pre_it, pre_par, NULL };
17895c635efSGarrett D'Amore static v_pre pres_os[] = { pre_os, NULL };
17995c635efSGarrett D'Amore static v_pre pres_pp[] = { pre_par, NULL };
18095c635efSGarrett D'Amore static v_pre pres_sh[] = { pre_sh, NULL };
18195c635efSGarrett D'Amore static v_pre pres_ss[] = { pre_ss, NULL };
18295c635efSGarrett D'Amore static v_pre pres_std[] = { pre_std, NULL };
18395c635efSGarrett D'Amore
18495c635efSGarrett D'Amore static const struct valids mdoc_valids[MDOC_MAX] = {
18595c635efSGarrett D'Amore { NULL, NULL }, /* Ap */
18695c635efSGarrett D'Amore { pres_dd, posts_dd }, /* Dd */
18795c635efSGarrett D'Amore { pres_dt, posts_dt }, /* Dt */
18895c635efSGarrett D'Amore { pres_os, posts_os }, /* Os */
18995c635efSGarrett D'Amore { pres_sh, posts_sh }, /* Sh */
19095c635efSGarrett D'Amore { pres_ss, posts_ss }, /* Ss */
191*698f87a4SGarrett D'Amore { pres_pp, posts_pp }, /* Pp */
192*698f87a4SGarrett D'Amore { pres_d1, posts_d1 }, /* D1 */
19395c635efSGarrett D'Amore { pres_dl, posts_dl }, /* Dl */
19495c635efSGarrett D'Amore { pres_bd, posts_bd }, /* Bd */
19595c635efSGarrett D'Amore { NULL, NULL }, /* Ed */
19695c635efSGarrett D'Amore { pres_bl, posts_bl }, /* Bl */
19795c635efSGarrett D'Amore { NULL, NULL }, /* El */
19895c635efSGarrett D'Amore { pres_it, posts_it }, /* It */
19995c635efSGarrett D'Amore { NULL, NULL }, /* Ad */
20095c635efSGarrett D'Amore { pres_an, posts_an }, /* An */
20195c635efSGarrett D'Amore { NULL, posts_defaults }, /* Ar */
20295c635efSGarrett D'Amore { NULL, NULL }, /* Cd */
20395c635efSGarrett D'Amore { NULL, NULL }, /* Cm */
20495c635efSGarrett D'Amore { NULL, NULL }, /* Dv */
205*698f87a4SGarrett D'Amore { NULL, NULL }, /* Er */
20695c635efSGarrett D'Amore { NULL, NULL }, /* Ev */
20795c635efSGarrett D'Amore { pres_std, posts_std }, /* Ex */
20895c635efSGarrett D'Amore { NULL, NULL }, /* Fa */
209*698f87a4SGarrett D'Amore { NULL, posts_text }, /* Fd */
21095c635efSGarrett D'Amore { NULL, NULL }, /* Fl */
21195c635efSGarrett D'Amore { NULL, NULL }, /* Fn */
21295c635efSGarrett D'Amore { NULL, NULL }, /* Ft */
21395c635efSGarrett D'Amore { NULL, NULL }, /* Ic */
21495c635efSGarrett D'Amore { NULL, posts_text1 }, /* In */
21595c635efSGarrett D'Amore { NULL, posts_defaults }, /* Li */
21695c635efSGarrett D'Amore { NULL, posts_nd }, /* Nd */
21795c635efSGarrett D'Amore { NULL, posts_nm }, /* Nm */
21895c635efSGarrett D'Amore { NULL, NULL }, /* Op */
21995c635efSGarrett D'Amore { NULL, NULL }, /* Ot */
22095c635efSGarrett D'Amore { NULL, posts_defaults }, /* Pa */
22195c635efSGarrett D'Amore { pres_std, posts_std }, /* Rv */
22295c635efSGarrett D'Amore { NULL, posts_st }, /* St */
22395c635efSGarrett D'Amore { NULL, NULL }, /* Va */
22495c635efSGarrett D'Amore { NULL, posts_vt }, /* Vt */
22595c635efSGarrett D'Amore { NULL, posts_text }, /* Xr */
22695c635efSGarrett D'Amore { NULL, posts_text }, /* %A */
227*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %B */ /* FIXME: can be used outside Rs/Re. */
22895c635efSGarrett D'Amore { NULL, posts_text }, /* %D */
22995c635efSGarrett D'Amore { NULL, posts_text }, /* %I */
23095c635efSGarrett D'Amore { NULL, posts_text }, /* %J */
231*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %N */
232*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %O */
23395c635efSGarrett D'Amore { NULL, posts_text }, /* %P */
234*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %R */
235*698f87a4SGarrett D'Amore { NULL, posts_hyphtext }, /* %T */ /* FIXME: can be used outside Rs/Re. */
23695c635efSGarrett D'Amore { NULL, posts_text }, /* %V */
23795c635efSGarrett D'Amore { NULL, NULL }, /* Ac */
23895c635efSGarrett D'Amore { NULL, NULL }, /* Ao */
23995c635efSGarrett D'Amore { NULL, NULL }, /* Aq */
24095c635efSGarrett D'Amore { NULL, posts_at }, /* At */
24195c635efSGarrett D'Amore { NULL, NULL }, /* Bc */
24295c635efSGarrett D'Amore { NULL, posts_bf }, /* Bf */
24395c635efSGarrett D'Amore { NULL, NULL }, /* Bo */
24495c635efSGarrett D'Amore { NULL, NULL }, /* Bq */
24595c635efSGarrett D'Amore { NULL, NULL }, /* Bsx */
24695c635efSGarrett D'Amore { NULL, posts_bx }, /* Bx */
24795c635efSGarrett D'Amore { NULL, posts_bool }, /* Db */
24895c635efSGarrett D'Amore { NULL, NULL }, /* Dc */
24995c635efSGarrett D'Amore { NULL, NULL }, /* Do */
25095c635efSGarrett D'Amore { NULL, NULL }, /* Dq */
25195c635efSGarrett D'Amore { NULL, NULL }, /* Ec */
25295c635efSGarrett D'Amore { NULL, NULL }, /* Ef */
25395c635efSGarrett D'Amore { NULL, NULL }, /* Em */
25495c635efSGarrett D'Amore { NULL, NULL }, /* Eo */
25595c635efSGarrett D'Amore { NULL, NULL }, /* Fx */
25695c635efSGarrett D'Amore { NULL, NULL }, /* Ms */
25795c635efSGarrett D'Amore { NULL, posts_notext }, /* No */
25895c635efSGarrett D'Amore { NULL, posts_ns }, /* Ns */
25995c635efSGarrett D'Amore { NULL, NULL }, /* Nx */
26095c635efSGarrett D'Amore { NULL, NULL }, /* Ox */
26195c635efSGarrett D'Amore { NULL, NULL }, /* Pc */
26295c635efSGarrett D'Amore { NULL, posts_text1 }, /* Pf */
26395c635efSGarrett D'Amore { NULL, NULL }, /* Po */
26495c635efSGarrett D'Amore { NULL, NULL }, /* Pq */
26595c635efSGarrett D'Amore { NULL, NULL }, /* Qc */
26695c635efSGarrett D'Amore { NULL, NULL }, /* Ql */
26795c635efSGarrett D'Amore { NULL, NULL }, /* Qo */
26895c635efSGarrett D'Amore { NULL, NULL }, /* Qq */
26995c635efSGarrett D'Amore { NULL, NULL }, /* Re */
27095c635efSGarrett D'Amore { NULL, posts_rs }, /* Rs */
27195c635efSGarrett D'Amore { NULL, NULL }, /* Sc */
27295c635efSGarrett D'Amore { NULL, NULL }, /* So */
27395c635efSGarrett D'Amore { NULL, NULL }, /* Sq */
27495c635efSGarrett D'Amore { NULL, posts_bool }, /* Sm */
275*698f87a4SGarrett D'Amore { NULL, posts_hyph }, /* Sx */
27695c635efSGarrett D'Amore { NULL, NULL }, /* Sy */
27795c635efSGarrett D'Amore { NULL, NULL }, /* Tn */
27895c635efSGarrett D'Amore { NULL, NULL }, /* Ux */
27995c635efSGarrett D'Amore { NULL, NULL }, /* Xc */
28095c635efSGarrett D'Amore { NULL, NULL }, /* Xo */
28195c635efSGarrett D'Amore { NULL, posts_fo }, /* Fo */
28295c635efSGarrett D'Amore { NULL, NULL }, /* Fc */
28395c635efSGarrett D'Amore { NULL, NULL }, /* Oo */
28495c635efSGarrett D'Amore { NULL, NULL }, /* Oc */
28595c635efSGarrett D'Amore { NULL, posts_bk }, /* Bk */
28695c635efSGarrett D'Amore { NULL, NULL }, /* Ek */
28795c635efSGarrett D'Amore { NULL, posts_eoln }, /* Bt */
28895c635efSGarrett D'Amore { NULL, NULL }, /* Hf */
28995c635efSGarrett D'Amore { NULL, NULL }, /* Fr */
29095c635efSGarrett D'Amore { NULL, posts_eoln }, /* Ud */
29195c635efSGarrett D'Amore { NULL, posts_lb }, /* Lb */
292*698f87a4SGarrett D'Amore { pres_pp, posts_pp }, /* Lp */
29395c635efSGarrett D'Amore { NULL, NULL }, /* Lk */
29495c635efSGarrett D'Amore { NULL, posts_defaults }, /* Mt */
29595c635efSGarrett D'Amore { NULL, NULL }, /* Brq */
29695c635efSGarrett D'Amore { NULL, NULL }, /* Bro */
29795c635efSGarrett D'Amore { NULL, NULL }, /* Brc */
29895c635efSGarrett D'Amore { NULL, posts_text }, /* %C */
29995c635efSGarrett D'Amore { NULL, NULL }, /* Es */
30095c635efSGarrett D'Amore { NULL, NULL }, /* En */
30195c635efSGarrett D'Amore { NULL, NULL }, /* Dx */
30295c635efSGarrett D'Amore { NULL, posts_text }, /* %Q */
303*698f87a4SGarrett D'Amore { NULL, posts_pp }, /* br */
304*698f87a4SGarrett D'Amore { NULL, posts_sp }, /* sp */
30595c635efSGarrett D'Amore { NULL, posts_text1 }, /* %U */
30695c635efSGarrett D'Amore { NULL, NULL }, /* Ta */
30795c635efSGarrett D'Amore };
30895c635efSGarrett D'Amore
30995c635efSGarrett D'Amore #define RSORD_MAX 14 /* Number of `Rs' blocks. */
31095c635efSGarrett D'Amore
31195c635efSGarrett D'Amore static const enum mdoct rsord[RSORD_MAX] = {
31295c635efSGarrett D'Amore MDOC__A,
31395c635efSGarrett D'Amore MDOC__T,
31495c635efSGarrett D'Amore MDOC__B,
31595c635efSGarrett D'Amore MDOC__I,
31695c635efSGarrett D'Amore MDOC__J,
31795c635efSGarrett D'Amore MDOC__R,
31895c635efSGarrett D'Amore MDOC__N,
31995c635efSGarrett D'Amore MDOC__V,
320*698f87a4SGarrett D'Amore MDOC__U,
32195c635efSGarrett D'Amore MDOC__P,
32295c635efSGarrett D'Amore MDOC__Q,
32395c635efSGarrett D'Amore MDOC__C,
324*698f87a4SGarrett D'Amore MDOC__D,
325*698f87a4SGarrett D'Amore MDOC__O
32695c635efSGarrett D'Amore };
32795c635efSGarrett D'Amore
32895c635efSGarrett D'Amore static const char * const secnames[SEC__MAX] = {
32995c635efSGarrett D'Amore NULL,
33095c635efSGarrett D'Amore "NAME",
33195c635efSGarrett D'Amore "LIBRARY",
33295c635efSGarrett D'Amore "SYNOPSIS",
33395c635efSGarrett D'Amore "DESCRIPTION",
33495c635efSGarrett D'Amore "IMPLEMENTATION NOTES",
33595c635efSGarrett D'Amore "RETURN VALUES",
33695c635efSGarrett D'Amore "ENVIRONMENT",
33795c635efSGarrett D'Amore "FILES",
33895c635efSGarrett D'Amore "EXIT STATUS",
33995c635efSGarrett D'Amore "EXAMPLES",
34095c635efSGarrett D'Amore "DIAGNOSTICS",
34195c635efSGarrett D'Amore "COMPATIBILITY",
34295c635efSGarrett D'Amore "ERRORS",
34395c635efSGarrett D'Amore "SEE ALSO",
34495c635efSGarrett D'Amore "STANDARDS",
34595c635efSGarrett D'Amore "HISTORY",
34695c635efSGarrett D'Amore "AUTHORS",
34795c635efSGarrett D'Amore "CAVEATS",
34895c635efSGarrett D'Amore "BUGS",
34995c635efSGarrett D'Amore "SECURITY CONSIDERATIONS",
35095c635efSGarrett D'Amore NULL
35195c635efSGarrett D'Amore };
35295c635efSGarrett D'Amore
35395c635efSGarrett D'Amore int
mdoc_valid_pre(struct mdoc * mdoc,struct mdoc_node * n)35495c635efSGarrett D'Amore mdoc_valid_pre(struct mdoc *mdoc, struct mdoc_node *n)
35595c635efSGarrett D'Amore {
35695c635efSGarrett D'Amore v_pre *p;
35795c635efSGarrett D'Amore int line, pos;
35895c635efSGarrett D'Amore char *tp;
35995c635efSGarrett D'Amore
36095c635efSGarrett D'Amore switch (n->type) {
36195c635efSGarrett D'Amore case (MDOC_TEXT):
36295c635efSGarrett D'Amore tp = n->string;
36395c635efSGarrett D'Amore line = n->line;
36495c635efSGarrett D'Amore pos = n->pos;
36595c635efSGarrett D'Amore check_text(mdoc, line, pos, tp);
36695c635efSGarrett D'Amore /* FALLTHROUGH */
36795c635efSGarrett D'Amore case (MDOC_TBL):
36895c635efSGarrett D'Amore /* FALLTHROUGH */
36995c635efSGarrett D'Amore case (MDOC_EQN):
37095c635efSGarrett D'Amore /* FALLTHROUGH */
37195c635efSGarrett D'Amore case (MDOC_ROOT):
37295c635efSGarrett D'Amore return(1);
37395c635efSGarrett D'Amore default:
37495c635efSGarrett D'Amore break;
37595c635efSGarrett D'Amore }
37695c635efSGarrett D'Amore
37795c635efSGarrett D'Amore check_args(mdoc, n);
37895c635efSGarrett D'Amore
37995c635efSGarrett D'Amore if (NULL == mdoc_valids[n->tok].pre)
38095c635efSGarrett D'Amore return(1);
38195c635efSGarrett D'Amore for (p = mdoc_valids[n->tok].pre; *p; p++)
38295c635efSGarrett D'Amore if ( ! (*p)(mdoc, n))
38395c635efSGarrett D'Amore return(0);
38495c635efSGarrett D'Amore return(1);
38595c635efSGarrett D'Amore }
38695c635efSGarrett D'Amore
38795c635efSGarrett D'Amore
38895c635efSGarrett D'Amore int
mdoc_valid_post(struct mdoc * mdoc)38995c635efSGarrett D'Amore mdoc_valid_post(struct mdoc *mdoc)
39095c635efSGarrett D'Amore {
39195c635efSGarrett D'Amore v_post *p;
39295c635efSGarrett D'Amore
39395c635efSGarrett D'Amore if (MDOC_VALID & mdoc->last->flags)
39495c635efSGarrett D'Amore return(1);
39595c635efSGarrett D'Amore mdoc->last->flags |= MDOC_VALID;
39695c635efSGarrett D'Amore
39795c635efSGarrett D'Amore switch (mdoc->last->type) {
39895c635efSGarrett D'Amore case (MDOC_TEXT):
39995c635efSGarrett D'Amore /* FALLTHROUGH */
40095c635efSGarrett D'Amore case (MDOC_EQN):
40195c635efSGarrett D'Amore /* FALLTHROUGH */
40295c635efSGarrett D'Amore case (MDOC_TBL):
40395c635efSGarrett D'Amore return(1);
40495c635efSGarrett D'Amore case (MDOC_ROOT):
40595c635efSGarrett D'Amore return(post_root(mdoc));
40695c635efSGarrett D'Amore default:
40795c635efSGarrett D'Amore break;
40895c635efSGarrett D'Amore }
40995c635efSGarrett D'Amore
41095c635efSGarrett D'Amore if (NULL == mdoc_valids[mdoc->last->tok].post)
41195c635efSGarrett D'Amore return(1);
41295c635efSGarrett D'Amore for (p = mdoc_valids[mdoc->last->tok].post; *p; p++)
41395c635efSGarrett D'Amore if ( ! (*p)(mdoc))
41495c635efSGarrett D'Amore return(0);
41595c635efSGarrett D'Amore
41695c635efSGarrett D'Amore return(1);
41795c635efSGarrett D'Amore }
41895c635efSGarrett D'Amore
41995c635efSGarrett D'Amore static int
check_count(struct mdoc * mdoc,enum mdoc_type type,enum check_lvl lvl,enum check_ineq ineq,int val)420*698f87a4SGarrett D'Amore check_count(struct mdoc *mdoc, enum mdoc_type type,
42195c635efSGarrett D'Amore enum check_lvl lvl, enum check_ineq ineq, int val)
42295c635efSGarrett D'Amore {
42395c635efSGarrett D'Amore const char *p;
42495c635efSGarrett D'Amore enum mandocerr t;
42595c635efSGarrett D'Amore
426*698f87a4SGarrett D'Amore if (mdoc->last->type != type)
42795c635efSGarrett D'Amore return(1);
42895c635efSGarrett D'Amore
42995c635efSGarrett D'Amore switch (ineq) {
43095c635efSGarrett D'Amore case (CHECK_LT):
43195c635efSGarrett D'Amore p = "less than ";
432*698f87a4SGarrett D'Amore if (mdoc->last->nchild < val)
43395c635efSGarrett D'Amore return(1);
43495c635efSGarrett D'Amore break;
43595c635efSGarrett D'Amore case (CHECK_GT):
43695c635efSGarrett D'Amore p = "more than ";
437*698f87a4SGarrett D'Amore if (mdoc->last->nchild > val)
43895c635efSGarrett D'Amore return(1);
43995c635efSGarrett D'Amore break;
44095c635efSGarrett D'Amore case (CHECK_EQ):
44195c635efSGarrett D'Amore p = "";
442*698f87a4SGarrett D'Amore if (val == mdoc->last->nchild)
44395c635efSGarrett D'Amore return(1);
44495c635efSGarrett D'Amore break;
44595c635efSGarrett D'Amore default:
44695c635efSGarrett D'Amore abort();
44795c635efSGarrett D'Amore /* NOTREACHED */
44895c635efSGarrett D'Amore }
44995c635efSGarrett D'Amore
45095c635efSGarrett D'Amore t = lvl == CHECK_WARN ? MANDOCERR_ARGCWARN : MANDOCERR_ARGCOUNT;
451*698f87a4SGarrett D'Amore mandoc_vmsg(t, mdoc->parse, mdoc->last->line, mdoc->last->pos,
45295c635efSGarrett D'Amore "want %s%d children (have %d)",
453*698f87a4SGarrett D'Amore p, val, mdoc->last->nchild);
45495c635efSGarrett D'Amore return(1);
45595c635efSGarrett D'Amore }
45695c635efSGarrett D'Amore
45795c635efSGarrett D'Amore static int
berr_ge1(POST_ARGS)45895c635efSGarrett D'Amore berr_ge1(POST_ARGS)
45995c635efSGarrett D'Amore {
46095c635efSGarrett D'Amore
46195c635efSGarrett D'Amore return(check_count(mdoc, MDOC_BODY, CHECK_ERROR, CHECK_GT, 0));
46295c635efSGarrett D'Amore }
46395c635efSGarrett D'Amore
46495c635efSGarrett D'Amore static int
bwarn_ge1(POST_ARGS)46595c635efSGarrett D'Amore bwarn_ge1(POST_ARGS)
46695c635efSGarrett D'Amore {
46795c635efSGarrett D'Amore return(check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0));
46895c635efSGarrett D'Amore }
46995c635efSGarrett D'Amore
47095c635efSGarrett D'Amore static int
ewarn_eq0(POST_ARGS)47195c635efSGarrett D'Amore ewarn_eq0(POST_ARGS)
47295c635efSGarrett D'Amore {
47395c635efSGarrett D'Amore return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0));
47495c635efSGarrett D'Amore }
47595c635efSGarrett D'Amore
47695c635efSGarrett D'Amore static int
ewarn_eq1(POST_ARGS)47795c635efSGarrett D'Amore ewarn_eq1(POST_ARGS)
47895c635efSGarrett D'Amore {
47995c635efSGarrett D'Amore return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1));
48095c635efSGarrett D'Amore }
48195c635efSGarrett D'Amore
48295c635efSGarrett D'Amore static int
ewarn_ge1(POST_ARGS)48395c635efSGarrett D'Amore ewarn_ge1(POST_ARGS)
48495c635efSGarrett D'Amore {
48595c635efSGarrett D'Amore return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0));
48695c635efSGarrett D'Amore }
48795c635efSGarrett D'Amore
48895c635efSGarrett D'Amore static int
ewarn_le1(POST_ARGS)48995c635efSGarrett D'Amore ewarn_le1(POST_ARGS)
49095c635efSGarrett D'Amore {
49195c635efSGarrett D'Amore return(check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_LT, 2));
49295c635efSGarrett D'Amore }
49395c635efSGarrett D'Amore
49495c635efSGarrett D'Amore static int
hwarn_eq0(POST_ARGS)49595c635efSGarrett D'Amore hwarn_eq0(POST_ARGS)
49695c635efSGarrett D'Amore {
49795c635efSGarrett D'Amore return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0));
49895c635efSGarrett D'Amore }
49995c635efSGarrett D'Amore
50095c635efSGarrett D'Amore static int
hwarn_eq1(POST_ARGS)50195c635efSGarrett D'Amore hwarn_eq1(POST_ARGS)
50295c635efSGarrett D'Amore {
50395c635efSGarrett D'Amore return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 1));
50495c635efSGarrett D'Amore }
50595c635efSGarrett D'Amore
50695c635efSGarrett D'Amore static int
hwarn_ge1(POST_ARGS)50795c635efSGarrett D'Amore hwarn_ge1(POST_ARGS)
50895c635efSGarrett D'Amore {
50995c635efSGarrett D'Amore return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_GT, 0));
51095c635efSGarrett D'Amore }
51195c635efSGarrett D'Amore
51295c635efSGarrett D'Amore static int
hwarn_le1(POST_ARGS)51395c635efSGarrett D'Amore hwarn_le1(POST_ARGS)
51495c635efSGarrett D'Amore {
51595c635efSGarrett D'Amore return(check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_LT, 2));
51695c635efSGarrett D'Amore }
51795c635efSGarrett D'Amore
51895c635efSGarrett D'Amore static void
check_args(struct mdoc * mdoc,struct mdoc_node * n)519*698f87a4SGarrett D'Amore check_args(struct mdoc *mdoc, struct mdoc_node *n)
52095c635efSGarrett D'Amore {
52195c635efSGarrett D'Amore int i;
52295c635efSGarrett D'Amore
52395c635efSGarrett D'Amore if (NULL == n->args)
52495c635efSGarrett D'Amore return;
52595c635efSGarrett D'Amore
52695c635efSGarrett D'Amore assert(n->args->argc);
52795c635efSGarrett D'Amore for (i = 0; i < (int)n->args->argc; i++)
528*698f87a4SGarrett D'Amore check_argv(mdoc, n, &n->args->argv[i]);
52995c635efSGarrett D'Amore }
53095c635efSGarrett D'Amore
53195c635efSGarrett D'Amore static void
check_argv(struct mdoc * mdoc,struct mdoc_node * n,struct mdoc_argv * v)532*698f87a4SGarrett D'Amore check_argv(struct mdoc *mdoc, struct mdoc_node *n, struct mdoc_argv *v)
53395c635efSGarrett D'Amore {
53495c635efSGarrett D'Amore int i;
53595c635efSGarrett D'Amore
53695c635efSGarrett D'Amore for (i = 0; i < (int)v->sz; i++)
537*698f87a4SGarrett D'Amore check_text(mdoc, v->line, v->pos, v->value[i]);
53895c635efSGarrett D'Amore
53995c635efSGarrett D'Amore /* FIXME: move to post_std(). */
54095c635efSGarrett D'Amore
54195c635efSGarrett D'Amore if (MDOC_Std == v->arg)
542*698f87a4SGarrett D'Amore if ( ! (v->sz || mdoc->meta.name))
543*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NONAME);
54495c635efSGarrett D'Amore }
54595c635efSGarrett D'Amore
54695c635efSGarrett D'Amore static void
check_text(struct mdoc * mdoc,int ln,int pos,char * p)547*698f87a4SGarrett D'Amore check_text(struct mdoc *mdoc, int ln, int pos, char *p)
54895c635efSGarrett D'Amore {
54995c635efSGarrett D'Amore char *cp;
55095c635efSGarrett D'Amore
551*698f87a4SGarrett D'Amore if (MDOC_LITERAL & mdoc->flags)
55295c635efSGarrett D'Amore return;
55395c635efSGarrett D'Amore
55495c635efSGarrett D'Amore for (cp = p; NULL != (p = strchr(p, '\t')); p++)
555*698f87a4SGarrett D'Amore mdoc_pmsg(mdoc, ln, pos + (int)(p - cp), MANDOCERR_BADTAB);
55695c635efSGarrett D'Amore }
55795c635efSGarrett D'Amore
55895c635efSGarrett D'Amore static int
check_parent(PRE_ARGS,enum mdoct tok,enum mdoc_type t)55995c635efSGarrett D'Amore check_parent(PRE_ARGS, enum mdoct tok, enum mdoc_type t)
56095c635efSGarrett D'Amore {
56195c635efSGarrett D'Amore
56295c635efSGarrett D'Amore assert(n->parent);
56395c635efSGarrett D'Amore if ((MDOC_ROOT == t || tok == n->parent->tok) &&
56495c635efSGarrett D'Amore (t == n->parent->type))
56595c635efSGarrett D'Amore return(1);
56695c635efSGarrett D'Amore
56795c635efSGarrett D'Amore mandoc_vmsg(MANDOCERR_SYNTCHILD, mdoc->parse, n->line,
56895c635efSGarrett D'Amore n->pos, "want parent %s", MDOC_ROOT == t ?
56995c635efSGarrett D'Amore "<root>" : mdoc_macronames[tok]);
57095c635efSGarrett D'Amore return(0);
57195c635efSGarrett D'Amore }
57295c635efSGarrett D'Amore
57395c635efSGarrett D'Amore
57495c635efSGarrett D'Amore static int
pre_display(PRE_ARGS)57595c635efSGarrett D'Amore pre_display(PRE_ARGS)
57695c635efSGarrett D'Amore {
57795c635efSGarrett D'Amore struct mdoc_node *node;
57895c635efSGarrett D'Amore
57995c635efSGarrett D'Amore if (MDOC_BLOCK != n->type)
58095c635efSGarrett D'Amore return(1);
58195c635efSGarrett D'Amore
58295c635efSGarrett D'Amore for (node = mdoc->last->parent; node; node = node->parent)
58395c635efSGarrett D'Amore if (MDOC_BLOCK == node->type)
58495c635efSGarrett D'Amore if (MDOC_Bd == node->tok)
58595c635efSGarrett D'Amore break;
58695c635efSGarrett D'Amore
58795c635efSGarrett D'Amore if (node)
58895c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NESTEDDISP);
58995c635efSGarrett D'Amore
59095c635efSGarrett D'Amore return(1);
59195c635efSGarrett D'Amore }
59295c635efSGarrett D'Amore
59395c635efSGarrett D'Amore
59495c635efSGarrett D'Amore static int
pre_bl(PRE_ARGS)59595c635efSGarrett D'Amore pre_bl(PRE_ARGS)
59695c635efSGarrett D'Amore {
59795c635efSGarrett D'Amore int i, comp, dup;
59895c635efSGarrett D'Amore const char *offs, *width;
59995c635efSGarrett D'Amore enum mdoc_list lt;
60095c635efSGarrett D'Amore struct mdoc_node *np;
60195c635efSGarrett D'Amore
60295c635efSGarrett D'Amore if (MDOC_BLOCK != n->type) {
60395c635efSGarrett D'Amore if (ENDBODY_NOT != n->end) {
60495c635efSGarrett D'Amore assert(n->pending);
60595c635efSGarrett D'Amore np = n->pending->parent;
60695c635efSGarrett D'Amore } else
60795c635efSGarrett D'Amore np = n->parent;
60895c635efSGarrett D'Amore
60995c635efSGarrett D'Amore assert(np);
61095c635efSGarrett D'Amore assert(MDOC_BLOCK == np->type);
61195c635efSGarrett D'Amore assert(MDOC_Bl == np->tok);
61295c635efSGarrett D'Amore return(1);
61395c635efSGarrett D'Amore }
61495c635efSGarrett D'Amore
61595c635efSGarrett D'Amore /*
61695c635efSGarrett D'Amore * First figure out which kind of list to use: bind ourselves to
61795c635efSGarrett D'Amore * the first mentioned list type and warn about any remaining
61895c635efSGarrett D'Amore * ones. If we find no list type, we default to LIST_item.
61995c635efSGarrett D'Amore */
62095c635efSGarrett D'Amore
62195c635efSGarrett D'Amore /* LINTED */
62295c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) {
62395c635efSGarrett D'Amore lt = LIST__NONE;
62495c635efSGarrett D'Amore dup = comp = 0;
62595c635efSGarrett D'Amore width = offs = NULL;
62695c635efSGarrett D'Amore switch (n->args->argv[i].arg) {
62795c635efSGarrett D'Amore /* Set list types. */
62895c635efSGarrett D'Amore case (MDOC_Bullet):
62995c635efSGarrett D'Amore lt = LIST_bullet;
63095c635efSGarrett D'Amore break;
63195c635efSGarrett D'Amore case (MDOC_Dash):
63295c635efSGarrett D'Amore lt = LIST_dash;
63395c635efSGarrett D'Amore break;
63495c635efSGarrett D'Amore case (MDOC_Enum):
63595c635efSGarrett D'Amore lt = LIST_enum;
63695c635efSGarrett D'Amore break;
63795c635efSGarrett D'Amore case (MDOC_Hyphen):
63895c635efSGarrett D'Amore lt = LIST_hyphen;
63995c635efSGarrett D'Amore break;
64095c635efSGarrett D'Amore case (MDOC_Item):
64195c635efSGarrett D'Amore lt = LIST_item;
64295c635efSGarrett D'Amore break;
64395c635efSGarrett D'Amore case (MDOC_Tag):
64495c635efSGarrett D'Amore lt = LIST_tag;
64595c635efSGarrett D'Amore break;
64695c635efSGarrett D'Amore case (MDOC_Diag):
64795c635efSGarrett D'Amore lt = LIST_diag;
64895c635efSGarrett D'Amore break;
64995c635efSGarrett D'Amore case (MDOC_Hang):
65095c635efSGarrett D'Amore lt = LIST_hang;
65195c635efSGarrett D'Amore break;
65295c635efSGarrett D'Amore case (MDOC_Ohang):
65395c635efSGarrett D'Amore lt = LIST_ohang;
65495c635efSGarrett D'Amore break;
65595c635efSGarrett D'Amore case (MDOC_Inset):
65695c635efSGarrett D'Amore lt = LIST_inset;
65795c635efSGarrett D'Amore break;
65895c635efSGarrett D'Amore case (MDOC_Column):
65995c635efSGarrett D'Amore lt = LIST_column;
66095c635efSGarrett D'Amore break;
66195c635efSGarrett D'Amore /* Set list arguments. */
66295c635efSGarrett D'Amore case (MDOC_Compact):
66395c635efSGarrett D'Amore dup = n->norm->Bl.comp;
66495c635efSGarrett D'Amore comp = 1;
66595c635efSGarrett D'Amore break;
66695c635efSGarrett D'Amore case (MDOC_Width):
66795c635efSGarrett D'Amore /* NB: this can be empty! */
66895c635efSGarrett D'Amore if (n->args->argv[i].sz) {
66995c635efSGarrett D'Amore width = n->args->argv[i].value[0];
67095c635efSGarrett D'Amore dup = (NULL != n->norm->Bl.width);
67195c635efSGarrett D'Amore break;
67295c635efSGarrett D'Amore }
67395c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
67495c635efSGarrett D'Amore break;
67595c635efSGarrett D'Amore case (MDOC_Offset):
67695c635efSGarrett D'Amore /* NB: this can be empty! */
67795c635efSGarrett D'Amore if (n->args->argv[i].sz) {
67895c635efSGarrett D'Amore offs = n->args->argv[i].value[0];
67995c635efSGarrett D'Amore dup = (NULL != n->norm->Bl.offs);
68095c635efSGarrett D'Amore break;
68195c635efSGarrett D'Amore }
68295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
68395c635efSGarrett D'Amore break;
68495c635efSGarrett D'Amore default:
68595c635efSGarrett D'Amore continue;
68695c635efSGarrett D'Amore }
68795c635efSGarrett D'Amore
68895c635efSGarrett D'Amore /* Check: duplicate auxiliary arguments. */
68995c635efSGarrett D'Amore
69095c635efSGarrett D'Amore if (dup)
69195c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
69295c635efSGarrett D'Amore
69395c635efSGarrett D'Amore if (comp && ! dup)
69495c635efSGarrett D'Amore n->norm->Bl.comp = comp;
69595c635efSGarrett D'Amore if (offs && ! dup)
69695c635efSGarrett D'Amore n->norm->Bl.offs = offs;
69795c635efSGarrett D'Amore if (width && ! dup)
69895c635efSGarrett D'Amore n->norm->Bl.width = width;
69995c635efSGarrett D'Amore
70095c635efSGarrett D'Amore /* Check: multiple list types. */
70195c635efSGarrett D'Amore
70295c635efSGarrett D'Amore if (LIST__NONE != lt && n->norm->Bl.type != LIST__NONE)
70395c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_LISTREP);
70495c635efSGarrett D'Amore
70595c635efSGarrett D'Amore /* Assign list type. */
70695c635efSGarrett D'Amore
70795c635efSGarrett D'Amore if (LIST__NONE != lt && n->norm->Bl.type == LIST__NONE) {
70895c635efSGarrett D'Amore n->norm->Bl.type = lt;
70995c635efSGarrett D'Amore /* Set column information, too. */
71095c635efSGarrett D'Amore if (LIST_column == lt) {
71195c635efSGarrett D'Amore n->norm->Bl.ncols =
71295c635efSGarrett D'Amore n->args->argv[i].sz;
71395c635efSGarrett D'Amore n->norm->Bl.cols = (void *)
71495c635efSGarrett D'Amore n->args->argv[i].value;
71595c635efSGarrett D'Amore }
71695c635efSGarrett D'Amore }
71795c635efSGarrett D'Amore
71895c635efSGarrett D'Amore /* The list type should come first. */
71995c635efSGarrett D'Amore
72095c635efSGarrett D'Amore if (n->norm->Bl.type == LIST__NONE)
72195c635efSGarrett D'Amore if (n->norm->Bl.width ||
72295c635efSGarrett D'Amore n->norm->Bl.offs ||
72395c635efSGarrett D'Amore n->norm->Bl.comp)
72495c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_LISTFIRST);
72595c635efSGarrett D'Amore
72695c635efSGarrett D'Amore continue;
72795c635efSGarrett D'Amore }
72895c635efSGarrett D'Amore
72995c635efSGarrett D'Amore /* Allow lists to default to LIST_item. */
73095c635efSGarrett D'Amore
73195c635efSGarrett D'Amore if (LIST__NONE == n->norm->Bl.type) {
73295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_LISTTYPE);
73395c635efSGarrett D'Amore n->norm->Bl.type = LIST_item;
73495c635efSGarrett D'Amore }
73595c635efSGarrett D'Amore
73695c635efSGarrett D'Amore /*
73795c635efSGarrett D'Amore * Validate the width field. Some list types don't need width
73895c635efSGarrett D'Amore * types and should be warned about them. Others should have it
739*698f87a4SGarrett D'Amore * and must also be warned. Yet others have a default and need
740*698f87a4SGarrett D'Amore * no warning.
74195c635efSGarrett D'Amore */
74295c635efSGarrett D'Amore
74395c635efSGarrett D'Amore switch (n->norm->Bl.type) {
74495c635efSGarrett D'Amore case (LIST_tag):
745*698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width)
74695c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NOWIDTHARG);
74795c635efSGarrett D'Amore break;
74895c635efSGarrett D'Amore case (LIST_column):
74995c635efSGarrett D'Amore /* FALLTHROUGH */
75095c635efSGarrett D'Amore case (LIST_diag):
75195c635efSGarrett D'Amore /* FALLTHROUGH */
75295c635efSGarrett D'Amore case (LIST_ohang):
75395c635efSGarrett D'Amore /* FALLTHROUGH */
75495c635efSGarrett D'Amore case (LIST_inset):
75595c635efSGarrett D'Amore /* FALLTHROUGH */
75695c635efSGarrett D'Amore case (LIST_item):
75795c635efSGarrett D'Amore if (n->norm->Bl.width)
75895c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
75995c635efSGarrett D'Amore break;
760*698f87a4SGarrett D'Amore case (LIST_bullet):
761*698f87a4SGarrett D'Amore /* FALLTHROUGH */
762*698f87a4SGarrett D'Amore case (LIST_dash):
763*698f87a4SGarrett D'Amore /* FALLTHROUGH */
764*698f87a4SGarrett D'Amore case (LIST_hyphen):
765*698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width)
766*698f87a4SGarrett D'Amore n->norm->Bl.width = "2n";
767*698f87a4SGarrett D'Amore break;
768*698f87a4SGarrett D'Amore case (LIST_enum):
769*698f87a4SGarrett D'Amore if (NULL == n->norm->Bl.width)
770*698f87a4SGarrett D'Amore n->norm->Bl.width = "3n";
771*698f87a4SGarrett D'Amore break;
77295c635efSGarrett D'Amore default:
77395c635efSGarrett D'Amore break;
77495c635efSGarrett D'Amore }
77595c635efSGarrett D'Amore
77695c635efSGarrett D'Amore return(1);
77795c635efSGarrett D'Amore }
77895c635efSGarrett D'Amore
77995c635efSGarrett D'Amore
78095c635efSGarrett D'Amore static int
pre_bd(PRE_ARGS)78195c635efSGarrett D'Amore pre_bd(PRE_ARGS)
78295c635efSGarrett D'Amore {
78395c635efSGarrett D'Amore int i, dup, comp;
78495c635efSGarrett D'Amore enum mdoc_disp dt;
78595c635efSGarrett D'Amore const char *offs;
78695c635efSGarrett D'Amore struct mdoc_node *np;
78795c635efSGarrett D'Amore
78895c635efSGarrett D'Amore if (MDOC_BLOCK != n->type) {
78995c635efSGarrett D'Amore if (ENDBODY_NOT != n->end) {
79095c635efSGarrett D'Amore assert(n->pending);
79195c635efSGarrett D'Amore np = n->pending->parent;
79295c635efSGarrett D'Amore } else
79395c635efSGarrett D'Amore np = n->parent;
79495c635efSGarrett D'Amore
79595c635efSGarrett D'Amore assert(np);
79695c635efSGarrett D'Amore assert(MDOC_BLOCK == np->type);
79795c635efSGarrett D'Amore assert(MDOC_Bd == np->tok);
79895c635efSGarrett D'Amore return(1);
79995c635efSGarrett D'Amore }
80095c635efSGarrett D'Amore
80195c635efSGarrett D'Amore /* LINTED */
80295c635efSGarrett D'Amore for (i = 0; n->args && i < (int)n->args->argc; i++) {
80395c635efSGarrett D'Amore dt = DISP__NONE;
80495c635efSGarrett D'Amore dup = comp = 0;
80595c635efSGarrett D'Amore offs = NULL;
80695c635efSGarrett D'Amore
80795c635efSGarrett D'Amore switch (n->args->argv[i].arg) {
80895c635efSGarrett D'Amore case (MDOC_Centred):
80995c635efSGarrett D'Amore dt = DISP_centred;
81095c635efSGarrett D'Amore break;
81195c635efSGarrett D'Amore case (MDOC_Ragged):
81295c635efSGarrett D'Amore dt = DISP_ragged;
81395c635efSGarrett D'Amore break;
81495c635efSGarrett D'Amore case (MDOC_Unfilled):
81595c635efSGarrett D'Amore dt = DISP_unfilled;
81695c635efSGarrett D'Amore break;
81795c635efSGarrett D'Amore case (MDOC_Filled):
81895c635efSGarrett D'Amore dt = DISP_filled;
81995c635efSGarrett D'Amore break;
82095c635efSGarrett D'Amore case (MDOC_Literal):
82195c635efSGarrett D'Amore dt = DISP_literal;
82295c635efSGarrett D'Amore break;
82395c635efSGarrett D'Amore case (MDOC_File):
82495c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_BADDISP);
82595c635efSGarrett D'Amore return(0);
82695c635efSGarrett D'Amore case (MDOC_Offset):
82795c635efSGarrett D'Amore /* NB: this can be empty! */
82895c635efSGarrett D'Amore if (n->args->argv[i].sz) {
82995c635efSGarrett D'Amore offs = n->args->argv[i].value[0];
83095c635efSGarrett D'Amore dup = (NULL != n->norm->Bd.offs);
83195c635efSGarrett D'Amore break;
83295c635efSGarrett D'Amore }
83395c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_IGNARGV);
83495c635efSGarrett D'Amore break;
83595c635efSGarrett D'Amore case (MDOC_Compact):
83695c635efSGarrett D'Amore comp = 1;
83795c635efSGarrett D'Amore dup = n->norm->Bd.comp;
83895c635efSGarrett D'Amore break;
83995c635efSGarrett D'Amore default:
84095c635efSGarrett D'Amore abort();
84195c635efSGarrett D'Amore /* NOTREACHED */
84295c635efSGarrett D'Amore }
84395c635efSGarrett D'Amore
84495c635efSGarrett D'Amore /* Check whether we have duplicates. */
84595c635efSGarrett D'Amore
84695c635efSGarrett D'Amore if (dup)
84795c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_ARGVREP);
84895c635efSGarrett D'Amore
84995c635efSGarrett D'Amore /* Make our auxiliary assignments. */
85095c635efSGarrett D'Amore
85195c635efSGarrett D'Amore if (offs && ! dup)
85295c635efSGarrett D'Amore n->norm->Bd.offs = offs;
85395c635efSGarrett D'Amore if (comp && ! dup)
85495c635efSGarrett D'Amore n->norm->Bd.comp = comp;
85595c635efSGarrett D'Amore
85695c635efSGarrett D'Amore /* Check whether a type has already been assigned. */
85795c635efSGarrett D'Amore
85895c635efSGarrett D'Amore if (DISP__NONE != dt && n->norm->Bd.type != DISP__NONE)
85995c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_DISPREP);
86095c635efSGarrett D'Amore
86195c635efSGarrett D'Amore /* Make our type assignment. */
86295c635efSGarrett D'Amore
86395c635efSGarrett D'Amore if (DISP__NONE != dt && n->norm->Bd.type == DISP__NONE)
86495c635efSGarrett D'Amore n->norm->Bd.type = dt;
86595c635efSGarrett D'Amore }
86695c635efSGarrett D'Amore
86795c635efSGarrett D'Amore if (DISP__NONE == n->norm->Bd.type) {
86895c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_DISPTYPE);
86995c635efSGarrett D'Amore n->norm->Bd.type = DISP_ragged;
87095c635efSGarrett D'Amore }
87195c635efSGarrett D'Amore
87295c635efSGarrett D'Amore return(1);
87395c635efSGarrett D'Amore }
87495c635efSGarrett D'Amore
87595c635efSGarrett D'Amore
87695c635efSGarrett D'Amore static int
pre_ss(PRE_ARGS)87795c635efSGarrett D'Amore pre_ss(PRE_ARGS)
87895c635efSGarrett D'Amore {
87995c635efSGarrett D'Amore
88095c635efSGarrett D'Amore if (MDOC_BLOCK != n->type)
88195c635efSGarrett D'Amore return(1);
88295c635efSGarrett D'Amore return(check_parent(mdoc, n, MDOC_Sh, MDOC_BODY));
88395c635efSGarrett D'Amore }
88495c635efSGarrett D'Amore
88595c635efSGarrett D'Amore
88695c635efSGarrett D'Amore static int
pre_sh(PRE_ARGS)88795c635efSGarrett D'Amore pre_sh(PRE_ARGS)
88895c635efSGarrett D'Amore {
88995c635efSGarrett D'Amore
89095c635efSGarrett D'Amore if (MDOC_BLOCK != n->type)
89195c635efSGarrett D'Amore return(1);
89295c635efSGarrett D'Amore return(check_parent(mdoc, n, MDOC_MAX, MDOC_ROOT));
89395c635efSGarrett D'Amore }
89495c635efSGarrett D'Amore
89595c635efSGarrett D'Amore
89695c635efSGarrett D'Amore static int
pre_it(PRE_ARGS)89795c635efSGarrett D'Amore pre_it(PRE_ARGS)
89895c635efSGarrett D'Amore {
89995c635efSGarrett D'Amore
90095c635efSGarrett D'Amore if (MDOC_BLOCK != n->type)
90195c635efSGarrett D'Amore return(1);
90295c635efSGarrett D'Amore
90395c635efSGarrett D'Amore return(check_parent(mdoc, n, MDOC_Bl, MDOC_BODY));
90495c635efSGarrett D'Amore }
90595c635efSGarrett D'Amore
90695c635efSGarrett D'Amore
90795c635efSGarrett D'Amore static int
pre_an(PRE_ARGS)90895c635efSGarrett D'Amore pre_an(PRE_ARGS)
90995c635efSGarrett D'Amore {
91095c635efSGarrett D'Amore int i;
91195c635efSGarrett D'Amore
91295c635efSGarrett D'Amore if (NULL == n->args)
91395c635efSGarrett D'Amore return(1);
91495c635efSGarrett D'Amore
91595c635efSGarrett D'Amore for (i = 1; i < (int)n->args->argc; i++)
91695c635efSGarrett D'Amore mdoc_pmsg(mdoc, n->args->argv[i].line,
91795c635efSGarrett D'Amore n->args->argv[i].pos, MANDOCERR_IGNARGV);
91895c635efSGarrett D'Amore
91995c635efSGarrett D'Amore if (MDOC_Split == n->args->argv[0].arg)
92095c635efSGarrett D'Amore n->norm->An.auth = AUTH_split;
92195c635efSGarrett D'Amore else if (MDOC_Nosplit == n->args->argv[0].arg)
92295c635efSGarrett D'Amore n->norm->An.auth = AUTH_nosplit;
92395c635efSGarrett D'Amore else
92495c635efSGarrett D'Amore abort();
92595c635efSGarrett D'Amore
92695c635efSGarrett D'Amore return(1);
92795c635efSGarrett D'Amore }
92895c635efSGarrett D'Amore
92995c635efSGarrett D'Amore static int
pre_std(PRE_ARGS)93095c635efSGarrett D'Amore pre_std(PRE_ARGS)
93195c635efSGarrett D'Amore {
93295c635efSGarrett D'Amore
93395c635efSGarrett D'Amore if (n->args && 1 == n->args->argc)
93495c635efSGarrett D'Amore if (MDOC_Std == n->args->argv[0].arg)
93595c635efSGarrett D'Amore return(1);
93695c635efSGarrett D'Amore
93795c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NOARGV);
93895c635efSGarrett D'Amore return(1);
93995c635efSGarrett D'Amore }
94095c635efSGarrett D'Amore
94195c635efSGarrett D'Amore static int
pre_dt(PRE_ARGS)94295c635efSGarrett D'Amore pre_dt(PRE_ARGS)
94395c635efSGarrett D'Amore {
94495c635efSGarrett D'Amore
94595c635efSGarrett D'Amore if (NULL == mdoc->meta.date || mdoc->meta.os)
94695c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
94795c635efSGarrett D'Amore
94895c635efSGarrett D'Amore if (mdoc->meta.title)
94995c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
95095c635efSGarrett D'Amore
95195c635efSGarrett D'Amore return(1);
95295c635efSGarrett D'Amore }
95395c635efSGarrett D'Amore
95495c635efSGarrett D'Amore static int
pre_os(PRE_ARGS)95595c635efSGarrett D'Amore pre_os(PRE_ARGS)
95695c635efSGarrett D'Amore {
95795c635efSGarrett D'Amore
95895c635efSGarrett D'Amore if (NULL == mdoc->meta.title || NULL == mdoc->meta.date)
95995c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
96095c635efSGarrett D'Amore
96195c635efSGarrett D'Amore if (mdoc->meta.os)
96295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
96395c635efSGarrett D'Amore
96495c635efSGarrett D'Amore return(1);
96595c635efSGarrett D'Amore }
96695c635efSGarrett D'Amore
96795c635efSGarrett D'Amore static int
pre_dd(PRE_ARGS)96895c635efSGarrett D'Amore pre_dd(PRE_ARGS)
96995c635efSGarrett D'Amore {
97095c635efSGarrett D'Amore
97195c635efSGarrett D'Amore if (mdoc->meta.title || mdoc->meta.os)
97295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGOOO);
97395c635efSGarrett D'Amore
97495c635efSGarrett D'Amore if (mdoc->meta.date)
97595c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_PROLOGREP);
97695c635efSGarrett D'Amore
97795c635efSGarrett D'Amore return(1);
97895c635efSGarrett D'Amore }
97995c635efSGarrett D'Amore
98095c635efSGarrett D'Amore
98195c635efSGarrett D'Amore static int
post_bf(POST_ARGS)98295c635efSGarrett D'Amore post_bf(POST_ARGS)
98395c635efSGarrett D'Amore {
98495c635efSGarrett D'Amore struct mdoc_node *np;
98595c635efSGarrett D'Amore enum mdocargt arg;
98695c635efSGarrett D'Amore
98795c635efSGarrett D'Amore /*
98895c635efSGarrett D'Amore * Unlike other data pointers, these are "housed" by the HEAD
98995c635efSGarrett D'Amore * element, which contains the goods.
99095c635efSGarrett D'Amore */
99195c635efSGarrett D'Amore
99295c635efSGarrett D'Amore if (MDOC_HEAD != mdoc->last->type) {
99395c635efSGarrett D'Amore if (ENDBODY_NOT != mdoc->last->end) {
99495c635efSGarrett D'Amore assert(mdoc->last->pending);
99595c635efSGarrett D'Amore np = mdoc->last->pending->parent->head;
99695c635efSGarrett D'Amore } else if (MDOC_BLOCK != mdoc->last->type) {
99795c635efSGarrett D'Amore np = mdoc->last->parent->head;
99895c635efSGarrett D'Amore } else
99995c635efSGarrett D'Amore np = mdoc->last->head;
100095c635efSGarrett D'Amore
100195c635efSGarrett D'Amore assert(np);
100295c635efSGarrett D'Amore assert(MDOC_HEAD == np->type);
100395c635efSGarrett D'Amore assert(MDOC_Bf == np->tok);
100495c635efSGarrett D'Amore return(1);
100595c635efSGarrett D'Amore }
100695c635efSGarrett D'Amore
100795c635efSGarrett D'Amore np = mdoc->last;
100895c635efSGarrett D'Amore assert(MDOC_BLOCK == np->parent->type);
100995c635efSGarrett D'Amore assert(MDOC_Bf == np->parent->tok);
101095c635efSGarrett D'Amore
101195c635efSGarrett D'Amore /*
101295c635efSGarrett D'Amore * Cannot have both argument and parameter.
101395c635efSGarrett D'Amore * If neither is specified, let it through with a warning.
101495c635efSGarrett D'Amore */
101595c635efSGarrett D'Amore
101695c635efSGarrett D'Amore if (np->parent->args && np->child) {
101795c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_SYNTARGVCOUNT);
101895c635efSGarrett D'Amore return(0);
101995c635efSGarrett D'Amore } else if (NULL == np->parent->args && NULL == np->child) {
102095c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
102195c635efSGarrett D'Amore return(1);
102295c635efSGarrett D'Amore }
102395c635efSGarrett D'Amore
102495c635efSGarrett D'Amore /* Extract argument into data. */
102595c635efSGarrett D'Amore
102695c635efSGarrett D'Amore if (np->parent->args) {
102795c635efSGarrett D'Amore arg = np->parent->args->argv[0].arg;
102895c635efSGarrett D'Amore if (MDOC_Emphasis == arg)
102995c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em;
103095c635efSGarrett D'Amore else if (MDOC_Literal == arg)
103195c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li;
103295c635efSGarrett D'Amore else if (MDOC_Symbolic == arg)
103395c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy;
103495c635efSGarrett D'Amore else
103595c635efSGarrett D'Amore abort();
103695c635efSGarrett D'Amore return(1);
103795c635efSGarrett D'Amore }
103895c635efSGarrett D'Amore
103995c635efSGarrett D'Amore /* Extract parameter into data. */
104095c635efSGarrett D'Amore
104195c635efSGarrett D'Amore if (0 == strcmp(np->child->string, "Em"))
104295c635efSGarrett D'Amore np->norm->Bf.font = FONT_Em;
104395c635efSGarrett D'Amore else if (0 == strcmp(np->child->string, "Li"))
104495c635efSGarrett D'Amore np->norm->Bf.font = FONT_Li;
104595c635efSGarrett D'Amore else if (0 == strcmp(np->child->string, "Sy"))
104695c635efSGarrett D'Amore np->norm->Bf.font = FONT_Sy;
104795c635efSGarrett D'Amore else
104895c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_FONTTYPE);
104995c635efSGarrett D'Amore
105095c635efSGarrett D'Amore return(1);
105195c635efSGarrett D'Amore }
105295c635efSGarrett D'Amore
105395c635efSGarrett D'Amore static int
post_lb(POST_ARGS)105495c635efSGarrett D'Amore post_lb(POST_ARGS)
105595c635efSGarrett D'Amore {
105695c635efSGarrett D'Amore const char *p;
105795c635efSGarrett D'Amore char *buf;
105895c635efSGarrett D'Amore size_t sz;
105995c635efSGarrett D'Amore
106095c635efSGarrett D'Amore check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
106195c635efSGarrett D'Amore
106295c635efSGarrett D'Amore assert(mdoc->last->child);
106395c635efSGarrett D'Amore assert(MDOC_TEXT == mdoc->last->child->type);
106495c635efSGarrett D'Amore
106595c635efSGarrett D'Amore p = mdoc_a2lib(mdoc->last->child->string);
106695c635efSGarrett D'Amore
106795c635efSGarrett D'Amore /* If lookup ok, replace with table value. */
106895c635efSGarrett D'Amore
106995c635efSGarrett D'Amore if (p) {
107095c635efSGarrett D'Amore free(mdoc->last->child->string);
107195c635efSGarrett D'Amore mdoc->last->child->string = mandoc_strdup(p);
107295c635efSGarrett D'Amore return(1);
107395c635efSGarrett D'Amore }
107495c635efSGarrett D'Amore
107595c635efSGarrett D'Amore /* If not, use "library ``xxxx''. */
107695c635efSGarrett D'Amore
107795c635efSGarrett D'Amore sz = strlen(mdoc->last->child->string) +
107895c635efSGarrett D'Amore 2 + strlen("\\(lqlibrary\\(rq");
107995c635efSGarrett D'Amore buf = mandoc_malloc(sz);
108095c635efSGarrett D'Amore snprintf(buf, sz, "library \\(lq%s\\(rq",
108195c635efSGarrett D'Amore mdoc->last->child->string);
108295c635efSGarrett D'Amore free(mdoc->last->child->string);
108395c635efSGarrett D'Amore mdoc->last->child->string = buf;
108495c635efSGarrett D'Amore return(1);
108595c635efSGarrett D'Amore }
108695c635efSGarrett D'Amore
108795c635efSGarrett D'Amore static int
post_eoln(POST_ARGS)108895c635efSGarrett D'Amore post_eoln(POST_ARGS)
108995c635efSGarrett D'Amore {
109095c635efSGarrett D'Amore
109195c635efSGarrett D'Amore if (mdoc->last->child)
109295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
109395c635efSGarrett D'Amore return(1);
109495c635efSGarrett D'Amore }
109595c635efSGarrett D'Amore
109695c635efSGarrett D'Amore
109795c635efSGarrett D'Amore static int
post_vt(POST_ARGS)109895c635efSGarrett D'Amore post_vt(POST_ARGS)
109995c635efSGarrett D'Amore {
110095c635efSGarrett D'Amore const struct mdoc_node *n;
110195c635efSGarrett D'Amore
110295c635efSGarrett D'Amore /*
110395c635efSGarrett D'Amore * The Vt macro comes in both ELEM and BLOCK form, both of which
110495c635efSGarrett D'Amore * have different syntaxes (yet more context-sensitive
110595c635efSGarrett D'Amore * behaviour). ELEM types must have a child, which is already
110695c635efSGarrett D'Amore * guaranteed by the in_line parsing routine; BLOCK types,
110795c635efSGarrett D'Amore * specifically the BODY, should only have TEXT children.
110895c635efSGarrett D'Amore */
110995c635efSGarrett D'Amore
111095c635efSGarrett D'Amore if (MDOC_BODY != mdoc->last->type)
111195c635efSGarrett D'Amore return(1);
111295c635efSGarrett D'Amore
111395c635efSGarrett D'Amore for (n = mdoc->last->child; n; n = n->next)
111495c635efSGarrett D'Amore if (MDOC_TEXT != n->type)
111595c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_CHILD);
111695c635efSGarrett D'Amore
111795c635efSGarrett D'Amore return(1);
111895c635efSGarrett D'Amore }
111995c635efSGarrett D'Amore
112095c635efSGarrett D'Amore
112195c635efSGarrett D'Amore static int
post_nm(POST_ARGS)112295c635efSGarrett D'Amore post_nm(POST_ARGS)
112395c635efSGarrett D'Amore {
112495c635efSGarrett D'Amore char buf[BUFSIZ];
112595c635efSGarrett D'Amore int c;
112695c635efSGarrett D'Amore
1127*698f87a4SGarrett D'Amore if (NULL != mdoc->meta.name)
112895c635efSGarrett D'Amore return(1);
112995c635efSGarrett D'Amore
1130*698f87a4SGarrett D'Amore /* Try to use our children for setting the meta name. */
113195c635efSGarrett D'Amore
1132*698f87a4SGarrett D'Amore if (NULL != mdoc->last->child) {
113395c635efSGarrett D'Amore buf[0] = '\0';
1134*698f87a4SGarrett D'Amore c = concat(buf, mdoc->last->child, BUFSIZ);
1135*698f87a4SGarrett D'Amore } else
1136*698f87a4SGarrett D'Amore c = 0;
1137*698f87a4SGarrett D'Amore
1138*698f87a4SGarrett D'Amore switch (c) {
1139*698f87a4SGarrett D'Amore case (-1):
114095c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
114195c635efSGarrett D'Amore return(0);
1142*698f87a4SGarrett D'Amore case (0):
1143*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NONAME);
1144*698f87a4SGarrett D'Amore mdoc->meta.name = mandoc_strdup("UNKNOWN");
1145*698f87a4SGarrett D'Amore break;
1146*698f87a4SGarrett D'Amore default:
114795c635efSGarrett D'Amore mdoc->meta.name = mandoc_strdup(buf);
1148*698f87a4SGarrett D'Amore break;
1149*698f87a4SGarrett D'Amore }
115095c635efSGarrett D'Amore return(1);
115195c635efSGarrett D'Amore }
115295c635efSGarrett D'Amore
115395c635efSGarrett D'Amore static int
post_literal(POST_ARGS)115495c635efSGarrett D'Amore post_literal(POST_ARGS)
115595c635efSGarrett D'Amore {
115695c635efSGarrett D'Amore
115795c635efSGarrett D'Amore /*
115895c635efSGarrett D'Amore * The `Dl' (note "el" not "one") and `Bd' macros unset the
115995c635efSGarrett D'Amore * MDOC_LITERAL flag as they leave. Note that `Bd' only sets
116095c635efSGarrett D'Amore * this in literal mode, but it doesn't hurt to just switch it
116195c635efSGarrett D'Amore * off in general since displays can't be nested.
116295c635efSGarrett D'Amore */
116395c635efSGarrett D'Amore
116495c635efSGarrett D'Amore if (MDOC_BODY == mdoc->last->type)
116595c635efSGarrett D'Amore mdoc->flags &= ~MDOC_LITERAL;
116695c635efSGarrett D'Amore
116795c635efSGarrett D'Amore return(1);
116895c635efSGarrett D'Amore }
116995c635efSGarrett D'Amore
117095c635efSGarrett D'Amore static int
post_defaults(POST_ARGS)117195c635efSGarrett D'Amore post_defaults(POST_ARGS)
117295c635efSGarrett D'Amore {
117395c635efSGarrett D'Amore struct mdoc_node *nn;
117495c635efSGarrett D'Amore
117595c635efSGarrett D'Amore /*
117695c635efSGarrett D'Amore * The `Ar' defaults to "file ..." if no value is provided as an
117795c635efSGarrett D'Amore * argument; the `Mt' and `Pa' macros use "~"; the `Li' just
117895c635efSGarrett D'Amore * gets an empty string.
117995c635efSGarrett D'Amore */
118095c635efSGarrett D'Amore
118195c635efSGarrett D'Amore if (mdoc->last->child)
118295c635efSGarrett D'Amore return(1);
118395c635efSGarrett D'Amore
118495c635efSGarrett D'Amore nn = mdoc->last;
118595c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
118695c635efSGarrett D'Amore
118795c635efSGarrett D'Amore switch (nn->tok) {
118895c635efSGarrett D'Amore case (MDOC_Ar):
118995c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "file"))
119095c635efSGarrett D'Amore return(0);
119195c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "..."))
119295c635efSGarrett D'Amore return(0);
119395c635efSGarrett D'Amore break;
119495c635efSGarrett D'Amore case (MDOC_At):
119595c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "AT&T"))
119695c635efSGarrett D'Amore return(0);
119795c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "UNIX"))
119895c635efSGarrett D'Amore return(0);
119995c635efSGarrett D'Amore break;
120095c635efSGarrett D'Amore case (MDOC_Li):
120195c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, ""))
120295c635efSGarrett D'Amore return(0);
120395c635efSGarrett D'Amore break;
120495c635efSGarrett D'Amore case (MDOC_Pa):
120595c635efSGarrett D'Amore /* FALLTHROUGH */
120695c635efSGarrett D'Amore case (MDOC_Mt):
120795c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, nn->line, nn->pos, "~"))
120895c635efSGarrett D'Amore return(0);
120995c635efSGarrett D'Amore break;
121095c635efSGarrett D'Amore default:
121195c635efSGarrett D'Amore abort();
121295c635efSGarrett D'Amore /* NOTREACHED */
121395c635efSGarrett D'Amore }
121495c635efSGarrett D'Amore
121595c635efSGarrett D'Amore mdoc->last = nn;
121695c635efSGarrett D'Amore return(1);
121795c635efSGarrett D'Amore }
121895c635efSGarrett D'Amore
121995c635efSGarrett D'Amore static int
post_at(POST_ARGS)122095c635efSGarrett D'Amore post_at(POST_ARGS)
122195c635efSGarrett D'Amore {
122295c635efSGarrett D'Amore const char *p, *q;
122395c635efSGarrett D'Amore char *buf;
122495c635efSGarrett D'Amore size_t sz;
122595c635efSGarrett D'Amore
122695c635efSGarrett D'Amore /*
122795c635efSGarrett D'Amore * If we have a child, look it up in the standard keys. If a
122895c635efSGarrett D'Amore * key exist, use that instead of the child; if it doesn't,
122995c635efSGarrett D'Amore * prefix "AT&T UNIX " to the existing data.
123095c635efSGarrett D'Amore */
123195c635efSGarrett D'Amore
123295c635efSGarrett D'Amore if (NULL == mdoc->last->child)
123395c635efSGarrett D'Amore return(1);
123495c635efSGarrett D'Amore
123595c635efSGarrett D'Amore assert(MDOC_TEXT == mdoc->last->child->type);
123695c635efSGarrett D'Amore p = mdoc_a2att(mdoc->last->child->string);
123795c635efSGarrett D'Amore
123895c635efSGarrett D'Amore if (p) {
123995c635efSGarrett D'Amore free(mdoc->last->child->string);
124095c635efSGarrett D'Amore mdoc->last->child->string = mandoc_strdup(p);
124195c635efSGarrett D'Amore } else {
124295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADATT);
124395c635efSGarrett D'Amore p = "AT&T UNIX ";
124495c635efSGarrett D'Amore q = mdoc->last->child->string;
124595c635efSGarrett D'Amore sz = strlen(p) + strlen(q) + 1;
124695c635efSGarrett D'Amore buf = mandoc_malloc(sz);
124795c635efSGarrett D'Amore strlcpy(buf, p, sz);
124895c635efSGarrett D'Amore strlcat(buf, q, sz);
124995c635efSGarrett D'Amore free(mdoc->last->child->string);
125095c635efSGarrett D'Amore mdoc->last->child->string = buf;
125195c635efSGarrett D'Amore }
125295c635efSGarrett D'Amore
125395c635efSGarrett D'Amore return(1);
125495c635efSGarrett D'Amore }
125595c635efSGarrett D'Amore
125695c635efSGarrett D'Amore static int
post_an(POST_ARGS)125795c635efSGarrett D'Amore post_an(POST_ARGS)
125895c635efSGarrett D'Amore {
125995c635efSGarrett D'Amore struct mdoc_node *np;
126095c635efSGarrett D'Amore
126195c635efSGarrett D'Amore np = mdoc->last;
126295c635efSGarrett D'Amore if (AUTH__NONE == np->norm->An.auth) {
126395c635efSGarrett D'Amore if (0 == np->child)
126495c635efSGarrett D'Amore check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_GT, 0);
126595c635efSGarrett D'Amore } else if (np->child)
126695c635efSGarrett D'Amore check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 0);
126795c635efSGarrett D'Amore
126895c635efSGarrett D'Amore return(1);
126995c635efSGarrett D'Amore }
127095c635efSGarrett D'Amore
127195c635efSGarrett D'Amore
127295c635efSGarrett D'Amore static int
post_it(POST_ARGS)127395c635efSGarrett D'Amore post_it(POST_ARGS)
127495c635efSGarrett D'Amore {
127595c635efSGarrett D'Amore int i, cols;
127695c635efSGarrett D'Amore enum mdoc_list lt;
127795c635efSGarrett D'Amore struct mdoc_node *n, *c;
127895c635efSGarrett D'Amore enum mandocerr er;
127995c635efSGarrett D'Amore
128095c635efSGarrett D'Amore if (MDOC_BLOCK != mdoc->last->type)
128195c635efSGarrett D'Amore return(1);
128295c635efSGarrett D'Amore
128395c635efSGarrett D'Amore n = mdoc->last->parent->parent;
128495c635efSGarrett D'Amore lt = n->norm->Bl.type;
128595c635efSGarrett D'Amore
128695c635efSGarrett D'Amore if (LIST__NONE == lt) {
128795c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_LISTTYPE);
128895c635efSGarrett D'Amore return(1);
128995c635efSGarrett D'Amore }
129095c635efSGarrett D'Amore
129195c635efSGarrett D'Amore switch (lt) {
129295c635efSGarrett D'Amore case (LIST_tag):
129395c635efSGarrett D'Amore if (mdoc->last->head->child)
129495c635efSGarrett D'Amore break;
129595c635efSGarrett D'Amore /* FIXME: give this a dummy value. */
129695c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
129795c635efSGarrett D'Amore break;
129895c635efSGarrett D'Amore case (LIST_hang):
129995c635efSGarrett D'Amore /* FALLTHROUGH */
130095c635efSGarrett D'Amore case (LIST_ohang):
130195c635efSGarrett D'Amore /* FALLTHROUGH */
130295c635efSGarrett D'Amore case (LIST_inset):
130395c635efSGarrett D'Amore /* FALLTHROUGH */
130495c635efSGarrett D'Amore case (LIST_diag):
130595c635efSGarrett D'Amore if (NULL == mdoc->last->head->child)
130695c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOARGS);
130795c635efSGarrett D'Amore break;
130895c635efSGarrett D'Amore case (LIST_bullet):
130995c635efSGarrett D'Amore /* FALLTHROUGH */
131095c635efSGarrett D'Amore case (LIST_dash):
131195c635efSGarrett D'Amore /* FALLTHROUGH */
131295c635efSGarrett D'Amore case (LIST_enum):
131395c635efSGarrett D'Amore /* FALLTHROUGH */
131495c635efSGarrett D'Amore case (LIST_hyphen):
131595c635efSGarrett D'Amore if (NULL == mdoc->last->body->child)
131695c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
131795c635efSGarrett D'Amore /* FALLTHROUGH */
131895c635efSGarrett D'Amore case (LIST_item):
131995c635efSGarrett D'Amore if (mdoc->last->head->child)
132095c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_ARGSLOST);
132195c635efSGarrett D'Amore break;
132295c635efSGarrett D'Amore case (LIST_column):
132395c635efSGarrett D'Amore cols = (int)n->norm->Bl.ncols;
132495c635efSGarrett D'Amore
132595c635efSGarrett D'Amore assert(NULL == mdoc->last->head->child);
132695c635efSGarrett D'Amore
132795c635efSGarrett D'Amore if (NULL == mdoc->last->body->child)
132895c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NOBODY);
132995c635efSGarrett D'Amore
133095c635efSGarrett D'Amore for (i = 0, c = mdoc->last->child; c; c = c->next)
133195c635efSGarrett D'Amore if (MDOC_BODY == c->type)
133295c635efSGarrett D'Amore i++;
133395c635efSGarrett D'Amore
133495c635efSGarrett D'Amore if (i < cols)
133595c635efSGarrett D'Amore er = MANDOCERR_ARGCOUNT;
133695c635efSGarrett D'Amore else if (i == cols || i == cols + 1)
133795c635efSGarrett D'Amore break;
133895c635efSGarrett D'Amore else
133995c635efSGarrett D'Amore er = MANDOCERR_SYNTARGCOUNT;
134095c635efSGarrett D'Amore
134195c635efSGarrett D'Amore mandoc_vmsg(er, mdoc->parse, mdoc->last->line,
134295c635efSGarrett D'Amore mdoc->last->pos,
134395c635efSGarrett D'Amore "columns == %d (have %d)", cols, i);
134495c635efSGarrett D'Amore return(MANDOCERR_ARGCOUNT == er);
134595c635efSGarrett D'Amore default:
134695c635efSGarrett D'Amore break;
134795c635efSGarrett D'Amore }
134895c635efSGarrett D'Amore
134995c635efSGarrett D'Amore return(1);
135095c635efSGarrett D'Amore }
135195c635efSGarrett D'Amore
135295c635efSGarrett D'Amore static int
post_bl_block(POST_ARGS)135395c635efSGarrett D'Amore post_bl_block(POST_ARGS)
135495c635efSGarrett D'Amore {
1355*698f87a4SGarrett D'Amore struct mdoc_node *n, *ni, *nc;
135695c635efSGarrett D'Amore
135795c635efSGarrett D'Amore /*
135895c635efSGarrett D'Amore * These are fairly complicated, so we've broken them into two
135995c635efSGarrett D'Amore * functions. post_bl_block_tag() is called when a -tag is
136095c635efSGarrett D'Amore * specified, but no -width (it must be guessed). The second
136195c635efSGarrett D'Amore * when a -width is specified (macro indicators must be
136295c635efSGarrett D'Amore * rewritten into real lengths).
136395c635efSGarrett D'Amore */
136495c635efSGarrett D'Amore
136595c635efSGarrett D'Amore n = mdoc->last;
136695c635efSGarrett D'Amore
136795c635efSGarrett D'Amore if (LIST_tag == n->norm->Bl.type &&
136895c635efSGarrett D'Amore NULL == n->norm->Bl.width) {
136995c635efSGarrett D'Amore if ( ! post_bl_block_tag(mdoc))
137095c635efSGarrett D'Amore return(0);
1371*698f87a4SGarrett D'Amore assert(n->norm->Bl.width);
137295c635efSGarrett D'Amore } else if (NULL != n->norm->Bl.width) {
137395c635efSGarrett D'Amore if ( ! post_bl_block_width(mdoc))
137495c635efSGarrett D'Amore return(0);
137595c635efSGarrett D'Amore assert(n->norm->Bl.width);
1376*698f87a4SGarrett D'Amore }
1377*698f87a4SGarrett D'Amore
1378*698f87a4SGarrett D'Amore for (ni = n->body->child; ni; ni = ni->next) {
1379*698f87a4SGarrett D'Amore if (NULL == ni->body)
1380*698f87a4SGarrett D'Amore continue;
1381*698f87a4SGarrett D'Amore nc = ni->body->last;
1382*698f87a4SGarrett D'Amore while (NULL != nc) {
1383*698f87a4SGarrett D'Amore switch (nc->tok) {
1384*698f87a4SGarrett D'Amore case (MDOC_Pp):
1385*698f87a4SGarrett D'Amore /* FALLTHROUGH */
1386*698f87a4SGarrett D'Amore case (MDOC_Lp):
1387*698f87a4SGarrett D'Amore /* FALLTHROUGH */
1388*698f87a4SGarrett D'Amore case (MDOC_br):
1389*698f87a4SGarrett D'Amore break;
1390*698f87a4SGarrett D'Amore default:
1391*698f87a4SGarrett D'Amore nc = NULL;
1392*698f87a4SGarrett D'Amore continue;
1393*698f87a4SGarrett D'Amore }
1394*698f87a4SGarrett D'Amore if (NULL == ni->next) {
1395*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, nc, MANDOCERR_MOVEPAR);
1396*698f87a4SGarrett D'Amore if ( ! mdoc_node_relink(mdoc, nc))
1397*698f87a4SGarrett D'Amore return(0);
1398*698f87a4SGarrett D'Amore } else if (0 == n->norm->Bl.comp &&
1399*698f87a4SGarrett D'Amore LIST_column != n->norm->Bl.type) {
1400*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, nc, MANDOCERR_IGNPAR);
1401*698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, nc);
1402*698f87a4SGarrett D'Amore } else
1403*698f87a4SGarrett D'Amore break;
1404*698f87a4SGarrett D'Amore nc = ni->body->last;
1405*698f87a4SGarrett D'Amore }
1406*698f87a4SGarrett D'Amore }
140795c635efSGarrett D'Amore return(1);
140895c635efSGarrett D'Amore }
140995c635efSGarrett D'Amore
141095c635efSGarrett D'Amore static int
post_bl_block_width(POST_ARGS)141195c635efSGarrett D'Amore post_bl_block_width(POST_ARGS)
141295c635efSGarrett D'Amore {
141395c635efSGarrett D'Amore size_t width;
141495c635efSGarrett D'Amore int i;
141595c635efSGarrett D'Amore enum mdoct tok;
141695c635efSGarrett D'Amore struct mdoc_node *n;
141795c635efSGarrett D'Amore char buf[NUMSIZ];
141895c635efSGarrett D'Amore
141995c635efSGarrett D'Amore n = mdoc->last;
142095c635efSGarrett D'Amore
142195c635efSGarrett D'Amore /*
142295c635efSGarrett D'Amore * Calculate the real width of a list from the -width string,
142395c635efSGarrett D'Amore * which may contain a macro (with a known default width), a
142495c635efSGarrett D'Amore * literal string, or a scaling width.
142595c635efSGarrett D'Amore *
142695c635efSGarrett D'Amore * If the value to -width is a macro, then we re-write it to be
142795c635efSGarrett D'Amore * the macro's width as set in share/tmac/mdoc/doc-common.
142895c635efSGarrett D'Amore */
142995c635efSGarrett D'Amore
143095c635efSGarrett D'Amore if (0 == strcmp(n->norm->Bl.width, "Ds"))
143195c635efSGarrett D'Amore width = 6;
143295c635efSGarrett D'Amore else if (MDOC_MAX == (tok = mdoc_hash_find(n->norm->Bl.width)))
143395c635efSGarrett D'Amore return(1);
143495c635efSGarrett D'Amore else if (0 == (width = macro2len(tok))) {
143595c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_BADWIDTH);
143695c635efSGarrett D'Amore return(1);
143795c635efSGarrett D'Amore }
143895c635efSGarrett D'Amore
143995c635efSGarrett D'Amore /* The value already exists: free and reallocate it. */
144095c635efSGarrett D'Amore
144195c635efSGarrett D'Amore assert(n->args);
144295c635efSGarrett D'Amore
144395c635efSGarrett D'Amore for (i = 0; i < (int)n->args->argc; i++)
144495c635efSGarrett D'Amore if (MDOC_Width == n->args->argv[i].arg)
144595c635efSGarrett D'Amore break;
144695c635efSGarrett D'Amore
144795c635efSGarrett D'Amore assert(i < (int)n->args->argc);
144895c635efSGarrett D'Amore
144995c635efSGarrett D'Amore snprintf(buf, NUMSIZ, "%un", (unsigned int)width);
145095c635efSGarrett D'Amore free(n->args->argv[i].value[0]);
145195c635efSGarrett D'Amore n->args->argv[i].value[0] = mandoc_strdup(buf);
145295c635efSGarrett D'Amore
145395c635efSGarrett D'Amore /* Set our width! */
145495c635efSGarrett D'Amore n->norm->Bl.width = n->args->argv[i].value[0];
145595c635efSGarrett D'Amore return(1);
145695c635efSGarrett D'Amore }
145795c635efSGarrett D'Amore
145895c635efSGarrett D'Amore static int
post_bl_block_tag(POST_ARGS)145995c635efSGarrett D'Amore post_bl_block_tag(POST_ARGS)
146095c635efSGarrett D'Amore {
146195c635efSGarrett D'Amore struct mdoc_node *n, *nn;
146295c635efSGarrett D'Amore size_t sz, ssz;
146395c635efSGarrett D'Amore int i;
146495c635efSGarrett D'Amore char buf[NUMSIZ];
146595c635efSGarrett D'Amore
146695c635efSGarrett D'Amore /*
146795c635efSGarrett D'Amore * Calculate the -width for a `Bl -tag' list if it hasn't been
146895c635efSGarrett D'Amore * provided. Uses the first head macro. NOTE AGAIN: this is
146995c635efSGarrett D'Amore * ONLY if the -width argument has NOT been provided. See
147095c635efSGarrett D'Amore * post_bl_block_width() for converting the -width string.
147195c635efSGarrett D'Amore */
147295c635efSGarrett D'Amore
147395c635efSGarrett D'Amore sz = 10;
147495c635efSGarrett D'Amore n = mdoc->last;
147595c635efSGarrett D'Amore
147695c635efSGarrett D'Amore for (nn = n->body->child; nn; nn = nn->next) {
147795c635efSGarrett D'Amore if (MDOC_It != nn->tok)
147895c635efSGarrett D'Amore continue;
147995c635efSGarrett D'Amore
148095c635efSGarrett D'Amore assert(MDOC_BLOCK == nn->type);
148195c635efSGarrett D'Amore nn = nn->head->child;
148295c635efSGarrett D'Amore
148395c635efSGarrett D'Amore if (nn == NULL)
148495c635efSGarrett D'Amore break;
148595c635efSGarrett D'Amore
148695c635efSGarrett D'Amore if (MDOC_TEXT == nn->type) {
148795c635efSGarrett D'Amore sz = strlen(nn->string) + 1;
148895c635efSGarrett D'Amore break;
148995c635efSGarrett D'Amore }
149095c635efSGarrett D'Amore
149195c635efSGarrett D'Amore if (0 != (ssz = macro2len(nn->tok)))
149295c635efSGarrett D'Amore sz = ssz;
149395c635efSGarrett D'Amore
149495c635efSGarrett D'Amore break;
149595c635efSGarrett D'Amore }
149695c635efSGarrett D'Amore
149795c635efSGarrett D'Amore /* Defaults to ten ens. */
149895c635efSGarrett D'Amore
149995c635efSGarrett D'Amore snprintf(buf, NUMSIZ, "%un", (unsigned int)sz);
150095c635efSGarrett D'Amore
150195c635efSGarrett D'Amore /*
150295c635efSGarrett D'Amore * We have to dynamically add this to the macro's argument list.
150395c635efSGarrett D'Amore * We're guaranteed that a MDOC_Width doesn't already exist.
150495c635efSGarrett D'Amore */
150595c635efSGarrett D'Amore
150695c635efSGarrett D'Amore assert(n->args);
150795c635efSGarrett D'Amore i = (int)(n->args->argc)++;
150895c635efSGarrett D'Amore
150995c635efSGarrett D'Amore n->args->argv = mandoc_realloc(n->args->argv,
151095c635efSGarrett D'Amore n->args->argc * sizeof(struct mdoc_argv));
151195c635efSGarrett D'Amore
151295c635efSGarrett D'Amore n->args->argv[i].arg = MDOC_Width;
151395c635efSGarrett D'Amore n->args->argv[i].line = n->line;
151495c635efSGarrett D'Amore n->args->argv[i].pos = n->pos;
151595c635efSGarrett D'Amore n->args->argv[i].sz = 1;
151695c635efSGarrett D'Amore n->args->argv[i].value = mandoc_malloc(sizeof(char *));
151795c635efSGarrett D'Amore n->args->argv[i].value[0] = mandoc_strdup(buf);
151895c635efSGarrett D'Amore
151995c635efSGarrett D'Amore /* Set our width! */
152095c635efSGarrett D'Amore n->norm->Bl.width = n->args->argv[i].value[0];
152195c635efSGarrett D'Amore return(1);
152295c635efSGarrett D'Amore }
152395c635efSGarrett D'Amore
152495c635efSGarrett D'Amore
152595c635efSGarrett D'Amore static int
post_bl_head(POST_ARGS)152695c635efSGarrett D'Amore post_bl_head(POST_ARGS)
152795c635efSGarrett D'Amore {
152895c635efSGarrett D'Amore struct mdoc_node *np, *nn, *nnp;
152995c635efSGarrett D'Amore int i, j;
153095c635efSGarrett D'Amore
153195c635efSGarrett D'Amore if (LIST_column != mdoc->last->norm->Bl.type)
153295c635efSGarrett D'Amore /* FIXME: this should be ERROR class... */
153395c635efSGarrett D'Amore return(hwarn_eq0(mdoc));
153495c635efSGarrett D'Amore
153595c635efSGarrett D'Amore /*
153695c635efSGarrett D'Amore * Convert old-style lists, where the column width specifiers
153795c635efSGarrett D'Amore * trail as macro parameters, to the new-style ("normal-form")
153895c635efSGarrett D'Amore * lists where they're argument values following -column.
153995c635efSGarrett D'Amore */
154095c635efSGarrett D'Amore
154195c635efSGarrett D'Amore /* First, disallow both types and allow normal-form. */
154295c635efSGarrett D'Amore
154395c635efSGarrett D'Amore /*
154495c635efSGarrett D'Amore * TODO: technically, we can accept both and just merge the two
154595c635efSGarrett D'Amore * lists, but I'll leave that for another day.
154695c635efSGarrett D'Amore */
154795c635efSGarrett D'Amore
154895c635efSGarrett D'Amore if (mdoc->last->norm->Bl.ncols && mdoc->last->nchild) {
154995c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_COLUMNS);
155095c635efSGarrett D'Amore return(0);
155195c635efSGarrett D'Amore } else if (NULL == mdoc->last->child)
155295c635efSGarrett D'Amore return(1);
155395c635efSGarrett D'Amore
155495c635efSGarrett D'Amore np = mdoc->last->parent;
155595c635efSGarrett D'Amore assert(np->args);
155695c635efSGarrett D'Amore
155795c635efSGarrett D'Amore for (j = 0; j < (int)np->args->argc; j++)
155895c635efSGarrett D'Amore if (MDOC_Column == np->args->argv[j].arg)
155995c635efSGarrett D'Amore break;
156095c635efSGarrett D'Amore
156195c635efSGarrett D'Amore assert(j < (int)np->args->argc);
156295c635efSGarrett D'Amore assert(0 == np->args->argv[j].sz);
156395c635efSGarrett D'Amore
156495c635efSGarrett D'Amore /*
156595c635efSGarrett D'Amore * Accommodate for new-style groff column syntax. Shuffle the
156695c635efSGarrett D'Amore * child nodes, all of which must be TEXT, as arguments for the
156795c635efSGarrett D'Amore * column field. Then, delete the head children.
156895c635efSGarrett D'Amore */
156995c635efSGarrett D'Amore
157095c635efSGarrett D'Amore np->args->argv[j].sz = (size_t)mdoc->last->nchild;
157195c635efSGarrett D'Amore np->args->argv[j].value = mandoc_malloc
157295c635efSGarrett D'Amore ((size_t)mdoc->last->nchild * sizeof(char *));
157395c635efSGarrett D'Amore
157495c635efSGarrett D'Amore mdoc->last->norm->Bl.ncols = np->args->argv[j].sz;
157595c635efSGarrett D'Amore mdoc->last->norm->Bl.cols = (void *)np->args->argv[j].value;
157695c635efSGarrett D'Amore
157795c635efSGarrett D'Amore for (i = 0, nn = mdoc->last->child; nn; i++) {
157895c635efSGarrett D'Amore np->args->argv[j].value[i] = nn->string;
157995c635efSGarrett D'Amore nn->string = NULL;
158095c635efSGarrett D'Amore nnp = nn;
158195c635efSGarrett D'Amore nn = nn->next;
158295c635efSGarrett D'Amore mdoc_node_delete(NULL, nnp);
158395c635efSGarrett D'Amore }
158495c635efSGarrett D'Amore
158595c635efSGarrett D'Amore mdoc->last->nchild = 0;
158695c635efSGarrett D'Amore mdoc->last->child = NULL;
158795c635efSGarrett D'Amore
158895c635efSGarrett D'Amore return(1);
158995c635efSGarrett D'Amore }
159095c635efSGarrett D'Amore
159195c635efSGarrett D'Amore static int
post_bl(POST_ARGS)159295c635efSGarrett D'Amore post_bl(POST_ARGS)
159395c635efSGarrett D'Amore {
1594*698f87a4SGarrett D'Amore struct mdoc_node *nparent, *nprev; /* of the Bl block */
1595*698f87a4SGarrett D'Amore struct mdoc_node *nblock, *nbody; /* of the Bl */
1596*698f87a4SGarrett D'Amore struct mdoc_node *nchild, *nnext; /* of the Bl body */
159795c635efSGarrett D'Amore
1598*698f87a4SGarrett D'Amore nbody = mdoc->last;
1599*698f87a4SGarrett D'Amore switch (nbody->type) {
1600*698f87a4SGarrett D'Amore case (MDOC_BLOCK):
160195c635efSGarrett D'Amore return(post_bl_block(mdoc));
1602*698f87a4SGarrett D'Amore case (MDOC_HEAD):
1603*698f87a4SGarrett D'Amore return(post_bl_head(mdoc));
1604*698f87a4SGarrett D'Amore case (MDOC_BODY):
160595c635efSGarrett D'Amore break;
1606*698f87a4SGarrett D'Amore default:
1607*698f87a4SGarrett D'Amore return(1);
160895c635efSGarrett D'Amore }
160995c635efSGarrett D'Amore
1610*698f87a4SGarrett D'Amore nchild = nbody->child;
1611*698f87a4SGarrett D'Amore while (NULL != nchild) {
1612*698f87a4SGarrett D'Amore if (MDOC_It == nchild->tok || MDOC_Sm == nchild->tok) {
1613*698f87a4SGarrett D'Amore nchild = nchild->next;
1614*698f87a4SGarrett D'Amore continue;
1615*698f87a4SGarrett D'Amore }
1616*698f87a4SGarrett D'Amore
1617*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, nchild, MANDOCERR_CHILD);
1618*698f87a4SGarrett D'Amore
1619*698f87a4SGarrett D'Amore /*
1620*698f87a4SGarrett D'Amore * Move the node out of the Bl block.
1621*698f87a4SGarrett D'Amore * First, collect all required node pointers.
1622*698f87a4SGarrett D'Amore */
1623*698f87a4SGarrett D'Amore
1624*698f87a4SGarrett D'Amore nblock = nbody->parent;
1625*698f87a4SGarrett D'Amore nprev = nblock->prev;
1626*698f87a4SGarrett D'Amore nparent = nblock->parent;
1627*698f87a4SGarrett D'Amore nnext = nchild->next;
1628*698f87a4SGarrett D'Amore
1629*698f87a4SGarrett D'Amore /*
1630*698f87a4SGarrett D'Amore * Unlink this child.
1631*698f87a4SGarrett D'Amore */
1632*698f87a4SGarrett D'Amore
1633*698f87a4SGarrett D'Amore assert(NULL == nchild->prev);
1634*698f87a4SGarrett D'Amore if (0 == --nbody->nchild) {
1635*698f87a4SGarrett D'Amore nbody->child = NULL;
1636*698f87a4SGarrett D'Amore nbody->last = NULL;
1637*698f87a4SGarrett D'Amore assert(NULL == nnext);
1638*698f87a4SGarrett D'Amore } else {
1639*698f87a4SGarrett D'Amore nbody->child = nnext;
1640*698f87a4SGarrett D'Amore nnext->prev = NULL;
1641*698f87a4SGarrett D'Amore }
1642*698f87a4SGarrett D'Amore
1643*698f87a4SGarrett D'Amore /*
1644*698f87a4SGarrett D'Amore * Relink this child.
1645*698f87a4SGarrett D'Amore */
1646*698f87a4SGarrett D'Amore
1647*698f87a4SGarrett D'Amore nchild->parent = nparent;
1648*698f87a4SGarrett D'Amore nchild->prev = nprev;
1649*698f87a4SGarrett D'Amore nchild->next = nblock;
1650*698f87a4SGarrett D'Amore
1651*698f87a4SGarrett D'Amore nblock->prev = nchild;
1652*698f87a4SGarrett D'Amore nparent->nchild++;
1653*698f87a4SGarrett D'Amore if (NULL == nprev)
1654*698f87a4SGarrett D'Amore nparent->child = nchild;
1655*698f87a4SGarrett D'Amore else
1656*698f87a4SGarrett D'Amore nprev->next = nchild;
1657*698f87a4SGarrett D'Amore
1658*698f87a4SGarrett D'Amore nchild = nnext;
165995c635efSGarrett D'Amore }
166095c635efSGarrett D'Amore
166195c635efSGarrett D'Amore return(1);
166295c635efSGarrett D'Amore }
166395c635efSGarrett D'Amore
166495c635efSGarrett D'Amore static int
ebool(struct mdoc * mdoc)166595c635efSGarrett D'Amore ebool(struct mdoc *mdoc)
166695c635efSGarrett D'Amore {
166795c635efSGarrett D'Amore
166895c635efSGarrett D'Amore if (NULL == mdoc->last->child) {
166995c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
167095c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last);
167195c635efSGarrett D'Amore return(1);
167295c635efSGarrett D'Amore }
167395c635efSGarrett D'Amore check_count(mdoc, MDOC_ELEM, CHECK_WARN, CHECK_EQ, 1);
167495c635efSGarrett D'Amore
167595c635efSGarrett D'Amore assert(MDOC_TEXT == mdoc->last->child->type);
167695c635efSGarrett D'Amore
1677*698f87a4SGarrett D'Amore if (0 == strcmp(mdoc->last->child->string, "on")) {
1678*698f87a4SGarrett D'Amore if (MDOC_Sm == mdoc->last->tok)
1679*698f87a4SGarrett D'Amore mdoc->flags &= ~MDOC_SMOFF;
168095c635efSGarrett D'Amore return(1);
1681*698f87a4SGarrett D'Amore }
1682*698f87a4SGarrett D'Amore if (0 == strcmp(mdoc->last->child->string, "off")) {
1683*698f87a4SGarrett D'Amore if (MDOC_Sm == mdoc->last->tok)
1684*698f87a4SGarrett D'Amore mdoc->flags |= MDOC_SMOFF;
168595c635efSGarrett D'Amore return(1);
1686*698f87a4SGarrett D'Amore }
168795c635efSGarrett D'Amore
168895c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADBOOL);
168995c635efSGarrett D'Amore return(1);
169095c635efSGarrett D'Amore }
169195c635efSGarrett D'Amore
169295c635efSGarrett D'Amore static int
post_root(POST_ARGS)169395c635efSGarrett D'Amore post_root(POST_ARGS)
169495c635efSGarrett D'Amore {
169595c635efSGarrett D'Amore int erc;
169695c635efSGarrett D'Amore struct mdoc_node *n;
169795c635efSGarrett D'Amore
169895c635efSGarrett D'Amore erc = 0;
169995c635efSGarrett D'Amore
170095c635efSGarrett D'Amore /* Check that we have a finished prologue. */
170195c635efSGarrett D'Amore
170295c635efSGarrett D'Amore if ( ! (MDOC_PBODY & mdoc->flags)) {
170395c635efSGarrett D'Amore erc++;
170495c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->first, MANDOCERR_NODOCPROLOG);
170595c635efSGarrett D'Amore }
170695c635efSGarrett D'Amore
170795c635efSGarrett D'Amore n = mdoc->first;
170895c635efSGarrett D'Amore assert(n);
170995c635efSGarrett D'Amore
171095c635efSGarrett D'Amore /* Check that we begin with a proper `Sh'. */
171195c635efSGarrett D'Amore
171295c635efSGarrett D'Amore if (NULL == n->child) {
171395c635efSGarrett D'Amore erc++;
171495c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
171595c635efSGarrett D'Amore } else if (MDOC_BLOCK != n->child->type ||
171695c635efSGarrett D'Amore MDOC_Sh != n->child->tok) {
171795c635efSGarrett D'Amore erc++;
171895c635efSGarrett D'Amore /* Can this be lifted? See rxdebug.1 for example. */
171995c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_NODOCBODY);
172095c635efSGarrett D'Amore }
172195c635efSGarrett D'Amore
172295c635efSGarrett D'Amore return(erc ? 0 : 1);
172395c635efSGarrett D'Amore }
172495c635efSGarrett D'Amore
172595c635efSGarrett D'Amore static int
post_st(POST_ARGS)172695c635efSGarrett D'Amore post_st(POST_ARGS)
172795c635efSGarrett D'Amore {
172895c635efSGarrett D'Amore struct mdoc_node *ch;
172995c635efSGarrett D'Amore const char *p;
173095c635efSGarrett D'Amore
173195c635efSGarrett D'Amore if (NULL == (ch = mdoc->last->child)) {
173295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_MACROEMPTY);
173395c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last);
173495c635efSGarrett D'Amore return(1);
173595c635efSGarrett D'Amore }
173695c635efSGarrett D'Amore
173795c635efSGarrett D'Amore assert(MDOC_TEXT == ch->type);
173895c635efSGarrett D'Amore
173995c635efSGarrett D'Amore if (NULL == (p = mdoc_a2st(ch->string))) {
174095c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADSTANDARD);
174195c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last);
174295c635efSGarrett D'Amore } else {
174395c635efSGarrett D'Amore free(ch->string);
174495c635efSGarrett D'Amore ch->string = mandoc_strdup(p);
174595c635efSGarrett D'Amore }
174695c635efSGarrett D'Amore
174795c635efSGarrett D'Amore return(1);
174895c635efSGarrett D'Amore }
174995c635efSGarrett D'Amore
175095c635efSGarrett D'Amore static int
post_rs(POST_ARGS)175195c635efSGarrett D'Amore post_rs(POST_ARGS)
175295c635efSGarrett D'Amore {
175395c635efSGarrett D'Amore struct mdoc_node *nn, *next, *prev;
175495c635efSGarrett D'Amore int i, j;
175595c635efSGarrett D'Amore
175695c635efSGarrett D'Amore switch (mdoc->last->type) {
175795c635efSGarrett D'Amore case (MDOC_HEAD):
175895c635efSGarrett D'Amore check_count(mdoc, MDOC_HEAD, CHECK_WARN, CHECK_EQ, 0);
175995c635efSGarrett D'Amore return(1);
176095c635efSGarrett D'Amore case (MDOC_BODY):
176195c635efSGarrett D'Amore if (mdoc->last->child)
176295c635efSGarrett D'Amore break;
176395c635efSGarrett D'Amore check_count(mdoc, MDOC_BODY, CHECK_WARN, CHECK_GT, 0);
176495c635efSGarrett D'Amore return(1);
176595c635efSGarrett D'Amore default:
176695c635efSGarrett D'Amore return(1);
176795c635efSGarrett D'Amore }
176895c635efSGarrett D'Amore
176995c635efSGarrett D'Amore /*
177095c635efSGarrett D'Amore * Make sure only certain types of nodes are allowed within the
177195c635efSGarrett D'Amore * the `Rs' body. Delete offending nodes and raise a warning.
177295c635efSGarrett D'Amore * Do this before re-ordering for the sake of clarity.
177395c635efSGarrett D'Amore */
177495c635efSGarrett D'Amore
177595c635efSGarrett D'Amore next = NULL;
177695c635efSGarrett D'Amore for (nn = mdoc->last->child; nn; nn = next) {
177795c635efSGarrett D'Amore for (i = 0; i < RSORD_MAX; i++)
177895c635efSGarrett D'Amore if (nn->tok == rsord[i])
177995c635efSGarrett D'Amore break;
178095c635efSGarrett D'Amore
178195c635efSGarrett D'Amore if (i < RSORD_MAX) {
178295c635efSGarrett D'Amore if (MDOC__J == rsord[i] || MDOC__B == rsord[i])
178395c635efSGarrett D'Amore mdoc->last->norm->Rs.quote_T++;
178495c635efSGarrett D'Amore next = nn->next;
178595c635efSGarrett D'Amore continue;
178695c635efSGarrett D'Amore }
178795c635efSGarrett D'Amore
178895c635efSGarrett D'Amore next = nn->next;
178995c635efSGarrett D'Amore mdoc_nmsg(mdoc, nn, MANDOCERR_CHILD);
179095c635efSGarrett D'Amore mdoc_node_delete(mdoc, nn);
179195c635efSGarrett D'Amore }
179295c635efSGarrett D'Amore
179395c635efSGarrett D'Amore /*
179495c635efSGarrett D'Amore * Nothing to sort if only invalid nodes were found
179595c635efSGarrett D'Amore * inside the `Rs' body.
179695c635efSGarrett D'Amore */
179795c635efSGarrett D'Amore
179895c635efSGarrett D'Amore if (NULL == mdoc->last->child)
179995c635efSGarrett D'Amore return(1);
180095c635efSGarrett D'Amore
180195c635efSGarrett D'Amore /*
180295c635efSGarrett D'Amore * The full `Rs' block needs special handling to order the
180395c635efSGarrett D'Amore * sub-elements according to `rsord'. Pick through each element
180495c635efSGarrett D'Amore * and correctly order it. This is a insertion sort.
180595c635efSGarrett D'Amore */
180695c635efSGarrett D'Amore
180795c635efSGarrett D'Amore next = NULL;
180895c635efSGarrett D'Amore for (nn = mdoc->last->child->next; nn; nn = next) {
180995c635efSGarrett D'Amore /* Determine order of `nn'. */
181095c635efSGarrett D'Amore for (i = 0; i < RSORD_MAX; i++)
181195c635efSGarrett D'Amore if (rsord[i] == nn->tok)
181295c635efSGarrett D'Amore break;
181395c635efSGarrett D'Amore
181495c635efSGarrett D'Amore /*
181595c635efSGarrett D'Amore * Remove `nn' from the chain. This somewhat
181695c635efSGarrett D'Amore * repeats mdoc_node_unlink(), but since we're
181795c635efSGarrett D'Amore * just re-ordering, there's no need for the
181895c635efSGarrett D'Amore * full unlink process.
181995c635efSGarrett D'Amore */
182095c635efSGarrett D'Amore
182195c635efSGarrett D'Amore if (NULL != (next = nn->next))
182295c635efSGarrett D'Amore next->prev = nn->prev;
182395c635efSGarrett D'Amore
182495c635efSGarrett D'Amore if (NULL != (prev = nn->prev))
182595c635efSGarrett D'Amore prev->next = nn->next;
182695c635efSGarrett D'Amore
182795c635efSGarrett D'Amore nn->prev = nn->next = NULL;
182895c635efSGarrett D'Amore
182995c635efSGarrett D'Amore /*
183095c635efSGarrett D'Amore * Scan back until we reach a node that's
183195c635efSGarrett D'Amore * ordered before `nn'.
183295c635efSGarrett D'Amore */
183395c635efSGarrett D'Amore
183495c635efSGarrett D'Amore for ( ; prev ; prev = prev->prev) {
183595c635efSGarrett D'Amore /* Determine order of `prev'. */
183695c635efSGarrett D'Amore for (j = 0; j < RSORD_MAX; j++)
183795c635efSGarrett D'Amore if (rsord[j] == prev->tok)
183895c635efSGarrett D'Amore break;
183995c635efSGarrett D'Amore
184095c635efSGarrett D'Amore if (j <= i)
184195c635efSGarrett D'Amore break;
184295c635efSGarrett D'Amore }
184395c635efSGarrett D'Amore
184495c635efSGarrett D'Amore /*
184595c635efSGarrett D'Amore * Set `nn' back into its correct place in front
184695c635efSGarrett D'Amore * of the `prev' node.
184795c635efSGarrett D'Amore */
184895c635efSGarrett D'Amore
184995c635efSGarrett D'Amore nn->prev = prev;
185095c635efSGarrett D'Amore
185195c635efSGarrett D'Amore if (prev) {
185295c635efSGarrett D'Amore if (prev->next)
185395c635efSGarrett D'Amore prev->next->prev = nn;
185495c635efSGarrett D'Amore nn->next = prev->next;
185595c635efSGarrett D'Amore prev->next = nn;
185695c635efSGarrett D'Amore } else {
185795c635efSGarrett D'Amore mdoc->last->child->prev = nn;
185895c635efSGarrett D'Amore nn->next = mdoc->last->child;
185995c635efSGarrett D'Amore mdoc->last->child = nn;
186095c635efSGarrett D'Amore }
186195c635efSGarrett D'Amore }
186295c635efSGarrett D'Amore
186395c635efSGarrett D'Amore return(1);
186495c635efSGarrett D'Amore }
186595c635efSGarrett D'Amore
1866*698f87a4SGarrett D'Amore /*
1867*698f87a4SGarrett D'Amore * For some arguments of some macros,
1868*698f87a4SGarrett D'Amore * convert all breakable hyphens into ASCII_HYPH.
1869*698f87a4SGarrett D'Amore */
1870*698f87a4SGarrett D'Amore static int
post_hyph(POST_ARGS)1871*698f87a4SGarrett D'Amore post_hyph(POST_ARGS)
1872*698f87a4SGarrett D'Amore {
1873*698f87a4SGarrett D'Amore struct mdoc_node *n, *nch;
1874*698f87a4SGarrett D'Amore char *cp;
1875*698f87a4SGarrett D'Amore
1876*698f87a4SGarrett D'Amore n = mdoc->last;
1877*698f87a4SGarrett D'Amore switch (n->type) {
1878*698f87a4SGarrett D'Amore case (MDOC_HEAD):
1879*698f87a4SGarrett D'Amore if (MDOC_Sh == n->tok || MDOC_Ss == n->tok)
1880*698f87a4SGarrett D'Amore break;
1881*698f87a4SGarrett D'Amore return(1);
1882*698f87a4SGarrett D'Amore case (MDOC_BODY):
1883*698f87a4SGarrett D'Amore if (MDOC_D1 == n->tok || MDOC_Nd == n->tok)
1884*698f87a4SGarrett D'Amore break;
1885*698f87a4SGarrett D'Amore return(1);
1886*698f87a4SGarrett D'Amore case (MDOC_ELEM):
1887*698f87a4SGarrett D'Amore break;
1888*698f87a4SGarrett D'Amore default:
1889*698f87a4SGarrett D'Amore return(1);
1890*698f87a4SGarrett D'Amore }
1891*698f87a4SGarrett D'Amore
1892*698f87a4SGarrett D'Amore for (nch = n->child; nch; nch = nch->next) {
1893*698f87a4SGarrett D'Amore if (MDOC_TEXT != nch->type)
1894*698f87a4SGarrett D'Amore continue;
1895*698f87a4SGarrett D'Amore cp = nch->string;
1896*698f87a4SGarrett D'Amore if (3 > strnlen(cp, 3))
1897*698f87a4SGarrett D'Amore continue;
1898*698f87a4SGarrett D'Amore while ('\0' != *(++cp))
1899*698f87a4SGarrett D'Amore if ('-' == *cp &&
1900*698f87a4SGarrett D'Amore isalpha((unsigned char)cp[-1]) &&
1901*698f87a4SGarrett D'Amore isalpha((unsigned char)cp[1]))
1902*698f87a4SGarrett D'Amore *cp = ASCII_HYPH;
1903*698f87a4SGarrett D'Amore }
1904*698f87a4SGarrett D'Amore return(1);
1905*698f87a4SGarrett D'Amore }
1906*698f87a4SGarrett D'Amore
190795c635efSGarrett D'Amore static int
post_ns(POST_ARGS)190895c635efSGarrett D'Amore post_ns(POST_ARGS)
190995c635efSGarrett D'Amore {
191095c635efSGarrett D'Amore
191195c635efSGarrett D'Amore if (MDOC_LINE & mdoc->last->flags)
191295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNNS);
191395c635efSGarrett D'Amore return(1);
191495c635efSGarrett D'Amore }
191595c635efSGarrett D'Amore
191695c635efSGarrett D'Amore static int
post_sh(POST_ARGS)191795c635efSGarrett D'Amore post_sh(POST_ARGS)
191895c635efSGarrett D'Amore {
191995c635efSGarrett D'Amore
192095c635efSGarrett D'Amore if (MDOC_HEAD == mdoc->last->type)
192195c635efSGarrett D'Amore return(post_sh_head(mdoc));
192295c635efSGarrett D'Amore if (MDOC_BODY == mdoc->last->type)
192395c635efSGarrett D'Amore return(post_sh_body(mdoc));
192495c635efSGarrett D'Amore
192595c635efSGarrett D'Amore return(1);
192695c635efSGarrett D'Amore }
192795c635efSGarrett D'Amore
192895c635efSGarrett D'Amore static int
post_sh_body(POST_ARGS)192995c635efSGarrett D'Amore post_sh_body(POST_ARGS)
193095c635efSGarrett D'Amore {
193195c635efSGarrett D'Amore struct mdoc_node *n;
193295c635efSGarrett D'Amore
193395c635efSGarrett D'Amore if (SEC_NAME != mdoc->lastsec)
193495c635efSGarrett D'Amore return(1);
193595c635efSGarrett D'Amore
193695c635efSGarrett D'Amore /*
193795c635efSGarrett D'Amore * Warn if the NAME section doesn't contain the `Nm' and `Nd'
193895c635efSGarrett D'Amore * macros (can have multiple `Nm' and one `Nd'). Note that the
193995c635efSGarrett D'Amore * children of the BODY declaration can also be "text".
194095c635efSGarrett D'Amore */
194195c635efSGarrett D'Amore
194295c635efSGarrett D'Amore if (NULL == (n = mdoc->last->child)) {
194395c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
194495c635efSGarrett D'Amore return(1);
194595c635efSGarrett D'Amore }
194695c635efSGarrett D'Amore
194795c635efSGarrett D'Amore for ( ; n && n->next; n = n->next) {
194895c635efSGarrett D'Amore if (MDOC_ELEM == n->type && MDOC_Nm == n->tok)
194995c635efSGarrett D'Amore continue;
195095c635efSGarrett D'Amore if (MDOC_TEXT == n->type)
195195c635efSGarrett D'Amore continue;
195295c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
195395c635efSGarrett D'Amore }
195495c635efSGarrett D'Amore
195595c635efSGarrett D'Amore assert(n);
195695c635efSGarrett D'Amore if (MDOC_BLOCK == n->type && MDOC_Nd == n->tok)
195795c635efSGarrett D'Amore return(1);
195895c635efSGarrett D'Amore
195995c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_BADNAMESEC);
196095c635efSGarrett D'Amore return(1);
196195c635efSGarrett D'Amore }
196295c635efSGarrett D'Amore
196395c635efSGarrett D'Amore static int
post_sh_head(POST_ARGS)196495c635efSGarrett D'Amore post_sh_head(POST_ARGS)
196595c635efSGarrett D'Amore {
196695c635efSGarrett D'Amore char buf[BUFSIZ];
196795c635efSGarrett D'Amore struct mdoc_node *n;
196895c635efSGarrett D'Amore enum mdoc_sec sec;
196995c635efSGarrett D'Amore int c;
197095c635efSGarrett D'Amore
197195c635efSGarrett D'Amore /*
197295c635efSGarrett D'Amore * Process a new section. Sections are either "named" or
197395c635efSGarrett D'Amore * "custom". Custom sections are user-defined, while named ones
197495c635efSGarrett D'Amore * follow a conventional order and may only appear in certain
197595c635efSGarrett D'Amore * manual sections.
197695c635efSGarrett D'Amore */
197795c635efSGarrett D'Amore
197895c635efSGarrett D'Amore sec = SEC_CUSTOM;
197995c635efSGarrett D'Amore buf[0] = '\0';
198095c635efSGarrett D'Amore if (-1 == (c = concat(buf, mdoc->last->child, BUFSIZ))) {
198195c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last->child, MANDOCERR_MEM);
198295c635efSGarrett D'Amore return(0);
198395c635efSGarrett D'Amore } else if (1 == c)
198495c635efSGarrett D'Amore sec = a2sec(buf);
198595c635efSGarrett D'Amore
198695c635efSGarrett D'Amore /* The NAME should be first. */
198795c635efSGarrett D'Amore
198895c635efSGarrett D'Amore if (SEC_NAME != sec && SEC_NONE == mdoc->lastnamed)
198995c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_NAMESECFIRST);
199095c635efSGarrett D'Amore
199195c635efSGarrett D'Amore /* The SYNOPSIS gets special attention in other areas. */
199295c635efSGarrett D'Amore
1993*698f87a4SGarrett D'Amore if (SEC_SYNOPSIS == sec) {
1994*698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 1, '=');
199595c635efSGarrett D'Amore mdoc->flags |= MDOC_SYNOPSIS;
1996*698f87a4SGarrett D'Amore } else {
1997*698f87a4SGarrett D'Amore roff_setreg(mdoc->roff, "nS", 0, '=');
199895c635efSGarrett D'Amore mdoc->flags &= ~MDOC_SYNOPSIS;
1999*698f87a4SGarrett D'Amore }
200095c635efSGarrett D'Amore
200195c635efSGarrett D'Amore /* Mark our last section. */
200295c635efSGarrett D'Amore
200395c635efSGarrett D'Amore mdoc->lastsec = sec;
200495c635efSGarrett D'Amore
200595c635efSGarrett D'Amore /*
200695c635efSGarrett D'Amore * Set the section attribute for the current HEAD, for its
200795c635efSGarrett D'Amore * parent BLOCK, and for the HEAD children; the latter can
200895c635efSGarrett D'Amore * only be TEXT nodes, so no recursion is needed.
200995c635efSGarrett D'Amore * For other blocks and elements, including .Sh BODY, this is
201095c635efSGarrett D'Amore * done when allocating the node data structures, but for .Sh
201195c635efSGarrett D'Amore * BLOCK and HEAD, the section is still unknown at that time.
201295c635efSGarrett D'Amore */
201395c635efSGarrett D'Amore
201495c635efSGarrett D'Amore mdoc->last->parent->sec = sec;
201595c635efSGarrett D'Amore mdoc->last->sec = sec;
201695c635efSGarrett D'Amore for (n = mdoc->last->child; n; n = n->next)
201795c635efSGarrett D'Amore n->sec = sec;
201895c635efSGarrett D'Amore
201995c635efSGarrett D'Amore /* We don't care about custom sections after this. */
202095c635efSGarrett D'Amore
202195c635efSGarrett D'Amore if (SEC_CUSTOM == sec)
202295c635efSGarrett D'Amore return(1);
202395c635efSGarrett D'Amore
202495c635efSGarrett D'Amore /*
202595c635efSGarrett D'Amore * Check whether our non-custom section is being repeated or is
202695c635efSGarrett D'Amore * out of order.
202795c635efSGarrett D'Amore */
202895c635efSGarrett D'Amore
202995c635efSGarrett D'Amore if (sec == mdoc->lastnamed)
203095c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECREP);
203195c635efSGarrett D'Amore
203295c635efSGarrett D'Amore if (sec < mdoc->lastnamed)
203395c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_SECOOO);
203495c635efSGarrett D'Amore
203595c635efSGarrett D'Amore /* Mark the last named section. */
203695c635efSGarrett D'Amore
203795c635efSGarrett D'Amore mdoc->lastnamed = sec;
203895c635efSGarrett D'Amore
203995c635efSGarrett D'Amore /* Check particular section/manual conventions. */
204095c635efSGarrett D'Amore
204195c635efSGarrett D'Amore assert(mdoc->meta.msec);
204295c635efSGarrett D'Amore
204395c635efSGarrett D'Amore switch (sec) {
204495c635efSGarrett D'Amore case (SEC_RETURN_VALUES):
204595c635efSGarrett D'Amore /* FALLTHROUGH */
204695c635efSGarrett D'Amore case (SEC_ERRORS):
204795c635efSGarrett D'Amore /* FALLTHROUGH */
204895c635efSGarrett D'Amore case (SEC_LIBRARY):
204995c635efSGarrett D'Amore if (*mdoc->meta.msec == '2')
205095c635efSGarrett D'Amore break;
205195c635efSGarrett D'Amore if (*mdoc->meta.msec == '3')
205295c635efSGarrett D'Amore break;
205395c635efSGarrett D'Amore if (*mdoc->meta.msec == '9')
205495c635efSGarrett D'Amore break;
2055*698f87a4SGarrett D'Amore mandoc_msg(MANDOCERR_SECMSEC, mdoc->parse,
2056*698f87a4SGarrett D'Amore mdoc->last->line, mdoc->last->pos, buf);
205795c635efSGarrett D'Amore break;
205895c635efSGarrett D'Amore default:
205995c635efSGarrett D'Amore break;
206095c635efSGarrett D'Amore }
206195c635efSGarrett D'Amore
206295c635efSGarrett D'Amore return(1);
206395c635efSGarrett D'Amore }
206495c635efSGarrett D'Amore
206595c635efSGarrett D'Amore static int
post_ignpar(POST_ARGS)206695c635efSGarrett D'Amore post_ignpar(POST_ARGS)
206795c635efSGarrett D'Amore {
206895c635efSGarrett D'Amore struct mdoc_node *np;
206995c635efSGarrett D'Amore
207095c635efSGarrett D'Amore if (MDOC_BODY != mdoc->last->type)
207195c635efSGarrett D'Amore return(1);
207295c635efSGarrett D'Amore
207395c635efSGarrett D'Amore if (NULL != (np = mdoc->last->child))
207495c635efSGarrett D'Amore if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
207595c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
207695c635efSGarrett D'Amore mdoc_node_delete(mdoc, np);
207795c635efSGarrett D'Amore }
207895c635efSGarrett D'Amore
207995c635efSGarrett D'Amore if (NULL != (np = mdoc->last->last))
208095c635efSGarrett D'Amore if (MDOC_Pp == np->tok || MDOC_Lp == np->tok) {
208195c635efSGarrett D'Amore mdoc_nmsg(mdoc, np, MANDOCERR_IGNPAR);
208295c635efSGarrett D'Amore mdoc_node_delete(mdoc, np);
208395c635efSGarrett D'Amore }
208495c635efSGarrett D'Amore
208595c635efSGarrett D'Amore return(1);
208695c635efSGarrett D'Amore }
208795c635efSGarrett D'Amore
208895c635efSGarrett D'Amore static int
pre_par(PRE_ARGS)208995c635efSGarrett D'Amore pre_par(PRE_ARGS)
209095c635efSGarrett D'Amore {
209195c635efSGarrett D'Amore
209295c635efSGarrett D'Amore if (NULL == mdoc->last)
209395c635efSGarrett D'Amore return(1);
209495c635efSGarrett D'Amore if (MDOC_ELEM != n->type && MDOC_BLOCK != n->type)
209595c635efSGarrett D'Amore return(1);
209695c635efSGarrett D'Amore
209795c635efSGarrett D'Amore /*
209895c635efSGarrett D'Amore * Don't allow prior `Lp' or `Pp' prior to a paragraph-type
209995c635efSGarrett D'Amore * block: `Lp', `Pp', or non-compact `Bd' or `Bl'.
210095c635efSGarrett D'Amore */
210195c635efSGarrett D'Amore
2102*698f87a4SGarrett D'Amore if (MDOC_Pp != mdoc->last->tok &&
2103*698f87a4SGarrett D'Amore MDOC_Lp != mdoc->last->tok &&
2104*698f87a4SGarrett D'Amore MDOC_br != mdoc->last->tok)
210595c635efSGarrett D'Amore return(1);
210695c635efSGarrett D'Amore if (MDOC_Bl == n->tok && n->norm->Bl.comp)
210795c635efSGarrett D'Amore return(1);
210895c635efSGarrett D'Amore if (MDOC_Bd == n->tok && n->norm->Bd.comp)
210995c635efSGarrett D'Amore return(1);
211095c635efSGarrett D'Amore if (MDOC_It == n->tok && n->parent->norm->Bl.comp)
211195c635efSGarrett D'Amore return(1);
211295c635efSGarrett D'Amore
211395c635efSGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
211495c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last);
211595c635efSGarrett D'Amore return(1);
211695c635efSGarrett D'Amore }
211795c635efSGarrett D'Amore
211895c635efSGarrett D'Amore static int
post_par(POST_ARGS)2119*698f87a4SGarrett D'Amore post_par(POST_ARGS)
2120*698f87a4SGarrett D'Amore {
2121*698f87a4SGarrett D'Amore
2122*698f87a4SGarrett D'Amore if (MDOC_ELEM != mdoc->last->type &&
2123*698f87a4SGarrett D'Amore MDOC_BLOCK != mdoc->last->type)
2124*698f87a4SGarrett D'Amore return(1);
2125*698f87a4SGarrett D'Amore
2126*698f87a4SGarrett D'Amore if (NULL == mdoc->last->prev) {
2127*698f87a4SGarrett D'Amore if (MDOC_Sh != mdoc->last->parent->tok &&
2128*698f87a4SGarrett D'Amore MDOC_Ss != mdoc->last->parent->tok)
2129*698f87a4SGarrett D'Amore return(1);
2130*698f87a4SGarrett D'Amore } else {
2131*698f87a4SGarrett D'Amore if (MDOC_Pp != mdoc->last->prev->tok &&
2132*698f87a4SGarrett D'Amore MDOC_Lp != mdoc->last->prev->tok &&
2133*698f87a4SGarrett D'Amore (MDOC_br != mdoc->last->tok ||
2134*698f87a4SGarrett D'Amore (MDOC_sp != mdoc->last->prev->tok &&
2135*698f87a4SGarrett D'Amore MDOC_br != mdoc->last->prev->tok)))
2136*698f87a4SGarrett D'Amore return(1);
2137*698f87a4SGarrett D'Amore }
2138*698f87a4SGarrett D'Amore
2139*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, mdoc->last, MANDOCERR_IGNPAR);
2140*698f87a4SGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last);
2141*698f87a4SGarrett D'Amore return(1);
2142*698f87a4SGarrett D'Amore }
2143*698f87a4SGarrett D'Amore
2144*698f87a4SGarrett D'Amore static int
pre_literal(PRE_ARGS)214595c635efSGarrett D'Amore pre_literal(PRE_ARGS)
214695c635efSGarrett D'Amore {
214795c635efSGarrett D'Amore
214895c635efSGarrett D'Amore if (MDOC_BODY != n->type)
214995c635efSGarrett D'Amore return(1);
215095c635efSGarrett D'Amore
215195c635efSGarrett D'Amore /*
215295c635efSGarrett D'Amore * The `Dl' (note "el" not "one") and `Bd -literal' and `Bd
215395c635efSGarrett D'Amore * -unfilled' macros set MDOC_LITERAL on entrance to the body.
215495c635efSGarrett D'Amore */
215595c635efSGarrett D'Amore
215695c635efSGarrett D'Amore switch (n->tok) {
215795c635efSGarrett D'Amore case (MDOC_Dl):
215895c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL;
215995c635efSGarrett D'Amore break;
216095c635efSGarrett D'Amore case (MDOC_Bd):
216195c635efSGarrett D'Amore if (DISP_literal == n->norm->Bd.type)
216295c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL;
216395c635efSGarrett D'Amore if (DISP_unfilled == n->norm->Bd.type)
216495c635efSGarrett D'Amore mdoc->flags |= MDOC_LITERAL;
216595c635efSGarrett D'Amore break;
216695c635efSGarrett D'Amore default:
216795c635efSGarrett D'Amore abort();
216895c635efSGarrett D'Amore /* NOTREACHED */
216995c635efSGarrett D'Amore }
217095c635efSGarrett D'Amore
217195c635efSGarrett D'Amore return(1);
217295c635efSGarrett D'Amore }
217395c635efSGarrett D'Amore
217495c635efSGarrett D'Amore static int
post_dd(POST_ARGS)217595c635efSGarrett D'Amore post_dd(POST_ARGS)
217695c635efSGarrett D'Amore {
217795c635efSGarrett D'Amore char buf[DATESIZE];
217895c635efSGarrett D'Amore struct mdoc_node *n;
217995c635efSGarrett D'Amore int c;
218095c635efSGarrett D'Amore
218195c635efSGarrett D'Amore if (mdoc->meta.date)
218295c635efSGarrett D'Amore free(mdoc->meta.date);
218395c635efSGarrett D'Amore
218495c635efSGarrett D'Amore n = mdoc->last;
218595c635efSGarrett D'Amore if (NULL == n->child || '\0' == n->child->string[0]) {
218695c635efSGarrett D'Amore mdoc->meta.date = mandoc_normdate
218795c635efSGarrett D'Amore (mdoc->parse, NULL, n->line, n->pos);
218895c635efSGarrett D'Amore return(1);
218995c635efSGarrett D'Amore }
219095c635efSGarrett D'Amore
219195c635efSGarrett D'Amore buf[0] = '\0';
219295c635efSGarrett D'Amore if (-1 == (c = concat(buf, n->child, DATESIZE))) {
219395c635efSGarrett D'Amore mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
219495c635efSGarrett D'Amore return(0);
219595c635efSGarrett D'Amore }
219695c635efSGarrett D'Amore
219795c635efSGarrett D'Amore assert(c);
219895c635efSGarrett D'Amore mdoc->meta.date = mandoc_normdate
219995c635efSGarrett D'Amore (mdoc->parse, buf, n->line, n->pos);
220095c635efSGarrett D'Amore
220195c635efSGarrett D'Amore return(1);
220295c635efSGarrett D'Amore }
220395c635efSGarrett D'Amore
220495c635efSGarrett D'Amore static int
post_dt(POST_ARGS)220595c635efSGarrett D'Amore post_dt(POST_ARGS)
220695c635efSGarrett D'Amore {
220795c635efSGarrett D'Amore struct mdoc_node *nn, *n;
220895c635efSGarrett D'Amore const char *cp;
220995c635efSGarrett D'Amore char *p;
221095c635efSGarrett D'Amore
221195c635efSGarrett D'Amore n = mdoc->last;
221295c635efSGarrett D'Amore
221395c635efSGarrett D'Amore if (mdoc->meta.title)
221495c635efSGarrett D'Amore free(mdoc->meta.title);
221595c635efSGarrett D'Amore if (mdoc->meta.vol)
221695c635efSGarrett D'Amore free(mdoc->meta.vol);
221795c635efSGarrett D'Amore if (mdoc->meta.arch)
221895c635efSGarrett D'Amore free(mdoc->meta.arch);
221995c635efSGarrett D'Amore
222095c635efSGarrett D'Amore mdoc->meta.title = mdoc->meta.vol = mdoc->meta.arch = NULL;
222195c635efSGarrett D'Amore
222295c635efSGarrett D'Amore /* First make all characters uppercase. */
222395c635efSGarrett D'Amore
222495c635efSGarrett D'Amore if (NULL != (nn = n->child))
222595c635efSGarrett D'Amore for (p = nn->string; *p; p++) {
222695c635efSGarrett D'Amore if (toupper((unsigned char)*p) == *p)
222795c635efSGarrett D'Amore continue;
222895c635efSGarrett D'Amore
222995c635efSGarrett D'Amore /*
223095c635efSGarrett D'Amore * FIXME: don't be lazy: have this make all
223195c635efSGarrett D'Amore * characters be uppercase and just warn once.
223295c635efSGarrett D'Amore */
223395c635efSGarrett D'Amore mdoc_nmsg(mdoc, nn, MANDOCERR_UPPERCASE);
223495c635efSGarrett D'Amore break;
223595c635efSGarrett D'Amore }
223695c635efSGarrett D'Amore
223795c635efSGarrett D'Amore /* Handles: `.Dt'
223895c635efSGarrett D'Amore * --> title = unknown, volume = local, msec = 0, arch = NULL
223995c635efSGarrett D'Amore */
224095c635efSGarrett D'Amore
224195c635efSGarrett D'Amore if (NULL == (nn = n->child)) {
224295c635efSGarrett D'Amore /* XXX: make these macro values. */
224395c635efSGarrett D'Amore /* FIXME: warn about missing values. */
224495c635efSGarrett D'Amore mdoc->meta.title = mandoc_strdup("UNKNOWN");
224595c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL");
224695c635efSGarrett D'Amore mdoc->meta.msec = mandoc_strdup("1");
224795c635efSGarrett D'Amore return(1);
224895c635efSGarrett D'Amore }
224995c635efSGarrett D'Amore
225095c635efSGarrett D'Amore /* Handles: `.Dt TITLE'
225195c635efSGarrett D'Amore * --> title = TITLE, volume = local, msec = 0, arch = NULL
225295c635efSGarrett D'Amore */
225395c635efSGarrett D'Amore
225495c635efSGarrett D'Amore mdoc->meta.title = mandoc_strdup
225595c635efSGarrett D'Amore ('\0' == nn->string[0] ? "UNKNOWN" : nn->string);
225695c635efSGarrett D'Amore
225795c635efSGarrett D'Amore if (NULL == (nn = nn->next)) {
225895c635efSGarrett D'Amore /* FIXME: warn about missing msec. */
225995c635efSGarrett D'Amore /* XXX: make this a macro value. */
226095c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup("LOCAL");
226195c635efSGarrett D'Amore mdoc->meta.msec = mandoc_strdup("1");
226295c635efSGarrett D'Amore return(1);
226395c635efSGarrett D'Amore }
226495c635efSGarrett D'Amore
226595c635efSGarrett D'Amore /* Handles: `.Dt TITLE SEC'
226695c635efSGarrett D'Amore * --> title = TITLE, volume = SEC is msec ?
226795c635efSGarrett D'Amore * format(msec) : SEC,
226895c635efSGarrett D'Amore * msec = SEC is msec ? atoi(msec) : 0,
226995c635efSGarrett D'Amore * arch = NULL
227095c635efSGarrett D'Amore */
227195c635efSGarrett D'Amore
227295c635efSGarrett D'Amore cp = mandoc_a2msec(nn->string);
227395c635efSGarrett D'Amore if (cp) {
227495c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(cp);
227595c635efSGarrett D'Amore mdoc->meta.msec = mandoc_strdup(nn->string);
227695c635efSGarrett D'Amore } else {
227795c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_BADMSEC);
227895c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(nn->string);
227995c635efSGarrett D'Amore mdoc->meta.msec = mandoc_strdup(nn->string);
228095c635efSGarrett D'Amore }
228195c635efSGarrett D'Amore
228295c635efSGarrett D'Amore if (NULL == (nn = nn->next))
228395c635efSGarrett D'Amore return(1);
228495c635efSGarrett D'Amore
228595c635efSGarrett D'Amore /* Handles: `.Dt TITLE SEC VOL'
228695c635efSGarrett D'Amore * --> title = TITLE, volume = VOL is vol ?
228795c635efSGarrett D'Amore * format(VOL) :
228895c635efSGarrett D'Amore * VOL is arch ? format(arch) :
228995c635efSGarrett D'Amore * VOL
229095c635efSGarrett D'Amore */
229195c635efSGarrett D'Amore
229295c635efSGarrett D'Amore cp = mdoc_a2vol(nn->string);
229395c635efSGarrett D'Amore if (cp) {
229495c635efSGarrett D'Amore free(mdoc->meta.vol);
229595c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(cp);
229695c635efSGarrett D'Amore } else {
229795c635efSGarrett D'Amore cp = mdoc_a2arch(nn->string);
229895c635efSGarrett D'Amore if (NULL == cp) {
2299*698f87a4SGarrett D'Amore mdoc_nmsg(mdoc, nn, MANDOCERR_BADVOLARCH);
230095c635efSGarrett D'Amore free(mdoc->meta.vol);
230195c635efSGarrett D'Amore mdoc->meta.vol = mandoc_strdup(nn->string);
230295c635efSGarrett D'Amore } else
230395c635efSGarrett D'Amore mdoc->meta.arch = mandoc_strdup(cp);
230495c635efSGarrett D'Amore }
230595c635efSGarrett D'Amore
230695c635efSGarrett D'Amore /* Ignore any subsequent parameters... */
230795c635efSGarrett D'Amore /* FIXME: warn about subsequent parameters. */
230895c635efSGarrett D'Amore
230995c635efSGarrett D'Amore return(1);
231095c635efSGarrett D'Amore }
231195c635efSGarrett D'Amore
231295c635efSGarrett D'Amore static int
post_prol(POST_ARGS)231395c635efSGarrett D'Amore post_prol(POST_ARGS)
231495c635efSGarrett D'Amore {
231595c635efSGarrett D'Amore /*
231695c635efSGarrett D'Amore * Remove prologue macros from the document after they're
231795c635efSGarrett D'Amore * processed. The final document uses mdoc_meta for these
231895c635efSGarrett D'Amore * values and discards the originals.
231995c635efSGarrett D'Amore */
232095c635efSGarrett D'Amore
232195c635efSGarrett D'Amore mdoc_node_delete(mdoc, mdoc->last);
232295c635efSGarrett D'Amore if (mdoc->meta.title && mdoc->meta.date && mdoc->meta.os)
232395c635efSGarrett D'Amore mdoc->flags |= MDOC_PBODY;
232495c635efSGarrett D'Amore
232595c635efSGarrett D'Amore return(1);
232695c635efSGarrett D'Amore }
232795c635efSGarrett D'Amore
232895c635efSGarrett D'Amore static int
post_bx(POST_ARGS)232995c635efSGarrett D'Amore post_bx(POST_ARGS)
233095c635efSGarrett D'Amore {
233195c635efSGarrett D'Amore struct mdoc_node *n;
233295c635efSGarrett D'Amore
233395c635efSGarrett D'Amore /*
233495c635efSGarrett D'Amore * Make `Bx's second argument always start with an uppercase
233595c635efSGarrett D'Amore * letter. Groff checks if it's an "accepted" term, but we just
233695c635efSGarrett D'Amore * uppercase blindly.
233795c635efSGarrett D'Amore */
233895c635efSGarrett D'Amore
233995c635efSGarrett D'Amore n = mdoc->last->child;
234095c635efSGarrett D'Amore if (n && NULL != (n = n->next))
234195c635efSGarrett D'Amore *n->string = (char)toupper
234295c635efSGarrett D'Amore ((unsigned char)*n->string);
234395c635efSGarrett D'Amore
234495c635efSGarrett D'Amore return(1);
234595c635efSGarrett D'Amore }
234695c635efSGarrett D'Amore
234795c635efSGarrett D'Amore static int
post_os(POST_ARGS)234895c635efSGarrett D'Amore post_os(POST_ARGS)
234995c635efSGarrett D'Amore {
235095c635efSGarrett D'Amore struct mdoc_node *n;
235195c635efSGarrett D'Amore char buf[BUFSIZ];
235295c635efSGarrett D'Amore int c;
235395c635efSGarrett D'Amore #ifndef OSNAME
235495c635efSGarrett D'Amore struct utsname utsname;
235595c635efSGarrett D'Amore #endif
235695c635efSGarrett D'Amore
235795c635efSGarrett D'Amore n = mdoc->last;
235895c635efSGarrett D'Amore
235995c635efSGarrett D'Amore /*
2360*698f87a4SGarrett D'Amore * Set the operating system by way of the `Os' macro.
2361*698f87a4SGarrett D'Amore * The order of precedence is:
2362*698f87a4SGarrett D'Amore * 1. the argument of the `Os' macro, unless empty
2363*698f87a4SGarrett D'Amore * 2. the -Ios=foo command line argument, if provided
2364*698f87a4SGarrett D'Amore * 3. -DOSNAME="\"foo\"", if provided during compilation
2365*698f87a4SGarrett D'Amore * 4. "sysname release" from uname(3)
236695c635efSGarrett D'Amore */
236795c635efSGarrett D'Amore
236895c635efSGarrett D'Amore free(mdoc->meta.os);
236995c635efSGarrett D'Amore
237095c635efSGarrett D'Amore buf[0] = '\0';
237195c635efSGarrett D'Amore if (-1 == (c = concat(buf, n->child, BUFSIZ))) {
237295c635efSGarrett D'Amore mdoc_nmsg(mdoc, n->child, MANDOCERR_MEM);
237395c635efSGarrett D'Amore return(0);
237495c635efSGarrett D'Amore }
237595c635efSGarrett D'Amore
237695c635efSGarrett D'Amore assert(c);
237795c635efSGarrett D'Amore
237895c635efSGarrett D'Amore if ('\0' == buf[0]) {
2379*698f87a4SGarrett D'Amore if (mdoc->defos) {
2380*698f87a4SGarrett D'Amore mdoc->meta.os = mandoc_strdup(mdoc->defos);
2381*698f87a4SGarrett D'Amore return(1);
2382*698f87a4SGarrett D'Amore }
238395c635efSGarrett D'Amore #ifdef OSNAME
238495c635efSGarrett D'Amore if (strlcat(buf, OSNAME, BUFSIZ) >= BUFSIZ) {
238595c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
238695c635efSGarrett D'Amore return(0);
238795c635efSGarrett D'Amore }
238895c635efSGarrett D'Amore #else /*!OSNAME */
238995c635efSGarrett D'Amore if (-1 == uname(&utsname)) {
239095c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_UNAME);
239195c635efSGarrett D'Amore mdoc->meta.os = mandoc_strdup("UNKNOWN");
239295c635efSGarrett D'Amore return(post_prol(mdoc));
239395c635efSGarrett D'Amore }
239495c635efSGarrett D'Amore
239595c635efSGarrett D'Amore if (strlcat(buf, utsname.sysname, BUFSIZ) >= BUFSIZ) {
239695c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
239795c635efSGarrett D'Amore return(0);
239895c635efSGarrett D'Amore }
239995c635efSGarrett D'Amore if (strlcat(buf, " ", BUFSIZ) >= BUFSIZ) {
240095c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
240195c635efSGarrett D'Amore return(0);
240295c635efSGarrett D'Amore }
240395c635efSGarrett D'Amore if (strlcat(buf, utsname.release, BUFSIZ) >= BUFSIZ) {
240495c635efSGarrett D'Amore mdoc_nmsg(mdoc, n, MANDOCERR_MEM);
240595c635efSGarrett D'Amore return(0);
240695c635efSGarrett D'Amore }
240795c635efSGarrett D'Amore #endif /*!OSNAME*/
240895c635efSGarrett D'Amore }
240995c635efSGarrett D'Amore
241095c635efSGarrett D'Amore mdoc->meta.os = mandoc_strdup(buf);
241195c635efSGarrett D'Amore return(1);
241295c635efSGarrett D'Amore }
241395c635efSGarrett D'Amore
241495c635efSGarrett D'Amore static int
post_std(POST_ARGS)241595c635efSGarrett D'Amore post_std(POST_ARGS)
241695c635efSGarrett D'Amore {
241795c635efSGarrett D'Amore struct mdoc_node *nn, *n;
241895c635efSGarrett D'Amore
241995c635efSGarrett D'Amore n = mdoc->last;
242095c635efSGarrett D'Amore
242195c635efSGarrett D'Amore /*
242295c635efSGarrett D'Amore * Macros accepting `-std' as an argument have the name of the
242395c635efSGarrett D'Amore * current document (`Nm') filled in as the argument if it's not
242495c635efSGarrett D'Amore * provided.
242595c635efSGarrett D'Amore */
242695c635efSGarrett D'Amore
242795c635efSGarrett D'Amore if (n->child)
242895c635efSGarrett D'Amore return(1);
242995c635efSGarrett D'Amore
243095c635efSGarrett D'Amore if (NULL == mdoc->meta.name)
243195c635efSGarrett D'Amore return(1);
243295c635efSGarrett D'Amore
243395c635efSGarrett D'Amore nn = n;
243495c635efSGarrett D'Amore mdoc->next = MDOC_NEXT_CHILD;
243595c635efSGarrett D'Amore
243695c635efSGarrett D'Amore if ( ! mdoc_word_alloc(mdoc, n->line, n->pos, mdoc->meta.name))
243795c635efSGarrett D'Amore return(0);
243895c635efSGarrett D'Amore
243995c635efSGarrett D'Amore mdoc->last = nn;
244095c635efSGarrett D'Amore return(1);
244195c635efSGarrett D'Amore }
244295c635efSGarrett D'Amore
244395c635efSGarrett D'Amore /*
244495c635efSGarrett D'Amore * Concatenate a node, stopping at the first non-text.
244595c635efSGarrett D'Amore * Concatenation is separated by a single whitespace.
244695c635efSGarrett D'Amore * Returns -1 on fatal (string overrun) error, 0 if child nodes were
244795c635efSGarrett D'Amore * encountered, 1 otherwise.
244895c635efSGarrett D'Amore */
244995c635efSGarrett D'Amore static int
concat(char * p,const struct mdoc_node * n,size_t sz)245095c635efSGarrett D'Amore concat(char *p, const struct mdoc_node *n, size_t sz)
245195c635efSGarrett D'Amore {
245295c635efSGarrett D'Amore
245395c635efSGarrett D'Amore for ( ; NULL != n; n = n->next) {
245495c635efSGarrett D'Amore if (MDOC_TEXT != n->type)
245595c635efSGarrett D'Amore return(0);
245695c635efSGarrett D'Amore if ('\0' != p[0] && strlcat(p, " ", sz) >= sz)
245795c635efSGarrett D'Amore return(-1);
245895c635efSGarrett D'Amore if (strlcat(p, n->string, sz) >= sz)
245995c635efSGarrett D'Amore return(-1);
246095c635efSGarrett D'Amore concat(p, n->child, sz);
246195c635efSGarrett D'Amore }
246295c635efSGarrett D'Amore
246395c635efSGarrett D'Amore return(1);
246495c635efSGarrett D'Amore }
246595c635efSGarrett D'Amore
246695c635efSGarrett D'Amore static enum mdoc_sec
a2sec(const char * p)246795c635efSGarrett D'Amore a2sec(const char *p)
246895c635efSGarrett D'Amore {
246995c635efSGarrett D'Amore int i;
247095c635efSGarrett D'Amore
247195c635efSGarrett D'Amore for (i = 0; i < (int)SEC__MAX; i++)
247295c635efSGarrett D'Amore if (secnames[i] && 0 == strcmp(p, secnames[i]))
247395c635efSGarrett D'Amore return((enum mdoc_sec)i);
247495c635efSGarrett D'Amore
247595c635efSGarrett D'Amore return(SEC_CUSTOM);
247695c635efSGarrett D'Amore }
247795c635efSGarrett D'Amore
247895c635efSGarrett D'Amore static size_t
macro2len(enum mdoct macro)247995c635efSGarrett D'Amore macro2len(enum mdoct macro)
248095c635efSGarrett D'Amore {
248195c635efSGarrett D'Amore
248295c635efSGarrett D'Amore switch (macro) {
248395c635efSGarrett D'Amore case(MDOC_Ad):
248495c635efSGarrett D'Amore return(12);
248595c635efSGarrett D'Amore case(MDOC_Ao):
248695c635efSGarrett D'Amore return(12);
248795c635efSGarrett D'Amore case(MDOC_An):
248895c635efSGarrett D'Amore return(12);
248995c635efSGarrett D'Amore case(MDOC_Aq):
249095c635efSGarrett D'Amore return(12);
249195c635efSGarrett D'Amore case(MDOC_Ar):
249295c635efSGarrett D'Amore return(12);
249395c635efSGarrett D'Amore case(MDOC_Bo):
249495c635efSGarrett D'Amore return(12);
249595c635efSGarrett D'Amore case(MDOC_Bq):
249695c635efSGarrett D'Amore return(12);
249795c635efSGarrett D'Amore case(MDOC_Cd):
249895c635efSGarrett D'Amore return(12);
249995c635efSGarrett D'Amore case(MDOC_Cm):
250095c635efSGarrett D'Amore return(10);
250195c635efSGarrett D'Amore case(MDOC_Do):
250295c635efSGarrett D'Amore return(10);
250395c635efSGarrett D'Amore case(MDOC_Dq):
250495c635efSGarrett D'Amore return(12);
250595c635efSGarrett D'Amore case(MDOC_Dv):
250695c635efSGarrett D'Amore return(12);
250795c635efSGarrett D'Amore case(MDOC_Eo):
250895c635efSGarrett D'Amore return(12);
250995c635efSGarrett D'Amore case(MDOC_Em):
251095c635efSGarrett D'Amore return(10);
251195c635efSGarrett D'Amore case(MDOC_Er):
251295c635efSGarrett D'Amore return(17);
251395c635efSGarrett D'Amore case(MDOC_Ev):
251495c635efSGarrett D'Amore return(15);
251595c635efSGarrett D'Amore case(MDOC_Fa):
251695c635efSGarrett D'Amore return(12);
251795c635efSGarrett D'Amore case(MDOC_Fl):
251895c635efSGarrett D'Amore return(10);
251995c635efSGarrett D'Amore case(MDOC_Fo):
252095c635efSGarrett D'Amore return(16);
252195c635efSGarrett D'Amore case(MDOC_Fn):
252295c635efSGarrett D'Amore return(16);
252395c635efSGarrett D'Amore case(MDOC_Ic):
252495c635efSGarrett D'Amore return(10);
252595c635efSGarrett D'Amore case(MDOC_Li):
252695c635efSGarrett D'Amore return(16);
252795c635efSGarrett D'Amore case(MDOC_Ms):
252895c635efSGarrett D'Amore return(6);
252995c635efSGarrett D'Amore case(MDOC_Nm):
253095c635efSGarrett D'Amore return(10);
253195c635efSGarrett D'Amore case(MDOC_No):
253295c635efSGarrett D'Amore return(12);
253395c635efSGarrett D'Amore case(MDOC_Oo):
253495c635efSGarrett D'Amore return(10);
253595c635efSGarrett D'Amore case(MDOC_Op):
253695c635efSGarrett D'Amore return(14);
253795c635efSGarrett D'Amore case(MDOC_Pa):
253895c635efSGarrett D'Amore return(32);
253995c635efSGarrett D'Amore case(MDOC_Pf):
254095c635efSGarrett D'Amore return(12);
254195c635efSGarrett D'Amore case(MDOC_Po):
254295c635efSGarrett D'Amore return(12);
254395c635efSGarrett D'Amore case(MDOC_Pq):
254495c635efSGarrett D'Amore return(12);
254595c635efSGarrett D'Amore case(MDOC_Ql):
254695c635efSGarrett D'Amore return(16);
254795c635efSGarrett D'Amore case(MDOC_Qo):
254895c635efSGarrett D'Amore return(12);
254995c635efSGarrett D'Amore case(MDOC_So):
255095c635efSGarrett D'Amore return(12);
255195c635efSGarrett D'Amore case(MDOC_Sq):
255295c635efSGarrett D'Amore return(12);
255395c635efSGarrett D'Amore case(MDOC_Sy):
255495c635efSGarrett D'Amore return(6);
255595c635efSGarrett D'Amore case(MDOC_Sx):
255695c635efSGarrett D'Amore return(16);
255795c635efSGarrett D'Amore case(MDOC_Tn):
255895c635efSGarrett D'Amore return(10);
255995c635efSGarrett D'Amore case(MDOC_Va):
256095c635efSGarrett D'Amore return(12);
256195c635efSGarrett D'Amore case(MDOC_Vt):
256295c635efSGarrett D'Amore return(12);
256395c635efSGarrett D'Amore case(MDOC_Xr):
256495c635efSGarrett D'Amore return(10);
256595c635efSGarrett D'Amore default:
256695c635efSGarrett D'Amore break;
256795c635efSGarrett D'Amore };
256895c635efSGarrett D'Amore return(0);
256995c635efSGarrett D'Amore }
2570