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

Annotation of mandoc/macro.c, Revision 1.17

1.17    ! kristaps    1: /* $Id: macro.c,v 1.16 2009/01/01 20:40:16 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:  */
1.2       kristaps   19: #include <assert.h>
                     20: #include <ctype.h>
1.1       kristaps   21: #include <stdlib.h>
1.2       kristaps   22: #include <stdio.h>
1.5       kristaps   23: #include <string.h>
1.11      kristaps   24: #ifdef __linux__
                     25: #include <time.h>
                     26: #endif
1.2       kristaps   27:
                     28: #include "private.h"
                     29:
1.10      kristaps   30: /* FIXME: maxlineargs should be per LINE, no per TOKEN. */
                     31:
1.3       kristaps   32: #define        _CC(p)  ((const char **)p)
1.2       kristaps   33:
1.16      kristaps   34: static int       scope_rewind_imp(struct mdoc *, int, int);
1.6       kristaps   35: static int       scope_rewind_exp(struct mdoc *, int, int, int);
1.16      kristaps   36: static int       scope_rewind_line(struct mdoc *, int, int);
1.3       kristaps   37: static int       append_text(struct mdoc *, int,
                     38:                        int, int, char *[]);
1.16      kristaps   39: static int       append_text_argv(struct mdoc *, int, int,
                     40:                        int, char *[], int, const struct mdoc_arg *);
1.7       kristaps   41: static int       append_delims(struct mdoc *, int, int *, char *);
1.6       kristaps   42:
                     43:
                     44: static int
1.16      kristaps   45: scope_rewind_line(struct mdoc *mdoc, int ppos, int tok)
1.6       kristaps   46: {
                     47:        struct mdoc_node *n;
1.7       kristaps   48:        int               t;
                     49:
1.6       kristaps   50:        /* LINTED */
1.16      kristaps   51:        for (n = mdoc->last; n; n = n->parent) {
                     52:                if (MDOC_HEAD != n->type)
1.6       kristaps   53:                        continue;
1.16      kristaps   54:                if (tok == (t = n->data.head.tok))
1.6       kristaps   55:                        break;
1.7       kristaps   56:                if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
                     57:                        continue;
1.6       kristaps   58:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
                     59:        }
                     60:
1.16      kristaps   61:        mdoc->last = n ? n : mdoc->last;
                     62:        mdoc->next = MDOC_NEXT_SIBLING;
1.6       kristaps   63:        return(1);
                     64: }
                     65:
                     66:
                     67: static int
1.16      kristaps   68: scope_rewind_exp(struct mdoc *mdoc, int ppos, int tok, int tt)
1.6       kristaps   69: {
1.7       kristaps   70:        struct mdoc_node *n;
1.6       kristaps   71:
1.7       kristaps   72:        assert(mdoc->last);
1.6       kristaps   73:
1.7       kristaps   74:        /* LINTED */
                     75:        for (n = mdoc->last->parent; n; n = n->parent) {
                     76:                if (MDOC_BLOCK != n->type)
                     77:                        continue;
1.16      kristaps   78:                if (tt == n->data.block.tok)
                     79:                        break;
                     80:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
                     81:        }
                     82:
                     83:        if (NULL == (mdoc->last = n))
                     84:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_NOCTX));
                     85:
                     86:        mdoc->next = MDOC_NEXT_SIBLING;
                     87:        return(mdoc_valid_post(mdoc, tok, ppos));
                     88: }
                     89:
                     90:
                     91: static int
                     92: scope_rewind_imp(struct mdoc *mdoc, int ppos, int tok)
                     93: {
                     94:        struct mdoc_node *n;
                     95:        int               t;
                     96:
                     97:        n = mdoc->last ? mdoc->last->parent : NULL;
                     98:
                     99:        /* LINTED */
                    100:        for ( ; n; n = n->parent) {
                    101:                if (MDOC_BLOCK != n->type)
                    102:                        continue;
                    103:                if (tok == (t = n->data.block.tok))
1.7       kristaps  104:                        break;
1.16      kristaps  105:                if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
                    106:                        continue;
1.7       kristaps  107:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
1.6       kristaps  108:        }
                    109:
1.16      kristaps  110:        mdoc->last = n ? n : mdoc->last;
                    111:        mdoc->next = MDOC_NEXT_SIBLING;
                    112:        return(mdoc_valid_post(mdoc, tok, ppos));
1.15      kristaps  113: }
1.6       kristaps  114:
1.15      kristaps  115:
                    116: static int
                    117: append_delims(struct mdoc *mdoc, int tok, int *pos, char *buf)
                    118: {
                    119:        int              c, lastarg;
                    120:        char            *p;
                    121:
                    122:        if (0 == buf[*pos])
                    123:                return(1);
                    124:
                    125:        for (;;) {
                    126:                lastarg = *pos;
                    127:                c = mdoc_args(mdoc, tok, pos, buf, 0, &p);
                    128:                if (ARGS_ERROR == c)
                    129:                        return(0);
                    130:                else if (ARGS_EOLN == c)
                    131:                        break;
                    132:                assert(mdoc_isdelim(p));
                    133:                mdoc_word_alloc(mdoc, lastarg, p);
1.16      kristaps  134:                mdoc->next = MDOC_NEXT_SIBLING;
1.15      kristaps  135:        }
1.2       kristaps  136:
1.1       kristaps  137:        return(1);
                    138: }
                    139:
1.2       kristaps  140:
                    141: static int
1.16      kristaps  142: append_text_argv(struct mdoc *mdoc, int tok, int pos,
                    143:                int sz, char *args[],
1.13      kristaps  144:                int argc, const struct mdoc_arg *argv)
                    145: {
                    146:
1.16      kristaps  147:        if ( ! mdoc_valid_pre(mdoc, tok, pos, 0, NULL, argc, argv))
1.15      kristaps  148:                return(0);
1.17    ! kristaps  149:
        !           150:        switch (tok) {
        !           151:        case (MDOC_Pf):
        !           152:                /* TODO: only use first two arguments in element. */
        !           153:                break;
        !           154:        default:
        !           155:                break;
        !           156:        }
        !           157:
1.16      kristaps  158:        mdoc_elem_alloc(mdoc, pos, tok, (size_t)argc,
                    159:                        argv, (size_t)sz, _CC(args));
                    160:        mdoc->next = MDOC_NEXT_SIBLING;
1.13      kristaps  161:        return(1);
                    162: }
                    163:
                    164:
                    165: static int
1.16      kristaps  166: append_text(struct mdoc *mdoc, int tok,
1.10      kristaps  167:                int pos, int sz, char *args[])
                    168: {
                    169:
1.16      kristaps  170:        if ( ! mdoc_valid_pre(mdoc, tok, pos, sz, _CC(args), 0, NULL))
1.14      kristaps  171:                return(0);
                    172:
1.10      kristaps  173:        switch (tok) {
1.11      kristaps  174:        case (MDOC_At):
                    175:                if (0 == sz)
                    176:                        break;
1.15      kristaps  177:                if (ATT_DEFAULT == mdoc_atoatt(args[0])) {
1.11      kristaps  178:                        mdoc_elem_alloc(mdoc, pos, tok,
                    179:                                        0, NULL, 0, NULL);
1.16      kristaps  180:                        mdoc->next = MDOC_NEXT_SIBLING;
1.11      kristaps  181:                        mdoc_word_alloc(mdoc, pos, args[0]);
1.16      kristaps  182:                        mdoc->next = MDOC_NEXT_SIBLING;
                    183:                } else {
1.15      kristaps  184:                        mdoc_elem_alloc(mdoc, pos, tok, 0,
                    185:                                        NULL, 1, _CC(&args[0]));
1.16      kristaps  186:                        mdoc->next = MDOC_NEXT_SIBLING;
                    187:                }
1.11      kristaps  188:
1.15      kristaps  189:                if (sz > 1)
                    190:                        mdoc_word_alloc(mdoc, pos, args[1]);
1.16      kristaps  191:                mdoc->next = MDOC_NEXT_SIBLING;
1.11      kristaps  192:                return(1);
1.16      kristaps  193:
1.14      kristaps  194:        default:
1.10      kristaps  195:                break;
                    196:        }
                    197:
                    198:        mdoc_elem_alloc(mdoc, pos, tok, 0, NULL, (size_t)sz, _CC(args));
1.16      kristaps  199:        mdoc->next = MDOC_NEXT_SIBLING;
1.4       kristaps  200:        return(1);
1.2       kristaps  201: }
                    202:
1.1       kristaps  203:
1.2       kristaps  204: int
1.5       kristaps  205: macro_text(MACRO_PROT_ARGS)
1.2       kristaps  206: {
1.15      kristaps  207:        int               lastarg, lastpunct, c, j, fl;
1.13      kristaps  208:        char             *args[MDOC_LINEARG_MAX];
1.1       kristaps  209:
1.7       kristaps  210:        /* Token pre-processing.  */
                    211:
                    212:        switch (tok) {
                    213:        case (MDOC_Pp):
                    214:                /* `.Pp' ignored when following `.Sh' or `.Ss'. */
                    215:                assert(mdoc->last);
                    216:                if (MDOC_BODY != mdoc->last->type)
                    217:                        break;
                    218:                switch (mdoc->last->data.body.tok) {
                    219:                case (MDOC_Ss):
                    220:                        /* FALLTHROUGH */
                    221:                case (MDOC_Sh):
                    222:                        if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_AFTER_BLK))
                    223:                                return(0);
                    224:                        return(1);
                    225:                default:
                    226:                        break;
                    227:                }
                    228:                break;
                    229:        default:
                    230:                break;
                    231:        }
                    232:
                    233:        /* Process line parameters. */
                    234:
                    235:        j = 0;
                    236:        lastarg = ppos;
                    237:        lastpunct = 0;
1.15      kristaps  238:        fl = ARGS_DELIM;
                    239:
                    240:        if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
                    241:                fl |= ARGS_QUOTED;
1.7       kristaps  242:
1.2       kristaps  243: again:
1.7       kristaps  244:        if (j == MDOC_LINEARG_MAX)
                    245:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
                    246:
                    247:        /*
                    248:         * Parse out the next argument, unquoted and unescaped.   If
                    249:         * we're a word (which may be punctuation followed eventually by
                    250:         * a real word), then fall into checking for callables.  If
                    251:         * only punctuation remains and we're the first, then flush
                    252:         * arguments, punctuation and exit; else, return to the caller.
                    253:         */
                    254:
1.6       kristaps  255:        lastarg = *pos;
1.2       kristaps  256:
1.15      kristaps  257:        switch (mdoc_args(mdoc, tok, pos, buf, fl, &args[j])) {
1.7       kristaps  258:        case (ARGS_ERROR):
1.2       kristaps  259:                return(0);
1.7       kristaps  260:        case (ARGS_WORD):
                    261:                break;
                    262:        case (ARGS_PUNCT):
                    263:                if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
                    264:                        return(0);
1.8       kristaps  265:                if (ppos > 1)
                    266:                        return(1);
1.7       kristaps  267:                return(append_delims(mdoc, tok, pos, buf));
                    268:        case (ARGS_EOLN):
1.8       kristaps  269:                if (lastpunct)
                    270:                        return(1);
1.7       kristaps  271:                return(append_text(mdoc, tok, ppos, j, args));
                    272:        default:
                    273:                abort();
                    274:                /* NOTREACHED */
                    275:        }
