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