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

Annotation of mandoc/roff.c, Revision 1.68

1.68    ! kristaps    1: /*     $Id: roff.c,v 1.67 2010/05/15 18:35:14 kristaps Exp $ */
1.1       kristaps    2: /*
1.67      kristaps    3:  * Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
1.1       kristaps    4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
1.66      kristaps    6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
1.1       kristaps    8:  *
1.66      kristaps    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.
1.1       kristaps   16:  */
1.66      kristaps   17: #ifdef HAVE_CONFIG_H
                     18: #include "config.h"
                     19: #endif
1.30      kristaps   20:
1.67      kristaps   21: #include <assert.h>
1.1       kristaps   22: #include <stdlib.h>
1.67      kristaps   23: #include <string.h>
1.1       kristaps   24:
1.67      kristaps   25: #include "mandoc.h"
1.43      kristaps   26: #include "roff.h"
1.33      kristaps   27:
1.67      kristaps   28: enum   rofft {
                     29:        ROFF_de,
                     30:        ROFF_dei,
                     31:        ROFF_am,
                     32:        ROFF_ami,
                     33:        ROFF_ig,
                     34:        ROFF_close,
                     35:        ROFF_MAX
                     36: };
                     37:
                     38: struct roff {
                     39:        struct roffnode *last; /* leaf of stack */
                     40:        mandocmsg        msg; /* err/warn/fatal messages */
                     41:        void            *data; /* privdata for messages */
                     42: };
                     43:
                     44: struct roffnode {
                     45:        enum rofft       tok; /* type of node */
                     46:        struct roffnode *parent; /* up one in stack */
                     47:        int              line; /* parse line */
                     48:        int              col; /* parse col */
                     49: };
                     50:
                     51: #define        ROFF_ARGS        struct roff *r, /* parse ctx */ \
                     52:                         char **bufp, /* input buffer */ \
                     53:                         size_t *szp, /* size of input buffer */ \
                     54:                         int ln, /* parse line */ \
                     55:                         int ppos /* current pos in buffer */
                     56:
                     57: typedef        enum rofferr (*roffproc)(ROFF_ARGS);
                     58:
                     59: struct roffmac {
                     60:        const char      *name; /* macro name */
                     61:        roffproc         sub; /* child of control black */
                     62:        roffproc         new; /* root of stack (type = ROFF_MAX) */
                     63: };
                     64:
                     65: static enum rofferr     roff_ignore(ROFF_ARGS);
                     66: static enum rofferr     roff_new_close(ROFF_ARGS);
                     67: static enum rofferr     roff_new_ig(ROFF_ARGS);
                     68: static enum rofferr     roff_sub_ig(ROFF_ARGS);
                     69:
                     70: const  struct roffmac   roffs[ROFF_MAX] = {
                     71:        { "de", NULL, roff_ignore },
                     72:        { "dei", NULL, roff_ignore },
                     73:        { "am", NULL, roff_ignore },
                     74:        { "ami", NULL, roff_ignore },
                     75:        { "ig", roff_sub_ig, roff_new_ig },
                     76:        { ".", NULL, roff_new_close },
                     77: };
                     78:
                     79: static void             roff_alloc1(struct roff *);
                     80: static void             roff_free1(struct roff *);
                     81: static enum rofft       roff_hash_find(const char *);
                     82: static int              roffnode_push(struct roff *,
                     83:                                enum rofft, int, int);
                     84: static void             roffnode_pop(struct roff *);
                     85: static enum rofft       roff_parse(const char *, int *);
                     86:
                     87:
                     88: /*
                     89:  * Look up a roff token by its name.  Returns ROFF_MAX if no macro by
                     90:  * the nil-terminated string name could be found.
                     91:  */
                     92: static enum rofft
                     93: roff_hash_find(const char *p)
                     94: {
                     95:        int              i;
                     96:
                     97:        /* FIXME: make this be fast and efficient. */
                     98:
                     99:        for (i = 0; i < (int)ROFF_MAX; i++)
                    100:                if (0 == strcmp(roffs[i].name, p))
                    101:                        return((enum rofft)i);
                    102:
                    103:        return(ROFF_MAX);
                    104: }
                    105:
                    106:
                    107: /*
                    108:  * Pop the current node off of the stack of roff instructions currently
                    109:  * pending.
                    110:  */
                    111: static void
                    112: roffnode_pop(struct roff *r)
                    113: {
                    114:        struct roffnode *p;
                    115:
                    116:        if (NULL == (p = r->last))
                    117:                return;
                    118:        r->last = p->parent;
                    119:        free(p);
                    120: }
                    121:
                    122:
                    123: /*
                    124:  * Push a roff node onto the instruction stack.  This must later be
                    125:  * removed with roffnode_pop().
                    126:  */
                    127: static int
                    128: roffnode_push(struct roff *r, enum rofft tok, int line, int col)
                    129: {
                    130:        struct roffnode *p;
                    131:
                    132:        if (NULL == (p = calloc(1, sizeof(struct roffnode)))) {
                    133:                (*r->msg)(MANDOCERR_MEM, r->data, line, col, NULL);
                    134:                return(0);
                    135:        }
                    136:
                    137:        p->tok = tok;
                    138:        p->parent = r->last;
                    139:        p->line = line;
                    140:        p->col = col;
                    141:
                    142:        r->last = p;
                    143:        return(1);
                    144: }
                    145:
                    146:
                    147: static void
                    148: roff_free1(struct roff *r)
                    149: {
                    150:
                    151:        while (r->last)
                    152:                roffnode_pop(r);
                    153: }
                    154:
                    155:
                    156: static void
                    157: roff_alloc1(struct roff *r)
                    158: {
                    159:
1.68    ! kristaps  160:        /* Do nothing for now. */
1.67      kristaps  161: }
                    162:
                    163:
                    164: void
                    165: roff_reset(struct roff *r)
                    166: {
                    167:
                    168:        roff_free1(r);
                    169:        roff_alloc1(r);
                    170: }
                    171:
                    172:
                    173: void
                    174: roff_free(struct roff *r)
                    175: {
                    176:
                    177:        roff_free1(r);
                    178:        free(r);
                    179: }
                    180:
                    181:
                    182: struct roff *
                    183: roff_alloc(const mandocmsg msg, void *data)
                    184: {
                    185:        struct roff     *r;
                    186:
                    187:        if (NULL == (r = calloc(1, sizeof(struct roff)))) {
                    188:                (*msg)(MANDOCERR_MEM, data, 0, 0, NULL);
                    189:                return(0);
                    190:        }
                    191:
                    192:        r->msg = msg;
                    193:        r->data = data;
                    194:        return(r);
                    195: }
                    196:
                    197:
                    198: enum rofferr
                    199: roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp)
                    200: {
                    201:        enum rofft       t;
                    202:        int              ppos;
                    203:
                    204:        if (NULL != r->last) {
                    205:                /*
                    206:                 * If there's a node on the stack, then jump directly
                    207:                 * into its processing function.
                    208:                 */
                    209:                t = r->last->tok;
                    210:                assert(roffs[t].sub);
                    211:                return((*roffs[t].sub)(r, bufp, szp, ln, 0));
                    212:        } else if ('.' != (*bufp)[0] && NULL == r->last)
                    213:                /* Return when in free text without a context. */
                    214:                return(ROFF_CONT);
                    215:
                    216:        /* There's nothing on the stack: make us anew. */
                    217:
                    218:        if (ROFF_MAX == (t = roff_parse(*bufp, &ppos)))
                    219:                return(ROFF_CONT);
                    220:
                    221:        assert(roffs[t].new);
                    222:        return((*roffs[t].new)(r, bufp, szp, ln, ppos));
                    223: }
                    224:
                    225:
                    226: /*
                    227:  * Parse a roff node's type from the input buffer.  This must be in the
                    228:  * form of ".foo xxx" in the usual way.
                    229:  */
                    230: static enum rofft
                    231: roff_parse(const char *buf, int *pos)
                    232: {
                    233:        int              j;
                    234:        char             mac[5];
                    235:        enum rofft       t;
                    236:
                    237:        assert('.' == buf[0]);
                    238:        *pos = 1;
                    239:
                    240:        while (buf[*pos] && (' ' == buf[*pos] || '\t' == buf[*pos]))
                    241:                (*pos)++;
                    242:
                    243:        if ('\0' == buf[*pos])
                    244:                return(ROFF_MAX);
                    245:
                    246:        for (j = 0; j < 4; j++, (*pos)++)
                    247:                if ('\0' == (mac[j] = buf[*pos]))
                    248:                        break;
                    249:                else if (' ' == buf[*pos])
                    250:                        break;
                    251:
                    252:        if (j == 4 || j < 1)
                    253:                return(ROFF_MAX);
                    254:
                    255:        mac[j] = '\0';
                    256:
                    257:        if (ROFF_MAX == (t = roff_hash_find(mac)))
                    258:                return(t);
                    259:
                    260:        while (buf[*pos] && ' ' == buf[*pos])
                    261:                (*pos)++;
                    262:
                    263:        return(t);
                    264: }
                    265:
                    266:
                    267: /* ARGSUSED */
                    268: static enum rofferr
                    269: roff_ignore(ROFF_ARGS)
                    270: {
                    271:
                    272:        return(ROFF_IGN);
                    273: }
                    274:
                    275:
                    276: /* ARGSUSED */
                    277: static enum rofferr
                    278: roff_sub_ig(ROFF_ARGS)
                    279: {
                    280:        enum rofft       t;
                    281:        int              pos;
                    282:
                    283:        /* Ignore free-text lines. */
                    284:
                    285:        if ('.' != (*bufp)[ppos])
                    286:                return(ROFF_IGN);
                    287:
                    288:        /* Ignore macros unless it's a closing macro. */
                    289:
                    290:        t = roff_parse(*bufp, &pos);
                    291:        if (ROFF_close != t)
                    292:                return(ROFF_IGN);
                    293:
                    294:        roffnode_pop(r);
                    295:        return(ROFF_IGN);
                    296: }
                    297:
                    298:
                    299: /* ARGSUSED */
                    300: static enum rofferr
                    301: roff_new_close(ROFF_ARGS)
                    302: {
                    303:
1.68    ! kristaps  304:        /*
1.67      kristaps  305:        if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
                    306:                return(ROFF_ERR);
1.68    ! kristaps  307:        */
        !           308:        return(ROFF_CONT);
1.67      kristaps  309: }
                    310:
                    311:
                    312: /* ARGSUSED */
                    313: static enum rofferr
                    314: roff_new_ig(ROFF_ARGS)
                    315: {
                    316:
                    317:        return(roffnode_push(r, ROFF_ig, ln, ppos) ?
                    318:                        ROFF_IGN : ROFF_ERR);
                    319: }
                    320:
                    321:
                    322: int
                    323: roff_endparse(struct roff *r)
                    324: {
                    325:
                    326:        if (NULL == r->last)
                    327:                return(1);
                    328:        return((*r->msg)(MANDOCERR_SCOPEEXIT, r->data,
                    329:                                r->last->line, r->last->col, NULL));
                    330: }

CVSweb