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