Annotation of mandoc/main.c, Revision 1.1
1.1 ! kristaps 1: /* $Id: mdocterm.c,v 1.49 2009/03/19 11:49:00 kristaps Exp $ */
! 2: /*
! 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@openbsd.org>
! 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:
! 21: #include <assert.h>
! 22: #include <err.h>
! 23: #include <fcntl.h>
! 24: #include <stdio.h>
! 25: #include <stdlib.h>
! 26: #include <string.h>
! 27: #include <unistd.h>
! 28:
! 29: #include "mdoc.h"
! 30:
! 31: #define WARN_WALL 0x03 /* All-warnings mask. */
! 32: #define WARN_WCOMPAT (1 << 0) /* Compatibility warnings. */
! 33: #define WARN_WSYNTAX (1 << 1) /* Syntax warnings. */
! 34: #define WARN_WERR (1 << 2) /* Warnings->errors. */
! 35:
! 36: enum outt {
! 37: OUTT_ASCII,
! 38: OUTT_LATIN1,
! 39: OUTT_UTF8,
! 40: OUTT_TREE,
! 41: OUTT_LINT
! 42: };
! 43:
! 44: typedef int (*out_run)(void *, const struct mdoc *);
! 45: typedef void (*out_free)(void *);
! 46:
! 47: extern char *__progname;
! 48:
! 49: extern void *ascii_alloc(void);
! 50: extern void *latin1_alloc(void);
! 51: extern void *utf8_alloc(void);
! 52: extern int terminal_run(void *, const struct mdoc *);
! 53: extern int tree_run(void *, const struct mdoc *);
! 54: extern void terminal_free(void *);
! 55:
! 56: __dead static void version(void);
! 57: __dead static void usage(void);
! 58: static int foptions(int *, char *);
! 59: static int toptions(enum outt *, char *);
! 60: static int woptions(int *, char *);
! 61: static int merr(void *, int, int, const char *);
! 62: static int mwarn(void *, int, int,
! 63: enum mdoc_warn, const char *);
! 64: static int file(char **, size_t *, char **, size_t *,
! 65: const char *, struct mdoc *);
! 66: static int fdesc(char **, size_t *, char **, size_t *,
! 67: const char *, int, struct mdoc *);
! 68:
! 69:
! 70: int
! 71: main(int argc, char *argv[])
! 72: {
! 73: int c, rc, fflags, wflags;
! 74: struct mdoc_cb cb;
! 75: struct mdoc *mdoc;
! 76: char *buf, *line;
! 77: size_t bufsz, linesz;
! 78: void *outdata;
! 79: enum outt outtype;
! 80: out_run outrun;
! 81: out_free outfree;
! 82:
! 83: fflags = wflags = 0;
! 84: outtype = OUTT_ASCII;
! 85:
! 86: /* LINTED */
! 87: while (-1 != (c = getopt(argc, argv, "f:VW:T:")))
! 88: switch (c) {
! 89: case ('f'):
! 90: if ( ! foptions(&fflags, optarg))
! 91: return(0);
! 92: break;
! 93: case ('T'):
! 94: if ( ! toptions(&outtype, optarg))
! 95: return(0);
! 96: break;
! 97: case ('W'):
! 98: if ( ! woptions(&wflags, optarg))
! 99: return(0);
! 100: break;
! 101: case ('V'):
! 102: version();
! 103: /* NOTREACHED */
! 104: default:
! 105: usage();
! 106: /* NOTREACHED */
! 107: }
! 108:
! 109: argc -= optind;
! 110: argv += optind;
! 111:
! 112: /*
! 113: * Allocate the appropriate front-end. Note that utf8, ascii
! 114: * and latin1 all resolve to the terminal front-end with
! 115: * different encodings (see terminal.c). Not all frontends have
! 116: * cleanup or alloc routines.
! 117: */
! 118:
! 119: switch (outtype) {
! 120: case (OUTT_LATIN1):
! 121: outdata = latin1_alloc();
! 122: outrun = terminal_run;
! 123: outfree = terminal_free;
! 124: break;
! 125: case (OUTT_UTF8):
! 126: outdata = utf8_alloc();
! 127: outrun = terminal_run;
! 128: outfree = terminal_free;
! 129: break;
! 130: case (OUTT_TREE):
! 131: outdata = NULL;
! 132: outrun = tree_run;
! 133: outfree = NULL;
! 134: break;
! 135: case (OUTT_LINT):
! 136: outdata = NULL;
! 137: outrun = NULL;
! 138: outfree = NULL;
! 139: break;
! 140: default:
! 141: outdata = ascii_alloc();
! 142: outrun = terminal_run;
! 143: outfree = terminal_free;
! 144: break;
! 145: }
! 146:
! 147: /*
! 148: * All callbacks route into here, where we print them onto the
! 149: * screen. XXX - for now, no path for debugging messages.
! 150: */
! 151:
! 152: cb.mdoc_msg = NULL;
! 153: cb.mdoc_err = merr;
! 154: cb.mdoc_warn = mwarn;
! 155:
! 156: buf = line = NULL;
! 157: bufsz = linesz = 0;
! 158:
! 159: mdoc = mdoc_alloc(&wflags, fflags, &cb);
! 160:
! 161: while (*argv) {
! 162: if ( ! file(&line, &linesz, &buf, &bufsz, *argv, mdoc))
! 163: break;
! 164: if (outrun && ! (*outrun)(outdata, mdoc))
! 165: break;
! 166:
! 167: /* Reset the parser for another file. */
! 168: mdoc_reset(mdoc);
! 169: argv++;
! 170: }
! 171:
! 172: rc = NULL == *argv;
! 173:
! 174: if (buf)
! 175: free(buf);
! 176: if (line)
! 177: free(line);
! 178: if (outfree)
! 179: (*outfree)(outdata);
! 180:
! 181: mdoc_free(mdoc);
! 182:
! 183: return(rc ? EXIT_SUCCESS : EXIT_FAILURE);
! 184: }
! 185:
! 186:
! 187: __dead static void
! 188: version(void)
! 189: {
! 190:
! 191: (void)printf("%s %s\n", __progname, VERSION);
! 192: exit(0);
! 193: /* NOTREACHED */
! 194: }
! 195:
! 196:
! 197: __dead static void
! 198: usage(void)
! 199: {
! 200:
! 201: (void)fprintf(stderr, "usage: %s\n", __progname);
! 202: exit(1);
! 203: /* NOTREACHED */
! 204: }
! 205:
! 206:
! 207: static int
! 208: file(char **ln, size_t *lnsz, char **buf, size_t *bufsz,
! 209: const char *file, struct mdoc *mdoc)
! 210: {
! 211: int fd, c;
! 212:
! 213: if (-1 == (fd = open(file, O_RDONLY, 0))) {
! 214: warn("%s", file);
! 215: return(0);
! 216: }
! 217:
! 218: c = fdesc(ln, lnsz, buf, bufsz, file, fd, mdoc);
! 219:
! 220: if (-1 == close(fd))
! 221: warn("%s", file);
! 222:
! 223: return(c);
! 224: }
! 225:
! 226:
! 227: static int
! 228: fdesc(char **lnp, size_t *lnsz, char **bufp, size_t *bufsz,
! 229: const char *f, int fd, struct mdoc *mdoc)
! 230: {
! 231: size_t sz;
! 232: ssize_t ssz;
! 233: struct stat st;
! 234: int j, i, pos, lnn;
! 235: char *ln, *buf;
! 236:
! 237: buf = *bufp;
! 238: ln = *lnp;
! 239:
! 240: /*
! 241: * Two buffers: ln and buf. buf is the input buffer, optimised
! 242: * for each file's block size. ln is a line buffer. Both
! 243: * growable, hence passed in by ptr-ptr.
! 244: */
! 245:
! 246: if (-1 == fstat(fd, &st)) {
! 247: warnx("%s", f);
! 248: sz = BUFSIZ;
! 249: } else
! 250: sz = (unsigned)BUFSIZ > st.st_blksize ?
! 251: (size_t)BUFSIZ : st.st_blksize;
! 252:
! 253: if (sz > *bufsz) {
! 254: if (NULL == (buf = realloc(buf, sz)))
! 255: err(1, "realloc");
! 256: *bufp = buf;
! 257: *bufsz = sz;
! 258: }
! 259:
! 260: /*
! 261: * Fill buf with file blocksize and parse newlines into ln.
! 262: */
! 263:
! 264: for (lnn = 1, pos = 0; ; ) {
! 265: if (-1 == (ssz = read(fd, buf, sz))) {
! 266: warn("%s", f);
! 267: return(0);
! 268: } else if (0 == ssz)
! 269: break;
! 270:
! 271: for (i = 0; i < (int)ssz; i++) {
! 272: if (pos >= (int)*lnsz) {
! 273: *lnsz += 256; /* Step-size. */
! 274: ln = realloc(ln, *lnsz);
! 275: if (NULL == ln)
! 276: err(1, "realloc");
! 277: *lnp = ln;
! 278: }
! 279:
! 280: if ('\n' != buf[i]) {
! 281: ln[pos++] = buf[i];
! 282: continue;
! 283: }
! 284:
! 285: /* Check for CPP-escaped newline. */
! 286:
! 287: if (pos > 0 && '\\' == ln[pos - 1]) {
! 288: for (j = pos - 1; j >= 0; j--)
! 289: if ('\\' != ln[j])
! 290: break;
! 291:
! 292: if ( ! ((pos - j) % 2)) {
! 293: pos--;
! 294: lnn++;
! 295: continue;
! 296: }
! 297: }
! 298:
! 299: ln[pos] = 0;
! 300: if ( ! mdoc_parseln(mdoc, lnn, ln))
! 301: return(0);
! 302: lnn++;
! 303: pos = 0;
! 304: }
! 305: }
! 306:
! 307: return(mdoc_endparse(mdoc));
! 308: }
! 309:
! 310:
! 311: static int
! 312: toptions(enum outt *tflags, char *arg)
! 313: {
! 314:
! 315: if (0 == strcmp(arg, "ascii"))
! 316: *tflags = OUTT_ASCII;
! 317: else if (0 == strcmp(arg, "latin1"))
! 318: *tflags = OUTT_LATIN1;
! 319: else if (0 == strcmp(arg, "utf8"))
! 320: *tflags = OUTT_UTF8;
! 321: else if (0 == strcmp(arg, "lint"))
! 322: *tflags = OUTT_LINT;
! 323: else if (0 == strcmp(arg, "tree"))
! 324: *tflags = OUTT_TREE;
! 325: else {
! 326: warnx("bad argument: -T%s", arg);
! 327: return(0);
! 328: }
! 329:
! 330: return(1);
! 331: }
! 332:
! 333:
! 334: /*
! 335: * Parse out the options for [-fopt...] setting compiler options. These
! 336: * can be comma-delimited or called again.
! 337: */
! 338: static int
! 339: foptions(int *fflags, char *arg)
! 340: {
! 341: char *v;
! 342: char *toks[4];
! 343:
! 344: toks[0] = "ign-scope";
! 345: toks[1] = "ign-escape";
! 346: toks[2] = "ign-macro";
! 347: toks[3] = NULL;
! 348:
! 349: while (*arg)
! 350: switch (getsubopt(&arg, toks, &v)) {
! 351: case (0):
! 352: *fflags |= MDOC_IGN_SCOPE;
! 353: break;
! 354: case (1):
! 355: *fflags |= MDOC_IGN_ESCAPE;
! 356: break;
! 357: case (2):
! 358: *fflags |= MDOC_IGN_MACRO;
! 359: break;
! 360: default:
! 361: warnx("bad argument: -f%s", arg);
! 362: return(0);
! 363: }
! 364:
! 365: return(1);
! 366: }
! 367:
! 368:
! 369: /*
! 370: * Parse out the options for [-Werr...], which sets warning modes.
! 371: * These can be comma-delimited or called again.
! 372: */
! 373: static int
! 374: woptions(int *wflags, char *arg)
! 375: {
! 376: char *v;
! 377: char *toks[5];
! 378:
! 379: toks[0] = "all";
! 380: toks[1] = "compat";
! 381: toks[2] = "syntax";
! 382: toks[3] = "error";
! 383: toks[4] = NULL;
! 384:
! 385: while (*arg)
! 386: switch (getsubopt(&arg, toks, &v)) {
! 387: case (0):
! 388: *wflags |= WARN_WALL;
! 389: break;
! 390: case (1):
! 391: *wflags |= WARN_WCOMPAT;
! 392: break;
! 393: case (2):
! 394: *wflags |= WARN_WSYNTAX;
! 395: break;
! 396: case (3):
! 397: *wflags |= WARN_WERR;
! 398: break;
! 399: default:
! 400: warnx("bad argument: -W%s", arg);
! 401: return(0);
! 402: }
! 403:
! 404: return(1);
! 405: }
! 406:
! 407:
! 408: static int
! 409: merr(void *arg, int line, int col, const char *msg)
! 410: {
! 411:
! 412: warnx("error: %s (line %d, column %d)", msg, line, col);
! 413: return(0);
! 414: }
! 415:
! 416:
! 417: static int
! 418: mwarn(void *arg, int line, int col,
! 419: enum mdoc_warn type, const char *msg)
! 420: {
! 421: int flags;
! 422: char *wtype;
! 423:
! 424: flags = *(int *)arg;
! 425: wtype = NULL;
! 426:
! 427: switch (type) {
! 428: case (WARN_COMPAT):
! 429: wtype = "compat";
! 430: if (flags & WARN_WCOMPAT)
! 431: break;
! 432: return(1);
! 433: case (WARN_SYNTAX):
! 434: wtype = "syntax";
! 435: if (flags & WARN_WSYNTAX)
! 436: break;
! 437: return(1);
! 438: }
! 439:
! 440: assert(wtype);
! 441: warnx("%s warning: %s (line %d, column %d)",
! 442: wtype, msg, line, col);
! 443:
! 444: if ( ! (flags & WARN_WERR))
! 445: return(1);
! 446:
! 447: warnx("%s: considering warnings as errors",
! 448: __progname);
! 449: return(0);
! 450: }
! 451:
! 452:
CVSweb