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

Annotation of mandoc/mmain.c, Revision 1.12

1.12    ! kristaps    1:        /* $Id: mmain.c,v 1.11 2009/03/09 13:35:09 kristaps Exp $ */
1.1       kristaps    2: /*
                      3:  * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
                      4:  *
                      5:  * Permission to use, copy, modify, and distribute this software for any
                      6:  * purpose with or without fee is hereby granted, provided that the
                      7:  * above copyright notice and this permission notice appear in all
                      8:  * copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
                     11:  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
                     12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
                     13:  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
                     14:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
                     15:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
                     16:  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
                     17:  * PERFORMANCE OF THIS SOFTWARE.
                     18:  */
                     19: #include <sys/stat.h>
                     20: #include <sys/param.h>
                     21:
                     22: #include <assert.h>
                     23: #include <fcntl.h>
                     24: #include <err.h>
                     25: #include <getopt.h>
                     26: #include <stdio.h>
                     27: #include <stdlib.h>
                     28: #include <string.h>
                     29: #include <unistd.h>
                     30:
                     31: #include "mmain.h"
                     32:
1.8       kristaps   33: #define        MD_LINE_SZ      (256)           /* Input line step-size. */
1.1       kristaps   34:
                     35: struct mmain {
                     36:        int               warn;         /* Warning flags. */
                     37: #define        MD_WARN_SYNTAX   (1 << 0)       /* Show syntax warnings. */
                     38: #define        MD_WARN_COMPAT   (1 << 1)       /* Show compat warnings. */
                     39: #define        MD_WARN_ALL      (0x03)         /* Show all warnings. */
                     40: #define        MD_WARN_ERR      (1 << 2)       /* Make warnings->errors. */
                     41:        int               dbg;          /* Debug level. */
                     42:        struct mdoc      *mdoc;         /* Active parser. */
                     43:        char             *buf;          /* Input buffer. */
1.9       kristaps   44:        size_t            bufsz;        /* Input buffer size. */
1.12    ! kristaps   45:        const char       *in;           /* Input file name. */
1.1       kristaps   46:        int               fdin;         /* Input file desc. */
1.6       kristaps   47:        int               pflags;       /* Parse flags. */
1.1       kristaps   48: };
                     49:
                     50: extern char             *__progname;
                     51:
1.12    ! kristaps   52: static void              usage(const char *, const char *);
1.6       kristaps   53: static int               optswarn(struct mmain *, char *);
                     54: static int               optsopt(struct mmain *, char *);
1.1       kristaps   55: static int               parse(struct mmain *);
                     56: static void              msg_msg(void *, int, int, const char *);
                     57: static int               msg_err(void *, int, int, const char *);
                     58: static int               msg_warn(void *, int, int,
                     59:                                enum mdoc_warn, const char *);
                     60:
                     61: #ifdef __linux__
                     62: extern int               getsubopt(char **, char *const *, char **);
1.3       kristaps   63: extern size_t            strlcpy(char *, const char *, size_t);
                     64: extern size_t            strlcat(char *, const char *, size_t);
1.1       kristaps   65: #endif
                     66:
                     67:
1.2       kristaps   68: /*
                     69:  * Print our and our caller's usage message.
                     70:  */
1.1       kristaps   71: void
1.12    ! kristaps   72: usage(const char *help, const char *args)
1.1       kristaps   73: {
                     74:
1.12    ! kristaps   75:        warnx("usage: %s %s%s[-v] [-foption...] [-Wwarn...]%s%s",
        !            76:                        __progname,
        !            77:                        help ? help : "", help ? " " : "",
        !            78:                        args ? " " : "", args ? args : "");
1.1       kristaps   79: }
                     80:
                     81:
1.2       kristaps   82: /*
                     83:  * Allocate the convenience library and initialise some values.
                     84:  */
1.1       kristaps   85: struct mmain *
                     86: mmain_alloc(void)
                     87: {
                     88:        struct mmain    *p;
                     89:
                     90:        if (NULL == (p = calloc(1, sizeof(struct mmain))))
                     91:                err(1, "malloc");
                     92:
                     93:        return(p);
                     94: }
                     95:
                     96:
