summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-07-12 20:29:47 -0400
committerJune McEnroe <june@causal.agency>2020-07-12 20:29:47 -0400
commit3b2a74a61a0199136d21c8f05c7171d9cf43d875 (patch)
tree3d86741134fe58619b1fe7294fd5479a5558d64b
parentLinkify IRC messages (diff)
downloadscooper-3b2a74a61a0199136d21c8f05c7171d9cf43d875.tar.gz
scooper-3b2a74a61a0199136d21c8f05c7171d9cf43d875.zip
Implement IRC formatting
-rw-r--r--html.c79
1 files changed, 75 insertions, 4 deletions
diff --git a/html.c b/html.c
index ae4c76f..1d2cec0 100644
--- a/html.c
+++ b/html.c
@@ -15,9 +15,11 @@
  */
 
 #include <assert.h>
+#include <ctype.h>
 #include <err.h>
 #include <inttypes.h>
 #include <regex.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -422,9 +424,78 @@ enum kcgi_err linkify(struct khtmlreq *html, const char *str, size_t len) {
 	return KCGI_OK;
 }
 
+static const struct Style {
+	int fg, bg;
+	bool b, r, i, u;
+} Default = { .fg = 99, .bg = 99 };
+
+enum kcgi_err htmlStyle(struct khtmlreq *html, struct Style style) {
+	enum kcgi_err error = KCGI_OK;
+	char class[sizeof("fg99")];
+	if (style.fg != Default.fg) {
+		snprintf(class, sizeof(class), "fg%02d", style.fg);
+		error = error || khtml_attr(
+			html, KELEM_SPAN,
+			KATTR_CLASS, class,
+			KATTR__MAX
+		);
+	}
+	if (style.bg != Default.bg) {
+		snprintf(class, sizeof(class), "bg%02d", style.bg);
+		error = error || khtml_attr(
+			html, KELEM_SPAN,
+			KATTR_CLASS, class,
+			KATTR__MAX
+		);
+	}
+	if (style.b) error = error || khtml_elem(html, KELEM_B);
+	if (style.r) error = error || khtml_elem(html, KELEM_MARK);
+	if (style.i) error = error || khtml_elem(html, KELEM_I);
+	if (style.u) error = error || khtml_elem(html, KELEM_U);
+	return error;
+}
+
 enum kcgi_err htmlIRC(struct khtmlreq *html, const char *str) {
-	return 0
-		|| khtml_attr(html, KELEM_SPAN, KATTR_CLASS, "irc", KATTR__MAX)
-		|| linkify(html, str, strlen(str))
-		|| khtml_closeelem(html, 1);
+	enum kcgi_err error = khtml_attr(
+		html, KELEM_SPAN,
+		KATTR_CLASS, "irc",
+		KATTR__MAX
+	);
+	if (error) return error;
+
+	size_t top = khtml_elemat(html);
+	struct Style style = Default;
+	for (;;) {
+		size_t len = strcspn(str, "\2\3\17\26\35\37");
+		if (len) {
+			error = 0
+				|| khtml_closeto(html, top)
+				|| htmlStyle(html, style)
+				|| linkify(html, str, len);
+			if (error) return error;
+		}
+
+		str += len;
+		if (!*str) break;
+		switch (*str++) {
+			break; case '\2':  style.b ^= true;
+			break; case '\26': style.r ^= true;
+			break; case '\35': style.i ^= true;
+			break; case '\37': style.u ^= true;
+			break; case '\3': {
+				if (!isdigit(*str)) {
+					style.fg = Default.fg;
+					style.bg = Default.bg;
+					break;
+				}
+				style.fg = *str++ - '0';
+				if (isdigit(*str)) style.fg = style.fg * 10 + *str++ - '0';
+				if (str[0] != ',' || !isdigit(str[1])) break;
+				str++;
+				style.bg = *str++ - '0';
+				if (isdigit(*str)) style.bg = style.bg * 10 + *str++ - '0';
+			}
+		}
+	}
+	return khtml_closeto(html, top) || khtml_closeelem(html, 1);
 }