📄 readtags.cpp
字号:
/******************************************************************************************************** * PROGRAM : * DATE - TIME : lundi 10 avril 2006 - 22:28 * AUTHOR : Darren Hiebert and Anacr0x ( fred.julian at gmail.com ) * FILENAME : * LICENSE : GPL * COMMENTARY : Modified file (with qt) of the ctags project ********************************************************************************************************//** This module contains functions for reading tag files.*//** INCLUDE FILES*/#include <stdlib.h>#include <string.h>#include <ctype.h>#include <stdio.h>#include <errno.h>#include <sys/types.h> /* to declare off_t */#include "readtags.h"/** MACROS*/#define TAB '\t'#include <QDebug>/** DATA DECLARATIONS*/typedef struct{ size_t size; char *buffer;}vstring;/* Information about current tag file */struct sTagFile{ /* has the file been opened and this structure initialized? */ short initialized; /* format of tag file */ short format; /* how is the tag file sorted? */ sortType sortMethod; /* pointer to file structure */ FILE *fp; /* file position of first character of `line' */ off_t pos; /* size of tag file in seekable positions */ off_t size; /* last line read */ vstring line; /* name of tag in last line read */ vstring name; /* defines tag search state */ struct { /* file position of last match for tag */ off_t pos; /* name of tag last searched for */ const char *name; /* length of name for partial matches */ size_t nameLength; /* peforming partial match */ short partial; /* ignoring case */ short ignorecase; } search; /* miscellaneous extension fields */ struct { /* number of entries in `list' */ unsigned short max; /* list of key value pairs */ tagExtensionField *list; } fields; /* buffers to be freed at close */ struct { /* name of program author */ char *author; /* name of program */ char *name; /* URL of distribution */ char *url; /* program version */ char *version; } program;};/** DATA DEFINITIONS*/const char *const EmptyString = "";const char *const PseudoTagPrefix = "!_";/** FUNCTION DEFINITIONS*//* * Compare two strings, ignoring case. * Return 0 for match, < 0 for smaller, > 0 for bigger * Make sure case is folded to uppercase in comparison (like for 'sort -f') * This makes a difference when one of the chars lies between upper and lower * ie. one of the chars [ \ ] ^ _ ` for ascii. (The '_' in particular !) */static int struppercmp(const char *s1, const char *s2){ int result; do { result = toupper((int) *s1) - toupper((int) *s2); } while (result == 0 && *s1++ != '\0' && *s2++ != '\0'); return result;}static int strnuppercmp(const char *s1, const char *s2, size_t n){ int result; do { result = toupper((int) *s1) - toupper((int) *s2); } while (result == 0 && --n > 0 && *s1++ != '\0' && *s2++ != '\0'); return result;}static int growString(vstring * s){ int result = 0; size_t newLength; char *newLine; if (s->size == 0) { newLength = 128; newLine = (char *) malloc(newLength); *newLine = '\0'; } else { newLength = 2 * s->size; newLine = (char *) realloc(s->buffer, newLength); } if (newLine == NULL) perror("string too large"); else { s->buffer = newLine; s->size = newLength; result = 1; } return result;}/* Copy name of tag out of tag line */static void copyName(tagFile * const file){ size_t length; const char *end = strchr(file->line.buffer, '\t'); if (end == NULL) { end = strchr(file->line.buffer, '\n'); if (end == NULL) end = strchr(file->line.buffer, '\r'); } if (end != NULL) length = end - file->line.buffer; else length = strlen(file->line.buffer); while (length >= file->name.size) growString(&file->name); strncpy(file->name.buffer, file->line.buffer, length); file->name.buffer[length] = '\0';}static int readTagLineRaw(tagFile * const file){ int result = 1; int reReadLine; /* If reading the line places any character other than a null or a * newline at the last character position in the buffer (one less than * the buffer size), then we must resize the buffer and reattempt to read * the line. */ do { char *const pLastChar = file->line.buffer + file->line.size - 2; char *line; file->pos = ftell(file->fp); reReadLine = 0; *pLastChar = '\0'; line = fgets(file->line.buffer, (int) file->line.size, file->fp); if (line == NULL) { /* read error */ if (!feof(file->fp)) perror("readTagLine"); result = 0; } else if (*pLastChar != '\0' && *pLastChar != '\n' && *pLastChar != '\r') { /* buffer overflow */ growString(&file->line); fseek(file->fp, file->pos, SEEK_SET); reReadLine = 1; } else { size_t i = strlen(file->line.buffer); while (i > 0 && (file->line.buffer[i - 1] == '\n' || file->line.buffer[i - 1] == '\r')) { file->line.buffer[i - 1] = '\0'; --i; } } } while (reReadLine && result); if (result) copyName(file); return result;}static int readTagLine(tagFile * const file){ int result; do { result = readTagLineRaw(file); } while (result && *file->name.buffer == '\0'); return result;}static tagResult growFields(tagFile * const file){ tagResult result = TagFailure; unsigned short newCount = 2 * file->fields.max; tagExtensionField *newFields = (tagExtensionField *) realloc(file->fields.list, newCount * sizeof(tagExtensionField)); if (newFields == NULL) perror("too many extension fields"); else { file->fields.list = newFields; file->fields.max = newCount; result = TagSuccess; } return result;}static void parseExtensionFields(tagFile * const file, tagEntry * const entry, char *const string){ char *p = string; while (p != NULL && *p != '\0') { while (*p == TAB) *p++ = '\0'; if (*p != '\0') { char *colon; char *field = p; p = strchr(p, TAB); if (p != NULL) *p++ = '\0'; colon = strchr(field, ':'); if (colon == NULL) entry->kind = field; else { const char *key = field; const char *value = colon + 1; *colon = '\0'; if (strcmp(key, "kind") == 0) entry->kind = value; else if (strcmp(key, "file") == 0) entry->fileScope = 1; else if (strcmp(key, "line") == 0) entry->address.lineNumber = atol(value); else { if (entry->fields.count == file->fields.max) growFields(file); file->fields.list[entry->fields.count].key = key; file->fields.list[entry->fields.count].value = value; ++entry->fields.count; } } } }}static void parseTagLine(tagFile * file, tagEntry * const entry){ int i; char *p = file->line.buffer; char *tab = strchr(p, TAB); int fieldsPresent = 0; entry->fields.list = NULL; entry->fields.count = 0; entry->kind = NULL; entry->fileScope = 0; entry->name = p; if (tab != NULL) { *tab = '\0'; p = tab + 1; entry->file = p; tab = strchr(p, TAB); if (tab != NULL) { *tab = '\0'; p = tab + 1; if (*p == '/' || *p == '?') { /* parse pattern */ int delimiter = *(unsigned char *) p; entry->address.lineNumber = 0; entry->address.pattern = p; do { p = strchr(p + 1, delimiter); } while (p != NULL && *(p - 1) == '\\'); if (p == NULL) { /* invalid pattern */ } else ++p; } else if (isdigit((int) *(unsigned char *) p)) { /* parse line number */ entry->address.pattern = p; entry->address.lineNumber = atol(p); while (isdigit((int) *(unsigned char *) p)) ++p; } else { /* invalid pattern */ } fieldsPresent = (strncmp(p, ";\"", 2) == 0); *p = '\0'; if (fieldsPresent) parseExtensionFields(file, entry, p + 2); } } if (entry->fields.count > 0) entry->fields.list = file->fields.list; for (i = entry->fields.count; i < file->fields.max; ++i) { file->fields.list[i].key = NULL; file->fields.list[i].value = NULL; }}static char *duplicate(const char *str){ char *result = NULL; if (str != NULL) { result = (char *) malloc(strlen(str) + 1); if (result == NULL) perror(NULL); else strcpy(result, str); } return result;}static void readPseudoTags(tagFile * const file, tagFileInfo * const info){ fpos_t startOfLine; const size_t prefixLength = strlen(PseudoTagPrefix); if (info != NULL) { info->file.format = 1; info->file.sort = TAG_UNSORTED;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -