[libgdata] [core] Add comparison functions for main Atom and GData structs



commit 371fceb5a6913e4d4eac69f5e850a76ab4847288
Author: Philip Withnall <philip tecnocode co uk>
Date:   Mon Jun 1 18:06:58 2009 +0100

    [core] Add comparison functions for main Atom and GData structs
    
    Consequently, add code to *_add_* functions to prevent duplicate structs being
    added to entries.
---
 docs/reference/gdata-sections.txt                |   15 +
 gdata/gdata-atom.c                               |  108 +++++++
 gdata/gdata-atom.h                               |    4 +
 gdata/gdata-entry.c                              |   30 ++-
 gdata/gdata-gdata.c                              |  331 ++++++++++++++++++++++
 gdata/gdata-gdata.h                              |   11 +
 gdata/gdata.symbols                              |   15 +
 gdata/services/calendar/gdata-calendar-event.c   |   21 ++-
 gdata/services/contacts/gdata-contacts-contact.c |   35 ++-
 9 files changed, 556 insertions(+), 14 deletions(-)

diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index cb3f591..79fac71 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -165,15 +165,19 @@ GDataEntryPrivate
 <TITLE>Atom API</TITLE>
 GDataAuthor
 gdata_author_new
+gdata_author_compare
 gdata_author_free
 GDataCategory
 gdata_category_new
+gdata_category_compare
 gdata_category_free
 GDataLink
 gdata_link_new
+gdata_link_compare
 gdata_link_free
 GDataGenerator
 gdata_generator_new
+gdata_generator_compare
 gdata_generator_free
 </SECTION>
 
@@ -182,36 +186,47 @@ gdata_generator_free
 <TITLE>GData API</TITLE>
 GDataGDEmailAddress
 gdata_gd_email_address_new
+gdata_gd_email_address_compare
 gdata_gd_email_address_free
 GDataGDFeedLink
 gdata_gd_feed_link_new
+gdata_gd_feed_link_compare
 gdata_gd_feed_link_free
 GDataGDIMAddress
 gdata_gd_im_address_new
+gdata_gd_im_address_compare
 gdata_gd_im_address_free
 GDataGDOrganization
 gdata_gd_organization_new
+gdata_gd_organization_compare
 gdata_gd_organization_free
 GDataGDPhoneNumber
 gdata_gd_phone_number_new
+gdata_gd_phone_number_compare
 gdata_gd_phone_number_free
 GDataGDPostalAddress
 gdata_gd_postal_address_new
+gdata_gd_postal_address_compare
 gdata_gd_postal_address_free
 GDataGDRating
 gdata_gd_rating_new
+gdata_gd_rating_compare
 gdata_gd_rating_free
 GDataGDWhen
 gdata_gd_when_new
+gdata_gd_when_compare
 gdata_gd_when_free
 GDataGDReminder
 gdata_gd_reminder_new
+gdata_gd_reminder_compare
 gdata_gd_reminder_free
 GDataGDWhere
 gdata_gd_where_new
+gdata_gd_where_compare
 gdata_gd_where_free
 GDataGDWho
 gdata_gd_who_new
+gdata_gd_who_compare
 gdata_gd_who_free
 </SECTION>
 
