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

Annotation of mandoc/eqn.c, Revision 1.14

1.14    ! kristaps    1: /*     $Id: eqn.c,v 1.13 2011/07/21 11:34:53 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>
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
                     25: #include <time.h>
                     26:
                     27: #include "mandoc.h"
                     28: #include "libmandoc.h"
                     29: #include "libroff.h"
                     30:
1.11      kristaps   31: #define        EQN_NEST_MAX     128 /* maximum nesting of defines */
1.12      kristaps   32: #define        EQN_MSG(t, x)    mandoc_msg((t), (x)->parse, (x)->eqn.ln, (x)->eqn.pos, NULL)
1.8       kristaps   33:
                     34: struct eqnpart {
                     35:        const char      *name;
                     36:        size_t           sz;
1.12      kristaps   37:        int             (*fp)(struct eqn_node *);
1.8       kristaps   38: };
                     39:
                     40: enum   eqnpartt {
                     41:        EQN_DEFINE = 0,
                     42:        EQN_SET,
                     43:        EQN_UNDEF,
                     44:        EQN__MAX
                     45: };
                     46:
1.13      kristaps   47: static void             eqn_box_free(struct eqn_box *);
1.12      kristaps   48: static struct eqn_def  *eqn_def_find(struct eqn_node *,
                     49:                                const char *, size_t);
                     50: static int              eqn_do_define(struct eqn_node *);
1.14    ! kristaps   51: static int              eqn_do_set(struct eqn_node *);
1.12      kristaps   52: static int              eqn_do_undef(struct eqn_node *);
                     53: static const char      *eqn_nexttok(struct eqn_node *, size_t *);
1.14    ! kristaps   54: static const char      *eqn_nextrawtok(struct eqn_node *, size_t *);
        !            55: static const char      *eqn_next(struct eqn_node *,
        !            56:                                char, size_t *, int);
1.13      kristaps   57: static int              eqn_box(struct eqn_node *, struct eqn_box *);
1.6       kristaps   58:
1.8       kristaps   59: static const struct eqnpart eqnparts[EQN__MAX] = {
                     60:        { "define", 6, eqn_do_define }, /* EQN_DEFINE */
1.14    ! kristaps   61:        { "set", 3, eqn_do_set }, /* EQN_SET */
1.8       kristaps   62:        { "undef", 5, eqn_do_undef }, /* EQN_UNDEF */
                     63: };
                     64:
1.1       kristaps   65: /* ARGSUSED */
                     66: enum rofferr
1.6       kristaps   67: eqn_read(struct eqn_node **epp, int ln,
                     68:                const char *p, int pos, int *offs)
1.1       kristaps   69: {
1.8       kristaps   70:        size_t           sz;
                     71:        struct eqn_node *ep;
1.12      kristaps   72:        enum rofferr     er;
                     73:
                     74:        ep = *epp;
                     75:
                     76:        /*
                     77:         * If we're the terminating mark, unset our equation status and
                     78:         * validate the full equation.
                     79:         */
1.1       kristaps   80:
                     81:        if (0 == strcmp(p, ".EN")) {
1.12      kristaps   82:                er = eqn_end(ep);
1.1       kristaps   83:                *epp = NULL;
1.12      kristaps   84:                return(er);
1.1       kristaps   85:        }
                     86:
1.12      kristaps   87:        /*
                     88:         * Build up the full string, replacing all newlines with regular
                     89:         * whitespace.
                     90:         */
1.6       kristaps   91:
1.12      kristaps   92:        sz = strlen(p + pos) + 1;
                     93:        ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
1.6       kristaps   94:
1.12      kristaps   95:        /* First invocation: nil terminate the string. */
1.8       kristaps   96:
1.12      kristaps   97:        if (0 == ep->sz)
                     98:                *ep->data = '\0';
1.8       kristaps   99:
1.12      kristaps  100:        ep->sz += sz;
                    101:        strlcat(ep->data, p + pos, ep->sz + 1);
                    102:        strlcat(ep->data, " ", ep->sz + 1);
1.11      kristaps  103:        return(ROFF_IGN);
                    104: }
                    105:
