diff --git a/configure.ac b/configure.ac
index 2ceef4c..a169ec9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -146,6 +146,11 @@ AC_SUBST(GIO_LIBS)
 if test $have_gio = 1 ; then
     AC_DEFINE(HAVE_GIO, 1, [Whether GIO is available])
 fi
+# MIO checks
+mio_modules="mio >= 0.1"
+PKG_CHECK_MODULES(MIO, [$mio_modules])
+AC_SUBST(MIO_CFLAGS)
+AC_SUBST(MIO_LIBS)
 
 # --disable-deprecated switch for GTK2 purification
 AC_ARG_ENABLE(deprecated, [  --disable-deprecated    Disable deprecated GTK functions. ],
diff --git a/src/Makefile.am b/src/Makefile.am
index 6866ca7..632b604 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -85,7 +85,7 @@ if MINGW
 
 geany_SOURCES = $(SRCS) win32.c win32.h
 
-geany_LDADD = ../scintilla/libscintilla.a ../tagmanager/libtagmanager.a @GTK_LIBS@ @GIO_LIBS@ \
+geany_LDADD = ../scintilla/libscintilla.a ../tagmanager/libtagmanager.a @GTK_LIBS@ @GIO_LIBS@ @MIO_LIBS@ \
 				$(INTLLIBS) -lole32 -luuid -liberty -lwsock32 geany_private.res
 
 AM_CFLAGS = -DGEANY_DATADIR=\"data\" \
@@ -112,7 +112,7 @@ else
 
 geany_SOURCES = $(SRCS) vte.c vte.h
 
-geany_LDADD = ../scintilla/libscintilla.a ../tagmanager/libtagmanager.a @GTK_LIBS@ @GIO_LIBS@ $(INTLLIBS)
+geany_LDADD = ../scintilla/libscintilla.a ../tagmanager/libtagmanager.a @GTK_LIBS@ @GIO_LIBS@ @MIO_LIBS@ $(INTLLIBS)
 
 AM_CFLAGS = -DGEANY_DATADIR=\""$(datadir)"\" \
 			-DGEANY_DOCDIR=\""$(docdir)"\" \
diff --git a/src/document.c b/src/document.c
index 48da97b..084223b 100644
--- a/src/document.c
+++ b/src/document.c
@@ -2359,7 +2359,7 @@ gint document_replace_all(GeanyDocument *doc, const gchar *find_text, const gcha
 static gboolean update_tags_from_buffer(GeanyDocument *doc)
 {
 	gboolean result;
-#if 1
+#if 0
 		/* old code */
 		result = tm_source_file_update(doc->tm_file, TRUE, FALSE, TRUE);
 #else
diff --git a/src/editor.c b/src/editor.c
index 5b79ae4..4ededf3 100644
--- a/src/editor.c
+++ b/src/editor.c
@@ -988,6 +988,26 @@ void editor_sci_notify_cb(G_GNUC_UNUSED GtkWidget *widget, G_GNUC_UNUSED gint sc
 }
 
 
+static gboolean document_tags_update_pending = FALSE;
+
+static gboolean on_document_update_tags_idle(gpointer data)
+{
+	document_update_tag_list(data, TRUE);
+	document_tags_update_pending = FALSE;
+	return FALSE;
+}
+
+
+static void request_update_tag_list(GeanyDocument *doc)
+{
+	if (!document_tags_update_pending)
+	{
+		document_tags_update_pending = TRUE;
+		g_idle_add(on_document_update_tags_idle, doc);
+	}
+}
+
+
 static gboolean on_editor_notify(G_GNUC_UNUSED GObject *object, GeanyEditor *editor,
 								 SCNotification *nt, G_GNUC_UNUSED gpointer data)
 {
@@ -1049,6 +1069,8 @@ static gboolean on_editor_notify(G_GNUC_UNUSED GObject *object, GeanyEditor *edi
 				/* handle special fold cases, e.g. #1923350 */
 				fold_changed(sci, nt->line, nt->foldLevelNow, nt->foldLevelPrev);
 			}
+			if (/*editor_prefs.real_time_tags*/ TRUE && (nt->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)))
+				request_update_tag_list(doc);
 			break;
 
 		case SCN_CHARADDED:
diff --git a/src/sidebar.c b/src/sidebar.c
index 6fc85a3..892cbc5 100644
--- a/src/sidebar.c
+++ b/src/sidebar.c
@@ -198,8 +198,18 @@ static void create_default_tag_tree(void)
 /* update = rescan the tags for doc->filename */
 void sidebar_update_tag_list(GeanyDocument *doc, gboolean update)
 {
-	if (gtk_bin_get_child(GTK_BIN(tag_window)))
-		gtk_container_remove(GTK_CONTAINER(tag_window), gtk_bin_get_child(GTK_BIN(tag_window)));
+	GtkWidget *child = gtk_bin_get_child(GTK_BIN(tag_window));
+
+	/* changes the tree view to the given one, trying not to do useless changes */
+	#define CHANGE_TREE(new_child) \
+		G_STMT_START { \
+			if (child != new_child) \
+			{ \
+				if (child) \
+					gtk_container_remove(GTK_CONTAINER(tag_window), child); \
+				gtk_container_add(GTK_CONTAINER(tag_window), new_child); \
+			} \
+		} G_STMT_END
 
 	if (tv.default_tag_tree == NULL)
 		create_default_tag_tree();
@@ -207,7 +217,7 @@ void sidebar_update_tag_list(GeanyDocument *doc, gboolean update)
 	/* show default empty tag tree if there are no tags */
 	if (doc == NULL || doc->file_type == NULL || ! filetype_has_tags(doc->file_type))
 	{
-		gtk_container_add(GTK_CONTAINER(tag_window), tv.default_tag_tree);
+		CHANGE_TREE(tv.default_tag_tree);
 		return;
 	}
 
@@ -216,7 +226,7 @@ void sidebar_update_tag_list(GeanyDocument *doc, gboolean update)
 		if (doc->priv->tag_tree == NULL)
 		{
 			doc->priv->tag_store = gtk_tree_store_new(
-				SYMBOLS_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_STRING);
+				SYMBOLS_N_COLUMNS, GDK_TYPE_PIXBUF, G_TYPE_STRING, TM_TYPE_TAG, G_TYPE_STRING, G_TYPE_BOOLEAN);
 			doc->priv->tag_tree = gtk_tree_view_new();
 			prepare_taglist(doc->priv->tag_tree, doc->priv->tag_store);
 			gtk_widget_show(doc->priv->tag_tree);
@@ -228,12 +238,14 @@ void sidebar_update_tag_list(GeanyDocument *doc, gboolean update)
 
 	if (doc->has_tags)
 	{
-		gtk_container_add(GTK_CONTAINER(tag_window), doc->priv->tag_tree);
+		CHANGE_TREE(doc->priv->tag_tree);
 	}
 	else
 	{
-		gtk_container_add(GTK_CONTAINER(tag_window), tv.default_tag_tree);
+		CHANGE_TREE(tv.default_tag_tree);
 	}
+
+	#undef CHANGE_TREE
 }
 
 
@@ -874,6 +886,7 @@ static gboolean on_taglist_tree_selection_changed(gpointer data)
 					change_focus_to_editor(doc, NULL);
 			}
 		}
+		tm_tag_unref(tag);
 	}
 	return FALSE;
 }
diff --git a/src/sidebar.h b/src/sidebar.h
index e58b182..0614c78 100644
--- a/src/sidebar.h
+++ b/src/sidebar.h
@@ -43,6 +43,7 @@ enum
 	SYMBOLS_COLUMN_NAME,
 	SYMBOLS_COLUMN_TAG,
 	SYMBOLS_COLUMN_TOOLTIP,
+	SYMBOLS_COLUMN_VALID,
 	SYMBOLS_N_COLUMNS
 };
 
diff --git a/src/symbols.c b/src/symbols.c
index 3e6ee33..afe0f23 100644
--- a/src/symbols.c
+++ b/src/symbols.c
@@ -547,6 +547,71 @@ static GdkPixbuf *get_tag_icon(const gchar *icon_name)
 }
 
 
+/* finds the next iter at any level
+ * @param iter in/out, the current iter, will be changed to the next one
+ * @return TRUE if there @p iter was set, or FALSE if there is no next iter */
+static gboolean next_iter(GtkTreeModel *model, GtkTreeIter *iter)
+{
+	GtkTreeIter guess;
+	GtkTreeIter copy = *iter;
+
+	/* go down if the item has children */
+	if (gtk_tree_model_iter_children(model, &guess, iter))
+		*iter = guess;
+	/* or to the next item at the same level */
+	else if (gtk_tree_model_iter_next(model, &copy))
+		*iter = copy;
+	/* or to the next item at a parent level */
+	else if (gtk_tree_model_iter_parent(model, &guess, iter))
+	{
+		copy = guess;
+		while(TRUE)
+		{
+			if (gtk_tree_model_iter_next(model, &copy))
+			{
+				*iter = copy;
+				return TRUE;
+			}
+			else if (gtk_tree_model_iter_parent(model, &copy, &guess))
+				guess = copy;
+			else
+				return FALSE;
+		}
+	}
+	else
+		return FALSE;
+
+	return TRUE;
+}
+
+
+static gboolean find_toplevel_iter(GtkTreeStore *store, GtkTreeIter *iter, const gchar *title)
+{
+	GtkTreeModel *model = GTK_TREE_MODEL(store);
+
+	if (!gtk_tree_model_get_iter_first(model, iter))
+		return FALSE;
+	do
+	{
+		gchar *candidate;
+
+		gtk_tree_model_get(model, iter, SYMBOLS_COLUMN_NAME, &candidate, -1);
+		/* FIXME: what if 2 different items have the same name?
+		 * this should never happen, but might be caused by a typo in a translation */
+		if (utils_str_equal(candidate, title))
+		{
+			g_free(candidate);
+			return TRUE;
+		}
+		else
+			g_free(candidate);
+	}
+	while (gtk_tree_model_iter_next(model, iter));
+
+	return FALSE;
+}
+
+
 /* Adds symbol list groups in (iter*, title) pairs.
  * The list must be ended with NULL. */
 static void G_GNUC_NULL_TERMINATED
