1355 lines
46 KiB
C
1355 lines
46 KiB
C
|
/* 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 <minlit.h> /* Types and constants */
|
||
|
#include <bndtrn.h> /* Types and constants */
|
||
|
#include <bndrel.h> /* Types and constants */
|
||
|
#include <lnkio.h> /* Linker I/O definitions */
|
||
|
#include <lnkmsg.h> /* Error messages */
|
||
|
#include <extern.h> /* External declarations */
|
||
|
#include <stdlib.h>
|
||
|
#if OSMSDOS
|
||
|
#include <dos.h> /* DOS interface definitions */
|
||
|
#if CPU286
|
||
|
#define INCL_BASE
|
||
|
#include <os2.h> /* 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 <errno.h> /* 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<<ifhLibCur);
|
||
|
|
||
|
if (pundListHead->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*/
|