diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 1717ba37d..4510c0ebb 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -3497,6 +3497,7 @@ g_arc_box_get_size refstring 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 diff --git a/glib/grefstring.c b/glib/grefstring.c index 91fe8b5f8..f3ed4df72 100644 --- a/glib/grefstring.c +++ b/glib/grefstring.c @@ -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 diff --git a/glib/grefstring.h b/glib/grefstring.h index 2afe23a73..65b391ffa 100644 --- a/glib/grefstring.h +++ b/glib/grefstring.h @@ -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 diff --git a/glib/tests/refstring.c b/glib/tests/refstring.c index a4d8f1a8d..41ab0c05c 100644 --- a/glib/tests/refstring.c +++ b/glib/tests/refstring.c @@ -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 ();