1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-23 21:35:11 +03:00

Merge pull request #8775 from poettering/strip-cso

teach strip_tab_ansi() to strip ANSI CSO sequences
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-04-24 20:57:56 +02:00 committed by GitHub
commit 722df70f10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 10 deletions

5
TODO
View File

@ -34,7 +34,10 @@ Features:
* cgroups: use inotify to get notified when somebody else modifies cgroups
owned by us, then log a friendly warning.
* doc: document NTP env var timedated groks in doc/ENVIRONMENT.md.
* beef up log.c with support for stripping ANSI sequences from strings, so that
it is OK to include them in log strings. This would be particularly useful so
that our log messages could contain clickable links for example for unit
files and suchlike we operate on.
* Fix DECIMAL_STR_MAX or DECIMAL_STR_WIDTH. One includes a trailing NUL, the
other doesn't. What a desaster. Probably to exclude it. Also

View File

@ -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);
}

View File

@ -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;
}