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