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

Annotation of mandoc/main.c, Revision 1.1

1.1     ! kristaps    1: /* $Id: mdocterm.c,v 1.49 2009/03/19 11:49:00 kristaps Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
        !             4:  *
        !             5:  * Permission to use, copy, modify, and distribute this software for any
        !             6:  * purpose with or without fee is hereby granted, provided that the
        !             7:  * above copyright notice and this permission notice appear in all
        !             8:  * copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
        !            11:  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
        !            12:  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
        !            13:  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
        !            14:  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
        !            15:  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
        !            16:  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
        !            17:  * PERFORMANCE OF THIS SOFTWARE.
        !            18:  */
        !            19: #include <sys/stat.h>
        !            20:
        !            21: #include <assert.h>
        !            22: #include <err.h>
        !            23: #include <fcntl.h>
        !            24: #include <stdio.h>
        !            25: #include <stdlib.h>
        !            26: #include <string.h>
        !            27: #include <unistd.h>
        !            28:
        !            29: #include "mdoc.h"
        !            30:
        !            31: #define        WARN_WALL         0x03          /* All-warnings mask. */
        !            32: #define        WARN_WCOMPAT     (1 << 0)       /* Compatibility warnings. */
        !            33: #define        WARN_WSYNTAX     (1 << 1)       /* Syntax warnings. */
        !            34: #define        WARN_WERR        (1 << 2)       /* Warnings->errors. */
        !            35:
        !            36: enum outt {
        !            37:        OUTT_ASCII,
        !            38:        OUTT_LATIN1,
        !            39:        OUTT_UTF8,
        !            40:        OUTT_TREE,
        !            41:        OUTT_LINT
        !            42: };
        !            43:
        !            44: typedef        int             (*out_run)(void *, const struct mdoc *);
        !            45: typedef        void            (*out_free)(void *);
        !            46:
        !            47: extern char             *__progname;
        !            48:
        !            49: extern void             *ascii_alloc(void);
        !            50: extern void             *latin1_alloc(void);
        !            51: extern void             *utf8_alloc(void);
        !            52: extern int               terminal_run(void *, const struct mdoc *);
        !            53: extern int               tree_run(void *, const struct mdoc *);
        !            54: extern void              terminal_free(void *);
        !            55:
        !            56: __dead static void       version(void);
        !            57: __dead static void       usage(void);
        !            58: static int               foptions(int *, char *);
        !            59: static int               toptions(enum outt *, char *);
        !            60: static int               woptions(int *, char *);
        !            61: static int               merr(void *, int, int, const char *);
        !            62: static int               mwarn(void *, int, int,
        !            63:                                enum mdoc_warn, const char *);
        !            64: static int               file(char **, size_t *, char **, size_t *,
        !            65:                                const char *, struct mdoc *);
        !            66: static int               fdesc(char **, size_t *, char **, size_t *,
        !            67:                                const char *, int, struct mdoc *);
        !            68:
        !            69:
        !            70: int
        !            71: main(int argc, char *argv[])
        !            72: {
        !            73:        int              c, rc, fflags, wflags;
        !            74:        struct mdoc_cb   cb;
        !            75:        struct mdoc     *mdoc;
        !            76:        char            *buf, *line;
        !            77:        size_t           bufsz, linesz;
        !            78:        void            *outdata;
        !            79:        enum outt        outtype;
        !            80:        out_run          outrun;
        !            81:        out_free         outfree;
        !            82:
        !            83:        fflags = wflags = 0;
        !            84:        outtype = OUTT_ASCII;
        !            85:
        !            86:        /* LINTED */
        !            87:        while (-1 != (c = getopt(argc, argv, "f:VW:T:")))
        !            88:                switch (c) {
        !            89:                case ('f'):
        !            90:                        if ( ! foptions(&fflags, optarg))
        !            91:                                return(0);
        !            92:                        break;
        !            93:                case ('T'):
        !            94:                        if ( ! toptions(&outtype, optarg))
        !            95:                                return(0);
        !            96:                        break;
        !            97:                case ('W'):
        !            98:                        if ( ! woptions(&wflags, optarg))
        !            99:                                return(0);
        !           100:                        break;
        !           101:                case ('V'):
        !           102:                        version();
        !           103:                        /* NOTREACHED */
        !           104:                default:
        !           105:                        usage();
        !           106:                        /* NOTREACHED */
        !           107:                }
        !           108:
        !           109:        argc -= optind;
        !           110:        argv += optind;
        !           111:
        !           112:        /*
        !           113:         * Allocate the appropriate front-end.  Note that utf8, ascii
        !           114:         * and latin1 all resolve to the terminal front-end with
        !           115:         * different encodings (see terminal.c).  Not all frontends have
        !           116:         * cleanup or alloc routines.
        !           117:         */
        !           118:
        !           119:        switch (outtype) {
        !           120:        case (OUTT_LATIN1):
        !           121:                outdata = latin1_alloc();
        !           122:                outrun = terminal_run;
        !           123:                outfree = terminal_free;
        !           124:                break;
        !           125:        case (OUTT_UTF8):
        !           126:                outdata = utf8_alloc();
        !           127:                outrun = terminal_run;
        !           128:                outfree = terminal_free;
        !           129:                break;
        !           130:        case (OUTT_TREE):
        !           131:                outdata = NULL;
        !           132:                outrun = tree_run;
        !           133:                outfree = NULL;
        !           134:                break;
        !           135:        case (OUTT_LINT):
        !           136:                outdata = NULL;
        !           137:                outrun = NULL;
        !           138:                outfree = NULL;
        !           139:                break;
        !           140:        default:
        !           141:                outdata = ascii_alloc();
        !           142:                outrun = terminal_run;
        !           143:                outfree = terminal_free;
        !           144:                break;
        !           145:        }
        !           146:
        !           147:        /*
        !           148:         * All callbacks route into here, where we print them onto the
        !           149:         * screen.  XXX - for now, no path for debugging messages.
        !           150:         */
        !           151:
        !           152:        cb.mdoc_msg = NULL;
        !           153:        cb.mdoc_err = merr;
        !           154:        cb.mdoc_warn = mwarn;
        !           155:
        !           156:        buf = line = NULL;
        !           157:        bufsz = linesz = 0;
        !           158:
        !           159:        mdoc = mdoc_alloc(&wflags, fflags, &cb);
        !           160:
        !           161:        while (*argv) {
        !           162:                if ( ! file(&line, &linesz, &buf, &bufsz, *argv, mdoc))
        !           163:                        break;
        !           164:                if (outrun && ! (*outrun)(outdata, mdoc))
        !           165:                        break;
        !           166:
        !           167:                /* Reset the parser for another file. */
        !           168:                mdoc_reset(mdoc);
        !           169:                argv++;
        !           170:        }
        !           171:
        !           172:        rc = NULL == *argv;
        !           173:
        !           174:        if (buf)
        !           175:                free(buf);
        !           176:        if (line)
        !           177:                free(line);
        !           178:        if (outfree)
        !           179:                (*outfree)(outdata);
        !           180:
        !           181:        mdoc_free(mdoc);
        !           182:
        !           183:        return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
        !           184: }
        !           185:
        !           186:
        !           187: __dead static void
        !           188: version(void)
        !           189: {
        !           190:
        !           191:        (void)printf("%s %s\n", __progname, VERSION);
        !           192:        exit(0);
        !           193:        /* NOTREACHED */
        !           194: }
        !           195:
        !           196:
        !           197: __dead static void
        !           198: usage(void)
        !           199: {
        !           200:
        !           201:        (void)fprintf(stderr, "usage: %s\n", __progname);
        !           202:        exit(1);
        !           203:        /* NOTREACHED */
        !           204: }
        !           205:
        !           206:
        !           207: static int
        !           208: file(char **ln, size_t *lnsz, char **buf, size_t *bufsz,
        !           209:                const char *file, struct mdoc *mdoc)
        !           210: {
        !           211:        int              fd, c;
        !           212:
        !           213:        if (-1 == (fd = open(file, O_RDONLY, 0))) {
        !           214:                warn("%s", file);
        !           215:                return(0);
        !           216:        }
        !           217:
        !           218:        c = fdesc(ln, lnsz, buf, bufsz, file, fd, mdoc);
        !           219:
        !           220:        if (-1 == close(fd))
        !           221:                warn("%s", file);
        !           222:
        !           223:        return(c);
        !           224: }
        !           225:
        !           226:
        !           227: static int
        !           228: fdesc(char **lnp, size_t *lnsz, char **bufp, size_t *bufsz,
        !           229:                const char *f, int fd, struct mdoc *mdoc)
        !           230: {
        !           231:        size_t           sz;
        !           232:        ssize_t          ssz;
        !           233:        struct stat      st;
        !           234:        int              j, i, pos, lnn;
        !           235:        char            *ln, *buf;
        !           236:
        !           237:        buf = *bufp;
        !           238:        ln = *lnp;
        !           239:
        !           240:        /*
        !           241:         * Two buffers: ln and buf.  buf is the input buffer, optimised
        !           242:         * for each file's block size.  ln is a line buffer.  Both
        !           243:         * growable, hence passed in by ptr-ptr.
        !           244:         */
        !           245:
        !           246:        if (-1 == fstat(fd, &st)) {
        !           247:                warnx("%s", f);
        !           248:                sz = BUFSIZ;
        !           249:        } else
        !           250:                sz = (unsigned)BUFSIZ > st.st_blksize ?
        !           251:                        (size_t)BUFSIZ : st.st_blksize;
        !           252:
        !           253:        if (sz > *bufsz) {
        !           254:                if (NULL == (buf = realloc(buf, sz)))
        !           255:                        err(1, "realloc");
        !           256:                *bufp = buf;
        !           257:                *bufsz = sz;
        !           258:        }
        !           259:
        !           260:        /*
        !           261:         * Fill buf with file blocksize and parse newlines into ln.
        !           262:         */
        !           263:
        !           264:        for (lnn = 1, pos = 0; ; ) {
        !           265:                if (-1 == (ssz = read(fd, buf, sz))) {
        !           266:                        warn("%s", f);
        !           267:                        return(0);
        !           268:                } else if (0 == ssz)
        !           269:                        break;
        !           270:
        !           271:                for (i = 0; i < (int)ssz; i++) {
        !           272:                        if (pos >= (int)*lnsz) {
        !           273:                                *lnsz += 256; /* Step-size. */
        !           274:                                ln = realloc(ln, *lnsz);
        !           275:                                if (NULL == ln)
        !           276:                                        err(1, "realloc");
        !           277:                                *lnp = ln;
        !           278:                        }
        !           279:
        !           280:                        if ('\n' != buf[i]) {
        !           281:                                ln[pos++] = buf[i];
        !           282:                                continue;
        !           283:                        }
        !           284:
        !           285:                        /* Check for CPP-escaped newline.  */
        !           286:
        !           287:                        if (pos > 0 && '\\' == ln[pos - 1]) {
        !           288:                                for (j = pos - 1; j >= 0; j--)
        !           289:                                        if ('\\' != ln[j])
        !           290:                                                break;
        !           291:
        !           292:                                if ( ! ((pos - j) % 2)) {
        !           293:                                        pos--;
        !           294:                                        lnn++;
        !           295:                                        continue;
        !           296:                                }
        !           297:                        }
        !           298:
        !           299:                        ln[pos] = 0;
        !           300:                        if ( ! mdoc_parseln(mdoc, lnn, ln))
        !           301:                                return(0);
        !           302:                        lnn++;
        !           303:                        pos = 0;
        !           304:                }
        !           305:        }
        !           306:
        !           307:        return(mdoc_endparse(mdoc));
        !           308: }
        !           309:
        !           310:
        !           311: static int
        !           312: toptions(enum outt *tflags, char *arg)
        !           313: {
        !           314:
        !           315:        if (0 == strcmp(arg, "ascii"))
        !           316:                *tflags = OUTT_ASCII;
        !           317:        else if (0 == strcmp(arg, "latin1"))
        !           318:                *tflags = OUTT_LATIN1;
        !           319:        else if (0 == strcmp(arg, "utf8"))
        !           320:                *tflags = OUTT_UTF8;
        !           321:        else if (0 == strcmp(arg, "lint"))
        !           322:                *tflags = OUTT_LINT;
        !           323:        else if (0 == strcmp(arg, "tree"))
        !           324:                *tflags = OUTT_TREE;
        !           325:        else {
        !           326:                warnx("bad argument: -T%s", arg);
        !           327:                return(0);
        !           328:        }
        !           329:
        !           330:        return(1);
        !           331: }
        !           332:
        !           333:
        !           334: /*
        !           335:  * Parse out the options for [-fopt...] setting compiler options.  These
        !           336:  * can be comma-delimited or called again.
        !           337:  */
        !           338: static int
        !           339: foptions(int *fflags, char *arg)
        !           340: {
        !           341:        char            *v;
        !           342:        char            *toks[4];
        !           343:
        !           344:        toks[0] = "ign-scope";
        !           345:        toks[1] = "ign-escape";
        !           346:        toks[2] = "ign-macro";
        !           347:        toks[3] = NULL;
        !           348:
        !           349:        while (*arg)
        !           350:                switch (getsubopt(&arg, toks, &v)) {
        !           351:                case (0):
        !           352:                        *fflags |= MDOC_IGN_SCOPE;
        !           353:                        break;
        !           354:                case (1):
        !           355:                        *fflags |= MDOC_IGN_ESCAPE;
        !           356:                        break;
        !           357:                case (2):
        !           358:                        *fflags |= MDOC_IGN_MACRO;
        !           359:                        break;
        !           360:                default:
        !           361:                        warnx("bad argument: -f%s", arg);
        !           362:                        return(0);
        !           363:                }
        !           364:
        !           365:        return(1);
        !           366: }
        !           367:
        !           368:
        !           369: /*
        !           370:  * Parse out the options for [-Werr...], which sets warning modes.
        !           371:  * These can be comma-delimited or called again.
        !           372:  */
        !           373: static int
        !           374: woptions(int *wflags, char *arg)
        !           375: {
        !           376:        char            *v;
        !           377:        char            *toks[5];
        !           378:
        !           379:        toks[0] = "all";
        !           380:        toks[1] = "compat";
        !           381:        toks[2] = "syntax";
        !           382:        toks[3] = "error";
        !           383:        toks[4] = NULL;
        !           384:
        !           385:        while (*arg)
        !           386:                switch (getsubopt(&arg, toks, &v)) {
        !           387:                case (0):
        !           388:                        *wflags |= WARN_WALL;
        !           389:                        break;
        !           390:                case (1):
        !           391:                        *wflags |= WARN_WCOMPAT;
        !           392:                        break;
        !           393:                case (2):
        !           394:                        *wflags |= WARN_WSYNTAX;
        !           395:                        break;
        !           396:                case (3):
        !           397:                        *wflags |= WARN_WERR;
        !           398:                        break;
        !           399:                default:
        !           400:                        warnx("bad argument: -W%s", arg);
        !           401:                        return(0);
        !           402:                }
        !           403:
        !           404:        return(1);
        !           405: }
        !           406:
        !           407:
        !           408: static int
        !           409: merr(void *arg, int line, int col, const char *msg)
        !           410: {
        !           411:
        !           412:        warnx("error: %s (line %d, column %d)", msg, line, col);
        !           413:        return(0);
        !           414: }
        !           415:
        !           416:
        !           417: static int
        !           418: mwarn(void *arg, int line, int col,
        !           419:                enum mdoc_warn type, const char *msg)
        !           420: {
        !           421:        int              flags;
        !           422:        char            *wtype;
        !           423:
        !           424:        flags = *(int *)arg;
        !           425:        wtype = NULL;
        !           426:
        !           427:        switch (type) {
        !           428:        case (WARN_COMPAT):
        !           429:                wtype = "compat";
        !           430:                if (flags & WARN_WCOMPAT)
        !           431:                        break;
        !           432:                return(1);
        !           433:        case (WARN_SYNTAX):
        !           434:                wtype = "syntax";
        !           435:                if (flags & WARN_WSYNTAX)
        !           436:                        break;
        !           437:                return(1);
        !           438:        }
        !           439:
        !           440:        assert(wtype);
        !           441:        warnx("%s warning: %s (line %d, column %d)",
        !           442:                        wtype, msg, line, col);
        !           443:
        !           444:        if ( ! (flags & WARN_WERR))
        !           445:                return(1);
        !           446:
        !           447:        warnx("%s: considering warnings as errors",
        !           448:                        __progname);
        !           449:        return(0);
        !           450: }
        !           451:
        !           452:

CVSweb