1.2       kristaps   97: /*
                     98:  * Parse command-line options.  Accepts a small (<28 char) opstring "u"
                     99:  * parameter (e.g. "ho:") or NULL, a corresponding "help" string (e.g.
                    100:  * "[-h] [-o output]" or NULL, a callback function for parsed arguments
                    101:  * and an opaque pointer argument for that function.
                    102:  */
1.1       kristaps  103: int
1.2       kristaps  104: mmain_getopt(struct mmain *p, int argc, char *argv[],
1.12    ! kristaps  105:                const char *help, const char *args,
        !           106:                const char *u, void *arg,
        !           107:                int (*getopt_cb)(void *, int, char *))
1.1       kristaps  108: {
1.2       kristaps  109:        int              c;
                    110:        char             opts[32]; /* XXX */
                    111:        size_t           sz;
                    112:
                    113:        extern int       optind;
1.1       kristaps  114:
1.6       kristaps  115:        sz = strlcpy(opts, "VvW:f:", 32);
1.2       kristaps  116:        assert(sz < 32);
1.1       kristaps  117:
1.2       kristaps  118:        if (u) {
                    119:                sz = strlcat(opts, u, 32);
                    120:                assert(sz < 32);
                    121:        }
1.1       kristaps  122:
1.3       kristaps  123:        optind = 1;
                    124:
1.2       kristaps  125:        /* LINTED */
                    126:        while (-1 != (c = getopt(argc, argv, opts)))
1.1       kristaps  127:                switch (c) {
1.6       kristaps  128:                case ('f'):
                    129:                        if ( ! optsopt(p, optarg))
1.12    ! kristaps  130:                                mmain_exit(p, 1);
1.6       kristaps  131:                        break;
1.1       kristaps  132:                case ('v'):
                    133:                        p->dbg++;
                    134:                        break;
1.5       kristaps  135:                case ('V'):
                    136:                        (void)printf("%s %s\n", __progname, VERSION);
1.12    ! kristaps  137:                        mmain_exit(p, 0);
        !           138:                        /* NOTREACHED */
1.1       kristaps  139:                case ('W'):
1.6       kristaps  140:                        if ( ! optswarn(p, optarg))
1.12    ! kristaps  141:                                mmain_exit(p, 1);
1.1       kristaps  142:                        break;
                    143:                case ('?'):
1.12    ! kristaps  144:                        usage(help, args);
        !           145:                        mmain_exit(p, 1);
        !           146:                        /* NOTREACHED */
1.1       kristaps  147:                default:
1.2       kristaps  148:                        assert(getopt_cb);
                    149:                        if ((*getopt_cb)(arg, c, optarg))
                    150:                                break;
1.12    ! kristaps  151:                        mmain_exit(p, 1);
        !           152:                        /* NOTREACHED */
1.1       kristaps  153:                }
                    154:
1.12    ! kristaps  155:        return(optind);
        !           156: }
        !           157:
        !           158:
        !           159: void
        !           160: mmain_reset(struct mmain *p)
        !           161: {
1.1       kristaps  162:
1.12    ! kristaps  163:        if (p->mdoc)
        !           164:                mdoc_free(p->mdoc);
        !           165:        p->mdoc = NULL;
1.1       kristaps  166: }
                    167:
                    168:
1.12    ! kristaps  169: void
        !           170: mmain_free(struct mmain *p)
1.1       kristaps  171: {
                    172:
                    173:        if (p->mdoc)
                    174:                mdoc_free(p->mdoc);
                    175:        free(p);
1.12    ! kristaps  176: }
        !           177:
        !           178:
        !           179: dead_pre void
        !           180: mmain_exit(struct mmain *p, int code)
        !           181: {
        !           182:
        !           183:        mmain_free(p);
1.1       kristaps  184:        exit(code);
                    185: }
                    186:
                    187:
1.12    ! kristaps  188: void
        !           189: mmain_prepare(struct mmain *p, const char *in)
