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

Annotation of mandoc/macro.c, Revision 1.52

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

CVSweb