[BACK]Return to mdoc_argv.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mandoc

Annotation of src/usr.bin/mandoc/mdoc_argv.c, Revision 1.38

1.38    ! schwarze    1: /*     $Id: mdoc_argv.c,v 1.37 2011/04/24 16:22:02 schwarze Exp $ */
1.1       kristaps    2: /*
1.36      schwarze    3:  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
1.1       kristaps    4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
1.2       schwarze    6:  * purpose with or without fee is hereby granted, provided that the above
                      7:  * copyright notice and this permission notice appear in all copies.
1.1       kristaps    8:  *
1.2       schwarze    9:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     10:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     11:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     12:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     13:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     14:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     15:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1       kristaps   16:  */
                     17: #include <sys/types.h>
                     18:
                     19: #include <assert.h>
                     20: #include <ctype.h>
                     21: #include <stdlib.h>
                     22: #include <stdio.h>
                     23: #include <string.h>
                     24:
1.37      schwarze   25: #include "mdoc.h"
1.29      schwarze   26: #include "mandoc.h"
1.1       kristaps   27: #include "libmdoc.h"
1.19      schwarze   28: #include "libmandoc.h"
1.1       kristaps   29:
1.36      schwarze   30: #define        MULTI_STEP       5 /* pre-allocate argument values */
1.38    ! schwarze   31: #define        DELIMSZ          6 /* max possible size of a delimiter */
        !            32:
        !            33: enum   argsflag {
        !            34:        ARGSFL_NONE = 0,
        !            35:        ARGSFL_DELIM, /* handle delimiters of [[::delim::][ ]+]+ */
        !            36:        ARGSFL_TABSEP /* handle tab/`Ta' separated phrases */
        !            37: };
        !            38:
        !            39: enum   argvflag {
        !            40:        ARGV_NONE, /* no args to flag (e.g., -split) */
        !            41:        ARGV_SINGLE, /* one arg to flag (e.g., -file xxx)  */
        !            42:        ARGV_MULTI, /* multiple args (e.g., -column xxx yyy) */
        !            43:        ARGV_OPT_SINGLE /* optional arg (e.g., -offset [xxx]) */
        !            44: };
1.1       kristaps   45:
1.33      schwarze   46: static enum mdocargt    argv_a2arg(enum mdoct, const char *);
1.24      schwarze   47: static enum margserr    args(struct mdoc *, int, int *,
1.38    ! schwarze   48:                                char *, enum argsflag, char **);
        !            49: static int              args_checkpunct(const char *, int);
1.1       kristaps   50: static int              argv(struct mdoc *, int,
                     51:                                struct mdoc_argv *, int *, char *);
                     52: static int              argv_single(struct mdoc *, int,
                     53:                                struct mdoc_argv *, int *, char *);
                     54: static int              argv_opt_single(struct mdoc *, int,
                     55:                                struct mdoc_argv *, int *, char *);
                     56: static int              argv_multi(struct mdoc *, int,
                     57:                                struct mdoc_argv *, int *, char *);
1.37      schwarze   58: static void             argn_free(struct mdoc_arg *, int);
1.1       kristaps   59:
1.36      schwarze   60: static const enum argvflag argvflags[MDOC_ARG_MAX] = {
1.1       kristaps   61:        ARGV_NONE,      /* MDOC_Split */
                     62:        ARGV_NONE,      /* MDOC_Nosplit */
                     63:        ARGV_NONE,      /* MDOC_Ragged */
                     64:        ARGV_NONE,      /* MDOC_Unfilled */
                     65:        ARGV_NONE,      /* MDOC_Literal */
1.17      schwarze   66:        ARGV_SINGLE,    /* MDOC_File */
1.15      schwarze   67:        ARGV_OPT_SINGLE, /* MDOC_Offset */
1.1       kristaps   68:        ARGV_NONE,      /* MDOC_Bullet */
                     69:        ARGV_NONE,      /* MDOC_Dash */
                     70:        ARGV_NONE,      /* MDOC_Hyphen */
                     71:        ARGV_NONE,      /* MDOC_Item */
                     72:        ARGV_NONE,      /* MDOC_Enum */
                     73:        ARGV_NONE,      /* MDOC_Tag */
                     74:        ARGV_NONE,      /* MDOC_Diag */
                     75:        ARGV_NONE,      /* MDOC_Hang */
                     76:        ARGV_NONE,      /* MDOC_Ohang */
                     77:        ARGV_NONE,      /* MDOC_Inset */
                     78:        ARGV_MULTI,     /* MDOC_Column */
                     79:        ARGV_SINGLE,    /* MDOC_Width */
                     80:        ARGV_NONE,      /* MDOC_Compact */
1.14      schwarze   81:        ARGV_NONE,      /* MDOC_Std */
1.1       kristaps   82:        ARGV_NONE,      /* MDOC_Filled */
                     83:        ARGV_NONE,      /* MDOC_Words */
                     84:        ARGV_NONE,      /* MDOC_Emphasis */
                     85:        ARGV_NONE,      /* MDOC_Symbolic */
                     86:        ARGV_NONE       /* MDOC_Symbolic */
                     87: };
                     88:
