📄 readtags.c
字号:
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_MAINstatic 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 + -