@@ -572,14 +637,15 @@ tag_list_add_groups(GtkTreeStore *tree_store, ...)
     	g_assert(title != NULL);
 		g_ptr_array_add(top_level_iter_names, title);
 
-		gtk_tree_store_append(tree_store, iter, NULL);
+		if (!find_toplevel_iter(tree_store, iter, title))
+			gtk_tree_store_append(tree_store, iter, NULL);
 
 		if (G_IS_OBJECT(icon))
 		{
 			gtk_tree_store_set(tree_store, iter, SYMBOLS_COLUMN_ICON, icon, -1);
 			g_object_unref(icon);
 		}
-		gtk_tree_store_set(tree_store, iter, SYMBOLS_COLUMN_NAME, title, -1);
+		gtk_tree_store_set(tree_store, iter, SYMBOLS_COLUMN_NAME, title, SYMBOLS_COLUMN_VALID, TRUE, -1);
 	}
 	va_end(args);
 }
@@ -890,30 +956,21 @@ static void add_top_level_items(GeanyDocument *doc)
 }
 
 
-/* the following code surely can be improved, at the moment it collects some iters
- * for removal and after that the actual removal is done. I didn't find a way to find and remove
- * an empty row in one loop (next iter fails then) */
+/* removes toplevel items that have no children */
 static void hide_empty_rows(GtkTreeStore *store)
 {
-	GtkTreeIter iter, *iters[MAX_SYMBOL_TYPES] = { NULL };
-	guint i = 0;
+	GtkTreeIter iter;
+	gboolean cont = TRUE;
 
 	if (! gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
 		return; /* stop when first iter is invalid, i.e. no elements */
 
-	do /* first collect the iters we need to delete empty rows */
+	while (cont)
 	{
 		if (! gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter))
-			iters[i++] = gtk_tree_iter_copy(&iter);
-	} while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
-
-	/* now actually delete the collected iters */
-	for (i = 0; i < MAX_SYMBOL_TYPES; i++)
-	{
-		if (G_UNLIKELY(iters[i] == NULL))
-			break;
-		gtk_tree_store_remove(store, iters[i]);
-		gtk_tree_iter_free(iters[i]);
+			cont = gtk_tree_store_remove(store, &iter);
+		else
+			cont = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
 	}
 }
 
@@ -1094,6 +1151,29 @@ static GdkPixbuf *get_child_icon(GtkTreeStore *tree_store, GtkTreeIter *parent)
 }
 
 
+static gboolean find_iter(GtkTreeStore *store, GtkTreeIter *iter, const TMTag *tag)
+{
+	GtkTreeModel *model = GTK_TREE_MODEL(store);
+	gboolean found = FALSE;
+
+	if (!gtk_tree_model_get_iter_first(model, iter))
+		return FALSE;
+	do
+	{
+		TMTag *candidate;
+
+		gtk_tree_model_get(model, iter, SYMBOLS_COLUMN_TAG, &candidate, -1);
+		found = (candidate && candidate->type == tag->type &&
+				 utils_str_equal(candidate->name, tag->name) &&
+				 utils_str_equal(candidate->atts.entry.scope, tag->atts.entry.scope));
+		tm_tag_unref(candidate);
+	}
+	while (!found && next_iter(model, iter));
+
+	return found;
+}
+
+
 static void add_tree_tag(GeanyDocument *doc, const TMTag *tag, GHashTable *parent_hash)
 {
 	filetype_id ft_id = doc->file_type->id;
@@ -1136,13 +1216,30 @@ static void add_tree_tag(GeanyDocument *doc, const TMTag *tag, GHashTable *paren
 			child = new_iter;
 		}
 
-		gtk_tree_store_append(tree_store, child, parent);
+		if (!find_iter(tree_store, child, tag))
+		{
+			gboolean expand = FALSE;
+
+			/* only expand to the iter if the parent was empty, otherwise we let the
+			 * folding as it was before (already expanded, or closed by the user) */
+			expand = !gtk_tree_model_iter_has_child(GTK_TREE_MODEL(tree_store), parent);
+			gtk_tree_store_append(tree_store, child, parent);
+			if (expand)
+			{
+				GtkTreePath *path;
+
+				path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store), child);
+				gtk_tree_view_expand_to_path(GTK_TREE_VIEW(doc->priv->tag_tree), path);
+				gtk_tree_path_free(path);
+			}
+		}
 
 		name = get_symbol_name(doc, tag, (parent_name != NULL));
 		gtk_tree_store_set(tree_store, child,
 			SYMBOLS_COLUMN_ICON, icon,
 			SYMBOLS_COLUMN_NAME, name,
 			SYMBOLS_COLUMN_TAG, tag,
+			SYMBOLS_COLUMN_VALID, TRUE,
 			-1);
 
 		if (gtk_check_version(2, 12, 0) == NULL)
@@ -1223,7 +1320,8 @@ static gint tree_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
 		gpointer user_data)
 {
 	gboolean sort_by_name = GPOINTER_TO_INT(user_data);
-	const TMTag *tag_a, *tag_b;
+	TMTag *tag_a, *tag_b;
+	gint cmp;
 
 	gtk_tree_model_get(model, a, SYMBOLS_COLUMN_TAG, &tag_a, -1);
 	gtk_tree_model_get(model, b, SYMBOLS_COLUMN_TAG, &tag_b, -1);
@@ -1233,13 +1331,12 @@ static gint tree_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
 	if (tag_a && !tag_has_missing_parent(tag_a, GTK_TREE_STORE(model), a) &&
 		tag_b && !tag_has_missing_parent(tag_b, GTK_TREE_STORE(model), b))
 	{
-		return sort_by_name ? compare_symbol(tag_a, tag_b) :
+		cmp = sort_by_name ? compare_symbol(tag_a, tag_b) :
 			compare_symbol_lines(tag_a, tag_b);
 	}
 	else
 	{
 		gchar *astr, *bstr;
-		gint cmp;
 
 		gtk_tree_model_get(model, a, SYMBOLS_COLUMN_NAME, &astr, -1);
 		gtk_tree_model_get(model, b, SYMBOLS_COLUMN_NAME, &bstr, -1);
@@ -1253,23 +1350,28 @@ static gint tree_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
 		{
 			/* this is what g_strcmp0() does */
 			if (! astr)
-				return -(astr != bstr);
+				cmp = -(astr != bstr);
 			if (! bstr)
-				return astr != bstr;
-
-			cmp = strcmp(astr, bstr);
-
-			/* sort duplicate 'ScopeName::OverloadedTagName' items by line as well */
-			if (tag_a && tag_b)
-				if (!sort_by_name ||
-					(utils_str_equal(tag_a->name, tag_b->name) &&
-						utils_str_equal(tag_a->atts.entry.scope, tag_b->atts.entry.scope)))
-					cmp = compare_symbol_lines(tag_a, tag_b);
+				cmp = astr != bstr;
+			else
+			{
+				cmp = strcmp(astr, bstr);
+
+				/* sort duplicate 'ScopeName::OverloadedTagName' items by line as well */
+				if (tag_a && tag_b)
+					if (!sort_by_name ||
+						(utils_str_equal(tag_a->name, tag_b->name) &&
+							utils_str_equal(tag_a->atts.entry.scope, tag_b->atts.entry.scope)))
+						cmp = compare_symbol_lines(tag_a, tag_b);
+			}
 		}
 		g_free(astr);
 		g_free(bstr);
-		return cmp;
 	}
+	tm_tag_unref(tag_a);
+	tm_tag_unref(tag_b);
+
+	return cmp;
 }
 
 
@@ -1282,6 +1384,53 @@ static void sort_tree(GtkTreeStore *store, gboolean sort_by_name)
 }
 
 
+static void invalidate_rows(GtkTreeStore *store)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model = GTK_TREE_MODEL(store);
+
+	if (!gtk_tree_model_get_iter_first(model, &iter))
+		return;
+	do
+	{
+		gtk_tree_store_set(store, &iter, SYMBOLS_COLUMN_VALID, FALSE, -1);
+	}
+	while (next_iter(model, &iter));
+}
+
+
+static void remove_invalid_rows(GtkTreeStore *store)
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model = GTK_TREE_MODEL(store);
+	gboolean cont;
+
+	cont = gtk_tree_model_get_iter_first(model, &iter);
+	while (cont)
+	{
+		gboolean valid;
+
+		gtk_tree_model_get(model, &iter, SYMBOLS_COLUMN_VALID, &valid, -1);
+		if (!valid)
+		{
+			GtkTreeIter parent;
+			gboolean have_parent;
+
+			have_parent = gtk_tree_model_iter_parent(model, &parent, &iter);
+			cont = gtk_tree_store_remove(store, &iter);
+			/* if there is no next at this level but there is a parent iter, continue from it */
+			if (!cont && have_parent)
+			{
+				iter = parent;
+				cont = next_iter(model, &iter);
+			}
+		}
+		else
+			cont = next_iter(model, &iter);
+	}
+}
+
+
 gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
 {
 	GList *tags;
@@ -1292,12 +1441,14 @@ gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
 	if (tags == NULL)
 		return FALSE;
 
-	/* Make sure the model stays with us after the tree view unrefs it */
-	g_object_ref(GTK_TREE_MODEL(doc->priv->tag_store));
-	/* Detach model from view */
-	gtk_tree_view_set_model(GTK_TREE_VIEW(doc->priv->tag_tree), NULL);
-	/* Clear all contents */
-	gtk_tree_store_clear(doc->priv->tag_store);
+	/* FIXME: Not sure why we detached the model here? */
+
+	/* disable sorting during update because the code doesn't support correctly
+	 * models that are currently being built */
+	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(doc->priv->tag_store), GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, 0);
+
+	/* invalidate all content */
+	invalidate_rows(doc->priv->tag_store);
 
 	/* add grandparent type iters */
 	add_top_level_items(doc);
@@ -1305,6 +1456,7 @@ gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
 	add_tree_tags(doc, tags);
 	g_list_free(tags);
 
