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