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