📄 entry.c
字号:
/** $Id: entry.c,v 1.11 2006/05/30 04:37:12 darren Exp $** Copyright (c) 1996-2002, Darren Hiebert** This source code is released for free distribution under the terms of the* GNU General Public License.** This module contains functions for creating tag entries.*//** INCLUDE FILES*/#include "general.h" /* must always come first */#include <string.h>#include <ctype.h> /* to define isspace () */#include <errno.h>#if defined (HAVE_SYS_TYPES_H)# include <sys/types.h> /* to declare off_t on some hosts */#endif#if defined (HAVE_TYPES_H)# include <types.h> /* to declare off_t on some hosts */#endif#if defined (HAVE_UNISTD_H)# include <unistd.h> /* to declare close (), ftruncate (), truncate () */#endif/* These header files provide for the functions necessary to do file * truncation. */#ifdef HAVE_FCNTL_H# include <fcntl.h>#endif#ifdef HAVE_IO_H# include <io.h>#endif#include "debug.h"#include "ctags.h"#include "entry.h"#include "main.h"#include "options.h"#include "read.h"#include "routines.h"#include "sort.h"#include "strlist.h"/** MACROS*/#define PSEUDO_TAG_PREFIX "!_"#define includeExtensionFlags() (Option.tagFileFormat > 1)/* * Portability defines */#if !defined(HAVE_TRUNCATE) && !defined(HAVE_FTRUNCATE) && !defined(HAVE_CHSIZE)# define USE_REPLACEMENT_TRUNCATE#endif/* Hack for rediculous practice of Microsoft Visual C++. */#if defined (WIN32) && defined (_MSC_VER)# define chsize _chsize# define open _open# define close _close# define O_RDWR _O_RDWR#endif/** DATA DEFINITIONS*/tagFile TagFile = { NULL, /* tag file name */ NULL, /* tag file directory (absolute) */ NULL, /* file pointer */ { 0, 0 }, /* numTags */ { 0, 0, 0 }, /* max */ { NULL, NULL, 0 }, /* etags */ NULL /* vLine */};static boolean TagsToStdout = FALSE;/** FUNCTION PROTOTYPES*/#ifdef NEED_PROTO_TRUNCATEextern int truncate (const char *path, off_t length);#endif#ifdef NEED_PROTO_FTRUNCATEextern int ftruncate (int fd, off_t length);#endif/** FUNCTION DEFINITIONS*/extern void freeTagFileResources (void){ if (TagFile.directory != NULL) eFree (TagFile.directory); vStringDelete (TagFile.vLine);}extern const char *tagFileName (void){ return TagFile.name;}/** Pseudo tag support*/static void rememberMaxLengths (const size_t nameLength, const size_t lineLength){ if (nameLength > TagFile.max.tag) TagFile.max.tag = nameLength; if (lineLength > TagFile.max.line) TagFile.max.line = lineLength;}static void writePseudoTag ( const char *const tagName, const char *const fileName, const char *const pattern){ const int length = fprintf ( TagFile.fp, "%s%s\t%s\t/%s/\n", PSEUDO_TAG_PREFIX, tagName, fileName, pattern); ++TagFile.numTags.added; rememberMaxLengths (strlen (tagName), (size_t) length);}static void addPseudoTags (void){ if (! Option.xref) { char format [11]; const char *formatComment = "unknown format"; sprintf (format, "%u", Option.tagFileFormat); if (Option.tagFileFormat == 1) formatComment = "original ctags format"; else if (Option.tagFileFormat == 2) formatComment = "extended format; --format=1 will not append ;\" to lines"; writePseudoTag ("TAG_FILE_FORMAT", format, formatComment); writePseudoTag ("TAG_FILE_SORTED", Option.sorted == SO_FOLDSORTED ? "2" : (Option.sorted == SO_SORTED ? "1" : "0"), "0=unsorted, 1=sorted, 2=foldcase"); writePseudoTag ("TAG_PROGRAM_AUTHOR", AUTHOR_NAME, AUTHOR_EMAIL); writePseudoTag ("TAG_PROGRAM_NAME", PROGRAM_NAME, ""); writePseudoTag ("TAG_PROGRAM_URL", PROGRAM_URL, "official site"); writePseudoTag ("TAG_PROGRAM_VERSION", PROGRAM_VERSION, ""); }}static void updateSortedFlag ( const char *const line, FILE *const fp, fpos_t startOfLine){ const char *const tab = strchr (line, '\t'); if (tab != NULL) { const long boolOffset = tab - line + 1; /* where it should be */ if (line [boolOffset] == '0' || line [boolOffset] == '1') { fpos_t nextLine; if (fgetpos (fp, &nextLine) == -1 || fsetpos (fp, &startOfLine) == -1) error (WARNING, "Failed to update 'sorted' pseudo-tag"); else { fpos_t flagLocation; int c, d; do c = fgetc (fp); while (c != '\t' && c != '\n'); fgetpos (fp, &flagLocation); d = fgetc (fp); if (c == '\t' && (d == '0' || d == '1') && d != (int) Option.sorted) { fsetpos (fp, &flagLocation); fputc (Option.sorted == SO_FOLDSORTED ? '2' : (Option.sorted == SO_SORTED ? '1' : '0'), fp); } fsetpos (fp, &nextLine); } } }}/* Look through all line beginning with "!_TAG_FILE", and update those which * require it. */static long unsigned int updatePseudoTags (FILE *const fp){ enum { maxEntryLength = 20 }; char entry [maxEntryLength + 1]; unsigned long linesRead = 0; fpos_t startOfLine; size_t entryLength; const char *line; sprintf (entry, "%sTAG_FILE", PSEUDO_TAG_PREFIX); entryLength = strlen (entry); Assert (entryLength < maxEntryLength); fgetpos (fp, &startOfLine); line = readLine (TagFile.vLine, fp); while (line != NULL && line [0] == entry [0]) { ++linesRead; if (strncmp (line, entry, entryLength) == 0) { char tab, classType [16]; if (sscanf (line + entryLength, "%15s%c", classType, &tab) == 2 && tab == '\t') { if (strcmp (classType, "_SORTED") == 0) updateSortedFlag (line, fp, startOfLine); } fgetpos (fp, &startOfLine); } line = readLine (TagFile.vLine, fp); } while (line != NULL) /* skip to end of file */ { ++linesRead; line = readLine (TagFile.vLine, fp); } return linesRead;}/* * Tag file management */static boolean isValidTagAddress (const char *const excmd){ boolean isValid = FALSE; if (strchr ("/?", excmd [0]) != NULL) isValid = TRUE; else { char *address = xMalloc (strlen (excmd) + 1, char); if (sscanf (excmd, "%[^;\n]", address) == 1 && strspn (address,"0123456789") == strlen (address)) isValid = TRUE; eFree (address); } return isValid;}static boolean isCtagsLine (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 = xMalloc (NUM_FIELDS * fieldLength, char); 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]%[^\r\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; eFree (fields); } return ok;}static boolean isEtagsLine (const char *const line){ boolean result = FALSE; if (line [0] == '\f') result = (boolean) (line [1] == '\n' || line [1] == '\r'); return result;}static boolean isTagFile (const char *const filename){ boolean ok = FALSE; /* we assume not unless confirmed */ FILE *const fp = fopen (filename, "rb"); if (fp == NULL && errno == ENOENT) ok = TRUE; else if (fp != NULL) { const char *line = readLine (TagFile.vLine, fp); if (line == NULL) ok = TRUE; else ok = (boolean) (isCtagsLine (line) || isEtagsLine (line)); fclose (fp); } return ok;}extern void copyBytes (FILE* const fromFp, FILE* const toFp, const long size){ enum { BufferSize = 1000 }; long toRead, numRead; char* buffer = xMalloc (BufferSize, char); long remaining = size; do { toRead = (0 < remaining && remaining < BufferSize) ? remaining : (long) BufferSize; numRead = fread (buffer, (size_t) 1, (size_t) toRead, fromFp); if (fwrite (buffer, (size_t)1, (size_t)numRead, toFp) < (size_t)numRead) error (FATAL | PERROR, "cannot complete write"); if (remaining > 0) remaining -= numRead; } while (numRead == toRead && remaining != 0); eFree (buffer);}extern void copyFile (const char *const from, const char *const to, const long size){ FILE* const fromFp = fopen (from, "rb"); if (fromFp == NULL) error (FATAL | PERROR, "cannot open file to copy"); else { FILE* const toFp = fopen (to, "wb"); if (toFp == NULL) error (FATAL | PERROR, "cannot open copy destination"); else { copyBytes (fromFp, toFp, size); fclose (toFp); } fclose (fromFp); }}extern void openTagFile (void){ setDefaultTagFileName (); TagsToStdout = isDestinationStdout (); if (TagFile.vLine == NULL) TagFile.vLine = vStringNew (); /* Open the tags file. */ if (TagsToStdout) TagFile.fp = tempFile ("w", &TagFile.name); else { boolean fileExists; setDefaultTagFileName (); TagFile.name = eStrdup (Option.tagFileName); fileExists = doesFileExist (TagFile.name); if (fileExists && ! isTagFile (TagFile.name)) error (FATAL, "\"%s\" doesn't look like a tag file; I refuse to overwrite it.", TagFile.name); if (Option.etags) { if (Option.append && fileExists) TagFile.fp = fopen (TagFile.name, "a+b"); else TagFile.fp = fopen (TagFile.name, "w+b"); } else { if (Option.append && fileExists) { TagFile.fp = fopen (TagFile.name, "r+"); if (TagFile.fp != NULL) { TagFile.numTags.prev = updatePseudoTags (TagFile.fp); fclose (TagFile.fp); TagFile.fp = fopen (TagFile.name, "a+"); } } else { TagFile.fp = fopen (TagFile.name, "w"); if (TagFile.fp != NULL) addPseudoTags ();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -