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