Windows2000/private/windbg64/windbg/cp.c

2524 lines
60 KiB
C
Raw Permalink Normal View History

2001-01-01 00:00:00 +01:00
/*** cp.c -- Command Parsing Subsystem API
Copyright <C> 1990, Microsoft Corporation
Purpose:
*/
#include "precomp.h"
#pragma hdrstop
#include <mathsup.h>
#include <rtlproto.h>
#include <ntsdsup.h>
#include <ntsdtok.h>
#define MAXNESTING (50)
static char rgchOpenQuote[] = {'\"', '\'', '(', '{', '['};
static char rgchCloseQuote[] = {'\"', '\'', ')', '}', ']'};
#define MAXQUOTE (sizeof(rgchOpenQuote) / sizeof(rgchOpenQuote[0]))
static char rgchDelim[] = { ' ', '\t', ',' };
#define MAXDELIM (sizeof(rgchDelim) / sizeof(rgchDelim[0]))
extern LPSHF Lpshf;
CPSTATUS
CPStatus(
EESTATUS ee
)
{
switch(ee) {
case EENOERROR: return CPNOERROR;
case EENOMEMORY: return CPNOMEMORY;
case EEGENERAL: return CPGENERAL;
case EEBADADDR: return CPBADADDR;
case EECATASTROPHIC: return CPCATASTROPHIC;
default: return CPGENERAL;
}
}
CPSTATUS
CPStatusNtsd(
ULONG Status
)
{
switch(Status) {
case 0: return CPNOERROR;
case ERR_OVERFLOW:
case ERR_SYNTAX:
case ERR_BADRANGE:
case ERR_VARDEF:
case ERR_EXTRACHARS:
case ERR_LISTSIZE:
case ERR_STRINGSIZE:
case ERR_MEMORY:
case ERR_BADREG:
case ERR_BADOPCODE:
case ERR_SUFFIX:
case ERR_OPERAND:
case ERR_ALIGNMENT:
case ERR_PREFIX:
case ERR_DISPLACEMENT:
case ERR_BPLISTFULL:
case ERR_BPDUPLICATE:
case ERR_BADTHREAD:
case ERR_DIVIDE:
case ERR_TOOFEW:
case ERR_TOOMANY:
case ERR_SIZE:
case ERR_BADSEG:
case ERR_RELOC:
case ERR_BADPROCESS:
case ERR_AMBIGUOUS:
case ERR_FILEREAD:
case ERR_LINENUMBER:
case ERR_BADSEL:
case ERR_SYMTOOSMALL:
case ERR_BPIONOTSUP:
return CPGENERAL;
default: return CPGENERAL;
}
}
char *
CPSzToken (
LPSTR *lplpSrc,
LPSTR buf OPTIONAL
)
/*++
Routine Description:
Parse a token from a string.
The scan will be terminated by a delimiter character or the end of the
input string. Delimiter characters will be ignored when in a quoted
segment. Quotes will always be preserved.
Arguments:
lplpSrc - Supplies and returns a pointer to a pointer to the source string
buf - Optionally supplies a buffer to receive the scanned token.
Return Value:
The beginning of the token, or NULL if an error occurs.
lplpSrc will point to the last character not consumed in the string.
This is not necessarily the same as the beginning of the next token.
If an error occurs, lplpSrc will point to the place where the scanner
stopped.
If a buffer is supplied, the token will be copied to the supplied buffer,
and the address of the buffer will be returned. If not, the delimiter
which terminated the scan will be replaced by a NUL character, and a pointer
to the beginning of the token in the source string will be returned.
--*/
{
char *lpSrc;
char *lpToken;
int CharType;
int QSP;
int QuoteStack[MAXNESTING];
int QuoteIndex;
enum {
Consume,
Error,
Done
} State;
lpSrc = *lplpSrc;
if (!lpSrc) {
return NULL;
}
// Skip whitespace
lpToken =
lpSrc = CPSkipWhitespace(lpSrc);
// Scan until a delimiter is found in unquoted space.
State = Consume;
QSP = 0;
while (*lpSrc && State == Consume) {
CharType = CPQueryChar(lpSrc, "");
switch (CharType) {
default:
// consume it.
break;
case CPISDELIM:
// if stack is empty, finish
// otherwise, just consume it.
if (QSP == 0) {
State = Done;
}
break;
case CPISOPENANDCLOSEQUOTE:
// got a ' or a "
// If it matches the last quote, pop it.
// If it doesn't match, push it.
QuoteIndex = CPQueryQuoteIndex( lpSrc );
if (QSP > 0 && QuoteStack[QSP-1] == QuoteIndex) {
--QSP;
} else {
QuoteStack[QSP++] = QuoteIndex;
}
break;
case CPISOPENQUOTE:
// Got a new open quote. Always valid.
QuoteIndex = CPQueryQuoteIndex( lpSrc );
QuoteStack[QSP++] = QuoteIndex;
break;
case CPISCLOSEQUOTE:
// Got a close quote. This must match the
// current open quote.
if (QSP < 1 || *lpSrc != rgchCloseQuote[QuoteStack[QSP-1]]) {
State = Error;
} else {
--QSP;
}
break;
}
if (State == Consume) {
++lpSrc;
}
}
if (QSP || State == Error) {
// Leave the string pointing to the error
*lplpSrc = lpSrc;
return NULL;
}
// if lpSrc is sitting on a delimiter, discard it.
*lplpSrc = CPAdvance(lpSrc, "");
if (buf) {
char *p = buf;
while (lpToken < lpSrc) {
*p++ = *lpToken++;
}
*p = 0;
lpToken = buf;
} else {
if (*lpSrc) {
*lpSrc = 0;
}
}
return lpToken;
}
int
CPCopyString(
LPSTR * lplps,
LPSTR lpT,
char chEscape,
BOOL fQuote
)
/*++
Routine Description:
Scan and copy an optionally quoted C-style string. If the first character is
a quote, a matching quote will terminate the string, otherwise the scanning will
stop at the first whitespace encountered. The target string will be null
terminated if any characters are copied.
Arguments:
lplps - Supplies a pointer to a pointer to the source string
lpt - Supplies a pointer to the target string
chEscape - Supplies the escape character (typically '\\')
fQuote - Supplies a flag indicating whether the first character is a quote
Return Value:
The number of characters copied into lpt[]. If an error occurs, -1 is returned.
--*/
{
LPSTR lps = *lplps;
LPSTR lpt = lpT;
int i;
int n;
int err = 0;
char cQuote = '\0';
if (fQuote) {
if (*lps) {
cQuote = *lps++;
}
}
while (!err) {
if (*lps == 0)
{
if (fQuote) {
err = 1;
} else {
*lpt = '\0';
}
break;
}
else if (fQuote && *lps == cQuote)
{
*lpt = '\0';
// eat the quote
lps++;
break;
}
else if (!fQuote && (!*lps || *lps == ' ' || *lps == '\t' || *lps == '\r' || *lps == '\n'))
{
*lpt = '\0';
break;
}
else if (*lps != chEscape)
{
*lpt++ = *lps++;
}
else
{
switch (*++lps) {
case 0:
err = 1;
--lps;
break;
default: // any char - usually escape or quote
*lpt++ = *lps;
break;
case 'b': // backspace
*lpt++ = '\b';
break;
case 'f': // formfeed
*lpt++ = '\f';
break;
case 'n': // newline
*lpt++ = '\n';
break;
case 'r': // return
*lpt++ = '\r';
break;
case 's': // space
*lpt++ = ' ';
break;
case 't': // tab
*lpt++ = '\t';
break;
case '0': // octal escape
for (n = 0, i = 0; i < 3; i++) {
++lps;
if (*lps < '0' || *lps > '7') {
--lps;
break;
}
n = (n<<3) + *lps - '0';
}
*lpt++ = (UCHAR)(n & 0xff);
break;
}
lps++; // skip char from switch
}
} // while
if (err) {
return -1;
} else {
*lplps = lps;
return (int) (lpt - lpT);
}
}
int
CPCopyToken(
LPSTR * lplps,
LPSTR lpt
)
/*++
Routine Description:
Copy a whitespace delimited token into lpt[]. Lpt[] is not modified
if there is no token to copy. If a token is copied, it is null terminated.
Arguments:
lplps - Supplies a pointer to a pointer to a string of characters
lpt - Supplies a pointer to the string to receive the token
Return Value:
The number of characters copied into lpt[]. If return value is 0,
lpt[] is unmodified. The pointer pointed to by lplps is modified to
point to the character where scanning stopped; either the whitespace
after the token or the null at the end of the string.
--*/
{
LPSTR lps = *lplps;
int cc = 0;
// DON'T modify lpt[] if there is no token!!
while (*lps && (*lps == ' ' || *lps == '\t' || *lps == '\r' || *lps == '\n')) {
lps++;
}
while (*lps && *lps != ' ' && *lps != '\t' && *lps != '\r' && *lps != '\n') {
*lpt++ = *lps++;
*lpt = 0;
cc++;
}
*lplps = lps; // points to separator or 0
return cc;
}
/*** CPQueryChar - Check the delimiter and Quote table for given char
Purpose: Given a character return whether or not it is a character in our
delimiter table or our Quoting table
Input: szSrc - command line entered by user
Output:
Returns:
Exceptions:
Notes:
*/
int
CPQueryChar (
char * szSrc,
char * szUserDelim
)
{
int i, nUserDelim;
Assert( szSrc != NULL );
for ( i = 0; i < MAXQUOTE; i++ ) {
if (*szSrc == rgchOpenQuote[i] && *szSrc == rgchCloseQuote[i] ) {
return CPISOPENANDCLOSEQUOTE;
}
else if (*szSrc == rgchOpenQuote[i] ) {
return CPISOPENQUOTE;
}
else if ( *szSrc == rgchCloseQuote[i] ) {
return CPISCLOSEQUOTE;
}
}
for ( i = 0; i < MAXDELIM; i++ ) {
if ( *szSrc == rgchDelim[i] ) {
return CPISDELIM;
}
}
nUserDelim = strlen( szUserDelim );
for ( i = 0; i < nUserDelim; i++ ) {
if ( *szSrc == szUserDelim[i] ) {
return CPISDELIM;
}
}
return CPNOERROR;
}
/*** CPQueryQuoteIndex - Given a Character return the index
Purpose: Given a character we must be able to get the index in the quote table
for the character
Input: szSrc - command line entered by user
Output:
Returns:
Exceptions:
Notes:
*/
int
CPQueryQuoteIndex(
char * szSrc
)
{
int i;
Assert( szSrc != NULL );
for ( i = 0; i < MAXQUOTE; i++ ) {
if (*szSrc == rgchOpenQuote[i] ) {
return i;
}
}
return -1;
}
LPSTR
CPAdvance (
char * szSrc,
char * szUserDelim
)
/*++
Routine Description:
Consume all whitespace and one or zero non-white delimiter characters,
until end of string or a non-delimiter character.
Arguments:
szSrc - Supplies the string to parse
szUserDelim - Supplies an optional string of delimiter characters
Return Value:
A pointer to the next token.
--*/
{
while (*szSrc == ' ' || *szSrc == '\t') {
szSrc++;
}
if ( CPQueryChar ( szSrc, szUserDelim ) == CPISDELIM ) {
szSrc++;
}
while (*szSrc == ' ' || *szSrc == '\t') {
szSrc++;
}
return szSrc;
}
CPSTATUS
CPGetCastNbr(
char * szExpr,
USHORT type,
int radix,
int fCase,
PCXF pCxf,
char * pValue,
char * szErrMsg,
BOOL fSpecial
)
/*++
Routine Description:
Evaluate an expression and convert the result to a particular type.
Arguments:
szExpr - Supplies the expression to evaluate
type - Supplies a type index
radix - Supplies the default number base for parser
fCase - Supplies TRUE to cause case-sensitive symbol recognition
pCxf - Supplies a context and frame for expression evaluation
pValue - Returns the result
szErrMsg - Returns an error string upon failure
fSpecial - Supplies TRUE if the NTSD expression evaluator is to be used.
The NTSD EE only supports ULONG type.
Return Value:
CPSTATUS value indicating success or reason for failure
--*/
{
HTM hTM = (HTM)NULL;
HTI hTI = (HTI)NULL;
PTI pTI = NULL;
ULONG64 vResult = 0;
RTMI RIT;
EESTATUS Err;
DWORD strIndex;
UNALIGNED PULONG_PTR pUValue = (PULONG_PTR)pValue;
if (fSpecial) {
ULONG Status;
PUCHAR lpNext;
Status = GetExpression ( (PUCHAR) szExpr,
&vResult,
radix,
LppdCur ? LppdCur->mptProcessorType : -1,
&lpNext
);
*pUValue = (ULONG_PTR)vResult;
return CPStatusNtsd(Status);
}
// initialize some stuff
Err = EENOERROR;
if (szErrMsg) {
*szErrMsg = '\0';
}
memset( &RIT, 0, sizeof(RTMI) );
RIT.fValue = TRUE;
RIT.Type = type;
RIT.fSzBytes = TRUE;
// parse the expression
Err = EEParse(szExpr, radix, fCase, &hTM, &strIndex);
if(!Err) Err = EEBindTM(&hTM, SHpCXTFrompCXF(pCxf), TRUE, FALSE);
if(!Err) Err = EEvaluateTM(&hTM, SHhFrameFrompCXF(pCxf), EEHORIZONTAL);
if(!Err) Err = EEInfoFromTM(&hTM, &RIT, &hTI);
if (!Err) {
// lock down the TI
if( !hTI || !(pTI = (PTI) MMLpvLockMb (hTI)) ) {
Err = NOROOM;
} else {
// now see if we have the value
if( pTI->fResponse.fValue && pTI->fResponse.Type == RIT.Type ) {
_fmemcpy (pValue, (char *) pTI->Value, (short) pTI->cbValue);
} else {
Err = BADTYPECAST;
}
MMbUnlockMb(hTI);
}
// get the error
if( szErrMsg ) {
CVMessage(ERRORMSG, Err, MSGSTRING, szErrMsg);
}
// get the error
} else {
if ( szErrMsg ) {
CVExprErr(Err, MSGSTRING, &hTM, szErrMsg);
} else {
CVExprErr ( Err, MSGGERRSTR, &hTM, NULL );
Err = GEXPRERR;
}
}
// free any handles
if(hTM) {
EEFreeTM(&hTM);
}
if( hTI ) {
EEFreeTI(&hTI);
}
// return the error code
return(CPStatus(Err));
}
/*** CPGetNbr
* Purpose: To convert and expression into a number
* Input:
* szExpr - The expression to evaluate
* Output:
* pErr - The Expression Evaluators error msg nbr.
* Returns The numeric value of the expression. Or zero. If the result
* is zero, check the Err value to determine if an error occured.
* Exceptions:
* Notes:
*/
long
CPGetNbr(
char * szExpr,
int radix,
int fCase,
PCXF pCxf,
char * szErrMsg,
int * pErr,
BOOL fSpecial
)
{
long Value;
*pErr = CPGetCastNbr(szExpr,
0x22,
radix,
fCase,
pCxf,
(char *)&Value,
szErrMsg,
fSpecial
);
return (*pErr == CPNOERROR) ? Value : 0;
}
CPSTATUS
CPGetFPNbr(
LPSTR lpExpr,
int cBits,
int nRadix,
int fCase,
PCXF pCxf,
LPSTR lpBuf,
LPSTR lpErr
)
/*++
Routine Description:
Get a floating point number. This is a front end for CPGetCastNbr
which maps a bitcount into an OMF type.
Arguments:
lpExpr - Supplies expr to evaluate
cBits - Supplies size in bits of result type
nRadix - Supplies default radix for integer exprs
fCase - Supplies case sensitivity flag
pCxf - Supplies context/frame for EE
lpBuf - Return result in buffer this points to
lpErr - Return error string from EE
Return Value:
CPSTATUS code
--*/
{
USHORT omftype;
switch (cBits) {
case 32:
omftype = T_REAL32;
break;
case 64:
omftype = T_REAL64;
break;
case 80:
omftype = T_REAL80;
break;
default:
return CPCATASTROPHIC;
}
return CPGetCastNbr(lpExpr,
omftype,
nRadix,
fCase,
pCxf,
lpBuf,
lpErr,
FALSE
);
}
/*** CPGetInt
*/
long
CPGetInt(
char * szExpr,
int * pErr,
int * cLength
)
{
long lVal = 0;
int cb = 0;
/*
** Clear out the error field first
*/
*pErr = FALSE;
/*
** First check for a null string. Return 0 and an error
*/
if (*szExpr == 0) {
*pErr = TRUE;
return 0;
}
/*
** Check that first character is numeric
*/
if ((*szExpr < '0') || ('9' < *szExpr)) {
*pErr = TRUE;
return 0;
}
/*
*/
while (('0' <= *szExpr) && (*szExpr <= '9')) {
lVal = lVal*10 + *szExpr - '0';
szExpr++;
cb += 1;
}
/*
*/
*cLength = cb;
return lVal;
} /* CPGetInt() */
CPSTATUS
CPGetAddress(
LPCSTR lpExprOrig,
LPINT lpcch,
PADDR lpAddr,
EERADIX radix,
PCXF pcxf,
BOOL fCase,
BOOL fSpecial
)
/*++
Routine Description:
This routine will attempt to take the first whitespace delimited
portion of the expression string and convert it into an address.
If the routine is not successful then it will give a reason error
code.
Arguments:
lpExpr - string which has the address in it
lpcch - pointer to return location for count of characters used
lpAddr - pointer to address structure to return value in
radix - radix to use for evaluation
pcxf - pointer to cxf structure
fCase - TRUE if case sensitive parse
fSpecial - Use NTSD expression eval
Return Value:
--*/
{
HTM hTm = (HTM) NULL;
HTI hTi = (HTI) NULL;
PTI pTi = NULL;
RTMI ri;
EESTATUS eeErr = EENOERROR;
DWORD strIndex;
int cch = 0;
LPSTR lpExpr;
LPSTR TokenBuffer;
LPSTR p;
HEXE hexe;
CHAR szFullContext[512];
LPSTR ExeName;
SHE She;
BOOL fUse;
BOOL fLoad;
CHAR fname[MAX_PATH];
SHE she;
LPSTR lpNext;
if (fSpecial) {
NTSDADDR NtsdAddress;
ULONG Status;
Status = GetAddrExpression( (PUCHAR) lpExprOrig,
&NtsdAddress,
radix,
LppdCur ? LppdCur->mptProcessorType : -1,
(ULONG)-1,
(PUCHAR*)&lpNext
);
if (Status == 0) {
NtsdAddrToAddr(&NtsdAddress, lpAddr);
*lpcch = (int) (lpNext - lpExprOrig);
}
return CPStatusNtsd(Status);
}
/*
** Setup Initialization
*/
memset( &ri, 0, sizeof(RTMI) );
memset( lpAddr, 0, sizeof(*lpAddr));
ri.fAddr = TRUE;
/*
** Skip over leading white space and then find the next white space
*/
TokenBuffer = (LPSTR)malloc(strlen(lpExprOrig) +1);
lpNext = (LPSTR)lpExprOrig;
lpExpr = CPSzToken(&lpNext, TokenBuffer);
if (!lpExpr || !*lpExpr) {
eeErr = EEGENERAL;
} else {
// get the length of the expr
cch = (int) (lpNext - lpExprOrig);
// check for a context override
p = (PSTR) strchr( (PUCHAR) lpExpr, '}' );
if (!p) {
p = (PSTR) strchr( (PUCHAR) lpExpr, '!' );
}
if (!p) {
// Parse the expression
eeErr = EEParse(lpExpr, radix, fCase, &hTm, &strIndex);
if (eeErr == EENOERROR) {
eeErr = EEBindTM(&hTm,
SHpCXTFrompCXF(pcxf),
TRUE,
FALSE
);
}
if (eeErr == EENOERROR) {
eeErr = EEvaluateTM(&hTm, SHhFrameFrompCXF(pcxf), EEHORIZONTAL);
}
if (eeErr == EENOERROR) {
eeErr = EEInfoFromTM(&hTm, &ri, &hTi);
}
} else {
// first try the context passed in
eeErr = EEParse(lpExpr, radix, fCase, &hTm, &strIndex);
if (eeErr == EENOERROR) {
eeErr = EEBindTM(&hTm,
SHpCXTFrompCXF(pcxf),
TRUE,
FALSE
);
}
if (eeErr == EENOERROR) {
eeErr = EEvaluateTM(&hTm,
SHhFrameFrompCXF(pcxf),
EEHORIZONTAL
);
}
if (eeErr == EENOERROR) {
eeErr = EEInfoFromTM(&hTm, &ri, &hTi);
}
if (eeErr != EENOERROR) {
// search all contexts looking for the expression
fLoad = FALSE;
search_again:
hexe = (HEXE) NULL;
while ((( hexe = SHGetNextExe( hexe ) ) != 0) ) {
// We try a module only if its symbols are loaded. If the
// symbols are defered and the caller wants to load them,
// we load them.
fUse = FALSE;
if (SHSymbolsLoaded(hexe, &she)) {
fUse = TRUE;
}
else if (she == sheDeferSyms) {
if ( fLoad ) {
SHWantSymbols( hexe );
if (SHSymbolsLoaded(hexe, NULL)) {
fUse = TRUE;
}
}
}
if ( fUse ) {
// format a fully qualified symbol name
ExeName = SHGetExeName( hexe );
if (ExeName) {
_splitpath( ExeName, NULL, NULL, fname, NULL );
sprintf( szFullContext, "%s!%s", fname, p+1 );
} else {
strcpy( szFullContext, lpExpr );
}
// try to parse and bind the expression
eeErr = EEParse(szFullContext,
radix,
fCase,
&hTm,
&strIndex
);
if (eeErr == EENOERROR) {
eeErr = EEBindTM(&hTm,
SHpCXTFrompCXF(pcxf),
TRUE,
FALSE
);
}
if (eeErr == EENOERROR) {
eeErr = EEvaluateTM(&hTm,
SHhFrameFrompCXF(pcxf),
EEHORIZONTAL
);
}
if (eeErr == EENOERROR) {
eeErr = EEInfoFromTM(&hTm, &ri, &hTi);
}
if (eeErr == EENOERROR) {
break;
}
if (hTm) {
EEFreeTM( &hTm );
hTm = NULL;
}
if (hTi) {
EEFreeTI( &hTi );
hTi = NULL;
}
}
}
if ((eeErr != EENOERROR) && (!fLoad)) {
fLoad = TRUE;
goto search_again;
}
}
}
// Extract the desired information
if (eeErr == EENOERROR) {
if (!hTi || !(pTi = (PTI) MMLpvLockMb( hTi ))) {
eeErr = EEGENERAL;
} else {
*lpcch = cch;
if (pTi->fResponse.fAddr) {
*lpAddr = pTi->AI;
} else
if (pTi->fResponse.fValue && pTi->fResponse.fSzBytes &&
pTi->cbValue >= sizeof(WORD)) {
switch( pTi->cbValue ) {
case sizeof(WORD):
SetAddrOff( lpAddr, *((WORD *) pTi->Value));
break;
case sizeof(DWORD):
SE_SetAddrOff( lpAddr, *((DWORD *) pTi->Value));
break;
case sizeof(DWORDLONG):
SetAddrOff( lpAddr, *((DWORDLONG *) pTi->Value));
break;
}
// set the segment
if ((pTi->SegType & EEDATA) == EEDATA) {
ADDR addrData = {0};
OSDGetAddr( LppdCur->hpid, LptdCur->htid, adrData, &addrData );
SetAddrSeg( lpAddr, (SEGMENT) GetAddrSeg( addrData ));
ADDR_IS_FLAT(*lpAddr) = ADDR_IS_FLAT(addrData);
SYUnFixupAddr ( lpAddr );
} else if ((pTi->SegType & EECODE) == EECODE) {
ADDR addrPC = {0};
OSDGetAddr( LppdCur->hpid, LptdCur->htid, adrPC, &addrPC);
SetAddrSeg( lpAddr, (SEGMENT) GetAddrSeg( addrPC ));
ADDR_IS_FLAT(*lpAddr) = ADDR_IS_FLAT(addrPC);
SYUnFixupAddr( lpAddr );
} else {
ADDR addrData = {0};
OSDGetAddr( LppdCur->hpid, LptdCur->htid, adrData, &addrData );
SetAddrSeg( lpAddr, (SEGMENT) GetAddrSeg( addrData ));
ADDR_IS_FLAT(*lpAddr) = ADDR_IS_FLAT(addrData);
SYUnFixupAddr ( lpAddr );
}
}
MMbUnlockMb( hTi );
}
}
}
/*
** Free up any handles
*/
if (hTm) {
EEFreeTM( &hTm );
}
if (hTi) {
EEFreeTI( &hTi );
}
if (TokenBuffer) {
free(TokenBuffer);
}
return CPStatus(eeErr);
} /* CPGetAddress() */
CPSTATUS
CPGetRange(
char * lpszExpr,
int * lpcch,
ADDR * lpAddr1,
ADDR * lpAddr2,
PULONG lpItems,
EERADIX radix,
int cbDefault,
int cbSize,
CXF * pcxf,
BOOL fCase,
BOOL fSpecial,
LPBOOL lpbSecondParamIsALength
)
/*++
Routine Description:
Decode a range expression of the form:
addr1 [ l count | addr2 ]
return it as two addresses.
Arguments:
lpszExpr - Supplies pointer to argument string
lpcch - Returns count of characters used
lpAddr1 - Returns start address
lpAddr2 - Returns end address.
lpItems - Returns item count, if possible.
radix - Supplies default radix for expression parser
cbDefault - Supplies default item count value
cbSize - Supplies size in bytes of data item
pcxf - Supplies pointer to context/frame info
fCase - Supplies case sensitivity flag for parser
fSpecial - Use NTSD expr eval
lpbSecondParamIsALength - (out) Optional, can be null. If not null, will return TRUE or FALSE.
TRUE indicates that the second address is of the form <L length>.
FALSE indicates that the second address is of the form <address>.
If an error occurs, this value is undefined.
Return Value:
0 For success, or error code (from parser?)
Note: this will succeed if addr2 < addr1 or addr1.seg != adr2.seg;
caller must decide whether range makes sense.
--*/
{
LPSTR lpsz;
LPSTR lpsz1;
LPSTR lpsz0;
ADDR addr1, addr2;
LONG64 ll;
int err;
int cch;
LONG64 count;
char ch;
BOOL fError = FALSE;
if (fSpecial) {
ULONG Status;
PUCHAR lpNext;
ULONG64 value;
NTSDADDR NtsdAddr;
BOOL fLength;
value = cbDefault;
Status = GetRange( (PUCHAR) lpszExpr,
&NtsdAddr,
&value,
cbSize,
&fLength,
radix,
LppdCur ? LppdCur->mptProcessorType : -1,
(ULONG)-1,
&lpNext,
lpbSecondParamIsALength
);
*lpcch = (int) ((PSTR) lpNext - lpszExpr);
// if Status == 0, it succeeded, otherwise it is
// an error status.
if (Status == 0) {
NtsdAddrToAddr(&NtsdAddr, lpAddr1);
if (fLength) {
*lpItems = (ULONG)value;
*lpAddr2 = *lpAddr1;
GetAddrOff(*lpAddr2) += cbSize * value;
} else {
*lpItems = 0;
NtsdAddrToAddr((PNTSDADDR)value, lpAddr2);
}
}
SYFixupAddr ( lpAddr1 );
SYFixupAddr ( lpAddr2 );
return CPStatusNtsd(Status);
}
lpsz0 = lpsz = _strdup(lpszExpr);
// first arg must be an address:
if ((err = CPGetAddress(lpsz, &cch, &addr1, radix, pcxf, fCase, fSpecial)) != EENOERROR) {
fError = TRUE;
goto done;
}
// Then, see how much s/b added to get the end.
lpsz = CPSkipWhitespace(lpsz + cch);
count = 0;
if ((ch = *lpsz) == '\0') {
// no second part - fill in default
addr2 = addr1;
ll = cbDefault * cbSize;
count = cbDefault;
} else if (!strchr( (PUCHAR) "iIlL", ch) || *(lpsz = CPSkipWhitespace(lpsz+1)) == '\0') {
// End address specified (not L or L is last token)
// must be an addr
if (lpbSecondParamIsALength) {
*lpbSecondParamIsALength = FALSE;
}
if ((err = CPGetAddress(lpsz, &cch, &addr2, radix, pcxf, fCase, fSpecial)) != EENOERROR) {
fError = TRUE;
goto done;
}
lpsz += cch;
ll = 0;
} else {
// Length specified
if (lpbSecondParamIsALength) {
*lpbSecondParamIsALength = TRUE;
}
if (!(lpsz1 = CPSzToken(&lpsz, NULL))) {
fError = TRUE;
goto done;
}
count = CPGetNbr(lpsz1, radix, fCase, pcxf, NULL, &err, fSpecial);
if (count == 0 && err != EENOERROR) {
fError = TRUE;
goto done;
}
addr2 = addr1;
ll = count * cbSize;
}
// Fixup each address to the final values.
SYFixupAddr ( &addr1 );
SYFixupAddr ( &addr2 );
GetAddrOff(addr2) += ll;
if (!count && cbSize) {
count = (GetAddrOff(addr2) - GetAddrOff(addr1)) / cbSize + 1;
GetAddrOff(addr2) = GetAddrOff(addr1) + cbSize * count;
}
// Sign extend
GetAddrOff(addr2) = SEPtrTo64( GetAddrOff(addr1) );
*lpcch = (int) (lpsz - lpsz0);
*lpAddr1 = addr1;
*lpAddr2 = addr2;
Assert(count < MAX_ULONG);
*lpItems = (ULONG) count;
done:
free(lpsz0);
if (fError) {
return CPGENERAL;
} else {
return CPNOERROR;
}
} /* CPGetRange */
/*** CPSkipWhitespace
** Synopsis:
** lpsz = CPSkipWhitespace(lpszIn)
** Entry:
** lpszIn - string to skip white space on
** Returns:
** Pointer to first non-white space character in string
** Description:
** This function will skip over any leading white space in a string
** and return a pointer to the first non-whitespace character
*/
char *
CPSkipWhitespace(
PCSTR lpszIn
)
{
Assert(lpszIn);
while (*lpszIn == ' ' || *lpszIn == '\t') {
lpszIn++;
}
return (PSTR) lpszIn;
} /* CPSkipWhiteSpace() */
/*** CPRemoveTrailingWhitespace
** Synopsis:
** CPRemoveTrailingWhitespace(pszStart)
** Entry:
** pszStart - string to remove trailing white space from
** Returns:
** nothing
** Description:
** This function will remove any tariling white space in a string
** by setting the null terminator past the
*/
void
CPRemoveTrailingWhitespace(
PSTR pszStart
)
{
Assert(pszStart);
PSTR pszEnd = pszStart + _tcslen(pszStart);
pszEnd--;
while ( !*pszEnd && pszEnd >= pszStart ) {
pszEnd--;
}
} /* CPSkipWhiteSpace() */
struct format {
DWORD cBits;
FMTTYPE fmtType;
DWORD radix;
DWORD fTwoFields;
DWORD cchMax;
LPSTR lpszDescription;
} RgFormats[] = {
{8, fmtAscii, 0, FALSE, 1, "ASCII"},
{8, fmtInt, 16, TRUE, 2, "Byte"},
{16, fmtInt, 10, FALSE, 6, "Short"},
{16, fmtUInt, 16, FALSE, 4, "Short Hex"},
{16, fmtUInt, 10, FALSE, 5, "Short Unsigned"},
{32, fmtInt, 10, FALSE, 11, "Long"},
{32, fmtUInt, 16, FALSE, 8, "Long Hex"},
{32, fmtUInt, 10, FALSE, 10, "Long Unsigned"},
{64, fmtInt, 10, FALSE, 21, "Quad"},
{64, fmtUInt, 16, FALSE, 16, "Quad Hex"},
{64, fmtUInt, 10, FALSE, 20, "Quad Unsigned"},
{32, fmtFloat, 10, FALSE, 14, "Real (32-bit)"},
{64, fmtFloat, 10, FALSE, 23, "Real (64-bit)"},
{80, fmtFloat, 10, FALSE, 25, "Real (10-byte)"}
// {128,fmtFloat, 10, FALSE, 42, "Real (16-byte)"}
};
// range[i] is smallest value larger than that
// expressible in 'i' bits.
ULONG range[] = {
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
};
LPSTR
LargeIntegerFormat(
LARGE_INTEGER li,
DWORD radix,
BOOL signe,
char * buf,
unsigned long max
)
/*++
Routine Description:
LargeIntegerFormat.
This routine formats a large integer, signed or unsigned,
in radix 8, 10 or 16, into a string.
This works on any machine with a LARGE_INTEGER type; it
does not require LARGE_INTEGER support from sprintf.
Arguments:
li - the large integer value to be formatted
radix - the radix to use in formatting (8, 10, 16)
signed - whether the li is signed
buf - where to store the result
max - the buffer size.
Returns:
pointer into buf where string begins
--*/
{
LARGE_INTEGER radixli, remain;
int digit;
BOOL needsign = FALSE;
// make sure the radix is ok, and put in LARGE_INTEGER
Assert (radix == 8 || radix == 10 || radix == 16 );
radixli.LowPart = radix;
radixli.HighPart = 0;
remain.LowPart = remain.HighPart = 0;
// null-terminate the string
max--;
buf[max] = '\0';
digit = 1;
// If we are to do a signed operation, and the value is negative
// operate on its inverse, and prepend a '-' sign when complete.
if (signe && li.QuadPart < 0) {
li.QuadPart = li.QuadPart * -1;
needsign = TRUE;
}
if (li.HighPart) {
sprintf(buf, "-%x%08x", li.HighPart, li.LowPart);
} else {
sprintf(buf, "-%x", li.LowPart);
}
if (needsign) {
return buf;
} else {
return buf+1; // skip minus skip if not needed
}
#if 0
// Starting with LSD, pull the digits out
// and put them in the string at the right end.
do {
remain.QuadPart = li.QuadPart - (li.QuadPart / radixli.QuadPart);
li.QuadPart = li.QuadPart / radixli.QuadPart;
// If remainder is > 9, then radix was 16, and
// we need to print A-E, else print 0-9.
if (remain.LowPart > 9) {
buf[max - digit++] = (char)('A' + remain.LowPart - 10);
} else {
buf[max - digit++] = (char)('0' + remain.LowPart);
}
} while ( li.LowPart || li.HighPart );
if (needsign) {
buf[max-digit++] = '-';
}
return(&buf[max-digit+1]);
#endif
}
CPSTATUS
CPFormatMemory(
LPCH lpchTarget,
DWORD cchTarget,
LPBYTE lpbSource,
DWORD cBits,
FMTTYPE fmtType,
DWORD radix
)
/*++
Routine Description:
CPFormatMemory.
formats a value by template
Arguments:
lpchTarget - Destination buffer.
cchTarget - Size of destination buffer.
lpbSource - Data to be formatted.
cBits - Number of bits in the data.
fmtType - Determines how the data will be treated?? UINT, float, real, ...
radix - Radix to use when formatting.
Return Value:
None.
--*/
{
LONG64 l;
long cb;
ULONG64 ul = 0;
char rgch[512] = {0};
Assert (radix == 8 || radix == 10 || radix == 16 ||
(fmtType & fmtBasis) == fmtAscii ||
(fmtType & fmtBasis) == fmtUnicode);
Assert (cBits != 0);
Assert (cchTarget <= sizeof(rgch));
switch (fmtType & fmtBasis) {
// Format from memory bytes into an integer format number
case fmtInt:
if (radix == 10) {
switch( (cBits + 7)/8 ) {
case 1:
l = *(signed char *)lpbSource;
if (fmtType & fmtZeroPad) {
sprintf(rgch, "%0*I64d", cchTarget-1, l);
} else {
sprintf(rgch, "% I64d", l);
}
break;
case 2:
l = *(short *)lpbSource;
if (fmtType & fmtZeroPad) {
sprintf(rgch, "%0*I64d", cchTarget-1, l);
} else {
sprintf(rgch, "% I64d", l);
}
break;
case 4:
l = *(long *)lpbSource;
if (fmtType & fmtZeroPad) {
sprintf(rgch, "%0*I64d", cchTarget-1, l);
} else {
sprintf(rgch, "% I64d", l);
}
break;
case 8:
l = *(LONG64 *)lpbSource;
if (fmtType & fmtZeroPad) {
sprintf(rgch, "%0*I64d", cchTarget-1, l);
} else {
sprintf(rgch, "% I64d", l);
}
break;
default:
return CPBADFORMAT;
}
if (strlen(rgch) >= cchTarget) {
return CPOVERRUN;
}
strcpy(lpchTarget, rgch);
break;
}
// then we should handle this as UInt
case fmtUInt:
cb = (cBits + 7)/8;
switch( cb ) {
case 1:
ul = *(BYTE *) lpbSource;
break;
case 2:
ul = *(USHORT *) lpbSource;
break;
case 4:
ul = *(ULONG *) lpbSource;
break;
// MBH - bugbug - CENTAUR bug;
// putting contents of instead of address of structure
// for return value in a0.
case 8:
ul = *(ULONG64 *) lpbSource;
break;
default:
if (radix != 16 || (fmtType & fmtZeroPad) == 0) {
return CPBADFORMAT;
}
}
if (fmtType & fmtZeroPad) {
switch (radix) {
case 8:
sprintf(rgch, "%0*.*I64o", cchTarget-1, cchTarget-1, ul);
break;
case 10:
sprintf(rgch, "%0*.*I64u", cchTarget-1, cchTarget-1, ul);
break;
case 16:
if (cb <= 8) {
sprintf(rgch, "%0*.*I64x", cchTarget-1, cchTarget-1, ul);
} else {
// handle any size:
// NOTENOTE a-kentf this is dependent on byte order
for (l = 0; l < cb; l++) {
sprintf(rgch+l+l, "%02.2x", lpbSource[cb - l - 1]);
}
//sprintf(rgch, "%0*.*x", cchTarget-1, cchTarget-1, ul);
}
break;
}
} else {
switch (radix) {
case 8:
sprintf(rgch, "%I64o", ul);
break;
case 10:
sprintf(rgch, "%I64u", ul);
break;
case 16:
sprintf(rgch, "%I64x", ul);
break;
}
}
if (strlen(rgch) >= cchTarget) {
return CPOVERRUN;
}
strcpy(lpchTarget, rgch);
break;
case fmtAscii:
if ( cBits != 8 ) {
return CPBADFORMAT;
}
lpchTarget[0] = *(BYTE *) lpbSource;
if ((lpchTarget[0] < ' ') || (lpchTarget[0] > 0x7e)) {
lpchTarget[0] = '.';
}
lpchTarget[1] = 0;
return CPNOERROR;
case fmtUnicode:
if (cBits != 16) {
return CPBADFORMAT;
}
Assert((DWORD)MB_CUR_MAX <= cchTarget);
if ((wctomb(lpchTarget, *(LPWCH)lpbSource) == -1) ||
(lpchTarget[0] < ' ') ||
(lpchTarget[0] > 0x7e)) {
lpchTarget[0] = '.';
}
lpchTarget[1] = 0;
return CPNOERROR;
case fmtFloat:
switch ( cBits ) {
case 4*8:
sprintf(rgch, "% 12.6e",*((float *) lpbSource));
break;
case 8*8:
// sprintf(rgch, "% 17.11le", *((double *) lpbSource));
sprintf(rgch, "% 21.14le", *((double *) lpbSource));
break;
case 10*8:
if (_uldtoa((_ULDOUBLE *)lpbSource, 25, rgch) == NULL) {
return CPBADFORMAT;
}
break;
case 16*8:
// v-vadimp this is an IA64 float - may have to rethink the format here
// what we are getting here is really FLOAT128
if (_uldtoa((_ULDOUBLE *)(lpbSource), 30, rgch) == NULL) {
return CPBADFORMAT;
}
break;
default:
return CPBADFORMAT;
}
if (strlen(rgch) >= cchTarget) {
return CPOVERRUN;
}
strncpy(lpchTarget, rgch, cchTarget-1);
lpchTarget[cchTarget-1] = 0;
return CPNOERROR;
case fmtAddress:
return CPBADFORMAT;
case fmtZeroPad:
return CPBADFORMAT;
case fmtBit:
{
WORD i,j,shift=0; //shift will allow for a blank after each 8 bits
for (i=0;i<cBits/8;i++) {
for(j=0;j<8;j++) {
if((lpbSource[i]>>j) & 0x1) {
rgch[i*8+j+shift]='1';
} else {
rgch[i*8+j+shift]='0';
}
}
rgch[(i+1)*8+shift]=' ';
shift++;
}
rgch[cBits+shift-1]='\0';
strcpy(lpchTarget,rgch);
}
return CPNOERROR;
}
return CPNOERROR;
} /* CPFormatMemory() */
CPSTATUS
CPUnformatMemory(
LPBYTE lpbTarget,
LPSTR lpszSource,
DWORD cBits,
FMTTYPE fmtType,
DWORD nradix
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
ULARGE_INTEGER largeint;
ULONG l;
char *ptr = lpszSource;
switch ( fmtType & fmtBasis ) {
case fmtBit:
{
ULONGLONG ul = 0;
ptr += strlen(lpszSource);
if (ptr != lpszSource) while (--ptr != lpszSource) {
switch (*ptr) {
case '1':
ul += 1;
case '0':
if (ptr!=lpszSource) ul <<= 1;
case ' ':
break;
default:
Assert(!"Bad binary digit");
return CPBADFORMAT;
}
}
*(ULONGLONG*)lpbTarget = ul;
return CPNOERROR;
}
case fmtInt:
case fmtUInt:
Assert (nradix == 8 || nradix == 10 || nradix == 16);
l = 0;
ptr = CPSkipWhitespace(ptr);
if ((fmtType & fmtOverRide) == 0) {
if (*ptr == '0') {
// force radix - is it hex or octal?
++ptr;
if (*ptr == 'x' || *ptr == 'X') {
++ptr;
nradix = 16;
} else if ((*ptr == 'o') || (*ptr == 'O')) {
nradix = 8;
}
}
}
errno = 0;
largeint = (strtouli(ptr, &ptr, (int)nradix));
l = largeint.LowPart;
if ((l == 0 || l == ULONG_MAX) && errno == ERANGE) {
return CPBADFORMAT;
}
if (cBits < 32 && l > range[cBits-1] ) {
return CPBADFORMAT;
}
if (*CPSkipWhitespace(ptr)) {
return CPBADFORMAT;
}
switch ( (cBits + 7)/8 ) {
case 1:
*(BYTE *) lpbTarget = (BYTE) l;
break;
case 2:
*(USHORT *) lpbTarget = (USHORT) l;
break;
case 4:
*(ULONG *) lpbTarget = l;
break;
case 8:
*(PULARGE_INTEGER)lpbTarget = largeint;
break;
default:
return CPBADFORMAT;
}
break;
case fmtFloat:
// radix is ALWAYS 10 in the world of floats
switch ( (cBits + 7)/8 ) {
case 4:
if (sscanf(lpszSource, "%f", (float *)lpbTarget) != 1) {
return CPBADFORMAT;
}
break;
case 8:
if (sscanf(lpszSource, "%lf", (double *)lpbTarget) != 1) {
return CPBADFORMAT;
}
break;
case 10:
// i = sscanf(lpszSource, "%Lf", (long double *)lpbTarget);
_atoldbl( (_ULDOUBLE *)lpbTarget, lpszSource );
break;
case 16: //v-vadimp this is an IA64 float (FLOAT128)
_atoldbl( (_ULDOUBLE *)lpbTarget, lpszSource );
break;
default:
return CPBADFORMAT;
}
break;
case fmtAscii:
case fmtUnicode:
case fmtAddress:
// these aren't handled here.
return CPBADFORMAT;
}
return CPNOERROR;
} /* CPUnformatMemory() */
CPSTATUS
CPUnformatAddr(
LPADDR lpaddr,
char * lpsz,
PBOOL pbSegAlwaysZero
)
/*++
Routine Description:
This routine takes an address string and converts it into an
ADDR packet. The assumption is that the address is in one of the
following formats:
XXXX:XXXX 16:16 address ( 9)
0xXXXX:0xXXXX 16:16 address (13)
XXXX:XXXXXXXX 16:32 address (13)
0xXXXX:0xXXXXXXXX 16:32 address (17)
0xXXXXXXXX 0:32 address (10)
XXXXXXXX 0:32 address ( 8)
0xXXXXXXXXXXXXXXXX 0:64 address (18)
XXXXXXXXXXXXXXXX 0:64 address (16)
Arguments:
lpaddr - Supplies the address packet to be filled in
lpsz - Supplies the string to be converted into an addr packet.
pbSegAlwaysZero - May be NULL.
This is dependent on the format of the
string passed into the function. With some formats, the segment
is always zero, with others, the segment may or may not be zero.
TRUE - Indicates that the segment of the address will always be
0 regardless of the value passed in.
FALSE - The segment may or may not be zero.
Return Value:
CPNOERROR - no errors
CPGENERAL - unable to do unformatting
--*/
{
int i;
SEGMENT seg = 0;
OFFSET off = 0;
BOOL fReal = FALSE;
if (pbSegAlwaysZero) {
*pbSegAlwaysZero = TRUE;
}
memset(lpaddr, 0, sizeof(*lpaddr));
if (lpsz == NULL) {
return CPGENERAL;
}
switch( strlen(lpsz) ) {
case 9:
for (i=0; i<9; i++) {
switch( i ) {
case 0:
case 1:
case 2:
case 3:
if (pbSegAlwaysZero) {
*pbSegAlwaysZero = FALSE;
}
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
seg = seg * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
seg = seg * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
seg = seg * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
case 4:
if (lpsz[i] == '#') {
ADDR_IS_REAL(*lpaddr) = TRUE;
} else if (lpsz[i] != ':') {
return CPGENERAL;
}
break;
case 5:
case 6:
case 7:
case 8:
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
off = off * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
off = off * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
off = off * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
}
}
SetAddrSeg(lpaddr, seg);
SE_SetAddrOff(lpaddr, off);
break;
case 13:
if (lpsz[1] == 'x') {
for (i=0; i<13; i++) {
switch( i ) {
case 0:
case 7:
if (lpsz[i] != '0') {
return CPGENERAL;
}
break;
case 1:
case 8:
if ((lpsz[i] != 'x') && (lpsz[i] != 'X')) {
return CPGENERAL;
}
break;
case 2:
case 3:
case 4:
case 5:
if (pbSegAlwaysZero) {
*pbSegAlwaysZero = FALSE;
}
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
seg = seg * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
seg = seg * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
seg = seg * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
case 6:
if (lpsz[i] == '#') {
ADDR_IS_REAL(*lpaddr) = TRUE;
} else if (lpsz[i] != ':') {
return CPGENERAL;
}
break;
case 9:
case 10:
case 11:
case 12:
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
off = off * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
off = off * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
off = off * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
}
}
SetAddrSeg(lpaddr, seg);
SE_SetAddrOff(lpaddr, off);
} else {
for (i=0; i<13; i++) {
switch( i ) {
case 0:
case 1:
case 2:
case 3:
if (pbSegAlwaysZero) {
*pbSegAlwaysZero = FALSE;
}
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
seg = seg * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
seg = seg * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
seg = seg * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
case 4:
if (lpsz[i] == '#') {
fReal = TRUE;
} else if (lpsz[i] != ':') {
return CPGENERAL;
}
break;
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
case 11:
case 12:
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
off = off * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
off = off * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
off = off * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
}
}
SetAddrSeg(lpaddr, seg);
SE_SetAddrOff(lpaddr, off);
ADDR_IS_OFF32(*lpaddr) = TRUE;
ADDR_IS_FLAT(*lpaddr) = FALSE;
}
break;
case 17:
for (i=0; i<17; i++) {
switch( i ) {
case 0:
case 7:
if (lpsz[i] != '0') {
return CPGENERAL;
}
break;
case 1:
case 8:
if ((lpsz[i] != 'x') && (lpsz[i] != 'X')) {
return CPGENERAL;
}
break;
case 2:
case 3:
case 4:
case 5:
if (pbSegAlwaysZero) {
*pbSegAlwaysZero = FALSE;
}
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
seg = seg * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
seg = seg * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
seg = seg * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
case 6:
if (lpsz[i] != ':') {
return CPGENERAL;
}
break;
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
case 16:
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
off = off * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
off = off * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
off = off * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
}
}
SetAddrSeg(lpaddr, seg);
SE_SetAddrOff(lpaddr, off);
ADDR_IS_OFF32(*lpaddr) = TRUE;
ADDR_IS_FLAT(*lpaddr) = TRUE;
break;
case 10:
for (i=0; i<10; i++) {
switch( i ) {
case 0:
if (lpsz[i] != '0') {
return CPGENERAL;
}
break;
case 1:
if ((lpsz[i] != 'x') && (lpsz[i] != 'X')) {
return CPGENERAL;
}
break;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
off = off * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
off = off * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
off = off * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
break;
}
}
SetAddrSeg(lpaddr, seg);
SE_SetAddrOff(lpaddr, SE32To64(off) );
ADDR_IS_OFF32(*lpaddr) = TRUE;
ADDR_IS_FLAT(*lpaddr) = TRUE;
break;
case 8:
for (i=0; i<8; i++) {
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
off = off * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
off = off * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
off = off * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
}
SetAddrSeg(lpaddr, seg);
SE_SetAddrOff(lpaddr, SE32To64(off) );
ADDR_IS_OFF32(*lpaddr) = TRUE;
ADDR_IS_FLAT(*lpaddr) = TRUE;
break;
case 18:
for (i=0; i<18; i++) {
if (i == 0) {
if (lpsz[i] != '0') {
return CPGENERAL;
}
} else if (i==1) {
if ((lpsz[i] != 'x') && (lpsz[i] != 'X')) {
return CPGENERAL;
}
} else {
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
off = off * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
off = off * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
off = off * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
}
}
SetAddrSeg(lpaddr, seg);
SE_SetAddrOff(lpaddr, off);
ADDR_IS_OFF32(*lpaddr) = TRUE; //v-vadimp ????? may be FALSE(i.e. 64-bit), same below
ADDR_IS_FLAT(*lpaddr) = TRUE;
break;
case 16:
for (i=0; i<16; i++) {
if (('0' <= lpsz[i]) && (lpsz[i] <= '9')) {
off = off * 16 + lpsz[i] - '0';
} else if (('a' <= lpsz[i]) && lpsz[i] <= 'f') {
off = off * 16 + lpsz[i] - 'a' + 10;
} else if (('A' <= lpsz[i]) && lpsz[i] <= 'F') {
off = off * 16 + lpsz[i] - 'A' + 10;
} else {
return CPGENERAL;
}
}
SetAddrSeg(lpaddr, seg);
SE_SetAddrOff(lpaddr, off);
ADDR_IS_OFF32(*lpaddr) = TRUE;
ADDR_IS_FLAT(*lpaddr) = TRUE;
break;
default:
return CPGENERAL;
}
return CPNOERROR;
}
/* EEUnFormatAddr() */
CPSTATUS
CPFormatEnumerate(
DWORD iFmt,
LPDWORD lpcBits,
FMTTYPE * lpFmtType,
PEERADIX lpRadix,
LPDWORD lpFTwoFields,
LPDWORD lpcchMax,
LPSTR * lplpszDesc
)
{
if (iFmt >= sizeof(RgFormats)/sizeof(struct format)) {
return CPGENERAL;
}
*lpcBits = RgFormats[iFmt].cBits;
*lpFmtType = RgFormats[iFmt].fmtType;
*lpRadix = RgFormats[iFmt].radix;
*lpFTwoFields = RgFormats[iFmt].fTwoFields;
*lpcchMax = RgFormats[iFmt].cchMax;
if (lplpszDesc != NULL) {
*lplpszDesc = &RgFormats[iFmt].lpszDescription[0];
}
return CPNOERROR;
} /* CPFormatEnumerate() */