=================================================================== RCS file: /cvs/mandoc/html.c,v retrieving revision 1.31 retrieving revision 1.33 diff -u -p -r1.31 -r1.33 --- mandoc/html.c 2009/09/17 07:41:28 1.31 +++ mandoc/html.c 2009/09/17 13:17:30 1.33 @@ -1,4 +1,4 @@ -/* $Id: html.c,v 1.31 2009/09/17 07:41:28 kristaps Exp $ */ +/* $Id: html.c,v 1.33 2009/09/17 13:17:30 kristaps Exp $ */ /* * Copyright (c) 2008, 2009 Kristaps Dzonsons * @@ -17,16 +17,22 @@ #include #include +#include #include #include #include +#include +#include "chars.h" #include "mdoc.h" #include "man.h" #define DOCTYPE "-//W3C//DTD HTML 4.01//EN" #define DTD "http://www.w3.org/TR/html4/strict.dtd" +#define INDENT 5 +#define HALFINDENT 3 + enum htmltag { TAG_HTML, TAG_HEAD, @@ -41,6 +47,10 @@ enum htmltag { TAG_LINK, TAG_BR, TAG_A, + TAG_TABLE, + TAG_COL, + TAG_TR, + TAG_TD, TAG_MAX }; @@ -53,6 +63,9 @@ enum htmlattr { ATTR_TYPE, ATTR_MEDIA, ATTR_CLASS, + ATTR_STYLE, + ATTR_WIDTH, + ATTR_VALIGN, ATTR_MAX }; @@ -68,7 +81,7 @@ static const struct htmldata htmltags[TAG_MAX] = { {"head", HTML_CLRLINE}, /* TAG_HEAD */ {"body", HTML_CLRLINE}, /* TAG_BODY */ {"meta", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_META */ - {"title", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_TITLE */ + {"title", HTML_CLRLINE}, /* TAG_TITLE */ {"div", HTML_CLRLINE}, /* TAG_DIV */ {"h1", 0}, /* TAG_H1 */ {"h2", 0}, /* TAG_H2 */ @@ -77,6 +90,10 @@ static const struct htmldata htmltags[TAG_MAX] = { {"link", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */ {"br", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */ {"a", 0}, /* TAG_A */ + {"table", HTML_CLRLINE}, /* TAG_TABLE */ + {"col", HTML_CLRLINE | HTML_NOSTACK}, /* TAG_COL */ + {"tr", HTML_CLRLINE}, /* TAG_TR */ + {"td", HTML_CLRLINE}, /* TAG_TD */ }; static const char *const htmlattrs[ATTR_MAX] = { @@ -87,7 +104,10 @@ static const char *const htmlattrs[ATTR_MAX] = { "href", "type", "media", - "class" + "class", + "style", + "width", + "valign", }; struct htmlpair { @@ -107,6 +127,7 @@ struct html { #define HTML_NOSPACE (1 << 0) #define HTML_NEWLINE (1 << 1) struct tagq stack; + void *symtab; }; #define MDOC_ARGS const struct mdoc_meta *m, \ @@ -134,12 +155,23 @@ static struct tag *print_otag(struct html *, enum htm static void print_tagq(struct html *, const struct tag *); static void print_stagq(struct html *, const struct tag *); static void print_ctag(struct html *, enum htmltag); -static void print_encode(const char *); +static void print_encode(struct html *, const char *); +static void print_escape(struct html *, const char **); static void print_text(struct html *, const char *); +static void print_res(struct html *, const char *, int); +static void print_spec(struct html *, const char *, int); + +static int a2width(const char *); +static int a2offs(const char *); + +static int mdoc_list_pre(MDOC_ARGS); static int mdoc_root_pre(MDOC_ARGS); +static int mdoc_hang_pre(MDOC_ARGS); static int mdoc_ar_pre(MDOC_ARGS); +static int mdoc_bl_pre(MDOC_ARGS); static int mdoc_fl_pre(MDOC_ARGS); +static int mdoc_it_pre(MDOC_ARGS); static int mdoc_nd_pre(MDOC_ARGS); static int mdoc_nm_pre(MDOC_ARGS); static int mdoc_ns_pre(MDOC_ARGS); @@ -149,7 +181,13 @@ static int mdoc_pp_pre(MDOC_ARGS); static int mdoc_sh_pre(MDOC_ARGS); static int mdoc_ss_pre(MDOC_ARGS); static int mdoc_xr_pre(MDOC_ARGS); +static int mdoc_xx_pre(MDOC_ARGS); +#ifdef __linux__ +extern size_t strlcpy(char *, const char *, size_t); +extern size_t strlcat(char *, const char *, size_t); +#endif + static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Ap */ {NULL, NULL}, /* Dd */ @@ -162,9 +200,9 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Dl */ {NULL, NULL}, /* Bd */ {NULL, NULL}, /* Ed */ - {NULL, NULL}, /* Bl */ + {mdoc_bl_pre, NULL}, /* Bl */ {NULL, NULL}, /* El */ - {NULL, NULL}, /* It */ + {mdoc_it_pre, NULL}, /* It */ {NULL, NULL}, /* Ad */ {NULL, NULL}, /* An */ {mdoc_ar_pre, NULL}, /* Ar */ @@ -211,7 +249,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Bf */ {NULL, NULL}, /* Bo */ {NULL, NULL}, /* Bq */ - {NULL, NULL}, /* Bsx */ + {mdoc_xx_pre, NULL}, /* Bsx */ {NULL, NULL}, /* Bx */ {NULL, NULL}, /* Db */ {NULL, NULL}, /* Dc */ @@ -221,12 +259,12 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Ef */ {NULL, NULL}, /* Em */ {NULL, NULL}, /* Eo */ - {NULL, NULL}, /* Fx */ + {mdoc_xx_pre, NULL}, /* Fx */ {NULL, NULL}, /* Ms */ {NULL, NULL}, /* No */ {mdoc_ns_pre, NULL}, /* Ns */ - {NULL, NULL}, /* Nx */ - {NULL, NULL}, /* Ox */ + {mdoc_xx_pre, NULL}, /* Nx */ + {mdoc_xx_pre, NULL}, /* Ox */ {NULL, NULL}, /* Pc */ {NULL, NULL}, /* Pf */ {NULL, NULL}, /* Po */ @@ -244,7 +282,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* Sx */ {NULL, NULL}, /* Sy */ {NULL, NULL}, /* Tn */ - {NULL, NULL}, /* Ux */ + {mdoc_xx_pre, NULL}, /* Ux */ {NULL, NULL}, /* Xc */ {NULL, NULL}, /* Xo */ {NULL, NULL}, /* Fo */ @@ -267,7 +305,7 @@ static const struct htmlmdoc mdocs[MDOC_MAX] = { {NULL, NULL}, /* %C */ {NULL, NULL}, /* Es */ {NULL, NULL}, /* En */ - {NULL, NULL}, /* Dx */ + {mdoc_xx_pre, NULL}, /* Dx */ {NULL, NULL}, /* %Q */ {NULL, NULL}, /* br */ {NULL, NULL}, /* sp */ @@ -317,6 +355,10 @@ html_alloc(void) return(NULL); SLIST_INIT(&h->stack); + if (NULL == (h->symtab = chars_init(CHARS_HTML))) { + free(h); + return(NULL); + } return(h); } @@ -393,7 +435,7 @@ print_mdoc_head(MDOC_ARGS) print_gen_head(h); print_otag(h, TAG_TITLE, 0, NULL); - print_encode(m->title); + print_encode(h, m->title); } @@ -471,7 +513,7 @@ print_man_head(MAN_ARGS) print_gen_head(h); print_otag(h, TAG_TITLE, 0, NULL); - print_encode(m->title); + print_encode(h, m->title); } @@ -485,13 +527,151 @@ print_man_body(MAN_ARGS) static void -print_encode(const char *p) +print_spec(struct html *h, const char *p, int len) { + const char *rhs; + int i; + size_t sz; - printf("%s", p); /* XXX */ + rhs = chars_a2ascii(h->symtab, p, (size_t)len, &sz); + + if (NULL == rhs) + return; + for (i = 0; i < (int)sz; i++) + putchar(rhs[i]); } +static void +print_res(struct html *h, const char *p, int len) +{ + const char *rhs; + int i; + size_t sz; + + rhs = chars_a2res(h->symtab, p, (size_t)len, &sz); + + if (NULL == rhs) + return; + for (i = 0; i < (int)sz; i++) + putchar(rhs[i]); +} + + +static void +print_escape(struct html *h, const char **p) +{ + int j, type; + const char *wp; + + wp = *p; + type = 1; + + if (0 == *(++wp)) { + *p = wp; + return; + } + + if ('(' == *wp) { + wp++; + if (0 == *wp || 0 == *(wp + 1)) { + *p = 0 == *wp ? wp : wp + 1; + return; + } + + print_spec(h, wp, 2); + *p = ++wp; + return; + + } else if ('*' == *wp) { + if (0 == *(++wp)) { + *p = wp; + return; + } + + switch (*wp) { + case ('('): + wp++; + if (0 == *wp || 0 == *(wp + 1)) { + *p = 0 == *wp ? wp : wp + 1; + return; + } + + print_res(h, wp, 2); + *p = ++wp; + return; + case ('['): + type = 0; + break; + default: + print_res(h, wp, 1); + *p = wp; + return; + } + + } else if ('f' == *wp) { + if (0 == *(++wp)) { + *p = wp; + return; + } + + switch (*wp) { + case ('B'): + /* TODO */ + break; + case ('I'): + /* TODO */ + break; + case ('P'): + /* FALLTHROUGH */ + case ('R'): + /* TODO */ + break; + default: + break; + } + + *p = wp; + return; + + } else if ('[' != *wp) { + print_spec(h, wp, 1); + *p = wp; + return; + } + + wp++; + for (j = 0; *wp && ']' != *wp; wp++, j++) + /* Loop... */ ; + + if (0 == *wp) { + *p = wp; + return; + } + + if (type) + print_spec(h, wp - j, j); + else + print_res(h, wp - j, j); + + *p = wp; +} + + +static void +print_encode(struct html *h, const char *p) +{ + + for (; *p; p++) { + if ('\\' != *p) { + putchar(*p); + continue; + } + print_escape(h, &p); + } +} + + static struct tag * print_otag(struct html *h, enum htmltag tag, int sz, const struct htmlpair *p) @@ -515,7 +695,7 @@ print_otag(struct html *h, enum htmltag tag, for (i = 0; i < sz; i++) { printf(" %s=\"", htmlattrs[p[i].key]); assert(p->val); - print_encode(p[i].val); + print_encode(h, p[i].val); printf("\""); } printf(">"); @@ -590,7 +770,7 @@ print_text(struct html *h, const char *p) h->flags &= ~HTML_NEWLINE; if (p) - print_encode(p); + print_encode(h, p); if (*p && 0 == *(p + 1)) switch (*p) { @@ -639,6 +819,54 @@ print_stagq(struct html *h, const struct tag *suntil) } +static int +a2offs(const char *p) +{ + int len, i; + + if (0 == strcmp(p, "left")) + return(0); + if (0 == strcmp(p, "indent")) + return(INDENT + 1); + if (0 == strcmp(p, "indent-two")) + return((INDENT + 1) * 2); + + if (0 == (len = (int)strlen(p))) + return(0); + + for (i = 0; i < len - 1; i++) + if ( ! isdigit((u_char)p[i])) + break; + + if (i == len - 1) + if ('n' == p[len - 1] || 'm' == p[len - 1]) + return(atoi(p)); + + return(len); +} + + +static int +a2width(const char *p) +{ + int i, len; + + if (0 == (len = (int)strlen(p))) + return(0); + for (i = 0; i < len - 1; i++) + if ( ! isdigit((u_char)p[i])) + break; + + if (i == len - 1) + if ('n' == p[len - 1] || 'm' == p[len - 1]) + return(atoi(p) + 2); + + return(len + 2); +} + + + + /* ARGSUSED */ static int mdoc_root_pre(MDOC_ARGS) @@ -659,7 +887,7 @@ mdoc_ss_pre(MDOC_ARGS) { if (MDOC_BODY == n->type) - print_otag(h, TAG_P, 0, NULL); + print_otag(h, TAG_DIV, 0, NULL); if (MDOC_HEAD == n->type) print_otag(h, TAG_H2, 0, NULL); return(1); @@ -755,7 +983,7 @@ mdoc_sh_pre(MDOC_ARGS) { if (MDOC_BODY == n->type) - print_otag(h, TAG_P, 0, NULL); + print_otag(h, TAG_DIV, 0, NULL); if (MDOC_HEAD == n->type) print_otag(h, TAG_H1, 0, NULL); return(1); @@ -798,7 +1026,6 @@ mdoc_ns_pre(MDOC_ARGS) return(1); } - /* ARGSUSED */ static int mdoc_ar_pre(MDOC_ARGS) @@ -810,4 +1037,191 @@ mdoc_ar_pre(MDOC_ARGS) print_otag(h, TAG_SPAN, 1, &tag); return(1); +} + +/* ARGSUSED */ +static int +mdoc_xx_pre(MDOC_ARGS) +{ + const char *pp; + + switch (n->tok) { + case (MDOC_Bsx): + pp = "BSDI BSD/OS"; + break; + case (MDOC_Dx): + pp = "DragonFlyBSD"; + break; + case (MDOC_Fx): + pp = "FreeBSD"; + break; + case (MDOC_Nx): + pp = "NetBSD"; + break; + case (MDOC_Ox): + pp = "OpenBSD"; + break; + case (MDOC_Ux): + pp = "UNIX"; + break; + default: + return(1); + } + + print_text(h, pp); + return(1); +} + + +static int +mdoc_hang_pre(MDOC_ARGS) +{ + int i, width, offs; + struct htmlpair tag; + char buf[BUFSIZ]; + const struct mdoc_node *bl; + + if (MDOC_BODY == n->type) { + print_otag(h, TAG_DIV, 0, NULL); + return(1); + } + + bl = n->parent->parent; + if (MDOC_BLOCK != n->type) + bl = bl->parent; + + assert(bl->args); + + for (width = i = 0; i < (int)bl->args->argc; i++) + if (MDOC_Width == bl->args->argv[i].arg) { + assert(bl->args->argv[i].sz); + width = a2width(bl->args->argv[i].value[0]); + break; + } else if (MDOC_Offset == bl->args->argv[i].arg) { + assert(bl->args->argv[i].sz); + offs = a2offs(bl->args->argv[i].value[0]); + break; + } + + if (0 == width) + width = 10; + + width *= 10; + + if (MDOC_BLOCK == n->type) + snprintf(buf, BUFSIZ - 1, "margin-left: %dpx; " + "clear: both;", width); + else + snprintf(buf, BUFSIZ - 1, "float: left; " + "margin-left: -%dpx;", width); + + tag.key = ATTR_STYLE; + tag.val = buf; + + print_otag(h, TAG_DIV, 1, &tag); + + return(1); +} + + +static int +mdoc_list_pre(MDOC_ARGS) +{ + + /* TODO */ + return(0); +} + + +static int +mdoc_it_pre(MDOC_ARGS) +{ + int i, len; + const struct mdoc_node *bl; + + if (MDOC_BLOCK == n->type) + bl = n->parent->parent; + else + bl = n->parent->parent->parent; + + assert(bl->args); + len = (int)bl->args->argc; + + for (i = 0; i < len; i++) + switch (bl->args->argv[i].arg) { + case (MDOC_Bullet): + /* FALLTHROUGH */ + case (MDOC_Dash): + /* FALLTHROUGH */ + case (MDOC_Enum): + /* FALLTHROUGH */ + case (MDOC_Hyphen): + return(0); /* TODO */ + case (MDOC_Tag): + return(0); + case (MDOC_Inset): + /* FALLTHROUGH */ + case (MDOC_Diag): + /* FALLTHROUGH */ + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Column): + /* FALLTHROUGH */ + case (MDOC_Hang): + return(mdoc_hang_pre(m, n, h)); + /* FALLTHROUGH */ + case (MDOC_Ohang): + return(0); /* TODO */ + default: + abort(); + /* NOTREACHED */ + } + + abort(); + /* NOTREACHED */ +} + + +static int +mdoc_bl_pre(MDOC_ARGS) +{ + int i, len; + + if (MDOC_BLOCK != n->type) + return(1); + + assert(n->args); + len = (int)n->args->argc; + + for (i = 0; i < len; i++) + switch (n->args->argv[i].arg) { + case (MDOC_Bullet): + /* FALLTHROUGH */ + case (MDOC_Dash): + /* FALLTHROUGH */ + case (MDOC_Enum): + /* FALLTHROUGH */ + case (MDOC_Hyphen): + return(mdoc_list_pre(m, n, h)); + case (MDOC_Tag): + return(0); + case (MDOC_Inset): + /* FALLTHROUGH */ + case (MDOC_Diag): + /* FALLTHROUGH */ + case (MDOC_Item): + /* FALLTHROUGH */ + case (MDOC_Column): + /* FALLTHROUGH */ + case (MDOC_Hang): + return(1); + case (MDOC_Ohang): + return(0); /* TODO */ + default: + abort(); + /* NOTREACHED */ + } + + abort(); + /* NOTREACHED */ }