ctags.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 449 行
C
449 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: VI ctags utility.
*
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#if defined(__UNIX__)
#include <dirent.h>
#include <sys/stat.h>
#else
#include <direct.h>
#endif
#include "ctags.h"
#include "banner.h"
static const char *usageMsg[] = {
"Usage: ctags [-?adempstqvxy] [-z[a,c,f]] [-f<fname>] [files] [@optfile]",
"\t[files]\t : source files (may be C, C++, or FORTRAN)",
"\t\t file names may contain wild cards (* and ?)",
"\t[@optfile] : specifies an option file",
"\tOption File Directives:",
"\t\t option <opts>: any command line options (no dashes).",
"\t\t\t\tan option line resets the d,m,s and t options.",
"\t\t\t\tthey must be specified on option line to",
"\t\t\t\tremain in effect",
"\t\t file <flist> : a list of files, separated by commas",
"\tOptions: -?\t : print this list",
"\t\t -a\t : append output to existing tags file",
"\t\t -c\t : add classes (C++ files)",
"\t\t -d\t : add all #defines (C,C++ files)",
"\t\t -e\t : add enumerated constants (C,C++ files)",
"\t\t -f<fname> : specify alternate tag file (default is \"tags\")",
"\t\t -m\t : add #defines (macros only) (C,C++ files)",
"\t\t -p\t : add prototypes to tags file",
"\t\t -s\t : add structs, enums and unions (C,C++ files)",
"\t\t -t\t : add typedefs (C,C++ files)",
"\t\t -q\t : quiet operation",
"\t\t -v\t : verbose operation",
"\t\t -x\t : add all possible tags (same as -cdst)",
"\t\t -y\t : add all non-c++ tags (same as -dst)",
"\t\t -z[a,c,f] : assume files are of type ASM, C/C++, or FORTRAN",
"\tOptions may be specified in a CTAGS environment variable",
NULL
};
static char optStr[] = "acdempstqvxyf:z:";
static bool quietFlag;
static bool appendFlag;
static char *fileName = "tags";
static char tmpFileName[_MAX_PATH];
static file_type fileType=TYPE_NONE;
static void displayBanner( void )
{
if( quietFlag ) {
return;
}
printf( "%s\n", banner1w( "CTAGS Utility", "1.0") );
printf( "%s\n", banner2a() );
printf( "%s\n", banner3 );
printf( "%s\n", banner3a );
} /* displayBanner */
/*
* doOption - handle a single option
*/
static void doOption( int ch )
{
switch( ch ) {
case 'a':
appendFlag = TRUE;
break;
case 'c':
WantClasses = TRUE;
break;
case 'd':
WantAllDefines = TRUE;
break;
case 'e':
WantEnums = TRUE;
break;
case 'f':
fileName = OptArg;
break;
case 'm':
WantMacros = TRUE;
break;
case 'p':
WantProtos = TRUE;
break;
case 's':
WantUSE = TRUE;
break;
case 't':
WantTypedefs = TRUE;
break;
case 'q':
quietFlag = TRUE;
break;
case 'x':
WantClasses = TRUE;
/* fall through */
case 'y':
WantAllDefines = TRUE;
WantMacros = TRUE;
WantUSE = TRUE;
WantTypedefs = TRUE;
break;
case 'v':
VerboseFlag = TRUE;
break;
case 'z':
switch( OptArg[0] ) {
case 'a':
fileType = TYPE_ASM;
break;
case 'c':
fileType = TYPE_C;
break;
case 'f':
fileType = TYPE_FORTRAN;
break;
default:
Quit( usageMsg, "Invalid file type\n" );
break;
}
}
} /* doOption */
/*
* processFile - process a specified file
*/
static void processFile( char *arg )
{
char buff[_MAX_EXT+5];
char *ext;
file_type ftype;
unsigned tagcnt;
StartFile( arg );
_splitpath2( arg, buff, NULL, NULL, NULL, &ext );
if( fileType == TYPE_NONE ) {
ftype = TYPE_C;
if( !stricmp( ext,".for" ) ) {
ftype = TYPE_FORTRAN;
} else if( !stricmp( ext,".fi" ) ) {
ftype = TYPE_FORTRAN;
} else if( !stricmp( ext,".pas" ) ) {
ftype = TYPE_PASCAL;
} else if( !stricmp( ext,".cpp" ) ) {
ftype = TYPE_CPLUSPLUS;
} else if( !stricmp( ext,".asm" ) ) {
ftype = TYPE_ASM;
}
} else {
ftype = fileType;
}
if( VerboseFlag ) {
printf( "Processing %s", arg );
tagcnt = TagCount;
fflush( stdout );
}
switch( ftype ) {
case TYPE_C:
ScanC();
break;
case TYPE_CPLUSPLUS:
ScanC();
break;
case TYPE_FORTRAN:
ScanFortran();
break;
case TYPE_PASCAL:
ScanFortran();
break;
case TYPE_ASM:
ScanAsm();
break;
}
if( VerboseFlag ) {
printf( ", %u tags.\n", TagCount-tagcnt );
}
EndFile();
} /* processFile */
/*
* processFileList - process a possible file list
*/
static void processFileList( char *ptr )
{
DIR *dirp;
struct dirent *dirent;
char *tmp;
bool has_wild=FALSE;
char buff1[_MAX_PATH2];
char buff2[_MAX_PATH2];
char *drive;
char *dir;
char *fname;
char *ext;
char path[_MAX_PATH];
tmp = ptr;
while( *tmp != 0 ) {
if( *tmp == '*' || *tmp == '?' ) {
has_wild = TRUE;
break;
}
tmp++;
}
if( !has_wild ) {
processFile( ptr );
return;
}
_splitpath2( ptr, buff1, &drive, &dir, &fname, &ext );
dirp = opendir( ptr );
if( dirp == NULL ) {
return;
}
while( (dirent = readdir( dirp )) != NULL ) {
#ifdef __UNIX__
{
struct stat buf;
stat( dirent->d_name, &buf );
if ( S_ISDIR( buf.st_mode ) )
continue;
}
#else
if( dirent->d_attr & (_A_SUBDIR|_A_VOLID ) )
continue;
#endif
_splitpath2( dirent->d_name, buff2, NULL, NULL, &fname, &ext );
_makepath( path, drive, dir, fname, ext );
strlwr( path );
processFile( path );
}
closedir( dirp );
} /* processFileList */
/*
* processOptionFile - process an option file
*/
static void processOptionFile( char *fname )
{
FILE *optfile;
char option[MAX_STR];
char *ptr,*cmd,*arg;
int ch;
optfile = fopen( fname, "r" );
if( optfile == NULL ) {
printf( "Could not open option file %s\n", fname );
return;
}
while( fgets( option, sizeof( option ), optfile ) != NULL ) {
ptr = option;
while( isspace( *ptr ) ) {
ptr++;
}
if( *ptr == '#' || *ptr == 0 ) {
continue;
}
cmd = ptr;
while( !isspace( *ptr ) && *ptr ) {
ptr++;
}
if( *ptr == 0 ) {
continue;
}
*ptr = 0;
ptr++;
while( isspace( *ptr ) ) {
ptr++;
}
if( *ptr == 0 ) {
continue;
}
if( !stricmp( cmd, "file" ) ) {
while( 1 ) {
arg = ptr;
while( !isspace( *ptr ) && *ptr != ',' && *ptr != 0 ) {
ptr++;
}
ch = *ptr;
*ptr = 0;
processFileList( arg );
if( ch == 0 ) {
break;
}
ptr++;
while( isspace( *ptr ) || *ptr == ',' ) {
ptr++;
}
if( *ptr == 0 ) {
break;
}
}
} else if( !stricmp( cmd, "option" ) ) {
WantTypedefs = FALSE;
WantMacros = FALSE;
WantAllDefines = FALSE;
WantUSE = FALSE;
while( *ptr != 0 ) {
if( *ptr == 'f' ) {
ptr++;
while( isspace( *ptr ) ) {
ptr++;
}
if( *ptr == 0 ) {
break;
}
strcpy( tmpFileName, ptr );
ptr = tmpFileName;
while( !isspace( *ptr ) ) {
ptr++;
}
*ptr = 0;
OptArg = tmpFileName;
doOption( 'f' );
break;
}
doOption( *ptr );
ptr++;
}
}
}
fclose( optfile );
} /* processOptionFile */
int main( int argc , char *argv[] )
{
int ch,i;
while( 1 ) {
ch = GetOpt( &argc, argv, optStr, usageMsg );
if( ch == -1 ) {
break;
}
doOption( ch );
}
displayBanner();
if( argc < 2 ) {
Quit( usageMsg, "No files specified\n" );
}
if( quietFlag ) {
VerboseFlag = FALSE;
}
for( i=1;i<argc;i++ ) {
if( argv[i][0] == '@' ) {
processOptionFile( &argv[i][1] );
} else {
processFileList( argv[i] );
}
}
if( appendFlag ) {
if( VerboseFlag ) {
printf( "Generated %u tags.\n", TagCount );
}
ReadExtraTags( fileName );
}
GenerateTagsFile( fileName );
return( 0 );
} /* main */
/*
* IsTokenChar - determine if a character is part of a token
*/
bool IsTokenChar( char ch )
{
if( isalnum( ch ) ) {
return( TRUE );
}
if( ch == '_' ) {
return( TRUE );
}
return( FALSE );
} /* IsTokenChar */
/*
* MyStricmp - ignore trailing null, advance buf pointer
*/
int MyStricmp( char **buf, char *literal )
{
int ret;
int len;
char *bufptr;
char save_ch;
len = strlen( literal );
bufptr = *buf;
save_ch = bufptr[len];
bufptr[len] = 0;
ret = stricmp( *buf, literal );
bufptr[len] = save_ch;
if( ret==0 ) {
(*buf) += len;
}
return( ret );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?