Annotation of mandoc/mdocml.c, Revision 1.21
1.21 ! kristaps 1: /* $Id: mdocml.c,v 1.20 2008/12/10 14:42:46 kristaps Exp $ */
1.1 kristaps 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: */
1.21 ! kristaps 19: #include <sys/stat.h>
1.1 kristaps 20: #include <sys/param.h>
21:
22: #include <assert.h>
1.21 ! kristaps 23: #include <fcntl.h>
1.1 kristaps 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:
1.21 ! kristaps 31: #include "mdoc.h"
1.1 kristaps 32:
1.21 ! kristaps 33: #define MD_LINE_SZ (256)
1.2 kristaps 34:
1.21 ! kristaps 35: struct md_parse {
! 36: int warn;
! 37: #define MD_WARN_ALL (1 << 0)
! 38: #define MD_WARN_ERR (1 << 1)
! 39: int dbg;
! 40: struct mdoc *mdoc;
! 41: char *buf;
! 42: u_long bufsz;
! 43: char *name;
! 44: int fd;
! 45: int lnn;
! 46: char *line;
! 47: };
1.17 kristaps 48:
1.9 kristaps 49: static void usage(void);
50:
1.21 ! kristaps 51: static int parse_begin(struct md_parse *);
! 52: static int parse_leave(struct md_parse *, int);
! 53: static int io_begin(struct md_parse *);
! 54: static int io_leave(struct md_parse *, int);
! 55: static int buf_begin(struct md_parse *);
! 56: static int buf_leave(struct md_parse *, int);
! 57:
! 58: static int msg_err(void *, int, int, enum mdoc_err);
! 59: static int msg_warn(void *, int, int, enum mdoc_warn);
! 60: static void msg_msg(void *, int, const char *);
1.1 kristaps 61:
1.19 kristaps 62: #ifdef __linux__
63: extern int getsubopt(char **, char *const *, char **);
64: #endif
65:
1.1 kristaps 66: int
67: main(int argc, char *argv[])
68: {
69: int c;
1.21 ! kristaps 70: struct md_parse parser;
! 71: char *opts, *v;
1.18 kristaps 72: #define ALL 0
73: #define ERROR 1
74: char *toks[] = { "all", "error", NULL };
1.1 kristaps 75:
76: extern char *optarg;
77: extern int optind;
78:
1.21 ! kristaps 79: (void)memset(&parser, 0, sizeof(struct md_parse));
1.17 kristaps 80:
1.21 ! kristaps 81: while (-1 != (c = getopt(argc, argv, "vW:")))
1.1 kristaps 82: switch (c) {
1.13 kristaps 83: case ('v'):
1.21 ! kristaps 84: parser.dbg++;
1.13 kristaps 85: break;
86: case ('W'):
1.18 kristaps 87: opts = optarg;
88: while (*opts)
89: switch (getsubopt(&opts, toks, &v)) {
90: case (ALL):
1.21 ! kristaps 91: parser.warn |= MD_WARN_ALL;
1.18 kristaps 92: break;
93: case (ERROR):
1.21 ! kristaps 94: parser.warn |= MD_WARN_ERR;
1.18 kristaps 95: break;
96: default:
97: usage();
98: return(1);
99: }
1.13 kristaps 100: break;
1.1 kristaps 101: default:
102: usage();
103: return(1);
104: }
105:
106: argv += optind;
1.4 kristaps 107: argc -= optind;
1.1 kristaps 108:
1.21 ! kristaps 109: parser.name = "-";
1.4 kristaps 110: if (1 == argc)
1.21 ! kristaps 111: parser.name = *argv++;
! 112:
! 113: if ( ! io_begin(&parser))
! 114: return(EXIT_FAILURE);
1.1 kristaps 115:
1.21 ! kristaps 116: return(EXIT_SUCCESS);
1.1 kristaps 117: }
118:
119:
120: static int
1.21 ! kristaps 121: io_leave(struct md_parse *p, int code)
1.1 kristaps 122: {
123:
1.21 ! kristaps 124: if (-1 == p->fd || STDIN_FILENO == p->fd)
! 125: return(code);
! 126:
! 127: if (-1 == close(p->fd)) {
! 128: warn("%s", p->name);
! 129: code = 0;
1.4 kristaps 130: }
1.21 ! kristaps 131: return(code);
! 132: }
! 133:
! 134:
! 135: static int
! 136: io_begin(struct md_parse *p)
! 137: {
! 138:
! 139: p->fd = STDIN_FILENO;
! 140: if (0 != strncmp(p->name, "-", 1))
! 141: if (-1 == (p->fd = open(p->name, O_RDONLY, 0))) {
! 142: warn("%s", p->name);
! 143: return(io_leave(p, 0));
! 144: }
1.1 kristaps 145:
1.21 ! kristaps 146: return(io_leave(p, buf_begin(p)));
1.1 kristaps 147: }
148:
149:
150: static int
1.21 ! kristaps 151: buf_leave(struct md_parse *p, int code)
1.1 kristaps 152: {
1.4 kristaps 153:
1.21 ! kristaps 154: if (p->buf)
! 155: free(p->buf);
! 156: return(code);
! 157: }
1.1 kristaps 158:
159:
1.21 ! kristaps 160: static int
! 161: buf_begin(struct md_parse *p)
! 162: {
! 163: struct stat st;
1.1 kristaps 164:
1.21 ! kristaps 165: if (-1 == fstat(p->fd, &st)) {
! 166: warn("%s", p->name);
! 167: return(1);
! 168: }
! 169:
! 170: p->bufsz = MAX(st.st_blksize, BUFSIZ);
! 171:
! 172: if (NULL == (p->buf = malloc(p->bufsz))) {
! 173: warn("malloc");
! 174: return(buf_leave(p, 0));
! 175: }
! 176:
! 177: return(buf_leave(p, parse_begin(p)));
! 178: }
! 179:
! 180:
! 181: static void
! 182: print_node(const struct mdoc_node *n, int indent)
! 183: {
! 184: const char *p, *t;
! 185: int i;
! 186:
! 187: switch (n->type) {
! 188: case (MDOC_TEXT):
! 189: assert(NULL == n->child);
! 190: p = "<text>";
! 191: t = "text";
! 192: break;
! 193: case (MDOC_BODY):
! 194: p = mdoc_macronames[n->data.body.tok];
! 195: t = "block-body";
! 196: break;
! 197: case (MDOC_HEAD):
! 198: p = mdoc_macronames[n->data.head.tok];
! 199: t = "block-head";
! 200: break;
! 201: case (MDOC_ELEM):
! 202: assert(NULL == n->child);
! 203: p = mdoc_macronames[n->data.elem.tok];
! 204: t = "element";
! 205: break;
! 206: case (MDOC_BLOCK):
! 207: p = mdoc_macronames[n->data.block.tok];
! 208: t = "block";
! 209: break;
! 210: }
! 211:
! 212: for (i = 0; i < indent; i++)
! 213: (void)printf(" ");
! 214: (void)printf("%s (%s)\n", p, t);
! 215:
! 216: if (n->child)
! 217: print_node(n->child, indent + 1);
! 218: if (n->next)
! 219: print_node(n->next, indent);
! 220: }
1.1 kristaps 221:
222:
1.21 ! kristaps 223: static int
! 224: parse_leave(struct md_parse *p, int code)
! 225: {
! 226: const struct mdoc_node *n;
! 227:
! 228: if (p->mdoc) {
! 229: if ((n = mdoc_result(p->mdoc)))
! 230: print_node(n, 0);
! 231: mdoc_free(p->mdoc);
! 232: }
! 233: return(code);
! 234: }
! 235:
! 236:
! 237: static int
! 238: parse_begin(struct md_parse *p)
! 239: {
! 240: ssize_t sz, i;
! 241: size_t pos;
! 242: char line[256], sv[256];
! 243: struct mdoc_cb cb;
! 244:
! 245: cb.mdoc_err = msg_err;
! 246: cb.mdoc_warn = msg_warn;
! 247: cb.mdoc_msg = msg_msg;
! 248:
! 249: if (NULL == (p->mdoc = mdoc_alloc(p, &cb)))
! 250: return(parse_leave(p, 0));
! 251:
! 252: p->lnn = 1;
! 253: p->line = sv;
! 254:
! 255: for (pos = 0; ; ) {
! 256: if (-1 == (sz = read(p->fd, p->buf, p->bufsz))) {
! 257: warn("%s", p->name);
! 258: return(parse_leave(p, 0));
! 259: } else if (0 == sz)
! 260: break;
! 261:
! 262: for (i = 0; i < sz; i++) {
! 263: if ('\n' != p->buf[i]) {
! 264: if (pos < sizeof(line)) {
! 265: /* LINTED */
! 266: sv[pos] = p->buf[i];
! 267: line[pos++] = p->buf[i];
! 268: continue;
! 269: }
! 270: warnx("%s: line %d too long",
! 271: p->name, p->lnn);
! 272: return(parse_leave(p, 0));
! 273: }
! 274:
! 275: line[(int)pos] = sv[(int)pos] = 0;
! 276: if ( ! mdoc_parseln(p->mdoc, line))
! 277: return(parse_leave(p, 0));
1.1 kristaps 278:
1.21 ! kristaps 279: p->lnn++;
! 280: pos = 0;
1.4 kristaps 281: }
1.21 ! kristaps 282: }
1.1 kristaps 283:
1.21 ! kristaps 284: return(parse_leave(p, 1));
1.4 kristaps 285: }
1.1 kristaps 286:
287:
1.4 kristaps 288: static int
1.21 ! kristaps 289: msg_err(void *arg, int tok, int col, enum mdoc_err type)
! 290: {
! 291: char *fmt, *lit;
! 292: struct md_parse *p;
! 293: int i;
! 294:
! 295: p = (struct md_parse *)arg;
! 296:
! 297: fmt = lit = NULL;
! 298:
! 299: switch (type) {
! 300: case (ERR_SYNTAX_QUOTE):
! 301: lit = "syntax: unterminated quotation";
! 302: break;
! 303: case (ERR_SYNTAX_WS):
! 304: lit = "syntax: whitespace in argument";
! 305: break;
! 306: case (ERR_SCOPE_BREAK):
! 307: /* Which scope is broken? */
! 308: fmt = "macro `%s' breaks prior explicit scope";
! 309: break;
! 310: case (ERR_MACRO_NOTSUP):
! 311: fmt = "macro `%s' not supported";
! 312: break;
! 313: case (ERR_MACRO_NOTCALL):
! 314: fmt = "macro `%s' not callable";
! 315: break;
! 316: case (ERR_ARGS_GE1):
! 317: fmt = "macro `%s' expects one or more arguments";
! 318: break;
! 319: default:
! 320: abort();
! 321: /* NOTREACHED */
! 322: }
! 323:
! 324: if (fmt) {
! 325: (void)fprintf(stderr, "%s:%d: error: ",
! 326: p->name, p->lnn);
! 327: (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
! 328: } else
! 329: (void)fprintf(stderr, "%s:%d: error: %s",
! 330: p->name, p->lnn, lit);
! 331:
! 332: if (p->dbg < 1) {
! 333: (void)fprintf(stderr, " (column %d)\n", col);
! 334: return(0);
! 335: }
! 336:
! 337: (void)fprintf(stderr, "\nFrom: %s\n ", p->line);
! 338: for (i = 0; i < col; i++)
! 339: (void)fprintf(stderr, " ");
! 340: (void)fprintf(stderr, "^\n");
! 341:
! 342: return(0);
! 343: }
! 344:
! 345:
! 346: static void
! 347: msg_msg(void *arg, int col, const char *msg)
1.4 kristaps 348: {
1.21 ! kristaps 349: struct md_parse *p;
! 350: int i;
! 351:
! 352: p = (struct md_parse *)arg;
! 353:
! 354: if (p->dbg < 2)
! 355: return;
! 356:
! 357: (void)printf("%s:%d: %s", p->name, p->lnn, msg);
! 358:
! 359: if (p->dbg < 3) {
! 360: (void)printf(" (column %d)\n", col);
! 361: return;
! 362: }
! 363:
! 364: (void)printf("\nFrom: %s\n ", p->line);
! 365: for (i = 0; i < col; i++)
! 366: (void)printf(" ");
! 367: (void)printf("^\n");
1.1 kristaps 368: }
369:
370:
371: static int
1.21 ! kristaps 372: msg_warn(void *arg, int tok, int col, enum mdoc_warn type)
1.1 kristaps 373: {
1.21 ! kristaps 374: char *fmt, *lit;
! 375: struct md_parse *p;
! 376: int i;
! 377: extern char *__progname;
1.1 kristaps 378:
1.21 ! kristaps 379: p = (struct md_parse *)arg;
1.1 kristaps 380:
1.21 ! kristaps 381: if ( ! (p->warn & MD_WARN_ALL))
1.1 kristaps 382: return(1);
1.21 ! kristaps 383:
! 384: fmt = lit = NULL;
! 385:
! 386: switch (type) {
! 387: case (WARN_SYNTAX_WS_EOLN):
! 388: lit = "syntax: whitespace at end-of-line";
! 389: break;
! 390: case (WARN_SYNTAX_MACLIKE):
! 391: lit = "syntax: macro-like argument";
! 392: break;
! 393: case (WARN_ARGS_GE1):
! 394: fmt = "macro `%s' suggests one or more arguments";
! 395: break;
! 396: default:
! 397: abort();
! 398: /* NOTREACHED */
1.1 kristaps 399: }
400:
1.21 ! kristaps 401: if (fmt) {
! 402: (void)fprintf(stderr, "%s:%d: warning: ",
! 403: p->name, p->lnn);
! 404: (void)fprintf(stderr, fmt, mdoc_macronames[tok]);
! 405: } else
! 406: (void)fprintf(stderr, "%s:%d: warning: %s",
! 407: p->name, p->lnn, lit);
! 408:
! 409: if (p->dbg >= 1) {
! 410: (void)fprintf(stderr, "\nFrom: %s\n ", p->line);
! 411: for (i = 0; i < col; i++)
! 412: (void)fprintf(stderr, " ");
! 413: (void)fprintf(stderr, "^\n");
! 414: } else
! 415: (void)fprintf(stderr, " (column %d)\n", col);
! 416:
! 417: if (p->warn & MD_WARN_ERR) {
! 418: (void)fprintf(stderr, "%s: considering warnings as "
! 419: "errors\n", __progname);
! 420: return(0);
1.1 kristaps 421: }
422:
1.21 ! kristaps 423: return(1);
1.1 kristaps 424: }
425:
426:
427: static void
428: usage(void)
429: {
430: extern char *__progname;
431:
1.21 ! kristaps 432: (void)fprintf(stderr, "usage: %s [-v] [-Wwarn...] [infile]\n",
1.19 kristaps 433: __progname);
1.1 kristaps 434: }
1.18 kristaps 435:
CVSweb