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

Annotation of mandoc/eqn.c, Revision 1.15

1.15    ! kristaps    1: /*     $Id: eqn.c,v 1.14 2011/07/21 11:57:56 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.15    ! kristaps   57: static int              eqn_box(struct eqn_node *,
        !            58:                                struct eqn_box *, struct eqn_box **);
1.6       kristaps   59:
1.8       kristaps   60: static const struct eqnpart eqnparts[EQN__MAX] = {
                     61:        { "define", 6, eqn_do_define }, /* EQN_DEFINE */
1.14      kristaps   62:        { "set", 3, eqn_do_set }, /* EQN_SET */
1.8       kristaps   63:        { "undef", 5, eqn_do_undef }, /* EQN_UNDEF */
                     64: };
                     65:
1.1       kristaps   66: /* ARGSUSED */
                     67: enum rofferr
1.6       kristaps   68: eqn_read(struct eqn_node **epp, int ln,
                     69:                const char *p, int pos, int *offs)
1.1       kristaps   70: {
1.8       kristaps   71:        size_t           sz;
                     72:        struct eqn_node *ep;
1.12      kristaps   73:        enum rofferr     er;
                     74:
                     75:        ep = *epp;
                     76:
                     77:        /*
                     78:         * If we're the terminating mark, unset our equation status and
                     79:         * validate the full equation.
                     80:         */
1.1       kristaps   81:
                     82:        if (0 == strcmp(p, ".EN")) {
1.12      kristaps   83:                er = eqn_end(ep);
1.1       kristaps   84:                *epp = NULL;
1.12      kristaps   85:                return(er);
1.1       kristaps   86:        }
                     87:
1.12      kristaps   88:        /*
                     89:         * Build up the full string, replacing all newlines with regular
                     90:         * whitespace.
                     91:         */
1.6       kristaps   92:
1.12      kristaps   93:        sz = strlen(p + pos) + 1;
                     94:        ep->data = mandoc_realloc(ep->data, ep->sz + sz + 1);
1.6       kristaps   95:
1.12      kristaps   96:        /* First invocation: nil terminate the string. */
1.8       kristaps   97:
1.12      kristaps   98:        if (0 == ep->sz)
                     99:                *ep->data = '\0';
1.8       kristaps  100:
1.12      kristaps  101:        ep->sz += sz;
                    102:        strlcat(ep->data, p + pos, ep->sz + 1);
                    103:        strlcat(ep->data, " ", ep->sz + 1);
1.11      kristaps  104:        return(ROFF_IGN);
                    105: }
                    106:
1.1       kristaps  107: struct eqn_node *
1.5       kristaps  108: eqn_alloc(int pos, int line, struct mparse *parse)
1.1       kristaps  109: {
                    110:        struct eqn_node *p;
                    111:
                    112:        p = mandoc_calloc(1, sizeof(struct eqn_node));
1.5       kristaps  113:        p->parse = parse;
1.12      kristaps  114:        p->eqn.ln = line;
1.2       kristaps  115:        p->eqn.pos = pos;
1.1       kristaps  116:
                    117:        return(p);
                    118: }
                    119:
1.12      kristaps  120: enum rofferr
                    121: eqn_end(struct eqn_node *ep)
                    122: {
1.15    ! kristaps  123:        struct eqn_box  *root, *last;
        !           124:        int              c;
1.13      kristaps  125:
                    126:        ep->eqn.root = root =
                    127:                mandoc_calloc(1, sizeof(struct eqn_box));
                    128:        root->type = EQN_ROOT;
                    129:
                    130:        if (0 == ep->sz)
                    131:                return(ROFF_IGN);
1.12      kristaps  132:
                    133:        /*
1.15    ! kristaps  134:         * Run the parser.
        !           135:         * If we return before reaching the end of our input, our scope
        !           136:         * is still open somewhere.
        !           137:         * If we return alright but don't have a symmetric scoping, then
        !           138:         * something's not right either.
        !           139:         * Otherwise, return the equation.
1.12      kristaps  140:         */
                    141:
1.15    ! kristaps  142:        if ((c = eqn_box(ep, root, &last)) > 0) {
        !           143:                EQN_MSG(MANDOCERR_EQNNSCOPE, ep);
        !           144:                c = 0;
        !           145:        } else if (0 == c && last != root)
        !           146:                EQN_MSG(MANDOCERR_EQNSCOPE, ep);
        !           147:
        !           148:        return(1 == c ? ROFF_EQN : ROFF_IGN);
1.12      kristaps  149: }
                    150:
                    151: static int
