//+-------------------------------------------------------------------------- // // 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 // 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 (dwIndexunicode) // // 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 (0m_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 (dwHashValuem_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 (pcTempm_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; };