#include "gunicode.h"
#include "macro.h"
#include "string-util.h"
+#include "terminal-util.h"
#include "utf8.h"
#include "util.h"
return ret;
}
-char *strip_tab_ansi(char **ibuf, size_t *_isz) {
+static void advance_offsets(ssize_t diff, size_t offsets[2], size_t shift[2], size_t size) {
+ if (!offsets)
+ return;
+
+ if ((size_t) diff < offsets[0])
+ shift[0] += size;
+ if ((size_t) diff < offsets[1])
+ shift[1] += size;
+}
+
+char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) {
const char *i, *begin = NULL;
enum {
STATE_OTHER,
STATE_BRACKET
} state = STATE_OTHER;
char *obuf = NULL;
- size_t osz = 0, isz;
+ size_t osz = 0, isz, shift[2] = {};
FILE *f;
assert(ibuf);
break;
else if (*i == '\x1B')
state = STATE_ESCAPE;
- else if (*i == '\t')
+ else if (*i == '\t') {
fputs(" ", f);
- else
+ advance_offsets(i - *ibuf, highlight, shift, 7);
+ } else
fputc(*i, f);
+
break;
case STATE_ESCAPE:
if (i >= *ibuf + isz) { /* EOT */
fputc('\x1B', f);
+ advance_offsets(i - *ibuf, highlight, shift, 1);
break;
} else if (*i == '[') {
state = STATE_BRACKET;
} else {
fputc('\x1B', f);
fputc(*i, f);
+ advance_offsets(i - *ibuf, highlight, shift, 1);
state = STATE_OTHER;
}
(!(*i >= '0' && *i <= '9') && !IN_SET(*i, ';', 'm'))) {
fputc('\x1B', f);
fputc('[', f);
+ advance_offsets(i - *ibuf, highlight, shift, 2);
state = STATE_OTHER;
i = begin-1;
} else if (*i == 'm')
if (_isz)
*_isz = osz;
+ if (highlight) {
+ highlight[0] += shift[0];
+ highlight[1] += shift[1];
+ }
+
return obuf;
}
return true;
}
-static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
- const char *color_on = "", *color_off = "";
+static bool print_multiline(
+ FILE *f,
+ unsigned prefix,
+ unsigned n_columns,
+ OutputFlags flags,
+ int priority,
+ const char* message,
+ size_t message_len,
+ size_t highlight[2]) {
+
+ const char *color_on = "", *color_off = "", *highlight_on = "";
const char *pos, *end;
bool ellipsized = false;
int line = 0;
if (priority <= LOG_ERR) {
color_on = ANSI_HIGHLIGHT_RED;
color_off = ANSI_NORMAL;
+ highlight_on = ANSI_HIGHLIGHT;
} else if (priority <= LOG_NOTICE) {
color_on = ANSI_HIGHLIGHT;
color_off = ANSI_NORMAL;
+ highlight_on = ANSI_HIGHLIGHT_RED;
}
}
if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
(prefix + len + 1 < n_columns && !tail_line)) {
- fprintf(f, "%*s%s%.*s%s\n",
- continuation * prefix, "",
- color_on, len, pos, color_off);
+ if (highlight &&
+ (size_t) (pos - message) <= highlight[0] &&
+ highlight[0] < (size_t) len) {
+
+ fprintf(f, "%*s%s%.*s",
+ continuation * prefix, "",
+ color_on, (int) highlight[0], pos);
+ fprintf(f, "%s%.*s",
+ highlight_on,
+ (int) (MIN((size_t) len, highlight[1]) - highlight[0]),
+ pos + highlight[0]);
+ if ((size_t) len > highlight[1])
+ fprintf(f, "%s%.*s",
+ color_on,
+ (int) (len - highlight[1]),
+ pos + highlight[1]);
+ fprintf(f, "%s\n", color_off);
+
+ } else
+ fprintf(f, "%*s%s%.*s%s\n",
+ continuation * prefix, "",
+ color_on, len, pos, color_off);
continue;
}
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields) {
+ Set *output_fields,
+ size_t highlight[2]) {
int r;
const void *data;
PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len),
PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len),
};
+ size_t highlight_shifted[] = {highlight ? highlight[0] : 0, highlight ? highlight[1] : 0};
assert(f);
assert(j);
}
if (!(flags & OUTPUT_SHOW_ALL))
- strip_tab_ansi(&message, &message_len);
+ strip_tab_ansi(&message, &message_len, highlight_shifted);
if (priority_len == 1 && *priority >= '0' && *priority <= '7')
p = *priority - '0';
} else {
fputs(": ", f);
ellipsized |=
- print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
+ print_multiline(f, n + 2, n_columns, flags, p,
+ message, message_len,
+ highlight_shifted);
}
if (flags & OUTPUT_CATALOG)
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields) {
+ Set *output_fields,
+ size_t highlight[2]) {
const void *data;
size_t length;
(((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
&& utf8_is_printable(data, length))) {
fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
- print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
+ print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1, NULL);
fputs(off, f);
} else {
char bytes[FORMAT_BYTES_MAX];
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields) {
+ Set *output_fields,
+ size_t highlight[2]) {
sd_id128_t boot_id;
char sid[33];
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields) {
+ Set *output_fields,
+ size_t highlight[2]) {
uint64_t realtime, monotonic;
_cleanup_free_ char *cursor = NULL;
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields) {
+ Set *output_fields,
+ size_t highlight[2]) {
const void *data;
size_t l;
int r;
+ const char *highlight_on = "", *highlight_off = "";
assert(j);
assert(f);
+ if (flags & OUTPUT_COLOR) {
+ highlight_on = ANSI_HIGHLIGHT_RED;
+ highlight_off = ANSI_NORMAL;
+ }
+
sd_journal_set_data_threshold(j, 0);
r = sd_journal_get_data(j, "MESSAGE", &data, &l);
assert(l >= 8);
- fwrite((const char*) data + 8, 1, l - 8, f);
+ if (highlight && (flags & OUTPUT_COLOR)) {
+ assert(highlight[0] <= highlight[1]);
+ assert(highlight[1] <= l - 8);
+
+ fwrite((const char*) data + 8, 1, highlight[0], f);
+ fwrite(highlight_on, 1, strlen(highlight_on), f);
+ fwrite((const char*) data + 8 + highlight[0], 1, highlight[1] - highlight[0], f);
+ fwrite(highlight_off, 1, strlen(highlight_off), f);
+ fwrite((const char*) data + 8 + highlight[1], 1, l - 8 - highlight[1], f);
+ } else
+ fwrite((const char*) data + 8, 1, l - 8, f);
fputc('\n', f);
return 0;
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
- Set *output_fields) = {
+ Set *output_fields,
+ size_t highlight[2]) = {
[OUTPUT_SHORT] = output_short,
[OUTPUT_SHORT_ISO] = output_short,
unsigned n_columns,
OutputFlags flags,
char **output_fields,
+ size_t highlight[2],
bool *ellipsized) {
int ret;
return ret;
}
- ret = output_funcs[mode](f, j, mode, n_columns, flags, fields);
+ ret = output_funcs[mode](f, j, mode, n_columns, flags, fields, highlight);
if (ellipsized && ret > 0)
*ellipsized = true;
line++;
maybe_print_begin_newline(f, &flags);
- r = output_journal(f, j, mode, n_columns, flags, NULL, ellipsized);
+ r = output_journal(f, j, mode, n_columns, flags, NULL, NULL, ellipsized);
if (r < 0)
return r;
}
char *p;
assert_se(p = strdup("\tFoobar\tbar\twaldo\t"));
- assert_se(strip_tab_ansi(&p, NULL));
+ assert_se(strip_tab_ansi(&p, NULL, NULL));
fprintf(stdout, "<%s>\n", p);
assert_se(streq(p, " Foobar bar waldo "));
free(p);
assert_se(p = strdup(ANSI_HIGHLIGHT "Hello" ANSI_NORMAL ANSI_HIGHLIGHT_RED " world!" ANSI_NORMAL));
- assert_se(strip_tab_ansi(&p, NULL));
+ assert_se(strip_tab_ansi(&p, NULL, NULL));
fprintf(stdout, "<%s>\n", p);
assert_se(streq(p, "Hello world!"));
free(p);
assert_se(p = strdup("\x1B[\x1B[\t\x1B[" ANSI_HIGHLIGHT "\x1B[" "Hello" ANSI_NORMAL ANSI_HIGHLIGHT_RED " world!" ANSI_NORMAL));
- assert_se(strip_tab_ansi(&p, NULL));
+ assert_se(strip_tab_ansi(&p, NULL, NULL));
assert_se(streq(p, "\x1B[\x1B[ \x1B[\x1B[Hello world!"));
free(p);
assert_se(p = strdup("\x1B[waldo"));
- assert_se(strip_tab_ansi(&p, NULL));
+ assert_se(strip_tab_ansi(&p, NULL, NULL));
assert_se(streq(p, "\x1B[waldo"));
free(p);