Force selection to change when Default or Alt colourscheme chosen
[geany-mirror.git] / tagmanager / tm_symbol.c
blobd36b50227c0e9d0a033742a8c7fc1fd4ea6dc9ed
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 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include "tm_symbol.h"
16 #define SYM_NEW(T) ((T) = g_slice_new0(TMSymbol))
17 #define SYM_FREE(T) g_slice_free(TMSymbol, (T))
20 void tm_symbol_print(TMSymbol *sym, guint level)
22 guint i;
24 g_return_if_fail (sym != NULL);
25 for (i=0; i < level; ++i)
26 fputc('\t', stderr);
27 fprintf(stderr, "%s\n", (sym->tag)?sym->tag->name:"Root");
28 if (sym->info.children)
30 if (sym->tag && tm_tag_function_t == sym->tag->type)
31 tm_tag_print(sym->info.equiv, stderr);
32 else
34 for (i=0; i < sym->info.children->len; ++i)
35 tm_symbol_print(TM_SYMBOL(sym->info.children->pdata[i])
36 , level + 1);
41 #define SYM_ORDER(T) (((tm_tag_class_t == (T)->type) || (tm_tag_struct_t ==\
42 (T)->type))?1:(((tm_tag_enum_t == (T)->type) || (tm_tag_interface_t ==\
43 (T)->type))?2:3))
45 /* Comparison function for sorting symbols alphabetically */
46 int tm_symbol_compare(const void *p1, const void *p2)
48 TMSymbol *s1, *s2;
50 if (!p1 && !p2)
51 return 0;
52 else if (!p2)
53 return 1;
54 else if (!p1)
55 return -1;
56 s1 = *(TMSymbol **) p1;
57 s2 = *(TMSymbol **) p2;
58 if (!s1 && !s2)
59 return 0;
60 else if (!s2)
61 return 1;
62 else if (!s1)
63 return -1;
64 if (!s1->tag && !s2->tag)
65 return 0;
66 else if (!s2->tag)
67 return 1;
68 else if (!s1->tag)
69 return -1;
70 return strcmp(s1->tag->name, s2->tag->name);
74 * Compares function argument lists.
75 * FIXME: Compare based on types, not an exact string match.
77 int tm_arglist_compare(const TMTag* t1, const TMTag* t2)
79 return strcmp(NVL(t1->atts.entry.arglist, ""),
80 NVL(t2->atts.entry.arglist, ""));
83 /* Need this custom compare function to generate a symbol tree
84 in a simgle pass from tag list */
85 int tm_symbol_tag_compare(const TMTag **t1, const TMTag **t2)
87 gint s1, s2;
89 if (!t1 && !t2)
90 return 0;
91 if (t1 && t2 && !*t1 && !*t2)
92 return 0;
93 else if (!t1 || !*t1)
94 return -1;
95 else if (!t2 || !*t2)
96 return 1;
97 if ((tm_tag_file_t == (*t1)->type) && (tm_tag_file_t == (*t2)->type))
98 return 0;
99 else if (tm_tag_file_t == (*t1)->type)
100 return -1;
101 else if (tm_tag_file_t == (*t2)->type)
102 return 1;
104 /* Compare on depth of scope - less depth gets higher priortity */
105 s1 = tm_tag_scope_depth(*t1);
106 s2 = tm_tag_scope_depth(*t2);
107 if (s1 != s2)
108 return (s1 - s2);
110 /* Compare of tag type using a symbol ordering routine */
111 s1 = SYM_ORDER(*t1);
112 s2 = SYM_ORDER(*t2);
113 if (s1 != s2)
114 return (s1 - s2);
116 /* Compare names alphabetically */
117 s1 = strcmp((*t1)->name, (*t2)->name);
118 if (s1 != 0)
119 return (s1);
121 /* Compare scope alphabetically */
122 s1 = strcmp(NVL((*t1)->atts.entry.scope, ""),
123 NVL((*t2)->atts.entry.scope, ""));
124 if (s1 != 0)
125 return s1;
127 /* If none of them are function/prototype, they are effectively equal */
128 if ((tm_tag_function_t != (*t1)->type) &&
129 (tm_tag_prototype_t != (*t1)->type)&&
130 (tm_tag_function_t != (*t2)->type) &&
131 (tm_tag_prototype_t != (*t2)->type))
132 return 0;
134 /* Whichever is not a function/prototype goes first */
135 if ((tm_tag_function_t != (*t1)->type) &&
136 (tm_tag_prototype_t != (*t1)->type))
137 return -1;
138 if ((tm_tag_function_t != (*t2)->type) &&
139 (tm_tag_prototype_t != (*t2)->type))
140 return 1;
142 /* Compare the argument list */
143 s1 = tm_arglist_compare(*t1, *t2);
144 if (s1 != 0)
145 return s1;
147 /* Functions go before prototypes */
148 if ((tm_tag_function_t == (*t1)->type) &&
149 (tm_tag_function_t != (*t2)->type))
150 return -1;
151 if ((tm_tag_function_t != (*t1)->type) &&
152 (tm_tag_function_t == (*t2)->type))
153 return 1;
155 /* Give up */
156 return 0;
159 TMSymbol *tm_symbol_tree_new(GPtrArray *tags_array)
161 TMSymbol *root = NULL;
162 GPtrArray *tags;
164 #ifdef TM_DEBUG
165 g_message("Building symbol tree..");
166 #endif
168 if ((!tags_array) || (tags_array->len <= 0))
169 return NULL;
171 #ifdef TM_DEBUG
172 fprintf(stderr, "Dumping all tags..\n");
173 tm_tags_array_print(tags_array, stderr);
174 #endif
176 tags = tm_tags_extract(tags_array, tm_tag_max_t);
177 #ifdef TM_DEBUG
178 fprintf(stderr, "Dumping unordered tags..\n");
179 tm_tags_array_print(tags, stderr);
180 #endif
182 if (tags && (tags->len > 0))
184 guint i;
185 int j;
186 int max_parents = -1;
187 TMTag *tag;
188 TMSymbol *sym = NULL, *sym1;
189 char *parent_name;
190 char *scope_end;
191 gboolean matched;
192 int str_match;
194 SYM_NEW(root);
195 tm_tags_custom_sort(tags, (TMTagCompareFunc) tm_symbol_tag_compare
196 , FALSE);
198 #ifdef TM_DEBUG
199 fprintf(stderr, "Dumping ordered tags..");
200 tm_tags_array_print(tags, stderr);
201 fprintf(stderr, "Rebuilding symbol table..\n");
202 #endif
203 for (i=0; i < tags->len; ++i)
205 tag = TM_TAG(tags->pdata[i]);
207 if (tm_tag_prototype_t == tag->type)
209 if (sym && (tm_tag_function_t == sym->tag->type) &&
210 (!sym->info.equiv) &&
211 (0 == strcmp(NVL(tag->atts.entry.scope, "")
212 , NVL(sym->tag->atts.entry.scope, ""))))
214 sym->info.equiv = tag;
215 continue;
218 if (max_parents < 0)
220 if (SYM_ORDER(tag) > 2)
222 max_parents = i;
223 if (max_parents > 0)
224 qsort(root->info.children->pdata, max_parents
225 , sizeof(gpointer), tm_symbol_compare);
228 SYM_NEW(sym);
229 sym->tag = tag;
230 if ((max_parents <= 0) || (!tag->atts.entry.scope))
232 sym->parent = root;
233 if (!root->info.children)
234 root->info.children = g_ptr_array_new();
235 g_ptr_array_add(root->info.children, sym);
237 else
239 parent_name = tag->atts.entry.scope;
240 scope_end = strstr(tag->atts.entry.scope, "::");
241 if (scope_end)
242 *scope_end = '\0';
243 matched = FALSE;
244 if (('\0' != parent_name[0]) &&
245 (0 != strcmp(parent_name, "<anonymous>")))
247 for (j=0; j < max_parents; ++j)
249 sym1 = TM_SYMBOL(root->info.children->pdata[j]);
250 str_match = strcmp(sym1->tag->name, parent_name);
251 if (str_match == 0)
253 matched = TRUE;
254 sym->parent = sym1;
255 if (!sym1->info.children)
256 sym1->info.children = g_ptr_array_new();
257 g_ptr_array_add(sym1->info.children, sym);
258 break;
260 else if (str_match > 0)
261 break;
264 if (!matched)
266 sym->parent = root;
267 if (!root->info.children)
268 root->info.children = g_ptr_array_new();
269 g_ptr_array_add(root->info.children, sym);
271 if (scope_end)
272 *scope_end = ':';
275 #ifdef TM_DEBUG
276 fprintf(stderr, "Done.Dumping symbol tree..");
277 tm_symbol_print(root, 0);
278 #endif
280 if (tags)
281 g_ptr_array_free(tags, TRUE);
283 return root;
286 static void tm_symbol_free(TMSymbol *sym)
288 if (!sym)
289 return;
290 if ((!sym->tag) || ((tm_tag_function_t != sym->tag->type) &&
291 (tm_tag_prototype_t != sym->tag->type)))
293 if (sym->info.children)
295 guint i;
296 for (i=0; i < sym->info.children->len; ++i)
297 tm_symbol_free(TM_SYMBOL(sym->info.children->pdata[i]));
298 g_ptr_array_free(sym->info.children, TRUE);
299 sym->info.children = NULL;
302 SYM_FREE(sym);
305 void tm_symbol_tree_free(gpointer root)
307 if (root)
308 tm_symbol_free(TM_SYMBOL(root));
311 TMSymbol *tm_symbol_tree_update(TMSymbol *root, GPtrArray *tags)
313 if (root)
314 tm_symbol_free(root);
315 if ((tags) && (tags->len > 0))
316 return tm_symbol_tree_new(tags);
317 else
318 return NULL;