shared: add nm_strquote() util

We already have nm_strquote_a(). That is useful, but uses alloca(), hence it
is ill suited to be called from a macro, inside a loop, or from a function
that should be inlined.

Instead, add nm_strquote() that has the same purpose but writes to a provided
string buffer.
This commit is contained in:
Thomas Haller 2017-10-05 14:27:24 +02:00
parent dccf9f3a61
commit f1009bcde3
3 changed files with 157 additions and 0 deletions

View file

@ -4852,6 +4852,88 @@ test_hexstr2bin (void)
/*****************************************************************************/
static void
_do_strquote (const char *str, gsize buf_len, const char *expected)
{
char canary = (char) nmtst_get_rand_int ();
gs_free char *buf_full = g_malloc (buf_len + 2);
char *buf = &buf_full[1];
const char *b;
buf[-1] = canary;
buf[buf_len] = canary;
if (buf_len == 0) {
b = nm_strquote (NULL, 0, str);
g_assert (b == NULL);
g_assert (expected == NULL);
b = nm_strquote (buf, 0, str);
g_assert (b == buf);
} else {
b = nm_strquote (buf, buf_len, str);
g_assert (b == buf);
g_assert (strlen (b) < buf_len);
g_assert_cmpstr (expected, ==, b);
}
g_assert (buf[-1] == canary);
g_assert (buf[buf_len] == canary);
}
static void
test_nm_strquote (void)
{
_do_strquote (NULL, 0, NULL);
_do_strquote ("", 0, NULL);
_do_strquote ("a", 0, NULL);
_do_strquote ("ab", 0, NULL);
_do_strquote (NULL, 1, "");
_do_strquote (NULL, 2, "(");
_do_strquote (NULL, 3, "(n");
_do_strquote (NULL, 4, "(nu");
_do_strquote (NULL, 5, "(nul");
_do_strquote (NULL, 6, "(null");
_do_strquote (NULL, 7, "(null)");
_do_strquote (NULL, 8, "(null)");
_do_strquote (NULL, 100, "(null)");
_do_strquote ("", 1, "");
_do_strquote ("", 2, "^");
_do_strquote ("", 3, "\"\"");
_do_strquote ("", 4, "\"\"");
_do_strquote ("", 5, "\"\"");
_do_strquote ("", 100, "\"\"");
_do_strquote ("a", 1, "");
_do_strquote ("a", 2, "^");
_do_strquote ("a", 3, "\"^");
_do_strquote ("a", 4, "\"a\"");
_do_strquote ("a", 5, "\"a\"");
_do_strquote ("a", 6, "\"a\"");
_do_strquote ("a", 100, "\"a\"");
_do_strquote ("ab", 1, "");
_do_strquote ("ab", 2, "^");
_do_strquote ("ab", 3, "\"^");
_do_strquote ("ab", 4, "\"a^");
_do_strquote ("ab", 5, "\"ab\"");
_do_strquote ("ab", 6, "\"ab\"");
_do_strquote ("ab", 7, "\"ab\"");
_do_strquote ("ab", 100, "\"ab\"");
_do_strquote ("abc", 1, "");
_do_strquote ("abc", 2, "^");
_do_strquote ("abc", 3, "\"^");
_do_strquote ("abc", 4, "\"a^");
_do_strquote ("abc", 5, "\"ab^");
_do_strquote ("abc", 6, "\"abc\"");
_do_strquote ("abc", 7, "\"abc\"");
_do_strquote ("abc", 100, "\"abc\"");
}
/*****************************************************************************/
#define UUID_NIL "00000000-0000-0000-0000-000000000000"
#define UUID_NS_DNS "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
@ -6366,6 +6448,7 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/test_setting_user_data", test_setting_user_data);
g_test_add_func ("/core/general/hexstr2bin", test_hexstr2bin);
g_test_add_func ("/core/general/nm_strquote", test_nm_strquote);
g_test_add_func ("/core/general/test_nm_utils_uuid_generate_from_string", test_nm_utils_uuid_generate_from_string);
g_test_add_func ("/core/general/_nm_utils_uuid_generate_from_strings", test_nm_utils_uuid_generate_from_strings);

View file

@ -115,6 +115,78 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
/*****************************************************************************/
/**
* nm_strquote:
* @buf: the output buffer of where to write the quoted @str argument.
* @buf_len: the size of @buf.
* @str: (allow-none): the string to quote.
*
* Writes @str to @buf with quoting. The resulting buffer
* is always NUL terminated, unless @buf_len is zero.
* If @str is %NULL, it writes "(null)".
*
* If @str needs to be truncated, the closing quote is '^' instead
* of '"'.
*
* This is similar to nm_strquote_a(), which however uses alloca()
* to allocate a new buffer. Also, here @buf_len is the size of @buf,
* while nm_strquote_a() has the number of characters to print. The latter
* doesn't include the quoting.
*
* Returns: the input buffer with the quoted string. */
const char *
nm_strquote (char *buf, gsize buf_len, const char *str)
{
const char *const buf0 = buf;
if (!str) {
nm_utils_strbuf_append_str (&buf, &buf_len, "(null)");
goto out;
}
if (G_UNLIKELY (buf_len <= 2)) {
switch (buf_len) {
case 2:
*(buf++) = '^';
/* fall-through*/
case 1:
*(buf++) = '\0';
break;
}
goto out;
}
*(buf++) = '"';
buf_len--;
nm_utils_strbuf_append_str (&buf, &buf_len, str);
/* if the string was too long we indicate truncation with a
* '^' instead of a closing quote. */
if (G_UNLIKELY (buf_len <= 1)) {
switch (buf_len) {
case 1:
buf[-1] = '^';
break;
case 0:
buf[-2] = '^';
break;
default:
nm_assert_not_reached ();
break;
}
} else {
nm_assert (buf_len >= 2);
*(buf++) = '"';
*(buf++) = '\0';
}
out:
return buf0;
}
/*****************************************************************************/
char _nm_utils_to_string_buffer[];
void

View file

@ -166,6 +166,8 @@ void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) _n
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_strquote (char *buf, gsize buf_len, const char *str);
/*****************************************************************************/
const char **nm_utils_strsplit_set (const char *str, const char *delimiters);