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