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

Annotation of mandoc/macro.c, Revision 1.51

1.51    ! kristaps    1: /* $Id: macro.c,v 1.50 2009/02/22 19:23:48 kristaps Exp $ */
1.1       kristaps    2: /*
                      3:  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the
                      7:  * above copyright notice and this permission notice appear in all
                      8:  * copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
                     11:  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
                     12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
                     13:  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
                     14:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
                     15:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
                     16:  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     17:  * PERFORMANCE OF THIS SOFTWARE.
                     18:  */
1.2       kristaps   19: #include <assert.h>
                     20: #include <ctype.h>
1.1       kristaps   21: #include <stdlib.h>
1.2       kristaps   22: #include <stdio.h>
1.5       kristaps   23: #include <string.h>
1.11      kristaps   24: #ifdef __linux__
                     25: #include <time.h>
                     26: #endif
1.2       kristaps   27:
1.44      kristaps   28: /*
                     29:  * This has scanning/parsing routines, each of which extract a macro and
                     30:  * its arguments and parameters, then know how to progress to the next
1.51    ! kristaps   31:  * macro.
1.44      kristaps   32:  */
                     33:
1.2       kristaps   34: #include "private.h"
                     35:
1.51    ! kristaps   36: static int       macro_obsolete(MACRO_PROT_ARGS);
        !            37: static int       macro_constant(MACRO_PROT_ARGS);
        !            38: static int       macro_constant_scoped(MACRO_PROT_ARGS);
        !            39: static int       macro_constant_delimited(MACRO_PROT_ARGS);
        !            40: static int       macro_text(MACRO_PROT_ARGS);
        !            41: static int       macro_scoped(MACRO_PROT_ARGS);
        !            42: static int       macro_scoped_close(MACRO_PROT_ARGS);
        !            43: static int       macro_scoped_line(MACRO_PROT_ARGS);
        !            44:
1.35      kristaps   45: #define        REWIND_REWIND   (1 << 0)
                     46: #define        REWIND_NOHALT   (1 << 1)
                     47: #define        REWIND_HALT     (1 << 2)
1.49      kristaps   48:
1.44      kristaps   49: static int       rewind_dohalt(int, enum mdoc_type,
                     50:                        const struct mdoc_node *);
                     51: static int       rewind_alt(int);
1.41      kristaps   52: static int       rewind_dobreak(int, const struct mdoc_node *);
1.28      kristaps   53: static int       rewind_elem(struct mdoc *, int);
1.38      kristaps   54: static int       rewind_impblock(struct mdoc *, int, int, int);
                     55: static int       rewind_expblock(struct mdoc *, int, int, int);
1.41      kristaps   56: static int       rewind_subblock(enum mdoc_type,
                     57:                        struct mdoc *, int, int, int);
                     58: static int       rewind_last(struct mdoc *, struct mdoc_node *);
                     59: static int       append_delims(struct mdoc *, int, int *, char *);
1.30      kristaps   60: static int       lookup(struct mdoc *, int, int, int, const char *);
1.49      kristaps   61: static int       pwarn(struct mdoc *, int, int, int);
                     62: static int       perr(struct mdoc *, int, int, int);
                     63:
                     64: #define        WMACPARM        (1)
                     65: #define        WOBS            (2)
                     66:
                     67: #define        ENOCTX          (1)
                     68: #define        ENOPARMS        (2)
                     69: #define        EARGVLIM        (3)
                     70:
1.51    ! kristaps   71: /* Central table of library: who gets parsed how. */
        !            72:
        !            73: const  struct mdoc_macro __mdoc_macros[MDOC_MAX] = {
        !            74:        { NULL, 0 }, /* \" */
        !            75:        { macro_constant, MDOC_PROLOGUE }, /* Dd */
        !            76:        { macro_constant, MDOC_PROLOGUE }, /* Dt */
        !            77:        { macro_constant, MDOC_PROLOGUE }, /* Os */
        !            78:        { macro_scoped, 0 }, /* Sh */
        !            79:        { macro_scoped, 0 }, /* Ss */
        !            80:        { macro_text, 0 }, /* Pp */
        !            81:        { macro_scoped_line, MDOC_PARSED }, /* D1 */
        !            82:        { macro_scoped_line, MDOC_PARSED }, /* Dl */
        !            83:        { macro_scoped, MDOC_EXPLICIT }, /* Bd */
        !            84:        { macro_scoped_close, MDOC_EXPLICIT }, /* Ed */
        !            85:        { macro_scoped, MDOC_EXPLICIT }, /* Bl */
        !            86:        { macro_scoped_close, MDOC_EXPLICIT }, /* El */
        !            87:        { macro_scoped, MDOC_PARSED }, /* It */
        !            88:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ad */
        !            89:        { macro_text, MDOC_PARSED }, /* An */
        !            90:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ar */
        !            91:        { macro_constant, 0 }, /* Cd */
        !            92:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Cm */
        !            93:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Dv */
        !            94:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Er */
        !            95:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ev */
        !            96:        { macro_constant, 0 }, /* Ex */
        !            97:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fa */
        !            98:        { macro_constant, 0 }, /* Fd */
        !            99:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fl */
        !           100:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Fn */
        !           101:        { macro_text, MDOC_PARSED }, /* Ft */
        !           102:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Ic */
        !           103:        { macro_constant, 0 }, /* In */
        !           104:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Li */
        !           105:        { macro_constant, 0 }, /* Nd */
        !           106:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Nm */
        !           107:        { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Op */
        !           108:        { macro_obsolete, 0 }, /* Ot */
        !           109:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Pa */
        !           110:        { macro_constant, 0 }, /* Rv */
        !           111:        /* XXX - .St supposed to be (but isn't) callable. */
        !           112:        { macro_constant_delimited, MDOC_PARSED }, /* St */
        !           113:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Va */
        !           114:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Vt */
        !           115:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Xr */
        !           116:        { macro_constant, 0 }, /* %A */
        !           117:        { macro_constant, 0 }, /* %B */
        !           118:        { macro_constant, 0 }, /* %D */
        !           119:        { macro_constant, 0 }, /* %I */
        !           120:        { macro_constant, 0 }, /* %J */
        !           121:        { macro_constant, 0 }, /* %N */
        !           122:        { macro_constant, 0 }, /* %O */
        !           123:        { macro_constant, 0 }, /* %P */
        !           124:        { macro_constant, 0 }, /* %R */
        !           125:        { macro_constant, 0 }, /* %T */
        !           126:        { macro_constant, 0 }, /* %V */
        !           127:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ac */
        !           128:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Ao */
        !           129:        { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Aq */
        !           130:        { macro_constant_delimited, 0 }, /* At */
        !           131:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Bc */
        !           132:        { macro_scoped, MDOC_EXPLICIT }, /* Bf */
        !           133:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Bo */
        !           134:        { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Bq */
        !           135:        { macro_constant_delimited, MDOC_PARSED }, /* Bsx */
        !           136:        { macro_constant_delimited, MDOC_PARSED }, /* Bx */
        !           137:        { macro_constant, 0 }, /* Db */
        !           138:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Dc */
        !           139:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Do */
        !           140:        { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Dq */
        !           141:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Ec */
        !           142:        { macro_scoped_close, MDOC_EXPLICIT }, /* Ef */
        !           143:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Em */
        !           144:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Eo */
        !           145:        { macro_constant_delimited, MDOC_PARSED }, /* Fx */
        !           146:        { macro_text, MDOC_PARSED }, /* Ms */
        !           147:        { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* No */
        !           148:        { macro_constant_delimited, MDOC_CALLABLE | MDOC_PARSED }, /* Ns */
        !           149:        { macro_constant_delimited, MDOC_PARSED }, /* Nx */
        !           150:        { macro_constant_delimited, MDOC_PARSED }, /* Ox */
        !           151:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Pc */
        !           152:        { macro_constant_delimited, MDOC_PARSED }, /* Pf */
        !           153:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Po */
        !           154:        { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Pq */
        !           155:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Qc */
        !           156:        { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Ql */
        !           157:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Qo */
        !           158:        { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Qq */
        !           159:        { macro_scoped_close, MDOC_EXPLICIT }, /* Re */
        !           160:        { macro_scoped, MDOC_EXPLICIT }, /* Rs */
        !           161:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Sc */
        !           162:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* So */
        !           163:        { macro_scoped_line, MDOC_CALLABLE | MDOC_PARSED }, /* Sq */
        !           164:        { macro_constant, 0 }, /* Sm */
        !           165:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Sx */
        !           166:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Sy */
        !           167:        { macro_text, MDOC_CALLABLE | MDOC_PARSED }, /* Tn */
        !           168:        { macro_constant_delimited, MDOC_PARSED }, /* Ux */
        !           169:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Xc */
        !           170:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Xo */
        !           171:        /* XXX - .Fo supposed to be (but isn't) callable. */
        !           172:        { macro_scoped, MDOC_EXPLICIT }, /* Fo */
        !           173:        /* XXX - .Fc supposed to be (but isn't) callable. */
        !           174:        { macro_scoped_close, MDOC_EXPLICIT }, /* Fc */
        !           175:        { macro_constant_scoped, MDOC_CALLABLE | MDOC_PARSED | MDOC_EXPLICIT }, /* Oo */
        !           176:        { macro_scoped_close, MDOC_EXPLICIT | MDOC_CALLABLE | MDOC_PARSED }, /* Oc */
        !           177:        { macro_scoped, MDOC_EXPLICIT }, /* Bk */
        !           178:        { macro_scoped_close, MDOC_EXPLICIT }, /* Ek */
        !           179:        { macro_constant, 0 }, /* Bt */
        !           180:        { macro_constant, 0 }, /* Hf */
        !           181:        { macro_obsolete, 0 }, /* Fr */
        !           182:        { macro_constant, 0 }, /* Ud */
        !           183: };
        !           184:
        !           185: const  struct mdoc_macro * const mdoc_macros = __mdoc_macros;
        !           186:
1.49      kristaps  187:
                    188: static int
                    189: perr(struct mdoc *mdoc, int line, int pos, int type)
                    190: {
                    191:        int              c;
                    192:
                    193:        switch (type) {
                    194:        case (ENOCTX):
                    195:                c = mdoc_perr(mdoc, line, pos,
                    196:                                "closing macro has prior context");
                    197:                break;
                    198:        case (ENOPARMS):
                    199:                c = mdoc_perr(mdoc, line, pos,
                    200:                                "macro doesn't expect parameters");
                    201:                break;
                    202:        case (EARGVLIM):
                    203:                c = mdoc_perr(mdoc, line, pos,
                    204:                                "argument hard-limit %d reached",
                    205:                                MDOC_LINEARG_MAX);
                    206:                break;
                    207:        default:
                    208:                abort();
                    209:                /* NOTREACHED */
                    210:        }
                    211:        return(c);
                    212: }
                    213:
                    214: static int
                    215: pwarn(struct mdoc *mdoc, int line, int pos, int type)
                    216: {
                    217:        int              c;
                    218:
                    219:        switch (type) {
                    220:        case (WMACPARM):
                    221:                c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
                    222:                                "macro-like parameter");
                    223:                break;
                    224:        case (WOBS):
                    225:                c = mdoc_pwarn(mdoc, line, pos, WARN_SYNTAX,
                    226:                                "macro is marked obsolete");
                    227:                break;
                    228:        default:
                    229:                abort();
                    230:                /* NOTREACHED */
                    231:        }
                    232:        return(c);
                    233: }
1.24      kristaps  234:
                    235:
                    236: static int
1.30      kristaps  237: lookup(struct mdoc *mdoc, int line, int pos, int from, const char *p)
1.24      kristaps  238: {
1.30      kristaps  239:        int              res;
1.24      kristaps  240:
1.30      kristaps  241:        res = mdoc_find(mdoc, p);
                    242:        if (MDOC_PARSED & mdoc_macros[from].flags)
                    243:                return(res);
                    244:        if (MDOC_MAX == res)
                    245:                return(res);
1.49      kristaps  246:        if ( ! pwarn(mdoc, line, pos, WMACPARM))
1.30      kristaps  247:                return(-1);
                    248:        return(MDOC_MAX);
1.24      kristaps  249: }
1.19      kristaps  250:
                    251:
                    252: static int
1.41      kristaps  253: rewind_last(struct mdoc *mdoc, struct mdoc_node *to)
1.25      kristaps  254: {
                    255:
                    256:        assert(to);
1.30      kristaps  257:        mdoc->next = MDOC_NEXT_SIBLING;
1.42      kristaps  258:
1.49      kristaps  259:        /* LINTED */
1.42      kristaps  260:        while (mdoc->last != to) {
1.30      kristaps  261:                if ( ! mdoc_valid_post(mdoc))
                    262:                        return(0);
                    263:                if ( ! mdoc_action_post(mdoc))
                    264:                        return(0);
1.29      kristaps  265:                mdoc->last = mdoc->last->parent;
                    266:                assert(mdoc->last);
1.42      kristaps  267:        }
1.28      kristaps  268:
1.42      kristaps  269:        if ( ! mdoc_valid_post(mdoc))
                    270:                return(0);
                    271:        return(mdoc_action_post(mdoc));
1.25      kristaps  272: }
                    273:
                    274:
                    275: static int
1.35      kristaps  276: rewind_alt(int tok)
                    277: {
                    278:        switch (tok) {
                    279:        case (MDOC_Ac):
                    280:                return(MDOC_Ao);
                    281:        case (MDOC_Bc):
                    282:                return(MDOC_Bo);
                    283:        case (MDOC_Dc):
                    284:                return(MDOC_Do);
                    285:        case (MDOC_Ec):
                    286:                return(MDOC_Eo);
                    287:        case (MDOC_Ed):
                    288:                return(MDOC_Bd);
                    289:        case (MDOC_Ef):
                    290:                return(MDOC_Bf);
                    291:        case (MDOC_Ek):
                    292:                return(MDOC_Bk);
                    293:        case (MDOC_El):
                    294:                return(MDOC_Bl);
                    295:        case (MDOC_Fc):
                    296:                return(MDOC_Fo);
                    297:        case (MDOC_Oc):
                    298:                return(MDOC_Oo);
                    299:        case (MDOC_Pc):
                    300:                return(MDOC_Po);
                    301:        case (MDOC_Qc):
                    302:                return(MDOC_Qo);
                    303:        case (MDOC_Re):
                    304:                return(MDOC_Rs);
                    305:        case (MDOC_Sc):
                    306:                return(MDOC_So);
                    307:        case (MDOC_Xc):
                    308:                return(MDOC_Xo);
                    309:        default:
                    310:                break;
                    311:        }
                    312:        abort();
                    313:        /* NOTREACHED */
                    314: }
                    315:
                    316:
                    317: static int
                    318: rewind_dohalt(int tok, enum mdoc_type type, const struct mdoc_node *p)
                    319: {
                    320:
                    321:        if (MDOC_ROOT == p->type)
                    322:                return(REWIND_HALT);
1.42      kristaps  323:        if (MDOC_VALID & p->flags)
1.35      kristaps  324:                return(REWIND_NOHALT);
                    325:
                    326:        switch (tok) {
                    327:        /* One-liner implicit-scope. */
                    328:        case (MDOC_Aq):
                    329:                /* FALLTHROUGH */
                    330:        case (MDOC_Bq):
                    331:                /* FALLTHROUGH */
                    332:        case (MDOC_D1):
                    333:                /* FALLTHROUGH */
                    334:        case (MDOC_Dl):
                    335:                /* FALLTHROUGH */
                    336:        case (MDOC_Dq):
                    337:                /* FALLTHROUGH */
                    338:        case (MDOC_Op):
                    339:                /* FALLTHROUGH */
                    340:        case (MDOC_Pq):
                    341:                /* FALLTHROUGH */
                    342:        case (MDOC_Ql):
                    343:                /* FALLTHROUGH */
                    344:        case (MDOC_Qq):
                    345:                /* FALLTHROUGH */
                    346:        case (MDOC_Sq):
1.44      kristaps  347:                assert(MDOC_HEAD != type);
1.35      kristaps  348:                assert(MDOC_TAIL != type);
                    349:                if (type == p->type && tok == p->tok)
                    350:                        return(REWIND_REWIND);
                    351:                break;
                    352:
                    353:        /* Multi-line implicit-scope. */
                    354:        case (MDOC_It):
                    355:                assert(MDOC_TAIL != type);
                    356:                if (type == p->type && tok == p->tok)
                    357:                        return(REWIND_REWIND);
1.36      kristaps  358:                if (MDOC_BODY == p->type && MDOC_Bl == p->tok)
1.35      kristaps  359:                        return(REWIND_HALT);
                    360:                break;
                    361:        case (MDOC_Sh):
1.36      kristaps  362:                if (type == p->type && tok == p->tok)
                    363:                        return(REWIND_REWIND);
                    364:                break;
1.35      kristaps  365:        case (MDOC_Ss):
1.36      kristaps  366:                assert(MDOC_TAIL != type);
1.35      kristaps  367:                if (type == p->type && tok == p->tok)
                    368:                        return(REWIND_REWIND);
1.36      kristaps  369:                if (MDOC_BODY == p->type && MDOC_Sh == p->tok)
                    370:                        return(REWIND_HALT);
1.35      kristaps  371:                break;
                    372:
                    373:        /* Multi-line explicit scope start. */
                    374:        case (MDOC_Ao):
                    375:                /* FALLTHROUGH */
                    376:        case (MDOC_Bd):
                    377:                /* FALLTHROUGH */
                    378:        case (MDOC_Bf):
                    379:                /* FALLTHROUGH */
                    380:        case (MDOC_Bk):
                    381:                /* FALLTHROUGH */
                    382:        case (MDOC_Bl):
                    383:                /* FALLTHROUGH */
                    384:        case (MDOC_Bo):
                    385:                /* FALLTHROUGH */
                    386:        case (MDOC_Do):
                    387:                /* FALLTHROUGH */
                    388:        case (MDOC_Eo):
                    389:                /* FALLTHROUGH */
                    390:        case (MDOC_Fo):
                    391:                /* FALLTHROUGH */
                    392:        case (MDOC_Oo):
                    393:                /* FALLTHROUGH */
                    394:        case (MDOC_Po):
                    395:                /* FALLTHROUGH */
                    396:        case (MDOC_Qo):
                    397:                /* FALLTHROUGH */
                    398:        case (MDOC_Rs):
                    399:                /* FALLTHROUGH */
                    400:        case (MDOC_So):
                    401:                /* FALLTHROUGH */
                    402:        case (MDOC_Xo):
                    403:                if (type == p->type && tok == p->tok)
                    404:                        return(REWIND_REWIND);
                    405:                break;
                    406:
                    407:        /* Multi-line explicit scope close. */
                    408:        case (MDOC_Ac):
                    409:                /* FALLTHROUGH */
                    410:        case (MDOC_Bc):
                    411:                /* FALLTHROUGH */
                    412:        case (MDOC_Dc):
                    413:                /* FALLTHROUGH */
                    414:        case (MDOC_Ec):
                    415:                /* FALLTHROUGH */
                    416:        case (MDOC_Ed):
                    417:                /* FALLTHROUGH */
                    418:        case (MDOC_Ek):
                    419:                /* FALLTHROUGH */
                    420:        case (MDOC_El):
                    421:                /* FALLTHROUGH */
                    422:        case (MDOC_Fc):
                    423:                /* FALLTHROUGH */
                    424:        case (MDOC_Ef):
                    425:                /* FALLTHROUGH */
                    426:        case (MDOC_Oc):
                    427:                /* FALLTHROUGH */
                    428:        case (MDOC_Pc):
                    429:                /* FALLTHROUGH */
                    430:        case (MDOC_Qc):
                    431:                /* FALLTHROUGH */
                    432:        case (MDOC_Re):
                    433:                /* FALLTHROUGH */
                    434:        case (MDOC_Sc):
                    435:                /* FALLTHROUGH */
                    436:        case (MDOC_Xc):
                    437:                if (type == p->type && rewind_alt(tok) == p->tok)
                    438:                        return(REWIND_REWIND);
                    439:                break;
                    440:        default:
                    441:                abort();
                    442:                /* NOTREACHED */
                    443:        }
                    444:
                    445:        return(REWIND_NOHALT);
                    446: }
                    447:
                    448:
                    449: static int
1.41      kristaps  450: rewind_dobreak(int tok, const struct mdoc_node *p)
1.35      kristaps  451: {
                    452:
                    453:        assert(MDOC_ROOT != p->type);
                    454:        if (MDOC_ELEM == p->type)
                    455:                return(1);
                    456:        if (MDOC_TEXT == p->type)
                    457:                return(1);
1.42      kristaps  458:        if (MDOC_VALID & p->flags)
                    459:                return(1);
1.35      kristaps  460:
                    461:        switch (tok) {
1.36      kristaps  462:        /* Implicit rules. */
1.35      kristaps  463:        case (MDOC_It):
                    464:                return(MDOC_It == p->tok);
                    465:        case (MDOC_Ss):
                    466:                return(MDOC_Ss == p->tok);
                    467:        case (MDOC_Sh):
                    468:                if (MDOC_Ss == p->tok)
                    469:                        return(1);
                    470:                return(MDOC_Sh == p->tok);
1.36      kristaps  471:
                    472:        /* Extra scope rules. */
                    473:        case (MDOC_El):
                    474:                if (MDOC_It == p->tok)
                    475:                        return(1);
                    476:                break;
                    477:        default:
                    478:                break;
1.35      kristaps  479:        }
                    480:
                    481:        if (MDOC_EXPLICIT & mdoc_macros[tok].flags)
                    482:                return(p->tok == rewind_alt(tok));
                    483:        else if (MDOC_BLOCK == p->type)
                    484:                return(1);
                    485:
                    486:        return(tok == p->tok);
                    487: }
                    488:
                    489:
                    490: static int
1.28      kristaps  491: rewind_elem(struct mdoc *mdoc, int tok)
1.19      kristaps  492: {
                    493:        struct mdoc_node *n;
1.2       kristaps  494:
1.19      kristaps  495:        n = mdoc->last;
                    496:        if (MDOC_ELEM != n->type)
                    497:                n = n->parent;
                    498:        assert(MDOC_ELEM == n->type);
1.32      kristaps  499:        assert(tok == n->tok);
1.19      kristaps  500:
1.41      kristaps  501:        return(rewind_last(mdoc, n));
1.19      kristaps  502: }
1.6       kristaps  503:
                    504:
                    505: static int
1.41      kristaps  506: rewind_subblock(enum mdoc_type type, struct mdoc *mdoc,
                    507:                int tok, int line, int ppos)
1.22      kristaps  508: {
                    509:        struct mdoc_node *n;
1.35      kristaps  510:        int               c;
1.28      kristaps  511:
1.6       kristaps  512:        /* LINTED */
1.42      kristaps  513:        for (n = mdoc->last; n; n = n->parent) {
1.36      kristaps  514:                c = rewind_dohalt(tok, type, n);
1.35      kristaps  515:                if (REWIND_HALT == c)
                    516:                        return(1);
                    517:                if (REWIND_REWIND == c)
1.6       kristaps  518:                        break;
1.41      kristaps  519:                else if (rewind_dobreak(tok, n))
1.7       kristaps  520:                        continue;
1.41      kristaps  521:                return(mdoc_perr(mdoc, line, ppos, "scope breaks prior %s", mdoc_node2a(n)));
1.6       kristaps  522:        }
                    523:
1.25      kristaps  524:        assert(n);
1.41      kristaps  525:        return(rewind_last(mdoc, n));
1.6       kristaps  526: }
                    527:
                    528:
                    529: static int
1.38      kristaps  530: rewind_expblock(struct mdoc *mdoc, int tok, int line, int ppos)
1.6       kristaps  531: {
1.7       kristaps  532:        struct mdoc_node *n;
1.35      kristaps  533:        int               c;
1.6       kristaps  534:
1.7       kristaps  535:        /* LINTED */
1.42      kristaps  536:        for (n = mdoc->last; n; n = n->parent) {
1.35      kristaps  537:                c = rewind_dohalt(tok, MDOC_BLOCK, n);
                    538:                if (REWIND_HALT == c)
1.49      kristaps  539:                        return(perr(mdoc, line, ppos, ENOCTX));
1.35      kristaps  540:                if (REWIND_REWIND == c)
1.16      kristaps  541:                        break;
1.41      kristaps  542:                else if (rewind_dobreak(tok, n))
1.22      kristaps  543:                        continue;
1.51    ! kristaps  544:                return(mdoc_perr(mdoc, line, ppos,
        !           545:                                        "scope breaks prior %s",
        !           546:                                        mdoc_node2a(n)));
1.16      kristaps  547:        }
                    548:
1.28      kristaps  549:        assert(n);
1.41      kristaps  550:        return(rewind_last(mdoc, n));
1.21      kristaps  551: }
                    552:
                    553:
                    554: static int
1.38      kristaps  555: rewind_impblock(struct mdoc *mdoc, int tok, int line, int ppos)
1.21      kristaps  556: {
                    557:        struct mdoc_node *n;
1.35      kristaps  558:        int               c;
1.21      kristaps  559:
                    560:        /* LINTED */
1.42      kristaps  561:        for (n = mdoc->last; n; n = n->parent) {
1.35      kristaps  562:                c = rewind_dohalt(tok, MDOC_BLOCK, n);
                    563:                if (REWIND_HALT == c)
                    564:                        return(1);
                    565:                else if (REWIND_REWIND == c)
1.21      kristaps  566:                        break;
1.41      kristaps  567:                else if (rewind_dobreak(tok, n))
1.21      kristaps  568:                        continue;
1.51    ! kristaps  569:                return(mdoc_perr(mdoc, line, ppos,
        !           570:                                        "scope breaks prior %s",
        !           571:                                        mdoc_node2a(n)));
1.21      kristaps  572:        }
                    573:
1.35      kristaps  574:        assert(n);
1.41      kristaps  575:        return(rewind_last(mdoc, n));
1.16      kristaps  576: }
                    577:
                    578:
1.22      kristaps  579: static int
1.41      kristaps  580: append_delims(struct mdoc *mdoc, int line, int *pos, char *buf)
1.22      kristaps  581: {
                    582:        int              c, lastarg;
                    583:        char            *p;
                    584:
                    585:        if (0 == buf[*pos])
                    586:                return(1);
                    587:
                    588:        for (;;) {
                    589:                lastarg = *pos;
1.28      kristaps  590:                c = mdoc_args(mdoc, line, pos, buf, 0, &p);
1.49      kristaps  591:                assert(ARGS_PHRASE != c);
                    592:
1.22      kristaps  593:                if (ARGS_ERROR == c)
                    594:                        return(0);
                    595:                else if (ARGS_EOLN == c)
                    596:                        break;
                    597:                assert(mdoc_isdelim(p));
1.28      kristaps  598:                if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
                    599:                        return(0);
1.22      kristaps  600:                mdoc->next = MDOC_NEXT_SIBLING;
                    601:        }
                    602:
                    603:        return(1);
                    604: }
                    605:
                    606:
1.44      kristaps  607: /*
                    608:  * Close out an explicit scope.  This optionally parses a TAIL type with
                    609:  * a set number of TEXT children.
                    610:  */
1.51    ! kristaps  611: static int
1.35      kristaps  612: macro_scoped_close(MACRO_PROT_ARGS)
1.19      kristaps  613: {
1.28      kristaps  614:        int              tt, j, c, lastarg, maxargs, flushed;
1.22      kristaps  615:        char            *p;
1.19      kristaps  616:
                    617:        switch (tok) {
1.22      kristaps  618:        case (MDOC_Ec):
                    619:                maxargs = 1;
                    620:                break;
                    621:        default:
                    622:                maxargs = 0;
                    623:                break;
                    624:        }
                    625:
1.35      kristaps  626:        tt = rewind_alt(tok);
                    627:
1.41      kristaps  628:        mdoc_msg(mdoc, "parse: %s closing %s",
1.36      kristaps  629:                        mdoc_macronames[tok], mdoc_macronames[tt]);
                    630:
1.22      kristaps  631:        if ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags)) {
1.35      kristaps  632:                if (0 == buf[*pos]) {
1.51    ! kristaps  633:                        if ( ! rewind_subblock(MDOC_BODY, mdoc,
        !           634:                                                tok, line, ppos))
1.35      kristaps  635:                                return(0);
1.38      kristaps  636:                        return(rewind_expblock(mdoc, tok, line, ppos));
1.35      kristaps  637:                }
1.49      kristaps  638:                return(perr(mdoc, line, ppos, ENOPARMS));
1.22      kristaps  639:        }
1.19      kristaps  640:
1.41      kristaps  641:        if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.22      kristaps  642:                return(0);
1.19      kristaps  643:
1.22      kristaps  644:        lastarg = ppos;
                    645:        flushed = 0;
1.15      kristaps  646:
1.22      kristaps  647:        if (maxargs > 0) {
1.28      kristaps  648:                if ( ! mdoc_tail_alloc(mdoc, line, ppos, tt))
                    649:                        return(0);
1.22      kristaps  650:                mdoc->next = MDOC_NEXT_CHILD;
                    651:        }
1.15      kristaps  652:
1.41      kristaps  653:        for (j = 0; /* No sentinel. */; j++) {
1.15      kristaps  654:                lastarg = *pos;
1.22      kristaps  655:
                    656:                if (j == maxargs && ! flushed) {
1.38      kristaps  657:                        if ( ! rewind_expblock(mdoc, tok, line, ppos))
1.22      kristaps  658:                                return(0);
                    659:                        flushed = 1;
                    660:                }
                    661:
1.48      kristaps  662:                c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49      kristaps  663:                assert(ARGS_PHRASE != c);
                    664:
1.15      kristaps  665:                if (ARGS_ERROR == c)
                    666:                        return(0);
1.22      kristaps  667:                if (ARGS_PUNCT == c)
                    668:                        break;
                    669:                if (ARGS_EOLN == c)
                    670:                        break;
                    671:
1.30      kristaps  672:                if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
                    673:                        return(0);
                    674:                else if (MDOC_MAX != c) {
1.22      kristaps  675:                        if ( ! flushed) {
1.51    ! kristaps  676:                                if ( ! rewind_expblock(mdoc, tok,
        !           677:                                                        line, ppos))
1.22      kristaps  678:                                        return(0);
                    679:                                flushed = 1;
                    680:                        }
1.26      kristaps  681:                        if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.22      kristaps  682:                                return(0);
1.15      kristaps  683:                        break;
1.30      kristaps  684:                }
1.22      kristaps  685:
1.28      kristaps  686:                if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
                    687:                        return(0);
1.16      kristaps  688:                mdoc->next = MDOC_NEXT_SIBLING;
1.15      kristaps  689:        }
1.2       kristaps  690:
1.38      kristaps  691:        if ( ! flushed && ! rewind_expblock(mdoc, tok, line, ppos))
1.28      kristaps  692:                return(0);
1.22      kristaps  693:
                    694:        if (ppos > 1)
                    695:                return(1);
1.41      kristaps  696:        return(append_delims(mdoc, line, pos, buf));
1.1       kristaps  697: }
                    698:
1.2       kristaps  699:
1.44      kristaps  700: /*
                    701:  * A general text macro.  This is a complex case because of punctuation.
                    702:  * If a text macro is followed by words, then punctuation, the macro is
                    703:  * "stopped" and "reopened" following the punctuation.  Thus, the
                    704:  * following arises:
                    705:  *
                    706:  *    .Fl a ; b
                    707:  *
                    708:  *    ELEMENT (.Fl)
                    709:  *        TEXT (`a')
                    710:  *    TEXT (`;')
                    711:  *    ELEMENT (.Fl)
                    712:  *        TEXT (`b')
                    713:  *
                    714:  * This must handle the following situations:
                    715:  *
                    716:  *    .Fl Ar b ; ;
                    717:  *
                    718:  *    ELEMENT (.Fl)
                    719:  *    ELEMENT (.Ar)
                    720:  *        TEXT (`b')
                    721:  *    TEXT (`;')
                    722:  *    TEXT (`;')
                    723:  */
1.51    ! kristaps  724: static int
1.19      kristaps  725: macro_text(MACRO_PROT_ARGS)
1.13      kristaps  726: {
1.48      kristaps  727:        int               la, lastpunct, c, w, argc;
1.19      kristaps  728:        struct mdoc_arg   argv[MDOC_LINEARG_MAX];
                    729:        char             *p;
1.13      kristaps  730:
1.28      kristaps  731:        la = ppos;
1.19      kristaps  732:        lastpunct = 0;
1.17      kristaps  733:
1.19      kristaps  734:        for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1.28      kristaps  735:                la = *pos;
                    736:                c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38      kristaps  737:                if (ARGV_EOLN == c)
1.19      kristaps  738:                        break;
1.38      kristaps  739:                if (ARGV_WORD == c) {
                    740:                        *pos = la;
                    741:                        break;
                    742:                } else if (ARGV_ARG == c)
1.19      kristaps  743:                        continue;
1.38      kristaps  744:
1.19      kristaps  745:                mdoc_argv_free(argc, argv);
1.14      kristaps  746:                return(0);
1.10      kristaps  747:        }
                    748:
1.28      kristaps  749:        if (MDOC_LINEARG_MAX == argc) {
1.41      kristaps  750:                mdoc_argv_free(argc - 1, argv);
1.49      kristaps  751:                return(perr(mdoc, line, ppos, EARGVLIM));
1.28      kristaps  752:        }
                    753:
1.40      kristaps  754:        c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
1.28      kristaps  755:
                    756:        if (0 == c) {
1.19      kristaps  757:                mdoc_argv_free(argc, argv);
                    758:                return(0);
1.7       kristaps  759:        }
                    760:
1.28      kristaps  761:        mdoc->next = MDOC_NEXT_CHILD;
                    762:
1.41      kristaps  763:        lastpunct = 0;
                    764:        for (;;) {
1.28      kristaps  765:                la = *pos;
1.48      kristaps  766:                w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49      kristaps  767:                assert(ARGS_PHRASE != c);
                    768:
1.45      kristaps  769:                if (ARGS_ERROR == w) {
1.19      kristaps  770:                        mdoc_argv_free(argc, argv);
1.7       kristaps  771:                        return(0);
1.19      kristaps  772:                }
                    773:
1.45      kristaps  774:                if (ARGS_EOLN == w)
1.19      kristaps  775:                        break;
1.45      kristaps  776:                if (ARGS_PUNCT == w)
1.19      kristaps  777:                        break;
1.2       kristaps  778:
1.45      kristaps  779:                c = ARGS_QWORD == w ? MDOC_MAX :
                    780:                        lookup(mdoc, line, la, tok, p);
                    781:
                    782:                if (MDOC_MAX != c && -1 != c) {
1.36      kristaps  783:                        if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
1.19      kristaps  784:                                mdoc_argv_free(argc, argv);
                    785:                                return(0);
                    786:                        }
                    787:                        mdoc_argv_free(argc, argv);
1.28      kristaps  788:                        c = mdoc_macro(mdoc, c, line, la, pos, buf);
                    789:                        if (0 == c)
1.19      kristaps  790:                                return(0);
                    791:                        if (ppos > 1)
                    792:                                return(1);
1.41      kristaps  793:                        return(append_delims(mdoc, line, pos, buf));
1.45      kristaps  794:                } else if (-1 == c) {
                    795:                        mdoc_argv_free(argc, argv);
                    796:                        return(0);
1.19      kristaps  797:                }
1.2       kristaps  798:
1.45      kristaps  799:                if (ARGS_QWORD != w && mdoc_isdelim(p)) {
1.36      kristaps  800:                        if (0 == lastpunct && ! rewind_elem(mdoc, tok)) {
1.19      kristaps  801:                                mdoc_argv_free(argc, argv);
                    802:                                return(0);
                    803:                        }
                    804:                        lastpunct = 1;
1.36      kristaps  805:                } else if (lastpunct) {
                    806:                        c = mdoc_elem_alloc(mdoc, line,
1.40      kristaps  807:                                        ppos, tok, argc, argv);
1.36      kristaps  808:                        if (0 == c) {
                    809:                                mdoc_argv_free(argc, argv);
                    810:                                return(0);
                    811:                        }
                    812:                        mdoc->next = MDOC_NEXT_CHILD;
                    813:                        lastpunct = 0;
1.19      kristaps  814:                }
1.36      kristaps  815:
1.28      kristaps  816:                if ( ! mdoc_word_alloc(mdoc, line, la, p))
                    817:                        return(0);
1.19      kristaps  818:                mdoc->next = MDOC_NEXT_SIBLING;
1.2       kristaps  819:        }
                    820:
1.19      kristaps  821:        mdoc_argv_free(argc, argv);
1.2       kristaps  822:
1.36      kristaps  823:        if (0 == lastpunct && ! rewind_elem(mdoc, tok))
1.7       kristaps  824:                return(0);
1.19      kristaps  825:        if (ppos > 1)
                    826:                return(1);
1.41      kristaps  827:        return(append_delims(mdoc, line, pos, buf));
1.5       kristaps  828: }
                    829:
                    830:
1.44      kristaps  831: /*
                    832:  * Handle explicit-scope (having a different closure token) and implicit
                    833:  * scope (closing out prior scopes when re-invoked) macros.  These
                    834:  * constitute the BLOCK type and usually span multiple lines.  These
                    835:  * always have HEAD and sometimes have BODY types.  In the multi-line
                    836:  * case:
                    837:  *
                    838:  *     .Bd -ragged
                    839:  *     Text.
                    840:  *     .Fl macro
                    841:  *     Another.
                    842:  *     .Ed
                    843:  *
                    844:  *     BLOCK (.Bd)
                    845:  *         HEAD
                    846:  *         BODY
                    847:  *             TEXT (`Text.')
                    848:  *             ELEMENT (.Fl)
                    849:  *                 TEXT (`macro')
                    850:  *             TEXT (`Another.')
                    851:  *
                    852:  * Note that the `.It' macro, possibly the most difficult (as it has
                    853:  * embedded scope, etc.) is handled by this routine.
                    854:  */
1.51    ! kristaps  855: static int
1.16      kristaps  856: macro_scoped(MACRO_PROT_ARGS)
1.6       kristaps  857: {
1.48      kristaps  858:        int               c, lastarg, argc;
1.6       kristaps  859:        struct mdoc_arg   argv[MDOC_LINEARG_MAX];
1.24      kristaps  860:        char             *p;
1.6       kristaps  861:
1.16      kristaps  862:        assert ( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.6       kristaps  863:
1.47      kristaps  864:        /* First rewind extant implicit scope. */
                    865:
1.35      kristaps  866:        if ( ! (MDOC_EXPLICIT & mdoc_macros[tok].flags)) {
1.41      kristaps  867:                if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35      kristaps  868:                        return(0);
1.38      kristaps  869:                if ( ! rewind_impblock(mdoc, tok, line, ppos))
1.16      kristaps  870:                        return(0);
1.35      kristaps  871:        }
1.2       kristaps  872:
1.47      kristaps  873:        /* Parse arguments. */
                    874:
1.16      kristaps  875:        for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
                    876:                lastarg = *pos;
1.28      kristaps  877:                c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38      kristaps  878:                if (ARGV_EOLN == c)
                    879:                        break;
                    880:                if (ARGV_WORD == c) {
                    881:                        *pos = lastarg;
1.16      kristaps  882:                        break;
1.38      kristaps  883:                } else if (ARGV_ARG == c)
1.16      kristaps  884:                        continue;
                    885:                mdoc_argv_free(argc, argv);
1.8       kristaps  886:                return(0);
1.16      kristaps  887:        }
1.2       kristaps  888:
1.28      kristaps  889:        if (MDOC_LINEARG_MAX == argc) {
1.41      kristaps  890:                mdoc_argv_free(argc - 1, argv);
1.49      kristaps  891:                return(perr(mdoc, line, ppos, EARGVLIM));
1.28      kristaps  892:        }
                    893:
                    894:        c = mdoc_block_alloc(mdoc, line, ppos,
                    895:                        tok, (size_t)argc, argv);
                    896:        mdoc_argv_free(argc, argv);
                    897:
                    898:        if (0 == c)
1.16      kristaps  899:                return(0);
1.8       kristaps  900:
1.19      kristaps  901:        mdoc->next = MDOC_NEXT_CHILD;
                    902:
1.24      kristaps  903:        if (0 == buf[*pos]) {
1.28      kristaps  904:                if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
                    905:                        return(0);
1.51    ! kristaps  906:                if ( ! rewind_subblock(MDOC_HEAD, mdoc,
        !           907:                                        tok, line, ppos))
1.28      kristaps  908:                        return(0);
                    909:                if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25      kristaps  910:                        return(0);
1.19      kristaps  911:                mdoc->next = MDOC_NEXT_CHILD;
1.24      kristaps  912:                return(1);
                    913:        }
1.19      kristaps  914:
1.28      kristaps  915:        if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
                    916:                return(0);
1.24      kristaps  917:        mdoc->next = MDOC_NEXT_CHILD;
1.7       kristaps  918:
1.41      kristaps  919:        for (;;) {
1.24      kristaps  920:                lastarg = *pos;
1.48      kristaps  921:                c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49      kristaps  922:
1.24      kristaps  923:                if (ARGS_ERROR == c)
1.19      kristaps  924:                        return(0);
1.24      kristaps  925:                if (ARGS_PUNCT == c)
                    926:                        break;
                    927:                if (ARGS_EOLN == c)
                    928:                        break;
1.48      kristaps  929:
1.49      kristaps  930:                if (ARGS_PHRASE == c) {
                    931:                        /*
                    932:                        if ( ! mdoc_phrase(mdoc, line, lastarg, buf))
                    933:                                return(0);
                    934:                        */
                    935:                        continue;
                    936:                }
                    937:
1.48      kristaps  938:                /* FIXME: if .It -column, the lookup must be for a
                    939:                 * sub-line component.  BLAH. */
1.24      kristaps  940:
1.30      kristaps  941:                if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
                    942:                        return(0);
1.48      kristaps  943:
                    944:                if (MDOC_MAX == c) {
1.28      kristaps  945:                        if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
                    946:                                return(0);
1.24      kristaps  947:                        mdoc->next = MDOC_NEXT_SIBLING;
                    948:                        continue;
1.30      kristaps  949:                }
1.2       kristaps  950:
1.26      kristaps  951:                if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.24      kristaps  952:                        return(0);
                    953:                break;
1.7       kristaps  954:        }
1.48      kristaps  955:
1.41      kristaps  956:        if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.24      kristaps  957:                return(0);
1.41      kristaps  958:        if (1 == ppos && ! append_delims(mdoc, line, pos, buf))
1.24      kristaps  959:                return(0);
                    960:
1.28      kristaps  961:        if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
                    962:                return(0);
1.16      kristaps  963:        mdoc->next = MDOC_NEXT_CHILD;
1.8       kristaps  964:
1.16      kristaps  965:        return(1);
1.1       kristaps  966: }
1.5       kristaps  967:
1.7       kristaps  968:
1.44      kristaps  969: /*
                    970:  * This handles a case of implicitly-scoped macro (BLOCK) limited to a
                    971:  * single line.  Instead of being closed out by a subsequent call to
                    972:  * another macro, the scope is closed at the end of line.  These don't
                    973:  * have BODY or TAIL types.  Notice that the punctuation falls outside
                    974:  * of the HEAD type.
                    975:  *
                    976:  *     .Qq a Fl b Ar d ; ;
                    977:  *
                    978:  *     BLOCK (Qq)
                    979:  *         HEAD
                    980:  *             TEXT (`a')
                    981:  *             ELEMENT (.Fl)
                    982:  *                 TEXT (`b')
                    983:  *             ELEMENT (.Ar)
                    984:  *                 TEXT (`d')
                    985:  *         TEXT (`;')
                    986:  *         TEXT (`;')
                    987:  */
1.51    ! kristaps  988: static int
1.16      kristaps  989: macro_scoped_line(MACRO_PROT_ARGS)
1.7       kristaps  990: {
1.41      kristaps  991:        int               lastarg, c;
1.8       kristaps  992:        char              *p;
1.7       kristaps  993:
1.28      kristaps  994:        if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
                    995:                return(0);
1.16      kristaps  996:        mdoc->next = MDOC_NEXT_CHILD;
1.8       kristaps  997:
1.28      kristaps  998:        if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
                    999:                return(0);
1.44      kristaps 1000:        mdoc->next = MDOC_NEXT_SIBLING;
                   1001:        if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
                   1002:                return(0);
1.16      kristaps 1003:        mdoc->next = MDOC_NEXT_CHILD;
1.8       kristaps 1004:
1.19      kristaps 1005:        /* XXX - no known argument macros. */
                   1006:
1.41      kristaps 1007:        lastarg = ppos;
                   1008:        for (;;) {
1.19      kristaps 1009:                lastarg = *pos;
1.48      kristaps 1010:                c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49      kristaps 1011:                assert(ARGS_PHRASE != c);
1.8       kristaps 1012:
1.19      kristaps 1013:                if (ARGS_ERROR == c)
                   1014:                        return(0);
                   1015:                if (ARGS_PUNCT == c)
                   1016:                        break;
                   1017:                if (ARGS_EOLN == c)
                   1018:                        break;
1.8       kristaps 1019:
1.30      kristaps 1020:                if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
                   1021:                        return(0);
                   1022:                else if (MDOC_MAX == c) {
1.28      kristaps 1023:                        if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
                   1024:                                return(0);
1.19      kristaps 1025:                        mdoc->next = MDOC_NEXT_SIBLING;
                   1026:                        continue;
1.30      kristaps 1027:                }
1.8       kristaps 1028:
1.26      kristaps 1029:                if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19      kristaps 1030:                        return(0);
1.8       kristaps 1031:                break;
                   1032:        }
                   1033:
1.19      kristaps 1034:        if (1 == ppos) {
1.44      kristaps 1035:                if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.16      kristaps 1036:                        return(0);
1.41      kristaps 1037:                if ( ! append_delims(mdoc, line, pos, buf))
1.8       kristaps 1038:                        return(0);
1.44      kristaps 1039:        } else if ( ! rewind_subblock(MDOC_BODY, mdoc, tok, line, ppos))
1.35      kristaps 1040:                return(0);
1.38      kristaps 1041:        return(rewind_impblock(mdoc, tok, line, ppos));
1.22      kristaps 1042: }
                   1043:
                   1044:
1.44      kristaps 1045: /*
                   1046:  * A constant-scoped macro is like a simple-scoped macro (mdoc_scoped)
                   1047:  * except that it doesn't handle implicit scopes and explicit ones have
                   1048:  * a fixed number of TEXT children to the BODY.
                   1049:  *
                   1050:  *     .Fl a So b Sc ;
                   1051:  *
                   1052:  *     ELEMENT (.Fl)
                   1053:  *         TEXT (`a')
                   1054:  *     BLOCK (.So)
                   1055:  *         HEAD
                   1056:  *         BODY
                   1057:  *             TEXT (`b')
                   1058:  *     TEXT (';')
                   1059:  */
1.51    ! kristaps 1060: static int
1.22      kristaps 1061: macro_constant_scoped(MACRO_PROT_ARGS)
                   1062: {
                   1063:        int               lastarg, flushed, j, c, maxargs;
                   1064:        char             *p;
                   1065:
                   1066:        lastarg = ppos;
                   1067:        flushed = 0;
                   1068:
                   1069:        switch (tok) {
                   1070:        case (MDOC_Eo):
                   1071:                maxargs = 1;
                   1072:                break;
                   1073:        default:
                   1074:                maxargs = 0;
                   1075:                break;
                   1076:        }
                   1077:
1.28      kristaps 1078:        if ( ! mdoc_block_alloc(mdoc, line, ppos, tok, 0, NULL))
                   1079:                return(0);
1.22      kristaps 1080:        mdoc->next = MDOC_NEXT_CHILD;
                   1081:
                   1082:        if (0 == maxargs) {
1.28      kristaps 1083:                if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
                   1084:                        return(0);
1.41      kristaps 1085:                if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28      kristaps 1086:                        return(0);
                   1087:                if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.25      kristaps 1088:                        return(0);
1.22      kristaps 1089:                flushed = 1;
1.28      kristaps 1090:        } else if ( ! mdoc_head_alloc(mdoc, line, ppos, tok))
                   1091:                return(0);
1.22      kristaps 1092:
                   1093:        mdoc->next = MDOC_NEXT_CHILD;
                   1094:
1.41      kristaps 1095:        for (j = 0; /* No sentinel. */; j++) {
1.22      kristaps 1096:                lastarg = *pos;
                   1097:
                   1098:                if (j == maxargs && ! flushed) {
1.41      kristaps 1099:                        if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.22      kristaps 1100:                                return(0);
                   1101:                        flushed = 1;
1.28      kristaps 1102:                        if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
                   1103:                                return(0);
1.22      kristaps 1104:                        mdoc->next = MDOC_NEXT_CHILD;
                   1105:                }
                   1106:
1.48      kristaps 1107:                c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49      kristaps 1108:                assert(ARGS_PHRASE != c);
                   1109:
1.22      kristaps 1110:                if (ARGS_ERROR == c)
                   1111:                        return(0);
                   1112:                if (ARGS_PUNCT == c)
                   1113:                        break;
                   1114:                if (ARGS_EOLN == c)
                   1115:                        break;
                   1116:
1.30      kristaps 1117:                if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
                   1118:                        return(0);
                   1119:                else if (MDOC_MAX != c) {
1.22      kristaps 1120:                        if ( ! flushed) {
1.51    ! kristaps 1121:                                if ( ! rewind_subblock(MDOC_HEAD, mdoc,
        !          1122:                                                        tok, line, ppos))
1.22      kristaps 1123:                                        return(0);
                   1124:                                flushed = 1;
1.51    ! kristaps 1125:                                if ( ! mdoc_body_alloc(mdoc, line,
        !          1126:                                                        ppos, tok))
1.28      kristaps 1127:                                        return(0);
1.22      kristaps 1128:                                mdoc->next = MDOC_NEXT_CHILD;
                   1129:                        }
1.51    ! kristaps 1130:                        if ( ! mdoc_macro(mdoc, c, line, lastarg,
        !          1131:                                                pos, buf))
1.22      kristaps 1132:                                return(0);
                   1133:                        break;
                   1134:                }
                   1135:
                   1136:                if ( ! flushed && mdoc_isdelim(p)) {
1.51    ! kristaps 1137:                        if ( ! rewind_subblock(MDOC_HEAD, mdoc,
        !          1138:                                                tok, line, ppos))
1.22      kristaps 1139:                                return(0);
                   1140:                        flushed = 1;
1.28      kristaps 1141:                        if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
                   1142:                                return(0);
1.22      kristaps 1143:                        mdoc->next = MDOC_NEXT_CHILD;
                   1144:                }
                   1145:
1.28      kristaps 1146:                if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
                   1147:                        return(0);
1.22      kristaps 1148:                mdoc->next = MDOC_NEXT_SIBLING;
                   1149:        }
                   1150:
                   1151:        if ( ! flushed) {
1.41      kristaps 1152:                if ( ! rewind_subblock(MDOC_HEAD, mdoc, tok, line, ppos))
1.28      kristaps 1153:                        return(0);
                   1154:                if ( ! mdoc_body_alloc(mdoc, line, ppos, tok))
1.22      kristaps 1155:                        return(0);
                   1156:                mdoc->next = MDOC_NEXT_CHILD;
                   1157:        }
                   1158:
                   1159:        if (ppos > 1)
                   1160:                return(1);
1.41      kristaps 1161:        return(append_delims(mdoc, line, pos, buf));
1.7       kristaps 1162: }
1.8       kristaps 1163:
1.10      kristaps 1164:
1.44      kristaps 1165: /*
                   1166:  * A delimited constant is very similar to the macros parsed by
                   1167:  * macro_text except that, in the event of punctuation, the macro isn't
                   1168:  * "re-opened" as it is in macro_text.  Also, these macros have a fixed
                   1169:  * number of parameters.
                   1170:  *
                   1171:  *    .Fl a No b
                   1172:  *
                   1173:  *    ELEMENT (.Fl)
                   1174:  *        TEXT (`a')
                   1175:  *    ELEMENT (.No)
                   1176:  *    TEXT (`b')
                   1177:  */
1.51    ! kristaps 1178: static int
1.10      kristaps 1179: macro_constant_delimited(MACRO_PROT_ARGS)
                   1180: {
1.50      kristaps 1181:        int               lastarg, flushed, j, c, maxargs, argc,
                   1182:                          igndelim;
1.24      kristaps 1183:        struct mdoc_arg   argv[MDOC_LINEARG_MAX];
1.13      kristaps 1184:        char             *p;
1.10      kristaps 1185:
                   1186:        lastarg = ppos;
                   1187:        flushed = 0;
                   1188:
                   1189:        switch (tok) {
1.16      kristaps 1190:        case (MDOC_No):
                   1191:                /* FALLTHROUGH */
                   1192:        case (MDOC_Ns):
                   1193:                /* FALLTHROUGH */
1.10      kristaps 1194:        case (MDOC_Ux):
1.24      kristaps 1195:                /* FALLTHROUGH */
                   1196:        case (MDOC_St):
1.10      kristaps 1197:                maxargs = 0;
                   1198:                break;
                   1199:        default:
                   1200:                maxargs = 1;
                   1201:                break;
                   1202:        }
                   1203:
1.50      kristaps 1204:        switch (tok) {
                   1205:        case (MDOC_Pf):
                   1206:                igndelim = 1;
                   1207:                break;
                   1208:        default:
                   1209:                igndelim = 0;
                   1210:                break;
                   1211:        }
                   1212:
1.24      kristaps 1213:        for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
                   1214:                lastarg = *pos;
1.28      kristaps 1215:                c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.38      kristaps 1216:                if (ARGV_EOLN == c)
1.24      kristaps 1217:                        break;
1.38      kristaps 1218:                if (ARGV_WORD == c) {
                   1219:                        *pos = lastarg;
                   1220:                        break;
                   1221:                } else if (ARGV_ARG == c)
1.24      kristaps 1222:                        continue;
                   1223:                mdoc_argv_free(argc, argv);
                   1224:                return(0);
                   1225:        }
                   1226:
1.41      kristaps 1227:        if (MDOC_LINEARG_MAX == argc) {
                   1228:                mdoc_argv_free(argc - 1, argv);
1.49      kristaps 1229:                return(perr(mdoc, line, ppos, EARGVLIM));
1.41      kristaps 1230:        }
                   1231:
1.40      kristaps 1232:        c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
1.28      kristaps 1233:        mdoc_argv_free(argc, argv);
                   1234:
                   1235:        if (0 == c)
1.24      kristaps 1236:                return(0);
                   1237:
1.19      kristaps 1238:        mdoc->next = MDOC_NEXT_CHILD;
1.10      kristaps 1239:
1.41      kristaps 1240:        for (j = 0; /* No sentinel. */; j++) {
1.19      kristaps 1241:                lastarg = *pos;
1.10      kristaps 1242:
1.19      kristaps 1243:                if (j == maxargs && ! flushed) {
1.28      kristaps 1244:                        if ( ! rewind_elem(mdoc, tok))
1.19      kristaps 1245:                                return(0);
                   1246:                        flushed = 1;
                   1247:                }
1.11      kristaps 1248:
1.48      kristaps 1249:                c = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49      kristaps 1250:                assert(ARGS_PHRASE != c);
                   1251:
1.19      kristaps 1252:                if (ARGS_ERROR == c)
1.10      kristaps 1253:                        return(0);
1.19      kristaps 1254:                if (ARGS_PUNCT == c)
                   1255:                        break;
                   1256:                if (ARGS_EOLN == c)
                   1257:                        break;
                   1258:
1.30      kristaps 1259:                if (-1 == (c = lookup(mdoc, line, lastarg, tok, p)))
                   1260:                        return(0);
                   1261:                else if (MDOC_MAX != c) {
1.28      kristaps 1262:                        if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19      kristaps 1263:                                return(0);
                   1264:                        flushed = 1;
1.26      kristaps 1265:                        if ( ! mdoc_macro(mdoc, c, line, lastarg, pos, buf))
1.19      kristaps 1266:                                return(0);
                   1267:                        break;
                   1268:                }
1.10      kristaps 1269:
1.50      kristaps 1270:                if ( ! flushed && mdoc_isdelim(p) && ! igndelim) {
1.28      kristaps 1271:                        if ( ! rewind_elem(mdoc, tok))
1.19      kristaps 1272:                                return(0);
                   1273:                        flushed = 1;
                   1274:                }
                   1275:
1.28      kristaps 1276:                if ( ! mdoc_word_alloc(mdoc, line, lastarg, p))
                   1277:                        return(0);
1.19      kristaps 1278:                mdoc->next = MDOC_NEXT_SIBLING;
1.10      kristaps 1279:        }
                   1280:
1.42      kristaps 1281:        if ( ! flushed && ! rewind_elem(mdoc, tok))
1.19      kristaps 1282:                return(0);
1.11      kristaps 1283:
1.19      kristaps 1284:        if (ppos > 1)
                   1285:                return(1);
1.41      kristaps 1286:        return(append_delims(mdoc, line, pos, buf));
1.10      kristaps 1287: }
1.11      kristaps 1288:
                   1289:
1.44      kristaps 1290: /*
                   1291:  * A constant macro is the simplest classification.  It spans an entire
                   1292:  * line.
                   1293:  */
1.51    ! kristaps 1294: static int
1.11      kristaps 1295: macro_constant(MACRO_PROT_ARGS)
                   1296: {
1.48      kristaps 1297:        int               c, w, la, argc;
1.43      kristaps 1298:        struct mdoc_arg   argv[MDOC_LINEARG_MAX];
                   1299:        char             *p;
1.44      kristaps 1300:
                   1301:        assert( ! (MDOC_CALLABLE & mdoc_macros[tok].flags));
1.11      kristaps 1302:
1.16      kristaps 1303:        for (argc = 0; argc < MDOC_LINEARG_MAX; argc++) {
1.45      kristaps 1304:                la = *pos;
1.28      kristaps 1305:                c = mdoc_argv(mdoc, line, tok, &argv[argc], pos, buf);
1.16      kristaps 1306:                if (ARGV_EOLN == c)
                   1307:                        break;
1.38      kristaps 1308:                if (ARGV_WORD == c) {
1.45      kristaps 1309:                        *pos = la;
1.38      kristaps 1310:                        break;
                   1311:                } else if (ARGV_ARG == c)
1.16      kristaps 1312:                        continue;
1.11      kristaps 1313:
1.16      kristaps 1314:                mdoc_argv_free(argc, argv);
1.11      kristaps 1315:                return(0);
                   1316:        }
                   1317:
1.41      kristaps 1318:        if (MDOC_LINEARG_MAX == argc) {
                   1319:                mdoc_argv_free(argc - 1, argv);
1.49      kristaps 1320:                return(perr(mdoc, line, ppos, EARGVLIM));
1.41      kristaps 1321:        }
                   1322:
1.28      kristaps 1323:        c = mdoc_elem_alloc(mdoc, line, ppos, tok, argc, argv);
                   1324:        mdoc_argv_free(argc, argv);
                   1325:
                   1326:        if (0 == c)
                   1327:                return(0);
1.11      kristaps 1328:
1.19      kristaps 1329:        mdoc->next = MDOC_NEXT_CHILD;
                   1330:
1.41      kristaps 1331:        for (;;) {
1.45      kristaps 1332:                la = *pos;
1.48      kristaps 1333:                w = mdoc_args(mdoc, line, pos, buf, tok, &p);
1.49      kristaps 1334:                assert(ARGS_PHRASE != c);
                   1335:
1.45      kristaps 1336:                if (ARGS_ERROR == w)
1.16      kristaps 1337:                        return(0);
1.45      kristaps 1338:                if (ARGS_EOLN == w)
1.13      kristaps 1339:                        break;
1.19      kristaps 1340:
1.45      kristaps 1341:                c = ARGS_QWORD == w ? MDOC_MAX :
                   1342:                        lookup(mdoc, line, la, tok, p);
                   1343:
                   1344:                if (MDOC_MAX != c && -1 != c) {
1.39      kristaps 1345:                        if ( ! rewind_elem(mdoc, tok))
                   1346:                                return(0);
1.45      kristaps 1347:                        return(mdoc_macro(mdoc, c, line, la, pos, buf));
                   1348:                } else if (-1 == c)
                   1349:                        return(0);
1.39      kristaps 1350:
1.45      kristaps 1351:                if ( ! mdoc_word_alloc(mdoc, line, la, p))
1.28      kristaps 1352:                        return(0);
1.21      kristaps 1353:                mdoc->next = MDOC_NEXT_SIBLING;
1.13      kristaps 1354:        }
                   1355:
1.44      kristaps 1356:        return(rewind_elem(mdoc, tok));
1.13      kristaps 1357: }
1.15      kristaps 1358:
                   1359:
1.16      kristaps 1360: /* ARGSUSED */
1.51    ! kristaps 1361: static int
1.15      kristaps 1362: macro_obsolete(MACRO_PROT_ARGS)
                   1363: {
                   1364:
1.49      kristaps 1365:        return(pwarn(mdoc, line, ppos, WOBS));
1.15      kristaps 1366: }
1.25      kristaps 1367:
                   1368:
1.44      kristaps 1369: /*
                   1370:  * This is called at the end of parsing.  It must traverse up the tree,
                   1371:  * closing out open [implicit] scopes.  Obviously, open explicit scopes
                   1372:  * are errors.
                   1373:  */
1.25      kristaps 1374: int
                   1375: macro_end(struct mdoc *mdoc)
                   1376: {
1.42      kristaps 1377:        struct mdoc_node *n;
1.25      kristaps 1378:
                   1379:        assert(mdoc->first);
                   1380:        assert(mdoc->last);
1.42      kristaps 1381:
                   1382:        /* Scan for open explicit scopes. */
                   1383:
                   1384:        n = MDOC_VALID & mdoc->last->flags ?
                   1385:                mdoc->last->parent : mdoc->last;
                   1386:
                   1387:        for ( ; n; n = n->parent) {
                   1388:                if (MDOC_BLOCK != n->type)
                   1389:                        continue;
                   1390:                if ( ! (MDOC_EXPLICIT & mdoc_macros[n->tok].flags))
                   1391:                        continue;
1.51    ! kristaps 1392:                return(mdoc_nerr(mdoc, n,
        !          1393:                                "macro scope still open on exit"));
1.42      kristaps 1394:        }
                   1395:
1.41      kristaps 1396:        return(rewind_last(mdoc, mdoc->first));
1.25      kristaps 1397: }

CVSweb