windows-nt/Source/XPSP1/NT/base/wow64/tools/genthnk/genthnk.c
2020-09-26 16:20:57 +08:00

8882 lines
248 KiB
C

/*++
Copyright (c) 1996-2000 Microsoft Corporation
Module Name:
genthnk.c
Abstract:
This program generates thunks.
Author:
08-Jul-1995 JonLe
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <imagehlp.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "gen.h"
// bitfield values to indicate which platform an API should be switched in on.
#define API_NONE 0
#define API_WIN95 1
#define API_WIN98 2
#define API_NT4 4
#define API_NT5 8
#define API_WIN9x (API_WIN95 | API_WIN98)
#define API_NTx (API_NT4 | API_NT5)
#define API_ALL (API_WIN9x | API_NTx)
#define API_SHIFT_WIN9x 0 // shift API bits right 0 to make Win9x leftmost
#define API_SHIFT_NTx 2 // shift API bits right 2 to make NTx leftmost
// This is the new VC6 import structure. VC6 import lib spec is checked
// in as wx86\doc\vc6.doc. Contact Dan Spalding or Kathleen Herold for
// more info. Or look at sdktools\vctools\coff\deflib.h ImportHdr.
typedef struct ImgImportHdr {
WORD Sig1; // always 0 (IMAGE_FILE_MACHINE_UNKNOWN)
WORD Sig2; // always ffff (IMPORT_HDR_SIG2)
WORD Version;
WORD Machine;
DWORD TimeStamp;
DWORD SizeOfData; // count of bytes in strings that follow
union {
WORD Ordinal;
WORD Hint;
};
WORD Type : 2; // IMPORT_TYPE
WORD NameType : 3; // IMPORT_NAME_TYPE
WORD Reserved : 11;// Reserved. Must be 0.
} VC6_IMAGE_IMPORT_HEADER, *PVC6_IMAGE_IMPORT_HEADER;
enum IMPORT_TYPE
{
IMPORT_CODE = 0,
IMPORT_DATA = 1,
IMPORT_CONST = 2,
};
enum IMPORT_NAME_TYPE
{
IMPORT_ORDINAL,
IMPORT_NAME,
IMPORT_NAME_NO_PREFIX,
IMPORT_NAME_UNDECORATE
};
// end of VC6 import structure
// string to put in front of all error messages so that BUILD can find them.
const char *ErrMsgPrefix = "NMAKE : U8600: 'GENTHNK' ";
// template sections types
char szIFUNC[]= "IFunc";
char szEFUNC[]= "EFunc";
char szEFAST[]= "EFast";
char szTYPES[]= "Types";
char szCODE[] = "Code";
char szFAILTYPES[] = "FailTypes";
char szMACROS[]="Macros";
// template properties
char szTEMPLENAME[]= "TemplateName";
char szMACRONAME[] = "MacroName";
char szTYPENAME[] = "TypeName";
char szINDLEVEL[] = "IndLevel";
char szDIRECTION[] = "Direction";
char szNUMARGS[] = "NumArgs";
char szCGENBEG[] = "Begin"; // default codeburst name
char szCGENEND[] = "End";
char szUSE[] = "Use";
char szALSO[] = "Also";
char szNOTYPE[] = "NoType";
char szCASE[] = "Case";
// substitution macros
char szTEMPLATE[]="Template";
char szDLLNAME[]="DllName";
char szXPTNAME[]="XPTName";
char szDLLTARGET[]="DllTarget";
char szAPIFNRET[]="ApiFnRet";
char szAPIFNMOD[]="ApiFnMod";
char szAPINAME[]="ApiName";
char szAPINAMESKIP[]="ApiNameSkip";
char szAPIFORWARD[]="ApiForward";
char szAPINUM[]="ApiNum";
char szAPIUNKNOWN[]="ApiUnknown";
char szAPINODECL[]="ApiNoDecl";
char szFASTCALL[]="FastCall";
char szSLOWCALL[]="SlowCall";
char szFASTX2NMETH[]="FastX2NMethod";
char szSLOWX2NMETH[]="SlowX2NMethod";
char szFATX2NMETH[]="FatX2NMethod";
char szMETHODNUMBER[]="MethodNumber";
char szRETSIZE[]="RetSize";
char szUNALIGNEDTAG64[]="UnalignedTag64";
char szARGSIZE[]="ArgSize";
char szARGTYPE[]="ArgType";
char szARGHOSTTYPE[] = "ArgHostType";
char szARGTYPEIND[]="ArgTypeInd";
char szARGHOSTTYPEIND[]="ArgHostTypeInd";
char szARGNAME[]="ArgName";
char szARGNAMEHOSTCASTED[]="ArgHostName";
char szARGVAL[]="ArgVal";
char szFUNCARGNUM[]="FuncArgNum";
char szARGMOD[]="ArgMod";
char szARGPOSTMOD[]="ArgPostMod";
char szARGLIST[]="ArgList";
char szIFAPIRET[]="IfApiRet";
char szIFARGS[]="IfArgs";
char szARGMORE[]="ArgMore";
char szAPILIST[]="ApiList";
char szAPIMORE[]="ApiMore";
char szLISTCOL[]="ListCol";
char szARGLOCAL[]="ArgLocal";
char szARGOFF[]="ArgOff";
char szARGADDR[]="ArgAddr";
char szEXPORTLIST[]="ExportList";
char szEXPNAME[]= "ExpName";
char szIFEXPFORWARD[]= "IfExpForward";
char szADDRARGSLIST[]="AddrArgsList";
char szNARGTYPE[]="NArgType";
char szNARGNAME[]="NArgName";
char szIFRETTYPE[]="IfRetType";
char szIFORDINALS[]="IfOrdinals";
char szAPISTRINGS[]="ApiStrings";
char szDBGSINDEX[]="DbgsIndex";
char szDBGSLIST[]="DbgsList";
char szDBGSSTRINGS[]="DbgsStrings";
char szDBGSMORE[]="DbgsMore";
char szCPPEXPORT[]="CppExport";
char szCEXPORT[]="CExport";
char szCPPOUTPUT[]="CppOutput";
char szCOUTPUT[]="COutput";
char szAPIDECLSPEC[]="ApiDeclSpec";
char szIFAPICODE[]="IfApiCode";
char szRETTYPE[]="RetType";
char szMARG[]="MArg";
char szMEMBERTYPES[]="MemberTypes";
char szBTOTMEMBERTYPES[]="BtoTMemberTypes";
char szFORCETYPE[]="ForceType";
char szLOG[]="Log";
char szRTOLTYPES[]= "RtoLTypes";
char szIFNOTRETTYPE[]="IfNotRetType";
char szIFISMEMBER[]="IfIsMember";
char szIFNISMEMBER[]="IfNotIsMember";
char szIFISBITFIELD[]="IfIsBitfield";
char szIFNISBITFIELD[]="IfNotIsBitfield";
char szIFISARRAY[]="IfIsArray";
char szIFNISARRAY[]="IfNotIsArray";
char szARGARRAYELEMENTS[]="ArrayElements";
char szIFPOINTERTOPTRDEP[]="IfPointerToPtrDep";
char szIFNPOINTERTOPTRDEP[]="IfNotPointerToPtrDep";
char szISPOINTERTOPTRDEP[]="IsPointerToPtrDep";
char szIFPTRDEP[]="IfPtrDep";
char szIFNPTRDEP[]="IfNotPtrDep";
char szIFINT64DEPUNION[]="IfInt64DepUnion";
char szIFNINT64DEPUNION[]="IfNotInt64DepUnion";
char szNL[]="NL";
char szINDENT[]="Indent";
char szNOFORMAT[]="NoFormat";
char szALIGN[]="Align";
char szCOMMENT[]="Comment";
char szOFFSET[]="OffSet";
char szHOSTAPPEND[]="Host";
char szCARG[]="CArg";
char szCARGEXIST[]="CArgExist";
char szFORCASE[]="ForCase";
char szCNUMBER[]="CNumber";
// if support
char szIF[]="If";
char szELSE[]="Else";
char szOR[]="Or";
char szAND[]="And";
char szNOT[]="Not";
char szARGUNIONULARGEINTEGER[]="PULARGE_INTEGER";
char szARGUNIONLARGEINTEGER[]="PLARGE_INTEGER";
extern char sz__PTR64[];
#define MAX_ALSO 80
#define MAX_CODEBURST 20
#define MAX_NOTYPE 32
typedef struct tagCODEBURST {
char *Name;
} CODEBURST;
CODEBURST CodeBursts[MAX_CODEBURST];
typedef struct _Templates{
LIST_ENTRY TempleEntry;
char *Name;
int IndLevel;
TOKENTYPE tkDirection;
PKNOWNTYPES pktType;
char *Comment;
char *CodeBurst[MAX_CODEBURST];
char *NoTypes[MAX_NOTYPE];
PLIST_ENTRY pCaseList;
char Buffer[1];
}TEMPLES, *PTEMPLES;
typedef struct _CGenerate {
LIST_ENTRY CGenerateEntry;
FILE *fp;
FILE *fpC;
char *FileNameC;
char *FileBaseNameC;
FILE *fpCpp;
char *FileNameCpp;
char *FileBaseNameCpp;
char TempleName[1];
}CGENERATE, *PCGENERATE;
FILE *fpLog; // file pointer to optional log file for @Log() calls
//
// handy macro to knock out the hi bit in implib style ordinals
//
#define IMPORDINAL(o) ((o) & ~0x80000000)
//
// Structure definining the list of arguments for a function
//
typedef struct _ArgumentsList {
LIST_ENTRY ArgumentsEntry; // ptr to prev and next arg
PKNOWNTYPES pKnownTypes; // type of this arg
PKNOWNTYPES pStructType; // cache used by MemberTypes()
DWORD ArgSize; // size of this arg
BOOL IsPtr64; // TRUE if this arg is __ptr64
int OffSet; // offset from stack for this arg
int IndLevel; // indirection level
TOKENTYPE tkDirection; // TK_NONE, TK_IN, TK_OUT, TK_INOUT
TOKENTYPE Mod; // modifier (TK_CONST/VOLATILE/NONE)
TOKENTYPE SUEOpt; // TK_STRUCT/ENUM/UNION/NONE
char *Type; // typename for this arg
TOKENTYPE PostMod; // modifier (TK_CONST/VOLATILE/NONE)
TOKENTYPE PrePostMod; // modifier (TK_CONST/VOLATILE/NONE)
char *Name; // argument name (may be a nonameX)
char *ArgLocal; // name of local var containing copy of arg
char *HostCastedName; // Contains full name of struct member with
// host casts or NULL
BOOL fRequiresThunk; // TRUE if arg type contains a nested
// function pointer (and hence needs
// special thunking)
BOOL fNoType; // TRUE if types templates should *not*
// be expanded for this param.
BOOL fIsMember; // This arg is actually a member of an array
BOOL bIsBitfield; // Determines if this is a bitfield
int BitsRequired; // Number of bits required for bitfield
BOOL bIsArray; // This member is an array
int ArrayElements; // Number of elements in the array
} ARGSLIST, *PARGSLIST;
//
// Structure containing the list of macro arguments
//
typedef struct _MacroArgsList {
int NumArgs;
LPSTR ArgText[1];
} MACROARGSLIST, *PMACROARGSLIST;
typedef struct _MLListEntry {
LIST_ENTRY ListEntry;
PMACROARGSLIST pMArgs;
} MLLISTENTRY, *PMLLISTENTRY;
#define MAX_MACRO_STACK 20
PMACROARGSLIST MacroStack[MAX_MACRO_STACK];
int MacroStackTop;
//
// This defines the first method number that would not be supported as a
// fast or slow method call. If this is to be changed then FastN2X and SlowN2X
// worker routines need to be addeed in whole32.dll
#define MAXFASTN2XMETHODNUMBER 16
//
// This defines the maximum number of parameters that are allowed to be in a
// FastX2N or SlowX2N method call. To change it new code would have to be
// added to FastX2N and SlowX2N in whole32\methods.c to deal with the
// additional number of parameters.
#define MAXX2NPARAMETERS 10
typedef enum {
UNKNOWNMETHOD = 0,
FATX2NMETHOD = 1,
FASTX2NMETHOD = 2,
SLOWX2NMETHOD = 3
} METHODTYPE;
typedef struct _ExportDebugInfo {
LIST_ENTRY ExportsDbgEntry;
LIST_ENTRY ArgsListHead;
struct _ExportDebugInfo *IntForward;
int ArgsSize;
ULONG Function;
char *ExtForward;
char *ExportName;
char *CplusDecoration;
ULONG Ordinal;
// 0 = known fn, -1 incomplete declaration, 1 no declaration
char UnKnownApi;
BOOLEAN Data;
BOOLEAN PrivateNamed;
CHAR FastCall;
BYTE ApiPlatform; // the API_ bit collection
METHODTYPE X2NMethodType;
ULONG MethodNumber;
char Buffer[1];
}EXPORTSDEBUG, *PEXPORTSDEBUG;
typedef struct _DebugStringsList {
LIST_ENTRY DebugStringsEntry;
char *Name;
char *ArgFormat;
char *RetFormat;
char Buffer[1];
} DEBUGSTRINGS, *PDEBUGSTRINGS;
typedef struct _CGenerateState {
PEXPORTSDEBUG ExportsDbg;
PDEBUGSTRINGS DebugStrings;
PCGENERATE CGen;
PTEMPLES Temple; // template for this func (may be IFunc or EFunc)
PKNOWNTYPES ApiTypes;
int ApiNum;
PARGSLIST pArgsList;
int ListCol;
BOOLEAN MoreApis;
BOOLEAN ExTemplate; // true if Temp is an EFunc template with a 'Begin='
PTEMPLES TempleEx; // EFunc for this API (if there is one)
int CodeBurstIndex;
PTEMPLES CurrentTemple; // This is the template that is currently being expanded.
PMACROARGSLIST pMacroArgsList;
PCHAR *MemberNoType; // Additional set of notypes to applyPMACROARGSLIST pMacroArgsList;
int CaseNumber; // Number of the current Case being expanded.
PLIST_ENTRY pCaseList;
PMACROARGSLIST pCaseArgsList;
} CGENSTATE, *PCGENSTATE;
int BeginCBI; // CodeBurstIndex for 'Begin='
PKNOWNTYPES NIL; // for red-black trees
PRBTREE FuncsList;
PRBTREE TypeDefsList;
PRBTREE StructsList;
RBTREE FakeFuncsList;
LIST_ENTRY TypeTempleList;
LIST_ENTRY FailTempleList;
LIST_ENTRY IFuncTempleList;
LIST_ENTRY EFuncTempleList;
LIST_ENTRY EFastTempleList;
LIST_ENTRY CodeTempleList;
LIST_ENTRY CGenerateList;
LIST_ENTRY ExportsList;
LIST_ENTRY DebugStringsList;
LIST_ENTRY MacroList;
ULONG NumDebugStringsEntries;
BOOL MapViewDll(char *DllName);
char DllName[MAX_PATH+1]= "";
char ExplicitDllBaseName[MAX_PATH+1] = "UNSPECIFIED";
char *DllBaseName = ExplicitDllBaseName;
PVOID DllMappedBase = NULL;
ULONG_PTR DllRvaOffset;
PULONG DllFunctions = NULL;
PUSHORT DllNameOrdinals = NULL;
PULONG DllNameTable = NULL;
ULONG DllExportDirSize;
PIMAGE_EXPORT_DIRECTORY DllExportDir;
BOOL MapViewImplib(char *ImplibName);
char ImplibName[MAX_PATH+1]="";
char *ImplibBaseName = NULL;
PVOID ImplibMappedBase= NULL;
ULONG ImplibNumSymbols=0;
PULONG ImplibSymbolMembers=NULL;
PCHAR ImplibSymbolNames=NULL;
char szIMPPREFIX[]="__imp_";
char szIDATA5[]=".idata$5";
char szTEXT[]=".text";
char szINTFORWARD[]="_IntForward_";
char XptName[MAX_PATH+1]= "";
char *XptBaseName = NULL;
// these are used to report errors while parsing .tpl files
char *TemplateFileName;
int TemplateLine;
char iHandleCpp = 0; // if == 0, Don't use CPP macros, and warn if CPP exports found
// if < 0, Don't use CPP macros, no warn if CPP exports found
// if > 0, Use CPP macros.
BOOL bNoFuzzyLogic;
BOOL bUseExpListAndImplib;
BOOL bWarnAboutNestedFuncPtrs;
BOOL bUseDirection = TRUE;
BOOL bStripNewline = TRUE;
int OutputColumn = 0;
int IndentLevel = 0;
BOOL bFirstCharHit = FALSE;
#define INDENTSIZE 4
void SetInternalForwards(void);
BOOL ExtractXpt(char *XptName, char *DllName);
BOOL ExtractExports(void);
BOOL ExtractPpm(char *FileName);
BOOL ExtractTemples(char *FileName);
BOOL ExtractCGenerate(char *pNames);
BOOL ExtractImplib(char *LibName);
char *CopyField(char *pDst, char *pSrc, int Len, char Sep);
void DumpTemplate(PTEMPLES ptpl, FILE *fp);
PTEMPLES GetTemplate(PLIST_ENTRY pHeadList, char *TempleName);
char *CGenerate(char *pSrc, PCGENSTATE pCGenState);
char *CGenerateEx(char *pSrc, PCGENSTATE pCGenState, char *OutBuffer, SIZE_T MaxLen, SIZE_T *BytesReturned);
char *ListApis(char *pSrc, PCGENSTATE pCGenState, BOOL bExports);
char *ListArgs(char *pSrc, PCGENSTATE pCGenState, BOOL Always);
void ProcessTemple(PCGENSTATE pCGenState);
char *IncludeTemplate(char *pSrc, PCGENSTATE pCGenState);
char *IncludeTypes(char *pSrc, PCGENSTATE pCGenState, BOOL bRtoL);
char *MemberTypes(char *pSrc, PCGENSTATE pCGenState, BOOL bBtoT);
char *IfNotRetType(char *pSrc, PCGENSTATE pCGenState);
char *IncludeRetType(char *pSrc, PCGENSTATE pCGenState);
char *WriteMore(char *pSrc, PCGENSTATE pCGenState, BOOL bMore);
BOOL AddToExportsList(PEXPORTSDEBUG pExportsDebug);
PEXPORTSDEBUG FindInExportsList(char *Name);
char *SkipSubExpression(char *pSrc, char **pSubExpression);
PKNOWNTYPES BuildFakeTypesInfo(PEXPORTSDEBUG pExportsDbg, PKNOWNTYPES pKnownTypes);
void WriteListColumn(PCGENSTATE pCGenState);
char *GetAltExportName(char *Buffer, PCGENSTATE pCGenState, int Len);
void BuildArgsList(PTEMPLES pTempleEx, PFUNCINFO funcinfo, PLIST_ENTRY pListHead);
char *IfApiRet(char *pSrc, PCGENSTATE pCGenState);
char *IfApiCode(char *pSrc, PCGENSTATE pCGenState);
char *IfRetType(char *pSrc, PCGENSTATE pCGenState);
char *IfArgs(char *pSrc, PCGENSTATE pCGenState);
void ApiStrings(PCGENSTATE pCGenState);
int GetFuncArgNum(PCGENSTATE pCGenState);
int GetFuncIndex(PCGENSTATE pCGenState, char *FuncTypeName);
char *ListDbgs(char *pSrc, PCGENSTATE pCGenState);
void WriteDbgsStrings(char *pSrc, PCGENSTATE pCGenState);
int GetRetSize(PCGENSTATE pCGenState);
int GetArgSize(PEXPORTSDEBUG ExportDebug);
char *GetOffSet(char *pSrc, char *Buffer);
char *LexMacroArgs(char *pch);
PLIST_ENTRY ListFromTempleType(char *TempleType);
void UseLogMacros(char *pLogName);
char *UpdateLog(char *pSrc, PCGENSTATE pCGenState);
BOOL IsPointerToPtrDep(PARGSLIST pArgsList);
char* ForceTypeExpand( char *pSrc, PCGENSTATE pCGenState);
VOID SetArgListToTypeForArg(PARGSLIST pArgsList, PARGSLIST pArgsListOld, char * pTypeName);
BOOLEAN
IsFastCall(
PCGENSTATE pCGenState
);
METHODTYPE
GetX2NMethodType(
PCGENSTATE pCGenState
);
char *
GetAddrFirstArg(
PCGENSTATE pCGenState,
char *Buffer,
int BuffLen
);
PKNOWNTYPES
IsSameType(
PKNOWNTYPES pktArgs,
int IndLevel,
TOKENTYPE tkArgDirection,
char *tplTypeName,
int tplIndLevel,
TOKENTYPE tkTypeDirection,
BOOL bScanBaseTypes
);
char *
WriteArgAddr(
char *pSrc,
PCGENSTATE pCGenState,
char *Buffer,
int BuffLen
);
BOOL
WriteArgLocal(
PCGENSTATE pCGenState,
char *Buffer,
int BuffLen
);
BOOL
AddTemple(
char *TempleType,
char *TempleName,
char *Comment,
char *IndLevel,
char *pCCode[MAX_CODEBURST],
TOKENTYPE tkDirection,
char *Also[MAX_ALSO],
int AlsoCount,
char *NoType[MAX_NOTYPE],
int NoTypeCount,
PLIST_ENTRY pCaseList
);
int
GetCodeBurstIndex(
char *BurstName
);
int
GetExistingCodeBurstIndex(
char *BurstName
);
BOOLEAN
ExpandMacro(
char *MacroName,
PCGENSTATE pCGenState,
char **ppIn,
char *OutBuffer,
SIZE_T MaxLen,
SIZE_T *BytesReturned
);
BOOLEAN
TempleHasNoCodeBursts(
PTEMPLES pTemple
);
void
PlatformSwitchStart(
PCGENSTATE pCGenState,
BYTE ApiPlatform
);
void
PlatformSwitchEnd(
PCGENSTATE pCGenState,
BYTE ApiPlatform
);
void
PlatformSwitchEndTable(
PCGENSTATE pCGenState,
BYTE ApiPlatform
);
char *
ExtractBoolean1(
char *pSrc,
PCGENSTATE pCGenState,
BOOLEAN *result
);
char *
ExtractBoolean2(
char *pSrc,
PCGENSTATE pCGenState,
BOOLEAN *result1,
BOOLEAN *result2
);
void
WriteBoolean (
char *pSrc,
BOOL Value
);
char *CPlatformSwitches[] = { "",
"(%s==0x0400)",
"(%s>0x0400)",
"(%s>=0x0400)" };
char *AsmPlatformSwitches[] = { "",
"(%s_ASM EQ 0400h)",
"(%s_ASM GT 0400h)",
"(%s_ASM GE 0400h)" };
BOOL
ExpandTemple(PTEMPLES ptpl,
int CodeBurstIndex,
PCGENSTATE pCGenState)
{
PLIST_ENTRY pOldCaseList;
PTEMPLES pOldCurrentTemple;
char *pSrc = ptpl->CodeBurst[CodeBurstIndex];
if (NULL == pSrc) {
return FALSE;
}
pSrc = ptpl->CodeBurst[CodeBurstIndex];
while (*pSrc && !isgraph(*pSrc)) {
pSrc++;
}
if ('\0' == *pSrc) {
return FALSE;
}
//
// Expand the type here
pOldCurrentTemple = pCGenState->CurrentTemple;
pOldCaseList = pCGenState->pCaseList;
if(ptpl->pCaseList != NULL &&
!IsListEmpty(ptpl->pCaseList)) {
pCGenState->pCaseList = ptpl->pCaseList;
}
pCGenState->CurrentTemple = ptpl;
CGenerate(pSrc, pCGenState);
pCGenState->CurrentTemple = pOldCurrentTemple;
pCGenState->pCaseList = pOldCaseList;
return TRUE;
}
PVOID CheckHeapAlloc(SIZE_T Size) {
PVOID pMem;
pMem = GenHeapAlloc(Size);
if(NULL == pMem) {
DbgPrintf("Error: Out of Memory!\n");
DebugBreak();
ExitErrMsg(FALSE, "Error: Out of Memory!\n");
}
return pMem;
}
typedef struct _StringListEntry {
LIST_ENTRY ListEntry;
PSTR pStr;
} STRINGLISTENTRY, *PSTRINGLISTENTRY;
VOID
FreeMacroArgsList(PMACROARGSLIST pArgs) {
SIZE_T c;
for(c=0; c < (SIZE_T)pArgs->NumArgs; c++) {
GenHeapFree(pArgs->ArgText[c]);
}
GenHeapFree(pArgs);
}
char *
CArg(
char *pSrc,
PCGENSTATE pCGenState,
PSTR *pBuffer,
BOOL TestExistOnly
)
{
int i;
int ArgNum;
CHAR s[MAX_PATH];
PCHAR pResult;
PMACROARGSLIST pList = pCGenState->pCaseArgsList;
PCHAR pCommandName = TestExistOnly ? szCARGEXIST : szCARG;
if (!pList) {
ExitErrMsg(FALSE, "%s(%d) %s unexpected: no case is currently being applied\n",
TemplateFileName, TemplateLine, pCommandName);
return NULL;
}
if (*pSrc != '(') {
ExitErrMsg(FALSE, "%s(%d) %s Incorrect parameter %s\n",
TemplateFileName, TemplateLine, pCommandName, pSrc);
return NULL;
}
pSrc++;
i = 0;
while ((*pSrc != ')') && (i < sizeof(s)-1)) {
s[i++] = *pSrc++;
}
s[i] = 0;
ArgNum = atoi(s);
pSrc++; // skip ')'
if (ArgNum-- == 0) {
ExitErrMsg(FALSE, "%s(%d) Invalid %s parameter %s\n", TemplateFileName, TemplateLine,
pCommandName, s);
return NULL;
}
if (TestExistOnly) {
pResult = (ArgNum >= pList->NumArgs) ? "0" : "1";
}
else {
if (ArgNum >= pList->NumArgs) {
ExitErrMsg(FALSE, "%s(%d) Case only has %d arguments\n", TemplateFileName, TemplateLine, pList->NumArgs);
return NULL;
}
pResult = pList->ArgText[ArgNum];
}
if (pBuffer != NULL) {
*pBuffer = pResult;
}
else {
CGenerate(pResult, pCGenState);
}
return pSrc;
}
char *ForCase(char *pSrc, PCGENSTATE pCGenState) {
PMACROARGSLIST pCaseArgsListOld;
PLIST_ENTRY pHead, pThis;
char *pch;
char *pExpression;
int OldCaseNumber;
// Are any cases available for application
if (pCGenState->pCaseList == NULL ||
(pCGenState->pCaseList != NULL && IsListEmpty(pCGenState->pCaseList))) {
//Do nothing
return SkipSubExpression(pSrc, NULL);
}
pch = SkipSubExpression(pSrc, &pExpression);
if (pSrc == pch || !pExpression) {
return pch;
}
pSrc = pch;
pCaseArgsListOld = pCGenState->pCaseArgsList;
pHead = pCGenState->pCaseList;
pThis = pHead->Flink;
OldCaseNumber = pCGenState->CaseNumber;
pCGenState->CaseNumber = 0;
do {
pCGenState->pCaseArgsList = CONTAINING_RECORD(pThis,MLLISTENTRY,ListEntry)->pMArgs;
CGenerate(pExpression, pCGenState);
pThis = pThis->Flink;
pCGenState->CaseNumber++;
} while (pThis != pHead );
pCGenState->CaseNumber = OldCaseNumber;
pCGenState->pCaseArgsList = pCaseArgsListOld;
return pSrc;
}
PCHAR
ParseMacroArgs(IN PCHAR pch,
IN SIZE_T maxlen,
OUT PMACROARGSLIST *ppMArgsList
)
{
PMACROARGSLIST pMArgsList = NULL;
LIST_ENTRY ArgsList;
PCHAR pl;
int ArgCount=0;
int ParenDepth=0;
SIZE_T len = 0;
if (maxlen == 0) {
len = MAXUINT_PTR;
}
InitializeListHead(&ArgsList);
if (*pch != '(') {
ExitErrMsg(FALSE, "ParseMacroArgs: Expected to find ( for args list\n");
}
pch++;
ParenDepth++;
len++;
while(ParenDepth > 0) {
pl = pch;
while(1) {
if('\0' == *pl || len > maxlen) {
ExitErrMsg(FALSE, "ParseMacroArgs: Unmatched paren for args list\n");
}
if (*pl == '(') {
ParenDepth++;
}
else if (*pl == ')') {
ParenDepth--;
}
if (ParenDepth == 0 ||
(ParenDepth == 1 && *pl == ',')) {
PSTRINGLISTENTRY pSl;
pSl = CheckHeapAlloc(sizeof(STRINGLISTENTRY));
pSl->pStr = CheckHeapAlloc(pl - pch + 1);
memcpy(pSl->pStr, pch, pl - pch);
pSl->pStr[pl - pch] = '\0';
InsertTailList(&ArgsList, &(pSl->ListEntry));
ArgCount++;
pch = pl + 1;
if (ParenDepth == 0) {
// No more arguments
goto Exit;
}
else {
// Do next argument
break;
}
}
pl++;
}
}
Exit:
pMArgsList = CheckHeapAlloc(sizeof(MACROARGSLIST) + sizeof(LPSTR) * ArgCount);
pMArgsList->NumArgs = ArgCount;
for(ArgCount = 0; ArgCount < pMArgsList->NumArgs; ArgCount++) {
PSTRINGLISTENTRY pSl;
pSl = CONTAINING_RECORD(ArgsList.Flink,STRINGLISTENTRY,ListEntry);
RemoveHeadList(&ArgsList);
pMArgsList->ArgText[ArgCount] = pSl->pStr;
GenHeapFree(pSl);
}
*ppMArgsList = pMArgsList;
return pch;
}
void ExtractServicesTab(char *pch);
/* main
*
* standard win32 base windows entry point
* returns 0 for clean exit, otherwise nonzero for error
*
*
* ExitCode:
* 0 - Clean exit with no Errors
* nonzero - error ocurred
*
*/
int __cdecl main(int argc, char **argv)
{
int i;
DWORD dw;
char *pch;
CGENSTATE CGenState;
PLIST_ENTRY Next;
BOOL bUseServicesTab = FALSE;
// init the lists
InitializeListHead(&TypeTempleList);
InitializeListHead(&FailTempleList);
InitializeListHead(&CodeTempleList);
InitializeListHead(&IFuncTempleList);
InitializeListHead(&EFuncTempleList);
InitializeListHead(&EFastTempleList);
InitializeListHead(&CGenerateList);
InitializeListHead(&ExportsList);
InitializeListHead(&DebugStringsList);
InitializeListHead(&MacroList);
NumDebugStringsEntries = 0;
BeginCBI = GetCodeBurstIndex(szCGENBEG); // Preload 'Begin=' as a valid codeburst
SetConsoleCtrlHandler(ConsoleControlHandler, TRUE);
/*try*/ {
/*
* Get cmd line args.
*/
i = 0;
while (++i < argc) {
pch = argv[i];
if (*pch == '-' || *pch == '/') {
pch++;
switch (toupper(*pch)) {
case 'D':
bDebug = TRUE;
setvbuf(stderr, NULL, _IONBF, 0);
break;
case 'F':
bExitClean = FALSE;
break;
case 'T': // template file name
if (!ExtractTemples(pch+1)) {
ExitErrMsg(FALSE, "ExtractTemples failed %s\n", pch);
}
break;
case 'C': //cgenerate "-cOutputFileName[,CppOutputFileName]:TemplateName"
if (!ExtractCGenerate(pch+1)) {
ExitErrMsg(FALSE, "ExtractCGenerate failed %s\n", pch);
}
break;
case 'M': // ppm file name (only 1 expected!)
if (FuncsList) {
ExitErrMsg(FALSE, "ExtractPpm only one Ppm file allowed %s\n", pch);
}
if (!ExtractPpm(pch+1)) {
ExitErrMsg(FALSE, "ExtractPpm failed %s\n", pch);
}
break;
case 'S': //use a services.tab instead of an exports list
bUseServicesTab = TRUE;
ExtractServicesTab(pch+1);
break;
case 'E': // xpt list for exports "-eExportListName"
dw = GetFullPathName(pch+1,
sizeof(XptName) - 1,
XptName,
&XptBaseName
);
if (!dw || dw >= sizeof(XptName) - 1) {
ExitErrMsg(FALSE, "Invalid XptName %s\n", pch);
}
break;
case 'X': // Enable exports from implib, -eXptName assumed
bUseExpListAndImplib = TRUE;
break;
case 'I': // implib file name "-iImplibName"
dw = GetFullPathName(pch+1,
sizeof(ImplibName) - 1,
ImplibName,
&ImplibBaseName
);
if (!dw || dw >= sizeof(ImplibName) - 1) {
ExitErrMsg(FALSE, "Invalid Import Library Name %s\n", pch);
}
break;
case 'L': // Disable fuzzy logic symbol name matching
bNoFuzzyLogic = TRUE;
break;
case 'W': // warn about unthunked structures containing function ptrs
bWarnAboutNestedFuncPtrs = TRUE;
break;
case 'U': // [U]se direction information (__in, __out)
bUseDirection = FALSE; // turn it off
break;
case 'K': // generate chec[K] file from @Log() macros
UseLogMacros(pch+1);
break;
case 'N': // specify explicit DLL base name
strncpy(DllBaseName, pch+1, MAX_PATH);
break;
default:
ExitErrMsg(FALSE, "Unrecognized option %s\n", pch);
}
}
else if (*pch) {
dw = GetFullPathName(pch,
sizeof(DllName) - 1,
DllName,
&DllBaseName
);
if (!dw || dw >= sizeof(DllName) - 1) {
ExitErrMsg(FALSE, "Invalid DllName %s\n", pch);
}
}
}
if(!bUseServicesTab) {
//
// MapView of importlib and dll into memory and
// set up global variables for easy access
//
if (ImplibName[0]) {
if (!MapViewImplib(ImplibName)) {
ExitErrMsg(FALSE, "Couldn't open import lib '%s'\n", ImplibName);
}
}
if (DllName[0]) {
if (!MapViewDll(DllName)) {
ExitErrMsg(FALSE, "Couldn't open DLL '%s'\n", DllName);
}
}
//
// Extract exports using dll and implib.
//
if (DllName[0] && (!XptName[0] || bUseExpListAndImplib)) {
// Insist that we have both an implib and a dll.
if ((DllName[0] && !ImplibName[0]) || (ImplibName[0] && !DllName[0])) {
ExitErrMsg(FALSE, "DllName or ImplibName missing\n");
}
if (!ExtractExports()) {
ExitErrMsg(FALSE, "Failed to get exports for <%s>\n", DllName);
}
}
//
// Extract exports from the api list
//
if (XptName[0]) {
if (!ExtractXpt(XptName, DllName)) {
ExitErrMsg(FALSE, "Failed to get exports for <%s>\n", XptName);
}
}
}
//
// Set Internal forwards.
//
SetInternalForwards();
Next = CGenerateList.Flink;
while (Next != &CGenerateList) {
memset(&CGenState, 0, sizeof(CGenState));
CGenState.CGen = CONTAINING_RECORD(Next,CGENERATE,CGenerateEntry);
ProcessTemple(&CGenState);
DelOpenFile(CGenState.CGen->fp, NULL);
fclose(CGenState.CGen->fp);
Next= Next->Flink;
}
}
/*except(EXCEPTION_EXECUTE_HANDLER) {
ExitErrMsg(FALSE,
"ExceptionCode=%x\n",
GetExceptionCode()
);
}*/
CloseOpenFileList(FALSE);
return 0;
}
int
GetCodeBurstIndex(
char *BurstName
)
/*++
Routine Description:
Given a name of a 'foo=' (ie. "foo"), return its index in the array
of codebursts. If there is no 'foo=' on file, add it.
Arguments:
BurstName - name of codeburst to get/add.
Return Value:
Index into template->CodeBursts[], or calls ExitErrMsg() on error.
--*/
{
int i;
int FirstFree = -1;
if (strcmp(BurstName, "CGenBegin") == 0) {
// Compatibility: Accept 'CGenBegin' as 'Begin'
return BeginCBI;
}
for (i=0; i<MAX_CODEBURST; ++i) {
if (CodeBursts[i].Name) {
if (strcmp(BurstName, CodeBursts[i].Name) == 0) {
return i;
}
} else {
if (FirstFree == -1) {
FirstFree = i;
}
}
}
if (FirstFree == -1) {
if (TemplateFileName) {
ExitErrMsg(FALSE,
"%s(%d) Cannot specify more than %d unique codeburst names (%s)",
TemplateFileName, TemplateLine,
MAX_CODEBURST, BurstName
);
} else {
ExitErrMsg(FALSE,
"Cannot specify more than %d unique codeburst names (%s)",
MAX_CODEBURST, BurstName
);
}
}
i = strlen(BurstName)+1;
CodeBursts[FirstFree].Name = GenHeapAlloc(i);
if (!CodeBursts[FirstFree].Name) {
ExitErrMsg(TRUE, "Out of memory in GetCodeBurstIndex");
}
memcpy(CodeBursts[FirstFree].Name, BurstName, i);
return FirstFree;
}
int
GetExistingCodeBurstIndex(
char *BurstName
)
/*++
Routine Description:
Given a name of a 'foo=' (ie. "foo"), return its index in the array
of codebursts. If there is no 'foo=' on file, call ExitErrMsg().
Arguments:
BurstName - name of codeburst to get.
Return Value:
Index into template->CodeBursts[], or -1 on error.
--*/
{
int i;
if (strcmp(BurstName, "CGenBegin") == 0) {
// Compatibility: Accept 'CGenBegin' as 'Begin'
return BeginCBI;
}
for (i=0; i<MAX_CODEBURST; ++i) {
if (CodeBursts[i].Name) {
if (strcmp(BurstName, CodeBursts[i].Name) == 0) {
return i;
}
}
}
return -1;
}
PKNOWNTYPES
GetApiTypes(
PEXPORTSDEBUG ExportsDbg
)
{
PKNOWNTYPES ApiTypes;
char *ExpName;
char *pch;
ExpName = ExportsDbg->IntForward ? ExportsDbg->IntForward->ExportName
: ExportsDbg->ExportName;
//
// Look in the FakeFuncsLIst, and the FuncsList.
//
ApiTypes = GetNameFromTypesList(&FakeFuncsList, ExpName);
if (!ApiTypes) {
ApiTypes = GetNameFromTypesList(FuncsList, ExpName);
}
//
// If export is a decorated name then lets see if we have
// a func that matches the undecorated name
//
if (!ApiTypes) {
pch = strchr(ExpName, '@');
if (pch) {
*pch = '\0';
ApiTypes = GetNameFromTypesList(&FakeFuncsList, ExpName);
if (!ApiTypes) {
ApiTypes = GetNameFromTypesList(FuncsList, ExpName);
}
*pch = '@';
}
}
if (!ApiTypes && ExportsDbg->Data) {
ApiTypes = GetNameFromTypesList(TypeDefsList, "PVOID");
}
else
{
if (!ApiTypes || !ApiTypes->pfuncinfo) {
ApiTypes = BuildFakeTypesInfo(ExportsDbg, ApiTypes);
}
if (!ApiTypes->pktRet) {
// Get KnownTypes info for Return Type
PKNOWNTYPES pkt;
ResetLexer();
LexMacroArgs(ApiTypes->FuncRet);
ConsumeConstVolatileOpt();
if (ParseTypes(TypeDefsList, NULL, &pkt) == FALSE) {
CurrentTokenIndex = 0;
if (ParseTypes(StructsList, NULL, &pkt) == FALSE ) {
ExitErrMsg(FALSE, "GetApiTypes: Undefined return type %s\n", ApiTypes->FuncRet);
}
}
ApiTypes->pktRet = pkt;
}
}
return ApiTypes;
}
/*
* ProcessTemple
*/
void ProcessTemple(PCGENSTATE pCGenState)
{
PLIST_ENTRY Next;
PTEMPLES pTemple;
PTEMPLES pTempleEx;
int i;
pTemple = GetTemplate(&CodeTempleList, pCGenState->CGen->TempleName);
if (pTemple) {
fprintf(pCGenState->CGen->fp,
"%s CodeTemplate:%s\n",
pTemple->Comment,
pTemple->Name
);
pCGenState->Temple = pTemple;
ExpandTemple(pCGenState->Temple, pCGenState->CodeBurstIndex, pCGenState);
} else if (pTemple = GetTemplate(&IFuncTempleList,
pCGenState->CGen->TempleName
)) {
pCGenState->ApiNum = 0;
Next = ExportsList.Flink;
while (Next != &ExportsList) {
BYTE ApiPlatform;
pCGenState->ExportsDbg = CONTAINING_RECORD(Next,
EXPORTSDEBUG,
ExportsDbgEntry
);
//
// Switch this API in or out depending on the platform info
//
ApiPlatform = pCGenState->ExportsDbg->ApiPlatform;
pCGenState->Temple = pTemple;
PlatformSwitchStart(pCGenState, ApiPlatform);
pCGenState->ApiTypes = GetApiTypes(pCGenState->ExportsDbg);
//
// Use exception template for this api if there is one
//
pTempleEx = GetTemplate(&EFuncTempleList,
pCGenState->ExportsDbg->ExportName
);
pCGenState->TempleEx = pTempleEx;
if (pTempleEx) {
pCGenState->ExTemplate = TRUE;
} else {
pCGenState->ExTemplate = FALSE;
}
if (pTempleEx && (pTempleEx->CodeBurst[BeginCBI] || TempleHasNoCodeBursts(pTempleEx))) {
pCGenState->Temple = pTempleEx;
fprintf(pCGenState->CGen->fp,
"%s Func Template:%s\n",
pTempleEx->Comment,
pTempleEx->Name
);
if (TempleHasNoCodeBursts(pTempleEx)) {
// skip this API: ex template, but not code at all
fprintf(pCGenState->CGen->fp,
"%s *** WARNING *** Excluded Api %s\n",
pCGenState->Temple->Comment,
pCGenState->ExportsDbg->ExportName
);
goto SkipGen;
}
} else {
// no ex template
pCGenState->Temple = pTemple;
if (pCGenState->ExportsDbg->Data) {
// DATA export - skip the API
fprintf(pCGenState->CGen->fp,
"%s *** WARNING *** Excluded Data Export %s\n",
pCGenState->Temple->Comment,
pCGenState->ExportsDbg->ExportName
);
goto SkipGen;
} else if (!pCGenState->ApiTypes->pfuncinfo) {
// members unknown - skip the API
ExitErrMsg(FALSE,
"API %s has no function prototype - unable to generate code.",
pCGenState->ExportsDbg->ExportName
);
} else if (!iHandleCpp && pCGenState->ExportsDbg->CplusDecoration) {
// CPP export and we aren't set up for CPP exports
fprintf(pCGenState->CGen->fp,
"%s *** WARNING *** Excluding CPP Api: %s\n",
pCGenState->Temple->Comment,
pCGenState->ExportsDbg->ExportName
);
goto SkipGen;
}
}
//
// skip this api if:
// - external forward reference
// - internal forward which does not define the fn
//
//
if ( (pCGenState->ExportsDbg->ExtForward ||
(pCGenState->ExportsDbg->IntForward &&
pCGenState->ExportsDbg->IntForward != pCGenState->ExportsDbg))) {
fprintf(pCGenState->CGen->fp,
"%s %s forwarded to %s\n",
pCGenState->Temple->Comment,
pCGenState->ExportsDbg->ExportName,
pCGenState->ExportsDbg->ExtForward
? pCGenState->ExportsDbg->ExtForward
: pCGenState->ExportsDbg->IntForward->ExportName
);
if (pTempleEx) {
fprintf(pCGenState->CGen->fp,
"%s WARNING: forwarded function has an exception template\n",
pCGenState->Temple->Comment,
pTempleEx->Name
);
}
} else { // gen code for this api
PLIST_ENTRY NextArg;
PARGSLIST pArgsList;
BuildArgsList(pTempleEx,
pCGenState->ApiTypes->pfuncinfo,
&pCGenState->ExportsDbg->ArgsListHead
);
if (GetArgSize(pCGenState->ExportsDbg) < 0) {
ExitErrMsg(FALSE,
"API %s has no function prototype - unable to generate code.",
pCGenState->ExportsDbg->ExportName
);
} else {
ExpandTemple(pCGenState->Temple, BeginCBI, pCGenState);
//
// Dump warnings about unthunked parameters which
// contain nested function pointers.
//
if (bWarnAboutNestedFuncPtrs && !pTempleEx) {
int ArgNum = 1;
NextArg = pCGenState->ExportsDbg->ArgsListHead.Flink;
while (NextArg != &pCGenState->ExportsDbg->ArgsListHead) {
pArgsList = CONTAINING_RECORD(NextArg,
ARGSLIST,
ArgumentsEntry
);
if (pArgsList->fRequiresThunk) {
//
// The argument contained a nested function
// pointer, and nothing thunked that
// function pointer. Warn about a potential
// bug.
//
fprintf(pCGenState->CGen->fp,
"// *** WARNING: Arg %d: type '%s' contains an unthunked function pointer ***\n",
ArgNum,
pArgsList->Type
);
}
NextArg = NextArg->Flink;
ArgNum++;
}
}
//
// clean up pArgsList->LocalVar and ArgHostName
//
NextArg = pCGenState->ExportsDbg->ArgsListHead.Flink;
while (NextArg != &pCGenState->ExportsDbg->ArgsListHead) {
pArgsList = CONTAINING_RECORD(NextArg,
ARGSLIST,
ArgumentsEntry
);
if (pArgsList->ArgLocal) {
GenHeapFree(pArgsList->ArgLocal);
pArgsList->ArgLocal = NULL;
}
if (pArgsList->HostCastedName) {
GenHeapFree(pArgsList->HostCastedName);
pArgsList->HostCastedName = NULL;
}
NextArg = NextArg->Flink;
}
pCGenState->ApiNum++;
}
}
SkipGen:
//
// End switching this API in or out depending on the platform info
//
ApiPlatform = pCGenState->ExportsDbg->ApiPlatform;
PlatformSwitchEnd(pCGenState, ApiPlatform);
Next= Next->Flink;
}
} else {
ExitErrMsg(FALSE,
"%s,%s:%s Template undefined\n",
pCGenState->CGen->FileNameC,
pCGenState->CGen->FileNameCpp ? pCGenState->CGen->FileNameCpp : "",
pCGenState->CGen->TempleName
);
}
}
void
PlatformSwitchStart(
PCGENSTATE pCGenState,
BYTE ApiPlatform
)
{
BOOL fIsAsm;
if (ApiPlatform == API_ALL) {
return;
}
//
// Switch this API in or out depending on the platform info
// 00: don't emit anything
// 01: emit "== 0x0400"
// 10: emit "> 0x0400"
// 11: emit ">= 0x0400"
//
if (!pCGenState->Temple || !pCGenState->Temple->Comment) {
fIsAsm = FALSE;
} else {
if (strcmp(pCGenState->Temple->Comment, ";") == 0) {
fIsAsm = TRUE;
} else {
fIsAsm = FALSE;
}
}
if (fIsAsm) {
fprintf(pCGenState->CGen->fp, "\nif ");
} else {
fprintf(pCGenState->CGen->fp, "\n#if ");
}
if (ApiPlatform & API_WIN9x) {
BYTE Plat = (ApiPlatform & API_WIN9x) >> API_SHIFT_WIN9x;
fprintf(pCGenState->CGen->fp,
(fIsAsm) ? AsmPlatformSwitches[Plat] : CPlatformSwitches[Plat],
"_WIN32_WINDOWS"
);
}
if ((ApiPlatform & API_WIN9x) && (ApiPlatform & API_NTx)) {
// API is on some flavor of Win9x and some NTx flavor
fprintf(pCGenState->CGen->fp, (fIsAsm) ? " OR " : " || ");
}
if (ApiPlatform & API_NTx) {
BYTE Plat = (ApiPlatform & API_NTx) >> API_SHIFT_NTx;
fprintf(pCGenState->CGen->fp,
(fIsAsm) ? AsmPlatformSwitches[Plat] : CPlatformSwitches[Plat],
"_WIN32_WINNT"
);
}
if (pCGenState->ListCol) {
WriteListColumn(pCGenState);
} else {
fprintf(pCGenState->CGen->fp, "\n");
}
}
void
PlatformSwitchEnd(
PCGENSTATE pCGenState,
BYTE ApiPlatform
)
{
if (ApiPlatform != API_ALL) {
if (strcmp(pCGenState->Temple->Comment, ";") == 0) {
fprintf(pCGenState->CGen->fp, "\nendif ; _WIN32_WIN...\n");
} else {
fprintf(pCGenState->CGen->fp, "\n#endif // _WIN32_WIN...\n");
}
if (pCGenState->ListCol) {
WriteListColumn(pCGenState);
} else {
fprintf(pCGenState->CGen->fp, "\n");
}
}
}
void
PlatformSwitchEndTable(
PCGENSTATE pCGenState,
BYTE ApiPlatform
)
{
if (ApiPlatform != API_ALL) {
if (strcmp(pCGenState->Temple->Comment, ";") == 0) {
fprintf(pCGenState->CGen->fp, "\nendif ; _WIN32_WIN...\n");
} else {
fprintf(pCGenState->CGen->fp, "\n#else\n {whInvalidCall, 0, 0},");
fprintf(pCGenState->CGen->fp, "\n#endif // _WIN32_WIN...\n");
}
if (pCGenState->ListCol) {
WriteListColumn(pCGenState);
} else {
fprintf(pCGenState->CGen->fp, "\n");
}
}
}
/*
* BuildArgsList
*
*
*/
void BuildArgsList(PTEMPLES pTempleEx, PFUNCINFO funcinfo, PLIST_ENTRY pListHead)
{
int i;
ULONG Size;
int OffSet=0;
int ArgOffSet;
PKNOWNTYPES pkt;
PARGSLIST pArgsList;
int NoTypeCount;
char *HostCastedName;
if (!IsListEmpty(pListHead)) {
return;
}
if (!pTempleEx) {
NoTypeCount = 0;
} else {
//
// There is an [EFunc] for this API. Get the count of
// NoType= entries for the EFunc.
//
for (NoTypeCount=0; NoTypeCount<MAX_NOTYPE; ++NoTypeCount) {
if (!pTempleEx->NoTypes[NoTypeCount]) {
break;
}
}
}
while (funcinfo) {
pkt = GetNameFromTypesList(TypeDefsList, funcinfo->sType);
if (!pkt) {
pkt = GetNameFromTypesList(StructsList, funcinfo->sType);
if (!pkt) {
ExitErrMsg(FALSE, "Unknown type %s\n", funcinfo->sType);
}
}
//
// Save the ArgOffSet, and add the args size to the cumulative
// offset for the next argument.
//
// Round up the arg size to the next dword. Assumes intel stack
// parameter passing conventions, and that all pointers are
// sizeof(int *) except __ptr64 which are sizeof(PVOID64).
//
ArgOffSet = OffSet;
Size = funcinfo->IndLevel +
pkt->IndLevel ?
funcinfo->fIsPtr64 ?
SIZEOFPOINTER64 : SIZEOFPOINTER : pkt->Size;
OffSet += ((Size + 3) & ~3) >> 2;
//
// Create ARGSLIST entry, and add it to the list
//
pArgsList = GenHeapAlloc(sizeof(ARGSLIST));
if (!pArgsList) {
ExitErrMsg(TRUE, "bal.\n");
}
memset(pArgsList, 0, sizeof(ARGSLIST));
if(funcinfo->sName == NULL) {
HostCastedName = GenHeapAlloc(sizeof(szHOSTAPPEND));
if (NULL == HostCastedName)
ExitErrMsg(FALSE, "Out of memory in BuildArgsList\n");
strcpy(HostCastedName, szHOSTAPPEND);
}
else {
HostCastedName = GenHeapAlloc(sizeof(szHOSTAPPEND) + strlen(funcinfo->sName));
if (NULL == HostCastedName)
ExitErrMsg(FALSE, "Out of memory in BuildArgsList\n");
strcpy(HostCastedName, funcinfo->sName);
strcat(HostCastedName, szHOSTAPPEND);
}
pArgsList->pKnownTypes = pkt;
pArgsList->OffSet = ArgOffSet;
pArgsList->IndLevel = funcinfo->IndLevel;
pArgsList->ArgSize = Size;
pArgsList->IsPtr64 = funcinfo->fIsPtr64;
pArgsList->Mod = funcinfo->tkPreMod;
pArgsList->tkDirection = funcinfo->tkDirection;
pArgsList->SUEOpt = funcinfo->tkSUE;
pArgsList->Type = funcinfo->sType;
pArgsList->PostMod = funcinfo->tkPostMod;
pArgsList->PrePostMod = funcinfo->tkPrePostMod;
pArgsList->Name = funcinfo->sName;
pArgsList->HostCastedName = HostCastedName;
pArgsList->fIsMember = FALSE;
pArgsList->bIsBitfield = FALSE;
pArgsList->BitsRequired= 0;
pArgsList->bIsArray = FALSE;
pArgsList->ArrayElements=0;
if (pkt->Flags & BTI_CONTAINSFUNCPTR) {
//
// This parameter type is either a function pointer, or
// a type which contains an embedded function pointer.
// Something is going to have to thunk it.
//
pArgsList->fRequiresThunk = TRUE;
}
if (pTempleEx) {
//
// There is an [EFunc] for this API. See if this param
// should have [Types] templates expanded or not.
//
for (i=0; i<NoTypeCount; ++i) {
if (pTempleEx->NoTypes[i] &&
strcmp(pArgsList->Name, pTempleEx->NoTypes[i]) == 0) {
//
// This param is not supposed to have [Types] expanded
//
pArgsList->fNoType = TRUE;
pTempleEx->NoTypes[i] = NULL;
}
}
}
InsertTailList(pListHead, &pArgsList->ArgumentsEntry);
//
// and on to the next argument .....
//
funcinfo = funcinfo->pfuncinfoNext;
}
if (pTempleEx) {
//
// For error reporting, indicate any NoTypes= that did not match
// a param name
//
for (i=0; i<NoTypeCount; ++i) {
if (pTempleEx->NoTypes[i]) {
ExitErrMsg(FALSE, "[EFunc] %s(%x) has a 'NoType=%s' which does not correspond to an argument name\n", pTempleEx->Name, pTempleEx, pTempleEx->NoTypes[i]);
}
}
}
return;
}
//
// return pointer to type of first argument
char *NArgType(PCGENSTATE pCGenState, char *s, int iLen, char **ppSrc)
{
PARGSLIST pArgsList;
PLIST_ENTRY Next;
char *pch = s;
CGENSTATE CGenState;
int Len, i;
char *pSrc;
pSrc = *ppSrc;
if (*pSrc != '(') {
ErrMsg("Incorrect NArgType parameter %s\n", pSrc);
fprintf(pCGenState->CGen->fp, "** ERROR ** Incorrect NArgType parameter %s\n", pSrc);
return NULL;
}
pSrc++;
i = 0;
while ((*pSrc != ')') && (i < iLen-1)) {
s[i++] = *pSrc++;
}
s[i] = 0;
*ppSrc = ++pSrc;
Len = atoi(s);
if (Len-- == 0) {
ErrMsg("Invalid NArgType parameter %s\n", s);
fprintf(pCGenState->CGen->fp, "** ERROR ** Invalid NArgType parameter %s\n", s);
return NULL;
}
if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** NArgType Missing argument List: %s\n\n",
pCGenState->ApiTypes->TypeName
);
return NULL;
}
Next = pCGenState->ExportsDbg->ArgsListHead.Flink;
// check for void arg list
pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry);
if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) {
return NULL;
}
CGenState = *pCGenState;
for (i = 0; (i < Len) && (Next != &CGenState.ExportsDbg->ArgsListHead); i++) {
Next= Next->Flink;
}
if (Next == &CGenState.ExportsDbg->ArgsListHead) {
ErrMsg("NArgType parameter out of range %d\n", Len);
fprintf(pCGenState->CGen->fp, "** ERROR ** NArgType parameter out of range %d\n", Len);
return NULL;
}
CGenState.pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry);
//
// Copy in the explicit struct/union/enum keyword, if present
//
strcat(pch, TokenString[CGenState.pArgsList->SUEOpt]);
//
// Copy in the actual typename
//
strcpy(pch, CGenState.pArgsList->Type);
if (CGenState.pArgsList->PrePostMod != TK_NONE) {
strcat(pch, " ");
strcat(pch, TokenString[CGenState.pArgsList->PrePostMod]);
}
pch = pch + strlen(pch);
if (CGenState.pArgsList->IndLevel) {
*pch++ = ' ';
for (i=0; i<CGenState.pArgsList->IndLevel; ++i) {
*pch++ = '*';
}
}
*pch = '\0';
return(s);
}
//
// return pointer to name of first argument
char *NArgName(PCGENSTATE pCGenState, char *s, int iLen, char **ppSrc)
{
PARGSLIST pArgsList;
PLIST_ENTRY Next;
char *pch = s;
CGENSTATE CGenState;
int Len, i;
char *pSrc;
pSrc = *ppSrc;
if (*pSrc != '(') {
ErrMsg("Incorrect NArgType parameter %s\n", pSrc);
fprintf(pCGenState->CGen->fp, "** ERROR ** Incorrect NArgType parameter %s\n", pSrc);
return(NULL);
}
pSrc++;
i = 0;
while ((*pSrc != ')') && (i < iLen-1)) {
s[i++] = *pSrc++;
}
s[i] = 0;
*ppSrc = ++pSrc;
Len = atoi(s);
if (Len-- == 0) {
ErrMsg("Invalid NArgType parameter %s\n", s);
fprintf(pCGenState->CGen->fp, "** ERROR ** Invalid NArgType parameter %s\n", s);
return(NULL);
}
if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** NArgType Missing argument List: %s\n\n",
pCGenState->ApiTypes->TypeName
);
return(NULL);
}
Next = pCGenState->ExportsDbg->ArgsListHead.Flink;
// check for void arg list
pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry);
if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) {
return(NULL);
}
CGenState = *pCGenState;
for (i = 0; (i < Len) && (Next != &CGenState.ExportsDbg->ArgsListHead); i++) {
Next= Next->Flink;
}
if (Next == &CGenState.ExportsDbg->ArgsListHead) {
ErrMsg("NArgName parameter out of range %d\n", Len);
fprintf(pCGenState->CGen->fp, "** ERROR ** NArgName parameter out of range %d\n", Len);
return(NULL);
}
CGenState.pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry);
strcpy(pch, CGenState.pArgsList->Name);
return(s);
}
char *
MArg(
char *pSrc,
PCGENSTATE pCGenState,
PSTR *pBuffer
)
/*++
Routine Description:
Expand the n'th argument for the current macro
Arguments:
pSrc - pointer to character following 'MArg'
pCGenState - current code-gen state
Return Value:
pointer to character following the end of the macro argument
--*/
{
int i;
int ArgNum;
PMACROARGSLIST pList = pCGenState->pMacroArgsList;
char s[MAX_PATH];
PMACROARGSLIST OldList;
if (!pList) {
ExitErrMsg(FALSE, "%s(%d) MArg unexpected: no macro is currently being expanded\n", TemplateFileName, TemplateLine);
return NULL;
}
if (*pSrc != '(') {
ExitErrMsg(FALSE, "%s(%d) Incorrect MArg parameter %s\n", TemplateFileName, TemplateLine, pSrc);
return NULL;
}
pSrc++;
i = 0;
while ((*pSrc != ')') && (i < sizeof(s)-1)) {
s[i++] = *pSrc++;
}
s[i] = 0;
ArgNum = atoi(s);
pSrc++; // skip ')'
if (ArgNum-- == 0) {
ExitErrMsg(FALSE, "%s(%d) Invalid MArg parameter %s\n", TemplateFileName, TemplateLine, s);
return NULL;
}
if (ArgNum >= pList->NumArgs) {
ExitErrMsg(FALSE, "%s(%d) Macro only takes %d arguments\n", TemplateFileName, TemplateLine, pList->NumArgs);
return NULL;
}
if (pBuffer == NULL) {
OldList = pCGenState->pMacroArgsList;
pCGenState->pMacroArgsList = MacroStack[--MacroStackTop];
CGenerate(pList->ArgText[ArgNum], pCGenState);
MacroStack[MacroStackTop++] = pCGenState->pMacroArgsList;
pCGenState->pMacroArgsList = OldList;
}
else {
*pBuffer = pList->ArgText[ArgNum];
}
return pSrc;
}
char *ArgType(char *Buffer, PCGENSTATE pCGenState) {
char *pch;
if (pCGenState->pArgsList) {
int i;
pch = Buffer;
if (pCGenState->pArgsList->SUEOpt != TK_NONE) {
strcpy(pch, TokenString[pCGenState->pArgsList->SUEOpt]);
strcat(pch, " ");
pch += strlen(pch);
}
strcpy(pch, pCGenState->pArgsList->Type);
if (pCGenState->pArgsList->PrePostMod != TK_NONE) {
strcat(pch, " ");
strcat(pch, TokenString[pCGenState->pArgsList->PrePostMod]);
}
pch = pch+strlen(pch);
if (pCGenState->pArgsList->IndLevel) {
*pch++ = ' ';
for (i=0; i<pCGenState->pArgsList->IndLevel; ++i) {
*pch++ = '*';
}
}
*pch = '\0';
pch = Buffer;
return pch;
}
else
return NULL;
}
char *UnalignedTag64(char *Buffer, PCGENSTATE pCGenState) {
//
// PUT UNALIGNED TAg for interested type like KLPWST KHBITMAP all kernel mode shareable struct
//
char CurrArgType[256];
if ( NULL == ArgType ( CurrArgType, pCGenState))
return NULL;
//
// Now chek the name
//
if ( pCGenState->pArgsList->ArgSize == 8 ) {
//
// BUGBUG: check if you need special case for KLPWSTR and KHBITMAP
// if so put more generic form
//(strncmp ( CurrAgrType, "KLPWSTR ",7) == 0) ||
//(strncmp ( CurrAgrType, "KHBITMAP ",8) == 0)
//
strcpy (Buffer, "*(UNALIGNED ");
strcat (Buffer, CurrArgType);
if (strchr(CurrArgType, '*') == NULL )
strcat ( Buffer, " ");
strcat (Buffer, "*)&");
return Buffer;
}
return NULL;
}
char *ArgHostType(char *Buffer, PCGENSTATE pCGenState) {
char *pch;
if (pCGenState->pArgsList) {
int i;
pch = Buffer;
/*if (pCGenState->pArgsList->SUEOpt != TK_NONE) {
strcpy(pch, TokenString[pCGenState->pArgsList->SUEOpt]);
strcat(pch, " ");
pch += strlen(pch);
}*/
if (pCGenState->pArgsList->IndLevel > 0) {
strcpy(pch, GetHostPointerName(pCGenState->pArgsList->IsPtr64));
pch += strlen(pch);
}
else {
char Buffer[MAX_PATH];
strcpy(pch, GetHostTypeName(pCGenState->pArgsList->pKnownTypes, Buffer));
pch += strlen(pch);
}
*pch = '\0';
pch = Buffer;
return pch;
}
else
return NULL;
}
BOOL IsPointer(PCGENSTATE pCGenState) {
return (pCGenState->pArgsList->IndLevel > 0) || (pCGenState->pArgsList->pKnownTypes->IndLevel > 0);
}
char *ArgTypeInd(char *Buffer, PCGENSTATE pCGenState, BOOL bHostName) {
CGENSTATE GenStateOld;
ARGSLIST ArgsListOld;
KNOWNTYPES KnownTypes;
PKNOWNTYPES pCurrent;
int IndLevel;
char *pch;
//copy over the old structures before mangaling them
GenStateOld = *pCGenState;
ArgsListOld = *(pCGenState->pArgsList);
KnownTypes = *(pCGenState->pArgsList->pKnownTypes);
pCGenState->pArgsList->pKnownTypes = &KnownTypes;
if (pCGenState->pArgsList->IndLevel > 0) {
IndLevel = pCGenState->pArgsList->IndLevel - 1;
goto success;
}
pCurrent = &KnownTypes;
IndLevel = pCurrent->IndLevel;
if (IndLevel == 0) {
ErrMsg("ArgTypeInd: Tried to get name of type pointed to by %s\n",pCGenState->pArgsList->Name);
ExitErrMsg(FALSE, "ArgTypeInd: %s is not a pointer!\n", pCGenState->pArgsList->Name);
}
while(1) {//chase all the way down to a struct/union/enum or a func_ptr
PCHAR IndName;
ASSERT(pCurrent != NULL);
if (pCurrent->IndLevel == 1 && !bHostName && ((IndName = IsDefinedPtrToPtrDependent(pCurrent->TypeName)) != NULL)) {
PKNOWNTYPES pkt;
IndLevel--;
pkt = GetNameFromTypesList(TypeDefsList, IndName);
ASSERT(pkt != NULL);
KnownTypes = *pkt;
goto success;
}
else if (pCurrent->pTypedefBase != NULL) {
pCurrent = pCurrent->pTypedefBase;
}
else {
//hit a struct/union/enum or func_ptr
KnownTypes = *pCurrent;
pCGenState->pArgsList->pStructType = NULL;
pCGenState->pArgsList->SUEOpt = TK_NONE;
IndLevel--;
if (pCurrent->Flags & BTI_NOTDERIVED) {
pCGenState->pArgsList->SUEOpt = TK_NONE;
goto success;
}
else if(strcmp("struct", KnownTypes.BaseName) == 0) {
pCGenState->pArgsList->SUEOpt = TK_STRUCT;
goto success;
}
else if(strcmp("union", KnownTypes.BaseName) == 0) {
pCGenState->pArgsList->SUEOpt = TK_UNION;
goto success;
}
else if(strcmp("enum", KnownTypes.BaseName) == 0) {
pCGenState->pArgsList->SUEOpt = TK_ENUM;
goto success;
}
else {
ExitErrMsg(FALSE, "ArgTypeInd: Can't determine what %s is.\n", pCGenState->pArgsList->Name);
}
}
}
success:
//fake out the typename and the indirection
KnownTypes.IndLevel = 0;
pCGenState->pArgsList->IndLevel = IndLevel;
pCGenState->pArgsList->Type = KnownTypes.TypeName;
//Print the mangled type, then restore the old type
if (bHostName)
pch = ArgHostType(Buffer, pCGenState);
else
pch = ArgType(Buffer, pCGenState);
*pCGenState = GenStateOld;
*(pCGenState->pArgsList) = ArgsListOld;
return pch;
}
char *ApiName(char *pSrc, char**pch, char *Buffer, PCGENSTATE pCGenState) {
char *pTemp;
strcpy(Buffer, pCGenState->ExportsDbg->ExportName);
// if ApiName has decoration then truncate it
pTemp = strchr(Buffer, '@');
if (pTemp) {
*pTemp = '\0';
}
*pch = Buffer;
return pSrc;
}
char *ApiNameSkip(char *pSrc, char**pch, char *Buffer, PCGENSTATE pCGenState) {
char *pNewSrc, *pTemp, *pEnd;
int CharsToSkip;
pNewSrc = ApiName(pSrc, pch, Buffer, pCGenState);
pEnd = SkipSubExpression(pNewSrc, NULL);
if (pNewSrc == pEnd)
return pNewSrc;
pTemp = pNewSrc+1;
CharsToSkip = atoi(pTemp);
while(**pch != '\0' && CharsToSkip > 0) {
(*pch)++;
CharsToSkip--;
}
return pEnd;
}
BOOL IsPointerToPtrDep(PARGSLIST pArgsList) {
PKNOWNTYPES pCurrent;
pCurrent = pArgsList->pKnownTypes;
if (pArgsList->IndLevel + pCurrent->IndLevel < 1)
ExitErrMsg(FALSE, "IsPointerToPtrDep: %s is not a pointer\n", pArgsList->Name);
if (pArgsList->IndLevel + pCurrent->IndLevel > 1) {
// Since pCurrent->IndLevel is acumulative, this can happen if and
// only if this type or one of its base types is a pointer to
// another pointer. This case is defined to be pointer dependent.
return TRUE;
}
// At this point, either pArgsList->IndLevel == 1 and pCurrent->IndLevel == 0
// or pArgsList->IndLevel == 0 and pCurrent->IndLevel = 1.
// First check if this type is defined to be a pointer to a pointer dependent type.
// If not, defererence the pointer by walking through typedefs until pCurrent->IndLevel = 0
// Note that multiple levels of pointers are no longer possible.
if(IsDefinedPtrToPtrDependent(pCurrent->TypeName)) {
return TRUE;
}
while(pCurrent->IndLevel != 0) {
// Check if this type is one of the special types used
// between sortpp and genthnk.
if (pCurrent->Flags & BTI_NOTDERIVED)
return FALSE;
// Assert that this type is not a struct, union, or enum.
// This shouldn't happen because sortpp should store
// these with an indlevel of 0.
ASSERT(strcmp(pCurrent->BaseName, "struct") != 0);
ASSERT(strcmp(pCurrent->BaseName, "union") != 0);
ASSERT(strcmp(pCurrent->BaseName, "enum") != 0);
// Check if this type is a function pointer. If it is,
// return FALSE since they are arbitrarly defined to not
// be pointer dependent. This may be changed check if any
// of the arguments to the function pointer are pointer dependent.
if (strcmp(pCurrent->BaseName, "()") == 0)
return FALSE;
// Get the base typedef.
pCurrent = pCurrent->pTypedefBase;
}
// Now that the pointer has been dereferenced, test if
// this type is pointer dependent.
return (pCurrent->Flags & BTI_POINTERDEP) != 0;
}
char *TestIfPointerToPtrDep(char *pSrc, PCGENSTATE pCGenState, PCHAR pch) {
PCHAR pEnd;
PMACROARGSLIST pMArgsList;
ARGSLIST ArgsList;
CHAR TypeName[MAX_PATH];
SIZE_T BytesReturned;
pEnd = SkipSubExpression(pSrc, NULL);
if (pSrc == pEnd) {
ExitErrMsg(FALSE, "TestIfPointerToPtrDep: exactly 1 argument is required.\n");
}
ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList);
if (pMArgsList->NumArgs != 1) {
ExitErrMsg(FALSE, "IncludeRetTypes: exactly 1 argument is required.\n");
}
CGenerateEx(pMArgsList->ArgText[0], pCGenState, TypeName, MAX_PATH, &BytesReturned);
SetArgListToTypeForArg(&ArgsList, &ArgsList, TypeName);
if(IsPointerToPtrDep(&ArgsList)) {
strcpy(pch, "1");
}
else {
strcpy(pch, "0");
}
FreeMacroArgsList(pMArgsList);
return pEnd;
}
BOOL IsPtrDep(PARGSLIST pArgsList) {
//This is a pointer to something(ptr dep.)
if (pArgsList->IndLevel > 0)
return TRUE;
return pArgsList->pKnownTypes->Flags & ( BTI_POINTERDEP | BTI_INT64DEP );
}
BOOL IsInt64DepUnion(PCGENSTATE pCGenState) {
char Buff[256];
Buff[0]=0;
ArgTypeInd( Buff, pCGenState, FALSE);
// make exception for union _ULARGE_INTEGER
if (strncmp(Buff, "union _ULARGE_INTEGER", sizeof ("union _ULARGE_INTEGER")) == 0 )
return TRUE; //IsPointerToPtrDep ( pArgsList );
if (strncmp(Buff, "union _LARGE_INTEGER", sizeof ("union _LARGE_INTEGER")) == 0 )
return TRUE; //IsPointerToPtrDep ( pArgsList );
return FALSE; //pArgsList->pKnownTypes->Flags & BTI_INT64DEP;
}
void DoIndent(PCGENSTATE pCGenState) {
int i;
for(i=IndentLevel, OutputColumn = 1; i > 0; i--,OutputColumn++) {
if (fputc(' ', pCGenState->CGen->fp) != ' ')
ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC);
OutputColumn++;
}
}
char * CGeneratePrintChar(char *pch, PCGENSTATE pCGenState) {
if (!bStripNewline) {
if('\n' == *pch)
OutputColumn = 0; //will be incremented to 1
goto PrintIt;
}
else {
int i;
if (*pch == '\n')
goto SkipIt;
if (!bFirstCharHit) {
if(!isspace(*pch)) {
DoIndent(pCGenState);
bFirstCharHit = TRUE;
goto PrintIt;
}
else
goto SkipIt;
}
else
goto PrintIt;
}
PrintIt:
if (fputc(*pch, pCGenState->CGen->fp) != *pch)
goto PrintError;
OutputColumn++;
SkipIt:
return pch + 1;
PrintError:
ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC);
return NULL;
}
char *CGenerate(char *pSrc, PCGENSTATE pCGenState) {
return CGenerateEx(pSrc, pCGenState, NULL, 0, NULL);
}
/*
* CGenerate
*
*/
char *CGenerateEx(char *pSrc, PCGENSTATE pCGenState, char *OutBuffer, SIZE_T MaxLen, SIZE_T *BytesReturned)
{
FILE **pfp = &pCGenState->CGen->fp;
char *pch;
int i;
size_t Len;
char Buffer[MAX_PATH*4];
char *BufferPos = NULL;
if (OutBuffer != NULL) {
BufferPos = OutBuffer;
*BytesReturned = 0;
}
while (*pSrc) {
if (OutBuffer != NULL && MaxLen == 0) {
ExitErrMsg(FALSE, "Out of buffer space!\n");
}
if (*pSrc != '@') {
if (OutBuffer != NULL) {
*BufferPos++ = *pSrc++;
*BytesReturned += 1;
MaxLen--;
}
else {
pSrc = CGeneratePrintChar(pSrc, pCGenState);
}
}
else if (*(pSrc + 1) == '@') {
pSrc++;
if (OutBuffer != NULL) {
*BufferPos++ = *pSrc++;
*BytesReturned += 1;
MaxLen--;
}
else {
pSrc = CGeneratePrintChar(pSrc, pCGenState);
}
}
else {
pch = NULL;
memset(Buffer, 0, sizeof(Buffer));
pSrc++; //skip the @ is the command name
if(bStripNewline && !bFirstCharHit) {
OutputColumn = 1 + IndentLevel;
}
if (!strncmp(pSrc, szNL, sizeof(szNL) - 1)) {
pSrc += sizeof(szNL) - 1;
if (fputc('\n', *pfp) != '\n')
ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC);
OutputColumn = 1;
bFirstCharHit = FALSE;
}
else if (!strncmp(pSrc, szINDENT, sizeof(szINDENT) - 1)) {
int OldIndent;
pSrc += sizeof(szINDENT) - 1;
OldIndent = IndentLevel;
IndentLevel += INDENTSIZE;
pSrc = WriteMore(pSrc, pCGenState, TRUE);
IndentLevel = OldIndent;
}
else if (!strncmp(pSrc, szNOFORMAT, sizeof(szNOFORMAT) - 1)) {
BOOL bOldStripNewline;
pSrc += sizeof(szNOFORMAT) - 1;
bOldStripNewline = bStripNewline;
bStripNewline = FALSE;
pSrc = WriteMore(pSrc, pCGenState, TRUE);
bStripNewline = bOldStripNewline;
}
else if (!strncmp(pSrc, szTEMPLATE, sizeof(szTEMPLATE) - 1)) {
pSrc += sizeof(szTEMPLATE) - 1;
pSrc = IncludeTemplate(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szAPILIST, sizeof(szAPILIST) - 1)) {
pSrc += sizeof(szAPILIST) - 1;
pSrc = ListApis(pSrc, pCGenState, FALSE);
}
else if (!strncmp(pSrc, szAPINAMESKIP, sizeof(szAPINAMESKIP) -1 )) {
pSrc += sizeof(szAPINAMESKIP) - 1;
pSrc = ApiNameSkip(pSrc, &pch, Buffer, pCGenState);
}
else if (!strncmp(pSrc, szAPINAME, sizeof(szAPINAME) - 1)) {
pSrc += sizeof(szAPINAME) - 1;
pSrc = ApiName(pSrc, &pch, Buffer, pCGenState);
}
else if (!strncmp(pSrc, szAPIFORWARD, sizeof(szAPIFORWARD) - 1)) {
pSrc += sizeof(szAPIFORWARD) - 1;
if (pCGenState->ExportsDbg->IntForward) {
strcpy(Buffer, szINTFORWARD);
strcpy(Buffer + sizeof(szINTFORWARD) - 1,
pCGenState->ExportsDbg->IntForward->ExportName
);
}
else {
strcpy(Buffer, pCGenState->ExportsDbg->ExportName);
}
// if ApiName has decoration then truncate it
pch = strchr(Buffer, '@');
if (pch) {
*pch = '\0';
}
pch = Buffer;
}
else if (!strncmp(pSrc, szAPINUM, sizeof(szAPINUM) - 1)) {
_itoa(pCGenState->ApiNum, Buffer, 10);
pch = Buffer;
pSrc += sizeof(szAPINUM) - 1;
}
else if (!strncmp(pSrc, szAPIFNRET, sizeof(szAPIFNRET) - 1)) {
if (pCGenState->ApiTypes) {
pch = pCGenState->ApiTypes->FuncRet;
}
pSrc += sizeof(szAPIFNRET) - 1;
}
else if (!strncmp(pSrc, szAPIDECLSPEC, sizeof(szAPIDECLSPEC) - 1)) {
BOOL b = pCGenState->ApiTypes && (pCGenState->ApiTypes->Flags & BTI_DLLEXPORT);
pSrc += sizeof(szAPIDECLSPEC) - 1;
pSrc = WriteMore(pSrc, pCGenState, b);
}
else if (!strncmp(pSrc, szAPIFNMOD, sizeof(szAPIFNMOD) - 1)) {
if (pCGenState->ApiTypes) {
pch = pCGenState->ApiTypes->FuncMod;
}
pSrc += sizeof(szAPIFNMOD) - 1;
}
else if (!strncmp(pSrc, szAPIMORE, sizeof(szAPIMORE) - 1)) {
pSrc += sizeof(szAPIMORE) - 1;
pSrc = WriteMore(pSrc, pCGenState, pCGenState->MoreApis);
}
else if (!strncmp(pSrc, szIFAPIRET, sizeof(szIFAPIRET) - 1)) {
pSrc += sizeof(szIFAPIRET) - 1;
pSrc = IfApiRet(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szIFISMEMBER, sizeof(szIFISMEMBER) - 1)) {
pSrc += sizeof(szIFISMEMBER) - 1;
pSrc = WriteMore(pSrc, pCGenState, pCGenState->pArgsList->fIsMember);
}
else if (!strncmp(pSrc, szIFNISMEMBER, sizeof(szIFNISMEMBER) - 1)) {
pSrc += sizeof(szIFNISMEMBER) - 1;
pSrc = WriteMore(pSrc, pCGenState, !(pCGenState->pArgsList->fIsMember));
}
else if (!strncmp(pSrc, szIFISBITFIELD, sizeof(szIFISBITFIELD) - 1)) {
pSrc += sizeof(szIFISBITFIELD) - 1;
pSrc = WriteMore(pSrc, pCGenState, pCGenState->pArgsList->bIsBitfield);
}
else if (!strncmp(pSrc, szIFNISBITFIELD, sizeof(szIFNISBITFIELD) - 1)) {
pSrc += sizeof(szIFNISBITFIELD) - 1;
pSrc = WriteMore(pSrc, pCGenState, !(pCGenState->pArgsList->bIsBitfield));
}
else if (!strncmp(pSrc, szIFISARRAY, sizeof(szIFISARRAY) - 1)) {
pSrc += sizeof(szIFISARRAY) - 1;
pSrc = WriteMore(pSrc, pCGenState, pCGenState->pArgsList->bIsArray);
}
else if (!strncmp(pSrc, szIFNISARRAY, sizeof(szIFNISARRAY) - 1)) {
pSrc += sizeof(szIFNISARRAY) - 1;
pSrc = WriteMore(pSrc, pCGenState, !(pCGenState->pArgsList->bIsArray));
}
else if (!strncmp(pSrc, szARGARRAYELEMENTS, sizeof(szARGARRAYELEMENTS) - 1)) {
pSrc += sizeof(szARGARRAYELEMENTS) - 1;
_itoa((int)(pCGenState->pArgsList->ArrayElements), Buffer, 10);
pch = Buffer;
}
else if (!strncmp(pSrc, szIFPOINTERTOPTRDEP, sizeof(szIFPOINTERTOPTRDEP) -1 )) {
pSrc += sizeof(szIFPOINTERTOPTRDEP) - 1;
pSrc = WriteMore(pSrc, pCGenState, IsPointerToPtrDep(pCGenState->pArgsList));
}
else if (!strncmp(pSrc, szIFNPOINTERTOPTRDEP, sizeof(szIFNPOINTERTOPTRDEP) -1 )) {
pSrc += sizeof(szIFNPOINTERTOPTRDEP) - 1;
pSrc = WriteMore(pSrc, pCGenState, !IsPointerToPtrDep(pCGenState->pArgsList));
}
else if (!strncmp(pSrc, szISPOINTERTOPTRDEP, sizeof(szISPOINTERTOPTRDEP) -1 )) {
pSrc += sizeof(szISPOINTERTOPTRDEP) - 1;
pch = Buffer;
pSrc = TestIfPointerToPtrDep(pSrc, pCGenState, pch);
}
else if (!strncmp(pSrc, szIFPTRDEP, sizeof(szIFPTRDEP) -1 )) {
pSrc += sizeof(szIFPTRDEP) - 1;
pSrc = WriteMore(pSrc, pCGenState, IsPtrDep(pCGenState->pArgsList));
}
else if (!strncmp(pSrc, szIFNPTRDEP, sizeof(szIFNPTRDEP) -1 )) {
pSrc += sizeof(szIFNPTRDEP) - 1;
pSrc = WriteMore(pSrc, pCGenState, !IsPtrDep(pCGenState->pArgsList));
}
else if (!strncmp(pSrc, szIFINT64DEPUNION, sizeof(szIFINT64DEPUNION) -1 )) {
pSrc += sizeof(szIFINT64DEPUNION) - 1;
pSrc = WriteMore(pSrc, pCGenState, IsInt64DepUnion(pCGenState));
}
else if (!strncmp(pSrc, szIFNINT64DEPUNION, sizeof(szIFNINT64DEPUNION) -1 )) {
pSrc += sizeof(szIFNINT64DEPUNION) - 1;
pSrc = WriteMore(pSrc, pCGenState, !IsInt64DepUnion(pCGenState));
}
else if (!strncmp(pSrc, szIFAPICODE, sizeof(szIFAPICODE) - 1)) {
pSrc += sizeof(szIFAPICODE) - 1;
pSrc = IfApiCode(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szFASTCALL, sizeof(szFASTCALL) - 1)) {
pSrc += sizeof(szFASTCALL) - 1;
pSrc = WriteMore(pSrc, pCGenState, IsFastCall(pCGenState));
}
else if (!strncmp(pSrc, szSLOWCALL, sizeof(szSLOWCALL) - 1)) {
pSrc += sizeof(szSLOWCALL) - 1;
pSrc = WriteMore(pSrc, pCGenState, !IsFastCall(pCGenState));
}
else if (!strncmp(pSrc, szFASTX2NMETH, sizeof(szFASTX2NMETH) - 1)) {
pSrc += sizeof(szFASTX2NMETH) - 1;
pSrc = WriteMore(pSrc, pCGenState, GetX2NMethodType(pCGenState) == FASTX2NMETHOD);
}
else if (!strncmp(pSrc, szSLOWX2NMETH, sizeof(szSLOWX2NMETH) - 1)) {
pSrc += sizeof(szSLOWX2NMETH) - 1;
pSrc = WriteMore(pSrc, pCGenState, GetX2NMethodType(pCGenState) == SLOWX2NMETHOD);
}
else if (!strncmp(pSrc, szFATX2NMETH, sizeof(szFATX2NMETH) - 1)) {
pSrc += sizeof(szFATX2NMETH) - 1;
pSrc = WriteMore(pSrc, pCGenState, GetX2NMethodType(pCGenState) == FATX2NMETHOD);
}
else if (!strncmp(pSrc, szMETHODNUMBER, sizeof(szMETHODNUMBER) - 1)) {
pSrc += sizeof(szMETHODNUMBER) - 1;
_itoa(pCGenState->ExportsDbg->MethodNumber, Buffer, 10);
pch = Buffer;
}
else if (!strncmp(pSrc, szIFARGS, sizeof(szIFARGS) - 1)) {
pSrc += sizeof(szIFARGS) - 1;
pSrc = IfArgs(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szFUNCARGNUM, sizeof(szFUNCARGNUM) - 1)) {
pSrc += sizeof(szFUNCARGNUM) - 1;
_itoa(GetFuncArgNum(pCGenState), Buffer, 10);
pch = Buffer;
}
else if (!strncmp(pSrc, szRETSIZE, sizeof(szRETSIZE) - 1)) {
pSrc += sizeof(szRETSIZE) - 1;
_itoa(GetRetSize(pCGenState), Buffer, 10);
pch = Buffer;
}
else if (!strncmp(pSrc, szARGSIZE, sizeof(szARGSIZE) - 1)) {
pSrc += sizeof(szARGSIZE) - 1;
_itoa(GetArgSize(pCGenState->ExportsDbg), Buffer, 10);
pch = Buffer;
}
else if (!strncmp(pSrc, szFORCASE, sizeof(szFORCASE) - 1)) {
pSrc += sizeof(szFORCASE) - 1;
pSrc = ForCase(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szCARGEXIST, sizeof(szCARGEXIST) - 1)) {
pSrc += sizeof(szCARGEXIST) - 1;
if (OutBuffer != NULL) {
pSrc = CArg(pSrc, pCGenState, &pch, TRUE);
}
else {
pSrc = CArg(pSrc, pCGenState, NULL, TRUE);
}
}
else if (!strncmp(pSrc, szCARG, sizeof(szCARG) - 1)) {
pSrc += sizeof(szCARG) - 1;
if (OutBuffer != NULL) {
pSrc = CArg(pSrc, pCGenState, &pch, FALSE);
}
else {
pSrc = CArg(pSrc, pCGenState, NULL, FALSE);
}
}
else if (!strncmp(pSrc, szCNUMBER, sizeof(szCNUMBER) - 1)) {
pSrc += sizeof(szCNUMBER) - 1;
_itoa(pCGenState->CaseNumber, Buffer, 10);
pch = Buffer;
}
else if (!strncmp(pSrc, szARGLIST, sizeof(szARGLIST) - 1)) {
pSrc += sizeof(szARGLIST) - 1;
if (pCGenState->ApiTypes) {
pSrc = ListArgs(pSrc, pCGenState, TRUE);
}
}
else if (!strncmp(pSrc, szNARGTYPE, sizeof(szNARGTYPE) - 1)) {
pSrc += sizeof(szNARGTYPE) - 1;
pch = NArgType(pCGenState, Buffer, sizeof(Buffer), &pSrc);
}
else if (!strncmp(pSrc, szNARGNAME, sizeof(szNARGNAME) - 1)) {
pSrc += sizeof(szNARGNAME) - 1;
pch = NArgName(pCGenState, Buffer, sizeof(Buffer), &pSrc);
}
else if (!strncmp(pSrc, szMARG, sizeof(szMARG) - 1)) {
pSrc += sizeof(szMARG) - 1;
if (OutBuffer != NULL) {
pSrc = MArg(pSrc, pCGenState, &pch);
}
else {
pSrc = MArg(pSrc, pCGenState, NULL);
}
}
else if (!strncmp(pSrc, szFORCETYPE, sizeof(szFORCETYPE) - 1)) {
pSrc += sizeof(szFORCETYPE) - 1;
pSrc = ForceTypeExpand( pSrc, pCGenState);
}
else if (!strncmp(pSrc, szMEMBERTYPES, sizeof(szMEMBERTYPES) - 1)) {
pSrc += sizeof(szMEMBERTYPES) - 1;
pSrc = MemberTypes( pSrc, pCGenState, FALSE);
}
else if (!strncmp(pSrc, szBTOTMEMBERTYPES, sizeof(szBTOTMEMBERTYPES) - 1)) {
pSrc += sizeof(szBTOTMEMBERTYPES) - 1;
pSrc = MemberTypes( pSrc, pCGenState, TRUE);
}
else if (!strncmp(pSrc, szLOG, sizeof(szLOG) - 1)) {
pSrc += sizeof(szLOG) - 1;
pSrc = UpdateLog(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szIFRETTYPE, sizeof(szIFRETTYPE) - 1)) {
pSrc += sizeof(szIFRETTYPE) - 1;
pSrc = IfRetType(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szIFNOTRETTYPE, sizeof(szIFNOTRETTYPE) - 1)) {
pSrc += sizeof(szIFNOTRETTYPE) - 1;
pSrc = IfNotRetType(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szARGMOD, sizeof(szARGMOD) - 1)) {
pSrc += sizeof(szARGMOD) - 1;
if (pCGenState->pArgsList) {
pch = TokenString[pCGenState->pArgsList->Mod];
}
}
else if (!strncmp(pSrc, szARGPOSTMOD, sizeof(szARGPOSTMOD) - 1)) {
pSrc += sizeof(szARGPOSTMOD) - 1;
if (pCGenState->pArgsList) {
pch = TokenString[pCGenState->pArgsList->PostMod];
}
}
else if (!strncmp(pSrc, szARGTYPEIND, sizeof(szARGTYPEIND) - 1)) {
pSrc += sizeof(szARGTYPEIND) - 1;
pch = ArgTypeInd(Buffer, pCGenState, FALSE);
}
else if (!strncmp(pSrc, szARGHOSTTYPEIND, sizeof(szARGHOSTTYPEIND) - 1)) {
pSrc += sizeof(szARGHOSTTYPEIND) - 1;
pch = ArgTypeInd(Buffer, pCGenState, TRUE);
}
else if (!strncmp(pSrc, szARGHOSTTYPE, sizeof(szARGHOSTTYPE) -1 )) {
pSrc += sizeof(szARGHOSTTYPE) - 1;
pch = ArgHostType(Buffer, pCGenState);
}
else if (!strncmp(pSrc, szARGTYPE, sizeof(szARGTYPE) - 1)) {
pSrc += sizeof(szARGTYPE) - 1;
pch = ArgType(Buffer, pCGenState);
}
else if (!strncmp(pSrc, szUNALIGNEDTAG64, sizeof(szUNALIGNEDTAG64) - 1)) {
pSrc += sizeof(szUNALIGNEDTAG64) - 1;
pch = UnalignedTag64(Buffer, pCGenState);
}
else if (!strncmp(pSrc, szARGNAME, sizeof(szARGNAME) - 1)) {
if (pCGenState->pArgsList) {
pch = pCGenState->pArgsList->Name;
if (!pch) {
pch = "";
}
}
pSrc += sizeof(szARGNAME) - 1;
}
else if (!strncmp(pSrc, szARGNAMEHOSTCASTED, sizeof(szARGNAMEHOSTCASTED) - 1)) {
if (pCGenState->pArgsList) {
pch = pCGenState->pArgsList->HostCastedName;
if (!pch) {
if (pCGenState->pArgsList->Name == NULL)
pch = "";
else
pch = pCGenState->pArgsList->Name;
}
}
pSrc += sizeof(szARGNAMEHOSTCASTED) - 1;
}
else if (!strncmp(pSrc, szARGVAL, sizeof(szARGVAL) - 1)) {
if (pCGenState->pArgsList) {
strcpy(Buffer, pCGenState->pArgsList->Name);
// replace all occurrences of '->' by '__'
// and '.', '*', ')', and '(' by '_'
pch = Buffer;
while (*pch) {
if (*pch == '.' || *pch == ')' || *pch == '(' || *pch == '*')
*pch = '_';
else if (*pch == '-' && *(pch+1) == '>') {
*pch = '_';
*(pch+1) = '_';
pch++;
}
pch++;
}
pch = Buffer;
} else {
pch = "";
}
pSrc += sizeof(szARGVAL) - 1;
}
else if (!strncmp(pSrc, szARGOFF, sizeof(szARGOFF) - 1)) {
pSrc += sizeof(szARGOFF) - 1;
if (pCGenState->pArgsList) {
_itoa(pCGenState->pArgsList->OffSet, Buffer, 10);
pch = Buffer;
}
}
else if (!strncmp(pSrc, szARGADDR, sizeof(szARGADDR) - 1)) {
pSrc += sizeof(szARGADDR) - 1;
if (pCGenState->pArgsList) {
if (pCGenState->pArgsList->ArgLocal) {
pch = Buffer;
*pch = '&';
strcpy(pch+1, pCGenState->pArgsList->ArgLocal);
pSrc = SkipSubExpression(pSrc, NULL); }
else {
pch = Buffer;
pSrc = WriteArgAddr(pSrc,
pCGenState,
pch,
sizeof(Buffer)-1
);
}
}
}
else if (!strncmp(pSrc, szADDRARGSLIST, sizeof(szADDRARGSLIST) - 1)) {
pSrc += sizeof(szADDRARGSLIST) - 1;
pch = GetAddrFirstArg(pCGenState, Buffer, sizeof(Buffer) - 1);
}
else if (!strncmp(pSrc, szARGLOCAL, sizeof(szARGLOCAL) - 1)) {
pSrc += sizeof(szARGLOCAL) - 1;
if (pCGenState->pArgsList) {
pch = Buffer;
if (!WriteArgLocal(pCGenState, pch, sizeof(Buffer)-1)) {
ExitErrMsg(FALSE, "CGenerate failed\n");
}
}
}
else if (!strncmp(pSrc, szARGMORE, sizeof(szARGMORE) - 1)) {
pSrc += sizeof(szARGMORE) - 1;
pSrc = WriteMore(pSrc,
pCGenState,
pCGenState->pArgsList &&
pCGenState->pArgsList->ArgumentsEntry.Flink
!= &pCGenState->ExportsDbg->ArgsListHead
);
}
else if (!strncmp(pSrc, szTYPES, sizeof(szTYPES) - 1)) {
pSrc += sizeof(szTYPES) - 1;
pSrc = IncludeTypes(pSrc, pCGenState, FALSE);
}
else if (!strncmp(pSrc, szRTOLTYPES, sizeof(szRTOLTYPES) - 1)) {
pSrc += sizeof(szRTOLTYPES) - 1;
pSrc = IncludeTypes(pSrc, pCGenState, TRUE);
}
else if (!strncmp(pSrc, szRETTYPE, sizeof(szRETTYPE) - 1)) {
pSrc += sizeof(szRETTYPE) - 1;
pSrc = IncludeRetType(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szEXPORTLIST, sizeof(szEXPORTLIST) - 1)) {
pSrc += sizeof(szEXPORTLIST) - 1;
pSrc = ListApis(pSrc, pCGenState, TRUE);
}
else if (!strncmp(pSrc, szEXPNAME, sizeof(szEXPNAME) - 1)) {
pSrc += sizeof(szEXPNAME) - 1;
pch = pCGenState->ExportsDbg->ExportName;
}
else if (!strncmp(pSrc, szIFEXPFORWARD, sizeof(szIFEXPFORWARD) - 1)) {
pSrc += sizeof(szIFEXPFORWARD) - 1;
pch = GetAltExportName(Buffer, pCGenState, sizeof(Buffer) - 1);
}
else if (!strncmp(pSrc, szIFORDINALS, sizeof(szIFORDINALS) - 1)) {
pSrc += sizeof(szIFORDINALS) - 1;
if (pCGenState->ExportsDbg &&
(pCGenState->ExportsDbg->Ordinal & 0x80000000))
{
pch = Buffer;
*pch = '@';
_itoa(IMPORDINAL(pCGenState->ExportsDbg->Ordinal),
pch + 1,
10
);
}
}
else if (!strncmp(pSrc, szLISTCOL, sizeof(szLISTCOL) - 1)) {
pSrc += sizeof(szLISTCOL) - 1;
pCGenState->ListCol = OutputColumn;
}
else if (!strncmp(pSrc, szDLLNAME, sizeof(szDLLNAME) - 1)) {
Len = CopyToken(Buffer, DllBaseName, sizeof(Buffer) - 1);
if (Len >= sizeof(Buffer) - 1) {
ExitErrMsg(FALSE, "OverFlow %s\n", pSrc);
}
pch = Buffer;
pSrc += sizeof(szDLLNAME) - 1;
}
else if (!strncmp(pSrc, szXPTNAME, sizeof(szXPTNAME) - 1)) {
Len = CopyToken(Buffer, XptBaseName, sizeof(Buffer) - 1);
if (Len >= sizeof(Buffer) - 1) {
ExitErrMsg(FALSE, "OverFlow %s\n", pSrc);
}
pch = Buffer;
pSrc += sizeof(szXPTNAME) - 1;
}
else if (!strncmp(pSrc, szDLLTARGET, sizeof(szDLLTARGET) - 1)) {
Len = CopyToken(Buffer, pCGenState->CGen->FileBaseNameC, sizeof(Buffer) - 1);
if (Len >= sizeof(Buffer) - 1) {
ExitErrMsg(FALSE, "Overflow %s\n", pSrc);
}
pch = Buffer;
pSrc += sizeof(szDLLTARGET) - 1;
}
else if (!strncmp(pSrc, szAPIUNKNOWN, sizeof(szAPIUNKNOWN) - 1)) {
pSrc += sizeof(szAPIUNKNOWN) - 1;
pSrc = WriteMore(pSrc,
pCGenState,
pCGenState->ExportsDbg->UnKnownApi
);
}
else if (!strncmp(pSrc, szAPINODECL, sizeof(szAPINODECL) - 1)) {
pSrc += sizeof(szAPINODECL) - 1;
pSrc = WriteMore(pSrc,
pCGenState,
pCGenState->ExportsDbg->UnKnownApi == 1
);
}
else if (!strncmp(pSrc, szAPISTRINGS, sizeof(szAPISTRINGS) - 1)) {
pSrc += sizeof(szAPISTRINGS) - 1;
if (pCGenState->ApiTypes) {
ApiStrings(pCGenState);
}
}
else if (!strncmp(pSrc, szDBGSINDEX, sizeof(szDBGSINDEX) - 1)) {
char *pExpression, *pFree;
int Index;
pSrc += sizeof(szDBGSINDEX) - 1;
pch = pSrc;
pSrc = SkipSubExpression(pch, &pFree);
if (pSrc != pch) {
if (!pFree && pCGenState->pArgsList ) {
pExpression = pCGenState->pArgsList->Type;
}
else {
pExpression = pFree;
}
Index = GetFuncIndex(pCGenState, pExpression);
if (Index == -1) {
ExitErrMsg(FALSE, "DebugsIndex unknown! %s\n", pch);
}
_itoa(Index, Buffer, 10);
pch = Buffer;
if (pFree) {
GenHeapFree(pFree);
}
}
else {
pch = NULL;
}
}
else if (!strncmp(pSrc, szDBGSLIST, sizeof(szDBGSLIST) - 1)) {
pSrc += sizeof(szDBGSLIST) - 1;
pSrc = ListDbgs(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szDBGSSTRINGS, sizeof(szDBGSSTRINGS) - 1)) {
pSrc += sizeof(szDBGSSTRINGS) - 1;
WriteDbgsStrings(pSrc, pCGenState);
}
else if (!strncmp(pSrc, szDBGSMORE, sizeof(szDBGSMORE) - 1)) {
pSrc += sizeof(szDBGSMORE) - 1;
pSrc = WriteMore(pSrc, pCGenState, pCGenState->MoreApis);
}
else if (!strncmp(pSrc, szOFFSET, sizeof(szOFFSET) - 1)) {
pSrc += sizeof(szOFFSET) - 1;
pSrc = GetOffSet(pSrc, Buffer);
pch = Buffer;
}
else if (!strncmp(pSrc, szCPPEXPORT, sizeof(szCPPEXPORT) - 1)) {
pSrc += sizeof(szCPPEXPORT) - 1;
pSrc = WriteMore(pSrc,
pCGenState,
iHandleCpp > 0 && pCGenState->ExportsDbg->CplusDecoration
);
}
else if (!strncmp(pSrc, szCEXPORT, sizeof(szCEXPORT) - 1)) {
pSrc += sizeof(szCEXPORT) - 1;
pSrc = WriteMore(pSrc,
pCGenState,
!(iHandleCpp > 0 && pCGenState->ExportsDbg->CplusDecoration)
);
}
else if (!strncmp(pSrc, szCPPOUTPUT, sizeof(szCPPOUTPUT) - 1)) {
pSrc += sizeof(szCPPOUTPUT) - 1;
if (pCGenState->CGen->FileNameCpp != NULL) {
pCGenState->CGen->fp = pCGenState->CGen->fpCpp;
}
}
else if (!strncmp(pSrc, szCOUTPUT, sizeof(szCOUTPUT) - 1)) {
pSrc += sizeof(szCOUTPUT) - 1;
pCGenState->CGen->fp = pCGenState->CGen->fpC;
}
else if (!strncmp(pSrc, szIF, sizeof(szIF) - 1)) {
BOOLEAN result;
pSrc += sizeof(szIF) - 1;
pSrc = ExtractBoolean1(pSrc, pCGenState, &result);
pSrc = WriteMore(pSrc, pCGenState, result );
if ( *pSrc == '@' &&
!strncmp(pSrc+1, szELSE, sizeof(szELSE) - 1)) {
pSrc += sizeof(szELSE) - 1+1;
pSrc = WriteMore(pSrc, pCGenState, !result);
}
}
else if (!strncmp(pSrc, szELSE, sizeof(szELSE) - 1)) {
ExitErrMsg ( FALSE, "@Else not immediately following @If" );
}
else if (!strncmp(pSrc, szOR, sizeof(szOR) - 1)) {
BOOLEAN result1, result2;
pSrc += sizeof(szOR) - 1;
pSrc = ExtractBoolean2(pSrc, pCGenState, &result1, &result2);
WriteBoolean ( Buffer, result1 || result2 );
pch = Buffer;
}
else if (!strncmp(pSrc, szAND, sizeof(szAND) - 1)) {
BOOLEAN result1, result2;
pSrc += sizeof(szAND) - 1;
pSrc = ExtractBoolean2(pSrc, pCGenState, &result1, &result2);
WriteBoolean ( Buffer, result1 && result2 );
pch = Buffer;
}
else if (!strncmp(pSrc, szNOT, sizeof(szNOT) - 1)) {
BOOLEAN result1;
pSrc += sizeof(szNOT) - 1;
pSrc = ExtractBoolean1(pSrc, pCGenState, &result1);
WriteBoolean ( Buffer, !result1);
pch = Buffer;
}
else {
//
// See if this is an '@macroname'
//
char MacroName[MAX_PATH];
char *p = MacroName;
char *pIn = pSrc;
SIZE_T Bytes;
while (isalnum(*pIn)) {
*p++ = *pIn++;
}
*p = '\0';
if (ExpandMacro(MacroName, pCGenState, &pIn, BufferPos, MaxLen, &Bytes)) {
if (OutBuffer != NULL) {
Bytes--; // subtract off terminating zero.
BufferPos += Bytes;
MaxLen -= Bytes;
*BytesReturned += Bytes;
}
pSrc = pIn;
} else {
ExitErrMsg(FALSE, "Unknown keyword '@%s'", MacroName);
}
}
if (pch) {
if (OutBuffer != NULL) {
SIZE_T Bytes;
CGenerateEx(pch, pCGenState, BufferPos, MaxLen, &Bytes);
Bytes--; // subtract off terminating zero.
BufferPos += Bytes;
MaxLen -= Bytes;
*BytesReturned += Bytes;
}
else {
while (*pch)
pch = CGeneratePrintChar(pch, pCGenState);
}
}
}
}
if (OutBuffer != NULL) {
if(MaxLen == 0) {
ExitErrMsg(FALSE, "Out of Buffer space!\n");
}
*BufferPos = '\0';
*BytesReturned += 1;
}
return pSrc;
}
int GetMemberOffset(char *sTypeName, char *sMemberName)
{
PKNOWNTYPES pkt = NULL;
PMEMBERINFO pmi;
int i;
//
// This is the same as running the lexer on a single identifier...
//
Tokens[0].TokenType = TK_IDENTIFIER;
Tokens[0].Name = sTypeName;
Tokens[1].TokenType = TK_EOS;
CurrentTokenIndex = 0;
if (ParseTypes(TypeDefsList, NULL, &pkt) && pkt != NULL) {
pkt = GetBasicType(pkt->BaseName, TypeDefsList, StructsList);
} else {
CurrentTokenIndex = 0;
ParseTypes(StructsList, NULL, &pkt);
}
if (pkt == NULL) {
ExitErrMsg(FALSE,
"GetOffSet: Unknown Type %s\n",
sTypeName
);
}
pmi = pkt->pmeminfo;
while (pmi) {
if (!pmi->sName) {
//
// Found a nameless member. See if the member name we're
// looking for is a member of this nameless member.
//
// ie. typedef struct { int bar; } FOO;
//
// typedef struct TEST {
// union {
// int i;
// FOO;
// }
// } test;
//
// GetOffset(TEST, bar) will recurse when pmi points
// at the memberinfo for the nameless member 'FOO'.
//
i = GetMemberOffset(pmi->sType, sMemberName);
if (i != -1) {
return i;
}
} else if (!strcmp(pmi->sName, sMemberName)) {
return pmi->dwOffset;
}
pmi = pmi->pmeminfoNext;
}
return -1;
}
char *
GetOffSet(
char *pSrc,
char *Buffer
)
{
char *pOrg = pSrc;
char *pch;
int Len;
char TypeName[MAX_PATH];
char MemberName[MAX_PATH];
if (*pSrc != '(') {
ExitErrMsg(TRUE, "GetOffset: Invalid %s\n", pSrc);
return NULL;
}
while (IsSeparator(*pSrc)) {
pSrc = GetNextToken(pSrc);
if (!*pSrc || *pSrc == ')') {
ExitErrMsg(TRUE, "GetOffset: Invalid %s\n", pOrg);
return NULL;
}
}
pch = TypeName;
Len = sizeof(TypeName)-1;
while ((*pSrc != ',') && (*pSrc != 0)) {
if (!--Len) {
*pch = '\0';
ExitErrMsg(TRUE, "GetOffset: Overflow %s\n", TypeName);
return NULL;
}
*pch++ = *pSrc++;
}
*pch = '\0';
while (IsSeparator(*pSrc)) {
pSrc = GetNextToken(pSrc);
if (!*pSrc || *pSrc == ')') {
ExitErrMsg(TRUE, "GetOffset: Invalid %s\n", pOrg);
return NULL;
}
}
pch = MemberName;
Len = sizeof(MemberName)-1;
while (!IsSeparator(*pSrc)) {
if (!--Len) {
*pch = '\0';
ExitErrMsg(TRUE, "GetOffset: Overflow %s\n", MemberName);
return NULL;
}
*pch++ = *pSrc++;
}
*pch = '\0';
while (*pSrc && *pSrc++ != ')') {
;
}
Len = GetMemberOffset(TypeName, MemberName);
if (Len < 0) {
ExitErrMsg(FALSE,
"GetOffSet: Unknown Member %s.%s\n",
TypeName,
MemberName
);
return NULL;
}
_ltoa(Len, Buffer, 16);
return(pSrc);
}
/*
* GetRetSize
*
*/
int GetRetSize(PCGENSTATE pCGenState)
{
FILE *fp = pCGenState->CGen->fp;
PKNOWNTYPES pkt;
int i, Len;
int RetSize, RetIndLevel;
if (!pCGenState->ApiTypes) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetRetSize: No Api defined\n\n"
);
return -1;
}
// Get KnownTypes info for Return Type. Can't use the ApiTypes->pktRet
// cache as ParseIndirection() needs the state of the parse.
ResetLexer();
LexMacroArgs(pCGenState->ApiTypes->FuncRet);
ConsumeConstVolatileOpt();
if (ParseTypes(TypeDefsList, NULL, &pkt) == FALSE) {
CurrentTokenIndex = 0;
if (ParseTypes(StructsList, NULL, &pkt) == FALSE ) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetRetSize: Undefind Type %s\n\n",
pCGenState->ApiTypes->FuncRet
);
return -1;
}
}
if (pCGenState->ApiTypes->RetIndLevel) {
RetSize = SIZEOFPOINTER;
} else {
RetSize = pkt->Size;
}
return RetSize;
}
/*
* GetArgSize
*
*/
int GetArgSize(PEXPORTSDEBUG ExportDebug)
{
PARGSLIST pArgsList;
PLIST_ENTRY Next;
int Total = 0;
int ArgSize;
if (IsListEmpty(&ExportDebug->ArgsListHead)) {
return -1;
}
if (ExportDebug->ArgsSize >= 0) {
return ExportDebug->ArgsSize;
}
if (ExportDebug->IntForward && ExportDebug->IntForward->ArgsSize >= 0) {
ExportDebug->ArgsSize = ExportDebug->IntForward->ArgsSize;
return ExportDebug->ArgsSize;
}
Next = ExportDebug->ArgsListHead.Flink;
// check for void arg list
pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry);
if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) {
return 0;
}
do {
pArgsList = CONTAINING_RECORD(Next,ARGSLIST, ArgumentsEntry);
ArgSize = (pArgsList->ArgSize + 3) & ~3;
Total += ArgSize;
Next= Next->Flink;
} while (Next != &ExportDebug->ArgsListHead);
ExportDebug->ArgsSize = Total;
if (ExportDebug->IntForward) {
ExportDebug->IntForward->ArgsSize = Total;
}
return Total;
}
/*
* ApiStrings
*
*/
void ApiStrings(PCGENSTATE pCGenState)
{
FILE *fp = pCGenState->CGen->fp;
PLIST_ENTRY Next;
PARGSLIST pArgsList;
PKNOWNTYPES pkt;
int ArgSize, IndLevel;
char *pRet;
char BaseName[MAX_PATH];
char *c;
// copy in the DLL name and whack off the extension
strcpy(BaseName, DllBaseName);
c = strchr(BaseName, '.');
if (c) {
*c = '\0';
}
//
// Write the ApiName <"ApiName", ">
//
fprintf(fp, "\"%s!%s\", \"", BaseName, pCGenState->ExportsDbg->ExportName);
//
// Write out the Args <Arg1 %x, ArgN %x>
//
if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) {
fprintf(fp,
"\n\t*** ERROR ***\n*** ArgFormat Missing argument List: %s\n\n",
pCGenState->ApiTypes->TypeName
);
return;
}
Next = pCGenState->ExportsDbg->ArgsListHead.Flink;
do {
pArgsList = CONTAINING_RECORD(Next,ARGSLIST, ArgumentsEntry);
// check for void arg list
if (!pArgsList->Name) {
break;
}
fprintf(fp, "%s %s ",
pArgsList->pKnownTypes->TypeName,
pArgsList->Name
);
// check for vargs
if (!strcmp(pArgsList->Name, szVARGS)) {
break;
}
ArgSize = pArgsList->ArgSize;
while (ArgSize > 0) {
ArgSize -= sizeof(int);
fprintf(fp,
"%s%s",
"%x",
ArgSize > 0 ? "." : ""
);
}
Next= Next->Flink;
if (Next != &pCGenState->ExportsDbg->ArgsListHead) {
fputc(',', fp);
}
} while (Next != &pCGenState->ExportsDbg->ArgsListHead);
//
// Write out Return Type <", "RetType %x">
//
pRet = pCGenState->ApiTypes->FuncRet;
fprintf(fp, "\", \"%s ", pRet);
ResetLexer();
LexMacroArgs(pRet);
ConsumeConstVolatileOpt();
// Get Known Types for size of Return Type
if (ParseTypes(TypeDefsList, NULL, &pkt) == FALSE) {
CurrentTokenIndex = 0;
if (ParseTypes(StructsList, NULL, &pkt) == FALSE) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetRetSize: Undefind Type %s\n\n",
pCGenState->ApiTypes->FuncRet
);
return;
}
}
ArgSize = pkt->Size;
ParseIndirection(NULL, &ArgSize, NULL, NULL, NULL);
while (ArgSize > 0) {
ArgSize -= sizeof(int);
fprintf(fp,
"%s%s",
"%x",
ArgSize > 0 ? "." : ""
);
}
fprintf(fp, "\"");
}
char *
GetAddrFirstArg(
PCGENSTATE pCGenState,
char *Buffer,
int BuffLen)
{
PLIST_ENTRY pFirstEntry;
PARGSLIST pArgsList;
if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) {
return "NULL";
}
pFirstEntry = pCGenState->ExportsDbg->ArgsListHead.Flink;
pArgsList = CONTAINING_RECORD(pFirstEntry, ARGSLIST, ArgumentsEntry);
if (!pArgsList->Name) {
return "NULL";
}
Buffer[0] = '&';
BuffLen--;
if ((int)strlen(pArgsList->Name) > BuffLen) {
ExitErrMsg(TRUE, "gafa: Overflow %s\n", pArgsList->Name);
}
strcpy(&Buffer[1], pArgsList->Name);
return Buffer;
}
/*
* IfArgs
*
*/
char *IfArgs(char *pSrc, PCGENSTATE pCGenState)
{
BOOL bMore = TRUE;
PARGSLIST pArgsList;
PLIST_ENTRY pFirstEntry;
PKNOWNTYPES pkt;
// skip empty list,
if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) {
bMore = FALSE;
}
// check for void arg list
else {
pFirstEntry = pCGenState->ExportsDbg->ArgsListHead.Flink;
pArgsList = CONTAINING_RECORD(pFirstEntry, ARGSLIST, ArgumentsEntry);
if (!pArgsList->Name) {
pkt = GetNameFromTypesList(TypeDefsList, pArgsList->Type);
if (!pkt) {
pkt = GetNameFromTypesList(StructsList, pArgsList->Type);
}
if (!pkt) {
ExitErrMsg(FALSE,
"ifArgs: Unknown Type %s\n",
pArgsList->Type
);
}
if (!pkt->IndLevel && !strcmp(pkt->BasicType, szVOID)) {
bMore = FALSE;
}
}
}
return WriteMore(pSrc,pCGenState, bMore);
}
/*
* IfApiRet
*
*/
char *IfApiRet(char *pSrc, PCGENSTATE pCGenState)
{
int i, Len;
BOOL bMore = TRUE;
PKNOWNTYPES pkt;
ResetLexer();
LexMacroArgs(pCGenState->ApiTypes->FuncRet);
ConsumeConstVolatileOpt();
if (ParseTypes(TypeDefsList,NULL, &pkt) == FALSE) {
CurrentTokenIndex = 0;
if (ParseTypes(StructsList, NULL, &pkt) == FALSE) {
bMore = FALSE;
}
}
if (bMore && CurrentToken()->TokenType != TK_STAR &&
!pkt->IndLevel && !strcmp(pkt->BasicType, szVOID)) {
bMore = FALSE;
}
return WriteMore(pSrc, pCGenState, bMore);
}
char *
IfApiCode(
char *pSrc,
PCGENSTATE pCGenState
)
/*++
Routine Description:
Expands an EFunc's codeburst, if it exists. ie. @IfApiCode(foo) will
expand to the 'foo=' section of the current EFunc, if the current EFunc
has a 'foo='. Otherwise, there is no expansion.
Arguments:
pSrc - pointer to character following '@IfApiCode'
pCGenState - current code-gen state
Return Value:
pointer to character following the end of the ')'
--*/
{
char *pch;
char *pEnd;
size_t Len;
int CodeBurstIndex;
char CodeName[MAX_PATH];
char *CodeBurst;
pch = SkipSubExpression(pSrc, NULL);
if (pSrc == pch) {
return pSrc;
}
pEnd = pch;
pch = pSrc+1;
if (IsSeparator(*pch)) {
return pSrc;
}
pSrc = pch;
while (!IsSeparator(*pch)) {
pch++;
}
Len = pch - pSrc;
// Copy name to a buffer and null-terminate
memcpy(CodeName, pSrc, Len);
CodeName[Len] = '\0';
CodeBurstIndex = GetExistingCodeBurstIndex(CodeName);
if (CodeBurstIndex == -1) {
ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", CodeName);
}
if (pCGenState->ExTemplate) {
CodeBurst = pCGenState->TempleEx->CodeBurst[CodeBurstIndex];
if (CodeBurst) {
//
// There is an [Efunc] with a non-empty codeburst for this API.
// Generate its codeburst.
//
CGenerate(CodeBurst, pCGenState);
}
}
return pEnd;
}
/*
* CheckFastCallArgs
*
*/
BOOLEAN
FastCallArgs(
PLIST_ENTRY ArgsListHead,
int ArgLimit,
BOOL fCheckTypes,
BOOL fCheckFirstArgType
)
{
PARGSLIST pArgsList;
PTEMPLES pTypeTemple;
PKNOWNTYPES pktTemple;
int tplIndLevel, NumArgs, ArgSize;
PLIST_ENTRY Next, NextTemple;
if (IsListEmpty(ArgsListHead)) {
return FALSE;
}
Next = ArgsListHead->Flink;
// check for void arg list, or vargs as first arg
pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry);
if (!pArgsList->Name) {
return strcmp(pArgsList->Type, szVARGS) ? TRUE : FALSE;
}
NumArgs = 0;
while (Next != ArgsListHead) {
pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry);
//
// Cannot have more than 4 args
//
if (++NumArgs > ArgLimit) {
return FALSE;
}
//
// arg size must be dword or less
//
ArgSize = (pArgsList->ArgSize + 3) & ~3;
if (ArgSize < 0 || ArgSize > 4) {
return FALSE;
}
//
// vargs of any indlevel aren't allowed
//
if (!strcmp(pArgsList->pKnownTypes->BaseName, szVARGS)) {
return FALSE;
}
//
// floats of Zero IndLevel aren't allowed
//
if (pArgsList->IndLevel == 0 &&
!strcmp(pArgsList->pKnownTypes->BaseName, szFLOAT))
{
return FALSE;
}
//
// type templates are not allowed except for the first arg in methods
//
if ((fCheckTypes) &&
((NumArgs != 1) ||
((NumArgs == 1) && fCheckFirstArgType))) {
NextTemple = TypeTempleList.Flink;
while (NextTemple != &TypeTempleList) {
pTypeTemple = CONTAINING_RECORD(NextTemple, TEMPLES, TempleEntry);
//
// get the Known types info for each type template.
//
pktTemple = pTypeTemple->pktType;
if (!pktTemple) {
//
// Don't have the Known types info yet, fetch it
// and save it in the TypeTemplate
//
pktTemple = GetNameFromTypesList(TypeDefsList,
pTypeTemple->Name
);
if (!pktTemple) {
pktTemple = GetNameFromTypesList(StructsList,
pTypeTemple->Name
);
}
pTypeTemple->pktType = pktTemple;
}
if (!pktTemple) {
ExitErrMsg(FALSE,
"Temple: Type not found %s\n",
pTypeTemple->Name
);
}
//
// See if arg matches this type template
//
if (IsSameType(pArgsList->pKnownTypes,
pArgsList->IndLevel,
TK_NONE,
pTypeTemple->Name,
pTypeTemple->IndLevel + pktTemple->IndLevel,
TK_NONE,
TRUE
))
{
return FALSE;
}
NextTemple = NextTemple->Flink;
}
}
Next= Next->Flink;
}
return TRUE;
}
BOOLEAN
IsFastCall(
PCGENSTATE pCGenState
)
{
if (!pCGenState->ExportsDbg) { // can this occur ?
return FALSE;
}
//
// If first time, determine if Api can be a fastcall.
// tri state flag, where:
// -1 == Cannot be a fastcall
// 0 == undetermined
// 1 == Can be a fastcall
//
if (!pCGenState->ExportsDbg->FastCall) {
int Size;
pCGenState->ExportsDbg->FastCall = -1; // assume not a fastcall
//
// Fast call criteria:
// 1. NOT have an exception template.
// 2. each param up to 4 bytes (exclude structures)
// 3. 0 to 4 params
// 4. return 0 or 1 dword.
// 5. Not be a float or a VARGS
// 6. Not have have a type template
// 7. Must not be in the EFastTemplate list
// 8. Must not have a C++ linkage
//
if (!pCGenState->ExTemplate && !pCGenState->ExportsDbg->CplusDecoration) {
Size = GetRetSize(pCGenState);
if (Size >= 0 && Size <= 4 &&
!GetTemplate(&EFastTempleList, pCGenState->ExportsDbg->ExportName) &&
FastCallArgs(&pCGenState->ExportsDbg->ArgsListHead, 4, TRUE, TRUE))
{
pCGenState->ExportsDbg->FastCall = 1;
}
}
}
return pCGenState->ExportsDbg->FastCall == 1;
}
METHODTYPE
GetX2NMethodType(
PCGENSTATE pCGenState
)
{
int RetSize;
//
// Fast X2N method criteria:
// 1. NOT have an exception template.
// 2. each param up to 4 bytes (exclude structures)
// 3. Number of parameters between 1 and MAXX2NPARAMETERS
// 4. return 0 or 1 dword.
// 5. Not be a float or a VARGS
// 6. Not have have a type template, except for this pointer
// 7. Must not be in the EFastTemplate list
// 8. Must not have a C++ linkage
//
//
// Slow X2N method criteria:
// 1. NOT have an exception template.
// 2. each param up to 4 bytes (exclude structures)
// 3. Number of parameters between 1 and MAX2NPARAMETERS
// 4. return 0 or 1 dword.
// 5. Not be a float or a VARGS
// 6. Must not be in the EFastTemplate list
// 7. Must not have a C++ linkage
//
// Fat X2N methods are neither Slow X2N methods or Fast X2N methods
if (!pCGenState->ExportsDbg) { // can this occur ?
return FALSE;
}
if (pCGenState->ExportsDbg->X2NMethodType == UNKNOWNMETHOD) {
RetSize = GetRetSize(pCGenState);
if (pCGenState->ExTemplate ||
pCGenState->ExportsDbg->CplusDecoration ||
GetTemplate(&EFastTempleList, pCGenState->ExportsDbg->ExportName) ||
(RetSize > 4) || (RetSize < 0)) {
pCGenState->ExportsDbg->X2NMethodType = FATX2NMETHOD;
}
else if (FastCallArgs(&pCGenState->ExportsDbg->ArgsListHead, MAXX2NPARAMETERS, TRUE, FALSE)) {
pCGenState->ExportsDbg->X2NMethodType = FASTX2NMETHOD;
}
else if (FastCallArgs(&pCGenState->ExportsDbg->ArgsListHead, MAXX2NPARAMETERS, FALSE, FALSE)) {
pCGenState->ExportsDbg->X2NMethodType = SLOWX2NMETHOD;
}
else {
pCGenState->ExportsDbg->X2NMethodType = FATX2NMETHOD;
}
}
return(pCGenState->ExportsDbg->X2NMethodType);
}
/*
* IfRetType
*
*/
char *IfRetType(char *pSrc, PCGENSTATE pCGenState)
{
char *pch;
BOOL bMore = FALSE;
char c;
pch = GetNextToken(pSrc);
if (pch != pSrc)
{
bMore = ( ! strncmp(pch, pCGenState->ApiTypes->FuncRet,
strlen( pCGenState->ApiTypes->FuncRet)));
}
pSrc = GetNextToken(pch);
pch = WriteMore(pSrc ,pCGenState, bMore);
return(pch);
}
/*
* IfNotRetType
*
*/
char *IfNotRetType(char *pSrc, PCGENSTATE pCGenState)
{
char *pch;
BOOL bMore = FALSE;
char c;
pch = GetNextToken(pSrc);
if (pch != pSrc)
{
bMore = (strncmp( pch, pCGenState->ApiTypes->FuncRet, strlen( pCGenState->ApiTypes->FuncRet ) ) != 0);
}
pSrc = GetNextToken(pch);
pch = WriteMore(pSrc ,pCGenState, bMore);
return(pch);
}
BOOL
ExpandType(
PCGENSTATE pCGenState,
PKNOWNTYPES pkt,
PLIST_ENTRY pTempleList,
int CodeBurstIndex
)
{
PARGSLIST pArgsList;
PKNOWNTYPES pktTemple;
int tplIndLevel;
PLIST_ENTRY NextArg, NextTemple;
PTEMPLES pTypeTemple;
BOOL bMatchFound = FALSE;
int i;
pArgsList = pCGenState->pArgsList;
i=2;
while (i--) {
NextTemple = pTempleList->Flink;
while (NextTemple != pTempleList) {
pTypeTemple = CONTAINING_RECORD(NextTemple, TEMPLES, TempleEntry);
tplIndLevel = pTypeTemple->IndLevel;
pktTemple = pTypeTemple->pktType;
if (!pktTemple) {
pktTemple = GetNameFromTypesList(TypeDefsList,
pTypeTemple->Name
);
if (!pktTemple) {
pktTemple = GetNameFromTypesList(StructsList,
pTypeTemple->Name
);
}
pTypeTemple->pktType = pktTemple;
}
if (!pktTemple) {
ExitErrMsg(FALSE,
"Temple: Type not found %s\n",
pTypeTemple->Name
);
}
tplIndLevel += pktTemple->IndLevel;
if (IsSameType(pkt,
pArgsList->IndLevel,
pArgsList->tkDirection,
pTypeTemple->Name,
tplIndLevel,
pTypeTemple->tkDirection,
i == 0
)) {
DbgPrintf("ttpl: MEMBER %s.%s Type=%s IndLevel=%d\n",
pCGenState->ApiTypes->FuncRet,
pTypeTemple->Name,
pTypeTemple->Name,
pTypeTemple->IndLevel
);
if(ExpandTemple(pTypeTemple, CodeBurstIndex, pCGenState)){
return TRUE;
}
}
NextTemple = NextTemple->Flink;
}
}
return FALSE;
}
BOOL IsInNoType(PCHAR *NoTypes, PMEMBERINFO pmi) {
SIZE_T NoTypeCount;
if (NoTypes == NULL || pmi->sName == NULL) {
return FALSE;
}
for (NoTypeCount=0; NoTypeCount<MAX_NOTYPE; ++NoTypeCount) {
if (!NoTypes[NoTypeCount]) {
return FALSE;
}
else {
if (strcmp(pmi->sName, NoTypes[NoTypeCount]) == 0) {
return TRUE;
}
}
}
return FALSE;
}
SIZE_T CountNoTypes(PCHAR *NoTypes) {
SIZE_T Count = 0;
if (NoTypes == NULL) {
return 0;
}
while(*NoTypes++ != NULL) {
Count++;
}
return Count;
}
VOID pMemberTypes( PCGENSTATE pCGenState, int CodeBurstIndex, char *MemReference, BOOL bBtoT);
void ExpandMemberType( PMEMBERINFO pmi, CGENSTATE CGenState, int CodeBurstIndex,
PKNOWNTYPES pktStruct, char* pszStructName, char *pszHostCastedStructName, PARGSLIST pArgsList, FILE* fpLog,
PARGSLIST pArgsListOld, char *pMemReference, BOOL bBtoT)
{
char *sName;
char *sNameNew;
char *sHostCastedName;
int i, Len, HostCastedNameLen;
int tplIndLevel;
PLIST_ENTRY NextArg, NextTemple;
PTEMPLES pTypeTemple;
PKNOWNTYPES pktTemple;
PKNOWNTYPES pkt;
BOOL bAddCast = TRUE;
SIZE_T NoTypeCount;
char Type[MAX_PATH];
PARGSLIST pArgsListTemp;
// Determine if this member should be expanded by checking for a NoType entry.
if (pmi->sName != NULL) {
if(IsInNoType(CGenState.CurrentTemple->NoTypes, pmi) ||
IsInNoType(CGenState.MemberNoType, pmi)) {
goto NextMember;
}
}
// Get the pkt for the member type
if ( pmi->pktCache )
{
pkt = pmi->pktCache;
}
else
{
ResetLexer();
LexMacroArgs(pmi->sType);
ConsumeConstVolatileOpt();
if (ParseTypes(TypeDefsList,NULL, &pkt) == FALSE)
{
CurrentTokenIndex = 0;
if ( ParseTypes( StructsList, NULL, &pkt ) == FALSE )
{
fprintf( fpLog, "%s *** WARNING *** Member %s->%s skipped - unknown type\n", CGenState.Temple->Comment,
pszStructName, pmi->sType );
goto NextMember;
}
}
pmi->pktCache = pkt;
}
if ( pktStruct == pkt )
{
//
// Rats! The structure contains a member which is a pointer
// with the same type as this structure. ie. this struct
// is self-referential. We can't expand it as the expansion
// is recursive.
//
fprintf( fpLog, "%s *** WARNING *** Member %s->%s skipped - self-referencing structure\n", CGenState.Temple->Comment,
pszStructName, pmi->sType );
goto NextMember;
}
// Build the new names.
sName = pmi->sName;
// This is a type without a name. No casting is needed.
if (pktStruct->Flags & BTI_ANONYMOUS) {
if (sName == NULL) {
sHostCastedName = CheckHeapAlloc(strlen(pszHostCastedStructName) + 1);
sNameNew = CheckHeapAlloc(strlen(pszStructName) + 1);
strcpy(sHostCastedName, pszHostCastedStructName);
strcpy(sNameNew, pszStructName);
}
else {
sHostCastedName = CheckHeapAlloc(strlen(pszHostCastedStructName) + strlen(pMemReference) + strlen(sName) + 1);
strcpy(sHostCastedName, pszHostCastedStructName);
strcat(sHostCastedName, pMemReference);
strcat(sHostCastedName, sName);
sNameNew = CheckHeapAlloc(strlen(pszStructName) + strlen(pMemReference) + strlen(sName) + 1);
strcpy(sNameNew, pszStructName);
strcat(sNameNew, pMemReference);
strcat(sNameNew, sName);
}
}
else {
pArgsListTemp = CGenState.pArgsList;
CGenState.pArgsList = pArgsListOld;
if (IsPointer(&CGenState)) {
ArgTypeInd(Type, &CGenState, TRUE);
strcat(Type, " *");
}
else {
ArgHostType(Type, &CGenState);
}
if (CGenState.pArgsList->bIsBitfield ||
(CGenState.pArgsList->IndLevel == 0 &&
CGenState.pArgsList->pKnownTypes->IndLevel == 0 &&
(strcmp(CGenState.pArgsList->pKnownTypes->BasicType, "struct") == 0 ||
strcmp(CGenState.pArgsList->pKnownTypes->BasicType, "enum") == 0 ||
strcmp(CGenState.pArgsList->pKnownTypes->BasicType, "union") == 0)
)
) {
bAddCast = FALSE;
}
else {
bAddCast = TRUE;
}
CGenState.pArgsList = pArgsListTemp;
HostCastedNameLen = strlen(pszHostCastedStructName) + strlen(Type) + 8;
Len = strlen(pszStructName) + 1;
if (sName != NULL) {
HostCastedNameLen += strlen(pMemReference) + strlen(sName);
Len += strlen(pMemReference) + strlen(sName);
}
if (Len >= MAX_PATH || HostCastedNameLen >= MAX_PATH) {
fprintf( fpLog,
"%s *** WARNING *** Member %s->%s skipped - name is too long\n",
CGenState.Temple->Comment,
pszStructName,
pmi->sType
);
goto NextMember;
}
sHostCastedName = CheckHeapAlloc(HostCastedNameLen);
sHostCastedName[0] = '\0';
if (bAddCast) {
strcpy(sHostCastedName, "((");
strcat(sHostCastedName, Type);
strcat(sHostCastedName, ")(");
strcat(sHostCastedName, pszHostCastedStructName);
strcat(sHostCastedName, "))");
}
else {
strcat(sHostCastedName, pszHostCastedStructName);
}
if(sName != NULL) {
strcat(sHostCastedName, pMemReference);
strcat(sHostCastedName, sName);
}
sNameNew = CheckHeapAlloc(Len);
strcpy(sNameNew, pszStructName);
if(sName != NULL) {
strcat(sNameNew, pMemReference);
strcat(sNameNew, sName);
}
}
pArgsList->pKnownTypes = pkt;
pArgsList->ArgSize = pkt->Size;
pArgsList->IsPtr64 = pmi->bIsPtr64;
pArgsList->OffSet = -1; // there is no stack offset for this member
pArgsList->IndLevel = pmi->IndLevel;
// pArgsList->tkDirection is same as the original arg
pArgsList->Type = pmi->sType;
pArgsList->pStructType = NULL;
pArgsList->Mod = TK_NONE;
pArgsList->SUEOpt = TK_NONE;
pArgsList->PostMod = TK_NONE;
pArgsList->PrePostMod = TK_NONE;
pArgsList->Name = sNameNew;
pArgsList->ArgLocal = sNameNew;
pArgsList->HostCastedName = sHostCastedName;
pArgsList->fIsMember = TRUE;
pArgsList->bIsBitfield = pmi->bIsBitfield;
pArgsList->BitsRequired= pmi->BitsRequired;
pArgsList->bIsArray = pmi->bIsArray;
pArgsList->ArrayElements=pmi->ArrayElements;
pArgsList->fRequiresThunk = ((pkt->Flags & BTI_CONTAINSFUNCPTR) != 0);
if (sName != NULL) {
CGenState.MemberNoType = NULL;
ExpandType(&CGenState, pArgsList->pKnownTypes, &TypeTempleList, CodeBurstIndex);
}
else {
// This field is a nameless field in a structure or union.
// Example:
// struct foobar {
// int x;
// };
// struct foobar2 {
// struct foobar;
// int y;
// };
// foobar2 will import all the fields of foobar.
//
// When walking down the structure, we want to continue expanding foobar when we reach the nameless field.
SIZE_T NumNoTypes1, NumNoTypes2;
PCHAR *NewNoTypes;
NumNoTypes1 = CountNoTypes(CGenState.MemberNoType);
NumNoTypes2 = CountNoTypes(CGenState.CurrentTemple->NoTypes);
if (NumNoTypes1 + NumNoTypes2 + 1 > MAX_NOTYPE) {
ExitErrMsg(FALSE, "ExpandMemberType: too many notypes.\n");
}
NewNoTypes = CheckHeapAlloc((NumNoTypes1 + NumNoTypes2 + 1)*sizeof(PCHAR));
memcpy(NewNoTypes, CGenState.MemberNoType, NumNoTypes1 * sizeof(PCHAR));
memcpy(NewNoTypes + NumNoTypes1, CGenState.CurrentTemple->NoTypes, NumNoTypes2 * sizeof(PCHAR));
NewNoTypes[NumNoTypes1 + NumNoTypes2] = NULL;
CGenState.MemberNoType = NewNoTypes;
pMemberTypes( &CGenState, CodeBurstIndex, pMemReference, bBtoT);
GenHeapFree(NewNoTypes);
}
GenHeapFree(sNameNew);
GenHeapFree(sHostCastedName);
NextMember:;
}
void ExpandMemberTypesBackwards( PMEMBERINFO pmi, CGENSTATE CGenState, int CodeBurstIndex,
PKNOWNTYPES pktStruct, char* pszStructName, char *pszHostCastedStructName, PARGSLIST pArgsList, FILE* fpLog,
PARGSLIST pArgsListOld, char *pMemReference, BOOL bBtoT)
{
if ( pmi->pmeminfoNext != NULL )
{
ExpandMemberTypesBackwards( pmi->pmeminfoNext, CGenState, CodeBurstIndex, pktStruct,
pszStructName, pszHostCastedStructName, pArgsList, fpLog,
pArgsListOld, pMemReference, bBtoT);
}
ExpandMemberType( pmi, CGenState, CodeBurstIndex, pktStruct,
pszStructName, pszHostCastedStructName, pArgsList, fpLog,
pArgsListOld, pMemReference, bBtoT);
}
VOID pMemberTypes( PCGENSTATE pCGenState, int CodeBurstIndex, char *MemReference, BOOL bBtoT) {
int Len;
PCGENERATE pCGen;
CGENSTATE CGenState;
PKNOWNTYPES pkt;
PKNOWNTYPES pktLast;
ARGSLIST ArgsListOld;
PMEMBERINFO pmi;
pCGen = CheckHeapAlloc(sizeof(CGENERATE)+strlen(pCGenState->CGen->TempleName)+1);
InitializeListHead(&pCGen->CGenerateEntry);
pCGen->fp = pCGenState->CGen->fp;
pCGen->FileNameC = pCGenState->CGen->FileNameC;
pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC;
pCGen->fpCpp = pCGenState->CGen->fpCpp;
pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp;
pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp;
strcpy(pCGen->TempleName, pCGenState->CGen->TempleName);
CGenState = *pCGenState;
CGenState.CGen = pCGen;
pkt = pCGenState->pArgsList->pKnownTypes;
while(pkt->pTypedefBase != NULL) {
pkt = pkt->pTypedefBase;
}
pCGenState->pArgsList->pStructType = pkt;
// Save the old ARGSLIST away
ArgsListOld = *(pCGenState->pArgsList);
// get a ptr to the member list for the struct
pmi = pkt->pmeminfo;
if ( !pmi )
{
ExitErrMsg(FALSE, "Type '%s' is not a struct", pCGenState->pArgsList->Type);
}
if(strcmp(pkt->BasicType, "union") == 0) {
PMEMBERINFO pmiTemp;
// check if any of the members of this union are in the notype list.
for (pmiTemp = pkt->pmeminfo; pmiTemp != NULL; pmiTemp = pmiTemp->pmeminfoNext) {
if (IsInNoType(pCGenState->MemberNoType, pmiTemp) ||
IsInNoType(pCGenState->CurrentTemple->NoTypes, pmiTemp)) {
//A member of the union is in the notype list, skip union.
goto done;
}
}
}
// loop over each member variable within the type
if ( bBtoT )
{
do
{
ExpandMemberType( pmi, CGenState, CodeBurstIndex, ArgsListOld.pKnownTypes, ArgsListOld.Name,
ArgsListOld.HostCastedName, pCGenState->pArgsList, pCGenState->CGen->fp,
&ArgsListOld, MemReference, bBtoT);
pmi = pmi->pmeminfoNext;
}
while ( pmi != NULL );
}
else
{
ExpandMemberTypesBackwards( pmi, CGenState, CodeBurstIndex, ArgsListOld.pKnownTypes, ArgsListOld.Name,
ArgsListOld.HostCastedName, pCGenState->pArgsList, pCGenState->CGen->fp,
&ArgsListOld, MemReference, bBtoT);
}
done:
// Restore the old ARGSLIST
*pCGenState->pArgsList = ArgsListOld;
GenHeapFree(pCGen);
}
char* MemberTypes( char *pSrc, PCGENSTATE pCGenState, BOOL bBtoT)
/*++
Routine Description:
Expands [Type] templates for the return value of an API call.
Arguments:
pSrc - pointer to character following '@RetType'
pCGenState - current code-gen state
Return Value:
pointer to character following the end of the ')'
--*/
{
char *pEnd;
char *pch;
int Len;
char BurstName[MAX_PATH];
int CodeBurstIndex;
PMACROARGSLIST pMArgsList = NULL;
SIZE_T BytesReturned;
char MemReference[MAX_PATH];
pch = SkipSubExpression(pSrc, NULL);
if (pSrc == pch) {
return pSrc;
}
pEnd = pch;
ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList);
if (pMArgsList->NumArgs < 1 || pMArgsList->NumArgs > 2) {
ExitErrMsg(FALSE, "MemberTypes: 1 or 2 arguments are required.\n");
}
CGenerateEx(pMArgsList->ArgText[0], pCGenState, BurstName, MAX_PATH, &BytesReturned);
CodeBurstIndex = GetExistingCodeBurstIndex(BurstName);
if (CodeBurstIndex == -1) {
ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", BurstName);
}
//handle optional member reference symbol
if (pMArgsList->NumArgs == 2) {
CGenerateEx(pMArgsList->ArgText[1], pCGenState, MemReference, MAX_PATH, &BytesReturned);
}
else {
strcpy(MemReference, "->");
}
pMemberTypes(pCGenState, CodeBurstIndex, MemReference, bBtoT);
FreeMacroArgsList(pMArgsList);
return pEnd;
}
char* ForceTypeExpand( char *pSrc, PCGENSTATE pCGenState)
{
char *pEnd;
char *pch;
int Len;
PCGENERATE pCGen;
CGENSTATE CGenState;
char BurstName[MAX_PATH];
char ArgName[MAX_PATH];
char ArgHostName[MAX_PATH];
char TypeName[MAX_PATH];
char Direction[MAX_PATH];
int CodeBurstIndex;
PARGSLIST pArgsList;
ARGSLIST ArgsListOld;
ARGSLIST ArgsListNew;
TOKENTYPE tkDirection;
PMACROARGSLIST pMArgsList = NULL;
SIZE_T BytesReturned;
BOOL bHasArgsList=FALSE;
pch = SkipSubExpression(pSrc, NULL);
if (pSrc == pch) {
return pSrc;
}
pEnd = pch;
ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList);
if (pMArgsList->NumArgs != 5) {
ExitErrMsg(FALSE, "ForceTypeExpand: 5 arguments are required.\n");
}
CGenerateEx(pMArgsList->ArgText[0], pCGenState, BurstName, MAX_PATH, &BytesReturned);
CodeBurstIndex = GetExistingCodeBurstIndex(BurstName);
if (CodeBurstIndex == -1) {
ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", BurstName);
}
pCGen = GenHeapAlloc(sizeof(CGENERATE)+strlen(pCGenState->CGen->TempleName)+1);
if (!pCGen) {
ExitErrMsg(TRUE, "mt: %s\n", pSrc);
}
CGenerateEx(pMArgsList->ArgText[1], pCGenState, ArgName, MAX_PATH, &BytesReturned);
CGenerateEx(pMArgsList->ArgText[2], pCGenState, ArgHostName, MAX_PATH, &BytesReturned);
CGenerateEx(pMArgsList->ArgText[3], pCGenState, TypeName, MAX_PATH, &BytesReturned);
CGenerateEx(pMArgsList->ArgText[4], pCGenState, Direction, MAX_PATH, &BytesReturned);
// Parse the direction
if(strcmp(Direction, "IN OUT") == 0) {
tkDirection = TK_INOUT;
}
else if (strcmp(Direction, "IN") == 0) {
tkDirection = TK_IN;
}
else if (strcmp(Direction, "OUT") == 0) {
tkDirection = TK_OUT;
}
else if (strcmp(Direction, "none") == 0) {
tkDirection = TK_NONE;
}
else {
ExitErrMsg(FALSE, "FORCETYPE: Unknown direction %s\n", Direction);
return NULL;
}
InitializeListHead(&pCGen->CGenerateEntry);
pCGen->fp = pCGenState->CGen->fp;
pCGen->FileNameC = pCGenState->CGen->FileNameC;
pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC;
pCGen->fpCpp = pCGenState->CGen->fpCpp;
pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp;
pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp;
strcpy(pCGen->TempleName, pCGenState->CGen->TempleName);
CGenState = *pCGenState;
CGenState.CGen = pCGen;
// Save the old ARGSLIST away
pArgsList = pCGenState->pArgsList;
if (pArgsList == NULL) {
CGenState.pArgsList = &ArgsListNew;
pArgsList = &ArgsListOld;
*pArgsList = *(PARGSLIST)pCGenState->ExportsDbg->ArgsListHead.Flink;
}
else {
ArgsListOld = *pArgsList;
bHasArgsList = TRUE;
}
pArgsList->pKnownTypes = NULL;
pArgsList->ArgSize = 0;
pArgsList->IsPtr64 = FALSE;
pArgsList->OffSet = -1; // there is no stack offset for this member
pArgsList->IndLevel = 0;
pArgsList->tkDirection = tkDirection;
pArgsList->Type = TypeName;
pArgsList->pStructType = NULL;
pArgsList->Mod = TK_NONE;
pArgsList->SUEOpt = TK_NONE;
pArgsList->PostMod = TK_NONE;
pArgsList->PrePostMod = TK_NONE;
pArgsList->Name = ArgName;
pArgsList->ArgLocal = ArgName;
pArgsList->HostCastedName = ArgHostName;
pArgsList->fIsMember = TRUE;
pArgsList->bIsBitfield = FALSE;
pArgsList->BitsRequired= FALSE;
pArgsList->bIsArray = FALSE;
pArgsList->ArrayElements=0;
pArgsList->fRequiresThunk = FALSE;
SetArgListToTypeForArg(CGenState.pArgsList, pArgsList, TypeName);
ExpandType(&CGenState, CGenState.pArgsList->pKnownTypes, &TypeTempleList, CodeBurstIndex);
// Restore the old ARGSLIST
if (bHasArgsList) {
*pCGenState->pArgsList = ArgsListOld;
}
else {
pCGenState->pArgsList = NULL;
}
GenHeapFree(pCGen);
FreeMacroArgsList(pMArgsList);
return pEnd;
}
char *
IncludeRetType(
char *pSrc,
PCGENSTATE pCGenState
)
/*++
Routine Description:
Expands [Type] templates for the return value of an API call.
Arguments:
pSrc - pointer to character following '@RetType'
pCGenState - current code-gen state
Return Value:
pointer to character following the end of the ')'
--*/
{
char *pEnd;
char *pch;
PCGENERATE pCGen;
CGENSTATE CGenState;
PKNOWNTYPES pkt;
int i, Len;
int tplIndLevel;
PTEMPLES pTypeTemple;
PKNOWNTYPES pktTemple;
PLIST_ENTRY NextArg, NextTemple;
char BurstName[MAX_PATH];
int CodeBurstIndex;
char *CodeBurst;
PMACROARGSLIST pMArgsList = NULL;
SIZE_T BytesReturned;
pch = SkipSubExpression(pSrc, NULL);
if (pSrc == pch) {
return pSrc;
}
pEnd = pch;
ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList);
if (pMArgsList->NumArgs != 1) {
ExitErrMsg(FALSE, "IncludeRetTypes: exactly 1 argument is required.\n");
}
CGenerateEx(pMArgsList->ArgText[0], pCGenState, BurstName, MAX_PATH, &BytesReturned);
CodeBurstIndex = GetExistingCodeBurstIndex(BurstName);
if (CodeBurstIndex == -1) {
ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", BurstName);
}
pCGen = GenHeapAlloc(sizeof(CGENERATE)+strlen(pCGenState->CGen->TempleName)+1);
if (!pCGen) {
ExitErrMsg(TRUE, "it: %s\n", pSrc);
}
InitializeListHead(&pCGen->CGenerateEntry);
pCGen->fp = pCGenState->CGen->fp;
pCGen->FileNameC = pCGenState->CGen->FileNameC;
pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC;
pCGen->fpCpp = pCGenState->CGen->fpCpp;
pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp;
pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp;
strcpy(pCGen->TempleName, pCGenState->CGen->TempleName);
CGenState = *pCGenState;
CGenState.CGen = pCGen;
if (pCGenState->ExTemplate) {
CodeBurst = pCGenState->TempleEx->CodeBurst[CodeBurstIndex];
if (CodeBurst) {
//
// The [EFunc] template for this API has a return-type codeburst.
// That is expanded in lieu of a [Types] template.
//
CGenerate(CodeBurst, &CGenState);
return pEnd;
}
}
pkt = pCGenState->ApiTypes->pktRet;
pkt = pCGenState->ApiTypes->pktRet;
i=2;
while (i--) {
NextTemple = TypeTempleList.Flink;
while (NextTemple != &TypeTempleList) {
pTypeTemple = CONTAINING_RECORD(NextTemple, TEMPLES, TempleEntry);
tplIndLevel = pTypeTemple->IndLevel;
pktTemple = pTypeTemple->pktType;
if (!pktTemple) {
pktTemple = GetNameFromTypesList(TypeDefsList,
pTypeTemple->Name
);
if (!pktTemple) {
pktTemple = GetNameFromTypesList(StructsList,
pTypeTemple->Name
);
}
pTypeTemple->pktType = pktTemple;
}
if (!pktTemple) {
ExitErrMsg(FALSE,
"Temple: Type not found %s\n",
pTypeTemple->Name
);
}
tplIndLevel += pktTemple->IndLevel;
if (IsSameType(pkt,
pCGenState->ApiTypes->RetIndLevel,
TK_NONE,
pTypeTemple->Name,
tplIndLevel,
TK_NONE,
i == 0
)) {
DbgPrintf("ttpl: RETURN %s.%s Type=%s IndLevel=%d\n",
CGenState.ApiTypes->FuncRet,
pTypeTemple->Name,
pTypeTemple->Name,
pTypeTemple->IndLevel
);
if (pTypeTemple->CodeBurst[CodeBurstIndex]) {
pSrc = pTypeTemple->CodeBurst[CodeBurstIndex];
while (*pSrc && !isgraph(*pSrc)) {
pSrc++;
}
if (*pSrc) {
CGenerate(pSrc, &CGenState);
}
}
i = 0;
break; // break from while loop over all templates
}
NextTemple = NextTemple->Flink;
}
}
GenHeapFree(pCGen);
FreeMacroArgsList(pMArgsList);
return pEnd;
}
VOID
SetArgListToTypeForArg(
PARGSLIST pArgsList,
PARGSLIST pArgsListOld,
char * pTypeName
)
{
int IndLevel = 0;
char TypeNameCopy[MAX_PATH];
PKNOWNTYPES pkt;
char *p;
BOOL bIsTypedef = TRUE;
*pArgsList = *pArgsListOld;
p = pTypeName;
strcpy(TypeNameCopy, p);
p = TypeNameCopy;
while(*p != '\0') {
if (*p == '*') {
IndLevel++;
*p = ' ';
}
p++;
}
ResetLexer();
LexMacroArgs(TypeNameCopy);
ConsumeConstVolatileOpt();
if (ParseTypes(TypeDefsList, NULL, &pkt) == FALSE) {
CurrentTokenIndex = 0;
bIsTypedef = FALSE;
if (ParseTypes(StructsList, NULL, &pkt) == FALSE ) {
ExitErrMsg(FALSE, "SetArgListToType: %s is not a valid type\n", TypeNameCopy);
}
}
pArgsList->pKnownTypes = pkt;
pArgsList->pStructType = NULL;
//DWORD ArgSize; // size of this arg (should be unchanged)
pArgsList->IsPtr64 = (IndLevel == 0 && (pkt->Flags & BTI_PTR64));
//BOOL IsPtr64; // TRUE if this arg is __ptr64 (should be unchanged)
//int OffSet; // offset from stack for this arg(should be unchanged)
pArgsList->IndLevel = IndLevel;
//TOKENTYPE tkDirection; // TK_NONE, TK_IN, TK_OUT, TK_INOUT(should be unchanged)
//TOKENTYPE Mod; // modifier (TK_CONST/VOLATILE/NONE)(should be unchanged)
if (!bIsTypedef) {
if (strcmp(pkt->BasicType, szSTRUCT) == 0) {
pArgsList->SUEOpt = TK_STRUCT;
} else if (strcmp(pkt->BasicType, szUNION) == 0) {
pArgsList->SUEOpt = TK_UNION;
} else if (strcmp(pkt->BasicType, szENUM) == 0) {
pArgsList->SUEOpt = TK_ENUM;
} else {
pArgsList->SUEOpt = TK_NONE;
}
}
pArgsList->Type = pkt->TypeName;
//TOKENTYPE PostMod; // modifier (TK_CONST/VOLATILE/NONE)
//TOKENTYPE PrePostMod; // modifier (TK_CONST/VOLATILE/NONE)
//char *Name; // argument name (may be a nonameX)
//char *ArgLocal; // name of local var containing copy of arg
//char *HostCastedName; // Contains full name of struct member with
// host casts or NULL
pArgsList->fRequiresThunk = pkt->Flags & BTI_CONTAINSFUNCPTR;
pArgsList->fNoType = FALSE; // TRUE if types templates should *not*
// be expanded for this param.
//BOOL fIsMember; // This arg is actually a member of an array
//BOOL bIsBitfield; // Determines if this is a bitfield
//int BitsRequired; // Number of bits required for bitfield
//BOOL bIsArray; // This member is an array
//int ArrayElements; // Number of elements in the array
}
BOOL
ExpandTypesForApi(
PLIST_ENTRY ArgsListHead,
PCGENSTATE CGenState,
PLIST_ENTRY pTypesList,
int CodeBurstIndex,
BOOL bExpandAll,
BOOL bRtoL
)
{
int i, Len;
int tplIndLevel;
PCGENERATE pCGen;
PARGSLIST pArgsList;
PTEMPLES pTypeTemple;
PKNOWNTYPES pktArgs, pktTemple;
PLIST_ENTRY NextArg, NextTemple;
BOOL fKeepGoing = TRUE;
//
// For each argument process a type template if any.
//
if ( bRtoL )
{
NextArg = &CGenState->ExportsDbg->ArgsListHead;
NextArg = NextArg->Blink;
}
else
{
NextArg = ArgsListHead;
}
do
{
CGenState->pArgsList = CONTAINING_RECORD(NextArg,ARGSLIST,ArgumentsEntry);
if (CGenState->pArgsList->fNoType) {
//
// This arg is listed in this API's [EFunc] NoTypes list.
// Do not expand [Types] templates for it.
//
goto NextArg;
}
ResetLexer();
LexMacroArgs(CGenState->pArgsList->Type);
ConsumeConstVolatileOpt();
// Get KnownTypes info for Argument
if (ParseTypes(TypeDefsList, NULL, &pktArgs) == FALSE) {
CurrentTokenIndex = 0;
if (ParseTypes(StructsList, NULL, &pktArgs) == FALSE ) {
ErrMsg(
"Args: Type not found %s %s\n",
CGenState->pArgsList->Type,
CGenState->ApiTypes->TypeName
);
return fKeepGoing;
}
}
fKeepGoing = !ExpandType(CGenState, CGenState->pArgsList->pKnownTypes,
pTypesList, CodeBurstIndex);
fKeepGoing = fKeepGoing | bExpandAll;
NextArg:
if ( bRtoL )
{
if ( NextArg == ArgsListHead )
{
break;
}
NextArg = NextArg->Blink;
}
else
{
NextArg = NextArg->Flink;
if ( NextArg == &CGenState->ExportsDbg->ArgsListHead )
{
break;
}
}
} while (fKeepGoing);
return fKeepGoing;
}
/*
* IncludeTypes
*
*/
char *IncludeTypes(char *pSrc, PCGENSTATE pCGenState, BOOL bRtoL)
{
char *pEnd;
char *pch;
int Len;
PCGENERATE pCGen;
CGENSTATE CGenState;
PARGSLIST pArgsList;
PLIST_ENTRY NextArg;
char BurstName[MAX_PATH];
PMACROARGSLIST pMArgsList = NULL;
SIZE_T BytesReturned;
int CodeBurstIndex;
pch = SkipSubExpression(pSrc, NULL);
if (pSrc == pch) {
return pSrc;
}
pEnd = pch;
//
// Functions must have an argument list (at least void)
//
if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n IncludeTypes Missing argument List: %s\n",
pCGenState->ApiTypes->TypeName
);
return pEnd;
}
//
// If void arg list, nothing to do!
//
NextArg = pCGenState->ExportsDbg->ArgsListHead.Flink;
pArgsList = CONTAINING_RECORD(NextArg, ARGSLIST, ArgumentsEntry);
if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) {
return pEnd;
}
ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList);
if (pMArgsList->NumArgs < 1) {
ExitErrMsg(FALSE, "IncludeTypes: CodeBurst name required\n");
}
CGenerateEx(pMArgsList->ArgText[0], pCGenState, BurstName, MAX_PATH, &BytesReturned);
CodeBurstIndex = GetExistingCodeBurstIndex(BurstName);
if (CodeBurstIndex == -1) {
ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", BurstName);
}
pCGen = GenHeapAlloc(sizeof(CGENERATE)+strlen(pCGenState->CGen->TempleName)+1);
if (!pCGen) {
ExitErrMsg(TRUE, "it: %s\n", pSrc);
}
InitializeListHead(&pCGen->CGenerateEntry);
pCGen->fp = pCGenState->CGen->fp;
pCGen->FileNameC = pCGenState->CGen->FileNameC;
pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC;
pCGen->fpCpp = pCGenState->CGen->fpCpp;
pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp;
pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp;
strcpy(pCGen->TempleName, pCGenState->CGen->TempleName);
CGenState = *pCGenState;
CGenState.CGen = pCGen;
if (pMArgsList->NumArgs >= 2) {
char ArgName[MAX_PATH];
char TypeName[MAX_PATH];
char CastedArgName[MAX_PATH];
size_t ArgNameLen;
size_t ArgTypeLen;
char *p;
BOOL bHasType = FALSE;
//extract arg name to expand types for
CGenerateEx(pMArgsList->ArgText[1], pCGenState, ArgName, MAX_PATH, &BytesReturned);
if (BytesReturned == 0) {
ExitErrMsg(FALSE, "IncludeTypes: Empty arg name is not allowed.\n");
}
ArgNameLen = BytesReturned - 1;
if (pMArgsList->NumArgs == 3) {
//extract the type name
CGenerateEx(pMArgsList->ArgText[2], pCGenState, TypeName, MAX_PATH, &BytesReturned);
if (BytesReturned == 0) {
ExitErrMsg(FALSE, "IncludeTypes: Empty type name is not allowed.\n");
}
ArgTypeLen = BytesReturned - 1;
bHasType = TRUE;
if (ArgTypeLen + ArgNameLen + 4 >= MAX_PATH) {
ExitErrMsg(FALSE, "ArgType + ArgName is too long\n");
}
memcpy(CastedArgName, "((", 2);
p = CastedArgName + 2;
memcpy(p, TypeName, ArgTypeLen);
p += ArgTypeLen;
memcpy(p, ")", 1);
p++;
memcpy(p, ArgName, ArgNameLen);
p += ArgNameLen;
memcpy(p, ")", 2);
}
else {
ExitErrMsg(FALSE, "IncludeTypes: Too many arguments\n");
}
//Find arg in the arglist.
do {
pArgsList = CONTAINING_RECORD(NextArg, ARGSLIST, ArgumentsEntry);
if (pArgsList->Name != NULL) {
if (strcmp(pArgsList->Name, ArgName) == 0) {
//Expand this argument
if (bHasType) {
CGenState.pArgsList = GenHeapAlloc(sizeof(ARGSLIST));
if(NULL == CGenState.pArgsList)
ExitErrMsg(FALSE, "IncludeTypes: out of memory.\n");
SetArgListToTypeForArg(CGenState.pArgsList, pArgsList, TypeName);
CGenState.pArgsList->Name = CastedArgName;
}
else {
CGenState.pArgsList = pArgsList;
}
if (!ExpandType(&CGenState, CGenState.pArgsList->pKnownTypes, &FailTempleList, CodeBurstIndex))
ExpandType(&CGenState, CGenState.pArgsList->pKnownTypes, &TypeTempleList, CodeBurstIndex);
if (bHasType) {
GenHeapFree(CGenState.pArgsList);
}
GenHeapFree(pCGen);
FreeMacroArgsList(pMArgsList);
return pEnd;
}
}
NextArg = NextArg->Flink;
} while (NextArg != &CGenState.ExportsDbg->ArgsListHead);
ExitErrMsg(FALSE, "IncludeTypes: %s is not a known argument for %s\n", ArgName, pCGenState->ExportsDbg->ExportName);
}
else {
if (ExpandTypesForApi(NextArg,
&CGenState,
&FailTempleList,
CodeBurstIndex,
FALSE,
bRtoL)) {
ExpandTypesForApi(NextArg,
&CGenState,
&TypeTempleList,
CodeBurstIndex,
TRUE,
bRtoL);
}
}
GenHeapFree(pCGen);
FreeMacroArgsList(pMArgsList);
return pEnd;
}
/*
* IsSameType
*
*/
PKNOWNTYPES
IsSameType(
PKNOWNTYPES pktArgs,
int IndLevel,
TOKENTYPE tkArgDirection,
char *tplTypeName,
int tplIndLevel,
TOKENTYPE tkTypeDirection,
BOOL bScanBaseTypes
)
{
if (*tplTypeName != '*' && strcmp(tplTypeName, "default") != 0 &&
IndLevel + pktArgs->IndLevel != tplIndLevel) {
//
// Not a generic '*' or 'default' types template, and levels of indirection
// don't match
//
return NULL;
}
if (!bUseDirection) {
tkArgDirection = TK_NONE;
}
if (tkTypeDirection != TK_EOS && tkArgDirection != tkTypeDirection) {
//
// Direction-sensitivity enabled, type template isn't generic to
// all directions, and IN, OUT, IN/OUT don't match
//
return NULL;
}
if (!strcmp(pktArgs->TypeName, tplTypeName)) {
//
// type names match
//
return pktArgs;
}
if (bScanBaseTypes) {
PKNOWNTYPES pkt;
if (strcmp(tplTypeName, "struct") == 0 &&
strcmp(pktArgs->BasicType, "struct") == 0) {
//
// This matches a generic 'struct' template.
//
return pktArgs;
}
if (strcmp(tplTypeName, "union") == 0 &&
strcmp(pktArgs->BasicType, "union") == 0) {
//
// This matches a generic 'union' template.
//
return pktArgs;
}
if (*tplTypeName == '*' && IndLevel+pktArgs->IndLevel) {
//
// The template is a generic pointer template, and the arg type
// is a pointer to something. Match.
//
return pktArgs;
}
if (!strcmp(pktArgs->BaseName, pktArgs->TypeName)) {
//
// Base name of the arg type matches this arg type, no
// possiblity of a match.
//
pkt = NULL;
goto try_default;
}
//
// Get the knowntype for basetype of the arg
//
if (pktArgs->pktBase) {
// the knowntype is already cached
pkt = pktArgs->pktBase;
} else {
pkt = GetNameFromTypesList(TypeDefsList, pktArgs->BaseName);
if (!pkt) {
pkt = GetNameFromTypesList(StructsList, pktArgs->BaseName);
}
if (!pkt) {
goto try_default;
}
pktArgs->pktBase = pkt;
}
IndLevel += pktArgs->IndLevel - pkt->IndLevel;
pkt = IsSameType(pkt,
IndLevel,
tkArgDirection,
tplTypeName,
tplIndLevel,
tkTypeDirection,
TRUE
);
if (NULL == pkt) {
try_default:
// The default type template matches everything
if (strcmp(tplTypeName, "default") == 0) {
//printf("Applying default template to %s\n", pktArgs->TypeName);
return pktArgs;
}
}
return pkt;
}
return NULL;
}
/*
* GetAltExportName
*
* Fetches the forward name if one exists, returns NULL if none.
*
*/
char *GetAltExportName(char *Buffer, PCGENSTATE pCGenState, int Len)
{
PKNOWNTYPES pkt;
PEXPORTSDEBUG pExportDebug;
PLIST_ENTRY Next;
int i;
pExportDebug = pCGenState->ExportsDbg;
if (pExportDebug->ExtForward) {
i = _snprintf(Buffer, Len, "=%s", pExportDebug->ExtForward);
}
else if (pExportDebug->IntForward) {
if (bNoFuzzyLogic && !strchr(pExportDebug->IntForward->ExportName, '@')) {
i = _snprintf(Buffer, Len, "=%s%s@%d",
szINTFORWARD,
pExportDebug->IntForward->ExportName,
GetArgSize(pExportDebug)
);
}
else {
i = _snprintf(Buffer, Len, "=%s%s",
szINTFORWARD,
pExportDebug->IntForward->ExportName
);
}
}
else if (bNoFuzzyLogic &&
!strchr(pExportDebug->ExportName, '@') &&
!strstr(pCGenState->ApiTypes->FuncMod, "cdecl"))
{
i = _snprintf(Buffer, Len, "=%s@%d",
pExportDebug->ExportName,
GetArgSize(pExportDebug)
);
}
else {
return NULL;
}
if (i < 0) {
ExitErrMsg(FALSE,
"GetAltExportName: Overflow %s\n",
pExportDebug->ExportName
);
}
return Buffer;
}
/*
* IncludeTemplate
*
*/
char *IncludeTemplate(char *pSrc, PCGENSTATE pCGenState)
{
char *pEnd;
char *pch;
size_t Len;
PCGENERATE pCGen;
CGENSTATE CGenState;
pch = SkipSubExpression(pSrc, NULL);
if (pSrc == pch) {
return pSrc;
}
pEnd = pch;
pch = pSrc + 1;
if (IsSeparator(*pch)) {
return pSrc;
}
pSrc = pch;
while (!IsSeparator(*pch)) {
pch++;
}
Len = pch - pSrc;
pCGen = GenHeapAlloc(Len + 1 + sizeof(CGENERATE));
if (!pCGen) {
ExitErrMsg(TRUE, "it: %s\n", pSrc);
}
InitializeListHead(&pCGen->CGenerateEntry);
pCGen->fp = pCGenState->CGen->fp;
pCGen->fpC = pCGenState->CGen->fpC;
pCGen->FileNameC = pCGenState->CGen->FileNameC;
pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC;
pCGen->fpCpp = pCGenState->CGen->fpCpp;
pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp;
pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp;
memcpy(pCGen->TempleName, pSrc, Len);
*(pCGen->TempleName + Len) = '\0';
memset(&CGenState, 0, sizeof(CGENSTATE));
CGenState.CGen = pCGen;
CGenState.ExportsDbg = pCGenState->ExportsDbg;
CGenState.DebugStrings = pCGenState->DebugStrings;
CGenState.ApiTypes = pCGenState->ApiTypes;
CGenState.ApiNum = pCGenState->ApiNum;
CGenState.pArgsList = pCGenState->pArgsList;
CGenState.ListCol = pCGenState->ListCol;
CGenState.MoreApis = pCGenState->MoreApis;
CGenState.CodeBurstIndex = pCGenState->CodeBurstIndex;
ProcessTemple(&CGenState);
GenHeapFree(pCGen);
return pEnd;
}
/*
* WriteMore
*/
char *WriteMore(char *pSrc, PCGENSTATE pCGenState, BOOL bMore)
{
char *pch;
char *pExpression;
CGENSTATE CGenState;
pch = SkipSubExpression(pSrc, bMore ? &pExpression : NULL);
if (pSrc == pch) {
return pSrc;
}
pSrc = pch;
if (!bMore || !pExpression) {
return pSrc;
}
CGenState = *pCGenState;
CGenerate(pExpression, &CGenState);
GenHeapFree(pExpression);
return pSrc;
}
/*
* WriteArgLocal
*/
BOOL
WriteArgLocal(
PCGENSTATE pCGenState,
char *Buffer,
int BuffLen)
{
char *pExpression;
char *pEnd;
char *pch;
int i, Len;
if (pCGenState->pArgsList->ArgLocal) {
ErrMsg("Type Template error multiple ArgLocals\n");
return FALSE;
}
// format the local var name
Len = _snprintf(Buffer, BuffLen, "%s", pCGenState->pArgsList->Name);
if (Len <= 0) {
ErrMsg(
"WriteArgLocal buffer overflow %s\n",
pCGenState->pArgsList->Name
);
return FALSE;
}
// alloc space for the local var name, and stash it away
pCGenState->pArgsList->ArgLocal = GenHeapAlloc(Len + 1);
if (!pCGenState->pArgsList->ArgLocal) {
ErrMsg("GenHeapAlloc(ArgLocal) %s\n", pCGenState->pArgsList->Name);
return FALSE;
}
strcpy(pCGenState->pArgsList->ArgLocal, Buffer);
//
// format the declarator statement: "ArgType IndLevel *ArgName"
//
pch = Buffer;
i = strlen(pCGenState->pArgsList->Type) +
strlen(TokenString[pCGenState->pArgsList->SUEOpt]) + 1;
if (i >= BuffLen) {
ErrMsg(
"WriteArgLocal buffer overflow %s\n",
pCGenState->pArgsList->Name
);
return FALSE;
}
if (pCGenState->pArgsList->SUEOpt != TK_NONE) {
strcpy(pch, TokenString[pCGenState->pArgsList->SUEOpt]);
strcat(pch, " ");
strcat(pch, pCGenState->pArgsList->Type);
} else {
strcpy(pch, pCGenState->pArgsList->Type);
}
if (pCGenState->pArgsList->PrePostMod != TK_NONE) {
strcat(pch, " ");
strcat(pch, TokenString[pCGenState->pArgsList->PrePostMod]);
}
i = strlen(pch);
Len = BuffLen - i - 1;
pch += i;
i = pCGenState->pArgsList->IndLevel;
if (!Len || i > Len) {
ErrMsg(
"WriteArgLocal buffer overflow %s\n",
pCGenState->pArgsList->Name
);
return FALSE;
}
if (i) {
*pch++ = ' ';
while (i) {
*pch++ = '*';
i--;
}
}
*pch++ = ' ';
i = strlen(pCGenState->pArgsList->ArgLocal);
if (!Len || i > Len) {
ErrMsg(
"WriteArgLocal buffer overflow %s\n",
pCGenState->pArgsList->Name
);
return FALSE;
}
strcpy(pch, pCGenState->pArgsList->ArgLocal);
//
// Record that some kind of exception template has been used
// during generation of this argument.
//
pCGenState->pArgsList->fRequiresThunk = FALSE;
return TRUE;
}
/*
* WriteArgAddr
*/
char *
WriteArgAddr(
char *pSrc,
PCGENSTATE pCGenState,
char *Buffer,
int BuffLen)
{
char *pEnd;
char *pch;
size_t Len;
pch = SkipSubExpression(pSrc, NULL);
if (pSrc == pch) {
return pSrc;
}
pEnd = pch;
Len = --pch - ++pSrc;
if (Len + 32 >= (size_t)BuffLen) {
ExitErrMsg(FALSE,
"WriteArgAddr buffer overflow %s\n",
pSrc
);
}
while (pSrc < pch) {
*Buffer++ = *pSrc++;
}
*Buffer++ = ' ';
*Buffer++ = '+';
*Buffer++ = ' ';
_itoa(pCGenState->pArgsList->OffSet, Buffer, 10);
return pEnd;
}
BOOLEAN
TempleHasNoCodeBursts(
PTEMPLES pTemple
)
/*++
Routine Description:
Determines if a template has no codebursts at all or not.
Arguments:
pTemple - template to examine
Return Value:
TRUE if template has no codebursts, FALSE if there is at least one.
--*/
{
int i;
for (i=0; i<MAX_CODEBURST; ++i) {
if (pTemple->CodeBurst[i]) {
return FALSE;
}
}
return TRUE;
}
/*
* ListApis
*/
char *ListApis(char *pSrc, PCGENSTATE pCGenState, BOOL bExports)
{
char *pch;
char *pExpression;
PLIST_ENTRY Next;
CGENSTATE CGenState;
PTEMPLES pTemple;
BOOL GenerateCode;
BYTE ApiPlatform;
BOOL ExcludedApi;
pch = SkipSubExpression(pSrc, &pExpression);
if (pSrc == pch || !pExpression) {
return pch;
}
pSrc = pch;
memset(&CGenState, 0, sizeof(CGenState));
CGenState.CGen = pCGenState->CGen;
CGenState.Temple = pCGenState->Temple;
CGenState.MoreApis = TRUE;
CGenState.ListCol = pCGenState->ListCol;
CGenState.CodeBurstIndex = pCGenState->CodeBurstIndex;
Next = ExportsList.Flink;
while (Next != &ExportsList) {
CGenState.ExportsDbg = CONTAINING_RECORD(Next,
EXPORTSDEBUG,
ExportsDbgEntry
);
Next= Next->Flink;
if (Next == &ExportsList) {
CGenState.MoreApis = FALSE;
}
//
// Switch this API in or out depending on the platform info
//
ApiPlatform = CGenState.ExportsDbg->ApiPlatform;
PlatformSwitchStart(&CGenState, ApiPlatform);
CGenState.ApiTypes = GetApiTypes(CGenState.ExportsDbg);
pTemple = GetTemplate(&EFuncTempleList,
CGenState.ExportsDbg->ExportName
);
ExcludedApi = FALSE;
// skip this api if ex template, but no code
if (!bExports && pTemple && TempleHasNoCodeBursts(pTemple)) {
ExcludedApi = TRUE;
fprintf(pCGenState->CGen->fp,
"%s *** WARNING *** Excluded Api %s\n",
CGenState.Temple->Comment,
CGenState.ExportsDbg->ExportName
);
}
//
// skip this api if:
// - external forward reference
// - internal forward which does not define the function.
// (exportname != forwardname)
//
else if (!bExports &&
(CGenState.ExportsDbg->ExtForward ||
(CGenState.ExportsDbg->IntForward &&
CGenState.ExportsDbg->IntForward != CGenState.ExportsDbg)))
{
ExcludedApi = TRUE;
fprintf(pCGenState->CGen->fp,
"%s %s forwarded to %s\n",
CGenState.Temple->Comment,
CGenState.ExportsDbg->ExportName,
CGenState.ExportsDbg->ExtForward
? CGenState.ExportsDbg->ExtForward
: CGenState.ExportsDbg->IntForward->ExportName
);
}
// skip this api if DATA and no ex template
else if (!pTemple && CGenState.ExportsDbg->Data) {
ExcludedApi = TRUE;
fprintf(pCGenState->CGen->fp,
"%s *** WARNING *** Excluded Data Export %s\n",
CGenState.Temple->Comment,
CGenState.ExportsDbg->ExportName
);
}
// skip this api if CPP export and we aren't setup for CPP exports,
else if (!pTemple && !iHandleCpp && CGenState.ExportsDbg->CplusDecoration)
{
ExcludedApi = TRUE;
fprintf(pCGenState->CGen->fp,
"%s *** WARNING *** Excluding CPP Api: %s\n",
CGenState.Temple->Comment,
CGenState.ExportsDbg->ExportName
);
}
// skip this api if members are unknown
else if (!CGenState.ApiTypes->pfuncinfo) {
ExcludedApi = TRUE;
ExitErrMsg(FALSE,
"API %s has no function prototype - unable to generate code.",
CGenState.ExportsDbg->ExportName
);
}
// gen code for this api
else {
if (pTemple) {
CGenState.ExTemplate= TRUE;
}
else {
CGenState.ExTemplate= FALSE;
}
BuildArgsList(pTemple,
CGenState.ApiTypes->pfuncinfo,
&CGenState.ExportsDbg->ArgsListHead
);
if (GetArgSize(CGenState.ExportsDbg) < 0) {
ExcludedApi = TRUE;
ExitErrMsg(FALSE,
"API %s has no function prototype - unable to generate code.",
CGenState.ExportsDbg->ExportName
);
}
else {
CGenerate(pExpression, &CGenState);
if (bExports) {
//
// we're generating the .DEF file. Mark some APIs
// as private so the linker doesn't warn us.
//
if (strcmp(CGenState.ExportsDbg->ExportName,
"DllGetClassObject") == 0 ||
strcmp(CGenState.ExportsDbg->ExportName,
"DllCanUnloadNow") == 0 ||
strcmp(CGenState.ExportsDbg->ExportName,
"DllRegisterServer") == 0 ||
strcmp(CGenState.ExportsDbg->ExportName,
"DllRegisterServerEx") == 0 ||
strcmp(CGenState.ExportsDbg->ExportName,
"DllInstall") == 0 ||
strcmp(CGenState.ExportsDbg->ExportName,
"DllUnregisterServer") == 0) {
fprintf(pCGenState->CGen->fp, " PRIVATE");
}
}
CGenState.ApiNum++;
}
}
if (bExports)
PlatformSwitchEnd(&CGenState, ApiPlatform);
else{
if (ExcludedApi)
PlatformSwitchEnd(&CGenState, ApiPlatform);
else
PlatformSwitchEndTable(&CGenState, ApiPlatform);
}
if (CGenState.ListCol) {
WriteListColumn(&CGenState);
}
}
GenHeapFree(pExpression);
return pSrc;
}
PKNOWNTYPES
BuildFakeTypesInfo(
PEXPORTSDEBUG pExportsDbg,
PKNOWNTYPES pKnownTypes
)
{
TYPESINFO ti;
int ArgsSize, i;
size_t Len;
PFUNCINFO funcinfo;
char *pch;
memset(&ti, 0, sizeof(TYPESINFO));
strcpy(ti.TypeName, pExportsDbg->ExportName);
if (pKnownTypes) {
strcpy(ti.BasicType, pKnownTypes->BasicType);
strcpy(ti.BaseName, pKnownTypes->BaseName);
strcpy(ti.FuncRet, pKnownTypes->FuncRet);
strcpy(ti.FuncMod, pKnownTypes->FuncMod);
pExportsDbg->UnKnownApi = -1; // incomplete fn declaration
/*
* WARNING:
* The type is added to the FakeFuncsList with args
* info from the dll symbols. The type is NOT removed
* from the FuncsList.
*/
}
else {
strcpy(ti.BasicType, szFUNC);
strcpy(ti.FuncRet, szINT);
pExportsDbg->UnKnownApi = 1; // missing fn declaration
}
ArgsSize = pExportsDbg->ArgsSize;
if (!ArgsSize) {
ti.TypeKind = TypeKindFunc;
ti.dwMemberSize = sizeof(FUNCINFO) + strlen(szVOID) + 1;
ti.pfuncinfo = (PFUNCINFO)ti.Members;
pch = ti.Members + sizeof(FUNCINFO);
strcpy(pch, szVOID);
ti.pfuncinfo->sType = pch;
}
else if (ArgsSize < 0) {
;
}
else {
ti.TypeKind = TypeKindFunc;
pch = ti.Members + sizeof(FUNCINFO);
Len = sizeof(ti.Members) - 1 - sizeof(FUNCINFO);
funcinfo = (PFUNCINFO)ti.Members;
ti.pfuncinfo = funcinfo;
while (ArgsSize && Len) {
ti.dwMemberSize+=sizeof(FUNCINFO);
i = _snprintf(pch, Len, "Fake%x", ArgsSize);
if (i < 0) {
return NULL;
}
i++;
Len -= i;
funcinfo->sName = pch;
pch += i;
ti.dwMemberSize+=i;
strcpy(pch, szINT);
funcinfo->sType = pch;
i = strlen(szINT) + 1;
pch += i;
ti.dwMemberSize+=i;
ArgsSize -= sizeof(int);
if (ArgsSize) {
PFUNCINFO funcinfoNext;
INT_PTR Realignment;
//
// Allocate space for another FUNCINFO, ensuring that
// it is DWORD-aligned.
//
Len -= sizeof(FUNCINFO);
Realignment = 4 - ((INT_PTR)pch & 3);
Len -= Realignment;
funcinfoNext = (PFUNCINFO)(pch + Realignment);
pch += sizeof(FUNCINFO)+Realignment;
ti.dwMemberSize += (DWORD)Realignment;
if ((INT_PTR)Len < 0) {
return NULL;
}
funcinfo->pfuncinfoNext = funcinfoNext;
funcinfo = funcinfoNext;
}
}
}
return AddToTypesList(&FakeFuncsList, &ti);
}
/*
* GetFuncArgNum
*/
int GetFuncArgNum(PCGENSTATE pCGenState)
{
PARGSLIST pArgsList;
PKNOWNTYPES pkt;
int NumArgs;
PFUNCINFO funcinfo;
pArgsList = pCGenState->pArgsList;
if (!pArgsList) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetFuncArgNum Missing argument List\n\n"
);
return -1;
}
pkt = pArgsList->pKnownTypes;
while (!pkt->Members || !pkt->pfuncinfo) {
if (pkt->pktBase) {
// the knowntype is already cached
pkt = pkt->pktBase;
} else {
PKNOWNTYPES pktOrg = pkt;
pkt = GetNameFromTypesList(TypeDefsList, pkt->BaseName);
if (!pkt) {
if (pArgsList->pKnownTypes) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetFuncArgNum BaseType Not found:<%s:%s>\n\n",
pArgsList->pKnownTypes->TypeName,
pArgsList->pKnownTypes->BasicType
);
} else {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERRR ***\n*** GetFuncArgNum BaseType Not found: no KnownTypes\n\n"
);
}
return -1;
}
pktOrg->pktBase = pkt;
}
if (!strcmp(pkt->BasicType, pkt->TypeName)) {
break;
}
}
funcinfo = pkt->pfuncinfo;
if (!pkt->Members || !funcinfo) {
fprintf(pCGenState->CGen->fp,
"/*** WARN gfan No Members:<%s:%s> ***/ ",
pArgsList->pKnownTypes->TypeName,
pkt->BasicType
);
return 0;
}
//
// "..." vargs is nonsense can't do it!
//
if (strcmp(funcinfo->sType, szVARGS) == 0) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetFuncArgNum variable Args:<%s:%s>\n\n",
pArgsList->pKnownTypes->TypeName,
pkt->BasicType
);
return -1;
}
//
// void arg list, Zero Args
//
if (strcmp(funcinfo->sType, szVOID) == 0) {
return 0;
}
NumArgs = 0;
do {
NumArgs++;
funcinfo = funcinfo->pfuncinfoNext;
} while(funcinfo);
return NumArgs;
}
/*
* GetFuncIndex
*/
int GetFuncIndex(PCGENSTATE pCGenState, char *FuncTypeName)
{
PKNOWNTYPES pkt, pktFunc;
int Len, LenExpr, LenArgs, LenRet;
char *pch;
char Args[1024];
PFUNCINFO funcinfo;
PDEBUGSTRINGS DebugStrings;
if (!FuncTypeName || !*FuncTypeName) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetFuncIndex TypeName Not specified\n\n"
);
return -1;
}
pkt = GetNameFromTypesList(TypeDefsList, FuncTypeName);
if (!pkt) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetFuncIndex Type Not found:<%s>\n\n",
FuncTypeName
);
return -1;
}
pktFunc = pkt;
while (!pkt->Members || !pkt->pfuncinfo) {
// NOTE: we cannot look at pkt->pktBase as it may point to a struct
// knowntype instead of a typedef
pkt = GetNameFromTypesList(TypeDefsList, pkt->BaseName);
if (!pkt) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetFuncIndex BaseType Not found:<%s:%s>\n\n",
FuncTypeName,
pktFunc->BaseName
);
return -1;
}
if (!strcmp(pkt->BasicType, pkt->TypeName)) {
break;
}
}
LenArgs = 1;
Args[0] = '\0';
funcinfo = pkt->pfuncinfo;
if (pkt->Members && funcinfo) {
//
// "..." vargs is nonsense can't do it!
//
if (strcmp(funcinfo->sType, szVARGS) == 0) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** GetFuncIndex variable Args:<%s:%s>\n\n",
FuncTypeName,
pkt->BasicType
);
return -1;
}
//
// void arg list means no args
//
if (strcmp(funcinfo->sType, szVOID) != 0) {
pch = Args;
do {
//
// Copy in the typename
//
Len = strlen(funcinfo->sType);
LenArgs += Len;
if (LenArgs >= sizeof(Args)-3) {
break;
}
strcpy(pch, funcinfo->sType);
pch += Len;
//
// Copy in the levels of indirection
//
LenArgs += funcinfo->IndLevel;
if (LenArgs >= sizeof(Args)-3) {
break;
}
for (Len = 0; Len<funcinfo->IndLevel; ++Len) {
*pch++ = '*';
}
//
// Copy in the argument name, if present
//
if (funcinfo->sName) {
Len = strlen(funcinfo->sName) + 1;
LenArgs += Len;
if (LenArgs >= sizeof(Args)-3) {
break;
}
*pch = ' ';
strcpy(pch+1, funcinfo->sName);
pch += Len;
}
//
// Copy in the printf-style formatting for this argument
//
LenArgs += 3;
*pch++ = ' ';
*pch++ = '%';
*pch++ = 'x';
funcinfo = funcinfo->pfuncinfoNext;
if (funcinfo) {
LenArgs+=2;
*pch++ = ',';
*pch++ = ' ';
}
} while (funcinfo);
if (LenArgs >= sizeof(Args)-5) {
ExitErrMsg(FALSE,
"GetFuncIndex overflow %s.%s\n",
FuncTypeName,
pkt->Members
);
}
}
//
// Null-terminate the Args[] string.
//
Args[LenArgs-1] = '\0';
}
LenExpr = strlen(FuncTypeName) + 1;
LenRet = strlen(pkt->FuncRet) + 4;
DebugStrings = GenHeapAlloc(LenExpr + LenRet + LenArgs + sizeof(DEBUGSTRINGS));
if (!DebugStrings) {
ExitErrMsg(TRUE,
"GetFuncIndex: GenHeapAlloc(DebugStrings) %s.%s\n",
FuncTypeName,
pkt->Members
);
}
Len = 0;
DebugStrings->Name = DebugStrings->Buffer;
strcpy(DebugStrings->Name, FuncTypeName);
Len += LenExpr;
DebugStrings->ArgFormat = DebugStrings->Buffer + Len;
strcpy(DebugStrings->ArgFormat, Args);
Len += LenArgs;
DebugStrings->RetFormat = DebugStrings->Buffer + Len;
strcpy(DebugStrings->RetFormat, pkt->FuncRet);
strcat(DebugStrings->RetFormat, " %x");
Len += LenRet;
InsertTailList(&DebugStringsList, &DebugStrings->DebugStringsEntry);
return NumDebugStringsEntries++;
}
/*
* WriteDbgsStrings
*
*/
void WriteDbgsStrings(char *pSrc, PCGENSTATE pCGenState)
{
DEBUGSTRINGS DebugStrings;
char BaseName[MAX_PATH];
char *c;
// copy in the DLL name and whack off the extension
strcpy(BaseName, DllBaseName);
c = strchr(BaseName, '.');
if (c) {
*c = '\0';
}
if (!pCGenState->DebugStrings) {
pCGenState->DebugStrings = &DebugStrings;
DebugStrings.Name =
DebugStrings.ArgFormat =
DebugStrings.RetFormat = "";
}
fprintf(pCGenState->CGen->fp,
"\"%s!%s\",\"%s\",\"%s\"",
BaseName,
pCGenState->DebugStrings->Name,
pCGenState->DebugStrings->ArgFormat,
pCGenState->DebugStrings->RetFormat
);
}
/*
* ListDbgs
*/
char *ListDbgs(char *pSrc, PCGENSTATE pCGenState)
{
char *pch;
char *pExpression;
PLIST_ENTRY Next;
CGENSTATE CGenState;
PTEMPLES pTemple;
pch = SkipSubExpression(pSrc, &pExpression);
if (pSrc == pch || !pExpression) {
return pch;
}
pSrc = pch;
memset(&CGenState, 0, sizeof(CGenState));
CGenState.CGen = pCGenState->CGen;
CGenState.Temple = pCGenState->Temple;
CGenState.ListCol = pCGenState->ListCol;
if (!IsListEmpty(&DebugStringsList)) {
Next = DebugStringsList.Flink;
while (Next != &DebugStringsList) {
CGenState.DebugStrings = CONTAINING_RECORD(Next,
DEBUGSTRINGS,
DebugStringsEntry
);
Next= Next->Flink;
CGenState.MoreApis = Next != &DebugStringsList;
CGenerate(pExpression, &CGenState);
if (CGenState.ListCol) {
WriteListColumn(&CGenState);
}
}
}
else {
CGenState.MoreApis = FALSE;
CGenerate(pExpression, &CGenState);
if (CGenState.ListCol) {
WriteListColumn(&CGenState);
}
}
GenHeapFree(pExpression);
return pSrc;
}
/*
* ListArgs
*/
char *ListArgs(char *pSrc, PCGENSTATE pCGenState, BOOL Always)
{
PARGSLIST pArgsList;
PLIST_ENTRY Next;
char *pch;
char *pExpression;
CGENSTATE CGenState;
if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) {
fprintf(pCGenState->CGen->fp,
"\n\t*** ERROR ***\n*** ListArgs Missing argument List: %s\n\n",
pCGenState->ApiTypes->TypeName
);
return SkipSubExpression(pSrc, NULL);
}
Next = pCGenState->ExportsDbg->ArgsListHead.Flink;
// check for void arg list
if (!Always) {
pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry);
if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) {
return SkipSubExpression(pSrc, NULL);
}
}
CGenState = *pCGenState;
pch = SkipSubExpression(pSrc, &pExpression);
if (pSrc == pch || !pExpression) {
return pch;
}
pSrc = pch;
do {
CGenState.pArgsList = CONTAINING_RECORD(Next,ARGSLIST, ArgumentsEntry);
CGenerate(pExpression, &CGenState);
if (CGenState.ListCol) {
WriteListColumn(&CGenState);
}
Next= Next->Flink;
} while (Next != &CGenState.ExportsDbg->ArgsListHead);
GenHeapFree(pExpression);
return pSrc;
}
/*
* WriteListColumn
*/
void WriteListColumn(PCGENSTATE pCGenState)
{
int Len;
FILE *fp = pCGenState->CGen->fp;
OutputColumn = pCGenState->ListCol;
Len = OutputColumn - 1;
if (fputc('\n', fp) != '\n') {
ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC);
return;
}
while (Len--) {
if (fputc(' ', fp) != ' ') {
ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC);
}
}
}
/*
* SkipSubExpression
*
*/
char *SkipSubExpression(char *pSrc, char **pSubExpression)
{
char *pOrg = pSrc;
char *pSave;
int Len = 0;
int ParenLevel;
if ((*pSrc != '(') && (*pSrc != ',')) {
return pOrg;
}
pSrc++;
pSave = pSrc;
ParenLevel = 1;
Len = 0;
while (*pSrc) {
if (*pSrc == '(') {
ParenLevel++;
}
else if (*pSrc == ')') {
ParenLevel--;
}
pSrc++;
if (!ParenLevel) {
break;
}
Len++;
}
if (pSubExpression) {
if (Len) {
*pSubExpression = GenHeapAlloc(Len + 1);
if (!*pSubExpression) {
ExitErrMsg(TRUE, "GenHeapAlloc(SubExpression) %s\n", pOrg);
}
if (Len) {
memcpy(*pSubExpression, pSave, Len);
}
*(*pSubExpression + Len) = '\0';
}
else {
*pSubExpression = NULL;
}
}
return pSrc;
}
/*
* GetTemplate
*/
PTEMPLES GetTemplate(PLIST_ENTRY pHeadList, char *TempleName)
{
PTEMPLES ptpl;
PLIST_ENTRY Next;
Next = pHeadList->Flink;
while (Next != pHeadList) {
ptpl = CONTAINING_RECORD(Next, TEMPLES, TempleEntry);
if (!strcmp(ptpl->Name, TempleName)) {
return ptpl;
}
Next= Next->Flink;
}
return NULL;
}
void
UseLogMacros(char *LogName)
{
DWORD Len;
char FullLogName[MAX_PATH+1];
char *LogBaseName;
Len = GetFullPathName(LogName,
sizeof(FullLogName) - 1,
FullLogName,
&LogBaseName
);
if (Len == 0 || Len >= sizeof(FullLogName) - 1) {
ExitErrMsg(TRUE, "Could not fully-qualify log filename '%s'\n", LogName);
}
fpLog = fopen(FullLogName, "w");
if (!fpLog) {
ExitErrMsg(TRUE, "fopen(%s) failed\n", FullLogName);
}
if (!AddOpenFile(FullLogName, fpLog, NULL)) {
ExitErrMsg(FALSE, "AddOpenFile failed\n");
}
}
char *
UpdateLog(
char *pSrc,
PCGENSTATE pCGenState
)
{
FILE *fpOld;
BOOL bMore;
if (fpLog) {
fpOld = pCGenState->CGen->fp;
pCGenState->CGen->fp = fpLog;
bMore = TRUE;
} else {
fpOld = NULL;
bMore = FALSE;
}
pSrc = WriteMore(pSrc,pCGenState,bMore);
if (bMore) {
pCGenState->CGen->fp = fpOld;
fprintf(fpLog, "\n");
}
return pSrc;
}
/*
* ExtractCGenerate
*/
BOOL ExtractCGenerate(char *pNames)
{
FILE *fp=NULL, *fpCpp=NULL;
size_t Len;
DWORD SizeFileName, SizeTempleName;
DWORD SizeFileNameCpp = 0;
char *pch;
char *pchColon, *pchComma;
PCGENERATE pCGen;
char *OutputBaseNameCpp;
char FullOutputNameCpp[MAX_PATH+1];
char *OutputBaseName;
char FullOutputName[MAX_PATH+1];
char OutputName[MAX_PATH+1];
char OutputNameCpp[MAX_PATH+1];
char TempleName[MAX_PATH];
DbgPrintf("CGenerate: %s\n", pNames);
pchComma = strchr(pNames, ',');
pchColon = strchr(pNames, ':');
if (pchComma != NULL) {
pch = pchComma;
}
else {
pch = pchColon;
}
Len = pch - pNames;
if (!pch || !Len || Len >= sizeof(OutputName) - 1) {
return FALSE;
}
strncpy(OutputName, pNames, Len);
*(OutputName + Len) = '\0';
//
// Extract the CPP filename, and initialize iHandleCPP
//
OutputNameCpp[0] = '\0';
if (pchComma) {
size_t LenCpp;
LenCpp = pchColon - ++pchComma;
if (LenCpp >= sizeof(OutputNameCpp) - 1) {
return(FALSE);
}
if (LenCpp) {
iHandleCpp = 1; // use CPP macros
strncpy(OutputNameCpp, pchComma, LenCpp);
*(OutputNameCpp + LenCpp) = '\0';
}
else {
iHandleCpp = -1; // ignore CPP macros, and don't warn
}
Len += LenCpp + 1;
}
pNames += Len;
if (*pNames != ':') { // no template name!
return FALSE;
}
Len = GetFullPathName(OutputName,
sizeof(FullOutputName) - 1,
FullOutputName,
&OutputBaseName
);
if (Len >= sizeof(FullOutputName) - 1) {
return FALSE;
}
SizeFileName = Len + 1;
fp = fopen(FullOutputName, "w");
if (!fp) {
ExitErrMsg(TRUE, "fopen(%s) failed\n", FullOutputName);
}
if (!AddOpenFile(FullOutputName, fp, NULL)) {
ExitErrMsg(FALSE, "AddOpenFile failed\n");
}
if (fseek(fp, 0, SEEK_SET)) {
ExitErrMsg(TRUE, "ExtractCGenerate: fseek to 0 failed\n");
}
//
// Open the CPP file name
//
//if (iHandleCpp > 0) {
if (OutputNameCpp[0]) {
Len = GetFullPathName(OutputNameCpp,
sizeof(FullOutputNameCpp) - 1,
FullOutputNameCpp,
&OutputBaseNameCpp
);
if (!Len || (Len >= sizeof(FullOutputNameCpp) - 1)) {
return FALSE;
}
SizeFileNameCpp = Len + 1;
fpCpp = fopen(FullOutputNameCpp, "w");
if (!fpCpp) {
ExitErrMsg(TRUE, "fopen(%s) failed\n", FullOutputNameCpp);
}
if (!AddOpenFile(FullOutputNameCpp, fpCpp, NULL)) {
ExitErrMsg(FALSE, "AddOpenFile failed\n");
}
if (fseek(fpCpp, 0, SEEK_SET)) {
ExitErrMsg(TRUE, "ExtractCGenerate fseek #2 to 0 failed\n");
}
}
pch = GetNextToken(pNames);
if (pch == pNames || !*pch) {
return FALSE;
}
Len = CopyToken(TempleName, pch, sizeof(TempleName) - 1);
if (!Len || Len >= sizeof(TempleName) - 1) {
return FALSE;
}
SizeTempleName = Len + 1;
Len = sizeof(CGENERATE) + 1;
Len += SizeFileName + SizeTempleName + SizeFileNameCpp;
pCGen = GenHeapAlloc(Len);
if (!pCGen) {
ExitErrMsg(TRUE, "GenHeapAlloc(CGENERATE)");
}
memset(pCGen, 0, Len);
if (bDebug) {
setvbuf(fp, NULL, _IONBF, 0);
}
pCGen->fp = fp;
pCGen->fpC = fp;
strcpy(pCGen->TempleName, TempleName);
pCGen->FileNameC = pCGen->TempleName + SizeTempleName;
pCGen->FileBaseNameC = pCGen->FileNameC;
pCGen->FileBaseNameC += OutputBaseName - FullOutputName;
strcpy(pCGen->FileNameC, FullOutputName);
//
// Save the CPP filename, and file handle.
//
if (iHandleCpp > 0 && OutputNameCpp[0]) {
if (bDebug) {
setvbuf(fpCpp, NULL, _IONBF, 0);
}
pCGen->fpCpp = fpCpp;
pCGen->FileNameCpp = pCGen->FileNameC + SizeFileName;
pCGen->FileBaseNameCpp = pCGen->FileNameCpp;
pCGen->FileBaseNameCpp += OutputBaseNameCpp - FullOutputNameCpp;
strcpy(pCGen->FileNameCpp, FullOutputNameCpp);
}
InsertTailList(&CGenerateList, &pCGen->CGenerateEntry);
return TRUE;
}
/*
* ExtractTemples
*
*/
BOOL ExtractTemples(char *FileName)
{
FILE *fp;
int FileSize;
BOOL bRet = FALSE;
char *pSrc;
char *pch;
size_t Len;
int CGenLen;
LPSTR pCCode[MAX_CODEBURST];
char Comment[MAX_PATH];
char IndLevel[MAX_PATH];
char TempleType[MAX_PATH];
char TempleName[MAX_PATH];
char CodeBurstName[MAX_PATH];
LPSTR Also[MAX_ALSO];
int AlsoCount;
LPSTR NoType[MAX_NOTYPE];
int NoTypeCount;
PLIST_ENTRY pCaseList;
char Line[1024];
int CodeBurstIndex;
TOKENTYPE tkDirection;
PTEMPLES tpl;
BOOL fFreeCCode = TRUE;
int i;
DbgPrintf("Template: %s\n", FileName);
fp = fopen(FileName, "r");
if (!fp) {
ExitErrMsg(TRUE, "fopen(%s) failed\n", FileName);
}
if (fseek(fp, 0, SEEK_END)) {
ExitErrMsg(TRUE, "fseek to EOF failed\n");
}
FileSize = ftell(fp);
if (fseek(fp, 0, SEEK_SET)) {
ExitErrMsg(TRUE, "fseek to 0 failed\n");
}
// Record the filename/line number information for error messages
TemplateFileName = FileName;
TemplateLine = 1;
if (!fgets(Line, sizeof(Line) - 1, fp)) {
if (ferror(fp)) {
ExitErrMsg(TRUE, "Failed to get Types from %s\n", FileName);
} else if (feof(fp)) {
ExitErrMsg(TRUE, "Premature EOF %s\n", FileName);
}
}
// reset the TempleType: no [TempleType] is active
*TempleType = '\0';
// reset all variables used within a [TempleType]
CGenLen = 0;
*IndLevel = 0;
*TempleName = '\0';
strcpy(Comment, "//");
memset(pCCode, 0, sizeof(LPSTR)*MAX_CODEBURST);
tkDirection = TK_EOS; // assume template handles all flavors of IN/OUT
AlsoCount=0;
NoTypeCount=0;
pCaseList = NULL;
// loop over all lines in the template file
do {
pSrc = Line;
// skip whitespace at the start of the line
while (*pSrc && isspace(*pSrc)) {
pSrc++;
}
// if at end-of-line or encountered ';' (comment-to-EOL), go to
// next line.
if (!*pSrc || *pSrc == ';') {
goto GetNextLine;
}
if (*pSrc == '[') {
// encountered new [TempleType]. If there was a previous template,
// add it now.
if (*TempleName &&
!AddTemple(TempleType, TempleName, Comment, IndLevel, pCCode, tkDirection, Also, AlsoCount, NoType, NoTypeCount, pCaseList)) {
ExitErrMsg(FALSE, "%s(%d) %s %s\n", TemplateFileName, TemplateLine, TempleType, pSrc);
}
// free the previous template's memory
if (fFreeCCode) {
for (i=0; i < MAX_CODEBURST; ++i) {
if (pCCode[i]) {
GenHeapFree(pCCode[i]);
}
}
}
fFreeCCode = TRUE;
// reset the vars used for each template
CGenLen = 0;
memset(pCCode, 0, sizeof(LPSTR)*MAX_CODEBURST);
*IndLevel = 0;
*TempleName = '\0';
strcpy(Comment, "//");
tkDirection = TK_EOS; // assume template handles all flavors of IN/OUT
pCaseList = NULL;
for (i=0; i<AlsoCount; ++i) {
GenHeapFree(Also[i]);
}
AlsoCount=0;
for (i=0; i<NoTypeCount; ++i) {
GenHeapFree(NoType[i]);
}
NoTypeCount=0;
// set up the new TempleType
pSrc++;
Len = CopyToken(TempleType, pSrc, sizeof(TempleType) - 1);
if (Len >= sizeof(TempleType) - 1) {
goto ETPLExit;
}
pch = pSrc + Len;
if (*pch != ']') {
*TempleType = '\0';
}
goto GetNextLine;
}
// if no active [TempleType], ignore the line
if (!*TempleType) {
goto GetNextLine;
}
// a [TempleType] is active. Scan for known property names
if ( ((pch = SkipKeyWord(pSrc, szTEMPLENAME)) != pSrc ||
(pch = SkipKeyWord(pSrc, szMACRONAME)) != pSrc ||
(pch = SkipKeyWord(pSrc, szTYPENAME)) != pSrc)
&& *pch == '=') {
// found: TemplateName=
// or MacroName=
// or TypeName=
// They all mean the same thing.
// If a template is outstanding, add it now.
if (*TempleName &&
!AddTemple(TempleType, TempleName, Comment, IndLevel, pCCode, tkDirection, Also, AlsoCount, NoType, NoTypeCount, pCaseList)) {
ExitErrMsg(FALSE, "%s(%d) %s %s\n", TemplateFileName, TemplateLine, TempleType, pSrc);
}
// free the previous template's memory
if (fFreeCCode) {
for (i=0; i < MAX_CODEBURST; ++i) {
if (pCCode[i]) {
GenHeapFree(pCCode[i]);
}
}
}
fFreeCCode = TRUE;
// reset the vars used for each template
CGenLen = 0;
memset(pCCode, 0, sizeof(LPSTR)*MAX_CODEBURST);
*IndLevel = 0;
*TempleName = '\0';
tkDirection = TK_EOS; // assume template handles all flavors of IN/OUT
pCaseList = NULL;
for (i=0; i<AlsoCount; ++i) {
GenHeapFree(Also[i]);
}
AlsoCount=0;
for (i=0; i<NoTypeCount; ++i) {
GenHeapFree(NoType[i]);
}
NoTypeCount=0;
// copy in the new TemplateName
pch = GetNextToken(pch);
Len = sizeof(TempleName) - 1;
pSrc = TempleName;
while (isgraph(*pch) && Len--) {
*pSrc++ = *pch++;
}
if (Len == 0) {
// name too long
goto ETPLExit;
}
*pSrc = '\0';
} else if ((pch = SkipKeyWord(pSrc, szCOMMENT)) != pSrc &&
*pch == '=') {
// found: Comment=
pch = GetNextToken(pch);
Len = sizeof(Comment) - 1;
pSrc = Comment;
while (isgraph(*pch) && Len--) {
*pSrc++ = *pch++;
}
*pSrc = '\0';
} else if ( ((pch = SkipKeyWord(pSrc, szINDLEVEL)) != pSrc ||
(pch = SkipKeyWord(pSrc, szNUMARGS)) != pSrc)
&& *pch == '=') {
// Found: IndLevel=
// or NumArgs=
// They mean the same thing
pch = GetNextToken(pch);
if (IsSeparator(*pch)) {
goto ETPLExit;
}
pSrc = pch;
Len = CopyToken(IndLevel, pSrc, sizeof(IndLevel) - 1);
pch += Len;
} else if ((pch = SkipKeyWord(pSrc, szDIRECTION)) != pSrc &&
*pch == '=') {
pch++;
// Found: Direction=
if (strncmp(pch, "IN OUT", 6) == 0) {
tkDirection = TK_INOUT;
pch += 6;
} else if (strncmp(pch, "IN", 2) == 0) {
tkDirection = TK_IN;
pch += 2;
} else if (strncmp(pch, "OUT", 3) == 0) {
tkDirection = TK_OUT;
pch += 3;
} else if (strncmp(pch, "none", 4) == 0) {
// this allows a type template to explicitly catch
// all pointer types which have no IN/OUT modifiers.
tkDirection = TK_NONE;
pch+=4;
} else {
goto ETPLExit;
}
} else if ((pch = SkipKeyWord(pSrc, szUSE)) != pSrc &&
*pch == '=') {
PLIST_ENTRY pHeadList;
char buffer[MAX_PATH];
// Found: Use=
pch++;
pHeadList = ListFromTempleType(TempleType);
if (!pHeadList) {
ExitErrMsg(FALSE, "%s(%d) Use= can only be used after a [Temple]\n", TemplateFileName, TemplateLine);
}
Len = CopyToken(buffer, pch, sizeof(buffer));
tpl = GetTemplate(pHeadList, buffer);
if (!tpl) {
ExitErrMsg(FALSE, "%s(%d) Use=%s: Template not found\n", TemplateFileName, TemplateLine, pch);
}
// copy the template back to our locals
strcpy(Comment, tpl->Comment);
sprintf(IndLevel, "%d", tpl->IndLevel);
tkDirection = tpl->tkDirection;
memcpy(pCCode, tpl->CodeBurst, sizeof(LPSTR)*MAX_CODEBURST);
fFreeCCode = FALSE; // Don't GenHeapFree() the pCCode array
// after adding this temple.
pch += Len;
} else if ((pch = SkipKeyWord(pSrc, szNOTYPE)) != pSrc &&
*pch == '=') {
char *t;
if (AlsoCount) {
ExitErrMsg(FALSE, "%s(%d) Cannot have both NoType= and Also= in the same template\n", TemplateFileName, TemplateLine);
}
// skip '=' and any leading spaces
do {
pch++;
if (*pch == '\0') {
goto ETPLExit;
}
} while (isspace(*pch) && *pch != '\0');
// get length of the NoType= name
t = pch;
while (isgraph(*t)) {
t++;
}
Len= t-pch;
// copy the name
t = GenHeapAlloc(Len + 1);
memcpy(t, pch, Len);
t[Len] = '\0';
if (NoTypeCount == MAX_NOTYPE) {
ExitErrMsg(FALSE, "%s(%d) Max. of %d NoType= clauses allowed. Also=%s\n", TemplateFileName, TemplateLine, MAX_ALSO, t);
}
NoType[NoTypeCount++] = t;
pch += Len;
} else if ((pch = SkipKeyWord(pSrc, szCASE)) != pSrc &&
*pch == '=') {
char *t;
PMACROARGSLIST pMArgsList = NULL;
PMLLISTENTRY pMLListEntry = NULL;
// skip '=' and any leading spaces
do {
pch++;
if (*pch == '\0') {
goto ETPLExit;
}
} while (isspace(*pch) && *pch != '\0');
// get length of the Case=
t = pch;
while (isgraph(*t)) {
t++;
}
Len= t-pch;
if (pCaseList == NULL) {
pCaseList = CheckHeapAlloc(sizeof(LIST_ENTRY));
InitializeListHead(pCaseList);
}
ParseMacroArgs(pch, Len, &pMArgsList);
pMLListEntry = CheckHeapAlloc(sizeof(MLLISTENTRY));
if (NULL == pMLListEntry) {
ExitErrMsg(FALSE, "Out of memory\n");
}
pMLListEntry->pMArgs = pMArgsList;
InsertTailList(pCaseList, &(pMLListEntry->ListEntry));
pch += Len;
} else if ((pch = SkipKeyWord(pSrc, szALSO)) != pSrc &&
*pch == '=') {
char *t;
if (NoTypeCount) {
ExitErrMsg(FALSE, "%s(%d) Cannot have both Also= and NoType= in the same template\n", TemplateFileName, TemplateLine);
}
// skip '=' and any leading spaces
do {
pch++;
if (*pch == '\0') {
goto ETPLExit;
}
} while (isspace(*pch) && *pch != '\0');
// get length of the Also= name
t = pch;
while (isgraph(*t)) {
t++;
}
Len= t-pch;
// copy the name
t = GenHeapAlloc(Len + 1);
memcpy(t, pch, Len);
t[Len] = '\0';
if (AlsoCount == MAX_ALSO) {
ExitErrMsg(FALSE, "%s(%d) Max. of %d Also= clauses allowed. Also=%s\n", TemplateFileName, TemplateLine, MAX_ALSO, t);
}
Also[AlsoCount++] = t;
pch += Len;
} else {
GetNextCodeBurst:
// grab the name, and if the next thing isn't '=', error out.
pch = GetNextToken(pSrc);
if (*pch != '=') {
goto ETPLExit;
}
Len = CopyToken(CodeBurstName, pSrc, pch-pSrc);
pch += Len;
// convert the name into an index
CodeBurstIndex = GetCodeBurstIndex(CodeBurstName);
if (pCCode[CodeBurstIndex]) {
// Two codebursts with the same name in this template
goto ETPLExit;
}
pCCode[CodeBurstIndex] = GenHeapAlloc(FileSize*2 + 1);
CGenLen = 0;
pSrc = pCCode[CodeBurstIndex];
while (fgets(pSrc, FileSize*2 - CGenLen, fp)) {
char buffer[MAX_PATH];
int len;
TemplateLine++;
len = CopyToken(buffer, pSrc, sizeof(buffer));
pch = pSrc;
if (len && pSrc[len] == '=') {
// The line starts with some keyword and is followed by
// an '=' sign.
if (strcmp(buffer, szCGENEND) == 0 ||
strcmp(buffer, "CGenEnd") == 0) {
// The string is 'End=' or 'CGenEnd='. The CodeBurst
// is done.
*pSrc = '\0';
CGenLen++;
pch += len+1;
break;
}
// See if it is the start of a new CodeBurst:
CodeBurstIndex = GetExistingCodeBurstIndex(buffer);
if (CodeBurstIndex != -1) {
strcpy(Line, pSrc);
*pSrc = '\0';
CGenLen++;
pSrc = Line;
goto GetNextCodeBurst;
}
}
Len = strlen(pSrc);
CGenLen += Len;
pSrc += Len;
}
if (!CGenLen) {
GenHeapFree(pCCode[CodeBurstIndex]);
pCCode[CodeBurstIndex] = NULL;
}
}
while (*pch && *pch != ';' && IsSeparator(*pch)) {
pch++;
}
if (*pch) {
if (*pch == ';') {
// comment to end-of-line
goto GetNextLine;
}
goto ETPLExit;
}
GetNextLine:
TemplateLine++;
} while (fgets(Line, sizeof(Line) - 1, fp));
// If there is an outstanding template when EOF is hit, add it now.
if (*TempleName &&
!AddTemple(TempleType, TempleName, Comment, IndLevel, pCCode, tkDirection, Also, AlsoCount, NoType, NoTypeCount, pCaseList)) {
ExitErrMsg(FALSE, "%s(%d) %s %s\n", TemplateFileName, TemplateLine, TempleType, pSrc);
}
if (!feof(fp) && ferror(fp)) {
ExitErrMsg(TRUE, "%s(%d) Read error: %s\n", TemplateFileName, TemplateLine, TempleName);
}
bRet = TRUE;
ETPLExit:
if (!bRet) {
ErrMsg("%s(%d) ETPL: Invalid Line <%s>\n%s\n", TemplateFileName, TemplateLine, pSrc, Line);
}
if (fFreeCCode) {
for (i=0; i < MAX_CODEBURST; ++i) {
if (pCCode[i]) {
GenHeapFree(pCCode[i]);
}
}
}
for (i=0; i<AlsoCount; ++i) {
GenHeapFree(Also[i]);
}
for (i=0; i<NoTypeCount; ++i) {
GenHeapFree(NoType[i]);
}
fclose(fp);
TemplateFileName = NULL;
return bRet;
}
PEXPORTSDEBUG
FindInExportsList(char *Name)
{
PLIST_ENTRY pNext;
PEXPORTSDEBUG pexportsdbg;
pNext = ExportsList.Flink;
while (pNext != &ExportsList) {
pexportsdbg = CONTAINING_RECORD(pNext, EXPORTSDEBUG, ExportsDbgEntry);
if (!strcmp(Name, pexportsdbg->ExportName)) {
return pexportsdbg;
}
pNext = pNext->Flink;
}
return NULL;
}
PLIST_ENTRY
ListFromTempleType(
char *TempleType
)
{
if (!TempleType || !*TempleType) {
return NULL;
}
if (!strcmp(TempleType, szIFUNC)) {
return &IFuncTempleList;
} else if (!strcmp(TempleType, szEFUNC)) {
return &EFuncTempleList;
} else if (!strcmp(TempleType, szTYPES)) {
return &TypeTempleList;
} else if (!strcmp(TempleType, szCODE)) {
return &CodeTempleList;
} else if (!strcmp(TempleType, szEFAST)) {
return &EFastTempleList;
} else if (!strcmp(TempleType, szMACROS)) {
return &MacroList;
} else if (!strcmp(TempleType, szFAILTYPES)) {
return &FailTempleList;
}
return NULL;
}
/*
* AddTemple
*
* worker function for ExtractTemple, to verify and store template.
*/
#pragma optimize("", off)
BOOL
AddTemple(
char *TempleType,
char *TempleName,
char *Comment,
char *IndLevel,
char *pCCode[MAX_CODEBURST],
TOKENTYPE tkDirection,
char *Also[MAX_ALSO],
int AlsoCount,
char *NoType[MAX_NOTYPE],
int NoTypeCount,
PLIST_ENTRY pCaseList
)
{
PLIST_ENTRY pHeadList = NULL;
PTEMPLES ptpl;
char *pch;
int SizeCGen, SizeTempleName, SizeComment, SizeNoType;
int Len;
int i;
int AlsoIndex;
if (!*TempleName) {
return FALSE;
}
pHeadList = ListFromTempleType(TempleType);
if (!pHeadList) {
return FALSE;
}
SizeCGen = 0;
for (i=0; i<MAX_CODEBURST; ++i) {
SizeCGen++;
if (pCCode[i]) {
SizeCGen += strlen(pCCode[i]);
}
}
AlsoIndex=0;
for (;;) {
if (pHeadList != &TypeTempleList && GetTemplate(pHeadList, TempleName)) {
ExitErrMsg(FALSE, "Multiple templates are not allowed. TemplateName=%s, Type=%s\n", TempleName, TempleType);
}
SizeTempleName = strlen(TempleName) + 1;
SizeComment = strlen(Comment) + 1;
SizeNoType = 0;
for (i=0; i<NoTypeCount; ++i) {
SizeNoType += strlen(NoType[i])+1;
}
Len = SizeCGen + SizeTempleName + SizeComment + SizeNoType;
Len += sizeof(TEMPLES);
ptpl = GenHeapAlloc(Len);
if (!ptpl) {
ExitErrMsg(TRUE, "GenHeapAlloc(TEMPLE)");
}
memset(ptpl, 0, Len);
ptpl->IndLevel = strtoul(IndLevel, &pch, 10);
ptpl->tkDirection = tkDirection;
Len = 0;
ptpl->Name = ptpl->Buffer;
strcpy(ptpl->Name, TempleName);
Len += SizeTempleName;
ptpl->Comment = ptpl->Buffer + Len;
strcpy(ptpl->Comment, Comment);
Len += SizeComment;
for (i=0; i<MAX_CODEBURST; ++i) {
if (pCCode[i]) {
//
// Copy the code for this codeburst name
//
ptpl->CodeBurst[i] = ptpl->Buffer + Len;
Len++;
strcpy(ptpl->CodeBurst[i], pCCode[i]);
Len += strlen(pCCode[i]);
}
}
for (i=0; i<NoTypeCount; ++i) {
ptpl->NoTypes[i] = ptpl->Buffer + Len;
Len++;
strcpy(ptpl->NoTypes[i], NoType[i]);
Len += strlen(NoType[i]);
}
ptpl->pCaseList = pCaseList;
InsertTailList(pHeadList, &ptpl->TempleEntry);
if (bDebug && Len >= SizeCGen+SizeTempleName+SizeComment+SizeNoType) {
ExitErrMsg(FALSE, "Buffer overrun in AddTemple! Heap is trashed! ptpl=%x\n", ptpl);
}
if (bDebug) {
DumpTemplate(ptpl, stdout);
}
if (AlsoIndex == AlsoCount) {
break;
}
// there are Also= lines, add those template, too
strcpy(TempleName, Also[AlsoIndex]);
AlsoIndex++;
}
return TRUE;
}
#pragma optimize("", on)
/*
*
*/
void DumpTemplate(PTEMPLES ptpl, FILE *fp)
{
int i;
fprintf(fp,"Temple: %d Name<%s>\n",
ptpl->IndLevel,
ptpl->Name
);
for (i=0; i<MAX_CODEBURST; ++i) {
if (CodeBursts[i].Name) {
fprintf(fp,"%s(%d) Temple: %s<%s>\n", TemplateFileName, TemplateLine, CodeBursts[i].Name, ptpl->CodeBurst[i]);
}
}
}
ULONG
EndianSwitch(
PULONG pul
)
{
ULONG NewValue;
PBYTE pbValue = (PBYTE)pul;
PBYTE pbNewValue = (PBYTE) &NewValue;
*pbNewValue++ = *(pbValue + 3);
*pbNewValue++ = *(pbValue + 2);
*pbNewValue++ = *(pbValue + 1);
*pbNewValue = *pbValue;
return NewValue;
}
/* MapViewDll
*
* Creates a Mapped view of a Dll and intializes
* Dll global variables for easy access to the Export Directory
*
* DllMappedBase
* DllRvaOffset
* DllExportDir
* DllExportDirSize
* DllFunctions
* DllNameOrdinals
* DllNameTable
*
*
*/
BOOL MapViewDll(char *DllName)
{
ULONG_PTR RvaOffset;
HANDLE hFile;
HANDLE hMapFile;
PVOID MappedBase;
PIMAGE_EXPORT_DIRECTORY ExportDir;
ULONG ExportDirSize;
ULONG Forward;
//
// open and map the file to get the exports info
//
hFile = CreateFile(DllName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
ErrMsg("MapViewDll CreateFile(%s) gle %d\n", DllName, GetLastError());
return FALSE;
}
hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0,NULL);
if (!hMapFile) {
ErrMsg("MapViewDll CreateFileMapping(%s) gle %d\n", DllName, GetLastError());
return FALSE;
}
MappedBase = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
if (!MappedBase) {
ErrMsg("MapViewDll MapViewOfFile(%s) gle %d\n", DllName, GetLastError());
return FALSE;
}
ExportDir = ImageDirectoryEntryToData( MappedBase,
TRUE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportDirSize
);
if (!ExportDir) {
ErrMsg("MapViewDll ImageDirectoryEntryToData=NULL\n");
return FALSE;
}
//
// Initialize the global variables.
//
RvaOffset = (ULONG_PTR)ExportDir - (ULONG_PTR)MappedBase;
ExportDir = ImageDirectoryEntryToData( MappedBase,
FALSE,
IMAGE_DIRECTORY_ENTRY_EXPORT,
&ExportDirSize
);
if (!ExportDir) {
ErrMsg("MapViewDll ImageDirectoryEntryToData=NULL on the second call\n");
return FALSE;
}
DllExportDirSize = ExportDirSize;
DllMappedBase = MappedBase;
DllRvaOffset = RvaOffset;
DllExportDir = ExportDir;
DllFunctions = (PULONG)((ULONG_PTR)ExportDir +
(ULONG_PTR)ExportDir->AddressOfFunctions - RvaOffset
);
DllNameTable = (PULONG)((ULONG_PTR)ExportDir +
(ULONG_PTR)ExportDir->AddressOfNames - RvaOffset
);
DllNameOrdinals = (PUSHORT)((ULONG_PTR)ExportDir +
(ULONG_PTR)ExportDir->AddressOfNameOrdinals - RvaOffset
);
fprintf(stdout,
"Name %s Base %x Ver %x.%x NumberOfFunctions %x NumberOfNames %x\n",
(PCHAR)((ULONG_PTR)ExportDir + (ULONG_PTR)ExportDir->Name - RvaOffset),
ExportDir->Base,
(ULONG)ExportDir->MajorVersion,
(ULONG)ExportDir->MinorVersion,
ExportDir->NumberOfFunctions,
ExportDir->NumberOfNames
);
return TRUE;
}
ULONG
DllOrdinalByName(
char *ExportName
)
{
PULONG pNames;
ULONG NumNames;
PUSHORT pNameOrdinals;
char *Name;
pNames = DllNameTable;
pNameOrdinals = DllNameOrdinals;
NumNames = DllExportDir->NumberOfNames;
while (NumNames--) {
Name = (char *)((ULONG_PTR)DllExportDir + *pNames - DllRvaOffset);
if (!strcmp(Name, ExportName)) {
return *pNameOrdinals + DllExportDir->Base;
}
pNames++;
pNameOrdinals++;
}
return 0;
}
/* MapViewImplib
*
* Creates a Mapped view of an import library and intializes
* ImpLib global variables for access to symbols in the first
* special linker member.
*
* ImplibMappedBase
* ImplibNumSymbols
* ImplibSymbolMembers
* ImplibSymbolNames
*
*/
BOOL MapViewImplib(char *LibName)
{
HANDLE hFile;
HANDLE hMapFile;
PBYTE MappedBase;
PBYTE VirtualOffset;
ULONG MemberSize;
PIMAGE_ARCHIVE_MEMBER_HEADER ArchiveMemberHeader;
//
// open and map the file.
//
hFile = CreateFile(LibName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
ErrMsg("MapViewImplib CreateFile(%s) gle %d\n", LibName, GetLastError());
return FALSE;
}
hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0,NULL);
if (!hMapFile) {
ErrMsg("MapViewImplib CreateFileMapping(%s) gle %d\n", LibName, GetLastError());
return FALSE;
}
MappedBase = (PBYTE)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
if (!MappedBase) {
ErrMsg("MapViewImplib MapViewOfFile(%s) gle %d\n", LibName, GetLastError());
return FALSE;
}
//
// Verify the file is an archive
//
if (memcmp(MappedBase, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE)) {
ErrMsg("MapViewImplib IMAGE_ARCHIVE_START_SIZE invalid(%s)\n", LibName);
return FALSE;
}
VirtualOffset = MappedBase + IMAGE_ARCHIVE_START_SIZE;
ArchiveMemberHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER) VirtualOffset;
if (sscanf((char *) ArchiveMemberHeader->Size, "%ld", &MemberSize) != 1) {
ErrMsg("MapViewImplib ArchiveMemberHeader->Size '%s' corrupt\n", (char *) ArchiveMemberHeader->Size);
return FALSE;
}
//
// Verify first special linker member exists (name == "\\")
//
if (memcmp(ArchiveMemberHeader->Name, IMAGE_ARCHIVE_LINKER_MEMBER, sizeof(ArchiveMemberHeader->Name))) {
ErrMsg("MapViewImplib first special linker member missing (%s)\n", LibName);
return FALSE;
}
//
// First Linker Member format (Big endian!)
// NumberOfSymbols, 4 bytes
// Offsets, 4 bytes * NumSymbols
// StringTable NumSymbols == NumStrings
//
VirtualOffset += sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
ImplibNumSymbols = EndianSwitch((PULONG)VirtualOffset);
VirtualOffset += 4;
ImplibSymbolMembers = (PULONG)VirtualOffset;
VirtualOffset += ImplibNumSymbols * sizeof(ULONG);
ImplibSymbolNames = (PCHAR)VirtualOffset;
ImplibMappedBase = MappedBase;
fprintf(stdout, "Implib: %s Base %p\n", LibName, ImplibMappedBase);
return TRUE;
}
BOOL
ExtractMember(
ULONG MemberOffset,
PULONG Ordinal,
BOOLEAN *Data
)
{
PIMAGE_FILE_HEADER ImageFileHeader;
PBYTE VirtualOffset;
BOOL Idata5Found, TextFound;
VirtualOffset = (PBYTE)ImplibMappedBase + MemberOffset;
VirtualOffset += sizeof(IMAGE_ARCHIVE_MEMBER_HEADER);
ImageFileHeader = (PIMAGE_FILE_HEADER) VirtualOffset;
*Ordinal = 0;
Idata5Found = FALSE;
TextFound = FALSE;
if (ImageFileHeader->Machine == 0 &&
ImageFileHeader->NumberOfSections == 0xffff) {
//
// VC6 format import lib found.
//
PVC6_IMAGE_IMPORT_HEADER pHdr;
pHdr = (PVC6_IMAGE_IMPORT_HEADER)ImageFileHeader;
if (pHdr->NameType == IMPORT_ORDINAL) {
//
// pHdr->wOrdinal specifies the ordinal for this import.
//
*Ordinal = 0x80000000 | (ULONG)pHdr->Ordinal;
}
if (pHdr->Type == IMPORT_DATA) {
//
// This is a data import
//
*Data = TRUE;
}
Idata5Found = TRUE;
} else {
//
// Pre-VC6 import lib.
//
ULONG NumSections;
ULONG UNALIGNED *RawDataPointer;
IMAGE_SECTION_HEADER UNALIGNED *ImageSectionHeader;
NumSections = ImageFileHeader->NumberOfSections;
//
// Carefull, librarian doesn't align the Image section header according
// to normal rules for images.
//
VirtualOffset += sizeof(IMAGE_FILE_HEADER) + ImageFileHeader->SizeOfOptionalHeader;
ImageSectionHeader = (IMAGE_SECTION_HEADER UNALIGNED *)VirtualOffset;
while (NumSections--) {
//
// Implib provides .idata5, and .idata4 (duplicate) which
// contains the ordinal number with the hi bit set if it
// was specified in the module definition file. Otherwise
// the ordinal number is not specified in the implib.
//
if (!Idata5Found &&
!strncmp(ImageSectionHeader->Name, szIDATA5, sizeof(szIDATA5)-1)) {
//
// Carefull, librarian doesn't align the begining of raw data
// according to normal rules for images.
//
RawDataPointer = (ULONG UNALIGNED *)((PBYTE)ImageFileHeader + ImageSectionHeader->PointerToRawData);
if (*RawDataPointer & 0x80000000) {
*Ordinal = *RawDataPointer;
}
Idata5Found = TRUE;
} else if (!TextFound &&
!strncmp(ImageSectionHeader->Name, szTEXT, sizeof(szTEXT)-1)) {
TextFound = TRUE;
}
ImageSectionHeader++;
}
*Data = !TextFound; // if no text section, must be data export
}
return Idata5Found;
}
BOOL
InitExportDebug(
PEXPORTSDEBUG ExportDebug,
char *SymbolName,
ULONG SymbolMember
)
{
ULONG_PTR Forward;
ULONG OrdinalIndex;
char *pch = SymbolName; // we assume __implib_ prefix not present
//
// C fn begins with "_"
// C++ fn begins with "?"
// Data export begins with "??_C" in real symbols,
// but in implib looks a C function
//
if (*pch == '?') {
ExportDebug->CplusDecoration = pch;
DbgPrintf("C++ export %s\n", SymbolName);
}
else {
ExportDebug->CplusDecoration = NULL;
}
//
// Copy out the ExportName.
//
if (*pch == '_' || *pch == '?') {
pch++; // skip lead char (underscor, qmark)
}
strcpy(ExportDebug->ExportName, pch);
pch = strchr(ExportDebug->ExportName, '@');
if (SymbolName[0] == '?' && SymbolName[1] == '?') {
//
// Found a "real" C++ name: a mangled version of
// "classname::membername". Use the fully-mangled function name,
// instead of the name with the leading '?' stripped, and don't
// truncate after the '@'.
//
strcpy(ExportDebug->ExportName, SymbolName);
pch = NULL;
}
if (pch && ExportDebug->CplusDecoration && pch[1] != '@') {
//
// This export is '?membername@classname@@...'. Don't truncate!
//
strcpy(ExportDebug->ExportName, SymbolName);
pch = NULL;
}
if (pch && !bNoFuzzyLogic) { // truncate the symbol from ExportName
*pch = '\0';
}
//
// Get the decoration, for synthetic args
// cdecl has no decoration
// stdcall has total arg size
//
if (pch && !ExportDebug->CplusDecoration) {
ExportDebug->ArgsSize = strtol(pch + 1, NULL, 10);
}
else {
ExportDebug->ArgsSize = -1;
}
//
// Fetch the ordinal from the implib. In an Implib the ordinal
// only appears if an ordinal is specifed in the def file.
//
if (!ExtractMember(SymbolMember, &ExportDebug->Ordinal, &ExportDebug->Data)) {
ErrMsg("InitExportDebug: %s Member not found\n", SymbolName);
return FALSE;
}
if (ExportDebug->Data) {
DbgPrintf("DATA export %s\n", SymbolName);
}
//
// If we don't yet have an ordinal, search the ExportNameTable
// for the Ordinal number. Note that Ordinals which *must* appear
// in generated def files have the hi-bit set!
//
if (!ExportDebug->Ordinal) {
ExportDebug->Ordinal = DllOrdinalByName(ExportDebug->ExportName);
if (!ExportDebug->Ordinal) {
ErrMsg("InitExportDebug: %s Ordinal not found\n", SymbolName);
return FALSE;
}
}
//
// Look up function using ordinal as index to function table.
//
OrdinalIndex = IMPORDINAL(ExportDebug->Ordinal) - DllExportDir->Base;
ExportDebug->Function = *(DllFunctions + OrdinalIndex);
//
// Check for references forwarded externally, we only need
// external forwards which are really internal forwards.
//
// e.g rpcrt4.dll has following def file entries:
//
// I_RpcBindingInqDynamicEndpoint=RPCRT4.I_RpcBindingInqDynamicEndpointW
// I_RpcBindingInqDynamicEndpointW
//
// Our thunk dll will use the following:
//
// I_RpcBindingInqDynamicEndpoint=I_RpcBindingInqDynamicEndpointW
// I_RpcBindingInqDynamicEndpointW
//
// It is important to strip the "rpcrt4." as this adds an extra
// loader reference to rpcrt4.dll.
//
//
ExportDebug->ExtForward = NULL;
Forward = (ULONG_PTR)DllExportDir + ExportDebug->Function - DllRvaOffset;
if (Forward > (ULONG_PTR)DllExportDir &&
Forward < (ULONG_PTR)DllExportDir + DllExportDirSize)
{
char *pSrc;
pSrc = (char *) Forward;
pch = DllBaseName;
while (*pSrc && *pSrc != '.' && toupper(*pSrc) == toupper(*pch)) {
pSrc++;
pch++;
}
if (*pSrc == *pch) {
ExportDebug->ExtForward = pSrc + 1;
}
}
DbgPrintf("%4.1d %8.1x(%4.1d) %8.1x %s(%s)\n",
ExportDebug->ArgsSize,
ExportDebug->Ordinal,
IMPORDINAL(ExportDebug->Ordinal),
ExportDebug->Function,
ExportDebug->ExportName,
ExportDebug->ExtForward ? ExportDebug->ExtForward : ""
);
return TRUE;
}
/*
* SetInternalForwards
*
*
*
*/
void
SetInternalForwards(void)
{
PLIST_ENTRY NextExport;
PEXPORTSDEBUG ExportDebug;
//
// check each export in the list for multiple exports to same function.
// For each set of internal forwards identify which export defines the api,
// and save this in the IntForward field.
//
NextExport= ExportsList.Flink;
while (NextExport != &ExportsList) {
ExportDebug = CONTAINING_RECORD(NextExport,
EXPORTSDEBUG,
ExportsDbgEntry
);
if (ExportDebug->Function &&
!ExportDebug->ExtForward &&
!ExportDebug->IntForward)
{
PLIST_ENTRY Next;
PEXPORTSDEBUG pexdbg;
PEXPORTSDEBUG KnownApi =NULL;
int ArgSize = ExportDebug->ArgsSize;
//
// Walk the rest of the list to find first duplicate function
//
Next = NextExport->Flink;
while (Next != &ExportsList) {
pexdbg = CONTAINING_RECORD(Next,
EXPORTSDEBUG,
ExportsDbgEntry
);
if (pexdbg->Function == ExportDebug->Function) {
if (pexdbg->ArgsSize >= 0) {
ArgSize = pexdbg->ArgsSize;
}
break;
}
Next = Next->Flink;
}
if (Next != &ExportsList) {
//
// We found one dup function. Temporarily link together this set
// of dup functions using the IntForward field, and determine
// the first KnownApi.
//
if (GetNameFromTypesList(FuncsList, ExportDebug->ExportName)) {
KnownApi = ExportDebug;
}
do {
pexdbg = CONTAINING_RECORD(Next,
EXPORTSDEBUG,
ExportsDbgEntry
);
if (pexdbg->Function == ExportDebug->Function) {
pexdbg->IntForward = ExportDebug->IntForward;
ExportDebug->IntForward = pexdbg;
if (pexdbg->ArgsSize >= 0) {
ArgSize = pexdbg->ArgsSize;
}
if (!KnownApi &&
GetNameFromTypesList(FuncsList, pexdbg->ExportName))
{
KnownApi = pexdbg;
}
}
Next = Next->Flink;
} while (Next != &ExportsList);
//
// If we found multiple entries, walk the temp links, and insert
// the KnownApi, which is used to define the api. If we didn't
// find a known api, use ExportDebug, and hope for the best
// (since its not known).
//
if (!KnownApi) {
KnownApi = ExportDebug;
}
pexdbg = ExportDebug;
while (pexdbg) {
PEXPORTSDEBUG NextForward;
NextForward = pexdbg->IntForward;
pexdbg->IntForward = KnownApi;
pexdbg->ArgsSize = ArgSize;
DbgPrintf("IntForward: %s to %s\n",
pexdbg->ExportName,
KnownApi->ExportName
);
pexdbg = NextForward;
}
}
}
NextExport = NextExport->Flink;
}
}
/*
* ExtractExports -
*
* reads the exports debug info from a dll,
* and builds the exports list.
*
*/
BOOL ExtractExports(void)
{
char *pch, pDst;
ULONG NumNames;
PULONG pNames;
PUSHORT pNameOrdinals;
PULONG ImpSymbolMember;
PCHAR ImpSymbolName;
EXPORTSDEBUG ExportDebug;
PEXPORTSDEBUG pexdbgForward;
char ExportName[MAX_PATH+1];
//
// For each "__imp_" in the implib, gather name, symbol and ordinal
// and determine its forward status. This will pick up all exports
// except those which are marked "PRIVATE".
//
NumNames = ImplibNumSymbols;
ImpSymbolMember = ImplibSymbolMembers;
ImpSymbolName = ImplibSymbolNames;
while (NumNames--) {
if (!strncmp(szIMPPREFIX, ImpSymbolName, sizeof(szIMPPREFIX) - 1)) {
memset(&ExportDebug, 0, sizeof(ExportDebug));
ExportDebug.ApiPlatform = API_ALL;
ExportDebug.ExportName = ExportName;
if (!InitExportDebug(&ExportDebug,
ImpSymbolName + sizeof(szIMPPREFIX) - 1,
EndianSwitch(ImpSymbolMember)
))
{
return FALSE;
}
if (!AddToExportsList(&ExportDebug)) {
return FALSE;
}
}
ImpSymbolMember++;
ImpSymbolName += strlen(ImpSymbolName) + 1;
}
//
// Search the Export name table for exports which haven't been added yet.
// These are "PRIVATE" exports with names. We will still be missing
// exports which are "PRIVATE NONAME", and we won't have symbolic info
// for the private named exports.
//
NumNames = DllExportDir->NumberOfNames;
pNames = DllNameTable;
pNameOrdinals = DllNameOrdinals;
while (NumNames--) {
memset(&ExportDebug, 0, sizeof(ExportDebug));
ExportDebug.Ordinal = *pNameOrdinals + DllExportDir->Base;
ExportDebug.Ordinal |= 0x80000000;
ExportDebug.Function = *(DllFunctions + *pNameOrdinals);
ExportDebug.ExportName = (char *)((ULONG_PTR)DllExportDir + *pNames - DllRvaOffset);
ExportDebug.ApiPlatform = API_ALL;
if (!FindInExportsList(ExportDebug.ExportName)) {
ULONG_PTR Forward;
char *pch;
//
// Check for references forwarded externally, we only need
// external forwards which are really internal forwards.
//
ExportDebug.ExtForward = NULL;
Forward = (ULONG_PTR)DllExportDir + ExportDebug.Function - DllRvaOffset;
if (Forward > (ULONG_PTR)DllExportDir &&
Forward < (ULONG_PTR)DllExportDir + DllExportDirSize)
{
char *pSrc;
pSrc = (char *)Forward;
pch = DllBaseName;
while (*pSrc && *pSrc != '.' && *pSrc == *pch) {
pSrc++;
pch++;
}
if (*pSrc == '.' && *pSrc == *pch) {
ExportDebug.ExtForward = pSrc + 1;
}
}
//
// Check for decorations embedded in the exportname
//
pch = strchr(ExportDebug.ExportName, '@');
if (pch++ && *pch != '@') {
ExportDebug.ArgsSize = strtol(pch, NULL, 10);
}
else {
ExportDebug.ArgsSize = -1;
}
ExportDebug.PrivateNamed = TRUE;
DbgPrintf("Private Named Export: %4.1d %8.1x(%4.1d) %8.1x %s(%s)\n",
ExportDebug.ArgsSize,
ExportDebug.Ordinal,
IMPORDINAL(ExportDebug.Ordinal),
ExportDebug.Function,
ExportDebug.ExportName,
ExportDebug.ExtForward ? ExportDebug.ExtForward : ""
);
if (!AddToExportsList(&ExportDebug)) {
return FALSE;
}
}
// advance to next name\ordinal
pNames++;
pNameOrdinals++;
}
return TRUE;
}
/*
ExtractServicesTab-
Used as a replacement to ExtractXpt. Extracts file list from a services.tab
file as used in the ntos project.
*/
void ExtractServicesTab(char *pch) {
FILE *fp;
char pTemp;
EXPORTSDEBUG ExportDebug;
char Line[MAX_PATH];
char ExportName[MAX_PATH];
char *ApiName;
char TempBuffer[MAX_PATH];
char *Prepend;
char *FileName;
size_t len, PrependLen;
//extract filename and optional prepend name
FileName = pch;
while(*pch != ':' && *pch != '\0')
pch++;
pTemp = *pch;
*pch = '\0';
if (pTemp == ':') {
pch++;
Prepend = pch;
while(*pch != '\0') {
pch++;
}
PrependLen = pch-Prepend;
}
else {
Prepend = pch;
PrependLen = 0;
}
if (PrependLen > MAX_PATH - 1) {
ExitErrMsg(FALSE, "ExSt: Text to prepend to functions names is too long\n");
}
memcpy(ExportName, Prepend, PrependLen);
DbgPrintf("ExST: %s,%s\n", FileName, Prepend);
fp = fopen(FileName, "r");
if (!fp) {
ExitErrMsg(TRUE, "ExST: fopen(%s) failed\n", FileName);
}
if (fseek(fp, 0, SEEK_SET)) {
ExitErrMsg(TRUE, "ExST: fseek to 0 failed\n");
}
if (!fgets(Line, sizeof(Line) - 1, fp)) {
if (ferror(fp)) {
ExitErrMsg(FALSE, "ExST: Failed to get Defs from %s\n", FileName);
} else if (feof(fp)) {
ExitErrMsg(FALSE, "ExST: Premature EOF %s\n", FileName);
}
}
do {
// skip leading spaces
pch = Line;
while (*pch && isspace(*pch)) {
pch++;
}
if (*pch == '\0')
continue;
// Grab the function name
ApiName = pch;
while(*pch != ',' && *pch != '\0')
pch++;
len = pch - ApiName;
if (len + PrependLen + 1 > sizeof(ExportName)) {
ErrMsg("ExST: ExportName Buffer overflow\n");
}
//Copy everything over
memcpy(ExportName + PrependLen, ApiName, len);
ExportName[PrependLen + len] = '\0';
if (FindInExportsList(ExportName)) {
//
// Name is already in the Exports list. Ignore the second
// one.
//
DbgPrintf("Warning: API %s was listed more than once in the services.tab. Ignoring subsequent copies.\n", ExportName);
continue;
}
memset(&ExportDebug, 0, sizeof(ExportDebug));
ExportDebug.ExportName = ExportName;
ExportDebug.MethodNumber = 3;
ExportDebug.ApiPlatform = API_ALL;
ExportDebug.Ordinal = 0;
ExportDebug.ArgsSize = -1;
if (!AddToExportsList(&ExportDebug)) {
ExitErrMsg(FALSE, "ExST: Invalid Line %s\n", Line);
}
} while (fgets(Line, sizeof(Line) - 1, fp));
if (!feof(fp) && ferror(fp)) {
ExitErrMsg(FALSE, "ExST: File Read error: %s\n", FileName);
}
fclose(fp);
return;
}
/*
* ExtractXpt-
*
* reads the exports from a ".xpt" file and builds the exports list.
* An ".xpt" file is simply a list of all of the exports.
*
*/
BOOL ExtractXpt(char *XptListName, char *DllName)
{
FILE *fp=NULL;
BOOL bRet = FALSE;
char *pch;
char *pSrc=NULL;
EXPORTSDEBUG ExportDebug;
ULONG MethodNumber = 3;
char Line[MAX_PATH];
char ExportName[MAX_PATH];
char ApiName[MAX_PATH];
char Platform[MAX_PATH];
BYTE ApiPlatform;
size_t len;
DbgPrintf("ExXpt: %s\n", XptListName);
fp = fopen(XptListName, "r");
if (!fp) {
ErrMsg("ExXpt: fopen(%s) failed\n", XptListName);
goto ExSrcExit;
}
if (fseek(fp, 0, SEEK_SET)) {
ErrMsg("ExXpt: fseek failed.\n");
goto ExSrcExit;
}
if (!fgets(Line, sizeof(Line) - 1, fp)) {
if (ferror(fp)) {
ErrMsg("ExXpt: Failed to get Defs from %s\n", XptListName);
goto ExSrcExit;
} else if (feof(fp)) {
ErrMsg("ExXpt: Premature EOF %s\n", XptListName);
goto ExSrcExit;
}
}
do {
// skip leading spaces
pSrc = Line;
while (*pSrc && isspace(*pSrc)) {
pSrc++;
}
if (!*pSrc) {
// line was blank. Reset OLE method stuff for start of new
// interface then get the next line.
MethodNumber = 3;
continue;
}
if (*pSrc == ';') {
// line starts with comment. If the comment indicates the
// ole method number, grab that, then ignore the rest of the line.
pSrc++;
if (*pSrc++ == '*') {
MethodNumber = atoi(pSrc);
}
continue;
}
// Grab the exported function name
len = CopyToken(ApiName, pSrc, sizeof(ApiName)-1);
if (len >= sizeof(ApiName) -1) {
ErrMsg("ExXpt: ExportName Buffer overflow\n");
}
pSrc += len;
if (FindInExportsList(ApiName)) {
//
// Name is already in the Exports list. Ignore the second
// one.
//
DbgPrintf("Warning: API %s was listed more than once in the .xpt. Ignoring subsequent copies.\n", ApiName);
continue;
}
// skip over any whitespace after the export name
while (*pSrc && isspace(*pSrc)) {
pSrc++;
}
if (*pSrc == '\0' || *pSrc == ';') {
// nothing else interresting on the line. This API is supported
// on all platoforms.
ApiPlatform = API_ALL;
} else {
// next non-whitespace is not a comment. This API has an explicit
// list of supported platforms.
ApiPlatform = API_NONE;
do {
len = CopyToken(Platform, pSrc, sizeof(Platform)-1);
if (_stricmp(Platform, "win95") == 0) {
ApiPlatform |= API_WIN95;
} else if (_stricmp(Platform, "win98") == 0) {
ApiPlatform |= API_WIN98;
} else if (_stricmp(Platform, "nt4") == 0) {
ApiPlatform |= API_NT4;
} else if (_stricmp(Platform, "nt5") == 0) {
ApiPlatform |= API_NT5;
} else if (_stricmp(Platform, "ntx") == 0) {
ApiPlatform |= API_NTx;
} else if (_stricmp(Platform, "win9x") == 0) {
ApiPlatform |= API_WIN9x;
} else {
ExitErrMsg(FALSE, "Error: %s(%d) Unknown platform name '%s'.\n", TemplateFileName, TemplateLine, Platform);
}
pSrc += len;
while (*pSrc && isspace(*pSrc)) {
pSrc++;
}
} while (*pSrc && *pSrc != ';');
DbgPrintf("API %s has Platform %x\n", ExportName, ApiPlatform);
}
memset(&ExportDebug, 0, sizeof(ExportDebug));
ExportDebug.ExportName = ExportName;
ExportDebug.MethodNumber = MethodNumber++;
ExportDebug.ApiPlatform = ApiPlatform;
//
// Look up the export in the implib
//
if (ImplibMappedBase) {
int Len;
ULONG SymbolMember=0;
ULONG ImpNumSymbols = ImplibNumSymbols;
PULONG ImpSymbolMember = ImplibSymbolMembers;
PCHAR ImpSymbolName = ImplibSymbolNames;
while (ImpNumSymbols--) {
Len = strlen(ApiName);
pch = ImpSymbolName + 1 + Len;
if (!strncmp(ApiName, ImpSymbolName + 1, Len) &&
(!*pch || *pch == '@')) {
SymbolMember = EndianSwitch(ImpSymbolMember);
break;
}
ImpSymbolMember++;
ImpSymbolName += strlen(ImpSymbolName) + 1;
}
if (SymbolMember) {
if (!InitExportDebug(&ExportDebug, ImpSymbolName, SymbolMember)) {
goto ExSrcExit;
}
} else {
//
// The export was not found in the implib, and for
// flexibility we don't required it to be in implib.
// fill up what we know.
//
ExportDebug.Ordinal = 0;
ExportDebug.ArgsSize = -1;
strcpy(ExportName, ApiName);
}
} else {
// most info is unknown!
ExportDebug.Ordinal = 0;
ExportDebug.ArgsSize = -1;
strcpy(ExportName, ApiName);
}
if (!AddToExportsList(&ExportDebug)) {
goto ExSrcExit;
}
} while (fgets(Line, sizeof(Line) - 1, fp));
if (!feof(fp) && ferror(fp)) {
ErrMsg("ExXpt: File Read error: %s\n", XptListName);
goto ExSrcExit;
}
bRet = TRUE;
ExSrcExit:
if (!bRet) {
ErrMsg("ExXpt: Invalid Line <%s>\n%s\n", pSrc, Line);
}
if (fp) {
fclose(fp);
}
return bRet;
}
BOOL AddToExportsList(PEXPORTSDEBUG pExportsDebug)
{
PEXPORTSDEBUG pexdbg;
int Len;
int SizeExportName;
SizeExportName = strlen(pExportsDebug->ExportName) + 1;
Len = sizeof(EXPORTSDEBUG) + SizeExportName + 1;
pexdbg = GenHeapAlloc(Len);
if (!pexdbg) {
ExitErrMsg(TRUE, "GenHeapAlloc(EXPORTSDEBUG)");
}
memset(pexdbg, 0, Len);
*pexdbg = *pExportsDebug;
pexdbg->ExportName = pexdbg->Buffer;
strcpy(pexdbg->ExportName, pExportsDebug->ExportName);
InitializeListHead(&pexdbg->ArgsListHead);
InsertTailList(&ExportsList, &pexdbg->ExportsDbgEntry);
return TRUE;
}
/*
* ExtractPpm. The on-disk .PPM file is opened as read-only, but
* the pages are copy-on-write to the pagefile, so genthnk
* can make changes to the in-memory version which go away
* when it exits.
*
*/
BOOL ExtractPpm(char *PpmName)
{
HANDLE hFile;
HANDLE hMapFile = NULL;
PVOID pvBaseAddress;
ULONG Version;
PVOID MappedBase;
ULONG BytesRead;
BOOL bSuccess;
NTSTATUS Status;
PCVMHEAPHEADER pHeader;
DbgPrintf("PpmName: %s\n", PpmName);
hFile = CreateFile(PpmName,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0,
NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
hFile = NULL;
ErrMsg("ExtractPpm CreateFile(%s) gle %d\n", PpmName, GetLastError());
return FALSE;
}
bSuccess = ReadFile(hFile,
&Version,
sizeof(ULONG),
&BytesRead,
NULL
);
if (!bSuccess || BytesRead != sizeof(ULONG)) {
ErrMsg("ExtractPpm ReadFile(%s) gle %d\n", PpmName, GetLastError());
return FALSE;
}
if (Version != VM_TOOL_VERSION) {
ErrMsg("ExtractPpm: .PPM version %x does not match genthnk version %x\n",
Version, VM_TOOL_VERSION);
return FALSE;
}
#if _WIN64
// Read and ignore the 4-byte padding between the Version and the Base
bSuccess = ReadFile(hFile,
&Version,
sizeof(ULONG),
&BytesRead,
NULL
);
if (!bSuccess || BytesRead != sizeof(ULONG)) {
ErrMsg("ExtractPpm ReadFile(%s) gle %d\n", PpmName, GetLastError());
return FALSE;
}
#endif
bSuccess = ReadFile(hFile,
&pvBaseAddress,
sizeof(ULONG_PTR),
&BytesRead,
NULL
);
if (!bSuccess || BytesRead != sizeof(ULONG_PTR)) {
ErrMsg("ExtractPpm ReadFile(%s) gle %d\n", PpmName, GetLastError());
return FALSE;
}
hMapFile = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0,NULL);
if (!hMapFile) {
ErrMsg("ExtractPpm CreateFileMapping(%s) gle %d\n", PpmName, GetLastError());
return FALSE;
}
MappedBase = MapViewOfFileEx(hMapFile, FILE_MAP_COPY, 0, 0, 0, pvBaseAddress);
if (!MappedBase || MappedBase != pvBaseAddress) {
ErrMsg("ExtractPpm MapViewOfFile(%s) gle %d\n", PpmName, GetLastError());
return FALSE;
}
pHeader = (PCVMHEAPHEADER)pvBaseAddress;
FuncsList = &pHeader->FuncsList;
StructsList = &pHeader->StructsList;
TypeDefsList = &pHeader->TypeDefsList;
NIL = &pHeader->NIL;
// This must be done after NIL is initialized.
RBInitTree(&FakeFuncsList);
return TRUE;
}
void
HandlePreprocessorDirective(
char *p
)
{
ExitErrMsg(FALSE, "Preprocessor directives not allowed: '%s'\n", p);
}
char *
LexMacroArgs(
char *pch
)
{
BOOL fLexDone;
char *pchNew;
ResetLexer();
pchNew = LexOneLine(pch, FALSE, &fLexDone);
CurrentTokenIndex = 0;
if (fLexDone) {
return pchNew;
} else {
return pch;
}
}
BOOLEAN
ExpandMacro(
char *MacroName,
PCGENSTATE pCGenState,
char **ppIn,
char *OutBuffer,
SIZE_T MaxLen,
SIZE_T *BytesReturned
)
/*++
Routine Description:
Expands an @MacroName(arg1, arg2, ...).
Arguments:
MacroName - name of macro to expand
pCGenState - current code-gen state
ppIn - pointer to pointer to character following '@MacroName'
Return Value:
TRUE if macro expanded OK, FALSE if not. *ppIn will be updated to
point to the character following the end of the macro.
--*/
{
PTEMPLES pMacroTemple;
PLIST_ENTRY NextMacro;
char *pIn;
char *pArg;
PMACROARGSLIST NewMacroArgsList;
int ArgCount;
int ParenDepth;
NextMacro = MacroList.Flink;
while (NextMacro != &MacroList) {
pMacroTemple = CONTAINING_RECORD(NextMacro, TEMPLES, TempleEntry);
if (strcmp(MacroName, pMacroTemple->Name) == 0) {
//
// Found a macro by that name
//
break;
}
NextMacro = NextMacro->Flink;
}
if (NextMacro == &MacroList) {
//
// No macro by that name.
//
return FALSE;
}
pIn = *ppIn;
ArgCount = pMacroTemple->IndLevel;
NewMacroArgsList = GenHeapAlloc(sizeof(MACROARGSLIST) + sizeof(LPSTR) * ArgCount);
if (!NewMacroArgsList) {
ExitErrMsg(TRUE, "ExpandMacro out of memory");
}
NewMacroArgsList->NumArgs = ArgCount;
if (!ArgCount) {
//
// This macro doesn't expect arguments
//
} else {
//
//
// This macro expects arguments. Parse the arguments.
//
pIn = ParseMacroArgs(pIn, 0, &NewMacroArgsList);
if (NewMacroArgsList->NumArgs != ArgCount) {
ExitErrMsg(FALSE, "Macro %s expects %d arguments\n", MacroName, ArgCount);
}
}
// swap out the currently active macro (if any) and swap in the new macro
MacroStack[MacroStackTop++] = pCGenState->pMacroArgsList;
pCGenState->pMacroArgsList = NewMacroArgsList;
// generate code for the Begin=/End= section of the macro
if (!pMacroTemple->CodeBurst[BeginCBI]) {
ExitErrMsg(FALSE, "%s(%d) Macro %s has no Begin= section: %s\n", TemplateFileName, TemplateLine, MacroName, *ppIn);
}
CGenerateEx(pMacroTemple->CodeBurst[BeginCBI], pCGenState, OutBuffer, MaxLen, BytesReturned);
// swap the previously active macro back in
pCGenState->pMacroArgsList = MacroStack[--MacroStackTop];
FreeMacroArgsList(NewMacroArgsList);
*ppIn = pIn;
return TRUE;
}
void
WriteBoolean (
char *pSrc,
BOOL Value
)
{
if (pSrc){
if ( Value ){
*pSrc++ = '1';
}
else{
*pSrc++ = '0';
}
*pSrc = '\0';
}
}
char *
ExtractBoolean (
char *expression,
BOOLEAN *result
)
{
char thischar =*expression;
*result = FALSE;
if ( thischar != '\0') {
char nextchar =*(expression+1);
if ( nextchar != '\0' && nextchar != ')' && nextchar != ',' ) {
ExitErrMsg(FALSE,"Invalid Expression");
return expression;
}
}
if (thischar == '0') {
*result = FALSE;
return expression+1;
}
else if (thischar == '1') {
*result = TRUE;
return expression+1;
}
else{
ExitErrMsg(FALSE,"Invalid Expression");
return expression;
}
}
char *
ExtractBoolean1(
char *pSrc,
PCGENSTATE pCGenState,
BOOLEAN *result
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
BOOLEAN TempResult = FALSE;
char *pExpression;
char *pch, *pch2;
char Buffer[MAX_PATH];
SIZE_T BytesReturned;
*result = FALSE;
pch = SkipSubExpression(pSrc, &pExpression);
if (pSrc == pch) {
return pSrc;
}
pSrc = pch;
if (pExpression) {
CGenerateEx(pExpression, pCGenState, Buffer, MAX_PATH, &BytesReturned);
ExtractBoolean ( Buffer, result );
GenHeapFree(pExpression);
}
return pSrc;
}
char *
ExtractBoolean2(
char *pSrc,
PCGENSTATE pCGenState,
BOOLEAN *result1,
BOOLEAN *result2
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
char *pExpression;
char *pch, *pch2;
char Buffer[MAX_PATH];
SIZE_T BytesReturned;
*result1 = FALSE;
*result2 = FALSE;
pch = SkipSubExpression(pSrc, &pExpression);
if (pSrc == pch) {
return pSrc;
}
pSrc = pch;
if (pExpression) {
CGenerateEx(pExpression, pCGenState, Buffer, MAX_PATH, &BytesReturned);
pch = Buffer;
pch = ExtractBoolean ( Buffer, result1 );
if ( *pch == ',') {
pch++;
}
else {
ExitErrMsg(FALSE,"Invalid Expression");
}
ExtractBoolean ( pch, result2 );
GenHeapFree(pExpression);
}
return pSrc;
}