1241675Suqs/* $Id: eqn.c,v 1.38 2011/07/25 15:37:00 kristaps Exp $ */ 2241675Suqs/* 3241675Suqs * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv> 4241675Suqs * 5241675Suqs * Permission to use, copy, modify, and distribute this software for any 6241675Suqs * purpose with or without fee is hereby granted, provided that the above 7241675Suqs * copyright notice and this permission notice appear in all copies. 8241675Suqs * 9241675Suqs * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10241675Suqs * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11241675Suqs * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12241675Suqs * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13241675Suqs * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14241675Suqs * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15241675Suqs * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16241675Suqs */ 17241675Suqs#ifdef HAVE_CONFIG_H 18241675Suqs#include "config.h" 19241675Suqs#endif 20241675Suqs 21241675Suqs#include <assert.h> 22241675Suqs#include <limits.h> 23241675Suqs#include <stdio.h> 24241675Suqs#include <stdlib.h> 25241675Suqs#include <string.h> 26241675Suqs#include <time.h> 27241675Suqs 28241675Suqs#include "mandoc.h" 29241675Suqs#include "libmandoc.h" 30241675Suqs#include "libroff.h" 31241675Suqs 32241675Suqs#define EQN_NEST_MAX 128 /* maximum nesting of defines */ 33241675Suqs#define EQN_MSG(t, x) mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL) 34241675Suqs 35241675Suqsenum eqn_rest { 36241675Suqs EQN_DESCOPE, 37241675Suqs EQN_ERR, 38241675Suqs EQN_OK, 39241675Suqs EQN_EOF 40241675Suqs}; 41241675Suqs 42241675Suqsenum eqn_symt { 43241675Suqs EQNSYM_alpha, 44241675Suqs EQNSYM_beta, 45241675Suqs EQNSYM_chi, 46241675Suqs EQNSYM_delta, 47241675Suqs EQNSYM_epsilon, 48241675Suqs EQNSYM_eta, 49241675Suqs EQNSYM_gamma, 50241675Suqs EQNSYM_iota, 51241675Suqs EQNSYM_kappa, 52241675Suqs EQNSYM_lambda, 53241675Suqs EQNSYM_mu, 54241675Suqs EQNSYM_nu, 55241675Suqs EQNSYM_omega, 56241675Suqs EQNSYM_omicron, 57241675Suqs EQNSYM_phi, 58241675Suqs EQNSYM_pi, 59241675Suqs EQNSYM_ps, 60241675Suqs EQNSYM_rho, 61241675Suqs EQNSYM_sigma, 62241675Suqs EQNSYM_tau, 63241675Suqs EQNSYM_theta, 64241675Suqs EQNSYM_upsilon, 65241675Suqs EQNSYM_xi, 66241675Suqs EQNSYM_zeta, 67241675Suqs EQNSYM_DELTA, 68241675Suqs EQNSYM_GAMMA, 69241675Suqs EQNSYM_LAMBDA, 70241675Suqs EQNSYM_OMEGA, 71241675Suqs EQNSYM_PHI, 72241675Suqs EQNSYM_PI, 73241675Suqs EQNSYM_PSI, 74241675Suqs EQNSYM_SIGMA, 75241675Suqs EQNSYM_THETA, 76241675Suqs EQNSYM_UPSILON, 77241675Suqs EQNSYM_XI, 78241675Suqs EQNSYM_inter, 79241675Suqs EQNSYM_union, 80241675Suqs EQNSYM_prod, 81241675Suqs EQNSYM_int, 82241675Suqs EQNSYM_sum, 83241675Suqs EQNSYM_grad, 84241675Suqs EQNSYM_del, 85241675Suqs EQNSYM_times, 86241675Suqs EQNSYM_cdot, 87241675Suqs EQNSYM_nothing, 88241675Suqs EQNSYM_approx, 89241675Suqs EQNSYM_prime, 90241675Suqs EQNSYM_half, 91241675Suqs EQNSYM_partial, 92241675Suqs EQNSYM_inf, 93241675Suqs EQNSYM_muchgreat, 94241675Suqs EQNSYM_muchless, 95241675Suqs EQNSYM_larrow, 96241675Suqs EQNSYM_rarrow, 97241675Suqs EQNSYM_pm, 98241675Suqs EQNSYM_nequal, 99241675Suqs EQNSYM_equiv, 100241675Suqs EQNSYM_lessequal, 101241675Suqs EQNSYM_moreequal, 102241675Suqs EQNSYM__MAX 103241675Suqs}; 104241675Suqs 105241675Suqsenum eqnpartt { 106241675Suqs EQN_DEFINE = 0, 107241675Suqs EQN_NDEFINE, 108241675Suqs EQN_TDEFINE, 109241675Suqs EQN_SET, 110241675Suqs EQN_UNDEF, 111241675Suqs EQN_GFONT, 112241675Suqs EQN_GSIZE, 113241675Suqs EQN_BACK, 114241675Suqs EQN_FWD, 115241675Suqs EQN_UP, 116241675Suqs EQN_DOWN, 117241675Suqs EQN__MAX 118241675Suqs}; 119241675Suqs 120241675Suqsstruct eqnstr { 121241675Suqs const char *name; 122241675Suqs size_t sz; 123241675Suqs}; 124241675Suqs 125241675Suqs#define STRNEQ(p1, sz1, p2, sz2) \ 126241675Suqs ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1))) 127241675Suqs#define EQNSTREQ(x, p, sz) \ 128241675Suqs STRNEQ((x)->name, (x)->sz, (p), (sz)) 129241675Suqs 130241675Suqsstruct eqnpart { 131241675Suqs struct eqnstr str; 132241675Suqs int (*fp)(struct eqn_node *); 133241675Suqs}; 134241675Suqs 135241675Suqsstruct eqnsym { 136241675Suqs struct eqnstr str; 137241675Suqs const char *sym; 138241675Suqs}; 139241675Suqs 140241675Suqs 141241675Suqsstatic enum eqn_rest eqn_box(struct eqn_node *, struct eqn_box *); 142241675Suqsstatic struct eqn_box *eqn_box_alloc(struct eqn_node *, 143241675Suqs struct eqn_box *); 144241675Suqsstatic void eqn_box_free(struct eqn_box *); 145241675Suqsstatic struct eqn_def *eqn_def_find(struct eqn_node *, 146241675Suqs const char *, size_t); 147241675Suqsstatic int eqn_do_gfont(struct eqn_node *); 148241675Suqsstatic int eqn_do_gsize(struct eqn_node *); 149241675Suqsstatic int eqn_do_define(struct eqn_node *); 150241675Suqsstatic int eqn_do_ign1(struct eqn_node *); 151241675Suqsstatic int eqn_do_ign2(struct eqn_node *); 152241675Suqsstatic int eqn_do_tdefine(struct eqn_node *); 153241675Suqsstatic int eqn_do_undef(struct eqn_node *); 154241675Suqsstatic enum eqn_rest eqn_eqn(struct eqn_node *, struct eqn_box *); 155241675Suqsstatic enum eqn_rest eqn_list(struct eqn_node *, struct eqn_box *); 156241675Suqsstatic enum eqn_rest eqn_matrix(struct eqn_node *, struct eqn_box *); 157241675Suqsstatic const char *eqn_nexttok(struct eqn_node *, size_t *); 158241675Suqsstatic const char *eqn_nextrawtok(struct eqn_node *, size_t *); 159241675Suqsstatic const char *eqn_next(struct eqn_node *, 160241675Suqs char, size_t *, int); 161241675Suqsstatic void eqn_rewind(struct eqn_node *); 162241675Suqs 163241675Suqsstatic const struct eqnpart eqnparts[EQN__MAX] = { 164241675Suqs { { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */ 165241675Suqs { { "ndefine", 7 }, eqn_do_define }, /* EQN_NDEFINE */ 166241675Suqs { { "tdefine", 7 }, eqn_do_tdefine }, /* EQN_TDEFINE */ 167241675Suqs { { "set", 3 }, eqn_do_ign2 }, /* EQN_SET */ 168241675Suqs { { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */ 169241675Suqs { { "gfont", 5 }, eqn_do_gfont }, /* EQN_GFONT */ 170241675Suqs { { "gsize", 5 }, eqn_do_gsize }, /* EQN_GSIZE */ 171241675Suqs { { "back", 4 }, eqn_do_ign1 }, /* EQN_BACK */ 172241675Suqs { { "fwd", 3 }, eqn_do_ign1 }, /* EQN_FWD */ 173241675Suqs { { "up", 2 }, eqn_do_ign1 }, /* EQN_UP */ 174241675Suqs { { "down", 4 }, eqn_do_ign1 }, /* EQN_DOWN */ 175241675Suqs}; 176241675Suqs 177241675Suqsstatic const struct eqnstr eqnmarks[EQNMARK__MAX] = { 178241675Suqs { "", 0 }, /* EQNMARK_NONE */ 179241675Suqs { "dot", 3 }, /* EQNMARK_DOT */ 180241675Suqs { "dotdot", 6 }, /* EQNMARK_DOTDOT */ 181241675Suqs { "hat", 3 }, /* EQNMARK_HAT */ 182241675Suqs { "tilde", 5 }, /* EQNMARK_TILDE */ 183241675Suqs { "vec", 3 }, /* EQNMARK_VEC */ 184241675Suqs { "dyad", 4 }, /* EQNMARK_DYAD */ 185241675Suqs { "bar", 3 }, /* EQNMARK_BAR */ 186241675Suqs { "under", 5 }, /* EQNMARK_UNDER */ 187241675Suqs}; 188241675Suqs 189241675Suqsstatic const struct eqnstr eqnfonts[EQNFONT__MAX] = { 190241675Suqs { "", 0 }, /* EQNFONT_NONE */ 191241675Suqs { "roman", 5 }, /* EQNFONT_ROMAN */ 192241675Suqs { "bold", 4 }, /* EQNFONT_BOLD */ 193241675Suqs { "fat", 3 }, /* EQNFONT_FAT */ 194241675Suqs { "italic", 6 }, /* EQNFONT_ITALIC */ 195241675Suqs}; 196241675Suqs 197241675Suqsstatic const struct eqnstr eqnposs[EQNPOS__MAX] = { 198241675Suqs { "", 0 }, /* EQNPOS_NONE */ 199241675Suqs { "over", 4 }, /* EQNPOS_OVER */ 200241675Suqs { "sup", 3 }, /* EQNPOS_SUP */ 201241675Suqs { "sub", 3 }, /* EQNPOS_SUB */ 202241675Suqs { "to", 2 }, /* EQNPOS_TO */ 203241675Suqs { "from", 4 }, /* EQNPOS_FROM */ 204241675Suqs}; 205241675Suqs 206241675Suqsstatic const struct eqnstr eqnpiles[EQNPILE__MAX] = { 207241675Suqs { "", 0 }, /* EQNPILE_NONE */ 208241675Suqs { "pile", 4 }, /* EQNPILE_PILE */ 209241675Suqs { "cpile", 5 }, /* EQNPILE_CPILE */ 210241675Suqs { "rpile", 5 }, /* EQNPILE_RPILE */ 211241675Suqs { "lpile", 5 }, /* EQNPILE_LPILE */ 212241675Suqs { "col", 3 }, /* EQNPILE_COL */ 213241675Suqs { "ccol", 4 }, /* EQNPILE_CCOL */ 214241675Suqs { "rcol", 4 }, /* EQNPILE_RCOL */ 215241675Suqs { "lcol", 4 }, /* EQNPILE_LCOL */ 216241675Suqs}; 217241675Suqs 218241675Suqsstatic const struct eqnsym eqnsyms[EQNSYM__MAX] = { 219241675Suqs { { "alpha", 5 }, "*a" }, /* EQNSYM_alpha */ 220241675Suqs { { "beta", 4 }, "*b" }, /* EQNSYM_beta */ 221241675Suqs { { "chi", 3 }, "*x" }, /* EQNSYM_chi */ 222241675Suqs { { "delta", 5 }, "*d" }, /* EQNSYM_delta */ 223241675Suqs { { "epsilon", 7 }, "*e" }, /* EQNSYM_epsilon */ 224241675Suqs { { "eta", 3 }, "*y" }, /* EQNSYM_eta */ 225241675Suqs { { "gamma", 5 }, "*g" }, /* EQNSYM_gamma */ 226241675Suqs { { "iota", 4 }, "*i" }, /* EQNSYM_iota */ 227241675Suqs { { "kappa", 5 }, "*k" }, /* EQNSYM_kappa */ 228241675Suqs { { "lambda", 6 }, "*l" }, /* EQNSYM_lambda */ 229241675Suqs { { "mu", 2 }, "*m" }, /* EQNSYM_mu */ 230241675Suqs { { "nu", 2 }, "*n" }, /* EQNSYM_nu */ 231241675Suqs { { "omega", 5 }, "*w" }, /* EQNSYM_omega */ 232241675Suqs { { "omicron", 7 }, "*o" }, /* EQNSYM_omicron */ 233241675Suqs { { "phi", 3 }, "*f" }, /* EQNSYM_phi */ 234241675Suqs { { "pi", 2 }, "*p" }, /* EQNSYM_pi */ 235241675Suqs { { "psi", 2 }, "*q" }, /* EQNSYM_psi */ 236241675Suqs { { "rho", 3 }, "*r" }, /* EQNSYM_rho */ 237241675Suqs { { "sigma", 5 }, "*s" }, /* EQNSYM_sigma */ 238241675Suqs { { "tau", 3 }, "*t" }, /* EQNSYM_tau */ 239241675Suqs { { "theta", 5 }, "*h" }, /* EQNSYM_theta */ 240241675Suqs { { "upsilon", 7 }, "*u" }, /* EQNSYM_upsilon */ 241241675Suqs { { "xi", 2 }, "*c" }, /* EQNSYM_xi */ 242241675Suqs { { "zeta", 4 }, "*z" }, /* EQNSYM_zeta */ 243241675Suqs { { "DELTA", 5 }, "*D" }, /* EQNSYM_DELTA */ 244241675Suqs { { "GAMMA", 5 }, "*G" }, /* EQNSYM_GAMMA */ 245241675Suqs { { "LAMBDA", 6 }, "*L" }, /* EQNSYM_LAMBDA */ 246241675Suqs { { "OMEGA", 5 }, "*W" }, /* EQNSYM_OMEGA */ 247241675Suqs { { "PHI", 3 }, "*F" }, /* EQNSYM_PHI */ 248241675Suqs { { "PI", 2 }, "*P" }, /* EQNSYM_PI */ 249241675Suqs { { "PSI", 3 }, "*Q" }, /* EQNSYM_PSI */ 250241675Suqs { { "SIGMA", 5 }, "*S" }, /* EQNSYM_SIGMA */ 251241675Suqs { { "THETA", 5 }, "*H" }, /* EQNSYM_THETA */ 252241675Suqs { { "UPSILON", 7 }, "*U" }, /* EQNSYM_UPSILON */ 253241675Suqs { { "XI", 2 }, "*C" }, /* EQNSYM_XI */ 254241675Suqs { { "inter", 5 }, "ca" }, /* EQNSYM_inter */ 255241675Suqs { { "union", 5 }, "cu" }, /* EQNSYM_union */ 256241675Suqs { { "prod", 4 }, "product" }, /* EQNSYM_prod */ 257241675Suqs { { "int", 3 }, "integral" }, /* EQNSYM_int */ 258241675Suqs { { "sum", 3 }, "sum" }, /* EQNSYM_sum */ 259241675Suqs { { "grad", 4 }, "gr" }, /* EQNSYM_grad */ 260241675Suqs { { "del", 3 }, "gr" }, /* EQNSYM_del */ 261241675Suqs { { "times", 5 }, "mu" }, /* EQNSYM_times */ 262241675Suqs { { "cdot", 4 }, "pc" }, /* EQNSYM_cdot */ 263241675Suqs { { "nothing", 7 }, "&" }, /* EQNSYM_nothing */ 264241675Suqs { { "approx", 6 }, "~~" }, /* EQNSYM_approx */ 265241675Suqs { { "prime", 5 }, "aq" }, /* EQNSYM_prime */ 266241675Suqs { { "half", 4 }, "12" }, /* EQNSYM_half */ 267241675Suqs { { "partial", 7 }, "pd" }, /* EQNSYM_partial */ 268241675Suqs { { "inf", 3 }, "if" }, /* EQNSYM_inf */ 269241675Suqs { { ">>", 2 }, ">>" }, /* EQNSYM_muchgreat */ 270241675Suqs { { "<<", 2 }, "<<" }, /* EQNSYM_muchless */ 271241675Suqs { { "<-", 2 }, "<-" }, /* EQNSYM_larrow */ 272241675Suqs { { "->", 2 }, "->" }, /* EQNSYM_rarrow */ 273241675Suqs { { "+-", 2 }, "+-" }, /* EQNSYM_pm */ 274241675Suqs { { "!=", 2 }, "!=" }, /* EQNSYM_nequal */ 275241675Suqs { { "==", 2 }, "==" }, /* EQNSYM_equiv */ 276241675Suqs { { "<=", 2 }, "<=" }, /* EQNSYM_lessequal */ 277241675Suqs { { ">=", 2 }, ">=" }, /* EQNSYM_moreequal */ 278241675Suqs}; 279241675Suqs 280241675Suqs/* ARGSUSED */ 281241675Suqsenum rofferr 282241675Suqseqn_read(struct eqn_node **epp, int ln, 283241675Suqs const char *p, int pos, int *offs) 284241675Suqs{ 285241675Suqs size_t sz; 286241675Suqs struct eqn_node *ep; 287241675Suqs enum rofferr er; 288241675Suqs 289241675Suqs ep = *epp; 290241675Suqs 291241675Suqs /* 292241675Suqs * If we're the terminating mark, unset our equation status and 293241675Suqs * validate the full equation. 294241675Suqs */ 295241675Suqs 296241675Suqs if (0 == strncmp(p, ".EN", 3)) { 297241675Suqs er = eqn_end(epp); 298241675Suqs p += 3; 299241675Suqs while (' ' == *p || '\t' == *p) 300241675Suqs p++; 301241675Suqs if ('\0' == *p) 302241675Suqs return(er); 303241675Suqs mandoc_msg(MANDOCERR_ARGSLOST, ep->parse, ln, pos, NULL); 304241675Suqs return(er); 305241675Suqs } 306241675Suqs 307241675Suqs /* 308241675Suqs * Build up the full string, replacing all newlines with regular 309241675Suqs * whitespace. 310241675Suqs */ 311241675Suqs 312241675Suqs sz = strlen(p + pos) + 1; 313241675Suqs ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1); 314241675Suqs 315241675Suqs /* First invocation: nil terminate the string. */ 316241675Suqs 317241675Suqs if (0 == ep->sz) 318241675Suqs *ep->data = '\0'; 319241675Suqs 320241675Suqs ep->sz += sz; 321241675Suqs strlcat(ep->data, p + pos, ep->sz + 1); 322241675Suqs strlcat(ep->data, " ", ep->sz + 1); 323241675Suqs return(ROFF_IGN); 324241675Suqs} 325241675Suqs 326241675Suqsstruct eqn_node * 327241675Suqseqn_alloc(const char *name, int pos, int line, struct mparse *parse) 328241675Suqs{ 329241675Suqs struct eqn_node *p; 330241675Suqs size_t sz; 331241675Suqs const char *end; 332241675Suqs 333241675Suqs p = mandoc_calloc(1, sizeof(struct eqn_node)); 334241675Suqs 335241675Suqs if (name && '\0' != *name) { 336241675Suqs sz = strlen(name); 337241675Suqs assert(sz); 338241675Suqs do { 339241675Suqs sz--; 340241675Suqs end = name + (int)sz; 341241675Suqs } while (' ' == *end || '\t' == *end); 342241675Suqs p->eqn.name = mandoc_strndup(name, sz + 1); 343241675Suqs } 344241675Suqs 345241675Suqs p->parse = parse; 346241675Suqs p->eqn.ln = line; 347241675Suqs p->eqn.pos = pos; 348241675Suqs p->gsize = EQN_DEFSIZE; 349241675Suqs 350241675Suqs return(p); 351241675Suqs} 352241675Suqs 353241675Suqsenum rofferr 354241675Suqseqn_end(struct eqn_node **epp) 355241675Suqs{ 356241675Suqs struct eqn_node *ep; 357241675Suqs struct eqn_box *root; 358241675Suqs enum eqn_rest c; 359241675Suqs 360241675Suqs ep = *epp; 361241675Suqs *epp = NULL; 362241675Suqs 363241675Suqs ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box)); 364241675Suqs 365241675Suqs root = ep->eqn.root; 366241675Suqs root->type = EQN_ROOT; 367241675Suqs 368241675Suqs if (0 == ep->sz) 369241675Suqs return(ROFF_IGN); 370241675Suqs 371241675Suqs if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) { 372241675Suqs EQN_MSG(MANDOCERR_EQNNSCOPE, ep); 373241675Suqs c = EQN_ERR; 374241675Suqs } 375241675Suqs 376241675Suqs return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN); 377241675Suqs} 378241675Suqs 379241675Suqsstatic enum eqn_rest 380241675Suqseqn_eqn(struct eqn_node *ep, struct eqn_box *last) 381241675Suqs{ 382241675Suqs struct eqn_box *bp; 383241675Suqs enum eqn_rest c; 384241675Suqs 385241675Suqs bp = eqn_box_alloc(ep, last); 386241675Suqs bp->type = EQN_SUBEXPR; 387241675Suqs 388241675Suqs while (EQN_OK == (c = eqn_box(ep, bp))) 389241675Suqs /* Spin! */ ; 390241675Suqs 391241675Suqs return(c); 392241675Suqs} 393241675Suqs 394241675Suqsstatic enum eqn_rest 395241675Suqseqn_matrix(struct eqn_node *ep, struct eqn_box *last) 396241675Suqs{ 397241675Suqs struct eqn_box *bp; 398241675Suqs const char *start; 399241675Suqs size_t sz; 400241675Suqs enum eqn_rest c; 401241675Suqs 402241675Suqs bp = eqn_box_alloc(ep, last); 403241675Suqs bp->type = EQN_MATRIX; 404241675Suqs 405241675Suqs if (NULL == (start = eqn_nexttok(ep, &sz))) { 406241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 407241675Suqs return(EQN_ERR); 408241675Suqs } 409241675Suqs if ( ! STRNEQ(start, sz, "{", 1)) { 410241675Suqs EQN_MSG(MANDOCERR_EQNSYNT, ep); 411241675Suqs return(EQN_ERR); 412241675Suqs } 413241675Suqs 414241675Suqs while (EQN_OK == (c = eqn_box(ep, bp))) 415241675Suqs switch (bp->last->pile) { 416241675Suqs case (EQNPILE_LCOL): 417241675Suqs /* FALLTHROUGH */ 418241675Suqs case (EQNPILE_CCOL): 419241675Suqs /* FALLTHROUGH */ 420241675Suqs case (EQNPILE_RCOL): 421241675Suqs continue; 422241675Suqs default: 423241675Suqs EQN_MSG(MANDOCERR_EQNSYNT, ep); 424241675Suqs return(EQN_ERR); 425241675Suqs }; 426241675Suqs 427241675Suqs if (EQN_DESCOPE != c) { 428241675Suqs if (EQN_EOF == c) 429241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 430241675Suqs return(EQN_ERR); 431241675Suqs } 432241675Suqs 433241675Suqs eqn_rewind(ep); 434241675Suqs start = eqn_nexttok(ep, &sz); 435241675Suqs assert(start); 436241675Suqs if (STRNEQ(start, sz, "}", 1)) 437241675Suqs return(EQN_OK); 438241675Suqs 439241675Suqs EQN_MSG(MANDOCERR_EQNBADSCOPE, ep); 440241675Suqs return(EQN_ERR); 441241675Suqs} 442241675Suqs 443241675Suqsstatic enum eqn_rest 444241675Suqseqn_list(struct eqn_node *ep, struct eqn_box *last) 445241675Suqs{ 446241675Suqs struct eqn_box *bp; 447241675Suqs const char *start; 448241675Suqs size_t sz; 449241675Suqs enum eqn_rest c; 450241675Suqs 451241675Suqs bp = eqn_box_alloc(ep, last); 452241675Suqs bp->type = EQN_LIST; 453241675Suqs 454241675Suqs if (NULL == (start = eqn_nexttok(ep, &sz))) { 455241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 456241675Suqs return(EQN_ERR); 457241675Suqs } 458241675Suqs if ( ! STRNEQ(start, sz, "{", 1)) { 459241675Suqs EQN_MSG(MANDOCERR_EQNSYNT, ep); 460241675Suqs return(EQN_ERR); 461241675Suqs } 462241675Suqs 463241675Suqs while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) { 464241675Suqs eqn_rewind(ep); 465241675Suqs start = eqn_nexttok(ep, &sz); 466241675Suqs assert(start); 467241675Suqs if ( ! STRNEQ(start, sz, "above", 5)) 468241675Suqs break; 469241675Suqs } 470241675Suqs 471241675Suqs if (EQN_DESCOPE != c) { 472241675Suqs if (EQN_ERR != c) 473241675Suqs EQN_MSG(MANDOCERR_EQNSCOPE, ep); 474241675Suqs return(EQN_ERR); 475241675Suqs } 476241675Suqs 477241675Suqs eqn_rewind(ep); 478241675Suqs start = eqn_nexttok(ep, &sz); 479241675Suqs assert(start); 480241675Suqs if (STRNEQ(start, sz, "}", 1)) 481241675Suqs return(EQN_OK); 482241675Suqs 483241675Suqs EQN_MSG(MANDOCERR_EQNBADSCOPE, ep); 484241675Suqs return(EQN_ERR); 485241675Suqs} 486241675Suqs 487241675Suqsstatic enum eqn_rest 488241675Suqseqn_box(struct eqn_node *ep, struct eqn_box *last) 489241675Suqs{ 490241675Suqs size_t sz; 491241675Suqs const char *start; 492241675Suqs char *left; 493241675Suqs char sym[64]; 494241675Suqs enum eqn_rest c; 495241675Suqs int i, size; 496241675Suqs struct eqn_box *bp; 497241675Suqs 498241675Suqs if (NULL == (start = eqn_nexttok(ep, &sz))) 499241675Suqs return(EQN_EOF); 500241675Suqs 501241675Suqs if (STRNEQ(start, sz, "}", 1)) 502241675Suqs return(EQN_DESCOPE); 503241675Suqs else if (STRNEQ(start, sz, "right", 5)) 504241675Suqs return(EQN_DESCOPE); 505241675Suqs else if (STRNEQ(start, sz, "above", 5)) 506241675Suqs return(EQN_DESCOPE); 507241675Suqs else if (STRNEQ(start, sz, "mark", 4)) 508241675Suqs return(EQN_OK); 509241675Suqs else if (STRNEQ(start, sz, "lineup", 6)) 510241675Suqs return(EQN_OK); 511241675Suqs 512241675Suqs for (i = 0; i < (int)EQN__MAX; i++) { 513241675Suqs if ( ! EQNSTREQ(&eqnparts[i].str, start, sz)) 514241675Suqs continue; 515241675Suqs return((*eqnparts[i].fp)(ep) ? 516241675Suqs EQN_OK : EQN_ERR); 517241675Suqs } 518241675Suqs 519241675Suqs if (STRNEQ(start, sz, "{", 1)) { 520241675Suqs if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) { 521241675Suqs if (EQN_ERR != c) 522241675Suqs EQN_MSG(MANDOCERR_EQNSCOPE, ep); 523241675Suqs return(EQN_ERR); 524241675Suqs } 525241675Suqs eqn_rewind(ep); 526241675Suqs start = eqn_nexttok(ep, &sz); 527241675Suqs assert(start); 528241675Suqs if (STRNEQ(start, sz, "}", 1)) 529241675Suqs return(EQN_OK); 530241675Suqs EQN_MSG(MANDOCERR_EQNBADSCOPE, ep); 531241675Suqs return(EQN_ERR); 532241675Suqs } 533241675Suqs 534241675Suqs for (i = 0; i < (int)EQNPILE__MAX; i++) { 535241675Suqs if ( ! EQNSTREQ(&eqnpiles[i], start, sz)) 536241675Suqs continue; 537241675Suqs if (EQN_OK == (c = eqn_list(ep, last))) 538241675Suqs last->last->pile = (enum eqn_pilet)i; 539241675Suqs return(c); 540241675Suqs } 541241675Suqs 542241675Suqs if (STRNEQ(start, sz, "matrix", 6)) 543241675Suqs return(eqn_matrix(ep, last)); 544241675Suqs 545241675Suqs if (STRNEQ(start, sz, "left", 4)) { 546241675Suqs if (NULL == (start = eqn_nexttok(ep, &sz))) { 547241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 548241675Suqs return(EQN_ERR); 549241675Suqs } 550241675Suqs left = mandoc_strndup(start, sz); 551241675Suqs c = eqn_eqn(ep, last); 552241675Suqs if (last->last) 553241675Suqs last->last->left = left; 554241675Suqs else 555241675Suqs free(left); 556241675Suqs if (EQN_DESCOPE != c) 557241675Suqs return(c); 558241675Suqs assert(last->last); 559241675Suqs eqn_rewind(ep); 560241675Suqs start = eqn_nexttok(ep, &sz); 561241675Suqs assert(start); 562241675Suqs if ( ! STRNEQ(start, sz, "right", 5)) 563241675Suqs return(EQN_DESCOPE); 564241675Suqs if (NULL == (start = eqn_nexttok(ep, &sz))) { 565241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 566241675Suqs return(EQN_ERR); 567241675Suqs } 568241675Suqs last->last->right = mandoc_strndup(start, sz); 569241675Suqs return(EQN_OK); 570241675Suqs } 571241675Suqs 572241675Suqs for (i = 0; i < (int)EQNPOS__MAX; i++) { 573241675Suqs if ( ! EQNSTREQ(&eqnposs[i], start, sz)) 574241675Suqs continue; 575241675Suqs if (NULL == last->last) { 576241675Suqs EQN_MSG(MANDOCERR_EQNSYNT, ep); 577241675Suqs return(EQN_ERR); 578241675Suqs } 579241675Suqs last->last->pos = (enum eqn_post)i; 580241675Suqs if (EQN_EOF == (c = eqn_box(ep, last))) { 581241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 582241675Suqs return(EQN_ERR); 583241675Suqs } 584241675Suqs return(c); 585241675Suqs } 586241675Suqs 587241675Suqs for (i = 0; i < (int)EQNMARK__MAX; i++) { 588241675Suqs if ( ! EQNSTREQ(&eqnmarks[i], start, sz)) 589241675Suqs continue; 590241675Suqs if (NULL == last->last) { 591241675Suqs EQN_MSG(MANDOCERR_EQNSYNT, ep); 592241675Suqs return(EQN_ERR); 593241675Suqs } 594241675Suqs last->last->mark = (enum eqn_markt)i; 595241675Suqs if (EQN_EOF == (c = eqn_box(ep, last))) { 596241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 597241675Suqs return(EQN_ERR); 598241675Suqs } 599241675Suqs return(c); 600241675Suqs } 601241675Suqs 602241675Suqs for (i = 0; i < (int)EQNFONT__MAX; i++) { 603241675Suqs if ( ! EQNSTREQ(&eqnfonts[i], start, sz)) 604241675Suqs continue; 605241675Suqs if (EQN_EOF == (c = eqn_box(ep, last))) { 606241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 607241675Suqs return(EQN_ERR); 608241675Suqs } else if (EQN_OK == c) 609241675Suqs last->last->font = (enum eqn_fontt)i; 610241675Suqs return(c); 611241675Suqs } 612241675Suqs 613241675Suqs if (STRNEQ(start, sz, "size", 4)) { 614241675Suqs if (NULL == (start = eqn_nexttok(ep, &sz))) { 615241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 616241675Suqs return(EQN_ERR); 617241675Suqs } 618241675Suqs size = mandoc_strntoi(start, sz, 10); 619241675Suqs if (EQN_EOF == (c = eqn_box(ep, last))) { 620241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 621241675Suqs return(EQN_ERR); 622241675Suqs } else if (EQN_OK != c) 623241675Suqs return(c); 624241675Suqs last->last->size = size; 625241675Suqs } 626241675Suqs 627241675Suqs bp = eqn_box_alloc(ep, last); 628241675Suqs bp->type = EQN_TEXT; 629241675Suqs for (i = 0; i < (int)EQNSYM__MAX; i++) 630241675Suqs if (EQNSTREQ(&eqnsyms[i].str, start, sz)) { 631241675Suqs sym[63] = '\0'; 632241675Suqs snprintf(sym, 62, "\\[%s]", eqnsyms[i].sym); 633241675Suqs bp->text = mandoc_strdup(sym); 634241675Suqs return(EQN_OK); 635241675Suqs } 636241675Suqs 637241675Suqs bp->text = mandoc_strndup(start, sz); 638241675Suqs return(EQN_OK); 639241675Suqs} 640241675Suqs 641241675Suqsvoid 642241675Suqseqn_free(struct eqn_node *p) 643241675Suqs{ 644241675Suqs int i; 645241675Suqs 646241675Suqs eqn_box_free(p->eqn.root); 647241675Suqs 648241675Suqs for (i = 0; i < (int)p->defsz; i++) { 649241675Suqs free(p->defs[i].key); 650241675Suqs free(p->defs[i].val); 651241675Suqs } 652241675Suqs 653241675Suqs free(p->eqn.name); 654241675Suqs free(p->data); 655241675Suqs free(p->defs); 656241675Suqs free(p); 657241675Suqs} 658241675Suqs 659241675Suqsstatic struct eqn_box * 660241675Suqseqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent) 661241675Suqs{ 662241675Suqs struct eqn_box *bp; 663241675Suqs 664241675Suqs bp = mandoc_calloc(1, sizeof(struct eqn_box)); 665241675Suqs bp->parent = parent; 666241675Suqs bp->size = ep->gsize; 667241675Suqs 668241675Suqs if (NULL == parent->first) 669241675Suqs parent->first = bp; 670241675Suqs else 671241675Suqs parent->last->next = bp; 672241675Suqs 673241675Suqs parent->last = bp; 674241675Suqs return(bp); 675241675Suqs} 676241675Suqs 677241675Suqsstatic void 678241675Suqseqn_box_free(struct eqn_box *bp) 679241675Suqs{ 680241675Suqs 681241675Suqs if (bp->first) 682241675Suqs eqn_box_free(bp->first); 683241675Suqs if (bp->next) 684241675Suqs eqn_box_free(bp->next); 685241675Suqs 686241675Suqs free(bp->text); 687241675Suqs free(bp->left); 688241675Suqs free(bp->right); 689241675Suqs free(bp); 690241675Suqs} 691241675Suqs 692241675Suqsstatic const char * 693241675Suqseqn_nextrawtok(struct eqn_node *ep, size_t *sz) 694241675Suqs{ 695241675Suqs 696241675Suqs return(eqn_next(ep, '"', sz, 0)); 697241675Suqs} 698241675Suqs 699241675Suqsstatic const char * 700241675Suqseqn_nexttok(struct eqn_node *ep, size_t *sz) 701241675Suqs{ 702241675Suqs 703241675Suqs return(eqn_next(ep, '"', sz, 1)); 704241675Suqs} 705241675Suqs 706241675Suqsstatic void 707241675Suqseqn_rewind(struct eqn_node *ep) 708241675Suqs{ 709241675Suqs 710241675Suqs ep->cur = ep->rew; 711241675Suqs} 712241675Suqs 713241675Suqsstatic const char * 714241675Suqseqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl) 715241675Suqs{ 716241675Suqs char *start, *next; 717241675Suqs int q, diff, lim; 718241675Suqs size_t ssz, dummy; 719241675Suqs struct eqn_def *def; 720241675Suqs 721241675Suqs if (NULL == sz) 722241675Suqs sz = &dummy; 723241675Suqs 724241675Suqs lim = 0; 725241675Suqs ep->rew = ep->cur; 726241675Suqsagain: 727241675Suqs /* Prevent self-definitions. */ 728241675Suqs 729241675Suqs if (lim >= EQN_NEST_MAX) { 730241675Suqs EQN_MSG(MANDOCERR_ROFFLOOP, ep); 731241675Suqs return(NULL); 732241675Suqs } 733241675Suqs 734241675Suqs ep->cur = ep->rew; 735241675Suqs start = &ep->data[(int)ep->cur]; 736241675Suqs q = 0; 737241675Suqs 738241675Suqs if ('\0' == *start) 739241675Suqs return(NULL); 740241675Suqs 741241675Suqs if (quote == *start) { 742241675Suqs ep->cur++; 743241675Suqs q = 1; 744241675Suqs } 745241675Suqs 746241675Suqs start = &ep->data[(int)ep->cur]; 747241675Suqs 748241675Suqs if ( ! q) { 749241675Suqs if ('{' == *start || '}' == *start) 750241675Suqs ssz = 1; 751241675Suqs else 752241675Suqs ssz = strcspn(start + 1, " ^~\"{}\t") + 1; 753241675Suqs next = start + (int)ssz; 754241675Suqs if ('\0' == *next) 755241675Suqs next = NULL; 756241675Suqs } else 757241675Suqs next = strchr(start, quote); 758241675Suqs 759241675Suqs if (NULL != next) { 760241675Suqs *sz = (size_t)(next - start); 761241675Suqs ep->cur += *sz; 762241675Suqs if (q) 763241675Suqs ep->cur++; 764241675Suqs while (' ' == ep->data[(int)ep->cur] || 765241675Suqs '\t' == ep->data[(int)ep->cur] || 766241675Suqs '^' == ep->data[(int)ep->cur] || 767241675Suqs '~' == ep->data[(int)ep->cur]) 768241675Suqs ep->cur++; 769241675Suqs } else { 770241675Suqs if (q) 771241675Suqs EQN_MSG(MANDOCERR_BADQUOTE, ep); 772241675Suqs next = strchr(start, '\0'); 773241675Suqs *sz = (size_t)(next - start); 774241675Suqs ep->cur += *sz; 775241675Suqs } 776241675Suqs 777241675Suqs /* Quotes aren't expanded for values. */ 778241675Suqs 779241675Suqs if (q || ! repl) 780241675Suqs return(start); 781241675Suqs 782241675Suqs if (NULL != (def = eqn_def_find(ep, start, *sz))) { 783241675Suqs diff = def->valsz - *sz; 784241675Suqs 785241675Suqs if (def->valsz > *sz) { 786241675Suqs ep->sz += diff; 787241675Suqs ep->data = mandoc_realloc(ep->data, ep->sz + 1); 788241675Suqs ep->data[ep->sz] = '\0'; 789241675Suqs start = &ep->data[(int)ep->rew]; 790241675Suqs } 791241675Suqs 792241675Suqs diff = def->valsz - *sz; 793241675Suqs memmove(start + *sz + diff, start + *sz, 794241675Suqs (strlen(start) - *sz) + 1); 795241675Suqs memcpy(start, def->val, def->valsz); 796241675Suqs goto again; 797241675Suqs } 798241675Suqs 799241675Suqs return(start); 800241675Suqs} 801241675Suqs 802241675Suqsstatic int 803241675Suqseqn_do_ign1(struct eqn_node *ep) 804241675Suqs{ 805241675Suqs 806241675Suqs if (NULL == eqn_nextrawtok(ep, NULL)) 807241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 808241675Suqs else 809241675Suqs return(1); 810241675Suqs 811241675Suqs return(0); 812241675Suqs} 813241675Suqs 814241675Suqsstatic int 815241675Suqseqn_do_ign2(struct eqn_node *ep) 816241675Suqs{ 817241675Suqs 818241675Suqs if (NULL == eqn_nextrawtok(ep, NULL)) 819241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 820241675Suqs else if (NULL == eqn_nextrawtok(ep, NULL)) 821241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 822241675Suqs else 823241675Suqs return(1); 824241675Suqs 825241675Suqs return(0); 826241675Suqs} 827241675Suqs 828241675Suqsstatic int 829241675Suqseqn_do_tdefine(struct eqn_node *ep) 830241675Suqs{ 831241675Suqs 832241675Suqs if (NULL == eqn_nextrawtok(ep, NULL)) 833241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 834241675Suqs else if (NULL == eqn_next(ep, ep->data[(int)ep->cur], NULL, 0)) 835241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 836241675Suqs else 837241675Suqs return(1); 838241675Suqs 839241675Suqs return(0); 840241675Suqs} 841241675Suqs 842241675Suqsstatic int 843241675Suqseqn_do_define(struct eqn_node *ep) 844241675Suqs{ 845241675Suqs const char *start; 846241675Suqs size_t sz; 847241675Suqs struct eqn_def *def; 848241675Suqs int i; 849241675Suqs 850241675Suqs if (NULL == (start = eqn_nextrawtok(ep, &sz))) { 851241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 852241675Suqs return(0); 853241675Suqs } 854241675Suqs 855241675Suqs /* 856241675Suqs * Search for a key that already exists. 857241675Suqs * Create a new key if none is found. 858241675Suqs */ 859241675Suqs 860241675Suqs if (NULL == (def = eqn_def_find(ep, start, sz))) { 861241675Suqs /* Find holes in string array. */ 862241675Suqs for (i = 0; i < (int)ep->defsz; i++) 863241675Suqs if (0 == ep->defs[i].keysz) 864241675Suqs break; 865241675Suqs 866241675Suqs if (i == (int)ep->defsz) { 867241675Suqs ep->defsz++; 868241675Suqs ep->defs = mandoc_realloc 869241675Suqs (ep->defs, ep->defsz * 870241675Suqs sizeof(struct eqn_def)); 871241675Suqs ep->defs[i].key = ep->defs[i].val = NULL; 872241675Suqs } 873241675Suqs 874241675Suqs ep->defs[i].keysz = sz; 875241675Suqs ep->defs[i].key = mandoc_realloc 876241675Suqs (ep->defs[i].key, sz + 1); 877241675Suqs 878241675Suqs memcpy(ep->defs[i].key, start, sz); 879241675Suqs ep->defs[i].key[(int)sz] = '\0'; 880241675Suqs def = &ep->defs[i]; 881241675Suqs } 882241675Suqs 883241675Suqs start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0); 884241675Suqs 885241675Suqs if (NULL == start) { 886241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 887241675Suqs return(0); 888241675Suqs } 889241675Suqs 890241675Suqs def->valsz = sz; 891241675Suqs def->val = mandoc_realloc(def->val, sz + 1); 892241675Suqs memcpy(def->val, start, sz); 893241675Suqs def->val[(int)sz] = '\0'; 894241675Suqs return(1); 895241675Suqs} 896241675Suqs 897241675Suqsstatic int 898241675Suqseqn_do_gfont(struct eqn_node *ep) 899241675Suqs{ 900241675Suqs 901241675Suqs if (NULL == eqn_nextrawtok(ep, NULL)) { 902241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 903241675Suqs return(0); 904241675Suqs } 905241675Suqs return(1); 906241675Suqs} 907241675Suqs 908241675Suqsstatic int 909241675Suqseqn_do_gsize(struct eqn_node *ep) 910241675Suqs{ 911241675Suqs const char *start; 912241675Suqs size_t sz; 913241675Suqs 914241675Suqs if (NULL == (start = eqn_nextrawtok(ep, &sz))) { 915241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 916241675Suqs return(0); 917241675Suqs } 918241675Suqs ep->gsize = mandoc_strntoi(start, sz, 10); 919241675Suqs return(1); 920241675Suqs} 921241675Suqs 922241675Suqsstatic int 923241675Suqseqn_do_undef(struct eqn_node *ep) 924241675Suqs{ 925241675Suqs const char *start; 926241675Suqs struct eqn_def *def; 927241675Suqs size_t sz; 928241675Suqs 929241675Suqs if (NULL == (start = eqn_nextrawtok(ep, &sz))) { 930241675Suqs EQN_MSG(MANDOCERR_EQNEOF, ep); 931241675Suqs return(0); 932241675Suqs } else if (NULL != (def = eqn_def_find(ep, start, sz))) 933241675Suqs def->keysz = 0; 934241675Suqs 935241675Suqs return(1); 936241675Suqs} 937241675Suqs 938241675Suqsstatic struct eqn_def * 939241675Suqseqn_def_find(struct eqn_node *ep, const char *key, size_t sz) 940241675Suqs{ 941241675Suqs int i; 942241675Suqs 943241675Suqs for (i = 0; i < (int)ep->defsz; i++) 944241675Suqs if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key, 945241675Suqs ep->defs[i].keysz, key, sz)) 946241675Suqs return(&ep->defs[i]); 947241675Suqs 948241675Suqs return(NULL); 949241675Suqs} 950