+	remove_invalid_rows(doc->priv->tag_store);
 	hide_empty_rows(doc->priv->tag_store);
 
 	if (sort_mode == SYMBOLS_SORT_USE_PREVIOUS)
@@ -1313,12 +1465,6 @@ gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
 	sort_tree(doc->priv->tag_store, sort_mode == SYMBOLS_SORT_BY_NAME);
 	doc->priv->symbol_list_sort_mode = sort_mode;
 
-	/* Re-attach model to view */
-	gtk_tree_view_set_model(GTK_TREE_VIEW(doc->priv->tag_tree),
-		GTK_TREE_MODEL(doc->priv->tag_store));
-	g_object_unref(GTK_TREE_MODEL(doc->priv->tag_store));
-	gtk_tree_view_expand_all(GTK_TREE_VIEW(doc->priv->tag_tree));
-
 	return TRUE;
 }
 
diff --git a/tagmanager/Makefile.am b/tagmanager/Makefile.am
index dd6ac89..cca1091 100644
--- a/tagmanager/Makefile.am
+++ b/tagmanager/Makefile.am
@@ -2,7 +2,7 @@
 # $Id$
 
 SUBDIRS = include
-INCLUDES = -I$(srcdir)/include $(GTK_CFLAGS)
+INCLUDES = -I$(srcdir)/include $(GTK_CFLAGS) $(MIO_CFLAGS)
 
 AM_CFLAGS = -DG_LOG_DOMAIN=\""Tagmanager"\"
 
diff --git a/tagmanager/c.c b/tagmanager/c.c
index b6714a2..cef1181 100644
--- a/tagmanager/c.c
+++ b/tagmanager/c.c
@@ -16,6 +16,7 @@
 
 #include <string.h>
 #include <setjmp.h>
+#include <mio/mio.h>
 
 #include "entry.h"
 #include "get.h"
@@ -180,8 +181,7 @@ typedef struct sTokenInfo
 	keywordId		keyword;
 	vString*		name;			/* the name of the token */
 	unsigned long	lineNumber;		/* line number of tag */
-	fpos_t			filePosition;	/* file position of line containing name */
-	int				bufferPosition;	/* buffer position of line containing name */
+	MIOPos			filePosition;	/* file position of line containing name */
 } tokenInfo;
 
 typedef enum eImplementation
@@ -602,10 +602,7 @@ static void initToken (tokenInfo* const token)
 	token->type			= TOKEN_NONE;
 	token->keyword		= KEYWORD_NONE;
 	token->lineNumber	= getSourceLineNumber();
-	if (useFile())
-		token->filePosition   = getInputFilePosition();
-	else
-		token->bufferPosition = getInputBufferPosition();
+	token->filePosition	= getInputFilePosition();
 	vStringClear(token->name);
 }
 
