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.

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