=================================================================== RCS file: /cvs/mandoc/main.c,v retrieving revision 1.1 retrieving revision 1.15 diff -u -p -r1.1 -r1.15 --- mandoc/main.c 2009/03/19 16:17:27 1.1 +++ mandoc/main.c 2009/03/25 21:03:13 1.15 @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.1 2009/03/19 16:17:27 kristaps Exp $ */ +/* $Id: main.c,v 1.15 2009/03/25 21:03:13 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -27,21 +27,52 @@ #include #include "mdoc.h" +#include "man.h" +#ifdef __linux__ +extern int getsubopt(char **, char * const *, char **); +# ifndef __dead +# define __dead __attribute__((__noreturn__)) +# endif +#elif defined(__dead2) +# ifndef __dead +# define __dead __dead2 +# endif +#endif + +struct buf { + char *buf; + size_t sz; +}; + +struct curparse { + const char *file; + int wflags; #define WARN_WALL 0x03 /* All-warnings mask. */ #define WARN_WCOMPAT (1 << 0) /* Compatibility warnings. */ #define WARN_WSYNTAX (1 << 1) /* Syntax warnings. */ #define WARN_WERR (1 << 2) /* Warnings->errors. */ +}; -enum outt { - OUTT_ASCII, +#define IGN_SCOPE (1 << 0) /* Flag to ignore scope. */ +#define IGN_ESCAPE (1 << 1) /* Flag to ignore bad escapes. */ +#define IGN_MACRO (1 << 2) /* Flag to ignore unknown macros. */ + +enum intt { + INTT_MDOC = 0, + INTT_MAN +}; + +enum outt { + OUTT_ASCII = 0, OUTT_LATIN1, OUTT_UTF8, OUTT_TREE, OUTT_LINT }; -typedef int (*out_run)(void *, const struct mdoc *); +typedef int (*out_run)(void *, const struct man *, + const struct mdoc *); typedef void (*out_free)(void *); extern char *__progname; @@ -49,53 +80,70 @@ extern char *__progname; extern void *ascii_alloc(void); extern void *latin1_alloc(void); extern void *utf8_alloc(void); -extern int terminal_run(void *, const struct mdoc *); -extern int tree_run(void *, const struct mdoc *); +extern int terminal_run(void *, const struct man *, + const struct mdoc *); +extern int tree_run(void *, const struct man *, + const struct mdoc *); extern void terminal_free(void *); -__dead static void version(void); -__dead static void usage(void); static int foptions(int *, char *); static int toptions(enum outt *, char *); +static int moptions(enum intt *, char *); static int woptions(int *, char *); static int merr(void *, int, int, const char *); -static int mwarn(void *, int, int, +static int manwarn(void *, int, int, const char *); +static int mdocwarn(void *, int, int, enum mdoc_warn, const char *); -static int file(char **, size_t *, char **, size_t *, - const char *, struct mdoc *); -static int fdesc(char **, size_t *, char **, size_t *, - const char *, int, struct mdoc *); +static int file(struct buf *, struct buf *, + const char *, + struct man *, struct mdoc *); +static int fdesc(struct buf *, struct buf *, + const char *, int, + struct man *, struct mdoc *); +__dead static void version(void); +__dead static void usage(void); + int main(int argc, char *argv[]) { - int c, rc, fflags, wflags; - struct mdoc_cb cb; + int c, rc, fflags, pflags; + struct mdoc_cb mdoccb; + struct man_cb mancb; + struct man *man; struct mdoc *mdoc; - char *buf, *line; - size_t bufsz, linesz; void *outdata; enum outt outtype; + enum intt inttype; + struct buf ln, blk; out_run outrun; out_free outfree; + struct curparse curp; - fflags = wflags = 0; + fflags = 0; outtype = OUTT_ASCII; + inttype = INTT_MDOC; + bzero(&curp, sizeof(struct curparse)); + /* LINTED */ - while (-1 != (c = getopt(argc, argv, "f:VW:T:"))) + while (-1 != (c = getopt(argc, argv, "f:m:VW:T:"))) switch (c) { case ('f'): if ( ! foptions(&fflags, optarg)) return(0); break; + case ('m'): + if ( ! moptions(&inttype, optarg)) + return(0); + break; case ('T'): if ( ! toptions(&outtype, optarg)) return(0); break; case ('W'): - if ( ! woptions(&wflags, optarg)) + if ( ! woptions(&curp.wflags, optarg)) return(0); break; case ('V'): @@ -149,37 +197,82 @@ main(int argc, char *argv[]) * screen. XXX - for now, no path for debugging messages. */ - cb.mdoc_msg = NULL; - cb.mdoc_err = merr; - cb.mdoc_warn = mwarn; + mdoccb.mdoc_msg = NULL; + mdoccb.mdoc_err = merr; + mdoccb.mdoc_warn = mdocwarn; - buf = line = NULL; - bufsz = linesz = 0; + mancb.man_err = merr; + mancb.man_warn = manwarn; - mdoc = mdoc_alloc(&wflags, fflags, &cb); + bzero(&ln, sizeof(struct buf)); + bzero(&blk, sizeof(struct buf)); - while (*argv) { - if ( ! file(&line, &linesz, &buf, &bufsz, *argv, mdoc)) - break; - if (outrun && ! (*outrun)(outdata, mdoc)) - break; + man = NULL; + mdoc = NULL; + pflags = 0; - /* Reset the parser for another file. */ - mdoc_reset(mdoc); - argv++; + switch (inttype) { + case (INTT_MAN): + if (fflags & IGN_MACRO) + pflags |= MAN_IGN_MACRO; + + man = man_alloc(&curp, pflags, &mancb); + break; + default: + if (fflags & IGN_SCOPE) + pflags |= MDOC_IGN_SCOPE; + if (fflags & IGN_ESCAPE) + pflags |= MDOC_IGN_ESCAPE; + if (fflags & IGN_MACRO) + pflags |= MDOC_IGN_MACRO; + + mdoc = mdoc_alloc(&curp, pflags, &mdoccb); + break; } - rc = NULL == *argv; + /* + * Loop around available files. + */ - if (buf) - free(buf); - if (line) - free(line); + if (NULL == *argv) { + curp.file = ""; + rc = 0; + c = fdesc(&blk, &ln, "stdin", + STDIN_FILENO, man, mdoc); + + if (c && NULL == outrun) + rc = 1; + else if (c && outrun && (*outrun)(outdata, man, mdoc)) + rc = 1; + } else { + while (*argv) { + curp.file = *argv; + c = file(&blk, &ln, *argv, man, mdoc); + if ( ! c) + break; + if (outrun && ! (*outrun)(outdata, man, mdoc)) + break; + if (man) + man_reset(man); + if (mdoc) + mdoc_reset(mdoc); + + argv++; + } + rc = NULL == *argv; + } + + if (blk.buf) + free(blk.buf); + if (ln.buf) + free(ln.buf); if (outfree) (*outfree)(outdata); + if (mdoc) + mdoc_free(mdoc); + if (man) + man_free(man); - mdoc_free(mdoc); - return(rc ? EXIT_SUCCESS : EXIT_FAILURE); } @@ -198,15 +291,17 @@ __dead static void usage(void) { - (void)fprintf(stderr, "usage: %s\n", __progname); + (void)fprintf(stderr, "usage: %s [-V] [-foption...] " + "[-mformat] [-Toutput] [-Werr...]\n", + __progname); exit(1); /* NOTREACHED */ } static int -file(char **ln, size_t *lnsz, char **buf, size_t *bufsz, - const char *file, struct mdoc *mdoc) +file(struct buf *blk, struct buf *ln, const char *file, + struct man *man, struct mdoc *mdoc) { int fd, c; @@ -215,7 +310,7 @@ file(char **ln, size_t *lnsz, char **buf, size_t *bufs return(0); } - c = fdesc(ln, lnsz, buf, bufsz, file, fd, mdoc); + c = fdesc(blk, ln, file, fd, man, mdoc); if (-1 == close(fd)) warn("%s", file); @@ -225,17 +320,16 @@ file(char **ln, size_t *lnsz, char **buf, size_t *bufs static int -fdesc(char **lnp, size_t *lnsz, char **bufp, size_t *bufsz, - const char *f, int fd, struct mdoc *mdoc) +fdesc(struct buf *blk, struct buf *ln, + const char *f, int fd, + struct man *man, struct mdoc *mdoc) { size_t sz; ssize_t ssz; struct stat st; int j, i, pos, lnn; - char *ln, *buf; - buf = *bufp; - ln = *lnp; + assert( ! (man && mdoc)); /* * Two buffers: ln and buf. buf is the input buffer, optimised @@ -243,18 +337,18 @@ fdesc(char **lnp, size_t *lnsz, char **bufp, size_t *b * growable, hence passed in by ptr-ptr. */ - if (-1 == fstat(fd, &st)) { + sz = BUFSIZ; + + if (-1 == fstat(fd, &st)) warnx("%s", f); - sz = BUFSIZ; - } else - sz = (unsigned)BUFSIZ > st.st_blksize ? - (size_t)BUFSIZ : st.st_blksize; + else if ((size_t)st.st_blksize > sz) + sz = st.st_blksize; - if (sz > *bufsz) { - if (NULL == (buf = realloc(buf, sz))) + if (sz > blk->sz) { + blk->buf = realloc(blk->buf, sz); + if (NULL == blk->buf) err(1, "realloc"); - *bufp = buf; - *bufsz = sz; + blk->sz = sz; } /* @@ -262,31 +356,30 @@ fdesc(char **lnp, size_t *lnsz, char **bufp, size_t *b */ for (lnn = 1, pos = 0; ; ) { - if (-1 == (ssz = read(fd, buf, sz))) { + if (-1 == (ssz = read(fd, blk->buf, sz))) { warn("%s", f); return(0); } else if (0 == ssz) break; for (i = 0; i < (int)ssz; i++) { - if (pos >= (int)*lnsz) { - *lnsz += 256; /* Step-size. */ - ln = realloc(ln, *lnsz); - if (NULL == ln) + if (pos >= (int)ln->sz) { + ln->sz += 256; /* Step-size. */ + ln->buf = realloc(ln->buf, ln->sz); + if (NULL == ln->buf) err(1, "realloc"); - *lnp = ln; } - if ('\n' != buf[i]) { - ln[pos++] = buf[i]; + if ('\n' != blk->buf[i]) { + ln->buf[pos++] = blk->buf[i]; continue; } /* Check for CPP-escaped newline. */ - if (pos > 0 && '\\' == ln[pos - 1]) { + if (pos > 0 && '\\' == ln->buf[pos - 1]) { for (j = pos - 1; j >= 0; j--) - if ('\\' != ln[j]) + if ('\\' != ln->buf[j]) break; if ( ! ((pos - j) % 2)) { @@ -296,19 +389,41 @@ fdesc(char **lnp, size_t *lnsz, char **bufp, size_t *b } } - ln[pos] = 0; - if ( ! mdoc_parseln(mdoc, lnn, ln)) + ln->buf[pos] = 0; + if (mdoc && ! mdoc_parseln(mdoc, lnn, ln->buf)) return(0); + if (man && ! man_parseln(man, lnn, ln->buf)) + return(0); lnn++; pos = 0; } } - return(mdoc_endparse(mdoc)); + if (mdoc) + return(mdoc_endparse(mdoc)); + + return(man_endparse(man)); } static int +moptions(enum intt *tflags, char *arg) +{ + + if (0 == strcmp(arg, "mdoc")) + *tflags = INTT_MDOC; + else if (0 == strcmp(arg, "man")) + *tflags = INTT_MAN; + else { + warnx("bad argument: -m%s", arg); + return(0); + } + + return(1); +} + + +static int toptions(enum outt *tflags, char *arg) { @@ -349,13 +464,13 @@ foptions(int *fflags, char *arg) while (*arg) switch (getsubopt(&arg, toks, &v)) { case (0): - *fflags |= MDOC_IGN_SCOPE; + *fflags |= IGN_SCOPE; break; case (1): - *fflags |= MDOC_IGN_ESCAPE; + *fflags |= IGN_ESCAPE; break; case (2): - *fflags |= MDOC_IGN_MACRO; + *fflags |= IGN_MACRO; break; default: warnx("bad argument: -f%s", arg); @@ -405,43 +520,48 @@ woptions(int *wflags, char *arg) } +/* ARGSUSED */ static int merr(void *arg, int line, int col, const char *msg) { + struct curparse *curp; - warnx("error: %s (line %d, column %d)", msg, line, col); + curp = (struct curparse *)arg; + + warnx("%s:%d: error: %s (column %d)", + curp->file, line, msg, col); return(0); } static int -mwarn(void *arg, int line, int col, +mdocwarn(void *arg, int line, int col, enum mdoc_warn type, const char *msg) { - int flags; + struct curparse *curp; char *wtype; - flags = *(int *)arg; + curp = (struct curparse *)arg; wtype = NULL; switch (type) { case (WARN_COMPAT): wtype = "compat"; - if (flags & WARN_WCOMPAT) + if (curp->wflags & WARN_WCOMPAT) break; return(1); case (WARN_SYNTAX): wtype = "syntax"; - if (flags & WARN_WSYNTAX) + if (curp->wflags & WARN_WSYNTAX) break; return(1); } assert(wtype); - warnx("%s warning: %s (line %d, column %d)", - wtype, msg, line, col); + warnx("%s:%d: %s warning: %s (column %d)", + curp->file, line, wtype, msg, col); - if ( ! (flags & WARN_WERR)) + if ( ! (curp->wflags & WARN_WERR)) return(1); warnx("%s: considering warnings as errors", @@ -450,3 +570,23 @@ mwarn(void *arg, int line, int col, } +static int +manwarn(void *arg, int line, int col, const char *msg) +{ + struct curparse *curp; + + curp = (struct curparse *)arg; + + if ( ! (curp->wflags & WARN_WSYNTAX)) + return(1); + + warnx("%s:%d: syntax warning: %s (column %d)", + curp->file, line, msg, col); + + if ( ! (curp->wflags & WARN_WERR)) + return(1); + + warnx("%s: considering warnings as errors", + __progname); + return(0); +}