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

Annotation of mandoc/roff.c, Revision 1.70

1.70    ! kristaps    1: /*     $Id: roff.c,v 1.69 2010/05/15 18:48:32 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_free1(struct roff *);
                     80: static enum rofft       roff_hash_find(const char *);
                     81: static int              roffnode_push(struct roff *,
                     82:                                enum rofft, int, int);
                     83: static void             roffnode_pop(struct roff *);
                     84: static enum rofft       roff_parse(const char *, int *);
                     85:
                     86:
                     87: /*
                     88:  * Look up a roff token by its name.  Returns ROFF_MAX if no macro by
                     89:  * the nil-terminated string name could be found.
                     90:  */
                     91: static enum rofft
                     92: roff_hash_find(const char *p)
                     93: {
                     94:        int              i;
                     95:
                     96:        /* FIXME: make this be fast and efficient. */
                     97:
                     98:        for (i = 0; i < (int)ROFF_MAX; i++)
                     99:                if (0 == strcmp(roffs[i].name, p))
                    100:                        return((enum rofft)i);
                    101:
                    102:        return(ROFF_MAX);
                    103: }
                    104:
                    105:
                    106: /*
                    107:  * Pop the current node off of the stack of roff instructions currently
                    108:  * pending.
                    109:  */
                    110: static void
                    111: roffnode_pop(struct roff *r)
                    112: {
                    113:        struct roffnode *p;
                    114:
                    115:        if (NULL == (p = r->last))
                    116:                return;
                    117:        r->last = p->parent;
                    118:        free(p);
                    119: }
                    120:
                    121:
                    122: /*
                    123:  * Push a roff node onto the instruction stack.  This must later be
                    124:  * removed with roffnode_pop().
                    125:  */
                    126: static int
                    127: roffnode_push(struct roff *r, enum rofft tok, int line, int col)
                    128: {
                    129:        struct roffnode *p;
                    130:
                    131:        if (NULL == (p = calloc(1, sizeof(struct roffnode)))) {
                    132:                (*r->msg)(MANDOCERR_MEM, r->data, line, col, NULL);
                    133:                return(0);
                    134:        }
                    135:
                    136:        p->tok = tok;
                    137:        p->parent = r->last;
                    138:        p->line = line;
                    139:        p->col = col;
                    140:
                    141:        r->last = p;
                    142:        return(1);
                    143: }
                    144:
                    145:
                    146: static void
                    147: roff_free1(struct roff *r)
                    148: {
                    149:
                    150:        while (r->last)
                    151:                roffnode_pop(r);
                    152: }
                    153:
                    154:
                    155: void
                    156: roff_reset(struct roff *r)
                    157: {
                    158:
                    159:        roff_free1(r);
                    160: }
                    161:
                    162:
                    163: void
                    164: roff_free(struct roff *r)
                    165: {
                    166:
                    167:        roff_free1(r);
                    168:        free(r);
                    169: }
                    170:
                    171:
                    172: struct roff *
                    173: roff_alloc(const mandocmsg msg, void *data)
                    174: {
                    175:        struct roff     *r;
                    176:
                    177:        if (NULL == (r = calloc(1, sizeof(struct roff)))) {
                    178:                (*msg)(MANDOCERR_MEM, data, 0, 0, NULL);
                    179:                return(0);
                    180:        }
                    181:
                    182:        r->msg = msg;
                    183:        r->data = data;
                    184:        return(r);
                    185: }
                    186:
                    187:
                    188: enum rofferr
                    189: roff_parseln(struct roff *r, int ln, char **bufp, size_t *szp)
                    190: {
                    191:        enum rofft       t;
                    192:        int              ppos;
                    193:
                    194:        if (NULL != r->last) {
                    195:                /*
                    196:                 * If there's a node on the stack, then jump directly
                    197:                 * into its processing function.
                    198:                 */
                    199:                t = r->last->tok;
                    200:                assert(roffs[t].sub);
                    201:                return((*roffs[t].sub)(r, bufp, szp, ln, 0));
                    202:        } else if ('.' != (*bufp)[0] && NULL == r->last)
                    203:                /* Return when in free text without a context. */
                    204:                return(ROFF_CONT);
                    205:
                    206:        /* There's nothing on the stack: make us anew. */
                    207:
                    208:        if (ROFF_MAX == (t = roff_parse(*bufp, &ppos)))
                    209:                return(ROFF_CONT);
                    210:
                    211:        assert(roffs[t].new);
                    212:        return((*roffs[t].new)(r, bufp, szp, ln, ppos));
                    213: }
                    214:
                    215:
                    216: /*
                    217:  * Parse a roff node's type from the input buffer.  This must be in the
                    218:  * form of ".foo xxx" in the usual way.
                    219:  */
                    220: static enum rofft
                    221: roff_parse(const char *buf, int *pos)
                    222: {
                    223:        int              j;
                    224:        char             mac[5];
                    225:        enum rofft       t;
                    226:
                    227:        assert('.' == buf[0]);
                    228:        *pos = 1;
                    229:
                    230:        while (buf[*pos] && (' ' == buf[*pos] || '\t' == buf[*pos]))
                    231:                (*pos)++;
                    232:
                    233:        if ('\0' == buf[*pos])
                    234:                return(ROFF_MAX);
                    235:
                    236:        for (j = 0; j < 4; j++, (*pos)++)
                    237:                if ('\0' == (mac[j] = buf[*pos]))
                    238:                        break;
                    239:                else if (' ' == buf[*pos])
                    240:                        break;
                    241:
                    242:        if (j == 4 || j < 1)
                    243:                return(ROFF_MAX);
                    244:
                    245:        mac[j] = '\0';
                    246:
                    247:        if (ROFF_MAX == (t = roff_hash_find(mac)))
                    248:                return(t);
                    249:
                    250:        while (buf[*pos] && ' ' == buf[*pos])
                    251:                (*pos)++;
                    252:
                    253:        return(t);
                    254: }
                    255:
                    256:
                    257: /* ARGSUSED */
                    258: static enum rofferr
                    259: roff_ignore(ROFF_ARGS)
                    260: {
                    261:
                    262:        return(ROFF_IGN);
                    263: }
                    264:
                    265:
                    266: /* ARGSUSED */
                    267: static enum rofferr
                    268: roff_sub_ig(ROFF_ARGS)
                    269: {
                    270:        enum rofft       t;
                    271:        int              pos;
                    272:
                    273:        /* Ignore free-text lines. */
                    274:
                    275:        if ('.' != (*bufp)[ppos])
                    276:                return(ROFF_IGN);
                    277:
                    278:        /* Ignore macros unless it's a closing macro. */
                    279:
                    280:        t = roff_parse(*bufp, &pos);
                    281:        if (ROFF_close != t)
                    282:                return(ROFF_IGN);
                    283:
                    284:        roffnode_pop(r);
                    285:        return(ROFF_IGN);
                    286: }
                    287:
                    288:
                    289: /* ARGSUSED */
                    290: static enum rofferr
                    291: roff_new_close(ROFF_ARGS)
                    292: {
                    293:
1.68      kristaps  294:        /*
1.67      kristaps  295:        if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
                    296:                return(ROFF_ERR);
1.68      kristaps  297:        */
1.69      kristaps  298:        return(ROFF_IGN);
1.67      kristaps  299: }
                    300:
                    301:
                    302: /* ARGSUSED */
                    303: static enum rofferr
                    304: roff_new_ig(ROFF_ARGS)
                    305: {
                    306:
                    307:        return(roffnode_push(r, ROFF_ig, ln, ppos) ?
                    308:                        ROFF_IGN : ROFF_ERR);
                    309: }
                    310:
                    311:
                    312: int
                    313: roff_endparse(struct roff *r)
                    314: {
                    315:
                    316:        if (NULL == r->last)
                    317:                return(1);
                    318:        return((*r->msg)(MANDOCERR_SCOPEEXIT, r->data,
                    319:                                r->last->line, r->last->col, NULL));
                    320: }

CVSweb