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

📄 entry.c

📁 Exuberant Ctags is a multilanguage reimplementation of the much-underused ctags(1) program and is i
💻 C
📖 第 1 页 / 共 2 页
字号:
/**   $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 + -