/*++ Copyright (c) 1997-2000 Microsoft Corporation Module Name: tracewpp.c Abstract: Parameter processing and main entry point for tracewpp.exe Author: Gor Nishanov (gorn) 03-Apr-1999 Revision History: gorn 03-Apr-1999 -- hacked together to prove that this can work GorN: 29-Sep-2000 - do not scan files that didn't change GorN: 29-Sep-2000 - support -notimechk -nohashchk -dll switches GorN: 29-Sep-2000 - add support for KdPrintEx((level,comp,msg,...)) like functions GorN: 09-Oct-2000 - fix hashing; added NULL arg GorN: 07-Mar-2001 - add arglimit option ToDo: all Clean it up parseConfigCheck for premature termination Ex: CUSTOM_TYPE(x, ItemListLong(dfdf)) cool Automatic fill of the arguments if ... nice better error chk types to mof it stinks to generate long enums multiple times later guidless bug check for types with dup names bug tpl: check for unterminated keyword later detect WPP_CLEANUP -- complain print in macros what to do about prints in macro? cmdline get the flags from the env variable !!! Don't assume that whatever is not recognized is func bug updated CRC computations to properly work with consts bug enum doesn't work bug %10!..! doesnt' work bug %% is not handled mess rename hidden => visible mess remove ugly MSGTYPBASE. Make FmtStr 0 based mess let message share some of the func field handlers traceprt think how to make the level indenting ezparse report unmatched end_wpp now get cmdline options from a file or env.var later handle "str" STRMACRO "another string" as a MSG arg strange output ..\logsup.c(4180) : error : Unterminated Format SpecifierHere is the signature: (0) ..\logsup.c(4180) : error : Extra argument. Only 0 are specified in the string why we didn't catch the error CsDbgPrint(LOG_NOISE, ("[FM] FmpSetGroupEnumOwner: Group %1!ws! not found\n")); CsDbgPrint(LOG_UNUSUAL, ( "[NMJOIN] Cannot add node '%1!ws!' to the cluster because " "no slots are available in the node table.\n" )); printf("Port no in network order %1!port!, regular order %1!u!, 0x0102); NetDeviceTrace( NETDEV_DBG_EXIT | NETDEV_DBG_INFO, "ClientMdlSetup Client[%10!d!], RCB[%11!d!]: " "Exit w/ Func 0x%12!04X!, Send 0x%14!04X!, Recv 0x%15!04X!", deviceExtension->Ordinal, // LOGULONG RequestCB->RequestIdx, // LOGUSHORT ios->MajorFunction, // LOGUCHAR ios->MajorFunction, // LOGUCHAR sendBytes, // LOGULONG recvBytes); // LOGULONG => AV's DONE DONE DONE DONE DONE DONE DONE DONE DONE DONE later handle KdPrintEx later add "if" to templates (at least if not empty) requirement md5 later detect WPP_INIT_TRACING main Time ourselves and print how fast we are useful ignore anything but .c .cxx .cpp .c++ useful -gen{a,b,c}h.tpl -ext:.c.cxx.cpp.c++ -v verbose -q extra quiet footprint merge multiple formats together difficult? Think how to unify DoTraceMacro0 TraceLazy, etc figureout DbgPrint -odir:path trivial add "\" to -odir if needed nice scan -gen:{a.tpl}auto.c -gen:{a.tpl}*.c outstanding take plain DebugPrint format as well difficult? Add generation of by value types --*/ #define STRICT #include #include #include #include #pragma warning(disable: 4702) // unreachable code #pragma warning(disable: 4786) #pragma warning(disable: 4503) // decorated length #pragma warning(disable: 4512) // cannot generate assignment #pragma warning(disable: 4100) // '_P' : unreferenced formal parameter #pragma warning(disable: 4267) // 'return' : conversion from 'size_t' to 'int' #include #include #include #include #pragma warning(disable: 4663) #pragma warning(disable: 4018) // signed/unsigned mismatch #include //#pragma warning(default: 4018 4663) // signed/unsigned mismatch #pragma warning(default: 4100) #include #include "ezparse.h" #include "crc32.h" #include "md5.h" #include "fieldtable.h" #include "tpl.h" #define override //typedef ULONG CRC32; using namespace std; BOOL md5 = TRUE; BOOL reorder = FALSE; BOOL userMode = TRUE; BOOL noshrieks = FALSE; UINT SeparateTraceGuidPerFile = 1; INT MSGTYPBASE = 10; UINT MessageCount = 0; UINT ArgBase = 1; BOOL CheckTimestamp = TRUE; BOOL CheckHash = TRUE; BOOL IgnoreDupTypes = FALSE; int arglimit = 32; //string OutputInc ("_tracewpp.h"); //string OutputMof ("_tracewpp.mof"); string OutputMac; string OutputDir (".\\"); //string ArrayPrefix("WPP_"); string MacroPrefix("LOG"); string AllowedExtensions(".c.cxx.cpp.c++.C.CPP"); string CurrentDir; #define DEFAULT_UM_GEN_OPTION "{um-default.tpl}*.tmh" #define DEFAULT_KM_GEN_OPTION "{km-default.tpl}*.tmh" #define DEFAULT_GEN_OPTION (userMode?DEFAULT_UM_GEN_OPTION:DEFAULT_KM_GEN_OPTION) #define DEFAULT_CONFIG_NAME "defaultwpp.ini" string LOCAL_CONFIG_NAME("localwpp.ini"); string WppDefault(DEFAULT_CONFIG_NAME); vector SearchDirs; //string Revision; string LocalConfig; string ComponentName; // Checks whether string passed has an allowed extension // Lame: uses global variable AllowedExtensions BOOL AllowedExtension(const string str) { string::size_type p = str.rfind('.'), q, n; if (p == string::npos) { Unusual("File %s has no extension\n", str.c_str() ); return FALSE; } n = str.size() - p; // extension length q = AllowedExtensions.find(&str[p], 0, n); if ( (q == string::npos) || (q + n < AllowedExtensions.size() && AllowedExtensions[q + n] != '.') ) { Unusual("File %s has unrecognized extension\n", str.c_str() ); return FALSE; } return TRUE; } inline size_t fprint_str(FILE* f, const string& str) { return fwrite(str.c_str(), str.length(), 1, f ); } inline size_t fprint_str(FILE* f, LPCSTR beg, LPCSTR end) { return fwrite(beg, end - beg, 1, f ); } inline size_t fprint_str(FILE* f, const STR_PAIR& Pair) { return fwrite(Pair.beg, Pair.end - Pair.beg, 1, f ); } inline int stoi(const STR_PAIR& str, LPCSTR name) { LPCSTR p = str.beg; int sum = 0; int sgn = 1; if (p < str.end && *p == '-') { ++p; sgn = -1; } while (p < str.end) { if (!isdigit(*p)) { ReportError("%s should be a number (%s supplied)\n", name, string(str.beg, str.end).c_str() ); break; } sum = 10 * sum + (*p - '0'); ++p; } return sgn * sum; } inline unsigned char HexVal(int ch) { return (unsigned char)(isdigit(ch) ? ch - '0' : ch - 'a' + 10); } UINT Hex(LPCSTR s, int n) { UINT res = 0; while(n--) { res = res * 16 + HexVal(*s++); } return res; } CHAR HexDigit(int val) { if (val < 10) return (CHAR)(val + '0'); else return (CHAR)(val + 'a' - 10); } ULONGLONG GetFileModificationTime(const string& str) { WIN32_FIND_DATA FindData; ULONGLONG Time; HANDLE FindHandle = FindFirstFile(str.c_str(), &FindData); if (FindHandle == INVALID_HANDLE_VALUE) { return 0; } FindClose(FindHandle); CopyMemory(&Time, &FindData.ftLastWriteTime, sizeof(Time)); return Time; } // Prototypes // void DealWithCmdLineOptions(LPCSTR s); void DealWithCmdLineOptions(LPCSTR beg, LPCSTR end) { DealWithCmdLineOptions(string(beg,end).c_str() ); } struct Hasher { virtual void Init() = 0; virtual void Finalize() = 0; virtual void Hash(const void* buf, int nBytes) = 0; virtual int Size() const = 0; virtual const unsigned char * Buf() const = 0; void Hash(const std::string& str) { Hash(str.begin(), (int)str.size()); } void fromString(LPCSTR beg, LPCSTR end) { int n = min((ULONG)(end - beg)/2, Size()); unsigned char * buf = BufRW(); ZeroMemory(buf, Size()); for(int i = 0; i < n; ++i) { buf[i] = HexVal(beg[2*i]) * 16 + HexVal(beg[2*i + 1]); } } void print(FILE* out) const { int n = Size(); const UCHAR* buf = Buf(); for(int i = 0; i < n; ++i) { fprintf(out, "%x%x", buf[i] >> 4, buf[i] & 0xF); } } bool operator ==(const Hasher& b) const { return Size() == b.Size() && memcmp(Buf(), b.Buf(), Size()) == 0; } private: unsigned char* BufRW() { return (unsigned char*)Buf(); } }; class Crc32Hasher : public Hasher { ULONG Crc; public: override void Init() { Crc = (ULONG)~0; } override void Finalize() {} override void Hash(const void* buf, int nBytes) { Crc = FstubCrc32(Crc, (PVOID)buf, nBytes); } override int Size() const { return sizeof(Crc); } override const unsigned char * Buf() const { return (UCHAR*)&Crc; } }; class Md5Hasher : public Hasher { MD5_CTX Ctx; public: override void Init() { MD5Init(&Ctx); } override void Finalize() { MD5Final(&Ctx); } override void Hash(const void* buf, int nBytes) { MD5Update(&Ctx, (const unsigned char*)buf, nBytes); } virtual int Size() const { // assert(MD5DIGESTLEN == sizeof(GUID)); return MD5DIGESTLEN; // == 16 } virtual const unsigned char * Buf() const { return Ctx.digest; } }; //typedef Crc32Hasher DefaultHasher; typedef Md5Hasher DefaultHasher; void ReplaceCrOrLfWith(string& s, char ch) { for(int i = 0; i < s.size(); ++i) { if (s[i] == '\n' || s[i] == '\r') s[i] = ch; if (s[i] == '"') s[i] = '\''; } } string currentFileName(); bool Files_AddFile(const string& Name, string Path, const WIN32_FIND_DATA& FindData) ; enum { WT_MACRONAME = 0x00000001, // TypeName is actually a MacroName. Don't have to be prepended with Log Macro Prefix }; struct WppType : FieldHolder { string TypeName; string EquivType; // c-type string MacroStart; // WPP_LOGVALARG(%s, if not specified string MofType; // yeah string Extension; // something to be merged with MofType string FormatSpec; // sprintf style string Sig; int priority; int ArgConsumed; mutable BOOL Used; DWORD Flags; void hash(Hasher& hash) const {hash.Hash(TypeName);} // BUGBUG ?? Maybe we need to hash it string sig() const { return Sig; } bool isConstant() const { return EquivType.size() == 0; } WppType() {} // To make STL happy WppType(const string& a, const string&b, const string& c, const string& d, const string& e, const string& f, const string& g, int prio, int argConsumed): TypeName(a), EquivType(b), MacroStart(c), MofType(d), Extension(e), FormatSpec(f), Sig(g), priority(prio),Used(0),ArgConsumed(argConsumed) {} // WppType(LPCSTR beg, LPCSTR end):TypeName(beg, end),Used(0){} // explicit WppType(char name):TypeName(&name, &name+1),Used(0){} bool operator < (const WppType& b) const { int diff = b.priority - priority; // higher prio first if (diff < 0) return TRUE; if (diff > 0) return FALSE; return TypeName.compare(b.TypeName) < 0; } virtual BOOL Hidden(std::string) const { return !Used; } BEGIN_FIELD_TABLE(WppType, f) TEXT_FIELD(Name) fprint_str(f, TypeName); TEXT_FIELD(EquivType) fprint_str(f, EquivType); TEXT_FIELD(MacroName) { if (!(Flags & WT_MACRONAME)) fprint_str(f, MacroPrefix); fprint_str(f, TypeName); } TEXT_FIELD(MacroStart) fprintf(f, MacroStart.c_str(), EquivType.c_str()); TEXT_FIELD(MacroEnd) fprintf(f, ")"); TEXT_FIELD(MofType) fprint_str(f, MofType); TEXT_FIELD(Extension) fprint_str(f, Extension); TEXT_FIELD(FormatSpec) fprint_str(f, FormatSpec); END_FIELD_TABLE }; typedef map TYPE_SET; string SimpleValueMacroStart("WPP_LOGTYPEVAL(%s,"); string SimplePtrMacroStart("WPP_LOGTYPEPTR("); TYPE_SET TypeSet; struct Argument : FieldHolder { const WppType* Type; string Name; string OverrideName; int No; bool operator < (const Argument& b) const { return *Type < *b.Type; } Argument(){} // To make STL happy // Argument(string name, const WppType* type):Type(type),Name(name) { ReplaceCrOrLfWith(Name, ' '); } void hash(Hasher& hash) const { hash.Hash(Name); if(Type) Type->hash(hash); } BEGIN_FIELD_TABLE(Argument, f) TEXT_FIELD(No) {fprintf(f, "%d", No);} TEXT_FIELD(Name) {fprint_str(f, Name);} TEXT_FIELD(MofType) {fprint_str(f, Type->MofType); fprint_str(f,Type->Extension);} END_FIELD_TABLE }; struct Reorder : FieldHolder { string Name; vector Args; Reorder(){} // to make stl happy explicit Reorder(string name, const vector& args): Name(name) { Args.resize( args.size() ); for(int i = 0; i < args.size(); ++i) { Args[i] = args[i].No - MSGTYPBASE; } } bool operator < (const Reorder& b) const { return Name.compare(b.Name) < 0; } BEGIN_FIELD_TABLE(Reorder, f) TEXT_FIELD(Name) fprint_str(f, Name); TEXT_FIELD(Permutation) { for(int i = 0; i < Args.size(); ++i) { fprintf(f, ", a%d", Args[i]); } } TEXT_FIELD(Arguments) { fprintf(f,"MSG"); for(int i = 0; i < Args.size(); ++i) { fprintf(f, ", a%d", i); } } END_FIELD_TABLE }; set ReorderSet; string GetReorderSig(const vector& args) { string sig; if (args.size() > 256) { ReportError("Only upto 256 arguments are supported\n"); return sig; } if (args.size() <= 16) { sig.resize(args.size()); for(int i = 0; i < args.size(); ++i) { sig[i] = HexDigit(args[i].No - MSGTYPBASE); } } else { sig.resize(2 * args.size()); for(int i = 0; i < args.size(); ++i) { int val = args[i].No; sig[2 * i] = HexDigit(val >> 16); sig[2 * i + 1] = HexDigit(val & 15); } } ReorderSet.insert( Reorder(sig, args) ); return sig; } #include "parsed-string.hxx" struct TypeSig : FieldHolder { string Name; vector Types; BOOL Unsafe; TypeSig() {} // To make STL happy TypeSig(const vector& args, const string& sig, BOOL unsafe): Unsafe(unsafe) { Name.assign(sig); for(int i = 0; i < args.size(); ++i) { Types.push_back(args[i].Type); } } bool operator < (const TypeSig& b) const { return Name.compare(b.Name) < 0; } virtual BOOL Hidden(std::string str) const { if (str.size() == 0) { return FALSE; } else if (str.compare("UnsafeArgs") == 0) { return !Unsafe; } else if (str.compare("!UnsafeArgs") == 0) { return Unsafe; } else { ReportError("Unknown filter '%s'\n", str.c_str()); exit(1); } return NULL; } BEGIN_FIELD_TABLE(TypeSig, f) TEXT_FIELD(Name) fprint_str(f, Name); TEXT_FIELD(Count) fprintf(f, "%d", Name.size()); TEXT_FIELD(Arguments) { for(int i = 0; i < Types.size(); ++i) { fprintf(f,", "); fprint_str(f, Types[i]->EquivType); fprintf(f, " _a%d", i+1); } } TEXT_FIELD(LogArgs) { for(int i = 0; i < Types.size(); ++i) { fprintf(f, Types[i]->MacroStart.c_str(), Types[i]->EquivType.c_str()); fprintf(f, "_a%d) ", i+1); } } TEXT_FIELD(DeclVars) { for(int i = 0; i < Types.size(); ++i) { fprintf(f, "%s _a%d = va_arg(ap, %s); ", Types[i]->EquivType.c_str(), i+1, Types[i]->EquivType.c_str()); } } END_FIELD_TABLE }; typedef map TYPESIG_MAP; TYPESIG_MAP TypeSigMap; TypeSig* GetTypeSig(const vector& args, BOOL unsafe) { string sig; if (unsafe) { sig.assign("v"); } for(int i = 0; i < args.size(); ++i) { sig.append(args[i].Type->sig() ); } TYPESIG_MAP::iterator it = TypeSigMap.find( sig ); if ( it == TypeSigMap.end() ) { // we need to add one // return &(TypeSigMap[ sig ] = TypeSig(args, sig, unsafe)); } return &it->second; } void Fill( string pattern) { WIN32_FIND_DATA findData; HANDLE handle; handle = FindFirstFile(pattern.c_str(), &findData); if (handle == INVALID_HANDLE_VALUE) { DWORD status = GetLastError(); if (status != ERROR_FILE_NOT_FOUND) { Noise("FindFirstFile(%s): error %d\n", pattern.c_str(), GetLastError() ); } return; } string::size_type p = pattern.find_last_of(":\\"); if (p != string::npos) { pattern.resize(p+1); // to include the symbol } else { pattern.resize(0); } do { Files_AddFile(findData.cFileName, pattern, findData); } while( FindNextFile(handle, &findData) ); FindClose(handle); } struct Group : FieldHolder { UINT GrpId; vector MsgIds; string _Name; Group(){} Group(UINT id, string Name, string Msg):GrpId(id),_Name(Name) { MsgIds.push_back(Msg); } BEGIN_FIELD_TABLE(Group, f) TEXT_FIELD(GuidNo) fprintf(f, "%d", GrpId / 32); TEXT_FIELD(BitNo) fprintf(f, "%d", GrpId & 31); TEXT_FIELD(Name) fprint_str(f, _Name); TEXT_FIELD(References) { vector::const_iterator i; for(i = MsgIds.begin(); i != MsgIds.end(); ++i) { putc(' ', f); fprint_str(f, *i); } } END_FIELD_TABLE }; //void RegenerateMacroMap(); struct Prefix{ string FuncName; // string MsgPrefix; // vector Args; ParsedFormatString FmtStr; Prefix(){} Prefix(PSTR_PAIR str, UINT count); }; int inline sign(UCHAR val) { return val?1:0; } enum FuncOptions { FO_VAR_ARGS = 0x01, FO_UNSAFE = 0x02, FO_DOUBLEP = 0x04, FO_LINE_BEG = 0x08, FO_NOMACRO = 0x10, }; struct Func : FieldHolder { const Prefix *prefix, *suffix; string _name; vector Args; // all supplied args - var args vector Goo; // values for GooId, usually = GooId vector GooId; // all unrecognized args + LEV UCHAR Grp, MsgArg, Msg, Arg; UCHAR Num, Indent, MsgVal, Reserved; ULONG Options; size_t nAssumedArgs; void SetPS(const Prefix* val, const Prefix*& var, LPCSTR msg) { if (val && val->FmtStr.ArgCount > 0 && MsgArg) { ReportError("Function %s has (something,(MSG,...)) type\n" "It cannot have non-const %s\n", _name.c_str(), msg ); } var = val; } void set(ULONG flag) { Options |= flag; } ULONG is(ULONG flag) const { return Options & flag; } void SetLineBeg() { Options |= FO_LINE_BEG; } void SetVarArgs() { Options |= FO_VAR_ARGS | FO_LINE_BEG; } void SetUnsafe() { Options |= FO_UNSAFE; } void SetDoubleP() { Options |= FO_DOUBLEP; } BOOL LineBeg() const { return Options & FO_LINE_BEG; } BOOL VarArgs() const { return Options & FO_VAR_ARGS; } BOOL Unsafe() const { return Options & FO_UNSAFE; } BOOL DoubleP() const { return Options & FO_DOUBLEP; } void SetPrefix(const Prefix* pr) { SetPS(pr,prefix,"prefix"); } void SetSuffix(const Prefix* sf) { SetPS(sf,suffix,"suffix"); } virtual BOOL Hidden(std::string str) const { if (str.size() == 0) { return FALSE; } if (is(FO_NOMACRO)) return str.compare("NoMacro") != 0; else if (str.compare("MsgArgs") == 0) { return !MsgArg; } else if (str.compare("!MsgArgs") == 0) { return MsgArg; } else if (str.compare("!DoubleP && !MsgArgs") == 0) { return !(!DoubleP() && !MsgArg); } else if (str.compare("DoubleP && !MsgArgs") == 0) { return !(DoubleP() && !MsgArg); } else { ReportError("Unknown filter '%s'\n", str.c_str()); exit(1); } return NULL; } #if 0 // returns recognized argument count int count() const { return sign(Grp) + sign(Id) + sign(Msg) + sign(Arg); } #endif void printArgs(FILE* f) const { for(int i = 1; i <= Num; ++i) { if (i > 1) fprintf(f, ", "); else fprintf(f, "("); fprint_str(f, Args[i]); /* if (i == Grp) fprintf(f,"GRP"); else if (i == Id) fprintf(f,"ID"); else if (i == Msg) fprintf(f,"MSG"); else if (i == Arg) fprintf(f,"ARG"); else fprintf(f,"_unknown%d", i); */ } fprintf(f, ")"); } BEGIN_FIELD_TABLE(Func, out) TEXT_FIELD(Name) fprintf(out, "%s", _name.c_str() ); TEXT_FIELD(Arguments) {printArgs(out);} TEXT_FIELD(MSG) {fprintf(out, Msg?"MSG":"\"\"");} TEXT_FIELD(ARG) {fprintf(out, Arg?"ARG":"");} TEXT_FIELD(GRP) {fprintf(out, Grp?"GRP":"WPP_DEFAULT_GROUP_ID");} // TEXT_FIELD(ID) {fprintf(out, Id?"ID":"WPP_AUTO_ID");} TEXT_FIELD(FixedArgs) { for(int i = 0; i < Args.size(); ++i) { fprint_str(out, Args[i]); fprintf(out,", "); } } TEXT_FIELD(GooArgs) { for(int i = 0; i < GooId.size(); ++i) { if (i > 0) fprintf(out,","); fprint_str(out, GooId[i]); } } TEXT_FIELD(GooVals) { for(int i = 0; i < Goo.size(); ++i) { if (i > 0) fprintf(out,", "); fprint_str(out, Goo[i]); } } TEXT_FIELD(GooId) { for(int i = 0; i < GooId.size(); ++i) { fprintf(out,"_"); fprint_str(out, GooId[i]); } } END_FIELD_TABLE Func(){} Func(std::string Name):_name(Name),prefix(0),suffix(0), Grp(0), MsgArg(0), Msg(0), Arg(0), Num(0), Indent(0), MsgVal(0), Options(0),nAssumedArgs(0) {} }; #define GRP(x) ((x).Grp) #define MSG(x) ((x).Msg) #define ARG(x) ((x).Arg) #define NUM(x) ((x).Num) //BOOL //UpgradeFormatSpecifiers(string& str, int startCount, string* TypeSig = 0); void printTraceGuid(FILE* f, int guidno); struct Message : FieldHolder { // string Msg; string IdName; string msgval; string Indent; string reorderSig; int LineNo; ParsedFormatString FormatStr; TypeSig* typeSig; const Func* func; vector Args; vector GooActualValues; UINT id; string TypeListHost; virtual BOOL Hidden(std::string str) const { return func->Hidden(str); } void hash(Hasher& hash) const; int ArgConsumed() const ; // void ChkArgs() const; BEGIN_FIELD_TABLE(Message, f) TEXT_FIELD(Text) { FormatStr.printMofTxt(f,LineNo); } TEXT_FIELD(Indent) { if(Indent.size()) { fprintf(f, "INDENT="); fprint_str(f, Indent); } } TEXT_FIELD(MsgNo) { fprintf(f, "%d", id & 0xFFFF); } TEXT_FIELD(GuidNo) { fprintf(f, "%d", id >> 16); } TEXT_FIELD(Guid) { printTraceGuid(f, id >> 16); } TEXT_FIELD(Name) { fprint_str(f, IdName ); } TEXT_FIELD(Line) { fprintf(f, "%d", LineNo ); } TEXT_FIELD(MsgVal) { fprint_str(f, msgval ); } TEXT_FIELD(ReorderSig) { fprint_str(f, reorderSig ); } TEXT_FIELD(TypeSig) { fprint_str(f, typeSig->Name); } TEXT_FIELD(Count) { fprintf(f, "%d", FormatStr.ArgCount); } // TEXT_FIELD(CtlMsg) { ??? } // TEXT_FIELD(Enabled) ENUM_FIELD(Arguments, Args, VectorTag) TEXT_FIELD(GooPairs) { size_t k = func->nAssumedArgs; // print assumed arguments for(size_t i = 0; i < k; ++i) { fprintf(f, " "); fprint_str(f, func->GooId[i]); fprintf(f, "="); fprint_str(f, func->Goo[i]); } // print the goo we pulled out of the trace statement itself size_t n = min(func->GooId.size()-k, GooActualValues.size()); for(size_t i = 0; i < n; ++i) { fprintf(f, " "); fprint_str(f, func->GooId[i+k]); fprintf(f, "="); fprint_str(f, GooActualValues[i]); } } TEXT_FIELD(FixedArgs) { for(int i = 0; i < func->Args.size(); ++i) { fprint_str(f, func->Args[i]); fprintf(f, ", "); } } TEXT_FIELD(GooVals) { for(int i = 0; i < func->Goo.size(); ++i) { if (i > 0) fprintf(f,", "); fprint_str(f, func->Goo[i]); } } TEXT_FIELD(GooArgs) { for(int i = 0; i < func->GooId.size(); ++i) { if (i > 0) fprintf(f,","); fprint_str(f, func->GooId[i]); } } TEXT_FIELD(GooId) { for(int i = 0; i < func->GooId.size(); ++i) { fprintf(f,"_"); fprint_str(f, func->GooId[i]); } } TEXT_FIELD(MacroExprs) { for(int i = 0; i < Args.size(); ++i) { if (Args[i].OverrideName.size() > 0) { fprintf(f,","); fprint_str(f, Args[i].OverrideName); } else { fprintf(f, ",a%d", Args[i].No); } } } TEXT_FIELD(MacroArgs) { fprintf(f,"MSG"); for(int i = 0; i < Args.size(); ++i) { if (Args[i].OverrideName.size() > 0) { // fprint_str(f, Args[i].OverrideName); } else { // if (i != 0) fprintf(f,","); fprintf(f, ",a%d", i + MSGTYPBASE); } } } END_FIELD_TABLE Message(){} Message( const string& idTxt, const string&, const vector&, UINT msgid, int lineno, const ParsedFormatString& fmtStr, const Func& aFunc ) :IdName(idTxt), id(msgid), LineNo(lineno), FormatStr(fmtStr),func(&aFunc) { Args.resize(FormatStr.ArgCount, Argument("",0) ); for(int i = 0; i < FormatStr.Items.size(); ++i) { int no = FormatStr.Items[i].no; if (no > 0) { Args[no-1] = Argument (FormatStr.Items[i].expr, FormatStr.Items[i].type); Args[no-1].OverrideName = FormatStr.Items[i].argName; Args[no-1].No = no-1 + MSGTYPBASE; } } if (reorder) { sort(Args.begin(), Args.end()); } for (int j = 0; j < FormatStr.Items.size(); ++j) { int& no = FormatStr.Items[j].no; if (no > 0) { // find new msg no for that for(int k = 0; k < Args.size(); ++k) { if (Args[k].No == no-1 + MSGTYPBASE) { no = MSGTYPBASE + k; break; } } // Args[no-1].OverrideName = FormatStr.Items[i].argName; } } typeSig = GetTypeSig(Args, func->Unsafe()); if (func->MsgArg) { reorderSig = GetReorderSig(Args); } // UpgradeFormatSpecifiers(Msg, 10, (typeSig.size())?0:&TypeSig); // ChkArgs(); } }; struct File : FieldHolder { string _CanonicalName; // lower case, bad chars => _ string _Path; string _UppercaseName; // uppercase canonical string _Name; string _BaseName; // no extension ULONGLONG ModificationTime; // // Since the file is a member of the set type // fields that don't affect set membership should be mutables // mutable vector Msgs; mutable set IdsFound; BEGIN_FIELD_TABLE(File, out) TEXT_FIELD(Name) fprint_str(out, _Name ); TEXT_FIELD(Path) fprint_str(out, _Path ); TEXT_FIELD(CanonicalName) fprint_str(out, _CanonicalName ); TEXT_FIELD(UppercaseName) fprint_str(out, _UppercaseName ); ENUM_FIELD(Messages, Msgs, VectorPtrTag) END_FIELD_TABLE File(){} // to make STL and compiler happy string FullFileName() const { string Tmp(_Path); Tmp.append(_Name); return Tmp; } File(const string& FileName, const string& Path, const WIN32_FIND_DATA& FindData) :_Name(FileName), _Path(Path) { CopyMemory(&ModificationTime, &FindData.ftLastWriteTime, sizeof(ModificationTime)); // Canonicalize FileName // i.e. make it suitable to be a DEFINE name // // Cut the path out. Replace all non-alphanumeric symbols // with an underscore. string::size_type pos = _Name.rfind('\\'); if (pos == string::npos) { // No back slash _CanonicalName.assign(_Name); } else { // Get only the name part _CanonicalName.assign(_Name.begin() + pos, _Name.end()); } // strip extension for a base name string::size_type ext = _CanonicalName.rfind('.'); if (ext != string::npos) { // there was a "." _BaseName.assign(_CanonicalName.begin(), _CanonicalName.begin() + ext); } else { _BaseName.assign(_CanonicalName); } // Can't have a digit in the first position // Let's prepend it with an underscore { char ch = _CanonicalName[0]; if ( ch >= '0' && ch <= '9' ) { _CanonicalName.insert(0, '_'); } } _UppercaseName.assign( _CanonicalName ); for(UINT i = 0; i < _CanonicalName.size(); ++i) { char ch = _CanonicalName[i]; if ( (ch == '_') || ((ch >= 'A') && (ch <= 'Z')) || ((ch >= '0') && (ch <= '9')) ) { // Good Character. Do nothing } else if ( (ch >= 'a') && (ch <= 'z') ) { _UppercaseName[i] = static_cast(ch - 'a' + 'A'); } else { _CanonicalName[i] = '_'; _UppercaseName[i] = '_'; } } } bool operator < (const File& b) const { return _CanonicalName.compare(b._CanonicalName) < 0; } }; int Message::ArgConsumed() const { vector::const_iterator i = Args.begin(); int sum = 0; for(;i != Args.end(); ++i) { sum += i->Type->ArgConsumed; } return sum; } void Message::hash(Hasher& hash) const { vector::const_iterator i = Args.begin(); for(;i != Args.end(); ++i) { i->hash(hash); } hash.Hash(&id, sizeof(id)); hash.Hash(IdName); hash.Hash(FormatStr.HostString); } typedef map TYPE_MAP; typedef map MSG_MAP; //typedef map MACRO_MAP; typedef map FUNC_MAP; typedef map GROUP_MAP; typedef vector< Prefix > PREFIX_VECTOR; typedef set FILES; FILES::iterator CurrentFile; string CurrentTpl; string currentFileName() { return CurrentFile->_Name; } void MsgMapHash( const MSG_MAP& msgmap, Hasher& hash ) { MSG_MAP::iterator i = msgmap.begin(); for(;i != msgmap.end(); ++i) { i->second.hash(hash); } } void expand(IN OUT string& str, const string& id); BOOL parseMsg( IN LPCSTR beg, IN LPCSTR end, IN OUT string& str, OUT LPCSTR* strend = 0 ) { LPCSTR p = beg; for(;;) { if (*p == '_' || isalpha(*p)) { const char * id = p; for(;;) { if (++p == end) { expand(str, string(id,p)); goto done; } if (*p == '_' || isalpha(*p) || isdigit(*p)) continue; break; } expand(str, string(id,p)); } if (*p == ',') goto done; if (*p == '"') { const char * run = ++p; for(;;) { if (p == end) goto unterminated; if (*p == '"' && p[-1] != '\\') break; ++p; } str.append(run,p); } if (++p == end) break; } done: if (str.size() == 0) { ReportError("parsing %s. Cannot find format string\n", string(beg,end).c_str() ); return FALSE; } // eat whitespace at the end while (str.size() > 0 && isspace( str.end()[-1]) ) { str.resize(str.size()-1); } // get rid of pesky trailing \n if (str.size() >= 2 && str.end()[-1] == 'n' && str.end()[-2] == '\\') { str.resize(str.size()-2); } Flood("msg: \"%s\".\n", str.c_str() ); if (strend) { *strend = p; } return TRUE; unterminated: ReportError("Unterminated string constant\n"); return FALSE; } BOOL parseArgs( IN LPCSTR beg, IN LPCSTR end, IN OUT vector& args ); #define isvar(x) ( isalnum(x) || (x == '_') ) /* ArgType::ArgType( IN const WppType* wppType):Type(0),TypevString(wppType->FormatSpec), NativeType(wppType),Used(FALSE) { MofType = wppType->MofType; ExtendedType = wppType->Extension; } */ Prefix::Prefix( IN PSTR_PAIR str, IN UINT count):FuncName(str[1].beg, str[1].end) { vector ArgNames; if (count > 2) { string msg; if (str[2].beg < str[2].end && str[2].beg[0] == '"') parseMsg(str[2].beg, str[2].end, msg); else msg.assign(str[2].beg, str[2].end); FmtStr.init( msg ); } if (count > 3) { count -= 3; str += 2; while (count-- > 0) { ++str; ArgNames.push_back( string(str->beg,str->end) ); } } // check that sizes match // if (ArgNames.size() > FmtStr.ArgCount ) { ReportError("Prefix: Extra argument. Only %d are specified in the string\n", FmtStr.ArgCount); exit(1); } if (ArgNames.size() < FmtStr.ArgCount ) { ReportError("Prefix: Not enough args. %d are specified in the string\n", FmtStr.ArgCount); exit(1); } for(int i = 0; i < FmtStr.Items.size(); ++i) { int no = FmtStr.Items[i].no; if (no > 0) { FmtStr.Items[i].argName = ArgNames[no-1]; FmtStr.Items[i].expr = ArgNames[no-1]; } } } struct GuidEntry : FieldHolder { GUID guid; string comment; int count; vector Msgs; void printTxt(FILE* f) const { fprintf(f,"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid.Data1,guid.Data2,guid.Data3, guid.Data4[0],guid.Data4[1],guid.Data4[2],guid.Data4[3], guid.Data4[4],guid.Data4[5],guid.Data4[6],guid.Data4[7] ); } void printDat(FILE* f) const { fprintf(f,"{0x%08x,0x%04x,0x%04x,{0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}}", guid.Data1,guid.Data2,guid.Data3, guid.Data4[0],guid.Data4[1],guid.Data4[2],guid.Data4[3], guid.Data4[4],guid.Data4[5],guid.Data4[6],guid.Data4[7] ); } BEGIN_FIELD_TABLE(GuidEntry, f) TEXT_FIELD(Text) { printTxt(f); } TEXT_FIELD(Struct) { printDat(f);} TEXT_FIELD(Comment) fprintf(f, "%s", comment.c_str() ); ENUM_FIELD(Messages, Msgs, VectorPtrTag); END_FIELD_TABLE GuidEntry(){} GuidEntry(int cnt, const string& cmnt):count(cnt),comment(cmnt) { RPC_STATUS status = UuidCreate( &guid ); if ( status != RPC_S_OK ) { ReportError("UuidCreate failed with error %s\n", status); exit(1); } } GuidEntry(PSTR_PAIR p, int cnt, const string& cmnt):count(cnt),comment(cmnt) { guid.Data1 = Hex(p->beg + 0, 8); guid.Data2 = (USHORT)Hex(p->beg + 9, 4); guid.Data3 = (USHORT)Hex(p->beg + 14, 4); guid.Data4[0] = (UCHAR) Hex(p->beg + 19, 2); guid.Data4[1] = (UCHAR) Hex(p->beg + 21, 2); guid.Data4[2] = (UCHAR) Hex(p->beg + 24, 2); guid.Data4[3] = (UCHAR) Hex(p->beg + 26, 2); guid.Data4[4] = (UCHAR) Hex(p->beg + 28, 2); guid.Data4[5] = (UCHAR) Hex(p->beg + 30, 2); guid.Data4[6] = (UCHAR) Hex(p->beg + 32, 2); guid.Data4[7] = (UCHAR) Hex(p->beg + 34, 2); } }; struct Guids : FieldHolder { UINT min_val; UINT max_val; vector guids; int current; string currentFileName; Guids(int lo, int hi) : min_val(lo),max_val(hi),current(0) {} void erase() {current = 0; guids.erase(guids.begin(), guids.end());} BEGIN_FIELD_TABLE(Guids, f) TEXT_FIELD(Count) fprintf(f, "%d", min(current+1, (signed)guids.size()) ); DEFAULT_ENUM_FIELD(guids, VectorTag) END_FIELD_TABLE //void add_guid(PSTR_PAIR p) { } ULONG getid() { for(;;) { if ( current == (signed)guids.size() ) { guids.push_back(GuidEntry(max_val - min_val + 1, currentFileName) ); } if ( guids[current].count ) { ULONG ret = (max_val + 1 - guids[current].count--) | ( current << 16 ); return ret; } ++current; } } void add_guids(PSTR_PAIR p, int count) { --count; ++p; // skip func name // string comment(p->beg,p->end); while (--count) { guids.push_back(GuidEntry(++p, max_val - min_val + 1, comment)); } } void new_file(const char* fname) { currentFileName.assign(fname); // this will force a new guid to be allocated // when a new id is required current = static_cast(guids.size()); } }; struct GenPair { string tpl; string out; GenPair(){} // STL pleaser GenPair(const string& a, const string& b) :tpl(a),out(b) {} }; //TYPE_MAP AutoGen; TYPE_MAP TypeMap; MSG_MAP MsgMap; //MACRO_MAP MacroMap; FUNC_MAP Funcs; GROUP_MAP Groups; PREFIX_VECTOR Prefixes; PREFIX_VECTOR Suffixes; //Guids CtrlGuids(0,31); Guids TraceGuids(10,65535); FILES Files; vector ScanForMacros; vector Touch; vectorGenMulti; vectorGenSingle; set LookFor; void printTraceGuid(FILE* f, int guidno) { TraceGuids.guids[guidno].printTxt(f); } struct Keyword { int nParams; // if < 0 then at least -nParams, otherwise = nParams // EZPARSE_CALLBACK handler; int id; PVOID context; Keyword(){} Keyword(EZPARSE_CALLBACK func, int n, UINT i, PVOID ctx) : nParams(n), handler(func), id(i), context(ctx) {} }; typedef map KEYWORD_MAP; KEYWORD_MAP Keywords; #if DEPRECATED //BOOL GenerateTypeTable; string TypeTableBegin; string TypeTableEntry; string TypeTableEnd; string TypeTablePrefix; string GuidStore; #endif const string CtlStr("LEVEL"); // the same as GRP const string MakeStr("MAKESTR"); const string MsgArgStrUnsafe("(MSG,..unsafe..)"); const string MsgArgStr("(MSG,...)"); const string MsgValStr("MsgVal"); const string MsgStr("MSG"); const string ArgStr("..."); const string ArgStrUnsafe("..unsafe.."); const string IndentStr("INDENT"); const string NullStr("NULL"); bool Files_AddFile(const string& Name, string Path, const WIN32_FIND_DATA& FindData) { if (!AllowedExtension(Name)) { return FALSE; } pair result = Files.insert(File(Name,Path,FindData)); if (!result.second) { if (Name.compare(result.first->_Name) == 0) { ReportError("File %s was already in the processing list\n"); } else { ReportError("Files %s and %s have the same canonical name %s\n", Name.c_str(), result.first->_Name.c_str(), result.first->_CanonicalName.c_str()); } } return result.second; } int compare(const string& a, const STR_PAIR& b) { return a.compare(0, a.length(), b.beg, b.end - b.beg); } BOOL parseLegacy( IN PSTR_PAIR strs, IN INT count, IN INT hole, // args - msg, usually one IN OUT string& Msg, IN OUT vector&, OUT ParsedFormatString& FmtStr ) { vector ArgNames; STR_PAIR buf = *strs; LPCSTR p = buf.beg, q; int i; if ( p < buf.end && buf.end[-1] == ')' ) --buf.end; if(!parseMsg(buf.beg, buf.end, Msg, &p)) { return FALSE; } if( !FmtStr.init(Msg) ) { return FALSE; } ArgNames.reserve(FmtStr.ArgCount); if (count == 1) { // need to grok args from the string // Let's get to the first ',' if (p == buf.end) goto success; while(*p != ',') if (++p == buf.end) goto success; q = ++p; for(i = 0;;++i) { int parlevel = 0; // currently we don't deal with the case of commas or parents within '"' while (p < buf.end) { if (parlevel == 0 && *p == ',') break; if (*p == '(') ++parlevel; if (*p == ')') { if (--parlevel < 0) {ReportError("Too many ')'\n"); return FALSE;} } ++p; } if (parlevel > 0) { ReportError("No closing ')'"); } LPCSTR tmp = p; // remember where we were while (q < p && isspace(*q)) ++ q; while (q < p && isspace(p[-1])) --p; ArgNames.push_back( string(q,p) ); p = tmp; if (p == buf.end) break; q = ++p; } } else { // arguments were supplied in strs strs += hole; count -= hole; while (count-- > 0) { ArgNames.push_back( string(strs->beg,strs->end) ); ++strs; } } success: // check that sizes match // if ((unsigned)ArgNames.size() != (unsigned)FmtStr.ArgCount ) { ReportError("%d argument(s) expected, argument(s) supplied: %d\n", FmtStr.ArgCount, ArgNames.size()); return FALSE; } for(i = 0; i < FmtStr.Items.size(); ++i) { int no = FmtStr.Items[i].no; if (no > 0) { FmtStr.Items[i].expr = ArgNames[no-1]; } } return TRUE; } BOOL parseArgs( IN LPCSTR beg, IN LPCSTR end, IN OUT vector& args ) { LPCSTR p = beg; // MACRO_MAP::iterator macro; TYPE_SET::iterator macro; for(;;) { while ( isspace(*p) ) { if (++p == end) return TRUE; } LPCSTR q = p; // id start while ( isvar(*p) ) { if (++p == end) return TRUE; } macro = TypeSet.find( string(q, p) ); if ( macro == TypeSet.end() ) { if (p == q) { q = beg; p = end; } ReportError("Unknown type: %s\n", string(q, p).c_str() ); return FALSE; } macro->second.Used = TRUE; while ( *p != '(') { if (++p == end) return TRUE; } q = p; // now q points to '(' int level = 0; for (;;) { if (*p == '(') { ++level; } else if (*p == ')') { if (--level == 0) { break; } } if (++p == end) return TRUE; } args.push_back( Argument(string(q+1,p), ¯o->second) ); if (++p == end) return TRUE; } // return TRUE; // unreachable code } enum { // ID_UseTraceGuid, // ID_UseCtrlGuid, // ID_GrpidRange, ID_TraceRange, ID_ProcessFiles, ID_TemplateFile, // ID_OutputInc, // ID_OutputMof, // ID_OutputRc, // ID_OutputCode, ID_TypeMacro, ID_TypevMacro, ID_Include, ID_UsePrefix, ID_UseSuffix, ID_NoPrefix, // ID_ArrayPrefix, ID_DefineSimpleTypePtr, ID_DefineSimpleType, ID_DefineCplxType, ID_CustomType, ID_DefineFlavor, ID_SeparateTraceGuidPerFile, ID_Touch, ID_ScanForMacros, ID_GenerateTypeTable, // ID_AutoGen, ID_Exceptions, ID_WppFlags, }; void UpdateIntVar( UINT* var, PSTR_PAIR Str ) { LPCSTR p = Str->beg, q = Str->end; UINT x = 0; while (p != q && isdigit(*p) ) { x = (x * 10) + (*p - '0'); ++p; } *var = x; } void parseAssumedArgs(Func& f,LPCSTR beg, LPCSTR end) { // we have a string of A=value1,B=value2,C=value3,...,F=valuen} // we need to put A,B,C into f.GooId, // and value1, value2, value3 into f.Goo LPCSTR p = beg, q, stop; if (p >= end) return; Flood("Got %p %p\n", beg, end ); for(;p < end;) { while (isspace(*p)) ++p; // cannot have spaces all the way. there is '}' if (p == end) return; q = p++; while (p < end && *p != '=') ++p; if (p == end) { ReportError("Missing '=' in %s\n", string(beg,end).c_str() ); exit(1); } stop = p; while (--p > q && isspace(*p)); if (p == q) { ReportError("Id required before '=' in %s\n", string(beg,end).c_str() ); exit(1); } f.GooId.push_back( string(q,p+1) ); p = stop + 1; while (isspace(*p)) ++p; // cannot have spaces all the way. there is '}' q = p++; while (*p != '}' && *p != ',') ++p; stop = p; while (--p > q && isspace(*p)); if (isspace(*p)) { // BUGBUG Verify that this condition is correct ReportError("value required after '=' in %s\n", string(beg,end).c_str() ); exit(1); } f.Goo.push_back( string(q,p+1) ); if (*stop == '}') break; p = stop + 1; } f.nAssumedArgs = f.Goo.size(); } DWORD ParseConfigCallback ( IN PSTR_PAIR Str, IN INT Count, IN PVOID Context, IN PEZPARSE_CONTEXT ParseContext ) { string Name(Str[0].beg, Str[0].end); KEYWORD_MAP::iterator keyword = Keywords.find(Name); if (Context) { // We need to ignore all the keywords besides ID_TypeMacro // if (keyword != Keywords.end() && keyword->second.id == ID_TypeMacro) { // proceed and do the job // } else { // Ignore everything else return ERROR_SUCCESS; } } if (keyword != Keywords.end() ) { if (keyword->second.nParams < 0 && Count - 1 < -keyword->second.nParams ) { ReportError("%s requires at least %d parameter(s)\n", Name.c_str(), -keyword->second.nParams); return ERROR_INVALID_PARAMETER; } if (keyword->second.nParams > 0 && Count - 1 != keyword->second.nParams ) { ReportError("%s requires %d parameter(s) (we have %s)\n", Name.c_str(), keyword->second.nParams, std::string(Str[1].beg, Str[Count-1].end).c_str() ); return ERROR_INVALID_PARAMETER; } switch (keyword->second.id) { #ifdef DEPRECATED case ID_UseTraceGuid: TraceGuids.add_guids(Str+1, Count-1); break; case ID_UseCtrlGuid: CtrlGuids.add_guids(Str+1, Count-1); break; case ID_SeparateTraceGuidPerFile: UpdateIntVar((UINT*)(keyword->second.context), Str+1); break; case ID_GrpidRange: UpdateIntVar(&CtrlGuids.min_val, Str+1); UpdateIntVar(&CtrlGuids.max_val, Str+2); break; #endif case ID_TraceRange: UpdateIntVar(&TraceGuids.min_val, Str+1); UpdateIntVar(&TraceGuids.max_val, Str+2); break; case ID_ProcessFiles: while(--Count) { ++Str; Fill( string(Str->beg, Str->end) ); } break; case ID_WppFlags: while(--Count) { ++Str; if(*Str->beg == '-') ++Str->beg; DealWithCmdLineOptions( Str->beg, Str->end ); } Unusual("\n"); break; case ID_ScanForMacros: while(--Count) { ++Str; ScanForMacros.push_back( string(Str->beg, Str->end) ); } break; case ID_Touch: while(--Count) { ++Str; Touch.push_back( string(Str->beg, Str->end) ); } break; case ID_DefineSimpleType: { string Name(Str[1].beg, Str[1].end); if (Str[4].beg < Str[4].end && *Str[4].beg == '"') Str[4].beg++; if (Str[4].beg < Str[4].end && Str[4].end[-1] == '"') Str[4].end--; if (TypeSet.find(Name) != TypeSet.end()) { if (IgnoreDupTypes) { return ERROR_SUCCESS; } ReportError("Type %s is already defined\n", Name.c_str() ); break; } Flood(" type %s\n", Name.c_str()); TypeSet[Name] = WppType( Name , // name string(Str[2].beg, Str[2].end), // c-type SimpleValueMacroStart, string(Str[3].beg, Str[3].end), // mof type "", // MofExtension string(Str[4].beg, Str[4].end), string(Str[5].beg, Str[5].end), stoi(Str[6], "priority"), Count > 7?stoi(Str[7], "argused"):1 ); break; } case ID_DefineSimpleTypePtr: { string Name(Str[1].beg, Str[1].end); if (Str[4].beg < Str[4].end && *Str[4].beg == '"') Str[4].beg++; if (Str[4].beg < Str[4].end && Str[4].end[-1] == '"') Str[4].end--; if (TypeSet.find(Name) != TypeSet.end()) { if (IgnoreDupTypes) { return ERROR_SUCCESS; } ReportError("Type %s is already defined\n", Name.c_str() ); break; } TypeSet[Name] = WppType( Name , // name string(Str[2].beg, Str[2].end), // c-type SimplePtrMacroStart, string(Str[3].beg, Str[3].end), // mof type "", // MofExtension string(Str[4].beg, Str[4].end), string(Str[5].beg, Str[5].end), stoi(Str[6], "priority"), Count > 7?stoi(Str[7], "argused"):1 ); break; } case ID_DefineCplxType: { string Name(Str[1].beg, Str[1].end); string MacroStart(Str[2].beg, Str[2].end); MacroStart.append("("); if (Str[5].beg < Str[5].end && *Str[5].beg == '"') Str[5].beg++; if (Str[5].beg < Str[5].end && Str[5].end[-1] == '"') Str[5].end--; if (TypeSet.find(Name) != TypeSet.end()) { if (IgnoreDupTypes) { return ERROR_SUCCESS; } ReportError("Type %s is already defined\n", Name.c_str() ); break; } TypeSet[Name] = WppType( Name , // name string(Str[3].beg, Str[3].end), // equiv type MacroStart, string(Str[4].beg, Str[4].end), // mof type "", // MofExtension string(Str[5].beg, Str[5].end), string(Str[6].beg, Str[6].end), stoi(Str[7], "priority"), Count > 8?stoi(Str[8], "argused"):1 ); } break; case ID_DefineFlavor: { string Name(Str[1].beg, Str[1].end); string BaseType(Str[2].beg, Str[2].end); TYPE_SET::const_iterator it = TypeSet.find(BaseType); if (Str[4].beg < Str[4].end && *Str[4].beg == '"') Str[4].beg++; if (Str[4].beg < Str[4].end && Str[4].end[-1] == '"') Str[4].end--; if (it == TypeSet.end()) { ReportError("Type Not Found %s\n", BaseType.c_str()); break; } if (TypeSet.find(Name) != TypeSet.end()) { if (IgnoreDupTypes) { return ERROR_SUCCESS; } ReportError("Type %s is already defined\n", Name.c_str() ); break; } WppType Flavor(it->second); Flavor.TypeName = Name; if (!Str[3].empty()) { Flavor.MofType.assign(Str[3].beg, Str[3].end); } if (!Str[4].empty()) { Flavor.FormatSpec.assign(Str[4].beg, Str[4].end); } TypeSet[Name] = Flavor; break; } case ID_TypeMacro: case ID_CustomType: { string Name(Str[1].beg, Str[1].end); LPCSTR p = Str[2].beg, q = Str[2].end; while (p < Str[2].end && *p != '(') ++p; if (p < Str[2].end) { q = p-1; while (q >= Str[2].beg && isspace(*q)) --q; ++q; } string BaseType(Str[2].beg, q); TYPE_SET::const_iterator it = TypeSet.find(BaseType); if (it == TypeSet.end()) { ReportError("Type Not Found %s\n", BaseType.c_str()); break; } if (TypeSet.find(Name) != TypeSet.end()) { if (IgnoreDupTypes) { return ERROR_SUCCESS; } ReportError("Type %s is already defined\n", Name.c_str() ); break; } if (Count == 4) { if (Str[3].beg < Str[3].end && *Str[3].beg == '"') Str[3].beg++; if (Str[3].beg < Str[3].end && Str[3].end[-1] == '"') Str[3].end--; } { string ExtendedType; LPCSTR end = Str[2].end; if ( p != end ) { ExtendedType.reserve(end - p); do { while(p != end && isspace(*p)) ++p; LPCSTR q = p; while(q != end && !isspace(*q)) ++q; ExtendedType.append(p, q); p = q; } while ( p != end ); } WppType Flavor(it->second); Flavor.TypeName = Name; Flavor.Extension = ExtendedType; if (Count == 4) { Flavor.FormatSpec.assign(Str[3].beg,Str[3].end); } if (keyword->second.id == ID_TypeMacro) { Flavor.Flags = WT_MACRONAME; } else { Flavor.Flags = 0; } TypeSet[Name] = Flavor; } break; } /* case ID_OutputInc: case ID_OutputCode: case ID_OutputMof: case ID_OutputRc: case ID_TemplateFile: case ID_ArrayPrefix: ((string*)(keyword->second.context))->assign(Str[1].beg, Str[1].end); break; */ // case ID_AutoGen: // AutoGen[ string(Str[1].beg, Str[1].end) ] = string(Str[2].beg, Str[2].end); // break; case ID_Include: return EzParse(std::string(Str[1].beg, Str[1].end).c_str(),ParseConfigCallback,0); case ID_UseSuffix: // RegenerateMacroMap(); Suffixes.push_back( Prefix(Str, Count) ); break; case ID_UsePrefix: case ID_NoPrefix: // We need to regenerate macro table before using prefix // // RegenerateMacroMap(); Prefixes.push_back( Prefix(Str, Count) ); break; default:; //return Keywords->handler(Str, Count, Context); } } else { // INT i; // // a macro can have a list of assumed arguments in // curly braces right after the name // // Ex: TraceNoise{LEVEL=Noise}(MSG,...) // Flood("Got %s\n", Name.c_str() ); LPCSTR assumed_beg = find(Str[0].beg,Str[0].end, '{'); LPCSTR assumed_end = find(Str[0].beg,Str[0].end, '}'); if (assumed_beg != Str[0].end) { if (assumed_end == Str[0].end) { ReportError("No closing brace in '%s'\n", Name.c_str() ); exit(1); } Name.assign(Str[0].beg, assumed_beg); Noise("Real name is %s (%s)\n", Name.c_str(), string(assumed_beg+1, assumed_end).c_str() ); } else if (assumed_end != Str[0].end) { ReportError("No openning brace in '%s'\n", Name.c_str() ); exit(1); } FUNC_MAP::iterator it = Funcs.find(Name); if (it != Funcs.end()) { ReportError("Function %s is already defined\n", Name.c_str() ); exit(1); } Func f(Name); if (ParseContext->doubleParent) { f.SetDoubleP(); } if (assumed_end > assumed_beg) { parseAssumedArgs(f, assumed_beg+1, assumed_end+1); } for (int i = 1; i < Count; ++i) { // check for '=' LPCSTR div = find(Str[i].beg, Str[i].end, '=' ); if ( div != Str[i].end ) { //f.Args.push_back( string(div+1, Str[i].end) ); f.Goo.push_back( string(Str[i].beg, div ) ); f.GooId.push_back( string(Str[i].beg, div ) ); f.MsgVal = static_cast(i); // can I have more of those? continue; } if ( compare(CtlStr, Str[i]) == 0 ) { f.Grp = static_cast(i); f.Goo.push_back( string(Str[i].beg, Str[i].end) ); f.GooId.push_back( string(Str[i].beg, Str[i].end) ); // } else if ( compare(GrpStr, Str[i]) == 0 ) { // f.Grp = static_cast(i); // f.Goo.push_back( string(Str[i].beg, Str[i].end) ); // } else if ( compare(ArgsStr, Str[i]) == 0 ) { // f.Arg = static_cast(i); } else if ( compare(MsgArgStr, Str[i]) == 0 ) { f.MsgArg = static_cast(i); // can I have more of those? // f.SetLineBeg(); continue; } else if ( compare(MsgArgStrUnsafe, Str[i]) == 0 ) { f.SetUnsafe(); f.MsgArg = static_cast(i); // can I have more of those? continue; } else if ( compare(MsgValStr, Str[i]) == 0 ) { f.MsgVal = static_cast(i); // can I have more of those? } else if ( compare(MakeStr, Str[i]) == 0 ) { f.MsgVal = static_cast(i); // can I have more of those? f.set(FO_NOMACRO); // f.SetLineBeg(); // should i continue? } else if ( compare(MsgStr, Str[i]) == 0 ) { f.Msg = static_cast(i); continue; // } else if ( compare(Msg2Str, Str[i]) == 0 ) { // f.Msg = static_cast(i); // } else if ( compare(IdStr, Str[i]) == 0 ) { // f.Id = static_cast(i); // } else if ( compare(MsgArgsStr, Str[i]) == 0 ) { // f.Msg = static_cast(i); // f.VarArgs = TRUE; } else if ( compare(NullStr, Str[i]) == 0 ) { // not used } else if ( compare(IndentStr, Str[i]) == 0 ) { f.Indent = static_cast(i); } else if ( compare(ArgStrUnsafe, Str[i]) == 0 ) { f.Arg = static_cast(i); f.SetUnsafe(); f.SetVarArgs(); if (i != Count - 1) { ReportError("func %s: '...' has to be the very last argument\n", Name.c_str() ); } continue; } else if ( compare(ArgStr, Str[i]) == 0 ) { f.Arg = static_cast(i); f.SetVarArgs(); if (i != Count - 1) { ReportError("func %s: '...' has to be the very last argument\n", Name.c_str() ); } continue; } else { f.Goo.push_back( string(Str[i].beg, Str[i].end) ); f.GooId.push_back( string(Str[i].beg, Str[i].end) ); } f.Args.push_back( string(Str[i].beg, Str[i].end) ); } f.Num = static_cast(Count - 1); Noise(" func %s\n", Name.c_str() ); Funcs[ Name ] = f; } return ERROR_SUCCESS; } #if 0 DWORD PrintCallback ( IN PSTR_PAIR Str, IN UINT Count, IN PVOID ) { UINT i; for (i = 0; i < Count; ++i) { putchar('<'); fwrite(Str[i].beg, Str[i].end - Str[i].beg, 1, stdout); putchar('>'); } putchar('\n'); return ERROR_SUCCESS; } #endif void CleanupString(LPCSTR beg, LPCSTR end, OUT string& msg) { LPCSTR p = beg, q; msg.resize(0); while (p < end) { // skip spaces while (p < end && isspace(*p)) ++p; q = p; if (p < end && *p == '"') { ++p; while (p < end && (*p != '"' || p[-1] != '\\')) ++p; } if (p < end) ++p; msg.append(q,p); } } DWORD ParseSrcCallback ( IN PSTR_PAIR Str, IN INT Count, IN PVOID, IN PEZPARSE_CONTEXT ParseContext ) { string FuncName(Str[0].beg, Str[0].end); string msg, msgval, id, indent; vector args; ParsedFormatString FmtStr; int LineNo; // UINT argno = 10; if (FuncName.compare("WPP_COMPONENT_NAME") == 0) { if (Count != 2) { ReportError("WPP_COMPONENT_NAME requires 1 argument.\n"); exit(1); } ComponentName.assign(Str[1].beg, Str[1].end); return ERROR_SUCCESS; } // Look for special directive if ( LookFor.find( FuncName ) != LookFor.end() ) { Noise("SpecialString found %s\n", FuncName.c_str()); CurrentFile->IdsFound.insert(FuncName); } FUNC_MAP::iterator func = Funcs.find( FuncName ); if (func == Funcs.end() ) { return ERROR_SUCCESS; } if (func->second.DoubleP() && !ParseContext->doubleParent) { ReportError("%s requires ((args))\n", func->first.c_str() ); exit(1); } if (!func->second.DoubleP() && ParseContext->doubleParent) { ReportError("%s doesn't take ((args))\n", func->first.c_str() ); exit(1); } msg.reserve(255); msgval.reserve(255); if (func->second.VarArgs()) { if (Count < func->second.Num ) { ReportError("%s requires at least %d arguments. (Found only %d)\n", func->first.c_str(), func->second.Num, Count-1); return ERROR_INVALID_PARAMETER; } } else { if (Count-1 != func->second.Num ) { ReportError("%s requires %d arguments. (Found only %d)\n", func->first.c_str(), func->second.Num, Count-1); return ERROR_INVALID_PARAMETER; } } if (func->second.LineBeg() && !func->second.DoubleP() ) { LineNo = EzGetLineNo(Str[0].beg, ParseContext); } else { LineNo = EzGetLineNo(ParseContext->macroEnd, ParseContext); } { char Num[64]; sprintf(Num,"%d", LineNo); id = CurrentFile->_CanonicalName; id += Num; } if (GRP(func->second)) { PSTR_PAIR p = Str + GRP(func->second); string group(p->beg, p->end); GROUP_MAP::iterator i = Groups.find(group); if (i == Groups.end()) { Groups[ string(p->beg, p->end) ] = Group(0, string(p->beg, p->end), id); } else { i->second.MsgIds.push_back(id); } } // BUGBUG make it legacy bugs /* if (ARG(func->second)) { PSTR_PAIR p = Str + ARG(func->second); if( !parseArgs(p->beg, p->end, args) ) { return ERROR_INVALID_PARAMETER; } } */ if (func->second.MsgArg) { PSTR_PAIR p = Str + func->second.MsgArg; if (p->beg == p->end || *p->beg != '(') { ReportError("MsgArg argument should have form (MSG,...)\n"); exit(1); } if (!parseLegacy(p, 1, 1, msg, args, FmtStr)) { return ERROR_INVALID_PARAMETER; } } if (MSG(func->second)) { PSTR_PAIR p = Str + MSG(func->second); if (func->second.VarArgs()) { if (!parseLegacy(p, Count-MSG(func->second), ARG(func->second) - MSG(func->second), msg, args, FmtStr)) { return ERROR_INVALID_PARAMETER; } } else if ( !parseMsg(p->beg, p->end, msg) ) { return ERROR_INVALID_PARAMETER; } } if (func->second.Indent) { PSTR_PAIR p = Str + func->second.Indent; indent.assign(p->beg, p->end); } if (func->second.MsgVal) { PSTR_PAIR p = Str + func->second.MsgVal; CleanupString(p->beg, p->end, msgval); //msgval.assign(p->beg, p->end); string::size_type div = msgval.find('='); if (div != string::npos) { FmtStr.HostString += msgval.substr(div+1); } else { FmtStr.HostString += msgval; } msgval.append(","); // Why comma? } if (func->second.prefix) { FmtStr.insert_prefix(func->second.prefix->FmtStr); } if (func->second.suffix) { FmtStr.append(func->second.suffix->FmtStr); } { MSG_MAP::iterator i = MsgMap.find(id); if ( i != MsgMap.end() ) { // Id already exists. Can't happen // ReportError("Can't handle two printf statements on the same line\n"); exit(1); } Message* Msg = &(MsgMap[id] = Message(id, msg, args, TraceGuids.getid(), LineNo, FmtStr, func->second) ) ; Msg->msgval = msgval; Msg->Indent = indent; for(int i = 1; i < Count; ++i) { if (i == func->second.Indent) continue; if (i == func->second.MsgVal || i == func->second.MsgArg || i == MSG(func->second) ) { break; } Msg->GooActualValues.push_back(string(Str[i].beg, Str[i].end)); } CurrentFile->Msgs.push_back( Msg ); TraceGuids.guids[TraceGuids.current].Msgs.push_back( Msg ); ++MessageCount; if (Msg->ArgConsumed() > arglimit) { ReportError("Too many arguments supplied: %d > %d\n", Msg->ArgConsumed(), arglimit); } } return ERROR_SUCCESS; } /* void RegenerateMacroMap() // // Fill Macro Map table // { TYPE_SET::const_iterator it = TypeSet.begin(); MacroMap.erase(MacroMap.begin(), MacroMap.end()); for(;it != TypeSet.end(); ++it) { string MacroName(MacroPrefix); if(it->second.Flags & WT_MACRONAME) { MacroName.assign(it->second.TypeName); } else { MacroName.append(it->second.TypeName); } MacroMap[ MacroName ] = ArgType(&it->second); } } */ void InitKeywords() { #define HANDLER(A,B,C,D) Keywords[B] = Keyword(0,C,ID_ ## A, D) // HANDLER( UseTraceGuid, "USETRACEGUID", -3, NULL); // HANDLER( UseCtrlGuid, "USECTRLGUID", -3, NULL); // HANDLER( GrpidRange, "GRPIDRANGE", 2, NULL); HANDLER( WppFlags, "WPP_FLAGS", -1, NULL); HANDLER( TraceRange, "TRACERANGE", 2, NULL); // HANDLER( AutoGen, "AUTOGEN", 2, NULL); HANDLER( ProcessFiles, "PROCESSFILES", -1, NULL); HANDLER( Touch, "TOUCH", -1, NULL); HANDLER( ScanForMacros,"SCANFORMACROS", -1, NULL); HANDLER( Exceptions, "EXCEPTIONS", -2, NULL); // HANDLER( OutputInc, "OUTPUT_H", 1, &OutputInc); // HANDLER( OutputMof, "OUTPUT_MOF", 1, &OutputMof); // HANDLER( ArrayPrefix, "ARRAY_PREFIX", 1, &ArrayPrefix); HANDLER( TypeMacro, "TYPEMACRO", 2, NULL); HANDLER( TypevMacro, "TYPEVMACRO", 3, NULL); HANDLER( Include, "INCLUDE", 1, NULL); HANDLER( UsePrefix, "USEPREFIX", -2, NULL); HANDLER( UseSuffix, "USESUFFIX", -2, NULL); // 3 HANDLER( NoPrefix, "NOPREFIX", 1, NULL); HANDLER( SeparateTraceGuidPerFile, "SEPARATE_TRACE_GUID_PERFILE", 1, &SeparateTraceGuidPerFile); HANDLER( DefineSimpleTypePtr, "DEFINE_SIMPLE_TYPE_PTR",-6, NULL); HANDLER( DefineSimpleType, "DEFINE_SIMPLE_TYPE", -6, NULL); HANDLER( DefineCplxType, "DEFINE_CPLX_TYPE", -7, NULL); HANDLER( DefineFlavor, "DEFINE_FLAVOR", 4, NULL); HANDLER( CustomType, "CUSTOM_TYPE", -2, NULL); // HANDLER( GenerateTypeTable, "GENERATE_TYPE_TABLE", 4, NULL); } struct iterless { typedef MSG_MAP::iterator ty; bool operator() (const ty& a, const ty&b) const { return a->second.id < b->second.id; } }; /* bool FileExists( LPSTR fileName ) { HANDLE hFile = CreateFile(fileName, 0, 0, 0, OPEN_EXISTING, 0, 0); if (hFile == INVALID_HANDLE_VALUE) { return FALSE; } else { CloseHandle( hFile ); return TRUE; } } */ void MyGetCurrentDirectory(string& str, int level = 0) { char buf[4096]; int n; n = GetCurrentDirectory(sizeof(buf), buf); if (n == 0 || n > sizeof(buf) ) { ReportError("GetCurrentDirectory failed: %d\n", GetLastError()); exit(1); } { char *p, *q; p = buf; while (level) { q = strrchr(buf, '\\'); if (q == 0) { break; } *q = '_'; p = q+1; --level; } str.assign(p); } } ContainerAdapter MsgMap_tpl("Messages", MsgMap); ContainerAdapter GroupMap_tpl("Groups", Groups); ContainerAdapter FuncMap_tpl("Funcs", Funcs); ContainerAdapter, VectorTag> Reorder_tpl("Reorder", ReorderSet); ContainerAdapter Files_tpl("Files", Files); ContainerAdapter TypeSet_tpl("TypeSet", TypeSet); ContainerAdapter TypeSigSet_tpl("TypeSigSet", TypeSigMap); StringAdapter CurrentDir_tpl("CurrentDir", CurrentDir); StringAdapter MacroPrefix_tpl("MacroPrefix", MacroPrefix); //StringAdapter GuidStore_tpl("GuidStore", GuidStore); StringAdapter TemplateFile_tpl("TemplateFile", CurrentTpl); IteratorAdapter CurrentFile_tpl(&CurrentFile); struct NameAlias : FieldHolder { string _Name, _Alias; NameAlias(){} // To make STL happy NameAlias(const string& Name, const string& Alias): _Name(Name), _Alias(Alias){} bool operator < (const NameAlias& b) const { return _Name.compare(b._Name) < 0; } BEGIN_FIELD_TABLE(NameAlias, f) TEXT_FIELD(Name) fprint_str(f, _Name); TEXT_FIELD(Alias) fprint_str(f, _Alias); TEXT_FIELD(MacroName) { string::size_type br = _Name.find('('); if (br == string::npos) { fprint_str(f, _Name); } else { fprint_str(f, _Name.begin(), _Name.begin() + br); } } END_FIELD_TABLE }; struct Compiler : FieldHolder { const Hasher* Checksum; BEGIN_FIELD_TABLE(Compiler, f) TEXT_FIELD(Name) fprintf(f, "WPP"); TEXT_FIELD(Version) fprintf(f, "0.01"); TEXT_FIELD(Checksum) if (Checksum) Checksum->print(f); TEXT_FIELD(Timestamp) fprintf(f, __TIMESTAMP__); END_FIELD_TABLE }; struct SystemObj : FieldHolder { BEGIN_FIELD_TABLE(SystemObject, out) TEXT_FIELD(Date) { SYSTEMTIME UtcTime; GetSystemTime(&UtcTime); fprintf(out, "%02d/%02d/%04d", UtcTime.wMonth, UtcTime.wDay, UtcTime.wYear); } TEXT_FIELD(Time) { SYSTEMTIME UtcTime; GetSystemTime(&UtcTime); fprintf(out, "%02d:%02d:%02d", UtcTime.wHour, UtcTime.wMinute, UtcTime.wSecond); } END_FIELD_TABLE }; struct FoundTpl: FieldHolder { virtual BOOL Hidden(std::string filter="") const { return CurrentFile->IdsFound.find(filter) == CurrentFile->IdsFound.end(); } BEGIN_FIELD_TABLE(FoundTpl, f) __f__; END_FIELD_TABLE }; FoundTpl Found_tpl; SystemObj System_tpl; Compiler Compiler_tpl; //vector AutoGenMacros; //ContainerAdapter< vector, VectorTag > AutoGenMacros_tpl("AutoGenMacros", AutoGenMacros); set MacroDefinitions; ContainerAdapter< set, VectorTag > MacroDefintions_tpl("MacroDefinitions", MacroDefinitions); void AddMacroDefinition(LPCSTR s) { LPCSTR end = s + strlen(s); LPCSTR q = strchr(s, '='); if (q == NULL) { MacroDefinitions.insert( NameAlias( s , "" ) ); } else { MacroDefinitions.insert( NameAlias( string(s,q) , string(q+1,end) ) ); } } void expand(IN OUT string& str, const string& id) { NameAlias dummy(id, ""); set::const_iterator it = MacroDefinitions.find(dummy); if (it != MacroDefinitions.end()) { str.append(it->_Alias); } } void processGenOption(LPCSTR s) { LPCSTR end = s + strlen(s), div = strchr(s,'}'), star = strchr(s,'*'); vector& v = star ? GenMulti : GenSingle; if (*s != '{') { goto usage; } if (div == 0) { goto usage; } if (s+1 == div || div+1 == end) { goto usage; } if (star) { if (div+1 != star) { ReportError(" '*' can appear only as a first charachter of output-filename part\n"); goto usage; } ++star; } else { star = div+1; } if (star == end) goto usage; v.push_back( GenPair(string(s+1, div), string(star, end)) ); return; usage: ReportError(" use -gen:{template-fpathname}output-fpathname\n" " you supplied -gen:%s\n", s); ExitProcess(1); } void PrepareSearchPaths(LPCSTR s) { // // split /Isdf;sdf;y into a vector of strings // while(s) { LPCSTR semi = strchr(s, ';'); if (semi) { SearchDirs.push_back(string(s,semi)); ++semi; } else { SearchDirs.push_back(string(s)); } s = semi; if (SearchDirs.back().size() > 0 && SearchDirs.back().end()[-1] != '\\') { SearchDirs.back().append("\\"); } } } // 2fb37eda-004b-4b64-a1c4-84c53cb55df5 // 0 1 2 3 // 01234567typeName1234567typeName1234567typeName12345 void processCtlOption(string s) { // first let's check that the guid is OK if ( (s.size() == 16 * 2 + 4) && (s[8] == '-') && (s[13] == '-') && (s[18] == '-') && s[23] == '-') { s[8] = s[13] = s[18] = s[23] = ','; MacroDefinitions.insert( NameAlias( string("WPP_DEFAULT_CONTROL_GUID"), s) ); } } void processCfgItem(const string& s) { LPCSTR beg = s.begin(), end = s.end(); ULONG Status; EZPARSE_CONTEXT ParseContext; ZeroMemory(&ParseContext, sizeof(ParseContext) ); ParseContext.start = beg; ParseContext.filename = "cmdline"; ParseContext.scannedLineCount = 1; ParseContext.lastScanned = beg; // EzParseCurrentContext = &ParseContext; Status = ScanForFunctionCallsEx (beg, end, ParseConfigCallback, 0, &ParseContext, NO_SEMICOLON); if (Status != ERROR_SUCCESS) { exit(1); } } vector cmdinit; // config commands specified on the command line. void ParseConfigFromCmdline() { for(int i = 0; i < cmdinit.size(); ++i) { processCfgItem(cmdinit[i]); } } void DealWithCmdLineOptions(LPCSTR s) { Unusual(" -%s", s); if (lstrcmp(s,"km") == 0) { AddMacroDefinition("WPP_KERNEL_MODE"); userMode = FALSE; } else if (lstrcmp(s,"um") == 0) { AddMacroDefinition("WPP_USER_MODE"); userMode = TRUE; } else if (strcmp(s, "dll")==0) { AddMacroDefinition("WPP_DLL"); } else if (strcmp(s, "ignoreduptypes")==0) { IgnoreDupTypes = TRUE; } else if (strncmp(s, "gen:", 4)==0) { processGenOption(s+4); } else if (strncmp(s, "gen{", 4)==0) { // I was always forgetting to put : processGenOption(s+3); } else if (strncmp(s, "ctl:", 4)==0) { processCtlOption(string(s+4)); } else if (strncmp(s, "scan:", 5)==0) { ScanForMacros.push_back(string(s+5)); } else if (strncmp(s, "defwpp:", 7)==0) { WppDefault.assign(s+7); } else if (strncmp(s, "v", 1)==0) { if ( isdigit(s[1]) ) { DbgLevel = s[1] - '0'; } else { DbgLevel = 1; } } else if (strncmp(s, "ini:", 4)==0) { LocalConfig.assign(s+4); } else if (strncmp(s, "lookfor:", 8)==0) { LookFor.insert(string(s+8)); } else if (strncmp(s, "ext:", 4)==0) { AllowedExtensions.assign(s+4); } else if (strncmp(s, "cfgdir:", 7)==0) { // OBSOLETE PrepareSearchPaths(s+7); } else if (strncmp(s, "arglimit:", 9)==0) { arglimit = atoi(s+9); } else if (strncmp(s, "I", 1)==0) { PrepareSearchPaths(s+1); } else if (strcmp(s, "reorder")==0) { reorder = TRUE; } else if (strcmp(s, "noreorder")==0) { reorder = FALSE; } else if (strcmp(s, "donothing")==0) { exit(0); } else if (strcmp(s, "notimechk")==0) { CheckTimestamp = FALSE; } else if (strcmp(s, "noshrieks")==0) { noshrieks = TRUE; } else if (strcmp(s, "nohashchk")==0) { CheckHash = FALSE; } else if (strncmp(s, "func:",5)==0) { cmdinit.push_back( string(s+5) ); } else if (strcmp(s, "md5")==0) { md5 = TRUE; } else if (strcmp(s, "nomd5")==0) { md5 = FALSE; } else if (strncmp(s, "omac:", 5)==0) { OutputMac.assign(s+5); } else if (strncmp(s, "argbase:", 8)==0) { ArgBase = atoi(s+8); } else if (strncmp(s, "odir:", 5)==0) { OutputDir.assign(s+5); if (OutputDir.size() > 0 && OutputDir.end()[-1] != '\\') { OutputDir.append("\\"); } } else if (strncmp(s, "D", 1)==0) { AddMacroDefinition(s+1); } else { ReportError("Unknown cmdline option: -%s\n", s); exit(1); } } void parseStringAsCmdLine( LPCSTR beg, LPCSTR end ) { LPCSTR p = beg; if( end == NULL ) { end = beg + strlen(beg); } // need to skip spaces. " is processed specially for(;;) { while (p < end && isspace(*p)) ++p; if (p == end) return; LPCSTR q = p; // beginning of the the string if (*p == '"') { ++q; // skip openning quote do { ++p; while (p < end && *p != '"') ++p; if (p == end) { ReportError("Unterminated string in %s\n", string(beg, end).c_str() ); exit(1); } } while (*p == '\\'); // now p points to '"' which is not prefixed by '\' } else { while (p < end && !isspace(*p)) ++p; } if (*q != '-') { ReportError("Option doesn't start with '-' %s in \"%s\"\n", string(q,p).c_str(), string(beg, end).c_str() ); } DealWithCmdLineOptions(q+1, p); if (*p == '"') ++p; } } enum { FAVOR_LOCAL_DIR = 0x01, UPDATE_NAME = 0x02, COMPLAIN_BITTERLY = 0x04, }; BOOL FileExists( string& fname, string path = "", ULONG options = 0) { string file(path); file.append(fname); WIN32_FIND_DATA Dummy; HANDLE ffh = FindFirstFile(file.c_str(), &Dummy); if (ffh != INVALID_HANDLE_VALUE) { FindClose(ffh); Noise("found %s in %s\n", fname.c_str(), path.c_str()); if (options & UPDATE_NAME) { fname = file; } return TRUE; } return FALSE; } void FindFileOnPath(string& Name, ULONG Options = 0) { if (Options & FAVOR_LOCAL_DIR) { if(FileExists(Name)) { goto found; } } int i; for(i = 0; i < SearchDirs.size(); ++i) { if(FileExists(Name, SearchDirs[i], Options)) { goto found; } } if ( !(Options & FAVOR_LOCAL_DIR) ) { if(FileExists(Name)) { goto found; } } if ( Options & COMPLAIN_BITTERLY ) { ReportError("File %s not found\n", Name.c_str()); exit(1); } found:; } void InitGlobals() { InitKeywords(); MyGetCurrentDirectory(CurrentDir, 1); // ArrayPrefix.assign(currentDir); // ArrayPrefix.append("_wpp_"); PopulateFieldMap(); if (OutputMac.size() > 0) { DeleteFile( OutputMac.c_str() ); } ObjectMap["Reorder"] = &Reorder_tpl; ObjectMap["TraceGuids"] = &TraceGuids; // ObjectMap["CtrlGuids"] = &CtrlGuids; ObjectMap["Messages"] = &MsgMap_tpl; ObjectMap["Groups"] = &GroupMap_tpl; ObjectMap["Funcs"] = &FuncMap_tpl; // ObjectMap["AutoMacros"] = &AutoGenMacros_tpl; ObjectMap["CurrentDir"] = &CurrentDir_tpl; ObjectMap["MacroPrefix"] = &MacroPrefix_tpl; ObjectMap["Compiler"] = &Compiler_tpl; ObjectMap["Files"] = &Files_tpl; ObjectMap["TypeSet"] = &TypeSet_tpl; ObjectMap["System"] = &System_tpl; ObjectMap["MacroDefinitions"] = &MacroDefintions_tpl; ObjectMap["TemplateFile"] = &TemplateFile_tpl; ObjectMap["SourceFile"] = &CurrentFile_tpl; ObjectMap["TypeSigSet"] = &TypeSigSet_tpl; ObjectMap["FOUND"] = &Found_tpl; } VOID ReadCommandLineArgs(int argc, char** argv) { Unusual(" tracewpp"); for (int i = 1; i < argc; ++i) { char* s = argv[i]; int len = (int)strlen(s); if (len > 1 && s[0] == '-') { DealWithCmdLineOptions(s+1); } else { Unusual(" %s", argv[i]); Fill( string(argv[i])); } } Unusual("\n"); { LPCSTR p = getenv("WPP_FLAGS"); if (p) { Noise("WPP_FLAGS defined: %s\n", p); parseStringAsCmdLine(p, NULL); } } /* // THINK do we need revision at all? if (Revision.size() > 0) { if(SearchDirs.size() == 0) { ReportError("Revision can be specified only when -cfgdir directive is specified"); ExitProcess(3); } else { if (Revision.end()[-1] != '\\') { Revision.append("\\"); } int i, n = SearchDirs.size(); for (i = 0; i < n; ++i) { SearchDirs.push_back( SearchDirs[i] ); SearchDirs.back().append(Revision); } } } */ } void ReadConfig() { DWORD status; BOOL WppParsed = FALSE; // If default config file was specified, // process it if (WppDefault.size() > 0) { WppParsed = TRUE; Noise("parsing config file %s\n", WppDefault.c_str()); status = EzParse(WppDefault.c_str(), ParseConfigCallback,0); if (status != ERROR_SUCCESS) { ExitProcess( status ); } } if (LocalConfig.size() == 0) { if (FileExists(LOCAL_CONFIG_NAME) ) { WppParsed = TRUE; Noise("parsing config file %s\n", LOCAL_CONFIG_NAME.c_str()); status = EzParse(LOCAL_CONFIG_NAME.c_str(),ParseConfigCallback,0); if (status != ERROR_SUCCESS) { ExitProcess( status ); } } } else { WppParsed = TRUE; Noise("parsing config file %s\n", LocalConfig.c_str()); status = EzParse(LocalConfig.c_str(),ParseConfigCallback,0); if (status != ERROR_SUCCESS) { ExitProcess( status ); } } if (!WppParsed) { ReportError("configuration file not found\n"); ExitProcess( ERROR_FILE_NOT_FOUND ); } if (Files.begin() == Files.end()) { Unusual("Nothing to compile\n"); ExitProcess( ERROR_FILE_NOT_FOUND ); } { // Scan files for macro // vector::iterator i; for (i = ScanForMacros.begin(); i != ScanForMacros.end(); ++i) { Noise("scanning %s... \n", i->c_str()); EzParseEx(i->c_str(), SmartScan, ParseConfigCallback,0, 0); } } ParseConfigFromCmdline(); // // We need to add prefix and suffix information to FuncMap // { PREFIX_VECTOR::iterator i; Prefix * defaultPrefix = 0; Prefix * defaultSuffix = 0; string star("*"); for (i = Prefixes.begin(); i != Prefixes.end(); ++i) { if ( 0 == i->FuncName.compare(star) ) { defaultPrefix = i; } else { Funcs[i->FuncName].SetPrefix(i); } } for (i = Suffixes.begin(); i != Suffixes.end(); ++i) { if ( 0 == i->FuncName.compare(star) ) { defaultSuffix = i; } else { Funcs[i->FuncName].SetSuffix(i); } } // // Assign the appendicies to the all other functions // FUNC_MAP::iterator j = Funcs.begin(); for(; j != Funcs.end(); ++j) { if (!j->second.prefix) { j->second.SetPrefix( defaultPrefix ); } if (!j->second.suffix) { j->second.SetSuffix( defaultSuffix ); } } } // // Generates names of the log macros based on type names // Thus users of the tool can have LOGULONG or log_ulong // or w_ulong(). Whatever they like best // // RegenerateMacroMap(); } // used by tpl.cpp to do template include [BUGBUG] currently broken void ProcessTemplate(LPCSTR b, LPCSTR e, void* Context) { string prev(CurrentTpl); CurrentTpl.assign(b,e); FindFileOnPath(CurrentTpl, COMPLAIN_BITTERLY | UPDATE_NAME | FAVOR_LOCAL_DIR); EzParseEx(CurrentTpl.c_str(), processTemplate,0, Context, 0); CurrentTpl.assign(prev); } void FormOutputFileName( IN const string& to, IN const string& suffix, OUT string& OutputFile, OUT BOOL &StdOut ) { string::size_type backSlash = to.find('\\'); string::size_type colon = to.find(':'); if (to.compare("-") == 0) { StdOut = TRUE; OutputFile.assign("-"); } else { StdOut = FALSE; if (backSlash == string::npos && colon == string::npos) { // can prepend odir OutputFile.assign(OutputDir); OutputFile.append(to); } else { OutputFile.assign(to); } OutputFile.append(suffix); } } void GenerateOutput(string tpl, string to, string suffix = "") { string OutputFile; FILE * f = 0; BOOL useStdOut = FALSE; FormOutputFileName(to, suffix, OutputFile, useStdOut); DefaultHasher computedHash; computedHash.Init(); MsgMapHash(MsgMap, computedHash); computedHash.Finalize(); Compiler_tpl.Checksum = &computedHash; if (md5) { size_t len = min(sizeof(GUID), computedHash.Size() ); Flood("Going MD5... %d guid(s) ", TraceGuids.guids.size()); for (int i = 0; i < TraceGuids.guids.size(); ++i) { // The following two lines are just needed in case // we ever decide DefaultHasher to be CRC32 // If it will always be MD5 hasher, we can remove them ZeroMemory(&TraceGuids.guids[i].guid, sizeof(TraceGuids.guids[i].guid)); TraceGuids.guids[i].guid.Data2 = (USHORT)i; CopyMemory(&TraceGuids.guids[i].guid, computedHash.Buf(), len); if (DbgLevel >= DBG_FLOOD) { TraceGuids.guids[i].printTxt(stdout); putchar(' '); } } Flood("\n"); } // check whether we need to regenerate the file if (ErrorCount == 0 && CheckHash) { // Scan the beginning of the FILE *inc = fopen(OutputFile.c_str(), "r"); if (inc) { DefaultHasher readHash; char buf[128], *p = buf; int n = (int)fread(buf, 1, sizeof(buf)-1, inc); fclose(inc); buf[n] = 0; while (!isalnum(*p) && *p ) ++p; readHash.fromString(p, buf + n); if (DbgLevel >= DBG_FLOOD) { computedHash.print(stdout); putchar(' '); readHash.print(stdout); putchar(' '); } if (computedHash == readHash) { Noise("No changes in %s.\n", CurrentFile->_Name.c_str() ); return; } } } if (ErrorCount) { DeleteFile(OutputFile.c_str()); Noise("errors detected. deleting %s...\n", OutputFile.c_str()); return; } Noise("generating %s...\n", OutputFile.c_str()); if (useStdOut) { f = stdout; } else { f = fopen(OutputFile.c_str(), "w"); if (!f) { ReportError("Cannot open '%s' for writing, error %d\n", OutputFile.c_str(), GetLastError() ); ExitProcess( GetLastError() ); } } ProcessTemplate(tpl.begin(), tpl.end(), f); if (!useStdOut) { fclose(f); } } void printTime(LPCSTR Name, ULONGLONG Time) { FILETIME Local; ZeroMemory(&Local, sizeof(Local)); SYSTEMTIME st; ZeroMemory(&st, sizeof(st)); FileTimeToLocalFileTime((LPFILETIME)&Time, &Local); //CopyMemory(&Local, &Time, sizeof(Time)); FileTimeToSystemTime(&Local, &st); printf("%s %04d/%02d/%02d %02d:%02d:%02d\n", Name, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond); } void VerifyAndUpdateTemplatesNames( vector& Gen ) { // verify that the template vector::iterator i; for(i = Gen.begin();i != Gen.end();++i){ FindFileOnPath(i->tpl, COMPLAIN_BITTERLY | UPDATE_NAME | FAVOR_LOCAL_DIR); } } int RealMain(int argc, char** argv) { InitGlobals(); ReadCommandLineArgs(argc, argv); if (WppDefault.size()) { FindFileOnPath(WppDefault, COMPLAIN_BITTERLY | UPDATE_NAME); } ReadConfig(); if (GenSingle.size() == 0 && GenMulti.size() == 0) { // add default template processGenOption(DEFAULT_GEN_OPTION); } BOOL OneAtATime = GenMulti.size() > 0; VerifyAndUpdateTemplatesNames(GenMulti); VerifyAndUpdateTemplatesNames(GenSingle); { FILES::iterator file; if (CheckTimestamp) { // // Before we do any heavyweight processing // let's check timestamps of source // and output files // ULONGLONG Now, MaxSrcTime, MinOutTime; string OutputFile; GetSystemTimeAsFileTime((LPFILETIME)&Now); MaxSrcTime = 0; MinOutTime = Now; for (file = Files.begin(); file != Files.end(); ++file) { if (file->ModificationTime == 0) { Always("%s file has invalid modification time\n", file->_BaseName.c_str()); goto out_of_date; } if (file->ModificationTime > Now) { Always("%s file modification time is in the future\n", file->_BaseName.c_str()); goto out_of_date; } if (file->ModificationTime > MaxSrcTime) { MaxSrcTime = file->ModificationTime; } vector::iterator i; for(i = GenMulti.begin();i != GenMulti.end();++i){ BOOL StdOut; ULONGLONG Time; FormOutputFileName(file->_BaseName, i->out.c_str(), OutputFile, StdOut); if (StdOut) { // StdOut is always out of date // goto out_of_date; } Time = GetFileModificationTime(OutputFile); if (Time == 0) { goto out_of_date; } if (Time > Now) { Always("%s file modification time is in the future\n", OutputFile.c_str()); goto out_of_date; } if (Time < MinOutTime) { MinOutTime = Time; } } } vector::iterator i; for(i = GenSingle.begin();i != GenSingle.end();++i){ BOOL StdOut; ULONGLONG Time; FormOutputFileName(file->_BaseName, i->out.c_str(), OutputFile, StdOut); if (StdOut) { // StdOut is always out of date // goto out_of_date; } Time = GetFileModificationTime(OutputFile); if (Time == 0) { goto out_of_date; } if (Time > Now) { Always("%s file modification time is in the future\n", OutputFile.c_str()); goto out_of_date; } if (Time < MinOutTime) { MinOutTime = Time; } } if (MaxSrcTime <= MinOutTime) { // printTime("Src time:", MaxSrcTime); // printTime("Out time:", MinOutTime); // Noise("No Processing Required\n"); return 0; } } // if (CheckTimestamp) // out_of_date: // // Now we are ready to start scanning the source files // for (file = Files.begin(); file != Files.end(); ++file) { Noise("processing %s... \n", file->FullFileName().c_str()); CurrentFile = file; if (SeparateTraceGuidPerFile) { TraceGuids.new_file( file->_Name.c_str() ); } EzParseWithOptions(file->FullFileName().c_str(), ParseSrcCallback, 0, IGNORE_CPP_COMMENT); { vector::iterator i; for(i = GenMulti.begin();i != GenMulti.end();++i){ GenerateOutput(i->tpl, file->_BaseName, i->out.c_str()); } } if (OneAtATime) { // Clear the tables for the next iteration MsgMap.erase(MsgMap.begin(), MsgMap.end()); TypeSigMap.erase(TypeSigMap.begin(), TypeSigMap.end()); TraceGuids.erase(); for (TYPE_SET::const_iterator i = TypeSet.begin(); i != TypeSet.end(); ++i) { i->second.Used = FALSE; } } } Noise("done. Errors: %d.\n", ErrorCount); } #if 0 // update Used field for every type in TypeSigSet { for (TYPESIG_MAP::const_iterator i = TypeSigMap.begin(); i != TypeSigMap.end(); ++i) { for(int j = 0; j < i->Types.size(); ++j) { i->second.Types[j]->Used = TRUE; } } } #endif // generate global files { vector::iterator i; for(i = GenSingle.begin();i != GenSingle.end();++i){ GenerateOutput(i->tpl, i->out.c_str()); } } return ErrorCount; } int __cdecl main(int argc, char** argv) { int status = 0; __int64 a, b; GetSystemTimeAsFileTime((LPFILETIME)&a); __try { status = RealMain(argc, argv); } __except(EXCEPTION_EXECUTE_HANDLER) { status = 1; ReportError("Internal Error : Contact GorN\n"); } { SYSTEMTIME st; GetSystemTimeAsFileTime((LPFILETIME)&b); b -= a; FileTimeToSystemTime((LPFILETIME)&b, &st); Always("tracewpp: %d file(s) with %d message(s), processed in %d.%03d seconds\n", Files.size(), MessageCount, st.wSecond, st.wMilliseconds); } return status; }