Annotation of mandoc/html.c, Revision 1.23
1.23 ! kristaps 1: /* $Id: html.c,v 1.22 2008/12/10 12:05:33 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) {
767: case (ROFF_Sx):
1.19 kristaps 768:
769: /* FIXME: use API in ml.h. */
770:
1.12 kristaps 771: assert(*argv);
772: if ( ! ml_nputs(mbuf, " href=\"#", 8, res))
773: return(0);
774: if ( ! ml_putstring(mbuf, *argv, res))
775: return(0);
776: if ( ! ml_nputs(mbuf, "\"", 1, res))
777: return(0);
1.13 kristaps 778: break;
1.12 kristaps 779: default:
780: break;
781: }
782:
783: return(1);
1.2 kristaps 784: }
785:
786:
1.3 kristaps 787: /* ARGSUSED */
1.7 kristaps 788: static int
1.2 kristaps 789: html_inlinetagname(struct md_mbuf *mbuf,
1.7 kristaps 790: const struct md_args *args, int tok, size_t *res)
1.2 kristaps 791: {
792:
793: switch (tok) {
1.4 kristaps 794: case (ROFF_Pp):
1.19 kristaps 795: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.12 kristaps 796: case (ROFF_Sx):
1.19 kristaps 797: return(html_stput(mbuf, HTML_TAG_A, res));
1.2 kristaps 798: default:
1.9 kristaps 799: break;
1.2 kristaps 800: }
1.9 kristaps 801:
1.19 kristaps 802: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.2 kristaps 803: }
804:
805:
806: static ssize_t
1.8 kristaps 807: html_begintag(struct md_mbuf *mbuf, void *data,
808: const struct md_args *args, enum md_ns ns,
809: int tok, const int *argc, const char **argv)
1.2 kristaps 810: {
1.7 kristaps 811: size_t res;
1.8 kristaps 812: struct htmlq *q;
813: struct htmlnode *node;
1.11 kristaps 814: int i;
1.2 kristaps 815:
816: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 817: res = 0;
818:
1.8 kristaps 819: assert(data);
820: q = (struct htmlq *)data;
821:
822: if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) {
823: warn("calloc");
824: return(-1);
825: }
826:
827: node->parent = q->last;
828: node->tok = tok;
829: node->ns = ns;
830:
1.10 kristaps 831: if (argc) {
832: /* TODO: argv. */
833:
834: assert(argv);
1.13 kristaps 835: /* LINTED */
1.11 kristaps 836: for (i = 0; ROFF_ARGMAX != argc[i]
1.10 kristaps 837: && i < ROFF_MAXLINEARG; i++)
838: node->argc[i] = argc[i];
839: assert(i != ROFF_MAXLINEARG);
1.12 kristaps 840: }
1.10 kristaps 841:
842:
1.8 kristaps 843: q->last = node;
844:
1.3 kristaps 845: switch (ns) {
846: case (MD_NS_BLOCK):
1.10 kristaps 847: if ( ! html_blocktagname(mbuf, args, tok,
848: q, argc, argv, &res))
1.7 kristaps 849: return(-1);
850: if ( ! html_blocktagargs(mbuf, args, tok,
851: argc, argv, &res))
852: return(-1);
853: break;
1.3 kristaps 854: case (MD_NS_BODY):
1.12 kristaps 855: if ( ! html_bodytagname(mbuf, args, tok,
1.10 kristaps 856: q, argc, argv, &res))
1.7 kristaps 857: return(-1);
1.12 kristaps 858: if ( ! html_bodytagargs(mbuf, args, tok,
1.7 kristaps 859: argc, argv, &res))
860: return(-1);
861: break;
1.3 kristaps 862: case (MD_NS_HEAD):
1.10 kristaps 863: if ( ! html_headtagname(mbuf, args, tok, q,
864: argc, argv, &res))
1.7 kristaps 865: return(-1);
1.10 kristaps 866: if ( ! html_headtagargs(mbuf, args, tok,
1.7 kristaps 867: argc, argv, &res))
868: return(-1);
869: break;
1.3 kristaps 870: default:
1.7 kristaps 871: if ( ! html_inlinetagname(mbuf, args, tok, &res))
872: return(-1);
873: if ( ! html_inlinetagargs(mbuf, args, tok,
874: argc, argv, &res))
875: return(-1);
1.3 kristaps 876: break;
1.2 kristaps 877: }
878:
1.7 kristaps 879: return((ssize_t)res);
1.2 kristaps 880: }
881:
882:
883: static ssize_t
1.8 kristaps 884: html_endtag(struct md_mbuf *mbuf, void *data,
885: const struct md_args *args, enum md_ns ns, int tok)
1.2 kristaps 886: {
1.7 kristaps 887: size_t res;
1.8 kristaps 888: struct htmlq *q;
889: struct htmlnode *node;
1.2 kristaps 890:
891: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 892: res = 0;
893:
1.8 kristaps 894: assert(data);
895: q = (struct htmlq *)data;
1.10 kristaps 896: node = q->last;
1.8 kristaps 897:
1.3 kristaps 898: switch (ns) {
899: case (MD_NS_BLOCK):
1.10 kristaps 900: if ( ! html_blocktagname(mbuf, args, tok,
901: q, node->argc,
902: (const char **)node->argv, &res))
1.7 kristaps 903: return(-1);
904: break;
1.3 kristaps 905: case (MD_NS_BODY):
1.12 kristaps 906: if ( ! html_bodytagname(mbuf, args, tok,
1.10 kristaps 907: q, node->argc,
908: (const char **)node->argv, &res))
1.7 kristaps 909: return(-1);
910: break;
1.3 kristaps 911: case (MD_NS_HEAD):
1.10 kristaps 912: if ( ! html_headtagname(mbuf, args, tok,
913: q, node->argc,
914: (const char **)node->argv, &res))
1.7 kristaps 915: return(-1);
916: break;
1.3 kristaps 917: default:
1.7 kristaps 918: if ( ! html_inlinetagname(mbuf, args, tok, &res))
919: return(-1);
1.3 kristaps 920: break;
921: }
1.2 kristaps 922:
1.8 kristaps 923: q->last = node->parent;
924:
1.9 kristaps 925: free(node);
1.8 kristaps 926:
1.7 kristaps 927: return((ssize_t)res);
1.2 kristaps 928: }
929:
930:
1.9 kristaps 931: static int
932: html_alloc(void **p)
933: {
934:
935: if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) {
936: warn("calloc");
937: return(0);
938: }
939: return(1);
940: }
941:
942:
943: static void
944: html_free(void *p)
945: {
946: struct htmlq *q;
947: struct htmlnode *n;
948:
949: assert(p);
950: q = (struct htmlq *)p;
951:
1.13 kristaps 952: /* LINTED */
1.9 kristaps 953: while ((n = q->last)) {
954: q->last = n->parent;
955: free(n);
956: }
957:
958: free(q);
959: }
960:
961:
1.23 ! kristaps 962: /* ARGSUSED */
1.14 kristaps 963: static ssize_t
964: html_beginhttp(struct md_mbuf *mbuf,
965: const struct md_args *args,
966: const char *buf, size_t sz)
967: {
968: size_t res;
1.19 kristaps 969: struct html_pair pair;
1.14 kristaps 970:
971: res = 0;
1.19 kristaps 972: pair.attr = HTML_ATTR_HREF;
973: pair.val = (char *)buf;
1.14 kristaps 974:
1.19 kristaps 975: if ( ! html_aput(mbuf, ML_OPEN, HTML_TAG_A, &res, 1, &pair))
1.14 kristaps 976: return(-1);
977: return((ssize_t)res);
978: }
979:
980:
1.23 ! kristaps 981: /* ARGSUSED */
1.14 kristaps 982: static ssize_t
983: html_endhttp(struct md_mbuf *mbuf,
984: const struct md_args *args,
985: const char *buf, size_t sz)
986: {
987: size_t res;
988:
989: res = 0;
1.19 kristaps 990: if ( ! html_tput(mbuf, ML_CLOSE, HTML_TAG_A, &res))
1.14 kristaps 991: return(-1);
992: return((ssize_t)res);
993: }
994:
995:
996: /* ARGSUSED */
997: static ssize_t
998: html_beginstring(struct md_mbuf *mbuf,
999: const struct md_args *args,
1000: const char *buf, size_t sz)
1001: {
1002:
1003: if (0 == strncmp(buf, "http://", 7))
1004: return(html_beginhttp(mbuf, args, buf, sz));
1005:
1006: return(0);
1007: }
1008:
1009:
1010: /* ARGSUSED */
1011: static ssize_t
1012: html_endstring(struct md_mbuf *mbuf,
1013: const struct md_args *args,
1014: const char *buf, size_t sz)
1015: {
1016:
1017: if (0 == strncmp(buf, "http://", 7))
1018: return(html_endhttp(mbuf, args, buf, sz));
1019:
1020: return(0);
1021: }
1022:
1023:
1.1 kristaps 1024: int
1025: md_line_html(void *data, char *buf)
1026: {
1027:
1.2 kristaps 1028: return(mlg_line((struct md_mlg *)data, buf));
1.1 kristaps 1029: }
1030:
1031:
1032: int
1033: md_exit_html(void *data, int flush)
1034: {
1035:
1.2 kristaps 1036: return(mlg_exit((struct md_mlg *)data, flush));
1.1 kristaps 1037: }
1038:
1039:
1040: void *
1041: md_init_html(const struct md_args *args,
1042: struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
1043: {
1.9 kristaps 1044: struct ml_cbs cbs;
1.8 kristaps 1045:
1.9 kristaps 1046: cbs.ml_alloc = html_alloc;
1047: cbs.ml_free = html_free;
1048: cbs.ml_begintag = html_begintag;
1049: cbs.ml_endtag = html_endtag;
1050: cbs.ml_begin = html_begin;
1051: cbs.ml_end = html_end;
1.14 kristaps 1052: cbs.ml_beginstring = html_beginstring;
1053: cbs.ml_endstring = html_endstring;
1.1 kristaps 1054:
1.9 kristaps 1055: return(mlg_alloc(args, rbuf, mbuf, &cbs));
1.1 kristaps 1056: }
CVSweb