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

Annotation of mandoc/macro.c, Revision 1.10

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

CVSweb