r5123 | ntrel | 2010-08-10 17:12:24 +0100 (Tue, 10 Aug 2010) | 4 lines
[geany-mirror.git] / tagmanager / tm_symbol.c
blobfa18ff47accb062ca3e1f2b1604ce87a24d52d9e
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 #if GLIB_CHECK_VERSION (2, 10, 0)
17 /* Use GSlices if present */
19 #define SYM_NEW(T) ((T) = g_slice_new0(TMSymbol))
20 #define SYM_FREE(T) g_slice_free(TMSymbol, (T))
22 #else /* GLib < 2.10 */
24 static GMemChunk *sym_mem_chunk = NULL;
26 #define SYM_NEW(T) {\
27 if (!sym_mem_chunk) \
28 sym_mem_chunk = g_mem_chunk_new("TMSymbol MemChunk", sizeof(TMSymbol), 1024 \
29 , G_ALLOC_AND_FREE); \
30 (T) = g_chunk_new0(TMSymbol, sym_mem_chunk);}
32 #define SYM_FREE(T) g_mem_chunk_free(sym_mem_chunk, (T))
34 #endif /* GLib version check */
37 void tm_symbol_print(TMSymbol *sym, guint level)
39 guint i;
41 g_return_if_fail (sym != NULL);
42 for (i=0; i < level; ++i)
43 fputc('\t', stderr);
44 fprintf(stderr, "%s\n", (sym->tag)?sym->tag->name:"Root");
45 if (sym->info.children)
47 if (sym->tag && tm_tag_function_t == sym->tag->type)
48 tm_tag_print(sym->info.equiv, stderr);
49 else
51 for (i=0; i < sym->info.children->len; ++i)
52 tm_symbol_print(TM_SYMBOL(sym->info.children->pdata[i])
53 , level + 1);
58 #define SYM_ORDER(T) (((tm_tag_class_t == (T)->type) || (tm_tag_struct_t ==\
59 (T)->type))?1:(((tm_tag_enum_t == (T)->type) || (tm_tag_interface_t ==\
60 (T)->type))?2:3))
62 /* Comparison function for sorting symbols alphabetically */
63 int tm_symbol_compare(const void *p1, const void *p2)
65 TMSymbol *s1, *s2;
67 if (!p1 && !p2)
68 return 0;
69 else if (!p2)
70 return 1;
71 else if (!p1)
72 return -1;
73 s1 = *(TMSymbol **) p1;
74 s2 = *(TMSymbol **) p2;
75 if (!s1 && !s2)
76 return 0;
77 else if (!s2)
78 return 1;
79 else if (!s1)
80 return -1;
81 if (!s1->tag && !s2->tag)
82 return 0;
83 else if (!s2->tag)
84 return 1;
85 else if (!s1->tag)
86 return -1;
87 return strcmp(s1->tag->name, s2->tag->name);
91 * Compares function argument lists.
92 * FIXME: Compare based on types, not an exact string match.
94 int tm_arglist_compare(const TMTag* t1, const TMTag* t2)
96 return strcmp(NVL(t1->atts.entry.arglist, ""),
97 NVL(t2->atts.entry.arglist, ""));
100 /* Need this custom compare function to generate a symbol tree
101 in a simgle pass from tag list */
102 int tm_symbol_tag_compare(const TMTag **t1, const TMTag **t2)
104 gint s1, s2;
106 if ((!t1 && !t2) || (!*t1 && !*t2))
107 return 0;
108 else if (!t1 || !*t1)
109 return -1;
110 else if (!t2 || !*t2)
111 return 1;
112 if ((tm_tag_file_t == (*t1)->type) && (tm_tag_file_t == (*t2)->type))
113 return 0;
114 else if (tm_tag_file_t == (*t1)->type)
115 return -1;
116 else if (tm_tag_file_t == (*t2)->type)
117 return 1;
119 /* Compare on depth of scope - less depth gets higher priortity */
120 s1 = tm_tag_scope_depth(*t1);
121 s2 = tm_tag_scope_depth(*t2);
122 if (s1 != s2)
123 return (s1 - s2);
125 /* Compare of tag type using a symbol ordering routine */
126 s1 = SYM_ORDER(*t1);
127 s2 = SYM_ORDER(*t2);
128 if (s1 != s2)
129 return (s1 - s2);
131 /* Compare names alphabetically */
132 s1 = strcmp((*t1)->name, (*t2)->name);
133 if (s1 != 0)
134 return (s1);
136 /* Compare scope alphabetically */
137 s1 = strcmp(NVL((*t1)->atts.entry.scope, ""),
138 NVL((*t2)->atts.entry.scope, ""));
139 if (s1 != 0)
140 return s1;
142 /* If none of them are function/prototype, they are effectively equal */
143 if ((tm_tag_function_t != (*t1)->type) &&
144 (tm_tag_prototype_t != (*t1)->type)&&
145 (tm_tag_function_t != (*t2)->type) &&
146 (tm_tag_prototype_t != (*t2)->type))
147 return 0;
149 /* Whichever is not a function/prototype goes first */
150 if ((tm_tag_function_t != (*t1)->type) &&
151 (tm_tag_prototype_t != (*t1)->type))
152 return -1;
153 if ((tm_tag_function_t != (*t2)->type) &&
154 (tm_tag_prototype_t != (*t2)->type))
155 return 1;
157 /* Compare the argument list */
158 s1 = tm_arglist_compare(*t1, *t2);
159 if (s1 != 0)
160 return s1;
162 /* Functions go before prototypes */
163 if ((tm_tag_function_t == (*t1)->type) &&
164 (tm_tag_function_t != (*t2)->type))
165 return -1;
166 if ((tm_tag_function_t != (*t1)->type) &&
167 (tm_tag_function_t == (*t2)->type))
168 return 1;
170 /* Give up */
171 return 0;
174 TMSymbol *tm_symbol_tree_new(GPtrArray *tags_array)
176 TMSymbol *root = NULL;
177 GPtrArray *tags;
179 #ifdef TM_DEBUG
180 g_message("Building symbol tree..");
181 #endif
183 if ((!tags_array) || (tags_array->len <= 0))
184 return NULL;
186 #ifdef TM_DEBUG
187 fprintf(stderr, "Dumping all tags..\n");
188 tm_tags_array_print(tags_array, stderr);
189 #endif
191 tags = tm_tags_extract(tags_array, tm_tag_max_t);
192 #ifdef TM_DEBUG
193 fprintf(stderr, "Dumping unordered tags..\n");
194 tm_tags_array_print(tags, stderr);
195 #endif
197 if (tags && (tags->len > 0))
199 guint i;
200 int j;
201 int max_parents = -1;
202 TMTag *tag;
203 TMSymbol *sym = NULL, *sym1;
204 char *parent_name;
205 char *scope_end;
206 gboolean matched;
207 int str_match;
209 SYM_NEW(root);
210 tm_tags_custom_sort(tags, (TMTagCompareFunc) tm_symbol_tag_compare
211 , FALSE);
213 #ifdef TM_DEBUG
214 fprintf(stderr, "Dumping ordered tags..");
215 tm_tags_array_print(tags, stderr);
216 fprintf(stderr, "Rebuilding symbol table..\n");
217 #endif
218 for (i=0; i < tags->len; ++i)
220 tag = TM_TAG(tags->pdata[i]);
222 if (tm_tag_prototype_t == tag->type)
224 if (sym && (tm_tag_function_t == sym->tag->type) &&
225 (!sym->info.equiv) &&
226 (0 == strcmp(NVL(tag->atts.entry.scope, "")
227 , NVL(sym->tag->atts.entry.scope, ""))))
229 sym->info.equiv = tag;
230 continue;
233 if (max_parents < 0)
235 if (SYM_ORDER(tag) > 2)
237 max_parents = i;
238 if (max_parents > 0)
239 qsort(root->info.children->pdata, max_parents
240 , sizeof(gpointer), tm_symbol_compare);
243 SYM_NEW(sym);
244 sym->tag = tag;
245 if ((max_parents <= 0) || (!tag->atts.entry.scope))
247 sym->parent = root;
248 if (!root->info.children)
249 root->info.children = g_ptr_array_new();
250 g_ptr_array_add(root->info.children, sym);
252 else
254 parent_name = tag->atts.entry.scope;
255 scope_end = strstr(tag->atts.entry.scope, "::");
256 if (scope_end)
257 *scope_end = '\0';
258 matched = FALSE;
259 if (('\0' != parent_name[0]) &&
260 (0 != strcmp(parent_name, "<anonymous>")))
262 for (j=0; j < max_parents; ++j)
264 sym1 = TM_SYMBOL(root->info.children->pdata[j]);
265 str_match = strcmp(sym1->tag->name, parent_name);
266 if (str_match == 0)
268 matched = TRUE;
269 sym->parent = sym1;
270 if (!sym1->info.children)
271 sym1->info.children = g_ptr_array_new();
272 g_ptr_array_add(sym1->info.children, sym);
273 break;
275 else if (str_match > 0)
276 break;
279 if (!matched)
281 sym->parent = root;
282 if (!root->info.children)
283 root->info.children = g_ptr_array_new();
284 g_ptr_array_add(root->info.children, sym);
286 if (scope_end)
287 *scope_end = ':';
290 #ifdef TM_DEBUG
291 fprintf(stderr, "Done.Dumping symbol tree..");
292 tm_symbol_print(root, 0);
293 #endif
295 if (tags)
296 g_ptr_array_free(tags, TRUE);
298 return root;
301 static void tm_symbol_free(TMSymbol *sym)
303 if (!sym)
304 return;
305 if ((!sym->tag) || ((tm_tag_function_t != sym->tag->type) &&
306 (tm_tag_prototype_t != sym->tag->type)))
308 if (sym->info.children)
310 guint i;
311 for (i=0; i < sym->info.children->len; ++i)
312 tm_symbol_free(TM_SYMBOL(sym->info.children->pdata[i]));
313 g_ptr_array_free(sym->info.children, TRUE);
314 sym->info.children = NULL;
317 SYM_FREE(sym);
320 void tm_symbol_tree_free(gpointer root)
322 if (root)
323 tm_symbol_free(TM_SYMBOL(root));
326 TMSymbol *tm_symbol_tree_update(TMSymbol *root, GPtrArray *tags)
328 if (root)
329 tm_symbol_free(root);
330 if ((tags) && (tags->len > 0))
331 return tm_symbol_tree_new(tags);
332 else
333 return NULL;