X-Git-Url: https://git.cameronkatri.com/mandoc.git/blobdiff_plain/69a80825be62eeca6a77c1f0a38955d29e30cd03..9425244d2b742390e69a9fedde12afadefb6802b:/html.c?ds=sidebyside

diff --git a/html.c b/html.c
index 70641b72..138d3e4c 100644
--- a/html.c
+++ b/html.c
@@ -1,6 +1,6 @@
-/*	$Id: html.c,v 1.93 2010/01/29 14:39:37 kristaps Exp $ */
+/*	$Id: html.c,v 1.112 2010/09/04 20:18:53 kristaps Exp $ */
 /*
- * Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@kth.se>
+ * Copyright (c) 2008, 2009, 2010 Kristaps Dzonsons <kristaps@bsd.lv>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
@@ -29,13 +29,12 @@
 #include <string.h>
 #include <unistd.h>
 
+#include "mandoc.h"
 #include "out.h"
 #include "chars.h"
 #include "html.h"
 #include "main.h"
 
-#define	UNCONST(a)	((void *)(uintptr_t)(const void *)(a))
-
 struct	htmldata {
 	const char	 *name;
 	int		  flags;
@@ -54,7 +53,7 @@ static	const struct htmldata htmltags[TAG_MAX] = {
 	{"h1",		0}, /* TAG_H1 */
 	{"h2",		0}, /* TAG_H2 */
 	{"span",	0}, /* TAG_SPAN */
-	{"link",	HTML_CLRLINE | HTML_NOSTACK}, /* TAG_LINK */
+	{"link",	HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_LINK */
 	{"br",		HTML_CLRLINE | HTML_NOSTACK | HTML_AUTOCLOSE}, /* TAG_BR */
 	{"a",		0}, /* TAG_A */
 	{"table",	HTML_CLRLINE}, /* TAG_TABLE */
@@ -89,13 +88,16 @@ static	const char	*const htmlattrs[ATTR_MAX] = {
 	"summary",
 };
 
-static	void		  print_spec(struct html *, const char *, size_t);
+static	void		  print_spec(struct html *, enum roffdeco,
+				const char *, size_t);
 static	void		  print_res(struct html *, const char *, size_t);
 static	void		  print_ctag(struct html *, enum htmltag);
 static	void		  print_doctype(struct html *);
 static	void		  print_xmltype(struct html *);
 static	int		  print_encode(struct html *, const char *, int);
 static	void		  print_metaf(struct html *, enum roffdeco);
+static	void		  print_attr(struct html *, 
+				const char *, const char *);
 static	void		 *ml_alloc(char *, enum htmltype);
 
 
@@ -114,7 +116,7 @@ ml_alloc(char *outopts, enum htmltype type)
 	h = calloc(1, sizeof(struct html));
 	if (NULL == h) {
 		perror(NULL);
-		exit(EXIT_FAILURE);
+		exit((int)MANDOCLEVEL_SYSERR);
 	}
 
 	h->type = type;
@@ -214,30 +216,41 @@ print_gen_head(struct html *h)
 
 
 static void
-print_spec(struct html *h, const char *p, size_t len)
+print_spec(struct html *h, enum roffdeco d, const char *p, size_t len)
 {
+	int		 cp;
 	const char	*rhs;
 	size_t		 sz;
 
-	rhs = chars_a2ascii(h->symtab, p, len, &sz);
-
-	if (NULL == rhs) 
+	if ((cp = chars_spec2cp(h->symtab, p, len)) > 0) {
+		printf("&#%d;", cp);
+		return;
+	} else if (-1 == cp && DECO_SSPECIAL == d) {
+		fwrite(p, 1, len, stdout);
 		return;
-	fwrite(rhs, 1, sz, stdout);
+	} else if (-1 == cp)
+		return;
+
+	if (NULL != (rhs = chars_spec2str(h->symtab, p, len, &sz)))
+		fwrite(rhs, 1, sz, stdout);
 }
 
 
 static void
 print_res(struct html *h, const char *p, size_t len)
 {
+	int		 cp;
 	const char	*rhs;
 	size_t		 sz;
 
-	rhs = chars_a2res(h->symtab, p, len, &sz);
-
-	if (NULL == rhs)
+	if ((cp = chars_res2cp(h->symtab, p, len)) > 0) {
+		printf("&#%d;", cp);
 		return;
-	fwrite(rhs, 1, sz, stdout);
+	} else if (-1 == cp)
+		return;
+
+	if (NULL != (rhs = chars_res2str(h->symtab, p, len, &sz)))
+		fwrite(rhs, 1, sz, stdout);
 }
 
 
@@ -294,11 +307,12 @@ print_encode(struct html *h, const char *p, int norecurse)
 	int		 len, nospace;
 	const char	*seq;
 	enum roffdeco	 deco;
+	static const char rejs[6] = { '\\', '<', '>', '&', ASCII_HYPH, '\0' };
 
 	nospace = 0;
 
 	for (; *p; p++) {
-		sz = strcspn(p, "\\<>&");
+		sz = strcspn(p, rejs);
 
 		fwrite(p, 1, sz, stdout);
 		p += /* LINTED */
@@ -313,6 +327,15 @@ print_encode(struct html *h, const char *p, int norecurse)
 		} else if ('&' == *p) {
 			printf("&amp;");
 			continue;
+		} else if (ASCII_HYPH == *p) {
+			/*
+			 * Note: "soft hyphens" aren't graphically
+			 * displayed when not breaking the text; we want
+			 * them to be displayed.
+			 */
+			/*printf("&#173;");*/
+			putchar('-');
+			continue;
 		} else if ('\0' == *p)
 			break;
 
@@ -323,8 +346,10 @@ print_encode(struct html *h, const char *p, int norecurse)
 		case (DECO_RESERVED):
 			print_res(h, seq, sz);
 			break;
+		case (DECO_SSPECIAL):
+			/* FALLTHROUGH */
 		case (DECO_SPECIAL):
-			print_spec(h, seq, sz);
+			print_spec(h, deco, seq, sz);
 			break;
 		case (DECO_PREVIOUS):
 			/* FALLTHROUGH */
@@ -351,6 +376,15 @@ print_encode(struct html *h, const char *p, int norecurse)
 }
 
 
