diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index b2d98ca58d..deab2a5869 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -1749,6 +1749,121 @@ nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len) return TRUE; } +void +nm_utils_strbuf_append_c (char **buf, gsize *len, char c) +{ + switch (*len) { + case 0: + return; + case 1: + (*buf)[0] = '\0'; + *len = 0; + (*buf)++; + return; + default: + (*buf)[0] = c; + (*buf)[1] = '\0'; + (*len)--; + (*buf)++; + return; + } +} + +void +nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str) +{ + gsize src_len; + + switch (*len) { + case 0: + return; + case 1: + if (!str || !*str) { + (*buf)[0] = '\0'; + return; + } + (*buf)[0] = '\0'; + *len = 0; + (*buf)++; + return; + default: + if (!str || !*str) { + (*buf)[0] = '\0'; + return; + } + src_len = g_strlcpy (*buf, str, *len); + if (src_len >= *len) { + *buf = &(*buf)[*len]; + *len = 0; + } else { + *buf = &(*buf)[src_len]; + *len -= src_len; + } + return; + } +} + +void +nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) +{ + char *p = *buf; + va_list args; + gint retval; + + if (*len == 0) + return; + + va_start (args, format); + retval = g_vsnprintf (p, *len, format, args); + va_end (args); + + if (retval >= *len) { + *buf = &p[*len]; + *len = 0; + } else { + *buf = &p[retval]; + *len -= retval; + } +} + +const char * +nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs, + gsize n_descs, + unsigned flags, + char *buf, + gsize len) +{ + gsize i; + char *p; + + nm_utils_to_string_buffer_init (&buf, &len); + + if (!len) + return buf; + + buf[0] = '\0'; + if (!flags) { + return buf; + } + + p = buf; + for (i = 0; flags && i < n_descs; i++) { + if (NM_FLAGS_HAS (flags, descs[i].flag)) { + flags &= ~descs[i].flag; + + if (buf[0] != '\0') + nm_utils_strbuf_append_c (&p, &len, ','); + nm_utils_strbuf_append_str (&p, &len, descs[i].name); + } + } + if (flags) { + if (buf[0] != '\0') + nm_utils_strbuf_append_c (&p, &len, ','); + nm_utils_strbuf_append (&p, &len, "0x%x", flags); + } + return buf; +}; + /*****************************************************************************/ /** diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h index b4cc180013..3da2235559 100644 --- a/src/NetworkManagerUtils.h +++ b/src/NetworkManagerUtils.h @@ -196,6 +196,23 @@ extern char _nm_utils_to_string_buffer[2096]; void nm_utils_to_string_buffer_init (char **buf, gsize *len); gboolean nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len); +typedef struct { + unsigned flag; + const char *name; +} NMUtilsFlags2StrDesc; + +#define NM_UTILS_FLAGS2STR(f, n) { .flag = f, .name = ""n, } + +const char *nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs, + gsize n_descs, + unsigned flags, + char *buf, + gsize len); + +void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) __attribute__((__format__ (__printf__, 3, 4))); +void nm_utils_strbuf_append_c (char **buf, gsize *len, char c); +void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str); + const char *nm_utils_get_shared_wifi_permission (NMConnection *connection); const char *nm_utils_get_ip_config_method (NMConnection *connection, diff --git a/src/tests/test-general.c b/src/tests/test-general.c index 3985d23ebe..2eb524c3b4 100644 --- a/src/tests/test-general.c +++ b/src/tests/test-general.c @@ -971,6 +971,116 @@ test_nm_match_spec_match_config (void) /*******************************************/ +static void +test_nm_utils_strbuf_append (void) +{ +#define BUF_ORIG "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define STR_ORIG "abcdefghijklmnopqrstuvwxyz" + int buf_len; + int rep; + char buf[STRLEN (BUF_ORIG) + 1]; + char str[STRLEN (BUF_ORIG) + 1]; + + for (buf_len = 0; buf_len < 10; buf_len++) { + for (rep = 0; rep < 50; rep++) { + const int s_len = nmtst_get_rand_int () % (sizeof (str) - 5); + char *t_buf; + gsize t_len; + int test_mode; + + strcpy (str, STR_ORIG); + str[s_len] = '\0'; + + g_assert_cmpint (str[sizeof (str) - 1], ==, '\0'); + g_assert_cmpint (strlen (str), ==, s_len); + + strcpy (buf, BUF_ORIG); + + t_buf = buf; + t_len = buf_len; + + test_mode = nmtst_get_rand_int () % 4; + + switch (test_mode) { + case 0: + if (s_len == 1) { + nm_utils_strbuf_append_c (&t_buf, &t_len, str[0]); + break; + } + /* fall-through */ + case 1: + nm_utils_strbuf_append_str (&t_buf, &t_len, str); + break; + case 2: + if (s_len == 1) { + nm_utils_strbuf_append (&t_buf, &t_len, "%c", str[0]); + break; + } + /* fall-through */ + case 3: + nm_utils_strbuf_append (&t_buf, &t_len, "%s", str); + break; + } + + /* Assert that the source-buffer is unmodified. */ + g_assert_cmpint (str[s_len], ==, '\0'); + str[s_len] = STR_ORIG[s_len]; + g_assert (!memcmp (str, STR_ORIG, sizeof (str))); + str[s_len] = '\0'; + + g_assert_cmpint (t_len, >=, 0); + g_assert_cmpint (t_len, <=, buf_len); + g_assert (t_buf >= buf); + + /* Assert what was written to the destination buffer. */ + switch (buf_len) { + case 0: + g_assert_cmpint (t_len, ==, 0); + g_assert (t_buf == buf); + g_assert (!memcmp (buf, BUF_ORIG, sizeof (buf))); + break; + case 1: + if (s_len == 0) { + g_assert_cmpint (t_len, ==, 1); + g_assert (t_buf == buf); + g_assert (buf[0] == '\0'); + g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1)); + } else { + g_assert_cmpint (t_len, ==, 0); + g_assert (t_buf == &buf[1]); + g_assert (buf[0] == '\0'); + g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1)); + } + break; + default: + if (s_len == 0) { + g_assert_cmpint (t_len, ==, buf_len); + g_assert (t_buf == buf); + g_assert (buf[0] == '\0'); + g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1)); + } else if (buf_len <= s_len) { + g_assert_cmpint (t_len, ==, 0); + g_assert (t_buf == &buf[buf_len]); + g_assert (!memcmp (buf, STR_ORIG, buf_len - 1)); + g_assert (buf[buf_len - 1] == '\0'); + g_assert (!memcmp (&buf[buf_len], &BUF_ORIG[buf_len], sizeof (buf) - buf_len)); + } else { + g_assert_cmpint (t_len, >, 0); + g_assert_cmpint (buf_len - t_len, ==, s_len); + g_assert_cmpint (strlen (buf), ==, s_len); + g_assert (t_buf == &buf[s_len]); + g_assert (!memcmp (buf, STR_ORIG, s_len)); + g_assert (buf[s_len] == '\0'); + g_assert (!memcmp (&buf[s_len + 1], &BUF_ORIG[s_len + 1], sizeof (buf) - s_len - 1)); + } + break; + } + } + } +} + +/*******************************************/ + NMTST_DEFINE (); int @@ -978,6 +1088,8 @@ main (int argc, char **argv) { nmtst_init_with_logging (&argc, &argv, NULL, "ALL"); + g_test_add_func ("/general/nm_utils_strbuf_append", test_nm_utils_strbuf_append); + g_test_add_func ("/general/nm_utils_ip6_address_clear_host_address", test_nm_utils_ip6_address_clear_host_address); g_test_add_func ("/general/nm_utils_log_connection_diff", test_nm_utils_log_connection_diff);