1.2       kristaps  276:
1.7       kristaps  277:        /*
                    278:         * Command found.  First flush out arguments, then call the
                    279:         * command.  If we're the line macro when it exits, flush
                    280:         * terminal punctuation.
                    281:         */
1.2       kristaps  282:
                    283:        if (MDOC_MAX != (c = mdoc_find(mdoc, args[j]))) {
1.7       kristaps  284:                if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
                    285:                        return(0);
                    286:                if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
                    287:                        return(0);
                    288:                if (ppos > 1)
                    289:                        return(1);
                    290:                return(append_delims(mdoc, tok, pos, buf));
1.2       kristaps  291:        }
                    292:
1.7       kristaps  293:        /* Word/non-term-punctuation found. */
1.2       kristaps  294:
1.4       kristaps  295:        if ( ! mdoc_isdelim(args[j])) {
1.7       kristaps  296:                /* Words are appended to the array of arguments. */
1.2       kristaps  297:                j++;
1.8       kristaps  298:                lastpunct = 0;
1.2       kristaps  299:                goto again;
                    300:        }
                    301:
1.7       kristaps  302:        /*
                    303:         * For punctuation, flush all collected words, then flush
                    304:         * punctuation, then start collecting again.   Of course, this
                    305:         * is non-terminal punctuation.
                    306:         */
1.2       kristaps  307:
1.7       kristaps  308:        if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
                    309:                return(0);
1.2       kristaps  310:
1.13      kristaps  311:        mdoc_word_alloc(mdoc, lastarg, args[j]);
1.16      kristaps  312:        mdoc->next = MDOC_NEXT_SIBLING;
1.7       kristaps  313:        j = 0;
1.2       kristaps  314:        lastpunct = 1;
                    315:
                    316:        goto again;
                    317:        /* NOTREACHED */
                    318: }
1.1       kristaps  319:
                    320:
1.16      kristaps  321:
                    322: /* ARGSUSED */
1.2       kristaps  323: int
1.16      kristaps  324: macro_close_explicit(MACRO_PROT_ARGS)
1.5       kristaps  325: {
1.16      kristaps  326:        int              tt;
1.5       kristaps  327:
1.16      kristaps  328:        /*
                    329:         * First close out the explicit scope.  The `end' tags (such as
                    330:         * `.El' to `.Bl' don't cause anything to happen: we merely
                    331:         * readjust our last parse point.
                    332:         */
1.5       kristaps  333:
1.16      kristaps  334:        switch (tok) {
                    335:        case (MDOC_El):
                    336:                tt = MDOC_Bl;
                    337:                break;
                    338:        case (MDOC_Ed):
                    339:                tt = MDOC_Bd;
1.7       kristaps  340:                break;
1.16      kristaps  341:        case (MDOC_Re):
                    342:                tt = MDOC_Rs;
1.7       kristaps  343:                break;
1.17    ! kristaps  344:        case (MDOC_Ef):
        !           345:                tt = MDOC_Bf;
        !           346:                break;
1.7       kristaps  347:        default:
1.16      kristaps  348:                abort();
                    349:                /* NOTREACHED */
1.7       kristaps  350:        }
1.5       kristaps  351:
1.16      kristaps  352:        return(scope_rewind_exp(mdoc, ppos, tok, tt));
1.5       kristaps  353: }
                    354:
                    355:
                    356: int
