Fix building with makefile.win32 from Windows command prompt, not MSYS
[geany-mirror.git] / tagmanager / tm_tag.c
blob9433083eb80e984ea3e8ac7b7f95d94d466d55ef
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 <stdlib.h>
11 #include <string.h>
12 #include <glib-object.h>
14 #include "general.h"
15 #include "entry.h"
16 #include "parse.h"
17 #include "read.h"
18 #define LIBCTAGS_DEFINED
19 #include "tm_tag.h"
22 #define TAG_NEW(T) ((T) = g_slice_new0(TMTag))
23 #define TAG_FREE(T) g_slice_free(TMTag, (T))
26 /* Note: To preserve binary compatibility, it is very important
27 that you only *append* to this list ! */
28 enum
30 TA_NAME = 200,
31 TA_LINE,
32 TA_LOCAL,
33 TA_POS, /* Obsolete */
34 TA_TYPE,
35 TA_ARGLIST,
36 TA_SCOPE,
37 TA_VARTYPE,
38 TA_INHERITS,
39 TA_TIME,
40 TA_ACCESS,
41 TA_IMPL,
42 TA_LANG,
43 TA_INACTIVE,
44 TA_POINTER
47 static guint *s_sort_attrs = NULL;
48 static gboolean s_partial = FALSE;
50 static const char *s_tag_type_names[] = {
51 "class", /* classes */
52 "enum", /* enumeration names */
53 "enumerator", /* enumerators (values inside an enumeration) */
54 "externvar", /* external variable declarations */
55 "field", /* fields */
56 "function", /* function definitions */
57 "interface", /* interfaces */
58 "macro", /* macro definitions */
59 "member", /* class, struct, and union members */
60 "method", /* methods */
61 "namespace", /* namespaces */
62 "package", /* packages */
63 "prototype", /* function prototypes */
64 "struct", /* structure names */
65 "typedef", /* typedefs */
66 "union", /* union names */
67 "variable", /* variable definitions */
68 "other" /* Other tag type (non C/C++/Java) */
71 static int s_tag_types[] = {
72 tm_tag_class_t,
73 tm_tag_enum_t,
74 tm_tag_enumerator_t,
75 tm_tag_externvar_t,
76 tm_tag_field_t,
77 tm_tag_function_t,
78 tm_tag_interface_t,
79 tm_tag_macro_t,
80 tm_tag_member_t,
81 tm_tag_method_t,
82 tm_tag_namespace_t,
83 tm_tag_package_t,
84 tm_tag_prototype_t,
85 tm_tag_struct_t,
86 tm_tag_typedef_t,
87 tm_tag_union_t,
88 tm_tag_variable_t,
89 tm_tag_other_t
92 GType tm_tag_get_type(void)
94 static GType gtype = 0;
95 if (G_UNLIKELY (gtype == 0))
97 gtype = g_boxed_type_register_static("TMTag", (GBoxedCopyFunc)tm_tag_ref,
98 (GBoxedFreeFunc)tm_tag_unref);
100 return gtype;
103 static int get_tag_type(const char *tag_name)
105 unsigned int i;
106 int cmp;
107 g_return_val_if_fail(tag_name, 0);
108 for (i=0; i < sizeof(s_tag_type_names)/sizeof(char *); ++i)
110 cmp = strcmp(tag_name, s_tag_type_names[i]);
111 if (0 == cmp)
112 return s_tag_types[i];
113 else if (cmp < 0)
114 break;
116 /* other is not checked above as it is last, not sorted alphabetically */
117 if (strcmp(tag_name, "other") == 0)
118 return tm_tag_other_t;
119 #ifdef TM_DEBUG
120 fprintf(stderr, "Unknown tag type %s\n", tag_name);
121 #endif
122 return tm_tag_undef_t;
125 gboolean tm_tag_init(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag_entry)
127 tag->refcount = 1;
128 if (NULL == tag_entry)
130 /* This is a file tag */
131 if (NULL == file)
132 return FALSE;
133 else
135 tag->name = g_strdup(file->work_object.file_name);
136 tag->type = tm_tag_file_t;
137 /* tag->atts.file.timestamp = file->work_object.analyze_time; */
138 tag->atts.file.lang = file->lang;
139 tag->atts.file.inactive = FALSE;
140 return TRUE;
143 else
145 /* This is a normal tag entry */
146 if (NULL == tag_entry->name)
147 return FALSE;
148 tag->name = g_strdup(tag_entry->name);
149 tag->type = get_tag_type(tag_entry->kindName);
150 tag->atts.entry.local = tag_entry->isFileScope;
151 tag->atts.entry.pointerOrder = 0; /* backward compatibility (use var_type instead) */
152 tag->atts.entry.line = tag_entry->lineNumber;
153 if (NULL != tag_entry->extensionFields.arglist)
154 tag->atts.entry.arglist = g_strdup(tag_entry->extensionFields.arglist);
155 if ((NULL != tag_entry->extensionFields.scope[1]) &&
156 (isalpha(tag_entry->extensionFields.scope[1][0]) ||
157 tag_entry->extensionFields.scope[1][0] == '_'))
158 tag->atts.entry.scope = g_strdup(tag_entry->extensionFields.scope[1]);
159 if (tag_entry->extensionFields.inheritance != NULL)
160 tag->atts.entry.inheritance = g_strdup(tag_entry->extensionFields.inheritance);
161 if (tag_entry->extensionFields.varType != NULL)
162 tag->atts.entry.var_type = g_strdup(tag_entry->extensionFields.varType);
163 if (tag_entry->extensionFields.access != NULL)
165 if (0 == strcmp("public", tag_entry->extensionFields.access))
166 tag->atts.entry.access = TAG_ACCESS_PUBLIC;
167 else if (0 == strcmp("protected", tag_entry->extensionFields.access))
168 tag->atts.entry.access = TAG_ACCESS_PROTECTED;
169 else if (0 == strcmp("private", tag_entry->extensionFields.access))
170 tag->atts.entry.access = TAG_ACCESS_PRIVATE;
171 else if (0 == strcmp("friend", tag_entry->extensionFields.access))
172 tag->atts.entry.access = TAG_ACCESS_FRIEND;
173 else if (0 == strcmp("default", tag_entry->extensionFields.access))
174 tag->atts.entry.access = TAG_ACCESS_DEFAULT;
175 else
177 #ifdef TM_DEBUG
178 g_warning("Unknown access type %s", tag_entry->extensionFields.access);
179 #endif
180 tag->atts.entry.access = TAG_ACCESS_UNKNOWN;
183 if (tag_entry->extensionFields.implementation != NULL)
185 if ((0 == strcmp("virtual", tag_entry->extensionFields.implementation))
186 || (0 == strcmp("pure virtual", tag_entry->extensionFields.implementation)))
187 tag->atts.entry.impl = TAG_IMPL_VIRTUAL;
188 else
190 #ifdef TM_DEBUG
191 g_warning("Unknown implementation %s", tag_entry->extensionFields.implementation);
192 #endif
193 tag->atts.entry.impl = TAG_IMPL_UNKNOWN;
196 if ((tm_tag_macro_t == tag->type) && (NULL != tag->atts.entry.arglist))
197 tag->type = tm_tag_macro_with_arg_t;
198 tag->atts.entry.file = file;
199 return TRUE;
203 TMTag *tm_tag_new(TMSourceFile *file, const tagEntryInfo *tag_entry)
205 TMTag *tag;
207 TAG_NEW(tag);
208 if (FALSE == tm_tag_init(tag, file, tag_entry))
210 TAG_FREE(tag);
211 return NULL;
213 return tag;
216 gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
218 guchar buf[BUFSIZ];
219 guchar *start, *end;
220 gboolean status;
221 guchar changed_char = TA_NAME;
223 tag->refcount = 1;
224 if ((NULL == fgets((gchar*)buf, BUFSIZ, fp)) || ('\0' == *buf))
225 return FALSE;
226 for (start = end = buf, status = TRUE; (TRUE == status); start = end, ++ end)
228 while ((*end < TA_NAME) && (*end != '\0') && (*end != '\n'))
229 ++ end;
230 if (('\0' == *end) || ('\n' == *end))
231 status = FALSE;
232 changed_char = *end;
233 *end = '\0';
234 if (NULL == tag->name)
236 if (!isprint(*start))
237 return FALSE;
238 else
239 tag->name = g_strdup((gchar*)start);
241 else
243 switch (*start)
245 case TA_LINE:
246 tag->atts.entry.line = atol((gchar*)start + 1);
247 break;
248 case TA_LOCAL:
249 tag->atts.entry.local = atoi((gchar*)start + 1);
250 break;
251 case TA_TYPE:
252 tag->type = (TMTagType) atoi((gchar*)start + 1);
253 break;
254 case TA_ARGLIST:
255 tag->atts.entry.arglist = g_strdup((gchar*)start + 1);
256 break;
257 case TA_SCOPE:
258 tag->atts.entry.scope = g_strdup((gchar*)start + 1);
259 break;
260 case TA_POINTER:
261 tag->atts.entry.pointerOrder = atoi((gchar*)start + 1);
262 break;
263 case TA_VARTYPE:
264 tag->atts.entry.var_type = g_strdup((gchar*)start + 1);
265 break;
266 case TA_INHERITS:
267 tag->atts.entry.inheritance = g_strdup((gchar*)start + 1);
268 break;
269 case TA_TIME:
270 if (tm_tag_file_t != tag->type)
272 g_warning("Got time attribute for non-file tag %s", tag->name);
273 return FALSE;
275 else
276 tag->atts.file.timestamp = atol((gchar*)start + 1);
277 break;
278 case TA_LANG:
279 if (tm_tag_file_t != tag->type)
281 g_warning("Got lang attribute for non-file tag %s", tag->name);
282 return FALSE;
284 else
285 tag->atts.file.lang = atoi((gchar*)start + 1);
286 break;
287 case TA_INACTIVE:
288 if (tm_tag_file_t != tag->type)
290 g_warning("Got inactive attribute for non-file tag %s", tag->name);
291 return FALSE;
293 else
294 tag->atts.file.inactive = (gboolean) atoi((gchar*)start + 1);
295 break;
296 case TA_ACCESS:
297 tag->atts.entry.access = *(start + 1);
298 break;
299 case TA_IMPL:
300 tag->atts.entry.impl = *(start + 1);
301 break;
302 default:
303 #ifdef GEANY_DEBUG
304 g_warning("Unknown attribute %s", start + 1);
305 #endif
306 break;
309 *end = changed_char;
311 if (NULL == tag->name)
312 return FALSE;
313 if (tm_tag_file_t != tag->type)
314 tag->atts.entry.file = file;
315 return TRUE;
318 /* alternative parser for Pascal and LaTeX global tags files with the following format
319 * tagname|return value|arglist|description\n */
320 gboolean tm_tag_init_from_file_alt(TMTag *tag, TMSourceFile *file, FILE *fp)
322 guchar buf[BUFSIZ];
323 guchar *start, *end;
324 gboolean status;
325 /*guchar changed_char = TA_NAME;*/
327 tag->refcount = 1;
328 if ((NULL == fgets((gchar*)buf, BUFSIZ, fp)) || ('\0' == *buf))
329 return FALSE;
331 gchar **fields;
332 guint field_len;
333 for (start = end = buf, status = TRUE; (TRUE == status); start = end, ++ end)
335 while ((*end < TA_NAME) && (*end != '\0') && (*end != '\n'))
336 ++ end;
337 if (('\0' == *end) || ('\n' == *end))
338 status = FALSE;
339 /*changed_char = *end;*/
340 *end = '\0';
341 if (NULL == tag->name && !isprint(*start))
342 return FALSE;
344 fields = g_strsplit((gchar*)start, "|", -1);
345 field_len = g_strv_length(fields);
347 if (field_len >= 1) tag->name = g_strdup(fields[0]);
348 else tag->name = NULL;
349 if (field_len >= 2 && fields[1] != NULL) tag->atts.entry.var_type = g_strdup(fields[1]);
350 if (field_len >= 3 && fields[2] != NULL) tag->atts.entry.arglist = g_strdup(fields[2]);
351 tag->type = tm_tag_prototype_t;
352 g_strfreev(fields);
356 if (NULL == tag->name)
357 return FALSE;
358 if (tm_tag_file_t != tag->type)
359 tag->atts.entry.file = file;
360 return TRUE;
363 TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp, gint mode, gboolean format_pipe)
365 TMTag *tag;
366 gboolean result;
368 TAG_NEW(tag);
370 if (format_pipe)
371 result = tm_tag_init_from_file_alt(tag, file, fp);
372 else
373 result = tm_tag_init_from_file(tag, file, fp);
375 if (! result)
377 TAG_FREE(tag);
378 return NULL;
380 tag->atts.file.lang = mode;
381 return tag;
384 gboolean tm_tag_write(TMTag *tag, FILE *fp, guint attrs)
386 fprintf(fp, "%s", tag->name);
387 if (attrs & tm_tag_attr_type_t)
388 fprintf(fp, "%c%d", TA_TYPE, tag->type);
389 if (tag->type == tm_tag_file_t)
391 if (attrs & tm_tag_attr_time_t)
392 fprintf(fp, "%c%ld", TA_TIME, tag->atts.file.timestamp);
393 if (attrs & tm_tag_attr_lang_t)
394 fprintf(fp, "%c%d", TA_LANG, tag->atts.file.lang);
395 if ((attrs & tm_tag_attr_inactive_t) && tag->atts.file.inactive)
396 fprintf(fp, "%c%d", TA_INACTIVE, tag->atts.file.inactive);
398 else
400 if ((attrs & tm_tag_attr_arglist_t) && (NULL != tag->atts.entry.arglist))
401 fprintf(fp, "%c%s", TA_ARGLIST, tag->atts.entry.arglist);
402 if (attrs & tm_tag_attr_line_t)
403 fprintf(fp, "%c%ld", TA_LINE, tag->atts.entry.line);
404 if (attrs & tm_tag_attr_local_t)
405 fprintf(fp, "%c%d", TA_LOCAL, tag->atts.entry.local);
406 if ((attrs & tm_tag_attr_scope_t) && (NULL != tag->atts.entry.scope))
407 fprintf(fp, "%c%s", TA_SCOPE, tag->atts.entry.scope);
408 if ((attrs & tm_tag_attr_inheritance_t) && (NULL != tag->atts.entry.inheritance))
409 fprintf(fp, "%c%s", TA_INHERITS, tag->atts.entry.inheritance);
410 if (attrs & tm_tag_attr_pointer_t)
411 fprintf(fp, "%c%d", TA_POINTER, tag->atts.entry.pointerOrder);
412 if ((attrs & tm_tag_attr_vartype_t) && (NULL != tag->atts.entry.var_type))
413 fprintf(fp, "%c%s", TA_VARTYPE, tag->atts.entry.var_type);
414 if ((attrs & tm_tag_attr_access_t) && (TAG_ACCESS_UNKNOWN != tag->atts.entry.access))
415 fprintf(fp, "%c%c", TA_ACCESS, tag->atts.entry.access);
416 if ((attrs & tm_tag_attr_impl_t) && (TAG_IMPL_UNKNOWN != tag->atts.entry.impl))
417 fprintf(fp, "%c%c", TA_IMPL, tag->atts.entry.impl);
419 if (fprintf(fp, "\n"))
420 return TRUE;
421 else
422 return FALSE;
425 static void tm_tag_destroy(TMTag *tag)
427 g_free(tag->name);
428 if (tm_tag_file_t != tag->type)
430 g_free(tag->atts.entry.arglist);
431 g_free(tag->atts.entry.scope);
432 g_free(tag->atts.entry.inheritance);
433 g_free(tag->atts.entry.var_type);
437 #if 0
438 void tm_tag_free(gpointer tag)
440 tm_tag_unref(tag);
442 #endif
444 void tm_tag_unref(TMTag *tag)
446 /* be NULL-proof because tm_tag_free() was NULL-proof and we indent to be a
447 * drop-in replacment of it */
448 if (NULL != tag && g_atomic_int_dec_and_test(&tag->refcount))
450 tm_tag_destroy(tag);
451 TAG_FREE(tag);
455 TMTag *tm_tag_ref(TMTag *tag)
457 g_atomic_int_inc(&tag->refcount);
458 return tag;
461 int tm_tag_compare(const void *ptr1, const void *ptr2)
463 unsigned int *sort_attr;
464 int returnval = 0;
465 TMTag *t1 = *((TMTag **) ptr1);
466 TMTag *t2 = *((TMTag **) ptr2);
468 if ((NULL == t1) || (NULL == t2))
470 g_warning("Found NULL tag");
471 return t2 - t1;
473 if (NULL == s_sort_attrs)
475 if (s_partial)
476 return strncmp(NVL(t1->name, ""), NVL(t2->name, ""), strlen(NVL(t1->name, "")));
477 else
478 return strcmp(NVL(t1->name, ""), NVL(t2->name, ""));
481 for (sort_attr = s_sort_attrs; *sort_attr != tm_tag_attr_none_t; ++ sort_attr)
483 switch (*sort_attr)
485 case tm_tag_attr_name_t:
486 if (s_partial)
487 returnval = strncmp(NVL(t1->name, ""), NVL(t2->name, ""), strlen(NVL(t1->name, "")));
488 else
489 returnval = strcmp(NVL(t1->name, ""), NVL(t2->name, ""));
490 if (0 != returnval)
491 return returnval;
492 break;
493 case tm_tag_attr_type_t:
494 if (0 != (returnval = (t1->type - t2->type)))
495 return returnval;
496 break;
497 case tm_tag_attr_file_t:
498 if (0 != (returnval = (t1->atts.entry.file - t2->atts.entry.file)))
499 return returnval;
500 break;
501 case tm_tag_attr_scope_t:
502 if (0 != (returnval = strcmp(NVL(t1->atts.entry.scope, ""), NVL(t2->atts.entry.scope, ""))))
503 return returnval;
504 break;
505 case tm_tag_attr_arglist_t:
506 if (0 != (returnval = strcmp(NVL(t1->atts.entry.arglist, ""), NVL(t2->atts.entry.arglist, ""))))
508 int line_diff = (t1->atts.entry.line - t2->atts.entry.line);
510 return line_diff ? line_diff : returnval;
512 break;
513 case tm_tag_attr_vartype_t:
514 if (0 != (returnval = strcmp(NVL(t1->atts.entry.var_type, ""), NVL(t2->atts.entry.var_type, ""))))
515 return returnval;
516 break;
517 case tm_tag_attr_line_t:
518 if (0 != (returnval = (t1->atts.entry.line - t2->atts.entry.line)))
519 return returnval;
520 break;
523 return returnval;
526 gboolean tm_tags_prune(GPtrArray *tags_array)
528 guint i, count;
529 for (i=0, count = 0; i < tags_array->len; ++i)
531 if (NULL != tags_array->pdata[i])
532 tags_array->pdata[count++] = tags_array->pdata[i];
534 tags_array->len = count;
535 return TRUE;
538 gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes)
540 guint i;
542 if ((!tags_array) || (!tags_array->len))
543 return TRUE;
544 s_sort_attrs = sort_attributes;
545 s_partial = FALSE;
546 for (i = 1; i < tags_array->len; ++i)
548 if (0 == tm_tag_compare(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i])))
550 tags_array->pdata[i-1] = NULL;
553 tm_tags_prune(tags_array);
554 return TRUE;
557 gboolean tm_tags_custom_dedup(GPtrArray *tags_array, TMTagCompareFunc compare_func)
559 guint i;
561 if ((!tags_array) || (!tags_array->len))
562 return TRUE;
563 for (i = 1; i < tags_array->len; ++i)
565 if (0 == compare_func(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i])))
566 tags_array->pdata[i-1] = NULL;
568 tm_tags_prune(tags_array);
569 return TRUE;
572 /* Sorts newly-added tags and merges them in order with existing tags.
573 * This is much faster than resorting the whole array.
574 * Note: Having the caller append to the existing array should be faster
575 * than creating a new array which would likely get resized more than once.
576 * tags_array: array with new (perhaps unsorted) tags appended.
577 * orig_len: number of existing tags. */
578 gboolean tm_tags_merge(GPtrArray *tags_array, gsize orig_len,
579 TMTagAttrType *sort_attributes, gboolean dedup)
581 gpointer *copy, *a, *b;
582 gsize copy_len, i;
584 if ((!tags_array) || (!tags_array->len) || orig_len >= tags_array->len)
585 return TRUE;
586 if (!orig_len)
587 return tm_tags_sort(tags_array, sort_attributes, dedup);
588 copy_len = tags_array->len - orig_len;
589 copy = g_memdup(tags_array->pdata + orig_len, copy_len * sizeof(gpointer));
590 s_sort_attrs = sort_attributes;
591 s_partial = FALSE;
592 /* enforce copy sorted with same attributes for merge */
593 qsort(copy, copy_len, sizeof(gpointer), tm_tag_compare);
594 a = tags_array->pdata + orig_len - 1;
595 b = copy + copy_len - 1;
596 for (i = tags_array->len - 1;; i--)
598 gint cmp = tm_tag_compare(a, b);
600 tags_array->pdata[i] = (cmp >= 0) ? *a-- : *b--;
601 if (a < tags_array->pdata)
603 /* include remainder of copy as well as current value of b */
604 memcpy(tags_array->pdata, copy, ((b + 1) - copy) * sizeof(gpointer));
605 break;
607 if (b < copy)
608 break; /* remaining elements of 'a' are in place already */
609 g_assert(i != 0);
611 s_sort_attrs = NULL;
612 g_free(copy);
613 if (dedup)
614 tm_tags_dedup(tags_array, sort_attributes);
615 return TRUE;
618 gboolean tm_tags_sort(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean dedup)
620 if ((!tags_array) || (!tags_array->len))
621 return TRUE;
622 s_sort_attrs = sort_attributes;
623 s_partial = FALSE;
624 qsort(tags_array->pdata, tags_array->len, sizeof(gpointer), tm_tag_compare);
625 s_sort_attrs = NULL;
626 if (dedup)
627 tm_tags_dedup(tags_array, sort_attributes);
628 return TRUE;
631 gboolean tm_tags_custom_sort(GPtrArray *tags_array, TMTagCompareFunc compare_func, gboolean dedup)
633 if ((!tags_array) || (!tags_array->len))
634 return TRUE;
635 qsort(tags_array->pdata, tags_array->len, sizeof(gpointer), compare_func);
636 if (dedup)
637 tm_tags_custom_dedup(tags_array, compare_func);
638 return TRUE;
641 GPtrArray *tm_tags_extract(GPtrArray *tags_array, guint tag_types)
643 GPtrArray *new_tags;
644 guint i;
645 if (NULL == tags_array)
646 return NULL;
647 new_tags = g_ptr_array_new();
648 for (i=0; i < tags_array->len; ++i)
650 if (NULL != tags_array->pdata[i])
652 if (tag_types & (((TMTag *) tags_array->pdata[i])->type))
653 g_ptr_array_add(new_tags, tags_array->pdata[i]);
656 return new_tags;
659 void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all)
661 if (tags_array)
663 guint i;
664 for (i = 0; i < tags_array->len; ++i)
665 tm_tag_unref(tags_array->pdata[i]);
666 if (free_all)
667 g_ptr_array_free(tags_array, TRUE);
668 else
669 g_ptr_array_set_size(tags_array, 0);
673 TMTag **tm_tags_find(const GPtrArray *sorted_tags_array, const char *name,
674 gboolean partial, int * tagCount)
676 static TMTag *tag = NULL;
677 TMTag **result;
678 int tagMatches=0;
680 if ((!sorted_tags_array) || (!sorted_tags_array->len))
681 return NULL;
683 if (NULL == tag)
684 tag = g_new0(TMTag, 1);
685 tag->name = (char *) name;
686 s_sort_attrs = NULL;
687 s_partial = partial;
688 result = (TMTag **) bsearch(&tag, sorted_tags_array->pdata, sorted_tags_array->len
689 , sizeof(gpointer), tm_tag_compare);
690 /* There can be matches on both sides of result */
691 if (result)
693 TMTag **last = (TMTag **) &sorted_tags_array->pdata[sorted_tags_array->len - 1];
694 TMTag **adv;
696 /* First look for any matches after result */
697 adv = result;
698 adv++;
699 for (; adv <= last && *adv; ++ adv)
701 if (0 != tm_tag_compare(&tag, adv))
702 break;
703 ++tagMatches;
705 /* Now look for matches from result and below */
706 for (; result >= (TMTag **) sorted_tags_array->pdata; -- result)
708 if (0 != tm_tag_compare(&tag, (TMTag **) result))
709 break;
710 ++tagMatches;
712 *tagCount=tagMatches;
713 ++ result; /* Correct address for the last successful match */
715 s_partial = FALSE;
716 return (TMTag **) result;
719 const char *tm_tag_type_name(const TMTag *tag)
721 g_return_val_if_fail(tag, NULL);
722 switch(tag->type)
724 case tm_tag_class_t: return "class";
725 case tm_tag_enum_t: return "enum";
726 case tm_tag_enumerator_t: return "enumval";
727 case tm_tag_field_t: return "field";
728 case tm_tag_function_t: return "function";
729 case tm_tag_interface_t: return "interface";
730 case tm_tag_member_t: return "member";
731 case tm_tag_method_t: return "method";
732 case tm_tag_namespace_t: return "namespace";
733 case tm_tag_package_t: return "package";
734 case tm_tag_prototype_t: return "prototype";
735 case tm_tag_struct_t: return "struct";
736 case tm_tag_typedef_t: return "typedef";
737 case tm_tag_union_t: return "union";
738 case tm_tag_variable_t: return "variable";
739 case tm_tag_externvar_t: return "extern";
740 case tm_tag_macro_t: return "define";
741 case tm_tag_macro_with_arg_t: return "macro";
742 case tm_tag_file_t: return "file";
743 default: return NULL;
745 return NULL;
748 TMTagType tm_tag_name_type(const char* tag_name)
750 g_return_val_if_fail(tag_name, tm_tag_undef_t);
752 if (strcmp(tag_name, "class") == 0) return tm_tag_class_t;
753 else if (strcmp(tag_name, "enum") == 0) return tm_tag_enum_t;
754 else if (strcmp(tag_name, "enumval") == 0) return tm_tag_enumerator_t;
755 else if (strcmp(tag_name, "field") == 0) return tm_tag_field_t;
756 else if (strcmp(tag_name, "function") == 0) return tm_tag_function_t;
757 else if (strcmp(tag_name, "interface") == 0) return tm_tag_interface_t;
758 else if (strcmp(tag_name, "member") == 0) return tm_tag_member_t;
759 else if (strcmp(tag_name, "method") == 0) return tm_tag_method_t;
760 else if (strcmp(tag_name, "namespace") == 0) return tm_tag_namespace_t;
761 else if (strcmp(tag_name, "package") == 0) return tm_tag_package_t;
762 else if (strcmp(tag_name, "prototype") == 0) return tm_tag_prototype_t;
763 else if (strcmp(tag_name, "struct") == 0) return tm_tag_struct_t;
764 else if (strcmp(tag_name, "typedef") == 0) return tm_tag_typedef_t;
765 else if (strcmp(tag_name, "union") == 0) return tm_tag_union_t;
766 else if (strcmp(tag_name, "variable") == 0) return tm_tag_variable_t;
767 else if (strcmp(tag_name, "extern") == 0) return tm_tag_externvar_t;
768 else if (strcmp(tag_name, "define") == 0) return tm_tag_macro_t;
769 else if (strcmp(tag_name, "macro") == 0) return tm_tag_macro_with_arg_t;
770 else if (strcmp(tag_name, "file") == 0) return tm_tag_file_t;
771 else return tm_tag_undef_t;
774 static const char *tm_tag_impl_name(TMTag *tag)
776 g_return_val_if_fail(tag && (tm_tag_file_t != tag->type), NULL);
777 if (TAG_IMPL_VIRTUAL == tag->atts.entry.impl)
778 return "virtual";
779 else
780 return NULL;
783 static const char *tm_tag_access_name(TMTag *tag)
785 g_return_val_if_fail(tag && (tm_tag_file_t != tag->type), NULL);
786 if (TAG_ACCESS_PUBLIC == tag->atts.entry.access)
787 return "public";
788 else if (TAG_ACCESS_PROTECTED == tag->atts.entry.access)
789 return "protected";
790 else if (TAG_ACCESS_PRIVATE == tag->atts.entry.access)
791 return "private";
792 else
793 return NULL;
796 void tm_tag_print(TMTag *tag, FILE *fp)
798 const char *laccess, *impl, *type;
799 if (!tag || !fp)
800 return;
801 if (tm_tag_file_t == tag->type)
803 fprintf(fp, "%s\n", tag->name);
804 return;
806 laccess = tm_tag_access_name(tag);
807 impl = tm_tag_impl_name(tag);
808 type = tm_tag_type_name(tag);
809 if (laccess)
810 fprintf(fp, "%s ", laccess);
811 if (impl)
812 fprintf(fp, "%s ", impl);
813 if (type)
814 fprintf(fp, "%s ", type);
815 if (tag->atts.entry.var_type)
816 fprintf(fp, "%s ", tag->atts.entry.var_type);
817 if (tag->atts.entry.scope)
818 fprintf(fp, "%s::", tag->atts.entry.scope);
819 fprintf(fp, "%s", tag->name);
820 if (tag->atts.entry.arglist)
821 fprintf(fp, "%s", tag->atts.entry.arglist);
822 if (tag->atts.entry.inheritance)
823 fprintf(fp, " : from %s", tag->atts.entry.inheritance);
824 if ((tag->atts.entry.file) && (tag->atts.entry.line > 0))
825 fprintf(fp, "[%s:%ld]", tag->atts.entry.file->work_object.file_name
826 , tag->atts.entry.line);
827 fprintf(fp, "\n");
830 void tm_tags_array_print(GPtrArray *tags, FILE *fp)
832 guint i;
833 TMTag *tag;
834 if (!(tags && (tags->len > 0) && fp))
835 return;
836 for (i = 0; i < tags->len; ++i)
838 tag = TM_TAG(tags->pdata[i]);
839 tm_tag_print(tag, fp);
843 gint tm_tag_scope_depth(const TMTag *t)
845 gint depth;
846 char *s;
847 if(!(t && t->atts.entry.scope))
848 return 0;
849 for (s = t->atts.entry.scope, depth = 0; s; s = strstr(s, "::"))
851 ++ depth;
852 ++ s;
854 return depth;