Create branch for 0.19.1 release (copied from 0.19).
[geany-mirror.git] / tagmanager / tm_workspace.c
blob559bdf3075e3e7920021a642cd0607c1c514095f
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 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);
305 strncpy(clean_path, includes[idx_inc] + 1, dirty_len - 1);
306 clean_path[dirty_len - 2] = 0;
308 #ifdef TM_DEBUG
309 g_message ("[o][%s]\n", clean_path);
310 #endif
311 glob(clean_path, 0, NULL, &globbuf);
313 #ifdef TM_DEBUG
314 g_message ("matches: %d\n", globbuf.gl_pathc);
315 #endif
317 for(idx_glob = 0; idx_glob < globbuf.gl_pathc; idx_glob++)
319 #ifdef TM_DEBUG
320 g_message (">>> %s\n", globbuf.gl_pathv[idx_glob]);
321 #endif
322 if (!g_hash_table_lookup(includes_files_hash,
323 globbuf.gl_pathv[idx_glob]))
325 char* file_name_copy = strdup(globbuf.gl_pathv[idx_glob]);
326 g_hash_table_insert(includes_files_hash, file_name_copy,
327 file_name_copy);
328 #ifdef TM_DEBUG
329 g_message ("Added ...\n");
330 #endif
333 globfree(&globbuf);
334 free(clean_path);
336 else
337 #endif
338 /* no glob support or globbing not wanted */
339 for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
341 if (!g_hash_table_lookup(includes_files_hash,
342 includes[idx_inc]))
344 char* file_name_copy = strdup(includes[idx_inc]);
345 g_hash_table_insert(includes_files_hash, file_name_copy,
346 file_name_copy);
350 /* Checks for duplicate file entries which would case trouble */
351 g_hash_table_foreach(includes_files_hash, tm_move_entries_to_g_list,
352 &includes_files);
354 includes_files = g_list_reverse (includes_files);
356 #ifdef TM_DEBUG
357 g_message ("writing out files to %s\n", temp_file);
358 #endif
359 if (pre_process != NULL)
360 write_includes_file(fp, includes_files);
361 else
362 append_to_temp_file(fp, includes_files);
364 g_list_free (includes_files);
365 g_hash_table_destroy(includes_files_hash);
366 includes_files_hash = NULL;
367 includes_files = NULL;
368 fclose(fp);
370 /* FIXME: The following grep command removes the lines
371 * G_BEGIN_DECLS and G_END_DECLS from the header files. The reason is
372 * that in tagmanager, the files are not correctly parsed and the typedefs
373 * following these lines are incorrectly parsed. The real fix should,
374 * of course be in tagmanager (c) parser. This is just a temporary fix.
376 if (pre_process != NULL)
378 int ret;
379 command = g_strdup_printf("%s %s | grep -v -E '^\\s*(G_BEGIN_DECLS|G_END_DECLS)\\s*$' > %s",
380 pre_process, temp_file, temp_file2);
381 #ifdef TM_DEBUG
382 g_message("Executing: %s", command);
383 #endif
384 ret = system(command);
385 g_free(command);
386 g_unlink(temp_file);
387 g_free(temp_file);
389 else
391 /* no pre-processing needed, so temp_file2 = temp_file */
392 g_free(temp_file2);
393 temp_file2 = temp_file;
394 temp_file = NULL;
396 source_file = tm_source_file_new(temp_file2, TRUE, tm_source_file_get_lang_name(lang));
397 if (NULL == source_file)
399 g_unlink(temp_file2);
400 return FALSE;
402 g_unlink(temp_file2);
403 g_free(temp_file2);
404 if ((NULL == source_file->tags_array) || (0 == source_file->tags_array->len))
406 tm_source_file_free(source_file);
407 return FALSE;
409 tags_array = tm_tags_extract(source_file->tags_array, tm_tag_max_t);
410 if ((NULL == tags_array) || (0 == tags_array->len))
412 if (tags_array)
413 g_ptr_array_free(tags_array, TRUE);
414 tm_source_file_free(source_file);
415 return FALSE;
417 if (FALSE == tm_tags_sort(tags_array, global_tags_sort_attrs, TRUE))
419 tm_source_file_free(source_file);
420 return FALSE;
422 if (NULL == (fp = g_fopen(tags_file, "w")))
424 tm_source_file_free(source_file);
425 return FALSE;
427 fprintf(fp, "# format=tagmanager\n");
428 for (i = 0; i < tags_array->len; ++i)
430 tm_tag_write(TM_TAG(tags_array->pdata[i]), fp, tm_tag_attr_type_t
431 | tm_tag_attr_scope_t | tm_tag_attr_arglist_t | tm_tag_attr_vartype_t
432 | tm_tag_attr_pointer_t);
434 fclose(fp);
435 tm_source_file_free(source_file);
436 g_ptr_array_free(tags_array, TRUE);
437 return TRUE;
440 TMWorkObject *tm_workspace_find_object(TMWorkObject *work_object, const char *file_name
441 , gboolean name_only)
443 TMWorkObject *w = NULL;
444 guint i;
446 if (work_object != TM_WORK_OBJECT(theWorkspace))
447 return NULL;
448 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects)
449 || (0 == theWorkspace->work_objects->len))
450 return NULL;
451 for (i = 0; i < theWorkspace->work_objects->len; ++i)
453 if (NULL != (w = tm_work_object_find(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])
454 , file_name, name_only)))
455 return w;
457 return NULL;
460 void tm_workspace_recreate_tags_array(void)
462 guint i, j;
463 TMWorkObject *w;
464 TMTagAttrType sort_attrs[] = { tm_tag_attr_name_t, tm_tag_attr_file_t
465 , tm_tag_attr_scope_t, tm_tag_attr_type_t, tm_tag_attr_arglist_t, 0};
467 #ifdef TM_DEBUG
468 g_message("Recreating workspace tags array");
469 #endif
471 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects))
472 return;
473 if (NULL != theWorkspace->work_object.tags_array)
474 g_ptr_array_set_size(theWorkspace->work_object.tags_array, 0);
475 else
476 theWorkspace->work_object.tags_array = g_ptr_array_new();
478 #ifdef TM_DEBUG
479 g_message("Total %d objects", theWorkspace->work_objects->len);
480 #endif
481 for (i=0; i < theWorkspace->work_objects->len; ++i)
483 w = TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]);
484 #ifdef TM_DEBUG
485 g_message("Adding tags of %s", w->file_name);
486 #endif
487 if ((NULL != w) && (NULL != w->tags_array) && (w->tags_array->len > 0))
489 for (j = 0; j < w->tags_array->len; ++j)
491 g_ptr_array_add(theWorkspace->work_object.tags_array,
492 w->tags_array->pdata[j]);
496 #ifdef TM_DEBUG
497 g_message("Total: %d tags", theWorkspace->work_object.tags_array->len);
498 #endif
499 tm_tags_sort(theWorkspace->work_object.tags_array, sort_attrs, TRUE);
502 gboolean tm_workspace_update(TMWorkObject *workspace, gboolean force
503 , gboolean recurse, gboolean __unused__ update_parent)
505 guint i;
506 gboolean update_tags = force;
508 #ifdef TM_DEBUG
509 g_message("Updating workspace");
510 #endif
512 if (workspace != TM_WORK_OBJECT(theWorkspace))
513 return FALSE;
514 if (NULL == theWorkspace)
515 return TRUE;
516 if ((recurse) && (theWorkspace->work_objects))
518 for (i=0; i < theWorkspace->work_objects->len; ++i)
520 if (TRUE == tm_work_object_update(TM_WORK_OBJECT(
521 theWorkspace->work_objects->pdata[i]), FALSE, TRUE, FALSE))
522 update_tags = TRUE;
525 if (update_tags)
526 tm_workspace_recreate_tags_array();
527 /* workspace->analyze_time = time(NULL); */
528 return update_tags;
531 void tm_workspace_dump(void)
533 if (theWorkspace)
535 #ifdef TM_DEBUG
536 g_message("Dumping TagManager workspace tree..");
537 #endif
538 tm_work_object_dump(TM_WORK_OBJECT(theWorkspace));
539 if (theWorkspace->work_objects)
541 guint i;
542 for (i=0; i < theWorkspace->work_objects->len; ++i)
544 if (IS_TM_PROJECT(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])))
545 tm_project_dump(TM_PROJECT(theWorkspace->work_objects->pdata[i]));
546 else
547 tm_work_object_dump(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]));
553 const GPtrArray *tm_workspace_find(const char *name, int type, TMTagAttrType *attrs
554 , gboolean partial, langType lang)
556 static GPtrArray *tags = NULL;
557 TMTag **matches[2];
558 int len, tagCount[2]={0,0}, tagIter;
559 gint tags_lang;
561 if ((!theWorkspace) || (!name))
562 return NULL;
563 len = strlen(name);
564 if (!len)
565 return NULL;
566 if (tags)
567 g_ptr_array_set_size(tags, 0);
568 else
569 tags = g_ptr_array_new();
571 matches[0] = tm_tags_find(theWorkspace->work_object.tags_array, name, partial, &tagCount[0]);
572 matches[1] = tm_tags_find(theWorkspace->global_tags, name, partial, &tagCount[1]);
574 /* file tags */
575 if (matches[0] && *matches[0])
577 /* tag->atts.file.lang contains the line of the tag and
578 * tags->atts.entry.file->lang contains the language */
579 tags_lang = (*matches[0])->atts.entry.file->lang;
581 for (tagIter=0;tagIter<tagCount[0];++tagIter)
583 if ((type & (*matches[0])->type) && (lang == -1 || tags_lang == lang))
584 g_ptr_array_add(tags, *matches[0]);
585 if (partial)
587 if (0 != strncmp((*matches[0])->name, name, len))
588 break;
590 else
592 if (0 != strcmp((*matches[0])->name, name))
593 break;
595 ++ matches[0];
599 /* global tags */
600 if (matches[1] && *matches[1])
602 int tags_lang_alt = 0;
603 /* tag->atts.file.lang contains the language and
604 * tags->atts.entry.file is NULL */
605 tags_lang = (*matches[1])->atts.file.lang;
606 /* tags_lang_alt is used to load C global tags only once for C and C++
607 * lang = 1 is C++, lang = 0 is C
608 * if we have lang 0, than accept also lang 1 for C++ */
609 if (tags_lang == 0) /* C or C++ */
610 tags_lang_alt = 1;
611 else
612 tags_lang_alt = tags_lang; /* otherwise just ignore it */
614 for (tagIter=0;tagIter<tagCount[1];++tagIter)
616 if ((type & (*matches[1])->type) && (lang == -1 ||
617 tags_lang == lang || tags_lang_alt == lang))
618 g_ptr_array_add(tags, *matches[1]);
620 if (partial)
622 if (0 != strncmp((*matches[1])->name, name, len))
623 break;
625 else
627 if (0 != strcmp((*matches[1])->name, name))
628 break;
630 ++ matches[1];
634 if (attrs)
635 tm_tags_sort(tags, attrs, TRUE);
636 return tags;
639 static gboolean match_langs(gint lang, const TMTag *tag)
641 if (tag->atts.entry.file)
642 { /* workspace tag */
643 if (lang == tag->atts.entry.file->lang)
644 return TRUE;
646 else
647 { /* global tag */
648 if (lang == tag->atts.file.lang)
649 return TRUE;
651 return FALSE;
654 /* scope can be NULL.
655 * lang can be -1 */
656 static int
657 fill_find_tags_array (GPtrArray *dst, const GPtrArray *src,
658 const char *name, const char *scope, int type, gboolean partial,
659 gint lang, gboolean first)
661 TMTag **match;
662 int tagIter, count;
664 if ((!src) || (!dst) || (!name) || (!*name))
665 return 0;
667 match = tm_tags_find (src, name, partial, &count);
668 if (count && match && *match)
670 for (tagIter = 0; tagIter < count; ++tagIter)
672 if (! scope || (match[tagIter]->atts.entry.scope &&
673 0 == strcmp(match[tagIter]->atts.entry.scope, scope)))
675 if (type & match[tagIter]->type)
676 if (lang == -1 || match_langs(lang, match[tagIter]))
678 g_ptr_array_add (dst, match[tagIter]);
679 if (first)
680 break;
685 return dst->len;
689 /* adapted from tm_workspace_find, Anjuta 2.02 */
690 const GPtrArray *
691 tm_workspace_find_scoped (const char *name, const char *scope, gint type,
692 TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search)
694 static GPtrArray *tags = NULL;
696 if ((!theWorkspace))
697 return NULL;
699 if (tags)
700 g_ptr_array_set_size (tags, 0);
701 else
702 tags = g_ptr_array_new ();
704 fill_find_tags_array (tags, theWorkspace->work_object.tags_array,
705 name, scope, type, partial, lang, FALSE);
706 if (global_search)
708 /* for a scoped tag, I think we always want the same language */
709 fill_find_tags_array (tags, theWorkspace->global_tags,
710 name, scope, type, partial, lang, FALSE);
712 if (attrs)
713 tm_tags_sort (tags, attrs, TRUE);
714 return tags;
718 const TMTag *
719 tm_get_current_function (GPtrArray * file_tags, const gulong line)
721 GPtrArray *const local = tm_tags_extract (file_tags, tm_tag_function_t);
722 if (local && local->len)
724 guint i;
725 TMTag *tag, *function_tag = NULL;
726 gulong function_line = 0;
727 glong delta;
729 for (i = 0; (i < local->len); ++i)
731 tag = TM_TAG (local->pdata[i]);
732 delta = line - tag->atts.entry.line;
733 if (delta >= 0 && (gulong)delta < line - function_line)
735 function_tag = tag;
736 function_line = tag->atts.entry.line;
739 g_ptr_array_free (local, TRUE);
740 return function_tag;
742 return NULL;
746 static int
747 find_scope_members_tags (const GPtrArray * all, GPtrArray * tags,
748 const langType langJava, const char *name,
749 const char *filename, gboolean no_definitions)
751 GPtrArray *local = g_ptr_array_new ();
752 unsigned int i;
753 TMTag *tag;
754 size_t len = strlen (name);
755 for (i = 0; (i < all->len); ++i)
757 tag = TM_TAG (all->pdata[i]);
758 if (no_definitions && filename && tag->atts.entry.file &&
759 0 != strcmp (filename,
760 tag->atts.entry.file->work_object.short_name))
762 continue;
764 if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
766 if (0 == strncmp (name, tag->atts.entry.scope, len))
768 g_ptr_array_add (local, tag);
772 if (local->len > 0)
774 unsigned int j;
775 TMTag *tag2;
776 char backup = 0;
777 char *s_backup = NULL;
778 char *var_type = NULL;
779 char *scope;
780 for (i = 0; (i < local->len); ++i)
782 tag = TM_TAG (local->pdata[i]);
783 scope = tag->atts.entry.scope;
784 if (scope && 0 == strcmp (name, scope))
786 g_ptr_array_add (tags, tag);
787 continue;
789 s_backup = NULL;
790 j = 0; /* someone could write better code :P */
791 while (scope)
793 if (s_backup)
795 backup = s_backup[0];
796 s_backup[0] = '\0';
797 if (0 == strcmp (name, tag->atts.entry.scope))
799 j = local->len;
800 s_backup[0] = backup;
801 break;
804 if (tag->atts.entry.file
805 && tag->atts.entry.file->lang == langJava)
807 scope = strrchr (tag->atts.entry.scope, '.');
808 if (scope)
809 var_type = scope + 1;
811 else
813 scope = strrchr (tag->atts.entry.scope, ':');
814 if (scope)
816 var_type = scope + 1;
817 scope--;
820 if (s_backup)
822 s_backup[0] = backup;
824 if (scope)
826 if (s_backup)
828 backup = s_backup[0];
829 s_backup[0] = '\0';
831 for (j = 0; (j < local->len); ++j)
833 if (i == j)
834 continue;
835 tag2 = TM_TAG (local->pdata[j]);
836 if (tag2->atts.entry.var_type &&
837 0 == strcmp (var_type, tag2->atts.entry.var_type))
839 break;
842 if (s_backup)
843 s_backup[0] = backup;
845 if (j < local->len)
847 break;
849 s_backup = scope;
851 if (j == local->len)
853 g_ptr_array_add (tags, tag);
857 g_ptr_array_free (local, TRUE);
858 return (int) tags->len;
862 #if 0
863 static int
864 find_namespace_members_tags (const GPtrArray * all, GPtrArray * tags,
865 const langType langJava, const char *name,
866 const char *filename)
868 GPtrArray *local = g_ptr_array_new ();
869 unsigned int i;
870 TMTag *tag;
871 size_t len = strlen (name);
873 g_return_val_if_fail (all != NULL, 0);
875 for (i = 0; (i < all->len); ++i)
877 tag = TM_TAG (all->pdata[i]);
878 if (filename && tag->atts.entry.file &&
879 0 != strcmp (filename,
880 tag->atts.entry.file->work_object.short_name))
882 continue;
885 if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
887 if (0 == strncmp (name, tag->atts.entry.scope, len))
889 g_ptr_array_add (local, tag);
894 if (local->len > 0)
896 char *scope;
897 for (i = 0; (i < local->len); ++i)
899 tag = TM_TAG (local->pdata[i]);
900 scope = tag->atts.entry.scope;
902 /* if we wanna complete something like
903 * namespace1::
904 * we'll just return the tags that have "namespace1"
905 * as their scope. So we won't return classes/members/namespaces
906 * under, for example, namespace2, where namespace1::namespace2
908 if (scope && 0 == strcmp (name, scope))
910 g_ptr_array_add (tags, tag);
915 g_ptr_array_free (local, TRUE);
916 return (int) tags->len;
919 const GPtrArray *
920 tm_workspace_find_namespace_members (const GPtrArray * file_tags, const char *name,
921 gboolean search_global)
923 static GPtrArray *tags = NULL;
924 GPtrArray *local = NULL;
925 char *new_name = (char *) name;
926 char *filename = NULL;
927 int found = 0, del = 0;
928 static langType langJava = -1;
929 TMTag *tag = NULL;
931 g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
933 if (!tags)
934 tags = g_ptr_array_new ();
936 while (1)
938 const GPtrArray *tags2;
939 int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t |
940 tm_tag_struct_t | tm_tag_typedef_t |
941 tm_tag_union_t | tm_tag_enum_t);
943 if (file_tags)
945 g_ptr_array_set_size (tags, 0);
946 got = fill_find_tags_array (tags, file_tags,
947 new_name, NULL, types, FALSE, -1, FALSE);
951 if (got)
953 tags2 = tags;
955 else
957 TMTagAttrType attrs[] = {
958 tm_tag_attr_name_t, tm_tag_attr_type_t,
959 tm_tag_attr_none_t
961 tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
964 if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
966 if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type
967 && tag->atts.entry.var_type[0] != '\0')
969 new_name = tag->atts.entry.var_type;
970 continue;
972 filename = (tag->atts.entry.file ?
973 tag->atts.entry.file->work_object.short_name : NULL);
974 if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
976 del = 1;
977 if (tag->atts.entry.file &&
978 tag->atts.entry.file->lang == langJava)
980 new_name = g_strdup_printf ("%s.%s",
981 tag->atts.entry.scope,
982 new_name);
984 else
986 new_name = g_strdup_printf ("%s::%s",
987 tag->atts.entry.scope,
988 new_name);
991 break;
993 else
995 return NULL;
999 g_ptr_array_set_size (tags, 0);
1001 if (tag && tag->atts.entry.file)
1003 local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array,
1004 (tm_tag_function_t |
1005 tm_tag_field_t | tm_tag_enumerator_t |
1006 tm_tag_namespace_t | tm_tag_class_t ));
1008 else
1010 local = tm_tags_extract (theWorkspace->work_object.tags_array,
1011 (tm_tag_function_t | tm_tag_prototype_t |
1012 tm_tag_member_t |
1013 tm_tag_field_t | tm_tag_enumerator_t |
1014 tm_tag_namespace_t | tm_tag_class_t ));
1017 if (local)
1019 found = find_namespace_members_tags (local, tags,
1020 langJava, new_name, filename);
1021 g_ptr_array_free (local, TRUE);
1025 if (!found && search_global)
1027 GPtrArray *global = tm_tags_extract (theWorkspace->global_tags,
1028 (tm_tag_member_t |
1029 tm_tag_prototype_t |
1030 tm_tag_field_t |
1031 tm_tag_method_t |
1032 tm_tag_function_t |
1033 tm_tag_enumerator_t |
1034 tm_tag_namespace_t |
1035 tm_tag_class_t ));
1037 if (global)
1039 find_namespace_members_tags (global, tags, langJava,
1040 new_name, filename);
1042 DEBUG_PRINT ("returning these");
1043 gint i;
1044 for (i=0; i < tags->len; i++) {
1045 TMTag *cur_tag;
1047 cur_tag = (TMTag*)g_ptr_array_index (tags, i);
1048 tm_tag_print (cur_tag, stdout );
1051 g_ptr_array_free (global, TRUE);
1056 if (del)
1058 g_free (new_name);
1061 return tags;
1063 #endif
1065 const GPtrArray *
1066 tm_workspace_find_scope_members (const GPtrArray * file_tags, const char *name,
1067 gboolean search_global, gboolean no_definitions)
1069 static GPtrArray *tags = NULL;
1070 GPtrArray *local = NULL;
1071 char *new_name = (char *) name;
1072 char *filename = NULL;
1073 int found = 0, del = 0;
1074 static langType langJava = -1;
1075 TMTag *tag = NULL;
1077 /* FIXME */
1078 /* langJava = getNamedLanguage ("Java"); */
1080 g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
1082 if (!tags)
1083 tags = g_ptr_array_new ();
1085 while (1)
1087 const GPtrArray *tags2;
1088 int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t |
1089 tm_tag_struct_t | tm_tag_typedef_t |
1090 tm_tag_union_t | tm_tag_enum_t);
1092 if (file_tags)
1094 g_ptr_array_set_size (tags, 0);
1095 got = fill_find_tags_array (tags, file_tags,
1096 new_name, NULL, types, FALSE, -1, FALSE);
1098 if (got)
1100 tags2 = tags;
1102 else
1104 TMTagAttrType attrs[] = {
1105 tm_tag_attr_name_t, tm_tag_attr_type_t,
1106 tm_tag_attr_none_t
1108 tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
1111 if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
1113 if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type
1114 && tag->atts.entry.var_type[0] != '\0')
1116 char *tmp_name;
1117 tmp_name = tag->atts.entry.var_type;
1118 if (strcmp(tmp_name, new_name) == 0) {
1119 new_name = NULL;
1121 else {
1122 new_name = tmp_name;
1124 continue;
1126 filename = (tag->atts.entry.file ?
1127 tag->atts.entry.file->work_object.short_name : NULL);
1128 if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
1130 del = 1;
1131 if (tag->atts.entry.file &&
1132 tag->atts.entry.file->lang == langJava)
1134 new_name = g_strdup_printf ("%s.%s",
1135 tag->atts.entry.scope,
1136 new_name);
1138 else
1140 new_name = g_strdup_printf ("%s::%s",
1141 tag->atts.entry.scope,
1142 new_name);
1145 break;
1147 else
1149 return NULL;
1153 g_ptr_array_set_size (tags, 0);
1155 if (no_definitions && tag && tag->atts.entry.file)
1157 local = tm_tags_extract (tag->atts.entry.file->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 else
1164 local = tm_tags_extract (theWorkspace->work_object.tags_array,
1165 (tm_tag_function_t | tm_tag_prototype_t |
1166 tm_tag_member_t | tm_tag_field_t |
1167 tm_tag_method_t | tm_tag_enumerator_t));
1169 if (local)
1171 found = find_scope_members_tags (local, tags, langJava, new_name,
1172 filename, no_definitions);
1173 g_ptr_array_free (local, TRUE);
1175 if (!found && search_global)
1177 GPtrArray *global = tm_tags_extract (theWorkspace->global_tags,
1178 (tm_tag_member_t |
1179 tm_tag_prototype_t |
1180 tm_tag_field_t |
1181 tm_tag_method_t |
1182 tm_tag_function_t |
1183 tm_tag_enumerator_t
1184 |tm_tag_struct_t | tm_tag_typedef_t |
1185 tm_tag_union_t | tm_tag_enum_t));
1186 if (global)
1188 find_scope_members_tags (global, tags, langJava, new_name,
1189 filename, no_definitions);
1190 g_ptr_array_free (global, TRUE);
1193 if (del)
1195 g_free (new_name);
1198 return tags;
1201 const GPtrArray *tm_workspace_get_parents(const gchar *name)
1203 static TMTagAttrType type[] = { tm_tag_attr_name_t, tm_tag_attr_none_t };
1204 static GPtrArray *parents = NULL;
1205 const GPtrArray *matches;
1206 guint i = 0;
1207 guint j;
1208 gchar **klasses;
1209 gchar **klass;
1210 TMTag *tag;
1212 g_return_val_if_fail(name && isalpha(*name),NULL);
1214 if (NULL == parents)
1215 parents = g_ptr_array_new();
1216 else
1217 g_ptr_array_set_size(parents, 0);
1218 matches = tm_workspace_find(name, tm_tag_class_t, type, FALSE, -1);
1219 if ((NULL == matches) || (0 == matches->len))
1220 return NULL;
1221 g_ptr_array_add(parents, matches->pdata[0]);
1222 while (i < parents->len)
1224 tag = TM_TAG(parents->pdata[i]);
1225 if ((NULL != tag->atts.entry.inheritance) && (isalpha(tag->atts.entry.inheritance[0])))
1227 klasses = g_strsplit(tag->atts.entry.inheritance, ",", 10);
1228 for (klass = klasses; (NULL != *klass); ++ klass)
1230 for (j=0; j < parents->len; ++j)
1232 if (0 == strcmp(*klass, TM_TAG(parents->pdata[j])->name))
1233 break;
1235 if (parents->len == j)
1237 matches = tm_workspace_find(*klass, tm_tag_class_t, type, FALSE, -1);
1238 if ((NULL != matches) && (0 < matches->len))
1239 g_ptr_array_add(parents, matches->pdata[0]);
1242 g_strfreev(klasses);
1244 ++ i;
1246 return parents;