1.38    ! schwarze   89: static const enum argsflag argflags[MDOC_MAX] = {
        !            90:        ARGSFL_NONE, /* Ap */
        !            91:        ARGSFL_NONE, /* Dd */
        !            92:        ARGSFL_NONE, /* Dt */
        !            93:        ARGSFL_NONE, /* Os */
        !            94:        ARGSFL_NONE, /* Sh */
        !            95:        ARGSFL_NONE, /* Ss */
        !            96:        ARGSFL_NONE, /* Pp */
        !            97:        ARGSFL_DELIM, /* D1 */
        !            98:        ARGSFL_DELIM, /* Dl */
        !            99:        ARGSFL_NONE, /* Bd */
        !           100:        ARGSFL_NONE, /* Ed */
        !           101:        ARGSFL_NONE, /* Bl */
        !           102:        ARGSFL_NONE, /* El */
        !           103:        ARGSFL_NONE, /* It */
        !           104:        ARGSFL_DELIM, /* Ad */
        !           105:        ARGSFL_DELIM, /* An */
        !           106:        ARGSFL_DELIM, /* Ar */
        !           107:        ARGSFL_NONE, /* Cd */
        !           108:        ARGSFL_DELIM, /* Cm */
        !           109:        ARGSFL_DELIM, /* Dv */
        !           110:        ARGSFL_DELIM, /* Er */
        !           111:        ARGSFL_DELIM, /* Ev */
        !           112:        ARGSFL_NONE, /* Ex */
        !           113:        ARGSFL_DELIM, /* Fa */
        !           114:        ARGSFL_NONE, /* Fd */
        !           115:        ARGSFL_DELIM, /* Fl */
        !           116:        ARGSFL_DELIM, /* Fn */
        !           117:        ARGSFL_DELIM, /* Ft */
        !           118:        ARGSFL_DELIM, /* Ic */
        !           119:        ARGSFL_NONE, /* In */
        !           120:        ARGSFL_DELIM, /* Li */
        !           121:        ARGSFL_NONE, /* Nd */
        !           122:        ARGSFL_DELIM, /* Nm */
        !           123:        ARGSFL_DELIM, /* Op */
        !           124:        ARGSFL_NONE, /* Ot */
        !           125:        ARGSFL_DELIM, /* Pa */
        !           126:        ARGSFL_NONE, /* Rv */
        !           127:        ARGSFL_DELIM, /* St */
        !           128:        ARGSFL_DELIM, /* Va */
        !           129:        ARGSFL_DELIM, /* Vt */
        !           130:        ARGSFL_DELIM, /* Xr */
        !           131:        ARGSFL_NONE, /* %A */
        !           132:        ARGSFL_NONE, /* %B */
        !           133:        ARGSFL_NONE, /* %D */
        !           134:        ARGSFL_NONE, /* %I */
        !           135:        ARGSFL_NONE, /* %J */
        !           136:        ARGSFL_NONE, /* %N */
        !           137:        ARGSFL_NONE, /* %O */
        !           138:        ARGSFL_NONE, /* %P */
        !           139:        ARGSFL_NONE, /* %R */
        !           140:        ARGSFL_NONE, /* %T */
        !           141:        ARGSFL_NONE, /* %V */
        !           142:        ARGSFL_DELIM, /* Ac */
        !           143:        ARGSFL_NONE, /* Ao */
        !           144:        ARGSFL_DELIM, /* Aq */
        !           145:        ARGSFL_DELIM, /* At */
        !           146:        ARGSFL_DELIM, /* Bc */
        !           147:        ARGSFL_NONE, /* Bf */
        !           148:        ARGSFL_NONE, /* Bo */
        !           149:        ARGSFL_DELIM, /* Bq */
        !           150:        ARGSFL_DELIM, /* Bsx */
        !           151:        ARGSFL_DELIM, /* Bx */
        !           152:        ARGSFL_NONE, /* Db */
        !           153:        ARGSFL_DELIM, /* Dc */
        !           154:        ARGSFL_NONE, /* Do */
        !           155:        ARGSFL_DELIM, /* Dq */
        !           156:        ARGSFL_DELIM, /* Ec */
        !           157:        ARGSFL_NONE, /* Ef */
        !           158:        ARGSFL_DELIM, /* Em */
        !           159:        ARGSFL_NONE, /* Eo */
        !           160:        ARGSFL_DELIM, /* Fx */
        !           161:        ARGSFL_DELIM, /* Ms */
        !           162:        ARGSFL_DELIM, /* No */
        !           163:        ARGSFL_DELIM, /* Ns */
        !           164:        ARGSFL_DELIM, /* Nx */
        !           165:        ARGSFL_DELIM, /* Ox */
        !           166:        ARGSFL_DELIM, /* Pc */
        !           167:        ARGSFL_DELIM, /* Pf */
        !           168:        ARGSFL_NONE, /* Po */
        !           169:        ARGSFL_DELIM, /* Pq */
        !           170:        ARGSFL_DELIM, /* Qc */
        !           171:        ARGSFL_DELIM, /* Ql */
        !           172:        ARGSFL_NONE, /* Qo */
        !           173:        ARGSFL_DELIM, /* Qq */
        !           174:        ARGSFL_NONE, /* Re */
        !           175:        ARGSFL_NONE, /* Rs */
        !           176:        ARGSFL_DELIM, /* Sc */
        !           177:        ARGSFL_NONE, /* So */
        !           178:        ARGSFL_DELIM, /* Sq */
        !           179:        ARGSFL_NONE, /* Sm */
        !           180:        ARGSFL_DELIM, /* Sx */
        !           181:        ARGSFL_DELIM, /* Sy */
        !           182:        ARGSFL_DELIM, /* Tn */
        !           183:        ARGSFL_DELIM, /* Ux */
        !           184:        ARGSFL_DELIM, /* Xc */
        !           185:        ARGSFL_NONE, /* Xo */
        !           186:        ARGSFL_NONE, /* Fo */
        !           187:        ARGSFL_NONE, /* Fc */
        !           188:        ARGSFL_NONE, /* Oo */
        !           189:        ARGSFL_DELIM, /* Oc */
        !           190:        ARGSFL_NONE, /* Bk */
        !           191:        ARGSFL_NONE, /* Ek */
        !           192:        ARGSFL_NONE, /* Bt */
        !           193:        ARGSFL_NONE, /* Hf */
        !           194:        ARGSFL_NONE, /* Fr */
        !           195:        ARGSFL_NONE, /* Ud */
        !           196:        ARGSFL_NONE, /* Lb */
        !           197:        ARGSFL_NONE, /* Lp */
        !           198:        ARGSFL_DELIM, /* Lk */
        !           199:        ARGSFL_DELIM, /* Mt */
        !           200:        ARGSFL_DELIM, /* Brq */
        !           201:        ARGSFL_NONE, /* Bro */
        !           202:        ARGSFL_DELIM, /* Brc */
        !           203:        ARGSFL_NONE, /* %C */
        !           204:        ARGSFL_NONE, /* Es */
        !           205:        ARGSFL_NONE, /* En */
        !           206:        ARGSFL_NONE, /* Dx */
        !           207:        ARGSFL_NONE, /* %Q */
        !           208:        ARGSFL_NONE, /* br */
        !           209:        ARGSFL_NONE, /* sp */
        !           210:        ARGSFL_NONE, /* %U */
        !           211:        ARGSFL_NONE, /* Ta */
1.1       kristaps  212: };
                    213:
