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