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

Annotation of mandoc/eqn.c, Revision 1.20

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

CVSweb