windows-nt/Source/XPSP1/NT/admin/pchealth/sr/nttest/srdiag2/tstparam.cxx
2020-09-26 16:20:57 +08:00

2242 lines
57 KiB
C++

//+--------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1998.
//
// File: tstparam.cxx
//
// Synopsys: Test paramers container class implementation
//
// Classes: CTestParams, CParamNode
//
// Notes: The test parameter containers provide a layer of abstraction
// above the particular ways to pass test parameters -
// (command line, environment, registry...)
//
// History: 10-Sep-1998 georgis created
//
//---------------------------------------------------------------------------
#include "srheader.hxx"
#include <tstparam.hxx>
// Private macros to avoid some easy mistakes
#define RETURN(x) hr=x; goto ErrReturn;
#define ENTER_SYNC \
EnterCriticalSection(&m_sync); \
bEnterSync=TRUE; \
if (!m_bUsed) \
{ \
m_bUsed=TRUE; \
hr=NotifyOnFirstUse(); \
if (S_OK!=hr) \
{ \
RETURN(hr); \
} \
}
#define LEAVE_SYNC \
if (bEnterSync) \
{ \
LeaveCriticalSection(&m_sync); \
}
//+--------------------------------------------------------------------------
//
// Function: CalculateHashValue
//
// Synopsys: Calculates hash value for asciiz string
// (case insensitive)
//
// Parameters: pszName: the string
//
// Returns: the hash value (the first 4 characters are used)
//
// History: 29-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
DWORD CalculateHashValue(LPCWSTR pwszName)
{
DH_ASSERT(NULL!=pwszName);
DWORD dwLen=(DWORD)wcslen(pwszName);
DWORD dwTemp=0;
for (DWORD dwIndex=0; dwIndex<2; dwIndex++)
{
dwTemp<<=16;
if (dwIndex<dwLen)
{
dwTemp|=towlower(pwszName[dwIndex]);
}
}
return dwTemp;
};
//+--------------------------------------------------------------------------
//
// Function: Unicode2Escaped
//
// Synopsys: Converts Unicode string to escaped ascii string
//
// Parameters: [in] pwszString: the source unicode string
// [out] ppszString: return the ptr to escaped ascii string here
// [in] dwEscapeMode: Escape mode
//
// History: 10-Nov-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT Unicode2Escaped(
LPCWSTR pwszString,
char ** ppszString,
DWORD dwEscapeMode)
{
HRESULT hr=S_OK;
char * pszEscaped=NULL;
char * pszDest=NULL;
LPCWSTR pwszSrc=NULL;
DWORD dwSize=0;
BOOL bNeedEscape=FALSE;
DH_VDATEPTROUT(ppszString,LPSTR);
*ppszString=NULL;
// if NULL passed, just return NULL
if (NULL==pwszString)
{
return S_OK;
}
// Count the size needed for the escaped string
dwSize=0;
for (pwszSrc=pwszString; 0!=*pwszSrc; pwszSrc++)
{
if (ESCAPE_NOTNEEDED(*pwszSrc))
{
dwSize++;
}
else
{
bNeedEscape=TRUE;
dwSize+=5; // $xxxx format
}
}
// Allocate memory for the escaped string
// Eventually put the prefix
if ((ESCAPEMODE_PREFIX_ALWAYS==dwEscapeMode)||
(ESCAPEMODE_PREFIX_IFCHANGED==dwEscapeMode)&&bNeedEscape)
{
pszEscaped=new char [dwSize+2]; // the ESCAPED_MARKER and ending 0
DH_ABORTIF(NULL==pszEscaped,E_OUTOFMEMORY,TEXT("new"));
pszDest=pszEscaped;
*pszDest++=ESCAPED_MARKER;
}
else
{
pszEscaped=new char [dwSize+1]; // ending 0
DH_ABORTIF(NULL==pszEscaped,E_OUTOFMEMORY,TEXT("new"));
pszDest=pszEscaped;
}
// Translate
for (pwszSrc=pwszString; 0!=*pwszSrc; pwszSrc++)
{
if (ESCAPE_NOTNEEDED(*pwszSrc))
{
*pszDest++=(char)*pwszSrc;
}
else
{
*pszDest++=ESCAPE_CHARACTER;
sprintf(pszDest,"%04x",*pwszSrc);
pszDest+=4;
}
}
*pszDest=0;
ErrReturn:
if (S_OK==hr)
{
*ppszString=pszEscaped;
}
else
{
delete pszEscaped;
}
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: Unicode2Escaped (unicode->unicode)
//
// Synopsys: Converts Unicode string to escaped ascii string
//
// Parameters: [in] pwszString: the source unicode string
// [out] ppwszString: return the ptr to escaped ascii string here
// [in] dwEscapeMode: Escape mode
//
// History: 10-Nov-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT Unicode2Escaped(
LPCWSTR pwszString,
LPWSTR* ppwszString,
DWORD dwEscapeMode)
{
HRESULT hr=S_OK;
char * pszEscaped=NULL;
DH_VDATEPTROUT(ppwszString,LPWSTR);
hr=Unicode2Escaped(pwszString,&pszEscaped,dwEscapeMode);
if ((S_OK==hr)&&(NULL!=pszEscaped))
{
hr=CopyString(pszEscaped,ppwszString);
}
else
{
*ppwszString=NULL;
}
delete pszEscaped;
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: Escaped2Unicode
//
// Synopsys: Converts Unicode string to escaped ascii string
//
// Parameters: [in] pszEscaped: the source escaped ascii string
// [out] ppwszString: return the ptr to unescaped unicode string
// [in] dwEscapeMode: escape mode
//
// History: 10-Nov-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT Escaped2Unicode(
const char * pszEscaped,
LPWSTR *ppwszString,
DWORD dwEscapeMode)
{
HRESULT hr=S_OK;
LPWSTR pwszDest=NULL;
LPWSTR pwszUnescaped=NULL;
const char * pszSrc=NULL;
DWORD dwSize=0;
int iTemp=0;
DH_VDATEPTROUT(ppwszString,LPWSTR);
*ppwszString=NULL;
// if NULL passed, just return NULL
if (NULL==pszEscaped)
{
return S_OK;
}
// Check for the escaped string marker
switch (dwEscapeMode)
{
case ESCAPEMODE_PREFIX_ALWAYS:
DH_ABORTIF(ESCAPED_MARKER!=*pszEscaped,E_UNEXPECTED,
TEXT("Bad escaped source string"));
pszEscaped++;
break;
case ESCAPEMODE_PREFIX_IFCHANGED:
if (ESCAPED_MARKER==*pszEscaped)
{
pszEscaped++;
}
break;
case ESCAPEMODE_PREFIX_NEVER:
break;
default:
hr=E_INVALIDARG;
DH_HRCHECK_ABORT(hr,TEXT("Bad escape mode"));
}
// Count the size needed for the escaped string
dwSize=0;
for (pszSrc=pszEscaped; 0!=*pszSrc; pszSrc++)
{
if (ESCAPE_CHARACTER==*pszSrc)
{
pszSrc+=4;
}
else
{
DH_ABORTIF(!ESCAPE_NOTNEEDED(*pszSrc),E_UNEXPECTED,
TEXT("Bad symbol in the escaped string"));
}
dwSize++;
}
// Allocate memory for the unescaped string
pwszUnescaped=new WCHAR [dwSize+1];
DH_ABORTIF(NULL==pwszUnescaped,E_OUTOFMEMORY,TEXT("new"));
// Translate
pwszDest=pwszUnescaped;
for (pszSrc=pszEscaped; 0!=*pszSrc; pwszDest++)
{
if (ESCAPE_CHARACTER==*pszSrc)
{
pszSrc++;
// sscanf can read hex, but the output buffer must be
// unsigned integer of the default int size, which is more
// then sizeof(wchar)
sscanf(pszSrc,"%04x",&iTemp);
*pwszDest=(WCHAR)iTemp;
pszSrc+=4;
}
else
{
*pwszDest=(WCHAR)*pszSrc++;
}
}
*pwszDest=0;
ErrReturn:
if (S_OK==hr)
{
*ppwszString=pwszUnescaped;
}
else
{
delete pwszUnescaped;
}
return hr;
}
//+--------------------------------------------------------------------------
//
// Function: Escaped2Unicode (unicode->unicode)
//
// Synopsys: Converts Unicode string to escaped ascii string
//
// Parameters: [in] pwszEscaped: the source escaped string (unicode)
// [out] ppwszString: return the ptr to unescaped unicode string
// [in] dwEscapeMode: escape mode
//
// History: 10-Nov-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT Escaped2Unicode(
LPCWSTR pwszEscaped,
LPWSTR *ppwszString,
DWORD dwEscapeMode)
{
HRESULT hr=S_OK;
char *pszTemp=NULL;
DH_VDATEPTROUT(ppwszString,LPWSTR);
if (NULL!=pwszEscaped)
{
hr=CopyString(pwszEscaped,&pszTemp);
}
if (S_OK==hr)
{
hr=Escaped2Unicode(pszTemp,ppwszString,dwEscapeMode);
}
else
{
*ppwszString=NULL;
}
delete pszTemp;
return hr;
}
//+--------------------------------------------------------------------------
//
// Constructor: CParamNode::CParamNode
//
// Synopsys: Initializes the parameter node as empty
//
// Arguments: dwFlags: General param info : source,priority,used
//
// History: 29-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
CParamNode::CParamNode(DWORD dwFlags)
{
m_dwFlags=dwFlags;
m_pwszName=NULL;
m_pwszValue=NULL;
m_pNext=NULL;
}
//+--------------------------------------------------------------------------
//
// Destructor: CParamNode::~CParamNode
//
// Synopsys: Releases the resources used by the parameter node
//
// History: 29-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
CParamNode::~CParamNode()
{
delete m_pwszName;
delete m_pwszValue;
}
//+--------------------------------------------------------------------------
//
// Method: CParamNode::Init
//
// Synopsys: Allocates memory for parameter Name and Value
//
// Parameters: pszName: the parameter name
// pszValue: the parameter value
//
// History: 29-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CParamNode::Init(LPCWSTR pwszName, LPCWSTR pwszValue)
{
HRESULT hr=S_OK;
DH_ASSERT(NULL!=pwszName);
DH_ASSERT(NULL==m_pwszName); // ensure the object is empty
hr=CopyString(pwszName,&m_pwszName);
if (S_OK==hr)
{
m_dwHashValue=CalculateHashValue(pwszName);
if (NULL!=pwszValue)
{
hr=CopyString(pwszValue,&m_pwszValue);
}
}
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CParamNode::ChangeValue
//
// Synopsys: Changes the parameter value
//
// Parameters: pszValue: the parameter value
// dwFlags: parameter info (source,usage,priority)
//
// History: 29-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CParamNode::ChangeValue(LPCWSTR pwszValue, DWORD dwFlags)
{
HRESULT hr=S_OK;
DH_ASSERT(dwFlags>0);
// Ensure we don't override used parameters unless asked
if (PARAMMASK_USAGE & m_dwFlags)
{
if ((dwFlags & PARAMFLAG_OVERRIDEUSED)&&
!(PARAMMASK_USAGE & (m_dwFlags & ~dwFlags)))
{
RETURN(E_ACCESSDENIED); // Can't override this type of usage
}
}
// Ensure we don't override higher priority parameters
if ((dwFlags & PARAMMASK_PRIORITY) < (m_dwFlags & PARAMMASK_PRIORITY))
{
if (dwFlags & PARAMFLAG_MUSTSET)
{
RETURN(E_ACCESSDENIED);
}
else
{
RETURN(S_OK);
}
}
m_dwFlags=dwFlags;
delete m_pwszValue;
m_pwszValue=NULL;
if (NULL!=pwszValue)
{
hr=CopyString(pwszValue,&m_pwszValue);
}
ErrReturn:
return hr;
}
//+--------------------------------------------------------------------------
//
// Constructor: CTestParams::CTestParams (public)
//
// Synopsys: Initializes the parameter container as empty
//
// History: 10-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
CTestParams::CTestParams()
{
m_pParamsList=NULL;
m_dwUsageInfo=PARAMUSAGE_GENERAL;
m_bUsed=FALSE;
InitializeCriticalSection(&m_sync);
}
//+--------------------------------------------------------------------------
//
// Destructor: CTestParams::~CTestParams (public)
//
// Synopsys: Releases the resources used by the parameter container object
//
// History: 15-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
CTestParams::~CTestParams()
{
EnterCriticalSection(&m_sync);
CParamNode *pNext=NULL;
for (CParamNode *pNode=m_pParamsList;
NULL!=pNode;
pNode=pNext)
{
pNext=pNode->m_pNext;
delete pNode;
}
DeleteCriticalSection(&m_sync);
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::GetParam (public, synchronized)
//
// Synopsys: Reads parameter of given name:format
//
// Arguments: pszName: The parameter definition string
// pTarget: the addres of the variable which receives the result
//
// Returns: S_OK on success,
// S_FALSE if the parameter is not present,
// E_FAIL if the format given is incompatible with the param value
// or HRESULT error code (E_INVALIDARG, E_OUTOFMEMORY)
//
// Notes: The parameter definition string must be in format name:format
// where name is the name which identyfies the parameter and
// format shows how to read this parameter.
// E.g. "my_int:%i"
//
// Formats may be of two types:
// 1) Any standard sscanf formats starting with %
// E.g. %i %u %d %lx %s ...
//
// 2) Custom formats
// bool - read BOOL (*pTarget is BOOL)
// cstr - read constant string (*pTarget is const char*)
// astr - heap allocated ascii string (*pTarget is char*)
// tstr - heap allocated TCHAR string (*pTarget is LPTSTR)
// olestr - heap allocated OLESTR string (*pTarget is LPOLESTR)
//
// For the heap allocated formats the string obtained is writable,
// and the caller is responsible for deleting it.
//
// History: 09-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::GetParam(const char *pszName, void* pTarget)
{
HRESULT hr=S_OK;
BOOL bEnterSync=FALSE;
LPWSTR pwszTemp=NULL;
LPWSTR pwszFormat=NULL;
CParamNode *pPrev=NULL; // not used
CParamNode *pNode=NULL;
if ((NULL==pszName)||(NULL==pTarget))
{
RETURN(E_INVALIDARG);
}
hr=CopyString(pszName,&pwszTemp);
if (S_OK!=hr)
{
RETURN(hr);
}
pwszFormat=wcschr(pwszTemp,L':');
if (NULL==pwszFormat)
{
RETURN(E_INVALIDARG);
}
*pwszFormat++=0;
ENTER_SYNC;
pNode=FindParam(pwszTemp,&pPrev);
// for BOOL we always succed, eventyally seting the parameter
// to FALSE if the switch is not found or has value "FALSE"
if (!_wcsicmp(PARAMFMT_BOOL,pwszFormat))
{
if ((NULL!=pNode)&&
((NULL==pNode->m_pwszValue)||_wcsicmp(L"FALSE",pNode->m_pwszValue)))
{
*(BOOL*)pTarget=TRUE;
pNode->MarkAsUsed(m_dwUsageInfo);
}
else
{
*(BOOL*)pTarget=FALSE;
}
RETURN(S_OK);
}
if (NULL==pNode)
{
RETURN(S_FALSE); // Not found
}
else
{
pNode->MarkAsUsed(m_dwUsageInfo);
}
// Process standard sscanf formats
if (L'%'==*pwszFormat)
{
if (NULL==pNode->m_pwszValue)
{
RETURN(E_FAIL); // Found, but has no value
}
if (0<swscanf(pNode->m_pwszValue,pwszFormat,pTarget))
{
RETURN(S_OK);
}
else
{
RETURN(E_FAIL); // sscanf failed - incompatible format
}
}
else // custom format
{
hr=GetCustomFmtParam(pwszFormat,pNode->m_pwszValue,pTarget);
RETURN(hr);
}
ErrReturn:
LEAVE_SYNC;
delete pwszTemp;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::GetCustomFmtParam (private)
//
// Synopsys: Extracts custom format parameter
//
// Arguments: pszFormat: The custom format.
// pszValue: The value as string
// pTarget: the addres of the variable which receives the result
//
// Custom formats:
// cstr - read constant string (*pTarget is const char*)
// astr - heap allocated ascii string (*pTarget is char*)
// tstr - heap allocated TCHAR string (*pTarget is LPTSTR)
// olestr - heap allocated OLESTR string (*pTarget is LPOLESTR)
//
//
// History: 10-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::GetCustomFmtParam(LPCWSTR pwszFormat, LPCWSTR pwszValue, void* pTarget)
{
HRESULT hr=S_OK;
DH_ASSERT(NULL!=pwszFormat);
DH_ASSERT(NULL!=pTarget);
// ASCII, allocated in heap
if (!wcscmp(PARAMFMT_ASTR,pwszFormat))
{
if (NULL!=pwszValue)
{
hr=CopyString(pwszValue,(char**)pTarget);
RETURN(hr);
}
else
{
*(char**)pTarget=NULL;
RETURN(E_FAIL);
}
}
// TSTR allocated in heap
if (!wcscmp(PARAMFMT_TSTR,pwszFormat))
{
if (NULL!=pwszValue)
{
hr=CopyString(pwszValue,(LPTSTR*)pTarget);
RETURN(hr);
}
else
{
*(LPTSTR*)pTarget=NULL;
RETURN(E_FAIL);
}
}
// OLESTR allocated in heap
if (!wcscmp(PARAMFMT_OLESTR,pwszFormat))
{
if (NULL!=pwszValue)
{
hr=CopyString(pwszValue,(LPOLESTR*)pTarget);
RETURN(hr);
}
else
{
*(LPOLESTR*)pTarget=NULL;
RETURN(E_FAIL);
}
}
// Unknown type
hr=E_FAIL;
ErrReturn:
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::IsPresent (public, synchronized)
//
// Synopsys: Retruns TRUE if the parameter is present
// and FALSE if not or error occurs
//
// Arguments: pszName: The parameter definition string
//
// Note: The preferred way to handle BOOL parameters is
// using GETPARAM*("name:bool"), which enables parameters
// to be overwriten by cmd line e.g.
// registry: REG_SZ myparam (existing, value do not matter)
// cmdline: /myparam:false
// The result of GETPARAM("myparam:bool") is FALSE,
// while IsPresent("myparam") will return TRUE,
// with or without cmdline switch /myparam:false
//
// History: 19-Oct-1998 georgis Created
//
//---------------------------------------------------------------------------
BOOL __cdecl CTestParams::IsPresent(const char *pszName, ...)
{
HRESULT hr=S_OK;
BOOL bEnterSync=FALSE;
LPWSTR pwszTemp=NULL;
LPWSTR pwszFormat=NULL;
CParamNode *pPrev=NULL; // not used
CParamNode *pNode=NULL;
if (NULL==pszName)
{
return FALSE;
}
// if the param definition string contains format,
// extract name only
if (S_OK!=CopyString(pszName,&pwszTemp))
{
return FALSE;
}
pwszFormat=wcschr(pwszTemp,L':');
if (NULL!=pwszFormat)
{
*pwszFormat=0;
}
ENTER_SYNC;
pNode=FindParam(pwszTemp,&pPrev);
ErrReturn:
LEAVE_SYNC;
delete pwszTemp;
return (NULL!=pNode);
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::SetParam (public)
//
// Synopsys: Sets the parameter of given name:format
//
// Arguments: pszName: The parameter definition string
// pTarget: the addres of the variable containig the param value
//
// Returns: S_OK on success,
// E_FAIL if the format given is incompatible with the param value
// or HRESULT error code (E_INVALIDARG, E_OUTOFMEMORY)
//
// Notes: The parameter definition string must be in format name:format
// where name is the name which identyfies the parameter and
// format shows how to read this parameter.
// E.g. "my_string:cstr"
//
// Formats may be of two types:
// 1) Standard sscanf formats
// Only formats
// %s %d %i %x %ld %lx %u %lu %ld, and %I64* are supported
//
// 2) Custom formats
// bool - read BOOL (*pTarget is BOOL)
// cstr - read constant string (*pTarget is const char*)
// astr - heap allocated ascii string (*pTarget is char*)
// tstr - heap allocated TCHAR string (*pTarget is LPTSTR)
// olestr - heap allocated OLESTR string (*pTarget is LPOLESTR)
//
// For the heap allocated formats the string obtained is writable,
// and the caller is responsible for deleting it.
//
// History: 17-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::SetParam(const char *pszName, void* pTarget, DWORD dwFlags)
{
HRESULT hr=S_OK;
LPWSTR pwszTempName=NULL;
LPWSTR pwszFormat=NULL;
if ((NULL==pszName)||(NULL==pTarget)||
(0==(PARAMMASK_SOURCE & dwFlags)))
{
RETURN(E_INVALIDARG);
}
hr=CopyString((char*)pszName,&pwszTempName);
if (S_OK!=hr)
{
RETURN(hr);
}
pwszFormat=wcschr(pwszTempName,L':');
if (NULL==pwszFormat)
{
RETURN(E_INVALIDARG);
}
*pwszFormat++=0;
hr=SetCustomFmtParam(pwszTempName,pwszFormat,pTarget,dwFlags);
ErrReturn:
delete pwszTempName;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::SetCustomFmtParam (private)
//
// Synopsys: Adds custom format parameter
//
// Arguments: pszName: The parameter name
// pszFormat: The custom format.
// pTarget: the addres of the variable which contains the value
//
// Custom formats:
// bool - BOOL (*pTarget is BOOL)
// cstr - ascii string (*pTarget is char*)
// tstr - TCHAR string (*pTarget is LPTSTR)
// olestr - OLESTR string (*pTarget is LPOLESTR)
//
//
// History: 17-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::SetCustomFmtParam(
LPCWSTR pwszName,
LPCWSTR pwszFormat,
void* pTarget,
DWORD dwFlags)
{
HRESULT hr=S_OK;
DH_ASSERT(NULL!=pwszName);
DH_ASSERT(NULL!=pwszFormat);
DH_ASSERT(NULL!=pTarget);
DH_ASSERT((PARAMMASK_SOURCE & dwFlags)>0);
LPWSTR pwszTempValue=NULL;
WCHAR wszTemp[21]; // enough to print even 64bit integers
// BOOL
if (!wcscmp(PARAMFMT_BOOL,pwszFormat))
{
if (*(BOOL*)pTarget)
{
hr=AddParam(pwszName,NULL,dwFlags);
RETURN(hr);
}
else
{
hr=AddParam(pwszName,L"FALSE",dwFlags);
RETURN(hr);
}
}
// Int
if (!_wcsicmp(L"%i",pwszFormat)||
!_wcsicmp(L"%d",pwszFormat)||
!_wcsicmp(L"%u",pwszFormat)||
!_wcsicmp(L"%lu",pwszFormat)||
!_wcsicmp(L"%lx",pwszFormat)||
!_wcsicmp(L"%ld",pwszFormat)||
!_wcsicmp(L"%x",pwszFormat))
{
if (1>swprintf(wszTemp,pwszFormat,*(long*)pTarget))
{
RETURN(E_FAIL);
}
hr=AddParam(pwszName,wszTemp,dwFlags);
RETURN(hr);
}
// I64 values
if (!_wcsnicmp(L"%I64",pwszFormat,4))
{
if (1>swprintf(wszTemp,pwszFormat,*(ULONGLONG*)pTarget))
{
RETURN(E_FAIL);
}
hr=AddParam(pwszName,wszTemp,dwFlags);
RETURN(hr);
}
// CONST ASCII - just pass the pszValue as pointer
if (!_wcsicmp(L"%s",pwszFormat))
{
hr=AddParam(pwszName,(LPCWSTR)pTarget,dwFlags);
RETURN(hr);
}
// ASTR
if (!wcscmp(PARAMFMT_ASTR,pwszFormat))
{
if (NULL!=*(char*)pTarget)
{
hr=CopyString((char*)pTarget,&pwszTempValue);
}
if (S_OK==hr)
{
hr=AddParam(pwszName,pwszTempValue,dwFlags);
}
RETURN(hr);
}
// TSTR
if (!wcscmp(PARAMFMT_TSTR,pwszFormat))
{
if (NULL!=*(LPTSTR*)pTarget)
{
hr=CopyString((LPTSTR)pTarget,&pwszTempValue);
}
if (S_OK==hr)
{
hr=AddParam(pwszName,pwszTempValue,dwFlags);
}
RETURN(hr);
}
// OLESTR
if (!_wcsicmp(PARAMFMT_OLESTR,pwszFormat))
{
if (NULL!=*(LPOLESTR*)pTarget)
{
hr=CopyString((LPOLESTR)pTarget,&pwszTempValue);
}
if (S_OK==hr)
{
hr=AddParam(pwszName,pwszTempValue,dwFlags);
}
RETURN(hr);
}
// Unknown type
hr=E_INVALIDARG;
ErrReturn:
delete pwszTempValue;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::FindParam (private)
//
// Synopsys: Finds given parameter in the list
//
// Arguments: pszName: Parameter name
// ppPrev: if not NULL, retrun the previous node here on success
//
// Returns: Pointer to the parmeter node
//
// History: 29-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
CParamNode* CTestParams::FindParam(LPCWSTR pwszName, CParamNode** ppPrev)
{
CParamNode *pNode=NULL;
DH_ASSERT(NULL!=pwszName);
DH_ASSERT(NULL!=ppPrev);
DWORD dwHashValue=CalculateHashValue(pwszName);
for (pNode=m_pParamsList;
NULL!=pNode;
*ppPrev=pNode, pNode=pNode->m_pNext)
{
if (dwHashValue>pNode->m_dwHashValue)
{
continue;
}
else if (dwHashValue<pNode->m_dwHashValue)
{
return NULL;
}
else // Equal hash values
{
int i=_wcsicmp(pwszName,pNode->m_pwszName);
if (i>0)
{
continue;
}
else if (i<0)
{
return NULL;
}
else
{
return pNode;
}
}
}
return NULL;
};
//+--------------------------------------------------------------------------
//
// Method: CTestParams::AddParam (public, synchronized)
//
// Synopsys: Adds a parameter to the container
//
// Arguments: pszName: The parameter name
// pszValue: The parameter value as string
// dwFlags: Param info (source,priority,usage)
//
// Returns: S_OK on success,
// or HRESULT error code (E_INVALIDARG, E_OUTOFMEMORY)
//
// History: 29-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::AddParam(
LPCWSTR pwszName,
LPCWSTR pwszValue,
DWORD dwFlags,
BOOL bWasQuoted)
{
HRESULT hr=S_OK;
BOOL bEnterSync=FALSE;
CParamNode *pPrev=NULL;
CParamNode *pParam=NULL;
LPWSTR pwszTemp=NULL;
if ((NULL==pwszName)||(0==(PARAMMASK_SOURCE & dwFlags)))
{
RETURN(E_INVALIDARG);
}
if ((NULL!=pwszValue)&&
(ESCAPED_MARKER==*pwszValue)&&
(!bWasQuoted))
{
hr=Escaped2Unicode(pwszValue,&pwszTemp,ESCAPEMODE_PREFIX_ALWAYS);
if (S_OK!=hr)
{
RETURN(hr);
}
pwszValue=pwszTemp;
}
ENTER_SYNC;
pParam=FindParam(pwszName,&pPrev);
if (NULL!=pParam) // The parameter is known => try to change the value
{
hr=pParam->ChangeValue(pwszValue,dwFlags);
RETURN(hr);
}
else // new parameter
{
// Create and initialize new parameter node
pParam=new CParamNode(dwFlags);
if (NULL==pParam)
{
RETURN(E_OUTOFMEMORY);
}
hr=pParam->Init(pwszName,pwszValue);
if (S_OK!=hr)
{
RETURN(hr);
}
// Insert in the list
if (NULL==pPrev)
{
// Add as first node
pParam->m_pNext=m_pParamsList;
m_pParamsList=pParam;
}
else
{
// Add after pPrev
pParam->m_pNext=pPrev->m_pNext;
pPrev->m_pNext=pParam;
}
RETURN(S_OK);
}
ErrReturn:
if (S_OK!=hr)
{
delete pParam;
}
else // Mark the repro info params as used
{
if (PARAMFLAG_REPROINFO & dwFlags)
{
pParam->MarkAsUsed(dwFlags);
}
}
LEAVE_SYNC;
delete pwszTemp;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::DeleteParam (public, synchronized)
//
// Synopsys: Deletes given arameter from the string table
//
// Arguments: pszName: Parameter name
//
// Returns: S_OK if the param was not found or successifully deleted
// or E_INVALIDARG
//
// Notes: Deleting parmeters do not cause reallocation of
// the string table to smaller size.
//
// History: 10-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::DeleteParam(const char *pszName)
{
HRESULT hr=S_OK;
BOOL bEnterSync=FALSE;
CParamNode *pPrev=NULL;
CParamNode *pParam=NULL;
LPWSTR pwszName=NULL;
if (NULL==pszName)
{
RETURN(E_INVALIDARG);
}
hr=CopyString(pszName,&pwszName);
if (S_OK!=hr)
{
RETURN(hr);
}
ENTER_SYNC;
pParam=FindParam(pwszName, &pPrev);
if (NULL==pParam)
{
RETURN(S_OK); // the param is not present anyway
}
if (NULL==pPrev)
{
DH_ASSERT(m_pParamsList==pParam);
m_pParamsList=pParam->m_pNext;
}
else
{
pPrev->m_pNext=pParam->m_pNext;
}
ErrReturn:
delete pParam;
delete pwszName;
LEAVE_SYNC;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::ReadCommandLine (public)
//
// Synopsys: Reads all the swithes from the command line
// to the parameter container.
//
// Parameters: pszCommandLine: the command line
// or NULL => use GetCommandLine()
//
// Returns: S_OK on success or E_OUTOFMEMORY
//
// History: 10-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::ReadCommandLine(LPCTSTR ptszCommandLine, DWORD dwFlags)
{
LPWSTR pwszCmdLine=NULL;
LPWSTR pwszName=NULL;
LPWSTR pwszValue=NULL;
LPWSTR pwszEnd=NULL;
HRESULT hr=S_OK;
BOOL bQuoted=FALSE;
// If the ptszCommandLine is not given use GetCommandLine
if (NULL!=ptszCommandLine)
{
hr=CopyString(ptszCommandLine,&pwszCmdLine);
if(S_OK!=hr)
{
RETURN(hr);
}
}
else
{
hr=CopyString(GetCommandLine(),&pwszCmdLine);
if(S_OK!=hr)
{
RETURN(hr);
}
}
// Loop for command line switches
pwszName=pwszCmdLine;
while ((NULL!=pwszName)&&(0!=*pwszName))
{
bQuoted=FALSE;
// Find switch begining with /
while ((0!=*pwszName)&&('/'!=*pwszName))
{
pwszName++;
}
if (0==*pwszName)
{
RETURN(S_OK);
}
// Find switch value
pwszValue=++pwszName;
while ((0!=*pwszValue)&&(' '!=*pwszValue)&&(':'!=*pwszValue))
{
pwszValue++;
}
switch (*pwszValue)
{
case 0: // we hit the end
pwszEnd=NULL;
pwszValue=NULL;
break;
case ' ': // parameter has no value
pwszEnd=pwszValue;
*pwszEnd++=0;
pwszValue=NULL;
break;
case ':': // parameter with value
*pwszValue++=0;
if ('"'!=*pwszValue) //string without spaces
{
pwszEnd=pwszValue;
while ((0!=*pwszEnd)&&(' '!=*pwszEnd))
{
pwszEnd++;
}
if (0!=*pwszEnd)
{
*pwszEnd++=0;
}
else
{
pwszEnd=NULL;
}
}
else // get quoted string
{
pwszEnd=++pwszValue;
while ((0!=*pwszEnd)&&('"'!=*pwszEnd))
{
pwszEnd++;
}
if ('"'==*pwszEnd)
{
*pwszEnd++=0;
bQuoted=TRUE;
break;
}
else // the string ended before the closing quote
{
RETURN(E_UNEXPECTED);
}
}
} // case end
hr=AddParam(pwszName,pwszValue,dwFlags,bQuoted);
if (S_OK!=hr)
{
RETURN(hr);
}
pwszName=pwszEnd;
}// parameter loop end
ErrReturn:
delete pwszCmdLine;
return hr;
};
//+--------------------------------------------------------------------------
//
// Method: CTestParams::ReadEnvironment (public)
//
// Synopsys: Copies all the environment vars to the parameter container.
//
// Returns: S_OK on success,
// or HRESULT error code (E_UNEXPECTED, E_OUTOFMEMORY)
//
// Note: The prefix should be always in upper case
//
// History: 10-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::ReadEnvironment(LPCWSTR pwszPrefix, DWORD dwFlags)
{
HRESULT hr=S_OK;
LPWSTR pwszTemp=NULL;
LPWSTR pwszName=NULL;
LPWSTR pwszValue=NULL;
int i=0;
int iLen=0;
// HACK - call getenv so that the system will create environment
// which can be accessed using the _tenviron
_tgetenv(TEXT("COMPUTRNAME"));
if (NULL==_tenviron)
{
RETURN(E_UNEXPECTED);
}
// Prepare the prefix length
if (NULL!=pwszPrefix)
{
iLen=(int)wcslen(pwszPrefix);
}
for (i=0; NULL!=_tenviron[i]; i++)
{
hr=CopyString(_environ[i],&pwszTemp);
if (S_OK!=hr)
{
RETURN(hr);
}
pwszValue=wcschr(pwszTemp,L'=');
DH_ASSERT(NULL!=pwszValue)
*pwszValue++=0; // cut the param name, get the value
if ((NULL==pwszPrefix)|| // no prefix
(!_wcsnicmp(pwszPrefix,pwszTemp,iLen))) // prefix maches
{
pwszName=pwszTemp+iLen; // cut the prefix
hr=AddParam(pwszName,pwszValue,dwFlags);
if (S_OK!=hr)
{
RETURN(hr);
}
}
delete pwszTemp;
pwszTemp=NULL;
}
ErrReturn:
delete pwszTemp;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::ReadRegistry (public)
//
// Synopsys: Reads the string values in the given registry key
// to the parameter container
//
// Returns: S_OK on success,
// or HRESULT error code (E_INVALIDARG, E_OUTOFMEMORY)
//
// Note: All non-string values under this key are currently ignored,
// as well as all too large string.
//
// Returns: S_OK on success, or HRESULT error code
//
// History: 10-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::ReadRegistry(HKEY hBaseKey, LPCTSTR ptszKeyName, DWORD dwFlags)
{
HRESULT hr=S_OK;
DWORD dwResult=ERROR_SUCCESS;
HKEY hKey=0;
TCHAR atszTempName[MAX_REGSTRLEN];
TCHAR atszTempValue[MAX_REGSTRLEN];
DWORD dwNameSize=0;
DWORD dwValueSize=0;
DWORD dwType=REG_SZ;
int i=0;
if ((0==hBaseKey)||(NULL==ptszKeyName))
{
RETURN(E_INVALIDARG);
}
dwResult=RegOpenKey(hBaseKey,ptszKeyName,&hKey);
if ((ERROR_SUCCESS!=dwResult)||(0==hKey))
{
RETURN(HRESULT_FROM_WIN32(dwResult));
}
// Loop for all the registry values
for (i=0; dwResult==ERROR_SUCCESS; i++)
{
dwNameSize = ARRAYSIZE(atszTempName);
dwValueSize = ARRAYSIZE(atszTempValue);
dwResult=RegEnumValue(
hKey,
i,
(LPTSTR)atszTempName,
&dwNameSize,
NULL,
&dwType,
(BYTE*)atszTempValue,
&dwValueSize);
if (ERROR_NO_MORE_ITEMS==dwResult)
{
RETURN(S_OK);
}
else if (ERROR_SUCCESS==dwResult)
{
// We won't take very big strings, or not strings
if ((dwType!=REG_SZ)||
(dwNameSize>=ARRAYSIZE(atszTempName))||
(dwValueSize>=ARRAYSIZE(atszTempValue)))
{
// BUGBUG: trace warning here
continue;
}
else
{
#ifndef UNICODE
WCHAR awszTempName[MAX_REGSTRLEN];
WCHAR awszTempValue[MAX_REGSTRLEN];
hr = CopyString(atszTempName,
awszTempName,
ARRAYSIZE(atszTempName)-1,
ARRAYSIZE(atszTempName)-1);
if (S_OK!=hr)
{
RETURN(hr);
}
hr = CopyString(atszTempValue,
awszTempValue,
ARRAYSIZE(atszTempValue)-1,
ARRAYSIZE(atszTempValue)-1);
if (S_OK!=hr)
{
RETURN(hr);
}
HRESULT hr=AddParam(
awszTempName,
awszTempValue,
dwFlags);
#else
HRESULT hr=AddParam(
atszTempName,
atszTempValue,
dwFlags);
#endif
if (S_OK!=hr)
{
RETURN(hr);
}
}
}
else if (ERROR_MORE_DATA==dwResult)
{
// BUGBUG:Trace warning here
continue; // acceptable error - proceed with other params
}
}
ErrReturn:
if (0!=hKey)
{
RegCloseKey(hKey);
}
return hr;
};
//+--------------------------------------------------------------------------
//
// Method: CTestParams::GetEnum (public, synchronized)
//
// Synopsis: Interprets parameter string value
// as enum DWORD.
//
// Parameters: pszSwitchName: the command line switch name.
// pdwValue: ptr to enum var which receives the result
// ... expected value names and values untill NULL
//
// Example: g_TestParams.GetParamAsEnum(
// "mode",
// &dwMode,
// "rw", STGM_READWRITE,
// "r", STGM_READ,
// "w", STGM_WRITE,
// NULL);
//
// Returns: S_OK on success HRESULT error code
//
// Note: If the parameter is not found the function succeeds and
// retruns the first option value in *pdwValue
//
// History: 15-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT __cdecl CTestParams::GetEnum(const char *pszParamName, DWORD *pdwValue,...)
{
HRESULT hr=S_OK;
char * pszOption=NULL;
DWORD dwValue=0xabcdabcd;
BOOL bFound=FALSE;
BOOL bEnterSync=FALSE;
va_list ARGS;
CParamNode *pPrev=NULL; // not used
CParamNode *pNode=NULL;
char * pszTemp=NULL;
LPWSTR pwszName=NULL;
if ((NULL==pszParamName)||(NULL==pdwValue))
{
RETURN(E_INVALIDARG);
}
// copy the name as unicode
hr=CopyString(pszParamName,&pwszName);
if (S_OK!=hr)
{
RETURN(hr);
}
// Get the switch string value
ENTER_SYNC;
pNode=FindParam(pwszName,&pPrev);
if (NULL!=pNode)
{
pNode->MarkAsUsed(m_dwUsageInfo);
}
// Copy the value as ascii
if ((NULL!=pNode)&&(NULL!=pNode->m_pwszValue))
{
hr=CopyString(pNode->m_pwszValue,&pszTemp);
if (S_OK!=hr)
{
RETURN(hr);
}
}
// Loop for all expected values
va_start(ARGS,pdwValue);
pszOption=va_arg(ARGS,char*);
while(NULL!=pszOption)
{
dwValue=va_arg(ARGS,DWORD);
if ((NULL==pszTemp)||
(!_stricmp(pszTemp,pszOption)))
{
bFound=TRUE;
break;
}
pszOption=va_arg(ARGS,char*);
}
va_end(ARGS);
if (bFound)
{
*pdwValue=dwValue;
hr=S_OK;
}
else
{
hr=E_FAIL;
}
ErrReturn:
LEAVE_SYNC;
delete pwszName;
delete pszTemp;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::ClearUsage (public, synchronized)
//
// Synopsys: Clears usage specific flags
//
// Parameters: dwFlags: DWORD containing the usage flags to clear
// (all other bits are ignored)
//
// History: 30-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
void CTestParams::ClearUsage(DWORD dwFlags)
{
HRESULT hr=S_OK;
BOOL bEnterSync=FALSE;
CParamNode **pLinkPtr=&m_pParamsList;
CParamNode *pNode=m_pParamsList;
CParamNode *pNext=NULL;
ENTER_SYNC;
while (NULL!=pNode)
{
pNode->ClearUsage(dwFlags);
pNext=pNode->m_pNext;
// Clear "repro info" parameters which are out of scope
// (all the usage flags are cleared)
if ((PARAMFLAG_REPROINFO & pNode->m_dwFlags)&&
!(PARAMMASK_USAGE & pNode->m_dwFlags))
{
*pLinkPtr=pNext;
delete pNode;
}
else
{
pLinkPtr=&pNode->m_pNext;
}
pNode=pNext;
}
ErrReturn:
LEAVE_SYNC;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::ChangeParamFlags (public, synchronized)
//
// Synopsys: Change parameter flags (all except usage marks)
//
// Parameters: dwFlags: DWORD containing the flags
// (usage bits are ignored)
//
// Note: This function may be used for changing priority
// of the parameters from given source
// e.g. ???.ChangeParam(
// PARAMFLAGS_CMDLINE,
// PARAMFLAGS_CMDLINE+1); // raise priority
//
// History: 30-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::ChangeFlags(DWORD dwOldFlags, DWORD dwNewFlags)
{
HRESULT hr=S_OK;
BOOL bEnterSync=FALSE;
CParamNode *pNode=NULL;
if ((0==(PARAMMASK_SOURCE & dwOldFlags))||
(0==(PARAMMASK_SOURCE & dwNewFlags)))
{
RETURN(E_INVALIDARG);
}
ENTER_SYNC;
for (pNode=m_pParamsList;
NULL!=pNode;
pNode=pNode->m_pNext)
{
if (dwOldFlags==(pNode->m_dwFlags & ~PARAMMASK_SOURCE))
{
pNode->ChangeFlags(dwNewFlags);
}
}
ErrReturn:
LEAVE_SYNC;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::SaveParams (public, synchronized)
//
// Synopsys: Allocates a memory block and saves all the parameter info
//
// Arguments: *ppcBuffer:[out] the pointer to the buffer with all params
// *pdwSize: [out] the size of the buffer
// dwMask: [in] filter for parameters
//
// Notes: This method enables storing the set of parameters,
// or sending it to different process.
//
// The caller is responsible for deleting the table obtained.
//
// History: 30-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::SaveParams(
char **ppcBuffer,
DWORD *pdwSize,
DWORD dwMask)
{
HRESULT hr=S_OK;
DWORD dwSize=0;
CParamNode *pNode=NULL;
BOOL bEnterSync=FALSE;
char *pcTemp=NULL;
if ((NULL==pdwSize)||(NULL==ppcBuffer))
{
RETURN(E_INVALIDARG);
}
*ppcBuffer=NULL;
*pdwSize=0;
ENTER_SYNC;
// Calculate the size needed
for (pNode=m_pParamsList; NULL!=pNode; pNode=pNode->m_pNext)
{
if (pNode->m_dwFlags & dwMask)
{
dwSize+=sizeof(DWORD)+((DWORD)wcslen(pNode->m_pwszName)+1)*sizeof(WCHAR);
if (NULL!=pNode->m_pwszValue)
{
dwSize+=((DWORD)wcslen(pNode->m_pwszValue)+1)*sizeof(WCHAR)+1; // mark 'y' + string
}
else
{
dwSize++; // mark 0
};
};
}
// Allocate a buffer
*ppcBuffer=new char[dwSize];
if (NULL==*ppcBuffer)
{
RETURN(E_OUTOFMEMORY);
}
memset(*ppcBuffer,0,dwSize);
// Copy all parameters
pcTemp=*ppcBuffer;
for (pNode=m_pParamsList; NULL!=pNode; pNode=pNode->m_pNext)
{
if (pNode->m_dwFlags & dwMask)
{
// Flags
*(DWORD*)(LPVOID)pcTemp=pNode->m_dwFlags;
pcTemp+=sizeof(DWORD);
// Name
wcscpy((LPWSTR)pcTemp,pNode->m_pwszName);
pcTemp+=(wcslen((LPWSTR)pcTemp)+1)*sizeof(WCHAR);
// Value
if (NULL!=pNode->m_pwszValue)
{
*pcTemp++='y'; // mark that we have a value
wcscpy((LPWSTR)pcTemp,pNode->m_pwszValue);
pcTemp+=(wcslen((LPWSTR)pcTemp)+1)*sizeof(WCHAR);
}
else
{
*pcTemp++=0; // mark that there is no value
}
}
}
*pdwSize=dwSize;
ErrReturn:
LEAVE_SYNC;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::LoadParams (public, synchronized)
//
// Synopsys: Loads the parameters from memory buffer obtained by
// the CTestParams::Save method
//
// Arguments: pcBuffer: [in] the pointer to the buffer with all params
// dwSize: [in] the size of the buffer
// dwChangeFlags:[in] if not 0, change all parameters flags
//
// Note: The CTestParams object will make a copy of the parameters
// and do not need the buffer anymore.
//
// History: 30-Sep-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::LoadParams(
char *pcBuffer,
DWORD dwSize,
DWORD dwChangeFlags)
{
HRESULT hr=S_OK;
BOOL bEnterSync=FALSE;
char *pcTemp=pcBuffer;
char *pcEndPtr=pcBuffer+dwSize;
if ((0==dwSize)||(NULL==pcBuffer))
{
RETURN(E_INVALIDARG);
}
ENTER_SYNC;
while (pcTemp<pcEndPtr)
{
// extract Flags
DWORD dwFlags=*(DWORD*)(LPVOID)(pcTemp);
pcTemp+=sizeof(DWORD);
if (0!=dwChangeFlags)
{
// Change all flags except the usage
dwFlags=(dwFlags & PARAMMASK_USAGE) |
(dwChangeFlags & ~PARAMMASK_USAGE);
}
// extract Name
LPWSTR pwszName=(LPWSTR)pcTemp;
pcTemp+=(wcslen((LPWSTR)pcTemp)+1)*sizeof(WCHAR);
// extract Value
LPWSTR pwszValue=NULL;
if ('y'==*pcTemp)
{
pwszValue=(LPWSTR)++pcTemp;
pcTemp=(char*)pwszValue+(wcslen(pwszValue)+1)*sizeof(WCHAR);
}
else
{
pwszValue=NULL;
pcTemp++;
}
// Add this parameter
HRESULT hr=AddParam(pwszName,pwszValue,dwFlags);
if (S_OK!=hr)
{
RETURN(hr);
}
}
ErrReturn:
LEAVE_SYNC;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::GetReproLine (public, synchronized)
//
// Synopsys: Extracts repro line including all the parameters
// which mach the mask
//
// Parameters: dwFlags: the mask to filter parameters,
// default is PARAMMASK_USAGE.
// Use PARAMMASK_ALL to get all parameters
//
// The caller is responsible for deleting the table obtained.
//
// History: 01-Oct-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::GetReproLine(LPWSTR *ppwszReproLine, DWORD dwFlags)
{
HRESULT hr=S_OK;
DWORD dwSize=1; // the ending 0 in the string
CParamNode *pNode=NULL;
BOOL bEnterSync=FALSE;
LPWSTR pwszBuffer=NULL;
LPWSTR pwszTemp=NULL;
if (NULL==ppwszReproLine)
{
RETURN(E_INVALIDARG);
}
ENTER_SYNC;
// Calculate the size needed
for (pNode=m_pParamsList; NULL!=pNode; pNode=pNode->m_pNext)
{
if (dwFlags & pNode->m_dwFlags)
{
dwSize+=(DWORD)wcslen(pNode->m_pwszName)+2; // the name, '/' and space
if (NULL!=pNode->m_pwszValue)
{
dwSize+=(DWORD)wcslen(pNode->m_pwszValue)+1; // ':' and value
}
}
}
if (0==dwSize)
{
hr=CopyString("",&pwszBuffer);
RETURN(hr);
}
// Allocate a buffer
pwszBuffer=new WCHAR[dwSize];
if (NULL==pwszBuffer)
{
RETURN(E_OUTOFMEMORY);
}
memset(pwszBuffer,0,dwSize*sizeof(WCHAR));
// Copy all parameters
pwszTemp=pwszBuffer;
for (pNode=m_pParamsList; NULL!=pNode; pNode=pNode->m_pNext)
{
if (dwFlags & pNode->m_dwFlags)
{
// Value
if (NULL!=pNode->m_pwszValue)
{
swprintf(pwszTemp,L"/%s:%s ",pNode->m_pwszName,pNode->m_pwszValue);
pwszTemp+=wcslen(pwszTemp); // point to the ending zero
}
else
{
// The parameter has no value (boolean switch)
swprintf(pwszTemp,L"/%s ",pNode->m_pwszName);
pwszTemp+=wcslen(pwszTemp); // point to the ending zero
};
}
}
ErrReturn:
LEAVE_SYNC;
if (S_OK==hr)
{
*ppwszReproLine=pwszBuffer;
}
else
{
delete pwszBuffer;
}
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::GetReproLine (public, synchronized)
//
// Synopsys: Extracts repro line including all the parameters
// which mach the mask
//
// Parameters: dwFlags: the mask to filter parameters,
// default is PARAMMASK_USAGE.
// Use PARAMMASK_ALL to get all parameters
//
// The caller is responsible for deleting the table obtained.
//
// History: 01-Oct-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::GetReproLine(char **ppszReproLine, DWORD dwFlags)
{
HRESULT hr=S_OK;
LPWSTR pwszTemp=NULL;
if (NULL==ppszReproLine)
{
RETURN(E_INVALIDARG);
}
hr=GetReproLine(&pwszTemp,dwFlags);
if (S_OK==hr)
{
if (NULL==pwszTemp)
{
*ppszReproLine=NULL;
}
else
{
hr=CopyString(pwszTemp,ppszReproLine);
}
}
ErrReturn:
delete pwszTemp;
return hr;
}
//+--------------------------------------------------------------------------
//
// Method: CTestParams::GetRange (public, synchronized)
//
// Synopsys: Gets the values treating the parameter as range min-max
//
//
// Parameters: pszParamName: [in] the parameter name
// pullMin,pullMin : [out] the range values
//
// Retruns: S_OK or HRESULT error code
//
// Note: The string value of the parameter should be "min-max"
// e.g. "10-20"
// If the parameter can't be found, or the string format is bad
// the values won't be chenged.
//
// History: 02-Oct-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::GetRange(
const char *pszParamName,
ULONGLONG *pullMin,
ULONGLONG *pullMax)
{
HRESULT hr=S_OK;
BOOL bEnterSync=FALSE;
CParamNode *pPrev=NULL; // not used
CParamNode *pNode=NULL;
LPWSTR pwszMin=NULL;
LPWSTR pwszMax=NULL;
ULONGLONG ullMin=0;
ULONGLONG ullMax=0;
LPWSTR pwszName=NULL;
if ((NULL==pszParamName)||(NULL==pullMin)||(NULL==pullMax))
{
RETURN(E_INVALIDARG);
}
hr=CopyString(pszParamName,&pwszName);
if (S_OK!=hr)
{
RETURN(hr);
}
// Get the switch string value
ENTER_SYNC;
pNode=FindParam(pwszName,&pPrev);
if ((NULL==pNode)||(NULL==pNode->m_pwszValue))
{
RETURN(S_FALSE);
}
pwszMin = pNode->m_pwszValue;
pwszMax = pwszMin;
// Advance the maximum pointer past the dash delimeter after
while ((*pwszMax != 0) && (*pwszMax++ != '-'))
{
;
}
#ifdef WINNT // only here we have functions to hangle 64bit integers
ullMin = _wtoi64(pwszMin);
ullMax = _wtoi64(pwszMax);
#else
// wtoi64 is not present in link libraries, ifdef this
// to avoid build break. BUGBUG param values >DWORD will be truncated!
ullMin = _wtol(pwszMin);
ullMax = _wtol(pwszMax);
#endif
if (0==*pwszMax) // only one value is given
{
ullMax=ullMin;
};
if (ullMin <= ullMax)
{
hr=S_OK;
*pullMin=ullMin;
*pullMax=ullMax;
}
else
{
hr=E_FAIL;
}
ErrReturn:
LEAVE_SYNC;
delete pwszName;
return hr;
};
//+--------------------------------------------------------------------------
//
// Method: CTestParams::GetRange (public, synchronized)
//
// Synopsys: Gets the values treating the parameter as range min-max
//
// Parameters: pszParamName: [in] the parameter name
// pulMin,pulMin : [out] the range values
//
// Retruns: S_OK or HRESULT error code
//
// Note: The string value of the parameter should be "min-max"
// e.g. "10-20"
// If the parameter can't be found, or the string format is bad
// the values won't be chenged.
//
// History: 02-Oct-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CTestParams::GetRange(
const char *pszParamName,
ULONG *pulMin,
ULONG *pulMax)
{
HRESULT hr=S_OK;
ULARGE_INTEGER uliMin;
ULARGE_INTEGER uliMax;
if ((NULL==pszParamName)||(NULL==pulMin)||(NULL==pulMax))
{
RETURN(E_INVALIDARG);
}
uliMin.QuadPart=0;
uliMax.QuadPart=0;
hr=GetRange(pszParamName,&uliMin.QuadPart,&uliMax.QuadPart);
if (S_OK==hr) // else leave the values in *pulMin and *pulMax untouched
{
DH_ASSERT(0==uliMin.HighPart);
*pulMin=uliMin.LowPart;
DH_ASSERT(0==uliMax.HighPart);
*pulMax=uliMax.LowPart;
}
ErrReturn:
return hr;
};
//************** CTOLESTG specific **************************
// Define the default global parameter container
CStgParams g_TestParams;
//+--------------------------------------------------------------------------
//
// Method: CStgParams::NotifyOnFirstUse (public)
//
// Synopsys: Reads all the common parameter sources for
// the CTOLESTG project
//
// Note: The cleaner way is to implement a single function,
// but we want to start using the CTestParams in the
// common code, without modifying each the main()
// for each of the existing suites (about 50 now)
//
// History: 23-Oct-1998 georgis Created
//
//---------------------------------------------------------------------------
HRESULT CStgParams::NotifyOnFirstUse()
{
HRESULT hr=S_OK;
HRESULT hr1=S_OK;
DWORD dwDumpMask=PARAMMASK_ALL;
// command line
hr1=ReadCommandLine();
if (S_OK!=hr1)
{
hr=hr1;
};
if (!GETPARAM_ISPRESENT(STG_CMDLINEONLY))
{
// HKEY_CURRENT_USER\Software\Microsoft\CTOLESTG
// is the switch is not present, act as if it was empty
hr1=ReadRegistry(
HKEY_CURRENT_USER,
TEXT("Software\\Microsoft\\CTOLESTG"));
// Environment
hr1=ReadEnvironment(L"STG_");
if (S_OK!=hr1)
{
hr=hr1;
};
} // if cmdline only
// Eventually dump all the parameters
if (GETPARAM_ISPRESENT(PARAMDUMP))
{
GETPARAM(PARAMDUMP,dwDumpMask);
}
return hr;
};