aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/html.c
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2017-01-17 15:32:43 +0000
committerIngo Schwarze <schwarze@openbsd.org>2017-01-17 15:32:43 +0000
commit6506abee45c903b6cd5093a2bf6ece5ac7aed4e3 (patch)
tree420d0dcbb8b9af88f08f2409068672f3b64b161f /html.c
parent24fd28849fa784bd04e3f5bbdb7152253c5d68ba (diff)
downloadmandoc-6506abee45c903b6cd5093a2bf6ece5ac7aed4e3.tar.gz
mandoc-6506abee45c903b6cd5093a2bf6ece5ac7aed4e3.tar.zst
mandoc-6506abee45c903b6cd5093a2bf6ece5ac7aed4e3.zip
Completely delete the buf field of struct html and all the buf*()
interfaces. Such a static buffer was a bad idea in the first place, causing unfixable truncation that was only prevented by triggering an assertion failure. Instead, let the small number of remaining users allocate and free their own, temporary dynamic buffers, or for the case of .Xr and .In, pass the original data to be assembled in print_otag().
Diffstat (limited to 'html.c')
-rw-r--r--html.c228
1 files changed, 73 insertions, 155 deletions
diff --git a/html.c b/html.c
index 1498f8db..5c947312 100644
--- a/html.c
+++ b/html.c
@@ -1,4 +1,4 @@
-/* $Id: html.c,v 1.194 2017/01/17 01:47:51 schwarze Exp $ */
+/* $Id: html.c,v 1.195 2017/01/17 15:32:43 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
@@ -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);
-}