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

Annotation of mandoc/eqn.c, Revision 1.23

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

CVSweb