#ifndef __MINGW32__
#include <pwd.h>
+#include <sys/ioctl.h>
#endif
-#define SYSTEM_PLUGIN_PATH INSTALL_LIBDIR "/babeltrace2/plugins"
+#define SYSTEM_PLUGIN_PATH BABELTRACE_PLUGINS_DIR
#define HOME_ENV_VAR "HOME"
#define HOME_PLUGIN_SUBPATH "/.local/lib/babeltrace2/plugins"
static const char *bt_common_color_code_fg_magenta = "";
static const char *bt_common_color_code_fg_cyan = "";
static const char *bt_common_color_code_fg_light_gray = "";
+static const char *bt_common_color_code_fg_bright_red = "";
+static const char *bt_common_color_code_fg_bright_green = "";
+static const char *bt_common_color_code_fg_bright_yellow = "";
+static const char *bt_common_color_code_fg_bright_blue = "";
+static const char *bt_common_color_code_fg_bright_magenta = "";
+static const char *bt_common_color_code_fg_bright_cyan = "";
+static const char *bt_common_color_code_fg_bright_light_gray = "";
static const char *bt_common_color_code_bg_default = "";
static const char *bt_common_color_code_bg_red = "";
static const char *bt_common_color_code_bg_green = "";
static const char *bt_common_color_code_bg_cyan = "";
static const char *bt_common_color_code_bg_light_gray = "";
+/*
+ * A color codes structure always filled with the proper color codes for the
+ * terminal.
+ */
+static struct bt_common_color_codes color_codes;
+
+/*
+ * A color codes structure always filled with empty strings, for when we want no
+ * colors.
+ */
+static struct bt_common_color_codes no_color_codes = {
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "", "", "", "", "", "",
+ "", "", "", "", "",
+};
+
static
void __attribute__((constructor)) bt_common_color_ctor(void)
{
+ const char *term_env_var;
+ const char *bright_means_bold_env_var;
+ bool bright_means_bold = true;
+ const char *code_fg_bright_red;
+ const char *code_fg_bright_green;
+ const char *code_fg_bright_yellow;
+ const char *code_fg_bright_blue;
+ const char *code_fg_bright_magenta;
+ const char *code_fg_bright_cyan;
+ const char *code_fg_bright_light_gray;
+
+ /*
+ * Check whether or not the terminal supports having
+ * bold foreground colors which do _not_ become bright
+ * colors, that is, the lines
+ *
+ * $ echo -e "\033[31mTHIS\n\033[1mTHAT\033[0m"
+ *
+ * have the _same_ color, but `THAT` uses a bold font.
+ *
+ * This is the case of the kitty terminal emulator.
+ *
+ * It's also possible with GNOME Terminal since 3.27.2
+ * and xfce4-terminal since 0.8.7 (and GNOME VTE since
+ * 0.51.2), but it's user-configurable. Since we don't
+ * have this configuration value here, assume it's not
+ * the case to support old versions of GNOME Terminal.
+ *
+ * Any user can set the
+ * `BABELTRACE_TERM_COLOR_BRIGHT_MEANS_BOLD` environment
+ * variable to `0` to use the bright foreground color
+ * codes instead of making the normal foreground color
+ * codes bold.
+ *
+ * Summary:
+ *
+ * With kitty or when
+ * `BABELTRACE_TERM_COLOR_BRIGHT_MEANS_BOLD` is `0`:
+ * Output bright colors using dedicated SGR codes
+ * 90 to 97.
+ *
+ * Otherwise:
+ * Output bright colors with bold + SGR codes 30 to
+ * 37.
+ */
+ term_env_var = getenv("TERM");
+
+ if (term_env_var && strcmp(term_env_var, "xterm-kitty") == 0) {
+ /*
+ * The kitty terminal emulator supports
+ * non-bright bold foreground colors.
+ */
+ bright_means_bold = false;
+ }
+
+ bright_means_bold_env_var =
+ getenv("BABELTRACE_TERM_COLOR_BRIGHT_MEANS_BOLD");
+
+ if (bright_means_bold_env_var) {
+ bright_means_bold =
+ !(strcmp(bright_means_bold_env_var, "0") == 0);
+ }
+
+ if (bright_means_bold) {
+ code_fg_bright_red = BT_COMMON_COLOR_FG_BOLD_RED;
+ code_fg_bright_green = BT_COMMON_COLOR_FG_BOLD_GREEN;
+ code_fg_bright_yellow = BT_COMMON_COLOR_FG_BOLD_YELLOW;
+ code_fg_bright_blue = BT_COMMON_COLOR_FG_BOLD_BLUE;
+ code_fg_bright_magenta = BT_COMMON_COLOR_FG_BOLD_MAGENTA;
+ code_fg_bright_cyan = BT_COMMON_COLOR_FG_BOLD_CYAN;
+ code_fg_bright_light_gray = BT_COMMON_COLOR_FG_BOLD_LIGHT_GRAY;
+ } else {
+ code_fg_bright_red = BT_COMMON_COLOR_FG_BRIGHT_RED;
+ code_fg_bright_green = BT_COMMON_COLOR_FG_BRIGHT_GREEN;
+ code_fg_bright_yellow = BT_COMMON_COLOR_FG_BRIGHT_YELLOW;
+ code_fg_bright_blue = BT_COMMON_COLOR_FG_BRIGHT_BLUE;
+ code_fg_bright_magenta = BT_COMMON_COLOR_FG_BRIGHT_MAGENTA;
+ code_fg_bright_cyan = BT_COMMON_COLOR_FG_BRIGHT_CYAN;
+ code_fg_bright_light_gray = BT_COMMON_COLOR_FG_BRIGHT_LIGHT_GRAY;
+ }
+
if (bt_common_colors_supported()) {
bt_common_color_code_reset = BT_COMMON_COLOR_RESET;
bt_common_color_code_bold = BT_COMMON_COLOR_BOLD;
bt_common_color_code_fg_magenta = BT_COMMON_COLOR_FG_MAGENTA;
bt_common_color_code_fg_cyan = BT_COMMON_COLOR_FG_CYAN;
bt_common_color_code_fg_light_gray = BT_COMMON_COLOR_FG_LIGHT_GRAY;
+
+ bt_common_color_code_fg_bright_red = code_fg_bright_red;
+ bt_common_color_code_fg_bright_green = code_fg_bright_green;
+ bt_common_color_code_fg_bright_yellow = code_fg_bright_yellow;
+ bt_common_color_code_fg_bright_blue = code_fg_bright_blue;
+ bt_common_color_code_fg_bright_magenta = code_fg_bright_magenta;
+ bt_common_color_code_fg_bright_cyan = code_fg_bright_cyan;
+ bt_common_color_code_fg_bright_light_gray = code_fg_bright_light_gray;
+
bt_common_color_code_bg_default = BT_COMMON_COLOR_BG_DEFAULT;
bt_common_color_code_bg_red = BT_COMMON_COLOR_BG_RED;
bt_common_color_code_bg_green = BT_COMMON_COLOR_BG_GREEN;
bt_common_color_code_bg_cyan = BT_COMMON_COLOR_BG_CYAN;
bt_common_color_code_bg_light_gray = BT_COMMON_COLOR_BG_LIGHT_GRAY;
}
+
+ color_codes.reset = BT_COMMON_COLOR_RESET;
+ color_codes.bold = BT_COMMON_COLOR_BOLD;
+ color_codes.fg_default = BT_COMMON_COLOR_FG_DEFAULT;
+ color_codes.fg_red = BT_COMMON_COLOR_FG_RED;
+ color_codes.fg_green = BT_COMMON_COLOR_FG_GREEN;
+ color_codes.fg_yellow = BT_COMMON_COLOR_FG_YELLOW;
+ color_codes.fg_blue = BT_COMMON_COLOR_FG_BLUE;
+ color_codes.fg_magenta = BT_COMMON_COLOR_FG_MAGENTA;
+ color_codes.fg_cyan = BT_COMMON_COLOR_FG_CYAN;
+ color_codes.fg_light_gray = BT_COMMON_COLOR_FG_LIGHT_GRAY;
+ color_codes.fg_bright_red = code_fg_bright_red;
+ color_codes.fg_bright_green = code_fg_bright_green;
+ color_codes.fg_bright_yellow = code_fg_bright_yellow;
+ color_codes.fg_bright_blue = code_fg_bright_blue;
+ color_codes.fg_bright_magenta = code_fg_bright_magenta;
+ color_codes.fg_bright_cyan = code_fg_bright_cyan;
+ color_codes.fg_bright_light_gray = code_fg_bright_light_gray;
+ color_codes.bg_default = BT_COMMON_COLOR_BG_DEFAULT;
+ color_codes.bg_red = BT_COMMON_COLOR_BG_RED;
+ color_codes.bg_green = BT_COMMON_COLOR_BG_GREEN;
+ color_codes.bg_yellow = BT_COMMON_COLOR_BG_YELLOW;
+ color_codes.bg_blue = BT_COMMON_COLOR_BG_BLUE;
+ color_codes.bg_magenta = BT_COMMON_COLOR_BG_MAGENTA;
+ color_codes.bg_cyan = BT_COMMON_COLOR_BG_CYAN;
+ color_codes.bg_light_gray = BT_COMMON_COLOR_BG_LIGHT_GRAY;
}
BT_HIDDEN
return bt_common_color_code_fg_light_gray;
}
+BT_HIDDEN
+const char *bt_common_color_fg_bright_red(void)
+{
+ return bt_common_color_code_fg_bright_red;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_bright_green(void)
+{
+ return bt_common_color_code_fg_bright_green;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_bright_yellow(void)
+{
+ return bt_common_color_code_fg_bright_yellow;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_bright_blue(void)
+{
+ return bt_common_color_code_fg_bright_blue;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_bright_magenta(void)
+{
+ return bt_common_color_code_fg_bright_magenta;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_bright_cyan(void)
+{
+ return bt_common_color_code_fg_bright_cyan;
+}
+
+BT_HIDDEN
+const char *bt_common_color_fg_bright_light_gray(void)
+{
+ return bt_common_color_code_fg_bright_light_gray;
+}
+
BT_HIDDEN
const char *bt_common_color_bg_default(void)
{
return bt_common_color_code_bg_light_gray;
}
+BT_HIDDEN
+void bt_common_color_get_codes(struct bt_common_color_codes *codes,
+ enum bt_common_color_when use_colors)
+{
+ if (use_colors == BT_COMMON_COLOR_WHEN_ALWAYS) {
+ *codes = color_codes;
+ } else if (use_colors == BT_COMMON_COLOR_WHEN_NEVER) {
+ *codes = no_color_codes;
+ } else {
+ BT_ASSERT(use_colors == BT_COMMON_COLOR_WHEN_AUTO);
+
+ if (bt_common_colors_supported()) {
+ *codes = color_codes;
+ } else {
+ *codes = no_color_codes;
+ }
+ }
+}
+
BT_HIDDEN
GString *bt_common_string_until(const char *input, const char *escapable_chars,
const char *end_chars, size_t *end_pos)
error:
if (output) {
g_string_free(output, TRUE);
+ output = NULL;
}
end:
{
const char *ch;
bool printable = true;
- BT_ASSERT(input);
+ BT_ASSERT_DBG(input);
for (ch = input; *ch != '\0'; ch++) {
- if (!isprint(*ch) && *ch != '\n' && *ch != '\r' &&
+ if (!isprint((unsigned char) *ch) && *ch != '\n' && *ch != '\r' &&
*ch != '\t' && *ch != '\v') {
printable = false;
goto end;
at += end_pos;
- /* :// */
+ /* `://` */
if (strncmp(at, "://", 3) != 0) {
if (error_buf) {
snprintf(error_buf, error_buf_size,
goto error;
}
+ /* Skip `://` */
at += 3;
/* Hostname */
}
if (at[end_pos] == '\0') {
+ /* Relay daemon hostname and ports provided only */
goto end;
}
at += end_pos;
- /* /host/ */
+ /* `/host/` */
if (strncmp(at, "/host/", 6) != 0) {
if (error_buf) {
snprintf(error_buf, error_buf_size,
}
if (at[end_pos] == '\0') {
- goto end;
+ if (error_buf) {
+ snprintf(error_buf, error_buf_size,
+ "Missing `/` after target hostname (`%s`)",
+ parts.target_hostname->str);
+ }
+
+ goto error;
}
+ /* Skip `/` */
at += end_pos + 1;
/* Session name */
norm_path = NULL;
}
end:
- if (tmp) {
- free(tmp);
- }
+ free(tmp);
return norm_path;
}
#else
if (page_size < 0) {
BT_LOGF("Cannot get system's page size: ret=%d",
page_size);
- abort();
+ bt_common_abort();
}
return page_size;
strncpy(_tmp_fmt, *out_fmt_ch, _tmp_fmt_size); \
_tmp_fmt[_tmp_fmt_size] = '\0'; \
_count = snprintf(*buf_ch, _size, _tmp_fmt, __VA_ARGS__); \
- BT_ASSERT(_count >= 0); \
+ BT_ASSERT_DBG(_count >= 0); \
*buf_ch += MIN(_count, _size); \
} while (0)
switch (length_mod) {
case LENGTH_MOD_NONE:
- BUF_STD_APPEND_SINGLE_ARG(int);
- break;
case LENGTH_MOD_LOW_L:
- BUF_STD_APPEND_SINGLE_ARG(wint_t);
+ BUF_STD_APPEND_SINGLE_ARG(int);
break;
default:
- abort();
+ bt_common_abort();
}
break;
}
BUF_STD_APPEND_SINGLE_ARG(wchar_t *);
break;
default:
- abort();
+ bt_common_abort();
}
break;
case 'd':
BUF_STD_APPEND_SINGLE_ARG(size_t);
break;
default:
- abort();
+ bt_common_abort();
}
break;
case 'o':
BUF_STD_APPEND_SINGLE_ARG(size_t);
break;
default:
- abort();
+ bt_common_abort();
}
break;
case 'f':
BUF_STD_APPEND_SINGLE_ARG(long double);
break;
default:
- abort();
+ bt_common_abort();
}
break;
case 'p':
if (length_mod == LENGTH_MOD_NONE) {
BUF_STD_APPEND_SINGLE_ARG(void *);
} else {
- abort();
+ bt_common_abort();
}
break;
default:
- abort();
+ bt_common_abort();
}
update_rw_fmt:
const char *fmt_ch = fmt;
char *buf_ch = buf;
- BT_ASSERT(buf);
- BT_ASSERT(fmt);
+ BT_ASSERT_DBG(buf);
+ BT_ASSERT_DBG(fmt);
while (*fmt_ch != '\0') {
switch (*fmt_ch) {
case '%':
- BT_ASSERT(fmt_ch[1] != '\0');
+ BT_ASSERT_DBG(fmt_ch[1] != '\0');
if (fmt_ch[1] == intro) {
handle_specifier(priv_data, &buf_ch,
uint64_t sep_count;
uint64_t new_len;
- BT_ASSERT(digits_per_group > 0);
- BT_ASSERT(sep != '\0');
+ BT_ASSERT_DBG(digits_per_group > 0);
+ BT_ASSERT_DBG(sep != '\0');
/* Compute new length of `str` */
orig_len = strlen(str);
- BT_ASSERT(orig_len > 0);
+ BT_ASSERT_DBG(orig_len > 0);
sep_count = (orig_len - 1) / digits_per_group;
new_len = strlen(str) + sep_count;
i++;
}
}
+
+BT_HIDDEN
+GString *bt_common_fold(const char *str, unsigned int total_length,
+ unsigned int indent)
+{
+ const unsigned int content_length = total_length - indent;
+ GString *folded = g_string_new(NULL);
+ GString *tmp_line = g_string_new(NULL);
+ gchar **lines = NULL;
+ gchar **line_words = NULL;
+ gchar * const *line;
+ unsigned int i;
+
+ BT_ASSERT_DBG(str);
+ BT_ASSERT_DBG(indent < total_length);
+ BT_ASSERT_DBG(tmp_line);
+ BT_ASSERT_DBG(folded);
+
+ if (strlen(str) == 0) {
+ /* Empty input string: empty output string */
+ goto end;
+ }
+
+ /* Split lines */
+ lines = g_strsplit(str, "\n", 0);
+ BT_ASSERT_DBG(lines);
+
+ /* For each source line */
+ for (line = lines; *line; line++) {
+ gchar * const *word;
+
+ /*
+ * Append empty line without indenting if source line is
+ * empty.
+ */
+ if (strlen(*line) == 0) {
+ g_string_append_c(folded, '\n');
+ continue;
+ }
+
+ /* Split words */
+ line_words = g_strsplit(*line, " ", 0);
+ BT_ASSERT_DBG(line_words);
+
+ /*
+ * Indent for first line (we know there's at least one
+ * word at this point).
+ */
+ for (i = 0; i < indent; i++) {
+ g_string_append_c(folded, ' ');
+ }
+
+ /* Append words, folding when necessary */
+ g_string_assign(tmp_line, "");
+
+ for (word = line_words; *word; word++) {
+ /*
+ * `tmp_line->len > 0` is in the condition so
+ * that words that are larger than
+ * `content_length` are at least written on
+ * their own line.
+ *
+ * `tmp_line->len - 1` because the temporary
+ * line always contains a trailing space which
+ * won't be part of the line if we fold.
+ */
+ if (tmp_line->len > 0 &&
+ tmp_line->len - 1 + strlen(*word) >= content_length) {
+ /* Fold (without trailing space) */
+ g_string_append_len(folded,
+ tmp_line->str, tmp_line->len - 1);
+ g_string_append_c(folded, '\n');
+
+ /* Indent new line */
+ for (i = 0; i < indent; i++) {
+ g_string_append_c(folded, ' ');
+ }
+
+ g_string_assign(tmp_line, "");
+ }
+
+ /* Append current word and space to temporary line */
+ g_string_append(tmp_line, *word);
+ g_string_append_c(tmp_line, ' ');
+ }
+
+ /* Append last line if any, without trailing space */
+ if (tmp_line->len > 0) {
+ g_string_append_len(folded, tmp_line->str,
+ tmp_line->len - 1);
+ }
+
+ /* Append source newline */
+ g_string_append_c(folded, '\n');
+
+ /* Free array of this line's words */
+ g_strfreev(line_words);
+ line_words = NULL;
+ }
+
+ /* Remove trailing newline if any */
+ if (folded->str[folded->len - 1] == '\n') {
+ g_string_truncate(folded, folded->len - 1);
+ }
+
+end:
+ if (lines) {
+ g_strfreev(lines);
+ }
+
+ BT_ASSERT_DBG(!line_words);
+
+ if (tmp_line) {
+ g_string_free(tmp_line, TRUE);
+ }
+
+ return folded;
+}
+
+#ifdef __MINGW32__
+BT_HIDDEN
+int bt_common_get_term_size(unsigned int *width, unsigned int *height)
+{
+ /* Not supported on Windows yet */
+ return -1;
+}
+#else /* __MINGW32__ */
+BT_HIDDEN
+int bt_common_get_term_size(unsigned int *width, unsigned int *height)
+{
+ int ret = 0;
+ struct winsize winsize;
+
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize) < 0) {
+ ret = -1;
+ goto end;
+ }
+
+ if (width) {
+ *width = (unsigned int) winsize.ws_col;
+ }
+
+ if (height) {
+ *height = (unsigned int) winsize.ws_row;
+ }
+
+end:
+ return ret;
+}
+#endif /* __MINGW32__ */
+
+BT_HIDDEN
+int bt_common_g_string_append_printf(GString *str, const char *fmt, ...)
+{
+ va_list ap;
+ gsize len, allocated_len, available_len;
+ int print_len;
+
+ /* str->len excludes \0. */
+ len = str->len;
+ /* Explicitly exclude \0. */
+ allocated_len = str->allocated_len - 1;
+ available_len = allocated_len - len;
+
+ str->len = allocated_len;
+ va_start(ap, fmt);
+ print_len = vsnprintf(str->str + len, available_len + 1, fmt, ap);
+ va_end(ap);
+ if (print_len < 0) {
+ return print_len;
+ }
+ if (G_UNLIKELY(available_len < print_len)) {
+ /* Resize. */
+ g_string_set_size(str, len + print_len);
+ va_start(ap, fmt);
+ print_len = vsprintf(str->str + len, fmt, ap);
+ va_end(ap);
+ } else {
+ str->len = len + print_len;
+ }
+ return print_len;
+}
+
+BT_HIDDEN
+int bt_common_append_file_content_to_g_string(GString *str, FILE *fp)
+{
+ const size_t chunk_size = 4096;
+ int ret = 0;
+ char *buf;
+ size_t read_len;
+ gsize orig_len = str->len;
+
+ BT_ASSERT(str);
+ BT_ASSERT(fp);
+ buf = g_malloc(chunk_size);
+ if (!buf) {
+ ret = -1;
+ goto end;
+ }
+
+ while (true) {
+ if (ferror(fp)) {
+ ret = -1;
+ goto end;
+ }
+
+ if (feof(fp)) {
+ break;
+ }
+
+ read_len = fread(buf, 1, chunk_size, fp);
+ g_string_append_len(str, buf, read_len);
+ }
+
+end:
+ if (ret) {
+ /* Remove what was appended */
+ g_string_truncate(str, orig_len);
+ }
+
+ g_free(buf);
+ return ret;
+}
+
+BT_HIDDEN
+void bt_common_abort(void)
+{
+ static const char * const exec_on_abort_env_name =
+ "BABELTRACE_EXEC_ON_ABORT";
+ const char *env_exec_on_abort;
+
+ env_exec_on_abort = getenv(exec_on_abort_env_name);
+ if (env_exec_on_abort) {
+ if (bt_common_is_setuid_setgid()) {
+ goto do_abort;
+ }
+
+ (void) g_spawn_command_line_sync(env_exec_on_abort,
+ NULL, NULL, NULL, NULL);
+ }
+
+do_abort:
+ abort();
+}