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.

454 lines
11 KiB

  1. /*
  2. **++
  3. **
  4. ** Copyright (c) 2000-2002 Microsoft Corporation
  5. **
  6. **
  7. ** Module Name:
  8. **
  9. ** cmdparse.h
  10. **
  11. **
  12. ** Abstract:
  13. **
  14. ** Command line parser
  15. **
  16. ** Author:
  17. **
  18. ** Adi Oltean [aoltean] 02/26/2002
  19. **
  20. ** Revision History:
  21. **
  22. **--
  23. */
  24. #ifndef __CMD_PARSE_HEADER_H__
  25. #define __CMD_PARSE_HEADER_H__
  26. #if _MSC_VER > 1000
  27. #pragma once
  28. #endif
  29. //////////////////////////////////////////////////////////////////
  30. //
  31. // Generic string class
  32. //
  33. class CGxnString
  34. {
  35. private:
  36. CGxnString(const CGxnString&);
  37. public:
  38. CGxnString(): m_pwszString(NULL), m_pwszCurrent(NULL) {};
  39. CGxnString(int nAllocatedChars): m_pwszString(NULL), m_pwszCurrent(NULL) {
  40. Allocate(nAllocatedChars);
  41. };
  42. CGxnString( const WCHAR* wszString, int nAllocatedChars = -1 ): m_pwszString(NULL), m_pwszCurrent(NULL) {
  43. CopyFrom(wszString, nAllocatedChars);
  44. };
  45. ~CGxnString(){
  46. Clear();
  47. };
  48. operator WCHAR* () { return m_pwszCurrent; };
  49. void operator ++ (int) { m_pwszCurrent++; };
  50. void operator += (int nChars) { m_pwszCurrent += nChars; };
  51. void CopyFrom(const WCHAR * wszString, int nAllocatedChars = -1) {
  52. int nLen = (nAllocatedChars == -1)? (int)wcslen(wszString): nAllocatedChars;
  53. Allocate(nLen);
  54. ::wcsncpy(m_pwszString, wszString, nLen);
  55. };
  56. void Allocate(int nAllocatedChars) {
  57. delete[] m_pwszString;
  58. m_pwszString = new WCHAR[nAllocatedChars + 1];
  59. if (NULL == m_pwszString) throw(E_OUTOFMEMORY);
  60. m_pwszString[nAllocatedChars] = L'\0';
  61. m_pwszCurrent = m_pwszString;
  62. };
  63. void Clear() {
  64. delete[] m_pwszString;
  65. m_pwszString = m_pwszCurrent = NULL;
  66. };
  67. private:
  68. WCHAR * m_pwszString;
  69. WCHAR * m_pwszCurrent;
  70. };
  71. //////////////////////////////////////////////////////////////////
  72. //
  73. // Generic tracing mechanism (can be replaced with a better one)
  74. //
  75. // Useful macros for tracing
  76. #define GXN_DBGINFO __LINE__, __FILE__
  77. // Tracing buffer - max value
  78. #define MAX_TRACING_BUFFER 400
  79. // Macro used for commoditized vsprintf
  80. #define GXN_VARARG( LastParam ) \
  81. CGxnString buffer(MAX_TRACING_BUFFER); \
  82. va_list marker; \
  83. va_start( marker, LastParam ); \
  84. StringCchVPrintfW( buffer, MAX_TRACING_BUFFER, LastParam, marker ); \
  85. va_end( marker );
  86. // The tracing class (a very simple implementation)
  87. struct CGxnTracer
  88. {
  89. enum{
  90. TraceFlag = 1,
  91. OutputFlag = 2,
  92. ErrorFlag = 4,
  93. AllFlags = 7,
  94. };
  95. CGxnTracer(int nLine = 0, char* szFile = NULL, WCHAR* wszFunction = NULL):
  96. m_nTraceFlags(OutputFlag | ErrorFlag),
  97. m_szFile(szFile), m_nLine(nLine), m_wszFunction(wszFunction) {};
  98. CGxnTracer(int nTraceFlags, int nLine = 0, char* szFile = NULL, WCHAR* wszFunction = NULL):
  99. m_nTraceFlags(nTraceFlags),
  100. m_szFile(szFile), m_nLine(nLine), m_wszFunction(wszFunction) {
  101. if (m_wszFunction) Trace(m_nLine, m_szFile, L"* Enter %s\n", m_wszFunction);
  102. };
  103. ~CGxnTracer() {
  104. if (m_wszFunction) Trace(m_nLine, m_szFile, L"* Exit %s\n", m_wszFunction);
  105. };
  106. int SetOptions( int nTraceFlags ) {
  107. int nPrevTraceFlags = m_nTraceFlags;
  108. m_nTraceFlags = nTraceFlags;
  109. return nPrevTraceFlags;
  110. }
  111. void Out( WCHAR* pwszMsgFormat, ... ) {
  112. if (m_nTraceFlags & OutputFlag) {
  113. GXN_VARARG( pwszMsgFormat );
  114. wprintf( L"%s", (LPWSTR)buffer);
  115. }
  116. }
  117. void Trace( int nLine, char* szFile, const WCHAR* pwszMsgFormat, ... ) {
  118. if (m_nTraceFlags & TraceFlag) {
  119. GXN_VARARG( pwszMsgFormat );
  120. wprintf( L"%s - %hs(%d)\n", (LPWSTR)buffer, szFile, nLine);
  121. }
  122. }
  123. void Err( WCHAR* pwszMsgFormat, ... ) {
  124. if (m_nTraceFlags & ErrorFlag) {
  125. GXN_VARARG( pwszMsgFormat );
  126. wprintf( L"%s", (LPWSTR)buffer);
  127. }
  128. }
  129. __declspec(noreturn) void Throw( INT nLine, char* szFile, HRESULT hr, const WCHAR* pwszMsgFormat, ... ) {
  130. if (m_nTraceFlags & ErrorFlag) {
  131. GXN_VARARG( pwszMsgFormat );
  132. wprintf( L"%s [ERROR: 0x%08lx] - %hs(%d)\n", (LPWSTR)buffer, hr, szFile, nLine);
  133. }
  134. throw (hr);
  135. }
  136. private:
  137. int m_nTraceFlags;
  138. char* m_szFile;
  139. int m_nLine;
  140. WCHAR* m_wszFunction;
  141. };
  142. //////////////////////////////////////////////////////////////////////////
  143. //
  144. // Command line parser
  145. //
  146. #define BEGIN_CMD_PARSER( AppName ) \
  147. virtual CHAR* GetAppName() { return #AppName; }; \
  148. virtual CmdTemplateEntry & GetCmdTemplate(INT nIndex) { \
  149. static CmdTemplateEntry arrEntries[] = { \
  150. #define CMD_ENTRY(pRoutine, wszTemplate, wszComment) \
  151. { pRoutine, wszTemplate, wszComment}, \
  152. #define END_CMD_PARSER \
  153. { NULL, NULL, NULL }, \
  154. }; \
  155. return arrEntries[nIndex]; \
  156. }
  157. // Command line parser class
  158. template <
  159. class CRoutineSupport,
  160. class CTracer = CGxnTracer,
  161. int MAX_PARAMS = 40
  162. >
  163. class CGxnCmdLineParser
  164. {
  165. // Types
  166. public:
  167. typedef void (CRoutineSupport::*PRoutineNonaligned)();
  168. typedef __declspec(align(16)) PRoutineNonaligned PRoutine;
  169. typedef struct {
  170. PRoutine pRoutine;
  171. LPWSTR wszCmdLine;
  172. LPWSTR wszComment;
  173. } CmdTemplateEntry;
  174. // Constructors/destructors
  175. private:
  176. CGxnCmdLineParser(const CGxnCmdLineParser&);
  177. public:
  178. CGxnCmdLineParser(): m_nParamCount(0), m_nSelectedTemplate(0) {};
  179. public:
  180. virtual CHAR* GetAppName() = 0;
  181. virtual CmdTemplateEntry & GetCmdTemplate(INT nIndex) = 0;
  182. // Operations
  183. public:
  184. bool ParseCmdLine(WCHAR* pwszCommandLine)
  185. {
  186. // CTracer ft( GXN_DBGINFO, L"CGxnCmdLineParser::ParseCmdLine");
  187. for (INT nIndex = 0;; nIndex++)
  188. {
  189. CmdTemplateEntry & entry = GetCmdTemplate(nIndex);
  190. // If this is the last entry print usage
  191. if (entry.pRoutine == NULL)
  192. return PrintUsage();
  193. // Clean parameter associations from previous iteration (if any)
  194. CleanParams();
  195. CGxnString strCommandLine(pwszCommandLine);
  196. CGxnString strCommandTemplate(entry.wszCmdLine);
  197. while (true) {
  198. // Skip spaces
  199. for(;iswspace(*strCommandLine);strCommandLine++);
  200. for(;iswspace(*strCommandTemplate);strCommandTemplate++);
  201. // Extract a name/value pair if possible
  202. CGxnString name, value;
  203. if (ExtractVariable(strCommandTemplate, name))
  204. {
  205. // No match, try with the next template
  206. if (!ExtractValue(strCommandLine, value))
  207. break;
  208. AddParam(name, value);
  209. continue;
  210. }
  211. // No match, try with the next template
  212. if (*strCommandTemplate != *strCommandLine)
  213. break;
  214. // Eliminate the current matching tokens
  215. while(*strCommandTemplate == *strCommandLine) {
  216. // If we reach an end, we just finished
  217. if ((*strCommandTemplate == L'\0')
  218. && (*strCommandLine == L'\0'))
  219. {
  220. m_nSelectedTemplate = nIndex;
  221. return true;
  222. }
  223. strCommandTemplate++;
  224. strCommandLine++;
  225. }
  226. }
  227. }
  228. return false;
  229. }
  230. LPWSTR GetStringParam(const WCHAR* wszName)
  231. {
  232. if ((wszName[0] != L'<') && (wszName[wcslen(wszName)-1] != L'>') )
  233. ft.Throw( GXN_DBGINFO, E_UNEXPECTED, L"Invalid name %s\n", wszName);
  234. // Extract the '<' and '>' suffixes and search into the array
  235. CGxnString name(wszName + 1, (int)wcslen(wszName) - 2);
  236. for (INT nIndex = 0; nIndex < m_nParamCount; nIndex++)
  237. if (wcscmp(name, m_arrNames[nIndex]) == 0)
  238. return m_arrValues[nIndex];
  239. ft.Throw( GXN_DBGINFO, E_UNEXPECTED, L"Invalid string param %s\n", wszName);
  240. }
  241. // Get a integer value
  242. INT GetIntParam(const WCHAR* wszName)
  243. {
  244. return _wtoi(GetStringParam( wszName ));
  245. }
  246. // Get a int64 value
  247. LONGLONG GetInt64Param(const WCHAR* wszName)
  248. {
  249. return _wtoi64(GetStringParam( wszName ));
  250. }
  251. // Get a int64 value
  252. LARGE_INTEGER GetLargeIntParam(const WCHAR* wszName)
  253. {
  254. LARGE_INTEGER li;
  255. li.QuadPart = _wtoi64(GetStringParam( wszName ));
  256. return li;
  257. }
  258. // Get a GUID value
  259. GUID GetGuidParam(const WCHAR* wszName)
  260. {
  261. GUID guid;
  262. LPWSTR wszString = GetValue(wszName);
  263. if (FAILED(CLSIDFromString(wszString, &guidValue)))
  264. ft.Throw( GXN_DBGINFO, E_INVALIDARG, L"Invalid GUID %s for param %s\n", wszString, wszName);
  265. return guid;
  266. }
  267. bool IsOptionPresent(const WCHAR* /*wszName*/)
  268. {
  269. return false;
  270. }
  271. PRoutine GetCurrentRoutine()
  272. {
  273. return GetCmdTemplate(m_nSelectedTemplate).pRoutine;
  274. };
  275. LPWSTR GetCurrentComment()
  276. {
  277. return GetCmdTemplate(m_nSelectedTemplate).wszComment;
  278. };
  279. LPWSTR GetCurrentTemplate()
  280. {
  281. return GetCmdTemplate(m_nSelectedTemplate).wszCmdLine;
  282. };
  283. void PrintArguments()
  284. {
  285. ft.Out(L"\n\nMatching parameters for template '%s':\n", GetCurrentTemplate());
  286. for(INT nIndex = 0; nIndex < m_nParamCount; nIndex++)
  287. ft.Out( L"* <%s> = '%s'\n", (LPWSTR)m_arrNames[nIndex], (LPWSTR)m_arrValues[nIndex] );
  288. if (m_nParamCount == 0)
  289. ft.Out( L"* (None)\n");
  290. ft.Out(L"\n");
  291. }
  292. bool PrintUsage()
  293. {
  294. ft.Out(L"\n\nUsage:\n");
  295. for (INT nIndex = 0;; nIndex++)
  296. {
  297. CmdTemplateEntry & entry = GetCmdTemplate(nIndex);
  298. if (entry.pRoutine == NULL)
  299. break;
  300. ft.Out(L" * %s:\t%hs %s\n", entry.wszComment, GetAppName(), entry.wszCmdLine);
  301. }
  302. ft.Out(L"\n");
  303. return false;
  304. }
  305. // Utility methods
  306. private:
  307. // Extract a variable of the "<name>" format
  308. bool ExtractVariable(CGxnString & str, CGxnString & name) {
  309. if ( *str != L'<')
  310. return false;
  311. str++;
  312. WCHAR* wszEnd = wcschr(str, L'>');
  313. if (!wszEnd || (str == wszEnd))
  314. ft.Throw( GXN_DBGINFO, E_INVALIDARG, L"Invalid variable name %s\n", (LPWSTR)str);
  315. name.CopyFrom( str, wszEnd - str );
  316. str += (wszEnd - str) + 1; // Skip the L'>' character also
  317. return true;
  318. }
  319. // Extract a value from the current string until we reach a space.
  320. bool ExtractValue(CGxnString & str, CGxnString & value) {
  321. LPWSTR wszEnd = str;
  322. // Get the first space or zero terminator
  323. for(; (*wszEnd) && !iswspace(*wszEnd); wszEnd++);
  324. if (str == wszEnd)
  325. return false;
  326. value.CopyFrom( str, wszEnd - str );
  327. str += (wszEnd - str);
  328. return true;
  329. }
  330. void CleanParams()
  331. {
  332. for (INT nIndex = 0; nIndex < m_nParamCount; nIndex++) {
  333. m_arrNames[nIndex].Clear();
  334. m_arrValues[nIndex].Clear();
  335. }
  336. m_nParamCount = 0;
  337. }
  338. void AddParam(CGxnString & name, CGxnString & value)
  339. {
  340. if (m_nParamCount == MAX_PARAMS)
  341. ft.Throw( GXN_DBGINFO, E_INVALIDARG, L"Too many parameters [%d]\n", m_nParamCount);
  342. m_arrNames[m_nParamCount].CopyFrom(name);
  343. m_arrValues[m_nParamCount].CopyFrom(value);
  344. m_nParamCount++;
  345. }
  346. // Internal data members
  347. private:
  348. INT m_nParamCount;
  349. CGxnString m_arrNames[MAX_PARAMS];
  350. CGxnString m_arrValues[MAX_PARAMS];
  351. INT m_nSelectedTemplate;
  352. protected:
  353. CTracer ft;
  354. };
  355. #endif // __CMD_PARSE_HEADER_H__