1.1       kristaps  190: {
                    191:        struct stat      st;
                    192:
1.12    ! kristaps  193:        p->in = in;
        !           194:        p->fdin = STDIN_FILENO;
1.1       kristaps  195:
                    196:        if (0 != strcmp(p->in, "-"))
                    197:                if (-1 == (p->fdin = open(p->in, O_RDONLY, 0))) {
                    198:                        warn("%s", p->in);
1.12    ! kristaps  199:                        mmain_exit(p, 1);
1.1       kristaps  200:                }
                    201:
                    202:        /* Allocate a buffer to be BUFSIZ/block size. */
                    203:
                    204:        if (-1 == fstat(p->fdin, &st)) {
                    205:                warn("%s", p->in);
                    206:                p->bufsz = BUFSIZ;
                    207:        } else
1.9       kristaps  208:                p->bufsz = (size_t)MAX(st.st_blksize, BUFSIZ);
1.1       kristaps  209:
                    210:        p->buf = malloc(p->bufsz);
                    211:        if (NULL == p->buf)
                    212:                err(1, "malloc");
1.12    ! kristaps  213: }
        !           214:
        !           215:
        !           216: struct mdoc *
        !           217: mmain_process(struct mmain *p)
        !           218: {
        !           219:        int              c;
        !           220:        struct mdoc_cb   cb;
        !           221:
        !           222:        /* XXX - in mmain_alloc.*/
        !           223:        cb.mdoc_err = msg_err;
        !           224:        cb.mdoc_warn = msg_warn;
        !           225:        cb.mdoc_msg = msg_msg;
1.1       kristaps  226:
                    227:        /* Allocate the parser. */
                    228:
1.7       kristaps  229:        p->mdoc = mdoc_alloc(p, p->pflags, &cb);
1.1       kristaps  230:
                    231:        /* Parse the input file. */
                    232:
                    233:        c = parse(p);
                    234:        free(p->buf);
                    235:
                    236:        if (STDIN_FILENO != p->fdin)
                    237:                if (-1 == close(p->fdin))
                    238:                        warn("%s", p->in);
                    239:
                    240:        return(c ? p->mdoc : NULL);
                    241: }
                    242:
                    243:
1.12    ! kristaps  244: struct mdoc *
        !           245: mmain_mdoc(struct mmain *p, const char *in)
        !           246: {
        !           247:
        !           248:        mmain_prepare(p, in);
        !           249:        return(mmain_process(p));
        !           250: }
        !           251:
        !           252:
1.1       kristaps  253: static int
1.6       kristaps  254: optsopt(struct mmain *p, char *arg)
                    255: {
                    256:        char            *v;
1.10      kristaps  257:        char            *toks[] = { "ign-scope", "ign-escape",
                    258:                                    "ign-macro", NULL };
1.6       kristaps  259:
                    260:        while (*arg)
                    261:                switch (getsubopt(&arg, toks, &v)) {
                    262:                case (0):
                    263:                        p->pflags |= MDOC_IGN_SCOPE;
                    264:                        break;
1.7       kristaps  265:                case (1):
                    266:                        p->pflags |= MDOC_IGN_ESCAPE;
                    267:                        break;
1.10      kristaps  268:                case (2):
                    269:                        p->pflags |= MDOC_IGN_MACRO;
                    270:                        break;
1.6       kristaps  271:                default:
1.10      kristaps  272:                        warnx("unknown -f argument");
1.6       kristaps  273:                        return(0);
                    274:                }
                    275:
                    276:        return(1);
                    277: }
                    278:
                    279:
                    280: static int
                    281: optswarn(struct mmain *p, char *arg)