1.16      kristaps  357: macro_scoped(MACRO_PROT_ARGS)
1.6       kristaps  358: {
1.16      kristaps  359:        int               i, c, lastarg, argc, sz;
                    360:        char             *args[MDOC_LINEARG_MAX];
1.6       kristaps  361:        struct mdoc_arg   argv[MDOC_LINEARG_MAX];
1.16      kristaps  362:        enum mdoc_sec     sec;
1.7       kristaps  363:        struct mdoc_node *n;
1.6       kristaps  364:
1.16      kristaps  365:        assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.6       kristaps  366:
1.7       kristaps  367:        /* Token pre-processing. */
                    368:
                    369:        switch (tok) {
                    370:        case (MDOC_Bl):
                    371:                /* FALLTHROUGH */
                    372:        case (MDOC_Bd):
                    373:                /* `.Pp' ignored when preceding `.Bl' or `.Bd'. */
                    374:                assert(mdoc->last);
                    375:                if (MDOC_ELEM != mdoc->last->type)
                    376:                        break;
                    377:                if (MDOC_Pp != mdoc->last->data.elem.tok)
                    378:                        break;
                    379:                if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
                    380:                        return(0);
                    381:                assert(mdoc->last->prev);
                    382:                n = mdoc->last;
                    383:                mdoc->last = mdoc->last->prev;
                    384:                mdoc->last->next = NULL;
                    385:                mdoc_node_free(n);
                    386:                break;
1.16      kristaps  387:        case (MDOC_Sh):
                    388:                /* FALLTHROUGH */
1.7       kristaps  389:        case (MDOC_Ss):
1.16      kristaps  390:                if ( ! scope_rewind_imp(mdoc, ppos, tok))
                    391:                        return(0);
1.7       kristaps  392:                /* `.Pp' ignored when preceding `.Ss' or `.Sh'. */
                    393:                if (NULL == mdoc->last)
                    394:                        break;
                    395:                if (MDOC_ELEM != mdoc->last->type)
                    396:                        break;
                    397:                if (MDOC_Pp != mdoc->last->data.elem.tok)
1.1       kristaps  398:                        break;
1.7       kristaps  399:                if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
                    400:                        return(0);
                    401:                assert(mdoc->last->prev);
                    402:                n = mdoc->last;
1.8       kristaps  403:                mdoc_msg(mdoc, ppos, "removing prior `Pp' macro");
1.7       kristaps  404:                mdoc->last = mdoc->last->prev;
                    405:                mdoc->last->next = NULL;
                    406:                mdoc_node_free(n);
                    407:                break;
                    408:        default:
                    409:                break;
1.2       kristaps  410:        }
                    411:
1.16      kristaps  412:        /* Argument processing. */
                    413:
                    414:        lastarg = *pos;
1.8       kristaps  415:
1.16      kristaps  416:        for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
                    417:                lastarg = *pos;
                    418:                c = mdoc_argv(mdoc, tok, &argv[argc], pos, buf);
                    419:                if (ARGV_EOLN == c || ARGV_WORD == c)
                    420:                        break;
                    421:                else if (ARGV_ARG == c)
                    422:                        continue;
                    423:                mdoc_argv_free(argc, argv);
1.8       kristaps  424:                return(0);
1.16      kristaps  425:        }
1.2       kristaps  426:
1.16      kristaps  427:        /* Parameter processing. */
1.2       kristaps  428:
1.16      kristaps  429:        for (sz = 0; argc + sz < MDOC_LINEARG_MAX; sz++) {
                    430:                lastarg = *pos;
                    431:                c = mdoc_args(mdoc, tok, pos, buf, 0, &args[sz]);
                    432:                if (ARGS_EOLN == c)
                    433:                        break;
                    434:                if (ARGS_WORD == c)
                    435:                        continue;
                    436:                mdoc_argv_free(argc, argv);
                    437:                return(0);
                    438:        }
