1 /* $Id: html.c,v 1.1 2009/10/21 19:13:50 schwarze Exp $ */
3 * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
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.
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.
17 #include <sys/types.h>
18 #include <sys/queue.h>
34 #define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
36 #define DOCTYPE "-//W3C//DTD HTML 4.01//EN"
37 #define DTD "http://www.w3.org/TR/html4/strict.dtd"
42 #define HTML_CLRLINE (1 << 0)
43 #define HTML_NOSTACK (1 << 1)
46 static const struct htmldata htmltags[TAG_MAX] = {
47 {"html", HTML_CLRLINE}, /* TAG_HTML */
48 {"head", HTML_CLRLINE}, /* TAG_HEAD */
49 {"body", HTML_CLRLINE}, /* TAG_BODY */
50 {"meta", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */
51 {"title", HTML_CLRLINE}, /* TAG_TITLE */
52 {"div", HTML_CLRLINE}, /* TAG_DIV */
53 {"h1", 0}, /* TAG_H1 */
54 {"h2", 0}, /* TAG_H2 */
55 {"p", HTML_CLRLINE}, /* TAG_P */
56 {"span", 0}, /* TAG_SPAN */
57 {"link", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
58 {"br", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
60 {"table", HTML_CLRLINE}, /* TAG_TABLE */
61 {"col", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_COL */
62 {"tr", HTML_CLRLINE}, /* TAG_TR */
63 {"td", HTML_CLRLINE}, /* TAG_TD */
64 {"li", HTML_CLRLINE}, /* TAG_LI */
65 {"ul", HTML_CLRLINE}, /* TAG_UL */
66 {"ol", HTML_CLRLINE}, /* TAG_OL */
67 {"base", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_BASE */
70 static const char *const htmlattrs[ATTR_MAX] = {
87 html_alloc(char *outopts)
98 if (NULL == (h = calloc(1, sizeof(struct html))))
101 SLIST_INIT(&h->tags);
102 SLIST_INIT(&h->ords);
104 if (NULL == (h->symtab = chars_init(CHARS_HTML))) {
109 while (outopts && *outopts)
110 switch (getsubopt(&outopts, UNCONST(toks), &v)) {
118 h->base_includes = v;
135 h = (struct html *)p;
137 while ( ! SLIST_EMPTY(&h->ords)) {
138 ord = SLIST_FIRST(&h->ords);
139 SLIST_REMOVE_HEAD(&h->ords, entry);
143 while ( ! SLIST_EMPTY(&h->tags)) {
144 tag = SLIST_FIRST(&h->tags);
145 SLIST_REMOVE_HEAD(&h->tags, entry);
150 chars_free(h->symtab);
157 print_gen_head(struct html *h)
159 struct htmlpair tag[4];
161 tag[0].key = ATTR_HTTPEQUIV;
162 tag[0].val = "Content-Type";
163 tag[1].key = ATTR_CONTENT;
164 tag[1].val = "text/html; charset=utf-8";
165 print_otag(h, TAG_META, 2, tag);
167 tag[0].key = ATTR_NAME;
168 tag[0].val = "resource-type";
169 tag[1].key = ATTR_CONTENT;
170 tag[1].val = "document";
171 print_otag(h, TAG_META, 2, tag);
174 tag[0].key = ATTR_REL;
175 tag[0].val = "stylesheet";
176 tag[1].key = ATTR_HREF;
177 tag[1].val = h->style;
178 tag[2].key = ATTR_TYPE;
179 tag[2].val = "text/css";
180 tag[3].key = ATTR_MEDIA;
182 print_otag(h, TAG_LINK, 4, tag);
188 print_spec(struct html *h, const char *p, int len)
194 rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz);
198 for (i = 0; i < (int)sz; i++)
204 print_res(struct html *h, const char *p, int len)
210 rhs = chars_a2res(h->symtab, p, (size_t)len, &sz);
214 for (i = 0; i < (int)sz; i++)
220 print_escape(struct html *h, const char **p)
235 if (0 == *wp || 0 == *(wp + 1)) {
236 *p = 0 == *wp ? wp : wp + 1;
240 print_spec(h, wp, 2);
244 } else if ('*' == *wp) {
253 if (0 == *wp || 0 == *(wp + 1)) {
254 *p = 0 == *wp ? wp : wp + 1;
270 } else if ('f' == *wp) {
295 } else if ('[' != *wp) {
296 print_spec(h, wp, 1);
302 for (j = 0; *wp && ']' != *wp; wp++, j++)
311 print_spec(h, wp - j, j);
313 print_res(h, wp - j, j);
320 print_encode(struct html *h, const char *p)
347 print_otag(struct html *h, enum htmltag tag,
348 int sz, const struct htmlpair *p)
353 if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
354 if (NULL == (t = malloc(sizeof(struct tag))))
355 err(EXIT_FAILURE, "malloc");
357 SLIST_INSERT_HEAD(&h->tags, t, entry);
361 if ( ! (HTML_NOSPACE & h->flags))
362 if ( ! (HTML_CLRLINE & htmltags[tag].flags))
365 printf("<%s", htmltags[tag].name);
366 for (i = 0; i < sz; i++) {
367 printf(" %s=\"", htmlattrs[p[i].key]);
369 print_encode(h, p[i].val);
374 h->flags |= HTML_NOSPACE;
375 if (HTML_CLRLINE & htmltags[tag].flags)
376 h->flags |= HTML_NEWLINE;
378 h->flags &= ~HTML_NEWLINE;
386 print_ctag(struct html *h, enum htmltag tag)
389 printf("</%s>", htmltags[tag].name);
390 if (HTML_CLRLINE & htmltags[tag].flags)
391 h->flags |= HTML_NOSPACE;
392 if (HTML_CLRLINE & htmltags[tag].flags)
393 h->flags |= HTML_NEWLINE;
395 h->flags &= ~HTML_NEWLINE;
401 print_gen_doctype(struct html *h)
404 printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">", DOCTYPE, DTD);
409 print_text(struct html *h, const char *p)
412 if (*p && 0 == *(p + 1))
431 if ( ! (HTML_IGNDELIM & h->flags))
432 h->flags |= HTML_NOSPACE;
438 if ( ! (h->flags & HTML_NOSPACE))
441 h->flags &= ~HTML_NOSPACE;
442 h->flags &= ~HTML_NEWLINE;
447 if (*p && 0 == *(p + 1))
454 h->flags |= HTML_NOSPACE;
463 print_tagq(struct html *h, const struct tag *until)
467 while ( ! SLIST_EMPTY(&h->tags)) {
468 tag = SLIST_FIRST(&h->tags);
469 print_ctag(h, tag->tag);
470 SLIST_REMOVE_HEAD(&h->tags, entry);
472 if (until && tag == until)
479 print_stagq(struct html *h, const struct tag *suntil)
483 while ( ! SLIST_EMPTY(&h->tags)) {
484 tag = SLIST_FIRST(&h->tags);
485 if (suntil && tag == suntil)
487 print_ctag(h, tag->tag);
488 SLIST_REMOVE_HEAD(&h->tags, entry);
495 bufinit(struct html *h)
504 bufcat_style(struct html *h, const char *key, const char *val)
515 bufcat(struct html *h, const char *p)
518 bufncat(h, p, strlen(p));
523 buffmt(struct html *h, const char *fmt, ...)
528 (void)vsnprintf(h->buf + (int)h->buflen,
529 BUFSIZ - h->buflen - 1, fmt, ap);
531 h->buflen = strlen(h->buf);
536 bufncat(struct html *h, const char *p, size_t sz)
539 if (h->buflen + sz > BUFSIZ - 1)
540 sz = BUFSIZ - 1 - h->buflen;
542 (void)strncat(h->buf, p, sz);
548 buffmt_includes(struct html *h, const char *name)
552 pp = h->base_includes;
554 while (NULL != (p = strchr(pp, '%'))) {
555 bufncat(h, pp, (size_t)(p - pp));
572 buffmt_man(struct html *h,
573 const char *name, const char *sec)
580 while (NULL != (p = strchr(pp, '%'))) {
581 bufncat(h, pp, (size_t)(p - pp));
584 bufcat(h, sec ? sec : "1");
601 bufcat_su(struct html *h, const char *p, const struct roffsu *su)
644 buffmt(h, "%s: %f%s;", p, v, u);
647 buffmt(h, "%s: %d%s;", p, (int)v, u);