mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
335 lines
13 KiB
335 lines
13 KiB
/**********************************************************************
|
|
// SEARCH.C
|
|
//
|
|
// Copyright (c) 1992 - Microsoft Corp.
|
|
// All rights reserved.
|
|
// Microsoft Confidential
|
|
//
|
|
// Entry point for string search criteria.
|
|
//
|
|
// TABS = 3
|
|
// johnhe - 04-26-92
|
|
**********************************************************************/
|
|
|
|
#include "shellprv.h"
|
|
#pragma hdrstop
|
|
|
|
#pragma warning( disable:4001 ) // Disable new type remark warning
|
|
|
|
//*********************************************************************
|
|
// Local function prototypes.
|
|
//*********************************************************************
|
|
|
|
void BldSearchLsts ( LPGREPINFO lpgi, LPSTR pStrLst, LPSTR pNotList );
|
|
static LPSTR s_pSrchStrLst = NULL; // Ptr to normal search string list
|
|
|
|
//*********************************************************************
|
|
// Builds allocates search buffers and builds search list trees.
|
|
//
|
|
// The format of the pStrLst and pNotLst is multiple zero terminated
|
|
// strings with a zero length string marking the end of the list.
|
|
//
|
|
// "string1",0,"string2",0,"string3",0,"...",0,0
|
|
//
|
|
// int InitGrepInfo( LPSTR pStrLst, LPSTR pNotList, unsigned uOpts )
|
|
//
|
|
// ARGUMENTS:
|
|
// pStrLst - Ptr to list of string to try to match
|
|
// pNotLst - Ptr to list of string which must not match
|
|
// uOpts - Search options of FLG_REGULAR and FLG_CASE
|
|
// RETURNS:
|
|
// int - OK is no errors else ERR_NOMEMORY, ERR_MEMCORUPT,
|
|
// ERR_STRLST_LEN, or ERR_SRCH_EXPRESSION
|
|
//
|
|
//*********************************************************************
|
|
|
|
LPGREPINFO InitGrepInfo( LPSTR pStrLst, LPSTR pNotList, unsigned uOpts )
|
|
{
|
|
int i; // Loop indice
|
|
LPGREPINFO lpgi;
|
|
|
|
// Make sure there is at least one string to match in at least
|
|
// one of the search lists and set flag if no normal srch strings.
|
|
|
|
if ( pStrLst[ 0 ] == '\0' && pNotList[ 0 ] == '\0' )
|
|
return( OK );
|
|
|
|
s_pSrchStrLst = pStrLst;
|
|
|
|
if ( (lpgi = InitGrepBufs()) == NULL )
|
|
return( NULL );
|
|
|
|
if ( (uOpts & FLG_REGULAR) != FALSE ) // Use regular expression (/R) ?
|
|
lpgi->addstr = addexpr; // Then add expression to list
|
|
else
|
|
lpgi->addstr = addstring; // Else treat strings literally
|
|
|
|
// Set if case sensitivity
|
|
lpgi->CaseSen = ((uOpts & FLG_CASE) ? TRUE : FALSE);
|
|
|
|
// Set longjmp to allow aborting on errors
|
|
_try
|
|
{
|
|
BldSearchLsts( lpgi, pStrLst, pNotList );
|
|
|
|
if ( !(uOpts & FLG_REGULAR) ) // If not using expressions
|
|
{
|
|
lpgi->find = findlist; // Assume finding many
|
|
|
|
for ( i = 0; i < 2; i++ )
|
|
{
|
|
_fmemset(lpgi->ge.td1, (int)(lpgi->ge.ShortStrLen + 1), TRTABLEN); // Init lpgi->ge.td1 tables
|
|
enumstrings(lpgi); // Build lpgi->ge.td1 table
|
|
|
|
|
|
if (lpgi->ge.StrCount == 1 && lpgi->CaseSen)
|
|
lpgi->find = findone; // Find one case-sensitive string
|
|
else
|
|
lpgi->find = findlist; // Assume finding many
|
|
SwapSrchTables(lpgi); // Do the data swap
|
|
}
|
|
}
|
|
else if (lpgi->find == NULL)
|
|
lpgi->find = findexpr; // Else find expressions
|
|
}
|
|
|
|
// Let the debugger get a chance at the exceptions first...
|
|
_except(SetErrorMode(SEM_NOGPFAULTERRORBOX),UnhandledExceptionFilter(GetExceptionInformation()))
|
|
{
|
|
FreeGrepBufs(lpgi);
|
|
return NULL ;
|
|
}
|
|
|
|
return( lpgi );
|
|
}
|
|
|
|
//*********************************************************************
|
|
// Initializes the search tree data for both the search list and
|
|
// not search list.
|
|
//
|
|
// void BldSearchLsts( LPSTR pStrLst, LPSTR pNotList )
|
|
//
|
|
// ARGUMENTS:
|
|
// pStrLst - Ptr to list of strings or expression to match
|
|
// pNotLst - Ptr to list of strings or expression which must not match
|
|
// RETURNS:
|
|
// void
|
|
//
|
|
//*********************************************************************
|
|
|
|
void BldSearchLsts( LPGREPINFO lpgi, LPSTR pStrLst, LPSTR pNotList )
|
|
{
|
|
LPSTR szNext; // Ptr to next string to add
|
|
int i; // Loop indice
|
|
int iStrLen; // Length of current string
|
|
|
|
// Loop 3 times. First iteration add all search strings to normal
|
|
// search list, 2nd iteration add all /NOT string to the normal
|
|
// search list and then swap the search data so that on the
|
|
// 3rd iteration all the /NOT string will be added to the /NOT
|
|
// search list. Then swap the data again to restore the original.
|
|
|
|
for ( szNext = pStrLst, i = 0; i < 3; i++ )
|
|
{
|
|
while ( *szNext != '\0' )
|
|
{
|
|
iStrLen = (int)lstrlenA( szNext );
|
|
|
|
// If doing string search make sure this is not a duplicate
|
|
// before adding it to the search tree.
|
|
|
|
if ( lpgi->addstr == addexpr ||
|
|
findlist( lpgi, szNext, szNext + iStrLen ) == NULL )
|
|
(*lpgi->addstr)( lpgi, szNext, iStrLen ); // Add string to list
|
|
szNext += iStrLen + 1;
|
|
}
|
|
|
|
if ( i == 1 ) // Is this the 2nd iteration
|
|
SwapSrchTables(lpgi); // Do the data swap
|
|
|
|
// Set string ptr to /NOT list for 2nd and 3rd iterations.
|
|
szNext = pNotList;
|
|
}
|
|
|
|
SwapSrchTables(lpgi); // Restore the original data area
|
|
}
|
|
|
|
//*********************************************************************
|
|
// Reads in portions of an open file and search the strings initialized
|
|
// by BldSearchLsts().
|
|
//
|
|
// If (fFlags & FLG_FIND_FILE) will continue reading thru the file until
|
|
// a matching search string is found or the end of the file is reached.
|
|
// If there are string specified in the /NOT list the file will continue
|
|
// to be scanned until either a string the the /NOT list is detected
|
|
// or the end of the file is reached.
|
|
//
|
|
// If !(fFlags & FLG_FIND_FILE) the file will be searched for lines
|
|
// which match containing a matching string and then the user supplied
|
|
// callback will be called for each line which contains a match or
|
|
// does not contain a match, depending on the bits in fFlags.
|
|
//
|
|
//
|
|
// NOTE:
|
|
// InitSearchInfo() must be called to setup the search information
|
|
// and intialize the search buffers before this function is called
|
|
// the first time.
|
|
//
|
|
// int FileFindGrep( HANDLE fh, unsigned fFlags, FIND_CALLBACK FindCb )
|
|
//
|
|
// ARGUMENTS:
|
|
// fHandle - Open DOS file handle of file to search
|
|
// fFlags - Operation flags can be a combination of:
|
|
// FLG_FIND_FILE - Only try to locate the file (EXCLUSIVE)
|
|
// FLG_FIND_NOMATCH - Display non-matching lines
|
|
// FLG_FIND_MATCH - Display matching lines
|
|
// FLG_FIND_COUNT - Display on count of matching lines
|
|
// FLG_FIND_LINENO - Display line numbers on output
|
|
// FindCb - Call function for displaying matching strings or NULL
|
|
// if (fFlags & FLG_FIND_FILE).
|
|
// RETURNS:
|
|
// int - If (fFlags & FLG_FIND_FILE) returns TRUE if at least one
|
|
// string match from pStrLst and no string match from pNotLst
|
|
// else FALSE. If !(fFlags & FLG_FIND_FILE) returns OK
|
|
// if no errors else returns ERR_FILE_READ or any value
|
|
// returned by a callback function.
|
|
//
|
|
//*********************************************************************
|
|
|
|
int FileFindGrep( LPGREPINFO lpgi, HANDLE fh, unsigned fFlags,
|
|
long (far pascal *AppCb)( int Func,
|
|
unsigned uArg0,
|
|
void far *pArg1,
|
|
unsigned long ulArg2 ) )
|
|
{
|
|
register LPSTR BufPtr; // Buffer pointer
|
|
LPSTR EndBuf; // End of buffer
|
|
LPSTR pchChar; // Ptr to matching string in buffer
|
|
|
|
#ifdef DO_CALLBACK
|
|
TCHAR *pchBegin; // Ptr to start of line
|
|
TCHAR *pchEnd; // Ptr to end of line
|
|
#endif
|
|
int iStatus; //
|
|
DWORD ByteCount; // Byte count
|
|
unsigned TailLen; // Length of buffer tail
|
|
unsigned long ulLineNum; // Current line number in the file
|
|
unsigned long ulMatchCnt; // Count of lines containing match
|
|
|
|
lpgi->ReadBuf[ 3 ] = '\n'; // Mark beginning with newline
|
|
BufPtr = lpgi->ReadBuf + 4; // Set buf ptr to after newline
|
|
TailLen = 0; // No buffer tail yet
|
|
ulLineNum = 0UL; // Start with line 1
|
|
ulMatchCnt = 0UL; // Zero the match count
|
|
iStatus = OK; // Assume no errors to start
|
|
|
|
// Loop filling the buffer and then searching it
|
|
while ( ReadFile(fh, BufPtr, SectorBased( FILBUFLEN - TailLen),
|
|
&ByteCount, NULL)
|
|
&& (ByteCount + TailLen != 0))
|
|
{
|
|
if ( ByteCount == 0 )
|
|
{ // If buffer tail is all that's left
|
|
TailLen = 0; // Set tail length to zero
|
|
*BufPtr++ = '\r'; // Add end of line sequence
|
|
*BufPtr++ = '\n';
|
|
EndBuf = BufPtr; // Note end of buffer
|
|
}
|
|
else // Else start next read
|
|
{ // Find length of partial line
|
|
TailLen = (unsigned)preveol( BufPtr + ByteCount - 1 );
|
|
if ( TailLen == ByteCount ) // Find tail length after last LF
|
|
{
|
|
TailLen = 0; // No linefeeds in buffer
|
|
EndBuf = BufPtr + ByteCount;
|
|
}
|
|
else
|
|
EndBuf = BufPtr + ByteCount - TailLen;
|
|
}
|
|
|
|
pchChar = lpgi->ReadBuf + 4;
|
|
|
|
// Loop searching thru the buffer for matching strings
|
|
|
|
while ( pchChar != NULL &&
|
|
EndBuf > pchChar &&
|
|
(EndBuf - pchChar) >= lpgi->ge.ShortStrLen )
|
|
{
|
|
if ( !(fFlags & FIND_FILE) )
|
|
{
|
|
#ifdef DO_CALLBACKS
|
|
ulLineNum++; // Increment the line count
|
|
pchBegin = pchChar;
|
|
pchEnd = NextEol( pchChar, EndBuf );
|
|
if ( (pchChar = (*find)( pchChar, pchEnd )) != NULL )
|
|
{
|
|
ulMatchCnt++;
|
|
if ( !(fFlags & FIND_NOMATCH) &&
|
|
!(fFlags & FIND_COUNT) )
|
|
iStatus = CB_FindMatch( pchEnd - pchBegin,
|
|
pchBegin, ulLineNum );
|
|
}
|
|
else if ( (fFlags & FLG_FIND_NOMATCH) )
|
|
iStatus = CB_FindMatch( pchEnd - pchBegin, pchBegin,
|
|
ulLineNum );
|
|
if ( iStatus != OK )
|
|
return( iStatus );
|
|
pchChar = pchEnd;
|
|
#endif // DO_CALLBACKS
|
|
}
|
|
|
|
else if ( (pchChar = (*lpgi->find)( lpgi, pchChar, EndBuf )) != NULL )
|
|
{
|
|
// If we looking for /NOT strings the
|
|
// findfile fails unless NoSrchStr == TRUE, if we are not
|
|
// looking for /NOT strings it means we found a normal
|
|
// string so see if there are any not strings.
|
|
|
|
if ( (fFlags & FIND_NOT) )
|
|
{
|
|
SwapSrchTables(lpgi); // Restore the normal data area
|
|
return( FALSE ); // Always FALSE if /NOT strs found
|
|
}
|
|
else if ( lpgi->geNot.TblEntriesUsed <= 1 ) // Are there any /NOT strings
|
|
return( TRUE ); // Found a match and no /NOT strings
|
|
else
|
|
{
|
|
SwapSrchTables(lpgi); // Need to search for /NOT strings
|
|
fFlags |= FIND_NOT; // Signal we've changed the data
|
|
}
|
|
}
|
|
// Copy tail to head of buffer
|
|
}
|
|
if ( TailLen != 0 )
|
|
hmemcpy( lpgi->ReadBuf + 4, EndBuf, TailLen );
|
|
BufPtr = lpgi->ReadBuf + TailLen + 4; // Skip over tail
|
|
|
|
// If our last read returned no bytes
|
|
}
|
|
|
|
|
|
if ( !(fFlags & FIND_FILE) )
|
|
#ifdef DOCALLBACKS
|
|
return( CB_FindCount( ulMatchCnt ) );
|
|
#else
|
|
return(1);
|
|
#endif //CALLBACK
|
|
else if ( !(fFlags & FIND_NOT) )
|
|
return( (s_pSrchStrLst[ 0 ] == '\0') ? TRUE : FALSE );
|
|
|
|
SwapSrchTables(lpgi); // Restore the normal data area
|
|
return( TRUE ); // No /NOT strings found success
|
|
}
|
|
|
|
//*********************************************************************
|
|
//*********************************************************************
|
|
|
|
LPSTR NextEol( LPSTR pchChar, LPSTR EndBuf )
|
|
{
|
|
pchChar++; // String starts with /r
|
|
|
|
while( pchChar < EndBuf && *pchChar != 0x0A )
|
|
pchChar++;
|
|
|
|
return( pchChar );
|
|
}
|