[BACK]Return to eqn.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mandoc

Annotation of src/usr.bin/mandoc/eqn.c, Revision 1.11

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