installer - Several improvements
[dragonfly.git] / contrib / mdocml / eqn.c
1 /*      $Id: eqn.c,v 1.44 2014/07/06 19:09:00 schwarze 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 "mandoc_aux.h"
30 #include "libmandoc.h"
31 #include "libroff.h"
32
33 #define EQN_NEST_MAX     128 /* maximum nesting of defines */
34 #define EQN_MSG(t, x)    mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
35
36 enum    eqn_rest {
37         EQN_DESCOPE,
38         EQN_ERR,
39         EQN_OK,
40         EQN_EOF
41 };
42
43 enum    eqn_symt {
44         EQNSYM_alpha,
45         EQNSYM_beta,
46         EQNSYM_chi,
47         EQNSYM_delta,
48         EQNSYM_epsilon,
49         EQNSYM_eta,
50         EQNSYM_gamma,
51         EQNSYM_iota,
52         EQNSYM_kappa,
53         EQNSYM_lambda,
54         EQNSYM_mu,
55         EQNSYM_nu,
56         EQNSYM_omega,
57         EQNSYM_omicron,
58         EQNSYM_phi,
59         EQNSYM_pi,
60         EQNSYM_ps,
61         EQNSYM_rho,
62         EQNSYM_sigma,
63         EQNSYM_tau,
64         EQNSYM_theta,
65         EQNSYM_upsilon,
66         EQNSYM_xi,
67         EQNSYM_zeta,
68         EQNSYM_DELTA,
69         EQNSYM_GAMMA,
70         EQNSYM_LAMBDA,
71         EQNSYM_OMEGA,
72         EQNSYM_PHI,
73         EQNSYM_PI,
74         EQNSYM_PSI,
75         EQNSYM_SIGMA,
76         EQNSYM_THETA,
77         EQNSYM_UPSILON,
78         EQNSYM_XI,
79         EQNSYM_inter,
80         EQNSYM_union,
81         EQNSYM_prod,
82         EQNSYM_int,
83         EQNSYM_sum,
84         EQNSYM_grad,
85         EQNSYM_del,
86         EQNSYM_times,
87         EQNSYM_cdot,
88         EQNSYM_nothing,
89         EQNSYM_approx,
90         EQNSYM_prime,
91         EQNSYM_half,
92         EQNSYM_partial,
93         EQNSYM_inf,
94         EQNSYM_muchgreat,
95         EQNSYM_muchless,
96         EQNSYM_larrow,
97         EQNSYM_rarrow,
98         EQNSYM_pm,
99         EQNSYM_nequal,
100         EQNSYM_equiv,
101         EQNSYM_lessequal,
102         EQNSYM_moreequal,
103         EQNSYM__MAX
104 };
105
106 enum    eqnpartt {
107         EQN_DEFINE = 0,
108         EQN_NDEFINE,
109         EQN_TDEFINE,
110         EQN_SET,
111         EQN_UNDEF,
112         EQN_GFONT,
113         EQN_GSIZE,
114         EQN_BACK,
115         EQN_FWD,
116         EQN_UP,
117         EQN_DOWN,
118         EQN__MAX
119 };
120
121 struct  eqnstr {
122         const char      *name;
123         size_t           sz;
124 };
125
126 #define STRNEQ(p1, sz1, p2, sz2) \
127         ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
128 #define EQNSTREQ(x, p, sz) \
129         STRNEQ((x)->name, (x)->sz, (p), (sz))
130
131 struct  eqnpart {
132         struct eqnstr    str;
133         int             (*fp)(struct eqn_node *);
134 };
135
136 struct  eqnsym {
137         struct eqnstr    str;
138         const char      *sym;
139 };
140
141 static  enum eqn_rest    eqn_box(struct eqn_node *, struct eqn_box *);
142 static  struct eqn_box  *eqn_box_alloc(struct eqn_node *,
143                                 struct eqn_box *);
144 static  void             eqn_box_free(struct eqn_box *);
145 static  struct eqn_def  *eqn_def_find(struct eqn_node *,
146                                 const char *, size_t);
147 static  int              eqn_do_gfont(struct eqn_node *);
148 static  int              eqn_do_gsize(struct eqn_node *);
149 static  int              eqn_do_define(struct eqn_node *);
150 static  int              eqn_do_ign1(struct eqn_node *);
151 static  int              eqn_do_ign2(struct eqn_node *);
152 static  int              eqn_do_tdefine(struct eqn_node *);
153 static  int              eqn_do_undef(struct eqn_node *);
154 static  enum eqn_rest    eqn_eqn(struct eqn_node *, struct eqn_box *);
155 static  enum eqn_rest    eqn_list(struct eqn_node *, struct eqn_box *);
156 static  enum eqn_rest    eqn_matrix(struct eqn_node *, struct eqn_box *);
157 static  const char      *eqn_nexttok(struct eqn_node *, size_t *);
158 static  const char      *eqn_nextrawtok(struct eqn_node *, size_t *);
159 static  const char      *eqn_next(struct eqn_node *,
160                                 char, size_t *, int);
161 static  void             eqn_rewind(struct eqn_node *);
162
163 static  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
177 static  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
189 static  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
197 static  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
206 static  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
218 static  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
281 enum rofferr
282 eqn_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_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
304                     ln, pos, "EN %s", p);
305                 return(er);
306         }
307
308         /*
309          * Build up the full string, replacing all newlines with regular
310          * whitespace.
311          */
312
313         sz = strlen(p + pos) + 1;
314         ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
315
316         /* First invocation: nil terminate the string. */
317
318         if (0 == ep->sz)
319                 *ep->data = '\0';
320
321         ep->sz += sz;
322         strlcat(ep->data, p + pos, ep->sz + 1);
323         strlcat(ep->data, " ", ep->sz + 1);
324         return(ROFF_IGN);
325 }
326
327 struct eqn_node *
328 eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
329 {
330         struct eqn_node *p;
331         size_t           sz;
332         const char      *end;
333
334         p = mandoc_calloc(1, sizeof(struct eqn_node));
335
336         if (name && '\0' != *name) {
337                 sz = strlen(name);
338                 assert(sz);
339                 do {
340                         sz--;
341                         end = name + (int)sz;
342                 } while (' ' == *end || '\t' == *end);
343                 p->eqn.name = mandoc_strndup(name, sz + 1);
344         }
345
346         p->parse = parse;
347         p->eqn.ln = line;
348         p->eqn.pos = pos;
349         p->gsize = EQN_DEFSIZE;
350
351         return(p);
352 }
353
354 enum rofferr
355 eqn_end(struct eqn_node **epp)
356 {
357         struct eqn_node *ep;
358         struct eqn_box  *root;
359         enum eqn_rest    c;
360
361         ep = *epp;
362         *epp = NULL;
363
364         ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
365
366         root = ep->eqn.root;
367         root->type = EQN_ROOT;
368
369         if (0 == ep->sz)
370                 return(ROFF_IGN);
371
372         if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
373                 EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
374                 c = EQN_ERR;
375         }
376
377         return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
378 }
379
380 static enum eqn_rest
381 eqn_eqn(struct eqn_node *ep, struct eqn_box *last)
382 {
383         struct eqn_box  *bp;
384         enum eqn_rest    c;
385
386         bp = eqn_box_alloc(ep, last);
387         bp->type = EQN_SUBEXPR;
388
389         while (EQN_OK == (c = eqn_box(ep, bp)))
390                 /* Spin! */ ;
391
392         return(c);
393 }
394
395 static enum eqn_rest
396 eqn_matrix(struct eqn_node *ep, struct eqn_box *last)
397 {
398         struct eqn_box  *bp;
399         const char      *start;
400         size_t           sz;
401         enum eqn_rest    c;
402
403         bp = eqn_box_alloc(ep, last);
404         bp->type = EQN_MATRIX;
405
406         if (NULL == (start = eqn_nexttok(ep, &sz))) {
407                 EQN_MSG(MANDOCERR_EQNEOF, ep);
408                 return(EQN_ERR);
409         }
410         if ( ! STRNEQ(start, sz, "{", 1)) {
411                 EQN_MSG(MANDOCERR_EQNSYNT, ep);
412                 return(EQN_ERR);
413         }
414
415         while (EQN_OK == (c = eqn_box(ep, bp)))
416                 switch (bp->last->pile) {
417                 case EQNPILE_LCOL:
418                         /* FALLTHROUGH */
419                 case EQNPILE_CCOL:
420                         /* FALLTHROUGH */
421                 case EQNPILE_RCOL:
422                         continue;
423                 default:
424                         EQN_MSG(MANDOCERR_EQNSYNT, ep);
425                         return(EQN_ERR);
426                 };
427
428         if (EQN_DESCOPE != c) {
429                 if (EQN_EOF == c)
430                         EQN_MSG(MANDOCERR_EQNEOF, ep);
431                 return(EQN_ERR);
432         }
433
434         eqn_rewind(ep);
435         start = eqn_nexttok(ep, &sz);
436         assert(start);
437         if (STRNEQ(start, sz, "}", 1))
438                 return(EQN_OK);
439
440         EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
441         return(EQN_ERR);
442 }
443
444 static enum eqn_rest
445 eqn_list(struct eqn_node *ep, struct eqn_box *last)
446 {
447         struct eqn_box  *bp;
448         const char      *start;
449         size_t           sz;
450         enum eqn_rest    c;
451
452         bp = eqn_box_alloc(ep, last);
453         bp->type = EQN_LIST;
454
455         if (NULL == (start = eqn_nexttok(ep, &sz))) {
456                 EQN_MSG(MANDOCERR_EQNEOF, ep);
457                 return(EQN_ERR);
458         }
459         if ( ! STRNEQ(start, sz, "{", 1)) {
460                 EQN_MSG(MANDOCERR_EQNSYNT, ep);
461                 return(EQN_ERR);
462         }
463
464         while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) {
465                 eqn_rewind(ep);
466                 start = eqn_nexttok(ep, &sz);
467                 assert(start);
468                 if ( ! STRNEQ(start, sz, "above", 5))
469                         break;
470         }
471
472         if (EQN_DESCOPE != c) {
473                 if (EQN_ERR != c)
474                         EQN_MSG(MANDOCERR_EQNSCOPE, ep);
475                 return(EQN_ERR);
476         }
477
478         eqn_rewind(ep);
479         start = eqn_nexttok(ep, &sz);
480         assert(start);
481         if (STRNEQ(start, sz, "}", 1))
482                 return(EQN_OK);
483
484         EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
485         return(EQN_ERR);
486 }
487
488 static enum eqn_rest
489 eqn_box(struct eqn_node *ep, struct eqn_box *last)
490 {
491         size_t           sz;
492         const char      *start;
493         char            *left;
494         char             sym[64];
495         enum eqn_rest    c;
496         int              i, size;
497         struct eqn_box  *bp;
498
499         if (NULL == (start = eqn_nexttok(ep, &sz)))
500                 return(EQN_EOF);
501
502         if (STRNEQ(start, sz, "}", 1))
503                 return(EQN_DESCOPE);
504         else if (STRNEQ(start, sz, "right", 5))
505                 return(EQN_DESCOPE);
506         else if (STRNEQ(start, sz, "above", 5))
507                 return(EQN_DESCOPE);
508         else if (STRNEQ(start, sz, "mark", 4))
509                 return(EQN_OK);
510         else if (STRNEQ(start, sz, "lineup", 6))
511                 return(EQN_OK);
512
513         for (i = 0; i < (int)EQN__MAX; i++) {
514                 if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
515                         continue;
516                 return((*eqnparts[i].fp)(ep) ? 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                         (void)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
641 void
642 eqn_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
659 static struct eqn_box *
660 eqn_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
677 static void
678 eqn_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
692 static const char *
693 eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
694 {
695
696         return(eqn_next(ep, '"', sz, 0));
697 }
698
699 static const char *
700 eqn_nexttok(struct eqn_node *ep, size_t *sz)
701 {
702
703         return(eqn_next(ep, '"', sz, 1));
704 }
705
706 static void
707 eqn_rewind(struct eqn_node *ep)
708 {
709
710         ep->cur = ep->rew;
711 }
712
713 static const char *
714 eqn_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;
726 again:
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_ARG_QUOTE, 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
802 static int
803 eqn_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
814 static int
815 eqn_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
828 static int
829 eqn_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
842 static int
843 eqn_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_reallocarray(ep->defs,
869                             ep->defsz, sizeof(struct eqn_def));
870                         ep->defs[i].key = ep->defs[i].val = NULL;
871                 }
872
873                 ep->defs[i].keysz = sz;
874                 ep->defs[i].key = mandoc_realloc(
875                     ep->defs[i].key, sz + 1);
876
877                 memcpy(ep->defs[i].key, start, sz);
878                 ep->defs[i].key[(int)sz] = '\0';
879                 def = &ep->defs[i];
880         }
881
882         start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
883
884         if (NULL == start) {
885                 EQN_MSG(MANDOCERR_EQNEOF, ep);
886                 return(0);
887         }
888
889         def->valsz = sz;
890         def->val = mandoc_realloc(def->val, sz + 1);
891         memcpy(def->val, start, sz);
892         def->val[(int)sz] = '\0';
893         return(1);
894 }
895
896 static int
897 eqn_do_gfont(struct eqn_node *ep)
898 {
899
900         if (NULL == eqn_nextrawtok(ep, NULL)) {
901                 EQN_MSG(MANDOCERR_EQNEOF, ep);
902                 return(0);
903         }
904         return(1);
905 }
906
907 static int
908 eqn_do_gsize(struct eqn_node *ep)
909 {
910         const char      *start;
911         size_t           sz;
912
913         if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
914                 EQN_MSG(MANDOCERR_EQNEOF, ep);
915                 return(0);
916         }
917         ep->gsize = mandoc_strntoi(start, sz, 10);
918         return(1);
919 }
920
921 static int
922 eqn_do_undef(struct eqn_node *ep)
923 {
924         const char      *start;
925         struct eqn_def  *def;
926         size_t           sz;
927
928         if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
929                 EQN_MSG(MANDOCERR_EQNEOF, ep);
930                 return(0);
931         } else if (NULL != (def = eqn_def_find(ep, start, sz)))
932                 def->keysz = 0;
933
934         return(1);
935 }
936
937 static struct eqn_def *
938 eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
939 {
940         int              i;
941
942         for (i = 0; i < (int)ep->defsz; i++)
943                 if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
944                     ep->defs[i].keysz, key, sz))
945                         return(&ep->defs[i]);
946
947         return(NULL);
948 }