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

Annotation of mandoc/eqn.c, Revision 1.19

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

CVSweb