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