1*260e9a87SYuri Pankov /* $Id: eqn.c,v 1.58 2015/03/04 12:19:49 schwarze Exp $ */ 295c635efSGarrett D'Amore /* 3*260e9a87SYuri Pankov * Copyright (c) 2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv> 4*260e9a87SYuri Pankov * Copyright (c) 2014, 2015 Ingo Schwarze <schwarze@openbsd.org> 595c635efSGarrett D'Amore * 695c635efSGarrett D'Amore * Permission to use, copy, modify, and distribute this software for any 795c635efSGarrett D'Amore * purpose with or without fee is hereby granted, provided that the above 895c635efSGarrett D'Amore * copyright notice and this permission notice appear in all copies. 995c635efSGarrett D'Amore * 1095c635efSGarrett D'Amore * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1195c635efSGarrett D'Amore * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1295c635efSGarrett D'Amore * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1395c635efSGarrett D'Amore * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1495c635efSGarrett D'Amore * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1595c635efSGarrett D'Amore * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1695c635efSGarrett D'Amore * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1795c635efSGarrett D'Amore */ 1895c635efSGarrett D'Amore #include "config.h" 19*260e9a87SYuri Pankov 20*260e9a87SYuri Pankov #include <sys/types.h> 2195c635efSGarrett D'Amore 2295c635efSGarrett D'Amore #include <assert.h> 2395c635efSGarrett D'Amore #include <limits.h> 2495c635efSGarrett D'Amore #include <stdio.h> 2595c635efSGarrett D'Amore #include <stdlib.h> 2695c635efSGarrett D'Amore #include <string.h> 2795c635efSGarrett D'Amore #include <time.h> 2895c635efSGarrett D'Amore 2995c635efSGarrett D'Amore #include "mandoc.h" 30*260e9a87SYuri Pankov #include "mandoc_aux.h" 3195c635efSGarrett D'Amore #include "libmandoc.h" 3295c635efSGarrett D'Amore #include "libroff.h" 3395c635efSGarrett D'Amore 3495c635efSGarrett D'Amore #define EQN_NEST_MAX 128 /* maximum nesting of defines */ 35*260e9a87SYuri Pankov #define STRNEQ(p1, sz1, p2, sz2) \ 36*260e9a87SYuri Pankov ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1))) 3795c635efSGarrett D'Amore 38*260e9a87SYuri Pankov enum eqn_tok { 39*260e9a87SYuri Pankov EQN_TOK_DYAD = 0, 40*260e9a87SYuri Pankov EQN_TOK_VEC, 41*260e9a87SYuri Pankov EQN_TOK_UNDER, 42*260e9a87SYuri Pankov EQN_TOK_BAR, 43*260e9a87SYuri Pankov EQN_TOK_TILDE, 44*260e9a87SYuri Pankov EQN_TOK_HAT, 45*260e9a87SYuri Pankov EQN_TOK_DOT, 46*260e9a87SYuri Pankov EQN_TOK_DOTDOT, 47*260e9a87SYuri Pankov EQN_TOK_FWD, 48*260e9a87SYuri Pankov EQN_TOK_BACK, 49*260e9a87SYuri Pankov EQN_TOK_DOWN, 50*260e9a87SYuri Pankov EQN_TOK_UP, 51*260e9a87SYuri Pankov EQN_TOK_FAT, 52*260e9a87SYuri Pankov EQN_TOK_ROMAN, 53*260e9a87SYuri Pankov EQN_TOK_ITALIC, 54*260e9a87SYuri Pankov EQN_TOK_BOLD, 55*260e9a87SYuri Pankov EQN_TOK_SIZE, 56*260e9a87SYuri Pankov EQN_TOK_SUB, 57*260e9a87SYuri Pankov EQN_TOK_SUP, 58*260e9a87SYuri Pankov EQN_TOK_SQRT, 59*260e9a87SYuri Pankov EQN_TOK_OVER, 60*260e9a87SYuri Pankov EQN_TOK_FROM, 61*260e9a87SYuri Pankov EQN_TOK_TO, 62*260e9a87SYuri Pankov EQN_TOK_BRACE_OPEN, 63*260e9a87SYuri Pankov EQN_TOK_BRACE_CLOSE, 64*260e9a87SYuri Pankov EQN_TOK_GSIZE, 65*260e9a87SYuri Pankov EQN_TOK_GFONT, 66*260e9a87SYuri Pankov EQN_TOK_MARK, 67*260e9a87SYuri Pankov EQN_TOK_LINEUP, 68*260e9a87SYuri Pankov EQN_TOK_LEFT, 69*260e9a87SYuri Pankov EQN_TOK_RIGHT, 70*260e9a87SYuri Pankov EQN_TOK_PILE, 71*260e9a87SYuri Pankov EQN_TOK_LPILE, 72*260e9a87SYuri Pankov EQN_TOK_RPILE, 73*260e9a87SYuri Pankov EQN_TOK_CPILE, 74*260e9a87SYuri Pankov EQN_TOK_MATRIX, 75*260e9a87SYuri Pankov EQN_TOK_CCOL, 76*260e9a87SYuri Pankov EQN_TOK_LCOL, 77*260e9a87SYuri Pankov EQN_TOK_RCOL, 78*260e9a87SYuri Pankov EQN_TOK_DELIM, 79*260e9a87SYuri Pankov EQN_TOK_DEFINE, 80*260e9a87SYuri Pankov EQN_TOK_TDEFINE, 81*260e9a87SYuri Pankov EQN_TOK_NDEFINE, 82*260e9a87SYuri Pankov EQN_TOK_UNDEF, 83*260e9a87SYuri Pankov EQN_TOK_EOF, 84*260e9a87SYuri Pankov EQN_TOK_ABOVE, 85*260e9a87SYuri Pankov EQN_TOK__MAX 86*260e9a87SYuri Pankov }; 87*260e9a87SYuri Pankov 88*260e9a87SYuri Pankov static const char *eqn_toks[EQN_TOK__MAX] = { 89*260e9a87SYuri Pankov "dyad", /* EQN_TOK_DYAD */ 90*260e9a87SYuri Pankov "vec", /* EQN_TOK_VEC */ 91*260e9a87SYuri Pankov "under", /* EQN_TOK_UNDER */ 92*260e9a87SYuri Pankov "bar", /* EQN_TOK_BAR */ 93*260e9a87SYuri Pankov "tilde", /* EQN_TOK_TILDE */ 94*260e9a87SYuri Pankov "hat", /* EQN_TOK_HAT */ 95*260e9a87SYuri Pankov "dot", /* EQN_TOK_DOT */ 96*260e9a87SYuri Pankov "dotdot", /* EQN_TOK_DOTDOT */ 97*260e9a87SYuri Pankov "fwd", /* EQN_TOK_FWD * */ 98*260e9a87SYuri Pankov "back", /* EQN_TOK_BACK */ 99*260e9a87SYuri Pankov "down", /* EQN_TOK_DOWN */ 100*260e9a87SYuri Pankov "up", /* EQN_TOK_UP */ 101*260e9a87SYuri Pankov "fat", /* EQN_TOK_FAT */ 102*260e9a87SYuri Pankov "roman", /* EQN_TOK_ROMAN */ 103*260e9a87SYuri Pankov "italic", /* EQN_TOK_ITALIC */ 104*260e9a87SYuri Pankov "bold", /* EQN_TOK_BOLD */ 105*260e9a87SYuri Pankov "size", /* EQN_TOK_SIZE */ 106*260e9a87SYuri Pankov "sub", /* EQN_TOK_SUB */ 107*260e9a87SYuri Pankov "sup", /* EQN_TOK_SUP */ 108*260e9a87SYuri Pankov "sqrt", /* EQN_TOK_SQRT */ 109*260e9a87SYuri Pankov "over", /* EQN_TOK_OVER */ 110*260e9a87SYuri Pankov "from", /* EQN_TOK_FROM */ 111*260e9a87SYuri Pankov "to", /* EQN_TOK_TO */ 112*260e9a87SYuri Pankov "{", /* EQN_TOK_BRACE_OPEN */ 113*260e9a87SYuri Pankov "}", /* EQN_TOK_BRACE_CLOSE */ 114*260e9a87SYuri Pankov "gsize", /* EQN_TOK_GSIZE */ 115*260e9a87SYuri Pankov "gfont", /* EQN_TOK_GFONT */ 116*260e9a87SYuri Pankov "mark", /* EQN_TOK_MARK */ 117*260e9a87SYuri Pankov "lineup", /* EQN_TOK_LINEUP */ 118*260e9a87SYuri Pankov "left", /* EQN_TOK_LEFT */ 119*260e9a87SYuri Pankov "right", /* EQN_TOK_RIGHT */ 120*260e9a87SYuri Pankov "pile", /* EQN_TOK_PILE */ 121*260e9a87SYuri Pankov "lpile", /* EQN_TOK_LPILE */ 122*260e9a87SYuri Pankov "rpile", /* EQN_TOK_RPILE */ 123*260e9a87SYuri Pankov "cpile", /* EQN_TOK_CPILE */ 124*260e9a87SYuri Pankov "matrix", /* EQN_TOK_MATRIX */ 125*260e9a87SYuri Pankov "ccol", /* EQN_TOK_CCOL */ 126*260e9a87SYuri Pankov "lcol", /* EQN_TOK_LCOL */ 127*260e9a87SYuri Pankov "rcol", /* EQN_TOK_RCOL */ 128*260e9a87SYuri Pankov "delim", /* EQN_TOK_DELIM */ 129*260e9a87SYuri Pankov "define", /* EQN_TOK_DEFINE */ 130*260e9a87SYuri Pankov "tdefine", /* EQN_TOK_TDEFINE */ 131*260e9a87SYuri Pankov "ndefine", /* EQN_TOK_NDEFINE */ 132*260e9a87SYuri Pankov "undef", /* EQN_TOK_UNDEF */ 133*260e9a87SYuri Pankov NULL, /* EQN_TOK_EOF */ 134*260e9a87SYuri Pankov "above", /* EQN_TOK_ABOVE */ 13595c635efSGarrett D'Amore }; 13695c635efSGarrett D'Amore 13795c635efSGarrett D'Amore enum eqn_symt { 13895c635efSGarrett D'Amore EQNSYM_alpha, 13995c635efSGarrett D'Amore EQNSYM_beta, 14095c635efSGarrett D'Amore EQNSYM_chi, 14195c635efSGarrett D'Amore EQNSYM_delta, 14295c635efSGarrett D'Amore EQNSYM_epsilon, 14395c635efSGarrett D'Amore EQNSYM_eta, 14495c635efSGarrett D'Amore EQNSYM_gamma, 14595c635efSGarrett D'Amore EQNSYM_iota, 14695c635efSGarrett D'Amore EQNSYM_kappa, 14795c635efSGarrett D'Amore EQNSYM_lambda, 14895c635efSGarrett D'Amore EQNSYM_mu, 14995c635efSGarrett D'Amore EQNSYM_nu, 15095c635efSGarrett D'Amore EQNSYM_omega, 15195c635efSGarrett D'Amore EQNSYM_omicron, 15295c635efSGarrett D'Amore EQNSYM_phi, 15395c635efSGarrett D'Amore EQNSYM_pi, 15495c635efSGarrett D'Amore EQNSYM_ps, 15595c635efSGarrett D'Amore EQNSYM_rho, 15695c635efSGarrett D'Amore EQNSYM_sigma, 15795c635efSGarrett D'Amore EQNSYM_tau, 15895c635efSGarrett D'Amore EQNSYM_theta, 15995c635efSGarrett D'Amore EQNSYM_upsilon, 16095c635efSGarrett D'Amore EQNSYM_xi, 16195c635efSGarrett D'Amore EQNSYM_zeta, 16295c635efSGarrett D'Amore EQNSYM_DELTA, 16395c635efSGarrett D'Amore EQNSYM_GAMMA, 16495c635efSGarrett D'Amore EQNSYM_LAMBDA, 16595c635efSGarrett D'Amore EQNSYM_OMEGA, 16695c635efSGarrett D'Amore EQNSYM_PHI, 16795c635efSGarrett D'Amore EQNSYM_PI, 16895c635efSGarrett D'Amore EQNSYM_PSI, 16995c635efSGarrett D'Amore EQNSYM_SIGMA, 17095c635efSGarrett D'Amore EQNSYM_THETA, 17195c635efSGarrett D'Amore EQNSYM_UPSILON, 17295c635efSGarrett D'Amore EQNSYM_XI, 17395c635efSGarrett D'Amore EQNSYM_inter, 17495c635efSGarrett D'Amore EQNSYM_union, 17595c635efSGarrett D'Amore EQNSYM_prod, 17695c635efSGarrett D'Amore EQNSYM_int, 17795c635efSGarrett D'Amore EQNSYM_sum, 17895c635efSGarrett D'Amore EQNSYM_grad, 17995c635efSGarrett D'Amore EQNSYM_del, 18095c635efSGarrett D'Amore EQNSYM_times, 18195c635efSGarrett D'Amore EQNSYM_cdot, 18295c635efSGarrett D'Amore EQNSYM_nothing, 18395c635efSGarrett D'Amore EQNSYM_approx, 18495c635efSGarrett D'Amore EQNSYM_prime, 18595c635efSGarrett D'Amore EQNSYM_half, 18695c635efSGarrett D'Amore EQNSYM_partial, 18795c635efSGarrett D'Amore EQNSYM_inf, 18895c635efSGarrett D'Amore EQNSYM_muchgreat, 18995c635efSGarrett D'Amore EQNSYM_muchless, 19095c635efSGarrett D'Amore EQNSYM_larrow, 19195c635efSGarrett D'Amore EQNSYM_rarrow, 19295c635efSGarrett D'Amore EQNSYM_pm, 19395c635efSGarrett D'Amore EQNSYM_nequal, 19495c635efSGarrett D'Amore EQNSYM_equiv, 19595c635efSGarrett D'Amore EQNSYM_lessequal, 19695c635efSGarrett D'Amore EQNSYM_moreequal, 197*260e9a87SYuri Pankov EQNSYM_minus, 19895c635efSGarrett D'Amore EQNSYM__MAX 19995c635efSGarrett D'Amore }; 20095c635efSGarrett D'Amore 20195c635efSGarrett D'Amore struct eqnsym { 202*260e9a87SYuri Pankov const char *str; 20395c635efSGarrett D'Amore const char *sym; 20495c635efSGarrett D'Amore }; 20595c635efSGarrett D'Amore 20695c635efSGarrett D'Amore static const struct eqnsym eqnsyms[EQNSYM__MAX] = { 207*260e9a87SYuri Pankov { "alpha", "*a" }, /* EQNSYM_alpha */ 208*260e9a87SYuri Pankov { "beta", "*b" }, /* EQNSYM_beta */ 209*260e9a87SYuri Pankov { "chi", "*x" }, /* EQNSYM_chi */ 210*260e9a87SYuri Pankov { "delta", "*d" }, /* EQNSYM_delta */ 211*260e9a87SYuri Pankov { "epsilon", "*e" }, /* EQNSYM_epsilon */ 212*260e9a87SYuri Pankov { "eta", "*y" }, /* EQNSYM_eta */ 213*260e9a87SYuri Pankov { "gamma", "*g" }, /* EQNSYM_gamma */ 214*260e9a87SYuri Pankov { "iota", "*i" }, /* EQNSYM_iota */ 215*260e9a87SYuri Pankov { "kappa", "*k" }, /* EQNSYM_kappa */ 216*260e9a87SYuri Pankov { "lambda", "*l" }, /* EQNSYM_lambda */ 217*260e9a87SYuri Pankov { "mu", "*m" }, /* EQNSYM_mu */ 218*260e9a87SYuri Pankov { "nu", "*n" }, /* EQNSYM_nu */ 219*260e9a87SYuri Pankov { "omega", "*w" }, /* EQNSYM_omega */ 220*260e9a87SYuri Pankov { "omicron", "*o" }, /* EQNSYM_omicron */ 221*260e9a87SYuri Pankov { "phi", "*f" }, /* EQNSYM_phi */ 222*260e9a87SYuri Pankov { "pi", "*p" }, /* EQNSYM_pi */ 223*260e9a87SYuri Pankov { "psi", "*q" }, /* EQNSYM_psi */ 224*260e9a87SYuri Pankov { "rho", "*r" }, /* EQNSYM_rho */ 225*260e9a87SYuri Pankov { "sigma", "*s" }, /* EQNSYM_sigma */ 226*260e9a87SYuri Pankov { "tau", "*t" }, /* EQNSYM_tau */ 227*260e9a87SYuri Pankov { "theta", "*h" }, /* EQNSYM_theta */ 228*260e9a87SYuri Pankov { "upsilon", "*u" }, /* EQNSYM_upsilon */ 229*260e9a87SYuri Pankov { "xi", "*c" }, /* EQNSYM_xi */ 230*260e9a87SYuri Pankov { "zeta", "*z" }, /* EQNSYM_zeta */ 231*260e9a87SYuri Pankov { "DELTA", "*D" }, /* EQNSYM_DELTA */ 232*260e9a87SYuri Pankov { "GAMMA", "*G" }, /* EQNSYM_GAMMA */ 233*260e9a87SYuri Pankov { "LAMBDA", "*L" }, /* EQNSYM_LAMBDA */ 234*260e9a87SYuri Pankov { "OMEGA", "*W" }, /* EQNSYM_OMEGA */ 235*260e9a87SYuri Pankov { "PHI", "*F" }, /* EQNSYM_PHI */ 236*260e9a87SYuri Pankov { "PI", "*P" }, /* EQNSYM_PI */ 237*260e9a87SYuri Pankov { "PSI", "*Q" }, /* EQNSYM_PSI */ 238*260e9a87SYuri Pankov { "SIGMA", "*S" }, /* EQNSYM_SIGMA */ 239*260e9a87SYuri Pankov { "THETA", "*H" }, /* EQNSYM_THETA */ 240*260e9a87SYuri Pankov { "UPSILON", "*U" }, /* EQNSYM_UPSILON */ 241*260e9a87SYuri Pankov { "XI", "*C" }, /* EQNSYM_XI */ 242*260e9a87SYuri Pankov { "inter", "ca" }, /* EQNSYM_inter */ 243*260e9a87SYuri Pankov { "union", "cu" }, /* EQNSYM_union */ 244*260e9a87SYuri Pankov { "prod", "product" }, /* EQNSYM_prod */ 245*260e9a87SYuri Pankov { "int", "integral" }, /* EQNSYM_int */ 246*260e9a87SYuri Pankov { "sum", "sum" }, /* EQNSYM_sum */ 247*260e9a87SYuri Pankov { "grad", "gr" }, /* EQNSYM_grad */ 248*260e9a87SYuri Pankov { "del", "gr" }, /* EQNSYM_del */ 249*260e9a87SYuri Pankov { "times", "mu" }, /* EQNSYM_times */ 250*260e9a87SYuri Pankov { "cdot", "pc" }, /* EQNSYM_cdot */ 251*260e9a87SYuri Pankov { "nothing", "&" }, /* EQNSYM_nothing */ 252*260e9a87SYuri Pankov { "approx", "~~" }, /* EQNSYM_approx */ 253*260e9a87SYuri Pankov { "prime", "fm" }, /* EQNSYM_prime */ 254*260e9a87SYuri Pankov { "half", "12" }, /* EQNSYM_half */ 255*260e9a87SYuri Pankov { "partial", "pd" }, /* EQNSYM_partial */ 256*260e9a87SYuri Pankov { "inf", "if" }, /* EQNSYM_inf */ 257*260e9a87SYuri Pankov { ">>", ">>" }, /* EQNSYM_muchgreat */ 258*260e9a87SYuri Pankov { "<<", "<<" }, /* EQNSYM_muchless */ 259*260e9a87SYuri Pankov { "<-", "<-" }, /* EQNSYM_larrow */ 260*260e9a87SYuri Pankov { "->", "->" }, /* EQNSYM_rarrow */ 261*260e9a87SYuri Pankov { "+-", "+-" }, /* EQNSYM_pm */ 262*260e9a87SYuri Pankov { "!=", "!=" }, /* EQNSYM_nequal */ 263*260e9a87SYuri Pankov { "==", "==" }, /* EQNSYM_equiv */ 264*260e9a87SYuri Pankov { "<=", "<=" }, /* EQNSYM_lessequal */ 265*260e9a87SYuri Pankov { ">=", ">=" }, /* EQNSYM_moreequal */ 266*260e9a87SYuri Pankov { "-", "mi" }, /* EQNSYM_minus */ 26795c635efSGarrett D'Amore }; 26895c635efSGarrett D'Amore 269*260e9a87SYuri Pankov static struct eqn_box *eqn_box_alloc(struct eqn_node *, struct eqn_box *); 270*260e9a87SYuri Pankov static void eqn_box_free(struct eqn_box *); 271*260e9a87SYuri Pankov static struct eqn_box *eqn_box_makebinary(struct eqn_node *, 272*260e9a87SYuri Pankov enum eqn_post, struct eqn_box *); 273*260e9a87SYuri Pankov static void eqn_def(struct eqn_node *); 274*260e9a87SYuri Pankov static struct eqn_def *eqn_def_find(struct eqn_node *, const char *, size_t); 275*260e9a87SYuri Pankov static void eqn_delim(struct eqn_node *); 276*260e9a87SYuri Pankov static const char *eqn_next(struct eqn_node *, char, size_t *, int); 277*260e9a87SYuri Pankov static const char *eqn_nextrawtok(struct eqn_node *, size_t *); 278*260e9a87SYuri Pankov static const char *eqn_nexttok(struct eqn_node *, size_t *); 279*260e9a87SYuri Pankov static enum rofferr eqn_parse(struct eqn_node *, struct eqn_box *); 280*260e9a87SYuri Pankov static enum eqn_tok eqn_tok_parse(struct eqn_node *, char **); 281*260e9a87SYuri Pankov static void eqn_undef(struct eqn_node *); 282*260e9a87SYuri Pankov 283*260e9a87SYuri Pankov 28495c635efSGarrett D'Amore enum rofferr 28595c635efSGarrett D'Amore eqn_read(struct eqn_node **epp, int ln, 28695c635efSGarrett D'Amore const char *p, int pos, int *offs) 28795c635efSGarrett D'Amore { 28895c635efSGarrett D'Amore size_t sz; 28995c635efSGarrett D'Amore struct eqn_node *ep; 29095c635efSGarrett D'Amore enum rofferr er; 29195c635efSGarrett D'Amore 29295c635efSGarrett D'Amore ep = *epp; 29395c635efSGarrett D'Amore 29495c635efSGarrett D'Amore /* 29595c635efSGarrett D'Amore * If we're the terminating mark, unset our equation status and 29695c635efSGarrett D'Amore * validate the full equation. 29795c635efSGarrett D'Amore */ 29895c635efSGarrett D'Amore 29995c635efSGarrett D'Amore if (0 == strncmp(p, ".EN", 3)) { 30095c635efSGarrett D'Amore er = eqn_end(epp); 30195c635efSGarrett D'Amore p += 3; 30295c635efSGarrett D'Amore while (' ' == *p || '\t' == *p) 30395c635efSGarrett D'Amore p++; 30495c635efSGarrett D'Amore if ('\0' == *p) 30595c635efSGarrett D'Amore return(er); 306*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_ARG_SKIP, ep->parse, 307*260e9a87SYuri Pankov ln, pos, "EN %s", p); 30895c635efSGarrett D'Amore return(er); 30995c635efSGarrett D'Amore } 31095c635efSGarrett D'Amore 31195c635efSGarrett D'Amore /* 31295c635efSGarrett D'Amore * Build up the full string, replacing all newlines with regular 31395c635efSGarrett D'Amore * whitespace. 31495c635efSGarrett D'Amore */ 31595c635efSGarrett D'Amore 31695c635efSGarrett D'Amore sz = strlen(p + pos) + 1; 31795c635efSGarrett D'Amore ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1); 31895c635efSGarrett D'Amore 31995c635efSGarrett D'Amore /* First invocation: nil terminate the string. */ 32095c635efSGarrett D'Amore 32195c635efSGarrett D'Amore if (0 == ep->sz) 32295c635efSGarrett D'Amore *ep->data = '\0'; 32395c635efSGarrett D'Amore 32495c635efSGarrett D'Amore ep->sz += sz; 32595c635efSGarrett D'Amore strlcat(ep->data, p + pos, ep->sz + 1); 32695c635efSGarrett D'Amore strlcat(ep->data, " ", ep->sz + 1); 32795c635efSGarrett D'Amore return(ROFF_IGN); 32895c635efSGarrett D'Amore } 32995c635efSGarrett D'Amore 33095c635efSGarrett D'Amore struct eqn_node * 331*260e9a87SYuri Pankov eqn_alloc(int pos, int line, struct mparse *parse) 33295c635efSGarrett D'Amore { 33395c635efSGarrett D'Amore struct eqn_node *p; 33495c635efSGarrett D'Amore 33595c635efSGarrett D'Amore p = mandoc_calloc(1, sizeof(struct eqn_node)); 33695c635efSGarrett D'Amore 33795c635efSGarrett D'Amore p->parse = parse; 33895c635efSGarrett D'Amore p->eqn.ln = line; 33995c635efSGarrett D'Amore p->eqn.pos = pos; 34095c635efSGarrett D'Amore p->gsize = EQN_DEFSIZE; 34195c635efSGarrett D'Amore 34295c635efSGarrett D'Amore return(p); 34395c635efSGarrett D'Amore } 34495c635efSGarrett D'Amore 345*260e9a87SYuri Pankov /* 346*260e9a87SYuri Pankov * Find the key "key" of the give size within our eqn-defined values. 347*260e9a87SYuri Pankov */ 348*260e9a87SYuri Pankov static struct eqn_def * 349*260e9a87SYuri Pankov eqn_def_find(struct eqn_node *ep, const char *key, size_t sz) 35095c635efSGarrett D'Amore { 35195c635efSGarrett D'Amore int i; 35295c635efSGarrett D'Amore 353*260e9a87SYuri Pankov for (i = 0; i < (int)ep->defsz; i++) 354*260e9a87SYuri Pankov if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key, 355*260e9a87SYuri Pankov ep->defs[i].keysz, key, sz)) 356*260e9a87SYuri Pankov return(&ep->defs[i]); 35795c635efSGarrett D'Amore 358*260e9a87SYuri Pankov return(NULL); 35995c635efSGarrett D'Amore } 36095c635efSGarrett D'Amore 361*260e9a87SYuri Pankov /* 362*260e9a87SYuri Pankov * Get the next token from the input stream using the given quote 363*260e9a87SYuri Pankov * character. 364*260e9a87SYuri Pankov * Optionally make any replacements. 365*260e9a87SYuri Pankov */ 36695c635efSGarrett D'Amore static const char * 36795c635efSGarrett D'Amore eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl) 36895c635efSGarrett D'Amore { 36995c635efSGarrett D'Amore char *start, *next; 37095c635efSGarrett D'Amore int q, diff, lim; 37195c635efSGarrett D'Amore size_t ssz, dummy; 37295c635efSGarrett D'Amore struct eqn_def *def; 37395c635efSGarrett D'Amore 37495c635efSGarrett D'Amore if (NULL == sz) 37595c635efSGarrett D'Amore sz = &dummy; 37695c635efSGarrett D'Amore 37795c635efSGarrett D'Amore lim = 0; 37895c635efSGarrett D'Amore ep->rew = ep->cur; 37995c635efSGarrett D'Amore again: 38095c635efSGarrett D'Amore /* Prevent self-definitions. */ 38195c635efSGarrett D'Amore 38295c635efSGarrett D'Amore if (lim >= EQN_NEST_MAX) { 383*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ROFFLOOP, ep->parse, 384*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, NULL); 38595c635efSGarrett D'Amore return(NULL); 38695c635efSGarrett D'Amore } 38795c635efSGarrett D'Amore 38895c635efSGarrett D'Amore ep->cur = ep->rew; 38995c635efSGarrett D'Amore start = &ep->data[(int)ep->cur]; 39095c635efSGarrett D'Amore q = 0; 39195c635efSGarrett D'Amore 39295c635efSGarrett D'Amore if ('\0' == *start) 39395c635efSGarrett D'Amore return(NULL); 39495c635efSGarrett D'Amore 39595c635efSGarrett D'Amore if (quote == *start) { 39695c635efSGarrett D'Amore ep->cur++; 39795c635efSGarrett D'Amore q = 1; 39895c635efSGarrett D'Amore } 39995c635efSGarrett D'Amore 40095c635efSGarrett D'Amore start = &ep->data[(int)ep->cur]; 40195c635efSGarrett D'Amore 40295c635efSGarrett D'Amore if ( ! q) { 40395c635efSGarrett D'Amore if ('{' == *start || '}' == *start) 40495c635efSGarrett D'Amore ssz = 1; 40595c635efSGarrett D'Amore else 40695c635efSGarrett D'Amore ssz = strcspn(start + 1, " ^~\"{}\t") + 1; 40795c635efSGarrett D'Amore next = start + (int)ssz; 40895c635efSGarrett D'Amore if ('\0' == *next) 40995c635efSGarrett D'Amore next = NULL; 41095c635efSGarrett D'Amore } else 41195c635efSGarrett D'Amore next = strchr(start, quote); 41295c635efSGarrett D'Amore 41395c635efSGarrett D'Amore if (NULL != next) { 41495c635efSGarrett D'Amore *sz = (size_t)(next - start); 41595c635efSGarrett D'Amore ep->cur += *sz; 41695c635efSGarrett D'Amore if (q) 41795c635efSGarrett D'Amore ep->cur++; 41895c635efSGarrett D'Amore while (' ' == ep->data[(int)ep->cur] || 41995c635efSGarrett D'Amore '\t' == ep->data[(int)ep->cur] || 42095c635efSGarrett D'Amore '^' == ep->data[(int)ep->cur] || 42195c635efSGarrett D'Amore '~' == ep->data[(int)ep->cur]) 42295c635efSGarrett D'Amore ep->cur++; 42395c635efSGarrett D'Amore } else { 42495c635efSGarrett D'Amore if (q) 425*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_ARG_QUOTE, ep->parse, 426*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, NULL); 42795c635efSGarrett D'Amore next = strchr(start, '\0'); 42895c635efSGarrett D'Amore *sz = (size_t)(next - start); 42995c635efSGarrett D'Amore ep->cur += *sz; 43095c635efSGarrett D'Amore } 43195c635efSGarrett D'Amore 43295c635efSGarrett D'Amore /* Quotes aren't expanded for values. */ 43395c635efSGarrett D'Amore 43495c635efSGarrett D'Amore if (q || ! repl) 43595c635efSGarrett D'Amore return(start); 43695c635efSGarrett D'Amore 43795c635efSGarrett D'Amore if (NULL != (def = eqn_def_find(ep, start, *sz))) { 43895c635efSGarrett D'Amore diff = def->valsz - *sz; 43995c635efSGarrett D'Amore 44095c635efSGarrett D'Amore if (def->valsz > *sz) { 44195c635efSGarrett D'Amore ep->sz += diff; 44295c635efSGarrett D'Amore ep->data = mandoc_realloc(ep->data, ep->sz + 1); 44395c635efSGarrett D'Amore ep->data[ep->sz] = '\0'; 44495c635efSGarrett D'Amore start = &ep->data[(int)ep->rew]; 44595c635efSGarrett D'Amore } 44695c635efSGarrett D'Amore 44795c635efSGarrett D'Amore diff = def->valsz - *sz; 44895c635efSGarrett D'Amore memmove(start + *sz + diff, start + *sz, 44995c635efSGarrett D'Amore (strlen(start) - *sz) + 1); 45095c635efSGarrett D'Amore memcpy(start, def->val, def->valsz); 45195c635efSGarrett D'Amore goto again; 45295c635efSGarrett D'Amore } 45395c635efSGarrett D'Amore 45495c635efSGarrett D'Amore return(start); 45595c635efSGarrett D'Amore } 45695c635efSGarrett D'Amore 457*260e9a87SYuri Pankov /* 458*260e9a87SYuri Pankov * Get the next delimited token using the default current quote 459*260e9a87SYuri Pankov * character. 460*260e9a87SYuri Pankov */ 461*260e9a87SYuri Pankov static const char * 462*260e9a87SYuri Pankov eqn_nexttok(struct eqn_node *ep, size_t *sz) 46395c635efSGarrett D'Amore { 46495c635efSGarrett D'Amore 465*260e9a87SYuri Pankov return(eqn_next(ep, '"', sz, 1)); 46695c635efSGarrett D'Amore } 46795c635efSGarrett D'Amore 468*260e9a87SYuri Pankov /* 469*260e9a87SYuri Pankov * Get next token without replacement. 470*260e9a87SYuri Pankov */ 471*260e9a87SYuri Pankov static const char * 472*260e9a87SYuri Pankov eqn_nextrawtok(struct eqn_node *ep, size_t *sz) 47395c635efSGarrett D'Amore { 47495c635efSGarrett D'Amore 475*260e9a87SYuri Pankov return(eqn_next(ep, '"', sz, 0)); 47695c635efSGarrett D'Amore } 47795c635efSGarrett D'Amore 478*260e9a87SYuri Pankov /* 479*260e9a87SYuri Pankov * Parse a token from the stream of text. 480*260e9a87SYuri Pankov * A token consists of one of the recognised eqn(7) strings. 481*260e9a87SYuri Pankov * Strings are separated by delimiting marks. 482*260e9a87SYuri Pankov * This returns EQN_TOK_EOF when there are no more tokens. 483*260e9a87SYuri Pankov * If the token is an unrecognised string literal, then it returns 484*260e9a87SYuri Pankov * EQN_TOK__MAX and sets the "p" pointer to an allocated, nil-terminated 485*260e9a87SYuri Pankov * string. 486*260e9a87SYuri Pankov * This must be later freed with free(3). 487*260e9a87SYuri Pankov */ 488*260e9a87SYuri Pankov static enum eqn_tok 489*260e9a87SYuri Pankov eqn_tok_parse(struct eqn_node *ep, char **p) 490*260e9a87SYuri Pankov { 491*260e9a87SYuri Pankov const char *start; 492*260e9a87SYuri Pankov size_t i, sz; 493*260e9a87SYuri Pankov int quoted; 494*260e9a87SYuri Pankov 495*260e9a87SYuri Pankov if (NULL != p) 496*260e9a87SYuri Pankov *p = NULL; 497*260e9a87SYuri Pankov 498*260e9a87SYuri Pankov quoted = ep->data[ep->cur] == '"'; 499*260e9a87SYuri Pankov 500*260e9a87SYuri Pankov if (NULL == (start = eqn_nexttok(ep, &sz))) 501*260e9a87SYuri Pankov return(EQN_TOK_EOF); 502*260e9a87SYuri Pankov 503*260e9a87SYuri Pankov if (quoted) { 504*260e9a87SYuri Pankov if (p != NULL) 505*260e9a87SYuri Pankov *p = mandoc_strndup(start, sz); 506*260e9a87SYuri Pankov return(EQN_TOK__MAX); 507*260e9a87SYuri Pankov } 508*260e9a87SYuri Pankov 509*260e9a87SYuri Pankov for (i = 0; i < EQN_TOK__MAX; i++) { 510*260e9a87SYuri Pankov if (NULL == eqn_toks[i]) 511*260e9a87SYuri Pankov continue; 512*260e9a87SYuri Pankov if (STRNEQ(start, sz, eqn_toks[i], strlen(eqn_toks[i]))) 513*260e9a87SYuri Pankov break; 514*260e9a87SYuri Pankov } 515*260e9a87SYuri Pankov 516*260e9a87SYuri Pankov if (i == EQN_TOK__MAX && NULL != p) 517*260e9a87SYuri Pankov *p = mandoc_strndup(start, sz); 518*260e9a87SYuri Pankov 519*260e9a87SYuri Pankov return(i); 520*260e9a87SYuri Pankov } 521*260e9a87SYuri Pankov 522*260e9a87SYuri Pankov static void 523*260e9a87SYuri Pankov eqn_box_free(struct eqn_box *bp) 52495c635efSGarrett D'Amore { 52595c635efSGarrett D'Amore 526*260e9a87SYuri Pankov if (bp->first) 527*260e9a87SYuri Pankov eqn_box_free(bp->first); 528*260e9a87SYuri Pankov if (bp->next) 529*260e9a87SYuri Pankov eqn_box_free(bp->next); 53095c635efSGarrett D'Amore 531*260e9a87SYuri Pankov free(bp->text); 532*260e9a87SYuri Pankov free(bp->left); 533*260e9a87SYuri Pankov free(bp->right); 534*260e9a87SYuri Pankov free(bp->top); 535*260e9a87SYuri Pankov free(bp->bottom); 536*260e9a87SYuri Pankov free(bp); 53795c635efSGarrett D'Amore } 53895c635efSGarrett D'Amore 539*260e9a87SYuri Pankov /* 540*260e9a87SYuri Pankov * Allocate a box as the last child of the parent node. 541*260e9a87SYuri Pankov */ 542*260e9a87SYuri Pankov static struct eqn_box * 543*260e9a87SYuri Pankov eqn_box_alloc(struct eqn_node *ep, struct eqn_box *parent) 544*260e9a87SYuri Pankov { 545*260e9a87SYuri Pankov struct eqn_box *bp; 546*260e9a87SYuri Pankov 547*260e9a87SYuri Pankov bp = mandoc_calloc(1, sizeof(struct eqn_box)); 548*260e9a87SYuri Pankov bp->parent = parent; 549*260e9a87SYuri Pankov bp->parent->args++; 550*260e9a87SYuri Pankov bp->expectargs = UINT_MAX; 551*260e9a87SYuri Pankov bp->size = ep->gsize; 552*260e9a87SYuri Pankov 553*260e9a87SYuri Pankov if (NULL != parent->first) { 554*260e9a87SYuri Pankov parent->last->next = bp; 555*260e9a87SYuri Pankov bp->prev = parent->last; 556*260e9a87SYuri Pankov } else 557*260e9a87SYuri Pankov parent->first = bp; 558*260e9a87SYuri Pankov 559*260e9a87SYuri Pankov parent->last = bp; 560*260e9a87SYuri Pankov return(bp); 561*260e9a87SYuri Pankov } 562*260e9a87SYuri Pankov 563*260e9a87SYuri Pankov /* 564*260e9a87SYuri Pankov * Reparent the current last node (of the current parent) under a new 565*260e9a87SYuri Pankov * EQN_SUBEXPR as the first element. 566*260e9a87SYuri Pankov * Then return the new parent. 567*260e9a87SYuri Pankov * The new EQN_SUBEXPR will have a two-child limit. 568*260e9a87SYuri Pankov */ 569*260e9a87SYuri Pankov static struct eqn_box * 570*260e9a87SYuri Pankov eqn_box_makebinary(struct eqn_node *ep, 571*260e9a87SYuri Pankov enum eqn_post pos, struct eqn_box *parent) 572*260e9a87SYuri Pankov { 573*260e9a87SYuri Pankov struct eqn_box *b, *newb; 574*260e9a87SYuri Pankov 575*260e9a87SYuri Pankov assert(NULL != parent->last); 576*260e9a87SYuri Pankov b = parent->last; 577*260e9a87SYuri Pankov if (parent->last == parent->first) 578*260e9a87SYuri Pankov parent->first = NULL; 579*260e9a87SYuri Pankov parent->args--; 580*260e9a87SYuri Pankov parent->last = b->prev; 581*260e9a87SYuri Pankov b->prev = NULL; 582*260e9a87SYuri Pankov newb = eqn_box_alloc(ep, parent); 583*260e9a87SYuri Pankov newb->pos = pos; 584*260e9a87SYuri Pankov newb->type = EQN_SUBEXPR; 585*260e9a87SYuri Pankov newb->expectargs = 2; 586*260e9a87SYuri Pankov newb->args = 1; 587*260e9a87SYuri Pankov newb->first = newb->last = b; 588*260e9a87SYuri Pankov newb->first->next = NULL; 589*260e9a87SYuri Pankov b->parent = newb; 590*260e9a87SYuri Pankov return(newb); 591*260e9a87SYuri Pankov } 592*260e9a87SYuri Pankov 593*260e9a87SYuri Pankov /* 594*260e9a87SYuri Pankov * Parse the "delim" control statement. 595*260e9a87SYuri Pankov */ 596*260e9a87SYuri Pankov static void 597*260e9a87SYuri Pankov eqn_delim(struct eqn_node *ep) 598*260e9a87SYuri Pankov { 599*260e9a87SYuri Pankov const char *start; 600*260e9a87SYuri Pankov size_t sz; 601*260e9a87SYuri Pankov 602*260e9a87SYuri Pankov if ((start = eqn_nextrawtok(ep, &sz)) == NULL) 603*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, 604*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "delim"); 605*260e9a87SYuri Pankov else if (strncmp(start, "off", 3) == 0) 606*260e9a87SYuri Pankov ep->delim = 0; 607*260e9a87SYuri Pankov else if (strncmp(start, "on", 2) == 0) { 608*260e9a87SYuri Pankov if (ep->odelim && ep->cdelim) 609*260e9a87SYuri Pankov ep->delim = 1; 610*260e9a87SYuri Pankov } else if (start[1] != '\0') { 611*260e9a87SYuri Pankov ep->odelim = start[0]; 612*260e9a87SYuri Pankov ep->cdelim = start[1]; 613*260e9a87SYuri Pankov ep->delim = 1; 614*260e9a87SYuri Pankov } 615*260e9a87SYuri Pankov } 616*260e9a87SYuri Pankov 617*260e9a87SYuri Pankov /* 618*260e9a87SYuri Pankov * Undefine a previously-defined string. 619*260e9a87SYuri Pankov */ 620*260e9a87SYuri Pankov static void 621*260e9a87SYuri Pankov eqn_undef(struct eqn_node *ep) 622*260e9a87SYuri Pankov { 623*260e9a87SYuri Pankov const char *start; 624*260e9a87SYuri Pankov struct eqn_def *def; 625*260e9a87SYuri Pankov size_t sz; 626*260e9a87SYuri Pankov 627*260e9a87SYuri Pankov if ((start = eqn_nextrawtok(ep, &sz)) == NULL) { 628*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, 629*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "undef"); 630*260e9a87SYuri Pankov return; 631*260e9a87SYuri Pankov } 632*260e9a87SYuri Pankov if ((def = eqn_def_find(ep, start, sz)) == NULL) 633*260e9a87SYuri Pankov return; 634*260e9a87SYuri Pankov free(def->key); 635*260e9a87SYuri Pankov free(def->val); 636*260e9a87SYuri Pankov def->key = def->val = NULL; 637*260e9a87SYuri Pankov def->keysz = def->valsz = 0; 638*260e9a87SYuri Pankov } 639*260e9a87SYuri Pankov 640*260e9a87SYuri Pankov static void 641*260e9a87SYuri Pankov eqn_def(struct eqn_node *ep) 64295c635efSGarrett D'Amore { 64395c635efSGarrett D'Amore const char *start; 64495c635efSGarrett D'Amore size_t sz; 64595c635efSGarrett D'Amore struct eqn_def *def; 64695c635efSGarrett D'Amore int i; 64795c635efSGarrett D'Amore 648*260e9a87SYuri Pankov if ((start = eqn_nextrawtok(ep, &sz)) == NULL) { 649*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, 650*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "define"); 651*260e9a87SYuri Pankov return; 65295c635efSGarrett D'Amore } 65395c635efSGarrett D'Amore 65495c635efSGarrett D'Amore /* 65595c635efSGarrett D'Amore * Search for a key that already exists. 65695c635efSGarrett D'Amore * Create a new key if none is found. 65795c635efSGarrett D'Amore */ 65895c635efSGarrett D'Amore if (NULL == (def = eqn_def_find(ep, start, sz))) { 65995c635efSGarrett D'Amore /* Find holes in string array. */ 66095c635efSGarrett D'Amore for (i = 0; i < (int)ep->defsz; i++) 66195c635efSGarrett D'Amore if (0 == ep->defs[i].keysz) 66295c635efSGarrett D'Amore break; 66395c635efSGarrett D'Amore 66495c635efSGarrett D'Amore if (i == (int)ep->defsz) { 66595c635efSGarrett D'Amore ep->defsz++; 666*260e9a87SYuri Pankov ep->defs = mandoc_reallocarray(ep->defs, 667*260e9a87SYuri Pankov ep->defsz, sizeof(struct eqn_def)); 66895c635efSGarrett D'Amore ep->defs[i].key = ep->defs[i].val = NULL; 66995c635efSGarrett D'Amore } 67095c635efSGarrett D'Amore 671*260e9a87SYuri Pankov def = ep->defs + i; 672*260e9a87SYuri Pankov free(def->key); 673*260e9a87SYuri Pankov def->key = mandoc_strndup(start, sz); 674*260e9a87SYuri Pankov def->keysz = sz; 67595c635efSGarrett D'Amore } 67695c635efSGarrett D'Amore 67795c635efSGarrett D'Amore start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0); 678*260e9a87SYuri Pankov if (start == NULL) { 679*260e9a87SYuri Pankov mandoc_vmsg(MANDOCERR_REQ_EMPTY, ep->parse, 680*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "define %s", def->key); 681*260e9a87SYuri Pankov free(def->key); 682*260e9a87SYuri Pankov free(def->val); 683*260e9a87SYuri Pankov def->key = def->val = NULL; 684*260e9a87SYuri Pankov def->keysz = def->valsz = 0; 685*260e9a87SYuri Pankov return; 68695c635efSGarrett D'Amore } 687*260e9a87SYuri Pankov free(def->val); 688*260e9a87SYuri Pankov def->val = mandoc_strndup(start, sz); 68995c635efSGarrett D'Amore def->valsz = sz; 69095c635efSGarrett D'Amore } 69195c635efSGarrett D'Amore 692*260e9a87SYuri Pankov /* 693*260e9a87SYuri Pankov * Recursively parse an eqn(7) expression. 694*260e9a87SYuri Pankov */ 695*260e9a87SYuri Pankov static enum rofferr 696*260e9a87SYuri Pankov eqn_parse(struct eqn_node *ep, struct eqn_box *parent) 69795c635efSGarrett D'Amore { 698*260e9a87SYuri Pankov char sym[64]; 699*260e9a87SYuri Pankov struct eqn_box *cur; 70095c635efSGarrett D'Amore const char *start; 701*260e9a87SYuri Pankov char *p; 702*260e9a87SYuri Pankov size_t i, sz; 703*260e9a87SYuri Pankov enum eqn_tok tok, subtok; 704*260e9a87SYuri Pankov enum eqn_post pos; 705*260e9a87SYuri Pankov int size; 70695c635efSGarrett D'Amore 707*260e9a87SYuri Pankov assert(parent != NULL); 708*260e9a87SYuri Pankov 709*260e9a87SYuri Pankov /* 710*260e9a87SYuri Pankov * Empty equation. 711*260e9a87SYuri Pankov * Do not add it to the high-level syntax tree. 712*260e9a87SYuri Pankov */ 713*260e9a87SYuri Pankov 714*260e9a87SYuri Pankov if (ep->data == NULL) 715*260e9a87SYuri Pankov return(ROFF_IGN); 716*260e9a87SYuri Pankov 717*260e9a87SYuri Pankov next_tok: 718*260e9a87SYuri Pankov tok = eqn_tok_parse(ep, &p); 719*260e9a87SYuri Pankov 720*260e9a87SYuri Pankov this_tok: 721*260e9a87SYuri Pankov switch (tok) { 722*260e9a87SYuri Pankov case (EQN_TOK_UNDEF): 723*260e9a87SYuri Pankov eqn_undef(ep); 724*260e9a87SYuri Pankov break; 725*260e9a87SYuri Pankov case (EQN_TOK_NDEFINE): 726*260e9a87SYuri Pankov case (EQN_TOK_DEFINE): 727*260e9a87SYuri Pankov eqn_def(ep); 728*260e9a87SYuri Pankov break; 729*260e9a87SYuri Pankov case (EQN_TOK_TDEFINE): 730*260e9a87SYuri Pankov if (eqn_nextrawtok(ep, NULL) == NULL || 731*260e9a87SYuri Pankov eqn_next(ep, ep->data[(int)ep->cur], NULL, 0) == NULL) 732*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, 733*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, "tdefine"); 734*260e9a87SYuri Pankov break; 735*260e9a87SYuri Pankov case (EQN_TOK_DELIM): 736*260e9a87SYuri Pankov eqn_delim(ep); 737*260e9a87SYuri Pankov break; 738*260e9a87SYuri Pankov case (EQN_TOK_GFONT): 739*260e9a87SYuri Pankov if (eqn_nextrawtok(ep, NULL) == NULL) 740*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, 741*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 742*260e9a87SYuri Pankov break; 743*260e9a87SYuri Pankov case (EQN_TOK_MARK): 744*260e9a87SYuri Pankov case (EQN_TOK_LINEUP): 745*260e9a87SYuri Pankov /* Ignore these. */ 746*260e9a87SYuri Pankov break; 747*260e9a87SYuri Pankov case (EQN_TOK_DYAD): 748*260e9a87SYuri Pankov case (EQN_TOK_VEC): 749*260e9a87SYuri Pankov case (EQN_TOK_UNDER): 750*260e9a87SYuri Pankov case (EQN_TOK_BAR): 751*260e9a87SYuri Pankov case (EQN_TOK_TILDE): 752*260e9a87SYuri Pankov case (EQN_TOK_HAT): 753*260e9a87SYuri Pankov case (EQN_TOK_DOT): 754*260e9a87SYuri Pankov case (EQN_TOK_DOTDOT): 755*260e9a87SYuri Pankov if (parent->last == NULL) { 756*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, 757*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 758*260e9a87SYuri Pankov cur = eqn_box_alloc(ep, parent); 759*260e9a87SYuri Pankov cur->type = EQN_TEXT; 760*260e9a87SYuri Pankov cur->text = mandoc_strdup(""); 76195c635efSGarrett D'Amore } 762*260e9a87SYuri Pankov parent = eqn_box_makebinary(ep, EQNPOS_NONE, parent); 763*260e9a87SYuri Pankov parent->type = EQN_LISTONE; 764*260e9a87SYuri Pankov parent->expectargs = 1; 765*260e9a87SYuri Pankov switch (tok) { 766*260e9a87SYuri Pankov case (EQN_TOK_DOTDOT): 767*260e9a87SYuri Pankov strlcpy(sym, "\\[ad]", sizeof(sym)); 768*260e9a87SYuri Pankov break; 769*260e9a87SYuri Pankov case (EQN_TOK_VEC): 770*260e9a87SYuri Pankov strlcpy(sym, "\\[->]", sizeof(sym)); 771*260e9a87SYuri Pankov break; 772*260e9a87SYuri Pankov case (EQN_TOK_DYAD): 773*260e9a87SYuri Pankov strlcpy(sym, "\\[<>]", sizeof(sym)); 774*260e9a87SYuri Pankov break; 775*260e9a87SYuri Pankov case (EQN_TOK_TILDE): 776*260e9a87SYuri Pankov strlcpy(sym, "\\[a~]", sizeof(sym)); 777*260e9a87SYuri Pankov break; 778*260e9a87SYuri Pankov case (EQN_TOK_UNDER): 779*260e9a87SYuri Pankov strlcpy(sym, "\\[ul]", sizeof(sym)); 780*260e9a87SYuri Pankov break; 781*260e9a87SYuri Pankov case (EQN_TOK_BAR): 782*260e9a87SYuri Pankov strlcpy(sym, "\\[rl]", sizeof(sym)); 783*260e9a87SYuri Pankov break; 784*260e9a87SYuri Pankov case (EQN_TOK_DOT): 785*260e9a87SYuri Pankov strlcpy(sym, "\\[a.]", sizeof(sym)); 786*260e9a87SYuri Pankov break; 787*260e9a87SYuri Pankov case (EQN_TOK_HAT): 788*260e9a87SYuri Pankov strlcpy(sym, "\\[ha]", sizeof(sym)); 789*260e9a87SYuri Pankov break; 790*260e9a87SYuri Pankov default: 791*260e9a87SYuri Pankov abort(); 79295c635efSGarrett D'Amore } 79395c635efSGarrett D'Amore 794*260e9a87SYuri Pankov switch (tok) { 795*260e9a87SYuri Pankov case (EQN_TOK_DOTDOT): 796*260e9a87SYuri Pankov case (EQN_TOK_VEC): 797*260e9a87SYuri Pankov case (EQN_TOK_DYAD): 798*260e9a87SYuri Pankov case (EQN_TOK_TILDE): 799*260e9a87SYuri Pankov case (EQN_TOK_BAR): 800*260e9a87SYuri Pankov case (EQN_TOK_DOT): 801*260e9a87SYuri Pankov case (EQN_TOK_HAT): 802*260e9a87SYuri Pankov parent->top = mandoc_strdup(sym); 803*260e9a87SYuri Pankov break; 804*260e9a87SYuri Pankov case (EQN_TOK_UNDER): 805*260e9a87SYuri Pankov parent->bottom = mandoc_strdup(sym); 806*260e9a87SYuri Pankov break; 807*260e9a87SYuri Pankov default: 808*260e9a87SYuri Pankov abort(); 809*260e9a87SYuri Pankov } 810*260e9a87SYuri Pankov parent = parent->parent; 811*260e9a87SYuri Pankov break; 812*260e9a87SYuri Pankov case (EQN_TOK_FWD): 813*260e9a87SYuri Pankov case (EQN_TOK_BACK): 814*260e9a87SYuri Pankov case (EQN_TOK_DOWN): 815*260e9a87SYuri Pankov case (EQN_TOK_UP): 816*260e9a87SYuri Pankov subtok = eqn_tok_parse(ep, NULL); 817*260e9a87SYuri Pankov if (subtok != EQN_TOK__MAX) { 818*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, 819*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 820*260e9a87SYuri Pankov tok = subtok; 821*260e9a87SYuri Pankov goto this_tok; 822*260e9a87SYuri Pankov } 823*260e9a87SYuri Pankov break; 824*260e9a87SYuri Pankov case (EQN_TOK_FAT): 825*260e9a87SYuri Pankov case (EQN_TOK_ROMAN): 826*260e9a87SYuri Pankov case (EQN_TOK_ITALIC): 827*260e9a87SYuri Pankov case (EQN_TOK_BOLD): 828*260e9a87SYuri Pankov while (parent->args == parent->expectargs) 829*260e9a87SYuri Pankov parent = parent->parent; 830*260e9a87SYuri Pankov /* 831*260e9a87SYuri Pankov * These values apply to the next word or sequence of 832*260e9a87SYuri Pankov * words; thus, we mark that we'll have a child with 833*260e9a87SYuri Pankov * exactly one of those. 834*260e9a87SYuri Pankov */ 835*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent); 836*260e9a87SYuri Pankov parent->type = EQN_LISTONE; 837*260e9a87SYuri Pankov parent->expectargs = 1; 838*260e9a87SYuri Pankov switch (tok) { 839*260e9a87SYuri Pankov case (EQN_TOK_FAT): 840*260e9a87SYuri Pankov parent->font = EQNFONT_FAT; 841*260e9a87SYuri Pankov break; 842*260e9a87SYuri Pankov case (EQN_TOK_ROMAN): 843*260e9a87SYuri Pankov parent->font = EQNFONT_ROMAN; 844*260e9a87SYuri Pankov break; 845*260e9a87SYuri Pankov case (EQN_TOK_ITALIC): 846*260e9a87SYuri Pankov parent->font = EQNFONT_ITALIC; 847*260e9a87SYuri Pankov break; 848*260e9a87SYuri Pankov case (EQN_TOK_BOLD): 849*260e9a87SYuri Pankov parent->font = EQNFONT_BOLD; 850*260e9a87SYuri Pankov break; 851*260e9a87SYuri Pankov default: 852*260e9a87SYuri Pankov abort(); 853*260e9a87SYuri Pankov } 854*260e9a87SYuri Pankov break; 855*260e9a87SYuri Pankov case (EQN_TOK_SIZE): 856*260e9a87SYuri Pankov case (EQN_TOK_GSIZE): 857*260e9a87SYuri Pankov /* Accept two values: integral size and a single. */ 858*260e9a87SYuri Pankov if (NULL == (start = eqn_nexttok(ep, &sz))) { 859*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, 860*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 861*260e9a87SYuri Pankov break; 862*260e9a87SYuri Pankov } 863*260e9a87SYuri Pankov size = mandoc_strntoi(start, sz, 10); 864*260e9a87SYuri Pankov if (-1 == size) { 865*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_IT_NONUM, ep->parse, 866*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 867*260e9a87SYuri Pankov break; 868*260e9a87SYuri Pankov } 869*260e9a87SYuri Pankov if (EQN_TOK_GSIZE == tok) { 870*260e9a87SYuri Pankov ep->gsize = size; 871*260e9a87SYuri Pankov break; 872*260e9a87SYuri Pankov } 873*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent); 874*260e9a87SYuri Pankov parent->type = EQN_LISTONE; 875*260e9a87SYuri Pankov parent->expectargs = 1; 876*260e9a87SYuri Pankov parent->size = size; 877*260e9a87SYuri Pankov break; 878*260e9a87SYuri Pankov case (EQN_TOK_FROM): 879*260e9a87SYuri Pankov case (EQN_TOK_TO): 880*260e9a87SYuri Pankov case (EQN_TOK_SUB): 881*260e9a87SYuri Pankov case (EQN_TOK_SUP): 882*260e9a87SYuri Pankov /* 883*260e9a87SYuri Pankov * We have a left-right-associative expression. 884*260e9a87SYuri Pankov * Repivot under a positional node, open a child scope 885*260e9a87SYuri Pankov * and keep on reading. 886*260e9a87SYuri Pankov */ 887*260e9a87SYuri Pankov if (parent->last == NULL) { 888*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, 889*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 890*260e9a87SYuri Pankov cur = eqn_box_alloc(ep, parent); 891*260e9a87SYuri Pankov cur->type = EQN_TEXT; 892*260e9a87SYuri Pankov cur->text = mandoc_strdup(""); 893*260e9a87SYuri Pankov } 894*260e9a87SYuri Pankov /* Handle the "subsup" and "fromto" positions. */ 895*260e9a87SYuri Pankov if (EQN_TOK_SUP == tok && parent->pos == EQNPOS_SUB) { 896*260e9a87SYuri Pankov parent->expectargs = 3; 897*260e9a87SYuri Pankov parent->pos = EQNPOS_SUBSUP; 898*260e9a87SYuri Pankov break; 899*260e9a87SYuri Pankov } 900*260e9a87SYuri Pankov if (EQN_TOK_TO == tok && parent->pos == EQNPOS_FROM) { 901*260e9a87SYuri Pankov parent->expectargs = 3; 902*260e9a87SYuri Pankov parent->pos = EQNPOS_FROMTO; 903*260e9a87SYuri Pankov break; 904*260e9a87SYuri Pankov } 905*260e9a87SYuri Pankov switch (tok) { 906*260e9a87SYuri Pankov case (EQN_TOK_FROM): 907*260e9a87SYuri Pankov pos = EQNPOS_FROM; 908*260e9a87SYuri Pankov break; 909*260e9a87SYuri Pankov case (EQN_TOK_TO): 910*260e9a87SYuri Pankov pos = EQNPOS_TO; 911*260e9a87SYuri Pankov break; 912*260e9a87SYuri Pankov case (EQN_TOK_SUP): 913*260e9a87SYuri Pankov pos = EQNPOS_SUP; 914*260e9a87SYuri Pankov break; 915*260e9a87SYuri Pankov case (EQN_TOK_SUB): 916*260e9a87SYuri Pankov pos = EQNPOS_SUB; 917*260e9a87SYuri Pankov break; 918*260e9a87SYuri Pankov default: 919*260e9a87SYuri Pankov abort(); 920*260e9a87SYuri Pankov } 921*260e9a87SYuri Pankov parent = eqn_box_makebinary(ep, pos, parent); 922*260e9a87SYuri Pankov break; 923*260e9a87SYuri Pankov case (EQN_TOK_SQRT): 924*260e9a87SYuri Pankov while (parent->args == parent->expectargs) 925*260e9a87SYuri Pankov parent = parent->parent; 926*260e9a87SYuri Pankov /* 927*260e9a87SYuri Pankov * Accept a left-right-associative set of arguments just 928*260e9a87SYuri Pankov * like sub and sup and friends but without rebalancing 929*260e9a87SYuri Pankov * under a pivot. 930*260e9a87SYuri Pankov */ 931*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent); 932*260e9a87SYuri Pankov parent->type = EQN_SUBEXPR; 933*260e9a87SYuri Pankov parent->pos = EQNPOS_SQRT; 934*260e9a87SYuri Pankov parent->expectargs = 1; 935*260e9a87SYuri Pankov break; 936*260e9a87SYuri Pankov case (EQN_TOK_OVER): 937*260e9a87SYuri Pankov /* 938*260e9a87SYuri Pankov * We have a right-left-associative fraction. 939*260e9a87SYuri Pankov * Close out anything that's currently open, then 940*260e9a87SYuri Pankov * rebalance and continue reading. 941*260e9a87SYuri Pankov */ 942*260e9a87SYuri Pankov if (parent->last == NULL) { 943*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_EQN_NOBOX, ep->parse, 944*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 945*260e9a87SYuri Pankov cur = eqn_box_alloc(ep, parent); 946*260e9a87SYuri Pankov cur->type = EQN_TEXT; 947*260e9a87SYuri Pankov cur->text = mandoc_strdup(""); 948*260e9a87SYuri Pankov } 949*260e9a87SYuri Pankov while (EQN_SUBEXPR == parent->type) 950*260e9a87SYuri Pankov parent = parent->parent; 951*260e9a87SYuri Pankov parent = eqn_box_makebinary(ep, EQNPOS_OVER, parent); 952*260e9a87SYuri Pankov break; 953*260e9a87SYuri Pankov case (EQN_TOK_RIGHT): 954*260e9a87SYuri Pankov case (EQN_TOK_BRACE_CLOSE): 955*260e9a87SYuri Pankov /* 956*260e9a87SYuri Pankov * Close out the existing brace. 957*260e9a87SYuri Pankov * FIXME: this is a shitty sentinel: we should really 958*260e9a87SYuri Pankov * have a native EQN_BRACE type or whatnot. 959*260e9a87SYuri Pankov */ 960*260e9a87SYuri Pankov for (cur = parent; cur != NULL; cur = cur->parent) 961*260e9a87SYuri Pankov if (cur->type == EQN_LIST && 962*260e9a87SYuri Pankov (tok == EQN_TOK_BRACE_CLOSE || 963*260e9a87SYuri Pankov cur->left != NULL)) 964*260e9a87SYuri Pankov break; 965*260e9a87SYuri Pankov if (cur == NULL) { 966*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_BLK_NOTOPEN, ep->parse, 967*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 968*260e9a87SYuri Pankov break; 969*260e9a87SYuri Pankov } 970*260e9a87SYuri Pankov parent = cur; 971*260e9a87SYuri Pankov if (EQN_TOK_RIGHT == tok) { 972*260e9a87SYuri Pankov if (NULL == (start = eqn_nexttok(ep, &sz))) { 973*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, 974*260e9a87SYuri Pankov ep->parse, ep->eqn.ln, 975*260e9a87SYuri Pankov ep->eqn.pos, eqn_toks[tok]); 976*260e9a87SYuri Pankov break; 977*260e9a87SYuri Pankov } 978*260e9a87SYuri Pankov /* Handling depends on right/left. */ 979*260e9a87SYuri Pankov if (STRNEQ(start, sz, "ceiling", 7)) { 980*260e9a87SYuri Pankov strlcpy(sym, "\\[rc]", sizeof(sym)); 981*260e9a87SYuri Pankov parent->right = mandoc_strdup(sym); 982*260e9a87SYuri Pankov } else if (STRNEQ(start, sz, "floor", 5)) { 983*260e9a87SYuri Pankov strlcpy(sym, "\\[rf]", sizeof(sym)); 984*260e9a87SYuri Pankov parent->right = mandoc_strdup(sym); 985*260e9a87SYuri Pankov } else 986*260e9a87SYuri Pankov parent->right = mandoc_strndup(start, sz); 987*260e9a87SYuri Pankov } 988*260e9a87SYuri Pankov parent = parent->parent; 989*260e9a87SYuri Pankov if (EQN_TOK_BRACE_CLOSE == tok && parent && 990*260e9a87SYuri Pankov (parent->type == EQN_PILE || 991*260e9a87SYuri Pankov parent->type == EQN_MATRIX)) 992*260e9a87SYuri Pankov parent = parent->parent; 993*260e9a87SYuri Pankov /* Close out any "singleton" lists. */ 994*260e9a87SYuri Pankov while (parent->type == EQN_LISTONE && 995*260e9a87SYuri Pankov parent->args == parent->expectargs) 996*260e9a87SYuri Pankov parent = parent->parent; 997*260e9a87SYuri Pankov break; 998*260e9a87SYuri Pankov case (EQN_TOK_BRACE_OPEN): 999*260e9a87SYuri Pankov case (EQN_TOK_LEFT): 1000*260e9a87SYuri Pankov /* 1001*260e9a87SYuri Pankov * If we already have something in the stack and we're 1002*260e9a87SYuri Pankov * in an expression, then rewind til we're not any more 1003*260e9a87SYuri Pankov * (just like with the text node). 1004*260e9a87SYuri Pankov */ 1005*260e9a87SYuri Pankov while (parent->args == parent->expectargs) 1006*260e9a87SYuri Pankov parent = parent->parent; 1007*260e9a87SYuri Pankov if (EQN_TOK_LEFT == tok && 1008*260e9a87SYuri Pankov (start = eqn_nexttok(ep, &sz)) == NULL) { 1009*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_REQ_EMPTY, ep->parse, 1010*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 1011*260e9a87SYuri Pankov break; 1012*260e9a87SYuri Pankov } 1013*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent); 1014*260e9a87SYuri Pankov parent->type = EQN_LIST; 1015*260e9a87SYuri Pankov if (EQN_TOK_LEFT == tok) { 1016*260e9a87SYuri Pankov if (STRNEQ(start, sz, "ceiling", 7)) { 1017*260e9a87SYuri Pankov strlcpy(sym, "\\[lc]", sizeof(sym)); 1018*260e9a87SYuri Pankov parent->left = mandoc_strdup(sym); 1019*260e9a87SYuri Pankov } else if (STRNEQ(start, sz, "floor", 5)) { 1020*260e9a87SYuri Pankov strlcpy(sym, "\\[lf]", sizeof(sym)); 1021*260e9a87SYuri Pankov parent->left = mandoc_strdup(sym); 1022*260e9a87SYuri Pankov } else 1023*260e9a87SYuri Pankov parent->left = mandoc_strndup(start, sz); 1024*260e9a87SYuri Pankov } 1025*260e9a87SYuri Pankov break; 1026*260e9a87SYuri Pankov case (EQN_TOK_PILE): 1027*260e9a87SYuri Pankov case (EQN_TOK_LPILE): 1028*260e9a87SYuri Pankov case (EQN_TOK_RPILE): 1029*260e9a87SYuri Pankov case (EQN_TOK_CPILE): 1030*260e9a87SYuri Pankov case (EQN_TOK_CCOL): 1031*260e9a87SYuri Pankov case (EQN_TOK_LCOL): 1032*260e9a87SYuri Pankov case (EQN_TOK_RCOL): 1033*260e9a87SYuri Pankov while (parent->args == parent->expectargs) 1034*260e9a87SYuri Pankov parent = parent->parent; 1035*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent); 1036*260e9a87SYuri Pankov parent->type = EQN_PILE; 1037*260e9a87SYuri Pankov parent->expectargs = 1; 1038*260e9a87SYuri Pankov break; 1039*260e9a87SYuri Pankov case (EQN_TOK_ABOVE): 1040*260e9a87SYuri Pankov for (cur = parent; cur != NULL; cur = cur->parent) 1041*260e9a87SYuri Pankov if (cur->type == EQN_PILE) 1042*260e9a87SYuri Pankov break; 1043*260e9a87SYuri Pankov if (cur == NULL) { 1044*260e9a87SYuri Pankov mandoc_msg(MANDOCERR_IT_STRAY, ep->parse, 1045*260e9a87SYuri Pankov ep->eqn.ln, ep->eqn.pos, eqn_toks[tok]); 1046*260e9a87SYuri Pankov break; 1047*260e9a87SYuri Pankov } 1048*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, cur); 1049*260e9a87SYuri Pankov parent->type = EQN_LIST; 1050*260e9a87SYuri Pankov break; 1051*260e9a87SYuri Pankov case (EQN_TOK_MATRIX): 1052*260e9a87SYuri Pankov while (parent->args == parent->expectargs) 1053*260e9a87SYuri Pankov parent = parent->parent; 1054*260e9a87SYuri Pankov parent = eqn_box_alloc(ep, parent); 1055*260e9a87SYuri Pankov parent->type = EQN_MATRIX; 1056*260e9a87SYuri Pankov parent->expectargs = 1; 1057*260e9a87SYuri Pankov break; 1058*260e9a87SYuri Pankov case (EQN_TOK_EOF): 1059*260e9a87SYuri Pankov /* 1060*260e9a87SYuri Pankov * End of file! 1061*260e9a87SYuri Pankov * TODO: make sure we're not in an open subexpression. 1062*260e9a87SYuri Pankov */ 1063*260e9a87SYuri Pankov return(ROFF_EQN); 1064*260e9a87SYuri Pankov default: 1065*260e9a87SYuri Pankov assert(tok == EQN_TOK__MAX); 1066*260e9a87SYuri Pankov assert(NULL != p); 1067*260e9a87SYuri Pankov /* 1068*260e9a87SYuri Pankov * If we already have something in the stack and we're 1069*260e9a87SYuri Pankov * in an expression, then rewind til we're not any more. 1070*260e9a87SYuri Pankov */ 1071*260e9a87SYuri Pankov while (parent->args == parent->expectargs) 1072*260e9a87SYuri Pankov parent = parent->parent; 1073*260e9a87SYuri Pankov cur = eqn_box_alloc(ep, parent); 1074*260e9a87SYuri Pankov cur->type = EQN_TEXT; 1075*260e9a87SYuri Pankov for (i = 0; i < EQNSYM__MAX; i++) 1076*260e9a87SYuri Pankov if (0 == strcmp(eqnsyms[i].str, p)) { 1077*260e9a87SYuri Pankov (void)snprintf(sym, sizeof(sym), 1078*260e9a87SYuri Pankov "\\[%s]", eqnsyms[i].sym); 1079*260e9a87SYuri Pankov cur->text = mandoc_strdup(sym); 1080*260e9a87SYuri Pankov free(p); 1081*260e9a87SYuri Pankov break; 1082*260e9a87SYuri Pankov } 1083*260e9a87SYuri Pankov 1084*260e9a87SYuri Pankov if (i == EQNSYM__MAX) 1085*260e9a87SYuri Pankov cur->text = p; 1086*260e9a87SYuri Pankov /* 1087*260e9a87SYuri Pankov * Post-process list status. 1088*260e9a87SYuri Pankov */ 1089*260e9a87SYuri Pankov while (parent->type == EQN_LISTONE && 1090*260e9a87SYuri Pankov parent->args == parent->expectargs) 1091*260e9a87SYuri Pankov parent = parent->parent; 1092*260e9a87SYuri Pankov break; 1093*260e9a87SYuri Pankov } 1094*260e9a87SYuri Pankov goto next_tok; 1095*260e9a87SYuri Pankov } 1096*260e9a87SYuri Pankov 1097*260e9a87SYuri Pankov enum rofferr 1098*260e9a87SYuri Pankov eqn_end(struct eqn_node **epp) 109995c635efSGarrett D'Amore { 1100*260e9a87SYuri Pankov struct eqn_node *ep; 110195c635efSGarrett D'Amore 1102*260e9a87SYuri Pankov ep = *epp; 1103*260e9a87SYuri Pankov *epp = NULL; 110495c635efSGarrett D'Amore 1105*260e9a87SYuri Pankov ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box)); 1106*260e9a87SYuri Pankov ep->eqn.root->expectargs = UINT_MAX; 1107*260e9a87SYuri Pankov return(eqn_parse(ep, ep->eqn.root)); 110895c635efSGarrett D'Amore } 110995c635efSGarrett D'Amore 1110*260e9a87SYuri Pankov void 1111*260e9a87SYuri Pankov eqn_free(struct eqn_node *p) 111295c635efSGarrett D'Amore { 111395c635efSGarrett D'Amore int i; 111495c635efSGarrett D'Amore 1115*260e9a87SYuri Pankov eqn_box_free(p->eqn.root); 111695c635efSGarrett D'Amore 1117*260e9a87SYuri Pankov for (i = 0; i < (int)p->defsz; i++) { 1118*260e9a87SYuri Pankov free(p->defs[i].key); 1119*260e9a87SYuri Pankov free(p->defs[i].val); 1120*260e9a87SYuri Pankov } 1121*260e9a87SYuri Pankov 1122*260e9a87SYuri Pankov free(p->data); 1123*260e9a87SYuri Pankov free(p->defs); 1124*260e9a87SYuri Pankov free(p); 112595c635efSGarrett D'Amore } 1126