[geany/geany] 8c77ac: Merge PR#356 from 'b4n/techee/tm'
Colomban Wendling
git-noreply at xxxxx
Sat Nov 8 18:37:20 UTC 2014
Branch: refs/heads/master
Author: Colomban Wendling <ban at herbesfolles.org>
Committer: Colomban Wendling <ban at herbesfolles.org>
Date: Sat, 08 Nov 2014 18:37:20 UTC
Commit: 8c77accfd090c794e8eb1366772f417596052eb1
https://github.com/geany/geany/commit/8c77accfd090c794e8eb1366772f417596052eb1
Log Message:
-----------
Merge PR#356 from 'b4n/techee/tm'
Huge TagManager improvements
Modified Paths:
--------------
doc/Doxyfile.in
doc/Makefile.am
plugins/geanyfunctions.h
src/dialogs.c
src/document.c
src/document.h
src/editor.c
src/highlighting.c
src/main.c
src/plugindata.h
src/plugins.c
src/sidebar.c
src/symbols.c
src/symbols.h
tagmanager/ctags/read.c
tagmanager/ctags/read.h
tagmanager/src/Makefile.am
tagmanager/src/makefile.win32
tagmanager/src/tm_file_entry.c
tagmanager/src/tm_file_entry.h
tagmanager/src/tm_source_file.c
tagmanager/src/tm_source_file.h
tagmanager/src/tm_tag.c
tagmanager/src/tm_tag.h
tagmanager/src/tm_tagmanager.h
tagmanager/src/tm_work_object.c
tagmanager/src/tm_work_object.h
tagmanager/src/tm_workspace.c
tagmanager/src/tm_workspace.h
tests/ctags/debian_432872.f90.tags
tests/ctags/keyword_explicit.cs.tags
tests/ctags/keyword_implicit.cs.tags
tests/ctags/keyword_names.f90.tags
tests/ctags/keyword_struct.cs.tags
wscript
Modified: doc/Doxyfile.in
2 lines changed, 0 insertions(+), 2 deletions(-)
===================================================================
@@ -778,8 +778,6 @@ INPUT = @top_srcdir@/src/ \
@top_srcdir@/plugins/geanyfunctions.h \
@top_srcdir@/tagmanager/src/tm_source_file.c \
@top_srcdir@/tagmanager/src/tm_source_file.h \
- @top_srcdir@/tagmanager/src/tm_work_object.c \
- @top_srcdir@/tagmanager/src/tm_work_object.h \
@top_srcdir@/tagmanager/src/tm_workspace.c \
@top_srcdir@/tagmanager/src/tm_workspace.h
Modified: doc/Makefile.am
1 lines changed, 0 insertions(+), 1 deletions(-)
===================================================================
@@ -98,7 +98,6 @@ doxygen_sources = \
$(top_srcdir)/plugins/geanyplugin.h \
$(top_srcdir)/plugins/geanyfunctions.h \
$(top_srcdir)/tagmanager/src/tm_source_file.[ch] \
- $(top_srcdir)/tagmanager/src/tm_work_object.[ch] \
$(top_srcdir)/tagmanager/src/tm_workspace.[ch]
Doxyfile.stamp: Doxyfile $(doxygen_sources)
Modified: plugins/geanyfunctions.h
18 lines changed, 10 insertions(+), 8 deletions(-)
===================================================================
@@ -346,14 +346,16 @@
geany_functions->p_tm->tm_get_real_path
#define tm_source_file_new \
geany_functions->p_tm->tm_source_file_new
-#define tm_workspace_add_object \
- geany_functions->p_tm->tm_workspace_add_object
-#define tm_source_file_update \
- geany_functions->p_tm->tm_source_file_update
-#define tm_work_object_free \
- geany_functions->p_tm->tm_work_object_free
-#define tm_workspace_remove_object \
- geany_functions->p_tm->tm_workspace_remove_object
+#define tm_source_file_free \
+ geany_functions->p_tm->tm_source_file_free
+#define tm_workspace_add_source_file \
+ geany_functions->p_tm->tm_workspace_add_source_file
+#define tm_workspace_remove_source_file \
+ geany_functions->p_tm->tm_workspace_remove_source_file
+#define tm_workspace_add_source_files \
+ geany_functions->p_tm->tm_workspace_add_source_files
+#define tm_workspace_remove_source_files \
+ geany_functions->p_tm->tm_workspace_remove_source_files
#define search_show_find_in_files_dialog \
geany_functions->p_search->search_show_find_in_files_dialog
#define highlighting_get_style \
Modified: src/dialogs.c
10 lines changed, 7 insertions(+), 3 deletions(-)
===================================================================
@@ -501,9 +501,13 @@ static gboolean handle_save_as(const gchar *utf8_filename, gboolean rename_file)
{
document_rename_file(doc, utf8_filename);
}
- /* create a new tm_source_file object otherwise tagmanager won't work correctly */
- tm_workspace_remove_object(doc->tm_file, TRUE, TRUE);
- doc->tm_file = NULL;
+ if (doc->tm_file)
+ {
+ /* create a new tm_source_file object otherwise tagmanager won't work correctly */
+ tm_workspace_remove_source_file(doc->tm_file);
+ tm_source_file_free(doc->tm_file);
+ doc->tm_file = NULL;
+ }
}
success = document_save_file_as(doc, utf8_filename);
Modified: src/document.c
40 lines changed, 16 insertions(+), 24 deletions(-)
===================================================================
@@ -140,7 +140,7 @@ static GtkWidget* document_show_message(GeanyDocument *doc, GtkMessageType msgty
* string returned by @c tm_get_real_path().
*
* @return The matching document, or @c NULL.
- * @note This is only really useful when passing a @c TMWorkObject::file_name.
+ * @note This is only really useful when passing a @c TMSourceFile::file_name.
* @see GeanyDocument::real_path.
* @see document_find_by_filename().
*
@@ -714,7 +714,11 @@ static gboolean remove_page(guint page_num)
g_free(doc->priv->saved_encoding.encoding);
g_free(doc->file_name);
g_free(doc->real_path);
- tm_workspace_remove_object(doc->tm_file, TRUE, !main_status.quitting);
+ if (doc->tm_file)
+ {
+ tm_workspace_remove_source_file(doc->tm_file);
+ tm_source_file_free(doc->tm_file);
+ }
if (doc->priv->tag_tree)
gtk_widget_destroy(doc->priv->tag_tree);
@@ -2483,17 +2487,14 @@ void document_update_tags(GeanyDocument *doc)
/* lookup the name rather than using filetype name to support custom filetypes */
name = tm_source_file_get_lang_name(doc->file_type->lang);
- doc->tm_file = tm_source_file_new(locale_filename, FALSE, name);
+ doc->tm_file = tm_source_file_new(locale_filename, name);
g_free(locale_filename);
- if (doc->tm_file && !tm_workspace_add_object(doc->tm_file))
- {
- tm_work_object_free(doc->tm_file);
- doc->tm_file = NULL;
- }
+ if (doc->tm_file)
+ tm_workspace_add_source_file_noupdate(doc->tm_file);
}
- /* early out if there's no work object and we couldn't create one */
+ /* early out if there's no tm source file and we couldn't create one */
if (doc->tm_file == NULL)
{
/* We must call sidebar_update_tag_list() before returning,
@@ -2503,20 +2504,11 @@ void document_update_tags(GeanyDocument *doc)
return;
}
- len = sci_get_length(doc->editor->sci);
- /* tm_source_file_buffer_update() below don't support 0-length data,
- * so just empty the tags array and leave */
- if (len < 1)
- {
- tm_tags_array_free(doc->tm_file->tags_array, FALSE);
- sidebar_update_tag_list(doc, FALSE);
- return;
- }
-
/* Parse Scintilla's buffer directly using TagManager
* Note: this buffer *MUST NOT* be modified */
+ len = sci_get_length(doc->editor->sci);
buffer_ptr = (guchar *) scintilla_send_message(doc->editor->sci, SCI_GETCHARACTERPOINTER, 0, 0);
- tm_source_file_buffer_update(doc->tm_file, buffer_ptr, len, TRUE);
+ tm_workspace_update_source_file_buffer(doc->tm_file, buffer_ptr, len);
sidebar_update_tag_list(doc, TRUE);
document_highlight_tags(doc);
@@ -2555,13 +2547,12 @@ void document_highlight_tags(GeanyDocument *doc)
default:
return; /* early out if type keywords are not supported */
}
- if (!app->tm_workspace->work_object.tags_array)
+ if (!app->tm_workspace->tags_array)
return;
/* get any type keywords and tell scintilla about them
* this will cause the type keywords to be colourized in scintilla */
- keywords_str = symbols_find_tags_as_string(app->tm_workspace->work_object.tags_array,
- TM_GLOBAL_TYPE_MASK, doc->file_type->lang);
+ keywords_str = symbols_find_typenames_as_string(doc->file_type->lang, FALSE);
if (keywords_str)
{
keywords = g_string_free(keywords_str, FALSE);
@@ -2617,7 +2608,8 @@ static void document_load_config(GeanyDocument *doc, GeanyFiletype *type,
/* delete tm file object to force creation of a new one */
if (doc->tm_file != NULL)
{
- tm_workspace_remove_object(doc->tm_file, TRUE, TRUE);
+ tm_workspace_remove_source_file(doc->tm_file);
+ tm_source_file_free(doc->tm_file);
doc->tm_file = NULL;
}
/* load tags files before highlighting (some lexers highlight global typenames) */
Modified: src/document.h
4 lines changed, 2 insertions(+), 2 deletions(-)
===================================================================
@@ -93,8 +93,8 @@ typedef struct GeanyDocument
/** The filetype for this document, it's only a reference to one of the elements of the global
* filetypes array. */
GeanyFiletype *file_type;
- /** TMWorkObject object for this document, or @c NULL. */
- TMWorkObject *tm_file;
+ /** TMSourceFile object for this document, or @c NULL. */
+ TMSourceFile *tm_file;
/** Whether this document is read-only. */
gboolean readonly;
/** Whether this document has been changed since it was last saved. */
Modified: src/editor.c
32 lines changed, 16 insertions(+), 16 deletions(-)
===================================================================
@@ -639,7 +639,7 @@ static void show_tags_list(GeanyEditor *editor, const GPtrArray *tags, gsize roo
g_string_append(words, tag->name);
/* for now, tag types don't all follow C, so just look at arglist */
- if (!EMPTY(tag->atts.entry.arglist))
+ if (!EMPTY(tag->arglist))
g_string_append(words, "?2");
else
g_string_append(words, "?1");
@@ -732,10 +732,10 @@ static void autocomplete_scope(GeanyEditor *editor)
return;
tag = g_ptr_array_index(tags, 0);
- name = tag->atts.entry.var_type;
+ name = tag->var_type;
if (name)
{
- TMWorkObject *obj = editor->document->tm_file;
+ TMSourceFile *obj = editor->document->tm_file;
tags = tm_workspace_find_scope_members(obj ? obj->tags_array : NULL,
name, TRUE, FALSE);
@@ -1784,43 +1784,43 @@ static gint find_start_bracket(ScintillaObject *sci, gint pos)
static gboolean append_calltip(GString *str, const TMTag *tag, filetype_id ft_id)
{
- if (! tag->atts.entry.arglist)
+ if (! tag->arglist)
return FALSE;
if (ft_id != GEANY_FILETYPES_PASCAL)
{ /* usual calltips: "retval tagname (arglist)" */
- if (tag->atts.entry.var_type)
+ if (tag->var_type)
{
guint i;
- g_string_append(str, tag->atts.entry.var_type);
- for (i = 0; i < tag->atts.entry.pointerOrder; i++)
+ g_string_append(str, tag->var_type);
+ for (i = 0; i < tag->pointerOrder; i++)
{
g_string_append_c(str, '*');
}
g_string_append_c(str, ' ');
}
- if (tag->atts.entry.scope)
+ if (tag->scope)
{
const gchar *cosep = symbols_get_context_separator(ft_id);
- g_string_append(str, tag->atts.entry.scope);
+ g_string_append(str, tag->scope);
g_string_append(str, cosep);
}
g_string_append(str, tag->name);
g_string_append_c(str, ' ');
- g_string_append(str, tag->atts.entry.arglist);
+ g_string_append(str, tag->arglist);
}
else
{ /* special case Pascal calltips: "tagname (arglist) : retval" */
g_string_append(str, tag->name);
g_string_append_c(str, ' ');
- g_string_append(str, tag->atts.entry.arglist);
+ g_string_append(str, tag->arglist);
- if (!EMPTY(tag->atts.entry.var_type))
+ if (!EMPTY(tag->var_type))
{
g_string_append(str, " : ");
- g_string_append(str, tag->atts.entry.var_type);
+ g_string_append(str, tag->var_type);
}
}
@@ -1831,7 +1831,7 @@ static gboolean append_calltip(GString *str, const TMTag *tag, filetype_id ft_id
static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
{
const GPtrArray *tags;
- const gint arg_types = tm_tag_function_t | tm_tag_prototype_t |
+ const TMTagType arg_types = tm_tag_function_t | tm_tag_prototype_t |
tm_tag_method_t | tm_tag_macro_with_arg_t;
TMTagAttrType *attrs = NULL;
TMTag *tag;
@@ -1862,7 +1862,7 @@ static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
{
tag = TM_TAG(tags->pdata[i]);
- if (! tag->atts.entry.arglist)
+ if (! tag->arglist)
tags->pdata[i] = NULL;
}
tm_tags_prune((GPtrArray *) tags);
@@ -1873,7 +1873,7 @@ static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
TMTagAttrType sort_attr[] = {tm_tag_attr_name_t, tm_tag_attr_scope_t,
tm_tag_attr_arglist_t, 0};
- tm_tags_sort((GPtrArray *) tags, sort_attr, TRUE);
+ tm_tags_sort((GPtrArray *) tags, sort_attr, TRUE, FALSE);
}
/* if the current word has changed since last time, start with the first tag match */
Modified: src/highlighting.c
19 lines changed, 1 insertions(+), 18 deletions(-)
===================================================================
@@ -433,23 +433,6 @@ void highlighting_free_styles(void)
}
-static GString *get_global_typenames(gint lang)
-{
- GString *s = NULL;
-
- if (app->tm_workspace)
- {
- GPtrArray *tags_array = app->tm_workspace->global_tags;
-
- if (tags_array)
- {
- s = symbols_find_tags_as_string(tags_array, TM_GLOBAL_TYPE_MASK, lang);
- }
- }
- return s;
-}
-
-
static gchar*
get_keyfile_whitespace_chars(GKeyFile *config, GKeyFile *configh)
{
@@ -823,7 +806,7 @@ static void merge_type_keywords(ScintillaObject *sci, guint ft_id, guint keyword
const gchar *user_words = style_sets[ft_id].keywords[keyword_idx];
GString *s;
- s = get_global_typenames(filetypes[ft_id]->lang);
+ s = symbols_find_typenames_as_string(filetypes[ft_id]->lang, TRUE);
if (G_UNLIKELY(s == NULL))
s = g_string_sized_new(200);
else
Modified: src/main.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -1289,7 +1289,7 @@ static void do_main_quit(void)
filetypes_free_types();
log_finalize();
- tm_workspace_free(TM_WORK_OBJECT(app->tm_workspace));
+ tm_workspace_free();
g_free(app->configdir);
g_free(app->datadir);
g_free(app->docdir);
Modified: src/plugindata.h
16 lines changed, 8 insertions(+), 8 deletions(-)
===================================================================
@@ -58,7 +58,7 @@ G_BEGIN_DECLS
* @warning You should not test for values below 200 as previously
* @c GEANY_API_VERSION was defined as an enum value, not a macro.
*/
-#define GEANY_API_VERSION 220
+#define GEANY_API_VERSION 221
/* hack to have a different ABI when built with GTK3 because loading GTK2-linked plugins
* with GTK3-linked Geany leads to crash */
@@ -72,7 +72,7 @@ G_BEGIN_DECLS
* Changing this forces all plugins to be recompiled before Geany can load them. */
/* This should usually stay the same if fields are only appended, assuming only pointers to
* structs and not structs themselves are declared by plugins. */
-#define GEANY_ABI_VERSION (69 << GEANY_ABI_SHIFT)
+#define GEANY_ABI_VERSION (70 << GEANY_ABI_SHIFT)
/** Defines a function to check the plugin is safe to load.
@@ -599,12 +599,12 @@ SearchFuncs;
typedef struct TagManagerFuncs
{
gchar* (*tm_get_real_path) (const gchar *file_name);
- TMWorkObject* (*tm_source_file_new) (const char *file_name, gboolean update, const char *name);
- gboolean (*tm_workspace_add_object) (TMWorkObject *work_object);
- gboolean (*tm_source_file_update) (TMWorkObject *source_file, gboolean force,
- gboolean recurse, gboolean update_parent);
- void (*tm_work_object_free) (gpointer work_object);
- gboolean (*tm_workspace_remove_object) (TMWorkObject *w, gboolean do_free, gboolean update);
+ TMSourceFile* (*tm_source_file_new) (const char *file_name, const char *name);
+ void (*tm_source_file_free) (TMSourceFile *source_file);
+ void (*tm_workspace_add_source_file) (TMSourceFile *source_file);
+ void (*tm_workspace_remove_source_file) (TMSourceFile *source_file);
+ void (*tm_workspace_add_source_files) (GPtrArray *source_files);
+ void (*tm_workspace_remove_source_files) (GPtrArray *source_files);
}
TagManagerFuncs;
Modified: src/plugins.c
9 lines changed, 5 insertions(+), 4 deletions(-)
===================================================================
@@ -290,10 +290,11 @@ static KeybindingFuncs keybindings_funcs = {
static TagManagerFuncs tagmanager_funcs = {
&tm_get_real_path,
&tm_source_file_new,
- &tm_workspace_add_object,
- &tm_source_file_update,
- &tm_work_object_free,
- &tm_workspace_remove_object
+ &tm_source_file_free,
+ &tm_workspace_add_source_file,
+ &tm_workspace_remove_source_file,
+ &tm_workspace_add_source_files,
+ &tm_workspace_remove_source_files
};
static SearchFuncs search_funcs = {
Modified: src/sidebar.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -904,7 +904,7 @@ static gboolean taglist_go_to_selection(GtkTreeSelection *selection, guint keyva
if (! tag)
return FALSE;
- line = tag->atts.entry.line;
+ line = tag->line;
if (line > 0)
{
GeanyDocument *doc = document_get_current();
Modified: src/symbols.c
129 lines changed, 60 insertions(+), 69 deletions(-)
===================================================================
@@ -64,11 +64,6 @@
#include <stdlib.h>
-const guint TM_GLOBAL_TYPE_MASK =
- tm_tag_class_t | tm_tag_enum_t | tm_tag_interface_t |
- tm_tag_struct_t | tm_tag_typedef_t | tm_tag_union_t | tm_tag_namespace_t;
-
-
static gchar **html_entities = NULL;
typedef struct
@@ -248,7 +243,7 @@ static void html_tags_loaded(void)
}
-GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gint lang)
+GString *symbols_find_typenames_as_string(gint lang, gboolean global)
{
guint j;
TMTag *tag;
@@ -256,9 +251,10 @@ GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gin
GPtrArray *typedefs;
gint tag_lang;
- g_return_val_if_fail(tags_array != NULL, NULL);
-
- typedefs = tm_tags_extract(tags_array, tag_types);
+ if (global)
+ typedefs = tm_tags_extract(app->tm_workspace->global_tags, TM_GLOBAL_TYPE_MASK);
+ else
+ typedefs = app->tm_workspace->typename_array;
if ((typedefs) && (typedefs->len > 0))
{
@@ -266,9 +262,7 @@ GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gin
for (j = 0; j < typedefs->len; ++j)
{
tag = TM_TAG(typedefs->pdata[j]);
- /* tag->atts.file.lang contains (for some reason) the line of the tag if
- * tag->atts.entry.file is not NULL */
- tag_lang = (tag->atts.entry.file) ? tag->atts.entry.file->lang : tag->atts.file.lang;
+ tag_lang = tag->lang;
/* the check for tag_lang == lang is necessary to avoid wrong type colouring of
* e.g. PHP classes in C++ files
@@ -282,7 +276,7 @@ GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gin
}
}
}
- if (typedefs)
+ if (typedefs && global)
g_ptr_array_free(typedefs, TRUE);
return s;
}
@@ -333,25 +327,25 @@ GString *symbols_get_macro_list(gint lang)
gint tag_lang;
TMTag *tag;
- if (app->tm_workspace->work_objects == NULL)
+ if (app->tm_workspace->source_files == NULL)
return NULL;
ftags = g_ptr_array_sized_new(50);
words = g_string_sized_new(200);
- for (j = 0; j < app->tm_workspace->work_objects->len; j++)
+ for (j = 0; j < app->tm_workspace->source_files->len; j++)
{
GPtrArray *tags;
- tags = tm_tags_extract(TM_WORK_OBJECT(app->tm_workspace->work_objects->pdata[j])->tags_array,
+ tags = tm_tags_extract(TM_SOURCE_FILE(app->tm_workspace->source_files->pdata[j])->tags_array,
tm_tag_enum_t | tm_tag_variable_t | tm_tag_macro_t | tm_tag_macro_with_arg_t);
if (NULL != tags)
{
for (i = 0; ((i < tags->len) && (i < editor_prefs.autocompletion_max_entries)); ++i)
{
tag = TM_TAG(tags->pdata[i]);
- tag_lang = (tag->atts.entry.file) ?
- tag->atts.entry.file->lang : tag->atts.file.lang;
+ tag_lang = (tag->file) ?
+ tag->file->lang : tag->lang;
if (tag_lang == lang)
g_ptr_array_add(ftags, (gpointer) tags->pdata[i]);
@@ -367,7 +361,7 @@ GString *symbols_get_macro_list(gint lang)
return NULL;
}
- tm_tags_sort(ftags, NULL, FALSE);
+ tm_tags_sort(ftags, NULL, FALSE, FALSE);
for (j = 0; j < ftags->len; j++)
{
if (j > 0)
@@ -395,24 +389,21 @@ symbols_find_tm_tag(const GPtrArray *tags, const gchar *tag_name)
}
-static TMTag *find_work_object_tag(const TMWorkObject *workobj,
+static TMTag *find_source_file_tag(GPtrArray *tags_array,
const gchar *tag_name, guint type)
{
GPtrArray *tags;
TMTag *tmtag;
- if (G_LIKELY(workobj != NULL))
+ tags = tm_tags_extract(tags_array, type);
+ if (tags != NULL)
{
- tags = tm_tags_extract(workobj->tags_array, type);
- if (tags != NULL)
- {
- tmtag = symbols_find_tm_tag(tags, tag_name);
+ tmtag = symbols_find_tm_tag(tags, tag_name);
- g_ptr_array_free(tags, TRUE);
+ g_ptr_array_free(tags, TRUE);
- if (tmtag != NULL)
- return tmtag;
- }
+ if (tmtag != NULL)
+ return tmtag;
}
return NULL; /* not found */
}
@@ -421,19 +412,19 @@ static TMTag *find_work_object_tag(const TMWorkObject *workobj,
static TMTag *find_workspace_tag(const gchar *tag_name, guint type)
{
guint j;
- const GPtrArray *work_objects = NULL;
+ const GPtrArray *source_files = NULL;
if (app->tm_workspace != NULL)
- work_objects = app->tm_workspace->work_objects;
+ source_files = app->tm_workspace->source_files;
- if (work_objects != NULL)
+ if (source_files != NULL)
{
- for (j = 0; j < work_objects->len; j++)
+ for (j = 0; j < source_files->len; j++)
{
- TMWorkObject *workobj = TM_WORK_OBJECT(work_objects->pdata[j]);
+ TMSourceFile *srcfile = source_files->pdata[j];
TMTag *tmtag;
- tmtag = find_work_object_tag(workobj, tag_name, type);
+ tmtag = find_source_file_tag(srcfile->tags_array, tag_name, type);
if (tmtag != NULL)
return tmtag;
}
@@ -468,7 +459,7 @@ static gint compare_symbol(const TMTag *tag_a, const TMTag *tag_b)
ret = strcmp(tag_a->name, tag_b->name);
if (ret == 0)
{
- return tag_a->atts.entry.line - tag_b->atts.entry.line;
+ return tag_a->line - tag_b->line;
}
return ret;
}
@@ -484,21 +475,21 @@ static gint compare_symbol_lines(gconstpointer a, gconstpointer b)
if (a == NULL || b == NULL)
return 0;
- ret = tag_a->atts.entry.line - tag_b->atts.entry.line;
+ ret = tag_a->line - tag_b->line;
if (ret == 0)
{
- if (tag_a->atts.entry.scope == NULL)
- return -(tag_a->atts.entry.scope != tag_b->atts.entry.scope);
- if (tag_b->atts.entry.scope == NULL)
- return tag_a->atts.entry.scope != tag_b->atts.entry.scope;
+ if (tag_a->scope == NULL)
+ return -(tag_a->scope != tag_b->scope);
+ if (tag_b->scope == NULL)
+ return tag_a->scope != tag_b->scope;
else
- return strcmp(tag_a->atts.entry.scope, tag_b->atts.entry.scope);
+ return strcmp(tag_a->scope, tag_b->scope);
}
return ret;
}
-static GList *get_tag_list(GeanyDocument *doc, guint tag_types)
+static GList *get_tag_list(GeanyDocument *doc, TMTagType tag_types)
{
GList *tag_names = NULL;
TMTag *tag;
@@ -1037,7 +1028,7 @@ static void hide_empty_rows(GtkTreeStore *store)
static const gchar *get_symbol_name(GeanyDocument *doc, const TMTag *tag, gboolean found_parent)
{
gchar *utf8_name;
- const gchar *scope = tag->atts.entry.scope;
+ const gchar *scope = tag->scope;
static GString *buffer = NULL; /* buffer will be small so we can keep it for reuse */
gboolean doc_is_utf8 = FALSE;
@@ -1078,7 +1069,7 @@ static const gchar *get_symbol_name(GeanyDocument *doc, const TMTag *tag, gboole
if (! doc_is_utf8)
g_free(utf8_name);
- g_string_append_printf(buffer, " [%lu]", tag->atts.entry.line);
+ g_string_append_printf(buffer, " [%lu]", tag->line);
return buffer->str;
}
@@ -1108,7 +1099,7 @@ static gchar *get_symbol_tooltip(GeanyDocument *doc, const TMTag *tag)
/* find the last word in "foo::bar::blah", e.g. "blah" */
static const gchar *get_parent_name(const TMTag *tag, filetype_id ft_id)
{
- const gchar *scope = tag->atts.entry.scope;
+ const gchar *scope = tag->scope;
const gchar *separator = symbols_get_context_separator(ft_id);
const gchar *str, *ptr;
@@ -1226,9 +1217,9 @@ static gboolean tag_equal(gconstpointer v1, gconstpointer v2)
const TMTag *t2 = v2;
return (t1->type == t2->type && strcmp(t1->name, t2->name) == 0 &&
- utils_str_equal(t1->atts.entry.scope, t2->atts.entry.scope) &&
+ utils_str_equal(t1->scope, t2->scope) &&
/* include arglist in match to support e.g. C++ overloading */
- utils_str_equal(t1->atts.entry.arglist, t2->atts.entry.arglist));
+ utils_str_equal(t1->arglist, t2->arglist));
}
@@ -1242,15 +1233,15 @@ static guint tag_hash(gconstpointer v)
h = (h << 5) + h + tag->type;
for (p = tag->name; *p != '\0'; p++)
h = (h << 5) + h + *p;
- if (tag->atts.entry.scope)
+ if (tag->scope)
{
- for (p = tag->atts.entry.scope; *p != '\0'; p++)
+ for (p = tag->scope; *p != '\0'; p++)
h = (h << 5) + h + *p;
}
/* for e.g. C++ overloading */
- if (tag->atts.entry.arglist)
+ if (tag->arglist)
{
- for (p = tag->atts.entry.arglist; *p != '\0'; p++)
+ for (p = tag->arglist; *p != '\0'; p++)
h = (h << 5) + h + *p;
}
@@ -1348,7 +1339,7 @@ static GList *tags_table_lookup(GHashTable *table, TMTag *tag)
glong delta;
data = node->data;
-#define TAG_DELTA(a, b) ABS((glong) TM_TAG(a)->atts.entry.line - (glong) TM_TAG(b)->atts.entry.line)
+#define TAG_DELTA(a, b) ABS((glong) TM_TAG(a)->line - (glong) TM_TAG(b)->line)
delta = TAG_DELTA(((GList *) node->data)->data, tag);
for (node = node->next; node; node = node->next)
@@ -1542,7 +1533,7 @@ static void update_tree_tags(GeanyDocument *doc, GList **tags)
gtk_tree_model_get(GTK_TREE_MODEL(store), node->data,
SYMBOLS_COLUMN_TAG, &parent_tag, -1);
- d = tag->atts.entry.line - parent_tag->atts.entry.line;
+ d = tag->line - parent_tag->line;
if (! parent_search || (d >= 0 && d < delta))
{
delta = d;
@@ -1616,7 +1607,7 @@ static gboolean tag_has_missing_parent(const TMTag *tag, GtkTreeStore *store,
GtkTreeIter *iter)
{
/* if the tag has a parent tag, it should be at depth >= 2 */
- return !EMPTY(tag->atts.entry.scope) &&
+ return !EMPTY(tag->scope) &&
gtk_tree_store_iter_depth(store, iter) == 1;
}
@@ -1666,7 +1657,7 @@ static gint tree_sort_func(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b,
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)))
+ utils_str_equal(tag_a->scope, tag_b->scope)))
cmp = compare_symbol_lines(tag_a, tag_b);
}
}
@@ -1931,8 +1922,8 @@ static void load_user_tags(filetype_id ft_id)
static gboolean goto_tag(const gchar *name, gboolean definition)
{
- const gint forward_types = tm_tag_prototype_t | tm_tag_externvar_t;
- guint type;
+ const TMTagType forward_types = tm_tag_prototype_t | tm_tag_externvar_t;
+ TMTagType type;
TMTag *tmtag = NULL;
GeanyDocument *old_doc = document_get_current();
@@ -1941,7 +1932,7 @@ static gboolean goto_tag(const gchar *name, gboolean definition)
/* first look in the current document */
if (old_doc != NULL && old_doc->tm_file)
- tmtag = find_work_object_tag(old_doc->tm_file, name, type);
+ tmtag = find_source_file_tag(old_doc->tm_file->tags_array, name, type);
/* if not found, look in the workspace */
if (tmtag == NULL)
@@ -1950,13 +1941,13 @@ static gboolean goto_tag(const gchar *name, gboolean definition)
if (tmtag != NULL)
{
GeanyDocument *new_doc = document_find_by_real_path(
- tmtag->atts.entry.file->work_object.file_name);
+ tmtag->file->file_name);
if (new_doc)
{
/* If we are already on the tag line, swap definition/declaration */
if (new_doc == old_doc &&
- tmtag->atts.entry.line == (guint)sci_get_current_line(old_doc->editor->sci) + 1)
+ tmtag->line == (guint)sci_get_current_line(old_doc->editor->sci) + 1)
{
if (goto_tag(name, !definition))
return TRUE;
@@ -1965,10 +1956,10 @@ static gboolean goto_tag(const gchar *name, gboolean definition)
else
{
/* not found in opened document, should open */
- new_doc = document_open_file(tmtag->atts.entry.file->work_object.file_name, FALSE, NULL, NULL);
+ new_doc = document_open_file(tmtag->file->file_name, FALSE, NULL, NULL);
}
- if (navqueue_goto_line(old_doc, new_doc, tmtag->atts.entry.line))
+ if (navqueue_goto_line(old_doc, new_doc, tmtag->line))
return TRUE;
}
return FALSE;
@@ -2122,7 +2113,7 @@ static gint get_fold_header_after(ScintillaObject *sci, gint line)
}
-static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_types)
+static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, TMTagType tag_types)
{
gint line;
gint parent;
@@ -2137,7 +2128,7 @@ static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_
if (tag)
{
- gint tag_line = tag->atts.entry.line - 1;
+ gint tag_line = tag->line - 1;
gint last_child = line + 1;
/* if it may be a false positive because we're inside a fold level not inside anything
@@ -2152,8 +2143,8 @@ static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_
if (line <= last_child)
{
- if (tag->atts.entry.scope)
- *tagname = g_strconcat(tag->atts.entry.scope,
+ if (tag->scope)
+ *tagname = g_strconcat(tag->scope,
symbols_get_context_separator(doc->file_type->id), tag->name, NULL);
else
*tagname = g_strdup(tag->name);
@@ -2199,7 +2190,7 @@ static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, guint tag_
}
-static gint get_current_tag_name_cached(GeanyDocument *doc, const gchar **tagname, guint tag_types)
+static gint get_current_tag_name_cached(GeanyDocument *doc, const gchar **tagname, TMTagType tag_types)
{
static gint tag_line = -1;
static gchar *cur_tag = NULL;
@@ -2245,7 +2236,7 @@ gint symbols_get_current_function(GeanyDocument *doc, const gchar **tagname)
/* same as symbols_get_current_function() but finds class, namespaces and more */
gint symbols_get_current_scope(GeanyDocument *doc, const gchar **tagname)
{
- guint tag_types = (tm_tag_function_t | tm_tag_method_t | tm_tag_class_t |
+ TMTagType tag_types = (tm_tag_function_t | tm_tag_method_t | tm_tag_class_t |
tm_tag_struct_t | tm_tag_enum_t | tm_tag_union_t);
/* Python parser reports imports as namespaces which confuses the scope detection */
Modified: src/symbols.h
4 lines changed, 1 insertions(+), 3 deletions(-)
===================================================================
@@ -34,8 +34,6 @@ const gchar *symbols_get_context_separator(gint ft_id);
#ifdef GEANY_PRIVATE
-extern const guint TM_GLOBAL_TYPE_MASK;
-
enum
{
SYMBOLS_SORT_BY_NAME,
@@ -52,7 +50,7 @@ void symbols_reload_config_files(void);
void symbols_global_tags_loaded(guint file_type_idx);
-GString *symbols_find_tags_as_string(GPtrArray *tags_array, guint tag_types, gint lang);
+GString *symbols_find_typenames_as_string(gint lang, gboolean global);
const GList *symbols_get_tag_list(GeanyDocument *doc, guint tag_types);
Modified: tagmanager/ctags/read.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -298,7 +298,7 @@ extern boolean fileOpen (const char *const fileName, const langType language)
* This func is NOT THREAD SAFE.
* The user should not tamper with the buffer while this func is executing.
*/
-extern boolean bufferOpen (unsigned char *buffer, int buffer_size,
+extern boolean bufferOpen (unsigned char *buffer, size_t buffer_size,
const char *const fileName, const langType language )
{
boolean opened = FALSE;
Modified: tagmanager/ctags/read.h
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -106,7 +106,7 @@ extern void fileUngetc (int c);
extern const unsigned char *fileReadLine (void);
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,
+extern boolean bufferOpen (unsigned char *buffer, size_t buffer_size,
const char *const fileName, const langType language );
#define bufferClose fileClose
Modified: tagmanager/src/Makefile.am
5 lines changed, 0 insertions(+), 5 deletions(-)
===================================================================
@@ -17,20 +17,15 @@ tagmanager_include_HEADERS = \
tm_source_file.h \
tm_tag.h \
tm_tagmanager.h \
- tm_work_object.h \
tm_workspace.h
libtagmanager_a_SOURCES =\
tm_tagmanager.h \
tm_parser.h \
- tm_file_entry.h \
- tm_file_entry.c \
tm_source_file.h \
tm_source_file.c \
tm_tag.h \
tm_tag.c \
- tm_work_object.c \
- tm_work_object.h \
tm_workspace.h \
tm_workspace.c
Modified: tagmanager/src/makefile.win32
3 lines changed, 1 insertions(+), 2 deletions(-)
===================================================================
@@ -44,8 +44,7 @@ all: $(COMPLIB)
clean:
-$(RM) deps.mak *.o $(COMPLIB)
-$(COMPLIB): tm_workspace.o tm_work_object.o tm_source_file.o tm_tag.o \
-tm_file_entry.o
+$(COMPLIB): tm_workspace.o tm_source_file.o tm_tag.o
$(AR) rc $@ $^
$(RANLIB) $@
Modified: tagmanager/src/tm_file_entry.c
282 lines changed, 0 insertions(+), 282 deletions(-)
===================================================================
@@ -1,282 +0,0 @@
-/*
-*
-* Copyright (c) 2001-2002, Biswapesh Chattopadhyay
-*
-* This source code is released for free distribution under the terms of the
-* GNU General Public License.
-*
-*/
-
-#include "general.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <dirent.h>
-#ifdef HAVE_FCNTL_H
-# include <fcntl.h>
-#endif
-#include <sys/types.h>
-#include <sys/stat.h>
-#ifdef HAVE_FNMATCH_H
-# include <fnmatch.h>
-#endif
-#include <glib/gstdio.h>
-
-#include "tm_work_object.h"
-#include "tm_file_entry.h"
-
-
-#define FILE_NEW(T) ((T) = g_slice_new0(TMFileEntry))
-#define FILE_FREE(T) g_slice_free(TMFileEntry, (T))
-
-
-void tm_file_entry_print(TMFileEntry *entry, gpointer UNUSED user_data
- , guint level)
-{
- guint i;
-
- g_return_if_fail(entry);
- for (i=0; i < level; ++i)
- fputc('\t', stderr);
- fprintf(stderr, "%s\n", entry->name);
-}
-
-gint tm_file_entry_compare(TMFileEntry *e1, TMFileEntry *e2)
-{
- g_return_val_if_fail(e1 && e2 && e1->name && e2->name, 0);
-#ifdef TM_DEBUG
- g_message("Comparing %s and %s", e1->name, e2->name);
-#endif
- return strcmp(e1->name, e2->name);
-}
-
-/* TTimo - modified to handle symlinks */
-static TMFileType tm_file_entry_type(const char *path)
-{
- struct stat s;
-
-#ifndef G_OS_WIN32
- if (0 != g_lstat(path, &s))
- return tm_file_unknown_t;
-#endif
- if (S_ISDIR(s.st_mode))
- return tm_file_dir_t;
-#ifndef G_OS_WIN32
- else if (S_ISLNK(s.st_mode))
- return tm_file_link_t;
-#endif
- else if (S_ISREG(s.st_mode))
- return tm_file_regular_t;
- else
- return tm_file_unknown_t;
-}
-
-static gboolean apply_filter(const char *name, GList *match, GList *unmatch
- , gboolean ignore_hidden)
-{
- GList *tmp;
- gboolean matched = (match == NULL);
- g_return_val_if_fail(name, FALSE);
- if (ignore_hidden && ('.' == name[0]))
- return FALSE;
- /* TTimo - ignore .svn directories */
- if (!strcmp(name, ".svn"))
- return FALSE;
- for (tmp = match; tmp; tmp = g_list_next(tmp))
- {
- if (0 == fnmatch((char *) tmp->data, name, 0))
- {
- matched = TRUE;
- break;
- }
- }
- if (!matched)
- return FALSE;
- for (tmp = unmatch; tmp; tmp = g_list_next(tmp))
- {
- if (0 == fnmatch((char *) tmp->data, name, 0))
- {
- return FALSE;
- }
- }
- return matched;
-}
-
-TMFileEntry *tm_file_entry_new(const char *path, TMFileEntry *parent
- , gboolean recurse, GList *file_match, GList *file_unmatch
- , GList *dir_match, GList *dir_unmatch, gboolean ignore_hidden_files
- , gboolean ignore_hidden_dirs)
-{
- TMFileEntry *entry;
- /* GList *tmp; */
- char *real_path;
- DIR *dir;
- struct dirent *dir_entry;
- TMFileEntry *new_entry;
- char *file_name;
- struct stat s;
- char *entries = NULL;
-
- g_return_val_if_fail (path != NULL, NULL);
-
- /* TTimo - don't follow symlinks */
- if (tm_file_entry_type(path) == tm_file_link_t)
- return NULL;
- real_path = tm_get_real_path(path);
- if (!real_path)
- return NULL;
- FILE_NEW(entry);
- entry->type = tm_file_entry_type(real_path);
- entry->parent = parent;
- entry->path = real_path;
- entry->name = strrchr(entry->path, '/');
- if (entry->name)
- ++ (entry->name);
- else
- entry->name = entry->path;
- switch(entry->type)
- {
- case tm_file_unknown_t:
- g_free(real_path);
- FILE_FREE(entry);
- return NULL;
- case tm_file_link_t:
- case tm_file_regular_t:
- if (parent && !apply_filter(entry->name, file_match, file_unmatch
- , ignore_hidden_files))
- {
- tm_file_entry_free(entry);
- return NULL;
- }
- break;
- case tm_file_dir_t:
- if (parent && !(recurse && apply_filter(entry->name, dir_match
- , dir_unmatch, ignore_hidden_dirs)))
- {
- tm_file_entry_free(entry);
- return NULL;
- }
- file_name = g_strdup_printf("%s/CVS/Entries", entry->path);
- if (0 == g_stat(file_name, &s))
- {
- if (S_ISREG(s.st_mode))
- {
- int fd;
- entries = g_new(char, s.st_size + 2);
- if (0 > (fd = open(file_name, O_RDONLY)))
- {
- g_free(entries);
- entries = NULL;
- }
- else
- {
- off_t n =0;
- off_t total_read = 1;
- while (0 < (n = read(fd, entries + total_read, s.st_size - total_read)))
- total_read += n;
- entries[s.st_size] = '\0';
- entries[0] = '\n';
- close(fd);
- entry->version = g_strdup("D");
- }
- }
- }
- g_free(file_name);
- if (NULL != (dir = opendir(entry->path)))
- {
- while (NULL != (dir_entry = readdir(dir)))
- {
- if ((0 == strcmp(dir_entry->d_name, "."))
- || (0 == strcmp(dir_entry->d_name, "..")))
- continue;
- file_name = g_strdup_printf("%s/%s", entry->path, dir_entry->d_name);
- new_entry = tm_file_entry_new(file_name, entry, recurse
- , file_match, file_unmatch, dir_match, dir_unmatch
- , ignore_hidden_files, ignore_hidden_dirs);
- g_free(file_name);
- if (new_entry)
- {
- if (entries)
- {
- char *str = g_strconcat("\n/", new_entry->name, "/", NULL);
- char *name_pos = strstr(entries, str);
- if (NULL != name_pos)
- {
- int len = strlen(str);
- char *version_pos = strchr(name_pos + len, '/');
- if (NULL != version_pos)
- {
- *version_pos = '\0';
- new_entry->version = g_strdup(name_pos + len);
- *version_pos = '/';
- }
- }
- g_free(str);
- }
- entry->children = g_slist_prepend(entry->children, new_entry);
- }
- }
- }
- closedir(dir);
- entry->children = g_slist_sort(entry->children, (GCompareFunc) tm_file_entry_compare);
- g_free(entries);
- break;
- }
- return entry;
-}
-
-void tm_file_entry_free(gpointer entry)
-{
- if (entry)
- {
- TMFileEntry *file_entry = TM_FILE_ENTRY(entry);
- if (file_entry->children)
- {
- GSList *tmp;
- for (tmp = file_entry->children; tmp; tmp = g_slist_next(tmp))
- tm_file_entry_free(tmp->data);
- g_slist_free(file_entry->children);
- }
- g_free(file_entry->version);
- g_free(file_entry->path);
- FILE_FREE(file_entry);
- }
-}
-
-void tm_file_entry_foreach(TMFileEntry *entry, TMFileEntryFunc func
- , gpointer user_data, guint level, gboolean reverse)
-{
- g_return_if_fail (entry != NULL);
- g_return_if_fail (func != NULL);
-
- if ((reverse) && (entry->children))
- {
- GSList *tmp;
- for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
- tm_file_entry_foreach(TM_FILE_ENTRY(tmp->data), func
- , user_data, level + 1, TRUE);
- }
- func(entry, user_data, level);
- if ((!reverse) && (entry->children))
- {
- GSList *tmp;
- for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
- tm_file_entry_foreach(TM_FILE_ENTRY(tmp->data), func
- , user_data, level + 1, FALSE);
- }
-}
-
-GList *tm_file_entry_list(TMFileEntry *entry, GList *files)
-{
- GSList *tmp;
- files = g_list_prepend(files, g_strdup(entry->path));
- for (tmp = entry->children; tmp; tmp = g_slist_next(tmp))
- {
- files = tm_file_entry_list((TMFileEntry *) tmp->data, files);
- }
- if (!files)
- files = g_list_reverse(files);
- return files;
-}
Modified: tagmanager/src/tm_file_entry.h
124 lines changed, 0 insertions(+), 124 deletions(-)
===================================================================
@@ -1,124 +0,0 @@
-/*
-*
-* Copyright (c) 2001-2002, Biswapesh Chattopadhyay
-*
-* This source code is released for free distribution under the terms of the
-* GNU General Public License.
-*
-*/
-
-#ifndef TM_FILE_ENTRY_H
-#define TM_FILE_ENTRY_H
-
-#include <glib.h>
-
-/* \file
-The TMFileEntry structure and associated functions can be used
-for file and directory traversal. The following example demonstrates
-the use of TMFileEntry.
-\include tm_file_tree_dump.c
-*/
-
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/* Enum defining file types */
-typedef enum
-{
- tm_file_unknown_t, /* Unknown file type/file does not exist */
- tm_file_regular_t, /* Is a regular file */
- tm_file_dir_t, /* Is a directory */
- tm_file_link_t /* Is a symbolic link */
-} TMFileType;
-
-/*
- This example demonstrates the use of TMFileEntry and associated functions
- for managing file hierarchies in a project.
-
- \example tm_file_tree_dump.c
-*/
-
-/* This structure stores the file tree */
-typedef struct _TMFileEntry
-{
- TMFileType type; /* File type */
- char *path; /* Full path to the file (incl. dir and name) */
- char *name; /* Just the file name (path minus the directory) */
- char *version; /* CVS version in case there is a CVS entry for this file */
- struct _TMFileEntry *parent; /* The parent directory file entry */
- GSList *children; /* List of children (for directory) */
-} TMFileEntry;
-
-/* Prototype for the function that gets called for each entry when
- tm_file_entry_foreach() is called.
-*/
-typedef void (*TMFileEntryFunc) (TMFileEntry *entry, gpointer user_data
- , guint level);
-
-/* Convinience casting macro */
-#define TM_FILE_ENTRY(E) ((TMFileEntry *) (E))
-
-/* Function that compares two file entries on name and returns the
- difference
-*/
-gint tm_file_entry_compare(TMFileEntry *e1, TMFileEntry *e2);
-
-/* Function to create a new file entry structure.
-\param path Path to the file for which the entry is to be created.
-\param parent Should be NULL for the first call. Since the function calls
- itself recursively, this parameter is required to build the hierarchy.
-\param recurse Whether the entry is to be recursively scanned (for
- directories only)
-\param file_match List of file name patterns to match. If set to NULL,
- all files match. You can use wildcards like '*.c'. See the example program
- for usage.
-\param file_unmatch Opposite of file_match. All files matching any of the patterns
- supplied are ignored. If set to NULL, no file is ignored.
-\param dir_match List of directory name patterns to match. If set to NULL,
- all directories match. You can use wildcards like '\.*'.
-\param dir_unmatch Opposite of dir_match. All directories matching any of the
- patterns supplied are ignored. If set to NULL, no directory is ignored.
-\param ignore_hidden_files If set to TRUE, hidden files (starting with '.')
- are ignored.
-\param ignore_hidden_dirs If set to TRUE, hidden directories (starting with '.')
- are ignored.
-\return Populated TMFileEntry structure on success, NULL on failure.
-*/
-TMFileEntry *tm_file_entry_new(const char *path, TMFileEntry *parent
- , gboolean recurse, GList *file_match, GList *file_unmatch
- , GList *dir_match, GList *dir_unmatch, gboolean ignore_hidden_files
- , gboolean ignore_hidden_dirs);
-
-/* Frees a TMFileEntry structure. Freeing is recursive, so all child
- entries are freed as well.
-\param entry The TMFileEntry structure to be freed.
-*/
-void tm_file_entry_free(gpointer entry);
-
-/* This will call the function func() for each file entry.
-\param entry The root file entry.
-\param func The function to be called.
-\param user_data Extra information to be passed to the function.
-\param level The recursion level. You should set this to 0 initially.
-\param reverse If set to TRUE, traversal is in reverse hierarchical order
-*/
-void tm_file_entry_foreach(TMFileEntry *entry, TMFileEntryFunc func
- , gpointer user_data, guint level, gboolean reverse);
-
-/* This is a sample function to show the use of tm_file_entry_foreach().
-*/
-void tm_file_entry_print(TMFileEntry *entry, gpointer user_data, guint level);
-
-/* Creates a list of path names from a TMFileEntry structure.
-\param entry The TMFileEntry structure.
-\files Current file list. Should be NULL.
-*/
-GList *tm_file_entry_list(TMFileEntry *entry, GList *files);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* TM_FILE_ENTRY_H */
Modified: tagmanager/src/tm_source_file.c
449 lines changed, 256 insertions(+), 193 deletions(-)
===================================================================
@@ -18,37 +18,159 @@
#include <limits.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <glib/gstdio.h>
+#ifdef G_OS_WIN32
+# define VC_EXTRALEAN
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h> /* for GetFullPathName */
+#endif
#include "general.h"
#include "entry.h"
#include "parse.h"
#include "read.h"
-#define LIBCTAGS_DEFINED
-#include "tm_work_object.h"
+#define LIBCTAGS_DEFINED
#include "tm_source_file.h"
#include "tm_tag.h"
-guint source_file_class_id = 0;
static TMSourceFile *current_source_file = NULL;
-gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name
- , gboolean update, const char* name)
+static int get_path_max(const char *path)
+{
+#ifdef PATH_MAX
+ return PATH_MAX;
+#else
+ int path_max = pathconf(path, _PC_PATH_MAX);
+ if (path_max <= 0)
+ path_max = 4096;
+ return path_max;
+#endif
+}
+
+
+#ifdef G_OS_WIN32
+/* realpath implementation for Windows found at http://bugzilla.gnome.org/show_bug.cgi?id=342926
+ * this one is better than e.g. liberty's lrealpath because this one uses Win32 API and works
+ * with special chars within the filename */
+static char *realpath (const char *pathname, char *resolved_path)
+{
+ int size;
+
+ if (resolved_path != NULL)
+ {
+ int path_max = get_path_max(pathname);
+ size = GetFullPathNameA (pathname, path_max, resolved_path, NULL);
+ if (size > path_max)
+ return NULL;
+ else
+ return resolved_path;
+ }
+ else
+ {
+ size = GetFullPathNameA (pathname, 0, NULL, NULL);
+ resolved_path = g_new0 (char, size);
+ GetFullPathNameA (pathname, size, resolved_path, NULL);
+ return resolved_path;
+ }
+}
+#endif
+
+/**
+ Given a file name, returns a newly allocated string containing the realpath()
+ of the file.
+ @param file_name The original file_name
+ @return A newly allocated string containing the real path to the file. NULL if none is available.
+*/
+gchar *tm_get_real_path(const gchar *file_name)
+{
+ if (file_name)
+ {
+ gsize len = get_path_max(file_name) + 1;
+ gchar *path = g_malloc0(len);
+
+ if (realpath(file_name, path))
+ return path;
+ else
+ g_free(path);
+ }
+ return NULL;
+}
+
+/*
+ This function is registered into the ctags parser when a file is parsed for
+ the first time. The function is then called by the ctags parser each time
+ it finds a new tag. You should not have to use this function.
+ @see tm_source_file_parse()
+*/
+static int tm_source_file_tags(const tagEntryInfo *tag)
+{
+ if (NULL == current_source_file)
+ return 0;
+ g_ptr_array_add(current_source_file->tags_array,
+ tm_tag_new(current_source_file, tag));
+ return TRUE;
+}
+
+/* Set the argument list of tag identified by its name */
+static void tm_source_file_set_tag_arglist(const char *tag_name, const char *arglist)
+{
+ guint count;
+ TMTag **tags, *tag;
+
+ if (NULL == arglist ||
+ NULL == tag_name ||
+ NULL == current_source_file)
+ {
+ return;
+ }
+
+ tags = tm_tags_find(current_source_file->tags_array, tag_name, FALSE, FALSE,
+ &count);
+ if (tags != NULL && count == 1)
+ {
+ tag = tags[0];
+ g_free(tag->arglist);
+ tag->arglist = g_strdup(arglist);
+ }
+}
+
+/* Initializes a TMSourceFile structure from a file name. */
+static gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name,
+ const char* name)
{
- if (0 == source_file_class_id)
- source_file_class_id = tm_work_object_register(tm_source_file_free
- , tm_source_file_update, NULL);
+ struct stat s;
+ int status;
#ifdef TM_DEBUG
g_message("Source File init: %s", file_name);
#endif
- if (FALSE == tm_work_object_init(&(source_file->work_object),
- source_file_class_id, file_name, FALSE))
- return FALSE;
+ if (file_name != NULL)
+ {
+ status = g_stat(file_name, &s);
+ if (0 != status)
+ {
+ /* g_warning("Unable to stat %s", file_name);*/
+ return FALSE;
+ }
+ if (!S_ISREG(s.st_mode))
+ {
+ g_warning("%s: Not a regular file", file_name);
+ return FALSE;
+ }
+ source_file->file_name = tm_get_real_path(file_name);
+ source_file->short_name = strrchr(source_file->file_name, '/');
+ if (source_file->short_name)
+ ++ source_file->short_name;
+ else
+ source_file->short_name = source_file->file_name;
+ }
+
+ source_file->tags_array = g_ptr_array_new();
- source_file->inactive = FALSE;
if (NULL == LanguageTable)
{
initializeParsing();
@@ -64,37 +186,46 @@ gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name
else
source_file->lang = getNamedLanguage(name);
- if (update)
- tm_source_file_update(TM_WORK_OBJECT(source_file), TRUE, FALSE, FALSE);
return TRUE;
}
-TMWorkObject *tm_source_file_new(const char *file_name, gboolean update, const char *name)
+/** Initializes a TMSourceFile structure and returns a pointer to it. The
+ * TMSourceFile has to be added to TMWorkspace to start its parsing.
+ * @param file_name The file name.
+ * @param name Name of the used programming language, NULL for autodetection.
+ * @return The created unparsed TMSourceFile object.
+ * */
+TMSourceFile *tm_source_file_new(const char *file_name, const char *name)
{
TMSourceFile *source_file = g_new(TMSourceFile, 1);
- if (TRUE != tm_source_file_init(source_file, file_name, update, name))
+ if (TRUE != tm_source_file_init(source_file, file_name, name))
{
g_free(source_file);
return NULL;
}
- return (TMWorkObject *) source_file;
+ return source_file;
}
-void tm_source_file_destroy(TMSourceFile *source_file)
+/* Destroys the contents of the source file. Note that the tags are owned by the
+ source file and are also destroyed when the source file is destroyed. If pointers
+ to these tags are used elsewhere, then those tag arrays should be rebuilt.
+*/
+static void tm_source_file_destroy(TMSourceFile *source_file)
{
#ifdef TM_DEBUG
- g_message("Destroying source file: %s", source_file->work_object.file_name);
+ g_message("Destroying source file: %s", source_file->file_name);
#endif
- if (NULL != TM_WORK_OBJECT(source_file)->tags_array)
- {
- tm_tags_array_free(TM_WORK_OBJECT(source_file)->tags_array, TRUE);
- TM_WORK_OBJECT(source_file)->tags_array = NULL;
- }
- tm_work_object_destroy(&(source_file->work_object));
+ g_free(source_file->file_name);
+ tm_tags_array_free(source_file->tags_array, TRUE);
+ source_file->tags_array = NULL;
}
-void tm_source_file_free(gpointer source_file)
+/** Frees a TMSourceFile structure, including all contents. Before calling this
+ function the TMSourceFile has to be removed from the TMWorkspace.
+ @param source_file The source file to free.
+*/
+void tm_source_file_free(TMSourceFile *source_file)
{
if (NULL != source_file)
{
@@ -103,79 +234,63 @@ void tm_source_file_free(gpointer source_file)
}
}
-gboolean tm_source_file_parse(TMSourceFile *source_file)
+/* Parses the text-buffer or source file and regenarates the tags.
+ @param source_file The source file to parse
+ @param text_buf The text buffer to parse
+ @param buf_size The size of text_buf.
+ @param use_buffer Set FALSE to ignore the buffer and parse the file directly or
+ TRUE to parse the buffer and ignore the file content.
+ @return TRUE on success, FALSE on failure
+*/
+gboolean tm_source_file_parse(TMSourceFile *source_file, guchar* text_buf, gsize buf_size,
+ gboolean use_buffer)
{
const char *file_name;
- gboolean status = TRUE;
- int passCount = 0;
+ gboolean retry = TRUE;
+ gboolean parse_file = FALSE;
+ gboolean free_buf = FALSE;
- if ((NULL == source_file) || (NULL == source_file->work_object.file_name))
+ if ((NULL == source_file) || (NULL == source_file->file_name))
{
g_warning("Attempt to parse NULL file");
return FALSE;
}
-
- file_name = source_file->work_object.file_name;
- if (NULL == LanguageTable)
+
+ if (source_file->lang == LANG_IGNORE)
{
- initializeParsing();
- installLanguageMapDefaults();
- if (NULL == TagEntryFunction)
- TagEntryFunction = tm_source_file_tags;
- if (NULL == TagEntrySetArglistFunction)
- TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
+ tm_tags_array_free(source_file->tags_array, FALSE);
+ return FALSE;
}
- current_source_file = source_file;
-
- if (LANG_AUTO == source_file->lang)
- source_file->lang = getFileLanguage (file_name);
-
- if (source_file->lang < 0 || ! LanguageTable [source_file->lang]->enabled)
- return status;
-
- while ((TRUE == status) && (passCount < 3))
+
+ file_name = source_file->file_name;
+
+ if (!use_buffer)
{
- if (source_file->work_object.tags_array)
- tm_tags_array_free(source_file->work_object.tags_array, FALSE);
- if (fileOpen (file_name, source_file->lang))
+ struct stat s;
+
+ /* load file to memory and parse it from memory unless the file is too big */
+ if (g_stat(file_name, &s) != 0 || s.st_size > 10*1024*1024)
+ parse_file = TRUE;
+ else
{
- if (LanguageTable [source_file->lang]->parser != NULL)
+ if (!g_file_get_contents(file_name, (gchar**)&text_buf, (gsize*)&buf_size, NULL))
{
- LanguageTable [source_file->lang]->parser ();
- fileClose ();
- break;
+ g_warning("Unable to open %s", file_name);
+ return FALSE;
}
- else if (LanguageTable [source_file->lang]->parser2 != NULL)
- status = LanguageTable [source_file->lang]->parser2 (passCount);
- fileClose ();
+ free_buf = TRUE;
}
- else
- {
- g_warning("%s: Unable to open %s", G_STRFUNC, file_name);
- return FALSE;
- }
- ++ passCount;
- }
- return status;
-}
-
-gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf, gint buf_size)
-{
- const char *file_name;
- gboolean status = TRUE;
-
- if ((NULL == source_file) || (NULL == source_file->work_object.file_name))
- {
- g_warning("Attempt to parse NULL file");
- return FALSE;
}
- if ((NULL == text_buf) || (0 == buf_size))
+ if (!parse_file && (NULL == text_buf || 0 == buf_size))
{
- g_warning("Attempt to parse a NULL text buffer");
+ /* Empty buffer, "parse" by setting empty tag array */
+ tm_tags_array_free(source_file->tags_array, FALSE);
+ if (free_buf)
+ g_free(text_buf);
+ return TRUE;
}
- file_name = source_file->work_object.file_name;
if (NULL == LanguageTable)
{
initializeParsing();
@@ -202,21 +317,34 @@ gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf
}
else
{
- int passCount = 0;
- while ((TRUE == status) && (passCount < 3))
+ guint passCount = 0;
+ while (retry && passCount < 3)
{
- if (source_file->work_object.tags_array)
- tm_tags_array_free(source_file->work_object.tags_array, FALSE);
- if (bufferOpen (text_buf, buf_size, file_name, source_file->lang))
+ tm_tags_array_free(source_file->tags_array, FALSE);
+ if (parse_file && fileOpen (file_name, source_file->lang))
+ {
+ if (LanguageTable [source_file->lang]->parser != NULL)
+ {
+ LanguageTable [source_file->lang]->parser ();
+ fileClose ();
+ retry = FALSE;
+ break;
+ }
+ else if (LanguageTable [source_file->lang]->parser2 != NULL)
+ retry = LanguageTable [source_file->lang]->parser2 (passCount);
+ fileClose ();
+ }
+ else if (!parse_file && bufferOpen (text_buf, buf_size, file_name, source_file->lang))
{
if (LanguageTable [source_file->lang]->parser != NULL)
{
LanguageTable [source_file->lang]->parser ();
bufferClose ();
+ retry = FALSE;
break;
}
else if (LanguageTable [source_file->lang]->parser2 != NULL)
- status = LanguageTable [source_file->lang]->parser2 (passCount);
+ retry = LanguageTable [source_file->lang]->parser2 (passCount);
bufferClose ();
}
else
@@ -226,103 +354,66 @@ gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf
}
++ passCount;
}
- return TRUE;
- }
- return status;
-}
-
-void tm_source_file_set_tag_arglist(const char *tag_name, const char *arglist)
-{
- int count;
- TMTag **tags, *tag;
-
- if (NULL == arglist ||
- NULL == tag_name ||
- NULL == current_source_file ||
- NULL == current_source_file->work_object.tags_array)
- {
- return;
- }
-
- tags = tm_tags_find(current_source_file->work_object.tags_array, tag_name, FALSE, FALSE,
- &count);
- if (tags != NULL && count == 1)
- {
- tag = tags[0];
- g_free(tag->atts.entry.arglist);
- tag->atts.entry.arglist = g_strdup(arglist);
}
+
+ if (free_buf)
+ g_free(text_buf);
+ return !retry;
}
-int tm_source_file_tags(const tagEntryInfo *tag)
-{
- if (NULL == current_source_file)
- return 0;
- if (NULL == current_source_file->work_object.tags_array)
- current_source_file->work_object.tags_array = g_ptr_array_new();
- g_ptr_array_add(current_source_file->work_object.tags_array,
- tm_tag_new(current_source_file, tag));
- return TRUE;
-}
-
-gboolean tm_source_file_update(TMWorkObject *source_file, gboolean force
- , gboolean UNUSED recurse, gboolean update_parent)
+/* Gets the name associated with the language index.
+ @param lang The language index.
+ @return The language name, or NULL.
+*/
+const gchar *tm_source_file_get_lang_name(gint lang)
{
- if (force)
+ if (NULL == LanguageTable)
{
- tm_source_file_parse(TM_SOURCE_FILE(source_file));
- tm_tags_sort(source_file->tags_array, NULL, FALSE);
- /* source_file->analyze_time = tm_get_file_timestamp(source_file->file_name); */
- if ((source_file->parent) && update_parent)
- {
- tm_work_object_update(source_file->parent, TRUE, FALSE, TRUE);
- }
- return TRUE;
- }
- else {
-#ifdef TM_DEBUG
- g_message ("no parsing of %s has been done", source_file->file_name);
-#endif
- return FALSE;
+ initializeParsing();
+ installLanguageMapDefaults();
+ if (NULL == TagEntryFunction)
+ TagEntryFunction = tm_source_file_tags;
+ if (NULL == TagEntrySetArglistFunction)
+ TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
}
+ return getLanguageName(lang);
}
-
-gboolean tm_source_file_buffer_update(TMWorkObject *source_file, guchar* text_buf,
- gint buf_size, gboolean update_parent)
+/* Gets the language index for \a name.
+ @param name The language name.
+ @return The language index, or -2.
+*/
+gint tm_source_file_get_named_lang(const gchar *name)
{
-#ifdef TM_DEBUG
- g_message("Buffer updating based on source file %s", source_file->file_name);
-#endif
-
- tm_source_file_buffer_parse (TM_SOURCE_FILE(source_file), text_buf, buf_size);
- tm_tags_sort(source_file->tags_array, NULL, FALSE);
- /* source_file->analyze_time = time(NULL); */
- if ((source_file->parent) && update_parent)
+ if (NULL == LanguageTable)
{
-#ifdef TM_DEBUG
- g_message("Updating parent from buffer..");
-#endif
- tm_work_object_update(source_file->parent, TRUE, FALSE, TRUE);
+ initializeParsing();
+ installLanguageMapDefaults();
+ if (NULL == TagEntryFunction)
+ TagEntryFunction = tm_source_file_tags;
+ if (NULL == TagEntrySetArglistFunction)
+ TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
}
-#ifdef TM_DEBUG
- else
- g_message("Skipping parent update because parent is %s and update_parent is %s"
- , source_file->parent?"NOT NULL":"NULL", update_parent?"TRUE":"FALSE");
-
-#endif
- return TRUE;
+ return getNamedLanguage(name);
}
-
-gboolean tm_source_file_write(TMWorkObject *source_file, FILE *fp, guint attrs)
+#if 0
+/*
+ Writes all tags of a source file (including the file tag itself) to the passed
+ file pointer.
+ @param source_file The source file to write.
+ @param fp The file pointer to write to.
+ @param attrs The attributes to write.
+ @return TRUE on success, FALSE on failure.
+*/
+static gboolean tm_source_file_write(TMSourceFile *source_file, FILE *fp, guint attrs)
{
TMTag *tag;
guint i;
if (NULL != source_file)
{
- if (NULL != (tag = tm_tag_new(TM_SOURCE_FILE(source_file), NULL)))
+ if (NULL != (tag = tm_tag_new(source_file, NULL)))
{
tm_tag_write(tag, fp, tm_tag_attr_max_t);
tm_tag_unref(tag);
@@ -339,32 +430,4 @@ gboolean tm_source_file_write(TMWorkObject *source_file, FILE *fp, guint attrs)
}
return TRUE;
}
-
-const gchar *tm_source_file_get_lang_name(gint lang)
-{
- if (NULL == LanguageTable)
- {
- initializeParsing();
- installLanguageMapDefaults();
- if (NULL == TagEntryFunction)
- TagEntryFunction = tm_source_file_tags;
- if (NULL == TagEntrySetArglistFunction)
- TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
- }
- return getLanguageName(lang);
-}
-
-gint tm_source_file_get_named_lang(const gchar *name)
-{
- if (NULL == LanguageTable)
- {
- initializeParsing();
- installLanguageMapDefaults();
- if (NULL == TagEntryFunction)
- TagEntryFunction = tm_source_file_tags;
- if (NULL == TagEntrySetArglistFunction)
- TagEntrySetArglistFunction = tm_source_file_set_tag_arglist;
- }
- return getNamedLanguage(name);
-}
-
+#endif
Modified: tagmanager/src/tm_source_file.h
136 lines changed, 18 insertions(+), 118 deletions(-)
===================================================================
@@ -10,8 +10,8 @@
#ifndef TM_SOURCE_FILE_H
#define TM_SOURCE_FILE_H
-#include "tm_work_object.h"
-
+#include <stdio.h>
+#include <glib.h>
#ifndef LIBCTAGS_DEFINED
typedef int langType;
@@ -27,138 +27,38 @@ extern "C"
#endif
/* Casts a pointer to a pointer to a TMSourceFile structure */
-#define TM_SOURCE_FILE(work_object) ((TMSourceFile *) work_object)
+#define TM_SOURCE_FILE(source_file) ((TMSourceFile *) source_file)
+
+/* Evaluates to X is X is defined, else evaluates to Y */
+#define FALLBACK(X,Y) (X)?(X):(Y)
-/* Checks whether the object is a TMSourceFile */
-#define IS_TM_SOURCE_FILE(source_file) (((TMWorkObject *) (source_file))->type \
- == source_file_class_id)
-/*!
- The TMSourceFile structure is derived from TMWorkObject and contains all it's
- attributes, plus an integer representing the language of the file.
+/**
+ The TMSourceFile structure represents the source file and its tags in the tag manager.
*/
typedef struct
{
- TMWorkObject work_object; /*!< The base work object */
- langType lang; /*!< Programming language used */
- gboolean inactive; /*!< Whether this file should be scanned for tags */
+ langType lang; /**< Programming language used */
+ char *file_name; /**< Full file name (inc. path) */
+ char *short_name; /**< Just the name of the file (without the path) */
+ GPtrArray *tags_array; /**< Sorted tag array obtained by parsing the object */
} TMSourceFile;
-/*! Initializes a TMSourceFile structure and returns a pointer to it.
- * \param file_name The file name.
- * \param update Update the tag array of the file.
- * \param name Name of the used programming language, NULL for autodetection.
- * \return The created TMSourceFile object.
- * */
-TMWorkObject *tm_source_file_new(const char *file_name, gboolean update, const char *name);
-
-/*! Updates the source file by reparsing if the modification time is greater
- than the timestamp in the structure, or if force is TRUE. The tags array and
- the tags themselves are destroyed and re-created, hence any other tag arrays
- pointing to these tags should be rebuilt as well. All sorting information is
- also lost. The language parameter is automatically set the first time the file
- is parsed.
- \param source_file The source file to update.
- \param force Ignored. The source file is always updated.
- \param recurse This parameter is ignored for source files and is only there for consistency.
- \param update_parent If set to TRUE, sends an update signal to parent if required. You should
- always set this to TRUE if you are calling this function directly.
- \return TRUE if the file was parsed, FALSE otherwise.
- \sa tm_work_object_update(), tm_workspace_update()
-*/
-gboolean tm_source_file_update(TMWorkObject *source_file, gboolean force
- , gboolean recurse, gboolean update_parent);
-
-
-#ifdef GEANY_PRIVATE
-
-/* Initializes a TMSourceFile structure from a file name. */
-gboolean tm_source_file_init(TMSourceFile *source_file, const char *file_name,
- gboolean update, const char *name);
-
-/* Destroys the contents of the source file. Note that the tags are owned by the
- source file and are also destroyed when the source file is destroyed. If pointers
- to these tags are used elsewhere, then those tag arrays should be rebuilt.
-*/
-void tm_source_file_destroy(TMSourceFile *source_file);
-
-/* Frees a TMSourceFile structure, including all contents */
-void tm_source_file_free(gpointer source_file);
-
-/* Updates the source file by reparsing the text-buffer passed as parameter.
- Ctags will use a parsing based on buffer instead of on files.
- You should call this function when you don't want a previous saving of the file
- you're editing. It's useful for a "real-time" updating of the tags.
- The tags array and the tags themselves are destroyed and re-created, hence any
- other tag arrays pointing to these tags should be rebuilt as well. All sorting
- information is also lost. The language parameter is automatically set the first
- time the file is parsed.
- \param source_file The source file to update with a buffer.
- \param text_buf A text buffer. The user should take care of allocate and free it after
- the use here.
- \param buf_size The size of text_buf.
- \param update_parent If set to TRUE, sends an update signal to parent if required. You should
- always set this to TRUE if you are calling this function directly.
- \return TRUE if the file was parsed, FALSE otherwise.
- \sa tm_work_object_update(), tm_workspace_update()
-*/
-gboolean tm_source_file_buffer_update(TMWorkObject *source_file, guchar* text_buf,
- gint buf_size, gboolean update_parent);
+TMSourceFile *tm_source_file_new(const char *file_name, const char *name);
-/* Parses the source file and regenarates the tags.
- \param source_file The source file to parse
- \return TRUE on success, FALSE on failure
- \sa tm_source_file_update()
-*/
-gboolean tm_source_file_parse(TMSourceFile *source_file);
-
-/* Parses the text-buffer and regenarates the tags.
- \param source_file The source file to parse
- \param text_buf The text buffer to parse
- \param buf_size The size of text_buf.
- \return TRUE on success, FALSE on failure
- \sa tm_source_file_update()
-*/
-gboolean tm_source_file_buffer_parse(TMSourceFile *source_file, guchar* text_buf, gint buf_size);
+void tm_source_file_free(TMSourceFile *source_file);
-/*
- This function is registered into the ctags parser when a file is parsed for
- the first time. The function is then called by the ctags parser each time
- it finds a new tag. You should not have to use this function.
- \sa tm_source_file_parse()
-*/
-int tm_source_file_tags(const tagEntryInfo *tag);
+gchar *tm_get_real_path(const gchar *file_name);
-/*
- Writes all tags of a source file (including the file tag itself) to the passed
- file pointer.
- \param source_file The source file to write.
- \param fp The file pointer to write to.
- \param attrs The attributes to write.
- \return TRUE on success, FALSE on failure.
-*/
-gboolean tm_source_file_write(TMWorkObject *source_file, FILE *fp, guint attrs);
-/* Contains the id obtained by registering the TMSourceFile class as a child of
- TMWorkObject.
- \sa tm_work_object_register()
-*/
-extern guint source_file_class_id;
+#ifdef GEANY_PRIVATE
-/* Gets the name associated with the language index.
- \param lang The language index.
- \return The language name, or NULL.
-*/
const gchar *tm_source_file_get_lang_name(gint lang);
-/* Gets the language index for \a name.
- \param name The language name.
- \return The language index, or -2.
-*/
gint tm_source_file_get_named_lang(const gchar *name);
-/* Set the argument list of tag identified by its name */
-void tm_source_file_set_tag_arglist(const char *tag_name, const char *arglist);
+gboolean tm_source_file_parse(TMSourceFile *source_file, guchar* text_buf, gsize buf_size,
+ gboolean use_buffer);
#endif /* GEANY_PRIVATE */
Modified: tagmanager/src/tm_tag.c
804 lines changed, 517 insertions(+), 287 deletions(-)
===================================================================
@@ -78,6 +78,11 @@ static void log_tag_free(TMTag *tag)
#endif /* DEBUG_TAG_REFS */
+const TMTagType TM_GLOBAL_TYPE_MASK =
+ tm_tag_class_t | tm_tag_enum_t | tm_tag_interface_t |
+ tm_tag_struct_t | tm_tag_typedef_t | tm_tag_union_t | tm_tag_namespace_t;
+
+
/* Note: To preserve binary compatibility, it is very important
that you only *append* to this list ! */
enum
@@ -95,12 +100,15 @@ enum
TA_ACCESS,
TA_IMPL,
TA_LANG,
- TA_INACTIVE,
+ TA_INACTIVE, /* Obsolete */
TA_POINTER
};
-static guint *s_sort_attrs = NULL;
-static gboolean s_partial = FALSE;
+typedef struct
+{
+ guint *sort_attrs;
+ gboolean partial;
+} TMSortOptions;
static const char *s_tag_type_names[] = {
"class", /* classes */
@@ -123,7 +131,7 @@ static const char *s_tag_type_names[] = {
"other" /* Other tag type (non C/C++/Java) */
};
-static int s_tag_types[] = {
+static TMTagType s_tag_types[] = {
tm_tag_class_t,
tm_tag_enum_t,
tm_tag_enumerator_t,
@@ -144,6 +152,7 @@ static int s_tag_types[] = {
tm_tag_other_t
};
+/* Gets the GType for a TMTag */
GType tm_tag_get_type(void)
{
static GType gtype = 0;
@@ -155,7 +164,7 @@ GType tm_tag_get_type(void)
return gtype;
}
-static int get_tag_type(const char *tag_name)
+static TMTagType get_tag_type(const char *tag_name)
{
unsigned int i;
int cmp;
@@ -208,56 +217,59 @@ static char get_tag_access(const char *access)
return TAG_ACCESS_UNKNOWN;
}
-gboolean tm_tag_init(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag_entry)
+/*
+ Initializes a TMTag structure with information from a tagEntryInfo struct
+ used by the ctags parsers. Note that the TMTag structure must be malloc()ed
+ before calling this function. This function is called by tm_tag_new() - you
+ should not need to call this directly.
+ @param tag The TMTag structure to initialize
+ @param file Pointer to a TMSourceFile struct (it is assigned to the file member)
+ @param tag_entry Tag information gathered by the ctags parser
+ @return TRUE on success, FALSE on failure
+*/
+static gboolean tm_tag_init(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag_entry)
{
tag->refcount = 1;
if (NULL == tag_entry)
- {
- /* This is a file tag */
- if (NULL == file)
- return FALSE;
- else
- {
- tag->name = g_strdup(file->work_object.file_name);
- tag->type = tm_tag_file_t;
- /* tag->atts.file.timestamp = file->work_object.analyze_time; */
- tag->atts.file.lang = file->lang;
- tag->atts.file.inactive = FALSE;
- return TRUE;
- }
- }
- else
- {
- /* This is a normal tag entry */
- if (NULL == tag_entry->name)
- return FALSE;
- tag->name = g_strdup(tag_entry->name);
- tag->type = get_tag_type(tag_entry->kindName);
- tag->atts.entry.local = tag_entry->isFileScope;
- tag->atts.entry.pointerOrder = 0; /* backward compatibility (use var_type instead) */
- tag->atts.entry.line = tag_entry->lineNumber;
- if (NULL != tag_entry->extensionFields.arglist)
- tag->atts.entry.arglist = g_strdup(tag_entry->extensionFields.arglist);
- if ((NULL != tag_entry->extensionFields.scope[1]) &&
- (isalpha(tag_entry->extensionFields.scope[1][0]) ||
- tag_entry->extensionFields.scope[1][0] == '_' ||
- tag_entry->extensionFields.scope[1][0] == '$'))
- tag->atts.entry.scope = g_strdup(tag_entry->extensionFields.scope[1]);
- if (tag_entry->extensionFields.inheritance != NULL)
- tag->atts.entry.inheritance = g_strdup(tag_entry->extensionFields.inheritance);
- if (tag_entry->extensionFields.varType != NULL)
- tag->atts.entry.var_type = g_strdup(tag_entry->extensionFields.varType);
- if (tag_entry->extensionFields.access != NULL)
- tag->atts.entry.access = get_tag_access(tag_entry->extensionFields.access);
- if (tag_entry->extensionFields.implementation != NULL)
- tag->atts.entry.impl = get_tag_impl(tag_entry->extensionFields.implementation);
- if ((tm_tag_macro_t == tag->type) && (NULL != tag->atts.entry.arglist))
- tag->type = tm_tag_macro_with_arg_t;
- tag->atts.entry.file = file;
- return TRUE;
- }
+ return FALSE;
+
+ /* This is a normal tag entry */
+ if (NULL == tag_entry->name)
+ return FALSE;
+ tag->name = g_strdup(tag_entry->name);
+ tag->type = get_tag_type(tag_entry->kindName);
+ tag->local = tag_entry->isFileScope;
+ tag->pointerOrder = 0; /* backward compatibility (use var_type instead) */
+ tag->line = tag_entry->lineNumber;
+ if (NULL != tag_entry->extensionFields.arglist)
+ tag->arglist = g_strdup(tag_entry->extensionFields.arglist);
+ if ((NULL != tag_entry->extensionFields.scope[1]) &&
+ (isalpha(tag_entry->extensionFields.scope[1][0]) ||
+ tag_entry->extensionFields.scope[1][0] == '_' ||
+ tag_entry->extensionFields.scope[1][0] == '$'))
+ tag->scope = g_strdup(tag_entry->extensionFields.scope[1]);
+ if (tag_entry->extensionFields.inheritance != NULL)
+ tag->inheritance = g_strdup(tag_entry->extensionFields.inheritance);
+ if (tag_entry->extensionFields.varType != NULL)
+ tag->var_type = g_strdup(tag_entry->extensionFields.varType);
+ if (tag_entry->extensionFields.access != NULL)
+ tag->access = get_tag_access(tag_entry->extensionFields.access);
+ if (tag_entry->extensionFields.implementation != NULL)
+ tag->impl = get_tag_impl(tag_entry->extensionFields.implementation);
+ if ((tm_tag_macro_t == tag->type) && (NULL != tag->arglist))
+ tag->type = tm_tag_macro_with_arg_t;
+ tag->file = file;
+ tag->lang = file->lang;
+ return TRUE;
}
+/*
+ Creates a new tag structure from a tagEntryInfo pointer and a TMSOurceFile pointer
+ and returns a pointer to it.
+ @param file - Pointer to the TMSourceFile structure containing the tag
+ @param tag_entry Contains tag information generated by ctags
+ @return the new TMTag structure. This should be free()-ed using tm_tag_free()
+*/
TMTag *tm_tag_new(TMSourceFile *file, const tagEntryInfo *tag_entry)
{
TMTag *tag;
@@ -271,7 +283,15 @@ TMTag *tm_tag_new(TMSourceFile *file, const tagEntryInfo *tag_entry)
return tag;
}
-gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
+/*
+ Initializes an already malloc()ed TMTag structure by reading a tag entry
+ line from a file. The structure should be allocated beforehand.
+ @param tag The TMTag structure to populate
+ @param file The TMSourceFile struct (assigned to the file member)
+ @param fp FILE pointer from where the tag line is read
+ @return TRUE on success, FALSE on FAILURE
+*/
+static gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
{
guchar buf[BUFSIZ];
guchar *start, *end;
@@ -301,61 +321,40 @@ gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
switch (*start)
{
case TA_LINE:
- tag->atts.entry.line = atol((gchar*)start + 1);
+ tag->line = atol((gchar*)start + 1);
break;
case TA_LOCAL:
- tag->atts.entry.local = atoi((gchar*)start + 1);
+ tag->local = atoi((gchar*)start + 1);
break;
case TA_TYPE:
tag->type = (TMTagType) atoi((gchar*)start + 1);
break;
case TA_ARGLIST:
- tag->atts.entry.arglist = g_strdup((gchar*)start + 1);
+ tag->arglist = g_strdup((gchar*)start + 1);
break;
case TA_SCOPE:
- tag->atts.entry.scope = g_strdup((gchar*)start + 1);
+ tag->scope = g_strdup((gchar*)start + 1);
break;
case TA_POINTER:
- tag->atts.entry.pointerOrder = atoi((gchar*)start + 1);
+ tag->pointerOrder = atoi((gchar*)start + 1);
break;
case TA_VARTYPE:
- tag->atts.entry.var_type = g_strdup((gchar*)start + 1);
+ tag->var_type = g_strdup((gchar*)start + 1);
break;
case TA_INHERITS:
- tag->atts.entry.inheritance = g_strdup((gchar*)start + 1);
+ tag->inheritance = g_strdup((gchar*)start + 1);
break;
- case TA_TIME:
- if (tm_tag_file_t != tag->type)
- {
- g_warning("Got time attribute for non-file tag %s", tag->name);
- return FALSE;
- }
- else
- tag->atts.file.timestamp = atol((gchar*)start + 1);
+ case TA_TIME: /* Obsolete */
break;
- case TA_LANG:
- if (tm_tag_file_t != tag->type)
- {
- g_warning("Got lang attribute for non-file tag %s", tag->name);
- return FALSE;
- }
- else
- tag->atts.file.lang = atoi((gchar*)start + 1);
+ case TA_LANG: /* Obsolete */
break;
- case TA_INACTIVE:
- if (tm_tag_file_t != tag->type)
- {
- g_warning("Got inactive attribute for non-file tag %s", tag->name);
- return FALSE;
- }
- else
- tag->atts.file.inactive = (gboolean) atoi((gchar*)start + 1);
+ case TA_INACTIVE: /* Obsolete */
break;
case TA_ACCESS:
- tag->atts.entry.access = *(start + 1);
+ tag->access = (char) *(start + 1);
break;
case TA_IMPL:
- tag->atts.entry.impl = *(start + 1);
+ tag->impl = (char) *(start + 1);
break;
default:
#ifdef GEANY_DEBUG
@@ -368,14 +367,13 @@ gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
}
if (NULL == tag->name)
return FALSE;
- if (tm_tag_file_t != tag->type)
- tag->atts.entry.file = file;
+ tag->file = file;
return TRUE;
}
/* alternative parser for Pascal and LaTeX global tags files with the following format
* tagname|return value|arglist|description\n */
-gboolean tm_tag_init_from_file_alt(TMTag *tag, TMSourceFile *file, FILE *fp)
+static gboolean tm_tag_init_from_file_alt(TMTag *tag, TMSourceFile *file, FILE *fp)
{
guchar buf[BUFSIZ];
guchar *start, *end;
@@ -404,8 +402,8 @@ gboolean tm_tag_init_from_file_alt(TMTag *tag, TMSourceFile *file, FILE *fp)
if (field_len >= 1) tag->name = g_strdup(fields[0]);
else tag->name = NULL;
- if (field_len >= 2 && fields[1] != NULL) tag->atts.entry.var_type = g_strdup(fields[1]);
- if (field_len >= 3 && fields[2] != NULL) tag->atts.entry.arglist = g_strdup(fields[2]);
+ if (field_len >= 2 && fields[1] != NULL) tag->var_type = g_strdup(fields[1]);
+ if (field_len >= 3 && fields[2] != NULL) tag->arglist = g_strdup(fields[2]);
tag->type = tm_tag_prototype_t;
g_strfreev(fields);
}
@@ -413,13 +411,15 @@ gboolean tm_tag_init_from_file_alt(TMTag *tag, TMSourceFile *file, FILE *fp)
if (NULL == tag->name)
return FALSE;
- if (tm_tag_file_t != tag->type)
- tag->atts.entry.file = file;
+ tag->file = file;
return TRUE;
}
-/* Reads ctags format (http://ctags.sourceforge.net/FORMAT) */
-gboolean tm_tag_init_from_file_ctags(TMTag *tag, TMSourceFile *file, FILE *fp)
+/*
+ Same as tm_tag_init_from_file(), but parsing CTags tag file format
+ (http://ctags.sourceforge.net/FORMAT)
+*/
+static gboolean tm_tag_init_from_file_ctags(TMTag *tag, TMSourceFile *file, FILE *fp)
{
gchar buf[BUFSIZ];
gchar *p, *tab;
@@ -460,7 +460,7 @@ gboolean tm_tag_init_from_file_ctags(TMTag *tag, TMSourceFile *file, FILE *fp)
}
}
else /* assume a line */
- tag->atts.entry.line = atol(p);
+ tag->line = atol(p);
tab = strstr(p, ";\"");
/* read extension fields */
if (tab)
@@ -501,7 +501,7 @@ gboolean tm_tag_init_from_file_ctags(TMTag *tag, TMSourceFile *file, FILE *fp)
case 'c': tag->type = tm_tag_class_t; break;
case 'd': tag->type = tm_tag_macro_t; break;
case 'e': tag->type = tm_tag_enumerator_t; break;
- case 'F': tag->type = tm_tag_file_t; break;
+ case 'F': tag->type = tm_tag_other_t; break; /* Obsolete */
case 'f': tag->type = tm_tag_function_t; break;
case 'g': tag->type = tm_tag_enum_t; break;
case 'I': tag->type = tm_tag_class_t; break;
@@ -527,39 +527,42 @@ gboolean tm_tag_init_from_file_ctags(TMTag *tag, TMSourceFile *file, FILE *fp)
}
else if (0 == strcmp(key, "inherits")) /* comma-separated list of classes this class inherits from */
{
- g_free(tag->atts.entry.inheritance);
- tag->atts.entry.inheritance = g_strdup(value);
+ g_free(tag->inheritance);
+ tag->inheritance = g_strdup(value);
}
else if (0 == strcmp(key, "implementation")) /* implementation limit */
- tag->atts.entry.impl = get_tag_impl(value);
+ tag->impl = get_tag_impl(value);
else if (0 == strcmp(key, "line")) /* line */
- tag->atts.entry.line = atol(value);
+ tag->line = atol(value);
else if (0 == strcmp(key, "access")) /* access */
- tag->atts.entry.access = get_tag_access(value);
+ tag->access = get_tag_access(value);
else if (0 == strcmp(key, "class") ||
0 == strcmp(key, "enum") ||
0 == strcmp(key, "function") ||
0 == strcmp(key, "struct") ||
0 == strcmp(key, "union")) /* Name of the class/enum/function/struct/union in which this tag is a member */
{
- g_free(tag->atts.entry.scope);
- tag->atts.entry.scope = g_strdup(value);
+ g_free(tag->scope);
+ tag->scope = g_strdup(value);
}
else if (0 == strcmp(key, "file")) /* static (local) tag */
- tag->atts.entry.local = TRUE;
+ tag->local = TRUE;
else if (0 == strcmp(key, "signature")) /* arglist */
{
- g_free(tag->atts.entry.arglist);
- tag->atts.entry.arglist = g_strdup(value);
+ g_free(tag->arglist);
+ tag->arglist = g_strdup(value);
}
}
}
- if (tm_tag_file_t != tag->type)
- tag->atts.entry.file = file;
+ tag->file = file;
return TRUE;
}
+/*
+ Same as tm_tag_new() except that the tag attributes are read from file.
+ @param mode langType to use for the tag.
+*/
TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp, gint mode, TMFileFormat format)
{
TMTag *tag;
@@ -585,70 +588,67 @@ TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp, gint mode, TMFileForma
TAG_FREE(tag);
return NULL;
}
- tag->atts.file.lang = mode;
+ tag->lang = mode;
return tag;
}
-gboolean tm_tag_write(TMTag *tag, FILE *fp, guint attrs)
+/*
+ Writes tag information to the given FILE *.
+ @param tag The tag information to write.
+ @param file FILE pointer to which the tag information is written.
+ @param attrs Attributes to be written (bitmask).
+ @return TRUE on success, FALSE on failure.
+*/
+gboolean tm_tag_write(TMTag *tag, FILE *fp, TMTagAttrType attrs)
{
fprintf(fp, "%s", tag->name);
if (attrs & tm_tag_attr_type_t)
fprintf(fp, "%c%d", TA_TYPE, tag->type);
- if (tag->type == tm_tag_file_t)
- {
- if (attrs & tm_tag_attr_time_t)
- fprintf(fp, "%c%ld", TA_TIME, tag->atts.file.timestamp);
- if (attrs & tm_tag_attr_lang_t)
- fprintf(fp, "%c%d", TA_LANG, tag->atts.file.lang);
- if ((attrs & tm_tag_attr_inactive_t) && tag->atts.file.inactive)
- fprintf(fp, "%c%d", TA_INACTIVE, tag->atts.file.inactive);
- }
- else
- {
- if ((attrs & tm_tag_attr_arglist_t) && (NULL != tag->atts.entry.arglist))
- fprintf(fp, "%c%s", TA_ARGLIST, tag->atts.entry.arglist);
- if (attrs & tm_tag_attr_line_t)
- fprintf(fp, "%c%ld", TA_LINE, tag->atts.entry.line);
- if (attrs & tm_tag_attr_local_t)
- fprintf(fp, "%c%d", TA_LOCAL, tag->atts.entry.local);
- if ((attrs & tm_tag_attr_scope_t) && (NULL != tag->atts.entry.scope))
- fprintf(fp, "%c%s", TA_SCOPE, tag->atts.entry.scope);
- if ((attrs & tm_tag_attr_inheritance_t) && (NULL != tag->atts.entry.inheritance))
- fprintf(fp, "%c%s", TA_INHERITS, tag->atts.entry.inheritance);
- if (attrs & tm_tag_attr_pointer_t)
- fprintf(fp, "%c%d", TA_POINTER, tag->atts.entry.pointerOrder);
- if ((attrs & tm_tag_attr_vartype_t) && (NULL != tag->atts.entry.var_type))
- fprintf(fp, "%c%s", TA_VARTYPE, tag->atts.entry.var_type);
- if ((attrs & tm_tag_attr_access_t) && (TAG_ACCESS_UNKNOWN != tag->atts.entry.access))
- fprintf(fp, "%c%c", TA_ACCESS, tag->atts.entry.access);
- if ((attrs & tm_tag_attr_impl_t) && (TAG_IMPL_UNKNOWN != tag->atts.entry.impl))
- fprintf(fp, "%c%c", TA_IMPL, tag->atts.entry.impl);
- }
+ if ((attrs & tm_tag_attr_arglist_t) && (NULL != tag->arglist))
+ fprintf(fp, "%c%s", TA_ARGLIST, tag->arglist);
+ if (attrs & tm_tag_attr_line_t)
+ fprintf(fp, "%c%ld", TA_LINE, tag->line);
+ if (attrs & tm_tag_attr_local_t)
+ fprintf(fp, "%c%d", TA_LOCAL, tag->local);
+ if ((attrs & tm_tag_attr_scope_t) && (NULL != tag->scope))
+ fprintf(fp, "%c%s", TA_SCOPE, tag->scope);
+ if ((attrs & tm_tag_attr_inheritance_t) && (NULL != tag->inheritance))
+ fprintf(fp, "%c%s", TA_INHERITS, tag->inheritance);
+ if (attrs & tm_tag_attr_pointer_t)
+ fprintf(fp, "%c%d", TA_POINTER, tag->pointerOrder);
+ if ((attrs & tm_tag_attr_vartype_t) && (NULL != tag->var_type))
+ fprintf(fp, "%c%s", TA_VARTYPE, tag->var_type);
+ if ((attrs & tm_tag_attr_access_t) && (TAG_ACCESS_UNKNOWN != tag->access))
+ fprintf(fp, "%c%c", TA_ACCESS, tag->access);
+ if ((attrs & tm_tag_attr_impl_t) && (TAG_IMPL_UNKNOWN != tag->impl))
+ fprintf(fp, "%c%c", TA_IMPL, tag->impl);
+
if (fprintf(fp, "\n"))
return TRUE;
else
return FALSE;
}
+/*
+ Destroys a TMTag structure, i.e. frees all elements except the tag itself.
+ @param tag The TMTag structure to destroy
+ @see tm_tag_free()
+*/
static void tm_tag_destroy(TMTag *tag)
{
g_free(tag->name);
- if (tm_tag_file_t != tag->type)
- {
- g_free(tag->atts.entry.arglist);
- g_free(tag->atts.entry.scope);
- g_free(tag->atts.entry.inheritance);
- g_free(tag->atts.entry.var_type);
- }
+ g_free(tag->arglist);
+ g_free(tag->scope);
+ g_free(tag->inheritance);
+ g_free(tag->var_type);
}
-#if 0
-void tm_tag_free(gpointer tag)
-{
- tm_tag_unref(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)
{
/* be NULL-proof because tm_tag_free() was NULL-proof and we indent to be a
@@ -660,77 +660,86 @@ 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)
{
g_atomic_int_inc(&tag->refcount);
return tag;
}
-int tm_tag_compare(const void *ptr1, const void *ptr2)
+/*
+ Inbuilt tag comparison function.
+*/
+static gint tm_tag_compare(gconstpointer ptr1, gconstpointer ptr2, gpointer user_data)
{
unsigned int *sort_attr;
int returnval = 0;
TMTag *t1 = *((TMTag **) ptr1);
TMTag *t2 = *((TMTag **) ptr2);
+ TMSortOptions *sort_options = user_data;
if ((NULL == t1) || (NULL == t2))
{
g_warning("Found NULL tag");
return t2 - t1;
}
- if (NULL == s_sort_attrs)
+ if (NULL == sort_options->sort_attrs)
{
- if (s_partial)
+ if (sort_options->partial)
return strncmp(FALLBACK(t1->name, ""), FALLBACK(t2->name, ""), strlen(FALLBACK(t1->name, "")));
else
return strcmp(FALLBACK(t1->name, ""), FALLBACK(t2->name, ""));
}
- for (sort_attr = s_sort_attrs; *sort_attr != tm_tag_attr_none_t; ++ sort_attr)
+ for (sort_attr = sort_options->sort_attrs; returnval == 0 && *sort_attr != tm_tag_attr_none_t; ++ sort_attr)
{
switch (*sort_attr)
{
case tm_tag_attr_name_t:
- if (s_partial)
+ if (sort_options->partial)
returnval = strncmp(FALLBACK(t1->name, ""), FALLBACK(t2->name, ""), strlen(FALLBACK(t1->name, "")));
else
returnval = strcmp(FALLBACK(t1->name, ""), FALLBACK(t2->name, ""));
- if (0 != returnval)
- return returnval;
- break;
- case tm_tag_attr_type_t:
- if (0 != (returnval = (t1->type - t2->type)))
- return returnval;
break;
case tm_tag_attr_file_t:
- if (0 != (returnval = (t1->atts.entry.file - t2->atts.entry.file)))
- return returnval;
+ returnval = t1->file - t2->file;
+ break;
+ case tm_tag_attr_line_t:
+ returnval = t1->line - t2->line;
+ break;
+ case tm_tag_attr_type_t:
+ returnval = t1->type - t2->type;
break;
case tm_tag_attr_scope_t:
- if (0 != (returnval = strcmp(FALLBACK(t1->atts.entry.scope, ""), FALLBACK(t2->atts.entry.scope, ""))))
- return returnval;
+ returnval = strcmp(FALLBACK(t1->scope, ""), FALLBACK(t2->scope, ""));
break;
case tm_tag_attr_arglist_t:
- if (0 != (returnval = strcmp(FALLBACK(t1->atts.entry.arglist, ""), FALLBACK(t2->atts.entry.arglist, ""))))
+ returnval = strcmp(FALLBACK(t1->arglist, ""), FALLBACK(t2->arglist, ""));
+ if (returnval != 0)
{
- int line_diff = (t1->atts.entry.line - t2->atts.entry.line);
+ int line_diff = (t1->line - t2->line);
- return line_diff ? line_diff : returnval;
+ returnval = line_diff ? line_diff : returnval;
}
break;
case tm_tag_attr_vartype_t:
- if (0 != (returnval = strcmp(FALLBACK(t1->atts.entry.var_type, ""), FALLBACK(t2->atts.entry.var_type, ""))))
- return returnval;
- break;
- case tm_tag_attr_line_t:
- if (0 != (returnval = (t1->atts.entry.line - t2->atts.entry.line)))
- return returnval;
+ returnval = strcmp(FALLBACK(t1->var_type, ""), FALLBACK(t2->var_type, ""));
break;
}
}
return returnval;
}
+/*
+ Removes NULL tag entries from an array of tags. Called after tm_tags_dedup() since
+ this function substitutes duplicate entries with NULL
+ @param tags_array Array of tags to dedup
+ @return TRUE on success, FALSE on failure
+*/
gboolean tm_tags_prune(GPtrArray *tags_array)
{
guint i, count;
@@ -743,18 +752,29 @@ gboolean tm_tags_prune(GPtrArray *tags_array)
return TRUE;
}
-gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes)
+/*
+ Deduplicates an array on tags using the inbuilt comparison function based on
+ the attributes specified. Called by tm_tags_sort() when dedup is TRUE.
+ @param tags_array Array of tags to dedup.
+ @param sort_attributes Attributes the array is sorted on. They will be deduped
+ on the same criteria.
+ @return TRUE on success, FALSE on failure
+*/
+gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean unref_duplicates)
{
+ TMSortOptions sort_options;
guint i;
if ((!tags_array) || (!tags_array->len))
return TRUE;
- s_sort_attrs = sort_attributes;
- s_partial = FALSE;
+ sort_options.sort_attrs = sort_attributes;
+ sort_options.partial = FALSE;
for (i = 1; i < tags_array->len; ++i)
{
- if (0 == tm_tag_compare(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i])))
+ if (0 == tm_tag_compare(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i]), &sort_options))
{
+ if (unref_duplicates)
+ tm_tag_unref(tags_array->pdata[i-1]);
tags_array->pdata[i-1] = NULL;
}
}
@@ -762,91 +782,200 @@ gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes)
return TRUE;
}
-gboolean tm_tags_custom_dedup(GPtrArray *tags_array, TMTagCompareFunc compare_func)
+/*
+ Sort an array of tags on the specified attribuites using the inbuilt comparison
+ function.
+ @param tags_array The array of tags to be sorted
+ @param sort_attributes Attributes to be sorted on (int array terminated by 0)
+ @param dedup Whether to deduplicate the sorted array
+ @return TRUE on success, FALSE on failure
+*/
+gboolean tm_tags_sort(GPtrArray *tags_array, TMTagAttrType *sort_attributes,
+ gboolean dedup, gboolean unref_duplicates)
{
- guint i;
-
+ TMSortOptions sort_options;
+
if ((!tags_array) || (!tags_array->len))
return TRUE;
- for (i = 1; i < tags_array->len; ++i)
+ sort_options.sort_attrs = sort_attributes;
+ sort_options.partial = FALSE;
+ g_ptr_array_sort_with_data(tags_array, tm_tag_compare, &sort_options);
+ if (dedup)
+ tm_tags_dedup(tags_array, sort_attributes, unref_duplicates);
+ return TRUE;
+}
+
+void tm_tags_remove_file_tags(TMSourceFile *source_file, GPtrArray *tags_array)
+{
+ guint i;
+ GPtrArray *to_delete = g_ptr_array_sized_new(source_file->tags_array->len);
+
+ for (i = 0; i < source_file->tags_array->len; i++)
{
- if (0 == compare_func(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i])))
- tags_array->pdata[i-1] = NULL;
+ guint j;
+ guint tag_count;
+ TMTag **found;
+ TMTag *tag = source_file->tags_array->pdata[i];
+
+ found = tm_tags_find(tags_array, tag->name, FALSE, TRUE, &tag_count);
+
+ for (j = 0; j < tag_count; j++)
+ {
+ if (*found != NULL && (*found)->file == source_file)
+ {
+ /* we cannot set the pointer to NULL now because the search wouldn't work */
+ g_ptr_array_add(to_delete, found);
+ /* no break - if there are multiple tags of the same name, we would
+ * always find the first instance and wouldn't remove others; duplicates
+ * in the to_delete list aren't a problem */
+ }
+ found++;
+ }
}
+
+ for (i = 0; i < to_delete->len; i++)
+ {
+ TMTag **tag = to_delete->pdata[i];
+ *tag = NULL;
+ }
+ g_ptr_array_free(to_delete, TRUE);
+
tm_tags_prune(tags_array);
- return TRUE;
}
-/* Sorts newly-added tags and merges them in order with existing tags.
- * This is much faster than resorting the whole array.
- * Note: Having the caller append to the existing array should be faster
- * than creating a new array which would likely get resized more than once.
- * tags_array: array with new (perhaps unsorted) tags appended.
- * orig_len: number of existing tags. */
-gboolean tm_tags_merge(GPtrArray *tags_array, gsize orig_len,
- TMTagAttrType *sort_attributes, gboolean dedup)
-{
- gpointer *copy, *a, *b;
- gsize copy_len, i;
+/* Optimized merge sort for merging sorted values from one array to another
+ * where one of the arrays is much smaller than the other.
+ * The merge complexity depends mostly on the size of the small array
+ * and is almost independent of the size of the big array.
+ * In addition, get rid of the duplicates (if both big_array and small_array are duplicate-free). */
+static GPtrArray *merge(GPtrArray *big_array, GPtrArray *small_array,
+ TMSortOptions *sort_options, gboolean unref_duplicates) {
+ guint i1 = 0; /* index to big_array */
+ guint i2 = 0; /* index to small_array */
+ guint initial_step;
+ guint step;
+ GPtrArray *res_array = g_ptr_array_sized_new(big_array->len + small_array->len);
+#ifdef TM_DEBUG
+ guint cmpnum = 0;
+#endif
- if ((!tags_array) || (!tags_array->len) || orig_len >= tags_array->len)
- return TRUE;
- if (!orig_len)
- return tm_tags_sort(tags_array, sort_attributes, dedup);
- copy_len = tags_array->len - orig_len;
- copy = g_memdup(tags_array->pdata + orig_len, copy_len * sizeof(gpointer));
- s_sort_attrs = sort_attributes;
- s_partial = FALSE;
- /* enforce copy sorted with same attributes for merge */
- qsort(copy, copy_len, sizeof(gpointer), tm_tag_compare);
- a = tags_array->pdata + orig_len - 1;
- b = copy + copy_len - 1;
- for (i = tags_array->len - 1;; i--)
+ /* swap the arrays if len(small) > len(big) */
+ if (small_array->len > big_array->len)
+ {
+ GPtrArray *tmp = small_array;
+ small_array = big_array;
+ big_array = tmp;
+ }
+
+ /* on average, we are merging a value from small_array every
+ * len(big_array) / len(small_array) values - good approximation for fast jump
+ * step size */
+ initial_step = (small_array->len > 0) ? big_array->len / small_array->len : 1;
+ initial_step = initial_step > 4 ? initial_step : 1;
+ step = initial_step;
+
+ while (i1 < big_array->len && i2 < small_array->len)
{
- gint cmp = tm_tag_compare(a, b);
+ gpointer val1;
+ gpointer val2 = small_array->pdata[i2];
- tags_array->pdata[i] = (cmp >= 0) ? *a-- : *b--;
- if (a < tags_array->pdata)
+ if (step > 4) /* fast path start */
{
- /* include remainder of copy as well as current value of b */
- memcpy(tags_array->pdata, copy, ((b + 1) - copy) * sizeof(gpointer));
- break;
+ guint j1 = (i1 + step < big_array->len) ? i1 + step : big_array->len - 1;
+
+ val1 = big_array->pdata[j1];
+#ifdef TM_DEBUG
+ cmpnum++;
+#endif
+ /* if the value in big_array after making the big step is still smaller
+ * than the value in small_array, we can copy all the values inbetween
+ * into the result without making expensive string comparisons */
+ if (tm_tag_compare(&val1, &val2, sort_options) < 0)
+ {
+ while (i1 <= j1)
+ {
+ val1 = big_array->pdata[i1];
+ /* we allocated enough space so we are sure we don't need to reallocate
+ * the array - copy and increment the size directly so it can be inlined */
+ res_array->pdata[res_array->len++] = val1;
+ i1++;
+ }
+ }
+ else
+ {
+ /* lower the step and try again */
+ step /= 2;
+ }
+ } /* fast path end */
+ else
+ {
+ gint cmpval;
+
+#ifdef TM_DEBUG
+ cmpnum++;
+#endif
+ val1 = big_array->pdata[i1];
+ cmpval = tm_tag_compare(&val1, &val2, sort_options);
+ if (cmpval < 0)
+ {
+ g_ptr_array_add(res_array, val1);
+ i1++;
+ }
+ else
+ {
+ g_ptr_array_add(res_array, val2);
+ i2++;
+ /* value from small_array gets merged - reset the step size */
+ step = initial_step;
+ if (cmpval == 0)
+ {
+ i1++; /* remove the duplicate, keep just the newly merged value */
+ if (unref_duplicates)
+ tm_tag_unref(val1);
+ }
+ }
}
- if (b < copy)
- break; /* remaining elements of 'a' are in place already */
- g_assert(i != 0);
}
- s_sort_attrs = NULL;
- g_free(copy);
- if (dedup)
- tm_tags_dedup(tags_array, sort_attributes);
- return TRUE;
-}
-gboolean tm_tags_sort(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean dedup)
-{
- if ((!tags_array) || (!tags_array->len))
- return TRUE;
- s_sort_attrs = sort_attributes;
- s_partial = FALSE;
- qsort(tags_array->pdata, tags_array->len, sizeof(gpointer), tm_tag_compare);
- s_sort_attrs = NULL;
- if (dedup)
- tm_tags_dedup(tags_array, sort_attributes);
- return TRUE;
+ /* end of one of the arrays reached - copy the rest from the other array */
+ while (i1 < big_array->len)
+ g_ptr_array_add(res_array, big_array->pdata[i1++]);
+ while (i2 < small_array->len)
+ g_ptr_array_add(res_array, small_array->pdata[i2++]);
+
+#ifdef TM_DEBUG
+ printf("cmpnums: %u\n", cmpnum);
+ printf("total tags: %u\n", big_array->len);
+ printf("merged tags: %u\n\n", small_array->len);
+#endif
+
+ return res_array;
}
-gboolean tm_tags_custom_sort(GPtrArray *tags_array, TMTagCompareFunc compare_func, gboolean dedup)
+GPtrArray *tm_tags_merge(GPtrArray *big_array, GPtrArray *small_array,
+ TMTagAttrType *sort_attributes, gboolean unref_duplicates)
{
- if ((!tags_array) || (!tags_array->len))
- return TRUE;
- qsort(tags_array->pdata, tags_array->len, sizeof(gpointer), compare_func);
- if (dedup)
- tm_tags_custom_dedup(tags_array, compare_func);
- return TRUE;
+ GPtrArray *res_array;
+ TMSortOptions sort_options;
+
+ sort_options.sort_attrs = sort_attributes;
+ sort_options.partial = FALSE;
+ res_array = merge(big_array, small_array, &sort_options, unref_duplicates);
+ return res_array;
}
-GPtrArray *tm_tags_extract(GPtrArray *tags_array, guint tag_types)
+/*
+ This function will extract the tags of the specified types from an array of tags.
+ The returned value is a GPtrArray which should be free-d with a call to
+ g_ptr_array_free(array, TRUE). However, do not free the tags themselves since they
+ are not duplicated.
+ @param tags_array The original array of tags
+ @param tag_types - The tag types to extract. Can be a bitmask. For example, passing
+ (tm_tag_typedef_t | tm_tag_struct_t) will extract all typedefs and structures from
+ the original array.
+ @return an array of tags (NULL on failure)
+*/
+GPtrArray *tm_tags_extract(GPtrArray *tags_array, TMTagType tag_types)
{
GPtrArray *new_tags;
guint i;
@@ -864,6 +993,11 @@ GPtrArray *tm_tags_extract(GPtrArray *tags_array, guint tag_types)
return new_tags;
}
+/*
+ Completely frees an array of tags.
+ @param tags_array Array of tags to be freed.
+ @param free_array Whether the GptrArray is to be freed as well.
+*/
void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all)
{
if (tags_array)
@@ -878,46 +1012,86 @@ void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all)
}
}
-static TMTag **tags_search(const GPtrArray *tags_array, TMTag *tag, gboolean partial,
- gboolean tags_array_sorted)
+/* copy/pasted bsearch() from libc extended with user_data for comparison function
+ * and using glib types */
+static gpointer binary_search(gpointer key, gpointer base, size_t nmemb,
+ GCompareDataFunc compar, gpointer user_data)
+{
+ gsize l, u, idx;
+ gpointer p;
+ gint comparison;
+
+ l = 0;
+ u = nmemb;
@@ Diff output truncated at 100000 characters. @@
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
More information about the Commits
mailing list