[BACK]Return to eqn.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/eqn.c, Revision 1.28

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

CVSweb