1.1       kristaps  106: struct eqn_node *
1.5       kristaps  107: eqn_alloc(int pos, int line, struct mparse *parse)
1.1       kristaps  108: {
                    109:        struct eqn_node *p;
                    110:
                    111:        p = mandoc_calloc(1, sizeof(struct eqn_node));
1.5       kristaps  112:        p->parse = parse;
1.12      kristaps  113:        p->eqn.ln = line;
1.2       kristaps  114:        p->eqn.pos = pos;
1.1       kristaps  115:
                    116:        return(p);
                    117: }
                    118:
1.12      kristaps  119: enum rofferr
                    120: eqn_end(struct eqn_node *ep)
                    121: {
1.13      kristaps  122:        struct eqn_box  *root;
                    123:
                    124:        ep->eqn.root = root =
                    125:                mandoc_calloc(1, sizeof(struct eqn_box));
                    126:        root->type = EQN_ROOT;
                    127:
                    128:        if (0 == ep->sz)
                    129:                return(ROFF_IGN);
1.12      kristaps  130:
                    131:        /*
                    132:         * Validate the expression.
                    133:         * Use the grammar found in the literature.
                    134:         */
                    135:
1.13      kristaps  136:        return(eqn_box(ep, root) < 0 ? ROFF_IGN : ROFF_EQN);
1.12      kristaps  137: }
                    138:
                    139: static int
1.13      kristaps  140: eqn_box(struct eqn_node *ep, struct eqn_box *last)
1.1       kristaps  141: {
1.12      kristaps  142:        size_t           sz;
                    143:        const char      *start;
1.13      kristaps  144:        int              i, nextc;
                    145:        struct eqn_box  *bp;
1.12      kristaps  146:
1.13      kristaps  147:        nextc = 1;
                    148: again:
1.12      kristaps  149:        if (NULL == (start = eqn_nexttok(ep, &sz)))
                    150:                return(0);
                    151:
                    152:        for (i = 0; i < (int)EQN__MAX; i++) {
                    153:                if (eqnparts[i].sz != sz)
                    154:                        continue;
                    155:                if (strncmp(eqnparts[i].name, start, sz))
                    156:                        continue;
                    157:                if ( ! (*eqnparts[i].fp)(ep))
                    158:                        return(-1);
                    159:
1.13      kristaps  160:                goto again;
1.12      kristaps  161:        }
                    162:
1.13      kristaps  163:        bp = mandoc_calloc(1, sizeof(struct eqn_box));
                    164:        bp->type = EQN_TEXT;
1.12      kristaps  165:
1.13      kristaps  166:        if (nextc)
                    167:                last->child = bp;
                    168:        else
                    169:                last->next = bp;
1.1       kristaps  170:
1.13      kristaps  171:        bp->text = mandoc_malloc(sz + 1);
                    172:        *bp->text = '\0';
                    173:        strlcat(bp->text, start, sz + 1);
                    174:
                    175:        last = bp;
                    176:        nextc = 0;
                    177:        goto again;
1.1       kristaps  178: }
                    179:
                    180: void
                    181: eqn_free(struct eqn_node *p)
                    182: {
1.6       kristaps  183:        int              i;
1.1       kristaps  184:
1.13      kristaps  185:        eqn_box_free(p->eqn.root);
1.6       kristaps  186:
                    187:        for (i = 0; i < (int)p->defsz; i++) {
                    188:                free(p->defs[i].key);
                    189:                free(p->defs[i].val);
                    190:        }
                    191:
1.12      kristaps  192:        free(p->data);
1.6       kristaps  193:        free(p->defs);
1.1       kristaps  194:        free(p);
1.6       kristaps  195: }
                    196:
1.13      kristaps  197: static void
                    198: eqn_box_free(struct eqn_box *bp)
                    199: {
                    200:
                    201:        if (bp->child)
                    202:                eqn_box_free(bp->child);
                    203:        if (bp->next)
                    204:                eqn_box_free(bp->next);
                    205:
                    206:        free(bp->text);
                    207:        free(bp);
                    208: }
                    209:
1.6       kristaps  210: static const char *
1.14    ! kristaps  211: eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
        !           212: {
        !           213:
        !           214:        return(eqn_next(ep, '"', sz, 0));
        !           215: }
        !           216:
        !           217: static const char *
1.12      kristaps  218: eqn_nexttok(struct eqn_node *ep, size_t *sz)
                    219: {
                    220:
1.14    ! kristaps  221:        return(eqn_next(ep, '"', sz, 1));
1.12      kristaps  222: }
                    223:
                    224: static const char *
1.14    ! kristaps  225: eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
1.6       kristaps  226: {
1.12      kristaps  227:        char            *start, *next;
                    228:        int              q, diff, lim;
                    229:        size_t           sv, ssz;
                    230:        struct eqn_def  *def;
                    231:
                    232:        if (NULL == sz)
                    233:                sz = &ssz;
1.6       kristaps  234:
1.13      kristaps  235:        lim = 0;
                    236:        sv = ep->cur;
                    237: again:
                    238:        /* Prevent self-definitions. */
                    239:
                    240:        if (lim >= EQN_NEST_MAX) {
                    241:                EQN_MSG(MANDOCERR_EQNNEST, ep);
                    242:                return(NULL);
                    243:        }
                    244:
                    245:        ep->cur = sv;
1.12      kristaps  246:        start = &ep->data[(int)ep->cur];
1.6       kristaps  247:        q = 0;
                    248:
                    249:        if ('\0' == *start)
                    250:                return(NULL);
                    251:
1.12      kristaps  252:        if (quote == *start) {
                    253:                ep->cur++;
1.6       kristaps  254:                q = 1;
                    255:        }
                    256:
1.12      kristaps  257:        start = &ep->data[(int)ep->cur];
                    258:        next = q ? strchr(start, quote) : strchr(start, ' ');
                    259:
                    260:        if (NULL != next) {
                    261:                *sz = (size_t)(next - start);
                    262:                ep->cur += *sz;
1.6       kristaps  263:                if (q)
1.12      kristaps  264:                        ep->cur++;
                    265:                while (' ' == ep->data[(int)ep->cur])
                    266:                        ep->cur++;
1.6       kristaps  267:        } else {
                    268:                if (q)
1.12      kristaps  269:                        EQN_MSG(MANDOCERR_BADQUOTE, ep);
                    270:                next = strchr(start, '\0');
                    271:                *sz = (size_t)(next - start);
                    272:                ep->cur += *sz;
                    273:        }
                    274:
1.13      kristaps  275:        /* Quotes aren't expanded for values. */
                    276:
1.14    ! kristaps  277:        if (q || ! repl)
1.13      kristaps  278:                return(start);
                    279:
1.12      kristaps  280:        if (NULL != (def = eqn_def_find(ep, start, *sz))) {
                    281:                diff = def->valsz - *sz;
                    282:
                    283:                if (def->valsz > *sz) {
                    284:                        ep->sz += diff;
                    285:                        ep->data = mandoc_realloc(ep->data, ep->sz + 1);
                    286:                        ep->data[ep->sz] = '\0';
                    287:                        start = &ep->data[(int)sv];
                    288:                }
                    289:
                    290:                diff = def->valsz - *sz;
                    291:                memmove(start + *sz + diff, start + *sz,
                    292:                                (strlen(start) - *sz) + 1);
                    293:                memcpy(start, def->val, def->valsz);
                    294:                goto again;
1.6       kristaps  295:        }
                    296:
                    297:        return(start);
1.8       kristaps  298: }
                    299:
                    300: static int
1.14    ! kristaps  301: eqn_do_set(struct eqn_node *ep)
1.8       kristaps  302: {
                    303:        const char      *start;
                    304:
1.14    ! kristaps  305:        if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12      kristaps  306:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.14    ! kristaps  307:        else if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12      kristaps  308:                EQN_MSG(MANDOCERR_EQNARGS, ep);
                    309:        else
                    310:                return(1);
1.8       kristaps  311:
1.12      kristaps  312:        return(0);
1.8       kristaps  313: }
                    314:
                    315: static int
1.12      kristaps  316: eqn_do_define(struct eqn_node *ep)
1.8       kristaps  317: {
                    318:        const char      *start;
                    319:        size_t           sz;
1.12      kristaps  320:        struct eqn_def  *def;
1.8       kristaps  321:        int              i;
                    322:
1.14    ! kristaps  323:        if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12      kristaps  324:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8       kristaps  325:                return(0);
                    326:        }
                    327:
                    328:        /*
                    329:         * Search for a key that already exists.
1.12      kristaps  330:         * Create a new key if none is found.
1.8       kristaps  331:         */
                    332:
1.12      kristaps  333:        if (NULL == (def = eqn_def_find(ep, start, sz))) {
1.8       kristaps  334:                /* Find holes in string array. */
                    335:                for (i = 0; i < (int)ep->defsz; i++)
                    336:                        if (0 == ep->defs[i].keysz)
                    337:                                break;
                    338:
                    339:                if (i == (int)ep->defsz) {
                    340:                        ep->defsz++;
                    341:                        ep->defs = mandoc_realloc
                    342:                                (ep->defs, ep->defsz *
                    343:                                 sizeof(struct eqn_def));
1.9       kristaps  344:                        ep->defs[i].key = ep->defs[i].val = NULL;
1.8       kristaps  345:                }
                    346:
                    347:                ep->defs[i].keysz = sz;
                    348:                ep->defs[i].key = mandoc_realloc
                    349:                        (ep->defs[i].key, sz + 1);
                    350:
                    351:                memcpy(ep->defs[i].key, start, sz);
                    352:                ep->defs[i].key[(int)sz] = '\0';
1.12      kristaps  353:                def = &ep->defs[i];
1.8       kristaps  354:        }
                    355:
1.14    ! kristaps  356:        start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
1.8       kristaps  357:
1.12      kristaps  358:        if (NULL == start) {
                    359:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8       kristaps  360:                return(0);
                    361:        }
                    362:
1.12      kristaps  363:        def->valsz = sz;
1.13      kristaps  364:        def->val = mandoc_realloc(def->val, sz + 1);
1.12      kristaps  365:        memcpy(def->val, start, sz);
                    366:        def->val[(int)sz] = '\0';
                    367:        return(1);
1.8       kristaps  368: }
                    369:
                    370: static int
1.12      kristaps  371: eqn_do_undef(struct eqn_node *ep)
1.8       kristaps  372: {
                    373:        const char      *start;
1.12      kristaps  374:        struct eqn_def  *def;
1.8       kristaps  375:        size_t           sz;
                    376:
1.14    ! kristaps  377:        if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12      kristaps  378:                EQN_MSG(MANDOCERR_EQNARGS, ep);
                    379:                return(0);
                    380:        } else if (NULL != (def = eqn_def_find(ep, start, sz)))
                    381:                def->keysz = 0;
1.8       kristaps  382:
1.12      kristaps  383:        return(1);
                    384: }
                    385:
                    386: static struct eqn_def *
                    387: eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
                    388: {
                    389:        int              i;
1.8       kristaps  390:
1.12      kristaps  391:        for (i = 0; i < (int)ep->defsz; i++)
                    392:                if (ep->defs[i].keysz && ep->defs[i].keysz == sz &&
                    393:                                0 == strncmp(ep->defs[i].key, key, sz))
                    394:                        return(&ep->defs[i]);
1.8       kristaps  395:
1.12      kristaps  396:        return(NULL);
1.1       kristaps  397: }

CVSweb