mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
712 lines
17 KiB
712 lines
17 KiB
//
|
|
// overload.cpp
|
|
//
|
|
// generate a list of all possible overloaded versions of a name given
|
|
// the partially qualified name
|
|
//
|
|
|
|
#include "pdbimpl.h"
|
|
|
|
#include "bsc1.h"
|
|
|
|
typedef WORD (*PFN_IINST_THUNK)(IINST, BOOL *);
|
|
|
|
// static data
|
|
static char szOperator[] = "operator";
|
|
static char szOpMap[] = "new delete = >> << ! == != [] "
|
|
"-> * ++ -- - + "
|
|
"& ->* / % < <= > >= "
|
|
", () ~ ^ | && || *= += -= /= %= "
|
|
">>= <<= &= |= ^= ";
|
|
|
|
static SZ SzOperator(SZ sz);
|
|
static int AddPrefixItems(SZ, MBF, PFN_IINST_THUNK);
|
|
static int AddPrefixItemsClass(SZ, MBF, PFN_IINST_THUNK, SZ);
|
|
static void AdjustClassname(SZ szIn, SZ szOut);
|
|
static BOOL XFormTempl (void);
|
|
static BOOL GetEscapedChar (char FAR * FAR *, unsigned short FAR *);
|
|
static BOOL FInRadix (char, int);
|
|
|
|
// copy of C runtime routines...
|
|
// we can't use the real C-runtime because of linkage problems
|
|
// this code needs to be able to be linked against any memory
|
|
// model library and multi-thread enabled or not so it is safer to
|
|
// roll our own (these are very small functions anyway)
|
|
|
|
/*
|
|
__inline BOOL isdigit(int i)
|
|
{
|
|
return (i >= '0' && i <= '9');
|
|
}
|
|
|
|
__inline BOOL isxdigit(int i)
|
|
{
|
|
return (i >= '0' && i <= '9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F');
|
|
}
|
|
|
|
__inline int toupper(int i)
|
|
{
|
|
return i - 0x20;
|
|
}
|
|
*/
|
|
|
|
static Bsc1 *pbsc;
|
|
static PFN_IINST pfnIinstSaved;
|
|
|
|
#define BUFFLEN 256
|
|
|
|
static char buffTempl[BUFFLEN];
|
|
|
|
static WORD
|
|
fnIinstThunkTempl(IINST iinst, BOOL *pfContinue)
|
|
// the thunk used by GenerateOverload when the input string
|
|
// contains a template
|
|
// returns a count of matches and assigns
|
|
// the return value of pfnIinstSaved to *pfContinue
|
|
{
|
|
// undecorate name and compare it against szName
|
|
// if they match, call the saved callback function.
|
|
SZ sz;
|
|
|
|
sz = pbsc->formatDname(pbsc->szFrIinst(iinst));
|
|
if (pbsc->cmpStrPrefix(buffTempl, sz) == 0) {
|
|
*pfContinue = (*pfnIinstSaved)(iinst);
|
|
// we have a successful match
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static WORD
|
|
fnIinstThunkNorm(IINST iinst, BOOL *pfContinue)
|
|
// the normal thunk used by GenerateOverload when the input string
|
|
// does *not* contain a template
|
|
// returns a count of matches (always 1) and assigns
|
|
// the return value of pfnIinstSaved to *pfContinue
|
|
{
|
|
*pfContinue = (*pfnIinstSaved)(iinst);
|
|
// we have a successful match
|
|
return 1;
|
|
}
|
|
|
|
static PFN_IINST pfnIinstMemThunk;
|
|
static WORD cIinstMembers;
|
|
static MBF mbfMem;
|
|
|
|
static BOOL
|
|
FGenerateMembers(IINST iinst)
|
|
{
|
|
IINST *rgiinst;
|
|
ULONG ciinst;
|
|
if (!pbsc->getMembersArray(iinst, mbfMem, &rgiinst, &ciinst) || !ciinst)
|
|
return TRUE;
|
|
|
|
for (ULONG i = 0; i < ciinst; i++) {
|
|
if (!(*pfnIinstMemThunk)(rgiinst[i])) {
|
|
pbsc->disposeArray(rgiinst);
|
|
return FALSE;
|
|
}
|
|
cIinstMembers++;
|
|
}
|
|
|
|
pbsc->disposeArray(rgiinst);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
WORD
|
|
GenerateOverloads(SZ szOverload, MBF mbf, PFN_IINST pfnIinstUser, Bsc1* pbsc_)
|
|
// Given the string in szOverload this function will enumerate
|
|
// all possible matching decorated names
|
|
{
|
|
IINST iinst, iinstMac;
|
|
|
|
char buffAdj[BUFFLEN];
|
|
WORD count = 0;
|
|
BOOL fContinue;
|
|
|
|
pbsc = pbsc_;
|
|
|
|
// save user callback routine
|
|
pfnIinstSaved = pfnIinstUser;
|
|
|
|
// use normal thunk (i.e., assume no template name in the string)
|
|
PFN_IINST_THUNK pfnIinstThunk = &fnIinstThunkNorm;
|
|
|
|
// if the string is empty return error
|
|
|
|
if (!szOverload || szOverload[0] == 0)
|
|
return 0;
|
|
|
|
// copy across and take out all the spaces
|
|
int length = 0;
|
|
char buff[BUFFLEN];
|
|
while (*szOverload && length < sizeof(buff)) {
|
|
if (*szOverload != ' ')
|
|
buff[length++] = *szOverload;
|
|
szOverload++;
|
|
}
|
|
|
|
// check if the string was too long...
|
|
if (length >= sizeof(buff))
|
|
return 0;
|
|
|
|
buff[length] = '\0';
|
|
int lenT = length;
|
|
|
|
if (buff[lenT-1] == '*') lenT--;
|
|
if (buff[lenT-1] == ':') lenT--;
|
|
if (buff[lenT-1] == ':')
|
|
{
|
|
// we've found the input to be of the form "class::class::" or "class::class::*"
|
|
buff[lenT-1] = 0;
|
|
pfnIinstMemThunk = pfnIinstUser;
|
|
mbfMem = mbf;
|
|
cIinstMembers = 0;
|
|
GenerateOverloads(buff, mbfClass|mbfTypes, FGenerateMembers, pbsc_);
|
|
return cIinstMembers;
|
|
}
|
|
|
|
SZ szTemplFirst, szTemplLast;
|
|
|
|
// check to see if the strings contains template class names
|
|
// (there can be at most one template class name in a valid string)
|
|
if (((szTemplFirst = strchr(buff, '<')) != NULL) &&
|
|
((szTemplLast = strchr(buff, '>')) != NULL)) {
|
|
// szOverload may contain one of the following:
|
|
// "classA::classB::", "classA::classB::*" etc
|
|
// "classA::classB::mem", "classA::classB::mem*" etc
|
|
// "mem", "mem*"
|
|
// If a template class name is present, it should be in the global
|
|
// scope (i.e., classA). A template class name "foo<bar>" starts
|
|
// at szOverload and ends at szTemplLast. In that case we
|
|
// remomove the "<bar>" part from the string and save the whole name
|
|
// "foo<bar>" in a separate buffer.
|
|
|
|
// compute the length of the whole template name (i.e., "foo<bar>")
|
|
int lengthTempl = szTemplLast + 1 - buff;
|
|
|
|
// copy the whole template name to the global buffer buffTempl
|
|
strncpy(buffTempl, buff, lengthTempl);
|
|
buffTempl[lengthTempl] = '\0';
|
|
// convert buffTempl to a "canonical" form
|
|
if (XFormTempl() == FALSE)
|
|
return 0;
|
|
|
|
// remove the "<..>" part from the original string
|
|
memmove(szTemplFirst, szTemplLast + 1, length + 1 - lengthTempl);
|
|
length = strlen(buff);
|
|
|
|
// use the thunk that handles templates
|
|
pfnIinstThunk = &fnIinstThunkTempl;
|
|
}
|
|
|
|
char buffClass[BUFFLEN];
|
|
char buffsrch[BUFFLEN];
|
|
|
|
buffClass[0] = '\0';
|
|
|
|
SZ sz = buff;
|
|
SZ szLast = buff;
|
|
SZ szT = NULL;
|
|
|
|
while (szT = strstr(sz, "::")) {
|
|
*szT = '\0';
|
|
szLast = sz; // save last class name so we can detect ctor & dtor
|
|
|
|
strcpy(buffsrch, buffClass); // save current scope
|
|
strcpy(buffClass, sz); // copy new piece to front
|
|
|
|
if (buffsrch[0]) { // add separator and old piece
|
|
strcat(buffClass, "@");
|
|
strcat(buffClass, buffsrch);
|
|
}
|
|
sz = szT + 2; // skip ::
|
|
}
|
|
|
|
|
|
// this is of the form 'function' or 'class::function'
|
|
|
|
if (sz == buff) { // sz == buff means there were no '::'s
|
|
// this is of the form 'identifier'
|
|
|
|
if (sz = SzOperator(buff)) { // check for operator...
|
|
// this is of the form operator<something>
|
|
strcpy(buffsrch, sz);
|
|
}
|
|
else if (buff[length-1] == '*') { // check for trailing wildcard...
|
|
// this is of the form 'identifier*'
|
|
|
|
// Note: This is going to find names of the form ?xxx* AND xxx*
|
|
// even though we don't do the search with a leading question mark
|
|
// this is because the browser string comparison function IGNORES
|
|
// one leading question mark. The other question mark strings
|
|
// in this file are there for clarity -- they too will be ignored
|
|
// and could be deleted.
|
|
// This means if you ask for x* you WILL get x1, x2, FOO::x1, FOO::BAR::x1,
|
|
// and void xf(int) as possible outputs (after demangling of course) [rm]
|
|
buff[length-1] = '\0';
|
|
|
|
// check template form...
|
|
AdjustClassname(buff, buffsrch); // ?$name...
|
|
count += AddPrefixItems(buffsrch, mbf, pfnIinstThunk);
|
|
|
|
strcpy(buffsrch, buff);
|
|
}
|
|
else {
|
|
// no wildcards, easy search coming up
|
|
|
|
// include any exact matches of the name in the list
|
|
|
|
if ((iinst = pbsc->iinstSupSz(buff)) != iinstNil) {
|
|
iinstMac = pbsc->iinstMac();
|
|
for ( ;iinst < iinstMac;iinst++) {
|
|
SZ sz = pbsc->szFrIinst(iinst);
|
|
if (pbsc->cmpStr(sz, buff))
|
|
break;
|
|
|
|
if (pbsc->fInstFilter(iinst, mbf)) {
|
|
count += (*pfnIinstThunk)(iinst, &fContinue);
|
|
if (!fContinue)
|
|
return count;
|
|
}
|
|
}
|
|
}
|
|
|
|
// check template form...
|
|
AdjustClassname(buff, buffAdj);
|
|
if (buffAdj[0] == '?')
|
|
sprintf(buffsrch, "%s@", buffAdj); // ?$C1@...
|
|
else
|
|
sprintf(buffsrch, "?%s@", buffAdj); // ?C1@C2@?$C3...
|
|
|
|
count += AddPrefixItems(buffsrch, mbf, pfnIinstThunk);
|
|
|
|
sprintf(buffsrch, "?%s@", buff);
|
|
}
|
|
}
|
|
else {
|
|
// this is of the form 'class::member'
|
|
|
|
if (szT = SzOperator(sz)) {
|
|
// this is class::operator<something>
|
|
AdjustClassname(buffClass, buffAdj);
|
|
|
|
// check the template form...
|
|
sprintf(buffsrch, "%s%s@", szT, buffAdj);
|
|
count += AddPrefixItems((SZ)buffsrch, mbf, pfnIinstThunk);
|
|
|
|
sprintf(buffsrch, "%s%s@@", szT, buffClass);
|
|
}
|
|
else if (buff[length-1] == '*') {
|
|
// this is of the form class::member*
|
|
|
|
buff[length-1] = '\0';
|
|
|
|
AdjustClassname(buffClass, buffAdj);
|
|
|
|
// check the template form...
|
|
sprintf(buffsrch, "@%s@", buffAdj);
|
|
count += AddPrefixItemsClass(sz, mbf, pfnIinstThunk, buffsrch);
|
|
|
|
// check the non-template form
|
|
sprintf(buffsrch, "@%s@@", buffClass);
|
|
count += AddPrefixItemsClass(sz, mbf, pfnIinstThunk, buffsrch);
|
|
|
|
return count;
|
|
}
|
|
else if (!strcmp(szLast, sz)) {
|
|
// this is the constructor...
|
|
|
|
// check the template form...
|
|
AdjustClassname(buffClass, buffAdj);
|
|
sprintf(buffsrch, "??0%s@", buffAdj);
|
|
count += AddPrefixItems((SZ)buffsrch, mbf, pfnIinstThunk);
|
|
|
|
// then the standard form...
|
|
sprintf(buffsrch, "??0%s@@", buffClass);
|
|
}
|
|
else if (*sz == '~' && !strcmp(szLast, sz+1)) {
|
|
// this is the destructor
|
|
|
|
// check the template form...
|
|
AdjustClassname(buffClass, buffAdj);
|
|
sprintf(buffsrch, "??1%s@", buffAdj);
|
|
count += AddPrefixItems((SZ)buffsrch, mbf, pfnIinstThunk);
|
|
|
|
// then the standard form...
|
|
sprintf(buffsrch, "??1%s@@", buffClass);
|
|
}
|
|
else {
|
|
// this is of the form class::member
|
|
// search for the members within class
|
|
|
|
// check template form...
|
|
AdjustClassname(buffClass, buffAdj);
|
|
sprintf(buffsrch, "?%s@%s@", sz, buffAdj);
|
|
count += AddPrefixItems((SZ)buffsrch, mbf, pfnIinstThunk);
|
|
|
|
// then check the standard form...
|
|
sprintf(buffsrch, "?%s@%s@@", sz, buffClass);
|
|
}
|
|
}
|
|
|
|
// search for all the indicated items...
|
|
count += AddPrefixItems((SZ)buffsrch, mbf, pfnIinstThunk);
|
|
|
|
return count;
|
|
}
|
|
|
|
static int
|
|
AddPrefixItems(SZ sz, MBF mbf, PFN_IINST_THUNK pfnIinst)
|
|
// add all the items whose prefix matches the given string
|
|
// return the count of items added
|
|
{
|
|
IINST iinstFirst, iinstLast;
|
|
BOOL fContinue;
|
|
int count = 0;
|
|
|
|
// search for items matching the required prefix
|
|
if (pbsc->findPrefixRange(sz, &iinstFirst, &iinstLast)) {
|
|
for (; iinstFirst <= iinstLast ; iinstFirst++) {
|
|
|
|
// verify the case of the match (FindPrefixRange is case INSENSTIVE
|
|
if (pbsc->cmpStrPrefix(sz, pbsc->szFrIinst(iinstFirst)))
|
|
continue;
|
|
|
|
if (pbsc->fInstFilter(iinstFirst, mbf)) {
|
|
count += (*pfnIinst)(iinstFirst, &fContinue);
|
|
if (!fContinue)
|
|
return count;
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static int
|
|
AddPrefixItemsClass(SZ sz, MBF mbf, PFN_IINST_THUNK pfnIinst, SZ szClass)
|
|
// add all the items whose prefix matches the given string
|
|
// AND the items that occur in class given by szClass
|
|
// szClass must be of the form @class@@ as it would occur embedded
|
|
// in the dname...
|
|
//
|
|
// return the count of items added
|
|
{
|
|
IINST iinstFirst, iinstLast;
|
|
int count = 0;
|
|
BOOL fContinue;
|
|
|
|
// search for items matching the required prefix
|
|
if (pbsc->findPrefixRange(sz, &iinstFirst, &iinstLast)) {
|
|
for (; iinstFirst <= iinstLast ; iinstFirst++) {
|
|
|
|
SZ szSym = pbsc->szFrIinst(iinstFirst);
|
|
// verify the case of the match (FindPrefixRange is case INSENSTIVE
|
|
if (pbsc->cmpStrPrefix(sz, szSym))
|
|
continue;
|
|
|
|
SZ szT;
|
|
|
|
// check to make sure there is a scoping qualifier
|
|
if (!(szT = strchr(szSym, '@')))
|
|
continue;
|
|
|
|
// compare the scope qualifier against the required
|
|
if (pbsc->cmpStrPrefix(szClass, szT))
|
|
continue;
|
|
|
|
if (pbsc->fInstFilter(iinstFirst, mbf)) {
|
|
count += (*pfnIinst)(iinstFirst, &fContinue);
|
|
if (!fContinue)
|
|
return count;
|
|
}
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
static SZ
|
|
SzOperator(SZ sz)
|
|
// check if the incoming string is an operator, if so return the operator
|
|
// mangling of it
|
|
//
|
|
{
|
|
SZ szOp;
|
|
UINT cbOp;
|
|
|
|
static char szMangledOp[5] = "??_0";
|
|
|
|
while (*sz == ' ') sz++;
|
|
|
|
if (strncmp(sz, szOperator, sizeof(szOperator)-1))
|
|
return NULL;
|
|
|
|
sz += sizeof(szOperator) - 1;
|
|
|
|
strcpy(szMangledOp, "??2");
|
|
|
|
while (*sz == ' ') sz++;
|
|
|
|
szOp = szOpMap;
|
|
for (;;) {
|
|
cbOp = 0;
|
|
|
|
if (*szOp == 0)
|
|
break;
|
|
|
|
while (szOp[cbOp] != ' ')
|
|
cbOp++;
|
|
|
|
if (strlen(sz) == cbOp && strncmp(sz, szOp, cbOp) == 0)
|
|
return szMangledOp;
|
|
|
|
szOp += cbOp + 1;
|
|
|
|
// counts 0-9, A, C-Z, _0 - _6
|
|
|
|
if (szMangledOp[2] == '9') {
|
|
szMangledOp[2] = 'A';
|
|
}
|
|
else if (szMangledOp[2] == 'A') {
|
|
szMangledOp[2] = 'C';
|
|
}
|
|
else if (szMangledOp[2] == 'Z') {
|
|
szMangledOp[2] = '_';
|
|
szMangledOp[3] = '0';
|
|
}
|
|
else if (szMangledOp[2] == '_') {
|
|
szMangledOp[3]++;
|
|
}
|
|
else {
|
|
szMangledOp[2]++;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static BOOL XFormTempl (void)
|
|
// Transforms template name in buffTempl by converting integer and
|
|
// character constants using a standard notation (decimal radix, no
|
|
// suffix). Returns TRUE if transformation succeds, FALSE otherwise.
|
|
{
|
|
char buffNew[BUFFLEN];
|
|
SZ sz = buffTempl;
|
|
SZ szNew = buffNew;
|
|
SZ pEnd;
|
|
char c;
|
|
char cEnd;
|
|
char cPrev;
|
|
INT numLen;
|
|
INT nNew;
|
|
char buffNum[20];
|
|
unsigned long num;
|
|
unsigned short nVal;
|
|
|
|
// NOTE: spaces have already been removed from the string
|
|
|
|
cPrev = '\0';
|
|
nNew = 0;
|
|
for (sz = buffTempl; (c = *sz) != '\0'; cPrev = c, sz++) {
|
|
|
|
// check if there is space for at least one additional char
|
|
if (nNew >= BUFFLEN)
|
|
return FALSE;
|
|
|
|
// check if there is an integer constant as a template argument
|
|
if (isdigit(c) &&
|
|
(cPrev == '<' || cPrev == ',' || cPrev == '-')) {
|
|
|
|
// convert int constant to a decimal string with no suffix
|
|
num = strtoul(sz, &pEnd, 0);
|
|
if (pEnd && pEnd != sz &&
|
|
// make sure the number is not float or double
|
|
'E' != (cEnd = toupper(*pEnd)) && '.' != cEnd) {
|
|
|
|
// skip suffix (if any) in the input string
|
|
if ('L' == cEnd || 'U' == cEnd) {
|
|
pEnd++;
|
|
}
|
|
|
|
// convert number to decimal representation
|
|
_ultoa(num, buffNum, 10);
|
|
|
|
// check if there is enough space in buffer
|
|
// and copy decimal string
|
|
numLen = strlen(buffNum);
|
|
if (numLen + nNew >= BUFFLEN)
|
|
return FALSE;
|
|
strcpy(szNew + nNew, buffNum);
|
|
nNew += numLen;
|
|
sz = pEnd - 1;
|
|
c = *sz;
|
|
}
|
|
else {
|
|
szNew[nNew++] = c;
|
|
}
|
|
}
|
|
else if (c == '\'') {
|
|
// read a char constant
|
|
// (does not support wide or multi-byte chars)
|
|
SZ szSav = sz;
|
|
sz++;
|
|
if ((c = *sz++) == '\\' ) {
|
|
if (GetEscapedChar (&sz, &nVal) == FALSE) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
else {
|
|
nVal = c;
|
|
}
|
|
if ((c = *sz) != '\'')
|
|
return FALSE;
|
|
|
|
// we have a valid char constant
|
|
// convert its value to a decimal string
|
|
_ultoa(nVal, buffNum, 10);
|
|
numLen = strlen(buffNum);
|
|
if (numLen + nNew >= BUFFLEN)
|
|
return FALSE;
|
|
strcpy(szNew + nNew, buffNum);
|
|
nNew += numLen;
|
|
}
|
|
else {
|
|
szNew[nNew++] = c;
|
|
}
|
|
}
|
|
|
|
buffNew[nNew] = '\0';
|
|
strcpy (buffTempl, buffNew);
|
|
return TRUE;
|
|
}
|
|
|
|
static BOOL FInRadix(char ch, int radix)
|
|
// returns true if character ch is appropriate for radix,
|
|
// returns false otherwise
|
|
{
|
|
switch (radix) {
|
|
case 8:
|
|
if (ch >= '8') {
|
|
return (FALSE);
|
|
}
|
|
// Fall through
|
|
|
|
case 10:
|
|
return (isdigit(ch));
|
|
|
|
case 16:
|
|
return (isxdigit(ch));
|
|
}
|
|
return (FALSE);
|
|
}
|
|
|
|
static BOOL GetEscapedChar (char FAR * FAR *ppb, unsigned short FAR *pVal)
|
|
// GetEscapedChar - Parse an escaped character
|
|
// Entry ppb = far pointer to far pointer to string
|
|
// ppb points to character after the backslash
|
|
//
|
|
// Exit ppb updated to end of escaped character constant
|
|
// *pVal = value of escaped character constant
|
|
//
|
|
// Returns TRUE if no error
|
|
// FALSE if error encountered
|
|
{
|
|
UINT nval = 0;
|
|
|
|
char c = **ppb;
|
|
(*ppb)++;
|
|
switch (c) {
|
|
case 'n':
|
|
*pVal = '\n';
|
|
break;
|
|
case 't':
|
|
*pVal = '\t';
|
|
break;
|
|
case 'b':
|
|
*pVal = '\b';
|
|
break;
|
|
case 'r':
|
|
*pVal = '\r';
|
|
break;
|
|
case 'f':
|
|
*pVal = '\f';
|
|
break;
|
|
case 'v':
|
|
*pVal = '\v';
|
|
break;
|
|
case 'a':
|
|
*pVal = '\a';
|
|
break;
|
|
case 'x':
|
|
if (!FInRadix (**ppb, 16)) {
|
|
return FALSE;
|
|
}
|
|
for (;;) {
|
|
c = **ppb;
|
|
if (!FInRadix (c, 16)) {
|
|
break;
|
|
}
|
|
nval *= 16;
|
|
if (isdigit (c)) {
|
|
nval += c - '0';
|
|
}
|
|
else {
|
|
nval += toupper(c) - 'A' + 10;
|
|
}
|
|
if (nval > 255) {
|
|
return FALSE;
|
|
}
|
|
(*ppb)++;
|
|
}
|
|
*pVal = (unsigned char)nval;
|
|
break;
|
|
|
|
default:
|
|
if (FInRadix (c, 8)) {
|
|
// Octal character constant
|
|
nval = (c - '0');
|
|
for (;;) {
|
|
c = **ppb;
|
|
if (!isdigit (c)) {
|
|
break;
|
|
}
|
|
if (!FInRadix (c, 8)) {
|
|
return FALSE;
|
|
}
|
|
nval = nval * 8 + (c - '0');
|
|
if (nval > 255) {
|
|
return FALSE;
|
|
}
|
|
(*ppb)++;
|
|
}
|
|
*pVal = (unsigned char)nval;
|
|
}
|
|
else {
|
|
*pVal = c;
|
|
}
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
static void AdjustClassname(SZ szIn, SZ szOut)
|
|
// make a copy of the incoming name with the last class in the scope
|
|
// adjusted so that it is the right form for a template class
|
|
// that is THIS@THAT@OTHER becomes THIS@THAT@?$OTHER
|
|
// NOTE: this function works on a restricted input alphabet so
|
|
// DBCS is not an issue
|
|
{
|
|
strcpy(szOut, szIn);
|
|
char *szT1 = strrchr(szIn, '@');
|
|
char *szT2 = strrchr(szOut, '@');
|
|
|
|
if (!szT1 || !szT2) {
|
|
strcpy(szOut, "?$");
|
|
strcpy(szOut+2, szIn);
|
|
}
|
|
else {
|
|
strcpy(szT2, "@?$");
|
|
strcpy(szT2+3, szT1+1);
|
|
}
|
|
}
|