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

Annotation of mandoc/validate.c, Revision 1.8

1.8     ! kristaps    1: /* $Id: macro.c,v 1.12 2008/12/29 19:25:29 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>
1.8     ! kristaps   21: #include <stdlib.h>
1.1       kristaps   22: #include <stdio.h>
                     23: #include <string.h>
1.8     ! kristaps   24: #ifdef __linux__
        !            25: #include <time.h>
        !            26: #endif
1.1       kristaps   27:
                     28: #include "private.h"
                     29:
1.8     ! kristaps   30: /* FIXME: maxlineargs should be per LINE, no per TOKEN. */
        !            31: /* FIXME: prologue check should be in macro_call. */
1.2       kristaps   32:
1.8     ! kristaps   33: #define        _CC(p)  ((const char **)p)
1.1       kristaps   34:
1.8     ! kristaps   35: static int       scope_rewind_exp(struct mdoc *, int, int, int);
        !            36: static int       scope_rewind_imp(struct mdoc *, int, int);
        !            37: static int       append_text(struct mdoc *, int,
        !            38:                        int, int, char *[]);
        !            39: static int       append_const(struct mdoc *, int, int, int, char *[]);
        !            40: static int       append_constarg(struct mdoc *, int, int,
        !            41:                         int, const struct mdoc_arg *);
        !            42: static int       append_scoped(struct mdoc *, int, int, int,
        !            43:                        const char *[], int, const struct mdoc_arg *);
        !            44: static int       append_delims(struct mdoc *, int, int *, char *);
1.6       kristaps   45:
                     46:
                     47: static int
1.8     ! kristaps   48: append_delims(struct mdoc *mdoc, int tok, int *pos, char *buf)
1.6       kristaps   49: {
1.8     ! kristaps   50:        int              c, lastarg;
        !            51:        char            *p;
        !            52:
        !            53:        if (0 == buf[*pos])
        !            54:                return(1);
        !            55:
        !            56:        mdoc_msg(mdoc, *pos, "`%s' flushing punctuation",
        !            57:                        mdoc_macronames[tok]);
        !            58:
        !            59:        for (;;) {
        !            60:                lastarg = *pos;
        !            61:                c = mdoc_args(mdoc, tok, pos, buf, 0, &p);
        !            62:                if (ARGS_ERROR == c)
        !            63:                        return(0);
        !            64:                else if (ARGS_EOLN == c)
        !            65:                        break;
        !            66:                assert(mdoc_isdelim(p));
        !            67:                mdoc_word_alloc(mdoc, lastarg, p);
        !            68:        }
1.6       kristaps   69:
1.8     ! kristaps   70:        return(1);
1.6       kristaps   71: }
                     72:
                     73:
                     74: static int
1.8     ! kristaps   75: scope_rewind_imp(struct mdoc *mdoc, int ppos, int tok)
1.6       kristaps   76: {
1.8     ! kristaps   77:        struct mdoc_node *n;
        !            78:        int               t;
        !            79:
        !            80:        n = mdoc->last ? mdoc->last->parent : NULL;
        !            81:
        !            82:        /* LINTED */
        !            83:        for ( ; n; n = n->parent) {
        !            84:                if (MDOC_BLOCK != n->type)
        !            85:                        continue;
        !            86:                if (tok == (t = n->data.block.tok))
        !            87:                        break;
        !            88:                if ( ! (MDOC_EXPLICIT & mdoc_macros[t].flags))
        !            89:                        continue;
        !            90:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
        !            91:        }
1.6       kristaps   92:
1.8     ! kristaps   93:        if (n) {
        !            94:                mdoc->last = n;
        !            95:                mdoc_msg(mdoc, ppos, "scope: rewound implicit `%s'",
        !            96:                                mdoc_macronames[tok]);
        !            97:                return(1);
        !            98:        }
        !            99:
        !           100:        mdoc_msg(mdoc, ppos, "scope: new implicit `%s'",
        !           101:                        mdoc_macronames[tok]);
        !           102:        return(1);
1.6       kristaps  103: }
1.1       kristaps  104:
                    105:
                    106: static int
1.8     ! kristaps  107: scope_rewind_exp(struct mdoc *mdoc, int ppos, int tok, int dst)
1.1       kristaps  108: {
1.8     ! kristaps  109:        struct mdoc_node *n;
1.1       kristaps  110:
1.8     ! kristaps  111:        assert(mdoc->last);
1.1       kristaps  112:
1.5       kristaps  113:        /* LINTED */
1.8     ! kristaps  114:        for (n = mdoc->last->parent; n; n = n->parent) {
        !           115:                if (MDOC_BLOCK != n->type)
        !           116:                        continue;
        !           117:                if (dst == n->data.block.tok)
        !           118:                        break;
        !           119:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_BREAK));
        !           120:        }
        !           121:
        !           122:        if (NULL == (mdoc->last = n))
        !           123:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_NOCTX));
        !           124:
        !           125:        mdoc_msg(mdoc, ppos, "scope: rewound explicit `%s' to `%s'",
        !           126:                        mdoc_macronames[tok], mdoc_macronames[dst]);
1.1       kristaps  127:
                    128:        return(1);
                    129: }
                    130:
                    131:
                    132: static int
1.8     ! kristaps  133: append_constarg(struct mdoc *mdoc, int tok, int pos,
        !           134:                int argc, const struct mdoc_arg *argv)
1.1       kristaps  135: {
                    136:
1.8     ! kristaps  137:        switch (tok) {
        !           138:        default:
        !           139:                break;
        !           140:        }
1.1       kristaps  141:
1.8     ! kristaps  142:        mdoc_elem_alloc(mdoc, pos, tok, argc, argv, 0, NULL);
1.2       kristaps  143:        return(1);
1.1       kristaps  144: }
                    145:
                    146:
1.8     ! kristaps  147: /*
        !           148:  * Append a node with implicit or explicit scoping ONLY.  ALL macros
        !           149:  * with the implicit- or explicit-scope callback must be included here.
        !           150:  */
1.1       kristaps  151: static int
1.8     ! kristaps  152: append_scoped(struct mdoc *mdoc, int tok, int pos,
        !           153:                int sz, const char *args[],
        !           154:                int argc, const struct mdoc_arg *argv)
1.1       kristaps  155: {
1.8     ! kristaps  156:        enum mdoc_sec     sec;
        !           157:        struct mdoc_node *node;
        !           158:
        !           159:        switch (tok) {
        !           160:         /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
        !           161:
        !           162:        case (MDOC_Sh):
        !           163:                /*
        !           164:                 * Check rules for section ordering.  We can have
        !           165:                 * "known" sections (like NAME and so on) and "custom"
        !           166:                 * sections, which are unknown.  If we have a known
        !           167:                 * section, we should fall within the conventional
        !           168:                 * section order.
        !           169:                 */
        !           170:                if (0 == sz)
        !           171:                        return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
        !           172:
        !           173:                sec = mdoc_atosec((size_t)sz, _CC(args));
        !           174:                if (SEC_CUSTOM != sec && sec < mdoc->sec_lastn)
        !           175:                        if ( ! mdoc_warn(mdoc, tok, pos, WARN_SEC_OO))
        !           176:                                return(0);
1.1       kristaps  177:
1.8     ! kristaps  178:                if (SEC_BODY == mdoc->sec_last && SEC_NAME != sec)
        !           179:                        return(mdoc_err(mdoc, tok, pos, ERR_SEC_NAME));
        !           180:                if (SEC_CUSTOM != sec)
        !           181:                        mdoc->sec_lastn = sec;
        !           182:                mdoc->sec_last = sec;
        !           183:                break;
        !           184:
        !           185:        case (MDOC_Ss):
        !           186:                if (0 != sz)
        !           187:                        break;
        !           188:                return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
        !           189:
        !           190:        case (MDOC_Bd):
        !           191:                /*
        !           192:                 * We can't be nested within any other block displays
        !           193:                 * (or really any other kind of display, although Bd is
        !           194:                 * the only multi-line one that will show up).
        !           195:                 */
        !           196:                assert(mdoc->last);
        !           197:                node = mdoc->last->parent;
        !           198:                /* LINTED */
        !           199:                for ( ; node; node = node->parent) {
        !           200:                        if (node->type != MDOC_BLOCK)
        !           201:                                continue;
        !           202:                        if (node->data.block.tok != MDOC_Bd)
        !           203:                                continue;
        !           204:                        break;
        !           205:                }
        !           206:                if (NULL == node)
        !           207:                        break;
        !           208:                return(mdoc_err(mdoc, tok, pos, ERR_SCOPE_NONEST));
1.1       kristaps  209:
1.8     ! kristaps  210:        case (MDOC_Bl):
        !           211:                break;
1.6       kristaps  212:
1.8     ! kristaps  213:         /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
        !           214:        default:
        !           215:                abort();
        !           216:                /* NOTREACHED */
        !           217:        }
1.1       kristaps  218:
1.8     ! kristaps  219:        mdoc_block_alloc(mdoc, pos, tok, (size_t)argc, argv);
        !           220:        mdoc_head_alloc(mdoc, pos, tok, (size_t)sz, _CC(args));
        !           221:        mdoc_body_alloc(mdoc, pos, tok);
        !           222:        return(1);
        !           223: }
1.1       kristaps  224:
                    225:
1.8     ! kristaps  226: static int
        !           227: append_const(struct mdoc *mdoc, int tok,
        !           228:                int pos, int sz, char *args[])
        !           229: {
1.1       kristaps  230:
1.8     ! kristaps  231:        switch (tok) {
        !           232:         /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
1.1       kristaps  233:
1.8     ! kristaps  234:        /* FIXME: this is the ugliest part of this page. */
        !           235:        case (MDOC_At):
        !           236:                /* This needs special handling. */
        !           237:                if (0 == sz)
        !           238:                        break;
        !           239:                else if (sz > 2)
        !           240:                        return(mdoc_err(mdoc, tok, pos, ERR_ARGS_LE2));
1.2       kristaps  241:
1.8     ! kristaps  242:                if (ATT_DEFAULT != mdoc_atoatt(args[0])) {
        !           243:                        mdoc_elem_alloc(mdoc, pos, tok, 0,
        !           244:                                        NULL, 1, _CC(&args[0]));
        !           245:                } else {
        !           246:                        mdoc_elem_alloc(mdoc, pos, tok,
        !           247:                                        0, NULL, 0, NULL);
        !           248:                        if (mdoc_isdelim(args[0]))
        !           249:                                return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_NOPUNCT));
        !           250:                        mdoc_word_alloc(mdoc, pos, args[0]);
1.1       kristaps  251:                }
                    252:
1.8     ! kristaps  253:                if (1 == sz)
        !           254:                        return(1);
        !           255:                if (mdoc_isdelim(args[1]))
        !           256:                        return(mdoc_err(mdoc, tok, pos, ERR_SYNTAX_NOPUNCT));
        !           257:                mdoc_word_alloc(mdoc, pos, args[1]);
        !           258:                return(1);
1.1       kristaps  259:
1.8     ! kristaps  260:        case (MDOC_Nd):
        !           261:                if (sz > 0)
        !           262:                        break;
        !           263:                if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_GE1))
1.1       kristaps  264:                        return(0);
1.8     ! kristaps  265:                break;
        !           266:
        !           267:        case (MDOC_Hf):
        !           268:                if (1 == sz)
        !           269:                        break;
        !           270:                return(mdoc_err(mdoc, tok, pos, ERR_ARGS_EQ1));
        !           271:
        !           272:        case (MDOC_Bx):
        !           273:                /* FALLTHROUGH */
        !           274:        case (MDOC_Bsx):
        !           275:                /* FALLTHROUGH */
        !           276:        case (MDOC_Os):
        !           277:                /* FALLTHROUGH */
        !           278:        case (MDOC_Fx):
        !           279:                /* FALLTHROUGH */
        !           280:        case (MDOC_Nx):
        !           281:                assert(sz <= 1);
        !           282:                break;
        !           283:
        !           284:        case (MDOC_Ux):
        !           285:                assert(0 == sz);
        !           286:                break;
        !           287:
        !           288:        case (MDOC_Bt):
        !           289:                /* FALLTHROUGH */
        !           290:        case (MDOC_Ud):
        !           291:                if (0 == sz)
        !           292:                        break;
        !           293:                return(mdoc_err(mdoc, tok, pos, ERR_ARGS_EQ0));
        !           294:
        !           295:         /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
        !           296:        default:
        !           297:                abort();
        !           298:                /* NOTREACHED */
1.1       kristaps  299:        }
                    300:
1.8     ! kristaps  301:        mdoc_elem_alloc(mdoc, pos, tok, 0, NULL, (size_t)sz, _CC(args));
1.1       kristaps  302:        return(1);
                    303: }
                    304:
                    305:
1.8     ! kristaps  306: static int
        !           307: append_text(struct mdoc *mdoc, int tok,
        !           308:                int pos, int sz, char *args[])
1.1       kristaps  309: {
                    310:
1.8     ! kristaps  311:        switch (tok) {
        !           312:         /* ======= ADD MORE MACRO CHECKS BELOW. ======= */
        !           313:        case (MDOC_Pp):
        !           314:                if (0 == sz)
        !           315:                        break;
        !           316:                if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_EQ0))
        !           317:                        return(0);
        !           318:                break;
        !           319:
        !           320:        case (MDOC_Ft):
        !           321:                /* FALLTHROUGH */
        !           322:        case (MDOC_Li):
        !           323:                /* FALLTHROUGH */
        !           324:        case (MDOC_Ms):
        !           325:                /* FALLTHROUGH */
        !           326:        case (MDOC_Pa):
        !           327:                /* FALLTHROUGH */
        !           328:        case (MDOC_Tn):
        !           329:                if (0 < sz)
        !           330:                        break;
        !           331:                if ( ! mdoc_warn(mdoc, tok, pos, WARN_ARGS_GE1))
        !           332:                        return(0);
        !           333:                break;
        !           334:
        !           335:        case (MDOC_Ar):
        !           336:                /* FALLTHROUGH */
        !           337:        case (MDOC_Cm):
        !           338:                /* FALLTHROUGH */
        !           339:        case (MDOC_Fl):
        !           340:                /* These can have no arguments. */
        !           341:                break;
        !           342:
        !           343:        case (MDOC_Ad):
        !           344:                /* FALLTHROUGH */
        !           345:        case (MDOC_Em):
        !           346:                /* FALLTHROUGH */
        !           347:        case (MDOC_Er):
        !           348:                /* FALLTHROUGH */
        !           349:        case (MDOC_Ev):
        !           350:                /* FALLTHROUGH */
        !           351:        case (MDOC_Fa):
        !           352:                /* FALLTHROUGH */
        !           353:        case (MDOC_Dv):
        !           354:                /* FALLTHROUGH */
        !           355:        case (MDOC_Ic):
        !           356:                /* FALLTHROUGH */
        !           357:        case (MDOC_Sy):
        !           358:                /* FALLTHROUGH */
        !           359:        case (MDOC_Sx):
        !           360:                /* FALLTHROUGH */
        !           361:        case (MDOC_Va):
        !           362:                /* FALLTHROUGH */
        !           363:        case (MDOC_Vt):
        !           364:                if (0 < sz)
        !           365:                        break;
        !           366:                return(mdoc_err(mdoc, tok, pos, ERR_ARGS_GE1));
        !           367:         /* ======= ADD MORE MACRO CHECKS ABOVE. ======= */
        !           368:        default:
        !           369:                abort();
        !           370:                /* NOTREACHED */
        !           371:        }
        !           372:
        !           373:        mdoc_elem_alloc(mdoc, pos, tok, 0, NULL, (size_t)sz, _CC(args));
        !           374:        return(1);
1.1       kristaps  375: }
                    376:
                    377:
                    378: int
1.8     ! kristaps  379: macro_text(MACRO_PROT_ARGS)
1.1       kristaps  380: {
1.8     ! kristaps  381:        int               lastarg, lastpunct, c, j;
        !           382:        char             *args[MDOC_LINEARG_MAX];
        !           383:
        !           384:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !           385:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
1.1       kristaps  386:
1.8     ! kristaps  387:        /* Token pre-processing.  */
1.1       kristaps  388:
1.8     ! kristaps  389:        switch (tok) {
        !           390:        case (MDOC_Pp):
        !           391:                /* `.Pp' ignored when following `.Sh' or `.Ss'. */
        !           392:                assert(mdoc->last);
        !           393:                if (MDOC_BODY != mdoc->last->type)
        !           394:                        break;
        !           395:                switch (mdoc->last->data.body.tok) {
        !           396:                case (MDOC_Ss):
        !           397:                        /* FALLTHROUGH */
        !           398:                case (MDOC_Sh):
        !           399:                        if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_AFTER_BLK))
        !           400:                                return(0);
        !           401:                        return(1);
        !           402:                default:
        !           403:                        break;
        !           404:                }
        !           405:                break;
        !           406:        default:
        !           407:                break;
        !           408:        }
        !           409:
        !           410:        /* Process line parameters. */
        !           411:
        !           412:        j = 0;
        !           413:        lastarg = ppos;
        !           414:        lastpunct = 0;
        !           415:
        !           416: again:
        !           417:        if (j == MDOC_LINEARG_MAX)
        !           418:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
1.1       kristaps  419:
1.8     ! kristaps  420:        /*
        !           421:         * Parse out the next argument, unquoted and unescaped.   If
        !           422:         * we're a word (which may be punctuation followed eventually by
        !           423:         * a real word), then fall into checking for callables.  If
        !           424:         * only punctuation remains and we're the first, then flush
        !           425:         * arguments, punctuation and exit; else, return to the caller.
        !           426:         */
1.1       kristaps  427:
1.8     ! kristaps  428:        lastarg = *pos;
1.1       kristaps  429:
1.8     ! kristaps  430:        switch (mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &args[j])) {
        !           431:        case (ARGS_ERROR):
        !           432:                return(0);
        !           433:        case (ARGS_WORD):
        !           434:                break;
        !           435:        case (ARGS_PUNCT):
        !           436:                if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
        !           437:                        return(0);
        !           438:                if (ppos > 1)
        !           439:                        return(1);
        !           440:                return(append_delims(mdoc, tok, pos, buf));
        !           441:        case (ARGS_EOLN):
        !           442:                if (lastpunct)
        !           443:                        return(1);
        !           444:                return(append_text(mdoc, tok, ppos, j, args));
        !           445:        default:
        !           446:                abort();
        !           447:                /* NOTREACHED */
        !           448:        }
