Annotation of mandoc/html.c, Revision 1.39
1.39 ! kristaps 1: /* $Id: html.c,v 1.38 2009/09/20 17:48:13 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
1.34 kristaps 35: #define PX_MULT 8
1.33 kristaps 36:
1.29 kristaps 37: enum htmltag {
38: TAG_HTML,
39: TAG_HEAD,
40: TAG_BODY,
41: TAG_META,
42: TAG_TITLE,
43: TAG_DIV,
44: TAG_H1,
45: TAG_H2,
46: TAG_P,
47: TAG_SPAN,
48: TAG_LINK,
1.30 kristaps 49: TAG_BR,
50: TAG_A,
1.33 kristaps 51: TAG_TABLE,
52: TAG_COL,
53: TAG_TR,
54: TAG_TD,
1.34 kristaps 55: TAG_LI,
56: TAG_UL,
57: TAG_OL,
1.29 kristaps 58: TAG_MAX
1.7 kristaps 59: };
60:
1.29 kristaps 61: enum htmlattr {
62: ATTR_HTTPEQUIV,
63: ATTR_CONTENT,
64: ATTR_NAME,
65: ATTR_REL,
66: ATTR_HREF,
67: ATTR_TYPE,
68: ATTR_MEDIA,
69: ATTR_CLASS,
1.33 kristaps 70: ATTR_STYLE,
71: ATTR_WIDTH,
72: ATTR_VALIGN,
1.29 kristaps 73: ATTR_MAX
1.7 kristaps 74: };
75:
1.29 kristaps 76: struct htmldata {
77: char *name;
78: int flags;
1.30 kristaps 79: #define HTML_CLRLINE (1 << 0)
80: #define HTML_NOSTACK (1 << 1)
1.29 kristaps 81: };
1.7 kristaps 82:
1.29 kristaps 83: static const struct htmldata htmltags[TAG_MAX] = {
1.30 kristaps 84: {"html", HTML_CLRLINE}, /* TAG_HTML */
85: {"head", HTML_CLRLINE}, /* TAG_HEAD */
86: {"body", HTML_CLRLINE}, /* TAG_BODY */
87: {"meta", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */
1.33 kristaps 88: {"title", HTML_CLRLINE}, /* TAG_TITLE */
1.30 kristaps 89: {"div", HTML_CLRLINE}, /* TAG_DIV */
1.29 kristaps 90: {"h1", 0}, /* TAG_H1 */
91: {"h2", 0}, /* TAG_H2 */
1.30 kristaps 92: {"p", HTML_CLRLINE}, /* TAG_P */
1.29 kristaps 93: {"span", 0}, /* TAG_SPAN */
1.30 kristaps 94: {"link", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
95: {"br", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
96: {"a", 0}, /* TAG_A */
1.33 kristaps 97: {"table", HTML_CLRLINE}, /* TAG_TABLE */
98: {"col", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_COL */
99: {"tr", HTML_CLRLINE}, /* TAG_TR */
100: {"td", HTML_CLRLINE}, /* TAG_TD */
1.34 kristaps 101: {"li", HTML_CLRLINE}, /* TAG_LI */
102: {"ul", HTML_CLRLINE}, /* TAG_UL */
103: {"ol", HTML_CLRLINE}, /* TAG_OL */
1.29 kristaps 104: };
1.10 kristaps 105:
1.29 kristaps 106: static const char *const htmlattrs[ATTR_MAX] = {
107: "http-equiv",
108: "content",
109: "name",
110: "rel",
111: "href",
112: "type",
113: "media",
1.33 kristaps 114: "class",
115: "style",
116: "width",
117: "valign",
1.29 kristaps 118: };
1.10 kristaps 119:
1.29 kristaps 120: struct htmlpair {
121: enum htmlattr key;
122: char *val;
123: };
1.10 kristaps 124:
1.30 kristaps 125: struct tag {
126: enum htmltag tag;
127: SLIST_ENTRY(tag) entry;
128: };
129:
1.37 kristaps 130: struct ord {
131: int pos;
132: const void *cookie;
133: SLIST_ENTRY(ord) entry;
134: };
135:
1.30 kristaps 136: SLIST_HEAD(tagq, tag);
1.37 kristaps 137: SLIST_HEAD(ordq, ord);
1.30 kristaps 138:
1.29 kristaps 139: struct html {
140: int flags;
141: #define HTML_NOSPACE (1 << 0)
1.30 kristaps 142: #define HTML_NEWLINE (1 << 1)
1.37 kristaps 143: struct tagq tags;
144: struct ordq ords;
1.32 kristaps 145: void *symtab;
1.29 kristaps 146: };
1.10 kristaps 147:
1.29 kristaps 148: #define MDOC_ARGS const struct mdoc_meta *m, \
149: const struct mdoc_node *n, \
150: struct html *h
151: #define MAN_ARGS const struct man_meta *m, \
152: const struct man_node *n, \
153: struct html *h
154: struct htmlmdoc {
155: int (*pre)(MDOC_ARGS);
156: void (*post)(MDOC_ARGS);
157: };
1.13 kristaps 158:
1.29 kristaps 159: static void print_gen_doctype(struct html *);
160: static void print_gen_head(struct html *);
161: static void print_mdoc(MDOC_ARGS);
162: static void print_mdoc_head(MDOC_ARGS);
1.30 kristaps 163: static void print_mdoc_title(MDOC_ARGS);
1.29 kristaps 164: static void print_mdoc_node(MDOC_ARGS);
1.39 ! kristaps 165: static void print_mdoc_nodelist(MDOC_ARGS);
1.29 kristaps 166: static void print_man(MAN_ARGS);
167: static void print_man_head(MAN_ARGS);
168: static void print_man_body(MAN_ARGS);
1.30 kristaps 169: static struct tag *print_otag(struct html *, enum htmltag,
1.29 kristaps 170: int, const struct htmlpair *);
1.30 kristaps 171: static void print_tagq(struct html *, const struct tag *);
172: static void print_stagq(struct html *, const struct tag *);
1.29 kristaps 173: static void print_ctag(struct html *, enum htmltag);
1.32 kristaps 174: static void print_encode(struct html *, const char *);
175: static void print_escape(struct html *, const char **);
1.29 kristaps 176: static void print_text(struct html *, const char *);
1.32 kristaps 177: static void print_res(struct html *, const char *, int);
178: static void print_spec(struct html *, const char *, int);
1.33 kristaps 179:
180: static int a2width(const char *);
181: static int a2offs(const char *);
1.37 kristaps 182: static int a2list(const struct mdoc_node *);
1.33 kristaps 183:
1.39 ! kristaps 184: static void mdoc_root_post(MDOC_ARGS);
1.29 kristaps 185: static int mdoc_root_pre(MDOC_ARGS);
1.34 kristaps 186: static int mdoc_tbl_pre(MDOC_ARGS, int);
1.37 kristaps 187: static int mdoc_tbl_block_pre(MDOC_ARGS, int, int, int, int);
1.34 kristaps 188: static int mdoc_tbl_body_pre(MDOC_ARGS, int, int);
189: static int mdoc_tbl_head_pre(MDOC_ARGS, int, int);
1.29 kristaps 190:
1.37 kristaps 191: static void mdoc_aq_post(MDOC_ARGS);
192: static int mdoc_aq_pre(MDOC_ARGS);
1.31 kristaps 193: static int mdoc_ar_pre(MDOC_ARGS);
1.39 ! kristaps 194: static int mdoc_bd_pre(MDOC_ARGS);
1.37 kristaps 195: static void mdoc_bl_post(MDOC_ARGS);
1.33 kristaps 196: static int mdoc_bl_pre(MDOC_ARGS);
1.34 kristaps 197: static int mdoc_d1_pre(MDOC_ARGS);
198: static void mdoc_dq_post(MDOC_ARGS);
199: static int mdoc_dq_pre(MDOC_ARGS);
1.30 kristaps 200: static int mdoc_fl_pre(MDOC_ARGS);
1.34 kristaps 201: static int mdoc_em_pre(MDOC_ARGS);
202: static int mdoc_ex_pre(MDOC_ARGS);
1.33 kristaps 203: static int mdoc_it_pre(MDOC_ARGS);
1.29 kristaps 204: static int mdoc_nd_pre(MDOC_ARGS);
205: static int mdoc_nm_pre(MDOC_ARGS);
1.31 kristaps 206: static int mdoc_ns_pre(MDOC_ARGS);
1.34 kristaps 207: static void mdoc_op_post(MDOC_ARGS);
1.30 kristaps 208: static int mdoc_op_pre(MDOC_ARGS);
1.39 ! kristaps 209: static int mdoc_pa_pre(MDOC_ARGS);
1.29 kristaps 210: static int mdoc_pp_pre(MDOC_ARGS);
1.34 kristaps 211: static void mdoc_pq_post(MDOC_ARGS);
212: static int mdoc_pq_pre(MDOC_ARGS);
1.39 ! kristaps 213: static void mdoc_qq_post(MDOC_ARGS);
! 214: static int mdoc_qq_pre(MDOC_ARGS);
1.29 kristaps 215: static int mdoc_sh_pre(MDOC_ARGS);
1.34 kristaps 216: static void mdoc_sq_post(MDOC_ARGS);
217: static int mdoc_sq_pre(MDOC_ARGS);
1.29 kristaps 218: static int mdoc_ss_pre(MDOC_ARGS);
1.34 kristaps 219: static int mdoc_sx_pre(MDOC_ARGS);
1.30 kristaps 220: static int mdoc_xr_pre(MDOC_ARGS);
1.33 kristaps 221: static int mdoc_xx_pre(MDOC_ARGS);
222:
223: #ifdef __linux__
1.35 kristaps 224: extern size_t strlcpy(char *, const char *, size_t);
225: extern size_t strlcat(char *, const char *, size_t);
1.33 kristaps 226: #endif
1.29 kristaps 227:
228: static const struct htmlmdoc mdocs[MDOC_MAX] = {
1.39 ! kristaps 229: {mdoc_pp_pre, NULL}, /* Ap */
1.29 kristaps 230: {NULL, NULL}, /* Dd */
231: {NULL, NULL}, /* Dt */
232: {NULL, NULL}, /* Os */
1.30 kristaps 233: {mdoc_sh_pre, NULL }, /* Sh */
234: {mdoc_ss_pre, NULL }, /* Ss */
1.29 kristaps 235: {mdoc_pp_pre, NULL}, /* Pp */
1.34 kristaps 236: {mdoc_d1_pre, NULL}, /* D1 */
237: {mdoc_d1_pre, NULL}, /* Dl */
1.39 ! kristaps 238: {mdoc_bd_pre, NULL}, /* Bd */
1.29 kristaps 239: {NULL, NULL}, /* Ed */
1.37 kristaps 240: {mdoc_bl_pre, mdoc_bl_post}, /* Bl */
1.29 kristaps 241: {NULL, NULL}, /* El */
1.33 kristaps 242: {mdoc_it_pre, NULL}, /* It */
1.29 kristaps 243: {NULL, NULL}, /* Ad */
244: {NULL, NULL}, /* An */
1.31 kristaps 245: {mdoc_ar_pre, NULL}, /* Ar */
1.29 kristaps 246: {NULL, NULL}, /* Cd */
247: {NULL, NULL}, /* Cm */
248: {NULL, NULL}, /* Dv */
249: {NULL, NULL}, /* Er */
250: {NULL, NULL}, /* Ev */
1.34 kristaps 251: {mdoc_ex_pre, NULL}, /* Ex */
1.29 kristaps 252: {NULL, NULL}, /* Fa */
253: {NULL, NULL}, /* Fd */
1.30 kristaps 254: {mdoc_fl_pre, NULL}, /* Fl */
1.29 kristaps 255: {NULL, NULL}, /* Fn */
256: {NULL, NULL}, /* Ft */
257: {NULL, NULL}, /* Ic */
258: {NULL, NULL}, /* In */
259: {NULL, NULL}, /* Li */
260: {mdoc_nd_pre, NULL}, /* Nd */
1.30 kristaps 261: {mdoc_nm_pre, NULL}, /* Nm */
262: {mdoc_op_pre, mdoc_op_post}, /* Op */
1.29 kristaps 263: {NULL, NULL}, /* Ot */
1.39 ! kristaps 264: {mdoc_pa_pre, NULL}, /* Pa */
1.29 kristaps 265: {NULL, NULL}, /* Rv */
266: {NULL, NULL}, /* St */
267: {NULL, NULL}, /* Va */
268: {NULL, NULL}, /* Vt */
1.30 kristaps 269: {mdoc_xr_pre, NULL}, /* Xr */
1.29 kristaps 270: {NULL, NULL}, /* %A */
271: {NULL, NULL}, /* %B */
272: {NULL, NULL}, /* %D */
273: {NULL, NULL}, /* %I */
274: {NULL, NULL}, /* %J */
275: {NULL, NULL}, /* %N */
276: {NULL, NULL}, /* %O */
277: {NULL, NULL}, /* %P */
278: {NULL, NULL}, /* %R */
279: {NULL, NULL}, /* %T */
280: {NULL, NULL}, /* %V */
281: {NULL, NULL}, /* Ac */
1.37 kristaps 282: {mdoc_aq_pre, mdoc_aq_post}, /* Ao */
283: {mdoc_aq_pre, mdoc_aq_post}, /* Aq */
1.29 kristaps 284: {NULL, NULL}, /* At */
285: {NULL, NULL}, /* Bc */
286: {NULL, NULL}, /* Bf */
287: {NULL, NULL}, /* Bo */
288: {NULL, NULL}, /* Bq */
1.33 kristaps 289: {mdoc_xx_pre, NULL}, /* Bsx */
1.29 kristaps 290: {NULL, NULL}, /* Bx */
291: {NULL, NULL}, /* Db */
292: {NULL, NULL}, /* Dc */
293: {NULL, NULL}, /* Do */
1.34 kristaps 294: {mdoc_dq_pre, mdoc_dq_post}, /* Dq */
1.29 kristaps 295: {NULL, NULL}, /* Ec */
296: {NULL, NULL}, /* Ef */
1.34 kristaps 297: {mdoc_em_pre, NULL}, /* Em */
1.29 kristaps 298: {NULL, NULL}, /* Eo */
1.33 kristaps 299: {mdoc_xx_pre, NULL}, /* Fx */
1.29 kristaps 300: {NULL, NULL}, /* Ms */
301: {NULL, NULL}, /* No */
1.31 kristaps 302: {mdoc_ns_pre, NULL}, /* Ns */
1.33 kristaps 303: {mdoc_xx_pre, NULL}, /* Nx */
304: {mdoc_xx_pre, NULL}, /* Ox */
1.29 kristaps 305: {NULL, NULL}, /* Pc */
306: {NULL, NULL}, /* Pf */
1.34 kristaps 307: {mdoc_pq_pre, mdoc_pq_post}, /* Po */
308: {mdoc_pq_pre, mdoc_pq_post}, /* Pq */
1.29 kristaps 309: {NULL, NULL}, /* Qc */
310: {NULL, NULL}, /* Ql */
1.39 ! kristaps 311: {mdoc_qq_pre, mdoc_qq_post}, /* Qo */
! 312: {mdoc_qq_pre, mdoc_qq_post}, /* Qq */
1.29 kristaps 313: {NULL, NULL}, /* Re */
314: {NULL, NULL}, /* Rs */
315: {NULL, NULL}, /* Sc */
1.34 kristaps 316: {mdoc_sq_pre, mdoc_sq_post}, /* So */
317: {mdoc_sq_pre, mdoc_sq_post}, /* Sq */
1.29 kristaps 318: {NULL, NULL}, /* Sm */
1.34 kristaps 319: {mdoc_sx_pre, NULL}, /* Sx */
1.29 kristaps 320: {NULL, NULL}, /* Sy */
321: {NULL, NULL}, /* Tn */
1.33 kristaps 322: {mdoc_xx_pre, NULL}, /* Ux */
1.29 kristaps 323: {NULL, NULL}, /* Xc */
324: {NULL, NULL}, /* Xo */
325: {NULL, NULL}, /* Fo */
326: {NULL, NULL}, /* Fc */
327: {NULL, NULL}, /* Oo */
328: {NULL, NULL}, /* Oc */
329: {NULL, NULL}, /* Bk */
330: {NULL, NULL}, /* Ek */
331: {NULL, NULL}, /* Bt */
332: {NULL, NULL}, /* Hf */
333: {NULL, NULL}, /* Fr */
334: {NULL, NULL}, /* Ud */
335: {NULL, NULL}, /* Lb */
336: {NULL, NULL}, /* Lp */
337: {NULL, NULL}, /* Lk */
338: {NULL, NULL}, /* Mt */
339: {NULL, NULL}, /* Brq */
340: {NULL, NULL}, /* Bro */
341: {NULL, NULL}, /* Brc */
342: {NULL, NULL}, /* %C */
343: {NULL, NULL}, /* Es */
344: {NULL, NULL}, /* En */
1.33 kristaps 345: {mdoc_xx_pre, NULL}, /* Dx */
1.29 kristaps 346: {NULL, NULL}, /* %Q */
347: {NULL, NULL}, /* br */
348: {NULL, NULL}, /* sp */
349: };
1.10 kristaps 350:
1.35 kristaps 351: static char buf[BUFSIZ]; /* XXX */
352:
353: #define bufcat(x) (void)strlcat(buf, (x), BUFSIZ)
354: #define bufinit() buf[0] = 0
355: #define buffmt(...) (void)snprintf(buf, BUFSIZ - 1, __VA_ARGS__)
1.33 kristaps 356:
1.30 kristaps 357: void
1.29 kristaps 358: html_mdoc(void *arg, const struct mdoc *m)
1.10 kristaps 359: {
1.29 kristaps 360: struct html *h;
1.30 kristaps 361: struct tag *t;
1.10 kristaps 362:
1.29 kristaps 363: h = (struct html *)arg;
1.10 kristaps 364:
1.29 kristaps 365: print_gen_doctype(h);
1.30 kristaps 366: t = print_otag(h, TAG_HTML, 0, NULL);
1.29 kristaps 367: print_mdoc(mdoc_meta(m), mdoc_node(m), h);
1.30 kristaps 368: print_tagq(h, t);
369:
1.29 kristaps 370: printf("\n");
1.10 kristaps 371: }
372:
1.33 kristaps 373:
1.30 kristaps 374: void
1.29 kristaps 375: html_man(void *arg, const struct man *m)
1.10 kristaps 376: {
1.29 kristaps 377: struct html *h;
1.30 kristaps 378: struct tag *t;
1.10 kristaps 379:
1.29 kristaps 380: h = (struct html *)arg;
1.10 kristaps 381:
1.29 kristaps 382: print_gen_doctype(h);
1.30 kristaps 383: t = print_otag(h, TAG_HTML, 0, NULL);
1.29 kristaps 384: print_man(man_meta(m), man_node(m), h);
1.30 kristaps 385: print_tagq(h, t);
386:
1.29 kristaps 387: printf("\n");
1.10 kristaps 388: }
389:
1.33 kristaps 390:
1.29 kristaps 391: void *
392: html_alloc(void)
1.10 kristaps 393: {
1.30 kristaps 394: struct html *h;
395:
396: if (NULL == (h = calloc(1, sizeof(struct html))))
397: return(NULL);
1.10 kristaps 398:
1.37 kristaps 399: SLIST_INIT(&h->tags);
400: SLIST_INIT(&h->ords);
401:
1.32 kristaps 402: if (NULL == (h->symtab = chars_init(CHARS_HTML))) {
403: free(h);
404: return(NULL);
405: }
1.30 kristaps 406: return(h);
1.29 kristaps 407: }
1.10 kristaps 408:
1.33 kristaps 409:
1.29 kristaps 410: void
411: html_free(void *p)
412: {
1.30 kristaps 413: struct tag *tag;
1.37 kristaps 414: struct ord *ord;
1.30 kristaps 415: struct html *h;
416:
417: h = (struct html *)p;
1.10 kristaps 418:
1.37 kristaps 419: while ( ! SLIST_EMPTY(&h->ords)) {
420: ord = SLIST_FIRST(&h->ords);
421: SLIST_REMOVE_HEAD(&h->ords, entry);
422: free(ord);
423: }
424:
425: while ( ! SLIST_EMPTY(&h->tags)) {
426: tag = SLIST_FIRST(&h->tags);
427: SLIST_REMOVE_HEAD(&h->tags, entry);
1.30 kristaps 428: free(tag);
429: }
1.36 kristaps 430:
431: if (h->symtab)
432: chars_free(h->symtab);
1.30 kristaps 433: free(h);
1.10 kristaps 434: }
1.2 kristaps 435:
1.33 kristaps 436:
1.29 kristaps 437: static void
438: print_mdoc(MDOC_ARGS)
1.4 kristaps 439: {
1.30 kristaps 440: struct tag *t;
1.4 kristaps 441:
1.30 kristaps 442: t = print_otag(h, TAG_HEAD, 0, NULL);
1.29 kristaps 443: print_mdoc_head(m, n, h);
1.30 kristaps 444: print_tagq(h, t);
445:
446: t = print_otag(h, TAG_BODY, 0, NULL);
447: print_mdoc_title(m, n, h);
1.39 ! kristaps 448: print_mdoc_nodelist(m, n, h);
1.30 kristaps 449: print_tagq(h, t);
1.29 kristaps 450: }
1.4 kristaps 451:
1.33 kristaps 452:
1.29 kristaps 453: static void
454: print_gen_head(struct html *h)
455: {
456: struct htmlpair meta0[2];
457: struct htmlpair meta1[2];
458: struct htmlpair link[4];
459:
460: meta0[0].key = ATTR_HTTPEQUIV;
461: meta0[0].val = "Content-Type";
462: meta0[1].key = ATTR_CONTENT;
1.34 kristaps 463: meta0[1].val = "text/html; charset=utf-8";
1.29 kristaps 464:
465: meta1[0].key = ATTR_NAME;
466: meta1[0].val = "resource-type";
467: meta1[1].key = ATTR_CONTENT;
468: meta1[1].val = "document";
469:
470: link[0].key = ATTR_REL;
471: link[0].val = "stylesheet";
472: link[1].key = ATTR_HREF;
1.30 kristaps 473: link[1].val = "style.css"; /* XXX */
1.29 kristaps 474: link[2].key = ATTR_TYPE;
475: link[2].val = "text/css";
476: link[3].key = ATTR_MEDIA;
477: link[3].val = "all";
478:
479: print_otag(h, TAG_META, 2, meta0);
480: print_otag(h, TAG_META, 2, meta1);
481: print_otag(h, TAG_LINK, 4, link);
1.4 kristaps 482: }
483:
1.33 kristaps 484:
1.30 kristaps 485: /* ARGSUSED */
1.29 kristaps 486: static void
487: print_mdoc_head(MDOC_ARGS)
1.18 kristaps 488: {
489:
1.29 kristaps 490: print_gen_head(h);
491: print_otag(h, TAG_TITLE, 0, NULL);
1.32 kristaps 492: print_encode(h, m->title);
1.2 kristaps 493: }
494:
1.33 kristaps 495:
1.30 kristaps 496: /* ARGSUSED */
1.29 kristaps 497: static void
1.30 kristaps 498: print_mdoc_title(MDOC_ARGS)
1.2 kristaps 499: {
500:
1.30 kristaps 501: /* TODO */
1.2 kristaps 502: }
503:
1.33 kristaps 504:
1.29 kristaps 505: static void
1.39 ! kristaps 506: print_mdoc_nodelist(MDOC_ARGS)
! 507: {
! 508:
! 509: print_mdoc_node(m, n, h);
! 510: if (n->next)
! 511: print_mdoc_nodelist(m, n->next, h);
! 512: }
! 513:
! 514:
! 515: static void
1.29 kristaps 516: print_mdoc_node(MDOC_ARGS)
1.2 kristaps 517: {
1.29 kristaps 518: int child;
1.30 kristaps 519: struct tag *t;
1.8 kristaps 520:
1.29 kristaps 521: child = 1;
1.37 kristaps 522: t = SLIST_FIRST(&h->tags);
1.8 kristaps 523:
1.35 kristaps 524: bufinit();
525:
1.29 kristaps 526: switch (n->type) {
527: case (MDOC_ROOT):
528: child = mdoc_root_pre(m, n, h);
1.7 kristaps 529: break;
1.29 kristaps 530: case (MDOC_TEXT):
531: print_text(h, n->string);
1.7 kristaps 532: break;
1.3 kristaps 533: default:
1.29 kristaps 534: if (mdocs[n->tok].pre)
535: child = (*mdocs[n->tok].pre)(m, n, h);
1.3 kristaps 536: break;
1.2 kristaps 537: }
538:
1.29 kristaps 539: if (child && n->child)
1.39 ! kristaps 540: print_mdoc_nodelist(m, n->child, h);
1.8 kristaps 541:
1.30 kristaps 542: print_stagq(h, t);
543:
1.35 kristaps 544: bufinit();
545:
1.29 kristaps 546: switch (n->type) {
547: case (MDOC_ROOT):
1.39 ! kristaps 548: mdoc_root_post(m, n, h);
1.7 kristaps 549: break;
1.29 kristaps 550: case (MDOC_TEXT):
1.7 kristaps 551: break;
1.3 kristaps 552: default:
1.29 kristaps 553: if (mdocs[n->tok].post)
554: (*mdocs[n->tok].post)(m, n, h);
1.3 kristaps 555: break;
556: }
1.2 kristaps 557: }
558:
1.33 kristaps 559:
1.29 kristaps 560: static void
561: print_man(MAN_ARGS)
1.9 kristaps 562: {
1.30 kristaps 563: struct tag *t;
1.9 kristaps 564:
1.30 kristaps 565: t = print_otag(h, TAG_HEAD, 0, NULL);
1.29 kristaps 566: print_man_head(m, n, h);
1.30 kristaps 567: print_tagq(h, t);
568:
569: t = print_otag(h, TAG_BODY, 0, NULL);
1.29 kristaps 570: print_man_body(m, n, h);
1.30 kristaps 571: print_tagq(h, t);
1.9 kristaps 572: }
573:
1.33 kristaps 574:
1.30 kristaps 575: /* ARGSUSED */
1.9 kristaps 576: static void
1.29 kristaps 577: print_man_head(MAN_ARGS)
1.9 kristaps 578: {
579:
1.29 kristaps 580: print_gen_head(h);
581: print_otag(h, TAG_TITLE, 0, NULL);
1.32 kristaps 582: print_encode(h, m->title);
1.29 kristaps 583: }
1.9 kristaps 584:
1.33 kristaps 585:
1.30 kristaps 586: /* ARGSUSED */
1.29 kristaps 587: static void
588: print_man_body(MAN_ARGS)
589: {
1.30 kristaps 590:
591: /* TODO */
1.9 kristaps 592: }
593:
1.33 kristaps 594:
1.32 kristaps 595: static void
596: print_spec(struct html *h, const char *p, int len)
597: {
598: const char *rhs;
599: int i;
600: size_t sz;
601:
602: rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz);
603:
604: if (NULL == rhs)
605: return;
606: for (i = 0; i < (int)sz; i++)
607: putchar(rhs[i]);
608: }
609:
1.33 kristaps 610:
1.32 kristaps 611: static void
612: print_res(struct html *h, const char *p, int len)
613: {
614: const char *rhs;
615: int i;
616: size_t sz;
617:
618: rhs = chars_a2res(h->symtab, p, (size_t)len, &sz);
619:
620: if (NULL == rhs)
621: return;
622: for (i = 0; i < (int)sz; i++)
623: putchar(rhs[i]);
624: }
625:
1.33 kristaps 626:
1.32 kristaps 627: static void
628: print_escape(struct html *h, const char **p)
629: {
630: int j, type;
631: const char *wp;
632:
633: wp = *p;
634: type = 1;
635:
636: if (0 == *(++wp)) {
637: *p = wp;
638: return;
639: }
640:
641: if ('(' == *wp) {
642: wp++;
643: if (0 == *wp || 0 == *(wp + 1)) {
644: *p = 0 == *wp ? wp : wp + 1;
645: return;
646: }
647:
648: print_spec(h, wp, 2);
649: *p = ++wp;
650: return;
651:
652: } else if ('*' == *wp) {
653: if (0 == *(++wp)) {
654: *p = wp;
655: return;
656: }
657:
658: switch (*wp) {
659: case ('('):
660: wp++;
661: if (0 == *wp || 0 == *(wp + 1)) {
662: *p = 0 == *wp ? wp : wp + 1;
663: return;
664: }
665:
666: print_res(h, wp, 2);
667: *p = ++wp;
668: return;
669: case ('['):
670: type = 0;
671: break;
672: default:
673: print_res(h, wp, 1);
674: *p = wp;
675: return;
676: }
677:
678: } else if ('f' == *wp) {
679: if (0 == *(++wp)) {
680: *p = wp;
681: return;
682: }
683:
684: switch (*wp) {
685: case ('B'):
686: /* TODO */
687: break;
688: case ('I'):
689: /* TODO */
690: break;
691: case ('P'):
692: /* FALLTHROUGH */
693: case ('R'):
694: /* TODO */
695: break;
696: default:
697: break;
698: }
699:
700: *p = wp;
701: return;
702:
703: } else if ('[' != *wp) {
704: print_spec(h, wp, 1);
705: *p = wp;
706: return;
707: }
708:
709: wp++;
710: for (j = 0; *wp && ']' != *wp; wp++, j++)
711: /* Loop... */ ;
712:
713: if (0 == *wp) {
714: *p = wp;
715: return;
716: }
717:
718: if (type)
719: print_spec(h, wp - j, j);
720: else
721: print_res(h, wp - j, j);
722:
723: *p = wp;
724: }
725:
1.9 kristaps 726:
1.29 kristaps 727: static void
1.32 kristaps 728: print_encode(struct html *h, const char *p)
1.29 kristaps 729: {
1.14 kristaps 730:
1.32 kristaps 731: for (; *p; p++) {
1.34 kristaps 732: if ('\\' == *p) {
733: print_escape(h, &p);
734: continue;
735: }
736: switch (*p) {
737: case ('<'):
738: printf("<");
739: break;
740: case ('>'):
741: printf(">");
742: break;
743: case ('&'):
744: printf("&");
745: break;
746: default:
1.32 kristaps 747: putchar(*p);
1.34 kristaps 748: break;
1.32 kristaps 749: }
750: }
1.14 kristaps 751: }
752:
753:
1.30 kristaps 754: static struct tag *
1.29 kristaps 755: print_otag(struct html *h, enum htmltag tag,
756: int sz, const struct htmlpair *p)
1.14 kristaps 757: {
1.29 kristaps 758: int i;
1.30 kristaps 759: struct tag *t;
760:
761: if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
762: if (NULL == (t = malloc(sizeof(struct tag))))
763: err(EXIT_FAILURE, "malloc");
764: t->tag = tag;
1.37 kristaps 765: SLIST_INSERT_HEAD(&h->tags, t, entry);
1.30 kristaps 766: } else
767: t = NULL;
1.29 kristaps 768:
769: if ( ! (HTML_NOSPACE & h->flags))
1.30 kristaps 770: if ( ! (HTML_CLRLINE & htmltags[tag].flags))
1.29 kristaps 771: printf(" ");
772:
773: printf("<%s", htmltags[tag].name);
774: for (i = 0; i < sz; i++) {
775: printf(" %s=\"", htmlattrs[p[i].key]);
776: assert(p->val);
1.32 kristaps 777: print_encode(h, p[i].val);
1.29 kristaps 778: printf("\"");
779: }
780: printf(">");
1.14 kristaps 781:
1.29 kristaps 782: h->flags |= HTML_NOSPACE;
1.30 kristaps 783: if (HTML_CLRLINE & htmltags[tag].flags)
784: h->flags |= HTML_NEWLINE;
785: else
786: h->flags &= ~HTML_NEWLINE;
1.14 kristaps 787:
1.30 kristaps 788: return(t);
1.14 kristaps 789: }
790:
791:
792: /* ARGSUSED */
1.29 kristaps 793: static void
794: print_ctag(struct html *h, enum htmltag tag)
1.14 kristaps 795: {
796:
1.29 kristaps 797: printf("</%s>", htmltags[tag].name);
1.30 kristaps 798: if (HTML_CLRLINE & htmltags[tag].flags)
1.29 kristaps 799: h->flags |= HTML_NOSPACE;
1.30 kristaps 800: if (HTML_CLRLINE & htmltags[tag].flags)
801: h->flags |= HTML_NEWLINE;
802: else
803: h->flags &= ~HTML_NEWLINE;
1.14 kristaps 804: }
805:
806:
1.29 kristaps 807: /* ARGSUSED */
808: static void
809: print_gen_doctype(struct html *h)
1.1 kristaps 810: {
1.29 kristaps 811:
812: printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n", DOCTYPE, DTD);
1.1 kristaps 813: }
814:
815:
1.29 kristaps 816: static void
817: print_text(struct html *h, const char *p)
1.1 kristaps 818: {
819:
1.29 kristaps 820: if (*p && 0 == *(p + 1))
821: switch (*p) {
822: case('.'):
823: /* FALLTHROUGH */
824: case(','):
825: /* FALLTHROUGH */
826: case(';'):
827: /* FALLTHROUGH */
828: case(':'):
829: /* FALLTHROUGH */
830: case('?'):
831: /* FALLTHROUGH */
832: case('!'):
833: /* FALLTHROUGH */
834: case(')'):
835: /* FALLTHROUGH */
836: case(']'):
837: /* FALLTHROUGH */
838: case('}'):
839: h->flags |= HTML_NOSPACE;
1.30 kristaps 840: break;
1.29 kristaps 841: default:
842: break;
843: }
1.1 kristaps 844:
1.29 kristaps 845: if ( ! (h->flags & HTML_NOSPACE))
846: printf(" ");
1.30 kristaps 847:
1.29 kristaps 848: h->flags &= ~HTML_NOSPACE;
1.30 kristaps 849: h->flags &= ~HTML_NEWLINE;
1.1 kristaps 850:
1.29 kristaps 851: if (p)
1.32 kristaps 852: print_encode(h, p);
1.8 kristaps 853:
1.29 kristaps 854: if (*p && 0 == *(p + 1))
855: switch (*p) {
856: case('('):
857: /* FALLTHROUGH */
858: case('['):
859: /* FALLTHROUGH */
860: case('{'):
861: h->flags |= HTML_NOSPACE;
1.30 kristaps 862: break;
1.29 kristaps 863: default:
864: break;
865: }
1.1 kristaps 866: }
1.30 kristaps 867:
868:
869: static void
870: print_tagq(struct html *h, const struct tag *until)
871: {
872: struct tag *tag;
873:
1.37 kristaps 874: while ( ! SLIST_EMPTY(&h->tags)) {
875: tag = SLIST_FIRST(&h->tags);
1.30 kristaps 876: print_ctag(h, tag->tag);
1.37 kristaps 877: SLIST_REMOVE_HEAD(&h->tags, entry);
1.30 kristaps 878: free(tag);
879: if (until && tag == until)
880: return;
881: }
882: }
883:
884:
885: static void
886: print_stagq(struct html *h, const struct tag *suntil)
887: {
888: struct tag *tag;
889:
1.37 kristaps 890: while ( ! SLIST_EMPTY(&h->tags)) {
891: tag = SLIST_FIRST(&h->tags);
1.30 kristaps 892: if (suntil && tag == suntil)
893: return;
894: print_ctag(h, tag->tag);
1.37 kristaps 895: SLIST_REMOVE_HEAD(&h->tags, entry);
1.30 kristaps 896: free(tag);
897: }
898: }
899:
900:
1.35 kristaps 901: /* FIXME: put in utility file for front-ends. */
1.33 kristaps 902: static int
903: a2offs(const char *p)
904: {
905: int len, i;
906:
907: if (0 == strcmp(p, "left"))
908: return(0);
909: if (0 == strcmp(p, "indent"))
910: return(INDENT + 1);
911: if (0 == strcmp(p, "indent-two"))
912: return((INDENT + 1) * 2);
913:
914: if (0 == (len = (int)strlen(p)))
915: return(0);
916:
917: for (i = 0; i < len - 1; i++)
918: if ( ! isdigit((u_char)p[i]))
919: break;
920:
921: if (i == len - 1)
922: if ('n' == p[len - 1] || 'm' == p[len - 1])
923: return(atoi(p));
924:
925: return(len);
926: }
927:
928:
1.35 kristaps 929: /* FIXME: put in utility file for front-ends. */
1.33 kristaps 930: static int
1.37 kristaps 931: a2list(const struct mdoc_node *bl)
932: {
933: int i;
934:
935: assert(MDOC_BLOCK == bl->type && MDOC_Bl == bl->tok);
936: assert(bl->args);
937:
938: for (i = 0; i < (int)bl->args->argc; i++)
939: switch (bl->args->argv[i].arg) {
940: case (MDOC_Enum):
941: /* FALLTHROUGH */
942: case (MDOC_Dash):
943: /* FALLTHROUGH */
944: case (MDOC_Hyphen):
945: /* FALLTHROUGH */
946: case (MDOC_Bullet):
947: /* FALLTHROUGH */
948: case (MDOC_Tag):
949: /* FALLTHROUGH */
950: case (MDOC_Hang):
951: /* FALLTHROUGH */
952: case (MDOC_Inset):
953: /* FALLTHROUGH */
954: case (MDOC_Diag):
955: /* FALLTHROUGH */
956: case (MDOC_Item):
957: /* FALLTHROUGH */
958: case (MDOC_Column):
959: /* FALLTHROUGH */
960: case (MDOC_Ohang):
961: return(bl->args->argv[i].arg);
962: default:
963: break;
964: }
965:
966: abort();
967: /* NOTREACHED */
968: }
969:
970:
971: /* FIXME: put in utility file for front-ends. */
972: static int
1.33 kristaps 973: a2width(const char *p)
974: {
975: int i, len;
976:
977: if (0 == (len = (int)strlen(p)))
978: return(0);
979: for (i = 0; i < len - 1; i++)
980: if ( ! isdigit((u_char)p[i]))
981: break;
982:
983: if (i == len - 1)
984: if ('n' == p[len - 1] || 'm' == p[len - 1])
985: return(atoi(p) + 2);
986:
987: return(len + 2);
988: }
989:
990:
1.39 ! kristaps 991: /* FIXME: parts should be in a utility file for front-ends. */
! 992: /* ARGSUSED */
! 993: static void
! 994: mdoc_root_post(MDOC_ARGS)
! 995: {
! 996: struct tm *tm;
! 997: struct htmlpair tag[2];
! 998: struct tag *t;
! 999: char b[BUFSIZ], os[BUFSIZ];
! 1000:
! 1001: tm = localtime(&m->date);
! 1002:
! 1003: if (0 == strftime(b, BUFSIZ - 1, "%B %e, %Y", tm))
! 1004: err(EXIT_FAILURE, "strftime");
1.33 kristaps 1005:
1.39 ! kristaps 1006: (void)strlcpy(os, m->os, BUFSIZ);
1.33 kristaps 1007:
1.39 ! kristaps 1008: tag[0].key = ATTR_STYLE;
! 1009: tag[0].val = "width: 100%; margin-top: 1em;";
! 1010: tag[1].key = ATTR_CLASS;
! 1011: tag[1].val = "foot";
! 1012:
! 1013: t = print_otag(h, TAG_DIV, 2, tag);
! 1014:
! 1015: bufinit();
! 1016: bufcat("width: 50%;");
! 1017: bufcat("text-align: left;");
! 1018: bufcat("float: left;");
! 1019: tag[0].key = ATTR_STYLE;
! 1020: tag[0].val = buf;
! 1021: print_otag(h, TAG_SPAN, 1, tag);
! 1022: print_text(h, b);
! 1023: print_stagq(h, t);
! 1024:
! 1025: bufinit();
! 1026: bufcat("width: 50%;");
! 1027: bufcat("text-align: right;");
! 1028: bufcat("float: left;");
! 1029: tag[0].key = ATTR_STYLE;
! 1030: tag[0].val = buf;
! 1031: print_otag(h, TAG_SPAN, 1, tag);
! 1032: print_text(h, os);
! 1033: print_tagq(h, t);
! 1034:
! 1035: }
! 1036:
! 1037:
! 1038: /* FIXME: parts should be in a utility file for front-ends. */
1.30 kristaps 1039: /* ARGSUSED */
1040: static int
1041: mdoc_root_pre(MDOC_ARGS)
1042: {
1.39 ! kristaps 1043: struct htmlpair tag[2];
! 1044: struct tag *t, *tt;
! 1045: char b[BUFSIZ], title[BUFSIZ];
! 1046:
! 1047: assert(m->vol);
! 1048: (void)strlcpy(b, m->vol, BUFSIZ);
! 1049:
! 1050: if (m->arch) {
! 1051: (void)strlcat(b, " (", BUFSIZ);
! 1052: (void)strlcat(b, m->arch, BUFSIZ);
! 1053: (void)strlcat(b, ")", BUFSIZ);
! 1054: }
! 1055:
! 1056: (void)snprintf(title, BUFSIZ - 1, "%s(%d)", m->title, m->msec);
! 1057:
! 1058: tag[0].key = ATTR_CLASS;
! 1059: tag[0].val = "body";
! 1060:
! 1061: t = print_otag(h, TAG_DIV, 1, tag);
! 1062:
! 1063: tag[0].key = ATTR_CLASS;
! 1064: tag[0].val = "head";
! 1065: tag[1].key = ATTR_STYLE;
! 1066: tag[1].val = "margin-bottom: 1em; clear: both;";
! 1067:
! 1068: tt = print_otag(h, TAG_DIV, 2, tag);
! 1069:
! 1070: bufinit();
! 1071: bufcat("width: 30%;");
! 1072: bufcat("text-align: left;");
! 1073: bufcat("float: left;");
! 1074: tag[0].key = ATTR_STYLE;
! 1075: tag[0].val = buf;
! 1076: print_otag(h, TAG_SPAN, 1, tag);
! 1077: print_text(h, b);
! 1078: print_stagq(h, tt);
! 1079:
! 1080: bufinit();
! 1081: bufcat("width: 30%;");
! 1082: bufcat("text-align: center;");
! 1083: bufcat("float: left;");
! 1084: tag[0].key = ATTR_STYLE;
! 1085: tag[0].val = buf;
! 1086: print_otag(h, TAG_SPAN, 1, tag);
! 1087: print_text(h, title);
! 1088: print_stagq(h, tt);
! 1089:
! 1090: bufinit();
! 1091: bufcat("width: 30%;");
! 1092: bufcat("text-align: right;");
! 1093: bufcat("float: left;");
! 1094: tag[0].key = ATTR_STYLE;
! 1095: tag[0].val = buf;
! 1096: print_otag(h, TAG_SPAN, 1, tag);
! 1097: print_text(h, b);
1.30 kristaps 1098:
1.39 ! kristaps 1099: print_stagq(h, t);
1.30 kristaps 1100:
1101: return(1);
1102: }
1103:
1104:
1105: /* ARGSUSED */
1106: static int
1.35 kristaps 1107: mdoc_sh_pre(MDOC_ARGS)
1.30 kristaps 1108: {
1.34 kristaps 1109: struct htmlpair tag[2];
1110:
1.35 kristaps 1111: if (MDOC_HEAD == n->type) {
1112: tag[0].key = ATTR_CLASS;
1113: tag[0].val = "sec-head";
1114: print_otag(h, TAG_DIV, 1, tag);
1115: print_otag(h, TAG_SPAN, 1, tag);
1116: return(1);
1117: } else if (MDOC_BLOCK == n->type) {
1118: tag[0].key = ATTR_CLASS;
1119: tag[0].val = "sec-block";
1.39 ! kristaps 1120:
! 1121: if (n->prev && NULL == n->prev->body->child) {
! 1122: print_otag(h, TAG_DIV, 1, tag);
! 1123: return(1);
! 1124: }
! 1125:
! 1126: tag[1].key = ATTR_STYLE;
! 1127: tag[1].val = "margin-top: 1em;";
! 1128:
! 1129: print_otag(h, TAG_DIV, 2, tag);
1.35 kristaps 1130: return(1);
1131: }
1132:
1133: buffmt("margin-left: %dem;", INDENT);
1134:
1.34 kristaps 1135: tag[0].key = ATTR_CLASS;
1.35 kristaps 1136: tag[0].val = "sec-body";
1137: tag[1].key = ATTR_STYLE;
1138: tag[1].val = buf;
1139:
1140: print_otag(h, TAG_DIV, 2, tag);
1141: return(1);
1142: }
1143:
1144:
1145: /* ARGSUSED */
1146: static int
1147: mdoc_ss_pre(MDOC_ARGS)
1148: {
1149: struct htmlpair tag[2];
1150: int i;
1151:
1152: i = 0;
1153:
1154: if (MDOC_BODY == n->type) {
1155: tag[i].key = ATTR_CLASS;
1156: tag[i++].val = "ssec-body";
1157: if (n->parent->next && n->child) {
1158: bufcat("margin-bottom: 1em;");
1159: tag[i].key = ATTR_STYLE;
1160: tag[i++].val = buf;
1161: }
1162: print_otag(h, TAG_DIV, i, tag);
1163: return(1);
1164: } else if (MDOC_BLOCK == n->type) {
1165: tag[i].key = ATTR_CLASS;
1166: tag[i++].val = "ssec-block";
1167: if (n->prev) {
1168: bufcat("margin-top: 1em;");
1169: tag[i].key = ATTR_STYLE;
1170: tag[i++].val = buf;
1171: }
1172: print_otag(h, TAG_DIV, i, tag);
1173: return(1);
1174: }
1175:
1176: buffmt("margin-left: -%dem;", INDENT - HALFINDENT);
1.34 kristaps 1177:
1.35 kristaps 1178: tag[0].key = ATTR_CLASS;
1179: tag[0].val = "ssec-head";
1.34 kristaps 1180: tag[1].key = ATTR_STYLE;
1.35 kristaps 1181: tag[1].val = buf;
1.30 kristaps 1182:
1.35 kristaps 1183: print_otag(h, TAG_DIV, 2, tag);
1184: print_otag(h, TAG_SPAN, 1, tag);
1.30 kristaps 1185: return(1);
1186: }
1187:
1188:
1189: /* ARGSUSED */
1190: static int
1191: mdoc_fl_pre(MDOC_ARGS)
1192: {
1193: struct htmlpair tag;
1194:
1195: tag.key = ATTR_CLASS;
1196: tag.val = "flag";
1197:
1198: print_otag(h, TAG_SPAN, 1, &tag);
1199: print_text(h, "\\-");
1200: h->flags |= HTML_NOSPACE;
1201: return(1);
1202: }
1203:
1204:
1205: /* ARGSUSED */
1206: static int
1207: mdoc_pp_pre(MDOC_ARGS)
1208: {
1.34 kristaps 1209: struct htmlpair tag;
1.30 kristaps 1210:
1.35 kristaps 1211: bufcat("clear: both;");
1212: bufcat("height: 1em;");
1213:
1.34 kristaps 1214: tag.key = ATTR_STYLE;
1.35 kristaps 1215: tag.val = buf;
1.34 kristaps 1216:
1.35 kristaps 1217: print_otag(h, TAG_DIV, 1, &tag);
1.30 kristaps 1218: return(0);
1219: }
1220:
1221:
1222: /* ARGSUSED */
1223: static int
1224: mdoc_nd_pre(MDOC_ARGS)
1225: {
1.35 kristaps 1226: struct htmlpair tag;
1227:
1228: if (MDOC_BODY != n->type)
1229: return(1);
1.30 kristaps 1230:
1.35 kristaps 1231: /* XXX - this can contain block elements! */
1232: print_text(h, "\\(em");
1233: tag.key = ATTR_CLASS;
1234: tag.val = "desc-body";
1235: print_otag(h, TAG_SPAN, 1, &tag);
1.30 kristaps 1236: return(1);
1237: }
1238:
1239:
1240: /* ARGSUSED */
1241: static int
1242: mdoc_op_pre(MDOC_ARGS)
1243: {
1.35 kristaps 1244: struct htmlpair tag;
1245:
1246: if (MDOC_BODY != n->type)
1247: return(1);
1.30 kristaps 1248:
1.35 kristaps 1249: /* XXX - this can contain block elements! */
1250: print_text(h, "\\(lB");
1251: tag.key = ATTR_CLASS;
1252: tag.val = "opt";
1253: print_otag(h, TAG_SPAN, 1, &tag);
1.30 kristaps 1254: return(1);
1255: }
1256:
1257:
1258: /* ARGSUSED */
1259: static void
1260: mdoc_op_post(MDOC_ARGS)
1261: {
1262:
1263: if (MDOC_BODY != n->type)
1264: return;
1265: h->flags |= HTML_NOSPACE;
1266: print_text(h, "\\(rB");
1267: }
1268:
1269:
1270: static int
1271: mdoc_nm_pre(MDOC_ARGS)
1272: {
1.35 kristaps 1273: struct htmlpair tag;
1.30 kristaps 1274:
1275: if ( ! (HTML_NEWLINE & h->flags))
1.35 kristaps 1276: if (SEC_SYNOPSIS == n->sec) {
1277: tag.key = ATTR_STYLE;
1278: tag.val = "clear: both;";
1279: print_otag(h, TAG_BR, 1, &tag);
1280: }
1.30 kristaps 1281:
1.35 kristaps 1282: tag.key = ATTR_CLASS;
1283: tag.val = "name";
1.30 kristaps 1284:
1.35 kristaps 1285: print_otag(h, TAG_SPAN, 1, &tag);
1.30 kristaps 1286: if (NULL == n->child)
1287: print_text(h, m->name);
1288:
1289: return(1);
1290: }
1291:
1292:
1293: /* ARGSUSED */
1294: static int
1295: mdoc_xr_pre(MDOC_ARGS)
1296: {
1.35 kristaps 1297: struct htmlpair tag[2];
1.30 kristaps 1298:
1.35 kristaps 1299: tag[0].key = ATTR_CLASS;
1300: tag[0].val = "link-man";
1301: tag[1].key = ATTR_HREF;
1302: tag[1].val = "#"; /* TODO */
1.30 kristaps 1303:
1.35 kristaps 1304: print_otag(h, TAG_A, 2, tag);
1.30 kristaps 1305:
1306: n = n->child;
1307: print_text(h, n->string);
1308: if (NULL == (n = n->next))
1309: return(0);
1310:
1311: h->flags |= HTML_NOSPACE;
1312: print_text(h, "(");
1313: h->flags |= HTML_NOSPACE;
1314: print_text(h, n->string);
1315: h->flags |= HTML_NOSPACE;
1316: print_text(h, ")");
1317:
1318: return(0);
1319: }
1.31 kristaps 1320:
1321:
1322: /* ARGSUSED */
1323: static int
1324: mdoc_ns_pre(MDOC_ARGS)
1325: {
1326:
1327: h->flags |= HTML_NOSPACE;
1328: return(1);
1329: }
1330:
1.35 kristaps 1331:
1.31 kristaps 1332: /* ARGSUSED */
1333: static int
1334: mdoc_ar_pre(MDOC_ARGS)
1335: {
1336: struct htmlpair tag;
1337:
1338: tag.key = ATTR_CLASS;
1339: tag.val = "arg";
1340:
1341: print_otag(h, TAG_SPAN, 1, &tag);
1342: return(1);
1343: }
1.33 kristaps 1344:
1.35 kristaps 1345:
1.33 kristaps 1346: /* ARGSUSED */
1347: static int
1348: mdoc_xx_pre(MDOC_ARGS)
1349: {
1350: const char *pp;
1.35 kristaps 1351: struct htmlpair tag;
1.33 kristaps 1352:
1353: switch (n->tok) {
1354: case (MDOC_Bsx):
1355: pp = "BSDI BSD/OS";
1356: break;
1357: case (MDOC_Dx):
1358: pp = "DragonFlyBSD";
1359: break;
1360: case (MDOC_Fx):
1361: pp = "FreeBSD";
1362: break;
1363: case (MDOC_Nx):
1364: pp = "NetBSD";
1365: break;
1366: case (MDOC_Ox):
1367: pp = "OpenBSD";
1368: break;
1369: case (MDOC_Ux):
1370: pp = "UNIX";
1371: break;
1372: default:
1373: return(1);
1374: }
1375:
1.35 kristaps 1376: tag.key = ATTR_CLASS;
1377: tag.val = "unix";
1378:
1379: print_otag(h, TAG_SPAN, 1, &tag);
1.33 kristaps 1380: print_text(h, pp);
1381: return(1);
1382: }
1383:
1384:
1.35 kristaps 1385: /* ARGSUSED */
1.33 kristaps 1386: static int
1.37 kristaps 1387: mdoc_tbl_block_pre(MDOC_ARGS, int t, int w, int o, int c)
1.34 kristaps 1388: {
1389: struct htmlpair tag;
1390:
1.37 kristaps 1391: switch (t) {
1.38 kristaps 1392: case (MDOC_Column):
1393: /* FALLTHROUGH */
1.37 kristaps 1394: case (MDOC_Item):
1395: /* FALLTHROUGH */
1396: case (MDOC_Ohang):
1397: buffmt("margin-left: %dem; clear: both;", o);
1398: break;
1399: default:
1400: buffmt("margin-left: %dem; clear: both;", w + o);
1401: break;
1402: }
1.34 kristaps 1403:
1.37 kristaps 1404: if ( ! c && n->prev && n->prev->body->child)
1.35 kristaps 1405: bufcat("padding-top: 1em;");
1.34 kristaps 1406:
1407: tag.key = ATTR_STYLE;
1408: tag.val = buf;
1409: print_otag(h, TAG_DIV, 1, &tag);
1410: return(1);
1411: }
1412:
1413:
1.35 kristaps 1414: /* ARGSUSED */
1.34 kristaps 1415: static int
1416: mdoc_tbl_body_pre(MDOC_ARGS, int t, int w)
1417: {
1418:
1.37 kristaps 1419: print_otag(h, TAG_DIV, 0, NULL);
1.34 kristaps 1420: return(1);
1421: }
1422:
1423:
1.35 kristaps 1424: /* ARGSUSED */
1.34 kristaps 1425: static int
1.35 kristaps 1426: mdoc_tbl_head_pre(MDOC_ARGS, int t, int w)
1.33 kristaps 1427: {
1.34 kristaps 1428: struct htmlpair tag;
1.37 kristaps 1429: struct ord *ord;
1430: char nbuf[BUFSIZ];
1.34 kristaps 1431:
1.35 kristaps 1432: switch (t) {
1.37 kristaps 1433: case (MDOC_Item):
1.35 kristaps 1434: /* FALLTHROUGH */
1.37 kristaps 1435: case (MDOC_Ohang):
1436: print_otag(h, TAG_DIV, 0, NULL);
1437: break;
1.38 kristaps 1438: case (MDOC_Column):
1439: buffmt("min-width: %dem;", w);
1440: bufcat("clear: none;");
1441: if (n->next && MDOC_HEAD == n->next->type)
1442: bufcat("float: left;");
1443: tag.key = ATTR_STYLE;
1444: tag.val = buf;
1445: print_otag(h, TAG_DIV, 1, &tag);
1446: break;
1.37 kristaps 1447: default:
1.35 kristaps 1448: buffmt("margin-left: -%dem;", w);
1449: bufcat("clear: left;");
1450: bufcat("float: left;");
1451: bufcat("padding-right: 1em;");
1.37 kristaps 1452: tag.key = ATTR_STYLE;
1453: tag.val = buf;
1454: print_otag(h, TAG_DIV, 1, &tag);
1.34 kristaps 1455: break;
1.37 kristaps 1456: }
1457:
1458: switch (t) {
1459: case (MDOC_Diag):
1460: tag.key = ATTR_CLASS;
1461: tag.val = "diag";
1462: print_otag(h, TAG_SPAN, 1, &tag);
1463: break;
1464: case (MDOC_Enum):
1465: ord = SLIST_FIRST(&h->ords);
1466: assert(ord);
1467: nbuf[BUFSIZ - 1] = 0;
1468: (void)snprintf(nbuf, BUFSIZ - 1, "%d.", ord->pos++);
1469: print_text(h, nbuf);
1470: return(0);
1471: case (MDOC_Dash):
1472: print_text(h, "\\(en");
1473: return(0);
1474: case (MDOC_Hyphen):
1475: print_text(h, "\\-");
1476: return(0);
1477: case (MDOC_Bullet):
1478: print_text(h, "\\(bu");
1479: return(0);
1.34 kristaps 1480: default:
1481: break;
1.33 kristaps 1482: }
1483:
1.34 kristaps 1484: return(1);
1485: }
1486:
1487:
1488: static int
1489: mdoc_tbl_pre(MDOC_ARGS, int type)
1490: {
1.38 kristaps 1491: int i, w, o, c, wp;
1492: const struct mdoc_node *bl, *nn;
1.34 kristaps 1493:
1.33 kristaps 1494: bl = n->parent->parent;
1495: if (MDOC_BLOCK != n->type)
1496: bl = bl->parent;
1497:
1.34 kristaps 1498: /* FIXME: fmt_vspace() equivalent. */
1499:
1.33 kristaps 1500: assert(bl->args);
1501:
1.34 kristaps 1502: w = o = c = 0;
1.38 kristaps 1503: wp = -1;
1.34 kristaps 1504:
1505: for (i = 0; i < (int)bl->args->argc; i++)
1.33 kristaps 1506: if (MDOC_Width == bl->args->argv[i].arg) {
1507: assert(bl->args->argv[i].sz);
1.38 kristaps 1508: wp = i;
1.34 kristaps 1509: w = a2width(bl->args->argv[i].value[0]);
1510: } else if (MDOC_Offset == bl->args->argv[i].arg) {
1511: assert(bl->args->argv[i].sz);
1512: o = a2offs(bl->args->argv[i].value[0]);
1513: } else if (MDOC_Compact == bl->args->argv[i].arg)
1514: c = 1;
1.38 kristaps 1515:
1516: if (MDOC_HEAD == n->type && MDOC_Column == type) {
1517: nn = n->parent->child;
1518: assert(nn && MDOC_HEAD == nn->type);
1519: for (i = 0; nn && nn != n; nn = nn->next, i++)
1520: /* Counter... */ ;
1521: assert(nn);
1522: if (wp >= 0 && i < (int)bl->args[wp].argv->sz)
1523: w = a2width(bl->args->argv[wp].value[i]);
1524: }
1.34 kristaps 1525:
1.37 kristaps 1526: switch (type) {
1527: case (MDOC_Enum):
1528: /* FALLTHROUGH */
1529: case (MDOC_Dash):
1530: /* FALLTHROUGH */
1531: case (MDOC_Hyphen):
1532: /* FALLTHROUGH */
1533: case (MDOC_Bullet):
1534: if (w < 4)
1535: w = 4;
1536: break;
1537: case (MDOC_Inset):
1538: /* FALLTHROUGH */
1539: case (MDOC_Diag):
1540: w = 1;
1541: break;
1542: default:
1543: if (0 == w)
1544: w = 10;
1545: break;
1546: }
1547:
1.34 kristaps 1548: switch (n->type) {
1549: case (MDOC_BLOCK):
1550: break;
1551: case (MDOC_HEAD):
1552: return(mdoc_tbl_head_pre(m, n, h, type, w));
1553: case (MDOC_BODY):
1554: return(mdoc_tbl_body_pre(m, n, h, type, w));
1555: default:
1556: abort();
1557: /* NOTREACHED */
1558: }
1559:
1.37 kristaps 1560: return(mdoc_tbl_block_pre(m, n, h, type, w, o, c));
1.34 kristaps 1561: }
1562:
1563:
1564: static int
1.37 kristaps 1565: mdoc_bl_pre(MDOC_ARGS)
1.34 kristaps 1566: {
1.37 kristaps 1567: struct ord *ord;
1.34 kristaps 1568:
1569: if (MDOC_BLOCK != n->type)
1570: return(1);
1.37 kristaps 1571: if (MDOC_Enum != a2list(n))
1572: return(1);
1.34 kristaps 1573:
1.37 kristaps 1574: ord = malloc(sizeof(struct ord));
1575: if (NULL == ord)
1576: err(EXIT_FAILURE, "malloc");
1577: ord->cookie = n;
1578: ord->pos = 1;
1579: SLIST_INSERT_HEAD(&h->ords, ord, entry);
1.33 kristaps 1580:
1581: return(1);
1582: }
1583:
1584:
1.37 kristaps 1585: static void
1586: mdoc_bl_post(MDOC_ARGS)
1.33 kristaps 1587: {
1.37 kristaps 1588: struct ord *ord;
1.33 kristaps 1589:
1.34 kristaps 1590: if (MDOC_BLOCK != n->type)
1.37 kristaps 1591: return;
1592: if (MDOC_Enum != a2list(n))
1593: return;
1.33 kristaps 1594:
1.37 kristaps 1595: ord = SLIST_FIRST(&h->ords);
1596: assert(ord);
1597: SLIST_REMOVE_HEAD(&h->ords, entry);
1598: free(ord);
1.33 kristaps 1599: }
1600:
1601:
1602: static int
1.34 kristaps 1603: mdoc_it_pre(MDOC_ARGS)
1.33 kristaps 1604: {
1.37 kristaps 1605: int type;
1.33 kristaps 1606:
1.34 kristaps 1607: if (MDOC_BLOCK == n->type)
1.37 kristaps 1608: type = a2list(n->parent->parent);
1.34 kristaps 1609: else
1.37 kristaps 1610: type = a2list(n->parent->parent->parent);
1.33 kristaps 1611:
1.37 kristaps 1612: return(mdoc_tbl_pre(m, n, h, type));
1.33 kristaps 1613: }
1.34 kristaps 1614:
1615:
1616: /* ARGSUSED */
1617: static int
1618: mdoc_ex_pre(MDOC_ARGS)
1619: {
1620: const struct mdoc_node *nn;
1621: struct tag *t;
1622: struct htmlpair tag;
1623:
1624: print_text(h, "The");
1625:
1626: tag.key = ATTR_CLASS;
1627: tag.val = "utility";
1628:
1629: for (nn = n->child; nn; nn = nn->next) {
1630: t = print_otag(h, TAG_SPAN, 1, &tag);
1631: print_text(h, nn->string);
1632: print_tagq(h, t);
1633:
1634: h->flags |= HTML_NOSPACE;
1635:
1636: if (nn->next && NULL == nn->next->next)
1637: print_text(h, ", and");
1638: else if (nn->next)
1639: print_text(h, ",");
1640: else
1641: h->flags &= ~HTML_NOSPACE;
1642: }
1643:
1644: if (n->child->next)
1645: print_text(h, "utilities exit");
1646: else
1647: print_text(h, "utility exits");
1648:
1649: print_text(h, "0 on success, and >0 if an error occurs.");
1650: return(0);
1651: }
1652:
1653:
1654: /* ARGSUSED */
1655: static int
1656: mdoc_dq_pre(MDOC_ARGS)
1657: {
1658:
1659: if (MDOC_BODY != n->type)
1660: return(1);
1661: print_text(h, "\\(lq");
1662: h->flags |= HTML_NOSPACE;
1663: return(1);
1664: }
1665:
1666:
1667: /* ARGSUSED */
1668: static void
1669: mdoc_dq_post(MDOC_ARGS)
1670: {
1671:
1672: if (MDOC_BODY != n->type)
1673: return;
1674: h->flags |= HTML_NOSPACE;
1675: print_text(h, "\\(rq");
1676: }
1677:
1678:
1679: /* ARGSUSED */
1680: static int
1681: mdoc_pq_pre(MDOC_ARGS)
1682: {
1683:
1684: if (MDOC_BODY != n->type)
1685: return(1);
1686: print_text(h, "\\&(");
1687: h->flags |= HTML_NOSPACE;
1688: return(1);
1689: }
1690:
1691:
1692: /* ARGSUSED */
1693: static void
1694: mdoc_pq_post(MDOC_ARGS)
1695: {
1696:
1697: if (MDOC_BODY != n->type)
1698: return;
1699: print_text(h, ")");
1700: }
1701:
1702:
1703: /* ARGSUSED */
1704: static int
1705: mdoc_sq_pre(MDOC_ARGS)
1706: {
1707:
1708: if (MDOC_BODY != n->type)
1709: return(1);
1710: print_text(h, "\\(oq");
1711: h->flags |= HTML_NOSPACE;
1712: return(1);
1713: }
1714:
1715:
1716: /* ARGSUSED */
1717: static void
1718: mdoc_sq_post(MDOC_ARGS)
1719: {
1720:
1721: if (MDOC_BODY != n->type)
1722: return;
1723: h->flags |= HTML_NOSPACE;
1724: print_text(h, "\\(aq");
1725: }
1726:
1727:
1728: /* ARGSUSED */
1729: static int
1730: mdoc_em_pre(MDOC_ARGS)
1731: {
1732: struct htmlpair tag;
1733:
1734: tag.key = ATTR_CLASS;
1735: tag.val = "emph";
1736:
1737: print_otag(h, TAG_SPAN, 1, &tag);
1738: return(1);
1739: }
1740:
1741:
1742: /* ARGSUSED */
1743: static int
1744: mdoc_d1_pre(MDOC_ARGS)
1745: {
1.35 kristaps 1746: struct htmlpair tag[2];
1.34 kristaps 1747:
1748: if (MDOC_BLOCK != n->type)
1749: return(1);
1750:
1.35 kristaps 1751: buffmt("margin-left: %dem;", INDENT);
1.34 kristaps 1752:
1.35 kristaps 1753: tag[0].key = ATTR_CLASS;
1754: tag[0].val = "lit-block";
1755: tag[1].key = ATTR_STYLE;
1756: tag[1].val = buf;
1.34 kristaps 1757:
1.35 kristaps 1758: print_otag(h, TAG_DIV, 2, tag);
1.34 kristaps 1759: return(1);
1760: }
1761:
1762:
1763: /* ARGSUSED */
1764: static int
1765: mdoc_sx_pre(MDOC_ARGS)
1766: {
1.35 kristaps 1767: struct htmlpair tag[2];
1.34 kristaps 1768:
1.35 kristaps 1769: tag[0].key = ATTR_HREF;
1770: tag[0].val = "#"; /* XXX */
1771: tag[1].key = ATTR_CLASS;
1772: tag[1].val = "link-sec";
1.34 kristaps 1773:
1.35 kristaps 1774: print_otag(h, TAG_A, 2, tag);
1.34 kristaps 1775: return(1);
1776: }
1.37 kristaps 1777:
1778:
1779: /* ARGSUSED */
1780: static int
1781: mdoc_aq_pre(MDOC_ARGS)
1782: {
1783:
1784: if (MDOC_BODY != n->type)
1785: return(1);
1786: print_text(h, "\\(la");
1787: h->flags |= HTML_NOSPACE;
1788: return(1);
1789: }
1790:
1791:
1792: /* ARGSUSED */
1793: static void
1794: mdoc_aq_post(MDOC_ARGS)
1795: {
1796:
1797: if (MDOC_BODY != n->type)
1798: return;
1799: h->flags |= HTML_NOSPACE;
1800: print_text(h, "\\(ra");
1801: }
1802:
1.39 ! kristaps 1803:
! 1804: /* ARGSUSED */
! 1805: static int
! 1806: mdoc_bd_pre(MDOC_ARGS)
! 1807: {
! 1808: struct htmlpair tag[2];
! 1809: int t, c, o, i;
! 1810: const struct mdoc_node *bl;
! 1811:
! 1812: /* FIXME: fmt_vspace() shit. */
! 1813:
! 1814: if (MDOC_BLOCK == n->type)
! 1815: bl = n;
! 1816: else if (MDOC_HEAD == n->type)
! 1817: return(0);
! 1818: else
! 1819: bl = n->parent;
! 1820:
! 1821: t = o = c = 0;
! 1822:
! 1823: for (i = 0; i < (int)bl->args->argc; i++)
! 1824: switch (bl->args->argv[i].arg) {
! 1825: case (MDOC_Offset):
! 1826: assert(bl->args->argv[i].sz);
! 1827: o = a2offs(bl->args->argv[i].value[0]);
! 1828: break;
! 1829: case (MDOC_Compact):
! 1830: c = 1;
! 1831: break;
! 1832: case (MDOC_Ragged):
! 1833: /* FALLTHROUGH */
! 1834: case (MDOC_Filled):
! 1835: /* FALLTHROUGH */
! 1836: case (MDOC_Unfilled):
! 1837: /* FALLTHROUGH */
! 1838: case (MDOC_Literal):
! 1839: t = bl->args->argv[i].arg;
! 1840: break;
! 1841: }
! 1842:
! 1843: if (MDOC_BLOCK == n->type) {
! 1844: if (o)
! 1845: buffmt("margin-left: %dem;", o);
! 1846: bufcat("margin-top: 1em;");
! 1847: tag[0].key = ATTR_STYLE;
! 1848: tag[0].val = buf;
! 1849: print_otag(h, TAG_DIV, 1, tag);
! 1850: return(1);
! 1851: }
! 1852:
! 1853: switch (t) {
! 1854: case (MDOC_Unfilled):
! 1855: case (MDOC_Literal):
! 1856: break;
! 1857: default:
! 1858: return(1);
! 1859: }
! 1860:
! 1861: bufcat("white-space: pre;");
! 1862: tag[0].key = ATTR_STYLE;
! 1863: tag[0].val = buf;
! 1864: tag[1].key = ATTR_CLASS;
! 1865: tag[1].val = "lit-block";
! 1866:
! 1867: print_otag(h, TAG_DIV, 2, tag);
! 1868:
! 1869: for (n = n->child; n; n = n->next) {
! 1870: h->flags |= HTML_NOSPACE;
! 1871: print_mdoc_node(m, n, h);
! 1872: if (n->next)
! 1873: print_text(h, "\n");
! 1874: }
! 1875:
! 1876: return(0);
! 1877: }
! 1878:
! 1879:
! 1880: /* ARGSUSED */
! 1881: static int
! 1882: mdoc_pa_pre(MDOC_ARGS)
! 1883: {
! 1884: struct htmlpair tag;
! 1885:
! 1886: tag.key = ATTR_CLASS;
! 1887: tag.val = "file";
! 1888:
! 1889: print_otag(h, TAG_SPAN, 1, &tag);
! 1890: return(1);
! 1891: }
! 1892:
! 1893:
! 1894: /* ARGSUSED */
! 1895: static int
! 1896: mdoc_qq_pre(MDOC_ARGS)
! 1897: {
! 1898:
! 1899: if (MDOC_BODY != n->type)
! 1900: return(1);
! 1901: print_text(h, "\\*q");
! 1902: h->flags |= HTML_NOSPACE;
! 1903: return(1);
! 1904: }
! 1905:
! 1906:
! 1907: /* ARGSUSED */
! 1908: static void
! 1909: mdoc_qq_post(MDOC_ARGS)
! 1910: {
! 1911:
! 1912: if (MDOC_BODY != n->type)
! 1913: return;
! 1914: h->flags |= HTML_NOSPACE;
! 1915: print_text(h, "\\*q");
! 1916: }
CVSweb