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