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

Annotation of mandoc/mdocml.c, Revision 1.21

1.21    ! kristaps    1: /* $Id: mdocml.c,v 1.20 2008/12/10 14:42:46 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:  */
1.21    ! kristaps   19: #include <sys/stat.h>
1.1       kristaps   20: #include <sys/param.h>
                     21:
                     22: #include <assert.h>
1.21    ! kristaps   23: #include <fcntl.h>
1.1       kristaps   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:
1.21    ! kristaps   31: #include "mdoc.h"
1.1       kristaps   32:
1.21    ! kristaps   33: #define        MD_LINE_SZ      (256)
1.2       kristaps   34:
1.21    ! kristaps   35: struct md_parse {
        !            36:        int              warn;
        !            37: #define        MD_WARN_ALL     (1 << 0)
        !            38: #define        MD_WARN_ERR     (1 << 1)
        !            39:        int              dbg;
        !            40:        struct mdoc     *mdoc;
        !            41:        char            *buf;
        !            42:        u_long           bufsz;
        !            43:        char            *name;
        !            44:        int              fd;
        !            45:        int              lnn;
        !            46:        char            *line;
        !            47: };
1.17      kristaps   48:
1.9       kristaps   49: static void             usage(void);
                     50:
1.21    ! kristaps   51: static int              parse_begin(struct md_parse *);
        !            52: static int              parse_leave(struct md_parse *, int);
        !            53: static int              io_begin(struct md_parse *);
        !            54: static int              io_leave(struct md_parse *, int);
        !            55: static int              buf_begin(struct md_parse *);
        !            56: static int              buf_leave(struct md_parse *, int);
        !            57:
        !            58: static int              msg_err(void *, int, int, enum mdoc_err);
        !            59: static int              msg_warn(void *, int, int, enum mdoc_warn);
        !            60: static void             msg_msg(void *, int, const char *);
1.1       kristaps   61:
1.19      kristaps   62: #ifdef __linux__
                     63: extern int              getsubopt(char **, char *const *, char **);
                     64: #endif
                     65:
1.1       kristaps   66: int
                     67: main(int argc, char *argv[])
                     68: {
                     69:        int              c;
1.21    ! kristaps   70:        struct md_parse  parser;
        !            71:        char            *opts, *v;
1.18      kristaps   72: #define ALL             0
                     73: #define ERROR           1
                     74:        char            *toks[] = { "all", "error", NULL };
1.1       kristaps   75:
                     76:        extern char     *optarg;
                     77:        extern int       optind;
                     78:
1.21    ! kristaps   79:        (void)memset(&parser, 0, sizeof(struct md_parse));
1.17      kristaps   80:
1.21    ! kristaps   81:        while (-1 != (c = getopt(argc, argv, "vW:")))
1.1       kristaps   82:                switch (c) {
1.13      kristaps   83:                case ('v'):
1.21    ! kristaps   84:                        parser.dbg++;
1.13      kristaps   85:                        break;
                     86:                case ('W'):
1.18      kristaps   87:                        opts = optarg;
                     88:                        while (*opts)
                     89:                                switch (getsubopt(&opts, toks, &v)) {
                     90:                                case (ALL):
1.21    ! kristaps   91:                                        parser.warn |= MD_WARN_ALL;
1.18      kristaps   92:                                        break;
                     93:                                case (ERROR):
1.21    ! kristaps   94:                                        parser.warn |= MD_WARN_ERR;
1.18      kristaps   95:                                        break;
                     96:                                default:
                     97:                                        usage();
                     98:                                        return(1);
                     99:                                }
1.13      kristaps  100:                        break;
1.1       kristaps  101:                default:
                    102:                        usage();
                    103:                        return(1);
                    104:                }
                    105:
                    106:        argv += optind;
1.4       kristaps  107:        argc -= optind;
1.1       kristaps  108:
1.21    ! kristaps  109:        parser.name = "-";
1.4       kristaps  110:        if (1 == argc)
1.21    ! kristaps  111:                parser.name = *argv++;
        !           112:
        !           113:        if ( ! io_begin(&parser))
        !           114:                return(EXIT_FAILURE);
1.1       kristaps  115:
1.21    ! kristaps  116:        return(EXIT_SUCCESS);
1.1       kristaps  117: }
                    118:
                    119:
                    120: static int
