1318 lines
31 KiB
C
1318 lines
31 KiB
C
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
#ifdef SYMTAB_STATS
|
|
UINT SymbolCount;
|
|
#endif
|
|
|
|
/*
|
|
** Purpose:
|
|
** Creates a new Symbol Table.
|
|
** Arguments:
|
|
** szName - Name of the INF file
|
|
** Returns:
|
|
** fFalse if the initialization failed because it could not allocate
|
|
** the memory it needed.
|
|
** fTrue if the initialization succeeded.
|
|
**
|
|
**************************************************************************/
|
|
PINFTEMPINFO APIENTRY CreateInfTempInfo( pPermInfo )
|
|
PINFPERMINFO pPermInfo;
|
|
{
|
|
PINFTEMPINFO pTempInfo;
|
|
|
|
//
|
|
// Allocate space for context data
|
|
//
|
|
pTempInfo = (PINFTEMPINFO)SAlloc( (CB)sizeof(INFTEMPINFO) );
|
|
|
|
if ( pTempInfo ) {
|
|
|
|
if ( !(pTempInfo->SymTab = SymTabAlloc())) {
|
|
|
|
SFree(pTempInfo);
|
|
pTempInfo = NULL;
|
|
|
|
} else if ( !(pTempInfo->pParsedInf = ParsedInfAlloc( pPermInfo )) ) {
|
|
|
|
FFreeSymTab( pTempInfo->SymTab );
|
|
SFree(pTempInfo);
|
|
pTempInfo = NULL;
|
|
|
|
} else {
|
|
|
|
pTempInfo->pInfPermInfo = pPermInfo;
|
|
|
|
pTempInfo->cRef = 1;
|
|
|
|
|
|
//
|
|
// Add to chain.
|
|
//
|
|
if ( pLocalContext() ) {
|
|
pTempInfo->pPrev = pLocalInfTempInfo();
|
|
} else {
|
|
pTempInfo->pPrev = NULL;
|
|
}
|
|
pTempInfo->pNext = pTempInfo->pPrev ? (pTempInfo->pPrev)->pNext : NULL;
|
|
|
|
if ( pTempInfo->pPrev ) {
|
|
(pTempInfo->pPrev)->pNext = pTempInfo;
|
|
}
|
|
if ( pTempInfo->pNext ) {
|
|
(pTempInfo->pNext)->pPrev = pTempInfo;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
return pTempInfo;
|
|
}
|
|
|
|
|
|
|
|
#ifdef SYMTAB_STATS
|
|
|
|
void ContextDump( FILE*);
|
|
void TempInfoDump( FILE*);
|
|
void PermInfoDump( FILE*);
|
|
void SymTabDump( FILE*, PSYMTAB);
|
|
|
|
void
|
|
SymTabStatDump(void)
|
|
{
|
|
FILE *statfile;
|
|
|
|
statfile = fopen("D:\\SYMTAB.TXT","wt");
|
|
|
|
ContextDump( statfile );
|
|
|
|
TempInfoDump( statfile );
|
|
|
|
PermInfoDump( statfile );
|
|
|
|
fclose(statfile);
|
|
}
|
|
|
|
|
|
void
|
|
ContextDump( FILE* f )
|
|
{
|
|
PINFCONTEXT pContext;
|
|
UINT i = 0;
|
|
|
|
fprintf( f, "CONTEXT STACK DUMP\n");
|
|
fprintf( f, "------------------\n");
|
|
|
|
pContext = pLocalContext();
|
|
|
|
while ( pContext ) {
|
|
|
|
fprintf( f, "\n\n\n");
|
|
fprintf( f, "Context #%u.- Line: %8u INF Name: %s\n",
|
|
i,
|
|
pContext->CurrentLine, pContext->pInfTempInfo->pInfPermInfo->szName );
|
|
fprintf( f, "Local Symbol Table:\n");
|
|
|
|
SymTabDump( f, pContext->SymTab );
|
|
|
|
i++;
|
|
pContext = pContext->pNext;
|
|
}
|
|
|
|
fprintf( f, "\n\n\n");
|
|
}
|
|
|
|
|
|
void
|
|
TempInfoDump( FILE* f )
|
|
{
|
|
PINFPERMINFO pPermInfo;
|
|
PINFTEMPINFO pTempInfo;
|
|
|
|
fprintf( f, "\n\n\n");
|
|
fprintf( f, "INF TEMPORARY INFO DUMP\n");
|
|
fprintf( f, "-----------------------\n");
|
|
|
|
pTempInfo = pGlobalContext()->pInfTempInfo;
|
|
|
|
while ( pTempInfo ) {
|
|
|
|
pPermInfo = pTempInfo->pInfPermInfo;
|
|
|
|
fprintf( f, "\n\n\n" );
|
|
fprintf( f, "INF Name: %s\n", pPermInfo->szName );
|
|
fprintf( f, "INF Id: %8u\n", pPermInfo->InfId );
|
|
fprintf( f, "Reference Count: %8u\n", pTempInfo->cRef );
|
|
fprintf( f, "Line Count: %8u\n", pTempInfo->MasterLineCount );
|
|
fprintf( f, "File Size: %8u\n", pTempInfo->MasterFileSize );
|
|
fprintf( f, "Static Symbol Table:\n");
|
|
|
|
SymTabDump( f, pTempInfo->SymTab );
|
|
|
|
pTempInfo = pTempInfo->pNext;
|
|
}
|
|
|
|
fprintf( f, "\n\n\n");
|
|
}
|
|
|
|
|
|
|
|
void
|
|
PermInfoDump( FILE* f )
|
|
{
|
|
PINFPERMINFO pPermInfo;
|
|
|
|
fprintf( f, "\n\n\n");
|
|
fprintf( f, "INF PERMANENT INFO DUMP\n");
|
|
fprintf( f, "-----------------------\n\n");
|
|
|
|
pPermInfo = pInfPermInfoHead;
|
|
|
|
while ( pPermInfo ) {
|
|
|
|
fprintf( f, "INF Name: %s\n", pPermInfo->szName );
|
|
|
|
pPermInfo = pPermInfo->pNext;
|
|
}
|
|
|
|
fprintf( f, "\n\n\n");
|
|
}
|
|
|
|
|
|
void
|
|
SymTabDump( FILE* f, PSYMTAB pSymTab )
|
|
{
|
|
UINT i;
|
|
PSTE p;
|
|
|
|
fprintf( f, "\n");
|
|
|
|
for(i=0; i<cHashBuckets; i++) {
|
|
|
|
p = pSymTab->HashBucket[i];
|
|
|
|
fprintf( f, "\n\tBucket # %u (%u items):\n",i,pSymTab->BucketCount[i]);
|
|
|
|
while(p) {
|
|
fprintf( f, "\n\t Symbol = %s\n\t Value = %s\n",p->szSymbol,p->szValue);
|
|
p = p->psteNext;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Allocates an STE structure and returns it.
|
|
** Arguments:
|
|
** none
|
|
** Returns:
|
|
** NULL if the allocation failed.
|
|
** Pointer to the allocated STE structure.
|
|
+++
|
|
** Notes:
|
|
** A linked list of unused STEs is maintained with FFreePste()
|
|
** placing unused STEs into it. If this linked list (psteUnused)
|
|
** is empty then a block of cStePerSteb STEs is allocated at once
|
|
** and added to the unused list with one being returned by this
|
|
** routine.
|
|
**
|
|
**************************************************************************/
|
|
PSTE APIENTRY PsteAlloc(VOID)
|
|
{
|
|
PSTE pste;
|
|
|
|
if (GLOBAL(psteUnused) == (PSTE)NULL)
|
|
{
|
|
PSTEB psteb;
|
|
USHORT us;
|
|
|
|
if ((psteb = (PSTEB)SAlloc((CB)sizeof(STEB))) == (PSTEB)NULL)
|
|
return((PSTE)NULL);
|
|
psteb->pstebNext = GLOBAL(pstebAllocatedBlocks);
|
|
GLOBAL(pstebAllocatedBlocks) = psteb;
|
|
|
|
GLOBAL(psteUnused) = &(psteb->rgste[0]);
|
|
for (us = 1; us < cStePerSteb; us++)
|
|
(psteb->rgste[us - 1]).psteNext = &(psteb->rgste[us]);
|
|
(psteb->rgste[cStePerSteb - 1]).psteNext = (PSTE)NULL;
|
|
}
|
|
|
|
pste = GLOBAL(psteUnused);
|
|
GLOBAL(psteUnused) = pste->psteNext;
|
|
|
|
pste->szSymbol = (SZ)NULL;
|
|
pste->szValue = (SZ)NULL;
|
|
|
|
#ifdef SYMTAB_STATS
|
|
SymbolCount++;
|
|
#endif
|
|
|
|
return(pste);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Frees an STE structure.
|
|
** Arguments:
|
|
** pste: non-NULL STE structure to be freed.
|
|
** Returns:
|
|
** fFalse if either of the string fields of the STE structure or the
|
|
** STE itself could not be successfully freed.
|
|
** fTrue if both string fields of the STE structure and the structure
|
|
** itself are successfully freed.
|
|
**
|
|
**************************************************************************/
|
|
BOOL APIENTRY FFreePste(pste)
|
|
PSTE pste;
|
|
{
|
|
BOOL fAnswer = fTrue;
|
|
|
|
ChkArg(pste != (PSTE)NULL, 1, fFalse);
|
|
|
|
if (pste->szSymbol != (SZ)NULL)
|
|
SFree(pste->szSymbol);
|
|
if (pste->szValue != (SZ)NULL)
|
|
SFree(pste->szValue);
|
|
|
|
pste->szSymbol = pste->szValue = (SZ)NULL;
|
|
pste->psteNext = GLOBAL(psteUnused);
|
|
GLOBAL(psteUnused) = pste;
|
|
|
|
#ifdef SYMTAB_STATS
|
|
SymbolCount--;
|
|
#endif
|
|
|
|
return(fAnswer);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Decrements the reference count of a symbol table, freeing its
|
|
** memory if the reference count reaches zero
|
|
** Arguments:
|
|
** none
|
|
** Returns:
|
|
** fFalse if all the STE structures and their string fields cannot be
|
|
** successfully freed.
|
|
** fTrue if all the STE structures and their string fields can be
|
|
** successfully freed.
|
|
**
|
|
**************************************************************************/
|
|
BOOL APIENTRY FFreeInfTempInfo( PVOID p )
|
|
{
|
|
BOOL fAnswer = fTrue;
|
|
PINFTEMPINFO pTempInfo = (PINFTEMPINFO)p;
|
|
|
|
AssertDataSeg();
|
|
|
|
|
|
if ( pTempInfo->cRef > 1 ) {
|
|
|
|
pTempInfo->cRef--;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Free static symbol table
|
|
//
|
|
FFreeSymTab( pTempInfo->SymTab );
|
|
|
|
//
|
|
// Free preparsed INF
|
|
//
|
|
FFreeParsedInf( pTempInfo->pParsedInf );
|
|
|
|
|
|
|
|
//
|
|
// Remove from chain
|
|
//
|
|
if ( pTempInfo->pPrev ) {
|
|
(pTempInfo->pPrev)->pNext = pTempInfo->pNext;
|
|
}
|
|
if ( pTempInfo->pNext ) {
|
|
(pTempInfo->pNext)->pPrev = pTempInfo->pPrev;
|
|
}
|
|
|
|
SFree(p);
|
|
|
|
//
|
|
// bugbug ramonsa - should we free PSTE blocks here?
|
|
//
|
|
}
|
|
return(fAnswer);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Calculates a hash value for a zero terminated string of bytes
|
|
** (characters) which is used by the Symbol Table to divide the
|
|
** symbols into separate buckets to improve the search efficiency.
|
|
** Arguments:
|
|
** pb: non-NULL, non-empty zero terminated string of bytes.
|
|
** Returns:
|
|
** -1 for an error.
|
|
** A number between 0 and cHashBuckets.
|
|
**
|
|
**************************************************************************/
|
|
USHORT APIENTRY UsHashFunction( pb )
|
|
register PB pb;
|
|
{
|
|
register USHORT usValue = 0;
|
|
register PB pbMax = pb + cbBytesToSumForHash ;
|
|
|
|
ChkArg(pb != (PB)NULL &&
|
|
*pb != '\0', 1, (USHORT)(-1));
|
|
|
|
while ( *pb && pb < pbMax )
|
|
{
|
|
usValue = (usValue << 1) ^ (USHORT) *pb++ ;
|
|
}
|
|
|
|
return(usValue % (USHORT)cHashBuckets);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Finds a corresponding STE structure if the symbol is already in
|
|
** the Symbol Table or else points to where it should be inserted.
|
|
** Arguments:
|
|
** szSymbol: non-NULL, non-empty zero terminated string containing
|
|
** the value of the symbol to be searched for.
|
|
** Notes:
|
|
** Requires that the Symbol Table was initialized with a successful
|
|
** call to FInitSymTab().
|
|
** Returns:
|
|
** NULL in an error.
|
|
** Non-NULL pointer to a pointer to an STE structure. If szSymbol is
|
|
** in the Symbol Table, then (*PPSTE)->szSymbol is it. If szSymbol
|
|
** is not in the Symbol Table, then *PPSTE is the PSTE to insert
|
|
** its record at.
|
|
**
|
|
**************************************************************************/
|
|
PPSTE APIENTRY PpsteFindSymbol(pSymTab, szSymbol)
|
|
PSYMTAB pSymTab;
|
|
SZ szSymbol;
|
|
{
|
|
PPSTE ppste;
|
|
USHORT usHashValue;
|
|
|
|
PreCondSymTabInit((PPSTE)NULL);
|
|
|
|
ChkArg( szSymbol != (SZ)NULL
|
|
&& *szSymbol != '\0', 1, (PPSTE)NULL);
|
|
|
|
usHashValue = UsHashFunction(szSymbol);
|
|
|
|
ppste = &(pSymTab->HashBucket[usHashValue]);
|
|
AssertRet(ppste != (PPSTE)NULL, (PPSTE)NULL);
|
|
AssertRet(*ppste == (PSTE)NULL ||
|
|
((*ppste)->szSymbol != (SZ)NULL &&
|
|
*((*ppste)->szSymbol) != '\0' &&
|
|
(*ppste)->szValue != (SZ)NULL), (PPSTE)NULL);
|
|
|
|
while ( *ppste != (PSTE)NULL &&
|
|
lstrcmp(szSymbol, (*ppste)->szSymbol) > 0 )
|
|
{
|
|
ppste = &((*ppste)->psteNext);
|
|
AssertRet(ppste != (PPSTE)NULL, (PPSTE)NULL);
|
|
AssertRet(*ppste == (PSTE)NULL ||
|
|
((*ppste)->szSymbol != (SZ)NULL &&
|
|
*((*ppste)->szSymbol) != '\0' &&
|
|
(*ppste)->szValue != (SZ)NULL), (PPSTE)NULL);
|
|
}
|
|
|
|
return(ppste);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Inserts a new symbol-value pair into the Symbol Table or replaces
|
|
** an existing value associated with the symbol if it already exists
|
|
** in the Symbol Table.
|
|
** Arguments:
|
|
** szSymbol: non-NULL, non-empty string symbol value.
|
|
** szValue: string value to associate with szSymbol, replacing and
|
|
** freeing any current value. If it is NULL then the empty string
|
|
** is used in its place. There are two types of values - simple
|
|
** and list. A simple value is any string of characters which is
|
|
** not a list. A list is a string which starts with a '{', and ends
|
|
** with a '}' and contains doubly quoted items, separated by commas
|
|
** with no extraneous whitespace. So examples of lists are:
|
|
** {}
|
|
** {"item1"}
|
|
** {"item1","item2"}
|
|
** {"item 1","item 2","item 3","item 4"}
|
|
** Examples of non-lists are:
|
|
** {item1}
|
|
** {"item1", "item2"}
|
|
** Notes:
|
|
** Requires that the Symbol Table was initialized with a successful
|
|
** call to FInitSymTab().
|
|
** Returns:
|
|
** fFalse if an existing value cannot be freed or if space cannot be
|
|
** allocated to create the needed STE structure or duplicate the
|
|
** szValue.
|
|
** fTrue if szValue is associated with szSymbol in the Symbol Table.
|
|
**
|
|
**************************************************************************/
|
|
BOOL APIENTRY FAddSymbolValueToSymTab(szSymbol, szValue)
|
|
SZ szSymbol;
|
|
SZ szValue;
|
|
{
|
|
PPSTE ppste;
|
|
SZ szValueNew;
|
|
SZ szRealSymbol;
|
|
PSYMTAB pSymTab;
|
|
|
|
|
|
AssertDataSeg();
|
|
|
|
PreCondSymTabInit(fFalse);
|
|
|
|
ChkArg(szSymbol != (SZ)NULL &&
|
|
*szSymbol != '\0' &&
|
|
!FWhiteSpaceChp(*szSymbol), 1, fFalse);
|
|
|
|
if (szValue == (SZ)NULL)
|
|
szValue = "";
|
|
|
|
if ((szValueNew = SzDupl(szValue)) == (SZ)NULL)
|
|
return(fFalse);
|
|
|
|
if ( !(pSymTab = PInfSymTabFind( szSymbol, &szRealSymbol ))) {
|
|
return(fFalse);
|
|
}
|
|
|
|
ppste = PpsteFindSymbol( pSymTab, szRealSymbol);
|
|
|
|
AssertRet(ppste != (PPSTE)NULL, fFalse);
|
|
AssertRet(*ppste == (PSTE)NULL ||
|
|
((*ppste)->szSymbol != (SZ)NULL &&
|
|
*((*ppste)->szSymbol) != '\0' &&
|
|
(*ppste)->szValue != (SZ)NULL), fFalse);
|
|
|
|
if (*ppste != (PSTE)NULL &&
|
|
CrcStringCompare((*ppste)->szSymbol, szRealSymbol) == crcEqual)
|
|
{
|
|
AssertRet((*ppste)->szValue != (SZ)NULL, fFalse);
|
|
SFree((*ppste)->szValue);
|
|
(*ppste)->szValue = (SZ)NULL;
|
|
}
|
|
|
|
else
|
|
{
|
|
PSTE pste;
|
|
|
|
if ((pste = PsteAlloc()) == (PSTE)NULL ||
|
|
(pste->szSymbol = SzDupl(szRealSymbol)) == (SZ)NULL)
|
|
{
|
|
if (pste != (PSTE)NULL)
|
|
EvalAssert(FFreePste(pste));
|
|
SFree(szValueNew);
|
|
return(fFalse);
|
|
}
|
|
#ifdef SYMTAB_STATS
|
|
pSymTab->BucketCount[UsHashFunction(szRealSymbol)]++;
|
|
#endif
|
|
pste->szValue = (SZ)NULL;
|
|
pste->psteNext = *ppste;
|
|
*ppste = pste;
|
|
}
|
|
|
|
AssertRet(ppste != (PPSTE)NULL &&
|
|
*ppste != (PSTE)NULL &&
|
|
(*ppste)->szValue == (SZ)NULL &&
|
|
(*ppste)->szSymbol != (SZ)NULL &&
|
|
*((*ppste)->szSymbol) != '\0' &&
|
|
CrcStringCompare((*ppste)->szSymbol, szRealSymbol) == crcEqual, fFalse);
|
|
|
|
(*ppste)->szValue = szValueNew;
|
|
|
|
return(fTrue);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Finds the associated string value for a given symbol from the
|
|
** Symbol Table if such exists.
|
|
** Arguments:
|
|
** szSymbol: non-NULL, non-empty string symbol value.
|
|
** Notes:
|
|
** Requires that the Symbol Table was initialized with a successful
|
|
** call to FInitSymTab().
|
|
** Returns:
|
|
** NULL if error or szSymbol could not be found in the Symbol Table.
|
|
** Non-NULL pointer to the associated string value in the Symbol
|
|
** Table. This value must not be mucked but should be duplicated
|
|
** before changing it. Changing it directly will change the value
|
|
** associated with the symbol. If it is changed, be sure the new
|
|
** value has the same length as the old.
|
|
**
|
|
**************************************************************************/
|
|
SZ APIENTRY SzFindSymbolValueInSymTab(szSymbol)
|
|
SZ szSymbol;
|
|
{
|
|
register PSTE pste;
|
|
PSYMTAB pSymTab;
|
|
SZ szValue = NULL ;
|
|
SZ szRealSymbol ;
|
|
int i ;
|
|
|
|
PreCondSymTabInit((SZ)NULL);
|
|
|
|
if ( !(pSymTab = PInfSymTabFind( szSymbol, & szRealSymbol )))
|
|
return NULL ;
|
|
|
|
pste = pSymTab->HashBucket[ UsHashFunction( szRealSymbol ) ] ;
|
|
|
|
do
|
|
{
|
|
if ( pste == NULL )
|
|
break ;
|
|
if ( pste->szSymbol == NULL )
|
|
break ;
|
|
if ( pste->szSymbol[0] == 0 )
|
|
break;
|
|
if ( pste->szValue == NULL )
|
|
break;
|
|
if ( (i = lstrcmp( szRealSymbol, pste->szSymbol )) == 0 )
|
|
szValue = pste->szValue ;
|
|
} while ( i > 0 && (pste = pste->psteNext) ) ;
|
|
|
|
return szValue ;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Removes and frees a symbols STE structure if it exists.
|
|
** Arguments:
|
|
** szSymbol: non-NULL, non-empty symbol string to remove from the
|
|
** Symbol Table which starts with a non-whitespace character.
|
|
** Notes:
|
|
** Requires that the Symbol Table was initialized with a successful
|
|
** call to FInitSymTab().
|
|
** Returns:
|
|
** fFalse if szSymbol was found but its STE structure could not be freed.
|
|
** fTrue if either szSymbol never existed in the Symbol Table or it was
|
|
** found, unlinked, and successfully freed.
|
|
**
|
|
**************************************************************************/
|
|
BOOL APIENTRY FRemoveSymbolFromSymTab(szSymbol)
|
|
SZ szSymbol;
|
|
{
|
|
PPSTE ppste;
|
|
PSTE pste;
|
|
PSYMTAB pSymTab;
|
|
SZ szRealSymbol;
|
|
|
|
AssertDataSeg();
|
|
|
|
PreCondSymTabInit(fFalse);
|
|
|
|
ChkArg(szSymbol != (SZ)NULL &&
|
|
*szSymbol != '\0' &&
|
|
!FWhiteSpaceChp(*szSymbol), 1, fFalse);
|
|
|
|
if ( !(pSymTab = PInfSymTabFind( szSymbol, &szRealSymbol ))) {
|
|
return(fFalse);
|
|
}
|
|
|
|
ppste = PpsteFindSymbol( pSymTab, szRealSymbol);
|
|
AssertRet(ppste != (PPSTE)NULL, fFalse);
|
|
|
|
if (*ppste == (PSTE)NULL ||
|
|
CrcStringCompare(szRealSymbol, (*ppste)->szSymbol) != crcEqual)
|
|
return(fTrue);
|
|
|
|
pste = *ppste;
|
|
*ppste = pste->psteNext;
|
|
|
|
return(FFreePste(pste));
|
|
}
|
|
|
|
|
|
PSYMTAB APIENTRY SymTabAlloc(VOID)
|
|
{
|
|
PSYMTAB pSymTab;
|
|
USHORT iHashBucket;
|
|
|
|
if ( pSymTab = (PSYMTAB)SAlloc( sizeof( SYMTAB ) ) ) {
|
|
|
|
for (iHashBucket = 0; iHashBucket < cHashBuckets; iHashBucket++) {
|
|
pSymTab->HashBucket[iHashBucket] = NULL;
|
|
#ifdef SYMTAB_STATS
|
|
pSymTab->BucketCount[iHashBucket] = 0;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
return pSymTab;
|
|
|
|
}
|
|
|
|
|
|
BOOL APIENTRY FFreeSymTab(PSYMTAB pSymTab)
|
|
{
|
|
|
|
USHORT iHashBucket;
|
|
BOOL fAnswer = fTrue;
|
|
|
|
// Free symbol table space
|
|
//
|
|
for (iHashBucket = 0; iHashBucket < cHashBuckets; iHashBucket++) {
|
|
|
|
PSTE pste = pSymTab->HashBucket[iHashBucket];
|
|
|
|
while (pste != (PSTE)NULL) {
|
|
|
|
PSTE psteSav = pste->psteNext;
|
|
|
|
fAnswer &= FFreePste(pste);
|
|
pste = psteSav;
|
|
}
|
|
}
|
|
|
|
SFree(pSymTab);
|
|
|
|
return fAnswer;
|
|
|
|
}
|
|
|
|
|
|
BOOL APIENTRY FCheckSymTab(PSYMTAB pSymTab)
|
|
{
|
|
|
|
USHORT iHashBucket;
|
|
|
|
for (iHashBucket = 0; iHashBucket < cHashBuckets; iHashBucket++) {
|
|
|
|
PSTE pste = pSymTab->HashBucket[iHashBucket];
|
|
SZ szPrev = "";
|
|
|
|
while (pste != (PSTE)NULL) {
|
|
|
|
if (pste->szSymbol == (SZ)NULL ||
|
|
*(pste->szSymbol) == '\0' ||
|
|
FWhiteSpaceChp(*(pste->szSymbol)))
|
|
AssertRet(fFalse, fFalse);
|
|
if (UsHashFunction((PB)(pste->szSymbol)) != iHashBucket)
|
|
AssertRet(fFalse, fFalse);
|
|
if (CrcStringCompare(szPrev, pste->szSymbol) != crcSecondHigher)
|
|
AssertRet(fFalse, fFalse);
|
|
if (pste->szValue == (SZ)NULL)
|
|
AssertRet(fFalse, fFalse);
|
|
pste = pste->psteNext;
|
|
}
|
|
}
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Ensures that the Symbol Table is valid. It checks that the
|
|
** Symbol Table has been initialized and that each STE structure
|
|
** is in the correct hash bucket and that the symbols are in
|
|
** ascending order within each hash bucket and that each has a
|
|
** non-NULL value string associated with it.
|
|
** Arguments:
|
|
** none
|
|
** Notes:
|
|
** Requires that the Symbol Table was initialized with a successful
|
|
** call to FInitSymTab().
|
|
** Returns:
|
|
** fFalse if the Symbol Table has not been initialized or if an STE
|
|
** structure is in the wrong hash bucket or if each STE linked
|
|
** list is not in ascending order or if each symbol does not have
|
|
** a non-NULL string value associated with it.
|
|
** fTrue if the Symbol Table has been initialized and if every STE
|
|
** structure is in the correct hash bucket and if each STE linked
|
|
** list is in ascending order and if each symbol does have a
|
|
** non-NULL string value associated with it.
|
|
**
|
|
**************************************************************************/
|
|
BOOL APIENTRY FCheckSymTabIntegrity(VOID)
|
|
{
|
|
PINFTEMPINFO pTempInfo;
|
|
|
|
AssertDataSeg();
|
|
|
|
PreCondSymTabInit(fFalse);
|
|
|
|
pTempInfo = pGlobalContext()->pInfTempInfo;
|
|
|
|
while ( pTempInfo ) {
|
|
if ( !FCheckSymTab( pTempInfo->SymTab ) ) {
|
|
return fFalse;
|
|
}
|
|
|
|
pTempInfo = pTempInfo->pNext;
|
|
}
|
|
|
|
return(fTrue);
|
|
}
|
|
|
|
BOOL
|
|
DumpSymbolTableToFile(
|
|
IN PCSTR Filename
|
|
)
|
|
{
|
|
FILE *OutFile;
|
|
UINT HashBucket;
|
|
PSTE pste;
|
|
PINFCONTEXT InfContext;
|
|
#define MAX_SYMTAB 1000
|
|
PVOID SymbolTables[MAX_SYMTAB];
|
|
PVOID InfNames[MAX_SYMTAB];
|
|
UINT SymbolTableCount;
|
|
UINT i;
|
|
BOOL Found;
|
|
|
|
//
|
|
// Handle preconditions.
|
|
//
|
|
PreCondSymTabInit(fFalse);
|
|
FCheckSymTabIntegrity();
|
|
|
|
//
|
|
// Open/create the dump file.
|
|
//
|
|
SetFileAttributes(Filename,FILE_ATTRIBUTE_NORMAL);
|
|
OutFile = fopen(Filename,"w");
|
|
if(!OutFile) {
|
|
return(FALSE);
|
|
}
|
|
|
|
//
|
|
// Iterate through all inf file contexts.
|
|
// Unfortunately there is no good way to simply iterate symbol tables
|
|
// we'll track the ones we've done and skip them if encountered again.
|
|
//
|
|
SymbolTableCount = 0;
|
|
for(InfContext=pContextTop; InfContext; InfContext=InfContext->pNext) {
|
|
if(SymbolTableCount < MAX_SYMTAB) {
|
|
Found = FALSE;
|
|
for(i=0; i<SymbolTableCount; i++) {
|
|
if(SymbolTables[i] == InfContext->SymTab) {
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
if(!Found) {
|
|
SymbolTables[SymbolTableCount] = InfContext->SymTab;
|
|
InfNames[SymbolTableCount] = InfContext->pInfTempInfo->pInfPermInfo->szName;
|
|
SymbolTableCount++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(i=0; i<SymbolTableCount; i++) {
|
|
|
|
fprintf(OutFile,"*** Inf %s:\n\n",InfNames[i] ? InfNames[i] : "(unknown)");
|
|
|
|
//
|
|
// Dump symbols in each hash bucket.
|
|
//
|
|
for(HashBucket=0; HashBucket<cHashBuckets; HashBucket++) {
|
|
for(pste=((PSYMTAB)(SymbolTables[i]))->HashBucket[HashBucket]; pste; pste=pste->psteNext) {
|
|
fprintf(OutFile,"[%s] = [%s]\n",pste->szSymbol,pste->szValue);
|
|
}
|
|
}
|
|
|
|
fprintf(OutFile,"\n\n");
|
|
}
|
|
|
|
fclose(OutFile);
|
|
return(TRUE);
|
|
}
|
|
|
|
#define cListItemsMax 0x07FF
|
|
#define ItemSizeIncr 0x2000
|
|
|
|
/*
|
|
** Purpose:
|
|
** Determines if a string is a list value.
|
|
** Arguments:
|
|
** szValue: non-NULL, zero terminated string to be tested.
|
|
** Returns:
|
|
** fTrue if a list; fFalse otherwise.
|
|
**
|
|
**************************************************************************/
|
|
BOOL
|
|
APIENTRY
|
|
FListValue(
|
|
IN SZ szValue
|
|
)
|
|
{
|
|
ChkArg(szValue != (SZ)NULL, 1, fFalse);
|
|
|
|
if(*szValue++ != '{') {
|
|
return(fFalse);
|
|
}
|
|
|
|
while((*szValue != '}') && *szValue) {
|
|
|
|
if(*szValue++ != '"') {
|
|
return(fFalse);
|
|
}
|
|
|
|
while(*szValue) {
|
|
|
|
if(*szValue != '"') {
|
|
szValue++;
|
|
} else if(*(szValue + 1) == '"') {
|
|
szValue += 2;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(*szValue++ != '"') {
|
|
return(fFalse);
|
|
}
|
|
|
|
if(*szValue == ',') {
|
|
if(*(++szValue) == '}') {
|
|
return(fFalse);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(*szValue != '}') {
|
|
return(fFalse);
|
|
}
|
|
|
|
return(fTrue);
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Converts a list value into an RGSZ.
|
|
** Arguments:
|
|
** szListValue: non-NULL, zero terminated string to be converted.
|
|
** Returns:
|
|
** NULL if an error occurred.
|
|
** Non-NULL RGSZ if the conversion was successful.
|
|
**
|
|
**************************************************************************/
|
|
RGSZ
|
|
APIENTRY
|
|
RgszFromSzListValue(
|
|
SZ szListValue
|
|
)
|
|
{
|
|
USHORT cItems;
|
|
SZ szCur;
|
|
RGSZ rgsz;
|
|
|
|
DWORD ValueBufferSize;
|
|
DWORD BytesLeftInValueBuffer;
|
|
|
|
|
|
ChkArg(szListValue != (SZ)NULL, 1, (RGSZ)NULL);
|
|
|
|
if(!FListValue(szListValue)) {
|
|
|
|
if((rgsz = (RGSZ)SAlloc((CB)(2 * sizeof(SZ)))) == (RGSZ)NULL ||
|
|
(rgsz[0] = SzDupl(szListValue)) == (SZ)NULL)
|
|
{
|
|
return((RGSZ)NULL);
|
|
}
|
|
rgsz[1] = (SZ)NULL;
|
|
return(rgsz);
|
|
}
|
|
|
|
if((rgsz = (RGSZ)SAlloc((CB)((cListItemsMax + 1) * sizeof(SZ)))) == (RGSZ)NULL) {
|
|
return((RGSZ)NULL);
|
|
}
|
|
|
|
cItems = 0;
|
|
szCur = szListValue + 1;
|
|
while((*szCur != '}') && (*szCur != '\0') && (cItems < cListItemsMax)) {
|
|
|
|
SZ szValue;
|
|
SZ szAddPoint;
|
|
|
|
AssertRet(*szCur == '"', (RGSZ)NULL);
|
|
szCur++;
|
|
|
|
//
|
|
// Allocate an initial buffer.
|
|
//
|
|
ValueBufferSize = ItemSizeIncr+1;
|
|
BytesLeftInValueBuffer = ItemSizeIncr;
|
|
|
|
if((szValue = (SZ)SAlloc(ValueBufferSize)) == (SZ)NULL) {
|
|
|
|
rgsz[cItems] = (SZ)NULL;
|
|
FFreeRgsz(rgsz);
|
|
return((RGSZ)NULL);
|
|
}
|
|
|
|
szAddPoint = szValue;
|
|
|
|
while(*szCur) {
|
|
|
|
if(*szCur == '"') {
|
|
|
|
//
|
|
// Got a quote. If the next character is a double quote, then
|
|
// we've got a literal double quote, and we want to store a
|
|
// single double quote in the target. If the next char is not
|
|
// a double-quote, then we've reached the string-ending double-quote.
|
|
//
|
|
// Advance szCur either way because:
|
|
// In the former case, szCur will now point to the second
|
|
// double-quote, and we can fall through the the ordinary
|
|
// character (ie, non-quote) case.
|
|
// In the latter case, we will break out of the loop, and want
|
|
// szCur advanced past the end of the string.
|
|
//
|
|
|
|
if(*(++szCur) != '"') {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!BytesLeftInValueBuffer) {
|
|
|
|
SZ szSave = szValue;
|
|
|
|
if(szValue = SRealloc(szValue,ValueBufferSize+ItemSizeIncr)) {
|
|
|
|
szAddPoint = (SZ)((PUCHAR)szValue + ValueBufferSize - 1);
|
|
|
|
BytesLeftInValueBuffer = ItemSizeIncr;
|
|
ValueBufferSize += ItemSizeIncr;
|
|
|
|
} else {
|
|
SFree(szSave);
|
|
rgsz[cItems] = (SZ)NULL;
|
|
FFreeRgsz(rgsz);
|
|
return((RGSZ)NULL);
|
|
}
|
|
}
|
|
|
|
BytesLeftInValueBuffer--;
|
|
|
|
*szAddPoint++ = *szCur++;
|
|
}
|
|
|
|
*szAddPoint = 0;
|
|
|
|
if((szAddPoint = SzDupl(szValue)) == NULL) {
|
|
|
|
SFree(szValue);
|
|
rgsz[cItems] = (SZ)NULL;
|
|
FFreeRgsz(rgsz);
|
|
return((RGSZ)NULL);
|
|
}
|
|
|
|
SFree(szValue);
|
|
|
|
if (*szCur == ',') {
|
|
szCur++;
|
|
}
|
|
|
|
rgsz[cItems++] = szAddPoint;
|
|
}
|
|
|
|
rgsz[cItems] = (SZ)NULL;
|
|
|
|
if((*szCur != '}') || (cItems >= cListItemsMax)) {
|
|
|
|
FFreeRgsz(rgsz);
|
|
return((RGSZ)NULL);
|
|
}
|
|
|
|
if (cItems < cListItemsMax) {
|
|
|
|
rgsz = (RGSZ)SRealloc(
|
|
(PB)rgsz,
|
|
(CB)((cItems + 1) * sizeof(SZ))
|
|
);
|
|
}
|
|
|
|
return(rgsz);
|
|
}
|
|
|
|
|
|
#define cbListMax (CB)0x2000
|
|
|
|
VOID
|
|
GrowValueBuffer( SZ *pszBuffer, PDWORD pSize, PDWORD pLeft, DWORD dwWanted, SZ *pszPointer );
|
|
|
|
|
|
#define VERIFY_SIZE(s) \
|
|
if ( dwSizeLeft < (s) ) { \
|
|
GrowValueBuffer( &szValue, &dwValueSize, &dwSizeLeft, (s), &szAddPoint ); \
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Converts an RGSZ into a list value.
|
|
** Arguments:
|
|
** rgsz: non-NULL, NULL-terminated array of zero-terminated strings to
|
|
** be converted.
|
|
** Returns:
|
|
** NULL if an error occurred.
|
|
** Non-NULL SZ if the conversion was successful.
|
|
**
|
|
**************************************************************************/
|
|
SZ APIENTRY SzListValueFromRgsz(rgsz)
|
|
RGSZ rgsz;
|
|
{
|
|
SZ szValue;
|
|
SZ szAddPoint;
|
|
SZ szItem;
|
|
BOOL fFirstItem = fTrue;
|
|
DWORD dwValueSize;
|
|
DWORD dwSizeLeft;
|
|
UINT rgszIndex = 0;
|
|
|
|
ChkArg(rgsz != (RGSZ)NULL, 1, (SZ)NULL);
|
|
|
|
if ((szAddPoint = szValue = (SZ)SAlloc(cbListMax)) == (SZ)NULL) {
|
|
return((SZ)NULL);
|
|
}
|
|
|
|
dwValueSize = dwSizeLeft = cbListMax;
|
|
|
|
*szAddPoint++ = '{';
|
|
dwSizeLeft--;
|
|
|
|
while(szItem = rgsz[rgszIndex]) {
|
|
|
|
VERIFY_SIZE(2);
|
|
|
|
if (fFirstItem) {
|
|
fFirstItem = fFalse;
|
|
} else {
|
|
*szAddPoint++ = ',';
|
|
dwSizeLeft--;
|
|
}
|
|
|
|
*szAddPoint++ = '"';
|
|
dwSizeLeft--;
|
|
|
|
while (*szItem) {
|
|
|
|
VERIFY_SIZE(1);
|
|
dwSizeLeft--;
|
|
if((*szAddPoint++ = *szItem++) == '"') {
|
|
VERIFY_SIZE(1);
|
|
dwSizeLeft--;
|
|
*szAddPoint++ = '"';
|
|
}
|
|
}
|
|
|
|
VERIFY_SIZE(1);
|
|
*szAddPoint++ = '"';
|
|
dwSizeLeft--;
|
|
rgszIndex++;
|
|
}
|
|
|
|
VERIFY_SIZE(2);
|
|
*szAddPoint++ = '}';
|
|
*szAddPoint = '\0';
|
|
dwSizeLeft -= 2;
|
|
|
|
// AssertRet(strlen(szValue) < dwValueSize, (SZ)NULL);
|
|
szItem = SzDupl(szValue);
|
|
SFree(szValue);
|
|
|
|
return(szItem);
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
GrowValueBuffer( SZ *pszBuffer, PDWORD pSize, PDWORD pLeft, DWORD dwWanted, SZ *pszPointer )
|
|
{
|
|
|
|
|
|
if ( *pLeft < dwWanted ) {
|
|
|
|
DWORD_PTR Offset = *pszPointer - *pszBuffer;
|
|
|
|
*pszBuffer = SRealloc( *pszBuffer, *pSize + cbListMax );
|
|
EvalAssert( *pszBuffer );
|
|
|
|
*pSize += cbListMax;
|
|
*pLeft += cbListMax;
|
|
|
|
*pszPointer = *pszBuffer + Offset;
|
|
}
|
|
}
|
|
|
|
|
|
static BOOL APIENTRY FSymbol(SZ sz)
|
|
{
|
|
ChkArg(sz != (SZ)NULL, 1, fFalse);
|
|
|
|
if (*sz++ != '$' ||
|
|
*sz++ != '(' ||
|
|
FWhiteSpaceChp(*sz) ||
|
|
*sz == ')')
|
|
return(fFalse);
|
|
|
|
while (*sz != ')' &&
|
|
*sz != '\0')
|
|
sz = SzNextChar(sz);
|
|
|
|
return(*sz == ')');
|
|
}
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Substitutes values from the Symbol Table for symbols of the form
|
|
** '$( <symbol> )' in the source string.
|
|
** Arguments:
|
|
** szSrc: non-NULL string in which to substitute symbol values.
|
|
** Notes:
|
|
** Requires that the Symbol Table was initialized with a successful
|
|
** call to FInitSymTab().
|
|
** A successful return value must be freed by the caller.
|
|
** Returns:
|
|
** NULL if any of the alloc operations fail or if the substituted
|
|
** string is larger than 8KB bytes (cchpFieldMax).
|
|
** non-NULL string with values substituted for symbols if all of the
|
|
** alloc operations succeed.
|
|
**
|
|
**************************************************************************/
|
|
SZ APIENTRY SzGetSubstitutedValue(SZ szSrc)
|
|
{
|
|
SZ szDest;
|
|
PCHP pchpDestCur;
|
|
CCHP cchpDest = (CCHP)0;
|
|
|
|
AssertDataSeg();
|
|
|
|
PreCondSymTabInit(NULL);
|
|
|
|
ChkArg(szSrc != (SZ)NULL, 1, (SZ)NULL);
|
|
|
|
if ((szDest = pchpDestCur = (SZ)SAlloc((CB)cchpFieldMax)) == (SZ)NULL)
|
|
return((SZ)NULL);
|
|
|
|
while (*szSrc != '\0')
|
|
{
|
|
if (FSymbol(szSrc))
|
|
{
|
|
SZ szSymEnd;
|
|
SZ szValue;
|
|
|
|
Assert(*szSrc == '$');
|
|
szSrc++;
|
|
Assert(*szSrc == '(');
|
|
szSymEnd = ++szSrc;
|
|
Assert(*szSrc != '\0' && *szSrc != ')');
|
|
while (*szSymEnd != ')')
|
|
{
|
|
Assert(*szSymEnd != '\0');
|
|
szSymEnd = SzNextChar(szSymEnd);
|
|
}
|
|
Assert(*szSymEnd == ')');
|
|
*szSymEnd = '\0';
|
|
szValue = SzFindSymbolValueInSymTab(szSrc);
|
|
*szSymEnd = ')';
|
|
szSrc = SzNextChar(szSymEnd);
|
|
|
|
if (szValue == (SZ)NULL)
|
|
continue;
|
|
|
|
if (cchpDest + strlen(szValue) >= cchpFieldMax ||
|
|
strcpy(pchpDestCur, szValue) != pchpDestCur)
|
|
{
|
|
SFree(szDest);
|
|
return((SZ)NULL);
|
|
}
|
|
|
|
pchpDestCur += strlen(szValue);
|
|
Assert(*pchpDestCur == '\0');
|
|
cchpDest += strlen(szValue);
|
|
Assert(cchpDest < cchpFieldMax);
|
|
}
|
|
else
|
|
{
|
|
SZ szNext = SzNextChar(szSrc);
|
|
|
|
while (szSrc < szNext)
|
|
{
|
|
*pchpDestCur++ = *szSrc++;
|
|
if (++cchpDest >= cchpFieldMax)
|
|
{
|
|
SFree(szDest);
|
|
return((SZ)NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Assert(cchpDest < cchpFieldMax);
|
|
|
|
*(szDest + cchpDest++) = '\0';
|
|
if (cchpDest < cchpFieldMax)
|
|
szDest = SRealloc(szDest,cchpFieldMax);
|
|
|
|
return(szDest);
|
|
}
|
|
|
|
|
|
//
|
|
// Routines exported from the legacy setup dll to allow
|
|
// direct manipulation of the inf symtab table.
|
|
//
|
|
|
|
PCSTR
|
|
LegacyInfLookUpSymbol(
|
|
IN PCSTR SymbolName
|
|
)
|
|
{
|
|
return(SzFindSymbolValueInSymTab((SZ)SymbolName));
|
|
}
|
|
|
|
|
|
BOOL
|
|
LegacyInfSetSymbolValue(
|
|
IN PCSTR SymbolName,
|
|
IN PCSTR SymbolValue
|
|
)
|
|
{
|
|
return(FAddSymbolValueToSymTab((SZ)SymbolName,(SZ)SymbolValue));
|
|
}
|
|
|
|
|
|
BOOL
|
|
LegacyInfRemoveInfSymbol(
|
|
IN PCSTR SymbolName
|
|
)
|
|
{
|
|
return(FRemoveSymbolFromSymTab((SZ)SymbolName));
|
|
}
|
|
|
|
|