Annotation of mandoc/html.c, Revision 1.24
1.24 ! kristaps 1: /* $Id: html.c,v 1.23 2008/12/10 12:09:47 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:
1.19 kristaps 30: #include "html.h"
1.2 kristaps 31: #include "ml.h"
32:
1.8 kristaps 33: /* TODO: allow head/tail-less invocations (just "div" start). */
34:
1.7 kristaps 35: struct htmlnode {
1.8 kristaps 36: int tok;
37: enum md_ns ns;
1.10 kristaps 38: int argc[ROFF_MAXLINEARG];
1.7 kristaps 39: char *argv[ROFF_MAXLINEARG];
40: struct htmlnode *parent;
41: };
42:
43: struct htmlq {
44: struct htmlnode *last;
45: };
46:
47:
1.19 kristaps 48: static int html_loadcss(struct md_mbuf *,
49: const char *);
1.9 kristaps 50: static int html_alloc(void **);
51: static void html_free(void *);
1.8 kristaps 52: static ssize_t html_endtag(struct md_mbuf *, void *,
1.2 kristaps 53: const struct md_args *,
54: enum md_ns, int);
1.14 kristaps 55: static ssize_t html_beginstring(struct md_mbuf *,
56: const struct md_args *,
57: const char *, size_t);
58: static ssize_t html_beginhttp(struct md_mbuf *,
59: const struct md_args *,
60: const char *, size_t);
61: static ssize_t html_endstring(struct md_mbuf *,
62: const struct md_args *,
63: const char *, size_t);
64: static ssize_t html_endhttp(struct md_mbuf *,
65: const struct md_args *,
66: const char *, size_t);
1.8 kristaps 67: static ssize_t html_begintag(struct md_mbuf *, void *,
1.2 kristaps 68: const struct md_args *,
69: enum md_ns, int,
70: const int *, const char **);
1.4 kristaps 71: static int html_begin(struct md_mbuf *,
72: const struct md_args *,
73: const struct tm *,
74: const char *, const char *,
1.21 kristaps 75: enum roffmsec, enum roffvol);
1.7 kristaps 76: static int html_printargs(struct md_mbuf *, int,
77: const char *, const int *,
78: const char **, size_t *);
1.22 kristaps 79: static int html_end(struct md_mbuf *,
80: const struct md_args *,
81: const struct tm *,
82: const char *, const char *,
83: enum roffmsec, enum roffvol);
1.7 kristaps 84: static int html_blocktagname(struct md_mbuf *,
1.10 kristaps 85: const struct md_args *, int,
86: struct htmlq *, const int *,
87: const char **, size_t *);
1.7 kristaps 88: static int html_blocktagargs(struct md_mbuf *,
1.2 kristaps 89: const struct md_args *, int,
1.7 kristaps 90: const int *, const char **, size_t *);
1.10 kristaps 91: static int html_headtagname(struct md_mbuf *,
92: const struct md_args *, int,
93: struct htmlq *, const int *,
94: const char **, size_t *);
95: static int html_headtagargs(struct md_mbuf *,
1.3 kristaps 96: const struct md_args *, int,
1.7 kristaps 97: const int *, const char **, size_t *);
1.12 kristaps 98: static int html_bodytagname(struct md_mbuf *,
1.10 kristaps 99: const struct md_args *,
100: int, struct htmlq *, const int *,
101: const char **, size_t *);
1.12 kristaps 102: static int html_bodytagargs(struct md_mbuf *,
1.3 kristaps 103: const struct md_args *, int,
1.7 kristaps 104: const int *, const char **, size_t *);
105: static int html_inlinetagname(struct md_mbuf *,
106: const struct md_args *, int, size_t *);
107: static int html_inlinetagargs(struct md_mbuf *,
1.2 kristaps 108: const struct md_args *, int,
1.7 kristaps 109: const int *, const char **, size_t *);
1.10 kristaps 110: static int html_Bl_bodytagname(struct md_mbuf *,
111: struct htmlq *, const int *,
112: const char **, size_t *);
113: static int html_It_blocktagname(struct md_mbuf *,
114: struct htmlq *, const int *,
115: const char **, size_t *);
116: static int html_It_headtagname(struct md_mbuf *,
117: struct htmlq *, const int *,
118: const char **, size_t *);
119: static int html_It_bodytagname(struct md_mbuf *,
120: struct htmlq *, const int *,
121: const char **, size_t *);
1.19 kristaps 122: static int html_tputln(struct md_mbuf *,
123: enum ml_scope, int, enum html_tag);
124: static int html_aputln(struct md_mbuf *, enum ml_scope,
125: int, enum html_tag,
126: int, const struct html_pair *);
1.10 kristaps 127:
128:
129: /* ARGSUSED */
130: static int
131: html_It_headtagname(struct md_mbuf *mbuf, struct htmlq *q,
132: const int *argc, const char **argv, size_t *res)
133: {
134: struct htmlnode *n;
1.11 kristaps 135: int i;
1.10 kristaps 136:
137: for (n = q->last; n; n = n->parent)
138: if (n->tok == ROFF_Bl)
139: break;
140:
141: assert(n);
1.13 kristaps 142:
143: /* LINTED */
1.11 kristaps 144: for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10 kristaps 145: i < ROFF_MAXLINEARG; i++) {
146: switch (n->argc[i]) {
1.14 kristaps 147: case (ROFF_Ohang):
1.19 kristaps 148: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.10 kristaps 149: case (ROFF_Tag):
150: /* FALLTHROUGH */
151: case (ROFF_Column):
1.19 kristaps 152: return(html_stput(mbuf, HTML_TAG_TD, res));
1.10 kristaps 153: default:
154: break;
155: }
156: }
157:
1.16 kristaps 158: return(0);
1.10 kristaps 159: }
160:
161:
162: /* ARGSUSED */
163: static int
164: html_It_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
165: const int *argc, const char **argv, size_t *res)
166: {
167: struct htmlnode *n;
1.11 kristaps 168: int i;
1.10 kristaps 169:
170: for (n = q->last; n; n = n->parent)
171: if (n->tok == ROFF_Bl)
172: break;
173:
174: assert(n);
1.13 kristaps 175:
176: /* LINTED */
1.11 kristaps 177: for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10 kristaps 178: i < ROFF_MAXLINEARG; i++) {
179: switch (n->argc[i]) {
180: case (ROFF_Enum):
181: /* FALLTHROUGH */
182: case (ROFF_Bullet):
183: /* FALLTHROUGH */
184: case (ROFF_Dash):
185: /* FALLTHROUGH */
186: case (ROFF_Hyphen):
187: /* FALLTHROUGH */
188: case (ROFF_Item):
189: /* FALLTHROUGH */
190: case (ROFF_Diag):
191: /* FALLTHROUGH */
192: case (ROFF_Hang):
193: /* FALLTHROUGH */
194: case (ROFF_Ohang):
195: /* FALLTHROUGH */
196: case (ROFF_Inset):
1.19 kristaps 197: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.10 kristaps 198: case (ROFF_Tag):
199: /* FALLTHROUGH */
200: case (ROFF_Column):
1.19 kristaps 201: return(html_stput(mbuf, HTML_TAG_TD, res));
1.10 kristaps 202: default:
203: break;
204: }
205: }
206:
207: assert(i != ROFF_MAXLINEARG);
1.16 kristaps 208: return(0);
1.10 kristaps 209: }
210:
211:
212: /* ARGSUSED */
213: static int
214: html_Bl_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
215: const int *argc, const char **argv, size_t *res)
216: {
1.11 kristaps 217: int i;
1.10 kristaps 218:
1.11 kristaps 219: for (i = 0; ROFF_ARGMAX != argc[i]
1.10 kristaps 220: && i < ROFF_MAXLINEARG; i++) {
221: switch (argc[i]) {
222: case (ROFF_Enum):
1.19 kristaps 223: return(html_stput(mbuf, HTML_TAG_OL, res));
1.10 kristaps 224: case (ROFF_Bullet):
225: /* FALLTHROUGH */
226: case (ROFF_Dash):
227: /* FALLTHROUGH */
228: case (ROFF_Hyphen):
229: /* FALLTHROUGH */
230: case (ROFF_Item):
231: /* FALLTHROUGH */
232: case (ROFF_Diag):
233: /* FALLTHROUGH */
234: case (ROFF_Hang):
235: /* FALLTHROUGH */
236: case (ROFF_Ohang):
237: /* FALLTHROUGH */
238: case (ROFF_Inset):
1.19 kristaps 239: return(html_stput(mbuf, HTML_TAG_UL, res));
1.10 kristaps 240: case (ROFF_Tag):
241: /* FALLTHROUGH */
242: case (ROFF_Column):
1.19 kristaps 243: return(html_stput(mbuf, HTML_TAG_TABLE, res));
1.10 kristaps 244: default:
245: break;
246: }
247: }
248:
249: assert(i != ROFF_MAXLINEARG);
1.16 kristaps 250: return(0);
1.10 kristaps 251: }
252:
253:
254: /* ARGSUSED */
255: static int
256: html_It_blocktagname(struct md_mbuf *mbuf, struct htmlq *q,
257: const int *argc, const char **argv, size_t *res)
258: {
259: struct htmlnode *n;
1.11 kristaps 260: int i;
1.10 kristaps 261:
262: for (n = q->last; n; n = n->parent)
263: if (n->tok == ROFF_Bl)
264: break;
265:
266: assert(n);
1.13 kristaps 267:
268: /* LINTED */
1.11 kristaps 269: for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10 kristaps 270: i < ROFF_MAXLINEARG; i++) {
271: switch (n->argc[i]) {
272: case (ROFF_Enum):
273: /* FALLTHROUGH */
274: case (ROFF_Bullet):
275: /* FALLTHROUGH */
276: case (ROFF_Dash):
277: /* FALLTHROUGH */
278: case (ROFF_Hyphen):
279: /* FALLTHROUGH */
280: case (ROFF_Item):
281: /* FALLTHROUGH */
282: case (ROFF_Diag):
283: /* FALLTHROUGH */
284: case (ROFF_Hang):
285: /* FALLTHROUGH */
286: case (ROFF_Ohang):
287: /* FALLTHROUGH */
288: case (ROFF_Inset):
1.19 kristaps 289: return(html_stput(mbuf, HTML_TAG_LI, res));
1.10 kristaps 290: case (ROFF_Tag):
291: /* FALLTHROUGH */
292: case (ROFF_Column):
1.19 kristaps 293: return(html_stput(mbuf, HTML_TAG_TR, res));
1.10 kristaps 294: default:
295: break;
296: }
297: }
298:
299: assert(i != ROFF_MAXLINEARG);
1.16 kristaps 300: return(0);
1.10 kristaps 301: }
1.2 kristaps 302:
303:
1.4 kristaps 304: static int
305: html_loadcss(struct md_mbuf *mbuf, const char *css)
306: {
307: size_t res, bufsz;
308: char *buf;
309: struct stat st;
310: int fd, c;
311: ssize_t ssz;
312:
313: c = 0;
314: res = 0;
315: buf = NULL;
316:
317: if (-1 == (fd = open(css, O_RDONLY, 0))) {
318: warn("%s", css);
319: return(0);
320: }
321:
322: if (-1 == fstat(fd, &st)) {
323: warn("%s", css);
324: goto out;
325: }
326:
327: bufsz = MAX(st.st_blksize, BUFSIZ);
328: if (NULL == (buf = malloc(bufsz))) {
329: warn("malloc");
330: goto out;
331: }
332:
333: for (;;) {
334: if (-1 == (ssz = read(fd, buf, bufsz))) {
335: warn("%s", css);
336: goto out;
337: } else if (0 == ssz)
338: break;
339: if ( ! ml_nputs(mbuf, buf, (size_t)ssz, &res))
340: goto out;
341: }
342:
343: c = 1;
344:
345: out:
346: if (-1 == close(fd)) {
347: warn("%s", css);
348: c = 0;
349: }
350:
351: if (buf)
352: free(buf);
353:
354: return(c);
355: }
356:
357:
1.18 kristaps 358: static int
1.19 kristaps 359: html_tputln(struct md_mbuf *mbuf, enum ml_scope scope,
360: int i, enum html_tag tag)
1.18 kristaps 361: {
362:
1.19 kristaps 363: if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
1.18 kristaps 364: return(0);
1.19 kristaps 365: if ( ! html_tput(mbuf, scope, tag, NULL))
1.18 kristaps 366: return(0);
1.19 kristaps 367: return(ml_nputs(mbuf, "\n", 1, NULL));
1.18 kristaps 368: }
369:
370:
371: static int
1.19 kristaps 372: html_aputln(struct md_mbuf *mbuf, enum ml_scope scope, int i,
373: enum html_tag tag, int sz, const struct html_pair *p)
1.18 kristaps 374: {
375:
1.19 kristaps 376: if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
1.18 kristaps 377: return(0);
1.19 kristaps 378: if ( ! html_aput(mbuf, scope, tag, NULL, sz, p))
379: return(0);
380: return(ml_nputs(mbuf, "\n", 1, NULL));
1.18 kristaps 381: }
382:
383:
1.3 kristaps 384: /* ARGSUSED */
1.2 kristaps 385: static int
1.4 kristaps 386: html_begin(struct md_mbuf *mbuf, const struct md_args *args,
387: const struct tm *tm, const char *os,
1.21 kristaps 388: const char *name, enum roffmsec msec, enum roffvol vol)
1.2 kristaps 389: {
1.22 kristaps 390: enum roffvol bvol;
1.19 kristaps 391: struct html_pair attr[4];
1.21 kristaps 392: char ts[32], title[64];
1.19 kristaps 393: int i;
1.2 kristaps 394:
1.19 kristaps 395: (void)snprintf(ts, sizeof(ts), "%s(%s)",
396: name, roff_msecname(msec));
1.4 kristaps 397:
1.21 kristaps 398: if (vol >= ROFF_ARCH_START) {
1.22 kristaps 399: switch (msec) {
400: case(ROFF_MSEC_1):
401: /* FALLTHROUGH */
402: case(ROFF_MSEC_6):
403: /* FALLTHROUGH */
404: case(ROFF_MSEC_7):
405: bvol = ROFF_VOL_URM;
406: break;
407: case(ROFF_MSEC_2):
408: /* FALLTHROUGH */
409: case(ROFF_MSEC_3):
410: /* FALLTHROUGH */
411: case(ROFF_MSEC_3p):
412: /* FALLTHROUGH */
413: case(ROFF_MSEC_4):
414: /* FALLTHROUGH */
415: case(ROFF_MSEC_5):
416: bvol = ROFF_VOL_PRM;
417: break;
418: case(ROFF_MSEC_8):
419: bvol = ROFF_VOL_PRM;
420: break;
421: case(ROFF_MSEC_9):
422: bvol = ROFF_VOL_KM;
423: break;
424: case(ROFF_MSEC_UNASS):
425: /* FALLTHROUGH */
426: case(ROFF_MSEC_DRAFT):
427: /* FALLTHROUGH */
428: case(ROFF_MSEC_PAPER):
429: bvol = ROFF_VOL_NONE;
430: break;
431: default:
432: abort();
433: /* NOTREACHED */
434: }
1.21 kristaps 435:
1.22 kristaps 436: (void)snprintf(title, sizeof(title), "%s (%s)",
437: roff_volname(bvol), roff_volname(vol));
438: } else
439: (void)snprintf(title, sizeof(title), "%s", roff_volname(vol));
1.21 kristaps 440:
441:
1.18 kristaps 442: i = 0;
1.4 kristaps 443:
1.19 kristaps 444: if ( ! html_typeput(mbuf, HTML_TYPE_4_01_STRICT, NULL))
1.17 kristaps 445: return(0);
1.19 kristaps 446: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_HTML))
1.17 kristaps 447: return(0);
1.19 kristaps 448: if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_HEAD))
1.17 kristaps 449: return(0);
1.19 kristaps 450:
451: attr[0].attr = HTML_ATTR_HTTP_EQUIV;
452: attr[0].val = "content-type";
453: attr[1].attr = HTML_ATTR_CONTENT;
454: attr[1].val = "text/html;charset=utf-8";
455:
456: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
1.17 kristaps 457: return(0);
1.19 kristaps 458:
459: attr[0].attr = HTML_ATTR_NAME;
460: attr[0].val = "resource-type";
461: attr[1].attr = HTML_ATTR_CONTENT;
462: attr[1].val = "document";
463:
464: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
1.17 kristaps 465: return(0);
1.19 kristaps 466:
467: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TITLE))
1.17 kristaps 468: return(0);
1.19 kristaps 469: if ( ! ml_putstring(mbuf, ts, NULL))
1.17 kristaps 470: return(0);
1.19 kristaps 471: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TITLE))
1.2 kristaps 472: return(0);
1.4 kristaps 473:
474: if (HTML_CSS_EMBED & args->params.html.flags) {
1.19 kristaps 475: attr[0].attr = HTML_ATTR_TYPE;
476: attr[0].val = "text/css";
477:
478: if ( ! html_aputln(mbuf, ML_OPEN, i,
479: HTML_TAG_STYLE, 1, attr))
1.4 kristaps 480: return(0);
1.19 kristaps 481: if ( ! html_commentput(mbuf, ML_OPEN, NULL))
1.22 kristaps 482: return(0);
1.19 kristaps 483:
1.4 kristaps 484: if ( ! html_loadcss(mbuf, args->params.html.css))
485: return(0);
1.19 kristaps 486:
487: if ( ! html_commentput(mbuf, ML_CLOSE, NULL))
1.22 kristaps 488: return(0);
1.19 kristaps 489: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_STYLE))
1.4 kristaps 490: return(0);
1.19 kristaps 491: } else {
492: attr[0].attr = HTML_ATTR_REL;
493: attr[0].val = "stylesheet";
494: attr[1].attr = HTML_ATTR_TYPE;
495: attr[1].val = "text/css";
496: attr[2].attr = HTML_ATTR_HREF;
497: attr[2].val = args->params.html.css;
498:
499: if ( ! html_aputln(mbuf, ML_OPEN, i,
500: HTML_TAG_LINK, 3, attr))
501: return(0);
502: }
1.4 kristaps 503:
1.19 kristaps 504: if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_HEAD))
1.18 kristaps 505: return(0);
1.19 kristaps 506: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_BODY))
1.18 kristaps 507: return(0);
1.19 kristaps 508:
509: attr[0].attr = HTML_ATTR_CLASS;
510: attr[0].val = "mdoc";
511:
512: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_DIV, 1, attr))
1.18 kristaps 513: return(0);
1.19 kristaps 514:
515: attr[0].attr = HTML_ATTR_WIDTH;
516: attr[0].val = "100%";
1.22 kristaps 517: attr[1].attr = HTML_ATTR_CLASS;
518: attr[1].val = "header-table";
1.19 kristaps 519:
1.22 kristaps 520: if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 2, attr))
1.18 kristaps 521: return(0);
1.19 kristaps 522: if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR))
1.18 kristaps 523: return(0);
1.19 kristaps 524:
1.22 kristaps 525: attr[0].attr = HTML_ATTR_ALIGN;
526: attr[0].val = "left";
527: attr[1].attr = HTML_ATTR_CLASS;
528: attr[1].val = "header-section";
529:
530: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
1.2 kristaps 531: return(0);
1.19 kristaps 532: if ( ! ml_putstring(mbuf, ts, NULL))
1.18 kristaps 533: return(0);
1.19 kristaps 534: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.18 kristaps 535: return(0);
1.19 kristaps 536:
1.22 kristaps 537: attr[0].attr = HTML_ATTR_ALIGN;
538: attr[0].val = "center";
539: attr[1].attr = HTML_ATTR_CLASS;
540: attr[1].val = "header-volume";
541:
542: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
543: return(0);
544: if ( ! ml_putstring(mbuf, title, NULL))
1.18 kristaps 545: return(0);
1.19 kristaps 546: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.18 kristaps 547: return(0);
1.19 kristaps 548:
1.20 kristaps 549: attr[0].attr = HTML_ATTR_ALIGN;
550: attr[0].val = "right";
1.22 kristaps 551: attr[1].attr = HTML_ATTR_CLASS;
552: attr[1].val = "header-section";
1.20 kristaps 553:
1.22 kristaps 554: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
1.18 kristaps 555: return(0);
1.19 kristaps 556: if ( ! ml_putstring(mbuf, ts, NULL))
1.17 kristaps 557: return(0);
1.19 kristaps 558: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.17 kristaps 559: return(0);
1.19 kristaps 560:
561: if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR))
1.17 kristaps 562: return(0);
1.19 kristaps 563: return(html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE));
1.2 kristaps 564: }
565:
566:
1.3 kristaps 567: /* ARGSUSED */
1.2 kristaps 568: static int
1.22 kristaps 569: html_end(struct md_mbuf *mbuf, const struct md_args *args,
570: const struct tm *tm, const char *os,
571: const char *name, enum roffmsec msec, enum roffvol vol)
1.2 kristaps 572: {
1.22 kristaps 573: struct html_pair attr[4];
574: int i;
575: char ts[64];
576:
577: if (0 == strftime(ts, sizeof(ts), "%B %d, %Y", tm)) {
578: warn("strftime");
579: return(0);
580: }
581:
582: i = 0;
583:
584: attr[0].attr = HTML_ATTR_WIDTH;
585: attr[0].val = "100%";
586: attr[1].attr = HTML_ATTR_CLASS;
587: attr[1].val = "header-footer";
588:
589: if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 2, attr))
590: return(0);
591: if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR))
592: return(0);
593:
594: attr[0].attr = HTML_ATTR_ALIGN;
595: attr[0].val = "left";
596: attr[1].attr = HTML_ATTR_CLASS;
597: attr[1].val = "footer-os";
598:
599: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
600: return(0);
601: if ( ! ml_putstring(mbuf, os, NULL))
602: return(0);
603: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
604: return(0);
605:
606: attr[0].attr = HTML_ATTR_ALIGN;
607: attr[0].val = "right";
608: attr[1].attr = HTML_ATTR_CLASS;
609: attr[1].val = "footer-date";
610:
611: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_TD, 2, attr))
612: return(0);
613: if ( ! ml_putstring(mbuf, ts, NULL))
614: return(0);
615: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
616: return(0);
617:
618: if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR))
619: return(0);
620: if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE))
621: return(0);
1.2 kristaps 622:
1.19 kristaps 623: if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_DIV))
1.18 kristaps 624: return(0);
1.19 kristaps 625: if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_BODY))
1.18 kristaps 626: return(0);
1.19 kristaps 627: return(html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_HTML));
1.2 kristaps 628: }
629:
630:
1.3 kristaps 631: /* ARGSUSED */
1.7 kristaps 632: static int
1.12 kristaps 633: html_bodytagname(struct md_mbuf *mbuf,
1.10 kristaps 634: const struct md_args *args, int tok, struct htmlq *q,
635: const int *argc, const char **argv, size_t *res)
1.2 kristaps 636: {
1.3 kristaps 637:
1.10 kristaps 638: switch (tok) {
639: case (ROFF_Bl):
640: return(html_Bl_bodytagname(mbuf, q, argc, argv, res));
1.12 kristaps 641: case (ROFF_Fo):
1.19 kristaps 642: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10 kristaps 643: case (ROFF_It):
644: return(html_It_bodytagname(mbuf, q, argc, argv, res));
1.12 kristaps 645: case (ROFF_Oo):
1.19 kristaps 646: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10 kristaps 647: default:
648: break;
649: }
650:
1.19 kristaps 651: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3 kristaps 652: }
653:
654:
655: /* ARGSUSED */
1.7 kristaps 656: static int
1.10 kristaps 657: html_headtagname(struct md_mbuf *mbuf,
658: const struct md_args *args, int tok, struct htmlq *q,
659: const int *argc, const char **argv, size_t *res)
1.3 kristaps 660: {
661:
1.10 kristaps 662: switch (tok) {
663: case (ROFF_It):
664: return(html_It_headtagname(mbuf, q, argc, argv, res));
1.12 kristaps 665: case (ROFF_Fo):
1.19 kristaps 666: /* FALLTHROUGH */
1.12 kristaps 667: case (ROFF_Oo):
1.19 kristaps 668: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10 kristaps 669: case (ROFF_Sh):
1.19 kristaps 670: return(html_stput(mbuf, HTML_TAG_H1, res));
1.10 kristaps 671: case (ROFF_Ss):
1.19 kristaps 672: return(html_stput(mbuf, HTML_TAG_H2, res));
1.10 kristaps 673: default:
674: break;
675: }
676:
1.19 kristaps 677: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3 kristaps 678: }
679:
680:
681: /* ARGSUSED */
1.7 kristaps 682: static int
1.10 kristaps 683: html_blocktagname(struct md_mbuf *mbuf, const struct md_args *args,
684: int tok, struct htmlq *q, const int *argc,
685: const char **argv, size_t *res)
1.3 kristaps 686: {
687:
1.10 kristaps 688: switch (tok) {
1.12 kristaps 689: case (ROFF_Fo):
1.19 kristaps 690: /* FALLTHROUGH */
1.12 kristaps 691: case (ROFF_Oo):
1.19 kristaps 692: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10 kristaps 693: case (ROFF_It):
694: return(html_It_blocktagname(mbuf, q, argc, argv, res));
695: default:
696: break;
697: }
698:
1.19 kristaps 699: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3 kristaps 700: }
701:
702:
1.9 kristaps 703: /* ARGSUSED */
1.7 kristaps 704: static int
705: html_printargs(struct md_mbuf *mbuf, int tok, const char *ns,
706: const int *argc, const char **argv, size_t *res)
1.3 kristaps 707: {
708:
1.19 kristaps 709: /* FIXME: use API in ml.h. */
710:
1.7 kristaps 711: if ( ! ml_puts(mbuf, " class=\"", res))
712: return(0);
713: if ( ! ml_puts(mbuf, ns, res))
714: return(0);
715: if ( ! ml_puts(mbuf, "-", res))
1.3 kristaps 716: return(0);
1.7 kristaps 717: if ( ! ml_puts(mbuf, toknames[tok], res))
1.3 kristaps 718: return(0);
1.9 kristaps 719: return(ml_puts(mbuf, "\"", res));
1.3 kristaps 720: }
721:
722:
723: /* ARGSUSED */
1.7 kristaps 724: static int
1.10 kristaps 725: html_headtagargs(struct md_mbuf *mbuf,
1.7 kristaps 726: const struct md_args *args, int tok,
727: const int *argc, const char **argv, size_t *res)
1.3 kristaps 728: {
729:
1.7 kristaps 730: return(html_printargs(mbuf, tok, "head", argc, argv, res));
731: }
1.3 kristaps 732:
733:
1.7 kristaps 734: /* ARGSUSED */
735: static int
1.12 kristaps 736: html_bodytagargs(struct md_mbuf *mbuf,
1.7 kristaps 737: const struct md_args *args, int tok,
738: const int *argc, const char **argv, size_t *res)
739: {
1.3 kristaps 740:
1.7 kristaps 741: return(html_printargs(mbuf, tok, "body", argc, argv, res));
1.2 kristaps 742: }
743:
744:
745: /* ARGSUSED */
1.7 kristaps 746: static int
747: html_blocktagargs(struct md_mbuf *mbuf,
748: const struct md_args *args, int tok,
749: const int *argc, const char **argv, size_t *res)
1.2 kristaps 750: {
1.3 kristaps 751:
1.7 kristaps 752: return(html_printargs(mbuf, tok, "block", argc, argv, res));
1.2 kristaps 753: }
1.1 kristaps 754:
755:
756: /* ARGSUSED */
1.7 kristaps 757: static int
758: html_inlinetagargs(struct md_mbuf *mbuf,
759: const struct md_args *args, int tok,
760: const int *argc, const char **argv, size_t *res)
1.2 kristaps 761: {
762:
1.12 kristaps 763: if ( ! html_printargs(mbuf, tok, "inline", argc, argv, res))
764: return(0);
765:
766: switch (tok) {
1.24 ! kristaps 767: case (ROFF_Sh):
! 768:
! 769: /* FIXME: use API in ml.h. */
! 770:
! 771: assert(*argv);
! 772: if ( ! ml_nputs(mbuf, " name=\"", 7, res))
! 773: return(0);
! 774: if ( ! ml_putstring(mbuf, *argv++, res))
! 775: return(0);
! 776: while (*argv) {
! 777: if ( ! ml_putstring(mbuf, "_", res))
! 778: return(0);
! 779: if ( ! ml_putstring(mbuf, *argv++, res))
! 780: return(0);
! 781: }
! 782: if ( ! ml_nputs(mbuf, "\"", 1, res))
! 783: return(0);
! 784: break;
! 785:
1.12 kristaps 786: case (ROFF_Sx):
1.19 kristaps 787:
788: /* FIXME: use API in ml.h. */
789:
1.12 kristaps 790: assert(*argv);
791: if ( ! ml_nputs(mbuf, " href=\"#", 8, res))
792: return(0);
1.24 ! kristaps 793: if ( ! ml_putstring(mbuf, *argv++, res))
1.12 kristaps 794: return(0);
1.24 ! kristaps 795: while (*argv) {
! 796: if ( ! ml_putstring(mbuf, "_", res))
! 797: return(0);
! 798: if ( ! ml_putstring(mbuf, *argv++, res))
! 799: return(0);
! 800: }
1.12 kristaps 801: if ( ! ml_nputs(mbuf, "\"", 1, res))
802: return(0);
1.24 ! kristaps 803:
1.13 kristaps 804: break;
1.12 kristaps 805: default:
806: break;
807: }
808:
809: return(1);
1.2 kristaps 810: }
811:
812:
1.3 kristaps 813: /* ARGSUSED */
1.7 kristaps 814: static int
1.2 kristaps 815: html_inlinetagname(struct md_mbuf *mbuf,
1.7 kristaps 816: const struct md_args *args, int tok, size_t *res)
1.2 kristaps 817: {
818:
819: switch (tok) {
1.24 ! kristaps 820: case (ROFF_Sh):
! 821: return(html_stput(mbuf, HTML_TAG_A, res));
1.4 kristaps 822: case (ROFF_Pp):
1.19 kristaps 823: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.12 kristaps 824: case (ROFF_Sx):
1.19 kristaps 825: return(html_stput(mbuf, HTML_TAG_A, res));
1.2 kristaps 826: default:
1.9 kristaps 827: break;
1.2 kristaps 828: }
1.9 kristaps 829:
1.19 kristaps 830: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.2 kristaps 831: }
832:
833:
834: static ssize_t
1.8 kristaps 835: html_begintag(struct md_mbuf *mbuf, void *data,
836: const struct md_args *args, enum md_ns ns,
837: int tok, const int *argc, const char **argv)
1.2 kristaps 838: {
1.7 kristaps 839: size_t res;
1.8 kristaps 840: struct htmlq *q;
841: struct htmlnode *node;
1.11 kristaps 842: int i;
1.2 kristaps 843:
844: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 845: res = 0;
846:
1.8 kristaps 847: assert(data);
848: q = (struct htmlq *)data;
849:
850: if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) {
851: warn("calloc");
852: return(-1);
853: }
854:
855: node->parent = q->last;
856: node->tok = tok;
857: node->ns = ns;
858:
1.10 kristaps 859: if (argc) {
860: /* TODO: argv. */
861:
862: assert(argv);
1.13 kristaps 863: /* LINTED */
1.11 kristaps 864: for (i = 0; ROFF_ARGMAX != argc[i]
1.10 kristaps 865: && i < ROFF_MAXLINEARG; i++)
866: node->argc[i] = argc[i];
867: assert(i != ROFF_MAXLINEARG);
1.12 kristaps 868: }
1.10 kristaps 869:
870:
1.8 kristaps 871: q->last = node;
872:
1.3 kristaps 873: switch (ns) {
874: case (MD_NS_BLOCK):
1.10 kristaps 875: if ( ! html_blocktagname(mbuf, args, tok,
876: q, argc, argv, &res))
1.7 kristaps 877: return(-1);
878: if ( ! html_blocktagargs(mbuf, args, tok,
879: argc, argv, &res))
880: return(-1);
881: break;
1.3 kristaps 882: case (MD_NS_BODY):
1.12 kristaps 883: if ( ! html_bodytagname(mbuf, args, tok,
1.10 kristaps 884: q, argc, argv, &res))
1.7 kristaps 885: return(-1);
1.12 kristaps 886: if ( ! html_bodytagargs(mbuf, args, tok,
1.7 kristaps 887: argc, argv, &res))
888: return(-1);
889: break;
1.3 kristaps 890: case (MD_NS_HEAD):
1.10 kristaps 891: if ( ! html_headtagname(mbuf, args, tok, q,
892: argc, argv, &res))
1.7 kristaps 893: return(-1);
1.10 kristaps 894: if ( ! html_headtagargs(mbuf, args, tok,
1.7 kristaps 895: argc, argv, &res))
896: return(-1);
897: break;
1.3 kristaps 898: default:
1.7 kristaps 899: if ( ! html_inlinetagname(mbuf, args, tok, &res))
900: return(-1);
901: if ( ! html_inlinetagargs(mbuf, args, tok,
902: argc, argv, &res))
903: return(-1);
1.3 kristaps 904: break;
1.2 kristaps 905: }
906:
1.7 kristaps 907: return((ssize_t)res);
1.2 kristaps 908: }
909:
910:
911: static ssize_t
1.8 kristaps 912: html_endtag(struct md_mbuf *mbuf, void *data,
913: const struct md_args *args, enum md_ns ns, int tok)
1.2 kristaps 914: {
1.7 kristaps 915: size_t res;
1.8 kristaps 916: struct htmlq *q;
917: struct htmlnode *node;
1.2 kristaps 918:
919: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 920: res = 0;
921:
1.8 kristaps 922: assert(data);
923: q = (struct htmlq *)data;
1.10 kristaps 924: node = q->last;
1.8 kristaps 925:
1.3 kristaps 926: switch (ns) {
927: case (MD_NS_BLOCK):
1.10 kristaps 928: if ( ! html_blocktagname(mbuf, args, tok,
929: q, node->argc,
930: (const char **)node->argv, &res))
1.7 kristaps 931: return(-1);
932: break;
1.3 kristaps 933: case (MD_NS_BODY):
1.12 kristaps 934: if ( ! html_bodytagname(mbuf, args, tok,
1.10 kristaps 935: q, node->argc,
936: (const char **)node->argv, &res))
1.7 kristaps 937: return(-1);
938: break;
1.3 kristaps 939: case (MD_NS_HEAD):
1.10 kristaps 940: if ( ! html_headtagname(mbuf, args, tok,
941: q, node->argc,
942: (const char **)node->argv, &res))
1.7 kristaps 943: return(-1);
944: break;
1.3 kristaps 945: default:
1.7 kristaps 946: if ( ! html_inlinetagname(mbuf, args, tok, &res))
947: return(-1);
1.3 kristaps 948: break;
949: }
1.2 kristaps 950:
1.8 kristaps 951: q->last = node->parent;
952:
1.9 kristaps 953: free(node);
1.8 kristaps 954:
1.7 kristaps 955: return((ssize_t)res);
1.2 kristaps 956: }
957:
958:
1.9 kristaps 959: static int
960: html_alloc(void **p)
961: {
962:
963: if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) {
964: warn("calloc");
965: return(0);
966: }
967: return(1);
968: }
969:
970:
971: static void
972: html_free(void *p)
973: {
974: struct htmlq *q;
975: struct htmlnode *n;
976:
977: assert(p);
978: q = (struct htmlq *)p;
979:
1.13 kristaps 980: /* LINTED */
1.9 kristaps 981: while ((n = q->last)) {
982: q->last = n->parent;
983: free(n);
984: }
985:
986: free(q);
987: }
988:
989:
1.23 kristaps 990: /* ARGSUSED */
1.14 kristaps 991: static ssize_t
992: html_beginhttp(struct md_mbuf *mbuf,
993: const struct md_args *args,
994: const char *buf, size_t sz)
995: {
996: size_t res;
1.19 kristaps 997: struct html_pair pair;
1.14 kristaps 998:
999: res = 0;
1.19 kristaps 1000: pair.attr = HTML_ATTR_HREF;
1001: pair.val = (char *)buf;
1.14 kristaps 1002:
1.19 kristaps 1003: if ( ! html_aput(mbuf, ML_OPEN, HTML_TAG_A, &res, 1, &pair))
1.14 kristaps 1004: return(-1);
1005: return((ssize_t)res);
1006: }
1007:
1008:
1.23 kristaps 1009: /* ARGSUSED */
1.14 kristaps 1010: static ssize_t
1011: html_endhttp(struct md_mbuf *mbuf,
1012: const struct md_args *args,
1013: const char *buf, size_t sz)
1014: {
1015: size_t res;
1016:
1017: res = 0;
1.19 kristaps 1018: if ( ! html_tput(mbuf, ML_CLOSE, HTML_TAG_A, &res))
1.14 kristaps 1019: return(-1);
1020: return((ssize_t)res);
1021: }
1022:
1023:
1024: /* ARGSUSED */
1025: static ssize_t
1026: html_beginstring(struct md_mbuf *mbuf,
1027: const struct md_args *args,
1028: const char *buf, size_t sz)
1029: {
1030:
1031: if (0 == strncmp(buf, "http://", 7))
1032: return(html_beginhttp(mbuf, args, buf, sz));
1033:
1034: return(0);
1035: }
1036:
1037:
1038: /* ARGSUSED */
1039: static ssize_t
1040: html_endstring(struct md_mbuf *mbuf,
1041: const struct md_args *args,
1042: const char *buf, size_t sz)
1043: {
1044:
1045: if (0 == strncmp(buf, "http://", 7))
1046: return(html_endhttp(mbuf, args, buf, sz));
1047:
1048: return(0);
1049: }
1050:
1051:
1.1 kristaps 1052: int
1053: md_line_html(void *data, char *buf)
1054: {
1055:
1.2 kristaps 1056: return(mlg_line((struct md_mlg *)data, buf));
1.1 kristaps 1057: }
1058:
1059:
1060: int
1061: md_exit_html(void *data, int flush)
1062: {
1063:
1.2 kristaps 1064: return(mlg_exit((struct md_mlg *)data, flush));
1.1 kristaps 1065: }
1066:
1067:
1068: void *
1069: md_init_html(const struct md_args *args,
1070: struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
1071: {
1.9 kristaps 1072: struct ml_cbs cbs;
1.8 kristaps 1073:
1.9 kristaps 1074: cbs.ml_alloc = html_alloc;
1075: cbs.ml_free = html_free;
1076: cbs.ml_begintag = html_begintag;
1077: cbs.ml_endtag = html_endtag;
1078: cbs.ml_begin = html_begin;
1079: cbs.ml_end = html_end;
1.14 kristaps 1080: cbs.ml_beginstring = html_beginstring;
1081: cbs.ml_endstring = html_endstring;
1.1 kristaps 1082:
1.9 kristaps 1083: return(mlg_alloc(args, rbuf, mbuf, &cbs));
1.1 kristaps 1084: }
CVSweb