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.

914 lines
28 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. dirlist.cxx
  5. Abstract:
  6. This module implements the member functions for TS_DIRECTORY_INFO
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 16-Jan-1995
  9. Project:
  10. Tsunami Lib
  11. ( Common caching and directory functions for Internet Services)
  12. Functions Exported:
  13. TS_DIRECTORY_INFO::CleanupThis()
  14. TS_DIRECTORY_INFO::GetDirectoryListingA()
  15. IN LPCSTR pszDirectoryName,
  16. IN HANDLE hListingUser)
  17. TS_DIRECTORY_INFO::SortFileInfoPointers(
  18. IN PFN_CMP_WIN32_FIND_DATA pfnCompare)
  19. TS_DIRECTORY_INFO::FilterFiles(
  20. IN PFN_IS_MATCH_WIN32_FIND_DATA pfnMatch,
  21. IN LPVOID pContext);
  22. Revision History:
  23. MuraliK 06-Dec-1995 Used Win32 apis instead of NT apis
  24. MCourage 05-Jan-1997 Moved to cache2 directory
  25. --*/
  26. /************************************************************
  27. * Include Headers
  28. ************************************************************/
  29. # include <tsunami.hxx>
  30. # include "tsunamip.hxx"
  31. # include "dbgutil.h"
  32. # include <string.h>
  33. /************************************************************
  34. * Type Definitions
  35. ************************************************************/
  36. dllexp
  37. VOID
  38. TS_DIRECTORY_INFO::CleanupThis( VOID)
  39. {
  40. IF_DEBUG( DIR_LIST) {
  41. DBGPRINTF( ( DBG_CONTEXT,
  42. "Cleaning up TS_DIRECTORY_INFO ( %08p)\n",
  43. this));
  44. Print();
  45. }
  46. if ( m_fValid) {
  47. if ( m_pTsDirectoryHeader != NULL) {
  48. TsFreeDirectoryListing( m_tsCache, m_pTsDirectoryHeader);
  49. m_pTsDirectoryHeader = NULL;
  50. }
  51. ASSERT( m_pTsDirectoryHeader == NULL);
  52. if ( m_prgFileInfo != NULL) {
  53. FREE( m_prgFileInfo);
  54. m_prgFileInfo = NULL;
  55. }
  56. }
  57. ASSERT( m_pTsDirectoryHeader == NULL);
  58. ASSERT( m_prgFileInfo == NULL);
  59. m_fValid = 0;
  60. m_cFilesInDirectory = 0;
  61. } // TS_DIRECTORY_INFO::CleanupThis()
  62. static BOOL
  63. MakeCopyOfFileInfoPointers(
  64. IN OUT PWIN32_FIND_DATA ** pppFileInfoTo,
  65. IN const PWIN32_FIND_DATA * ppFileInfoFrom,
  66. IN int nEntries)
  67. /*++
  68. Allocates memory and makes a copy of the file info pointers in the array
  69. in ppFileInfoFrom.
  70. Returns:
  71. TRUE if success and FALSE if there is any failure.
  72. --*/
  73. {
  74. DWORD cbCopy;
  75. ASSERT( *pppFileInfoTo == NULL);
  76. cbCopy = nEntries * sizeof( PWIN32_FIND_DATA);
  77. *pppFileInfoTo = (PWIN32_FIND_DATA *) ALLOC( cbCopy);
  78. if ( *pppFileInfoTo != NULL) {
  79. memcpy((PVOID ) *pppFileInfoTo,
  80. (const PVOID ) ppFileInfoFrom,
  81. cbCopy);
  82. } else {
  83. SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  84. }
  85. return ( *pppFileInfoTo != NULL);
  86. } // MakeCopyOfFileInfoPointers()
  87. dllexp
  88. BOOL
  89. TS_DIRECTORY_INFO::GetDirectoryListingA(
  90. IN LPCSTR pszDirectoryName,
  91. IN HANDLE hListingUser)
  92. {
  93. if ( m_pTsDirectoryHeader == NULL) {
  94. //
  95. // Only if already a directory listing is not obtained.
  96. // we obtain newly
  97. //
  98. IF_DEBUG( DIR_LIST) {
  99. DBGPRINTF( ( DBG_CONTEXT,
  100. "Obtaining Dir Listing for %s. UserHandle=%08p.\n",
  101. pszDirectoryName, hListingUser));
  102. }
  103. m_fValid = TsGetDirectoryListing( m_tsCache,
  104. pszDirectoryName,
  105. hListingUser,
  106. &m_pTsDirectoryHeader);
  107. m_fValid = m_fValid &&
  108. MakeCopyOfFileInfoPointers(
  109. &m_prgFileInfo,
  110. m_pTsDirectoryHeader->QueryArrayOfFileInfoPointers(),
  111. m_pTsDirectoryHeader->QueryNumEntries());
  112. m_cFilesInDirectory = ( m_pTsDirectoryHeader == NULL) ? 0 :
  113. m_pTsDirectoryHeader->QueryNumEntries();
  114. }
  115. return ( m_fValid);
  116. } // TS_DIRECTORY_INFO::GetDirectoryListingA()
  117. dllexp
  118. BOOL
  119. TS_DIRECTORY_INFO::SortFileInfoPointers(
  120. IN PFN_CMP_WIN32_FIND_DATA pfnCompare)
  121. {
  122. BOOL fReturn = FALSE;
  123. if ( IsValid()) {
  124. fReturn = SortInPlaceFileInfoPointers(m_prgFileInfo,
  125. m_cFilesInDirectory,
  126. pfnCompare);
  127. }
  128. return ( fReturn);
  129. } // TS_DIRECTORY_INFO::SortFileInfoPointers()
  130. dllexp
  131. BOOL
  132. TS_DIRECTORY_INFO::FilterFiles( IN PFN_IS_MATCH_WIN32_FIND_DATA pfnMatch,
  133. IN LPVOID pContext)
  134. /*++
  135. This function filters the list of files using the pfnMatch function
  136. and the context information specified by pContext.
  137. This function eliminates all the pointers to FileInfo which do not
  138. match the given file specification.
  139. Returns:
  140. TRUE on success and FALSE on failure.
  141. --*/
  142. {
  143. BOOL fReturn = FALSE;
  144. if ( IsValid()) {
  145. int idxScan; // for scanning the files
  146. int idxCur; // for updating after filter
  147. IF_DEBUG( DIR_LIST) {
  148. DBGPRINTF( ( DBG_CONTEXT,
  149. "FilterFiles in DirList( %08p) for FileSpec %08p\n",
  150. this, pContext));
  151. }
  152. for( idxCur = idxScan = 0;
  153. idxScan < m_cFilesInDirectory;
  154. idxScan++) {
  155. PWIN32_FIND_DATA pFileInfo =
  156. GetFileInfoPointerFromIdx( idxScan);
  157. ASSERT( pFileInfo != NULL);
  158. ASSERT( idxCur <= idxScan);
  159. if ( (*pfnMatch)( pFileInfo, pContext)) {
  160. //
  161. // this is a match. Retain this item and advance CurPtr
  162. //
  163. m_prgFileInfo[ idxCur++] = m_prgFileInfo[ idxScan];
  164. }
  165. } // for
  166. m_cFilesInDirectory = idxCur;
  167. fReturn = TRUE;
  168. }
  169. return ( fReturn);
  170. } // TS_DIRECTORY_INFO::FilterFiles()
  171. # if DBG
  172. VOID
  173. TS_DIRECTORY_INFO::Print( VOID) const
  174. {
  175. DBGPRINTF( ( DBG_CONTEXT,
  176. " Printing TS_DIRECTORY_INFO ( %08p).\n"
  177. "NumEntries=%d\t Valid = %d\n"
  178. "Directory Header ( %08p) \t ArrayOfFileInfo = %08p\n",
  179. this,
  180. m_cFilesInDirectory, m_fValid,
  181. m_pTsDirectoryHeader, m_prgFileInfo));
  182. for( int idx = 0; idx < m_cFilesInDirectory; idx++) {
  183. PWIN32_FIND_DATA pfi = m_prgFileInfo[idx];
  184. DBGPRINTF( ( DBG_CONTEXT,
  185. "rgFileInfo[%4d] = %08p. Name=%s Attr=0x%x"
  186. "Size=0x%x:%x\n",
  187. idx, pfi,
  188. pfi->cFileName,
  189. pfi->dwFileAttributes,
  190. pfi->nFileSizeHigh,
  191. pfi->nFileSizeLow
  192. ));
  193. }
  194. m_pTsDirectoryHeader->Print();
  195. return;
  196. } // TS_DIRECTORY_INFO::Print()
  197. # endif // DBG
  198. BOOL __cdecl
  199. RegExpressionMatchFileInfo( IN const WIN32_FIND_DATA * pFileInfo,
  200. IN CHAR * pszExpression)
  201. /*++
  202. This function tries to find a match between the file name in
  203. pFileInfo and the regular expression specified in pszExpression.
  204. Arguments:
  205. pFileInfo -- pointer to file information consisting under query.
  206. pszExpression - pointer to null-terminated string containing the
  207. regular expression, against which file name is tobe
  208. matched for.
  209. Returns:
  210. TRUE on a match and false if there is any failure.
  211. --*/
  212. {
  213. const CHAR * pszFileName;
  214. DBG_ASSERT( pFileInfo != NULL);
  215. pszFileName = pFileInfo->cFileName;
  216. if ( strpbrk( pszExpression, "?*<>") != NULL) {
  217. // No Wild cards. Do normal file comparisons
  218. return ( strcmp( pszFileName, pszExpression) == 0);
  219. } else {
  220. // do a case sensitive comparison
  221. return IsNameInRegExpressionA( pszExpression, pszFileName, FALSE);
  222. }
  223. } // RegExpressionMatch()
  224. /************************************************************
  225. * Following code is based on the FileSystem Rtl routines
  226. * from ntos\fsrtl\name.c
  227. * But these are optimized for performance, in our case
  228. * using ANSI strings!
  229. ************************************************************/
  230. # define MAX_MATCHES_ARRAY_SIZE (16)
  231. # define IS_EMPTY_STRING(psz) ( (psz) == NULL || *(psz) == '\0')
  232. //
  233. // Original code used USHORT for ULEN. However using USHORT asks
  234. // a 32 bit processor to add "and <value>, 0xff for each instruction
  235. // that accessed the 16 bit (USHORT) value.
  236. // Hence, I decided to use DWORD, since the space usage is not tremendous
  237. // during the fast path work, compared to performance benefits.
  238. // - MuraliK (Oct 27, 1995)
  239. //
  240. // typedef USHORT ULEN;
  241. typedef DWORD ULEN;
  242. BOOL __cdecl
  243. IsNameInRegExpressionA(
  244. IN LPCSTR pszExpression,
  245. IN LPCSTR pszName,
  246. IN BOOL fIgnoreCase)
  247. /*++
  248. This routine compares an ANSI name and an expression and decries to the
  249. caller if the name is in hte language defined by the expression. The input
  250. name cannot contain wildcards, while the expression itself may contain
  251. wildcards.
  252. Expression wild cards are evaluated as shown in the non-deterministic finite
  253. automatons below. Note that ~* and ~? stand for DOS_STAR and DOS_QM.
  254. ~* is DOS_STAR, ~? is DOS_QM, and ~. is DOS_DOT
  255. S
  256. <-----<
  257. X | | e Y
  258. X * Y == (0)----->-(1)->-----(2)-----(3)
  259. S-.
  260. <-----<
  261. X | | e Y
  262. X ~* Y == (0)----->-(1)->-----(2)-----(3)
  263. X S S Y
  264. X ?? Y == (0)---(1)---(2)---(3)---(4)
  265. X . . Y
  266. X ~.~. Y == (0)---(1)----(2)------(3)---(4)
  267. | |________|
  268. | ^ |
  269. |_______________|
  270. ^EOF or .^
  271. X S-. S-. Y
  272. X ~?~? Y == (0)---(1)-----(2)-----(3)---(4)
  273. | |________|
  274. | ^ |
  275. |_______________|
  276. ^EOF or .^
  277. where S is any single character
  278. S-. is any single character except .
  279. e is a null character transition
  280. EOF is the end of the name string
  281. The last construction, ~? (the DOS question mark), can either match any
  282. single character, or upon encountering a period or end of input string,
  283. advances the expression to the end of the set of contiguous ~?s. This may
  284. seem somewhat convoluted, but is what DOS needs.
  285. Arguments:
  286. pszExpression - Supplies the input expression to check against
  287. ( Caller must already lowercased if passing fIgnoreCase TRUE.)
  288. pszName - supplies the input name to check for.
  289. fIgnoreCase - if TRUE, the name should be lower-cased before comparing.
  290. ( that is done by this function, dynamically without destroying pszName)
  291. This function is costly, if the pszExpression does not contain
  292. any wild cards to be matched for. So Dont use it if there are
  293. no wild cards in the pszExpression
  294. Returns:
  295. BOOL -- TRUE if pszName is an element in the set of strings denoted
  296. by the input expression. FALSE if otherwise.
  297. --*/
  298. {
  299. ULEN NameLen; // length in character count
  300. ULEN ExprLen;
  301. /*
  302. * Algorithm:
  303. * Keep track of all possible locations in the regular expression
  304. * that are matching the name. If when the name has been exhausted
  305. * one of the locations in the expression is also just exhausted, the
  306. * name is in the language defined by the regular expression.
  307. */
  308. DBG_ASSERT( pszName != NULL && *pszName != '\0');
  309. DBG_ASSERT( pszExpression != NULL && *pszExpression != '\0');
  310. //
  311. // if one string is empty return FALSE. If both are empty TRUE.
  312. //
  313. if ( IS_EMPTY_STRING(pszName) || IS_EMPTY_STRING(pszExpression)) {
  314. IF_DEBUG( DIR_LIST) {
  315. DBGPRINTF((DBG_CONTEXT, " IsNameInRegExpr( %s, %s, %d) ==>%d\n",
  316. pszExpression, pszName, fIgnoreCase,
  317. !(*pszName + *pszExpression)
  318. ));
  319. }
  320. return (BOOL ) (IS_EMPTY_STRING(pszName) && IS_EMPTY_STRING(pszExpression));
  321. }
  322. NameLen = strlen(pszName);
  323. ExprLen = strlen(pszExpression);
  324. //
  325. // Special case: reduce the most common wild card search of *
  326. //
  327. if ( ExprLen == 1 && pszExpression[0] == '*') {
  328. IF_DEBUG ( DIR_LIST) {
  329. DBGPRINTF((DBG_CONTEXT, " IsNameInRegExpr( %s, %s, %d) ==>%d\n",
  330. pszExpression, pszName, fIgnoreCase,
  331. TRUE
  332. ));
  333. }
  334. // matches anything. so return TRUE
  335. return (TRUE);
  336. }
  337. //
  338. // Walk through the name string, picking off characters. We go one
  339. // character beyond the end because some wild cards are able to match
  340. // zero characters beyond the end of the string.
  341. //
  342. // With each new name character we determine a new set of states that
  343. // match the name so far. We use two arrays that we swap back and forth
  344. // for this purpose. One array lists the possible expression states for
  345. // all name characters up to but not including the current one, and other
  346. // array is used to build up the list of states considering the current
  347. // name character as well. The arrays are then switched and the process
  348. // repeated.
  349. //
  350. // There is not a one-to-one correspondence between state number and
  351. // offset into the pszExpression. This is evident from the NFAs in the
  352. // initial comment to this function. State numbering is not continuous.
  353. // This allows a simple conversion between state number and expression
  354. // offset. Each character in the Expression can represent one or two
  355. // states. '*' and DOS_STAR generate two states: ExprOffset*2 and
  356. // ExprOffset*2 + 1. All other expression characters can produce only
  357. // a single state. Thus ExprOffset = State/2.
  358. //
  359. //
  360. // Here is a short description of the variables involved:
  361. //
  362. // NameOffset -The offset of the current name char being processed.
  363. //
  364. // ExprOffset -The offset of the current expression char being processed.
  365. //
  366. // SrcCount -Prior match being investigated with current name char
  367. //
  368. // DestCount -Next location to put a matching assuming current name char
  369. //
  370. // NameFinished - Allows one more iteration through the Matches array
  371. // after the name is exhusted (to come *s for example)
  372. //
  373. // PreviousDestCount - This is used to prevent entry duplication,
  374. // see comment
  375. //
  376. // PreviousMatches - Holds the previous set of matches (the Src array)
  377. //
  378. // CurrentMatches - Holds the current set of matches (the Dest array)
  379. //
  380. // AuxBuffer, LocalBuffer - the storage for the Matches arrays
  381. //
  382. ULEN NameOffset; // offset in terms of byte count
  383. ULEN ExprOffset; // offset in terms of byte count
  384. ULONG SrcCount;
  385. ULONG DestCount;
  386. ULONG PreviousDestCount;
  387. ULONG MatchesCount;
  388. ULONG BufSize = MAX_MATCHES_ARRAY_SIZE;
  389. CHAR NameChar, ExprChar;
  390. // for prev and current matches
  391. ULEN *AuxBuffer = NULL;
  392. ULEN *PreviousMatches;
  393. ULEN *CurrentMatches;
  394. ULEN MaxState;
  395. ULEN CurrentState;
  396. BOOL NameFinished;
  397. ULEN LocalBuffer[MAX_MATCHES_ARRAY_SIZE * 2];
  398. // set up the intial values
  399. // Use the different portions of local buffer for matches.
  400. PreviousMatches = &LocalBuffer[0];
  401. CurrentMatches = &LocalBuffer[MAX_MATCHES_ARRAY_SIZE];
  402. PreviousMatches[0] = 0;
  403. MatchesCount = 1;
  404. NameOffset = 0;
  405. MaxState = (ULEN ) (ExprLen * 2);
  406. NameFinished = FALSE;
  407. while (!NameFinished) {
  408. if ( NameOffset < NameLen) {
  409. NameChar = pszName[NameOffset/sizeof(CHAR)];
  410. NameOffset += sizeof(CHAR);
  411. } else {
  412. NameFinished = TRUE;
  413. // if we already exhauseted expression, stop. Else continue
  414. DBG_ASSERT( MatchesCount >= 1);
  415. if ( PreviousMatches[MatchesCount - 1] == MaxState) {
  416. break;
  417. }
  418. }
  419. //
  420. // Now, for each of previous stored expression matches,
  421. // see what we can do with the new name character.
  422. //
  423. DestCount = 0;
  424. PreviousDestCount = 0;
  425. for( SrcCount = 0; SrcCount < MatchesCount; ) {
  426. ULEN Length;
  427. //
  428. // We have to carry on our expression analysis as far as possible
  429. // for each character of name, so we loop here until the
  430. // expression stops matching. A clue here is that expression
  431. // cases that can match zero or more characters end with a
  432. // continue, while those that can accept only a single character
  433. // end with a break.
  434. //
  435. ExprOffset = (ULEN)((PreviousMatches[SrcCount++] + 1) / 2);
  436. for( Length = 0; ExprOffset != ExprLen; ) {
  437. //
  438. // increment the expression offset to move to next character.
  439. //
  440. ExprOffset += Length;
  441. Length = sizeof(CHAR);
  442. CurrentState = (ULEN)(ExprOffset * 2);
  443. if ( ExprOffset == ExprLen * sizeof(CHAR)) {
  444. CurrentMatches[DestCount++] = MaxState;
  445. break;
  446. }
  447. ExprChar = pszExpression[ ExprOffset/sizeof(CHAR) ];
  448. ASSERT( !fIgnoreCase ||
  449. !((ExprChar >= 'A') && (ExprChar <= 'Z')));
  450. //
  451. // Before we get started, we have to check for something really
  452. // gross. We may be about to exhaust the local space for
  453. // ExpressionMatch[][], so when we have to allocate some
  454. // pool if this is the case. Yuk!
  455. //
  456. if ( DestCount >= BufSize - 2 ) {
  457. if (AuxBuffer == NULL) {
  458. // 2 copies of array each with 2 states for each char
  459. // in the expression. Each state == ULEN.
  460. IF_DEBUG( DIR_LIST) {
  461. DBGPRINTF((DBG_CONTEXT, "IsNInExpr(%s,%s,%d):"
  462. "alloc %d for exprlen=%d\n",
  463. pszExpression, pszName, fIgnoreCase,
  464. (ExprLen + 1) *sizeof(ULEN)*2*2,
  465. ExprLen));
  466. }
  467. BufSize = (ExprLen+1)*2;
  468. AuxBuffer = ((ULEN *)
  469. ALLOC(BufSize * sizeof(ULEN) * 2)
  470. );
  471. if ( AuxBuffer == NULL) {
  472. DBG_ASSERT(!"Failure in mem alloc");
  473. return ( FALSE);
  474. }
  475. RtlCopyMemory( AuxBuffer, CurrentMatches,
  476. MAX_MATCHES_ARRAY_SIZE*sizeof(ULEN));
  477. CurrentMatches = AuxBuffer;
  478. RtlCopyMemory( AuxBuffer + BufSize,
  479. PreviousMatches,
  480. MAX_MATCHES_ARRAY_SIZE * sizeof(ULEN));
  481. PreviousMatches = AuxBuffer + BufSize;
  482. } else {
  483. DBG_ASSERT(!"Double Overflow occured\n");
  484. FREE( AuxBuffer );
  485. return FALSE;
  486. }
  487. }
  488. //
  489. // '*' Matches any character zero or more times
  490. //
  491. if ( ExprChar == '*') {
  492. // Add all possible next states into the list
  493. // use the above state diagram to identify this.
  494. CurrentMatches[DestCount] = CurrentState;
  495. CurrentMatches[DestCount+1] = CurrentState + 1;
  496. DestCount+= 2;
  497. continue;
  498. }
  499. //
  500. // ANSI_DOS_STAR matches any char, zero or more times,
  501. // except the DOS's extension '.'
  502. //
  503. if ( ExprChar == ANSI_DOS_STAR) {
  504. BOOL ICanEatADot = FALSE;
  505. //
  506. // If we are at a period, determine if we are
  507. // allowed to consume it. i.e make it is not last one.
  508. //
  509. if ( !NameFinished && (NameChar == '.')) {
  510. ULEN cchOffset; // in character counts
  511. for( cchOffset = NameOffset/sizeof(CHAR);
  512. cchOffset < NameLen;
  513. cchOffset ++) {
  514. if ( pszName[cchOffset] == '.') {
  515. ICanEatADot = TRUE;
  516. break;
  517. }
  518. } // for
  519. }
  520. if ( NameFinished || (NameChar != '.') || ICanEatADot) {
  521. //
  522. // Go ahead and consume this character.
  523. // Gives two options to move forward.
  524. //
  525. CurrentMatches[DestCount] = CurrentState;
  526. CurrentMatches[DestCount+1] = CurrentState+1;
  527. DestCount += 2;
  528. continue;
  529. } else {
  530. //
  531. // We are at the period. We can only match zero
  532. // or more characters (ie. the epsilon transition)
  533. //
  534. CurrentMatches[DestCount++] = CurrentState+1;
  535. continue;
  536. }
  537. } // if ( ExprChar == DOS_STAR)
  538. //
  539. // The following expression characters all match by consuming
  540. // a character, thus force the expression, and thus state
  541. // move forward.
  542. //
  543. CurrentState += (ULEN)(sizeof(CHAR) *2);
  544. //
  545. // DOS_QM is the most complicated. If the name is finished,
  546. // we can match zero characters. If this name is a '.', we
  547. // don't match, but look at the next expression. Otherwise
  548. // we match a single character.
  549. //
  550. if ( ExprChar == ANSI_DOS_QM ) {
  551. if ( NameFinished || (NameChar == '.') ) {
  552. continue;
  553. }
  554. CurrentMatches[DestCount++] = CurrentState;
  555. break;
  556. }
  557. //
  558. // DOS_DOT can match either a period, or zero characters
  559. // beyond the end of the name
  560. //
  561. if ( ExprChar == ANSI_DOS_DOT) {
  562. if ( NameFinished) {
  563. continue;
  564. }
  565. if ( NameChar == '.') {
  566. CurrentMatches[DestCount++] = CurrentState;
  567. break;
  568. }
  569. }
  570. //
  571. // From this point on a name character is required to
  572. // even continue searching, let alone make a match.
  573. // So if Name is finished, stop.
  574. //
  575. if ( NameFinished) {
  576. break;
  577. }
  578. //
  579. // If the expression was a '?' we can match it once
  580. //
  581. if ( ExprChar == '?') {
  582. CurrentMatches[DestCount++] = CurrentState;
  583. break;
  584. }
  585. //
  586. // Finally, check if the expression char matches name char
  587. //
  588. if ( ExprChar == (CHAR ) (fIgnoreCase ?
  589. tolower(NameChar) : NameChar)
  590. ){
  591. CurrentMatches[DestCount++] = CurrentState;
  592. break;
  593. }
  594. //
  595. // The expression did not match, go look at the next
  596. // previous match
  597. //
  598. break;
  599. } // for matching from an old state.
  600. //
  601. // Prevent duplication in the destination array.
  602. //
  603. // Each of the arrays is montonically increasing and non-
  604. // duplicating, thus we skip over any source element in the src
  605. // array if we just added the same element to the destination
  606. // array. This guarentees non-duplication in the dest. array.
  607. //
  608. while ( SrcCount < MatchesCount &&
  609. PreviousDestCount < DestCount) {
  610. //
  611. // logic here is: by eliminating the states with
  612. // lesser number than current matched ==> we are
  613. // skipping over the smallest states from which
  614. // no match may be found.
  615. //
  616. if ( PreviousMatches[SrcCount] <
  617. CurrentMatches[PreviousDestCount] ) {
  618. SrcCount ++;
  619. }
  620. PreviousDestCount += 1;
  621. } // while
  622. } // for each of old matches....
  623. //
  624. // If we found no matches in the just finished iteration, it's time
  625. // to bail.
  626. //
  627. if ( DestCount == 0 ) {
  628. if (AuxBuffer != NULL) {
  629. IF_DEBUG( DIR_LIST) {
  630. DBGPRINTF((DBG_CONTEXT, " Freeing %08p\n", AuxBuffer));
  631. }
  632. FREE( AuxBuffer );
  633. }
  634. return FALSE;
  635. }
  636. //
  637. // Swap the meaning the two arrays
  638. //
  639. {
  640. ULEN *Tmp;
  641. Tmp = PreviousMatches;
  642. PreviousMatches = CurrentMatches;
  643. CurrentMatches = Tmp;
  644. }
  645. MatchesCount = DestCount;
  646. } // for each char in Name, until name is finished.
  647. DBG_ASSERT(MatchesCount > 0);
  648. CurrentState = PreviousMatches[MatchesCount-1];
  649. if (AuxBuffer != NULL) {
  650. IF_DEBUG( DIR_LIST) {
  651. DBGPRINTF((DBG_CONTEXT, " Freeing %08p\n", AuxBuffer));
  652. }
  653. FREE( AuxBuffer );
  654. }
  655. return (BOOL ) ( CurrentState == MaxState);
  656. } // IsNameInRegExpressionA()
  657. /************************ End of File ***********************/