diff --git a/gdata/gdata-atom.c b/gdata/gdata-atom.c
index 8d4d622..b58e4ac 100644
--- a/gdata/gdata-atom.c
+++ b/gdata/gdata-atom.c
@@ -58,6 +58,33 @@ gdata_category_new (const gchar *term, const gchar *scheme, const gchar *label)
 }
 
 /**
+ * gdata_category_compare:
+ * @a: a #GDataCategory, or %NULL
+ * @b: another #GDataCategory, or %NULL
+ *
+ * Compares the two categories in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @term field of the #GDataCategory<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_category_compare (const GDataCategory *a, const GDataCategory *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->term, b->term);
+}
+
+/**
  * gdata_category_free
  * @self: a #GDataCategory
  *
@@ -111,6 +138,33 @@ gdata_link_new (const gchar *href, const gchar *rel, const gchar *type, const gc
 }
 
 /**
+ * gdata_link_compare:
+ * @a: a #GDataLink, or %NULL
+ * @b: another #GDataLink, or %NULL
+ *
+ * Compares the two links in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @href field of the #GDataLink<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_link_compare (const GDataLink *a, const GDataLink *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->href, b->href);
+}
+
+/**
  * gdata_link_free
  * @self: a #GDataLink
  *
@@ -158,6 +212,33 @@ gdata_author_new (const gchar *name, const gchar *uri, const gchar *email)
 }
 
 /**
+ * gdata_author_compare:
+ * @a: a #GDataAuthor, or %NULL
+ * @b: another #GDataAuthor, or %NULL
+ *
+ * Compares the two authors in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @name field of the #GDataAuthor<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_author_compare (const GDataAuthor *a, const GDataAuthor *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->name, b->name);
+}
+
+/**
  * gdata_author_free
  * @self: a #GDataAuthor
  *
@@ -203,6 +284,33 @@ gdata_generator_new (const gchar *name, const gchar *uri, const gchar *version)
 }
 
 /**
+ * gdata_generator_compare:
+ * @a: a #GDataGenerator, or %NULL
+ * @b: another #GDataGenerator, or %NULL
+ *
+ * Compares the two generators in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @name field of the #GDataGenerator<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_generator_compare (const GDataGenerator *a, const GDataGenerator *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->name, b->name);
+}
+
+/**
  * gdata_generator_free
  * @self: a #GDataGenerator
  *
diff --git a/gdata/gdata-atom.h b/gdata/gdata-atom.h
index 5c8baea..0b68014 100644
--- a/gdata/gdata-atom.h
+++ b/gdata/gdata-atom.h
@@ -42,6 +42,7 @@ typedef struct {
 } GDataCategory;
 
 GDataCategory *gdata_category_new (const gchar *term, const gchar *scheme, const gchar *label) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_category_compare (const GDataCategory *a, const GDataCategory *b);
 void gdata_category_free (GDataCategory *self);
 
 /**
@@ -69,6 +70,7 @@ typedef struct {
 
 GDataLink *gdata_link_new (const gchar *href, const gchar *rel, const gchar *type, const gchar *hreflang,
 			   const gchar *title, gint length) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_link_compare (const GDataLink *a, const GDataLink *b);
 void gdata_link_free (GDataLink *self);
 
 /**
@@ -89,6 +91,7 @@ typedef struct {
 } GDataAuthor;
 
 GDataAuthor *gdata_author_new (const gchar *name, const gchar *uri, const gchar *email) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_author_compare (const GDataAuthor *a, const GDataAuthor *b);
 void gdata_author_free (GDataAuthor *self);
 
 /**
@@ -109,6 +112,7 @@ typedef struct {
 } GDataGenerator;
 
 GDataGenerator *gdata_generator_new (const gchar *name, const gchar *uri, const gchar *version) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_generator_compare (const GDataGenerator *a, const GDataGenerator *b);
 void gdata_generator_free (GDataGenerator *self);
 
 G_END_DECLS
diff --git a/gdata/gdata-entry.c b/gdata/gdata-entry.c
index c46f8f0..5b14a34 100644
--- a/gdata/gdata-entry.c
+++ b/gdata/gdata-entry.c
@@ -635,7 +635,10 @@ gdata_entry_get_published (GDataEntry *self, GTimeVal *published)
  * @self: a #GDataEntry
  * @category: a #GDataCategory to add
  *
- * Adds @category to the list of categories in the given #GDataEntry.
+ * Adds @category to the list of categories in the given #GDataEntry. The #GDataEntry takes
+ * ownership of @category, so it must not be freed after being added.
+ *
+ * Duplicate categories will not be added to the list.
  **/
 void
 gdata_entry_add_category (GDataEntry *self, GDataCategory *category)
@@ -643,7 +646,10 @@ gdata_entry_add_category (GDataEntry *self, GDataCategory *category)
 	g_return_if_fail (GDATA_IS_ENTRY (self));
 	g_return_if_fail (category != NULL);
 
-	self->priv->categories = g_list_prepend (self->priv->categories, category);
+	if (g_list_find_custom (self->priv->categories, category, (GCompareFunc) gdata_category_compare) == NULL)
+		self->priv->categories = g_list_prepend (self->priv->categories, category);
+	else
+		gdata_category_free (category);
 }
 
 /**
@@ -700,7 +706,10 @@ gdata_entry_set_content (GDataEntry *self, const gchar *content)
  * @self: a #GDataEntry
  * @link: a #GDataLink to add
  *
- * Adds @link to the list of links in the given #GDataEntry.
+ * Adds @link to the list of links in the given #GDataEntry. The #GDataEntry takes
+ * ownership of @link, so it must not be freed after being added.
+ *
+ * Duplicate links will not be added to the list.
  **/
 void
 gdata_entry_add_link (GDataEntry *self, GDataLink *link)
