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

Annotation of mandoc/mdocml.c, Revision 1.46

1.46    ! kristaps    1: /* $Id: mdocml.c,v 1.45 2009/01/16 11:50:54 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:
1.46    ! kristaps  197: /* TODO: remove this to a print-tree output filter. */
1.21      kristaps  198: static void
                    199: print_node(const struct mdoc_node *n, int indent)
                    200: {
1.26      kristaps  201:        const char       *p, *t;
                    202:        int               i, j;
                    203:        size_t            argc, sz;
                    204:        char            **params;
                    205:        struct mdoc_arg  *argv;
1.24      kristaps  206:
                    207:        argv = NULL;
1.44      kristaps  208:        argc = sz = 0;
1.26      kristaps  209:        params = NULL;
1.21      kristaps  210:
1.42      kristaps  211:        t = mdoc_type2a(n->type);
                    212:
1.21      kristaps  213:        switch (n->type) {
                    214:        case (MDOC_TEXT):
1.25      kristaps  215:                p = n->data.text.string;
1.21      kristaps  216:                break;
                    217:        case (MDOC_BODY):
1.40      kristaps  218:                p = mdoc_macronames[n->tok];
1.21      kristaps  219:                break;
                    220:        case (MDOC_HEAD):
1.40      kristaps  221:                p = mdoc_macronames[n->tok];
1.21      kristaps  222:                break;
1.34      kristaps  223:        case (MDOC_TAIL):
1.40      kristaps  224:                p = mdoc_macronames[n->tok];
1.34      kristaps  225:                break;
1.21      kristaps  226:        case (MDOC_ELEM):
1.40      kristaps  227:                p = mdoc_macronames[n->tok];
1.24      kristaps  228:                argv = n->data.elem.argv;
                    229:                argc = n->data.elem.argc;
1.21      kristaps  230:                break;
                    231:        case (MDOC_BLOCK):
1.40      kristaps  232:                p = mdoc_macronames[n->tok];
1.24      kristaps  233:                argv = n->data.block.argv;
                    234:                argc = n->data.block.argc;
1.21      kristaps  235:                break;
1.38      kristaps  236:        case (MDOC_ROOT):
                    237:                p = "root";
                    238:                break;
1.22      kristaps  239:        default:
                    240:                abort();
                    241:                /* NOTREACHED */
1.21      kristaps  242:        }
                    243:
                    244:        for (i = 0; i < indent; i++)
1.44      kristaps  245:                xprintf("    ");
                    246:        xprintf("%s (%s)", p, t);
1.24      kristaps  247:
                    248:        for (i = 0; i < (int)argc; i++) {
1.44      kristaps  249:                xprintf(" -%s", mdoc_argnames[argv[i].arg]);
1.42      kristaps  250:                if (argv[i].sz > 0)
1.44      kristaps  251:                        xprintf(" [");
1.24      kristaps  252:                for (j = 0; j < (int)argv[i].sz; j++)
1.44      kristaps  253:                        xprintf(" [%s]", argv[i].value[j]);
1.42      kristaps  254:                if (argv[i].sz > 0)
1.44      kristaps  255:                        xprintf(" ]");
1.24      kristaps  256:        }
                    257:
1.26      kristaps  258:        for (i = 0; i < (int)sz; i++)
1.44      kristaps  259:                xprintf(" [%s]", params[i]);
1.26      kristaps  260:
1.44      kristaps  261:        xprintf(" %d:%d\n", n->line, n->pos);
1.21      kristaps  262:
                    263:        if (n->child)
                    264:                print_node(n->child, indent + 1);
                    265:        if (n->next)
                    266:                print_node(n->next, indent);
                    267: }
1.1       kristaps  268:
                    269:
1.21      kristaps  270: static int
                    271: parse_leave(struct md_parse *p, int code)
                    272: {
                    273:        const struct mdoc_node *n;
                    274:
1.36      kristaps  275:        if (NULL == p->mdoc)
                    276:                return(code);
                    277:
                    278:        if ( ! mdoc_endparse(p->mdoc))
                    279:                code = 0;
                    280:        if ((n = mdoc_result(p->mdoc)))
                    281:                print_node(n, 0);
                    282:
1.38      kristaps  283:        mdoc_free(p->mdoc);
                    284:
1.21      kristaps  285:        return(code);
                    286: }
                    287:
                    288:
                    289: static int
                    290: parse_begin(struct md_parse *p)
                    291: {
                    292:        ssize_t          sz, i;
                    293:        size_t           pos;
1.44      kristaps  294:        char             line[MD_LINE_SZ];
1.21      kristaps  295:        struct mdoc_cb   cb;
1.43      kristaps  296:        int              lnn;
1.21      kristaps  297:
                    298:        cb.mdoc_err = msg_err;
                    299:        cb.mdoc_warn = msg_warn;
                    300:        cb.mdoc_msg = msg_msg;
                    301:
                    302:        if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
                    303:                return(parse_leave(p, 0));
                    304:
1.43      kristaps  305:        for (lnn = 1, pos = 0; ; ) {
1.21      kristaps  306:                if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
                    307:                        warn("%s", p->name);
                    308:                        return(parse_leave(p, 0));
                    309:                } else if (0 == sz)
                    310:                        break;
                    311:
                    312:                for (i = 0; i < sz; i++) {
                    313:                        if ('\n' != p->buf[i]) {
                    314:                                if (pos < sizeof(line)) {
1.44      kristaps  315:                                        line[(int)pos++] = p->buf[(int)i];
1.21      kristaps  316:                                        continue;
                    317:                                }
                    318:                                warnx("%s: line %d too long",
1.43      kristaps  319:                                                p->name, lnn);
1.21      kristaps  320:                                return(parse_leave(p, 0));
                    321:                        }
                    322:
1.44      kristaps  323:                        line[(int)pos] = 0;
1.43      kristaps  324:                        if ( ! mdoc_parseln(p->mdoc, lnn, line))
1.21      kristaps  325:                                return(parse_leave(p, 0));
1.1       kristaps  326:
1.43      kristaps  327:                        lnn++;
1.21      kristaps  328:                        pos = 0;
1.4       kristaps  329:                }
1.21      kristaps  330:        }
1.1       kristaps  331:
1.21      kristaps  332:        return(parse_leave(p, 1));
1.4       kristaps  333: }
1.1       kristaps  334:
                    335:
1.4       kristaps  336: static int
1.44      kristaps  337: msg_err(void *arg, int line, int col, const char *msg)
1.21      kristaps  338: {
                    339:        struct md_parse  *p;
                    340:
                    341:        p = (struct md_parse *)arg;
                    342:
1.45      kristaps  343:        xfprintf(stderr, "%s:%d: error: %s (column %d)\n",
1.44      kristaps  344:                        p->name, line, msg, col);
1.21      kristaps  345:        return(0);
                    346: }
                    347:
                    348:
                    349: static void
1.37      kristaps  350: msg_msg(void *arg, int line, int col, const char *msg)
1.4       kristaps  351: {
1.21      kristaps  352:        struct md_parse  *p;
                    353:
                    354:        p = (struct md_parse *)arg;
                    355:
1.44      kristaps  356:        if (0 == p->dbg)
1.21      kristaps  357:                return;
                    358:
1.45      kristaps  359:        xfprintf(stderr, "%s:%d: debug: %s (column %d)\n",
1.39      kristaps  360:                        p->name, line, msg, col);
1.1       kristaps  361: }
                    362:
                    363:
                    364: static int
1.44      kristaps  365: msg_warn(void *arg, int line, int col,
                    366:                enum mdoc_warn type, const char *msg)
1.1       kristaps  367: {
1.21      kristaps  368:        struct md_parse  *p;
1.1       kristaps  369:
1.21      kristaps  370:        p = (struct md_parse *)arg;
1.1       kristaps  371:
1.44      kristaps  372:        switch (type) {
                    373:        case (WARN_COMPAT):
                    374:                if (p->warn & MD_WARN_COMPAT)
                    375:                        break;
                    376:                return(1);
                    377:        case (WARN_SYNTAX):
                    378:                if (p->warn & MD_WARN_SYNTAX)
                    379:                        break;
1.1       kristaps  380:                return(1);
                    381:        }
                    382:
1.44      kristaps  383:        xfprintf(stderr, "%s:%d: warning: %s (column %d)\n",
                    384:                        p->name, line, msg, col);
1.21      kristaps  385:
1.44      kristaps  386:        if ( ! (p->warn & MD_WARN_ERR))
                    387:                return(1);
1.21      kristaps  388:
1.44      kristaps  389:        xfprintf(stderr, "%s: considering warnings as errors\n",
                    390:                        __progname);
                    391:        return(0);
1.1       kristaps  392: }
                    393:
                    394:
                    395: static void
                    396: usage(void)
                    397: {
                    398:
1.44      kristaps  399:        xfprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
1.19      kristaps  400:                        __progname);
1.1       kristaps  401: }
1.18      kristaps  402:

CVSweb