Annotation of mandoc/html.c, Revision 1.9
1.9 ! kristaps 1: /* $Id: html.c,v 1.8 2008/12/05 17:43:14 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.4 kristaps 19: #include <sys/param.h>
20: #include <sys/stat.h>
21:
1.1 kristaps 22: #include <assert.h>
1.4 kristaps 23: #include <err.h>
24: #include <fcntl.h>
1.1 kristaps 25: #include <stdlib.h>
1.4 kristaps 26: #include <stdio.h>
1.2 kristaps 27: #include <string.h>
1.4 kristaps 28: #include <unistd.h>
1.1 kristaps 29:
30: #include "libmdocml.h"
31: #include "private.h"
1.2 kristaps 32: #include "ml.h"
33:
34:
1.8 kristaps 35: /* TODO: allow head/tail-less invocations (just "div" start). */
36:
1.7 kristaps 37: struct htmlnode {
1.8 kristaps 38: int tok;
39: enum md_ns ns;
1.7 kristaps 40: int *argc[ROFF_MAXLINEARG];
41: char *argv[ROFF_MAXLINEARG];
42: struct htmlnode *parent;
43: };
44:
45:
46: struct htmlq {
47: struct htmlnode *last;
48: };
49:
50:
1.4 kristaps 51: static int html_loadcss(struct md_mbuf *, const char *);
52:
1.9 ! kristaps 53: static int html_alloc(void **);
! 54: static void html_free(void *);
1.8 kristaps 55: static ssize_t html_endtag(struct md_mbuf *, void *,
1.2 kristaps 56: const struct md_args *,
57: enum md_ns, int);
1.8 kristaps 58: static ssize_t html_begintag(struct md_mbuf *, void *,
1.2 kristaps 59: const struct md_args *,
60: enum md_ns, int,
61: const int *, const char **);
1.4 kristaps 62: static int html_begin(struct md_mbuf *,
63: const struct md_args *,
64: const struct tm *,
65: const char *, const char *,
66: const char *, const char *);
1.7 kristaps 67: static int html_printargs(struct md_mbuf *, int,
68: const char *, const int *,
69: const char **, size_t *);
1.2 kristaps 70: static int html_end(struct md_mbuf *,
71: const struct md_args *);
1.7 kristaps 72: static int html_blocktagname(struct md_mbuf *,
73: const struct md_args *, int, size_t *);
74: static int html_blocktagargs(struct md_mbuf *,
1.2 kristaps 75: const struct md_args *, int,
1.7 kristaps 76: const int *, const char **, size_t *);
77: static int html_blockheadtagname(struct md_mbuf *,
78: const struct md_args *, int, size_t *);
79: static int html_blockheadtagargs(struct md_mbuf *,
1.3 kristaps 80: const struct md_args *, int,
1.7 kristaps 81: const int *, const char **, size_t *);
82: static int html_blockbodytagname(struct md_mbuf *,
83: const struct md_args *, int, size_t *);
84: static int html_blockbodytagargs(struct md_mbuf *,
1.3 kristaps 85: const struct md_args *, int,
1.7 kristaps 86: const int *, const char **, size_t *);
87: static int html_inlinetagname(struct md_mbuf *,
88: const struct md_args *, int, size_t *);
89: static int html_inlinetagargs(struct md_mbuf *,
1.2 kristaps 90: const struct md_args *, int,
1.7 kristaps 91: const int *, const char **, size_t *);
1.2 kristaps 92:
93:
1.4 kristaps 94: static int
95: html_loadcss(struct md_mbuf *mbuf, const char *css)
96: {
97: size_t res, bufsz;
98: char *buf;
99: struct stat st;
100: int fd, c;
101: ssize_t ssz;
102:
103: c = 0;
104: res = 0;
105: buf = NULL;
106:
107: if (-1 == (fd = open(css, O_RDONLY, 0))) {
108: warn("%s", css);
109: return(0);
110: }
111:
112: if (-1 == fstat(fd, &st)) {
113: warn("%s", css);
114: goto out;
115: }
116:
117: bufsz = MAX(st.st_blksize, BUFSIZ);
118: if (NULL == (buf = malloc(bufsz))) {
119: warn("malloc");
120: goto out;
121: }
122:
123: for (;;) {
124: if (-1 == (ssz = read(fd, buf, bufsz))) {
125: warn("%s", css);
126: goto out;
127: } else if (0 == ssz)
128: break;
129: if ( ! ml_nputs(mbuf, buf, (size_t)ssz, &res))
130: goto out;
131: }
132:
133: c = 1;
134:
135: out:
136: if (-1 == close(fd)) {
137: warn("%s", css);
138: c = 0;
139: }
140:
141: if (buf)
142: free(buf);
143:
144: return(c);
145: }
146:
147:
1.3 kristaps 148: /* ARGSUSED */
1.2 kristaps 149: static int
1.4 kristaps 150: html_begin(struct md_mbuf *mbuf, const struct md_args *args,
151: const struct tm *tm, const char *os,
152: const char *title, const char *section,
153: const char *vol)
1.2 kristaps 154: {
1.4 kristaps 155: const char *preamble, *css, *trail;
156: char buf[512];
1.2 kristaps 157: size_t res;
158:
1.4 kristaps 159: preamble =
160: "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\n"
161: " \"http://www.w3.org/TR/html4/strict.dtd\">\n"
162: "<html>\n"
163: "<head>\n"
164: " <meta http-equiv=\"Content-Type\"\n"
165: " content=\"text/html;charset=utf-8\">\n"
166: " <meta name=\"resource-type\" content=\"document\">\n"
167: " <title>Manual Page for %s(%s)</title>\n";
168:
169: css =
170: " <link rel=\"stylesheet\" type=\"text/css\"\n"
171: " href=\"%s\">\n";
172: trail =
173: "</head>\n"
174: "<body>\n"
175: "<div class=\"mdoc\">\n";
176:
1.2 kristaps 177: res = 0;
1.4 kristaps 178:
179: (void)snprintf(buf, sizeof(buf) - 1,
180: preamble, title, section);
181:
182: if ( ! ml_puts(mbuf, buf, &res))
1.2 kristaps 183: return(0);
1.4 kristaps 184:
185: assert(args->params.html.css);
186: if (HTML_CSS_EMBED & args->params.html.flags) {
1.5 kristaps 187: if ( ! ml_puts(mbuf, " <style type=\"text/css\"><!--\n", &res))
1.4 kristaps 188: return(0);
189: if ( ! html_loadcss(mbuf, args->params.html.css))
190: return(0);
191: if ( ! ml_puts(mbuf, " --!></style>\n", &res))
192: return(0);
193: } else {
194: (void)snprintf(buf, sizeof(buf) - 1, css,
195: args->params.html.css);
196: if ( ! ml_puts(mbuf, buf, &res))
197: return(0);
198: }
199:
200: if ( ! ml_puts(mbuf, trail, &res))
1.2 kristaps 201: return(0);
202:
203: return(1);
204: }
205:
206:
1.3 kristaps 207: /* ARGSUSED */
1.2 kristaps 208: static int
209: html_end(struct md_mbuf *mbuf, const struct md_args *args)
210: {
211:
1.9 ! kristaps 212: return(ml_puts(mbuf, "</div></body>\n</html>", NULL));
1.2 kristaps 213: }
214:
215:
1.3 kristaps 216: /* ARGSUSED */
1.7 kristaps 217: static int
1.3 kristaps 218: html_blockbodytagname(struct md_mbuf *mbuf,
1.7 kristaps 219: const struct md_args *args, int tok, size_t *res)
1.2 kristaps 220: {
1.3 kristaps 221:
1.7 kristaps 222: return(ml_puts(mbuf, "div", res));
1.3 kristaps 223: }
224:
225:
226: /* ARGSUSED */
1.7 kristaps 227: static int
1.3 kristaps 228: html_blockheadtagname(struct md_mbuf *mbuf,
1.7 kristaps 229: const struct md_args *args, int tok, size_t *res)
1.3 kristaps 230: {
231:
1.7 kristaps 232: return(ml_puts(mbuf, "div", res));
1.3 kristaps 233: }
234:
235:
236: /* ARGSUSED */
1.7 kristaps 237: static int
1.3 kristaps 238: html_blocktagname(struct md_mbuf *mbuf,
1.7 kristaps 239: const struct md_args *args, int tok, size_t *res)
1.3 kristaps 240: {
241:
1.7 kristaps 242: return(ml_puts(mbuf, "div", res));
1.3 kristaps 243: }
244:
245:
1.9 ! kristaps 246: /* ARGSUSED */
1.7 kristaps 247: static int
248: html_printargs(struct md_mbuf *mbuf, int tok, const char *ns,
249: const int *argc, const char **argv, size_t *res)
1.3 kristaps 250: {
251:
1.7 kristaps 252: if ( ! ml_puts(mbuf, " class=\"", res))
253: return(0);
254: if ( ! ml_puts(mbuf, ns, res))
255: return(0);
256: if ( ! ml_puts(mbuf, "-", res))
1.3 kristaps 257: return(0);
1.7 kristaps 258: if ( ! ml_puts(mbuf, toknames[tok], res))
1.3 kristaps 259: return(0);
1.9 ! kristaps 260: return(ml_puts(mbuf, "\"", res));
1.3 kristaps 261: }
262:
263:
264: /* ARGSUSED */
1.7 kristaps 265: static int
266: html_blockheadtagargs(struct md_mbuf *mbuf,
267: const struct md_args *args, int tok,
268: const int *argc, const char **argv, size_t *res)
1.3 kristaps 269: {
270:
1.7 kristaps 271: return(html_printargs(mbuf, tok, "head", argc, argv, res));
272: }
1.3 kristaps 273:
274:
1.7 kristaps 275: /* ARGSUSED */
276: static int
277: html_blockbodytagargs(struct md_mbuf *mbuf,
278: const struct md_args *args, int tok,
279: const int *argc, const char **argv, size_t *res)
280: {
1.3 kristaps 281:
1.7 kristaps 282: return(html_printargs(mbuf, tok, "body", argc, argv, res));
1.2 kristaps 283: }
284:
285:
286: /* ARGSUSED */
1.7 kristaps 287: static int
288: html_blocktagargs(struct md_mbuf *mbuf,
289: const struct md_args *args, int tok,
290: const int *argc, const char **argv, size_t *res)
1.2 kristaps 291: {
1.3 kristaps 292:
1.7 kristaps 293: return(html_printargs(mbuf, tok, "block", argc, argv, res));
1.2 kristaps 294: }
1.1 kristaps 295:
296:
297: /* ARGSUSED */
1.7 kristaps 298: static int
299: html_inlinetagargs(struct md_mbuf *mbuf,
300: const struct md_args *args, int tok,
301: const int *argc, const char **argv, size_t *res)
1.2 kristaps 302: {
303:
1.7 kristaps 304: return(html_printargs(mbuf, tok, "inline", argc, argv, res));
1.2 kristaps 305: }
306:
307:
1.3 kristaps 308: /* ARGSUSED */
1.7 kristaps 309: static int
1.2 kristaps 310: html_inlinetagname(struct md_mbuf *mbuf,
1.7 kristaps 311: const struct md_args *args, int tok, size_t *res)
1.2 kristaps 312: {
313:
314: switch (tok) {
1.4 kristaps 315: case (ROFF_Pp):
1.7 kristaps 316: return(ml_puts(mbuf, "div", res));
1.2 kristaps 317: default:
1.9 ! kristaps 318: break;
1.2 kristaps 319: }
1.9 ! kristaps 320:
! 321: return(ml_puts(mbuf, "span", res));
1.2 kristaps 322: }
323:
324:
325: static ssize_t
1.8 kristaps 326: html_begintag(struct md_mbuf *mbuf, void *data,
327: const struct md_args *args, enum md_ns ns,
328: int tok, const int *argc, const char **argv)
1.2 kristaps 329: {
1.7 kristaps 330: size_t res;
1.8 kristaps 331: struct htmlq *q;
332: struct htmlnode *node;
1.2 kristaps 333:
334: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 335: res = 0;
336:
1.8 kristaps 337: assert(data);
338: q = (struct htmlq *)data;
339:
340: if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) {
341: warn("calloc");
342: return(-1);
343: }
344:
345: node->parent = q->last;
346: node->tok = tok;
347: node->ns = ns;
348:
349: q->last = node;
350:
1.3 kristaps 351: switch (ns) {
352: case (MD_NS_BLOCK):
1.7 kristaps 353: if ( ! html_blocktagname(mbuf, args, tok, &res))
354: return(-1);
355: if ( ! html_blocktagargs(mbuf, args, tok,
356: argc, argv, &res))
357: return(-1);
358: break;
1.3 kristaps 359: case (MD_NS_BODY):
1.7 kristaps 360: if ( ! html_blockbodytagname(mbuf, args, tok, &res))
361: return(-1);
362: if ( ! html_blockbodytagargs(mbuf, args, tok,
363: argc, argv, &res))
364: return(-1);
365: break;
1.3 kristaps 366: case (MD_NS_HEAD):
1.7 kristaps 367: if ( ! html_blockheadtagname(mbuf, args, tok, &res))
368: return(-1);
369: if ( ! html_blockheadtagargs(mbuf, args, tok,
370: argc, argv, &res))
371: return(-1);
372: break;
1.3 kristaps 373: default:
1.7 kristaps 374: if ( ! html_inlinetagname(mbuf, args, tok, &res))
375: return(-1);
376: if ( ! html_inlinetagargs(mbuf, args, tok,
377: argc, argv, &res))
378: return(-1);
1.3 kristaps 379: break;
1.2 kristaps 380: }
381:
1.7 kristaps 382: return((ssize_t)res);
1.2 kristaps 383: }
384:
385:
386: static ssize_t
1.8 kristaps 387: html_endtag(struct md_mbuf *mbuf, void *data,
388: const struct md_args *args, enum md_ns ns, int tok)
1.2 kristaps 389: {
1.7 kristaps 390: size_t res;
1.8 kristaps 391: struct htmlq *q;
392: struct htmlnode *node;
1.2 kristaps 393:
394: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 395: res = 0;
396:
1.8 kristaps 397: assert(data);
398: q = (struct htmlq *)data;
399:
1.3 kristaps 400: switch (ns) {
401: case (MD_NS_BLOCK):
1.7 kristaps 402: if ( ! html_blocktagname(mbuf, args, tok, &res))
403: return(-1);
404: break;
1.3 kristaps 405: case (MD_NS_BODY):
1.7 kristaps 406: if ( ! html_blockbodytagname(mbuf, args, tok, &res))
407: return(-1);
408: break;
1.3 kristaps 409: case (MD_NS_HEAD):
1.7 kristaps 410: if ( ! html_blockheadtagname(mbuf, args, tok, &res))
411: return(-1);
412: break;
1.3 kristaps 413: default:
1.7 kristaps 414: if ( ! html_inlinetagname(mbuf, args, tok, &res))
415: return(-1);
1.3 kristaps 416: break;
417: }
1.2 kristaps 418:
1.8 kristaps 419: node = q->last;
420: q->last = node->parent;
421:
1.9 ! kristaps 422: free(node);
1.8 kristaps 423:
1.7 kristaps 424: return((ssize_t)res);
1.2 kristaps 425: }
426:
427:
1.9 ! kristaps 428: static int
! 429: html_alloc(void **p)
! 430: {
! 431:
! 432: if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) {
! 433: warn("calloc");
! 434: return(0);
! 435: }
! 436: return(1);
! 437: }
! 438:
! 439:
! 440: static void
! 441: html_free(void *p)
! 442: {
! 443: struct htmlq *q;
! 444: struct htmlnode *n;
! 445:
! 446: assert(p);
! 447: q = (struct htmlq *)p;
! 448:
! 449: while ((n = q->last)) {
! 450: q->last = n->parent;
! 451: free(n);
! 452: }
! 453:
! 454: free(q);
! 455: }
! 456:
! 457:
1.1 kristaps 458: int
459: md_line_html(void *data, char *buf)
460: {
461:
1.2 kristaps 462: return(mlg_line((struct md_mlg *)data, buf));
1.1 kristaps 463: }
464:
465:
466: int
467: md_exit_html(void *data, int flush)
468: {
469:
1.2 kristaps 470: return(mlg_exit((struct md_mlg *)data, flush));
1.1 kristaps 471: }
472:
473:
474: void *
475: md_init_html(const struct md_args *args,
476: struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
477: {
1.9 ! kristaps 478: struct ml_cbs cbs;
1.8 kristaps 479:
1.9 ! kristaps 480: cbs.ml_alloc = html_alloc;
! 481: cbs.ml_free = html_free;
! 482: cbs.ml_begintag = html_begintag;
! 483: cbs.ml_endtag = html_endtag;
! 484: cbs.ml_begin = html_begin;
! 485: cbs.ml_end = html_end;
1.1 kristaps 486:
1.9 ! kristaps 487: return(mlg_alloc(args, rbuf, mbuf, &cbs));
1.1 kristaps 488: }
1.2 kristaps 489:
CVSweb