@@ -709,7 +718,10 @@ gdata_entry_add_link (GDataEntry *self, GDataLink *link)
 	g_return_if_fail (GDATA_IS_ENTRY (self));
 	g_return_if_fail (link != NULL);
 
-	self->priv->links = g_list_prepend (self->priv->links, link);
+	if (g_list_find_custom (self->priv->links, link, (GCompareFunc) gdata_link_compare) == NULL)
+		self->priv->links = g_list_prepend (self->priv->links, link);
+	else
+		gdata_link_free (link);
 }
 
 static gint
@@ -748,7 +760,10 @@ gdata_entry_look_up_link (GDataEntry *self, const gchar *rel)
  * @self: a #GDataEntry
  * @author: a #GDataAuthor to add
  *
- * Adds @author to the list of authors in the given #GDataEntry.
+ * Adds @author to the list of authors in the given #GDataEntry. The #GDataEntry takes
+ * ownership of @author, so it must not be freed after being added.
+ *
+ * Duplicate authors will not be added to the list.
  **/
 void
 gdata_entry_add_author (GDataEntry *self, GDataAuthor *author)
@@ -757,7 +772,10 @@ gdata_entry_add_author (GDataEntry *self, GDataAuthor *author)
 	g_return_if_fail (GDATA_IS_ENTRY (self));
 	g_return_if_fail (author != NULL);
 
