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