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

Annotation of mandoc/mdoc_argv.c, Revision 1.1

1.1     ! kristaps    1: /* $Id: argv.c,v 1.57 2009/03/23 14:31:58 kristaps Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the
        !             7:  * above copyright notice and this permission notice appear in all
        !             8:  * copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
        !            11:  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
        !            12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
        !            13:  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
        !            14:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
        !            15:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
        !            16:  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
        !            17:  * PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19: #include <sys/types.h>
        !            20:
        !            21: #include <assert.h>
        !            22: #include <ctype.h>
        !            23: #include <err.h>
        !            24: #include <stdlib.h>
        !            25: #include <stdio.h>
        !            26: #include <string.h>
        !            27:
        !            28: #include "libmdoc.h"
        !            29:
        !            30: /*
        !            31:  * Routines to parse arguments of macros.  Arguments follow the syntax
        !            32:  * of `-arg [val [valN...]]'.  Arguments come in all types:  quoted
        !            33:  * arguments, multiple arguments per value, no-value arguments, etc.
        !            34:  *
        !            35:  * There's no limit to the number or arguments that may be allocated.
        !            36:  */
        !            37:
        !            38: #define        ARGS_QUOTED     (1 << 0)
        !            39: #define        ARGS_DELIM      (1 << 1)
        !            40: #define        ARGS_TABSEP     (1 << 2)
        !            41: #define        ARGS_ARGVLIKE   (1 << 3)
        !            42:
        !            43: #define        ARGV_NONE       (1 << 0)
        !            44: #define        ARGV_SINGLE     (1 << 1)
        !            45: #define        ARGV_MULTI      (1 << 2)
        !            46: #define        ARGV_OPT_SINGLE (1 << 3)
        !            47:
        !            48: #define        MULTI_STEP       5
        !            49:
        !            50: enum   mwarn {
        !            51:        WQUOTPARM,
        !            52:        WARGVPARM,
        !            53:        WCOLEMPTY,
        !            54:        WTAILWS
        !            55: };
        !            56:
        !            57: enum   merr {
        !            58:        EQUOTTERM,
        !            59:        EARGVAL
        !            60: };
        !            61:
        !            62: static int              argv_a2arg(int, const char *);
        !            63: static int              args(struct mdoc *, int, int *,
        !            64:                                char *, int, char **);
        !            65: static int              argv(struct mdoc *, int,
        !            66:                                struct mdoc_argv *, int *, char *);
        !            67: static int              argv_single(struct mdoc *, int,
        !            68:                                struct mdoc_argv *, int *, char *);
        !            69: static int              argv_opt_single(struct mdoc *, int,
        !            70:                                struct mdoc_argv *, int *, char *);
        !            71: static int              argv_multi(struct mdoc *, int,
        !            72:                                struct mdoc_argv *, int *, char *);
        !            73: static int              pwarn(struct mdoc *, int, int, enum mwarn);
        !            74: static int              perr(struct mdoc *, int, int, enum merr);
        !            75:
        !            76: /* Per-argument flags. */
        !            77:
        !            78: static int mdoc_argvflags[MDOC_ARG_MAX] = {
        !            79:        ARGV_NONE,      /* MDOC_Split */
        !            80:        ARGV_NONE,      /* MDOC_Nosplit */
        !            81:        ARGV_NONE,      /* MDOC_Ragged */
        !            82:        ARGV_NONE,      /* MDOC_Unfilled */
        !            83:        ARGV_NONE,      /* MDOC_Literal */
        !            84:        ARGV_NONE,      /* MDOC_File */
        !            85:        ARGV_SINGLE,    /* MDOC_Offset */
        !            86:        ARGV_NONE,      /* MDOC_Bullet */
        !            87:        ARGV_NONE,      /* MDOC_Dash */
        !            88:        ARGV_NONE,      /* MDOC_Hyphen */
        !            89:        ARGV_NONE,      /* MDOC_Item */
        !            90:        ARGV_NONE,      /* MDOC_Enum */
        !            91:        ARGV_NONE,      /* MDOC_Tag */
        !            92:        ARGV_NONE,      /* MDOC_Diag */
        !            93:        ARGV_NONE,      /* MDOC_Hang */
        !            94:        ARGV_NONE,      /* MDOC_Ohang */
        !            95:        ARGV_NONE,      /* MDOC_Inset */
        !            96:        ARGV_MULTI,     /* MDOC_Column */
        !            97:        ARGV_SINGLE,    /* MDOC_Width */
        !            98:        ARGV_NONE,      /* MDOC_Compact */
        !            99:        ARGV_OPT_SINGLE, /* MDOC_Std */
        !           100:        ARGV_NONE,      /* MDOC_Filled */
        !           101:        ARGV_NONE,      /* MDOC_Words */
        !           102:        ARGV_NONE,      /* MDOC_Emphasis */
        !           103:        ARGV_NONE,      /* MDOC_Symbolic */
        !           104:        ARGV_NONE       /* MDOC_Symbolic */
        !           105: };
        !           106:
        !           107: static int mdoc_argflags[MDOC_MAX] = {
        !           108:        0, /* \" */
        !           109:        0, /* Dd */
        !           110:        0, /* Dt */
        !           111:        0, /* Os */
        !           112:        ARGS_QUOTED, /* Sh */
        !           113:        ARGS_QUOTED, /* Ss */
        !           114:        ARGS_DELIM, /* Pp */
        !           115:        ARGS_DELIM, /* D1 */
        !           116:        ARGS_DELIM | ARGS_QUOTED, /* Dl */
        !           117:        0, /* Bd */
        !           118:        0, /* Ed */
        !           119:        0, /* Bl */
        !           120:        0, /* El */
        !           121:        0, /* It */
        !           122:        ARGS_DELIM, /* Ad */
        !           123:        ARGS_DELIM, /* An */
        !           124:        ARGS_DELIM | ARGS_QUOTED, /* Ar */
        !           125:        ARGS_QUOTED, /* Cd */
        !           126:        ARGS_DELIM, /* Cm */
        !           127:        ARGS_DELIM, /* Dv */
        !           128:        ARGS_DELIM, /* Er */
        !           129:        ARGS_DELIM, /* Ev */
        !           130:        0, /* Ex */
        !           131:        ARGS_DELIM | ARGS_QUOTED, /* Fa */
        !           132:        0, /* Fd */
        !           133:        ARGS_DELIM, /* Fl */
        !           134:        ARGS_DELIM | ARGS_QUOTED, /* Fn */
        !           135:        ARGS_DELIM | ARGS_QUOTED, /* Ft */
        !           136:        ARGS_DELIM, /* Ic */
        !           137:        0, /* In */
        !           138:        ARGS_DELIM | ARGS_QUOTED, /* Li */
        !           139:        ARGS_QUOTED, /* Nd */
        !           140:        ARGS_DELIM, /* Nm */
        !           141:        ARGS_DELIM, /* Op */
        !           142:        0, /* Ot */
        !           143:        ARGS_DELIM, /* Pa */
        !           144:        0, /* Rv */
        !           145:        ARGS_DELIM | ARGS_ARGVLIKE, /* St */
        !           146:        ARGS_DELIM, /* Va */
        !           147:        ARGS_DELIM, /* Vt */
        !           148:        ARGS_DELIM, /* Xr */
        !           149:        ARGS_QUOTED, /* %A */
        !           150:        ARGS_QUOTED, /* %B */
        !           151:        ARGS_QUOTED, /* %D */
        !           152:        ARGS_QUOTED, /* %I */
        !           153:        ARGS_QUOTED, /* %J */
        !           154:        ARGS_QUOTED, /* %N */
        !           155:        ARGS_QUOTED, /* %O */
        !           156:        ARGS_QUOTED, /* %P */
        !           157:        ARGS_QUOTED, /* %R */
        !           158:        ARGS_QUOTED, /* %T */
        !           159:        ARGS_QUOTED, /* %V */
        !           160:        ARGS_DELIM, /* Ac */
        !           161:        0, /* Ao */
        !           162:        ARGS_DELIM, /* Aq */
        !           163:        ARGS_DELIM, /* At */
        !           164:        ARGS_DELIM, /* Bc */
        !           165:        0, /* Bf */
        !           166:        0, /* Bo */
        !           167:        ARGS_DELIM, /* Bq */
        !           168:        ARGS_DELIM, /* Bsx */
        !           169:        ARGS_DELIM, /* Bx */
        !           170:        0, /* Db */
        !           171:        ARGS_DELIM, /* Dc */
        !           172:        0, /* Do */
        !           173:        ARGS_DELIM, /* Dq */
        !           174:        ARGS_DELIM, /* Ec */
        !           175:        0, /* Ef */
        !           176:        ARGS_DELIM, /* Em */
        !           177:        0, /* Eo */
        !           178:        ARGS_DELIM, /* Fx */
        !           179:        ARGS_DELIM, /* Ms */
        !           180:        ARGS_DELIM, /* No */
        !           181:        ARGS_DELIM, /* Ns */
        !           182:        ARGS_DELIM, /* Nx */
        !           183:        ARGS_DELIM, /* Ox */
        !           184:        ARGS_DELIM, /* Pc */
        !           185:        ARGS_DELIM, /* Pf */
        !           186:        0, /* Po */
        !           187:        ARGS_DELIM, /* Pq */
        !           188:        ARGS_DELIM, /* Qc */
        !           189:        ARGS_DELIM, /* Ql */
        !           190:        0, /* Qo */
        !           191:        ARGS_DELIM, /* Qq */
        !           192:        0, /* Re */
        !           193:        0, /* Rs */
        !           194:        ARGS_DELIM, /* Sc */
        !           195:        0, /* So */
        !           196:        ARGS_DELIM, /* Sq */
        !           197:        0, /* Sm */
        !           198:        ARGS_DELIM, /* Sx */
        !           199:        ARGS_DELIM | ARGS_QUOTED, /* Sy */
        !           200:        ARGS_DELIM, /* Tn */
        !           201:        ARGS_DELIM, /* Ux */
        !           202:        ARGS_DELIM, /* Xc */
        !           203:        0, /* Xo */
        !           204:        ARGS_QUOTED, /* Fo */
        !           205:        0, /* Fc */
        !           206:        0, /* Oo */
        !           207:        ARGS_DELIM, /* Oc */
        !           208:        0, /* Bk */
        !           209:        0, /* Ek */
        !           210:        0, /* Bt */
        !           211:        0, /* Hf */
        !           212:        0, /* Fr */
        !           213:        0, /* Ud */
        !           214:        0, /* Lb */
        !           215:        0, /* Ap */
        !           216:        ARGS_DELIM, /* Lp */
        !           217:        ARGS_DELIM | ARGS_QUOTED, /* Lk */
        !           218:        ARGS_DELIM | ARGS_QUOTED, /* Mt */
        !           219:        ARGS_DELIM, /* Brq */
        !           220:        0, /* Bro */
        !           221:        ARGS_DELIM, /* Brc */
        !           222:        ARGS_QUOTED, /* %C */
        !           223:        0, /* Es */
        !           224:        0, /* En */
        !           225:        0, /* Dx */
        !           226:        ARGS_QUOTED, /* %Q */
        !           227: };
        !           228:
        !           229:
        !           230: /*
        !           231:  * Parse an argument from line text.  This comes in the form of -key
        !           232:  * [value0...], which may either have a single mandatory value, at least
        !           233:  * one mandatory value, an optional single value, or no value.
        !           234:  */
        !           235: int
        !           236: mdoc_argv(struct mdoc *mdoc, int line, int tok,
        !           237:                struct mdoc_arg **v, int *pos, char *buf)
        !           238: {
        !           239:        int               i;
        !           240:        char             *p, sv;
        !           241:        struct mdoc_argv tmp;
        !           242:        struct mdoc_arg  *arg;
        !           243:
        !           244:        if (0 == buf[*pos])
        !           245:                return(ARGV_EOLN);
        !           246:
        !           247:        assert(' ' != buf[*pos]);
        !           248:
        !           249:        if ('-' != buf[*pos] || ARGS_ARGVLIKE & mdoc_argflags[tok])
        !           250:                return(ARGV_WORD);
        !           251:
        !           252:        /* Parse through to the first unescaped space. */
        !           253:
        !           254:        i = *pos;
        !           255:        p = &buf[++(*pos)];
        !           256:
        !           257:        assert(*pos > 0);
        !           258:
        !           259:        /* LINTED */
        !           260:        while (buf[*pos]) {
        !           261:                if (' ' == buf[*pos])
        !           262:                        if ('\\' != buf[*pos - 1])
        !           263:                                break;
        !           264:                (*pos)++;
        !           265:        }
        !           266:
        !           267:        /* XXX - save zeroed byte, if not an argument. */
        !           268:
        !           269:        sv = 0;
        !           270:        if (buf[*pos]) {
        !           271:                sv = buf[*pos];
        !           272:                buf[(*pos)++] = 0;
        !           273:        }
        !           274:
        !           275:        (void)memset(&tmp, 0, sizeof(struct mdoc_argv));
        !           276:        tmp.line = line;
        !           277:        tmp.pos = *pos;
        !           278:
        !           279:        /* See if our token accepts the argument. */
        !           280:
        !           281:        if (MDOC_ARG_MAX == (tmp.arg = argv_a2arg(tok, p))) {
        !           282:                /* XXX - restore saved zeroed byte. */
        !           283:                if (sv)
        !           284:                        buf[*pos - 1] = sv;
        !           285:                if ( ! pwarn(mdoc, line, i, WARGVPARM))
        !           286:                        return(ARGV_ERROR);
        !           287:                return(ARGV_WORD);
        !           288:        }
        !           289:
        !           290:        while (buf[*pos] && ' ' == buf[*pos])
        !           291:                (*pos)++;
        !           292:
        !           293:        if ( ! argv(mdoc, line, &tmp, pos, buf))
        !           294:                return(ARGV_ERROR);
        !           295:
        !           296:        if (NULL == (arg = *v)) {
        !           297:                if (NULL == (*v = calloc(1, sizeof(struct mdoc_arg))))
        !           298:                        err(1, "calloc");
        !           299:                arg = *v;
        !           300:        }
        !           301:
        !           302:        arg->argc++;
        !           303:        arg->argv = xrealloc(arg->argv, arg->argc *
        !           304:                        sizeof(struct mdoc_argv));
        !           305:
        !           306:        (void)memcpy(&arg->argv[(int)arg->argc - 1],
        !           307:                        &tmp, sizeof(struct mdoc_argv));
        !           308:
        !           309:        return(ARGV_ARG);
        !           310: }
        !           311:
        !           312:
        !           313: void
        !           314: mdoc_argv_free(struct mdoc_arg *p)
        !           315: {
        !           316:        int              i, j;
        !           317:
        !           318:        if (NULL == p)
        !           319:                return;
        !           320:
        !           321:        if (p->refcnt) {
        !           322:                --(p->refcnt);
        !           323:                if (p->refcnt)
        !           324:                        return;
        !           325:        }
        !           326:
        !           327:        assert(p->argc);
        !           328:
        !           329:        /* LINTED */
        !           330:        for (i = 0; i < (int)p->argc; i++) {
        !           331:                if (0 == p->argv[i].sz)
        !           332:                        continue;
        !           333:                /* LINTED */
        !           334:                for (j = 0; j < (int)p->argv[i].sz; j++)
        !           335:                        free(p->argv[i].value[j]);
        !           336:
        !           337:                free(p->argv[i].value);
        !           338:        }
        !           339:
        !           340:        free(p->argv);
        !           341:        free(p);
        !           342: }
        !           343:
        !           344:
        !           345:
        !           346: static int
        !           347: perr(struct mdoc *mdoc, int line, int pos, enum merr code)
        !           348: {
        !           349:        char            *p;
        !           350:
        !           351:        p = NULL;
        !           352:
        !           353:        switch (code) {
        !           354:        case (EQUOTTERM):
        !           355:                p = "unterminated quoted parameter";
        !           356:                break;
        !           357:        case (EARGVAL):
        !           358:                p = "argument requires a value";
        !           359:                break;
        !           360:        }
        !           361:
        !           362:        assert(p);
        !           363:        return(mdoc_perr(mdoc, line, pos, p));
        !           364: }
        !           365:
        !           366:
        !           367: static int
        !           368: pwarn(struct mdoc *mdoc, int line, int pos, enum mwarn code)
        !           369: {
        !           370:        char            *p;
        !           371:        int              c;
        !           372:
        !           373:        p = NULL;
        !           374:        c = WARN_SYNTAX;
        !           375:
        !           376:        switch (code) {
        !           377:        case (WQUOTPARM):
        !           378:                p = "unexpected quoted parameter";
        !           379:                break;
        !           380:        case (WARGVPARM):
        !           381:                p = "argument-like parameter";
        !           382:                break;
        !           383:        case (WCOLEMPTY):
        !           384:                p = "last list column is empty";
        !           385:                c = WARN_COMPAT;
        !           386:                break;
        !           387:        case (WTAILWS):
        !           388:                p = "trailing whitespace";
        !           389:                c = WARN_COMPAT;
        !           390:                break;
        !           391:        }
        !           392:
        !           393:        assert(p);
        !           394:        return(mdoc_pwarn(mdoc, line, pos, c, p));
        !           395: }
        !           396:
        !           397:
        !           398: int
        !           399: mdoc_args(struct mdoc *mdoc, int line,
        !           400:                int *pos, char *buf, int tok, char **v)
        !           401: {
        !           402:        int               fl, c, i;
        !           403:        struct mdoc_node *n;
        !           404:
        !           405:        fl = (0 == tok) ? 0 : mdoc_argflags[tok];
        !           406:
        !           407:        /*
        !           408:         * Override per-macro argument flags with context-specific ones.
        !           409:         * As of now, this is only valid for `It' depending on its list
        !           410:         * context.
        !           411:         */
        !           412:
        !           413:        switch (tok) {
        !           414:        case (MDOC_It):
        !           415:                for (n = mdoc->last; n; n = n->parent)
        !           416:                        if (MDOC_BLOCK == n->type && MDOC_Bl == n->tok)
        !           417:                                break;
        !           418:
        !           419:                assert(n);
        !           420:                c = (int)(n->args ? n->args->argc : 0);
        !           421:                assert(c > 0);
        !           422:
        !           423:                /*
        !           424:                 * Using `Bl -column' adds ARGS_TABSEP to the arguments
        !           425:                 * and invalidates ARGS_DELIM.  Using `Bl -diag' allows
        !           426:                 * for quoted arguments.
        !           427:                 */
        !           428:
        !           429:                /* LINTED */
        !           430:                for (i = 0; i < c; i++) {
        !           431:                        switch (n->args->argv[i].arg) {
        !           432:                        case (MDOC_Column):
        !           433:                                fl |= ARGS_TABSEP;
        !           434:                                fl &= ~ARGS_DELIM;
        !           435:                                i = c;
        !           436:                                break;
        !           437:                        case (MDOC_Diag):
        !           438:                                fl |= ARGS_QUOTED;
        !           439:                                i = c;
        !           440:                                break;
        !           441:                        default:
        !           442:                                break;
        !           443:                        }
        !           444:                }
        !           445:                break;
        !           446:        default:
        !           447:                break;
        !           448:        }
        !           449:
        !           450:        return(args(mdoc, line, pos, buf, fl, v));
        !           451: }
        !           452:
        !           453:
        !           454: static int
        !           455: args(struct mdoc *mdoc, int line,
        !           456:                int *pos, char *buf, int fl, char **v)
        !           457: {
        !           458:        int               i;
        !           459:        char             *p, *pp;
        !           460:
        !           461:        assert(*pos > 0);
        !           462:
        !           463:        if (0 == buf[*pos])
        !           464:                return(ARGS_EOLN);
        !           465:
        !           466:        if ('\"' == buf[*pos] && ! (fl & ARGS_QUOTED))
        !           467:                if ( ! pwarn(mdoc, line, *pos, WQUOTPARM))
        !           468:                        return(ARGS_ERROR);
        !           469:
        !           470:        if ( ! (fl & ARGS_ARGVLIKE) && '-' == buf[*pos])
        !           471:                if ( ! pwarn(mdoc, line, *pos, WARGVPARM))
        !           472:                        return(ARGS_ERROR);
        !           473:
        !           474:        /*
        !           475:         * If the first character is a delimiter and we're to look for
        !           476:         * delimited strings, then pass down the buffer seeing if it
        !           477:         * follows the pattern of [[::delim::][ ]+]+.
        !           478:         */
        !           479:
        !           480:        if ((fl & ARGS_DELIM) && mdoc_iscdelim(buf[*pos])) {
        !           481:                for (i = *pos; buf[i]; ) {
        !           482:                        if ( ! mdoc_iscdelim(buf[i]))
        !           483:                                break;
        !           484:                        i++;
        !           485:                        /* There must be at least one space... */
        !           486:                        if (0 == buf[i] || ' ' != buf[i])
        !           487:                                break;
        !           488:                        i++;
        !           489:                        while (buf[i] && ' ' == buf[i])
        !           490:                                i++;
        !           491:                }
        !           492:                if (0 == buf[i]) {
        !           493:                        *v = &buf[*pos];
        !           494:                        return(ARGS_PUNCT);
        !           495:                }
        !           496:        }
        !           497:
        !           498:        /* First parse non-quoted strings. */
        !           499:
        !           500:        if ('\"' != buf[*pos] || ! (ARGS_QUOTED & fl)) {
        !           501:                *v = &buf[*pos];
        !           502:
        !           503:                /*
        !           504:                 * Thar be dragons here!  If we're tab-separated, search
        !           505:                 * ahead for either a tab or the `Ta' macro.
        !           506:                 * If a `Ta' is detected, it must be space-buffered before and
        !           507:                 * after.  If either of these hold true, then prune out the
        !           508:                 * extra spaces and call it an argument.
        !           509:                 */
        !           510:
        !           511:                if (ARGS_TABSEP & fl) {
        !           512:                        /* Scan ahead to unescaped tab. */
        !           513:
        !           514:                        p = strchr(*v, '\t');
        !           515:
        !           516:                        /* Scan ahead to unescaped `Ta'. */
        !           517:
        !           518:                        for (pp = *v; ; pp++) {
        !           519:                                if (NULL == (pp = strstr(pp, "Ta")))
        !           520:                                        break;
        !           521:                                if (pp > *v && ' ' != *(pp - 1))
        !           522:                                        continue;
        !           523:                                if (' ' == *(pp + 2) || 0 == *(pp + 2))
        !           524:                                        break;
        !           525:                        }
        !           526:
        !           527:                        /* Choose delimiter tab/Ta. */
        !           528:
        !           529:                        if (p && pp)
        !           530:                                p = (p < pp ? p : pp);
        !           531:                        else if ( ! p && pp)
        !           532:                                p = pp;
        !           533:
        !           534:                        /* Strip delimiter's preceding whitespace. */
        !           535:
        !           536:                        if (p && p > *v) {
        !           537:                                pp = p - 1;
        !           538:                                while (pp > *v && ' ' == *pp)
        !           539:                                        pp--;
        !           540:                                if (pp == *v && ' ' == *pp)
        !           541:                                        *pp = 0;
        !           542:                                else if (' ' == *pp)
        !           543:                                        *(pp + 1) = 0;
        !           544:                        }
        !           545:
        !           546:                        /* ...in- and proceding whitespace. */
        !           547:
        !           548:                        if (p && ('\t' != *p)) {
        !           549:                                *p++ = 0;
        !           550:                                *p++ = 0;
        !           551:                        } else if (p)
        !           552:                                *p++ = 0;
        !           553:
        !           554:                        if (p) {
        !           555:                                while (' ' == *p)
        !           556:                                        p++;
        !           557:                                if (0 != *p)
        !           558:                                        *(p - 1) = 0;
        !           559:                                *pos += (int)(p - *v);
        !           560:                        }
        !           561:
        !           562:                        if (p && 0 == *p)
        !           563:                                if ( ! pwarn(mdoc, line, *pos, WCOLEMPTY))
        !           564:                                        return(0);
        !           565:                        if (p && 0 == *p && p > *v && ' ' == *(p - 1))
        !           566:                                if ( ! pwarn(mdoc, line, *pos, WTAILWS))
        !           567:                                        return(0);
        !           568:
        !           569:                        if (p)
        !           570:                                return(ARGS_PHRASE);
        !           571:
        !           572:                        /* Configure the eoln case, too. */
        !           573:
        !           574:                        p = strchr(*v, 0);
        !           575:                        assert(p);
        !           576:
        !           577:                        if (p > *v && ' ' == *(p - 1))
        !           578:                                if ( ! pwarn(mdoc, line, *pos, WTAILWS))
        !           579:                                        return(0);
        !           580:                        *pos += (int)(p - *v);
        !           581:
        !           582:                        return(ARGS_PHRASE);
        !           583:                }
        !           584:
        !           585:                /* Do non-tabsep look-ahead here. */
        !           586:
        !           587:                if ( ! (ARGS_TABSEP & fl))
        !           588:                        while (buf[*pos]) {
        !           589:                                if (' ' == buf[*pos])
        !           590:                                        if ('\\' != buf[*pos - 1])
        !           591:                                                break;
        !           592:                                (*pos)++;
        !           593:                        }
        !           594:
        !           595:                if (0 == buf[*pos])
        !           596:                        return(ARGS_WORD);
        !           597:
        !           598:                buf[(*pos)++] = 0;
        !           599:
        !           600:                if (0 == buf[*pos])
        !           601:                        return(ARGS_WORD);
        !           602:
        !           603:                if ( ! (ARGS_TABSEP & fl))
        !           604:                        while (buf[*pos] && ' ' == buf[*pos])
        !           605:                                (*pos)++;
        !           606:
        !           607:                if (buf[*pos])
        !           608:                        return(ARGS_WORD);
        !           609:
        !           610:                if ( ! pwarn(mdoc, line, *pos, WTAILWS))
        !           611:                        return(ARGS_ERROR);
        !           612:
        !           613:                return(ARGS_WORD);
        !           614:        }
        !           615:
        !           616:        /*
        !           617:         * If we're a quoted string (and quoted strings are allowed),
        !           618:         * then parse ahead to the next quote.  If none's found, it's an
        !           619:         * error.  After, parse to the next word.
        !           620:         */
        !           621:
        !           622:        *v = &buf[++(*pos)];
        !           623:
        !           624:        while (buf[*pos] && '\"' != buf[*pos])
        !           625:                (*pos)++;
        !           626:
        !           627:        if (0 == buf[*pos]) {
        !           628:                (void)perr(mdoc, line, *pos, EQUOTTERM);
        !           629:                return(ARGS_ERROR);
        !           630:        }
        !           631:
        !           632:        buf[(*pos)++] = 0;
        !           633:        if (0 == buf[*pos])
        !           634:                return(ARGS_QWORD);
        !           635:
        !           636:        while (buf[*pos] && ' ' == buf[*pos])
        !           637:                (*pos)++;
        !           638:
        !           639:        if (buf[*pos])
        !           640:                return(ARGS_QWORD);
        !           641:
        !           642:        if ( ! pwarn(mdoc, line, *pos, WTAILWS))
        !           643:                return(ARGS_ERROR);
        !           644:
        !           645:        return(ARGS_QWORD);
        !           646: }
        !           647:
        !           648:
        !           649: static int
        !           650: argv_a2arg(int tok, const char *argv)
        !           651: {
        !           652:
        !           653:        /*
        !           654:         * Parse an argument identifier from its text.  XXX - this
        !           655:         * should really be table-driven to clarify the code.
        !           656:         *
        !           657:         * If you add an argument to the list, make sure that you
        !           658:         * register it here with its one or more macros!
        !           659:         */
        !           660:
        !           661:        switch (tok) {
        !           662:        case (MDOC_An):
        !           663:                if (xstrcmp(argv, "split"))
        !           664:                        return(MDOC_Split);
        !           665:                else if (xstrcmp(argv, "nosplit"))
        !           666:                        return(MDOC_Nosplit);
        !           667:                break;
        !           668:
        !           669:        case (MDOC_Bd):
        !           670:                if (xstrcmp(argv, "ragged"))
        !           671:                        return(MDOC_Ragged);
        !           672:                else if (xstrcmp(argv, "unfilled"))
        !           673:                        return(MDOC_Unfilled);
        !           674:                else if (xstrcmp(argv, "filled"))
        !           675:                        return(MDOC_Filled);
        !           676:                else if (xstrcmp(argv, "literal"))
        !           677:                        return(MDOC_Literal);
        !           678:                else if (xstrcmp(argv, "file"))
        !           679:                        return(MDOC_File);
        !           680:                else if (xstrcmp(argv, "offset"))
        !           681:                        return(MDOC_Offset);
        !           682:                else if (xstrcmp(argv, "compact"))
        !           683:                        return(MDOC_Compact);
        !           684:                break;
        !           685:
        !           686:        case (MDOC_Bf):
        !           687:                if (xstrcmp(argv, "emphasis"))
        !           688:                        return(MDOC_Emphasis);
        !           689:                else if (xstrcmp(argv, "literal"))
        !           690:                        return(MDOC_Literal);
        !           691:                else if (xstrcmp(argv, "symbolic"))
        !           692:                        return(MDOC_Symbolic);
        !           693:                break;
        !           694:
        !           695:        case (MDOC_Bk):
        !           696:                if (xstrcmp(argv, "words"))
        !           697:                        return(MDOC_Words);
        !           698:                break;
        !           699:
        !           700:        case (MDOC_Bl):
        !           701:                if (xstrcmp(argv, "bullet"))
        !           702:                        return(MDOC_Bullet);
        !           703:                else if (xstrcmp(argv, "dash"))
        !           704:                        return(MDOC_Dash);
        !           705:                else if (xstrcmp(argv, "hyphen"))
        !           706:                        return(MDOC_Hyphen);
        !           707:                else if (xstrcmp(argv, "item"))
        !           708:                        return(MDOC_Item);
        !           709:                else if (xstrcmp(argv, "enum"))
        !           710:                        return(MDOC_Enum);
        !           711:                else if (xstrcmp(argv, "tag"))
        !           712:                        return(MDOC_Tag);
        !           713:                else if (xstrcmp(argv, "diag"))
        !           714:                        return(MDOC_Diag);
        !           715:                else if (xstrcmp(argv, "hang"))
        !           716:                        return(MDOC_Hang);
        !           717:                else if (xstrcmp(argv, "ohang"))
        !           718:                        return(MDOC_Ohang);
        !           719:                else if (xstrcmp(argv, "inset"))
        !           720:                        return(MDOC_Inset);
        !           721:                else if (xstrcmp(argv, "column"))
        !           722:                        return(MDOC_Column);
        !           723:                else if (xstrcmp(argv, "width"))
        !           724:                        return(MDOC_Width);
        !           725:                else if (xstrcmp(argv, "offset"))
        !           726:                        return(MDOC_Offset);
        !           727:                else if (xstrcmp(argv, "compact"))
        !           728:                        return(MDOC_Compact);
        !           729:                else if (xstrcmp(argv, "nested"))
        !           730:                        return(MDOC_Nested);
        !           731:                break;
        !           732:
        !           733:        case (MDOC_Rv):
        !           734:                /* FALLTHROUGH */
        !           735:        case (MDOC_Ex):
        !           736:                if (xstrcmp(argv, "std"))
        !           737:                        return(MDOC_Std);
        !           738:                break;
        !           739:        default:
        !           740:                break;
        !           741:        }
        !           742:
        !           743:        return(MDOC_ARG_MAX);
        !           744: }
        !           745:
        !           746:
        !           747: static int
        !           748: argv_multi(struct mdoc *mdoc, int line,
        !           749:                struct mdoc_argv *v, int *pos, char *buf)
        !           750: {
        !           751:        int              c, ppos;
        !           752:        char            *p;
        !           753:
        !           754:        ppos = *pos;
        !           755:
        !           756:        for (v->sz = 0; ; v->sz++) {
        !           757:                if ('-' == buf[*pos])
        !           758:                        break;
        !           759:                c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
        !           760:                if (ARGS_ERROR == c)
        !           761:                        return(0);
        !           762:                else if (ARGS_EOLN == c)
        !           763:                        break;
        !           764:
        !           765:                if (0 == v->sz % MULTI_STEP)
        !           766:                        v->value = xrealloc(v->value,
        !           767:                                (v->sz + MULTI_STEP) * sizeof(char *));
        !           768:                if (NULL == (v->value[(int)v->sz] = strdup(p)))
        !           769:                        err(1, "strdup");
        !           770:        }
        !           771:
        !           772:        if (v->sz)
        !           773:                return(1);
        !           774:
        !           775:        return(perr(mdoc, line, ppos, EARGVAL));
        !           776: }
        !           777:
        !           778:
        !           779: static int
        !           780: argv_opt_single(struct mdoc *mdoc, int line,
        !           781:                struct mdoc_argv *v, int *pos, char *buf)
        !           782: {
        !           783:        int              c;
        !           784:        char            *p;
        !           785:
        !           786:        if ('-' == buf[*pos])
        !           787:                return(1);
        !           788:
        !           789:        c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
        !           790:        if (ARGS_ERROR == c)
        !           791:                return(0);
        !           792:        if (ARGS_EOLN == c)
        !           793:                return(1);
        !           794:
        !           795:        v->sz = 1;
        !           796:        if (NULL == (v->value = calloc(1, sizeof(char *))))
        !           797:                err(1, "calloc");
        !           798:        if (NULL == (v->value[0] = strdup(p)))
        !           799:                err(1, "strdup");
        !           800:        return(1);
        !           801: }
        !           802:
        !           803:
        !           804: /*
        !           805:  * Parse a single, mandatory value from the stream.
        !           806:  */
        !           807: static int
        !           808: argv_single(struct mdoc *mdoc, int line,
        !           809:                struct mdoc_argv *v, int *pos, char *buf)
        !           810: {
        !           811:        int              c, ppos;
        !           812:        char            *p;
        !           813:
        !           814:        ppos = *pos;
        !           815:
        !           816:        c = args(mdoc, line, pos, buf, ARGS_QUOTED, &p);
        !           817:        if (ARGS_ERROR == c)
        !           818:                return(0);
        !           819:        if (ARGS_EOLN == c)
        !           820:                return(perr(mdoc, line, ppos, EARGVAL));
        !           821:
        !           822:        v->sz = 1;
        !           823:        if (NULL == (v->value = calloc(1, sizeof(char *))))
        !           824:                err(1, "calloc");
        !           825:        if (NULL == (v->value[0] = strdup(p)))
        !           826:                err(1, "strdup");
        !           827:        return(1);
        !           828: }
        !           829:
        !           830:
        !           831: /*
        !           832:  * Determine rules for parsing arguments.  Arguments can either accept
        !           833:  * no parameters, an optional single parameter, one parameter, or
        !           834:  * multiple parameters.
        !           835:  */
        !           836: static int
        !           837: argv(struct mdoc *mdoc, int line,
        !           838:                struct mdoc_argv *v, int *pos, char *buf)
        !           839: {
        !           840:
        !           841:        v->sz = 0;
        !           842:        v->value = NULL;
        !           843:
        !           844:        switch (mdoc_argvflags[v->arg]) {
        !           845:        case (ARGV_SINGLE):
        !           846:                return(argv_single(mdoc, line, v, pos, buf));
        !           847:        case (ARGV_MULTI):
        !           848:                return(argv_multi(mdoc, line, v, pos, buf));
        !           849:        case (ARGV_OPT_SINGLE):
        !           850:                return(argv_opt_single(mdoc, line, v, pos, buf));
        !           851:        default:
        !           852:                /* ARGV_NONE */
        !           853:                break;
        !           854:        }
        !           855:
        !           856:        return(1);
        !           857: }

CVSweb