1.37      schwarze  214: static const enum mdocargt args_Ex[] = {
                    215:        MDOC_Std,
                    216:        MDOC_ARG_MAX
                    217: };
                    218:
                    219: static const enum mdocargt args_An[] = {
                    220:        MDOC_Split,
                    221:        MDOC_Nosplit,
                    222:        MDOC_ARG_MAX
                    223: };
                    224:
                    225: static const enum mdocargt args_Bd[] = {
                    226:        MDOC_Ragged,
                    227:        MDOC_Unfilled,
                    228:        MDOC_Filled,
                    229:        MDOC_Literal,
                    230:        MDOC_File,
                    231:        MDOC_Offset,
                    232:        MDOC_Compact,
                    233:        MDOC_Centred,
                    234:        MDOC_ARG_MAX
                    235: };
                    236:
                    237: static const enum mdocargt args_Bf[] = {
                    238:        MDOC_Emphasis,
                    239:        MDOC_Literal,
                    240:        MDOC_Symbolic,
                    241:        MDOC_ARG_MAX
                    242: };
                    243:
                    244: static const enum mdocargt args_Bk[] = {
                    245:        MDOC_Words,
                    246:        MDOC_ARG_MAX
                    247: };
                    248:
                    249: static const enum mdocargt args_Bl[] = {
                    250:        MDOC_Bullet,
                    251:        MDOC_Dash,
                    252:        MDOC_Hyphen,
                    253:        MDOC_Item,
                    254:        MDOC_Enum,
                    255:        MDOC_Tag,
                    256:        MDOC_Diag,
                    257:        MDOC_Hang,
                    258:        MDOC_Ohang,
                    259:        MDOC_Inset,
                    260:        MDOC_Column,
                    261:        MDOC_Width,
                    262:        MDOC_Offset,
                    263:        MDOC_Compact,
                    264:        MDOC_Nested,
                    265:        MDOC_ARG_MAX
                    266: };
                    267:
1.1       kristaps  268: /*
                    269:  * Parse an argument from line text.  This comes in the form of -key
                    270:  * [value0...], which may either have a single mandatory value, at least
                    271:  * one mandatory value, an optional single value, or no value.
                    272:  */
1.24      schwarze  273: enum margverr
1.22      schwarze  274: mdoc_argv(struct mdoc *m, int line, enum mdoct tok,
1.1       kristaps  275:                struct mdoc_arg **v, int *pos, char *buf)
                    276: {
                    277:        char             *p, sv;
                    278:        struct mdoc_argv tmp;
                    279:        struct mdoc_arg  *arg;
                    280:
1.30      schwarze  281:        if ('\0' == buf[*pos])
1.1       kristaps  282:                return(ARGV_EOLN);
                    283:
                    284:        assert(' ' != buf[*pos]);
                    285:
                    286:        /* Parse through to the first unescaped space. */
                    287:
                    288:        p = &buf[++(*pos)];
                    289:
                    290:        assert(*pos > 0);
                    291:
                    292:        /* LINTED */
                    293:        while (buf[*pos]) {
                    294:                if (' ' == buf[*pos])
                    295:                        if ('\\' != buf[*pos - 1])
                    296:                                break;
                    297:                (*pos)++;
                    298:        }
                    299:
                    300:        /* XXX - save zeroed byte, if not an argument. */
                    301:
1.30      schwarze  302:        sv = '\0';
1.1       kristaps  303:        if (buf[*pos]) {
                    304:                sv = buf[*pos];
1.30      schwarze  305:                buf[(*pos)++] = '\0';
1.1       kristaps  306:        }
                    307:
1.36      schwarze  308:        memset(&tmp, 0, sizeof(struct mdoc_argv));
1.1       kristaps  309:        tmp.line = line;
                    310:        tmp.pos = *pos;
                    311:
                    312:        /* See if our token accepts the argument. */
                    313:
                    314:        if (MDOC_ARG_MAX == (tmp.arg = argv_a2arg(tok, p))) {
                    315:                /* XXX - restore saved zeroed byte. */
                    316:                if (sv)
                    317:                        buf[*pos - 1] = sv;
                    318:                return(ARGV_WORD);
                    319:        }
                    320:
                    321:        while (buf[*pos] && ' ' == buf[*pos])
                    322:                (*pos)++;
                    323:
1.6       schwarze  324:        if ( ! argv(m, line, &tmp, pos, buf))
1.1       kristaps  325:                return(ARGV_ERROR);
                    326:
1.19      schwarze  327:        if (NULL == (arg = *v))
                    328:                arg = *v = mandoc_calloc(1, sizeof(struct mdoc_arg));
1.1       kristaps  329:
                    330:        arg->argc++;
1.19      schwarze  331:        arg->argv = mandoc_realloc
                    332:                (arg->argv, arg->argc * sizeof(struct mdoc_argv));
1.1       kristaps  333:
1.36      schwarze  334:        memcpy(&arg->argv[(int)arg->argc - 1],
1.1       kristaps  335:                        &tmp, sizeof(struct mdoc_argv));
                    336:
                    337:        return(ARGV_ARG);
                    338: }
                    339:
                    340: void
                    341: mdoc_argv_free(struct mdoc_arg *p)
                    342: {
1.23      schwarze  343:        int              i;
1.1       kristaps  344:
                    345:        if (NULL == p)
                    346:                return;
                    347:
                    348:        if (p->refcnt) {
                    349:                --(p->refcnt);
                    350:                if (p->refcnt)
                    351:                        return;
                    352:        }
                    353:        assert(p->argc);
                    354:
1.24      schwarze  355:        for (i = (int)p->argc - 1; i >= 0; i--)
1.37      schwarze  356:                argn_free(p, i);
1.23      schwarze  357:
                    358:        free(p->argv);
                    359:        free(p);
                    360: }
                    361:
1.37      schwarze  362: static void
                    363: argn_free(struct mdoc_arg *p, int iarg)