+static void
+print_attr(struct html *h, const char *key, const char *val)
+{
+	printf(" %s=\"", key);
+	(void)print_encode(h, val, 1);
+	putchar('\"');
+}
+
+
 struct tag *
 print_otag(struct html *h, enum htmltag tag, 
 		int sz, const struct htmlpair *p)
@@ -358,11 +392,13 @@ print_otag(struct html *h, enum htmltag tag,
 	int		 i;
 	struct tag	*t;
 
+	/* Push this tags onto the stack of open scopes. */
+
 	if ( ! (HTML_NOSTACK & htmltags[tag].flags)) {
 		t = malloc(sizeof(struct tag));
 		if (NULL == t) {
 			perror(NULL);
-			exit(EXIT_FAILURE);
+			exit((int)MANDOCLEVEL_SYSERR);
 		}
 		t->tag = tag;
 		t->next = h->tags.head;
@@ -371,17 +407,37 @@ print_otag(struct html *h, enum htmltag tag,
 		t = NULL;
 
 	if ( ! (HTML_NOSPACE & h->flags))
-		if ( ! (HTML_CLRLINE & htmltags[tag].flags))
-			putchar(' ');
+		if ( ! (HTML_CLRLINE & htmltags[tag].flags)) {
+			/* Manage keeps! */
+			if ( ! (HTML_KEEP & h->flags)) {
+				if (HTML_PREKEEP & h->flags)
+					h->flags |= HTML_KEEP;
+				putchar(' ');
+			} else
+				printf("&#160;");
+		}
+
+	if ( ! (h->flags & HTML_NONOSPACE))
+		h->flags &= ~HTML_NOSPACE;
+	else
+		h->flags |= HTML_NOSPACE;
+
+	/* Print out the tag name and attributes. */
 
 	printf("<%s", htmltags[tag].name);
-	for (i = 0; i < sz; i++) {
-		printf(" %s=\"", htmlattrs[p[i].key]);
-		assert(p->val);
-		(void)print_encode(h, p[i].val, 1);
-		putchar('\"');
+	for (i = 0; i < sz; i++)
+		print_attr(h, htmlattrs[p[i].key], p[i].val);
+
+	/* Add non-overridable attributes. */
+
+	if (TAG_HTML == tag && HTML_XHTML_1_0_STRICT == h->type) {
+		print_attr(h, "xmlns", "http://www.w3.org/1999/xhtml");
+		print_attr(h, "xml:lang", "en");
+		print_attr(h, "lang", "en");
 	}
 
+	/* Accomodate for XML "well-formed" singleton escaping. */
+
 	if (HTML_AUTOCLOSE & htmltags[tag].flags)
 		switch (h->type) {
 		case (HTML_XHTML_1_0_STRICT):
@@ -422,21 +478,9 @@ print_gen_decls(struct html *h)
 static void
 print_xmltype(struct html *h)
 {
-	const char	*decl;
-
-	switch (h->type) {
-	case (HTML_XHTML_1_0_STRICT):
-		decl = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
-		break;
-	default:
-		decl = NULL;
-		break;
-	}
-
-	if (NULL == decl)
-		return;
 
-	printf("%s\n", decl);
+	if (HTML_XHTML_1_0_STRICT == h->type)
+		printf("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 }
 
 
@@ -445,28 +489,32 @@ print_doctype(struct html *h)
 {
 	const char	*doctype;
 	const char	*dtd;
+	const char	*name;
 
 	switch (h->type) {
 	case (HTML_HTML_4_01_STRICT):
+		name = "HTML";
 		doctype = "-//W3C//DTD HTML 4.01//EN";
 		dtd = "http://www.w3.org/TR/html4/strict.dtd";
 		break;
 	default:
+		name = "html";
 		doctype = "-//W3C//DTD XHTML 1.0 Strict//EN";
 		dtd = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd";
 		break;
 	}
 
-	printf("<!DOCTYPE HTML PUBLIC \"%s\" \"%s\">\n", doctype, dtd);
+	printf("<!DOCTYPE %s PUBLIC \"%s\" \"%s\">\n", 
+			name, doctype, dtd);
 }
 
 
 void
-print_text(struct html *h, const char *p)
+print_text(struct html *h, const char *word)
 {
 
-	if (*p && 0 == *(p + 1))
-		switch (*p) {
+	if (word[0] && '\0' == word[1])
+		switch (word[0]) {
 		case('.'):
 			/* FALLTHROUGH */
 		case(','):
@@ -482,8 +530,6 @@ print_text(struct html *h, const char *p)
 		case(')'):
 			/* FALLTHROUGH */
 		case(']'):
-			/* FALLTHROUGH */
-		case('}'):
 			if ( ! (HTML_IGNDELIM & h->flags))
 				h->flags |= HTML_NOSPACE;
 			break;
@@ -491,20 +537,30 @@ print_text(struct html *h, const char *p)
 			break;
 		}
 
-	if ( ! (h->flags & HTML_NOSPACE))
-		putchar(' ');
-
-	assert(p);
-	if ( ! print_encode(h, p, 0))
-		h->flags &= ~HTML_NOSPACE;
+	if ( ! (HTML_NOSPACE & h->flags)) {
+		/* Manage keeps! */
+		if ( ! (HTML_KEEP & h->flags)) {
+			if (HTML_PREKEEP & h->flags)
+				h->flags |= HTML_KEEP;
+			putchar(' ');
+		} else
+			printf("&#160;");
+	}
 
-	if (*p && 0 == *(p + 1))
-		switch (*p) {
+	assert(word);
+	if ( ! print_encode(h, word, 0))
+		if ( ! (h->flags & HTML_NONOSPACE))
+			h->flags &= ~HTML_NOSPACE;
+
+	/* 
+	 * Note that we don't process the pipe: the parser sees it as
+	 * punctuation, but we don't in terms of typography.
+	 */
+	if (word[0] && '\0' == word[1])
+		switch (word[0]) {
 		case('('):
 			/* FALLTHROUGH */
 		case('['):
-			/* FALLTHROUGH */
-		case('{'):
 			h->flags |= HTML_NOSPACE;
 			break;
 		default:
@@ -696,11 +752,11 @@ bufcat_su(struct html *h, const char *p, const struct roffsu *su)
 		break;
 	}
 
-	if (su->pt)
-		buffmt(h, "%s: %f%s;", p, v, u);
-	else
-		/* LINTED */
-		buffmt(h, "%s: %d%s;", p, (int)v, u);
+	/* 
+	 * XXX: the CSS spec isn't clear as to which types accept
+	 * integer or real numbers, so we just make them all decimals.
+	 */
+	buffmt(h, "%s: %.2f%s;", p, v, u);
 }