1.1       kristaps  449:
1.8     ! kristaps  450:        /*
        !           451:         * Command found.  First flush out arguments, then call the
        !           452:         * command.  If we're the line macro when it exits, flush
        !           453:         * terminal punctuation.
        !           454:         */
1.1       kristaps  455:
1.8     ! kristaps  456:        if (MDOC_MAX != (c = mdoc_find(mdoc, args[j]))) {
        !           457:                if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
        !           458:                        return(0);
        !           459:                if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
        !           460:                        return(0);
        !           461:                if (ppos > 1)
        !           462:                        return(1);
        !           463:                return(append_delims(mdoc, tok, pos, buf));
        !           464:        }
1.1       kristaps  465:
1.8     ! kristaps  466:        /* Word/non-term-punctuation found. */
1.1       kristaps  467:
1.8     ! kristaps  468:        if ( ! mdoc_isdelim(args[j])) {
        !           469:                /* Words are appended to the array of arguments. */
        !           470:                j++;
        !           471:                lastpunct = 0;
        !           472:                goto again;
1.1       kristaps  473:        }
                    474:
1.8     ! kristaps  475:        /*
        !           476:         * For punctuation, flush all collected words, then flush
        !           477:         * punctuation, then start collecting again.   Of course, this
        !           478:         * is non-terminal punctuation.
        !           479:         */
        !           480:
        !           481:        if ( ! lastpunct && ! append_text(mdoc, tok, ppos, j, args))
        !           482:                return(0);
        !           483:
        !           484:        mdoc_word_alloc(mdoc, lastarg, args[j]);
        !           485:        j = 0;
        !           486:        lastpunct = 1;
        !           487:
        !           488:        goto again;
        !           489:        /* NOTREACHED */
1.1       kristaps  490: }
                    491:
                    492:
1.8     ! kristaps  493: int
        !           494: macro_prologue_dtitle(MACRO_PROT_ARGS)
1.1       kristaps  495: {
1.8     ! kristaps  496:        int               lastarg, j;
        !           497:        char             *args[MDOC_LINEARG_MAX];
1.2       kristaps  498:
1.8     ! kristaps  499:        if (SEC_PROLOGUE != mdoc->sec_lastn)
        !           500:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
        !           501:        if (0 == mdoc->meta.date)
        !           502:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
        !           503:        if (mdoc->meta.title[0])
        !           504:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
        !           505:
        !           506:        j = -1;
        !           507:        lastarg = ppos;
        !           508:
        !           509: again:
        !           510:        if (j == MDOC_LINEARG_MAX)
        !           511:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !           512:
        !           513:        lastarg = *pos;
        !           514:
        !           515:        switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[++j])) {
        !           516:        case (ARGS_EOLN):
        !           517:                if (mdoc->meta.title)
        !           518:                        return(1);
        !           519:                if ( ! mdoc_warn(mdoc, tok, ppos, WARN_ARGS_GE1))
        !           520:                        return(0);
        !           521:                (void)xstrlcpy(mdoc->meta.title,
        !           522:                                "UNTITLED", META_TITLE_SZ);
        !           523:                return(1);
        !           524:        case (ARGS_ERROR):
        !           525:                return(0);
        !           526:        default:
        !           527:                break;
        !           528:        }
1.2       kristaps  529:
1.8     ! kristaps  530:        if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
        !           531:                        (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
1.6       kristaps  532:                return(0);
1.4       kristaps  533:
1.8     ! kristaps  534:        if (0 == j) {
        !           535:                if (xstrlcpy(mdoc->meta.title, args[0], META_TITLE_SZ))
        !           536:                        goto again;
        !           537:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
        !           538:
        !           539:        } else if (1 == j) {
        !           540:                mdoc->meta.msec = mdoc_atomsec(args[1]);
        !           541:                if (MSEC_DEFAULT != mdoc->meta.msec)
        !           542:                        goto again;
        !           543:                return(mdoc_err(mdoc, tok, -1, ERR_SYNTAX_ARGFORM));
        !           544:
        !           545:        } else if (2 == j) {
        !           546:                mdoc->meta.vol = mdoc_atovol(args[2]);
        !           547:                if (VOL_DEFAULT != mdoc->meta.vol)
        !           548:                        goto again;
        !           549:                mdoc->meta.arch = mdoc_atoarch(args[2]);
        !           550:                if (ARCH_DEFAULT != mdoc->meta.arch)
        !           551:                        goto again;
        !           552:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
        !           553:        }
        !           554:
        !           555:        return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
1.1       kristaps  556: }
                    557:
                    558:
1.8     ! kristaps  559: int
        !           560: macro_prologue_os(MACRO_PROT_ARGS)
1.1       kristaps  561: {
1.8     ! kristaps  562:        int               lastarg, j;
        !           563:        char             *args[MDOC_LINEARG_MAX];
1.1       kristaps  564:
1.8     ! kristaps  565:        if (SEC_PROLOGUE != mdoc->sec_lastn)
        !           566:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
        !           567:        if (0 == mdoc->meta.title[0])
        !           568:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
        !           569:        if (mdoc->meta.os[0])
        !           570:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
        !           571:
        !           572:        j = -1;
        !           573:        lastarg = ppos;
        !           574:
        !           575: again:
        !           576:        if (j == MDOC_LINEARG_MAX)
        !           577:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !           578:
        !           579:        lastarg = *pos;
        !           580:
        !           581:        switch (mdoc_args(mdoc, tok, pos, buf,
        !           582:                                ARGS_QUOTED, &args[++j])) {
        !           583:        case (ARGS_EOLN):
        !           584:                mdoc->sec_lastn = mdoc->sec_last = SEC_BODY;
        !           585:                return(1);
        !           586:        case (ARGS_ERROR):
1.2       kristaps  587:                return(0);
1.8     ! kristaps  588:        default:
        !           589:                break;
        !           590:        }
        !           591:
        !           592:        if ( ! xstrlcat(mdoc->meta.os, args[j], sizeof(mdoc->meta.os)))
        !           593:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
        !           594:        if ( ! xstrlcat(mdoc->meta.os, " ", sizeof(mdoc->meta.os)))
        !           595:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
1.6       kristaps  596:
1.8     ! kristaps  597:        goto again;
        !           598:        /* NOTREACHED */
1.1       kristaps  599: }
                    600:
                    601:
1.8     ! kristaps  602: int
        !           603: macro_prologue_ddate(MACRO_PROT_ARGS)
1.1       kristaps  604: {
1.8     ! kristaps  605:        int               lastarg, j;
        !           606:        char             *args[MDOC_LINEARG_MAX], date[64];
        !           607:
        !           608:        if (SEC_PROLOGUE != mdoc->sec_lastn)
        !           609:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_NPROLOGUE));
        !           610:        if (mdoc->meta.title[0])
        !           611:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_OO));
        !           612:        if (mdoc->meta.date)
        !           613:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE_REP));
        !           614:
        !           615:        j = -1;
        !           616:        date[0] = 0;
        !           617:        lastarg = ppos;
        !           618:
        !           619: again:
        !           620:        if (j == MDOC_LINEARG_MAX)
        !           621:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !           622:
        !           623:        lastarg = *pos;
        !           624:        switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[++j])) {
        !           625:        case (ARGS_EOLN):
        !           626:                if (mdoc->meta.date)
        !           627:                        return(1);
        !           628:                mdoc->meta.date = mdoc_atotime(date);
        !           629:                if (mdoc->meta.date)
        !           630:                        return(1);
        !           631:                return(mdoc_err(mdoc, tok, ppos, ERR_SYNTAX_ARGFORM));
        !           632:        case (ARGS_ERROR):
        !           633:                return(0);
        !           634:        default:
        !           635:                break;
        !           636:        }
        !           637:
        !           638:        if (MDOC_MAX != mdoc_find(mdoc, args[j]) && ! mdoc_warn
        !           639:                        (mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
        !           640:                return(0);
        !           641:
        !           642:        if (0 == j) {
        !           643:                if (xstrcmp("$Mdocdate$", args[j])) {
        !           644:                        mdoc->meta.date = time(NULL);
        !           645:                        goto again;
        !           646:                } else if (xstrcmp("$Mdocdate:", args[j]))
        !           647:                        goto again;
        !           648:        } else if (4 == j)
        !           649:                if ( ! xstrcmp("$", args[j]))
        !           650:                        goto again;
        !           651:
        !           652:        if ( ! xstrlcat(date, args[j], sizeof(date)))
        !           653:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
        !           654:        if ( ! xstrlcat(date, " ", sizeof(date)))
        !           655:                return(mdoc_err(mdoc, tok, lastarg, ERR_SYNTAX_ARGFORM));
1.1       kristaps  656:
1.8     ! kristaps  657:        goto again;
        !           658:        /* NOTREACHED */
1.1       kristaps  659: }
                    660:
                    661:
1.8     ! kristaps  662: int
        !           663: macro_scoped_explicit(MACRO_PROT_ARGS)
1.1       kristaps  664: {
1.8     ! kristaps  665:        int               c, lastarg, j;
        !           666:        struct mdoc_arg   argv[MDOC_LINEARG_MAX];
        !           667:        struct mdoc_node *n;
        !           668:
        !           669:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !           670:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
        !           671:
        !           672:        /*
        !           673:         * First close out the explicit scope.  The `end' tags (such as
        !           674:         * `.El' to `.Bl' don't cause anything to happen: we merely
        !           675:         * readjust our last parse point.
        !           676:         */
        !           677:
        !           678:        switch (tok) {
        !           679:        case (MDOC_El):
        !           680:                return(scope_rewind_exp(mdoc, ppos, tok, MDOC_Bl));
        !           681:        case (MDOC_Ed):
        !           682:                return(scope_rewind_exp(mdoc, ppos, tok, MDOC_Bd));
        !           683:        default:
        !           684:                break;
        !           685:        }
1.1       kristaps  686:
1.8     ! kristaps  687:        assert(MDOC_EXPLICIT & mdoc_macros[tok].flags);
1.1       kristaps  688:
1.8     ! kristaps  689:        /* Token pre-processing. */
        !           690:
        !           691:        switch (tok) {
        !           692:        case (MDOC_Bl):
        !           693:                /* FALLTHROUGH */
        !           694:        case (MDOC_Bd):
        !           695:                /* `.Pp' ignored when preceding `.Bl' or `.Bd'. */
        !           696:                assert(mdoc->last);
        !           697:                if (MDOC_ELEM != mdoc->last->type)
        !           698:                        break;
        !           699:                if (MDOC_Pp != mdoc->last->data.elem.tok)
        !           700:                        break;
        !           701:                if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
1.1       kristaps  702:                        return(0);
1.8     ! kristaps  703:                assert(mdoc->last->prev);
        !           704:                n = mdoc->last;
        !           705:                mdoc->last = mdoc->last->prev;
        !           706:                mdoc->last->next = NULL;
        !           707:                mdoc_node_free(n);
        !           708:                break;
        !           709:        default:
        !           710:                break;
        !           711:        }
        !           712:
        !           713:        lastarg = *pos;
        !           714:
        !           715:        for (j = 0; j < MDOC_LINEARG_MAX; j++) {
        !           716:                lastarg = *pos;
        !           717:                c = mdoc_argv(mdoc, tok, &argv[j], pos, buf);
        !           718:                if (0 == c)
        !           719:                        break;
        !           720:                else if (1 == c)
        !           721:                        continue;
        !           722:
        !           723:                mdoc_argv_free(j, argv);
        !           724:                return(0);
        !           725:        }
        !           726:
        !           727:        if (MDOC_LINEARG_MAX == j) {
        !           728:                mdoc_argv_free(j, argv);
        !           729:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !           730:        }
        !           731:
        !           732:        c = append_scoped(mdoc, tok, ppos, 0, NULL, j, argv);
        !           733:        mdoc_argv_free(j, argv);
        !           734:        return(c);
        !           735: }
        !           736:
        !           737:
        !           738: /*
        !           739:  * Implicity-scoped macros, like `.Ss', have a scope that terminates
        !           740:  * with a subsequent call to the same macro.  Implicit macros cannot
        !           741:  * break the scope of explicitly-scoped macros; however, they can break
        !           742:  * the scope of other implicit macros (so `.Sh' can break `.Ss').  This
        !           743:  * is ok with macros like `.It' because they exist only within an
        !           744:  * explicit context.
        !           745:  *
        !           746:  * These macros put line arguments (which it's allowed to have) into the
        !           747:  * HEAD section and open a BODY scope to be used until the macro scope
        !           748:  * closes.
        !           749:  */
        !           750: int
        !           751: macro_scoped_implicit(MACRO_PROT_ARGS)
        !           752: {
        !           753:        int               lastarg, j;
        !           754:        char             *args[MDOC_LINEARG_MAX];
        !           755:        struct mdoc_node *n;
        !           756:
        !           757:        assert( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags));
        !           758:
        !           759:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !           760:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
        !           761:
        !           762:        /* Token pre-processing. */
        !           763:
        !           764:        switch (tok) {
        !           765:        case (MDOC_Ss):
        !           766:                /* FALLTHROUGH */
        !           767:        case (MDOC_Sh):
        !           768:                /* `.Pp' ignored when preceding `.Ss' or `.Sh'. */
        !           769:                if (NULL == mdoc->last)
        !           770:                        break;
        !           771:                if (MDOC_ELEM != mdoc->last->type)
        !           772:                        break;
        !           773:                if (MDOC_Pp != mdoc->last->data.elem.tok)
        !           774:                        break;
        !           775:                if ( ! mdoc_warn(mdoc, tok, ppos, WARN_IGN_BEFORE_BLK))
1.1       kristaps  776:                        return(0);
1.8     ! kristaps  777:                assert(mdoc->last->prev);
        !           778:                n = mdoc->last;
        !           779:                mdoc_msg(mdoc, ppos, "removing prior `Pp' macro");
        !           780:                mdoc->last = mdoc->last->prev;
        !           781:                mdoc->last->next = NULL;
        !           782:                mdoc_node_free(n);
        !           783:                break;
        !           784:        default:
        !           785:                break;
        !           786:        }
        !           787:
        !           788:        /* Rewind our scope. */
        !           789:
        !           790:        if ( ! scope_rewind_imp(mdoc, ppos, tok))
1.2       kristaps  791:                return(0);
1.1       kristaps  792:
1.8     ! kristaps  793:        j = 0;
        !           794:        lastarg = ppos;
        !           795:
        !           796:        /*
        !           797:         * Process until we hit a line.  Note that current implicit
        !           798:         * macros don't have any arguments, so we don't need to do any
        !           799:         * argument processing.
        !           800:         */
        !           801:
        !           802: again:
        !           803:        if (j == MDOC_LINEARG_MAX)
        !           804:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !           805:
        !           806:        lastarg = *pos;
        !           807:
        !           808:        switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[j])) {
        !           809:        case (ARGS_ERROR):
1.1       kristaps  810:                return(0);
1.8     ! kristaps  811:        case (ARGS_EOLN):
        !           812:                return(append_scoped(mdoc, tok, ppos, j, _CC(args), 0, NULL));
        !           813:        default:
        !           814:                break;
        !           815:        }
1.5       kristaps  816:
1.8     ! kristaps  817:        if (MDOC_MAX != mdoc_find(mdoc, args[j]))
        !           818:                if ( ! mdoc_warn(mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
1.5       kristaps  819:                        return(0);
1.8     ! kristaps  820:
        !           821:        j++;
        !           822:        goto again;
        !           823:        /* NOTREACHED */
        !           824: }
        !           825:
        !           826:
        !           827: /*
        !           828:  * A line-scoped macro opens a scope for the contents of its line, which
        !           829:  * are placed under the HEAD node.  Punctuation trailing the line is put
        !           830:  * as a sibling to the HEAD node, under the BLOCK node.
        !           831:  */
        !           832: int
        !           833: macro_scoped_line(MACRO_PROT_ARGS)
        !           834: {
        !           835:        int               lastarg, c, j;
        !           836:        char              *p;
        !           837:        struct mdoc_node  *n;
        !           838:
        !           839:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !           840:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
        !           841:
        !           842:        assert(1 == ppos);
        !           843:
        !           844:        /* Token pre-processing.  */
        !           845:
        !           846:        switch (tok) {
        !           847:        case (MDOC_D1):
        !           848:                /* FALLTHROUGH */
        !           849:        case (MDOC_Dl):
        !           850:                /* These can't be nested in a display block. */
        !           851:                assert(mdoc->last);
        !           852:                for (n = mdoc->last->parent ; n; n = n->parent)
        !           853:                        if (MDOC_BLOCK != n->type)
        !           854:                                continue;
        !           855:                        else if (MDOC_Bd == n->data.block.tok)
        !           856:                                break;
        !           857:                if (NULL == n)
        !           858:                        break;
        !           859:                return(mdoc_err(mdoc, tok, ppos, ERR_SCOPE_NONEST));
        !           860:        default:
        !           861:                break;
        !           862:        }
        !           863:
        !           864:        /*
        !           865:         * All line-scoped macros have a HEAD and optionally a BODY
        !           866:         * section.  We open our scope here; when we exit this function,
        !           867:         * we'll rewind our scope appropriately.
        !           868:         */
        !           869:
        !           870:        mdoc_block_alloc(mdoc, ppos, tok, 0, NULL);
        !           871:        mdoc_head_alloc(mdoc, ppos, tok, 0, NULL);
        !           872:
        !           873:        /* Process line parameters. */
        !           874:
        !           875:        j = 0;
        !           876:        lastarg = ppos;
        !           877:
        !           878: again:
        !           879:        if (j == MDOC_LINEARG_MAX)
        !           880:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !           881:
        !           882:        lastarg = *pos;
        !           883:        c = mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p);
        !           884:
        !           885:        switch (c) {
        !           886:        case (ARGS_ERROR):
        !           887:                return(0);
        !           888:        case (ARGS_WORD):
        !           889:                break;
        !           890:        case (ARGS_PUNCT):
        !           891:                if ( ! append_delims(mdoc, tok, pos, buf))
1.5       kristaps  892:                        return(0);
1.8     ! kristaps  893:                return(scope_rewind_imp(mdoc, ppos, tok));
        !           894:        case (ARGS_EOLN):
        !           895:                return(scope_rewind_imp(mdoc, ppos, tok));
        !           896:        default:
        !           897:                abort();
        !           898:                /* NOTREACHED */
        !           899:        }
        !           900:
        !           901:        if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
        !           902:                if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
1.5       kristaps  903:                        return(0);
1.8     ! kristaps  904:                if ( ! append_delims(mdoc, tok, pos, buf))
1.5       kristaps  905:                        return(0);
1.8     ! kristaps  906:                return(scope_rewind_imp(mdoc, ppos, tok));
1.5       kristaps  907:        }
                    908:
1.8     ! kristaps  909:        if (mdoc_isdelim(p))
        !           910:                j = 0;
1.1       kristaps  911:
1.8     ! kristaps  912:        mdoc_word_alloc(mdoc, lastarg, p);
        !           913:        goto again;
        !           914:        /* NOTREACHED */
1.1       kristaps  915: }
                    916:
                    917:
1.8     ! kristaps  918: /*
        !           919:  * Partial-line scope is identical to line scope (macro_scoped_line())
        !           920:  * except that trailing punctuation is appended to the BLOCK, instead of
        !           921:  * contained within the HEAD.
        !           922:  */
        !           923: int
        !           924: macro_scoped_pline(MACRO_PROT_ARGS)
1.1       kristaps  925: {
1.8     ! kristaps  926:        int               lastarg, c, j;
        !           927:        char              *p;
1.1       kristaps  928:
1.8     ! kristaps  929:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !           930:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
1.1       kristaps  931:
1.8     ! kristaps  932:        /* Token pre-processing.  */
1.2       kristaps  933:
1.8     ! kristaps  934:        switch (tok) {
        !           935:        case (MDOC_Ql):
        !           936:                if ( ! mdoc_warn(mdoc, tok, ppos, WARN_COMPAT_TROFF))
1.2       kristaps  937:                        return(0);
1.8     ! kristaps  938:                break;
        !           939:        default:
        !           940:                break;
        !           941:        }
        !           942:
        !           943:        mdoc_block_alloc(mdoc, ppos, tok, 0, NULL);
        !           944:        mdoc_head_alloc(mdoc, ppos, tok, 0, NULL);
        !           945:
        !           946:        /* Process line parameters. */
        !           947:
        !           948:        j = 0;
        !           949:        lastarg = ppos;
        !           950:
        !           951: again:
        !           952:        if (j == MDOC_LINEARG_MAX)
        !           953:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !           954:
        !           955:        lastarg = *pos;
        !           956:        c = mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p);
        !           957:
        !           958:        switch (c) {
        !           959:        case (ARGS_ERROR):
        !           960:                return(0);
        !           961:        case (ARGS_WORD):
        !           962:                break;
        !           963:        case (ARGS_PUNCT):
        !           964:                if ( ! scope_rewind_imp(mdoc, ppos, tok))
        !           965:                        return(0);
        !           966:                if (ppos > 1)
        !           967:                        return(1);
        !           968:                return(append_delims(mdoc, tok, pos, buf));
        !           969:        case (ARGS_EOLN):
        !           970:                return(scope_rewind_imp(mdoc, ppos, tok));
        !           971:        default:
        !           972:                abort();
        !           973:                /* NOTREACHED */
        !           974:        }
        !           975:
        !           976:        if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
        !           977:                if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
        !           978:                        return(0);
        !           979:                if ( ! scope_rewind_imp(mdoc, ppos, tok))
1.2       kristaps  980:                        return(0);
1.8     ! kristaps  981:                if (ppos > 1)
        !           982:                        return(1);
        !           983:                return(append_delims(mdoc, tok, pos, buf));
        !           984:        }
1.1       kristaps  985:
1.8     ! kristaps  986:        if (mdoc_isdelim(p))
        !           987:                j = 0;
1.1       kristaps  988:
1.8     ! kristaps  989:        mdoc_word_alloc(mdoc, lastarg, p);
        !           990:        goto again;
        !           991:        /* NOTREACHED */
1.1       kristaps  992: }
                    993:
                    994:
1.8     ! kristaps  995: /*
        !           996:  * A delimited-constant macro is similar to a general text macro: the
        !           997:  * macro is followed by a 0 or 1 arguments (possibly-unspecified) then
        !           998:  * terminating punctuation, other words, or another callable macro.
        !           999:  */
        !          1000: int
        !          1001: macro_constant_delimited(MACRO_PROT_ARGS)
1.1       kristaps 1002: {
1.8     ! kristaps 1003:        int               lastarg, flushed, c, maxargs;
        !          1004:        char             *p;
        !          1005:
        !          1006:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !          1007:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
        !          1008:
        !          1009:        /* Process line parameters. */
1.2       kristaps 1010:
1.8     ! kristaps 1011:        lastarg = ppos;
        !          1012:        flushed = 0;
1.2       kristaps 1013:
1.8     ! kristaps 1014:        /* Token pre-processing. */
        !          1015:
        !          1016:        switch (tok) {
        !          1017:        case (MDOC_Ux):
        !          1018:                maxargs = 0;
        !          1019:                break;
        !          1020:        default:
        !          1021:                maxargs = 1;
        !          1022:                break;
        !          1023:        }
1.2       kristaps 1024:
1.8     ! kristaps 1025: again:
        !          1026:        lastarg = *pos;
1.5       kristaps 1027:
1.8     ! kristaps 1028:        switch (mdoc_args(mdoc, tok, pos, buf, ARGS_DELIM, &p)) {
        !          1029:        case (ARGS_ERROR):
1.2       kristaps 1030:                return(0);
1.8     ! kristaps 1031:        case (ARGS_WORD):
        !          1032:                break;
        !          1033:        case (ARGS_PUNCT):
        !          1034:                if ( ! flushed && ! append_const(mdoc, tok, ppos, 0, &p))
        !          1035:                        return(0);
        !          1036:                if (ppos > 1)
        !          1037:                        return(1);
        !          1038:                return(append_delims(mdoc, tok, pos, buf));
        !          1039:        case (ARGS_EOLN):
        !          1040:                if (flushed)
        !          1041:                        return(1);
        !          1042:                return(append_const(mdoc, tok, ppos, 0, &p));
        !          1043:        default:
        !          1044:                abort();
        !          1045:                /* NOTREACHED */
        !          1046:        }
        !          1047:
        !          1048:        /* Accepts no arguments: flush out symbol and continue. */
1.5       kristaps 1049:
1.8     ! kristaps 1050:        if (0 == maxargs) {
        !          1051:                if ( ! append_const(mdoc, tok, ppos, 0, &p))
1.5       kristaps 1052:                        return(0);
1.8     ! kristaps 1053:                flushed = 1;
        !          1054:        }
        !          1055:
        !          1056:        if (MDOC_MAX != (c = mdoc_find(mdoc, p))) {
        !          1057:                if ( ! flushed && ! append_const(mdoc, tok, ppos, 0, &p))
1.5       kristaps 1058:                        return(0);
1.8     ! kristaps 1059:                if ( ! mdoc_macro(mdoc, c, lastarg, pos, buf))
1.5       kristaps 1060:                        return(0);
1.8     ! kristaps 1061:                if (ppos > 1)
        !          1062:                        return(1);
        !          1063:                return(append_delims(mdoc, tok, pos, buf));
        !          1064:        }
        !          1065:
        !          1066:        /*
        !          1067:         * We only accept one argument; subsequent tokens are considered
        !          1068:         * as literal words (until a macro).
        !          1069:         */
        !          1070:
        !          1071:        if ( ! flushed && ! mdoc_isdelim(p)) {
        !          1072:               if ( ! append_const(mdoc, tok, ppos, 1, &p))
1.5       kristaps 1073:                        return(0);
1.8     ! kristaps 1074:                flushed = 1;
        !          1075:                goto again;
        !          1076:        } else if ( ! flushed) {
        !          1077:                if ( ! append_const(mdoc, tok, ppos, 0, &p))
1.5       kristaps 1078:                        return(0);
1.8     ! kristaps 1079:                flushed = 1;
1.5       kristaps 1080:        }
                   1081:
1.8     ! kristaps 1082:        mdoc_word_alloc(mdoc, lastarg, p);
        !          1083:        goto again;
        !          1084:        /* NOTREACHED */
1.1       kristaps 1085: }
                   1086:
                   1087:
1.8     ! kristaps 1088: int
        !          1089: macro_constant(MACRO_PROT_ARGS)
1.1       kristaps 1090: {
1.8     ! kristaps 1091:        int               lastarg, j;
        !          1092:        char             *args[MDOC_LINEARG_MAX];
1.2       kristaps 1093:
1.8     ! kristaps 1094:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !          1095:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
1.2       kristaps 1096:
1.8     ! kristaps 1097:        j = 0;
        !          1098:        lastarg = ppos;
1.2       kristaps 1099:
1.8     ! kristaps 1100: again:
        !          1101:        if (j == MDOC_LINEARG_MAX)
        !          1102:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
1.1       kristaps 1103:
1.8     ! kristaps 1104:        lastarg = *pos;
1.1       kristaps 1105:
1.8     ! kristaps 1106:        switch (mdoc_args(mdoc, tok, pos, buf, 0, &args[j])) {
        !          1107:        case (ARGS_ERROR):
        !          1108:                return(0);
        !          1109:        case (ARGS_WORD):
1.1       kristaps 1110:                break;
1.8     ! kristaps 1111:        case (ARGS_EOLN):
        !          1112:                return(append_const(mdoc, tok, ppos, j, args));
1.1       kristaps 1113:        default:
                   1114:                abort();
1.8     ! kristaps 1115:                /* NOTREACHED */
1.1       kristaps 1116:        }
                   1117:
1.8     ! kristaps 1118:        if (MDOC_MAX != mdoc_find(mdoc, args[j]))
        !          1119:                if ( ! mdoc_warn(mdoc, tok, lastarg, WARN_SYNTAX_MACLIKE))
        !          1120:                        return(0);
        !          1121:
        !          1122:        j++;
        !          1123:        goto again;
        !          1124:        /* NOTREACHED */
1.1       kristaps 1125: }
                   1126:
                   1127:
1.8     ! kristaps 1128: int
        !          1129: macro_constant_argv(MACRO_PROT_ARGS)
1.1       kristaps 1130: {
1.8     ! kristaps 1131:        int               c, lastarg, j;
        !          1132:        struct mdoc_arg   argv[MDOC_LINEARG_MAX];
        !          1133:
        !          1134:        if (SEC_PROLOGUE == mdoc->sec_lastn)
        !          1135:                return(mdoc_err(mdoc, tok, ppos, ERR_SEC_PROLOGUE));
1.1       kristaps 1136:
1.8     ! kristaps 1137:        lastarg = *pos;
        !          1138:
        !          1139:        for (j = 0; j < MDOC_LINEARG_MAX; j++) {
        !          1140:                lastarg = *pos;
        !          1141:                c = mdoc_argv(mdoc, tok, &argv[j], pos, buf);
        !          1142:                if (0 == c)
        !          1143:                        break;
        !          1144:                else if (1 == c)
        !          1145:                        continue;
        !          1146:
        !          1147:                mdoc_argv_free(j, argv);
        !          1148:                return(0);
        !          1149:        }
        !          1150:
        !          1151:        if (MDOC_LINEARG_MAX == j) {
        !          1152:                mdoc_argv_free(j, argv);
        !          1153:                return(mdoc_err(mdoc, tok, lastarg, ERR_ARGS_MANY));
        !          1154:        }
        !          1155:
        !          1156:        c = append_constarg(mdoc, tok, ppos, j, argv);
        !          1157:        mdoc_argv_free(j, argv);
        !          1158:        return(c);
1.1       kristaps 1159: }

CVSweb