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.

1853 lines
40 KiB

  1. #include "precomp.h"
  2. #pragma hdrstop
  3. /* File: search.c */
  4. /**************************************************************************/
  5. /* file search functions
  6. /**************************************************************************/
  7. extern PSTR LOCAL_SOURCE_DIRECTORY;
  8. //*******************************************************************
  9. //
  10. // Exe Info
  11. //
  12. //*******************************************************************
  13. typedef enum _EXETYPE {
  14. EXE_WIN16,
  15. EXE_WIN32,
  16. EXE_DOS,
  17. EXE_DUNNO
  18. } EXETYPE;
  19. #define EXE_WIN16_SZ "WIN16"
  20. #define EXE_WIN32_SZ "WIN32"
  21. #define EXE_DOS_SZ "DOS"
  22. #define EXE_DUNNO_SZ NULL
  23. typedef struct _EXEINFO *PEXEINFO;
  24. typedef struct _EXEINFO {
  25. EXETYPE ExeType;
  26. SZ szExeType;
  27. SZ szDescr;
  28. } EXEINFO;
  29. PEXEINFO
  30. ExeInfoAlloc(
  31. SZ szPath,
  32. SZ szFile
  33. );
  34. BOOL
  35. FExeInfoInit(
  36. PEXEINFO pExeInfo,
  37. SZ szPath,
  38. SZ szFile
  39. );
  40. BOOL
  41. FIsExeOrCom(
  42. SZ szFile
  43. );
  44. BOOL
  45. FIsCom(
  46. SZ szFile
  47. );
  48. BOOL
  49. FIsWin16(
  50. HANDLE Handle,
  51. PIMAGE_DOS_HEADER pDosHeader,
  52. PIMAGE_OS2_HEADER pOs2Header
  53. );
  54. BOOL
  55. FFapi(
  56. HANDLE Handle,
  57. PIMAGE_OS2_HEADER pOs2Header,
  58. DWORD dwOffset
  59. );
  60. SZ
  61. GetBaseName(
  62. SZ szFile
  63. );
  64. SZ
  65. ReadWin16Descr(
  66. SZ szFile,
  67. HANDLE Handle,
  68. PIMAGE_DOS_HEADER pDosHeader,
  69. PIMAGE_OS2_HEADER pOs2Header
  70. );
  71. SZ
  72. ReadWin32Descr(
  73. SZ szFile,
  74. HANDLE Handle,
  75. PIMAGE_DOS_HEADER pDosHeader,
  76. PIMAGE_NT_HEADERS pNtHeader
  77. );
  78. SZ
  79. ReadDescr(
  80. HANDLE Handle,
  81. DWORD Offset,
  82. DWORD Size
  83. );
  84. VOID
  85. ExeInfoFree(
  86. PEXEINFO pInfo
  87. );
  88. #define ExeInfoGetType(p) ((p)->ExeType)
  89. #define ExeInfoGetTypeSz(p) ((p)->szExeType)
  90. #define ExeInfoGetDescr(p) ((p)->szDescr)
  91. //
  92. // Allocates an ExeInfo
  93. //
  94. PEXEINFO
  95. ExeInfoAlloc(
  96. SZ szPath,
  97. SZ szFile
  98. )
  99. {
  100. PEXEINFO pExeInfo;
  101. if (pExeInfo = (PEXEINFO)SAlloc( sizeof(EXEINFO) )) {
  102. if ( !FExeInfoInit( pExeInfo, szPath, szFile ) ) {
  103. ExeInfoFree( pExeInfo );
  104. pExeInfo = NULL;
  105. }
  106. }
  107. return pExeInfo;
  108. }
  109. //
  110. // Initialize an ExeInfo
  111. //
  112. BOOL
  113. FExeInfoInit(
  114. PEXEINFO pExeInfo,
  115. SZ szPath,
  116. SZ szFile
  117. )
  118. {
  119. HANDLE Handle;
  120. BOOL fOkay = fFalse;
  121. IMAGE_DOS_HEADER DosHeader;
  122. IMAGE_OS2_HEADER Os2Header;
  123. IMAGE_NT_HEADERS NtHeader;
  124. DWORD BytesRead;
  125. if ( !FIsExeOrCom(szFile) ) {
  126. pExeInfo->ExeType = EXE_DOS;
  127. pExeInfo->szExeType = EXE_DOS_SZ;
  128. pExeInfo->szDescr = GetBaseName( szFile );
  129. return fTrue;
  130. }
  131. //
  132. // Initialize the pExeInfo so that it can be Freed up if something
  133. // wrong happens.
  134. //
  135. pExeInfo->szDescr = NULL;
  136. //
  137. // Open file
  138. //
  139. Handle = CreateFile( szPath,
  140. GENERIC_READ,
  141. FILE_SHARE_READ | FILE_SHARE_WRITE,
  142. NULL,
  143. OPEN_EXISTING,
  144. 0,
  145. NULL );
  146. if ( Handle != INVALID_HANDLE_VALUE ) {
  147. //
  148. // Read DOS header
  149. //
  150. if ( ReadFile( Handle, &DosHeader, sizeof(IMAGE_DOS_HEADER), &BytesRead, NULL ) &&
  151. (BytesRead == sizeof(IMAGE_DOS_HEADER)) &&
  152. (DosHeader.e_magic == IMAGE_DOS_SIGNATURE) ) {
  153. //
  154. // Read OS/2 header
  155. //
  156. if ( (SetFilePointer( Handle, DosHeader.e_lfanew, 0, FILE_BEGIN ) != -1) &&
  157. ReadFile( Handle, &Os2Header, sizeof(IMAGE_OS2_HEADER), &BytesRead, NULL ) &&
  158. (BytesRead == sizeof(IMAGE_OS2_HEADER)) &&
  159. FIsWin16( Handle, &DosHeader, &Os2Header )
  160. ) {
  161. //
  162. // WIN16 EXE
  163. //
  164. pExeInfo->ExeType = EXE_WIN16;
  165. pExeInfo->szExeType = EXE_WIN16_SZ;
  166. pExeInfo->szDescr = ReadWin16Descr( szFile, Handle, &DosHeader, &Os2Header );
  167. fOkay = fTrue;
  168. } else if ( (SetFilePointer( Handle, DosHeader.e_lfanew, 0, FILE_BEGIN ) != -1) &&
  169. ReadFile( Handle, &NtHeader, sizeof(IMAGE_NT_HEADERS), &BytesRead, NULL ) &&
  170. (BytesRead == sizeof(IMAGE_NT_HEADERS)) &&
  171. (NtHeader.Signature == IMAGE_NT_SIGNATURE) ) {
  172. //
  173. // Make sure that it is a WIN32 subsystem exe
  174. //
  175. if ( (NtHeader.FileHeader.SizeOfOptionalHeader >= IMAGE_SIZEOF_NT_OPTIONAL_HEADER) &&
  176. ((NtHeader.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_GUI) ||
  177. (NtHeader.OptionalHeader.Subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI)) ) {
  178. //
  179. // WIN32
  180. //
  181. pExeInfo->ExeType = EXE_WIN32;
  182. pExeInfo->szExeType = EXE_WIN32_SZ;
  183. // pExeInfo->szDescr = ReadWin32Descr( szFile, Handle, &DosHeader, &NtHeader );
  184. pExeInfo->szDescr = GetBaseName( szFile );
  185. fOkay = fTrue;
  186. }
  187. } else {
  188. //
  189. // Assume DOS
  190. //
  191. pExeInfo->ExeType = EXE_DOS;
  192. pExeInfo->szExeType = EXE_DOS_SZ;
  193. pExeInfo->szDescr = GetBaseName( szFile );
  194. fOkay = fTrue;
  195. }
  196. } else {
  197. //
  198. // Might be a DOS .com file, which wouldn't have an exe header on it.
  199. //
  200. if ( FIsCom(szFile) ) {
  201. pExeInfo->ExeType = EXE_DOS;
  202. pExeInfo->szExeType = EXE_DOS_SZ;
  203. pExeInfo->szDescr = GetBaseName( szFile );
  204. fOkay = fTrue;
  205. }
  206. }
  207. CloseHandle( Handle );
  208. if ( !fOkay ) {
  209. pExeInfo->ExeType = EXE_DUNNO;
  210. pExeInfo->szExeType = EXE_DUNNO_SZ;
  211. pExeInfo->szDescr = NULL;
  212. fOkay = fTrue;
  213. }
  214. }
  215. return fOkay;
  216. }
  217. //
  218. // Determines if the file is a Win16 app
  219. //
  220. BOOL
  221. FIsWin16(
  222. HANDLE Handle,
  223. PIMAGE_DOS_HEADER pDosHeader,
  224. PIMAGE_OS2_HEADER pOs2Header
  225. )
  226. {
  227. #define NE_TYPE(ne) (((BYTE *)(ne))[0x36])
  228. BOOL fW16 = fFalse;
  229. if ( pOs2Header->ne_magic == IMAGE_OS2_SIGNATURE ) {
  230. switch ( NE_TYPE( pOs2Header ) ) {
  231. case 0: // Unknown EXE type, may be a windows exe
  232. //
  233. // Assume this file is a Windows App iff:
  234. // it has a "expected windows version" value or
  235. // it test's FALSE as a FAPI app
  236. //
  237. if (pOs2Header->ne_expver != 0) {
  238. fW16 = fTrue;
  239. } else {
  240. fW16 = !FFapi( Handle, pOs2Header, pDosHeader->e_lfanew );
  241. }
  242. break;
  243. case 2: // Windows EXE type
  244. fW16 = fTrue;
  245. break;
  246. default: // Definitly NOT a windows EXE (DOS4 or OS/2)
  247. break;
  248. }
  249. }
  250. return fW16;
  251. }
  252. //
  253. // Determine if the app is FAPI
  254. //
  255. BOOL
  256. FFapi(
  257. HANDLE Handle,
  258. PIMAGE_OS2_HEADER pOs2Header,
  259. DWORD dwOffset
  260. )
  261. {
  262. #define szDOSCALLS "DOSCALLS"
  263. #define lenDOSCALLS 8
  264. char buf[256];
  265. char *pch;
  266. WORD UNALIGNED *pw;
  267. int n;
  268. int i;
  269. BOOL f = FALSE;
  270. DWORD BytesRead;
  271. /*
  272. * look through the imported module table for the name "DOSCALLS" if
  273. * found the EXE is a FAPI app.
  274. *
  275. * NOTE! assumes module table will fit in a 256 byte buffer
  276. */
  277. // make sure this doesn't point off the end of the buffer we will use
  278. if (pOs2Header->ne_modtab > sizeof(buf)) {
  279. return fFalse;
  280. }
  281. SetFilePointer( Handle, dwOffset, 0, FILE_BEGIN );
  282. ReadFile( Handle, buf, sizeof(buf), &BytesRead, NULL );
  283. pw = (WORD UNALIGNED *)(buf + pOs2Header->ne_modtab);
  284. for (i = 0; (unsigned)i < pOs2Header->ne_cmod; i++)
  285. {
  286. pch = buf + pOs2Header->ne_imptab + *pw++;
  287. if (pch > (buf + sizeof(buf))) // be sure we don't go off the end
  288. break;
  289. n = (int)*pch++;
  290. if (n == 0)
  291. break;
  292. if ( (n == lenDOSCALLS) && !_strnicmp(szDOSCALLS,pch,lenDOSCALLS) )
  293. {
  294. f = TRUE;
  295. break;
  296. }
  297. }
  298. return f;
  299. }
  300. //
  301. // Obtains the base portion of a file name (i.e. no extension)
  302. //
  303. SZ
  304. GetBaseName(
  305. SZ szFile
  306. )
  307. {
  308. SZ szEnd;
  309. SZ szLast;
  310. SZ sz;
  311. CB cbSize;
  312. szEnd = szLast = szFile + strlen( szFile ) - 1;
  313. //
  314. // Look for last '.'
  315. //
  316. while ( (szEnd >= szFile) && (*szEnd != '.')) {
  317. szEnd--;
  318. }
  319. if ( szEnd < szFile ) {
  320. cbSize = (CB)(szLast - szFile);
  321. } else {
  322. cbSize = (CB)(szEnd - szFile);
  323. }
  324. if (sz = (SZ)SAlloc( cbSize+1 )) {
  325. memcpy( sz, szFile, cbSize );
  326. sz[cbSize] = '\0';
  327. }
  328. return sz;
  329. }
  330. //
  331. // Determines if a filename is COM
  332. //
  333. BOOL
  334. FIsCom(
  335. SZ szFile
  336. )
  337. {
  338. SZ szEnd;
  339. szEnd = szFile + strlen( szFile ) - 1;
  340. //
  341. // Look for last '.'
  342. //
  343. while ( (szEnd >= szFile) && (*szEnd != '.')) {
  344. szEnd--;
  345. }
  346. if ( szEnd >= szFile ) {
  347. return (BOOL)( (CrcStringCompare( szEnd, ".COM" ) == crcEqual) );
  348. }
  349. return fFalse;
  350. }
  351. //
  352. // Determines if a filename is EXE or COM
  353. //
  354. BOOL
  355. FIsExeOrCom(
  356. SZ szFile
  357. )
  358. {
  359. SZ szEnd;
  360. szEnd = szFile + strlen( szFile ) - 1;
  361. //
  362. // Look for last '.'
  363. //
  364. while ( (szEnd >= szFile) && (*szEnd != '.')) {
  365. szEnd--;
  366. }
  367. if ( szEnd >= szFile ) {
  368. return (BOOL)( (CrcStringCompare( szEnd, ".EXE" ) == crcEqual) ||
  369. (CrcStringCompare( szEnd, ".COM" ) == crcEqual) );
  370. }
  371. return fFalse;
  372. }
  373. //
  374. // Gets a Win16 Description
  375. //
  376. SZ
  377. ReadWin16Descr(
  378. SZ szFile,
  379. HANDLE Handle,
  380. PIMAGE_DOS_HEADER pDosHeader,
  381. PIMAGE_OS2_HEADER pOs2Header
  382. )
  383. {
  384. DWORD DescrOff;
  385. BYTE DescrSize;
  386. SZ szDescr = NULL;
  387. DWORD BytesRead;
  388. UNREFERENCED_PARAMETER( pDosHeader );
  389. //
  390. // Try to get description (first entry in nonresident table).
  391. //
  392. DescrOff = pOs2Header->ne_nrestab;
  393. if ( !(SetFilePointer( Handle, DescrOff, 0, FILE_BEGIN) != -1) ||
  394. !ReadFile( Handle, &DescrSize, sizeof(BYTE), &BytesRead, NULL ) ||
  395. !(BytesRead == sizeof(BYTE)) ||
  396. !(szDescr = ReadDescr( Handle, DescrOff+1, (DWORD)DescrSize ))
  397. ) {
  398. //
  399. // Could not get description, try to get module name
  400. // (first entry in resident table).
  401. //
  402. DescrOff = pOs2Header->ne_restab;
  403. if ( !(SetFilePointer( Handle, DescrOff, 0, FILE_BEGIN) != -1) ||
  404. !ReadFile( Handle, &DescrSize, sizeof(BYTE), &BytesRead, NULL ) ||
  405. !(BytesRead == sizeof(BYTE)) ||
  406. !(szDescr = ReadDescr( Handle, DescrOff+1, (DWORD)DescrSize ))
  407. ) {
  408. //
  409. // Could not get module name, use file base name.
  410. //
  411. szDescr = GetBaseName( szFile );
  412. }
  413. }
  414. return szDescr;
  415. }
  416. #if 0
  417. //
  418. // Get Win32 Description
  419. //
  420. SZ
  421. ReadWin32Descr(
  422. SZ szFile,
  423. HANDLE Handle,
  424. PIMAGE_DOS_HEADER pDosHeader,
  425. PIMAGE_NT_HEADERS pNtHeader
  426. )
  427. {
  428. DWORD DescrOff;
  429. DWORD DescrSize;
  430. SZ szDescr = NULL;
  431. UNREFERENCED_PARAMETER( pDosHeader );
  432. //
  433. // Try to get the description
  434. //
  435. DescrOff = pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT].VirtualAddress;
  436. DescrSize = pNtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COPYRIGHT].Size;
  437. if ( !(szDescr = ReadDescr( Handle, DescrOff, DescrSize ) ) ) {
  438. //
  439. // Could not get description, try to get module name.
  440. //
  441. // BUGBUG: Where do we find the module name?
  442. //
  443. //
  444. // Could not get module name, use file base name.
  445. //
  446. szDescr = GetBaseName( szFile );
  447. }
  448. return szDescr;
  449. }
  450. #endif
  451. //
  452. // Reads a module description
  453. //
  454. SZ
  455. ReadDescr(
  456. HANDLE Handle,
  457. DWORD Offset,
  458. DWORD Size
  459. )
  460. {
  461. SZ szDescr = NULL;
  462. DWORD BytesRead;
  463. size_t SizeUsed;
  464. SZ sz;
  465. if ( Size > 0 ) {
  466. if (szDescr = (SZ)SAlloc( Size+1 )) {
  467. //
  468. // Read description
  469. //
  470. if ( (SetFilePointer( Handle, Offset, 0, FILE_BEGIN) != -1) &&
  471. ReadFile( Handle, szDescr, Size, &BytesRead, NULL) &&
  472. (BytesRead == Size) ) {
  473. //
  474. // Get rid of padding blanks
  475. //
  476. sz = szDescr+Size-1;
  477. while ( (sz >= szDescr) &&
  478. ( (*sz == ' ') || (*sz == '\t') ) ) {
  479. sz--;
  480. }
  481. sz++;
  482. sz = '\0';
  483. SizeUsed = (size_t)(sz-szDescr);
  484. //
  485. // If description has quotes or commas, or if it is longer
  486. // than 26 characters, we don't want it.
  487. //
  488. if ( (SizeUsed > 25) ||
  489. (strcspn( szDescr, """," ) >= SizeUsed)
  490. ) {
  491. SFree(szDescr);
  492. szDescr = NULL;
  493. } else {
  494. if ( (SizeUsed < Size) &&
  495. (szDescr = SRealloc( szDescr, SizeUsed))) {
  496. *(szDescr+SizeUsed) = '\0';
  497. }
  498. }
  499. } else {
  500. SFree(szDescr);
  501. szDescr = NULL;
  502. }
  503. }
  504. }
  505. return szDescr;
  506. }
  507. //
  508. // Frees an Exe info
  509. //
  510. VOID
  511. ExeInfoFree(
  512. PEXEINFO pInfo
  513. )
  514. {
  515. if ( pInfo->szDescr ) {
  516. SFree(pInfo->szDescr);
  517. }
  518. SFree(pInfo);
  519. }
  520. //*******************************************************************
  521. //
  522. // File List
  523. //
  524. //*******************************************************************
  525. typedef struct _FILELIST *PFILELIST;
  526. typedef struct _FILELIST {
  527. SYMTAB SymTab;
  528. } FILELIST;
  529. PFILELIST
  530. FileListAlloc(
  531. SZ szFiles
  532. );
  533. BOOL
  534. FFileListInit(
  535. PFILELIST pFileList
  536. );
  537. VOID
  538. FileListFree(
  539. PFILELIST pFileList
  540. );
  541. VOID
  542. FileListDealloc(
  543. PFILELIST pFileList
  544. );
  545. BOOL
  546. FFileInFileList(
  547. SZ szFileName,
  548. PFILELIST pFileList
  549. );
  550. BOOL
  551. FFileListAdd(
  552. SZ szFileName,
  553. PFILELIST pFileList
  554. );
  555. //
  556. // Allocates a file list
  557. //
  558. PFILELIST
  559. FileListAlloc(
  560. SZ szFiles
  561. )
  562. {
  563. BOOL fOkay = fFalse;
  564. RGSZ rgszFile;
  565. PFILELIST pFileList = NULL;
  566. INT iFile;
  567. if (rgszFile = RgszFromSzListValue( szFiles )) {
  568. if (pFileList = (PFILELIST)SAlloc( sizeof(FILELIST) )) {
  569. FFileListInit( pFileList );
  570. fOkay = fTrue;
  571. if ( rgszFile[0] ) {
  572. //
  573. // Add files to FileList.
  574. //
  575. for ( iFile = 0; fOkay && rgszFile[iFile]; iFile++ ) {
  576. if ( !(fOkay = FFileListAdd( rgszFile[iFile], pFileList ))) {
  577. FileListFree( pFileList );
  578. pFileList = NULL;
  579. }
  580. }
  581. }
  582. }
  583. FFreeRgsz( rgszFile );
  584. }
  585. return pFileList;
  586. }
  587. //
  588. // Initializes a File list
  589. //
  590. BOOL
  591. FFileListInit(
  592. PFILELIST pFileList
  593. )
  594. {
  595. USHORT iHashBucket;
  596. for (iHashBucket = 0; iHashBucket < cHashBuckets; iHashBucket++) {
  597. pFileList->SymTab.HashBucket[iHashBucket] = NULL;
  598. }
  599. return fTrue;
  600. }
  601. //
  602. // Frees a file list
  603. //
  604. VOID
  605. FileListFree(
  606. PFILELIST pFileList
  607. )
  608. {
  609. FileListDealloc( pFileList );
  610. SFree(pFileList);
  611. }
  612. //
  613. // Deallocates a file list
  614. //
  615. VOID
  616. FileListDealloc (
  617. PFILELIST pFileList
  618. )
  619. {
  620. USHORT iHashBucket;
  621. for (iHashBucket = 0; iHashBucket < cHashBuckets; iHashBucket++) {
  622. PSTE pste = pFileList->SymTab.HashBucket[iHashBucket];
  623. while (pste != (PSTE)NULL) {
  624. PSTE psteSav = pste->psteNext;
  625. FFreePste(pste);
  626. pste = psteSav;
  627. }
  628. }
  629. }
  630. //
  631. // Finds a file in a file list
  632. //
  633. BOOL
  634. FFileInFileList(
  635. SZ szFileName,
  636. PFILELIST pFileList
  637. )
  638. {
  639. PPSTE ppste;
  640. PSYMTAB pSymTab = &(pFileList->SymTab);
  641. if ( szFileName && (szFileName[0] != '\0') ) {
  642. ppste = PpsteFindSymbol( pSymTab, szFileName );
  643. AssertRet(ppste != (PPSTE)NULL, fFalse);
  644. if (*ppste == (PSTE)NULL) {
  645. return fFalse;
  646. }
  647. AssertRet( (*ppste)->szSymbol != (SZ)NULL &&
  648. *((*ppste)->szSymbol) != '\0' &&
  649. (*ppste)->szValue != (SZ)NULL, fFalse);
  650. if (CrcStringCompare(szFileName, (*ppste)->szSymbol) != crcEqual) {
  651. return fFalse;
  652. }
  653. return fTrue;
  654. }
  655. return fFalse;
  656. }
  657. //
  658. // Adds a file to the file list
  659. //
  660. BOOL
  661. FFileListAdd(
  662. SZ szFileData,
  663. PFILELIST pFileList
  664. )
  665. {
  666. BOOL fOkay = fFalse;
  667. PPSTE ppste;
  668. SZ szFile;
  669. SZ szValue;
  670. PSYMTAB pSymTab = &(pFileList->SymTab);
  671. if ( szFileData ) {
  672. if ( (szFile = SzDupl(szFileData)) != NULL ) {
  673. SzStrUpper( szFile );
  674. if ( (szValue = SzDupl("")) != NULL ) {
  675. fOkay = fTrue;
  676. } else {
  677. SFree(szFile);
  678. }
  679. }
  680. }
  681. if ( fOkay ) {
  682. ppste = PpsteFindSymbol( pSymTab, szFile );
  683. if ( *ppste != NULL &&
  684. CrcStringCompare( (*ppste)->szSymbol, szFile) == crcEqual) {
  685. if ((*ppste)->szValue == NULL) {
  686. SFree(szFile);
  687. SFree(szValue);
  688. fOkay = fFalse;
  689. goto AddExit;
  690. }
  691. SFree((*ppste)->szValue);
  692. SFree(szFile);
  693. (*ppste)->szValue = NULL;
  694. } else {
  695. PSTE pste;
  696. if ( (pste = PsteAlloc()) == NULL ) {
  697. SFree(szFile);
  698. SFree(szValue);
  699. fOkay = fFalse;
  700. goto AddExit;
  701. }
  702. pste->szSymbol = szFile;
  703. #ifdef SYMTAB_STATS
  704. pSymTab->BucketCount[UsHashFunction(szFile)]++;
  705. #endif
  706. pste->szValue = NULL;
  707. pste->psteNext = *ppste;
  708. *ppste = pste;
  709. }
  710. (*ppste)->szValue = szValue;
  711. }
  712. AddExit:
  713. return fOkay;
  714. }
  715. //*******************************************************************
  716. //
  717. // Search List
  718. //
  719. //*******************************************************************
  720. typedef struct _SEARCHLIST *PSEARCHLIST;
  721. typedef struct _SEARCHLIST {
  722. DWORD dwPatterns;
  723. RGSZ rgszPattern;
  724. FILELIST FileList;
  725. } SEARCHLIST;
  726. PSEARCHLIST
  727. SearchListAlloc(
  728. SZ szFiles
  729. );
  730. VOID
  731. SearchListFree(
  732. PSEARCHLIST pList
  733. );
  734. BOOL
  735. FSearchListAddPattern(
  736. SZ szPattern,
  737. PSEARCHLIST pSearchList
  738. );
  739. BOOL
  740. FFileInSearchList(
  741. SZ szFileName,
  742. PSEARCHLIST pSearchList
  743. );
  744. BOOL
  745. FHasWildCard(
  746. SZ szFile
  747. );
  748. BOOL
  749. FPatternMatch(
  750. SZ szFile,
  751. SZ szPattern
  752. );
  753. //
  754. // Allocates a search list
  755. //
  756. PSEARCHLIST
  757. SearchListAlloc(
  758. SZ szFiles
  759. )
  760. {
  761. BOOL fOkay = fTrue;
  762. RGSZ rgszFile;
  763. PSEARCHLIST pSearchList = NULL;
  764. INT iFile;
  765. if (rgszFile = RgszFromSzListValue( szFiles )) {
  766. if ( rgszFile[0] != NULL ) {
  767. if (pSearchList = (PSEARCHLIST)SAlloc( sizeof(SEARCHLIST) )) {
  768. FFileListInit( &(pSearchList->FileList) );
  769. if ( pSearchList->rgszPattern = (RGSZ)SAlloc( sizeof(SZ) ) ) {
  770. pSearchList->rgszPattern[0] = NULL;
  771. pSearchList->dwPatterns = 0;
  772. //
  773. // Add files to FileList.
  774. //
  775. for ( iFile = 0; fOkay && rgszFile[iFile]; iFile++ ) {
  776. //
  777. // If the file has wildcards, add it to the pattern list,
  778. // otherwise add it to the file list
  779. //
  780. if ( FHasWildCard( rgszFile[iFile] ) ) {
  781. fOkay = FSearchListAddPattern( rgszFile[iFile], pSearchList );
  782. } else {
  783. fOkay = FFileListAdd( rgszFile[iFile], &(pSearchList->FileList) );
  784. }
  785. if (!fOkay) {
  786. SearchListFree( pSearchList );
  787. pSearchList = NULL;
  788. }
  789. }
  790. } else {
  791. SFree(pSearchList);
  792. pSearchList = NULL;
  793. }
  794. }
  795. }
  796. FFreeRgsz( rgszFile );
  797. }
  798. return pSearchList;
  799. }
  800. //
  801. // Frees a search list
  802. //
  803. VOID
  804. SearchListFree(
  805. PSEARCHLIST pSearchList
  806. )
  807. {
  808. FileListDealloc( &(pSearchList->FileList) );
  809. FFreeRgsz( pSearchList->rgszPattern );
  810. SFree(pSearchList);
  811. }
  812. //
  813. // Adds a pattern to the search list
  814. //
  815. BOOL
  816. FSearchListAddPattern(
  817. SZ szPattern,
  818. PSEARCHLIST pSearchList
  819. )
  820. {
  821. SZ sz;
  822. RGSZ rgsz;
  823. BOOL fOkay = fFalse;
  824. if (sz = SzDupl( szPattern )) {
  825. rgsz = (RGSZ)SRealloc( pSearchList->rgszPattern,
  826. ((pSearchList->dwPatterns+2)*sizeof(SZ)));
  827. if ( rgsz ) {
  828. rgsz[pSearchList->dwPatterns] = sz;
  829. rgsz[pSearchList->dwPatterns+1] = NULL;
  830. pSearchList->rgszPattern = rgsz;
  831. pSearchList->dwPatterns++;
  832. fOkay = fTrue;
  833. } else {
  834. SFree(sz);
  835. }
  836. }
  837. return fOkay;
  838. }
  839. //
  840. // Determines if a file name is in the search list
  841. //
  842. BOOL
  843. FFileInSearchList(
  844. SZ szFileName,
  845. PSEARCHLIST pSearchList
  846. )
  847. {
  848. INT i;
  849. if ( FFileInFileList( szFileName, &(pSearchList->FileList) ) ) {
  850. return fTrue;
  851. } else {
  852. for (i=0; pSearchList->rgszPattern[i]; i++ ) {
  853. if ( FPatternMatch( szFileName, pSearchList->rgszPattern[i] ) ) {
  854. return fTrue;
  855. }
  856. }
  857. }
  858. return fFalse;
  859. }
  860. //
  861. // Determines if a file name has a wildcard
  862. //
  863. BOOL
  864. FHasWildCard(
  865. SZ szFile
  866. )
  867. {
  868. return (strcspn( szFile, "*?" ) < strlen( szFile ) );
  869. }
  870. BOOL
  871. FPatternMatch(
  872. SZ szFile,
  873. SZ szPattern
  874. )
  875. {
  876. switch (*szPattern) {
  877. case '\0':
  878. return ( *szFile == '\0' );
  879. case '?':
  880. return ( *szFile != '\0' && FPatternMatch (szPattern + 1, szFile + 1) );
  881. case '*':
  882. do {
  883. if (FPatternMatch (szPattern + 1, szFile))
  884. return fTrue;
  885. } while (*szFile++);
  886. return fFalse;
  887. default:
  888. return ( toupper (*szFile) == toupper (*szPattern) && FPatternMatch (szPattern + 1, szFile + 1) );
  889. }
  890. }
  891. //*******************************************************************
  892. //
  893. // Found List
  894. //
  895. //*******************************************************************
  896. #define FOUNDLIST_INCR 32
  897. typedef struct _FOUNDLIST *PFOUNDLIST;
  898. typedef struct _FOUNDLIST {
  899. DWORD Index;
  900. DWORD Size;
  901. RGSZ rgszList;
  902. } FOUNDLIST;
  903. PFOUNDLIST
  904. FoundListAlloc(
  905. );
  906. VOID
  907. FoundListFree(
  908. PFOUNDLIST pList
  909. );
  910. BOOL
  911. FoundListAdd(
  912. SZ szFile,
  913. SZ szDirectory,
  914. PEXEINFO pExeInfo,
  915. PFOUNDLIST pFoundList
  916. );
  917. SZ
  918. SzFromFoundList(
  919. PFOUNDLIST pFoundList
  920. );
  921. //
  922. // Initialize a Found List
  923. //
  924. PFOUNDLIST
  925. FoundListAlloc(
  926. )
  927. {
  928. PFOUNDLIST pFoundList;
  929. if ( (pFoundList = (PFOUNDLIST)SAlloc( sizeof(FOUNDLIST) )) != NULL ) {
  930. if ( (pFoundList->rgszList = (RGSZ)SAlloc( FOUNDLIST_INCR * sizeof(SZ) )) != NULL ) {
  931. pFoundList->Index = 0;
  932. pFoundList->Size = FOUNDLIST_INCR;
  933. pFoundList->rgszList[0] = NULL;
  934. } else {
  935. SFree(pFoundList);
  936. pFoundList = (PFOUNDLIST)NULL;
  937. }
  938. }
  939. return pFoundList;
  940. }
  941. //
  942. // Free a found list
  943. //
  944. VOID
  945. FoundListFree(
  946. PFOUNDLIST pFoundList
  947. )
  948. {
  949. RGSZ rgszList;
  950. rgszList = (RGSZ)SRealloc( pFoundList->rgszList,
  951. ((pFoundList->Index+1)*sizeof(SZ)));
  952. FFreeRgsz( rgszList );
  953. SFree(pFoundList);
  954. }
  955. //
  956. // Add and entry to the found list
  957. //
  958. BOOL
  959. FoundListAdd (
  960. SZ szFile,
  961. SZ szDirectory,
  962. PEXEINFO pExeInfo,
  963. PFOUNDLIST pFoundList
  964. )
  965. {
  966. BOOL fOkay = fFalse;
  967. RGSZ rgszEntry;
  968. RGSZ rgszList;
  969. SZ szEntry;
  970. if (rgszEntry = (RGSZ)SAlloc( 5 * sizeof(SZ) )) {
  971. rgszEntry[0] = szFile;
  972. rgszEntry[1] = szDirectory;
  973. rgszEntry[2] = ExeInfoGetTypeSz( pExeInfo );
  974. rgszEntry[3] = ExeInfoGetDescr( pExeInfo );
  975. rgszEntry[4] = NULL;
  976. if (szEntry = SzListValueFromRgsz( rgszEntry )) {
  977. if ( pFoundList->Index >= (pFoundList->Size - 1) ) {
  978. rgszList = (RGSZ)SRealloc( pFoundList->rgszList,
  979. ((pFoundList->Size+FOUNDLIST_INCR)*sizeof(SZ)));
  980. if ( rgszList ) {
  981. pFoundList->Size += FOUNDLIST_INCR;
  982. pFoundList->rgszList = rgszList;
  983. fOkay = fTrue;
  984. }
  985. } else {
  986. fOkay = fTrue;
  987. }
  988. if ( fOkay ) {
  989. pFoundList->rgszList[pFoundList->Index++] = szEntry;
  990. pFoundList->rgszList[pFoundList->Index] = NULL;
  991. } else {
  992. SFree(szEntry);
  993. }
  994. }
  995. SFree(rgszEntry);
  996. }
  997. return fOkay;
  998. }
  999. //
  1000. // Get SZ from found list
  1001. //
  1002. SZ
  1003. SzFromFoundList(
  1004. PFOUNDLIST pFoundList
  1005. )
  1006. {
  1007. return SzListValueFromRgsz( pFoundList->rgszList );
  1008. }
  1009. //*******************************************************************
  1010. //
  1011. // Application Search
  1012. //
  1013. //*******************************************************************
  1014. extern HWND hwndFrame;
  1015. CHAR GaugeText1[50];
  1016. CHAR GaugeText2[50];
  1017. CHAR GaugeText3[50];
  1018. WIN32_FIND_DATA FindData;
  1019. #define BARRANGE 30000
  1020. //
  1021. // Local Prototypes
  1022. //
  1023. BOOL APIENTRY FSearchDirectoryList(
  1024. RGSZ rgszDirs,
  1025. BOOL fRecurse,
  1026. BOOL fSilent,
  1027. PSEARCHLIST pSearchList,
  1028. PFILELIST pWin16Restr,
  1029. PFILELIST pWin32Restr,
  1030. PFILELIST pDosRestr,
  1031. PFOUNDLIST pFoundList
  1032. );
  1033. BOOL APIENTRY FSearchDirectory(
  1034. SZ szDirectory,
  1035. BOOL fRecurse,
  1036. BOOL fSilent,
  1037. PSEARCHLIST pSearchList,
  1038. PFILELIST pWin16Restr,
  1039. PFILELIST pWin32Restr,
  1040. PFILELIST pDosRestr,
  1041. PFOUNDLIST pFoundList,
  1042. INT Position,
  1043. INT Range,
  1044. SZ szDisplayBuffer
  1045. );
  1046. //
  1047. // Purpose:
  1048. //
  1049. // Prepares for application search.
  1050. //
  1051. // Arguments:
  1052. //
  1053. // szInfVar - Where to put the result
  1054. // szDirList - List of directories to search
  1055. // fRecurse - Recursive flag
  1056. // fSilent - Silent mode flag
  1057. // szSearchList - List of files to search, can have wildcards
  1058. // szWin16Restr - Win16 restriction list
  1059. // szWin32Restr - Win32 restriction list
  1060. // szDosRestr - Dos restriction list
  1061. //
  1062. // Returns:
  1063. //
  1064. // fTrue if success.
  1065. //
  1066. BOOL APIENTRY FSearchDirList(
  1067. SZ szInfVar,
  1068. SZ szDirList,
  1069. BOOL fRecurse,
  1070. BOOL fSilent,
  1071. SZ szSearchList,
  1072. SZ szWin16Restr,
  1073. SZ szWin32Restr,
  1074. SZ szDosRestr
  1075. )
  1076. {
  1077. BOOL fOkay = fFalse;
  1078. RGSZ rgszDirs;
  1079. PSEARCHLIST pSearchList;
  1080. PFILELIST pWin16Restr;
  1081. PFILELIST pWin32Restr;
  1082. PFILELIST pDosRestr;
  1083. PFOUNDLIST pFoundList;
  1084. SZ szResult;
  1085. SetCursor(CurrentCursor = LoadCursor(NULL,IDC_WAIT));
  1086. fSilent = (fSilent || fSilentSystem);
  1087. if ( rgszDirs = RgszFromSzListValue( szDirList ) ) {
  1088. if ( pSearchList = SearchListAlloc( szSearchList )) {
  1089. if ( pWin16Restr = FileListAlloc( szWin16Restr ) ) {
  1090. if ( pWin32Restr = FileListAlloc( szWin32Restr ) ) {
  1091. if ( pDosRestr = FileListAlloc( szDosRestr ) ) {
  1092. if ( pFoundList = FoundListAlloc() ) {
  1093. SetCursor(CurrentCursor = LoadCursor(NULL,IDC_ARROW));
  1094. fOkay = FSearchDirectoryList( rgszDirs,
  1095. fRecurse,
  1096. fSilent,
  1097. pSearchList,
  1098. pWin16Restr,
  1099. pWin32Restr,
  1100. pDosRestr,
  1101. pFoundList );
  1102. if ( fOkay ) {
  1103. if ( szResult = SzFromFoundList( pFoundList ) ) {
  1104. while (!FAddSymbolValueToSymTab( szInfVar, szResult)) {
  1105. if (!FHandleOOM(hwndFrame)) {
  1106. fOkay = fFalse;
  1107. break;
  1108. }
  1109. }
  1110. SFree(szResult);
  1111. } else {
  1112. fOkay = fFalse;
  1113. }
  1114. }
  1115. FoundListFree( pFoundList );
  1116. }
  1117. FileListFree( pDosRestr );
  1118. }
  1119. FileListFree( pWin32Restr );
  1120. }
  1121. FileListFree( pWin16Restr );
  1122. }
  1123. SearchListFree( pSearchList );
  1124. }
  1125. FFreeRgsz( rgszDirs );
  1126. }
  1127. return fOkay;
  1128. }
  1129. //
  1130. // Purpose:
  1131. //
  1132. // Performs the application search.
  1133. //
  1134. // Arguments:
  1135. //
  1136. // rgszDirs - List of directories to traverse
  1137. // fRecurse - Recursive flag
  1138. // fSilent - Silent mode flag
  1139. // pSearchList - The list of files to search
  1140. // pWin16Restr - List of Win16 restrictions
  1141. // pWin32Restr - List of Win32 restrictions
  1142. // pDosRestr - List of DOS restrictions
  1143. // pFoundList - Found list
  1144. //
  1145. // Returns:
  1146. //
  1147. // fTrue if success.
  1148. //
  1149. BOOL APIENTRY FSearchDirectoryList(
  1150. RGSZ rgszDirs,
  1151. BOOL fRecurse,
  1152. BOOL fSilent,
  1153. PSEARCHLIST pSearchList,
  1154. PFILELIST pWin16Restr,
  1155. PFILELIST pWin32Restr,
  1156. PFILELIST pDosRestr,
  1157. PFOUNDLIST pFoundList
  1158. )
  1159. {
  1160. DWORD iDir;
  1161. DWORD cDirs;
  1162. INT SubRange;
  1163. INT Pos;
  1164. CHAR szDirectory[ cchlFullPathMax ];
  1165. CHAR szDisplayBuffer[cchlFullPathMax ];
  1166. BOOL fOkay = fTrue;
  1167. //
  1168. // Figure out how many directories we have to traverse
  1169. //
  1170. for ( cDirs = 0, iDir = 0; rgszDirs[iDir] != NULL; iDir++ ) {
  1171. if ( *rgszDirs[iDir] != '\0' ) {
  1172. cDirs++;
  1173. }
  1174. }
  1175. //
  1176. // Traverse the directories
  1177. //
  1178. if ( cDirs > 0 ) {
  1179. if (!fSilent) {
  1180. SZ szText;
  1181. ProOpen(hwndFrame, 0);
  1182. ProSetBarRange(BARRANGE);
  1183. ProSetBarPos(0);
  1184. szText = SzFindSymbolValueInSymTab("ProText1");
  1185. if (szText) {
  1186. strcpy(GaugeText1, szText);
  1187. }
  1188. szText = SzFindSymbolValueInSymTab("ProText2");
  1189. if (szText) {
  1190. strcpy(GaugeText2, szText);
  1191. }
  1192. szText = SzFindSymbolValueInSymTab("ProText3");
  1193. if (szText) {
  1194. strcpy(GaugeText3, szText);
  1195. }
  1196. ProSetText(ID_STATUS1, GaugeText1);
  1197. ProSetText(ID_STATUS4, "");
  1198. }
  1199. SubRange = BARRANGE/cDirs;
  1200. Pos = 0;
  1201. //
  1202. // Do one directory at a time
  1203. //
  1204. for ( iDir = 0;
  1205. fOkay && FYield() && !fUserQuit && (iDir < cDirs);
  1206. iDir++ ) {
  1207. SZ szEnd;
  1208. BOOL fRecursive;
  1209. strcpy( szDirectory, rgszDirs[iDir] );
  1210. szEnd = szDirectory + strlen( szDirectory ) - 1;
  1211. if ( ( (szEnd - szDirectory) >= 1) &&
  1212. ( szDirectory[1] == ':' ) &&
  1213. ( szDirectory[2] == '\0' ) ) {
  1214. fRecursive = fTrue;
  1215. } else {
  1216. fRecursive = fRecurse;
  1217. }
  1218. if ( *szEnd == '\\' ) {
  1219. *szEnd = '\0';
  1220. }
  1221. fOkay = FSearchDirectory( szDirectory,
  1222. fRecursive,
  1223. fSilent,
  1224. pSearchList,
  1225. pWin16Restr,
  1226. pWin32Restr,
  1227. pDosRestr,
  1228. pFoundList,
  1229. Pos,
  1230. SubRange,
  1231. szDisplayBuffer );
  1232. Pos += SubRange;
  1233. }
  1234. if (!fSilent) {
  1235. ProSetBarPos(BARRANGE - 1);
  1236. ProClose(hwndFrame);
  1237. }
  1238. }
  1239. return fOkay;
  1240. }
  1241. //
  1242. // Purpose:
  1243. //
  1244. // Performs the application search in one directory
  1245. //
  1246. // Arguments:
  1247. //
  1248. // szDirectory - Directory to traverse
  1249. // fRecurse - Recursive flag
  1250. // fSilent - Silent mode flag
  1251. // pSearchList - The list of files to search
  1252. // pWin16Restr - List of Win16 restrictions
  1253. // pWin32Restr - List of Win32 restrictions
  1254. // pDosRestr - List of DOS restrictions
  1255. // pFoundList - Found list
  1256. // Position - Gauge initial position
  1257. // Range - Gauge range
  1258. // szDisplayBuffer - Tmp buffer.
  1259. //
  1260. // Returns:
  1261. //
  1262. // fTrue if success.
  1263. //
  1264. BOOL APIENTRY FSearchDirectory(
  1265. SZ szDirectory,
  1266. BOOL fRecurse,
  1267. BOOL fSilent,
  1268. PSEARCHLIST pSearchList,
  1269. PFILELIST pWin16Restr,
  1270. PFILELIST pWin32Restr,
  1271. PFILELIST pDosRestr,
  1272. PFOUNDLIST pFoundList,
  1273. INT Position,
  1274. INT Range,
  1275. SZ szDisplayBuffer
  1276. )
  1277. {
  1278. SZ pFileName;
  1279. HANDLE FindHandle;
  1280. BOOL fOkay = fTrue;
  1281. INT cDirectories = 0;
  1282. INT SubRange;
  1283. INT Pos;
  1284. PEXEINFO pExeInfo;
  1285. BOOL fAdd;
  1286. if ( !szDirectory || szDirectory[0] == '\0' || szDirectory[0] == '.') {
  1287. return fFalse;
  1288. }
  1289. //
  1290. // catch local source directory -- don't want to find files in there!
  1291. //
  1292. if(!_strnicmp(szDirectory+2,LOCAL_SOURCE_DIRECTORY,lstrlen(LOCAL_SOURCE_DIRECTORY))) {
  1293. return fTrue;
  1294. }
  1295. if (!fSilent) {
  1296. wsprintf(szDisplayBuffer, "%s%s", GaugeText2, szDirectory );
  1297. ProSetText(ID_STATUS2, szDisplayBuffer);
  1298. }
  1299. pFileName = szDirectory + strlen( szDirectory );
  1300. SzStrCat( szDirectory, "\\*.*" );
  1301. FindHandle = FindFirstFile( szDirectory, &FindData );
  1302. if ( FindHandle != INVALID_HANDLE_VALUE ) {
  1303. //
  1304. // Look at all files under this directory.
  1305. //
  1306. do {
  1307. if ( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  1308. //
  1309. // Increment the count of directories just in case we're interactive
  1310. // and we want to recurse.
  1311. //
  1312. if ( FindData.cFileName[0] != '.' ) {
  1313. cDirectories++;
  1314. }
  1315. } else {
  1316. //
  1317. // If the file is in the search list, determine if we have to add it
  1318. // to the found list and if so add it.
  1319. //
  1320. SzStrUpper( FindData.cFileName );
  1321. if ( FFileInSearchList( FindData.cFileName, pSearchList ) ) {
  1322. *pFileName = '\0';
  1323. SzStrCat( szDirectory, "\\" );
  1324. SzStrCat( szDirectory, FindData.cFileName );
  1325. if ( ((pExeInfo = ExeInfoAlloc( szDirectory, FindData.cFileName )) != NULL) ) {
  1326. switch( ExeInfoGetType( pExeInfo ) ) {
  1327. case EXE_WIN16:
  1328. //
  1329. // We only add if not in Win16Restr
  1330. //
  1331. fAdd = !FFileInFileList( FindData.cFileName, pWin16Restr );
  1332. break;
  1333. case EXE_WIN32:
  1334. //
  1335. // We only add if not in Win32Restr
  1336. //
  1337. fAdd = !FFileInFileList( FindData.cFileName, pWin32Restr );
  1338. break;
  1339. case EXE_DOS:
  1340. //
  1341. // We only add if in DosRestr
  1342. //
  1343. fAdd = FFileInFileList( FindData.cFileName, pDosRestr );
  1344. break;
  1345. default:
  1346. fAdd = fFalse;
  1347. break;
  1348. }
  1349. if ( fAdd ) {
  1350. if (!fSilent) {
  1351. wsprintf(szDisplayBuffer, "%s%s", GaugeText3, FindData.cFileName );
  1352. ProSetText(ID_STATUS3, szDisplayBuffer);
  1353. }
  1354. *pFileName = '\\';
  1355. *(pFileName+1) = '\0';
  1356. fOkay = FoundListAdd( FindData.cFileName, szDirectory, pExeInfo, pFoundList );
  1357. }
  1358. ExeInfoFree( pExeInfo );
  1359. }
  1360. }
  1361. }
  1362. } while ( fOkay && FYield() && !fUserQuit && FindNextFile( FindHandle, &FindData ));
  1363. FindClose( FindHandle );
  1364. //
  1365. // Recurse thru all the subdirectories if the fRecurse flag is set.
  1366. //
  1367. if ( fOkay && fRecurse && !fUserQuit && (cDirectories > 0) ) {
  1368. *pFileName = '\0';
  1369. SzStrCat( szDirectory, "\\*.*" );
  1370. FindHandle = FindFirstFile( szDirectory, &FindData );
  1371. if ( FindHandle != INVALID_HANDLE_VALUE ) {
  1372. SubRange = Range/cDirectories;
  1373. Pos = Position;
  1374. do {
  1375. if ( (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  1376. (FindData.cFileName[0] != '.') ) {
  1377. *pFileName = '\\';
  1378. *(pFileName+1) = '\0';
  1379. SzStrCat( szDirectory, FindData.cFileName );
  1380. fOkay = FSearchDirectory( szDirectory,
  1381. fRecurse,
  1382. fSilent,
  1383. pSearchList,
  1384. pWin16Restr,
  1385. pWin32Restr,
  1386. pDosRestr,
  1387. pFoundList,
  1388. Pos,
  1389. SubRange,
  1390. szDisplayBuffer );
  1391. Pos += SubRange;
  1392. }
  1393. } while ( fOkay && FYield() && !fUserQuit && FindNextFile( FindHandle, &FindData ));
  1394. FindClose( FindHandle );
  1395. }
  1396. }
  1397. }
  1398. if ( !fSilent && (Range > 0) ) {
  1399. ProSetBarPos( Position + Range - 1 );
  1400. }
  1401. //
  1402. // Restore original Directory name.
  1403. //
  1404. *pFileName = '\0';
  1405. return fOkay;
  1406. }