1.21    ! kristaps  121: io_leave(struct md_parse *p, int code)
1.1       kristaps  122: {
                    123:
1.21    ! kristaps  124:        if (-1 == p->fd || STDIN_FILENO == p->fd)
        !           125:                return(code);
        !           126:
        !           127:        if (-1 == close(p->fd)) {
        !           128:                warn("%s", p->name);
        !           129:                code = 0;
1.4       kristaps  130:        }
1.21    ! kristaps  131:        return(code);
        !           132: }
        !           133:
        !           134:
        !           135: static int
        !           136: io_begin(struct md_parse *p)
        !           137: {
        !           138:
        !           139:        p->fd = STDIN_FILENO;
        !           140:        if (0 != strncmp(p->name, "-", 1))
        !           141:                if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
        !           142:                        warn("%s", p->name);
        !           143:                        return(io_leave(p, 0));
        !           144:                }
1.1       kristaps  145:
1.21    ! kristaps  146:        return(io_leave(p, buf_begin(p)));
1.1       kristaps  147: }
                    148:
                    149:
                    150: static int
1.21    ! kristaps  151: buf_leave(struct md_parse *p, int code)
1.1       kristaps  152: {
1.4       kristaps  153:
1.21    ! kristaps  154:        if (p->buf)
        !           155:                free(p->buf);
        !           156:        return(code);
        !           157: }
1.1       kristaps  158:
                    159:
1.21    ! kristaps  160: static int
        !           161: buf_begin(struct md_parse *p)
        !           162: {
        !           163:        struct stat      st;
1.1       kristaps  164:
1.21    ! kristaps  165:        if (-1 == fstat(p->fd, &st)) {
        !           166:                warn("%s", p->name);
        !           167:                return(1);
        !           168:        }
        !           169:
        !           170:        p->bufsz = MAX(st.st_blksize, BUFSIZ);
        !           171:
        !           172:        if (NULL == (p->buf = malloc(p->bufsz))) {
        !           173:                warn("malloc");
        !           174:                return(buf_leave(p, 0));
        !           175:        }
        !           176:
        !           177:        return(buf_leave(p, parse_begin(p)));
        !           178: }
        !           179:
        !           180:
        !           181: static void
        !           182: print_node(const struct mdoc_node *n, int indent)
        !           183: {
        !           184:        const char      *p, *t;
        !           185:        int              i;
        !           186:
        !           187:        switch (n->type) {
        !           188:        case (MDOC_TEXT):
        !           189:                assert(NULL == n->child);
        !           190:                p = "<text>";
        !           191:                t = "text";
        !           192:                break;
        !           193:        case (MDOC_BODY):
        !           194:                p = mdoc_macronames[n->data.body.tok];
        !           195:                t = "block-body";
        !           196:                break;
        !           197:        case (MDOC_HEAD):
        !           198:                p = mdoc_macronames[n->data.head.tok];
        !           199:                t = "block-head";
        !           200:                break;
        !           201:        case (MDOC_ELEM):
        !           202:                assert(NULL == n->child);
        !           203:                p = mdoc_macronames[n->data.elem.tok];
        !           204:                t = "element";
        !           205:                break;
        !           206:        case (MDOC_BLOCK):
        !           207:                p = mdoc_macronames[n->data.block.tok];
        !           208:                t = "block";
        !           209:                break;
        !           210:        }
        !           211:
        !           212:        for (i = 0; i < indent; i++)
        !           213:                (void)printf("    ");
        !           214:        (void)printf("%s (%s)\n", p, t);
        !           215:
        !           216:        if (n->child)
        !           217:                print_node(n->child, indent + 1);
        !           218:        if (n->next)
        !           219:                print_node(n->next, indent);
        !           220: }
1.1       kristaps  221:
                    222:
1.21    ! kristaps  223: static int
        !           224: parse_leave(struct md_parse *p, int code)
        !           225: {
        !           226:        const struct mdoc_node *n;
        !           227:
        !           228:        if (p->mdoc) {
        !           229:                if ((n = mdoc_result(p->mdoc)))
        !           230:                        print_node(n, 0);
        !           231:                mdoc_free(p->mdoc);
        !           232:        }
        !           233:        return(code);
        !           234: }
        !           235:
        !           236:
        !           237: static int
        !           238: parse_begin(struct md_parse *p)
        !           239: {
        !           240:        ssize_t          sz, i;
        !           241:        size_t           pos;
        !           242:        char             line[256], sv[256];
        !           243:        struct mdoc_cb   cb;
        !           244:
        !           245:        cb.mdoc_err = msg_err;
        !           246:        cb.mdoc_warn = msg_warn;
        !           247:        cb.mdoc_msg = msg_msg;
        !           248:
        !           249:        if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
        !           250:                return(parse_leave(p, 0));
        !           251:
        !           252:        p->lnn = 1;
        !           253:        p->line = sv;
        !           254:
        !           255:        for (pos = 0; ; ) {
        !           256:                if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
        !           257:                        warn("%s", p->name);
        !           258:                        return(parse_leave(p, 0));
        !           259:                } else if (0 == sz)
        !           260:                        break;
        !           261:
        !           262:                for (i = 0; i < sz; i++) {
        !           263:                        if ('\n' != p->buf[i]) {
        !           264:                                if (pos < sizeof(line)) {
        !           265:                                        /* LINTED */
        !           266:                                        sv[pos] = p->buf[i];
        !           267:                                        line[pos++] = p->buf[i];
        !           268:                                        continue;
        !           269:                                }
        !           270:                                warnx("%s: line %d too long",
        !           271:                                                p->name, p->lnn);
        !           272:                                return(parse_leave(p, 0));
        !           273:                        }
        !           274:
        !           275:                        line[(int)pos] = sv[(int)pos] = 0;
        !           276:                        if ( ! mdoc_parseln(p->mdoc, line))
        !           277:                                return(parse_leave(p, 0));
1.1       kristaps  278:
1.21    ! kristaps  279:                        p->lnn++;
        !           280:                        pos = 0;
1.4       kristaps  281:                }
1.21    ! kristaps  282:        }
1.1       kristaps  283:
1.21    ! kristaps  284:        return(parse_leave(p, 1));
1.4       kristaps  285: }
1.1       kristaps  286:
                    287:
