wgrep.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,267 行 · 第 1/3 页
C
1,267 行
/****************************************************************************
*
* 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: Yet another grep utility.
*
****************************************************************************/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <process.h>
#include <signal.h>
#include <limits.h>
#if defined( __UNIX__ )
#include <dirent.h>
#else
#include <direct.h>
#endif
#define BINC 1024
#if defined(__NT__)
#define BSIZE (256 * BINC)
#else
#define BSIZE (128 * BINC)
#endif
#define MAX_SRCH_STRINGS 2048
typedef int wbool;
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#if defined(__WATCOMC__)
#define READABLE (S_IRUSR|S_IRGRP|S_IROTH)
#define WRITABLE (S_IWUSR|S_IWGRP|S_IWOTH)
#define EXECUTABLE (S_IXUSR|S_IXGRP|S_IXOTH)
#else
#define READABLE (S_IREAD)
#define WRITABLE (S_IWRITE)
#define EXECUTABLE (S_IEXEC)
#endif
typedef struct dirstack {
struct dirstack *prev;
char name[ _MAX_PATH ];
} dirstack;
// Default list of file extensions that we will not search when -g is specified.
char *DefIgnoredExt = {
".aps"
".avi"
".bin"
".bmp"
".class"
".cur"
".db"
".dll"
".doc"
".exe"
".fts"
".gid"
".gif"
".hlp"
".ico"
".ilk"
".jar"
".jpg"
".lib"
".mch"
".mcp"
".mp3"
".mpg"
".nlm"
".obj"
".pch"
".pdb"
".res"
".sym"
".tdt"
".tlb"
".xls"
".zip"
};
char **IgnoreList = NULL;
char *IgnoreListBuffer = NULL;
unsigned IgnoreListCnt = 0;
char CurrPattern[ _MAX_FNAME + _MAX_EXT ];
char PathBuff[ _MAX_PATH ];
int DoneFlag = 0;
int RecurLevels = 1;
dirstack *Stack = NULL;
char *FName;
char *Buff;
size_t BSize;
wbool PrtFn;
wbool PrtAll;
wbool PrtCount;
wbool PrtMatch;
wbool PrtLines;
wbool PrtFiles;
wbool PrtPath;
wbool QuitFirst;
wbool OnePerFile;
wbool Similar;
wbool NoSubstring;
int Context;
int ExitStatus;
long MatchCount;
long TotalMatchCount;
FILE *FOut;
char *FOutFmt;
char *SrchStrings[ MAX_SRCH_STRINGS ];
unsigned Recs;
char StdoutBuf[ 512 ]; // used for files w/o \r
int CurOutMode;
int FileMode = 0;
unsigned char CharInSrchStrings[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
unsigned char CharTrans[] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
};
char *Help[] = {
"Usage: wgrep {option}* string [file [file [file...]]]",
"",
" string - the search string",
" or @FILE : FILE contains a list of search strings, one per line",
" or @CON : You will be prompted for search strings",
" Escape characters are:",
" \\[ matches <",
" \\] matches >",
" \\! matches |",
" \\\\ matches \\",
" \\t matches TAB character",
" \\^ matches start of line (must double up ^ on command line)",
" \\$ matches end of line",
" \\? matches ?",
" 4NT users must double up % to search for %",
" 4NT users must place quotes around \\^c to avoid conversion of ^c",
" to a single byte value (e.g., ^n becomes 0x0A)",
"",
" file - A wild card file name to be searched - defaults to '*.*'.",
" - if file is a directory, all files in that directory are searched",
" - file name patterns may be separated by spaces or semicolons",
" - file may refer to an environment variable using % (e.g., %include)",
"",
" option -a Print each file name as it is searched",
" -c Print only number of lines that contain matches",
" -d Display command line arguments",
" -f Don't print file names",
" -g[list] Ignore files with specific extensions.",
" The default list of extensions includes:",
" .aps .avi .bin .bmp .class .cur .db .dll .doc .exe .fts",
" .gid .gif .hlp .ico .ilk .jar .jpg .lib .mch .mcp .mp3",
" .mpg .nlm .obj .pch .pdb .res .sym .tdt .tlb .xls .zip",
" The default list can be overridden using the WGREPIGNORE",
" environment variable. The list of extensions are of the",
" the form '.exe.obj.dll'. Additional extensions may be",
" included after the -g (e.g., -g.prj.tmp.log).",
" -h Display this usage message",
" -i Make search case insensitive",
" -l Print matching file names only",
" -n Print 'File:' and '1234:' on beginning of output lines",
" -ofn(fmt) Create a list of files with matches in fn, using printf",
" format string fmt - %s is replaced with the file name",
" - \\b is replaced with a blank",
" fn defaults to tmp.bat",
" fmt defaults to (%s)",
" -p Include full path specification",
" -q Don't print anything (quiet)",
" -s Display only similar strings (e.g., B is similar to b)",
" -t No substring matches",
" -wN Display N lines of context",
" -x Stop searching each file after one occurrence found",
" -1 Exit when all strings matched once with return code",
" -rN Recurse subdirectories (max. N levels deep)",
" -ro Restrict search to read-only files (no writeable files)",
" -estring Specify additional search string",
NULL
};
static void Error( char *msg, char *other )
{
printf( "%s '%s'\r\n", msg, other );
exit( 3 );
}
static void Warning( char *msg, char *other )
{
printf( "%s '%s'\r\n", msg, other );
}
static void *SafeMalloc( size_t n )
{
void *p;
p = malloc( n );
if( p == NULL ) {
Error( "Out of memory", "Stack" );
}
return( p );
}
static void GetDefIgnoreList( char *extra ) {
char *env;
char *ptr;
char *bufPtr;
unsigned exts;
unsigned exts_len;
unsigned pass;
exts = 0;
extra += 2; // skip the -g
ptr = extra;
if( *ptr != '\0' ) {
ptr++; // in case the string doesn't start with a "."
exts++; // we count at least 1 extension
while( *ptr != '\0' ) {
if( *ptr++ == '.' ) exts++;
}
}
env = getenv( "WGREPIGNORE" );
if( env == NULL ) {
env = DefIgnoredExt;
}
ptr = env;
if( *ptr != '\0' ) {
ptr++; // in case the string doesn't start with a "."
exts++; // we count at least 1 extension
while( *ptr != '\0' ) {
if( *ptr++ == '.' ) exts++;
}
}
IgnoreList = (char **)SafeMalloc( (exts+1) * sizeof( char * ) );
if( IgnoreList == NULL ) return;
exts_len = (unsigned)(strlen( env ) + strlen( extra ));
// allocate space for all extensions + null chars + 1 extra in case "." missing
IgnoreListBuffer = (char *)SafeMalloc( exts_len + exts + 1 );
if( IgnoreListBuffer == NULL ) return;
memset( IgnoreListBuffer, '\xee', exts_len + exts + 1 );
IgnoreListCnt = exts; // non-zero means we successfully allocated buffers
bufPtr = IgnoreListBuffer;
IgnoreListCnt = 0;
pass = 0;
ptr = NULL;
for( ;; ) {
if( ptr == NULL && pass == 0 ) {
ptr = env;
} else if( ptr == NULL && pass == 1 ) {
ptr = extra;
}
if( *ptr == '\0' ) break;
IgnoreList[ IgnoreListCnt ] = bufPtr;
IgnoreListCnt++;
if( *ptr != '.' ) {
printf( "Warning! - file extension does not begin with a '.'\n" );
} else {
ptr++;
}
*bufPtr = '.';
bufPtr++;
while( *ptr != '.' && *ptr !='\0' ) {
*bufPtr = *ptr;
bufPtr++;
ptr++;
}
*bufPtr = '\0';
bufPtr++;
if( *ptr == '\0' ) {
pass++;
ptr = NULL;
}
if( pass == 2 ) break;
}
IgnoreList[ IgnoreListCnt ] = NULL;
}
static void printFileName( void )
{
int i;
char buff[_MAX_PATH]; // Can't use PathBuff since FName is
// a pointer into it!
char *p = buff;
if( PrtLines ) {
printf( "File: " );
}
if( PrtPath && _fullpath( buff, FName, _MAX_PATH ) ) {
printf( "%s\r\n", buff );
} else {
i = 0;
while( FName[i] != '\0' ) {
if( FName[i] == '.' && FName[i+1] == '\\' ) {
if( i != 0 && FName[i-1] != '\\' ) {
*p = FName[i];
p++;
*p = FName[i+1];
p++;
}
i += 2;
} else {
*p = FName[i];
p++;
i++;
}
}
*p = '\0';
printf( "%s\r\n", buff );
}
}
static void dumpMatch( char *buff, size_t len )
{
char *stop = &buff[len];
while( buff != stop ) {
char c = *buff;
if( c == 0x07 ) {
// bell chars have bothered me for years! (AFS)
fputc( '^', stdout );
c = 'G';
}
fputc( c, stdout );
++buff;
}
}
static wbool outputMatch( char *where, size_t read, wbool disp )
{
wbool done;
char *endrec;
int i;
done = FALSE;
if( where >= &Buff[read] ) {
done = TRUE; // this is the string we added to buffer! we're done buffer
} else if( disp ) {
if( PrtFn ) {
if( FOut != NULL ) {
fprintf( FOut, FOutFmt, FName );
fprintf( FOut, "\n" );
}
if( PrtFiles && !PrtAll ) {
printFileName();
}
PrtFn = FALSE;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?