summaryrefslogtreecommitdiff
path: root/src/basic/string-util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-06-01 21:45:23 +0200
committerSven Eden <yamakuzure@gmx.net>2018-08-24 16:47:08 +0200
commitae22dea58699350462ac7100283bec6919a60765 (patch)
tree7d0b7aa2912b02c823a147f8291a9b4186e80f74 /src/basic/string-util.c
parent5acc15fbb0ce306d4a2f4e0d47f4c5d5ac433b08 (diff)
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.
Diffstat (limited to 'src/basic/string-util.c')
-rw-r--r--src/basic/string-util.c57
1 files changed, 45 insertions, 12 deletions
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index f241a3376..cb6428e8a 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -631,25 +631,58 @@ char *cellescape(char *buf, size_t len, const char *s) {
* very end.
*/
- size_t i;
- const char *t = s;
+ size_t i = 0, last_char_width[4] = {}, k = 0, j;
+
+ assert(len > 0); /* at least a terminating NUL */
- assert(len > 4 + 4 + 1); /* two chars and the terminator */
+ for (;;) {
+ char four[4];
+ int w;
- for (i = 0; i < len - 9; t++) {
- if (!*t)
+ if (*s == 0) /* terminating NUL detected? then we are 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 */
- if (*t) {
- if (*(t+1))
- i += write_ellipsis(buf + i, false);
- else
- i += cescape_char(*t, buf + i);
+ /* Ellipsation is necessary. This means we might need to truncate the string again to make space for 4
+ * characters ideally, but the buffer is shorter than that in the first place take what we can get */
+ for (j = 0; j < ELEMENTSOF(last_char_width); j++) {
+
+ if (i + 4 <= len) /* nice, we reached our space goal */
+ 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:
buf[i] = '\0';
return buf;