|
|
/*
* 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 MYvrprop;
/* 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 */ MYvrprop = aprop->a_next; /* Try next item in list */ DEBUGVALUE(MYvrprop); /* Debug info */
aprop = (APROPPTR) FetchSym(MYvrprop,FALSE); /* Fetch from VM */ if(aprop->a_attr == ATTRNIL) /* If no entry here */ { return(MYvrprop); /* 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
|