summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>2018-04-24 20:57:56 +0200
committerGitHub <noreply@github.com>2018-04-24 20:57:56 +0200
commit722df70f106d936f994f5789bd81205957a0b50c (patch)
tree69d9364adbdbbfcbb2a8d411406015d1e8399888 /src
parent81183d9b9934bc508820d7bedb82695c5f74ed27 (diff)
parente44924f5c199d634750459a1949a3be59b03ce20 (diff)
downloadsystemd-722df70f106d936f994f5789bd81205957a0b50c.tar.gz
systemd-722df70f106d936f994f5789bd81205957a0b50c.tar.bz2
systemd-722df70f106d936f994f5789bd81205957a0b50c.zip
Merge pull request #8775 from poettering/strip-cso
teach strip_tab_ansi() to strip ANSI CSO sequences
Diffstat (limited to 'src')
-rw-r--r--src/basic/string-util.c46
-rw-r--r--src/test/test-strip-tab-ansi.c23
2 files changed, 60 insertions, 9 deletions
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index 4bcfee973c..07c9938a3f 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -21,6 +21,7 @@
#include "terminal-util.h"
#include "utf8.h"
#include "util.h"
+#include "fileio.h"
int strcmp_ptr(const char *a, const char *b) {
@@ -694,7 +695,8 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
enum {
STATE_OTHER,
STATE_ESCAPE,
- STATE_BRACKET
+ STATE_CSI,
+ STATE_CSO,
} state = STATE_OTHER;
char *obuf = NULL;
size_t osz = 0, isz, shift[2] = {};
@@ -703,7 +705,17 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
assert(ibuf);
assert(*ibuf);
- /* Strips ANSI color and replaces TABs by 8 spaces */
+ /* This does three things:
+ *
+ * 1. Replaces TABs by 8 spaces
+ * 2. Strips ANSI color sequences (a subset of CSI), i.e. ESC '[' … 'm' sequences
+ * 3. Strips ANSI operating system sequences (CSO), i.e. ESC ']' … BEL sequences
+ *
+ * Everything else will be left as it is. In particular other ANSI sequences are left as they are, as are any
+ * other special characters. Truncated ANSI sequences are left-as is too. This call is supposed to suppress the
+ * most basic formatting noise, but nothing else.
+ *
+ * Why care for CSO sequences? Well, to undo what terminal_urlify() and friends generate. */
isz = _isz ? *_isz : strlen(*ibuf);
@@ -738,8 +750,11 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
fputc('\x1B', f);
advance_offsets(i - *ibuf, highlight, shift, 1);
break;
- } else if (*i == '[') {
- state = STATE_BRACKET;
+ } else if (*i == '[') { /* ANSI CSI */
+ state = STATE_CSI;
+ begin = i + 1;
+ } else if (*i == ']') { /* ANSI CSO */
+ state = STATE_CSO;
begin = i + 1;
} else {
fputc('\x1B', f);
@@ -750,10 +765,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
break;
- case STATE_BRACKET:
+ case STATE_CSI:
- if (i >= *ibuf + isz || /* EOT */
- (!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) {
+ if (i >= *ibuf + isz || /* EOT … */
+ !strchr("01234567890;m", *i)) { /* … or invalid chars in sequence */
fputc('\x1B', f);
fputc('[', f);
advance_offsets(i - *ibuf, highlight, shift, 2);
@@ -761,11 +776,26 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
i = begin-1;
} else if (*i == 'm')
state = STATE_OTHER;
+
+ break;
+
+ case STATE_CSO:
+
+ if (i >= *ibuf + isz || /* EOT … */
+ (*i != '\a' && (uint8_t) *i < 32U) || (uint8_t) *i > 126U) { /* … or invalid chars in sequence */
+ fputc('\x1B', f);
+ fputc(']', f);
+ advance_offsets(i - *ibuf, highlight, shift, 2);
+ state = STATE_OTHER;
+ i = begin-1;
+ } else if (*i == '\a')
+ state = STATE_OTHER;
+
break;
}
}
- if (ferror(f)) {
+ if (fflush_and_check(f) < 0) {
fclose(f);
return mfree(obuf);
}
diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c
index fff3fcd0d7..641d537887 100644
--- a/src/test/test-strip-tab-ansi.c
+++ b/src/test/test-strip-tab-ansi.c
@@ -7,12 +7,14 @@
#include <stdio.h>
+#include "alloc-util.h"
#include "string-util.h"
#include "terminal-util.h"
#include "util.h"
int main(int argc, char *argv[]) {
- char *p;
+ _cleanup_free_ char *urlified = NULL, *q = NULL, *qq = NULL;
+ char *p, *z;
assert_se(p = strdup("\tFoobar\tbar\twaldo\t"));
assert_se(strip_tab_ansi(&p, NULL, NULL));
@@ -36,5 +38,24 @@ int main(int argc, char *argv[]) {
assert_se(streq(p, "\x1B[waldo"));
free(p);
+ assert_se(terminal_urlify_path("/etc/fstab", "i am a fabulous link", &urlified) >= 0);
+ assert_se(p = strjoin("something ", urlified, " something-else"));
+ assert_se(q = strdup(p));
+ printf("<%s>\n", p);
+ assert_se(strip_tab_ansi(&p, NULL, NULL));
+ printf("<%s>\n", p);
+ assert_se(streq(p, "something i am a fabulous link something-else"));
+ p = mfree(p);
+
+ /* Truncate the formatted string in the middle of an ANSI sequence (in which case we shouldn't touch the
+ * incomplete sequence) */
+ z = strstr(q, "fstab");
+ if (z) {
+ *z = 0;
+ assert_se(qq = strdup(q));
+ assert_se(strip_tab_ansi(&q, NULL, NULL));
+ assert_se(streq(q, qq));
+ }
+
return 0;
}