e65d0f2362
Adjust code and scripts which generate global tags files to add the new format specification. Update global tags files. Add documentation for the two supported global tags files formats. git-svn-id: https://geany.svn.sourceforge.net/svnroot/geany/trunk@3465 ea778897-0a13-0410-b9d1-a72fbfd435f5
794 lines
21 KiB
C
794 lines
21 KiB
C
/*
|
|
*
|
|
* Copyright (c) 2001-2002, Biswapesh Chattopadhyay
|
|
*
|
|
* This source code is released for free distribution under the terms of the
|
|
* GNU General Public License.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "general.h"
|
|
#include "entry.h"
|
|
#include "parse.h"
|
|
#include "read.h"
|
|
#define LIBCTAGS_DEFINED
|
|
#include "tm_tag.h"
|
|
|
|
|
|
#if GLIB_CHECK_VERSION (2, 10, 0)
|
|
/* Use GSlices if present */
|
|
|
|
#define TAG_NEW(T) ((T) = g_slice_new0(TMTag))
|
|
#define TAG_FREE(T) g_slice_free(TMTag, (T))
|
|
|
|
#else /* GLib < 2.10 */
|
|
|
|
static GMemChunk *s_tag_mem_chunk = NULL;
|
|
|
|
#define TAG_NEW(T) {\
|
|
if (!s_tag_mem_chunk) \
|
|
s_tag_mem_chunk = g_mem_chunk_new("TMTag memChunk", sizeof(TMTag), 1024 \
|
|
, G_ALLOC_AND_FREE); \
|
|
(T) = g_chunk_new0(TMTag, s_tag_mem_chunk);}
|
|
|
|
#define TAG_FREE(T) g_mem_chunk_free(s_tag_mem_chunk, (T))
|
|
|
|
#endif /* GLib version check */
|
|
|
|
|
|
/* Note: To preserve binary compatibility, it is very important
|
|
that you only *append* to this list ! */
|
|
enum
|
|
{
|
|
TA_NAME = 200,
|
|
TA_LINE,
|
|
TA_LOCAL,
|
|
TA_POS, /* Obsolete */
|
|
TA_TYPE,
|
|
TA_ARGLIST,
|
|
TA_SCOPE,
|
|
TA_VARTYPE,
|
|
TA_INHERITS,
|
|
TA_TIME,
|
|
TA_ACCESS,
|
|
TA_IMPL,
|
|
TA_LANG,
|
|
TA_INACTIVE,
|
|
TA_POINTER
|
|
};
|
|
|
|
static guint *s_sort_attrs = NULL;
|
|
static gboolean s_partial = FALSE;
|
|
|
|
static const char *s_tag_type_names[] = {
|
|
"class", /* classes */
|
|
"enum", /* enumeration names */
|
|
"enumerator", /* enumerators (values inside an enumeration) */
|
|
"externvar", /* external variable declarations */
|
|
"field", /* fields */
|
|
"function", /* function definitions */
|
|
"interface", /* interfaces */
|
|
"macro", /* macro definitions */
|
|
"member", /* class, struct, and union members */
|
|
"method", /* methods */
|
|
"namespace", /* namespaces */
|
|
"package", /* packages */
|
|
"prototype", /* function prototypes */
|
|
"struct", /* structure names */
|
|
"typedef", /* typedefs */
|
|
"union", /* union names */
|
|
"variable", /* variable definitions */
|
|
"other" /* Other tag type (non C/C++/Java) */
|
|
};
|
|
|
|
static int s_tag_types[] = {
|
|
tm_tag_class_t,
|
|
tm_tag_enum_t,
|
|
tm_tag_enumerator_t,
|
|
tm_tag_externvar_t,
|
|
tm_tag_field_t,
|
|
tm_tag_function_t,
|
|
tm_tag_interface_t,
|
|
tm_tag_macro_t,
|
|
tm_tag_member_t,
|
|
tm_tag_method_t,
|
|
tm_tag_namespace_t,
|
|
tm_tag_package_t,
|
|
tm_tag_prototype_t,
|
|
tm_tag_struct_t,
|
|
tm_tag_typedef_t,
|
|
tm_tag_union_t,
|
|
tm_tag_variable_t,
|
|
tm_tag_other_t
|
|
};
|
|
|
|
static int get_tag_type(const char *tag_name)
|
|
{
|
|
unsigned int i;
|
|
int cmp;
|
|
g_return_val_if_fail(tag_name, 0);
|
|
for (i=0; i < sizeof(s_tag_type_names)/sizeof(char *); ++i)
|
|
{
|
|
cmp = strcmp(tag_name, s_tag_type_names[i]);
|
|
if (0 == cmp)
|
|
return s_tag_types[i];
|
|
else if (cmp < 0)
|
|
break;
|
|
}
|
|
#ifdef TM_DEBUG
|
|
fprintf(stderr, "Unknown tag type %s\n", tag_name);
|
|
#endif
|
|
return tm_tag_undef_t;
|
|
}
|
|
|
|
gboolean tm_tag_init(TMTag *tag, TMSourceFile *file, const tagEntryInfo *tag_entry)
|
|
{
|
|
if (NULL == tag_entry)
|
|
{
|
|
/* This is a file tag */
|
|
if (NULL == file)
|
|
return FALSE;
|
|
else
|
|
{
|
|
tag->name = g_strdup(file->work_object.file_name);
|
|
tag->type = tm_tag_file_t;
|
|
tag->atts.file.timestamp = file->work_object.analyze_time;
|
|
tag->atts.file.lang = file->lang;
|
|
tag->atts.file.inactive = FALSE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* This is a normal tag entry */
|
|
if (NULL == tag_entry->name)
|
|
return FALSE;
|
|
tag->name = g_strdup(tag_entry->name);
|
|
tag->type = get_tag_type(tag_entry->kindName);
|
|
tag->atts.entry.local = tag_entry->isFileScope;
|
|
tag->atts.entry.pointerOrder = 0; /* backward compatibility (use var_type instead) */
|
|
tag->atts.entry.line = tag_entry->lineNumber;
|
|
if (NULL != tag_entry->extensionFields.arglist)
|
|
tag->atts.entry.arglist = g_strdup(tag_entry->extensionFields.arglist);
|
|
if ((NULL != tag_entry->extensionFields.scope[1]) &&
|
|
(isalpha(tag_entry->extensionFields.scope[1][0]) ||
|
|
tag_entry->extensionFields.scope[1][0] == '_'))
|
|
tag->atts.entry.scope = g_strdup(tag_entry->extensionFields.scope[1]);
|
|
if (tag_entry->extensionFields.inheritance != NULL)
|
|
tag->atts.entry.inheritance = g_strdup(tag_entry->extensionFields.inheritance);
|
|
if (tag_entry->extensionFields.varType != NULL)
|
|
tag->atts.entry.var_type = g_strdup(tag_entry->extensionFields.varType);
|
|
if (tag_entry->extensionFields.access != NULL)
|
|
{
|
|
if (0 == strcmp("public", tag_entry->extensionFields.access))
|
|
tag->atts.entry.access = TAG_ACCESS_PUBLIC;
|
|
else if (0 == strcmp("protected", tag_entry->extensionFields.access))
|
|
tag->atts.entry.access = TAG_ACCESS_PROTECTED;
|
|
else if (0 == strcmp("private", tag_entry->extensionFields.access))
|
|
tag->atts.entry.access = TAG_ACCESS_PRIVATE;
|
|
else if (0 == strcmp("friend", tag_entry->extensionFields.access))
|
|
tag->atts.entry.access = TAG_ACCESS_FRIEND;
|
|
else if (0 == strcmp("default", tag_entry->extensionFields.access))
|
|
tag->atts.entry.access = TAG_ACCESS_DEFAULT;
|
|
else
|
|
{
|
|
#ifdef TM_DEBUG
|
|
g_warning("Unknown access type %s", tag_entry->extensionFields.access);
|
|
#endif
|
|
tag->atts.entry.access = TAG_ACCESS_UNKNOWN;
|
|
}
|
|
}
|
|
if (tag_entry->extensionFields.implementation != NULL)
|
|
{
|
|
if ((0 == strcmp("virtual", tag_entry->extensionFields.implementation))
|
|
|| (0 == strcmp("pure virtual", tag_entry->extensionFields.implementation)))
|
|
tag->atts.entry.impl = TAG_IMPL_VIRTUAL;
|
|
else
|
|
{
|
|
#ifdef TM_DEBUG
|
|
g_warning("Unknown implementation %s", tag_entry->extensionFields.implementation);
|
|
#endif
|
|
tag->atts.entry.impl = TAG_IMPL_UNKNOWN;
|
|
}
|
|
}
|
|
if ((tm_tag_macro_t == tag->type) && (NULL != tag->atts.entry.arglist))
|
|
tag->type = tm_tag_macro_with_arg_t;
|
|
tag->atts.entry.file = file;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
TMTag *tm_tag_new(TMSourceFile *file, const tagEntryInfo *tag_entry)
|
|
{
|
|
TMTag *tag;
|
|
|
|
TAG_NEW(tag);
|
|
if (FALSE == tm_tag_init(tag, file, tag_entry))
|
|
{
|
|
TAG_FREE(tag);
|
|
return NULL;
|
|
}
|
|
return tag;
|
|
}
|
|
|
|
gboolean tm_tag_init_from_file(TMTag *tag, TMSourceFile *file, FILE *fp)
|
|
{
|
|
guchar buf[BUFSIZ];
|
|
guchar *start, *end;
|
|
gboolean status;
|
|
guchar changed_char = TA_NAME;
|
|
|
|
if ((NULL == fgets((gchar*)buf, BUFSIZ, fp)) || ('\0' == *buf))
|
|
return FALSE;
|
|
for (start = end = buf, status = TRUE; (TRUE == status); start = end, ++ end)
|
|
{
|
|
while ((*end < TA_NAME) && (*end != '\0') && (*end != '\n'))
|
|
++ end;
|
|
if (('\0' == *end) || ('\n' == *end))
|
|
status = FALSE;
|
|
changed_char = *end;
|
|
*end = '\0';
|
|
if (NULL == tag->name)
|
|
{
|
|
if (!isprint(*start))
|
|
return FALSE;
|
|
else
|
|
tag->name = g_strdup((gchar*)start);
|
|
}
|
|
else
|
|
{
|
|
switch (*start)
|
|
{
|
|
case TA_LINE:
|
|
tag->atts.entry.line = atol((gchar*)start + 1);
|
|
break;
|
|
case TA_LOCAL:
|
|
tag->atts.entry.local = atoi((gchar*)start + 1);
|
|
break;
|
|
case TA_TYPE:
|
|
tag->type = (TMTagType) atoi((gchar*)start + 1);
|
|
break;
|
|
case TA_ARGLIST:
|
|
tag->atts.entry.arglist = g_strdup((gchar*)start + 1);
|
|
break;
|
|
case TA_SCOPE:
|
|
tag->atts.entry.scope = g_strdup((gchar*)start + 1);
|
|
break;
|
|
case TA_POINTER:
|
|
tag->atts.entry.pointerOrder = atoi((gchar*)start + 1);
|
|
break;
|
|
case TA_VARTYPE:
|
|
tag->atts.entry.var_type = g_strdup((gchar*)start + 1);
|
|
break;
|
|
case TA_INHERITS:
|
|
tag->atts.entry.inheritance = g_strdup((gchar*)start + 1);
|
|
break;
|
|
case TA_TIME:
|
|
if (tm_tag_file_t != tag->type)
|
|
{
|
|
g_warning("Got time attribute for non-file tag %s", tag->name);
|
|
return FALSE;
|
|
}
|
|
else
|
|
tag->atts.file.timestamp = atol((gchar*)start + 1);
|
|
break;
|
|
case TA_LANG:
|
|
if (tm_tag_file_t != tag->type)
|
|
{
|
|
g_warning("Got lang attribute for non-file tag %s", tag->name);
|
|
return FALSE;
|
|
}
|
|
else
|
|
tag->atts.file.lang = atoi((gchar*)start + 1);
|
|
break;
|
|
case TA_INACTIVE:
|
|
if (tm_tag_file_t != tag->type)
|
|
{
|
|
g_warning("Got inactive attribute for non-file tag %s", tag->name);
|
|
return FALSE;
|
|
}
|
|
else
|
|
tag->atts.file.inactive = (gboolean) atoi((gchar*)start + 1);
|
|
break;
|
|
case TA_ACCESS:
|
|
tag->atts.entry.access = *(start + 1);
|
|
break;
|
|
case TA_IMPL:
|
|
tag->atts.entry.impl = *(start + 1);
|
|
break;
|
|
default:
|
|
#ifdef GEANY_DEBUG
|
|
g_warning("Unknown attribute %s", start + 1);
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
*end = changed_char;
|
|
}
|
|
if (NULL == tag->name)
|
|
return FALSE;
|
|
if (tm_tag_file_t != tag->type)
|
|
tag->atts.entry.file = file;
|
|
return TRUE;
|
|
}
|
|
|
|
/* alternative parser for Pascal and LaTeX global tags files with the following format
|
|
* tagname|return value|arglist|description\n */
|
|
gboolean tm_tag_init_from_file_alt(TMTag *tag, TMSourceFile *file, FILE *fp)
|
|
{
|
|
guchar buf[BUFSIZ];
|
|
guchar *start, *end;
|
|
gboolean status;
|
|
/*guchar changed_char = TA_NAME;*/
|
|
|
|
if ((NULL == fgets((gchar*)buf, BUFSIZ, fp)) || ('\0' == *buf))
|
|
return FALSE;
|
|
{
|
|
gchar **fields;
|
|
guint field_len;
|
|
for (start = end = buf, status = TRUE; (TRUE == status); start = end, ++ end)
|
|
{
|
|
while ((*end < TA_NAME) && (*end != '\0') && (*end != '\n'))
|
|
++ end;
|
|
if (('\0' == *end) || ('\n' == *end))
|
|
status = FALSE;
|
|
/*changed_char = *end;*/
|
|
*end = '\0';
|
|
if (NULL == tag->name && !isprint(*start))
|
|
return FALSE;
|
|
|
|
fields = g_strsplit((gchar*)start, "|", -1);
|
|
field_len = g_strv_length(fields);
|
|
|
|
if (field_len >= 1) tag->name = g_strdup(fields[0]);
|
|
else tag->name = NULL;
|
|
if (field_len >= 2 && fields[1] != NULL) tag->atts.entry.var_type = g_strdup(fields[1]);
|
|
if (field_len >= 3 && fields[2] != NULL) tag->atts.entry.arglist = g_strdup(fields[2]);
|
|
tag->type = tm_tag_prototype_t;
|
|
g_strfreev(fields);
|
|
}
|
|
}
|
|
|
|
if (NULL == tag->name)
|
|
return FALSE;
|
|
if (tm_tag_file_t != tag->type)
|
|
tag->atts.entry.file = file;
|
|
return TRUE;
|
|
}
|
|
|
|
TMTag *tm_tag_new_from_file(TMSourceFile *file, FILE *fp, gint mode, gboolean format_pipe)
|
|
{
|
|
TMTag *tag;
|
|
gboolean result;
|
|
|
|
TAG_NEW(tag);
|
|
|
|
if (format_pipe)
|
|
result = tm_tag_init_from_file_alt(tag, file, fp);
|
|
else
|
|
result = tm_tag_init_from_file(tag, file, fp);
|
|
|
|
if (! result)
|
|
{
|
|
TAG_FREE(tag);
|
|
return NULL;
|
|
}
|
|
tag->atts.file.lang = mode;
|
|
return tag;
|
|
}
|
|
|
|
gboolean tm_tag_write(TMTag *tag, FILE *fp, guint attrs)
|
|
{
|
|
fprintf(fp, "%s", tag->name);
|
|
if (attrs & tm_tag_attr_type_t)
|
|
fprintf(fp, "%c%d", TA_TYPE, tag->type);
|
|
if (tag->type == tm_tag_file_t)
|
|
{
|
|
if (attrs & tm_tag_attr_time_t)
|
|
fprintf(fp, "%c%ld", TA_TIME, tag->atts.file.timestamp);
|
|
if (attrs & tm_tag_attr_lang_t)
|
|
fprintf(fp, "%c%d", TA_LANG, tag->atts.file.lang);
|
|
if ((attrs & tm_tag_attr_inactive_t) && tag->atts.file.inactive)
|
|
fprintf(fp, "%c%d", TA_INACTIVE, tag->atts.file.inactive);
|
|
}
|
|
else
|
|
{
|
|
if ((attrs & tm_tag_attr_arglist_t) && (NULL != tag->atts.entry.arglist))
|
|
fprintf(fp, "%c%s", TA_ARGLIST, tag->atts.entry.arglist);
|
|
if (attrs & tm_tag_attr_line_t)
|
|
fprintf(fp, "%c%ld", TA_LINE, tag->atts.entry.line);
|
|
if (attrs & tm_tag_attr_local_t)
|
|
fprintf(fp, "%c%d", TA_LOCAL, tag->atts.entry.local);
|
|
if ((attrs & tm_tag_attr_scope_t) && (NULL != tag->atts.entry.scope))
|
|
fprintf(fp, "%c%s", TA_SCOPE, tag->atts.entry.scope);
|
|
if ((attrs & tm_tag_attr_inheritance_t) && (NULL != tag->atts.entry.inheritance))
|
|
fprintf(fp, "%c%s", TA_INHERITS, tag->atts.entry.inheritance);
|
|
if (attrs & tm_tag_attr_pointer_t)
|
|
fprintf(fp, "%c%d", TA_POINTER, tag->atts.entry.pointerOrder);
|
|
if ((attrs & tm_tag_attr_vartype_t) && (NULL != tag->atts.entry.var_type))
|
|
fprintf(fp, "%c%s", TA_VARTYPE, tag->atts.entry.var_type);
|
|
if ((attrs & tm_tag_attr_access_t) && (TAG_ACCESS_UNKNOWN != tag->atts.entry.access))
|
|
fprintf(fp, "%c%c", TA_ACCESS, tag->atts.entry.access);
|
|
if ((attrs & tm_tag_attr_impl_t) && (TAG_IMPL_UNKNOWN != tag->atts.entry.impl))
|
|
fprintf(fp, "%c%c", TA_IMPL, tag->atts.entry.impl);
|
|
}
|
|
if (fprintf(fp, "\n"))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static void tm_tag_destroy(TMTag *tag)
|
|
{
|
|
g_free(tag->name);
|
|
if (tm_tag_file_t != tag->type)
|
|
{
|
|
g_free(tag->atts.entry.arglist);
|
|
g_free(tag->atts.entry.scope);
|
|
g_free(tag->atts.entry.inheritance);
|
|
g_free(tag->atts.entry.var_type);
|
|
}
|
|
}
|
|
|
|
void tm_tag_free(gpointer tag)
|
|
{
|
|
if (NULL != tag)
|
|
{
|
|
tm_tag_destroy((TMTag *) tag);
|
|
TAG_FREE(tag);
|
|
}
|
|
}
|
|
|
|
int tm_tag_compare(const void *ptr1, const void *ptr2)
|
|
{
|
|
unsigned int *sort_attr;
|
|
int returnval = 0;
|
|
TMTag *t1 = *((TMTag **) ptr1);
|
|
TMTag *t2 = *((TMTag **) ptr2);
|
|
|
|
if ((NULL == t1) || (NULL == t2))
|
|
{
|
|
g_warning("Found NULL tag");
|
|
return t2 - t1;
|
|
}
|
|
if (NULL == s_sort_attrs)
|
|
{
|
|
if (s_partial)
|
|
return strncmp(NVL(t1->name, ""), NVL(t2->name, ""), strlen(NVL(t1->name, "")));
|
|
else
|
|
return strcmp(NVL(t1->name, ""), NVL(t2->name, ""));
|
|
}
|
|
|
|
for (sort_attr = s_sort_attrs; *sort_attr != tm_tag_attr_none_t; ++ sort_attr)
|
|
{
|
|
switch (*sort_attr)
|
|
{
|
|
case tm_tag_attr_name_t:
|
|
if (s_partial)
|
|
returnval = strncmp(NVL(t1->name, ""), NVL(t2->name, ""), strlen(NVL(t1->name, "")));
|
|
else
|
|
returnval = strcmp(NVL(t1->name, ""), NVL(t2->name, ""));
|
|
if (0 != returnval)
|
|
return returnval;
|
|
break;
|
|
case tm_tag_attr_type_t:
|
|
if (0 != (returnval = (t1->type - t2->type)))
|
|
return returnval;
|
|
break;
|
|
case tm_tag_attr_file_t:
|
|
if (0 != (returnval = (t1->atts.entry.file - t2->atts.entry.file)))
|
|
return returnval;
|
|
break;
|
|
case tm_tag_attr_scope_t:
|
|
if (0 != (returnval = strcmp(NVL(t1->atts.entry.scope, ""), NVL(t2->atts.entry.scope, ""))))
|
|
return returnval;
|
|
break;
|
|
case tm_tag_attr_arglist_t:
|
|
if (0 != (returnval = strcmp(NVL(t1->atts.entry.arglist, ""), NVL(t2->atts.entry.arglist, ""))))
|
|
{
|
|
int line_diff = (t1->atts.entry.line - t2->atts.entry.line);
|
|
|
|
return line_diff ? line_diff : returnval;
|
|
}
|
|
break;
|
|
case tm_tag_attr_vartype_t:
|
|
if (0 != (returnval = strcmp(NVL(t1->atts.entry.var_type, ""), NVL(t2->atts.entry.var_type, ""))))
|
|
return returnval;
|
|
break;
|
|
case tm_tag_attr_line_t:
|
|
if (0 != (returnval = (t1->atts.entry.line - t2->atts.entry.line)))
|
|
return returnval;
|
|
break;
|
|
}
|
|
}
|
|
return returnval;
|
|
}
|
|
|
|
gboolean tm_tags_prune(GPtrArray *tags_array)
|
|
{
|
|
guint i, count;
|
|
for (i=0, count = 0; i < tags_array->len; ++i)
|
|
{
|
|
if (NULL != tags_array->pdata[i])
|
|
tags_array->pdata[count++] = tags_array->pdata[i];
|
|
}
|
|
tags_array->len = count;
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean tm_tags_dedup(GPtrArray *tags_array, TMTagAttrType *sort_attributes)
|
|
{
|
|
guint i;
|
|
|
|
if ((!tags_array) || (!tags_array->len))
|
|
return TRUE;
|
|
s_sort_attrs = sort_attributes;
|
|
s_partial = FALSE;
|
|
for (i = 1; i < tags_array->len; ++i)
|
|
{
|
|
if (0 == tm_tag_compare(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i])))
|
|
{
|
|
tags_array->pdata[i-1] = NULL;
|
|
}
|
|
}
|
|
tm_tags_prune(tags_array);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean tm_tags_custom_dedup(GPtrArray *tags_array, TMTagCompareFunc compare_func)
|
|
{
|
|
guint i;
|
|
|
|
if ((!tags_array) || (!tags_array->len))
|
|
return TRUE;
|
|
for (i = 1; i < tags_array->len; ++i)
|
|
{
|
|
if (0 == compare_func(&(tags_array->pdata[i - 1]), &(tags_array->pdata[i])))
|
|
tags_array->pdata[i-1] = NULL;
|
|
}
|
|
tm_tags_prune(tags_array);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean tm_tags_sort(GPtrArray *tags_array, TMTagAttrType *sort_attributes, gboolean dedup)
|
|
{
|
|
if ((!tags_array) || (!tags_array->len))
|
|
return TRUE;
|
|
s_sort_attrs = sort_attributes;
|
|
s_partial = FALSE;
|
|
qsort(tags_array->pdata, tags_array->len, sizeof(gpointer), tm_tag_compare);
|
|
s_sort_attrs = NULL;
|
|
if (dedup)
|
|
tm_tags_dedup(tags_array, sort_attributes);
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean tm_tags_custom_sort(GPtrArray *tags_array, TMTagCompareFunc compare_func, gboolean dedup)
|
|
{
|
|
if ((!tags_array) || (!tags_array->len))
|
|
return TRUE;
|
|
qsort(tags_array->pdata, tags_array->len, sizeof(gpointer), compare_func);
|
|
if (dedup)
|
|
tm_tags_custom_dedup(tags_array, compare_func);
|
|
return TRUE;
|
|
}
|
|
|
|
GPtrArray *tm_tags_extract(GPtrArray *tags_array, guint tag_types)
|
|
{
|
|
GPtrArray *new_tags;
|
|
guint i;
|
|
if (NULL == tags_array)
|
|
return NULL;
|
|
new_tags = g_ptr_array_new();
|
|
for (i=0; i < tags_array->len; ++i)
|
|
{
|
|
if (NULL != tags_array->pdata[i])
|
|
{
|
|
if (tag_types & (((TMTag *) tags_array->pdata[i])->type))
|
|
g_ptr_array_add(new_tags, tags_array->pdata[i]);
|
|
}
|
|
}
|
|
return new_tags;
|
|
}
|
|
|
|
void tm_tags_array_free(GPtrArray *tags_array, gboolean free_all)
|
|
{
|
|
if (tags_array)
|
|
{
|
|
guint i;
|
|
for (i = 0; i < tags_array->len; ++i)
|
|
tm_tag_free(tags_array->pdata[i]);
|
|
if (free_all)
|
|
g_ptr_array_free(tags_array, TRUE);
|
|
else
|
|
g_ptr_array_set_size(tags_array, 0);
|
|
}
|
|
}
|
|
|
|
TMTag **tm_tags_find(const GPtrArray *sorted_tags_array, const char *name,
|
|
gboolean partial, int * tagCount)
|
|
{
|
|
static TMTag *tag = NULL;
|
|
TMTag **result;
|
|
int tagMatches=0;
|
|
|
|
if ((!sorted_tags_array) || (!sorted_tags_array->len))
|
|
return NULL;
|
|
|
|
if (NULL == tag)
|
|
tag = g_new0(TMTag, 1);
|
|
tag->name = (char *) name;
|
|
s_sort_attrs = NULL;
|
|
s_partial = partial;
|
|
result = (TMTag **) bsearch(&tag, sorted_tags_array->pdata, sorted_tags_array->len
|
|
, sizeof(gpointer), tm_tag_compare);
|
|
/* There can be matches on both sides of result */
|
|
if (result)
|
|
{
|
|
TMTag **last = (TMTag **) &sorted_tags_array->pdata[sorted_tags_array->len - 1];
|
|
TMTag **adv;
|
|
|
|
/* First look for any matches after result */
|
|
adv = result;
|
|
adv++;
|
|
for (; adv <= last && *adv; ++ adv)
|
|
{
|
|
if (0 != tm_tag_compare(&tag, adv))
|
|
break;
|
|
++tagMatches;
|
|
}
|
|
/* Now look for matches from result and below */
|
|
for (; result >= (TMTag **) sorted_tags_array->pdata; -- result)
|
|
{
|
|
if (0 != tm_tag_compare(&tag, (TMTag **) result))
|
|
break;
|
|
++tagMatches;
|
|
}
|
|
*tagCount=tagMatches;
|
|
++ result; /* Correct address for the last successful match */
|
|
}
|
|
s_partial = FALSE;
|
|
return (TMTag **) result;
|
|
}
|
|
|
|
const char *tm_tag_type_name(const TMTag *tag)
|
|
{
|
|
g_return_val_if_fail(tag, NULL);
|
|
switch(tag->type)
|
|
{
|
|
case tm_tag_class_t: return "class";
|
|
case tm_tag_enum_t: return "enum";
|
|
case tm_tag_enumerator_t: return "enumval";
|
|
case tm_tag_field_t: return "field";
|
|
case tm_tag_function_t: return "function";
|
|
case tm_tag_interface_t: return "interface";
|
|
case tm_tag_member_t: return "member";
|
|
case tm_tag_method_t: return "method";
|
|
case tm_tag_namespace_t: return "namespace";
|
|
case tm_tag_package_t: return "package";
|
|
case tm_tag_prototype_t: return "prototype";
|
|
case tm_tag_struct_t: return "struct";
|
|
case tm_tag_typedef_t: return "typedef";
|
|
case tm_tag_union_t: return "union";
|
|
case tm_tag_variable_t: return "variable";
|
|
case tm_tag_externvar_t: return "extern";
|
|
case tm_tag_macro_t: return "define";
|
|
case tm_tag_macro_with_arg_t: return "macro";
|
|
case tm_tag_file_t: return "file";
|
|
default: return NULL;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
TMTagType tm_tag_name_type(const char* tag_name)
|
|
{
|
|
g_return_val_if_fail(tag_name, tm_tag_undef_t);
|
|
|
|
if (strcmp(tag_name, "class") == 0) return tm_tag_class_t;
|
|
else if (strcmp(tag_name, "enum") == 0) return tm_tag_enum_t;
|
|
else if (strcmp(tag_name, "enumval") == 0) return tm_tag_enumerator_t;
|
|
else if (strcmp(tag_name, "field") == 0) return tm_tag_field_t;
|
|
else if (strcmp(tag_name, "function") == 0) return tm_tag_function_t;
|
|
else if (strcmp(tag_name, "interface") == 0) return tm_tag_interface_t;
|
|
else if (strcmp(tag_name, "member") == 0) return tm_tag_member_t;
|
|
else if (strcmp(tag_name, "method") == 0) return tm_tag_method_t;
|
|
else if (strcmp(tag_name, "namespace") == 0) return tm_tag_namespace_t;
|
|
else if (strcmp(tag_name, "package") == 0) return tm_tag_package_t;
|
|
else if (strcmp(tag_name, "prototype") == 0) return tm_tag_prototype_t;
|
|
else if (strcmp(tag_name, "struct") == 0) return tm_tag_struct_t;
|
|
else if (strcmp(tag_name, "typedef") == 0) return tm_tag_typedef_t;
|
|
else if (strcmp(tag_name, "union") == 0) return tm_tag_union_t;
|
|
else if (strcmp(tag_name, "variable") == 0) return tm_tag_variable_t;
|
|
else if (strcmp(tag_name, "extern") == 0) return tm_tag_externvar_t;
|
|
else if (strcmp(tag_name, "define") == 0) return tm_tag_macro_t;
|
|
else if (strcmp(tag_name, "macro") == 0) return tm_tag_macro_with_arg_t;
|
|
else if (strcmp(tag_name, "file") == 0) return tm_tag_file_t;
|
|
else return tm_tag_undef_t;
|
|
}
|
|
|
|
static const char *tm_tag_impl_name(TMTag *tag)
|
|
{
|
|
g_return_val_if_fail(tag && (tm_tag_file_t != tag->type), NULL);
|
|
if (TAG_IMPL_VIRTUAL == tag->atts.entry.impl)
|
|
return "virtual";
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
static const char *tm_tag_access_name(TMTag *tag)
|
|
{
|
|
g_return_val_if_fail(tag && (tm_tag_file_t != tag->type), NULL);
|
|
if (TAG_ACCESS_PUBLIC == tag->atts.entry.access)
|
|
return "public";
|
|
else if (TAG_ACCESS_PROTECTED == tag->atts.entry.access)
|
|
return "protected";
|
|
else if (TAG_ACCESS_PRIVATE == tag->atts.entry.access)
|
|
return "private";
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void tm_tag_print(TMTag *tag, FILE *fp)
|
|
{
|
|
const char *laccess, *impl, *type;
|
|
if (!tag || !fp)
|
|
return;
|
|
if (tm_tag_file_t == tag->type)
|
|
{
|
|
fprintf(fp, "%s\n", tag->name);
|
|
return;
|
|
}
|
|
laccess = tm_tag_access_name(tag);
|
|
impl = tm_tag_impl_name(tag);
|
|
type = tm_tag_type_name(tag);
|
|
if (laccess)
|
|
fprintf(fp, "%s ", laccess);
|
|
if (impl)
|
|
fprintf(fp, "%s ", impl);
|
|
if (type)
|
|
fprintf(fp, "%s ", type);
|
|
if (tag->atts.entry.var_type)
|
|
fprintf(fp, "%s ", tag->atts.entry.var_type);
|
|
if (tag->atts.entry.scope)
|
|
fprintf(fp, "%s::", tag->atts.entry.scope);
|
|
fprintf(fp, "%s", tag->name);
|
|
if (tag->atts.entry.arglist)
|
|
fprintf(fp, "%s", tag->atts.entry.arglist);
|
|
if (tag->atts.entry.inheritance)
|
|
fprintf(fp, " : from %s", tag->atts.entry.inheritance);
|
|
if ((tag->atts.entry.file) && (tag->atts.entry.line > 0))
|
|
fprintf(fp, "[%s:%ld]", tag->atts.entry.file->work_object.file_name
|
|
, tag->atts.entry.line);
|
|
fprintf(fp, "\n");
|
|
}
|
|
|
|
void tm_tags_array_print(GPtrArray *tags, FILE *fp)
|
|
{
|
|
guint i;
|
|
TMTag *tag;
|
|
if (!(tags && (tags->len > 0) && fp))
|
|
return;
|
|
for (i = 0; i < tags->len; ++i)
|
|
{
|
|
tag = TM_TAG(tags->pdata[i]);
|
|
tm_tag_print(tag, fp);
|
|
}
|
|
}
|
|
|
|
gint tm_tag_scope_depth(const TMTag *t)
|
|
{
|
|
gint depth;
|
|
char *s;
|
|
if(!(t && t->atts.entry.scope))
|
|
return 0;
|
|
for (s = t->atts.entry.scope, depth = 0; s; s = strstr(s, "::"))
|
|
{
|
|
++ depth;
|
|
++ s;
|
|
}
|
|
return depth;
|
|
}
|