Annotation of mandoc/mdocterm.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: mdocml.c,v 1.54 2009/02/21 15:34:46 kristaps Exp $ */
! 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: */
! 19: #include <sys/stat.h>
! 20: #include <sys/param.h>
! 21:
! 22: #include <assert.h>
! 23: #include <fcntl.h>
! 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:
! 31: #include "mdoc.h"
! 32: #include "term.h"
! 33:
! 34: #define MD_LINE_SZ (256) /* Max input line size. */
! 35:
! 36: struct md_parse {
! 37: int warn; /* Warning flags. */
! 38: #define MD_WARN_SYNTAX (1 << 0) /* Show syntax warnings. */
! 39: #define MD_WARN_COMPAT (1 << 1) /* Show compat warnings. */
! 40: #define MD_WARN_ALL (0x03) /* Show all warnings. */
! 41: #define MD_WARN_ERR (1 << 2) /* Make warnings->errors. */
! 42: int dbg; /* Debug level. */
! 43: struct mdoc *mdoc; /* Active parser. */
! 44: char *buf; /* Input buffer. */
! 45: u_long bufsz; /* Input buffer size. */
! 46: char *in; /* Input file name. */
! 47: int fdin; /* Input file desc. */
! 48: };
! 49:
! 50: extern char *__progname;
! 51:
! 52: static void usage(void);
! 53: static int getsopts(struct md_parse *, char *);
! 54: static int parse(struct md_parse *);
! 55: static void msg_msg(void *, int, int, const char *);
! 56: static int msg_err(void *, int, int, const char *);
! 57: static int msg_warn(void *, int, int,
! 58: enum mdoc_warn, const char *);
! 59:
! 60: #ifdef __linux__
! 61: extern int getsubopt(char **, char *const *, char **);
! 62: #endif
! 63:
! 64: int
! 65: main(int argc, char *argv[])
! 66: {
! 67: struct md_parse p;
! 68: struct mdoc_cb cb;
! 69: struct stat st;
! 70: int c;
! 71: extern char *optarg;
! 72: extern int optind;
! 73:
! 74: (void)memset(&p, 0, sizeof(struct md_parse));
! 75:
! 76: while (-1 != (c = getopt(argc, argv, "vW:")))
! 77: switch (c) {
! 78: case ('v'):
! 79: p.dbg++;
! 80: break;
! 81: case ('W'):
! 82: if ( ! getsopts(&p, optarg))
! 83: return(0);
! 84: break;
! 85: default:
! 86: usage();
! 87: return(0);
! 88: }
! 89:
! 90: argv += optind;
! 91: argc -= optind;
! 92:
! 93: /* Initialise the input file. */
! 94:
! 95: p.in = "-";
! 96: p.fdin = STDIN_FILENO;
! 97:
! 98: if (argc > 0) {
! 99: p.in = *argv++;
! 100: p.fdin = open(p.in, O_RDONLY, 0);
! 101: if (-1 == p.fdin)
! 102: err(1, "%s", p.in);
! 103: }
! 104:
! 105: /* Allocate a buffer to be BUFSIZ/block size. */
! 106:
! 107: if (-1 == fstat(p.fdin, &st)) {
! 108: warn("%s", p.in);
! 109: p.bufsz = BUFSIZ;
! 110: } else
! 111: p.bufsz = MAX(st.st_blksize, BUFSIZ);
! 112:
! 113: p.buf = malloc(p.bufsz);
! 114: if (NULL == p.buf)
! 115: err(1, "malloc");
! 116:
! 117: /* Allocate the parser. */
! 118:
! 119: cb.mdoc_err = msg_err;
! 120: cb.mdoc_warn = msg_warn;
! 121: cb.mdoc_msg = msg_msg;
! 122:
! 123: p.mdoc = mdoc_alloc(&p, &cb);
! 124:
! 125: /* Parse the input file. */
! 126:
! 127: c = parse(&p);
! 128: free(p.buf);
! 129:
! 130: if (STDIN_FILENO != p.fdin && -1 == close(p.fdin))
! 131: warn("%s", p.in);
! 132:
! 133: if (0 == c) {
! 134: mdoc_free(p.mdoc);
! 135: return(EXIT_FAILURE);
! 136: }
! 137:
! 138: /* If the parse succeeded, print it out. */
! 139:
! 140: termprint(mdoc_node(p.mdoc), mdoc_meta(p.mdoc));
! 141: mdoc_free(p.mdoc);
! 142:
! 143: return(EXIT_SUCCESS);
! 144: }
! 145:
! 146:
! 147: static int
! 148: getsopts(struct md_parse *p, char *arg)
! 149: {
! 150: char *v;
! 151: char *toks[] = { "all", "compat",
! 152: "syntax", "error", NULL };
! 153:
! 154: while (*arg)
! 155: switch (getsubopt(&arg, toks, &v)) {
! 156: case (0):
! 157: p->warn |= MD_WARN_ALL;
! 158: break;
! 159: case (1):
! 160: p->warn |= MD_WARN_COMPAT;
! 161: break;
! 162: case (2):
! 163: p->warn |= MD_WARN_SYNTAX;
! 164: break;
! 165: case (3):
! 166: p->warn |= MD_WARN_ERR;
! 167: break;
! 168: default:
! 169: usage();
! 170: return(0);
! 171: }
! 172:
! 173: return(1);
! 174: }
! 175:
! 176:
! 177: static int
! 178: parse(struct md_parse *p)
! 179: {
! 180: ssize_t sz, i;
! 181: size_t pos;
! 182: char line[MD_LINE_SZ];
! 183: int lnn;
! 184:
! 185: /*
! 186: * This is a little more complicated than fgets. TODO: have
! 187: * some benchmarks that show it's faster (note that I want to
! 188: * check many, many manuals simultaneously, so speed is
! 189: * important). Fill a buffer (sized to the block size) with a
! 190: * single read, then parse \n-terminated lines into a line
! 191: * buffer, which is passed to the parser. Hard-code the line
! 192: * buffer to a particular size -- a reasonable assumption.
! 193: */
! 194:
! 195: for (lnn = 1, pos = 0; ; ) {
! 196: if (-1 == (sz = read(p->fdin, p->buf, p->bufsz))) {
! 197: warn("%s", p->in);
! 198: return(0);
! 199: } else if (0 == sz)
! 200: break;
! 201:
! 202: for (i = 0; i < sz; i++) {
! 203: if ('\n' != p->buf[i]) {
! 204: if (pos < sizeof(line)) {
! 205: line[(int)pos++] = p->buf[(int)i];
! 206: continue;
! 207: }
! 208: warnx("%s: line %d too long", p->in, lnn);
! 209: return(0);
! 210: }
! 211:
! 212: line[(int)pos] = 0;
! 213: if ( ! mdoc_parseln(p->mdoc, lnn, line))
! 214: return(0);
! 215:
! 216: lnn++;
! 217: pos = 0;
! 218: }
! 219: }
! 220:
! 221: return(mdoc_endparse(p->mdoc));
! 222: }
! 223:
! 224:
! 225: static int
! 226: msg_err(void *arg, int line, int col, const char *msg)
! 227: {
! 228: struct md_parse *p;
! 229:
! 230: p = (struct md_parse *)arg;
! 231:
! 232: warnx("%s:%d: error: %s (column %d)",
! 233: p->in, line, msg, col);
! 234: return(0);
! 235: }
! 236:
! 237:
! 238: static void
! 239: msg_msg(void *arg, int line, int col, const char *msg)
! 240: {
! 241: struct md_parse *p;
! 242:
! 243: p = (struct md_parse *)arg;
! 244:
! 245: if (0 == p->dbg)
! 246: return;
! 247:
! 248: warnx("%s:%d: debug: %s (column %d)",
! 249: p->in, line, msg, col);
! 250: }
! 251:
! 252:
! 253: static int
! 254: msg_warn(void *arg, int line, int col,
! 255: enum mdoc_warn type, const char *msg)
! 256: {
! 257: struct md_parse *p;
! 258:
! 259: p = (struct md_parse *)arg;
! 260:
! 261: switch (type) {
! 262: case (WARN_COMPAT):
! 263: if (p->warn & MD_WARN_COMPAT)
! 264: break;
! 265: return(1);
! 266: case (WARN_SYNTAX):
! 267: if (p->warn & MD_WARN_SYNTAX)
! 268: break;
! 269: return(1);
! 270: }
! 271:
! 272: warnx("%s:%d: warning: %s (column %d)",
! 273: p->in, line, msg, col);
! 274:
! 275: if ( ! (p->warn & MD_WARN_ERR))
! 276: return(1);
! 277:
! 278: warnx("%s: considering warnings as errors", __progname);
! 279: return(0);
! 280: }
! 281:
! 282:
! 283: static void
! 284: usage(void)
! 285: {
! 286:
! 287: warnx("usage: %s [-v] [-Wwarn...] [infile]", __progname);
! 288: }
! 289:
CVSweb