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.

828 lines
19 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1997.
  5. //
  6. // File: parse.cxx
  7. //
  8. // Contents: IIS Pathname Parser
  9. //
  10. // The Pathname Parser is a key component in ADs providers. It checks for
  11. // syntactic validity of an ADs pathname that has been passed to this
  12. // provider. If the syntax is valid, then an OBJECTINFO structure is
  13. // constructed. This OBJECTINFO structure contains a componentized version
  14. // of the ADs pathname for this object.
  15. //
  16. // Note all that is being done is a syntax check. Rather than special-case
  17. // every single new nuance to pathnames, all path checking must conform to
  18. // the grammar rules laid out by the parser.
  19. //
  20. //
  21. //
  22. // History:
  23. //----------------------------------------------------------------------------
  24. #include "iisext.hxx"
  25. #pragma hdrstop
  26. // Object -> PathName, Type, eos
  27. // Object -> PathName, eos
  28. //+---------------------------------------------------------------------------
  29. // Function: ADsObject
  30. //
  31. // Synopsis: parses an ADs pathname passed to this provider. This function
  32. // parses the following grammar rules
  33. //
  34. // <ADsObject> -> <ProviderName> <IISObject>
  35. //
  36. //
  37. // Arguments: [CLexer * pTokenizer] - a lexical analyzer object
  38. // [POBJECTINFO pObjectInfo] - a pointer to an OBJECTINFO structure
  39. //
  40. // Returns: [HRESULT] 0 if successful, error HRESULT if not
  41. //
  42. // Modifies: pTokenizer (consumes the input buffer)
  43. //
  44. // History: 11-3-95 krishnag Created.
  45. //
  46. //----------------------------------------------------------------------------
  47. HRESULT
  48. ADsObject(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  49. {
  50. WCHAR szToken[MAX_TOKEN_LENGTH];
  51. DWORD dwToken;
  52. HRESULT hr;
  53. hr = ProviderName(pTokenizer, pObjectInfo);
  54. BAIL_IF_ERROR(hr);
  55. pObjectInfo->ComponentArray = NULL;
  56. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  57. BAIL_IF_ERROR(hr);
  58. switch (dwToken) {
  59. case TOKEN_END:
  60. RRETURN(S_OK);
  61. case TOKEN_COMMA:
  62. hr = Type(pTokenizer, pObjectInfo);
  63. BAIL_IF_ERROR(hr);
  64. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  65. BAIL_IF_ERROR(hr);
  66. if (dwToken == TOKEN_END) {
  67. RRETURN(S_OK);
  68. }else {
  69. RRETURN(E_ADS_BAD_PATHNAME);
  70. }
  71. default:
  72. hr = pTokenizer->PushBackToken();
  73. hr = IISObject(pTokenizer, pObjectInfo);
  74. BAIL_IF_ERROR(hr);
  75. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  76. BAIL_IF_ERROR(hr);
  77. switch (dwToken) {
  78. case TOKEN_END:
  79. RRETURN(S_OK);
  80. case TOKEN_COMMA:
  81. hr = Type(pTokenizer, pObjectInfo);
  82. BAIL_IF_ERROR(hr);
  83. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  84. BAIL_IF_ERROR(hr);
  85. if (dwToken == TOKEN_END) {
  86. RRETURN(S_OK);
  87. }else {
  88. RRETURN(E_ADS_BAD_PATHNAME);
  89. }
  90. default:
  91. RRETURN(E_FAIL);
  92. }
  93. }
  94. cleanup:
  95. RRETURN(hr);
  96. }
  97. //+---------------------------------------------------------------------------
  98. // Function: IISObject
  99. //
  100. // Synopsis: parses an ADs pathname passed to this provider. This function
  101. // parses the following grammar rules
  102. //
  103. // <IISObject> -> "\\""identifier""\" <IISObject>
  104. //
  105. //
  106. // Arguments: [CLexer * pTokenizer] - a lexical analyzer object
  107. // [POBJECTINFO pObjectInfo] - a pointer to an OBJECTINFO structure
  108. //
  109. // Returns: [HRESULT] 0 if successful, error HRESULT if not
  110. //
  111. // Modifies: pTokenizer (consumes the input buffer)
  112. //
  113. // History: 11-3-95 krishnag Created.
  114. //
  115. //----------------------------------------------------------------------------
  116. HRESULT
  117. IISObject(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  118. {
  119. WCHAR szToken[MAX_TOKEN_LENGTH];
  120. DWORD dwToken;
  121. HRESULT hr;
  122. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  123. BAIL_IF_ERROR(hr);
  124. if ((dwToken != TOKEN_FSLASH) && (dwToken != TOKEN_BSLASH)) {
  125. RRETURN(E_ADS_BAD_PATHNAME);
  126. }
  127. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  128. BAIL_IF_ERROR(hr);
  129. if ((dwToken != TOKEN_FSLASH) && (dwToken != TOKEN_BSLASH)) {
  130. RRETURN(E_ADS_BAD_PATHNAME);
  131. }
  132. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  133. BAIL_IF_ERROR(hr);
  134. if (dwToken != TOKEN_IDENTIFIER) {
  135. RRETURN(E_ADS_BAD_PATHNAME);
  136. }
  137. hr = AddTreeName(pObjectInfo, szToken);
  138. BAIL_IF_ERROR(hr);
  139. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  140. BAIL_IF_ERROR(hr);
  141. //
  142. // If we get an TOKEN_END, then we have a tree name only \\<tree_name>
  143. //
  144. if (dwToken == TOKEN_END || dwToken == TOKEN_COMMA) {
  145. hr = pTokenizer->PushBackToken();
  146. RRETURN(S_OK);
  147. }
  148. if ((dwToken != TOKEN_BSLASH) && (dwToken != TOKEN_FSLASH)) {
  149. RRETURN(E_ADS_BAD_PATHNAME);
  150. }
  151. hr = PathName(pTokenizer, pObjectInfo);
  152. BAIL_IF_ERROR(hr);
  153. cleanup:
  154. RRETURN(hr);
  155. }
  156. HRESULT
  157. ProviderName(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  158. {
  159. WCHAR szToken[MAX_TOKEN_LENGTH];
  160. DWORD dwToken;
  161. HRESULT hr;
  162. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  163. BAIL_IF_ERROR(hr);
  164. if (dwToken == TOKEN_ATSIGN) {
  165. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  166. BAIL_IF_ERROR(hr);
  167. if (dwToken != TOKEN_IDENTIFIER) {
  168. RRETURN(E_ADS_BAD_PATHNAME);
  169. }
  170. hr = AddProviderName(pObjectInfo, szToken);
  171. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  172. BAIL_IF_ERROR(hr);
  173. if (dwToken != TOKEN_EXCLAMATION) {
  174. RRETURN(E_ADS_BAD_PATHNAME);
  175. }
  176. }else if (dwToken == TOKEN_IDENTIFIER) {
  177. hr = AddProviderName(pObjectInfo, szToken);
  178. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  179. BAIL_IF_ERROR(hr);
  180. if (dwToken != TOKEN_COLON) {
  181. RRETURN(E_ADS_BAD_PATHNAME);
  182. }
  183. }else {
  184. RRETURN(E_ADS_BAD_PATHNAME);
  185. }
  186. //
  187. // You can now disable the processing for "@" and "!" treat them
  188. // as ordinary characters.
  189. //
  190. pTokenizer->SetAtDisabler(TRUE);
  191. RRETURN(S_OK);
  192. cleanup:
  193. RRETURN(hr);
  194. }
  195. // PathName -> Component \\ PathName
  196. // PathName -> Component
  197. HRESULT
  198. DsPathName(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  199. {
  200. WCHAR szToken[MAX_TOKEN_LENGTH];
  201. DWORD dwToken;
  202. HRESULT hr;
  203. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  204. BAIL_IF_ERROR(hr);
  205. if ((dwToken != TOKEN_FSLASH) && (dwToken != TOKEN_BSLASH)) {
  206. RRETURN(E_ADS_BAD_PATHNAME);
  207. }
  208. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  209. BAIL_IF_ERROR(hr);
  210. if ((dwToken != TOKEN_FSLASH) && (dwToken != TOKEN_BSLASH)) {
  211. RRETURN(E_ADS_BAD_PATHNAME);
  212. }
  213. hr = PathName(pTokenizer, pObjectInfo);
  214. BAIL_IF_ERROR(hr);
  215. RRETURN(S_OK);
  216. cleanup:
  217. RRETURN(hr);
  218. }
  219. //+---------------------------------------------------------------------------
  220. // Function:
  221. //
  222. // Synopsis:
  223. //
  224. // Arguments:
  225. //
  226. // Returns:
  227. //
  228. // Modifies:
  229. //
  230. // History: 11-3-95 krishnag Created.
  231. //
  232. //----------------------------------------------------------------------------
  233. HRESULT
  234. PathName(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  235. {
  236. HRESULT hr;
  237. WCHAR szToken[MAX_TOKEN_LENGTH];
  238. DWORD dwToken;
  239. do
  240. {
  241. hr = Component(pTokenizer, pObjectInfo);
  242. BAIL_IF_ERROR(hr);
  243. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  244. BAIL_IF_ERROR(hr);
  245. }
  246. while( (dwToken == TOKEN_BSLASH) || (dwToken == TOKEN_FSLASH) );
  247. hr = pTokenizer->PushBackToken();
  248. BAIL_IF_ERROR(hr);
  249. cleanup:
  250. RRETURN(hr);
  251. }
  252. //+---------------------------------------------------------------------------
  253. // Function:
  254. //
  255. // Synopsis: Component -> <identifier>
  256. //
  257. // Arguments:
  258. //
  259. // Returns:
  260. //
  261. // Modifies:
  262. //
  263. // History: 11-3-95 krishnag Created.
  264. //
  265. //----------------------------------------------------------------------------
  266. HRESULT
  267. Component(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  268. {
  269. WCHAR szValue[MAX_TOKEN_LENGTH];
  270. WCHAR szEqual[MAX_TOKEN_LENGTH];
  271. WCHAR szComponent[MAX_TOKEN_LENGTH];
  272. DWORD dwToken;
  273. HRESULT hr;
  274. hr = pTokenizer->GetNextToken(szComponent, &dwToken);
  275. BAIL_IF_ERROR(hr);
  276. if (dwToken != TOKEN_IDENTIFIER) {
  277. RRETURN(E_ADS_BAD_PATHNAME);
  278. }
  279. hr = pTokenizer->GetNextToken(szEqual, &dwToken);
  280. BAIL_IF_ERROR(hr);
  281. if (dwToken == TOKEN_EQUAL) {
  282. hr = pTokenizer->GetNextToken(szValue, &dwToken);
  283. BAIL_IF_ERROR(hr);
  284. if (dwToken != TOKEN_IDENTIFIER) {
  285. RRETURN(E_ADS_BAD_PATHNAME);
  286. }
  287. hr = AddComponent(pObjectInfo, szComponent, szValue);
  288. BAIL_IF_ERROR(hr);
  289. }else {
  290. hr = AddComponent(pObjectInfo, szComponent, NULL);
  291. BAIL_IF_ERROR(hr);
  292. hr = pTokenizer->PushBackToken();
  293. BAIL_IF_ERROR(hr);
  294. }
  295. RRETURN(S_OK);
  296. cleanup:
  297. RRETURN(hr);
  298. }
  299. //+---------------------------------------------------------------------------
  300. // Function:
  301. //
  302. // Synopsis:
  303. //
  304. // Arguments:
  305. //
  306. // Returns:
  307. //
  308. // Modifies:
  309. //
  310. // History: 11-3-95 krishnag Created.
  311. //
  312. //----------------------------------------------------------------------------
  313. CLexer::CLexer():
  314. _ptr(NULL),
  315. _Buffer(NULL),
  316. _dwLastTokenLength(0),
  317. _dwLastToken(0),
  318. _dwEndofString(0),
  319. _bAtDisabled(FALSE)
  320. {
  321. return;
  322. }
  323. HRESULT
  324. CLexer::Initialize(LPWSTR szBuffer)
  325. {
  326. if (!szBuffer || !*szBuffer) {
  327. RRETURN(S_OK);
  328. }
  329. _Buffer = AllocADsStr(szBuffer);
  330. if (!_Buffer) {
  331. RRETURN(E_OUTOFMEMORY);
  332. }
  333. _ptr = _Buffer;
  334. RRETURN(S_OK);
  335. }
  336. //+---------------------------------------------------------------------------
  337. // Function:
  338. //
  339. // Synopsis:
  340. //
  341. // Arguments:
  342. //
  343. // Returns:
  344. //
  345. // Modifies:
  346. //
  347. // History: 08-12-96 t-danal Created.
  348. //
  349. //----------------------------------------------------------------------------
  350. CLexer::~CLexer()
  351. {
  352. FreeADsStr(_Buffer);
  353. }
  354. /*++
  355. This routine assumes that szToken is a buffer of at least MAX_TOKEN_LENGTH
  356. --*/
  357. HRESULT
  358. CLexer::GetNextToken(LPWSTR szToken, LPDWORD pdwToken)
  359. {
  360. WCHAR c;
  361. DWORD state = 0;
  362. LPWSTR pch = szToken;
  363. memset(szToken, 0, sizeof(WCHAR) * MAX_TOKEN_LENGTH);
  364. _dwLastTokenLength = 0;
  365. while (1) {
  366. c = NextChar();
  367. switch (state) {
  368. case 0:
  369. if (_dwLastTokenLength++ >= MAX_TOKEN_LENGTH) {
  370. RRETURN(RETURNCODETOHRESULT(ERROR_INVALID_NAME));
  371. }
  372. *pch++ = c;
  373. if (c == L'\\') {
  374. *pdwToken = TOKEN_BSLASH;
  375. _dwLastToken = *pdwToken;
  376. RRETURN(S_OK);
  377. }else if (c == L'/') {
  378. *pdwToken = TOKEN_FSLASH;
  379. _dwLastToken = *pdwToken;
  380. RRETURN(S_OK);
  381. }else if (c == L',') {
  382. *pdwToken = TOKEN_COMMA;
  383. _dwLastToken = *pdwToken;
  384. RRETURN(S_OK);
  385. }else if (c == L'='){
  386. *pdwToken = TOKEN_EQUAL;
  387. _dwLastToken = *pdwToken;
  388. RRETURN(S_OK);
  389. }
  390. else if (c == L':'){
  391. *pdwToken = TOKEN_COLON;
  392. _dwLastToken = *pdwToken;
  393. RRETURN(S_OK);
  394. }else if (c == L'\0'){
  395. *pdwToken = TOKEN_END;
  396. _dwLastToken = *pdwToken;
  397. RRETURN(S_OK);
  398. }else if (c == L'@') {
  399. if (!_bAtDisabled) {
  400. *pdwToken = TOKEN_ATSIGN;
  401. _dwLastToken = *pdwToken;
  402. RRETURN(S_OK);
  403. }else {
  404. state = 1;
  405. }
  406. }else if (c == L'!'){
  407. if (!_bAtDisabled) {
  408. *pdwToken = TOKEN_EXCLAMATION;
  409. _dwLastToken = *pdwToken;
  410. RRETURN(S_OK);
  411. }else {
  412. state = 1;
  413. }
  414. }else {
  415. state = 1;
  416. }
  417. break;
  418. case 1:
  419. if (c == L'\\' || c == L'\0' || c == L',' ||
  420. c == L'=' ||
  421. c == L':' || c == L'/') {
  422. PushbackChar();
  423. *pdwToken = TOKEN_IDENTIFIER;
  424. _dwLastToken = *pdwToken;
  425. RRETURN (S_OK);
  426. }else if (c == L'@' || c == L'!') {
  427. if (!_bAtDisabled) {
  428. PushbackChar();
  429. *pdwToken = TOKEN_IDENTIFIER;
  430. _dwLastToken = *pdwToken;
  431. RRETURN(S_OK);
  432. }else {
  433. if (_dwLastTokenLength++ >= MAX_TOKEN_LENGTH) {
  434. RRETURN(RETURNCODETOHRESULT(ERROR_INVALID_NAME));
  435. }
  436. *pch++ = c;
  437. state = 1;
  438. break;
  439. }
  440. }else {
  441. if (_dwLastTokenLength++ >= MAX_TOKEN_LENGTH) {
  442. RRETURN(RETURNCODETOHRESULT(ERROR_INVALID_NAME));
  443. }
  444. *pch++ = c;
  445. state = 1;
  446. break;
  447. }
  448. default:
  449. RRETURN(E_FAIL);
  450. }
  451. }
  452. }
  453. //+---------------------------------------------------------------------------
  454. // Function:
  455. //
  456. // Synopsis:
  457. //
  458. // Arguments:
  459. //
  460. // Returns:
  461. //
  462. // Modifies:
  463. //
  464. // History: 11-3-95 krishnag Created.
  465. //
  466. //----------------------------------------------------------------------------
  467. WCHAR
  468. CLexer::NextChar()
  469. {
  470. if (_ptr == NULL || *_ptr == L'\0') {
  471. _dwEndofString = TRUE;
  472. return(L'\0');
  473. }
  474. return(*_ptr++);
  475. }
  476. //+---------------------------------------------------------------------------
  477. // Function:
  478. //
  479. // Synopsis:
  480. //
  481. // Arguments:
  482. //
  483. // Returns:
  484. //
  485. // Modifies:
  486. //
  487. // History: 11-3-95 krishnag Created.
  488. //
  489. //----------------------------------------------------------------------------
  490. HRESULT
  491. CLexer::PushBackToken()
  492. {
  493. if (_dwLastToken == TOKEN_END) {
  494. RRETURN(S_OK);
  495. }
  496. _ptr -= _dwLastTokenLength;
  497. RRETURN(S_OK);
  498. }
  499. //+---------------------------------------------------------------------------
  500. // Function:
  501. //
  502. // Synopsis:
  503. //
  504. // Arguments:
  505. //
  506. // Returns:
  507. //
  508. // Modifies:
  509. //
  510. // History: 11-3-95 krishnag Created.
  511. //
  512. //----------------------------------------------------------------------------
  513. void
  514. CLexer::PushbackChar()
  515. {
  516. if (_dwEndofString) {
  517. return;
  518. }
  519. _ptr--;
  520. }
  521. #if 0
  522. //+---------------------------------------------------------------------------
  523. // Function:
  524. //
  525. // Synopsis:
  526. //
  527. // Arguments:
  528. //
  529. // Returns:
  530. //
  531. // Modifies:
  532. //
  533. // History: 11-3-95 krishnag Created.
  534. //
  535. //----------------------------------------------------------------------------
  536. BOOL
  537. CLexer::IsKeyword(LPWSTR szToken, LPDWORD pdwToken)
  538. {
  539. DWORD i = 0;
  540. for (i = 0; i < MAX_KEYWORDS; i++) {
  541. if (!_wcsicmp(szToken, KeywordList[i].Keyword)) {
  542. *pdwToken = KeywordList[i].dwTokenId;
  543. return(TRUE);
  544. }
  545. }
  546. *pdwToken = 0;
  547. return(FALSE);
  548. }
  549. #endif
  550. //+---------------------------------------------------------------------------
  551. //Function:
  552. //
  553. //Synopsis:
  554. //
  555. //Arguments:
  556. //
  557. //Returns:
  558. //
  559. //Modifies:
  560. //
  561. //History: 11-3-95 krishnag Created.
  562. //
  563. //----------------------------------------------------------------------------
  564. HRESULT
  565. AddComponent(POBJECTINFO pObjectInfo, LPWSTR szComponent, LPWSTR szValue)
  566. {
  567. if (!szComponent || !*szComponent) {
  568. RRETURN(E_FAIL);
  569. }
  570. if (pObjectInfo->ComponentArray == NULL) {
  571. pObjectInfo->ComponentArray =
  572. (PCOMPONENT) AllocADsMem(sizeof(COMPONENT)*MAXCOMPONENTS);
  573. pObjectInfo->MaxComponents = MAXCOMPONENTS;
  574. }
  575. else if (pObjectInfo->NumComponents == pObjectInfo->MaxComponents) {
  576. pObjectInfo->ComponentArray =
  577. (PCOMPONENT) ReallocADsMem(
  578. pObjectInfo->ComponentArray,
  579. sizeof(COMPONENT)*pObjectInfo->MaxComponents,
  580. sizeof(COMPONENT)*(
  581. pObjectInfo->MaxComponents+MAXCOMPONENTS)
  582. );
  583. pObjectInfo->MaxComponents += MAXCOMPONENTS;
  584. }
  585. pObjectInfo->ComponentArray[pObjectInfo->NumComponents].szComponent =
  586. AllocADsStr(szComponent);
  587. if (szValue && *szValue) {
  588. pObjectInfo->ComponentArray[pObjectInfo->NumComponents].szValue =
  589. AllocADsStr(szValue);
  590. }
  591. else {
  592. pObjectInfo->ComponentArray[pObjectInfo->NumComponents].szValue = NULL;
  593. }
  594. pObjectInfo->NumComponents++;
  595. RRETURN(S_OK);
  596. }
  597. HRESULT
  598. AddProviderName(POBJECTINFO pObjectInfo, LPWSTR szToken)
  599. {
  600. if (!szToken || !*szToken) {
  601. RRETURN(E_FAIL);
  602. }
  603. pObjectInfo->ProviderName = AllocADsStr(szToken);
  604. RRETURN(S_OK);
  605. }
  606. HRESULT
  607. AddTreeName(POBJECTINFO pObjectInfo, LPWSTR szToken)
  608. {
  609. if (!szToken || !*szToken) {
  610. RRETURN(E_FAIL);
  611. }
  612. pObjectInfo->TreeName = AllocADsStr(szToken);
  613. RRETURN(S_OK);
  614. }
  615. //+---------------------------------------------------------------------------
  616. // Function:
  617. //
  618. // Synopsis:
  619. //
  620. // Arguments:
  621. //
  622. // Returns:
  623. //
  624. // Modifies:
  625. //
  626. // History: 11-3-95 krishnag Created.
  627. //
  628. //----------------------------------------------------------------------------
  629. HRESULT
  630. SetType(POBJECTINFO pObjectInfo, DWORD dwToken)
  631. {
  632. pObjectInfo->ObjectType = dwToken;
  633. RRETURN(S_OK);
  634. }
  635. // Type -> "user", "group","printer","service", "fileservice"
  636. //+---------------------------------------------------------------------------
  637. // Function: Type
  638. //
  639. // Synopsis: Parses Type-> "user" | "group" etc
  640. //
  641. // Arguments: [CLexer * pTokenizer]
  642. // [POBJECTINFo pObjectInfo]
  643. //
  644. // Returns: HRESULT
  645. //
  646. // Modifies: -
  647. //
  648. // History: 11-3-95 krishnag Created.
  649. //
  650. //----------------------------------------------------------------------------
  651. HRESULT
  652. Type(CLexer * pTokenizer, POBJECTINFO pObjectInfo)
  653. {
  654. WCHAR szToken[MAX_PATH];
  655. DWORD dwToken;
  656. HRESULT hr;
  657. hr = pTokenizer->GetNextToken(szToken, &dwToken);
  658. BAIL_IF_ERROR(hr);
  659. if (dwToken == TOKEN_IDENTIFIER ) {
  660. RRETURN(hr);
  661. }
  662. RRETURN(E_FAIL);
  663. cleanup:
  664. RRETURN(hr);
  665. }
  666. void
  667. CLexer::SetAtDisabler(
  668. BOOL bFlag
  669. )
  670. {
  671. _bAtDisabled = bFlag;
  672. }
  673. BOOL
  674. CLexer::GetAtDisabler()
  675. {
  676. return(_bAtDisabled);
  677. }