Make API CTF-agnostic
[babeltrace.git] / common / common.c
index aa67b21f39528436b0d865f37428193ae9777c6e..1c49a465ccfcee27ec228fa2c1862cbe8717fbe2 100644 (file)
 
 #include <unistd.h>
 #include <string.h>
+#include <inttypes.h>
 #include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
-#include <assert.h>
+#include <babeltrace/assert-internal.h>
+#include <stdarg.h>
 #include <ctype.h>
 #include <glib.h>
 #include <stdlib.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <stdbool.h>
 #include <babeltrace/babeltrace-internal.h>
 #include <babeltrace/common-internal.h>
 #include <babeltrace/compat/unistd-internal.h>
@@ -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) {
@@ -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;
@@ -1056,7 +1097,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 +1126,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 +1158,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 +1250,320 @@ 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);
+               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);
+               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);
+               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);
+               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);
+               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);
+               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);
+       BT_ASSERT(*args);
+
+       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);
+}
This page took 0.030792 seconds and 4 git commands to generate.