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