Fix build with bleeding edge GLib
[geany-mirror.git] / tagmanager / src / tm_workspace.c
blob9190132419fdd1851e44d7a2c86a8caba1b74441
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_unref(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 gsize orig_len;
146 guchar buf[BUFSIZ];
147 FILE *fp;
148 TMTag *tag;
149 gboolean format_pipe = FALSE;
151 if (NULL == theWorkspace)
152 return FALSE;
153 if (NULL == (fp = g_fopen(tags_file, "r")))
154 return FALSE;
155 if (NULL == theWorkspace->global_tags)
156 theWorkspace->global_tags = g_ptr_array_new();
157 orig_len = theWorkspace->global_tags->len;
158 if ((NULL == fgets((gchar*) buf, BUFSIZ, fp)) || ('\0' == *buf))
160 fclose(fp);
161 return FALSE; /* early out on error */
163 else
164 { /* We read the first line for the format specification. */
165 if (buf[0] == '#' && strstr((gchar*) buf, "format=pipe") != NULL)
166 format_pipe = TRUE;
167 else if (buf[0] == '#' && strstr((gchar*) buf, "format=tagmanager") != NULL)
168 format_pipe = FALSE;
169 else
170 { /* We didn't find a valid format specification, so we try to auto-detect the format
171 * by counting the pipe characters on the first line and asumme pipe format when
172 * we find more than one pipe on the line. */
173 guint i, pipe_cnt = 0;
174 for (i = 0; i < BUFSIZ && buf[i] != '\0' && pipe_cnt < 2; i++)
176 if (buf[i] == '|')
177 pipe_cnt++;
179 format_pipe = (pipe_cnt > 1);
181 rewind(fp); /* reset the file pointer, to start reading again from the beginning */
183 while (NULL != (tag = tm_tag_new_from_file(NULL, fp, mode, format_pipe)))
184 g_ptr_array_add(theWorkspace->global_tags, tag);
185 fclose(fp);
187 /* reorder the whole array, because tm_tags_find expects a sorted array */
188 tm_tags_merge(theWorkspace->global_tags, orig_len, 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);
227 fwrite(str, str_len, 1, fp);
228 g_free(str);
229 node = g_list_next(node);
234 static void append_to_temp_file(FILE *fp, GList *file_list)
236 GList *node;
238 node = file_list;
239 while (node)
241 const char *fname = node->data;
242 char *contents;
243 size_t length;
244 GError *err = NULL;
246 if (! g_file_get_contents(fname, &contents, &length, &err))
248 fprintf(stderr, "Unable to read file: %s\n", err->message);
249 g_error_free(err);
251 else
253 fwrite(contents, length, 1, fp);
254 fwrite("\n", 1, 1, fp); /* in case file doesn't end in newline (e.g. windows). */
255 g_free(contents);
257 node = g_list_next (node);
261 static gchar *create_temp_file(const gchar *tpl)
263 gchar *name;
264 gint fd;
266 fd = g_file_open_tmp(tpl, &name, NULL);
267 if (fd < 0)
268 name = NULL;
269 else
270 close(fd);
272 return name;
275 gboolean tm_workspace_create_global_tags(const char *pre_process, const char **includes,
276 int includes_count, const char *tags_file, int lang)
278 #ifdef HAVE_GLOB_H
279 glob_t globbuf;
280 size_t idx_glob;
281 #endif
282 int idx_inc;
283 char *command;
284 guint i;
285 FILE *fp;
286 TMWorkObject *source_file;
287 GPtrArray *tags_array;
288 GHashTable *includes_files_hash;
289 GList *includes_files = NULL;
290 gchar *temp_file = create_temp_file("tmp_XXXXXX.cpp");
291 gchar *temp_file2 = create_temp_file("tmp_XXXXXX.cpp");
293 if (NULL == temp_file || NULL == temp_file2 ||
294 NULL == theWorkspace || NULL == (fp = g_fopen(temp_file, "w")))
296 g_free(temp_file);
297 g_free(temp_file2);
298 return FALSE;
301 includes_files_hash = g_hash_table_new_full (tm_file_inode_hash,
302 g_direct_equal,
303 NULL, g_free);
305 #ifdef HAVE_GLOB_H
306 globbuf.gl_offs = 0;
308 if (includes[0][0] == '"') /* leading \" char for glob matching */
309 for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
311 int dirty_len = strlen(includes[idx_inc]);
312 char *clean_path = g_malloc(dirty_len - 1);
314 strncpy(clean_path, includes[idx_inc] + 1, dirty_len - 1);
315 clean_path[dirty_len - 2] = 0;
317 #ifdef TM_DEBUG
318 g_message ("[o][%s]\n", clean_path);
319 #endif
320 glob(clean_path, 0, NULL, &globbuf);
322 #ifdef TM_DEBUG
323 g_message ("matches: %d\n", globbuf.gl_pathc);
324 #endif
326 for(idx_glob = 0; idx_glob < globbuf.gl_pathc; idx_glob++)
328 #ifdef TM_DEBUG
329 g_message (">>> %s\n", globbuf.gl_pathv[idx_glob]);
330 #endif
331 if (!g_hash_table_lookup(includes_files_hash,
332 globbuf.gl_pathv[idx_glob]))
334 char* file_name_copy = strdup(globbuf.gl_pathv[idx_glob]);
335 g_hash_table_insert(includes_files_hash, file_name_copy,
336 file_name_copy);
337 #ifdef TM_DEBUG
338 g_message ("Added ...\n");
339 #endif
342 globfree(&globbuf);
343 g_free(clean_path);
345 else
346 #endif
347 /* no glob support or globbing not wanted */
348 for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
350 if (!g_hash_table_lookup(includes_files_hash,
351 includes[idx_inc]))
353 char* file_name_copy = strdup(includes[idx_inc]);
354 g_hash_table_insert(includes_files_hash, file_name_copy,
355 file_name_copy);
359 /* Checks for duplicate file entries which would case trouble */
360 g_hash_table_foreach(includes_files_hash, tm_move_entries_to_g_list,
361 &includes_files);
363 includes_files = g_list_reverse (includes_files);
365 #ifdef TM_DEBUG
366 g_message ("writing out files to %s\n", temp_file);
367 #endif
368 if (pre_process != NULL)
369 write_includes_file(fp, includes_files);
370 else
371 append_to_temp_file(fp, includes_files);
373 g_list_free (includes_files);
374 g_hash_table_destroy(includes_files_hash);
375 includes_files_hash = NULL;
376 includes_files = NULL;
377 fclose(fp);
379 if (pre_process != NULL)
381 gint ret;
382 gchar *tmp_errfile = create_temp_file("tmp_XXXXXX");
383 gchar *errors = NULL;
384 command = g_strdup_printf("%s %s >%s 2>%s",
385 pre_process, temp_file, temp_file2, tmp_errfile);
386 #ifdef TM_DEBUG
387 g_message("Executing: %s", command);
388 #endif
389 ret = system(command);
390 g_free(command);
391 g_unlink(temp_file);
392 g_free(temp_file);
393 g_file_get_contents(tmp_errfile, &errors, NULL, NULL);
394 if (errors && *errors)
395 g_printerr("%s", errors);
396 g_free(errors);
397 g_unlink(tmp_errfile);
398 g_free(tmp_errfile);
399 if (ret == -1)
401 g_unlink(temp_file2);
402 return FALSE;
405 else
407 /* no pre-processing needed, so temp_file2 = temp_file */
408 g_unlink(temp_file2);
409 g_free(temp_file2);
410 temp_file2 = temp_file;
411 temp_file = NULL;
413 source_file = tm_source_file_new(temp_file2, TRUE, tm_source_file_get_lang_name(lang));
414 if (NULL == source_file)
416 g_unlink(temp_file2);
417 return FALSE;
419 g_unlink(temp_file2);
420 g_free(temp_file2);
421 if ((NULL == source_file->tags_array) || (0 == source_file->tags_array->len))
423 tm_source_file_free(source_file);
424 return FALSE;
426 tags_array = tm_tags_extract(source_file->tags_array, tm_tag_max_t);
427 if ((NULL == tags_array) || (0 == tags_array->len))
429 if (tags_array)
430 g_ptr_array_free(tags_array, TRUE);
431 tm_source_file_free(source_file);
432 return FALSE;
434 if (FALSE == tm_tags_sort(tags_array, global_tags_sort_attrs, TRUE))
436 tm_source_file_free(source_file);
437 return FALSE;
439 if (NULL == (fp = g_fopen(tags_file, "w")))
441 tm_source_file_free(source_file);
442 return FALSE;
444 fprintf(fp, "# format=tagmanager\n");
445 for (i = 0; i < tags_array->len; ++i)
447 tm_tag_write(TM_TAG(tags_array->pdata[i]), fp, tm_tag_attr_type_t
448 | tm_tag_attr_scope_t | tm_tag_attr_arglist_t | tm_tag_attr_vartype_t
449 | tm_tag_attr_pointer_t);
451 fclose(fp);
452 tm_source_file_free(source_file);
453 g_ptr_array_free(tags_array, TRUE);
454 return TRUE;
457 TMWorkObject *tm_workspace_find_object(TMWorkObject *work_object, const char *file_name
458 , gboolean name_only)
460 TMWorkObject *w = NULL;
461 guint i;
463 if (work_object != TM_WORK_OBJECT(theWorkspace))
464 return NULL;
465 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects)
466 || (0 == theWorkspace->work_objects->len))
467 return NULL;
468 for (i = 0; i < theWorkspace->work_objects->len; ++i)
470 if (NULL != (w = tm_work_object_find(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])
471 , file_name, name_only)))
472 return w;
474 return NULL;
477 void tm_workspace_recreate_tags_array(void)
479 guint i, j;
480 TMWorkObject *w;
481 TMTagAttrType sort_attrs[] = { tm_tag_attr_name_t, tm_tag_attr_file_t
482 , tm_tag_attr_scope_t, tm_tag_attr_type_t, tm_tag_attr_arglist_t, 0};
484 #ifdef TM_DEBUG
485 g_message("Recreating workspace tags array");
486 #endif
488 if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects))
489 return;
490 if (NULL != theWorkspace->work_object.tags_array)
491 g_ptr_array_set_size(theWorkspace->work_object.tags_array, 0);
492 else
493 theWorkspace->work_object.tags_array = g_ptr_array_new();
495 #ifdef TM_DEBUG
496 g_message("Total %d objects", theWorkspace->work_objects->len);
497 #endif
498 for (i=0; i < theWorkspace->work_objects->len; ++i)
500 w = TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]);
501 #ifdef TM_DEBUG
502 g_message("Adding tags of %s", w->file_name);
503 #endif
504 if ((NULL != w) && (NULL != w->tags_array) && (w->tags_array->len > 0))
506 for (j = 0; j < w->tags_array->len; ++j)
508 g_ptr_array_add(theWorkspace->work_object.tags_array,
509 w->tags_array->pdata[j]);
513 #ifdef TM_DEBUG
514 g_message("Total: %d tags", theWorkspace->work_object.tags_array->len);
515 #endif
516 tm_tags_sort(theWorkspace->work_object.tags_array, sort_attrs, TRUE);
519 gboolean tm_workspace_update(TMWorkObject *workspace, gboolean force
520 , gboolean recurse, gboolean UNUSED update_parent)
522 guint i;
523 gboolean update_tags = force;
525 #ifdef TM_DEBUG
526 g_message("Updating workspace");
527 #endif
529 if (workspace != TM_WORK_OBJECT(theWorkspace))
530 return FALSE;
531 if (NULL == theWorkspace)
532 return TRUE;
533 if ((recurse) && (theWorkspace->work_objects))
535 for (i=0; i < theWorkspace->work_objects->len; ++i)
537 if (TRUE == tm_work_object_update(TM_WORK_OBJECT(
538 theWorkspace->work_objects->pdata[i]), FALSE, TRUE, FALSE))
539 update_tags = TRUE;
542 if (update_tags)
543 tm_workspace_recreate_tags_array();
544 /* workspace->analyze_time = time(NULL); */
545 return update_tags;
548 void tm_workspace_dump(void)
550 if (theWorkspace)
552 #ifdef TM_DEBUG
553 g_message("Dumping TagManager workspace tree..");
554 #endif
555 tm_work_object_dump(TM_WORK_OBJECT(theWorkspace));
556 if (theWorkspace->work_objects)
558 guint i;
559 for (i=0; i < theWorkspace->work_objects->len; ++i)
561 if (IS_TM_PROJECT(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i])))
562 tm_project_dump(TM_PROJECT(theWorkspace->work_objects->pdata[i]));
563 else
564 tm_work_object_dump(TM_WORK_OBJECT(theWorkspace->work_objects->pdata[i]));
570 const GPtrArray *tm_workspace_find(const char *name, int type, TMTagAttrType *attrs
571 , gboolean partial, langType lang)
573 static GPtrArray *tags = NULL;
574 TMTag **matches[2];
575 int len, tagCount[2]={0,0}, tagIter;
576 gint tags_lang;
578 if ((!theWorkspace) || (!name))
579 return NULL;
580 len = strlen(name);
581 if (!len)
582 return NULL;
583 if (tags)
584 g_ptr_array_set_size(tags, 0);
585 else
586 tags = g_ptr_array_new();
588 matches[0] = tm_tags_find(theWorkspace->work_object.tags_array, name, partial, &tagCount[0]);
589 matches[1] = tm_tags_find(theWorkspace->global_tags, name, partial, &tagCount[1]);
591 /* file tags */
592 if (matches[0] && *matches[0])
594 /* tag->atts.file.lang contains the line of the tag and
595 * tags->atts.entry.file->lang contains the language */
596 tags_lang = (*matches[0])->atts.entry.file->lang;
598 for (tagIter=0;tagIter<tagCount[0];++tagIter)
600 if ((type & (*matches[0])->type) && (lang == -1 || tags_lang == lang))
601 g_ptr_array_add(tags, *matches[0]);
602 if (partial)
604 if (0 != strncmp((*matches[0])->name, name, len))
605 break;
607 else
609 if (0 != strcmp((*matches[0])->name, name))
610 break;
612 ++ matches[0];
616 /* global tags */
617 if (matches[1] && *matches[1])
619 int tags_lang_alt = 0;
620 /* tag->atts.file.lang contains the language and
621 * tags->atts.entry.file is NULL */
622 tags_lang = (*matches[1])->atts.file.lang;
623 /* tags_lang_alt is used to load C global tags only once for C and C++
624 * lang = 1 is C++, lang = 0 is C
625 * if we have lang 0, than accept also lang 1 for C++ */
626 if (tags_lang == 0) /* C or C++ */
627 tags_lang_alt = 1;
628 else
629 tags_lang_alt = tags_lang; /* otherwise just ignore it */
631 for (tagIter=0;tagIter<tagCount[1];++tagIter)
633 if ((type & (*matches[1])->type) && (lang == -1 ||
634 tags_lang == lang || tags_lang_alt == lang))
635 g_ptr_array_add(tags, *matches[1]);
637 if (partial)
639 if (0 != strncmp((*matches[1])->name, name, len))
640 break;
642 else
644 if (0 != strcmp((*matches[1])->name, name))
645 break;
647 ++ matches[1];
651 if (attrs)
652 tm_tags_sort(tags, attrs, TRUE);
653 return tags;
656 static gboolean match_langs(gint lang, const TMTag *tag)
658 if (tag->atts.entry.file)
659 { /* workspace tag */
660 if (lang == tag->atts.entry.file->lang)
661 return TRUE;
663 else
664 { /* global tag */
665 if (lang == tag->atts.file.lang)
666 return TRUE;
668 return FALSE;
671 /* scope can be NULL.
672 * lang can be -1 */
673 static int
674 fill_find_tags_array (GPtrArray *dst, const GPtrArray *src,
675 const char *name, const char *scope, int type, gboolean partial,
676 gint lang, gboolean first)
678 TMTag **match;
679 int tagIter, count;
681 if ((!src) || (!dst) || (!name) || (!*name))
682 return 0;
684 match = tm_tags_find (src, name, partial, &count);
685 if (count && match && *match)
687 for (tagIter = 0; tagIter < count; ++tagIter)
689 if (! scope || (match[tagIter]->atts.entry.scope &&
690 0 == strcmp(match[tagIter]->atts.entry.scope, scope)))
692 if (type & match[tagIter]->type)
693 if (lang == -1 || match_langs(lang, match[tagIter]))
695 g_ptr_array_add (dst, match[tagIter]);
696 if (first)
697 break;
702 return dst->len;
706 /* adapted from tm_workspace_find, Anjuta 2.02 */
707 const GPtrArray *
708 tm_workspace_find_scoped (const char *name, const char *scope, gint type,
709 TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search)
711 static GPtrArray *tags = NULL;
713 if ((!theWorkspace))
714 return NULL;
716 if (tags)
717 g_ptr_array_set_size (tags, 0);
718 else
719 tags = g_ptr_array_new ();
721 fill_find_tags_array (tags, theWorkspace->work_object.tags_array,
722 name, scope, type, partial, lang, FALSE);
723 if (global_search)
725 /* for a scoped tag, I think we always want the same language */
726 fill_find_tags_array (tags, theWorkspace->global_tags,
727 name, scope, type, partial, lang, FALSE);
729 if (attrs)
730 tm_tags_sort (tags, attrs, TRUE);
731 return tags;
735 const TMTag *
736 tm_get_current_tag (GPtrArray * file_tags, const gulong line, const guint tag_types)
738 GPtrArray *const local = tm_tags_extract (file_tags, tag_types);
739 TMTag *matching_tag = NULL;
740 if (local && local->len)
742 guint i;
743 gulong matching_line = 0;
744 glong delta;
746 for (i = 0; (i < local->len); ++i)
748 TMTag *tag = TM_TAG (local->pdata[i]);
749 delta = line - tag->atts.entry.line;
750 if (delta >= 0 && (gulong)delta < line - matching_line)
752 matching_tag = tag;
753 matching_line = tag->atts.entry.line;
757 if (local)
758 g_ptr_array_free (local, TRUE);
759 return matching_tag;
763 const TMTag *
764 tm_get_current_function (GPtrArray * file_tags, const gulong line)
766 return tm_get_current_tag (file_tags, line, tm_tag_function_t | tm_tag_method_t);
770 static int
771 find_scope_members_tags (const GPtrArray * all, GPtrArray * tags,
772 const langType langJava, const char *name,
773 const char *filename, gboolean no_definitions)
775 GPtrArray *local = g_ptr_array_new ();
776 unsigned int i;
777 TMTag *tag;
778 size_t len = strlen (name);
779 for (i = 0; (i < all->len); ++i)
781 tag = TM_TAG (all->pdata[i]);
782 if (no_definitions && filename && tag->atts.entry.file &&
783 0 != strcmp (filename,
784 tag->atts.entry.file->work_object.short_name))
786 continue;
788 if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
790 if (0 == strncmp (name, tag->atts.entry.scope, len))
792 g_ptr_array_add (local, tag);
796 if (local->len > 0)
798 unsigned int j;
799 TMTag *tag2;
800 char backup = 0;
801 char *s_backup = NULL;
802 char *var_type = NULL;
803 char *scope;
804 for (i = 0; (i < local->len); ++i)
806 tag = TM_TAG (local->pdata[i]);
807 scope = tag->atts.entry.scope;
808 if (scope && 0 == strcmp (name, scope))
810 g_ptr_array_add (tags, tag);
811 continue;
813 s_backup = NULL;
814 j = 0; /* someone could write better code :P */
815 while (scope)
817 if (s_backup)
819 backup = s_backup[0];
820 s_backup[0] = '\0';
821 if (0 == strcmp (name, tag->atts.entry.scope))
823 j = local->len;
824 s_backup[0] = backup;
825 break;
828 if (tag->atts.entry.file
829 && tag->atts.entry.file->lang == langJava)
831 scope = strrchr (tag->atts.entry.scope, '.');
832 if (scope)
833 var_type = scope + 1;
835 else
837 scope = strrchr (tag->atts.entry.scope, ':');
838 if (scope)
840 var_type = scope + 1;
841 scope--;
844 if (s_backup)
846 s_backup[0] = backup;
848 if (scope)
850 if (s_backup)
852 backup = s_backup[0];
853 s_backup[0] = '\0';
855 for (j = 0; (j < local->len); ++j)
857 if (i == j)
858 continue;
859 tag2 = TM_TAG (local->pdata[j]);
860 if (tag2->atts.entry.var_type &&
861 0 == strcmp (var_type, tag2->atts.entry.var_type))
863 break;
866 if (s_backup)
867 s_backup[0] = backup;
869 if (j < local->len)
871 break;
873 s_backup = scope;
875 if (j == local->len)
877 g_ptr_array_add (tags, tag);
881 g_ptr_array_free (local, TRUE);
882 return (int) tags->len;
886 #if 0
887 static int
888 find_namespace_members_tags (const GPtrArray * all, GPtrArray * tags,
889 const langType langJava, const char *name,
890 const char *filename)
892 GPtrArray *local = g_ptr_array_new ();
893 unsigned int i;
894 TMTag *tag;
895 size_t len = strlen (name);
897 g_return_val_if_fail (all != NULL, 0);
899 for (i = 0; (i < all->len); ++i)
901 tag = TM_TAG (all->pdata[i]);
902 if (filename && tag->atts.entry.file &&
903 0 != strcmp (filename,
904 tag->atts.entry.file->work_object.short_name))
906 continue;
909 if (tag && tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
911 if (0 == strncmp (name, tag->atts.entry.scope, len))
913 g_ptr_array_add (local, tag);
918 if (local->len > 0)
920 char *scope;
921 for (i = 0; (i < local->len); ++i)
923 tag = TM_TAG (local->pdata[i]);
924 scope = tag->atts.entry.scope;
926 /* if we wanna complete something like
927 * namespace1::
928 * we'll just return the tags that have "namespace1"
929 * as their scope. So we won't return classes/members/namespaces
930 * under, for example, namespace2, where namespace1::namespace2
932 if (scope && 0 == strcmp (name, scope))
934 g_ptr_array_add (tags, tag);
939 g_ptr_array_free (local, TRUE);
940 return (int) tags->len;
943 const GPtrArray *
944 tm_workspace_find_namespace_members (const GPtrArray * file_tags, const char *name,
945 gboolean search_global)
947 static GPtrArray *tags = NULL;
948 GPtrArray *local = NULL;
949 char *new_name = (char *) name;
950 char *filename = NULL;
951 int found = 0, del = 0;
952 static langType langJava = -1;
953 TMTag *tag = NULL;
955 g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
957 if (!tags)
958 tags = g_ptr_array_new ();
960 while (1)
962 const GPtrArray *tags2;
963 int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t |
964 tm_tag_struct_t | tm_tag_typedef_t |
965 tm_tag_union_t | tm_tag_enum_t);
967 if (file_tags)
969 g_ptr_array_set_size (tags, 0);
970 got = fill_find_tags_array (tags, file_tags,
971 new_name, NULL, types, FALSE, -1, FALSE);
975 if (got)
977 tags2 = tags;
979 else
981 TMTagAttrType attrs[] = {
982 tm_tag_attr_name_t, tm_tag_attr_type_t,
983 tm_tag_attr_none_t
985 tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
988 if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
990 if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type
991 && tag->atts.entry.var_type[0] != '\0')
993 new_name = tag->atts.entry.var_type;
994 continue;
996 filename = (tag->atts.entry.file ?
997 tag->atts.entry.file->work_object.short_name : NULL);
998 if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
1000 del = 1;
1001 if (tag->atts.entry.file &&
1002 tag->atts.entry.file->lang == langJava)
1004 new_name = g_strdup_printf ("%s.%s",
1005 tag->atts.entry.scope,
1006 new_name);
1008 else
1010 new_name = g_strdup_printf ("%s::%s",
1011 tag->atts.entry.scope,
1012 new_name);
1015 break;
1017 else
1019 return NULL;
1023 g_ptr_array_set_size (tags, 0);
1025 if (tag && tag->atts.entry.file)
1027 local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array,
1028 (tm_tag_function_t |
1029 tm_tag_field_t | tm_tag_enumerator_t |
1030 tm_tag_namespace_t | tm_tag_class_t ));
1032 else
1034 local = tm_tags_extract (theWorkspace->work_object.tags_array,
1035 (tm_tag_function_t | tm_tag_prototype_t |
1036 tm_tag_member_t |
1037 tm_tag_field_t | tm_tag_enumerator_t |
1038 tm_tag_namespace_t | tm_tag_class_t ));
1041 if (local)
1043 found = find_namespace_members_tags (local, tags,
1044 langJava, new_name, filename);
1045 g_ptr_array_free (local, TRUE);
1049 if (!found && search_global)
1051 GPtrArray *global = tm_tags_extract (theWorkspace->global_tags,
1052 (tm_tag_member_t |
1053 tm_tag_prototype_t |
1054 tm_tag_field_t |
1055 tm_tag_method_t |
1056 tm_tag_function_t |
1057 tm_tag_enumerator_t |
1058 tm_tag_namespace_t |
1059 tm_tag_class_t ));
1061 if (global)
1063 find_namespace_members_tags (global, tags, langJava,
1064 new_name, filename);
1066 DEBUG_PRINT ("returning these");
1067 gint i;
1068 for (i=0; i < tags->len; i++) {
1069 TMTag *cur_tag;
1071 cur_tag = (TMTag*)g_ptr_array_index (tags, i);
1072 tm_tag_print (cur_tag, stdout );
1075 g_ptr_array_free (global, TRUE);
1080 if (del)
1082 g_free (new_name);
1085 return tags;
1087 #endif
1089 const GPtrArray *
1090 tm_workspace_find_scope_members (const GPtrArray * file_tags, const char *name,
1091 gboolean search_global, gboolean no_definitions)
1093 static GPtrArray *tags = NULL;
1094 GPtrArray *local = NULL;
1095 char *new_name = (char *) name;
1096 char *filename = NULL;
1097 int found = 0, del = 0;
1098 static langType langJava = -1;
1099 TMTag *tag = NULL;
1101 /* FIXME */
1102 /* langJava = getNamedLanguage ("Java"); */
1104 g_return_val_if_fail ((theWorkspace && name && name[0] != '\0'), NULL);
1106 if (!tags)
1107 tags = g_ptr_array_new ();
1109 while (1)
1111 const GPtrArray *tags2;
1112 int got = 0, types = (tm_tag_class_t | tm_tag_namespace_t |
1113 tm_tag_struct_t | tm_tag_typedef_t |
1114 tm_tag_union_t | tm_tag_enum_t);
1116 if (file_tags)
1118 g_ptr_array_set_size (tags, 0);
1119 got = fill_find_tags_array (tags, file_tags,
1120 new_name, NULL, types, FALSE, -1, FALSE);
1122 if (got)
1124 tags2 = tags;
1126 else
1128 TMTagAttrType attrs[] = {
1129 tm_tag_attr_name_t, tm_tag_attr_type_t,
1130 tm_tag_attr_none_t
1132 tags2 = tm_workspace_find (new_name, types, attrs, FALSE, -1);
1135 if ((tags2) && (tags2->len == 1) && (tag = TM_TAG (tags2->pdata[0])))
1137 if (tag->type == tm_tag_typedef_t && tag->atts.entry.var_type
1138 && tag->atts.entry.var_type[0] != '\0')
1140 char *tmp_name;
1141 tmp_name = tag->atts.entry.var_type;
1142 if (strcmp(tmp_name, new_name) == 0) {
1143 new_name = NULL;
1145 else {
1146 new_name = tmp_name;
1148 continue;
1150 filename = (tag->atts.entry.file ?
1151 tag->atts.entry.file->work_object.short_name : NULL);
1152 if (tag->atts.entry.scope && tag->atts.entry.scope[0] != '\0')
1154 del = 1;
1155 if (tag->atts.entry.file &&
1156 tag->atts.entry.file->lang == langJava)
1158 new_name = g_strdup_printf ("%s.%s",
1159 tag->atts.entry.scope,
1160 new_name);
1162 else
1164 new_name = g_strdup_printf ("%s::%s",
1165 tag->atts.entry.scope,
1166 new_name);
1169 break;
1171 else
1173 return NULL;
1177 g_ptr_array_set_size (tags, 0);
1179 if (no_definitions && tag && tag->atts.entry.file)
1181 local = tm_tags_extract (tag->atts.entry.file->work_object.tags_array,
1182 (tm_tag_function_t | tm_tag_prototype_t |
1183 tm_tag_member_t | tm_tag_field_t |
1184 tm_tag_method_t | tm_tag_enumerator_t));
1186 else
1188 local = tm_tags_extract (theWorkspace->work_object.tags_array,
1189 (tm_tag_function_t | tm_tag_prototype_t |
1190 tm_tag_member_t | tm_tag_field_t |
1191 tm_tag_method_t | tm_tag_enumerator_t));
1193 if (local)
1195 found = find_scope_members_tags (local, tags, langJava, new_name,
1196 filename, no_definitions);
1197 g_ptr_array_free (local, TRUE);
1199 if (!found && search_global)
1201 GPtrArray *global = tm_tags_extract (theWorkspace->global_tags,
1202 (tm_tag_member_t |
1203 tm_tag_prototype_t |
1204 tm_tag_field_t |
1205 tm_tag_method_t |
1206 tm_tag_function_t |
1207 tm_tag_enumerator_t
1208 |tm_tag_struct_t | tm_tag_typedef_t |
1209 tm_tag_union_t | tm_tag_enum_t));
1210 if (global)
1212 find_scope_members_tags (global, tags, langJava, new_name,
1213 filename, no_definitions);
1214 g_ptr_array_free (global, TRUE);
1217 if (del)
1219 g_free (new_name);
1222 return tags;
1225 const GPtrArray *tm_workspace_get_parents(const gchar *name)
1227 static TMTagAttrType type[] = { tm_tag_attr_name_t, tm_tag_attr_none_t };
1228 static GPtrArray *parents = NULL;
1229 const GPtrArray *matches;
1230 guint i = 0;
1231 guint j;
1232 gchar **klasses;
1233 gchar **klass;
1234 TMTag *tag;
1236 g_return_val_if_fail(name && isalpha(*name),NULL);
1238 if (NULL == parents)
1239 parents = g_ptr_array_new();
1240 else
1241 g_ptr_array_set_size(parents, 0);
1242 matches = tm_workspace_find(name, tm_tag_class_t, type, FALSE, -1);
1243 if ((NULL == matches) || (0 == matches->len))
1244 return NULL;
1245 g_ptr_array_add(parents, matches->pdata[0]);
1246 while (i < parents->len)
1248 tag = TM_TAG(parents->pdata[i]);
1249 if ((NULL != tag->atts.entry.inheritance) && (isalpha(tag->atts.entry.inheritance[0])))
1251 klasses = g_strsplit(tag->atts.entry.inheritance, ",", 10);
1252 for (klass = klasses; (NULL != *klass); ++ klass)
1254 for (j=0; j < parents->len; ++j)
1256 if (0 == strcmp(*klass, TM_TAG(parents->pdata[j])->name))
1257 break;
1259 if (parents->len == j)
1261 matches = tm_workspace_find(*klass, tm_tag_class_t, type, FALSE, -1);
1262 if ((NULL != matches) && (0 < matches->len))
1263 g_ptr_array_add(parents, matches->pdata[0]);
1266 g_strfreev(klasses);
1268 ++ i;
1270 return parents;