Commit dad58d73 authored by Richard Hughes's avatar Richard Hughes

Add a g_ref_string_new_len() to allow creating from non-NUL byte arrays

A lot of GLib APIs provide a string length and explicitly say that the strings
are not NUL terminated. For instance, parsing XML using GMarkupParser or
reading packed binary strings from mmapped data files.
parent 2585099a
Pipeline #18795 passed with stages
in 9 minutes and 28 seconds
......@@ -3497,6 +3497,7 @@ g_arc_box_get_size
<FILE>refstring</FILE>
g_ref_string_new
g_ref_string_new_intern
g_ref_string_new_len
g_ref_string_acquire
g_ref_string_release
g_ref_string_length
......
......@@ -130,6 +130,39 @@ g_ref_string_new (const char *str)
return res;
}
/**
* g_ref_string_new_len:
* @str: (not nullable): a string
* @len: length of @str to use, or -1 if @str is nul-terminated
*
* Creates a new reference counted string and copies the contents of @str
* into it, up to @len bytes.
*
* Since this function does not stop at nul bytes, it is the caller's
* responsibility to ensure that @str has at least @len addressable bytes.
*
* Returns: (transfer full) (not nullable): the newly created reference counted string
*
* Since: 2.58
*/
char *
g_ref_string_new_len (const char *str, gssize len)
{
char *res;
g_return_val_if_fail (str != NULL, NULL);
if (len < 0)
return g_ref_string_new (str);
/* allocate then copy as str[len] may not be readable */
res = (char *) g_atomic_rc_box_alloc ((gsize) len + 1);
memcpy (res, str, len);
res[len] = '\0';
return res;
}
/* interned_str_equal: variant of g_str_equal() that compares
* pointers as well as contents; this avoids running strcmp()
* on arbitrarily long strings, as it's more likely to have
......
......@@ -26,6 +26,9 @@ G_BEGIN_DECLS
GLIB_AVAILABLE_IN_2_58
char * g_ref_string_new (const char *str);
GLIB_AVAILABLE_IN_2_58
char * g_ref_string_new_len (const char *str,
gssize len);
GLIB_AVAILABLE_IN_2_58
char * g_ref_string_new_intern (const char *str);
GLIB_AVAILABLE_IN_2_58
......
......@@ -36,6 +36,42 @@ test_refstring_base (void)
g_ref_string_release (s);
}
/* test_refstring_length: Test the _len variant */
static void
test_refstring_length (void)
{
char buf[] = {'h', 'e', 'l', 'l', 'o'}; /* no NUL */
char *s = g_ref_string_new_len (buf, 5);
g_assert_cmpstr (s, ==, "hello");
g_assert_cmpint (strlen (s), ==, strlen ("hello"));
g_assert_cmpuint (g_ref_string_length (s), ==, strlen ("hello"));
g_ref_string_release (s);
}
/* test_refstring_length: Test the _len variant with no size set */
static void
test_refstring_length_auto (void)
{
char *s = g_ref_string_new_len ("hello", -1);
g_assert_cmpstr (s, ==, "hello");
g_assert_cmpuint (g_ref_string_length (s), ==, strlen ("hello"));
g_ref_string_release (s);
}
/* test_refstring_length_nuls: Test the _len variant */
static void
test_refstring_length_nuls (void)
{
char buf[] = {'h', 'e', '\0', 'l', 'o'}; /* no NUL */
char *s = g_ref_string_new_len (buf, 5);
g_assert_cmpstr (s, ==, "he");
g_assert_cmpint (memcmp (s, "he\0lo", 5), ==, 0);
g_assert_cmpuint (g_ref_string_length (s), ==, 5);
g_ref_string_release (s);
}
/* test_refstring_intern: Test the interning API of GRefString */
static void
test_refstring_intern (void)
......@@ -76,6 +112,9 @@ main (int argc,
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/refstring/base", test_refstring_base);
g_test_add_func ("/refstring/length", test_refstring_length);
g_test_add_func ("/refstring/length-auto", test_refstring_length_auto);
g_test_add_func ("/refstring/length-nuls", test_refstring_length_nuls);
g_test_add_func ("/refstring/intern", test_refstring_intern);
return g_test_run ();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment