>From 4416a190ca584ad8809c92652f2c480ec193a02f Mon Sep 17 00:00:00 2001
From: Colomban Wendling <ban@herbesfolles.org>
Date: Thu, 16 Dec 2010 22:49:33 +0100
Subject: [PATCH 5/8] Make TMTag reference-counted

---
 tagmanager/include/tm_tag.h |   17 ++++++++++++++++-
 tagmanager/tm_project.c     |    6 +++---
 tagmanager/tm_source_file.c |    2 +-
 tagmanager/tm_tag.c         |   24 +++++++++++++++++++++---
 tagmanager/tm_workspace.c   |    2 +-
 5 files changed, 42 insertions(+), 9 deletions(-)

diff --git a/tagmanager/include/tm_tag.h b/tagmanager/include/tm_tag.h
index 00c15dc..33f4b32 100644
--- a/tagmanager/include/tm_tag.h
+++ b/tagmanager/include/tm_tag.h
@@ -147,6 +147,7 @@ typedef struct _TMTag
 			gboolean inactive; /*!< Whether this file is to be parsed */
 		} file;
 	} atts;
+	gint refcount; /*!< the reference count of the tag */
 } TMTag;
 
 /*!
@@ -306,13 +307,27 @@ void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all);
  \sa tm_tag_free()
 */
 void tm_tag_destroy(TMTag *tag);
-#endif
 
 /*!
  Destroys all data in the tag and frees the tag structure as well.
  \param tag Pointer to a TMTag structure
 */
 void tm_tag_free(gpointer tag);
+#endif
+
+/*!
+ Drops a reference from a TMTag. If the reference count reaches 0, this function
+ destroys all data in the tag and frees the tag structure as well.
+ \param tag Pointer to a TMTag structure
+*/
+void tm_tag_unref(TMTag *tag);
+
+/*!
+ Adds a reference to a TMTag.
+ \param tag Pointer to a TMTag structure
+ \return the passed-in TMTag
+*/
+TMTag *tm_tag_ref(TMTag *tag);
 
 /*!
  Returns the type of tag as a string
diff --git a/tagmanager/tm_project.c b/tagmanager/tm_project.c
index dc193b2..5800df8 100644
--- a/tagmanager/tm_project.c
+++ b/tagmanager/tm_project.c
@@ -396,7 +396,7 @@ gboolean tm_project_open(TMProject *project, gboolean force)
 #endif
 				if (!force)
 				{
-					tm_tag_free(tag);
+					tm_tag_unref(tag);
 					fclose(fp);
 					return FALSE;
 				}
@@ -412,7 +412,7 @@ gboolean tm_project_open(TMProject *project, gboolean force)
 					project->file_list = g_ptr_array_new();
 				g_ptr_array_add(project->file_list, source_file);
 			}
-			tm_tag_free(tag);
+			tm_tag_unref(tag);
 		}
 		else
 		{
@@ -421,7 +421,7 @@ gboolean tm_project_open(TMProject *project, gboolean force)
 #ifdef TM_DEBUG
 				g_warning("Dangling tag %s", tag->name);
 #endif
-				tm_tag_free(tag);
+				tm_tag_unref(tag);
 				if (!force)
 				{
 					fclose(fp);
diff --git a/tagmanager/tm_source_file.c b/tagmanager/tm_source_file.c
index e013368..ebd4b54 100644
--- a/tagmanager/tm_source_file.c
+++ b/tagmanager/tm_source_file.c
@@ -324,7 +324,7 @@ gboolean tm_source_file_write(TMWorkObject *source_file, FILE *fp, guint attrs)
 		if (NULL != (tag = tm_tag_new(TM_SOURCE_FILE(source_file), NULL)))
 		{
 			tm_tag_write(tag, fp, tm_tag_attr_max_t);
-			tm_tag_free(tag);
+			tm_tag_unref(tag);
 			if (NULL != source_file->tags_array)
 			{
 				for (i=0; i < source_file->tags_array->len; ++i)
diff --git a/tagmanager/tm_tag.c b/tagmanager/tm_tag.c
index 25249c0..1ab347a 100644
--- a/tagmanager/tm_tag.c
+++ b/tagmanager/tm_tag.c
@@ -129,6 +129,7 @@ static int get_tag_type(const char *tag_name)
 
 gboolean tm_tag_init(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag_entry)
 {
+	tag->refcount = 1;
 	if (NULL == tag_entry)
 	{
 		/* This is a file tag */
@@ -224,6 +225,7 @@ gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
 	gboolean status;
 	guchar changed_char = TA_NAME;
 
+	tag->refcount = 1;
 	if ((NULL == fgets((gchar*)buf, BUFSIZ, fp)) || ('\0' == *buf))
 		return FALSE;
 	for (start = end = buf, status = TRUE; (TRUE == status); start = end, ++ end)
@@ -327,6 +329,7 @@ gboolean tm_tag_init_from_file_alt(TMTag *tag, TMSourceFile *file, FILE *fp)
 	gboolean status;
 	/*guchar changed_char = TA_NAME;*/
 
+	tag->refcount = 1;
 	if ((NULL == fgets((gchar*)buf, BUFSIZ, fp)) || ('\0' == *buf))
 		return FALSE;
 	{
@@ -436,15 +439,30 @@ static void tm_tag_destroy(TMTag *tag)
 	}
 }
 
+#if 0
 void tm_tag_free(gpointer tag)
 {
-	if (NULL != tag)
+	tm_tag_unref(tag);
+}
+#endif
+
+void tm_tag_unref(TMTag *tag)
+{
+	/* be NULL-proof because tm_tag_free() was NULL-proof and we indent to be a
+	 * drop-in replacment of it */
+	if (NULL != tag && g_atomic_int_dec_and_test(&tag->refcount))
 	{
-		tm_tag_destroy((TMTag *) tag);
+		tm_tag_destroy(tag);
 		TAG_FREE(tag);
 	}
 }
 
+TMTag *tm_tag_ref(TMTag *tag)
+{
+	g_atomic_int_inc(&tag->refcount);
+	return tag;
+}
+
 int tm_tag_compare(const void *ptr1, const void *ptr2)
 {
 	unsigned int *sort_attr;
@@ -603,7 +621,7 @@ void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all)
 	{
 		guint i;
 		for (i = 0; i < tags_array->len; ++i)
-			tm_tag_free(tags_array->pdata[i]);
+			tm_tag_unref(tags_array->pdata[i]);
 		if (free_all)
 			g_ptr_array_free(tags_array, TRUE);
 		else
diff --git a/tagmanager/tm_workspace.c b/tagmanager/tm_workspace.c
index 6a1f849..8aba6a6 100644
--- a/tagmanager/tm_workspace.c
+++ b/tagmanager/tm_workspace.c
@@ -82,7 +82,7 @@ void tm_workspace_free(gpointer workspace)
 		if (theWorkspace->global_tags)
 		{
 			for (i=0; i < theWorkspace->global_tags->len; ++i)
-				tm_tag_free(theWorkspace->global_tags->pdata[i]);
+				tm_tag_unref(theWorkspace->global_tags->pdata[i]);
 			g_ptr_array_free(theWorkspace->global_tags, TRUE);
 		}
 		tm_work_object_destroy(TM_WORK_OBJECT(theWorkspace));
-- 
1.7.2.3

