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

Annotation of mandoc/eqn.c, Revision 1.25

1.25    ! kristaps    1: /*     $Id: eqn.c,v 1.24 2011/07/22 10:22:47 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.17      kristaps   42: struct eqnstr {
1.8       kristaps   43:        const char      *name;
                     44:        size_t           sz;
                     45: };
                     46:
1.24      kristaps   47: #define        STRNEQ(p1, sz1, p2, sz2) \
1.25    ! kristaps   48:        ((sz1) == (sz2) && 0 == strncmp((p1), (p2), (sz1)))
1.24      kristaps   49: #define        EQNSTREQ(x, p, sz) \
                     50:        STRNEQ((x)->name, (x)->sz, (p), (sz))
                     51:
1.17      kristaps   52: struct eqnpart {
                     53:        struct eqnstr    str;
                     54:        int             (*fp)(struct eqn_node *);
1.16      kristaps   55: };
                     56:
1.8       kristaps   57: enum   eqnpartt {
                     58:        EQN_DEFINE = 0,
                     59:        EQN_SET,
                     60:        EQN_UNDEF,
                     61:        EQN__MAX
                     62: };
                     63:
1.23      kristaps   64: static enum eqn_rest    eqn_box(struct eqn_node *, struct eqn_box *);
1.20      kristaps   65: static struct eqn_box  *eqn_box_alloc(struct eqn_box *);
1.13      kristaps   66: static void             eqn_box_free(struct eqn_box *);
1.12      kristaps   67: static struct eqn_def  *eqn_def_find(struct eqn_node *,
                     68:                                const char *, size_t);
                     69: static int              eqn_do_define(struct eqn_node *);
1.14      kristaps   70: static int              eqn_do_set(struct eqn_node *);
1.12      kristaps   71: static int              eqn_do_undef(struct eqn_node *);
1.23      kristaps   72: static enum eqn_rest    eqn_eqn(struct eqn_node *, struct eqn_box *);
                     73: static enum eqn_rest    eqn_list(struct eqn_node *, struct eqn_box *);
1.12      kristaps   74: static const char      *eqn_nexttok(struct eqn_node *, size_t *);
1.14      kristaps   75: static const char      *eqn_nextrawtok(struct eqn_node *, size_t *);
                     76: static const char      *eqn_next(struct eqn_node *,
                     77:                                char, size_t *, int);
1.20      kristaps   78: static void             eqn_rewind(struct eqn_node *);
1.6       kristaps   79:
1.8       kristaps   80: static const struct eqnpart eqnparts[EQN__MAX] = {
1.17      kristaps   81:        { { "define", 6 }, eqn_do_define }, /* EQN_DEFINE */
                     82:        { { "set", 3 }, eqn_do_set }, /* EQN_SET */
                     83:        { { "undef", 5 }, eqn_do_undef }, /* EQN_UNDEF */
1.8       kristaps   84: };
                     85:
1.17      kristaps   86: static const struct eqnstr eqnmarks[EQNMARK__MAX] = {
1.16      kristaps   87:        { "", 0 }, /* EQNMARK_NONE */
                     88:        { "dot", 3 }, /* EQNMARK_DOT */
                     89:        { "dotdot", 6 }, /* EQNMARK_DOTDOT */
                     90:        { "hat", 3 }, /* EQNMARK_HAT */
                     91:        { "tilde", 5 }, /* EQNMARK_TILDE */
                     92:        { "vec", 3 }, /* EQNMARK_VEC */
                     93:        { "dyad", 4 }, /* EQNMARK_DYAD */
                     94:        { "bar", 3 }, /* EQNMARK_BAR */
                     95:        { "under", 5 }, /* EQNMARK_UNDER */
                     96: };
                     97:
1.17      kristaps   98: static const struct eqnstr eqnfonts[EQNFONT__MAX] = {
1.20      kristaps   99:        { "", 0 }, /* EQNFONT_NONE */
                    100:        { "roman", 5 }, /* EQNFONT_ROMAN */
                    101:        { "bold", 4 }, /* EQNFONT_BOLD */
                    102:        { "italic", 6 }, /* EQNFONT_ITALIC */
1.17      kristaps  103: };
                    104:
