Refactor snippets_complete_constructs().
[geany-mirror.git] / tagmanager / tm_workspace.c
blob6244ff01bf81805ca6f36decae10efe882cf3405
1 /*
3 * Copyright (c) 2001-2002, Biswapesh Chattopadhyay
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
8 */
10 /*!
11 * @file tm_workspace.h
12 The TMWorkspace structure is meant to be used as a singleton to store application
13 wide tag information.
15 The workspace is intended to contain a list of global tags
16 and a set of work objects (projects or individual files). You need not use the
17 workspace, though, to use tag manager, unless you need things like global tags
18 and a place to store all current open projects and individual files. TMWorkspace
19 is derived from TMWorkObject.
22 #include "general.h"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #include <sys/types.h>
29 #include <string.h>
30 #include <sys/stat.h>
31 #ifdef HAVE_GLOB_H
32 # include <glob.h>
33 #endif
34 #include <glib/gstdio.h>
36 #include "tm_tag.h"
37 #include "tm_workspace.h"
38 #include "tm_project.h"
41 static TMWorkspace *theWorkspace = NULL;
42 guint workspace_class_id = 0;
44 static gboolean tm_create_workspace(void)
46 workspace_class_id = tm_work_object_register(tm_workspace_free, tm_workspace_update
47 , tm_workspace_find_object);
48 theWorkspace = g_new(TMWorkspace, 1);
49 if (FALSE == tm_work_object_init(TM_WORK_OBJECT(theWorkspace),
50 workspace_class_id, NULL, TRUE))
52 g_free(theWorkspace);
53 theWorkspace = NULL;
54 g_warning("Failed to initialize workspace");
55 return FALSE;
58 theWorkspace->global_tags = NULL;
59 theWorkspace->work_objects = NULL;
60 return TRUE;
63 void tm_workspace_free(gpointer workspace)
65 guint i;
67 if (workspace != theWorkspace)
68 return;
70 #ifdef TM_DEBUG
71 g_message("Workspace destroyed");
72 #endif
74 if (theWorkspace)
76 if (theWorkspace->work_objects)
78 for (i=0; i < theWorkspace->work_objects->len; ++i)
79 tm_work_object_free(theWorkspace->work_objects->pdata[i]);
80 g_ptr_array_free(theWorkspace->work_objects, TRUE);
82 if (theWorkspace->global_tags)
84 for (i=0; i < theWorkspace->global_tags->len; ++i)
85 tm_tag_free(theWorkspace->global_tags->pdata[i]);
86 g_ptr_array_free(theWorkspace->global_tags, TRUE);
88 tm_work_object_destroy(TM_WORK_OBJECT(theWorkspace));
89 g_free(theWorkspace);
90 theWorkspace = NULL;
94 const TMWorkspace *tm_get_workspace()
96 if (NULL == theWorkspace)
97 tm_create_workspace();
98 return theWorkspace;
101 gboolean tm_workspace_add_object(TMWorkObject *work_object)
103 /* theWorkspace should already have been created otherwise something went wrong */
104 if (NULL == theWorkspace)
105 return FALSE;
106 if (NULL == theWorkspace->work_objects)
107 theWorkspace->work_objects = g_ptr_array_new();
108 g_ptr_array_add(theWorkspace->work_objects, work_object);
109 work_object->parent = TM_WORK_OBJECT(theWorkspace);
110 return TRUE;
113 gboolean tm_workspace_remove_object(TMWorkObject *w, gboolean do_free, gboolean update)
115 guint i;
116 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects)
117 || (NULL == w))
118 return FALSE;
121 for (i=0; i < theWorkspace->work_objects->len; ++i)
123 if (theWorkspace->work_objects->pdata[i] == w)
125 if (do_free)
126 tm_work_object_free(w);
127 g_ptr_array_remove_index_fast(theWorkspace->work_objects, i);
128 if (update)
129 tm_workspace_update(TM_WORK_OBJECT(theWorkspace), TRUE, FALSE, FALSE);
130 return TRUE;
134 return FALSE;
137 static TMTagAttrType global_tags_sort_attrs[] =
139 tm_tag_attr_name_t, tm_tag_attr_scope_t,
140 tm_tag_attr_type_t, tm_tag_attr_arglist_t, 0
143 gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode)
145 guchar buf[BUFSIZ];
146 FILE *fp;
147 TMTag *tag;
148 gboolean format_pipe = FALSE;
150 if (NULL == (fp = g_fopen(tags_file, "r")))
151 return FALSE;
152 if (NULL == theWorkspace)
153 return FALSE;
154 if (NULL == theWorkspace->global_tags)
155 theWorkspace->global_tags = g_ptr_array_new();
156 if ((NULL == fgets((gchar*) buf, BUFSIZ, fp)) || ('\0' == *buf))
157 return FALSE; /* early out on error */
158 else
159 { /* We read the first line for the format specification. */
160 if (buf[0] == '#' && strstr((gchar*) buf, "format=pipe") != NULL)
161 format_pipe = TRUE;
162 else if (buf[0] == '#' && strstr((gchar*) buf, "format=tagmanager") != NULL)
163 format_pipe = FALSE;
164 else
165 { /* We didn't find a valid format specification, so we try to auto-detect the format
166 * by counting the pipe characters on the first line and asumme pipe format when
167 * we find more than one pipe on the line. */
168 guint i, pipe_cnt = 0;
169 for (i = 0; i < BUFSIZ && buf[i] != '\0' && pipe_cnt < 2; i++)
171 if (buf[i] == '|')
172 pipe_cnt++;
174 format_pipe = (pipe_cnt > 1);
176 rewind(fp); /* reset the file pointer, to start reading again from the beginning */
178 while (NULL != (tag = tm_tag_new_from_file(NULL, fp, mode, format_pipe)))
179 g_ptr_array_add(theWorkspace->global_tags, tag);
180 fclose(fp);
182 /* resort the whole array, because tm_tags_find expects a sorted array and it is not sorted
183 * when c99.tags, php.tags and latex.tags are loaded at the same time */
184 tm_tags_sort(theWorkspace->global_tags, global_tags_sort_attrs, TRUE);
186 return TRUE;
189 static guint tm_file_inode_hash(gconstpointer key)
191 struct stat file_stat;
192 const char *filename = (const char*)key;
193 if (g_stat(filename, &file_stat) == 0)
195 #ifdef TM_DEBUG
196 g_message ("Hash for '%s' is '%d'\n", filename, file_stat.st_ino);
197 #endif
198 return g_direct_hash (GUINT_TO_POINTER (file_stat.st_ino));
199 } else {
200 return 0;
204 static void tm_move_entries_to_g_list(gpointer key, gpointer value, gpointer user_data)
206 GList **pp_list = (GList**)user_data;
208 if (user_data == NULL)
209 return;
211 *pp_list = g_list_prepend(*pp_list, value);
214 static void write_includes_file(FILE *fp, GList *includes_files)
216 GList *node;
218 node = includes_files;
219 while (node)
221 char *str = g_strdup_printf("#include \"%s\"\n", (char*)node->data);
222 int str_len = strlen(str);
223 size_t size;
225 size = fwrite(str, str_len, 1, fp);
226 free(str);
227 node = g_list_next (node);
232 static void append_to_temp_file(FILE *fp, GList *file_list)
234 GList *node;
236 node = file_list;
237 while (node)
239 const char *fname = node->data;
240 char *contents;
241 size_t length;
242 GError *err = NULL;
244 if (! g_file_get_contents(fname, &contents, &length, &err))
246 fprintf(stderr, "Unable to read file: %s\n", err->message);
247 g_error_free(err);
249 else
251 size_t size;
252 size = fwrite(contents, length, 1, fp);
253 size = fwrite("\n", 1, 1, fp); /* in case file doesn't end in newline (e.g. windows). */
254 g_free(contents);
256 node = g_list_next (node);
260 gboolean tm_workspace_create_global_tags(const char *config_dir, const char *pre_process,
261 const char **includes, int includes_count, const char *tags_file, int lang)
263 #ifdef HAVE_GLOB_H
264 glob_t globbuf;
265 size_t idx_glob;
266 #endif
267 int idx_inc;
268 char *command;
269 guint i;
270 FILE *fp;
271 TMWorkObject *source_file;
272 GPtrArray *tags_array;
273 GHashTable *includes_files_hash;
274 GList *includes_files = NULL;
275 #ifdef G_OS_WIN32
276 char *temp_file = g_strdup_printf("%s\\_%d_%ld_1.cpp", config_dir, getpid(), time(NULL));
277 char *temp_file2 = g_strdup_printf("%s\\_%d_%ld_2.cpp", config_dir, getpid(), time(NULL));
278 #else
279 char *temp_file = g_strdup_printf("%s/%d_%ld_1.cpp", config_dir, getpid(), time(NULL));
280 char *temp_file2 = g_strdup_printf("%s/%d_%ld_2.cpp", config_dir, getpid(), time(NULL));
281 #endif
283 if (NULL == theWorkspace || NULL == (fp = g_fopen(temp_file, "w")))
284 return FALSE;
286 includes_files_hash = g_hash_table_new_full (tm_file_inode_hash,
287 g_direct_equal,
288 NULL, g_free);
290 #ifdef HAVE_GLOB_H
291 globbuf.gl_offs = 0;
293 if (includes[0][0] == '"') /* leading \" char for glob matching */
294 for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
296 int dirty_len = strlen(includes[idx_inc]);
297 char *clean_path = g_malloc(dirty_len - 1);
298 strncpy(clean_path, includes[idx_inc] + 1, dirty_len - 1);
299 clean_path[dirty_len - 2] = 0;
301 #ifdef TM_DEBUG
302 g_message ("[o][%s]\n", clean_path);
303 #endif
304 glob(clean_path, 0, NULL, &globbuf);
306 #ifdef TM_DEBUG
307 g_message ("matches: %d\n", globbuf.gl_pathc);
308 #endif
310 for(idx_glob = 0; idx_glob < globbuf.gl_pathc; idx_glob++)
312 #ifdef TM_DEBUG
313 g_message (">>> %s\n", globbuf.gl_pathv[idx_glob]);
314 #endif
315 if (!g_hash_table_lookup(includes_files_hash,
316 globbuf.gl_pathv[idx_glob]))
318 char* file_name_copy = strdup(globbuf.gl_pathv[idx_glob]);
319 g_hash_table_insert(includes_files_hash, file_name_copy,
320 file_name_copy);
321 #ifdef TM_DEBUG
322 g_message ("Added ...\n");
323 #endif
326 globfree(&globbuf);
327 free(clean_path);
329 else
330 #endif
331 /* no glob support or globbing not wanted */
332 for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
334 if (!g_hash_table_lookup(includes_files_hash,
335 includes[idx_inc]))
337 char* file_name_copy = strdup(includes[idx_inc]);
338 g_hash_table_insert(includes_files_hash, file_name_copy,
339 file_name_copy);
343 /* Checks for duplicate file entries which would case trouble */
344 g_hash_table_foreach(includes_files_hash, tm_move_entries_to_g_list,
345 &includes_files);
347 includes_files = g_list_reverse (includes_files);
349 #ifdef TM_DEBUG
350 g_message ("writing out files to %s\n", temp_file);
351 #endif
352 if (pre_process != NULL)
353 write_includes_file(fp, includes_files);
354 else
355 append_to_temp_file(fp, includes_files);
357 g_list_free (includes_files);
358 g_hash_table_destroy(includes_files_hash);
359 includes_files_hash = NULL;
360 includes_files = NULL;
361 fclose(fp);
363 /* FIXME: The following grep command removes the lines
364 * G_BEGIN_DECLS and G_END_DECLS from the header files. The reason is
365 * that in tagmanager, the files are not correctly parsed and the typedefs
366 * following these lines are incorrectly parsed. The real fix should,
367 * of course be in tagmanager (c) parser. This is just a temporary fix.
369 if (pre_process != NULL)
371 int ret;
372 command = g_strdup_printf("%s %s | grep -v -E '^\\s*(G_BEGIN_DECLS|G_END_DECLS)\\s*$' > %s",
373 pre_process, temp_file, temp_file2);
374 #ifdef TM_DEBUG
375 g_message("Executing: %s", command);
376 #endif
377 ret = system(command);
378 g_free(command);
379 g_unlink(temp_file);
380 g_free(temp_file);
382 else
384 /* no pre-processing needed, so temp_file2 = temp_file */
385 g_free(temp_file2);
386 temp_file2 = temp_file;
387 temp_file = NULL;
389 source_file = tm_source_file_new(temp_file2, TRUE, tm_source_file_get_lang_name(lang));
390 if (NULL == source_file)
392 g_unlink(temp_file2);
393 return FALSE;
395 g_unlink(temp_file2);
396 g_free(temp_file2);
397 if ((NULL == source_file->tags_array) || (0 == source_file->tags_array->len))
399 tm_source_file_free(source_file);
400 return FALSE;
402 tags_array = tm_tags_extract(source_file->tags_array, tm_tag_max_t);
403 if ((NULL == tags_array) || (0 == tags_array->len))
405 if (tags_array)
406 g_ptr_array_free(tags_array, TRUE);
407 tm_source_file_free(source_file);
408 return FALSE;
410 if (FALSE == tm_tags_sort(tags_array, global_tags_sort_attrs, TRUE))
412 tm_source_file_free(source_file);
413 return FALSE;
415 if (NULL == (fp = g_fopen(tags_file, "w")))
417 tm_source_file_free(source_file);
418 return FALSE;
420 fprintf(fp, "# format=tagmanager\n");
421 for (i = 0; i < tags_array->len; ++i)
423 tm_tag_write(TM_TAG(tags_array->pdata[i]), fp, tm_tag_attr_type_t
424 | tm_tag_attr_scope_t | tm_tag_attr_arglist_t | tm_tag_attr_vartype_t
425 | tm_tag_attr_pointer_t);
427 fclose(fp);
428 tm_source_file_free(source_file);
429 g_ptr_array_free(tags_array, TRUE);
430 return TRUE;
433 TMWorkObject *tm_workspace_find_object(TMWorkObject *work_object, const char *file_name
434 , gboolean name_only)
436 TMWorkObject *w = NULL;
437 guint i;
439 if (work_object != TM_WORK_OBJECT(theWorkspace))
440 return NULL;
441 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects)
442 || (0 == theWorkspace->work_objects->len))
443 return NULL;
444 for (i = 0; i < theWorkspace->work_objects->len; ++i)
446 if (NULL != (w = tm_work_object_find(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])
447 , file_name, name_only)))
448 return w;
450 return NULL;
453 void tm_workspace_recreate_tags_array(void)
455 guint i, j;
456 TMWorkObject *w;
457 TMTagAttrType sort_attrs[] = { tm_tag_attr_name_t, tm_tag_attr_file_t
458 , tm_tag_attr_scope_t, tm_tag_attr_type_t, tm_tag_attr_arglist_t, 0};
460 #ifdef TM_DEBUG
461 g_message("Recreating workspace tags array");
462 #endif
464 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects))
465 return;
466 if (NULL != theWorkspace->work_object.tags_array)
467 g_ptr_array_set_size(theWorkspace->work_object.tags_array, 0);
468 else
469 theWorkspace->work_object.tags_array = g_ptr_array_new();
471 #ifdef TM_DEBUG
472 g_message("Total %d objects", theWorkspace->work_objects->len);
473 #endif
474 for (i=0; i < theWorkspace->work_objects->len; ++i)
476 w = TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]);
477 #ifdef TM_DEBUG
478 g_message("Adding tags of %s", w->file_name);
479 #endif
480 if ((NULL != w) && (NULL != w->tags_array) && (w->tags_array->len > 0))
482 for (j = 0; j < w->tags_array->len; ++j)
484 g_ptr_array_add(theWorkspace->work_object.tags_array,
485 w->tags_array->pdata[j]);
489 #ifdef TM_DEBUG
490 g_message("Total: %d tags", theWorkspace->work_object.tags_array->len);
491 #endif
492 tm_tags_sort(theWorkspace->work_object.tags_array, sort_attrs, TRUE);
495 gboolean tm_workspace_update(TMWorkObject *workspace, gboolean force
496 , gboolean recurse, gboolean __unused__ update_parent)
498 guint i;
499 gboolean update_tags = force;
501 #ifdef TM_DEBUG
502 g_message("Updating workspace");
503 #endif
505 if (workspace != TM_WORK_OBJECT(theWorkspace))
506 return FALSE;
507 if (NULL == theWorkspace)
508 return TRUE;
509 if ((recurse) && (theWorkspace->work_objects))
511 for (i=0; i < theWorkspace->work_objects->len; ++i)
513 if (TRUE == tm_work_object_update(TM_WORK_OBJECT(
514 theWorkspace->work_objects->pdata[i]), FALSE, TRUE, FALSE))
515 update_tags = TRUE;
518 if (update_tags)
519 tm_workspace_recreate_tags_array();
520 /* workspace->analyze_time = time(NULL); */
521 return update_tags;
524 void tm_workspace_dump(void)
526 if (theWorkspace)
528 #ifdef TM_DEBUG
529 g_message("Dumping TagManager workspace tree..");
530 #endif
531 tm_work_object_dump(TM_WORK_OBJECT(theWorkspace));
532 if (theWorkspace->work_objects)
534 guint i;
535 for (i=0; i < theWorkspace->work_objects->len; ++i)
537 if (IS_TM_PROJECT(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])))
538 tm_project_dump(TM_PROJECT(theWorkspace->work_objects->pdata[i]));
539 else
540 tm_work_object_dump(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]));
546 const GPtrArray *tm_workspace_find(const char *name, int type, TMTagAttrType *attrs
547 , gboolean partial, langType lang)
549 static GPtrArray *tags = NULL;
550 TMTag **matches[2];
551 int len, tagCount[2]={0,0}, tagIter;
552 gint tags_lang;
554 if ((!theWorkspace) || (!name))
555 return NULL;
556 len = strlen(name);
557 if (!len)
558 return NULL;
559 if (tags)
560 g_ptr_array_set_size(tags, 0);
561 else
562 tags = g_ptr_array_new();
564 matches[0] = tm_tags_find(theWorkspace->work_object.tags_array, name, partial, &tagCount[0]);
565 matches[1] = tm_tags_find(theWorkspace->global_tags, name, partial, &tagCount[1]);
567 /* file tags */
568 if (matches[0] && *matches[0])
570 /* tag->atts.file.lang contains the line of the tag and
571 * tags->atts.entry.file->lang contains the language */
572 tags_lang = (*matches[0])->atts.entry.file->lang;
574 for (tagIter=0;tagIter<tagCount[0];++tagIter)
576 if ((type & (*matches[0])->type) && (lang == -1 || tags_lang == lang))
577 g_ptr_array_add(tags, *matches[0]);
578 if (partial)
580 if (0 != strncmp((*matches[0])->name, name, len))
581 break;
583 else
585 if (0 != strcmp((*matches[0])->name, name))
586 break;
588 ++ matches[0];
592 /* global tags */
593 if (matches[1] && *matches[1])
595 int tags_lang_alt = 0;
596 /* tag->atts.file.lang contains the language and
597 * tags->atts.entry.file is NULL */
598 tags_lang = (*matches[1])->atts.file.lang;
599 /* tags_lang_alt is used to load C global tags only once for C and C++
600 * lang = 1 is C++, lang = 0 is C
601 * if we have lang 0, than accept also lang 1 for C++ */
602 if (tags_lang == 0) /* C or C++ */
603 tags_lang_alt = 1;
604 else
605 tags_lang_alt = tags_lang; /* otherwise just ignore it */
607 for (tagIter=0;tagIter<tagCount[1];++tagIter)
609 if ((type & (*matches[1])->type) && (lang == -1 ||
610 tags_lang == lang || tags_lang_alt == lang))
611 g_ptr_array_add(tags, *matches[1]);
613 if (partial)
615 if (0 != strncmp((*matches[1])->name, name, len))
616 break;
618 else
620 if (0 != strcmp((*matches[1])->name, name))
621 break;
623 ++ matches[1];
627 if (attrs)
628 tm_tags_sort(tags, attrs, TRUE);
629 return tags;
632 static gboolean match_langs(gint lang, const TMTag *tag)
634 if (tag->atts.entry.file)
635 { /* workspace tag */
636 if (lang == tag->atts.entry.file->lang)
637 return TRUE;
639 else
640 { /* global tag */
641 if (lang == tag->atts.file.lang)
642 return TRUE;
644 return FALSE;
647 /* scope can be NULL.
648 * lang can be -1 */
649 static int
650 fill_find_tags_array (GPtrArray *dst, const GPtrArray *src,
651 const char *name, const char *scope, int type, gboolean partial,
652 gint lang, gboolean first)
654 TMTag **match;
655 int tagIter, count;
657 if ((!src) || (!dst) || (!name) || (!*name))
658 return 0;
660 match = tm_tags_find (src, name, partial, &count);
661 if (count && match && *match)
663 for (tagIter = 0; tagIter < count; ++tagIter)
665 if (! scope || (match[tagIter]->atts.entry.scope &&
666 0 == strcmp(match[tagIter]->atts.entry.scope, scope)))
668 if (type & match[tagIter]->type)
669 if (lang == -1 || match_langs(lang, match[tagIter]))
671 g_ptr_array_add (dst, match[tagIter]);
672 if (first)
673 break;
678 return dst->len;
682 /* adapted from tm_workspace_find, Anjuta 2.02 */
683 const GPtrArray *
684 tm_workspace_find_scoped (const char *name, const char *scope, gint type,
685 TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search)
687 static GPtrArray *tags = NULL;
689 if ((!theWorkspace))
690 return NULL;
692 if (tags)
693 g_ptr_array_set_size (tags, 0);
694 else
695 tags = g_ptr_array_new ();
697 fill_find_tags_array (tags, theWorkspace->work_object.tags_array,
698 name, scope, type, partial, lang, FALSE);
699 if (global_search)
701 /* for a scoped tag, I think we always want the same language */
702 fill_find_tags_array (tags, theWorkspace->global_tags,
703 name, scope, type, partial, lang, FALSE);
705 if (attrs)
706 tm_tags_sort (tags, attrs, TRUE);
707 return tags;
711 const TMTag *
712 tm_get_current_function (GPtrArray * file_tags, const gulong line)
714 GPtrArray *const local = tm_tags_extract (file_tags, tm_tag_function_t);
715 if (local && local->len)
717 guint i;
718 TMTag *tag, *function_tag = NULL;
719 gulong function_line = 0;
720 glong delta;
722 for (i = 0; (i < local->len); ++i)
724 tag = TM_TAG (local->pdata[i]);
725 delta = line - tag->atts.entry.line;
726 if (delta >= 0 && (gulong)delta < line - function_line)
728 function_tag = tag;
729 function_line = tag->atts.entry.line;
732 g_ptr_array_free (local, TRUE);
733 return function_tag;
735 return NULL;
739 static int
740 find_scope_members_tags (const GPtrArray * all, GPtrArray * tags,
741 const langType langJava, const char *name,
742 const char *filename, gboolean no_definitions)
744 GPtrArray *local = g_ptr_array_new ();
745 unsigned int i;
746 TMTag *tag;
747 size_t len = strlen (name);
748 for (i = 0; (i < all->len); ++i)
750 tag = TM_TAG (all->pdata[i]);
751 if (no_definitions && filename && tag->atts.entry.file &&
752 0 != strcmp (filename,
753 tag->atts.entry.file->work_object.short_name))
755 continue;
757 if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
759 if (0 == strncmp (name, tag->atts.entry.scope, len))
761 g_ptr_array_add (local, tag);
765 if (local->len > 0)
767 unsigned int j;
768 TMTag *tag2;
769 char backup = 0;
770 char *s_backup = NULL;
771 char *var_type = NULL;
772 char *scope;
773 for (i = 0; (i < local->len); ++i)
775 tag = TM_TAG (local->pdata[i]);
776 scope = tag->atts.entry.scope;
777 if (scope && 0 == strcmp (name, scope))
779 g_ptr_array_add (tags, tag);
780 continue;
782 s_backup = NULL;
783 j = 0; /* someone could write better code :P */
784 while (scope)
786 if (s_backup)
788 backup = s_backup[0];
789 s_backup[0] = '\0';
790 if (0 == strcmp (name, tag->atts.entry.scope))
792 j = local->len;
793 s_backup[0] = backup;
794 break;
797 if (tag->atts.entry.file
798 && tag->atts.entry.file->lang == langJava)
800 scope = strrchr (tag->atts.entry.scope, '.');
801 if (scope)
802 var_type = scope + 1;
804 else
806 scope = strrchr (tag->atts.entry.scope, ':');
807 if (scope)
809 var_type = scope + 1;
810 scope--;
813 if (s_backup)
815 s_backup[0] = backup;
817 if (scope)
819 if (s_backup)
821 backup = s_backup[0];
822 s_backup[0] = '\0';
824 for (j = 0; (j < local->len); ++j)
826 if (i == j)
827 continue;
828 tag2 = TM_TAG (local->pdata[j]);
829 if (tag2->atts.entry.var_type &&
830 0 == strcmp (var_type, tag2->atts.entry.var_type))
832 break;
835 if (s_backup)
836 s_backup[0] = backup;
838 if (j < local->len)
840 break;
842 s_backup = scope;
844 if (j == local->len)
846 g_ptr_array_add (tags, tag);
850 g_ptr_array_free (local, TRUE);
851 return (int) tags->len;
855 #if 0
856 static int
857 find_namespace_members_tags (const GPtrArray * all, GPtrArray * tags,
858 const langType langJava, const char *name,
859 const char *filename)
861 GPtrArray *local = g_ptr_array_new ();
862 unsigned int i;
863 TMTag *tag;
864 size_t len = strlen (name);
866 g_return_val_if_fail (all != NULL, 0);
868 for (i = 0; (i < all->len); ++i)
870 tag = TM_TAG (all->pdata[i]);
871 if (filename && tag->atts.entry.file &&
872 0 != strcmp (filename,
873 tag->atts.entry.file->work_object.short_name))
875 continue;
878 if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
880 if (0 == strncmp (name, tag->atts.entry.scope, len))
882 g_ptr_array_add (local, tag);
887 if (local->len > 0)
889 char *scope;
890 for (i = 0; (i < local->len); ++i)
892 tag = TM_TAG (local->pdata[i]);
893 scope = tag->atts.entry.scope;
895 /* if we wanna complete something like
896 * namespace1::
897 * we'll just return the tags that have "namespace1"
898 * as their scope. So we won't return classes/members/namespaces
899 * under, for example, namespace2, where namespace1::namespace2
901 if (scope && 0 == strcmp (name, scope))
903 g_ptr_array_add (tags, tag);
908 g_ptr_array_free (local, TRUE);
909 return (int) tags->len;
912 const GPtrArray *
913 tm_workspace_find_namespace_members (const GPtrArray * file_tags, const char *name,
914 gboolean search_global)
916 static GPtrArray *tags = NULL;
917 GPtrArray *local = NULL;
918 char *new_name = (char *) name;
919 char *filename = NULL;
920 int found = 0, del = 0;
921 static langType langJava = -1;
922 TMTag *tag = NULL;
924 g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
926 if (!tags)
927 tags = g_ptr_array_new ();
929 while (1)
931 const GPtrArray *tags2;
932 int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t |
933 tm_tag_struct_t | tm_tag_typedef_t |
934 tm_tag_union_t | tm_tag_enum_t);
936 if (file_tags)
938 g_ptr_array_set_size (tags, 0);
939 got = fill_find_tags_array (tags, file_tags,
940 new_name, NULL, types, FALSE, -1, FALSE);
944 if (got)
946 tags2 = tags;
948 else
950 TMTagAttrType attrs[] = {
951 tm_tag_attr_name_t, tm_tag_attr_type_t,
952 tm_tag_attr_none_t
954 tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
957 if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
959 if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type
960 && tag->atts.entry.var_type[0] != '\0')
962 new_name = tag->atts.entry.var_type;
963 continue;
965 filename = (tag->atts.entry.file ?
966 tag->atts.entry.file->work_object.short_name : NULL);
967 if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
969 del = 1;
970 if (tag->atts.entry.file &&
971 tag->atts.entry.file->lang == langJava)
973 new_name = g_strdup_printf ("%s.%s",
974 tag->atts.entry.scope,
975 new_name);
977 else
979 new_name = g_strdup_printf ("%s::%s",
980 tag->atts.entry.scope,
981 new_name);
984 break;
986 else
988 return NULL;
992 g_ptr_array_set_size (tags, 0);
994 if (tag && tag->atts.entry.file)
996 local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array,
997 (tm_tag_function_t |
998 tm_tag_field_t | tm_tag_enumerator_t |
999 tm_tag_namespace_t | tm_tag_class_t ));
1001 else
1003 local = tm_tags_extract (theWorkspace->work_object.tags_array,
1004 (tm_tag_function_t | tm_tag_prototype_t |
1005 tm_tag_member_t |
1006 tm_tag_field_t | tm_tag_enumerator_t |
1007 tm_tag_namespace_t | tm_tag_class_t ));
1010 if (local)
1012 found = find_namespace_members_tags (local, tags,
1013 langJava, new_name, filename);
1014 g_ptr_array_free (local, TRUE);
1018 if (!found && search_global)
1020 GPtrArray *global = tm_tags_extract (theWorkspace->global_tags,
1021 (tm_tag_member_t |
1022 tm_tag_prototype_t |
1023 tm_tag_field_t |
1024 tm_tag_method_t |
1025 tm_tag_function_t |
1026 tm_tag_enumerator_t |
1027 tm_tag_namespace_t |
1028 tm_tag_class_t ));
1030 if (global)
1032 find_namespace_members_tags (global, tags, langJava,
1033 new_name, filename);
1035 DEBUG_PRINT ("returning these");
1036 gint i;
1037 for (i=0; i < tags->len; i++) {
1038 TMTag *cur_tag;
1040 cur_tag = (TMTag*)g_ptr_array_index (tags, i);
1041 tm_tag_print (cur_tag, stdout );
1044 g_ptr_array_free (global, TRUE);
1049 if (del)
1051 g_free (new_name);
1054 return tags;
1056 #endif
1058 const GPtrArray *
1059 tm_workspace_find_scope_members (const GPtrArray * file_tags, const char *name,
1060 gboolean search_global, gboolean no_definitions)
1062 static GPtrArray *tags = NULL;
1063 GPtrArray *local = NULL;
1064 char *new_name = (char *) name;
1065 char *filename = NULL;
1066 int found = 0, del = 0;
1067 static langType langJava = -1;
1068 TMTag *tag = NULL;
1070 /* FIXME */
1071 /* langJava = getNamedLanguage ("Java"); */
1073 g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
1075 if (!tags)
1076 tags = g_ptr_array_new ();
1078 while (1)
1080 const GPtrArray *tags2;
1081 int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t |
1082 tm_tag_struct_t | tm_tag_typedef_t |
1083 tm_tag_union_t | tm_tag_enum_t);
1085 if (file_tags)
1087 g_ptr_array_set_size (tags, 0);
1088 got = fill_find_tags_array (tags, file_tags,
1089 new_name, NULL, types, FALSE, -1, FALSE);
1091 if (got)
1093 tags2 = tags;
1095 else
1097 TMTagAttrType attrs[] = {
1098 tm_tag_attr_name_t, tm_tag_attr_type_t,
1099 tm_tag_attr_none_t
1101 tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
1104 if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
1106 if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type
1107 && tag->atts.entry.var_type[0] != '\0')
1109 char *tmp_name;
1110 tmp_name = tag->atts.entry.var_type;
1111 if (strcmp(tmp_name, new_name) == 0) {
1112 new_name = NULL;
1114 else {
1115 new_name = tmp_name;
1117 continue;
1119 filename = (tag->atts.entry.file ?
1120 tag->atts.entry.file->work_object.short_name : NULL);
1121 if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
1123 del = 1;
1124 if (tag->atts.entry.file &&
1125 tag->atts.entry.file->lang == langJava)
1127 new_name = g_strdup_printf ("%s.%s",
1128 tag->atts.entry.scope,
1129 new_name);
1131 else
1133 new_name = g_strdup_printf ("%s::%s",
1134 tag->atts.entry.scope,
1135 new_name);
1138 break;
1140 else
1142 return NULL;
1146 g_ptr_array_set_size (tags, 0);
1148 if (no_definitions && tag && tag->atts.entry.file)
1150 local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array,
1151 (tm_tag_function_t | tm_tag_prototype_t |
1152 tm_tag_member_t | tm_tag_field_t |
1153 tm_tag_method_t | tm_tag_enumerator_t));
1155 else
1157 local = tm_tags_extract (theWorkspace->work_object.tags_array,
1158 (tm_tag_function_t | tm_tag_prototype_t |
1159 tm_tag_member_t | tm_tag_field_t |
1160 tm_tag_method_t | tm_tag_enumerator_t));
1162 if (local)
1164 found = find_scope_members_tags (local, tags, langJava, new_name,
1165 filename, no_definitions);
1166 g_ptr_array_free (local, TRUE);
1168 if (!found && search_global)
1170 GPtrArray *global = tm_tags_extract (theWorkspace->global_tags,
1171 (tm_tag_member_t |
1172 tm_tag_prototype_t |
1173 tm_tag_field_t |
1174 tm_tag_method_t |
1175 tm_tag_function_t |
1176 tm_tag_enumerator_t
1177 |tm_tag_struct_t | tm_tag_typedef_t |
1178 tm_tag_union_t | tm_tag_enum_t));
1179 if (global)
1181 find_scope_members_tags (global, tags, langJava, new_name,
1182 filename, no_definitions);
1183 g_ptr_array_free (global, TRUE);
1186 if (del)
1188 g_free (new_name);
1191 return tags;
1194 const GPtrArray *tm_workspace_get_parents(const gchar *name)
1196 static TMTagAttrType type[] = { tm_tag_attr_name_t, tm_tag_attr_none_t };
1197 static GPtrArray *parents = NULL;
1198 const GPtrArray *matches;
1199 guint i = 0;
1200 guint j;
1201 gchar **klasses;
1202 gchar **klass;
1203 TMTag *tag;
1205 g_return_val_if_fail(name && isalpha(*name),NULL);
1207 if (NULL == parents)
1208 parents = g_ptr_array_new();
1209 else
1210 g_ptr_array_set_size(parents, 0);
1211 matches = tm_workspace_find(name, tm_tag_class_t, type, FALSE, -1);
1212 if ((NULL == matches) || (0 == matches->len))
1213 return NULL;
1214 g_ptr_array_add(parents, matches->pdata[0]);
1215 while (i < parents->len)
1217 tag = TM_TAG(parents->pdata[i]);
1218 if ((NULL != tag->atts.entry.inheritance) && (isalpha(tag->atts.entry.inheritance[0])))
1220 klasses = g_strsplit(tag->atts.entry.inheritance, ",", 10);
1221 for (klass = klasses; (NULL != *klass); ++ klass)
1223 for (j=0; j < parents->len; ++j)
1225 if (0 == strcmp(*klass, TM_TAG(parents->pdata[j])->name))
1226 break;
1228 if (parents->len == j)
1230 matches = tm_workspace_find(*klass, tm_tag_class_t, type, FALSE, -1);
1231 if ((NULL != matches) && (0 < matches->len))
1232 g_ptr_array_add(parents, matches->pdata[0]);
1235 g_strfreev(klasses);
1237 ++ i;
1239 return parents;