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