675 lines
14 KiB
C
675 lines
14 KiB
C
#include "precomp.h"
|
|
#pragma hdrstop
|
|
/*********************************************************************/
|
|
/***** Common Library Component - Context Handling Routines 1 ********/
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
PINFCONTEXT pContextTop = NULL;
|
|
PINFCONTEXT pContextBottom = NULL;
|
|
PINFPERMINFO pInfPermInfoHead = NULL;
|
|
PINFPERMINFO pInfPermInfoTail = NULL;
|
|
PPARSED_INF pParsedInfCache = NULL;
|
|
INT ParsedInfCached = 0;
|
|
|
|
|
|
//
|
|
// Maximum number of parsed INFs that we keep in the cache
|
|
//
|
|
#define INF_CACHE_THRESHOLD 4
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Pushes INF context onto stack
|
|
**
|
|
** Arguments:
|
|
** Context to push
|
|
**
|
|
** Returns:
|
|
** True if pushed.
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
BOOL APIENTRY PushContext( PINFCONTEXT pContext )
|
|
{
|
|
|
|
SZ szHelpContext;
|
|
BOOL fOkay = fTrue;
|
|
|
|
|
|
//
|
|
// Set the per-context information
|
|
//
|
|
if ( pContextTop ) {
|
|
|
|
if ( pContextTop->szHelpFile ) {
|
|
while ((pContext->szHelpFile = SzDupl(pContextTop->szHelpFile )) == (SZ)NULL) {
|
|
if (!FHandleOOM(hWndShell)) {
|
|
pContext->szHelpFile = NULL;
|
|
return fFalse;
|
|
}
|
|
}
|
|
} else {
|
|
pContext->szHelpFile = NULL;
|
|
}
|
|
|
|
pContext->pseflHead = NULL;
|
|
pContext->dwLowContext = pContextTop->dwLowContext;
|
|
pContext->dwHighContext = pContextTop->dwHighContext;
|
|
pContext->dwHelpIndex = pContextTop->dwHelpIndex;
|
|
pContext->bHelpIsIndexed = pContextTop->bHelpIsIndexed;
|
|
szHelpContext = SzFindSymbolValueInSymTab("HelpContext");
|
|
|
|
} else {
|
|
|
|
pContext->pseflHead = NULL;
|
|
pContext->szHelpFile = NULL;
|
|
pContext->dwLowContext = 0;
|
|
pContext->dwHighContext = 0;
|
|
pContext->dwHelpIndex = 0;
|
|
pContext->bHelpIsIndexed = fFalse;
|
|
szHelpContext = NULL;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Allocate the local symbol table
|
|
//
|
|
|
|
if ( !(pContext->SymTab = SymTabAlloc()) ) {
|
|
if ( pContext->szHelpFile ) {
|
|
SFree( pContext->szHelpFile );
|
|
pContext->szHelpFile = NULL;
|
|
}
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
//
|
|
// Push context onto stack
|
|
//
|
|
pContext->pNext = pContextTop;
|
|
pContextTop = pContext;
|
|
|
|
if ( !pContextBottom ) {
|
|
pContextBottom = pContextTop;
|
|
}
|
|
|
|
|
|
//
|
|
// Add to the symbol table any per-context values.
|
|
//
|
|
if ( szHelpContext ) {
|
|
while (!FAddSymbolValueToSymTab("HelpContext", szHelpContext)) {
|
|
if (!FHandleOOM(hWndShell)) {
|
|
PopContext();
|
|
fOkay = fFalse;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
while (!FAddSymbolValueToSymTab("$ShellCode", "0")) {
|
|
if (!FHandleOOM(hWndShell)) {
|
|
PopContext();
|
|
fOkay = fFalse;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fOkay;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Pops a context off the stack
|
|
**
|
|
** Arguments:
|
|
** none
|
|
**
|
|
** Returns:
|
|
** Popped context
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
PINFCONTEXT APIENTRY PopContext( VOID )
|
|
{
|
|
PINFCONTEXT pContext = pContextTop;
|
|
|
|
pContextTop = pContext->pNext;
|
|
|
|
return pContext;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Frees memory of a context
|
|
**
|
|
** Arguments:
|
|
** Pointer to context
|
|
**
|
|
** Returns:
|
|
** nothing
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
VOID APIENTRY FreeContext( PINFCONTEXT pContext )
|
|
{
|
|
//
|
|
// Free per-context information
|
|
//
|
|
if ( pContext->pseflHead ) {
|
|
|
|
PSEFL psefl = pContext->pseflHead;
|
|
PSEFL pseflNext;
|
|
|
|
while ( psefl ) {
|
|
pseflNext = psefl->pseflNext;
|
|
FFreePsefl(psefl);
|
|
psefl = pseflNext;
|
|
}
|
|
}
|
|
|
|
if ( pContext->szHelpFile ) {
|
|
SFree( pContext->szHelpFile );
|
|
}
|
|
|
|
if ( pContext->szShlScriptSection ) {
|
|
SFree( pContext->szShlScriptSection );
|
|
}
|
|
|
|
//
|
|
// Free local symbol table
|
|
//
|
|
FFreeSymTab( pContext->SymTab );
|
|
|
|
//
|
|
// Free context
|
|
//
|
|
SFree( pContext );
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Given an INF name, returns a pointer to the corresponding
|
|
** INF permanent information block. It creates a new permanent
|
|
** information block if none exists for the name provided.
|
|
**
|
|
** Arguments:
|
|
** INF name
|
|
**
|
|
** Returns:
|
|
** Pointer to INF permanent information block.
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
PINFPERMINFO APIENTRY NameToInfPermInfo( SZ szName , BOOL AllocIfNotPresent)
|
|
{
|
|
PINFPERMINFO pInfo;
|
|
|
|
if ( pInfPermInfoHead ) {
|
|
|
|
pInfo = pInfPermInfoHead;
|
|
|
|
while ( pInfo ) {
|
|
|
|
if (CrcStringCompare( szName, pInfo->szName ) == crcEqual) {
|
|
return pInfo;
|
|
}
|
|
pInfo = pInfo->pNext;
|
|
}
|
|
}
|
|
|
|
if( AllocIfNotPresent ) {
|
|
return AddInfPermInfo( szName );
|
|
}
|
|
else {
|
|
return (PINFPERMINFO)NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Adds a new INF permanent information block with the given INF
|
|
** name.
|
|
**
|
|
** Arguments:
|
|
** INF name
|
|
**
|
|
** Returns:
|
|
** Pointer to the INF permanent information block.
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
PINFPERMINFO APIENTRY AddInfPermInfo( SZ szName )
|
|
{
|
|
|
|
PINFPERMINFO pInfo;
|
|
SZ szInfName;
|
|
|
|
if ( (pInfo = (PINFPERMINFO)SAlloc( sizeof( INFPERMINFO ) )) != NULL ) {
|
|
|
|
if ( (szInfName = (SZ)SAlloc( lstrlen( szName ) + 1 )) != NULL) {
|
|
|
|
strcpy( szInfName, szName );
|
|
|
|
|
|
pInfo->szName = szInfName;
|
|
pInfo->psdleHead = NULL;
|
|
pInfo->psdleCur = NULL;
|
|
pInfo->pclnHead = NULL;
|
|
pInfo->ppclnTail = &(pInfo->pclnHead);
|
|
pInfo->pNext = NULL;
|
|
pInfo->pstfHead = NULL;
|
|
|
|
if ( pInfPermInfoTail ) {
|
|
|
|
pInfo->InfId = pInfPermInfoTail->InfId+1;
|
|
pInfPermInfoTail->pNext = pInfo;
|
|
pInfPermInfoTail = pInfo;
|
|
|
|
} else {
|
|
|
|
pInfo->InfId = 0;
|
|
pInfPermInfoHead = pInfPermInfoTail = pInfo;
|
|
}
|
|
|
|
return pInfo;
|
|
}
|
|
|
|
SFree( pInfo);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Given the path of an INF file, obtains the INF name (i.e. the
|
|
** name of the file without extension.
|
|
**
|
|
** Arguments:
|
|
** Path to inf file
|
|
** Pointer to buffer where the INF name will be stored
|
|
**
|
|
** Returns:
|
|
** TRUE if name obtained.
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
BOOL APIENTRY PathToInfName( SZ szPath, SZ szName )
|
|
{
|
|
PCHAR p,r,q;
|
|
|
|
p = r = szPath + strlen(szPath) - 1;
|
|
while ( (p >= szPath) && (*p != '\\') && (*p != ':') ) {
|
|
p--;
|
|
}
|
|
p++;
|
|
q = p;
|
|
while ( (q <= r) && (*q != '.') && (*q != '\0') ) {
|
|
q++;
|
|
}
|
|
memcpy( szName, p, (size_t)(q-p) );
|
|
szName[q-p] = '\0';
|
|
SzStrUpper( szName );
|
|
|
|
return fTrue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
** Purpose:
|
|
** Determines what symbol table to use for a given symbol
|
|
**
|
|
** Arguments:
|
|
** szSymbol: non-NULL, non-empty zero terminated string containing
|
|
** the value of the symbol to be searched for.
|
|
**
|
|
**
|
|
**
|
|
** Syntax:
|
|
**
|
|
** VarName := [![<Modifier>:]]Name
|
|
**
|
|
** Modifier := L | G | P | S
|
|
**
|
|
**
|
|
** L = Local (this context)
|
|
** G = Global (top context)
|
|
** P = Parent (parent context)
|
|
** S = Static (INF temp. info)
|
|
**
|
|
**
|
|
**
|
|
** Returns:
|
|
** Pointer to the context in which to look for the symbol
|
|
**
|
|
**
|
|
**************************************************************************/
|
|
PSYMTAB APIENTRY PInfSymTabFind( SZ szSymbol, SZ *szRealSymbol )
|
|
{
|
|
|
|
|
|
SZ p;
|
|
PSYMTAB pSymTab = NULL;
|
|
|
|
p = szSymbol;
|
|
|
|
if ( p && *p != '\0' ) {
|
|
|
|
if ( *p == '!' ) {
|
|
|
|
p++;
|
|
|
|
if ( (strlen(p) > 2) && (*(p+1) == ':') ) {
|
|
|
|
switch ( *p ) {
|
|
|
|
case 'G':
|
|
case 'g':
|
|
//
|
|
// Global
|
|
//
|
|
pSymTab = pGlobalContext()->SymTab;
|
|
*szRealSymbol = p+2;
|
|
break;
|
|
|
|
case 'L':
|
|
case 'l':
|
|
//
|
|
// Local
|
|
//
|
|
pSymTab = pLocalContext()->SymTab;
|
|
*szRealSymbol = p+2;
|
|
break;
|
|
|
|
case 'P':
|
|
case 'p':
|
|
//
|
|
// Parent
|
|
//
|
|
pSymTab = pLocalContext()->pNext->SymTab;
|
|
*szRealSymbol = p+2;
|
|
break;
|
|
|
|
case 'S':
|
|
case 's':
|
|
//
|
|
// Static
|
|
//
|
|
pSymTab = pLocalContext()->pInfTempInfo->SymTab;
|
|
*szRealSymbol = p+2;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Invalid
|
|
//
|
|
pSymTab = NULL;
|
|
*szRealSymbol = NULL;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Global variable
|
|
//
|
|
pSymTab = pGlobalContext()->SymTab;
|
|
*szRealSymbol = p;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Local variable
|
|
//
|
|
pSymTab = pLocalContext()->SymTab;
|
|
*szRealSymbol = p;
|
|
|
|
}
|
|
}
|
|
|
|
return pSymTab;
|
|
}
|
|
|
|
|
|
|
|
PPARSED_INF
|
|
APIENTRY
|
|
ParsedInfAlloc(
|
|
PINFPERMINFO pInfPermInfo
|
|
)
|
|
{
|
|
PPARSED_INF pParsedInf = NULL;
|
|
|
|
|
|
//
|
|
// If the cache is not empty, see if this INF is already in
|
|
// the cache.
|
|
//
|
|
if ( ParsedInfCached > 0 ) {
|
|
|
|
pParsedInf = pParsedInfCache;
|
|
|
|
while ( pParsedInf ) {
|
|
|
|
if ( pParsedInf->pInfPermInfo == pInfPermInfo ) {
|
|
|
|
//
|
|
// Found the parsed INF in the cache.
|
|
// Take it out of the cache.
|
|
//
|
|
if (pParsedInf->pPrev) {
|
|
(pParsedInf->pPrev)->pNext = pParsedInf->pNext;
|
|
}
|
|
|
|
if (pParsedInf->pNext) {
|
|
(pParsedInf->pNext)->pPrev = pParsedInf->pPrev;
|
|
}
|
|
|
|
if ( pParsedInfCache == pParsedInf ) {
|
|
pParsedInfCache = pParsedInf->pNext;
|
|
}
|
|
|
|
pParsedInf->pPrev = NULL;
|
|
pParsedInf->pNext = NULL;
|
|
|
|
ParsedInfCached--;
|
|
|
|
break;
|
|
}
|
|
|
|
pParsedInf = pParsedInf->pNext;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If the parsed INF was not in the cache, we allocate space for a
|
|
// new one.
|
|
//
|
|
if ( pParsedInf == NULL ) {
|
|
|
|
if ( pParsedInf = (PPARSED_INF)SAlloc( sizeof( PARSED_INF ) ) ) {
|
|
|
|
pParsedInf->pPrev = NULL;
|
|
pParsedInf->pNext = NULL;
|
|
pParsedInf->pInfPermInfo = pInfPermInfo;
|
|
pParsedInf->MasterLineArray = NULL;
|
|
pParsedInf->MasterLineCount = 0;
|
|
pParsedInf->MasterFile = NULL;
|
|
pParsedInf->MasterFileSize = 0;
|
|
}
|
|
}
|
|
|
|
return pParsedInf;
|
|
}
|
|
|
|
|
|
|
|
extern
|
|
BOOL
|
|
APIENTRY
|
|
FFreeParsedInf(
|
|
PPARSED_INF pParsedInf
|
|
)
|
|
{
|
|
PPARSED_INF pInf;
|
|
|
|
|
|
//
|
|
// We will put this Parsed INF in the cache. If the number of cached
|
|
// INFs is above the threshold we will free the least recently used
|
|
// one.
|
|
//
|
|
|
|
if (pParsedInfCache) {
|
|
pParsedInfCache->pPrev = pParsedInf;
|
|
}
|
|
pParsedInf->pNext = pParsedInfCache;
|
|
pParsedInfCache = pParsedInf;
|
|
|
|
|
|
if ( ParsedInfCached++ >= INF_CACHE_THRESHOLD ) {
|
|
|
|
//
|
|
// There are too many INFs in the cache, look for the last one
|
|
// and free it.
|
|
//
|
|
pInf = pParsedInf;
|
|
|
|
while ( pInf->pNext ) {
|
|
pInf = pInf->pNext;
|
|
}
|
|
|
|
if (pInf->pPrev) {
|
|
(pInf->pPrev)->pNext = pInf->pNext;
|
|
}
|
|
|
|
if (pInf->pNext) {
|
|
(pInf->pNext)->pPrev = pInf->pPrev;
|
|
}
|
|
|
|
if ( pParsedInfCache == pInf ) {
|
|
pParsedInfCache = pInf->pNext;
|
|
}
|
|
|
|
pInf->pPrev = NULL;
|
|
pInf->pNext = NULL;
|
|
|
|
ParsedInfCached--;
|
|
|
|
if ( pInf->MasterLineArray ) {
|
|
SFree( pInf->MasterLineArray);
|
|
}
|
|
|
|
if ( pInf->MasterFile ) {
|
|
SFree( pInf->MasterFile );
|
|
}
|
|
|
|
SFree( pInf);
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
extern
|
|
BOOL
|
|
APIENTRY
|
|
FFlushInfParsedInfo(
|
|
SZ szInfName
|
|
)
|
|
{
|
|
CHAR szName[cchlFullPathMax];
|
|
PINFPERMINFO pPermInfo;
|
|
PPARSED_INF pInf;
|
|
|
|
//
|
|
// Convert the inf path passed in to an inf name
|
|
//
|
|
|
|
PathToInfName( szInfName, szName );
|
|
|
|
//
|
|
// Find the perminfo for this inf. If none exists then return
|
|
//
|
|
|
|
if( !( pPermInfo = NameToInfPermInfo( szName , FALSE ) ) ) {
|
|
return ( TRUE );
|
|
}
|
|
|
|
//
|
|
// Go through the parsed inf cache, see if inf exists in the cache.
|
|
// if it does, flush it.
|
|
//
|
|
|
|
if (pParsedInfCache) {
|
|
pInf = pParsedInfCache;
|
|
while ( pInf ) {
|
|
if( pInf->pInfPermInfo == pPermInfo ) {
|
|
|
|
if (pInf->pPrev) {
|
|
(pInf->pPrev)->pNext = pInf->pNext;
|
|
}
|
|
|
|
if (pInf->pNext) {
|
|
(pInf->pNext)->pPrev = pInf->pPrev;
|
|
}
|
|
|
|
if ( pParsedInfCache == pInf ) {
|
|
pParsedInfCache = pInf->pNext;
|
|
}
|
|
|
|
pInf->pPrev = NULL;
|
|
pInf->pNext = NULL;
|
|
|
|
ParsedInfCached--;
|
|
|
|
if ( pInf->MasterLineArray ) {
|
|
SFree( pInf->MasterLineArray );
|
|
}
|
|
|
|
if ( pInf->MasterFile ) {
|
|
SFree( pInf->MasterFile );
|
|
}
|
|
|
|
SFree( pInf );
|
|
break;
|
|
}
|
|
|
|
pInf = pInf->pNext;
|
|
}
|
|
|
|
}
|
|
return ( TRUE );
|
|
}
|