diff --git a/docs/reference/glib/glib-sections.txt.in b/docs/reference/glib/glib-sections.txt.in index 2b500257c..10d5029ff 100644 --- a/docs/reference/glib/glib-sections.txt.in +++ b/docs/reference/glib/glib-sections.txt.in @@ -1464,6 +1464,7 @@ utimbuf String Utility Functions string_utils glib.h,glib/gprintf.h +g_set_str g_strdup g_strndup g_strdupv diff --git a/glib/gstrfuncs.h b/glib/gstrfuncs.h index 37d2728d8..3c1dc45ec 100644 --- a/glib/gstrfuncs.h +++ b/glib/gstrfuncs.h @@ -32,9 +32,11 @@ #endif #include +#include #include #include #include +#include G_BEGIN_DECLS @@ -363,6 +365,51 @@ gboolean g_ascii_string_to_unsigned (const gchar *str, guint64 *out_num, GError **error); +/** + * g_set_str: (skip) + * @str_pointer: (inout) (not optional) (nullable): a pointer to either a string or %NULL + * @new_str: (nullable): a string to assign to @str_pointer, or %NULL + * + * Updates a pointer to a string to a copy of @new_str. The previous string + * pointed to by @str_pointer will be freed with g_free(). + * + * @str_pointer must not be %NULL, but can point to a %NULL value. + * + * One convenient usage of this function is in implementing property settings: + * |[ + * void + * foo_set_bar (Foo *foo, + * const char *new_bar) + * { + * g_return_if_fail (IS_FOO (foo)); + * + * if (g_set_str (&foo->bar, new_bar)) + * g_object_notify (foo, "bar"); + * } + * ]| + * + * Returns: %TRUE if the value of @str_pointer changed, %FALSE otherwise + * + * Since: 2.76 + */ +GLIB_AVAILABLE_STATIC_INLINE_IN_2_76 +static inline gboolean +g_set_str (char **str_pointer, + const char *new_str) +{ + char *copy; + + if (*str_pointer == new_str || + (*str_pointer && new_str && strcmp (*str_pointer, new_str) == 0)) + return FALSE; + + copy = g_strdup (new_str); + g_free (*str_pointer); + *str_pointer = copy; + + return TRUE; +} + G_END_DECLS #endif /* __G_STRFUNCS_H__ */ diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c index 082eec074..0ae3f89c1 100644 --- a/glib/tests/strfuncs.c +++ b/glib/tests/strfuncs.c @@ -2546,6 +2546,33 @@ test_ascii_string_to_number_pathological (void) g_assert_cmpint (svalue, ==, G_MININT64); } +static void +test_set_str (void) +{ + char *str = NULL; + + g_assert_false (g_set_str (&str, NULL)); + g_assert_null (str); + + g_assert_true (g_set_str (&str, "")); + g_assert_false (g_set_str (&str, "")); + g_assert_nonnull (str); + g_assert_true ((gpointer)str != (gpointer)""); + g_assert_cmpstr (str, ==, ""); + + g_assert_true (g_set_str (&str, NULL)); + g_assert_null (str); + + g_assert_true (g_set_str (&str, "")); + g_assert_true (g_set_str (&str, "test")); + g_assert_cmpstr (str, ==, "test"); + + g_assert_true (g_set_str (&str, &str[2])); + g_assert_cmpstr (str, ==, "st"); + + g_free (str); +} + int main (int argc, char *argv[]) @@ -2563,6 +2590,7 @@ main (int argc, g_test_add_func ("/strfuncs/has-suffix", test_has_suffix); g_test_add_func ("/strfuncs/memdup", test_memdup); g_test_add_func ("/strfuncs/memdup2", test_memdup2); + g_test_add_func ("/strfuncs/set_str", test_set_str); g_test_add_func ("/strfuncs/stpcpy", test_stpcpy); g_test_add_func ("/strfuncs/str_match_string", test_str_match_string); g_test_add_func ("/strfuncs/str_tokenize_and_fold", test_str_tokenize_and_fold);