22
// handling of P_tmpdir, should be something like /tmp, take the root directory under Win32,
23
// and assume /tmp on non-Win32 systems where P_tmpdir is not set
26
# define P_tmpdir "\\"
28
# define P_tmpdir "/tmp"
22
#include <glib/gstdio.h>
32
24
#include "tm_tag.h"
33
25
#include "tm_workspace.h"
34
26
#include "tm_project.h"
36
29
static TMWorkspace *theWorkspace = NULL;
37
30
guint workspace_class_id = 0;
39
32
static gboolean tm_create_workspace(void)
42
char *file_name = g_strdup_printf("%s_%s_%ld.%d", P_tmpdir, PACKAGE, time(NULL), getpid());
44
char *file_name = g_strdup_printf("%s/%s_%ld.%d", P_tmpdir, PACKAGE, time(NULL), getpid());
47
34
workspace_class_id = tm_work_object_register(tm_workspace_free, tm_workspace_update
48
35
, tm_workspace_find_object);
49
36
theWorkspace = g_new(TMWorkspace, 1);
50
37
if (FALSE == tm_work_object_init(TM_WORK_OBJECT(theWorkspace),
51
workspace_class_id, file_name, TRUE))
38
workspace_class_id, NULL, TRUE))
54
40
g_free(theWorkspace);
55
41
theWorkspace = NULL;
56
42
g_warning("Failed to initialize workspace");
61
46
theWorkspace->global_tags = NULL;
62
47
theWorkspace->work_objects = NULL;
116
gboolean tm_workspace_remove_object(TMWorkObject *w, gboolean free)
101
gboolean tm_workspace_remove_object(TMWorkObject *w, gboolean do_free, gboolean update)
119
104
if ((NULL == theWorkspace) || (NULL == theWorkspace->work_objects)
122
109
for (i=0; i < theWorkspace->work_objects->len; ++i)
124
111
if (theWorkspace->work_objects->pdata[i] == w)
127
114
tm_work_object_free(w);
128
115
g_ptr_array_remove_index_fast(theWorkspace->work_objects, i);
129
tm_workspace_update(TM_WORK_OBJECT(theWorkspace), TRUE, FALSE, FALSE);
117
tm_workspace_update(TM_WORK_OBJECT(theWorkspace), TRUE, FALSE, FALSE);
125
static TMTagAttrType global_tags_sort_attrs[] =
127
tm_tag_attr_name_t, tm_tag_attr_scope_t,
128
tm_tag_attr_type_t, tm_tag_attr_arglist_t, 0
136
131
gboolean tm_workspace_load_global_tags(const char *tags_file, gint mode)
140
TMTagAttrType attr[] = { tm_tag_attr_name_t, 0 };
142
if (NULL == (fp = fopen(tags_file, "r")))
136
if (NULL == (fp = g_fopen(tags_file, "r")))
144
138
if (NULL == theWorkspace)
145
tm_create_workspace();
146
140
if (NULL == theWorkspace->global_tags)
147
141
theWorkspace->global_tags = g_ptr_array_new();
148
142
while (NULL != (tag = tm_tag_new_from_file(NULL, fp, mode)))
149
143
g_ptr_array_add(theWorkspace->global_tags, tag);
152
// resort the whole array, because tm_tags_find expects a sorted array and it is not sorted
153
// when global.tags, php.tags and latex.tags are loaded at the same time
154
tm_tags_sort(theWorkspace->global_tags, attr, TRUE);
146
/* resort the whole array, because tm_tags_find expects a sorted array and it is not sorted
147
* when global.tags, php.tags and latex.tags are loaded at the same time */
148
tm_tags_sort(theWorkspace->global_tags, global_tags_sort_attrs, TRUE);
159
gboolean tm_workspace_create_global_tags(const char *pre_process, const char **includes
160
, int includes_count, const char *tags_file)
153
static guint tm_file_inode_hash(gconstpointer key)
155
struct stat file_stat;
156
const char *filename = (const char*)key;
157
if (g_stat(filename, &file_stat) == 0)
160
g_message ("Hash for '%s' is '%d'\n", filename, file_stat.st_ino);
162
return g_direct_hash (GUINT_TO_POINTER (file_stat.st_ino));
168
static void tm_move_entries_to_g_list(gpointer key, gpointer value, gpointer user_data)
170
GList **pp_list = (GList**)user_data;
172
if (user_data == NULL)
175
*pp_list = g_list_prepend(*pp_list, value);
178
static void write_includes_file(FILE *fp, GList *includes_files)
182
node = includes_files;
185
char *str = g_strdup_printf("#include \"%s\"\n", (char*)node->data);
186
int str_len = strlen(str);
188
fwrite(str, str_len, 1, fp);
190
node = g_list_next (node);
195
static void append_to_temp_file(FILE *fp, GList *file_list)
202
const char *fname = node->data;
207
if (! g_file_get_contents(fname, &contents, &length, &err))
209
fprintf(stderr, "Unable to read file: %s\n", err->message);
214
fwrite(contents, length, 1, fp);
215
fwrite("\n", 1, 1, fp); /* in case file doesn't end in newline (e.g. windows). */
218
node = g_list_next (node);
222
static gint get_global_tag_type_mask(gint lang)
229
return tm_tag_class_t | tm_tag_typedef_t | tm_tag_enum_t | tm_tag_enumerator_t |
231
tm_tag_function_t | tm_tag_method_t | /* for inline functions */
232
tm_tag_macro_t | tm_tag_macro_with_arg_t;
238
gboolean tm_workspace_create_global_tags(const char *config_dir, const char *pre_process,
239
const char **includes, int includes_count, const char *tags_file, int lang)
162
241
#ifdef HAVE_GLOB_H
170
249
TMWorkObject *source_file;
171
250
GPtrArray *tags_array;
251
GHashTable *includes_files_hash;
172
252
GList *includes_files = NULL;
176
int remove_count = 0;
177
253
#ifdef G_OS_WIN32
178
char *temp_file = g_strdup_printf("%s_%d_%ld_1.cpp", P_tmpdir, getpid(), time(NULL));
179
char *temp_file2 = g_strdup_printf("%s_%d_%ld_2.cpp", P_tmpdir, getpid(), time(NULL));
254
char *temp_file = g_strdup_printf("%s\\_%d_%ld_1.cpp", config_dir, getpid(), time(NULL));
255
char *temp_file2 = g_strdup_printf("%s\\_%d_%ld_2.cpp", config_dir, getpid(), time(NULL));
181
char *temp_file = g_strdup_printf("%s/%d_%ld_1.cpp", P_tmpdir, getpid(), time(NULL));
182
char *temp_file2 = g_strdup_printf("%s/%d_%ld_2.cpp", P_tmpdir, getpid(), time(NULL));
257
char *temp_file = g_strdup_printf("%s/%d_%ld_1.cpp", config_dir, getpid(), time(NULL));
258
char *temp_file2 = g_strdup_printf("%s/%d_%ld_2.cpp", config_dir, getpid(), time(NULL));
184
TMTagAttrType sort_attrs[] = { tm_tag_attr_name_t, tm_tag_attr_scope_t
185
, tm_tag_attr_type_t, 0};
186
if (NULL == (fp = fopen(temp_file, "w")))
261
if (NULL == theWorkspace || NULL == (fp = g_fopen(temp_file, "w")))
264
includes_files_hash = g_hash_table_new_full (tm_file_inode_hash,
189
268
#ifdef HAVE_GLOB_H
190
269
globbuf.gl_offs = 0;
271
if (includes[0][0] == '"') /* leading \" char for glob matching */
191
272
for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
193
274
int dirty_len = strlen(includes[idx_inc]);
194
char *clean_path = malloc(dirty_len - 1);
275
char *clean_path = g_malloc(dirty_len - 1);
195
276
strncpy(clean_path, includes[idx_inc] + 1, dirty_len - 1);
196
277
clean_path[dirty_len - 2] = 0;
198
//printf("[o][%s]\n", clean_path);
280
g_message ("[o][%s]\n", clean_path);
199
282
glob(clean_path, 0, NULL, &globbuf);
200
//printf("matches: %d\n", globbuf.gl_pathc);
285
g_message ("matches: %d\n", globbuf.gl_pathc);
201
288
for(idx_glob = 0; idx_glob < globbuf.gl_pathc; idx_glob++)
203
includes_files = g_list_append(includes_files, strdup(globbuf.gl_pathv[idx_glob]));
204
//printf(">>> %s\n", globbuf.gl_pathv[idx_glob]);
291
g_message (">>> %s\n", globbuf.gl_pathv[idx_glob]);
293
if (!g_hash_table_lookup(includes_files_hash,
294
globbuf.gl_pathv[idx_glob]))
296
char* file_name_copy = strdup(globbuf.gl_pathv[idx_glob]);
297
g_hash_table_insert(includes_files_hash, file_name_copy,
300
g_message ("Added ...\n");
206
304
globfree(&globbuf);
207
305
free(clean_path);
309
/* no glob support or globbing not wanted */
210
310
for(idx_inc = 0; idx_inc < includes_count; idx_inc++)
212
includes_files = g_list_append(includes_files, strdup(includes[idx_inc]));
312
if (!g_hash_table_lookup(includes_files_hash,
315
char* file_name_copy = strdup(includes[idx_inc]);
316
g_hash_table_insert(includes_files_hash, file_name_copy,
217
321
/* Checks for duplicate file entries which would case trouble */
219
struct stat main_stat;
220
struct stat sub_stat;
224
list_len = g_list_length(includes_files);
226
/* We look for files with the same inode */
227
for(idx_main = 0; idx_main < list_len; idx_main++)
229
// printf("%d / %d\n", idx_main, list_len - 1);
230
stat(g_list_nth_data(includes_files, idx_main), &main_stat);
231
for(idx_sub = idx_main + 1; idx_sub < list_len; idx_sub++)
233
GList *element = NULL;
235
stat(g_list_nth_data(includes_files, idx_sub), &sub_stat);
238
if(main_stat.st_ino != sub_stat.st_ino)
243
element = g_list_nth(includes_files, idx_sub);
245
/* printf("%s == %s\n", g_list_nth_data(includes_files, idx_main),
246
g_list_nth_data(includes_files, idx_sub)); */
248
/* We delete the duplicate entry from the list */
249
includes_files = g_list_remove_link(includes_files, element);
252
/* Don't forget to free the mallocs (we duplicated every string earlier!) */
255
idx_sub--; /* Cause the inner loop not to move; good since we removed
256
an element at the current position; we don't have to worry
257
about the outer loop because the inner loop always starts
258
after the outer loop's index */
260
list_len = g_list_length(includes_files);
266
printf("writing out files to %s\n", temp_file);
267
for(idx_main = 0; idx_main < g_list_length(includes_files); idx_main++)
269
char *str = g_strdup_printf("#include \"%s\"\n",
270
(char*)g_list_nth_data(includes_files,
272
int str_len = strlen(str);
274
fwrite(str, str_len, 1, fp);
277
free(g_list_nth(includes_files, idx_main) -> data);
322
g_hash_table_foreach(includes_files_hash, tm_move_entries_to_g_list,
325
includes_files = g_list_reverse (includes_files);
328
g_message ("writing out files to %s\n", temp_file);
330
if (pre_process != NULL)
331
write_includes_file(fp, includes_files);
333
append_to_temp_file(fp, includes_files);
335
g_list_free (includes_files);
336
g_hash_table_destroy(includes_files_hash);
337
includes_files_hash = NULL;
338
includes_files = NULL;
282
command = g_strdup_printf("%s %s >%s", pre_process, temp_file, temp_file2);
287
source_file = tm_source_file_new(temp_file2, TRUE, NULL);
341
/* FIXME: The following grep command removes the lines
342
* G_BEGIN_DECLS and G_END_DECLS from the header files. The reason is
343
* that in tagmanager, the files are not correctly parsed and the typedefs
344
* following these lines are incorrectly parsed. The real fix should,
345
* of course be in tagmanager (c) parser. This is just a temporary fix.
347
if (pre_process != NULL)
349
command = g_strdup_printf("%s %s | grep -v -E '^\\s*(G_BEGIN_DECLS|G_END_DECLS)\\s*$' > %s",
350
pre_process, temp_file, temp_file2);
352
g_message("Executing: %s", command);
361
/* no pre-processing needed, so temp_file2 = temp_file */
363
temp_file2 = temp_file;
366
source_file = tm_source_file_new(temp_file2, TRUE, tm_source_file_get_lang_name(lang));
288
367
if (NULL == source_file)
369
g_unlink(temp_file2);
372
g_unlink(temp_file2);
294
373
g_free(temp_file2);
295
374
if ((NULL == source_file->tags_array) || (0 == source_file->tags_array->len))
297
376
tm_source_file_free(source_file);
300
tags_array = tm_tags_extract(source_file->tags_array, tm_tag_class_t |
301
tm_tag_typedef_t | tm_tag_prototype_t | tm_tag_enum_t | tm_tag_macro_with_arg_t);
379
tags_array = tm_tags_extract(source_file->tags_array, get_global_tag_type_mask(lang));
302
380
if ((NULL == tags_array) || (0 == tags_array->len))
524
tm_tags_sort(tags, attrs, TRUE);
604
tm_tags_sort(tags, attrs, TRUE);
608
static gboolean match_langs(gint lang, const TMTag *tag)
610
if (tag->atts.entry.file)
611
{ /* workspace tag */
612
if (lang == tag->atts.entry.file->lang)
617
if (lang == tag->atts.file.lang)
623
/* scope can be NULL.
626
fill_find_tags_array (GPtrArray *dst, const GPtrArray *src,
627
const char *name, const char *scope, int type, gboolean partial,
628
gint lang, gboolean first)
633
if ((!src) || (!dst) || (!name) || (!*name))
636
match = tm_tags_find (src, name, partial, &count);
637
if (count && match && *match)
639
for (tagIter = 0; tagIter < count; ++tagIter)
641
if (! scope || (match[tagIter]->atts.entry.scope &&
642
0 == strcmp(match[tagIter]->atts.entry.scope, scope)))
644
if (type & match[tagIter]->type)
645
if (lang == -1 || match_langs(lang, match[tagIter]))
647
g_ptr_array_add (dst, match[tagIter]);
658
/* adapted from tm_workspace_find, Anjuta 2.02 */
660
tm_workspace_find_scoped (const char *name, const char *scope, gint type,
661
TMTagAttrType *attrs, gboolean partial, langType lang, gboolean global_search)
663
static GPtrArray *tags = NULL;
669
g_ptr_array_set_size (tags, 0);
671
tags = g_ptr_array_new ();
673
fill_find_tags_array (tags, theWorkspace->work_object.tags_array,
674
name, scope, type, partial, lang, FALSE);
677
/* for a scoped tag, I think we always want the same language */
678
fill_find_tags_array (tags, theWorkspace->global_tags,
679
name, scope, type, partial, lang, FALSE);
682
tm_tags_sort (tags, attrs, TRUE);
688
tm_get_current_function (GPtrArray * file_tags, const gulong line)
690
GPtrArray *const local = tm_tags_extract (file_tags, tm_tag_function_t);
691
if (local && local->len)
694
TMTag *tag, *function_tag = NULL;
695
gulong function_line = 0;
698
for (i = 0; (i < local->len); ++i)
700
tag = TM_TAG (local->pdata[i]);
701
delta = line - tag->atts.entry.line;
702
if (delta >= 0 && (gulong)delta < line - function_line)
705
function_line = tag->atts.entry.line;
708
g_ptr_array_free (local, TRUE);