1241675Suqs/*	$Id: eqn.c,v 1.38 2011/07/25 15:37:00 kristaps Exp $ */
2241675Suqs/*
3241675Suqs * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
4241675Suqs *
5241675Suqs * Permission to use, copy, modify, and distribute this software for any
6241675Suqs * purpose with or without fee is hereby granted, provided that the above
7241675Suqs * copyright notice and this permission notice appear in all copies.
8241675Suqs *
9241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16241675Suqs */
17241675Suqs#ifdef HAVE_CONFIG_H
18241675Suqs#include "config.h"
19241675Suqs#endif
20241675Suqs
21241675Suqs#include <assert.h>
22241675Suqs#include <limits.h>
23241675Suqs#include <stdio.h>
24241675Suqs#include <stdlib.h>
25241675Suqs#include <string.h>
26241675Suqs#include <time.h>
27241675Suqs
28241675Suqs#include "mandoc.h"
29241675Suqs#include "libmandoc.h"
30241675Suqs#include "libroff.h"
31241675Suqs
32241675Suqs#define	EQN_NEST_MAX	 128 /* maximum nesting of defines */
33241675Suqs#define	EQN_MSG(t, x)	 mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
34241675Suqs
35241675Suqsenum	eqn_rest {
36241675Suqs	EQN_DESCOPE,
37241675Suqs	EQN_ERR,
38241675Suqs	EQN_OK,
39241675Suqs	EQN_EOF
40241675Suqs};
41241675Suqs
42241675Suqsenum	eqn_symt {
43241675Suqs	EQNSYM_alpha,
44241675Suqs	EQNSYM_beta,
45241675Suqs	EQNSYM_chi,
46241675Suqs	EQNSYM_delta,
47241675Suqs	EQNSYM_epsilon,
48241675Suqs	EQNSYM_eta,
49241675Suqs	EQNSYM_gamma,
50241675Suqs	EQNSYM_iota,
51241675Suqs	EQNSYM_kappa,
52241675Suqs	EQNSYM_lambda,
53241675Suqs	EQNSYM_mu,
54241675Suqs	EQNSYM_nu,
55241675Suqs	EQNSYM_omega,
56241675Suqs	EQNSYM_omicron,
57241675Suqs	EQNSYM_phi,
58241675Suqs	EQNSYM_pi,
59241675Suqs	EQNSYM_ps,
60241675Suqs	EQNSYM_rho,
61241675Suqs	EQNSYM_sigma,
62241675Suqs	EQNSYM_tau,
63241675Suqs	EQNSYM_theta,
64241675Suqs	EQNSYM_upsilon,
65241675Suqs	EQNSYM_xi,
66241675Suqs	EQNSYM_zeta,
67241675Suqs	EQNSYM_DELTA,
68241675Suqs	EQNSYM_GAMMA,
69241675Suqs	EQNSYM_LAMBDA,
70241675Suqs	EQNSYM_OMEGA,
71241675Suqs	EQNSYM_PHI,
72241675Suqs	EQNSYM_PI,
73241675Suqs	EQNSYM_PSI,
74241675Suqs	EQNSYM_SIGMA,
75241675Suqs	EQNSYM_THETA,
76241675Suqs	EQNSYM_UPSILON,
77241675Suqs	EQNSYM_XI,
78241675Suqs	EQNSYM_inter,
79241675Suqs	EQNSYM_union,
80241675Suqs	EQNSYM_prod,
81241675Suqs	EQNSYM_int,
82241675Suqs	EQNSYM_sum,
83241675Suqs	EQNSYM_grad,
84241675Suqs	EQNSYM_del,
85241675Suqs	EQNSYM_times,
86241675Suqs	EQNSYM_cdot,
87241675Suqs	EQNSYM_nothing,
88241675Suqs	EQNSYM_approx,
89241675Suqs	EQNSYM_prime,
90241675Suqs	EQNSYM_half,
91241675Suqs	EQNSYM_partial,
92241675Suqs	EQNSYM_inf,
93241675Suqs	EQNSYM_muchgreat,
94241675Suqs	EQNSYM_muchless,
95241675Suqs	EQNSYM_larrow,
96241675Suqs	EQNSYM_rarrow,
97241675Suqs	EQNSYM_pm,
98241675Suqs	EQNSYM_nequal,
99241675Suqs	EQNSYM_equiv,
100241675Suqs	EQNSYM_lessequal,
101241675Suqs	EQNSYM_moreequal,
102241675Suqs	EQNSYM__MAX
103241675Suqs};
104241675Suqs
105241675Suqsenum	eqnpartt {
106241675Suqs	EQN_DEFINE = 0,
107241675Suqs	EQN_NDEFINE,
108241675Suqs	EQN_TDEFINE,
109241675Suqs	EQN_SET,
110241675Suqs	EQN_UNDEF,
111241675Suqs	EQN_GFONT,
112241675Suqs	EQN_GSIZE,
113241675Suqs	EQN_BACK,
114241675Suqs	EQN_FWD,
115241675Suqs	EQN_UP,
116241675Suqs	EQN_DOWN,
117241675Suqs	EQN__MAX
118241675Suqs};
119241675Suqs
120241675Suqsstruct	eqnstr {
121241675Suqs	const char	*name;
122241675Suqs	size_t		 sz;
123241675Suqs};
124241675Suqs
125241675Suqs#define	STRNEQ(p1, sz1, p2, sz2) \
126241675Suqs	((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
127241675Suqs#define	EQNSTREQ(x, p, sz) \
128241675Suqs	STRNEQ((x)->name, (x)->sz, (p), (sz))
129241675Suqs
130241675Suqsstruct	eqnpart {
131241675Suqs	struct eqnstr	 str;
132241675Suqs	int		(*fp)(struct eqn_node *);
133241675Suqs};
134241675Suqs
135241675Suqsstruct	eqnsym {
136241675Suqs	struct eqnstr	 str;
137241675Suqs	const char	*sym;
138241675Suqs};
139241675Suqs
140241675Suqs
141241675Suqsstatic	enum eqn_rest	 eqn_box(struct eqn_node *, struct eqn_box *);
142241675Suqsstatic	struct eqn_box	*eqn_box_alloc(struct eqn_node *,
143241675Suqs				struct eqn_box *);
144241675Suqsstatic	void		 eqn_box_free(struct eqn_box *);
145241675Suqsstatic	struct eqn_def	*eqn_def_find(struct eqn_node *,
146241675Suqs				const char *, size_t);
147241675Suqsstatic	int		 eqn_do_gfont(struct eqn_node *);
148241675Suqsstatic	int		 eqn_do_gsize(struct eqn_node *);
149241675Suqsstatic	int		 eqn_do_define(struct eqn_node *);
150241675Suqsstatic	int		 eqn_do_ign1(struct eqn_node *);
151241675Suqsstatic	int		 eqn_do_ign2(struct eqn_node *);
152241675Suqsstatic	int		 eqn_do_tdefine(struct eqn_node *);
153241675Suqsstatic	int		 eqn_do_undef(struct eqn_node *);
154241675Suqsstatic	enum eqn_rest	 eqn_eqn(struct eqn_node *, struct eqn_box *);
155241675Suqsstatic	enum eqn_rest	 eqn_list(struct eqn_node *, struct eqn_box *);
156241675Suqsstatic	enum eqn_rest	 eqn_matrix(struct eqn_node *, struct eqn_box *);
157241675Suqsstatic	const char	*eqn_nexttok(struct eqn_node *, size_t *);
158241675Suqsstatic	const char	*eqn_nextrawtok(struct eqn_node *, size_t *);
159241675Suqsstatic	const char	*eqn_next(struct eqn_node *,
160241675Suqs				char, size_t *, int);
161241675Suqsstatic	void		 eqn_rewind(struct eqn_node *);
162241675Suqs
163241675Suqsstatic	const struct eqnpart eqnparts[EQN__MAX] = {
164241675Suqs	{ { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */
165241675Suqs	{ { "ndefine", 7 }, eqn_do_define }, /* EQN_NDEFINE */
166241675Suqs	{ { "tdefine", 7 }, eqn_do_tdefine }, /* EQN_TDEFINE */
167241675Suqs	{ { "set", 3 }, eqn_do_ign2 }, /* EQN_SET */
168241675Suqs	{ { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */
169241675Suqs	{ { "gfont", 5 }, eqn_do_gfont }, /* EQN_GFONT */
170241675Suqs	{ { "gsize", 5 }, eqn_do_gsize }, /* EQN_GSIZE */
171241675Suqs	{ { "back", 4 }, eqn_do_ign1 }, /* EQN_BACK */
172241675Suqs	{ { "fwd", 3 }, eqn_do_ign1 }, /* EQN_FWD */
173241675Suqs	{ { "up", 2 }, eqn_do_ign1 }, /* EQN_UP */
174241675Suqs	{ { "down", 4 }, eqn_do_ign1 }, /* EQN_DOWN */
175241675Suqs};
176241675Suqs
177241675Suqsstatic	const struct eqnstr eqnmarks[EQNMARK__MAX] = {
178241675Suqs	{ "", 0 }, /* EQNMARK_NONE */
179241675Suqs	{ "dot", 3 }, /* EQNMARK_DOT */
180241675Suqs	{ "dotdot", 6 }, /* EQNMARK_DOTDOT */
181241675Suqs	{ "hat", 3 }, /* EQNMARK_HAT */
182241675Suqs	{ "tilde", 5 }, /* EQNMARK_TILDE */
183241675Suqs	{ "vec", 3 }, /* EQNMARK_VEC */
184241675Suqs	{ "dyad", 4 }, /* EQNMARK_DYAD */
185241675Suqs	{ "bar", 3 }, /* EQNMARK_BAR */
186241675Suqs	{ "under", 5 }, /* EQNMARK_UNDER */
187241675Suqs};
188241675Suqs
189241675Suqsstatic	const struct eqnstr eqnfonts[EQNFONT__MAX] = {
190241675Suqs	{ "", 0 }, /* EQNFONT_NONE */
191241675Suqs	{ "roman", 5 }, /* EQNFONT_ROMAN */
192241675Suqs	{ "bold", 4 }, /* EQNFONT_BOLD */
193241675Suqs	{ "fat", 3 }, /* EQNFONT_FAT */
194241675Suqs	{ "italic", 6 }, /* EQNFONT_ITALIC */
195241675Suqs};
196241675Suqs
197241675Suqsstatic	const struct eqnstr eqnposs[EQNPOS__MAX] = {
198241675Suqs	{ "", 0 }, /* EQNPOS_NONE */
199241675Suqs	{ "over", 4 }, /* EQNPOS_OVER */
200241675Suqs	{ "sup", 3 }, /* EQNPOS_SUP */
201241675Suqs	{ "sub", 3 }, /* EQNPOS_SUB */
202241675Suqs	{ "to", 2 }, /* EQNPOS_TO */
203241675Suqs	{ "from", 4 }, /* EQNPOS_FROM */
204241675Suqs};
205241675Suqs
206241675Suqsstatic	const struct eqnstr eqnpiles[EQNPILE__MAX] = {
207241675Suqs	{ "", 0 }, /* EQNPILE_NONE */
208241675Suqs	{ "pile", 4 }, /* EQNPILE_PILE */
209241675Suqs	{ "cpile", 5 }, /* EQNPILE_CPILE */
210241675Suqs	{ "rpile", 5 }, /* EQNPILE_RPILE */
211241675Suqs	{ "lpile", 5 }, /* EQNPILE_LPILE */
212241675Suqs	{ "col", 3 }, /* EQNPILE_COL */
213241675Suqs	{ "ccol", 4 }, /* EQNPILE_CCOL */
214241675Suqs	{ "rcol", 4 }, /* EQNPILE_RCOL */
215241675Suqs	{ "lcol", 4 }, /* EQNPILE_LCOL */
216241675Suqs};
217241675Suqs
218241675Suqsstatic	const struct eqnsym eqnsyms[EQNSYM__MAX] = {
219241675Suqs	{ { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */
220241675Suqs	{ { "beta", 4 }, "*b" }, /* EQNSYM_beta */
221241675Suqs	{ { "chi", 3 }, "*x" }, /* EQNSYM_chi */
222241675Suqs	{ { "delta", 5 }, "*d" }, /* EQNSYM_delta */
223241675Suqs	{ { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */
224241675Suqs	{ { "eta", 3 }, "*y" }, /* EQNSYM_eta */
225241675Suqs	{ { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */
226241675Suqs	{ { "iota", 4 }, "*i" }, /* EQNSYM_iota */
227241675Suqs	{ { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */
228241675Suqs	{ { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */
229241675Suqs	{ { "mu", 2 }, "*m" }, /* EQNSYM_mu */
230241675Suqs	{ { "nu", 2 }, "*n" }, /* EQNSYM_nu */
231241675Suqs	{ { "omega", 5 }, "*w" }, /* EQNSYM_omega */
232241675Suqs	{ { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */
233241675Suqs	{ { "phi", 3 }, "*f" }, /* EQNSYM_phi */
234241675Suqs	{ { "pi", 2 }, "*p" }, /* EQNSYM_pi */
235241675Suqs	{ { "psi", 2 }, "*q" }, /* EQNSYM_psi */
236241675Suqs	{ { "rho", 3 }, "*r" }, /* EQNSYM_rho */
237241675Suqs	{ { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */
238241675Suqs	{ { "tau", 3 }, "*t" }, /* EQNSYM_tau */
239241675Suqs	{ { "theta", 5 }, "*h" }, /* EQNSYM_theta */
240241675Suqs	{ { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */
241241675Suqs	{ { "xi", 2 }, "*c" }, /* EQNSYM_xi */
242241675Suqs	{ { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */
243241675Suqs	{ { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */
244241675Suqs	{ { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */
245241675Suqs	{ { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */
246241675Suqs	{ { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */
247241675Suqs	{ { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */
248241675Suqs	{ { "PI", 2 }, "*P" }, /* EQNSYM_PI */
249241675Suqs	{ { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */
250241675Suqs	{ { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */
251241675Suqs	{ { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */
252241675Suqs	{ { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */
253241675Suqs	{ { "XI", 2 }, "*C" }, /* EQNSYM_XI */
254241675Suqs	{ { "inter", 5 }, "ca" }, /* EQNSYM_inter */
255241675Suqs	{ { "union", 5 }, "cu" }, /* EQNSYM_union */
256241675Suqs	{ { "prod", 4 }, "product" }, /* EQNSYM_prod */
257241675Suqs	{ { "int", 3 }, "integral" }, /* EQNSYM_int */
258241675Suqs	{ { "sum", 3 }, "sum" }, /* EQNSYM_sum */
259241675Suqs	{ { "grad", 4 }, "gr" }, /* EQNSYM_grad */
260241675Suqs	{ { "del", 3 }, "gr" }, /* EQNSYM_del */
261241675Suqs	{ { "times", 5 }, "mu" }, /* EQNSYM_times */
262241675Suqs	{ { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */
263241675Suqs	{ { "nothing", 7 }, "&" }, /* EQNSYM_nothing */
264241675Suqs	{ { "approx", 6 }, "~~" }, /* EQNSYM_approx */
265241675Suqs	{ { "prime", 5 }, "aq" }, /* EQNSYM_prime */
266241675Suqs	{ { "half", 4 }, "12" }, /* EQNSYM_half */
267241675Suqs	{ { "partial", 7 }, "pd" }, /* EQNSYM_partial */
268241675Suqs	{ { "inf", 3 }, "if" }, /* EQNSYM_inf */
269241675Suqs	{ { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */
270241675Suqs	{ { "<<", 2 }, "<<" }, /* EQNSYM_muchless */
271241675Suqs	{ { "<-", 2 }, "<-" }, /* EQNSYM_larrow */
272241675Suqs	{ { "->", 2 }, "->" }, /* EQNSYM_rarrow */
273241675Suqs	{ { "+-", 2 }, "+-" }, /* EQNSYM_pm */
274241675Suqs	{ { "!=", 2 }, "!=" }, /* EQNSYM_nequal */
275241675Suqs	{ { "==", 2 }, "==" }, /* EQNSYM_equiv */
276241675Suqs	{ { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */
277241675Suqs	{ { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
278241675Suqs};
279241675Suqs
280241675Suqs/* ARGSUSED */
281241675Suqsenum rofferr
282241675Suqseqn_read(struct eqn_node **epp, int ln,
283241675Suqs		const char *p, int pos, int *offs)
284241675Suqs{
285241675Suqs	size_t		 sz;
286241675Suqs	struct eqn_node	*ep;
287241675Suqs	enum rofferr	 er;
288241675Suqs
289241675Suqs	ep = *epp;
290241675Suqs
291241675Suqs	/*
292241675Suqs	 * If we're the terminating mark, unset our equation status and
293241675Suqs	 * validate the full equation.
294241675Suqs	 */
295241675Suqs
296241675Suqs	if (0 == strncmp(p, ".EN", 3)) {
297241675Suqs		er = eqn_end(epp);
298241675Suqs		p += 3;
299241675Suqs		while (' ' == *p || '\t' == *p)
300241675Suqs			p++;
301241675Suqs		if ('\0' == *p)
302241675Suqs			return(er);
303241675Suqs		mandoc_msg(MANDOCERR_ARGSLOST, ep->parse, ln, pos, NULL);
304241675Suqs		return(er);
305241675Suqs	}
306241675Suqs
307241675Suqs	/*
308241675Suqs	 * Build up the full string, replacing all newlines with regular
309241675Suqs	 * whitespace.
310241675Suqs	 */
311241675Suqs
312241675Suqs	sz = strlen(p + pos) + 1;
313241675Suqs	ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
314241675Suqs
315241675Suqs	/* First invocation: nil terminate the string. */
316241675Suqs
317241675Suqs	if (0 == ep->sz)
318241675Suqs		*ep->data = '\0';
319241675Suqs
320241675Suqs	ep->sz += sz;
321241675Suqs	strlcat(ep->data, p + pos, ep->sz + 1);
322241675Suqs	strlcat(ep->data, " ", ep->sz + 1);
323241675Suqs	return(ROFF_IGN);
324241675Suqs}
325241675Suqs
326241675Suqsstruct eqn_node *
327241675Suqseqn_alloc(const char *name, int pos, int line, struct mparse *parse)
328241675Suqs{
329241675Suqs	struct eqn_node	*p;
330241675Suqs	size_t		 sz;
331241675Suqs	const char	*end;
332241675Suqs
333241675Suqs	p = mandoc_calloc(1, sizeof(struct eqn_node));
334241675Suqs
335241675Suqs	if (name && '\0' != *name) {
336241675Suqs		sz = strlen(name);
337241675Suqs		assert(sz);
338241675Suqs		do {
339241675Suqs			sz--;
340241675Suqs			end = name + (int)sz;
341241675Suqs		} while (' ' == *end || '\t' == *end);
342241675Suqs		p->eqn.name = mandoc_strndup(name, sz + 1);
343241675Suqs	}
344241675Suqs
345241675Suqs	p->parse = parse;
346241675Suqs	p->eqn.ln = line;
347241675Suqs	p->eqn.pos = pos;
348241675Suqs	p->gsize = EQN_DEFSIZE;
349241675Suqs
350241675Suqs	return(p);
351241675Suqs}
352241675Suqs
353241675Suqsenum rofferr
354241675Suqseqn_end(struct eqn_node **epp)
355241675Suqs{
356241675Suqs	struct eqn_node	*ep;
357241675Suqs	struct eqn_box	*root;
358241675Suqs	enum eqn_rest	 c;
359241675Suqs
360241675Suqs	ep = *epp;
361241675Suqs	*epp = NULL;
362241675Suqs
363241675Suqs	ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
364241675Suqs
365241675Suqs	root = ep->eqn.root;
366241675Suqs	root->type = EQN_ROOT;
367241675Suqs
368241675Suqs	if (0 == ep->sz)
369241675Suqs		return(ROFF_IGN);
370241675Suqs
371241675Suqs	if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
372241675Suqs		EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
373241675Suqs		c = EQN_ERR;
374241675Suqs	}
375241675Suqs
376241675Suqs	return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
377241675Suqs}
378241675Suqs
379241675Suqsstatic enum eqn_rest
380241675Suqseqn_eqn(struct eqn_node *ep, struct eqn_box *last)
381241675Suqs{
382241675Suqs	struct eqn_box	*bp;
383241675Suqs	enum eqn_rest	 c;
384241675Suqs
385241675Suqs	bp = eqn_box_alloc(ep, last);
386241675Suqs	bp->type = EQN_SUBEXPR;
387241675Suqs
388241675Suqs	while (EQN_OK == (c = eqn_box(ep, bp)))
389241675Suqs		/* Spin! */ ;
390241675Suqs
391241675Suqs	return(c);
392241675Suqs}
393241675Suqs
394241675Suqsstatic enum eqn_rest
395241675Suqseqn_matrix(struct eqn_node *ep, struct eqn_box *last)
396241675Suqs{
397241675Suqs	struct eqn_box	*bp;
398241675Suqs	const char	*start;
399241675Suqs	size_t		 sz;
400241675Suqs	enum eqn_rest	 c;
401241675Suqs
402241675Suqs	bp = eqn_box_alloc(ep, last);
403241675Suqs	bp->type = EQN_MATRIX;
404241675Suqs
405241675Suqs	if (NULL == (start = eqn_nexttok(ep, &sz))) {
406241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
407241675Suqs		return(EQN_ERR);
408241675Suqs	}
409241675Suqs	if ( ! STRNEQ(start, sz, "{", 1)) {
410241675Suqs		EQN_MSG(MANDOCERR_EQNSYNT, ep);
411241675Suqs		return(EQN_ERR);
412241675Suqs	}
413241675Suqs
414241675Suqs	while (EQN_OK == (c = eqn_box(ep, bp)))
415241675Suqs		switch (bp->last->pile) {
416241675Suqs		case (EQNPILE_LCOL):
417241675Suqs			/* FALLTHROUGH */
418241675Suqs		case (EQNPILE_CCOL):
419241675Suqs			/* FALLTHROUGH */
420241675Suqs		case (EQNPILE_RCOL):
421241675Suqs			continue;
422241675Suqs		default:
423241675Suqs			EQN_MSG(MANDOCERR_EQNSYNT, ep);
424241675Suqs			return(EQN_ERR);
425241675Suqs		};
426241675Suqs
427241675Suqs	if (EQN_DESCOPE != c) {
428241675Suqs		if (EQN_EOF == c)
429241675Suqs			EQN_MSG(MANDOCERR_EQNEOF, ep);
430241675Suqs		return(EQN_ERR);
431241675Suqs	}
432241675Suqs
433241675Suqs	eqn_rewind(ep);
434241675Suqs	start = eqn_nexttok(ep, &sz);
435241675Suqs	assert(start);
436241675Suqs	if (STRNEQ(start, sz, "}", 1))
437241675Suqs		return(EQN_OK);
438241675Suqs
439241675Suqs	EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
440241675Suqs	return(EQN_ERR);
441241675Suqs}
442241675Suqs
443241675Suqsstatic enum eqn_rest
444241675Suqseqn_list(struct eqn_node *ep, struct eqn_box *last)
445241675Suqs{
446241675Suqs	struct eqn_box	*bp;
447241675Suqs	const char	*start;
448241675Suqs	size_t		 sz;
449241675Suqs	enum eqn_rest	 c;
450241675Suqs
451241675Suqs	bp = eqn_box_alloc(ep, last);
452241675Suqs	bp->type = EQN_LIST;
453241675Suqs
454241675Suqs	if (NULL == (start = eqn_nexttok(ep, &sz))) {
455241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
456241675Suqs		return(EQN_ERR);
457241675Suqs	}
458241675Suqs	if ( ! STRNEQ(start, sz, "{", 1)) {
459241675Suqs		EQN_MSG(MANDOCERR_EQNSYNT, ep);
460241675Suqs		return(EQN_ERR);
461241675Suqs	}
462241675Suqs
463241675Suqs	while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) {
464241675Suqs		eqn_rewind(ep);
465241675Suqs		start = eqn_nexttok(ep, &sz);
466241675Suqs		assert(start);
467241675Suqs		if ( ! STRNEQ(start, sz, "above", 5))
468241675Suqs			break;
469241675Suqs	}
470241675Suqs
471241675Suqs	if (EQN_DESCOPE != c) {
472241675Suqs		if (EQN_ERR != c)
473241675Suqs			EQN_MSG(MANDOCERR_EQNSCOPE, ep);
474241675Suqs		return(EQN_ERR);
475241675Suqs	}
476241675Suqs
477241675Suqs	eqn_rewind(ep);
478241675Suqs	start = eqn_nexttok(ep, &sz);
479241675Suqs	assert(start);
480241675Suqs	if (STRNEQ(start, sz, "}", 1))
481241675Suqs		return(EQN_OK);
482241675Suqs
483241675Suqs	EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
484241675Suqs	return(EQN_ERR);
485241675Suqs}
486241675Suqs
487241675Suqsstatic enum eqn_rest
488241675Suqseqn_box(struct eqn_node *ep, struct eqn_box *last)
489241675Suqs{
490241675Suqs	size_t		 sz;
491241675Suqs	const char	*start;
492241675Suqs	char		*left;
493241675Suqs	char		 sym[64];
494241675Suqs	enum eqn_rest	 c;
495241675Suqs	int		 i, size;
496241675Suqs	struct eqn_box	*bp;
497241675Suqs
498241675Suqs	if (NULL == (start = eqn_nexttok(ep, &sz)))
499241675Suqs		return(EQN_EOF);
500241675Suqs
501241675Suqs	if (STRNEQ(start, sz, "}", 1))
502241675Suqs		return(EQN_DESCOPE);
503241675Suqs	else if (STRNEQ(start, sz, "right", 5))
504241675Suqs		return(EQN_DESCOPE);
505241675Suqs	else if (STRNEQ(start, sz, "above", 5))
506241675Suqs		return(EQN_DESCOPE);
507241675Suqs	else if (STRNEQ(start, sz, "mark", 4))
508241675Suqs		return(EQN_OK);
509241675Suqs	else if (STRNEQ(start, sz, "lineup", 6))
510241675Suqs		return(EQN_OK);
511241675Suqs
512241675Suqs	for (i = 0; i < (int)EQN__MAX; i++) {
513241675Suqs		if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
514241675Suqs			continue;
515241675Suqs		return((*eqnparts[i].fp)(ep) ?
516241675Suqs				EQN_OK : EQN_ERR);
517241675Suqs	}
518241675Suqs
519241675Suqs	if (STRNEQ(start, sz, "{", 1)) {
520241675Suqs		if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
521241675Suqs			if (EQN_ERR != c)
522241675Suqs				EQN_MSG(MANDOCERR_EQNSCOPE, ep);
523241675Suqs			return(EQN_ERR);
524241675Suqs		}
525241675Suqs		eqn_rewind(ep);
526241675Suqs		start = eqn_nexttok(ep, &sz);
527241675Suqs		assert(start);
528241675Suqs		if (STRNEQ(start, sz, "}", 1))
529241675Suqs			return(EQN_OK);
530241675Suqs		EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
531241675Suqs		return(EQN_ERR);
532241675Suqs	}
533241675Suqs
534241675Suqs	for (i = 0; i < (int)EQNPILE__MAX; i++) {
535241675Suqs		if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
536241675Suqs			continue;
537241675Suqs		if (EQN_OK == (c = eqn_list(ep, last)))
538241675Suqs			last->last->pile = (enum eqn_pilet)i;
539241675Suqs		return(c);
540241675Suqs	}
541241675Suqs
542241675Suqs	if (STRNEQ(start, sz, "matrix", 6))
543241675Suqs		return(eqn_matrix(ep, last));
544241675Suqs
545241675Suqs	if (STRNEQ(start, sz, "left", 4)) {
546241675Suqs		if (NULL == (start = eqn_nexttok(ep, &sz))) {
547241675Suqs			EQN_MSG(MANDOCERR_EQNEOF, ep);
548241675Suqs			return(EQN_ERR);
549241675Suqs		}
550241675Suqs		left = mandoc_strndup(start, sz);
551241675Suqs		c = eqn_eqn(ep, last);
552241675Suqs		if (last->last)
553241675Suqs			last->last->left = left;
554241675Suqs		else
555241675Suqs			free(left);
556241675Suqs		if (EQN_DESCOPE != c)
557241675Suqs			return(c);
558241675Suqs		assert(last->last);
559241675Suqs		eqn_rewind(ep);
560241675Suqs		start = eqn_nexttok(ep, &sz);
561241675Suqs		assert(start);
562241675Suqs		if ( ! STRNEQ(start, sz, "right", 5))
563241675Suqs			return(EQN_DESCOPE);
564241675Suqs		if (NULL == (start = eqn_nexttok(ep, &sz))) {
565241675Suqs			EQN_MSG(MANDOCERR_EQNEOF, ep);
566241675Suqs			return(EQN_ERR);
567241675Suqs		}
568241675Suqs		last->last->right = mandoc_strndup(start, sz);
569241675Suqs		return(EQN_OK);
570241675Suqs	}
571241675Suqs
572241675Suqs	for (i = 0; i < (int)EQNPOS__MAX; i++) {
573241675Suqs		if ( ! EQNSTREQ(&eqnposs[i], start, sz))
574241675Suqs			continue;
575241675Suqs		if (NULL == last->last) {
576241675Suqs			EQN_MSG(MANDOCERR_EQNSYNT, ep);
577241675Suqs			return(EQN_ERR);
578241675Suqs		}
579241675Suqs		last->last->pos = (enum eqn_post)i;
580241675Suqs		if (EQN_EOF == (c = eqn_box(ep, last))) {
581241675Suqs			EQN_MSG(MANDOCERR_EQNEOF, ep);
582241675Suqs			return(EQN_ERR);
583241675Suqs		}
584241675Suqs		return(c);
585241675Suqs	}
586241675Suqs
587241675Suqs	for (i = 0; i < (int)EQNMARK__MAX; i++) {
588241675Suqs		if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
589241675Suqs			continue;
590241675Suqs		if (NULL == last->last) {
591241675Suqs			EQN_MSG(MANDOCERR_EQNSYNT, ep);
592241675Suqs			return(EQN_ERR);
593241675Suqs		}
594241675Suqs		last->last->mark = (enum eqn_markt)i;
595241675Suqs		if (EQN_EOF == (c = eqn_box(ep, last))) {
596241675Suqs			EQN_MSG(MANDOCERR_EQNEOF, ep);
597241675Suqs			return(EQN_ERR);
598241675Suqs		}
599241675Suqs		return(c);
600241675Suqs	}
601241675Suqs
602241675Suqs	for (i = 0; i < (int)EQNFONT__MAX; i++) {
603241675Suqs		if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
604241675Suqs			continue;
605241675Suqs		if (EQN_EOF == (c = eqn_box(ep, last))) {
606241675Suqs			EQN_MSG(MANDOCERR_EQNEOF, ep);
607241675Suqs			return(EQN_ERR);
608241675Suqs		} else if (EQN_OK == c)
609241675Suqs			last->last->font = (enum eqn_fontt)i;
610241675Suqs		return(c);
611241675Suqs	}
612241675Suqs
613241675Suqs	if (STRNEQ(start, sz, "size", 4)) {
614241675Suqs		if (NULL == (start = eqn_nexttok(ep, &sz))) {
615241675Suqs			EQN_MSG(MANDOCERR_EQNEOF, ep);
616241675Suqs			return(EQN_ERR);
617241675Suqs		}
618241675Suqs		size = mandoc_strntoi(start, sz, 10);
619241675Suqs		if (EQN_EOF == (c = eqn_box(ep, last))) {
620241675Suqs			EQN_MSG(MANDOCERR_EQNEOF, ep);
621241675Suqs			return(EQN_ERR);
622241675Suqs		} else if (EQN_OK != c)
623241675Suqs			return(c);
624241675Suqs		last->last->size = size;
625241675Suqs	}
626241675Suqs
627241675Suqs	bp = eqn_box_alloc(ep, last);
628241675Suqs	bp->type = EQN_TEXT;
629241675Suqs	for (i = 0; i < (int)EQNSYM__MAX; i++)
630241675Suqs		if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
631241675Suqs			sym[63] = '\0';
632241675Suqs			snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
633241675Suqs			bp->text = mandoc_strdup(sym);
634241675Suqs			return(EQN_OK);
635241675Suqs		}
636241675Suqs
637241675Suqs	bp->text = mandoc_strndup(start, sz);
638241675Suqs	return(EQN_OK);
639241675Suqs}
640241675Suqs
641241675Suqsvoid
642241675Suqseqn_free(struct eqn_node *p)
643241675Suqs{
644241675Suqs	int		 i;
645241675Suqs
646241675Suqs	eqn_box_free(p->eqn.root);
647241675Suqs
648241675Suqs	for (i = 0; i < (int)p->defsz; i++) {
649241675Suqs		free(p->defs[i].key);
650241675Suqs		free(p->defs[i].val);
651241675Suqs	}
652241675Suqs
653241675Suqs	free(p->eqn.name);
654241675Suqs	free(p->data);
655241675Suqs	free(p->defs);
656241675Suqs	free(p);
657241675Suqs}
658241675Suqs
659241675Suqsstatic struct eqn_box *
660241675Suqseqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
661241675Suqs{
662241675Suqs	struct eqn_box	*bp;
663241675Suqs
664241675Suqs	bp = mandoc_calloc(1, sizeof(struct eqn_box));
665241675Suqs	bp->parent = parent;
666241675Suqs	bp->size = ep->gsize;
667241675Suqs
668241675Suqs	if (NULL == parent->first)
669241675Suqs		parent->first = bp;
670241675Suqs	else
671241675Suqs		parent->last->next = bp;
672241675Suqs
673241675Suqs	parent->last = bp;
674241675Suqs	return(bp);
675241675Suqs}
676241675Suqs
677241675Suqsstatic void
678241675Suqseqn_box_free(struct eqn_box *bp)
679241675Suqs{
680241675Suqs
681241675Suqs	if (bp->first)
682241675Suqs		eqn_box_free(bp->first);
683241675Suqs	if (bp->next)
684241675Suqs		eqn_box_free(bp->next);
685241675Suqs
686241675Suqs	free(bp->text);
687241675Suqs	free(bp->left);
688241675Suqs	free(bp->right);
689241675Suqs	free(bp);
690241675Suqs}
691241675Suqs
692241675Suqsstatic const char *
693241675Suqseqn_nextrawtok(struct eqn_node *ep, size_t *sz)
694241675Suqs{
695241675Suqs
696241675Suqs	return(eqn_next(ep, '"', sz, 0));
697241675Suqs}
698241675Suqs
699241675Suqsstatic const char *
700241675Suqseqn_nexttok(struct eqn_node *ep, size_t *sz)
701241675Suqs{
702241675Suqs
703241675Suqs	return(eqn_next(ep, '"', sz, 1));
704241675Suqs}
705241675Suqs
706241675Suqsstatic void
707241675Suqseqn_rewind(struct eqn_node *ep)
708241675Suqs{
709241675Suqs
710241675Suqs	ep->cur = ep->rew;
711241675Suqs}
712241675Suqs
713241675Suqsstatic const char *
714241675Suqseqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
715241675Suqs{
716241675Suqs	char		*start, *next;
717241675Suqs	int		 q, diff, lim;
718241675Suqs	size_t		 ssz, dummy;
719241675Suqs	struct eqn_def	*def;
720241675Suqs
721241675Suqs	if (NULL == sz)
722241675Suqs		sz = &dummy;
723241675Suqs
724241675Suqs	lim = 0;
725241675Suqs	ep->rew = ep->cur;
726241675Suqsagain:
727241675Suqs	/* Prevent self-definitions. */
728241675Suqs
729241675Suqs	if (lim >= EQN_NEST_MAX) {
730241675Suqs		EQN_MSG(MANDOCERR_ROFFLOOP, ep);
731241675Suqs		return(NULL);
732241675Suqs	}
733241675Suqs
734241675Suqs	ep->cur = ep->rew;
735241675Suqs	start = &ep->data[(int)ep->cur];
736241675Suqs	q = 0;
737241675Suqs
738241675Suqs	if ('\0' == *start)
739241675Suqs		return(NULL);
740241675Suqs
741241675Suqs	if (quote == *start) {
742241675Suqs		ep->cur++;
743241675Suqs		q = 1;
744241675Suqs	}
745241675Suqs
746241675Suqs	start = &ep->data[(int)ep->cur];
747241675Suqs
748241675Suqs	if ( ! q) {
749241675Suqs		if ('{' == *start || '}' == *start)
750241675Suqs			ssz = 1;
751241675Suqs		else
752241675Suqs			ssz = strcspn(start + 1, " ^~\"{}\t") + 1;
753241675Suqs		next = start + (int)ssz;
754241675Suqs		if ('\0' == *next)
755241675Suqs			next = NULL;
756241675Suqs	} else
757241675Suqs		next = strchr(start, quote);
758241675Suqs
759241675Suqs	if (NULL != next) {
760241675Suqs		*sz = (size_t)(next - start);
761241675Suqs		ep->cur += *sz;
762241675Suqs		if (q)
763241675Suqs			ep->cur++;
764241675Suqs		while (' ' == ep->data[(int)ep->cur] ||
765241675Suqs				'\t' == ep->data[(int)ep->cur] ||
766241675Suqs				'^' == ep->data[(int)ep->cur] ||
767241675Suqs				'~' == ep->data[(int)ep->cur])
768241675Suqs			ep->cur++;
769241675Suqs	} else {
770241675Suqs		if (q)
771241675Suqs			EQN_MSG(MANDOCERR_BADQUOTE, ep);
772241675Suqs		next = strchr(start, '\0');
773241675Suqs		*sz = (size_t)(next - start);
774241675Suqs		ep->cur += *sz;
775241675Suqs	}
776241675Suqs
777241675Suqs	/* Quotes aren't expanded for values. */
778241675Suqs
779241675Suqs	if (q || ! repl)
780241675Suqs		return(start);
781241675Suqs
782241675Suqs	if (NULL != (def = eqn_def_find(ep, start, *sz))) {
783241675Suqs		diff = def->valsz - *sz;
784241675Suqs
785241675Suqs		if (def->valsz > *sz) {
786241675Suqs			ep->sz += diff;
787241675Suqs			ep->data = mandoc_realloc(ep->data, ep->sz + 1);
788241675Suqs			ep->data[ep->sz] = '\0';
789241675Suqs			start = &ep->data[(int)ep->rew];
790241675Suqs		}
791241675Suqs
792241675Suqs		diff = def->valsz - *sz;
793241675Suqs		memmove(start + *sz + diff, start + *sz,
794241675Suqs				(strlen(start) - *sz) + 1);
795241675Suqs		memcpy(start, def->val, def->valsz);
796241675Suqs		goto again;
797241675Suqs	}
798241675Suqs
799241675Suqs	return(start);
800241675Suqs}
801241675Suqs
802241675Suqsstatic int
803241675Suqseqn_do_ign1(struct eqn_node *ep)
804241675Suqs{
805241675Suqs
806241675Suqs	if (NULL == eqn_nextrawtok(ep, NULL))
807241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
808241675Suqs	else
809241675Suqs		return(1);
810241675Suqs
811241675Suqs	return(0);
812241675Suqs}
813241675Suqs
814241675Suqsstatic int
815241675Suqseqn_do_ign2(struct eqn_node *ep)
816241675Suqs{
817241675Suqs
818241675Suqs	if (NULL == eqn_nextrawtok(ep, NULL))
819241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
820241675Suqs	else if (NULL == eqn_nextrawtok(ep, NULL))
821241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
822241675Suqs	else
823241675Suqs		return(1);
824241675Suqs
825241675Suqs	return(0);
826241675Suqs}
827241675Suqs
828241675Suqsstatic int
829241675Suqseqn_do_tdefine(struct eqn_node *ep)
830241675Suqs{
831241675Suqs
832241675Suqs	if (NULL == eqn_nextrawtok(ep, NULL))
833241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
834241675Suqs	else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0))
835241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
836241675Suqs	else
837241675Suqs		return(1);
838241675Suqs
839241675Suqs	return(0);
840241675Suqs}
841241675Suqs
842241675Suqsstatic int
843241675Suqseqn_do_define(struct eqn_node *ep)
844241675Suqs{
845241675Suqs	const char	*start;
846241675Suqs	size_t		 sz;
847241675Suqs	struct eqn_def	*def;
848241675Suqs	int		 i;
849241675Suqs
850241675Suqs	if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
851241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
852241675Suqs		return(0);
853241675Suqs	}
854241675Suqs
855241675Suqs	/*
856241675Suqs	 * Search for a key that already exists.
857241675Suqs	 * Create a new key if none is found.
858241675Suqs	 */
859241675Suqs
860241675Suqs	if (NULL == (def = eqn_def_find(ep, start, sz))) {
861241675Suqs		/* Find holes in string array. */
862241675Suqs		for (i = 0; i < (int)ep->defsz; i++)
863241675Suqs			if (0 == ep->defs[i].keysz)
864241675Suqs				break;
865241675Suqs
866241675Suqs		if (i == (int)ep->defsz) {
867241675Suqs			ep->defsz++;
868241675Suqs			ep->defs = mandoc_realloc
869241675Suqs				(ep->defs, ep->defsz *
870241675Suqs				 sizeof(struct eqn_def));
871241675Suqs			ep->defs[i].key = ep->defs[i].val = NULL;
872241675Suqs		}
873241675Suqs
874241675Suqs		ep->defs[i].keysz = sz;
875241675Suqs		ep->defs[i].key = mandoc_realloc
876241675Suqs			(ep->defs[i].key, sz + 1);
877241675Suqs
878241675Suqs		memcpy(ep->defs[i].key, start, sz);
879241675Suqs		ep->defs[i].key[(int)sz] = '\0';
880241675Suqs		def = &ep->defs[i];
881241675Suqs	}
882241675Suqs
883241675Suqs	start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
884241675Suqs
885241675Suqs	if (NULL == start) {
886241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
887241675Suqs		return(0);
888241675Suqs	}
889241675Suqs
890241675Suqs	def->valsz = sz;
891241675Suqs	def->val = mandoc_realloc(def->val, sz + 1);
892241675Suqs	memcpy(def->val, start, sz);
893241675Suqs	def->val[(int)sz] = '\0';
894241675Suqs	return(1);
895241675Suqs}
896241675Suqs
897241675Suqsstatic int
898241675Suqseqn_do_gfont(struct eqn_node *ep)
899241675Suqs{
900241675Suqs
901241675Suqs	if (NULL == eqn_nextrawtok(ep, NULL)) {
902241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
903241675Suqs		return(0);
904241675Suqs	}
905241675Suqs	return(1);
906241675Suqs}
907241675Suqs
908241675Suqsstatic int
909241675Suqseqn_do_gsize(struct eqn_node *ep)
910241675Suqs{
911241675Suqs	const char	*start;
912241675Suqs	size_t		 sz;
913241675Suqs
914241675Suqs	if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
915241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
916241675Suqs		return(0);
917241675Suqs	}
918241675Suqs	ep->gsize = mandoc_strntoi(start, sz, 10);
919241675Suqs	return(1);
920241675Suqs}
921241675Suqs
922241675Suqsstatic int
923241675Suqseqn_do_undef(struct eqn_node *ep)
924241675Suqs{
925241675Suqs	const char	*start;
926241675Suqs	struct eqn_def	*def;
927241675Suqs	size_t		 sz;
928241675Suqs
929241675Suqs	if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
930241675Suqs		EQN_MSG(MANDOCERR_EQNEOF, ep);
931241675Suqs		return(0);
932241675Suqs	} else if (NULL != (def = eqn_def_find(ep, start, sz)))
933241675Suqs		def->keysz = 0;
934241675Suqs
935241675Suqs	return(1);
936241675Suqs}
937241675Suqs
938241675Suqsstatic struct eqn_def *
939241675Suqseqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
940241675Suqs{
941241675Suqs	int		 i;
942241675Suqs
943241675Suqs	for (i = 0; i < (int)ep->defsz; i++)
944241675Suqs		if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
945241675Suqs					ep->defs[i].keysz, key, sz))
946241675Suqs			return(&ep->defs[i]);
947241675Suqs
948241675Suqs	return(NULL);
949241675Suqs}
950