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