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

Annotation of mandoc/macro.c, Revision 1.8

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

CVSweb