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

Annotation of mandoc/mdocml.c, Revision 1.44

1.44    ! kristaps    1: /* $Id: mdocml.c,v 1.43 2009/01/15 15:59:19 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.44    ! kristaps   33: #define        xfprintf        (void)fprintf
        !            34: #define        xprintf         (void)printf
        !            35: #define        xvfprintf       (void)fvprintf
        !            36:
        !            37: #define        MD_LINE_SZ      (256)           /* Max input line size. */
1.2       kristaps   38:
1.21      kristaps   39: struct md_parse {
1.44    ! kristaps   40:        int              warn;          /* Warning flags. */
        !            41: #define        MD_WARN_SYNTAX  (1 << 0)        /* Show syntax warnings. */
        !            42: #define        MD_WARN_COMPAT  (1 << 1)        /* Show compat warnings. */
        !            43: #define        MD_WARN_ALL     (0x03)          /* Show all warnings. */
        !            44: #define        MD_WARN_ERR     (1 << 2)        /* Make warnings->errors. */
        !            45:        int              dbg;           /* Debug level. */
        !            46:        struct mdoc     *mdoc;          /* Active parser. */
        !            47:        char            *buf;           /* Input buffer. */
        !            48:        u_long           bufsz;         /* Input buffer size. */
        !            49:        char            *name;          /* Input file name. */
        !            50:        int              fd;            /* Input file desc. */
1.21      kristaps   51: };
1.17      kristaps   52:
1.44    ! kristaps   53: extern char            *__progname;
        !            54:
1.9       kristaps   55: static void             usage(void);
                     56:
1.21      kristaps   57: static int              parse_begin(struct md_parse *);
                     58: static int              parse_leave(struct md_parse *, int);
                     59: static int              io_begin(struct md_parse *);
                     60: static int              io_leave(struct md_parse *, int);
                     61: static int              buf_begin(struct md_parse *);
                     62: static int              buf_leave(struct md_parse *, int);
                     63:
1.37      kristaps   64: static void             msg_msg(void *, int, int, const char *);
1.44    ! kristaps   65: static int              msg_err(void *, int, int, const char *);
        !            66: static int              msg_warn(void *, int, int,
        !            67:                                enum mdoc_warn, const char *);
1.1       kristaps   68:
1.19      kristaps   69: #ifdef __linux__
                     70: extern int              getsubopt(char **, char *const *, char **);
                     71: #endif
                     72:
1.1       kristaps   73: int
                     74: main(int argc, char *argv[])
                     75: {
                     76:        int              c;
1.21      kristaps   77:        struct md_parse  parser;
                     78:        char            *opts, *v;
1.18      kristaps   79: #define ALL             0
1.44    ! kristaps   80: #define COMPAT          1
        !            81: #define SYNTAX          2
        !            82: #define ERROR           3
        !            83:        char            *toks[] = { "all", "compat", "syntax",
        !            84:                                    "error", NULL };
1.1       kristaps   85:
                     86:        extern char     *optarg;
                     87:        extern int       optind;
                     88:
1.21      kristaps   89:        (void)memset(&parser, 0, sizeof(struct md_parse));
1.17      kristaps   90:
1.21      kristaps   91:        while (-1 != (c = getopt(argc, argv, "vW:")))
1.1       kristaps   92:                switch (c) {
1.13      kristaps   93:                case ('v'):
1.21      kristaps   94:                        parser.dbg++;
1.13      kristaps   95:                        break;
                     96:                case ('W'):
1.18      kristaps   97:                        opts = optarg;
                     98:                        while (*opts)
                     99:                                switch (getsubopt(&opts, toks, &v)) {
                    100:                                case (ALL):
1.21      kristaps  101:                                        parser.warn |= MD_WARN_ALL;
1.18      kristaps  102:                                        break;
1.44    ! kristaps  103:                                case (COMPAT):
        !           104:                                        parser.warn |= MD_WARN_COMPAT;
        !           105:                                        break;
        !           106:                                case (SYNTAX):
        !           107:                                        parser.warn |= MD_WARN_SYNTAX;
        !           108:                                        break;
1.18      kristaps  109:                                case (ERROR):
1.21      kristaps  110:                                        parser.warn |= MD_WARN_ERR;
1.18      kristaps  111:                                        break;
                    112:                                default:
                    113:                                        usage();
                    114:                                        return(1);
                    115:                                }
1.13      kristaps  116:                        break;
1.1       kristaps  117:                default:
                    118:                        usage();
                    119:                        return(1);
                    120:                }
                    121:
                    122:        argv += optind;
1.4       kristaps  123:        argc -= optind;
1.1       kristaps  124:
1.21      kristaps  125:        parser.name = "-";
1.4       kristaps  126:        if (1 == argc)
1.21      kristaps  127:                parser.name = *argv++;
                    128:
                    129:        if ( ! io_begin(&parser))
                    130:                return(EXIT_FAILURE);
1.1       kristaps  131:
1.21      kristaps  132:        return(EXIT_SUCCESS);
1.1       kristaps  133: }
                    134:
                    135:
                    136: static int
