Annotation of mandoc/html.c, Revision 1.32
1.32 ! kristaps 1: /* $Id: html.c,v 1.31 2009/09/17 07:41:28 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.4 kristaps 20: #include <err.h>
1.29 kristaps 21: #include <stdio.h>
1.1 kristaps 22: #include <stdlib.h>
23:
1.32 ! kristaps 24: #include "chars.h"
1.29 kristaps 25: #include "mdoc.h"
26: #include "man.h"
1.2 kristaps 27:
1.29 kristaps 28: #define DOCTYPE "-//W3C//DTD HTML 4.01//EN"
29: #define DTD "http://www.w3.org/TR/html4/strict.dtd"
1.8 kristaps 30:
1.29 kristaps 31: enum htmltag {
32: TAG_HTML,
33: TAG_HEAD,
34: TAG_BODY,
35: TAG_META,
36: TAG_TITLE,
37: TAG_DIV,
38: TAG_H1,
39: TAG_H2,
40: TAG_P,
41: TAG_SPAN,
42: TAG_LINK,
1.30 kristaps 43: TAG_BR,
44: TAG_A,
1.29 kristaps 45: TAG_MAX
1.7 kristaps 46: };
47:
1.29 kristaps 48: enum htmlattr {
49: ATTR_HTTPEQUIV,
50: ATTR_CONTENT,
51: ATTR_NAME,
52: ATTR_REL,
53: ATTR_HREF,
54: ATTR_TYPE,
55: ATTR_MEDIA,
56: ATTR_CLASS,
57: ATTR_MAX
1.7 kristaps 58: };
59:
1.29 kristaps 60: struct htmldata {
61: char *name;
62: int flags;
1.30 kristaps 63: #define HTML_CLRLINE (1 << 0)
64: #define HTML_NOSTACK (1 << 1)
1.29 kristaps 65: };
1.7 kristaps 66:
1.29 kristaps 67: static const struct htmldata htmltags[TAG_MAX] = {
1.30 kristaps 68: {"html", HTML_CLRLINE}, /* TAG_HTML */
69: {"head", HTML_CLRLINE}, /* TAG_HEAD */
70: {"body", HTML_CLRLINE}, /* TAG_BODY */
71: {"meta", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */
72: {"title", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_TITLE */
73: {"div", HTML_CLRLINE}, /* TAG_DIV */
1.29 kristaps 74: {"h1", 0}, /* TAG_H1 */
75: {"h2", 0}, /* TAG_H2 */
1.30 kristaps 76: {"p", HTML_CLRLINE}, /* TAG_P */
1.29 kristaps 77: {"span", 0}, /* TAG_SPAN */
1.30 kristaps 78: {"link", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
79: {"br", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
80: {"a", 0}, /* TAG_A */
1.29 kristaps 81: };
1.10 kristaps 82:
1.29 kristaps 83: static const char *const htmlattrs[ATTR_MAX] = {
84: "http-equiv",
85: "content",
86: "name",
87: "rel",
88: "href",
89: "type",
90: "media",
91: "class"
92: };
1.10 kristaps 93:
1.29 kristaps 94: struct htmlpair {
95: enum htmlattr key;
96: char *val;
97: };
1.10 kristaps 98:
1.30 kristaps 99: struct tag {
100: enum htmltag tag;
101: SLIST_ENTRY(tag) entry;
102: };
103:
104: SLIST_HEAD(tagq, tag);
105:
1.29 kristaps 106: struct html {
107: int flags;
108: #define HTML_NOSPACE (1 << 0)
1.30 kristaps 109: #define HTML_NEWLINE (1 << 1)
110: struct tagq stack;
1.32 ! kristaps 111: void *symtab;
1.29 kristaps 112: };
1.10 kristaps 113:
1.29 kristaps 114: #define MDOC_ARGS const struct mdoc_meta *m, \
115: const struct mdoc_node *n, \
116: struct html *h
117: #define MAN_ARGS const struct man_meta *m, \
118: const struct man_node *n, \
119: struct html *h
120: struct htmlmdoc {
121: int (*pre)(MDOC_ARGS);
122: void (*post)(MDOC_ARGS);
123: };
1.13 kristaps 124:
1.29 kristaps 125: static void print_gen_doctype(struct html *);
126: static void print_gen_head(struct html *);
127: static void print_mdoc(MDOC_ARGS);
128: static void print_mdoc_head(MDOC_ARGS);
1.30 kristaps 129: static void print_mdoc_title(MDOC_ARGS);
1.29 kristaps 130: static void print_mdoc_node(MDOC_ARGS);
131: static void print_man(MAN_ARGS);
132: static void print_man_head(MAN_ARGS);
133: static void print_man_body(MAN_ARGS);
1.30 kristaps 134: static struct tag *print_otag(struct html *, enum htmltag,
1.29 kristaps 135: int, const struct htmlpair *);
1.30 kristaps 136: static void print_tagq(struct html *, const struct tag *);
137: static void print_stagq(struct html *, const struct tag *);
1.29 kristaps 138: static void print_ctag(struct html *, enum htmltag);
1.32 ! kristaps 139: static void print_encode(struct html *, const char *);
! 140: static void print_escape(struct html *, const char **);
1.29 kristaps 141: static void print_text(struct html *, const char *);
1.32 ! kristaps 142: static void print_res(struct html *, const char *, int);
! 143: static void print_spec(struct html *, const char *, int);
1.29 kristaps 144: static int mdoc_root_pre(MDOC_ARGS);
145:
1.31 kristaps 146: static int mdoc_ar_pre(MDOC_ARGS);
1.30 kristaps 147: static int mdoc_fl_pre(MDOC_ARGS);
1.29 kristaps 148: static int mdoc_nd_pre(MDOC_ARGS);
149: static int mdoc_nm_pre(MDOC_ARGS);
1.31 kristaps 150: static int mdoc_ns_pre(MDOC_ARGS);
1.30 kristaps 151: static int mdoc_op_pre(MDOC_ARGS);
152: static void mdoc_op_post(MDOC_ARGS);
1.29 kristaps 153: static int mdoc_pp_pre(MDOC_ARGS);
154: static int mdoc_sh_pre(MDOC_ARGS);
155: static int mdoc_ss_pre(MDOC_ARGS);
1.30 kristaps 156: static int mdoc_xr_pre(MDOC_ARGS);
1.29 kristaps 157:
158: static const struct htmlmdoc mdocs[MDOC_MAX] = {
159: {NULL, NULL}, /* Ap */
160: {NULL, NULL}, /* Dd */
161: {NULL, NULL}, /* Dt */
162: {NULL, NULL}, /* Os */
1.30 kristaps 163: {mdoc_sh_pre, NULL }, /* Sh */
164: {mdoc_ss_pre, NULL }, /* Ss */
1.29 kristaps 165: {mdoc_pp_pre, NULL}, /* Pp */
166: {NULL, NULL}, /* D1 */
167: {NULL, NULL}, /* Dl */
168: {NULL, NULL}, /* Bd */
169: {NULL, NULL}, /* Ed */
170: {NULL, NULL}, /* Bl */
171: {NULL, NULL}, /* El */
172: {NULL, NULL}, /* It */
173: {NULL, NULL}, /* Ad */
174: {NULL, NULL}, /* An */
1.31 kristaps 175: {mdoc_ar_pre, NULL}, /* Ar */
1.29 kristaps 176: {NULL, NULL}, /* Cd */
177: {NULL, NULL}, /* Cm */
178: {NULL, NULL}, /* Dv */
179: {NULL, NULL}, /* Er */
180: {NULL, NULL}, /* Ev */
181: {NULL, NULL}, /* Ex */
182: {NULL, NULL}, /* Fa */
183: {NULL, NULL}, /* Fd */
1.30 kristaps 184: {mdoc_fl_pre, NULL}, /* Fl */
1.29 kristaps 185: {NULL, NULL}, /* Fn */
186: {NULL, NULL}, /* Ft */
187: {NULL, NULL}, /* Ic */
188: {NULL, NULL}, /* In */
189: {NULL, NULL}, /* Li */
190: {mdoc_nd_pre, NULL}, /* Nd */
1.30 kristaps 191: {mdoc_nm_pre, NULL}, /* Nm */
192: {mdoc_op_pre, mdoc_op_post}, /* Op */
1.29 kristaps 193: {NULL, NULL}, /* Ot */
194: {NULL, NULL}, /* Pa */
195: {NULL, NULL}, /* Rv */
196: {NULL, NULL}, /* St */
197: {NULL, NULL}, /* Va */
198: {NULL, NULL}, /* Vt */
1.30 kristaps 199: {mdoc_xr_pre, NULL}, /* Xr */
1.29 kristaps 200: {NULL, NULL}, /* %A */
201: {NULL, NULL}, /* %B */
202: {NULL, NULL}, /* %D */
203: {NULL, NULL}, /* %I */
204: {NULL, NULL}, /* %J */
205: {NULL, NULL}, /* %N */
206: {NULL, NULL}, /* %O */
207: {NULL, NULL}, /* %P */
208: {NULL, NULL}, /* %R */
209: {NULL, NULL}, /* %T */
210: {NULL, NULL}, /* %V */
211: {NULL, NULL}, /* Ac */
212: {NULL, NULL}, /* Ao */
213: {NULL, NULL}, /* Aq */
214: {NULL, NULL}, /* At */
215: {NULL, NULL}, /* Bc */
216: {NULL, NULL}, /* Bf */
217: {NULL, NULL}, /* Bo */
218: {NULL, NULL}, /* Bq */
219: {NULL, NULL}, /* Bsx */
220: {NULL, NULL}, /* Bx */
221: {NULL, NULL}, /* Db */
222: {NULL, NULL}, /* Dc */
223: {NULL, NULL}, /* Do */
224: {NULL, NULL}, /* Dq */
225: {NULL, NULL}, /* Ec */
226: {NULL, NULL}, /* Ef */
227: {NULL, NULL}, /* Em */
228: {NULL, NULL}, /* Eo */
229: {NULL, NULL}, /* Fx */
230: {NULL, NULL}, /* Ms */
231: {NULL, NULL}, /* No */
1.31 kristaps 232: {mdoc_ns_pre, NULL}, /* Ns */
1.29 kristaps 233: {NULL, NULL}, /* Nx */
234: {NULL, NULL}, /* Ox */
235: {NULL, NULL}, /* Pc */
236: {NULL, NULL}, /* Pf */
237: {NULL, NULL}, /* Po */
238: {NULL, NULL}, /* Pq */
239: {NULL, NULL}, /* Qc */
240: {NULL, NULL}, /* Ql */
241: {NULL, NULL}, /* Qo */
242: {NULL, NULL}, /* Qq */
243: {NULL, NULL}, /* Re */
244: {NULL, NULL}, /* Rs */
245: {NULL, NULL}, /* Sc */
246: {NULL, NULL}, /* So */
247: {NULL, NULL}, /* Sq */
248: {NULL, NULL}, /* Sm */
249: {NULL, NULL}, /* Sx */
250: {NULL, NULL}, /* Sy */
251: {NULL, NULL}, /* Tn */
252: {NULL, NULL}, /* Ux */
253: {NULL, NULL}, /* Xc */
254: {NULL, NULL}, /* Xo */
255: {NULL, NULL}, /* Fo */
256: {NULL, NULL}, /* Fc */
257: {NULL, NULL}, /* Oo */
258: {NULL, NULL}, /* Oc */
259: {NULL, NULL}, /* Bk */
260: {NULL, NULL}, /* Ek */
261: {NULL, NULL}, /* Bt */
262: {NULL, NULL}, /* Hf */
263: {NULL, NULL}, /* Fr */
264: {NULL, NULL}, /* Ud */
265: {NULL, NULL}, /* Lb */
266: {NULL, NULL}, /* Lp */
267: {NULL, NULL}, /* Lk */
268: {NULL, NULL}, /* Mt */
269: {NULL, NULL}, /* Brq */
270: {NULL, NULL}, /* Bro */
271: {NULL, NULL}, /* Brc */
272: {NULL, NULL}, /* %C */
273: {NULL, NULL}, /* Es */
274: {NULL, NULL}, /* En */
275: {NULL, NULL}, /* Dx */
276: {NULL, NULL}, /* %Q */
277: {NULL, NULL}, /* br */
278: {NULL, NULL}, /* sp */
279: };
1.10 kristaps 280:
1.30 kristaps 281: void
1.29 kristaps 282: html_mdoc(void *arg, const struct mdoc *m)
1.10 kristaps 283: {
1.29 kristaps 284: struct html *h;
1.30 kristaps 285: struct tag *t;
1.10 kristaps 286:
1.29 kristaps 287: h = (struct html *)arg;
1.10 kristaps 288:
1.29 kristaps 289: print_gen_doctype(h);
1.30 kristaps 290: t = print_otag(h, TAG_HTML, 0, NULL);
1.29 kristaps 291: print_mdoc(mdoc_meta(m), mdoc_node(m), h);
1.30 kristaps 292: print_tagq(h, t);
293:
1.29 kristaps 294: printf("\n");
1.10 kristaps 295: }
296:
1.30 kristaps 297: void
1.29 kristaps 298: html_man(void *arg, const struct man *m)
1.10 kristaps 299: {
1.29 kristaps 300: struct html *h;
1.30 kristaps 301: struct tag *t;
1.10 kristaps 302:
1.29 kristaps 303: h = (struct html *)arg;
1.10 kristaps 304:
1.29 kristaps 305: print_gen_doctype(h);
1.30 kristaps 306: t = print_otag(h, TAG_HTML, 0, NULL);
1.29 kristaps 307: print_man(man_meta(m), man_node(m), h);
1.30 kristaps 308: print_tagq(h, t);
309:
1.29 kristaps 310: printf("\n");
1.10 kristaps 311: }
312:
1.29 kristaps 313: void *
314: html_alloc(void)
1.10 kristaps 315: {
1.30 kristaps 316: struct html *h;
317:
318: if (NULL == (h = calloc(1, sizeof(struct html))))
319: return(NULL);
1.10 kristaps 320:
1.30 kristaps 321: SLIST_INIT(&h->stack);
1.32 ! kristaps 322: if (NULL == (h->symtab = chars_init(CHARS_HTML))) {
! 323: free(h);
! 324: return(NULL);
! 325: }
1.30 kristaps 326: return(h);
1.29 kristaps 327: }
1.10 kristaps 328:
1.29 kristaps 329: void
330: html_free(void *p)
331: {
1.30 kristaps 332: struct tag *tag;
333: struct html *h;
334:
335: h = (struct html *)p;
1.10 kristaps 336:
1.30 kristaps 337: while ( ! SLIST_EMPTY(&h->stack)) {
338: tag = SLIST_FIRST(&h->stack);
339: SLIST_REMOVE_HEAD(&h->stack, entry);
340: free(tag);
341: }
342: free(h);
1.10 kristaps 343: }
1.2 kristaps 344:
1.29 kristaps 345: static void
346: print_mdoc(MDOC_ARGS)
1.4 kristaps 347: {
1.30 kristaps 348: struct tag *t;
1.4 kristaps 349:
1.30 kristaps 350: t = print_otag(h, TAG_HEAD, 0, NULL);
1.29 kristaps 351: print_mdoc_head(m, n, h);
1.30 kristaps 352: print_tagq(h, t);
353:
354: t = print_otag(h, TAG_BODY, 0, NULL);
355: print_mdoc_title(m, n, h);
1.29 kristaps 356: print_mdoc_node(m, n, h);
1.30 kristaps 357: print_tagq(h, t);
1.29 kristaps 358: }
1.4 kristaps 359:
1.29 kristaps 360: static void
361: print_gen_head(struct html *h)
362: {
363: struct htmlpair meta0[2];
364: struct htmlpair meta1[2];
365: struct htmlpair link[4];
366:
367: meta0[0].key = ATTR_HTTPEQUIV;
368: meta0[0].val = "Content-Type";
369: meta0[1].key = ATTR_CONTENT;
370: meta0[1].val = "text/html; charest-utf-8";
371:
372: meta1[0].key = ATTR_NAME;
373: meta1[0].val = "resource-type";
374: meta1[1].key = ATTR_CONTENT;
375: meta1[1].val = "document";
376:
377: link[0].key = ATTR_REL;
378: link[0].val = "stylesheet";
379: link[1].key = ATTR_HREF;
1.30 kristaps 380: link[1].val = "style.css"; /* XXX */
1.29 kristaps 381: link[2].key = ATTR_TYPE;
382: link[2].val = "text/css";
383: link[3].key = ATTR_MEDIA;
384: link[3].val = "all";
385:
386: print_otag(h, TAG_META, 2, meta0);
387: print_otag(h, TAG_META, 2, meta1);
388: print_otag(h, TAG_LINK, 4, link);
1.4 kristaps 389: }
390:
1.30 kristaps 391: /* ARGSUSED */
1.29 kristaps 392: static void
393: print_mdoc_head(MDOC_ARGS)
1.18 kristaps 394: {
395:
1.29 kristaps 396: print_gen_head(h);
397: print_otag(h, TAG_TITLE, 0, NULL);
1.32 ! kristaps 398: print_encode(h, m->title);
1.2 kristaps 399: }
400:
1.30 kristaps 401: /* ARGSUSED */
1.29 kristaps 402: static void
1.30 kristaps 403: print_mdoc_title(MDOC_ARGS)
1.2 kristaps 404: {
405:
1.30 kristaps 406: /* TODO */
1.2 kristaps 407: }
408:
1.29 kristaps 409: static void
410: print_mdoc_node(MDOC_ARGS)
1.2 kristaps 411: {
1.29 kristaps 412: int child;
1.30 kristaps 413: struct tag *t;
1.8 kristaps 414:
1.29 kristaps 415: child = 1;
1.30 kristaps 416: t = SLIST_FIRST(&h->stack);
1.8 kristaps 417:
1.29 kristaps 418: switch (n->type) {
419: case (MDOC_ROOT):
420: child = mdoc_root_pre(m, n, h);
1.7 kristaps 421: break;
1.29 kristaps 422: case (MDOC_TEXT):
423: print_text(h, n->string);
1.7 kristaps 424: break;
1.3 kristaps 425: default:
1.29 kristaps 426: if (mdocs[n->tok].pre)
427: child = (*mdocs[n->tok].pre)(m, n, h);
1.3 kristaps 428: break;
1.2 kristaps 429: }
430:
1.29 kristaps 431: if (child && n->child)
432: print_mdoc_node(m, n->child, h);
1.8 kristaps 433:
1.30 kristaps 434: print_stagq(h, t);
435:
1.29 kristaps 436: switch (n->type) {
437: case (MDOC_ROOT):
1.7 kristaps 438: break;
1.29 kristaps 439: case (MDOC_TEXT):
1.7 kristaps 440: break;
1.3 kristaps 441: default:
1.29 kristaps 442: if (mdocs[n->tok].post)
443: (*mdocs[n->tok].post)(m, n, h);
1.3 kristaps 444: break;
445: }
1.2 kristaps 446:
1.29 kristaps 447: if (n->next)
448: print_mdoc_node(m, n->next, h);
1.2 kristaps 449: }
450:
1.29 kristaps 451: static void
452: print_man(MAN_ARGS)
1.9 kristaps 453: {
1.30 kristaps 454: struct tag *t;
1.9 kristaps 455:
1.30 kristaps 456: t = print_otag(h, TAG_HEAD, 0, NULL);
1.29 kristaps 457: print_man_head(m, n, h);
1.30 kristaps 458: print_tagq(h, t);
459:
460: t = print_otag(h, TAG_BODY, 0, NULL);
1.29 kristaps 461: print_man_body(m, n, h);
1.30 kristaps 462: print_tagq(h, t);
1.9 kristaps 463: }
464:
1.30 kristaps 465: /* ARGSUSED */
1.9 kristaps 466: static void
1.29 kristaps 467: print_man_head(MAN_ARGS)
1.9 kristaps 468: {
469:
1.29 kristaps 470: print_gen_head(h);
471: print_otag(h, TAG_TITLE, 0, NULL);
1.32 ! kristaps 472: print_encode(h, m->title);
1.29 kristaps 473: }
1.9 kristaps 474:
1.30 kristaps 475: /* ARGSUSED */
1.29 kristaps 476: static void
477: print_man_body(MAN_ARGS)
478: {
1.30 kristaps 479:
480: /* TODO */
1.9 kristaps 481: }
482:
1.32 ! kristaps 483: static void
! 484: print_spec(struct html *h, const char *p, int len)
! 485: {
! 486: const char *rhs;
! 487: int i;
! 488: size_t sz;
! 489:
! 490: rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz);
! 491:
! 492: if (NULL == rhs)
! 493: return;
! 494: for (i = 0; i < (int)sz; i++)
! 495: putchar(rhs[i]);
! 496: }
! 497:
! 498: static void
! 499: print_res(struct html *h, const char *p, int len)
! 500: {
! 501: const char *rhs;
! 502: int i;
! 503: size_t sz;
! 504:
! 505: rhs = chars_a2res(h->symtab, p, (size_t)len, &sz);
! 506:
! 507: if (NULL == rhs)
! 508: return;
! 509: for (i = 0; i < (int)sz; i++)
! 510: putchar(rhs[i]);
! 511: }
! 512:
! 513: static void
! 514: print_escape(struct html *h, const char **p)
! 515: {
! 516: int j, type;
! 517: const char *wp;
! 518:
! 519: wp = *p;
! 520: type = 1;
! 521:
! 522: if (0 == *(++wp)) {
! 523: *p = wp;
! 524: return;
! 525: }
! 526:
! 527: if ('(' == *wp) {
! 528: wp++;
! 529: if (0 == *wp || 0 == *(wp + 1)) {
! 530: *p = 0 == *wp ? wp : wp + 1;
! 531: return;
! 532: }
! 533:
! 534: print_spec(h, wp, 2);
! 535: *p = ++wp;
! 536: return;
! 537:
! 538: } else if ('*' == *wp) {
! 539: if (0 == *(++wp)) {
! 540: *p = wp;
! 541: return;
! 542: }
! 543:
! 544: switch (*wp) {
! 545: case ('('):
! 546: wp++;
! 547: if (0 == *wp || 0 == *(wp + 1)) {
! 548: *p = 0 == *wp ? wp : wp + 1;
! 549: return;
! 550: }
! 551:
! 552: print_res(h, wp, 2);
! 553: *p = ++wp;
! 554: return;
! 555: case ('['):
! 556: type = 0;
! 557: break;
! 558: default:
! 559: print_res(h, wp, 1);
! 560: *p = wp;
! 561: return;
! 562: }
! 563:
! 564: } else if ('f' == *wp) {
! 565: if (0 == *(++wp)) {
! 566: *p = wp;
! 567: return;
! 568: }
! 569:
! 570: switch (*wp) {
! 571: case ('B'):
! 572: /* TODO */
! 573: break;
! 574: case ('I'):
! 575: /* TODO */
! 576: break;
! 577: case ('P'):
! 578: /* FALLTHROUGH */
! 579: case ('R'):
! 580: /* TODO */
! 581: break;
! 582: default:
! 583: break;
! 584: }
! 585:
! 586: *p = wp;
! 587: return;
! 588:
! 589: } else if ('[' != *wp) {
! 590: print_spec(h, wp, 1);
! 591: *p = wp;
! 592: return;
! 593: }
! 594:
! 595: wp++;
! 596: for (j = 0; *wp && ']' != *wp; wp++, j++)
! 597: /* Loop... */ ;
! 598:
! 599: if (0 == *wp) {
! 600: *p = wp;
! 601: return;
! 602: }
! 603:
! 604: if (type)
! 605: print_spec(h, wp - j, j);
! 606: else
! 607: print_res(h, wp - j, j);
! 608:
! 609: *p = wp;
! 610: }
! 611:
1.9 kristaps 612:
1.29 kristaps 613: static void
1.32 ! kristaps 614: print_encode(struct html *h, const char *p)
1.29 kristaps 615: {
1.14 kristaps 616:
1.32 ! kristaps 617: for (; *p; p++) {
! 618: if ('\\' != *p) {
! 619: putchar(*p);
! 620: continue;
! 621: }
! 622: print_escape(h, &p);
! 623: }
1.14 kristaps 624: }
625:
626:
1.30 kristaps 627: static struct tag *
1.29 kristaps 628: print_otag(struct html *h, enum htmltag tag,
629: int sz, const struct htmlpair *p)
1.14 kristaps 630: {
1.29 kristaps 631: int i;
1.30 kristaps 632: struct tag *t;
633:
634: if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
635: if (NULL == (t = malloc(sizeof(struct tag))))
636: err(EXIT_FAILURE, "malloc");
637: t->tag = tag;
638: SLIST_INSERT_HEAD(&h->stack, t, entry);
639: } else
640: t = NULL;
1.29 kristaps 641:
642: if ( ! (HTML_NOSPACE & h->flags))
1.30 kristaps 643: if ( ! (HTML_CLRLINE & htmltags[tag].flags))
1.29 kristaps 644: printf(" ");
645:
646: printf("<%s", htmltags[tag].name);
647: for (i = 0; i < sz; i++) {
648: printf(" %s=\"", htmlattrs[p[i].key]);
649: assert(p->val);
1.32 ! kristaps 650: print_encode(h, p[i].val);
1.29 kristaps 651: printf("\"");
652: }
653: printf(">");
1.14 kristaps 654:
1.29 kristaps 655: h->flags |= HTML_NOSPACE;
1.30 kristaps 656: if (HTML_CLRLINE & htmltags[tag].flags)
657: h->flags |= HTML_NEWLINE;
658: else
659: h->flags &= ~HTML_NEWLINE;
1.14 kristaps 660:
1.30 kristaps 661: return(t);
1.14 kristaps 662: }
663:
664:
665: /* ARGSUSED */
1.29 kristaps 666: static void
667: print_ctag(struct html *h, enum htmltag tag)
1.14 kristaps 668: {
669:
1.29 kristaps 670: printf("</%s>", htmltags[tag].name);
1.30 kristaps 671: if (HTML_CLRLINE & htmltags[tag].flags)
1.29 kristaps 672: h->flags |= HTML_NOSPACE;
1.30 kristaps 673: if (HTML_CLRLINE & htmltags[tag].flags)
674: h->flags |= HTML_NEWLINE;
675: else
676: h->flags &= ~HTML_NEWLINE;
1.14 kristaps 677: }
678:
679:
1.29 kristaps 680: /* ARGSUSED */
681: static void
682: print_gen_doctype(struct html *h)
1.1 kristaps 683: {
1.29 kristaps 684:
685: printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n", DOCTYPE, DTD);
1.1 kristaps 686: }
687:
688:
1.29 kristaps 689: static void
690: print_text(struct html *h, const char *p)
1.1 kristaps 691: {
692:
1.29 kristaps 693: if (*p && 0 == *(p + 1))
694: switch (*p) {
695: case('.'):
696: /* FALLTHROUGH */
697: case(','):
698: /* FALLTHROUGH */
699: case(';'):
700: /* FALLTHROUGH */
701: case(':'):
702: /* FALLTHROUGH */
703: case('?'):
704: /* FALLTHROUGH */
705: case('!'):
706: /* FALLTHROUGH */
707: case(')'):
708: /* FALLTHROUGH */
709: case(']'):
710: /* FALLTHROUGH */
711: case('}'):
712: h->flags |= HTML_NOSPACE;
1.30 kristaps 713: break;
1.29 kristaps 714: default:
715: break;
716: }
1.1 kristaps 717:
1.29 kristaps 718: if ( ! (h->flags & HTML_NOSPACE))
719: printf(" ");
1.30 kristaps 720:
1.29 kristaps 721: h->flags &= ~HTML_NOSPACE;
1.30 kristaps 722: h->flags &= ~HTML_NEWLINE;
1.1 kristaps 723:
1.29 kristaps 724: if (p)
1.32 ! kristaps 725: print_encode(h, p);
1.8 kristaps 726:
1.29 kristaps 727: if (*p && 0 == *(p + 1))
728: switch (*p) {
729: case('('):
730: /* FALLTHROUGH */
731: case('['):
732: /* FALLTHROUGH */
733: case('{'):
734: h->flags |= HTML_NOSPACE;
1.30 kristaps 735: break;
1.29 kristaps 736: default:
737: break;
738: }
1.1 kristaps 739: }
1.30 kristaps 740:
741:
742: static void
743: print_tagq(struct html *h, const struct tag *until)
744: {
745: struct tag *tag;
746:
747: while ( ! SLIST_EMPTY(&h->stack)) {
748: tag = SLIST_FIRST(&h->stack);
749: print_ctag(h, tag->tag);
750: SLIST_REMOVE_HEAD(&h->stack, entry);
751: free(tag);
752: if (until && tag == until)
753: return;
754: }
755: }
756:
757:
758: static void
759: print_stagq(struct html *h, const struct tag *suntil)
760: {
761: struct tag *tag;
762:
763: while ( ! SLIST_EMPTY(&h->stack)) {
764: tag = SLIST_FIRST(&h->stack);
765: if (suntil && tag == suntil)
766: return;
767: print_ctag(h, tag->tag);
768: SLIST_REMOVE_HEAD(&h->stack, entry);
769: free(tag);
770: }
771: }
772:
773:
774: /* ARGSUSED */
775: static int
776: mdoc_root_pre(MDOC_ARGS)
777: {
778: struct htmlpair tag;
779:
780: tag.key = ATTR_CLASS;
781: tag.val = "body";
782:
783: print_otag(h, TAG_DIV, 1, &tag);
784: return(1);
785: }
786:
787:
788: /* ARGSUSED */
789: static int
790: mdoc_ss_pre(MDOC_ARGS)
791: {
792:
793: if (MDOC_BODY == n->type)
794: print_otag(h, TAG_P, 0, NULL);
795: if (MDOC_HEAD == n->type)
796: print_otag(h, TAG_H2, 0, NULL);
797: return(1);
798: }
799:
800:
801: /* ARGSUSED */
802: static int
803: mdoc_fl_pre(MDOC_ARGS)
804: {
805: struct htmlpair tag;
806:
807: tag.key = ATTR_CLASS;
808: tag.val = "flag";
809:
810: print_otag(h, TAG_SPAN, 1, &tag);
811: print_text(h, "\\-");
812: h->flags |= HTML_NOSPACE;
813: return(1);
814: }
815:
816:
817: /* ARGSUSED */
818: static int
819: mdoc_pp_pre(MDOC_ARGS)
820: {
821:
822: print_otag(h, TAG_BR, 0, NULL);
823: print_otag(h, TAG_BR, 0, NULL);
824: return(0);
825: }
826:
827:
828: /* ARGSUSED */
829: static int
830: mdoc_nd_pre(MDOC_ARGS)
831: {
832:
833: if (MDOC_BODY == n->type)
1.31 kristaps 834: print_text(h, "\\(en");
1.30 kristaps 835: return(1);
836: }
837:
838:
839: /* ARGSUSED */
840: static int
841: mdoc_op_pre(MDOC_ARGS)
842: {
843:
844: if (MDOC_BODY == n->type) {
845: print_text(h, "\\(lB");
846: h->flags |= HTML_NOSPACE;
847: }
848: return(1);
849: }
850:
851:
852: /* ARGSUSED */
853: static void
854: mdoc_op_post(MDOC_ARGS)
855: {
856:
857: if (MDOC_BODY != n->type)
858: return;
859: h->flags |= HTML_NOSPACE;
860: print_text(h, "\\(rB");
861: }
862:
863:
864: static int
865: mdoc_nm_pre(MDOC_ARGS)
866: {
867: struct htmlpair class;
868:
869: if ( ! (HTML_NEWLINE & h->flags))
870: if (SEC_SYNOPSIS == n->sec)
871: print_otag(h, TAG_BR, 0, NULL);
872:
873: class.key = ATTR_CLASS;
874: class.val = "name";
875:
876: print_otag(h, TAG_SPAN, 1, &class);
877: if (NULL == n->child)
878: print_text(h, m->name);
879:
880: return(1);
881: }
882:
883:
884: /* ARGSUSED */
885: static int
886: mdoc_sh_pre(MDOC_ARGS)
887: {
888:
889: if (MDOC_BODY == n->type)
890: print_otag(h, TAG_P, 0, NULL);
891: if (MDOC_HEAD == n->type)
892: print_otag(h, TAG_H1, 0, NULL);
893: return(1);
894: }
895:
896:
897: /* ARGSUSED */
898: static int
899: mdoc_xr_pre(MDOC_ARGS)
900: {
901: struct htmlpair tag;
902:
903: tag.key = ATTR_HREF;
904: tag.val = "#"; /* TODO */
905:
906: print_otag(h, TAG_A, 1, &tag);
907:
908: n = n->child;
909: print_text(h, n->string);
910: if (NULL == (n = n->next))
911: return(0);
912:
913: h->flags |= HTML_NOSPACE;
914: print_text(h, "(");
915: h->flags |= HTML_NOSPACE;
916: print_text(h, n->string);
917: h->flags |= HTML_NOSPACE;
918: print_text(h, ")");
919:
920: return(0);
921: }
1.31 kristaps 922:
923:
924: /* ARGSUSED */
925: static int
926: mdoc_ns_pre(MDOC_ARGS)
927: {
928:
929: h->flags |= HTML_NOSPACE;
930: return(1);
931: }
932:
933:
934: /* ARGSUSED */
935: static int
936: mdoc_ar_pre(MDOC_ARGS)
937: {
938: struct htmlpair tag;
939:
940: tag.key = ATTR_CLASS;
941: tag.val = "arg";
942:
943: print_otag(h, TAG_SPAN, 1, &tag);
944: return(1);
945: }
CVSweb