1.15    ! kristaps  152: eqn_box(struct eqn_node *ep, struct eqn_box *last, struct eqn_box **sv)
1.1       kristaps  153: {
1.12      kristaps  154:        size_t           sz;
                    155:        const char      *start;
1.15    ! kristaps  156:        int              c, i, nextc;
1.13      kristaps  157:        struct eqn_box  *bp;
1.12      kristaps  158:
1.15    ! kristaps  159:        /*
        !           160:         * Mark our last level of subexpression.
        !           161:         * Also mark whether that the next node should be a
        !           162:         * subexpression node.
        !           163:         */
        !           164:
        !           165:        *sv = last;
1.13      kristaps  166:        nextc = 1;
                    167: again:
1.12      kristaps  168:        if (NULL == (start = eqn_nexttok(ep, &sz)))
                    169:                return(0);
                    170:
                    171:        for (i = 0; i < (int)EQN__MAX; i++) {
                    172:                if (eqnparts[i].sz != sz)
                    173:                        continue;
                    174:                if (strncmp(eqnparts[i].name, start, sz))
                    175:                        continue;
                    176:                if ( ! (*eqnparts[i].fp)(ep))
                    177:                        return(-1);
                    178:
1.13      kristaps  179:                goto again;
1.12      kristaps  180:        }
                    181:
1.15    ! kristaps  182:        /* Exit this [hopefully] subexpression. */
        !           183:
        !           184:        if (sz == 1 && 0 == strncmp("}", start, 1))
        !           185:                return(1);
        !           186:
1.13      kristaps  187:        bp = mandoc_calloc(1, sizeof(struct eqn_box));
                    188:        if (nextc)
                    189:                last->child = bp;
                    190:        else
                    191:                last->next = bp;
1.1       kristaps  192:
1.15    ! kristaps  193:        last = bp;
        !           194:
        !           195:        /*
        !           196:         * See if we're to open a new subexpression.
        !           197:         * If so, mark our node as such and descend.
        !           198:         */
        !           199:
        !           200:        if (sz == 1 && 0 == strncmp("{", start, 1)) {
        !           201:                bp->type = EQN_SUBEXPR;
        !           202:                c = eqn_box(ep, bp, sv);
        !           203:
        !           204:                nextc = 0;
        !           205:                goto again;
        !           206:        }
        !           207:
        !           208:        /* A regular text node. */
        !           209:
        !           210:        bp->type = EQN_TEXT;
1.13      kristaps  211:        bp->text = mandoc_malloc(sz + 1);
                    212:        *bp->text = '\0';
                    213:        strlcat(bp->text, start, sz + 1);
                    214:
                    215:        nextc = 0;
                    216:        goto again;
1.1       kristaps  217: }
                    218:
                    219: void
                    220: eqn_free(struct eqn_node *p)
                    221: {
1.6       kristaps  222:        int              i;
1.1       kristaps  223:
1.13      kristaps  224:        eqn_box_free(p->eqn.root);
1.6       kristaps  225:
                    226:        for (i = 0; i < (int)p->defsz; i++) {
                    227:                free(p->defs[i].key);
                    228:                free(p->defs[i].val);
                    229:        }
                    230:
1.12      kristaps  231:        free(p->data);
1.6       kristaps  232:        free(p->defs);
1.1       kristaps  233:        free(p);
1.6       kristaps  234: }
                    235:
1.13      kristaps  236: static void
                    237: eqn_box_free(struct eqn_box *bp)
                    238: {
                    239:
                    240:        if (bp->child)
                    241:                eqn_box_free(bp->child);
                    242:        if (bp->next)
                    243:                eqn_box_free(bp->next);
                    244:
                    245:        free(bp->text);
                    246:        free(bp);
                    247: }
                    248:
1.6       kristaps  249: static const char *
1.14      kristaps  250: eqn_nextrawtok(struct eqn_node *ep, size_t *sz)
                    251: {
                    252:
                    253:        return(eqn_next(ep, '"', sz, 0));
                    254: }
                    255:
                    256: static const char *
1.12      kristaps  257: eqn_nexttok(struct eqn_node *ep, size_t *sz)
                    258: {
                    259:
1.14      kristaps  260:        return(eqn_next(ep, '"', sz, 1));
1.12      kristaps  261: }
                    262:
                    263: static const char *
1.14      kristaps  264: eqn_next(struct eqn_node *ep, char quote, size_t *sz, int repl)
1.6       kristaps  265: {
1.12      kristaps  266:        char            *start, *next;
                    267:        int              q, diff, lim;
                    268:        size_t           sv, ssz;
                    269:        struct eqn_def  *def;
                    270:
                    271:        if (NULL == sz)
                    272:                sz = &ssz;
1.6       kristaps  273:
1.13      kristaps  274:        lim = 0;
                    275:        sv = ep->cur;
                    276: again:
                    277:        /* Prevent self-definitions. */
                    278:
                    279:        if (lim >= EQN_NEST_MAX) {
                    280:                EQN_MSG(MANDOCERR_EQNNEST, ep);
                    281:                return(NULL);
                    282:        }
                    283:
                    284:        ep->cur = sv;
1.12      kristaps  285:        start = &ep->data[(int)ep->cur];
1.6       kristaps  286:        q = 0;
                    287:
                    288:        if ('\0' == *start)
                    289:                return(NULL);
                    290:
1.12      kristaps  291:        if (quote == *start) {
                    292:                ep->cur++;
1.6       kristaps  293:                q = 1;
                    294:        }
                    295:
1.12      kristaps  296:        start = &ep->data[(int)ep->cur];
                    297:        next = q ? strchr(start, quote) : strchr(start, ' ');
                    298:
                    299:        if (NULL != next) {
                    300:                *sz = (size_t)(next - start);
                    301:                ep->cur += *sz;
1.6       kristaps  302:                if (q)
1.12      kristaps  303:                        ep->cur++;
                    304:                while (' ' == ep->data[(int)ep->cur])
                    305:                        ep->cur++;
1.6       kristaps  306:        } else {
                    307:                if (q)
1.12      kristaps  308:                        EQN_MSG(MANDOCERR_BADQUOTE, ep);
                    309:                next = strchr(start, '\0');
                    310:                *sz = (size_t)(next - start);
                    311:                ep->cur += *sz;
                    312:        }
                    313:
1.13      kristaps  314:        /* Quotes aren't expanded for values. */
                    315:
1.14      kristaps  316:        if (q || ! repl)
1.13      kristaps  317:                return(start);
                    318:
1.12      kristaps  319:        if (NULL != (def = eqn_def_find(ep, start, *sz))) {
                    320:                diff = def->valsz - *sz;
                    321:
                    322:                if (def->valsz > *sz) {
                    323:                        ep->sz += diff;
                    324:                        ep->data = mandoc_realloc(ep->data, ep->sz + 1);
                    325:                        ep->data[ep->sz] = '\0';
                    326:                        start = &ep->data[(int)sv];
                    327:                }
                    328:
                    329:                diff = def->valsz - *sz;
                    330:                memmove(start + *sz + diff, start + *sz,
                    331:                                (strlen(start) - *sz) + 1);
                    332:                memcpy(start, def->val, def->valsz);
                    333:                goto again;
1.6       kristaps  334:        }
                    335:
                    336:        return(start);
1.8       kristaps  337: }
                    338:
                    339: static int
1.14      kristaps  340: eqn_do_set(struct eqn_node *ep)
1.8       kristaps  341: {
                    342:        const char      *start;
                    343:
1.14      kristaps  344:        if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12      kristaps  345:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.14      kristaps  346:        else if (NULL == (start = eqn_nextrawtok(ep, NULL)))
1.12      kristaps  347:                EQN_MSG(MANDOCERR_EQNARGS, ep);
                    348:        else
                    349:                return(1);
1.8       kristaps  350:
1.12      kristaps  351:        return(0);
1.8       kristaps  352: }
                    353:
                    354: static int
1.12      kristaps  355: eqn_do_define(struct eqn_node *ep)
1.8       kristaps  356: {
                    357:        const char      *start;
                    358:        size_t           sz;
1.12      kristaps  359:        struct eqn_def  *def;
1.8       kristaps  360:        int              i;
                    361:
1.14      kristaps  362:        if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12      kristaps  363:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8       kristaps  364:                return(0);
                    365:        }
                    366:
                    367:        /*
                    368:         * Search for a key that already exists.
1.12      kristaps  369:         * Create a new key if none is found.
1.8       kristaps  370:         */
                    371:
1.12      kristaps  372:        if (NULL == (def = eqn_def_find(ep, start, sz))) {
1.8       kristaps  373:                /* Find holes in string array. */
                    374:                for (i = 0; i < (int)ep->defsz; i++)
                    375:                        if (0 == ep->defs[i].keysz)
                    376:                                break;
                    377:
                    378:                if (i == (int)ep->defsz) {
                    379:                        ep->defsz++;
                    380:                        ep->defs = mandoc_realloc
                    381:                                (ep->defs, ep->defsz *
                    382:                                 sizeof(struct eqn_def));
1.9       kristaps  383:                        ep->defs[i].key = ep->defs[i].val = NULL;
1.8       kristaps  384:                }
                    385:
                    386:                ep->defs[i].keysz = sz;
                    387:                ep->defs[i].key = mandoc_realloc
                    388:                        (ep->defs[i].key, sz + 1);
                    389:
                    390:                memcpy(ep->defs[i].key, start, sz);
                    391:                ep->defs[i].key[(int)sz] = '\0';
1.12      kristaps  392:                def = &ep->defs[i];
1.8       kristaps  393:        }
                    394:
1.14      kristaps  395:        start = eqn_next(ep, ep->data[(int)ep->cur], &sz, 0);
1.8       kristaps  396:
1.12      kristaps  397:        if (NULL == start) {
                    398:                EQN_MSG(MANDOCERR_EQNARGS, ep);
1.8       kristaps  399:                return(0);
                    400:        }
                    401:
1.12      kristaps  402:        def->valsz = sz;
1.13      kristaps  403:        def->val = mandoc_realloc(def->val, sz + 1);
1.12      kristaps  404:        memcpy(def->val, start, sz);
                    405:        def->val[(int)sz] = '\0';
                    406:        return(1);
1.8       kristaps  407: }
                    408:
                    409: static int
1.12      kristaps  410: eqn_do_undef(struct eqn_node *ep)
1.8       kristaps  411: {
                    412:        const char      *start;
1.12      kristaps  413:        struct eqn_def  *def;
1.8       kristaps  414:        size_t           sz;
                    415:
1.14      kristaps  416:        if (NULL == (start = eqn_nextrawtok(ep, &sz))) {
1.12      kristaps  417:                EQN_MSG(MANDOCERR_EQNARGS, ep);
                    418:                return(0);
                    419:        } else if (NULL != (def = eqn_def_find(ep, start, sz)))
                    420:                def->keysz = 0;
1.8       kristaps  421:
1.12      kristaps  422:        return(1);
                    423: }
                    424:
                    425: static struct eqn_def *
                    426: eqn_def_find(struct eqn_node *ep, const char *key, size_t sz)
                    427: {
                    428:        int              i;
1.8       kristaps  429:
1.12      kristaps  430:        for (i = 0; i < (int)ep->defsz; i++)
                    431:                if (ep->defs[i].keysz && ep->defs[i].keysz == sz &&
                    432:                                0 == strncmp(ep->defs[i].key, key, sz))
                    433:                        return(&ep->defs[i]);
1.8       kristaps  434:
1.12      kristaps  435:        return(NULL);
1.1       kristaps  436: }

CVSweb