📄 main.c
字号:
sprintf(filePath, "%s%c%s", path, PATH_SEPARATOR, file);
#else
if ((path[strlen(path) - 1]) == PATH_SEPARATOR)
sprintf(filePath, "%s%s", path, file);
else
sprintf(filePath, "%s%c%s", path, PATH_SEPARATOR, file);
#endif
}
/*----------------------------------------------------------------------------
* File extension and language handling
*--------------------------------------------------------------------------*/
static const char *findExtension( fileName )
const char *const fileName;
{
const char *extension;
const char *const start = strrchr(fileName, '.'); /* find last '.' */
if (start == NULL)
extension = "";
else
extension = start + 1; /* skip to character after '.' */
return extension;
}
/* Determines whether the specified file name is considered to be a header
* file for the purposes of determining whether enclosed tags are global or
* static.
*/
static boolean isFileHeader( fileName )
const char *const fileName;
{
const char *const extension = findExtension(fileName);
boolean header = FALSE; /* default unless match found */
int i;
for (i = 0 ; Option.headerExt[i] != NULL ; ++i)
{
if (strcmp(Option.headerExt[i], extension) == 0)
{
header = TRUE; /* found in list */
break;
}
}
return header;
}
static boolean isExtensionInList( extension, list )
const char *const extension;
const char *const *const list;
{
boolean isKnown = FALSE;
if (list != NULL)
{
const char *const *pExtension = list;
while (! isKnown && *pExtension != NULL)
{
#if defined(MSDOS) || defined(WIN32) || defined(OS2)
if (strequiv(extension, *pExtension))
#else
if (strcmp(extension, *pExtension) == 0)
#endif
isKnown = TRUE;
++pExtension;
}
}
return isKnown;
}
static langType getExtensionLanguage( extension )
const char *const extension;
{
unsigned int i;
langType language = LANG_IGNORE;
for (i = 0 ; i < (int)LANG_COUNT ; ++i)
{
if (isExtensionInList(extension, Option.langMap[i]))
{
language = (langType)i;
break;
}
}
return language;
}
static langType getFileLanguage( fileName )
const char *const fileName;
{
const char *const extension = findExtension(fileName);
langType language;
if (Option.language != LANG_AUTO)
language = Option.language;
else if (isFileHeader(fileName))
language = LANG_CPP;
else if (extension[0] == '\0')
language = LANG_IGNORE; /* ignore files with no extension */
else
language = getExtensionLanguage(extension);
return language;
}
/*----------------------------------------------------------------------------
* Tag file management
*--------------------------------------------------------------------------*/
static boolean isValidTagAddress( excmd )
const char *const excmd;
{
boolean isValid = FALSE;
if (strchr("/?", excmd[0]) != NULL)
isValid = TRUE;
else
{
char *address = (char *)malloc(strlen(excmd) + 1);
if (address != NULL)
{
if (sscanf(excmd, "%[^;\n]", address) == 1 &&
strspn(address,"0123456789") == strlen(address))
isValid = TRUE;
free(address);
}
}
return isValid;
}
static boolean isCtagsLine( line )
const char *const line;
{
enum fieldList { TAG, TAB1, SRC_FILE, TAB2, EXCMD, NUM_FIELDS };
boolean ok = FALSE; /* we assume not unless confirmed */
const size_t fieldLength = strlen(line) + 1;
char *const fields = (char *)malloc((size_t)NUM_FIELDS * fieldLength);
if (fields == NULL)
error(FATAL, "Cannot analyze tag file");
else
{
#define field(x) (fields + ((size_t)(x) * fieldLength))
const int numFields = sscanf(line, "%[^\t]%[\t]%[^\t]%[\t]%[^\n]",
field(TAG), field(TAB1), field(SRC_FILE),
field(TAB2), field(EXCMD));
/* There must be exactly five fields: two tab fields containing
* exactly one tab each, the tag must not begin with "#", and the
* file name should not end with ";", and the excmd must be
* accceptable.
*
* These conditions will reject tag-looking lines like:
* int a; <C-comment>
* #define LABEL <C-comment>
*/
if (numFields == NUM_FIELDS &&
strlen(field(TAB1)) == 1 &&
strlen(field(TAB2)) == 1 &&
field(TAG)[0] != '#' &&
field(SRC_FILE)[strlen(field(SRC_FILE)) - 1] != ';' &&
isValidTagAddress(field(EXCMD)))
ok = TRUE;
free(fields);
}
return ok;
}
static boolean isEtagsLine( line )
const char *const line;
{
const char *const magic = "\f\n";
return (boolean)(strncmp(line, magic, strlen(magic)) == 0);
}
static boolean isTagFile( filename )
const char *const filename;
{
boolean ok = FALSE; /* we assume not unless confirmed */
FILE *const fp = fopen(filename, "r");
if (fp == NULL && errno == ENOENT)
ok = TRUE;
else if (fp != NULL)
{
const char *line = readLine(&TagFile.line, fp);
if (line == NULL)
ok = TRUE;
else if (Option.etags) /* check for etags magic number */
ok = isEtagsLine(line);
else
ok = isCtagsLine(line);
fclose(fp);
}
return ok;
}
static void openTagFile( toStdout )
const boolean toStdout;
{
static char tempName[L_tmpnam];
/* Open the tags File.
*/
if (toStdout)
{
TagFile.name = tmpnam(tempName);
TagFile.fp = fopen(TagFile.name, "w");
}
else
{
const char *const fname = Option.tagFileName;
const boolean fileExists = doesFileExist(fname);
TagFile.name = fname;
if (fileExists && ! isTagFile(fname))
error(FATAL,
"\"%s\" doesn't look like a tag file; I refuse to overwrite it.",
fname);
if (Option.append && fileExists)
{
TagFile.fp = fopen(fname, "r+");
if (TagFile.fp != NULL)
{
TagFile.numTags.prev = updatePseudoTags();
fseek(TagFile.fp, 0L, SEEK_END);
}
}
else
{
TagFile.fp = fopen(fname, "w");
if (TagFile.fp != NULL)
addPseudoTags();
}
}
if (TagFile.fp == NULL)
{
error(FATAL | PERROR, "cannot open tag file");
exit(1);
}
}
#ifdef USE_REPLACEMENT_TRUNCATE
static int copyChars __ARGS((FILE *const fpFrom, FILE *const fpTo, const off_t size));
static int copyFile __ARGS((const char *const from, const char *const to, const off_t size));
static int replacementTruncate __ARGS((const char *const name, const off_t size));
static int copyChars( fpFrom, fpTo, size )
FILE *const fpFrom;
FILE *const fpTo;
const off_t size;
{
off_t count;
int result = -1;
for (count = 0 ; count < size ; ++count)
{
const int c = getc(fpFrom);
if (c == EOF || putc(c, fpTo) == EOF)
break;
}
if (count == size)
result = 0;
return result;
}
static int copyFile( from, to, size )
const char *const from;
const char *const to;
const off_t size;
{
int result = -1;
FILE *const fpFrom = fopen(from, "r");
if (fpFrom != NULL)
{
FILE *const fpTo = fopen(to, "w");
if (fpFrom != NULL)
{
result = copyChars(fpFrom, fpTo, size);
if (result == 0)
result = fclose(fpTo);
}
if (result == 0)
result = fclose(fpFrom);
}
return result;
}
/* Replacement for missing library function.
*/
static int replacementTruncate( name, size )
const char *const name;
const off_t size;
{
char tempName[L_tmpnam];
int result = -1;
if (tmpnam(tempName) != NULL)
{
result = copyFile(name, tempName, size);
if (result == 0)
result = copyFile(tempName, name, size);
if (result == 0)
result = remove(tempName);
}
return result;
}
#endif
static void closeTagFile( resize )
const boolean resize;
{
const long __unused__ size = ftell(TagFile.fp);
fclose(TagFile.fp);
if (resize)
{
int __unused__ result = 0;
#ifdef USE_REPLACEMENT_TRUNCATE
result = replacementTruncate(TagFile.name, (off_t)size);
#else
# ifdef HAVE_TRUNCATE
result = truncate(TagFile.name, (off_t)size);
# else
const int fd = open(TagFile.name, O_RDWR);
if (fd != -1)
{
# ifdef HAVE_FTRUNCATE
result = ftruncate(fd, (off_t)size);
# else
# ifdef HAVE_CHSIZE
result = chsize(fd, size);
# endif
# endif
close(fd);
}
# endif
#endif
if (result == -1)
fprintf(errout, "Cannot shorten tag file: errno = %d\n", errno);
}
}
/*----------------------------------------------------------------------------
* Create tags
*--------------------------------------------------------------------------*/
static void beginEtagsFile()
{
tmpnam(TagFile.etags.name);
TagFile.etags.fp = fopen(TagFile.etags.name, "w+b");
if (TagFile.etags.fp == NULL)
error(FATAL | PERROR, "cannot open \"%s\"", TagFile.etags.name);
TagFile.etags.byteCount = 0;
}
static void endEtagsFile( name )
const char *const name;
{
const char *line;
fprintf(TagFile.fp, "\f\n%s,%ld\n", name, (long)TagFile.etags.byteCount);
if (TagFile.etags.fp != NULL)
{
rewind(TagFile.etags.fp);
while ((line = readLine(&TagFile.line, TagFile.etags.fp)) != NULL)
fputs(line, TagFile.fp);
fclose(TagFile.etags.fp);
remove(TagFile.etags.name);
}
TagFile.etags.name[0] = '\0';
}
static boolean createTagsForFile( filePath, language )
const char *const filePath;
const langType language;
{
boolean ok;
if (filePath == NULL)
ok = FALSE;
else
{
const boolean isHeader = isFileHeader(filePath);
ok = TRUE;
if (Option.etags)
beginEtagsFile();
if (cppOpen(filePath, language, isHeader))
{
tagInfo tag;
DebugStatement( clearString(tag.name, MaxNameLength); )
strcpy(tag.name, baseFilename(filePath));
tag.location = 0;
tag.lineNumber = 1;
makeTag(&tag, &NoClass, SCOPE_GLOBAL, TAG_SOURCE_FILE);
ok = createTags(0, NULL);
cppClose();
}
if (Option.etags)
endEtagsFile(filePath);
}
return ok;
}
static const char *getNextListFile( fp )
FILE *const fp;
{
static char fileName[PATH_MAX + 1];
const char *const buf = fgets(fileName, PATH_MAX + 1, fp);
if (buf != NULL)
{
char *const newline = strchr(fileName, '\n');
if (newline == NULL)
fileName[PATH_MAX] = '\0';
else
*newline = '\0';
}
return buf;
}
static const char *sourceFilePath( file )
const char *const file;
{
const char *result = NULL;
if (Option.path == NULL || isAbsolutePath(file))
result = file;
else if (strlen(Option.path) + strlen(file) < (size_t)PATH_MAX)
{
static char filePath[PATH_MAX + 1];
combinePathAndFile(filePath, Option.path, file);
result = filePath;
}
return result;
}
static boolean createTagsWithFallback( fileName, language )
const char *const fileName;
const langType language;
{
const char *const filePath = sourceFilePath(fileName);
const unsigned long numTags = TagFile.numTags.added;
const long tagFilePosition = ftell(TagFile.fp);
boolean resize = FALSE;
if (! createTagsForFile(filePath, language))
{
/* Restore prior state of tag file.
*/
fseek(TagFile.fp, tagFilePosition, SEEK_SET);
TagFile.numTags.added = numTags;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -