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.

572 lines
17 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. CallSetOrCreatePresent() )
  171. {
  172. m_nTokenOffSet++;
  173. while ((m_nTokenOffSet < nCmdLength)
  174. && (m_pszCommandLine[m_nTokenOffSet] != _T(')')))
  175. {
  176. m_nTokenOffSet++;
  177. }
  178. }
  179. }
  180. }
  181. m_nTokenOffSet++;
  182. }
  183. else
  184. {
  185. while (m_nTokenOffSet < nCmdLength)
  186. {
  187. if ((m_pszCommandLine[m_nTokenOffSet] == _T('/'))
  188. || (m_pszCommandLine[m_nTokenOffSet] == _T('-'))
  189. || (m_pszCommandLine[m_nTokenOffSet] == _T(' '))
  190. || (m_pszCommandLine[m_nTokenOffSet] == _T('\t'))
  191. || (m_pszCommandLine[m_nTokenOffSet] == _T(','))
  192. || (m_pszCommandLine[m_nTokenOffSet] == _T('('))
  193. || (m_pszCommandLine[m_nTokenOffSet] == _T(')'))
  194. || (m_pszCommandLine[m_nTokenOffSet] == _T('=') &&
  195. !CompareTokens(*(theIterator-1), CLI_TOKEN_WHERE) &&
  196. !CompareTokens(*(theIterator-1), CLI_TOKEN_PATH)))
  197. {
  198. break;
  199. }
  200. // if the command option is specified in quotes
  201. if (m_pszCommandLine[m_nTokenOffSet] == _T('"'))
  202. {
  203. m_nTokenOffSet++;
  204. // To include " within an quoted string it should
  205. // be preceded by \
  206. while (m_nTokenOffSet < nCmdLength)
  207. {
  208. if (m_pszCommandLine[m_nTokenOffSet] == _T(',')){ m_nTokenOffSet--; break; }
  209. if (m_pszCommandLine[m_nTokenOffSet] == _T('"'))
  210. {
  211. if (m_pszCommandLine[m_nTokenOffSet-1] == _T('\\'))
  212. {
  213. m_bEscapeSeq = TRUE;
  214. }
  215. else
  216. break;
  217. }
  218. m_nTokenOffSet++;
  219. }
  220. } else if (m_pszCommandLine[m_nTokenOffSet] == _T('\'')){
  221. m_nTokenOffSet++;
  222. // To include " within an quoted string it should
  223. // be preceded by \
  224. while (m_nTokenOffSet < nCmdLength)
  225. {
  226. if (m_pszCommandLine[m_nTokenOffSet] == _T(',')){ m_nTokenOffSet--; break; }
  227. if (m_pszCommandLine[m_nTokenOffSet] == _T('\''))
  228. {
  229. if (m_pszCommandLine[m_nTokenOffSet-1] == _T('\\'))
  230. {
  231. m_bEscapeSeq = TRUE;
  232. }
  233. else
  234. break;
  235. }
  236. m_nTokenOffSet++;
  237. }
  238. }
  239. m_nTokenOffSet++;
  240. }
  241. }
  242. return Token();
  243. }
  244. /*------------------------------------------------------------------------
  245. Name :Token
  246. Synopsis :This function extracts the portion of the command
  247. string using the token-start and token-offset value.
  248. If the token is not NULL, adds it to the list of
  249. tokens in the token vector.
  250. Type :Member Function
  251. Input parameter :None
  252. Output parameters :None
  253. Return Type :_TCHAR*
  254. Global Variables :None
  255. Calling Syntax :Token()
  256. Notes :None
  257. ------------------------------------------------------------------------*/
  258. _TCHAR* CCmdTokenizer::Token() throw(WMICLIINT)
  259. {
  260. WMICLIINT nLength = (m_nTokenOffSet - m_nTokenStart);
  261. _TCHAR* sToken = NULL;
  262. CHARVECTOR::iterator theIterator = NULL;
  263. if (nLength > 0)
  264. {
  265. // Allocate the memory for the new token.
  266. sToken = new _TCHAR [nLength + 1];
  267. if (sToken)
  268. {
  269. try
  270. {
  271. WMICLIINT nLoop = 0;
  272. WMICLIINT nInd = 0;
  273. BOOL bSpecialChar = FALSE;
  274. BOOL bPush = TRUE;
  275. // Form the token(s).
  276. while(nInd < nLength)
  277. {
  278. BOOL bPush = TRUE;
  279. while (nInd < nLength)
  280. {
  281. //If the character is ':'
  282. if(m_pszCommandLine[nInd + m_nTokenStart] == _T(':') &&
  283. bSpecialChar == FALSE)
  284. {
  285. _TCHAR* sToktemp = NULL;
  286. sToktemp = new _TCHAR [nLoop + 1];
  287. if (sToktemp == NULL)
  288. throw OUT_OF_MEMORY;
  289. if(nInd > 0)
  290. {
  291. lstrcpyn(sToktemp,sToken,nLoop + 1);
  292. sToktemp[nLoop] = _T('\0');
  293. //if ':' is preceeded by ASSOC token
  294. if(CompareTokens(sToktemp,CLI_TOKEN_ASSOC))
  295. {
  296. bSpecialChar = TRUE;
  297. bPush = FALSE;
  298. SAFEDELETE(sToktemp);
  299. break;
  300. }
  301. //if ':' is preceded by FORMAT token
  302. else if(CompareTokens(sToktemp,CLI_TOKEN_FORMAT))
  303. { theIterator = m_cvTokens.end();
  304. if((theIterator - 1) >= m_cvTokens.begin() &&
  305. IsOption(*(theIterator - 1)))
  306. {
  307. m_bFormatToken = TRUE;
  308. bSpecialChar = TRUE;
  309. bPush = FALSE;
  310. SAFEDELETE(sToktemp);
  311. break;
  312. }
  313. }
  314. SAFEDELETE(sToktemp);
  315. }
  316. if (!m_cvTokens.empty())
  317. {
  318. theIterator = m_cvTokens.end();
  319. //if ':' is present previous token is '/'
  320. //(case arises when ':'
  321. //is specified without space after a switch)
  322. if( (theIterator - 1) >= m_cvTokens.begin() &&
  323. IsOption(*(theIterator - 1)))
  324. {
  325. bSpecialChar = TRUE;
  326. bPush = FALSE;
  327. break;
  328. }
  329. //if ':' is first character in the new token
  330. //(case arises when ':' is preceded by blank space)
  331. else if(m_nTokenStart != 0 &&
  332. m_pszCommandLine[m_nTokenStart] == _T(':'))
  333. {
  334. bSpecialChar = TRUE;
  335. bPush = FALSE;
  336. break;
  337. }
  338. //if ':' is encountered after format switch
  339. //and previous token is ':' or a ','
  340. //(case arises for specifying format switch)
  341. else if(m_bFormatToken == TRUE &&
  342. (CompareTokens(*(theIterator - 1),_T(":"))) ||
  343. (IsOption(*(theIterator - 1))))
  344. {
  345. bSpecialChar = TRUE;
  346. bPush = FALSE;
  347. break;
  348. }
  349. //if ':' is preceded by '?' and '?' in turn
  350. //is preceded by '/'
  351. //(case arises for specifying help option)
  352. else
  353. {
  354. theIterator = m_cvTokens.end();
  355. if(theIterator &&
  356. (theIterator - 2) >= m_cvTokens.begin() &&
  357. (CompareTokens(*(theIterator - 1),_T("?"))) &&
  358. (IsOption(*(theIterator - 2))))
  359. {
  360. bSpecialChar = TRUE;
  361. bPush = FALSE;
  362. break;
  363. }
  364. }
  365. }
  366. }
  367. //if character is '?'(for help switch)
  368. else if(m_pszCommandLine[nInd + m_nTokenStart] ==
  369. _T('?') && bSpecialChar == FALSE)
  370. {
  371. if (!m_cvTokens.empty())
  372. {
  373. theIterator = m_cvTokens.end();
  374. //if character is '?' and preceded by '/'(for help switch)
  375. if( (theIterator - 1) >= m_cvTokens.begin() &&
  376. IsOption(*(theIterator - 1)))
  377. {
  378. bSpecialChar = TRUE;
  379. bPush = FALSE;
  380. break;
  381. }
  382. }
  383. }
  384. sToken[nLoop] = m_pszCommandLine[nInd + m_nTokenStart];
  385. nLoop++;
  386. nInd++;
  387. if(m_pszCommandLine[nInd - 1 + m_nTokenStart] == _T('"'))
  388. {
  389. while(nInd < nLength)
  390. {
  391. sToken[nLoop] = m_pszCommandLine[
  392. nInd + m_nTokenStart];
  393. nLoop++;
  394. nInd++;
  395. if(nInd < nLength &&
  396. m_pszCommandLine[nInd + m_nTokenStart]
  397. == _T('"'))
  398. {
  399. if(m_pszCommandLine[nInd - 1 + m_nTokenStart]
  400. == _T('\\'))
  401. {
  402. if (0 == nInd)
  403. {
  404. m_bEscapeSeq = TRUE;
  405. }
  406. }
  407. else
  408. {
  409. sToken[nLoop] = m_pszCommandLine[
  410. nInd + m_nTokenStart];
  411. nLoop++;
  412. nInd++;
  413. break;
  414. }
  415. }
  416. }
  417. }
  418. }
  419. // terminate the string with '\0'
  420. sToken[nLoop] = _T('\0');
  421. UnQuoteString(sToken);
  422. // If Escape sequence flag is set
  423. if (m_bEscapeSeq)
  424. {
  425. try
  426. {
  427. CHString sTemp((WCHAR*)sToken);
  428. /* Remove the escape sequence character i.e \ */
  429. RemoveEscapeChars(sTemp);
  430. lstrcpy(sToken, sTemp);
  431. m_bEscapeSeq = FALSE;
  432. }
  433. catch(CHeap_Exception)
  434. {
  435. throw OUT_OF_MEMORY;
  436. }
  437. catch(...)
  438. {
  439. throw OUT_OF_MEMORY;
  440. }
  441. }
  442. _TCHAR* sTokenTemp = NULL;
  443. sTokenTemp = new _TCHAR[nLoop + 1];
  444. if (sTokenTemp == NULL)
  445. throw OUT_OF_MEMORY;
  446. lstrcpy(sTokenTemp,sToken);
  447. if(bPush == TRUE || lstrlen(sTokenTemp) > 0)
  448. m_cvTokens.push_back(sTokenTemp);
  449. else
  450. SAFEDELETE(sTokenTemp);
  451. //reset m_FormatToken if next switch is expected
  452. if(m_bFormatToken == TRUE && IsOption(sTokenTemp))
  453. m_bFormatToken = FALSE;
  454. //if the character is found to be a special character
  455. if(bSpecialChar == TRUE)
  456. {
  457. sToken[0] = m_pszCommandLine[nInd + m_nTokenStart];
  458. sToken[1] = _T('\0');
  459. sTokenTemp = new _TCHAR[2];
  460. if (sTokenTemp == NULL)
  461. throw OUT_OF_MEMORY;
  462. lstrcpy(sTokenTemp,sToken);
  463. bSpecialChar = FALSE;
  464. nLoop = 0;
  465. nInd++;
  466. m_cvTokens.push_back(sTokenTemp);
  467. bPush = TRUE;
  468. theIterator++;
  469. }
  470. }
  471. SAFEDELETE(sToken);
  472. }
  473. catch(...)
  474. {
  475. SAFEDELETE(sToken);
  476. throw OUT_OF_MEMORY;
  477. }
  478. }
  479. else
  480. throw OUT_OF_MEMORY;
  481. }
  482. return sToken;
  483. }
  484. /*------------------------------------------------------------------------
  485. Name :GetTokenVector
  486. Synopsis :This function returns a reference to the token
  487. vector
  488. Type :Member Function
  489. Input parameter :None
  490. Output parameters :None
  491. Return Type :CHARVECTOR&
  492. Global Variables :None
  493. Calling Syntax :GetTokenVector()
  494. Notes :None
  495. ------------------------------------------------------------------------*/
  496. CHARVECTOR& CCmdTokenizer::GetTokenVector()
  497. {
  498. return m_cvTokens;
  499. }
  500. /*------------------------------------------------------------------------
  501. Name :CallSetOrCreatePresent
  502. Synopsis :This function checks whether CALL or SET or CREATE
  503. is present in the tokens vector.
  504. Type :Member Function
  505. Input parameter :None
  506. Output parameters :None
  507. Return Type :BOOL
  508. Global Variables :None
  509. Calling Syntax :CallSetOrCreatePresent()
  510. Notes :None
  511. ------------------------------------------------------------------------*/
  512. BOOL CCmdTokenizer::CallSetOrCreatePresent()
  513. {
  514. BOOL bRet = FALSE;
  515. WMICLIINT nSizeOfVector = m_cvTokens.size();
  516. // Check is there any CALL or SET verbs in the vector
  517. for(WMICLIINT i=0; i<nSizeOfVector; ++i)
  518. {
  519. if( CompareTokens(m_cvTokens[i], CLI_TOKEN_CALL) ||
  520. CompareTokens(m_cvTokens[i], CLI_TOKEN_SET) ||
  521. CompareTokens(m_cvTokens[i], CLI_TOKEN_CREATE) )
  522. {
  523. bRet = TRUE;
  524. break;
  525. }
  526. }
  527. return bRet;
  528. }