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