about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-04-29 12:55:28 -0400
committerJune McEnroe <june@causal.agency>2020-04-29 12:55:28 -0400
commit0dbf097da16a5c27ca87d21aa0cb2bdbf1fb8154 (patch)
tree620673d6c90549b9c17b0680248031aff9293af2
parentClean up html.c (diff)
downloadbubger-0dbf097da16a5c27ca87d21aa0cb2bdbf1fb8154.tar.gz
bubger-0dbf097da16a5c27ca87d21aa0cb2bdbf1fb8154.zip
Turn URLs into HTML links
-rw-r--r--html.c63
1 files changed, 56 insertions, 7 deletions
diff --git a/html.c b/html.c
index 5147798..850e070 100644
--- a/html.c
+++ b/html.c
@@ -14,6 +14,7 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
+#include <regex.h>
 #include <err.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -213,6 +214,48 @@ static int htmlInlineAttrs(FILE *file, const struct BodyPart *part) {
 	return 0;
 }
 
+static void swap(char *a, char *b) {
+	char ch = *a;
+	*a = *b;
+	*b = ch;
+}
+
+static int htmlMarkupURLs(FILE *file, char *buf) {
+	static const char *Pattern = "(^|[[:space:]<])(https?:[^[:space:]>]+)(.|$)";
+	static regex_t regex;
+	if (!regex.re_nsub) {
+		int error = regcomp(&regex, Pattern, REG_EXTENDED);
+		if (error) {
+			char buf[256];
+			regerror(error, &regex, buf, sizeof(buf));
+			errx(EX_SOFTWARE, "%s: %s", buf, Pattern);
+		}
+	}
+
+	int error;
+	char *ptr;
+	regmatch_t match[4];
+	for (ptr = buf; !regexec(&regex, ptr, 4, match, 0); ptr += match[2].rm_eo) {
+		char nul = '\0';
+
+		swap(&ptr[match[2].rm_so], &nul);
+		error = escapeXML(file, ptr);
+		if (error) return error;
+		swap(&ptr[match[2].rm_so], &nul);
+
+		const char *template = TEMPLATE(<a href="[url]">[url]</a>);
+		swap(&ptr[match[3].rm_so], &nul);
+		struct Variable vars[] = {
+			{ "url", &ptr[match[2].rm_so] },
+			{0},
+		};
+		error = templateRender(file, template, vars, escapeXML);
+		if (error) return error;
+		swap(&ptr[match[3].rm_so], &nul);
+	}
+	return escapeXML(file, ptr);
+}
+
 static int htmlMarkup(FILE *file, const char *content) {
 	int error = 0;
 	size_t cap = 0;
@@ -240,24 +283,30 @@ static int htmlMarkup(FILE *file, const char *content) {
 
 		if (patch && !strncmp(buf, "@@", 2)) {
 			error = templateRender(
-				file, TEMPLATE(<b>[line]</b>) "\n", vars, escapeXML
+				file, TEMPLATE(<b>[line]</b>), vars, escapeXML
 			);
 		} else if (patch && buf[0] == '-' && strncmp(buf, "---", 3)) {
 			error = templateRender(
-				file, TEMPLATE(<del>[line]</del>) "\n", vars, escapeXML
+				file, TEMPLATE(<del>[line]</del>), vars, escapeXML
 			);
 		} else if (patch && buf[0] == '+' && strncmp(buf, "+++", 3)) {
 			error = templateRender(
-				file, TEMPLATE(<ins>[line]</ins>) "\n", vars, escapeXML
+				file, TEMPLATE(<ins>[line]</ins>), vars, escapeXML
 			);
+		} else if (patch) {
+			error = escapeXML(file, buf);
 		} else if (buf[0] == '>') {
-			error = templateRender(
-				file, TEMPLATE(<q>[line]</q>) "\n", vars, escapeXML
-			);
+			error = 0
+				|| templateRender(file, TEMPLATE(<q>), NULL, NULL)
+				|| htmlMarkupURLs(file, buf)
+				|| templateRender(file, TEMPLATE(</q>), NULL, NULL);
 		} else {
-			error = templateRender(file, "[line]\n", vars, escapeXML);
+			error = htmlMarkupURLs(file, buf);
 		}
 		if (error) break;
+
+		error = templateRender(file, "\n", NULL, NULL);
+		if (error) break;
 	}
 	free(buf);
 	return error;