Annotation of mandoc/validate.c, Revision 1.6
1.6 ! kristaps 1: /* $Id: validate.c,v 1.5 2008/11/30 20:00:08 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: */
19: #include <sys/param.h>
20:
21: #include <assert.h>
22: #include <ctype.h>
23: #include <err.h>
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
27:
28: #include "libmdocml.h"
29: #include "private.h"
30:
1.2 kristaps 31: #define INDENT 4
1.6 ! kristaps 32: #define COLUMNS 72
1.2 kristaps 33:
1.1 kristaps 34: #ifdef __linux__ /* FIXME */
1.2 kristaps 35: #define strlcat strncat
1.1 kristaps 36: #endif
37:
1.6 ! kristaps 38: enum md_tok {
! 39: MD_BLKIN,
! 40: MD_BLKOUT,
! 41: MD_IN,
! 42: MD_OUT,
! 43: MD_TEXT
! 44: };
! 45:
1.1 kristaps 46: struct md_valid {
47: const struct md_args *args;
48: const struct md_rbuf *rbuf;
1.6 ! kristaps 49:
1.1 kristaps 50: struct md_mbuf *mbuf;
51: struct rofftree *tree;
52: size_t indent;
53: size_t pos;
1.6 ! kristaps 54: enum md_tok last;
1.1 kristaps 55: int flags;
1.6 ! kristaps 56: #define MD_LITERAL (1 << 0) /* FIXME */
1.1 kristaps 57: };
58:
59: static void roffmsg(void *arg, enum roffmsg,
60: const char *, const char *, char *);
61: static int roffhead(void *);
62: static int rofftail(void *);
1.6 ! kristaps 63: static int roffin(void *, int, int, int *, char **);
1.4 kristaps 64: static int roffdata(void *, int, char *);
1.1 kristaps 65: static int roffout(void *, int);
1.2 kristaps 66: static int roffblkin(void *, int, int *, char **);
1.1 kristaps 67: static int roffblkout(void *, int);
68: static int roffspecial(void *, int);
69:
70: static int mbuf_newline(struct md_valid *);
71: static int mbuf_indent(struct md_valid *);
1.4 kristaps 72: static int mbuf_data(struct md_valid *, int, char *);
1.6 ! kristaps 73: static int mbuf_putstring(struct md_valid *,
! 74: const char *);
! 75: static int mbuf_nputstring(struct md_valid *,
! 76: const char *, size_t);
! 77:
! 78:
! 79: static int
! 80: mbuf_putstring(struct md_valid *p, const char *buf)
! 81: {
! 82:
! 83: return(mbuf_nputstring(p, buf, strlen(buf)));
! 84: }
! 85:
! 86:
! 87: static int
! 88: mbuf_nputstring(struct md_valid *p, const char *buf, size_t sz)
! 89: {
! 90:
! 91: p->pos += sz;
! 92: return(md_buf_puts(p->mbuf, buf, sz));
! 93: }
1.1 kristaps 94:
95:
96: static int
97: mbuf_indent(struct md_valid *p)
98: {
99: size_t i;
100:
1.2 kristaps 101: assert(p->pos == 0);
1.1 kristaps 102:
1.5 kristaps 103: /* LINTED */
1.2 kristaps 104: for (i = 0; i < MIN(p->indent, INDENT); i++)
1.1 kristaps 105: if ( ! md_buf_putstring(p->mbuf, " "))
106: return(0);
107:
1.2 kristaps 108: p->pos += i * INDENT;
1.1 kristaps 109: return(1);
110: }
111:
112:
113: static int
114: mbuf_newline(struct md_valid *p)
115: {
116:
117: if ( ! md_buf_putchar(p->mbuf, '\n'))
118: return(0);
119:
120: p->pos = 0;
1.2 kristaps 121: return(1);
1.1 kristaps 122: }
123:
124:
125: static int
1.4 kristaps 126: mbuf_data(struct md_valid *p, int space, char *buf)
1.1 kristaps 127: {
128: size_t sz;
129: char *bufp;
130:
131: assert(p->mbuf);
132: assert(0 != p->indent);
133:
1.6 ! kristaps 134: /*
! 135: * FIXME: punctuation/no-space stuff shouldn't have a newline
! 136: * before it.
! 137: */
! 138:
1.1 kristaps 139: if (MD_LITERAL & p->flags)
1.6 ! kristaps 140: return(mbuf_putstring(p, buf));
1.1 kristaps 141:
142: while (*buf) {
143: while (*buf && isspace(*buf))
144: buf++;
145:
146: if (0 == *buf)
147: break;
148:
149: bufp = buf;
150: while (*buf && ! isspace(*buf))
151: buf++;
152:
153: if (0 != *buf)
154: *buf++ = 0;
155:
156: sz = strlen(bufp);
1.2 kristaps 157:
158: if (0 == p->pos) {
159: if ( ! mbuf_indent(p))
160: return(0);
1.6 ! kristaps 161: if ( ! mbuf_nputstring(p, bufp, sz))
1.1 kristaps 162: return(0);
1.6 ! kristaps 163: if (p->indent * INDENT + sz >= COLUMNS) {
1.2 kristaps 164: if ( ! mbuf_newline(p))
165: return(0);
166: continue;
167: }
1.1 kristaps 168: continue;
169: }
170:
1.6 ! kristaps 171: if (sz + p->pos >= COLUMNS) {
1.2 kristaps 172: if ( ! mbuf_newline(p))
173: return(0);
174: if ( ! mbuf_indent(p))
175: return(0);
1.3 kristaps 176: } else if (space)
1.6 ! kristaps 177: if ( ! mbuf_nputstring(p, " ", 1))
1.3 kristaps 178: return(0);
1.1 kristaps 179:
1.6 ! kristaps 180: if ( ! mbuf_nputstring(p, bufp, sz))
1.1 kristaps 181: return(0);
182: }
183:
184: return(1);
185: }
186:
187:
188: int
189: md_line_valid(void *arg, char *buf)
190: {
191: struct md_valid *p;
192:
193: p = (struct md_valid *)arg;
194: return(roff_engine(p->tree, buf));
195: }
196:
197:
198: int
199: md_exit_valid(void *data, int flush)
200: {
201: int c;
202: struct md_valid *p;
203:
204: p = (struct md_valid *)data;
205: c = roff_free(p->tree, flush);
206: free(p);
207:
208: return(c);
209: }
210:
211:
212: void *
213: md_init_valid(const struct md_args *args,
214: struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
215: {
216: struct roffcb cb;
217: struct md_valid *p;
218:
219: cb.roffhead = roffhead;
220: cb.rofftail = rofftail;
221: cb.roffin = roffin;
222: cb.roffout = roffout;
223: cb.roffblkin = roffblkin;
224: cb.roffblkout = roffblkout;
225: cb.roffspecial = roffspecial;
226: cb.roffmsg = roffmsg;
227: cb.roffdata = roffdata;
228:
229: if (NULL == (p = calloc(1, sizeof(struct md_valid))))
230: err(1, "malloc");
231:
232: p->args = args;
233: p->mbuf = mbuf;
234: p->rbuf = rbuf;
235:
236: assert(mbuf);
237:
238: if (NULL == (p->tree = roff_alloc(&cb, p))) {
239: free(p);
240: return(NULL);
241: }
242:
243: return(p);
244: }
245:
246:
247: /* ARGSUSED */
248: static int
249: roffhead(void *arg)
250: {
1.2 kristaps 251: struct md_valid *p;
252:
253: assert(arg);
254: p = (struct md_valid *)arg;
255:
1.6 ! kristaps 256: if ( ! mbuf_putstring(p, "<?xml version=\"1.0\" "
1.4 kristaps 257: "encoding=\"UTF-8\"?>\n"))
258: return(0);
1.6 ! kristaps 259: if ( ! mbuf_nputstring(p, "<mdoc>", 6))
! 260: return(0);
1.4 kristaps 261:
1.2 kristaps 262: p->indent++;
1.4 kristaps 263: return(mbuf_newline(p));
1.1 kristaps 264: }
265:
266:
267: static int
268: rofftail(void *arg)
269: {
270: struct md_valid *p;
271:
272: assert(arg);
273: p = (struct md_valid *)arg;
274:
1.2 kristaps 275: if (0 != p->pos && ! mbuf_newline(p))
276: return(0);
1.6 ! kristaps 277:
! 278: if ( ! mbuf_nputstring(p, "</mdoc>", 7))
! 279: return(0);
! 280: return(mbuf_newline(p));
1.1 kristaps 281: }
282:
283:
1.5 kristaps 284: /* ARGSUSED */
1.1 kristaps 285: static int
286: roffspecial(void *arg, int tok)
287: {
288:
289: return(1);
290: }
291:
292:
293: static int
1.2 kristaps 294: roffblkin(void *arg, int tok, int *argc, char **argv)
1.1 kristaps 295: {
296: struct md_valid *p;
1.5 kristaps 297: int i;
1.1 kristaps 298:
299: assert(arg);
300: p = (struct md_valid *)arg;
301:
1.2 kristaps 302: if (0 != p->pos) {
303: if ( ! mbuf_newline(p))
1.1 kristaps 304: return(0);
305: if ( ! mbuf_indent(p))
306: return(0);
1.2 kristaps 307: } else if ( ! mbuf_indent(p))
308: return(0);
1.1 kristaps 309:
1.6 ! kristaps 310: if ( ! mbuf_nputstring(p, "<", 1))
1.2 kristaps 311: return(0);
1.6 ! kristaps 312: if ( ! mbuf_putstring(p, toknames[tok]))
1.1 kristaps 313: return(0);
1.5 kristaps 314:
315: for (i = 0; ROFF_ARGMAX != argc[i]; i++) {
1.6 ! kristaps 316: if ( ! mbuf_nputstring(p, " ", 1))
1.5 kristaps 317: return(0);
1.6 ! kristaps 318: if ( ! mbuf_putstring(p, tokargnames[argc[i]]))
1.5 kristaps 319: return(0);
1.6 ! kristaps 320: if ( ! mbuf_nputstring(p, "=\"", 2))
1.5 kristaps 321: return(0);
1.6 ! kristaps 322: if ( ! mbuf_putstring(p, argv[i] ? argv[i] : "true"))
1.5 kristaps 323: return(0);
1.6 ! kristaps 324: if ( ! mbuf_nputstring(p, "\"", 1))
1.5 kristaps 325: return(0);
326: }
327:
1.6 ! kristaps 328: if ( ! mbuf_nputstring(p, ">", 1))
1.2 kristaps 329: return(0);
330: if ( ! mbuf_newline(p))
1.1 kristaps 331: return(0);
332:
333: p->indent++;
1.2 kristaps 334: return(1);
1.1 kristaps 335: }
336:
337:
338: static int
339: roffblkout(void *arg, int tok)
340: {
341: struct md_valid *p;
342:
343: assert(arg);
344: p = (struct md_valid *)arg;
345:
1.2 kristaps 346: p->indent--;
347:
348: if (0 != p->pos) {
349: if ( ! mbuf_newline(p))
350: return(0);
351: if ( ! mbuf_indent(p))
352: return(0);
353: } else if ( ! mbuf_indent(p))
1.1 kristaps 354: return(0);
355:
1.6 ! kristaps 356: if ( ! mbuf_nputstring(p, "</", 2))
1.2 kristaps 357: return(0);
1.6 ! kristaps 358: if ( ! mbuf_putstring(p, toknames[tok]))
1.2 kristaps 359: return(0);
1.6 ! kristaps 360: if ( ! mbuf_nputstring(p, ">", 1))
1.2 kristaps 361: return(0);
362: if ( ! mbuf_newline(p))
363: return(0);
1.1 kristaps 364:
1.2 kristaps 365: return(1);
1.1 kristaps 366: }
367:
368:
369: static int
1.6 ! kristaps 370: roffin(void *arg, int tok, int space, int *argc, char **argv)
1.1 kristaps 371: {
1.2 kristaps 372: struct md_valid *p;
1.5 kristaps 373: int i;
1.2 kristaps 374:
375: assert(arg);
376: p = (struct md_valid *)arg;
377:
378: if (0 == p->pos && ! mbuf_indent(p))
379: return(0);
380:
1.6 ! kristaps 381: /*
! 382: * FIXME: put into a buffer before writing (check line length).
! 383: */
1.5 kristaps 384:
1.6 ! kristaps 385: if (space && ! mbuf_nputstring(p, " ", 1))
! 386: return(0);
! 387: if ( ! mbuf_nputstring(p, "<", 1))
1.2 kristaps 388: return(0);
1.6 ! kristaps 389: if ( ! mbuf_putstring(p, toknames[tok]))
1.2 kristaps 390: return(0);
1.5 kristaps 391:
392: for (i = 0; ROFF_ARGMAX != argc[i]; i++) {
1.6 ! kristaps 393: if ( ! mbuf_nputstring(p, " ", 1))
1.5 kristaps 394: return(0);
1.6 ! kristaps 395: if ( ! mbuf_putstring(p, tokargnames[argc[i]]))
1.5 kristaps 396: return(0);
1.6 ! kristaps 397: if ( ! mbuf_nputstring(p, "=\"", 2))
1.5 kristaps 398: return(0);
1.6 ! kristaps 399: if ( ! mbuf_putstring(p, argv[i] ? argv[i] : "true"))
1.5 kristaps 400: return(0);
1.6 ! kristaps 401: if ( ! mbuf_nputstring(p, "\"", 1))
1.5 kristaps 402: return(0);
403: }
404:
1.6 ! kristaps 405: return(mbuf_nputstring(p, ">", 1));
1.1 kristaps 406: }
407:
408:
409: static int
410: roffout(void *arg, int tok)
411: {
1.2 kristaps 412: struct md_valid *p;
413:
414: assert(arg);
415: p = (struct md_valid *)arg;
416:
417: if (0 == p->pos && ! mbuf_indent(p))
418: return(0);
419:
1.6 ! kristaps 420: if ( ! mbuf_nputstring(p, "</", 2))
1.2 kristaps 421: return(0);
1.6 ! kristaps 422: if ( ! mbuf_putstring(p, toknames[tok]))
1.2 kristaps 423: return(0);
1.6 ! kristaps 424: return(mbuf_nputstring(p, ">", 1));
1.1 kristaps 425: }
426:
427:
428: static void
429: roffmsg(void *arg, enum roffmsg lvl,
430: const char *buf, const char *pos, char *msg)
431: {
432: char *level;
433: struct md_valid *p;
434:
435: assert(arg);
436: p = (struct md_valid *)arg;
437:
438: switch (lvl) {
439: case (ROFF_WARN):
440: if ( ! (MD_WARN_ALL & p->args->warnings))
441: return;
442: level = "warning";
443: break;
444: case (ROFF_ERROR):
445: level = "error";
446: break;
447: default:
448: abort();
449: }
450:
451: if (pos)
1.6 ! kristaps 452: (void)fprintf(stderr, "%s:%zu: %s: %s (column %zu)\n",
! 453: p->rbuf->name, p->rbuf->line, level,
! 454: msg, pos - buf);
1.1 kristaps 455: else
456: (void)fprintf(stderr, "%s: %s: %s\n",
457: p->rbuf->name, level, msg);
458:
459: }
460:
461:
462: static int
1.4 kristaps 463: roffdata(void *arg, int space, char *buf)
1.1 kristaps 464: {
465: struct md_valid *p;
466:
467: assert(arg);
468: p = (struct md_valid *)arg;
1.4 kristaps 469: return(mbuf_data(p, space, buf));
1.1 kristaps 470: }
CVSweb