aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Eric Janouch <p@janouch.name>2021-08-29 12:06:53 +0200
committerPřemysl Eric Janouch <p@janouch.name>2021-08-29 12:06:53 +0200
commitde7df1f60d8965d6eb0db9d863f950ffa8720004 (patch)
treee12ff1131561c8fceb3d3ee6f6b627970e64b7ed
parentb082e82b625eca244ac0d1381c152f12b946d463 (diff)
downloadxK-de7df1f60d8965d6eb0db9d863f950ffa8720004.tar.gz
xK-de7df1f60d8965d6eb0db9d863f950ffa8720004.tar.xz
xK-de7df1f60d8965d6eb0db9d863f950ffa8720004.zip
xC: refactor parsing of IRC formatting
-rw-r--r--xC.c166
1 files changed, 83 insertions, 83 deletions
diff --git a/xC.c b/xC.c
index e714c65..96d54b5 100644
--- a/xC.c
+++ b/xC.c
@@ -2961,6 +2961,7 @@ attr_printer_apply (struct attr_printer *self,
attr_printer_reset (self);
+ // TEXT_MONOSPACE is unimplemented, for obvious reasons
if (text_attrs)
attr_printer_tputs (self, tparm (set_attributes,
0, // standout
@@ -3153,8 +3154,6 @@ formatter_add_item (struct formatter *self, struct formatter_item template_)
FORMATTER_ADD_ITEM ((self), ATTR, .attribute = ATTR_RESET)
#define FORMATTER_ADD_TEXT(self, text_) \
FORMATTER_ADD_ITEM ((self), TEXT, .text = (text_))
-#define FORMATTER_ADD_SIMPLE(self, attribute_) \
- FORMATTER_ADD_ITEM ((self), SIMPLE, .attribute = TEXT_ ## attribute_)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -3225,6 +3224,82 @@ irc_parse_mirc_color (const char *s, uint8_t *fg, uint8_t *bg)
return s;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+struct irc_char_attrs
+{
+ uint8_t fg, bg; ///< {Fore,back}ground colour or 99
+ uint8_t attributes; ///< TEXT_* flags, except TEXT_BLINK
+ uint8_t starts_at_boundary; ///< Possible to split here?
+};
+
+static void
+irc_serialize_char_attrs (const struct irc_char_attrs *attrs, struct str *out)
+{
+ soft_assert (attrs->fg < 100 && attrs->bg < 100);
+
+ if (attrs->fg != 99 || attrs->bg != 99)
+ {
+ str_append_printf (out, "\x03%u", attrs->fg);
+ if (attrs->bg != 99)
+ str_append_printf (out, ",%02u", attrs->bg);
+ }
+ if (attrs->attributes & TEXT_BOLD) str_append_c (out, '\x02');
+ if (attrs->attributes & TEXT_ITALIC) str_append_c (out, '\x1d');
+ if (attrs->attributes & TEXT_UNDERLINE) str_append_c (out, '\x1f');
+ if (attrs->attributes & TEXT_INVERSE) str_append_c (out, '\x16');
+ if (attrs->attributes & TEXT_CROSSED_OUT) str_append_c (out, '\x1e');
+ if (attrs->attributes & TEXT_MONOSPACE) str_append_c (out, '\x11');
+}
+
+static int
+irc_parse_attribute (char c)
+{
+ switch (c)
+ {
+ case '\x02' /* ^B */: return TEXT_BOLD;
+ case '\x11' /* ^Q */: return TEXT_MONOSPACE;
+ case '\x16' /* ^V */: return TEXT_INVERSE;
+ case '\x1d' /* ^] */: return TEXT_ITALIC;
+ case '\x1e' /* ^^ */: return TEXT_CROSSED_OUT;
+ case '\x1f' /* ^_ */: return TEXT_UNDERLINE;
+ case '\x0f' /* ^O */: return -1;
+ }
+ return 0;
+}
+
+// The text needs to be NUL-terminated, and a valid UTF-8 string
+static struct irc_char_attrs *
+irc_analyze_text (const char *text, size_t len)
+{
+ struct irc_char_attrs *attrs = xcalloc (len, sizeof *attrs),
+ blank = { .fg = 99, .bg = 99, .starts_at_boundary = true },
+ next = blank, cur = next;
+
+ for (size_t i = 0; i != len; cur = next)
+ {
+ const char *start = text;
+ hard_assert (utf8_decode (&text, len - i) >= 0);
+
+ int attribute = irc_parse_attribute (*start);
+ if (*start == '\x03')
+ text = irc_parse_mirc_color (text, &next.fg, &next.bg);
+ else if (attribute > 0)
+ next.attributes ^= attribute;
+ else if (attribute < 0)
+ next = blank;
+
+ while (start++ != text)
+ {
+ attrs[i++] = cur;
+ cur.starts_at_boundary = false;
+ }
+ }
+ return attrs;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
static const char *
formatter_parse_mirc_color (struct formatter *self, const char *s)
{
@@ -3261,24 +3336,15 @@ formatter_parse_mirc (struct formatter *self, const char *s)
str_reset (&buf);
}
- switch (c)
- {
- case '\x02': FORMATTER_ADD_SIMPLE (self, BOLD); break;
- case '\x11': /* monospace, N/A */ break;
- case '\x1d': FORMATTER_ADD_SIMPLE (self, ITALIC); break;
- case '\x1e': FORMATTER_ADD_SIMPLE (self, CROSSED_OUT); break;
- case '\x1f': FORMATTER_ADD_SIMPLE (self, UNDERLINE); break;
- case '\x16': FORMATTER_ADD_SIMPLE (self, INVERSE); break;
-
- case '\x03':
+ int attribute = irc_parse_attribute (c);
+ if (c == '\x03')
s = formatter_parse_mirc_color (self, s);
- break;
- case '\x0f':
+ else if (attribute > 0)
+ FORMATTER_ADD_ITEM (self, SIMPLE, .attribute = attribute);
+ else if (attribute < 0)
FORMATTER_ADD_RESET (self);
- break;
- default:
+ else
str_append_c (&buf, c);
- }
}
if (buf.len)
@@ -8240,70 +8306,6 @@ irc_process_message (const struct irc_message *msg, struct server *s)
// This is a rather basic algorithm; something like ICU with proper
// locale specification would be needed to make it work better.
-struct irc_char_attrs
-{
- uint8_t fg, bg; ///< {Fore,back}ground colour or 99
- uint8_t attributes; ///< TEXT_* flags, except TEXT_BLINK
- uint8_t starts_at_boundary; ///< Possible to split here?
-};
-
-static void
-irc_serialize_char_attrs (const struct irc_char_attrs *attrs, struct str *out)
-{
- soft_assert (attrs->fg < 100 && attrs->bg < 100);
-
- if (attrs->fg != 99 || attrs->bg != 99)
- {
- str_append_printf (out, "\x03%u", attrs->fg);
- if (attrs->bg != 99)
- str_append_printf (out, ",%02u", attrs->bg);
- }
- if (attrs->attributes & TEXT_BOLD) str_append_c (out, '\x02');
- if (attrs->attributes & TEXT_ITALIC) str_append_c (out, '\x1d');
- if (attrs->attributes & TEXT_UNDERLINE) str_append_c (out, '\x1f');
- if (attrs->attributes & TEXT_INVERSE) str_append_c (out, '\x16');
- if (attrs->attributes & TEXT_CROSSED_OUT) str_append_c (out, '\x1e');
- if (attrs->attributes & TEXT_MONOSPACE) str_append_c (out, '\x11');
-}
-
-// The text needs to be NUL-terminated
-// TODO: try to deduplicate analogous code in formatter_parse_mirc()
-static struct irc_char_attrs *
-irc_analyze_text (const char *text, size_t len)
-{
- struct irc_char_attrs *attrs = xcalloc (len, sizeof *attrs),
- blank = { .fg = 99, .bg = 99, .starts_at_boundary = true },
- next = blank, cur = next;
-
- for (size_t i = 0; i != len; cur = next)
- {
- const char *start = text;
- hard_assert (utf8_decode (&text, len - i) >= 0);
- switch (*start)
- {
- case '\x02': next.attributes ^= TEXT_BOLD; break;
- case '\x11': next.attributes ^= TEXT_MONOSPACE; break;
- case '\x1d': next.attributes ^= TEXT_ITALIC; break;
- case '\x1e': next.attributes ^= TEXT_CROSSED_OUT; break;
- case '\x1f': next.attributes ^= TEXT_UNDERLINE; break;
- case '\x16': next.attributes ^= TEXT_INVERSE; break;
-
- case '\x03':
- text = irc_parse_mirc_color (text, &next.fg, &next.bg);
- break;
- case '\x0f':
- next = blank;
- }
-
- while (start++ != text)
- {
- attrs[i++] = cur;
- cur.starts_at_boundary = false;
- }
- }
- return attrs;
-}
-
static size_t
wrap_text_for_single_line (const char *text, struct irc_char_attrs *attrs,
size_t text_len, size_t target_len, struct str *output)
@@ -8344,8 +8346,6 @@ wrap_text_for_single_line (const char *text, struct irc_char_attrs *attrs,
return eaten;
}
-// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
// In practice, this should never fail at all, although it's not guaranteed
static bool
wrap_message (const char *message,