1.23      schwarze  364: {
1.33      schwarze  365:        struct mdoc_argv *arg;
1.23      schwarze  366:        int               j;
1.1       kristaps  367:
1.33      schwarze  368:        arg = &p->argv[iarg];
                    369:
1.23      schwarze  370:        if (arg->sz && arg->value) {
1.24      schwarze  371:                for (j = (int)arg->sz - 1; j >= 0; j--)
1.23      schwarze  372:                        free(arg->value[j]);
                    373:                free(arg->value);
1.1       kristaps  374:        }
                    375:
1.23      schwarze  376:        for (--p->argc; iarg < (int)p->argc; iarg++)
                    377:                p->argv[iarg] = p->argv[iarg+1];
1.1       kristaps  378: }
                    379:
1.24      schwarze  380: enum margserr
1.38    ! schwarze  381: mdoc_zargs(struct mdoc *m, int line, int *pos, char *buf, char **v)
1.12      schwarze  382: {
                    383:
1.38    ! schwarze  384:        return(args(m, line, pos, buf, ARGSFL_NONE, v));
1.12      schwarze  385: }
                    386:
1.24      schwarze  387: enum margserr
1.22      schwarze  388: mdoc_args(struct mdoc *m, int line, int *pos,
                    389:                char *buf, enum mdoct tok, char **v)
1.1       kristaps  390: {
1.38    ! schwarze  391:        enum argsflag     fl;
1.1       kristaps  392:        struct mdoc_node *n;
                    393:
1.36      schwarze  394:        fl = argflags[tok];
1.1       kristaps  395:
1.12      schwarze  396:        if (MDOC_It != tok)
                    397:                return(args(m, line, pos, buf, fl, v));
                    398:
1.30      schwarze  399:        /*
                    400:         * We know that we're in an `It', so it's reasonable to expect
                    401:         * us to be sitting in a `Bl'.  Someday this may not be the case
                    402:         * (if we allow random `It's sitting out there), so provide a
                    403:         * safe fall-back into the default behaviour.
1.1       kristaps  404:         */
                    405:
1.12      schwarze  406:        for (n = m->last; n; n = n->parent)
1.30      schwarze  407:                if (MDOC_Bl == n->tok)
1.38    ! schwarze  408:                        if (LIST_column == n->norm->Bl.type) {
        !           409:                                fl = ARGSFL_TABSEP;
        !           410:                                break;
        !           411:                        }
1.1       kristaps  412:
1.8       schwarze  413:        return(args(m, line, pos, buf, fl, v));
1.1       kristaps  414: }
                    415:
1.24      schwarze  416: static enum margserr
1.12      schwarze  417: args(struct mdoc *m, int line, int *pos,
1.38    ! schwarze  418:                char *buf, enum argsflag fl, char **v)
1.1       kristaps  419: {
1.30      schwarze  420:        char            *p, *pp;
                    421:        enum margserr    rc;
1.1       kristaps  422:
1.12      schwarze  423:        assert(' ' != buf[*pos]);
1.1       kristaps  424:
1.28      schwarze  425:        if ('\0' == buf[*pos]) {
                    426:                if (MDOC_PPHRASE & m->flags)
                    427:                        return(ARGS_EOLN);
                    428:                /*
                    429:                 * If we're not in a partial phrase and the flag for
                    430:                 * being a phrase literal is still set, the punctuation
                    431:                 * is unterminated.
                    432:                 */
                    433:                if (MDOC_PHRASELIT & m->flags)
1.36      schwarze  434:                        mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
1.28      schwarze  435:
                    436:                m->flags &= ~MDOC_PHRASELIT;
1.1       kristaps  437:                return(ARGS_EOLN);
1.28      schwarze  438:        }
1.1       kristaps  439:
1.36      schwarze  440:        *v = &buf[*pos];
1.1       kristaps  441:
1.38    ! schwarze  442:        if (ARGSFL_DELIM == fl)
        !           443:                if (args_checkpunct(buf, *pos))
1.36      schwarze  444:                        return(ARGS_PUNCT);
1.1       kristaps  445:
1.12      schwarze  446:        /*
                    447:         * First handle TABSEP items, restricted to `Bl -column'.  This
                    448:         * ignores conventional token parsing and instead uses tabs or
                    449:         * `Ta' macros to separate phrases.  Phrases are parsed again
                    450:         * for arguments at a later phase.
                    451:         */
                    452:
1.38    ! schwarze  453:        if (ARGSFL_TABSEP == fl) {
1.12      schwarze  454:                /* Scan ahead to tab (can't be escaped). */
                    455:                p = strchr(*v, '\t');
1.28      schwarze  456:                pp = NULL;
1.12      schwarze  457:
                    458:                /* Scan ahead to unescaped `Ta'. */
1.28      schwarze  459:                if ( ! (MDOC_PHRASELIT & m->flags))
                    460:                        for (pp = *v; ; pp++) {
                    461:                                if (NULL == (pp = strstr(pp, "Ta")))
                    462:                                        break;
                    463:                                if (pp > *v && ' ' != *(pp - 1))
                    464:                                        continue;
1.30      schwarze  465:                                if (' ' == *(pp + 2) || '\0' == *(pp + 2))
1.28      schwarze  466:                                        break;
                    467:                        }
1.1       kristaps  468:
1.24      schwarze  469:                /* By default, assume a phrase. */
                    470:                rc = ARGS_PHRASE;
                    471:
1.1       kristaps  472:                /*
1.12      schwarze  473:                 * Adjust new-buffer position to be beyond delimiter
                    474:                 * mark (e.g., Ta -> end + 2).
1.1       kristaps  475:                 */
1.12      schwarze  476:                if (p && pp) {
                    477:                        *pos += pp < p ? 2 : 1;
1.24      schwarze  478:                        rc = pp < p ? ARGS_PHRASE : ARGS_PPHRASE;
1.12      schwarze  479:                        p = pp < p ? pp : p;
                    480:                } else if (p && ! pp) {
1.24      schwarze  481:                        rc = ARGS_PPHRASE;
1.12      schwarze  482:                        *pos += 1;
                    483:                } else if (pp && ! p) {
                    484:                        p = pp;
                    485:                        *pos += 2;
1.25      schwarze  486:                } else {
                    487:                        rc = ARGS_PEND;
1.12      schwarze  488:                        p = strchr(*v, 0);
1.25      schwarze  489:                }
1.1       kristaps  490:
1.12      schwarze  491:                /* Whitespace check for eoln case... */
1.38    ! schwarze  492:                if ('\0' == *p && ' ' == *(p - 1))
1.36      schwarze  493:                        mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
1.12      schwarze  494:
                    495:                *pos += (int)(p - *v);
                    496:
                    497:                /* Strip delimiter's preceding whitespace. */
                    498:                pp = p - 1;
                    499:                while (pp > *v && ' ' == *pp) {
                    500:                        if (pp > *v && '\\' == *(pp - 1))
                    501:                                break;
                    502:                        pp--;
                    503:                }
                    504:                *(pp + 1) = 0;
1.1       kristaps  505:
1.12      schwarze  506:                /* Strip delimiter's proceeding whitespace. */
                    507:                for (pp = &buf[*pos]; ' ' == *pp; pp++, (*pos)++)
                    508:                        /* Skip ahead. */ ;
1.1       kristaps  509:
1.24      schwarze  510:                return(rc);
1.12      schwarze  511:        }
1.1       kristaps  512:
1.12      schwarze  513:        /*
                    514:         * Process a quoted literal.  A quote begins with a double-quote
                    515:         * and ends with a double-quote NOT preceded by a double-quote.
                    516:         * Whitespace is NOT involved in literal termination.
                    517:         */
1.1       kristaps  518:
1.28      schwarze  519:        if (MDOC_PHRASELIT & m->flags || '\"' == buf[*pos]) {
                    520:                if ( ! (MDOC_PHRASELIT & m->flags))
                    521:                        *v = &buf[++(*pos)];
                    522:
                    523:                if (MDOC_PPHRASE & m->flags)
                    524:                        m->flags |= MDOC_PHRASELIT;
1.1       kristaps  525:
1.12      schwarze  526:                for ( ; buf[*pos]; (*pos)++) {
                    527:                        if ('\"' != buf[*pos])
                    528:                                continue;
                    529:                        if ('\"' != buf[*pos + 1])
                    530:                                break;
                    531:                        (*pos)++;
                    532:                }
1.1       kristaps  533:
1.28      schwarze  534:                if ('\0' == buf[*pos]) {
1.38    ! schwarze  535:                        if (MDOC_PPHRASE & m->flags)
1.13      schwarze  536:                                return(ARGS_QWORD);
1.36      schwarze  537:                        mdoc_pmsg(m, line, *pos, MANDOCERR_BADQUOTE);
1.12      schwarze  538:                        return(ARGS_QWORD);
                    539:                }
1.1       kristaps  540:
1.28      schwarze  541:                m->flags &= ~MDOC_PHRASELIT;
                    542:                buf[(*pos)++] = '\0';
1.1       kristaps  543:
1.28      schwarze  544:                if ('\0' == buf[*pos])
1.12      schwarze  545:                        return(ARGS_QWORD);
1.1       kristaps  546:
1.12      schwarze  547:                while (' ' == buf[*pos])
                    548:                        (*pos)++;
1.1       kristaps  549:
1.38    ! schwarze  550:                if ('\0' == buf[*pos])
1.36      schwarze  551:                        mdoc_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE);
1.1       kristaps  552:
1.12      schwarze  553:                return(ARGS_QWORD);
1.1       kristaps  554:        }
                    555:
1.38    ! schwarze  556:        p = &buf[*pos];
        !           557:        *v = mandoc_getarg(m->parse, &p, line, pos);
1.1       kristaps  558:
1.12      schwarze  559:        return(ARGS_WORD);
1.1       kristaps  560: }
                    561:
1.36      schwarze  562: /*
                    563:  * Check if the string consists only of space-separated closing
                    564:  * delimiters.  This is a bit of a dance: the first must be a close
                    565:  * delimiter, but it may be followed by middle delimiters.  Arbitrary
                    566:  * whitespace may separate these tokens.
                    567:  */
                    568: static int
1.38    ! schwarze  569: args_checkpunct(const char *buf, int i)
1.36      schwarze  570: {
1.38    ! schwarze  571:        int              j;
        !           572:        char             dbuf[DELIMSZ];
1.36      schwarze  573:        enum mdelim      d;
                    574:
                    575:        /* First token must be a close-delimiter. */
                    576:
1.38    ! schwarze  577:        for (j = 0; buf[i] && ' ' != buf[i] && j < DELIMSZ; j++, i++)
        !           578:                dbuf[j] = buf[i];
1.1       kristaps  579:
1.36      schwarze  580:        if (DELIMSZ == j)
                    581:                return(0);
                    582:
1.38    ! schwarze  583:        dbuf[j] = '\0';
        !           584:        if (DELIM_CLOSE != mdoc_isdelim(dbuf))
1.36      schwarze  585:                return(0);
                    586:
1.38    ! schwarze  587:        while (' ' == buf[i])
1.36      schwarze  588:                i++;
                    589:
                    590:        /* Remaining must NOT be open/none. */
                    591:
1.38    ! schwarze  592:        while (buf[i]) {
1.36      schwarze  593:                j = 0;
1.38    ! schwarze  594:                while (buf[i] && ' ' != buf[i] && j < DELIMSZ)
        !           595:                        dbuf[j++] = buf[i++];
1.36      schwarze  596:
                    597:                if (DELIMSZ == j)
                    598:                        return(0);
                    599:
1.38    ! schwarze  600:                dbuf[j] = '\0';
        !           601:                d = mdoc_isdelim(dbuf);
1.36      schwarze  602:                if (DELIM_NONE == d || DELIM_OPEN == d)
                    603:                        return(0);
                    604:
1.38    ! schwarze  605:                while (' ' == buf[i])
1.36      schwarze  606:                        i++;
                    607:        }
                    608:
1.38    ! schwarze  609:        return('\0' == buf[i]);
1.36      schwarze  610: }
                    611:
                    612: /*
                    613:  * Match up an argument string (e.g., `-foo bar' having "foo") with the
1.37      schwarze  614:  * correct identifier.  It must apply to the given macro.  If none was
1.36      schwarze  615:  * found (including bad matches), return MDOC_ARG_MAX.
                    616:  */
1.33      schwarze  617: static enum mdocargt
1.22      schwarze  618: argv_a2arg(enum mdoct tok, const char *p)
1.1       kristaps  619: {
1.38    ! schwarze  620:        const enum mdocargt *argsp;
1.1       kristaps  621:
1.38    ! schwarze  622:        argsp = NULL;
1.1       kristaps  623:
                    624:        switch (tok) {
                    625:        case (MDOC_An):
1.38    ! schwarze  626:                argsp = args_An;
1.1       kristaps  627:                break;
                    628:        case (MDOC_Bd):
1.38    ! schwarze  629:                argsp = args_Bd;
1.1       kristaps  630:                break;
                    631:        case (MDOC_Bf):
1.38    ! schwarze  632:                argsp = args_Bf;
1.1       kristaps  633:                break;
                    634:        case (MDOC_Bk):
1.38    ! schwarze  635:                argsp = args_Bk;
1.1       kristaps  636:                break;
                    637:        case (MDOC_Bl):
1.38    ! schwarze  638:                argsp = args_Bl;
1.1       kristaps  639:                break;
                    640:        case (MDOC_Rv):
                    641:                /* FALLTHROUGH */
                    642:        case (MDOC_Ex):
1.38    ! schwarze  643:                argsp = args_Ex;
1.1       kristaps  644:                break;
                    645:        default:
1.37      schwarze  646:                return(MDOC_ARG_MAX);
1.1       kristaps  647:        }
                    648:
1.38    ! schwarze  649:        assert(argsp);
1.37      schwarze  650:
1.38    ! schwarze  651:        for ( ; MDOC_ARG_MAX != *argsp ; argsp++)
        !           652:                if (0 == strcmp(p, mdoc_argnames[*argsp]))
        !           653:                        return(*argsp);
1.36      schwarze  654:
1.1       kristaps  655:        return(MDOC_ARG_MAX);
                    656: }
                    657:
                    658: static int