-	self->priv->authors = g_list_prepend (self->priv->authors, author);
+	if (g_list_find_custom (self->priv->authors, author, (GCompareFunc) gdata_author_compare) == NULL)
+		self->priv->authors = g_list_prepend (self->priv->authors, author);
+	else
+		gdata_author_free (author);
 }
 
 /**
diff --git a/gdata/gdata-gdata.c b/gdata/gdata-gdata.c
index 343e313..9571735 100644
--- a/gdata/gdata-gdata.c
+++ b/gdata/gdata-gdata.c
@@ -57,6 +57,35 @@ gdata_gd_rating_new (guint min, guint max, guint num_raters, gdouble average)
 }
 
 /**
+ * gdata_gd_rating_compare:
+ * @a: a #GDataGDRating, or %NULL
+ * @b: another #GDataGDRating, or %NULL
+ *
+ * Compares the two ratings in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @average and @num_raters fields of the #GDataGDRating<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_rating_compare (const GDataGDRating *a, const GDataGDRating *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	if (a->num_raters == b->num_raters)
+		return CLAMP (b->average - a->average, -1, 1);
+	return CLAMP ((gint) (b->num_raters - a->num_raters), -1, (gint) 1);
+}
+
+/**
  * gdata_gd_rating_free:
  * @self: a #GDataGDRating
  *
@@ -101,6 +130,33 @@ gdata_gd_feed_link_new (const gchar *href, const gchar *rel, guint count_hint, g
 }
 
 /**
+ * gdata_gd_feed_link_compare:
+ * @a: a #GDataGDFeedLink, or %NULL
+ * @b: another #GDataGDFeedLink, or %NULL
+ *
+ * Compares the two feed links in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @href field of the #GDataGDFeedLink<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_feed_link_compare (const GDataGDFeedLink *a, const GDataGDFeedLink *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->href, b->href);
+}
+
+/**
  * gdata_gd_feed_link_free:
  * @self: a #GDataGDFeedLink
  *
@@ -160,6 +216,38 @@ gdata_gd_when_new (GTimeVal *start_time, GTimeVal *end_time, gboolean is_date, c
 }
 
 /**
+ * gdata_gd_when_compare:
+ * @a: a #GDataGDWhen, or %NULL
+ * @b: another #GDataGDWhen, or %NULL
+ *
+ * Compares the two times in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @start_time, @end_time and @is_date fields of the #GDataGDWhen<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_when_compare (const GDataGDWhen *a, const GDataGDWhen *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	if (a->is_date != b->is_date)
+		return CLAMP (b->is_date - a->is_date, -1, 1);
+
+	if (a->start_time.tv_sec == b->start_time.tv_sec && a->start_time.tv_usec == b->start_time.tv_usec)
+		return CLAMP ((b->end_time.tv_sec * 1000 + b->end_time.tv_usec) - (a->end_time.tv_sec * 1000 + a->end_time.tv_usec), -1, 1);
+	return CLAMP ((b->start_time.tv_sec * 1000 + b->start_time.tv_usec) - (a->start_time.tv_sec * 1000 + a->start_time.tv_usec), -1, 1);
+}
+
+/**
  * gdata_gd_when_free:
  * @self: a #GDataGDWhen
  *
@@ -203,6 +291,39 @@ gdata_gd_who_new (const gchar *rel, const gchar *value_string, const gchar *emai
 }
 
 /**
+ * gdata_gd_who_compare:
+ * @a: a #GDataGDWho, or %NULL
+ * @b: another #GDataGDWho, or %NULL
+ *
+ * Compares the two people in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @email and @value_string fields of the #GDataGDWho<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_who_compare (const GDataGDWho *a, const GDataGDWho *b)
+{
+	gint value_string_cmp;
+
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+
+	value_string_cmp = g_strcmp0 (a->value_string, b->value_string);
+	if (value_string_cmp == 0 && g_strcmp0 (a->email, b->email))
+		return 0;
+	return value_string_cmp;
+}
+
+/**
  * gdata_gd_who_free:
  * @self: a #GDataGDWho
  *
@@ -244,6 +365,39 @@ gdata_gd_where_new (const gchar *rel, const gchar *value_string, const gchar *la
 }
 
 /**
+ * gdata_gd_where_compare:
+ * @a: a #GDataGDWhere, or %NULL
+ * @b: another #GDataGDWhere, or %NULL
+ *
+ * Compares the two places in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @label and @value_string fields of the #GDataGDWhere<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_where_compare (const GDataGDWhere *a, const GDataGDWhere *b)
+{
+	gint value_string_cmp;
+
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+
+	value_string_cmp = g_strcmp0 (a->value_string, b->value_string);
+	if (value_string_cmp == 0 && g_strcmp0 (a->label, b->label))
+		return 0;
+	return value_string_cmp;
+}
+
+/**
  * gdata_gd_where_free:
  * @self: a #GDataGDWhere
  *
@@ -291,6 +445,33 @@ gdata_gd_email_address_new (const gchar *address, const gchar *rel, const gchar
 }
 
 /**
+ * gdata_gd_email_address_compare:
+ * @a: a #GDataGDEmailAddress, or %NULL
+ * @b: another #GDataGDEmailAddress, or %NULL
+ *
+ * Compares the two e-mail addresses in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @address field of the #GDataGDEmailAddress<!-- -->es.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_email_address_compare (const GDataGDEmailAddress *a, const GDataGDEmailAddress *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->address, b->address);
+}
+
+/**
  * gdata_gd_email_address_free:
  * @self: a #GDataGDEmailAddress
  *
@@ -342,6 +523,39 @@ gdata_gd_im_address_new (const gchar *address, const gchar *protocol, const gcha
 }
 
 /**
+ * gdata_gd_im_address_compare:
+ * @a: a #GDataGDIMAddress, or %NULL
+ * @b: another #GDataGDIMAddress, or %NULL
+ *
+ * Compares the two IM addresses in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @address and @protocol fields of the #GDataGDIMAddress<!-- -->es.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_im_address_compare (const GDataGDIMAddress *a, const GDataGDIMAddress *b)
+{
+	gint address_cmp;
+
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+
+	address_cmp = g_strcmp0 (a->address, b->address);
+	if (address_cmp == 0 && g_strcmp0 (a->protocol, b->protocol) == 0)
+		return 0;
+	return address_cmp;
+}
+
+/**
  * gdata_gd_im_address_free:
  * @self: a #GDataGDIMAddress
  *
@@ -395,6 +609,33 @@ gdata_gd_phone_number_new (const gchar *number, const gchar *rel, const gchar *l
 }
 
 /**
+ * gdata_gd_phone_number_compare:
+ * @a: a #GDataGDPhoneNumber, or %NULL
+ * @b: another #GDataGDPhoneNumber, or %NULL
+ *
+ * Compares the two phone numbers in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @number field of the #GDataGDPhoneNumber<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_phone_number_compare (const GDataGDPhoneNumber *a, const GDataGDPhoneNumber *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->number, b->number);
+}
+
+/**
  * gdata_gd_phone_number_free:
  * @self: a #GDataGDPhoneNumber
  *
@@ -445,6 +686,33 @@ gdata_gd_postal_address_new (const gchar *address, const gchar *rel, const gchar
 }
 
 /**
+ * gdata_gd_postal_address_compare:
+ * @a: a #GDataGDPostalAddress, or %NULL
+ * @b: another #GDataGDPostalAddress, or %NULL
+ *
+ * Compares the two postal addresses in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @address field of the #GDataGDPostalAddress<!-- -->es.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_postal_address_compare (const GDataGDPostalAddress *a, const GDataGDPostalAddress *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->address, b->address);
+}
+
+/**
  * gdata_gd_postal_address_free:
  * @self: a #GDataGDPostalAddress
  *
@@ -492,6 +760,33 @@ gdata_gd_organization_new (const gchar *name, const gchar *title, const gchar *r
 }
 
 /**
+ * gdata_gd_organization_compare:
+ * @a: a #GDataGDOrganization, or %NULL
+ * @b: another #GDataGDOrganization, or %NULL
+ *
+ * Compares the two organizations in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis of the @name field of the #GDataGDOrganization<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_organization_compare (const GDataGDOrganization *a, const GDataGDOrganization *b)
+{
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+	return g_strcmp0 (a->name, b->name);
+}
+
+/**
  * gdata_gd_organization_free:
  * @self: a #GDataGDOrganization
  *
@@ -555,6 +850,42 @@ gdata_gd_reminder_new (const gchar *method, GTimeVal *absolute_time, gint days,
 }
 
 /**
+ * gdata_gd_reminder_compare:
+ * @a: a #GDataGDReminder, or %NULL
+ * @b: another #GDataGDReminder, or %NULL
+ *
+ * Compares the two reminders in a strcmp() fashion. %NULL values are handled gracefully, with
+ * %0 returned if both @a and @b are %NULL, %-1 if @a is %NULL and %1 if @b is %NULL.
+ *
+ * The comparison of non-%NULL values is done on the basis all the fields of the #GDataGDReminder<!-- -->s.
+ *
+ * Return value: %0 if @a equals @b, %-1 or %1 as appropriate otherwise
+ *
+ * Since: 0.4.0
+ **/
+gint
+gdata_gd_reminder_compare (const GDataGDReminder *a, const GDataGDReminder *b)
+{
+	gint method_cmp;
+
+	if (a == NULL && b != NULL)
+		return -1;
+	else if (b == NULL)
+		return 1;
+
+	if (a == b)
+		return 0;
+
+	method_cmp = g_strcmp0 (a->method, b->method);
+	if (method_cmp == 0 &&
+	    a->days == b->days &&
+	    a->hours == b->hours &&
+	    a->minutes == b->minutes)
+		return 0;
+	return method_cmp;
+}
+
+/**
  * gdata_gd_reminder_free:
  * @self: a #GDataGDReminder
  *
diff --git a/gdata/gdata-gdata.h b/gdata/gdata-gdata.h
index f6bbd77..28dbc1f 100644
--- a/gdata/gdata-gdata.h
+++ b/gdata/gdata-gdata.h
@@ -46,6 +46,7 @@ typedef struct {
 } GDataGDRating;
 
 GDataGDRating *gdata_gd_rating_new (guint min, guint max, guint num_raters, gdouble average) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_rating_compare (const GDataGDRating *a, const GDataGDRating *b);
 void gdata_gd_rating_free (GDataGDRating *self);
 
 /**
@@ -70,6 +71,7 @@ typedef struct {
 } GDataGDFeedLink;
 
 GDataGDFeedLink *gdata_gd_feed_link_new (const gchar *href, const gchar *rel, guint count_hint, gboolean read_only) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_feed_link_compare (const GDataGDFeedLink *a, const GDataGDFeedLink *b);
 void gdata_gd_feed_link_free (GDataGDFeedLink *self);
 
 /**
@@ -97,6 +99,7 @@ typedef struct {
 } GDataGDWhen;
 
 GDataGDWhen *gdata_gd_when_new (GTimeVal *start_time, GTimeVal *end_time, gboolean is_date, const gchar *value_string, GList *reminders);
+gint gdata_gd_when_compare (const GDataGDWhen *a, const GDataGDWhen *b);
 void gdata_gd_when_free (GDataGDWhen *self);
 
 /**
@@ -120,6 +123,7 @@ typedef struct {
 } GDataGDWho;
 
 GDataGDWho *gdata_gd_who_new (const gchar *rel, const gchar *value_string, const gchar *email) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_who_compare (const GDataGDWho *a, const GDataGDWho *b);
 void gdata_gd_who_free (GDataGDWho *self);
 
 /**
@@ -143,6 +147,7 @@ typedef struct {
 } GDataGDWhere;
 
 GDataGDWhere *gdata_gd_where_new (const gchar *rel, const gchar *value_string, const gchar *label) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_where_compare (const GDataGDWhere *a, const GDataGDWhere *b);
 void gdata_gd_where_free (GDataGDWhere *self);
 
 /**
@@ -166,6 +171,7 @@ typedef struct {
 } GDataGDEmailAddress;
 
 GDataGDEmailAddress *gdata_gd_email_address_new (const gchar *address, const gchar *rel, const gchar *label, gboolean primary) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_email_address_compare (const GDataGDEmailAddress *a, const GDataGDEmailAddress *b);
 void gdata_gd_email_address_free (GDataGDEmailAddress *self);
 
 /**
@@ -191,6 +197,7 @@ typedef struct {
 
 GDataGDIMAddress *gdata_gd_im_address_new (const gchar *address, const gchar *protocol, const gchar *rel,
 					   const gchar *label, gboolean primary) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_im_address_compare (const GDataGDIMAddress *a, const GDataGDIMAddress *b);
 void gdata_gd_im_address_free (GDataGDIMAddress *self);
 
 /**
@@ -218,6 +225,7 @@ typedef struct {
 
 GDataGDPhoneNumber *gdata_gd_phone_number_new (const gchar *number, const gchar *rel, const gchar *label,
 					       const gchar *uri, gboolean primary) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_phone_number_compare (const GDataGDPhoneNumber *a, const GDataGDPhoneNumber *b);
 void gdata_gd_phone_number_free (GDataGDPhoneNumber *self);
 
 /**
@@ -242,6 +250,7 @@ typedef struct {
 
 GDataGDPostalAddress *gdata_gd_postal_address_new (const gchar *address, const gchar *rel, const gchar *label,
 						   gboolean primary) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_postal_address_compare (const GDataGDPostalAddress *a, const GDataGDPostalAddress *b);
 void gdata_gd_postal_address_free (GDataGDPostalAddress *self);
 
 /**
@@ -267,6 +276,7 @@ typedef struct {
 
 GDataGDOrganization *gdata_gd_organization_new (const gchar *name, const gchar *title, const gchar *rel,
 						const gchar *label, gboolean primary) G_GNUC_WARN_UNUSED_RESULT;
+gint gdata_gd_organization_compare (const GDataGDOrganization *a, const GDataGDOrganization *b);
 void gdata_gd_organization_free (GDataGDOrganization *self);
 
 /**
@@ -292,6 +302,7 @@ typedef struct {
 } GDataGDReminder;
 
 GDataGDReminder *gdata_gd_reminder_new (const gchar *method, GTimeVal *absolute_time, gint days, gint hours, gint minutes);
+gint gdata_gd_reminder_compare (const GDataGDReminder *a, const GDataGDReminder *b);
 void gdata_gd_reminder_free (GDataGDReminder *self);
 
 G_END_DECLS
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index e9290e0..404af68 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -94,12 +94,16 @@ gdata_query_set_etag
 gdata_g_time_val_get_type
 gdata_soup_uri_get_type
 gdata_category_new
+gdata_category_compare
 gdata_category_free
 gdata_link_new
+gdata_link_compare
 gdata_link_free
 gdata_author_new
+gdata_author_compare
 gdata_author_free
 gdata_generator_new
+gdata_generator_compare
 gdata_generator_free
 gdata_media_rating_new
 gdata_media_rating_free
@@ -269,26 +273,37 @@ gdata_calendar_service_insert_event
 gdata_service_error_get_type
 gdata_authentication_error_get_type
 gdata_gd_rating_new
+gdata_gd_rating_compare
 gdata_gd_rating_free
 gdata_gd_feed_link_new
+gdata_gd_feed_link_compare
 gdata_gd_feed_link_free
 gdata_gd_when_new
+gdata_gd_when_compare
 gdata_gd_when_free
 gdata_gd_who_new
+gdata_gd_who_compare
 gdata_gd_who_free
 gdata_gd_where_new
+gdata_gd_where_compare
 gdata_gd_where_free
 gdata_gd_email_address_new
+gdata_gd_email_address_compare
 gdata_gd_email_address_free
 gdata_gd_im_address_new
+gdata_gd_im_address_compare
 gdata_gd_im_address_free
 gdata_gd_phone_number_new
+gdata_gd_phone_number_compare
 gdata_gd_phone_number_free
 gdata_gd_postal_address_new
+gdata_gd_postal_address_compare
 gdata_gd_postal_address_free
 gdata_gd_organization_new
+gdata_gd_organization_compare
 gdata_gd_organization_free
 gdata_gd_reminder_new
+gdata_gd_reminder_compare
 gdata_gd_reminder_free
 gdata_media_expression_get_type
 gdata_parser_error_get_type
diff --git a/gdata/services/calendar/gdata-calendar-event.c b/gdata/services/calendar/gdata-calendar-event.c
index eb61e69..c5e24c8 100644
--- a/gdata/services/calendar/gdata-calendar-event.c
+++ b/gdata/services/calendar/gdata-calendar-event.c
@@ -1104,6 +1104,8 @@ gdata_calendar_event_set_anyone_can_add_self (GDataCalendarEvent *self, gboolean
  *
  * Adds the person @who to the event as a guest (attendee, organiser, performer, etc.).
  * The #GDataCalendarEvent takes ownership of @who, so it must not be freed after being added.
+ *
+ * Duplicate people will not be added to the list.
  **/
 void
 gdata_calendar_event_add_person (GDataCalendarEvent *self, GDataGDWho *who)
