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

Annotation of mandoc/roff.c, Revision 1.4

1.4     ! kristaps    1: /* $Id: roff.c,v 1.3 2008/11/24 18:34:50 kristaps Exp $ */
1.1       kristaps    2: /*
                      3:  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
                      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
                      7:  * above copyright notice and this permission notice appear in all
                      8:  * copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
                     11:  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
                     12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
                     13:  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
                     14:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
                     15:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
                     16:  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     17:  * PERFORMANCE OF THIS SOFTWARE.
                     18:  */
                     19: #include <assert.h>
                     20: #include <ctype.h>
                     21: #include <err.h>
                     22: #include <stdlib.h>
                     23: #include <stdio.h>
                     24: #include <string.h>
                     25: #include <time.h>
                     26:
                     27: #include "libmdocml.h"
                     28: #include "private.h"
                     29:
                     30: #define        ROFF_MAXARG       10
                     31:
                     32: enum   roffd {
                     33:        ROFF_ENTER = 0,
                     34:        ROFF_EXIT
                     35: };
                     36:
1.3       kristaps   37: /* FIXME: prolog roffs can be text roffs, too. */
                     38:
1.1       kristaps   39: enum   rofftype {
                     40:        ROFF_COMMENT,
                     41:        ROFF_TEXT,
                     42:        ROFF_LAYOUT
                     43: };
                     44:
                     45: #define        ROFFCALL_ARGS \
1.2       kristaps   46:        int tok, struct rofftree *tree, \
                     47:        const char *argv[], enum roffd type
1.1       kristaps   48:
                     49: struct rofftree;
                     50:
                     51: struct rofftok {
                     52:        int             (*cb)(ROFFCALL_ARGS);
                     53:        enum rofftype     type;
                     54:        int               flags;
                     55: #define        ROFF_NESTED      (1 << 0)
                     56: #define        ROFF_PARSED      (1 << 1)
                     57: #define        ROFF_CALLABLE    (1 << 2)
                     58: #define        ROFF_QUOTES      (1 << 3)
                     59: };
                     60:
                     61: struct roffarg {
1.4     ! kristaps   62:        int               tok;
1.1       kristaps   63:        int               flags;
                     64: #define        ROFF_VALUE       (1 << 0)
                     65: };
                     66:
                     67: struct roffnode {
                     68:        int               tok;
                     69:        struct roffnode  *parent;
                     70:        size_t            line;
                     71: };
                     72:
                     73: struct rofftree {
                     74:        struct roffnode  *last;
                     75:        time_t            date;
1.4     ! kristaps   76:        char              os[64];
        !            77:        char              title[64];
        !            78:        char              section[64];
        !            79:        char              volume[64];
1.1       kristaps   80:        int               state;
                     81: #define        ROFF_PRELUDE     (1 << 1)
                     82: #define        ROFF_PRELUDE_Os  (1 << 2)
                     83: #define        ROFF_PRELUDE_Dt  (1 << 3)
                     84: #define        ROFF_PRELUDE_Dd  (1 << 4)
                     85: #define        ROFF_BODY        (1 << 5)
                     86:
1.4     ! kristaps   87:        roffin           roffin;
        !            88:        roffblkin        roffblkin;
        !            89:        roffout          roffout;
        !            90:        roffblkout       roffblkout;
        !            91:
        !            92:        struct md_mbuf          *mbuf; /* NULL if !flush. */
1.1       kristaps   93:        const struct md_args    *args;
                     94:        const struct md_rbuf    *rbuf;
                     95: };
                     96:
                     97: static int               roff_Dd(ROFFCALL_ARGS);
                     98: static int               roff_Dt(ROFFCALL_ARGS);
                     99: static int               roff_Os(ROFFCALL_ARGS);
1.2       kristaps  100:
                    101: static int               roff_layout(ROFFCALL_ARGS);
                    102: static int               roff_text(ROFFCALL_ARGS);
1.1       kristaps  103:
1.4     ! kristaps  104: static struct roffnode  *roffnode_new(int, struct rofftree *);
1.1       kristaps  105: static void              roffnode_free(int, struct rofftree *);
                    106:
                    107: static int               rofffindtok(const char *);
                    108: static int               rofffindarg(const char *);
