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.

1538 lines
31 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1998 - 1999
  3. Module Name:
  4. TclRdCmd
  5. Abstract:
  6. This module provides the implementation for the Tcl command line reader.
  7. Author:
  8. Doug Barlow (dbarlow) 3/14/1998
  9. Environment:
  10. Win32, C++ w/ exceptions, Tcl
  11. Notes:
  12. ?Notes?
  13. --*/
  14. // #ifndef WIN32_LEAN_AND_MEAN
  15. // #define WIN32_LEAN_AND_MEAN
  16. // #endif
  17. // #include <windows.h> // All the Windows definitions.
  18. #include <afx.h>
  19. #include <tchar.h>
  20. extern "C"
  21. {
  22. #include "tclHelp.h"
  23. }
  24. #include "tclRdCmd.h" // Our definitions
  25. //
  26. //==============================================================================
  27. //
  28. // CTclCommand
  29. //
  30. /*++
  31. CONSTRUCTOR:
  32. These are the constructors for a CTclCommand object.
  33. Arguments:
  34. Per the standard Tcl command calling sequence, the parameters are:
  35. interp - The Tcl interpreter against which to report errors.
  36. argc - The number of command line arguments
  37. argv - The vector of command line arguments
  38. Return Value:
  39. None
  40. Author:
  41. Doug Barlow (dbarlow) 3/14/1998
  42. --*/
  43. CTclCommand::CTclCommand(
  44. void)
  45. {
  46. Constructor();
  47. }
  48. CTclCommand::CTclCommand(
  49. Tcl_Interp *interp,
  50. int argc,
  51. char *argv[])
  52. {
  53. Constructor();
  54. Initialize(interp, argc, argv);
  55. }
  56. /*++
  57. Constructor:
  58. This is a constructor helper routine. All constructors call this routine
  59. first to be sure internal properties are initialized.
  60. Arguments:
  61. None
  62. Return Value:
  63. None
  64. Author:
  65. Doug Barlow (dbarlow) 3/14/1998
  66. --*/
  67. void
  68. CTclCommand::Constructor(
  69. void)
  70. {
  71. m_fErrorDeclared = FALSE;
  72. m_pInterp = NULL;
  73. m_dwArgCount = 0;
  74. m_dwArgIndex = 0;
  75. m_rgszArgs = NULL;
  76. }
  77. /*++
  78. DESTRUCTOR:
  79. This is the destructor for the object. It cleans up any outstanding
  80. resources.
  81. Author:
  82. Doug Barlow (dbarlow) 3/14/1998
  83. --*/
  84. CTclCommand::~CTclCommand()
  85. {
  86. }
  87. /*++
  88. Initialize:
  89. This method initializes the object with the standard Tcl command parameters.
  90. Arguments:
  91. Per the standard Tcl command calling sequence, the parameters are:
  92. interp - The Tcl interpreter against which to report errors.
  93. argc - The number of command line arguments
  94. argv - The vector of command line arguments
  95. Return Value:
  96. None
  97. Throws:
  98. Errors are thrown as DWORD status codes.
  99. Author:
  100. Doug Barlow (dbarlow) 3/14/1998
  101. --*/
  102. void
  103. CTclCommand::Initialize(
  104. Tcl_Interp *interp,
  105. int argc,
  106. char *argv[])
  107. {
  108. if (NULL != m_pInterp)
  109. throw (DWORD)ERROR_ALREADY_INITIALIZED;
  110. m_pInterp = interp;
  111. m_dwArgCount = (DWORD)argc;
  112. m_rgszArgs = argv;
  113. m_dwArgIndex = 1;
  114. }
  115. /*++
  116. SetError:
  117. These routines establish an error message for the command, if one doesn't
  118. exist already.
  119. Arguments:
  120. dwError supplies an error code who's message should be reported.
  121. szMessage supplies a text string to be reported.
  122. szMsg<n> supplies a list of text strings to be reported. The last
  123. parameter must be NULL to terminate the list.
  124. Return Value:
  125. None
  126. Author:
  127. Doug Barlow (dbarlow) 3/14/1998
  128. --*/
  129. void
  130. CTclCommand::SetError(
  131. DWORD dwError)
  132. {
  133. SetError(ErrorString(dwError), (LPCTSTR)NULL);
  134. }
  135. void
  136. CTclCommand::SetError(
  137. LPCTSTR szMessage,
  138. DWORD dwError)
  139. {
  140. SetError(szMessage, ErrorString(dwError), NULL);
  141. }
  142. void
  143. CTclCommand::SetError(
  144. LPCTSTR szMsg1,
  145. ...)
  146. {
  147. va_list vaArgs;
  148. LPCTSTR szMsg;
  149. va_start(vaArgs, szMsg1);
  150. szMsg = szMsg1;
  151. if (!m_fErrorDeclared)
  152. {
  153. Tcl_ResetResult(m_pInterp);
  154. while (NULL != szMsg)
  155. {
  156. Tcl_AppendResult(m_pInterp, szMsg, NULL);
  157. szMsg = va_arg(vaArgs, LPCTSTR);
  158. }
  159. m_fErrorDeclared = TRUE;
  160. }
  161. va_end(vaArgs);
  162. }
  163. /*++
  164. TclError:
  165. This routine is called to note that Tcl has already filled in the error
  166. reason, and we should just pass it along.
  167. Arguments:
  168. None
  169. Return Value:
  170. TCL_ERROR (suitable for throwing)
  171. Author:
  172. Doug Barlow (dbarlow) 3/14/1998
  173. --*/
  174. DWORD
  175. CTclCommand::TclError(
  176. void)
  177. {
  178. m_fErrorDeclared = TRUE;
  179. return TCL_ERROR;
  180. }
  181. /*++
  182. Keyword:
  183. This method converts a list of keywords into an integer identifying the
  184. keyword. The list of keywords must be NULL-terminated (the last parameter
  185. must be NULL).
  186. Arguments:
  187. szKeyword - supplies one or more keywords to be translated into an integer.
  188. The last keyword must be NULL to terminate the list.
  189. Return Value:
  190. 0 - None of the keywords matched the next input argument.
  191. -1 - More than one of the keywords matched the next input argument.
  192. n > 0 - Keyword 'n' (counting from one) matched the next input argument.
  193. Author:
  194. Doug Barlow (dbarlow) 3/14/1998
  195. --*/
  196. LONG
  197. CTclCommand::Keyword(
  198. IN LPCTSTR szKeyword, ...)
  199. {
  200. va_list vaArgs;
  201. LPCTSTR szKey;
  202. CString szArg;
  203. DWORD dwLength;
  204. DWORD dwReturn = 0;
  205. DWORD dwCount = 0;
  206. PeekArgument(szArg);
  207. dwLength = szArg.GetLength();
  208. if (0 == dwLength)
  209. return 0; // Empty strings don't match anything.
  210. va_start(vaArgs, szKeyword);
  211. szKey = szKeyword;
  212. while (NULL != szKey)
  213. {
  214. dwCount += 1;
  215. if (0 == _tcsncicmp(szArg, szKey, dwLength))
  216. {
  217. if (0 != dwReturn)
  218. {
  219. dwReturn = -1;
  220. break;
  221. }
  222. dwReturn = dwCount;
  223. }
  224. szKey = va_arg(vaArgs, LPCTSTR);
  225. }
  226. va_end(vaArgs);
  227. if (0 < dwReturn)
  228. NextArgument();
  229. return dwReturn;
  230. }
  231. /*++
  232. GetArgument:
  233. This method obtains the specified argument in the command.
  234. Arguments:
  235. szToken receives the specified argument of the command.
  236. Return Value:
  237. None
  238. Throws:
  239. TCL_ERROR - if there aren't enough arguments on the command line,
  240. preprepping the error string.
  241. Author:
  242. Doug Barlow (dbarlow) 3/14/1998
  243. --*/
  244. void
  245. CTclCommand::GetArgument(
  246. DWORD dwArgId,
  247. CString &szToken)
  248. {
  249. if (dwArgId >= m_dwArgCount)
  250. {
  251. CString szCommand;
  252. GetArgument(0, szCommand);
  253. SetError(
  254. TEXT("Insufficient parameters to the '"),
  255. szCommand,
  256. TEXT("' command."),
  257. NULL);
  258. throw (DWORD)TCL_ERROR;
  259. }
  260. szToken = m_rgszArgs[dwArgId];
  261. }
  262. /*++
  263. PeekArgument:
  264. This method obtains the next argument in the command without moving on to
  265. the next argument.
  266. Arguments:
  267. szToken receives the next argument of the command.
  268. Return Value:
  269. None
  270. Throws:
  271. TCL_ERROR - if there are no more arguments on the command line, preprepping
  272. the error string.
  273. Author:
  274. Doug Barlow (dbarlow) 3/14/1998
  275. --*/
  276. void
  277. CTclCommand::PeekArgument(
  278. CString &szToken)
  279. {
  280. GetArgument(m_dwArgIndex, szToken);
  281. }
  282. /*++
  283. NextArgument:
  284. This method moves forward to the next argument.
  285. Arguments:
  286. szToken receives the next argument of the command.
  287. Return Value:
  288. None
  289. Throws:
  290. TCL_ERROR - if there are no more arguments on the command line, preprepping
  291. the error string.
  292. Author:
  293. Doug Barlow (dbarlow) 3/14/1998
  294. --*/
  295. void
  296. CTclCommand::NextArgument(
  297. void)
  298. {
  299. m_dwArgIndex += 1;
  300. }
  301. void
  302. CTclCommand::NextArgument(
  303. CString &szToken)
  304. {
  305. PeekArgument(szToken);
  306. NextArgument();
  307. }
  308. /*++
  309. IsMoreArguments:
  310. This method obtains whether or not there are additional parameters to be
  311. processed. It returns TRUE while parameters remain, and returns FALSE if
  312. none remain. A minimum number of parameters may be specified, in which case
  313. it returns whether or not there are at least that number of parameters
  314. remaining.
  315. Arguments:
  316. dwCount - If supplied, this provides a way to ask if 'dwCount' parameters
  317. remain.
  318. Return Value:
  319. TRUE - At least dwCount parameters remain to be processed
  320. FALSE - less that dwCount parameters remain to be processed.
  321. Throws:
  322. None
  323. Author:
  324. Doug Barlow (dbarlow) 3/14/1998
  325. --*/
  326. BOOL
  327. CTclCommand::IsMoreArguments(
  328. DWORD dwCount)
  329. const
  330. {
  331. return m_dwArgIndex + dwCount <= m_dwArgCount;
  332. }
  333. /*++
  334. NoMoreArguments:
  335. This method asserts that there are no more arguments in the command line. If there are,
  336. a BadSyntax error is thrown.
  337. Arguments:
  338. None
  339. Return Value:
  340. None
  341. Throws:
  342. TCL_ERROR as a DWORD if more arguments remain on the command line
  343. Author:
  344. Doug Barlow (dbarlow) 3/14/1998
  345. --*/
  346. void
  347. CTclCommand::NoMoreArguments(
  348. void)
  349. {
  350. if (m_dwArgIndex < m_dwArgCount)
  351. throw BadSyntax();
  352. }
  353. /*++
  354. BadSyntax:
  355. This method declares a syntax error. It does not throw an error, but
  356. returns a DWORD suitable for throwing.
  357. Arguments:
  358. szParam - Supplies the syntactic offender string, or NULL.
  359. Return Value:
  360. A DWORD error code suitable for throwing.
  361. Throws:
  362. None
  363. Author:
  364. Doug Barlow (dbarlow) 3/14/1998
  365. --*/
  366. DWORD
  367. CTclCommand::BadSyntax(
  368. LPCTSTR szOffender)
  369. {
  370. DWORD dwIndex;
  371. if (NULL == szOffender)
  372. szOffender = m_rgszArgs[m_dwArgIndex];
  373. Tcl_ResetResult(m_pInterp);
  374. Tcl_AppendResult(
  375. m_pInterp,
  376. "Invalid option '",
  377. szOffender,
  378. "' to the '",
  379. NULL);
  380. for (dwIndex = 0; dwIndex < m_dwArgIndex; dwIndex += 1)
  381. Tcl_AppendResult(m_pInterp, m_rgszArgs[dwIndex], " ", NULL);
  382. Tcl_AppendResult(m_pInterp, "...' command.", NULL);
  383. m_fErrorDeclared = TRUE;
  384. return TCL_ERROR;
  385. }
  386. /*++
  387. Value:
  388. This method extracts a LONG value from the argument list.
  389. Arguments:
  390. lDefault supplies the default value.
  391. Return Value:
  392. The value extracted.
  393. Throws:
  394. If no default value is suppled and the next parameter is not an integer,
  395. TCL_ERROR is thrown as a DWORD.
  396. Author:
  397. Doug Barlow (dbarlow) 3/14/1998
  398. --*/
  399. LONG
  400. CTclCommand::Value(
  401. LONG lDefault)
  402. {
  403. LONG lReturn;
  404. CString szValue;
  405. PeekArgument(szValue);
  406. if (TCL_OK == Tcl_ExprLong(m_pInterp, SZ(szValue), &lReturn))
  407. NextArgument();
  408. else
  409. {
  410. Tcl_ResetResult(m_pInterp);
  411. lReturn = lDefault;
  412. }
  413. return lReturn;
  414. }
  415. LONG
  416. CTclCommand::Value(
  417. void)
  418. {
  419. LONG lReturn;
  420. CString szValue;
  421. PeekArgument(szValue);
  422. if (TCL_OK != Tcl_ExprLong(m_pInterp, SZ(szValue), &lReturn))
  423. throw (DWORD)TCL_ERROR;
  424. NextArgument();
  425. return lReturn;
  426. }
  427. /*++
  428. MapValue:
  429. This method converts text into a value, given a ValueMap structure. The
  430. class member automatically extracts the keyword.
  431. Arguments:
  432. rgvmMap supplies the value map array. The last element's string value
  433. must be NULL.
  434. szString supplies the value to be parsed.
  435. fValueOk supplies a flag indicating whether or not an integral value may be
  436. supplied instead of a symbolic token.
  437. Return Value:
  438. The value resulting from the map.
  439. Throws:
  440. If no default value is suppled and the next parameter is not an integer,
  441. TCL_ERROR is thrown as a DWORD.
  442. Author:
  443. Doug Barlow (dbarlow) 3/14/1998
  444. --*/
  445. LONG
  446. CTclCommand::MapValue(
  447. const ValueMap *rgvmMap,
  448. BOOL fValueOk)
  449. {
  450. CString szValue;
  451. LONG lReturn;
  452. PeekArgument(szValue);
  453. lReturn = MapValue(rgvmMap, szValue, fValueOk);
  454. NextArgument();
  455. return lReturn;
  456. }
  457. LONG
  458. CTclCommand::MapValue(
  459. const ValueMap *rgvmMap,
  460. CString &szValue,
  461. BOOL fValueOk)
  462. {
  463. LONG lReturn;
  464. LONG lMap = -1;
  465. DWORD dwIndex, dwLength;
  466. if (fValueOk && (TCL_OK != Tcl_ExprLong(m_pInterp, SZ(szValue), &lReturn)))
  467. {
  468. Tcl_ResetResult(m_pInterp);
  469. dwLength = szValue.GetLength();
  470. if (0 == dwLength)
  471. throw BadSyntax();
  472. for (dwIndex = 0; NULL != rgvmMap[dwIndex].szValue; dwIndex += 1)
  473. {
  474. if (0 == _tcsncicmp(
  475. szValue,
  476. rgvmMap[dwIndex].szValue,
  477. dwLength))
  478. {
  479. if (-1 != lMap)
  480. throw BadSyntax();
  481. lMap = (LONG)dwIndex;
  482. if (0 == rgvmMap[dwIndex].szValue[dwLength])
  483. break;
  484. }
  485. }
  486. if (-1 == lMap)
  487. throw BadSyntax(szValue);
  488. lReturn = rgvmMap[lMap].lValue;
  489. }
  490. return lReturn;
  491. }
  492. /*++
  493. MapFlags:
  494. This method converts a text list into a single value, given a ValueMap
  495. structure. The list is taken as an array of flags. The corresponding
  496. values are OR'ed together to obtain the return value.
  497. The class member automatically extracts the keyword.
  498. Arguments:
  499. rgvmMap supplies the value map array. The last element's string value
  500. must be NULL.
  501. fValueOk supplies a flag indicating whether or not an integral value may be
  502. supplied instead of a symbolic token.
  503. Return Value:
  504. The value resulting from the map.
  505. Throws:
  506. If no default value is suppled and the next parameter is not an integer,
  507. TCL_ERROR is thrown as a DWORD.
  508. Author:
  509. Doug Barlow (dbarlow) 3/14/1998
  510. --*/
  511. DWORD
  512. CTclCommand::MapFlags(
  513. const ValueMap *rgvmMap,
  514. BOOL fValueOk)
  515. {
  516. CArgArray rgFlags(*this);
  517. CString szFlags;
  518. CString szFlag;
  519. DWORD dwFlags = 0;
  520. DWORD dwIndex = 0;
  521. NextArgument(szFlags);
  522. rgFlags.LoadList(szFlags);
  523. for (dwIndex = rgFlags.Count(); dwIndex > 0;)
  524. {
  525. rgFlags.Fetch(--dwIndex, szFlag);
  526. dwFlags |= MapValue(rgvmMap, szFlag);
  527. }
  528. return dwFlags;
  529. }
  530. /*++
  531. OutputStyle:
  532. This method parses the common binary data output flags and prepares to
  533. properly render it on output.
  534. Arguments:
  535. outData supplies the CRenderableData object with information on how to
  536. render its internal binary data.
  537. Return Value:
  538. None
  539. Throws:
  540. Errors are thrown as exceptions
  541. Author:
  542. Doug Barlow (dbarlow) 5/5/1998
  543. --*/
  544. void
  545. CTclCommand::OutputStyle(
  546. CRenderableData &outData)
  547. {
  548. outData.SetDisplayType(CRenderableData::Undefined);
  549. if (IsMoreArguments())
  550. {
  551. switch (Keyword(TEXT("/OUTPUT"), TEXT("-OUTPUT"),
  552. TEXT("/HEXIDECIMAL"), TEXT("-HEXIDECIMAL"),
  553. TEXT("/TEXT"), TEXT("-TEXT"),
  554. TEXT("/ANSI"), TEXT("-ANSI"),
  555. TEXT("/UNICODE"), TEXT("-UNICODE"),
  556. TEXT("/FILE"), TEXT("-FILE"),
  557. NULL))
  558. {
  559. case 1: // /OUTPUT
  560. case 2: // -OUTPUT
  561. switch (Keyword(TEXT("HEXIDECIMAL"), TEXT("TEXT"),
  562. TEXT("ANSI"), TEXT("UNICODE"),
  563. TEXT("FILE"), NULL))
  564. {
  565. case 1: // HEX
  566. outData.SetDisplayType(CRenderableData::Hexidecimal);
  567. break;
  568. case 2: // TEXT
  569. outData.SetDisplayType(CRenderableData::Text);
  570. break;
  571. case 3: // ANSI
  572. outData.SetDisplayType(CRenderableData::Ansi);
  573. break;
  574. case 4: // UNICODE
  575. outData.SetDisplayType(CRenderableData::Unicode);
  576. break;
  577. case 5: // FILE
  578. outData.SetDisplayType(CRenderableData::File);
  579. NextArgument(outData.m_szFile);
  580. break;
  581. default:
  582. throw BadSyntax();
  583. }
  584. break;
  585. case 3: // /HEX
  586. case 4: // -HEX
  587. outData.SetDisplayType(CRenderableData::Hexidecimal);
  588. break;
  589. case 5: // /TEXT
  590. case 6: // -TEXT
  591. outData.SetDisplayType(CRenderableData::Text);
  592. break;
  593. case 7: // /ANSI
  594. case 8: // -ANSI
  595. outData.SetDisplayType(CRenderableData::Ansi);
  596. break;
  597. case 9: // /UNICODE
  598. case 10: // -UNICODE
  599. outData.SetDisplayType(CRenderableData::Unicode);
  600. break;
  601. case 11: // /FILE <name>
  602. case 12: // -FILE <name>
  603. outData.SetDisplayType(CRenderableData::File);
  604. NextArgument(outData.m_szFile);
  605. break;
  606. default:
  607. ; // No action
  608. }
  609. }
  610. }
  611. /*++
  612. InputStyle:
  613. This method parses the common binary data input flags and prepares to
  614. properly interpret input data.
  615. Arguments:
  616. inData supplies the CRenderableData object with information on how to
  617. interpret binary data.
  618. Return Value:
  619. None
  620. Throws:
  621. Errors are thrown as exceptions
  622. Author:
  623. Doug Barlow (dbarlow) 5/5/1998
  624. --*/
  625. void
  626. CTclCommand::InputStyle(
  627. CRenderableData &inData)
  628. {
  629. inData.SetDisplayType(CRenderableData::Undefined);
  630. switch (Keyword(TEXT("/INPUT"), TEXT("-INPUT"),
  631. TEXT("/HEXIDECIMAL"), TEXT("-HEXIDECIMAL"),
  632. TEXT("/TEXT"), TEXT("-TEXT"),
  633. TEXT("/ANSI"), TEXT("-ANSI"),
  634. TEXT("/UNICODE"), TEXT("-UNICODE"),
  635. TEXT("/FILE"), TEXT("-FILE"),
  636. NULL))
  637. {
  638. case 1: // /INPUT
  639. case 2: // -INPUT
  640. switch (Keyword(TEXT("HEXIDECIMAL"), TEXT("TEXT"),
  641. TEXT("ANSI"), TEXT("UNICODE"),
  642. TEXT("FILE"), NULL))
  643. {
  644. case 1: // HEX
  645. inData.SetDisplayType(CRenderableData::Hexidecimal);
  646. break;
  647. case 2: // TEXT
  648. inData.SetDisplayType(CRenderableData::Text);
  649. break;
  650. case 3: // ANSI
  651. inData.SetDisplayType(CRenderableData::Ansi);
  652. break;
  653. case 4: // UNICODE
  654. inData.SetDisplayType(CRenderableData::Unicode);
  655. break;
  656. case 5: // FILE
  657. inData.SetDisplayType(CRenderableData::File);
  658. break;
  659. default:
  660. throw BadSyntax();
  661. }
  662. break;
  663. case 3: // /HEX
  664. case 4: // -HEX
  665. inData.SetDisplayType(CRenderableData::Hexidecimal);
  666. break;
  667. case 5: // /TEXT
  668. case 6: // -TEXT
  669. inData.SetDisplayType(CRenderableData::Text);
  670. break;
  671. case 7: // /ANSI
  672. case 8: // -ANSI
  673. inData.SetDisplayType(CRenderableData::Ansi);
  674. break;
  675. case 9: // /UNICODE
  676. case 10: // -UNICODE
  677. inData.SetDisplayType(CRenderableData::Unicode);
  678. break;
  679. case 11: // /FILE <name>
  680. case 12: // -FILE <name>
  681. inData.SetDisplayType(CRenderableData::File);
  682. break;
  683. default:
  684. ; // No action
  685. }
  686. }
  687. /*++
  688. IOStyle:
  689. This method parses the common binary data input and output flags, and
  690. prepares to properly interpret and render data.
  691. Arguments:
  692. outData supplies the CRenderableData object with information on how to
  693. render its internal binary data.
  694. Return Value:
  695. None
  696. Throws:
  697. Errors are thrown as exceptions
  698. Author:
  699. Doug Barlow (dbarlow) 5/5/1998
  700. --*/
  701. void
  702. CTclCommand::IOStyle(
  703. CRenderableData &inData,
  704. CRenderableData &outData)
  705. {
  706. BOOL fInput, fOutput;
  707. outData.SetDisplayType(CRenderableData::Undefined);
  708. inData.SetDisplayType(CRenderableData::Undefined);
  709. fInput = fOutput = FALSE;
  710. do
  711. {
  712. switch (Keyword(TEXT("/OUTPUT"), TEXT("-OUTPUT"),
  713. TEXT("/INPUT"), TEXT("-INPUT"),
  714. NULL))
  715. {
  716. case 1: // /OUTPUT
  717. case 2: // -OUTPUT
  718. if (fOutput)
  719. throw BadSyntax();
  720. switch (Keyword(TEXT("HEXIDECIMAL"), TEXT("TEXT"),
  721. TEXT("ANSI"), TEXT("UNICODE"),
  722. TEXT("FILE"), NULL))
  723. {
  724. case 1: // HEX
  725. outData.SetDisplayType(CRenderableData::Hexidecimal);
  726. break;
  727. case 2: // TEXT
  728. outData.SetDisplayType(CRenderableData::Text);
  729. break;
  730. case 3: // ANSI
  731. outData.SetDisplayType(CRenderableData::Ansi);
  732. break;
  733. case 4: // UNICODE
  734. outData.SetDisplayType(CRenderableData::Unicode);
  735. break;
  736. case 5: // FILE
  737. outData.SetDisplayType(CRenderableData::File);
  738. NextArgument(outData.m_szFile);
  739. break;
  740. default:
  741. throw BadSyntax();
  742. }
  743. fOutput = TRUE;
  744. break;
  745. case 3: // /INPUT
  746. case 4: // -INPUT
  747. if (fInput)
  748. throw BadSyntax();
  749. switch (Keyword(TEXT("HEXIDECIMAL"), TEXT("TEXT"),
  750. TEXT("ANSI"), TEXT("UNICODE"),
  751. TEXT("FILE"), NULL))
  752. {
  753. case 1: // HEX
  754. inData.SetDisplayType(CRenderableData::Hexidecimal);
  755. break;
  756. case 2: // TEXT
  757. inData.SetDisplayType(CRenderableData::Text);
  758. break;
  759. case 3: // ANSI
  760. inData.SetDisplayType(CRenderableData::Ansi);
  761. break;
  762. case 4: // UNICODE
  763. inData.SetDisplayType(CRenderableData::Unicode);
  764. break;
  765. case 5: // FILE
  766. inData.SetDisplayType(CRenderableData::File);
  767. break;
  768. default:
  769. throw BadSyntax();
  770. }
  771. fInput = TRUE;
  772. break;
  773. default:
  774. fInput = fOutput = TRUE;
  775. }
  776. } while (!fInput || !fOutput);
  777. }
  778. /*++
  779. Render:
  780. This method renders data from a CRenderableData object into the Tcl output
  781. buffer.
  782. Arguments:
  783. outData supplies the CRenderableData object with information on how to
  784. render its internal binary data.
  785. Return Value:
  786. None
  787. Throws:
  788. Errors are thrown as exceptions
  789. Author:
  790. Doug Barlow (dbarlow) 5/6/1998
  791. --*/
  792. void
  793. CTclCommand::Render(
  794. CRenderableData &outData)
  795. {
  796. try
  797. {
  798. Tcl_AppendResult(*this, outData.RenderData(), NULL);
  799. }
  800. catch (DWORD dwError)
  801. {
  802. SetError(
  803. TEXT("Failed to render output data: "),
  804. dwError);
  805. throw (DWORD)TCL_ERROR;
  806. }
  807. }
  808. /*++
  809. ReadData:
  810. This method reads input data into a CRenderableData object from the Tcl
  811. input stream.
  812. Arguments:
  813. inData supplies the CRenderableData object with information on how to
  814. read the next parameter into its internal binary data.
  815. Return Value:
  816. None
  817. Throws:
  818. Errors are thrown as exceptions
  819. Author:
  820. Doug Barlow (dbarlow) 5/14/1998
  821. --*/
  822. void
  823. CTclCommand::ReadData(
  824. CRenderableData &inData)
  825. {
  826. CString szValue;
  827. try
  828. {
  829. PeekArgument(szValue);
  830. inData.LoadData(szValue);
  831. NextArgument();
  832. }
  833. catch (...)
  834. {
  835. throw BadSyntax();
  836. }
  837. }
  838. //
  839. //==============================================================================
  840. //
  841. // CRenderableData
  842. //
  843. /*++
  844. CONSTRUCTOR:
  845. This is the constructor for a CRenderableData object.
  846. Arguments:
  847. None
  848. Return Value:
  849. None
  850. Author:
  851. Doug Barlow (dbarlow) 5/5/1998
  852. --*/
  853. CRenderableData::CRenderableData(
  854. void)
  855. : m_bfData(),
  856. m_szString(),
  857. m_szFile()
  858. {
  859. m_dwType = Undefined;
  860. }
  861. /*++
  862. DESTRUCTOR:
  863. This is the destructor for a CRenderableData object.
  864. Arguments:
  865. None
  866. Return Value:
  867. None
  868. Author:
  869. Doug Barlow (dbarlow) 5/5/1998
  870. --*/
  871. CRenderableData::~CRenderableData()
  872. {
  873. }
  874. /*++
  875. LoadData:
  876. This method loads data into the style buffer. There are two forms, loading
  877. from a string, and direct binary loading.
  878. Arguments:
  879. szData supplies the data to be loaded, in it's string format.
  880. dwType supplies the type of string data being loaded.
  881. Return Value:
  882. None
  883. Throws:
  884. Errors are thrown as DWORD status codes.
  885. Author:
  886. Doug Barlow (dbarlow) 5/5/1998
  887. --*/
  888. void
  889. CRenderableData::LoadData(
  890. LPCTSTR szData,
  891. DisplayType dwType)
  892. {
  893. if (Undefined == dwType)
  894. dwType = m_dwType;
  895. switch (dwType)
  896. {
  897. case Text:
  898. m_bfData.Set((LPCBYTE)szData, (lstrlen(szData) + 1) * sizeof(TCHAR));
  899. break;
  900. case Ansi:
  901. case Unicode:
  902. throw (DWORD)SCARD_F_INTERNAL_ERROR;
  903. break;
  904. case Undefined: // Default output
  905. case Hexidecimal:
  906. {
  907. DWORD dwHex, dwLength, dwIndex;
  908. BYTE bHex;
  909. m_bfData.Reset();
  910. dwLength = lstrlen(szData);
  911. if (dwLength != _tcsspn(szData, TEXT("0123456789ABCDEFabcdef")))
  912. throw (DWORD)SCARD_E_INVALID_VALUE;
  913. m_bfData.Resize(dwLength / 2);
  914. for (dwIndex = 0; dwIndex < dwLength; dwIndex += 2)
  915. {
  916. _stscanf(&szData[dwIndex], TEXT(" %2lx"), &dwHex);
  917. bHex = (BYTE)dwHex;
  918. *m_bfData.Access(dwIndex / 2) = bHex;
  919. }
  920. break;
  921. }
  922. case File:
  923. {
  924. HANDLE hFile = INVALID_HANDLE_VALUE;
  925. BOOL fSts;
  926. DWORD dwLen;
  927. try
  928. {
  929. hFile = CreateFile(
  930. szData,
  931. GENERIC_READ,
  932. FILE_SHARE_READ,
  933. NULL,
  934. OPEN_EXISTING,
  935. FILE_ATTRIBUTE_NORMAL,
  936. NULL);
  937. if (INVALID_HANDLE_VALUE == hFile)
  938. throw GetLastError();
  939. m_bfData.Presize(GetFileSize(hFile, NULL));
  940. fSts = ReadFile(
  941. hFile,
  942. m_bfData.Access(),
  943. m_bfData.Space(),
  944. &dwLen,
  945. NULL);
  946. if (!fSts)
  947. throw GetLastError();
  948. m_bfData.Resize(dwLen, TRUE);
  949. fSts = CloseHandle(hFile);
  950. hFile = INVALID_HANDLE_VALUE;
  951. if (!fSts)
  952. throw GetLastError();
  953. }
  954. catch (...)
  955. {
  956. if (INVALID_HANDLE_VALUE != hFile)
  957. {
  958. fSts = CloseHandle(hFile);
  959. ASSERT(fSts);
  960. }
  961. throw;
  962. }
  963. break;
  964. }
  965. default:
  966. throw (DWORD)SCARD_F_INTERNAL_ERROR;
  967. }
  968. }
  969. /*++
  970. RenderData:
  971. This method converts the raw binary data stored in the stype to the
  972. provided display type.
  973. Arguments:
  974. dwType supplies the type of string data to be returned.
  975. Return Value:
  976. The rendered string
  977. Throws:
  978. Errors are thrown as DWORD status codes
  979. Author:
  980. Doug Barlow (dbarlow) 5/5/1998
  981. --*/
  982. LPCTSTR
  983. CRenderableData::RenderData(
  984. DisplayType dwType)
  985. {
  986. if (Undefined == dwType)
  987. dwType = m_dwType;
  988. switch (dwType)
  989. {
  990. case Text:
  991. m_bfData.Append((LPBYTE)TEXT("\000"), sizeof(TCHAR));
  992. m_szString = (LPCTSTR)m_bfData.Access();
  993. break;
  994. case Ansi:
  995. m_bfData.Append((LPBYTE)"\000", sizeof(CHAR));
  996. m_szString = (LPCSTR)m_bfData.Access();
  997. break;
  998. case Unicode:
  999. m_bfData.Append((LPBYTE)L"\000", sizeof(WCHAR));
  1000. m_szString = (LPCWSTR)m_bfData.Access();
  1001. break;
  1002. case Undefined: // Default output
  1003. case Hexidecimal:
  1004. {
  1005. DWORD dwIndex;
  1006. DWORD dwLength = m_bfData.Length();
  1007. CBuffer bfString((dwLength * 2 + 1) * sizeof(TCHAR));
  1008. for (dwIndex = 0; dwIndex < dwLength; dwIndex += 1)
  1009. wsprintf(
  1010. (LPTSTR)bfString.Access(dwIndex * 2 * sizeof(TCHAR)),
  1011. TEXT("%02x"),
  1012. m_bfData[dwIndex]);
  1013. *(LPTSTR)bfString.Access(dwLength * 2 * sizeof(TCHAR)) = TEXT('\000');
  1014. m_szString = (LPCTSTR)bfString.Access();
  1015. break;
  1016. }
  1017. case File:
  1018. {
  1019. HANDLE hFile = INVALID_HANDLE_VALUE;
  1020. BOOL fSts;
  1021. DWORD dwLen;
  1022. m_szString.Empty();
  1023. try
  1024. {
  1025. if (m_szFile.IsEmpty())
  1026. throw (DWORD)ERROR_INVALID_NAME;
  1027. hFile = CreateFile(
  1028. m_szFile,
  1029. GENERIC_WRITE,
  1030. 0,
  1031. NULL,
  1032. CREATE_ALWAYS,
  1033. FILE_ATTRIBUTE_NORMAL,
  1034. NULL);
  1035. if (INVALID_HANDLE_VALUE == hFile)
  1036. throw GetLastError();
  1037. fSts = WriteFile(
  1038. hFile,
  1039. m_bfData.Access(),
  1040. m_bfData.Length(),
  1041. &dwLen,
  1042. NULL);
  1043. if (!fSts)
  1044. throw GetLastError();
  1045. ASSERT(dwLen == m_bfData.Length());
  1046. fSts = CloseHandle(hFile);
  1047. hFile = INVALID_HANDLE_VALUE;
  1048. if (!fSts)
  1049. throw GetLastError();
  1050. }
  1051. catch (...)
  1052. {
  1053. if (INVALID_HANDLE_VALUE != hFile)
  1054. {
  1055. fSts = CloseHandle(hFile);
  1056. ASSERT(fSts);
  1057. }
  1058. throw;
  1059. }
  1060. break;
  1061. }
  1062. default:
  1063. throw (DWORD)SCARD_F_INTERNAL_ERROR;
  1064. }
  1065. return m_szString;
  1066. }
  1067. //
  1068. //==============================================================================
  1069. //
  1070. // CArgArray
  1071. //
  1072. /*++
  1073. CONSTRUCTOR:
  1074. This method is the default constructor for a CArgArray.
  1075. Arguments:
  1076. None
  1077. Author:
  1078. Doug Barlow (dbarlow) 5/14/1998
  1079. --*/
  1080. CArgArray::CArgArray(
  1081. CTclCommand &tclCmd)
  1082. : m_rgszElements()
  1083. {
  1084. m_pTclCmd = &tclCmd;
  1085. m_pszMemory = NULL;
  1086. m_dwElements = 0;
  1087. }
  1088. /*++
  1089. DESTRUCTOR:
  1090. This is the destructor method for the CArgArray.
  1091. Remarks:
  1092. The string elements are automatically freed.
  1093. Author:
  1094. Doug Barlow (dbarlow) 5/14/1998
  1095. --*/
  1096. CArgArray::~CArgArray()
  1097. {
  1098. if (NULL != m_pszMemory)
  1099. ckfree((LPSTR)m_pszMemory);
  1100. }
  1101. /*++
  1102. LoadList:
  1103. Load a potential list of arguments into the argument list, so that they may
  1104. be accessed individually.
  1105. Arguments:
  1106. szList supplies the Tcl Text string that contains the individual arguments.
  1107. Return Value:
  1108. None
  1109. Throws:
  1110. Errors are thrown as DWORD exceptions.
  1111. Author:
  1112. Doug Barlow (dbarlow) 5/14/1998
  1113. --*/
  1114. void
  1115. CArgArray::LoadList(
  1116. LPCSTR szList)
  1117. {
  1118. int nElements;
  1119. DWORD dwIndex;
  1120. Tcl_SplitList(*m_pTclCmd, (LPSTR)szList, &nElements, &m_pszMemory);
  1121. m_dwElements = (DWORD)nElements;
  1122. for (dwIndex = 0; dwIndex < m_dwElements; dwIndex += 1)
  1123. m_rgszElements.Add(m_pszMemory[dwIndex]);
  1124. }