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 + -
显示快捷键?