Annotation of mandoc/html.c, Revision 1.19
1.19 ! kristaps 1: /* $Id: html.c,v 1.18 2008/12/09 19:57:26 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008 Kristaps Dzonsons <kristaps@kth.se>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the
7: * above copyright notice and this permission notice appear in all
8: * copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11: * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12: * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13: * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16: * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
1.4 kristaps 19: #include <sys/param.h>
20: #include <sys/stat.h>
21:
1.1 kristaps 22: #include <assert.h>
1.4 kristaps 23: #include <err.h>
24: #include <fcntl.h>
1.1 kristaps 25: #include <stdlib.h>
1.4 kristaps 26: #include <stdio.h>
1.2 kristaps 27: #include <string.h>
1.4 kristaps 28: #include <unistd.h>
1.1 kristaps 29:
1.19 ! kristaps 30: #include "html.h"
1.2 kristaps 31: #include "ml.h"
32:
1.8 kristaps 33: /* TODO: allow head/tail-less invocations (just "div" start). */
34:
1.7 kristaps 35: struct htmlnode {
1.8 kristaps 36: int tok;
37: enum md_ns ns;
1.10 kristaps 38: int argc[ROFF_MAXLINEARG];
1.7 kristaps 39: char *argv[ROFF_MAXLINEARG];
40: struct htmlnode *parent;
41: };
42:
43: struct htmlq {
44: struct htmlnode *last;
45: };
46:
47:
1.19 ! kristaps 48: static int html_loadcss(struct md_mbuf *,
! 49: const char *);
1.9 kristaps 50: static int html_alloc(void **);
51: static void html_free(void *);
1.8 kristaps 52: static ssize_t html_endtag(struct md_mbuf *, void *,
1.2 kristaps 53: const struct md_args *,
54: enum md_ns, int);
1.14 kristaps 55: static ssize_t html_beginstring(struct md_mbuf *,
56: const struct md_args *,
57: const char *, size_t);
58: static ssize_t html_beginhttp(struct md_mbuf *,
59: const struct md_args *,
60: const char *, size_t);
61: static ssize_t html_endstring(struct md_mbuf *,
62: const struct md_args *,
63: const char *, size_t);
64: static ssize_t html_endhttp(struct md_mbuf *,
65: const struct md_args *,
66: const char *, size_t);
1.8 kristaps 67: static ssize_t html_begintag(struct md_mbuf *, void *,
1.2 kristaps 68: const struct md_args *,
69: enum md_ns, int,
70: const int *, const char **);
1.4 kristaps 71: static int html_begin(struct md_mbuf *,
72: const struct md_args *,
73: const struct tm *,
74: const char *, const char *,
1.15 kristaps 75: enum roffmsec, const char *);
1.7 kristaps 76: static int html_printargs(struct md_mbuf *, int,
77: const char *, const int *,
78: const char **, size_t *);
1.2 kristaps 79: static int html_end(struct md_mbuf *,
80: const struct md_args *);
1.7 kristaps 81: static int html_blocktagname(struct md_mbuf *,
1.10 kristaps 82: const struct md_args *, int,
83: struct htmlq *, const int *,
84: const char **, size_t *);
1.7 kristaps 85: static int html_blocktagargs(struct md_mbuf *,
1.2 kristaps 86: const struct md_args *, int,
1.7 kristaps 87: const int *, const char **, size_t *);
1.10 kristaps 88: static int html_headtagname(struct md_mbuf *,
89: const struct md_args *, int,
90: struct htmlq *, const int *,
91: const char **, size_t *);
92: static int html_headtagargs(struct md_mbuf *,
1.3 kristaps 93: const struct md_args *, int,
1.7 kristaps 94: const int *, const char **, size_t *);
1.12 kristaps 95: static int html_bodytagname(struct md_mbuf *,
1.10 kristaps 96: const struct md_args *,
97: int, struct htmlq *, const int *,
98: const char **, size_t *);
1.12 kristaps 99: static int html_bodytagargs(struct md_mbuf *,
1.3 kristaps 100: const struct md_args *, int,
1.7 kristaps 101: const int *, const char **, size_t *);
102: static int html_inlinetagname(struct md_mbuf *,
103: const struct md_args *, int, size_t *);
104: static int html_inlinetagargs(struct md_mbuf *,
1.2 kristaps 105: const struct md_args *, int,
1.7 kristaps 106: const int *, const char **, size_t *);
1.10 kristaps 107: static int html_Bl_bodytagname(struct md_mbuf *,
108: struct htmlq *, const int *,
109: const char **, size_t *);
110: static int html_It_blocktagname(struct md_mbuf *,
111: struct htmlq *, const int *,
112: const char **, size_t *);
113: static int html_It_headtagname(struct md_mbuf *,
114: struct htmlq *, const int *,
115: const char **, size_t *);
116: static int html_It_bodytagname(struct md_mbuf *,
117: struct htmlq *, const int *,
118: const char **, size_t *);
1.19 ! kristaps 119: static int html_tputln(struct md_mbuf *,
! 120: enum ml_scope, int, enum html_tag);
! 121: static int html_aputln(struct md_mbuf *, enum ml_scope,
! 122: int, enum html_tag,
! 123: int, const struct html_pair *);
1.10 kristaps 124:
125:
126: /* ARGSUSED */
127: static int
128: html_It_headtagname(struct md_mbuf *mbuf, struct htmlq *q,
129: const int *argc, const char **argv, size_t *res)
130: {
131: struct htmlnode *n;
1.11 kristaps 132: int i;
1.10 kristaps 133:
134: for (n = q->last; n; n = n->parent)
135: if (n->tok == ROFF_Bl)
136: break;
137:
138: assert(n);
1.13 kristaps 139:
140: /* LINTED */
1.11 kristaps 141: for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10 kristaps 142: i < ROFF_MAXLINEARG; i++) {
143: switch (n->argc[i]) {
1.14 kristaps 144: case (ROFF_Ohang):
1.19 ! kristaps 145: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.10 kristaps 146: case (ROFF_Tag):
147: /* FALLTHROUGH */
148: case (ROFF_Column):
1.19 ! kristaps 149: return(html_stput(mbuf, HTML_TAG_TD, res));
1.10 kristaps 150: default:
151: break;
152: }
153: }
154:
1.16 kristaps 155: return(0);
1.10 kristaps 156: }
157:
158:
159: /* ARGSUSED */
160: static int
161: html_It_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
162: const int *argc, const char **argv, size_t *res)
163: {
164: struct htmlnode *n;
1.11 kristaps 165: int i;
1.10 kristaps 166:
167: for (n = q->last; n; n = n->parent)
168: if (n->tok == ROFF_Bl)
169: break;
170:
171: assert(n);
1.13 kristaps 172:
173: /* LINTED */
1.11 kristaps 174: for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10 kristaps 175: i < ROFF_MAXLINEARG; i++) {
176: switch (n->argc[i]) {
177: case (ROFF_Enum):
178: /* FALLTHROUGH */
179: case (ROFF_Bullet):
180: /* FALLTHROUGH */
181: case (ROFF_Dash):
182: /* FALLTHROUGH */
183: case (ROFF_Hyphen):
184: /* FALLTHROUGH */
185: case (ROFF_Item):
186: /* FALLTHROUGH */
187: case (ROFF_Diag):
188: /* FALLTHROUGH */
189: case (ROFF_Hang):
190: /* FALLTHROUGH */
191: case (ROFF_Ohang):
192: /* FALLTHROUGH */
193: case (ROFF_Inset):
1.19 ! kristaps 194: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.10 kristaps 195: case (ROFF_Tag):
196: /* FALLTHROUGH */
197: case (ROFF_Column):
1.19 ! kristaps 198: return(html_stput(mbuf, HTML_TAG_TD, res));
1.10 kristaps 199: default:
200: break;
201: }
202: }
203:
204: assert(i != ROFF_MAXLINEARG);
1.16 kristaps 205: return(0);
1.10 kristaps 206: }
207:
208:
209: /* ARGSUSED */
210: static int
211: html_Bl_bodytagname(struct md_mbuf *mbuf, struct htmlq *q,
212: const int *argc, const char **argv, size_t *res)
213: {
1.11 kristaps 214: int i;
1.10 kristaps 215:
1.11 kristaps 216: for (i = 0; ROFF_ARGMAX != argc[i]
1.10 kristaps 217: && i < ROFF_MAXLINEARG; i++) {
218: switch (argc[i]) {
219: case (ROFF_Enum):
1.19 ! kristaps 220: return(html_stput(mbuf, HTML_TAG_OL, res));
1.10 kristaps 221: case (ROFF_Bullet):
222: /* FALLTHROUGH */
223: case (ROFF_Dash):
224: /* FALLTHROUGH */
225: case (ROFF_Hyphen):
226: /* FALLTHROUGH */
227: case (ROFF_Item):
228: /* FALLTHROUGH */
229: case (ROFF_Diag):
230: /* FALLTHROUGH */
231: case (ROFF_Hang):
232: /* FALLTHROUGH */
233: case (ROFF_Ohang):
234: /* FALLTHROUGH */
235: case (ROFF_Inset):
1.19 ! kristaps 236: return(html_stput(mbuf, HTML_TAG_UL, res));
1.10 kristaps 237: case (ROFF_Tag):
238: /* FALLTHROUGH */
239: case (ROFF_Column):
1.19 ! kristaps 240: return(html_stput(mbuf, HTML_TAG_TABLE, res));
1.10 kristaps 241: default:
242: break;
243: }
244: }
245:
246: assert(i != ROFF_MAXLINEARG);
1.16 kristaps 247: return(0);
1.10 kristaps 248: }
249:
250:
251: /* ARGSUSED */
252: static int
253: html_It_blocktagname(struct md_mbuf *mbuf, struct htmlq *q,
254: const int *argc, const char **argv, size_t *res)
255: {
256: struct htmlnode *n;
1.11 kristaps 257: int i;
1.10 kristaps 258:
259: for (n = q->last; n; n = n->parent)
260: if (n->tok == ROFF_Bl)
261: break;
262:
263: assert(n);
1.13 kristaps 264:
265: /* LINTED */
1.11 kristaps 266: for (i = 0; ROFF_ARGMAX != n->argc[i] &&
1.10 kristaps 267: i < ROFF_MAXLINEARG; i++) {
268: switch (n->argc[i]) {
269: case (ROFF_Enum):
270: /* FALLTHROUGH */
271: case (ROFF_Bullet):
272: /* FALLTHROUGH */
273: case (ROFF_Dash):
274: /* FALLTHROUGH */
275: case (ROFF_Hyphen):
276: /* FALLTHROUGH */
277: case (ROFF_Item):
278: /* FALLTHROUGH */
279: case (ROFF_Diag):
280: /* FALLTHROUGH */
281: case (ROFF_Hang):
282: /* FALLTHROUGH */
283: case (ROFF_Ohang):
284: /* FALLTHROUGH */
285: case (ROFF_Inset):
1.19 ! kristaps 286: return(html_stput(mbuf, HTML_TAG_LI, res));
1.10 kristaps 287: case (ROFF_Tag):
288: /* FALLTHROUGH */
289: case (ROFF_Column):
1.19 ! kristaps 290: return(html_stput(mbuf, HTML_TAG_TR, res));
1.10 kristaps 291: default:
292: break;
293: }
294: }
295:
296: assert(i != ROFF_MAXLINEARG);
1.16 kristaps 297: return(0);
1.10 kristaps 298: }
1.2 kristaps 299:
300:
1.4 kristaps 301: static int
302: html_loadcss(struct md_mbuf *mbuf, const char *css)
303: {
304: size_t res, bufsz;
305: char *buf;
306: struct stat st;
307: int fd, c;
308: ssize_t ssz;
309:
310: c = 0;
311: res = 0;
312: buf = NULL;
313:
314: if (-1 == (fd = open(css, O_RDONLY, 0))) {
315: warn("%s", css);
316: return(0);
317: }
318:
319: if (-1 == fstat(fd, &st)) {
320: warn("%s", css);
321: goto out;
322: }
323:
324: bufsz = MAX(st.st_blksize, BUFSIZ);
325: if (NULL == (buf = malloc(bufsz))) {
326: warn("malloc");
327: goto out;
328: }
329:
330: for (;;) {
331: if (-1 == (ssz = read(fd, buf, bufsz))) {
332: warn("%s", css);
333: goto out;
334: } else if (0 == ssz)
335: break;
336: if ( ! ml_nputs(mbuf, buf, (size_t)ssz, &res))
337: goto out;
338: }
339:
340: c = 1;
341:
342: out:
343: if (-1 == close(fd)) {
344: warn("%s", css);
345: c = 0;
346: }
347:
348: if (buf)
349: free(buf);
350:
351: return(c);
352: }
353:
354:
1.18 kristaps 355: static int
1.19 ! kristaps 356: html_tputln(struct md_mbuf *mbuf, enum ml_scope scope,
! 357: int i, enum html_tag tag)
1.18 kristaps 358: {
359:
1.19 ! kristaps 360: if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
1.18 kristaps 361: return(0);
1.19 ! kristaps 362: if ( ! html_tput(mbuf, scope, tag, NULL))
1.18 kristaps 363: return(0);
1.19 ! kristaps 364: return(ml_nputs(mbuf, "\n", 1, NULL));
1.18 kristaps 365: }
366:
367:
368: static int
1.19 ! kristaps 369: html_aputln(struct md_mbuf *mbuf, enum ml_scope scope, int i,
! 370: enum html_tag tag, int sz, const struct html_pair *p)
1.18 kristaps 371: {
372:
1.19 ! kristaps 373: if ( ! ml_putchars(mbuf, ' ', INDENT(i) * INDENT_SZ, NULL))
1.18 kristaps 374: return(0);
1.19 ! kristaps 375: if ( ! html_aput(mbuf, scope, tag, NULL, sz, p))
! 376: return(0);
! 377: return(ml_nputs(mbuf, "\n", 1, NULL));
1.18 kristaps 378: }
379:
380:
1.3 kristaps 381: /* ARGSUSED */
1.2 kristaps 382: static int
1.4 kristaps 383: html_begin(struct md_mbuf *mbuf, const struct md_args *args,
384: const struct tm *tm, const char *os,
1.19 ! kristaps 385: const char *name, enum roffmsec msec, const char *vol)
1.2 kristaps 386: {
1.19 ! kristaps 387: struct html_pair attr[4];
! 388: char ts[32];
! 389: int i;
1.2 kristaps 390:
1.19 ! kristaps 391: (void)snprintf(ts, sizeof(ts), "%s(%s)",
! 392: name, roff_msecname(msec));
1.4 kristaps 393:
1.18 kristaps 394: i = 0;
1.4 kristaps 395:
1.19 ! kristaps 396: if ( ! html_typeput(mbuf, HTML_TYPE_4_01_STRICT, NULL))
1.17 kristaps 397: return(0);
1.19 ! kristaps 398: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_HTML))
1.17 kristaps 399: return(0);
1.19 ! kristaps 400: if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_HEAD))
1.17 kristaps 401: return(0);
1.19 ! kristaps 402:
! 403: attr[0].attr = HTML_ATTR_HTTP_EQUIV;
! 404: attr[0].val = "content-type";
! 405: attr[1].attr = HTML_ATTR_CONTENT;
! 406: attr[1].val = "text/html;charset=utf-8";
! 407:
! 408: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
1.17 kristaps 409: return(0);
1.19 ! kristaps 410:
! 411: attr[0].attr = HTML_ATTR_NAME;
! 412: attr[0].val = "resource-type";
! 413: attr[1].attr = HTML_ATTR_CONTENT;
! 414: attr[1].val = "document";
! 415:
! 416: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_META, 2, attr))
1.17 kristaps 417: return(0);
1.19 ! kristaps 418:
! 419: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TITLE))
1.17 kristaps 420: return(0);
1.19 ! kristaps 421: if ( ! ml_putstring(mbuf, ts, NULL))
1.17 kristaps 422: return(0);
1.19 ! kristaps 423: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TITLE))
1.2 kristaps 424: return(0);
1.4 kristaps 425:
426: if (HTML_CSS_EMBED & args->params.html.flags) {
1.19 ! kristaps 427: attr[0].attr = HTML_ATTR_TYPE;
! 428: attr[0].val = "text/css";
! 429:
! 430: if ( ! html_aputln(mbuf, ML_OPEN, i,
! 431: HTML_TAG_STYLE, 1, attr))
1.4 kristaps 432: return(0);
1.19 ! kristaps 433: if ( ! html_commentput(mbuf, ML_OPEN, NULL))
! 434: return(NULL);
! 435:
1.4 kristaps 436: if ( ! html_loadcss(mbuf, args->params.html.css))
437: return(0);
1.19 ! kristaps 438:
! 439: if ( ! html_commentput(mbuf, ML_CLOSE, NULL))
! 440: return(NULL);
! 441: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_STYLE))
1.4 kristaps 442: return(0);
1.19 ! kristaps 443: } else {
! 444: attr[0].attr = HTML_ATTR_REL;
! 445: attr[0].val = "stylesheet";
! 446: attr[1].attr = HTML_ATTR_TYPE;
! 447: attr[1].val = "text/css";
! 448: attr[2].attr = HTML_ATTR_HREF;
! 449: attr[2].val = args->params.html.css;
! 450:
! 451: if ( ! html_aputln(mbuf, ML_OPEN, i,
! 452: HTML_TAG_LINK, 3, attr))
! 453: return(0);
! 454: }
1.4 kristaps 455:
1.19 ! kristaps 456: if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_HEAD))
1.18 kristaps 457: return(0);
1.19 ! kristaps 458: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_BODY))
1.18 kristaps 459: return(0);
1.19 ! kristaps 460:
! 461: attr[0].attr = HTML_ATTR_CLASS;
! 462: attr[0].val = "mdoc";
! 463:
! 464: if ( ! html_aputln(mbuf, ML_OPEN, i, HTML_TAG_DIV, 1, attr))
1.18 kristaps 465: return(0);
1.19 ! kristaps 466:
! 467: attr[0].attr = HTML_ATTR_WIDTH;
! 468: attr[0].val = "100%";
! 469:
! 470: if ( ! html_aputln(mbuf, ML_OPEN, i++, HTML_TAG_TABLE, 1, attr))
1.18 kristaps 471: return(0);
1.19 ! kristaps 472: if ( ! html_tputln(mbuf, ML_OPEN, i++, HTML_TAG_TR))
1.18 kristaps 473: return(0);
1.19 ! kristaps 474:
! 475: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TD))
1.2 kristaps 476: return(0);
1.19 ! kristaps 477: if ( ! ml_putstring(mbuf, ts, NULL))
1.18 kristaps 478: return(0);
1.19 ! kristaps 479: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.18 kristaps 480: return(0);
1.19 ! kristaps 481:
! 482: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TD))
1.18 kristaps 483: return(0);
1.19 ! kristaps 484: /* TODO: middle. */
! 485: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.18 kristaps 486: return(0);
1.19 ! kristaps 487:
! 488: if ( ! html_tputln(mbuf, ML_OPEN, i, HTML_TAG_TD))
1.18 kristaps 489: return(0);
1.19 ! kristaps 490: if ( ! ml_putstring(mbuf, ts, NULL))
1.17 kristaps 491: return(0);
1.19 ! kristaps 492: if ( ! html_tputln(mbuf, ML_CLOSE, i, HTML_TAG_TD))
1.17 kristaps 493: return(0);
1.19 ! kristaps 494:
! 495: if ( ! html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TR))
1.17 kristaps 496: return(0);
1.19 ! kristaps 497: return(html_tputln(mbuf, ML_CLOSE, --i, HTML_TAG_TABLE));
1.2 kristaps 498: }
499:
500:
1.3 kristaps 501: /* ARGSUSED */
1.2 kristaps 502: static int
503: html_end(struct md_mbuf *mbuf, const struct md_args *args)
504: {
505:
1.19 ! kristaps 506: if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_DIV))
1.18 kristaps 507: return(0);
1.19 ! kristaps 508: if ( ! html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_BODY))
1.18 kristaps 509: return(0);
1.19 ! kristaps 510: return(html_tputln(mbuf, ML_CLOSE, 0, HTML_TAG_HTML));
1.2 kristaps 511: }
512:
513:
1.3 kristaps 514: /* ARGSUSED */
1.7 kristaps 515: static int
1.12 kristaps 516: html_bodytagname(struct md_mbuf *mbuf,
1.10 kristaps 517: const struct md_args *args, int tok, struct htmlq *q,
518: const int *argc, const char **argv, size_t *res)
1.2 kristaps 519: {
1.3 kristaps 520:
1.10 kristaps 521: switch (tok) {
522: case (ROFF_Bl):
523: return(html_Bl_bodytagname(mbuf, q, argc, argv, res));
1.12 kristaps 524: case (ROFF_Fo):
1.19 ! kristaps 525: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10 kristaps 526: case (ROFF_It):
527: return(html_It_bodytagname(mbuf, q, argc, argv, res));
1.12 kristaps 528: case (ROFF_Oo):
1.19 ! kristaps 529: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10 kristaps 530: default:
531: break;
532: }
533:
1.19 ! kristaps 534: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3 kristaps 535: }
536:
537:
538: /* ARGSUSED */
1.7 kristaps 539: static int
1.10 kristaps 540: html_headtagname(struct md_mbuf *mbuf,
541: const struct md_args *args, int tok, struct htmlq *q,
542: const int *argc, const char **argv, size_t *res)
1.3 kristaps 543: {
544:
1.10 kristaps 545: switch (tok) {
546: case (ROFF_It):
547: return(html_It_headtagname(mbuf, q, argc, argv, res));
1.12 kristaps 548: case (ROFF_Fo):
1.19 ! kristaps 549: /* FALLTHROUGH */
1.12 kristaps 550: case (ROFF_Oo):
1.19 ! kristaps 551: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10 kristaps 552: case (ROFF_Sh):
1.19 ! kristaps 553: return(html_stput(mbuf, HTML_TAG_H1, res));
1.10 kristaps 554: case (ROFF_Ss):
1.19 ! kristaps 555: return(html_stput(mbuf, HTML_TAG_H2, res));
1.10 kristaps 556: default:
557: break;
558: }
559:
1.19 ! kristaps 560: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3 kristaps 561: }
562:
563:
564: /* ARGSUSED */
1.7 kristaps 565: static int
1.10 kristaps 566: html_blocktagname(struct md_mbuf *mbuf, const struct md_args *args,
567: int tok, struct htmlq *q, const int *argc,
568: const char **argv, size_t *res)
1.3 kristaps 569: {
570:
1.10 kristaps 571: switch (tok) {
1.12 kristaps 572: case (ROFF_Fo):
1.19 ! kristaps 573: /* FALLTHROUGH */
1.12 kristaps 574: case (ROFF_Oo):
1.19 ! kristaps 575: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.10 kristaps 576: case (ROFF_It):
577: return(html_It_blocktagname(mbuf, q, argc, argv, res));
578: default:
579: break;
580: }
581:
1.19 ! kristaps 582: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.3 kristaps 583: }
584:
585:
1.9 kristaps 586: /* ARGSUSED */
1.7 kristaps 587: static int
588: html_printargs(struct md_mbuf *mbuf, int tok, const char *ns,
589: const int *argc, const char **argv, size_t *res)
1.3 kristaps 590: {
591:
1.19 ! kristaps 592: /* FIXME: use API in ml.h. */
! 593:
1.7 kristaps 594: if ( ! ml_puts(mbuf, " class=\"", res))
595: return(0);
596: if ( ! ml_puts(mbuf, ns, res))
597: return(0);
598: if ( ! ml_puts(mbuf, "-", res))
1.3 kristaps 599: return(0);
1.7 kristaps 600: if ( ! ml_puts(mbuf, toknames[tok], res))
1.3 kristaps 601: return(0);
1.9 kristaps 602: return(ml_puts(mbuf, "\"", res));
1.3 kristaps 603: }
604:
605:
606: /* ARGSUSED */
1.7 kristaps 607: static int
1.10 kristaps 608: html_headtagargs(struct md_mbuf *mbuf,
1.7 kristaps 609: const struct md_args *args, int tok,
610: const int *argc, const char **argv, size_t *res)
1.3 kristaps 611: {
612:
1.7 kristaps 613: return(html_printargs(mbuf, tok, "head", argc, argv, res));
614: }
1.3 kristaps 615:
616:
1.7 kristaps 617: /* ARGSUSED */
618: static int
1.12 kristaps 619: html_bodytagargs(struct md_mbuf *mbuf,
1.7 kristaps 620: const struct md_args *args, int tok,
621: const int *argc, const char **argv, size_t *res)
622: {
1.3 kristaps 623:
1.7 kristaps 624: return(html_printargs(mbuf, tok, "body", argc, argv, res));
1.2 kristaps 625: }
626:
627:
628: /* ARGSUSED */
1.7 kristaps 629: static int
630: html_blocktagargs(struct md_mbuf *mbuf,
631: const struct md_args *args, int tok,
632: const int *argc, const char **argv, size_t *res)
1.2 kristaps 633: {
1.3 kristaps 634:
1.7 kristaps 635: return(html_printargs(mbuf, tok, "block", argc, argv, res));
1.2 kristaps 636: }
1.1 kristaps 637:
638:
639: /* ARGSUSED */
1.7 kristaps 640: static int
641: html_inlinetagargs(struct md_mbuf *mbuf,
642: const struct md_args *args, int tok,
643: const int *argc, const char **argv, size_t *res)
1.2 kristaps 644: {
645:
1.12 kristaps 646: if ( ! html_printargs(mbuf, tok, "inline", argc, argv, res))
647: return(0);
648:
649: switch (tok) {
650: case (ROFF_Sx):
1.19 ! kristaps 651:
! 652: /* FIXME: use API in ml.h. */
! 653:
1.12 kristaps 654: assert(*argv);
655: if ( ! ml_nputs(mbuf, " href=\"#", 8, res))
656: return(0);
657: if ( ! ml_putstring(mbuf, *argv, res))
658: return(0);
659: if ( ! ml_nputs(mbuf, "\"", 1, res))
660: return(0);
1.13 kristaps 661: break;
1.12 kristaps 662: default:
663: break;
664: }
665:
666: return(1);
1.2 kristaps 667: }
668:
669:
1.3 kristaps 670: /* ARGSUSED */
1.7 kristaps 671: static int
1.2 kristaps 672: html_inlinetagname(struct md_mbuf *mbuf,
1.7 kristaps 673: const struct md_args *args, int tok, size_t *res)
1.2 kristaps 674: {
675:
676: switch (tok) {
1.4 kristaps 677: case (ROFF_Pp):
1.19 ! kristaps 678: return(html_stput(mbuf, HTML_TAG_DIV, res));
1.12 kristaps 679: case (ROFF_Sx):
1.19 ! kristaps 680: return(html_stput(mbuf, HTML_TAG_A, res));
1.2 kristaps 681: default:
1.9 kristaps 682: break;
1.2 kristaps 683: }
1.9 kristaps 684:
1.19 ! kristaps 685: return(html_stput(mbuf, HTML_TAG_SPAN, res));
1.2 kristaps 686: }
687:
688:
689: static ssize_t
1.8 kristaps 690: html_begintag(struct md_mbuf *mbuf, void *data,
691: const struct md_args *args, enum md_ns ns,
692: int tok, const int *argc, const char **argv)
1.2 kristaps 693: {
1.7 kristaps 694: size_t res;
1.8 kristaps 695: struct htmlq *q;
696: struct htmlnode *node;
1.11 kristaps 697: int i;
1.2 kristaps 698:
699: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 700: res = 0;
701:
1.8 kristaps 702: assert(data);
703: q = (struct htmlq *)data;
704:
705: if (NULL == (node = calloc(1, sizeof(struct htmlnode)))) {
706: warn("calloc");
707: return(-1);
708: }
709:
710: node->parent = q->last;
711: node->tok = tok;
712: node->ns = ns;
713:
1.10 kristaps 714: if (argc) {
715: /* TODO: argv. */
716:
717: assert(argv);
1.13 kristaps 718: /* LINTED */
1.11 kristaps 719: for (i = 0; ROFF_ARGMAX != argc[i]
1.10 kristaps 720: && i < ROFF_MAXLINEARG; i++)
721: node->argc[i] = argc[i];
722: assert(i != ROFF_MAXLINEARG);
1.12 kristaps 723: }
1.10 kristaps 724:
725:
1.8 kristaps 726: q->last = node;
727:
1.3 kristaps 728: switch (ns) {
729: case (MD_NS_BLOCK):
1.10 kristaps 730: if ( ! html_blocktagname(mbuf, args, tok,
731: q, argc, argv, &res))
1.7 kristaps 732: return(-1);
733: if ( ! html_blocktagargs(mbuf, args, tok,
734: argc, argv, &res))
735: return(-1);
736: break;
1.3 kristaps 737: case (MD_NS_BODY):
1.12 kristaps 738: if ( ! html_bodytagname(mbuf, args, tok,
1.10 kristaps 739: q, argc, argv, &res))
1.7 kristaps 740: return(-1);
1.12 kristaps 741: if ( ! html_bodytagargs(mbuf, args, tok,
1.7 kristaps 742: argc, argv, &res))
743: return(-1);
744: break;
1.3 kristaps 745: case (MD_NS_HEAD):
1.10 kristaps 746: if ( ! html_headtagname(mbuf, args, tok, q,
747: argc, argv, &res))
1.7 kristaps 748: return(-1);
1.10 kristaps 749: if ( ! html_headtagargs(mbuf, args, tok,
1.7 kristaps 750: argc, argv, &res))
751: return(-1);
752: break;
1.3 kristaps 753: default:
1.7 kristaps 754: if ( ! html_inlinetagname(mbuf, args, tok, &res))
755: return(-1);
756: if ( ! html_inlinetagargs(mbuf, args, tok,
757: argc, argv, &res))
758: return(-1);
1.3 kristaps 759: break;
1.2 kristaps 760: }
761:
1.7 kristaps 762: return((ssize_t)res);
1.2 kristaps 763: }
764:
765:
766: static ssize_t
1.8 kristaps 767: html_endtag(struct md_mbuf *mbuf, void *data,
768: const struct md_args *args, enum md_ns ns, int tok)
1.2 kristaps 769: {
1.7 kristaps 770: size_t res;
1.8 kristaps 771: struct htmlq *q;
772: struct htmlnode *node;
1.2 kristaps 773:
774: assert(ns != MD_NS_DEFAULT);
1.7 kristaps 775: res = 0;
776:
1.8 kristaps 777: assert(data);
778: q = (struct htmlq *)data;
1.10 kristaps 779: node = q->last;
1.8 kristaps 780:
1.3 kristaps 781: switch (ns) {
782: case (MD_NS_BLOCK):
1.10 kristaps 783: if ( ! html_blocktagname(mbuf, args, tok,
784: q, node->argc,
785: (const char **)node->argv, &res))
1.7 kristaps 786: return(-1);
787: break;
1.3 kristaps 788: case (MD_NS_BODY):
1.12 kristaps 789: if ( ! html_bodytagname(mbuf, args, tok,
1.10 kristaps 790: q, node->argc,
791: (const char **)node->argv, &res))
1.7 kristaps 792: return(-1);
793: break;
1.3 kristaps 794: case (MD_NS_HEAD):
1.10 kristaps 795: if ( ! html_headtagname(mbuf, args, tok,
796: q, node->argc,
797: (const char **)node->argv, &res))
1.7 kristaps 798: return(-1);
799: break;
1.3 kristaps 800: default:
1.7 kristaps 801: if ( ! html_inlinetagname(mbuf, args, tok, &res))
802: return(-1);
1.3 kristaps 803: break;
804: }
1.2 kristaps 805:
1.8 kristaps 806: q->last = node->parent;
807:
1.9 kristaps 808: free(node);
1.8 kristaps 809:
1.7 kristaps 810: return((ssize_t)res);
1.2 kristaps 811: }
812:
813:
1.9 kristaps 814: static int
815: html_alloc(void **p)
816: {
817:
818: if (NULL == (*p = calloc(1, sizeof(struct htmlq)))) {
819: warn("calloc");
820: return(0);
821: }
822: return(1);
823: }
824:
825:
826: static void
827: html_free(void *p)
828: {
829: struct htmlq *q;
830: struct htmlnode *n;
831:
832: assert(p);
833: q = (struct htmlq *)p;
834:
1.13 kristaps 835: /* LINTED */
1.9 kristaps 836: while ((n = q->last)) {
837: q->last = n->parent;
838: free(n);
839: }
840:
841: free(q);
842: }
843:
844:
1.14 kristaps 845: static ssize_t
846: html_beginhttp(struct md_mbuf *mbuf,
847: const struct md_args *args,
848: const char *buf, size_t sz)
849: {
850: size_t res;
1.19 ! kristaps 851: struct html_pair pair;
1.14 kristaps 852:
853: res = 0;
1.19 ! kristaps 854: pair.attr = HTML_ATTR_HREF;
! 855: pair.val = (char *)buf;
1.14 kristaps 856:
1.19 ! kristaps 857: if ( ! html_aput(mbuf, ML_OPEN, HTML_TAG_A, &res, 1, &pair))
1.14 kristaps 858: return(-1);
859: return((ssize_t)res);
860: }
861:
862:
863: static ssize_t
864: html_endhttp(struct md_mbuf *mbuf,
865: const struct md_args *args,
866: const char *buf, size_t sz)
867: {
868: size_t res;
869:
870: res = 0;
1.19 ! kristaps 871: if ( ! html_tput(mbuf, ML_CLOSE, HTML_TAG_A, &res))
1.14 kristaps 872: return(-1);
873: return((ssize_t)res);
874: }
875:
876:
877: /* ARGSUSED */
878: static ssize_t
879: html_beginstring(struct md_mbuf *mbuf,
880: const struct md_args *args,
881: const char *buf, size_t sz)
882: {
883:
884: if (0 == strncmp(buf, "http://", 7))
885: return(html_beginhttp(mbuf, args, buf, sz));
886:
887: return(0);
888: }
889:
890:
891: /* ARGSUSED */
892: static ssize_t
893: html_endstring(struct md_mbuf *mbuf,
894: const struct md_args *args,
895: const char *buf, size_t sz)
896: {
897:
898: if (0 == strncmp(buf, "http://", 7))
899: return(html_endhttp(mbuf, args, buf, sz));
900:
901: return(0);
902: }
903:
904:
1.1 kristaps 905: int
906: md_line_html(void *data, char *buf)
907: {
908:
1.2 kristaps 909: return(mlg_line((struct md_mlg *)data, buf));
1.1 kristaps 910: }
911:
912:
913: int
914: md_exit_html(void *data, int flush)
915: {
916:
1.2 kristaps 917: return(mlg_exit((struct md_mlg *)data, flush));
1.1 kristaps 918: }
919:
920:
921: void *
922: md_init_html(const struct md_args *args,
923: struct md_mbuf *mbuf, const struct md_rbuf *rbuf)
924: {
1.9 kristaps 925: struct ml_cbs cbs;
1.8 kristaps 926:
1.9 kristaps 927: cbs.ml_alloc = html_alloc;
928: cbs.ml_free = html_free;
929: cbs.ml_begintag = html_begintag;
930: cbs.ml_endtag = html_endtag;
931: cbs.ml_begin = html_begin;
932: cbs.ml_end = html_end;
1.14 kristaps 933: cbs.ml_beginstring = html_beginstring;
934: cbs.ml_endstring = html_endstring;
1.1 kristaps 935:
1.9 kristaps 936: return(mlg_alloc(args, rbuf, mbuf, &cbs));
1.1 kristaps 937: }
CVSweb