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

📄 main.c

📁 Exuberant Ctags is a multilanguage reimplementation of the much-underused ctags(1) program and is i
💻 C
字号:
/**   $Id: main.c,v 1.24 2006/05/30 04:37:12 darren Exp $**   Copyright (c) 1996-2003, Darren Hiebert**   Author: Darren Hiebert <dhiebert@users.sourceforge.net>*           http://ctags.sourceforge.net**   This source code is released for free distribution under the terms of the*   GNU General Public License. It is provided on an as-is basis and no*   responsibility is accepted for its failure to perform as expected.**   This is a reimplementation of the ctags (1) program. It is an attempt to*   provide a fully featured ctags program which is free of the limitations*   which most (all?) others are subject to.**   This module contains the start-up code and routines to determine the list*   of files to parsed for tags.*//**   INCLUDE FILES*/#include "general.h"  /* must always come first */#include <string.h>/*  To provide timings features if available. */#ifdef HAVE_CLOCK# ifdef HAVE_TIME_H#  include <time.h># endif#else# ifdef HAVE_TIMES#  ifdef HAVE_SYS_TIMES_H#   include <sys/times.h>#  endif# endif#endif/*  To provide directory searching for recursion feature. */#ifdef AMIGA# include <dos/dosasl.h>       /* for struct AnchorPath */# include <clib/dos_protos.h>  /* function prototypes */# define ANCHOR_BUF_SIZE 512# define ANCHOR_SIZE (sizeof (struct AnchorPath) + ANCHOR_BUF_SIZE)# ifdef __SASC   extern struct DosLibrary *DOSBase;#  include <pragmas/dos_pragmas.h># endif#endif#ifdef HAVE_DIRENT_H# ifdef __BORLANDC__#  define boolean BORLAND_boolean# endif# ifdef HAVE_SYS_TYPES_H#  include <sys/types.h>  /* required by dirent.h */# endif# include <dirent.h>  /* to declare opendir() */# undef boolean#endif#ifdef HAVE_DIRECT_H# include <direct.h>  /* to _getcwd() */#endif#ifdef HAVE_DOS_H# include <dos.h>  /* to declare FA_DIREC */#endif#ifdef HAVE_DIR_H# include <dir.h>  /* to declare findfirst() and findnext */#endif#ifdef HAVE_IO_H# include <io.h>  /* to declare _findfirst() */#endif#include "debug.h"#include "keyword.h"#include "main.h"#include "options.h"#include "read.h"#include "routines.h"/**   MACROS*/#define plural(value)  (((unsigned long)(value) == 1L) ? "" : "s")/**   DATA DEFINITIONS*/static struct { long files, lines, bytes; } Totals = { 0, 0, 0 };#ifdef AMIGA# include "ctags.h"  static const char *VERsion = "$VER: "PROGRAM_NAME" "PROGRAM_VERSION" "# ifdef __SASC  __AMIGADATE__# else  __DATE__# endif  " "AUTHOR_NAME" $";#endif/**   FUNCTION PROTOTYPES*/static boolean createTagsForEntry (const char *const entryName);/**   FUNCTION DEFINITIONS*/extern void addTotals (		const unsigned int files, const long unsigned int lines,		const long unsigned int bytes){	Totals.files += files;	Totals.lines += lines;	Totals.bytes += bytes;}extern boolean isDestinationStdout (void){	boolean toStdout = FALSE;	if (Option.xref  ||  Option.filter  ||		(Option.tagFileName != NULL  &&  (strcmp (Option.tagFileName, "-") == 0#if defined (VMS)	|| strcmp (Option.tagFileName, "sys$output") == 0#else	|| strcmp (Option.tagFileName, "/dev/stdout") == 0#endif		)))		toStdout = TRUE;	return toStdout;}#if defined (HAVE_OPENDIR)static boolean recurseUsingOpendir (const char *const dirName){	boolean resize = FALSE;	DIR *const dir = opendir (dirName);	if (dir == NULL)		error (WARNING | PERROR, "cannot recurse into directory \"%s\"", dirName);	else	{		struct dirent *entry;		while ((entry = readdir (dir)) != NULL)		{			if (strcmp (entry->d_name, ".") != 0  &&				strcmp (entry->d_name, "..") != 0)			{				vString *filePath;				if (strcmp (dirName, ".") == 0)					filePath = vStringNewInit (entry->d_name);				else					filePath = combinePathAndFile (dirName, entry->d_name);				resize |= createTagsForEntry (vStringValue (filePath));				vStringDelete (filePath);			}		}		closedir (dir);	}	return resize;}#elif defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)static boolean createTagsForWildcardEntry (		const char *const pattern, const size_t dirLength,		const char *const entryName){	boolean resize = FALSE;	/* we must not recurse into the directories "." or ".." */	if (strcmp (entryName, ".") != 0  &&  strcmp (entryName, "..") != 0)	{		vString *const filePath = vStringNew ();		vStringNCopyS (filePath, pattern, dirLength);		vStringCatS (filePath, entryName);		resize = createTagsForEntry (vStringValue (filePath));		vStringDelete (filePath);	}	return resize;}static boolean createTagsForWildcardUsingFindfirst (const char *const pattern){	boolean resize = FALSE;	const size_t dirLength = baseFilename (pattern) - pattern;#if defined (HAVE_FINDFIRST)	struct ffblk fileInfo;	int result = findfirst (pattern, &fileInfo, FA_DIREC);	while (result == 0)	{		const char *const entry = (const char *) fileInfo.ff_name;		resize |= createTagsForWildcardEntry (pattern, dirLength, entry);		result = findnext (&fileInfo);	}#elif defined (HAVE__FINDFIRST)	struct _finddata_t fileInfo;	findfirst_t hFile = _findfirst (pattern, &fileInfo);	if (hFile != -1L)	{		do		{			const char *const entry = (const char *) fileInfo.name;			resize |= createTagsForWildcardEntry (pattern, dirLength, entry);		} while (_findnext (hFile, &fileInfo) == 0);		_findclose (hFile);	}#endif	return resize;}#elif defined (AMIGA)static boolean createTagsForAmigaWildcard (const char *const pattern){	boolean resize = FALSE;	struct AnchorPath *const anchor =			(struct AnchorPath *) eMalloc ((size_t) ANCHOR_SIZE);	LONG result;	memset (anchor, 0, (size_t) ANCHOR_SIZE);	anchor->ap_Strlen = ANCHOR_BUF_SIZE;	/* Allow '.' for current directory */#ifdef APF_DODOT	anchor->ap_Flags = APF_DODOT | APF_DOWILD;#else	anchor->ap_Flags = APF_DoDot | APF_DoWild;#endif	result = MatchFirst ((UBYTE *) pattern, anchor);	while (result == 0)	{		resize |= createTagsForEntry ((char *) anchor->ap_Buf);		result = MatchNext (anchor);	}	MatchEnd (anchor);	eFree (anchor);	return resize;}#endifstatic boolean recurseIntoDirectory (const char *const dirName){	boolean resize = FALSE;	if (isRecursiveLink (dirName))		verbose ("ignoring \"%s\" (recursive link)\n", dirName);	else if (! Option.recurse)		verbose ("ignoring \"%s\" (directory)\n", dirName);	else	{		verbose ("RECURSING into directory \"%s\"\n", dirName);#if defined (HAVE_OPENDIR)		resize = recurseUsingOpendir (dirName);#elif defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)		{			vString *const pattern = vStringNew ();			vStringCopyS (pattern, dirName);			vStringPut (pattern, OUTPUT_PATH_SEPARATOR);			vStringCatS (pattern, "*.*");			resize = createTagsForWildcardUsingFindfirst (vStringValue (pattern));			vStringDelete (pattern);		}#elif defined (AMIGA)		{			vString *const pattern = vStringNew ();			if (*dirName != '\0'  &&  strcmp (dirName, ".") != 0)			{				vStringCopyS (pattern, dirName);				if (dirName [strlen (dirName) - 1] != '/')					vStringPut (pattern, '/');			}			vStringCatS (pattern, "#?");			resize = createTagsForAmigaWildcard (vStringValue (pattern));			vStringDelete (pattern);		}#endif	}	return resize;}static boolean createTagsForEntry (const char *const entryName){	boolean resize = FALSE;	fileStatus *status = eStat (entryName);	Assert (entryName != NULL);	if (isExcludedFile (entryName))		verbose ("excluding \"%s\"\n", entryName);	else if (status->isSymbolicLink  &&  ! Option.followLinks)		verbose ("ignoring \"%s\" (symbolic link)\n", entryName);	else if (! status->exists)		error (WARNING | PERROR, "cannot open source file \"%s\"", entryName);	else if (status->isDirectory)		resize = recurseIntoDirectory (entryName);	else if (! status->isNormalFile)		verbose ("ignoring \"%s\" (special file)\n", entryName);	else		resize = parseFile (entryName);	return resize;}#ifdef MANUAL_GLOBBINGstatic boolean createTagsForWildcardArg (const char *const arg){	boolean resize = FALSE;	vString *const pattern = vStringNewInit (arg);	char *patternS = vStringValue (pattern);#if defined (HAVE_FINDFIRST) || defined (HAVE__FINDFIRST)	/*  We must transform the "." and ".." forms into something that can	 *  be expanded by the findfirst/_findfirst functions.	 */	if (Option.recurse  &&		(strcmp (patternS, ".") == 0  ||  strcmp (patternS, "..") == 0))	{		vStringPut (pattern, OUTPUT_PATH_SEPARATOR);		vStringCatS (pattern, "*.*");	}	resize |= createTagsForWildcardUsingFindfirst (patternS);#endif	vStringDelete (pattern);	return resize;}#endifstatic boolean createTagsForArgs (cookedArgs *const args){	boolean resize = FALSE;	/*  Generate tags for each argument on the command line.	 */	while (! cArgOff (args))	{		const char *const arg = cArgItem (args);#ifdef MANUAL_GLOBBING		resize |= createTagsForWildcardArg (arg);#else		resize |= createTagsForEntry (arg);#endif		cArgForth (args);		parseOptions (args);	}	return resize;}/*  Read from an opened file a list of file names for which to generate tags. */static boolean createTagsFromFileInput (FILE *const fp, const boolean filter){	boolean resize = FALSE;	if (fp != NULL)	{		cookedArgs *args = cArgNewFromLineFile (fp);		parseOptions (args);		while (! cArgOff (args))		{			resize |= createTagsForEntry (cArgItem (args));			if (filter)			{				if (Option.filterTerminator != NULL)					fputs (Option.filterTerminator, stdout);				fflush (stdout);			}			cArgForth (args);			parseOptions (args);		}		cArgDelete (args);	}	return resize;}/*  Read from a named file a list of file names for which to generate tags. */static boolean createTagsFromListFile (const char *const fileName){	boolean resize;	Assert (fileName != NULL);	if (strcmp (fileName, "-") == 0)		resize = createTagsFromFileInput (stdin, FALSE);	else	{		FILE *const fp = fopen (fileName, "r");		if (fp == NULL)			error (FATAL | PERROR, "cannot open list file \"%s\"", fileName);		resize = createTagsFromFileInput (fp, FALSE);		fclose (fp);	}	return resize;}#if defined (HAVE_CLOCK)# define CLOCK_AVAILABLE# ifndef CLOCKS_PER_SEC#  define CLOCKS_PER_SEC		1000000# endif#elif defined (HAVE_TIMES)# define CLOCK_AVAILABLE# define CLOCKS_PER_SEC	60static clock_t clock (void){	struct tms buf;	times (&buf);	return (buf.tms_utime + buf.tms_stime);}#else# define clock()  (clock_t)0#endifstatic void printTotals (const clock_t *const timeStamps){	const unsigned long totalTags = TagFile.numTags.added +									TagFile.numTags.prev;	fprintf (errout, "%ld file%s, %ld line%s (%ld kB) scanned",			Totals.files, plural (Totals.files),			Totals.lines, plural (Totals.lines),			Totals.bytes/1024L);#ifdef CLOCK_AVAILABLE	{		const double interval = ((double) (timeStamps [1] - timeStamps [0])) /								CLOCKS_PER_SEC;		fprintf (errout, " in %.01f seconds", interval);		if (interval != (double) 0.0)			fprintf (errout, " (%lu kB/s)",					(unsigned long) (Totals.bytes / interval) / 1024L);	}#endif	fputc ('\n', errout);	fprintf (errout, "%lu tag%s added to tag file",			TagFile.numTags.added, plural (TagFile.numTags.added));	if (Option.append)		fprintf (errout, " (now %lu tags)", totalTags);	fputc ('\n', errout);	if (totalTags > 0  &&  Option.sorted != SO_UNSORTED)	{		fprintf (errout, "%lu tag%s sorted", totalTags, plural (totalTags));#ifdef CLOCK_AVAILABLE		fprintf (errout, " in %.02f seconds",				((double) (timeStamps [2] - timeStamps [1])) / CLOCKS_PER_SEC);#endif		fputc ('\n', errout);	}#ifdef DEBUG	fprintf (errout, "longest tag line = %lu\n",			(unsigned long) TagFile.max.line);#endif}static boolean etagsInclude (void){	return (boolean)(Option.etags && Option.etagsInclude != NULL);}static void makeTags (cookedArgs *args){	clock_t timeStamps [3];	boolean resize = FALSE;	boolean files = (boolean)(! cArgOff (args) || Option.fileList != NULL							  || Option.filter);	if (! files)	{		if (filesRequired ())			error (FATAL, "No files specified. Try \"%s --help\".",				getExecutableName ());		else if (! Option.recurse && ! etagsInclude ())			return;	}#define timeStamp(n) timeStamps[(n)]=(Option.printTotals ? clock():(clock_t)0)	if (! Option.filter)		openTagFile ();	timeStamp (0);	if (! cArgOff (args))	{		verbose ("Reading command line arguments\n");		resize = createTagsForArgs (args);	}	if (Option.fileList != NULL)	{		verbose ("Reading list file\n");		resize = (boolean) (createTagsFromListFile (Option.fileList) || resize);	}	if (Option.filter)	{		verbose ("Reading filter input\n");		resize = (boolean) (createTagsFromFileInput (stdin, TRUE) || resize);	}	if (! files  &&  Option.recurse)		resize = recurseIntoDirectory (".");	timeStamp (1);	if (! Option.filter)		closeTagFile (resize);	timeStamp (2);	if (Option.printTotals)		printTotals (timeStamps);#undef timeStamp}/* *		Start up code */extern int main (int __unused__ argc, char **argv){	cookedArgs *args;#ifdef VMS	extern int getredirection (int *ac, char ***av);	/* do wildcard expansion and I/O redirection */	getredirection (&argc, &argv);#endif#ifdef AMIGA	/* This program doesn't work when started from the Workbench */	if (argc == 0)		exit (1);#endif#ifdef __EMX__	_wildcard (&argc, &argv);  /* expand wildcards in argument list */#endif#if defined (macintosh) && BUILD_MPW_TOOL == 0	argc = ccommand (&argv);#endif	setCurrentDirectory ();	setExecutableName (*argv++);	checkRegex ();	args = cArgNewFromArgv (argv);	previewFirstOption (args);	testEtagsInvocation ();	initializeParsing ();	initOptions ();	readOptionConfiguration ();	verbose ("Reading initial options from command line\n");	parseOptions (args);	checkOptions ();	makeTags (args);	/*  Clean up.	 */	cArgDelete (args);	freeKeywordTable ();	freeRoutineResources ();	freeSourceFileResources ();	freeTagFileResources ();	freeOptionResources ();	freeParserResources ();	freeRegexResources ();	exit (0);	return 0;}/* vi:set tabstop=4 shiftwidth=4: */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -