diff options
-rw-r--r-- | TODO | 9 | ||||
-rw-r--r-- | html.c | 226 | ||||
-rw-r--r-- | html.h | 15 | ||||
-rw-r--r-- | man_html.c | 9 | ||||
-rw-r--r-- | mandoc_html.3 | 46 | ||||
-rw-r--r-- | mdoc_html.c | 150 |
6 files changed, 174 insertions, 281 deletions
@@ -33,15 +33,6 @@ Obviously, as the issues have not been solved yet, these annotations are mere guesses, and some may be wrong. ************************************************************************ -* crashes -************************************************************************ - -- The abort() in bufcat(), html.c, can be triggered via buffmt_includes() - by running -Thtml -Oincludes on a file containing a long .In argument. - Fixing this will probably require reworking the whole bufcat() concept. - loc ** exist * algo * size ** imp ** - -************************************************************************ * missing features ************************************************************************ @@ -106,12 +106,11 @@ static const char *const roffscales[SCALE_MAX] = { }; static void a2width(const char *, struct roffsu *); -static void bufncat(struct html *, const char *, size_t); static void print_ctag(struct html *, struct tag *); static int print_escape(char); -static int print_encode(struct html *, const char *, int); +static int print_encode(struct html *, const char *, const char *, int); +static void print_href(struct html *, const char *, const char *, int); static void print_metaf(struct html *, enum mandoc_esc); -static void print_attr(struct html *, const char *, const char *); void * @@ -304,7 +303,7 @@ print_escape(char c) } static int -print_encode(struct html *h, const char *p, int norecurse) +print_encode(struct html *h, const char *p, const char *pend, int norecurse) { size_t sz; int c, len, nospace; @@ -313,9 +312,12 @@ print_encode(struct html *h, const char *p, int norecurse) static const char rejs[9] = { '\\', '<', '>', '&', '"', ASCII_NBRSP, ASCII_HYPH, ASCII_BREAK, '\0' }; + if (pend == NULL) + pend = strchr(p, '\0'); + nospace = 0; - while ('\0' != *p) { + while (p < pend) { if (HTML_SKIPCHAR & h->flags && '\\' != *p) { h->flags &= ~HTML_SKIPCHAR; p++; @@ -323,11 +325,13 @@ print_encode(struct html *h, const char *p, int norecurse) } sz = strcspn(p, rejs); + if (p + sz > pend) + sz = pend - p; fwrite(p, 1, sz, stdout); p += (int)sz; - if ('\0' == *p) + if (p >= pend) break; if (print_escape(*p++)) @@ -399,11 +403,27 @@ print_encode(struct html *h, const char *p, int norecurse) } static void -print_attr(struct html *h, const char *key, const char *val) +print_href(struct html *h, const char *name, const char *sec, int man) { - printf(" %s=\"", key); - (void)print_encode(h, val, 1); - putchar('\"'); + const char *p, *pp; + + pp = man ? h->base_man : h->base_includes; + while ((p = strchr(pp, '%')) != NULL) { + print_encode(h, pp, p, 1); + if (man && p[1] == 'S') { + if (sec == NULL) + putchar('1'); + else + print_encode(h, sec, NULL, 1); + } else if ((man && p[1] == 'N') || + (man == 0 && p[1] == 'I')) + print_encode(h, name, NULL, 1); + else + print_encode(h, p, p + 2, 1); + pp = p + 2; + } + if (*pp != '\0') + print_encode(h, pp, NULL, 1); } struct tag * @@ -412,7 +432,9 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) va_list ap; struct roffsu mysu, *su; struct tag *t; + const char *attr; char *s; + double v; int i, have_style; /* Push this tags onto the stack of open scopes. */ @@ -458,20 +480,40 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) s = va_arg(ap, char *); switch (*fmt++) { case 'c': - print_attr(h, "class", s); + attr = "class"; break; case 'h': - print_attr(h, "href", s); + attr = "href"; break; case 'i': - print_attr(h, "id", s); + attr = "id"; break; case '?': - print_attr(h, s, va_arg(ap, char *)); + attr = s; + s = va_arg(ap, char *); break; default: abort(); } + printf(" %s=\"", attr); + switch (*fmt) { + case 'M': + print_href(h, s, va_arg(ap, char *), 1); + fmt++; + break; + case 'I': + print_href(h, s, NULL, 0); + fmt++; + break; + case 'R': + putchar('#'); + fmt++; + /* FALLTHROUGH */ + default: + print_encode(h, s, NULL, 1); + break; + } + putchar('"'); } /* Print out styles. */ @@ -507,36 +549,40 @@ print_otag(struct html *h, enum htmltag tag, const char *fmt, ...) /* Second letter: style name. */ - bufinit(h); switch (*fmt++) { case 'b': - bufcat_su(h, "margin-bottom", su); + attr = "margin-bottom"; break; case 'h': - bufcat_su(h, "height", su); + attr = "height"; break; case 'i': - bufcat_su(h, "text-indent", su); + attr = "text-indent"; break; case 'l': - bufcat_su(h, "margin-left", su); + attr = "margin-left"; break; case 't': - bufcat_su(h, "margin-top", su); + attr = "margin-top"; break; case 'w': - bufcat_su(h, "width", su); + attr = "width"; break; case 'W': - bufcat_su(h, "min-width", su); + attr = "min-width"; break; case '?': - bufcat_style(h, s, va_arg(ap, char *)); - break; + printf("%s: %s;", s, va_arg(ap, char *)); + continue; default: abort(); } - printf("%s", h->buf); + v = su->scale; + if (su->unit == SCALE_MM && (v /= 100.0) == 0.0) + v = 1.0; + else if (su->unit == SCALE_BU) + v /= 24.0; + printf("%s: %.2f%s;", attr, v, roffscales[su->unit]); } if (have_style) putchar('"'); @@ -619,7 +665,7 @@ print_text(struct html *h, const char *word) } assert(word); - if ( ! print_encode(h, word, 0)) { + if ( ! print_encode(h, word, NULL, 0)) { if ( ! (h->flags & HTML_NONOSPACE)) h->flags &= ~HTML_NOSPACE; h->flags &= ~HTML_NONEWLINE; @@ -682,131 +728,3 @@ a2width(const char *p, struct roffsu *su) } else if (su->scale < 0.0) su->scale = 0.0; } - -void -bufinit(struct html *h) -{ - - h->buf[0] = '\0'; - h->buflen = 0; -} - -void -bufcat_style(struct html *h, const char *key, const char *val) -{ - - bufcat(h, key); - bufcat(h, ":"); - bufcat(h, val); - bufcat(h, ";"); -} - -void -bufcat(struct html *h, const char *p) -{ - - /* - * XXX This is broken and not easy to fix. - * When using the -Oincludes option, buffmt_includes() - * may pass in strings overrunning BUFSIZ, causing a crash. - */ - - h->buflen = strlcat(h->buf, p, BUFSIZ); - assert(h->buflen < BUFSIZ); -} - -void -bufcat_fmt(struct html *h, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - (void)vsnprintf(h->buf + (int)h->buflen, - BUFSIZ - h->buflen - 1, fmt, ap); - va_end(ap); - h->buflen = strlen(h->buf); -} - -static void -bufncat(struct html *h, const char *p, size_t sz) -{ - - assert(h->buflen + sz + 1 < BUFSIZ); - strncat(h->buf, p, sz); - h->buflen += sz; -} - -void -buffmt_includes(struct html *h, const char *name) -{ - const char *p, *pp; - - pp = h->base_includes; - - bufinit(h); - while (NULL != (p = strchr(pp, '%'))) { - bufncat(h, pp, (size_t)(p - pp)); - switch (*(p + 1)) { - case 'I': - bufcat(h, name); - break; - default: - bufncat(h, p, 2); - break; - } - pp = p + 2; - } - if (pp) - bufcat(h, pp); -} - -void -buffmt_man(struct html *h, const char *name, const char *sec) -{ - const char *p, *pp; - - pp = h->base_man; - - bufinit(h); - while (NULL != (p = strchr(pp, '%'))) { - bufncat(h, pp, (size_t)(p - pp)); - switch (*(p + 1)) { - case 'S': - bufcat(h, sec ? sec : "1"); - break; - case 'N': - bufcat_fmt(h, "%s", name); - break; - default: - bufncat(h, p, 2); - break; - } - pp = p + 2; - } - if (pp) - bufcat(h, pp); -} - -void -bufcat_su(struct html *h, const char *p, const struct roffsu *su) -{ - double v; - - v = su->scale; - if (SCALE_MM == su->unit && 0.0 == (v /= 100.0)) - v = 1.0; - else if (SCALE_BU == su->unit) - v /= 24.0; - - bufcat_fmt(h, "%s: %.2f%s;", p, v, roffscales[su->unit]); -} - -void -bufcat_id(struct html *h, const char *src) -{ - - /* Cf. <http://www.w3.org/TR/html5/dom.html#the-id-attribute>. */ - - for (; '\0' != *src; src++) - bufncat(h, *src == ' ' ? "_" : src, 1); -} @@ -101,8 +101,6 @@ struct html { char *base_man; /* base for manpage href */ char *base_includes; /* base for include href */ char *style; /* style-sheet URI */ - char buf[BUFSIZ]; /* see bufcat and friends */ - size_t buflen; struct tag *metaf; /* current open font scope */ enum htmlfont metal; /* last used font */ enum htmlfont metac; /* current font mode */ @@ -125,17 +123,4 @@ void print_tbl(struct html *, const struct tbl_span *); void print_eqn(struct html *, const struct eqn *); void print_paragraph(struct html *); -void bufcat_fmt(struct html *, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); -void bufcat(struct html *, const char *); -void bufcat_id(struct html *, const char *); -void bufcat_style(struct html *, - const char *, const char *); -void bufcat_su(struct html *, const char *, - const struct roffsu *); -void bufinit(struct html *); -void buffmt_man(struct html *, - const char *, const char *); -void buffmt_includes(struct html *, const char *); - int html_strlen(const char *); @@ -172,14 +172,13 @@ html_man(void *arg, const struct roff_man *man) static void print_man_head(MAN_ARGS) { + char *cp; print_gen_head(h); - assert(man->title); - assert(man->msec); - bufinit(h); - bufcat_fmt(h, "%s(%s)", man->title, man->msec); + mandoc_asprintf(&cp, "%s(%s)", man->title, man->msec); print_otag(h, TAG_TITLE, ""); - print_text(h, h->buf); + print_text(h, cp); + free(cp); } static void diff --git a/mandoc_html.3 b/mandoc_html.3 index 5e132979..517b0eff 100644 --- a/mandoc_html.3 +++ b/mandoc_html.3 @@ -1,6 +1,6 @@ .\" $Id$ .\" -.\" Copyright (c) 2014 Ingo Schwarze <schwarze@openbsd.org> +.\" Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org> .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -146,6 +146,26 @@ attribute. Print a .Cm href attribute. +This attribute letter can optionally be followed by a modifier letter. +If followed by +.Cm R , +it formats the link as a local one by prefixing a +.Sq # +character. +If followed by +.Cm I , +it interpretes the argument as a header file name +and generates a link using the +.Xr mandoc 1 +.Fl O Cm includes +option. +If followed by +.Cm M , +it takes two arguments instead of one, a manual page name and +section, and formats them as a link to a manual page using the +.Xr mandoc 1 +.Fl O Cm man +option. .It Cm i Print an .Cm id @@ -235,8 +255,6 @@ The first is the style name, the second its value. .Pp .Fn print_otag uses the private function -.Fn print_attr -which in turn uses the private function .Fn print_encode to take care of HTML encoding. If required by the element type, it remembers in @@ -270,28 +288,6 @@ and functions. .Pp The functions -.Fn bufinit , -.Fn bufcat* , -and -.Fn buffmt* -do not directly produce output but buffer text in the -.Fa buf -member of -.Fa h . -They are not used internally by -.Pa html.c -but intended for use by the language-specific formatters -to ease preparation of strings for the -.Fa p -argument of -.Fn print_otag -and for the -.Fa word -argument of -.Fn print_text . -Consequently, these functions do not do any HTML encoding. -.Pp -The functions .Fn html_strlen , .Fn print_eqn , .Fn print_tbl , diff --git a/mdoc_html.c b/mdoc_html.c index 40a78138..f613e6a1 100644 --- a/mdoc_html.c +++ b/mdoc_html.c @@ -324,17 +324,23 @@ html_mdoc(void *arg, const struct roff_man *mdoc) static void print_mdoc_head(MDOC_ARGS) { + char *cp; print_gen_head(h); - bufinit(h); - bufcat(h, meta->title); - if (meta->msec) - bufcat_fmt(h, "(%s)", meta->msec); - if (meta->arch) - bufcat_fmt(h, " (%s)", meta->arch); + + if (meta->arch != NULL && meta->msec != NULL) + mandoc_asprintf(&cp, "%s(%s) (%s)", meta->title, + meta->msec, meta->arch); + else if (meta->msec != NULL) + mandoc_asprintf(&cp, "%s(%s)", meta->title, meta->msec); + else if (meta->arch != NULL) + mandoc_asprintf(&cp, "%s (%s)", meta->title, meta->arch); + else + cp = mandoc_strdup(meta->title); print_otag(h, TAG_TITLE, ""); - print_text(h, h->buf); + print_text(h, cp); + free(cp); } static void @@ -489,9 +495,33 @@ mdoc_root_pre(MDOC_ARGS) return 1; } +char * +make_id(const struct roff_node *n) +{ + const struct roff_node *nch; + char *buf, *cp; + + for (nch = n->child; nch != NULL; nch = nch->next) + if (nch->type != ROFFT_TEXT) + return NULL; + + buf = NULL; + deroff(&buf, n); + + /* http://www.w3.org/TR/html5/dom.html#the-id-attribute */ + + for (cp = buf; *cp != '\0'; cp++) + if (*cp == ' ') + *cp = '_'; + + return buf; +} + static int mdoc_sh_pre(MDOC_ARGS) { + char *id; + switch (n->type) { case ROFFT_BLOCK: print_otag(h, TAG_DIV, "c", "section"); @@ -504,17 +534,10 @@ mdoc_sh_pre(MDOC_ARGS) break; } - bufinit(h); - - for (n = n->child; n != NULL && n->type == ROFFT_TEXT; ) { - bufcat_id(h, n->string); - if (NULL != (n = n->next)) - bufcat_id(h, " "); - } - - if (NULL == n) - print_otag(h, TAG_H1, "i", h->buf); - else + if ((id = make_id(n)) != NULL) { + print_otag(h, TAG_H1, "i", id); + free(id); + } else print_otag(h, TAG_H1, ""); return 1; @@ -523,23 +546,18 @@ mdoc_sh_pre(MDOC_ARGS) static int mdoc_ss_pre(MDOC_ARGS) { + char *id; + if (n->type == ROFFT_BLOCK) { print_otag(h, TAG_DIV, "c", "subsection"); return 1; } else if (n->type == ROFFT_BODY) return 1; - bufinit(h); - - for (n = n->child; n != NULL && n->type == ROFFT_TEXT; ) { - bufcat_id(h, n->string); - if (NULL != (n = n->next)) - bufcat_id(h, " "); - } - - if (NULL == n) - print_otag(h, TAG_H2, "i", h->buf); - else + if ((id = make_id(n)) != NULL) { + print_otag(h, TAG_H2, "i", id); + free(id); + } else print_otag(h, TAG_H2, ""); return 1; @@ -623,12 +641,11 @@ mdoc_xr_pre(MDOC_ARGS) if (NULL == n->child) return 0; - if (h->base_man) { - buffmt_man(h, n->child->string, - n->child->next ? - n->child->next->string : NULL); - print_otag(h, TAG_A, "ch", "link-man", h->buf); - } else + if (h->base_man) + print_otag(h, TAG_A, "chM", "link-man", + n->child->string, n->child->next == NULL ? + NULL : n->child->next->string); + else print_otag(h, TAG_A, "c", "link-man"); n = n->child; @@ -850,17 +867,15 @@ mdoc_d1_pre(MDOC_ARGS) static int mdoc_sx_pre(MDOC_ARGS) { - bufinit(h); - bufcat(h, "#"); - - for (n = n->child; n; ) { - bufcat_id(h, n->string); - if (NULL != (n = n->next)) - bufcat_id(h, " "); - } + char *id; print_otag(h, TAG_I, "c", "link-sec"); - print_otag(h, TAG_A, "ch", "link-sec", h->buf); + if ((id = make_id(n)) != NULL) { + print_otag(h, TAG_A, "chR", "link-sec", id); + free(id); + } else + print_otag(h, TAG_A, "c", "link-sec"); + return 1; } @@ -1051,9 +1066,8 @@ mdoc_fa_pre(MDOC_ARGS) static int mdoc_fd_pre(MDOC_ARGS) { - char buf[BUFSIZ]; - size_t sz; struct tag *t; + char *buf, *cp; synopsis_pre(h, n); @@ -1073,25 +1087,16 @@ mdoc_fd_pre(MDOC_ARGS) if (NULL != (n = n->next)) { assert(n->type == ROFFT_TEXT); - /* - * XXX This is broken and not easy to fix. - * When using -Oincludes, truncation may occur. - * Dynamic allocation wouldn't help because - * passing long strings to buffmt_includes() - * does not work either. - */ - - strlcpy(buf, '<' == *n->string || '"' == *n->string ? - n->string + 1 : n->string, BUFSIZ); - - sz = strlen(buf); - if (sz && ('>' == buf[sz - 1] || '"' == buf[sz - 1])) - buf[sz - 1] = '\0'; - if (h->base_includes) { - buffmt_includes(h, buf); - t = print_otag(h, TAG_A, "ch", "link-includes", - h->buf); + cp = n->string; + if (*cp == '<' || *cp == '"') + cp++; + buf = mandoc_strdup(cp); + cp = strchr(buf, '\0') - 1; + if (cp >= buf && (*cp == '>' || *cp == '"')) + *cp = '\0'; + t = print_otag(h, TAG_A, "chI", "link-includes", buf); + free(buf); } else t = print_otag(h, TAG_A, "c", "link-includes"); @@ -1279,16 +1284,16 @@ static int mdoc_mt_pre(MDOC_ARGS) { struct tag *t; + char *cp; for (n = n->child; n; n = n->next) { assert(n->type == ROFFT_TEXT); - bufinit(h); - bufcat(h, "mailto:"); - bufcat(h, n->string); - t = print_otag(h, TAG_A, "ch", "link-mail", h->buf); + mandoc_asprintf(&cp, "mailto:%s", n->string); + t = print_otag(h, TAG_A, "ch", "link-mail", cp); print_text(h, n->string); print_tagq(h, t); + free(cp); } return 0; @@ -1355,11 +1360,10 @@ mdoc_in_pre(MDOC_ARGS) if (NULL != (n = n->child)) { assert(n->type == ROFFT_TEXT); - if (h->base_includes) { - buffmt_includes(h, n->string); - t = print_otag(h, TAG_A, "ch", "link-includes", - h->buf); - } else + if (h->base_includes) + t = print_otag(h, TAG_A, "chI", "link-includes", + n->string); + else t = print_otag(h, TAG_A, "c", "link-includes"); print_text(h, n->string); print_tagq(h, t); |