1/*	$Id: mdoc_state.c,v 1.8 2017/05/05 15:17:32 schwarze Exp $ */
2/*
3 * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17#include <sys/types.h>
18
19#include <assert.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include "mandoc.h"
24#include "roff.h"
25#include "mdoc.h"
26#include "libmandoc.h"
27#include "libmdoc.h"
28
29#define STATE_ARGS  struct roff_man *mdoc, struct roff_node *n
30
31typedef	void	(*state_handler)(STATE_ARGS);
32
33static	void	 state_bd(STATE_ARGS);
34static	void	 state_bl(STATE_ARGS);
35static	void	 state_dl(STATE_ARGS);
36static	void	 state_sh(STATE_ARGS);
37static	void	 state_sm(STATE_ARGS);
38
39static	const state_handler __state_handlers[MDOC_MAX - MDOC_Dd] = {
40	NULL,		/* Dd */
41	NULL,		/* Dt */
42	NULL,		/* Os */
43	state_sh,	/* Sh */
44	NULL,		/* Ss */
45	NULL,		/* Pp */
46	NULL,		/* D1 */
47	state_dl,	/* Dl */
48	state_bd,	/* Bd */
49	NULL,		/* Ed */
50	state_bl,	/* Bl */
51	NULL,		/* El */
52	NULL,		/* It */
53	NULL,		/* Ad */
54	NULL,		/* An */
55	NULL,		/* Ap */
56	NULL,		/* Ar */
57	NULL,		/* Cd */
58	NULL,		/* Cm */
59	NULL,		/* Dv */
60	NULL,		/* Er */
61	NULL,		/* Ev */
62	NULL,		/* Ex */
63	NULL,		/* Fa */
64	NULL,		/* Fd */
65	NULL,		/* Fl */
66	NULL,		/* Fn */
67	NULL,		/* Ft */
68	NULL,		/* Ic */
69	NULL,		/* In */
70	NULL,		/* Li */
71	NULL,		/* Nd */
72	NULL,		/* Nm */
73	NULL,		/* Op */
74	NULL,		/* Ot */
75	NULL,		/* Pa */
76	NULL,		/* Rv */
77	NULL,		/* St */
78	NULL,		/* Va */
79	NULL,		/* Vt */
80	NULL,		/* Xr */
81	NULL,		/* %A */
82	NULL,		/* %B */
83	NULL,		/* %D */
84	NULL,		/* %I */
85	NULL,		/* %J */
86	NULL,		/* %N */
87	NULL,		/* %O */
88	NULL,		/* %P */
89	NULL,		/* %R */
90	NULL,		/* %T */
91	NULL,		/* %V */
92	NULL,		/* Ac */
93	NULL,		/* Ao */
94	NULL,		/* Aq */
95	NULL,		/* At */
96	NULL,		/* Bc */
97	NULL,		/* Bf */
98	NULL,		/* Bo */
99	NULL,		/* Bq */
100	NULL,		/* Bsx */
101	NULL,		/* Bx */
102	NULL,		/* Db */
103	NULL,		/* Dc */
104	NULL,		/* Do */
105	NULL,		/* Dq */
106	NULL,		/* Ec */
107	NULL,		/* Ef */
108	NULL,		/* Em */
109	NULL,		/* Eo */
110	NULL,		/* Fx */
111	NULL,		/* Ms */
112	NULL,		/* No */
113	NULL,		/* Ns */
114	NULL,		/* Nx */
115	NULL,		/* Ox */
116	NULL,		/* Pc */
117	NULL,		/* Pf */
118	NULL,		/* Po */
119	NULL,		/* Pq */
120	NULL,		/* Qc */
121	NULL,		/* Ql */
122	NULL,		/* Qo */
123	NULL,		/* Qq */
124	NULL,		/* Re */
125	NULL,		/* Rs */
126	NULL,		/* Sc */
127	NULL,		/* So */
128	NULL,		/* Sq */
129	state_sm,	/* Sm */
130	NULL,		/* Sx */
131	NULL,		/* Sy */
132	NULL,		/* Tn */
133	NULL,		/* Ux */
134	NULL,		/* Xc */
135	NULL,		/* Xo */
136	NULL,		/* Fo */
137	NULL,		/* Fc */
138	NULL,		/* Oo */
139	NULL,		/* Oc */
140	NULL,		/* Bk */
141	NULL,		/* Ek */
142	NULL,		/* Bt */
143	NULL,		/* Hf */
144	NULL,		/* Fr */
145	NULL,		/* Ud */
146	NULL,		/* Lb */
147	NULL,		/* Lp */
148	NULL,		/* Lk */
149	NULL,		/* Mt */
150	NULL,		/* Brq */
151	NULL,		/* Bro */
152	NULL,		/* Brc */
153	NULL,		/* %C */
154	NULL,		/* Es */
155	NULL,		/* En */
156	NULL,		/* Dx */
157	NULL,		/* %Q */
158	NULL,		/* %U */
159	NULL,		/* Ta */
160};
161static const state_handler *const state_handlers = __state_handlers - MDOC_Dd;
162
163
164void
165mdoc_state(struct roff_man *mdoc, struct roff_node *n)
166{
167	state_handler handler;
168
169	if (n->tok == TOKEN_NONE || n->tok < ROFF_MAX)
170		return;
171
172	assert(n->tok >= MDOC_Dd && n->tok < MDOC_MAX);
173	if ( ! (mdoc_macros[n->tok].flags & MDOC_PROLOGUE))
174		mdoc->flags |= MDOC_PBODY;
175
176	handler = state_handlers[n->tok];
177	if (*handler)
178		(*handler)(mdoc, n);
179}
180
181void
182mdoc_state_reset(struct roff_man *mdoc)
183{
184
185	roff_setreg(mdoc->roff, "nS", 0, '=');
186	mdoc->flags = 0;
187}
188
189static void
190state_bd(STATE_ARGS)
191{
192	enum mdocargt arg;
193
194	if (n->type != ROFFT_HEAD &&
195	    (n->type != ROFFT_BODY || n->end != ENDBODY_NOT))
196		return;
197
198	if (n->parent->args == NULL)
199		return;
200
201	arg = n->parent->args->argv[0].arg;
202	if (arg != MDOC_Literal && arg != MDOC_Unfilled)
203		return;
204
205	state_dl(mdoc, n);
206}
207
208static void
209state_bl(STATE_ARGS)
210{
211
212	if (n->type != ROFFT_HEAD || n->parent->args == NULL)
213		return;
214
215	switch(n->parent->args->argv[0].arg) {
216	case MDOC_Diag:
217		n->norm->Bl.type = LIST_diag;
218		break;
219	case MDOC_Column:
220		n->norm->Bl.type = LIST_column;
221		break;
222	default:
223		break;
224	}
225}
226
227static void
228state_dl(STATE_ARGS)
229{
230
231	switch (n->type) {
232	case ROFFT_HEAD:
233		mdoc->flags |= MDOC_LITERAL;
234		break;
235	case ROFFT_BODY:
236		mdoc->flags &= ~MDOC_LITERAL;
237		break;
238	default:
239		break;
240	}
241}
242
243static void
244state_sh(STATE_ARGS)
245{
246	struct roff_node *nch;
247	char		 *secname;
248
249	if (n->type != ROFFT_HEAD)
250		return;
251
252	if ( ! (n->flags & NODE_VALID)) {
253		secname = NULL;
254		deroff(&secname, n);
255
256		/*
257		 * Set the section attribute for the BLOCK, HEAD,
258		 * and HEAD children; the latter can only be TEXT
259		 * nodes, so no recursion is needed.  For other
260		 * nodes, including the .Sh BODY, this is done
261		 * when allocating the node data structures, but
262		 * for .Sh BLOCK and HEAD, the section is still
263		 * unknown at that time.
264		 */
265
266		n->sec = n->parent->sec = secname == NULL ?
267		    SEC_CUSTOM : mdoc_a2sec(secname);
268		for (nch = n->child; nch != NULL; nch = nch->next)
269			nch->sec = n->sec;
270		free(secname);
271	}
272
273	if ((mdoc->lastsec = n->sec) == SEC_SYNOPSIS) {
274		roff_setreg(mdoc->roff, "nS", 1, '=');
275		mdoc->flags |= MDOC_SYNOPSIS;
276	} else {
277		roff_setreg(mdoc->roff, "nS", 0, '=');
278		mdoc->flags &= ~MDOC_SYNOPSIS;
279	}
280}
281
282static void
283state_sm(STATE_ARGS)
284{
285
286	if (n->child == NULL)
287		mdoc->flags ^= MDOC_SMOFF;
288	else if ( ! strcmp(n->child->string, "on"))
289		mdoc->flags &= ~MDOC_SMOFF;
290	else if ( ! strcmp(n->child->string, "off"))
291		mdoc->flags |= MDOC_SMOFF;
292}
293