PROFILE.CPP 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Library profiler *
  23. * *
  24. * File Name : PROFILE.CPP *
  25. * *
  26. * Programmer : Steve Tall *
  27. * *
  28. * Start Date : 11/17/95 *
  29. * *
  30. * Last Update : November 20th 1995 [ST] *
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Overview: *
  34. * Uses a map file to match addresses of functions in the sample file with their names *
  35. * *
  36. * *
  37. *---------------------------------------------------------------------------------------------*
  38. * *
  39. * Functions: *
  40. * Start_Profiler -- initialises the profiler data and starts gathering data *
  41. * Stop_Profiler -- stops the timer and writes the profile data to disk *
  42. * *
  43. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  44. #include <string.h>
  45. #include <stdio.h>
  46. #include <sys\types.h>
  47. #include <sys\stat.h>
  48. #include <fcntl.h>
  49. #include <malloc.h>
  50. #include <io.h>
  51. #include <conio.h>
  52. #define bool int
  53. #define true 1
  54. #define false 0
  55. #define NAME_TABLE_SIZE 1000000 //Storage space for function names
  56. #define SAMPLE_START 1 //Offset (in dwords) of sample data in sample file
  57. /*
  58. ** Function prototypes
  59. */
  60. void Print_My_Name(void);
  61. void Print_Usage(void);
  62. int Load_File(char *file_name , unsigned *file_ptr , unsigned mode);
  63. bool Extract_Function_Addresses(void);
  64. unsigned Get_Hex (char string[] , int length);
  65. char *Search_For_Char (char character , char buffer_ptr[] , int buffer_length);
  66. char *Search_For_String (char *string , char *buffer_ptr , int buffer_length);
  67. void Map_Profiler_Hits (void);
  68. void Sort_Functions(void);
  69. void Sort_Functions_Again(void);
  70. void Output_Profile(void);
  71. char *SampleFile; //Ptr to sample file name
  72. char *MapFile; //Ptr to map file name
  73. unsigned *SampleFileBuffer; //Ptr to buffer that sample file is loaded in to
  74. char *MapFileBuffer; //Ptr to buffer that map file is loaded in to
  75. unsigned SampleFileLength; //Length of sample file
  76. unsigned MapFileLength; //Length of map file
  77. char FunctionNames[NAME_TABLE_SIZE]; //Buffer to store function names in
  78. char *FunctionNamePtr=&FunctionNames[0]; //Ptr to end of last function name in buffer
  79. int TotalFunctions; //Total number of functions extracted from map file
  80. int SampleRate; //Number of samples/sec that data was collected at
  81. unsigned EndCodeSegment; //Length of the sampled programs code segments
  82. /*
  83. ** Structure for collating function data
  84. */
  85. typedef struct tFunction {
  86. unsigned FunctionAddress; //Address of function relative to start of code seg
  87. char *FunctionName; //Ptr to name of function in FunctionNames buffer
  88. int Hits; //Number of times function was 'hit' when sampling
  89. } Function;
  90. Function FunctionList[10000]; //max 10,000 functions in map file.
  91. /***********************************************************************************************
  92. * main -- program entry point *
  93. * *
  94. * *
  95. * *
  96. * INPUT: argc , argv *
  97. * *
  98. * OUTPUT: 0 *
  99. * *
  100. * WARNINGS: None *
  101. * *
  102. * HISTORY: *
  103. * 11/20/95 5:21PM ST : Created *
  104. *=============================================================================================*/
  105. int main(int argc, char *argv[])
  106. {
  107. Print_My_Name(); // print the programs name
  108. /*
  109. ** If the arguments dont make sense then print the usage
  110. */
  111. if (argc!=3 ||
  112. !strcmpi(argv[1],"/?") ||
  113. !strcmpi(argv[1],"/h") ||
  114. !strcmpi(argv[1],"/help") ||
  115. !strcmpi(argv[1],"-?") ||
  116. !strcmpi(argv[1],"-h") ||
  117. !strcmpi(argv[1],"-help") ||
  118. !strcmpi(argv[1],"?") ||
  119. !strcmpi(argv[1],"h") ||
  120. !strcmpi(argv[1],"help")){
  121. Print_Usage();
  122. return(0);
  123. }
  124. /*
  125. ** Get the names of the files to load
  126. */
  127. SampleFile=argv[1];
  128. MapFile=argv[2];
  129. /*
  130. ** Load the profile sample file
  131. */
  132. SampleFileLength = Load_File (SampleFile , (unsigned*)&SampleFileBuffer , O_BINARY);
  133. if (!SampleFileLength) return(0);
  134. /*
  135. ** The sample rate is the 1st dword in the file
  136. */
  137. SampleRate=*SampleFileBuffer;
  138. /*
  139. ** Load the .map file
  140. */
  141. MapFileLength = Load_File (MapFile , (unsigned*)&MapFileBuffer , O_BINARY);
  142. if (!MapFileLength){
  143. free (SampleFileBuffer);
  144. return(0);
  145. }
  146. /*
  147. ** Get the function names from the map file
  148. */
  149. cprintf ("Extracting function data from map file.\n");
  150. if (!Extract_Function_Addresses()){
  151. cprintf ("Error parsing .MAP file - aborting\n\n");
  152. return (0);
  153. }
  154. /*
  155. ** Sort the functions into address order to make it easier to map the functions
  156. */
  157. cprintf ("Sorting function list by address");
  158. Sort_Functions();
  159. /*
  160. ** Map the addresses in the sample file to the function addresses
  161. */
  162. cprintf ("\nMapping profiler hits to functions");
  163. Map_Profiler_Hits();
  164. /*
  165. ** Sort the functions into order of usage for output
  166. */
  167. cprintf ("\nSorting function list by activity");
  168. Sort_Functions_Again();
  169. cprintf ("\n\n");
  170. /*
  171. ** Print the function usage statistics
  172. */
  173. Output_Profile();
  174. /*
  175. ** Cleanup and out
  176. */
  177. free (SampleFileBuffer);
  178. free (MapFileBuffer);
  179. return(0);
  180. }
  181. /***********************************************************************************************
  182. * Print_My_Name -- print the programs name and version *
  183. * *
  184. * *
  185. * INPUT: Nothing *
  186. * *
  187. * OUTPUT: Nothing *
  188. * *
  189. * WARNINGS: None *
  190. * *
  191. * HISTORY: *
  192. * 11/20/95 5:25PM ST : Created *
  193. *=============================================================================================*/
  194. void Print_My_Name(void)
  195. {
  196. cprintf("Westwood profile data analyzer.\n");
  197. cprintf("V 1.0 - 11/17/95\n");
  198. cprintf("Programmer - Steve Tall.\n\n");
  199. }
  200. /***********************************************************************************************
  201. * Print_Usage -- print the instructions *
  202. * *
  203. * *
  204. * INPUT: Nothing *
  205. * *
  206. * OUTPUT: Nothing *
  207. * *
  208. * WARNINGS: None *
  209. * *
  210. * HISTORY: *
  211. * 11/20/95 5:26PM ST : Created *
  212. *=============================================================================================*/
  213. void Print_Usage (void)
  214. {
  215. cprintf("Usage: PROFILE <sample_file> <map_file)\n\n");
  216. }
  217. /***********************************************************************************************
  218. * File_Error -- display a file error message *
  219. * *
  220. * *
  221. * INPUT: name of file error occurred on *
  222. * *
  223. * OUTPUT: Nothing *
  224. * *
  225. * WARNINGS: None *
  226. * *
  227. * HISTORY: *
  228. * 11/20/95 5:26PM ST : Created *
  229. *=============================================================================================*/
  230. void File_Error (char *file_name)
  231. {
  232. cprintf ("Error reading file:%s - aborting\n",file_name);
  233. }
  234. /***********************************************************************************************
  235. * Memory_Error -- display an out of memory message *
  236. * *
  237. * *
  238. * *
  239. * INPUT: Nothing *
  240. * *
  241. * OUTPUT: Nothing *
  242. * *
  243. * WARNINGS: None *
  244. * *
  245. * HISTORY: *
  246. * 11/20/95 5:27PM ST : Created *
  247. *=============================================================================================*/
  248. void Memory_Error (void)
  249. {
  250. cprintf ("Error - insufficient memory - aborting\n");
  251. }
  252. /***********************************************************************************************
  253. * Load_File -- load an entire file into memory *
  254. * *
  255. * *
  256. * *
  257. * INPUT: File name *
  258. * address to load at *
  259. * read mode (text or binary) *
  260. * *
  261. * OUTPUT: number of bytes read *
  262. * *
  263. * WARNINGS: None *
  264. * *
  265. * HISTORY: *
  266. * 11/20/95 5:27PM ST : Created *
  267. *=============================================================================================*/
  268. int Load_File(char *file_name , unsigned *load_addr , unsigned mode)
  269. {
  270. int handle;
  271. unsigned file_length;
  272. void *buffer;
  273. handle=open (file_name , O_RDONLY | mode);
  274. if (handle==-1){
  275. File_Error(file_name);
  276. return (false);
  277. }
  278. file_length = filelength(handle);
  279. if (file_length==-1) return (false);
  280. buffer = malloc (file_length+10);
  281. if (!buffer){
  282. Memory_Error();
  283. return (false);
  284. }
  285. if (read (handle , buffer , file_length)!=file_length){
  286. File_Error(file_name);
  287. free(buffer);
  288. return (false);
  289. }
  290. close (handle);
  291. *load_addr = (unsigned)buffer;
  292. return (file_length);
  293. }
  294. /***********************************************************************************************
  295. * Map_Profiler_Hits -- map function hits from sample file to functions in map file *
  296. * *
  297. * *
  298. * *
  299. * INPUT: Nothing *
  300. * *
  301. * OUTPUT: Nothing *
  302. * *
  303. * WARNINGS: Map file functions must be sorted into address order 1st *
  304. * *
  305. * HISTORY: *
  306. * 11/20/95 5:28PM ST : Created *
  307. *=============================================================================================*/
  308. void Map_Profiler_Hits (void)
  309. {
  310. unsigned *samples=(unsigned*)SampleFileBuffer;
  311. unsigned function_hit;
  312. for (int i=SAMPLE_START ; i<SampleFileLength/4 ; i++){
  313. function_hit=*(samples+i);
  314. if (1023==(1023 & i)){
  315. cprintf (".");
  316. }
  317. for (int j=TotalFunctions-1 ; j>=0 ; j--){
  318. if (FunctionList[j].FunctionAddress < function_hit){
  319. FunctionList[j].Hits++;
  320. break;
  321. }
  322. }
  323. }
  324. }
  325. /***********************************************************************************************
  326. * Sort_Functions -- hideous bubble sort of functions into address order *
  327. * *
  328. * *
  329. * INPUT: Nothing *
  330. * *
  331. * OUTPUT: Nothing *
  332. * *
  333. * WARNINGS: None *
  334. * *
  335. * HISTORY: *
  336. * 11/20/95 5:29PM ST : Created *
  337. *=============================================================================================*/
  338. void Sort_Functions (void)
  339. {
  340. Function address_swap;
  341. if (TotalFunctions>1){
  342. for (int outer=0 ; outer <TotalFunctions ; outer++){
  343. address_swap.FunctionAddress=0;
  344. if (127==(127 & outer)){
  345. cprintf (".");
  346. }
  347. for (int inner=0 ; inner < TotalFunctions-1 ; inner++){
  348. if (FunctionList[inner].FunctionAddress > FunctionList[inner+1].FunctionAddress ){
  349. memcpy (&address_swap , &FunctionList[inner] , sizeof(Function));
  350. memcpy (&FunctionList[inner] , &FunctionList[inner+1] , sizeof(Function));
  351. memcpy (&FunctionList[inner+1] , &address_swap , sizeof(Function));
  352. }
  353. }
  354. if (!address_swap.FunctionAddress) break;
  355. }
  356. }
  357. }
  358. /***********************************************************************************************
  359. * Sort_Functions -- hideous bubble sort of functions into usage order *
  360. * *
  361. * *
  362. * INPUT: Nothing *
  363. * *
  364. * OUTPUT: Nothing *
  365. * *
  366. * WARNINGS: None *
  367. * *
  368. * HISTORY: *
  369. * 11/20/95 5:29PM ST : Created *
  370. *=============================================================================================*/
  371. void Sort_Functions_Again (void)
  372. {
  373. Function address_swap;
  374. if (TotalFunctions>1){
  375. for (int outer=0 ; outer <TotalFunctions ; outer++){
  376. address_swap.FunctionAddress=0;
  377. if (127==(127 & outer)){
  378. cprintf (".");
  379. }
  380. for (int inner=0 ; inner < TotalFunctions-1 ; inner++){
  381. if (FunctionList[inner].Hits < FunctionList[inner+1].Hits ){
  382. memcpy (&address_swap , &FunctionList[inner] , sizeof(Function));
  383. memcpy (&FunctionList[inner] , &FunctionList[inner+1] , sizeof(Function));
  384. memcpy (&FunctionList[inner+1] , &address_swap , sizeof(Function));
  385. }
  386. }
  387. if (!address_swap.FunctionAddress) break;
  388. }
  389. }
  390. }
  391. /***********************************************************************************************
  392. * Output_Profile -- output the function data to the screen *
  393. * *
  394. * *
  395. * INPUT: Nothing *
  396. * *
  397. * OUTPUT: Nothing *
  398. * *
  399. * WARNINGS: None *
  400. * *
  401. * HISTORY: *
  402. * 11/20/95 5:31PM ST : Created *
  403. *=============================================================================================*/
  404. void Output_Profile(void)
  405. {
  406. double period=(((double)SampleFileLength/(double)4) - (double)SAMPLE_START) / (double)SampleRate;
  407. double percentage;
  408. printf ( "\n Profile information from %s and %s.\n\n",SampleFile,MapFile);
  409. printf ( "Samples collected:%d\n" , SampleFileLength/4-SAMPLE_START);
  410. printf ( "Sample rate :%d samples per second\n",SampleRate);
  411. printf ( "Sample period :%f seconds\n\n\n" , period);
  412. printf ( "Hits %% Function\n");
  413. printf ( "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n");
  414. for (int i=0 ; i<TotalFunctions ; i++){
  415. if (FunctionList[i].Hits){
  416. percentage= ((double)FunctionList[i].Hits*(double)100) / ((double)SampleFileLength/(double)4-(double)SAMPLE_START);
  417. printf ("%-6d %-3.3f%% %s\n",FunctionList[i].Hits , percentage , FunctionList[i].FunctionName);
  418. }
  419. }
  420. }
  421. /***********************************************************************************************
  422. * Extract_Function_Addresses -- gets the addresses of all global functions from a map file *
  423. * *
  424. * *
  425. * INPUT: Nothing *
  426. * *
  427. * OUTPUT: Nothing *
  428. * *
  429. * WARNINGS: true if successfully extracted *
  430. * *
  431. * HISTORY: *
  432. * 11/20/95 5:31PM ST : Created *
  433. *=============================================================================================*/
  434. bool Extract_Function_Addresses(void)
  435. {
  436. char *map_ptr;
  437. char *segment_ptr;
  438. char *end_str_ptr;
  439. unsigned chars_left=MapFileLength;
  440. int function_name_length;
  441. unsigned end_of_last_code_segment;
  442. unsigned code_segment_start;
  443. unsigned code_segment_size;
  444. char unknown[]={"Windows API or system code."};
  445. /*
  446. ** Clear out the list of functions
  447. */
  448. memset (&FunctionNames[0] , 0 , NAME_TABLE_SIZE);
  449. /*
  450. ** Search for the 'Segments' header in the memory map
  451. */
  452. segment_ptr = Search_For_String ("Segments" , MapFileBuffer , chars_left);
  453. if (!segment_ptr) return (false);
  454. chars_left = MapFileLength - ( (unsigned)segment_ptr - (unsigned)MapFileBuffer );
  455. segment_ptr = Search_For_String ("+-----" , segment_ptr , chars_left);
  456. segment_ptr +=2;
  457. chars_left = MapFileLength - ( (unsigned)segment_ptr - (unsigned)MapFileBuffer );
  458. /*
  459. ** Get the length of the segment section by searching for the start of the next section
  460. */
  461. end_str_ptr = Search_For_String ("+-----" , segment_ptr , chars_left);
  462. if (end_str_ptr){
  463. chars_left = end_str_ptr - segment_ptr;
  464. } else {
  465. return (false);
  466. }
  467. EndCodeSegment = 0;
  468. /*
  469. ** Find the end of the last code segment
  470. */
  471. do {
  472. /*
  473. ** Search for a code segment identifier
  474. */
  475. chars_left = end_str_ptr - segment_ptr;
  476. segment_ptr = Search_For_String ("CODE" , segment_ptr , chars_left);
  477. if (!segment_ptr) break; //No more code segments so break
  478. /*
  479. ** Search for the segment address which should always be 0001
  480. */
  481. chars_left = end_str_ptr - segment_ptr;
  482. segment_ptr = Search_For_String ("0001:" , segment_ptr , chars_left);
  483. if (!segment_ptr) return (false); //Couldnt find the segment address - must be a problem so abort
  484. /*
  485. ** Get the start address and length of the segment
  486. */
  487. code_segment_start = Get_Hex(segment_ptr+5,8);
  488. code_segment_size = Get_Hex(segment_ptr+16,8);
  489. /*
  490. ** If this segment ends higher in memory than the previous highest then
  491. ** we have a new last segment
  492. */
  493. if (code_segment_start+code_segment_size > EndCodeSegment){
  494. EndCodeSegment = code_segment_start+code_segment_size;
  495. }
  496. chars_left = end_str_ptr - segment_ptr;
  497. segment_ptr = Search_For_Char ( 13 , segment_ptr , chars_left );
  498. chars_left = end_str_ptr - segment_ptr;
  499. } while (chars_left > 0);
  500. chars_left=MapFileLength;
  501. /*
  502. ** Search for the 'Memory Map' segment of the map file
  503. */
  504. map_ptr = Search_For_String ("Memory Map" , MapFileBuffer , chars_left);
  505. if (!map_ptr){
  506. return (false);
  507. }
  508. chars_left = MapFileLength - ( (unsigned)map_ptr - (unsigned)MapFileBuffer );
  509. /*
  510. ** Get the length of the memory map segment by searching for the start of the next segment
  511. */
  512. end_str_ptr = Search_For_String ("+-----" , map_ptr , chars_left);
  513. if (end_str_ptr){
  514. MapFileLength = ((unsigned)MapFileBuffer + MapFileLength) - (unsigned)end_str_ptr;
  515. }
  516. chars_left = MapFileLength - ( (unsigned)map_ptr - (unsigned)MapFileBuffer );
  517. /*
  518. ** Reset the total number of functions found
  519. */
  520. TotalFunctions = 0;
  521. /*
  522. **
  523. ** Find each occurrence of 0001: as all the functions we want are in the 1st segment
  524. **
  525. */
  526. do {
  527. /*
  528. ** Find '0001:'
  529. */
  530. map_ptr = Search_For_String ("0001:" , map_ptr , chars_left);
  531. if (!map_ptr){
  532. break;
  533. }
  534. chars_left = MapFileLength - ( (unsigned)map_ptr - (unsigned)MapFileBuffer );
  535. /*
  536. ** Skip the '0001:' portion of the address and get the hext offset of the function
  537. */
  538. map_ptr+=5;
  539. FunctionList[TotalFunctions].FunctionAddress=Get_Hex(map_ptr,8);
  540. /*
  541. ** Skip to the function name and get its length by searching for the end of the line
  542. */
  543. map_ptr+=10;
  544. chars_left = MapFileLength - ( (unsigned)map_ptr - (unsigned)MapFileBuffer );
  545. end_str_ptr = Search_For_Char (13 , map_ptr , chars_left);
  546. if (!end_str_ptr){
  547. break;
  548. }
  549. function_name_length = (unsigned)end_str_ptr - (unsigned)map_ptr;
  550. /*
  551. ** Copy the function name into the name list and keep a pointer to it
  552. */
  553. memcpy (FunctionNamePtr , map_ptr , function_name_length);
  554. FunctionList[TotalFunctions].FunctionName = FunctionNamePtr;
  555. FunctionNamePtr += function_name_length+1; //Leave an extra 0 on the end as a terminator
  556. FunctionList[TotalFunctions].Hits = 0; //We dont yet know how many times we hit it
  557. TotalFunctions++;
  558. } while (1);
  559. /*
  560. ** Add in a dummy function at the highest address to represent unknown code hits
  561. */
  562. FunctionList[TotalFunctions].FunctionAddress = EndCodeSegment;
  563. memcpy (FunctionNamePtr , &unknown , sizeof (unknown));
  564. FunctionList[TotalFunctions].FunctionName = FunctionNamePtr;
  565. FunctionNamePtr += sizeof (unknown);
  566. FunctionList[TotalFunctions].Hits = 0;
  567. TotalFunctions++;
  568. return (true);
  569. }
  570. /***********************************************************************************************
  571. * Get_Hex -- nasty function to convert an ascii hex number to an unsigned int *
  572. * I'm sure there must be a lovely 'c' way of doing this but I dont know what it is *
  573. * *
  574. * *
  575. * INPUT: ptr to ascii hex string , number of digits in string *
  576. * *
  577. * OUTPUT: value of hex string *
  578. * *
  579. * WARNINGS: None *
  580. * *
  581. * HISTORY: *
  582. * 11/20/95 5:39PM ST : Created *
  583. *=============================================================================================*/
  584. unsigned Get_Hex (char string[] , int length)
  585. {
  586. unsigned hex_val=0;
  587. int multiplier=1;
  588. char hex_char;
  589. for (int i=0 ; i<length ; i++){
  590. hex_char=string[length-1-i];
  591. switch (hex_char){
  592. case '0':
  593. hex_char=0;
  594. break;
  595. case '1':
  596. hex_char=1;
  597. break;
  598. case '2':
  599. hex_char=2;
  600. break;
  601. case '3':
  602. hex_char=3;
  603. break;
  604. case '4':
  605. hex_char=4;
  606. break;
  607. case '5':
  608. hex_char=5;
  609. break;
  610. case '6':
  611. hex_char=6;
  612. break;
  613. case '7':
  614. hex_char=7;
  615. break;
  616. case '8':
  617. hex_char=8;
  618. break;
  619. case '9':
  620. hex_char=9;
  621. break;
  622. case 'A':
  623. hex_char=10;
  624. break;
  625. case 'B':
  626. hex_char=11;
  627. break;
  628. case 'C':
  629. hex_char=12;
  630. break;
  631. case 'D':
  632. hex_char=13;
  633. break;
  634. case 'E':
  635. hex_char=14;
  636. break;
  637. case 'F':
  638. hex_char=15;
  639. break;
  640. case 'a':
  641. hex_char=10;
  642. break;
  643. case 'b':
  644. hex_char=11;
  645. break;
  646. case 'c':
  647. hex_char=12;
  648. break;
  649. case 'd':
  650. hex_char=13;
  651. break;
  652. case 'e':
  653. hex_char=14;
  654. break;
  655. case 'f':
  656. hex_char=15;
  657. break;
  658. }
  659. hex_val += hex_char * multiplier;
  660. multiplier = multiplier<<4;
  661. }
  662. return (hex_val);
  663. }
  664. /***********************************************************************************************
  665. * Search_For_Char -- search through ascii data for a particular character *
  666. * *
  667. * *
  668. * *
  669. * INPUT: character *
  670. * ptr to buffer *
  671. * length of buffer *
  672. * *
  673. * OUTPUT: ptr to char in buffer or NULL if not found *
  674. * *
  675. * WARNINGS: None *
  676. * *
  677. * HISTORY: *
  678. * 11/20/95 5:41PM ST : Created *
  679. *=============================================================================================*/
  680. char *Search_For_Char (char character , char buffer_ptr[] , int buffer_length)
  681. {
  682. for ( unsigned i=0 ; i<buffer_length ; i++){
  683. if (buffer_ptr[i]==character){
  684. return ((char*) (unsigned)buffer_ptr+i);
  685. }
  686. }
  687. return (NULL);
  688. }
  689. /***********************************************************************************************
  690. * Search_For_String -- search for a string of chars within a buffer *
  691. * *
  692. * *
  693. * *
  694. * INPUT: string *
  695. * ptr to buffer to search in *
  696. * length of buffer *
  697. * *
  698. * OUTPUT: ptr to string in buffer or NULL if not found *
  699. * *
  700. * WARNINGS: None *
  701. * *
  702. * HISTORY: *
  703. * 11/20/95 5:42PM ST : Created *
  704. *=============================================================================================*/
  705. char *Search_For_String (char *string , char *buffer_ptr , int buffer_length)
  706. {
  707. int j;
  708. int string_length=strlen(string);
  709. for (int i=0 ; i<buffer_length-string_length ; i++){
  710. for (j=0 ; j<string_length ; j++){
  711. if ( *(string+j) != *(buffer_ptr+i+j)) break;
  712. }
  713. if (j==string_length) return buffer_ptr+i;
  714. }
  715. return (NULL);
  716. }