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.

723 lines
17 KiB

  1. /*
  2. * Module Name: WSTCAT.C
  3. *
  4. * Program: WSTCAT
  5. *
  6. *
  7. * Description:
  8. *
  9. * Concatenates multiple WSP files, for the same module, into one WSP file.
  10. * Creates a single TMI file from the resulting files.
  11. *
  12. *
  13. * Modification History:
  14. *
  15. * 8-20-92 Created marklea
  16. * 4-24-98, QFE: DerrickG (mdg)
  17. * - new WSP file format for large symbol counts (ULONG vs. USHORT)
  18. * - support for long file names (LFN) of input/output files
  19. * - removed limit on symbol name lengths
  20. *
  21. *
  22. *
  23. *
  24. */
  25. #include <windows.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <wsdata.h>
  30. #include <..\wsfslib\wserror.h>
  31. #include <..\wsfslib\wsfslib.h>
  32. #include <ntverp.h>
  33. #define MODULE "WSTCAT"
  34. #define VERSION VER_PRODUCTVERSION_STR
  35. /*
  36. * Global variable declaration and initialization.
  37. */
  38. static ULONG rc = NO_ERROR; // Return code
  39. typedef struct tagTMI{
  40. CHAR *pszFxnName;
  41. ULONG ulAddr;
  42. ULONG ulSize;
  43. ULONG ulIndex;
  44. BOOL fSet;
  45. }TMI;
  46. typedef struct indxMOD{
  47. ULONG ulSetCnt; // mdg 4/98
  48. ULONG ulFxnTot;
  49. ULONG ulOffset;
  50. ULONG ulSnaps;
  51. PULONG pulBitStrings;
  52. FILE *hFileNDX;
  53. TMI *tmi;
  54. }NDXMOD;
  55. typedef struct tagMOD{
  56. ULONG ulSetCnt; // mdg 4/98
  57. UINT uiLeft;
  58. ULONG ulOffset;
  59. ULONG ulSnaps;
  60. FILE *hFileWxx;
  61. PULONG pulAddr;
  62. }WSTMOD;
  63. NDXMOD nmod;
  64. WSTMOD wmod[256];
  65. CHAR *szFileWSP; //WSP file name
  66. CHAR *szFileTMI; //TMI file name
  67. CHAR *szFileWxx; //extra wsp files
  68. CHAR *szFileTxx; //extra tmi files
  69. CHAR *szModName; //Module or DLL name
  70. CHAR *szFileWSPtmp; // Temporary .WSP file name
  71. CHAR *szFileTMItmp; // Temporary .TMI file name
  72. ULONG clVarTot = 0; // Total number of dwords in bitstr
  73. UINT uiModCount;
  74. WSPHDR WspHdr, tmpHdr;
  75. FILE *hFileWSP;
  76. FILE *hFileTmpWSP;
  77. FILE *hFileTMI;
  78. FILE *hFileTmpTMI;
  79. /*
  80. * Function prototypes.
  81. */
  82. VOID wspCatSetup(VOID);
  83. VOID wspCatUsage(VOID);
  84. VOID wspCat(VOID);
  85. INT wspCatExit(INT, USHORT, UINT, ULONG, LPSTR);
  86. int WspBCompare (ULONG, PULONG);
  87. LONG WspBSearch (ULONG ulAddr, WSTMOD wmod);
  88. /****************************** M A I N **************************************
  89. *
  90. * Function: main (INT argc, CHAR *argv[])
  91. *
  92. *
  93. * Purpose: Parses command line and dumps the WSP and TMI files
  94. *
  95. * Usage: [d:][path]wstcat modulename
  96. *
  97. * where: modulename is the name of the module whose wXX files
  98. * you want to concatenate.
  99. *
  100. * Returns: NONE
  101. *
  102. *****************************************************************************/
  103. VOID __cdecl main (INT argc, CHAR *argv[])
  104. {
  105. ConvertAppToOem( argc, argv );
  106. if (argc != 2) {
  107. wspCatUsage();
  108. exit( -1 );
  109. }
  110. else {
  111. UINT nLen;
  112. char * pDot;
  113. if ((pDot = strrchr( argv[ 1 ], '.' )) != NULL)
  114. *pDot = '\0';
  115. nLen = strlen( argv[1] ) + 1;
  116. szModName = malloc( nLen );
  117. if (szModName)
  118. strcpy(szModName, argv[1]);
  119. else {
  120. exit(1);
  121. }
  122. szFileWSP = malloc( nLen + 4 );
  123. if (szFileWSP)
  124. strcat( strcpy( szFileWSP, szModName ), ".WSP" );
  125. else {
  126. free(szModName);
  127. exit(1);
  128. }
  129. szFileTMI = malloc( nLen + 4 );
  130. if (szFileTMI)
  131. strcat( strcpy( szFileTMI, szModName ), ".TMI" );
  132. else {
  133. free(szFileWSP);
  134. free(szModName);
  135. exit(1);
  136. }
  137. szFileWxx = malloc( nLen + 4 );
  138. if (szFileWxx)
  139. strcat( strcpy( szFileWxx, szModName ), ".Wxx" );
  140. else {
  141. free(szFileTMI);
  142. free(szFileWSP);
  143. free(szModName);
  144. exit(1);
  145. }
  146. szFileTxx = malloc( nLen + 4 );
  147. if (szFileTxx)
  148. strcat( strcpy( szFileTxx, szModName ), ".Txx" );
  149. else {
  150. free(szFileWxx);
  151. free(szFileTMI);
  152. free(szFileWSP);
  153. free(szModName);
  154. exit(1);
  155. }
  156. szFileWSPtmp = malloc( nLen + 4 );
  157. if (szFileWSPtmp)
  158. strcat( strcpy( szFileWSPtmp, szModName ), ".Wzz" );
  159. else {
  160. free(szFileTxx);
  161. free(szFileWxx);
  162. free(szFileTMI);
  163. free(szFileWSP);
  164. free(szModName);
  165. exit(1);
  166. }
  167. szFileTMItmp = malloc( nLen + 4 );
  168. if (szFileTMItmp)
  169. strcat( strcpy( szFileTMItmp, szModName ), ".Tzz" );
  170. else {
  171. free(szFileTMItmp);
  172. free(szFileTxx);
  173. free(szFileWxx);
  174. free(szFileTMI);
  175. free(szFileWSP);
  176. free(szModName);
  177. exit(1);
  178. }
  179. }
  180. // Setup input files for dump processing.
  181. wspCatSetup();
  182. wspCat();
  183. // Free allocated memory
  184. free( szModName );
  185. free( szFileWSP );
  186. free( szFileTMI );
  187. free( szFileWxx );
  188. free( szFileTxx );
  189. }
  190. /*
  191. *
  192. ***LP wspCatSetup
  193. *
  194. *
  195. * Effects:
  196. *
  197. * Opens the module's WSP and TMI input files, seeks to the start of the
  198. * first function's bitstring data in the WSP file, and allocates memory
  199. * to hold one function's bitstring.
  200. *
  201. * Returns:
  202. *
  203. * Void. If an error is encountered, exits through wspCatExit()
  204. * with ERROR.
  205. *
  206. */
  207. VOID wspCatSetup(VOID)
  208. {
  209. ULONG ulTmp;
  210. UINT uiExt = 0;
  211. UINT x;
  212. char * pszTmpName;
  213. /* Open input WSP file. Read and validate WSP file header.*/
  214. rc = WsWSPOpen(szFileWSP, &hFileWSP,(PFN)wspCatExit,
  215. (wsphdr_t *)&WspHdr, ERROR, PRINT_MSG );
  216. if(rc){
  217. exit(rc);
  218. }
  219. //
  220. // Open a temporary tmi file to hold concatenated information.
  221. // This file will be renamed to module.tmi when the cat process
  222. // is complete, and the current module.tmi will be renamed to module.txx.
  223. //
  224. hFileTMI = fopen(szFileTMI, "rt");
  225. if (!hFileTMI) {
  226. wspCatExit(ERROR, PRINT_MSG, MSG_FILE_OPEN, GetLastError(), szFileTMI);
  227. }
  228. hFileTmpTMI = fopen(szFileTMItmp, "wt");
  229. if (!hFileTmpTMI) {
  230. wspCatExit(ERROR, PRINT_MSG, MSG_FILE_OPEN, GetLastError(), szFileTMItmp);
  231. }
  232. pszTmpName = malloc( 128 + 1 );
  233. if (pszTmpName) {
  234. fputs (fgets (pszTmpName, 128, hFileTMI), hFileTmpTMI);
  235. fputs (fgets (pszTmpName, 128, hFileTMI), hFileTmpTMI);
  236. fputs (fgets (pszTmpName, 128, hFileTMI), hFileTmpTMI);
  237. fputs (fgets (pszTmpName, 128, hFileTMI), hFileTmpTMI);
  238. fputs (fgets (pszTmpName, 128, hFileTMI), hFileTmpTMI);
  239. free( pszTmpName );
  240. }
  241. fclose(hFileTMI);
  242. //
  243. // Set key, module specific information
  244. //
  245. clVarTot = WspHdr.ulSnaps;
  246. nmod.ulSnaps = WspHdr.ulSnaps;
  247. nmod.ulSetCnt = WspHdr.ulSetSymbols; // mdg 4/98
  248. nmod.ulOffset = WspHdr.ulOffset;
  249. nmod.ulFxnTot = WsTMIOpen(szFileTMI, &hFileTMI, (PFN) wspCatExit,
  250. 0, (PCHAR)0);
  251. //
  252. // Open a temporary wsp file to hold concatenated information.
  253. // This file will be renamed to module.wsp when the cat process
  254. // is complete, and the current module.wsp will be renamed to module.wxx.
  255. // The header is also written.
  256. //
  257. hFileTmpWSP = fopen(szFileWSPtmp, "wb");
  258. if (!hFileTmpWSP) {
  259. wspCatExit(ERROR, PRINT_MSG, MSG_FILE_OPEN, GetLastError(), szFileWSPtmp);
  260. }
  261. WspHdr.ulOffset = sizeof(WSPHDR) + strlen( szModName ); // Set data location correctly
  262. fwrite(&WspHdr, sizeof(WSPHDR), 1, hFileTmpWSP);
  263. fwrite(szModName, strlen(szModName), 1, hFileTmpWSP);
  264. //
  265. // Allocate memory to hold TMI data for each Symbol in the
  266. // main TMI file
  267. //
  268. nmod.tmi = (TMI *)malloc(nmod.ulFxnTot * sizeof(TMI));
  269. if (nmod.tmi == NULL) {
  270. wspCatExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  271. nmod.ulFxnTot * sizeof(TMI), "nmod.tmi[]");
  272. }
  273. //
  274. // Read data for each symbol record in the key TMI file
  275. //
  276. for (x = 0; x < nmod.ulFxnTot ; x++ ) {
  277. nmod.tmi[x].ulSize = WsTMIReadRec(&pszTmpName, &(nmod.tmi[x].ulIndex),
  278. &(nmod.tmi[x].ulAddr), hFileTMI,
  279. (PFN)wspCatExit, (PCHAR)0);
  280. nmod.tmi[x].pszFxnName = pszTmpName;
  281. }
  282. fclose(hFileTMI);
  283. //
  284. // Get Txx and Wxx specific information
  285. //
  286. while(rc == NO_ERROR){
  287. //
  288. // Modify the file name to the first wxx and txx file
  289. //
  290. sprintf(szFileWxx, "%s.w%02d", szModName, uiExt+1);
  291. sprintf(szFileTxx, "%s.t%02d", szModName, uiExt+1);
  292. //
  293. // Open file.Wxx and read header information.
  294. //
  295. rc = WsWSPOpen(szFileWxx, &(wmod[uiExt].hFileWxx),(PFN)wspCatExit,
  296. (wsphdr_t *)&tmpHdr, NOEXIT, NO_MSG );
  297. //
  298. // Check for an error from the open command. Could be the last
  299. // file.
  300. //
  301. if(rc == NO_ERROR){
  302. clVarTot += tmpHdr.ulSnaps; //Increment the total number of
  303. //Snapshots by the number from
  304. //each data file.
  305. wmod[uiExt].ulSetCnt = tmpHdr.ulSetSymbols; // mdg 4/98
  306. wmod[uiExt].uiLeft = tmpHdr.ulSetSymbols; // mdg 4/98
  307. wmod[uiExt].ulOffset = tmpHdr.ulOffset;
  308. wmod[uiExt].ulSnaps = tmpHdr.ulSnaps;
  309. wmod[uiExt].pulAddr = (ULONG *)malloc(wmod[uiExt].ulSetCnt * // mdg 4/98
  310. sizeof(ULONG));
  311. //
  312. // Open the TMI file associated with this data file
  313. //
  314. WsTMIOpen(szFileTxx, &hFileTMI,(PFN)wspCatExit,
  315. 0, (PCHAR)0);
  316. //
  317. // Read each address from the TMI file.
  318. //
  319. if(rc == NO_ERROR){
  320. for (x = 0; x < wmod[uiExt].ulSetCnt ; x++ ) { // mdg 4/98
  321. WsTMIReadRec(&pszTmpName, &ulTmp, (wmod[uiExt].pulAddr)+x,
  322. hFileTMI, (PFN)wspCatExit, (PCHAR)0);
  323. free( pszTmpName );
  324. }
  325. }
  326. }
  327. //
  328. // Increment the module index
  329. //
  330. uiExt++;
  331. }
  332. uiModCount = uiExt;
  333. //
  334. // Allocate enough memory to hold all the bit strings for each module
  335. // in a single array.
  336. //
  337. nmod.pulBitStrings = (ULONG *) malloc(clVarTot * sizeof(ULONG));
  338. if (nmod.pulBitStrings == NULL)
  339. wspCatExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  340. clVarTot * sizeof(ULONG), "pulBitStrings[]");
  341. }
  342. /*
  343. *
  344. ***LP wspCat
  345. *
  346. *
  347. * Effects:
  348. *
  349. * For each function,
  350. *
  351. * Returns:
  352. *
  353. * Void. If an error is encountered, exits through wspCatExit()
  354. * with ERROR.
  355. *
  356. */
  357. VOID wspCat(VOID)
  358. {
  359. UINT uiFxn = 0; // Function number.
  360. UINT x = 0;
  361. PULONG pulBitStrings; // Pointer to bitstring data.
  362. ULONG culSnaps = 0; // Cumulative snapshots.
  363. LONG lIndex = 0; // Index to WSP file.
  364. BOOL fSetBits = FALSE;
  365. CHAR szBuffer [256];
  366. ULONG ulNewSetCnt = 0; // mdg 4/98
  367. for (uiFxn = 0; uiFxn < nmod.ulFxnTot; uiFxn++)
  368. {
  369. pulBitStrings = &(nmod.pulBitStrings[0]);
  370. culSnaps = nmod.ulSnaps;
  371. //
  372. // Check to see if any non-zero bit strings remain
  373. //
  374. if(uiFxn < nmod.ulSetCnt){ // mdg 4/98
  375. //
  376. // Seek to function's bitstring in WSP file.
  377. // only for the first function
  378. //
  379. if(!uiFxn){
  380. if ((rc = fseek(hFileWSP,nmod.ulOffset,SEEK_SET))!=NO_ERROR)
  381. wspCatExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET,
  382. rc, szModName);
  383. }
  384. //
  385. // Read bitstring for NDX api
  386. //
  387. if (fread(pulBitStrings, sizeof(ULONG), nmod.ulSnaps, hFileWSP) != (sizeof(ULONG) * nmod.ulSnaps))
  388. wspCatExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET, 0, szModName);
  389. fSetBits = TRUE;
  390. }
  391. //
  392. // If not, set the bitstring to '0'. This is faster than seeking
  393. // to each bit string when they are zero.
  394. //
  395. else
  396. memset(pulBitStrings, '\0' , (sizeof(ULONG) * nmod.ulSnaps));
  397. //
  398. // Increment the pointer to allow for the addition of the next
  399. // bitstring set
  400. //
  401. pulBitStrings += nmod.ulSnaps;
  402. //
  403. // Now search WSTMOD array for a matching Function address
  404. //
  405. for (x=0; x < uiModCount - 1 ; x++ ) {
  406. culSnaps += wmod[x].ulSnaps;
  407. //
  408. // See if there are any functions that remain
  409. // and if so search for them
  410. //
  411. if(wmod[x].uiLeft){
  412. lIndex = WspBSearch(nmod.tmi[uiFxn].ulAddr, wmod[x]);
  413. //
  414. // If search has found a matching address, get the bitstring
  415. // and append it pulBitStrings
  416. //
  417. if (lIndex >= 0L) {
  418. lIndex = wmod[x].ulOffset +
  419. ( lIndex * (wmod[x].ulSnaps * sizeof(ULONG)));
  420. if (rc = fseek(wmod[x].hFileWxx, lIndex, SEEK_SET) != NO_ERROR)
  421. wspCatExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET, rc, szModName);
  422. if (fread(pulBitStrings, sizeof(ULONG), wmod[x].ulSnaps, wmod[x].hFileWxx) !=
  423. (sizeof(ULONG) * wmod[x].ulSnaps))
  424. {
  425. wspCatExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET, 0, szModName);
  426. }
  427. wmod[x].uiLeft--;
  428. fSetBits = TRUE;
  429. }
  430. //
  431. // Otherwise, set all bytes to 0
  432. //
  433. else{
  434. memset(pulBitStrings, '\0' , (sizeof(ULONG) * wmod[x].ulSnaps));
  435. }
  436. }
  437. //
  438. // Otherwise, set all bytes to 0
  439. //
  440. else
  441. memset(pulBitStrings, '\0' , (sizeof(ULONG) * wmod[x].ulSnaps));
  442. //
  443. // Now increment the pointer to allow for appending of additional
  444. // bitstring data.
  445. //
  446. pulBitStrings += wmod[x].ulSnaps;
  447. }
  448. //
  449. // Now we need to write the TMI & WSP file with the concatenated
  450. // bitstring (only if set)
  451. //
  452. nmod.tmi[uiFxn].fSet = fSetBits;
  453. if (fSetBits) {
  454. ulNewSetCnt++; // 4/98
  455. sprintf(szBuffer, "%ld 0000:%08lx 0x%lx %ld ",
  456. (LONG)nmod.tmi[uiFxn].ulIndex, nmod.tmi[uiFxn].ulAddr,
  457. nmod.tmi[uiFxn].ulSize, strlen( nmod.tmi[uiFxn].pszFxnName ));
  458. fwrite(szBuffer, sizeof(char), strlen(szBuffer), hFileTmpTMI);
  459. fputs( nmod.tmi[uiFxn].pszFxnName, hFileTmpTMI );
  460. fputc( '\n', hFileTmpTMI );
  461. fwrite(nmod.pulBitStrings, sizeof(ULONG), culSnaps, hFileTmpWSP);
  462. fSetBits = FALSE;
  463. }
  464. }
  465. //
  466. // Now write all the TMI symbols not set to the temporary .tmi file
  467. //
  468. memset(nmod.pulBitStrings, '\0' , (sizeof(ULONG) * culSnaps));
  469. for (uiFxn = 0; uiFxn < nmod.ulFxnTot; uiFxn++) {
  470. if (!nmod.tmi[uiFxn].fSet) {
  471. sprintf(szBuffer, "%ld 0000:%08lx 0x%lx %ld ",
  472. (LONG)nmod.tmi[uiFxn].ulIndex, nmod.tmi[uiFxn].ulAddr,
  473. nmod.tmi[uiFxn].ulSize, strlen( nmod.tmi[uiFxn].pszFxnName ));
  474. fwrite(szBuffer, sizeof(char), strlen(szBuffer), hFileTmpTMI);
  475. fputs( nmod.tmi[uiFxn].pszFxnName, hFileTmpTMI );
  476. fputc( '\n', hFileTmpTMI );
  477. fwrite(nmod.pulBitStrings, sizeof(ULONG), culSnaps, hFileTmpWSP);
  478. }
  479. }
  480. //
  481. // Seek to the beginning of the WSP file and update the snapshot
  482. // count in the header
  483. //
  484. if (!fseek(hFileTmpWSP, 0L, SEEK_SET)) {
  485. WspHdr.ulSnaps = culSnaps;
  486. WspHdr.ulSetSymbols = ulNewSetCnt; // mdg 4/98
  487. fprintf(stdout,"Set symbols: %lu\n", WspHdr.ulSetSymbols); // mdg 4/98
  488. fwrite(&WspHdr, sizeof(WSPHDR), 1, hFileTmpWSP);
  489. }
  490. _fcloseall();
  491. //
  492. // Rename the non-cat'd .wsp file and rename the cat'd temporary .wsp
  493. // to the original .wsp. We might also consider deleting all the
  494. // Wxx and Txx files.
  495. //
  496. sprintf (szFileWxx, "%s.%s", szModName, "WSP");
  497. sprintf (szFileTxx, "%s.%s", szModName, "WXX");
  498. remove(szFileTxx);
  499. if (rename(szFileWxx, szFileTxx) !=0){
  500. printf("Unable to rename file %s to %s\n", szFileWxx, szFileTxx);
  501. }
  502. else{
  503. if (rename(szFileWSPtmp, szFileWSP) !=0){
  504. printf ("Unable to rename %s to %s!\n", szFileWSPtmp, szFileWxx);
  505. }
  506. }
  507. //
  508. // Rename the non-cat'd .tmi file and rename the cat'd temporary .tmi
  509. // to the original .tmi. We might also consider deleting all the
  510. // Wxx and Txx files.
  511. //
  512. sprintf (szFileWxx, "%s.%s", szModName, "TMI");
  513. sprintf (szFileTxx, "%s.%s", szModName, "TXX");
  514. remove(szFileTxx);
  515. if (rename(szFileWxx, szFileTxx) !=0){
  516. printf("Unable to rename file %s to %s\n", szFileWxx, szFileTxx);
  517. }
  518. else{
  519. if (rename(szFileTMItmp, szFileTMI) !=0){
  520. printf ("Unable to rename %s to %s!\n", szFileTMItmp, szFileWxx);
  521. }
  522. }
  523. }
  524. /*
  525. *
  526. * wspCatUsage
  527. *
  528. *
  529. * Effects:
  530. *
  531. * Prints out usage message, and exits with an error.
  532. *
  533. * Returns:
  534. *
  535. * Exits with ERROR.
  536. */
  537. VOID wspCatUsage(VOID)
  538. {
  539. printf("\nUsage: %s moduleName[.WSP]\n\n", MODULE);
  540. printf(" \"moduleName\" is the name of the module file to combine.\n\n");
  541. printf("%s %s\n", MODULE, VERSION);
  542. exit(ERROR);
  543. }
  544. /*
  545. *
  546. ***LP wspCatExit
  547. *
  548. *
  549. ***
  550. *
  551. * Effects:
  552. *
  553. * Frees up resources (as necessary). Exits with the specified
  554. * exit code, or returns void if exit code is NOEXIT.
  555. *
  556. ***
  557. * Returns:
  558. *
  559. * Void, else exits.
  560. */
  561. INT wspCatExit(INT iExitCode, USHORT fPrintMsg, UINT uiMsgCode,
  562. ULONG ulParam1, LPSTR pszParam2)
  563. {
  564. /* Print message, if necessary. */
  565. if (fPrintMsg)
  566. {
  567. printf(pchMsg[uiMsgCode], MODULE, VERSION , ulParam1, pszParam2);
  568. }
  569. // Special case: do NOT exit if called with NOEXIT.
  570. if (iExitCode != NOEXIT)
  571. exit(iExitCode);
  572. return(uiMsgCode);
  573. }
  574. /*********************** W s p B S e a r c h *******************************
  575. *
  576. * Function: WspBSearch(ULONG ulAddr, PULONG pulAddr)
  577. *
  578. * Purpose: Binary search function for finding a match in the WST array
  579. *
  580. *
  581. * Parameters:
  582. *
  583. *
  584. *
  585. * Returns: ULONG lIndex;
  586. *
  587. * History: 8-5-92 Marklea - created
  588. *
  589. */
  590. LONG WspBSearch (ULONG ulAddr, WSTMOD wmod)
  591. {
  592. int i;
  593. // ULONG ulHigh = (ULONG)wmod.usSetCnt;
  594. ULONG ulHigh = (ULONG)wmod.ulSetCnt; // mdg 4/98
  595. ULONG ulLow = 0;
  596. ULONG ulMid;
  597. while(ulLow < ulHigh){
  598. ulMid = ulLow + (ulHigh - ulLow) /2;
  599. if((i = WspBCompare(ulAddr, wmod.pulAddr+ulMid)) < 0) {
  600. ulHigh = ulMid;
  601. }
  602. else if (i > 0) {
  603. ulLow = ulMid + 1;
  604. }
  605. else {
  606. return (ulMid);
  607. }
  608. }
  609. return (-1L);
  610. } /* WspBSearch () */
  611. /*********************** W s p B C o m p a r e ********************************
  612. *
  613. * Function: WspBCompare(ULONG ulAddr, PULONG pulAddr)
  614. *
  615. * Purpose: Compare values for Binary search
  616. *
  617. *
  618. * Parameters:
  619. *
  620. * Returns: -1 if val1 < val2
  621. * 1 if val1 > val2
  622. * 0 if val1 == val2
  623. *
  624. * History: 8-3-92 Marklea - created
  625. *
  626. */
  627. int WspBCompare(ULONG ulAddr, PULONG pulAddr)
  628. {
  629. return (ulAddr < *pulAddr ? -1:
  630. ulAddr == *pulAddr ? 0:
  631. 1);
  632. } /* WspBCompare () */