1.2       kristaps  109: static int               rofffindcallable(const char *);
1.1       kristaps  110: static int               roffargs(int, char *, char **);
                    111: static int               roffparse(struct rofftree *, char *, size_t);
                    112: static int               textparse(const struct rofftree *,
                    113:                                const char *, size_t);
                    114:
                    115:
1.4     ! kristaps  116: static const struct rofftok tokens[ROFF_MAX] = {
        !           117:        {        NULL, ROFF_COMMENT, 0 },
        !           118:        {     roff_Dd, ROFF_TEXT, 0 },                  /* Dd */
        !           119:        {     roff_Dt, ROFF_TEXT, 0 },                  /* Dt */
        !           120:        {     roff_Os, ROFF_TEXT, 0 },                  /* Os */
        !           121:        { roff_layout, ROFF_LAYOUT, ROFF_PARSED },      /* Sh */
        !           122:        { roff_layout, ROFF_LAYOUT, ROFF_PARSED },      /* Ss XXX */
        !           123:        { roff_layout, ROFF_LAYOUT, 0 },                /* Pp */
        !           124:        { roff_layout, ROFF_LAYOUT, 0 },                /* D1 */
        !           125:        { roff_layout, ROFF_LAYOUT, 0 },                /* Dl */
        !           126:        { roff_layout, ROFF_LAYOUT, 0 },                /* Bd */
        !           127:        { roff_layout, ROFF_LAYOUT, 0 },                /* Ed */
        !           128:        { roff_layout, ROFF_LAYOUT, 0 },                /* Bl */
        !           129:        { roff_layout, ROFF_LAYOUT, 0 },                /* El */
        !           130:        { roff_layout, ROFF_LAYOUT, 0 },                /* It */
        !           131:        {   roff_text, ROFF_TEXT, ROFF_PARSED },        /* An */
        !           132:        {   roff_text, ROFF_TEXT, ROFF_PARSED | ROFF_CALLABLE }, /* Li */
1.1       kristaps  133: };
                    134:
1.4     ! kristaps  135: /* FIXME: multiple owners? */
        !           136:
        !           137: static const struct roffarg tokenargs[ROFF_ARGMAX] = {
        !           138:        { ROFF_An, 0 },                         /* split */
        !           139:        { ROFF_An, 0 },                         /* nosplit */
        !           140:        { ROFF_Bd, 0 },                         /* ragged */
        !           141:        { ROFF_Bd, 0 },                         /* unfilled */
        !           142:        { ROFF_Bd, 0 },                         /* literal */
        !           143:        { ROFF_Bd, ROFF_VALUE },                /* file */
        !           144:        { ROFF_Bd, ROFF_VALUE },                /* offset */
        !           145:        { ROFF_Bl, 0 },                         /* bullet */
        !           146:        { ROFF_Bl, 0 },                         /* dash */
        !           147:        { ROFF_Bl, 0 },                         /* hyphen */
        !           148:        { ROFF_Bl, 0 },                         /* item */
        !           149:        { ROFF_Bl, 0 },                         /* enum */
        !           150:        { ROFF_Bl, 0 },                         /* tag */
        !           151:        { ROFF_Bl, 0 },                         /* diag */
        !           152:        { ROFF_Bl, 0 },                         /* hang */
        !           153:        { ROFF_Bl, 0 },                         /* ohang */
        !           154:        { ROFF_Bl, 0 },                         /* inset */
        !           155:        { ROFF_Bl, 0 },                         /* column */
1.1       kristaps  156: };
                    157:
1.4     ! kristaps  158: static const char *const toknames[ROFF_MAX] = ROFF_NAMES;
        !           159: static         const char *const tokargnames[ROFF_ARGMAX] = ROFF_ARGNAMES;
        !           160:
1.1       kristaps  161:
                    162: int
                    163: roff_free(struct rofftree *tree, int flush)
                    164: {
                    165:        int              error;
                    166:
                    167:        assert(tree->mbuf);
                    168:        if ( ! flush)
                    169:                tree->mbuf = NULL;
                    170:
                    171:        /* LINTED */
                    172:        while (tree->last)
                    173:                if ( ! (*tokens[tree->last->tok].cb)
1.2       kristaps  174:                                (tree->last->tok, tree, NULL, ROFF_EXIT))
1.1       kristaps  175:                        /* Disallow flushing. */
                    176:                        tree->mbuf = NULL;
                    177:
                    178:        error = tree->mbuf ? 0 : 1;
                    179:
                    180:        if (tree->mbuf && (ROFF_PRELUDE & tree->state)) {
                    181:                warnx("%s: prelude never finished",
                    182:                                tree->rbuf->name);
                    183:                error = 1;
                    184:        }
                    185:
                    186:        free(tree);
                    187:        return(error ? 0 : 1);
                    188: }
                    189:
                    190:
                    191: struct rofftree *
                    192: roff_alloc(const struct md_args *args, struct md_mbuf *out,
1.4     ! kristaps  193:                const struct md_rbuf *in, roffin textin,
        !           194:                roffout textout, roffblkin blkin, roffblkout blkout)
1.1       kristaps  195: {
                    196:        struct rofftree *tree;
                    197:
                    198:        if (NULL == (tree = calloc(1, sizeof(struct rofftree)))) {
                    199:                warn("malloc");
                    200:                return(NULL);
                    201:        }
                    202:
                    203:        tree->state = ROFF_PRELUDE;
                    204:        tree->args = args;
                    205:        tree->mbuf = out;
                    206:        tree->rbuf = in;
1.4     ! kristaps  207:        tree->roffin = textin;
        !           208:        tree->roffout = textout;
        !           209:        tree->roffblkin = blkin;
        !           210:        tree->roffblkout = blkout;
1.1       kristaps  211:
                    212:        return(tree);
                    213: }
                    214:
                    215:
                    216: int
                    217: roff_engine(struct rofftree *tree, char *buf, size_t sz)
                    218: {
                    219:
                    220:        if (0 == sz) {
                    221:                warnx("%s: blank line (line %zu)",
                    222:                                tree->rbuf->name,
                    223:                                tree->rbuf->line);
                    224:                return(0);
                    225:        } else if ('.' != *buf)
                    226:                return(textparse(tree, buf, sz));
                    227:
                    228:        return(roffparse(tree, buf, sz));
                    229: }
                    230:
                    231:
                    232: static int
                    233: textparse(const struct rofftree *tree, const char *buf, size_t sz)
                    234: {
                    235:
                    236:        if (NULL == tree->last) {
                    237:                warnx("%s: unexpected text (line %zu)",
                    238:                                tree->rbuf->name,
                    239:                                tree->rbuf->line);
                    240:                return(0);
                    241:        } else if (NULL == tree->last->parent) {
                    242:                warnx("%s: disallowed text (line %zu)",
                    243:                                tree->rbuf->name,
                    244:                                tree->rbuf->line);
                    245:                return(0);
                    246:        }
                    247:
                    248:        /* Print text. */
                    249:
                    250:        return(1);
                    251: }
                    252:
                    253:
                    254: static int
                    255: roffargs(int tok, char *buf, char **argv)
                    256: {
                    257:        int              i;
                    258:
                    259:        (void)tok;/* FIXME: quotable strings? */
                    260:
                    261:        assert(tok >= 0 && tok < ROFF_MAX);
                    262:        assert('.' == *buf);
                    263:
                    264:        /* LINTED */
                    265:        for (i = 0; *buf && i < ROFF_MAXARG; i++) {
                    266:                argv[i] = buf++;
                    267:                while (*buf && ! isspace(*buf))
                    268:                        buf++;
                    269:                if (0 == *buf) {
                    270:                        continue;
                    271:                }
                    272:                *buf++ = 0;
                    273:                while (*buf && isspace(*buf))
                    274:                        buf++;
                    275:        }
                    276:
                    277:        assert(i > 0);
                    278:        if (i < ROFF_MAXARG)
                    279:                argv[i] = NULL;
                    280:
                    281:        return(ROFF_MAXARG > i);
                    282: }
                    283:
                    284:
                    285: static int
                    286: roffparse(struct rofftree *tree, char *buf, size_t sz)
                    287: {
                    288:        int               tok, t;
                    289:        struct roffnode  *node;
                    290:        char             *argv[ROFF_MAXARG];
                    291:        const char      **argvp;
                    292:
                    293:        assert(sz > 0);
                    294:
                    295:        /*
                    296:         * Extract the token identifier from the buffer.  If there's no
                    297:         * callback for the token (comment, etc.) then exit immediately.
                    298:         * We don't do any error handling (yet), so if the token doesn't
                    299:         * exist, die.
                    300:         */
                    301:
                    302:        if (3 > sz) {
                    303:                warnx("%s: malformed line (line %zu)",
                    304:                                tree->rbuf->name,
                    305:                                tree->rbuf->line);
                    306:                return(0);
                    307:        } else if (ROFF_MAX == (tok = rofffindtok(buf + 1))) {
                    308:                warnx("%s: unknown line token `%c%c' (line %zu)",
                    309:                                tree->rbuf->name,
                    310:                                *(buf + 1), *(buf + 2),
                    311:                                tree->rbuf->line);
                    312:                return(0);
                    313:        } else if (ROFF_COMMENT == tokens[tok].type)
                    314:                /* Ignore comment tokens. */
                    315:                return(1);
                    316:
                    317:        if ( ! roffargs(tok, buf, argv)) {
                    318:                warnx("%s: too many arguments to `%s' (line %zu)",
1.4     ! kristaps  319:                                tree->rbuf->name, toknames[tok],
1.1       kristaps  320:                                tree->rbuf->line);
                    321:                return(0);
                    322:        }
                    323:
                    324:        /*
                    325:         * If this is a non-nestable layout token and we're below a
                    326:         * token of the same type, then recurse upward to the token,
                    327:         * closing out the interim scopes.
                    328:         *
                    329:         * If there's a nested token on the chain, then raise an error
                    330:         * as nested tokens have corresponding "ending" tokens and we're
                    331:         * breaking their scope.
                    332:         */
                    333:
                    334:        node = NULL;
                    335:
                    336:        if (ROFF_LAYOUT == tokens[tok].type &&
                    337:                        ! (ROFF_NESTED & tokens[tok].flags)) {
                    338:                for (node = tree->last; node; node = node->parent) {
                    339:                        if (node->tok == tok)
                    340:                                break;
                    341:
                    342:                        /* Don't break nested scope. */
                    343:
                    344:                        if ( ! (ROFF_NESTED & tokens[node->tok].flags))
                    345:                                continue;
                    346:                        warnx("%s: scope of %s (line %zu) broken by "
                    347:                                        "%s (line %zu)",
                    348:                                        tree->rbuf->name,
1.4     ! kristaps  349:                                        toknames[tok], node->line,
        !           350:                                        toknames[node->tok],
1.1       kristaps  351:                                        tree->rbuf->line);
                    352:                        return(0);
                    353:                }
                    354:        }
                    355:
                    356:        if (node) {
                    357:                assert(ROFF_LAYOUT == tokens[tok].type);
                    358:                assert( ! (ROFF_NESTED & tokens[tok].flags));
                    359:                assert(node->tok == tok);
                    360:
                    361:                /* Clear up to last scoped token. */
                    362:
                    363:                /* LINTED */
                    364:                do {
                    365:                        t = tree->last->tok;
                    366:                        if ( ! (*tokens[tree->last->tok].cb)
1.2       kristaps  367:                                        (tree->last->tok, tree, NULL, ROFF_EXIT))
1.1       kristaps  368:                                return(0);
                    369:                } while (t != tok);
                    370:        }
                    371:
                    372:        /* Proceed with actual token processing. */
                    373:
                    374:        argvp = (const char **)&argv[1];
1.2       kristaps  375:        return((*tokens[tok].cb)(tok, tree, argvp, ROFF_ENTER));
1.1       kristaps  376: }
                    377:
                    378:
                    379: static int
                    380: rofffindarg(const char *name)
                    381: {
                    382:        size_t           i;
                    383:
                    384:        /* FIXME: use a table, this is slow but ok for now. */
                    385:
                    386:        /* LINTED */
                    387:        for (i = 0; i < ROFF_ARGMAX; i++)
                    388:                /* LINTED */
1.4     ! kristaps  389:                if (0 == strcmp(name, tokargnames[i]))
1.1       kristaps  390:                        return((int)i);
                    391:
                    392:        return(ROFF_ARGMAX);
                    393: }
                    394:
                    395:
                    396: static int
                    397: rofffindtok(const char *name)
                    398: {
                    399:        size_t           i;
                    400:
                    401:        /* FIXME: use a table, this is slow but ok for now. */
                    402:
                    403:        /* LINTED */
                    404:        for (i = 0; i < ROFF_MAX; i++)
                    405:                /* LINTED */
1.4     ! kristaps  406:                if (0 == strncmp(name, toknames[i], 2))
1.1       kristaps  407:                        return((int)i);
                    408:
                    409:        return(ROFF_MAX);
                    410: }
                    411:
                    412:
1.2       kristaps  413: static int
                    414: rofffindcallable(const char *name)
                    415: {
                    416:        int              c;
                    417:
                    418:        if (ROFF_MAX == (c = rofffindtok(name)))
                    419:                return(ROFF_MAX);
                    420:        return(ROFF_CALLABLE & tokens[c].flags ? c : ROFF_MAX);
                    421: }
                    422:
                    423:
1.1       kristaps  424: static struct roffnode *
1.4     ! kristaps  425: roffnode_new(int tokid, struct rofftree *tree)
1.1       kristaps  426: {
                    427:        struct roffnode *p;
                    428:
                    429:        if (NULL == (p = malloc(sizeof(struct roffnode)))) {
                    430:                warn("malloc");
                    431:                return(NULL);
                    432:        }
                    433:
1.4     ! kristaps  434:        p->line = tree->rbuf->line;
1.1       kristaps  435:        p->tok = tokid;
                    436:        p->parent = tree->last;
                    437:        tree->last = p;
                    438:        return(p);
                    439: }
                    440:
                    441:
                    442: static void
                    443: roffnode_free(int tokid, struct rofftree *tree)
                    444: {
                    445:        struct roffnode *p;
                    446:
                    447:        assert(tree->last);
                    448:        assert(tree->last->tok == tokid);
                    449:
                    450:        p = tree->last;
                    451:        tree->last = tree->last->parent;
                    452:        free(p);
                    453: }
                    454:
                    455:
                    456: /* ARGSUSED */
                    457: static int
                    458: roff_Dd(ROFFCALL_ARGS)
                    459: {
                    460:
1.4     ! kristaps  461:        if (ROFF_BODY & tree->state) {
        !           462:                assert( ! (ROFF_PRELUDE & tree->state));
        !           463:                assert(ROFF_PRELUDE_Dd & tree->state);
        !           464:                return(roff_text(tok, tree, argv, type));
        !           465:        }
        !           466:
1.1       kristaps  467:        assert(ROFF_PRELUDE & tree->state);
1.4     ! kristaps  468:        assert( ! (ROFF_BODY & tree->state));
        !           469:
        !           470:        if (ROFF_PRELUDE_Dd & tree->state ||
        !           471:                        ROFF_PRELUDE_Dt & tree->state) {
1.1       kristaps  472:                warnx("%s: prelude `Dd' out-of-order (line %zu)",
                    473:                                tree->rbuf->name, tree->rbuf->line);
                    474:                return(0);
                    475:        }
                    476:
1.4     ! kristaps  477:        /* TODO: parse date. */
        !           478:
1.1       kristaps  479:        assert(NULL == tree->last);
                    480:        tree->state |= ROFF_PRELUDE_Dd;
                    481:
                    482:        return(1);
                    483: }
                    484:
                    485:
                    486: /* ARGSUSED */
                    487: static int
                    488: roff_Dt(ROFFCALL_ARGS)
                    489: {
                    490:
1.4     ! kristaps  491:        if (ROFF_BODY & tree->state) {
        !           492:                assert( ! (ROFF_PRELUDE & tree->state));
        !           493:                assert(ROFF_PRELUDE_Dt & tree->state);
        !           494:                return(roff_text(tok, tree, argv, type));
        !           495:        }
        !           496:
1.1       kristaps  497:        assert(ROFF_PRELUDE & tree->state);
1.4     ! kristaps  498:        assert( ! (ROFF_BODY & tree->state));
        !           499:
1.1       kristaps  500:        if ( ! (ROFF_PRELUDE_Dd & tree->state) ||
                    501:                        (ROFF_PRELUDE_Dt & tree->state)) {
                    502:                warnx("%s: prelude `Dt' out-of-order (line %zu)",
                    503:                                tree->rbuf->name, tree->rbuf->line);
                    504:                return(0);
                    505:        }
                    506:
1.4     ! kristaps  507:        /* TODO: parse date. */
        !           508:
1.1       kristaps  509:        assert(NULL == tree->last);
                    510:        tree->state |= ROFF_PRELUDE_Dt;
                    511:
                    512:        return(1);
                    513: }
                    514:
                    515:
                    516: /* ARGSUSED */
                    517: static int
                    518: roff_Os(ROFFCALL_ARGS)
                    519: {
                    520:
                    521:        if (ROFF_EXIT == type) {
1.4     ! kristaps  522:                assert(ROFF_PRELUDE_Os & tree->state);
        !           523:                return(roff_layout(tok, tree, argv, type));
        !           524:        } else if (ROFF_BODY & tree->state) {
        !           525:                assert( ! (ROFF_PRELUDE & tree->state));
        !           526:                assert(ROFF_PRELUDE_Os & tree->state);
        !           527:                return(roff_text(tok, tree, argv, type));
        !           528:        }
1.1       kristaps  529:
                    530:        assert(ROFF_PRELUDE & tree->state);
                    531:        if ( ! (ROFF_PRELUDE_Dt & tree->state) ||
                    532:                        ! (ROFF_PRELUDE_Dd & tree->state)) {
                    533:                warnx("%s: prelude `Os' out-of-order (line %zu)",
                    534:                                tree->rbuf->name, tree->rbuf->line);
                    535:                return(0);
                    536:        }
                    537:
1.4     ! kristaps  538:        /* TODO: extract OS. */
1.1       kristaps  539:
                    540:        tree->state |= ROFF_PRELUDE_Os;
                    541:        tree->state &= ~ROFF_PRELUDE;
                    542:        tree->state |= ROFF_BODY;
                    543:
1.4     ! kristaps  544:        assert(NULL == tree->last);
        !           545:
        !           546:        return(roff_layout(tok, tree, argv, type));
1.1       kristaps  547: }
                    548:
                    549:
1.2       kristaps  550: /* ARGUSED */
1.1       kristaps  551: static int
                    552: roffnextopt(const char ***in, char **val)
                    553: {
                    554:        const char      *arg, **argv;
                    555:        int              v;
                    556:
                    557:        *val = NULL;
                    558:        argv = *in;
                    559:        assert(argv);
                    560:
                    561:        if (NULL == (arg = *argv))
                    562:                return(-1);
                    563:        if ('-' != *arg)
                    564:                return(-1);
                    565:        if (ROFF_ARGMAX == (v = rofffindarg(&arg[1])))
                    566:                return(-1);
                    567:        if ( ! (ROFF_VALUE & tokenargs[v].flags))
                    568:                return(v);
                    569:
                    570:        *in = ++argv;
                    571:
                    572:        /* FIXME: what if this looks like a roff token or argument? */
                    573:
                    574:        return(*argv ? v : ROFF_ARGMAX);
                    575: }
                    576:
                    577:
                    578: /* ARGSUSED */
                    579: static int
1.2       kristaps  580: roff_layout(ROFFCALL_ARGS)
1.1       kristaps  581: {
1.2       kristaps  582:        int              i, c, argcp[ROFF_MAXARG];
                    583:        char            *v, *argvp[ROFF_MAXARG];
1.1       kristaps  584:
1.4     ! kristaps  585:        if (ROFF_PRELUDE & tree->state) {
        !           586:                warnx("%s: macro `%s' called in prelude (line %zu)",
        !           587:                                tree->rbuf->name, toknames[tok],
        !           588:                                tree->rbuf->line);
        !           589:                return(0);
        !           590:        }
        !           591:
1.2       kristaps  592:        if (ROFF_EXIT == type) {
                    593:                roffnode_free(tok, tree);
1.4     ! kristaps  594:                return((*tree->roffblkout)(tok));
1.2       kristaps  595:        }
1.1       kristaps  596:
1.2       kristaps  597:        i = 0;
                    598:        while (-1 != (c = roffnextopt(&argv, &v))) {
                    599:                if (ROFF_ARGMAX == c) {
                    600:                        warnx("%s: error parsing `%s' args (line %zu)",
1.1       kristaps  601:                                        tree->rbuf->name,
1.4     ! kristaps  602:                                        toknames[tok],
1.1       kristaps  603:                                        tree->rbuf->line);
                    604:                        return(0);
                    605:                }
1.2       kristaps  606:                argcp[i] = c;
                    607:                argvp[i] = v;
1.1       kristaps  608:                argv++;
                    609:        }
                    610:
1.4     ! kristaps  611:        if (NULL == roffnode_new(tok, tree))
1.2       kristaps  612:                return(0);
                    613:
1.4     ! kristaps  614:        if ( ! (*tree->roffin)(tok, argcp, argvp))
1.2       kristaps  615:                return(0);
                    616:
                    617:        if ( ! (ROFF_PARSED & tokens[tok].flags)) {
                    618:                /* TODO: print all tokens. */
                    619:
1.4     ! kristaps  620:                if ( ! ((*tree->roffout)(tok)))
1.2       kristaps  621:                        return(0);
1.4     ! kristaps  622:                return((*tree->roffblkin)(tok));
1.2       kristaps  623:        }
                    624:
1.1       kristaps  625:        while (*argv) {
1.2       kristaps  626:                if (2 >= strlen(*argv) && ROFF_MAX !=
                    627:                                (c = rofffindcallable(*argv)))
                    628:                        if ( ! (*tokens[c].cb)(c, tree,
                    629:                                                argv + 1, ROFF_ENTER))
                    630:                                return(0);
                    631:
                    632:                /* TODO: print token. */
                    633:                argv++;
                    634:        }
                    635:
1.4     ! kristaps  636:        if ( ! ((*tree->roffout)(tok)))
1.2       kristaps  637:                return(0);
                    638:
1.4     ! kristaps  639:        return((*tree->roffblkin)(tok));
1.2       kristaps  640: }
                    641:
                    642:
                    643: /* ARGSUSED */
                    644: static int
                    645: roff_text(ROFFCALL_ARGS)
                    646: {
                    647:        int              i, c, argcp[ROFF_MAXARG];
                    648:        char            *v, *argvp[ROFF_MAXARG];
                    649:
1.4     ! kristaps  650:        if (ROFF_PRELUDE & tree->state) {
        !           651:                warnx("%s: macro `%s' called in prelude (line %zu)",
        !           652:                                tree->rbuf->name, toknames[tok],
        !           653:                                tree->rbuf->line);
        !           654:                return(0);
        !           655:        }
        !           656:
1.2       kristaps  657:        i = 0;
                    658:        while (-1 != (c = roffnextopt(&argv, &v))) {
                    659:                if (ROFF_ARGMAX == c) {
                    660:                        warnx("%s: error parsing `%s' args (line %zu)",
                    661:                                        tree->rbuf->name,
1.4     ! kristaps  662:                                        toknames[tok],
1.2       kristaps  663:                                        tree->rbuf->line);
                    664:                        return(0);
1.1       kristaps  665:                }
1.2       kristaps  666:                argcp[i] = c;
                    667:                argvp[i] = v;
1.1       kristaps  668:                argv++;
                    669:        }
                    670:
1.4     ! kristaps  671:        if ( ! (*tree->roffin)(tok, argcp, argvp))
1.2       kristaps  672:                return(0);
1.1       kristaps  673:
1.2       kristaps  674:        if ( ! (ROFF_PARSED & tokens[tok].flags)) {
                    675:                /* TODO: print all tokens. */
1.4     ! kristaps  676:                return((*tree->roffout)(tok));
1.2       kristaps  677:        }
1.1       kristaps  678:
1.2       kristaps  679:        while (*argv) {
                    680:                if (2 >= strlen(*argv) && ROFF_MAX !=
                    681:                                (c = rofffindcallable(*argv)))
                    682:                        if ( ! (*tokens[c].cb)(c, tree,
                    683:                                                argv + 1, ROFF_ENTER))
                    684:                                return(0);
                    685:
                    686:                /* TODO: print token. */
                    687:                argv++;
                    688:        }
                    689:
1.4     ! kristaps  690:        return((*tree->roffout)(tok));
1.1       kristaps  691: }

CVSweb