1.1       kristaps  282: {
                    283:        char            *v;
                    284:        char            *toks[] = { "all", "compat",
                    285:                                "syntax", "error", NULL };
                    286:
                    287:        while (*arg)
                    288:                switch (getsubopt(&arg, toks, &v)) {
                    289:                case (0):
                    290:                        p->warn |= MD_WARN_ALL;
                    291:                        break;
                    292:                case (1):
                    293:                        p->warn |= MD_WARN_COMPAT;
                    294:                        break;
                    295:                case (2):
                    296:                        p->warn |= MD_WARN_SYNTAX;
                    297:                        break;
                    298:                case (3):
                    299:                        p->warn |= MD_WARN_ERR;
                    300:                        break;
                    301:                default:
1.10      kristaps  302:                        warnx("unknown -W argument");
1.1       kristaps  303:                        return(0);
                    304:                }
                    305:
                    306:        return(1);
                    307: }
                    308:
                    309:
                    310: static int
                    311: parse(struct mmain *p)
                    312: {
1.8       kristaps  313:        ssize_t          sz;
1.10      kristaps  314:        int              j, i, pos, len, lnn;
                    315:        char            *ln;
1.1       kristaps  316:
1.10      kristaps  317:        for (ln = NULL, lnn = 1, len = pos = 0; ; ) {
1.1       kristaps  318:                if (-1 == (sz = read(p->fdin, p->buf, p->bufsz))) {
                    319:                        warn("%s", p->in);
                    320:                        return(0);
                    321:                } else if (0 == sz)
                    322:                        break;
                    323:
1.8       kristaps  324:                for (i = 0; i < (int)sz; i++) {
                    325:                        if (pos >= len) {
                    326:                                len += MD_LINE_SZ;
1.10      kristaps  327:                                ln = realloc(ln, (size_t)len);
                    328:                                if (NULL == ln)
1.8       kristaps  329:                                        err(1, "realloc");
                    330:                        }
                    331:
1.1       kristaps  332:                        if ('\n' != p->buf[i]) {
1.10      kristaps  333:                                ln[pos++] = p->buf[i];
1.8       kristaps  334:                                continue;
1.1       kristaps  335:                        }
1.8       kristaps  336:
1.10      kristaps  337:                        /* Check for escaped newline.  */
                    338:
                    339:                        if (pos > 0 && '\\' == ln[pos - 1]) {
                    340:                                for (j = pos - 1; j >= 0; j--)
                    341:                                        if ('\\' != ln[j])
                    342:                                                break;
                    343:
                    344:                                if ( ! ((pos - j) % 2)) {
                    345:                                        pos--;
                    346:                                        lnn++;
                    347:                                        continue;
                    348:                                }
                    349:                        }
                    350:
                    351:                        ln[pos] = 0;
1.11      kristaps  352:                        if ( ! mdoc_parseln(p->mdoc, lnn, ln)) {
                    353:                                free(ln);
1.1       kristaps  354:                                return(0);
1.11      kristaps  355:                        }
1.1       kristaps  356:                        lnn++;
                    357:                        pos = 0;
                    358:                }
                    359:        }
                    360:
1.11      kristaps  361:        if (ln)
                    362:                free(ln);
1.10      kristaps  363:        if (pos > 0)
                    364:                warnx("%s: file not eof-terminated", p->in);
1.1       kristaps  365:        return(mdoc_endparse(p->mdoc));
                    366: }
                    367:
                    368:
                    369: static int
                    370: msg_err(void *arg, int line, int col, const char *msg)
                    371: {
                    372:        struct mmain     *p;
                    373:
                    374:        p = (struct mmain *)arg;
                    375:
                    376:        warnx("%s:%d: error: %s (column %d)",
                    377:                        p->in, line, msg, col);
                    378:        return(0);
                    379: }
                    380:
                    381:
                    382: static void
                    383: msg_msg(void *arg, int line, int col, const char *msg)
                    384: {
                    385:        struct mmain     *p;
                    386:
                    387:        p = (struct mmain *)arg;
                    388:
                    389:        if (0 == p->dbg)
                    390:                return;
                    391:
                    392:        warnx("%s:%d: debug: %s (column %d)",
                    393:                        p->in, line, msg, col);
                    394: }
                    395:
                    396:
                    397: static int
                    398: msg_warn(void *arg, int line, int col,
                    399:                enum mdoc_warn type, const char *msg)
                    400: {
                    401:        struct mmain     *p;
                    402:
                    403:        p = (struct mmain *)arg;
                    404:
                    405:        switch (type) {
                    406:        case (WARN_COMPAT):
                    407:                if (p->warn & MD_WARN_COMPAT)
                    408:                        break;
                    409:                return(1);
                    410:        case (WARN_SYNTAX):
                    411:                if (p->warn & MD_WARN_SYNTAX)
                    412:                        break;
                    413:                return(1);
                    414:        }
                    415:
                    416:        warnx("%s:%d: warning: %s (column %d)",
                    417:                        p->in, line, msg, col);
                    418:
                    419:        if ( ! (p->warn & MD_WARN_ERR))
                    420:                return(1);
                    421:
                    422:        warnx("%s: considering warnings as errors", __progname);
                    423:        return(0);
                    424: }

CVSweb