/* * 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 /* Types and constants */ #include /* More types and constants */ #include /* More types and constants */ #include /* Linker I/O definitions */ #include /* Error messages */ #include /* 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