1.18      kristaps  105: static const struct eqnstr eqnposs[EQNPOS__MAX] = {
1.20      kristaps  106:        { "", 0 }, /* EQNPOS_NONE */
                    107:        { "over", 4 }, /* EQNPOS_OVER */
                    108:        { "sup", 3 }, /* EQNPOS_SUP */
                    109:        { "sub", 3 }, /* EQNPOS_SUB */
                    110:        { "to", 2 }, /* EQNPOS_TO */
                    111:        { "from", 4 }, /* EQNPOS_FROM */
                    112: };
                    113:
                    114: static const struct eqnstr eqnpiles[EQNPILE__MAX] = {
                    115:        { "", 0 }, /* EQNPILE_NONE */
                    116:        { "cpile", 5 }, /* EQNPILE_CPILE */
                    117:        { "rpile", 5 }, /* EQNPILE_RPILE */
                    118:        { "lpile", 5 }, /* EQNPILE_LPILE */
1.18      kristaps  119: };
                    120:
1.1       kristaps  121: /* ARGSUSED */
                    122: enum rofferr
1.6       kristaps  123: eqn_read(struct eqn_node **epp, int ln,
                    124:                const char *p, int pos, int *offs)
1.1       kristaps  125: {
1.8       kristaps  126:        size_t           sz;
                    127:        struct eqn_node *ep;
1.12      kristaps  128:        enum rofferr     er;
                    129:
                    130:        ep = *epp;
                    131:
                    132:        /*
                    133:         * If we're the terminating mark, unset our equation status and
                    134:         * validate the full equation.
                    135:         */
1.1       kristaps  136:
                    137:        if (0 == strcmp(p, ".EN")) {
1.12      kristaps  138:                er = eqn_end(ep);
1.1       kristaps  139:                *epp = NULL;
1.12      kristaps  140:                return(er);
1.1       kristaps  141:        }
                    142:
1.12      kristaps  143:        /*
                    144:         * Build up the full string, replacing all newlines with regular
                    145:         * whitespace.
                    146:         */
1.6       kristaps  147:
1.12      kristaps  148:        sz = strlen(p + pos) + 1;
                    149:        ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
1.6       kristaps  150:
1.12      kristaps  151:        /* First invocation: nil terminate the string. */
1.8       kristaps  152:
1.12      kristaps  153:        if (0 == ep->sz)
                    154:                *ep->data = '\0';
1.8       kristaps  155:
1.12      kristaps  156:        ep->sz += sz;
                    157:        strlcat(ep->data, p + pos, ep->sz + 1);
                    158:        strlcat(ep->data, " ", ep->sz + 1);
1.11      kristaps  159:        return(ROFF_IGN);
                    160: }
                    161:
1.1       kristaps  162: struct eqn_node *
1.5       kristaps  163: eqn_alloc(int pos, int line, struct mparse *parse)
1.1       kristaps  164: {
                    165:        struct eqn_node *p;
                    166:
                    167:        p = mandoc_calloc(1, sizeof(struct eqn_node));
1.5       kristaps  168:        p->parse = parse;
1.12      kristaps  169:        p->eqn.ln = line;
1.2       kristaps  170:        p->eqn.pos = pos;
1.1       kristaps  171:
                    172:        return(p);
                    173: }
                    174:
1.12      kristaps  175: enum rofferr
                    176: eqn_end(struct eqn_node *ep)
                    177: {
1.20      kristaps  178:        struct eqn_box  *root;
                    179:        enum eqn_rest    c;
                    180:
                    181:        ep->eqn.root = mandoc_calloc(1, sizeof(struct eqn_box));
1.13      kristaps  182:
1.20      kristaps  183:        root = ep->eqn.root;
1.13      kristaps  184:        root->type = EQN_ROOT;
                    185:
                    186:        if (0 == ep->sz)
                    187:                return(ROFF_IGN);
1.12      kristaps  188:
1.20      kristaps  189:        if (EQN_DESCOPE == (c = eqn_eqn(ep, root))) {
                    190:                EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
                    191:                c = EQN_ERR;
                    192:        }
                    193:
                    194:        return(EQN_EOF == c ? ROFF_EQN : ROFF_IGN);
                    195: }
                    196:
                    197: static enum eqn_rest
                    198: eqn_eqn(struct eqn_node *ep, struct eqn_box *last)
                    199: {
                    200:        struct eqn_box  *bp;
                    201:        enum eqn_rest    c;
                    202:
                    203:        bp = eqn_box_alloc(last);
                    204:        bp->type = EQN_SUBEXPR;
1.12      kristaps  205:
1.20      kristaps  206:        while (EQN_OK == (c = eqn_box(ep, bp)))
                    207:                /* Spin! */ ;
1.15      kristaps  208:
1.20      kristaps  209:        return(c);
1.12      kristaps  210: }
                    211:
1.20      kristaps  212: static enum eqn_rest
1.23      kristaps  213: eqn_list(struct eqn_node *ep, struct eqn_box *last)
                    214: {
                    215:        struct eqn_box  *bp;
                    216:        const char      *start;
                    217:        size_t           sz;
                    218:        enum eqn_rest    c;
                    219:
                    220:        bp = eqn_box_alloc(last);
                    221:        bp->type = EQN_LIST;
                    222:
                    223:        if (NULL == (start = eqn_nexttok(ep, &sz))) {
                    224:                EQN_MSG(MANDOCERR_EQNEOF, ep);
                    225:                return(EQN_ERR);
                    226:        }
1.24      kristaps  227:        if ( ! STRNEQ(start, sz, "{", 1)) {
1.23      kristaps  228:                EQN_MSG(MANDOCERR_EQNSYNT, ep);
                    229:                return(EQN_ERR);
                    230:        }
                    231:
                    232:        while (EQN_DESCOPE == (c = eqn_eqn(ep, bp))) {
                    233:                eqn_rewind(ep);
                    234:                start = eqn_nexttok(ep, &sz);
                    235:                assert(start);
1.24      kristaps  236:                if ( ! STRNEQ(start, sz, "above", 5))
1.23      kristaps  237:                        break;
                    238:                bp->last->above = 1;
                    239:        }
                    240:
                    241:        if (EQN_DESCOPE != c) {
                    242:                if (EQN_ERR != c)
                    243:                        EQN_MSG(MANDOCERR_EQNSCOPE, ep);
                    244:                return(EQN_ERR);
                    245:        }
                    246:
                    247:        eqn_rewind(ep);
                    248:        start = eqn_nexttok(ep, &sz);
                    249:        assert(start);
1.24      kristaps  250:        if (STRNEQ(start, sz, "}", 1))
1.23      kristaps  251:                return(EQN_OK);
                    252:
                    253:        EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
                    254:        return(EQN_ERR);
                    255: }
                    256:
                    257: static enum eqn_rest