@@ -1111,7 +1113,10 @@ gdata_calendar_event_add_person (GDataCalendarEvent *self, GDataGDWho *who)
 	g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
 	g_return_if_fail (who != NULL);
 
-	self->priv->people = g_list_append (self->priv->people, who);
+	if (g_list_find_custom (self->priv->people, who, (GCompareFunc) gdata_gd_who_compare) == NULL)
+		self->priv->people = g_list_append (self->priv->people, who);
+	else
+		gdata_gd_who_free (who);
 }
 
 /**
@@ -1138,6 +1143,8 @@ gdata_calendar_event_get_people (GDataCalendarEvent *self)
  *
  * Adds the place @where to the event as a location.
  * The #GDataCalendarEvent takes ownership of @where, so it must not be freed after being added.
+ *
+ * Duplicate places will not be added to the list.
  **/
 void
 gdata_calendar_event_add_place (GDataCalendarEvent *self, GDataGDWhere *where)
@@ -1145,7 +1152,10 @@ gdata_calendar_event_add_place (GDataCalendarEvent *self, GDataGDWhere *where)
 	g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
 	g_return_if_fail (where != NULL);
 
-	self->priv->places = g_list_append (self->priv->places, where);
+	if (g_list_find_custom (self->priv->places, where, (GCompareFunc) gdata_gd_where_compare) == NULL)
+		self->priv->places = g_list_append (self->priv->places, where);
+	else
+		gdata_gd_where_free (where);
 }
 
 /**
@@ -1173,6 +1183,8 @@ gdata_calendar_event_get_places (GDataCalendarEvent *self)
  * Adds @when to the event as a time period when the event happens.
  * The #GDataCalendarEvent takes ownership of @when, so it must not be freed after being added.
  *
+ * Duplicate times will not be added to the list.
+ *
  * Since: 0.2.0
  **/
 void
@@ -1181,7 +1193,10 @@ gdata_calendar_event_add_time (GDataCalendarEvent *self, GDataGDWhen *when)
 	g_return_if_fail (GDATA_IS_CALENDAR_EVENT (self));
 	g_return_if_fail (when != NULL);
 
-	self->priv->times = g_list_append (self->priv->times, when);
+	if (g_list_find_custom (self->priv->times, when, (GCompareFunc) gdata_gd_when_compare) == NULL)
+		self->priv->times = g_list_append (self->priv->times, when);
+	else
+		gdata_gd_when_free (when);
 }
 
 /**
diff --git a/gdata/services/contacts/gdata-contacts-contact.c b/gdata/services/contacts/gdata-contacts-contact.c
index bb4d194..8ac6762 100644
--- a/gdata/services/contacts/gdata-contacts-contact.c
+++ b/gdata/services/contacts/gdata-contacts-contact.c
@@ -683,6 +683,8 @@ gdata_contacts_contact_get_edited (GDataContactsContact *self, GTimeVal *edited)
  * (with gdata_contacts_service_insert_contact()) will return an error if more than one e-mail address
  * is marked as primary.
  *
+ * Duplicate e-mail addresses will not be added to the list.
+ *
  * Since: 0.2.0
  **/
 void
