geany  1.38
About: Geany is a text editor (using GTK2) with basic features of an integrated development environment (syntax highlighting, code folding, symbol name auto-completion, ...). F: office T: editor programming GTK+ IDE
  Fossies Dox: geany-1.38.tar.bz2  ("unofficial" and yet experimental doxygen-generated source code documentation)  

tm_tag.c
Go to the documentation of this file.
1/*
2*
3* Copyright (c) 2001-2002, Biswapesh Chattopadhyay
4* Copyright 2005 The Geany contributors
5*
6* This source code is released for free distribution under the terms of the
7* GNU General Public License.
8*
9*/
10
11#include <stdlib.h>
12#include <string.h>
13#include <glib-object.h>
14
15#include "tm_tag.h"
16#include "tm_ctags.h"
17
18
19#define TAG_NEW(T) ((T) = g_slice_new0(TMTag))
20#define TAG_FREE(T) g_slice_free(TMTag, (T))
21
22
23#ifdef DEBUG_TAG_REFS
24
25static GHashTable *alive_tags = NULL;
26
27static void foreach_tags_log(gpointer key, gpointer value, gpointer data)
28{
29 gsize *ref_count = data;
30 const TMTag *tag = value;
31
32 *ref_count += (gsize) tag->refcount;
33 g_debug("Leaked TMTag (%d refs): %s", tag->refcount, tag->name);
34}
35
36static void log_refs_at_exit(void)
37{
38 gsize ref_count = 0;
39
40 g_hash_table_foreach(alive_tags, foreach_tags_log, &ref_count);
41 g_debug("TMTag references left at exit: %lu", ref_count);
42}
43
44static TMTag *log_tag_new(void)
45{
46 TMTag *tag;
47
48 if (! alive_tags)
49 {
50 alive_tags = g_hash_table_new(g_direct_hash, g_direct_equal);
51 atexit(log_refs_at_exit);
52 }
53 TAG_NEW(tag);
54 g_hash_table_insert(alive_tags, tag, tag);
55
56 return tag;
57}
58
59static void log_tag_free(TMTag *tag)
60{
61 g_return_if_fail(alive_tags != NULL);
62
63 if (! g_hash_table_remove(alive_tags, tag)) {
64 g_critical("Freeing invalid TMTag pointer %p", (void *) tag);
65 } else {
66 TAG_FREE(tag);
67 }
68}
69
70#undef TAG_NEW
71#undef TAG_FREE
72#define TAG_NEW(T) ((T) = log_tag_new())
73#define TAG_FREE(T) log_tag_free(T)
74
75#endif /* DEBUG_TAG_REFS */
76
77
78typedef struct
79{
80 guint *sort_attrs;
81 gboolean partial;
82 const GPtrArray *tags_array;
83 gboolean first;
85
86/** Gets the GType for a TMTag.
87 *
88 * @return TMTag type
89 * @since 1.32 (API 233) */
90GEANY_API_SYMBOL
91GType tm_tag_get_type(void)
92{
93 static GType gtype = 0;
94 if (G_UNLIKELY (gtype == 0))
95 {
96 gtype = g_boxed_type_register_static("TMTag", (GBoxedCopyFunc)tm_tag_ref,
97 (GBoxedFreeFunc)tm_tag_unref);
98 }
99 return gtype;
100}
101
102/*
103 Creates a new tag structure and returns a pointer to it.
104 @return the new TMTag structure. This should be free()-ed using tm_tag_free()
105*/
107{
108 TMTag *tag;
109
110 TAG_NEW(tag);
111 tag->refcount = 1;
112
113 return tag;
114}
115
116/*
117 Destroys a TMTag structure, i.e. frees all elements except the tag itself.
118 @param tag The TMTag structure to destroy
119 @see tm_tag_free()
120*/
121static void tm_tag_destroy(TMTag *tag)
122{
123 g_free(tag->name);
124 g_free(tag->arglist);
125 g_free(tag->scope);
126 g_free(tag->inheritance);
127 g_free(tag->var_type);
128}
129
130
131/*
132 Drops a reference from a TMTag. If the reference count reaches 0, this function
133 destroys all data in the tag and frees the tag structure as well.
134 @param tag Pointer to a TMTag structure
135*/
137{
138 /* be NULL-proof because tm_tag_free() was NULL-proof and we indent to be a
139 * drop-in replacment of it */
140 if (NULL != tag && g_atomic_int_dec_and_test(&tag->refcount))
141 {
142 tm_tag_destroy(tag);
143 TAG_FREE(tag);
144 }
145}
146
147/*
148 Adds a reference to a TMTag.
149 @param tag Pointer to a TMTag structure
150 @return the passed-in TMTag
151*/
153{
154 g_atomic_int_inc(&tag->refcount);
155 return tag;
156}
157
158/*
159 Inbuilt tag comparison function.
160*/
161static gint tm_tag_compare(gconstpointer ptr1, gconstpointer ptr2, gpointer user_data)
162{
163 unsigned int *sort_attr;
164 int returnval = 0;
165 TMTag *t1 = *((TMTag **) ptr1);
166 TMTag *t2 = *((TMTag **) ptr2);
167 TMSortOptions *sort_options = user_data;
168
169 if ((NULL == t1) || (NULL == t2))
170 {
171 g_warning("Found NULL tag");
172 return t2 - t1;
173 }
174 if (NULL == sort_options->sort_attrs)
175 {
176 if (sort_options->partial)
177 return strncmp(FALLBACK(t1->name, ""), FALLBACK(t2->name, ""), strlen(FALLBACK(t1->name, "")));
178 else
179 return strcmp(FALLBACK(t1->name, ""), FALLBACK(t2->name, ""));
180 }
181
182 for (sort_attr = sort_options->sort_attrs; returnval == 0 && *sort_attr != tm_tag_attr_none_t; ++ sort_attr)
183 {
184 switch (*sort_attr)
185 {
187 if (sort_options->partial)
188 returnval = strncmp(FALLBACK(t1->name, ""), FALLBACK(t2->name, ""), strlen(FALLBACK(t1->name, "")));
189 else
190 returnval = strcmp(FALLBACK(t1->name, ""), FALLBACK(t2->name, ""));
191 break;
193 returnval = t1->file - t2->file;
194 break;
196 returnval = t1->line - t2->line;
197 break;
199 returnval = t1->type - t2->type;
200 break;
202 returnval = strcmp(FALLBACK(t1->scope, ""), FALLBACK(t2->scope, ""));
203 break;
205 returnval = strcmp(FALLBACK(t1->arglist, ""), FALLBACK(t2->arglist, ""));
206 if (returnval != 0)
207 {
208 int line_diff = (t1->line - t2->line);
209
210 returnval = line_diff ? line_diff : returnval;
211 }
212 break;
214 returnval = strcmp(FALLBACK(t1->var_type, ""), FALLBACK(t2->var_type, ""));
215 break;
216 }
217 }
218 return returnval;
219}
220
221gboolean tm_tags_equal(const TMTag *a, const TMTag *b)
222{
223 if (a == b)
224 return TRUE;
225
226 return (a->line == b->line &&
227 a->file == b->file /* ptr comparison */ &&
228 strcmp(FALLBACK(a->name, ""), FALLBACK(b->name, "")) == 0 &&
229 a->type == b->type &&
230 a->local == b->local &&
231 a->pointerOrder == b->pointerOrder &&
232 a->access == b->access &&
233 a->impl == b->impl &&
234 a->lang == b->lang &&
235 strcmp(FALLBACK(a->scope, ""), FALLBACK(b->scope, "")) == 0 &&
236 strcmp(FALLBACK(a->arglist, ""), FALLBACK(b->arglist, "")) == 0 &&
237 strcmp(FALLBACK(a->inheritance, ""), FALLBACK(b->inheritance, "")) == 0 &&
238 strcmp(FALLBACK(a->var_type, ""), FALLBACK(b->var_type, "")) == 0);
239}
240
241/*
242 Removes NULL tag entries from an array of tags. Called after tm_tags_dedup() since
243 this function substitutes duplicate entries with NULL
244 @param tags_array Array of tags to dedup
245*/
246void tm_tags_prune(GPtrArray *tags_array)
247{
248 guint i, count;
249
250 g_return_if_fail(tags_array);
251
252 for (i=0, count = 0; i < tags_array->len; ++i)
253 {
254 if (NULL != tags_array->pdata[i])
255 tags_array->pdata[count++] = tags_array->pdata[i];
256 }
257 tags_array->len = count;
258}
259
260/*
261 Deduplicates an array on tags using the inbuilt comparison function based on
262 the attributes specified. Called by tm_tags_sort() when dedup is TRUE.
263 @param tags_array Array of tags to dedup.
264 @param sort_attributes Attributes the array is sorted on. They will be deduped
265 on the same criteria.
266*/
267void tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean unref_duplicates)
268{
269 TMSortOptions sort_options;
270 guint i;
271
272 g_return_if_fail(tags_array);
273 if (tags_array->len < 2)
274 return;
275
276 sort_options.sort_attrs = sort_attributes;
277 sort_options.partial = FALSE;
278 for (i = 1; i < tags_array->len; ++i)
279 {
280 if (0 == tm_tag_compare(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i]), &sort_options))
281 {
282 if (unref_duplicates)
283 tm_tag_unref(tags_array->pdata[i-1]);
284 tags_array->pdata[i-1] = NULL;
285 }
286 }
287 tm_tags_prune(tags_array);
288}
289
290/*
291 Sort an array of tags on the specified attribuites using the inbuilt comparison
292 function.
293 @param tags_array The array of tags to be sorted
294 @param sort_attributes Attributes to be sorted on (int array terminated by 0)
295 @param dedup Whether to deduplicate the sorted array
296*/
297void tm_tags_sort(GPtrArray *tags_array, TMTagAttrType *sort_attributes,
298 gboolean dedup, gboolean unref_duplicates)
299{
300 TMSortOptions sort_options;
301
302 g_return_if_fail(tags_array);
303
304 sort_options.sort_attrs = sort_attributes;
305 sort_options.partial = FALSE;
306 g_ptr_array_sort_with_data(tags_array, tm_tag_compare, &sort_options);
307 if (dedup)
308 tm_tags_dedup(tags_array, sort_attributes, unref_duplicates);
309}
310
311void tm_tags_remove_file_tags(TMSourceFile *source_file, GPtrArray *tags_array)
312{
313 guint i;
314
315 /* Now we choose between an algorithm with complexity O(tags_array->len) and
316 * O(source_file->tags_array->len * log(tags_array->len)). The latter algorithm
317 * is better when tags_array contains many times more tags than
318 * source_file->tags_array so instead of trying to find the removed tags
319 * linearly, binary search is used. The constant 20 is more or less random
320 * but seems to work well. It's exact value isn't so critical because it's
321 * the extremes where the difference is the biggest: when
322 * source_file->tags_array->len == tags_array->len (single file open) and
323 * source_file->tags_array->len << tags_array->len (the number of tags
324 * from the file is a small fraction of all tags).
325 */
326 if (source_file->tags_array->len != 0 &&
327 tags_array->len / source_file->tags_array->len < 20)
328 {
329 for (i = 0; i < tags_array->len; i++)
330 {
331 TMTag *tag = tags_array->pdata[i];
332
333 if (tag->file == source_file)
334 tags_array->pdata[i] = NULL;
335 }
336 }
337 else
338 {
339 GPtrArray *to_delete = g_ptr_array_sized_new(source_file->tags_array->len);
340
341 for (i = 0; i < source_file->tags_array->len; i++)
342 {
343 guint j;
344 guint tag_count;
345 TMTag **found;
346 TMTag *tag = source_file->tags_array->pdata[i];
347
348 found = tm_tags_find(tags_array, tag->name, FALSE, &tag_count);
349
350 for (j = 0; j < tag_count; j++)
351 {
352 if (*found != NULL && (*found)->file == source_file)
353 {
354 /* we cannot set the pointer to NULL now because the search wouldn't work */
355 g_ptr_array_add(to_delete, found);
356 /* no break - if there are multiple tags of the same name, we would
357 * always find the first instance and wouldn't remove others; duplicates
358 * in the to_delete list aren't a problem */
359 }
360 found++;
361 }
362 }
363
364 for (i = 0; i < to_delete->len; i++)
365 {
366 TMTag **tag = to_delete->pdata[i];
367 *tag = NULL;
368 }
369 g_ptr_array_free(to_delete, TRUE);
370 }
371
372 tm_tags_prune(tags_array);
373}
374
375/* Optimized merge sort for merging sorted values from one array to another
376 * where one of the arrays is much smaller than the other.
377 * The merge complexity depends mostly on the size of the small array
378 * and is almost independent of the size of the big array.
379 * In addition, get rid of the duplicates (if both big_array and small_array are duplicate-free). */
380static GPtrArray *merge(GPtrArray *big_array, GPtrArray *small_array,
381 TMSortOptions *sort_options, gboolean unref_duplicates) {
382 guint i1 = 0; /* index to big_array */
383 guint i2 = 0; /* index to small_array */
384 guint initial_step;
385 guint step;
386 GPtrArray *res_array = g_ptr_array_sized_new(big_array->len + small_array->len);
387#ifdef TM_DEBUG
388 guint cmpnum = 0;
389#endif
390
391 /* swap the arrays if len(small) > len(big) */
392 if (small_array->len > big_array->len)
393 {
394 GPtrArray *tmp = small_array;
395 small_array = big_array;
396 big_array = tmp;
397 }
398
399 /* on average, we are merging a value from small_array every
400 * len(big_array) / len(small_array) values - good approximation for fast jump
401 * step size */
402 initial_step = (small_array->len > 0) ? big_array->len / small_array->len : 1;
403 initial_step = initial_step > 4 ? initial_step : 1;
404 step = initial_step;
405
406 while (i1 < big_array->len && i2 < small_array->len)
407 {
408 gpointer val1;
409 gpointer val2 = small_array->pdata[i2];
410
411 if (step > 4) /* fast path start */
412 {
413 guint j1 = (i1 + step < big_array->len) ? i1 + step : big_array->len - 1;
414
415 val1 = big_array->pdata[j1];
416#ifdef TM_DEBUG
417 cmpnum++;
418#endif
419 /* if the value in big_array after making the big step is still smaller
420 * than the value in small_array, we can copy all the values inbetween
421 * into the result without making expensive string comparisons */
422 if (tm_tag_compare(&val1, &val2, sort_options) < 0)
423 {
424 while (i1 <= j1)
425 {
426 val1 = big_array->pdata[i1];
427 g_ptr_array_add(res_array, val1);
428 i1++;
429 }
430 }
431 else
432 {
433 /* lower the step and try again */
434 step /= 2;
435 }
436 } /* fast path end */
437 else
438 {
439 gint cmpval;
440
441#ifdef TM_DEBUG
442 cmpnum++;
443#endif
444 val1 = big_array->pdata[i1];
445 cmpval = tm_tag_compare(&val1, &val2, sort_options);
446 if (cmpval < 0)
447 {
448 g_ptr_array_add(res_array, val1);
449 i1++;
450 }
451 else
452 {
453 g_ptr_array_add(res_array, val2);
454 i2++;
455 /* value from small_array gets merged - reset the step size */
456 step = initial_step;
457 if (cmpval == 0)
458 {
459 i1++; /* remove the duplicate, keep just the newly merged value */
460 if (unref_duplicates)
461 tm_tag_unref(val1);
462 }
463 }
464 }
465 }
466
467 /* end of one of the arrays reached - copy the rest from the other array */
468 while (i1 < big_array->len)
469 g_ptr_array_add(res_array, big_array->pdata[i1++]);
470 while (i2 < small_array->len)
471 g_ptr_array_add(res_array, small_array->pdata[i2++]);
472
473#ifdef TM_DEBUG
474 printf("cmpnums: %u\n", cmpnum);
475 printf("total tags: %u\n", big_array->len);
476 printf("merged tags: %u\n\n", small_array->len);
477#endif
478
479 return res_array;
480}
481
482GPtrArray *tm_tags_merge(GPtrArray *big_array, GPtrArray *small_array,
483 TMTagAttrType *sort_attributes, gboolean unref_duplicates)
484{
485 GPtrArray *res_array;
486 TMSortOptions sort_options;
487
488 sort_options.sort_attrs = sort_attributes;
489 sort_options.partial = FALSE;
490 res_array = merge(big_array, small_array, &sort_options, unref_duplicates);
491 return res_array;
492}
493
494/*
495 This function will extract the tags of the specified types from an array of tags.
496 The returned value is a GPtrArray which should be free-d with a call to
497 g_ptr_array_free(array, TRUE). However, do not free the tags themselves since they
498 are not duplicated.
499 @param tags_array The original array of tags
500 @param tag_types - The tag types to extract. Can be a bitmask. For example, passing
501 (tm_tag_typedef_t | tm_tag_struct_t) will extract all typedefs and structures from
502 the original array.
503 @return an array of tags (NULL on failure)
504*/
505GPtrArray *tm_tags_extract(GPtrArray *tags_array, TMTagType tag_types)
506{
507 GPtrArray *new_tags;
508 guint i;
509
510 g_return_val_if_fail(tags_array, NULL);
511
512 new_tags = g_ptr_array_new();
513 for (i=0; i < tags_array->len; ++i)
514 {
515 if (NULL != tags_array->pdata[i])
516 {
517 if (tag_types & (((TMTag *) tags_array->pdata[i])->type))
518 g_ptr_array_add(new_tags, tags_array->pdata[i]);
519 }
520 }
521 return new_tags;
522}
523
524/*
525 Completely frees an array of tags.
526 @param tags_array Array of tags to be freed.
527 @param free_array Whether the GptrArray is to be freed as well.
528*/
529void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all)
530{
531 if (tags_array)
532 {
533 guint i;
534 for (i = 0; i < tags_array->len; ++i)
535 tm_tag_unref(tags_array->pdata[i]);
536 if (free_all)
537 g_ptr_array_free(tags_array, TRUE);
538 else
539 g_ptr_array_set_size(tags_array, 0);
540 }
541}
542
543/* copy/pasted bsearch() from libc extended with user_data for comparison function
544 * and using glib types */
545static gpointer binary_search(gpointer key, gpointer base, size_t nmemb,
546 GCompareDataFunc compar, gpointer user_data)
547{
548 gsize l, u, idx;
549 gpointer p;
550 gint comparison;
551
552 l = 0;
553 u = nmemb;
554 while (l < u)
555 {
556 idx = (l + u) / 2;
557 p = (gpointer) (((const gchar *) base) + (idx * sizeof(gpointer)));
558 comparison = (*compar) (key, p, user_data);
559 if (comparison < 0)
560 u = idx;
561 else if (comparison > 0)
562 l = idx + 1;
563 else
564 return (gpointer) p;
565 }
566
567 return NULL;
568}
569
570static gint tag_search_cmp(gconstpointer ptr1, gconstpointer ptr2, gpointer user_data)
571{
572 gint res = tm_tag_compare(ptr1, ptr2, user_data);
573
574 if (res == 0)
575 {
576 TMSortOptions *sort_options = user_data;
577 const GPtrArray *tags_array = sort_options->tags_array;
578 TMTag **tag = (TMTag **) ptr2;
579
580 /* if previous/next (depending on sort options) tag equal, we haven't
581 * found the first/last tag in a sequence of equal tags yet */
582 if (sort_options->first && ptr2 != &tags_array->pdata[0]) {
583 if (tm_tag_compare(ptr1, tag - 1, user_data) == 0)
584 return -1;
585 }
586 else if (!sort_options->first && ptr2 != &tags_array->pdata[tags_array->len-1])
587 {
588 if (tm_tag_compare(ptr1, tag + 1, user_data) == 0)
589 return 1;
590 }
591 }
592 return res;
593}
594
595/*
596 Returns a pointer to the position of the first matching tag in a (sorted) tags array.
597 The passed array of tags must be already sorted by name (searched with binary search).
598 @param tags_array Tag array (sorted on name)
599 @param name Name of the tag to locate.
600 @param partial If TRUE, matches the first part of the name instead of doing exact match.
601 @param tagCount Return location of the matched tags.
602*/
603TMTag **tm_tags_find(const GPtrArray *tags_array, const char *name,
604 gboolean partial, guint *tagCount)
605{
606 TMTag *tag, **first;
607 TMSortOptions sort_options;
608
609 *tagCount = 0;
610 if (!tags_array || !tags_array->len)
611 return NULL;
612
613 tag = g_new0(TMTag, 1);
614 tag->name = (char *) name;
615
616 sort_options.sort_attrs = NULL;
617 sort_options.partial = partial;
618 sort_options.tags_array = tags_array;
619 sort_options.first = TRUE;
620 first = (TMTag **)binary_search(&tag, tags_array->pdata, tags_array->len,
621 tag_search_cmp, &sort_options);
622
623 if (first)
624 {
625 TMTag **last;
626 unsigned first_pos;
627
628 sort_options.first = FALSE;
629 first_pos = first - (TMTag **)tags_array->pdata;
630 /* search between the first element and end */
631 last = (TMTag **)binary_search(&tag, first, tags_array->len - first_pos,
632 tag_search_cmp, &sort_options);
633 *tagCount = last - first + 1;
634 }
635
636 g_free(tag);
637 return (TMTag **) first;
638}
639
640/* Returns TMTag which "own" given line
641 @param line Current line in edited file.
642 @param file_tags A GPtrArray of edited file TMTag pointers.
643 @param tag_types the tag types to include in the match
644 @return TMTag pointers to owner tag. */
645const TMTag *
646tm_get_current_tag (GPtrArray * file_tags, const gulong line, const TMTagType tag_types)
647{
648 TMTag *matching_tag = NULL;
649 if (file_tags && file_tags->len)
650 {
651 guint i;
652 gulong matching_line = 0;
653
654 for (i = 0; (i < file_tags->len); ++i)
655 {
656 TMTag *tag = TM_TAG (file_tags->pdata[i]);
657 if (tag && tag->type & tag_types &&
658 tag->line <= line && tag->line > matching_line)
659 {
660 matching_tag = tag;
661 matching_line = tag->line;
662 }
663 }
664 }
665 return matching_tag;
666}
667
668gboolean tm_tag_is_anon(const TMTag *tag)
669{
670 guint i;
671 char dummy;
672
673 if (tag->lang == TM_PARSER_C || tag->lang == TM_PARSER_CPP)
674 return sscanf(tag->name, "anon_%*[a-z]_%u%c", &i, &dummy) == 1;
675 else if (tag->lang == TM_PARSER_FORTRAN || tag->lang == TM_PARSER_F77)
676 return sscanf(tag->name, "Structure#%u%c", &i, &dummy) == 1 ||
677 sscanf(tag->name, "Interface#%u%c", &i, &dummy) == 1 ||
678 sscanf(tag->name, "Enum#%u%c", &i, &dummy) == 1;
679 return FALSE;
680}
681
682
683#ifdef TM_DEBUG /* various debugging functions */
684
685/*
686 Returns the type of tag as a string
687 @param tag The tag whose type is required
688*/
689const char *tm_tag_type_name(const TMTag *tag)
690{
691 g_return_val_if_fail(tag, NULL);
692
694}
695
696/*
697 Returns the TMTagType given the name of the type. Reverse of tm_tag_type_name.
698 @param tag_name Name of the tag type
699*/
700TMTagType tm_tag_name_type(const char* tag_name, TMParserType lang)
701{
702 g_return_val_if_fail(tag_name, tm_tag_undef_t);
703
704 return tm_parser_get_tag_type(tm_ctags_get_kind_from_name(tag_name, lang), lang);
705}
706
707static const char *tm_tag_impl_name(TMTag *tag)
708{
709 g_return_val_if_fail(tag, NULL);
710 if (TAG_IMPL_VIRTUAL == tag->impl)
711 return "virtual";
712 else
713 return NULL;
714}
715
716static const char *tm_tag_access_name(TMTag *tag)
717{
718 g_return_val_if_fail(tag, NULL);
719 if (TAG_ACCESS_PUBLIC == tag->access)
720 return "public";
721 else if (TAG_ACCESS_PROTECTED == tag->access)
722 return "protected";
723 else if (TAG_ACCESS_PRIVATE == tag->access)
724 return "private";
725 else
726 return NULL;
727}
728
729/*
730 Prints information about a tag to the given file pointer.
731 @param tag The tag whose info is required.
732 @param fp The file pointer of the file to print the info to.
733*/
734void tm_tag_print(TMTag *tag, FILE *fp)
735{
736 const char *laccess, *impl, *type;
737 if (!tag || !fp)
738 return;
739 laccess = tm_tag_access_name(tag);
740 impl = tm_tag_impl_name(tag);
741 type = tm_tag_type_name(tag);
742 if (laccess)
743 fprintf(fp, "%s ", laccess);
744 if (impl)
745 fprintf(fp, "%s ", impl);
746 if (type)
747 fprintf(fp, "%s ", type);
748 if (tag->var_type)
749 fprintf(fp, "%s ", tag->var_type);
750 if (tag->scope)
751 fprintf(fp, "%s::", tag->scope);
752 fprintf(fp, "%s", tag->name);
753 if (tag->arglist)
754 fprintf(fp, "%s", tag->arglist);
755 if (tag->inheritance)
756 fprintf(fp, " : from %s", tag->inheritance);
757 if ((tag->file) && (tag->line > 0))
758 fprintf(fp, "[%s:%ld]", tag->file->file_name
759 , tag->line);
760 fprintf(fp, "\n");
761}
762
763/*
764 Prints info about all tags in the array to the given file pointer.
765*/
766void tm_tags_array_print(GPtrArray *tags, FILE *fp)
767{
768 guint i;
769 TMTag *tag;
770 if (!(tags && (tags->len > 0) && fp))
771 return;
772 for (i = 0; i < tags->len; ++i)
773 {
774 tag = TM_TAG(tags->pdata[i]);
775 tm_tag_print(tag, fp);
776 }
777}
778
779/*
780 Returns the depth of tag scope (useful for finding tag hierarchy
781*/
782gint tm_tag_scope_depth(const TMTag *t)
783{
784 const gchar *context_sep = tm_parser_context_separator(t->lang);
785 gint depth;
786 char *s;
787 if(!(t && t->scope))
788 return 0;
789 for (s = t->scope, depth = 0; s; s = strstr(s, context_sep))
790 {
791 ++ depth;
792 ++ s;
793 }
794 return depth;
795}
796
797#endif /* TM_DEBUG */
const gchar * name
Definition: document.c:3219
vString * line
Definition: geany_cobol.c:133
unsigned int count
implType impl
Definition: geany_php.c:233
static gboolean dummy
Definition: libmain.c:115
#define NULL
Definition: rbtree.h:150
char * strstr(const char *str, const char *substr)
Definition: routines.c:304
if(!stash_group_load_from_file(group, filename)) g_warning(_("Could not load keyfile %s!")
const GPtrArray * tags_array
Definition: tm_tag.c:82
gboolean partial
Definition: tm_tag.c:81
gboolean first
Definition: tm_tag.c:83
guint * sort_attrs
Definition: tm_tag.c:80
The TMSourceFile structure represents the source file and its tags in the tag manager.
GPtrArray * tags_array
Sorted tag array obtained by parsing the object.
char * file_name
Full file name (inc.
The TMTag structure represents a single tag in the tag manager.
Definition: tm_tag.h:88
char * scope
Scope of tag.
Definition: tm_tag.h:99
char * inheritance
Parent classes.
Definition: tm_tag.h:100
char * var_type
Variable type (maps to struct for typedefs)
Definition: tm_tag.h:101
char * arglist
Argument list (functions/prototypes/macros)
Definition: tm_tag.h:98
TMSourceFile * file
These are tag attributes.
Definition: tm_tag.h:94
TMTagType type
Tag Type.
Definition: tm_tag.h:90
gulong line
Line number of the tag.
Definition: tm_tag.h:95
char * name
Name of tag.
Definition: tm_tag.h:89
char access
Access type (public/protected/private/etc.)
Definition: tm_tag.h:102
gint refcount
Definition: tm_tag.h:91
TMParserType lang
Definition: tm_tag.h:104
guint pointerOrder
Definition: tm_tag.h:97
char impl
Implementation (e.g.
Definition: tm_tag.h:103
gboolean local
Is the tag of local scope.
Definition: tm_tag.h:96
gchar tm_ctags_get_kind_from_name(const gchar *name, TMParserType lang)
Definition: tm_ctags.c:265
const gchar * tm_ctags_get_kind_name(gchar kind, TMParserType lang)
Definition: tm_ctags.c:258
gchar tm_parser_get_tag_kind(TMTagType type, TMParserType lang)
Definition: tm_parser.c:629
const gchar * tm_parser_context_separator(TMParserType lang)
Definition: tm_parser.c:764
TMTagType tm_parser_get_tag_type(gchar kind, TMParserType lang)
Definition: tm_parser.c:613
TMTagType
Types of tags.
Definition: tm_parser.h:23
@ tm_tag_undef_t
Unknown type.
Definition: tm_parser.h:24
gint TMParserType
Definition: tm_parser.h:52
#define FALLBACK(X, Y)
const TMTag * tm_get_current_tag(GPtrArray *file_tags, const gulong line, const TMTagType tag_types)
Definition: tm_tag.c:646
GPtrArray * tm_tags_merge(GPtrArray *big_array, GPtrArray *small_array, TMTagAttrType *sort_attributes, gboolean unref_duplicates)
Definition: tm_tag.c:482
GType tm_tag_get_type(void)
Gets the GType for a TMTag.
Definition: tm_tag.c:91
static GPtrArray * merge(GPtrArray *big_array, GPtrArray *small_array, TMSortOptions *sort_options, gboolean unref_duplicates)
Definition: tm_tag.c:380
TMTag * tm_tag_new(void)
Definition: tm_tag.c:106
GPtrArray * tm_tags_extract(GPtrArray *tags_array, TMTagType tag_types)
Definition: tm_tag.c:505
#define TAG_NEW(T)
Definition: tm_tag.c:19
void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all)
Definition: tm_tag.c:529
void tm_tags_remove_file_tags(TMSourceFile *source_file, GPtrArray *tags_array)
Definition: tm_tag.c:311
static gint tm_tag_compare(gconstpointer ptr1, gconstpointer ptr2, gpointer user_data)
Definition: tm_tag.c:161
TMTag ** tm_tags_find(const GPtrArray *tags_array, const char *name, gboolean partial, guint *tagCount)
Definition: tm_tag.c:603
TMTag * tm_tag_ref(TMTag *tag)
Definition: tm_tag.c:152
gboolean tm_tag_is_anon(const TMTag *tag)
Definition: tm_tag.c:668
void tm_tag_unref(TMTag *tag)
Definition: tm_tag.c:136
gboolean tm_tags_equal(const TMTag *a, const TMTag *b)
Definition: tm_tag.c:221
static void tm_tag_destroy(TMTag *tag)
Definition: tm_tag.c:121
void tm_tags_prune(GPtrArray *tags_array)
Definition: tm_tag.c:246
#define TAG_FREE(T)
Definition: tm_tag.c:20
void tm_tags_sort(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean dedup, gboolean unref_duplicates)
Definition: tm_tag.c:297
void tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean unref_duplicates)
Definition: tm_tag.c:267
static gpointer binary_search(gpointer key, gpointer base, size_t nmemb, GCompareDataFunc compar, gpointer user_data)
Definition: tm_tag.c:545
static gint tag_search_cmp(gconstpointer ptr1, gconstpointer ptr2, gpointer user_data)
Definition: tm_tag.c:570
#define TAG_ACCESS_PROTECTED
Protected member.
Definition: tm_tag.h:74
#define TM_TAG(tag)
Use the TM_TAG() macro to cast a pointer to (TMTag *)
Definition: tm_tag.h:40
#define TAG_IMPL_VIRTUAL
Tag implementation type for functions.
Definition: tm_tag.h:81
#define TAG_ACCESS_PRIVATE
Private member.
Definition: tm_tag.h:75
#define TAG_ACCESS_PUBLIC
Tag access type for C++/Java member functions and variables.
Definition: tm_tag.h:73
TMTagAttrType
Tag Attributes.
Definition: tm_tag.h:51
@ tm_tag_attr_none_t
Undefined.
Definition: tm_tag.h:52
@ tm_tag_attr_vartype_t
Variable Type.
Definition: tm_tag.h:63
@ tm_tag_attr_name_t
Tag Name.
Definition: tm_tag.h:53
@ tm_tag_attr_file_t
File in which tag exists.
Definition: tm_tag.h:55
@ tm_tag_attr_scope_t
Scope of the tag.
Definition: tm_tag.h:58
@ tm_tag_attr_arglist_t
Argument list.
Definition: tm_tag.h:60
@ tm_tag_attr_line_t
Line number of tag.
Definition: tm_tag.h:56
@ tm_tag_attr_type_t
Tag Type.
Definition: tm_tag.h:54