home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 09 / objlib.lst < prev    next >
File List  |  1991-08-21  |  29KB  |  660 lines

  1. _OB╩ LIBRAR┘ MANAGEMENT_
  2. b∙ Thoma≤ Siering
  3.  
  4. [LISTING ONE]
  5.  
  6. //****** svc.h  --  Service functions *******
  7.  
  8. #define NOFILE              NULL        // no error log file
  9. typedef enum {
  10.     Message,
  11.     Warning,
  12.     Error
  13. } MESSAGETYPE;
  14.  
  15. char *MakeASCIIZ(unsigned char *LString);
  16. void Output(MESSAGETYPE MsgType, FILE *Stream, char *OutputFormat, ...);
  17.  
  18.  
  19.  
  20. [LISTING TWO]
  21. //****** svc.c  --  Service functions *******
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <stdarg.h>
  26. #include "svc.h"
  27.  
  28. // MakeASCIIZ - Take a string of 1-byte length/data format, and make it ASCIIZ.
  29. char *MakeASCIIZ(unsigned char *LString)
  30. {
  31.     char *ASCIIZString;
  32.     unsigned char StringLength;
  33.  
  34.     StringLength = *LString++;
  35.     if ((ASCIIZString = malloc((int) StringLength + 1)) == NULL) 
  36.         return (NULL);
  37.     strncpy(ASCIIZString, (signed char *) LString, StringLength);
  38.     ASCIIZString[StringLength] = '\0';
  39.     return (ASCIIZString);
  40. }
  41.  
  42. // Output -- Write to the output stream. This function adds an exception-
  43. // handling layer to disk IO. It handles abnormal program termination, and 
  44. // warnings to both stderr and output. Three types of message can be handled: 
  45. // Message, simply printed to a file; Warning, print to file AND stderr; 
  46. // Error, same as warning, but terminate with abnormal exit code.
  47. void Output(MESSAGETYPE MsgType, FILE *Stream, char *OutputFormat, ...)
  48. {
  49.     char OutputBuffer[133];
  50.     va_list VarArgP;
  51.  
  52.     va_start(VarArgP, OutputFormat);
  53.     vsprintf(OutputBuffer, OutputFormat, VarArgP);
  54.     // If this is (non-fatal) warning or (fatal) error, also send it to stderr 
  55.     if (MsgType != Message)è        fprintf(stderr, "\a%s", OutputBuffer);
  56.     // In any case: attempt to print message to output file.  Exception check. 
  57.     if (Stream != NOFILE)
  58.         if ((size_t) fprintf(Stream, OutputBuffer) != strlen(OutputBuffer)) {
  59.             fprintf(stderr, "\aDisk Write Failure!\n");
  60.             abort();
  61.         }
  62.     /* If this was (fatal) error message, abort on the spot */
  63.     if (MsgType == Error) {
  64.         flushall();
  65.         fcloseall();
  66.         abort();
  67.     }
  68.     va_end(VarArgP);
  69. }
  70.  
  71.  
  72.  
  73. [LISTING THREE]
  74.  
  75. //***** ole.h  --  Global include info for Object Library Engine (ole.c) ******
  76.  
  77. #define THEADR              0x80        // OMF module header
  78. #define COMENT              0x88        // OMF comment record
  79. #define MODEND              0x8A        // OMF module end record
  80. #define LIBMOD              0xA3        // library module name comment class
  81. #define LIBHEADER           0xF0        // LIB file header
  82. #define MARKER_RECORD       0xF1        // marker between modules & dictionary
  83. #define NUMBUCKETS          37          // number of buckets/block    
  84. #define DICTBLOCKSIZE       512         // bytes/symbol dictionary block
  85. #define DICTBLKFULL         0xFF        // Symbol dictionary block full
  86.  
  87. #define UNDEFINED           -1          // to indicate non-initialized data
  88. #define STR_EQUAL           0           // string equality
  89.  
  90. // These two macros will rotate word operand opw by nbits bits (0 - 16) 
  91. #define WORDBITS            16
  92. #define ROL(opw, nbits) (((opw) << (nbits)) | ((opw) >> (WORDBITS - (nbits))))
  93. #define ROR(opw, nbits) (((opw) >> (nbits)) | ((opw) << (WORDBITS - (nbits))))
  94.  
  95. typedef enum {
  96.     false,
  97.     true
  98. } bool;
  99.  
  100. #pragma pack(1)
  101.  
  102. typedef struct {
  103.     unsigned char RecType;
  104.     int RecLength;
  105. } OMFHEADER;
  106.  
  107. typedef struct {
  108.     unsigned char RecType;
  109.     int RecLength;è    unsigned char Attrib;
  110.     unsigned char CommentClass;
  111. } COMENTHEADER;
  112.  
  113. typedef struct {                    // Record Type F0h
  114.     int PageSize;                   // Header length (excl. first 3 bytes)
  115.                                     // == page size (module at page boundary)
  116.                                     // page size == 2 ** n, 4 <= n <= 15
  117.     long DictionaryOffset;          // file offset of Symbol Dictionary
  118.     int NumDictBlocks;              // number of Symbol Dictionary blocks
  119.                                     // <= 251 512-byte dictionary pages
  120.     unsigned char Flags;            // only valid flag: 01h => case-sensitive
  121.     bool IsCaseSensitive;
  122.     bool IsLIBMODFormat;            // is MS extension type LIBMOD present?
  123. } LIBHDR;
  124.  
  125. typedef struct {
  126.     unsigned char MarkerType;       // This's better be F1h
  127.     int MarkerLength;               // filler to dictionary's 512-byte alignment
  128. } DICTMARKER;
  129.  
  130. typedef struct {
  131.     int  BlockNumber;
  132.     int  BucketNumber;
  133.     unsigned char *SymbolP;
  134.     long ModuleFilePos;
  135.     bool IsFound;
  136. } DICTENTRY;
  137.  
  138. typedef struct {
  139.     int BlockHash;
  140.     int BlockOvfl;
  141.     int BucketHash;
  142.     int BucketOvfl;
  143. } HashT;
  144.  
  145. void GetLibHeader(LIBHDR *LibHeader, FILE *InLibFH);
  146. HashT Hash(char SymbolZ[], int NumHashBlocks);
  147. DICTENTRY FindSymbol(char *SymbolZ, LIBHDR *LibHeader, FILE *InLibFH);
  148. void GetSymDictBlock(int BlockNumber, LIBHDR *LibHeader, 
  149.         FILE *InLibFH);
  150. long FindModule(char *ModuleName, LIBHDR *LibHeader, FILE *InLibFH);
  151. DICTENTRY GetSymDictEntry(int BlockNumber, int BucketNumber, 
  152.         LIBHDR *LibHeader, FILE *InLibFH);
  153. char *GetModuleName(long ModuleFilePos, LIBHDR *LibHeader, FILE *InLibFH);
  154. bool FindLIBMOD(FILE *InLibFH);
  155. bool FindObjRecord(FILE *ObjFH, unsigned char RecType);
  156. bool ExtractModule(char *ModuleName, char *NewModuleName, LIBHDR *LibHeader, 
  157.         FILE *InLibFH);
  158. void CopyObjModule(FILE *NewObjFH, long FilePos, FILE *InLibFH);
  159.  
  160.  
  161.  
  162. [LISTING FOUR]
  163. è//***** ole.c  --  Object Library Engine ******
  164.  
  165. #include <stdio.h>
  166. #include <io.h>
  167. #include <stdlib.h>
  168. #include <string.h>
  169. #include "ole.h"
  170. #include "svc.h"
  171.  
  172. typedef struct {
  173.     unsigned char SymbolDictBlock[DICTBLOCKSIZE];   // symbol dictionary block
  174.     int FreeSpaceIdx;                // cursor to next free symbol space slot
  175.     bool IsFull;                     // is this sym. dict. block full?
  176.     int BlockNumber;                 // current block number
  177. } DICTBLOCK;
  178.  
  179. // The number of pages in the Symbol Dictionary has to be a prime <= 251.
  180. // NOTE: The smallest page number in MS LIB is 2, in Borland TLIB it's 1.
  181. static int Primes[] = { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,
  182.         47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
  183.         127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 
  184.         197, 199, 211, 223, 227, 229, 233, 239, 241, 251 };
  185. // Symbol Dictionary Block
  186. static DICTBLOCK DictBlock;
  187. //  GetLibHeader -- Get header of an object module library. The library 
  188. //  header's ( record type F0) main purpose is to identify this data file as a
  189. //  library, give page size, and size and location of Symbol Dictionary.
  190. void GetLibHeader(LIBHDR *LibHeader, FILE *InLibFH)
  191. {
  192.     if (fgetc(InLibFH) != LIBHEADER) 
  193.         Output(Error, NOFILE, "Bogus Library Header\n");
  194.     // NOTE: The LIBHDR data structure has been enlarged to include more
  195.     // info than the actual LIB header contains.  As a result, a few more bytes
  196.     // are read in past the actual header when we take sizeof(LIBHDR).  This
  197.     // is no problem since there's plenty to read after the header, anyway!
  198.     if (fread(LibHeader, sizeof(LIBHDR), 1, InLibFH) != 1) 
  199.         Output(Error, NOFILE, "Couldn't Read Library Header\n");
  200.     // Add in Header length word & checksum byte
  201.     LibHeader->PageSize += 3;       
  202.     // Determine if LIB includes Microsoft's LIBMOD extension
  203.     // Find the first OBJ module in the LIB file
  204.     if (fseek(InLibFH, (long) LibHeader->PageSize, SEEK_SET) != 0)
  205.         Output(Error, NOFILE, "Seek for first object module failed\n");
  206.     LibHeader->IsLIBMODFormat = FindLIBMOD(InLibFH);
  207.     LibHeader->IsCaseSensitive = LibHeader->Flags == 0x01 ? true : false;
  208.     // Make it clear that we haven't read Symbol Dictionary yet
  209.     DictBlock.BlockNumber = UNDEFINED;
  210.  }
  211. //  FindModule -- Find a module in Symbol Dictionary and return its file
  212. //  position.  If not found, return -1L.
  213. long FindModule(char *ModuleName, LIBHDR *LibHeader, FILE *InLibFH)
  214. {
  215.     char *ObjName;
  216.     DICTENTRY DictEntry;
  217.     char *ExtP;è    // Allow extra space for terminating "!\0"
  218.     if ((ObjName = malloc(strlen(ModuleName) + 2)) == NULL) 
  219.         Output(Error, NOFILE, "OBJ Name Memory Allocation Failed\n");
  220.     strcpy(ObjName, ModuleName);
  221.     // Allow search for module name xxx.obj
  222.     if ((ExtP = strrchr(ObjName, '.')) != NULL)
  223.         *ExtP = '\0';
  224.     // NOTE: Module names are stored in LIB's with terminating '!'
  225.     strcat(ObjName, "!");
  226.     DictEntry = FindSymbol(ObjName, LibHeader, InLibFH);
  227.  
  228.     free(ObjName);
  229.     return (DictEntry.IsFound == true ? DictEntry.ModuleFilePos : -1L);
  230. }
  231. //  FindSymbol  --  Find a symbol in Symbol Dictionary by (repeatedly, if 
  232. //  necessary) hashing the symbol and doing dictionary lookup.
  233. DICTENTRY FindSymbol(char *SymbolZ, LIBHDR *LibHeader, FILE *InLibFH)
  234. {
  235.     DICTENTRY DictEntry;
  236.     char *SymbolP;
  237.     HashT HashVal;
  238.     int MaxTries;
  239.     int Block, Bucket;
  240.  
  241.     HashVal = Hash(SymbolZ, LibHeader->NumDictBlocks);
  242.     Block = HashVal.BlockHash;
  243.     Bucket = HashVal.BucketHash;
  244.     MaxTries = LibHeader->NumDictBlocks * NUMBUCKETS;
  245.     DictEntry.IsFound = false;
  246.  
  247.     while (MaxTries--) {
  248.         DictEntry = GetSymDictEntry(Block, Bucket, LibHeader, InLibFH);
  249.         // Three alternatives to check after Symbol Dictionary lookup:
  250.         // 1. If the entry is zero, but the dictionary block is NOT full,
  251.         //    the symbol is not present:
  252.         if (DictEntry.IsFound == false && DictBlock.IsFull == false) 
  253.             return (DictEntry);
  254.         // 2. If the entry is zero, and the dictionary block is full, the
  255.         //    symbol may have been rehashed to another block; keep looking:
  256.         // 3. If the entry is non-zero, we still have to verify the symbol.
  257.         //    If it's the wrong one (hash clash), keep looking:
  258.         if (DictEntry.IsFound == true) {
  259.             // Get the symbol name
  260.             SymbolP = MakeASCIIZ(DictEntry.SymbolP); 
  261.             // Choose case-sensitive or insensitive comparison as appropriate
  262.             if ((LibHeader->IsCaseSensitive == true ? strcmp(SymbolZ, SymbolP) : 
  263.                     stricmp(SymbolZ, SymbolP)) == STR_EQUAL) {
  264.                 free(SymbolP);
  265.                 return (DictEntry);
  266.             }
  267.             free(SymbolP);
  268.         }   
  269.         // Cases 2 and 3 (w/o a symbol match) require re-hash:
  270.         Block += HashVal.BlockOvfl;
  271.         Bucket += HashVal.BucketOvfl;è        Block %= LibHeader->NumDictBlocks;
  272.         Bucket %= NUMBUCKETS;
  273.     }    
  274.     // We never found the entry!
  275.     DictEntry.IsFound = false;
  276.     return (DictEntry);
  277. }
  278. //  Hash  --  Hash a symbol for Symbol Dictionary entry
  279. //  Inputs: SymbolZ - Symbol in ASCIIZ form; NumHashBlocks - current number of 
  280. //    Symbol Dictionary blocks (MS LIB max. 251 blocks)
  281. //  Outputs: Hash data structure, containing: BlockHash, index of block 
  282. //    containing symbol; BlockOvfl, block index's rehash delta; BucketHash, 
  283. //    index of symbol's bucket (position) on page; BucketOvfl, bucket index's 
  284. //    rehash delta
  285. //  Algorithm: Determine block index, i.e. page number in Symbol Dictionary 
  286. //    where the symbol is to reside, and the bucket index, i.e. the position 
  287. //    within that page (0-36). If this leads to collision, retry with bucket 
  288. //    delta until entire block has turned out to be full. Then, apply block 
  289. //    delta, and start over with original bucket index.
  290. HashT Hash(char SymbolZ[], int NumHashBlocks)
  291. {
  292.     HashT SymHash;                     // the resulting aggregate hash values
  293.     unsigned char *SymbolC;            // symbol with prepended count
  294.     int  SymLength;                    // length of symbol to be hashed
  295.     unsigned char *FwdP, *BwdP;        // temp. pts's to string: forward/back.
  296.     unsigned int FwdC, BwdC;           // current char's at fwd/backw. pointers
  297.     unsigned int BlockH, BlockD, BucketH, BucketD;   // temporary values 
  298.     int i;
  299.     SymLength = strlen(SymbolZ);
  300.     // Make symbol string in Length byte/ASCII string format
  301.     if ((SymbolC = malloc(SymLength + 2)) == NULL)
  302.         Output(Error, NOFILE, "Memory Allocation Failed\n");
  303.     SymbolC[0] = (unsigned char) SymLength;
  304.     // copy w/o EOS
  305.     strncpy((signed char *) &SymbolC[1], SymbolZ, SymLength + 1);    
  306.     FwdP = &SymbolC[0];
  307.     BwdP = &SymbolC[SymLength];
  308.     BlockH = BlockD = BucketH = BucketD = 0;
  309.     for (i = 0; i < SymLength; i++) {
  310.         // Hashing is done case-insensitive, incl. length byte
  311.         FwdC = (unsigned int) *FwdP++ | 0x20;
  312.         BwdC = (unsigned int) *BwdP-- | 0x20;
  313.         // XOR the current character (moving forward or reverse, depending
  314.         // on variable calculated) with the intermediate result rotated
  315.         // by 2 bits (again, left or right, depending on variable).
  316.         // Block Hash: traverse forward, rotate left
  317.         BlockH = FwdC ^ ROL(BlockH, 2);
  318.         // Block Overflow delta: traverse reverse, rotate left
  319.         BlockD = BwdC ^ ROL(BlockD, 2);
  320.         // Bucket Hash: traverse reverse, rotate right
  321.         BucketH = BwdC ^ ROR(BucketH, 2);
  322.         // Bucket Overflow delta: traverse forward, rotate right
  323.         BucketD = FwdC ^ ROR(BucketD, 2);
  324.     }
  325.     // NOTE: Results are zero-basedè    SymHash.BlockHash = BlockH % NumHashBlocks;
  326.     SymHash.BucketHash = BucketH % NUMBUCKETS;
  327.     // Obviously, hash deltas of 0 would be nonsense!
  328.     SymHash.BlockOvfl = max(BlockD % NumHashBlocks, 1);
  329.     SymHash.BucketOvfl = max(BucketD % NUMBUCKETS, 1);
  330.  
  331.     free(SymbolC);
  332.     return (SymHash);
  333. }
  334. //  GetSymDictBlock  --  Read and pre-process a Symbol Dictionary block
  335. void GetSymDictBlock(int BlockNumber, LIBHDR *LibHeader, FILE *InLibFH)
  336. {
  337.     // Find and read the whole Symbol Dictionary block
  338.     if (fseek(InLibFH, LibHeader->DictionaryOffset + (long) BlockNumber * 
  339.             (long) DICTBLOCKSIZE, SEEK_SET) != 0)
  340.         Output(Error, NOFILE, "Could Not Find Symbol Dictionary\n");
  341.     if (fread(DictBlock.SymbolDictBlock, DICTBLOCKSIZE, 1, InLibFH) != 1) 
  342.         Output(Error, NOFILE, "Couldn't Read Library Header\n");
  343.     // Is this block all used up?
  344.     DictBlock.FreeSpaceIdx = DictBlock.SymbolDictBlock[NUMBUCKETS];
  345.     DictBlock.IsFull = (DictBlock.FreeSpaceIdx == DICTBLKFULL) ? true : false;
  346.     // For future reference, remember block number
  347.     DictBlock.BlockNumber = BlockNumber;
  348. }
  349. //  GetSymDictEntry  --  Look up and process a Symbol Dictionary block entry
  350. DICTENTRY GetSymDictEntry(int BlockNumber, int BucketNumber, 
  351.         LIBHDR *LibHeader, FILE *InLibFH)
  352. {
  353.     DICTENTRY DictEntry;
  354.     unsigned char SymbolOffset;
  355.     unsigned char SymbolLength;
  356.     int PageNumber;
  357.     // Remember entry's block/bucket and init. to no (NULL) entry
  358.     DictEntry.BlockNumber = BlockNumber;
  359.     DictEntry.BucketNumber = BucketNumber;
  360.     DictEntry.SymbolP = NULL;   
  361.     DictEntry.IsFound = false;
  362.     // Make sure the appropriate block was already read from obj. mod. library
  363.     if (DictBlock.BlockNumber != BlockNumber)
  364.         GetSymDictBlock(BlockNumber, LibHeader, InLibFH);
  365.     // WORD offset of symbol in dictionary block: 0 means no entry
  366.     SymbolOffset = DictBlock.SymbolDictBlock[BucketNumber];
  367.     if (SymbolOffset != 0) {
  368.         // Since it's word offset, need to multiply by two
  369.         DictEntry.SymbolP = &DictBlock.SymbolDictBlock[SymbolOffset * 2];
  370.         // Get the symbol's object module offset in LIB
  371.         SymbolLength = *DictEntry.SymbolP;
  372.         // Object module's LIB page number is right after symbol string
  373.         PageNumber = *(int *) (DictEntry.SymbolP + SymbolLength + 1);
  374.         DictEntry.ModuleFilePos = (long) PageNumber * 
  375.                 (long) LibHeader->PageSize;
  376.         DictEntry.IsFound = true;
  377.     }
  378.     return (DictEntry);
  379. }è//  GetModuleName -- Read the OMF module header record (THEADR - 80h) or, if
  380. //    present, MS's LIBMOD extension record type. NOTE: For Microsoft C, 
  381. //    THEADR reflects the source code name file at compilation time. OBJ name 
  382. //    may differ from this; the LIBMOD record will contain its name. For 
  383. //    Borland C++, THEADR is the only pertinent record and will contain OBJ 
  384. //    module's name rather than the source's.  
  385. char *GetModuleName(long ModuleFilePos, LIBHDR *LibHeader, FILE *InLibFH)
  386. {
  387.     int SymbolLength;
  388.     char *ModuleName;
  389.     OMFHEADER OmfHeader;
  390.     // Position at beginning of pertinent object module
  391.     if (fseek(InLibFH, ModuleFilePos, SEEK_SET) != 0)
  392.         Output(Error, NOFILE, "Seek for object module at %lx failed\n", 
  393.                     ModuleFilePos);
  394.     if (LibHeader->IsLIBMODFormat == false) {
  395.         if (fread(&OmfHeader, sizeof(OmfHeader), 1, InLibFH) != 1) 
  396.             Output(Error, NOFILE, "Couldn't Read THEADR at %lx\n", 
  397.                     ModuleFilePos);
  398.         if (OmfHeader.RecType != THEADR)
  399.             Output(Error, NOFILE, "Bogus THEADR OMF record at %lx\n", 
  400.                     ModuleFilePos);
  401.     }
  402.     else
  403.         if (FindLIBMOD(InLibFH) == false) {
  404.             Output(Warning, NOFILE, "No LIBMOD record found at %lx\n", 
  405.                     ModuleFilePos);
  406.             return (NULL);
  407.         }
  408.     SymbolLength = fgetc(InLibFH);
  409.     if ((ModuleName = malloc(SymbolLength + 1)) == NULL)
  410.         Output(Error, NOFILE, "Malloc failure Reading module name\n");
  411.     if (fread(ModuleName, SymbolLength, 1, InLibFH) != 1) 
  412.         Output(Error, NOFILE, "Couldn't Read THEADR\n");
  413.     ModuleName[SymbolLength] = '\0';
  414.     return(ModuleName);
  415. }
  416. //  FindLIBMOD  --  Get a LIBMOD (A3) comment record, if present.
  417. //  NOTE: This is a special OMF COMENT (88h) record comment class used by
  418. //  Microsoft only.  It provides the name of the object modules which may 
  419. //  differ from the source (contained in THEADR). This record is added when an
  420. //  object module is put into library, and stripped out when it's extracted. 
  421. //  This routine will leave file pointer at the LIBMOD name field.
  422. bool FindLIBMOD(FILE *InLibFH)
  423. {
  424.     COMENTHEADER CommentHdr;
  425.     // Search (up to) all COMENT records in OBJ module
  426.     while (FindObjRecord(InLibFH, COMENT) == true) {
  427.         if (fread(&CommentHdr, sizeof(CommentHdr), 1, InLibFH) != 1) 
  428.             Output(Error, NOFILE, "Couldn't Read OBJ\n");
  429.         if (CommentHdr.CommentClass == LIBMOD)
  430.             return (true);
  431.         else
  432.             // if not found: forward to next record, and retry
  433.             if (fseek(InLibFH, (long) CommentHdr.RecLength - è                    sizeof(CommentHdr) + sizeof(OMFHEADER), SEEK_CUR) != 0)
  434.                 Output(Error, NOFILE, "Seek retry for LIBMOD failed\n");
  435.     }
  436.     // We got here only if COMENT of class LIBMOD was never found
  437.     return (false);
  438. }
  439. //  FindObjRecord  --  Find an object module record in one given module.
  440. //  On call, file pointer must be set to an objec record.  Search will
  441. //  quit at the end of current module (or when record found).
  442. bool FindObjRecord(FILE *ObjFH, unsigned char RecType)
  443. {
  444.     OMFHEADER ObjHeader;
  445.     while (fread(&ObjHeader, sizeof(ObjHeader), 1, ObjFH) == 1) {
  446.         // If it's the record type we're looking for, we're done
  447.         if (ObjHeader.RecType == RecType) {
  448.             // Return with obj module set to record requested
  449.             if (fseek(ObjFH, -(long) sizeof(ObjHeader), SEEK_CUR) != 0)
  450.                 Output(Error, NOFILE, "Seek for Record Type %02x failed\n", 
  451.                         RecType & 0xFF);
  452.             return (true);
  453.         }
  454.         // End of object module, record type NEVER found
  455.         if (ObjHeader.RecType == MODEND)
  456.             return (false);
  457.         // Forward file pointer to next object module record
  458.         if (fseek(ObjFH, (long) ObjHeader.RecLength, SEEK_CUR) != 0)
  459.             Output(Error, NOFILE, "Seek retry for Record Type %02x failed\n", 
  460.                         RecType & 0xFF);
  461.     }
  462.     // If this quit due to I/O condition, it's either EOF or I/O error
  463.     if (feof(ObjFH) == 0) 
  464.     Output(Error, NOFILE, "Couldn't Read OBJ\n");
  465.     // we completed w/o error and w/o finding the record (should NEVER happen)
  466.     return (false);
  467. }
  468. //  ExtractModule -- Find an object module in a library and extract it into
  469. //  "stand-alone" object file.  Return true if ok, else false. 
  470. //  Optional: Can specify a new name for the module.
  471. bool ExtractModule(char *ModuleName, char *NewModuleName, LIBHDR *LibHeader, 
  472.         FILE *InLibFH)
  473. {
  474.     long FilePos;
  475.     char *NewObjP;
  476.     char *NewObjName;
  477.     FILE *NewObjFH;
  478.     // Find the object module's position in the library file
  479.     FilePos = FindModule(ModuleName, LibHeader, InLibFH);
  480.     if (FilePos == -1L)
  481.         return (false);
  482.     // Determine name for new .obj, and set it up
  483.     NewObjP = NewModuleName != NULL ? NewModuleName : ModuleName;
  484.     if ((NewObjName = malloc(strlen(NewObjP) + 5)) == NULL)
  485.         Output(Error, NOFILE, "Malloc failure Making module name %s\n",
  486.                 NewObjP);
  487.     strcpy(NewObjName, NewObjP);è    // Open the new .obj file, and pass everything off to low-level routine
  488.     if ((NewObjFH = fopen(NewObjName, "wb")) == NULL)
  489.         Output(Error, NOFILE, "Open failure new module %s\n", NewObjName);
  490.     CopyObjModule(NewObjFH, FilePos, InLibFH);
  491.     fclose(NewObjFH);
  492.     free(NewObjName);
  493.     return (true);
  494. }
  495. //  CopyObjModule  --  Low-level copy of LIB member to OBJ file.
  496. void CopyObjModule(FILE *NewObjFH, long FilePos, FILE *InLibFH)
  497. {
  498.     OMFHEADER RecHdr;
  499.     // Get to the object module in LIB 
  500.     if (fseek(InLibFH, FilePos, SEEK_SET) != 0)
  501.         Output(Error, NOFILE, "Seek failure to file position %ld\n", FilePos);
  502.     // Write module from LIB to separate obj file
  503.     do {
  504.         // Read OMF header record, this will give record type and length
  505.         if (fread(&RecHdr, sizeof(RecHdr), 1, InLibFH) != 1) 
  506.             Output(Error, NOFILE, "Couldn't Read OBJ\n");
  507.         // Need to check every COMENT record to make sure to strip LIBMOD out
  508.         if (RecHdr.RecType == COMENT) {
  509.             // Throw away next byte (Attrib COMENT byte) for now
  510.             fgetc(InLibFH);
  511.             // Check COMENT's Comment Class
  512.             // If it's a LIBMOD, set file pointer ro next record and continue
  513.             if (fgetc(InLibFH) == LIBMOD) {
  514.                if (fseek(InLibFH, (long) RecHdr.RecLength - 2L, SEEK_CUR) != 0)
  515.                     Output(Error, NOFILE, "Seek error on COMENT\n");
  516.                 continue;
  517.             }
  518.             else 
  519.                 // Wasn't a LIBMOD: reset file pointer to continue normally    
  520.                 if (fseek(InLibFH, -2L, SEEK_CUR) != 0)
  521.                     Output(Error, NOFILE, "Seek error on COMENT\n");
  522.         }       
  523.         if (fwrite(&RecHdr, sizeof(RecHdr), 1, NewObjFH) != 1)
  524.             Output(Error, NOFILE, "Couldn't Write new OBJ\n");
  525.         while (RecHdr.RecLength--) 
  526.             fputc(fgetc(InLibFH), NewObjFH);
  527.     } while (RecHdr.RecType != MODEND);
  528. }
  529.  
  530.  
  531.  
  532. [LISTING FIVE]
  533.  
  534. //***** olu1.c  --  Object Library Utility, Sample Application 1. *****
  535. // This utility performs a linear scan and dump of an object module library's
  536. // Symbol Dictionary. NOTE: Due to Borland TLIB bug, this utility may NOT work 
  537. // with libraries generated with versions 3.01 or less.    
  538. //*****************************************************************************
  539. #include <stdio.h>
  540. #include <stdlib.h>
  541. #include "ole.h"è#include "svc.h"
  542.  
  543. static void DumpSymbolDictionary(LIBHDR *LibHeader, FILE *InLibFH);
  544. void main(int argc, char *argv[]);
  545.  
  546. //  main  --   Surprise!
  547. void main(int argc, char *argv[])
  548. {
  549.     FILE *InLibFH;
  550.     LIBHDR LibHeader;
  551.     long ModFilePos;
  552.     if (argc != 2)
  553.         Output(Error, NOFILE, "Usage: %s file.lib\n", argv[0]);
  554.     if ((InLibFH = fopen(argv[1], "rb")) == NULL) 
  555.         Output(Error, NOFILE, "Couldn't Open %s\n", argv[1]);
  556.     GetLibHeader(&LibHeader, InLibFH);
  557.     DumpSymbolDictionary(&LibHeader, InLibFH);
  558. }
  559. //  DumpSymbolDictionary  --  Print out an entire Symbol Dictionary
  560. static void DumpSymbolDictionary(LIBHDR *LibHeader, FILE *InLibFH)
  561. {
  562.     int BlockIdx, BucketIdx;
  563.     DICTENTRY DictEntry;
  564.     char *ModuleName;
  565.     char *SymbolP;
  566.     for (BlockIdx = 0; BlockIdx < LibHeader->NumDictBlocks; BlockIdx++) 
  567.         for (BucketIdx = 0; BucketIdx < NUMBUCKETS; BucketIdx++) {
  568.             DictEntry = GetSymDictEntry(BlockIdx, BucketIdx, LibHeader, 
  569.                     InLibFH);
  570.             if (DictEntry.IsFound == false)
  571.                 continue;
  572.             // Get the symbol name
  573.             SymbolP = MakeASCIIZ(DictEntry.SymbolP); 
  574.             // Get to the corresponding module name record (THEADR or LIBMOD)
  575.             ModuleName = GetModuleName(DictEntry.ModuleFilePos, LibHeader, 
  576.                     InLibFH);
  577.             printf("%s -- Module %s (%08lxh)\n", SymbolP, 
  578.                     ModuleName, DictEntry.ModuleFilePos);
  579.             printf("Hash: Block %d , Bucket %d\n", BlockIdx, BucketIdx);
  580.             free(SymbolP);                           
  581.             free(ModuleName);
  582.         }
  583. }
  584.  
  585.  
  586. [LISTING SIX]
  587.  
  588. //***** olu2.c -- Object Library Utility, Sample Application 2. *****
  589. //  This utility explodes an object module library, i.e. move all its members 
  590. //  out into .obj form. This functionality is absent from popular library 
  591. //  managers; useful for libraries the user is unfamiliar with. Optionally, 
  592. //  named single members can be copied, as well. NOTE: Modules can be 
  593. //  extracted in sequence efficiently, but we're showing off functions!
  594. #include <stdio.h>
  595. #include <stdlib.h>è#include <string.h>
  596. #include "ole.h"
  597. #include "svc.h"
  598.  
  599. static void ExplodeLibrary(LIBHDR *LibHeader, FILE *InLibFH);
  600. void main(int argc, char *argv[]);
  601.  
  602. //  main  --   Surprise!
  603. void main(int argc, char *argv[])
  604. {
  605.     FILE *InLibFH;
  606.     LIBHDR LibHeader;
  607.  
  608.     if (argc != 2 && argc!= 3)
  609.         Output(Error, NOFILE, "Usage: %s file.lib [file.obj]\n", argv[0]);
  610.     if ((InLibFH = fopen(argv[1], "rb")) == NULL) 
  611.         Output(Error, NOFILE, "Couldn't Open %s\n", argv[1]);
  612.     GetLibHeader(&LibHeader, InLibFH);
  613.     if (argc == 3) {
  614.         if (ExtractModule(argv[2], NULL, &LibHeader, InLibFH) == false) 
  615.             Output(Error, NOFILE, "Extraction of Module %s failed\n",
  616.                     argv[2]);
  617.     }
  618.     else
  619.         ExplodeLibrary(&LibHeader, InLibFH);
  620. }
  621. //  Explode Library  -- Extract all (or one specific) library member(s). 
  622. //  NOTE: This is done in a contrived way just to show off some of functions.  
  623. //  We go through entire Symbol Dict., determine if a symbol is a module name 
  624. //  by comparing its entry to the module name that entry is leading to, and 
  625. //  then extract the module.
  626. static void ExplodeLibrary(LIBHDR *LibHeader, FILE *InLibFH)
  627. {
  628.     int BlockIdx, BucketIdx;
  629.     DICTENTRY DictEntry;
  630.     char *ModuleName;
  631.     char *SymbolP;
  632.     char *ModuleFN;
  633.     for (BlockIdx = 0; BlockIdx < LibHeader->NumDictBlocks; BlockIdx++) 
  634.         for (BucketIdx = 0; BucketIdx < NUMBUCKETS; BucketIdx++) {
  635.             DictEntry = GetSymDictEntry(BlockIdx, BucketIdx, LibHeader, 
  636.                     InLibFH);
  637.             if (DictEntry.IsFound == false)
  638.                 continue;
  639.             // Get the symbol name
  640.             SymbolP = MakeASCIIZ(DictEntry.SymbolP); 
  641.             ModuleName = GetModuleName(DictEntry.ModuleFilePos, LibHeader, 
  642.                     InLibFH);
  643.             // If it compares, it's a module name
  644.             if (strnicmp(SymbolP, ModuleName, strlen(ModuleName)) == 
  645.                     STR_EQUAL) {
  646.                 if ((ModuleFN = malloc(strlen(ModuleName) + 4)) == NULL)
  647.                     Output(Error, NOFILE, "Couldn't malloc file name %s\n",
  648.                             ModuleName);
  649.                 strcpy(ModuleFN, ModuleName);è                strcat(ModuleFN, ".obj");
  650.                 if (ExtractModule(ModuleFN, NULL, LibHeader, InLibFH) == 
  651.                         false) 
  652.                     Output(Error, NOFILE, "Extraction of Module %s failed\n",
  653.                             ModuleFN);
  654.                 free(ModuleFN);
  655.             }
  656.             free(SymbolP);                           
  657.             free(ModuleName);
  658.         }
  659. }
  660.