1.20      kristaps  258: eqn_box(struct eqn_node *ep, struct eqn_box *last)
1.1       kristaps  259: {
1.12      kristaps  260:        size_t           sz;
                    261:        const char      *start;
1.20      kristaps  262:        char            *left;
                    263:        enum eqn_rest    c;
                    264:        int              i, size;
1.13      kristaps  265:        struct eqn_box  *bp;
1.12      kristaps  266:
1.20      kristaps  267:        if (NULL == (start = eqn_nexttok(ep, &sz)))
                    268:                return(EQN_EOF);
                    269:
1.24      kristaps  270:        if (STRNEQ(start, sz, "}", 1))
1.20      kristaps  271:                return(EQN_DESCOPE);
1.24      kristaps  272:        else if (STRNEQ(start, sz, "right", 5))
1.20      kristaps  273:                return(EQN_DESCOPE);
1.24      kristaps  274:        else if (STRNEQ(start, sz, "above", 5))
1.20      kristaps  275:                return(EQN_DESCOPE);
                    276:
                    277:        for (i = 0; i < (int)EQN__MAX; i++) {
1.24      kristaps  278:                if ( ! EQNSTREQ(&eqnparts[i].str, start, sz))
1.20      kristaps  279:                        continue;
                    280:                return((*eqnparts[i].fp)(ep) ? EQN_OK : EQN_ERR);
                    281:        }
1.15      kristaps  282:
1.24      kristaps  283:        if (STRNEQ(start, sz, "{", 1)) {
1.20      kristaps  284:                if (EQN_DESCOPE != (c = eqn_eqn(ep, last))) {
                    285:                        if (EQN_ERR != c)
                    286:                                EQN_MSG(MANDOCERR_EQNSCOPE, ep);
                    287:                        return(EQN_ERR);
                    288:                }
                    289:                eqn_rewind(ep);
                    290:                start = eqn_nexttok(ep, &sz);
                    291:                assert(start);
1.24      kristaps  292:                if (STRNEQ(start, sz, "}", 1))
1.20      kristaps  293:                        return(EQN_OK);
                    294:                EQN_MSG(MANDOCERR_EQNBADSCOPE, ep);
                    295:                return(EQN_ERR);
                    296:        }
1.12      kristaps  297:
1.20      kristaps  298:        for (i = 0; i < (int)EQNPILE__MAX; i++) {
1.24      kristaps  299:                if ( ! EQNSTREQ(&eqnpiles[i], start, sz))
1.17      kristaps  300:                        continue;
1.23      kristaps  301:                if (EQN_OK == (c = eqn_list(ep, last)))
1.21      kristaps  302:                        last->last->pile = (enum eqn_pilet)i;
1.23      kristaps  303:                return(c);
1.18      kristaps  304:        }
                    305:
1.24      kristaps  306:        if (STRNEQ(start, sz, "left", 4)) {
1.20      kristaps  307:                if (NULL == (start = eqn_nexttok(ep, &sz))) {
                    308:                        EQN_MSG(MANDOCERR_EQNEOF, ep);
                    309:                        return(EQN_ERR);
                    310:                }
                    311:                left = mandoc_strndup(start, sz);
                    312:                if (EQN_DESCOPE != (c = eqn_eqn(ep, last)))
                    313:                        return(c);
                    314:                assert(last->last);
                    315:                last->last->left = left;
                    316:                eqn_rewind(ep);
                    317:                start = eqn_nexttok(ep, &sz);
                    318:                assert(start);
1.24      kristaps  319:                if (STRNEQ(start, sz, "right", 5))
1.20      kristaps  320:                        return(EQN_DESCOPE);
                    321:                if (NULL == (start = eqn_nexttok(ep, &sz))) {
                    322:                        EQN_MSG(MANDOCERR_EQNEOF, ep);
                    323:                        return(EQN_ERR);
                    324:                }
                    325:                last->last->right = mandoc_strndup(start, sz);
                    326:                return(EQN_OK);
                    327:        }
                    328:
                    329:        for (i = 0; i < (int)EQNPOS__MAX; i++) {
1.24      kristaps  330:                if ( ! EQNSTREQ(&eqnposs[i], start, sz))
1.18      kristaps  331:                        continue;
1.20      kristaps  332:                if (NULL == last->last) {
                    333:                        EQN_MSG(MANDOCERR_EQNSYNT, ep);
                    334:                        return(EQN_ERR);
                    335:                }
                    336:                last->last->pos = (enum eqn_post)i;
                    337:                if (EQN_EOF == (c = eqn_box(ep, last))) {
                    338:                        EQN_MSG(MANDOCERR_EQNEOF, ep);
                    339:                        return(EQN_ERR);
                    340:                }
                    341:                return(c);
1.17      kristaps  342:        }
                    343:
1.16      kristaps  344:        for (i = 0; i < (int)EQNMARK__MAX; i++) {
1.24      kristaps  345:                if ( ! EQNSTREQ(&eqnmarks[i], start, sz))
1.16      kristaps  346:                        continue;
1.20      kristaps  347:                if (NULL == last->last) {
                    348:                        EQN_MSG(MANDOCERR_EQNSYNT, ep);
                    349:                        return(EQN_ERR);
                    350:                }
                    351:                last->last->mark = (enum eqn_markt)i;
                    352:                if (EQN_EOF == (c = eqn_box(ep, last))) {
                    353:                        EQN_MSG(MANDOCERR_EQNEOF, ep);
                    354:                        return(EQN_ERR);
                    355:                }
                    356:                return(c);
1.16      kristaps  357:        }
1.12      kristaps  358:
1.20      kristaps  359:        for (i = 0; i < (int)EQNFONT__MAX; i++) {
1.24      kristaps  360:                if ( ! EQNSTREQ(&eqnfonts[i], start, sz))
1.20      kristaps  361:                        continue;
                    362:                if (EQN_EOF == (c = eqn_box(ep, last))) {
                    363:                        EQN_MSG(MANDOCERR_EQNEOF, ep);
                    364:                        return(EQN_ERR);
                    365:                } else if (EQN_OK == c)
                    366:                        last->last->font = (enum eqn_fontt)i;
                    367:                return(c);
1.19      kristaps  368:        }
1.15      kristaps  369:
1.24      kristaps  370:        if (STRNEQ(start, sz, "size", 4)) {
1.20      kristaps  371:                if (NULL == (start = eqn_nexttok(ep, &sz))) {
                    372:                        EQN_MSG(MANDOCERR_EQNEOF, ep);
                    373:                        return(EQN_ERR);
                    374:                }
                    375:                size = mandoc_strntoi(start, sz, 10);
                    376:                if (EQN_EOF == (c = eqn_box(ep, last))) {
                    377:                        EQN_MSG(MANDOCERR_EQNEOF, ep);
                    378:                        return(EQN_ERR);
                    379:                } else if (EQN_OK != c)
                    380:                        return(c);
                    381:                last->last->size = size;
1.15      kristaps  382:        }
                    383:
1.20      kristaps  384:        bp = eqn_box_alloc(last);
1.15      kristaps  385:        bp->type = EQN_TEXT;
1.20      kristaps  386:        bp->text = mandoc_strndup(start, sz);
                    387:        return(EQN_OK);
1.1       kristaps  388: }
                    389:
                    390: void
                    391: eqn_free(struct eqn_node *p)
                    392: {
1.6       kristaps  393:        int              i;
1.1       kristaps  394:
1.13      kristaps  395:        eqn_box_free(p->eqn.root);
1.6       kristaps  396:
                    397:        for (i = 0; i < (int)p->defsz; i++) {
                    398:                free(p->defs[i].key);
                    399:                free(p->defs[i].val);
                    400:        }
                    401:
1.12      kristaps  402:        free(p->data);
1.6       kristaps  403:        free(p->defs);
1.1       kristaps  404:        free(p);
1.6       kristaps  405: }
                    406:
1.20      kristaps  407: static struct eqn_box *
                    408: eqn_box_alloc(struct eqn_box *parent)
                    409: {
                    410:        struct eqn_box  *bp;
                    411:
                    412:        bp = mandoc_calloc(1, sizeof(struct eqn_box));
                    413:        bp->parent = parent;
                    414:        bp->size = EQN_DEFSIZE;
                    415:
                    416:        if (NULL == parent->first)
                    417:                parent->first = bp;
                    418:        else
                    419:                parent->last->next = bp;
                    420:
                    421:        parent->last = bp;
                    422:        return(bp);
                    423: }
                    424:
1.13      kristaps  425: static void
                    426: eqn_box_free(struct eqn_box *bp)
                    427: {
                    428:
1.20      kristaps  429:        if (bp->first)
                    430:                eqn_box_free(bp->first);
1.13      kristaps  431:        if (bp->next)
                    432:                eqn_box_free(bp->next);
                    433:
                    434:        free(bp->text);
1.20      kristaps  435:        free(bp->left);
                    436:        free(bp->right);
1.13      kristaps  437:        free(bp);
                    438: }
                    439:
1.6       kristaps  440: static const char *
1.14      kristaps  441: eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
                    442: {
                    443:
                    444:        return(eqn_next(ep, '"', sz, 0));
                    445: }
                    446:
                    447: static const char *
