📄 main.c
字号:
/*****************************************************************************
* $Id: main.c,v 6.23 1998/08/18 04:26:50 darren Exp $
*
* Copyright (c) 1996-1998, Darren Hiebert
*
* Author: Darren Hiebert <darren@hiebert.com>, <darren@hiwaay.net>
* http://darren.hiebert.com
*
* 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.
*
* It is derived from and inspired by the ctags program by Steve Kirkendall
* (kirkenda@cs.pdx.edu) that comes with the Elvis vi clone (though almost
* none of the original code remains). This, too, was freely available.
*
* This program provides the following features:
*
* Support for both K&R style and new ANSI style function definitions.
*
* Generates tags for the following objects:
* - macro definitions
* - enumeration values
* - function definitions (and C++ methods)
* - function declarations (optional)
* - enum, struct and union tags and C++ class names
* - typedefs
* - variables
*
* This module contains top level start-up and portability functions.
*****************************************************************************/
/*============================================================================
= Include files
============================================================================*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined(__STDC__) || defined(MSDOS) || defined(WIN32) || defined(OS2)
# define ENABLE_STDARG
#endif
#if defined(MSDOS) || defined(WIN32)
# define HAVE_DOS_H
# define HAVE_IO_H
# define HAVE_TIME_H
# define HAVE_CLOCK
# define HAVE_CHSIZE
# define HAVE_STRERROR
# define HAVE_FINDNEXT
# ifdef __BORLANDC__
# define HAVE_DIR_H
# define HAVE_DIRENT_H
# define HAVE_FINDFIRST
# else
# ifdef _MSC_VER
# define HAVE__FINDFIRST
# endif
# endif
#endif
#ifdef DJGPP
# define HAVE_DIR_H
# define HAVE_UNISTD_H
# define HAVE_FINDFIRST
# define HAVE_TRUNCATE
#endif
#if defined(OS2)
# define HAVE_DIRENT_H
# define HAVE_TIME_H
# define HAVE_IO_H
# define HAVE_CLOCK
# define HAVE_CHSIZE
# define HAVE_OPENDIR
# define HAVE_STRERROR
#endif
#ifdef AMIGA
# define HAVE_TIME_H
# define HAVE_SYS_STAT_H
# define HAVE_CLOCK
# define HAVE_STRERROR
# define PATH_MAX 255
# 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)
#endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h> /* to declare close(), ftruncate(), truncate() */
#endif
#include <errno.h>
#ifdef ENABLE_STDARG
# include <stdarg.h>
#else
# include <varargs.h>
#endif
/* To declare "struct stat" and stat().
*/
#if defined(__MWERKS__) && defined(__MACINTOSH__)
# include <stat.h> /* there is no sys directory on the Mac */
#else
# include <sys/types.h>
# include <sys/stat.h>
#endif
#ifdef HAVE_DIRENT_H
# ifdef __BORLANDC__
# define boolean BORLAND_boolean
# endif
# include <dirent.h>
# undef boolean
#endif
/* These header files provide for the functions necessary to do file
* truncation.
*/
#include <fcntl.h>
#ifdef HAVE_IO_H
# include <io.h>
#endif
#ifdef HAVE_DOS_H
# include <dos.h>
#endif
#ifdef HAVE_DIR_H
# include <dir.h>
#endif
/* To define the maximum path length
*/
#include <limits.h> /* to define PATH_MAX (hopefully) */
#ifndef PATH_MAX
# ifdef MAXNAMLEN
# define PATH_MAX MAXNAMLEN
# endif
#endif
#if !defined(PATH_MAX) && defined(MAXPATH) /* found in Borland C <dir.h> */
# define PATH_MAX MAXPATH
#endif
#ifndef PATH_MAX
# define PATH_MAX 127 /* ultimate fall-back */
#endif
/* 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
#ifdef DEBUG
# include <assert.h>
#endif
#include "ctags.h"
/*============================================================================
= Defines
============================================================================*/
/*----------------------------------------------------------------------------
* Portability defines
*--------------------------------------------------------------------------*/
#if !defined(HAVE_TRUNCATE) && !defined(HAVE_FTRUNCATE) && !defined(HAVE_CHSIZE)
# define USE_REPLACEMENT_TRUNCATE
#endif
#if defined(MSDOS) || defined(WIN32) || defined(OS2)
# define PATH_SEPARATOR '\\'
#else
# define PATH_SEPARATOR '/'
#endif
/* File type tests.
*/
#ifndef S_ISREG
# if defined(S_IFREG) && !defined(AMIGA)
# define S_ISREG(mode) ((mode) & S_IFREG)
# else
# define S_ISREG(mode) TRUE /* assume regular file */
# endif
#endif
#ifndef S_ISLNK
# ifdef S_IFLNK
# define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)
# else
# define S_ISLNK(mode) FALSE /* assume no soft links */
# endif
#endif
#ifndef S_ISDIR
# ifdef S_IFDIR
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
# else
# define S_ISDIR(mode) FALSE /* assume no soft links */
# endif
#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 stat _stat
# define O_RDWR _O_RDWR
#endif
/*----------------------------------------------------------------------------
* Miscellaneous defines
*--------------------------------------------------------------------------*/
#ifndef ETAGS
# define ETAGS "etags" /* name which causes default use of to -e */
#endif
#define selected(var,feature) (((int)(var) & (int)(feature)) == (int)feature)
#define plural(value) (((unsigned long)(value) == 1L) ? "" : "s")
/*============================================================================
= Data definitions
============================================================================*/
#if defined(MSDOS) || defined(WIN32) || defined(OS2)
static const char DosPathDelimiters[] = ":/\\";
#endif
static const char *ExecutableName = NULL;
static struct { long files, lines, bytes; } Totals = { 0, 0, 0 };
tagFile TagFile = {
NULL, /* file name */
NULL, /* file pointer */
{ 0, 0 }, /* numTags */
{ 0, 0, 0 }, /* max */
{ "", NULL }, /* etags */
{ 0, NULL } /* line */
};
memberInfo NoClass = { MEMBER_NONE, VIS_UNDEFINED, FALSE, "" };
/*============================================================================
= Function prototypes
============================================================================*/
#ifdef NEED_PROTO_STAT
extern int stat __ARGS((const char *, struct stat *));
#endif
#ifdef NEED_PROTO_TRUNCATE
extern int truncate __ARGS((const char *path, off_t length));
#endif
#ifdef NEED_PROTO_FTRUNCATE
extern int ftruncate __ARGS((int fd, off_t length));
#endif
static const char *baseFilename __ARGS((const char *const path));
static boolean isAbsolutePath __ARGS((const char *const path));
static void combinePathAndFile __ARGS((char *const filePath, const char *const path, const char *const file));
static const char *findExtension __ARGS((const char *const fileName));
static boolean isFileHeader __ARGS((const char *const FileName));
static boolean isExtensionInList __ARGS((const char *const extension, const char *const *const list));
static langType getExtensionLanguage __ARGS((const char *const extension));
static langType getFileLanguage __ARGS((const char *const FileName));
static boolean isValidTagAddress __ARGS((const char *const tag));
static boolean isCtagsLine __ARGS((const char *const tag));
static boolean isEtagsLine __ARGS((const char *const tag));
static boolean isTagFile __ARGS((const char *const filename));
static void openTagFile __ARGS((const boolean toStdout));
static void closeTagFile __ARGS((const boolean resize));
static void beginEtagsFile __ARGS((void));
static void endEtagsFile __ARGS((const char *const name));
static boolean createTagsForFile __ARGS((const char *const filePath, const langType language));
static const char *getNextListFile __ARGS((FILE *const fp));
static const char *sourceFilePath __ARGS((const char *const file));
static boolean createTagsWithFallback __ARGS((const char *const fileName, const langType language));
static boolean createTagsForDirectory __ARGS((const char *const dirName));
static boolean createTagsForEntry __ARGS((const char *const entryName));
static boolean createTagsForList __ARGS((const char *const listFile));
static boolean createTagsForArgs __ARGS((const char *const *const argList));
static void printTotals __ARGS((const clock_t *const timeStamps));
static void makeTags __ARGS((const char *const *const argList));
static void setExecutableName __ARGS((const char *const path));
static void setDefaultTagFileName __ARGS((void));
static void setOptionDefaults __ARGS((void));
static void testEtagsInvocation __ARGS((void));
extern int main __ARGS((int argc, char **argv));
/*============================================================================
= Function definitions
============================================================================*/
#ifdef ENABLE_STDARG
extern void error( const errorSelection selection,
const char *const format, ... )
#else
extern void error( va_alist )
va_dcl
#endif
{
va_list ap;
#ifdef ENABLE_STDARG
va_start(ap, format);
#else
const char *format;
errorSelection selection;
va_start(ap);
selection = va_arg(ap, errorSelection);
format = va_arg(ap, char *);
#endif
fprintf(errout, "%s: %s", getExecutableName(),
selected(selection, WARNING) ? "warning: " : "");
vfprintf(errout, format, ap);
if (selected(selection, PERROR))
#ifdef HAVE_STRERROR
fprintf(errout, " : %s", strerror(errno));
#else
perror(" ");
#endif
fputs("\n", errout);
va_end(ap);
if (selected(selection, FATAL))
exit(1);
}
extern unsigned long getFileSize( name )
const char *const __unused__ name;
{
struct stat fileStatus;
unsigned long size = 0;
if (stat(name, &fileStatus) == 0)
size = fileStatus.st_size;
return size;
}
extern boolean isNormalFile( name )
const char *const name;
{
struct stat fileStatus;
boolean isNormal = FALSE;
if (stat(name, &fileStatus) == 0)
isNormal = (boolean)(S_ISLNK(fileStatus.st_mode) ||
S_ISREG(fileStatus.st_mode) );
return isNormal;
}
extern boolean isDirectory( name )
const char *const name;
{
boolean isDir = FALSE;
#ifdef AMIGA
struct FileInfoBlock *const fib = (struct FileInfoBlock *)
malloc(sizeof(struct FileInfoBlock));
if (fib != NULL)
{
const BPTR flock = Lock((UBYTE *)name, (long)ACCESS_READ);
if (flock != (BPTR)NULL)
{
if (Examine(flock, fib))
isDir = ((fib->fib_DirEntryType >= 0) ? TRUE : FALSE);
UnLock(flock);
}
free(fib);
}
#else
struct stat fileStatus;
if (stat(name, &fileStatus) == 0)
isDir = (boolean)S_ISDIR(fileStatus.st_mode);
#endif
return isDir;
}
extern boolean doesFileExist( fileName )
const char *const fileName;
{
struct stat fileStatus;
return (boolean)(stat(fileName, &fileStatus) == 0);
}
extern void addTotals( files, lines, bytes )
const unsigned int files;
const unsigned long lines;
const unsigned long bytes;
{
Totals.files += files;
Totals.lines += lines;
Totals.bytes += bytes;
}
/*----------------------------------------------------------------------------
* Pathname manipulation (O/S dependent!!!)
*--------------------------------------------------------------------------*/
static const char *baseFilename( filePath )
const char *const filePath;
{
#if defined(MSDOS) || defined(WIN32) || defined(OS2)
const char *tail = NULL;
unsigned int i;
/* Find whichever of the path delimiters is last.
*/
for (i = 0 ; i < strlen(DosPathDelimiters) ; ++i)
{
const char *sep = strrchr(filePath, DosPathDelimiters[i]);
if (sep > tail)
tail = sep;
}
#else
const char *tail = strrchr(filePath, PATH_SEPARATOR);
#endif
if (tail == NULL)
tail = filePath;
else
++tail; /* step past last delimiter */
return tail;
}
static boolean isAbsolutePath( path )
const char *const path;
{
#if defined(MSDOS) || defined(WIN32) || defined(OS2)
return (strchr(DosPathDelimiters, path[0]) != NULL);
#else
return (boolean)(path[0] == PATH_SEPARATOR);
#endif
}
static void combinePathAndFile( filePath, path, file )
char *const filePath;
const char *const path;
const char *const file;
{
#if defined(MSDOS) || defined(WIN32) || defined(OS2)
if (strchr(DosPathDelimiters, path[strlen(path)-1]) != NULL)
sprintf(filePath, "%s%s", path, file);
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -