string-util: tweak cellescape() a bit
For short buffer sizes cellescape() was a bit wasteful, as it might suffice to to drop a single character to find enough place for the full four byte ellipsis, if that one character was a four character escape. With this rework we'll guarantee to drop the minimum number of characters from the end to fit in the ellipsis. If the buffers we write to are large this doesn't matter much. However, if they are short (as they are when talking about the process comm field) then it starts to matter that we put as much information as we can in the space we get.
This commit is contained in:
parent
76a359736f
commit
61f6e27671
|
@ -627,25 +627,58 @@ char *cellescape(char *buf, size_t len, const char *s) {
|
||||||
* very end.
|
* very end.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
size_t i;
|
size_t i = 0, last_char_width[4] = {}, k = 0, j;
|
||||||
const char *t = s;
|
|
||||||
|
|
||||||
assert(len > 4 + 4 + 1); /* two chars and the terminator */
|
assert(len > 0); /* at least a terminating NUL */
|
||||||
|
|
||||||
for (i = 0; i < len - 9; t++) {
|
for (;;) {
|
||||||
if (!*t)
|
char four[4];
|
||||||
|
int w;
|
||||||
|
|
||||||
|
if (*s == 0) /* terminating NUL detected? then we are done! */
|
||||||
goto done;
|
goto done;
|
||||||
i += cescape_char(*t, buf + i);
|
|
||||||
|
w = cescape_char(*s, four);
|
||||||
|
if (i + w + 1 > len) /* This character doesn't fit into the buffer anymore? In that case let's
|
||||||
|
* ellipsize at the previous location */
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* OK, there was space, let's add this escaped character to the buffer */
|
||||||
|
memcpy(buf + i, four, w);
|
||||||
|
i += w;
|
||||||
|
|
||||||
|
/* And remember its width in the ring buffer */
|
||||||
|
last_char_width[k] = w;
|
||||||
|
k = (k + 1) % 4;
|
||||||
|
|
||||||
|
s++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We have space for one more char and terminating nul at this point */
|
/* Ellipsation is necessary. This means we might need to truncate the string again to make space for 4
|
||||||
if (*t) {
|
* characters ideally, but the buffer is shorter than that in the first place take what we can get */
|
||||||
if (*(t+1))
|
for (j = 0; j < ELEMENTSOF(last_char_width); j++) {
|
||||||
i += write_ellipsis(buf + i, false);
|
|
||||||
else
|
if (i + 4 <= len) /* nice, we reached our space goal */
|
||||||
i += cescape_char(*t, buf + i);
|
break;
|
||||||
|
|
||||||
|
k = k == 0 ? 3 : k - 1;
|
||||||
|
if (last_char_width[k] == 0) /* bummer, we reached the beginning of the strings */
|
||||||
|
break;
|
||||||
|
|
||||||
|
assert(i >= last_char_width[k]);
|
||||||
|
i -= last_char_width[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i + 4 <= len) /* yay, enough space */
|
||||||
|
i += write_ellipsis(buf + i, false);
|
||||||
|
else if (i + 3 <= len) { /* only space for ".." */
|
||||||
|
buf[i++] = '.';
|
||||||
|
buf[i++] = '.';
|
||||||
|
} else if (i + 2 <= len) /* only space for a single "." */
|
||||||
|
buf[i++] = '.';
|
||||||
|
else
|
||||||
|
assert(i + 1 <= len);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
buf[i] = '\0';
|
buf[i] = '\0';
|
||||||
return buf;
|
return buf;
|
||||||
|
|
|
@ -81,21 +81,79 @@ static void test_ascii_strcasecmp_nn(void) {
|
||||||
static void test_cellescape(void) {
|
static void test_cellescape(void) {
|
||||||
char buf[40];
|
char buf[40];
|
||||||
|
|
||||||
assert_se(streq(cellescape(buf, 10, "1"), "1"));
|
assert_se(streq(cellescape(buf, 1, ""), ""));
|
||||||
assert_se(streq(cellescape(buf, 10, "12"), "12"));
|
assert_se(streq(cellescape(buf, 1, "1"), ""));
|
||||||
assert_se(streq(cellescape(buf, 10, "123"), is_locale_utf8() ? "1…" : "1..."));
|
assert_se(streq(cellescape(buf, 1, "12"), ""));
|
||||||
|
|
||||||
assert_se(streq(cellescape(buf, 10, "1\011"), "1\\t"));
|
assert_se(streq(cellescape(buf, 2, ""), ""));
|
||||||
assert_se(streq(cellescape(buf, 10, "1\020"), "1\\020"));
|
assert_se(streq(cellescape(buf, 2, "1"), "1"));
|
||||||
assert_se(streq(cellescape(buf, 10, "1\020x"), is_locale_utf8() ? "1…" : "1..."));
|
assert_se(streq(cellescape(buf, 2, "12"), "."));
|
||||||
|
assert_se(streq(cellescape(buf, 2, "123"), "."));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 3, ""), ""));
|
||||||
|
assert_se(streq(cellescape(buf, 3, "1"), "1"));
|
||||||
|
assert_se(streq(cellescape(buf, 3, "12"), "12"));
|
||||||
|
assert_se(streq(cellescape(buf, 3, "123"), ".."));
|
||||||
|
assert_se(streq(cellescape(buf, 3, "1234"), ".."));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 4, ""), ""));
|
||||||
|
assert_se(streq(cellescape(buf, 4, "1"), "1"));
|
||||||
|
assert_se(streq(cellescape(buf, 4, "12"), "12"));
|
||||||
|
assert_se(streq(cellescape(buf, 4, "123"), "123"));
|
||||||
|
assert_se(streq(cellescape(buf, 4, "1234"), is_locale_utf8() ? "…" : "..."));
|
||||||
|
assert_se(streq(cellescape(buf, 4, "12345"), is_locale_utf8() ? "…" : "..."));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 5, ""), ""));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "1"), "1"));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "12"), "12"));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "123"), "123"));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "1234"), "1234"));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "12345"), is_locale_utf8() ? "1…" : "1..."));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "123456"), is_locale_utf8() ? "1…" : "1..."));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 1, "\020"), ""));
|
||||||
|
assert_se(streq(cellescape(buf, 2, "\020"), "."));
|
||||||
|
assert_se(streq(cellescape(buf, 3, "\020"), ".."));
|
||||||
|
assert_se(streq(cellescape(buf, 4, "\020"), "…"));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "\020"), "\\020"));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 5, "1234\020"), "1…"));
|
||||||
|
assert_se(streq(cellescape(buf, 6, "1234\020"), "12…"));
|
||||||
|
assert_se(streq(cellescape(buf, 7, "1234\020"), "123…"));
|
||||||
|
assert_se(streq(cellescape(buf, 8, "1234\020"), "1234…"));
|
||||||
|
assert_se(streq(cellescape(buf, 9, "1234\020"), "1234\\020"));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 1, "\t\n"), ""));
|
||||||
|
assert_se(streq(cellescape(buf, 2, "\t\n"), "."));
|
||||||
|
assert_se(streq(cellescape(buf, 3, "\t\n"), ".."));
|
||||||
|
assert_se(streq(cellescape(buf, 4, "\t\n"), "…"));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "\t\n"), "\\t\\n"));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 5, "1234\t\n"), "1…"));
|
||||||
|
assert_se(streq(cellescape(buf, 6, "1234\t\n"), "12…"));
|
||||||
|
assert_se(streq(cellescape(buf, 7, "1234\t\n"), "123…"));
|
||||||
|
assert_se(streq(cellescape(buf, 8, "1234\t\n"), "1234…"));
|
||||||
|
assert_se(streq(cellescape(buf, 9, "1234\t\n"), "1234\\t\\n"));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 4, "x\t\020\n"), "…"));
|
||||||
|
assert_se(streq(cellescape(buf, 5, "x\t\020\n"), "x…"));
|
||||||
|
assert_se(streq(cellescape(buf, 6, "x\t\020\n"), "x…"));
|
||||||
|
assert_se(streq(cellescape(buf, 7, "x\t\020\n"), "x\\t…"));
|
||||||
|
assert_se(streq(cellescape(buf, 8, "x\t\020\n"), "x\\t…"));
|
||||||
|
assert_se(streq(cellescape(buf, 9, "x\t\020\n"), "x\\t…"));
|
||||||
|
assert_se(streq(cellescape(buf, 10, "x\t\020\n"), "x\\t\\020\\n"));
|
||||||
|
|
||||||
|
assert_se(streq(cellescape(buf, 6, "1\011"), "1\\t"));
|
||||||
|
assert_se(streq(cellescape(buf, 6, "1\020"), "1\\020"));
|
||||||
|
assert_se(streq(cellescape(buf, 6, "1\020x"), is_locale_utf8() ? "1…" : "1..."));
|
||||||
|
|
||||||
assert_se(streq(cellescape(buf, 40, "1\020"), "1\\020"));
|
assert_se(streq(cellescape(buf, 40, "1\020"), "1\\020"));
|
||||||
assert_se(streq(cellescape(buf, 40, "1\020x"), "1\\020x"));
|
assert_se(streq(cellescape(buf, 40, "1\020x"), "1\\020x"));
|
||||||
|
|
||||||
assert_se(streq(cellescape(buf, 40, "\a\b\f\n\r\t\v\\\"'"), "\\a\\b\\f\\n\\r\\t\\v\\\\\\\"\\'"));
|
assert_se(streq(cellescape(buf, 40, "\a\b\f\n\r\t\v\\\"'"), "\\a\\b\\f\\n\\r\\t\\v\\\\\\\"\\'"));
|
||||||
assert_se(streq(cellescape(buf, 10, "\a\b\f\n\r\t\v\\\"'"), is_locale_utf8() ? "\\a…" : "\\a..."));
|
assert_se(streq(cellescape(buf, 6, "\a\b\f\n\r\t\v\\\"'"), is_locale_utf8() ? "\\a…" : "\\a..."));
|
||||||
assert_se(streq(cellescape(buf, 11, "\a\b\f\n\r\t\v\\\"'"), is_locale_utf8() ? "\\a…" : "\\a..."));
|
assert_se(streq(cellescape(buf, 7, "\a\b\f\n\r\t\v\\\"'"), is_locale_utf8() ? "\\a…" : "\\a..."));
|
||||||
assert_se(streq(cellescape(buf, 12, "\a\b\f\n\r\t\v\\\"'"), is_locale_utf8() ? "\\a\\b…" : "\\a\\b..."));
|
assert_se(streq(cellescape(buf, 8, "\a\b\f\n\r\t\v\\\"'"), is_locale_utf8() ? "\\a\\b…" : "\\a\\b..."));
|
||||||
|
|
||||||
assert_se(streq(cellescape(buf, sizeof buf, "1\020"), "1\\020"));
|
assert_se(streq(cellescape(buf, sizeof buf, "1\020"), "1\\020"));
|
||||||
assert_se(streq(cellescape(buf, sizeof buf, "1\020x"), "1\\020x"));
|
assert_se(streq(cellescape(buf, sizeof buf, "1\020x"), "1\\020x"));
|
||||||
|
|
Loading…
Reference in a new issue