1.6       schwarze  659: argv_multi(struct mdoc *m, int line,
1.1       kristaps  660:                struct mdoc_argv *v, int *pos, char *buf)
                    661: {
1.24      schwarze  662:        enum margserr    ac;
1.1       kristaps  663:        char            *p;
                    664:
                    665:        for (v->sz = 0; ; v->sz++) {
                    666:                if ('-' == buf[*pos])
                    667:                        break;
1.38    ! schwarze  668:                ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
1.24      schwarze  669:                if (ARGS_ERROR == ac)
1.1       kristaps  670:                        return(0);
1.24      schwarze  671:                else if (ARGS_EOLN == ac)
1.1       kristaps  672:                        break;
                    673:
1.19      schwarze  674:                if (0 == v->sz % MULTI_STEP)
                    675:                        v->value = mandoc_realloc(v->value,
1.1       kristaps  676:                                (v->sz + MULTI_STEP) * sizeof(char *));
1.19      schwarze  677:
                    678:                v->value[(int)v->sz] = mandoc_strdup(p);
1.1       kristaps  679:        }
                    680:
1.4       schwarze  681:        return(1);
1.1       kristaps  682: }
                    683:
                    684: static int
1.6       schwarze  685: argv_opt_single(struct mdoc *m, int line,
1.1       kristaps  686:                struct mdoc_argv *v, int *pos, char *buf)
                    687: {
1.24      schwarze  688:        enum margserr    ac;
1.1       kristaps  689:        char            *p;
                    690:
                    691:        if ('-' == buf[*pos])
                    692:                return(1);
                    693:
1.38    ! schwarze  694:        ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
1.24      schwarze  695:        if (ARGS_ERROR == ac)
1.1       kristaps  696:                return(0);
1.24      schwarze  697:        if (ARGS_EOLN == ac)
1.1       kristaps  698:                return(1);
                    699:
                    700:        v->sz = 1;
1.19      schwarze  701:        v->value = mandoc_malloc(sizeof(char *));
                    702:        v->value[0] = mandoc_strdup(p);
1.1       kristaps  703:
                    704:        return(1);
                    705: }
                    706:
                    707: /*
                    708:  * Parse a single, mandatory value from the stream.
                    709:  */
                    710: static int
1.6       schwarze  711: argv_single(struct mdoc *m, int line,
1.1       kristaps  712:                struct mdoc_argv *v, int *pos, char *buf)
                    713: {
1.24      schwarze  714:        int              ppos;
                    715:        enum margserr    ac;
1.1       kristaps  716:        char            *p;
                    717:
                    718:        ppos = *pos;
                    719:
1.38    ! schwarze  720:        ac = args(m, line, pos, buf, ARGSFL_NONE, &p);
1.29      schwarze  721:        if (ARGS_EOLN == ac) {
                    722:                mdoc_pmsg(m, line, ppos, MANDOCERR_SYNTARGVCOUNT);
                    723:                return(0);
                    724:        } else if (ARGS_ERROR == ac)
1.1       kristaps  725:                return(0);
                    726:
                    727:        v->sz = 1;
1.19      schwarze  728:        v->value = mandoc_malloc(sizeof(char *));
                    729:        v->value[0] = mandoc_strdup(p);
1.1       kristaps  730:
                    731:        return(1);
                    732: }
                    733:
                    734: /*
                    735:  * Determine rules for parsing arguments.  Arguments can either accept
                    736:  * no parameters, an optional single parameter, one parameter, or
                    737:  * multiple parameters.
                    738:  */
                    739: static int
                    740: argv(struct mdoc *mdoc, int line,
                    741:                struct mdoc_argv *v, int *pos, char *buf)
                    742: {
                    743:
                    744:        v->sz = 0;
                    745:        v->value = NULL;
                    746:
1.36      schwarze  747:        switch (argvflags[v->arg]) {
1.1       kristaps  748:        case (ARGV_SINGLE):
                    749:                return(argv_single(mdoc, line, v, pos, buf));
                    750:        case (ARGV_MULTI):
                    751:                return(argv_multi(mdoc, line, v, pos, buf));
                    752:        case (ARGV_OPT_SINGLE):
                    753:                return(argv_opt_single(mdoc, line, v, pos, buf));
1.36      schwarze  754:        case (ARGV_NONE):
                    755:                break;
1.1       kristaps  756:        default:
1.36      schwarze  757:                abort();
                    758:                /* NOTREACHED */
1.1       kristaps  759:        }
                    760:
                    761:        return(1);
                    762: }