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