1.4       kristaps  288: static int
1.21    ! kristaps  289: msg_err(void *arg, int tok, int col, enum mdoc_err type)
        !           290: {
        !           291:        char             *fmt, *lit;
        !           292:        struct md_parse  *p;
        !           293:        int               i;
        !           294:
        !           295:        p = (struct md_parse *)arg;
        !           296:
        !           297:        fmt = lit = NULL;
        !           298:
        !           299:        switch (type) {
        !           300:        case (ERR_SYNTAX_QUOTE):
        !           301:                lit = "syntax: unterminated quotation";
        !           302:                break;
        !           303:        case (ERR_SYNTAX_WS):
        !           304:                lit = "syntax: whitespace in argument";
        !           305:                break;
        !           306:        case (ERR_SCOPE_BREAK):
        !           307:                /* Which scope is broken? */
        !           308:                fmt = "macro `%s' breaks prior explicit scope";
        !           309:                break;
        !           310:        case (ERR_MACRO_NOTSUP):
        !           311:                fmt = "macro `%s' not supported";
        !           312:                break;
        !           313:        case (ERR_MACRO_NOTCALL):
        !           314:                fmt = "macro `%s' not callable";
        !           315:                break;
        !           316:        case (ERR_ARGS_GE1):
        !           317:                fmt = "macro `%s' expects one or more arguments";
        !           318:                break;
        !           319:        default:
        !           320:                abort();
        !           321:                /* NOTREACHED */
        !           322:        }
        !           323:
        !           324:        if (fmt) {
        !           325:                (void)fprintf(stderr, "%s:%d: error: ",
        !           326:                                p->name, p->lnn);
        !           327:                (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
        !           328:        } else
        !           329:                (void)fprintf(stderr, "%s:%d: error: %s",
        !           330:                                p->name, p->lnn, lit);
        !           331:
        !           332:        if (p->dbg < 1) {
        !           333:                (void)fprintf(stderr, " (column %d)\n", col);
        !           334:                return(0);
        !           335:        }
        !           336:
        !           337:        (void)fprintf(stderr, "\nFrom: %s\n      ", p->line);
        !           338:        for (i = 0; i < col; i++)
        !           339:                (void)fprintf(stderr, " ");
        !           340:        (void)fprintf(stderr, "^\n");
        !           341:
        !           342:        return(0);
        !           343: }
        !           344:
        !           345:
        !           346: static void
        !           347: msg_msg(void *arg, int col, const char *msg)
1.4       kristaps  348: {
1.21    ! kristaps  349:        struct md_parse  *p;
        !           350:        int               i;
        !           351:
        !           352:        p = (struct md_parse *)arg;
        !           353:
        !           354:        if (p->dbg < 2)
        !           355:                return;
        !           356:
        !           357:        (void)printf("%s:%d: %s", p->name, p->lnn, msg);
        !           358:
        !           359:        if (p->dbg < 3) {
        !           360:                (void)printf(" (column %d)\n", col);
        !           361:                return;
        !           362:        }
        !           363:
        !           364:        (void)printf("\nFrom: %s\n      ", p->line);
        !           365:        for (i = 0; i < col; i++)
        !           366:                (void)printf(" ");
        !           367:        (void)printf("^\n");
1.1       kristaps  368: }
                    369:
                    370:
                    371: static int
1.21    ! kristaps  372: msg_warn(void *arg, int tok, int col, enum mdoc_warn type)
1.1       kristaps  373: {
1.21    ! kristaps  374:        char             *fmt, *lit;
        !           375:        struct md_parse  *p;
        !           376:        int               i;
        !           377:        extern char      *__progname;
1.1       kristaps  378:
1.21    ! kristaps  379:        p = (struct md_parse *)arg;
1.1       kristaps  380:
1.21    ! kristaps  381:        if ( ! (p->warn & MD_WARN_ALL))
1.1       kristaps  382:                return(1);
1.21    ! kristaps  383:
        !           384:        fmt = lit = NULL;
        !           385:
        !           386:        switch (type) {
        !           387:        case (WARN_SYNTAX_WS_EOLN):
        !           388:                lit = "syntax: whitespace at end-of-line";
        !           389:                break;
        !           390:        case (WARN_SYNTAX_MACLIKE):
        !           391:                lit = "syntax: macro-like argument";
        !           392:                break;
        !           393:        case (WARN_ARGS_GE1):
        !           394:                fmt = "macro `%s' suggests one or more arguments";
        !           395:                break;
        !           396:        default:
        !           397:                abort();
        !           398:                /* NOTREACHED */
1.1       kristaps  399:        }
                    400:
1.21    ! kristaps  401:        if (fmt) {
        !           402:                (void)fprintf(stderr, "%s:%d: warning: ",
        !           403:                                p->name, p->lnn);
        !           404:                (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
        !           405:        } else
        !           406:                (void)fprintf(stderr, "%s:%d: warning: %s",
        !           407:                                p->name, p->lnn, lit);
        !           408:
        !           409:        if (p->dbg >= 1) {
        !           410:                (void)fprintf(stderr, "\nFrom: %s\n      ", p->line);
        !           411:                for (i = 0; i < col; i++)
        !           412:                        (void)fprintf(stderr, " ");
        !           413:                (void)fprintf(stderr, "^\n");
        !           414:        } else
        !           415:                (void)fprintf(stderr, " (column %d)\n", col);
        !           416:
        !           417:        if (p->warn & MD_WARN_ERR) {
        !           418:                (void)fprintf(stderr, "%s: considering warnings as "
        !           419:                                "errors\n", __progname);
        !           420:                return(0);
1.1       kristaps  421:        }
                    422:
1.21    ! kristaps  423:        return(1);
1.1       kristaps  424: }
                    425:
                    426:
                    427: static void
                    428: usage(void)
                    429: {
                    430:        extern char     *__progname;
                    431:
1.21    ! kristaps  432:        (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
1.19      kristaps  433:                        __progname);
1.1       kristaps  434: }
1.18      kristaps  435:

CVSweb