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.

1525 lines
41 KiB

  1. /*****************************************************************************\
  2. Author: Hiteshr
  3. Copyright (c) 1998-2000 Microsoft Corporation
  4. Change History:
  5. Adapted From Parser Implemenation of Corey Morgan
  6. \*****************************************************************************/
  7. #include "pch.h"
  8. #include "..\dsutil2.h" // GetEscapedElement
  9. BOOL ValidateCommands(IN ARG_RECORD *Commands,OUT PPARSE_ERROR pError);
  10. // void DisplayDebugInfo(IN ARG_RECORD *Commands);
  11. // JonN 4/26/01 256583
  12. DWORD AddDNEscaping_Commands( IN OUT ARG_RECORD *Commands );
  13. DWORD AddDNEscaping_DN( OUT LPWSTR* ppszOut, IN LPWSTR pszIn );
  14. BOOL StartBuffer( OUT LPTSTR* pbuffer,
  15. OUT LONG* pmaxSize,
  16. OUT LONG* pcurrentSize );
  17. DWORD AddToBuffer( IN LPCTSTR psz,
  18. IN OUT LPTSTR* pbuffer,
  19. IN OUT LONG* pmaxSize,
  20. IN OUT LONG* pcurrentSize,
  21. IN BOOL fMSZBuffer);
  22. #define FILL_ERROR(pError,source,error_code,rec_index,argv_index) \
  23. pError->ErrorSource = source; \
  24. pError->Error = error_code; \
  25. pError->ArgRecIndex = rec_index; \
  26. pError->ArgvIndex = argv_index;
  27. BOOL IsCmd( PARG_RECORD arg, LPTOKEN pToken)
  28. {
  29. if(!arg || !pToken)
  30. return FALSE;
  31. LPWSTR str = pToken->GetToken();
  32. if(!str)
  33. return FALSE;
  34. if(pToken->IsSwitch())
  35. {
  36. str++;
  37. }else
  38. {
  39. if( (arg->fFlag & ARG_FLAG_NOFLAG) && !arg->bDefined )
  40. {
  41. return TRUE;
  42. }
  43. if( !(arg->fFlag & ARG_FLAG_VERB) )
  44. {
  45. return FALSE;
  46. }
  47. }
  48. if( ( arg->strArg1 && !_tcsicmp( str, arg->strArg1 ) )
  49. ||(arg->strArg2 && !_tcsicmp( str, arg->strArg2 )) )
  50. {
  51. return TRUE;
  52. }
  53. return FALSE;
  54. }
  55. void FreeCmd(ARG_RECORD *Commands)
  56. {
  57. int i;
  58. for(i=0;Commands[i].fType != ARG_TYPE_LAST;i++)
  59. {
  60. if((Commands[i].fType == ARG_TYPE_STR ||
  61. Commands[i].fType == ARG_TYPE_MSZ ) &&
  62. Commands[i].bDefined )
  63. {
  64. LocalFree( Commands[i].strValue );
  65. Commands[i].strValue = NULL;
  66. }
  67. if( Commands[i].idArg1 && Commands[i].strArg1 != NULL )
  68. {
  69. LocalFree(Commands[i].strArg1);
  70. }
  71. if( Commands[i].idArg2 && Commands[i].strArg2 != NULL )
  72. {
  73. LocalFree( Commands[i].strArg2 );
  74. }
  75. Commands[i].bDefined = FALSE;
  76. }
  77. }
  78. BOOL LoadCmd(ARG_RECORD *Commands)
  79. {
  80. int i;
  81. BOOL bRet = TRUE;
  82. for( i=0; Commands[i].fType!=ARG_TYPE_LAST; i++ )
  83. {
  84. if(Commands[i].idArg1 !=0)
  85. if(!LoadStringAlloc(&Commands[i].strArg1, NULL,Commands[i].idArg1))
  86. {
  87. bRet = FALSE;
  88. break;
  89. }
  90. if(Commands[i].idArg2 !=0 && Commands[i].idArg2 != ID_ARG2_NULL)
  91. if(!LoadStringAlloc(&Commands[i].strArg2, NULL,Commands[i].idArg2))
  92. {
  93. bRet = FALSE;
  94. break;
  95. }
  96. }
  97. return bRet;
  98. }
  99. BOOL
  100. ValidateCommands(ARG_RECORD *Commands, PPARSE_ERROR pError)
  101. {
  102. int i = 0;
  103. LONG cReadFromStdin = 0;
  104. ARG_RECORD *CommandsIn = NULL;
  105. LPWSTR pBuffer=NULL;
  106. LONG BufferLen = 0;
  107. LPTOKEN pToken = NULL;
  108. int argc=0;
  109. BOOL bRet = FALSE;
  110. bool bAtLeastOne = false;
  111. bool bAtLeastOneDefined = false;
  112. if(!Commands || !pError)
  113. goto exit_gracefully;
  114. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  115. {
  116. if( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined)
  117. {
  118. if(Commands[i].fFlag & ARG_FLAG_STDIN)
  119. {
  120. cReadFromStdin++;
  121. }
  122. else
  123. {
  124. FILL_ERROR(pError,
  125. ERROR_FROM_PARSER,
  126. PARSE_ERROR_SWITCH_NOTDEFINED,
  127. i,
  128. -1);
  129. goto exit_gracefully;
  130. }
  131. }
  132. if (Commands[i].fFlag & ARG_FLAG_ATLEASTONE)
  133. {
  134. bAtLeastOne = true;
  135. if (Commands[i].bDefined)
  136. {
  137. bAtLeastOneDefined = true;
  138. }
  139. }
  140. }
  141. if (bAtLeastOne && !bAtLeastOneDefined)
  142. {
  143. pError->ErrorSource = ERROR_FROM_PARSER;
  144. pError->Error = PARSE_ERROR_ATLEASTONE_NOTDEFINED;
  145. pError->ArgRecIndex = -1;
  146. pError->ArgvIndex = -1;
  147. goto exit_gracefully;
  148. }
  149. if(!cReadFromStdin)
  150. {
  151. bRet = TRUE;
  152. goto exit_gracefully;
  153. }
  154. //Read From STDIN
  155. BufferLen = ReadFromIn(&pBuffer);
  156. if(BufferLen == -1)
  157. {
  158. FILL_ERROR(pError,
  159. ERROR_WIN32_ERROR,
  160. GetLastError(),
  161. -1,
  162. -1);
  163. goto exit_gracefully;
  164. }
  165. if(BufferLen == 0)
  166. {
  167. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  168. {
  169. if( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined)
  170. {
  171. FILL_ERROR(pError,
  172. ERROR_FROM_PARSER,
  173. PARSE_ERROR_SWITCH_NOTDEFINED,
  174. i,
  175. -1);
  176. goto exit_gracefully;
  177. }
  178. }
  179. }
  180. if(BufferLen)
  181. {
  182. //Tokenize what you have read from STDIN
  183. DWORD dwErr;
  184. WCHAR szDelimiters[] = L" \n\t";
  185. dwErr = Tokenize(pBuffer,
  186. BufferLen,
  187. szDelimiters,
  188. &pToken,
  189. &argc);
  190. if( dwErr != ERROR_SUCCESS )
  191. {
  192. FILL_ERROR(pError,
  193. ERROR_WIN32_ERROR,
  194. dwErr,
  195. -1,
  196. -1);
  197. goto exit_gracefully;
  198. }
  199. //Prepare a CommandArray for them
  200. CommandsIn = (ARG_RECORD*)LocalAlloc(LPTR,sizeof(ARG_RECORD)*(cReadFromStdin+1));
  201. if(!CommandsIn)
  202. {
  203. FILL_ERROR(pError,
  204. ERROR_WIN32_ERROR,
  205. ERROR_NOT_ENOUGH_MEMORY,
  206. -1,
  207. -1);
  208. goto exit_gracefully;
  209. }
  210. int j;
  211. j = 0;
  212. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  213. {
  214. if((Commands[i].fFlag & ARG_FLAG_REQUIRED) &&
  215. (Commands[i].fFlag & ARG_FLAG_STDIN) &&
  216. !Commands[i].bDefined)
  217. {
  218. CommandsIn[j++] = Commands[i];
  219. }
  220. }
  221. //Copy the Last One
  222. CommandsIn[j] = Commands[i];
  223. if(!ParseCmd(CommandsIn,
  224. argc,
  225. pToken,
  226. 0,
  227. pError,
  228. FALSE))
  229. {
  230. goto exit_gracefully;
  231. }
  232. //Copy the values back to Commands
  233. j=0;
  234. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  235. {
  236. if((Commands[i].fFlag & ARG_FLAG_REQUIRED) &&
  237. (Commands[i].fFlag & ARG_FLAG_STDIN) &&
  238. !Commands[i].bDefined)
  239. {
  240. Commands[i] = CommandsIn[j++];
  241. }
  242. }
  243. //Validate Commands
  244. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  245. {
  246. if( (Commands[i].fFlag & ARG_FLAG_REQUIRED) && !Commands[i].bDefined)
  247. {
  248. FILL_ERROR(pError,
  249. ERROR_FROM_PARSER,
  250. PARSE_ERROR_SWITCH_NOTDEFINED,
  251. i,
  252. -1);
  253. goto exit_gracefully;
  254. }
  255. }
  256. }
  257. bRet = TRUE;
  258. exit_gracefully:
  259. if(CommandsIn)
  260. LocalFree(CommandsIn);
  261. if(pBuffer)
  262. LocalFree(pBuffer);
  263. if(pToken)
  264. {
  265. delete []pToken;
  266. }
  267. return bRet;
  268. }
  269. BOOL ParseCmd(IN ARG_RECORD *Commands,
  270. IN int argc,
  271. IN LPTOKEN pToken,
  272. IN DWORD UsageMessageId,
  273. OUT PPARSE_ERROR pError,
  274. IN BOOL bValidate )
  275. {
  276. int i;
  277. BOOL bFound;
  278. BOOL bDoDebug = FALSE;
  279. int argCount;
  280. DWORD dwErr = ERROR_SUCCESS;
  281. BOOL bReturn = TRUE;
  282. LPTOKEN pTokenCopy = pToken;
  283. if(!Commands || argc == 0 || !pToken || !pError)
  284. {
  285. bReturn = FALSE;
  286. goto exit_gracefully;
  287. }
  288. if(!LoadCmd(Commands))
  289. {
  290. bReturn = FALSE;
  291. goto exit_gracefully;
  292. }
  293. argCount = argc;
  294. while( argc > 0 )
  295. {
  296. bFound = FALSE;
  297. for(i=0; Commands[i].fType != ARG_TYPE_LAST && (!bFound);i++)
  298. {
  299. if( IsCmd( &Commands[i], pToken) )
  300. {
  301. if(Commands[i].bDefined)
  302. {
  303. FILL_ERROR(pError,
  304. ERROR_FROM_PARSER,
  305. PARSE_ERROR_MULTIPLE_DEF,
  306. i,
  307. -1);
  308. bReturn = FALSE;
  309. goto exit_gracefully;
  310. }
  311. if( pToken->IsSwitch() || Commands[i].fFlag & ARG_FLAG_VERB ){
  312. pToken++;argc--;
  313. }
  314. bFound = TRUE;
  315. Commands[i].bDefined = TRUE;
  316. switch( Commands[i].fType ){
  317. case ARG_TYPE_HELP:
  318. {
  319. Commands[i].bValue = TRUE;
  320. if( Commands[i].fntValidation != NULL )
  321. {
  322. Commands[i].fntValidation( Commands + i );
  323. }
  324. FILL_ERROR(pError,
  325. ERROR_FROM_PARSER,
  326. PARSE_ERROR_HELP_SWITCH,
  327. i,
  328. -1);
  329. if(UsageMessageId)
  330. DisplayMessage(UsageMessageId);
  331. bReturn = FALSE;
  332. goto exit_gracefully;
  333. }
  334. break;
  335. case ARG_TYPE_DEBUG:
  336. //
  337. // REVIEW_JEFFJON : removed for now because it was AVing for dsadd group -secgrp
  338. //
  339. // bDoDebug = TRUE;
  340. Commands[i].fFlag |= ARG_FLAG_DEFAULTABLE;
  341. case ARG_TYPE_INT:
  342. {
  343. if( argc > 0 && !pToken->IsSwitch())
  344. {
  345. PWSTR pszToken = pToken->GetToken();
  346. Commands[i].nValue = _ttoi( pszToken);
  347. if (Commands[i].nValue == 0 &&
  348. !iswdigit(pszToken[0]))
  349. {
  350. FILL_ERROR(pError,
  351. ERROR_FROM_PARSER,
  352. PARSE_ERROR_SWITCH_VALUE,
  353. i,
  354. argCount - argc);
  355. bReturn = FALSE;
  356. goto exit_gracefully;
  357. }
  358. pToken++;argc--;
  359. }
  360. else if( !(Commands[i].fFlag & ARG_FLAG_DEFAULTABLE) )
  361. {
  362. FILL_ERROR(pError,
  363. ERROR_FROM_PARSER,
  364. PARSE_ERROR_SWICH_NO_VALUE,
  365. i,
  366. argCount - argc);
  367. bReturn = FALSE;
  368. goto exit_gracefully;
  369. }
  370. }
  371. break;
  372. case ARG_TYPE_BOOL:
  373. Commands[i].bValue = TRUE;
  374. break;
  375. case ARG_TYPE_MSZ:
  376. if( argc > 0 && !pToken->IsSwitch())
  377. {
  378. LPTSTR buffer = NULL;
  379. LONG maxSize = 0;
  380. LONG currentSize = 0;
  381. if (!StartBuffer(&buffer,&maxSize,&currentSize))
  382. {
  383. FILL_ERROR(pError,
  384. ERROR_WIN32_ERROR,
  385. ERROR_NOT_ENOUGH_MEMORY,
  386. -1,
  387. argCount - argc);
  388. bReturn = FALSE;
  389. goto exit_gracefully;
  390. }
  391. LPCTSTR pszTemp = pToken->GetToken();
  392. dwErr = AddToBuffer(pszTemp,&buffer,&maxSize,&currentSize,TRUE);
  393. if (NO_ERROR != dwErr)
  394. {
  395. FILL_ERROR(pError,
  396. ERROR_WIN32_ERROR,
  397. dwErr,
  398. i,
  399. -1);
  400. bReturn = FALSE;
  401. goto exit_gracefully;
  402. }
  403. pToken++;argc--;
  404. while( argc > 0 && !pToken->IsSwitch() )
  405. {
  406. pszTemp = pToken->GetToken();
  407. dwErr = AddToBuffer(pszTemp,&buffer,&maxSize,&currentSize,TRUE);
  408. if (NO_ERROR != dwErr)
  409. {
  410. FILL_ERROR(pError,
  411. ERROR_WIN32_ERROR,
  412. dwErr,
  413. i,
  414. -1);
  415. bReturn = FALSE;
  416. goto exit_gracefully;
  417. }
  418. pToken++;argc--;
  419. }
  420. Commands[i].strValue = buffer;
  421. }
  422. else if( Commands[i].fFlag & ARG_FLAG_DEFAULTABLE ){
  423. LPTSTR strValue = Commands[i].strValue;
  424. Commands[i].strValue = (LPTSTR)LocalAlloc(LPTR, (_tcslen(strValue)+1) * sizeof(TCHAR) );
  425. if( Commands[i].strValue != NULL ){
  426. _tcscpy( Commands[i].strValue, strValue );
  427. }
  428. }
  429. else
  430. {
  431. FILL_ERROR(pError,
  432. ERROR_FROM_PARSER,
  433. PARSE_ERROR_SWICH_NO_VALUE,
  434. i,
  435. -1);
  436. bReturn = FALSE;
  437. goto exit_gracefully;
  438. }
  439. break;
  440. case ARG_TYPE_STR:
  441. if( argc > 0 && !pToken->IsSwitch())
  442. {
  443. Commands[i].strValue = (LPTSTR)LocalAlloc(LPTR, (_tcslen(pToken->GetToken())+2) * sizeof(TCHAR) );
  444. if( Commands[i].strValue != NULL )
  445. {
  446. _tcscpy( Commands[i].strValue, pToken->GetToken() );
  447. }
  448. pToken++;argc--;
  449. }else if( Commands[i].fFlag & ARG_FLAG_DEFAULTABLE )
  450. {
  451. LPTSTR strValue = Commands[i].strValue;
  452. Commands[i].strValue = (LPTSTR)LocalAlloc(LPTR, (_tcslen(strValue)+2) * sizeof(TCHAR) );
  453. if( Commands[i].strValue != NULL )
  454. {
  455. _tcscpy( Commands[i].strValue, strValue );
  456. }
  457. }else
  458. {
  459. FILL_ERROR(pError,
  460. ERROR_FROM_PARSER,
  461. PARSE_ERROR_SWICH_NO_VALUE,
  462. i,
  463. -1);
  464. bReturn = FALSE;
  465. goto exit_gracefully;
  466. }
  467. break;
  468. case ARG_TYPE_INTSTR:
  469. //
  470. // We use IsSlash here instead of IsSwitch because we want to allow
  471. // negative numbers
  472. //
  473. if( argc > 0 && !pToken->IsSlash())
  474. {
  475. PWSTR pszToken = pToken->GetToken();
  476. size_t strLen = wcslen(pszToken);
  477. Commands[i].nValue = _ttoi( pszToken);
  478. Commands[i].fType = ARG_TYPE_INT;
  479. if (Commands[i].nValue == 0 &&
  480. !iswdigit(pszToken[0]))
  481. {
  482. //
  483. // Then treat as a string
  484. //
  485. Commands[i].strValue = (LPTSTR)LocalAlloc(LPTR, (_tcslen(pToken->GetToken())+2) * sizeof(TCHAR) );
  486. if( Commands[i].strValue != NULL )
  487. {
  488. _tcscpy( Commands[i].strValue, pToken->GetToken() );
  489. Commands[i].fType = ARG_TYPE_STR;
  490. }
  491. }
  492. pToken++;argc--;
  493. }
  494. else if( !(Commands[i].fFlag & ARG_FLAG_DEFAULTABLE) )
  495. {
  496. FILL_ERROR(pError,
  497. ERROR_FROM_PARSER,
  498. PARSE_ERROR_SWICH_NO_VALUE,
  499. i,
  500. argCount - argc);
  501. bReturn = FALSE;
  502. goto exit_gracefully;
  503. }
  504. break;
  505. }
  506. if( Commands[i].bDefined && Commands[i].fntValidation != NULL )
  507. {
  508. dwErr = Commands[i].fntValidation(Commands + i);
  509. if( dwErr != ERROR_SUCCESS )
  510. {
  511. FILL_ERROR(pError,
  512. ERROR_FROM_VLDFN,
  513. dwErr,
  514. i,
  515. -1);
  516. bReturn = FALSE;
  517. goto exit_gracefully;
  518. }
  519. }
  520. }
  521. }
  522. if (!bFound)
  523. {
  524. pError->ErrorSource = ERROR_FROM_PARSER;
  525. pError->Error = PARSE_ERROR_UNKNOWN_INPUT_PARAMETER;
  526. pError->ArgRecIndex = -1;
  527. pError->ArgvIndex = argCount - argc;
  528. bReturn = FALSE;
  529. goto exit_gracefully;
  530. }
  531. }
  532. if( bDoDebug )
  533. {
  534. // DisplayDebugInfo(Commands);
  535. }
  536. if(bValidate && !ValidateCommands(Commands,pError))
  537. {
  538. bReturn = FALSE;
  539. goto exit_gracefully;
  540. }
  541. // JonN 4/26/01 256583
  542. // Note that this must be called after ValidateCommands, which completes
  543. // reading parameters from STDIN. If !bValidate, then we are in the
  544. // middle of a call to ValidateCommands.
  545. if (bValidate)
  546. {
  547. dwErr = AddDNEscaping_Commands(Commands);
  548. if( dwErr != ERROR_SUCCESS )
  549. {
  550. FILL_ERROR(pError,
  551. ERROR_WIN32_ERROR,
  552. dwErr,
  553. -1,
  554. -1);
  555. bReturn = FALSE;
  556. goto exit_gracefully;
  557. }
  558. }
  559. exit_gracefully:
  560. if(!bReturn)
  561. DisplayParseError(pError, Commands, pTokenCopy);
  562. return bReturn;
  563. }
  564. /*
  565. void
  566. DisplayDebugInfo(ARG_RECORD *Commands)
  567. {
  568. int i;
  569. int nOut;
  570. for(i=0; Commands[i].fType != ARG_TYPE_LAST;i++)
  571. {
  572. if( Commands[i].fType == ARG_TYPE_HELP ){
  573. continue;
  574. }
  575. nOut = _tprintf( _T("%s"), Commands[i].strArg1 );
  576. while( ++nOut < 10 )
  577. {
  578. _tprintf( _T(" ") );
  579. }
  580. _tprintf( _T("= ") );
  581. switch( Commands[i].fType )
  582. {
  583. case ARG_TYPE_DEBUG:
  584. case ARG_TYPE_INT:
  585. _tprintf( _T("%d"),
  586. Commands[i].nValue
  587. );
  588. break;
  589. case ARG_TYPE_BOOL:
  590. _tprintf( _T("%s"),
  591. Commands[i].bValue ? _T("TRUE") : _T("FALSE")
  592. );
  593. break;
  594. case ARG_TYPE_MSZ:
  595. if( NULL != Commands[i].strValue && _tcslen( Commands[i].strValue ) )
  596. {
  597. _tprintf( _T("%s ..."), Commands[i].strValue);
  598. }else
  599. {
  600. _tprintf( _T("%s"),_T("-") );
  601. }
  602. break;
  603. case ARG_TYPE_STR:
  604. _tprintf( _T("%s"),
  605. (Commands[i].strValue == NULL || !(_tcslen(Commands[i].strValue)) ) ?
  606. _T("-") : Commands[i].strValue
  607. );
  608. break;
  609. }
  610. _tprintf( _T("\n") );
  611. }
  612. _tprintf( _T("\n") );
  613. }
  614. */
  615. //This Function reads from the Command Line,
  616. //return it in tokenized format.
  617. DWORD GetCommandInput( OUT int *pargc, //Number of Tokens
  618. OUT LPTOKEN *ppToken) //Array of CToken
  619. {
  620. LPWSTR pBuffer = NULL;
  621. DWORD dwErr = ERROR_SUCCESS;
  622. WCHAR szDelimiters[] = L" \n\t";
  623. *pargc = 0;
  624. //Read the commandline input
  625. pBuffer = GetCommandLine();
  626. if(pBuffer)
  627. dwErr = Tokenize(pBuffer,
  628. wcslen(pBuffer),
  629. szDelimiters,
  630. ppToken,
  631. pargc);
  632. return dwErr;
  633. }
  634. BOOL IsDelimiter(WCHAR ch, LPWSTR pszDelimiters)
  635. {
  636. while(*pszDelimiters)
  637. if((WCHAR)*pszDelimiters++ == ch)
  638. return TRUE;
  639. return FALSE;
  640. }
  641. /*
  642. This Function Tokenize the input buffer. It needs to be called in two step.
  643. First time you call it, provide pBuf and Buflen. First Call will return
  644. the first token. To get next token, call the function with NULL for pBuf and
  645. 0 for Buflen.
  646. Output: pbQuote is true if this token was enclosed in a quote.
  647. ppToken: Token string. Call LocalFree to free it.
  648. Return Value:Length of Token if token found.
  649. 0 if no token found.
  650. -1 in case of error. Call GetLastError to get the error.
  651. */
  652. LONG GetToken(IN LPWSTR pBuf,
  653. IN LONG BufLen,
  654. IN LPWSTR pszDelimiters,
  655. OUT BOOL *pbQuote,
  656. OUT LPWSTR *ppToken)
  657. {
  658. static LPWSTR pBuffer;
  659. static LONG BufferLen;
  660. DWORD dwErr = ERROR_SUCCESS;
  661. if(pbQuote)
  662. *pbQuote = FALSE;
  663. if(ppToken)
  664. *ppToken = NULL;
  665. LONG MaxSize = INIT_SIZE;
  666. LONG pos = 0;
  667. if(pBuf)
  668. pBuffer = pBuf;
  669. if(BufLen)
  670. BufferLen = BufLen;
  671. if(!BufferLen)
  672. return pos;
  673. do
  674. {
  675. BOOL bQuoteBegin = FALSE;
  676. LPTSTR pItem = NULL;
  677. //Find the begining of Next Token
  678. // while( pBuffer[0] == L' ' ||
  679. // pBuffer[0] == L'\t' ||
  680. // pBuffer[0] == L'\n' && BufferLen)
  681. while(BufferLen && IsDelimiter(pBuffer[0],pszDelimiters) )
  682. {
  683. ++pBuffer;--BufferLen;
  684. }
  685. if(!BufferLen)
  686. break;
  687. //Does Token Start with '"'
  688. if( pBuffer[0] == L'"' )
  689. {
  690. if(pbQuote)
  691. *pbQuote = TRUE;
  692. bQuoteBegin = TRUE;
  693. pBuffer++; --BufferLen;
  694. }
  695. if(!BufferLen)
  696. break;
  697. if(ppToken)
  698. {
  699. pItem = (LPTSTR)LocalAlloc(LPTR,sizeof(WCHAR)*INIT_SIZE);
  700. if(!pItem)
  701. {
  702. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  703. return -1;
  704. }
  705. }
  706. //Now get the end
  707. WCHAR ch;
  708. while( BufferLen )
  709. {
  710. BOOL bChar = TRUE;
  711. if( BufferLen >= 2 && *pBuffer == L'\\' && *(pBuffer+1) == L'"')
  712. {
  713. ch = L'"';
  714. pBuffer +=2; BufferLen -=2;
  715. }
  716. else if(pBuffer[0] == L'"')
  717. {
  718. //A Matching Quote Found.
  719. if(bQuoteBegin)
  720. {
  721. ++pBuffer;
  722. --BufferLen;
  723. if(BufferLen)
  724. {
  725. //If next char is whitespace endof token
  726. //Ex "ABC" "xyz" . after C its endof token
  727. //if(pBuffer[0] == L' ' ||
  728. // pBuffer[0] == L'\t' ||
  729. // pBuffer[0] == L'\n')
  730. if(IsDelimiter(pBuffer[0],pszDelimiters) )
  731. break;
  732. else
  733. {
  734. //Ex "ABC"xyz
  735. if(pBuffer[0] != L'"')
  736. bQuoteBegin = FALSE;
  737. //"ABC""xyz"
  738. else
  739. {
  740. ++pBuffer;
  741. --BufferLen;
  742. }
  743. }
  744. }
  745. bChar = FALSE;
  746. //
  747. // Don't break because "" means that we want to clear the field out
  748. //
  749. // else
  750. // break;
  751. }
  752. //ABC" xyz" will get one token 'ABC xyz'
  753. else
  754. {
  755. bQuoteBegin = TRUE;
  756. ++pBuffer;
  757. --BufferLen;
  758. bChar = FALSE;
  759. }
  760. }
  761. // else if(!bQuoteBegin && (pBuffer[0] == L' ' ||
  762. // pBuffer[0] == L'\t' ||
  763. // pBuffer[0] == L'\n'))
  764. else if(!bQuoteBegin && IsDelimiter(pBuffer[0],pszDelimiters))
  765. {
  766. ++pBuffer;
  767. --BufferLen;
  768. break;
  769. }
  770. else
  771. {
  772. ch = pBuffer[0];
  773. ++pBuffer;
  774. --BufferLen;
  775. }
  776. if(bChar && ppToken)
  777. {
  778. if(pos == MaxSize -1)
  779. if(ERROR_SUCCESS != ResizeByTwo(&pItem,&MaxSize))
  780. {
  781. LocalFree(pItem);
  782. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  783. return -1;
  784. }
  785. pItem[pos] = ch;
  786. }
  787. if(bChar)
  788. ++pos;
  789. }
  790. if(pos ||
  791. (!pos && bQuoteBegin))
  792. {
  793. if(ppToken)
  794. {
  795. pItem[pos] = '\0';
  796. *ppToken = pItem;
  797. }
  798. ++pos;
  799. }
  800. }while(0);
  801. return pos;
  802. }
  803. /*
  804. Function to convert string an array of CTokens.
  805. INPUT: pBuf Input Buffer
  806. BufLen Length of bBuf
  807. OUTPUT:ppToken Gets Pointer to array of CToken
  808. argc Lenght of array of CToken
  809. Return Value: WIN32 Error
  810. */
  811. DWORD Tokenize(IN LPWSTR pBuf,
  812. IN LONG BufLen,
  813. LPWSTR szDelimiters,
  814. OUT CToken **ppToken,
  815. OUT int *argc)
  816. {
  817. *argc = 0;
  818. CToken *pToken = NULL;
  819. DWORD dwErr = ERROR_SUCCESS;
  820. BOOL bQuote;
  821. LPWSTR pszItem = NULL;
  822. //Get First Token
  823. LONG ret = GetToken(pBuf,
  824. BufLen,
  825. szDelimiters,
  826. &bQuote,
  827. NULL);
  828. if(ret == -1)
  829. {
  830. dwErr = GetLastError();
  831. goto exit_gracefully;
  832. }
  833. while(ret)
  834. {
  835. ++(*argc);
  836. ret = GetToken(NULL,
  837. NULL,
  838. szDelimiters,
  839. &bQuote,
  840. NULL);
  841. if(ret == -1)
  842. {
  843. dwErr = GetLastError();
  844. goto exit_gracefully;
  845. }
  846. }
  847. if(*argc)
  848. {
  849. int i =0;
  850. pToken = new CToken[*argc];
  851. if(!pToken)
  852. {
  853. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  854. goto exit_gracefully;
  855. }
  856. ret = GetToken(pBuf,
  857. BufLen,
  858. szDelimiters,
  859. &bQuote,
  860. &pszItem);
  861. if(ret == -1)
  862. {
  863. dwErr = GetLastError();
  864. goto exit_gracefully;
  865. }
  866. while(ret)
  867. {
  868. pToken[i++].Init(pszItem,bQuote);
  869. if(pszItem)
  870. LocalFree(pszItem);
  871. pszItem = NULL;
  872. ret = GetToken(NULL,
  873. NULL,
  874. szDelimiters,
  875. &bQuote,
  876. &pszItem);
  877. if(ret == -1)
  878. {
  879. dwErr = GetLastError();
  880. goto exit_gracefully;
  881. }
  882. }
  883. }
  884. exit_gracefully:
  885. if(dwErr != ERROR_SUCCESS)
  886. {
  887. if(pToken)
  888. {
  889. delete [] pToken ;
  890. }
  891. return dwErr;
  892. }
  893. *ppToken = pToken;
  894. return dwErr;
  895. }
  896. /*
  897. Function to display the parsing errors. If function cannot
  898. handle some error, it will return False and calling function
  899. must handle that error.
  900. */
  901. BOOL DisplayParseError(IN PPARSE_ERROR pError,
  902. IN ARG_RECORD *Commands,
  903. IN CToken *pToken)
  904. {
  905. if(!pError)
  906. return FALSE;
  907. VOID *parg1 = NULL;
  908. VOID *parg2 = NULL;
  909. UINT idStr = 0;
  910. BOOL bReturn = TRUE;
  911. switch(pError->ErrorSource)
  912. {
  913. case ERROR_FROM_PARSER:
  914. {
  915. switch(pError->Error)
  916. {
  917. case PARSE_ERROR_SWITCH_VALUE:
  918. {
  919. idStr = IDS_PARSE_ERROR_SWITCH_VALUE;
  920. parg1 = Commands[pError->ArgRecIndex].strArg1;
  921. }
  922. break;
  923. case PARSE_ERROR_SWICH_NO_VALUE:
  924. {
  925. idStr = IDS_PARSE_ERROR_SWICH_NO_VALUE;
  926. parg1 = Commands[pError->ArgRecIndex].strArg1;
  927. }
  928. break;
  929. case PARSE_ERROR_UNKNOWN_INPUT_PARAMETER:
  930. {
  931. idStr = IDS_PARSE_ERROR_UNKNOWN_INPUT_PARAMETER;
  932. parg1 = (pToken + pError->ArgvIndex)->GetToken();
  933. }
  934. break;
  935. case PARSE_ERROR_SWITCH_NOTDEFINED:
  936. {
  937. idStr = IDS_PARSE_ERROR_SWITCH_NOTDEFINED;
  938. parg1 = Commands[pError->ArgRecIndex].strArg1;
  939. }
  940. break;
  941. case PARSE_ERROR_MULTIPLE_DEF:
  942. {
  943. idStr = IDS_PARSE_ERROR_MULTIPLE_DEF;
  944. parg1 = Commands[pError->ArgRecIndex].strArg1;
  945. }
  946. break;
  947. default:
  948. bReturn = FALSE;
  949. }
  950. if(idStr)
  951. {
  952. //Format the string
  953. LPWSTR pBuffer = NULL;
  954. FormatStringID(&pBuffer,
  955. NULL,
  956. idStr,
  957. parg1,
  958. parg2);
  959. //Display it
  960. if(pBuffer)
  961. DisplayError(pBuffer);
  962. LocalFreeString(&pBuffer);
  963. }
  964. }
  965. break;
  966. case ERROR_FROM_VLDFN:
  967. {
  968. if(pError->Error != VLDFN_ERROR_NO_ERROR)
  969. bReturn = FALSE;
  970. }
  971. break;
  972. case ERROR_WIN32_ERROR:
  973. {
  974. LPWSTR pBuffer = NULL;
  975. if(GetSystemErrorText(&pBuffer, pError->Error))
  976. {
  977. if(pBuffer)
  978. {
  979. DisplayError(pBuffer);
  980. LocalFreeString(&pBuffer);
  981. }
  982. else
  983. bReturn = FALSE;
  984. }
  985. else
  986. bReturn = FALSE;
  987. }
  988. break;
  989. default:
  990. bReturn = FALSE;
  991. break;
  992. }
  993. return bReturn;
  994. }
  995. VOID DisplayError(LPWSTR pszError)
  996. {
  997. if(pszError)
  998. WriteStandardError(L"%s\n",pszError);
  999. }
  1000. VOID DisplayOutput(LPWSTR pszOutput)
  1001. {
  1002. if(pszOutput)
  1003. WriteStandardOut(L"%s\r\n",pszOutput);
  1004. }
  1005. VOID DisplayOutputNoNewline(LPWSTR pszOutput)
  1006. {
  1007. if(pszOutput)
  1008. WriteStandardOut(L"%s",pszOutput);
  1009. }
  1010. /*******************************************************************
  1011. NAME: DisplayMessage
  1012. SYNOPSIS: Loads Message from Message Table and Formats its
  1013. IN Indent - Number of tabs to indent
  1014. MessageId - Id of the message to load
  1015. ... - Optional list of parameters
  1016. RETURNS: NONE
  1017. ********************************************************************/
  1018. VOID DisplayMessage(DWORD MessageId,...)
  1019. {
  1020. PWSTR MessageDisplayString;
  1021. va_list ArgList;
  1022. ULONG Length;
  1023. va_start( ArgList, MessageId );
  1024. Length = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1025. NULL,
  1026. MessageId,
  1027. 0,
  1028. (PWSTR)&MessageDisplayString,
  1029. 0,
  1030. &ArgList );
  1031. if ( Length != 0 ) {
  1032. WriteStandardError(L"%s",MessageDisplayString);
  1033. LocalFree( MessageDisplayString );
  1034. }
  1035. va_end( ArgList );
  1036. }
  1037. /*
  1038. Class CToken
  1039. */
  1040. CToken::CToken(LPWSTR psz, BOOL bQuote)
  1041. {
  1042. StringCopy(&m_pszToken,psz);
  1043. m_bInitQuote = bQuote;
  1044. }
  1045. CToken::CToken():m_bInitQuote(FALSE),m_pszToken(NULL){}
  1046. CToken::~CToken()
  1047. {
  1048. LocalFree(m_pszToken);
  1049. }
  1050. VOID CToken::Init(LPWSTR psz, BOOL bQuote)
  1051. {
  1052. StringCopy(&m_pszToken,psz);
  1053. m_bInitQuote = bQuote;
  1054. }
  1055. LPWSTR CToken::GetToken(){return m_pszToken;}
  1056. BOOL CToken::IsSwitch()
  1057. {
  1058. //Assert(m_pszToken);
  1059. if(!m_pszToken)
  1060. return FALSE;
  1061. if(m_bInitQuote)
  1062. return FALSE;
  1063. if(m_pszToken[0] == L'/' ||
  1064. m_pszToken[0] == L'-')
  1065. return TRUE;
  1066. return FALSE;
  1067. }
  1068. BOOL CToken::IsSlash()
  1069. {
  1070. if (!m_pszToken)
  1071. return FALSE;
  1072. if (m_bInitQuote)
  1073. return FALSE;
  1074. if (m_pszToken[0] == L'/')
  1075. return TRUE;
  1076. return FALSE;
  1077. }
  1078. // Copied from JSchwart
  1079. BOOL
  1080. FileIsConsole(
  1081. HANDLE fp
  1082. )
  1083. {
  1084. unsigned htype;
  1085. htype = GetFileType(fp);
  1086. htype &= ~FILE_TYPE_REMOTE;
  1087. return htype == FILE_TYPE_CHAR;
  1088. }
  1089. void
  1090. MyWriteConsole(
  1091. HANDLE fp,
  1092. LPWSTR lpBuffer,
  1093. DWORD cchBuffer
  1094. )
  1095. {
  1096. //
  1097. // Jump through hoops for output because:
  1098. //
  1099. // 1. printf() family chokes on international output (stops
  1100. // printing when it hits an unrecognized character)
  1101. //
  1102. // 2. WriteConsole() works great on international output but
  1103. // fails if the handle has been redirected (i.e., when the
  1104. // output is piped to a file)
  1105. //
  1106. // 3. WriteFile() works great when output is piped to a file
  1107. // but only knows about bytes, so Unicode characters are
  1108. // printed as two Ansi characters.
  1109. //
  1110. if (FileIsConsole(fp))
  1111. {
  1112. WriteConsole(fp, lpBuffer, cchBuffer, &cchBuffer, NULL);
  1113. }
  1114. else
  1115. {
  1116. LPSTR lpAnsiBuffer = (LPSTR) LocalAlloc(LMEM_FIXED, cchBuffer * sizeof(WCHAR));
  1117. if (lpAnsiBuffer != NULL)
  1118. {
  1119. cchBuffer = WideCharToMultiByte(CP_OEMCP,
  1120. 0,
  1121. lpBuffer,
  1122. cchBuffer,
  1123. lpAnsiBuffer,
  1124. cchBuffer * sizeof(WCHAR),
  1125. NULL,
  1126. NULL);
  1127. if (cchBuffer != 0)
  1128. {
  1129. WriteFile(fp, lpAnsiBuffer, cchBuffer, &cchBuffer, NULL);
  1130. }
  1131. LocalFree(lpAnsiBuffer);
  1132. }
  1133. }
  1134. }
  1135. void
  1136. WriteStandardOut(PCWSTR pszFormat, ...)
  1137. {
  1138. static HANDLE standardOut = GetStdHandle(STD_OUTPUT_HANDLE);
  1139. //
  1140. // Verify parameters
  1141. //
  1142. if (!pszFormat)
  1143. {
  1144. return;
  1145. }
  1146. va_list args;
  1147. va_start(args, pszFormat);
  1148. int nBuf;
  1149. WCHAR szBuffer[4 * MAX_PATH];
  1150. ZeroMemory(szBuffer, sizeof(szBuffer));
  1151. nBuf = _vsnwprintf(szBuffer, sizeof(szBuffer)/sizeof(WCHAR), pszFormat, args);
  1152. //
  1153. // Output the results
  1154. //
  1155. if (nBuf > 0)
  1156. {
  1157. MyWriteConsole(standardOut,
  1158. szBuffer,
  1159. nBuf);
  1160. }
  1161. va_end(args);
  1162. }
  1163. void
  1164. WriteStandardError(PCWSTR pszFormat, ...)
  1165. {
  1166. static HANDLE standardErr = GetStdHandle(STD_ERROR_HANDLE);
  1167. //
  1168. // Verify parameters
  1169. //
  1170. if (!pszFormat)
  1171. {
  1172. return;
  1173. }
  1174. va_list args;
  1175. va_start(args, pszFormat);
  1176. int nBuf;
  1177. WCHAR szBuffer[100 * MAX_PATH];
  1178. ZeroMemory(szBuffer, sizeof(szBuffer));
  1179. nBuf = _vsnwprintf(szBuffer, sizeof(szBuffer)/sizeof(WCHAR), pszFormat, args);
  1180. //
  1181. // Output the results
  1182. //
  1183. if (nBuf > 0)
  1184. {
  1185. MyWriteConsole(standardErr,
  1186. szBuffer,
  1187. nBuf);
  1188. }
  1189. va_end(args);
  1190. }
  1191. /*******************************************************************
  1192. NAME: AddDNEscaping_Commands
  1193. SYNOPSIS: Adds full ADSI escaping to DN arguments
  1194. ********************************************************************/
  1195. DWORD AddDNEscaping_Commands( IN OUT ARG_RECORD *Commands )
  1196. {
  1197. for( int i=0; ARG_TYPE_LAST != Commands[i].fType; i++ )
  1198. {
  1199. if (!(ARG_FLAG_DN & Commands[i].fFlag))
  1200. continue;
  1201. if (ARG_TYPE_STR == Commands[i].fType)
  1202. {
  1203. if (NULL == Commands[i].strValue)
  1204. continue;
  1205. LPWSTR pszEscaped = NULL;
  1206. DWORD dwErr = AddDNEscaping_DN(&pszEscaped, Commands[i].strValue);
  1207. if (ERROR_SUCCESS != dwErr)
  1208. return dwErr;
  1209. LocalFree(Commands[i].strValue);
  1210. Commands[i].strValue = pszEscaped;
  1211. continue;
  1212. }
  1213. if (ARG_TYPE_MSZ != Commands[i].fType)
  1214. {
  1215. continue; // shouldn't happen
  1216. }
  1217. if (NULL == Commands[i].strValue)
  1218. continue;
  1219. // count through double-NULL-terminated string list
  1220. PWSTR pszDoubleNullObjectDN = Commands[i].strValue;
  1221. LPTSTR buffer = NULL;
  1222. LONG maxSize = 0;
  1223. LONG currentSize = 0;
  1224. if (!StartBuffer(&buffer,&maxSize,&currentSize))
  1225. return ERROR_NOT_ENOUGH_MEMORY;
  1226. for ( ;
  1227. NULL != pszDoubleNullObjectDN &&
  1228. L'\0' != *pszDoubleNullObjectDN;
  1229. pszDoubleNullObjectDN += (wcslen(pszDoubleNullObjectDN)+1) )
  1230. {
  1231. LPWSTR pszEscaped = NULL;
  1232. DWORD dwErr = AddDNEscaping_DN(&pszEscaped, pszDoubleNullObjectDN);
  1233. if (ERROR_SUCCESS != dwErr)
  1234. return dwErr;
  1235. dwErr = AddToBuffer(pszEscaped,
  1236. &buffer,&maxSize,&currentSize,TRUE);
  1237. if (ERROR_SUCCESS != dwErr)
  1238. return dwErr;
  1239. LocalFree(pszEscaped);
  1240. }
  1241. LocalFree(Commands[i].strValue);
  1242. Commands[i].strValue = buffer;
  1243. }
  1244. return ERROR_SUCCESS;
  1245. } // AddDNEscaping_Commands
  1246. DWORD AddDNEscaping_DN( OUT LPWSTR* ppszOut, IN LPWSTR pszIn )
  1247. {
  1248. //
  1249. // JonN 5/12/01 special-case "domainroot" and "forestroot" which can be
  1250. // parameters to "-startnode" but fail IADsPathname::GetEscapedElement().
  1251. //
  1252. if (!pszIn ||
  1253. !*pszIn ||
  1254. !_tcsicmp(L"domainroot",pszIn) ||
  1255. !_tcsicmp(L"forestroot",pszIn))
  1256. {
  1257. return (StringCopy(ppszOut,pszIn))
  1258. ? ERROR_SUCCESS : ERROR_NOT_ENOUGH_MEMORY;
  1259. }
  1260. LONG maxSize = 0;
  1261. LONG currentSize = 0;
  1262. if (!StartBuffer(ppszOut,&maxSize,&currentSize))
  1263. return ERROR_NOT_ENOUGH_MEMORY;
  1264. // copy pszIn into temporary buffer
  1265. LPWSTR pszCopy = NULL;
  1266. if (!StringCopy(&pszCopy,pszIn) || NULL == pszCopy)
  1267. return ERROR_NOT_ENOUGH_MEMORY;
  1268. WCHAR* pchElement = pszCopy;
  1269. WCHAR* pch = pszCopy;
  1270. do {
  1271. if (L'\\' == *pch && (L',' == *(pch+1) || L'\\' == *(pch+1)))
  1272. {
  1273. //
  1274. // manual escaping on command line
  1275. //
  1276. // also copies trailing L'\0'
  1277. memmove(pch, pch+1, wcslen(pch)*sizeof(WCHAR));
  1278. }
  1279. else if (L',' == *pch || L'\0' == *pch)
  1280. {
  1281. //
  1282. // completes path element
  1283. //
  1284. WCHAR chTemp = *pch;
  1285. *pch = L'\0';
  1286. LPWSTR pszEscaped = NULL;
  1287. HRESULT hr = GetEscapedElement( &pszEscaped, pchElement );
  1288. if (FAILED(hr) || NULL == pszEscaped)
  1289. return ERROR_NOT_ENOUGH_MEMORY; // CODEWORK can FILL_ERROR handle an HRESULT?
  1290. if (NULL != *ppszOut && L'\0' != **ppszOut)
  1291. {
  1292. // add seperator to DN
  1293. DWORD dwErr = AddToBuffer(L",",
  1294. ppszOut,&maxSize,&currentSize,
  1295. FALSE); // not MSZ output
  1296. if (ERROR_SUCCESS != dwErr)
  1297. return dwErr;
  1298. }
  1299. // add path element to DN
  1300. DWORD dwErr = AddToBuffer(pszEscaped,
  1301. ppszOut,&maxSize,&currentSize,
  1302. FALSE); // not MSZ output
  1303. if (ERROR_SUCCESS != dwErr)
  1304. return dwErr;
  1305. ::LocalFree(pszEscaped);
  1306. if (L'\0' == chTemp)
  1307. break;
  1308. *pch = chTemp;
  1309. pchElement = pch+1;
  1310. }
  1311. pch++;
  1312. } while (true);
  1313. LocalFree(pszCopy);
  1314. return ERROR_SUCCESS;
  1315. } // AddDNEscaping_DN
  1316. BOOL StartBuffer( OUT LPTSTR* pbuffer,
  1317. OUT LONG* pmaxSize,
  1318. OUT LONG* pcurrentSize )
  1319. {
  1320. *pbuffer = (LPTSTR)LocalAlloc(LPTR,MAXSTR*sizeof(TCHAR)); // init to zero
  1321. *pmaxSize = MAXSTR;
  1322. *pcurrentSize = 0;
  1323. return (NULL != pbuffer);
  1324. }
  1325. DWORD AddToBuffer( IN LPCTSTR psz,
  1326. IN OUT LPTSTR* pbuffer,
  1327. IN OUT LONG* pmaxSize,
  1328. IN OUT LONG* pcurrentSize,
  1329. BOOL fMSZBuffer)
  1330. {
  1331. LONG len = (LONG)wcslen(psz);
  1332. //-2 as last string is delimited by two null
  1333. while(((*pcurrentSize) + len) > ((*pmaxSize) - 2))
  1334. {
  1335. DWORD dwErr = ResizeByTwo(pbuffer,pmaxSize);
  1336. if (dwErr != ERROR_SUCCESS)
  1337. return dwErr;
  1338. }
  1339. _tcscpy(((*pbuffer) + (*pcurrentSize)), psz);
  1340. (*pcurrentSize) += len;
  1341. //tail end of pbuffer is all NULLs
  1342. if (fMSZBuffer)
  1343. (*pcurrentSize)++;
  1344. return NO_ERROR;
  1345. }