Annotation of mandoc/html.c, Revision 1.33
1.33 ! kristaps 1: /* $Id: html.c,v 1.32 2009/09/17 08:21:42 kristaps Exp $ */
1.1 kristaps 2: /*
1.29 kristaps 3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
1.1 kristaps 4: *
5: * Permission to use, copy, modify, and distribute this software for any
1.29 kristaps 6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
1.1 kristaps 8: *
1.29 kristaps 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1.1 kristaps 16: */
1.30 kristaps 17: #include <sys/queue.h>
18:
1.1 kristaps 19: #include <assert.h>
1.33 ! kristaps 20: #include <ctype.h>
1.4 kristaps 21: #include <err.h>
1.29 kristaps 22: #include <stdio.h>
1.1 kristaps 23: #include <stdlib.h>
1.33 ! kristaps 24: #include <string.h>
1.1 kristaps 25:
1.32 kristaps 26: #include "chars.h"
1.29 kristaps 27: #include "mdoc.h"
28: #include "man.h"
1.2 kristaps 29:
1.29 kristaps 30: #define DOCTYPE "-//W3C//DTD HTML 4.01//EN"
31: #define DTD "http://www.w3.org/TR/html4/strict.dtd"
1.8 kristaps 32:
1.33 ! kristaps 33: #define INDENT 5
! 34: #define HALFINDENT 3
! 35:
1.29 kristaps 36: enum htmltag {
37: TAG_HTML,
38: TAG_HEAD,
39: TAG_BODY,
40: TAG_META,
41: TAG_TITLE,
42: TAG_DIV,
43: TAG_H1,
44: TAG_H2,
45: TAG_P,
46: TAG_SPAN,
47: TAG_LINK,
1.30 kristaps 48: TAG_BR,
49: TAG_A,
1.33 ! kristaps 50: TAG_TABLE,
! 51: TAG_COL,
! 52: TAG_TR,
! 53: TAG_TD,
1.29 kristaps 54: TAG_MAX
1.7 kristaps 55: };
56:
1.29 kristaps 57: enum htmlattr {
58: ATTR_HTTPEQUIV,
59: ATTR_CONTENT,
60: ATTR_NAME,
61: ATTR_REL,
62: ATTR_HREF,
63: ATTR_TYPE,
64: ATTR_MEDIA,
65: ATTR_CLASS,
1.33 ! kristaps 66: ATTR_STYLE,
! 67: ATTR_WIDTH,
! 68: ATTR_VALIGN,
1.29 kristaps 69: ATTR_MAX
1.7 kristaps 70: };
71:
1.29 kristaps 72: struct htmldata {
73: char *name;
74: int flags;
1.30 kristaps 75: #define HTML_CLRLINE (1 << 0)
76: #define HTML_NOSTACK (1 << 1)
1.29 kristaps 77: };
1.7 kristaps 78:
1.29 kristaps 79: static const struct htmldata htmltags[TAG_MAX] = {
1.30 kristaps 80: {"html", HTML_CLRLINE}, /* TAG_HTML */
81: {"head", HTML_CLRLINE}, /* TAG_HEAD */
82: {"body", HTML_CLRLINE}, /* TAG_BODY */
83: {"meta", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */
1.33 ! kristaps 84: {"title", HTML_CLRLINE}, /* TAG_TITLE */
1.30 kristaps 85: {"div", HTML_CLRLINE}, /* TAG_DIV */
1.29 kristaps 86: {"h1", 0}, /* TAG_H1 */
87: {"h2", 0}, /* TAG_H2 */
1.30 kristaps 88: {"p", HTML_CLRLINE}, /* TAG_P */
1.29 kristaps 89: {"span", 0}, /* TAG_SPAN */
1.30 kristaps 90: {"link", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
91: {"br", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
92: {"a", 0}, /* TAG_A */
1.33 ! kristaps 93: {"table", HTML_CLRLINE}, /* TAG_TABLE */
! 94: {"col", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_COL */
! 95: {"tr", HTML_CLRLINE}, /* TAG_TR */
! 96: {"td", HTML_CLRLINE}, /* TAG_TD */
1.29 kristaps 97: };
1.10 kristaps 98:
1.29 kristaps 99: static const char *const htmlattrs[ATTR_MAX] = {
100: "http-equiv",
101: "content",
102: "name",
103: "rel",
104: "href",
105: "type",
106: "media",
1.33 ! kristaps 107: "class",
! 108: "style",
! 109: "width",
! 110: "valign",
1.29 kristaps 111: };
1.10 kristaps 112:
1.29 kristaps 113: struct htmlpair {
114: enum htmlattr key;
115: char *val;
116: };
1.10 kristaps 117:
1.30 kristaps 118: struct tag {
119: enum htmltag tag;
120: SLIST_ENTRY(tag) entry;
121: };
122:
123: SLIST_HEAD(tagq, tag);
124:
1.29 kristaps 125: struct html {
126: int flags;
127: #define HTML_NOSPACE (1 << 0)
1.30 kristaps 128: #define HTML_NEWLINE (1 << 1)
129: struct tagq stack;
1.32 kristaps 130: void *symtab;
1.29 kristaps 131: };
1.10 kristaps 132:
1.29 kristaps 133: #define MDOC_ARGS const struct mdoc_meta *m, \
134: const struct mdoc_node *n, \
135: struct html *h
136: #define MAN_ARGS const struct man_meta *m, \
137: const struct man_node *n, \
138: struct html *h
139: struct htmlmdoc {
140: int (*pre)(MDOC_ARGS);
141: void (*post)(MDOC_ARGS);
142: };
1.13 kristaps 143:
1.29 kristaps 144: static void print_gen_doctype(struct html *);
145: static void print_gen_head(struct html *);
146: static void print_mdoc(MDOC_ARGS);
147: static void print_mdoc_head(MDOC_ARGS);
1.30 kristaps 148: static void print_mdoc_title(MDOC_ARGS);
1.29 kristaps 149: static void print_mdoc_node(MDOC_ARGS);
150: static void print_man(MAN_ARGS);
151: static void print_man_head(MAN_ARGS);
152: static void print_man_body(MAN_ARGS);
1.30 kristaps 153: static struct tag *print_otag(struct html *, enum htmltag,
1.29 kristaps 154: int, const struct htmlpair *);
1.30 kristaps 155: static void print_tagq(struct html *, const struct tag *);
156: static void print_stagq(struct html *, const struct tag *);
1.29 kristaps 157: static void print_ctag(struct html *, enum htmltag);
1.32 kristaps 158: static void print_encode(struct html *, const char *);
159: static void print_escape(struct html *, const char **);
1.29 kristaps 160: static void print_text(struct html *, const char *);
1.32 kristaps 161: static void print_res(struct html *, const char *, int);
162: static void print_spec(struct html *, const char *, int);
1.33 ! kristaps 163:
! 164: static int a2width(const char *);
! 165: static int a2offs(const char *);
! 166:
! 167: static int mdoc_list_pre(MDOC_ARGS);
1.29 kristaps 168: static int mdoc_root_pre(MDOC_ARGS);
1.33 ! kristaps 169: static int mdoc_hang_pre(MDOC_ARGS);
1.29 kristaps 170:
1.31 kristaps 171: static int mdoc_ar_pre(MDOC_ARGS);
1.33 ! kristaps 172: static int mdoc_bl_pre(MDOC_ARGS);
1.30 kristaps 173: static int mdoc_fl_pre(MDOC_ARGS);
1.33 ! kristaps 174: static int mdoc_it_pre(MDOC_ARGS);
1.29 kristaps 175: static int mdoc_nd_pre(MDOC_ARGS);
176: static int mdoc_nm_pre(MDOC_ARGS);
1.31 kristaps 177: static int mdoc_ns_pre(MDOC_ARGS);
1.30 kristaps 178: static int mdoc_op_pre(MDOC_ARGS);
179: static void mdoc_op_post(MDOC_ARGS);
1.29 kristaps 180: static int mdoc_pp_pre(MDOC_ARGS);
181: static int mdoc_sh_pre(MDOC_ARGS);
182: static int mdoc_ss_pre(MDOC_ARGS);
1.30 kristaps 183: static int mdoc_xr_pre(MDOC_ARGS);
1.33 ! kristaps 184: static int mdoc_xx_pre(MDOC_ARGS);
! 185:
! 186: #ifdef __linux__
! 187: extern size_t strlcpy(char *, const char *, size_t);
! 188: extern size_t strlcat(char *, const char *, size_t);
! 189: #endif
1.29 kristaps 190:
191: static const struct htmlmdoc mdocs[MDOC_MAX] = {
192: {NULL, NULL}, /* Ap */
193: {NULL, NULL}, /* Dd */
194: {NULL, NULL}, /* Dt */
195: {NULL, NULL}, /* Os */
1.30 kristaps 196: {mdoc_sh_pre, NULL }, /* Sh */
197: {mdoc_ss_pre, NULL }, /* Ss */
1.29 kristaps 198: {mdoc_pp_pre, NULL}, /* Pp */
199: {NULL, NULL}, /* D1 */
200: {NULL, NULL}, /* Dl */
201: {NULL, NULL}, /* Bd */
202: {NULL, NULL}, /* Ed */
1.33 ! kristaps 203: {mdoc_bl_pre, NULL}, /* Bl */
1.29 kristaps 204: {NULL, NULL}, /* El */
1.33 ! kristaps 205: {mdoc_it_pre, NULL}, /* It */
1.29 kristaps 206: {NULL, NULL}, /* Ad */
207: {NULL, NULL}, /* An */
1.31 kristaps 208: {mdoc_ar_pre, NULL}, /* Ar */
1.29 kristaps 209: {NULL, NULL}, /* Cd */
210: {NULL, NULL}, /* Cm */
211: {NULL, NULL}, /* Dv */
212: {NULL, NULL}, /* Er */
213: {NULL, NULL}, /* Ev */
214: {NULL, NULL}, /* Ex */
215: {NULL, NULL}, /* Fa */
216: {NULL, NULL}, /* Fd */
1.30 kristaps 217: {mdoc_fl_pre, NULL}, /* Fl */
1.29 kristaps 218: {NULL, NULL}, /* Fn */
219: {NULL, NULL}, /* Ft */
220: {NULL, NULL}, /* Ic */
221: {NULL, NULL}, /* In */
222: {NULL, NULL}, /* Li */
223: {mdoc_nd_pre, NULL}, /* Nd */
1.30 kristaps 224: {mdoc_nm_pre, NULL}, /* Nm */
225: {mdoc_op_pre, mdoc_op_post}, /* Op */
1.29 kristaps 226: {NULL, NULL}, /* Ot */
227: {NULL, NULL}, /* Pa */
228: {NULL, NULL}, /* Rv */
229: {NULL, NULL}, /* St */
230: {NULL, NULL}, /* Va */
231: {NULL, NULL}, /* Vt */
1.30 kristaps 232: {mdoc_xr_pre, NULL}, /* Xr */
1.29 kristaps 233: {NULL, NULL}, /* %A */
234: {NULL, NULL}, /* %B */
235: {NULL, NULL}, /* %D */
236: {NULL, NULL}, /* %I */
237: {NULL, NULL}, /* %J */
238: {NULL, NULL}, /* %N */
239: {NULL, NULL}, /* %O */
240: {NULL, NULL}, /* %P */
241: {NULL, NULL}, /* %R */
242: {NULL, NULL}, /* %T */
243: {NULL, NULL}, /* %V */
244: {NULL, NULL}, /* Ac */
245: {NULL, NULL}, /* Ao */
246: {NULL, NULL}, /* Aq */
247: {NULL, NULL}, /* At */
248: {NULL, NULL}, /* Bc */
249: {NULL, NULL}, /* Bf */
250: {NULL, NULL}, /* Bo */
251: {NULL, NULL}, /* Bq */
1.33 ! kristaps 252: {mdoc_xx_pre, NULL}, /* Bsx */
1.29 kristaps 253: {NULL, NULL}, /* Bx */
254: {NULL, NULL}, /* Db */
255: {NULL, NULL}, /* Dc */
256: {NULL, NULL}, /* Do */
257: {NULL, NULL}, /* Dq */
258: {NULL, NULL}, /* Ec */
259: {NULL, NULL}, /* Ef */
260: {NULL, NULL}, /* Em */
261: {NULL, NULL}, /* Eo */
1.33 ! kristaps 262: {mdoc_xx_pre, NULL}, /* Fx */
1.29 kristaps 263: {NULL, NULL}, /* Ms */
264: {NULL, NULL}, /* No */
1.31 kristaps 265: {mdoc_ns_pre, NULL}, /* Ns */
1.33 ! kristaps 266: {mdoc_xx_pre, NULL}, /* Nx */
! 267: {mdoc_xx_pre, NULL}, /* Ox */
1.29 kristaps 268: {NULL, NULL}, /* Pc */
269: {NULL, NULL}, /* Pf */
270: {NULL, NULL}, /* Po */
271: {NULL, NULL}, /* Pq */
272: {NULL, NULL}, /* Qc */
273: {NULL, NULL}, /* Ql */
274: {NULL, NULL}, /* Qo */
275: {NULL, NULL}, /* Qq */
276: {NULL, NULL}, /* Re */
277: {NULL, NULL}, /* Rs */
278: {NULL, NULL}, /* Sc */
279: {NULL, NULL}, /* So */
280: {NULL, NULL}, /* Sq */
281: {NULL, NULL}, /* Sm */
282: {NULL, NULL}, /* Sx */
283: {NULL, NULL}, /* Sy */
284: {NULL, NULL}, /* Tn */
1.33 ! kristaps 285: {mdoc_xx_pre, NULL}, /* Ux */
1.29 kristaps 286: {NULL, NULL}, /* Xc */
287: {NULL, NULL}, /* Xo */
288: {NULL, NULL}, /* Fo */
289: {NULL, NULL}, /* Fc */
290: {NULL, NULL}, /* Oo */
291: {NULL, NULL}, /* Oc */
292: {NULL, NULL}, /* Bk */
293: {NULL, NULL}, /* Ek */
294: {NULL, NULL}, /* Bt */
295: {NULL, NULL}, /* Hf */
296: {NULL, NULL}, /* Fr */
297: {NULL, NULL}, /* Ud */
298: {NULL, NULL}, /* Lb */
299: {NULL, NULL}, /* Lp */
300: {NULL, NULL}, /* Lk */
301: {NULL, NULL}, /* Mt */
302: {NULL, NULL}, /* Brq */
303: {NULL, NULL}, /* Bro */
304: {NULL, NULL}, /* Brc */
305: {NULL, NULL}, /* %C */
306: {NULL, NULL}, /* Es */
307: {NULL, NULL}, /* En */
1.33 ! kristaps 308: {mdoc_xx_pre, NULL}, /* Dx */
1.29 kristaps 309: {NULL, NULL}, /* %Q */
310: {NULL, NULL}, /* br */
311: {NULL, NULL}, /* sp */
312: };
1.10 kristaps 313:
1.33 ! kristaps 314:
1.30 kristaps 315: void
1.29 kristaps 316: html_mdoc(void *arg, const struct mdoc *m)
1.10 kristaps 317: {
1.29 kristaps 318: struct html *h;
1.30 kristaps 319: struct tag *t;
1.10 kristaps 320:
1.29 kristaps 321: h = (struct html *)arg;
1.10 kristaps 322:
1.29 kristaps 323: print_gen_doctype(h);
1.30 kristaps 324: t = print_otag(h, TAG_HTML, 0, NULL);
1.29 kristaps 325: print_mdoc(mdoc_meta(m), mdoc_node(m), h);
1.30 kristaps 326: print_tagq(h, t);
327:
1.29 kristaps 328: printf("\n");
1.10 kristaps 329: }
330:
1.33 ! kristaps 331:
1.30 kristaps 332: void
1.29 kristaps 333: html_man(void *arg, const struct man *m)
1.10 kristaps 334: {
1.29 kristaps 335: struct html *h;
1.30 kristaps 336: struct tag *t;
1.10 kristaps 337:
1.29 kristaps 338: h = (struct html *)arg;
1.10 kristaps 339:
1.29 kristaps 340: print_gen_doctype(h);
1.30 kristaps 341: t = print_otag(h, TAG_HTML, 0, NULL);
1.29 kristaps 342: print_man(man_meta(m), man_node(m), h);
1.30 kristaps 343: print_tagq(h, t);
344:
1.29 kristaps 345: printf("\n");
1.10 kristaps 346: }
347:
1.33 ! kristaps 348:
1.29 kristaps 349: void *
350: html_alloc(void)
1.10 kristaps 351: {
1.30 kristaps 352: struct html *h;
353:
354: if (NULL == (h = calloc(1, sizeof(struct html))))
355: return(NULL);
1.10 kristaps 356:
1.30 kristaps 357: SLIST_INIT(&h->stack);
1.32 kristaps 358: if (NULL == (h->symtab = chars_init(CHARS_HTML))) {
359: free(h);
360: return(NULL);
361: }
1.30 kristaps 362: return(h);
1.29 kristaps 363: }
1.10 kristaps 364:
1.33 ! kristaps 365:
1.29 kristaps 366: void
367: html_free(void *p)
368: {
1.30 kristaps 369: struct tag *tag;
370: struct html *h;
371:
372: h = (struct html *)p;
1.10 kristaps 373:
1.30 kristaps 374: while ( ! SLIST_EMPTY(&h->stack)) {
375: tag = SLIST_FIRST(&h->stack);
376: SLIST_REMOVE_HEAD(&h->stack, entry);
377: free(tag);
378: }
379: free(h);
1.10 kristaps 380: }
1.2 kristaps 381:
1.33 ! kristaps 382:
1.29 kristaps 383: static void
384: print_mdoc(MDOC_ARGS)
1.4 kristaps 385: {
1.30 kristaps 386: struct tag *t;
1.4 kristaps 387:
1.30 kristaps 388: t = print_otag(h, TAG_HEAD, 0, NULL);
1.29 kristaps 389: print_mdoc_head(m, n, h);
1.30 kristaps 390: print_tagq(h, t);
391:
392: t = print_otag(h, TAG_BODY, 0, NULL);
393: print_mdoc_title(m, n, h);
1.29 kristaps 394: print_mdoc_node(m, n, h);
1.30 kristaps 395: print_tagq(h, t);
1.29 kristaps 396: }
1.4 kristaps 397:
1.33 ! kristaps 398:
1.29 kristaps 399: static void
400: print_gen_head(struct html *h)
401: {
402: struct htmlpair meta0[2];
403: struct htmlpair meta1[2];
404: struct htmlpair link[4];
405:
406: meta0[0].key = ATTR_HTTPEQUIV;
407: meta0[0].val = "Content-Type";
408: meta0[1].key = ATTR_CONTENT;
409: meta0[1].val = "text/html; charest-utf-8";
410:
411: meta1[0].key = ATTR_NAME;
412: meta1[0].val = "resource-type";
413: meta1[1].key = ATTR_CONTENT;
414: meta1[1].val = "document";
415:
416: link[0].key = ATTR_REL;
417: link[0].val = "stylesheet";
418: link[1].key = ATTR_HREF;
1.30 kristaps 419: link[1].val = "style.css"; /* XXX */
1.29 kristaps 420: link[2].key = ATTR_TYPE;
421: link[2].val = "text/css";
422: link[3].key = ATTR_MEDIA;
423: link[3].val = "all";
424:
425: print_otag(h, TAG_META, 2, meta0);
426: print_otag(h, TAG_META, 2, meta1);
427: print_otag(h, TAG_LINK, 4, link);
1.4 kristaps 428: }
429:
1.33 ! kristaps 430:
1.30 kristaps 431: /* ARGSUSED */
1.29 kristaps 432: static void
433: print_mdoc_head(MDOC_ARGS)
1.18 kristaps 434: {
435:
1.29 kristaps 436: print_gen_head(h);
437: print_otag(h, TAG_TITLE, 0, NULL);
1.32 kristaps 438: print_encode(h, m->title);
1.2 kristaps 439: }
440:
1.33 ! kristaps 441:
1.30 kristaps 442: /* ARGSUSED */
1.29 kristaps 443: static void
1.30 kristaps 444: print_mdoc_title(MDOC_ARGS)
1.2 kristaps 445: {
446:
1.30 kristaps 447: /* TODO */
1.2 kristaps 448: }
449:
1.33 ! kristaps 450:
1.29 kristaps 451: static void
452: print_mdoc_node(MDOC_ARGS)
1.2 kristaps 453: {
1.29 kristaps 454: int child;
1.30 kristaps 455: struct tag *t;
1.8 kristaps 456:
1.29 kristaps 457: child = 1;
1.30 kristaps 458: t = SLIST_FIRST(&h->stack);
1.8 kristaps 459:
1.29 kristaps 460: switch (n->type) {
461: case (MDOC_ROOT):
462: child = mdoc_root_pre(m, n, h);
1.7 kristaps 463: break;
1.29 kristaps 464: case (MDOC_TEXT):
465: print_text(h, n->string);
1.7 kristaps 466: break;
1.3 kristaps 467: default:
1.29 kristaps 468: if (mdocs[n->tok].pre)
469: child = (*mdocs[n->tok].pre)(m, n, h);
1.3 kristaps 470: break;
1.2 kristaps 471: }
472:
1.29 kristaps 473: if (child && n->child)
474: print_mdoc_node(m, n->child, h);
1.8 kristaps 475:
1.30 kristaps 476: print_stagq(h, t);
477:
1.29 kristaps 478: switch (n->type) {
479: case (MDOC_ROOT):
1.7 kristaps 480: break;
1.29 kristaps 481: case (MDOC_TEXT):
1.7 kristaps 482: break;
1.3 kristaps 483: default:
1.29 kristaps 484: if (mdocs[n->tok].post)
485: (*mdocs[n->tok].post)(m, n, h);
1.3 kristaps 486: break;
487: }
1.2 kristaps 488:
1.29 kristaps 489: if (n->next)
490: print_mdoc_node(m, n->next, h);
1.2 kristaps 491: }
492:
1.33 ! kristaps 493:
1.29 kristaps 494: static void
495: print_man(MAN_ARGS)
1.9 kristaps 496: {
1.30 kristaps 497: struct tag *t;
1.9 kristaps 498:
1.30 kristaps 499: t = print_otag(h, TAG_HEAD, 0, NULL);
1.29 kristaps 500: print_man_head(m, n, h);
1.30 kristaps 501: print_tagq(h, t);
502:
503: t = print_otag(h, TAG_BODY, 0, NULL);
1.29 kristaps 504: print_man_body(m, n, h);
1.30 kristaps 505: print_tagq(h, t);
1.9 kristaps 506: }
507:
1.33 ! kristaps 508:
1.30 kristaps 509: /* ARGSUSED */
1.9 kristaps 510: static void
1.29 kristaps 511: print_man_head(MAN_ARGS)
1.9 kristaps 512: {
513:
1.29 kristaps 514: print_gen_head(h);
515: print_otag(h, TAG_TITLE, 0, NULL);
1.32 kristaps 516: print_encode(h, m->title);
1.29 kristaps 517: }
1.9 kristaps 518:
1.33 ! kristaps 519:
1.30 kristaps 520: /* ARGSUSED */
1.29 kristaps 521: static void
522: print_man_body(MAN_ARGS)
523: {
1.30 kristaps 524:
525: /* TODO */
1.9 kristaps 526: }
527:
1.33 ! kristaps 528:
1.32 kristaps 529: static void
530: print_spec(struct html *h, const char *p, int len)
531: {
532: const char *rhs;
533: int i;
534: size_t sz;
535:
536: rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz);
537:
538: if (NULL == rhs)
539: return;
540: for (i = 0; i < (int)sz; i++)
541: putchar(rhs[i]);
542: }
543:
1.33 ! kristaps 544:
1.32 kristaps 545: static void
546: print_res(struct html *h, const char *p, int len)
547: {
548: const char *rhs;
549: int i;
550: size_t sz;
551:
552: rhs = chars_a2res(h->symtab, p, (size_t)len, &sz);
553:
554: if (NULL == rhs)
555: return;
556: for (i = 0; i < (int)sz; i++)
557: putchar(rhs[i]);
558: }
559:
1.33 ! kristaps 560:
1.32 kristaps 561: static void
562: print_escape(struct html *h, const char **p)
563: {
564: int j, type;
565: const char *wp;
566:
567: wp = *p;
568: type = 1;
569:
570: if (0 == *(++wp)) {
571: *p = wp;
572: return;
573: }
574:
575: if ('(' == *wp) {
576: wp++;
577: if (0 == *wp || 0 == *(wp + 1)) {
578: *p = 0 == *wp ? wp : wp + 1;
579: return;
580: }
581:
582: print_spec(h, wp, 2);
583: *p = ++wp;
584: return;
585:
586: } else if ('*' == *wp) {
587: if (0 == *(++wp)) {
588: *p = wp;
589: return;
590: }
591:
592: switch (*wp) {
593: case ('('):
594: wp++;
595: if (0 == *wp || 0 == *(wp + 1)) {
596: *p = 0 == *wp ? wp : wp + 1;
597: return;
598: }
599:
600: print_res(h, wp, 2);
601: *p = ++wp;
602: return;
603: case ('['):
604: type = 0;
605: break;
606: default:
607: print_res(h, wp, 1);
608: *p = wp;
609: return;
610: }
611:
612: } else if ('f' == *wp) {
613: if (0 == *(++wp)) {
614: *p = wp;
615: return;
616: }
617:
618: switch (*wp) {
619: case ('B'):
620: /* TODO */
621: break;
622: case ('I'):
623: /* TODO */
624: break;
625: case ('P'):
626: /* FALLTHROUGH */
627: case ('R'):
628: /* TODO */
629: break;
630: default:
631: break;
632: }
633:
634: *p = wp;
635: return;
636:
637: } else if ('[' != *wp) {
638: print_spec(h, wp, 1);
639: *p = wp;
640: return;
641: }
642:
643: wp++;
644: for (j = 0; *wp && ']' != *wp; wp++, j++)
645: /* Loop... */ ;
646:
647: if (0 == *wp) {
648: *p = wp;
649: return;
650: }
651:
652: if (type)
653: print_spec(h, wp - j, j);
654: else
655: print_res(h, wp - j, j);
656:
657: *p = wp;
658: }
659:
1.9 kristaps 660:
1.29 kristaps 661: static void
1.32 kristaps 662: print_encode(struct html *h, const char *p)
1.29 kristaps 663: {
1.14 kristaps 664:
1.32 kristaps 665: for (; *p; p++) {
666: if ('\\' != *p) {
667: putchar(*p);
668: continue;
669: }
670: print_escape(h, &p);
671: }
1.14 kristaps 672: }
673:
674:
1.30 kristaps 675: static struct tag *
1.29 kristaps 676: print_otag(struct html *h, enum htmltag tag,
677: int sz, const struct htmlpair *p)
1.14 kristaps 678: {
1.29 kristaps 679: int i;
1.30 kristaps 680: struct tag *t;
681:
682: if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
683: if (NULL == (t = malloc(sizeof(struct tag))))
684: err(EXIT_FAILURE, "malloc");
685: t->tag = tag;
686: SLIST_INSERT_HEAD(&h->stack, t, entry);
687: } else
688: t = NULL;
1.29 kristaps 689:
690: if ( ! (HTML_NOSPACE & h->flags))
1.30 kristaps 691: if ( ! (HTML_CLRLINE & htmltags[tag].flags))
1.29 kristaps 692: printf(" ");
693:
694: printf("<%s", htmltags[tag].name);
695: for (i = 0; i < sz; i++) {
696: printf(" %s=\"", htmlattrs[p[i].key]);
697: assert(p->val);
1.32 kristaps 698: print_encode(h, p[i].val);
1.29 kristaps 699: printf("\"");
700: }
701: printf(">");
1.14 kristaps 702:
1.29 kristaps 703: h->flags |= HTML_NOSPACE;
1.30 kristaps 704: if (HTML_CLRLINE & htmltags[tag].flags)
705: h->flags |= HTML_NEWLINE;
706: else
707: h->flags &= ~HTML_NEWLINE;
1.14 kristaps 708:
1.30 kristaps 709: return(t);
1.14 kristaps 710: }
711:
712:
713: /* ARGSUSED */
1.29 kristaps 714: static void
715: print_ctag(struct html *h, enum htmltag tag)
1.14 kristaps 716: {
717:
1.29 kristaps 718: printf("</%s>", htmltags[tag].name);
1.30 kristaps 719: if (HTML_CLRLINE & htmltags[tag].flags)
1.29 kristaps 720: h->flags |= HTML_NOSPACE;
1.30 kristaps 721: if (HTML_CLRLINE & htmltags[tag].flags)
722: h->flags |= HTML_NEWLINE;
723: else
724: h->flags &= ~HTML_NEWLINE;
1.14 kristaps 725: }
726:
727:
1.29 kristaps 728: /* ARGSUSED */
729: static void
730: print_gen_doctype(struct html *h)
1.1 kristaps 731: {
1.29 kristaps 732:
733: printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n", DOCTYPE, DTD);
1.1 kristaps 734: }
735:
736:
1.29 kristaps 737: static void
738: print_text(struct html *h, const char *p)
1.1 kristaps 739: {
740:
1.29 kristaps 741: if (*p && 0 == *(p + 1))
742: switch (*p) {
743: case('.'):
744: /* FALLTHROUGH */
745: case(','):
746: /* FALLTHROUGH */
747: case(';'):
748: /* FALLTHROUGH */
749: case(':'):
750: /* FALLTHROUGH */
751: case('?'):
752: /* FALLTHROUGH */
753: case('!'):
754: /* FALLTHROUGH */
755: case(')'):
756: /* FALLTHROUGH */
757: case(']'):
758: /* FALLTHROUGH */
759: case('}'):
760: h->flags |= HTML_NOSPACE;
1.30 kristaps 761: break;
1.29 kristaps 762: default:
763: break;
764: }
1.1 kristaps 765:
1.29 kristaps 766: if ( ! (h->flags & HTML_NOSPACE))
767: printf(" ");
1.30 kristaps 768:
1.29 kristaps 769: h->flags &= ~HTML_NOSPACE;
1.30 kristaps 770: h->flags &= ~HTML_NEWLINE;
1.1 kristaps 771:
1.29 kristaps 772: if (p)
1.32 kristaps 773: print_encode(h, p);
1.8 kristaps 774:
1.29 kristaps 775: if (*p && 0 == *(p + 1))
776: switch (*p) {
777: case('('):
778: /* FALLTHROUGH */
779: case('['):
780: /* FALLTHROUGH */
781: case('{'):
782: h->flags |= HTML_NOSPACE;
1.30 kristaps 783: break;
1.29 kristaps 784: default:
785: break;
786: }
1.1 kristaps 787: }
1.30 kristaps 788:
789:
790: static void
791: print_tagq(struct html *h, const struct tag *until)
792: {
793: struct tag *tag;
794:
795: while ( ! SLIST_EMPTY(&h->stack)) {
796: tag = SLIST_FIRST(&h->stack);
797: print_ctag(h, tag->tag);
798: SLIST_REMOVE_HEAD(&h->stack, entry);
799: free(tag);
800: if (until && tag == until)
801: return;
802: }
803: }
804:
805:
806: static void
807: print_stagq(struct html *h, const struct tag *suntil)
808: {
809: struct tag *tag;
810:
811: while ( ! SLIST_EMPTY(&h->stack)) {
812: tag = SLIST_FIRST(&h->stack);
813: if (suntil && tag == suntil)
814: return;
815: print_ctag(h, tag->tag);
816: SLIST_REMOVE_HEAD(&h->stack, entry);
817: free(tag);
818: }
819: }
820:
821:
1.33 ! kristaps 822: static int
! 823: a2offs(const char *p)
! 824: {
! 825: int len, i;
! 826:
! 827: if (0 == strcmp(p, "left"))
! 828: return(0);
! 829: if (0 == strcmp(p, "indent"))
! 830: return(INDENT + 1);
! 831: if (0 == strcmp(p, "indent-two"))
! 832: return((INDENT + 1) * 2);
! 833:
! 834: if (0 == (len = (int)strlen(p)))
! 835: return(0);
! 836:
! 837: for (i = 0; i < len - 1; i++)
! 838: if ( ! isdigit((u_char)p[i]))
! 839: break;
! 840:
! 841: if (i == len - 1)
! 842: if ('n' == p[len - 1] || 'm' == p[len - 1])
! 843: return(atoi(p));
! 844:
! 845: return(len);
! 846: }
! 847:
! 848:
! 849: static int
! 850: a2width(const char *p)
! 851: {
! 852: int i, len;
! 853:
! 854: if (0 == (len = (int)strlen(p)))
! 855: return(0);
! 856: for (i = 0; i < len - 1; i++)
! 857: if ( ! isdigit((u_char)p[i]))
! 858: break;
! 859:
! 860: if (i == len - 1)
! 861: if ('n' == p[len - 1] || 'm' == p[len - 1])
! 862: return(atoi(p) + 2);
! 863:
! 864: return(len + 2);
! 865: }
! 866:
! 867:
! 868:
! 869:
1.30 kristaps 870: /* ARGSUSED */
871: static int
872: mdoc_root_pre(MDOC_ARGS)
873: {
874: struct htmlpair tag;
875:
876: tag.key = ATTR_CLASS;
877: tag.val = "body";
878:
879: print_otag(h, TAG_DIV, 1, &tag);
880: return(1);
881: }
882:
883:
884: /* ARGSUSED */
885: static int
886: mdoc_ss_pre(MDOC_ARGS)
887: {
888:
889: if (MDOC_BODY == n->type)
1.33 ! kristaps 890: print_otag(h, TAG_DIV, 0, NULL);
1.30 kristaps 891: if (MDOC_HEAD == n->type)
892: print_otag(h, TAG_H2, 0, NULL);
893: return(1);
894: }
895:
896:
897: /* ARGSUSED */
898: static int
899: mdoc_fl_pre(MDOC_ARGS)
900: {
901: struct htmlpair tag;
902:
903: tag.key = ATTR_CLASS;
904: tag.val = "flag";
905:
906: print_otag(h, TAG_SPAN, 1, &tag);
907: print_text(h, "\\-");
908: h->flags |= HTML_NOSPACE;
909: return(1);
910: }
911:
912:
913: /* ARGSUSED */
914: static int
915: mdoc_pp_pre(MDOC_ARGS)
916: {
917:
918: print_otag(h, TAG_BR, 0, NULL);
919: print_otag(h, TAG_BR, 0, NULL);
920: return(0);
921: }
922:
923:
924: /* ARGSUSED */
925: static int
926: mdoc_nd_pre(MDOC_ARGS)
927: {
928:
929: if (MDOC_BODY == n->type)
1.31 kristaps 930: print_text(h, "\\(en");
1.30 kristaps 931: return(1);
932: }
933:
934:
935: /* ARGSUSED */
936: static int
937: mdoc_op_pre(MDOC_ARGS)
938: {
939:
940: if (MDOC_BODY == n->type) {
941: print_text(h, "\\(lB");
942: h->flags |= HTML_NOSPACE;
943: }
944: return(1);
945: }
946:
947:
948: /* ARGSUSED */
949: static void
950: mdoc_op_post(MDOC_ARGS)
951: {
952:
953: if (MDOC_BODY != n->type)
954: return;
955: h->flags |= HTML_NOSPACE;
956: print_text(h, "\\(rB");
957: }
958:
959:
960: static int
961: mdoc_nm_pre(MDOC_ARGS)
962: {
963: struct htmlpair class;
964:
965: if ( ! (HTML_NEWLINE & h->flags))
966: if (SEC_SYNOPSIS == n->sec)
967: print_otag(h, TAG_BR, 0, NULL);
968:
969: class.key = ATTR_CLASS;
970: class.val = "name";
971:
972: print_otag(h, TAG_SPAN, 1, &class);
973: if (NULL == n->child)
974: print_text(h, m->name);
975:
976: return(1);
977: }
978:
979:
980: /* ARGSUSED */
981: static int
982: mdoc_sh_pre(MDOC_ARGS)
983: {
984:
985: if (MDOC_BODY == n->type)
1.33 ! kristaps 986: print_otag(h, TAG_DIV, 0, NULL);
1.30 kristaps 987: if (MDOC_HEAD == n->type)
988: print_otag(h, TAG_H1, 0, NULL);
989: return(1);
990: }
991:
992:
993: /* ARGSUSED */
994: static int
995: mdoc_xr_pre(MDOC_ARGS)
996: {
997: struct htmlpair tag;
998:
999: tag.key = ATTR_HREF;
1000: tag.val = "#"; /* TODO */
1001:
1002: print_otag(h, TAG_A, 1, &tag);
1003:
1004: n = n->child;
1005: print_text(h, n->string);
1006: if (NULL == (n = n->next))
1007: return(0);
1008:
1009: h->flags |= HTML_NOSPACE;
1010: print_text(h, "(");
1011: h->flags |= HTML_NOSPACE;
1012: print_text(h, n->string);
1013: h->flags |= HTML_NOSPACE;
1014: print_text(h, ")");
1015:
1016: return(0);
1017: }
1.31 kristaps 1018:
1019:
1020: /* ARGSUSED */
1021: static int
1022: mdoc_ns_pre(MDOC_ARGS)
1023: {
1024:
1025: h->flags |= HTML_NOSPACE;
1026: return(1);
1027: }
1028:
1029: /* ARGSUSED */
1030: static int
1031: mdoc_ar_pre(MDOC_ARGS)
1032: {
1033: struct htmlpair tag;
1034:
1035: tag.key = ATTR_CLASS;
1036: tag.val = "arg";
1037:
1038: print_otag(h, TAG_SPAN, 1, &tag);
1039: return(1);
1040: }
1.33 ! kristaps 1041:
! 1042: /* ARGSUSED */
! 1043: static int
! 1044: mdoc_xx_pre(MDOC_ARGS)
! 1045: {
! 1046: const char *pp;
! 1047:
! 1048: switch (n->tok) {
! 1049: case (MDOC_Bsx):
! 1050: pp = "BSDI BSD/OS";
! 1051: break;
! 1052: case (MDOC_Dx):
! 1053: pp = "DragonFlyBSD";
! 1054: break;
! 1055: case (MDOC_Fx):
! 1056: pp = "FreeBSD";
! 1057: break;
! 1058: case (MDOC_Nx):
! 1059: pp = "NetBSD";
! 1060: break;
! 1061: case (MDOC_Ox):
! 1062: pp = "OpenBSD";
! 1063: break;
! 1064: case (MDOC_Ux):
! 1065: pp = "UNIX";
! 1066: break;
! 1067: default:
! 1068: return(1);
! 1069: }
! 1070:
! 1071: print_text(h, pp);
! 1072: return(1);
! 1073: }
! 1074:
! 1075:
! 1076: static int
! 1077: mdoc_hang_pre(MDOC_ARGS)
! 1078: {
! 1079: int i, width, offs;
! 1080: struct htmlpair tag;
! 1081: char buf[BUFSIZ];
! 1082: const struct mdoc_node *bl;
! 1083:
! 1084: if (MDOC_BODY == n->type) {
! 1085: print_otag(h, TAG_DIV, 0, NULL);
! 1086: return(1);
! 1087: }
! 1088:
! 1089: bl = n->parent->parent;
! 1090: if (MDOC_BLOCK != n->type)
! 1091: bl = bl->parent;
! 1092:
! 1093: assert(bl->args);
! 1094:
! 1095: for (width = i = 0; i < (int)bl->args->argc; i++)
! 1096: if (MDOC_Width == bl->args->argv[i].arg) {
! 1097: assert(bl->args->argv[i].sz);
! 1098: width = a2width(bl->args->argv[i].value[0]);
! 1099: break;
! 1100: } else if (MDOC_Offset == bl->args->argv[i].arg) {
! 1101: assert(bl->args->argv[i].sz);
! 1102: offs = a2offs(bl->args->argv[i].value[0]);
! 1103: break;
! 1104: }
! 1105:
! 1106: if (0 == width)
! 1107: width = 10;
! 1108:
! 1109: width *= 10;
! 1110:
! 1111: if (MDOC_BLOCK == n->type)
! 1112: snprintf(buf, BUFSIZ - 1, "margin-left: %dpx; "
! 1113: "clear: both;", width);
! 1114: else
! 1115: snprintf(buf, BUFSIZ - 1, "float: left; "
! 1116: "margin-left: -%dpx;", width);
! 1117:
! 1118: tag.key = ATTR_STYLE;
! 1119: tag.val = buf;
! 1120:
! 1121: print_otag(h, TAG_DIV, 1, &tag);
! 1122:
! 1123: return(1);
! 1124: }
! 1125:
! 1126:
! 1127: static int
! 1128: mdoc_list_pre(MDOC_ARGS)
! 1129: {
! 1130:
! 1131: /* TODO */
! 1132: return(0);
! 1133: }
! 1134:
! 1135:
! 1136: static int
! 1137: mdoc_it_pre(MDOC_ARGS)
! 1138: {
! 1139: int i, len;
! 1140: const struct mdoc_node *bl;
! 1141:
! 1142: if (MDOC_BLOCK == n->type)
! 1143: bl = n->parent->parent;
! 1144: else
! 1145: bl = n->parent->parent->parent;
! 1146:
! 1147: assert(bl->args);
! 1148: len = (int)bl->args->argc;
! 1149:
! 1150: for (i = 0; i < len; i++)
! 1151: switch (bl->args->argv[i].arg) {
! 1152: case (MDOC_Bullet):
! 1153: /* FALLTHROUGH */
! 1154: case (MDOC_Dash):
! 1155: /* FALLTHROUGH */
! 1156: case (MDOC_Enum):
! 1157: /* FALLTHROUGH */
! 1158: case (MDOC_Hyphen):
! 1159: return(0); /* TODO */
! 1160: case (MDOC_Tag):
! 1161: return(0);
! 1162: case (MDOC_Inset):
! 1163: /* FALLTHROUGH */
! 1164: case (MDOC_Diag):
! 1165: /* FALLTHROUGH */
! 1166: case (MDOC_Item):
! 1167: /* FALLTHROUGH */
! 1168: case (MDOC_Column):
! 1169: /* FALLTHROUGH */
! 1170: case (MDOC_Hang):
! 1171: return(mdoc_hang_pre(m, n, h));
! 1172: /* FALLTHROUGH */
! 1173: case (MDOC_Ohang):
! 1174: return(0); /* TODO */
! 1175: default:
! 1176: abort();
! 1177: /* NOTREACHED */
! 1178: }
! 1179:
! 1180: abort();
! 1181: /* NOTREACHED */
! 1182: }
! 1183:
! 1184:
! 1185: static int
! 1186: mdoc_bl_pre(MDOC_ARGS)
! 1187: {
! 1188: int i, len;
! 1189:
! 1190: if (MDOC_BLOCK != n->type)
! 1191: return(1);
! 1192:
! 1193: assert(n->args);
! 1194: len = (int)n->args->argc;
! 1195:
! 1196: for (i = 0; i < len; i++)
! 1197: switch (n->args->argv[i].arg) {
! 1198: case (MDOC_Bullet):
! 1199: /* FALLTHROUGH */
! 1200: case (MDOC_Dash):
! 1201: /* FALLTHROUGH */
! 1202: case (MDOC_Enum):
! 1203: /* FALLTHROUGH */
! 1204: case (MDOC_Hyphen):
! 1205: return(mdoc_list_pre(m, n, h));
! 1206: case (MDOC_Tag):
! 1207: return(0);
! 1208: case (MDOC_Inset):
! 1209: /* FALLTHROUGH */
! 1210: case (MDOC_Diag):
! 1211: /* FALLTHROUGH */
! 1212: case (MDOC_Item):
! 1213: /* FALLTHROUGH */
! 1214: case (MDOC_Column):
! 1215: /* FALLTHROUGH */
! 1216: case (MDOC_Hang):
! 1217: return(1);
! 1218: case (MDOC_Ohang):
! 1219: return(0); /* TODO */
! 1220: default:
! 1221: abort();
! 1222: /* NOTREACHED */
! 1223: }
! 1224:
! 1225: abort();
! 1226: /* NOTREACHED */
! 1227: }
CVSweb