Annotation of mandoc/html.c, Revision 1.53
1.53 ! kristaps 1: /* $Id: html.c,v 1.52 2009/09/24 09:50:31 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.41 kristaps 17: #include <sys/types.h>
1.30 kristaps 18: #include <sys/queue.h>
19:
1.1 kristaps 20: #include <assert.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.45 kristaps 25: #include <unistd.h>
1.1 kristaps 26:
1.32 kristaps 27: #include "chars.h"
1.51 kristaps 28: #include "html.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.29 kristaps 33: struct htmldata {
34: char *name;
35: int flags;
1.30 kristaps 36: #define HTML_CLRLINE (1 << 0)
37: #define HTML_NOSTACK (1 << 1)
1.29 kristaps 38: };
1.7 kristaps 39:
1.29 kristaps 40: static const struct htmldata htmltags[TAG_MAX] = {
1.30 kristaps 41: {"html", HTML_CLRLINE}, /* TAG_HTML */
42: {"head", HTML_CLRLINE}, /* TAG_HEAD */
43: {"body", HTML_CLRLINE}, /* TAG_BODY */
44: {"meta", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */
1.33 kristaps 45: {"title", HTML_CLRLINE}, /* TAG_TITLE */
1.30 kristaps 46: {"div", HTML_CLRLINE}, /* TAG_DIV */
1.29 kristaps 47: {"h1", 0}, /* TAG_H1 */
48: {"h2", 0}, /* TAG_H2 */
1.30 kristaps 49: {"p", HTML_CLRLINE}, /* TAG_P */
1.29 kristaps 50: {"span", 0}, /* TAG_SPAN */
1.30 kristaps 51: {"link", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
52: {"br", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
53: {"a", 0}, /* TAG_A */
1.33 kristaps 54: {"table", HTML_CLRLINE}, /* TAG_TABLE */
55: {"col", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_COL */
56: {"tr", HTML_CLRLINE}, /* TAG_TR */
57: {"td", HTML_CLRLINE}, /* TAG_TD */
1.34 kristaps 58: {"li", HTML_CLRLINE}, /* TAG_LI */
59: {"ul", HTML_CLRLINE}, /* TAG_UL */
60: {"ol", HTML_CLRLINE}, /* TAG_OL */
1.41 kristaps 61: {"base", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_BASE */
1.29 kristaps 62: };
1.10 kristaps 63:
1.29 kristaps 64: static const char *const htmlattrs[ATTR_MAX] = {
65: "http-equiv",
66: "content",
67: "name",
68: "rel",
69: "href",
70: "type",
71: "media",
1.33 kristaps 72: "class",
73: "style",
74: "width",
75: "valign",
1.29 kristaps 76: };
1.10 kristaps 77:
1.33 kristaps 78: #ifdef __linux__
1.43 kristaps 79: extern int getsubopt(char **, char * const *, char **);
1.33 kristaps 80: #endif
1.29 kristaps 81:
82: void *
1.43 kristaps 83: html_alloc(char *outopts)
1.10 kristaps 84: {
1.30 kristaps 85: struct html *h;
1.53 ! kristaps 86: char *toks[4], *v;
1.43 kristaps 87:
88: toks[0] = "style";
1.53 ! kristaps 89: toks[1] = "man";
1.43 kristaps 90: toks[2] = NULL;
1.30 kristaps 91:
92: if (NULL == (h = calloc(1, sizeof(struct html))))
93: return(NULL);
1.10 kristaps 94:
1.37 kristaps 95: SLIST_INIT(&h->tags);
96: SLIST_INIT(&h->ords);
97:
1.32 kristaps 98: if (NULL == (h->symtab = chars_init(CHARS_HTML))) {
99: free(h);
100: return(NULL);
101: }
1.41 kristaps 102:
1.53 ! kristaps 103: h->base_man = "%N.%S.html";
! 104:
1.47 kristaps 105: while (outopts && *outopts)
1.43 kristaps 106: switch (getsubopt(&outopts, toks, &v)) {
107: case (0):
108: h->style = v;
109: break;
110: case (1):
1.53 ! kristaps 111: h->base_man = v;
1.43 kristaps 112: break;
113: default:
114: break;
115: }
116:
1.30 kristaps 117: return(h);
1.29 kristaps 118: }
1.10 kristaps 119:
1.33 kristaps 120:
1.29 kristaps 121: void
122: html_free(void *p)
123: {
1.30 kristaps 124: struct tag *tag;
1.37 kristaps 125: struct ord *ord;
1.30 kristaps 126: struct html *h;
127:
128: h = (struct html *)p;
1.10 kristaps 129:
1.37 kristaps 130: while ( ! SLIST_EMPTY(&h->ords)) {
131: ord = SLIST_FIRST(&h->ords);
132: SLIST_REMOVE_HEAD(&h->ords, entry);
133: free(ord);
134: }
135:
136: while ( ! SLIST_EMPTY(&h->tags)) {
137: tag = SLIST_FIRST(&h->tags);
138: SLIST_REMOVE_HEAD(&h->tags, entry);
1.30 kristaps 139: free(tag);
140: }
1.36 kristaps 141:
1.53 ! kristaps 142: if (h->buf)
! 143: free(h->buf);
1.36 kristaps 144: if (h->symtab)
145: chars_free(h->symtab);
1.53 ! kristaps 146:
1.30 kristaps 147: free(h);
1.10 kristaps 148: }
1.2 kristaps 149:
1.33 kristaps 150:
1.51 kristaps 151: void
1.29 kristaps 152: print_gen_head(struct html *h)
153: {
1.41 kristaps 154: struct htmlpair tag[4];
155:
156: tag[0].key = ATTR_HTTPEQUIV;
157: tag[0].val = "Content-Type";
158: tag[1].key = ATTR_CONTENT;
159: tag[1].val = "text/html; charset=utf-8";
160: print_otag(h, TAG_META, 2, tag);
161:
162: tag[0].key = ATTR_NAME;
163: tag[0].val = "resource-type";
164: tag[1].key = ATTR_CONTENT;
165: tag[1].val = "document";
166: print_otag(h, TAG_META, 2, tag);
167:
168: if (h->style) {
169: tag[0].key = ATTR_REL;
170: tag[0].val = "stylesheet";
171: tag[1].key = ATTR_HREF;
172: tag[1].val = h->style;
173: tag[2].key = ATTR_TYPE;
174: tag[2].val = "text/css";
175: tag[3].key = ATTR_MEDIA;
176: tag[3].val = "all";
177: print_otag(h, TAG_LINK, 4, tag);
178: }
1.4 kristaps 179: }
180:
1.33 kristaps 181:
1.29 kristaps 182: static void
1.32 kristaps 183: print_spec(struct html *h, const char *p, int len)
184: {
185: const char *rhs;
186: int i;
187: size_t sz;
188:
189: rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz);
190:
191: if (NULL == rhs)
192: return;
193: for (i = 0; i < (int)sz; i++)
194: putchar(rhs[i]);
195: }
196:
1.33 kristaps 197:
1.32 kristaps 198: static void
199: print_res(struct html *h, const char *p, int len)
200: {
201: const char *rhs;
202: int i;
203: size_t sz;
204:
205: rhs = chars_a2res(h->symtab, p, (size_t)len, &sz);
206:
207: if (NULL == rhs)
208: return;
209: for (i = 0; i < (int)sz; i++)
210: putchar(rhs[i]);
211: }
212:
1.33 kristaps 213:
1.32 kristaps 214: static void
215: print_escape(struct html *h, const char **p)
216: {
217: int j, type;
218: const char *wp;
219:
220: wp = *p;
221: type = 1;
222:
223: if (0 == *(++wp)) {
224: *p = wp;
225: return;
226: }
227:
228: if ('(' == *wp) {
229: wp++;
230: if (0 == *wp || 0 == *(wp + 1)) {
231: *p = 0 == *wp ? wp : wp + 1;
232: return;
233: }
234:
235: print_spec(h, wp, 2);
236: *p = ++wp;
237: return;
238:
239: } else if ('*' == *wp) {
240: if (0 == *(++wp)) {
241: *p = wp;
242: return;
243: }
244:
245: switch (*wp) {
246: case ('('):
247: wp++;
248: if (0 == *wp || 0 == *(wp + 1)) {
249: *p = 0 == *wp ? wp : wp + 1;
250: return;
251: }
252:
253: print_res(h, wp, 2);
254: *p = ++wp;
255: return;
256: case ('['):
257: type = 0;
258: break;
259: default:
260: print_res(h, wp, 1);
261: *p = wp;
262: return;
263: }
264:
265: } else if ('f' == *wp) {
266: if (0 == *(++wp)) {
267: *p = wp;
268: return;
269: }
270:
271: switch (*wp) {
272: case ('B'):
273: /* TODO */
274: break;
275: case ('I'):
276: /* TODO */
277: break;
278: case ('P'):
279: /* FALLTHROUGH */
280: case ('R'):
281: /* TODO */
282: break;
283: default:
284: break;
285: }
286:
287: *p = wp;
288: return;
289:
290: } else if ('[' != *wp) {
291: print_spec(h, wp, 1);
292: *p = wp;
293: return;
294: }
295:
296: wp++;
297: for (j = 0; *wp && ']' != *wp; wp++, j++)
298: /* Loop... */ ;
299:
300: if (0 == *wp) {
301: *p = wp;
302: return;
303: }
304:
305: if (type)
306: print_spec(h, wp - j, j);
307: else
308: print_res(h, wp - j, j);
309:
310: *p = wp;
311: }
312:
1.9 kristaps 313:
1.29 kristaps 314: static void
1.32 kristaps 315: print_encode(struct html *h, const char *p)
1.29 kristaps 316: {
1.14 kristaps 317:
1.32 kristaps 318: for (; *p; p++) {
1.34 kristaps 319: if ('\\' == *p) {
320: print_escape(h, &p);
321: continue;
322: }
323: switch (*p) {
324: case ('<'):
325: printf("<");
326: break;
327: case ('>'):
328: printf(">");
329: break;
330: case ('&'):
331: printf("&");
332: break;
333: default:
1.32 kristaps 334: putchar(*p);
1.34 kristaps 335: break;
1.32 kristaps 336: }
337: }
1.14 kristaps 338: }
339:
340:
1.51 kristaps 341: struct tag *
1.29 kristaps 342: print_otag(struct html *h, enum htmltag tag,
343: int sz, const struct htmlpair *p)
1.14 kristaps 344: {
1.29 kristaps 345: int i;
1.30 kristaps 346: struct tag *t;
347:
348: if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
349: if (NULL == (t = malloc(sizeof(struct tag))))
350: err(EXIT_FAILURE, "malloc");
351: t->tag = tag;
1.37 kristaps 352: SLIST_INSERT_HEAD(&h->tags, t, entry);
1.30 kristaps 353: } else
354: t = NULL;
1.29 kristaps 355:
356: if ( ! (HTML_NOSPACE & h->flags))
1.30 kristaps 357: if ( ! (HTML_CLRLINE & htmltags[tag].flags))
1.29 kristaps 358: printf(" ");
359:
360: printf("<%s", htmltags[tag].name);
361: for (i = 0; i < sz; i++) {
362: printf(" %s=\"", htmlattrs[p[i].key]);
363: assert(p->val);
1.32 kristaps 364: print_encode(h, p[i].val);
1.29 kristaps 365: printf("\"");
366: }
367: printf(">");
1.14 kristaps 368:
1.29 kristaps 369: h->flags |= HTML_NOSPACE;
1.30 kristaps 370: if (HTML_CLRLINE & htmltags[tag].flags)
371: h->flags |= HTML_NEWLINE;
372: else
373: h->flags &= ~HTML_NEWLINE;
1.14 kristaps 374:
1.30 kristaps 375: return(t);
1.14 kristaps 376: }
377:
378:
379: /* ARGSUSED */
1.29 kristaps 380: static void
381: print_ctag(struct html *h, enum htmltag tag)
1.14 kristaps 382: {
383:
1.29 kristaps 384: printf("</%s>", htmltags[tag].name);
1.30 kristaps 385: if (HTML_CLRLINE & htmltags[tag].flags)
1.29 kristaps 386: h->flags |= HTML_NOSPACE;
1.30 kristaps 387: if (HTML_CLRLINE & htmltags[tag].flags)
388: h->flags |= HTML_NEWLINE;
389: else
390: h->flags &= ~HTML_NEWLINE;
1.14 kristaps 391: }
392:
393:
1.29 kristaps 394: /* ARGSUSED */
1.51 kristaps 395: void
1.29 kristaps 396: print_gen_doctype(struct html *h)
1.1 kristaps 397: {
1.29 kristaps 398:
1.46 kristaps 399: printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">", DOCTYPE, DTD);
1.1 kristaps 400: }
401:
402:
1.51 kristaps 403: void
1.29 kristaps 404: print_text(struct html *h, const char *p)
1.1 kristaps 405: {
406:
1.29 kristaps 407: if (*p && 0 == *(p + 1))
408: switch (*p) {
409: case('.'):
410: /* FALLTHROUGH */
411: case(','):
412: /* FALLTHROUGH */
413: case(';'):
414: /* FALLTHROUGH */
415: case(':'):
416: /* FALLTHROUGH */
417: case('?'):
418: /* FALLTHROUGH */
419: case('!'):
420: /* FALLTHROUGH */
421: case(')'):
422: /* FALLTHROUGH */
423: case(']'):
424: /* FALLTHROUGH */
425: case('}'):
1.52 kristaps 426: if ( ! (HTML_IGNDELIM & h->flags))
427: h->flags |= HTML_NOSPACE;
1.30 kristaps 428: break;
1.29 kristaps 429: default:
430: break;
431: }
1.1 kristaps 432:
1.29 kristaps 433: if ( ! (h->flags & HTML_NOSPACE))
434: printf(" ");
1.30 kristaps 435:
1.29 kristaps 436: h->flags &= ~HTML_NOSPACE;
1.30 kristaps 437: h->flags &= ~HTML_NEWLINE;
1.1 kristaps 438:
1.29 kristaps 439: if (p)
1.32 kristaps 440: print_encode(h, p);
1.8 kristaps 441:
1.29 kristaps 442: if (*p && 0 == *(p + 1))
443: switch (*p) {
444: case('('):
445: /* FALLTHROUGH */
446: case('['):
447: /* FALLTHROUGH */
448: case('{'):
449: h->flags |= HTML_NOSPACE;
1.30 kristaps 450: break;
1.29 kristaps 451: default:
452: break;
453: }
1.1 kristaps 454: }
1.30 kristaps 455:
456:
1.51 kristaps 457: void
1.30 kristaps 458: print_tagq(struct html *h, const struct tag *until)
459: {
460: struct tag *tag;
461:
1.37 kristaps 462: while ( ! SLIST_EMPTY(&h->tags)) {
463: tag = SLIST_FIRST(&h->tags);
1.30 kristaps 464: print_ctag(h, tag->tag);
1.37 kristaps 465: SLIST_REMOVE_HEAD(&h->tags, entry);
1.30 kristaps 466: free(tag);
467: if (until && tag == until)
468: return;
469: }
470: }
471:
472:
1.51 kristaps 473: void
1.30 kristaps 474: print_stagq(struct html *h, const struct tag *suntil)
475: {
476: struct tag *tag;
477:
1.37 kristaps 478: while ( ! SLIST_EMPTY(&h->tags)) {
479: tag = SLIST_FIRST(&h->tags);
1.30 kristaps 480: if (suntil && tag == suntil)
481: return;
482: print_ctag(h, tag->tag);
1.37 kristaps 483: SLIST_REMOVE_HEAD(&h->tags, entry);
1.30 kristaps 484: free(tag);
485: }
486: }
CVSweb