# HG changeset patch
# Node ID 826e2ee34645905dc1ddd1c4fc6066d7cd5505f2
# Parent  8826a3c84cfb94238fcbdccddf5da2040c2ae870
diff --git a/ibis/ibismessage.c b/ibis/ibismessage.c
--- a/ibis/ibismessage.c
+++ b/ibis/ibismessage.c
@@ -347,7 +347,9 @@
 		ibis_message_set_source(message, g_value_get_string(value));
 		break;
 	case PROP_TAGS:
+		G_GNUC_BEGIN_IGNORE_DEPRECATIONS
 		ibis_message_set_tags(message, g_value_get_object(value));
+		G_GNUC_END_IGNORE_DEPRECATIONS
 		break;
 	case PROP_ERROR:
 		ibis_message_set_error(message, g_value_get_boxed(value));
@@ -370,7 +372,8 @@
 }
 
 static void
-ibis_message_init(G_GNUC_UNUSED IbisMessage *message) {
+ibis_message_init(IbisMessage *message) {
+	message->tags = ibis_tags_new();
 }
 
 static void
@@ -706,7 +709,6 @@
 IbisMessage *
 ibis_message_parse(const char *buffer, GError **error) {
 	IbisMessage *message = NULL;
-	IbisTags *tags = NULL;
 	GError *local_error = NULL;
 	GMatchInfo *info = NULL;
 	GRegex *regex = NULL;
@@ -757,13 +759,15 @@
 
 	tags_string = g_match_info_fetch_named(info, "tags");
 	if(!ibis_str_is_empty(tags_string)) {
-		tags = ibis_tags_parse(tags_string, &local_error);
+		IbisTags *tags = ibis_message_get_tags(message);
+
+		ibis_tags_parse_string(tags, tags_string, &local_error);
 		if(local_error != NULL) {
 			g_propagate_error(error, local_error);
 
 			g_free(tags_string);
 			g_free(command);
-			g_clear_object(&tags);
+			g_clear_object(&message);
 			g_match_info_unref(info);
 			g_clear_pointer(&validated, g_free);
 
@@ -774,11 +778,6 @@
 	}
 	g_free(tags_string);
 
-	if(tags != NULL) {
-		ibis_message_set_tags(message, tags);
-		g_clear_object(&tags);
-	}
-
 	source = g_match_info_fetch_named(info, "source");
 	if(!ibis_str_is_empty(source)) {
 		ibis_message_set_source(message, source);
diff --git a/ibis/ibismessage.h b/ibis/ibismessage.h
--- a/ibis/ibismessage.h
+++ b/ibis/ibismessage.h
@@ -239,8 +239,10 @@
  * Sets the tags of @message to @tags.
  *
  * Since: 0.1
+ *
+ * Deprecated: 0.10: Use [method@Message.get_tags] and update that directly.
  */
-IBIS_AVAILABLE_IN_0_1
+IBIS_DEPRECATED
 void ibis_message_set_tags(IbisMessage *message, IbisTags *tags);
 
 /**
diff --git a/ibis/ibistags.c b/ibis/ibistags.c
--- a/ibis/ibistags.c
+++ b/ibis/ibistags.c
@@ -161,6 +161,14 @@
 	}
 }
 
+void
+ibis_tags_clear(IbisTags *tags) {
+	g_return_if_fail(IBIS_IS_TAGS(tags));
+
+	g_hash_table_remove_all(tags->tags);
+	g_queue_clear(tags->keys);
+}
+
 gboolean
 ibis_tags_contains(IbisTags *tags1, IbisTags *tags2) {
 	GHashTableIter iter;
@@ -245,22 +253,36 @@
 
 IbisTags *
 ibis_tags_parse(const char *tags_string, GError **error) {
+	IbisTags *tags = NULL;
+
+	g_return_val_if_fail(tags_string != NULL, NULL);
+
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, tags_string, error);
+
+	return tags;
+}
+
+void
+ibis_tags_parse_string(IbisTags *tags, const char *tags_string,
+                       GError **error)
+{
 	GError *local_error = NULL;
-	IbisTags *tags = NULL;
 	GMatchInfo *info = NULL;
 	GRegex *regex = NULL;
 	gboolean matches = FALSE;
 
-	g_return_val_if_fail(tags_string != NULL, NULL);
+	g_return_if_fail(IBIS_IS_TAGS(tags));
+	g_return_if_fail(tags_string != NULL);
 
-	tags = ibis_tags_new();
+	ibis_tags_clear(tags);
 
 	/* tags_string can never be NULL, because g_match_info_fetch_named always
 	 * returns a string. So if we were passed an empty string, just return the
 	 * empty hash table.
 	 */
 	if(*tags_string == '\0') {
-		return tags;
+		return;
 	}
 
 	regex = g_regex_new("(?<key>(?<client_prefix>\\+?)"
@@ -281,7 +303,7 @@
 
 		g_clear_pointer(&info, g_match_info_unref);
 
-		return tags;
+		return;
 	}
 
 	if(!matches) {
@@ -290,7 +312,7 @@
 
 		g_clear_pointer(&info, g_match_info_unref);
 
-		return tags;
+		return;
 	}
 
 	while(g_match_info_matches(info)) {
@@ -319,8 +341,6 @@
 	}
 
 	g_clear_pointer(&info, g_match_info_unref);
-
-	return tags;
 }
 
 gboolean
diff --git a/ibis/ibistags.h b/ibis/ibistags.h
--- a/ibis/ibistags.h
+++ b/ibis/ibistags.h
@@ -73,6 +73,17 @@
 void ibis_tags_add(IbisTags *tags, const char *key, const char *value);
 
 /**
+ * ibis_tags_clear:
+ * @tags: The instance.
+ *
+ * Removes all tags from @tags.
+ *
+ * Since: 0.10
+ */
+IBIS_AVAILABLE_IN_0_10
+void ibis_tags_clear(IbisTags *tags);
+
+/**
  * ibis_tags_contains:
  * @tags1: The first instance.
  * @tags2: The second instance.
@@ -166,10 +177,29 @@
  *
  * Since: 0.1
  */
-IBIS_AVAILABLE_IN_0_1
+IBIS_DEPRECATED_FOR(ibis_tags_parse_string)
 IbisTags *ibis_tags_parse(const char *tags_string, GError **error);
 
 /**
+ * ibis_tags_parse_string:
+ * @tags: The instance.
+ * @tags_string: The string to parse.
+ * @error: (nullable): A return address for a #GError.
+ *
+ * Parses @tags_string and updates @tags with the results.
+ *
+ * This calls [method@Tags.clear] before adding any new tags.
+ *
+ * If an error was encountered, %NULL will be returned and @error will be set.
+ *
+ * Returns: (transfer full): The new tags object or %NULL on error.
+ *
+ * Since: 0.10
+ */
+IBIS_AVAILABLE_IN_0_10
+void ibis_tags_parse_string(IbisTags *tags, const char *tags_string, GError **error);
+
+/**
  * ibis_tags_remove:
  * @tags: The instance.
  * @key: The key to remove.
diff --git a/ibis/tests/test_message.c b/ibis/tests/test_message.c
--- a/ibis/tests/test_message.c
+++ b/ibis/tests/test_message.c
@@ -369,10 +369,8 @@
 
 	message = ibis_message_new("command");
 
-	tags = ibis_tags_new();
+	tags = ibis_message_get_tags(message);
 	ibis_tags_add(tags, "foo", "bar");
-	ibis_message_set_tags(message, tags);
-	g_clear_object(&tags);
 
 	serialized = ibis_message_serialize_to_string(message, TRUE);
 	g_assert_cmpstr(serialized, ==, "@foo=bar COMMAND\r\n");
@@ -390,10 +388,8 @@
 
 	message = ibis_message_new("command");
 
-	tags = ibis_tags_new();
+	tags = ibis_message_get_tags(message);
 	ibis_tags_add(tags, "foo", "bar");
-	ibis_message_set_tags(message, tags);
-	g_clear_object(&tags);
 
 	serialized = ibis_message_serialize_to_string(message, FALSE);
 	g_assert_cmpstr(serialized, ==, "COMMAND\r\n");
@@ -806,11 +802,10 @@
 	IbisTags *tags = NULL;
 	char *serialized = NULL;
 
-	tags = ibis_tags_new();
+	message = ibis_message_new("foo");
+	tags = ibis_message_get_tags(message);
 	ibis_tags_add(tags, "asd", "");
 
-	message = ibis_message_new("foo");
-	ibis_message_set_tags(message, tags);
 	ibis_message_set_source(message, "coolguy");
 	ibis_message_set_params(message, "bar", "baz", "  ", NULL);
 
@@ -820,7 +815,6 @@
 
 	g_clear_pointer(&serialized, g_free);
 	g_assert_finalize_object(message);
-	g_assert_finalize_object(tags);
 }
 
 static void
@@ -829,11 +823,11 @@
 	IbisTags *tags = NULL;
 	char *serialized = NULL;
 
-	tags = ibis_tags_new();
+	message = ibis_message_new("foo");
+
+	tags = ibis_message_get_tags(message);
 	ibis_tags_add(tags, "asd", NULL);
 
-	message = ibis_message_new("foo");
-	ibis_message_set_tags(message, tags);
 	ibis_message_set_source(message, "coolguy");
 	ibis_message_set_params(message, "bar", "baz", "  ", NULL);
 
@@ -843,7 +837,6 @@
 
 	g_clear_pointer(&serialized, g_free);
 	g_assert_finalize_object(message);
-	g_assert_finalize_object(tags);
 }
 
 static void
@@ -852,20 +845,18 @@
 	IbisTags *tags = NULL;
 	char *serialized = NULL;
 
-	tags = ibis_tags_new();
+	message = ibis_message_new("foo");
+
+	tags = ibis_message_get_tags(message);
 	ibis_tags_add(tags, "a", "b\\and\nk");
 	ibis_tags_add(tags, "d", "gh;764");
 
-	message = ibis_message_new("foo");
-	ibis_message_set_tags(message, tags);
-
 	serialized = ibis_message_serialize_to_string(message, TRUE);
 
 	g_assert_cmpstr(serialized, ==, "@a=b\\\\and\\nk;d=gh\\:764 FOO\r\n");
 
 	g_clear_pointer(&serialized, g_free);
 	g_assert_finalize_object(message);
-	g_assert_finalize_object(tags);
 }
 
 static void
@@ -874,12 +865,12 @@
 	IbisTags *tags = NULL;
 	char *serialized = NULL;
 
-	tags = ibis_tags_new();
+	message = ibis_message_new("foo");
+
+	tags = ibis_message_get_tags(message);
 	ibis_tags_add(tags, "a", "b\\and\nk");
 	ibis_tags_add(tags, "d", "gh;764");
 
-	message = ibis_message_new("foo");
-	ibis_message_set_tags(message, tags);
 	ibis_message_set_params(message, "par1", "par2", NULL);
 
 	serialized = ibis_message_serialize_to_string(message, TRUE);
@@ -889,7 +880,6 @@
 
 	g_clear_pointer(&serialized, g_free);
 	g_assert_finalize_object(message);
-	g_assert_finalize_object(tags);
 }
 
 static void
@@ -898,11 +888,10 @@
 	IbisTags *tags = NULL;
 	char *serialized = NULL;
 
-	tags = ibis_tags_new();
-	ibis_tags_add(tags, "foo", "\\\\;\\s \r\n");
 
 	message = ibis_message_new("COMMAND");
-	ibis_message_set_tags(message, tags);
+	tags = ibis_message_get_tags(message);
+	ibis_tags_add(tags, "foo", "\\\\;\\s \r\n");
 
 	serialized = ibis_message_serialize_to_string(message, TRUE);
 
@@ -911,7 +900,6 @@
 
 	g_clear_pointer(&serialized, g_free);
 	g_assert_finalize_object(message);
-	g_assert_finalize_object(tags);
 }
 
 /******************************************************************************
diff --git a/ibis/tests/test_tags.c b/ibis/tests/test_tags.c
--- a/ibis/tests/test_tags.c
+++ b/ibis/tests/test_tags.c
@@ -216,7 +216,8 @@
 	IbisTags *tags = NULL;
 	GError *error = NULL;
 
-	tags = ibis_tags_parse("", &error);
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, "", &error);
 	g_assert_no_error(error);
 
 	g_assert_cmpuint(ibis_tags_get_size(tags), ==, 0);
@@ -230,7 +231,8 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo=bar", &error);
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, "@foo=bar", &error);
 	g_assert_no_error(error);
 
 	g_assert_cmpuint(ibis_tags_get_size(tags), ==, 1);
@@ -248,7 +250,8 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo", &error);
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, "@foo", &error);
 	g_assert_no_error(error);
 
 	g_assert_cmpuint(ibis_tags_get_size(tags), ==, 1);
@@ -266,7 +269,8 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo=", &error);
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, "@foo=", &error);
 	g_assert_no_error(error);
 
 	g_assert_cmpuint(ibis_tags_get_size(tags), ==, 1);
@@ -284,7 +288,8 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo=bar;baz;quux;corge;grault=garply;waldo",
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, "@foo=bar;baz;quux;corge;grault=garply;waldo",
 	                       &error);
 	g_assert_no_error(error);
 
@@ -323,7 +328,8 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo=\\:;bar=\\s;baz=\\\\;quux=\\r;qux=\\n",
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, "@foo=\\:;bar=\\s;baz=\\\\;quux=\\r;qux=\\n",
 	                       &error);
 	g_assert_no_error(error);
 
@@ -358,7 +364,9 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo=a\\:b\\:c;bar=one\\stwo\\sthree;"
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags,
+	                       "@foo=a\\:b\\:c;bar=one\\stwo\\sthree;"
 	                       "baz=c:\\\\Users;quux=hello\\sworld!\\r\\n",
 	                       &error);
 	g_assert_no_error(error);
@@ -390,7 +398,9 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo=seven\\seight\\snine;bar=one\\stwo\\sthree;"
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags,
+	                       "@foo=seven\\seight\\snine;bar=one\\stwo\\sthree;"
 	                       "foo=7,8,9;bar=1,2,3",
 	                       &error);
 	g_assert_no_error(error);
@@ -417,7 +427,8 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo=test\\", &error);
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, "@foo=test\\", &error);
 	g_assert_no_error(error);
 
 	g_assert_true(ibis_tags_exists(tags, "foo"));
@@ -434,7 +445,8 @@
 	GError *error = NULL;
 	const char *value = NULL;
 
-	tags = ibis_tags_parse("@foo=\\b", &error);
+	tags = ibis_tags_new();
+	ibis_tags_parse_string(tags, "@foo=\\b", &error);
 	g_assert_no_error(error);
 
 	g_assert_true(ibis_tags_exists(tags, "foo"));
