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