Source code of Windows XP (NT5)
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.

516 lines
14 KiB

  1. /****************************************************************************
  2. Copyright information : Copyright (c) 1998-1999 Microsoft Corporation
  3. File Name : CmdTokenizer.cpp
  4. Project Name : WMI Command Line
  5. Author Name : Ch. Sriramachandramurthy
  6. Date of Creation (dd/mm/yy) : 27th-September-2000
  7. Version Number : 1.0
  8. Brief Description : The CCmdTokenizer class provides with the
  9. functionality for tokenizing a command entered
  10. as input on the command line, following the
  11. pre-defined rules for tokenizing.
  12. Revision History :
  13. Last Modified By : P. Sashank
  14. Last Modified Date : 10th-April-2001
  15. ****************************************************************************/
  16. #include "Precomp.h"
  17. #include "CmdTokenizer.h"
  18. /*------------------------------------------------------------------------
  19. Name :CCmdTokenizer
  20. Synopsis :This function initializes the member variables when
  21. an object of the class type is instantiated
  22. Type :Constructor
  23. Input parameter :None
  24. Output parameters :None
  25. Return Type :None
  26. Global Variables :None
  27. Calling Syntax :None
  28. Notes :None
  29. ------------------------------------------------------------------------*/
  30. CCmdTokenizer::CCmdTokenizer()
  31. {
  32. m_nTokenOffSet = 0;
  33. m_nTokenStart = 0;
  34. m_pszCommandLine = NULL;
  35. m_bEscapeSeq = FALSE;
  36. m_bFormatToken = FALSE;
  37. }
  38. /*------------------------------------------------------------------------
  39. Name :~CCmdTokenizer
  40. Synopsis :This function uninitializes the member variables
  41. when an object of the class type goes out of scope.
  42. Type :Destructor
  43. Input parameter :None
  44. Output parameters :None
  45. Return Type :None
  46. Global Variables :None
  47. Calling Syntax :None
  48. Notes :None
  49. ------------------------------------------------------------------------*/
  50. CCmdTokenizer::~CCmdTokenizer()
  51. {
  52. Uninitialize();
  53. }
  54. /*------------------------------------------------------------------------
  55. Name :Uninitialize
  56. Synopsis :This function uninitializes the member variables
  57. when the execution of a command string issued on the
  58. command line is completed.
  59. Type :Member Function
  60. Input parameter :None
  61. Output parameters :None
  62. Return Type :None
  63. Global Variables :None
  64. Calling Syntax :Uninitialize()
  65. Notes :None
  66. ------------------------------------------------------------------------*/
  67. void CCmdTokenizer::Uninitialize()
  68. {
  69. m_nTokenOffSet = 0;
  70. m_nTokenStart = 0;
  71. m_bEscapeSeq = FALSE;
  72. SAFEDELETE(m_pszCommandLine);
  73. CleanUpCharVector(m_cvTokens);
  74. }
  75. /*------------------------------------------------------------------------
  76. Name :TokenizeCommand
  77. Synopsis :This function tokenizes the command string entered
  78. as input based on the pre-identified delimiters and
  79. stores the tokens in the list of m_cvTokens.
  80. Type :Member Function
  81. Input parameter :
  82. pszCommandInpout - Command line Input
  83. Output parameters :None
  84. Return Type :BOOL
  85. Global Variables :None
  86. Calling Syntax :TokenizeCommand(pszCommandInput)
  87. Notes :None
  88. ------------------------------------------------------------------------*/
  89. BOOL CCmdTokenizer::TokenizeCommand(_TCHAR* pszCommandInput) throw(WMICLIINT)
  90. {
  91. BOOL bResult = TRUE;
  92. // Free the memory pointed by the member variable m_pszCommandLine
  93. // if the pointer is not NULL.
  94. SAFEDELETE(m_pszCommandLine);
  95. if(pszCommandInput)
  96. {
  97. try
  98. {
  99. // Allocate the memory for the command line string.
  100. m_pszCommandLine = new _TCHAR [lstrlen(pszCommandInput) + 1];
  101. if (m_pszCommandLine != NULL)
  102. {
  103. // Copy the contents to the member variable m_pszCommandLine
  104. lstrcpy(m_pszCommandLine, pszCommandInput);
  105. // Set the token-offset and token-start counters to '0'
  106. m_nTokenOffSet = 0;
  107. m_nTokenStart = 0;
  108. WMICLIINT nCmdLength = lstrlen(m_pszCommandLine);
  109. // Tokenize the command string.
  110. while (m_nTokenOffSet < nCmdLength)
  111. {
  112. NextToken();
  113. }
  114. }
  115. else
  116. throw OUT_OF_MEMORY;
  117. }
  118. catch(...)
  119. {
  120. bResult = FALSE;
  121. }
  122. }
  123. return bResult;
  124. }
  125. /*------------------------------------------------------------------------
  126. Name :NextToken
  127. Synopsis :This function dissects the command string entered
  128. as input, and adjusts the the token-offset and
  129. token-start positions, and call the Token()
  130. function for extracting the token out of the
  131. input string.
  132. Type :Member Function
  133. Input parameter :None
  134. Output parameters :None
  135. Return Type :_TCHAR*
  136. Global Variables :None
  137. Calling Syntax :NextToken
  138. Notes :None
  139. ------------------------------------------------------------------------*/
  140. _TCHAR* CCmdTokenizer::NextToken()
  141. {
  142. WMICLIINT nCmdLength = lstrlen(m_pszCommandLine);
  143. // step over leading whitespace(s)
  144. while ((m_pszCommandLine[m_nTokenOffSet] == _T(' ') ||
  145. m_pszCommandLine[m_nTokenOffSet] == _T('\t'))
  146. && (m_nTokenOffSet < nCmdLength))
  147. {
  148. m_nTokenOffSet++;
  149. }
  150. m_nTokenStart = m_nTokenOffSet;
  151. CHARVECTOR::iterator theIterator;
  152. theIterator = m_cvTokens.end();
  153. //step up to next delimiter i.e '/', '-' or '?'
  154. if ((m_pszCommandLine[m_nTokenOffSet] == _T('/'))
  155. || (m_pszCommandLine[m_nTokenOffSet] == _T('-'))
  156. || (m_pszCommandLine[m_nTokenOffSet] == _T(','))
  157. || (m_pszCommandLine[m_nTokenOffSet] == _T('('))
  158. || (m_pszCommandLine[m_nTokenOffSet] == _T(')'))
  159. || (m_pszCommandLine[m_nTokenOffSet] == _T('=') &&
  160. !CompareTokens(*(theIterator-1), CLI_TOKEN_WHERE) &&
  161. !CompareTokens(*(theIterator-1), CLI_TOKEN_PATH)))
  162. {
  163. // To handle optional parenthesis with WHERE
  164. if (m_pszCommandLine[m_nTokenOffSet] == _T('('))
  165. {
  166. if (m_cvTokens.size())
  167. {
  168. //Check whether the previous token is "WHERE"
  169. if (CompareTokens(*(theIterator-1), CLI_TOKEN_WHERE))
  170. {
  171. m_nTokenOffSet++;
  172. while ((m_nTokenOffSet < nCmdLength)
  173. && (m_pszCommandLine[m_nTokenOffSet] != _T(')')))
  174. {
  175. m_nTokenOffSet++;
  176. }
  177. }
  178. }
  179. }
  180. m_nTokenOffSet++;
  181. }
  182. else
  183. {
  184. while (m_nTokenOffSet < nCmdLength)
  185. {
  186. if ((m_pszCommandLine[m_nTokenOffSet] == _T('/'))
  187. || (m_pszCommandLine[m_nTokenOffSet] == _T('-'))
  188. || (m_pszCommandLine[m_nTokenOffSet] == _T(' '))
  189. || (m_pszCommandLine[m_nTokenOffSet] == _T('\t'))
  190. || (m_pszCommandLine[m_nTokenOffSet] == _T(','))
  191. || (m_pszCommandLine[m_nTokenOffSet] == _T('('))
  192. || (m_pszCommandLine[m_nTokenOffSet] == _T(')'))
  193. || (m_pszCommandLine[m_nTokenOffSet] == _T('=') &&
  194. !CompareTokens(*(theIterator-1), CLI_TOKEN_WHERE) &&
  195. !CompareTokens(*(theIterator-1), CLI_TOKEN_PATH)))
  196. {
  197. break;
  198. }
  199. // if the command option is specified in quotes
  200. if (m_pszCommandLine[m_nTokenOffSet] == _T('"'))
  201. {
  202. m_nTokenOffSet++;
  203. // To include " within an quoted string it should
  204. // be preceded by \
  205. while (m_nTokenOffSet < nCmdLength)
  206. {
  207. if (m_pszCommandLine[m_nTokenOffSet] == _T('"'))
  208. {
  209. if (m_pszCommandLine[m_nTokenOffSet-1] == _T('\\'))
  210. {
  211. m_bEscapeSeq = TRUE;
  212. }
  213. else
  214. break;
  215. }
  216. m_nTokenOffSet++;
  217. }
  218. }
  219. m_nTokenOffSet++;
  220. }
  221. }
  222. return Token();
  223. }
  224. /*------------------------------------------------------------------------
  225. Name :Token
  226. Synopsis :This function extracts the portion of the command
  227. string using the token-start and token-offset value.
  228. If the token is not NULL, adds it to the list of
  229. tokens in the token vector.
  230. Type :Member Function
  231. Input parameter :None
  232. Output parameters :None
  233. Return Type :_TCHAR*
  234. Global Variables :None
  235. Calling Syntax :Token()
  236. Notes :None
  237. ------------------------------------------------------------------------*/
  238. _TCHAR* CCmdTokenizer::Token() throw(WMICLIINT)
  239. {
  240. WMICLIINT nLength = (m_nTokenOffSet - m_nTokenStart);
  241. _TCHAR* sToken = NULL;
  242. CHARVECTOR::iterator theIterator = NULL;
  243. if (nLength > 0)
  244. {
  245. // Allocate the memory for the new token.
  246. sToken = new _TCHAR [nLength + 1];
  247. if (sToken)
  248. {
  249. try
  250. {
  251. WMICLIINT nLoop = 0;
  252. WMICLIINT nInd = 0;
  253. BOOL bSpecialChar = FALSE;
  254. BOOL bPush = TRUE;
  255. // Form the token(s).
  256. while(nInd < nLength)
  257. {
  258. BOOL bPush = TRUE;
  259. while (nInd < nLength)
  260. {
  261. //If the character is ':'
  262. if(m_pszCommandLine[nInd + m_nTokenStart] == _T(':') &&
  263. bSpecialChar == FALSE)
  264. {
  265. _TCHAR* sToktemp = NULL;
  266. sToktemp = new _TCHAR [nLoop + 1];
  267. if (sToktemp == NULL)
  268. throw OUT_OF_MEMORY;
  269. if(lstrlen(sToken) > 0)
  270. {
  271. lstrcpyn(sToktemp,sToken,nLoop + 1);
  272. sToktemp[nLoop] = _T('\0');
  273. //if ':' is preceeded by ASSOC token
  274. if(CompareTokens(sToktemp,CLI_TOKEN_ASSOC))
  275. {
  276. bSpecialChar = TRUE;
  277. bPush = FALSE;
  278. SAFEDELETE(sToktemp);
  279. break;
  280. }
  281. //if ':' is preceded by FORMAT token
  282. else if(CompareTokens(sToktemp,CLI_TOKEN_FORMAT))
  283. { theIterator = m_cvTokens.end();
  284. if((theIterator - 1) >= m_cvTokens.begin() &&
  285. IsOption(*(theIterator - 1)))
  286. {
  287. m_bFormatToken = TRUE;
  288. bSpecialChar = TRUE;
  289. bPush = FALSE;
  290. SAFEDELETE(sToktemp);
  291. break;
  292. }
  293. }
  294. SAFEDELETE(sToktemp);
  295. }
  296. if (!m_cvTokens.empty())
  297. {
  298. theIterator = m_cvTokens.end();
  299. //if ':' is present previous token is '/'
  300. //(case arises when ':'
  301. //is specified without space after a switch)
  302. if( (theIterator - 1) >= m_cvTokens.begin() &&
  303. IsOption(*(theIterator - 1)))
  304. {
  305. bSpecialChar = TRUE;
  306. bPush = FALSE;
  307. break;
  308. }
  309. //if ':' is first character in the new token
  310. //(case arises when ':' is preceded by blank space)
  311. else if(m_nTokenStart != 0 &&
  312. m_pszCommandLine[m_nTokenStart] == _T(':'))
  313. {
  314. bSpecialChar = TRUE;
  315. bPush = FALSE;
  316. break;
  317. }
  318. //if ':' is encountered after format switch
  319. //and previous token is ':' or a ','
  320. //(case arises for specifying format switch)
  321. else if(m_bFormatToken == TRUE &&
  322. (CompareTokens(*(theIterator - 1),_T(":"))) ||
  323. (CompareTokens(*(theIterator - 1), CLI_TOKEN_COMMA)) ||
  324. (IsOption(*(theIterator - 1))))
  325. {
  326. bSpecialChar = TRUE;
  327. bPush = FALSE;
  328. break;
  329. }
  330. //if ':' is preceded by '?' and '?' in turn
  331. //is preceded by '/'
  332. //(case arises for specifying help option)
  333. else
  334. {
  335. theIterator = m_cvTokens.end();
  336. if(theIterator &&
  337. (theIterator - 2) >= m_cvTokens.begin() &&
  338. (CompareTokens(*(theIterator - 1),_T("?"))) &&
  339. (IsOption(*(theIterator - 2))))
  340. {
  341. bSpecialChar = TRUE;
  342. bPush = FALSE;
  343. break;
  344. }
  345. }
  346. }
  347. }
  348. //if character is '?'(for help switch)
  349. else if(m_pszCommandLine[nInd + m_nTokenStart] ==
  350. _T('?') && bSpecialChar == FALSE)
  351. {
  352. if (!m_cvTokens.empty())
  353. {
  354. theIterator = m_cvTokens.end();
  355. //if character is '?' and preceded by '/'(for help switch)
  356. if( (theIterator - 1) >= m_cvTokens.begin() &&
  357. IsOption(*(theIterator - 1)))
  358. {
  359. bSpecialChar = TRUE;
  360. bPush = FALSE;
  361. break;
  362. }
  363. }
  364. }
  365. sToken[nLoop] = m_pszCommandLine[nInd + m_nTokenStart];
  366. nLoop++;
  367. nInd++;
  368. if(m_pszCommandLine[nInd - 1 + m_nTokenStart] == _T('"'))
  369. {
  370. while(nInd < nLength)
  371. {
  372. sToken[nLoop] = m_pszCommandLine[
  373. nInd + m_nTokenStart];
  374. nLoop++;
  375. nInd++;
  376. if(nInd < nLength &&
  377. m_pszCommandLine[nInd + m_nTokenStart]
  378. == _T('"'))
  379. {
  380. if(m_pszCommandLine[nInd - 1 + m_nTokenStart]
  381. == _T('\\'))
  382. {
  383. m_bEscapeSeq = TRUE;
  384. }
  385. else
  386. {
  387. sToken[nLoop] = m_pszCommandLine[
  388. nInd + m_nTokenStart];
  389. nLoop++;
  390. nInd++;
  391. break;
  392. }
  393. }
  394. }
  395. }
  396. }
  397. // terminate the string with '\0'
  398. sToken[nLoop] = _T('\0');
  399. UnQuoteString(sToken);
  400. // If Escape sequence flag is set
  401. if (m_bEscapeSeq)
  402. {
  403. try
  404. {
  405. CHString sTemp((WCHAR*)sToken);
  406. /* Remove the escape sequence character i.e \ */
  407. RemoveEscapeChars(sTemp);
  408. lstrcpy(sToken, sTemp);
  409. m_bEscapeSeq = FALSE;
  410. }
  411. catch(CHeap_Exception)
  412. {
  413. throw OUT_OF_MEMORY;
  414. }
  415. catch(...)
  416. {
  417. throw OUT_OF_MEMORY;
  418. }
  419. }
  420. _TCHAR* sTokenTemp = NULL;
  421. sTokenTemp = new _TCHAR[nLoop + 1];
  422. if (sTokenTemp == NULL)
  423. throw OUT_OF_MEMORY;
  424. lstrcpy(sTokenTemp,sToken);
  425. if(bPush == TRUE || lstrlen(sTokenTemp) > 0)
  426. m_cvTokens.push_back(sTokenTemp);
  427. else
  428. SAFEDELETE(sTokenTemp);
  429. //reset m_FormatToken if next switch is expected
  430. if(m_bFormatToken == TRUE && IsOption(sTokenTemp))
  431. m_bFormatToken = FALSE;
  432. //if the character is found to be a special character
  433. if(bSpecialChar == TRUE)
  434. {
  435. sToken[0] = m_pszCommandLine[nInd + m_nTokenStart];
  436. sToken[1] = _T('\0');
  437. sTokenTemp = new _TCHAR[2];
  438. if (sTokenTemp == NULL)
  439. throw OUT_OF_MEMORY;
  440. lstrcpy(sTokenTemp,sToken);
  441. bSpecialChar = FALSE;
  442. nLoop = 0;
  443. nInd++;
  444. m_cvTokens.push_back(sTokenTemp);
  445. bPush = TRUE;
  446. theIterator++;
  447. }
  448. }
  449. SAFEDELETE(sToken);
  450. }
  451. catch(...)
  452. {
  453. SAFEDELETE(sToken);
  454. throw OUT_OF_MEMORY;
  455. }
  456. }
  457. else
  458. throw OUT_OF_MEMORY;
  459. }
  460. return sToken;
  461. }
  462. /*------------------------------------------------------------------------
  463. Name :GetTokenVector
  464. Synopsis :This function returns a reference to the token
  465. vector
  466. Type :Member Function
  467. Input parameter :None
  468. Output parameters :None
  469. Return Type :CHARVECTOR&
  470. Global Variables :None
  471. Calling Syntax :GetTokenVector()
  472. Notes :None
  473. ------------------------------------------------------------------------*/
  474. CHARVECTOR& CCmdTokenizer::GetTokenVector()
  475. {
  476. return m_cvTokens;
  477. }