]> git.cameronkatri.com Git - mandoc.git/blob - eqn.c
Make eqn tree output a bit more useful.
[mandoc.git] / eqn.c
1 /* $Id: eqn.c,v 1.46 2014/09/28 11:32:08 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 #include "config.h"
18
19 #include <sys/types.h>
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 { NULL, 0 }, /* EQNPOS_SUPSUB */
202 { "sub", 3 }, /* EQNPOS_SUB */
203 { "to", 2 }, /* EQNPOS_TO */
204 { "from", 4 }, /* EQNPOS_FROM */
205 };
206
207 static const struct eqnstr eqnpiles[EQNPILE__MAX] = {
208 { "", 0 }, /* EQNPILE_NONE */
209 { "pile", 4 }, /* EQNPILE_PILE */
210 { "cpile", 5 }, /* EQNPILE_CPILE */
211 { "rpile", 5 }, /* EQNPILE_RPILE */
212 { "lpile", 5 }, /* EQNPILE_LPILE */
213 { "col", 3 }, /* EQNPILE_COL */
214 { "ccol", 4 }, /* EQNPILE_CCOL */
215 { "rcol", 4 }, /* EQNPILE_RCOL */
216 { "lcol", 4 }, /* EQNPILE_LCOL */
217 };
218
219 static const struct eqnsym eqnsyms[EQNSYM__MAX] = {
220 { { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */
221 { { "beta", 4 }, "*b" }, /* EQNSYM_beta */
222 { { "chi", 3 }, "*x" }, /* EQNSYM_chi */
223 { { "delta", 5 }, "*d" }, /* EQNSYM_delta */
224 { { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */
225 { { "eta", 3 }, "*y" }, /* EQNSYM_eta */
226 { { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */
227 { { "iota", 4 }, "*i" }, /* EQNSYM_iota */
228 { { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */
229 { { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */
230 { { "mu", 2 }, "*m" }, /* EQNSYM_mu */
231 { { "nu", 2 }, "*n" }, /* EQNSYM_nu */
232 { { "omega", 5 }, "*w" }, /* EQNSYM_omega */
233 { { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */
234 { { "phi", 3 }, "*f" }, /* EQNSYM_phi */
235 { { "pi", 2 }, "*p" }, /* EQNSYM_pi */
236 { { "psi", 2 }, "*q" }, /* EQNSYM_psi */
237 { { "rho", 3 }, "*r" }, /* EQNSYM_rho */
238 { { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */
239 { { "tau", 3 }, "*t" }, /* EQNSYM_tau */
240 { { "theta", 5 }, "*h" }, /* EQNSYM_theta */
241 { { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */
242 { { "xi", 2 }, "*c" }, /* EQNSYM_xi */
243 { { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */
244 { { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */
245 { { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */
246 { { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */
247 { { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */
248 { { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */
249 { { "PI", 2 }, "*P" }, /* EQNSYM_PI */
250 { { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */
251 { { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */
252 { { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */
253 { { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */
254 { { "XI", 2 }, "*C" }, /* EQNSYM_XI */
255 { { "inter", 5 }, "ca" }, /* EQNSYM_inter */
256 { { "union", 5 }, "cu" }, /* EQNSYM_union */
257 { { "prod", 4 }, "product" }, /* EQNSYM_prod */
258 { { "int", 3 }, "integral" }, /* EQNSYM_int */
259 { { "sum", 3 }, "sum" }, /* EQNSYM_sum */
260 { { "grad", 4 }, "gr" }, /* EQNSYM_grad */
261 { { "del", 3 }, "gr" }, /* EQNSYM_del */
262 { { "times", 5 }, "mu" }, /* EQNSYM_times */
263 { { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */
264 { { "nothing", 7 }, "&" }, /* EQNSYM_nothing */
265 { { "approx", 6 }, "~~" }, /* EQNSYM_approx */
266 { { "prime", 5 }, "aq" }, /* EQNSYM_prime */
267 { { "half", 4 }, "12" }, /* EQNSYM_half */
268 { { "partial", 7 }, "pd" }, /* EQNSYM_partial */
269 { { "inf", 3 }, "if" }, /* EQNSYM_inf */
270 { { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */
271 { { "<<", 2 }, "<<" }, /* EQNSYM_muchless */
272 { { "<-", 2 }, "<-" }, /* EQNSYM_larrow */
273 { { "->", 2 }, "->" }, /* EQNSYM_rarrow */
274 { { "+-", 2 }, "+-" }, /* EQNSYM_pm */
275 { { "!=", 2 }, "!=" }, /* EQNSYM_nequal */
276 { { "==", 2 }, "==" }, /* EQNSYM_equiv */
277 { { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */
278 { { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */
279 };
280
281
282 enum rofferr
283 eqn_read(struct eqn_node **epp, int ln,
284 const char *p, int pos, int *offs)
285 {
286 size_t sz;
287 struct eqn_node *ep;
288 enum rofferr er;
289
290 ep = *epp;
291
292 /*
293 * If we're the terminating mark, unset our equation status and
294 * validate the full equation.
295 */
296
297 if (0 == strncmp(p, ".EN", 3)) {
298 er = eqn_end(epp);
299 p += 3;
300 while (' ' == *p || '\t' == *p)
301 p++;
302 if ('\0' == *p)
303 return(er);
304 mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse,
305 ln, pos, "EN %s", p);
306 return(er);
307 }
308
309 /*
310 * Build up the full string, replacing all newlines with regular
311 * whitespace.
312 */
313
314 sz = strlen(p + pos) + 1;
315 ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
316
317 /* First invocation: nil terminate the string. */
318
319 if (0 == ep->sz)
320 *ep->data = '\0';
321
322 ep->sz += sz;
323 strlcat(ep->data, p + pos, ep->sz + 1);
324 strlcat(ep->data, " ", ep->sz + 1);
325 return(ROFF_IGN);
326 }
327
328 struct eqn_node *
329 eqn_alloc(const char *name, int pos, int line, struct mparse *parse)
330 {
331 struct eqn_node *p;
332 size_t sz;
333 const char *end;
334
335 p = mandoc_calloc(1, sizeof(struct eqn_node));
336
337 if (name && '\0' != *name) {
338 sz = strlen(name);
339 assert(sz);
340 do {
341 sz--;
342 end = name + (int)sz;
343 } while (' ' == *end || '\t' == *end);
344 p->eqn.name = mandoc_strndup(name, sz + 1);
345 }
346
347 p->parse = parse;
348 p->eqn.ln = line;
349 p->eqn.pos = pos;
350 p->gsize = EQN_DEFSIZE;
351
352 return(p);
353 }
354
355 enum rofferr
356 eqn_end(struct eqn_node **epp)
357 {
358 struct eqn_node *ep;
359 struct eqn_box *root;
360 enum eqn_rest c;
361
362 ep = *epp;
363 *epp = NULL;
364
365 ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
366
367 root = ep->eqn.root;
368 root->type = EQN_ROOT;
369
370 if (0 == ep->sz)
371 return(ROFF_IGN);
372
373 if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
374 EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
375 c = EQN_ERR;
376 }
377
378 return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
379 }
380
381 static enum eqn_rest
382 eqn_eqn(struct eqn_node *ep, struct eqn_box *last)
383 {
384 struct eqn_box *bp;
385 enum eqn_rest c;
386
387 bp = eqn_box_alloc(ep, last);
388 bp->type = EQN_SUBEXPR;
389
390 while (EQN_OK == (c = eqn_box(ep, bp)))
391 /* Spin! */ ;
392
393 return(c);
394 }
395
396 static enum eqn_rest
397 eqn_matrix(struct eqn_node *ep, struct eqn_box *last)
398 {
399 struct eqn_box *bp;
400 const char *start;
401 size_t sz;
402 enum eqn_rest c;
403
404 bp = eqn_box_alloc(ep, last);
405 bp->type = EQN_MATRIX;
406
407 if (NULL == (start = eqn_nexttok(ep, &sz))) {
408 EQN_MSG(MANDOCERR_EQNEOF, ep);
409 return(EQN_ERR);
410 }
411 if ( ! STRNEQ(start, sz, "{", 1)) {
412 EQN_MSG(MANDOCERR_EQNSYNT, ep);
413 return(EQN_ERR);
414 }
415
416 while (EQN_OK == (c = eqn_box(ep, bp)))
417 switch (bp->last->pile) {
418 case EQNPILE_LCOL:
419 /* FALLTHROUGH */
420 case EQNPILE_CCOL:
421 /* FALLTHROUGH */
422 case EQNPILE_RCOL:
423 continue;
424 default:
425 EQN_MSG(MANDOCERR_EQNSYNT, ep);
426 return(EQN_ERR);
427 };
428
429 if (EQN_DESCOPE != c) {
430 if (EQN_EOF == c)
431 EQN_MSG(MANDOCERR_EQNEOF, ep);
432 return(EQN_ERR);
433 }
434
435 eqn_rewind(ep);
436 start = eqn_nexttok(ep, &sz);
437 assert(start);
438 if (STRNEQ(start, sz, "}", 1))
439 return(EQN_OK);
440
441 EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
442 return(EQN_ERR);
443 }
444
445 static enum eqn_rest
446 eqn_list(struct eqn_node *ep, struct eqn_box *last)
447 {
448 struct eqn_box *bp;
449 const char *start;
450 size_t sz;
451 enum eqn_rest c;
452
453 bp = eqn_box_alloc(ep, last);
454 bp->type = EQN_LIST;
455
456 if (NULL == (start = eqn_nexttok(ep, &sz))) {
457 EQN_MSG(MANDOCERR_EQNEOF, ep);
458 return(EQN_ERR);
459 }
460 if ( ! STRNEQ(start, sz, "{", 1)) {
461 EQN_MSG(MANDOCERR_EQNSYNT, ep);
462 return(EQN_ERR);
463 }
464
465 while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) {
466 eqn_rewind(ep);
467 start = eqn_nexttok(ep, &sz);
468 assert(start);
469 if ( ! STRNEQ(start, sz, "above", 5))
470 break;
471 }
472
473 if (EQN_DESCOPE != c) {
474 if (EQN_ERR != c)
475 EQN_MSG(MANDOCERR_EQNSCOPE, ep);
476 return(EQN_ERR);
477 }
478
479 eqn_rewind(ep);
480 start = eqn_nexttok(ep, &sz);
481 assert(start);
482 if (STRNEQ(start, sz, "}", 1))
483 return(EQN_OK);
484
485 EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
486 return(EQN_ERR);
487 }
488
489 static enum eqn_rest
490 eqn_box(struct eqn_node *ep, struct eqn_box *last)
491 {
492 size_t sz;
493 const char *start;
494 char *left;
495 char sym[64];
496 enum eqn_rest c;
497 int i, size;
498 struct eqn_box *bp;
499
500 if (NULL == (start = eqn_nexttok(ep, &sz)))
501 return(EQN_EOF);
502
503 if (STRNEQ(start, sz, "}", 1))
504 return(EQN_DESCOPE);
505 else if (STRNEQ(start, sz, "right", 5))
506 return(EQN_DESCOPE);
507 else if (STRNEQ(start, sz, "above", 5))
508 return(EQN_DESCOPE);
509 else if (STRNEQ(start, sz, "mark", 4))
510 return(EQN_OK);
511 else if (STRNEQ(start, sz, "lineup", 6))
512 return(EQN_OK);
513
514 for (i = 0; i < (int)EQN__MAX; i++) {
515 if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
516 continue;
517 return((*eqnparts[i].fp)(ep) ? EQN_OK : EQN_ERR);
518 }
519
520 if (STRNEQ(start, sz, "{", 1)) {
521 if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
522 if (EQN_ERR != c)
523 EQN_MSG(MANDOCERR_EQNSCOPE, ep);
524 return(EQN_ERR);
525 }
526 eqn_rewind(ep);
527 start = eqn_nexttok(ep, &sz);
528 assert(start);
529 if (STRNEQ(start, sz, "}", 1))
530 return(EQN_OK);
531 EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
532 return(EQN_ERR);
533 }
534
535 for (i = 0; i < (int)EQNPILE__MAX; i++) {
536 if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
537 continue;
538 if (EQN_OK == (c = eqn_list(ep, last)))
539 last->last->pile = (enum eqn_pilet)i;
540 return(c);
541 }
542
543 if (STRNEQ(start, sz, "matrix", 6))
544 return(eqn_matrix(ep, last));
545
546 if (STRNEQ(start, sz, "left", 4)) {
547 if (NULL == (start = eqn_nexttok(ep, &sz))) {
548 EQN_MSG(MANDOCERR_EQNEOF, ep);
549 return(EQN_ERR);
550 }
551 left = mandoc_strndup(start, sz);
552 c = eqn_eqn(ep, last);
553 if (last->last)
554 last->last->left = left;
555 else
556 free(left);
557 if (EQN_DESCOPE != c)
558 return(c);
559 assert(last->last);
560 eqn_rewind(ep);
561 start = eqn_nexttok(ep, &sz);
562 assert(start);
563 if ( ! STRNEQ(start, sz, "right", 5))
564 return(EQN_DESCOPE);
565 if (NULL == (start = eqn_nexttok(ep, &sz))) {
566 EQN_MSG(MANDOCERR_EQNEOF, ep);
567 return(EQN_ERR);
568 }
569 last->last->right = mandoc_strndup(start, sz);
570 return(EQN_OK);
571 }
572
573 /*
574 * Positional elements (e.g., over, sub, sup, ...).
575 */
576 for (i = 0; i < (int)EQNPOS__MAX; i++) {
577 /* Some elements don't have names (are virtual). */
578 if (NULL == eqnposs[i].name)
579 continue;
580 else if ( ! EQNSTREQ(&eqnposs[i], start, sz))
581 continue;
582 if (NULL == last->last) {
583 EQN_MSG(MANDOCERR_EQNSYNT, ep);
584 return(EQN_ERR);
585 }
586 /*
587 * If we encounter x sub y sup z, then according to the
588 * eqn manual, we regard this as x subsup y z.
589 */
590 if (EQNPOS_SUP == i &&
591 NULL != last->last->prev &&
592 EQNPOS_SUB == last->last->prev->pos)
593 last->last->prev->pos = EQNPOS_SUBSUP;
594 else
595 last->last->pos = (enum eqn_post)i;
596
597 if (EQN_EOF == (c = eqn_box(ep, last))) {
598 EQN_MSG(MANDOCERR_EQNEOF, ep);
599 return(EQN_ERR);
600 }
601 return(c);
602 }
603
604 for (i = 0; i < (int)EQNMARK__MAX; i++) {
605 if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
606 continue;
607 if (NULL == last->last) {
608 EQN_MSG(MANDOCERR_EQNSYNT, ep);
609 return(EQN_ERR);
610 }
611 last->last->mark = (enum eqn_markt)i;
612 if (EQN_EOF == (c = eqn_box(ep, last))) {
613 EQN_MSG(MANDOCERR_EQNEOF, ep);
614 return(EQN_ERR);
615 }
616 return(c);
617 }
618
619 for (i = 0; i < (int)EQNFONT__MAX; i++) {
620 if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
621 continue;
622 if (EQN_EOF == (c = eqn_box(ep, last))) {
623 EQN_MSG(MANDOCERR_EQNEOF, ep);
624 return(EQN_ERR);
625 } else if (EQN_OK == c)
626 last->last->font = (enum eqn_fontt)i;
627 return(c);
628 }
629
630 if (STRNEQ(start, sz, "size", 4)) {
631 if (NULL == (start = eqn_nexttok(ep, &sz))) {
632 EQN_MSG(MANDOCERR_EQNEOF, ep);
633 return(EQN_ERR);
634 }
635 size = mandoc_strntoi(start, sz, 10);
636 if (EQN_EOF == (c = eqn_box(ep, last))) {
637 EQN_MSG(MANDOCERR_EQNEOF, ep);
638 return(EQN_ERR);
639 } else if (EQN_OK != c)
640 return(c);
641 last->last->size = size;
642 }
643
644 bp = eqn_box_alloc(ep, last);
645 bp->type = EQN_TEXT;
646 for (i = 0; i < (int)EQNSYM__MAX; i++)
647 if (EQNSTREQ(&eqnsyms[i].str, start, sz)) {
648 sym[63] = '\0';
649 (void)snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym);
650 bp->text = mandoc_strdup(sym);
651 return(EQN_OK);
652 }
653
654 bp->text = mandoc_strndup(start, sz);
655 return(EQN_OK);
656 }
657
658 void
659 eqn_free(struct eqn_node *p)
660 {
661 int i;
662
663 eqn_box_free(p->eqn.root);
664
665 for (i = 0; i < (int)p->defsz; i++) {
666 free(p->defs[i].key);
667 free(p->defs[i].val);
668 }
669
670 free(p->eqn.name);
671 free(p->data);
672 free(p->defs);
673 free(p);
674 }
675
676 static struct eqn_box *
677 eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent)
678 {
679 struct eqn_box *bp;
680
681 bp = mandoc_calloc(1, sizeof(struct eqn_box));
682 bp->parent = parent;
683 bp->size = ep->gsize;
684
685 if (NULL != parent->first) {
686 parent->last->next = bp;
687 bp->prev = parent->last;
688 } else
689 parent->first = bp;
690
691 parent->last = bp;
692 return(bp);
693 }
694
695 static void
696 eqn_box_free(struct eqn_box *bp)
697 {
698
699 if (bp->first)
700 eqn_box_free(bp->first);
701 if (bp->next)
702 eqn_box_free(bp->next);
703
704 free(bp->text);
705 free(bp->left);
706 free(bp->right);
707 free(bp);
708 }
709
710 static const char *
711 eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
712 {
713
714 return(eqn_next(ep, '"', sz, 0));
715 }
716
717 static const char *
718 eqn_nexttok(struct eqn_node *ep, size_t *sz)
719 {
720
721 return(eqn_next(ep, '"', sz, 1));
722 }
723
724 static void
725 eqn_rewind(struct eqn_node *ep)
726 {
727
728 ep->cur = ep->rew;
729 }
730
731 static const char *
732 eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
733 {
734 char *start, *next;
735 int q, diff, lim;
736 size_t ssz, dummy;
737 struct eqn_def *def;
738
739 if (NULL == sz)
740 sz = &dummy;
741
742 lim = 0;
743 ep->rew = ep->cur;
744 again:
745 /* Prevent self-definitions. */
746
747 if (lim >= EQN_NEST_MAX) {
748 EQN_MSG(MANDOCERR_ROFFLOOP, ep);
749 return(NULL);
750 }
751
752 ep->cur = ep->rew;
753 start = &ep->data[(int)ep->cur];
754 q = 0;
755
756 if ('\0' == *start)
757 return(NULL);
758
759 if (quote == *start) {
760 ep->cur++;
761 q = 1;
762 }
763
764 start = &ep->data[(int)ep->cur];
765
766 if ( ! q) {
767 if ('{' == *start || '}' == *start)
768 ssz = 1;
769 else
770 ssz = strcspn(start + 1, " ^~\"{}\t") + 1;
771 next = start + (int)ssz;
772 if ('\0' == *next)
773 next = NULL;
774 } else
775 next = strchr(start, quote);
776
777 if (NULL != next) {
778 *sz = (size_t)(next - start);
779 ep->cur += *sz;
780 if (q)
781 ep->cur++;
782 while (' ' == ep->data[(int)ep->cur] ||
783 '\t' == ep->data[(int)ep->cur] ||
784 '^' == ep->data[(int)ep->cur] ||
785 '~' == ep->data[(int)ep->cur])
786 ep->cur++;
787 } else {
788 if (q)
789 EQN_MSG(MANDOCERR_ARG_QUOTE, ep);
790 next = strchr(start, '\0');
791 *sz = (size_t)(next - start);
792 ep->cur += *sz;
793 }
794
795 /* Quotes aren't expanded for values. */
796
797 if (q || ! repl)
798 return(start);
799
800 if (NULL != (def = eqn_def_find(ep, start, *sz))) {
801 diff = def->valsz - *sz;
802
803 if (def->valsz > *sz) {
804 ep->sz += diff;
805 ep->data = mandoc_realloc(ep->data, ep->sz + 1);
806 ep->data[ep->sz] = '\0';
807 start = &ep->data[(int)ep->rew];
808 }
809
810 diff = def->valsz - *sz;
811 memmove(start + *sz + diff, start + *sz,
812 (strlen(start) - *sz) + 1);
813 memcpy(start, def->val, def->valsz);
814 goto again;
815 }
816
817 return(start);
818 }
819
820 static int
821 eqn_do_ign1(struct eqn_node *ep)
822 {
823
824 if (NULL == eqn_nextrawtok(ep, NULL))
825 EQN_MSG(MANDOCERR_EQNEOF, ep);
826 else
827 return(1);
828
829 return(0);
830 }
831
832 static int
833 eqn_do_ign2(struct eqn_node *ep)
834 {
835
836 if (NULL == eqn_nextrawtok(ep, NULL))
837 EQN_MSG(MANDOCERR_EQNEOF, ep);
838 else if (NULL == eqn_nextrawtok(ep, NULL))
839 EQN_MSG(MANDOCERR_EQNEOF, ep);
840 else
841 return(1);
842
843 return(0);
844 }
845
846 static int
847 eqn_do_tdefine(struct eqn_node *ep)
848 {
849
850 if (NULL == eqn_nextrawtok(ep, NULL))
851 EQN_MSG(MANDOCERR_EQNEOF, ep);
852 else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0))
853 EQN_MSG(MANDOCERR_EQNEOF, ep);
854 else
855 return(1);
856
857 return(0);
858 }
859
860 static int
861 eqn_do_define(struct eqn_node *ep)
862 {
863 const char *start;
864 size_t sz;
865 struct eqn_def *def;
866 int i;
867
868 if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
869 EQN_MSG(MANDOCERR_EQNEOF, ep);
870 return(0);
871 }
872
873 /*
874 * Search for a key that already exists.
875 * Create a new key if none is found.
876 */
877
878 if (NULL == (def = eqn_def_find(ep, start, sz))) {
879 /* Find holes in string array. */
880 for (i = 0; i < (int)ep->defsz; i++)
881 if (0 == ep->defs[i].keysz)
882 break;
883
884 if (i == (int)ep->defsz) {
885 ep->defsz++;
886 ep->defs = mandoc_reallocarray(ep->defs,
887 ep->defsz, sizeof(struct eqn_def));
888 ep->defs[i].key = ep->defs[i].val = NULL;
889 }
890
891 ep->defs[i].keysz = sz;
892 ep->defs[i].key = mandoc_realloc(
893 ep->defs[i].key, sz + 1);
894
895 memcpy(ep->defs[i].key, start, sz);
896 ep->defs[i].key[(int)sz] = '\0';
897 def = &ep->defs[i];
898 }
899
900 start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
901
902 if (NULL == start) {
903 EQN_MSG(MANDOCERR_EQNEOF, ep);
904 return(0);
905 }
906
907 def->valsz = sz;
908 def->val = mandoc_realloc(def->val, sz + 1);
909 memcpy(def->val, start, sz);
910 def->val[(int)sz] = '\0';
911 return(1);
912 }
913
914 static int
915 eqn_do_gfont(struct eqn_node *ep)
916 {
917
918 if (NULL == eqn_nextrawtok(ep, NULL)) {
919 EQN_MSG(MANDOCERR_EQNEOF, ep);
920 return(0);
921 }
922 return(1);
923 }
924
925 static int
926 eqn_do_gsize(struct eqn_node *ep)
927 {
928 const char *start;
929 size_t sz;
930
931 if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
932 EQN_MSG(MANDOCERR_EQNEOF, ep);
933 return(0);
934 }
935 ep->gsize = mandoc_strntoi(start, sz, 10);
936 return(1);
937 }
938
939 static int
940 eqn_do_undef(struct eqn_node *ep)
941 {
942 const char *start;
943 struct eqn_def *def;
944 size_t sz;
945
946 if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
947 EQN_MSG(MANDOCERR_EQNEOF, ep);
948 return(0);
949 } else if (NULL != (def = eqn_def_find(ep, start, sz)))
950 def->keysz = 0;
951
952 return(1);
953 }
954
955 static struct eqn_def *
956 eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
957 {
958 int i;
959
960 for (i = 0; i < (int)ep->defsz; i++)
961 if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
962 ep->defs[i].keysz, key, sz))
963 return(&ep->defs[i]);
964
965 return(NULL);
966 }