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

Annotation of mandoc/mdoc_argv.c, Revision 1.76

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

CVSweb