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

Annotation of mandoc/eqn.c, Revision 1.27

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

CVSweb