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