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.

699 lines
18 KiB

  1. /*
  2. * Module Name: WSPDUMP.C
  3. *
  4. * Program: WSPDUMP
  5. *
  6. *
  7. * Description:
  8. *
  9. * Dumps the contents of a WSP file.
  10. *
  11. * Contitional compilation notes:
  12. *
  13. * Modification History:
  14. *
  15. * 6-12-92: Adapted OS/2 version of wspdump for NT marklea
  16. * 6-17-92: Modified wspDumpBits to dump in correct order marklea
  17. * 6-18-92: Added page useage information marklea
  18. * 8-31-92: Made single exe from wspdump, wsreduce and wstune marklea
  19. * 4-13-98: QFE DerrickG (mdg):
  20. * - new WSP file format for large symbol counts (ULONG vs. USHORT)
  21. * - support for long file names (LFN) of input/output files
  22. * - removed buggy reference to WSDIR env. variable
  23. * - based .TMI file name exclusively on .WSP name for consistency
  24. * - removed limit on symbol name lengths - return allocated name from WsTMIReadRec()
  25. * - removed unused static declarations
  26. *
  27. */
  28. #include "wstune.h"
  29. /*
  30. * Global variable declaration and initialization.
  31. */
  32. typedef struct fxn_t{
  33. CHAR *pszFxnName;
  34. ULONG cbFxn;
  35. ULONG ulTmiIndex;
  36. ULONG ulOrigIndex;
  37. }FXN;
  38. typedef FXN *PFXN;
  39. /*
  40. * Function prototypes.
  41. */
  42. static VOID wspDumpSetup( VOID );
  43. static VOID wspDumpRandom( VOID );
  44. static UINT wspDumpBits( VOID );
  45. static VOID wspDumpExit( UINT, USHORT, UINT, ULONG, PSZ );
  46. static void wspDumpCleanup( void );
  47. static VOID wspDumpSeq(VOID);
  48. static int __cdecl wspCompare(const void *fxn1, const void *fxn2);
  49. static CHAR *szFileWSP = NULL; // WSP file name
  50. static CHAR *szFileTMI = NULL; // TMI file name
  51. static CHAR *szFileWSR = NULL; // WSR file name
  52. static CHAR *szDatFile = NULL; // DAT file name
  53. static ULONG rc = NO_ERROR; // Return code
  54. static ULONG ulTmp; // Temp variable for Dos API returns
  55. static ULONG ulFxnIndex; // Original index in symbol table
  56. static FILE *hFileWSP; // Input WSP file handle
  57. static FILE *hFileTMI; // Input TMI file handle
  58. static FILE *hFileDAT; // Data file for dump
  59. static wsphdr_t WspHdr; // Input WSP file header
  60. static BOOL fRandom = FALSE; // Flag for random mode
  61. static BOOL fVerbose = FALSE; // Flag for verbose mode
  62. static ULONG ulFxnTot = 0; // Total number of functions
  63. static ULONG clVarTot = 0; // Total number of dwords in bitstr
  64. static ULONG *pulFxnBitstring; // Function bitstring
  65. static ULONG ulSetSym = 0; // Number of symbols set // mdg 4/98
  66. static BOOL fDatFile = FALSE;
  67. /*
  68. * Procedure wspDumpMain
  69. *
  70. *
  71. ***
  72. * Effects:
  73. *
  74. * Constructs .WSP and .TMI input names from input basefile name. If szDatExt is
  75. * not NULL, appends it to szBaseFile to create output data file name. If fRandom,
  76. * constructs a .WSR output file. If fVerbose, adds extra output to data file.
  77. *
  78. * Processes the input files and displays the function reference data
  79. * for each function in the specified module WSP file.
  80. *
  81. */
  82. BOOL wspDumpMain( CHAR *szBaseFile, CHAR *szDatExt, BOOL fRndm, BOOL fVbose )
  83. {
  84. size_t c;
  85. char * pSlash;
  86. fRandom = fRndm;
  87. fVerbose = fVbose;
  88. // mdg 98/4 Allocate space for filenames - don't use static buffers
  89. c = 5 + strlen( szBaseFile ); // Length to allocate for filenames
  90. szFileWSP = malloc( c );
  91. if (szFileWSP) {
  92. strcat( strcpy( szFileWSP, szBaseFile ), ".WSP" );
  93. } else {
  94. return (1);
  95. }
  96. szFileTMI = malloc( c );
  97. if (szFileTMI) {
  98. strcat( strcpy( szFileTMI, szBaseFile ), ".TMI" );
  99. } else {
  100. free(szFileWSP);
  101. return (1);
  102. }
  103. // Create output file in current directory
  104. if (NULL != (pSlash = strrchr( szBaseFile, '\\' ))
  105. || NULL != (pSlash = strrchr( szBaseFile, '/' ))
  106. || NULL != (pSlash = strrchr( szBaseFile, ':' )))
  107. {
  108. c = strlen( ++pSlash ) + 5;
  109. } else
  110. pSlash = szBaseFile;
  111. if (fRandom) {
  112. szFileWSR = malloc( c );
  113. if (szFileWSR) {
  114. strcat( strcpy( szFileWSR, pSlash ), ".WSR" );
  115. } else {
  116. free(szFileTMI);
  117. free(szFileWSP);
  118. return (1);
  119. }
  120. }
  121. if (szDatExt != NULL) {
  122. fDatFile = TRUE;
  123. szDatFile = malloc( c - 4 + strlen( szDatExt ) );
  124. if (szDatFile) {
  125. strcat( strcpy( szDatFile, pSlash ), szDatExt );
  126. } else {
  127. free(szFileWSR);
  128. free(szFileTMI);
  129. free(szFileWSP);
  130. return (1);
  131. }
  132. } else {
  133. fDatFile = FALSE;
  134. szDatFile = "";
  135. }
  136. // Setup input files for dump processing.
  137. wspDumpSetup();
  138. /* Print the WSP file info, either randomly (based on WSR file
  139. * input) or sequentially (the default).
  140. */
  141. if (fRandom == TRUE)
  142. wspDumpRandom();
  143. else
  144. wspDumpSeq();
  145. wspDumpCleanup();
  146. return(NO_ERROR);
  147. }
  148. /*
  149. *
  150. ***LP wspDumpSetup
  151. *
  152. *
  153. * Effects:
  154. *
  155. * Opens the module's WSP and TMI input files, seeks to the start of the
  156. * first function's bitstring data in the WSP file, and allocates memory
  157. * to hold one function's bitstring.
  158. *
  159. * Returns:
  160. *
  161. * Void. If an error is encountered, exits through wspDumpExit()
  162. * with ERROR.
  163. *
  164. */
  165. VOID
  166. wspDumpSetup()
  167. {
  168. CHAR szLineTMI[MAXLINE]; // Line from TMI file
  169. if(fDatFile){
  170. hFileDAT = fopen (szDatFile, "wt");
  171. if (hFileDAT == NULL) {
  172. printf("Error creating file %s, will send output to stdout.\n",
  173. szDatFile);
  174. hFileDAT = stdout;
  175. }
  176. }
  177. else hFileDAT = stdout;
  178. /* Open input WSP file. Read and validate WSP file header.*/
  179. rc = WsWSPOpen(szFileWSP, &hFileWSP,(PFN)wspDumpExit,&WspHdr,ERROR,PRINT_MSG);
  180. ulSetSym = WspHdr.wsphdr_dtqo.dtqo_SymCnt;
  181. clVarTot = WspHdr.wsphdr_ulSnaps;
  182. fprintf(stdout, "\n%s: Set symbol count=%lu - Segment size=%ld\n", // mdg 4/98
  183. szDatFile, WspHdr.wsphdr_dtqo.dtqo_SymCnt,
  184. WspHdr.wsphdr_dtqo.dtqo_clSegSize);
  185. /* Open TMI file (contains function names, obj:offset, size, etc.).
  186. * Verify that the TMI file identifier matches the module
  187. * identifier from the WSP file.
  188. */
  189. ulFxnTot = WsTMIOpen(szFileTMI, &hFileTMI, (PFN) wspDumpExit,
  190. 0, (PCHAR)0);
  191. if (!fseek(hFileTMI, 0L, SEEK_SET)) {
  192. return;
  193. }
  194. fgets(szLineTMI, MAXLINE, hFileTMI);
  195. /* Print module header information for output file */
  196. szLineTMI[strlen(szLineTMI)-1] = '\0';
  197. fprintf(hFileDAT,"\nDUMP OF FUNCTION REFERENCES FOR '%s':\n\n",szLineTMI);
  198. fclose (hFileTMI);
  199. ulFxnTot = WsTMIOpen(szFileTMI, &hFileTMI, (PFN) wspDumpExit,
  200. 0, (PCHAR)0);
  201. /* Allocate memory to hold one function's entire bitstring. */
  202. pulFxnBitstring = (ULONG *) malloc(clVarTot * sizeof(ULONG));
  203. if (pulFxnBitstring == NULL)
  204. wspDumpExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  205. clVarTot * sizeof(ULONG), "pulFxnBitstring[]");
  206. }
  207. /*
  208. *
  209. ***LP wspDumpSeq
  210. *
  211. *
  212. * Effects:
  213. *
  214. * For each function, prints the bitstring in ASCII form.
  215. *
  216. * Returns:
  217. *
  218. * Void. If an error is encountered, exits through wspDumpExit()
  219. * with ERROR.
  220. *
  221. */
  222. VOID wspDumpSeq(VOID)
  223. {
  224. UINT uiFxn = 0; // Function number
  225. UINT cTouched=0; // Count of touched pages
  226. BOOL fTouched=0; // Flag to indicate page is touched. // mdg 4/98
  227. UINT i=0; // Generic counter
  228. ULONG cbFxnCum =0; // Cumulative function sizes
  229. PFXN Fxn; // pointer to array of fxn name ptrs
  230. FILE *fpFileWSR = NULL; // WSR file pointer
  231. ULONG cbFBits = 0; // Count of bytes in bitstring
  232. UINT uiPageCount=0; // Pages touched.
  233. ULONG ulMaxBytes=0; // Bytes of touched pages.
  234. /* Allocate memory for function names. */
  235. Fxn = (PFXN) malloc(ulFxnTot * sizeof(FXN));
  236. if (Fxn == NULL)
  237. wspDumpExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  238. ulFxnTot * sizeof(FXN), "Fxn[]");
  239. WsIndicator( WSINDF_NEW, "Load Functions", ulFxnTot );
  240. /* Read function names from TMI file. */
  241. for (uiFxn = 0; uiFxn < ulFxnTot; uiFxn++)
  242. {
  243. WsIndicator( WSINDF_PROGRESS, NULL, uiFxn );
  244. Fxn[uiFxn].cbFxn = WsTMIReadRec(&Fxn[uiFxn].pszFxnName, &ulFxnIndex, &ulTmp, hFileTMI,
  245. (PFN) wspDumpExit, (PCHAR)0);
  246. Fxn[uiFxn].ulOrigIndex = ulFxnIndex;
  247. Fxn[uiFxn].ulTmiIndex = (ULONG)uiFxn;
  248. }
  249. qsort(Fxn, ulFxnTot, sizeof(FXN), wspCompare);
  250. WsIndicator( WSINDF_FINISH, NULL, 0 );
  251. cbFBits = clVarTot * sizeof(ULONG);
  252. WsIndicator( WSINDF_NEW, "Write Data Out", ulFxnTot );
  253. for (uiFxn = 0; uiFxn < ulFxnTot; uiFxn++)
  254. {
  255. WsIndicator( WSINDF_PROGRESS, NULL, uiFxn );
  256. /* Seek to function's bitstring in WSP file. */
  257. if ((rc = fseek(hFileWSP,(WspHdr.wsphdr_ulOffBits+(Fxn[uiFxn].ulTmiIndex*cbFBits)),SEEK_SET))!=NO_ERROR)
  258. wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET,
  259. rc, szFileWSP);
  260. fprintf(hFileDAT,"Fxn '%s' (#%d):\n\t", Fxn[uiFxn].pszFxnName, Fxn[uiFxn].ulOrigIndex);
  261. free(Fxn[uiFxn].pszFxnName); // mdg 98/4: Free allocated name string
  262. Fxn[uiFxn].pszFxnName = NULL;
  263. // Print this function's reference bitstring.
  264. // and if it has had a bit set, set touched flag to true
  265. if(wspDumpBits()){
  266. fTouched |=1;
  267. ulMaxBytes += Fxn[uiFxn].cbFxn;
  268. }
  269. fprintf(hFileDAT,"%-28s %10ld bytes.\n","Function size:", Fxn[uiFxn].cbFxn);
  270. cbFxnCum += Fxn[uiFxn].cbFxn;
  271. fprintf(hFileDAT,"%-28s %10ld bytes.\n\n","Cumulative function sizes:",
  272. cbFxnCum);
  273. //Checck to see if a 4k page boundry has been reached
  274. if(cbFxnCum >= (4096+(4096 * uiPageCount))){
  275. for(i=0; i < 60; i++){
  276. fprintf(hFileDAT, "*");
  277. }
  278. fprintf(hFileDAT,"\n\nTotal function sizes has reached or exceeds %d bytes.\n\n",
  279. (4096+(4096*uiPageCount)));
  280. ++uiPageCount;
  281. //Check to see of the page has been touched.
  282. if(fTouched){
  283. fprintf(hFileDAT,"This page has been touched.\n");
  284. ++cTouched;
  285. }
  286. else{
  287. fprintf(hFileDAT,"This page has not been touched.\n");
  288. }
  289. fTouched = 0;
  290. for(i=0; i < 60; i++){
  291. fprintf(hFileDAT, "*");
  292. }
  293. fprintf(hFileDAT, "\n\n");
  294. }
  295. }
  296. ++uiPageCount;
  297. if(fTouched){
  298. fprintf(hFileDAT,"\n\n");
  299. for(i=0; i < 70; i++){
  300. fprintf(hFileDAT, "=");
  301. }
  302. ++cTouched;
  303. fprintf(hFileDAT,"\n\nThis page has been touched.");
  304. }
  305. fprintf(hFileDAT,"\n\n");
  306. for(i=0; i < 70; i++){
  307. fprintf(hFileDAT, "=");
  308. }
  309. fprintf(hFileDAT,"\n\n%-28s %10ld bytes\n\n","Cumulative function size:", cbFxnCum);
  310. fprintf(hFileDAT,"%-28s %10d bytes\n\n", "Size of functions touched:", ulMaxBytes);
  311. fprintf(hFileDAT,"%-28s %10d\n\n", "Total page count:", uiPageCount);
  312. fprintf(hFileDAT,"%-28s %10d\n\n", "Total pages touched:", cTouched);
  313. WsIndicator( WSINDF_FINISH, NULL, 0 );
  314. }
  315. /*
  316. *
  317. ***LP wspDumpBits
  318. *
  319. *
  320. * Effects:
  321. *
  322. * Prints a function's reference bitstring (verbose mode only), followed
  323. * by the sum of the "on" bits.
  324. *
  325. * Returns:
  326. *
  327. * Void. If an error is encountered, exits through wspDumpExit()
  328. * with ERROR.
  329. *
  330. */
  331. UINT
  332. wspDumpBits()
  333. {
  334. ULONG clVar = 0; // Current dword of bitstring
  335. UINT uiBit = 0; // Result of bit test (1 or 0)
  336. UINT cBitsOn; // Count of "on" bits
  337. ULONG *pulBits; // Pointer to ULONG packets of bits
  338. CHAR szTmp[33];
  339. CHAR szBits[33];
  340. cBitsOn = 0;
  341. pulBits = pulFxnBitstring;
  342. /* Read next dword of function's bitstring. */
  343. szBits[0] = '\0';
  344. szTmp[0] = '\0';
  345. for (clVar = 0; clVar < clVarTot; clVar++, pulBits++)
  346. {
  347. rc = fread((PVOID)pulBits,
  348. (ULONG) sizeof(ULONG),1, hFileWSP);
  349. if(rc == 1)
  350. rc = NO_ERROR;
  351. else
  352. rc = 2;
  353. if (rc != NO_ERROR)
  354. wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_READ,
  355. rc, szFileWSP);
  356. if (*pulBits == 0)
  357. {
  358. if (fVerbose == TRUE)
  359. fprintf(hFileDAT,"00000000000000000000000000000000");
  360. }
  361. else
  362. for (uiBit = 0; uiBit < NUM_VAR_BITS; uiBit++)
  363. {
  364. if (*pulBits & 1)
  365. {
  366. cBitsOn++;
  367. if (fVerbose == TRUE){
  368. strcpy(szTmp,szBits);
  369. strcpy(szBits,"1");
  370. strcat(szBits,szTmp);
  371. }
  372. }
  373. else
  374. {
  375. if (fVerbose == TRUE){
  376. strcpy(szTmp,szBits);
  377. strcpy(szBits,"0");
  378. strcat(szBits,szTmp);
  379. }
  380. }
  381. *pulBits = *pulBits >> 1;
  382. }
  383. if (fVerbose == TRUE)
  384. {
  385. if ((clVar % 2) != 0){
  386. fprintf(hFileDAT,"%s",szBits);
  387. szBits[0]='\0';
  388. fprintf(hFileDAT,"\n\t");
  389. }
  390. else{
  391. fprintf(hFileDAT,"%s",szBits);
  392. szBits[0]='\0';
  393. fprintf(hFileDAT," ");
  394. }
  395. }
  396. }
  397. fprintf(hFileDAT,"\n\t*** Sum of '1' bits = %ld\n\n", cBitsOn);
  398. return(cBitsOn);
  399. }
  400. /*
  401. *
  402. ***LP wspDumpRandom
  403. *
  404. *
  405. * Effects:
  406. *
  407. * For each function ordinal specified in the WSR file, prints the
  408. * corresponding function's reference bitstring in ASCII form (verbose
  409. * mode only), followed by a sum of the "on" bits..
  410. *
  411. * Returns:
  412. *
  413. * Void. If an error is encountered, exits through wspDumpExit()
  414. * with ERROR.
  415. */
  416. VOID
  417. wspDumpRandom()
  418. {
  419. UINT uiFxn = 0; // Function number
  420. UINT cTouched=0; // Count of touched pages
  421. BOOL fTouched=0; // Flag to indicate page is touched. // mdg 4/98
  422. UINT i=0; // Generic counter
  423. ULONG cbFxnCum =0; // Cumulative function sizes
  424. PFXN Fxn; // pointer to array of fxn name ptrs
  425. ULONG ulFxnOrd; // function number within module
  426. FILE *fpFileWSR = NULL; // WSR file pointer
  427. ULONG cbFBits = 0; // Count of bytes in bitstring
  428. UINT uiPageCount=0; // Pages touched.
  429. ULONG ulMaxBytes=0; // Bytes of touched pages.
  430. /* Open WSR file (contains function ordinal numbers in ASCII). */
  431. if ((fpFileWSR = fopen(szFileWSR, "r")) == NULL)
  432. {
  433. wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_OPEN, rc, szFileWSR);
  434. }
  435. /* Allocate memory for function names. */
  436. Fxn = (PFXN) malloc(ulFxnTot * sizeof(FXN));
  437. if (Fxn == NULL)
  438. wspDumpExit(ERROR, PRINT_MSG, MSG_NO_MEM,
  439. ulFxnTot * sizeof(FXN), "Fxn[]");
  440. WsIndicator( WSINDF_NEW, "Load Functions", ulFxnTot );
  441. /* Read function names from TMI file. */
  442. for (uiFxn = 0; uiFxn < ulFxnTot; uiFxn++)
  443. {
  444. WsIndicator( WSINDF_PROGRESS, NULL, uiFxn );
  445. Fxn[uiFxn].cbFxn = WsTMIReadRec(&Fxn[uiFxn].pszFxnName, &ulFxnIndex, &ulTmp, hFileTMI,
  446. (PFN) wspDumpExit, (PCHAR)0);
  447. }
  448. WsIndicator( WSINDF_FINISH, NULL, 0 );
  449. cbFBits = clVarTot * sizeof(ULONG);
  450. WsIndicator( WSINDF_NEW, "Write Data Out", ulFxnTot );
  451. for (uiFxn = 0; uiFxn < ulFxnTot; uiFxn++)
  452. {
  453. WsIndicator( WSINDF_PROGRESS, NULL, uiFxn );
  454. /* Read function number from WSR file. */
  455. rc = fscanf(fpFileWSR, "%ld\n", &ulFxnOrd);
  456. if (rc != 1)
  457. wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_READ,
  458. rc, szFileWSR);
  459. /* Seek to function's bitstring in WSP file. */
  460. if ((rc = fseek(hFileWSP,(WspHdr.wsphdr_ulOffBits+(ulFxnOrd*cbFBits)),SEEK_SET))!=NO_ERROR)
  461. wspDumpExit(ERROR, PRINT_MSG, MSG_FILE_OFFSET,
  462. rc, szFileWSP);
  463. fprintf(hFileDAT,"Fxn '%s' (#%d):\n\t", Fxn[ulFxnOrd].pszFxnName, ulFxnOrd);
  464. free(Fxn[ulFxnOrd].pszFxnName); // mdg 98/4: Free allocated name string
  465. Fxn[ulFxnOrd].pszFxnName = NULL;
  466. // Print this function's reference bitstring.
  467. // and if it has had a bit set, set touched flag to true
  468. if(uiFxn < ulSetSym){ // mdg 4/98
  469. if(wspDumpBits()){
  470. fTouched |= 1;
  471. ulMaxBytes += Fxn[ulFxnOrd].cbFxn;
  472. }
  473. }
  474. else{
  475. fprintf(hFileDAT,"\n\t*** Sum of '1' bits = %ld\n\n", 0L);
  476. }
  477. fprintf(hFileDAT,"%-28s %10ld bytes.\n","Function size:", Fxn[ulFxnOrd].cbFxn);
  478. cbFxnCum += Fxn[ulFxnOrd].cbFxn;
  479. fprintf(hFileDAT,"%-28s %10ld bytes.\n\n","Cumulative function sizes:",
  480. cbFxnCum);
  481. //Check to see if a 4k page boundry has been reached
  482. if(cbFxnCum >= (4096+(4096 * uiPageCount))){
  483. for(i=0; i < 60; i++){
  484. fprintf(hFileDAT, "*");
  485. }
  486. fprintf(hFileDAT,"\n\nTotal function sizes has reached or exceeds %d bytes.\n\n",
  487. (4096+(4096*uiPageCount)));
  488. ++uiPageCount;
  489. //Check to see of the page has been touched.
  490. if(fTouched){
  491. fprintf(hFileDAT,"This page has been touched.\n");
  492. ++cTouched;
  493. }
  494. else{
  495. fprintf(hFileDAT,"This page has not been touched.\n");
  496. }
  497. fTouched = 0;
  498. for(i=0; i < 60; i++){
  499. fprintf(hFileDAT, "*");
  500. }
  501. fprintf(hFileDAT, "\n\n");
  502. }
  503. }
  504. ++uiPageCount;
  505. if(fTouched){
  506. fprintf(hFileDAT,"\n\n");
  507. for(i=0; i < 70; i++){
  508. fprintf(hFileDAT, "=");
  509. }
  510. ++cTouched;
  511. fprintf(hFileDAT,"\n\nThis page has been touched.");
  512. }
  513. fprintf(hFileDAT,"\n\n");
  514. for(i=0; i < 70; i++){
  515. fprintf(hFileDAT, "=");
  516. }
  517. fprintf(hFileDAT,"\n\n%-28s %10ld bytes\n\n","Cumulative function size:", cbFxnCum);
  518. fprintf(hFileDAT,"%-28s %10d bytes\n\n", "Size of functions touched:", ulMaxBytes);
  519. fprintf(hFileDAT,"%-28s %10d\n\n", "Total page count:", uiPageCount);
  520. fprintf(hFileDAT,"%-28s %10d\n\n", "Total pages touched:", cTouched);
  521. WsIndicator( WSINDF_FINISH, NULL, 0 );
  522. }
  523. /*
  524. *
  525. ***LP wspDumpExit
  526. *
  527. *
  528. ***
  529. *
  530. * Effects:
  531. *
  532. * Frees up resources (as necessary). Exits with the specified
  533. * exit code, or returns void if exit code is NOEXIT.
  534. *
  535. ***
  536. * Returns:
  537. *
  538. * Void, else exits.
  539. */
  540. VOID
  541. wspDumpExit(uiExitCode, fPrintMsg, uiMsgCode, ulParam1, pszParam2)
  542. UINT uiExitCode;
  543. USHORT fPrintMsg;
  544. UINT uiMsgCode;
  545. ULONG ulParam1;
  546. PSZ pszParam2;
  547. {
  548. /* Print message, if necessary. */
  549. if (fPrintMsg == TRUE)
  550. {
  551. printf(pchMsg[uiMsgCode], szProgName, pszVersion, ulParam1, pszParam2);
  552. }
  553. // Special case: do NOT exit if called with NOEXIT.
  554. if (uiExitCode == NOEXIT)
  555. return;
  556. wspDumpCleanup();
  557. exit(uiExitCode);
  558. }
  559. /*
  560. *
  561. ***LP wspDumpCleanup
  562. *
  563. *
  564. ***
  565. *
  566. * Effects:
  567. *
  568. * Frees up resources (as necessary).
  569. *
  570. ***
  571. * Returns:
  572. *
  573. * Void.
  574. */
  575. void
  576. wspDumpCleanup( void )
  577. {
  578. _fcloseall();
  579. free( szFileWSP );
  580. free( szFileTMI );
  581. if (fRandom)
  582. free( szFileWSR );
  583. if (fDatFile)
  584. free( szDatFile );
  585. }
  586. int __cdecl wspCompare(const void *fxn1, const void *fxn2)
  587. {
  588. return (((PFXN)fxn1)->ulOrigIndex < ((PFXN)fxn2)->ulOrigIndex ? -1:
  589. ((PFXN)fxn1)->ulOrigIndex == ((PFXN)fxn2)->ulOrigIndex ? 0:
  590. 1);
  591. }