@@ -664,7 +661,7 @@ static void deleteToken (tokenInfo *const token)
 
 static const char *accessString (const accessType laccess)
 {
-	static const char *const names [] ={
+	static const char *const names [] = {
 		"?", "private", "protected", "public", "default"
 	};
 	Assert (sizeof (names) / sizeof (names [0]) == ACCESS_COUNT);
@@ -674,7 +671,7 @@ static const char *accessString (const accessType laccess)
 
 static const char *implementationString (const impType imp)
 {
-	static const char *const names [] ={
+	static const char *const names [] = {
 		"?", "abstract", "virtual", "pure virtual"
 	};
 	Assert (sizeof (names) / sizeof (names [0]) == IMP_COUNT);
@@ -694,7 +691,7 @@ static const char *tokenString (const tokenType type)
 {
 	static const char *const names [] = {
 		"none", "args", "}", "{", "comma", "double colon", "keyword", "name",
-		"package", "paren-name", "semicolon", "specifier", "*", "[]", "count"
+		"package", "paren-name", "semicolon", "specifier", "*", "[]"
 	};
 	Assert (sizeof (names) / sizeof (names [0]) == TOKEN_COUNT);
 	Assert ((int) type < TOKEN_COUNT);
@@ -713,13 +710,14 @@ static const char *scopeString (const tagScope scope)
 
 static const char *declString (const declType declaration)
 {
-		static const char *const names [] = {
-			"?", "base", "class", "enum", "function", "ignore", "interface",
-			"namespace", "no mangle", "package", "struct", "union",
-		};
-		Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
-		Assert ((int) declaration < DECL_COUNT);
-		return names[(int) declaration];
+	static const char *const names [] = {
+		"?", "base", "class", "enum", "event", "signal", "function",
+		"function template", "ignore", "interface", "module", "namespace",
+		"no mangle", "package", "struct", "union",
+	};
+	Assert (sizeof (names) / sizeof (names [0]) == DECL_COUNT);
+	Assert ((int) declaration < DECL_COUNT);
+	return names[(int) declaration];
 }
 
 static const char *keywordString (const keywordId keyword)
@@ -897,6 +895,7 @@ static void initMemberInfo (statementInfo *const st)
 {
 	accessType accessDefault = ACCESS_UNDEFINED;
 
+	/* TODO: review this for Vala */
 	if (st->parent != NULL) switch (st->parent->declaration)
 	{
 		case DECL_ENUM:
@@ -956,8 +955,7 @@ static void reinitStatement (statementInfo *const st, const boolean partial)
 	initToken (st->blockName);
 	vStringClear (st->parentClasses);
 
-	/*  Init member info.
-	 */
+	/* Init member info. */
 	if (! partial)
 		st->member.access = st->member.accessDefault;
 
@@ -984,7 +982,7 @@ static void initStatement (statementInfo *const st, statementInfo *const parent)
 	st->parent = parent;
 	initMemberInfo (st);
 	reinitStatement (st, FALSE);
-	if(parent)
+	if (parent)
 	{
 		const tokenInfo *const src = activeToken (parent);
 		tokenInfo *const dst = activeToken (st);
@@ -1185,11 +1183,11 @@ static const char* accessField (const statementInfo *const st)
 static void addOtherFields (tagEntryInfo* const tag, const tagType type,
 							const statementInfo *const st, vString *const scope)
 {
-    /*  For selected tag types, append an extension flag designating the
-     *  parent object in which the tag is defined.
-     */
-    switch (type)
-    {
+	/*  For selected tag types, append an extension flag designating the
+	 *  parent object in which the tag is defined.
+	 */
+	switch (type)
+	{
 		default: break;
 
 		case TAG_CLASS:
@@ -1218,7 +1216,6 @@ static void addOtherFields (tagEntryInfo* const tag, const tagType type,
 			if ((type == TAG_CLASS  ||  type == TAG_INTERFACE  ||
 				 type == TAG_STRUCT) && vStringLength (st->parentClasses) > 0)
 			{
-
 				tag->extensionFields.inheritance =
 						vStringValue (st->parentClasses);
 			}
@@ -1236,16 +1233,8 @@ static void addOtherFields (tagEntryInfo* const tag, const tagType type,
             if ((TRUE == st->gotArgs) && (TRUE == Option.extensionFields.argList) &&
 				((TAG_FUNCTION == type) || (TAG_METHOD == type) || (TAG_PROTOTYPE == type)))
 			{
-				if (useFile())
-				{
-					tag->extensionFields.arglist = getArglistFromFilePos(
+				tag->extensionFields.arglist = getArglistFromFilePos(
 						tag->filePosition, tag->name);
-				}
-				else
-				{
-					tag->extensionFields.arglist = getArglistFromBufferPos(
-						tag->bufferPosition, tag->name);
-				}
 			}
 			break;
 		}
@@ -1424,10 +1413,7 @@ static void makeTag (const tokenInfo *const token,
 		initTagEntry (&e, vStringValue (token->name));
 
 		e.lineNumber	= token->lineNumber;
-		if (useFile())
-			e.filePosition	= token->filePosition;
-		else
-			e.bufferPosition = token->bufferPosition;
+		e.filePosition	= token->filePosition;
 		e.isFileScope = isFileScope;
 		e.kindName	= tagName (type);
 		e.kind		= tagLetter (type);
@@ -1561,7 +1547,8 @@ static void qualifyVariableTag (const statementInfo *const st,
 			else if (st->scope == SCOPE_GLOBAL  ||  st->scope == SCOPE_STATIC)
 				makeTag (nameToken, st, TRUE, TAG_MEMBER);
 		}
-		else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala));
+		else if (isLanguage (Lang_java) || isLanguage (Lang_csharp) || isLanguage (Lang_vala))
+			;
 		else
 		{
 			if (st->scope == SCOPE_EXTERN  ||  ! st->haveQualifyingName)
@@ -1894,10 +1881,7 @@ static void copyToken (tokenInfo *const dest, const tokenInfo *const src)
 {
 	dest->type         = src->type;
 	dest->keyword      = src->keyword;
-	if (useFile())
-		dest->filePosition = src->filePosition;
-	else
-		dest->bufferPosition = src->bufferPosition;
+	dest->filePosition = src->filePosition;
 	dest->lineNumber   = src->lineNumber;
 	vStringCopy (dest->name, src->name);
 }
@@ -2485,15 +2469,8 @@ static int parseParens (statementInfo *const st, parenInfo *const info)
 		skipToMatch ("()");
 		--depth;
 	}
-		if (st->argEndPosition == 0)
-		{
-			if (useFile())
-				st->argEndPosition = ftell(File.fp);
-			else
-				/* FIXME File.fpBufferPosition is wrong here, this breaks function signatures and
-				 * so Geany's calltips */
-				st->argEndPosition = File.fpBufferPosition;
-		}
+	if (st->argEndPosition == 0)
+		st->argEndPosition = mio_tell (File.mio);
 
 	if (! info->isNameCandidate)
 		initToken (token);
@@ -2541,7 +2518,8 @@ static void analyzeParens (statementInfo *const st)
 			token->type = TOKEN_NAME;
 			processName (st);
 			st->gotParenName = TRUE;
-			if (isLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME)) {
+			if (isLanguage(Lang_d) && c == '(' && isType (prev, TOKEN_NAME))
+			{
 				st->declaration = DECL_FUNCTION_TEMPLATE;
 				copyToken (st->blockName, prev);
 			}
@@ -2876,12 +2854,12 @@ static void nest (statementInfo *const st, const unsigned int nestLevel)
 
 static void tagCheck (statementInfo *const st)
 {
-    const tokenInfo *const token = activeToken (st);
-    const tokenInfo *const prev  = prevToken (st, 1);
-    const tokenInfo *const prev2 = prevToken (st, 2);
+	const tokenInfo *const token = activeToken (st);
+	const tokenInfo *const prev  = prevToken (st, 1);
+	const tokenInfo *const prev2 = prevToken (st, 2);
 
-    switch (token->type)
-    {
+	switch (token->type)
+	{
 		case TOKEN_NAME:
 		{
 			if (insideEnumBody (st))
@@ -2913,6 +2891,7 @@ static void tagCheck (statementInfo *const st)
 			else if (isContextualStatement (st))
 			{
 				tokenInfo *name_token = (tokenInfo *)prev;
+				boolean free_name_token = FALSE;
 
 				if (isType (name_token, TOKEN_NAME))
 				{
@@ -2949,6 +2928,7 @@ static void tagCheck (statementInfo *const st)
 						char buffer[64];
 
 						name_token = newToken ();
+						free_name_token = TRUE;
 						copyToken (name_token, contextual_token);
 
 						sprintf(buffer, "anon_%s_%d", name_token->name->buffer, contextual_fake_count++);
@@ -2967,6 +2947,8 @@ static void tagCheck (statementInfo *const st)
 					}
 				}
 				qualifyBlockTag (st, name_token);
+				if (free_name_token)
+					deleteToken (name_token);
 			}
 			break;
 		}
@@ -3044,6 +3026,8 @@ static boolean findCTags (const unsigned int passCount)
 	exception_t exception;
 	boolean retry;
 
+	contextual_fake_count = 0;
+
 	Assert (passCount < 3);
 	cppInit ((boolean) (passCount > 1), isLanguage (Lang_csharp));
 
@@ -3082,56 +3066,48 @@ static void buildKeywordHash (const langType language, unsigned int idx)
 
 static void initializeCParser (const langType language)
 {
-	contextual_fake_count = 0;
 	Lang_c = language;
 	buildKeywordHash (language, 0);
 }
 
 static void initializeCppParser (const langType language)
 {
-	contextual_fake_count = 0;
 	Lang_cpp = language;
 	buildKeywordHash (language, 1);
 }
 
 static void initializeJavaParser (const langType language)
 {
-	contextual_fake_count = 0;
 	Lang_java = language;
 	buildKeywordHash (language, 3);
 }
 
 static void initializeDParser (const langType language)
 {
-	contextual_fake_count = 0;
 	Lang_d = language;
 	buildKeywordHash (language, 6);
 }
 
 static void initializeGLSLParser (const langType language)
 {
-	contextual_fake_count = 0;
 	Lang_glsl = language;
 	buildKeywordHash (language, 0); /* C keywords */
 }
 
 static void initializeFeriteParser (const langType language)
 {
-	contextual_fake_count = 0;
 	Lang_ferite = language;
 	buildKeywordHash (language, 1);	/* C++ keywords */
 }
 
 static void initializeCsharpParser (const langType language)
 {
-	contextual_fake_count = 0;
 	Lang_csharp = language;
 	buildKeywordHash (language, 2);
 }
 
 static void initializeValaParser (const langType language)
 {
-	contextual_fake_count = 0;
 	Lang_vala = language;
 	buildKeywordHash (language, 5);
 }
diff --git a/tagmanager/entry.c b/tagmanager/entry.c
index f09b095..8dfd312 100644
--- a/tagmanager/entry.c
+++ b/tagmanager/entry.c
@@ -127,8 +127,8 @@ static void writePseudoTag (const char *const tagName,
 			    const char *const fileName,
 			    const char *const pattern)
 {
-    const int length = fprintf (TagFile.fp, "%s%s\t%s\t/%s/\n",
-			       PSEUDO_TAG_PREFIX, tagName, fileName, pattern);
+    const int length = mio_printf (TagFile.mio, "%s%s\t%s\t/%s/\n",
+				   PSEUDO_TAG_PREFIX, tagName, fileName, pattern);
     ++TagFile.numTags.added;
     rememberMaxLengths (strlen (tagName), (size_t) length);
 }
@@ -159,7 +159,7 @@ static void addPseudoTags (void)
 }
 
 static void updateSortedFlag (const char *const line,
-			      FILE *const fp, fpos_t startOfLine)
+			      MIO *const mio, MIOPos startOfLine)
 {
     const char *const tab = strchr (line, '\t');
 
@@ -169,27 +169,27 @@ static void updateSortedFlag (const char *const line,
 
 	if (line [boolOffset] == '0'  ||  line [boolOffset] == '1')
 	{
-	    fpos_t nextLine;
+	    MIOPos nextLine;
 
-	    if (fgetpos (fp, &nextLine) == -1 || fsetpos (fp, &startOfLine) == -1)
+	    if (mio_getpos (mio, &nextLine) == -1 || mio_setpos (mio, &startOfLine) == -1)
 		error (WARNING, "Failed to update 'sorted' pseudo-tag");
 	    else
 	    {
-		fpos_t flagLocation;
+		MIOPos flagLocation;
 		int c, d;
 
 		do
-		    c = fgetc (fp);
+		    c = mio_getc (mio);
 		while (c != '\t'  &&  c != '\n');
-		fgetpos (fp, &flagLocation);
-		d = fgetc (fp);
+		mio_getpos (mio, &flagLocation);
+		d = mio_getc (mio);
 		if (c == '\t'  &&  (d == '0'  ||  d == '1')  &&
 		    d != (int) Option.sorted)
 		{
-		    fsetpos (fp, &flagLocation);
-		    fputc (Option.sorted ? '1' : '0', fp);
+		    mio_setpos (mio, &flagLocation);
+		    mio_putc (mio, Option.sorted ? '1' : '0');
 		}
-		fsetpos (fp, &nextLine);
+		mio_setpos (mio, &nextLine);
 	    }
 	}
     }
@@ -198,12 +198,12 @@ static void updateSortedFlag (const char *const line,
 /*  Look through all line beginning with "!_TAG_FILE", and update those which
  *  require it.
  */
-static long unsigned int updatePseudoTags (FILE *const fp)
+static long unsigned int updatePseudoTags (MIO *const mio)
 {
     enum { maxClassLength = 20 };
     char class [maxClassLength + 1];
     unsigned long linesRead = 0;
-    fpos_t startOfLine;
+    MIOPos startOfLine;
     size_t classLength;
     const char *line;
 
@@ -211,8 +211,8 @@ static long unsigned int updatePseudoTags (FILE *const fp)
     classLength = strlen (class);
     Assert (classLength < maxClassLength);
 
-    fgetpos (fp, &startOfLine);
-    line = readLine (TagFile.vLine, fp);
+    mio_getpos (mio, &startOfLine);
+    line = readLine (TagFile.vLine, mio);
     while (line != NULL  &&  line [0] == class [0])
     {
 	++linesRead;
@@ -224,16 +224,16 @@ static long unsigned int updatePseudoTags (FILE *const fp)
 		tab == '\t')
 	    {
 		if (strcmp (classType, "_SORTED") == 0)
-		    updateSortedFlag (line, fp, startOfLine);
+		    updateSortedFlag (line, mio, startOfLine);
 	    }
-	    fgetpos (fp, &startOfLine);
+	    mio_getpos (mio, &startOfLine);
 	}
-	line = readLine (TagFile.vLine, fp);
+	line = readLine (TagFile.vLine, mio);
     }
     while (line != NULL)			/* skip to end of file */
     {
 	++linesRead;
-	line = readLine (TagFile.vLine, fp);
+	line = readLine (TagFile.vLine, mio);
     }
     return linesRead;
 }
@@ -247,22 +247,22 @@ static long unsigned int updatePseudoTags (FILE *const fp)
 static boolean isTagFile (const char *const filename)
 {
     boolean ok = FALSE;			/* we assume not unless confirmed */
-    FILE *const fp = g_fopen (filename, "rb");
+    MIO *const mio = mio_new_file_full (filename, "rb", g_fopen, fclose);
 
-    if (fp == NULL  &&  errno == ENOENT)
+    if (mio == NULL  &&  errno == ENOENT)
 	ok = TRUE;
-    else if (fp != NULL)
+    else if (mio != NULL)
     {
-	const char *line = readLine (TagFile.vLine, fp);
+	const char *line = readLine (TagFile.vLine, mio);
 
 	if (line == NULL)
 	    ok = TRUE;
-	fclose (fp);
+	mio_free (mio);
     }
     return ok;
 }
 
-extern void copyBytes (FILE* const fromFp, FILE* const toFp, const long size)
+extern void copyBytes (MIO* const fromMio, MIO* const toMio, const long size)
 {
     enum { BufferSize = 1000 };
     long toRead, numRead;
@@ -272,8 +272,8 @@ extern void copyBytes (FILE* const fromFp, FILE* const toFp, const long size)
     {
 	toRead = (0 < remaining && remaining < BufferSize) ?
 		    remaining : BufferSize;
-	numRead = fread (buffer, (size_t) 1, (size_t) toRead, fromFp);
-	if (fwrite (buffer, (size_t)1, (size_t)numRead, toFp) < (size_t)numRead)
+	numRead = mio_read (fromMio, buffer, (size_t) 1, (size_t) toRead);
+	if (mio_write (toMio, buffer, (size_t)1, (size_t)numRead) < (size_t)numRead)
 	    error (FATAL | PERROR, "cannot complete write");
 	if (remaining > 0)
 	    remaining -= numRead;
@@ -283,20 +283,20 @@ extern void copyBytes (FILE* const fromFp, FILE* const toFp, const long size)
 
 extern void copyFile (const char *const from, const char *const to, const long size)
 {
-    FILE* const fromFp = g_fopen (from, "rb");
-    if (fromFp == NULL)
+    MIO* const fromMio = mio_new_file_full (from, "rb", g_fopen, fclose);
+    if (fromMio == NULL)
 	error (FATAL | PERROR, "cannot open file to copy");
     else
     {
-	FILE* const toFp = g_fopen (to, "wb");
-	if (toFp == NULL)
+	MIO* const toMio = mio_new_file_full (to, "wb", g_fopen, fclose);
+	if (toMio == NULL)
 	    error (FATAL | PERROR, "cannot open copy destination");
 	else
 	{
-	    copyBytes (fromFp, toFp, size);
-	    fclose (toFp);
+	    copyBytes (fromMio, toMio, size);
+	    mio_free (toMio);
 	}
-	fclose (fromFp);
+	mio_free (fromMio);
     }
 }
 
@@ -311,7 +311,12 @@ extern void openTagFile (void)
     /*  Open the tags file.
      */
     if (TagsToStdout)
-	TagFile.fp = tempFile ("w", &TagFile.name);
+    {
+	FILE *fp;
+
+	fp = tempFile ("w", &TagFile.name);
+	TagFile.mio = mio_new_fp (fp, fclose);
+    }
     else
     {
 	boolean fileExists;
@@ -324,24 +329,24 @@ extern void openTagFile (void)
 	      "\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
 		  TagFile.name);
 
-    if (Option.append  &&  fileExists)
-    {
-	TagFile.fp = g_fopen (TagFile.name, "r+");
-	if (TagFile.fp != NULL)
+	if (Option.append  &&  fileExists)
 	{
-	    TagFile.numTags.prev = updatePseudoTags (TagFile.fp);
-	    fclose (TagFile.fp);
-	    TagFile.fp = g_fopen (TagFile.name, "a+");
+	    TagFile.mio = mio_new_file_full (TagFile.name, "r+", g_fopen, fclose);
+	    if (TagFile.mio != NULL)
+	    {
+		TagFile.numTags.prev = updatePseudoTags (TagFile.mio);
+		mio_free (TagFile.mio);
+		TagFile.mio = mio_new_file_full (TagFile.name, "a+", g_fopen, fclose);
+	    }
+	}
+	else
+	{
+	    TagFile.mio = mio_new_file_full (TagFile.name, "w", g_fopen, fclose);
+	    if (TagFile.mio != NULL)
+		addPseudoTags ();
 	}
-    }
-    else
-    {
-	TagFile.fp = g_fopen (TagFile.name, "w");
-	if (TagFile.fp != NULL)
-	    addPseudoTags ();
-    }
 
-	if (TagFile.fp == NULL)
+	if (TagFile.mio == NULL)
 	{
 	    error (FATAL | PERROR, "cannot open tag file");
 	    exit (1);
@@ -409,7 +414,6 @@ extern void initTagEntry (tagEntryInfo *const e, const char *const name)
     e->lineNumber	= getSourceLineNumber ();
     e->language		= getSourceLanguageName ();
     e->filePosition	= getInputFilePosition ();
-    e->bufferPosition	= getInputBufferPosition ();
     e->sourceFileName	= getSourceFileTagPath ();
     e->name		= name;
 }
diff --git a/tagmanager/entry.h b/tagmanager/entry.h
index 7a19f11..e4a2d1e 100644
--- a/tagmanager/entry.h
+++ b/tagmanager/entry.h
@@ -15,7 +15,7 @@
 */
 #include "general.h"	/* must always come first */
 
-#include <stdio.h>
+#include <mio/mio.h>
 
 #include "vstring.h"
 
@@ -33,12 +33,12 @@
 typedef struct eTagFile {
     char *name;
     char *directory;
-    FILE *fp;
+    MIO *mio;
     struct sNumTags { unsigned long added, prev; } numTags;
     struct sMax { size_t line, tag, file; } max;
     struct sEtags {
 	char *name;
-	FILE *fp;
+	MIO *mio;
 	size_t byteCount;
     } etags;
     vString *vLine;
@@ -55,7 +55,7 @@ typedef struct sTagFields {
 typedef struct sTagEntryInfo {
     boolean	lineNumberEntry;/* pattern or line number entry */
     unsigned long lineNumber;	/* line number of tag */
-    fpos_t	filePosition;	/* file position of line containing tag */
+    MIOPos	filePosition;	/* file position of line containing tag */
     int bufferPosition;		/* buffer position of line containing tag */
     const char*	language;	/* language of source file */
     boolean	isFileScope;	/* is tag visibile only within source file? */
@@ -88,7 +88,7 @@ extern tagFile TagFile;
 */
 extern void freeTagFileResources (void);
 extern const char *tagFileName (void);
-extern void copyBytes (FILE* const fromFp, FILE* const toFp, const long size);
+extern void copyBytes (MIO* const fromMio, MIO* const toMio, const long size);
 extern void copyFile (const char *const from, const char *const to, const long size);
 extern void openTagFile (void);
 extern void closeTagFile (const boolean resize);
diff --git a/tagmanager/fortran.c b/tagmanager/fortran.c
index e341a95..3dbe59b 100644
--- a/tagmanager/fortran.c
+++ b/tagmanager/fortran.c
@@ -19,6 +19,7 @@
 #include <limits.h>
 #include <ctype.h>	/* to define tolower () */
 #include <setjmp.h>
+#include <mio/mio.h>
 
 #include "entry.h"
 #include "keyword.h"
@@ -183,8 +184,7 @@ typedef struct sTokenInfo {
 	vString* string;
 	struct sTokenInfo *secondary;
 	unsigned long lineNumber;
-	fpos_t filePosition;
-	int bufferPosition;	/* buffer position of line containing name */
+	MIOPos filePosition;
 } tokenInfo;
 
 /*
@@ -423,10 +423,7 @@ static tokenInfo *newToken (void)
 	token->string       = vStringNew ();
 	token->secondary    = NULL;
 	token->lineNumber   = getSourceLineNumber ();
-	if (useFile())
-	    token->filePosition = getInputFilePosition ();
-	else
-	    token->bufferPosition = getInputBufferPosition ();
+	token->filePosition = getInputFilePosition ();
 
 	return token;
 }
@@ -480,10 +477,7 @@ static void makeFortranTag (tokenInfo *const token, tagType tag)
 			e.lineNumberEntry = (boolean) (Option.locate != EX_PATTERN);
 
 		e.lineNumber	= token->lineNumber;
-		if (useFile())
-		    e.filePosition   = token->filePosition;
-		else
-		    e.bufferPosition = token->bufferPosition;
+		e.filePosition	= token->filePosition;
 		e.isFileScope	= isFileScope (token->tag);
 		e.kindName		= FortranKinds [token->tag].name;
 		e.kind			= FortranKinds [token->tag].letter;
@@ -959,10 +953,7 @@ getNextChar:
 	c = getChar ();
 
 	token->lineNumber	= getSourceLineNumber ();
-	if (useFile())
-	    token->filePosition = getInputFilePosition ();
-	else
-	    token->bufferPosition = getInputBufferPosition ();
+	token->filePosition = getInputFilePosition ();
 
 	switch (c)
 	{
diff --git a/tagmanager/get.c b/tagmanager/get.c
index 0e924e3..5472a6b 100644
--- a/tagmanager/get.c
+++ b/tagmanager/get.c
@@ -314,14 +314,8 @@ static void makeDefineTag (const char *const name, boolean parameterized)
 		e.kind         = 'd';
 		if (parameterized)
 		{
-			if (useFile()) {
-				e.extensionFields.arglist = getArglistFromFilePos(getInputFilePosition()
-		  			, e.name);
-			}
-			else {
-				e.extensionFields.arglist = getArglistFromBufferPos(getInputBufferPosition()
-		  			, e.name);
-			}
+			e.extensionFields.arglist = getArglistFromFilePos(getInputFilePosition()
+					, e.name);
 		}
 		makeTagEntry (&e);
 		if (parameterized)
@@ -715,63 +709,30 @@ process:
 	return c;
 }
 
-extern char *getArglistFromBufferPos(int startPosition, const char *tokenName)
-{
-	int bufferOriginalPosition;
-	char *result = NULL;
-	char *arglist = NULL;
-	long pos1, pos2;
-
-	/* FIXME startPosition as well as getBufPos() are mostly wrong here */
-	pos2 = getBufPos();
-
-	if (!useFile()) {
-		bufferOriginalPosition = getBufPos ();
-		setBufPos(startPosition);
-		pos1 = File.fpBufferPosition;
-	}
-	else
-		return NULL;
-
-	if (pos2 > pos1)
-	{
-		result = (char *) g_malloc(sizeof(char ) * (pos2 - pos1 + 2));
-		if (result != NULL)
-		{
-			memcpy(result, &File.fpBuffer[getBufPos()], pos2 - pos1 + 1);
-			result[pos2-pos1+1] = '\0';
-			arglist = getArglistFromStr(result, tokenName);
-			g_free(result);
-		}
-	}
-	setBufPos (bufferOriginalPosition);
-	return arglist;
-}
-
-extern char *getArglistFromFilePos(fpos_t startPosition, const char *tokenName)
+extern char *getArglistFromFilePos(MIOPos startPosition, const char *tokenName)
 {
-	fpos_t originalPosition;
+	MIOPos originalPosition;
 	char *result = NULL;
 	char *arglist = NULL;
 	long pos1, pos2;
 
-	pos2 = ftell(File.fp);
+	pos2 = mio_tell(File.mio);
 
-	fgetpos(File.fp, &originalPosition);
-	fsetpos(File.fp, &startPosition);
-	pos1 = ftell(File.fp);
+	mio_getpos(File.mio, &originalPosition);
+	mio_setpos(File.mio, &startPosition);
+	pos1 = mio_tell(File.mio);
 
 	if (pos2 > pos1)
 	{
 		result = (char *) g_malloc(sizeof(char ) * (pos2 - pos1 + 2));
-		if (result != NULL && fread(result, sizeof(char), pos2 - pos1 + 1, File.fp) > 0)
+		if (result != NULL && mio_read(File.mio, result, sizeof(char), pos2 - pos1 + 1) > 0)
 		{
 			result[pos2-pos1+1] = '\0';
 			arglist = getArglistFromStr(result, tokenName);
 		}
 		g_free(result);
 	}
-	fsetpos(File.fp, &originalPosition);
+	mio_setpos(File.mio, &originalPosition);
 	return arglist;
 }
 
diff --git a/tagmanager/get.h b/tagmanager/get.h
index a34e33b..e284a3f 100644
--- a/tagmanager/get.h
+++ b/tagmanager/get.h
@@ -45,8 +45,7 @@ extern void cppEndStatement (void);
 extern void cppUngetc (const int c);
 extern int cppGetc (void);
 extern int skipOverCComment (void);
-extern char *getArglistFromFilePos(fpos_t startPosition, const char *tokenName);
-extern char *getArglistFromBufferPos(int startPosition, const char *tokenName);
+extern char *getArglistFromFilePos(MIOPos startPosition, const char *tokenName);
 extern char *getArglistFromStr(char *buf, const char *name);
 
 #endif  /* _GET_H */
diff --git a/tagmanager/include/tm_tag.h b/tagmanager/include/tm_tag.h
index 00c15dc..0107e99 100644
--- a/tagmanager/include/tm_tag.h
+++ b/tagmanager/include/tm_tag.h
@@ -30,6 +30,7 @@
 */
 
 #include "tm_source_file.h"
+#include <glib-object.h>
 
 #ifdef __cplusplus
 extern "C"
@@ -147,6 +148,7 @@ typedef struct _TMTag
 			gboolean inactive; /*!< Whether this file is to be parsed */
 		} file;
 	} atts;
+	gint refcount; /*!< the reference count of the tag */
 } TMTag;
 
 /*!
@@ -158,6 +160,12 @@ typedef struct _TMTag
 */
 typedef int (*TMTagCompareFunc) (const void *ptr1, const void *ptr2);
 
+/*! The GType for a TMTag */
+#define TM_TYPE_TAG (tm_tag_get_type())
+
+/*! Gets the GType for a TMTag */
+GType tm_tag_get_type(void) G_GNUC_CONST;
+
 /*!
  Initializes a TMTag structure with information from a tagEntryInfo struct
  used by the ctags parsers. Note that the TMTag structure must be malloc()ed
@@ -306,13 +314,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/js.c b/tagmanager/js.c
index 7c1844d..897b333 100644
--- a/tagmanager/js.c
+++ b/tagmanager/js.c
@@ -21,6 +21,7 @@
 #include "general.h"	/* must always come first */
 #include <ctype.h>	/* to define isalpha () */
 #include <setjmp.h>
+#include <mio/mio.h>
 #ifdef DEBUG
 #include <stdio.h>
 #endif
@@ -107,10 +108,9 @@ typedef struct sTokenInfo {
 	vString *		string;
 	vString *		scope;
 	unsigned long 	lineNumber;
-	fpos_t 			filePosition;
+	MIOPos			filePosition;
 	int				nestLevel;
 	boolean			ignoreTag;
-    int	bufferPosition;	/* buffer position of line containing name */
 } tokenInfo;
 
 /*
@@ -198,10 +198,7 @@ static tokenInfo *newToken (void)
 	token->nestLevel	= 0;
 	token->ignoreTag	= FALSE;
 	token->lineNumber   = getSourceLineNumber ();
-    if (useFile())
-		token->filePosition = getInputFilePosition ();
-    else
-		token->bufferPosition = getInputBufferPosition ();
+	token->filePosition = getInputFilePosition ();
 
 	return token;
 }
@@ -357,11 +354,8 @@ getNextChar:
 	{
 		c = fileGetc ();
 		token->lineNumber   = getSourceLineNumber ();
-		if (useFile())
-			token->filePosition = getInputFilePosition ();
-		else
-			token->bufferPosition = getInputBufferPosition ();
-		}
+		token->filePosition = getInputFilePosition ();
+	}
 	while (c == '\t'  ||  c == ' ' ||  c == '\n');
 
 	switch (c)
@@ -384,10 +378,7 @@ getNextChar:
 				  token->type = TOKEN_STRING;
 				  parseString (token->string, c);
 				  token->lineNumber = getSourceLineNumber ();
-				  if (useFile())
-					token->filePosition = getInputFilePosition ();
-				  else
-					token->bufferPosition = getInputBufferPosition ();
+				  token->filePosition = getInputFilePosition ();
 				  break;
 
 		case '\\':
@@ -396,10 +387,7 @@ getNextChar:
 					  fileUngetc (c);
 				  token->type = TOKEN_CHARACTER;
 				  token->lineNumber = getSourceLineNumber ();
-				  if (useFile())
-					token->filePosition = getInputFilePosition ();
-				  else
-					token->bufferPosition = getInputBufferPosition ();
+				  token->filePosition = getInputFilePosition ();
 				  break;
 
 		case '/':
@@ -442,10 +430,7 @@ getNextChar:
 				  {
 					  parseIdentifier (token->string, c);
 					  token->lineNumber = getSourceLineNumber ();
-					  if (useFile())
-						token->filePosition = getInputFilePosition ();
-					  else
-						token->bufferPosition = getInputBufferPosition ();
+					  token->filePosition = getInputFilePosition ();
 					  token->keyword = analyzeToken (token->string);
 					  if (isKeyword (token, KEYWORD_NONE))
 						  token->type = TOKEN_IDENTIFIER;
@@ -460,10 +445,7 @@ static void copyToken (tokenInfo *const dest, tokenInfo *const src)
 {
 	dest->nestLevel = src->nestLevel;
 	dest->lineNumber = src->lineNumber;
-    if (useFile())
-		dest->filePosition = src->filePosition;
-    else
-		dest->bufferPosition = src->bufferPosition;
+	dest->filePosition = src->filePosition;
 	dest->type = src->type;
 	dest->keyword = src->keyword;
 	vStringCopy(dest->string, src->string);
diff --git a/tagmanager/lregex.c b/tagmanager/lregex.c
index db97c31..bc79102 100644
--- a/tagmanager/lregex.c
+++ b/tagmanager/lregex.c
@@ -20,6 +20,7 @@
 
 #include <string.h>
 #include <glib.h>
+#include <mio/mio.h>
 
 #ifdef HAVE_REGCOMP
 # include <ctype.h>
@@ -410,15 +411,15 @@ static void processLanguageRegex (const langType language,
 	else
 	{
 		const char* regexfile = parameter + 1;
-		FILE* const fp = fopen (regexfile, "r");
-		if (fp == NULL)
+		MIO* const mio = mio_new_file (regexfile, "r");
+		if (mio == NULL)
 			printf ("regex: %s\n", regexfile);
 		else
 		{
 			vString* const regex = vStringNew ();
-			while (readLine (regex, fp))
+			while (readLine (regex, mio))
 				addLanguageRegex (language, vStringValue (regex));
-			fclose (fp);
+			mio_free (mio);
 			vStringDelete (regex);
 		}
 	}
diff --git a/tagmanager/parse.c b/tagmanager/parse.c
index a9c23ef..a6312ac 100644
--- a/tagmanager/parse.c
+++ b/tagmanager/parse.c
@@ -15,6 +15,7 @@
 #include "general.h"	/* must always come first */
 
 #include <string.h>
+#include <mio/mio.h>
 
 
 #include "entry.h"
@@ -613,16 +614,16 @@ static boolean createTagsWithFallback (const char *const fileName,
 				       const langType language)
 {
     const unsigned long numTags	= TagFile.numTags.added;
-    fpos_t tagFilePosition;
+    MIOPos tagFilePosition;
     unsigned int passCount = 0;
     boolean tagFileResized = FALSE;
 
-    fgetpos (TagFile.fp, &tagFilePosition);
+    mio_getpos (TagFile.mio, &tagFilePosition);
     while (createTagsForFile (fileName, language, ++passCount))
     {
 	/*  Restore prior state of tag file.
 	 */
-	fsetpos (TagFile.fp, &tagFilePosition);
+	mio_setpos (TagFile.mio, &tagFilePosition);
 	TagFile.numTags.added = numTags;
 	tagFileResized = TRUE;
     }
diff --git a/tagmanager/read.c b/tagmanager/read.c
index fbd0616..422e8da 100644
--- a/tagmanager/read.c
+++ b/tagmanager/read.c
@@ -28,12 +28,19 @@
 *   DATA DEFINITIONS
 */
 inputFile File;			/* globally read through macros */
-static fpos_t StartOfLine;	/* holds deferred position of start of line */
-static int bufferStartOfLine;   /* the same as StartOfLine but for buffer */
+static MIOPos StartOfLine;	/* holds deferred position of start of line */
 
 
-static int readNextChar (void);
-static int pushBackChar (int c);
+
+/* Read a character choosing automatically between file or buffer, depending
+ * on which mode we are.
+ */
+#define readNextChar() (mio_getc (File.mio))
+
+/* Replaces ungetc() for file. In case of buffer we'll perform the same action:
+ * fpBufferPosition-- and write of the param char into the buf.
+ */
+#define pushBackChar(c) (mio_ungetc (File.mio, c))
 
 /*
 *   FUNCTION DEFINITIONS
@@ -253,22 +260,22 @@ extern boolean fileOpen (const char *const fileName, const langType language)
 
     /*	If another file was already open, then close it.
      */
-    if (File.fp != NULL)
+    if (File.mio != NULL)
     {
-	fclose (File.fp);		/* close any open source file */
-	File.fp = NULL;
+	mio_free (File.mio);		/* close any open source file */
+	File.mio = NULL;
     }
 
-    File.fp = g_fopen (fileName, openMode);
-    if (File.fp == NULL)
+    File.mio = mio_new_file_full (fileName, openMode, g_fopen, fclose);
+    if (File.mio == NULL)
 	error (WARNING | PERROR, "cannot open \"%s\"", fileName);
     else
     {
 	opened = TRUE;
 
 	setInputFileName (fileName);
-	fgetpos (File.fp, &StartOfLine);
-	fgetpos (File.fp, &File.filePosition);
+	mio_getpos (File.mio, &StartOfLine);
+	mio_getpos (File.mio, &File.filePosition);
 	File.currentLine  = NULL;
 	File.language     = language;
 	File.lineNumber   = 0L;
@@ -297,19 +304,13 @@ extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
 {
     boolean opened = FALSE;
 	
-    /*	Check whether a file of a buffer were already open, then close them.
+    /* Check whether a file of a buffer were already open, then close them.
      */
-    if (File.fp != NULL) {
-	fclose (File.fp);		/* close any open source file */
-	File.fp = NULL;
+    if (File.mio != NULL) {
+	mio_free (File.mio);		/* close any open source file */
+	File.mio = NULL;
     }
 
-    if (File.fpBuffer != NULL) {
-	error(PERROR, "An unallocated buffer was found. Please check you called \
-	correctly bufferClose ()\n");
-	File.fpBuffer = NULL;
-    }
-    
     /* check if we got a good buffer */
     if (buffer == NULL || buffer_size == 0) {
 	opened = FALSE;
@@ -318,11 +319,10 @@ extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
 	
     opened = TRUE;
 	    
-    File.fpBuffer = buffer;		
+    File.mio = mio_new_memory (buffer, buffer_size, NULL, NULL);
     setInputFileName (fileName);
-    bufferStartOfLine = 0;
-    File.fpBufferPosition = 0;
-    File.fpBufferSize = buffer_size;
+    mio_getpos (File.mio, &StartOfLine);
+    mio_getpos (File.mio, &File.filePosition);
     File.currentLine  = NULL;
     File.language     = language;
     File.lineNumber   = 0L;
@@ -339,12 +339,12 @@ extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
 	    getLanguageName (language),
 	    File.source.isHeader ? "include " : "");
 
-    return opened;	
+    return opened;
 }
 
 extern void fileClose (void)
 {
-    if (File.fp != NULL)
+    if (File.mio != NULL)
     {
 	/*  The line count of the file is 1 too big, since it is one-based
 	 *  and is incremented upon each newline.
@@ -353,16 +353,8 @@ extern void fileClose (void)
 	    addTotals (0, File.lineNumber - 1L,
 		      getFileSize (vStringValue (File.name)));
 
-	fclose (File.fp);
-	File.fp = NULL;
-    }
-}
-
-/* user should take care of freeing the buffer */
-extern void bufferClose (void)
-{
-    if (File.fpBuffer != NULL) {
-	File.fpBuffer = NULL;
+	mio_free (File.mio);
+	File.mio = NULL;
     }
 }
 
@@ -403,11 +395,7 @@ readnext:
 		goto readnext;
 	    else
 	    {
-		/* FIXME: find out a better way to do this check */
-		if (File.fp != NULL)
-		    fsetpos (File.fp, &StartOfLine);
-		else
-		    File.fpBufferPosition = bufferStartOfLine;
+		mio_setpos (File.mio, &StartOfLine);
 
 		c = readNextChar ();
 	    }
@@ -419,10 +407,7 @@ readnext:
     else if (c == NEWLINE)
     {
 	File.newLine = TRUE;
-	if (File.fp != NULL)		/* we have a file */
-	    fgetpos (File.fp, &StartOfLine);
-	else						/* it's a buffer */
-	    bufferStartOfLine = File.fpBufferPosition;
+	mio_getpos (File.mio, &StartOfLine);
     }
     else if (c == CRETURN)
     {
@@ -437,10 +422,7 @@ readnext:
 
 	c = NEWLINE;				/* convert CR into newline */
 	File.newLine = TRUE;
-	if (File.fp != NULL)
-	    fgetpos (File.fp, &StartOfLine);
-	else
-	    bufferStartOfLine = File.fpBufferPosition;
+	mio_getpos (File.mio, &StartOfLine);
     }
     DebugStatement ( debugPutc (DEBUG_RAW, c); )
     return c;
@@ -535,75 +517,17 @@ extern const unsigned char *fileReadLine (void)
     return result;
 }
 
-/* Read a character choosing automatically between file or buffer, depending
- * on which mode we are.
- */
-static int readNextChar(void) 
-{
-    if (File.fp != NULL) {
-	return getc(File.fp);
-    }
-    else {
-	int c;
-	if (File.fpBufferPosition >= File.fpBufferSize)
-	    return EOF;
-
-	c = File.fpBuffer[File.fpBufferPosition];
-	File.fpBufferPosition++;
-	
-	return c;
-    }
-}
-
-/* Replaces ungetc() for file. In case of buffer we'll perform the same action:
- * fpBufferPosition-- and write of the param char into the buf.
- */
-static int pushBackChar (int c) 
-{
-    if (File.fp != NULL) {
-	return ungetc (c, File.fp);
-    }
-    else {
-	File.fpBufferPosition--;
-	if (File.fpBufferPosition < 0)
-	    return EOF;
-	File.fpBuffer[File.fpBufferPosition] = c;
-	return File.fpBuffer[File.fpBufferPosition];
-    }
-}
-
-
-/* replacement for fsetpos, applied to a buffer */
-extern void setBufPos (int new_position) 
-{
-    File.fpBufferPosition = new_position;
-}
-
-/* replacement for fgetpos, applied to a buffer */
-extern int getBufPos (void) 
-{
-    return File.fpBufferPosition;
-}
-
-extern boolean useFile (void)
-{
-    if (File.fp != NULL)
-	return TRUE;
-    else
-	return FALSE;
-}
 
 /*
  *   Source file line reading with automatic buffer sizing
- *   Does not perform file/buffer checks. Only file is supported.
  */
-extern char *readLine (vString *const vLine, FILE *const fp)
+extern char *readLine (vString *const vLine, MIO *const mio)
 {
     char *result = NULL;
 
     vStringClear (vLine);
-    if (fp == NULL)		/* to free memory allocated to buffer */
-	error (FATAL, "NULL file pointer");
+    if (mio == NULL)		/* to free memory allocated to buffer */
+	error (FATAL, "NULL MIO pointer");
     else
     {
 	boolean reReadLine;
@@ -616,15 +540,15 @@ extern char *readLine (vString *const vLine, FILE *const fp)
 	do
 	{
 	    char *const pLastChar = vStringValue (vLine) + vStringSize (vLine) -2;
-	    fpos_t startOfLine;
+	    MIOPos startOfLine;
 
-	    fgetpos (fp, &startOfLine);
+	    mio_getpos (mio, &startOfLine);
 	    reReadLine = FALSE;
 	    *pLastChar = '\0';
-	    result = fgets (vStringValue (vLine), (int) vStringSize (vLine), fp);
+	    result = mio_gets (mio, vStringValue (vLine), (int) vStringSize (vLine));
 	    if (result == NULL)
 	    {
-		if (! feof (fp))
+		if (! mio_eof (mio))
 		    error (FATAL | PERROR, "Failure on attempt to read file");
 	    }
 	    else if (*pLastChar != '\0'  &&
@@ -633,7 +557,7 @@ extern char *readLine (vString *const vLine, FILE *const fp)
 		/*  buffer overflow */
 		reReadLine = vStringAutoResize (vLine);
 		if (reReadLine)
-		    fsetpos (fp, &startOfLine);
+		    mio_setpos (mio, &startOfLine);
 		else
 		    error (FATAL | PERROR, "input line too big; out of memory");
 	    }
@@ -660,20 +584,20 @@ extern char *readLine (vString *const vLine, FILE *const fp)
 /*  Places into the line buffer the contents of the line referenced by
  *  "location".
  */
-extern char *readSourceLine (vString *const vLine, fpos_t location,
+extern char *readSourceLine (vString *const vLine, MIOPos location,
 			     long *const pSeekValue)
 {
-    fpos_t orignalPosition;
+    MIOPos orignalPosition;
     char *result;
 
-    fgetpos (File.fp, &orignalPosition);
-    fsetpos (File.fp, &location);
+    mio_getpos (File.mio, &orignalPosition);
+    mio_setpos (File.mio, &location);
     if (pSeekValue != NULL)
-	*pSeekValue = ftell (File.fp);
-    result = readLine (vLine, File.fp);
+	*pSeekValue = mio_tell (File.mio);
+    result = readLine (vLine, File.mio);
     if (result == NULL)
 	error (FATAL, "Unexpected end of file: %s", vStringValue (File.name));
-    fsetpos (File.fp, &orignalPosition);
+    mio_setpos (File.mio, &orignalPosition);
 
     return result;
 }
diff --git a/tagmanager/read.h b/tagmanager/read.h
index 30fd424..0542712 100644
--- a/tagmanager/read.h
+++ b/tagmanager/read.h
@@ -23,6 +23,7 @@
 
 #include <stdio.h>
 #include <ctype.h>
+#include <mio/mio.h>
 
 #include "parse.h"
 #include "vstring.h"
@@ -33,7 +34,6 @@
 #define getInputLineNumber()	File.lineNumber
 #define getInputFileName()	vStringValue (File.source.name)
 #define getInputFilePosition()	File.filePosition
-#define getInputBufferPosition()	File.fpBufferPosition
 #define getSourceFileName()	vStringValue (File.source.name)
 #define getSourceFileTagPath()	File.source.tagPath
 #define getSourceLanguage()	File.source.language
@@ -73,13 +73,9 @@ typedef struct sInputFile {
     vString	*path;		/* path of input file (if any) */
     vString	*line;		/* last line read from file */
     const unsigned char* currentLine;	/* current line being worked on */
-    FILE	*fp;		/* stream used for reading the file */
-    unsigned char* fpBuffer;	/* buffer which contains the text to be parsed.
-				   This is optional to the use of a file-descriptor */
-    int fpBufferSize;		/* size of the fpBuffer */
-    int fpBufferPosition;	/* pointer to the current position in buffer */
+    MIO		*mio;		/* stream used for reading the file */
     unsigned long lineNumber;	/* line number in the input file */
-    fpos_t	filePosition;	/* file position of current line */
+    MIOPos	filePosition;	/* file position of current line */
     int		ungetch;	/* a single character that was ungotten */
     boolean	eof;		/* have we reached the end of file? */
     boolean	newLine;	/* will the next character begin a new line? */
@@ -106,11 +102,6 @@ extern CONST_FILE inputFile File;
 /*
 *   FUNCTION PROTOTYPES
 */
-#ifdef NEED_PROTO_FGETPOS
-extern int fgetpos  (FILE *stream, fpos_t *pos);
-extern int fsetpos  (FILE *stream, const fpos_t *pos);
-#endif
-
 extern void freeSourceFileResources (void);
 extern boolean fileOpen (const char *const fileName, const langType language);
 extern boolean fileEOF (void);
@@ -118,15 +109,11 @@ extern void fileClose (void);
 extern int fileGetc (void);
 extern void fileUngetc (int c);
 extern const unsigned char *fileReadLine (void);
-extern char *readLine (vString *const vLine, FILE *const fp);
-extern char *readSourceLine (vString *const vLine, fpos_t location, long *const pSeekValue);
-
+extern char *readLine (vString *const vLine, MIO *const mio);
+extern char *readSourceLine (vString *const vLine, MIOPos location, long *const pSeekValue);
 extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
 			   const char *const fileName, const langType language );
-extern void bufferClose (void);
-extern void setBufPos (int new_position);
-extern int getBufPos (void);
-extern boolean useFile (void);
+#define bufferClose fileClose
 
 #endif	/* _READ_H */
 
diff --git a/tagmanager/sort.c b/tagmanager/sort.c
index 6f43577..230d6bd 100644
--- a/tagmanager/sort.c
+++ b/tagmanager/sort.c
@@ -105,11 +105,11 @@ extern void externalSortTags (const boolean toStdout)
  *  so have lots of memory if you have large tag files.
  */
 
-static void failedSort (FILE *const fp, const char* msg)
+static void failedSort (MIO *const mio, const char* msg)
 {
     const char* const cannotSort = "cannot sort tag file";
-    if (fp != NULL)
-	fclose (fp);
+    if (mio != NULL)
+	mio_free (mio);
     if (msg == NULL)
 	error (FATAL | PERROR, "%s", cannotSort);
     else
@@ -127,18 +127,18 @@ static int compareTags (const void *const one, const void *const two)
 static void writeSortedTags (char **const table, const size_t numTags,
 			     const boolean toStdout)
 {
-    FILE *fp;
+    MIO *mio;
     size_t i;
 
     /*	Write the sorted lines back into the tag file.
      */
     if (toStdout)
-	fp = stdout;
+	mio = mio_new_fp (stdout, NULL);
     else
     {
-	fp = g_fopen (tagFileName (), "w");
-	if (fp == NULL)
-	    failedSort (fp, NULL);
+	mio = mio_new_file_full (tagFileName (), "w", g_fopen, fclose);
+	if (mio == NULL)
+	    failedSort (mio, NULL);
     }
     for (i = 0 ; i < numTags ; ++i)
     {
@@ -146,19 +146,18 @@ static void writeSortedTags (char **const table, const size_t numTags,
 	 *  pattern) if this is not an xref file.
 	 */
 	if (i == 0  ||  Option.xref  ||  strcmp (table [i], table [i-1]) != 0)
-	    if (fputs (table [i], fp) == EOF)
-		failedSort (fp, NULL);
+	    if (mio_puts (mio, table [i]) == EOF)
+		failedSort (mio, NULL);
     }
     if (toStdout)
-	fflush (fp);
-    else
-	fclose (fp);
+	fflush (mio_file_get_fp (mio));
+    mio_free (mio);
 }
 
 extern void internalSortTags (const boolean toStdout)
 {
     vString *vLine = vStringNew ();
-    FILE *fp = NULL;
+    MIO *mio = NULL;
     const char *line;
     size_t i;
 
@@ -170,20 +169,20 @@ extern void internalSortTags (const boolean toStdout)
     DebugStatement ( size_t mallocSize = tableSize; )	/* cumulative total */
 
     if (table == NULL)
-	failedSort (fp, "out of memory");
+	failedSort (mio, "out of memory");
 
     /*	Open the tag file and place its lines into allocated buffers.
      */
-    fp = g_fopen (tagFileName (), "r");
-    if (fp == NULL)
-	failedSort (fp, NULL);
-    for (i = 0  ;  i < numTags  &&  ! feof (fp)  ;  )
+    mio = mio_new_file_full (tagFileName (), "r", g_fopen, fclose);
+    if (mio == NULL)
+	failedSort (mio, NULL);
+    for (i = 0  ;  i < numTags  &&  ! mio_eof (mio)  ;  )
     {
-	line = readLine (vLine, fp);
+	line = readLine (vLine, mio);
 	if (line == NULL)
 	{
-	    if (! feof (fp))
-		failedSort (fp, NULL);
+	    if (! mio_eof (mio))
+		failedSort (mio, NULL);
 	    break;
 	}
 	else if (*line == '\0'  ||  strcmp (line, "\n") == 0)
@@ -194,14 +193,14 @@ extern void internalSortTags (const boolean toStdout)
 
 	    table [i] = (char *) g_malloc (stringSize);
 	    if (table [i] == NULL)
-		failedSort (fp, "out of memory");
+		failedSort (mio, "out of memory");
 	    DebugStatement ( mallocSize += stringSize; )
 	    strcpy (table [i], line);
 	    ++i;
 	}
     }
     numTags = i;
-    fclose (fp);
+    mio_free (mio);
     vStringDelete (vLine);
 
     /*	Sort the lines.
diff --git a/tagmanager/sql.c b/tagmanager/sql.c
index 02733cc..31123aa 100644
--- a/tagmanager/sql.c
+++ b/tagmanager/sql.c
@@ -137,8 +137,7 @@ typedef struct sTokenInfo {
     vString *	string;
     vString *	scope;
     unsigned long lineNumber;
-    fpos_t filePosition;
-    int	bufferPosition;	/* buffer position of line containing name */
+    MIOPos filePosition;
 } tokenInfo;
 
 /*
@@ -392,10 +391,7 @@ static void makeConstTag (tokenInfo *const token, const sqlKind kind)
 	initTagEntry (&e, name);
 
 	e.lineNumber   = token->lineNumber;
-	if (useFile())
-	    e.filePosition	= token->filePosition;
-	else
-	    e.bufferPosition 	= token->bufferPosition;
+	e.filePosition = token->filePosition;
 	e.kindName     = SqlKinds [kind].name;
 	e.kind         = SqlKinds [kind].letter;
 
@@ -495,10 +491,7 @@ getNextChar:
 	    token->type = TOKEN_STRING;
 	    parseString (token->string, c);
             token->lineNumber = getSourceLineNumber ();
-	    if (useFile())
-		token->filePosition	= getInputFilePosition ();
-	    else
-		token->bufferPosition = getInputBufferPosition ();
+	    token->filePosition	= getInputFilePosition ();
 	    break;
 
 	case '-':
@@ -564,10 +557,7 @@ getNextChar:
 	    {
 		parseIdentifier (token->string, c);
 		token->lineNumber = getSourceLineNumber ();
-		if (useFile())
-		    token->filePosition	= getInputFilePosition ();
-		else
-		    token->bufferPosition = getInputBufferPosition ();
+		token->filePosition = getInputFilePosition ();
 		token->keyword = analyzeToken (token->string);
 		if (isKeyword (token, KEYWORD_rem))
 		{
diff --git a/tagmanager/strlist.c b/tagmanager/strlist.c
index aa42ef7..34a3338 100644
--- a/tagmanager/strlist.c
+++ b/tagmanager/strlist.c
@@ -92,20 +92,21 @@ extern stringList* stringListNewFromArgv (const char* const* const argv)
 extern stringList* stringListNewFromFile (const char* const fileName)
 {
 	stringList* result = NULL;
-	FILE* const fp = g_fopen (fileName, "r");
-	if (fp != NULL)
+	MIO* const mio = mio_new_file_full (fileName, "r", g_fopen, fclose);
+	if (mio != NULL)
 	{
 		result = stringListNew ();
-		while (! feof (fp))
+		while (! mio_eof (mio))
 		{
 			vString* const str = vStringNew ();
-			readLine (str, fp);
+			readLine (str, mio);
 			vStringStripTrailing (str);
 			if (vStringLength (str) > 0)
 				stringListAdd (result, str);
 			else
 				vStringDelete (str);
 		}
+		mio_free (mio);
 	}
 	return result;
 }
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..708f5dc 100644
--- a/tagmanager/tm_tag.c
+++ b/tagmanager/tm_tag.c
@@ -9,6 +9,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <glib-object.h>
 
 #include "general.h"
 #include "entry.h"
@@ -105,6 +106,17 @@ static int s_tag_types[] = {
 	tm_tag_other_t
 };
 
+GType tm_tag_get_type(void)
+{
+	static GType gtype = 0;
+	if (G_UNLIKELY (gtype == 0))
+	{
+		gtype = g_boxed_type_register_static("TMTag", (GBoxedCopyFunc)tm_tag_ref,
+											 (GBoxedFreeFunc)tm_tag_unref);
+	}
+	return gtype;
+}
+
 static int get_tag_type(const char *tag_name)
 {
 	unsigned int i;
@@ -129,6 +141,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 +237,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 +341,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 +451,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 +633,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));
diff --git a/wscript b/wscript
index a6dfa5e..2e3ed2c 100644
--- a/wscript
+++ b/wscript
@@ -171,6 +171,9 @@ def configure(conf):
     else:
         gtk_version = 'Unknown'
     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=False)
+    # MIO check
+    conf.check_cfg(package='mio', atleast_version='0.1', uselib_store='MIO',
+        mandatory=True, args='--cflags --libs')
 
     # Windows specials
     if is_win32:
@@ -309,7 +312,7 @@ def build(bld):
         target          = 'tagmanager',
         includes        = ['.', 'tagmanager/include/'],
         defines         = 'G_LOG_DOMAIN="Tagmanager"',
-        uselib          = 'GTK',
+        uselib          = ['GTK', 'MIO'],
         install_path    = None) # do not install this library
 
 
@@ -338,7 +341,7 @@ def build(bld):
         source          = geany_sources,
         includes        = ['.', 'scintilla/include/', 'tagmanager/include/'],
         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
-        uselib          = ['GTK', 'GIO', 'WIN32', 'SUNOS_SOCKET'],
+        uselib          = ['GTK', 'GIO', 'WIN32', 'SUNOS_SOCKET', 'MIO'],
         use             = ['scintilla', 'tagmanager'])
 
     # geanyfunctions.h
