Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

467 lines
11 KiB

/*
**++
**
** Copyright (c) 2000-2002 Microsoft Corporation
**
**
** Module Name:
**
** cmdparse.h
**
**
** Abstract:
**
** Command line parser
**
** Author:
**
** Adi Oltean [aoltean] 02/26/2002
**
** Revision History:
**
**--
*/
#ifndef __CMD_PARSE_HEADER_H__
#define __CMD_PARSE_HEADER_H__
#if _MSC_VER > 1000
#pragma once
#endif
//////////////////////////////////////////////////////////////////
//
// Generic string class
//
class CGxnString
{
private:
CGxnString(const CGxnString&);
public:
CGxnString(): m_pwszString(NULL), m_pwszCurrent(NULL) {};
CGxnString(int nAllocatedChars): m_pwszString(NULL), m_pwszCurrent(NULL) {
Allocate(nAllocatedChars);
};
CGxnString( const WCHAR* wszString, int nAllocatedChars = -1 ): m_pwszString(NULL), m_pwszCurrent(NULL) {
CopyFrom(wszString, nAllocatedChars);
};
~CGxnString(){
Clear();
};
operator WCHAR* () { return m_pwszCurrent; };
void operator ++ (int) { m_pwszCurrent++; };
void operator += (int nChars) { m_pwszCurrent += nChars; };
void CopyFrom(const WCHAR * wszString, int nAllocatedChars = -1) {
int nLen = (nAllocatedChars == -1)? wcslen(wszString): nAllocatedChars;
Allocate(nLen);
::wcsncpy(m_pwszString, wszString, nLen);
};
void Allocate(int nAllocatedChars) {
delete[] m_pwszString;
m_pwszString = new WCHAR[nAllocatedChars + 1];
if (NULL == m_pwszString) throw(E_OUTOFMEMORY);
m_pwszString[nAllocatedChars] = L'\0';
m_pwszCurrent = m_pwszString;
};
void Clear() {
delete[] m_pwszString;
m_pwszString = m_pwszCurrent = NULL;
};
private:
WCHAR * m_pwszString;
WCHAR * m_pwszCurrent;
};
//////////////////////////////////////////////////////////////////
//
// Generic tracing mechanism (can be replaced with a better one)
//
// Useful macros for tracing
#define GXN_DBGINFO __LINE__, __FILE__
// Tracing buffer - max value
#define MAX_TRACING_BUFFER 400
// Macro used for commoditized vsprintf
#define GXN_VARARG( LastParam ) \
CGxnString buffer(MAX_TRACING_BUFFER); \
va_list marker; \
va_start( marker, LastParam ); \
_vsnwprintf( buffer, MAX_TRACING_BUFFER - 1, LastParam, marker ); \
va_end( marker );
// The tracing class (a very simple implementation)
struct CGxnTracer
{
enum{
TraceFlag = 1,
OutputFlag = 2,
ErrorFlag = 4,
AllFlags = 7,
};
CGxnTracer(int nLine = 0, char* szFile = NULL, WCHAR* wszFunction = NULL):
m_nTraceFlags(OutputFlag | ErrorFlag),
m_szFile(szFile), m_nLine(nLine), m_wszFunction(wszFunction) {};
CGxnTracer(int nTraceFlags, int nLine = 0, char* szFile = NULL, WCHAR* wszFunction = NULL):
m_nTraceFlags(nTraceFlags),
m_szFile(szFile), m_nLine(nLine), m_wszFunction(wszFunction) {
if (m_wszFunction) Trace(m_nLine, m_szFile, L"* Enter %s\n", m_wszFunction);
};
~CGxnTracer() {
if (m_wszFunction) Trace(m_nLine, m_szFile, L"* Exit %s\n", m_wszFunction);
};
int SetOptions( int nTraceFlags ) {
int nPrevTraceFlags = m_nTraceFlags;
m_nTraceFlags = nTraceFlags;
return nPrevTraceFlags;
}
void Out( WCHAR* pwszMsgFormat, ... ) {
if (m_nTraceFlags & OutputFlag) {
GXN_VARARG( pwszMsgFormat );
wprintf( L"%s", (LPWSTR)buffer);
}
}
void Trace( int nLine, char* szFile, const WCHAR* pwszMsgFormat, ... ) {
if (m_nTraceFlags & TraceFlag) {
GXN_VARARG( pwszMsgFormat );
wprintf( L"%s - %hs(%d)\n", (LPWSTR)buffer, szFile, nLine);
}
}
void Err( WCHAR* pwszMsgFormat, ... ) {
if (m_nTraceFlags & ErrorFlag) {
GXN_VARARG( pwszMsgFormat );
wprintf( L"%s", (LPWSTR)buffer);
}
}
__declspec(noreturn) void Throw( INT nLine, char* szFile, HRESULT hr, const WCHAR* pwszMsgFormat, ... ) {
if (m_nTraceFlags & ErrorFlag) {
GXN_VARARG( pwszMsgFormat );
wprintf( L"%s [ERROR: 0x%08lx] - %hs(%d)\n", (LPWSTR)buffer, hr, szFile, nLine);
}
throw (hr);
}
private:
int m_nTraceFlags;
char* m_szFile;
int m_nLine;
WCHAR* m_wszFunction;
};
//////////////////////////////////////////////////////////////////////////
//
// Command line parser
//
#define BEGIN_CMD_PARSER( AppName ) \
virtual CHAR* GetAppName() { return #AppName; }; \
virtual CmdTemplateEntry & GetCmdTemplate(INT nIndex) { \
static CmdTemplateEntry arrEntries[] = { \
#define CMD_ENTRY(pRoutine, wszTemplate, wszComment) \
{ pRoutine, wszTemplate, wszComment}, \
#define END_CMD_PARSER \
{ NULL, NULL, NULL }, \
}; \
return arrEntries[nIndex]; \
}
// Command line parser class
template <
class CRoutineSupport,
class CTracer = CGxnTracer,
int MAX_PARAMS = 40
>
class CGxnCmdLineParser
{
// Types
public:
typedef void (CRoutineSupport::*PRoutineNonaligned)();
typedef __declspec(align(16)) PRoutineNonaligned PRoutine;
typedef struct {
PRoutine pRoutine;
LPWSTR wszCmdLine;
LPWSTR wszComment;
} CmdTemplateEntry;
// Constructors/destructors
private:
CGxnCmdLineParser(const CGxnCmdLineParser&);
public:
CGxnCmdLineParser(): m_nParamCount(0), m_nSelectedTemplate(0) {};
public:
virtual CHAR* GetAppName() = 0;
virtual CmdTemplateEntry & GetCmdTemplate(INT nIndex) = 0;
// Operations
public:
bool ParseCmdLine(WCHAR* pwszCommandLine)
{
// CTracer ft( GXN_DBGINFO, L"CGxnCmdLineParser::ParseCmdLine");
for (INT nIndex = 0;; nIndex++)
{
CmdTemplateEntry & entry = GetCmdTemplate(nIndex);
// If this is the last entry print usage
if (entry.pRoutine == NULL)
return PrintUsage();
// Clean parameter associations from previous iteration (if any)
CleanParams();
CGxnString strCommandLine(pwszCommandLine);
CGxnString strCommandTemplate(entry.wszCmdLine);
while (true) {
// Skip spaces
for(;iswspace(*strCommandLine);strCommandLine++);
for(;iswspace(*strCommandTemplate);strCommandTemplate++);
// Extract a name/value pair if possible
CGxnString name, value;
if (ExtractVariable(strCommandTemplate, name))
{
// No match, try with the next template
if (!ExtractValue(strCommandLine, value))
break;
AddParam(name, value);
continue;
}
// No match, try with the next template
if (*strCommandTemplate != *strCommandLine)
break;
// Eliminate the current matching tokens
while(*strCommandTemplate == *strCommandLine) {
// If we reach an end, we just finished
if ((*strCommandTemplate == L'\0')
&& (*strCommandLine == L'\0'))
{
m_nSelectedTemplate = nIndex;
return true;
}
strCommandTemplate++;
strCommandLine++;
}
}
}
return false;
}
LPWSTR GetStringParam(const WCHAR* wszName)
{
if ((wszName[0] != L'<') && (wszName[wcslen(wszName)-1] != L'>') )
ft.Throw( GXN_DBGINFO, E_UNEXPECTED, L"Invalid name %s\n", wszName);
// Extract the '<' and '>' suffixes and search into the array
CGxnString name(wszName + 1, wcslen(wszName) - 2);
for (INT nIndex = 0; nIndex < m_nParamCount; nIndex++)
if (wcscmp(name, m_arrNames[nIndex]) == 0)
return m_arrValues[nIndex];
ft.Throw( GXN_DBGINFO, E_UNEXPECTED, L"Invalid string param %s\n", wszName);
}
// Get a integer value
INT GetIntParam(const WCHAR* wszName)
{
return _wtoi(GetStringParam( wszName ));
}
// Get a int64 value
LONGLONG GetInt64Param(const WCHAR* wszName)
{
return _wtoi64(GetStringParam( wszName ));
}
// Get a int64 value
LARGE_INTEGER GetLargeIntParam(const WCHAR* wszName)
{
LARGE_INTEGER li;
li.QuadPart = _wtoi64(GetStringParam( wszName ));
return li;
}
// Get a GUID value
GUID GetGuidParam(const WCHAR* wszName)
{
GUID guid;
LPWSTR wszString = GetValue(wszName);
if (FAILED(CLSIDFromString(wszString, &guidValue)))
ft.Throw( GXN_DBGINFO, E_INVALIDARG, L"Invalid GUID %s for param %s\n", wszString, wszName);
return guid;
}
bool IsOptionPresent(const WCHAR* /*wszName*/)
{
return false;
}
PRoutine GetCurrentRoutine()
{
return GetCmdTemplate(m_nSelectedTemplate).pRoutine;
};
LPWSTR GetCurrentComment()
{
return GetCmdTemplate(m_nSelectedTemplate).wszComment;
};
LPWSTR GetCurrentTemplate()
{
return GetCmdTemplate(m_nSelectedTemplate).wszCmdLine;
};
void PrintArguments()
{
ft.Out(L"\n\nMatching parameters for template '%s':\n", GetCurrentTemplate());
for(INT nIndex = 0; nIndex < m_nParamCount; nIndex++)
ft.Out( L"* <%s> = '%s'\n", (LPWSTR)m_arrNames[nIndex], (LPWSTR)m_arrValues[nIndex] );
if (m_nParamCount == 0)
ft.Out( L"* (None)\n");
ft.Out(L"\n");
}
bool PrintUsage()
{
ft.Out(L"\n\nUsage:\n");
for (INT nIndex = 0;; nIndex++)
{
CmdTemplateEntry & entry = GetCmdTemplate(nIndex);
if (entry.pRoutine == NULL)
break;
ft.Out(L" * %s:\t%hs %s\n", entry.wszComment, GetAppName(), entry.wszCmdLine);
}
ft.Out(L"\n");
return false;
}
// Utility methods
private:
// Extract a variable of the "<name>" format
bool ExtractVariable(CGxnString & str, CGxnString & name) {
if ( *str != L'<')
return false;
str++;
WCHAR* wszEnd = wcschr(str, L'>');
if (!wszEnd || (str == wszEnd))
ft.Throw( GXN_DBGINFO, E_INVALIDARG, L"Invalid variable name %s\n", (LPWSTR)str);
name.CopyFrom( str, wszEnd - str );
str += (wszEnd - str) + 1; // Skip the L'>' character also
return true;
}
// Extract a value from the current string until we reach a space.
bool ExtractValue(CGxnString & str, CGxnString & value) {
LPWSTR wszEnd = str;
// Check if we have quota-enclosed parameters
if (*str == L'"')
{
wszEnd = wcschr(str + 1, L'"');
if (wszEnd == NULL)
ft.Throw( GXN_DBGINFO, E_INVALIDARG, L"Quota not enclosed at %s\n", (LPWSTR)str);
value.CopyFrom( str + 1, wszEnd - str - 1 );
str += (wszEnd-str) + 1;
return true;
}
else
{
// Get the first space or zero terminator
for(; (*wszEnd) && !iswspace(*wszEnd); wszEnd++);
if (str == wszEnd)
return false;
value.CopyFrom( str, wszEnd - str );
str += (wszEnd-str);
return true;
}
}
void CleanParams()
{
for (INT nIndex = 0; nIndex < m_nParamCount; nIndex++) {
m_arrNames[nIndex].Clear();
m_arrValues[nIndex].Clear();
}
m_nParamCount = 0;
}
void AddParam(CGxnString & name, CGxnString & value)
{
if (m_nParamCount == MAX_PARAMS)
ft.Throw( GXN_DBGINFO, E_INVALIDARG, L"Too many parameters [%d]\n", m_nParamCount);
m_arrNames[m_nParamCount].CopyFrom(name);
m_arrValues[m_nParamCount].CopyFrom(value);
m_nParamCount++;
}
// Internal data members
private:
INT m_nParamCount;
CGxnString m_arrNames[MAX_PARAMS];
CGxnString m_arrValues[MAX_PARAMS];
INT m_nSelectedTemplate;
protected:
CTracer ft;
};
#endif // __CMD_PARSE_HEADER_H__