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