1.12      kristaps  448: eqn_nexttok(struct eqn_node *ep, size_t *sz)
                    449: {
                    450:
1.14      kristaps  451:        return(eqn_next(ep, '"', sz, 1));
1.12      kristaps  452: }
                    453:
1.20      kristaps  454: static void
                    455: eqn_rewind(struct eqn_node *ep)
                    456: {
                    457:
                    458:        ep->cur = ep->rew;
                    459: }
                    460:
1.12      kristaps  461: static const char *
1.14      kristaps  462: eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
1.6       kristaps  463: {
1.12      kristaps  464:        char            *start, *next;
                    465:        int              q, diff, lim;
1.22      kristaps  466:        size_t           ssz, dummy;
1.12      kristaps  467:        struct eqn_def  *def;
                    468:
                    469:        if (NULL == sz)
1.22      kristaps  470:                sz = &dummy;
1.6       kristaps  471:
1.13      kristaps  472:        lim = 0;
1.20      kristaps  473:        ep->rew = ep->cur;
1.13      kristaps  474: again:
                    475:        /* Prevent self-definitions. */
                    476:
                    477:        if (lim >= EQN_NEST_MAX) {
                    478:                EQN_MSG(MANDOCERR_EQNNEST, ep);
                    479:                return(NULL);
                    480:        }
                    481:
1.20      kristaps  482:        ep->cur = ep->rew;
1.12      kristaps  483:        start = &ep->data[(int)ep->cur];
1.6       kristaps  484:        q = 0;
                    485:
                    486:        if ('\0' == *start)
                    487:                return(NULL);
                    488:
1.12      kristaps  489:        if (quote == *start) {
                    490:                ep->cur++;
1.6       kristaps  491:                q = 1;
                    492:        }
                    493:
1.12      kristaps  494:        start = &ep->data[(int)ep->cur];
1.22      kristaps  495:
                    496:        if ( ! q) {
                    497:                if ('{' == *start || '}' == *start)
                    498:                        ssz = 1;
                    499:                else
                    500:                        ssz = strcspn(start + 1, " ~\"{}\t") + 1;
                    501:                next = start + (int)ssz;
                    502:                if ('\0' == *next)
                    503:                        next = NULL;
                    504:        } else
                    505:                next = strchr(start, quote);
1.12      kristaps  506:
                    507:        if (NULL != next) {
                    508:                *sz = (size_t)(next - start);
                    509:                ep->cur += *sz;
1.6       kristaps  510:                if (q)
1.12      kristaps  511:                        ep->cur++;
1.22      kristaps  512:                while (' ' == ep->data[(int)ep->cur] ||
                    513:                                '\t' == ep->data[(int)ep->cur] ||
                    514:                                '~' == ep->data[(int)ep->cur])
1.12      kristaps  515:                        ep->cur++;
1.6       kristaps  516:        } else {
                    517:                if (q)
1.12      kristaps  518:                        EQN_MSG(MANDOCERR_BADQUOTE, ep);
                    519:                next = strchr(start, '\0');
                    520:                *sz = (size_t)(next - start);
                    521:                ep->cur += *sz;
                    522:        }
                    523:
1.13      kristaps  524:        /* Quotes aren't expanded for values. */
                    525:
1.14      kristaps  526:        if (q || ! repl)
1.13      kristaps  527:                return(start);
                    528:
1.12      kristaps  529:        if (NULL != (def = eqn_def_find(ep, start, *sz))) {
                    530:                diff = def->valsz - *sz;
                    531:
                    532:                if (def->valsz > *sz) {
                    533:                        ep->sz += diff;
                    534:                        ep->data = mandoc_realloc(ep->data, ep->sz + 1);
                    535:                        ep->data[ep->sz] = '\0';
1.20      kristaps  536:                        start = &ep->data[(int)ep->rew];
1.12      kristaps  537:                }
                    538:
                    539:                diff = def->valsz - *sz;
                    540:                memmove(start + *sz + diff, start + *sz,
                    541:                                (strlen(start) - *sz) + 1);
                    542:                memcpy(start, def->val, def->valsz);
                    543:                goto again;
1.6       kristaps  544:        }
                    545:
                    546:        return(start);
1.8       kristaps  547: }
                    548:
                    549: static int
