Windows2000/private/windbg64/windbg/vib.c
2020-09-30 17:12:32 +02:00

2101 lines
46 KiB
C

/*++
Copyright 1992 Microsoft Corporation
Module Name:
vib.c
Abstract:
This module contains the VIB (Variable Information Block) support
routines used by the watch and local windows.
Author:
William J. Heaton (v-willhe) 20-Jul-1992
Griffith Wm. Kadnier (v-griffk) 10-Mar-1993
Environment:
Win32, User Mode
--*/
#include "precomp.h"
#pragma hdrstop
typedef struct {
USHORT cb;
LPVOID lpv;
} MEMLINK, * PTRMEMLINK;
#define NAMES_BUFFER 2048
#define BUFFERMAX 1024
// Global Storage (PROGRAM)
extern CXF CxfIp;
// Global Storage (FILE)
static char szBuffer[BUFFERMAX+1];
// Prototypes (LOCAL)
PTRCIF PASCAL FTGetCif( VOID );
VOID PASCAL FTFreeVib( PTRVIB );
VOID PASCAL FTFreeVibChildren( PTRVIB );
VOID PASCAL FTFreeAllCif( PTRCIF );
LTS PASCAL FTExpandVib( PTRVIB pvib );
VOID PASCAL FTInvalidateVib( PTRVIB pvib);
VOID PASCAL FTResetVib( PTRVIB pvib);
BOOL PASCAL FTSetupWoj( PTRVIB pvib, PSTR pName, UINT cbSize);
/*** FTMakeWatchEntry
* Purpose: To make a watchentry
* Input:
* ppvib - A pointer to a vib pointer of where to place the new vib
* pvit - The vit tree that the watchentry is to be added to.
* szExpStr- A string containing the expression
* Output:
* Returns FALSE is ok, TRUE if errors
* Exceptions:
* Notes:
*/
int
FTMakeWatchEntry (
void *ppvibVoid,
void *pvit,
char *szExpStr
)
{
EESTATUS Err;
UINT cbszExpStr;
char * pch;
ULONG iLast;
PTRVIB * ppvib = (PTRVIB *) ppvibVoid;
// get a new vib
if( !(*ppvib = PvibAlloc ( NULL, (PTRVIB) pvit )) ) {
FTError ( OUTOFMEMORY );
return TRUE;
}
// take out leading and trailing spaces
while( *szExpStr == ' ' ) {
szExpStr++;
}
if ( !*szExpStr ) {
return TRUE;
}
pch = szExpStr + strlen(szExpStr);
while (pch > szExpStr) {
if (*(pch = CharPrev(szExpStr, pch)) != ' ') {
break;
}
}
pch += (IsDBCSLeadByte(*pch) ? 2 : 1);
strcpy(szBuffer,szExpStr);
// do a parse
if( (Err = EEParse(szBuffer, radix, fCaseSensitive, &(*ppvib)->hTMBd, &iLast)) ) {
// (*ppvib) = (PTRVIB)NULL;
// return(TRUE);
}
// Setup the Woj
cbszExpStr = (UINT) (pch - szExpStr);
if ( !FTSetupWoj( *ppvib, szExpStr, cbszExpStr) ) {
*ppvib = NULL;
FTError ( OUTOFMEMORY );
return TRUE;
}
(*ppvib)->vibPtr = vibWatch;
return FALSE;
} /* WTMakeWatchEntry() */
/*** FTSetupWoj
* Purpose: Add a Woj (Watch Object?) to a vib
* Input:
* pvib - Pointer to the vib
* pName - Pointer to the Name
* cbSize - Size of Name
* Output:
* TRUE/FALSE if memory alloc failed
* Exceptions:
* Notes:
*/
BOOL
FTSetupWoj(
PTRVIB pvib,
PSTR pName,
UINT cbSize
)
{
// If we already have one, lose it
if ( pvib->pwoj ) {
free( pvib->pwoj );
}
// Allocate the Woj
pvib->pwoj = (PTRWOJ) malloc( sizeof(WOJ) + cbSize + 1 );
if ( pvib->pwoj == NULL ) {
return(FALSE);
}
// copy over the string
strncpy ( pvib->pwoj->szExpStr, pName, cbSize);
pvib->pwoj->szExpStr[cbSize] = '\0';
// Fill out the other info
pvib->pwoj->iFormSpec = (WORD)cbSize;
pvib->pwoj->ErrNbr = 0;
pvib->pwoj->cbLen = (unsigned char)cbSize;
return(TRUE);
}
/*** FTVerify
* Purpose: To verify the watch tree
* Input:
* pcxf - A pointer to the current CXF
* pvib - A pointer to the vib to verify
* Output:
* Returns:
* Exceptions:
* Notes:
*/
BOOL
FTVerify (
PCXF pcxf,
PTRVIB pvib
)
{
EEPDTYP ExpTyp;
BOOL fBind = FALSE;
EEHSTR hTypeOld = NULL;
EEHSTR hTypeNew = NULL;
LPSTR lszTypeOld;
LPSTR lszTypeNew;
HTI hti;
RTMI rti = {0};
PTI pti;
BOOL fStatus = FALSE;
/*
* If we're in a function evaluation get out fast
*/
if ( (LptdCur != NULL) && (LptdCur->fInFuncEval)) {
return(fStatus);
}
/*
* only while the Variable Info Block is valid
*/
for (; pvib; pvib = pvib->pvibSib ) {
/*
* Don't rebind this items
*/
if (pvib->vibPtr == vibGeneric) {
continue;
}
/*
* rebind, the error will be displayed during evaluation
*/
if (EEGetTypeFromTM(&pvib->hTMBd, NULL, &hTypeOld, TRUE ) != EENOERROR) {
hTypeOld = NULL;
}
fBind = ((pvib->hprocCache != ( SHpCXTFrompCXF ( pcxf ) )->hProc) ||
(pvib->hblkCache != ( SHpCXTFrompCXF ( pcxf ) )->hBlk));
if ( fBind ) {
pvib->hprocCache = ( SHpCXTFrompCXF ( pcxf ) )->hProc;
pvib->hblkCache = ( SHpCXTFrompCXF ( pcxf ) )->hBlk;
fStatus = TRUE;
}
/*
* Make sure we can still Bind
*/
if ( pvib->hTMBd &&
EEBindTM(&pvib->hTMBd, SHpCXTFrompCXF(pcxf),fBind,FALSE) == EENOERROR ) {
/*
* Reset the NoBind Flag because it back in context
*/
FTResetVib(pvib);
/*
* Make sure the Function Evaluation gets updated
*/
if (EEInfoFromTM ( &pvib->hTMBd, &rti, &hti ) == EENOERROR) {
DAssert(hti != (HTI)NULL);
pti = (PTI) MMLpvLockMb (hti);
if (pti->fFunction) {
pvib->flags.FuncEval = 1;
}
if ( pti != NULL ) {
MMbUnlockMb ( hti );
}
}
if (hti != (HTI) NULL) {
EEFreeTI(&hti);
}
/*
* Has the Type changed for a Watch or a Type
*/
if ((pvib->vibPtr == vibWatch) || (pvib->vibPtr == vibType)) {
lszTypeOld = NULL;
lszTypeNew = NULL;
if (hTypeOld) {
if (EEGetTypeFromTM(&pvib->hTMBd, NULL, &hTypeNew, TRUE ) != EENOERROR) {
hTypeNew = NULL;
} else {
lszTypeOld = (PSTR) MMLpvLockMb( hTypeOld );
lszTypeNew = (PSTR) MMLpvLockMb( hTypeNew );
}
}
if (!lszTypeNew || strcmp(lszTypeOld, lszTypeNew)) {
/*
* remove the rest of the tree
*/
FTFreeAllCif(pvib->pcif);
pvib->pcif = NULL;
FTclnUpdateParent ( pvib, (1-pvib->cln) );
fStatus = TRUE;
/*
* Make sure VibPtr is reset
*/
if ( pvib->vibPtr == vibWatch || pvib->vibPtr == vibType ) {
ExpTyp = EEIsExpandable(&pvib->hTMBd);
if ( ExpTyp == EETYPE || ExpTyp == EETYPENOTEXP ) {
pvib->vibPtr = vibType;
} else {
pvib->vibPtr = vibWatch;
}
}
}
if (lszTypeNew) {
MMbUnlockMb( hTypeOld );
MMbUnlockMb( hTypeNew );
}
}
/*
* Update any children
*/
if (pvib->pcif) {
if ( pvib->pcif->hTMBd ) {
EEBindTM( &pvib->pcif->hTMBd, SHpCXTFrompCXF(pcxf),
fBind, FALSE);
}
/*
* If a child had a signicant change, so did we
*/
if ( FTVerify ( pcxf, pvib->pcif->pvibChild ) ) {
fStatus = TRUE;
}
}
} else {
/*
* Couldn't Bind, Invalidate any children
*/
if ( pvib->pcif ) {
FTInvalidateVib(pvib->pcif->pvibChild);
}
}
}
if (hTypeOld) {
EEFreeStr(hTypeOld);
}
if (hTypeNew) {
EEFreeStr(hTypeNew);
}
return(fStatus);
} /* FTVerify() */
/*** FTVerifyNew
* Purpose: Determine if a vib's result have changed since
* the last time a user saw it
* Input:
* pvit - A pointer to the vit
* oln - Item number of interest
* Output:
* Returns:
* TRUE/FALSE the item has changed
* Exceptions:
* Notes:
*/
BOOL
FTVerifyNew(
PTRVIT pVit,
ULONG oln
)
{
PTRVIB pVib = FTvibGetAtLine( pVit, oln);
VPI i;
// No Vib, No change
if ( pVib == 0) {
return(FALSE);
}
i = pVib->vibIndex;
// Give EE a chance to fill out the result
FTEnsureTextExists( pVib );
FTGetPanelString( pVit, pVib, ID_PANE_RIGHT);
// Do we have a string at all?
if ( pVib->pvtext[i].pszValueP || pVib->pvtext[i].pszValueC) {
// Do we have both strings?
if ( pVib->pvtext[i].pszValueP && pVib->pvtext[i].pszValueC ) {
if ((!_strcmpi(pVib->pvtext[i].pszValueC,pVib->pvtext[i].pszValueP)) &&
(pVib->pvtext[i].fChanged == FALSE))
{
return(FALSE);
} else
if ((!_strcmpi(pVib->pvtext[i].pszValueC,pVib->pvtext[i].pszValueP)) &&
(pVib->pvtext[i].fChanged == TRUE))
{
pVib->pvtext[i].fChanged = FALSE;
return(TRUE);
}
}
// Nope, It changed
pVib->pvtext[i].fChanged = TRUE;
return(TRUE);
}
// Nope, No change
return(FALSE);
} /* FTVerifyNew() */
/*** FTvibGetAtLine Get the vib starting at the line specified.
* Purpose: Given a vit, and a line, return the vib packet discribing that line.
* Input:
* pvit - A valid Variable Info block Top describing a Variable Info
* Block list
* oln - The line of interest
* Output:
* Returns
* pvib - A pointer to a vib that describes the requested line
* Exceptions:
* Notes: Make sure the Variable Info block Top list is valid!
*/
PTRVIB
FTvibGetAtLine(
PTRVIT pvit,
ULONG oln
)
{
ULONG olnCur = 0;
VPI vpiT = 0;
PTRVIB pvib;
ULONG strIndex;
HTI hti;
RTMI rti = {0};
PTI pti;
if ( pvit ) {
pvib = pvit->pvibChild;
} else {
return(NULL);
}
/*
* Loop through the vib tree looking for the correct vib. Do this
* by adding the count of lines in a pvib structure until we get
* to the correct vib.
*/
while( pvib && olnCur != oln ) {
/*
* Is the line number we are looking for in the current vib?
* YES -- move to the child of this vib (expanded item)
* NO -- skip to the next vib in this list
*/
if( oln < olnCur + (WORD)pvib->cln ) {
olnCur++;
vpiT = 0;
pvib = pvib->pcif->pvibChild; // go into the expanded item.
}
else { // skip this vib, go on to the next
olnCur += pvib->cln;
pvib = pvib->pvibSib;
}
if ( pvib == NULL ) {
break;
}
/*
* Move to the i-th element of the current vib, where i is the
* distance between the first line in the vib and the
* actual line desired.
* If the current vib is a vibGeneric then we need to get the
* i-th element in this vib.
* If the current vib is a vibChild -????
* ELSE -- no action needs to be taken -- use the current vib
* since it is a one line item.
*/
if ( pvib->vibPtr == vibGeneric || pvib->vibPtr == vibChild ) {
HTM hTM;
if ((!pvib->pvibSib) ||
(oln < olnCur + pvib->vibIndex - vpiT) ) {
EESTATUS Err;
/*
* search for the generic vib
*/
while( pvib->pvibSib ) {
pvib = pvib->pvibSib;
}
/*
* OK -- now if we have some data for this item then we
* can get information about it.
*/
DAssert(pvib->hTMBd == 0);
if ( !pvib->flags.NoData ) {
// get the index and TM
pvib->vibIndex = (unsigned short) (vpiT + oln - olnCur);
/*
* Make sure the structure we are about to index into
* already exitsts.
*/
FTEnsureTextExists( pvib );
/*
* Now see if we have already created a TM for this, if
* so then we can just use it.
*/
if (pvib->pvtext[pvib->vibIndex].htm) {
;
} else {
/*
* get the TM to expand.
*/
if( pvib->pvibParent->pcif->hTMBd ) {
hTM = pvib->pvibParent->pcif->hTMBd;
} else {
hTM = pvib->pvibParent->hTMBd;
}
Err = EEGetChildTM ( &hTM, pvib->vibIndex,
&pvib->pvtext[pvib->vibIndex].htm,
&strIndex, fCaseSensitive, radix );
if (Err) {
CVExprErr ( Err, MSGGERRSTR, &hTM, NULL);
pvib->flags.NoBind;
} else {
if (!EEInfoFromTM(&pvib->pvtext[pvib->vibIndex].htm,
&rti, &hti)) {
DAssert(hti != (HTI) NULL);
pti = (PTI) MMLpvLockMb( hti );
if (pti != NULL) {
if (pti->fFunction) {
pvib->flags.FuncEval = 1;
}
MMbUnlockMb( hti );
}
}
if (hti != (HTI) NULL) {
EEFreeTI(&hti);
}
}
}
olnCur = oln;
}
}
else {
// check out this Variable Info Block, it cannot be
// the generic Variable Info Block!
// we must advance by the preceeding blank space
olnCur += pvib->vibIndex - vpiT;
vpiT = pvib->vibIndex + 1;
}
}
}
return( pvib );
} /* FTvibGetAtLine() */
/*** PvibAlloc
* Purpose: To get a new Variable Info Block. If the list has a Variable
* Info Block after it, choose that as the next Variable Info Block,
* but don't alter the current Variable Info Block. If a new Variable
* Info Block must be allocated, all fields are initialized. This
* does not update anything in the parent!
* Input:
* pvib - A pointer to the potential next vib. This may be NULL;
* pvibParent - A pointer to the parent vib, This may not be NULL;
* Output:
* Returns
* A pointer to the next vib. The new vib will be unchanged if it
* already existed, otherwise it will be initialized.
* Exceptions:
* Notes:
*/
PTRVIB
PvibAlloc (
PTRVIB pvib,
PTRVIB pvibParent
)
{
if ( !pvib ) {
pvib = (PTRVIB) malloc( sizeof(VIB) );
if ( !( pvib ) ) {
return ( NULL );
}
memset ( pvib, 0, sizeof( VIB ) );
pvib->cln = 1;
pvib->pvibParent = pvibParent;
pvib->vibPtr = vibUndefined;
// if the parent has a parent, then it must not be a Variable
// Info block Top, get one more than the parents level
if ( pvibParent->pvibParent ) {
pvib->level = (unsigned char) (pvibParent->level + 1);
}
else {
pvib->level = 0;
}
}
return ( pvib );
} /* PvibAlloc() */
/*** FTvibGet
* Purpose: To get a new Variable Info Block. If the list has a Variable
* Info Block after it, choose that as the next Variable Info Block,
* but don't alter the current Variable Info Block. If a new Variable
* Info Block must be allocated, all fields are initialized. This
* does not update anything in the parent!
* Input:
* pvib - A pointer to the potential next vib. This may be NULL;
* pvibParent - A pointer to the parent vib, This may not be NULL;
* Output:
* Returns
* A pointer to the next vib. The new vib will be unchanged if it
* already existed, otherwise it will be initialized.
* Exceptions:
* Notes:
*/
PTRVIB
FTvibGet (
PTRVIB pvib,
PTRVIB pvibParent
)
{
if ( !pvib ) {
pvib = (PTRVIB) malloc( sizeof(VIB) );
if ( !( pvib ) ) {
return ( NULL );
}
memset ( pvib, 0, sizeof( VIB ) );
pvib->cln = 1;
pvib->pvibParent = pvibParent;
pvib->vibPtr = vibUndefined;
// if the parent has a parent, then it must not be a Variable
// Info block Top, get one more than the parents level
if ( pvibParent->pvibParent ) {
pvib->level = (unsigned char) (pvibParent->level + 1);
}
else {
pvib->level = 0;
}
}
return ( pvib );
}
/*** FTvibInit
* Purpose: To clear out an existing Variable Info Block, freeing all of
* its children and sibilings.
* Input:
* pvib - A pointer to the vib to be initialized
* pvibParent - A pointer to the parent, this may not be NULL
* Output:
* Returns pvib
* Exceptions:
* Notes:
*/
PTRVIB
FTvibInit(
PTRVIB pvib,
PTRVIB pvibParent
)
{
// Free all of the children. Don't use FTFreeVibChildren() because it may
// merge this vibif it is an array
FTFreeAllCif ( pvib->pcif );
// free all remaining sibiling
FTFreeAllSib ( pvib->pvibSib );
pvib->pvibSib = (PTRVIB) NULL;
// reinitialize the packet
if ( pvib->vibPtr != vibGeneric && pvib->vibPtr != vibUndefined && pvib->hTMBd ) {
EEFreeTM (&pvib->hTMBd);
}
if ( pvib->pwoj ) {
free( pvib->pwoj );
pvib->pwoj = (PTRWOJ)NULL;
}
memset ( pvib, 0, sizeof( VIB ) );
pvib->cln = 1;
pvib->pvibParent = pvibParent;
pvib->vibPtr = vibUndefined;
// if the parent has a parent, then it must not be a Variable Info
// block Top, get one more than the parent's level
if( pvibParent->pvibParent ) {
pvib->level = (unsigned char) (pvibParent->level + 1);
} else {
pvib->level = 0;
}
return(pvib);
} /* FTvibInit() */
/*** FTGetCif
* Purpose: To allocate a full Child InFo packet.
* Input: NONE
* Output:
* Returns A pointer to a new Child InFo packet.
* Exceptions:
* Notes:
*/
PTRCIF
FTGetCif(
void
)
{
PTRCIF pcif;
if ( (pcif = (PTRCIF) malloc( sizeof(CIF) )) ) {
memset(pcif, 0, sizeof(CIF));
}
return ( pcif );
} /* FTGetCif() */
/*** FTFreeVib
* Purpose: To free a Variable Info Block and all of its associated memory
* Input:
* pvib - A pointer to the Variable Info Block that is to be freed
* Output:
* Returns .....
* Exceptions:
* Notes:
*/
VOID
FTFreeVib (
PTRVIB pvib
)
{
ULONG i;
if ( pvib ) {
// free the TM if it is appropriate
// For child TMS -- this is a copy of the item in the vibGeneric
if ( pvib->vibPtr == vibChild) {
pvib->hTMBd = 0;
}
if ( pvib->vibPtr != vibUndefined && pvib->hTMBd ) {
EEFreeTM ( &pvib->hTMBd );
}
// Free the watch information
if ( pvib->pwoj )
free(pvib->pwoj );
// free any text strings
if ( pvib->cText ) {
for (i=0; i<pvib->cText ; i++ ) {
if ( pvib->pvtext[i].pszValueC)
free(pvib->pvtext[i].pszValueC);
if ( pvib->pvtext[i].pszValueP)
free(pvib->pvtext[i].pszValueP);
if ( pvib->pvtext[i].pszFormat)
free(pvib->pvtext[i].pszFormat);
if ( pvib->pvtext[i].htm) {
EEFreeTM(&pvib->pvtext[i].htm);
}
}
free(pvib->pvtext);
}
// now free the Variable Info Block itself
free(pvib);
}
return;
} /* FTFreeVib() */
/*** FTFreeVibChildren
* Purpose: Given a Variable Info Block, clear out all child structures.
* The pcif (Pointer to Child Info) field will be NULL on return.
* Input:
* pvib - A pointer to the Variable Info Block that is to be cleared
* Output:
* Returns .....
* Exceptions:
* Notes: If the vib is of type vibArray, the vib itself may be merged in
* with the genaric array vib.
*/
VOID
FTFreeVibChildren (
PTRVIB pvib
)
{
PTRVIB pvibCur;
VIB vibT;
// free all of its Child InFo packets
FTFreeAllCif ( pvib->pcif );
pvib->pcif = NULL;
// if the Variable Info Block is expanded, merge it back into the
// the generic element by eliminating it from the child list
if( pvib->vibPtr != vibChild ) return;
// search the list
pvibCur = &vibT;
// This should never be at level 0 of the chain,
// the parent should never be a Variable Info block Top
pvibCur->pvibSib = pvib->pvibParent->pcif->pvibChild;
while( pvibCur->pvibSib != pvib ) pvibCur = pvibCur->pvibSib;
pvibCur->pvibSib = pvib->pvibSib;
pvib->pvibParent->pcif->pvibChild = vibT.pvibSib;
// Don't free the hTM since it is a copy of the one being saved in
// the generic structure rather than a duplicate handle.
pvib->hTMBd = 0;
// if ( pvib->hTMBd ) {
// EEFreeTM ( &pvib->hTMBd );
// }
FTFreeVib ( pvib );
return;
} /* FTFreeVibChildren() */
/*** FTFreeAllSib
* Purpose: Starting at the point specifed in the tree, all following children
* and sibilings are freed. The Variable Info Block specified is also freed.
* Input:
* pvib - The first Variable Info Block in the list to be freed.
* Output:
* Returns .....
* Exceptions:
* Notes:
*/
void
FTFreeAllSib(
PTRVIB pvib
)
{
while ( pvib ) {
if( pvib->pcif ) {
FTFreeAllCif( pvib->pcif );
}
if( pvib->pvibSib ) {
pvib->pvibSib->pvibParent = pvib;
pvib = pvib->pvibSib;
FTFreeVib ( pvib->pvibParent );
} else {
FTFreeVib( pvib ); // free the last vib and get out
break;
}
}
return;
} /* FTFreeAllSib() */
/*** FTFreeAllCif
* Purpose: To free all children blocks and the Child InFo.
* Input:
* pcif A pointer to the Child InFo.
* Output:
* Returns .....
* Exceptions:
* Notes:
*/
VOID
FTFreeAllCif(
PTRCIF pcif
)
{
if( pcif ) {
FTFreeAllSib ( pcif->pvibChild );
pcif->pvibChild = (PTRVIB) NULL;
if ( pcif->hTMBd ) {
EEFreeTM ( &pcif->hTMBd );
}
free ( pcif );
}
return;
} /* FTFreeAllCif() */
/*** FTExpandOne(PTRVIB pvib)
* Purpose:
* Expand all vibs at this level in the tree (All siblings)
* Input:
* pVib - Pointer to a VIB
* Output:
* None
* Exceptions:
* Notes:
*/
VOID
FTExpandOne(
PTRVIB pvib
)
{
while ( pvib) {
// Don't Collapse if it's already open!
if ( !pvib->pcif && pvib->flags.ExpandMe ) {
FTExpandVib(pvib);
}
// Now take care of the siblings
pvib = pvib->pvibSib;
}
}
/*** FTExpand
* Purpose: To expand the structure at the line pointed to by oln. oln is
* the offset from the start of the locals, not the start of the
* window.
* Input:
* pvit - A Pointer to the Variable Information Top
* oln - The offset from the first local
* Output:
* Returns a LTS
* Exceptions:
*/
LTS
FTExpand (
PTRVIT pvit,
ULONG oln
)
{
PTRVIB pvib;
if ( pvit && (pvib = FTvibGetAtLine( pvit, oln)) ) {
return( FTExpandVib(pvib) );
}
return(UNABLETOEXPAND);
}
/*** FTExpand
* Purpose: To expand the structure at a particular vib.
* Input:
* PTR pvib - Pointer to a VIB
* Output:
* Returns a LTS
* Exceptions:
*/
LTS
FTExpandVib(
PTRVIB pvib
)
{
EESTATUS Err;
HTM hTM;
long cChild;
EEPDTYP ExpTyp;
SHFLAG shflag;
ULONG strIndex;
HTI hti;
RTMI rti = {0};
HTM hTMParent;
// If its already expand, collasse it
if ( pvib->pcif ) {
FTclnUpdateParent ( pvib, (1-pvib->cln) );
FTFreeVibChildren ( pvib );
return OK;
}
// Can we Expand?
if ( pvib->flags.NoData || pvib->flags.NoBind ) {
return(UNABLETOEXPAND);
}
if (pvib->vibPtr == vibGeneric) {
hTMParent = pvib->pvtext[pvib->vibIndex].htm;
} else {
hTMParent = pvib->hTMBd;
}
if ( EEInfoFromTM ( &hTMParent, &rti, &hti ) != EENOERROR) {
return(UNABLETOEXPAND);
}
if (hti != (HTI) 0) {
EEFreeTI(&hti);
}
ExpTyp = EEIsExpandable ( &hTMParent );
if ( ExpTyp == EENOTEXP || ExpTyp == EETYPENOTEXP ) {
return ( UNABLETOEXPAND );
}
// here is the nasty, if we are currently an expandable, we don't
// want to update the generic vib, but rather make a new one
if( pvib->vibPtr == vibGeneric ) {
PTRVIB *ppvib;
PTRVIB pvibNew;
// get a new vib
if ( !(pvibNew = PvibAlloc ( NULL, pvib->pvibParent )) ) return ( OUTOFMEMORY );
// copy the generic vib
*pvibNew = *pvib;
pvibNew->cln = 1; // put in the count
// Copy over the correct hTM
pvibNew->hTMBd = pvib->pvtext[pvib->vibIndex].htm;
// put this vib in the list, this should alway be at least two down
// from the root vit. A sym must be in between
ppvib = &pvib->pvibParent->pcif->pvibChild;
pvib = *ppvib;
while ( pvib->pvibSib && pvib->vibIndex < pvibNew->vibIndex ) {
ppvib = &pvib->pvibSib;
pvib = pvib->pvibSib;
}
// fixup the link list
*ppvib = pvibNew;
pvibNew->pvibSib = pvib;
// now select this vib
pvib = pvibNew;
pvib->vibPtr = vibChild;
pvib->pvtext = NULL; // Make sure that Text Info isn't dup'd
pvib->cText = 0; // because of the copy above.
}
// now expand it
if( !(pvib->pcif = FTGetCif()) || !(pvib->pcif->pvibChild = PvibAlloc ( NULL, pvib )) ) {
FTFreeVibChildren( pvib );
return ( UNABLETOEXPAND );
}
// if it is a pointer and I can't dereference, get out
hTM = hTMParent;
if( ExpTyp == EEPOINTER &&
EEDereferenceTM ( &hTMParent, &hTM, &strIndex, fCaseSensitive ) != EENOERROR ) {
FTFreeVibChildren( pvib );
return ( UNABLETOEXPAND );
}
// get the count
Err = EEcChildrenTM ( &hTM, &cChild, &shflag );
// set up the new Variable Info Block after expansion
switch(ExpTyp) {
case EEAGGREGATE:
if ( !cChild ) {
pvib->pcif->pvibChild->flags.NoData;
cChild = 1;
}
// FALL THROUGH
case EETYPE:
pvib->pcif->pvibChild->vibPtr = vibGeneric;
break;
case EEPOINTER:
if( cChild ) {
pvib->pcif->pvibChild->vibPtr = vibGeneric;
pvib->pcif->hTMBd = hTM;
} else {
pvib->pcif->pvibChild->vibPtr = vibPointer;
pvib->pcif->pvibChild->hTMBd = hTM;
cChild = 1;
}
break;
}
// say we are expanded, and put the expand count in the tree.
FTclnUpdateParent( pvib, (short) cChild );
pvib->flags.ExpandMe = FALSE;
return(OK);
} /* FTExpand() */
/*** FTclnUpdateParent
* Purpose: To Go up the tree and update all of the parent's cln fields
* Input:
* pvibParent - The first parent to update
* dcln - The difference to update them by
* Output:
* Exceptions:
* Notes:
*/
void
FTclnUpdateParent(
PTRVIB pvibParent,
int dcln
)
{
while ( pvibParent ) { // Walk up the tree
pvibParent->cln += (short) dcln;
pvibParent = pvibParent->pvibParent;
}
} /* FTclnUpdateParent() */
/*** FTGetVibTypeString
* Purpose:
* Get a pointer to a vib return a string that contains the
* text for its expansion button.
* Input:
* pVib - Pointer to the Vib
* Output:
* Returns a pointer to the String o rNULL
* Exceptions:
*/
PSTR
FTGetVibTypeString(
PTRVIB pVib
)
{
EEPDTYP ExpTyp;
// If we don't have any data, return a space
if ( pVib->flags.NoData || pVib->flags.NoBind ) {
return( " " );
}
/*
* If EE says we can't expand, return a space
*/
if (pVib->vibPtr == vibGeneric) {
ExpTyp = EEIsExpandable( &pVib->pvtext[pVib->vibIndex].htm );
} else {
ExpTyp = EEIsExpandable ( &pVib->hTMBd );
}
if ( (ExpTyp == EENOTEXP) || (ExpTyp == EETYPENOTEXP)) {
return( " " );
// If we have a child info block, we're already expanded
} else if ( pVib->pcif ) {
return( "-" );
}
// Else we are expandable
return( "+" );
} /* FTGetVibTypeString() */
/*** FTGetVibResultString
* Purpose:
* Get a pointer to a vib return a string that contains the
* text for the evaluated result.
* Input:
* pVit - Pointer to the VIT (Variable Information Top)
* pVib - Pointer to the VIB (Variable Information Block)
* Output:
* Returns a pointer to the String o rNULL
* Exceptions:
*/
PSTR
FTGetVibResultString(
PTRVIT pVit,
PTRVIB pVib
)
{
EEHSTR hValue = 0;
PCXF pCxf;
PSTR szValue;
EESTATUS Err;
PSTR pszFormat = NULL;
PVTEXT pvtext;
HTM hTM;
pCxf = (pVib->vibPtr == vibWatch) ? &CxfIp : &pVit->cxf;
if ( pVib->flags.NoBind) {
szBuffer[0] = 0;
return(szBuffer);
}
if (pVib->vibPtr == vibGeneric) {
hTM = pVib->pvtext[pVib->vibIndex].htm;
} else {
hTM = pVib->hTMBd;
}
if ( pVib->flags.NoData ) {
LoadString(g_hInst, ERR_Expclass_No_Members, szBuffer, BUFFERMAX);
return(szBuffer);
}
if ( pVib->flags.FuncEval) {
LoadString(g_hInst, ERR_No_Funcs_In_Watch, szBuffer, BUFFERMAX);
return(szBuffer);
}
// If we have a format override, make sure it passed
if ( pVib->pvtext) {
pvtext = &pVib->pvtext[pVib->vibIndex];
if ( pvtext->pszFormat ) {
pszFormat = pvtext->pszFormat;
}
}
if (pszFormat && *pszFormat == ',') {
pszFormat++;
}
if ( (Err = EEvaluateTM ( &hTM, SHhFrameFrompCXF(pCxf),EEVERTICAL )) ||
(Err = EEGetValueFromTM ( &hTM, radix, (PUCHAR) pszFormat, &hValue)) ) {
CVExprErr ( Err, MSGSTRING, &hTM, szBuffer );
return(szBuffer);
}
szValue = (PSTR) MMLpvLockMb( (HDEP)hValue );
strncpy(szBuffer,szValue,BUFFERMAX);
MMbUnlockMb ( (HDEP)hValue );
EEFreeStr(hValue);
// If we have a new line in the string then terminate there
//pszBuffer = strchr(szBuffer,'\n');
//if (pszBuffer) *pszBuffer = 0;
return(szBuffer);
}
/*** FTGetVibNameString
* Purpose:
* Get a pointer to a vib return a string that contains the
* text for the name portion.
* Input:
* pVib - Pointer to the VIB (Variable Information Block)
* Output:
* Returns a pointer to the String o rNULL
* Exceptions:
*/
PSTR
FTGetVibNameString(
PTRVIB pVib
)
{
PSTR pszBuffer = szBuffer;
PSTR szValue;
HDEP hType = 0;
EEHSTR hName = 0;
int i;
int len = 0;
EESTATUS Err;
/*
* put in indent
*/
if ((int)pVib->level < 128) {
for(i=0; i<(int)pVib->level; i++) {
*pszBuffer++ = '|';
*pszBuffer++ = ' ';
len += 2;
}
}
/*
* Get the Name
*/
switch(pVib->vibPtr) {
/*
* Case 1:
* This implies that the item is a real variable and we can
* know its name from what was typed in to the system. So
* get it from the typed in expression.
*/
case vibWatch:
strncpy(pszBuffer,pVib->pwoj->szExpStr,BUFFERMAX-len);
break;
/*
* Get the Name from the Type info
*/
case vibType:
if ((pVib->pwoj != NULL) && (pVib->pwoj->szExpStr != NULL)) {
strncpy(pszBuffer, pVib->pwoj->szExpStr, BUFFERMAX-len);
} else if ( pVib->flags.NoBind ) {
/*
* Out of Context, no info
*/
*pszBuffer = 0;
} else {
/*
* Get the Type String
*/
if (((Err = EEGetNameFromTM(&pVib->hTMBd, &hName)) != EENOERROR) ||
((Err = EEGetTypeFromTM(&pVib->hTMBd, hName,
(PEEHSTR)&hType, TRUE) != EENOERROR))) {
CVExprErr ( Err, MSGSTRING, &pVib->hTMBd, szBuffer );
if (hName) {
EEFreeStr(hName);
}
if (hType) {
EEFreeStr(hType);
}
return(szBuffer);
}
/*
* Lock it down and copy to the woj
*/
szValue = (PSTR) MMLpvLockMb ( hType );
strncpy(pszBuffer,szValue + sizeof(HDR_TYPE),BUFFERMAX-len);
MMbUnlockMb ( hType );
EEFreeStr ( (EEHSTR)hType );
}
break;
/*
* Case 3:
* We are doing deverivations from a base item. In this
* case we are hopless about getting the string correct
* on our own so let the EE get the string for use. It
* will still be wrong sometimes but mostly correct.
*/
case vibGeneric:
if (pVib->flags.NoBind) {
/*
* Expression is out of context so return NULL string
*/
*pszBuffer = 0;
} else {
/*
* Get the name from the TM
*/
Err = EEGetNameFromTM( &pVib->pvtext[pVib->vibIndex].htm,
&hName );
if ( Err != EENOERROR ) {
CVExprErr( Err, MSGSTRING,
&pVib->pvtext[pVib->vibIndex].htm, szBuffer);
if (hName) {
EEFreeStr( hName );
}
return szBuffer;
}
szValue = (PSTR) MMLpvLockMb( (HDEP) hName );
strncpy( pszBuffer, szValue, BUFFERMAX-len );
pszBuffer[BUFFERMAX-len] = 0;
MMbUnlockMb( (HDEP) hName );
EEFreeStr( hName );
}
break;
/*
* Case 4:
* Get the Name from the Evaluation tree
*/
default:
if ( pVib->flags.NoBind ) {
/*
* Out of Context, no info
*/
*pszBuffer = 0;
} else {
/*
* Get the Name from the tm
*/
if ( Err = EEGetNameFromTM ( &pVib->hTMBd, &hName) ) {
CVExprErr ( Err, MSGSTRING, &pVib->hTMBd, szBuffer );
if ( hName ) {
EEFreeStr(hName);
}
return(szBuffer);
}
szValue = (PSTR) MMLpvLockMb( (HDEP)hName );
strncpy(pszBuffer,szValue,BUFFERMAX-len);
pszBuffer[BUFFERMAX-len] = 0;
MMbUnlockMb ( (HDEP)hName );
EEFreeStr(hName);
}
break;
}
return(szBuffer);
}
/*** FTGetWatchList
* Purpose:
* Return a buffer that has a list of all the Toplevel watchs
* for the given vit.
* Input:
* pVit - Pointer to the Variable Information Top
* Output:
* Returns a pointer to the formatted buffer or NULL if there
* was an error.
* Exceptions:
* Notes:
* The Buffer was malloced and needs to be free'd by the caller.
* The first character of each line is the expansion type.
*/
PSTR
FTGetWatchList(
PTRVIT pVit
)
{
PTRVIB pVib;
PSTR pBuffer; // Pointer to start of buffer
PSTR pCh; // Pointer to End of buffer
PSTR pName; // Pointer to next string
PSTR pType; // Pointer to the expansion string
ULONG Size = NAMES_BUFFER; // Size of Buffer
ULONG Cnt = 0; // Count of Lines
ULONG Len = 1; // Lenth of filled buffer
// If we can't get a buffer, give up
if ( !pVit || (pBuffer = (PSTR) malloc(NAMES_BUFFER)) == NULL) {
return(NULL);
}
pCh = pBuffer;
*pCh = 0;
// Loop through the VIT
pVib = pVit->pvibChild;
while ( pVib ) {
// Get the values
pName = FTGetVibNameString(pVib);
pType = FTGetVibTypeString(pVib);
// Make sure we fit in the buffer
if ( Len + strlen(pName) + 3 > Size ) {
Size += NAMES_BUFFER;
pBuffer = (PSTR) realloc(pBuffer, Size);
pCh = pBuffer + Len - 1 ; // Reposition to the same offset
}
// Copy the string and point to the end
*pCh++ = *pType;
strcpy(pCh, pName);
pCh += strlen(pName);
// Copy in the carriage return/linefeed
*pCh++ = '\r';
*pCh++ = '\n';
// Increment the length and get next vib
Len += strlen(pName) + 3;
pVib = pVib->pvibSib;
}
*pCh = 0;
return(pBuffer);
}
/*** FTSetWatchList
* Purpose:
* Restore a watch list that was generated by FTGetWatchList()
* for a given vit.
* Input:
* pVit - Pointer to the Variable Information Top
* List - Save area generated by FTGetWatchList()
* Output:
* None
* Exceptions:
* Notes:
*/
VOID
FTSetWatchList(
PTRVIT pVit,
PSTR list
)
{
PSTR pWatch;
PTRVIB pVib;
char cType;
// While we have line with \r\n
pWatch = strtok(list, "\r\n");
while ( pWatch ) {
if (IsDBCSLeadByte(*pWatch)) {
pWatch = strtok( NULL, "\r\n"); // Get the Next Watch
continue;
}
cType = *pWatch++; // Get the Expansion Type
pVib = AddCVWatch(pVit, pWatch); // Add the Watch
#if V-WILLHE
// NOTENOTE - V-Willhe If we do this we get free() areas. The
// vib is ok....check for corruption in
// FTExpandVib.
if ( pVib && cType == '-') { // If it was expanded,
FTExpandVib( pVib); // Make it so...
}
#endif
pWatch = strtok( NULL, "\r\n"); // Get the Next Watch
}
return;
}
/*** FTInvalidateVib
* Purpose:
* To invalidate the entire tree starting at a given node.
* Input:
* pVib - Pointer to a VIB
* Output:
* None
* Exceptions:
* Notes:
*/
VOID
FTInvalidateVib(
PTRVIB pvib
)
{
while ( pvib) {
// Make sure this one is invalidated
pvib->flags.NoBind = TRUE;
// If we have any children, invalidate them
if ( pvib->pcif ) {
FTInvalidateVib( pvib->pcif->pvibChild);
}
// Now take care of the siblings
pvib = pvib->pvibSib;
}
}
/*** FTResetVib
* Purpose:
* Reset any NoBind flags from this vib down
* Input:
* pVib - Pointer to a VIB
* Output:
* None
* Exceptions:
* Notes:
*/
VOID
FTResetVib(
PTRVIB pvib
)
{
while ( pvib) {
// Make sure this one is turned off
pvib->flags.NoBind = FALSE;
// If we have any children, reset them
if ( pvib->pcif ) {
FTResetVib( pvib->pcif->pvibChild);
}
// Now take care of the siblings
pvib = pvib->pvibSib;
}
}
/*** FTAgeVibValues
* Purpose:
* Age the Vib's value strings by moving it to the previous value.
* If we have a previous value free it. Null the current value.
* Input:
* pVib - Pointer to a VIB
* Output:
* None
* Exceptions:
* Notes:
*/
VOID
FTAgeVibValues(
PTRVIB pvib
)
{
ULONG i;
while ( pvib) {
FTEnsureTextExists( pvib );
if ( pvib->cText ) {
// For each text segment
for ( i=0; i < pvib->cText ; i++) {
// Free the Prev. If it exists
if ( pvib->pvtext[i].pszValueP ) {
free(pvib->pvtext[i].pszValueP);
}
// Move Current to Prev. and Null current
pvib->pvtext[i].pszValueP = pvib->pvtext[i].pszValueC;
pvib->pvtext[i].pszValueC = NULL;
}
}
// If we have any children, Age them
if ( pvib->pcif ) {
FTAgeVibValues( pvib->pcif->pvibChild);
}
// Now take care of the siblings
pvib = pvib->pvibSib;
}
}
/*** FTGetPanelString
* Purpose:
* Get the String associated with a vib index.
* Input:
* UINT PanelNumber - Panel whos string we need (BUTTON, LEFT, RIGHT)
* UINT VibINdex - Index of the Vib we need
* Output:
* PSTR Pointer to the buffer containing the string.
* Exceptions:
* Notes:
*/
PSTR
FTGetPanelString(
PTRVIT pVit,
PTRVIB pVib,
UINT PanelNumber
)
{
PVTEXT pvtext;
FTEnsureTextExists( pVib );
// Focus in on the one we want
switch (PanelNumber) {
case ID_PANE_BUTTON:
return(FTGetVibTypeString(pVib));
case ID_PANE_LEFT:
return(FTGetVibNameString(pVib));
case ID_PANE_RIGHT:
pvtext = &pVib->pvtext[pVib->vibIndex];
if ( pvtext->pszValueC == NULL) {
pvtext->pszValueC = _strdup(FTGetVibResultString(pVit,pVib));
}
return(pvtext->pszValueC);
default:
return(NULL);
}
}
/*** FTGetPanelStatus
* Purpose:
* Has the text for a panel id changed?
* Input:
* UINT PanelNumber - Panel whos string we need (BUTTON, LEFT, RIGHT)
* UINT VibINdex - Index of the Vib we need
* Output:
* TRUE/FALSE
* Exceptions:
* Notes:
*/
BOOL
FTGetPanelStatus(
PTRVIB pVib,
UINT PanelNumber
)
{
PVTEXT pvtext;
if ( PanelNumber == ID_PANE_RIGHT) {
FTEnsureTextExists( pVib );
pvtext = &pVib->pvtext[pVib->vibIndex];
if ( pvtext->pszValueC && pvtext->pszValueP) {
return ( strcmp( pvtext->pszValueC, pvtext->pszValueP) );
} else {
return(FALSE);
}
}
else {
return(FALSE);
}
}
/*** FTEnsureTextExists
* Purpose:
* Ensure that the Text segment for a vib exists
* Input:
* PRTVIB pVib - Pointer to the vib to check
* Output:
* Exceptions:
* Notes:
*/
VOID
FTEnsureTextExists(
PTRVIB pVib
)
{
int count;
int slack;
// Make sure we have a text segment
if ( pVib->pvtext == NULL) {
pVib->pvtext = (PVTEXT) malloc( sizeof(VTEXT) );
RAssert(pVib->pvtext);
memset(pVib->pvtext,0, sizeof(VTEXT));
pVib->cText = 1;
}
// Make sure the Indicated index has text associated
// with it, if not expand in 10 entry increments
if ( pVib->vibIndex + 1 > pVib->cText) {
count = pVib->vibIndex + 11;
slack = count - pVib->cText;
pVib->pvtext = (PVTEXT) realloc(pVib->pvtext, count * sizeof(VTEXT) );
RAssert(pVib->pvtext);
memset(&pVib->pvtext[pVib->cText], 0, slack * sizeof(VTEXT) );
pVib->cText = count;
}
}
BOOL
FTAddWatchVariable(
PTRVIT * ppVit,
PTRVIB * ppVib,
LPSTR lpszWatchVar
)
/*++
Routine Desciption:
Adds an expression to the pvitWatch tree
Arguments:
ppVit - * If NULL, then this argument is ignored.
* If not NULL, then the current VIT will be returned.
ppVib - * If NULL, then this argument is ignored.
* If not NULL, then the new VIB will be returned.
lpszWatchVar - Can be NULL, or point to a zero length string, However
nothing will be added.
Return Value:
FALSE - Failure. If the expression could not be added.
TRUE - Success. The expression was added.
--*/
{
PTRVIT pVit = NULL;
PTRVIB pVib = NULL;
if (!lpszWatchVar) {
return FALSE;
}
while (whitespace(*lpszWatchVar)) {
lpszWatchVar++;
}
if (strlen(lpszWatchVar) == 0) {
return FALSE;
}
pVit = InitWatchVit();
pVib = AddCVWatch( pVit, lpszWatchVar);
if (ppVit) {
*ppVit = pVit;
}
if (ppVib) {
*ppVib = pVib;
}
return TRUE;
}