#if KERNEL
#include <stdarg.h>
#include <string.h>
#include <sys/systm.h>
#include <libkern/OSTypes.h>
#include <libsa/stdlib.h>
enum { false = 0, true = 1 };
#else
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
#endif
#include "c++rem3.h"
#define STRLEN(s) (sizeof(s)-1)
#define APPENDSTR(c, str) do { appendNStr(c, str, STRLEN(str)); } while (0)
#define MAX_COMPOUND_TYPES 128
#define MAX_ENTRIES 256
#define MAX_SDICT_ENTRIES 256
#define MAX_BDICT_ENTRIES 64
#define MAX_RETURN_BUFFER 256
typedef enum NameTypes {
kNTUndefined, kNTClass, kNTFunction, kNTFuncEnd,
kNTMethod, kNTBuiltIn, kNTDeclarator, kNTArray,
kNTKName, kNTSubstitute, kNTSubQualClass
} NameTypes;
typedef struct TypeData {
short fStartEntry, fNumEntries;
} TypeData;
typedef struct BaseTypeData {
const char *fFundTypeID; unsigned int fLen:16;
unsigned int fType:4; unsigned int fVolatile:1;
unsigned int fConst:1;
unsigned int fSigned:1;
unsigned int fUnsigned:1;
unsigned int fPseudo:1;
unsigned int fQualified:1;
} BaseTypeData;
typedef struct CheckPoint {
const char *fInChar;
unsigned char fNumI, fNumO, fNumT, fNumB, fNumS;
} CheckPoint;
typedef struct ParseContext {
CheckPoint fP;
BaseTypeData fInEntries[MAX_ENTRIES]; BaseTypeData fOutEntries[MAX_ENTRIES]; TypeData fTypeList[MAX_COMPOUND_TYPES]; TypeData fSubDict[MAX_SDICT_ENTRIES];
TypeData fBDict[MAX_BDICT_ENTRIES]; BaseTypeData *fCurBaseP;
const char *fInStr;
char *fOutStrEnd;
char *fOutChar;
int fInSize;
Rem3Return fRetCode;
} ParseContext;
static Boolean parse_type(ParseContext *c);
static __inline__ char getNext(ParseContext *c)
{
return *c->fP.fInChar++;
}
static __inline__ CheckPoint *checkPoint(ParseContext *c)
{
return &c->fP;
}
static __inline__ void resetTo(ParseContext *c, CheckPoint *chk)
{
c->fP = *chk;
}
static __inline__ const char *inCharFromCheck(ParseContext *c, CheckPoint *chk)
{
return chk->fInChar;
}
static __inline__ void advance(ParseContext *c, int len)
{
c->fP.fInChar += len;
}
static __inline__ Boolean retard(ParseContext *c, int len)
{
const char *cp = c->fP.fInChar - len;
if (cp < c->fInStr)
return false;
c->fP.fInChar = cp;
return true;
}
static __inline__ char peekAt(ParseContext *c, int index)
{
return c->fP.fInChar[index];
}
static __inline__ char peekNext(ParseContext *c)
{
return peekAt(c, 0);
}
static __inline__ Boolean atEnd(ParseContext *c)
{
return '\0' == peekNext(c);
}
static __inline__ Boolean hasRemain(ParseContext *c, int len)
{
return (c->fP.fInChar - c->fInStr + len <= c->fInSize);
}
static __inline__ BaseTypeData *newIn(ParseContext *c)
{
BaseTypeData *iP;
if (c->fP.fNumI < MAX_ENTRIES) {
iP = &c->fInEntries[c->fP.fNumI++];
bzero(iP, sizeof(*iP));
c->fCurBaseP = iP;
return iP;
}
else {
c->fRetCode = kR3InternalNotRemangled;
return NULL;
}
}
static __inline__ BaseTypeData *newOut(ParseContext *c)
{
BaseTypeData *oP;
if (c->fP.fNumO < MAX_ENTRIES) {
oP = &c->fOutEntries[c->fP.fNumO++];
return oP;
}
else {
c->fRetCode = kR3InternalNotRemangled;
return NULL;
}
}
static __inline__ TypeData *
newSub(ParseContext *c, int start, int num)
{
TypeData *sP;
if (c->fP.fNumS < MAX_SDICT_ENTRIES) {
sP = &c->fSubDict[c->fP.fNumS++];
sP->fStartEntry = start;
sP->fNumEntries = num;
return sP;
}
else {
c->fRetCode = kR3InternalNotRemangled;
return NULL;
}
}
static __inline__ TypeData *
newBDict(ParseContext *c, int start, int num)
{
TypeData *bP;
if (c->fP.fNumB < MAX_BDICT_ENTRIES) {
bP = &c->fBDict[c->fP.fNumB++];
bP->fStartEntry = start;
bP->fNumEntries = num;
return bP;
}
else {
c->fRetCode = kR3InternalNotRemangled;
return NULL;
}
}
static __inline__ TypeData *
newType(ParseContext *c, int start)
{
TypeData *tP;
if (c->fP.fNumT < MAX_COMPOUND_TYPES) {
tP = &c->fTypeList[c->fP.fNumT++];
tP->fStartEntry = start;
return tP;
}
else
return NULL;
}
static __inline__ TypeData *
dupType(ParseContext *c, TypeData *iTP, int offset)
{
TypeData *tP = newType(c, iTP->fStartEntry + offset);
if (tP)
tP->fNumEntries = iTP->fNumEntries;
return tP;
}
static __inline__ Boolean isValidFirstAlphabetic(char c)
{
if ('a' <= c && c <= 'z')
return true;
else if ('A' <= c && c <= 'Z')
return true;
else
return false;
}
static __inline__ Boolean isValidFirstChar(char c)
{
if (isValidFirstAlphabetic(c))
return true;
else if (c == '_')
return true;
else
return false;
}
static __inline__ Boolean isValidChar(char c)
{
if (isValidFirstChar(c))
return true;
else if ('0' <= c && c <= '9')
return true;
else
return false;
}
static __inline__ Boolean isNext(ParseContext *c, char ch)
{
if (peekNext(c) == ch) {
advance(c, 1);
return true;
}
else
return false;
}
static Boolean charNext(ParseContext *c, char *str)
{
if (hasRemain(c, 1)) {
char ch = peekNext(c);
char next;
while ( (next = *str++) )
if (next == ch) {
advance(c, 1);
return true;
}
}
return false;
}
static Boolean strNext(ParseContext *c, const char *str)
{
const char *cp = c->fP.fInChar;
do {
if (!*str) {
c->fP.fInChar = (char *) cp;
return true;
}
else if (!*cp)
return false;
} while (*cp++ == *str++);
return false;
}
static void
decodeQual(BaseTypeData *typeP, int *qualLenP, const char **qualP)
{
const char *qual;
int qualLen;
if (typeP->fConst && typeP->fVolatile)
{ qual = "VK"; qualLen = 2; }
else if (typeP->fConst)
{ qual = "K"; qualLen = 1; }
else if (typeP->fVolatile)
{ qual = "V"; qualLen = 1; }
else
{ qual = NULL; qualLen = 0; }
*qualLenP = qualLen;
*qualP = qual;
}
static void appendChar(ParseContext *c, char ch)
{
char *outAddr = c->fOutChar++;
if (outAddr < c->fOutStrEnd)
*outAddr = ch;
}
static void appendNStr(ParseContext *c, const char *str, int len)
{
char *outAddr = c->fOutChar;
c->fOutChar += len;
if (c->fOutChar < c->fOutStrEnd)
bcopy(str, outAddr, len);
}
static __inline__ void appendStr(ParseContext *c, const char *str)
{
appendNStr(c, str, strlen(str));
}
static void appendSub(ParseContext *c, int ls)
{
appendChar(c, 'S');
if (ls) {
if (--ls >= 36) {
int ms;
ms = ls / 36;
appendChar(c, (ms < 10)? '0' + ms : 'A' + ms - 10);
ls -= (ms * 36);
}
appendChar(c, (ls < 10)? '0' + ls : 'A' + ls - 10);
}
appendChar(c, '_');
}
static Boolean compareTypes(ParseContext *c, int sub, int entry, int numEntries)
{
TypeData *subP = &c->fSubDict[sub];
BaseTypeData *bSP, *bIP;
int i;
if (subP->fNumEntries != numEntries)
return false;
bSP = &c->fInEntries[subP->fStartEntry];
bIP = &c->fInEntries[entry];
for (i = 0; i < numEntries; i++, bSP++, bIP++) {
if (bSP->fType != bIP->fType)
return false;
switch (bSP->fType) {
case kNTClass:
if (bSP->fLen != bIP->fLen)
return false;
else if (strncmp(bSP->fFundTypeID, bIP->fFundTypeID, bSP->fLen))
return false;
break;
case kNTArray:
case kNTBuiltIn:
case kNTDeclarator:
if (bSP->fFundTypeID != bIP->fFundTypeID)
return false;
break;
case kNTMethod:
case kNTFunction:
case kNTUndefined:
case kNTKName:
break;
default:
return false; }
}
return true;
}
static int searchDict(ParseContext *c, int entry, int numE)
{
int sub, numSubs = c->fP.fNumS;
if (numE == 1 && kNTBuiltIn == c->fInEntries[entry].fType)
return -1;
for (sub = 0; sub < numSubs; sub++)
if (compareTypes(c, sub, entry, numE))
return sub;
return -1;
}
static int searchDictClass(ParseContext *c, const char *qname, int len)
{
TypeData *subP;
int sub, numSubs = c->fP.fNumS;
for (sub = 0, subP = c->fSubDict; sub < numSubs; sub++, subP++) {
BaseTypeData *iP = &c->fInEntries[subP->fStartEntry];
if (kNTClass != iP->fType || iP->fLen != len)
continue;
if (!strncmp(iP->fFundTypeID, qname, len))
return sub;
}
return -1;
}
static Boolean
appendQualifiedClass(ParseContext *c, int entry)
{
BaseTypeData *iP, *oP, *sP, *endSP;
const char *cp, *typeID;
int sub, subEntry, prefixLen;
int q_count;
int decodeStart = c->fP.fNumI;
iP = &c->fInEntries[entry];
endSP = &c->fInEntries[MAX_ENTRIES];
sP = &c->fInEntries[decodeStart];
prefixLen = iP->fLen;
typeID = cp = iP->fFundTypeID;
for (q_count = 0; sP < endSP && (cp-typeID) < prefixLen; q_count++, sP++) {
int count;
count = strtoul(cp, (char **) &cp, 10);
cp += count;
sP->fType = kNTClass;
sP->fFundTypeID = typeID;
sP->fLen = cp - typeID;
}
if (sP >= endSP)
return false;
sub = -1;
for (subEntry = q_count, sP--; subEntry > 0; subEntry--, sP--) {
sub = searchDictClass(c, sP->fFundTypeID, sP->fLen);
if (-1 != sub)
break;
}
oP = newOut(c);
if (!oP)
return false;
if (sub < 0)
*oP = *iP; else {
prefixLen = sP->fLen;
oP->fType = kNTSubstitute; oP->fLen = sub;
oP->fFundTypeID = 0;
if (prefixLen != iP->fLen) {
oP->fType = kNTSubQualClass;
oP = newOut(c);
if (!oP)
return false;
*oP = *iP; oP->fType = kNTSubQualClass;
oP->fFundTypeID += prefixLen; oP->fLen -= prefixLen;
}
}
for (subEntry++, sP++; subEntry < q_count; subEntry++, decodeStart++) {
c->fInEntries[decodeStart] = *sP++;
if (!newSub(c, decodeStart, 1))
return false;
}
c->fP.fNumI = decodeStart;
if (!newSub(c, entry, 1))
return false;
return true;
}
static int
appendType(ParseContext *c, int type)
{
BaseTypeData *iP, *oP;
TypeData *tP;
int i, sub;
int entry, numE, lastEntry;
Boolean found;
if (type >= c->fP.fNumT)
return -1;
tP = &c->fTypeList[type++];
entry = tP->fStartEntry;
numE = tP->fNumEntries;
lastEntry = entry + numE;
iP = 0;
for (i = 0, found = false, sub = -1; i < numE; i++) {
iP = &c->fInEntries[entry + i];
switch (iP->fType) {
case kNTFunction:
case kNTBuiltIn:
i++; found = true;
break;
case kNTClass:
case kNTMethod:
sub = searchDict(c, entry + i, numE - i);
if (sub < 0 && !iP->fQualified)
i++;
found = true;
break;
case kNTDeclarator:
case kNTArray:
sub = searchDict(c, entry + i, numE - i);
found = (sub >= 0);
break;
case kNTKName:
case kNTSubstitute:
case kNTSubQualClass:
case kNTUndefined:
default:
return -1;
}
if (found)
break;
}
if (!found)
return -1;
oP = &c->fOutEntries[c->fP.fNumO];
if (i) {
if (c->fP.fNumO + i >= MAX_ENTRIES)
return -1;
bcopy(&c->fInEntries[entry], oP, i * sizeof(*oP));
c->fP.fNumO += i;
oP += i;
}
if (sub >= 0) {
oP->fType = kNTSubstitute;
oP->fLen = sub;
c->fP.fNumO++;
while (type < c->fP.fNumT
&& c->fTypeList[type].fStartEntry < lastEntry)
type++;
}
else switch (iP->fType)
{
case kNTMethod:
type = appendType(c, type); if (type < 0)
return type;
type = appendType(c, type); if (type < 0)
return type;
break;
case kNTFunction:
type = appendType(c, type); if (type < 0)
return type;
do {
tP = &c->fTypeList[type];
if (tP->fStartEntry < lastEntry) {
type = appendType(c, type);
if (type < 0)
return type;
}
else
break;
} while (type < c->fP.fNumT);
oP = newOut(c);
if (!oP)
return -1;
oP->fType = kNTFuncEnd;
break;
case kNTBuiltIn:
i--; break;
case kNTClass: if (!iP->fQualified)
break;
else if (appendQualifiedClass(c, entry + i))
break;
else
return -1;
}
for (i += entry; --i >= entry; ) {
if (!newSub(c, i, lastEntry - i))
return -1;
}
return type;
}
static Boolean appendArgumentList(ParseContext *c)
{
int i, num;
c->fRetCode = kR3InternalNotRemangled;
num = c->fP.fNumT;
for (i = 0; i < num; ) {
i = appendType(c, i);
if (i < 0)
return false;
}
for (i = 0, num = c->fP.fNumO; i < num; i++) {
BaseTypeData *bP;
bP = &c->fOutEntries[i];
if (bP->fPseudo)
continue;
switch (bP->fType) {
case kNTSubstitute: appendSub(c, bP->fLen); break;
case kNTSubQualClass:
appendChar(c, 'N');
appendSub(c, bP->fLen);
i++; bP = &c->fOutEntries[i];
appendNStr(c, bP->fFundTypeID, bP->fLen);
appendChar(c, 'E');
break;
case kNTClass:
if (bP->fQualified) {
appendChar(c, 'N');
appendNStr(c, bP->fFundTypeID, bP->fLen);
appendChar(c, 'E');
}
else
appendNStr(c, bP->fFundTypeID, bP->fLen);
break;
case kNTArray: {
char numbuf[16]; int len;
len = snprintf(numbuf, sizeof(numbuf),
"A%lu_", (unsigned long) bP->fFundTypeID);
appendNStr(c, numbuf, len);
break;
}
case kNTBuiltIn:
case kNTDeclarator: appendChar(c, (int) bP->fFundTypeID); break;
case kNTMethod: appendChar(c, 'M'); break;
case kNTFunction: appendChar(c, 'F'); break;
case kNTFuncEnd: appendChar(c, 'E'); break;
case kNTUndefined:
case kNTKName:
default:
return false; }
}
c->fRetCode = kR3Remangled;
return true;
}
static Boolean parse_count(ParseContext *c, int *countP)
{
int count = 0;
char ch;
ch = peekNext(c);
if (ch < '1' || ch > '9')
return false;
count = strtol(c->fP.fInChar, (char **) &c->fP.fInChar, 10);
if (countP)
*countP = count;
return true;
}
static Boolean parse_index(ParseContext *c, int *indexP)
{
CheckPoint chk = *checkPoint(c);
char ch0, ch1;
int index;
ch0 = peekAt(c, 0);
ch1 = peekAt(c, 1);
if ( !('0' <= ch0 && ch0 <= '9') )
goto abandonParse;
if ('0' <= ch1 && ch1 <= '9') {
if (!parse_count(c, &index))
goto abandonParse;
if (isNext(c, '_')) {
if (indexP)
*indexP = index;
return true;
}
else
resetTo(c, &chk); }
advance(c, 1);
index = ch0 - '0';
if (indexP)
*indexP = index;
return true;
abandonParse:
return false;
}
static Boolean parse_qualifiers(ParseContext *c)
{
BaseTypeData *bP = c->fCurBaseP;
for (;;) {
if (isNext(c, 'C'))
bP->fConst = true; else if (isNext(c, 'V'))
bP->fVolatile = true; else if (isNext(c, 'u'))
return false; else if (isNext(c, 'G'))
continue; else
break;
}
return true;
}
static Boolean duplicateEntries(ParseContext *c, int start, int numE)
{
BaseTypeData *bIP = &c->fInEntries[start]; BaseTypeData *bP = c->fCurBaseP;
int i;
if (kNTMethod == bIP->fType) {
bP--; c->fP.fNumI--;
}
numE--;
if (c->fP.fNumI + numE >= MAX_ENTRIES)
return false;
bcopy(bIP, bP, (numE + 1) * sizeof(*bP));
for (i = 0; i < c->fP.fNumT; i++) {
TypeData *tP = &c->fTypeList[i];
if (tP->fStartEntry < start)
continue;
else if (tP->fStartEntry <= start + numE)
dupType(c, tP, bP - bIP);
else
break;
}
c->fP.fNumI += numE;
bP += numE;
c->fCurBaseP = bP;
return true;
}
static Boolean
parse_class_name(ParseContext *c)
{
BaseTypeData *bP = c->fCurBaseP;
const char *typeId = c->fP.fInChar;
char ch;
int count;
if (parse_count(c, &count)) {
if (!hasRemain(c, count))
goto abandonParse;
bP->fType = kNTClass;
advance(c, count);
bP->fFundTypeID = typeId;
bP->fLen = c->fP.fInChar - typeId;
}
else {
switch (peekNext(c)) {
case 'Q': {
int i, q_count;
advance(c, 1);
if ('_' == (ch = getNext(c))) {
advance(c, 1);
if (!parse_count(c, &q_count) || !isNext(c, '_'))
goto abandonParse;
}
else if ('1' <= ch && ch <= '9')
q_count = ch - '0';
if (!q_count)
goto abandonParse;
typeId = c->fP.fInChar;
bP->fType = kNTClass;
bP->fQualified = true;
i = 0;
for (i = 0; i < q_count; i++) {
if (parse_count(c, &count))
advance(c, count);
else
goto abandonParse;
}
bP->fLen = c->fP.fInChar - typeId;
bP->fFundTypeID = typeId;
break;
}
case 'B':
advance(c, 1);
if (!parse_index(c, &count) || count >= c->fP.fNumB)
goto abandonParse;
if (!duplicateEntries(c, c->fBDict[count].fStartEntry,
c->fBDict[count].fNumEntries))
goto abandonParse;
return true;
case 'K': default:
goto abandonParse;
}
}
if (newBDict(c, bP - c->fInEntries, 1))
return true;
abandonParse:
return false;
}
static Boolean parse_fund_type_id(ParseContext *c)
{
BaseTypeData *bP = c->fCurBaseP;
if (!parse_class_name(c)) {
char ch = peekNext(c);
if (bP->fSigned && 'c' != ch)
goto abandonParse;
switch (ch) {
case 'b': case 'd': case 'f': case 'v': case 'w': break;
case 'c': if (bP->fSigned) ch = 'a';
else if (bP->fUnsigned) ch = 'h';
break;
case 'e': ch = 'z';
break;
case 'i': if (bP->fUnsigned) ch = 'j';
break;
case 'l': if (bP->fUnsigned) ch = 'm';
break;
case 'r': ch = 'e';
break;
case 's': if (bP->fUnsigned) ch = 't';
break;
case 'x': if (bP->fUnsigned) ch = 'y';
break;
case 'G': default:
goto abandonParse;
}
advance(c, 1); bP->fFundTypeID = (void *) (int) ch;
bP->fLen = 0;
bP->fType = kNTBuiltIn;
}
return true;
abandonParse:
return false;
}
static Boolean parse_arg_type(ParseContext *c)
{
TypeData *typeP;
int repeat = 0;
typeP = &c->fTypeList[c->fP.fNumT]; if (!parse_type(c))
return false;
if (isNext(c, 'n')) {
if (!parse_index(c, &repeat))
return false;
do {
c->fCurBaseP = newIn(c); if (!c->fCurBaseP)
return false;
if (!duplicateEntries(c, typeP->fStartEntry, typeP->fNumEntries))
return false;
} while (--repeat);
}
return true;
}
static Boolean parse_argument_types(ParseContext *c)
{
if (atEnd(c))
return true;
if (!parse_arg_type(c))
goto abandonParse;
while (!atEnd(c) && parse_arg_type(c))
;
return true;
abandonParse:
return false;
}
static Boolean
rotateFunction(ParseContext *c, int argStart, int retStart)
{
char returnTypeBuffer[MAX_RETURN_BUFFER];
int numArg, numRet;
int lenArg, lenRet;
char *sArgP, *sRetP;
int i;
TypeData *argTP = &c->fTypeList[argStart];
TypeData *retTP = &c->fTypeList[retStart];
numArg = retTP->fStartEntry - argTP->fStartEntry;
numRet = retTP->fNumEntries;
lenArg = numArg * sizeof(BaseTypeData);
lenRet = numRet * sizeof(BaseTypeData);
if (lenRet > sizeof(returnTypeBuffer))
return false;
sArgP = (char *) (&c->fInEntries[argTP->fStartEntry]);
sRetP = (char *) (&c->fInEntries[retTP->fStartEntry]);
bcopy(sRetP, returnTypeBuffer, lenRet);
bcopy(sArgP, sArgP + lenRet, lenArg);
bcopy(returnTypeBuffer, sArgP, lenRet);
lenArg = numArg;
lenRet = numRet;
numArg = retStart - argStart;
numRet = c->fP.fNumT - retStart;
for (i = 0; i < numArg; i++)
c->fTypeList[argStart+i].fStartEntry += lenRet;
for (i = 0; i < numRet; i++)
c->fTypeList[retStart+i].fStartEntry -= lenArg;
for (i = 0; i < c->fP.fNumB; i++) {
TypeData *bDP = &c->fBDict[i];
int start = bDP->fStartEntry;
if (start >= argTP->fStartEntry)
bDP->fStartEntry = start + lenRet;
else if (start >= retTP->fStartEntry)
bDP->fStartEntry = start - lenArg;
}
lenArg = numArg * sizeof(TypeData);
lenRet = numRet * sizeof(TypeData);
sArgP = (char *) (&c->fTypeList[argStart]);
sRetP = (char *) (&c->fTypeList[retStart]);
bcopy(sRetP, returnTypeBuffer, lenRet);
bcopy(sArgP, sArgP + lenRet, lenArg);
bcopy(returnTypeBuffer, sArgP, lenRet);
return true;
}
static Boolean parse_function_type(ParseContext *c, Boolean forMethod)
{
TypeData *bDictP = 0;
BaseTypeData *bP = c->fCurBaseP;
int argTypeStart, retTypeStart;
if (!forMethod) {
bDictP = newBDict(c, c->fP.fNumI-1, 0);
if (!bDictP)
goto abandonParse;
}
if (!isNext(c, 'F'))
goto abandonParse;
bP->fType = kNTFunction;
argTypeStart = c->fP.fNumT;
if (!parse_argument_types(c))
goto abandonParse;
if (!isNext(c, '_'))
goto abandonParse;
retTypeStart = c->fP.fNumT;
if (!parse_type(c))
goto abandonParse;
if (!rotateFunction(c, argTypeStart, retTypeStart))
goto abandonParse;
if (!forMethod)
bDictP->fNumEntries = c->fP.fNumI - bDictP->fStartEntry;
return true;
abandonParse:
return false;
}
static Boolean cleanMethodFunction(ParseContext *c, int type)
{
TypeData *typeP, *startTP, *endTP;
BaseTypeData *bP;
int i, thisStart, thisEnd, thisLen, funcRemain;
startTP = &c->fTypeList[type+1];
endTP = &c->fTypeList[c->fP.fNumT];
thisEnd = startTP->fStartEntry + startTP->fNumEntries;
for (startTP++; startTP < endTP; startTP++)
if (startTP->fStartEntry >= thisEnd)
break;
if (startTP >= endTP) {
c->fRetCode = kR3InternalNotRemangled;
return false; }
thisLen = startTP->fNumEntries;
thisStart = startTP->fStartEntry;
thisEnd = thisStart + thisLen;
funcRemain = c->fP.fNumI - thisEnd;
bP = &c->fInEntries[thisStart];
if (!funcRemain) {
c->fP.fNumI -= (thisLen - 1);
bP->fFundTypeID = (void *) (int) 'v'; bP->fLen = 0;
bP->fType = kNTBuiltIn;
startTP->fNumEntries = 1;
return true;
}
bcopy(bP + thisLen, bP, funcRemain * sizeof(*bP));
c->fP.fNumI -= thisLen;
for (typeP = startTP + 1; typeP < endTP; typeP++)
if (typeP->fStartEntry >= thisEnd)
break;
if (typeP >= endTP) {
c->fRetCode = kR3InternalNotRemangled;
return false; }
bcopy(typeP, startTP, (char *) endTP - (char *) typeP);
c->fP.fNumT -= typeP - startTP;
endTP = &c->fTypeList[c->fP.fNumT];
for (typeP = startTP ; typeP < endTP; typeP++)
typeP->fStartEntry -= thisLen;
for (i = 0; i < c->fP.fNumB; i++) {
TypeData *bDP = &c->fBDict[i];
int start = bDP->fStartEntry;
if (start < thisStart)
continue;
if (start >= thisEnd)
break;
bDP->fStartEntry = start - thisLen;
}
return true;
}
static Boolean parse_method_type(ParseContext *c)
{
TypeData *bDictP;
TypeData *typeP;
BaseTypeData *bP;
bDictP = newBDict(c, c->fP.fNumI-2, 0);
if (!bDictP)
goto abandonParse;
c->fP.fNumI--;
bP = c->fCurBaseP - 1;
if (!isNext(c, 'M'))
goto abandonParse;
if (bP->fFundTypeID != (void *) (int) 'P')
goto abandonParse;
bP->fType = kNTMethod;
bP->fFundTypeID = NULL;
bP->fLen = 0;
typeP = newType(c, c->fP.fNumI);
if (!newIn(c) || !typeP)
goto abandonParse;
if (!parse_class_name(c))
goto abandonParse;
typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
typeP = newType(c, c->fP.fNumI);
if (!newIn(c) || !typeP)
goto abandonParse;
if (!parse_function_type(c, true))
goto abandonParse;
if (!cleanMethodFunction(c, typeP - c->fTypeList))
goto abandonParse;
typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
bDictP->fNumEntries = c->fP.fNumI - bDictP->fStartEntry;
return true;
abandonParse:
return false;
}
static Boolean emitQualifiers(ParseContext *c)
{
BaseTypeData *bP = c->fCurBaseP;
if (bP->fVolatile || bP->fConst) {
Boolean isConst, isVolatile, isSigned, isUnsigned;
isVolatile = bP->fVolatile;
isConst = bP->fConst;
isSigned = bP->fSigned;
isUnsigned = bP->fUnsigned;
bP->fConst = bP->fVolatile = bP->fSigned = bP->fUnsigned = 0;
if (isVolatile) {
bP->fType = kNTDeclarator;
bP->fFundTypeID = (void *) (int) 'V';
bP->fLen = 0;
bP = newIn(c);
if (!bP)
return false;
}
if (isConst) {
bP->fType = kNTDeclarator;
bP->fFundTypeID = (void *) (int) 'K';
bP->fLen = 0;
bP = newIn(c);
if (!bP)
return false;
}
bP->fSigned = isSigned;
bP->fUnsigned = isUnsigned;
}
return true;
}
static Boolean parse_base_type(ParseContext *c)
{
if ('F' == peekNext(c)) {
if (!parse_function_type(c, false))
goto abandonParse;
}
else if ('M' == peekNext(c)) {
if (!parse_method_type(c))
goto abandonParse;
}
else {
BaseTypeData *bP = c->fCurBaseP;
for (;;) {
if (isNext(c, 'S'))
{ bP->fSigned = true; continue; }
else if (isNext(c, 'U'))
{ bP->fUnsigned = true; continue; }
else if (isNext(c, 'C'))
{ bP->fConst = true; continue; }
else if (isNext(c, 'V'))
{ bP->fVolatile = true; continue; }
else if (charNext(c, "Ju"))
goto abandonParse; else
break;
}
if (!emitQualifiers(c))
goto abandonParse;
if (!parse_fund_type_id(c))
goto abandonParse;
}
return true;
abandonParse:
return false;
}
static Boolean parse_declarators(ParseContext *c)
{
int count;
BaseTypeData *dP;
for (count = 0; ; count++) {
const char *curDecl;
char ch;
if (!newIn(c))
goto abandonParse;
if (!parse_qualifiers(c) || !emitQualifiers(c))
goto abandonParse;
dP = c->fCurBaseP;
curDecl = c->fP.fInChar;
switch (peekNext(c)) {
case 'P': case 'p': case 'R':
dP->fType = kNTDeclarator;
advance(c, 1);
ch = *curDecl;
if ('p' == ch) ch = 'P';
dP->fFundTypeID = (void *) (int) ch;
dP->fLen = 0;
continue;
case 'A':
dP->fType = kNTArray;
advance(c, 1); curDecl++;
curDecl = (void *)
strtoul(curDecl, (char **) &c->fP.fInChar, 10);
if (!curDecl)
goto abandonParse;
dP->fFundTypeID = curDecl;
dP->fLen = 0;
continue;
case 'T': case 'O':
goto abandonParse;
default:
break;
}
break;
}
dP->fLen = 0;
return true;
abandonParse:
return false;
}
static Boolean parse_type(ParseContext *c)
{
CheckPoint chk = *checkPoint(c);
TypeData *typeP = newType(c, c->fP.fNumI);
if (!typeP)
goto abandonParse;
if (!parse_declarators(c))
goto abandonParse;
if (!parse_base_type(c) || kNTUndefined == c->fCurBaseP->fType)
goto abandonParse;
typeP->fNumEntries = c->fP.fNumI - typeP->fStartEntry;
return true;
abandonParse:
resetTo(c, &chk);
return false;
}
static Boolean
parse_function_name(ParseContext *c)
{
char ch;
while ( (ch = peekNext(c)) )
{
advance(c, 1);
if ('_' == ch && '_' == peekNext(c)) {
do {
advance(c, 1);
} while ('_' == peekNext(c));
return true;
}
}
return false;
}
static struct opMap {
const char *op295, *op3;
} opMapTable[] = {
{"aad", "aN" }, {"adv", "dV" }, {"aer", "eO" }, {"als", "lS" },
{"amd", "rM" }, {"ami", "mI" }, {"aml", "mL" }, {"aor", "oR" },
{"apl", "pL" }, {"ars", "rS" }, {"aa", "aa" }, {"ad", "ad" },
{"as", "aS" }, {"cl", "cl" }, {"cm", "cm" }, {"cn", "qu" },
{"co", "co" }, {"dl", "dl" }, {"dv", "dv" }, {"eq", "eq" },
{"er", "eo" }, {"ge", "ge" }, {"gt", "gt" }, {"le", "le" },
{"ls", "ls" }, {"lt", "lt" }, {"md", "rm" }, {"mi", "mi" },
{"ml", "ml" }, {"mm", "mm" }, {"mn", NULL }, {"mx", NULL },
{"ne", "ne" }, {"nt", "nt" }, {"nw", "nw" }, {"oo", "oo" },
{"or", "or" }, {"pl", "pl" }, {"pp", "pp" }, {"rf", "pt" },
{"rm", "pm" }, {"rs", "rs" }, {"sz", "sz" }, {"vc", "ix" },
{"vd", "da" }, {"vn", "na" },
};
static Boolean parse_opinfo(ParseContext *c, const char **opInfoP)
{
CheckPoint chk = *checkPoint(c);
const char *op;
char ch;
int i;
if ('a' == (ch = peekNext(c))) {
goto abandonParse;
}
else if (strNext(c, "type")) {
goto abandonParse;
}
else if (retard(c, 4) && strNext(c, "____op")) {
goto abandonParse;
}
resetTo(c, &chk);
if (!strrchr("acdeglmnoprsv", peekNext(c)))
goto abandonParse;
op = NULL;
for (i = 0; i < sizeof(opMapTable)/sizeof(opMapTable[0]); i++) {
if (strNext(c, opMapTable[i].op295)) {
op = opMapTable[i].op3;
break;
}
}
if (!op)
goto abandonParse;
if (!strNext(c, "__")) goto abandonParse;
if (opInfoP)
*opInfoP = op;
return true;
abandonParse:
return false;
}
static Boolean
parse_signature(ParseContext *c,
const char *func, int funcLen, const char *op)
{
BaseTypeData *bP;
TypeData *tP;
Boolean isFunction = false;
if (isNext(c, 'F')) {
char numbuf[16]; int len;
isFunction = true;
if (!funcLen)
goto abandonParse;
len = snprintf(numbuf, sizeof(numbuf), "__Z%d", funcLen);
appendNStr(c, numbuf, len);
appendNStr(c, func, funcLen);
}
else if (isNext(c, 'S')) {
goto abandonParse;
}
else {
const char *qual;
int qualLen;
tP = newType(c, c->fP.fNumI);
if (!tP)
goto abandonParse;
bP = newIn(c);
if (!bP)
goto abandonParse;
bP->fPseudo = true;
if (!parse_qualifiers(c))
goto abandonParse;
if (!parse_class_name(c))
goto abandonParse;
bP = c->fCurBaseP; tP->fNumEntries = c->fP.fNumI - tP->fStartEntry;
APPENDSTR(c, "__ZN");
decodeQual(bP, &qualLen, &qual);
if (qualLen)
appendNStr(c, qual, qualLen);
appendNStr(c, bP->fFundTypeID, bP->fLen);
if (funcLen) {
char numbuf[16]; int len;
len = snprintf(numbuf, sizeof(numbuf), "%d", funcLen);
appendNStr(c, numbuf, len);
appendNStr(c, func, funcLen);
}
else if (op)
appendStr(c, op);
else {
APPENDSTR(c, "C2");
}
appendChar(c, 'E');
}
if (atEnd(c)) {
appendChar(c, 'v'); c->fRetCode = kR3Remangled;
return true;
}
c->fCurBaseP = NULL;
if (!parse_argument_types(c))
goto abandonParse;
if (isFunction) {
if (isNext(c, '_')) {
c->fRetCode = kR3InternalNotRemangled;
goto abandonParse;
}
}
if (!atEnd(c))
goto abandonParse;
return appendArgumentList(c);
abandonParse:
return false;
}
static Boolean parse_mangled_name(ParseContext *c)
{
CheckPoint chk;
CheckPoint dubBarChk;
const char *func;
if (strNext(c, "_GLOBAL_")) { c->fRetCode = kR3InternalNotRemangled;
return false; }
func = c->fP.fInChar;
for (chk = *checkPoint(c); ; resetTo(c, &dubBarChk)) {
int funcLen;
const char *op = NULL;
if (!parse_function_name(c))
goto abandonParse;
dubBarChk = *checkPoint(c);
(void) parse_opinfo(c, &op);
if (atEnd(c))
goto abandonParse;
funcLen = inCharFromCheck(c, &dubBarChk) - func - 2;
if (parse_signature(c, func, funcLen, op))
return true;
if (kR3NotRemangled != c->fRetCode)
goto abandonParse;
}
abandonParse:
resetTo(c, &chk);
return false;
}
static Boolean parse_gnu_special(ParseContext *c)
{
CheckPoint chk = *checkPoint(c);
BaseTypeData *bP = newIn(c);
if (!bP)
return false;
if (strNext(c, "_._") || strNext(c, "_$_") ) {
if (!parse_class_name(c) || !atEnd(c))
goto abandonParse;
APPENDSTR(c, "__ZN");
appendNStr(c, bP->fFundTypeID, bP->fLen);
APPENDSTR(c, "D2Ev");
c->fRetCode = kR3Remangled;
return true;
}
else if (strNext(c, "__vt_")) {
if (!parse_class_name(c) || !atEnd(c))
goto abandonParse;
APPENDSTR(c, "__ZTV");
if (kNTClass != bP->fType)
goto abandonParse;
else if (bP->fQualified) {
appendChar(c, 'N');
appendNStr(c, bP->fFundTypeID, bP->fLen);
appendChar(c, 'E');
}
else
appendNStr(c, bP->fFundTypeID, bP->fLen);
c->fRetCode = kR3Remangled;
return true;
}
else if (isNext(c, '_')) {
const char *varname;
int varlen, len;
char numbuf[16];
if (!parse_class_name(c)) goto abandonParse;
if (!isNext(c, '.') && !isNext(c, '$'))
goto abandonParse;
varname = c->fP.fInChar;
if (atEnd(c) || !isValidFirstChar(getNext(c)))
goto abandonParse;
while ( !atEnd(c) )
if (!isValidChar(getNext(c)))
goto abandonParse;
varlen = c->fP.fInChar - varname;
len = snprintf(numbuf, sizeof(numbuf), "%d", varlen);
APPENDSTR(c, "__ZN");
appendNStr(c, bP->fFundTypeID, bP->fLen);
appendNStr(c, numbuf, len);
appendNStr(c, varname, varlen);
appendChar(c, 'E');
c->fRetCode = kR3Remangled;
return true;
}
abandonParse:
resetTo(c, &chk);
return false;
}
static Boolean parse_special_or_name(ParseContext *c)
{
Boolean res;
res = (parse_gnu_special(c) || parse_mangled_name(c));
appendChar(c, '\0');
return res;
}
Rem3Return rem3_remangle_name(char *gcc3, int *gcc3size, const char *gcc295)
{
ParseContext *c;
Rem3Return result;
int size;
if (!gcc295 || !gcc3 || !gcc3size)
return kR3BadArgument;
size = strlen(gcc295);
if (size < 2)
return kR3NotRemangled; else if (*gcc295 != '_')
return kR3NotRemangled;
c = (ParseContext *) malloc(sizeof(*c));
if (!c)
return kR3InternalNotRemangled;
bzero(c, sizeof(*c));
c->fInSize = size;
c->fInStr = gcc295 + 1; c->fP.fInChar = c->fInStr;
c->fOutStrEnd = gcc3 + *gcc3size;
c->fOutChar = gcc3;
c->fRetCode = kR3NotRemangled;
(void) parse_special_or_name(c);
result = c->fRetCode;
if (kR3Remangled == result) {
if (c->fOutChar > c->fOutStrEnd)
result = kR3BufferTooSmallRemangled;
*gcc3size = c->fOutChar - gcc3 - 1; }
free(c);
return result;
}