WindowsXP-SP1/admin/cmdline/lib/filterresults.c
2020-09-30 16:53:49 +02:00

1396 lines
40 KiB
C

/**********************************************************************************
Copyright (c) Microsoft Corporation
Module Name:
FilterResults.c
Abstract:
This modules has functions which are required to parse Command Line options.
Author:
G.V.N.Murali Sunil
Revision History:
None
**********************************************************************************/
#include "pch.h"
#include "cmdline.h"
//
// constants / definitions / enumerations
//
#define OPERATOR_DELIMITER _T( "|" )
#define CHAR_ASTERISK _T( '*' )
#define OPERATOR_EQ _T( "=| eq " )
#define OPERATOR_NE _T( "!=| ne " )
#define OPERATOR_GT _T( ">| gt " )
#define OPERATOR_LT _T( "<| lt " )
#define OPERATOR_GE _T( ">=| ge " )
#define OPERATOR_LE _T( "<=| le " )
//
// private user-defined types ... for internal usage only
//
typedef struct ___tagOperator
{
DWORD dwMask;
OPERATORS szOperator;
} TOPERATOR;
typedef TOPERATOR* PTOPERATOR;
//
// private functions ... used only within this file
//
/***************************************************************************
Routine Description:
Arguments:
[ in ] dwCount:
[ in ] optInfo[]:
[ in ] szOperator:
Return Value:
***************************************************************************/
DWORD __FindOperatorMask( DWORD dwCount, TOPERATOR optInfo[], LPCTSTR szOperator )
{
// local variables
DWORD dw = 0; // looping variable
// check the input value
if ( optInfo == NULL || szOperator == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return 0;
}
// traverse thru the list of operators list
for( dw = 0; dw < dwCount; dw++ )
{
// check whether the current operator information matches
if ( InString( szOperator, optInfo[ dw ].szOperator, TRUE ) )
return optInfo[ dw ].dwMask; // operator matched ... return its mask
}
// operator not found
return 0;
}
/***************************************************************************
Routine Description:
Compares Two Strings in two ways with and without case sensitivily,
Arguments:
[ in ] szValue1 = First String
[ in ] szValue2 = Second String
[ in ] bIgnoreCase = Case Sensitivity or not
[ in ] lCount = no. of characters to be compare
Return Value:
MASK_EQ - if both strings are equal
MASK_LT - First string is less
MASK_GT - Second String is less
***************************************************************************/
DWORD __StringCompare( LPCTSTR szValue1, LPCTSTR szValue2, BOOL bIgnoreCase, LONG lCount )
{
// local variables
LONG lResult = 0; // hold the string comparision result
// check the input value
if ( szValue1 == NULL || szValue2 == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return 0;
}
// if the no. of characters that needs to checked is -1, just return
if ( lCount == -1 )
return MASK_ALL; // that strings are equal
// compare the two strings and get the result of comparision
lResult = StringCompare( szValue1, szValue2, bIgnoreCase, lCount );
//
// now determine the result value
if ( lResult == 0 )
return MASK_EQ;
else if ( lResult < 0 )
return MASK_LT;
else if ( lResult > 0 )
return MASK_GT;
// never come across this situation ... still
return 0;
}
// ***************************************************************************
// Routine Description:
// compares two long data type values
//
// Arguments:
// [ in ] lvalue1: First value
// [ in ] lvalue2: Second Value
//
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __LongCompare( LONG lValue1, LONG lValue2 )
{
//
// determine the result value
if ( lValue1 == lValue2 )
return MASK_EQ;
else if ( lValue1 < lValue2 )
return MASK_LT;
else if ( lValue1 > lValue2 )
return MASK_GT;
// never come across this situation ... still
return 0;
}
// ***************************************************************************
// Routine Description:
// compares two DWORD data type values
//
// Arguments:
// [ in ] dwValue1: First value
// [ in ] dwValue2: Second Value
//
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __DWORDCompare( DWORD dwValue1, DWORD dwValue2 )
{
//
// determine the result value
if ( dwValue1 == dwValue2 )
return MASK_EQ;
else if ( dwValue1 < dwValue2 )
return MASK_LT;
else if ( dwValue1 > dwValue2 )
return MASK_GT;
// never come across this situation ... still
return 0;
}
// ***************************************************************************
// Routine Description:
// compares two float data type values
//
// Arguments:
// [ in ] fValue1: First value
// [ in ] fValue2: Second Value
//
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __FloatCompare( float fValue1, float fValue2 )
{
//
// determine the result value
if ( fValue1 == fValue2 )
return MASK_EQ;
else if ( fValue1 < fValue2 )
return MASK_LT;
else if ( fValue1 > fValue2 )
return MASK_GT;
// never come across this situation ... still
return 0;
}
// ***************************************************************************
// Routine Description:
// compares two double data type values
//
// Arguments:
// [ in ] dblValue1: First value
// [ in ] dblValue2: Second Value
//
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __DoubleCompare( double dblValue1, double dblValue2 )
{
//
// determine the result value
if ( dblValue1 == dblValue2 )
return MASK_EQ;
else if ( dblValue1 < dblValue2 )
return MASK_LT;
else if ( dblValue1 > dblValue2 )
return MASK_GT;
// never come across this situation ... still
return 0;
}
// ***************************************************************************
// Routine Description:
// compares two date data type values
//
// Arguments:
// [ in ] szValue1: First value
// [ in ] szValue2: Second Value
//
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __DateCompare( LPCTSTR szValue1, LPCTSTR szValue2 )
{
// check the input value
if ( szValue1 == NULL || szValue2 == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return 0;
}
// never come across this situation ... still
return 0;
}
// ***************************************************************************
// Routine Description:
// compares two time data type values
// Arguments:
// szValue1: First value
// szValue2: Second Value
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __TimeCompare( LPCTSTR szValue1, LPCTSTR szValue2 )
{
// check the input value
if ( szValue1 == NULL || szValue2 == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return 0;
}
// never come across this situation ... still
return 0;
}
// ***************************************************************************
// Routine Description:
// compares two date+time data type values
//
// Arguments:
// [ in ] szValue1: First value
// [ in ] szValue2: Second Value
//
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __DateTimeCompare( LPCTSTR szValue1, LPCTSTR szValue2 )
{
// check the input value
if ( szValue1 == NULL || szValue2 == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return 0;
}
// never come across this situation ... still
return 0;
}
// ***************************************************************************
// Routine Description:
// compares value stored in arrRecords and arrFilter array depending on
// filterConfig structure
//
// Arguments:
// [ in ] arrRecord: First value
// [ in ] arrFilter: Second Value
// [ in ] filterConfig: Compare criteria.
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __DoComparision( TARRAY arrRecord, TARRAY arrFilter, TFILTERCONFIG filter )
{
// local variables
LONG lLength = 0; // used for pattern matched strings
LPTSTR pszTemp = NULL;
DWORD dwCompareResult = 0;
__MAX_SIZE_STRING szValue = NULL_STRING;
// variables used for comparision
LPVOID pData = NULL;
LONG lValue1 = 0, lValue2 = 0;
DWORD dwValue1 = 0, dwValue2 = 0;
float fValue1 = 0.0f, fValue2 = 0.0f;
double dblValue1 = 0.0f, dblValue2 = 0.0f;
LPCTSTR pszValue1 = NULL, pszValue2 = NULL;
LPCTSTR pszProperty = NULL, pszOperator = NULL, pszValue = NULL;
// check the input value
if ( arrRecord == NULL || arrFilter == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return 0;
}
// do the comparision
switch( filter.dwFlags & F_TYPE_MASK )
{
case F_TYPE_TEXT:
{
//
// string comparision
// get the value at the specified column and filter value
pszValue1 = DynArrayItemAsString( arrRecord, filter.dwColumn );
pszValue2 = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_VALUE );
// check the values we got from the dynamic array
if ( pszValue1 == NULL || pszValue2 == NULL )
return F_RESULT_REMOVE;
// determine the length of the string that has to be compared
lLength = 0;
if ( filter.dwFlags & F_MODE_PATTERN )
{
// needs to do the pattern matching
// identify till which part string should be compared
lstrcpy( szValue, pszValue2 );
pszTemp = _tcschr( szValue, CHAR_ASTERISK );
if ( pszTemp != NULL )
{
lLength = lstrlen( szValue ) - lstrlen( pszTemp );
// special case:
// if the pattern is just asterisk, which means that all the
// information needs to passed thru the filter
if ( lLength == 0 )
lLength = -1; // match all values
}
}
// do the comparision and get the result
dwCompareResult = __StringCompare( pszValue1, pszValue2, TRUE, lLength );
// break from the switch case
break;
}
case F_TYPE_NUMERIC:
{
//
// numeric comparision
// get the value into buffer - PREFIX PURPOSE
pszValue = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_VALUE );
if ( pszValue == NULL )
return 0;
// get the value at the specified column and filter value
lValue1 = DynArrayItemAsLong( arrRecord, filter.dwColumn );
lValue2 = AsLong( pszValue, 10 );
// do the comparision and get the result
dwCompareResult = __LongCompare( lValue1, lValue2 );
// break from the switch case
break;
}
case F_TYPE_UNUMERIC:
{
//
// unsigned numeric comparision
// get the value into buffer - PREFIX PURPOSE
pszValue = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_VALUE );
if ( pszValue == NULL )
return 0;
// get the value at the specified column and filter value
dwValue1 = DynArrayItemAsLong( arrRecord, filter.dwColumn );
dwValue2 = (DWORD) AsLong( pszValue, 10 );
// do the comparision and get the result
dwCompareResult = __DWORDCompare( dwValue1, dwValue2 );
// break from the switch case
break;
}
case F_TYPE_DATE:
case F_TYPE_TIME:
case F_TYPE_DATETIME:
{
// not yet implemented
dwCompareResult = F_RESULT_KEEP;
// break from the switch case
break;
}
case F_TYPE_FLOAT:
{
//
// float comparision
// get the value into buffer - PREFIX PURPOSE
pszValue = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_VALUE );
if ( pszValue == NULL )
return 0;
// get the value at the specified column and filter value
fValue1 = DynArrayItemAsFloat( arrRecord, filter.dwColumn );
fValue2 = (float) AsFloat( pszValue );
// do the comparision and get the result
dwCompareResult = __FloatCompare( fValue1, fValue2 );
// break from the switch case
break;
}
case F_TYPE_DOUBLE:
{
//
// double comparision
// get the value into buffer - PREFIX PURPOSE
pszValue = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_VALUE );
if ( pszValue == NULL )
return 0;
// get the value at the specified column and filter value
dblValue1 = DynArrayItemAsDouble( arrRecord, filter.dwColumn );
dblValue2 = AsFloat( pszValue );
// do the comparision and get the result
dwCompareResult = __DoubleCompare( dblValue1, dblValue2 );
// break from the switch case
break;
}
case F_TYPE_CUSTOM:
{
//
// custom comparision
// get the filter values
pszProperty = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_PROPERTY );
pszOperator = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_OPERATOR );
pszValue = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_VALUE );
// check ...
if ( pszProperty == NULL || pszOperator == NULL || pszValue == NULL )
return 0;
// call the custom function
dwCompareResult = (filter.pFunction)( pszProperty, pszOperator, pszValue,
filter.pFunctionData == NULL ? &filter : filter.pFunctionData, arrRecord );
// break from the switch case
break;
}
default:
{
// not yet implemented
dwCompareResult = F_RESULT_KEEP;
// break from the switch case
break;
}
}
// return the result
return dwCompareResult;
}
// ***************************************************************************
// Routine Description:
// compares two arrays
//
// Arguments:
// [ in ] arrRecord: First Value
// [ in ] arrFilter: Second Value
// [ in ] filterConfig: Comperison Criteria
//
// Return Value:
// MASK_EQ: both are equal
// MASK_LT: First is less than second
// MASK_GT: First is geater than second
// ***************************************************************************
DWORD __DoArrayComparision( TARRAY arrRecord, TARRAY arrFilter, TFILTERCONFIG filterConfig )
{
// local variables
LONG lIndex = 0;
LONG lLength = 0; // used for pattern matched strings
DWORD dwCompareResult = 0;
LPCTSTR pszTemp = NULL;
__MAX_SIZE_STRING szValue = NULL_STRING;
// variables used for comparision
TARRAY arrValues = NULL;
LPCTSTR pszFilterValue = NULL;
// check the input value
if ( arrRecord == NULL || arrFilter == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return F_RESULT_REMOVE;
}
// array data in the record
arrValues = DynArrayItem( arrRecord, filterConfig.dwColumn );
if ( arrValues == NULL )
return F_RESULT_REMOVE;
switch( filterConfig.dwFlags & F_TYPE_MASK )
{
case F_TYPE_TEXT:
{
//
// string comparision
// get the value at the specified column and filter value
pszFilterValue = DynArrayItemAsString( arrFilter, F_PARSED_INDEX_VALUE );
if ( pszFilterValue == NULL )
return F_RESULT_REMOVE;
// determine the length of the string that has to be compared
lLength = 0;
if ( filterConfig.dwFlags & F_MODE_PATTERN )
{
// needs to do the pattern matching
// identify till which part string should be compared
lstrcpy( szValue, pszFilterValue );
pszTemp = _tcschr( szValue, CHAR_ASTERISK );
if ( pszTemp != NULL )
{
lLength = lstrlen( szValue ) - lstrlen( pszTemp );
// special case:
// if the pattern is just asterisk, which means that all the
// information needs to passed thru the filter
if ( lLength == 0 )
lLength = -1; // match all values
}
}
// do the comparision and get the result
if ( lLength == -1 )
{
// filter has to be passed
dwCompareResult = MASK_ALL;
}
else
{
// find the string in the array and check the result
lIndex = DynArrayFindString( arrValues, pszFilterValue, TRUE, lLength );
if ( lIndex == -1 )
{
// value not found
dwCompareResult = MASK_NE;
}
else
{
pszTemp = DynArrayItemAsString( arrValues, lIndex );
if ( pszTemp == NULL )
return F_RESULT_REMOVE;
// comparision ...
dwCompareResult = __StringCompare(pszTemp, pszFilterValue, TRUE, lLength);
}
}
// break from the switch case
break;
}
}
// return the result
return dwCompareResult;
}
// ***************************************************************************
// Routine Description:
// Prepares a two dimensional array(arrOperators)based on Operator information
// supplied with pfilterConfigs variable
//
//
// Arguments:
// [ in] dwCount = No. of operatores
// [ in] pfilterConfigs = Pointer to TFILTERCONFIG structure
// [out] arrOperators = Array of operators.
//
// Return Value:
// NONE
//
// ***************************************************************************
VOID __PrepareOperators( DWORD dwCount, PTFILTERCONFIG pfilterConfigs, TARRAY arrOperators )
{
// local variables
DWORD i = 0; // looping varible
LONG lIndex = 0; // holds the result of find operation
LPTSTR pszOperator = NULL; // operator specified in filter
PTFILTERCONFIG pFilter = NULL; // temporary filter configuration
__MAX_SIZE_STRING szTemp = NULL_STRING; // temporary string buffer
// check the input value
if ( pfilterConfigs == NULL || arrOperators == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return;
}
// NOTE:- Here in this logic, we are compromising on the memory Vs time
// At the cost of using more memory, the time taken by the validating
// functionality is improved.
//
// collect all the operators that are supported and save them in the local array
// Idea:-
// => This is a two-dimensional array
// => In all rows, the first column will have the operator
// => operator column is followed by the index of the filter property supporting
// this operator, and this column is followed by filter property name
// => This filter property index and its name's can be any number
// => The operator is being treated as key field in the array
//
// SAMPLE:
// 0 1 2 3 4 5 6
// -------------------------------------------------------------------
// = 1 property1 2 property2
// != 0 property0 2 property2
// <= 0 property0 3 property3
// >= 1 property1 3 property3 4 property4
//
for( i = 0; i < dwCount; i++ )
{
// get the filter info at the specified index into local memory
pFilter = pfilterConfigs + i;
// collect operators and prepare with all the available operators
lstrcpy( szTemp, pFilter->szOperators ); // IMP. get the local copy.
pszOperator = _tcstok( szTemp, OPERATOR_DELIMITER ); // get the first token
while ( pszOperator != NULL )
{
// check whether this operator exists in the operators array
lIndex = DynArrayFindStringEx( arrOperators, 0, pszOperator, TRUE, 0 );
if ( lIndex == -1 )
{
//
// operator is not in the list
// add the new operator to the list and set the index to the row added
// for this operator
lIndex = DynArrayAppendRow( arrOperators, 0 );
if ( lIndex == -1 )
return;
// now add the operator as the first column to the newly added row
DynArrayAppendString2( arrOperators, lIndex, pszOperator, 0 );
}
// add the filter property info and its index to the operator row
DynArrayAppendLong2( arrOperators, lIndex, i );
DynArrayAppendString2( arrOperators, lIndex, pFilter->szProperty, 0 );
// fetch the next token
pszOperator = _tcstok( NULL, OPERATOR_DELIMITER );
}
}
}
// ***************************************************************************
// Routine Description:
// Checks the type of pszValue string for the criteria given by fcInfo
// filters.
// Arguments:
// [ in ] fcInfo = filter stucture.
// [ in ] pszProperty = property string
// [ in ] pszOperator = operator
// [ in ] pszValue = string to be checked
//
// Return Value:
// TRUE = valid line
// FALSE = not a valid line
// ***************************************************************************
BOOL __CheckValue( TFILTERCONFIG fcInfo,
LPCTSTR pszProperty, LPCTSTR pszOperator, LPCTSTR pszValue )
{
// local variables
DWORD dwResult = 0;
LPTSTR pszTemp = NULL;
__MAX_SIZE_STRING szValue = NULL_STRING;
// check the input value
if ( pszProperty == NULL || pszOperator == NULL || pszValue == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return FALSE;
}
// check the length of the value string ... it should not be empty
if ( lstrlen( pszValue ) == 0 )
return FALSE; // value string is empty
// start validating the data
switch( fcInfo.dwFlags & F_TYPE_MASK )
{
case F_TYPE_TEXT:
{
// check if the pattern is supported
// if supported, see the '*' is appearing only at the end. if not error
if ( fcInfo.dwFlags & F_MODE_PATTERN )
{
// copy the current value to the local buffer
lstrcpy( szValue, pszValue );
// search for the wild card character
pszTemp = _tcschr( szValue, CHAR_ASTERISK );
// if the wild card character was found and if it is not the last character
// (or) wild card is the only character specified, then invalid filter
if ( pszTemp != NULL && ( lstrlen( pszTemp ) != 1 || pszTemp == szValue ) )
return FALSE; // error ... invalid pattern string
}
// for all these types, no need to do any special checking
// provided, they need not be checked with the list of values
if ( ! ( fcInfo.dwFlags & F_MODE_VALUES ) )
return TRUE; // no special validation
// check for the value in the list and return the result
return ( InString( pszValue, fcInfo.szValues, TRUE ) );
// break from the switch
break;
}
case F_TYPE_NUMERIC:
{
// if the value is not of numeric type, invalid value
if ( ! IsNumeric( pszValue, 10, TRUE ) )
return FALSE;
// check for the value in the list and return the result
// if values are pre-defined
if ( fcInfo.dwFlags & F_MODE_VALUES )
return ( InString( fcInfo.szValues, pszValue, TRUE ) );
// value is valid
return TRUE;
// break from the switch
break;
}
case F_TYPE_UNUMERIC:
{
// if the value is not of unsigned numeric type, invalid value
if ( ! IsNumeric( pszValue, 10, FALSE ) )
return FALSE;
// check for the value in the list and return the result
// if values are pre-defined
if ( fcInfo.dwFlags & F_MODE_VALUES )
return ( InString( fcInfo.szValues, pszValue, TRUE ) );
// value is valid
return TRUE;
// break from the switch
break;
}
case F_TYPE_FLOAT:
case F_TYPE_DOUBLE:
{
// NOTE: Values attribute is ignored for this data type
// return the result of the type validation function itself
return ( IsFloatingPoint( pszValue ) );
// break from the switch
break;
}
case F_TYPE_DATE:
case F_TYPE_TIME:
case F_TYPE_DATETIME:
{
// break from the switch
break;
}
case F_TYPE_CUSTOM:
{
// check whether function pointer is specified or not
// if not specified, error
if ( fcInfo.pFunction == NULL )
return FALSE; // function ptr not specified ... error
// call the custom function
dwResult = (*fcInfo.pFunction)( pszProperty, pszOperator, pszValue,
fcInfo.pFunctionData == NULL ? &fcInfo : fcInfo.pFunctionData, NULL );
// check the result and return appropriately
if ( dwResult == F_FILTER_INVALID )
return FALSE;
else
return TRUE;
// break from the switch
break;
}
default:
{
// invalid configuration information
return FALSE;
// break from the switch
break;
}
}
// not a valid value
return FALSE;
}
// ***************************************************************************
// Routine Description:
//
// Arguments:
// [ in] szFilter = filter
// [ in ] arrOperators = Array of Operators
// [ in ] pfilterConfigs = filter configurations
// [ in ] pszProperty =property
// [ in ] pszOperator = operator
// [ in ] pszValue - value
//
// Return Value: Returns a long value
//
// ***************************************************************************
LONG __IdentifyFilterConfig( LPCTSTR szFilter,
TARRAY arrOperators,
PTFILTERCONFIG pfilterConfigs,
LPTSTR pszProperty, LPTSTR pszOperator, LPTSTR pszValue )
{
// local variables
DWORD dw = 0; // looping variable
LONG lPosition = 0; // used to result of 'find' function
LONG lIndex = 0;
DWORD dwOperators = 0; // holds the count of operators supported
LPTSTR pszBuffer = NULL;
__MAX_SIZE_STRING szTemp = NULL_STRING; // temporary string buffer
__MAX_SIZE_STRING szFmtFilter = NULL_STRING;
__MAX_SIZE_STRING szFmtOperator = NULL_STRING;
// check the input value
if ( szFilter == NULL || arrOperators == NULL || pfilterConfigs == NULL ||
pszProperty == NULL || pszOperator == NULL || pszValue == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return -1;
}
// get the filter info into local format buffer and change the case
lstrcpy( szFmtFilter, szFilter );
CharUpper( szFmtFilter );
// initially assume the filter is unknown and set the message
SetLastError( ERROR_DS_FILTER_UNKNOWN );
SaveLastError();
// traverse thru the list of operators available and check
// whether the filter is having any of the supported operator
dwOperators = DynArrayGetCount( arrOperators ); // no. of operators supported
for( dw = 0; dw < dwOperators; dw++ )
{
// get the operator
pszBuffer = ( LPTSTR ) DynArrayItemAsString2( arrOperators, dw, 0 );
if ( pszBuffer == NULL )
{
SetLastError( EVENT_E_INTERNALERROR );
SaveLastError();
return -1;
}
// ...
lstrcpy( pszOperator, pszBuffer );
lstrcpy( szFmtOperator, pszOperator ); // also get the operator
CharUpper( szFmtOperator ); // into format buffer and chane the case
// search for the current operator in the filter
// check whether the operator was found or not
// before processing, copy to the temp buffer and do manipulations on that
lstrcpy( szTemp, szFmtFilter );
if ( ( pszBuffer = _tcsstr( szTemp, szFmtOperator ) ) != NULL )
{
//
// operator was found
// extract the property, and value information
// => property name
// ( total length of the string - position where the operator starts )
// => value
// ( start position of operator + length of operator )
szTemp[ lstrlen( szTemp ) - lstrlen( pszBuffer ) ] = NULL_CHAR;
lstrcpy( pszProperty, szTemp );
// value might not have specified at all ... so be careful
if ( (pszBuffer + lstrlen(pszOperator)) != NULL )
{
// copy the value part
lstrcpy( pszValue, (pszBuffer + lstrlen(pszOperator)) );
//
// now cross-check whether the property name exists or not for the current
// operator.
// remove the leading and trailing spaces ( if any )
// in the property name and value
lstrcpy( pszValue, TrimString( pszValue, TRIM_ALL ) );
lstrcpy( pszProperty, TrimString( pszProperty, TRIM_ALL ) );
// check whether this property exists or not
// if found, return to the caller, else continue furthur
// this might match with some with some other operator
lPosition = DynArrayFindString2( arrOperators, dw, pszProperty, TRUE, 0 );
if ( lPosition > 1 )
{
// NOTE:
// we know that the property name if exist, starts from index number
// 2 only that is the reason why, the condition is > 1 is only valid
// get the corresponding filter config. info
lIndex = DynArrayItemAsLong2( arrOperators, dw, lPosition - 1 );
// now check whether the filter is having appropriate value
if ( __CheckValue( pfilterConfigs[ lIndex ], pszProperty, pszOperator, pszValue) )
{
//
// filter is having valid value
SetLastError( NOERROR );
SetReason( NULL_STRING );
// return the filter configuration index
return lIndex;
}
}
}
}
}
// filter is not valid
return -1;
}
//
// public functions ... exposed to external world
//
// ***************************************************************************
// Routine Description:
//
// Arguments:
// [ in ] dwCount = Count
// [ in ] pfilterConfigs = filter configurations
// [ in ] arrFilterArgs = filter arguments
// [ in ] parrParsedFilters = array of parsed filters
//
// Return Value:return a boolean value
//
// ***************************************************************************
BOOL ParseAndValidateFilter( DWORD dwCount,
PTFILTERCONFIG pfilterConfigs,
TARRAY arrFilterArgs, PTARRAY parrParsedFilters )
{
// local variables
DWORD dw = 0; // looping variables
DWORD dwFilters = 0; // holds the count of filters
LONG lIndex = 0; // index variable
LONG lNewIndex = 0; // index variable
BOOL bResult = FALSE; // holds the result of the filter validation
__MAX_SIZE_STRING szValue = NULL_STRING; // value specified in filter
__MAX_SIZE_STRING szOperator = NULL_STRING; // operator specified in filter
__MAX_SIZE_STRING szProperty = NULL_STRING; // property specified in filter
LPCTSTR pszFilter = NULL;
TARRAY arrOperators = NULL; // operator-wise filter configuration
// check the input value
if ( pfilterConfigs == NULL || arrFilterArgs == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return FALSE;
}
//
// parse the filter configuration information and customize the information
// to fasten the performance of the validating functionality
//
// create the dynamic array and prepare
arrOperators = CreateDynamicArray();
if ( arrOperators == NULL )
{
SetLastError( E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// ...
__PrepareOperators( dwCount, pfilterConfigs, arrOperators );
// check whether filters ( parsed ) needs to initialized
if ( parrParsedFilters != NULL && *parrParsedFilters == NULL )
{
*parrParsedFilters = CreateDynamicArray(); // create a dynamic array
if ( *parrParsedFilters == NULL )
{
SetLastError( E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
}
//
// now start validating the filter
//
// traverse through the filters information and validate them
bResult = TRUE; // assume that filter validation is passed
dwFilters = DynArrayGetCount( arrFilterArgs ); // count of filter specified
for( dw = 0; dw < dwFilters; dw++ )
{
// reset all the needed variables
lstrcpy( szValue, NULL_STRING );
lstrcpy( szOperator, NULL_STRING );
lstrcpy( szProperty, NULL_STRING );
// get the filter
pszFilter = DynArrayItemAsString( arrFilterArgs, dw );
if ( pszFilter == NULL )
{
// error occured
bResult = FALSE;
break; // break from the loop ... no need of furthur processing
}
// identify the filter config for the current filter
lIndex = __IdentifyFilterConfig( pszFilter,
arrOperators, pfilterConfigs, szProperty, szOperator, szValue );
// check whether the filter is found or not
if ( lIndex == -1 )
{
// filter found to be invalid
bResult = FALSE;
break; // break from the loop ... no need of furthur processing
}
// now that we found, current filter is having
// valid property name, operator and valid value
// save the parsed filter info and its corresponding filter configuration index
// in global dynamic array if it is available
if ( parrParsedFilters != NULL )
{
// append the filter info at the end of the array
lNewIndex = DynArrayAppendRow( *parrParsedFilters, F_PARSED_INFO_COUNT );
if ( lNewIndex == -1 )
{
SetLastError( E_OUTOFMEMORY );
SaveLastError();
return FALSE;
}
// ...
DynArraySetDWORD2( *parrParsedFilters, lNewIndex, F_PARSED_INDEX_FILTER, lIndex );
DynArraySetString2( *parrParsedFilters, lNewIndex, F_PARSED_INDEX_PROPERTY, szProperty, 0 );
DynArraySetString2( *parrParsedFilters, lNewIndex, F_PARSED_INDEX_OPERATOR, szOperator, 0 );
DynArraySetString2( *parrParsedFilters, lNewIndex, F_PARSED_INDEX_VALUE, szValue, 0 );
}
}
// destroy the operators array
DestroyDynamicArray( &arrOperators );
// return the filter validation result
return bResult;
}
// ***************************************************************************
// Routine Description:
//
// Arguments:
// [ in ] dwCount = count
// [ in ] filterConfigs[] = filter configurations
// [ in ] arrRecord = array of records
//
// [ ]arrParsedFilters = array of parsed filters
// Return Value:return a boolean value
//
// ***************************************************************************
BOOL CanFilterRecord( DWORD dwCount,
TFILTERCONFIG filterConfigs[],
TARRAY arrRecord, TARRAY arrParsedFilters )
{
// local variables
DWORD dw = 0; // looping variables
DWORD dwFilters = 0; // holds the total no. of filter available
DWORD dwOperator = 0; // holds the mask of the current filter
DWORD dwFilterIndex = 0;
DWORD dwCompareResult = 0; // holds the result of comparision
LPCTSTR pszTemp = NULL;
TARRAY arrTemp = NULL;
// prepare the operators mappings
DWORD dwOperatorsCount = 0;
TOPERATOR operators[] = {
{ MASK_EQ, OPERATOR_EQ },
{ MASK_NE, OPERATOR_NE },
{ MASK_GT, OPERATOR_GT },
{ MASK_LT, OPERATOR_LT },
{ MASK_GE, OPERATOR_GE },
{ MASK_LE, OPERATOR_LE }
};
// check the input value
if ( filterConfigs == NULL || arrRecord == NULL || arrParsedFilters == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return FALSE;
}
// traverse thru all the filters
dwFilters = DynArrayGetCount( arrParsedFilters );
dwOperatorsCount = sizeof( operators ) / sizeof( operators[ 0 ] );
for( dw = 0; dw < dwFilters; dw++ )
{
// get the current filter configuration index
dwFilterIndex = DynArrayItemAsDWORD2( arrParsedFilters, dw, F_PARSED_INDEX_FILTER );
// get the appropriate operator mask
pszTemp = DynArrayItemAsString2( arrParsedFilters, dw, F_PARSED_INDEX_OPERATOR );
if ( pszTemp == NULL )
continue;
// ...
dwOperator = __FindOperatorMask( dwOperatorsCount, operators, pszTemp );
// if the operator is undefined, the filter should have
// custom validation mask
if ( dwOperator == 0 &&
( filterConfigs[ dwFilterIndex ].dwFlags & F_TYPE_MASK ) != F_TYPE_CUSTOM )
return FALSE; // invalid filter configuration
// get the parsed filter info into local buffer
arrTemp = DynArrayItem( arrParsedFilters, dw );
if ( arrTemp == NULL )
return FALSE;
// do the comparision and get the result
if ( filterConfigs[ dwFilterIndex ].dwFlags & F_MODE_ARRAY )
{
dwCompareResult = __DoArrayComparision(
arrRecord, arrTemp, filterConfigs[ dwFilterIndex ] );
}
else
{
dwCompareResult = __DoComparision( arrRecord, arrTemp, filterConfigs[ dwFilterIndex ] );
}
// now check whether the current can be kept or not
// if the filter is failed, break from the loop so that this row can be deleted
if ( ( dwCompareResult & dwOperator ) == 0 )
break; // filter failed
}
// return the result of filter operation
return ( dw != dwFilters ); // TRUE : delete record, FALSE : keep record
}
// ***************************************************************************
// Routine Description:
//
// Arguments:
// [ in ] dwCount = count
// [ in ] filterConfigs[] = filter configurations
// [ in ] arrData = array of data
// [ in ] arrParsedFilters = array of parsed filters
//
// Return Value: Return a DWord
//
// ***************************************************************************
DWORD FilterResults( DWORD dwCount,
TFILTERCONFIG filterConfigs[],
TARRAY arrData, TARRAY arrParsedFilters )
{
// local variables
DWORD dw = 0; // looping variables
DWORD dwDeleted = 0;
DWORD dwRecords = 0; // holds the total no. of records
LPCTSTR szTemp = NULL;
TARRAY arrRecord = NULL;
// check the input value
if ( filterConfigs == NULL || arrData == NULL || arrParsedFilters == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return 0;
}
//
// start filtering the data
// get the count of filters and records
dwRecords = DynArrayGetCount( arrData );
// traverse thru all thru the data
for( dw = 0; dw < dwRecords; dw++ )
{
// get the current row ... this is just to increase fastness
arrRecord = DynArrayItem( arrData, dw );
if ( arrRecord == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return 0;
}
// check whether this record needs to be deleted or not
if ( CanFilterRecord( dwCount, filterConfigs, arrRecord, arrParsedFilters ) )
{
DynArrayRemove( arrData, dw ); // delete record
dw--; // adjust the next record position
dwRecords--; // also adjust the total no. of records information
dwDeleted++;
}
}
// return no. of records deleted
return dwDeleted;
}
// ***************************************************************************
// Routine Description:
// retuns the mathematical operator from english operator
//
// Arguments:
// [ in ] szOperator = mathematical (or) english operator
//
// Return Value:
// Return a mathematical operator
//
// ***************************************************************************
LPCTSTR FindOperator( LPCTSTR szOperator )
{
// local variables
DWORD dwMask = 0;
DWORD dwOperatorsCount = 0;
TOPERATOR operators[] = {
{ MASK_EQ, OPERATOR_EQ },
{ MASK_NE, OPERATOR_NE },
{ MASK_GT, OPERATOR_GT },
{ MASK_LT, OPERATOR_LT },
{ MASK_GE, OPERATOR_GE },
{ MASK_LE, OPERATOR_LE }
};
// check the input value
if ( szOperator == NULL )
{
SetLastError( ERROR_INVALID_PARAMETER );
SaveLastError();
return MATH_EQ;
}
// find the operator mask
dwOperatorsCount = sizeof( operators ) / sizeof( operators[ 0 ] );
dwMask = __FindOperatorMask( dwOperatorsCount, operators, szOperator );
switch ( dwMask )
{
case MASK_EQ:
return MATH_EQ;
break;
case MASK_NE:
return MATH_NE;
break;
case MASK_LT:
return MATH_LT;
break;
case MASK_GT:
return MATH_GT;
break;
case MASK_LE:
return MATH_LE;
break;
case MASK_GE:
return MATH_GE;
break;
default:
// default to be on safe side ... return '=' operator
return MATH_EQ;
break;
}
// defaul
return MATH_EQ;
}