⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 readtags.c

📁 ultraEdit的Ctag标签工具的实现源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
    if (file->program.author != NULL)
	free (file->program.author);
    if (file->program.name != NULL)
	free (file->program.name);
    if (file->program.url != NULL)
	free (file->program.url);
    if (file->program.version != NULL)
	free (file->program.version);

    memset (file, 0, sizeof (tagFile));

    free (file);
}

static tagResult readNext (tagFile *const file, tagEntry *const entry)
{
    tagResult result = TagFailure;
    if (file == NULL  ||  ! file->initialized)
	result = TagFailure;
    else if (! readTagLine (file))
	result = TagFailure;
    else
    {
	if (entry != NULL)
	    parseTagLine (file, entry);
	result = TagSuccess;
    }
    return result;
}

static const char *readFieldValue (
    const tagEntry *const entry, const char *const key)
{
    const char *result = NULL;
    int i;
    if (strcmp (key, "kind") == 0)
	result = entry->kind;
    else if (strcmp (key, "file") == 0)
	result = EmptyString;
    else for (i = 0  ;  i < entry->fields.count  &&  result == NULL  ;  ++i)
	if (strcmp (entry->fields.list [i].key, key) == 0)
	    result = entry->fields.list [i].value;
    return result;
}

static int readTagLineSeek (tagFile *const file, const off_t pos)
{
    int result = 0;
    if (fseek (file->fp, pos, SEEK_SET) == 0)
    {
	result = readTagLine (file);		/* read probable partial line */
	if (pos > 0  &&  result)
	    result = readTagLine (file);	/* read complete line */
    }
    return result;
}

static int nameComparison (tagFile *const file)
{
    int result;
    if (file->search.ignorecase)
    {
	if (file->search.partial)
	    result = strnuppercmp (file->search.name, file->name.buffer,
		    file->search.nameLength);
	else
	    result = struppercmp (file->search.name, file->name.buffer);
    }
    else
    {
	if (file->search.partial)
	    result = strncmp (file->search.name, file->name.buffer,
		    file->search.nameLength);
	else
	    result = strcmp (file->search.name, file->name.buffer);
    }
    return result;
}

static void findFirstNonMatchBefore (tagFile *const file)
{
#define JUMP_BACK 512
    int more_lines;
    int comp;
    off_t start = file->pos;
    off_t pos = start;
    do
    {
	if (pos < (off_t) JUMP_BACK)
	    pos = 0;
	else
	    pos = pos - JUMP_BACK;
	more_lines = readTagLineSeek (file, pos);
	comp = nameComparison (file);
    } while (more_lines  &&  comp == 0  &&  pos > 0  &&  pos < start);
}

static tagResult findFirstMatchBefore (tagFile *const file)
{
    tagResult result = TagFailure;
    int more_lines;
    off_t start = file->pos;
    findFirstNonMatchBefore (file);
    do
    {
	more_lines = readTagLine (file);
	if (nameComparison (file) == 0)
	    result = TagSuccess;
    } while (more_lines  &&  result != TagSuccess  &&  file->pos < start);
    return result;
}

static tagResult findBinary (tagFile *const file)
{
    tagResult result = TagFailure;
    off_t lower_limit = 0;
    off_t upper_limit = file->size;
    off_t last_pos = 0;
    off_t pos = upper_limit / 2;
    while (result != TagSuccess)
    {
	if (! readTagLineSeek (file, pos))
	{
	    /* in case we fell off end of file */
	    result = findFirstMatchBefore (file);
	    break;
	}
	else if (pos == last_pos)
	{
	    /* prevent infinite loop if we backed up to beginning of file */
	    break;
	}
	else
	{
	    const int comp = nameComparison (file);
	    last_pos = pos;
	    if (comp < 0)
	    {
		upper_limit = pos;
		pos = lower_limit + ((upper_limit - lower_limit) / 2);
	    }
	    else if (comp > 0)
	    {
		lower_limit = pos;
		pos = lower_limit + ((upper_limit - lower_limit) / 2);
	    }
	    else if (pos == 0)
		result = TagSuccess;
	    else
		result = findFirstMatchBefore (file);
	}
    }
    return result;
}

static tagResult findSequential (tagFile *const file)
{
    tagResult result = TagFailure;
    if (file->initialized)
    {
	while (result == TagFailure  &&  readTagLine (file))
	{
	    if (nameComparison (file) == 0)
		result = TagSuccess;
	}
    }
    return result;
}

static tagResult find (tagFile *const file, tagEntry *const entry,
		       const char *const name, const int options)
{
    tagResult result = TagFailure;
    file->search.name = name;
    file->search.nameLength = strlen (name);
    file->search.partial = (options & TAG_PARTIALMATCH) != 0;
    file->search.ignorecase = (options & TAG_IGNORECASE) != 0;
    fseek (file->fp, 0, SEEK_END);
    file->size = ftell (file->fp);
    rewind (file->fp);
    if ((file->sortMethod == TAG_SORTED      && !file->search.ignorecase) ||
	(file->sortMethod == TAG_FOLDSORTED  &&  file->search.ignorecase))
    {
#ifdef DEBUG
	printf ("<performing binary search>\n");
#endif
	result = findBinary (file);
    }
    else
    {
#ifdef DEBUG
	printf ("<performing sequential search>\n");
#endif
	result = findSequential (file);
    }

    if (result != TagSuccess)
	file->search.pos = file->size;
    else
    {
	file->search.pos = file->pos;
	if (entry != NULL)
	    parseTagLine (file, entry);
    }
    return result;
}

static tagResult findNext (tagFile *const file, tagEntry *const entry)
{
    tagResult result = TagFailure;
    if ((file->sortMethod == TAG_SORTED      && !file->search.ignorecase) ||
	(file->sortMethod == TAG_FOLDSORTED  &&  file->search.ignorecase))
    {
	result = tagsNext (file, entry);
	if (result == TagSuccess  && nameComparison (file) != 0)
	    result = TagFailure;
    }
    else
    {
	result = findSequential (file);
	if (result == TagSuccess  &&  entry != NULL)
	    parseTagLine (file, entry);
    }
    return result;
}

/*
*  EXTERNAL INTERFACE
*/

extern tagFile *tagsOpen (const char *const filePath, tagFileInfo *const info)
{
    return initialize (filePath, info);
}

extern tagResult tagsSetSortType (tagFile *const file, const sortType type)
{
    tagResult result = TagFailure;
    if (file != NULL  &&  file->initialized)
    {
	file->sortMethod = type;
	result = TagSuccess;
    }
    return result;
}

extern tagResult tagsFirst (tagFile *const file, tagEntry *const entry)
{
    tagResult result = TagFailure;
    if (file != NULL  &&  file->initialized)
    {
	gotoFirstLogicalTag (file);
	result = readNext (file, entry);
    }
    return result;
}

extern tagResult tagsNext (tagFile *const file, tagEntry *const entry)
{
    tagResult result = TagFailure;
    if (file != NULL  &&  file->initialized)
	result = readNext (file, entry);
    return result;
}

extern const char *tagsField (const tagEntry *const entry, const char *const key)
{
    const char *result = NULL;
    if (entry != NULL)
	result = readFieldValue (entry, key);
    return result;
}

extern tagResult tagsFind (tagFile *const file, tagEntry *const entry,
			   const char *const name, const int options)
{
    tagResult result = TagFailure;
    if (file != NULL  &&  file->initialized)
	result = find (file, entry, name, options);
    return result;
}

extern tagResult tagsFindNext (tagFile *const file, tagEntry *const entry)
{
    tagResult result = TagFailure;
    if (file != NULL  &&  file->initialized)
	result = findNext (file, entry);
    return result;
}

extern tagResult tagsClose (tagFile *const file)
{
    tagResult result = TagFailure;
    if (file != NULL  &&  file->initialized)
    {
	terminate (file);
	result = TagSuccess;
    }
    return result;
}

/*
*  TEST FRAMEWORK
*/

#ifdef READTAGS_MAIN

static const char *TagFileName = "tags";
static const char *ProgramName;
static int extensionFields;
static int SortOverride;
static sortType SortMethod;

static void printTag (const tagEntry *entry)
{
    int i;
    int first = 1;
    const char* separator = ";\"";
    const char* const empty = "";
/* "sep" returns a value only the first time it is evaluated */
#define sep (first ? (first = 0, separator) : empty)
    printf ("%s\t%s\t%s",
	entry->name, entry->file, entry->address.pattern);
    if (extensionFields)
    {
	if (entry->kind != NULL  &&  entry->kind [0] != '\0')
	    printf ("%s\tkind:%s", sep, entry->kind);
	if (entry->fileScope)
	    printf ("%s\tfile:", sep);
#if 0
	if (entry->address.lineNumber > 0)
	    printf ("%s\tline:%lu", sep, entry->address.lineNumber);
#endif
	for (i = 0  ;  i < entry->fields.count  ;  ++i)
	    printf ("%s\t%s:%s", sep, entry->fields.list [i].key,
		entry->fields.list [i].value);
    }
    putchar ('\n');
#undef sep
}

static void findTag (const char *const name, const int options)
{
    tagFileInfo info;
    tagEntry entry;
    tagFile *const file = tagsOpen (TagFileName, &info);
    if (file == NULL)
    {
	fprintf (stderr, "%s: cannot open tag file: %s: %s\n",
		ProgramName, strerror (info.status.error_number), name);
	exit (1);
    }
    else
    {
	if (SortOverride)
	    tagsSetSortType (file, SortMethod);
	if (tagsFind (file, &entry, name, options) == TagSuccess)
	{
	    do
	    {
		printTag (&entry);
	    } while (tagsFindNext (file, &entry) == TagSuccess);
	}
	tagsClose (file);
    }
}

static void listTags (void)
{
    tagFileInfo info;
    tagEntry entry;
    tagFile *const file = tagsOpen (TagFileName, &info);
    if (file == NULL)
    {
	fprintf (stderr, "%s: cannot open tag file: %s: %s\n",
		ProgramName, strerror (info.status.error_number), TagFileName);
	exit (1);
    }
    else
    {
	while (tagsNext (file, &entry) == TagSuccess)
	    printTag (&entry);
	tagsClose (file);
    }
}

const char *const Usage =
    "Find tag file entries matching specified names.\n\n"
    "Usage: %s [-ilp] [-s[0|1]] [-t file] [name(s)]\n\n"
    "Options:\n"
    "    -e           Include extension fields in output.\n"
    "    -i           Perform case-insensitive matching.\n"
    "    -l           List all tags.\n"
    "    -p           Perform partial matching.\n"
    "    -s[0|1|2]    Override sort detection of tag file.\n"
    "    -t file      Use specified tag file (default: \"tags\").\n"
    "Note that options are acted upon as encountered, so order is significant.\n";

extern int main (int argc, char **argv)
{
    int options = 0;
    int actionSupplied = 0;
    int i;
    ProgramName = argv [0];
    if (argc == 1)
    {
	fprintf (stderr, Usage, ProgramName);
	exit (1);
    }
    for (i = 1  ;  i < argc  ;  ++i)
    {
	const char *const arg = argv [i];
	if (arg [0] != '-')
	{
	    findTag (arg, options);
	    actionSupplied = 1;
	}
	else
	{
	    size_t j;
	    for (j = 1  ;  arg [j] != '\0'  ;  ++j)
	    {
		switch (arg [j])
		{
		    case 'e': extensionFields = 1;         break;
		    case 'i': options |= TAG_IGNORECASE;   break;
		    case 'p': options |= TAG_PARTIALMATCH; break;
		    case 'l': listTags (); actionSupplied = 1; break;
	    
		    case 't':
			if (arg [j+1] != '\0')
			{
			    TagFileName = arg + j + 1;
			    j += strlen (TagFileName);
			}
			else if (i + 1 < argc)
			    TagFileName = argv [++i];
			else
			{
			    fprintf (stderr, Usage, ProgramName);
			    exit (1);
			}
			break;
		    case 's':
			SortOverride = 1;
			++j;
			if (arg [j] == '\0')
			    SortMethod = TAG_SORTED;
			else if (strchr ("012", arg[j]) != NULL)
			    SortMethod = (sortType) (arg[j] - '0');
			else
			{
			    fprintf (stderr, Usage, ProgramName);
			    exit (1);
			}
			break;
		    default:
			fprintf (stderr, "%s: unknown option: %c\n",
				    ProgramName, arg[j]);
			exit (1);
			break;
		}
	    }
	}
    }
    if (! actionSupplied)
    {
	fprintf (stderr,
	    "%s: no action specified: specify tag name(s) or -l option\n",
	    ProgramName);
	exit (1);
    }
    return 0;
}

#endif

/* vi:set tabstop=8 shiftwidth=4: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -