From f1f5b2a3bdc3178d57c4088a7cd7758afaeba9cb Mon Sep 17 00:00:00 2001
From: David Herrmann <dh.herrmann@gmail.com>
Date: Thu, 2 Oct 2014 16:36:09 +0200
Subject: [PATCH] terminal: make utf8 decoder return length
Lets return the parsed length in term_utf8_decode() instead of a buffer
pointer. Store the pointer in the passed argument.
This makes it adhere to the systemd coding-style, were we always avoid
returning pointers, but store them in output arguments. In this case, the
storage is not allocated, so it doesn't fit 100% to this idiom, but still
looks much nicer.
---
src/libsystemd-terminal/subterm.c | 4 +--
src/libsystemd-terminal/term-parser.c | 24 ++++++++-------
src/libsystemd-terminal/term-screen.c | 4 +--
src/libsystemd-terminal/term.h | 2 +-
src/libsystemd-terminal/test-term-parser.c | 49 +++++++++++++++---------------
5 files changed, 43 insertions(+), 40 deletions(-)
diff --git a/src/libsystemd-terminal/subterm.c b/src/libsystemd-terminal/subterm.c
index 3990fb392b..adc4caa42e 100644
--- a/src/libsystemd-terminal/subterm.c
+++ b/src/libsystemd-terminal/subterm.c
@@ -716,10 +716,10 @@ static int terminal_io_fn(sd_event_source *source, int fd, uint32_t revents, voi
for (i = 0; i < len; ++i) {
const term_seq *seq;
- const uint32_t *str;
+ uint32_t *str;
size_t n_str, j;
- str = term_utf8_decode(&t->utf8, &n_str, buf[i]);
+ n_str = term_utf8_decode(&t->utf8, &str, buf[i]);
for (j = 0; j < n_str; ++j) {
type = term_parser_feed(t->parser, &seq, str[j]);
if (type < 0) {
diff --git a/src/libsystemd-terminal/term-parser.c b/src/libsystemd-terminal/term-parser.c
index c8c1d13d2e..f9326d563a 100644
--- a/src/libsystemd-terminal/term-parser.c
+++ b/src/libsystemd-terminal/term-parser.c
@@ -81,15 +81,16 @@ size_t term_utf8_encode(char *out_utf8, uint32_t g) {
/**
* term_utf8_decode() - Try decoding the next UCS-4 character
* @p: decoder object to operate on or NULL
- * @out_len: output buffer for length of decoded UCS-4 string or NULL
+ * @out_len: output storage for pointer to decoded UCS-4 string or NULL
* @c: next char to push into decoder
*
* This decodes a UTF-8 stream. It must be called for each input-byte of the
- * UTF-8 stream and returns a UCS-4 stream. The length of the returned UCS-4
- * string (number of parsed characters) is stored in @out_len if non-NULL. A
- * pointer to the string is returned (or NULL if none was parsed). The string
- * is not zero-terminated! Furthermore, the string is only valid until the next
- * invokation of this function. It is also bound to the parser-state @p.
+ * UTF-8 stream and returns a UCS-4 stream. A pointer to the parsed UCS-4
+ * string is stored in @out_buf if non-NULL. The length of this string (number
+ * of parsed UCS4 characters) is returned as result. The string is not
+ * zero-terminated! Furthermore, the string is only valid until the next
+ * invocation of this function. It is also bound to the parser state @p and
+ * must not be freed nor written to by the caller.
*
* This function is highly optimized to work with terminal-emulators. Instead
* of being strict about UTF-8 validity, this tries to perform a fallback to
@@ -100,9 +101,10 @@ size_t term_utf8_encode(char *out_utf8, uint32_t g) {
* no helpers to do that for you. To initialize it, simply reset it to all
* zero. You can reset or free the object at any point in time.
*
- * Returns: Pointer to the UCS-4 string or NULL.
+ * Returns: Number of parsed UCS4 characters
*/
-const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c) {
+size_t term_utf8_decode(term_utf8 *p, uint32_t **out_buf, char c) {
+ static uint32_t ucs4_null = 0;
uint32_t t, *res = NULL;
uint8_t byte;
size_t len = 0;
@@ -246,9 +248,9 @@ const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c) {
p->n_bytes = 0;
out:
- if (out_len)
- *out_len = len;
- return len > 0 ? res : NULL;
+ if (out_buf)
+ *out_buf = res ? : &ucs4_null;
+ return len;
}
/*
diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c
index 14c32aceb9..2f3f6f91cb 100644
--- a/src/libsystemd-terminal/term-screen.c
+++ b/src/libsystemd-terminal/term-screen.c
@@ -3756,7 +3756,7 @@ unsigned int term_screen_get_height(term_screen *screen) {
}
int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
- const uint32_t *ucs4_str;
+ uint32_t *ucs4_str;
size_t i, j, ucs4_len;
const term_seq *seq;
int r;
@@ -3768,7 +3768,7 @@ int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
* 8bit mode if the stream is not valid UTF-8. This should be more than
* enough to support old 7bit/8bit modes. */
for (i = 0; i < size; ++i) {
- ucs4_str = term_utf8_decode(&screen->utf8, &ucs4_len, in[i]);
+ ucs4_len = term_utf8_decode(&screen->utf8, &ucs4_str, in[i]);
for (j = 0; j < ucs4_len; ++j) {
r = term_parser_feed(screen->parser, &seq, ucs4_str[j]);
if (r < 0) {
diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h
index 021cf1c42b..d5b934fc59 100644
--- a/src/libsystemd-terminal/term.h
+++ b/src/libsystemd-terminal/term.h
@@ -111,7 +111,7 @@ struct term_utf8 {
};
size_t term_utf8_encode(char *out_utf8, uint32_t g);
-const uint32_t *term_utf8_decode(term_utf8 *p, size_t *out_len, char c);
+size_t term_utf8_decode(term_utf8 *p, uint32_t **out_buf, char c);
/*
* Parsers
diff --git a/src/libsystemd-terminal/test-term-parser.c b/src/libsystemd-terminal/test-term-parser.c
index ed16f5f276..e8d5dcfbf2 100644
--- a/src/libsystemd-terminal/test-term-parser.c
+++ b/src/libsystemd-terminal/test-term-parser.c
@@ -33,39 +33,40 @@
static void test_term_utf8_invalid(void) {
term_utf8 p = { };
- const uint32_t *res;
+ uint32_t *res;
size_t len;
- res = term_utf8_decode(NULL, NULL, 0);
- assert_se(res == NULL);
+ len = term_utf8_decode(NULL, NULL, 0);
+ assert_se(!len);
- res = term_utf8_decode(&p, NULL, 0);
- assert_se(res != NULL);
-
- len = 5;
- res = term_utf8_decode(NULL, &len, 0);
- assert_se(res == NULL);
- assert_se(len == 0);
+ len = term_utf8_decode(&p, NULL, 0);
+ assert_se(len == 1);
- len = 5;
- res = term_utf8_decode(&p, &len, 0);
+ res = NULL;
+ len = term_utf8_decode(NULL, &res, 0);
+ assert_se(!len);
assert_se(res != NULL);
+ assert_se(!*res);
+
+ len = term_utf8_decode(&p, &res, 0);
assert_se(len == 1);
+ assert_se(res != NULL);
+ assert_se(!*res);
- len = 5;
- res = term_utf8_decode(&p, &len, 0xCf);
- assert_se(res == NULL);
+ len = term_utf8_decode(&p, &res, 0xCf);
assert_se(len == 0);
-
- len = 5;
- res = term_utf8_decode(&p, &len, 0x0);
assert_se(res != NULL);
+ assert_se(!*res);
+
+ len = term_utf8_decode(&p, &res, 0);
assert_se(len == 2);
+ assert_se(res != NULL);
+ assert_se(res[0] == 0xCf && res[1] == 0);
}
static void test_term_utf8_range(void) {
term_utf8 p = { };
- const uint32_t *res;
+ uint32_t *res;
char u8[4];
uint32_t i, j;
size_t ulen, len;
@@ -78,8 +79,8 @@ static void test_term_utf8_range(void) {
continue;
for (j = 0; j < ulen; ++j) {
- res = term_utf8_decode(&p, &len, u8[j]);
- if (!res) {
+ len = term_utf8_decode(&p, &res, u8[j]);
+ if (len < 1) {
assert_se(j + 1 != ulen);
continue;
}
@@ -117,13 +118,13 @@ static void test_term_utf8_mix(void) {
0x00F0, 0x0080, 0x0080, 0x0001,
};
term_utf8 p = { };
- const uint32_t *res;
+ uint32_t *res;
unsigned int i, j;
size_t len;
for (i = 0, j = 0; i < sizeof(source); ++i) {
- res = term_utf8_decode(&p, &len, source[i]);
- if (!res)
+ len = term_utf8_decode(&p, &res, source[i]);
+ if (len < 1)
continue;
assert_se(j + len <= ELEMENTSOF(result));