1.21      kristaps  137: io_leave(struct md_parse *p, int code)
1.1       kristaps  138: {
                    139:
1.21      kristaps  140:        if (-1 == p->fd || STDIN_FILENO == p->fd)
                    141:                return(code);
                    142:
                    143:        if (-1 == close(p->fd)) {
                    144:                warn("%s", p->name);
                    145:                code = 0;
1.4       kristaps  146:        }
1.21      kristaps  147:        return(code);
                    148: }
                    149:
                    150:
                    151: static int
                    152: io_begin(struct md_parse *p)
                    153: {
                    154:
                    155:        p->fd = STDIN_FILENO;
                    156:        if (0 != strncmp(p->name, "-", 1))
                    157:                if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
                    158:                        warn("%s", p->name);
                    159:                        return(io_leave(p, 0));
                    160:                }
1.1       kristaps  161:
1.21      kristaps  162:        return(io_leave(p, buf_begin(p)));
1.1       kristaps  163: }
                    164:
                    165:
                    166: static int
1.21      kristaps  167: buf_leave(struct md_parse *p, int code)
1.1       kristaps  168: {
1.4       kristaps  169:
1.21      kristaps  170:        if (p->buf)
                    171:                free(p->buf);
                    172:        return(code);
                    173: }
1.1       kristaps  174:
                    175:
1.21      kristaps  176: static int
                    177: buf_begin(struct md_parse *p)
                    178: {
                    179:        struct stat      st;
1.1       kristaps  180:
1.21      kristaps  181:        if (-1 == fstat(p->fd, &st)) {
                    182:                warn("%s", p->name);
                    183:                return(1);
                    184:        }
                    185:
                    186:        p->bufsz = MAX(st.st_blksize, BUFSIZ);
                    187:
                    188:        if (NULL == (p->buf = malloc(p->bufsz))) {
                    189:                warn("malloc");
                    190:                return(buf_leave(p, 0));
                    191:        }
                    192:
                    193:        return(buf_leave(p, parse_begin(p)));
                    194: }
                    195:
                    196:
                    197: static void
                    198: print_node(const struct mdoc_node *n, int indent)
                    199: {
1.26      kristaps  200:        const char       *p, *t;
                    201:        int               i, j;
                    202:        size_t            argc, sz;
                    203:        char            **params;
                    204:        struct mdoc_arg  *argv;
1.24      kristaps  205:
                    206:        argv = NULL;
1.44    ! kristaps  207:        argc = sz = 0;
1.26      kristaps  208:        params = NULL;
1.21      kristaps  209:
1.42      kristaps  210:        t = mdoc_type2a(n->type);
                    211:
1.21      kristaps  212:        switch (n->type) {
                    213:        case (MDOC_TEXT):
1.25      kristaps  214:                p = n->data.text.string;
1.21      kristaps  215:                break;
                    216:        case (MDOC_BODY):
1.40      kristaps  217:                p = mdoc_macronames[n->tok];
1.21      kristaps  218:                break;
                    219:        case (MDOC_HEAD):
1.40      kristaps  220:                p = mdoc_macronames[n->tok];
1.21      kristaps  221:                break;
1.34      kristaps  222:        case (MDOC_TAIL):
1.40      kristaps  223:                p = mdoc_macronames[n->tok];
1.34      kristaps  224:                break;
1.21      kristaps  225:        case (MDOC_ELEM):
1.40      kristaps  226:                p = mdoc_macronames[n->tok];
1.24      kristaps  227:                argv = n->data.elem.argv;
                    228:                argc = n->data.elem.argc;
1.21      kristaps  229:                break;
                    230:        case (MDOC_BLOCK):
1.40      kristaps  231:                p = mdoc_macronames[n->tok];
1.24      kristaps  232:                argv = n->data.block.argv;
                    233:                argc = n->data.block.argc;
1.21      kristaps  234:                break;
1.38      kristaps  235:        case (MDOC_ROOT):
                    236:                p = "root";
                    237:                break;
1.22      kristaps  238:        default:
                    239:                abort();
                    240:                /* NOTREACHED */
1.21      kristaps  241:        }
                    242:
                    243:        for (i = 0; i < indent; i++)
1.44    ! kristaps  244:                xprintf("    ");
        !           245:        xprintf("%s (%s)", p, t);
1.24      kristaps  246:
                    247:        for (i = 0; i < (int)argc; i++) {
1.44    ! kristaps  248:                xprintf(" -%s", mdoc_argnames[argv[i].arg]);
1.42      kristaps  249:                if (argv[i].sz > 0)
1.44    ! kristaps  250:                        xprintf(" [");
1.24      kristaps  251:                for (j = 0; j < (int)argv[i].sz; j++)
1.44    ! kristaps  252:                        xprintf(" [%s]", argv[i].value[j]);
1.42      kristaps  253:                if (argv[i].sz > 0)
1.44    ! kristaps  254:                        xprintf(" ]");
1.24      kristaps  255:        }
                    256:
1.26      kristaps  257:        for (i = 0; i < (int)sz; i++)
1.44    ! kristaps  258:                xprintf(" [%s]", params[i]);
1.26      kristaps  259:
1.44    ! kristaps  260:        xprintf(" %d:%d\n", n->line, n->pos);
1.21      kristaps  261:
                    262:        if (n->child)
                    263:                print_node(n->child, indent + 1);
                    264:        if (n->next)
                    265:                print_node(n->next, indent);
                    266: }
1.1       kristaps  267:
                    268:
1.21      kristaps  269: static int
                    270: parse_leave(struct md_parse *p, int code)
                    271: {
                    272:        const struct mdoc_node *n;
                    273:
1.36      kristaps  274:        if (NULL == p->mdoc)
                    275:                return(code);
                    276:
                    277:        if ( ! mdoc_endparse(p->mdoc))
                    278:                code = 0;
                    279:        if ((n = mdoc_result(p->mdoc)))
                    280:                print_node(n, 0);
                    281:
1.38      kristaps  282:        mdoc_free(p->mdoc);
                    283:
1.21      kristaps  284:        return(code);
                    285: }
                    286:
                    287:
                    288: static int
                    289: parse_begin(struct md_parse *p)
                    290: {
                    291:        ssize_t          sz, i;
                    292:        size_t           pos;
1.44    ! kristaps  293:        char             line[MD_LINE_SZ];
1.21      kristaps  294:        struct mdoc_cb   cb;
1.43      kristaps  295:        int              lnn;
1.21      kristaps  296:
                    297:        cb.mdoc_err = msg_err;
                    298:        cb.mdoc_warn = msg_warn;
                    299:        cb.mdoc_msg = msg_msg;
                    300:
                    301:        if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
                    302:                return(parse_leave(p, 0));
                    303:
1.43      kristaps  304:        for (lnn = 1, pos = 0; ; ) {
1.21      kristaps  305:                if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
                    306:                        warn("%s", p->name);
                    307:                        return(parse_leave(p, 0));
                    308:                } else if (0 == sz)
                    309:                        break;
                    310:
                    311:                for (i = 0; i < sz; i++) {
                    312:                        if ('\n' != p->buf[i]) {
                    313:                                if (pos < sizeof(line)) {
1.44    ! kristaps  314:                                        line[(int)pos++] = p->buf[(int)i];
1.21      kristaps  315:                                        continue;
                    316:                                }
                    317:                                warnx("%s: line %d too long",
1.43      kristaps  318:                                                p->name, lnn);
1.21      kristaps  319:                                return(parse_leave(p, 0));
                    320:                        }
                    321:
1.44    ! kristaps  322:                        line[(int)pos] = 0;
1.43      kristaps  323:                        if ( ! mdoc_parseln(p->mdoc, lnn, line))
1.21      kristaps  324:                                return(parse_leave(p, 0));
1.1       kristaps  325:
1.43      kristaps  326:                        lnn++;
1.21      kristaps  327:                        pos = 0;
1.4       kristaps  328:                }
1.21      kristaps  329:        }
1.1       kristaps  330:
1.21      kristaps  331:        return(parse_leave(p, 1));
1.4       kristaps  332: }
1.1       kristaps  333:
                    334:
1.4       kristaps  335: static int
1.44    ! kristaps  336: msg_err(void *arg, int line, int col, const char *msg)
1.21      kristaps  337: {
                    338:        struct md_parse  *p;
                    339:
                    340:        p = (struct md_parse *)arg;
                    341:
1.44    ! kristaps  342:        xfprintf(stderr, "%s:%d: error: %s (column %d)",
        !           343:                        p->name, line, msg, col);
1.21      kristaps  344:        return(0);
                    345: }
                    346:
                    347:
                    348: static void
1.37      kristaps  349: msg_msg(void *arg, int line, int col, const char *msg)
1.4       kristaps  350: {
1.21      kristaps  351:        struct md_parse  *p;
                    352:
                    353:        p = (struct md_parse *)arg;
                    354:
1.44    ! kristaps  355:        if (0 == p->dbg)
1.21      kristaps  356:                return;
                    357:
1.44    ! kristaps  358:        xfprintf(stderr, "%s:%d: debug: %s (column %d)",
1.39      kristaps  359:                        p->name, line, msg, col);
1.1       kristaps  360: }
                    361:
                    362:
                    363: static int
1.44    ! kristaps  364: msg_warn(void *arg, int line, int col,
        !           365:                enum mdoc_warn type, const char *msg)
1.1       kristaps  366: {
1.21      kristaps  367:        struct md_parse  *p;
1.1       kristaps  368:
1.21      kristaps  369:        p = (struct md_parse *)arg;
1.1       kristaps  370:
1.44    ! kristaps  371:        switch (type) {
        !           372:        case (WARN_COMPAT):
        !           373:                if (p->warn & MD_WARN_COMPAT)
        !           374:                        break;
        !           375:                return(1);
        !           376:        case (WARN_SYNTAX):
        !           377:                if (p->warn & MD_WARN_SYNTAX)
        !           378:                        break;
1.1       kristaps  379:                return(1);
                    380:        }
                    381:
1.44    ! kristaps  382:        xfprintf(stderr, "%s:%d: warning: %s (column %d)\n",
        !           383:                        p->name, line, msg, col);
1.21      kristaps  384:
1.44    ! kristaps  385:        if ( ! (p->warn & MD_WARN_ERR))
        !           386:                return(1);
1.21      kristaps  387:
1.44    ! kristaps  388:        xfprintf(stderr, "%s: considering warnings as errors\n",
        !           389:                        __progname);
        !           390:        return(0);
1.1       kristaps  391: }
                    392:
                    393:
                    394: static void
                    395: usage(void)
                    396: {
                    397:
1.44    ! kristaps  398:        xfprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
1.19      kristaps  399:                        __progname);
1.1       kristaps  400: }
1.18      kristaps  401:

CVSweb