-/* $Id: html.c,v 1.218 2017/07/14 16:28:38 schwarze Exp $ */
+/* $Id: html.c,v 1.229 2018/05/25 20:23:51 schwarze Exp $ */
/*
* Copyright (c) 2008-2011, 2014 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2011-2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011-2015, 2017, 2018 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
#include <assert.h>
#include <ctype.h>
#include <stdarg.h>
+#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include "mandoc_aux.h"
+#include "mandoc_ohash.h"
#include "mandoc.h"
#include "roff.h"
#include "out.h"
{"meta", HTML_NOSTACK | HTML_AUTOCLOSE | HTML_NLALL},
{"title", HTML_NLAROUND},
{"div", HTML_NLAROUND},
+ {"div", 0},
{"h1", HTML_NLAROUND},
{"h2", HTML_NLAROUND},
{"span", 0},
"ex", /* SCALE_FS */
};
+/* Avoid duplicate HTML id= attributes. */
+static struct ohash id_unique;
+
static void a2width(const char *, struct roffsu *);
static void print_byte(struct html *, char);
static void print_endword(struct html *);
if (outopts->fragment)
h->oflags |= HTML_FRAGMENT;
+ mandoc_ohash_init(&id_unique, 4, 0);
+
return h;
}
{
struct tag *tag;
struct html *h;
+ char *cp;
+ unsigned int slot;
h = (struct html *)p;
-
while ((tag = h->tag) != NULL) {
h->tag = tag->next;
free(tag);
}
-
free(h);
+
+ cp = ohash_first(&id_unique, &slot);
+ while (cp != NULL) {
+ free(cp);
+ cp = ohash_next(&id_unique, &slot);
+ }
+ ohash_delete(&id_unique);
}
void
struct tag *t;
print_otag(h, TAG_META, "?", "charset", "utf-8");
+ if (h->style != NULL) {
+ print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
+ h->style, "type", "text/css", "media", "all");
+ return;
+ }
/*
- * Print a default style-sheet.
+ * Print a minimal embedded style sheet.
*/
t = print_otag(h, TAG_STYLE, "");
print_text(h, "td.head-vol { text-align: center; }");
print_endline(h);
print_text(h, "div.Pp { margin: 1ex 0ex; }");
+ print_endline(h);
+ print_text(h, "div.Nd, div.Bf, div.Op { display: inline; }");
+ print_endline(h);
+ print_text(h, "span.Pa, span.Ad { font-style: italic; }");
+ print_endline(h);
+ print_text(h, "span.Ms { font-weight: bold; }");
+ print_endline(h);
+ print_text(h, "dl.Bl-diag ");
+ print_byte(h, '>');
+ print_text(h, " dt { font-weight: bold; }");
+ print_endline(h);
+ print_text(h, "code.Nm, code.Fl, code.Cm, code.Ic, "
+ "code.In, code.Fd, code.Fn,");
+ print_endline(h);
+ print_text(h, "code.Cd { font-weight: bold; "
+ "font-family: inherit; }");
print_tagq(h, t);
-
- if (h->style)
- print_otag(h, TAG_LINK, "?h??", "rel", "stylesheet",
- h->style, "type", "text/css", "media", "all");
}
static void
}
char *
-html_make_id(const struct roff_node *n)
+html_make_id(const struct roff_node *n, int unique)
{
const struct roff_node *nch;
- char *buf, *cp;
+ char *buf, *bufs, *cp;
+ unsigned int slot;
+ int suffix;
for (nch = n->child; nch != NULL; nch = nch->next)
if (nch->type != ROFFT_TEXT)
buf = NULL;
deroff(&buf, n);
+ if (buf == NULL)
+ return NULL;
/* http://www.w3.org/TR/html5/dom.html#the-id-attribute */
if (*cp == ' ')
*cp = '_';
+ if (unique == 0)
+ return buf;
+
+ /* Avoid duplicate HTML id= attributes. */
+
+ bufs = NULL;
+ suffix = 1;
+ slot = ohash_qlookup(&id_unique, buf);
+ cp = ohash_find(&id_unique, slot);
+ if (cp != NULL) {
+ while (cp != NULL) {
+ free(bufs);
+ if (++suffix > 127) {
+ free(buf);
+ return NULL;
+ }
+ mandoc_asprintf(&bufs, "%s_%d", buf, suffix);
+ slot = ohash_qlookup(&id_unique, bufs);
+ cp = ohash_find(&id_unique, slot);
+ }
+ free(buf);
+ buf = bufs;
+ }
+ ohash_insert(&id_unique, slot, buf);
return buf;
}
su = va_arg(ap, struct roffsu *);
break;
case 'w':
- if ((arg2 = va_arg(ap, char *)) == NULL) {
- if (*fmt == '+')
- fmt++;
- if (*fmt == '-')
- fmt++;
- break;
+ if ((arg2 = va_arg(ap, char *)) != NULL) {
+ su = &mysu;
+ a2width(arg2, su);
+ }
+ if (*fmt == '*') {
+ if (su != NULL && su->unit == SCALE_EN &&
+ su->scale > 5.9 && su->scale < 6.1)
+ su = NULL;
+ fmt++;
}
- su = &mysu;
- a2width(arg2, su);
if (*fmt == '+') {
- /* Increase to make even bold text fit. */
- su->scale *= 1.2;
- /* Add padding. */
- su->scale += 3.0;
+ if (su != NULL) {
+ /* Make even bold text fit. */
+ su->scale *= 1.2;
+ /* Add padding. */
+ su->scale += 3.0;
+ }
fmt++;
}
if (*fmt == '-') {
- su->scale *= -1.0;
+ if (su != NULL)
+ su->scale *= -1.0;
fmt++;
}
break;
print_endline(h);
}
+void
+print_gen_comment(struct html *h, struct roff_node *n)
+{
+ int wantblank;
+
+ print_word(h, "<!-- This is an automatically generated file."
+ " Do not edit.");
+ h->indent = 1;
+ wantblank = 0;
+ while (n != NULL && n->type == ROFFT_COMMENT) {
+ if (strstr(n->string, "-->") == NULL &&
+ (wantblank || *n->string != '\0')) {
+ print_endline(h);
+ print_indent(h);
+ print_word(h, n->string);
+ wantblank = *n->string != '\0';
+ }
+ n = n->next;
+ }
+ if (wantblank)
+ print_endline(h);
+ print_word(h, " -->");
+ print_endline(h);
+ h->indent = 0;
+}
+
void
print_text(struct html *h, const char *word)
{