@@ -691,7 +693,10 @@ gdata_contacts_contact_add_email_address (GDataContactsContact *self, GDataGDEma
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (email_address != NULL);
 
-	self->priv->email_addresses = g_list_append (self->priv->email_addresses, email_address);
+	if (g_list_find_custom (self->priv->email_addresses, email_address, (GCompareFunc) gdata_gd_email_address_compare) == NULL)
+		self->priv->email_addresses = g_list_append (self->priv->email_addresses, email_address);
+	else
+		gdata_gd_email_address_free (email_address);
 }
 
 /**
@@ -748,6 +753,8 @@ gdata_contacts_contact_get_primary_email_address (GDataContactsContact *self)
  * (with gdata_contacts_service_insert_contact()) will return an error if more than one IM address
  * is marked as primary.
  *
+ * Duplicate IM addresses will not be added to the list.
+ *
  * Since: 0.2.0
  **/
 void
@@ -756,7 +763,10 @@ gdata_contacts_contact_add_im_address (GDataContactsContact *self, GDataGDIMAddr
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (im_address != NULL);
 
-	self->priv->im_addresses = g_list_append (self->priv->im_addresses, im_address);
+	if (g_list_find_custom (self->priv->im_addresses, im_address, (GCompareFunc) gdata_gd_im_address_compare) == NULL)
+		self->priv->im_addresses = g_list_append (self->priv->im_addresses, im_address);
+	else
+		gdata_gd_im_address_free (im_address);
 }
 
 /**
@@ -813,6 +823,8 @@ gdata_contacts_contact_get_primary_im_address (GDataContactsContact *self)
  * (with gdata_contacts_service_insert_contact()) will return an error if more than one phone number
  * is marked as primary.
  *
+ * Duplicate phone numbers will not be added to the list.
+ *
  * Since: 0.2.0
  **/
 void
