/* SCCSID = %W% %E% */ /* * Copyright Microsoft Corporation, 1983-1987 * * This Module contains Proprietary Information of Microsoft * Corporation and should be treated as Confidential. */ /**************************************************************** * * * LIBRARY PROCESSING ROUTINES * * * ****************************************************************/ #include /* Types and constants */ #include /* Types and constants */ #include /* Types and constants */ #include /* Linker I/O definitions */ #include /* Error messages */ #include /* External declarations */ #include #if OSMSDOS #include /* DOS interface definitions */ #if CPU286 #define INCL_BASE #include /* OS/2 interface definitions */ #if defined(M_I86LM) #undef NEAR #define NEAR #endif #endif #endif #define DICHDR 0xF1 /* Dictionary header type (F1H) */ #if OSXENIX #define ShrOpenRd(f) fopen(f,RDBIN) #endif #if NEWIO #include /* System error codes */ #endif #define PNSORTMAX 512 /* Maximum # modules can be sorted */ typedef struct _edmt /* Extended Dictionary Module Table */ { WORD page; WORD list; } edmt; LOCAL FTYPE fUndefHit; /* found this undef in the library */ LOCAL FTYPE fFileExtracted; /* Took file from library flag */ LOCAL FTYPE fUndefsSeen; /* True if externals seen in library */ LOCAL WORD ipnMac; /* Count of page numbers in sort table */ LOCAL WORD *pnSort; /* Sort table for library page numbers */ /* f(ifh) = pointer to dictionary */ LOCAL WORD mpifhcpnHash[IFHLIBMAX]; /* f(ifh) = # pages in hash table */ LOCAL BYTE mpifhAlign[IFHLIBMAX]; /* f(ifh) = lib alignment factor */ LOCAL RBTYPE vrpNewList; /* List of unprocessed files */ LOCAL FTYPE vfLibOpen; /* Library open flag */ #if M_BYTESWAP OR defined( _WIN32 ) #define getfarword getword /* This assumes no far data */ #else #define getfarword(x) (((WORD FAR *)(x))[0]) #endif /* * INTERFACE WITH ASSEMBLY LANGUAGE FUNCTION */ WORD libAlign; /* Library alignment factor */ WORD libcpnHash; /* Length of hash table in pages */ BYTE FAR *mpifhDict[IFHLIBMAX]; /* * FUNCTION PROTOTYPES */ LOCAL unsigned char NEAR OpenLibrary(unsigned char *sbLib); LOCAL void NEAR FreeDictionary(void); #if CPU8086 OR CPU286 LOCAL WORD NEAR readfar(int fh, char FAR *buf,int n); #endif LOCAL void NEAR GetDictionary(void); LOCAL WORD NEAR GetLib(void); LOCAL void ProcessAnUndef(APROPNAMEPTR papropUndef, RBTYPE rhte, RBTYPE rprop, WORD fNewHte); LOCAL int cdecl FGtNum(const WORD *pn1, const WORD *pn2); LOCAL void NEAR LookMod(edmt *modtab,unsigned short iMod); LOCAL void NEAR LookPage(edmt *modtab,unsigned short cMod,unsigned short page); LOCAL void NEAR ProcExtDic(char *pExtDic); LOCAL char * NEAR GetExtDic(void); #if NEW_LIB_SEARCH /// undef lookaside list typedef struct tag_UND { struct tag_UND * pNext; APROPNAMEPTR papropUndef; DWORD dwLibMask; RBTYPE rhte; } UND; #define C_UNDS_POOL 128 typedef struct tag_UNDPOOL { struct tag_UNDPOOL *pNext; UND und[C_UNDS_POOL]; } UNDPOOL; // pool storage management variables UNDPOOL *pundpoolCur; UNDPOOL *pundpoolHead; int iundPool = C_UNDS_POOL; UND * pundFree; UND * pundListHead; #define FUndefsLeft() (pundListHead != NULL) void StoreUndef(APROPNAMEPTR, RBTYPE, RBTYPE, WORD); #else #define FUndefsLeft() (fUndefsSeen) #endif FTYPE fStoreUndefsInLookaside = FALSE; ///// #if NOASM LOCAL WORD NEAR rolw(WORD x, WORD n) /* Rotate word left */ { return(LO16BITS((x << n) | ((x >> (WORDLN - n)) & ~(~0 << n)))); } LOCAL WORD NEAR rorw(WORD x, WORD n) /* Rotate word right */ { return(LO16BITS((x << (WORDLN - n)) | ((x >> n) & ~(~0 << (WORDLN - n))))); } #endif #if OSMSDOS BSTYPE NEAR ShrOpenRd(pname) char *pname; /* Name of file (null-terminated) */ { int fh; /* File handle */ #if NEWIO if(mpifhfh[ifhLibCur]) { fh = mpifhfh[ifhLibCur]; /* If dictionary not allocated, seek to beginning since we're * somewhere else now. */ if(!mpifhDict[ifhLibCur]) _lseek(fh,0L,0); } else fh = SmartOpen(pname,ifhLibCur); if(fh > 0) { fflush(bsInput); bsInput->_file = (char) fh; return(bsInput); } else return(NULL); #else if((fh = _sopen(pname,O_RDONLY | O_BINARY,SH_DENYWR)) < 0) return(NULL); return(fdopen(fh,RDBIN)); #endif } #endif /* OSMSDOS */ #pragma check_stack(on) /**************************************************************** * * * OpenLibrary: * * * * This function takes as its arguments a pointer to the text * * of the name of the library to open, a count of the bytes in * * that name, an index into a global table in which to place * * the file handle for the opened library. It returns TRUE if * * it succeeds, FALSE if it fails to open the file; and it * * dies gracefully if the file is not a valid library. * * * ****************************************************************/ LOCAL FTYPE NEAR OpenLibrary(sbLib) BYTE *sbLib; /* Library name */ { SBTYPE libnam; /* Library name */ WORD reclen; /* Library header record length */ BSTYPE bsLib; /* File stream pointer for library */ memcpy(libnam,&sbLib[1],B2W(sbLib[0])); /* Copy library name */ libnam[B2W(sbLib[0])] = '\0'; /* Null-terminate name */ /* WARNING: do not assign bsInput to NULL if open fails, it * screws up NEWIO. */ if((bsLib = ShrOpenRd(libnam)) != NULL) { /* If open successful */ bsInput = bsLib; /* If dictionary already allocated, no need to do anything */ if(mpifhDict[ifhLibCur]) return((FTYPE) TRUE); #if OSMSDOS /* Reduce buffer size. We can avoid calling setvbuf() because * everything is set up properly at this point. */ #if OWNSTDIO bsInput->_bsize = 512; #else setvbuf(bsInput, bsInput->_base, _IOFBF, 512); #endif #endif if(getc(bsInput) == LIBHDR) /* If we have a library */ { reclen = (WORD) (3 + WSGets()); /* Get record length */ for(libAlign = 15; libAlign && !(reclen & (1 << libAlign)); --libAlign); /* Calculate alignment factor */ mpifhAlign[ifhLibCur] = (BYTE) libAlign; if(libAlign >= 4 && reclen == (WORD) (1 << libAlign)) { /* Check legality of alignment */ libHTAddr = (long) WSGets(); libHTAddr += (long) WSGets() << WORDLN; /* Get the offset of the hash table */ if (libHTAddr <= 0L) Fatal(ER_badlib,libnam); if ((mpifhcpnHash[ifhLibCur] = WSGets()) <= 0) /* Get size of hash table in pages */ Fatal(ER_badlib,libnam); #if OSMSDOS /* Restore big buffer size. Avoid calling setvbuf(). */ #if OWNSTDIO bsInput->_bsize = LBUFSIZ; #else setvbuf(bsInput, bsInput->_base, _IOFBF, LBUFSIZ); #endif #endif return((FTYPE) TRUE); /* Success */ } } Fatal(ER_badlib,libnam); } return(FALSE); /* Failure */ } #pragma check_stack(off) /* * LookupLibSym: look up a symbol in library dictionary * * The minimum page size is 16, so we can return paragraph offsets. * This is a win because offsets are stored as paragraphs in the * sorting table anyway. Also, the majority of libraries have page * size of 16. * * Parameters: * char *psb - pointer to length-prefixed string * Returns: * Long paragraph offset to location of module which defines * the symbol, or 0L if not found. */ #if NOASM LOCAL WORD NEAR LookupLibSym(psb) BYTE *psb; /* Symbol to look up */ { WORD i1; /* First hash value */ WORD d1; /* First hash delta */ WORD i2; /* Second hash value */ WORD d2; /* Second hash delta */ WORD pn; /* Page number */ WORD dpn; /* Page number delta */ WORD pslot; /* Page slot */ WORD dpslot; /* Page slot delta */ WORD ipn; /* Initial page number */ BYTE FAR *hpg; #if NOASM WORD ch1; /* Character */ WORD ch2; /* Character */ char *pc1; /* Character pointer */ char *pc2; /* Character pointer */ WORD length; /* Symbol length */ #endif #if LIBDEBUG OutSb(stderr,psb); fprintf(stderr," is wanted; dictionary is %d pages\r\n",libcpnHash); #endif #if NOASM length = B2W(psb[0]); /* Get symbol length */ pc1 = (char *) psb; /* Initialize */ pc2 = (char *) &psb[B2W(psb[0])]; /* Initialize */ i1 = 0; /* Initialize */ d1 = 0; /* Initialize */ i2 = 0; /* Initialize */ d2 = 0; /* Initialize */ while(length--) /* Hashing loop */ { ch1 = (WORD) (B2W(*pc1++) | 040);/* Force to lower case */ ch2 = (WORD) (B2W(*pc2--) | 040);/* Force to lower case */ i1 = (WORD) (rolw(i1,2) ^ ch1); /* Hash */ d1 = (WORD) (rolw(d1,2) ^ ch2); /* Hash */ i2 = (WORD) (rorw(i2,2) ^ ch2); /* Hash */ d2 = (WORD) (rorw(d2,2) ^ ch1); /* Hash */ } #else i1 = libhash(psb,&d1,&i2,&d2); /* Hash */ #endif pn = (WORD) (i1 % libcpnHash); /* Calculate page number index */ if(!(dpn = (WORD) (d1 % libcpnHash))) dpn = 1; /* Calculate page number delta */ pslot = (WORD) (i2 % CSLOTMAX); /* Calculate page slot index */ if(!(dpslot = (WORD) (d2 % CSLOTMAX))) dpslot = 1; /* Calculate page slot delta */ #if LIBDEBUG fprintf(stderr,"page index %d, delta %d, bucket index %d, delta %d\r\n", pn,dpn,pslot,dpslot); #endif ipn = pn; /* Remember initial page number */ for(;;) /* Search loop */ { #if LIBDEBUG fprintf(stderr,"Page %d:\r\n",pn); #endif // Get pointer to the dictionary page hpg = mpifhDict[ifhLibCur] + (pn << LG2PAG); for(i2 = 0; i2 < CSLOTMAX; ++i2)/* Loop to check slots */ { #if LIBDEBUG fprintf(stderr,"Bucket %d %sempty, page %sfull\r\n", pslot,hpg[pslot]? "not ": "", B2W(hpg[CSLOTMAX]) == 0xFF? "": "not "); #endif if(!(i1 = (WORD) (B2W(hpg[pslot]) << 1))) { /* If slot is empty */ if(B2W(hpg[CSLOTMAX]) == 0xFF) break; /* If page is full, break */ return(0); /* Search failed */ } #if LIBDEBUG fprintf(stderr," Comparing "); OutSb(stderr,psb); fprintf(stderr," to "); OutSb(stderr,&hpg[i1]); fprintf(stderr," %signoring case\r\n",fIgnoreCase? "": "not "); #endif if(psb[0] == hpg[i1] && SbNewComp(psb,&hpg[i1],fIgnoreCase)) { /* If symbols match */ #if LIBDEBUG fprintf(stderr,"Match found in slot %d\r\n",i2 >> 1); #endif i1 += (WORD) (B2W(hpg[i1]) + 1); /* Skip over name */ i1 = getfarword(&hpg[i1]); /* Get page number of module */ return(i1); /* Return page number of module */ } if((pslot += dpslot) >= CSLOTMAX) pslot -= CSLOTMAX; /* Try next slot */ } if((pn += dpn) >= libcpnHash) pn -= libcpnHash; /* Try next page */ if (ipn == pn) return(0); /* Once around without finding it */ } } #endif /*NOASM*/ /* * FreeDictionary : free space allocated for dictionaries */ LOCAL void NEAR FreeDictionary () { WORD i; for (i = 0; i < ifhLibMac; ++i) if (mpifhDict[i]) FFREE(mpifhDict[i]); } #if CPU8086 OR CPU286 /* * readfar : read() with a far buffer * * Emulate read() except use a far buffer. Call the system * directly. * * Returns: * 0 if error, else number of bytes read. */ LOCAL WORD NEAR readfar (fh, buf, n) int fh; /* File handle */ char FAR *buf; /* Buffer to store bytes in */ int n; /* # bytes to read */ { #if OSMSDOS unsigned bytesread; /* Number of bytes read */ #if CPU8086 if (_dos_read(fh, buf, n, &bytesread)) return(0); return(bytesread); #else if(DosRead(fh,buf,n,(unsigned FAR *) &bytesread)) return(0); return(bytesread); #endif #endif /* OSMSDOS */ #if OSXENIX char mybuf[PAGLEN]; int cppage; char *p; while(n > 0) { cppage = n > PAGLEN ? PAGLEN : n; if(read(fh,mybuf,cppage) != cppage) return(0); n -= cppage; for(p = mybuf; p < mybuf[cppage]; *buf++ = *p++); } #endif } #endif LOCAL void NEAR GetDictionary () { unsigned cb; #if CPU8086 OR CPU286 // If there is more than 128 pages in dictionary return, // because the dictionary is bigger than 64k if (libcpnHash >= 128) return; #endif cb = libcpnHash << LG2PAG; mpifhDict[ifhLibCur] = GetMem(cb); // Go to the dictionary and read it in a single call #if defined(M_I386) || defined( _WIN32 ) fseek(bsInput, libHTAddr, 0); if (fread(mpifhDict[ifhLibCur], 1, cb, bsInput) != (int) cb) Fatal(ER_badlib,1 + GetPropName(FetchSym(mpifhrhte[ifhLibCur],FALSE))); #else _lseek(fileno(bsInput), libHTAddr, 0); if (readfar(fileno(bsInput), mpifhDict[ifhLibCur], cb) != cb) Fatal(ER_badlib,1 + GetPropName(FetchSym(mpifhrhte[ifhLibCur],FALSE))); #endif } #pragma check_stack(on) LOCAL WORD NEAR GetLib(void) /* Open the next library in list */ { AHTEPTR pahteLib; /* Pointer to library name */ #if OSMSDOS SBTYPE sbLib; /* Library name */ SBTYPE sbNew; /* New parts to library name */ #endif if(mpifhrhte[ifhLibCur] == RHTENIL) /* If this library is to be skipped */ { return(FALSE); /* No library opened */ } for(;;) /* Loop to open library */ { pahteLib = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE); /* Get name from hash table */ if(OpenLibrary(GetFarSb(pahteLib->cch))) break; /* Break if lib opened okay */ if(fNoprompt) Fatal(ER_libopn,1 + GetFarSb(pahteLib->cch)); else { sbLib[0] = '\0'; /* No string yet */ UpdateFileParts(sbLib,GetFarSb(pahteLib->cch)); (*pfPrompt)(sbNew,ER_libopn, /* Prompt for new filespec */ (int) (__int64) (1 + GetFarSb(pahteLib->cch)), P_EnterNewFileSpec, 0); } if(fNoprompt || !sbNew[0]) { mpifhrhte[ifhLibCur] = RHTENIL; /* Do not bother next time */ return(FALSE); /* Unsuccessful */ } #if OSMSDOS UpdateFileParts(sbLib,sbNew); /* Update file name with new parts */ PropSymLookup(sbLib,ATTRFIL,TRUE); /* Add library to symbol table */ mpifhrhte[ifhLibCur] = vrhte; /* Save virtual address */ AddLibPath(ifhLibCur); /* Add default path spec, maybe */ #endif } vfLibOpen = (FTYPE) TRUE; /* A library is open */ libcpnHash = mpifhcpnHash[ifhLibCur]; libAlign = mpifhAlign[ifhLibCur]; if (mpifhDict[ifhLibCur] == NULL) /* If dictionary not allocated, do it */ GetDictionary(); return(TRUE); /* Success */ } #pragma check_stack(off) /**************************************************************** * * * ProcessAnUndef: * * * * This function takes as its arguments two pointers, two * * RBTYPEs, and a flag. It does not return a meaningful * * value. Most of the parameters to this function are * * dummies; this function's address is passed as a parameter, * * and its parameter list must match those of all the * * functions whose addresses can be passed as a parameter to * * the same function to which ProcessAnUndef's address is * * passed. Called by EnSyms. * * * ****************************************************************/ LOCAL void ProcessAnUndef(APROPNAMEPTR papropUndef, RBTYPE rhte, RBTYPE rprop__NotUsed__, WORD fNewHte__NotUsed__) { AHTEPTR pahte; /* Pointer to hash table entry */ WORD pn; /* Library page number */ APROPUNDEFPTR pUndef; ATTRTYPE attr; #if NOT NEWSYM SBTYPE sb; /* Undefined symbol */ #endif fUndefHit = FALSE; pUndef = (APROPUNDEFPTR ) papropUndef; attr = pUndef->au_flags; // don't pull out any "weak" externs or unused aliased externals if (((attr & WEAKEXT) && !(attr & UNDECIDED)) || ((attr & SUBSTITUTE) && !(attr & SEARCH_LIB))) { fUndefHit = TRUE; // this item is effectively resolved... return; } fUndefsSeen = (FTYPE) TRUE; /* Set flag */ if(!mpifhDict[ifhLibCur] && !vfLibOpen) return; /* Return if unable to get library */ pahte = (AHTEPTR ) FetchSym(rhte,FALSE); /* Fetch name from symbol table */ #if NOT NEWSYM memcpy(sb,pahte->cch,B2W(pahte->cch[0]) + 1); /* Copy name */ #endif #if LIBDEBUG fprintf(stdout,"Looking for '%s' - ", 1+GetFarSb(pahte->cch)); fflush(stdout); #endif #if NEWSYM if(pn = LookupLibSym(GetFarSb(pahte->cch))) #else if(pn = LookupLibSym(sb)) /* If symbol defined in this library */ #endif { fUndefHit = TRUE; #if LIBDEBUG fprintf(stdout,"Symbol found at page %xH\r\n", pn); fflush(stdout); #endif /* We now try to stuff the page number (pn) into a table that will * be sorted later. */ if (ipnMac < PNSORTMAX) { pnSort[ipnMac++] = pn; return; } /* * No room to save the file offset so save file directly. */ pahte = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE); /* * If SaveInput returns 0, then module was seen before. Means * that dictionary says symbol is defined in this module but * for some reason, such as IMPDEF, the definition wasn't * accepted. In this case, we return. */ if(!SaveInput(GetFarSb(pahte->cch), (long)pn << libAlign, ifhLibCur, 0)) return; /* * If first module extracted, save start of file list. */ if(!fFileExtracted) { vrpNewList = vrpropTailFile; fFileExtracted = (FTYPE) TRUE; } } #if LIBDEBUG else { fprintf(stdout, "Symbol NOT found\r\n"); /* Debug message */ fflush(stdout); } #endif } #if NEW_LIB_SEARCH void StoreUndef(APROPNAMEPTR papropUndef, RBTYPE rhte, RBTYPE rprop, WORD fNewHte) { UND * pund; APROPUNDEFPTR pUndef; ATTRTYPE attr; pUndef = (APROPUNDEFPTR ) papropUndef; attr = pUndef->au_flags; // don't pull out any "weak" externs or unused aliased externals if (((attr & WEAKEXT) && !(attr & UNDECIDED)) || ((attr & SUBSTITUTE) && !(attr & SEARCH_LIB))) return; #ifdef LIBDEBUG { AHTEPTR pahte; pahte = (AHTEPTR) FetchSym(rhte,FALSE); fprintf(stdout,"Adding '%s'\r\n", 1+GetFarSb(pahte->cch)); fflush(stdout); } #endif if (pundFree) // check free list { pund = pundFree; pundFree = pundFree->pNext; } else if (iundPool < C_UNDS_POOL) // check pool { pund = &pundpoolCur->und[iundPool]; iundPool++; } else { // allocate new pool... pundpoolCur = (UNDPOOL *)GetMem(sizeof(UNDPOOL)); pundpoolCur->pNext = pundpoolHead; pundpoolHead = pundpoolCur; pund = &pundpoolCur->und[0]; iundPool = 1; // entry zero is already used up } pund->dwLibMask = 0; pund->pNext = pundListHead; pund->papropUndef = papropUndef; pund->rhte = rhte; pundListHead = pund; } #endif /* * Greater-than comparator to be used by Sort routine. */ LOCAL int cdecl FGtNum(const WORD *pn1, const WORD *pn2) { if (*pn1 < *pn2) return(-1); if (*pn1 > *pn2) return(1); return(0); } /************************************************************************ * Extended Dictionary * * The extended dictionary occurs at the end of the regular dictionary * and contains a first-level dependency tree for all the modules * in the library. ************************************************************************/ #define LIBEXD 0xf2 /* Library EXtended Dictionary */ /**************************************************************** * * * Extended Dictionary Format: * * * * * * BYTE =0xF2 Extended Dictionary header * * WORD length of extended dictionary in bytes * * excluding 1st 3 bytes * * * * Start of ext. dictionary: * * * * WORD number of modules in library = N * * * * Module table, indexed by module number, with N + 1 fixed- * * length entries: * * * * WORD module page number * * WORD offset from start of ext. dictionary to list * * of required modules * * * * Last entry is null. * * * * Module dependency lists, N variable-length lists: * * * * WORD list length (number of required modules) * * WORD module index, 0-based; this is index to module * * . . . table at the begin of ext. dictionary. * * . . . * * * * * ****************************************************************/ #pragma loop_opt(on) /* * LookMod : look up a module by index in the extended dictionary * * Get the list of modules required by the given module. If not * already marked, save index in sorting table (which will be * converted to page number later) and mark the entry in the * module table as seen by setting the low bit of the list offset. * * Parameters: * modtab: Pointer to module table * iMod: Index into table, 0-based */ LOCAL void NEAR LookMod (edmt *modtab, WORD iMod) { WORD *pw; /* Pointer to list of indexes */ WORD n; /* List counter */ /* * Get the pointer to the list. Mask off low bit since it is used * as a marker. */ pw = (WORD *) ((char *) modtab + (modtab[iMod].list & ~1)); /* * For every entry in the list, if the corresponding entry in the * module table is not marked, save the index in pnSort and mark * the entry in the module table. */ for(n = *pw++; n--; pw++) { if(!(modtab[*pw].list & 1)) { /* * Check for table overflow. */ if(ipnMac == PNSORTMAX) return; pnSort[ipnMac++] = *pw; modtab[*pw].list |= 1; } } } /* * LookPage : Look up a module in the module table by page number * * Use binary search. If page is found, call LookMod() on the * matching entry. * * Parameters: * modtab: Pointer to module table * cMod: Number of entries in table * page: Page number * ASSUMES: * The highest entry in the table has a page number of 0xffff. */ LOCAL void NEAR LookPage (edmt *modtab, WORD cMod, WORD page) { WORD mid; /* Current mid point */ WORD lo, hi; /* Current low and high points */ lo = 0; /* Table is 0-based. */ hi = (WORD) (cMod - 1); while(lo <= hi) { if(modtab[mid = (WORD) ((lo + hi) >> 1)].page == page) { modtab[mid].list |= 1; LookMod(modtab,mid); return; } else if(modtab[mid].page < page) lo = (WORD) (mid + 1); else hi = (WORD) (mid - 1); } } #pragma loop_opt(off) /* * ProcExtDic : Process Extended Dictionary * * Store in pnSort all the secondary modules required by * the modules obtained from the regular dictionary lookup. * * Parameters: * pExtDic: Pointer to extended dictionary */ LOCAL void NEAR ProcExtDic (pExtDic) char *pExtDic; { WORD *p; WORD *pEnd; WORD cMod; edmt *modtab; cMod = getword(pExtDic); modtab = (edmt *) (pExtDic + 2); /* For the binary search algorithm, we make an artifical last entry * with a page # at least as high as anything else. */ modtab[cMod].page = 0xffff; /* Process by page numbers */ for(p = pnSort, pEnd = &pnSort[ipnMac]; p < pEnd; ++p) LookPage(modtab, cMod, *p); /* Now pnSort from pEnd to lfaSort[ipnMac] contains module * index numbers. Process by index number and convert to page. */ for( ; p < &pnSort[ipnMac]; ++p) { LookMod(modtab,*p); *p = modtab[*p].page; } } /* * GetExtDic - Get Extended Dictionary */ LOCAL char * NEAR GetExtDic () { char *p; int length; if(!vfLibOpen) if(!GetLib()) return(NULL); /* WARNING: we must just have read dictionary for this to work, * otherwise an fseek() is required here. */ if (!mpifhDict[ifhLibCur]) { fflush(bsInput); fseek(bsInput, libHTAddr + (libcpnHash << LG2PAG), 0); } if(getc(bsInput) != LIBEXD) return(NULL); if((p = GetMem(length = WSGets())) != NULL) if(fread(p,1,length,bsInput) != length) { FreeMem(p); p = NULL; } return(p); } char *pExtDic = NULL; /* Pointer to extended dictionary */ /**************************************************************** * * * LibrarySearch: * * * * This function takes no arguments. It searches all open * * libraries to resolve undefined externals. It does not * * return a meaningful value. * * * ****************************************************************/ void NEAR LibrarySearch(void) { RBTYPE vrpTmpFileFirst; WORD ifhLibMacInit; /* Initial number of libs to search */ FTYPE searchMore; /* Search continue flag */ WORD bufpnSort[PNSORTMAX]; /* Actual space for pnSort */ SBTYPE sbLibname; /* Name of current library */ AHTEPTR pahte; /* Pointer to hash table entry */ REGISTER WORD i; FTYPE fLibPass1 = (FTYPE) TRUE; /* True if on 1st pass thru libs */ FTYPE *fUsedInPass1; /* True if lib used in 1st pass thru libs */ FTYPE fFirstTime; /* True if lib seen for the first time */ extern FTYPE fNoExtDic; /* True if /NOEXTDICTIONARY */ #if NEW_LIB_SEARCH UND *pund; /* pointer in undef lookaside list */ UND *pundPrev; /* pointer to previous undef entry */ UND *pundNext; /* pointer to next undef entry */ #endif fUndefsSeen = (FTYPE) TRUE; /* There are undefined externals */ vfLibOpen = FALSE; /* No libraries open yet */ pnSort = bufpnSort; /* Initialize sort table pointer */ ifhLibMacInit = ifhLibMac; fUsedInPass1 = (FTYPE *) GetMem(ifhLibMac * sizeof(FTYPE)); if (fUsedInPass1 != NULL) memset(fUsedInPass1, TRUE, ifhLibMac); #if NEW_LIB_SEARCH // build up the the lookaside list EnSyms(StoreUndef,ATTRUND); fStoreUndefsInLookaside = TRUE; #endif do /* Loop to search libraries */ { searchMore = FALSE; /* Assume on final pass */ for(ifhLibCur = 0; ifhLibCur < ifhLibMac && FUndefsLeft(); ++ifhLibCur) { /* While undefs and libraries */ #if NEW_LIB_SEARCH DWORD libMask = (1<dwLibMask & libMask) continue; // no need to search this library // the first item in the list has already // been searched... #endif if(!GetLib()) continue; /* * If this is first pass through the libraries and /NOEXT was * not given, try to get the extended dictionary. We assume that * if there is one then only one library pass is needed. */ if(fLibPass1 && !fNoExtDic) pExtDic = GetExtDic(); else pExtDic = NULL; /* If no extended dictionary, reduce buffer size because more * seeking will be done. This will affect remaining libraries * in search; we don't care about mixed extended and non- * extended libraries. */ if(!pExtDic) setvbuf(bsInput,bsInput->_base,_IOFBF,1024); pahte = (AHTEPTR ) FetchSym(mpifhrhte[ifhLibCur],FALSE); /* Get library name */ memcpy(sbLibname,GetFarSb(pahte->cch),B2W(pahte->cch[0])+1); #if WIN_3 OR C8_IDE sbLibname[B2W(*sbLibname)+1] = '\0'; #endif #if WIN_3 StatMsgWin( "%s\r\n", sbLibname+1); #endif #if C8_IDE if(fC8IDE) { sprintf(msgBuf, "@I4%s\r\n", sbLibname+1); _write(fileno(stderr), msgBuf, strlen(msgBuf)); } #endif fFirstTime = (FTYPE) TRUE; while(FUndefsLeft()) /* While there are undefs seen */ { fFileExtracted = FALSE; /* Assume we won't take anything */ fUndefsSeen = FALSE; /* Assume no more undefs */ ipnMac = 0; /* Initialize sort table count */ #if NOT NEW_LIB_SEARCH EnSyms(ProcessAnUndef,ATTRUND); #else pund = pundListHead; pundPrev = NULL; while (pund) { if (pund->dwLibMask & libMask) { break; // since items are added to the head, // as soon as we find one item that has // already been searched, the rest have // also already been searched... // pundPrev = pund; // pund = pund->pNext; // continue; } pundNext = pund->pNext; if (pund->papropUndef->an_attr == ATTRUND) ProcessAnUndef(pund->papropUndef, pund->rhte, 0, 0); else fUndefHit = TRUE; // no longer undefined -- remove if (fUndefHit) { // remove this item from the undef list... if (pundPrev) pundPrev->pNext = pundNext; else pundListHead = pundNext; pund->pNext = pundFree; pundFree = pund; } else { pund->dwLibMask |= libMask; pundPrev = pund; } pund = pundNext; } #endif /* Try to resolve references */ /* If no modules obtained, exit loop. */ if(!ipnMac) { #if NEWIO if (fLibPass1) { /* * If this library is seen for the first time in * the first pass thru libraries and we don't * pull out any modules from it, then close this * library, because there are big chances this * library is not needed. */ if (fFirstTime) { _close(mpifhfh[ifhLibCur]); mpifhfh[ifhLibCur] = 0; /* * Mark it also as not used in pass 1 * so, we can closed it also in the * next passes thru libs. */ if (fUsedInPass1) fUsedInPass1[ifhLibCur] = FALSE; } } else if (fUsedInPass1 && !fUsedInPass1[ifhLibCur]) { /* * In pass "n" thru libs close libraries * not used in pass 1. */ _close(mpifhfh[ifhLibCur]); mpifhfh[ifhLibCur] = 0; } #endif break; } fFirstTime = FALSE; /* No longer first time seen */ /* If extended dictionary present, process it. */ if(pExtDic) ProcExtDic(pExtDic); /* Sort modules by page offset. */ qsort(pnSort, ipnMac, sizeof(WORD), (int (__cdecl *)(const void *, const void *)) FGtNum); /* * Save each module represented in the table. */ for (i = 0; i < ipnMac; i++) { /* * If SaveInput returns 0, the module was already seen. See * above comment in ProcessAnUndef(). */ if(!SaveInput(sbLibname, (long)pnSort[i] << libAlign, ifhLibCur, 0)) continue; if(!fFileExtracted) /* If no files extracted yet */ { vrpNewList = vrpropTailFile; /* Save start of file list */ fFileExtracted = (FTYPE) TRUE; /* We have extracted a file */ } } if(!fFileExtracted) break; /* If we didn't take anything, break */ /* Library might not be open because we may have searched * an already-loaded dictionary. If necessary, re-open * library. */ if(!vfLibOpen) GetLib(); searchMore = (FTYPE) TRUE; /* Otherwise it's worth another pass */ vrpTmpFileFirst = rprop1stFile; /* Save head of module list */ rprop1stFile = vrpNewList; /* Put new modules at head of list */ fLibPass = (FTYPE) TRUE; /* Processing object from library */ DrivePass(ProcP1); /* Do pass 1 on object from library */ fLibPass = FALSE; /* No longer processing lib. object */ rprop1stFile = vrpTmpFileFirst; /* Restore original head of list */ if (fUsedInPass1 && ifhLibMacInit < ifhLibMac) { /* DrivePass added more libraries to search */ /* Reallocate fUsedInPass1 */ FTYPE *p; /* Temporary pointer */ p = (FTYPE *) GetMem(ifhLibMac * sizeof(FTYPE)); if (p == NULL) { FFREE(fUsedInPass1); fUsedInPass1 = NULL; } else { memset(p, TRUE, ifhLibMac); memcpy(p, fUsedInPass1, ifhLibMacInit); FFREE(fUsedInPass1); fUsedInPass1 = p; } ifhLibMacInit = ifhLibMac; } } /* Free space for extended dictionary if present */ if(pExtDic) FFREE(pExtDic); if(vfLibOpen) { #if NOT NEWIO fclose(bsInput); /* Close the library */ #endif vfLibOpen = FALSE; /* No library open */ } } /* No longer on 1st pass thru libraries. */ fLibPass1 = FALSE; } while(searchMore && FUndefsLeft()); /* Do until search done */ FreeMem(fUsedInPass1); FreeDictionary(); /* Free dictionary space */ /* * Restore large buffer size in case it was reduced. */ setvbuf(bsInput,bsInput->_base,_IOFBF,LBUFSIZ); #if NEW_LIB_SEARCH fStoreUndefsInLookaside = FALSE; while (pundpoolHead) { pundpoolCur = pundpoolHead->pNext; FFREE(pundpoolHead); pundpoolHead = pundpoolCur; } #endif } #if CMDMSDOS /* * GetLibAll: * * Process all the modules in a given library in Pass 1. * Create property cells for them and insert into the file list. */ void NEAR GetLibAll(sbLib) BYTE *sbLib; { WORD ifh; /* (fake) library index */ long lfa; /* Current file offset */ IOVTYPE iov; /* Overlay number */ RBTYPE rbFileNext; /* Pointer to next file property */ RBTYPE rbFileNew; /* Pointer to new file property */ APROPFILEPTR apropFile, apropFilePrev; BYTE *sbInput; /* Asciiz filename */ int fh; /* File handle */ fDrivePass = FALSE; sbInput = sbLib + 1; /* Get the ifh, iov, and pointer to the next file from the current * file pointer. */ apropFile = (APROPFILEPTR ) FetchSym(vrpropFile,TRUE); ifh = apropFile->af_ifh; iov = apropFile->af_iov; rbFileNext = apropFile->af_FNxt; #if NEWIO fh = SmartOpen(sbInput,ifh); if (fh <= 0 && lpszLIB != NULL) fh = SearchPathLink(lpszLIB, sbInput, ifh, TRUE); if (fh > 0) { fflush(bsInput); bsInput->_file = (char) fh; } else Fatal(ER_fileopn,sbInput); #else if((bsInput = fopen(sbInput,RDBIN)) == NULL) Fatal(ER_fileopn,sbInput); #endif if(getc(bsInput) != LIBHDR) /* Check for valid record type */ Fatal(ER_badlib,sbInput); cbRec = (WORD) (3 + WSGets()); /* Get record length */ for(libAlign = 15; libAlign && !(cbRec & (1 << libAlign)); --libAlign); /* Calculate alignment factor */ fDrivePass = (FTYPE) TRUE; /* Reset current file's lfa from 0 to offset of 1st module */ apropFile->af_lfa = lfa = 1L << libAlign; /* Go to the first module */ fseek(bsInput,lfa,0); /* Process the library as follows: Process the current module. * Go to the next module; if it starts with DICHDR then we're * done. Else, create a new file property cell for the next * module, insert it in the file list, and go to start of loop. */ rect = (WORD) getc(bsInput); while (rect != DICHDR) { ungetc(rect, bsInput); lfaLast = apropFile->af_lfa = ftell(bsInput); ProcP1(); while (TYPEOF(rect) != MODEND) { rect = (WORD) getc(bsInput); fseek(bsInput, (cbRec = WSGets()), 1); } do { rect = (WORD) getc(bsInput); } while (rect != THEADR && rect != DICHDR && rect != EOF); if (rect == DICHDR) { if (rbFileNext == RHTENIL) vrpropTailFile = vrpropFile; #if NOT NEWIO fclose(bsInput); #else rbFilePrev = vrpropFile; #endif return; } if (rect == EOF) Fatal(ER_libeof); // Make a new file property cell apropFile = (APROPFILEPTR ) PropAdd(vrhteFile, ATTRFIL); rbFileNew = vrprop; #if ILINK apropFile->af_imod = ++imodCur; // allocate a module number apropFile->af_cont = 0; apropFile->af_ientOnt = 0; #endif apropFile->af_rMod = 0; apropFile->af_ifh = (char) ifh; apropFile->af_iov = (IOVTYPE) iov; apropFile->af_FNxt = rbFileNext; #if SYMDEB apropFile->af_publics = NULL; apropFile->af_Src = NULL; apropFile->af_SrcLast = NULL; apropFile->af_cvInfo = NULL; #endif apropFile->af_ComDat = 0L; apropFile->af_ComDatLast = 0L; MARKVP(); // Get the just-processed property file cell apropFilePrev = (APROPFILEPTR ) FetchSym(vrpropFile,TRUE); apropFilePrev->af_FNxt = rbFileNew; vrpropFile = rbFileNew; }; // Remove an empty Lib from the chain of files if (vrpropFile == rprop1stFile) { // If the empty lib is first on list rprop1stFile = rbFileNext; } else { #if NEWIO apropFilePrev = (APROPFILEPTR)FetchSym(rbFilePrev, TRUE); apropFilePrev->af_FNxt = apropFile->af_FNxt; #endif } #if NEWIO if (rbFileNext == RHTENIL) vrpropTailFile = rbFilePrev; // In case we removed the last file _close(fileno(bsInput)); rbFilePrev = vrpropFile; #endif } #endif /*CMDMSDOS*/