r5123 | ntrel | 2010-08-10 17:12:24 +0100 (Tue, 10 Aug 2010) | 4 lines
[geany-mirror.git] / tagmanager / tm_workspace.c
blob6a1f8490c53f34359aca7e67d20f6f3d47817542
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 == theWorkspace)
151 return FALSE;
152 if (NULL == (fp = g_fopen(tags_file, "r")))
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))
158 fclose(fp);
159 return FALSE; /* early out on error */
161 else
162 { /* We read the first line for the format specification. */
163 if (buf[0] == '#' && strstr((gchar*) buf, "format=pipe") != NULL)
164 format_pipe = TRUE;
165 else if (buf[0] == '#' && strstr((gchar*) buf, "format=tagmanager") != NULL)
166 format_pipe = FALSE;
167 else
168 { /* We didn't find a valid format specification, so we try to auto-detect the format
169 * by counting the pipe characters on the first line and asumme pipe format when
170 * we find more than one pipe on the line. */
171 guint i, pipe_cnt = 0;
172 for (i = 0; i < BUFSIZ && buf[i] != '\0' && pipe_cnt < 2; i++)
174 if (buf[i] == '|')
175 pipe_cnt++;
177 format_pipe = (pipe_cnt > 1);
179 rewind(fp); /* reset the file pointer, to start reading again from the beginning */
181 while (NULL != (tag = tm_tag_new_from_file(NULL, fp, mode, format_pipe)))
182 g_ptr_array_add(theWorkspace->global_tags, tag);
183 fclose(fp);
185 /* resort the whole array, because tm_tags_find expects a sorted array and it is not sorted
186 * when c99.tags, php.tags and latex.tags are loaded at the same time */
187 tm_tags_sort(theWorkspace->global_tags, global_tags_sort_attrs, TRUE);
189 return TRUE;
192 static guint tm_file_inode_hash(gconstpointer key)
194 struct stat file_stat;
195 const char *filename = (const char*)key;
196 if (g_stat(filename, &file_stat) == 0)
198 #ifdef TM_DEBUG
199 g_message ("Hash for '%s' is '%d'\n", filename, file_stat.st_ino);
200 #endif
201 return g_direct_hash (GUINT_TO_POINTER (file_stat.st_ino));
202 } else {
203 return 0;
207 static void tm_move_entries_to_g_list(gpointer key, gpointer value, gpointer user_data)
209 GList **pp_list = (GList**)user_data;
211 if (user_data == NULL)
212 return;
214 *pp_list = g_list_prepend(*pp_list, value);
217 static void write_includes_file(FILE *fp, GList *includes_files)
219 GList *node;
221 node = includes_files;
222 while (node)
224 char *str = g_strdup_printf("#include \"%s\"\n", (char*)node->data);
225 int str_len = strlen(str);
226 size_t size;
228 size = fwrite(str, str_len, 1, fp);
229 g_free(str);
230 node = g_list_next (node);
235 static void append_to_temp_file(FILE *fp, GList *file_list)
237 GList *node;
239 node = file_list;
240 while (node)
242 const char *fname = node->data;
243 char *contents;
244 size_t length;
245 GError *err = NULL;
247 if (! g_file_get_contents(fname, &contents, &length, &err))
249 fprintf(stderr, "Unable to read file: %s\n", err->message);
250 g_error_free(err);
252 else
254 size_t size;
255 size = fwrite(contents, length, 1, fp);
256 size = fwrite("\n", 1, 1, fp); /* in case file doesn't end in newline (e.g. windows). */
257 g_free(contents);
259 node = g_list_next (node);
263 gboolean tm_workspace_create_global_tags(const char *config_dir, const char *pre_process,
264 const char **includes, int includes_count, const char *tags_file, int lang)
266 #ifdef HAVE_GLOB_H
267 glob_t globbuf;
268 size_t idx_glob;
269 #endif
270 int idx_inc;
271 char *command;
272 guint i;
273 FILE *fp;
274 TMWorkObject *source_file;
275 GPtrArray *tags_array;
276 GHashTable *includes_files_hash;
277 GList *includes_files = NULL;
278 #ifdef G_OS_WIN32
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 #else
282 char *temp_file = g_strdup_printf("%s/%d_%ld_1.cpp", config_dir, getpid(), time(NULL));
283 char *temp_file2 = g_strdup_printf("%s/%d_%ld_2.cpp", config_dir, getpid(), time(NULL));
284 #endif
286 if (NULL == theWorkspace || NULL == (fp = g_fopen(temp_file, "w")))
288 g_free(temp_file);
289 g_free(temp_file2);
290 return FALSE;
293 includes_files_hash = g_hash_table_new_full (tm_file_inode_hash,
294 g_direct_equal,
295 NULL, g_free);
297 #ifdef HAVE_GLOB_H
298 globbuf.gl_offs = 0;
300 if (includes[0][0] == '"') /* leading \" char for glob matching */
301 for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
303 int dirty_len = strlen(includes[idx_inc]);
304 char *clean_path = g_malloc(dirty_len - 1);
306 strncpy(clean_path, includes[idx_inc] + 1, dirty_len - 1);
307 clean_path[dirty_len - 2] = 0;
309 #ifdef TM_DEBUG
310 g_message ("[o][%s]\n", clean_path);
311 #endif
312 glob(clean_path, 0, NULL, &globbuf);
314 #ifdef TM_DEBUG
315 g_message ("matches: %d\n", globbuf.gl_pathc);
316 #endif
318 for(idx_glob = 0; idx_glob < globbuf.gl_pathc; idx_glob++)
320 #ifdef TM_DEBUG
321 g_message (">>> %s\n", globbuf.gl_pathv[idx_glob]);
322 #endif
323 if (!g_hash_table_lookup(includes_files_hash,
324 globbuf.gl_pathv[idx_glob]))
326 char* file_name_copy = strdup(globbuf.gl_pathv[idx_glob]);
327 g_hash_table_insert(includes_files_hash, file_name_copy,
328 file_name_copy);
329 #ifdef TM_DEBUG
330 g_message ("Added ...\n");
331 #endif
334 globfree(&globbuf);
335 g_free(clean_path);
337 else
338 #endif
339 /* no glob support or globbing not wanted */
340 for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
342 if (!g_hash_table_lookup(includes_files_hash,
343 includes[idx_inc]))
345 char* file_name_copy = strdup(includes[idx_inc]);
346 g_hash_table_insert(includes_files_hash, file_name_copy,
347 file_name_copy);
351 /* Checks for duplicate file entries which would case trouble */
352 g_hash_table_foreach(includes_files_hash, tm_move_entries_to_g_list,
353 &includes_files);
355 includes_files = g_list_reverse (includes_files);
357 #ifdef TM_DEBUG
358 g_message ("writing out files to %s\n", temp_file);
359 #endif
360 if (pre_process != NULL)
361 write_includes_file(fp, includes_files);
362 else
363 append_to_temp_file(fp, includes_files);
365 g_list_free (includes_files);
366 g_hash_table_destroy(includes_files_hash);
367 includes_files_hash = NULL;
368 includes_files = NULL;
369 fclose(fp);
371 /* FIXME: The following grep command removes the lines
372 * G_BEGIN_DECLS and G_END_DECLS from the header files. The reason is
373 * that in tagmanager, the files are not correctly parsed and the typedefs
374 * following these lines are incorrectly parsed. The real fix should,
375 * of course be in tagmanager (c) parser. This is just a temporary fix.
377 if (pre_process != NULL)
379 int ret;
380 command = g_strdup_printf("%s %s | grep -v -E '^\\s*(G_BEGIN_DECLS|G_END_DECLS)\\s*$' > %s",
381 pre_process, temp_file, temp_file2);
382 #ifdef TM_DEBUG
383 g_message("Executing: %s", command);
384 #endif
385 ret = system(command);
386 g_free(command);
387 g_unlink(temp_file);
388 g_free(temp_file);
390 else
392 /* no pre-processing needed, so temp_file2 = temp_file */
393 g_free(temp_file2);
394 temp_file2 = temp_file;
395 temp_file = NULL;
397 source_file = tm_source_file_new(temp_file2, TRUE, tm_source_file_get_lang_name(lang));
398 if (NULL == source_file)
400 g_unlink(temp_file2);
401 return FALSE;
403 g_unlink(temp_file2);
404 g_free(temp_file2);
405 if ((NULL == source_file->tags_array) || (0 == source_file->tags_array->len))
407 tm_source_file_free(source_file);
408 return FALSE;
410 tags_array = tm_tags_extract(source_file->tags_array, tm_tag_max_t);
411 if ((NULL == tags_array) || (0 == tags_array->len))
413 if (tags_array)
414 g_ptr_array_free(tags_array, TRUE);
415 tm_source_file_free(source_file);
416 return FALSE;
418 if (FALSE == tm_tags_sort(tags_array, global_tags_sort_attrs, TRUE))
420 tm_source_file_free(source_file);
421 return FALSE;
423 if (NULL == (fp = g_fopen(tags_file, "w")))
425 tm_source_file_free(source_file);
426 return FALSE;
428 fprintf(fp, "# format=tagmanager\n");
429 for (i = 0; i < tags_array->len; ++i)
431 tm_tag_write(TM_TAG(tags_array->pdata[i]), fp, tm_tag_attr_type_t
432 | tm_tag_attr_scope_t | tm_tag_attr_arglist_t | tm_tag_attr_vartype_t
433 | tm_tag_attr_pointer_t);
435 fclose(fp);
436 tm_source_file_free(source_file);
437 g_ptr_array_free(tags_array, TRUE);
438 return TRUE;
441 TMWorkObject *tm_workspace_find_object(TMWorkObject *work_object, const char *file_name
442 , gboolean name_only)
444 TMWorkObject *w = NULL;
445 guint i;
447 if (work_object != TM_WORK_OBJECT(theWorkspace))
448 return NULL;
449 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects)
450 || (0 == theWorkspace->work_objects->len))
451 return NULL;
452 for (i = 0; i < theWorkspace->work_objects->len; ++i)
454 if (NULL != (w = tm_work_object_find(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])
455 , file_name, name_only)))
456 return w;
458 return NULL;
461 void tm_workspace_recreate_tags_array(void)
463 guint i, j;
464 TMWorkObject *w;
465 TMTagAttrType sort_attrs[] = { tm_tag_attr_name_t, tm_tag_attr_file_t
466 , tm_tag_attr_scope_t, tm_tag_attr_type_t, tm_tag_attr_arglist_t, 0};
468 #ifdef TM_DEBUG
469 g_message("Recreating workspace tags array");
470 #endif
472 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects))
473 return;
474 if (NULL != theWorkspace->work_object.tags_array)
475 g_ptr_array_set_size(theWorkspace->work_object.tags_array, 0);
476 else
477 theWorkspace->work_object.tags_array = g_ptr_array_new();
479 #ifdef TM_DEBUG
480 g_message("Total %d objects", theWorkspace->work_objects->len);
481 #endif
482 for (i=0; i < theWorkspace->work_objects->len; ++i)
484 w = TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]);
485 #ifdef TM_DEBUG
486 g_message("Adding tags of %s", w->file_name);
487 #endif
488 if ((NULL != w) && (NULL != w->tags_array) && (w->tags_array->len > 0))
490 for (j = 0; j < w->tags_array->len; ++j)
492 g_ptr_array_add(theWorkspace->work_object.tags_array,
493 w->tags_array->pdata[j]);
497 #ifdef TM_DEBUG
498 g_message("Total: %d tags", theWorkspace->work_object.tags_array->len);
499 #endif
500 tm_tags_sort(theWorkspace->work_object.tags_array, sort_attrs, TRUE);
503 gboolean tm_workspace_update(TMWorkObject *workspace, gboolean force
504 , gboolean recurse, gboolean __unused__ update_parent)
506 guint i;
507 gboolean update_tags = force;
509 #ifdef TM_DEBUG
510 g_message("Updating workspace");
511 #endif
513 if (workspace != TM_WORK_OBJECT(theWorkspace))
514 return FALSE;
515 if (NULL == theWorkspace)
516 return TRUE;
517 if ((recurse) && (theWorkspace->work_objects))
519 for (i=0; i < theWorkspace->work_objects->len; ++i)
521 if (TRUE == tm_work_object_update(TM_WORK_OBJECT(
522 theWorkspace->work_objects->pdata[i]), FALSE, TRUE, FALSE))
523 update_tags = TRUE;
526 if (update_tags)
527 tm_workspace_recreate_tags_array();
528 /* workspace->analyze_time = time(NULL); */
529 return update_tags;
532 void tm_workspace_dump(void)
534 if (theWorkspace)
536 #ifdef TM_DEBUG
537 g_message("Dumping TagManager workspace tree..");
538 #endif
539 tm_work_object_dump(TM_WORK_OBJECT(theWorkspace));
540 if (theWorkspace->work_objects)
542 guint i;
543 for (i=0; i < theWorkspace->work_objects->len; ++i)
545 if (IS_TM_PROJECT(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])))
546 tm_project_dump(TM_PROJECT(theWorkspace->work_objects->pdata[i]));
547 else
548 tm_work_object_dump(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]));
554 const GPtrArray *tm_workspace_find(const char *name, int type, TMTagAttrType *attrs
555 , gboolean partial, langType lang)
557 static GPtrArray *tags = NULL;
558 TMTag **matches[2];
559 int len, tagCount[2]={0,0}, tagIter;
560 gint tags_lang;
562 if ((!theWorkspace) || (!name))
563 return NULL;
564 len = strlen(name);
565 if (!len)
566 return NULL;
567 if (tags)
568 g_ptr_array_set_size(tags, 0);
569 else
570 tags = g_ptr_array_new();
572 matches[0] = tm_tags_find(theWorkspace->work_object.tags_array, name, partial, &tagCount[0]);
573 matches[1] = tm_tags_find(theWorkspace->global_tags, name, partial, &tagCount[1]);
575 /* file tags */
576 if (matches[0] && *matches[0])
578 /* tag->atts.file.lang contains the line of the tag and
579 * tags->atts.entry.file->lang contains the language */
580 tags_lang = (*matches[0])->atts.entry.file->lang;
582 for (tagIter=0;tagIter<tagCount[0];++tagIter)
584 if ((type & (*matches[0])->type) && (lang == -1 || tags_lang == lang))
585 g_ptr_array_add(tags, *matches[0]);
586 if (partial)
588 if (0 != strncmp((*matches[0])->name, name, len))
589 break;
591 else
593 if (0 != strcmp((*matches[0])->name, name))
594 break;
596 ++ matches[0];
600 /* global tags */
601 if (matches[1] && *matches[1])
603 int tags_lang_alt = 0;
604 /* tag->atts.file.lang contains the language and
605 * tags->atts.entry.file is NULL */
606 tags_lang = (*matches[1])->atts.file.lang;
607 /* tags_lang_alt is used to load C global tags only once for C and C++
608 * lang = 1 is C++, lang = 0 is C
609 * if we have lang 0, than accept also lang 1 for C++ */
610 if (tags_lang == 0) /* C or C++ */
611 tags_lang_alt = 1;
612 else
613 tags_lang_alt = tags_lang; /* otherwise just ignore it */
615 for (tagIter=0;tagIter<tagCount[1];++tagIter)
617 if ((type & (*matches[1])->type) && (lang == -1 ||
618 tags_lang == lang || tags_lang_alt == lang))
619 g_ptr_array_add(tags, *matches[1]);
621 if (partial)
623 if (0 != strncmp((*matches[1])->name, name, len))
624 break;
626 else
628 if (0 != strcmp((*matches[1])->name, name))
629 break;
631 ++ matches[1];
635 if (attrs)
636 tm_tags_sort(tags, attrs, TRUE);
637 return tags;
640 static gboolean match_langs(gint lang, const TMTag *tag)
642 if (tag->atts.entry.file)
643 { /* workspace tag */
644 if (lang == tag->atts.entry.file->lang)
645 return TRUE;
647 else
648 { /* global tag */
649 if (lang == tag->atts.file.lang)
650 return TRUE;
652 return FALSE;
655 /* scope can be NULL.
656 * lang can be -1 */
657 static int
658 fill_find_tags_array (GPtrArray *dst, const GPtrArray *src,
659 const char *name, const char *scope, int type, gboolean partial,
660 gint lang, gboolean first)
662 TMTag **match;
663 int tagIter, count;
665 if ((!src) || (!dst) || (!name) || (!*name))
666 return 0;
668 match = tm_tags_find (src, name, partial, &count);
669 if (count && match && *match)
671 for (tagIter = 0; tagIter < count; ++tagIter)
673 if (! scope || (match[tagIter]->atts.entry.scope &&
674 0 == strcmp(match[tagIter]->atts.entry.scope, scope)))
676 if (type & match[tagIter]->type)
677 if (lang == -1 || match_langs(lang, match[tagIter]))
679 g_ptr_array_add (dst, match[tagIter]);
680 if (first)
681 break;
686 return dst->len;
690 /* adapted from tm_workspace_find, Anjuta 2.02 */
691 const GPtrArray *
692 tm_workspace_find_scoped (const char *name, const char *scope, gint type,
693 TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search)
695 static GPtrArray *tags = NULL;
697 if ((!theWorkspace))
698 return NULL;
700 if (tags)
701 g_ptr_array_set_size (tags, 0);
702 else
703 tags = g_ptr_array_new ();
705 fill_find_tags_array (tags, theWorkspace->work_object.tags_array,
706 name, scope, type, partial, lang, FALSE);
707 if (global_search)
709 /* for a scoped tag, I think we always want the same language */
710 fill_find_tags_array (tags, theWorkspace->global_tags,
711 name, scope, type, partial, lang, FALSE);
713 if (attrs)
714 tm_tags_sort (tags, attrs, TRUE);
715 return tags;
719 const TMTag *
720 tm_get_current_function (GPtrArray * file_tags, const gulong line)
722 GPtrArray *const local = tm_tags_extract (file_tags, tm_tag_function_t);
723 if (local && local->len)
725 guint i;
726 TMTag *tag, *function_tag = NULL;
727 gulong function_line = 0;
728 glong delta;
730 for (i = 0; (i < local->len); ++i)
732 tag = TM_TAG (local->pdata[i]);
733 delta = line - tag->atts.entry.line;
734 if (delta >= 0 && (gulong)delta < line - function_line)
736 function_tag = tag;
737 function_line = tag->atts.entry.line;
740 g_ptr_array_free (local, TRUE);
741 return function_tag;
743 return NULL;
747 static int
748 find_scope_members_tags (const GPtrArray * all, GPtrArray * tags,
749 const langType langJava, const char *name,
750 const char *filename, gboolean no_definitions)
752 GPtrArray *local = g_ptr_array_new ();
753 unsigned int i;
754 TMTag *tag;
755 size_t len = strlen (name);
756 for (i = 0; (i < all->len); ++i)
758 tag = TM_TAG (all->pdata[i]);
759 if (no_definitions && filename && tag->atts.entry.file &&
760 0 != strcmp (filename,
761 tag->atts.entry.file->work_object.short_name))
763 continue;
765 if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
767 if (0 == strncmp (name, tag->atts.entry.scope, len))
769 g_ptr_array_add (local, tag);
773 if (local->len > 0)
775 unsigned int j;
776 TMTag *tag2;
777 char backup = 0;
778 char *s_backup = NULL;
779 char *var_type = NULL;
780 char *scope;
781 for (i = 0; (i < local->len); ++i)
783 tag = TM_TAG (local->pdata[i]);
784 scope = tag->atts.entry.scope;
785 if (scope && 0 == strcmp (name, scope))
787 g_ptr_array_add (tags, tag);
788 continue;
790 s_backup = NULL;
791 j = 0; /* someone could write better code :P */
792 while (scope)
794 if (s_backup)
796 backup = s_backup[0];
797 s_backup[0] = '\0';
798 if (0 == strcmp (name, tag->atts.entry.scope))
800 j = local->len;
801 s_backup[0] = backup;
802 break;
805 if (tag->atts.entry.file
806 && tag->atts.entry.file->lang == langJava)
808 scope = strrchr (tag->atts.entry.scope, '.');
809 if (scope)
810 var_type = scope + 1;
812 else
814 scope = strrchr (tag->atts.entry.scope, ':');
815 if (scope)
817 var_type = scope + 1;
818 scope--;
821 if (s_backup)
823 s_backup[0] = backup;
825 if (scope)
827 if (s_backup)
829 backup = s_backup[0];
830 s_backup[0] = '\0';
832 for (j = 0; (j < local->len); ++j)
834 if (i == j)
835 continue;
836 tag2 = TM_TAG (local->pdata[j]);
837 if (tag2->atts.entry.var_type &&
838 0 == strcmp (var_type, tag2->atts.entry.var_type))
840 break;
843 if (s_backup)
844 s_backup[0] = backup;
846 if (j < local->len)
848 break;
850 s_backup = scope;
852 if (j == local->len)
854 g_ptr_array_add (tags, tag);
858 g_ptr_array_free (local, TRUE);
859 return (int) tags->len;
863 #if 0
864 static int
865 find_namespace_members_tags (const GPtrArray * all, GPtrArray * tags,
866 const langType langJava, const char *name,
867 const char *filename)
869 GPtrArray *local = g_ptr_array_new ();
870 unsigned int i;
871 TMTag *tag;
872 size_t len = strlen (name);
874 g_return_val_if_fail (all != NULL, 0);
876 for (i = 0; (i < all->len); ++i)
878 tag = TM_TAG (all->pdata[i]);
879 if (filename && tag->atts.entry.file &&
880 0 != strcmp (filename,
881 tag->atts.entry.file->work_object.short_name))
883 continue;
886 if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
888 if (0 == strncmp (name, tag->atts.entry.scope, len))
890 g_ptr_array_add (local, tag);
895 if (local->len > 0)
897 char *scope;
898 for (i = 0; (i < local->len); ++i)
900 tag = TM_TAG (local->pdata[i]);
901 scope = tag->atts.entry.scope;
903 /* if we wanna complete something like
904 * namespace1::
905 * we'll just return the tags that have "namespace1"
906 * as their scope. So we won't return classes/members/namespaces
907 * under, for example, namespace2, where namespace1::namespace2
909 if (scope && 0 == strcmp (name, scope))
911 g_ptr_array_add (tags, tag);
916 g_ptr_array_free (local, TRUE);
917 return (int) tags->len;
920 const GPtrArray *
921 tm_workspace_find_namespace_members (const GPtrArray * file_tags, const char *name,
922 gboolean search_global)
924 static GPtrArray *tags = NULL;
925 GPtrArray *local = NULL;
926 char *new_name = (char *) name;
927 char *filename = NULL;
928 int found = 0, del = 0;
929 static langType langJava = -1;
930 TMTag *tag = NULL;
932 g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
934 if (!tags)
935 tags = g_ptr_array_new ();
937 while (1)
939 const GPtrArray *tags2;
940 int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t |
941 tm_tag_struct_t | tm_tag_typedef_t |
942 tm_tag_union_t | tm_tag_enum_t);
944 if (file_tags)
946 g_ptr_array_set_size (tags, 0);
947 got = fill_find_tags_array (tags, file_tags,
948 new_name, NULL, types, FALSE, -1, FALSE);
952 if (got)
954 tags2 = tags;
956 else
958 TMTagAttrType attrs[] = {
959 tm_tag_attr_name_t, tm_tag_attr_type_t,
960 tm_tag_attr_none_t
962 tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
965 if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
967 if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type
968 && tag->atts.entry.var_type[0] != '\0')
970 new_name = tag->atts.entry.var_type;
971 continue;
973 filename = (tag->atts.entry.file ?
974 tag->atts.entry.file->work_object.short_name : NULL);
975 if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
977 del = 1;
978 if (tag->atts.entry.file &&
979 tag->atts.entry.file->lang == langJava)
981 new_name = g_strdup_printf ("%s.%s",
982 tag->atts.entry.scope,
983 new_name);
985 else
987 new_name = g_strdup_printf ("%s::%s",
988 tag->atts.entry.scope,
989 new_name);
992 break;
994 else
996 return NULL;
1000 g_ptr_array_set_size (tags, 0);
1002 if (tag && tag->atts.entry.file)
1004 local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array,
1005 (tm_tag_function_t |
1006 tm_tag_field_t | tm_tag_enumerator_t |
1007 tm_tag_namespace_t | tm_tag_class_t ));
1009 else
1011 local = tm_tags_extract (theWorkspace->work_object.tags_array,
1012 (tm_tag_function_t | tm_tag_prototype_t |
1013 tm_tag_member_t |
1014 tm_tag_field_t | tm_tag_enumerator_t |
1015 tm_tag_namespace_t | tm_tag_class_t ));
1018 if (local)
1020 found = find_namespace_members_tags (local, tags,
1021 langJava, new_name, filename);
1022 g_ptr_array_free (local, TRUE);
1026 if (!found && search_global)
1028 GPtrArray *global = tm_tags_extract (theWorkspace->global_tags,
1029 (tm_tag_member_t |
1030 tm_tag_prototype_t |
1031 tm_tag_field_t |
1032 tm_tag_method_t |
1033 tm_tag_function_t |
1034 tm_tag_enumerator_t |
1035 tm_tag_namespace_t |
1036 tm_tag_class_t ));
1038 if (global)
1040 find_namespace_members_tags (global, tags, langJava,
1041 new_name, filename);
1043 DEBUG_PRINT ("returning these");
1044 gint i;
1045 for (i=0; i < tags->len; i++) {
1046 TMTag *cur_tag;
1048 cur_tag = (TMTag*)g_ptr_array_index (tags, i);
1049 tm_tag_print (cur_tag, stdout );
1052 g_ptr_array_free (global, TRUE);
1057 if (del)
1059 g_free (new_name);
1062 return tags;
1064 #endif
1066 const GPtrArray *
1067 tm_workspace_find_scope_members (const GPtrArray * file_tags, const char *name,
1068 gboolean search_global, gboolean no_definitions)
1070 static GPtrArray *tags = NULL;
1071 GPtrArray *local = NULL;
1072 char *new_name = (char *) name;
1073 char *filename = NULL;
1074 int found = 0, del = 0;
1075 static langType langJava = -1;
1076 TMTag *tag = NULL;
1078 /* FIXME */
1079 /* langJava = getNamedLanguage ("Java"); */
1081 g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
1083 if (!tags)
1084 tags = g_ptr_array_new ();
1086 while (1)
1088 const GPtrArray *tags2;
1089 int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t |
1090 tm_tag_struct_t | tm_tag_typedef_t |
1091 tm_tag_union_t | tm_tag_enum_t);
1093 if (file_tags)
1095 g_ptr_array_set_size (tags, 0);
1096 got = fill_find_tags_array (tags, file_tags,
1097 new_name, NULL, types, FALSE, -1, FALSE);
1099 if (got)
1101 tags2 = tags;
1103 else
1105 TMTagAttrType attrs[] = {
1106 tm_tag_attr_name_t, tm_tag_attr_type_t,
1107 tm_tag_attr_none_t
1109 tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
1112 if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
1114 if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type
1115 && tag->atts.entry.var_type[0] != '\0')
1117 char *tmp_name;
1118 tmp_name = tag->atts.entry.var_type;
1119 if (strcmp(tmp_name, new_name) == 0) {
1120 new_name = NULL;
1122 else {
1123 new_name = tmp_name;
1125 continue;
1127 filename = (tag->atts.entry.file ?
1128 tag->atts.entry.file->work_object.short_name : NULL);
1129 if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
1131 del = 1;
1132 if (tag->atts.entry.file &&
1133 tag->atts.entry.file->lang == langJava)
1135 new_name = g_strdup_printf ("%s.%s",
1136 tag->atts.entry.scope,
1137 new_name);
1139 else
1141 new_name = g_strdup_printf ("%s::%s",
1142 tag->atts.entry.scope,
1143 new_name);
1146 break;
1148 else
1150 return NULL;
1154 g_ptr_array_set_size (tags, 0);
1156 if (no_definitions && tag && tag->atts.entry.file)
1158 local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array,
1159 (tm_tag_function_t | tm_tag_prototype_t |
1160 tm_tag_member_t | tm_tag_field_t |
1161 tm_tag_method_t | tm_tag_enumerator_t));
1163 else
1165 local = tm_tags_extract (theWorkspace->work_object.tags_array,
1166 (tm_tag_function_t | tm_tag_prototype_t |
1167 tm_tag_member_t | tm_tag_field_t |
1168 tm_tag_method_t | tm_tag_enumerator_t));
1170 if (local)
1172 found = find_scope_members_tags (local, tags, langJava, new_name,
1173 filename, no_definitions);
1174 g_ptr_array_free (local, TRUE);
1176 if (!found && search_global)
1178 GPtrArray *global = tm_tags_extract (theWorkspace->global_tags,
1179 (tm_tag_member_t |
1180 tm_tag_prototype_t |
1181 tm_tag_field_t |
1182 tm_tag_method_t |
1183 tm_tag_function_t |
1184 tm_tag_enumerator_t
1185 |tm_tag_struct_t | tm_tag_typedef_t |
1186 tm_tag_union_t | tm_tag_enum_t));
1187 if (global)
1189 find_scope_members_tags (global, tags, langJava, new_name,
1190 filename, no_definitions);
1191 g_ptr_array_free (global, TRUE);
1194 if (del)
1196 g_free (new_name);
1199 return tags;
1202 const GPtrArray *tm_workspace_get_parents(const gchar *name)
1204 static TMTagAttrType type[] = { tm_tag_attr_name_t, tm_tag_attr_none_t };
1205 static GPtrArray *parents = NULL;
1206 const GPtrArray *matches;
1207 guint i = 0;
1208 guint j;
1209 gchar **klasses;
1210 gchar **klass;
1211 TMTag *tag;
1213 g_return_val_if_fail(name && isalpha(*name),NULL);
1215 if (NULL == parents)
1216 parents = g_ptr_array_new();
1217 else
1218 g_ptr_array_set_size(parents, 0);
1219 matches = tm_workspace_find(name, tm_tag_class_t, type, FALSE, -1);
1220 if ((NULL == matches) || (0 == matches->len))
1221 return NULL;
1222 g_ptr_array_add(parents, matches->pdata[0]);
1223 while (i < parents->len)
1225 tag = TM_TAG(parents->pdata[i]);
1226 if ((NULL != tag->atts.entry.inheritance) && (isalpha(tag->atts.entry.inheritance[0])))
1228 klasses = g_strsplit(tag->atts.entry.inheritance, ",", 10);
1229 for (klass = klasses; (NULL != *klass); ++ klass)
1231 for (j=0; j < parents->len; ++j)
1233 if (0 == strcmp(*klass, TM_TAG(parents->pdata[j])->name))
1234 break;
1236 if (parents->len == j)
1238 matches = tm_workspace_find(*klass, tm_tag_class_t, type, FALSE, -1);
1239 if ((NULL != matches) && (0 < matches->len))
1240 g_ptr_array_add(parents, matches->pdata[0]);
1243 g_strfreev(klasses);
1245 ++ i;
1247 return parents;