Annotation of mandoc/man_html.c, Revision 1.7
1.7 ! kristaps 1: /* $Id: man_html.c,v 1.6 2009/10/04 15:24:54 kristaps Exp $ */
1.1 kristaps 2: /*
3: * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
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.
16: */
17: #include <sys/types.h>
18: #include <sys/queue.h>
19:
1.5 kristaps 20: #include <assert.h>
21: #include <ctype.h>
1.4 kristaps 22: #include <err.h>
1.2 kristaps 23: #include <stdio.h>
1.1 kristaps 24: #include <stdlib.h>
1.4 kristaps 25: #include <string.h>
1.1 kristaps 26:
1.7 ! kristaps 27: #include "out.h"
1.1 kristaps 28: #include "html.h"
29: #include "man.h"
30:
1.6 kristaps 31: /* TODO: preserve ident widths. */
32:
33: #define INDENT 5
1.4 kristaps 34: #define HALFINDENT 3
35:
1.3 kristaps 36: #define MAN_ARGS const struct man_meta *m, \
37: const struct man_node *n, \
38: struct html *h
39:
40: struct htmlman {
41: int (*pre)(MAN_ARGS);
42: int (*post)(MAN_ARGS);
43: };
44:
45: static void print_man(MAN_ARGS);
46: static void print_man_head(MAN_ARGS);
1.4 kristaps 47: static void print_man_nodelist(MAN_ARGS);
48: static void print_man_node(MAN_ARGS);
1.3 kristaps 49:
1.7 ! kristaps 50: static int a2width(const struct man_node *,
! 51: struct roffsu *);
1.5 kristaps 52:
1.4 kristaps 53: static int man_br_pre(MAN_ARGS);
1.6 kristaps 54: static int man_HP_pre(MAN_ARGS);
1.5 kristaps 55: static int man_IP_pre(MAN_ARGS);
1.4 kristaps 56: static int man_PP_pre(MAN_ARGS);
57: static void man_root_post(MAN_ARGS);
58: static int man_root_pre(MAN_ARGS);
59: static int man_SH_pre(MAN_ARGS);
60: static int man_SS_pre(MAN_ARGS);
61:
62: #ifdef __linux__
63: extern size_t strlcpy(char *, const char *, size_t);
64: extern size_t strlcat(char *, const char *, size_t);
65: #endif
1.3 kristaps 66:
67: static const struct htmlman mans[MAN_MAX] = {
1.4 kristaps 68: { man_br_pre, NULL }, /* br */
1.3 kristaps 69: { NULL, NULL }, /* TH */
1.4 kristaps 70: { man_SH_pre, NULL }, /* SH */
71: { man_SS_pre, NULL }, /* SS */
1.6 kristaps 72: { man_IP_pre, NULL }, /* TP */
1.4 kristaps 73: { man_PP_pre, NULL }, /* LP */
74: { man_PP_pre, NULL }, /* PP */
75: { man_PP_pre, NULL }, /* P */
1.5 kristaps 76: { man_IP_pre, NULL }, /* IP */
1.6 kristaps 77: { man_HP_pre, NULL }, /* HP */
1.3 kristaps 78: { NULL, NULL }, /* SM */
79: { NULL, NULL }, /* SB */
80: { NULL, NULL }, /* BI */
81: { NULL, NULL }, /* IB */
82: { NULL, NULL }, /* BR */
83: { NULL, NULL }, /* RB */
84: { NULL, NULL }, /* R */
85: { NULL, NULL }, /* B */
86: { NULL, NULL }, /* I */
87: { NULL, NULL }, /* IR */
88: { NULL, NULL }, /* RI */
89: { NULL, NULL }, /* na */
90: { NULL, NULL }, /* i */
1.4 kristaps 91: { man_br_pre, NULL }, /* sp */
1.3 kristaps 92: { NULL, NULL }, /* nf */
93: { NULL, NULL }, /* fi */
94: { NULL, NULL }, /* r */
95: { NULL, NULL }, /* RE */
96: { NULL, NULL }, /* RS */
97: { NULL, NULL }, /* DT */
98: { NULL, NULL }, /* UC */
99: };
100:
1.1 kristaps 101:
102: void
103: html_man(void *arg, const struct man *m)
104: {
1.3 kristaps 105: struct html *h;
106: struct tag *t;
107:
108: h = (struct html *)arg;
109:
110: print_gen_doctype(h);
111:
112: t = print_otag(h, TAG_HTML, 0, NULL);
113: print_man(man_meta(m), man_node(m), h);
114: print_tagq(h, t);
115:
116: printf("\n");
117: }
118:
119:
120: static void
121: print_man(MAN_ARGS)
122: {
123: struct tag *t;
124: struct htmlpair tag;
125:
126: t = print_otag(h, TAG_HEAD, 0, NULL);
127:
128: print_man_head(m, n, h);
129: print_tagq(h, t);
130: t = print_otag(h, TAG_BODY, 0, NULL);
131:
132: tag.key = ATTR_CLASS;
133: tag.val = "body";
134: print_otag(h, TAG_DIV, 1, &tag);
135:
1.4 kristaps 136: print_man_nodelist(m, n, h);
1.3 kristaps 137:
138: print_tagq(h, t);
139: }
140:
141:
142: /* ARGSUSED */
143: static void
144: print_man_head(MAN_ARGS)
145: {
146:
147: print_gen_head(h);
148: bufinit(h);
149: buffmt(h, "%s(%d)", m->title, m->msec);
150:
151: print_otag(h, TAG_TITLE, 0, NULL);
152: print_text(h, h->buf);
1.1 kristaps 153: }
1.4 kristaps 154:
155:
156: static void
157: print_man_nodelist(MAN_ARGS)
158: {
159:
160: print_man_node(m, n, h);
161: if (n->next)
162: print_man_nodelist(m, n->next, h);
163: }
164:
165:
166: static void
167: print_man_node(MAN_ARGS)
168: {
169: int child;
170: struct tag *t;
171:
172: child = 1;
173: t = SLIST_FIRST(&h->tags);
174:
175: bufinit(h);
176:
177: switch (n->type) {
178: case (MAN_ROOT):
179: child = man_root_pre(m, n, h);
180: break;
181: case (MAN_TEXT):
182: print_text(h, n->string);
183: break;
184: default:
185: if (mans[n->tok].pre)
186: child = (*mans[n->tok].pre)(m, n, h);
187: break;
188: }
189:
190: if (child && n->child)
191: print_man_nodelist(m, n->child, h);
192:
193: print_stagq(h, t);
194:
195: bufinit(h);
196:
197: switch (n->type) {
198: case (MAN_ROOT):
199: man_root_post(m, n, h);
200: break;
201: case (MAN_TEXT):
202: break;
203: default:
204: if (mans[n->tok].post)
205: (*mans[n->tok].post)(m, n, h);
206: break;
207: }
208: }
209:
210:
1.5 kristaps 211: static int
1.7 ! kristaps 212: a2width(const struct man_node *n, struct roffsu *su)
1.5 kristaps 213: {
214:
1.6 kristaps 215: if (MAN_TEXT != n->type)
1.7 ! kristaps 216: return(0);
! 217: if (a2roffsu(n->string, su))
! 218: return(1);
1.5 kristaps 219:
1.7 ! kristaps 220: return(0);
1.5 kristaps 221: }
222:
223:
1.4 kristaps 224: /* ARGSUSED */
225: static int
226: man_root_pre(MAN_ARGS)
227: {
228: struct htmlpair tag[2];
229: struct tag *t, *tt;
230: char b[BUFSIZ], title[BUFSIZ];
231:
232: b[0] = 0;
233: if (m->vol)
234: (void)strlcat(b, m->vol, BUFSIZ);
235:
236: (void)snprintf(title, BUFSIZ - 1,
237: "%s(%d)", m->title, m->msec);
238:
1.7 ! kristaps 239: PAIR_CLASS_INIT(&tag[0], "header");
! 240: bufcat_style(h, "width", "100%");
! 241: PAIR_STYLE_INIT(&tag[1], h);
1.4 kristaps 242: t = print_otag(h, TAG_TABLE, 2, tag);
243: tt = print_otag(h, TAG_TR, 0, NULL);
244:
1.7 ! kristaps 245: bufinit(h);
! 246: bufcat_style(h, "width", "10%");
! 247: PAIR_STYLE_INIT(&tag[0], h);
1.4 kristaps 248: print_otag(h, TAG_TD, 1, tag);
249: print_text(h, title);
250: print_stagq(h, tt);
251:
1.7 ! kristaps 252: bufinit(h);
! 253: bufcat_style(h, "width", "80%");
! 254: bufcat_style(h, "white-space", "nowrap");
! 255: bufcat_style(h, "text-align", "center");
! 256: PAIR_STYLE_INIT(&tag[0], h);
1.4 kristaps 257: print_otag(h, TAG_TD, 1, tag);
258: print_text(h, b);
259: print_stagq(h, tt);
260:
1.7 ! kristaps 261: bufinit(h);
! 262: bufcat_style(h, "width", "10%");
! 263: bufcat_style(h, "text-align", "right");
! 264: PAIR_STYLE_INIT(&tag[0], h);
1.4 kristaps 265: print_otag(h, TAG_TD, 1, tag);
266: print_text(h, title);
267: print_tagq(h, t);
268: return(1);
269: }
270:
271:
272: /* ARGSUSED */
273: static void
274: man_root_post(MAN_ARGS)
275: {
276: struct tm tm;
277: struct htmlpair tag[2];
278: struct tag *t, *tt;
279: char b[BUFSIZ];
280:
281: (void)localtime_r(&m->date, &tm);
282:
283: if (0 == strftime(b, BUFSIZ - 1, "%B %e, %Y", &tm))
284: err(EXIT_FAILURE, "strftime");
285:
1.7 ! kristaps 286: PAIR_CLASS_INIT(&tag[0], "footer");
! 287: bufcat_style(h, "width", "100%");
! 288: PAIR_STYLE_INIT(&tag[1], h);
1.4 kristaps 289: t = print_otag(h, TAG_TABLE, 2, tag);
290: tt = print_otag(h, TAG_TR, 0, NULL);
291:
1.7 ! kristaps 292: bufinit(h);
! 293: bufcat_style(h, "width", "50%");
! 294: PAIR_STYLE_INIT(&tag[0], h);
1.4 kristaps 295: print_otag(h, TAG_TD, 1, tag);
296: print_text(h, b);
297: print_stagq(h, tt);
298:
1.7 ! kristaps 299: bufinit(h);
! 300: bufcat_style(h, "width", "50%");
! 301: bufcat_style(h, "text-align", "right");
! 302: PAIR_STYLE_INIT(&tag[0], h);
1.4 kristaps 303: print_otag(h, TAG_TD, 1, tag);
304: if (m->source)
305: print_text(h, m->source);
306: print_tagq(h, t);
307: }
308:
309:
310:
311: /* ARGSUSED */
312: static int
313: man_br_pre(MAN_ARGS)
314: {
1.7 ! kristaps 315: struct roffsu su;
! 316: struct htmlpair tag;
1.4 kristaps 317:
1.7 ! kristaps 318: SCALE_VS_INIT(&su, 1);
! 319:
! 320: if (MAN_sp == n->tok) {
! 321: su.scale = 1;
! 322: if (n->child)
! 323: a2roffsu(n->child->string, &su);
! 324: } else if (MAN_br == n->tok)
! 325: su.scale = 0;
1.4 kristaps 326:
1.7 ! kristaps 327: bufcat_su(h, "height", &su);
! 328: PAIR_STYLE_INIT(&tag, h);
1.4 kristaps 329: print_otag(h, TAG_DIV, 1, &tag);
1.7 ! kristaps 330: return(0);
1.4 kristaps 331: }
332:
333:
334: /* ARGSUSED */
335: static int
336: man_SH_pre(MAN_ARGS)
337: {
1.7 ! kristaps 338: struct htmlpair tag[2];
! 339: struct roffsu su;
1.4 kristaps 340:
341: if (MAN_BODY == n->type) {
1.7 ! kristaps 342: SCALE_HS_INIT(&su, INDENT);
! 343: bufcat_su(h, "margin-left", &su);
! 344: PAIR_CLASS_INIT(&tag[0], "sec-body");
! 345: PAIR_STYLE_INIT(&tag[1], h);
1.4 kristaps 346: print_otag(h, TAG_DIV, 2, tag);
347: return(1);
348: } else if (MAN_BLOCK == n->type) {
1.7 ! kristaps 349: PAIR_CLASS_INIT(&tag[0], "sec-block");
1.4 kristaps 350: if (n->prev && MAN_SH == n->prev->tok)
351: if (NULL == n->prev->body->child) {
352: print_otag(h, TAG_DIV, 1, tag);
353: return(1);
354: }
355:
1.7 ! kristaps 356: SCALE_VS_INIT(&su, 1);
! 357: bufcat_su(h, "margin-top", &su);
1.4 kristaps 358: if (NULL == n->next)
1.7 ! kristaps 359: bufcat_su(h, "margin-bottom", &su);
! 360: PAIR_STYLE_INIT(&tag[1], h);
1.4 kristaps 361: print_otag(h, TAG_DIV, 2, tag);
362: return(1);
363: }
364:
1.7 ! kristaps 365: PAIR_CLASS_INIT(&tag[0], "sec-head");
1.4 kristaps 366: print_otag(h, TAG_DIV, 1, tag);
367: return(1);
368: }
369:
370:
371: /* ARGSUSED */
372: static int
373: man_SS_pre(MAN_ARGS)
374: {
375: struct htmlpair tag[3];
1.7 ! kristaps 376: struct roffsu su;
1.4 kristaps 377:
1.7 ! kristaps 378: SCALE_VS_INIT(&su, 1);
1.4 kristaps 379:
380: if (MAN_BODY == n->type) {
1.7 ! kristaps 381: PAIR_CLASS_INIT(&tag[0], "ssec-body");
1.4 kristaps 382: if (n->parent->next && n->child) {
1.7 ! kristaps 383: bufcat_su(h, "margin-bottom", &su);
! 384: PAIR_STYLE_INIT(&tag[1], h);
! 385: print_otag(h, TAG_DIV, 2, tag);
! 386: return(1);
1.4 kristaps 387: }
388:
1.7 ! kristaps 389: print_otag(h, TAG_DIV, 1, tag);
1.4 kristaps 390: return(1);
391: } else if (MAN_BLOCK == n->type) {
1.7 ! kristaps 392: PAIR_CLASS_INIT(&tag[0], "ssec-block");
1.4 kristaps 393: if (n->prev && MAN_SS == n->prev->tok)
394: if (n->prev->body->child) {
1.7 ! kristaps 395: bufcat_su(h, "margin-top", &su);
! 396: PAIR_STYLE_INIT(&tag[1], h);
! 397: print_otag(h, TAG_DIV, 2, tag);
! 398: return(1);
1.4 kristaps 399: }
400:
1.7 ! kristaps 401: print_otag(h, TAG_DIV, 1, tag);
1.4 kristaps 402: return(1);
403: }
404:
1.7 ! kristaps 405: SCALE_HS_INIT(&su, INDENT - HALFINDENT);
! 406: bufcat_su(h, "margin-left", &su);
! 407: PAIR_CLASS_INIT(&tag[0], "ssec-head");
! 408: PAIR_STYLE_INIT(&tag[1], h);
1.4 kristaps 409: print_otag(h, TAG_DIV, 2, tag);
410: return(1);
411: }
412:
413:
414: /* ARGSUSED */
415: static int
416: man_PP_pre(MAN_ARGS)
417: {
1.5 kristaps 418: struct htmlpair tag;
1.7 ! kristaps 419: struct roffsu su;
1.5 kristaps 420: int i;
1.4 kristaps 421:
422: if (MAN_BLOCK != n->type)
423: return(1);
424:
1.5 kristaps 425: i = 0;
426:
427: if (MAN_ROOT == n->parent->tok) {
1.7 ! kristaps 428: SCALE_HS_INIT(&su, INDENT);
! 429: bufcat_su(h, "margin-left", &su);
! 430: i++;
1.5 kristaps 431: }
432: if (n->next && n->next->child) {
1.7 ! kristaps 433: SCALE_VS_INIT(&su, 1);
! 434: bufcat_su(h, "margin-bottom", &su);
! 435: i++;
1.5 kristaps 436: }
1.4 kristaps 437:
1.7 ! kristaps 438: PAIR_STYLE_INIT(&tag, h);
! 439: print_otag(h, TAG_DIV, i ? 1 : 0, &tag);
1.5 kristaps 440: return(1);
441: }
442:
443:
444: /* ARGSUSED */
445: static int
446: man_IP_pre(MAN_ARGS)
447: {
1.7 ! kristaps 448: struct roffsu su;
1.5 kristaps 449: struct htmlpair tag;
450: const struct man_node *nn;
1.7 ! kristaps 451: int width;
1.5 kristaps 452:
1.7 ! kristaps 453: /*
! 454: * This scattering of 1-BU margins and pads is to make sure that
! 455: * when text overruns its box, the subsequent text isn't flush
! 456: * up against it. However, the rest of the right-hand box must
! 457: * also be adjusted in consideration of this 1-BU space.
! 458: */
! 459:
! 460: if (MAN_BODY == n->type) {
! 461: SCALE_HS_INIT(&su, INDENT);
! 462: bufcat_su(h, "margin-left", &su);
! 463: PAIR_STYLE_INIT(&tag, h);
! 464: print_otag(h, TAG_DIV, 1, &tag);
1.6 kristaps 465: return(1);
466: }
467:
468: nn = MAN_BLOCK == n->type ?
469: n->head->child : n->parent->head->child;
470:
1.7 ! kristaps 471: SCALE_HS_INIT(&su, INDENT);
! 472: width = 0;
1.6 kristaps 473:
1.7 ! kristaps 474: if (MAN_IP == n->tok && NULL != nn)
1.5 kristaps 475: if (NULL != (nn = nn->next)) {
476: for ( ; nn->next; nn = nn->next)
477: /* Do nothing. */ ;
1.7 ! kristaps 478: width = a2width(nn, &su);
1.5 kristaps 479: }
480:
1.7 ! kristaps 481: if (MAN_TP == n->tok && NULL != nn)
! 482: width = a2width(nn, &su);
! 483:
1.5 kristaps 484: if (MAN_BLOCK == n->type) {
1.7 ! kristaps 485: bufcat_su(h, "margin-left", &su);
! 486: bufcat_style(h, "clear", "both");
! 487: PAIR_STYLE_INIT(&tag, h);
1.5 kristaps 488: print_otag(h, TAG_DIV, 1, &tag);
489: return(1);
1.6 kristaps 490: }
491:
1.7 ! kristaps 492: bufcat_su(h, "min-width", &su);
! 493: SCALE_INVERT(&su);
! 494: bufcat_su(h, "margin-left", &su);
! 495: SCALE_HS_INIT(&su, 1);
! 496: bufcat_su(h, "margin-right", &su);
! 497: bufcat_style(h, "clear", "left");
1.6 kristaps 498:
499: if (n->next && n->next->child)
1.7 ! kristaps 500: bufcat_style(h, "float", "left");
1.6 kristaps 501:
1.7 ! kristaps 502: PAIR_STYLE_INIT(&tag, h);
1.6 kristaps 503: print_otag(h, TAG_DIV, 1, &tag);
504:
1.7 ! kristaps 505: /* With a length string, manually omit the last child. */
! 506:
! 507: if ( ! width)
1.6 kristaps 508: return(1);
509:
1.7 ! kristaps 510: if (MAN_IP == n->tok)
! 511: for (nn = n->child; nn->next; nn = nn->next)
! 512: print_man_node(m, nn, h);
! 513: if (MAN_TP == n->tok)
! 514: for (nn = n->child->next; nn; nn = nn->next)
! 515: print_man_node(m, nn, h);
1.6 kristaps 516:
517: return(0);
518: }
519:
520:
521: /* ARGSUSED */
522: static int
523: man_HP_pre(MAN_ARGS)
524: {
525: const struct man_node *nn;
526: struct htmlpair tag;
1.7 ! kristaps 527: struct roffsu su;
1.6 kristaps 528:
529: if (MAN_HEAD == n->type)
530: return(0);
531:
532: nn = MAN_BLOCK == n->type ?
533: n->head->child : n->parent->head->child;
534:
1.7 ! kristaps 535: SCALE_HS_INIT(&su, INDENT);
1.6 kristaps 536:
537: if (NULL != nn)
1.7 ! kristaps 538: (void)a2width(nn, &su);
1.6 kristaps 539:
540: if (MAN_BLOCK == n->type) {
1.7 ! kristaps 541: bufcat_su(h, "margin-left", &su);
! 542: bufcat_style(h, "clear", "both");
! 543: PAIR_STYLE_INIT(&tag, h);
1.5 kristaps 544: print_otag(h, TAG_DIV, 1, &tag);
1.6 kristaps 545: return(1);
546: }
1.5 kristaps 547:
1.7 ! kristaps 548: bufcat_su(h, "margin-left", &su);
! 549: SCALE_INVERT(&su);
! 550: bufcat_su(h, "text-indent", &su);
1.5 kristaps 551:
1.7 ! kristaps 552: PAIR_STYLE_INIT(&tag, h);
1.6 kristaps 553: print_otag(h, TAG_DIV, 1, &tag);
1.4 kristaps 554: return(1);
555: }
1.6 kristaps 556:
CVSweb