1/*	$Id: eqn.c,v 1.38 2011/07/25 15:37:00 kristaps Exp $ */
2/*
3 * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
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#ifdef HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <assert.h>
22#include <limits.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <time.h>
27
28#include "mandoc.h"
29#include "libmandoc.h"
30#include "libroff.h"
31
32#define	EQN_NEST_MAX	 128 /* maximum nesting of defines */
33#define	EQN_MSG(t, x)	 mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
34
35enum	eqn_rest {
36	EQN_DESCOPE,
37	EQN_ERR,
38	EQN_OK,
39	EQN_EOF
40};
41
42enum	eqn_symt {
43	EQNSYM_alpha,
44	EQNSYM_beta,
45	EQNSYM_chi,
46	EQNSYM_delta,
47	EQNSYM_epsilon,
48	EQNSYM_eta,
49	EQNSYM_gamma,
50	EQNSYM_iota,
51	EQNSYM_kappa,
52	EQNSYM_lambda,
53	EQNSYM_mu,
54	EQNSYM_nu,
55	EQNSYM_omega,
56	EQNSYM_omicron,
57	EQNSYM_phi,
58	EQNSYM_pi,
59	EQNSYM_ps,
60	EQNSYM_rho,
61	EQNSYM_sigma,
62	EQNSYM_tau,
63	EQNSYM_theta,
64	EQNSYM_upsilon,
65	EQNSYM_xi,
66	EQNSYM_zeta,
67	EQNSYM_DELTA,
68	EQNSYM_GAMMA,
69	EQNSYM_LAMBDA,
70	EQNSYM_OMEGA,
71	EQNSYM_PHI,
72	EQNSYM_PI,
73	EQNSYM_PSI,
74	EQNSYM_SIGMA,
75	EQNSYM_THETA,
76	EQNSYM_UPSILON,
77	EQNSYM_XI,
78	EQNSYM_inter,
79	EQNSYM_union,
80	EQNSYM_prod,
81	EQNSYM_int,
82	EQNSYM_sum,
83	EQNSYM_grad,
84	EQNSYM_del,
85	EQNSYM_times,
86	EQNSYM_cdot,
87	EQNSYM_nothing,
88	EQNSYM_approx,
89	EQNSYM_prime,
90	EQNSYM_half,
91	EQNSYM_partial,
92	EQNSYM_inf,
93	EQNSYM_muchgreat,
94	EQNSYM_muchless,
95	EQNSYM_larrow,
96	EQNSYM_rarrow,
97	EQNSYM_pm,
98	EQNSYM_nequal,
99	EQNSYM_equiv,
100	EQNSYM_lessequal,
101	EQNSYM_moreequal,
102	EQNSYM__MAX
103};
104
105enum	eqnpartt {
106	EQN_DEFINE = 0,
107	EQN_NDEFINE,
108	EQN_TDEFINE,
109	EQN_SET,
110	EQN_UNDEF,
111	EQN_GFONT,
112	EQN_GSIZE,
113	EQN_BACK,
114	EQN_FWD,
115	EQN_UP,
116	EQN_DOWN,
117	EQN__MAX
118};
119
120struct	eqnstr {
121	const char	*name;
122	size_t		 sz;
123};
124
125#define	STRNEQ(p1, sz1, p2, sz2) \
126	((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
127#define	EQNSTREQ(x, p, sz) \
128	STRNEQ((x)->name, (x)->sz, (p), (sz))
129
130struct	eqnpart {
131	struct eqnstr	 str;
132	int		(*fp)(struct eqn_node *);
133};
134
135struct	eqnsym {
136	struct eqnstr	 str;
137	const char	*sym;
138};
139
140
141static	enum eqn_rest	 eqn_box(struct eqn_node *, struct eqn_box *);
142static	struct eqn_box	*eqn_box_alloc(struct eqn_node *,
143				struct eqn_box *);
144static	void		 eqn_box_free(struct eqn_box *);
145static	struct eqn_def	*eqn_def_find(struct eqn_node *,
146				const char *, size_t);
147static	int		 eqn_do_gfont(struct eqn_node *);
148static	int		 eqn_do_gsize(struct eqn_node *);
149static	int		 eqn_do_define(struct eqn_node *);
150static	int		 eqn_do_ign1(struct eqn_node *);
151static	int		 eqn_do_ign2(struct eqn_node *);
152static	int		 eqn_do_tdefine(struct eqn_node *);
153static	int		 eqn_do_undef(struct eqn_node *);
154static	enum eqn_rest	 eqn_eqn(struct eqn_node *, struct eqn_box *);
155static	enum eqn_rest	 eqn_list(struct eqn_node *, struct eqn_box *);
156static	enum eqn_rest	 eqn_matrix(struct eqn_node *, struct eqn_box *);
157static	const char	*eqn_nexttok(struct eqn_node *, size_t *);
158static	const char	*eqn_nextrawtok(struct eqn_node *, size_t *);
159static	const char	*eqn_next(struct eqn_node *,
160				char, size_t *, int);
161static	void		 eqn_rewind(struct eqn_node *);
162
163static	const struct eqnpart eqnparts[EQN__MAX] = {
164	{ { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */
165	{ { "ndefine", 7 }, eqn_do_define }, /* EQN_NDEFINE */
166	{ { "tdefine", 7 }, eqn_do_tdefine }, /* EQN_TDEFINE */
167	{ { "set", 3 }, eqn_do_ign2 }, /* EQN_SET */
168	{ { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */
169	{ { "gfont", 5 }, eqn_do_gfont }, /* EQN_GFONT */
170	{ { "gsize", 5 }, eqn_do_gsize }, /* EQN_GSIZE */
171	{ { "back", 4 }, eqn_do_ign1 }, /* EQN_BACK */
172	{ { "fwd", 3 }, eqn_do_ign1 }, /* EQN_FWD */
173	{ { "up", 2 }, eqn_do_ign1 }, /* EQN_UP */
174	{ { "down", 4 }, eqn_do_ign1 }, /* EQN_DOWN */
175};
176
177static	const struct eqnstr eqnmarks[EQNMARK__MAX] = {
178	{ "", 0 }, /* EQNMARK_NONE */
179	{ "dot", 3 }, /* EQNMARK_DOT */
180	{ "dotdot", 6 }, /* EQNMARK_DOTDOT */
181	{ "hat", 3 }, /* EQNMARK_HAT */
182	{ "tilde", 5 }, /* EQNMARK_TILDE */
183	{ "vec", 3 }, /* EQNMARK_VEC */
184	{ "dyad", 4 }, /* EQNMARK_DYAD */
185	{ "bar", 3 }, /* EQNMARK_BAR */
186	{ "under", 5 }, /* EQNMARK_UNDER */
187};
188
189static	const struct eqnstr eqnfonts[EQNFONT__MAX] = {
190	{ "", 0 }, /* EQNFONT_NONE */
191	{ "roman", 5 }, /* EQNFONT_ROMAN */
192	{ "bold", 4 }, /* EQNFONT_BOLD */
193	{ "fat", 3 }, /* EQNFONT_FAT */
194	{ "italic", 6 }, /* EQNFONT_ITALIC */
195};
196
197static	const struct eqnstr eqnposs[EQNPOS__MAX] = {
198	{ "", 0 }, /* EQNPOS_NONE */
199	{ "over", 4 }, /* EQNPOS_OVER */
200	{ "sup", 3 }, /* EQNPOS_SUP */
201	{ "sub", 3 }, /* EQNPOS_SUB */
202	{ "to", 2 }, /* EQNPOS_TO */
203	{ "from", 4 }, /* EQNPOS_FROM */
204};
205
206static	const struct eqnstr eqnpiles[EQNPILE__MAX] = {
207	{ "", 0 }, /* EQNPILE_NONE */
208	{ "pile", 4 }, /* EQNPILE_PILE */
209	{ "cpile", 5 }, /* EQNPILE_CPILE */
210	{ "rpile", 5 }, /* EQNPILE_RPILE */
211	{ "lpile", 5 }, /* EQNPILE_LPILE */
212	{ "col", 3 }, /* EQNPILE_COL */
213	{ "ccol", 4 }, /* EQNPILE_CCOL */
214	{ "rcol", 4 }, /* EQNPILE_RCOL */
215	{ "lcol", 4 }, /* EQNPILE_LCOL */
216};
217
218static	const struct eqnsym eqnsyms[EQNSYM__MAX] = {
219	{ { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */
220	{ { "beta", 4 }, "*b" }, /* EQNSYM_beta */
221	{ { "chi", 3 }, "*x" }, /* EQNSYM_chi */
222	{ { "delta", 5 }, "*d" }, /* EQNSYM_delta */
223	{ { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */
224	{ { "eta", 3 }, "*y" }, /* EQNSYM_eta */
225	{ { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */
226	{ { "iota", 4 }, "*i" }, /* EQNSYM_iota */
227	{ { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */
228	{ { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */
229	{ { "mu", 2 }, "*m" }, /* EQNSYM_mu */
230	{ { "nu", 2 }, "*n" }, /* EQNSYM_nu */
231	{ { "omega", 5 }, "*w" }, /* EQNSYM_omega */
232	{ { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */
233	{ { "phi", 3 }, "*f" }, /* EQNSYM_phi */
234	{ { "pi", 2 }, "*p" }, /* EQNSYM_pi */
235	{ { "psi", 2 }, "*q" }, /* EQNSYM_psi */
236	{ { "rho", 3 }, "*r" }, /* EQNSYM_rho */
237	{ { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */
238	{ { "tau", 3 }, "*t" }, /* EQNSYM_tau */
239	{ { "theta", 5 }, "*h" }, /* EQNSYM_theta */
240	{ { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */
241	{ { "xi", 2 }, "*c" }, /* EQNSYM_xi */
242	{ { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */
243	{ { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */
244	{ { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */
245	{ { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */
246	{ { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */
247	{ { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */
248	{ { "PI", 2 }, "*P" }, /* EQNSYM_PI */
249	{ { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */
250	{ { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */
251	{ { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */
252	{ { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */
253	{ { "XI", 2 }, "*C" }, /* EQNSYM_XI */
254	{ { "inter", 5 }, "ca" }, /* EQNSYM_inter */
255	{ { "union", 5 }, "cu" }, /* EQNSYM_union */
256	{ { "prod", 4 }, "product" }, /* EQNSYM_prod */
257	{ { "int", 3 }, "integral" }, /* EQNSYM_int */
258	{ { "sum", 3 }, "sum" }, /* EQNSYM_sum */
259	{ { "grad", 4 }, "gr" }, /* EQNSYM_grad */
260	{ { "del", 3 }, "gr" }, /* EQNSYM_del */
261	{ { "times", 5 }, "mu" }, /* EQNSYM_times */
262	{ { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */
263	{ { "nothing", 7 }, "&" }, /* EQNSYM_nothing */
264	{ { "approx", 6 }, "~~" }, /* EQNSYM_approx */
265	{ { "prime", 5 }, "aq" }, /* EQNSYM_prime */
266	{ { "half", 4 }, "12" }, /* EQNSYM_half */
267	{ { "partial", 7 }, "pd" }, /* EQNSYM_partial */
268	{ { "inf", 3 }, "if" }, /* EQNSYM_inf */
269	{ { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */
270	{ { "<<", 2 }, "<<" }, /* EQNSYM_muchless */
271	{ { "<-", 2 }, "<-" }, /* EQNSYM_larrow */
272	{ { "->", 2 }, "->" }, /* EQNSYM_rarrow */
273	{ { "+-", 2 }, "+-" }, /* EQNSYM_pm */
274	{ { "!=", 2 }, "!=" }, /* EQNSYM_nequal */
275	{ { "==", 2 }, "==" }, /* EQNSYM_equiv */
276	{ { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */
277	{ { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
278};
279
280/* ARGSUSED */
281enum rofferr
282eqn_read(struct eqn_node **epp, int ln,
283		const char *p, int pos, int *offs)
284{
285	size_t		 sz;
286	struct eqn_node	*ep;
287	enum rofferr	 er;
288
289	ep = *epp;
290
291	/*
292	 * If we're the terminating mark, unset our equation status and
293	 * validate the full equation.
294	 */
295
296	if (0 == strncmp(p, ".EN", 3)) {
297		er = eqn_end(epp);
298		p += 3;
299		while (' ' == *p || '\t' == *p)
300			p++;
301		if ('\0' == *p)
302			return(er);
303		mandoc_msg(MANDOCERR_ARGSLOST, ep->parse, ln, pos, NULL);
304		return(er);
305	}
306
307	/*
308	 * Build up the full string, replacing all newlines with regular
309	 * whitespace.
310	 */
311
312	sz = strlen(p + pos) + 1;
313	ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
314
315	/* First invocation: nil terminate the string. */
316
317	if (0 == ep->sz)
318		*ep->data = '\0';
319
320	ep->sz += sz;
321	strlcat(ep->data, p + pos, ep->sz + 1);
322	strlcat(ep->data, " ", ep->sz + 1);
323	return(ROFF_IGN);
324}
325
326struct eqn_node *
327eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
328{
329	struct eqn_node	*p;
330	size_t		 sz;
331	const char	*end;
332
333	p = mandoc_calloc(1, sizeof(struct eqn_node));
334
335	if (name && '\0' != *name) {
336		sz = strlen(name);
337		assert(sz);
338		do {
339			sz--;
340			end = name + (int)sz;
341		} while (' ' == *end || '\t' == *end);
342		p->eqn.name = mandoc_strndup(name, sz + 1);
343	}
344
345	p->parse = parse;
346	p->eqn.ln = line;
347	p->eqn.pos = pos;
348	p->gsize = EQN_DEFSIZE;
349
350	return(p);
351}
352
353enum rofferr
354eqn_end(struct eqn_node **epp)
355{
356	struct eqn_node	*ep;
357	struct eqn_box	*root;
358	enum eqn_rest	 c;
359
360	ep = *epp;
361	*epp = NULL;
362
363	ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
364
365	root = ep->eqn.root;
366	root->type = EQN_ROOT;
367
368	if (0 == ep->sz)
369		return(ROFF_IGN);
370
371	if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
372		EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
373		c = EQN_ERR;
374	}
375
376	return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
377}
378
379static enum eqn_rest
380eqn_eqn(struct eqn_node *ep, struct eqn_box *last)
381{
382	struct eqn_box	*bp;
383	enum eqn_rest	 c;
384
385	bp = eqn_box_alloc(ep, last);
386	bp->type = EQN_SUBEXPR;
387
388	while (EQN_OK == (c = eqn_box(ep, bp)))
389		/* Spin! */ ;
390
391	return(c);
392}
393
394static enum eqn_rest
395eqn_matrix(struct eqn_node *ep, struct eqn_box *last)
396{
397	struct eqn_box	*bp;
398	const char	*start;
399	size_t		 sz;
400	enum eqn_rest	 c;
401
402	bp = eqn_box_alloc(ep, last);
403	bp->type = EQN_MATRIX;
404
405	if (NULL == (start = eqn_nexttok(ep, &sz))) {
406		EQN_MSG(MANDOCERR_EQNEOF, ep);
407		return(EQN_ERR);
408	}
409	if ( ! STRNEQ(start, sz, "{", 1)) {
410		EQN_MSG(MANDOCERR_EQNSYNT, ep);
411		return(EQN_ERR);
412	}
413
414	while (EQN_OK == (c = eqn_box(ep, bp)))
415		switch (bp->last->pile) {
416		case (EQNPILE_LCOL):
417			/* FALLTHROUGH */
418		case (EQNPILE_CCOL):
419			/* FALLTHROUGH */
420		case (EQNPILE_RCOL):
421			continue;
422		default:
423			EQN_MSG(MANDOCERR_EQNSYNT, ep);
424			return(EQN_ERR);
425		};
426
427	if (EQN_DESCOPE != c) {
428		if (EQN_EOF == c)
429			EQN_MSG(MANDOCERR_EQNEOF, ep);
430		return(EQN_ERR);
431	}
432
433	eqn_rewind(ep);
434	start = eqn_nexttok(ep, &sz);
435	assert(start);
436	if (STRNEQ(start, sz, "}", 1))
437		return(EQN_OK);
438
439	EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
440	return(EQN_ERR);
441}
442
443static enum eqn_rest
444eqn_list(struct eqn_node *ep, struct eqn_box *last)
445{
446	struct eqn_box	*bp;
447	const char	*start;
448	size_t		 sz;
449	enum eqn_rest	 c;
450
451	bp = eqn_box_alloc(ep, last);
452	bp->type = EQN_LIST;
453
454	if (NULL == (start = eqn_nexttok(ep, &sz))) {
455		EQN_MSG(MANDOCERR_EQNEOF, ep);
456		return(EQN_ERR);
457	}
458	if ( ! STRNEQ(start, sz, "{", 1)) {
459		EQN_MSG(MANDOCERR_EQNSYNT, ep);
460		return(EQN_ERR);
461	}
462
463	while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) {
464		eqn_rewind(ep);
465		start = eqn_nexttok(ep, &sz);
466		assert(start);
467		if ( ! STRNEQ(start, sz, "above", 5))
468			break;
469	}
470
471	if (EQN_DESCOPE != c) {
472		if (EQN_ERR != c)
473			EQN_MSG(MANDOCERR_EQNSCOPE, ep);
474		return(EQN_ERR);
475	}
476
477	eqn_rewind(ep);
478	start = eqn_nexttok(ep, &sz);
479	assert(start);
480	if (STRNEQ(start, sz, "}", 1))
481		return(EQN_OK);
482
483	EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
484	return(EQN_ERR);
485}
486
487static enum eqn_rest
488eqn_box(struct eqn_node *ep, struct eqn_box *last)
489{
490	size_t		 sz;
491	const char	*start;
492	char		*left;
493	char		 sym[64];
494	enum eqn_rest	 c;
495	int		 i, size;
496	struct eqn_box	*bp;
497
498	if (NULL == (start = eqn_nexttok(ep, &sz)))
499		return(EQN_EOF);
500
501	if (STRNEQ(start, sz, "}", 1))
502		return(EQN_DESCOPE);
503	else if (STRNEQ(start, sz, "right", 5))
504		return(EQN_DESCOPE);
505	else if (STRNEQ(start, sz, "above", 5))
506		return(EQN_DESCOPE);
507	else if (STRNEQ(start, sz, "mark", 4))
508		return(EQN_OK);
509	else if (STRNEQ(start, sz, "lineup", 6))
510		return(EQN_OK);
511
512	for (i = 0; i < (int)EQN__MAX; i++) {
513		if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
514			continue;
515		return((*eqnparts[i].fp)(ep) ?
516				EQN_OK : EQN_ERR);
517	}
518
519	if (STRNEQ(start, sz, "{", 1)) {
520		if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
521			if (EQN_ERR != c)
522				EQN_MSG(MANDOCERR_EQNSCOPE, ep);
523			return(EQN_ERR);
524		}
525		eqn_rewind(ep);
526		start = eqn_nexttok(ep, &sz);
527		assert(start);
528		if (STRNEQ(start, sz, "}", 1))
529			return(EQN_OK);
530		EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
531		return(EQN_ERR);
532	}
533
534	for (i = 0; i < (int)EQNPILE__MAX; i++) {
535		if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
536			continue;
537		if (EQN_OK == (c = eqn_list(ep, last)))
538			last->last->pile = (enum eqn_pilet)i;
539		return(c);
540	}
541
542	if (STRNEQ(start, sz, "matrix", 6))
543		return(eqn_matrix(ep, last));
544
545	if (STRNEQ(start, sz, "left", 4)) {
546		if (NULL == (start = eqn_nexttok(ep, &sz))) {
547			EQN_MSG(MANDOCERR_EQNEOF, ep);
548			return(EQN_ERR);
549		}
550		left = mandoc_strndup(start, sz);
551		c = eqn_eqn(ep, last);
552		if (last->last)
553			last->last->left = left;
554		else
555			free(left);
556		if (EQN_DESCOPE != c)
557			return(c);
558		assert(last->last);
559		eqn_rewind(ep);
560		start = eqn_nexttok(ep, &sz);
561		assert(start);
562		if ( ! STRNEQ(start, sz, "right", 5))
563			return(EQN_DESCOPE);
564		if (NULL == (start = eqn_nexttok(ep, &sz))) {
565			EQN_MSG(MANDOCERR_EQNEOF, ep);
566			return(EQN_ERR);
567		}
568		last->last->right = mandoc_strndup(start, sz);
569		return(EQN_OK);
570	}
571
572	for (i = 0; i < (int)EQNPOS__MAX; i++) {
573		if ( ! EQNSTREQ(&eqnposs[i], start, sz))
574			continue;
575		if (NULL == last->last) {
576			EQN_MSG(MANDOCERR_EQNSYNT, ep);
577			return(EQN_ERR);
578		}
579		last->last->pos = (enum eqn_post)i;
580		if (EQN_EOF == (c = eqn_box(ep, last))) {
581			EQN_MSG(MANDOCERR_EQNEOF, ep);
582			return(EQN_ERR);
583		}
584		return(c);
585	}
586
587	for (i = 0; i < (int)EQNMARK__MAX; i++) {
588		if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
589			continue;
590		if (NULL == last->last) {
591			EQN_MSG(MANDOCERR_EQNSYNT, ep);
592			return(EQN_ERR);
593		}
594		last->last->mark = (enum eqn_markt)i;
595		if (EQN_EOF == (c = eqn_box(ep, last))) {
596			EQN_MSG(MANDOCERR_EQNEOF, ep);
597			return(EQN_ERR);
598		}
599		return(c);
600	}
601
602	for (i = 0; i < (int)EQNFONT__MAX; i++) {
603		if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
604			continue;
605		if (EQN_EOF == (c = eqn_box(ep, last))) {
606			EQN_MSG(MANDOCERR_EQNEOF, ep);
607			return(EQN_ERR);
608		} else if (EQN_OK == c)
609			last->last->font = (enum eqn_fontt)i;
610		return(c);
611	}
612
613	if (STRNEQ(start, sz, "size", 4)) {
614		if (NULL == (start = eqn_nexttok(ep, &sz))) {
615			EQN_MSG(MANDOCERR_EQNEOF, ep);
616			return(EQN_ERR);
617		}
618		size = mandoc_strntoi(start, sz, 10);
619		if (EQN_EOF == (c = eqn_box(ep, last))) {
620			EQN_MSG(MANDOCERR_EQNEOF, ep);
621			return(EQN_ERR);
622		} else if (EQN_OK != c)
623			return(c);
624		last->last->size = size;
625	}
626
627	bp = eqn_box_alloc(ep, last);
628	bp->type = EQN_TEXT;
629	for (i = 0; i < (int)EQNSYM__MAX; i++)
630		if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
631			sym[63] = '\0';
632			snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
633			bp->text = mandoc_strdup(sym);
634			return(EQN_OK);
635		}
636
637	bp->text = mandoc_strndup(start, sz);
638	return(EQN_OK);
639}
640
641void
642eqn_free(struct eqn_node *p)
643{
644	int		 i;
645
646	eqn_box_free(p->eqn.root);
647
648	for (i = 0; i < (int)p->defsz; i++) {
649		free(p->defs[i].key);
650		free(p->defs[i].val);
651	}
652
653	free(p->eqn.name);
654	free(p->data);
655	free(p->defs);
656	free(p);
657}
658
659static struct eqn_box *
660eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
661{
662	struct eqn_box	*bp;
663
664	bp = mandoc_calloc(1, sizeof(struct eqn_box));
665	bp->parent = parent;
666	bp->size = ep->gsize;
667
668	if (NULL == parent->first)
669		parent->first = bp;
670	else
671		parent->last->next = bp;
672
673	parent->last = bp;
674	return(bp);
675}
676
677static void
678eqn_box_free(struct eqn_box *bp)
679{
680
681	if (bp->first)
682		eqn_box_free(bp->first);
683	if (bp->next)
684		eqn_box_free(bp->next);
685
686	free(bp->text);
687	free(bp->left);
688	free(bp->right);
689	free(bp);
690}
691
692static const char *
693eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
694{
695
696	return(eqn_next(ep, '"', sz, 0));
697}
698
699static const char *
700eqn_nexttok(struct eqn_node *ep, size_t *sz)
701{
702
703	return(eqn_next(ep, '"', sz, 1));
704}
705
706static void
707eqn_rewind(struct eqn_node *ep)
708{
709
710	ep->cur = ep->rew;
711}
712
713static const char *
714eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
715{
716	char		*start, *next;
717	int		 q, diff, lim;
718	size_t		 ssz, dummy;
719	struct eqn_def	*def;
720
721	if (NULL == sz)
722		sz = &dummy;
723
724	lim = 0;
725	ep->rew = ep->cur;
726again:
727	/* Prevent self-definitions. */
728
729	if (lim >= EQN_NEST_MAX) {
730		EQN_MSG(MANDOCERR_ROFFLOOP, ep);
731		return(NULL);
732	}
733
734	ep->cur = ep->rew;
735	start = &ep->data[(int)ep->cur];
736	q = 0;
737
738	if ('\0' == *start)
739		return(NULL);
740
741	if (quote == *start) {
742		ep->cur++;
743		q = 1;
744	}
745
746	start = &ep->data[(int)ep->cur];
747
748	if ( ! q) {
749		if ('{' == *start || '}' == *start)
750			ssz = 1;
751		else
752			ssz = strcspn(start + 1, " ^~\"{}\t") + 1;
753		next = start + (int)ssz;
754		if ('\0' == *next)
755			next = NULL;
756	} else
757		next = strchr(start, quote);
758
759	if (NULL != next) {
760		*sz = (size_t)(next - start);
761		ep->cur += *sz;
762		if (q)
763			ep->cur++;
764		while (' ' == ep->data[(int)ep->cur] ||
765				'\t' == ep->data[(int)ep->cur] ||
766				'^' == ep->data[(int)ep->cur] ||
767				'~' == ep->data[(int)ep->cur])
768			ep->cur++;
769	} else {
770		if (q)
771			EQN_MSG(MANDOCERR_BADQUOTE, ep);
772		next = strchr(start, '\0');
773		*sz = (size_t)(next - start);
774		ep->cur += *sz;
775	}
776
777	/* Quotes aren't expanded for values. */
778
779	if (q || ! repl)
780		return(start);
781
782	if (NULL != (def = eqn_def_find(ep, start, *sz))) {
783		diff = def->valsz - *sz;
784
785		if (def->valsz > *sz) {
786			ep->sz += diff;
787			ep->data = mandoc_realloc(ep->data, ep->sz + 1);
788			ep->data[ep->sz] = '\0';
789			start = &ep->data[(int)ep->rew];
790		}
791
792		diff = def->valsz - *sz;
793		memmove(start + *sz + diff, start + *sz,
794				(strlen(start) - *sz) + 1);
795		memcpy(start, def->val, def->valsz);
796		goto again;
797	}
798
799	return(start);
800}
801
802static int
803eqn_do_ign1(struct eqn_node *ep)
804{
805
806	if (NULL == eqn_nextrawtok(ep, NULL))
807		EQN_MSG(MANDOCERR_EQNEOF, ep);
808	else
809		return(1);
810
811	return(0);
812}
813
814static int
815eqn_do_ign2(struct eqn_node *ep)
816{
817
818	if (NULL == eqn_nextrawtok(ep, NULL))
819		EQN_MSG(MANDOCERR_EQNEOF, ep);
820	else if (NULL == eqn_nextrawtok(ep, NULL))
821		EQN_MSG(MANDOCERR_EQNEOF, ep);
822	else
823		return(1);
824
825	return(0);
826}
827
828static int
829eqn_do_tdefine(struct eqn_node *ep)
830{
831
832	if (NULL == eqn_nextrawtok(ep, NULL))
833		EQN_MSG(MANDOCERR_EQNEOF, ep);
834	else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0))
835		EQN_MSG(MANDOCERR_EQNEOF, ep);
836	else
837		return(1);
838
839	return(0);
840}
841
842static int
843eqn_do_define(struct eqn_node *ep)
844{
845	const char	*start;
846	size_t		 sz;
847	struct eqn_def	*def;
848	int		 i;
849
850	if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
851		EQN_MSG(MANDOCERR_EQNEOF, ep);
852		return(0);
853	}
854
855	/*
856	 * Search for a key that already exists.
857	 * Create a new key if none is found.
858	 */
859
860	if (NULL == (def = eqn_def_find(ep, start, sz))) {
861		/* Find holes in string array. */
862		for (i = 0; i < (int)ep->defsz; i++)
863			if (0 == ep->defs[i].keysz)
864				break;
865
866		if (i == (int)ep->defsz) {
867			ep->defsz++;
868			ep->defs = mandoc_realloc
869				(ep->defs, ep->defsz *
870				 sizeof(struct eqn_def));
871			ep->defs[i].key = ep->defs[i].val = NULL;
872		}
873
874		ep->defs[i].keysz = sz;
875		ep->defs[i].key = mandoc_realloc
876			(ep->defs[i].key, sz + 1);
877
878		memcpy(ep->defs[i].key, start, sz);
879		ep->defs[i].key[(int)sz] = '\0';
880		def = &ep->defs[i];
881	}
882
883	start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
884
885	if (NULL == start) {
886		EQN_MSG(MANDOCERR_EQNEOF, ep);
887		return(0);
888	}
889
890	def->valsz = sz;
891	def->val = mandoc_realloc(def->val, sz + 1);
892	memcpy(def->val, start, sz);
893	def->val[(int)sz] = '\0';
894	return(1);
895}
896
897static int
898eqn_do_gfont(struct eqn_node *ep)
899{
900
901	if (NULL == eqn_nextrawtok(ep, NULL)) {
902		EQN_MSG(MANDOCERR_EQNEOF, ep);
903		return(0);
904	}
905	return(1);
906}
907
908static int
909eqn_do_gsize(struct eqn_node *ep)
910{
911	const char	*start;
912	size_t		 sz;
913
914	if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
915		EQN_MSG(MANDOCERR_EQNEOF, ep);
916		return(0);
917	}
918	ep->gsize = mandoc_strntoi(start, sz, 10);
919	return(1);
920}
921
922static int
923eqn_do_undef(struct eqn_node *ep)
924{
925	const char	*start;
926	struct eqn_def	*def;
927	size_t		 sz;
928
929	if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
930		EQN_MSG(MANDOCERR_EQNEOF, ep);
931		return(0);
932	} else if (NULL != (def = eqn_def_find(ep, start, sz)))
933		def->keysz = 0;
934
935	return(1);
936}
937
938static struct eqn_def *
939eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
940{
941	int		 i;
942
943	for (i = 0; i < (int)ep->defsz; i++)
944		if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
945					ep->defs[i].keysz, key, sz))
946			return(&ep->defs[i]);
947
948	return(NULL);
949}
950