3525 lines
101 KiB
C
3525 lines
101 KiB
C
|
/*** debfmt.c - expression evaluator formatting routines
|
||
|
|
||
|
* GLOBAL
|
||
|
|
||
|
|
||
|
* LOCAL
|
||
|
|
||
|
|
||
|
|
||
|
* DESCRIPTION
|
||
|
* Expression evaluator formatting routines
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "debexpr.h"
|
||
|
#include "ldouble.h"
|
||
|
#ifndef _SBCS
|
||
|
#include <mbctype.h>
|
||
|
#endif
|
||
|
|
||
|
#include "locale.h"
|
||
|
|
||
|
#define _CRTBLD // work around bug in headers
|
||
|
#include "undname.h"
|
||
|
#undef _CRTBLD
|
||
|
|
||
|
#ifdef USE_CUSTVIEW
|
||
|
|
||
|
#include "custview.h"
|
||
|
|
||
|
HRESULT WINAPI ExportViewHwnd( DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved );
|
||
|
HRESULT WINAPI ExportViewGuid( DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved );
|
||
|
HRESULT WINAPI ExportViewVariant( DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved );
|
||
|
HRESULT WINAPI ExportViewHresult( DWORD dwAddress, DEBUGHELPER *pHelper, int nBase, BOOL bUniStrings, char *pResult, size_t max, DWORD reserved );
|
||
|
extern DEBUGHELPER StaticHelper;
|
||
|
|
||
|
#endif // USE_CUSTVIEW
|
||
|
|
||
|
void InsertCache (CV_typ_t, HEXE);
|
||
|
|
||
|
typedef enum FMT_ret {
|
||
|
FMT_error,
|
||
|
FMT_none,
|
||
|
FMT_ok
|
||
|
} FMT_ret;
|
||
|
|
||
|
typedef struct FMT_state {
|
||
|
pexstate_t pExState;
|
||
|
char *pExStr;
|
||
|
PCXT pCxt;
|
||
|
} FMT_state;
|
||
|
|
||
|
// definitions used for caching auto-expansion rules
|
||
|
// The cache is implemented as a table. Each entry maps a pair
|
||
|
// (type, hExe) to the corresponding auto expansion rule string
|
||
|
// (that string may be NULL if no rule exists for the particular type)
|
||
|
|
||
|
typedef struct aecache_t {
|
||
|
CV_typ_t typ;
|
||
|
HEXE hExe;
|
||
|
EEHSTR hStr;
|
||
|
} aecache_t;
|
||
|
|
||
|
#define AECACHE_MAX 64 // max number of entries in the cache
|
||
|
static aecache_t AECache [AECACHE_MAX] = {0}; // cache for auto-exp. rules
|
||
|
static int cAECache = 0; // current number of entries
|
||
|
|
||
|
void AppendCVQualifier (peval_t, char * *, uint *);
|
||
|
int ConvertWCToMB (char *, wchar_t);
|
||
|
EESTATUS Format (peval_t, uint, char * *, int *, bool_t);
|
||
|
void EvalString (peval_t, char * *, int *, bool_t);
|
||
|
void EvalMem (peval_t, char *FAR *, int *, char);
|
||
|
void FormatAutoExpand (peval_t, uint, char * *, int *);
|
||
|
void FormatAEChildTM (uint, peval_t, uint, char * *, int *);
|
||
|
void FormatAEDownCastType (peval_t, uint, char * *, int *);
|
||
|
void FormatAEError (peval_t, uint, char * * , int *);
|
||
|
BOOL GetRawAddr( peval_t pv, ADDR *paddr );
|
||
|
void FormatExpand (peval_t, char * *, uint *, char * *, ulong, PHDR_TYPE);
|
||
|
void FormatClass (peval_t, uint, char * * , int *);
|
||
|
EESTATUS FormatEnum (peval_t, char * , int );
|
||
|
void FormatProc (peval_t, char * *, uint *, char * *, CV_typ_t, CV_typ_t, CV_call_e, ulong , CV_typ_t, ulong, PHDR_TYPE);
|
||
|
char * FormatUndecorate( char*, char*);
|
||
|
char * FormatVirtual (char *, peval_t, PEEHSTR);
|
||
|
FMT_ret VerifyFormat (peval_t, PEEFORMAT, char * *, int *, bool_t *);
|
||
|
INLINE bool_t IsPrint (int ch);
|
||
|
|
||
|
void FASTCALL DoAutoExpand (PHTM);
|
||
|
void FASTCALL DoBindAutoExpand (PHTM);
|
||
|
void FASTCALL DoEvalAutoExpand (PHTM);
|
||
|
bool_t FASTCALL FindAERule (peval_t, LSZ, uint);
|
||
|
bool_t FASTCALL UpdateEEHSTR(EEHSTR *, LSZ);
|
||
|
void FASTCALL SaveFmtState (FMT_state *);
|
||
|
void FASTCALL RestoreFmtState (FMT_state *);
|
||
|
bool_t FASTCALL LookupAECache (CV_typ_t, HEXE, char *);
|
||
|
void FASTCALL ReorderAECache (int);
|
||
|
void FASTCALL InsertAECache (CV_typ_t, HEXE, char far *);
|
||
|
|
||
|
static char accessstr[4][4] = {" ", "PV ", "PR ", "PB "};
|
||
|
|
||
|
struct typestr {
|
||
|
uchar type; // type and subtype
|
||
|
uchar len;
|
||
|
char SEGBASED (_segname("_CODE")) * name;
|
||
|
};
|
||
|
|
||
|
struct modestr {
|
||
|
uchar mode;
|
||
|
uchar len;
|
||
|
char SEGBASED (_segname("_CODE")) * name;
|
||
|
};
|
||
|
|
||
|
#pragma warning ( disable:4120 ) // "based/unbased mismatch"
|
||
|
|
||
|
// define all the strings in the code segment
|
||
|
#define TYPENAME(name, type, len, str) static char SEGBASED(_segname("_CODE")) S##name[] = str;
|
||
|
#define MODENAME(name, mode, len, str) static char SEGBASED(_segname("_CODE")) S##name[] = str;
|
||
|
#define PTRNAME(name, str) static char SEGBASED(_segname("_CODE")) S##name[] = str;
|
||
|
#include "fmtstr.h"
|
||
|
#undef TYPENAME
|
||
|
#undef MODENAME
|
||
|
#undef PTRNAME
|
||
|
|
||
|
// load all the type names into a table
|
||
|
static struct typestr SEGBASED(_segname("_CODE")) nametype[] = {
|
||
|
#define TYPENAME(name, type, len, str) {type, len, S##name},
|
||
|
#define MODENAME(name, mode, len, str)
|
||
|
#define PTRNAME(name, str)
|
||
|
#include "fmtstr.h"
|
||
|
#undef TYPENAME
|
||
|
#undef MODENAME
|
||
|
#undef PTRNAME
|
||
|
};
|
||
|
|
||
|
// load all the mode names into a table
|
||
|
static struct modestr SEGBASED(_segname("_CODE")) namemode[] = {
|
||
|
#define TYPENAME(name, type, len, str)
|
||
|
#define MODENAME(name, mode, len, str) {mode, len, S##name},
|
||
|
#define PTRNAME(name, str)
|
||
|
#include "fmtstr.h"
|
||
|
#undef TYPENAME
|
||
|
#undef MODENAME
|
||
|
#undef PTRNAME
|
||
|
};
|
||
|
|
||
|
// load all the pointer type names into an array
|
||
|
static char SEGBASED(_segname("_CODE")) *SEGBASED(_segname("_CODE")) ptrname[] = {
|
||
|
#define TYPENAME(name, type, len, str)
|
||
|
#define MODENAME(name, mode, len, str)
|
||
|
#define PTRNAME(name, str) S##name,
|
||
|
#include "fmtstr.h"
|
||
|
#undef TYPENAME
|
||
|
#undef MODENAME
|
||
|
#undef PTRNAME
|
||
|
};
|
||
|
|
||
|
#pragma warning ( default:4120 ) // "based/unbased mismatch"
|
||
|
|
||
|
|
||
|
#define typecount (sizeof (nametype) / sizeof (nametype[0]))
|
||
|
#define modecount (sizeof (namemode) / sizeof (namemode[0]))
|
||
|
|
||
|
char *fmt_char_nz[] = {
|
||
|
"0%03.03o '%c'",
|
||
|
"%d '%c'",
|
||
|
"0x%02.02x '%c'",
|
||
|
"0x%02.02X '%c'",
|
||
|
};
|
||
|
|
||
|
// The IDE wants to show a null character as '\x00', but CV wants to show
|
||
|
// it as ''
|
||
|
|
||
|
#ifdef WINQCXX
|
||
|
#define szNullChar "\\x00"
|
||
|
#else
|
||
|
#define szNullChar ""
|
||
|
#endif
|
||
|
|
||
|
char *fmt_char_zr[] = {
|
||
|
"0%03.03o '" szNullChar "'",
|
||
|
"%d '" szNullChar "'",
|
||
|
"0x%02.02x '" szNullChar "'",
|
||
|
"0x%02.02X '" szNullChar "'",
|
||
|
};
|
||
|
|
||
|
|
||
|
char *fmt_char[] = {
|
||
|
"0%03.03o",
|
||
|
"%d",
|
||
|
"0x%02.02x",
|
||
|
"0x%02.02X",
|
||
|
};
|
||
|
|
||
|
|
||
|
char *fmt_short[] = {
|
||
|
"0%06.06ho",
|
||
|
"%hd",
|
||
|
"0x%04.04hx",
|
||
|
"0x%04.04hX",
|
||
|
};
|
||
|
|
||
|
|
||
|
char *fmt_ushort[] = {
|
||
|
"0%06.06ho",
|
||
|
"%hu",
|
||
|
"0x%04.04hx",
|
||
|
"0x%04.04hX",
|
||
|
};
|
||
|
|
||
|
|
||
|
char *fmt_long[] = {
|
||
|
"0%011.011lo",
|
||
|
"%ld",
|
||
|
"0x%08.08lx",
|
||
|
"0x%08.08lX",
|
||
|
};
|
||
|
|
||
|
|
||
|
char *fmt_ulong[] = {
|
||
|
"0%011.011lo",
|
||
|
"%lu",
|
||
|
"0x%08.08lx",
|
||
|
"0x%08.08lX",
|
||
|
};
|
||
|
|
||
|
char *fmt_quad[] = {
|
||
|
"0%022.022I64o",
|
||
|
"%I64d",
|
||
|
"0x%016.016I64x",
|
||
|
"0x%016.016I64X",
|
||
|
};
|
||
|
|
||
|
char *fmt_uquad[] = {
|
||
|
"0%022.022I64o",
|
||
|
"%I64u",
|
||
|
"0x%016.016I64x",
|
||
|
"0x%016.016I64X",
|
||
|
};
|
||
|
|
||
|
char *fmt_ptr_16_16[] = {
|
||
|
"0x%04hx:0x%04hx",
|
||
|
"0x%04hX:0x%04hX",
|
||
|
};
|
||
|
|
||
|
|
||
|
char *fmt_ptr_16_32[] = {
|
||
|
"0x%04hx:0x%08lx",
|
||
|
"0x%04hX:0x%08lX",
|
||
|
};
|
||
|
|
||
|
|
||
|
char *fmt_ptr_0_16[] = {
|
||
|
"0x%04hx",
|
||
|
"0x%04hX",
|
||
|
};
|
||
|
|
||
|
|
||
|
char *fmt_ptr_0_32[] = {
|
||
|
"0x%08lx",
|
||
|
"0x%08lX",
|
||
|
};
|
||
|
|
||
|
char *fmt_ptr_64[] = {
|
||
|
"0x%016I64x",
|
||
|
"0x%016I64X",
|
||
|
};
|
||
|
|
||
|
char *bailout = "\x006""??? * ";
|
||
|
|
||
|
// on some locales (eg German) use commas instead of periods in floats.
|
||
|
// This confuses the EE greatly as it thinks the commas are part of the format specifier
|
||
|
|
||
|
int sprintf_english( char *buffer, const char *fmtStr, ... )
|
||
|
{
|
||
|
int cResult;
|
||
|
va_list marker;
|
||
|
va_start( marker, fmtStr );
|
||
|
|
||
|
setlocale( LC_NUMERIC, "C" );
|
||
|
|
||
|
cResult = vsprintf( buffer, fmtStr, marker );
|
||
|
|
||
|
setlocale( LC_NUMERIC, "" );
|
||
|
|
||
|
va_end( marker );
|
||
|
|
||
|
return cResult;
|
||
|
}
|
||
|
|
||
|
/** FormatCXT - format context packet
|
||
|
|
||
|
* status = FormatCXT (pCXT, phStr, dwFlags);
|
||
|
|
||
|
* Entry pCXT = pointer to context
|
||
|
* phStr = return location for string
|
||
|
* dwFlags = control flags for formatting
|
||
|
|
||
|
* Exit context formatted into buffer as a context operator
|
||
|
|
||
|
* Returns EENONE if no error
|
||
|
* EEGENERAL if error
|
||
|
*/
|
||
|
|
||
|
ulong FormatCXT (PCXT pCXT, PEEHSTR phStr, DWORD dwFlags)
|
||
|
{
|
||
|
HMOD hMod;
|
||
|
HPROC hProc;
|
||
|
HSF hsf;
|
||
|
HEXE hExe;
|
||
|
SYMPTR pProc;
|
||
|
char *pFile;
|
||
|
char *pExe;
|
||
|
char *pStr;
|
||
|
uint len = 6;
|
||
|
eval_t eval;
|
||
|
peval_t pv = &eval;
|
||
|
char buf[FCNSTRMAX + sizeof(HDR_TYPE)];
|
||
|
char *pName = buf;
|
||
|
char procName[NAMESTRMAX];
|
||
|
char *pFName;
|
||
|
char *pc = 0;
|
||
|
uint lenP;
|
||
|
CV_typ_t typ;
|
||
|
PHDR_TYPE pHdr;
|
||
|
|
||
|
hMod = SHHMODFrompCXT (pCXT);
|
||
|
hProc = SHHPROCFrompCXT (pCXT);
|
||
|
if ((hMod == 0) && (hProc == 0)) {
|
||
|
if ((*phStr = MemAllocate (10)) != 0) {
|
||
|
pStr = (char *) MemLock (*phStr);
|
||
|
*pStr = 0;
|
||
|
MemUnLock (*phStr);
|
||
|
return (EENOERROR);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
hsf = SLHsfFromPcxt (pCXT);
|
||
|
hExe = SHHexeFromHmod (hMod);
|
||
|
|
||
|
if (dwFlags & HCXTFMT_Short) {
|
||
|
pExe = SHGetModNameFromHexe( hExe );
|
||
|
}
|
||
|
else {
|
||
|
pExe = SHGetExeName( hExe );
|
||
|
}
|
||
|
|
||
|
if ( pExe == NULL) {
|
||
|
|
||
|
// we can't generate a CXT if we can't get the exe name
|
||
|
return (EECATASTROPHIC);
|
||
|
}
|
||
|
|
||
|
pFile = SLNameFromHsf (hsf) ;
|
||
|
// it is possible to get the exe name, but not source
|
||
|
// file/line information (ex. a public) In this case we will use
|
||
|
// pExe instead of pFile (ie. {,,foob.exe} )
|
||
|
|
||
|
if (hProc != 0) {
|
||
|
switch ((pProc = (SYMPTR)MHOmfLock ((HSYM)hProc))->rectyp) {
|
||
|
case S_LPROC16:
|
||
|
case S_GPROC16:
|
||
|
lenP = ((PROCPTR16)pProc)->name[0];
|
||
|
pFName = (char *) &((PROCPTR16)pProc)->name[1];
|
||
|
typ = ((PROCPTR16)pProc)->typind;
|
||
|
break;
|
||
|
|
||
|
case S_LPROC32:
|
||
|
case S_GPROC32:
|
||
|
lenP = ((PROCPTR32)pProc)->name[0];
|
||
|
pFName = (char *) &((PROCPTR32)pProc)->name[1];
|
||
|
typ = ((PROCPTR32)pProc)->typind;
|
||
|
break;
|
||
|
|
||
|
case S_LPROCMIPS:
|
||
|
case S_GPROCMIPS:
|
||
|
lenP = ((PROCPTRMIPS)pProc)->name[0];
|
||
|
pFName = (char *) &((PROCPTRMIPS)pProc)->name[1];
|
||
|
typ = ((PROCPTRMIPS)pProc)->typind;
|
||
|
break;
|
||
|
|
||
|
case S_LPROCIA64:
|
||
|
case S_GPROCIA64:
|
||
|
lenP = ((PROCPTRIA64)pProc)->name[0];
|
||
|
pFName = (char *) &((PROCPTRIA64)pProc)->name[1];
|
||
|
typ = ((PROCPTRIA64)pProc)->typind;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DASSERT (FALSE);
|
||
|
|
||
|
|
||
|
// Perhaps this should be handled differently. The situation is that
|
||
|
// a thunk has MOD and PROC context, but no typind.
|
||
|
|
||
|
case S_THUNK32:
|
||
|
MHOmfUnLock (hProc);
|
||
|
return (EECATASTROPHIC);
|
||
|
}
|
||
|
|
||
|
_tcsncpy(procName, pFName, lenP);
|
||
|
procName[lenP] = '\0';
|
||
|
EVAL_MOD(pv) = hMod;
|
||
|
pv->CXTT = *pCXT;
|
||
|
SetNodeType(pv, typ);
|
||
|
|
||
|
pHdr = (PHDR_TYPE)pName;
|
||
|
memset (pName, 0, FCNSTRMAX + sizeof (HDR_TYPE));
|
||
|
pName = pName + sizeof (HDR_TYPE);
|
||
|
pc = pName;
|
||
|
lenP = FCNSTRMAX - 1;
|
||
|
pFName = procName;
|
||
|
// set selection mask in order to supress formatting
|
||
|
// of the proc return type
|
||
|
FormatType (pv, &pName, &lenP, &pFName, 0x1L, pHdr);
|
||
|
lenP = FCNSTRMAX - lenP;
|
||
|
|
||
|
// ignore buffer header from FormatType
|
||
|
|
||
|
memmove ((char *)pHdr, pc, lenP);
|
||
|
pc = (char *)pHdr;
|
||
|
len += lenP;
|
||
|
}
|
||
|
|
||
|
if ( pFile ) {
|
||
|
len += (UINT)(BYTE)*pFile + (int)_tcslen (pExe) ;
|
||
|
}
|
||
|
else {
|
||
|
len += (int)_tcslen (pExe) ;
|
||
|
}
|
||
|
|
||
|
if ((*phStr = MemAllocate (len)) != 0) {
|
||
|
pStr = (char *) MemLock (*phStr);
|
||
|
if (dwFlags & HCXTFMT_Short) {
|
||
|
_tcscpy(pStr, pExe);
|
||
|
_tcsupr(pStr);
|
||
|
_tcscat(pStr, "!");
|
||
|
}
|
||
|
else {
|
||
|
_tcscpy (pStr, "{");
|
||
|
if (hProc != 0 && !(dwFlags & HCXTFMT_No_Procedure)) {
|
||
|
_tcscat (pStr, pc);
|
||
|
}
|
||
|
_tcscat (pStr, ",");
|
||
|
|
||
|
if ( pFile ) {
|
||
|
_tcsncat (pStr, pFile + 1, (UINT)(BYTE)*pFile);
|
||
|
}
|
||
|
|
||
|
_tcscat (pStr, ",");
|
||
|
_tcscat (pStr, pExe);
|
||
|
_tcscat (pStr, "}");
|
||
|
}
|
||
|
MemUnLock (*phStr);
|
||
|
}
|
||
|
else {
|
||
|
MHOmfUnLock (hProc);
|
||
|
return (EECATASTROPHIC);
|
||
|
}
|
||
|
MHOmfUnLock (hProc);
|
||
|
return (EENOERROR);
|
||
|
}
|
||
|
|
||
|
|
||
|
/** AppendCVQualifier - append "const"/"volatile" qualifier
|
||
|
|
||
|
* AppendCVQualifier (pv, buf, buflen);
|
||
|
|
||
|
* Entry pv = pointer to value node
|
||
|
* buf = pointer pointer to buffer
|
||
|
* buflen = pointer to buffer length
|
||
|
|
||
|
* Exit type qualifier (const / volatile) appended to buffer
|
||
|
* *buflen = space remaining in buffer
|
||
|
|
||
|
* Returns none
|
||
|
*/
|
||
|
|
||
|
void AppendCVQualifier (peval_t pv, char * *buf, uint *buflen)
|
||
|
{
|
||
|
uint len;
|
||
|
|
||
|
if (EVAL_IS_CONST (pv)) {
|
||
|
len = min (*buflen, 6);
|
||
|
_tcsncpy (*buf, "const ", len);
|
||
|
*buf += len;
|
||
|
*buflen -= len;
|
||
|
}
|
||
|
else if (EVAL_IS_VOLATILE (pv)) {
|
||
|
len = min (*buflen, 9);
|
||
|
_tcsncpy (*buf, "volatile ", len);
|
||
|
*buf += len;
|
||
|
*buflen -= len;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/** FormatType - format type string
|
||
|
|
||
|
* FormatType (pv, ppbuf, pcount, ppName, select, pHdr);
|
||
|
|
||
|
* Entry pv = pointer to value node
|
||
|
* ppbuf = pointer pointer to buffer
|
||
|
* pcount = pointer to buffer length
|
||
|
* ppName = pointer to name if not null
|
||
|
* select = selection mask
|
||
|
* pHdr = pointer to structure describing formatting
|
||
|
|
||
|
* Exit type formatted into buffer
|
||
|
* *pcount = space remaining in buffer
|
||
|
* *pHdr updated
|
||
|
|
||
|
* Returns none
|
||
|
*/
|
||
|
|
||
|
void FormatType (peval_t pv, char * *buf, uint *buflen,
|
||
|
char * *ppName, ulong select, PHDR_TYPE pHdr)
|
||
|
{
|
||
|
eval_t evalT;
|
||
|
peval_t pvT = &evalT;
|
||
|
uint skip = 1;
|
||
|
uint len;
|
||
|
int itype, imode;
|
||
|
char *tname;
|
||
|
CV_typ_t type;
|
||
|
|
||
|
#if defined (NEVR)
|
||
|
if (EVAL_ACCESS (pv) != 0) {
|
||
|
len = min (*buflen, 3);
|
||
|
_tcsncpy (*buf, accessstr[EVAL_ACCESS (pv)], len);
|
||
|
*buf += len;
|
||
|
*buflen -= len;
|
||
|
}
|
||
|
#endif
|
||
|
if (!EVAL_IS_PTR (pv)) {
|
||
|
AppendCVQualifier(pv, buf, buflen);
|
||
|
}
|
||
|
|
||
|
if (CV_IS_PRIMITIVE (EVAL_TYP (pv))) {
|
||
|
switch (EVAL_TYP (pv)) {
|
||
|
default:
|
||
|
// determine type
|
||
|
|
||
|
for (itype = 0; itype < typecount; itype++) {
|
||
|
if (nametype[itype].type == (EVAL_TYP (pv) & (CV_TMASK|CV_SMASK)))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// determine mode (e.g. direct, near ptr, etc.)
|
||
|
|
||
|
for (imode = 0; imode < modecount; imode++) {
|
||
|
if (namemode[imode].mode == CV_MODE (EVAL_TYP (pv)))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// if the whole type consists of the matched type & mode,
|
||
|
// then we have a match
|
||
|
if (EVAL_TYP (pv) ==
|
||
|
(CV_typ_t) ((nametype[itype].type) |
|
||
|
(namemode[imode].mode << CV_MSHIFT))) {
|
||
|
// copy type string
|
||
|
|
||
|
len = min (*buflen, nametype[itype].len);
|
||
|
_tcsncpy (*buf, nametype[itype].name, len);
|
||
|
*buf += len;
|
||
|
*buflen -= len;
|
||
|
|
||
|
// copy mode string
|
||
|
|
||
|
len = min (*buflen, namemode[imode].len);
|
||
|
_tcsncpy (*buf, namemode[imode].name, len);
|
||
|
*buf += len;
|
||
|
*buflen -= len;
|
||
|
}
|
||
|
else {
|
||
|
// no match
|
||
|
len = min (*buflen, (sizeof("??? ") - 1));
|
||
|
_tcsncpy (*buf, "??? ", len);
|
||
|
*buf += len;
|
||
|
*buflen -= len;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case T_NCVPTR:
|
||
|
tname = "\x007""near * ";
|
||
|
goto formatmode;
|
||
|
|
||
|
case T_HCVPTR:
|
||
|
tname = "\x007""huge * ";
|
||
|
goto formatmode;
|
||
|
|
||
|
case T_FCVPTR:
|
||
|
tname = "\x006""far * ";
|
||
|
goto formatmode;
|
||
|
|
||
|
case T_32NCVPTR:
|
||
|
case T_32FCVPTR:
|
||
|
case T_64NCVPTR:
|
||
|
tname = "\x002""* ";
|
||
|
|
||
|
formatmode:
|
||
|
AppendCVQualifier(pv, buf, buflen);
|
||
|
*pvT = *pv;
|
||
|
SetNodeType (pvT, PTR_UTYPE (pv));
|
||
|
type = EVAL_TYP (pvT);
|
||
|
if (CV_IS_INTERNAL_PTR (type)) {
|
||
|
// we are in a bind here. The type generator messed
|
||
|
// up and generated a created type pointing to a created
|
||
|
// type. we are going to bail out here.
|
||
|
|
||
|
len = min (*buflen, (uint)*bailout);
|
||
|
_tcsncpy (*buf, bailout + 1, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
|
||
|
}
|
||
|
else {
|
||
|
FormatType (pvT, buf, buflen, 0, select, pHdr);
|
||
|
}
|
||
|
len = min (*buflen, (uint)*tname);
|
||
|
_tcsncpy (*buf, tname + 1, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
#ifdef NEVER
|
||
|
if (FormatUDT (pv, buf, buflen) == FALSE)
|
||
|
#endif
|
||
|
FormatExpand (pv, buf, buflen, ppName, select, pHdr);
|
||
|
}
|
||
|
if (ppName != NULL && *ppName != NULL) {
|
||
|
len = (int)_tcslen (*ppName);
|
||
|
len = min (len, *buflen);
|
||
|
pHdr->offname = (ulong)(*buf - (char *)pHdr - sizeof (HDR_TYPE));
|
||
|
pHdr->lenname = len;
|
||
|
_tcsncpy (*buf, *ppName, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
*ppName = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/** FormatExpand - format expanded type definition
|
||
|
|
||
|
* FormatExpand (pv, ppbuf, pbuflen, ppName, select)
|
||
|
|
||
|
* Entry pv = pointer to value node
|
||
|
* ppbuf = pointer to pointer to buffer
|
||
|
* pbuflen = pointer to space remaining in buffer
|
||
|
* ppName = pointer to name to insert after type if not null
|
||
|
* select = selection mask
|
||
|
* pHdr = pointer to type formatting header
|
||
|
|
||
|
* Exit buffer contains formatted type
|
||
|
* ppbuf = end of formatted string
|
||
|
* pbuflen = space remaining in buffer
|
||
|
|
||
|
* Returns none
|
||
|
*/
|
||
|
|
||
|
|
||
|
void
|
||
|
FormatExpand (
|
||
|
peval_t pv,
|
||
|
char * *buf,
|
||
|
uint *buflen,
|
||
|
char * *ppName,
|
||
|
ulong select,
|
||
|
PHDR_TYPE pHdr
|
||
|
)
|
||
|
{
|
||
|
eval_t evalT;
|
||
|
peval_t pvT = &evalT;
|
||
|
uint skip = 1;
|
||
|
uint len;
|
||
|
HTYPE hType;
|
||
|
plfEasy pType;
|
||
|
unsigned model;
|
||
|
ulong count;
|
||
|
char tempbuf[33];
|
||
|
CV_typ_t rvtype;
|
||
|
CV_typ_t mclass;
|
||
|
CV_call_e call;
|
||
|
ulong cparam;
|
||
|
CV_typ_t parmtype;
|
||
|
CV_typ_t thistype;
|
||
|
char *movestart;
|
||
|
uint movelen;
|
||
|
uint movedist;
|
||
|
HEXE hExe;
|
||
|
long nTypeSize;
|
||
|
|
||
|
if ((hType = THGetTypeFromIndex (EVAL_MOD (pv), EVAL_TYP (pv))) == 0) {
|
||
|
return;
|
||
|
}
|
||
|
pType = (plfEasy)(&((TYPPTR)(MHOmfLock (hType)))->leaf);
|
||
|
switch (pType->leaf) {
|
||
|
case LF_STRUCTURE:
|
||
|
case LF_CLASS:
|
||
|
skip = offsetof (lfClass, data);
|
||
|
RNumLeaf (((char *)(&pType->leaf)) + skip, &skip);
|
||
|
len = *(((char *)&(pType->leaf)) + skip);
|
||
|
len = min (len, *buflen);
|
||
|
_tcsncpy (*buf, ((char *)pType) + skip + 1, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
if (*buflen > 1) {
|
||
|
**buf = ' ';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
}
|
||
|
MHOmfUnLock (hType);
|
||
|
break;
|
||
|
|
||
|
case LF_UNION:
|
||
|
skip = offsetof (lfUnion, data);
|
||
|
RNumLeaf (((char *)(&pType->leaf)) + skip, &skip);
|
||
|
len = *(((char *)&(pType->leaf)) + skip);
|
||
|
len = min (len, *buflen);
|
||
|
_tcsncpy (*buf, ((char *)pType) + skip + 1, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
if (*buflen > 1) {
|
||
|
**buf = ' ';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
}
|
||
|
MHOmfUnLock (hType);
|
||
|
break;
|
||
|
|
||
|
case LF_ENUM:
|
||
|
skip = offsetof (lfEnum, Name);
|
||
|
len = ((plfEnum)pType)->Name[0];
|
||
|
len = min (len, *buflen);
|
||
|
_tcsncpy (*buf, (char *) &((plfEnum)pType)->Name[1], len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
if (*buflen > 1) {
|
||
|
**buf = ' ';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
}
|
||
|
MHOmfUnLock (hType);
|
||
|
break;
|
||
|
|
||
|
case LF_POINTER:
|
||
|
// we're going to be looking for this real soon
|
||
|
// put it in the cache now...
|
||
|
hExe = SHHexeFromHmod (EVAL_MOD (pv));
|
||
|
InsertCache(EVAL_TYP(pv), hExe);
|
||
|
|
||
|
// set up a node to evaluate this field
|
||
|
model = ((plfPointer)pType)->attr.ptrtype;
|
||
|
// format the underlying type
|
||
|
*pvT = *pv;
|
||
|
EVAL_TYP (pvT) = ((plfPointer)pType)->utype;
|
||
|
|
||
|
|
||
|
MHOmfUnLock (hType);
|
||
|
SetNodeType (pvT, EVAL_TYP (pvT));
|
||
|
FormatType (pvT, buf, buflen, 0, select, pHdr);
|
||
|
len = min (*buflen, (uint)*ptrname[model]);
|
||
|
_tcsncpy (*buf, ptrname[model] + 1, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
if (((plfPointer)pType)->attr.ptrmode == CV_PTR_MODE_REF) {
|
||
|
// this is a reference type -- we must fix the string
|
||
|
// that we just formatted so that it looks like a reference
|
||
|
// and not a pointer [rm]
|
||
|
|
||
|
DASSERT((*buf)[-1] == ' ');
|
||
|
DASSERT((*buf)[-2] == '*');
|
||
|
(*buf)[-2] = '&';
|
||
|
}
|
||
|
// const/volatile qualifier for the pointer type
|
||
|
// should be appended after the '*'
|
||
|
AppendCVQualifier (pv, buf, buflen);
|
||
|
break;
|
||
|
|
||
|
case LF_ARRAY:
|
||
|
*pvT = *pv;
|
||
|
EVAL_TYP (pvT) = ((plfArray)(&pType->leaf))->elemtype;
|
||
|
skip = offsetof (lfArray, data);
|
||
|
count = (ulong) RNumLeaf (((char *)(&pType->leaf)) + skip, &skip);
|
||
|
MHOmfUnLock (hType);
|
||
|
SetNodeType (pvT, EVAL_TYP (pvT));
|
||
|
// continue down until the underlying type is reached
|
||
|
|
||
|
FormatType (pvT, buf, buflen, ppName, select, pHdr);
|
||
|
if ((ppName != NULL) && (*ppName != NULL)) {
|
||
|
len = _tcslen (*ppName);
|
||
|
len = min (len, *buflen);
|
||
|
pHdr->offname = (ulong)(*buf - (char *)pHdr - sizeof (HDR_TYPE));
|
||
|
pHdr->lenname = len;
|
||
|
_tcsncpy (*buf, *ppName, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
*ppName = NULL;
|
||
|
}
|
||
|
|
||
|
// display size of array or * if size unknown. We have to
|
||
|
// move the trailing part of the string down if it already
|
||
|
// set so that the array dimensions come out in the proper
|
||
|
// order
|
||
|
|
||
|
nTypeSize = TypeSize (pvT);
|
||
|
if (count != 0 && nTypeSize != 0) {
|
||
|
ultoa (count / nTypeSize, tempbuf, 10);
|
||
|
len = _tcslen (tempbuf);
|
||
|
}
|
||
|
else {
|
||
|
*tempbuf = '?';
|
||
|
*(tempbuf + 1) = 0;
|
||
|
len = 1;
|
||
|
}
|
||
|
if (*buflen >= 2) {
|
||
|
if (pHdr->offtrail == 0) {
|
||
|
pHdr->offtrail = (ulong)(*buf - (char *)pHdr - sizeof (HDR_TYPE));
|
||
|
movestart = (char *)pHdr + sizeof (HDR_TYPE) + pHdr->offtrail;
|
||
|
movelen = 0;
|
||
|
movedist = 0;
|
||
|
}
|
||
|
else {
|
||
|
movestart = (char *)pHdr + sizeof (HDR_TYPE) + pHdr->offtrail;
|
||
|
movelen = _tcslen (movestart);
|
||
|
movedist = _tcslen (tempbuf) + 2;
|
||
|
movelen = min (*buflen, movelen);
|
||
|
memmove (movestart + movedist, movestart, movelen);
|
||
|
}
|
||
|
*movestart++ = '[';
|
||
|
memmove (movestart, tempbuf, len);
|
||
|
movestart += len;
|
||
|
*movestart++ = ']';
|
||
|
*buf += len + 2;
|
||
|
*buflen -= len + 2;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case LF_PROCEDURE:
|
||
|
mclass = 0;
|
||
|
rvtype = ((plfProc)pType)->rvtype;
|
||
|
call = (CV_call_e) ((plfProc)pType)->calltype;
|
||
|
cparam = ((plfProc)pType)->parmcount;
|
||
|
parmtype = ((plfProc)pType)->arglist;
|
||
|
MHOmfUnLock (hType);
|
||
|
FormatProc (pv, buf, buflen, ppName, rvtype, mclass, call,
|
||
|
cparam, parmtype, select, pHdr);
|
||
|
break;
|
||
|
|
||
|
case LF_MFUNCTION:
|
||
|
rvtype = ((plfMFunc)pType)->rvtype;
|
||
|
mclass = ((plfMFunc)pType)->classtype;
|
||
|
call = (CV_call_e) ((plfMFunc)pType)->calltype;
|
||
|
thistype = ((plfMFunc)pType)->thistype;
|
||
|
cparam = ((plfMFunc)pType)->parmcount;
|
||
|
parmtype = ((plfMFunc)pType)->arglist;
|
||
|
MHOmfUnLock (hType);
|
||
|
FormatProc (pv, buf, buflen, ppName, rvtype, mclass, call,
|
||
|
cparam, parmtype, select, pHdr);
|
||
|
break;
|
||
|
|
||
|
case LF_MODIFIER:
|
||
|
#ifdef NEVER
|
||
|
// Disabled. We emitted const in the wrong order if the following
|
||
|
// node was a pointer. Let FormatType handle this [dolphin #5043]
|
||
|
if (*buflen >= 6) {
|
||
|
if (((plfModifier)pType)->attr.MOD_const == TRUE) {
|
||
|
_tcsncpy (*buf, "const ", 6);
|
||
|
*buf += 6;
|
||
|
*buflen -= 6;
|
||
|
}
|
||
|
}
|
||
|
if (*buflen >= 9) {
|
||
|
if (((plfModifier)pType)->attr.MOD_volatile == TRUE) {
|
||
|
_tcsncpy (*buf, "volatile ", 9);
|
||
|
*buf += 9;
|
||
|
*buflen -= 9;
|
||
|
}
|
||
|
}
|
||
|
EVAL_TYP (pv) = ((plfModifier)pType)->type;
|
||
|
#endif
|
||
|
MHOmfUnLock (hType);
|
||
|
SetNodeType (pv, EVAL_TYP (pv));
|
||
|
FormatType (pv, buf, buflen, ppName, select, pHdr);
|
||
|
break;
|
||
|
|
||
|
case LF_LABEL:
|
||
|
MHOmfUnLock (hType);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
MHOmfUnLock (hType);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef NEVER
|
||
|
bool_t FormatUDT (peval_t pv, char * *buf,
|
||
|
uint *buflen)
|
||
|
{
|
||
|
// Slow ineffective search disabled jsg 2/1/92
|
||
|
|
||
|
// This code would search all symbols for typedefs to the current type index.
|
||
|
// This was making the local window repaint too sluggish, since 'FormatUDT'
|
||
|
// can be called many times per line.
|
||
|
|
||
|
#if NEVER
|
||
|
search_t Name;
|
||
|
UDTPTR pUDT;
|
||
|
uint len;
|
||
|
|
||
|
// Format typedef string
|
||
|
|
||
|
InitSearchtDef (&Name, pv, SCP_module | SCP_global);
|
||
|
if (SearchSym (&Name) == HR_found) {
|
||
|
pUDT = (UDTPTR)MHOmfLock (Name.hSym);
|
||
|
len = pUDT->name[0];
|
||
|
len = min (len, *buflen);
|
||
|
_tcsncpy (*buf, &pUDT->name[1], len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
if (*buflen > 1) {
|
||
|
**buf = ' ';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
}
|
||
|
MHOmfUnLock (Name.hSym);
|
||
|
return (TRUE);
|
||
|
}
|
||
|
#endif
|
||
|
if (pExState != NULL)
|
||
|
pExState->err_num = ERR_NONE;
|
||
|
return (FALSE);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/** FormatProc - format proc or member function
|
||
|
|
||
|
* FormatProc (pv. buf, buflen, ppName, rvtype, mclass, call, cparam, paramtype, select)
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
FormatProc (
|
||
|
peval_t pv,
|
||
|
char * *buf,
|
||
|
uint *buflen,
|
||
|
char * *ppName,
|
||
|
CV_typ_t rvtype,
|
||
|
CV_typ_t mclass,
|
||
|
CV_call_e call,
|
||
|
ulong cparam,
|
||
|
CV_typ_t paramtype,
|
||
|
ulong select,
|
||
|
PHDR_TYPE pHdr
|
||
|
)
|
||
|
{
|
||
|
eval_t evalT;
|
||
|
peval_t pvT;
|
||
|
HTYPE hArg;
|
||
|
plfArgList pArg;
|
||
|
ulong noffset = 1;
|
||
|
int len;
|
||
|
bool_t farcall;
|
||
|
ulong argCnt;
|
||
|
ulong saveOfftrail = pHdr->offtrail;
|
||
|
|
||
|
Unreferenced( mclass );
|
||
|
|
||
|
pvT = &evalT;
|
||
|
*pvT = *pv;
|
||
|
|
||
|
if (GettingChild == FALSE && (select & 0x00000001) == FALSE ) {
|
||
|
// output function return type if we are not getting a child TM.
|
||
|
// If we are getting a child tm and the function type is included,
|
||
|
// the subsequent parse of the generated expression will fail
|
||
|
// because the parse cannot handle
|
||
|
// type fcn (..........
|
||
|
|
||
|
// OR...
|
||
|
// if select == 0x1 then this is a request to format procs
|
||
|
// without the return type (for BPs etc)
|
||
|
|
||
|
EVAL_TYP (pvT) = (rvtype == 0)? T_VOID: rvtype;
|
||
|
FormatType (pvT, buf, buflen, NULL, select, pHdr);
|
||
|
//M00KLUDGE - need to output call and model here
|
||
|
switch (call) {
|
||
|
case CV_CALL_NEAR_C:
|
||
|
//near C call - caller pops stack
|
||
|
call = (CV_call_e) FCN_C;
|
||
|
farcall = FALSE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_FAR_C:
|
||
|
// far C call - caller pops stack
|
||
|
call = (CV_call_e) FCN_C;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_NEAR_PASCAL:
|
||
|
// near pascal call - callee pops stack
|
||
|
call = (CV_call_e) FCN_PASCAL;
|
||
|
farcall = FALSE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_FAR_PASCAL:
|
||
|
// far pascal call - callee pops stack
|
||
|
call = (CV_call_e) FCN_PASCAL;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_NEAR_FAST:
|
||
|
// near fast call - callee pops stack
|
||
|
call = (CV_call_e) FCN_FAST;
|
||
|
farcall = FALSE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_FAR_FAST:
|
||
|
// far fast call - callee pops stack
|
||
|
call = (CV_call_e) FCN_FAST;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_NEAR_STD:
|
||
|
// near fast call - callee pops stack
|
||
|
call = (CV_call_e) FCN_STD;
|
||
|
farcall = FALSE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_FAR_STD:
|
||
|
// far fast call - callee pops stack
|
||
|
call = (CV_call_e) FCN_STD;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_THISCALL:
|
||
|
// this goes in a reg - callee pops stack
|
||
|
call = (CV_call_e) FCN_THISCALL;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_MIPSCALL:
|
||
|
call = (CV_call_e) FCN_MIPS;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_ALPHACALL:
|
||
|
call = (CV_call_e) FCN_ALPHA;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_PPCCALL:
|
||
|
call = (CV_call_e) FCN_PPC;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
case CV_CALL_IA64CALL:
|
||
|
call = (CV_call_e) FCN_IA64;
|
||
|
farcall = TRUE;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DASSERT (FALSE);
|
||
|
call = (CV_call_e) 0;
|
||
|
farcall = FALSE;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// output function name
|
||
|
|
||
|
if ((ppName != NULL) && (*ppName != NULL)) {
|
||
|
len = (int)_tcslen (*ppName);
|
||
|
len = __min (len, (int ) *buflen);
|
||
|
pHdr->offname = (ulong)(*buf - (char *)pHdr - sizeof (HDR_TYPE));
|
||
|
pHdr->lenname = len;
|
||
|
_tcsncpy (*buf, *ppName, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
*ppName = NULL;
|
||
|
}
|
||
|
if (*buflen > 1) {
|
||
|
saveOfftrail = (ulong)(*buf - (char *)pHdr - sizeof (HDR_TYPE));
|
||
|
**buf = '(';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
}
|
||
|
if (cparam == 0) {
|
||
|
EVAL_TYP (pvT) = T_VOID;
|
||
|
FormatType (pvT, buf, buflen, NULL, select, pHdr);
|
||
|
}
|
||
|
else {
|
||
|
if ((hArg = THGetTypeFromIndex (EVAL_MOD (pv), paramtype)) == 0) {
|
||
|
return;
|
||
|
}
|
||
|
argCnt = 0;
|
||
|
while (argCnt < cparam) {
|
||
|
pArg = (plfArgList)((&((TYPPTR)MHOmfLock (hArg))->leaf));
|
||
|
EVAL_TYP (pvT) = pArg->arg[argCnt];
|
||
|
MHOmfUnLock (hArg);
|
||
|
FormatType (pvT, buf, buflen, NULL, select, pHdr);
|
||
|
argCnt++;
|
||
|
if ((argCnt < cparam) && (*buflen > 1)) {
|
||
|
// strip trailing blanks after the arg we just formatted
|
||
|
while (*((*buf)-1) == ' ') {
|
||
|
(*buf)--;
|
||
|
(*buflen)++;
|
||
|
}
|
||
|
// insert a comma and space if there are further arguments
|
||
|
**buf = ',';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
**buf = ' ';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (*buflen > 1) {
|
||
|
// strip trailing blanks
|
||
|
while (*((*buf)-1) == ' ') {
|
||
|
(*buf)--;
|
||
|
(*buflen)++;
|
||
|
}
|
||
|
// insert a closing parenthesis
|
||
|
**buf = ')';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
}
|
||
|
pHdr->offtrail = saveOfftrail;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/** FormatNode - format node according to format string
|
||
|
|
||
|
* retval = FormatNode (phTM, radix, pFormat, phValue);
|
||
|
|
||
|
* Entry phTM = pointer to handle to TM
|
||
|
* radix = default radix for formatting
|
||
|
* pFormat = pointer to format string
|
||
|
* phValue = pointer to handle for display string
|
||
|
* fAutoExpand = flag that enables auto-expanding
|
||
|
|
||
|
* Exit evaluation result formatted
|
||
|
|
||
|
* Returns EENOERROR if no error in formatting
|
||
|
* error number if error
|
||
|
*/
|
||
|
|
||
|
|
||
|
EESTATUS
|
||
|
FormatNode (
|
||
|
PHTM phTM,
|
||
|
uint Radix,
|
||
|
PEEFORMAT pFormat,
|
||
|
PEEHSTR phszValue,
|
||
|
SHFLAG fAutoExpand
|
||
|
)
|
||
|
{
|
||
|
char islong = FALSE;
|
||
|
char fc = 0;
|
||
|
char *buf;
|
||
|
int buflen = FMTSTRMAX - 1;
|
||
|
eval_t evalT;
|
||
|
peval_t pv = &evalT;
|
||
|
ulong retval = EECATASTROPHIC;
|
||
|
bool_t fPtrAndString;
|
||
|
|
||
|
DASSERT (*phTM != 0);
|
||
|
if (*phTM == 0) {
|
||
|
return (retval);
|
||
|
}
|
||
|
|
||
|
if (fAutoExpand) {
|
||
|
// Prepare auto-expanded child TM List
|
||
|
// We have to build the list here since the relevant
|
||
|
// code needs a handle to the TM, not just a pointer
|
||
|
// to the locked TM state
|
||
|
DoAutoExpand( phTM );
|
||
|
}
|
||
|
|
||
|
if ((*phszValue = MemAllocate (FMTSTRMAX)) == 0) {
|
||
|
// unable to allocate memory for formatting
|
||
|
return (retval);
|
||
|
}
|
||
|
buf = (char *)MemLock (*phszValue);
|
||
|
memset (buf, 0, FMTSTRMAX);
|
||
|
pExState = (pexstate_t) MemLock (*phTM);
|
||
|
pCxt = &pExState->cxt;
|
||
|
|
||
|
// Get expression string
|
||
|
pExStr = (char *)MemLock (pExState->hExStr);
|
||
|
|
||
|
if (pExState->state.eval_ok == TRUE) {
|
||
|
*pv = pExState->result;
|
||
|
if ((EVAL_STATE (pv) == EV_lvalue) ||
|
||
|
(EVAL_STATE (pv) == EV_type) ||
|
||
|
(EVAL_STATE (pv) == EV_rvalue && EVAL_IS_PTR (pv))) {
|
||
|
// do nothing
|
||
|
}
|
||
|
else {
|
||
|
// this handles the case were the return result is a large
|
||
|
// structure.
|
||
|
|
||
|
pv = &pExState->result;
|
||
|
}
|
||
|
if (EVAL_IS_REF (pv)) {
|
||
|
if (!LoadSymVal (pv)) {
|
||
|
// unable to load value
|
||
|
goto formatexit;
|
||
|
}
|
||
|
EVAL_IS_REF (pv) = FALSE;
|
||
|
EVAL_STATE (pv) = EV_lvalue;
|
||
|
EVAL_SYM (pv) = EVAL_PTR (pv);
|
||
|
SetNodeType (pv, PTR_UTYPE (pv));
|
||
|
}
|
||
|
if (EVAL_IS_CLASS (pv)) {
|
||
|
// For structures and classes ignore format string and format
|
||
|
// according to element data types
|
||
|
|
||
|
EVAL_STATE (pv) = EV_rvalue;
|
||
|
goto format;
|
||
|
}
|
||
|
|
||
|
// load value and format according to format string
|
||
|
|
||
|
|
||
|
if ((EVAL_STATE (pv) == EV_type) || !LoadSymVal (pv)) {
|
||
|
// unable to load value
|
||
|
retval = EEGENERAL;
|
||
|
if (pExState->err_num == ERR_NONE) {
|
||
|
pExState->err_num = ERR_NOTEVALUATABLE;
|
||
|
}
|
||
|
goto formatexit;
|
||
|
}
|
||
|
else {
|
||
|
switch (VerifyFormat (pv, pFormat, &buf, &buflen, &fPtrAndString)) {
|
||
|
case FMT_error:
|
||
|
retval = EEGENERAL;
|
||
|
pExState->err_num = ERR_FORMAT;
|
||
|
goto formatexit;
|
||
|
|
||
|
case FMT_none:
|
||
|
goto format;
|
||
|
|
||
|
case FMT_ok:
|
||
|
retval = EENOERROR;
|
||
|
goto formatexit;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// not evaluated, fail
|
||
|
retval = EEGENERAL;
|
||
|
pExState->err_num = ERR_NOTEVALUATABLE;
|
||
|
goto formatexit;
|
||
|
}
|
||
|
|
||
|
format:
|
||
|
retval = Format (pv, Radix, &buf, &buflen, fPtrAndString);
|
||
|
if ( ( retval == EENOERROR ) && fAutoExpand && EVAL_IS_PTR (pv)) {
|
||
|
FormatAutoExpand (pv, Radix, &buf, &buflen);
|
||
|
}
|
||
|
formatexit:
|
||
|
MemUnLock (pExState->hExStr);
|
||
|
MemUnLock (*phszValue);
|
||
|
MemUnLock (*phTM);
|
||
|
return (retval);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/** ExtendToQuad - convert a scalar to a quad
|
||
|
|
||
|
* If the input node is of a scalar type, convert it to type T_QUAD,
|
||
|
* for display purposes.
|
||
|
|
||
|
* (This routine replaced "ExtendToLong" in order to support __int64)
|
||
|
*/
|
||
|
|
||
|
void ExtendToQuad (peval_t pv, bool_t fUnsigned)
|
||
|
{
|
||
|
CV_typ_t type = EVAL_TYP(pv);
|
||
|
|
||
|
if (CV_IS_PRIMITIVE (type) &&
|
||
|
CV_TYP_IS_DIRECT (type) &&
|
||
|
!CV_TYP_IS_REAL (type) &&
|
||
|
!CV_TYP_IS_COMPLEX (type)) {
|
||
|
|
||
|
int size = TypeSizePrim (type);
|
||
|
|
||
|
// CUDA #4028 [rm]
|
||
|
// if the incoming type is unsigned, we don't want to sign extend
|
||
|
// all the way to long even if the user asked us to display a signed
|
||
|
// integer. Perserving the unsigned-ness of the base type prevents
|
||
|
// us from display (unsigned char)255,d as -1. We would display
|
||
|
// correctly display 0xffffffff,d as -1 however
|
||
|
|
||
|
fUnsigned |= CV_TYP_IS_UNSIGNED(type);
|
||
|
|
||
|
if (fUnsigned) {
|
||
|
switch (size) {
|
||
|
case 1:
|
||
|
EVAL_QUAD(pv) = EVAL_UCHAR (pv);
|
||
|
break;
|
||
|
case 2:
|
||
|
EVAL_QUAD (pv) = EVAL_USHORT (pv);
|
||
|
break;
|
||
|
case 4:
|
||
|
EVAL_QUAD (pv) = EVAL_ULONG (pv);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
switch (size) {
|
||
|
case 1:
|
||
|
EVAL_QUAD (pv) = EVAL_CHAR (pv);
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
EVAL_QUAD (pv) = EVAL_SHORT (pv);
|
||
|
break;
|
||
|
|
||
|
case 4:
|
||
|
EVAL_QUAD (pv) = EVAL_LONG (pv);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** VerifyFormat -
|
||
|
|
||
|
|
||
|
*/
|
||
|
|
||
|
static char stPrefixQuad[] = "\x003" "I64";
|
||
|
|
||
|
FMT_ret
|
||
|
VerifyFormat (
|
||
|
peval_t pv,
|
||
|
PEEFORMAT pFmtIn,
|
||
|
char * *buf,
|
||
|
int *buflen,
|
||
|
bool_t * pfPtrAndString
|
||
|
)
|
||
|
{
|
||
|
static const double MAXFP = 1e40; //max value printed in %f format
|
||
|
char tempbuf[128]; //large enough to hold a nice big HRESULT string but not bigger than *buflen
|
||
|
char prefix = 0;
|
||
|
char postfix = 0;
|
||
|
char fmtchar = 0;
|
||
|
int nfmtcnt = 0;
|
||
|
ulong size = 0;
|
||
|
char *pf;
|
||
|
char fmtstr[10];
|
||
|
ADDR addr;
|
||
|
ulong cnt;
|
||
|
uint fHexUpper;
|
||
|
CV_typ_t PtrToCharType = pExState->state.f32bit ? T_32PCHAR : T_PFCHAR;
|
||
|
bool_t fUnicode = FALSE;
|
||
|
|
||
|
DASSERT (*buflen >= sizeof(tempbuf));
|
||
|
if (EVAL_TYP (pv) == T_VOID) {
|
||
|
// if the value is void, ignore all formatting
|
||
|
_tcscpy (*buf, "<void>");
|
||
|
*buflen -= 6;
|
||
|
*buf += 6;
|
||
|
return (FMT_ok);
|
||
|
}
|
||
|
if (pFmtIn) {
|
||
|
pf = pFmtIn;
|
||
|
} else {
|
||
|
pf = &pExStr[pExState->strIndex];
|
||
|
}
|
||
|
if (*pf == ',') {
|
||
|
pf++;
|
||
|
}
|
||
|
while ((*pf != 0) && ((*pf == ' ') || (*pf == '\t'))) {
|
||
|
pf++;
|
||
|
}
|
||
|
|
||
|
//BUGBUG: is this really 68k specific -- if so delete it.
|
||
|
|
||
|
#if defined(TARGMAC68K)
|
||
|
if ((pFmtIn != NULL) && (*pf == 'p') && (EVAL_IS_ADDR(pv))) {
|
||
|
if (ADDR_IS_LI (EVAL_PTR(pv))) {
|
||
|
SHFixupAddr (&(EVAL_PTR(pv)));
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
if (*pf != '\0') {
|
||
|
// use the format from the command
|
||
|
*pfPtrAndString = FALSE;
|
||
|
}
|
||
|
else if ((pFmtIn != NULL) && (*pf == 'p')) {
|
||
|
// do not add string to pointer display
|
||
|
*pfPtrAndString = FALSE;
|
||
|
return (FMT_none);
|
||
|
}
|
||
|
else {
|
||
|
// add string to pointer display
|
||
|
*pfPtrAndString = TRUE;
|
||
|
return (FMT_none);
|
||
|
}
|
||
|
size = (ulong )TypeSize (pv);
|
||
|
if (*pf != 0) {
|
||
|
// extract the prefix character if it exists
|
||
|
|
||
|
switch (*pf) {
|
||
|
case 'h':
|
||
|
case 'l':
|
||
|
case 'L':
|
||
|
prefix = *pf++;
|
||
|
break;
|
||
|
case 'I':
|
||
|
if (!_tcsncmp(pf, &stPrefixQuad[1], stPrefixQuad[0])) {
|
||
|
prefix = *pf;
|
||
|
pf += stPrefixQuad[0];
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// extract the format character
|
||
|
|
||
|
switch (*pf) {
|
||
|
case 'd':
|
||
|
case 'i':
|
||
|
case 'u':
|
||
|
case 'o':
|
||
|
if (prefix == 0) {
|
||
|
prefix = 'I';
|
||
|
}
|
||
|
fmtchar = *pf++;
|
||
|
break;
|
||
|
|
||
|
case 'f':
|
||
|
case 'e':
|
||
|
case 'E':
|
||
|
case 'g':
|
||
|
case 'G':
|
||
|
if (prefix == 'h') {
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
|
||
|
// force suitable prefix according to the type of data
|
||
|
switch (EVAL_TYP (pv)) {
|
||
|
case T_REAL32:
|
||
|
prefix = 0;
|
||
|
break;
|
||
|
case T_REAL64:
|
||
|
prefix = 'l';
|
||
|
break;
|
||
|
case T_REAL80:
|
||
|
prefix = 'L';
|
||
|
break;
|
||
|
default:
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
|
||
|
fmtchar = *pf++;
|
||
|
break;
|
||
|
|
||
|
case 'c':
|
||
|
if (prefix != 0) {
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
fmtchar = *pf++;
|
||
|
break;
|
||
|
|
||
|
case 'm':
|
||
|
if (prefix != 0) {
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
fmtchar = *pf++;
|
||
|
if (*pf == 0) {
|
||
|
// assume byte display
|
||
|
postfix = (char) 'b';
|
||
|
}
|
||
|
else {
|
||
|
switch (postfix = *pf++) {
|
||
|
case 'b':
|
||
|
case 'w':
|
||
|
case 'd':
|
||
|
case 'a':
|
||
|
case 'u':
|
||
|
case 'q':
|
||
|
break;
|
||
|
default:
|
||
|
if (_istspace((_TUCHAR)postfix))
|
||
|
break;
|
||
|
else
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 's':
|
||
|
if (prefix != 0 && prefix != 'l' && prefix != 'L') {
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
fmtchar = *pf++;
|
||
|
if (prefix == 'l' || prefix =='L') {
|
||
|
fUnicode = TRUE;
|
||
|
} else
|
||
|
if (*pf == 'u') {
|
||
|
fUnicode = TRUE;
|
||
|
pf ++;
|
||
|
} else
|
||
|
if (*pf == 't') {
|
||
|
fUnicode = GetUnicodeStrings();
|
||
|
pf ++;
|
||
|
} else
|
||
|
if (T_USHORT == (EVAL_TYP(pv) & (CV_TMASK | CV_SMASK) ) ) {
|
||
|
// If we are pointing to an unisgned short
|
||
|
// this is a unicode string.
|
||
|
fUnicode = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'x':
|
||
|
case 'X':
|
||
|
if (prefix == 0) {
|
||
|
prefix = 'I';
|
||
|
|
||
|
// two hex digits for each byte of the value; since we're
|
||
|
// formatting with %lx, there's no point in having a size
|
||
|
// greater than 4
|
||
|
|
||
|
// __int64 support: we're now formatting with %I64x
|
||
|
// and the max size can be 8 bytes
|
||
|
nfmtcnt = min(size,8) * 2;
|
||
|
}
|
||
|
if (nfmtcnt == 0) {
|
||
|
if (prefix == 'h')
|
||
|
nfmtcnt = 4;
|
||
|
else if (prefix == 'I')
|
||
|
nfmtcnt = 16;
|
||
|
else
|
||
|
nfmtcnt = 8;
|
||
|
}
|
||
|
fmtchar = *pf++;
|
||
|
fHexUpper = (fmtchar == 'X');
|
||
|
break;
|
||
|
|
||
|
case 'r':
|
||
|
if (prefix != 'h') {
|
||
|
return FMT_error;
|
||
|
}
|
||
|
fmtchar = *pf++;
|
||
|
break;
|
||
|
|
||
|
case 'p':
|
||
|
fmtchar = *pf++;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
while (_istspace((_TUCHAR)*pf))
|
||
|
pf++;
|
||
|
if (*pf != 0) {
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
|
||
|
if (EVAL_IS_ENUM (pv)) {
|
||
|
SetNodeType (pv, ENUM_UTYPE (pv));
|
||
|
}
|
||
|
|
||
|
pf = fmtstr;
|
||
|
*pf++ = '%';
|
||
|
if (nfmtcnt != 0) {
|
||
|
pf += sprintf (pf, "%d", nfmtcnt);
|
||
|
}
|
||
|
if (prefix == 'I') {
|
||
|
_tcsncpy (pf, &stPrefixQuad[1], stPrefixQuad[0]);
|
||
|
pf += stPrefixQuad[0];
|
||
|
}
|
||
|
else if (prefix != 0) {
|
||
|
*pf++ = prefix;
|
||
|
}
|
||
|
*pf++ = fmtchar;
|
||
|
*pf = 0;
|
||
|
|
||
|
switch (fmtchar) {
|
||
|
case 'd':
|
||
|
case 'i':
|
||
|
case 'u':
|
||
|
ExtendToQuad (pv, (fmtchar == 'u'));
|
||
|
cnt = sprintf (tempbuf, fmtstr, EVAL_QUAD (pv));
|
||
|
break;
|
||
|
|
||
|
case 'o':
|
||
|
ExtendToQuad (pv, TRUE);
|
||
|
pf = fmtstr;
|
||
|
*pf++ = '0';
|
||
|
*pf++ = '%';
|
||
|
if (nfmtcnt != 0) {
|
||
|
pf += sprintf (fmtstr, "%d", nfmtcnt);
|
||
|
}
|
||
|
if (prefix == 'I') {
|
||
|
_tcsncpy (pf, &stPrefixQuad[1], stPrefixQuad[0]);
|
||
|
pf += stPrefixQuad[0];
|
||
|
}
|
||
|
else if (prefix != 0) {
|
||
|
*pf++ = prefix;
|
||
|
}
|
||
|
*pf++ = fmtchar;
|
||
|
*pf = 0;
|
||
|
cnt = sprintf (tempbuf, fmtstr, EVAL_QUAD (pv));
|
||
|
break;
|
||
|
|
||
|
case 'f':
|
||
|
// prevent internal buffer overflow
|
||
|
if (prefix == 'l' && EVAL_DOUBLE(pv) > MAXFP ||
|
||
|
prefix == 'L' && !Float10LessThanEqual (EVAL_LDOUBLE(pv), Float10FromDouble (MAXFP))) {
|
||
|
_tcscpy (fmtstr, prefix == 'l' ? "%le" : "%Le");
|
||
|
}
|
||
|
// fall through
|
||
|
case 'e':
|
||
|
case 'E':
|
||
|
case 'g':
|
||
|
case 'G':
|
||
|
|
||
|
if (TargetMachine != mptmppc) {
|
||
|
switch (prefix) {
|
||
|
case 'l':
|
||
|
cnt = sprintf_english (tempbuf, fmtstr, EVAL_DOUBLE(pv));
|
||
|
break;
|
||
|
case 'L':
|
||
|
//BUGBUG: this seems suspect
|
||
|
|
||
|
#if defined(WIN32) && !defined(_MIPS_) && !defined(_ALPHA_) && !defined(_PPC_) && !defined(_IA64_)
|
||
|
#pragma message("WARNING: Only one format for 10-byte reals")
|
||
|
cnt = _tcslen ( SzFromLd ( tempbuf, sizeof(tempbuf), EVAL_LDOUBLE(pv) ) );
|
||
|
#else
|
||
|
cnt = sprintf_english (tempbuf, fmtstr, EVAL_LDOUBLE(pv));
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
cnt = sprintf_english (tempbuf, fmtstr, EVAL_FLOAT(pv));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
switch (CV_SUBT (EVAL_TYP (pv))) {
|
||
|
case CV_RC_REAL32:
|
||
|
cnt = sprintf (tempbuf, fmtstr, EVAL_FLOAT (pv));
|
||
|
break;
|
||
|
case CV_RC_REAL64:
|
||
|
cnt = sprintf (tempbuf, fmtstr, EVAL_DOUBLE (pv));
|
||
|
break;
|
||
|
default:
|
||
|
cnt = sprintf (tempbuf, fmtstr, EVAL_LDOUBLE (pv));
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'm':
|
||
|
// Need to set Evaluating to 1 to force Normalization
|
||
|
// of based ptrs in CastNode (and reset to 0 immediately
|
||
|
// afterwards)
|
||
|
|
||
|
Evaluating = TRUE;
|
||
|
// CUDA #4044 : make sure we can do the cast... [rm]
|
||
|
if (!CastNode (pv, PtrToCharType, PtrToCharType)) {
|
||
|
Evaluating = FALSE;
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
EvalMem (pv, buf, buflen, postfix);
|
||
|
Evaluating = FALSE;
|
||
|
return (FMT_ok);
|
||
|
|
||
|
case 's':
|
||
|
if (EVAL_IS_ADDR (pv)) {
|
||
|
// Need to set Evaluating to 1 to force Normalization
|
||
|
// of based ptrs in CastNode (and reset to 0 immediately
|
||
|
// afterwards)
|
||
|
|
||
|
Evaluating = TRUE;
|
||
|
// CUDA #4044 : make sure we can do the cast... [rm]
|
||
|
if (!CastNode (pv, PtrToCharType, PtrToCharType)) {
|
||
|
Evaluating = FALSE;
|
||
|
return (FMT_error);
|
||
|
}
|
||
|
EvalString (pv, buf, buflen, fUnicode);
|
||
|
Evaluating = FALSE;
|
||
|
return (FMT_ok);
|
||
|
}
|
||
|
// if not an addr then just fall thru and display as
|
||
|
// individual chars
|
||
|
// sps - 9/14/92
|
||
|
fmtchar = 'c';
|
||
|
|
||
|
case 'c':
|
||
|
pf = fmtstr;
|
||
|
*pf++ = '\'';
|
||
|
if (EVAL_CHAR (pv) != 0) {
|
||
|
// if the value is not zero, then display it.
|
||
|
// otherwise, display '' (CodeView) or '\x00' (IDE)
|
||
|
*pf++ = '%';
|
||
|
*pf++ = fmtchar;
|
||
|
}
|
||
|
else {
|
||
|
pf += sprintf(pf, szNullChar);
|
||
|
}
|
||
|
*pf++ = '\'';
|
||
|
*pf = 0;
|
||
|
cnt = sprintf (tempbuf, fmtstr, EVAL_CHAR (pv));
|
||
|
break;
|
||
|
|
||
|
#ifdef USE_CUSTVIEW
|
||
|
case 'r':
|
||
|
{
|
||
|
DWORD dwValue = EVAL_ULONG(pv);
|
||
|
HRESULT hr = ExportViewHresult( dwValue,
|
||
|
&StaticHelper,
|
||
|
16 /* AMPHACK a lie */,
|
||
|
GetUnicodeStrings(),
|
||
|
tempbuf,
|
||
|
sizeof(tempbuf),
|
||
|
0 );
|
||
|
if (hr!=S_OK) {
|
||
|
sprintf( tempbuf, "0x%08lx", dwValue );
|
||
|
}
|
||
|
cnt = _tcslen( tempbuf );
|
||
|
}
|
||
|
break;
|
||
|
#endif
|
||
|
|
||
|
case 'x':
|
||
|
case 'X':
|
||
|
case 'p':
|
||
|
if (EVAL_IS_PTR (pv)) {
|
||
|
addr = EVAL_PTR (pv);
|
||
|
if (ADDR_IS_LI (addr)) {
|
||
|
SHFixupAddr (&addr);
|
||
|
}
|
||
|
fHexUpper = !!fHexUpper; // canonicalize
|
||
|
#if defined(TARGMAC68K)
|
||
|
if(GetAddrSeg(addr) != 0)
|
||
|
{
|
||
|
cnt = sprintf (tempbuf, fmt_ptr_16_32[fHexUpper],
|
||
|
GetAddrSeg (addr), (CV_uoff32_t)GetAddrOff (addr));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
cnt = sprintf (tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(CV_uoff32_t)GetAddrOff (addr));
|
||
|
}
|
||
|
#else // !TARGMAC68K
|
||
|
// [cuda#4793 5/25/93 mikemo] Don't use EVAL_IS_NPTR32
|
||
|
// and EVAL_IS_FPTR32 here, because they fail on arrays
|
||
|
if (EVAL_PTRTYPE (pv) == CV_PTR_NEAR32 ||
|
||
|
EVAL_PTRTYPE (pv) == CV_PTR_FAR32) {
|
||
|
cnt = sprintf (tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(CV_uoff32_t)GetAddrOff (addr));
|
||
|
} else if (EVAL_PTRTYPE (pv) == CV_PTR_64) {
|
||
|
cnt = sprintf (tempbuf, fmt_ptr_64[fHexUpper],
|
||
|
GetAddrOff (addr));
|
||
|
}
|
||
|
else {
|
||
|
// if it is a near ptr we will treat is as a ptr
|
||
|
// since we always carry around the seg & offset
|
||
|
// even if it is near.
|
||
|
|
||
|
cnt = sprintf (tempbuf, fmt_ptr_16_16[fHexUpper],
|
||
|
GetAddrSeg (addr), (CV_uoff16_t)GetAddrOff (addr));
|
||
|
}
|
||
|
#endif // TARGMAC68K
|
||
|
}
|
||
|
else {
|
||
|
ExtendToQuad(pv, TRUE);
|
||
|
pf = fmtstr;
|
||
|
*pf++ = '0';
|
||
|
*pf++ = 'x';
|
||
|
*pf++ = '%';
|
||
|
*pf++ = '.';
|
||
|
if (nfmtcnt != 0) {
|
||
|
pf += sprintf(pf, "%d", nfmtcnt);
|
||
|
}
|
||
|
if (prefix == 'I') {
|
||
|
_tcsncpy (pf, &stPrefixQuad[1], stPrefixQuad[0]);
|
||
|
pf += stPrefixQuad[0];
|
||
|
}
|
||
|
else if (prefix != 0) {
|
||
|
*pf++ = prefix;
|
||
|
}
|
||
|
*pf++ = fmtchar;
|
||
|
*pf = 0;
|
||
|
cnt = sprintf (tempbuf, fmtstr, EVAL_UQUAD (pv));
|
||
|
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
_tcsncpy (*buf, tempbuf, cnt + 1);
|
||
|
*buf += cnt;
|
||
|
*buflen -= cnt;
|
||
|
}
|
||
|
|
||
|
return(FMT_ok);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Format - format data
|
||
|
|
||
|
*/
|
||
|
|
||
|
|
||
|
EESTATUS
|
||
|
Format (
|
||
|
peval_t pv,
|
||
|
uint radix,
|
||
|
char * *buf,
|
||
|
int *plen,
|
||
|
bool_t fPtrAndString
|
||
|
)
|
||
|
{
|
||
|
char tempbuf[FMTSTRMAX];
|
||
|
char *pTempBuf = tempbuf;
|
||
|
uint cnt;
|
||
|
ulong isfloat = FALSE;
|
||
|
HSYM hProc = 0;
|
||
|
// M00FLAT32
|
||
|
SYMPTR pProc;
|
||
|
char *pc = NULL;
|
||
|
ulong cbTempBuf;
|
||
|
ulong *pcbTempBuf = &cbTempBuf;
|
||
|
ulong iRadix;
|
||
|
ADDR addr;
|
||
|
CV_typ_t type;
|
||
|
EEHSTR hStr = 0;
|
||
|
uint fHexUpper = 0;
|
||
|
|
||
|
if (*plen < 5 ) {
|
||
|
return (EENOERROR);
|
||
|
}
|
||
|
|
||
|
fHexUpper = !!fHexUpper; // canonicalize
|
||
|
|
||
|
if (EVAL_IS_BITF (pv)) {
|
||
|
// for a bitfield, change the type to the underlying type
|
||
|
SetNodeType (pv, BITF_UTYPE (pv));
|
||
|
}
|
||
|
if (EVAL_IS_CLASS (pv)) {
|
||
|
FormatClass (pv, radix, buf, plen);
|
||
|
return (EENOERROR);
|
||
|
|
||
|
}
|
||
|
else if (EVAL_IS_ENUM (pv)) {
|
||
|
if (EVAL_STATE(pv) == EV_constant) {
|
||
|
SetNodeType(pv, ENUM_UTYPE(pv));
|
||
|
}
|
||
|
else {
|
||
|
return (FormatEnum(pv, *buf, *plen));
|
||
|
}
|
||
|
}
|
||
|
if (CV_IS_PRIMITIVE (EVAL_TYP (pv)) && !EVAL_IS_PTR (pv)) {
|
||
|
if (EVAL_TYP (pv) == T_VOID) {
|
||
|
_tcscpy (tempbuf, "<void>");
|
||
|
}
|
||
|
else {
|
||
|
// establish format string index
|
||
|
switch (radix) {
|
||
|
case 8:
|
||
|
iRadix = 0;
|
||
|
break;
|
||
|
|
||
|
case 10:
|
||
|
iRadix = 1;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DASSERT (FALSE);
|
||
|
// note fall through
|
||
|
case 16:
|
||
|
if (fHexUpper) {
|
||
|
iRadix = 3;
|
||
|
}
|
||
|
else {
|
||
|
iRadix = 2;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
switch (EVAL_TYP (pv)) {
|
||
|
case T_CHAR:
|
||
|
case T_RCHAR:
|
||
|
case T_INT1:
|
||
|
if (fPtrAndString) {
|
||
|
if (EVAL_CHAR (pv) != 0) {
|
||
|
sprintf (tempbuf, fmt_char_nz[iRadix],
|
||
|
(radix==10) ? EVAL_CHAR (pv) : EVAL_UCHAR (pv),
|
||
|
EVAL_CHAR (pv));
|
||
|
}
|
||
|
else {
|
||
|
// don't stick a 0 in the string
|
||
|
sprintf (tempbuf, fmt_char_zr[iRadix],
|
||
|
EVAL_CHAR (pv), EVAL_CHAR (pv));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
sprintf (tempbuf, fmt_char[iRadix],
|
||
|
(radix==10) ? EVAL_CHAR (pv) : EVAL_UCHAR (pv));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case T_UCHAR:
|
||
|
case T_UINT1:
|
||
|
if (fPtrAndString) {
|
||
|
if (EVAL_UCHAR (pv) != 0) {
|
||
|
sprintf (tempbuf, fmt_char_nz[iRadix],
|
||
|
EVAL_UCHAR (pv), EVAL_UCHAR (pv));
|
||
|
}
|
||
|
else {
|
||
|
// don't stick a 0 in the string
|
||
|
sprintf (tempbuf, fmt_char_zr[iRadix],
|
||
|
EVAL_UCHAR (pv), EVAL_UCHAR (pv));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
sprintf (tempbuf, fmt_char[iRadix], EVAL_UCHAR (pv));
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case T_SHORT:
|
||
|
case T_INT2:
|
||
|
sprintf (tempbuf, fmt_short[iRadix], EVAL_SHORT (pv));
|
||
|
break;
|
||
|
|
||
|
case T_SEGMENT:
|
||
|
case T_USHORT:
|
||
|
case T_UINT2:
|
||
|
sprintf (tempbuf, fmt_ushort[iRadix], EVAL_USHORT (pv));
|
||
|
break;
|
||
|
|
||
|
case T_LONG:
|
||
|
case T_INT4:
|
||
|
sprintf (tempbuf, fmt_long[iRadix], EVAL_LONG (pv));
|
||
|
break;
|
||
|
|
||
|
case T_ULONG:
|
||
|
case T_UINT4:
|
||
|
sprintf (tempbuf, fmt_ulong[iRadix], EVAL_ULONG (pv));
|
||
|
break;
|
||
|
|
||
|
case T_QUAD:
|
||
|
case T_INT8:
|
||
|
sprintf (tempbuf, fmt_quad[iRadix], EVAL_QUAD (pv));
|
||
|
break;
|
||
|
|
||
|
case T_UQUAD:
|
||
|
case T_UINT8:
|
||
|
sprintf (tempbuf, fmt_uquad[iRadix], EVAL_UQUAD (pv));
|
||
|
break;
|
||
|
|
||
|
case T_REAL32:
|
||
|
sprintf_english (tempbuf, "%#g", EVAL_FLOAT (pv));
|
||
|
isfloat = TRUE;
|
||
|
break;
|
||
|
|
||
|
case T_REAL64:
|
||
|
sprintf_english (tempbuf, "%#.14g", EVAL_DOUBLE (pv));
|
||
|
isfloat = TRUE;
|
||
|
break;
|
||
|
|
||
|
case T_REAL80:
|
||
|
#if defined(WIN32) && !defined(_MIPS_) && !defined(_ALPHA_) && !defined(_IA64_)
|
||
|
#pragma message("WARNING: Only one format for 10-byte reals.")
|
||
|
SzFromLd ( tempbuf, sizeof(tempbuf), EVAL_LDOUBLE ( pv ) );
|
||
|
#else
|
||
|
sprintf_english (tempbuf, "%#.20Lg", EVAL_LDOUBLE (pv));
|
||
|
#endif
|
||
|
isfloat = TRUE;
|
||
|
break;
|
||
|
|
||
|
case T_NOTYPE:
|
||
|
default:
|
||
|
if ( ADDR_IS_OFF32(pv->addr) ) {
|
||
|
sprintf (tempbuf, fmt_ulong[iRadix], EVAL_ULONG (pv) );
|
||
|
}
|
||
|
else {
|
||
|
sprintf (tempbuf, fmt_ushort[iRadix], EVAL_USHORT (pv));
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (EVAL_IS_ADDR (pv)) {
|
||
|
addr = EVAL_PTR (pv);
|
||
|
if (EVAL_IS_BASED (pv)) {
|
||
|
#if defined(TARGMAC68K)
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(ulong)EVAL_PTR_OFF (pv));
|
||
|
#else
|
||
|
if (pExState->state.f32bit) {
|
||
|
// a based pointer in a 32bit context is
|
||
|
// treated as a 32bit based pointer -- dolphin #979
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(ulong)EVAL_PTR_OFF (pv));
|
||
|
}
|
||
|
else
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_0_16[fHexUpper],
|
||
|
(ushort)EVAL_PTR_OFF (pv));
|
||
|
#endif
|
||
|
}
|
||
|
#if defined(TARGMAC68K)
|
||
|
else {
|
||
|
if (ADDR_IS_LI (addr)) {
|
||
|
SHFixupAddr (&addr);
|
||
|
}
|
||
|
if(GetAddrSeg(addr) != 0) {
|
||
|
cbTempBuf = sprintf (tempbuf,
|
||
|
fmt_ptr_16_32[fHexUpper],
|
||
|
GetAddrSeg (addr), (CV_uoff32_t)GetAddrOff (addr));
|
||
|
}
|
||
|
else {
|
||
|
cbTempBuf = sprintf (tempbuf,
|
||
|
fmt_ptr_0_32[fHexUpper],
|
||
|
(CV_uoff32_t)GetAddrOff (addr));
|
||
|
}
|
||
|
}
|
||
|
#else // !TARGMAC68K
|
||
|
else if (EVAL_IS_PTR (pv) && EVAL_IS_REG (pv)) {
|
||
|
if (EVAL_IS_NPTR (pv)) {
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_16_16[fHexUpper],
|
||
|
GetSegmentRegister(pExState->hframe, REG_DS), (CV_uoff16_t)EVAL_PTR_OFF (pv));
|
||
|
}
|
||
|
else if (EVAL_IS_NPTR32 (pv)) {
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(CV_uoff32_t)EVAL_PTR_OFF (pv));
|
||
|
}
|
||
|
else {
|
||
|
if (ADDR_IS_LI (addr)) {
|
||
|
SHFixupAddr (&addr);
|
||
|
}
|
||
|
if (EVAL_IS_FPTR32 (pv)) {
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(CV_uoff32_t)GetAddrOff (addr));
|
||
|
}
|
||
|
else {
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_16_16[fHexUpper],
|
||
|
GetAddrSeg (addr), (CV_uoff16_t)GetAddrOff (addr));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (EVAL_IS_PTR (pv) && EVAL_IS_NPTR (pv)) {
|
||
|
// if it is a near ptr we will treat is as a far ptr
|
||
|
// since we always carry around the seg & offset
|
||
|
// even if it is near.
|
||
|
// DASSERT( EVAL_PTR_SEG (pv) != 0);
|
||
|
if (ADDR_IS_LI (addr)) {
|
||
|
SHFixupAddr (&addr);
|
||
|
}
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_16_16[fHexUpper],
|
||
|
GetAddrSeg (addr), (CV_uoff16_t)GetAddrOff (addr));
|
||
|
}
|
||
|
else if (EVAL_IS_PTR (pv) && EVAL_IS_NPTR32 (pv)) {
|
||
|
// if it is a near ptr we will treat is as a far ptr
|
||
|
// since we always carry around the seg & offset
|
||
|
// even if it is near.
|
||
|
// DASSERT( EVAL_PTR_SEG (pv) != 0);
|
||
|
if (ADDR_IS_LI (addr)) {
|
||
|
SHFixupAddr (&addr);
|
||
|
}
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(CV_uoff32_t)GetAddrOff (addr));
|
||
|
}
|
||
|
else {
|
||
|
if (ADDR_IS_LI (addr)) {
|
||
|
SHFixupAddr (&addr);
|
||
|
}
|
||
|
if (EVAL_IS_FPTR32 (pv)) {
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(CV_uoff32_t)GetAddrOff (addr));
|
||
|
} else if (EVAL_IS_PTR64 (pv)) {
|
||
|
cbTempBuf = sprintf (tempbuf, fmt_ptr_64[fHexUpper],
|
||
|
/*v-vadimp (CV_uoff64_t)*/GetAddrOff (addr));
|
||
|
}
|
||
|
else {
|
||
|
if ( ADDR_IS_FLAT ( addr ) ) {
|
||
|
|
||
|
DASSERT ( ADDR_IS_OFF32 ( addr) );
|
||
|
cbTempBuf = sprintf (
|
||
|
tempbuf,
|
||
|
(TargetMachine == mptia64)? fmt_ptr_64[fHexUpper] : fmt_ptr_0_32[fHexUpper],
|
||
|
GetAddrOff ( addr )
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
|
||
|
if ( ADDR_IS_OFF32 ( addr ) ) {
|
||
|
cbTempBuf = sprintf (
|
||
|
tempbuf,
|
||
|
fmt_ptr_16_32[fHexUpper],
|
||
|
GetAddrSeg (addr),
|
||
|
(CV_uoff32_t) GetAddrOff (addr)
|
||
|
);
|
||
|
}
|
||
|
else {
|
||
|
cbTempBuf = sprintf (
|
||
|
tempbuf,
|
||
|
fmt_ptr_16_16[fHexUpper],
|
||
|
GetAddrSeg (addr),
|
||
|
(CV_uoff16_t) GetAddrOff (addr)
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif // TARGMAC68K
|
||
|
if (!EVAL_IS_DPTR (pv)) {
|
||
|
CXT cxt;
|
||
|
eval_t nv = *pv;
|
||
|
|
||
|
memset(&cxt, 0, sizeof(CXT));
|
||
|
|
||
|
addr = EVAL_PTR (pv);
|
||
|
if (!ADDR_IS_LI (addr)) {
|
||
|
SHUnFixupAddr (&addr);
|
||
|
}
|
||
|
SHSetCxtMod ( &addr, &cxt );
|
||
|
nv.CXTT = cxt;
|
||
|
if (SHGetNearestHsym (&addr, SHHMODFrompCXT (&cxt), EECODE, &hProc) == 0) {
|
||
|
// the address exactly matches a symbol
|
||
|
switch ((pProc = (SYMPTR)MHOmfLock ((HSYM)hProc))->rectyp) {
|
||
|
case S_LPROC16:
|
||
|
case S_GPROC16:
|
||
|
EVAL_MOD(&nv) = SHHMODFrompCXT (&cxt);
|
||
|
SetNodeType(&nv, (CV_typ_t)((PROCPTR16)pProc)->typind);
|
||
|
pc = FormatVirtual ((char *) ((PROCPTR16)pProc)->name, &nv, &hStr);
|
||
|
break;
|
||
|
|
||
|
case S_THUNK16:
|
||
|
pc = (char *) ((THUNKPTR16)pProc)->name;
|
||
|
break;
|
||
|
|
||
|
case S_LPROC32:
|
||
|
case S_GPROC32:
|
||
|
EVAL_MOD(&nv) = SHHMODFrompCXT (&cxt);
|
||
|
SetNodeType(&nv, (CV_typ_t)((PROCPTR32)pProc)->typind);
|
||
|
pc = FormatVirtual ((char *) ((PROCPTR32)pProc)->name, &nv, &hStr);
|
||
|
break;
|
||
|
|
||
|
case S_LPROCMIPS:
|
||
|
case S_GPROCMIPS:
|
||
|
EVAL_MOD(&nv) = SHHMODFrompCXT (&cxt);
|
||
|
SetNodeType(&nv, (CV_typ_t)((PROCPTRMIPS)pProc)->typind);
|
||
|
pc = FormatVirtual ((char *) ((PROCPTRMIPS)pProc)->name, &nv, &hStr);
|
||
|
break;
|
||
|
|
||
|
case S_LPROCIA64:
|
||
|
case S_GPROCIA64:
|
||
|
EVAL_MOD(&nv) = SHHMODFrompCXT (&cxt);
|
||
|
SetNodeType(&nv, (CV_typ_t)((PROCPTRIA64)pProc)->typind);
|
||
|
pc = FormatVirtual ((char *) ((PROCPTRIA64)pProc)->name, &nv, &hStr);
|
||
|
break;
|
||
|
|
||
|
case S_THUNK32:
|
||
|
pc = (char *) ((THUNKPTR32)pProc)->name;
|
||
|
break;
|
||
|
|
||
|
case S_PUB32:
|
||
|
{
|
||
|
char undname[256];
|
||
|
pc = FormatUndecorate( (char*) ((DATASYM32*)pProc)->name, undname );
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
MHOmfUnLock ((HSYM)hProc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// M00KLUDGE - display strings of chars
|
||
|
if ((fPtrAndString) && (EVAL_IS_PTR (pv))) {
|
||
|
type = EVAL_TYP (pv);
|
||
|
if (EVAL_IS_BASED (pv) || !CV_IS_PRIMITIVE(type)) {
|
||
|
type = PTR_UTYPE (pv);
|
||
|
}
|
||
|
else {
|
||
|
type &= (CV_TMASK | CV_SMASK);
|
||
|
}
|
||
|
if ((type == T_CHAR) || (type == T_UCHAR) || (type == T_RCHAR) || (type == T_WCHAR)
|
||
|
|| (GetUnicodeStrings () && (type == T_USHORT))
|
||
|
) {
|
||
|
|
||
|
CV_typ_t PtrToCharType;
|
||
|
BOOL fUnicode = FALSE;
|
||
|
if ((type == T_USHORT) || (type == T_WCHAR))
|
||
|
{
|
||
|
PtrToCharType = pExState->state.f32bit? ((TargetMachine == mptia64)? T_64PUSHORT : T_32PUSHORT) : T_PFUSHORT;
|
||
|
fUnicode = TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PtrToCharType = pExState->state.f32bit ? ((TargetMachine == mptia64)? T_64PCHAR : T_32PCHAR) : T_PFCHAR;
|
||
|
}
|
||
|
|
||
|
tempbuf[cbTempBuf] = ' ';
|
||
|
|
||
|
// Need to set Evaluating to 1 to force Normalization
|
||
|
// of based ptrs in CastNode (and reset to 0 immediately
|
||
|
// afterwards)
|
||
|
Evaluating = TRUE;
|
||
|
|
||
|
// CUDA #4044 : make sure we can do the cast... [rm]
|
||
|
if (!CastNode (pv, PtrToCharType, PtrToCharType)) {
|
||
|
Evaluating = FALSE;
|
||
|
return (EEGENERAL);
|
||
|
}
|
||
|
Evaluating = FALSE;
|
||
|
pTempBuf += cbTempBuf + 1;
|
||
|
*pcbTempBuf = FMTSTRMAX - cbTempBuf - 1;
|
||
|
EvalString (pv, &pTempBuf, (int *) pcbTempBuf, fUnicode);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
pExState->err_num = ERR_UNKNOWNTYPE;
|
||
|
return (EEGENERAL);
|
||
|
}
|
||
|
cnt = _tcslen (tempbuf);
|
||
|
cnt = min ((uint)*plen, cnt);
|
||
|
_tcsncpy (*buf, tempbuf, cnt);
|
||
|
*plen -= cnt;
|
||
|
*buf += cnt;
|
||
|
if (pc != NULL) {
|
||
|
cnt = min ((uint)*plen, ((uint)*pc) + 1);
|
||
|
**buf = ' ';
|
||
|
(*buf)++;
|
||
|
_tcsncpy (*buf, pc + 1, cnt - 1);
|
||
|
*plen -= cnt;
|
||
|
*buf += cnt;
|
||
|
}
|
||
|
if (hStr != 0) {
|
||
|
MemUnLock (hStr);
|
||
|
MHMemFree (hStr);
|
||
|
}
|
||
|
return (EENOERROR);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static char *szClassDisp = "{...}";
|
||
|
|
||
|
void FormatClass (peval_t pv, uint radix, char * *buf,
|
||
|
int *buflen)
|
||
|
{
|
||
|
int len;
|
||
|
|
||
|
Unreferenced( radix );
|
||
|
Unreferenced( pv );
|
||
|
|
||
|
if (pExState->hAutoExpandRule) {
|
||
|
FormatAutoExpand (pv, radix, buf, buflen);
|
||
|
}
|
||
|
else {
|
||
|
len = _tcslen (szClassDisp);
|
||
|
len = min (*buflen, len);
|
||
|
_tcsncpy (*buf, szClassDisp, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
#ifdef USE_CUSTVIEW
|
||
|
|
||
|
BOOL WINAPI StaticHelperReadMem ( DEBUGHELPER *pThis, DWORD dwAddr, DWORD nWant, VOID* pWhere, DWORD *nGot )
|
||
|
{
|
||
|
ADDR addr;
|
||
|
UINT count;
|
||
|
|
||
|
if (pThis!=&StaticHelper)
|
||
|
{
|
||
|
// check correct 'this' usage
|
||
|
DASSERT( !"Bad this pointer to HelperReadMem" );
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
AddrInit( &addr, 0, 0, dwAddr, TRUE, TRUE, FALSE, FALSE );
|
||
|
|
||
|
count = GetDebuggeeBytes (addr, nWant, pWhere, T_RCHAR);
|
||
|
|
||
|
*nGot = count;
|
||
|
|
||
|
if (count==0) {
|
||
|
return E_FAIL;
|
||
|
} else if (count!=nWant) {
|
||
|
return S_FALSE;
|
||
|
} else {
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
DEBUGHELPER StaticHelper =
|
||
|
{
|
||
|
0x10000,
|
||
|
StaticHelperReadMem
|
||
|
};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* FormatAutoExpand
|
||
|
|
||
|
* Format the auto-expanding part of a pointer or class
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
FormatAutoExpand (
|
||
|
peval_t pv,
|
||
|
uint radix,
|
||
|
char * *buf,
|
||
|
int *buflen
|
||
|
)
|
||
|
{
|
||
|
uint cHTM = 0;
|
||
|
int len;
|
||
|
LSZ lsz;
|
||
|
char *pcLDelim;
|
||
|
char *pcRDelim;
|
||
|
#ifdef USE_CUSTVIEW
|
||
|
CUSTOMVIEWER pViewer = NULL;
|
||
|
#endif
|
||
|
|
||
|
if (pExState->hAutoExpandRule) {
|
||
|
|
||
|
if (EVAL_IS_PTR (pv) && *buflen > 1) {
|
||
|
// we're right after the ptr value string
|
||
|
// so leave an extra space
|
||
|
* ((*buf)++) = ' ';
|
||
|
**buf = '\0';
|
||
|
*buflen -= 1;
|
||
|
}
|
||
|
|
||
|
if (*buflen > 1) {
|
||
|
* ((*buf)++) = '{';
|
||
|
**buf = '\0';
|
||
|
*buflen -= 1;
|
||
|
}
|
||
|
|
||
|
lsz = (LSZ) MemLock (pExState->hAutoExpandRule);
|
||
|
|
||
|
|
||
|
#ifdef USE_CUSTVIEW
|
||
|
if (_tcsncmp(lsz,"$$ADDON(",8)==0)
|
||
|
{
|
||
|
CUSTOMVIEWER pViewer = NULL;
|
||
|
HRESULT hr;
|
||
|
char arg[256];
|
||
|
char *p = _tcschr( lsz+8, ')' );
|
||
|
|
||
|
if (p)
|
||
|
{
|
||
|
memcpy( arg, lsz+8, p-(lsz+8) );
|
||
|
arg[ p-(lsz+8) ] = 0;
|
||
|
// one day look up these names in the registry, but
|
||
|
// hard-coded for now
|
||
|
if (_tcscmp( arg, "GUID" )==0)
|
||
|
pViewer = ExportViewGuid;
|
||
|
else if (_tcscmp( arg, "HWND" )==0)
|
||
|
pViewer = ExportViewHwnd;
|
||
|
else if (_tcscmp( arg, "VARIANT" )==0)
|
||
|
pViewer = ExportViewVariant;
|
||
|
|
||
|
if (pViewer)
|
||
|
{
|
||
|
// call the external DLL to expand the item
|
||
|
ADDR addr;
|
||
|
|
||
|
GetRawAddr( pv, &addr );
|
||
|
**buf = 0;
|
||
|
|
||
|
hr = pViewer( GetAddrOff( addr ), &StaticHelper, radix, GetUnicodeStrings(), *buf, *buflen, 0 );
|
||
|
if (hr==S_OK)
|
||
|
{
|
||
|
short len = (short)_tcslen(*buf);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if ( (pViewer==NULL) || (hr!=S_OK) )
|
||
|
FormatAEError( pv, radix, buf, buflen );
|
||
|
// skip to end of AE string
|
||
|
lsz += _tcslen( lsz );
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
|
||
|
while ( (pcLDelim = _tcschr (lsz, _T ('<'))) != NULL &&
|
||
|
(pcRDelim = _tcschr (pcLDelim, _T('>'))) != NULL ) {
|
||
|
|
||
|
// If the '>' we found is actually a '->' skip over this
|
||
|
// and look for the next one.
|
||
|
while (pcRDelim && *(pcRDelim - 1) == '-' )
|
||
|
{
|
||
|
pcRDelim = _tcschr(pcRDelim + 1, _T('>'));
|
||
|
}
|
||
|
|
||
|
if (pcRDelim == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// copy string that precedes '<'
|
||
|
len = (int) min (*buflen, pcLDelim - lsz);
|
||
|
_tcsncpy (*buf, lsz, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
|
||
|
lsz = pcLDelim + 1;
|
||
|
*pcRDelim = 0;
|
||
|
|
||
|
switch (AEParseRule(lsz)) {
|
||
|
case AE_downcasttype:
|
||
|
// print downcast class name (if any)
|
||
|
FormatAEDownCastType (pv, radix, buf, buflen);
|
||
|
break;
|
||
|
case AE_childTM:
|
||
|
// display value of auto-expand child TM
|
||
|
FormatAEChildTM (cHTM++, pv, radix, buf, buflen);
|
||
|
break;
|
||
|
default:
|
||
|
FormatAEError (pv, radix, buf, buflen);
|
||
|
}
|
||
|
|
||
|
*pcRDelim = _T('>');
|
||
|
|
||
|
lsz = pcRDelim + 1;
|
||
|
}
|
||
|
MemUnLock (pExState->hAutoExpandRule);
|
||
|
|
||
|
// copy remainder of format string
|
||
|
len = _tcslen (lsz);
|
||
|
len = min (*buflen, len);
|
||
|
_tcsncpy (*buf, lsz, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
|
||
|
if (*buflen > 1) {
|
||
|
* ((*buf)++) = '}';
|
||
|
**buf = '\0';
|
||
|
*buflen -= 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* FormatAEChildTM
|
||
|
|
||
|
* Format an auto-expanding child TM
|
||
|
*/
|
||
|
|
||
|
void FormatAEChildTM (uint cHTM, peval_t pv, uint radix, char * *buf,
|
||
|
int *buflen)
|
||
|
{
|
||
|
pexstate_t pExStateSav = pExState;
|
||
|
EEHSTR hszValue;
|
||
|
LSZ szValue;
|
||
|
PTML pTML;
|
||
|
HTM * rgHTM;
|
||
|
int len;
|
||
|
bool_t fRebind = pExState->state.fAErebind;
|
||
|
bool_t fReeval = pExState->state.fAEreeval;
|
||
|
bool_t fFormatOK = FALSE;
|
||
|
FMT_state fmtstate;
|
||
|
EESTATUS error;
|
||
|
|
||
|
pTML = &pExState->TMLAutoExpand;
|
||
|
|
||
|
// Find the appropriate TM in the TMLAutoExpand list
|
||
|
// and display its value.
|
||
|
if (cHTM < pTML->cTMListAct) {
|
||
|
DASSERT (pTML->hTMList);
|
||
|
rgHTM = (HTM *)MemLock (pTML->hTMList);
|
||
|
if (rgHTM && rgHTM [cHTM] != NULL) {
|
||
|
SaveFmtState (&fmtstate);
|
||
|
error = FormatNode (&rgHTM[cHTM], radix, NULL, &hszValue, FALSE);
|
||
|
RestoreFmtState (&fmtstate);
|
||
|
if (EENOERROR == error) {
|
||
|
fFormatOK = TRUE;
|
||
|
szValue = (LSZ) MemLock (hszValue);
|
||
|
len = _tcslen (szValue);
|
||
|
len = min (*buflen, len);
|
||
|
_tcsncpy (*buf, szValue, len);
|
||
|
MemUnLock (hszValue);
|
||
|
MemFree (hszValue);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
}
|
||
|
}
|
||
|
MemUnLock (pTML->hTMList);
|
||
|
}
|
||
|
pExState = pExStateSav;
|
||
|
if (!fFormatOK) {
|
||
|
FormatAEError (pv, radix, buf, buflen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* FormatAEError
|
||
|
|
||
|
* Display Error message while auto-expanding an expression
|
||
|
*/
|
||
|
|
||
|
static char *szErrDisp = "???";
|
||
|
|
||
|
void FormatAEError (peval_t pv, uint radix, char * *buf,
|
||
|
int *buflen)
|
||
|
{
|
||
|
int len;
|
||
|
|
||
|
Unreferenced( radix );
|
||
|
Unreferenced( pv );
|
||
|
|
||
|
len = _tcslen (szErrDisp);
|
||
|
len = min (*buflen, len);
|
||
|
_tcsncpy (*buf, szErrDisp, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* FormatAEDownCastType
|
||
|
|
||
|
* Format derived-most class type name
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
FormatAEDownCastType (
|
||
|
peval_t pv,
|
||
|
uint radix,
|
||
|
char * *buf,
|
||
|
int *buflen
|
||
|
)
|
||
|
{
|
||
|
LSZ lsz;
|
||
|
char *pch;
|
||
|
int len;
|
||
|
|
||
|
if (pExState->hDClassName)
|
||
|
lsz = (LSZ) MemLock (pExState->hDClassName);
|
||
|
else {
|
||
|
CV_typ_t type = EVAL_TYP (pv);
|
||
|
if (EVAL_IS_PTR (pv)) {
|
||
|
type = PTR_UTYPE (pv);
|
||
|
}
|
||
|
lsz = GetTypeName (type, EVAL_MOD (pv));
|
||
|
}
|
||
|
|
||
|
DASSERT (lsz);
|
||
|
// hDClassName may contain a context operator
|
||
|
// We skip this operator in order to display the class name only
|
||
|
if ((pch = _tcschr (lsz, '}')) != NULL )
|
||
|
lsz = pch + 1;
|
||
|
len = _tcslen (lsz);
|
||
|
len = min (*buflen, len);
|
||
|
_tcsncpy (*buf, lsz, len);
|
||
|
*buflen -= len;
|
||
|
*buf += len;
|
||
|
|
||
|
if (pExState->hDClassName)
|
||
|
MemUnLock (pExState->hDClassName);
|
||
|
}
|
||
|
|
||
|
|
||
|
EESTATUS
|
||
|
FormatEnum (
|
||
|
peval_t pv,
|
||
|
char *buf,
|
||
|
int buflen
|
||
|
)
|
||
|
{
|
||
|
HTYPE hType, hFieldType;
|
||
|
plfEnum pEnumType;
|
||
|
plfFieldList pFieldType;
|
||
|
char * pEnumerate;
|
||
|
uint i, skip;
|
||
|
EESTATUS retval = EENOERROR;
|
||
|
|
||
|
if ((hType = THGetTypeFromIndex (EVAL_MOD (pv), EVAL_TYP (pv))) == 0) {
|
||
|
goto NoDisplay;
|
||
|
}
|
||
|
pEnumType = (plfEnum)(&((TYPPTR)(MHOmfLock (hType)))->leaf);
|
||
|
DASSERT(pEnumType->leaf == LF_ENUM);
|
||
|
|
||
|
if ((hFieldType = THGetTypeFromIndex (EVAL_MOD (pv), pEnumType->field)) == 0) {
|
||
|
goto NoDisplay;
|
||
|
}
|
||
|
pFieldType = (plfFieldList)(&((TYPPTR)(MHOmfLock (hFieldType)))->leaf);
|
||
|
|
||
|
for (i = 0, pEnumerate = (char *)pFieldType + offsetof(lfFieldList, data);
|
||
|
i < pEnumType->count;
|
||
|
i++, pEnumerate += skip)
|
||
|
{
|
||
|
DASSERT(*((unsigned short *)pEnumerate) == LF_ENUMERATE);
|
||
|
skip = offsetof (lfEnumerate, value);
|
||
|
if (EVAL_UQUAD(pv) == RNumLeaf ((char *)(&(((plfEnumerate)pEnumerate)->value)), &skip)) {
|
||
|
_tcsncpy(buf, pEnumerate + skip + 1, min(buflen, *(pEnumerate + skip)));
|
||
|
goto Exit;
|
||
|
}
|
||
|
skip += *(pEnumerate + skip) + 1; //skip name field
|
||
|
skip += SkipPad((uchar *)pEnumerate + skip);
|
||
|
}
|
||
|
|
||
|
NoDisplay:
|
||
|
retval = EEGENERAL;
|
||
|
pExState->err_num = ERR_INVENUMVAL;
|
||
|
|
||
|
Exit:
|
||
|
MHOmfUnLock (hType);
|
||
|
MHOmfUnLock (hFieldType);
|
||
|
return(retval);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL GetRawAddr( peval_t pv, ADDR *paddr )
|
||
|
{
|
||
|
if (EVAL_IS_ADDR(pv))
|
||
|
{
|
||
|
BOOL bCast;
|
||
|
Evaluating = TRUE;
|
||
|
bCast = CastNode (pv, T_32PCHAR, T_32PCHAR);
|
||
|
Evaluating = FALSE;
|
||
|
|
||
|
if (!bCast) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*paddr = EVAL_PTR(pv);
|
||
|
}
|
||
|
else if (EVAL_IS_PTR(pv)) {
|
||
|
*paddr = EVAL_PTR(pv);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ResolveAddr(pv);
|
||
|
*paddr = EVAL_SYM(pv);
|
||
|
}
|
||
|
|
||
|
if (ADDR_IS_LI (*paddr)) {
|
||
|
SHFixupAddr (paddr);
|
||
|
}
|
||
|
|
||
|
if (EVAL_IS_PTR (pv) && (EVAL_IS_NPTR (pv) || EVAL_IS_NPTR32 (pv))) {
|
||
|
paddr->addr.seg = GetSegmentRegister(pExState->hframe, REG_DS);
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*
|
||
|
* EvalString
|
||
|
|
||
|
* Evaluate an expression whose format string contains an 's'.
|
||
|
*/
|
||
|
|
||
|
void EvalString (peval_t pv, char *FAR *buf,
|
||
|
int *buflen, bool_t fUnicode)
|
||
|
{
|
||
|
ADDR addr;
|
||
|
int count;
|
||
|
|
||
|
if(*buflen < 3) return;
|
||
|
**buf = '\"';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
addr = EVAL_PTR (pv);
|
||
|
if (ADDR_IS_LI (addr)) {
|
||
|
SHFixupAddr (&addr);
|
||
|
}
|
||
|
if (EVAL_IS_PTR (pv) && (EVAL_IS_NPTR (pv) || EVAL_IS_NPTR32 (pv))) {
|
||
|
addr.addr.seg = GetSegmentRegister(pExState->hframe, REG_DS);
|
||
|
}
|
||
|
count = GetDebuggeeBytes (addr, *buflen - 2, *buf, T_RCHAR);
|
||
|
|
||
|
if (fUnicode) {
|
||
|
// Convert unicode characters to MBCS, so that
|
||
|
// we can display them using the existing non-Unicode
|
||
|
// formatting routines
|
||
|
int cb;
|
||
|
wchar_t UNALIGNED *pwch = (wchar_t UNALIGNED *)*buf;
|
||
|
|
||
|
while (count >= sizeof (wchar_t) && *pwch != 0 ) {
|
||
|
cb = ConvertWCToMB (*buf, *pwch);
|
||
|
(*buflen) -= cb;
|
||
|
*buf += cb;
|
||
|
pwch ++;
|
||
|
count -= sizeof (wchar_t);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
while ((**buf != 0) && (count > 0)) {
|
||
|
int clen = _tclen (*buf);
|
||
|
(*buflen) -= clen;
|
||
|
*buf = _tcsinc (*buf);
|
||
|
count -= clen;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
**buf = '\"';
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
**buf = 0;
|
||
|
(*buf)++;
|
||
|
(*buflen)--;
|
||
|
}
|
||
|
/*
|
||
|
* Use IsPrint instead of the runtime function isprint,
|
||
|
* since the latter is not exported to the EE
|
||
|
*/
|
||
|
INLINE bool_t IsPrint (int ch)
|
||
|
{
|
||
|
return (ch >= 0x20) && (ch <= 0x7e) ? TRUE : FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* EvalMem
|
||
|
|
||
|
* Evaluate an expression whose format string contains an 'm'.
|
||
|
* The format is similar to the memory window of codeview :
|
||
|
|
||
|
* ,m or ,mb (memory -byte display)
|
||
|
* SSSS:OOOO xx xx xx xx ... xx aaaa...a
|
||
|
|
||
|
* ,mw (memory -word display)
|
||
|
* SSSS:OOOO xxxx ... xxxx
|
||
|
|
||
|
* ,md (memory -dword display)
|
||
|
* SSSS:OOOO xxxxxxxx ... xxxxxxxx
|
||
|
|
||
|
* ,mq (memory -qword display)
|
||
|
* SSSS:OOOO xxxxxxxxxxxxxxxx ... xxxxxxxxxxxxxxxx
|
||
|
|
||
|
* ,ma (memory -ascii display)
|
||
|
* SSSS:OOOO aaa...a
|
||
|
|
||
|
* where SSSS:OOOO is the address, xx is dump info in hex,
|
||
|
* and a is an ascii char. (If the address is a 32-bit
|
||
|
* address, we will emit "OOOOOOOO" instead of "SSSS:OOOO".)
|
||
|
|
||
|
*/
|
||
|
#define MCOUNT 16 /* number of bytes to read */
|
||
|
#define MCOUNTA 64 /* number of bytes to read for ,ma display */
|
||
|
#define MINLBUFSZ 64 /* minimum local buf size for byte transfer */
|
||
|
#define MINBUFSZ 256 /* minimum buf size for display */
|
||
|
|
||
|
void EvalMem (peval_t pv, char *FAR *buf, int *buflen, char postfix)
|
||
|
{
|
||
|
ADDR addr;
|
||
|
int count;
|
||
|
char tempbuf[MINBUFSZ];
|
||
|
uchar localbuf[MINLBUFSZ];
|
||
|
int cnt = 0;
|
||
|
int nItems;
|
||
|
int nBytes;
|
||
|
int i;
|
||
|
char *pFmt;
|
||
|
uint fHexUpper = 0;
|
||
|
bool_t fDisplayString = FALSE;
|
||
|
|
||
|
fHexUpper = !!fHexUpper; // canonicalize
|
||
|
|
||
|
addr = EVAL_PTR (pv);
|
||
|
if (ADDR_IS_LI (addr)) {
|
||
|
SHFixupAddr (&addr);
|
||
|
}
|
||
|
if (EVAL_IS_PTR (pv) && (EVAL_IS_NPTR (pv) || EVAL_IS_NPTR32 (pv))) {
|
||
|
addr.addr.seg = GetSegmentRegister(pExState->hframe, REG_DS);
|
||
|
}
|
||
|
|
||
|
if (ADDR_IS_FLAT(addr)) {
|
||
|
DASSERT ( ADDR_IS_OFF32 ( addr ) );
|
||
|
cnt = sprintf(tempbuf, fmt_ptr_0_32[fHexUpper],
|
||
|
(CV_uoff32_t)GetAddrOff (addr));
|
||
|
}
|
||
|
else {
|
||
|
if ( ADDR_IS_OFF32 ( addr ) ) {
|
||
|
cnt = sprintf(tempbuf, fmt_ptr_16_32[fHexUpper],
|
||
|
GetAddrSeg (addr), (CV_uoff32_t)GetAddrOff (addr));
|
||
|
}
|
||
|
else {
|
||
|
cnt = sprintf(tempbuf, fmt_ptr_16_16[fHexUpper],
|
||
|
GetAddrSeg (addr), (CV_uoff16_t)GetAddrOff (addr));
|
||
|
}
|
||
|
}
|
||
|
tempbuf[cnt++] = ' ';
|
||
|
tempbuf[cnt++] = ' ';
|
||
|
|
||
|
nBytes = (postfix == 'a' ? MCOUNTA : MCOUNT);
|
||
|
|
||
|
count = GetDebuggeeBytes (addr, nBytes, (char *)localbuf, T_RCHAR);
|
||
|
|
||
|
nItems = nBytes; //assume ,m ,mb or ,ma display
|
||
|
|
||
|
switch (postfix) {
|
||
|
case 'b':
|
||
|
if (fHexUpper) {
|
||
|
pFmt = "%02X ";
|
||
|
}
|
||
|
else {
|
||
|
pFmt = "%02x ";
|
||
|
}
|
||
|
for (i=0; i<nItems; i++) {
|
||
|
cnt += i<count
|
||
|
? sprintf (tempbuf+cnt, pFmt, (unsigned int)localbuf[i])
|
||
|
: sprintf (tempbuf+cnt, "?? ");
|
||
|
}
|
||
|
|
||
|
tempbuf[cnt++] = ' ';
|
||
|
// fall through
|
||
|
|
||
|
case 'a':
|
||
|
fDisplayString = TRUE;
|
||
|
break;
|
||
|
|
||
|
case 'w':
|
||
|
case 'u':
|
||
|
nItems = nBytes >> 1;
|
||
|
count >>= 1;
|
||
|
if (fHexUpper) {
|
||
|
pFmt = "%04hX ";
|
||
|
}
|
||
|
else {
|
||
|
pFmt = "%04hx ";
|
||
|
}
|
||
|
for (i=0; i<nItems; i++) {
|
||
|
cnt += i<count
|
||
|
? sprintf (tempbuf+cnt, pFmt, *((unsigned short UNALIGNED *)localbuf+i))
|
||
|
: sprintf (tempbuf+cnt, "???? ");
|
||
|
}
|
||
|
if ('u' == postfix) {
|
||
|
char *pch;
|
||
|
int i;
|
||
|
|
||
|
// Low budget unicode display: convert unicode
|
||
|
// string to MBCS and use existing display code
|
||
|
// In-place conversion should be OK, since the
|
||
|
// translated character is at most two bytes long
|
||
|
tempbuf[cnt++] = ' ';
|
||
|
fDisplayString = TRUE;
|
||
|
pch = (char *) localbuf;
|
||
|
for (i=0; i<nItems; i++) {
|
||
|
pch += ConvertWCToMB (pch, ((wchar_t *)localbuf)[i]);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'd':
|
||
|
nItems = nBytes >> 2;
|
||
|
count >>= 2;
|
||
|
if (fHexUpper) {
|
||
|
pFmt = "%08lX ";
|
||
|
}
|
||
|
else {
|
||
|
pFmt = "%08lx ";
|
||
|
}
|
||
|
for (i=0; i<nItems; i++) {
|
||
|
cnt += i<count
|
||
|
? sprintf (tempbuf+cnt, pFmt, *((unsigned long UNALIGNED *)localbuf+i))
|
||
|
: sprintf (tempbuf+cnt, "???????? ");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case 'q':
|
||
|
nItems = nBytes >> 3;
|
||
|
count >>= 3;
|
||
|
if (fHexUpper) {
|
||
|
pFmt = "%016I64X ";
|
||
|
}
|
||
|
else {
|
||
|
pFmt = "%016I64x ";
|
||
|
}
|
||
|
for (i=0; i<nItems; i++) {
|
||
|
cnt += i<count
|
||
|
? sprintf (tempbuf+cnt, pFmt, *((unsigned __int64 UNALIGNED *)localbuf+i))
|
||
|
: sprintf (tempbuf+cnt, "???????? ");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (fDisplayString) {
|
||
|
#ifndef _SBCS
|
||
|
for (i=0; i<nItems; i++) {
|
||
|
if( i<count ) {
|
||
|
if ( _ismbblead( localbuf[i] ) ) {
|
||
|
if ( i+1<count && _ismbbtrail( localbuf[ i+1 ] ) ) {
|
||
|
tempbuf[cnt++] = localbuf[ i++ ];
|
||
|
tempbuf[cnt++] = localbuf[ i ];
|
||
|
}
|
||
|
else {
|
||
|
tempbuf[cnt++] = '.';
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
else if ( _ismbbkana( localbuf[ i ] ) ||
|
||
|
IsPrint( localbuf[ i ] ) ) {
|
||
|
|
||
|
tempbuf[cnt++] = localbuf[ i ];
|
||
|
}
|
||
|
else {
|
||
|
tempbuf[cnt++] = '.';
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
tempbuf[cnt++] = '?';
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
for (i=0; i<nItems; i++) {
|
||
|
if ( i<count ) {
|
||
|
if ( IsPrint(localbuf[i]) ) {
|
||
|
tempbuf[cnt++] = localbuf[i];
|
||
|
}
|
||
|
else {
|
||
|
tempbuf[cnt++] = '.';
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
tempbuf[cnt++] = '?';
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// If the size of the buffer is less than the display string,
|
||
|
// clip the formatted memory string but copy what we can
|
||
|
if ( *buflen - 1 < cnt ) {
|
||
|
cnt = *buflen - 1;
|
||
|
}
|
||
|
|
||
|
tempbuf[cnt] = '\0';
|
||
|
_tcsncpy (*buf, tempbuf, cnt + 1);
|
||
|
*buf += cnt;
|
||
|
*buflen -= cnt;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* ConvertWCToMB - convert wide char to multi-byte
|
||
|
*/
|
||
|
|
||
|
int ConvertWCToMB (char *pchmb, wchar_t wch)
|
||
|
{
|
||
|
int cb;
|
||
|
if ((cb = wctomb (pchmb, wch)) < 0) {
|
||
|
// no conversion was possible,
|
||
|
// use a default character
|
||
|
*pchmb = '?';
|
||
|
cb = 1;
|
||
|
}
|
||
|
else if (cb == 0) {
|
||
|
// converting L'\0'
|
||
|
*pchmb = '\0';
|
||
|
cb = 1;
|
||
|
}
|
||
|
return cb;
|
||
|
}
|
||
|
|
||
|
// undecorate a symbol, currently only does @ILT symbols (for vtable entries)
|
||
|
// turns @ILT+nnn(?mangledname) into unmangled name
|
||
|
// and simply mangled ones
|
||
|
|
||
|
char *
|
||
|
FormatUndecorate (
|
||
|
char *pc,
|
||
|
char *newstr
|
||
|
)
|
||
|
{
|
||
|
size_t oLen;
|
||
|
char *pOpen;
|
||
|
char *pClose;
|
||
|
char undname[256];
|
||
|
char *pResult;
|
||
|
|
||
|
newstr++; // leave room for length byte
|
||
|
|
||
|
// make null-terminated version in user buffer
|
||
|
oLen = *(uchar*)pc;
|
||
|
memcpy( newstr, pc+1, oLen );
|
||
|
newstr[oLen] = 0;
|
||
|
|
||
|
if (pc[1]=='?')
|
||
|
{
|
||
|
// simple mangled name starts with "?"
|
||
|
pResult = __unDName( undname, newstr, sizeof(undname), malloc, free, UNDNAME_NAME_ONLY );
|
||
|
}
|
||
|
else if ( (pc[0]>5) && (memcmp(pc+1, "@ILT", 4)==0))
|
||
|
{
|
||
|
// "@ILT+nnn(?mangled)"
|
||
|
pOpen = _tcschr(newstr, '(' );
|
||
|
if (!pOpen) {
|
||
|
return pc;
|
||
|
}
|
||
|
pClose = _tcschr(pOpen+1, ')' );
|
||
|
if (!pClose) {
|
||
|
return pc;
|
||
|
}
|
||
|
*pClose = 0;
|
||
|
|
||
|
pResult = __unDName( undname, pOpen+1, sizeof(undname), malloc, free, UNDNAME_NAME_ONLY );
|
||
|
}
|
||
|
else {
|
||
|
return pc;
|
||
|
}
|
||
|
|
||
|
if (!pResult) {
|
||
|
return pc; // if failed return original
|
||
|
}
|
||
|
|
||
|
// undecorated OK, so convert
|
||
|
_tcscpy( newstr, undname );
|
||
|
|
||
|
newstr--;
|
||
|
newstr[0] = (uchar)_tcslen(newstr+1); // set length field
|
||
|
return newstr;
|
||
|
}
|
||
|
|
||
|
char *
|
||
|
FormatVirtual (
|
||
|
char *pc,
|
||
|
peval_t pv,
|
||
|
PEEHSTR phStr
|
||
|
)
|
||
|
{
|
||
|
char save;
|
||
|
char *pEnd;
|
||
|
char *bufsave;
|
||
|
char *buf;
|
||
|
uint buflen;
|
||
|
PHDR_TYPE pHdr;
|
||
|
char *pName;
|
||
|
|
||
|
if ((*phStr = MemAllocate (TYPESTRMAX + sizeof (HDR_TYPE))) == 0) {
|
||
|
// unable to allocate memory for type string. at least print name
|
||
|
return (pc);
|
||
|
}
|
||
|
bufsave = (char *)MemLock (*phStr);
|
||
|
memset (bufsave, 0, TYPESTRMAX + sizeof (HDR_TYPE));
|
||
|
buflen = TYPESTRMAX - 1;
|
||
|
pHdr = (PHDR_TYPE)bufsave;
|
||
|
buf = bufsave + sizeof (HDR_TYPE);
|
||
|
pCxt = &pExState->cxt;
|
||
|
bnCxt = 0;
|
||
|
pEnd = pc + *pc + 1;
|
||
|
save = *pEnd;
|
||
|
*pEnd = 0;
|
||
|
pName = pc + 1;
|
||
|
FormatType (pv, &buf, &buflen, &pName, 1L, pHdr);
|
||
|
*pEnd = save;
|
||
|
*(bufsave + sizeof (HDR_TYPE) - 1) = TYPESTRMAX - 1 - buflen;
|
||
|
return (bufsave + sizeof (HDR_TYPE) - 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** DoAutoExpand - Prepare TM for auto expansion
|
||
|
|
||
|
* void DoAutoExpand (phTM)
|
||
|
|
||
|
* Entry phTM = pointer to handle of parent TM
|
||
|
|
||
|
* Exit Creates auto-expanded TM list and stores it
|
||
|
* in the parent TM.
|
||
|
|
||
|
* Returns void
|
||
|
*/
|
||
|
|
||
|
|
||
|
void FASTCALL DoAutoExpand (PHTM phTM)
|
||
|
{
|
||
|
static char bufRule [256];
|
||
|
static char bufDeriv [256];
|
||
|
eval_t Eval;
|
||
|
peval_t pv = &Eval;
|
||
|
bool_t fNewDownCast = FALSE;
|
||
|
bool_t fNewRule;
|
||
|
bool_t fAErebind;
|
||
|
bool_t fAEreeval;
|
||
|
|
||
|
DASSERT (phTM && *phTM);
|
||
|
|
||
|
pExState = (pexstate_t) MemLock (*phTM);
|
||
|
fAErebind = pExState->state.fAErebind;
|
||
|
fAEreeval = pExState->state.fAEreeval;
|
||
|
|
||
|
if (fAErebind || fAEreeval) {
|
||
|
// Auto-expand rule and down-cast info need to be updated.
|
||
|
// The auto-expand list has not been bound (or evaluated)
|
||
|
// since the last time this TM was bound (or evaluated)
|
||
|
|
||
|
pCxt = &pExState->cxt;
|
||
|
*pv = pExState->result;
|
||
|
|
||
|
// if we don't have a class or a pointer to a class,
|
||
|
// no autoexpansion is performed
|
||
|
if (EVAL_IS_PTR (pv) && !SetNodeType(pv, PTR_UTYPE(pv)) ||
|
||
|
!EVAL_IS_CLASS (pv)) {
|
||
|
EEFreeTML (&pExState->TMLAutoExpand);
|
||
|
MemFree (pExState->hAutoExpandRule);
|
||
|
pExState->hAutoExpandRule = 0;
|
||
|
pExState->state.fAErebind = FALSE;
|
||
|
pExState->state.fAEreeval = FALSE;
|
||
|
MemUnLock (*phTM);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Get the expansion rule associated with the derived-most class, if any
|
||
|
if (EVAL_IS_PTR (&pExState->result) &&
|
||
|
!EVAL_IS_REF (&pExState->result)) {
|
||
|
*bufDeriv = 0;
|
||
|
GetDerivClassName (&pExState->result, TRUE, bufDeriv, sizeof(bufDeriv));
|
||
|
fNewDownCast = UpdateEEHSTR (&pExState->hDClassName, bufDeriv);
|
||
|
|
||
|
if (*bufDeriv) {
|
||
|
FMT_state fmtstate;
|
||
|
uint radix = pExState->radix;
|
||
|
SHFLAG fCase = pExState->state.fCase;
|
||
|
PCXT pBindCxt = &pExState->cxt;
|
||
|
ulong end;
|
||
|
HTM hTMOut;
|
||
|
// bufDeriv contains a derived-most class name prepended
|
||
|
// by a context operator.
|
||
|
// Parse and Bind in order to get the corresponding
|
||
|
// evaluation node
|
||
|
SaveFmtState (&fmtstate);
|
||
|
if (EENOERROR == Parse (bufDeriv, radix, fCase, FALSE, &hTMOut, &end) &&
|
||
|
EENOERROR == DoBind (&hTMOut, pBindCxt, BIND_fSupOvlOps) ) {
|
||
|
pExState = (pexstate_t) MemLock (hTMOut);
|
||
|
*pv = pExState->result;
|
||
|
MemUnLock (hTMOut);
|
||
|
}
|
||
|
if (hTMOut)
|
||
|
EEFreeTM (&hTMOut);
|
||
|
RestoreFmtState (&fmtstate);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// pv should now contain the class for which we need to find
|
||
|
// an auto expansion rule
|
||
|
|
||
|
*bufRule = 0;
|
||
|
FindAERule (pv, bufRule, sizeof(bufRule));
|
||
|
|
||
|
fNewRule = UpdateEEHSTR (&pExState->hAutoExpandRule, bufRule);
|
||
|
|
||
|
if (fNewDownCast || fNewRule) {
|
||
|
// AutoExpand TMList should be rebound
|
||
|
pExState->state.fAErebind = TRUE;
|
||
|
pExState->state.fAEreeval = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
MemUnLock (*phTM);
|
||
|
|
||
|
if (fAErebind) {
|
||
|
// should apply new rule, so we'll have to
|
||
|
// reconstruct and rebind child TMs
|
||
|
DoBindAutoExpand (phTM);
|
||
|
}
|
||
|
|
||
|
if (fAEreeval) {
|
||
|
DoEvalAutoExpand (phTM);
|
||
|
}
|
||
|
|
||
|
pExState = (pexstate_t) MemLock (*phTM);
|
||
|
pExState->state.fAErebind = FALSE;
|
||
|
pExState->state.fAEreeval = FALSE;
|
||
|
MemUnLock (*phTM);
|
||
|
}
|
||
|
|
||
|
/*** SaveFmtState - Save Format state
|
||
|
|
||
|
* Saves global variables used by Format
|
||
|
*/
|
||
|
|
||
|
void FASTCALL SaveFmtState (FMT_state *pfmtstate)
|
||
|
{
|
||
|
pfmtstate->pExState = pExState;
|
||
|
pfmtstate->pExStr = pExStr;
|
||
|
pfmtstate->pCxt = pCxt;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** RestoreFmtState - Restore Format state
|
||
|
|
||
|
* Restores global variables used by Format
|
||
|
*/
|
||
|
|
||
|
void FASTCALL RestoreFmtState (FMT_state *pfmtstate)
|
||
|
{
|
||
|
pExState = pfmtstate->pExState;
|
||
|
pExStr = pfmtstate->pExStr;
|
||
|
pCxt = pfmtstate->pCxt;
|
||
|
}
|
||
|
|
||
|
/*** DoBindAutoExpand - Construct and bind auto-expanded child-TMs
|
||
|
|
||
|
* error = DoBindAutoExpand (phTM)
|
||
|
|
||
|
* Entry phTM = ptr to handle of parent TM
|
||
|
|
||
|
* Exit Auto-expand TM list created and bound
|
||
|
|
||
|
* Returns void
|
||
|
*/
|
||
|
|
||
|
void FASTCALL DoBindAutoExpand (PHTM phTM)
|
||
|
{
|
||
|
pexstate_t pTM;
|
||
|
LSZ lsz;
|
||
|
char *pcLDelim;
|
||
|
char *pcRDelim;
|
||
|
HTM hTMChild;
|
||
|
|
||
|
pTM = (pexstate_t) MemLock (*phTM);
|
||
|
EEFreeTML (&pTM->TMLAutoExpand);
|
||
|
MemUnLock (*phTM);
|
||
|
|
||
|
if (pTM->hAutoExpandRule) {
|
||
|
lsz = (LSZ) MemLock (pTM->hAutoExpandRule);
|
||
|
while ( (pcLDelim = _tcschr (lsz, _T ('<'))) != NULL &&
|
||
|
(pcRDelim = _tcschr (pcLDelim, _T('>'))) != NULL ) {
|
||
|
|
||
|
// If the '>' we found is actually a '->' skip over this
|
||
|
// and look for the next one.
|
||
|
while (pcRDelim && *(pcRDelim - 1) == '-' )
|
||
|
{
|
||
|
pcRDelim = _tcschr(pcRDelim + 1, _T('>'));
|
||
|
}
|
||
|
|
||
|
if (pcRDelim == NULL)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
hTMChild = 0;
|
||
|
lsz = pcLDelim + 1;
|
||
|
*pcRDelim = '\0';
|
||
|
switch (AEParseRule(lsz)) {
|
||
|
case AE_childTM:
|
||
|
GetDerivedTM (*phTM, lsz, &hTMChild);
|
||
|
pTM = (pexstate_t) MemLock (*phTM);
|
||
|
// hTMchild may be NULL, but we still need to add it to
|
||
|
// the list in order to keep in sync with the "<>" pairs
|
||
|
// in the expansion rule
|
||
|
TMLAddHTM ( &pTM->TMLAutoExpand, hTMChild );
|
||
|
MemUnLock (*phTM);
|
||
|
break;
|
||
|
case AE_downcasttype:
|
||
|
// do nothing, we'll just print the class name
|
||
|
// during formatting
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*(lsz = pcRDelim) = _T('>');
|
||
|
}
|
||
|
MemUnLock (pTM->hAutoExpandRule);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*** DoEvalAutoExpand - Evaluate auto-expanded child TM list
|
||
|
|
||
|
* error = DoEvalAutoExpand (phTM)
|
||
|
|
||
|
* Entry phTM = ptr to handle of parent TM
|
||
|
|
||
|
* Exit Auto-expand TM list is evaluated
|
||
|
|
||
|
* Returns void
|
||
|
*/
|
||
|
|
||
|
void FASTCALL DoEvalAutoExpand (PHTM phTM)
|
||
|
{
|
||
|
HTM *rgHTM;
|
||
|
pexstate_t pTM;
|
||
|
PTML pTML;
|
||
|
uint i;
|
||
|
|
||
|
// try to evaluate auto-expand child TMs
|
||
|
pTM = (pexstate_t) MemLock (*phTM);
|
||
|
pTML = &pTM->TMLAutoExpand;
|
||
|
rgHTM = (HTM *)MemLock (pTML->hTMList);
|
||
|
for (i=0; i<pTML->cTMListAct; i++) {
|
||
|
if (rgHTM[i])
|
||
|
DoEval (&rgHTM[i], pTM->hframe, (EEDSP) pTM->style);
|
||
|
}
|
||
|
MemUnLock (pTML->hTMList);
|
||
|
MemUnLock (*phTM);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** UpdateEEHSTR - Update EE String
|
||
|
|
||
|
* flag = UpdateEEHSTR(phStr, lszNew)
|
||
|
|
||
|
* Entry phStr = pointer to handle of EE String to be updated
|
||
|
* lszNew = Null-terminated string
|
||
|
|
||
|
* Exit The contents of EE string are replaced with lszNew
|
||
|
|
||
|
* Returns TRUE if the contents of the EE string have changed
|
||
|
* FALSE otherwise
|
||
|
*/
|
||
|
|
||
|
bool_t FASTCALL UpdateEEHSTR(EEHSTR *phStr, LSZ lszNew)
|
||
|
{
|
||
|
EEHSTR hNew;
|
||
|
uint lenNew;
|
||
|
LSZ lsz;
|
||
|
|
||
|
lenNew = _tcslen (lszNew) + 1;
|
||
|
if (*lszNew) {
|
||
|
if (*phStr) {
|
||
|
// new string is non-NULL, old string is non-NULL
|
||
|
lsz = (LSZ) MemLock (*phStr);
|
||
|
if (!_tcscmp(lsz, lszNew)) {
|
||
|
// strings are the same, no update necessary
|
||
|
MemUnLock (*phStr);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else {
|
||
|
MemUnLock (*phStr);
|
||
|
if ((hNew = MemReAlloc (*phStr, lenNew)) == 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if ((hNew = MemAllocate (lenNew)) == 0) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
// copy new string over the old string
|
||
|
lsz = (LSZ) MemLock (hNew);
|
||
|
_tcscpy (lsz, lszNew);
|
||
|
MemUnLock (hNew);
|
||
|
*phStr = hNew;
|
||
|
return TRUE;
|
||
|
}
|
||
|
else if (*phStr) {
|
||
|
// new string is NULL, old string is non-NULL
|
||
|
// Free old string
|
||
|
MemFree (*phStr);
|
||
|
*phStr = 0;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// both strings are NULL, no update
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*** FindAERule - Find Auto Expansion rule
|
||
|
|
||
|
* flag = FindAERule (pvP, buf, cchbuf)
|
||
|
|
||
|
* Entry pvP = pointer to the evaluation node containing the
|
||
|
* result of the expression that is auto-expanded
|
||
|
* buf = buffer to hold the auto-expansion rule
|
||
|
* cchbuf = max buffer size
|
||
|
|
||
|
* Exit if an auto-expansion rule is found for pvP it is loaded
|
||
|
* into buf.
|
||
|
* Otherwise the class hierarchy is searched in order to
|
||
|
* locate the nearest base class for which an auto-expansion
|
||
|
* rule exists
|
||
|
|
||
|
* Returns TRUE if an auto-expansion rule was found
|
||
|
* FALSE otherwise
|
||
|
*/
|
||
|
|
||
|
bool_t FASTCALL FindAERule (peval_t pvP, LSZ buf, uint cchbuf)
|
||
|
{
|
||
|
search_t Name;
|
||
|
psearch_t pName = &Name;
|
||
|
eval_t Eval;
|
||
|
peval_t pv = &Eval;
|
||
|
LSZ lsz;
|
||
|
CV_typ_t typ = EVAL_TYP (pvP);
|
||
|
HMOD hMod = EVAL_MOD (pvP);
|
||
|
bool_t retval = FALSE;
|
||
|
HEXE hExe = SHHexeFromHmod(hMod);
|
||
|
|
||
|
if (LookupAECache (typ, SHHexeFromHmod(hMod), buf)) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
// will have to search for the rule based on
|
||
|
// the type name
|
||
|
lsz = GetTypeName (typ, hMod);
|
||
|
if (LoadAERule (lsz, buf, cchbuf)) {
|
||
|
retval = TRUE;
|
||
|
}
|
||
|
else {
|
||
|
BOOL fSupBaseSaved = pExState->state.fSupBase;
|
||
|
pExState->state.fSupBase = FALSE;
|
||
|
|
||
|
InitSearchAErule (pName, pv, EVAL_TYP (pvP), EVAL_MOD (pvP));
|
||
|
if (HR_found == SearchSym (pName)) {
|
||
|
PopStack();
|
||
|
lsz = GetTypeName (EVAL_TYP (pv), EVAL_MOD (pv));
|
||
|
retval = LoadAERule (lsz, buf, cchbuf);
|
||
|
}
|
||
|
|
||
|
pExState->state.fSupBase = fSupBaseSaved;
|
||
|
}
|
||
|
|
||
|
InsertAECache (typ, hExe, buf);
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Interface for accessing the auto-expansion rule cache
|
||
|
|
||
|
* void InsertAECache (type, hExe, buf)
|
||
|
* inserts the rule containd in buf into the cache and associates
|
||
|
* it with type "type" defined in executable "hExe"
|
||
|
|
||
|
* void ReorderCache (i)
|
||
|
* brings entry i to the top (helper routine for implementing
|
||
|
* LRU scheme)
|
||
|
|
||
|
* flag = LookupAECache (type, hExe, buf)
|
||
|
* looks-up the rule associated with type "type" defined in "hExe"
|
||
|
* and loads it in buffer buf
|
||
|
* It is assumed that buf is sufficiently large to hold the string
|
||
|
*/
|
||
|
|
||
|
|
||
|
void FASTCALL InsertAECache (CV_typ_t type, HEXE hExe, char far *buf)
|
||
|
{
|
||
|
int i;
|
||
|
EEHSTR hStr;
|
||
|
LSZ lsz;
|
||
|
|
||
|
if ((hStr = MemAllocate (_tcslen (buf) + 1)) != NULL) {
|
||
|
lsz = (LSZ) MemLock (hStr);
|
||
|
_tcscpy (lsz, buf);
|
||
|
MemUnLock ((HDEP)lsz);
|
||
|
|
||
|
if (cAECache == AECACHE_MAX) {
|
||
|
if (AECache[AECACHE_MAX - 1].hStr)
|
||
|
MemFree (AECache[AECACHE_MAX - 1].hStr);
|
||
|
cAECache--;
|
||
|
}
|
||
|
|
||
|
for (i = cAECache; i > 0; i--) {
|
||
|
AECache[i] = AECache[i - 1];
|
||
|
}
|
||
|
AECache[0].typ = type;
|
||
|
AECache[0].hExe = hExe;
|
||
|
AECache[0].hStr = hStr;
|
||
|
cAECache++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void FASTCALL ReorderAECache (int iAECache)
|
||
|
{
|
||
|
aecache_t temp;
|
||
|
int i;
|
||
|
|
||
|
if (iAECache == 0) {
|
||
|
return;
|
||
|
}
|
||
|
temp = AECache[iAECache];
|
||
|
for (i = iAECache; i > 0; i--) {
|
||
|
AECache[i] = AECache[i - 1];
|
||
|
}
|
||
|
AECache[0] = temp;
|
||
|
}
|
||
|
|
||
|
bool_t FASTCALL LookupAECache (CV_typ_t typ, HEXE hExe, char *buf)
|
||
|
{
|
||
|
int i;
|
||
|
LSZ lsz;
|
||
|
bool_t retval = FALSE;
|
||
|
|
||
|
for (i=0; i<cAECache; i++) {
|
||
|
if (typ == AECache[i].typ && hExe == AECache[i].hExe) {
|
||
|
lsz = (LSZ) MemLock (AECache[i].hStr);
|
||
|
_tcscpy (buf, lsz);
|
||
|
MemUnLock (AECache[i].hStr);
|
||
|
ReorderAECache (i);
|
||
|
retval = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUGVER
|
||
|
{
|
||
|
static int hit = 0;
|
||
|
static int miss = 0;
|
||
|
if (retval == TRUE)
|
||
|
hit ++;
|
||
|
else
|
||
|
miss ++;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return retval;
|
||
|
}
|