X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=common%2Fcommon.c;h=68f537ba0187c08f0f5bfc89fdf83df6babe8d20;hb=2f69c7e71eff0b5b313a6737f8744605e7a6ce7f;hp=aa67b21f39528436b0d865f37428193ae9777c6e;hpb=1cd3decc938dccecb88719fa6bb6d7fc8329ecee;p=babeltrace.git diff --git a/common/common.c b/common/common.c index aa67b21f..68f537ba 100644 --- a/common/common.c +++ b/common/common.c @@ -27,12 +27,18 @@ #include #include +#include #include +#include #include -#include +#include +#include #include #include #include +#include +#include +#include #include #include #include @@ -188,7 +194,7 @@ int bt_common_append_plugin_path_dirs(const char *paths, GPtrArray *dirs) const char *end; size_t init_dirs_len; - assert(dirs); + BT_ASSERT(dirs); init_dirs_len = dirs->len; if (!paths) { @@ -240,13 +246,37 @@ end: return ret; } +static +bool isarealtty(int fd) +{ + bool istty = false; + struct stat tty_stats; + + if (!isatty(fd)) { + /* Not a TTY */ + goto end; + } + + if (fstat(fd, &tty_stats) == 0) { + if (!S_ISCHR(tty_stats.st_mode)) { + /* Not a character device: not a TTY */ + goto end; + } + } + + istty = true; + +end: + return istty; +} + BT_HIDDEN bool bt_common_colors_supported(void) { static bool supports_colors = false; static bool supports_colors_set = false; - const char *term; - const char *force; + const char *term_env_var; + const char *term_color_env_var; if (supports_colors_set) { goto end; @@ -254,28 +284,39 @@ bool bt_common_colors_supported(void) supports_colors_set = true; - force = getenv("BABELTRACE_FORCE_COLORS"); - if (force && strcmp(force, "1") == 0) { - supports_colors = true; - goto end; + /* + * `BABELTRACE_TERM_COLOR` environment variable always overrides + * the automatic color support detection. + */ + term_color_env_var = getenv("BABELTRACE_TERM_COLOR"); + if (term_color_env_var) { + if (g_ascii_strcasecmp(term_color_env_var, "always") == 0) { + /* Force colors */ + supports_colors = true; + } else if (g_ascii_strcasecmp(term_color_env_var, "never") == 0) { + /* Force no colors */ + goto end; + } } - term = getenv("TERM"); - if (!term) { + /* We need a compatible, known terminal */ + term_env_var = getenv("TERM"); + if (!term_env_var) { goto end; } - if (strncmp(term, "xterm", 5) != 0 && - strncmp(term, "rxvt", 4) != 0 && - strncmp(term, "konsole", 7) != 0 && - strncmp(term, "gnome", 5) != 0 && - strncmp(term, "screen", 5) != 0 && - strncmp(term, "tmux", 4) != 0 && - strncmp(term, "putty", 5) != 0) { + if (strncmp(term_env_var, "xterm", 5) != 0 && + strncmp(term_env_var, "rxvt", 4) != 0 && + strncmp(term_env_var, "konsole", 7) != 0 && + strncmp(term_env_var, "gnome", 5) != 0 && + strncmp(term_env_var, "screen", 5) != 0 && + strncmp(term_env_var, "tmux", 4) != 0 && + strncmp(term_env_var, "putty", 5) != 0) { goto end; } - if (!isatty(1)) { + /* Both standard output and error streams need to be TTYs */ + if (!isarealtty(STDOUT_FILENO) || !isarealtty(STDERR_FILENO)) { goto end; } @@ -536,7 +577,7 @@ bool bt_common_string_is_printable(const char *input) { const char *ch; bool printable = true; - assert(input); + BT_ASSERT(input); for (ch = input; *ch != '\0'; ch++) { if (!isprint(*ch) && *ch != '\n' && *ch != '\r' && @@ -590,7 +631,7 @@ struct bt_common_lttng_live_url_parts bt_common_parse_lttng_live_url( const char *at = url; size_t end_pos; - assert(url); + BT_ASSERT(url); memset(&parts, 0, sizeof(parts)); parts.port = -1; @@ -759,7 +800,7 @@ void bt_common_normalize_star_glob_pattern(char *pattern) char *np; bool got_star = false; - assert(pattern); + BT_ASSERT(pattern); for (p = pattern, np = pattern; *p != '\0'; p++) { switch (*p) { @@ -781,7 +822,7 @@ void bt_common_normalize_star_glob_pattern(char *pattern) goto end; } - /* Fall through default case. */ + /* fall-through */ default: got_star = false; break; @@ -967,7 +1008,7 @@ retry: * ^ ^ SUCCESS */ while ((c - candidate) < candidate_len && *c != '\0') { - assert(*c); + BT_ASSERT(*c); if (at_end_of_pattern(p, pattern, pattern_len)) { goto end_of_pattern; @@ -1001,6 +1042,7 @@ retry: * Fall through the default case which compares * the escaped character now. */ + /* fall-through */ default: if (at_end_of_pattern(p, pattern, pattern_len) || *c != *p) { @@ -1056,7 +1098,7 @@ void append_path_parts(const char *path, GPtrArray *parts) if (ch - last > 0) { GString *part = g_string_new(NULL); - assert(part); + BT_ASSERT(part); g_string_append_len(part, last, ch - last); g_ptr_array_add(parts, part); } @@ -1085,7 +1127,7 @@ GString *bt_common_normalize_path(const char *path, const char *wd) char *tmp; GString *norm_path = NULL; - assert(path); + BT_ASSERT(path); tmp = _fullpath(NULL, path, PATH_MAX); if (!tmp) { @@ -1117,7 +1159,7 @@ GString *bt_common_normalize_path(const char *path, const char *wd) GString *norm_path; GPtrArray *parts = NULL; - assert(path); + BT_ASSERT(path); norm_path = g_string_new(G_DIR_SEPARATOR_S); if (!norm_path) { goto error; @@ -1209,3 +1251,319 @@ size_t bt_common_get_page_size(void) return page_size; } + +#define BUF_STD_APPEND(...) \ + do { \ + char _tmp_fmt[64]; \ + int _count; \ + size_t _size = buf_size - (size_t) (*buf_ch - buf); \ + size_t _tmp_fmt_size = (size_t) (fmt_ch - *out_fmt_ch); \ + 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); \ + *buf_ch += MIN(_count, _size); \ + } while (0) + +#define BUF_STD_APPEND_SINGLE_ARG(_type) \ + do { \ + _type _arg = va_arg(*args, _type); \ + BUF_STD_APPEND(_arg); \ + } while (0) + +static inline void handle_conversion_specifier_std(char *buf, char **buf_ch, + size_t buf_size, const char **out_fmt_ch, va_list *args) +{ + const char *fmt_ch = *out_fmt_ch; + enum LENGTH_MODIFIER { + LENGTH_MOD_H, + LENGTH_MOD_HH, + LENGTH_MOD_NONE, + LENGTH_MOD_LOW_L, + LENGTH_MOD_LOW_LL, + LENGTH_MOD_UP_L, + LENGTH_MOD_Z, + } length_mod = LENGTH_MOD_NONE; + + /* skip '%' */ + fmt_ch++; + + if (*fmt_ch == '%') { + fmt_ch++; + **buf_ch = '%'; + (*buf_ch)++; + goto update_rw_fmt; + } + + /* flags */ + for (;;) { + switch (*fmt_ch) { + case '-': + case '+': + case ' ': + case '#': + case '0': + case '\'': + fmt_ch++; + continue; + default: + break; + } + break; + } + + /* width */ + for (;;) { + if (*fmt_ch < '0' || *fmt_ch > '9') { + break; + } + + fmt_ch++; + } + + /* precision */ + if (*fmt_ch == '.') { + fmt_ch++; + + for (;;) { + if (*fmt_ch < '0' || *fmt_ch > '9') { + break; + } + + fmt_ch++; + } + } + + /* format (PRI*64) */ + if (strncmp(fmt_ch, PRId64, sizeof(PRId64) - 1) == 0) { + fmt_ch += sizeof(PRId64) - 1; + BUF_STD_APPEND_SINGLE_ARG(int64_t); + goto update_rw_fmt; + } else if (strncmp(fmt_ch, PRIu64, sizeof(PRIu64) - 1) == 0) { + fmt_ch += sizeof(PRIu64) - 1; + BUF_STD_APPEND_SINGLE_ARG(uint64_t); + goto update_rw_fmt; + } else if (strncmp(fmt_ch, PRIx64, sizeof(PRIx64) - 1) == 0) { + fmt_ch += sizeof(PRIx64) - 1; + BUF_STD_APPEND_SINGLE_ARG(uint64_t); + goto update_rw_fmt; + } else if (strncmp(fmt_ch, PRIX64, sizeof(PRIX64) - 1) == 0) { + fmt_ch += sizeof(PRIX64) - 1; + BUF_STD_APPEND_SINGLE_ARG(uint64_t); + goto update_rw_fmt; + } else if (strncmp(fmt_ch, PRIo64, sizeof(PRIo64) - 1) == 0) { + fmt_ch += sizeof(PRIo64) - 1; + BUF_STD_APPEND_SINGLE_ARG(uint64_t); + goto update_rw_fmt; + } else if (strncmp(fmt_ch, PRIi64, sizeof(PRIi64) - 1) == 0) { + fmt_ch += sizeof(PRIi64) - 1; + BUF_STD_APPEND_SINGLE_ARG(int64_t); + goto update_rw_fmt; + } + + // length modifier + switch (*fmt_ch) { + case 'h': + length_mod = LENGTH_MOD_H; + fmt_ch++; + + if (*fmt_ch == 'h') { + length_mod = LENGTH_MOD_HH; + fmt_ch++; + break; + } + break; + case 'l': + length_mod = LENGTH_MOD_LOW_L; + fmt_ch++; + + if (*fmt_ch == 'l') { + length_mod = LENGTH_MOD_LOW_LL; + fmt_ch++; + break; + } + break; + case 'L': + length_mod = LENGTH_MOD_UP_L; + fmt_ch++; + break; + case 'z': + length_mod = LENGTH_MOD_Z; + fmt_ch++; + break; + default: + break; + } + + // format + switch (*fmt_ch) { + case 'c': + { + fmt_ch++; + + 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); + break; + default: + abort(); + } + break; + } + case 's': + fmt_ch++; + + switch (length_mod) { + case LENGTH_MOD_NONE: + BUF_STD_APPEND_SINGLE_ARG(char *); + break; + case LENGTH_MOD_LOW_L: + BUF_STD_APPEND_SINGLE_ARG(wchar_t *); + break; + default: + abort(); + } + break; + case 'd': + case 'i': + fmt_ch++; + + switch (length_mod) { + case LENGTH_MOD_NONE: + case LENGTH_MOD_H: + case LENGTH_MOD_HH: + BUF_STD_APPEND_SINGLE_ARG(int); + break; + case LENGTH_MOD_LOW_L: + BUF_STD_APPEND_SINGLE_ARG(long); + break; + case LENGTH_MOD_LOW_LL: + BUF_STD_APPEND_SINGLE_ARG(long long); + break; + case LENGTH_MOD_Z: + BUF_STD_APPEND_SINGLE_ARG(size_t); + break; + default: + abort(); + } + break; + case 'o': + case 'x': + case 'X': + case 'u': + fmt_ch++; + + switch (length_mod) { + case LENGTH_MOD_NONE: + case LENGTH_MOD_H: + case LENGTH_MOD_HH: + BUF_STD_APPEND_SINGLE_ARG(unsigned int); + break; + case LENGTH_MOD_LOW_L: + BUF_STD_APPEND_SINGLE_ARG(unsigned long); + break; + case LENGTH_MOD_LOW_LL: + BUF_STD_APPEND_SINGLE_ARG(unsigned long long); + break; + case LENGTH_MOD_Z: + BUF_STD_APPEND_SINGLE_ARG(size_t); + break; + default: + abort(); + } + break; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + fmt_ch++; + + switch (length_mod) { + case LENGTH_MOD_NONE: + BUF_STD_APPEND_SINGLE_ARG(double); + break; + case LENGTH_MOD_UP_L: + BUF_STD_APPEND_SINGLE_ARG(long double); + break; + default: + abort(); + } + break; + case 'p': + fmt_ch++; + + if (length_mod == LENGTH_MOD_NONE) { + BUF_STD_APPEND_SINGLE_ARG(void *); + } else { + abort(); + } + break; + default: + abort(); + } + +update_rw_fmt: + *out_fmt_ch = fmt_ch; +} + +BT_HIDDEN +void bt_common_custom_vsnprintf(char *buf, size_t buf_size, + char intro, + bt_common_handle_custom_specifier_func handle_specifier, + void *priv_data, const char *fmt, va_list *args) +{ + const char *fmt_ch = fmt; + char *buf_ch = buf; + + BT_ASSERT(buf); + BT_ASSERT(fmt); + + while (*fmt_ch != '\0') { + switch (*fmt_ch) { + case '%': + BT_ASSERT(fmt_ch[1] != '\0'); + + if (fmt_ch[1] == intro) { + handle_specifier(priv_data, &buf_ch, + buf_size - (size_t) (buf_ch - buf), + &fmt_ch, args); + } else { + handle_conversion_specifier_std(buf, &buf_ch, + buf_size, &fmt_ch, args); + } + + if (buf_ch >= buf + buf_size - 1) { + fmt_ch = ""; + } + break; + default: + *buf_ch = *fmt_ch; + buf_ch++; + if (buf_ch >= buf + buf_size - 1) { + fmt_ch = ""; + } + + fmt_ch++; + } + } + + *buf_ch = '\0'; +} + +BT_HIDDEN +void bt_common_custom_snprintf(char *buf, size_t buf_size, + char intro, + bt_common_handle_custom_specifier_func handle_specifier, + void *priv_data, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + bt_common_custom_vsnprintf(buf, buf_size, intro, handle_specifier, + priv_data, fmt, &args); + va_end(args); +}