windows-nt/Source/XPSP1/NT/sdktools/link16/newsym.c

847 lines
33 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
* Copyright Microsoft Corporation, 1983-1989
*
* This Module contains Proprietary Information of Microsoft
* Corporation and should be treated as Confidential.
*/
/*
* NEWSYM.C -- Symbol table routine.
*
* Modifications:
*
* 05-Jan-1989 RB Delete MaskSymbols hack.
*/
#include <minlit.h> /* Types and constants */
#include <bndtrn.h> /* More types and constants */
#include <bndrel.h> /* More types and constants */
#include <lnkio.h> /* Linker I/O definitions */
#include <lnkmsg.h> /* Error messages */
#include <extern.h> /* External declarations */
#if NEWSYM
#if OSXENIX
#define _osmode 1 /* Xenix is always protect mode */
#endif
#endif /* NEWSYM */
#ifndef IRHTEMAX
#ifdef DOSX32
#define IRHTEMAX 16384
#else
#define IRHTEMAX 256
#endif
#endif
LOCAL WORD IHashKey(BYTE *psb);
LOCAL PROPTYPE CreateNewSym(WORD irhte, BYTE *psym, ATTRTYPE attr);
#if AUTOVM
LOCAL RBTYPE AllocVirtMem(WORD cb);
LOCAL FTYPE fVirtualAllocation = FALSE;
#endif
#define _32k 0x8000
typedef struct _SymTabBlock
{
struct _SymTabBlock FAR *next;
WORD size;
WORD used;
BYTE FAR *mem;
}
SYMTABBLOCK;
SYMTABBLOCK *pSymTab;
SYMTABBLOCK FAR *pCurBlock;
#if NOT NEWSYM
BYTE symtab[CBMAXSYMSRES];
/* Resident portion of symbol table */
#endif
LOCAL BYTE mpattrcb[] = /* Attribute size have to be <= 255 */
/* Map attribute to struct size */
{
3,
CBPROPSN, /* Size of APROPSNTYPE */
CBPROPSN, /* Size of APROPSNTYPE */
(CBPROPNAME>CBPROPUNDEF)? CBPROPNAME: CBPROPUNDEF,
/* Max(CBPROPNAME,CBPROPUNDEF) */
(CBPROPNAME>CBPROPUNDEF)? CBPROPNAME: CBPROPUNDEF,
/* Max(CBPROPNAME,CBPROPUNDEF) */
CBPROPFILE, /* Size of APROPFILETYPE */
CBPROPGROUP, /* Size of APROPGROUPTYPE */
(CBPROPNAME>CBPROPUNDEF)? CBPROPNAME: CBPROPUNDEF,
/* Max(CBPROPNAME,CBPROPUNDEF) */
CBHTE, /* Size of AHTETYPE */
CBPROPCOMDAT, /* Size of APROPCOMDAT */
CBPROPALIAS, /* Size of APROPALIAS */
#if OSEGEXE
/* These two are always at the end */
/* Adding something make sure that */
/* this stays that way */
CBPROPEXP, /* Size of APROPEXPTYPE */
CBPROPIMP, /* Size of APROPIMPTYPE */
#endif
3
};
#if NEWSYM AND (CPU8086 OR CPU286 OR DOSEXTENDER)
LOCAL WORD cbMaxBlk; /* # bytes available in block */
LOCAL WORD cbMacBlk; /* # bytes allocated in block */
LOCAL WORD saBlk; /* Address of current block */
#endif
/*
* INTERFACE TO ASSEMBLY LANGUAGE FUNCTIONS
*/
#if NEWSYM AND (CPU8086 OR CPU286 OR DOSEXTENDER)
WORD saFirst; /* Address of 1st block */
#endif
RBTYPE rgrhte[IRHTEMAX];
/* Symbol hash table */
/****************************************************************
* *
* InitSym: *
* *
* This function takes no arguments and returns no meaningful *
* value. It initializes the symbol table handler. *
* *
****************************************************************/
void InitSym(void) /* Initialize symbol table handler */
{
// Allocate first symbol table memory block
pSymTab = (SYMTABBLOCK FAR *) GetMem(sizeof(SYMTABBLOCK));
pSymTab->mem = (BYTE FAR *) GetMem(_32k);
pSymTab->size = _32k;
pSymTab->used = 0;
pCurBlock = pSymTab;
}
#if AUTOVM
/****************************************************************
* *
* FetchSym: *
* *
* This function fetches a symbol from the symbol table given *
* its virtual address. The symbol may either be resident or *
* in virtual memory. *
* *
****************************************************************/
BYTE FAR * NEAR FetchSym(rb, fDirty)
RBTYPE rb; /* Virtual address */
WORD fDirty; /* Dirty page flag */
{
union {
long vptr; /* Virtual pointer */
BYTE FAR *fptr; /* FAR pointer */
struct {
unsigned short offset;
/* Offset value */
unsigned short seg;
} /* Segmnet value */
ptr;
}
pointer; /* Different ways to describe pointer */
pointer.fptr = rb;
if(pointer.ptr.seg) /* If resident - segment value != 0 */
{
picur = 0; /* Picur not valid */
return(pointer.fptr); /* Return pointer */
}
pointer.fptr = (BYTE FAR *) mapva(AREASYMS + (pointer.vptr << SYMSCALE),fDirty);
/* Fetch from virtual memory */
return(pointer.fptr);
}
#endif
/****************************************************************
* *
* IHashKey: *
* *
* This function hashes a length-prefixed string and returns *
* hash value. *
* *
****************************************************************/
#if NOASM
#define FOUR_BYTE_HASH
#ifdef FOUR_BYTE_HASH
LOCAL WORD IHashKey(psb)
BYTE *psb; /* Pointer to length-prefixed string */
{
unsigned cb = *psb++;
unsigned hash = cb;
while (cb >= sizeof(unsigned))
{
hash = ((hash >> 28) | (hash << 4)) ^ (*(unsigned UNALIGNED *)psb | 0x20202020);
cb -= sizeof(unsigned);
psb += sizeof(unsigned);
}
while (cb)
{
hash = ((hash >> 28) | (hash << 4)) ^ (*psb++ | 0x20);
cb--;
}
return ((WORD)hash) ^ (WORD)(hash>>16);
}
#else
LOCAL WORD IHashKey(psb)
BYTE *psb; /* Pointer to length-prefixed string */
{
#if defined(M_I386)
_asm
{
push edi ; Save edi
push esi ; Save esi
mov ebx, psb ; ebx = pointer to length prefixed string
xor edx, edx
mov dl, byte ptr [ebx] ; edx = string length
mov edi, edx ; edi = hash value
mov esi, ebx
add esi, edx ; esi = &psb[psb[0]]
std ; Loop down
HashLoop:
xor eax, eax
lodsb ; Get char from DS:ESI into AL
or eax, 0x20
mov cl, dl
and cl, 3
shl eax, cl
add edi, eax
dec edx
jg HashLoop ; Allow for EDX = -1 here so we don't have to special-case null symbol.
cld
mov eax, edi ; eax = hash value
pop esi
pop edi
}
#else
REGISTER WORD i; /* Index */
REGISTER WORD hashval; /* Hash value */
/* NOTE: IRHTEMAX MUST BE 256 OR THIS FUNCTION WILL FAIL */
hashval = B2W(psb[0]); /* Get length as initial hash value */
#if DEBUG
fputs("Hashing ",stderr); /* Message */
OutSb(stderr,psb); /* Symbol */
fprintf(stderr," length %d\r\n",hashval);
/* Length */
#endif
for(i = hashval; i; --i) /* Loop through string */
{
/*
* Old hash function:
*
* hashval = rorb(hashval,2) ^ (B2W(psb[i]) | 040);
*/
hashval += (WORD) ((B2W(psb[i]) | 040) << (i & 3));
/* Hash */
}
#if DEBUG
fprintf(stderr,"Hash value: %u\r\n",hashval);
#endif
#if IRHTEMAX == 512
return((hashval & 0xfeff) | ((psb[0] & 1) << 8));
#else
return(hashval); /* Return value */
#endif
#endif // M_I386
}
#endif /*FOUR_BYTE_HASH*/
#endif /*NOASM*/
#if AUTOVM
/****************************************************************
* *
* AllocVirtMem: *
* *
* This function takes as its input a WORD n, and it allocates *
* n continguous bytes in the symbol area and returns a *
* virtual pointer to the first of those bytes. The bytes *
* are guaranteed to reside on the same virtual page. *
* *
****************************************************************/
LOCAL RBTYPE AllocVirtMem(cb)
WORD cb;
{
WORD rbLimVbf; /* End of current page */
WORD rb; /* Address of allocated bytes */
WORD x;
ASSERT(cb <= PAGLEN); /* Cannot alloc. more than 512 bytes */
x = cb;
cb = (WORD) ((cb + (1 << SYMSCALE) - 1) >> SYMSCALE);
/* Determine number of units wanted */
if(rbMacSyms > (WORD) (0xFFFF - cb)) Fatal(ER_symovf);
/* Check for symbol table overflow */
rbLimVbf = (rbMacSyms + (1 << (LG2PAG - SYMSCALE)) - 1) &
(~0 << (LG2PAG - SYMSCALE)); /* Find limit of current page */
if((WORD) (rbMacSyms + cb) > rbLimVbf && rbLimVbf) rbMacSyms = rbLimVbf;
/* If alloc. would cross page
* boundary, start with new page
*/
rb = rbMacSyms; /* Get address to return */
rbMacSyms += cb; /* Update pointer to end of area */
#if FALSE
fprintf(stderr,"Allocated %u bytes at VA %x\r\n",cb << SYMSCALE,rb);
#endif
return((BYTE FAR *) (long) rb);
/* Return the address */
}
#endif
/*** RbAllocSymNode - symbol table memory allocator
*
* Purpose:
* This function takes as its input a WORD n, and it allocates
* n continguous bytes in the symbol area and returns a
* pointer to the first of those bytes. The bytes are
* guaranteed to reside on the same virtual page (when not in
* memory).
*
*
* Input:
* cb - number of bytes to allocate
*
* Output:
* Pointer to allocated memory area. Pointer can be real or virtual.
*
* Exceptions:
* I/O error in temporary file used for VM.
*
* Notes:
* Uses differnet strategy depending under which operating system
* memory is allocated.
*
*************************************************************************/
RBTYPE NEAR RbAllocSymNode(WORD cb)
{
SYMTABBLOCK FAR *pTmp;
RBTYPE rb; /* Address of allocated bytes */
#if defined( _WIN32 )
// Round up allocation size to keep returned pointers
// at least DWORD aligned.
cb = ( cb + sizeof(DWORD) - 1 ) & ~( sizeof(DWORD) - 1 );
#endif // _WIN32
if ((WORD) (pCurBlock->used + cb) >= pCurBlock->size)
{
// Allocate new symbol table memory block
pTmp = (SYMTABBLOCK FAR *) GetMem(sizeof(SYMTABBLOCK));
pTmp->mem = (BYTE FAR *) GetMem(_32k);
pTmp->size = _32k;
pTmp->used = 0;
pCurBlock->next = pTmp;
pCurBlock = pTmp;
}
// Sub-allocated in the current block
rb = (RBTYPE) &(pCurBlock->mem[pCurBlock->used]);
pCurBlock->used += cb;
cbSymtab += cb;
return(rb);
}
void FreeSymTab(void)
{
SYMTABBLOCK FAR *pTmp;
SYMTABBLOCK FAR *pNext;
FFREE(mplnamerhte);
FFREE(mpsegraFirst);
FFREE(mpgsndra);
FFREE(mpgsnrprop);
FFREE(mpsegsa);
FFREE(mpgsnseg);
FFREE(mpseggsn);
for (pTmp = pSymTab; pTmp != NULL;)
{
pNext = pTmp->next;
FFREE(pTmp->mem);
FFREE(pTmp);
pTmp = pNext;
}
}
/****************************************************************
* *
* PropAdd: *
* *
* This function adds a property to a hash table entry node. *
* It returns the location of the property. Inputs are the *
* virtual address of the hash table entry and the attribute *
* (or property) to be added. *
* *
****************************************************************/
PROPTYPE NEAR PropAdd(rhte,attr)
RBTYPE rhte; /* Virtual addr of hash tab ent */
ATTRTYPE attr; /* Attribute to add to entry */
{
REGISTER AHTEPTR hte; /* Hash table entry pointer */
REGISTER APROPPTR aprop; /* Property list pointer */
RBTYPE rprop; /* Property cell list pointer */
DEBUGVALUE(rhte); /* Debug info */
DEBUGVALUE(attr); /* Debug info */
hte = (AHTEPTR ) FetchSym(rhte,TRUE);
/* Fetch from VM */
DEBUGVALUE(hte); /* Debug info */
rprop = hte->rprop; /* Save pointer to property list */
vrprop = RbAllocSymNode(mpattrcb[attr]);
/* Allocate symbol space */
hte->rprop = vrprop; /* Complete link */
aprop = (APROPPTR ) FetchSym(vrprop,TRUE);
/* Fetch the property cell */
FMEMSET(aprop,'\0',mpattrcb[attr]); /* Zero the space */
aprop->a_attr = attr; /* Store the attribute */
aprop->a_next = rprop; /* Set link */
#if NEW_LIB_SEARCH
if (attr == ATTRUND && fStoreUndefsInLookaside)
StoreUndef((APROPNAMEPTR)aprop, rhte, 0, 0);
#endif
return((PROPTYPE) aprop); /* Return pointer */
}
/****************************************************************
* *
* PropRhteLookup: *
* *
* "Look up a property on hash table entry (possibly creating *
* it) and return pointer to property. *
* *
* Input: rhte Virtual address of hash table entry. *
* attr Property to look up. *
* fCreate Flag to create property cell if not *
* present. *
* Return: pointer to property cell." *
* *
****************************************************************/
PROPTYPE NEAR PropRhteLookup(rhte,attr,fCreate)
RBTYPE rhte; /* Virt. addr. of hash table entry */
ATTRTYPE attr; /* Property to look up */
FTYPE fCreate; /* Create property cell flag */
{
REGISTER APROPPTR aprop;
AHTEPTR ahte;
DEBUGVALUE(rhte); /* Debug info */
DEBUGVALUE(attr); /* Debug info */
DEBUGVALUE(fCreate); /* Debug info */
vrhte = rhte; /* Set global */
ahte = (AHTEPTR ) FetchSym(rhte,FALSE);
/* Fetch symbol */
vrprop = ahte->rprop;
vfCreated = FALSE; /* Assume no creation takes place */
for(;;)
{
aprop = (APROPPTR ) FetchSym(vrprop,FALSE);
/* Fetch from VM */
if(aprop->a_attr == attr) /* If match found */
{
DEBUGMSG("Match found"); /* Debug message */
return((PROPTYPE) aprop); /* Return address of cell */
}
DEBUGMSG("Following link:"); /* Debug message */
vrprop = aprop->a_next; /* Try next item in list */
DEBUGVALUE(vrprop); /* Debug info */
if(aprop->a_attr == ATTRNIL) /* If no entry here */
{
DEBUGMSG("Match NOT found");/* Debug message */
if(!fCreate) /* If creation inhibited */
{
/* Debug info */
return(PROPNIL); /* Return nil pointer */
}
vfCreated = (FTYPE) TRUE; /* A new creation! */
DEBUGMSG("Leaving PropRhteLookup with value of PropAdd");
/* Debug message */
return(PropAdd(vrhte,attr));/* Let someone else do it */
}
}
}
/****************************************************************
* *
* RhteFromProp: *
* *
* give back the master rhte for this prop entry *
* *
* Input: aprop mapped address of the propery cell *
* *
* Return: Virtual address of hash table entry. *
* *
****************************************************************/
RBTYPE NEAR RhteFromProp(aprop)
APROPPTR aprop; /* address of property block */
{
RBTYPE vrprop;
/* if we're already at the head, we have to go all the way around
* to compute the *virutal* address of the head
*/
for(;;)
{
DEBUGMSG("Following link:"); /* Debug message */
vrprop = aprop->a_next; /* Try next item in list */
DEBUGVALUE(vrprop); /* Debug info */
aprop = (APROPPTR) FetchSym(vrprop,FALSE);
/* Fetch from VM */
if(aprop->a_attr == ATTRNIL) /* If no entry here */
{
return(vrprop); /* found head -- return it */
}
}
}
#if NEWSYM AND NOASM
FTYPE NEAR SbNewComp(ps1,ps2,fncs)
BYTE *ps1; /* Pointer to symbol */
BYTE FAR *ps2; /* Pointer to FAR symbol */
FTYPE fncs; /* True if not case-sensitive */
{
WORD length; /* No. of char.s to compare */
length = B2W(*ps1); /* Get length */
if (!fncs) /* If case-sensitive */
{ /* Simple string comparison */
while (length && (*++ps1 == *++ps2)) {
length--;
}
return((FTYPE) (length ? FALSE : TRUE)); /* Success iff nothing left */
}
while(length--)
{
#ifdef _MBCS
ps1++;
ps2++;
if (IsLeadByte(*ps1))
if (*((WORD *)ps1) != *((WORD *)ps2)) {
return FALSE;
}
else {
ps1++;
ps2++;
length--;
continue;
}
else
#else
if(*++ps1 == *++ps2)
continue; /* Bytes match */
else
#endif
if((*ps1 & 0137) != (*ps2 & 0137)) {
return(FALSE);
}
}
return(TRUE); /* They match */
}
#endif
/****************************************************************
* *
* PropSymLookup: *
* *
* This function looks up a symbol and its property. It *
* can create an entry, if necessary. It returns a pointer to *
* the property cell. It takes as its inputs a pointer to a *
* symbol, the property to look up, and a flag which specifies *
* if a new property cell is to be created in the event that *
* one of the given type does not already exist. *
* *
****************************************************************/
#if NOASM
PROPTYPE NEAR PropSymLookup(psym,attr,fCreate)
BYTE *psym; /* Pointer to length-prefixed string */
ATTRTYPE attr; /* Attribute to look up */
WORD fCreate; /* Create prop cell if not found */
{
AHTEPTR ahte; /* Pointer to hash table entry */
WORD hashval; /* Hash value */
#if DEBUG /* If debugging on */
fputs("Looking up ",stderr); /* Message */
OutSb(stderr,psym); /* Symbol */
fprintf(stderr,"(%d) with attr %d\r\n",B2W(psym[0]),B2W(attr));
#endif /* End debugging code */
hashval = IHashKey(psym); /* Get hash index */
vrhte = rgrhte[hashval % IRHTEMAX]; /* Get VM address of chain */
vfCreated = FALSE; /* Assume nothing will be created */
for(;;)
{
DEBUGVALUE(vrhte); /* Debug info */
if(vrhte == RHTENIL) /* If nil pointer */
{
DEBUGMSG("Empty slot found");
/* Debug message */
if(!fCreate) /* If creation inhibited */
{
return(PROPNIL); /* Return nil pointer */
}
else
{
DEBUGMSG("Leaving PropSymLookup with value of CreateNewSym");
return CreateNewSym(hashval, psym, attr);
}
}
DEBUGMSG("Collision"); /* Debug message */
ahte = (AHTEPTR ) FetchSym(vrhte,FALSE);
/* Fetch from VM */
#if DEBUG
fputs("Comparing \"",stderr); /* Message */
OutSb(stderr,psym); /* Symbol */
fprintf(stderr,"\"(%d) to \"",B2W(psym[0]));
/* Message */
OutSb(stderr,GetFarSb(ahte->cch)); /* Symbol */
fprintf(stderr,"\"(%d) %signoring case\r\n",
B2W(ahte->cch[0]),fIgnoreCase? "": "NOT ");
/* Message */
#endif
if(hashval == ahte->hashval && psym[0] == ahte->cch[0]
&& SbNewComp(psym,(BYTE FAR *)ahte->cch,fIgnoreCase))
{ /* If a match found */
DEBUGMSG("Match found"); /* Debug message */
DEBUGMSG("Leaving PropSymLookup w/ val of PropRhteLookup");
return(PropRhteLookup(vrhte,attr, (FTYPE) fCreate));
/* Return property cell pointer */
}
vrhte = ahte->rhteNext; /* Move down list */
DEBUGMSG("Following link:"); /* Debug message */
DEBUGVALUE(vrhte); /* Debug info */
}
}
#endif /*NOASM*/
/****************************************************************
* *
* CreateNewSym: *
* *
* This function adds the given symbol into the hash table at *
* the position indicated by hashval. If attr is not ATTRNIL *
* then it also creates the specified property type *
* *
****************************************************************/
LOCAL PROPTYPE NEAR CreateNewSym(hashval, psym, attr)
WORD hashval; /* the hash value of this symbol */
BYTE *psym; /* Pointer to length-prefixed string */
ATTRTYPE attr; /* Attribute to create */
{
AHTEPTR ahte; /* Pointer to hash table entry */
WORD irhte; /* hash bucket */
irhte = hashval % IRHTEMAX;
vfCreated = TRUE; /* New creation */
vrhte = RbAllocSymNode((WORD) (CBHTE + B2W(psym[0])));
/* Allocate space for symbol entry */
ahte = (AHTEPTR ) FetchSym(vrhte,TRUE);
/* Fetch symbol from virtual memory */
ahte->rhteNext = rgrhte[irhte];
/* Tack on chain */
DEBUGMSG("Origin of original chain:");
DEBUGVALUE(rgrhte[irhte]); /* Debug info */
ahte->attr = ATTRNIL; /* Symbol has Nil attribute */
ahte->rprop = vrhte; /* Prop list points to self */
ahte->hashval = hashval; /* Save hash value */
memcpy(ahte->cch, psym, psym[0] + 1);
rgrhte[irhte] = vrhte; /* Make new symbol first in chain */
DEBUGMSG("Origin of new chain:");
DEBUGVALUE(rgrhte[irhte]); /* Debug info */
if(attr != ATTRNIL) /* If property to give symbol */
{
DEBUGMSG("Leaving PropSymLookup with the value of PropAdd");
return(PropAdd(vrhte,attr));
/* Add the attribute */
}
/* Debug info */
return(PROPNIL); /* Nothing to return */
}
/****************************************************************
* *
* The legendary EnSyms: *
* *
* This function applies a function to all symbol/property *
* pairs that have a particular property. It takes as its *
* inputs a pointer to a function to call and a property to *
* look for. EnSyms() does not return a meaningful value. *
* *
****************************************************************/
void BigEnSyms(void (*pproc)(APROPNAMEPTR papropName,
RBTYPE rhte,
RBTYPE rprop,
WORD fNewHte), ATTRTYPE attr)
{
APROPPTR aprop; /* Pointer to a property cell */
AHTEPTR ahte; /* Pointer to a hash table entry */
WORD irhte; /* Hash table index */
RBTYPE rhte; /* Hash table entry address */
ATTRTYPE attrT;
FTYPE fNewHte;
RBTYPE rprop;
RBTYPE rhteNext;
RBTYPE rpropNext;
DEBUGVALUE(attr); /* Debug info */
for(irhte = 0; irhte < IRHTEMAX; ++irhte)
{ /* Look through hash table */
rhte = rgrhte[irhte]; /* Get pointer to chain */
while(rhte != RHTENIL) /* While not at end of chain */
{
DEBUGVALUE(rhte); /* Debug info */
ahte = (AHTEPTR ) FetchSym(rhte,FALSE);
/* Fetch entry from VM */
DEBUGSB(ahte->cch); /* Debug info */
fNewHte = (FTYPE) TRUE; /* First call on this hash tab entry */
rhteNext = ahte->rhteNext; /* Get pointer to next in chain */
rprop = ahte->rprop; /* Get pointer to property list */
for(;;) /* Loop to search property list */
{
aprop = (APROPPTR ) FetchSym(rprop,FALSE);
/* Fetch entry from symbol table */
rpropNext = aprop->a_next;
/* Get pointer to next in list */
attrT = aprop->a_attr; /* Get the attribute */
DEBUGVALUE(attrT); /* Debug info */
if(attr == attrT || attr == ATTRNIL)
{ /* If property is acceptable */
(*pproc)((APROPNAMEPTR) aprop, rhte, rprop, (WORD) fNewHte);
/* Apply function to node */
fNewHte = FALSE; /* Next call (if any) won't be first */
}
if(attrT == ATTRNIL) break;
/* Break if at end of prop list */
rprop = rpropNext; /* Move down the list */
}
rhte = rhteNext; /* Move down the chain */
}
}
}
#if PROFSYM
/*
* ProfSym : Profile the symbol table, displaying results to stdout
*/
void ProfSym ()
{
REGISTER AHTEPTR ahte; /* Pointer to a hash table entry */
WORD irhte; /* Hash table index */
RBTYPE rhte; /* Hash table entry address */
unsigned cSymbols = 0; /* # of symtab entries */
unsigned cBktlen = 0; /* Total length of buckets */
unsigned bucketlen; /* Current bucket length */
unsigned maxBkt = 0;
long sumBktSqr = 0L; /* Sum of bucketlen squared */
int bdist[6];
bdist[0] = bdist[1] = bdist[2] = bdist[3] = bdist[4] = bdist[5] = 0;
for(irhte = 0; irhte < IRHTEMAX; ++irhte)
{ /* Look through hash table */
rhte = rgrhte[irhte]; /* Get pointer to chain */
bucketlen = 0;
while(rhte != RHTENIL) /* While not at end of chain */
{
++cSymbols;
++bucketlen;
ahte = (AHTEPTR ) FetchSym(rhte,FALSE);
rhte = ahte->rhteNext; /* Move down the chain */
}
if (bucketlen >= 5)
bdist[5]++;
else
bdist[bucketlen]++;
sumBktSqr += bucketlen * bucketlen;
cBktlen += bucketlen;
if(bucketlen > maxBkt) maxBkt = bucketlen;
}
fprintf(stdout,"\r\n");
fprintf(stdout,"Total number of buckets = %6u\r\n",IRHTEMAX);
fprintf(stdout,"Total number of symbols = %6u\r\n",cSymbols);
fprintf(stdout,"Sum of bucketlen^2 = %6lu\r\n",sumBktSqr);
fprintf(stdout,"(cSymbols^2)/#buckets = %6lu\r\n",
((long) cSymbols * cSymbols) / IRHTEMAX);
fprintf(stdout,"Average bucket length = %6u\r\n",cBktlen/IRHTEMAX);
fprintf(stdout,"Maximum bucket length = %6u\r\n",maxBkt);
fprintf(stdout,"# of buckets with 0 = %6u\r\n",bdist[0]);
fprintf(stdout,"# of buckets with 1 = %6u\r\n",bdist[1]);
fprintf(stdout,"# of buckets with 2 = %6u\r\n",bdist[2]);
fprintf(stdout,"# of buckets with 3 = %6u\r\n",bdist[3]);
fprintf(stdout,"# of buckets with 4 = %6u\r\n",bdist[4]);
fprintf(stdout,"# of buckets with >= 5 = %6u\r\n",bdist[5]);
fprintf(stdout,"\r\n");
}
#endif /*PROFSYM*/
#if DEBUG AND ( NOT defined( _WIN32 ) )
void DispMem( void)
{
unsigned int mem_para, mem_kb;
unsigned int error_code=0;
_asm{
mov bx, 0xffff
mov ax, 0x4800
int 21h
jc Error
mov bx, 0xffff
jmp MyEnd
Error:
mov error_code, ax
MyEnd:
mov mem_para, bx
}
mem_kb = mem_para>>6;
if(error_code == 8 || error_code)
fprintf( stdout, "\r\nAvailable Memory: %u KB, %u paragraphs, error: %d\r\n", mem_kb, mem_para, error_code);
else
fprintf( stdout, "\r\nMemory Error No %d\r\n", error_code);
fflush(stdout);
}
#endif