xref: /illumos-gate/usr/src/cmd/mandoc/mdoc_validate.c (revision 698f87a48e2e945bfe5493ce168e0d0ae1cedd5c)
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 
22*698f87a4SGarrett 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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)
746*698f87a4SGarrett 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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) {
1133*698f87a4SGarrett 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:
1147*698f87a4SGarrett D'Amore 		mdoc->meta.name = mandoc_strdup(buf);
1148*698f87a4SGarrett D'Amore 		break;
114995c635efSGarrett D'Amore 	}
115095c635efSGarrett D'Amore 	return(1);
115195c635efSGarrett D'Amore }
115295c635efSGarrett D'Amore 
115395c635efSGarrett D'Amore static int
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
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
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
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
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
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);
1375*698f87a4SGarrett D'Amore 		assert(n->norm->Bl.width);
1376*698f87a4SGarrett D'Amore 	}
137795c635efSGarrett 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
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
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
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
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):
1605*698f87a4SGarrett D'Amore 		break;
1606*698f87a4SGarrett D'Amore 	default:
160795c635efSGarrett D'Amore 		return(1);
1608*698f87a4SGarrett 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;
161495c635efSGarrett D'Amore 			continue;
161595c635efSGarrett D'Amore 		}
161695c635efSGarrett 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
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
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
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
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
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
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
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
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
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
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
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 
2118*698f87a4SGarrett D'Amore static int
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 
214495c635efSGarrett D'Amore static int
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
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
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
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
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
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 
2368*698f87a4SGarrett 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
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
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
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
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