1.8       kristaps  439:
1.16      kristaps  440:        if (MDOC_LINEARG_MAX == (argc + sz)) {
                    441:                mdoc_argv_free(argc, argv);
1.7       kristaps  442:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
1.16      kristaps  443:        }
1.7       kristaps  444:
1.16      kristaps  445:        /* Post-processing. */
1.2       kristaps  446:
1.16      kristaps  447:        if ( ! mdoc_valid_pre(mdoc, tok, ppos, sz, _CC(args), argc, argv)) {
                    448:                mdoc_argv_free(argc, argv);
1.2       kristaps  449:                return(0);
1.7       kristaps  450:        }
1.1       kristaps  451:
1.8       kristaps  452:        switch (tok) {
1.16      kristaps  453:        case (MDOC_Sh):
                    454:                sec = mdoc_atosec((size_t)sz, _CC(args));
                    455:                if (SEC_CUSTOM != sec)
                    456:                        mdoc->sec_lastn = sec;
                    457:                mdoc->sec_last = sec;
                    458:                break;
1.8       kristaps  459:        default:
                    460:                break;
                    461:        }
                    462:
1.16      kristaps  463:        mdoc_block_alloc(mdoc, ppos, tok, (size_t)argc, argv);
                    464:        mdoc->next = MDOC_NEXT_CHILD;
1.8       kristaps  465:
1.16      kristaps  466:        mdoc_argv_free(argc, argv);
1.8       kristaps  467:
1.16      kristaps  468:        mdoc_head_alloc(mdoc, ppos, tok);
                    469:        mdoc->next = MDOC_NEXT_CHILD;
1.8       kristaps  470:
1.16      kristaps  471:        for (i = 0; i < sz; i++) {
                    472:                mdoc_word_alloc(mdoc, ppos, args[i]);
                    473:                mdoc->next = MDOC_NEXT_SIBLING;
                    474:        }
1.8       kristaps  475:
1.16      kristaps  476:        if ( ! scope_rewind_line(mdoc, ppos, tok))
1.8       kristaps  477:                return(0);
1.1       kristaps  478:
1.16      kristaps  479:        mdoc_body_alloc(mdoc, ppos, tok);
                    480:        mdoc->next = MDOC_NEXT_CHILD;
1.8       kristaps  481:
1.16      kristaps  482:        return(1);
1.1       kristaps  483: }
1.5       kristaps  484:
1.7       kristaps  485:
                    486: int
1.16      kristaps  487: macro_scoped_line(MACRO_PROT_ARGS)
1.7       kristaps  488: {
1.8       kristaps  489:        int               lastarg, c, j;
                    490:        char              *p;
1.7       kristaps  491:
1.16      kristaps  492:        assert(1 == ppos);
                    493:
                    494:        mdoc_block_alloc(mdoc, ppos, tok, 0, NULL);
                    495:        mdoc->next = MDOC_NEXT_CHILD;
1.8       kristaps  496:
1.16      kristaps  497:        mdoc_head_alloc(mdoc, ppos, tok);
                    498:        mdoc->next = MDOC_NEXT_CHILD;
1.8       kristaps  499:
1.16      kristaps  500:        if ( ! mdoc_valid_pre(mdoc, tok, ppos, 0, NULL, 0, NULL))
                    501:                return(0);
1.8       kristaps  502:
                    503:        /* Process line parameters. */
                    504:
                    505:        j = 0;
                    506:        lastarg = ppos;
                    507:
                    508: again:
                    509:        if (j == MDOC_LINEARG_MAX)
                    510:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
                    511:
                    512:        lastarg = *pos;
                    513:        c = mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p);
                    514:
                    515:        switch (c) {
                    516:        case (ARGS_ERROR):
                    517:                return(0);
                    518:        case (ARGS_WORD):
                    519:                break;
                    520:        case (ARGS_PUNCT):
1.16      kristaps  521:                if (ppos > 1)
                    522:                        return(scope_rewind_imp(mdoc, ppos, tok));
                    523:                if ( ! scope_rewind_line(mdoc, ppos, tok))
                    524:                        return(0);
                    525:                if ( ! append_delims(mdoc, tok, pos, buf))
1.8       kristaps  526:                        return(0);
1.16      kristaps  527:                return(scope_rewind_imp(mdoc, ppos, tok));
1.8       kristaps  528:        case (ARGS_EOLN):
                    529:                return(scope_rewind_imp(mdoc, ppos, tok));
                    530:        default:
                    531:                abort();
                    532:                /* NOTREACHED */
                    533:        }
                    534:
                    535:        if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
                    536:                if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
                    537:                        return(0);
1.16      kristaps  538:                if (ppos > 1)
                    539:                        return(scope_rewind_imp(mdoc, ppos, tok));
                    540:                if ( ! scope_rewind_line(mdoc, ppos, tok))
                    541:                        return(0);
                    542:                if ( ! append_delims(mdoc, tok, pos, buf))
1.8       kristaps  543:                        return(0);
1.16      kristaps  544:                return(scope_rewind_imp(mdoc, ppos, tok));
1.8       kristaps  545:        }
                    546:
                    547:        if (mdoc_isdelim(p))
                    548:                j = 0;
                    549:
                    550:        mdoc_word_alloc(mdoc, lastarg, p);
1.16      kristaps  551:        mdoc->next = MDOC_NEXT_SIBLING;
1.8       kristaps  552:        goto again;
                    553:        /* NOTREACHED */
1.7       kristaps  554: }
1.8       kristaps  555:
1.10      kristaps  556:
1.17    ! kristaps  557: /*
        !           558:  * FIXME: like in with macro_constant, have the append_ routine chop the
        !           559:  * number of requisite arguments (this is ugly when done in-line).
        !           560:  */
1.10      kristaps  561: int
                    562: macro_constant_delimited(MACRO_PROT_ARGS)
                    563: {
                    564:        int               lastarg, flushed, c, maxargs;
1.13      kristaps  565:        char             *p;
1.10      kristaps  566:
                    567:        /* Process line parameters. */
                    568:
                    569:        lastarg = ppos;
                    570:        flushed = 0;
                    571:
1.11      kristaps  572:        /* Token pre-processing. */
                    573:
1.10      kristaps  574:        switch (tok) {
1.16      kristaps  575:        case (MDOC_No):
                    576:                /* FALLTHROUGH */
                    577:        case (MDOC_Ns):
                    578:                /* FALLTHROUGH */
1.10      kristaps  579:        case (MDOC_Ux):
                    580:                maxargs = 0;
                    581:                break;
                    582:        default:
                    583:                maxargs = 1;
                    584:                break;
                    585:        }
                    586:
                    587: again:
                    588:        lastarg = *pos;
                    589:
                    590:        switch (mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p)) {
                    591:        case (ARGS_ERROR):
                    592:                return(0);
                    593:        case (ARGS_WORD):
                    594:                break;
                    595:        case (ARGS_PUNCT):
1.16      kristaps  596:                if ( ! flushed && ! append_text(mdoc, tok, ppos, 0, &p))
1.10      kristaps  597:                        return(0);
                    598:                if (ppos > 1)
                    599:                        return(1);
                    600:                return(append_delims(mdoc, tok, pos, buf));
                    601:        case (ARGS_EOLN):
                    602:                if (flushed)
                    603:                        return(1);
1.16      kristaps  604:                return(append_text(mdoc, tok, ppos, 0, &p));
1.10      kristaps  605:        default:
                    606:                abort();
                    607:                /* NOTREACHED */
                    608:        }
                    609:
1.11      kristaps  610:        /* Accepts no arguments: flush out symbol and continue. */
                    611:
1.16      kristaps  612:        if ( ! flushed && 0 == maxargs) {
                    613:                if ( ! append_text(mdoc, tok, ppos, 0, &p))
1.10      kristaps  614:                        return(0);
                    615:                flushed = 1;
                    616:        }
                    617:
                    618:        if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
1.16      kristaps  619:                if ( ! flushed && ! append_text(mdoc, tok, ppos, 0, &p))
1.10      kristaps  620:                        return(0);
                    621:                if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
                    622:                        return(0);
                    623:                if (ppos > 1)
                    624:                        return(1);
                    625:                return(append_delims(mdoc, tok, pos, buf));
                    626:        }
                    627:
1.11      kristaps  628:        /*
                    629:         * We only accept one argument; subsequent tokens are considered
                    630:         * as literal words (until a macro).
                    631:         */
                    632:
1.10      kristaps  633:        if ( ! flushed && ! mdoc_isdelim(p)) {
1.16      kristaps  634:               if ( ! append_text(mdoc, tok, ppos, 1, &p))
1.10      kristaps  635:                        return(0);
                    636:                flushed = 1;
                    637:                goto again;
                    638:        } else if ( ! flushed) {
1.16      kristaps  639:                if ( ! append_text(mdoc, tok, ppos, 0, &p))
1.10      kristaps  640:                        return(0);
                    641:                flushed = 1;
                    642:        }
                    643:
                    644:        mdoc_word_alloc(mdoc, lastarg, p);
1.16      kristaps  645:        mdoc->next = MDOC_NEXT_SIBLING;
1.10      kristaps  646:        goto again;
                    647:        /* NOTREACHED */
                    648: }
1.11      kristaps  649:
                    650:
                    651: int
                    652: macro_constant(MACRO_PROT_ARGS)
                    653: {
1.16      kristaps  654:        int               c, lastarg, argc, sz, fl;
1.11      kristaps  655:        char             *args[MDOC_LINEARG_MAX];
1.16      kristaps  656:        struct mdoc_arg   argv[MDOC_LINEARG_MAX];
1.11      kristaps  657:
1.16      kristaps  658:        fl = 0;
1.15      kristaps  659:        if (MDOC_QUOTABLE & mdoc_macros[tok].flags)
                    660:                fl = ARGS_QUOTED;
1.11      kristaps  661:
1.16      kristaps  662:        for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
                    663:                lastarg = *pos;
                    664:                c = mdoc_argv(mdoc, tok, &argv[argc], pos, buf);
                    665:                if (ARGV_EOLN == c)
                    666:                        break;
                    667:                else if (ARGV_ARG == c)
                    668:                        continue;
                    669:                else if (ARGV_WORD == c)
                    670:                        break;
1.11      kristaps  671:
1.16      kristaps  672:                mdoc_argv_free(argc, argv);
1.11      kristaps  673:                return(0);
                    674:        }
                    675:
1.16      kristaps  676:        if (MDOC_LINEARG_MAX == argc) {
                    677:                mdoc_argv_free(argc, argv);
                    678:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
                    679:        }
1.11      kristaps  680:
1.16      kristaps  681:        for (sz = 0; sz + argc < MDOC_LINEARG_MAX; sz++) {
1.13      kristaps  682:                lastarg = *pos;
1.16      kristaps  683:                c = mdoc_args(mdoc, tok, pos, buf, fl, &args[sz]);
                    684:                if (ARGS_ERROR == c)
                    685:                        return(0);
                    686:                if (ARGS_EOLN == c)
1.13      kristaps  687:                        break;
                    688:        }
                    689:
1.16      kristaps  690:        if (MDOC_LINEARG_MAX == sz + argc) {
                    691:                mdoc_argv_free(argc, argv);
1.13      kristaps  692:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
                    693:        }
                    694:
1.16      kristaps  695:        c = append_text_argv(mdoc, tok, ppos, sz, args, argc, argv);
                    696:        mdoc_argv_free(argc, argv);
1.13      kristaps  697:        return(c);
                    698: }
1.15      kristaps  699:
                    700:
1.16      kristaps  701: /* ARGSUSED */
1.15      kristaps  702: int
                    703: macro_obsolete(MACRO_PROT_ARGS)
                    704: {
                    705:
                    706:        return(mdoc_warn(mdoc, tok, ppos, WARN_IGN_OBSOLETE));
                    707: }

CVSweb