Annotation of mandoc/html.c, Revision 1.27
1.27 ! kristaps 1: /* $Id: html.c,v 1.26 2008/12/10 17:40:56 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.27 ! kristaps 825: case (ROFF_Dl):
! 826: /* FALLTHROUGH */
! 827: case (ROFF_D1):
! 828: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.24 kristaps 829: case (ROFF_Sh):
830: return(html_stput(mbuf, HTML_TAG_A, res));
1.4 kristaps 831: case (ROFF_Pp):
1.19 kristaps 832: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.12 kristaps 833: case (ROFF_Sx):
1.19 kristaps 834: return(html_stput(mbuf, HTML_TAG_A, res));
1.2 kristaps 835: default:
1.9 kristaps 836: break;
1.2 kristaps 837: }
1.9 kristaps 838:
1.19 kristaps 839: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.2 kristaps 840: }
841:
842:
843: static ssize_t
1.25 kristaps 844: html_begintag(struct ml_args *p, enum md_ns ns,
1.8 kristaps 845: int tok, const int *argc, const char **argv)
1.2 kristaps 846: {
1.7 kristaps 847: size_t res;
1.8 kristaps 848: struct htmlq *q;
849: struct htmlnode *node;
1.11 kristaps 850: int i;
1.2 kristaps 851:
852: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 853: res = 0;
854:
1.25 kristaps 855: q = (struct htmlq *)p->data;
1.8 kristaps 856:
857: if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) {
858: warn("calloc");
859: return(-1);
860: }
861:
862: node->parent = q->last;
863: node->tok = tok;
864: node->ns = ns;
865:
1.10 kristaps 866: if (argc) {
867: /* TODO: argv. */
868:
869: assert(argv);
1.13 kristaps 870: /* LINTED */
1.11 kristaps 871: for (i = 0; ROFF_ARGMAX != argc[i]
1.10 kristaps 872: && i < ROFF_MAXLINEARG; i++)
873: node->argc[i] = argc[i];
874: assert(i != ROFF_MAXLINEARG);
1.12 kristaps 875: }
1.10 kristaps 876:
877:
1.8 kristaps 878: q->last = node;
879:
1.3 kristaps 880: switch (ns) {
881: case (MD_NS_BLOCK):
1.25 kristaps 882: if ( ! html_blocktagname(p->mbuf, p->args, tok,
1.10 kristaps 883: q, argc, argv, &res))
1.7 kristaps 884: return(-1);
1.25 kristaps 885: if ( ! html_blocktagargs(p->mbuf, p->args, tok,
1.7 kristaps 886: argc, argv, &res))
887: return(-1);
888: break;
1.3 kristaps 889: case (MD_NS_BODY):
1.25 kristaps 890: if ( ! html_bodytagname(p->mbuf, p->args, tok,
1.10 kristaps 891: q, argc, argv, &res))
1.7 kristaps 892: return(-1);
1.25 kristaps 893: if ( ! html_bodytagargs(p->mbuf, p->args, tok,
1.7 kristaps 894: argc, argv, &res))
895: return(-1);
896: break;
1.3 kristaps 897: case (MD_NS_HEAD):
1.25 kristaps 898: if ( ! html_headtagname(p->mbuf, p->args, tok, q,
1.10 kristaps 899: argc, argv, &res))
1.7 kristaps 900: return(-1);
1.25 kristaps 901: if ( ! html_headtagargs(p->mbuf, p->args, tok,
1.7 kristaps 902: argc, argv, &res))
903: return(-1);
904: break;
1.3 kristaps 905: default:
1.25 kristaps 906: if ( ! html_inlinetagname(p->mbuf, p->args, tok, &res))
1.7 kristaps 907: return(-1);
1.25 kristaps 908: if ( ! html_inlinetagargs(p->mbuf, p->args, tok,
1.7 kristaps 909: argc, argv, &res))
910: return(-1);
1.3 kristaps 911: break;
1.2 kristaps 912: }
913:
1.7 kristaps 914: return((ssize_t)res);
1.2 kristaps 915: }
916:
917:
918: static ssize_t
1.25 kristaps 919: html_endtag(struct ml_args *p, enum md_ns ns, int tok)
1.2 kristaps 920: {
1.7 kristaps 921: size_t res;
1.8 kristaps 922: struct htmlq *q;
923: struct htmlnode *node;
1.2 kristaps 924:
925: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 926: res = 0;
927:
1.25 kristaps 928: q = (struct htmlq *)p->data;
1.10 kristaps 929: node = q->last;
1.8 kristaps 930:
1.3 kristaps 931: switch (ns) {
932: case (MD_NS_BLOCK):
1.25 kristaps 933: if ( ! html_blocktagname(p->mbuf, p->args, tok,
1.10 kristaps 934: q, node->argc,
935: (const char **)node->argv, &res))
1.7 kristaps 936: return(-1);
937: break;
1.3 kristaps 938: case (MD_NS_BODY):
1.25 kristaps 939: if ( ! html_bodytagname(p->mbuf, p->args, tok,
1.10 kristaps 940: q, node->argc,
941: (const char **)node->argv, &res))
1.7 kristaps 942: return(-1);
943: break;
1.3 kristaps 944: case (MD_NS_HEAD):
1.25 kristaps 945: if ( ! html_headtagname(p->mbuf, p->args, tok,
1.10 kristaps 946: q, node->argc,
947: (const char **)node->argv, &res))
1.7 kristaps 948: return(-1);
949: break;
1.3 kristaps 950: default:
1.25 kristaps 951: if ( ! html_inlinetagname(p->mbuf, p->args, tok, &res))
1.7 kristaps 952: return(-1);
1.3 kristaps 953: break;
954: }
1.2 kristaps 955:
1.8 kristaps 956: q->last = node->parent;
957:
1.9 kristaps 958: free(node);
1.8 kristaps 959:
1.7 kristaps 960: return((ssize_t)res);
1.2 kristaps 961: }
962:
963:
1.9 kristaps 964: static int
965: html_alloc(void **p)
966: {
967:
968: if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) {
969: warn("calloc");
970: return(0);
971: }
972: return(1);
973: }
974:
975:
976: static void
977: html_free(void *p)
978: {
979: struct htmlq *q;
980: struct htmlnode *n;
981:
982: assert(p);
983: q = (struct htmlq *)p;
984:
1.13 kristaps 985: /* LINTED */
1.9 kristaps 986: while ((n = q->last)) {
987: q->last = n->parent;
988: free(n);
989: }
990:
991: free(q);
992: }
993:
994:
1.23 kristaps 995: /* ARGSUSED */
1.14 kristaps 996: static ssize_t
997: html_beginhttp(struct md_mbuf *mbuf,
998: const struct md_args *args,
999: const char *buf, size_t sz)
1000: {
1001: size_t res;
1.19 kristaps 1002: struct html_pair pair;
1.14 kristaps 1003:
1004: res = 0;
1.19 kristaps 1005: pair.attr = HTML_ATTR_HREF;
1006: pair.val = (char *)buf;
1.14 kristaps 1007:
1.19 kristaps 1008: if ( ! html_aput(mbuf, ML_OPEN, HTML_TAG_A, &res, 1, &pair))
1.14 kristaps 1009: return(-1);
1010: return((ssize_t)res);
1011: }
1012:
1013:
1.23 kristaps 1014: /* ARGSUSED */
1.14 kristaps 1015: static ssize_t
1016: html_endhttp(struct md_mbuf *mbuf,
1017: const struct md_args *args,
1018: const char *buf, size_t sz)
1019: {
1020: size_t res;
1021:
1022: res = 0;
1.19 kristaps 1023: if ( ! html_tput(mbuf, ML_CLOSE, HTML_TAG_A, &res))
1.14 kristaps 1024: return(-1);
1025: return((ssize_t)res);
1026: }
1027:
1028:
1029: /* ARGSUSED */
1030: static ssize_t
1.25 kristaps 1031: html_beginstring(struct ml_args *p, const char *buf, size_t sz)
1.14 kristaps 1032: {
1033:
1034: if (0 == strncmp(buf, "http://", 7))
1.25 kristaps 1035: return(html_beginhttp(p->mbuf, p->args, buf, sz));
1.14 kristaps 1036:
1037: return(0);
1038: }
1039:
1040:
1041: /* ARGSUSED */
1042: static ssize_t
1.25 kristaps 1043: html_endstring(struct ml_args *p, const char *buf, size_t sz)
1.14 kristaps 1044: {
1045:
1046: if (0 == strncmp(buf, "http://", 7))
1.25 kristaps 1047: return(html_endhttp(p->mbuf, p->args, buf, sz));
1.14 kristaps 1048:
1049: return(0);
1050: }
1051:
1052:
1.1 kristaps 1053: int
1054: md_line_html(void *data, char *buf)
1055: {
1056:
1.2 kristaps 1057: return(mlg_line((struct md_mlg *)data, buf));
1.1 kristaps 1058: }
1059:
1060:
1061: int
1062: md_exit_html(void *data, int flush)
1063: {
1064:
1.2 kristaps 1065: return(mlg_exit((struct md_mlg *)data, flush));
1.1 kristaps 1066: }
1067:
1068:
1069: void *
1070: md_init_html(const struct md_args *args,
1071: struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
1072: {
1.9 kristaps 1073: struct ml_cbs cbs;
1.8 kristaps 1074:
1.9 kristaps 1075: cbs.ml_alloc = html_alloc;
1076: cbs.ml_free = html_free;
1077: cbs.ml_begintag = html_begintag;
1078: cbs.ml_endtag = html_endtag;
1079: cbs.ml_begin = html_begin;
1080: cbs.ml_end = html_end;
1.14 kristaps 1081: cbs.ml_beginstring = html_beginstring;
1082: cbs.ml_endstring = html_endstring;
1.1 kristaps 1083:
1.9 kristaps 1084: return(mlg_alloc(args, rbuf, mbuf, &cbs));
1.1 kristaps 1085: }
CVSweb