1.14      kristaps  550: eqn_do_set(struct eqn_node *ep)
1.8       kristaps  551: {
                    552:        const char      *start;
                    553:
1.14      kristaps  554:        if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12      kristaps  555:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.14      kristaps  556:        else if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12      kristaps  557:                EQN_MSG(MANDOCERR_EQNARGS, ep);
                    558:        else
                    559:                return(1);
1.8       kristaps  560:
1.12      kristaps  561:        return(0);
1.8       kristaps  562: }
                    563:
                    564: static int
1.12      kristaps  565: eqn_do_define(struct eqn_node *ep)
1.8       kristaps  566: {
                    567:        const char      *start;
                    568:        size_t           sz;
1.12      kristaps  569:        struct eqn_def  *def;
1.8       kristaps  570:        int              i;
                    571:
1.14      kristaps  572:        if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12      kristaps  573:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8       kristaps  574:                return(0);
                    575:        }
                    576:
                    577:        /*
                    578:         * Search for a key that already exists.
1.12      kristaps  579:         * Create a new key if none is found.
1.8       kristaps  580:         */
                    581:
1.12      kristaps  582:        if (NULL == (def = eqn_def_find(ep, start, sz))) {
1.8       kristaps  583:                /* Find holes in string array. */
                    584:                for (i = 0; i < (int)ep->defsz; i++)
                    585:                        if (0 == ep->defs[i].keysz)
                    586:                                break;
                    587:
                    588:                if (i == (int)ep->defsz) {
                    589:                        ep->defsz++;
                    590:                        ep->defs = mandoc_realloc
                    591:                                (ep->defs, ep->defsz *
                    592:                                 sizeof(struct eqn_def));
1.9       kristaps  593:                        ep->defs[i].key = ep->defs[i].val = NULL;
1.8       kristaps  594:                }
                    595:
                    596:                ep->defs[i].keysz = sz;
                    597:                ep->defs[i].key = mandoc_realloc
                    598:                        (ep->defs[i].key, sz + 1);
                    599:
                    600:                memcpy(ep->defs[i].key, start, sz);
                    601:                ep->defs[i].key[(int)sz] = '\0';
1.12      kristaps  602:                def = &ep->defs[i];
1.8       kristaps  603:        }
                    604:
1.14      kristaps  605:        start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
1.8       kristaps  606:
1.12      kristaps  607:        if (NULL == start) {
                    608:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8       kristaps  609:                return(0);
                    610:        }
                    611:
1.12      kristaps  612:        def->valsz = sz;
1.13      kristaps  613:        def->val = mandoc_realloc(def->val, sz + 1);
1.12      kristaps  614:        memcpy(def->val, start, sz);
                    615:        def->val[(int)sz] = '\0';
                    616:        return(1);
1.8       kristaps  617: }
                    618:
                    619: static int
1.12      kristaps  620: eqn_do_undef(struct eqn_node *ep)
1.8       kristaps  621: {
                    622:        const char      *start;
1.12      kristaps  623:        struct eqn_def  *def;
1.8       kristaps  624:        size_t           sz;
                    625:
1.14      kristaps  626:        if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12      kristaps  627:                EQN_MSG(MANDOCERR_EQNARGS, ep);
                    628:                return(0);
                    629:        } else if (NULL != (def = eqn_def_find(ep, start, sz)))
                    630:                def->keysz = 0;
1.8       kristaps  631:
1.12      kristaps  632:        return(1);
                    633: }
                    634:
                    635: static struct eqn_def *
                    636: eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
                    637: {
                    638:        int              i;
1.8       kristaps  639:
1.12      kristaps  640:        for (i = 0; i < (int)ep->defsz; i++)
1.24      kristaps  641:                if (ep->defs[i].keysz && STRNEQ(ep->defs[i].key,
                    642:                                        ep->defs[i].keysz, key, sz))
1.12      kristaps  643:                        return(&ep->defs[i]);
1.8       kristaps  644:
1.12      kristaps  645:        return(NULL);
1.1       kristaps  646: }

CVSweb