// Make sure all dependent defines exist and have a valid value #ifndef TUNE #define TUNE 0 #endif #ifndef DEBUG #define DEBUG 0 #endif #ifndef STANDALONE #define STANDALONE 0 #endif #ifndef SPECIAL #define SPECIAL 0 #endif #ifndef TARGET_32BIT #define TARGET_32BIT 1 // DLH set in makefile originally #endif #ifndef USE_CRT_HEAP #define USE_CRT_HEAP 0 #endif #ifndef NO_COMPILER_NAMES #define NO_COMPILER_NAMES 0 #endif #ifndef NO_OPTIONS #define NO_OPTIONS 0 #endif #ifndef NO_INLINES #define NO_INLINES 0 #endif #ifndef VERS_P3 #define VERS_P3 0 #endif #ifndef VERS_PWB #define VERS_PWB 0 #endif #ifndef VERS_LNK #define VERS_LNK 1 // DLH set in makefile originally #endif #ifndef PACK_SIZE #define PACK_SIZE 1 #endif #ifndef inline_p3 #define inline_p3 #endif #ifndef inline_pwb #define inline_pwb #endif #ifndef inline_lnk #define inline_lnk #endif #ifndef NO_VIRTUAL #define NO_VIRTUAL 0 #endif // Check for version inconsistancies, ans setup version flags #if ( TUNE && STANDALONE ) #error "TUNE and STANDALONE are incompatible" #endif // TUNE && STANDALONE #if ( VERS_P3 == 1 ) #if ( VERS_PWB == 1 ) #error "VERS_P3 and VERS_PWB are incompatible" #endif // VERS_PWB #if ( VERS_LNK == 1 ) #error "VERS_P3 and VERS_LNK are incompatible" #endif // VERS_LNK #undef inline_p3 #define inline_p3 inline #undef USE_CRT_HEAP #define USE_CRT_HEAP 1 #undef NO_COMPILER_NAMES #define NO_COMPILER_NAMES 1 #undef NO_OPTIONS #define NO_OPTIONS 1 #pragma inline_depth ( 3 ) #pragma pack ( 2 ) #undef PACK_SIZE #define PACK_SIZE 1 #endif #if ( VERS_PWB == 1 ) #if ( DEBUG == 1 ) #error "VERS_PWB and DEBUG are incompatible" #endif // DEBUG #if ( VERS_LNK == 1 ) #error "VERS_PWB and VERS_LNK are incompatible" #endif // VERS_LNK #undef inline_pwb #define inline_pwb inline #undef USE_CRT_HEAP #define USE_CRT_HEAP 0 #undef NO_COMPILER_NAMES #define NO_COMPILER_NAMES 1 #undef NO_OPTIONS #define NO_OPTIONS 1 #undef PACK_SIZE #define PACK_SIZE 2 #undef NO_VIRTUAL #define NO_VIRTUAL 1 #pragma inline_depth ( 5 ) #pragma pack ( 2 ) #endif // VERS_PWB #if ( VERS_LNK == 1 ) #if ( VERS_PWB == 1 ) #error "VERS_LNK and VERS_PWB are incompatible" #endif // VERS_PWB #undef inline_lnk #define inline_lnk inline #if ( DEBUG == 1 ) #if !STANDALONE #undef USE_CRT_HEAP #define USE_CRT_HEAP 1 #endif #else // } else !DEBUG { #undef USE_CRT_HEAP #define USE_CRT_HEAP 0 #endif // !DEBUG #undef NO_COMPILER_NAMES #define NO_COMPILER_NAMES 0 #undef NO_OPTIONS #define NO_OPTIONS 0 #undef NO_VIRTUAL #define NO_VIRTUAL 1 #pragma inline_depth ( 3 ) #pragma pack ( 2 ) #undef PACK_SIZE #define PACK_SIZE 2 #endif // VERS_LNK #if ( TARGET_32BIT ) #define __far /* no far */ #define __near /* no near */ #define __pascal /* no pascal */ #if !defined( _WIN32 ) #define __cdecl /* no cdecl */ #endif #define __loadds /* no loadds */ #endif // TARGET_32BIT #if ( !NO_VIRTUAL ) #define PURE =0 #else // } elif NO_VIRTUAL { #define PURE #define virtual #endif #if DEBUG && STANDALONE #define STDEBUG 1 #endif #include "undname.hxx" static unsigned int __near __pascal strlen ( pcchar_t ); static pchar_t __near __pascal strncpy ( pchar_t, pcchar_t, unsigned int ); #if USE_CRT_HEAP extern "C" void __far * __far __cdecl malloc ( unsigned int ); extern "C" void __far __cdecl free ( void __far * ); #endif // USE_CRT_HEAP #if STDEBUG #pragma inline_depth ( 0 ) #pragma pack ( 2 ) #undef PACK_SIZE #define PACK_SIZE 1 #include class DName; class DNameNode; class CallTrace { private: enum InOut { out = -1, mark = 0, in = 1 }; pchar_t name; static int trace; static FILE * fp; static char buf[ 512 ]; static int inTrace; static void indent ( InOut inOut ) { static depth = 0; for ( int d = depth - (( inOut == out ) ? 1 : 0 ); d; d-- ) fputc ( '.', fp ); switch ( inOut ) { case in: depth++; break; case out: depth--; break; }} public: CallTrace ( pchar_t p ) : name ( p ) { if(trace&&!inTrace){ indent ( in ); fprintf ( fp, "Entered : '%s'\n", name ); fflush ( fp ); }} static void On ( pchar_t f ) { fp = fopen ( f, "wt" ); if(fp) trace = 1; } void Dump ( const DName &, pcchar_t, int ); void Dump ( const DNameNode &, pcchar_t, int ); void Dump ( unsigned long, pcchar_t, int ); void Dump ( void*, pcchar_t, int ); void Dump ( pcchar_t, pcchar_t, int ); void Message ( pcchar_t, int ); void Track ( pcchar_t, int ); void LogError ( int ); ~CallTrace () { if(trace&&!inTrace){ indent ( out ); fprintf ( fp, "Leaving : '%s'\n", name ); fflush ( fp ); }} }; int CallTrace::trace = 0; int CallTrace::inTrace = 0; FILE * CallTrace::fp = 0; char CallTrace::buf[ 512 ]; #undef NO_INLINES #define NO_INLINES 1 #define FTRACE(n) CallTrace fName(#n) #define TRACEON() do{if((argc>=2)&&(*argv[1]!='?')&&((*argv[1]<'0')||(*argv[1]>'9'))){argv++;argc--;CallTrace::On(*argv);}}while(0) #define DUMP(n) (fName.Dump(n,#n,__LINE__)) #define TRACK() (fName.Track(__FILE__,__LINE__)) #define MESSAGE(m) (fName.Message(#m,__LINE__)) #define ERROR (fName.LogError(__LINE__),DN_error) #else // } elif !STDEBUG { #pragma check_stack ( off ) #pragma pack ( 2 ) #undef PACK_SIZE #define PACK_SIZE 1 #define FTRACE(n) #define TRACEON() #define DUMP(n) #define TRACK() #define MESSAGE(m) (0) #define ERROR DN_error #endif // !STDEBUG #if ( NO_INLINES ) #undef inline_p3 #undef inline_pwb #undef inline_lnk #define inline #define inline_p3 #define inline_pwb #define inline_lnk #endif // NO_INLINES #if STANDALONE extern "C" int __far __cdecl printf ( pcchar_t, ... ); extern "C" int __far __cdecl atoi ( pcchar_t ); extern "C" void __far * __far __cdecl malloc ( unsigned int ); extern "C" void __far __cdecl free ( void __far * ); #if STDEBUG int shallowCopies = 0; int deepCopies = 0; int shallowAssigns = 0; int deepAssigns = 0; #endif int actual = 0; int requested = 0; int clones = 0; int __cdecl main ( int argc, pchar_t* argv ) { TRACEON(); FTRACE(main); unsigned short flags = 0; if (( argc > 2 ) && ( *argv[ 1 ] >= '0' ) && ( *argv[ 1 ] <= '9' )) ( flags = atoi ( argv[ 1 ]), argc--, argv++ ); for ( int i = 1; i < argc; i++ ) { printf ( "Undecoration of :- \"%s\"\n", argv[ i ]); pchar_t uName = unDName ( 0, argv[ i ], 0 #if ( !USE_CRT_HEAP ) ,&malloc ,&free #endif // !USE_CRT_HEAP #if ( !NO_OPTIONS ) ,flags #endif // !NO_OPTIONS ); if ( uName ) printf ( "is :- \"%s\"\n\n", uName ); else printf ( "Internal Error in Undecorator\n" ); } #if STDEBUG printf ( "%d bytes of memory requested, %d bytes allocated\n", requested, actual ); printf ( "%d shallow copies and %d deep copies\n", shallowCopies, deepCopies ); printf ( "%d shallow assigns and %d deep assigns\n", shallowAssigns, deepAssigns ); printf ( "%d clones\n", clones ); #endif return 0; } // End of PROGRAM #endif // STANDALONE #if TUNE void __cdecl main () { (void)unDName ( 0, 0, 0 #if ( !USE_CRT_HEAP ) ,0, 0 #endif // !USE_CRT_HEAP #if ( !NO_OPTIONS ) ,0 #endif // !NO_OPTIONS ); } #endif // TUNE class DName; class DNameNode; class Replicator; class HeapManager; class UnDecorator; const unsigned int memBlockSize = 508; // A '512' byte block including the header class HeapManager { private: #if ( !USE_CRT_HEAP ) Alloc_t pOpNew; Free_t pOpDelete; #endif // !USE_CRT_HEAP struct Block { Block * next; char memBlock[ memBlockSize ]; __near Block () { next = 0; } }; Block * head; Block * tail; unsigned int blockLeft; public: #if ( !USE_CRT_HEAP ) void __near Constructor ( Alloc_t pAlloc, Free_t pFree ) { pOpNew = pAlloc; pOpDelete = pFree; #else // } elif USE_CRT_HEAP { void __near Constructor ( void ) { #endif // USE_CRT_HEAP blockLeft = 0; head = 0; tail = 0; } void __far * __near getMemory ( size_t, int ); void __near Destructor ( void ) { while ( tail = head ) { head = tail->next; #if ( !USE_CRT_HEAP ) ( *pOpDelete )( tail ); #else // } elif USE_CRT_HEAP { free ( tail ); #endif // USE_CRT_HEAP } } #define gnew new(heap,0) #define rnew new(heap,1) }; void * __near __pascal operator new ( size_t, HeapManager &, int = 0 ); static HeapManager heap; #if ( !VERS_PWB ) // The MS Token table enum Tokens { TOK_near, TOK_nearSp, TOK_nearP, TOK_far, TOK_farSp, TOK_farP, TOK_huge, TOK_hugeSp, TOK_hugeP, TOK_basedLp, TOK_cdecl, TOK_pascal, TOK_stdcall, TOK_syscall, TOK_fastcall, TOK_interrupt, TOK_saveregs, TOK_self, TOK_segment, TOK_segnameLpQ }; static pcchar_t __near tokenTable[] = { "__near", // TOK_near "__near ", // TOK_nearSp "__near*", // TOK_nearP "__far", // TOK_far "__far ", // TOK_farSp "__far*", // TOK_farP "__huge", // TOK_huge "__huge ", // TOK_hugeSp "__huge*", // TOK_hugeP "__based(", // TOK_basedLp "__cdecl", // TOK_cdecl "__pascal", // TOK_pascal "__stdcall", // TOK_stdcall "__syscall", // TOK_syscall "__fastcall", // TOK_fastcall "__interrupt", // TOK_interrupt "__saveregs", // TOK_saveregs "__self", // TOK_self "__segment", // TOK_segment "__segname(\"" // TOK_segnameLpQ }; #endif // !VERS_PWB // The operator mapping table static pcchar_t __near nameTable[] = { " new", " delete", "=", ">>", "<<", "!", "==", "!=", "[]", #if VERS_P3 "", #else // } !VERS_P3 { "operator", #endif // VERS_P3 "->", "*", "++", "--", "-", "+", "&", "->*", "/", "%", "<", "<=", ">", ">=", ",", "()", "~", "^", "|", "&&", "||", "*=", "+=", "-=", "/=", "%=", ">>=", "<<=", "&=", "|=", "^=", #if ( !NO_COMPILER_NAMES ) "`vftable'", "`vbtable'", "`vcall", "`typeof'", "`local static guard", "`reserved'", "`vbase destructor'", "`vector deleting destructor'", "`default constructor closure'", "`scalar deleting destructor'", "`vector constructor iterator'", "`vector destructor iterator'", "`vector vbase constructor iterator'" #endif // !NO_COMPILER_NAMES }; // The following 'enum' should really be nested inside 'class DName', but to // make the code compile better with Glockenspiel, I have extracted it enum DNameStatus { DN_valid, DN_invalid, DN_truncated, DN_error }; class DName { public: __near DName (); __near DName ( char ); #if 1 __near DName ( const DName & ); // Shallow copy #endif __near DName ( DNameNode * ); __near DName ( pcchar_t ); __near DName ( pcchar_t&, char ); __near DName ( DNameStatus ); #if ( !VERS_P3 ) __near DName ( DName * ); __near DName ( unsigned long ); #endif // !VERS_P3 int __near isValid () const; int __near isEmpty () const; DNameStatus __near status () const; #if ( !VERS_P3 ) DName & __near setPtrRef (); int __near isPtrRef () const; int __near isUDC () const; void __near setIsUDC (); #endif // !VERS_P3 int __near length () const; pchar_t __near getString ( pchar_t, int ) const; DName __near operator + ( pcchar_t ) const; DName __near operator + ( const DName & ) const; #if ( !VERS_P3 ) DName __near operator + ( char ) const; DName __near operator + ( DName * ) const; DName __near operator + ( DNameStatus ) const; DName & __near operator += ( char ); DName & __near operator += ( pcchar_t ); DName & __near operator += ( DName * ); DName & __near operator += ( DNameStatus ); DName & __near operator |= ( const DName & ); #endif // !VERS_P3 DName & __near operator += ( const DName & ); DName & __near operator = ( pcchar_t ); DName & __near operator = ( const DName & ); #if ( !VERS_P3 ) DName & __near operator = ( char ); DName & __near operator = ( DName * ); DName & __near operator = ( DNameStatus ); #endif // !VERS_P3 // Friends : friend DName __near __pascal operator + ( char, const DName & ); friend DName __near __pascal operator + ( pcchar_t, const DName & ); #if ( !VERS_P3 ) friend DName __near __pascal operator + ( DNameStatus, const DName & ); #endif // !VERS_P3 private: DNameNode * node; DNameStatus stat : 4; unsigned int isIndir : 1; unsigned int isAUDC : 1; void __near doPchar ( pcchar_t, int ); }; class Replicator { private: // Declare, in order to suppress automatic generation void operator = ( const Replicator& ); int index; DName * dNameBuffer[ 10 ]; const DName ErrorDName; const DName InvalidDName; public: __near Replicator (); int __near isFull () const; Replicator & __near operator += ( const DName & ); const DName & __near operator [] ( int ) const; }; class UnDecorator { private: // Declare, in order to suppress automatic generation void operator = ( const UnDecorator& ); #if ( !VERS_P3 ) Replicator ArgList; static Replicator * pArgList; #endif // !VERS_P3 Replicator ZNameList; static Replicator * pZNameList; static pcchar_t gName; static pcchar_t name; static pchar_t outputString; static int maxStringLength; #if (!NO_OPTIONS) static unsigned short disableFlags; #endif // !NO_OPTIONS static DName __near getDecoratedName ( void ); static DName __near getSymbolName ( void ); static DName __near getZName ( void ); static DName __near getOperatorName ( void ); static DName __near getScope ( void ); #if ( !VERS_P3 ) static DName __near getDimension ( void ); static int __near getNumberOfDimensions ( void ); static DName __near getTemplateName ( void ); static DName __near composeDeclaration ( const DName & ); static int __near getTypeEncoding ( void ); static DName __near getBasedType ( void ); static DName __near getECSUName ( void ); static DName __near getEnumName ( void ); static DName __near getCallingConvention ( void ); static DName __near getReturnType ( DName * = 0 ); static DName __near getDataType ( DName * ); static DName __near getPrimaryDataType ( const DName & ); static DName __near getDataIndirectType ( const DName &, char, const DName &, int = FALSE ); static DName __near getDataIndirectType (); static DName __near getBasicDataType ( const DName & ); static DName __near getECSUDataType ( int = 0 ); static int __near getECSUDataIndirectType (); static DName __near getPtrRefType ( const DName &, const DName &, int ); static DName __near getPtrRefDataType ( const DName &, int ); static DName __near getArrayType ( DName * ); static DName __near getArgumentTypes ( void ); static DName __near getArgumentList ( void ); static DName __near getThrowTypes ( void ); static DName __near getLexicalFrame ( void ); static DName __near getStorageConvention ( void ); static DName __near getThisType ( void ); static DName __near getPointerType ( const DName &, const DName & ); static DName __near getReferenceType ( const DName &, const DName & ); static DName __near getExternalDataType ( const DName & ); #if ( !VERS_PWB ) static DName __near getSegmentName ( void ); #endif // !VERS_PWB #if ( !NO_COMPILER_NAMES ) static DName __near getDisplacement ( void ); static DName __near getCallIndex ( void ); static DName __near getGuardNumber ( void ); static DName __near getVfTableType ( const DName & ); static DName __near getVbTableType ( const DName & ); static DName __near getVCallThunkType ( void ); #endif // !NO_COMPILER_NAMES #endif // !VERS_P3 public: #if ( !NO_OPTIONS ) __near UnDecorator ( pchar_t, pcchar_t, int, unsigned short ); static int __near doUnderScore (); static int __near doMSKeywords (); static int __near doFunctionReturns (); static int __near doAllocationModel (); static int __near doAllocationLanguage (); #if 0 static int __near doMSThisType (); static int __near doCVThisType (); #endif static int __near doThisTypes (); static int __near doAccessSpecifiers (); static int __near doThrowTypes (); static int __near doMemberTypes (); static int __near doReturnUDTModel (); #else // } elif NO_OPTIONS { __near UnDecorator ( pchar_t, pcchar_t, int ); #endif // NO_OPTIONS #if ( !VERS_P3 && !VERS_PWB ) static pcchar_t __near UScore ( Tokens ); #endif // !VERS_P3 && !VERS_PWB __near operator pchar_t (); }; #if ( !VERS_P3 ) Replicator * UnDecorator::pArgList; #endif // !VERS_P3 Replicator * UnDecorator::pZNameList = 0; pcchar_t UnDecorator::gName = 0; pcchar_t UnDecorator::name = 0; pchar_t UnDecorator::outputString = 0; int UnDecorator::maxStringLength = 0; #if (!NO_OPTIONS) unsigned short UnDecorator::disableFlags = 0; #endif // !NO_OPTIONS pchar_t __far __cdecl __loadds unDName ( pchar_t outputString, pcchar_t name, int maxStringLength // Note, COMMA is leading following optional arguments #if ( !USE_CRT_HEAP ) ,Alloc_t pAlloc ,Free_t pFree #endif // !USE_CRT_HEAP #if ( !NO_OPTIONS ) ,unsigned short disableFlags #endif // !NO_OPTIONS ) /* * This function will undecorate a name, returning the string corresponding to * the C++ declaration needed to produce the name. Its has a similar interface * to 'strncpy'. * * If the target string 'outputString' is specified to be NULL, a string of * suitable length will be allocated and its address returned. If the returned * string is allocated by 'unDName', then it is the programmers responsibility * to deallocate it. It will have been allocated on the far heap. * * If the target string is not NULL, then the parameter 'maxStringLength' will * specify the maximum number of characters which may be placed in the string. * In this case, the returned value is the same as 'outputString'. * * Both the input parameter 'name' and the returned string are NULL terminated * strings of characters. * * If the returned value is NULL, it indicates that the undecorator ran out of * memory, or an internal error occurred, and was unable to complete its task. */ { FTRACE(unDName); #if ( VERS_P3 && !STANDALONE ) // Abort if input is invalid if ( !outputString || !name || !maxStringLength ) return 0; #endif // ( VERS_P3 && !STANDALONE ) #if ( !USE_CRT_HEAP ) // Must have an allocator and a deallocator (and we MUST trust them) if ( !( pAlloc && pFree )) return 0; else heap.Constructor ( pAlloc, pFree ); #else // } elif USE_CRT_HEAP { heap.Constructor (); #endif // USE_CRT_HEAP // Create the undecorator object, and get the result UnDecorator unDecorate ( outputString, name, maxStringLength #if ( !NO_OPTIONS ) ,disableFlags #endif // !NO_OPTIONS ); pchar_t unDecoratedName = unDecorate; // Destruct the heap (would use a destructor, but that causes DLL problems) heap.Destructor (); // And return the composed name return unDecoratedName; } // End of FUNCTION "unDName" // The 'UnDecorator' member functions inline __near UnDecorator::UnDecorator ( pchar_t output, pcchar_t dName, int maxLen #if ( !NO_OPTIONS ) ,unsigned short disable #endif // !NO_OPTIONS ) { FTRACE(UnDecorator::UnDecorator); #if STDEBUG if ( dName ) { while ( *dName == ' ' ) dName++; pchar_t s = gnew char[ strlen ( dName ) + 1 ]; if ( name = s ) do { if (( *s = *dName ) != ' ' ) s++; } while ( *dName++ ); } else name = 0; #else // } elif !STDEBUG { name = dName; #endif // !STDEBUG gName = name; maxStringLength = maxLen; outputString = output; pZNameList = &ZNameList; #if ( !VERS_P3 ) pArgList = &ArgList; #endif // !VERS_P3 #if ( !NO_OPTIONS ) disableFlags = disable; #endif // !NO_OPTIONS } // End of "UnDecorator" CONSTRUCTOR '()' inline __near UnDecorator::operator pchar_t () { FTRACE(UnDecorator::pchar_t); DName result; DName unDName; // Find out if the name is a decorated name or not. Could be a reserved // CodeView variant of a decorated name if ( name ) { if (( *name == '?' ) && ( name[ 1 ] == '@' )) { #if ( !NO_COMPILER_NAMES ) gName += 2; result = "CV: " + getDecoratedName (); #else // } elif NO_COMPILER_NAMES result = DN_invalid; #endif // NO_COMPILER_NAMES } // End of IF then else result = getDecoratedName (); } // End of IF then // If the name was not a valid name, then make the name the same as the original // It is also invalid if there are any remaining characters in the name if ( result.status () == DN_error ) return 0; #if ( !VERS_P3 ) elif ( *gName || ( result.status () == DN_invalid )) unDName = name; // Return the original name #else // } elif VERS_P3 { elif ( !*gName || ( *gName != '@' ) || ( result.status () == DN_invalid )) unDName = ""; // Blank #endif // VERS_P3 else unDName = result; #if ( !VERS_P3 || STANDALONE ) // Construct the return string if ( !outputString ) { maxStringLength = unDName.length () + 1; outputString = rnew char[ maxStringLength ]; } // End of IF if ( outputString ) #endif // ( !VERS_P3 || STANDALONE ) unDName.getString ( outputString, maxStringLength ); // Return the result return outputString; } // End of "UnDecorator" OPERATOR 'pchar_t' DName __near UnDecorator::getDecoratedName ( void ) { FTRACE(getDecoratedName); // Ensure that it is intended to be a decorated name if ( *gName == '?' ) { // Extract the basic symbol name gName++; // Advance the original name pointer DName symbolName = getSymbolName (); #if ( !VERS_P3 ) int udcSeen = symbolName.isUDC (); #endif // !VERS_P3 // Abort if the symbol name is invalid if ( !symbolName.isValid ()) return symbolName; // Extract, and prefix the scope qualifiers if ( *gName && ( *gName != '@' )) symbolName = getScope () + "::" + symbolName; #if ( !VERS_P3 ) if ( udcSeen ) symbolName.setIsUDC (); // Now compose declaration if ( symbolName.isEmpty ()) return symbolName; elif ( !*gName || ( *gName == '@' )) { if ( *gName ) gName++; return composeDeclaration ( symbolName ); } // End of ELIF then else return DN_invalid; #else // } elif VERS_P3 { return symbolName; #endif // VERS_P3 } // End of IF then elif ( *gName ) return DN_invalid; else return DN_truncated; } // End of "UnDecorator" FUNCTION "getDecoratedName" inline DName __near UnDecorator::getSymbolName ( void ) { FTRACE(getSymbolName); if ( *gName == '?' ) { gName++; return getOperatorName (); } // End of IF then else return getZName (); } // End of "UnDecorator" FUNCTION "getSymbolName" DName __near UnDecorator::getZName ( void ) { FTRACE(getZName); int zNameIndex = *gName - '0'; // Handle 'zname-replicators', otherwise an actual name if (( zNameIndex >= 0 ) && ( zNameIndex <= 9 )) { gName++; // Skip past the replicator // And return the indexed name return ( *pZNameList )[ zNameIndex ]; } // End of IF then else { // Extract the 'zname' to the terminator DName zName ( gName, '@' ); // This constructor updates 'name' // Add it to the current list of 'zname's if ( !pZNameList->isFull ()) *pZNameList += zName; // And return the symbol name return zName; } // End of IF else } // End of "UnDecorator" FUNCTION "getZName" inline DName __near UnDecorator::getOperatorName ( void ) { FTRACE(getOperatorName); DName operatorName; #if ( !VERS_P3 ) int udcSeen = FALSE; #endif // VERS_P3 // So what type of operator is it ? switch ( *gName++ ) { case 0: gName--; // End of string, better back-track return DN_truncated; case OC_ctor: case OC_dtor: // The constructor and destructor are special { // Use a temporary. Don't want to advance the name pointer pcchar_t pName = gName; operatorName = getZName (); gName = pName; if ( !operatorName.isEmpty () && ( gName[ -1 ] == OC_dtor )) operatorName = '~' + operatorName; return operatorName; } // End of CASE 'OC_ctor,OC_dtor' break; case OC_new: case OC_delete: case OC_assign: case OC_rshift: case OC_lshift: case OC_not: case OC_equal: case OC_unequal: operatorName = nameTable[ gName[ -1 ] - OC_new ]; break; case OC_udc: #if ( !VERS_P3 ) udcSeen = TRUE; #endif // !VERS_P3 // No break case OC_index: case OC_pointer: case OC_star: case OC_incr: case OC_decr: case OC_minus: case OC_plus: case OC_amper: case OC_ptrmem: case OC_divide: case OC_modulo: case OC_less: case OC_leq: case OC_greater: case OC_geq: case OC_comma: case OC_call: case OC_compl: case OC_xor: case OC_or: case OC_land: case OC_lor: case OC_asmul: case OC_asadd: case OC_assub: // Regular operators from the first group operatorName = nameTable[ gName[ -1 ] - OC_index + ( OC_unequal - OC_new + 1 )]; break; case '_': switch ( *gName++ ) { case 0: gName--; // End of string, better back-track return DN_truncated; case OC_asdiv: case OC_asmod: case OC_asrshift: case OC_aslshift: case OC_asand: case OC_asor: case OC_asxor: // Regular operators from the extended group operatorName = nameTable[ gName[ -1 ] - OC_asdiv + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; break; #if ( !NO_COMPILER_NAMES ) case OC_vftable: case OC_vbtable: case OC_vcall: return nameTable[ gName[ -1 ] - OC_asdiv + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; case OC_metatype: case OC_guard: case OC_uctor: case OC_udtor: case OC_vdeldtor: case OC_defctor: case OC_sdeldtor: case OC_vctor: case OC_vdtor: case OC_vallctor: // Special purpose names return nameTable[ gName[ -1 ] - OC_metatype + ( OC_vcall - OC_asdiv + 1 ) + ( OC_assub - OC_index + 1 ) + ( OC_unequal - OC_new + 1 )]; #endif // !NO_COMPILER_NAMES default: return DN_invalid; } // End of SWITCH break; default: return DN_invalid; } // End of SWITCH #if ( !VERS_P3 ) // This really is an operator name, so prefix it with 'operator' if ( udcSeen ) operatorName.setIsUDC (); elif ( !operatorName.isEmpty ()) #endif // !VERS_P3 operatorName = "operator" + operatorName; return operatorName; } // End of "UnDecorator" FUNCTION "getOperatorName" DName __near UnDecorator::getScope ( void ) { FTRACE(getScope); int first = TRUE; DName scope; // Get the list of scopes while (( scope.status () == DN_valid ) && *gName && ( *gName != '@' )) { // Insert the scope operator if not the first scope if ( first ) first = FALSE; else scope = "::" + scope; // Determine what kind of scope it is if ( *gName == '?' ) #if ( !VERS_P3 ) switch ( *++gName ) { case '?': scope = '`' + getDecoratedName () + '\'' + scope; break; case '$': #if ( !VERS_PWB ) gName++; scope = getTemplateName () + scope; break; #else // } elif VERS_PWB { return DN_invalid; #endif // VERS_PWB default: scope = getLexicalFrame () + scope; break; } // End of SWITCH #else // } elif VERS_P3 { return DN_invalid; #endif // VERS_P3 else scope = getZName () + scope; } // End of WHILE // Catch error conditions switch ( *gName ) { case 0: if ( first ) scope = DN_truncated; else scope = DName ( DN_truncated ) + "::" + scope; break; case '@': // '@' expected to end the scope list break; default: scope = DN_invalid; break; } // End of SWITCH // Return the composed scope return scope; } // End of "UnDecorator" FUNCTION "getScope" #if ( !VERS_P3 ) DName __near UnDecorator::getDimension ( void ) { FTRACE(getDimension); if ( !*gName ) return DN_truncated; elif (( *gName >= '0' ) && ( *gName <= '9' )) return DName ((unsigned long)( *gName++ - '0' + 1 )); else { unsigned long dim = 0L; // Don't bother detecting overflow, it's not worth it while ( *gName != '@' ) { if ( !*gName ) return DN_truncated; elif (( *gName >= 'A' ) && ( *gName <= 'P' )) dim = ( dim << 4 ) + ( *gName - 'A' ); else return DN_invalid; gName++; } // End of WHILE // Ensure integrity, and return if ( *gName++ != '@' ) return DN_invalid; // Should never get here return dim; } // End of ELIF else } // End of "UnDecorator" FUNCTION "getDimension" inline_pwb int __near UnDecorator::getNumberOfDimensions ( void ) { FTRACE(getNumberOfDimensions); if ( !*gName ) return 0; elif (( *gName >= '0' ) && ( *gName <= '9' )) return (( *gName++ - '0' ) + 1 ); else { int dim = 0; // Don't bother detecting overflow, it's not worth it while ( *gName != '@' ) { if ( !*gName ) return 0; elif (( *gName >= 'A' ) && ( *gName <= 'P' )) dim = ( dim << 4 ) + ( *gName - 'A' ); else return -1; gName++; } // End of WHILE // Ensure integrity, and return if ( *gName++ != '@' ) return -1; // Should never get here return dim; } // End of ELIF else } // End of "UnDecorator" FUNCTION "getNumberOfDimensions" #if ( !VERS_PWB ) DName __near UnDecorator::getTemplateName ( void ) { FTRACE(getTemplateName); DName templateName = "template " + getZName (); if ( !templateName.isEmpty ()) templateName += '<' + getArgumentList () + '>'; // Return the completed 'template-name' return templateName; } // End of "UnDecorator" FUNCTION "getTemplateName" #endif // !VERS_PWB #if defined(COFF) //inline DName __near UnDecorator::composeDeclaration ( const DName & symbol ) // // The above line was replaced by the line below because the COFF linker // can't handle COMDATs // DName __near UnDecorator::composeDeclaration ( const DName & symbol ) #else inline DName __near UnDecorator::composeDeclaration ( const DName & symbol ) #endif { FTRACE(composeDeclaration); DName declaration; unsigned int typeCode = getTypeEncoding (); int symIsUDC = symbol.isUDC (); // Handle bad typeCode's, or truncation if ( TE_isbadtype ( typeCode )) return DN_invalid; elif ( TE_istruncated ( typeCode )) return ( DN_truncated + symbol ); // This is a very complex part. The type of the declaration must be // determined, and the exact composition must be dictated by this type. // Is it any type of a function ? // However, for ease of decoding, treat the 'localdtor' thunk as data, since // its decoration is a function of the variable to which it belongs and not // a usual function type of decoration. #if ( NO_COMPILER_NAMES ) if ( TE_isthunk ( typeCode )) return DN_invalid; if ( TE_isfunction ( typeCode )) #else // } elif !NO_COMPILER_NAMES { if ( TE_isfunction ( typeCode ) && !( TE_isthunk ( typeCode ) && TE_islocaldtor ( typeCode ))) #endif // !NO_COMPILER_NAMES { // If it is based, then compose the 'based' prefix for the name if ( TE_isbased ( typeCode )) #if ( !VERS_PWB ) if ( doMSKeywords () && doAllocationModel ()) declaration = ' ' + getBasedType (); else #endif // !VERS_PWB declaration |= getBasedType (); // Just lose the 'based-type' #if ( !NO_COMPILER_NAMES ) // Check for some of the specially composed 'thunk's if ( TE_isthunk ( typeCode ) && TE_isvcall ( typeCode )) { declaration += symbol + '{' + getCallIndex () + ','; declaration += getVCallThunkType () + "}' "; } // End of IF then else #endif // !NO_COMPILER_NAMES { DName vtorDisp; DName adjustment; DName thisType; #if ( !NO_COMPILER_NAMES ) if ( TE_isthunk ( typeCode )) { if ( TE_isvtoradj ( typeCode )) vtorDisp = getDisplacement (); adjustment = getDisplacement (); } // End of IF else #endif // !NO_COMPILER_NAMES // Get the 'this-type' for non-static function members if ( TE_ismember ( typeCode ) && !TE_isstatic ( typeCode )) #if ( !VERS_PWB ) if ( doThisTypes ()) thisType = getThisType (); else #endif // !VERS_PWB thisType |= getThisType (); #if ( !VERS_PWB ) if ( doMSKeywords ()) { // Attach the calling convention if ( doAllocationLanguage ()) declaration = getCallingConvention () + declaration; // What calling convention ? else declaration |= getCallingConvention (); // Just lose the 'calling-convention' // Any model specifiers ? if ( doAllocationModel ()) if ( TE_isnear ( typeCode )) declaration = UScore ( TOK_nearSp ) + declaration; elif ( TE_isfar ( typeCode )) declaration = UScore ( TOK_farSp ) + declaration; } // End of IF else #endif // !VERS_PWB declaration |= getCallingConvention (); // Just lose the 'calling-convention' // Now put them all together if ( !symbol.isEmpty ()) if ( !declaration.isEmpty ()) // And the symbol name declaration += ' ' + symbol; else declaration = symbol; // Compose the return type, catching the UDC case DName * pDeclarator = 0; DName returnType; if ( symIsUDC ) // Is the symbol a UDC operator ? declaration += "`" + getReturnType () + "' "; else { pDeclarator = gnew DName; returnType = getReturnType ( pDeclarator ); } // End of IF else #if ( !NO_COMPILER_NAMES ) // Add the displacements for virtual function thunks if ( TE_isthunk ( typeCode )) { if ( TE_isvtoradj ( typeCode )) declaration += "`vtordisp{" + vtorDisp + ','; else declaration += "`adjustor{"; declaration += adjustment + "}' "; } // End of IF #endif // !NO_COMPILER_NAMES // Add the function argument prototype declaration += '(' + getArgumentTypes () + ')'; // If this is a non-static member function, append the 'this' modifiers if ( TE_ismember ( typeCode ) && !TE_isstatic ( typeCode )) declaration += thisType; // Add the 'throw' signature #if ( !VERS_PWB ) if ( doThrowTypes ()) declaration += getThrowTypes (); else #endif // !VERS_PWB declaration |= getThrowTypes (); // Just lose the 'throw-types' #if ( !VERS_PWB ) // If it has a declarator, then insert it into the declaration, // sensitive to the return type composition if ( doFunctionReturns () && pDeclarator ) { *pDeclarator = declaration; declaration = returnType; } // End of IF #endif // !VERS_PWB } // End of IF else } // End of IF then else { declaration += symbol; // Catch the special handling cases #if ( !NO_COMPILER_NAMES ) if ( TE_isvftable ( typeCode )) return getVfTableType ( declaration ); elif ( TE_isvbtable ( typeCode )) return getVbTableType ( declaration ); elif ( TE_isguard ( typeCode )) return ( declaration + '{' + getGuardNumber () + "}'" ); elif ( TE_isthunk ( typeCode ) && TE_islocaldtor ( typeCode )) declaration += "`local static destructor helper'"; elif ( TE_ismetaclass ( typeCode )) #pragma message ( "NYI: Meta Class" ) #else // } elif NO_COMPILER_NAMES { if ( TE_isvftable ( typeCode ) || TE_isvbtable ( typeCode ) || TE_isguard ( typeCode ) || TE_ismetaclass ( typeCode )) #endif // NO_COMPILER_NAMES return DN_invalid; // All others are decorated as data symbols declaration = getExternalDataType ( declaration ); } // End of IF else #if ( !VERS_PWB ) // Prepend the 'virtual' and 'static' attributes for members if ( TE_ismember ( typeCode )) { if ( doMemberTypes ()) { if ( TE_isstatic ( typeCode )) declaration = "static " + declaration; if ( TE_isvirtual ( typeCode ) || ( TE_isthunk ( typeCode ) && ( TE_isvtoradj ( typeCode ) || TE_isadjustor ( typeCode )))) declaration = "virtual " + declaration; } // End of IF // Prepend the access specifiers if ( doAccessSpecifiers ()) if ( TE_isprivate ( typeCode )) declaration = "private: " + declaration; elif ( TE_isprotected ( typeCode )) declaration = "protected: " + declaration; elif ( TE_ispublic ( typeCode )) declaration = "public: " + declaration; } // End of IF #endif // !VERS_PWB #if ( !NO_COMPILER_NAMES ) // If it is a thunk, mark it appropriately if ( TE_isthunk ( typeCode )) declaration = "[thunk]:" + declaration; #endif // !NO_COMPILER_NAMES // Return the composed declaration return declaration; } // End of "UnDecorator" FUNCTION "composeDeclaration" inline int __near UnDecorator::getTypeEncoding ( void ) { FTRACE(getTypeEncoding); unsigned int typeCode = 0u; // Strip any leading '_' which indicates that it is based if ( *gName == '_' ) { TE_setisbased ( typeCode ); gName++; } // End of IF // Now handle the code proper :- if (( *gName >= 'A' ) && ( *gName <= 'Z' )) // Is it some sort of function ? { int code = *gName++ - 'A'; // Now determine the function type TE_setisfunction ( typeCode ); // All of them are functions ? // Determine the calling model if ( code & TE_far ) TE_setisfar ( typeCode ); else TE_setisnear ( typeCode ); // Is it a member function or not ? if ( code < TE_external ) { // Record the fact that it is a member TE_setismember ( typeCode ); // What access permissions does it have switch ( code & TE_access ) { case TE_private: TE_setisprivate ( typeCode ); break; case TE_protect: TE_setisprotected ( typeCode ); break; case TE_public: TE_setispublic ( typeCode ); break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH // What type of a member function is it ? switch ( code & TE_adjustor ) { case TE_adjustor: TE_setisadjustor ( typeCode ); break; case TE_virtual: TE_setisvirtual ( typeCode ); break; case TE_static: TE_setisstatic ( typeCode ); break; case TE_member: break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH } // End of IF } // End of IF then elif ( *gName == '$' ) // Extended set ? Special handling { // What type of symbol is it ? switch ( *( ++gName )) { case 'A': // A destructor helper for a local static ? TE_setislocaldtor ( typeCode ); break; case 'B': // A VCall-thunk ? TE_setisvcall ( typeCode ); break; case 0: TE_setistruncated ( typeCode ); break; case '0': case '1': case '2': case '3': case '4': case '5': // Construction displacement adjustor thunks { int code = *gName - '0'; // Set up the principal type information TE_setisfunction ( typeCode ); TE_setismember ( typeCode ); TE_setisvtoradj ( typeCode ); // Is it 'near' or 'far' ? if ( code & TE_far ) TE_setisfar ( typeCode ); else TE_setisnear ( typeCode ); // What type of access protection ? switch ( code & TE_access_vadj ) { case TE_private_vadj: TE_setisprivate ( typeCode ); break; case TE_protect_vadj: TE_setisprotected ( typeCode ); break; case TE_public_vadj: TE_setispublic ( typeCode ); break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH } // End of CASE '0,1,2,3,4,5' break; default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH // Advance past the code character gName++; } // End of ELIF then elif (( *gName >= TE_static_d ) && ( *gName <= TE_metatype )) // Non function decorations ? { int code = *gName++; TE_setisdata ( typeCode ); // What type of symbol is it ? switch ( code ) { case ( TE_static_d | TE_private_d ): TE_setisstatic ( typeCode ); TE_setisprivate ( typeCode ); break; case ( TE_static_d | TE_protect_d ): TE_setisstatic ( typeCode ); TE_setisprotected ( typeCode ); break; case ( TE_static_d | TE_public_d ): TE_setisstatic ( typeCode ); TE_setispublic ( typeCode ); break; case TE_global: TE_setisglobal ( typeCode ); break; #if ( !VERS_PWB ) case TE_guard: TE_setisguard ( typeCode ); break; case TE_local: TE_setislocal ( typeCode ); break; case TE_vftable: TE_setisvftable ( typeCode ); break; case TE_vbtable: TE_setisvbtable ( typeCode ); break; case TE_metatype: #pragma message ( "NYI: MetaClass Information" ) #else // } elif VERS_PWB { case TE_guard: case TE_local: case TE_vftable: case TE_vbtable: case TE_metatype: #endif // VERS_PWB default: TE_setisbadtype ( typeCode ); return typeCode; } // End of SWITCH } // End of ELIF then elif ( *gName ) TE_setisbadtype ( typeCode ); else TE_setistruncated ( typeCode ); // Return the composed type code return typeCode; } // End of "UnDecorator" FUNCTION "getTypeEncoding" DName __near UnDecorator::getBasedType ( void ) { FTRACE(getBasedType); #if ( !VERS_PWB ) DName basedDecl ( UScore ( TOK_basedLp )); #else // } elif VERS_PWB { DName basedDecl; #endif // VERS_PWB // What type of 'based' is it ? if ( *gName ) { switch ( *gName++ ) { #if ( !VERS_PWB ) case BT_segname: basedDecl += UScore ( TOK_segnameLpQ ) + getSegmentName () + "\")"; break; case BT_segment: basedDecl += DName ( "NYI:" ) + UScore ( TOK_segment ); break; case BT_void: basedDecl += "void"; break; case BT_self: basedDecl += UScore ( TOK_self ); break; case BT_nearptr: basedDecl += DName ( "NYI:" ) + UScore ( TOK_nearP ); break; case BT_farptr: basedDecl += DName ( "NYI:" ) + UScore ( TOK_farP ); break; case BT_hugeptr: basedDecl += DName ( "NYI:" ) + UScore ( TOK_hugeP ); break; case BT_segaddr: basedDecl += "NYI:"; break; #else // } elif VERS_PWB { case BT_segname: basedDecl |= getZName (); break; case BT_segment: case BT_void: case BT_self: case BT_nearptr: case BT_farptr: case BT_hugeptr: case BT_segaddr: break; #endif // VERS_PWB case BT_basedptr: #pragma message ( "NOTE: Reserved. Based pointer to based pointer" ) return DN_invalid; } // End of SWITCH } // End of IF else else basedDecl += DN_truncated; #if ( !VERS_PWB ) // Close the based syntax basedDecl += ") "; #endif // !VERS_PWB // Return completed based declaration return basedDecl; } // End of "UnDecorator" FUNCTION "getBasedType" DName __near UnDecorator::getECSUName ( void ) { FTRACE(getECSUName); DName ecsuName; // Get the beginning of the name if ( *gName == '?' ) { #if ( !VERS_PWB ) gName++; ecsuName = getTemplateName (); #else // } elif VERS_PWB { return DN_invalid; #endif // VERS_PWB } // End of IF then else ecsuName = getZName (); // Now the scope (if any) if (( ecsuName.status () == DN_valid ) && *gName && ( *gName != '@' )) ecsuName = getScope () + "::" + ecsuName; // Skip the trailing '@' if ( *gName == '@' ) gName++; elif ( *gName ) ecsuName = DN_invalid; elif ( ecsuName.isEmpty ()) ecsuName = DN_truncated; else ecsuName = DName ( DN_truncated ) + "::" + ecsuName; // And return the complete name return ecsuName; } // End of "UnDecorator" FUNCTION "getECSUName" inline DName __near UnDecorator::getEnumName ( void ) { FTRACE(getEnumName); #if ( !VERS_PWB ) DName ecsuName; #endif // !VERS_PWB if ( *gName ) { #if ( !VERS_PWB ) // What type of an 'enum' is it ? switch ( *gName ) { case ET_schar: case ET_uchar: ecsuName = "char "; break; case ET_sshort: case ET_ushort: ecsuName = "short "; break; case ET_sint: break; case ET_uint: ecsuName = "int "; break; case ET_slong: case ET_ulong: ecsuName = "long "; break; default: return DN_invalid; } // End of SWITCH // Add the 'unsigned'ness if appropriate switch ( *gName++ ) { case ET_uchar: case ET_ushort: case ET_uint: case ET_ulong: ecsuName = "unsigned " + ecsuName; break; } // End of SWITCH // Now return the composed name return ecsuName + getECSUName (); #else // } elif VERS_PWB { if ( *gName++ == ET_sint ) return getECSUName (); else return DN_invalid; #endif // VERS_PWB } // End of IF then else return DN_truncated; } // End of "UnDecorator" FUNCTION "getEnumName" DName __near UnDecorator::getCallingConvention ( void ) { FTRACE(getCallingConvention); if ( *gName ) { unsigned int callCode = ((unsigned int)*gName++ ) - 'A'; // What is the primary calling convention if (( callCode <= CC_interrupt )) { #if ( !VERS_PWB ) DName callType; // Now, what type of 'calling-convention' is it, 'interrupt' is special ? if ( doMSKeywords ()) if ( callCode == CC_interrupt ) callType = UScore ( TOK_interrupt ); else { switch ( callCode & ~CC_saveregs ) { case CC_cdecl: callType = UScore ( TOK_cdecl ); break; case CC_pascal: callType = UScore ( TOK_pascal ); break; case CC_syscall: callType = UScore ( TOK_syscall ); break; case CC_stdcall: callType = UScore ( TOK_stdcall ); break; case CC_fastcall: callType = UScore ( TOK_fastcall ); break; } // End of SWITCH // Has it also got 'saveregs' marked ? if ( callCode & CC_saveregs ) callType += ' ' + UScore ( TOK_saveregs ); } // End of IF else // And return return callType; #else // } elif VERS_PWB { return DN_valid; #endif // VERS_PWB } // End of IF then else return DN_invalid; } // End of IF then else return DN_truncated; } // End of "UnDecorator" FUNCTION "getCallingConvention" DName __near UnDecorator::getReturnType ( DName * pDeclarator ) { FTRACE(getReturnType); if ( *gName == '@' ) // Return type for constructors and destructors ? { gName++; return DName ( pDeclarator ); } // End of IF then else return getDataType ( pDeclarator ); } // End of "UnDecorator" FUNCTION "getReturnType" DName __near UnDecorator::getDataType ( DName * pDeclarator ) { FTRACE(getDataType); DName superType ( pDeclarator ); // What type is it ? switch ( *gName ) { case 0: return ( DN_truncated + superType ); case DT_void: gName++; if ( superType.isEmpty ()) return "void"; else return "void " + superType; case '?': { int ecsuMods; gName++; // Skip the '?' ecsuMods = getECSUDataIndirectType (); superType = getECSUDataType ( ecsuMods ) + ' ' + superType; return superType; } // End of CASE '?' default: return getPrimaryDataType ( superType ); } // End of SWITCH } // End of "UnDecorator" FUNCTION "getDataType" DName __near UnDecorator::getPrimaryDataType ( const DName & superType ) { FTRACE(getPrimaryDataType); DName cvType; switch ( *gName ) { case 0: return ( DN_truncated + superType ); case PDT_volatileReference: cvType = "volatile"; if ( !superType.isEmpty ()) cvType += ' '; // No break case PDT_reference: { DName super ( superType ); gName++; return getReferenceType ( cvType, super.setPtrRef ()); } // End of CASE 'PDT_reference' default: return getBasicDataType ( superType ); } // End of SWITCH } // End of "UnDecorator" FUNCTION "getPrimaryDataType" DName __near UnDecorator::getArgumentTypes ( void ) { FTRACE(getArgumentTypes); switch ( *gName ) { case AT_ellipsis: return ( gName++, "..." ); case AT_void: #if ( !VERS_PWB ) return ( gName++, "void" ); #else // } elif VERS_PWB { return ( gName++, DName ()); #endif // VERS_PWB default: { DName arguments ( getArgumentList ()); // Now, is it a varargs function or not ? if ( arguments.status () == DN_valid ) switch ( *gName ) { case 0: return arguments; case AT_ellipsis: return ( gName++, arguments + ",..." ); case AT_endoflist: return ( gName++, arguments ); default: return DN_invalid; } // End of SWITCH else return arguments; } // End of DEFAULT } // End of SWITCH } // End of "UnDecorator" FUNCTION "getArgumentTypes" inline_pwb DName __near UnDecorator::getArgumentList ( void ) { FTRACE(getArgumentList); int first = TRUE; DName aList; while (( aList.status () == DN_valid ) && ( *gName != AT_endoflist ) && ( *gName != AT_ellipsis )) { // Insert the argument list separator if not the first argument if ( first ) first = FALSE; else aList += ','; // Get the individual argument type if ( *gName ) { int argIndex = *gName - '0'; // Handle 'argument-replicators', otherwise a new argument type if (( argIndex >= 0 ) && ( argIndex <= 9 )) { gName++; // Skip past the replicator // Append to the argument list aList += ( *pArgList )[ argIndex ]; } // End of IF then else { // Extract the 'argument' type DName arg ( getPrimaryDataType ( DName ())); // Add it to the current list of 'argument's if ( !pArgList->isFull ()) *pArgList += arg; // Append to the argument list aList += arg; } // End of IF else } // End of IF then else { aList += DN_truncated; break; } // End of IF else } // End of WHILE // Return the completed argument list return aList; } // End of "UnDecorator" FUNCTION "getArgumentList" DName __near UnDecorator::getThrowTypes ( void ) { FTRACE(getThrowTypes); if ( *gName ) #if ( !VERS_PWB ) if ( *gName == AT_ellipsis ) // Handle ellipsis here to suppress the 'throw' signature return ( gName++, DName ()); else return ( " throw(" + getArgumentTypes () + ')' ); else return ( DName ( " throw(" ) + DN_truncated + ')' ); #else // } elif VERS_PWB { if ( *gName++ == AT_ellipsis ) return DName (); else return DN_invalid; else return DN_truncated; #endif // VERS_PWB } // End of "UnDecorator" FUNCTION "getThrowTypes" DName __near UnDecorator::getBasicDataType ( const DName & superType ) { FTRACE(getBasicDataType); if ( *gName ) { unsigned char bdtCode = *gName++; int pCvCode = -1; DName basicDataType; // Extract the principal type information itself, and validate the codes switch ( bdtCode ) { case BDT_schar: case BDT_char: case ( BDT_char | BDT_unsigned ): basicDataType = "char"; break; case BDT_short: case ( BDT_short | BDT_unsigned ): basicDataType = "short"; break; case BDT_int: case ( BDT_int | BDT_unsigned ): basicDataType = "int"; break; case BDT_long: case ( BDT_long | BDT_unsigned ): basicDataType = "long"; break; case BDT_segment: #if ( !VERS_PWB ) basicDataType = UScore ( TOK_segment ); #else // } elif VERS_PWB { basicDataType = "__segment"; #endif // VERS_PWB break; case BDT_float: basicDataType = "float"; break; case BDT_longdouble: basicDataType = "long "; // No break case BDT_double: basicDataType += "double"; break; case BDT_pointer: case ( BDT_pointer | BDT_const ): case ( BDT_pointer | BDT_volatile ): case ( BDT_pointer | BDT_const | BDT_volatile ): pCvCode = ( bdtCode & ( BDT_const | BDT_volatile )); break; default: gName--; // Backup, since 'ecsu-data-type' does it's own decoding basicDataType = getECSUDataType (); if ( basicDataType.isEmpty ()) return basicDataType; break; } // End of SWITCH // What type of basic data type composition is involved ? if ( pCvCode == -1 ) // Simple ? { // Determine the 'signed/unsigned'ness switch ( bdtCode ) { case ( BDT_char | BDT_unsigned ): case ( BDT_short | BDT_unsigned ): case ( BDT_int | BDT_unsigned ): case ( BDT_long | BDT_unsigned ): basicDataType = "unsigned " + basicDataType; break; case BDT_schar: basicDataType = "signed " + basicDataType; break; } // End of SWITCH // Add the indirection type to the type if ( !superType.isEmpty ()) basicDataType += ' ' + superType; // And return the completed type return basicDataType; } // End of IF then else { DName cvType; DName super ( superType ); // Is it 'const/volatile' qualified ? if ( pCvCode & BDT_const ) { cvType = "const"; if ( pCvCode & BDT_volatile ) cvType += " volatile"; } // End of IF then elif ( pCvCode & BDT_volatile ) cvType = "volatile"; // Construct the appropriate pointer type declaration return getPointerType ( cvType, super.setPtrRef ()); } // End of IF else } // End of IF then else return ( DN_truncated + superType ); } // End of "UnDecorator" FUNCTION "getBasicDataType" DName __near UnDecorator::getECSUDataType ( int ecsuMods ) { FTRACE(getECSUDataType); DName ecsuDataType; // Get the 'model' modifiers if applicable if ( ecsuMods ) if ( ecsuMods == ECSU_invalid ) return DN_invalid; elif ( ecsuMods == ECSU_truncated ) ecsuDataType = DN_truncated; #if ( !VERS_PWB ) else switch ( ecsuMods & ECSU_modelmask ) { case ECSU_near: if ( doMSKeywords () && doReturnUDTModel ()) ecsuDataType = UScore ( TOK_nearSp ); break; case ECSU_far: if ( doMSKeywords () && doReturnUDTModel ()) ecsuDataType = UScore ( TOK_farSp ); break; case ECSU_huge: if ( doMSKeywords () && doReturnUDTModel ()) ecsuDataType = UScore ( TOK_hugeSp ); break; case ECSU_based: if ( doMSKeywords () && doReturnUDTModel ()) ecsuDataType = getBasedType (); else ecsuDataType |= getBasedType (); // Just lose the 'based-type' break; } // End of SWITCH #else // } elif VERS_PWB { elif (( ecsuMods & ECSU_modelmask ) == ECSU_based ) ecsuDataType |= getBasedType (); #endif // VERS_PWB // Extract the principal type information itself, and validate the codes switch ( *gName++ ) { case 0: gName--; // Backup to permit later error recovery to work safely return "`unknown ecsu'" + ecsuDataType + DN_truncated; case BDT_union: if ( 1 ) // Non-redundant control flow trick ecsuDataType = "union " + ecsuDataType; else case BDT_struct: if ( 1 ) // Non-redundant control flow trick ecsuDataType = "struct " + ecsuDataType; else case BDT_class: if ( 1 ) // Non-redundant control flow trick ecsuDataType = "class " + ecsuDataType; // Get the UDT 'const/volatile' modifiers if applicable // Get the 'class/struct/union' name ecsuDataType += getECSUName (); break; case BDT_enum: ecsuDataType = "enum " + ecsuDataType + getEnumName (); break; default: return DN_invalid; } // End of SWITCH // And return the formed 'ecsu-data-type' return ecsuDataType; } // End of "UnDecorator" FUNCTION "getECSUDataType" DName __near UnDecorator::getPtrRefType ( const DName & cvType, const DName & superType, int isPtr ) { FTRACE(getPtrRefType); // Doubles up as 'pointer-type' and 'reference-type' if ( *gName ) if ( IT_isfunction ( *gName )) // Is it a function or data indirection ? { // Since I haven't coded a discrete 'function-type', both // 'function-indirect-type' and 'function-type' are implemented // inline under this condition. int fitCode = *gName++ - '6'; if ( fitCode == ( '_' - '6' )) { if ( *gName ) { fitCode = *gName++ - 'A' + FIT_based; if (( fitCode < FIT_based ) || ( fitCode > ( FIT_based | FIT_far | FIT_member ))) fitCode = -1; } // End of IF then else return ( DN_truncated + superType ); } // End of IF then elif (( fitCode < FIT_near ) || ( fitCode > ( FIT_far | FIT_member ))) fitCode = -1; // Return if invalid name if ( fitCode == -1 ) return DN_invalid; // Otherwise, what are the function indirect attributes DName thisType; DName fitType = ( isPtr ? '*' : '&' ); if ( !cvType.isEmpty () && ( superType.isEmpty () || superType.isPtrRef ())) fitType += cvType; if ( !superType.isEmpty ()) fitType += superType; // Is it a pointer to member function ? if ( fitCode & FIT_member ) { fitType = "::" + fitType; if ( *gName ) fitType = ' ' + getScope (); else fitType = DN_truncated + fitType; if ( *gName ) if ( *gName == '@' ) gName++; else return DN_invalid; else return ( DN_truncated + fitType ); #if ( !VERS_PWB ) if ( doThisTypes ()) thisType = getThisType (); else #endif // !VERS_PWB thisType |= getThisType (); } // End of IF // Is it a based allocated function ? if ( fitCode & FIT_based ) #if ( !VERS_PWB ) if ( doMSKeywords ()) fitType = ' ' + getBasedType () + fitType; else #endif // !VERS_PWB fitType |= getBasedType (); // Just lose the 'based-type' // Get the 'calling-convention' #if ( !VERS_PWB ) if ( doMSKeywords ()) { fitType = getCallingConvention () + fitType; // Is it a near or far function pointer fitType = UScore ((( fitCode & FIT_far ) ? TOK_farSp : TOK_nearSp )) + fitType; } // End of IF then else #endif // !VERS_PWB fitType |= getCallingConvention (); // Just lose the 'calling-convention' // Parenthesise the indirection component, and work on the rest fitType = '(' + fitType + ')'; // Get the rest of the 'function-type' pieces DName * pDeclarator = gnew DName; DName returnType ( getReturnType ( pDeclarator )); fitType += '(' + getArgumentTypes () + ')'; #if ( !VERS_PWB ) if ( doThisTypes () && ( fitCode & FIT_member )) fitType += thisType; if ( doThrowTypes ()) fitType += getThrowTypes (); else #endif // !VERS_PWB fitType |= getThrowTypes (); // Just lose the 'throw-types' // Now insert the indirected declarator, catch the allocation failure here if ( pDeclarator ) *pDeclarator = fitType; else return ERROR; // And return the composed function type (now in 'returnType' ) return returnType; } // End of IF then else { // Otherwise, it is either a pointer or a reference to some data type DName innerType ( getDataIndirectType ( superType, ( isPtr ? '*' : '&' ), cvType )); return getPtrRefDataType ( innerType, isPtr ); } // End of IF else else { DName trunk ( DN_truncated ); trunk += ( isPtr ? '*' : '&' ); if ( !cvType.isEmpty ()) trunk += cvType; if ( !superType.isEmpty ()) { if ( !cvType.isEmpty ()) trunk += ' '; trunk += superType; } // End of IF return trunk; } // End of IF else } // End of "UnDecorator" FUNCTION "getPtrRefType" DName __near UnDecorator::getDataIndirectType ( const DName & superType, char prType, const DName & cvType, int thisFlag ) { FTRACE(getDataIndirectType); if ( *gName ) { unsigned int ditCode = ( *gName - (( *gName >= 'A' ) ? (unsigned int)'A': (unsigned int)( '0' - 26 ))); gName++; // Skip to next character in name // Is it a valid 'data-indirection-type' ? if (( ditCode <= ( DIT_const | DIT_volatile | DIT_modelmask | DIT_member ))) { DName ditType ( prType ); // If it is a member, then these attributes immediately precede the indirection token if ( ditCode & DIT_member ) { // If it is really 'this-type', then it cannot be any form of pointer to member if ( thisFlag ) return DN_invalid; // Otherwise, extract the scope for the PM ditType = "::" + ditType; if ( *gName ) ditType = ' ' + getScope (); else ditType = DN_truncated + ditType; // Now skip the scope terminator if ( !*gName ) ditType += DN_truncated; elif ( *gName++ != '@' ) return DN_invalid; } // End of IF #if ( !VERS_PWB ) // Add the 'model' attributes (prefixed) as appropriate if ( doMSKeywords ()) switch ( ditCode & DIT_modelmask ) { case DIT_near: ditType = UScore ( TOK_near ) + ditType; break; case DIT_far: ditType = UScore ( TOK_far ) + ditType; break; case DIT_huge: ditType = UScore ( TOK_huge ) + ditType; break; case DIT_based: // The 'this-type' can never be 'based' if ( thisFlag ) return DN_invalid; ditType = getBasedType () + ditType; break; } // End of SWITCH elif (( ditCode & DIT_modelmask ) == DIT_based ) #else // } elif VERS_PWB { if (( ditCode & DIT_modelmask ) == DIT_based ) #endif // VERS_PWB ditType |= getBasedType (); // Just lose the 'based-type' // Handle the 'const' and 'volatile' attributes if ( ditCode & DIT_volatile ) ditType = "volatile " + ditType; if ( ditCode & DIT_const ) ditType = "const " + ditType; // Append the supertype, if not 'this-type' if ( !thisFlag ) if ( !superType.isEmpty ()) { // Is the super context included 'cv' information, ensure that it is added appropriately if ( superType.isPtrRef () || cvType.isEmpty ()) ditType += ' ' + superType; else ditType += ' ' + cvType + ' ' + superType; } // End of IF then elif ( !cvType.isEmpty ()) ditType += ' ' + cvType; // Finally, return the composed 'data-indirection-type' (with embedded sub-type) return ditType; } // End of IF then else return DN_invalid; } // End of IF then elif ( !thisFlag && !superType.isEmpty ()) { // Is the super context included 'cv' information, ensure that it is added appropriately if ( superType.isPtrRef () || cvType.isEmpty ()) return ( DN_truncated + superType ); else return ( DN_truncated + cvType + ' ' + superType ); } // End of ELIF then elif ( !thisFlag && !cvType.isEmpty ()) return ( DN_truncated + cvType ); else return DN_truncated; } // End of "UnDecorator" FUNCTION "getDataIndirectType" inline int __near UnDecorator::getECSUDataIndirectType () { FTRACE(getECSUDataIndirectType); if ( *gName ) { unsigned int ecsuCode = *gName++ - 'A'; // Is it a valid 'ecsu-data-indirection-type' ? if (( ecsuCode <= ( ECSU_const | ECSU_volatile | ECSU_modelmask ))) return ( ecsuCode | ECSU_valid ); else return ECSU_invalid; } // End of IF then else return ECSU_truncated; } // End of "UnDecorator" FUNCTION "getECSUDataIndirectType" inline DName __near UnDecorator::getPtrRefDataType ( const DName & superType, int isPtr ) { FTRACE(getPtrRefDataType); // Doubles up as 'pointer-data-type' and 'reference-data-type' if ( *gName ) { // Is this a 'pointer-data-type' ? if ( isPtr && ( *gName == PoDT_void )) { gName++; // Skip this character if ( superType.isEmpty ()) return "void"; else return "void " + superType; } // End of IF // Otherwise it may be a 'reference-data-type' if ( *gName == RDT_array ) // An array ? { DName * pDeclarator = gnew DName; if ( !pDeclarator ) return ERROR; gName++; DName theArray ( getArrayType ( pDeclarator )); if ( !theArray.isEmpty ()) *pDeclarator = superType; // And return it return theArray; } // End of IF // Otherwise, it is a 'basic-data-type' return getBasicDataType ( superType ); } // End of IF then else return ( DN_truncated + superType ); } // End of "UnDecorator" FUNCTION "getPtrRefDataType" inline DName __near UnDecorator::getArrayType ( DName * pDeclarator ) { FTRACE(getArrayType); DName superType ( pDeclarator ); if ( *gName ) { int noDimensions = getNumberOfDimensions (); if ( !noDimensions ) return getBasicDataType ( DName ( '[' ) + DN_truncated + ']' ); else { DName arrayType; while ( noDimensions-- ) arrayType += '[' + getDimension () + ']'; // If it is indirect, then parenthesise the 'super-type' if ( !superType.isEmpty ()) arrayType = '(' + superType + ')' + arrayType; // Return the finished array dimension information return getBasicDataType ( arrayType ); } // End of IF else } // End of IF elif ( !superType.isEmpty ()) return getBasicDataType ( '(' + superType + ")[" + DN_truncated + ']' ); else return getBasicDataType ( DName ( '[' ) + DN_truncated + ']' ); } // End of "UnDecorator" FUNCTION "getArrayType" inline DName __near UnDecorator::getLexicalFrame ( void ) { return '`' + getDimension () + '\''; } inline DName __near UnDecorator::getStorageConvention ( void ) { return getDataIndirectType (); } inline DName __near UnDecorator::getDataIndirectType () { return getDataIndirectType ( DName (), 0, DName ()); } inline_lnk DName __near UnDecorator::getThisType ( void ) { return getDataIndirectType ( DName (), 0, DName (), TRUE ); } inline DName __near UnDecorator::getPointerType ( const DName & cv, const DName & name ) { return getPtrRefType ( cv, name, TRUE ); } inline DName __near UnDecorator::getReferenceType ( const DName & cv, const DName & name ) { return getPtrRefType ( cv, name, FALSE ); } #if ( !VERS_PWB ) inline DName __near UnDecorator::getSegmentName ( void ) { return getZName (); } #endif // !VERS_PWB #if ( !NO_COMPILER_NAMES ) inline DName __near UnDecorator::getDisplacement ( void ) { return getDimension (); } inline DName __near UnDecorator::getCallIndex ( void ) { return getDimension (); } inline DName __near UnDecorator::getGuardNumber ( void ) { return getDimension (); } inline DName __near UnDecorator::getVbTableType ( const DName & superType ) { return getVfTableType ( superType ); } inline DName __near UnDecorator::getVCallThunkType ( void ) { FTRACE(UnDecorator::getVCallThunkType); DName vcallType = '{'; // Get the 'this' model, and validate all values switch ( *gName ) { case VMT_nTnCnV: case VMT_nTfCnV: case VMT_nTnCfV: case VMT_nTfCfV: case VMT_nTnCbV: case VMT_nTfCbV: vcallType += UScore ( TOK_nearSp ); break; case VMT_fTnCnV: case VMT_fTfCnV: case VMT_fTnCfV: case VMT_fTfCfV: case VMT_fTnCbV: case VMT_fTfCbV: vcallType += UScore ( TOK_farSp ); break; case 0: return DN_truncated; default: return DN_invalid; } // End of SWITCH // Always append 'this' vcallType += "this, "; // Get the 'call' model switch ( *gName ) { case VMT_nTnCnV: case VMT_fTnCnV: case VMT_nTnCfV: case VMT_fTnCfV: case VMT_nTnCbV: case VMT_fTnCbV: vcallType += UScore ( TOK_nearSp ); break; case VMT_nTfCnV: case VMT_fTfCnV: case VMT_nTfCfV: case VMT_fTfCfV: case VMT_nTfCbV: case VMT_fTfCbV: vcallType += UScore ( TOK_farSp ); break; } // End of SWITCH // Always append 'call' vcallType += "call, "; // Get the 'vfptr' model switch ( *gName++ ) // Last time, so advance the pointer { case VMT_nTnCnV: case VMT_nTfCnV: case VMT_fTnCnV: case VMT_fTfCnV: vcallType += UScore ( TOK_nearSp ); break; case VMT_nTnCfV: case VMT_nTfCfV: case VMT_fTnCfV: case VMT_fTfCfV: vcallType += UScore ( TOK_farSp ); break; case VMT_nTnCbV: case VMT_nTfCbV: case VMT_fTnCbV: case VMT_fTfCbV: vcallType += getBasedType (); break; } // End of SWITCH // Always append 'vfptr' vcallType += "vfptr}"; // And return the resultant 'vcall-model-type' return vcallType; } // End of "UnDecorator" FUNCTION "getVCallThunk" inline DName __near UnDecorator::getVfTableType ( const DName & superType ) { FTRACE(UnDecorator::getVfTableType); DName vxTableName = superType; if ( vxTableName.isValid () && *gName ) { vxTableName = getStorageConvention () + ' ' + vxTableName; if ( vxTableName.isValid ()) { if ( *gName != '@' ) { vxTableName += "{for "; while ( vxTableName.isValid () && *gName && ( *gName != '@' )) { vxTableName += '`' + getScope () + '\''; // Skip the scope delimiter if ( *gName == '@' ) gName++; // Close the current scope, and add a conjunction for the next (if any) if ( vxTableName.isValid () && ( *gName != '@' )) vxTableName += "s "; } // End of WHILE if ( vxTableName.isValid ()) { if ( !*gName ) vxTableName += DN_truncated; vxTableName += '}'; } // End of IF } // End of IF // Skip the 'vpath-name' terminator if ( *gName == '@' ) gName++; } // End of IF } // End of IF then elif ( vxTableName.isValid ()) vxTableName = DN_truncated + vxTableName; return vxTableName; } // End of "UnDecorator" FUNCTION "getVfTableType" #endif // !NO_COMPILER_NAMES inline DName __near UnDecorator::getExternalDataType ( const DName & superType ) { FTRACE(UnDecorator::getExternalDataType); // Create an indirect declarator for the the rest DName * pDeclarator = gnew DName (); DName declaration = getDataType ( pDeclarator ); // Now insert the declarator into the declaration along with its 'storage-convention' *pDeclarator = getStorageConvention () + ' ' + superType; return declaration; } // End of "UnDecorator" FUNCTION "getExternalDataType" #endif // !VERS_P3 #if ( !NO_OPTIONS ) inline int __near UnDecorator::doUnderScore () { return !( disableFlags & UNDNAME_NO_LEADING_UNDERSCORES ); } inline int __near UnDecorator::doMSKeywords () { return !( disableFlags & UNDNAME_NO_MS_KEYWORDS ); } inline int __near UnDecorator::doFunctionReturns () { return !( disableFlags & UNDNAME_NO_FUNCTION_RETURNS ); } inline int __near UnDecorator::doAllocationModel () { return !( disableFlags & UNDNAME_NO_ALLOCATION_MODEL ); } inline int __near UnDecorator::doAllocationLanguage () { return !( disableFlags & UNDNAME_NO_ALLOCATION_LANGUAGE ); } #if 0 inline int __near UnDecorator::doMSThisType () { return !( disableFlags & UNDNAME_NO_MS_THISTYPE ); } inline int __near UnDecorator::doCVThisType () { return !( disableFlags & UNDNAME_NO_CV_THISTYPE ); } #endif inline int __near UnDecorator::doThisTypes () { return (( disableFlags & UNDNAME_NO_THISTYPE ) != UNDNAME_NO_THISTYPE ); } inline int __near UnDecorator::doAccessSpecifiers () { return !( disableFlags & UNDNAME_NO_ACCESS_SPECIFIERS ); } inline int __near UnDecorator::doThrowTypes () { return !( disableFlags & UNDNAME_NO_THROW_SIGNATURES ); } inline int __near UnDecorator::doMemberTypes () { return !( disableFlags & UNDNAME_NO_MEMBER_TYPE ); } inline int __near UnDecorator::doReturnUDTModel () { return !( disableFlags & UNDNAME_NO_RETURN_UDT_MODEL ); } #endif // !NO_OPTIONS #if ( !VERS_P3 && !VERS_PWB ) pcchar_t __near UnDecorator::UScore ( Tokens tok ) { FTRACE(UnDecorator::UScore); #if ( !NO_OPTIONS ) return ( doUnderScore () ? tokenTable[ tok ] : tokenTable[ tok ] + 2 ); #else // } elif NO_OPTIONS { return tokenTable[ tok ]; #endif // NO_OPTIONS } // End of "UnDecorator" FUNCTION "UScore" #endif // !VERS_P3 && !VERS_PWB #include "undname.inl"