@@ -821,7 +833,10 @@ gdata_contacts_contact_add_phone_number (GDataContactsContact *self, GDataGDPhon
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (phone_number != NULL);
 
-	self->priv->phone_numbers = g_list_append (self->priv->phone_numbers, phone_number);
+	if (g_list_find_custom (self->priv->phone_numbers, phone_number, (GCompareFunc) gdata_gd_phone_number_compare) == NULL)
+		self->priv->phone_numbers = g_list_append (self->priv->phone_numbers, phone_number);
+	else
+		gdata_gd_phone_number_free (phone_number);
 }
 
 /**
@@ -878,6 +893,8 @@ gdata_contacts_contact_get_primary_phone_number (GDataContactsContact *self)
  * (with gdata_contacts_service_insert_contact()) will return an error if more than one postal address
  * is marked as primary.
  *
+ * Duplicate postal addresses will not be added to the list.
+ *
  * Since: 0.2.0
  **/
 void
@@ -886,7 +903,10 @@ gdata_contacts_contact_add_postal_address (GDataContactsContact *self, GDataGDPo
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (postal_address != NULL);
 
-	self->priv->postal_addresses = g_list_append (self->priv->postal_addresses, postal_address);
+	if (g_list_find_custom (self->priv->postal_addresses, postal_address, (GCompareFunc) gdata_gd_postal_address_compare) == NULL)
+		self->priv->postal_addresses = g_list_append (self->priv->postal_addresses, postal_address);
+	else
+		gdata_gd_postal_address_free (postal_address);
 }
 
 /**
@@ -943,6 +963,8 @@ gdata_contacts_contact_get_primary_postal_address (GDataContactsContact *self)
  * (with gdata_contacts_service_insert_contact()) will return an error if more than one organization
  * is marked as primary.
  *
+ * Duplicate organizations will not be added to the list.
+ *
  * Since: 0.2.0
  **/
 void
@@ -951,7 +973,10 @@ gdata_contacts_contact_add_organization (GDataContactsContact *self, GDataGDOrga
 	g_return_if_fail (GDATA_IS_CONTACTS_CONTACT (self));
 	g_return_if_fail (organization != NULL);
 
-	self->priv->organizations = g_list_append (self->priv->organizations, organization);
+	if (g_list_find_custom (self->priv->organizations, organization, (GCompareFunc) gdata_gd_organization_compare) == NULL)
+		self->priv->organizations = g_list_append (self->priv->organizations, organization);
+	else
+		gdata_gd_organization_free (organization);
 }
 
 /**



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]