/* * * Copyright (c) 2001-2002, Biswapesh Chattopadhyay * * This source code is released for free distribution under the terms of the * GNU General Public License. * */ /*! * @file tm_workspace.h The TMWorkspace structure is meant to be used as a singleton to store application wide tag information. The workspace is intended to contain a list of global tags and a set of work objects (projects or individual files). You need not use the workspace, though, to use tag manager, unless you need things like global tags and a place to store all current open projects and individual files. TMWorkspace is derived from TMWorkObject. */ #include "general.h" #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <ctype.h> #include <sys/types.h> #include <string.h> #include <sys/stat.h> #ifdef HAVE_GLOB_H # include <glob.h> #endif #include <glib/gstdio.h> #include "tm_tag.h" #include "tm_workspace.h" #include "tm_project.h" static TMWorkspace *theWorkspace = NULL; guint workspace_class_id = 0; static gboolean tm_create_workspace(void) { workspace_class_id = tm_work_object_register(tm_workspace_free, tm_workspace_update , tm_workspace_find_object); theWorkspace = g_new(TMWorkspace, 1); if (FALSE == tm_work_object_init(TM_WORK_OBJECT(theWorkspace), workspace_class_id, NULL, TRUE)) { g_free(theWorkspace); theWorkspace = NULL; g_warning("Failed to initialize workspace"); return FALSE; } theWorkspace->global_tags = NULL; theWorkspace->work_objects = NULL; return TRUE; } void tm_workspace_free(gpointer workspace) { guint i; if (workspace != theWorkspace) return; #ifdef TM_DEBUG g_message("Workspace destroyed"); #endif if (theWorkspace) { if (theWorkspace->work_objects) { for (i=0; i < theWorkspace->work_objects->len; ++i) tm_work_object_free(theWorkspace->work_objects->pdata[i]); g_ptr_array_free(theWorkspace->work_objects, TRUE); } if (theWorkspace->global_tags) { for (i=0; i < theWorkspace->global_tags->len; ++i) tm_tag_unref(theWorkspace->global_tags->pdata[i]); g_ptr_array_free(theWorkspace->global_tags, TRUE); } tm_work_object_destroy(TM_WORK_OBJECT(theWorkspace)); g_free(theWorkspace); theWorkspace = NULL; } } const TMWorkspace *tm_get_workspace() { if (NULL == theWorkspace) tm_create_workspace(); return theWorkspace; } gboolean tm_workspace_add_object(TMWorkObject *work_object) { /* theWorkspace should already have been created otherwise something went wrong */ if (NULL == theWorkspace) return FALSE; if (NULL == theWorkspace->work_objects) theWorkspace->work_objects = g_ptr_array_new(); g_ptr_array_add(theWorkspace->work_objects, work_object); work_object->parent = TM_WORK_OBJECT(theWorkspace); return TRUE; } gboolean tm_workspace_remove_object(TMWorkObject *w, gboolean do_free, gboolean update) { guint i; if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects) || (NULL == w)) return FALSE; for (i=0; i < theWorkspace->work_objects->len; ++i) { if (theWorkspace->work_objects->pdata[i] == w) { if (do_free) tm_work_object_free(w); g_ptr_array_remove_index_fast(theWorkspace->work_objects, i); if (update) tm_workspace_update(TM_WORK_OBJECT(theWorkspace), TRUE, FALSE, FALSE); return TRUE; } } return FALSE; } static TMTagAttrType global_tags_sort_attrs[] = { tm_tag_attr_name_t, tm_tag_attr_scope_t, tm_tag_attr_type_t, tm_tag_attr_arglist_t, 0 }; gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode) { guchar buf[BUFSIZ]; FILE *fp; TMTag *tag; gboolean format_pipe = FALSE; if (NULL == theWorkspace) return FALSE; if (NULL == (fp = g_fopen(tags_file, "r"))) return FALSE; if (NULL == theWorkspace->global_tags) theWorkspace->global_tags = g_ptr_array_new(); if ((NULL == fgets((gchar*) buf, BUFSIZ, fp)) || ('\0' == *buf)) { fclose(fp); return FALSE; /* early out on error */ } else { /* We read the first line for the format specification. */ if (buf[0] == '#' && strstr((gchar*) buf, "format=pipe") != NULL) format_pipe = TRUE; else if (buf[0] == '#' && strstr((gchar*) buf, "format=tagmanager") != NULL) format_pipe = FALSE; else { /* We didn't find a valid format specification, so we try to auto-detect the format * by counting the pipe characters on the first line and asumme pipe format when * we find more than one pipe on the line. */ guint i, pipe_cnt = 0; for (i = 0; i < BUFSIZ && buf[i] != '\0' && pipe_cnt < 2; i++) { if (buf[i] == '|') pipe_cnt++; } format_pipe = (pipe_cnt > 1); } rewind(fp); /* reset the file pointer, to start reading again from the beginning */ } while (NULL != (tag = tm_tag_new_from_file(NULL, fp, mode, format_pipe))) g_ptr_array_add(theWorkspace->global_tags, tag); fclose(fp); /* resort the whole array, because tm_tags_find expects a sorted array and it is not sorted * when c99.tags, php.tags and latex.tags are loaded at the same time */ tm_tags_sort(theWorkspace->global_tags, global_tags_sort_attrs, TRUE); return TRUE; } static guint tm_file_inode_hash(gconstpointer key) { struct stat file_stat; const char *filename = (const char*)key; if (g_stat(filename, &file_stat) == 0) { #ifdef TM_DEBUG g_message ("Hash for '%s' is '%d'\n", filename, file_stat.st_ino); #endif return g_direct_hash (GUINT_TO_POINTER (file_stat.st_ino)); } else { return 0; } } static void tm_move_entries_to_g_list(gpointer key, gpointer value, gpointer user_data) { GList **pp_list = (GList**)user_data; if (user_data == NULL) return; *pp_list = g_list_prepend(*pp_list, value); } static void write_includes_file(FILE *fp, GList *includes_files) { GList *node; node = includes_files; while (node) { char *str = g_strdup_printf("#include \"%s\"\n", (char*)node->data); int str_len = strlen(str); fwrite(str, str_len, 1, fp); g_free(str); node = g_list_next(node); } } static void append_to_temp_file(FILE *fp, GList *file_list) { GList *node; node = file_list; while (node) { const char *fname = node->data; char *contents; size_t length; GError *err = NULL; if (! g_file_get_contents(fname, &contents, &length, &err)) { fprintf(stderr, "Unable to read file: %s\n", err->message); g_error_free(err); } else { fwrite(contents, length, 1, fp); fwrite("\n", 1, 1, fp); /* in case file doesn't end in newline (e.g. windows). */ g_free(contents); } node = g_list_next (node); } } static gchar *create_temp_file(const gchar *tpl) { gchar *name; gint fd; fd = g_file_open_tmp(tpl, &name, NULL); if (fd < 0) name = NULL; else close(fd); return name; } gboolean tm_workspace_create_global_tags(const char *pre_process, const char **includes, int includes_count, const char *tags_file, int lang) { #ifdef HAVE_GLOB_H glob_t globbuf; size_t idx_glob; #endif int idx_inc; char *command; guint i; FILE *fp; TMWorkObject *source_file; GPtrArray *tags_array; GHashTable *includes_files_hash; GList *includes_files = NULL; gchar *temp_file = create_temp_file("tmp_XXXXXX.cpp"); gchar *temp_file2 = create_temp_file("tmp_XXXXXX.cpp"); if (NULL == temp_file || NULL == temp_file2 || NULL == theWorkspace || NULL == (fp = g_fopen(temp_file, "w"))) { g_free(temp_file); g_free(temp_file2); return FALSE; } includes_files_hash = g_hash_table_new_full (tm_file_inode_hash, g_direct_equal, NULL, g_free); #ifdef HAVE_GLOB_H globbuf.gl_offs = 0; if (includes[0][0] == '"') /* leading \" char for glob matching */ for(idx_inc = 0; idx_inc < includes_count; idx_inc++) { int dirty_len = strlen(includes[idx_inc]); char *clean_path = g_malloc(dirty_len - 1); strncpy(clean_path, includes[idx_inc] + 1, dirty_len - 1); clean_path[dirty_len - 2] = 0; #ifdef TM_DEBUG g_message ("[o][%s]\n", clean_path); #endif glob(clean_path, 0, NULL, &globbuf); #ifdef TM_DEBUG g_message ("matches: %d\n", globbuf.gl_pathc); #endif for(idx_glob = 0; idx_glob < globbuf.gl_pathc; idx_glob++) { #ifdef TM_DEBUG g_message (">>> %s\n", globbuf.gl_pathv[idx_glob]); #endif if (!g_hash_table_lookup(includes_files_hash, globbuf.gl_pathv[idx_glob])) { char* file_name_copy = strdup(globbuf.gl_pathv[idx_glob]); g_hash_table_insert(includes_files_hash, file_name_copy, file_name_copy); #ifdef TM_DEBUG g_message ("Added ...\n"); #endif } } globfree(&globbuf); g_free(clean_path); } else #endif /* no glob support or globbing not wanted */ for(idx_inc = 0; idx_inc < includes_count; idx_inc++) { if (!g_hash_table_lookup(includes_files_hash, includes[idx_inc])) { char* file_name_copy = strdup(includes[idx_inc]); g_hash_table_insert(includes_files_hash, file_name_copy, file_name_copy); } } /* Checks for duplicate file entries which would case trouble */ g_hash_table_foreach(includes_files_hash, tm_move_entries_to_g_list, &includes_files); includes_files = g_list_reverse (includes_files); #ifdef TM_DEBUG g_message ("writing out files to %s\n", temp_file); #endif if (pre_process != NULL) write_includes_file(fp, includes_files); else append_to_temp_file(fp, includes_files); g_list_free (includes_files); g_hash_table_destroy(includes_files_hash); includes_files_hash = NULL; includes_files = NULL; fclose(fp); /* FIXME: The following grep command removes the lines * G_BEGIN_DECLS and G_END_DECLS from the header files. The reason is * that in tagmanager, the files are not correctly parsed and the typedefs * following these lines are incorrectly parsed. The real fix should, * of course be in tagmanager (c) parser. This is just a temporary fix. */ if (pre_process != NULL) { command = g_strdup_printf("%s %s | grep -v -E '^\\s*(G_BEGIN_DECLS|G_END_DECLS)\\s*$' > %s", pre_process, temp_file, temp_file2); #ifdef TM_DEBUG g_message("Executing: %s", command); #endif system(command); g_free(command); g_unlink(temp_file); g_free(temp_file); } else { /* no pre-processing needed, so temp_file2 = temp_file */ g_unlink(temp_file2); g_free(temp_file2); temp_file2 = temp_file; temp_file = NULL; } source_file = tm_source_file_new(temp_file2, TRUE, tm_source_file_get_lang_name(lang)); if (NULL == source_file) { g_unlink(temp_file2); return FALSE; } g_unlink(temp_file2); g_free(temp_file2); if ((NULL == source_file->tags_array) || (0 == source_file->tags_array->len)) { tm_source_file_free(source_file); return FALSE; } tags_array = tm_tags_extract(source_file->tags_array, tm_tag_max_t); if ((NULL == tags_array) || (0 == tags_array->len)) { if (tags_array) g_ptr_array_free(tags_array, TRUE); tm_source_file_free(source_file); return FALSE; } if (FALSE == tm_tags_sort(tags_array, global_tags_sort_attrs, TRUE)) { tm_source_file_free(source_file); return FALSE; } if (NULL == (fp = g_fopen(tags_file, "w"))) { tm_source_file_free(source_file); return FALSE; } fprintf(fp, "# format=tagmanager\n"); for (i = 0; i < tags_array->len; ++i) { tm_tag_write(TM_TAG(tags_array->pdata[i]), fp, tm_tag_attr_type_t | tm_tag_attr_scope_t | tm_tag_attr_arglist_t | tm_tag_attr_vartype_t | tm_tag_attr_pointer_t); } fclose(fp); tm_source_file_free(source_file); g_ptr_array_free(tags_array, TRUE); return TRUE; } TMWorkObject *tm_workspace_find_object(TMWorkObject *work_object, const char *file_name , gboolean name_only) { TMWorkObject *w = NULL; guint i; if (work_object != TM_WORK_OBJECT(theWorkspace)) return NULL; if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects) || (0 == theWorkspace->work_objects->len)) return NULL; for (i = 0; i < theWorkspace->work_objects->len; ++i) { if (NULL != (w = tm_work_object_find(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]) , file_name, name_only))) return w; } return NULL; } void tm_workspace_recreate_tags_array(void) { guint i, j; TMWorkObject *w; TMTagAttrType sort_attrs[] = { tm_tag_attr_name_t, tm_tag_attr_file_t , tm_tag_attr_scope_t, tm_tag_attr_type_t, tm_tag_attr_arglist_t, 0}; #ifdef TM_DEBUG g_message("Recreating workspace tags array"); #endif if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects)) return; if (NULL != theWorkspace->work_object.tags_array) g_ptr_array_set_size(theWorkspace->work_object.tags_array, 0); else theWorkspace->work_object.tags_array = g_ptr_array_new(); #ifdef TM_DEBUG g_message("Total %d objects", theWorkspace->work_objects->len); #endif for (i=0; i < theWorkspace->work_objects->len; ++i) { w = TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]); #ifdef TM_DEBUG g_message("Adding tags of %s", w->file_name); #endif if ((NULL != w) && (NULL != w->tags_array) && (w->tags_array->len > 0)) { for (j = 0; j < w->tags_array->len; ++j) { g_ptr_array_add(theWorkspace->work_object.tags_array, w->tags_array->pdata[j]); } } } #ifdef TM_DEBUG g_message("Total: %d tags", theWorkspace->work_object.tags_array->len); #endif tm_tags_sort(theWorkspace->work_object.tags_array, sort_attrs, TRUE); } gboolean tm_workspace_update(TMWorkObject *workspace, gboolean force , gboolean recurse, gboolean __unused__ update_parent) { guint i; gboolean update_tags = force; #ifdef TM_DEBUG g_message("Updating workspace"); #endif if (workspace != TM_WORK_OBJECT(theWorkspace)) return FALSE; if (NULL == theWorkspace) return TRUE; if ((recurse) && (theWorkspace->work_objects)) { for (i=0; i < theWorkspace->work_objects->len; ++i) { if (TRUE == tm_work_object_update(TM_WORK_OBJECT( theWorkspace->work_objects->pdata[i]), FALSE, TRUE, FALSE)) update_tags = TRUE; } } if (update_tags) tm_workspace_recreate_tags_array(); /* workspace->analyze_time = time(NULL); */ return update_tags; } void tm_workspace_dump(void) { if (theWorkspace) { #ifdef TM_DEBUG g_message("Dumping TagManager workspace tree.."); #endif tm_work_object_dump(TM_WORK_OBJECT(theWorkspace)); if (theWorkspace->work_objects) { guint i; for (i=0; i < theWorkspace->work_objects->len; ++i) { if (IS_TM_PROJECT(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]))) tm_project_dump(TM_PROJECT(theWorkspace->work_objects->pdata[i])); else tm_work_object_dump(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])); } } } } const GPtrArray *tm_workspace_find(const char *name, int type, TMTagAttrType *attrs , gboolean partial, langType lang) { static GPtrArray *tags = NULL; TMTag **matches[2]; int len, tagCount[2]={0,0}, tagIter; gint tags_lang; if ((!theWorkspace) || (!name)) return NULL; len = strlen(name); if (!len) return NULL; if (tags) g_ptr_array_set_size(tags, 0); else tags = g_ptr_array_new(); matches[0] = tm_tags_find(theWorkspace->work_object.tags_array, name, partial, &tagCount[0]); matches[1] = tm_tags_find(theWorkspace->global_tags, name, partial, &tagCount[1]); /* file tags */ if (matches[0] && *matches[0]) { /* tag->atts.file.lang contains the line of the tag and * tags->atts.entry.file->lang contains the language */ tags_lang = (*matches[0])->atts.entry.file->lang; for (tagIter=0;tagIter<tagCount[0];++tagIter) { if ((type & (*matches[0])->type) && (lang == -1 || tags_lang == lang)) g_ptr_array_add(tags, *matches[0]); if (partial) { if (0 != strncmp((*matches[0])->name, name, len)) break; } else { if (0 != strcmp((*matches[0])->name, name)) break; } ++ matches[0]; } } /* global tags */ if (matches[1] && *matches[1]) { int tags_lang_alt = 0; /* tag->atts.file.lang contains the language and * tags->atts.entry.file is NULL */ tags_lang = (*matches[1])->atts.file.lang; /* tags_lang_alt is used to load C global tags only once for C and C++ * lang = 1 is C++, lang = 0 is C * if we have lang 0, than accept also lang 1 for C++ */ if (tags_lang == 0) /* C or C++ */ tags_lang_alt = 1; else tags_lang_alt = tags_lang; /* otherwise just ignore it */ for (tagIter=0;tagIter<tagCount[1];++tagIter) { if ((type & (*matches[1])->type) && (lang == -1 || tags_lang == lang || tags_lang_alt == lang)) g_ptr_array_add(tags, *matches[1]); if (partial) { if (0 != strncmp((*matches[1])->name, name, len)) break; } else { if (0 != strcmp((*matches[1])->name, name)) break; } ++ matches[1]; } } if (attrs) tm_tags_sort(tags, attrs, TRUE); return tags; } static gboolean match_langs(gint lang, const TMTag *tag) { if (tag->atts.entry.file) { /* workspace tag */ if (lang == tag->atts.entry.file->lang) return TRUE; } else { /* global tag */ if (lang == tag->atts.file.lang) return TRUE; } return FALSE; } /* scope can be NULL. * lang can be -1 */ static int fill_find_tags_array (GPtrArray *dst, const GPtrArray *src, const char *name, const char *scope, int type, gboolean partial, gint lang, gboolean first) { TMTag **match; int tagIter, count; if ((!src) || (!dst) || (!name) || (!*name)) return 0; match = tm_tags_find (src, name, partial, &count); if (count && match && *match) { for (tagIter = 0; tagIter < count; ++tagIter) { if (! scope || (match[tagIter]->atts.entry.scope && 0 == strcmp(match[tagIter]->atts.entry.scope, scope))) { if (type & match[tagIter]->type) if (lang == -1 || match_langs(lang, match[tagIter])) { g_ptr_array_add (dst, match[tagIter]); if (first) break; } } } } return dst->len; } /* adapted from tm_workspace_find, Anjuta 2.02 */ const GPtrArray * tm_workspace_find_scoped (const char *name, const char *scope, gint type, TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search) { static GPtrArray *tags = NULL; if ((!theWorkspace)) return NULL; if (tags) g_ptr_array_set_size (tags, 0); else tags = g_ptr_array_new (); fill_find_tags_array (tags, theWorkspace->work_object.tags_array, name, scope, type, partial, lang, FALSE); if (global_search) { /* for a scoped tag, I think we always want the same language */ fill_find_tags_array (tags, theWorkspace->global_tags, name, scope, type, partial, lang, FALSE); } if (attrs) tm_tags_sort (tags, attrs, TRUE); return tags; } const TMTag * tm_get_current_function (GPtrArray * file_tags, const gulong line) { GPtrArray *const local = tm_tags_extract (file_tags, tm_tag_function_t); if (local && local->len) { guint i; TMTag *tag, *function_tag = NULL; gulong function_line = 0; glong delta; for (i = 0; (i < local->len); ++i) { tag = TM_TAG (local->pdata[i]); delta = line - tag->atts.entry.line; if (delta >= 0 && (gulong)delta < line - function_line) { function_tag = tag; function_line = tag->atts.entry.line; } } g_ptr_array_free (local, TRUE); return function_tag; } return NULL; } static int find_scope_members_tags (const GPtrArray * all, GPtrArray * tags, const langType langJava, const char *name, const char *filename, gboolean no_definitions) { GPtrArray *local = g_ptr_array_new (); unsigned int i; TMTag *tag; size_t len = strlen (name); for (i = 0; (i < all->len); ++i) { tag = TM_TAG (all->pdata[i]); if (no_definitions && filename && tag->atts.entry.file && 0 != strcmp (filename, tag->atts.entry.file->work_object.short_name)) { continue; } if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0') { if (0 == strncmp (name, tag->atts.entry.scope, len)) { g_ptr_array_add (local, tag); } } } if (local->len > 0) { unsigned int j; TMTag *tag2; char backup = 0; char *s_backup = NULL; char *var_type = NULL; char *scope; for (i = 0; (i < local->len); ++i) { tag = TM_TAG (local->pdata[i]); scope = tag->atts.entry.scope; if (scope && 0 == strcmp (name, scope)) { g_ptr_array_add (tags, tag); continue; } s_backup = NULL; j = 0; /* someone could write better code :P */ while (scope) { if (s_backup) { backup = s_backup[0]; s_backup[0] = '\0'; if (0 == strcmp (name, tag->atts.entry.scope)) { j = local->len; s_backup[0] = backup; break; } } if (tag->atts.entry.file && tag->atts.entry.file->lang == langJava) { scope = strrchr (tag->atts.entry.scope, '.'); if (scope) var_type = scope + 1; } else { scope = strrchr (tag->atts.entry.scope, ':'); if (scope) { var_type = scope + 1; scope--; } } if (s_backup) { s_backup[0] = backup; } if (scope) { if (s_backup) { backup = s_backup[0]; s_backup[0] = '\0'; } for (j = 0; (j < local->len); ++j) { if (i == j) continue; tag2 = TM_TAG (local->pdata[j]); if (tag2->atts.entry.var_type && 0 == strcmp (var_type, tag2->atts.entry.var_type)) { break; } } if (s_backup) s_backup[0] = backup; } if (j < local->len) { break; } s_backup = scope; } if (j == local->len) { g_ptr_array_add (tags, tag); } } } g_ptr_array_free (local, TRUE); return (int) tags->len; } #if 0 static int find_namespace_members_tags (const GPtrArray * all, GPtrArray * tags, const langType langJava, const char *name, const char *filename) { GPtrArray *local = g_ptr_array_new (); unsigned int i; TMTag *tag; size_t len = strlen (name); g_return_val_if_fail (all != NULL, 0); for (i = 0; (i < all->len); ++i) { tag = TM_TAG (all->pdata[i]); if (filename && tag->atts.entry.file && 0 != strcmp (filename, tag->atts.entry.file->work_object.short_name)) { continue; } if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0') { if (0 == strncmp (name, tag->atts.entry.scope, len)) { g_ptr_array_add (local, tag); } } } if (local->len > 0) { char *scope; for (i = 0; (i < local->len); ++i) { tag = TM_TAG (local->pdata[i]); scope = tag->atts.entry.scope; /* if we wanna complete something like * namespace1:: * we'll just return the tags that have "namespace1" * as their scope. So we won't return classes/members/namespaces * under, for example, namespace2, where namespace1::namespace2 */ if (scope && 0 == strcmp (name, scope)) { g_ptr_array_add (tags, tag); } } } g_ptr_array_free (local, TRUE); return (int) tags->len; } const GPtrArray * tm_workspace_find_namespace_members (const GPtrArray * file_tags, const char *name, gboolean search_global) { static GPtrArray *tags = NULL; GPtrArray *local = NULL; char *new_name = (char *) name; char *filename = NULL; int found = 0, del = 0; static langType langJava = -1; TMTag *tag = NULL; g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL); if (!tags) tags = g_ptr_array_new (); while (1) { const GPtrArray *tags2; int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t | tm_tag_struct_t | tm_tag_typedef_t | tm_tag_union_t | tm_tag_enum_t); if (file_tags) { g_ptr_array_set_size (tags, 0); got = fill_find_tags_array (tags, file_tags, new_name, NULL, types, FALSE, -1, FALSE); } if (got) { tags2 = tags; } else { TMTagAttrType attrs[] = { tm_tag_attr_name_t, tm_tag_attr_type_t, tm_tag_attr_none_t }; tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1); } if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0]))) { if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type && tag->atts.entry.var_type[0] != '\0') { new_name = tag->atts.entry.var_type; continue; } filename = (tag->atts.entry.file ? tag->atts.entry.file->work_object.short_name : NULL); if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0') { del = 1; if (tag->atts.entry.file && tag->atts.entry.file->lang == langJava) { new_name = g_strdup_printf ("%s.%s", tag->atts.entry.scope, new_name); } else { new_name = g_strdup_printf ("%s::%s", tag->atts.entry.scope, new_name); } } break; } else { return NULL; } } g_ptr_array_set_size (tags, 0); if (tag && tag->atts.entry.file) { local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array, (tm_tag_function_t | tm_tag_field_t | tm_tag_enumerator_t | tm_tag_namespace_t | tm_tag_class_t )); } else { local = tm_tags_extract (theWorkspace->work_object.tags_array, (tm_tag_function_t | tm_tag_prototype_t | tm_tag_member_t | tm_tag_field_t | tm_tag_enumerator_t | tm_tag_namespace_t | tm_tag_class_t )); } if (local) { found = find_namespace_members_tags (local, tags, langJava, new_name, filename); g_ptr_array_free (local, TRUE); } if (!found && search_global) { GPtrArray *global = tm_tags_extract (theWorkspace->global_tags, (tm_tag_member_t | tm_tag_prototype_t | tm_tag_field_t | tm_tag_method_t | tm_tag_function_t | tm_tag_enumerator_t | tm_tag_namespace_t | tm_tag_class_t )); if (global) { find_namespace_members_tags (global, tags, langJava, new_name, filename); /*/ DEBUG_PRINT ("returning these"); gint i; for (i=0; i < tags->len; i++) { TMTag *cur_tag; cur_tag = (TMTag*)g_ptr_array_index (tags, i); tm_tag_print (cur_tag, stdout ); } /*/ g_ptr_array_free (global, TRUE); } } if (del) { g_free (new_name); } return tags; } #endif const GPtrArray * tm_workspace_find_scope_members (const GPtrArray * file_tags, const char *name, gboolean search_global, gboolean no_definitions) { static GPtrArray *tags = NULL; GPtrArray *local = NULL; char *new_name = (char *) name; char *filename = NULL; int found = 0, del = 0; static langType langJava = -1; TMTag *tag = NULL; /* FIXME */ /* langJava = getNamedLanguage ("Java"); */ g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL); if (!tags) tags = g_ptr_array_new (); while (1) { const GPtrArray *tags2; int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t | tm_tag_struct_t | tm_tag_typedef_t | tm_tag_union_t | tm_tag_enum_t); if (file_tags) { g_ptr_array_set_size (tags, 0); got = fill_find_tags_array (tags, file_tags, new_name, NULL, types, FALSE, -1, FALSE); } if (got) { tags2 = tags; } else { TMTagAttrType attrs[] = { tm_tag_attr_name_t, tm_tag_attr_type_t, tm_tag_attr_none_t }; tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1); } if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0]))) { if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type && tag->atts.entry.var_type[0] != '\0') { char *tmp_name; tmp_name = tag->atts.entry.var_type; if (strcmp(tmp_name, new_name) == 0) { new_name = NULL; } else { new_name = tmp_name; } continue; } filename = (tag->atts.entry.file ? tag->atts.entry.file->work_object.short_name : NULL); if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0') { del = 1; if (tag->atts.entry.file && tag->atts.entry.file->lang == langJava) { new_name = g_strdup_printf ("%s.%s", tag->atts.entry.scope, new_name); } else { new_name = g_strdup_printf ("%s::%s", tag->atts.entry.scope, new_name); } } break; } else { return NULL; } } g_ptr_array_set_size (tags, 0); if (no_definitions && tag && tag->atts.entry.file) { local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array, (tm_tag_function_t | tm_tag_prototype_t | tm_tag_member_t | tm_tag_field_t | tm_tag_method_t | tm_tag_enumerator_t)); } else { local = tm_tags_extract (theWorkspace->work_object.tags_array, (tm_tag_function_t | tm_tag_prototype_t | tm_tag_member_t | tm_tag_field_t | tm_tag_method_t | tm_tag_enumerator_t)); } if (local) { found = find_scope_members_tags (local, tags, langJava, new_name, filename, no_definitions); g_ptr_array_free (local, TRUE); } if (!found && search_global) { GPtrArray *global = tm_tags_extract (theWorkspace->global_tags, (tm_tag_member_t | tm_tag_prototype_t | tm_tag_field_t | tm_tag_method_t | tm_tag_function_t | tm_tag_enumerator_t |tm_tag_struct_t | tm_tag_typedef_t | tm_tag_union_t | tm_tag_enum_t)); if (global) { find_scope_members_tags (global, tags, langJava, new_name, filename, no_definitions); g_ptr_array_free (global, TRUE); } } if (del) { g_free (new_name); } return tags; } const GPtrArray *tm_workspace_get_parents(const gchar *name) { static TMTagAttrType type[] = { tm_tag_attr_name_t, tm_tag_attr_none_t }; static GPtrArray *parents = NULL; const GPtrArray *matches; guint i = 0; guint j; gchar **klasses; gchar **klass; TMTag *tag; g_return_val_if_fail(name && isalpha(*name),NULL); if (NULL == parents) parents = g_ptr_array_new(); else g_ptr_array_set_size(parents, 0); matches = tm_workspace_find(name, tm_tag_class_t, type, FALSE, -1); if ((NULL == matches) || (0 == matches->len)) return NULL; g_ptr_array_add(parents, matches->pdata[0]); while (i < parents->len) { tag = TM_TAG(parents->pdata[i]); if ((NULL != tag->atts.entry.inheritance) && (isalpha(tag->atts.entry.inheritance[0]))) { klasses = g_strsplit(tag->atts.entry.inheritance, ",", 10); for (klass = klasses; (NULL != *klass); ++ klass) { for (j=0; j < parents->len; ++j) { if (0 == strcmp(*klass, TM_TAG(parents->pdata[j])->name)) break; } if (parents->len == j) { matches = tm_workspace_find(*klass, tm_tag_class_t, type, FALSE, -1); if ((NULL != matches) && (0 < matches->len)) g_ptr_array_add(parents, matches->pdata[0]); } } g_strfreev(klasses); } ++ i; } return parents; }