/* **============================================================================== ** ** Open Management Infrastructure (OMI) ** ** Copyright (c) Microsoft Corporation ** ** Licensed under the Apache License, Version 2.0 (the "License"); you may not ** use this file except in compliance with the License. You may obtain a copy ** of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** ** THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ** KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED ** WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABLITY OR NON-INFRINGEMENT. ** ** See the Apache 2 License for the specific language governing permissions ** and limitations under the License. ** **============================================================================== */ #include "Parser.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "QualifierDecls.h" #include #include #include #include #include #include #if defined(CONFIG_OS_WINDOWS) # include #else # include # include # include #endif #include "gen.h" // C Provider Templates: #include "cprototypes_t.h" #include "cprovider_t.h" #include "cmodule_t.h" #include "cmakefile_t.h" // C++ Provider Templates: #include "cxxmodule_t.h" #include "cxxprovider_t.h" #include "cxxstubs_t.h" #include "cxxmakefile_t.h" using namespace std; /* xlc doesn't want to use static inline funciotns inside temaplate functions */ int _Scasecmp(const MI_Char* s1, const MI_Char* s2) { return Zcasecmp(s1, s2); } //============================================================================== // // GeneratorOptions // //============================================================================== GeneratorOptions::GeneratorOptions() { paths.clear(); descriptions = false; values = false; mappingStrings = false; standardQualifiers = false; booleanQualifiers = false; ignoreAllQualifiers = false; filterSupport = false; quiet = false; noProviders = false; all = false; cpp = false; schema.clear(); dir.clear(); localize = false; providerRegistryPath.clear(); association = false; extraClasses.clear(); entryPoint.clear(); warnings = false; } //============================================================================== // // WARNING // // Message included in all generated files that are not intended to be // modified by the developer. // //============================================================================== #define WARNING \ "WARNING: THIS FILE WAS AUTOMATICALLY GENERATED. PLEASE DO NOT EDIT." //============================================================================== // // arg0 // // A global pointer to argv[0] that is set immediately by main(). // //============================================================================== static const char* arg0; static FILE* s_stdout; //============================================================================== // // providerClasses // // The set of class names for which there are providers (used by generator // to include or exclude various elements). // //============================================================================== typedef set ProviderClassSet; static ProviderClassSet providerClasses; //============================================================================== // // generated // // Allows keep tracking of generated classes in 'generateHeader' function // //============================================================================== static set generated_headers; static set generated_classes; //============================================================================== // // err() // // Writes a formatted error message to standard error (preceded by argv[0]) // and then exists. // //============================================================================== PRINTF_FORMAT(3, 4) static void Fprintf(FILE* os, int id, const MI_Char* format, ...) { va_list ap; va_start(ap, format); #if defined(_MSC_VER) wchar_t* wformat = LookupString(id); if (wformat) { vfwprintf(os, wformat, ap); free(wformat); } else #endif { vfprintf(os, format, ap); } va_end(ap); } //============================================================================== // // err() // // Writes a formatted error message to standard error (preceded by argv[0]) // and then exists. // //============================================================================== PRINTF_FORMAT(2, 3) void FUNCTION_NEVER_RETURNS err(int id, const char* format, ...) { fprintf(stderr, "%s: ", arg0); va_list ap; va_start(ap, format); #if defined(_MSC_VER) wchar_t* wformat = LookupString(id); if (wformat) { vfwprintf(stderr, wformat, ap); free(wformat); } else #endif { vfprintf(stderr, format, ap); } va_end(ap); fputc('\n', stderr); exit(1); } //============================================================================== // // put() // // Write formatted output to the given stream (similar to fprintf). // //============================================================================== PRINTF_FORMAT(2, 3) static void put(FILE* os, const char* fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(os, fmt, ap); va_end(ap); } //============================================================================== // // putl() // // Similar to put() but adds a newline at the end. // //============================================================================== PRINTF_FORMAT(2, 3) static void putl(FILE* os, const char* fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(os, fmt, ap); va_end(ap); fputc('\n', os); } //============================================================================== // // Exists() // // Return true if the given file exists. // //============================================================================== static bool Exists(const char* path) { return access(path, F_OK) == 0; } //============================================================================== // // ValidIdent() // // Check whether the given string is a valid C identifier. // //============================================================================== static bool ValidIdent(const string& s) { const char* p = s.c_str(); if (!isalpha((unsigned char)(*p)) && *p != '_') return false; p++; for (; *p; p++) { if (!isalnum((unsigned char)(*p)) && *p != '_') return false; } return true; } //============================================================================== // // Inhale() // // Read the contents of the given file into memory. // //============================================================================== static bool Inhale(const char* path, vector& data) { FILE* is = Fopen(path, "r"); if (!is) return false; size_t n; char buf[4096]; while ((n = fread(buf, 1, sizeof(buf), is)) != 0) { data.insert(data.end(), buf, buf + n); } data.push_back('\0'); fclose(is); return true; } //============================================================================== // // puts() // // Put a string onto the output stream. // //============================================================================== static void puts(FILE* os, const string& s) { fprintf(os, "%s", s.c_str()); } //============================================================================== // // eqi() // // Return true if the two strings are identical except for case. // //============================================================================== static bool eqi(const char* s1, const char* s2) { return Strcasecmp(s1, s2) == 0; } //============================================================================== // // nl() // // Print a newline to the given stream. // //============================================================================== inline void nl(FILE* os) { fputc('\n', os); } //============================================================================== // // Generate a random key // //============================================================================== #if 0 static MI_Uint64 _GetCurrentTime() { #if defined(CONFIG_OS_WINDOWS) FILETIME ft; ULARGE_INTEGER tmp; GetSystemTimeAsFileTime(&ft); tmp.u.LowPart = ft.dwLowDateTime; tmp.u.HighPart = ft.dwHighDateTime; tmp.QuadPart -= 0X19DB1DED53E8000; return tmp.QuadPart / (UINT64)10; #else struct timeval tv; struct timezone tz; memset(&tv, 0, sizeof(tv)); memset(&tz, 0, sizeof(tz)); if (gettimeofday(&tv, &tz) != 0) return MI_RESULT_FAILED; return (MI_Uint64)tv.tv_sec * (MI_Uint64)1000000 + (MI_Uint64)tv.tv_usec; #endif } static void _SleepMsec(MI_Uint64 msec) { #if defined(CONFIG_OS_WINDOWS) Sleep((DWORD)msec); #else struct timespec rqtp; rqtp.tv_sec = static_cast(msec/1000); rqtp.tv_nsec = static_cast((msec%1000)*1000*1000); nanosleep(&rqtp, NULL); #endif } static void _MakeID(char id[33]) { MI_Uint64 s1 = _GetCurrentTime(); _SleepMsec(10); MI_Uint64 s2 = _GetCurrentTime(); srand((unsigned int)(((s1 >> 32) ^ s1 ^ (s2 >> 32)) | s2)); static const char XDIGITS[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F', }; for (size_t i = 0; i < 32; i++) { int x = rand() % 16; id[i] = XDIGITS[x]; } id[32] = '\0'; } #endif //============================================================================== // // GeneratorOptions // // This structure defines program options. These include: // //============================================================================== static GeneratorOptions s_options; static set s_generated; //============================================================================== // // GenStatikGenLine() // //============================================================================== static void GenStatikGenLine(FILE* os) { // Files generated by Statik may be located by searching for files which // contain the following string. The ampersands are separted into a format // argument to prevent this file (generator.cpp) from containg that string. fprintf(os, "/* %cmigen%c */\n", '@', '@'); } //============================================================================== // // aliases // // Maps MOF classnames to aliases. This map is built in main before // classes are generated. The generator consults this table to determine // the real name of the C structure (the alias) which may be different // than the name of the MOF class. // //============================================================================== typedef map Aliases; static Aliases aliases; //============================================================================== // // Quote() // // This function puts quotation marks around a string. // //============================================================================== static string Quote(const string& str) { return "MI_T(\"" + str + "\")"; } //============================================================================== // // ExpandPath() // // Obtain the full path (including directory given by optional -d option). // //============================================================================== static string ExpandPath(const string& str) { if (s_options.dir.size()) { string r = s_options.dir + "/" + str; return s_options.dir + "/" + str; } else return str; } //============================================================================== // // Contains() // // Return true if this vector contains the given string. // //============================================================================== static bool Contains(const vector& v, const string& s) { for (size_t i = 0; i < v.size(); i++) { if (s == v[i]) return true; } return false; } //============================================================================== // // MakeFlags() // // This function builds a flags expression from a bit mask. For example, // for a key property, the flag expression might look like this: // // MI_FLAG_PROPERTY | MI_FLAG_KEY // // Many structures have a flags field whose bits indicate the type of the // object (e.g., MI_FLAG_CLASS, MI_FLAG_METHOD, MI_FLAG_PROPERTY) as well // as any boolean qualifiers whose values are true (e.g., MI_FLAG_KEY, // MI_FLAG_IN, MI_FLAG_OUT). // //============================================================================== static string MakeFlags(MI_Uint32 flags) { struct { const char* name; MI_Uint32 flag; } _flags[] = { { "CLASS", MI_FLAG_CLASS }, { "METHOD", MI_FLAG_METHOD }, { "PROPERTY", MI_FLAG_PROPERTY }, { "PARAMETER", MI_FLAG_PARAMETER }, { "ASSOCIATION", MI_FLAG_ASSOCIATION }, { "INDICATION", MI_FLAG_INDICATION }, { "REFERENCE", MI_FLAG_REFERENCE }, { "KEY", MI_FLAG_KEY }, { "IN", MI_FLAG_IN }, { "OUT", MI_FLAG_OUT }, { "REQUIRED", MI_FLAG_REQUIRED }, { "STATIC", MI_FLAG_STATIC }, { "ABSTRACT", MI_FLAG_ABSTRACT }, { "TERMINAL", MI_FLAG_TERMINAL }, { "EXPENSIVE", MI_FLAG_EXPENSIVE }, { "STREAM", MI_FLAG_STREAM }, { "ENABLEOVERRIDE", MI_FLAG_ENABLEOVERRIDE }, { "DISABLEOVERRIDE", MI_FLAG_DISABLEOVERRIDE }, { "RESTRICTED", MI_FLAG_RESTRICTED}, { "TOSUBCLASS", MI_FLAG_TOSUBCLASS}, { "TRANSLATABLE", MI_FLAG_TRANSLATABLE}, }; string result; size_t count = 0; for (size_t i = 0; i < MI_COUNT(_flags); i++) { if (_flags[i].flag & flags) { if (count) result += "|"; result += string("MI_FLAG_") + _flags[i].name; count++; } } if (result.size()) return result; return "0"; } //============================================================================== // // MakeFlavor() // // This function builds a flavor string from the given flavor mask. For // example: // // MI_FLAG_TOSUBCLASS | MI_FLAG_DISABLEOVERRIDE // //============================================================================== static string MakeFlavor(MI_Uint32 flavor) { struct { MI_Uint32 mask; const char* name; } _flavors[] = { { MI_FLAG_ENABLEOVERRIDE, "MI_FLAG_ENABLEOVERRIDE" }, { MI_FLAG_DISABLEOVERRIDE, "MI_FLAG_DISABLEOVERRIDE" }, { MI_FLAG_TOSUBCLASS, "MI_FLAG_TOSUBCLASS" }, { MI_FLAG_TRANSLATABLE, "MI_FLAG_TRANSLATABLE" }, { MI_FLAG_RESTRICTED, "MI_FLAG_RESTRICTED" }, }; string result; size_t count = 0; for (size_t i = 0; i < MI_COUNT(_flavors); i++) { if (_flavors[i].mask & flavor) { if (count) result += "|"; result += _flavors[i].name; count++; } } if (result.size()) return result; return "0"; } //============================================================================== // // MakeScope() // // This function builds a scope string from the given scope mask. For // example: // // MI_FLAG_TOSUBCLASS | MI_FLAG_DISABLEOVERRIDE // //============================================================================== static string MakeScope(MI_Uint32 scope) { struct { MI_Uint32 mask; const char* name; } _scopes[] = { { MI_FLAG_ASSOCIATION, "MI_FLAG_ASSOCIATION" }, { MI_FLAG_CLASS, "MI_FLAG_CLASS" }, { MI_FLAG_INDICATION, "MI_FLAG_INDICATION" }, { MI_FLAG_METHOD, "MI_FLAG_METHOD" }, { MI_FLAG_PARAMETER, "MI_FLAG_PARAMETER" }, { MI_FLAG_PROPERTY, "MI_FLAG_PROPERTY" }, { MI_FLAG_REFERENCE, "MI_FLAG_REFERENCE" }, }; if ((scope & MI_FLAG_ANY) == MI_FLAG_ANY) return "MI_FLAG_ANY"; string result; size_t count = 0; for (size_t i = 0; i < MI_COUNT(_scopes); i++) { if (_scopes[i].mask & scope) { if (count) result += "|"; result += _scopes[i].name; count++; } } if (result.size()) return result; return "0"; } //============================================================================== // // MakeType() // // This function returns the type tag string for the given Statik type // (given by the MI_Type structure). // //============================================================================== static string MakeType(MI_Uint32 type) { switch (type) { case MI_BOOLEAN: return "MI_BOOLEAN"; case MI_UINT8: return "MI_UINT8"; case MI_SINT8: return "MI_SINT8"; case MI_UINT16: return "MI_UINT16"; case MI_SINT16: return "MI_SINT16"; case MI_UINT32: return "MI_UINT32"; case MI_SINT32: return "MI_SINT32"; case MI_UINT64: return "MI_UINT64"; case MI_SINT64: return "MI_SINT64"; case MI_REAL32: return "MI_REAL32"; case MI_REAL64: return "MI_REAL64"; case MI_CHAR16: return "MI_CHAR16"; case MI_DATETIME: return "MI_DATETIME"; case MI_STRING: return "MI_STRING"; case MI_REFERENCE: return "MI_REFERENCE"; case MI_INSTANCE: return "MI_INSTANCE"; case MI_BOOLEANA: return "MI_BOOLEANA"; case MI_UINT8A: return "MI_UINT8A"; case MI_SINT8A: return "MI_SINT8A"; case MI_UINT16A: return "MI_UINT16A"; case MI_SINT16A: return "MI_SINT16A"; case MI_UINT32A: return "MI_UINT32A"; case MI_SINT32A: return "MI_SINT32A"; case MI_UINT64A: return "MI_UINT64A"; case MI_SINT64A: return "MI_SINT64A"; case MI_REAL32A: return "MI_REAL32A"; case MI_REAL64A: return "MI_REAL64A"; case MI_CHAR16A: return "MI_CHAR16A"; case MI_DATETIMEA: return "MI_DATETIMEA"; case MI_STRINGA: return "MI_STRINGA"; case MI_REFERENCEA: return "MI_REFERENCEA"; case MI_INSTANCEA: return "MI_INSTANCEA"; default: return "UNKNOWN_TYPE"; }; } //============================================================================== // // AliasOf() // // The the given class name is in the alias map, return the alias. // Otherwise, just return the class name. // //============================================================================== string AliasOf(const string& className) { Aliases::const_iterator pos = aliases.find(className); if (pos != aliases.end()) return (*pos).second; return className; } //============================================================================== // // PutRule() // // Put a rule line (2 '*' characters followed by 78 '=' characters). // //============================================================================== static void PutRule(FILE* os) { put(os, "**"); for (size_t i = 0; i < 78; i++) put(os, "="); nl(os); } //============================================================================== // // PutCommentBox() // // Put a C comment box with a message in it. // //============================================================================== static void PutCommentBox(FILE* os, const string& msg) { putl(os, "/*"); PutRule(os); putl(os, "**"); putl(os, "** %s", msg.c_str()); putl(os, "**"); PutRule(os); putl(os, "*/"); } //============================================================================== // // TypeNameOf() // // Return the C type name for the given Statik type tag. For arrays type // tags, return the C type name of the element type. For example: // // TypeNameOf(MI_UINT8) => "Uint8" // TypeNameOf(MI_UINT8A) => "Uint8" // //============================================================================== static const char* TypeNameOf(MI_Uint32 type) { switch (type) { case MI_BOOLEAN: return "Boolean"; case MI_SINT8: return "Sint8"; case MI_UINT8: return "Uint8"; case MI_SINT16: return "Sint16"; case MI_UINT16: return "Uint16"; case MI_SINT32: return "Sint32"; case MI_UINT32: return "Uint32"; case MI_SINT64: return "Sint64"; case MI_UINT64: return "Uint64"; case MI_REAL32: return "Real32"; case MI_REAL64: return "Real64"; case MI_CHAR16: return "Char16"; case MI_DATETIME: return "Datetime"; case MI_STRING: return "String"; case MI_REFERENCE: return "Reference"; case MI_INSTANCE: return "Instance"; case MI_BOOLEANA: return "Boolean"; case MI_SINT8A: return "Sint8"; case MI_UINT8A: return "Uint8"; case MI_SINT16A: return "Sint16"; case MI_UINT16A: return "Uint16"; case MI_SINT32A: return "Sint32"; case MI_UINT32A: return "Uint32"; case MI_SINT64A: return "Sint64"; case MI_UINT64A: return "Uint64"; case MI_REAL32A: return "Real32"; case MI_REAL64A: return "Real64"; case MI_CHAR16A: return "Char16"; case MI_DATETIMEA: return "Datetime"; case MI_STRINGA: return "String"; case MI_REFERENCEA: return "Reference"; case MI_INSTANCEA: return "Instance"; default: return "UNKNOWN"; } } //============================================================================== // // CountRefs() // // Count how many roles (references) the given class has. // //============================================================================== static size_t CountRefs(const MI_ClassDecl* cd) { size_t r = 0; for (size_t i = 0; i < cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; if (pd->type == MI_REFERENCE) r++; } return r; } //============================================================================== // // CanGenerateAssocRoles() // // returns true if: // - association class has two references // - ref classes are not inherited from each other // //============================================================================== static bool CanGenerateAssocRoles(const MI_ClassDecl* cd) { if (2 != CountRefs(cd)) return false; int index1 = -1, index2 = -1; for (int i = 0; i < (int)cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; if (pd->type == MI_REFERENCE) { if (-1 == index1) index1 = i; else index2 = i; } } if (-1 == index2 || !cd->properties[index1]->className || !cd->properties[index2]->className) return false; return _Scasecmp(cd->properties[index1]->className,cd->properties[index2]->className) != 0; } //============================================================================== // // FullTypeNameOf() // // Same as TypeNameOf() except that it gives the full typedef name. // // TypeNameOf(MI_UINT8) => "MI_Uint8" // //============================================================================== static string FullTypeNameOf(MI_Uint32 type) { return string("MI_") + TypeNameOf(type); } //============================================================================== // // CppTypeNameOf() // // Return the Cpp type name for the given Statik type tag. For arrays type // tags, return the Cpp type name of the element type. For example: // // CppTypeNameOf(MI_UINT8) => "Uint8" // CppTypeNameOf(MI_UINT8A) => "Uint8" // //============================================================================== const char* CppTypeNameOf(MI_Uint32 type) { const char* res = TypeNameOf(type); return res; } //============================================================================== // // ScalarSizeOf() // // Return the size of the given type; for arrays return the element size. // //============================================================================== INLINE MI_Uint32 ScalarSizeOf(MI_Uint32 type) { return (MI_Uint32)Type_SizeOf(Type_ScalarOf(MI_Type(type))); } //============================================================================== // // sub() // // Substitute all occurences of 'pattern' with 'replacement' within the // 'str' parameter. Return the result. // //============================================================================== string sub( const string& str, const string& pattern, const string& replacement) { size_t pos = 0; string r = str; while ((pos = r.find(pattern, pos)) != string::npos) { r = r.substr(0, pos) + replacement + r.substr(pos + pattern.size()); pos += replacement.size(); } return r; } //============================================================================== // // subu() // // Similiar to sub() but substitutes an unsigned integer. // //============================================================================== static string subu( const string& str, const string& pattern, MI_Uint32 replacement) { char buf[32]; Snprintf(buf, sizeof(buf), "%u", replacement); return sub(str, pattern, buf); } //============================================================================== // // subx() // // Similiar to sub() but substitutes an unsigned integer (as hex string). // //============================================================================== static string subx( const string& str, const string& pattern, MI_Uint32 replacement) { char buf[32]; Snprintf(buf, sizeof(buf), "0x%08X", replacement); return sub(str, pattern, buf); } //============================================================================== // // subd() // // Substitute all occurences of 'pattern' with the string form of // 'replacement' within the 'str' parameter. // //============================================================================== #if 0 static string subd( const string& str, const string& pattern, MI_Sint32 replacement) { char buf[32]; Snprintf(buf, sizeof(buf), "%d", replacement); return sub(str, pattern, buf); } #endif //============================================================================== // // FindStandardQualifierDecl() // // Find the standard qualifier declaration with the given name. // //============================================================================== static const MI_QualifierDecl* FindStandardQualifierDecl(const char* name) { for (size_t i = 0; i < g_numQualifierDecls; i++) { MI_QualifierDecl* qd = g_qualifierDecls[i]; if (Strcasecmp(qd->name, name) == 0) return qd; } /* Not found! */ return NULL; } //============================================================================== // // FindPropertyDecl() // // Find the named property in the given class declarartion. Return a // pointer if found, else return NULL. // //============================================================================== static const MI_PropertyDecl* FindPropertyDecl( const MI_ClassDecl* cd, const char* name) { for (size_t i = 0; i < cd->numProperties; i++) { if (Strcasecmp(cd->properties[i]->name, name) == 0) return cd->properties[i]; } /* Not found */ return NULL; } //============================================================================== // // ExistInstanceQualifier // // returns 'true' if EmbeddedInstance/Object qualifier is set // //============================================================================== template< typename PropertyDeclType> bool ExistInstanceQualifier( const PropertyDeclType* pd) { for ( MI_Uint32 i = 0; i < pd->numQualifiers; i++ ) { if (_Scasecmp(pd->qualifiers[i]->name,MI_T("EmbeddedInstance")) == 0) return true; if (_Scasecmp(pd->qualifiers[i]->name,MI_T("EmbeddedObject")) == 0) return true; } return false; } //============================================================================== // // IsPropertyRefOrInstance // // returns 'true' if property (or parameter) is // REFERENCE, REFERENCEA, EmbeddedInstance [arry], EmbeddedObject [array] // //============================================================================== template< typename PropertyDeclType> bool IsPropertyRefOrInstance( const PropertyDeclType* pd) { if ((pd->type == MI_REFERENCE) || (pd->type == MI_REFERENCEA)) return true; if ((pd->type == MI_INSTANCE) || (pd->type == MI_INSTANCEA)) return true; if ((pd->type == MI_STRING) || (pd->type == MI_STRINGA)) return ExistInstanceQualifier(pd); return false; } //============================================================================== // // GetPropertyClassname // // returns 'class-name' of the property; only makes sense for // REFERENCE, REFERENCEA, EmbeddedInstance [arry], EmbeddedObject [array] // for EmbeddedObject returns empty string // //============================================================================== template< typename PropertyDeclType> string GetPropertyClassname( const PropertyDeclType* pd) { if ((pd->type == MI_REFERENCE) || (pd->type == MI_REFERENCEA)) return pd->className; if ((pd->type == MI_INSTANCE) || (pd->type == MI_INSTANCEA)) return pd->className ? pd->className : ""; if ((pd->type == MI_STRING) || (pd->type == MI_STRINGA)) { for ( MI_Uint32 i = 0; i < pd->numQualifiers; i++ ) { if (_Scasecmp(pd->qualifiers[i]->name,MI_T("EmbeddedInstance"))==0) { if (pd->qualifiers[i]->type != MI_STRING) { err(ID_EMBEDDEDINSTANCE_ON_NON_STRING, "EmbeddedInstance qualifier on non-string type: %s", pd->name); } return (const MI_Char*)pd->qualifiers[i]->value; } if (_Scasecmp(pd->qualifiers[i]->name,MI_T("EmbeddedObject")) == 0) return string(); } return string(); } return string(); } //============================================================================== // // GenProperties() // // This function writes properties for the MOF class currently being // generated (i.e., it generates fields for the corresponing C structure). // Properties are written in the order they are encountered when // traversing from the root of the inheritance chain to the current class. // A property may be defined more than once in the inheritance chain due // to overriding. In that case, overrides by descendent classes have no // bearing on the order. // //============================================================================== // Keeps track of property-name/class-name pairs. typedef map NameClassMap; typedef pair NameClassPair; static void GenProperties( FILE* os, Parser& parser, const MI_ClassDecl* lcd, /* the leaf class in the recursion */ const MI_ClassDecl* cd, NameClassMap& map) { // Inject the property-name and class-name for all reference properties // first. During recursion we want to use the class-name of the most // derived reference declaration. for (size_t i = 0; i < cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; if (pd->type == MI_REFERENCE) { if (map.find(pd->name) == map.end()) map.insert(NameClassPair(pd->name, pd->className)); } } // Recurse on superclass (if any) and print its properties first. if (cd->superClass) { const MI_ClassDecl* scd = parser.findClassDecl(cd->superClass); if (!scd) err(ID_UNKNOWN_SUPERCLASS_FOR, "unknown superclass for %s: %s", cd->name, cd->superClass); GenProperties(os, parser, lcd, scd, map); } // Print the local properties of this class. putl(os, " /* %s properties */", AliasOf(cd->name).c_str()); for (size_t i = 0; i < cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; // Skip non-local properties: if (Strcasecmp(cd->name, pd->origin) != 0) continue; // Indent this property. put(os, " "); // Put the key attribute if the property in the leaf class has // the Key qualifier. { const MI_PropertyDecl* lpd = FindPropertyDecl(lcd, pd->name); if (lpd && (lpd->flags & MI_FLAG_KEY)) put(os, "/*KEY*/ "); } if (pd->type == MI_REFERENCE) { // If a derived class defines this property, use the classname // that it uses for the property. NameClassMap::iterator p = map.find(pd->name); string al; if (p == map.end()) { al = AliasOf(pd->className); } else { al = AliasOf((*p).second); } putl(os, "%s_ConstRef %s;", al.c_str(), pd->name); } else if (pd->type == MI_REFERENCEA) { err(ID_REFERENCE_ARRAY_AS_PROPERTY, "reference arrays are not allowed as properties"); } else if (IsPropertyRefOrInstance(pd) && !GetPropertyClassname(pd).empty()) { // embedded instance const string al = AliasOf(GetPropertyClassname(pd)); if (pd->type & MI_ARRAY_BIT) { putl(os, "%s_ConstArrayRef %s;", al.c_str(), pd->name); } else { putl(os, "%s_ConstRef %s;", al.c_str(), pd->name); } } else if (IsPropertyRefOrInstance(pd) && GetPropertyClassname(pd).empty()) { // embedded object if (pd->type & MI_ARRAY_BIT) { putl(os, "MI_ConstReferenceAField %s;", pd->name); } else { putl(os, "MI_ConstReferenceField %s;", pd->name); } } else if (pd->type & MI_ARRAY_BIT) { putl(os, "MI_Const%sAField %s;", TypeNameOf(pd->type), pd->name); } else { putl(os, "MI_Const%sField %s;", TypeNameOf(pd->type), pd->name); } } } //============================================================================== // // GenSingleParameter() // // This function generates the parameter structure, which holds the // extrinsic method parameters that are passed to an extrinsic method // provider stub. The return value is also defined in the structure whose // field name is "MIReturn". // //============================================================================== static void GenSingleParameter( FILE* os, const MI_ParameterDecl* pd) { if (pd->flags & MI_FLAG_IN && pd->flags & MI_FLAG_OUT) put(os, " /*IN-OUT*/ "); else if (pd->flags & MI_FLAG_IN) put(os, " /*IN*/ "); else if (pd->flags & MI_FLAG_OUT) put(os, " /*OUT*/ "); if (IsPropertyRefOrInstance(pd) && !GetPropertyClassname(pd).empty()) { const string al = AliasOf(GetPropertyClassname(pd)); if (pd->type & MI_ARRAY_BIT) { putl(os, "%s_ConstArrayRef %s;", al.c_str(), pd->name); } else { putl(os, "%s_ConstRef %s;", al.c_str(), pd->name); } } else if (IsPropertyRefOrInstance(pd) && GetPropertyClassname(pd).empty()) { // embedded object if (pd->type & MI_ARRAY_BIT) { putl(os, "MI_ConstReferenceAField %s;", pd->name); } else { putl(os, "MI_ConstReferenceField %s;", pd->name); } } else if (pd->type & MI_ARRAY_BIT) { putl(os, "MI_Const%sAField %s;", TypeNameOf(pd->type), pd->name); } else { putl(os, "MI_Const%sField %s;", TypeNameOf(pd->type), pd->name); } } //============================================================================== // // GenParameters() // // This function generates MOF method parameters (i.e., C fields for the // parameters structure). // //============================================================================== static void GenParameters( FILE* os, const MI_ClassDecl* cd, const MI_MethodDecl* md) { for (size_t i = 0; i < md->numParameters; i++) { const MI_ParameterDecl* pd = md->parameters[i]; // Skip stream parameters: if (pd->flags & MI_FLAG_STREAM) { if (!(pd->type & MI_ARRAY_BIT)) { err(ID_STREAM_QUALIFIER_ON_NON_ARRAY, "'Stream' qualifiers may only appear on array parameters: " "%s.%s(): %s", cd->name, md->name, pd->name); } if (!(pd->flags & MI_FLAG_OUT)) { err(ID_STREAM_QUALIFIER_ON_NON_OUTPUT, "'Stream' qualifiers may only appear on output parameters: " "%s.%s(): %s", cd->name, md->name, pd->name); } continue; } // Reject properties named "MIReturn". if (Strcasecmp(pd->name, "MIReturn") == 0) { err(ID_RESERVED_PARAMETER_NAME, "reserved parameter name: %s.%s(): %s", cd->name, md->name, pd->name); } GenSingleParameter(os,pd); } } //============================================================================== // // GenParametersStruct() // // This function generates the parameters structure, which holds the // extrinsic method parameters that are passed to an extrinsic method // provider stub. The return value is also defined in the structure whose // field name is "MIReturn". // //============================================================================== static void GenParametersStruct( FILE* os, const MI_ClassDecl* cd, const MI_MethodDecl* md) { const string alias = AliasOf(cd->name); // Put comment box for the parameter structure name. const string str = alias + "." + md->name + "()"; PutCommentBox(os, str); nl(os); // Put method structure definition. putl(os, "typedef struct _%s_%s", alias.c_str(), md->name); putl(os, "{"); putl(os, " MI_Instance __instance;"); { MI_ParameterDecl pd; memset(&pd, 0, sizeof(pd)); pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT; pd.name = (char*)"MIReturn"; pd.type = md->returnType; pd.offset = sizeof(MI_Instance); pd.numQualifiers = md->numQualifiers; pd.qualifiers = md->qualifiers; GenSingleParameter(os,&pd); } GenParameters(os, cd, md); putl(os, "}"); putl(os, "%s_%s;", alias.c_str(), md->name); nl(os); } //============================================================================== // // GenSetter() // // This function generates the 'setter' convenience functions for the // given class property or method parameter. // //============================================================================== static void GenSetter( FILE* os, const MI_ClassDecl* cd, const MI_MethodDecl* md, const MI_ParameterDecl* pd) { const string alias = AliasOf(cd->name); string r,r_ptr; MI_Uint32 index = (MI_Uint32)-1; // Form the structure prefix ( for classes, for // methods. string prefix = alias; if (md) { prefix += "_"; prefix += md->name; } // Find index of this property. if (md) { if (strcmp(pd->name, "MIReturn") == 0) { index = 0; } else { for (MI_Uint32 i = 0; i < md->numParameters; i++) { if (md->parameters[i] == pd) { index = i; break; } } // Increment parameter index to make room for insertion of // the "MIReturn" pseudo-parameter. index++; } } else { for (MI_Uint32 i = 0; i < cd->numProperties; i++) { if (cd->properties[i] == (MI_PropertyDecl*)pd) { index = i; break; } } } if (index == (MI_Uint32)-1) err(ID_INTERNAL_ERROR, "internal error: %s(%u)", __FILE__, __LINE__); // Generate *_Set_* and *_SetPtr_* functions. if (pd->type & MI_ARRAY_BIT) { const char T[] = "MI_INLINE MI_Result MI_CALL (\n" " * self,\n" " const * data,\n" " MI_Uint32 size)\n" "{\n" " MI_Array arr;\n" " arr.data = (void*)data;\n" " arr.size = size;\n" " return self->__instance.ft->SetElementAt(\n" " (MI_Instance*)&self->__instance,\n" " ,\n" " (MI_Value*)&arr,\n" " ,\n" " );\n" "}\n" "\n"; r = T; r = sub(r, "", prefix); r = sub(r, "", pd->name); r = subu(r, "", index); if (pd->type == MI_REFERENCEA) r = sub(r, "", AliasOf(pd->className) + "* const"); else if (pd->type == MI_STRINGA && IsPropertyRefOrInstance(pd) && !GetPropertyClassname(pd).empty()) { r = sub(r, "", AliasOf(GetPropertyClassname(pd)) + string(" * const ")); r = sub(r, "", "MI_INSTANCEA"); } else if (pd->type == MI_STRINGA && IsPropertyRefOrInstance(pd) && GetPropertyClassname(pd).empty()) { r = sub(r, "", "MI_Instance * const "); r = sub(r, "", "MI_INSTANCEA"); } else if (pd->type == MI_STRINGA) r = sub(r, "", "MI_Char*"); else r = sub(r, "", FullTypeNameOf(pd->type)); r = sub(r, "", MakeType(pd->type)); r_ptr = r; // non-copying version has to be created from initial template // otherwise name conflict is possible if function name is 'Set' r = sub(r, "", "_Set_"); r = sub(r, "", "0"); r_ptr = sub(r_ptr, "", "_SetPtr_"); r_ptr = sub(r_ptr, "", "MI_FLAG_BORROW"); puts(os, r); puts(os, r_ptr); } else if (IsPropertyRefOrInstance(pd)) { const char T[] = "MI_INLINE MI_Result MI_CALL (\n" " * self,\n" " const * x)\n" "{\n" " return self->__instance.ft->SetElementAt(\n" " (MI_Instance*)&self->__instance,\n" " ,\n" " (MI_Value*)&x,\n" " ,\n" " );\n" "}\n" "\n"; r = T; r = sub(r, "", prefix); r = sub(r, "", pd->name); r = subu(r, "", index); r = sub(r, "", pd->type == MI_REFERENCE ? "MI_REFERENCE" : "MI_INSTANCE"); if (!GetPropertyClassname(pd).empty()) r = sub(r, "", AliasOf(GetPropertyClassname(pd))); else r = sub(r, "", "MI_Instance"); r_ptr = r; // non-copying version has to be created from initial template // otherwise name conflict is possible if function name is 'Set' r = sub(r, "", "_Set_"); r = sub(r, "", "0"); r_ptr = sub(r_ptr, "", "_SetPtr_"); r_ptr = sub(r_ptr, "", "MI_FLAG_BORROW"); puts(os, r); puts(os, r_ptr); } else if (pd->type == MI_STRING) { const char T[] = "MI_INLINE MI_Result MI_CALL (\n" " * self,\n" " const MI_Char* str)\n" "{\n" " return self->__instance.ft->SetElementAt(\n" " (MI_Instance*)&self->__instance,\n" " ,\n" " (MI_Value*)&str,\n" " MI_STRING,\n" " );\n" "}\n" "\n"; r = T; r = sub(r, "", prefix); r = sub(r, "", pd->name); r = subu(r, "", index); r_ptr = r; // non-copying version has to be created from initial template // otherwise name conflict is possible if function name is 'Set' r = sub(r, "", "_Set_"); r = sub(r, "", "0"); r_ptr = sub(r_ptr, "", "_SetPtr_"); r_ptr = sub(r_ptr, "", "MI_FLAG_BORROW"); puts(os, r); puts(os, r_ptr); } else { const char T[] = "MI_INLINE MI_Result MI_CALL _Set_(\n" " * self,\n" " MI_ x)\n" "{\n" " ((MI_Field*)&self->)->value = x;\n" " ((MI_Field*)&self->)->exists = 1;\n" " return MI_RESULT_OK;\n" "}\n" "\n"; r = T; r = sub(r, "", prefix); r = sub(r, "", pd->name); r = sub(r, "", TypeNameOf(pd->type)); puts(os, r); } // Generate *_Clear_* function. if ((pd->type & MI_ARRAY_BIT) != 0 || pd->type == MI_STRING || pd->type == MI_REFERENCE || pd->type == MI_INSTANCE) { const char T[] = "MI_INLINE MI_Result MI_CALL _Clear_(\n" " * self)\n" "{\n" " return self->__instance.ft->ClearElementAt(\n" " (MI_Instance*)&self->__instance,\n" " );\n" "}\n" "\n"; r = T; r = sub(r, "", prefix); r = sub(r, "", pd->name); r = subu(r, "", index); puts(os, r); } else { const char T[] = "MI_INLINE MI_Result MI_CALL _Clear_(\n" " * self)\n" "{\n" " memset((void*)&self->, 0, sizeof(self->));\n" " return MI_RESULT_OK;\n" "}\n" "\n"; r = T; r = sub(r, "", prefix); r = sub(r, "", pd->name); puts(os, r); } #if 0 // Generate function to obtain the flags for this property: { const char T[] = "MI_INLINE MI_Result MI_CALL _GetFlags_(\n" " const * self,\n" " MI_Uint32* flags)\n" "{\n" " return self->__instance.ft->GetElementAt(&self->__instance,\n" " , NULL, NULL, NULL, flags);\n" "}\n" "\n"; r = T; r = sub(r, "", prefix); r = sub(r, "", pd->name); r = subu(r, "", index); puts(os, r); } #endif } //============================================================================== // // GenInstanceFunctions() // // This function generates the 'initInstance' convenience function for the // given class. // //============================================================================== static void GenInstanceFunctions( FILE* os, const MI_ClassDecl* cd) { const string alias = AliasOf(cd->name); const char T[] = "MI_INLINE MI_Result MI_CALL _Construct(\n" " * self,\n" " MI_Context* context)\n" "{\n" " return MI_ConstructInstance(context, &_rtti,\n" " (MI_Instance*)&self->__instance);\n" "}\n" "\n" "MI_INLINE MI_Result MI_CALL _Clone(\n" " const * self,\n" " ** newInstance)\n" "{\n" " return MI_Instance_Clone(\n" " &self->__instance, (MI_Instance**)newInstance);\n" "}\n" "\n" "MI_INLINE MI_Boolean MI_CALL _IsA(\n" " const MI_Instance* self)\n" "{\n" " MI_Boolean res = MI_FALSE;\n" " return MI_Instance_IsA(self, &_rtti, &res) == MI_RESULT_OK && res;\n" "}\n" "\n" "MI_INLINE MI_Result MI_CALL _Destruct(* self)\n" "{\n" " return MI_Instance_Destruct(&self->__instance);\n" "}\n" "\n" "MI_INLINE MI_Result MI_CALL _Delete(* self)\n" "{\n" " return MI_Instance_Delete(&self->__instance);\n" "}\n" "\n" "MI_INLINE MI_Result MI_CALL _Post(\n" " const * self,\n" " MI_Context* context)\n" "{\n" " return MI_PostInstance(context, &self->__instance);\n" "}\n" "\n"; string r = T; r = sub(r, "", alias); puts(os, r); } //============================================================================== // // GenMethodFunctions() // // This function generates convenience functions for the given method. // //============================================================================== static void GenMethodFunctions( FILE* os, const MI_ClassDecl* cd, const MI_MethodDecl* md) { const string alias = AliasOf(cd->name); const char T[] = "MI_EXTERN_C MI_CONST MI_MethodDecl __rtti;\n" "\n" "MI_INLINE MI_Result MI_CALL __Construct(\n" " _* self,\n" " MI_Context* context)\n" "{\n" " return MI_ConstructParameters(context, &__rtti,\n" " (MI_Instance*)&self->__instance);\n" "}\n" "\n" "MI_INLINE MI_Result MI_CALL __Clone(\n" " const _* self,\n" " _** newInstance)\n" "{\n" " return MI_Instance_Clone(\n" " &self->__instance, (MI_Instance**)newInstance);\n" "}\n" "\n" "MI_INLINE MI_Result MI_CALL __Destruct(\n" " _* self)\n" "{\n" " return MI_Instance_Destruct(&self->__instance);\n" "}\n" "\n" "MI_INLINE MI_Result MI_CALL __Delete(\n" " _* self)\n" "{\n" " return MI_Instance_Delete(&self->__instance);\n" "}\n" "\n" "MI_INLINE MI_Result MI_CALL __Post(\n" " const _* self,\n" " MI_Context* context)\n" "{\n" " return MI_PostInstance(context, &self->__instance);\n" "}\n" "\n"; string r = T; r = sub(r, "", alias); r = sub(r, "", md->name); puts(os, r); } //============================================================================== // // FindDirectDependencies // // Find classes that this class depends (via superclasses and references). // //============================================================================== static void FindDirectDependencies( const MI_ClassDecl* cd, vector& deps) { // Find super classes. if (cd->superClass) deps.push_back(cd->superClass); // Find property reference dependencies. for (MI_Uint32 i = 0; i < cd->numProperties; i++) { MI_PropertyDecl* pd = cd->properties[i]; if (IsPropertyRefOrInstance(pd)) { string cn = GetPropertyClassname(pd); if (!cn.empty() && !Contains(deps, cn)) deps.push_back(cn); } } // Find parameter reference dependencies. for (MI_Uint32 i = 0; i < cd->numMethods; i++) { MI_MethodDecl* md = cd->methods[i]; // check return type { MI_ParameterDecl pd; memset(&pd, 0, sizeof(pd)); pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT; pd.name = (char*)"MIReturn"; pd.type = md->returnType; pd.offset = sizeof(MI_Instance); pd.numQualifiers = md->numQualifiers; pd.qualifiers = md->qualifiers; if (IsPropertyRefOrInstance(&pd)) { string cn = GetPropertyClassname(&pd); if (!cn.empty() && !Contains(deps, cn)) deps.push_back(cn); } } for (MI_Uint32 j = 0; j < md->numParameters; j++) { MI_ParameterDecl* pd = md->parameters[j]; if (IsPropertyRefOrInstance(pd)) { string cn = GetPropertyClassname(pd); if (!cn.empty() && !Contains(deps, cn)) deps.push_back(cn); } } } } //============================================================================== // // PutCppPropertyAccessor // // Generate inline functions to access a single property // //============================================================================== template< typename PropertyDeclType> void PutCppPropertyAccessor( FILE* os, const PropertyDeclType* pd, const string& alias) { const char T[] = " //\n" " // =ALIAS=_Class.=NAME=\n" " //\n" " \n" " const Field<=TYPE=>& =NAME=() const\n" " {\n" " const size_t n = offsetof(Self, =NAME=);\n" " return GetField<=TYPE=>(n);\n" " }\n" " \n" " void =NAME=(const Field<=TYPE=>& x)\n" " {\n" " const size_t n = offsetof(Self, =NAME=);\n" " GetField<=TYPE=>(n) = x;\n" " }\n" " \n" " const =TYPE=& =NAME=_value() const\n" " {\n" " const size_t n = offsetof(Self, =NAME=);\n" " return GetField<=TYPE=>(n).value;\n" " }\n" " \n" " void =NAME=_value(const =TYPE=& x)\n" " {\n" " const size_t n = offsetof(Self, =NAME=);\n" " GetField<=TYPE=>(n).Set(x);\n" " }\n" " \n" " bool =NAME=_exists() const\n" " {\n" " const size_t n = offsetof(Self, =NAME=);\n" " return GetField<=TYPE=>(n).exists ? true : false;\n" " }\n" " \n" " void =NAME=_clear()\n" " {\n" " const size_t n = offsetof(Self, =NAME=);\n" " GetField<=TYPE=>(n).Clear();\n" " }\n"; string r = sub(T, "=ALIAS=", alias); if (IsPropertyRefOrInstance(pd) && !GetPropertyClassname(pd).empty()) { const string al = AliasOf(GetPropertyClassname(pd)); if (pd->type & MI_ARRAY_BIT) { r = sub(r, "=TYPE=", al + "_ClassA"); } else { r = sub(r, "=TYPE=", al + "_Class"); } } else if (IsPropertyRefOrInstance(pd) && GetPropertyClassname(pd).empty()) { // embedded object const string al = AliasOf(GetPropertyClassname(pd)); if (pd->type & MI_ARRAY_BIT) r = sub(r, "=TYPE=", "InstanceA"); else r = sub(r, "=TYPE=", "Instance"); } else if (pd->type & MI_ARRAY_BIT) { r = sub(r, "=TYPE=", string(CppTypeNameOf(pd->type)) + "A"); } else { r = sub(r, "=TYPE=", CppTypeNameOf(pd->type)); } r = sub(r, "=NAME=", pd->name); puts(os, r); } //============================================================================== // // getReturnType // // returns 'return-type' for funciton declaration; for instances return false // //============================================================================== template< typename ClassDeclType, typename PropertyDeclType> bool getReturnType(const ClassDeclType* cd, MI_Uint32& type); template<> bool getReturnType( const MI_ClassDecl* , MI_Uint32& ) { return false; } template<> bool getReturnType( const MI_MethodDecl* cd, MI_Uint32& type) { type = cd->returnType; return true; } //============================================================================== // // isPropertyLocal // // checks if rpoerty is local // //============================================================================== template< typename ClassDeclType, typename PropertyDeclType> bool isPropertyLocal(const ClassDeclType* , const PropertyDeclType* ); template<> bool isPropertyLocal( const MI_ClassDecl* cd, const _MI_PropertyDecl* pd) { return Strcasecmp(cd->name, pd->origin) == 0; } template<> bool isPropertyLocal( const MI_MethodDecl*, const _MI_ParameterDecl*) { return true; } //============================================================================== // // HashKeys() // // Return true if the given class declaration has any key properties. // //============================================================================== static bool HasKeys(const MI_ClassDecl* cd) { for (MI_Uint32 i = 0; i < cd->numProperties; i++) { if (cd->properties[i]->flags & MI_FLAG_KEY) return true; } // No keys found! return false; } //============================================================================== // // GenCppPropertiesAccessors // // Generate C++ class property accessors funciotns // //============================================================================== template< typename ClassDeclType, typename PropertyDeclType> void GenCppPropertiesAccessors( FILE* os, const ClassDeclType* cd, const string& alias, size_t numProperties, PropertyDeclType** const properties ) { // Print the local properties of this class. { // put MIReturn if it's a method MI_Uint32 type = 0; if (getReturnType(cd,type)) { MI_ParameterDecl pd; memset(&pd, 0, sizeof(pd)); pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT; pd.name = (char*)"MIReturn"; pd.type = type; pd.offset = sizeof(MI_Instance); pd.numQualifiers = cd->numQualifiers; pd.qualifiers = cd->qualifiers; PutCppPropertyAccessor(os,&pd,alias); if (numProperties) nl(os); } } for (size_t i = 0; i < numProperties; i++) { const PropertyDeclType* pd = properties[i]; // Skip non-local properties: if (!isPropertyLocal(cd,pd)) continue; // Skip stream parameters: if (pd->flags & MI_FLAG_STREAM) continue; // generate skeleton PutCppPropertyAccessor(os,pd,alias); if (i +1 != numProperties) nl(os); } } //============================================================================== // // GenCppClassDeclaration // // Generate C++ class // //============================================================================== template< typename ClassDeclType, typename PropertyDeclType> void GenCppClassDeclaration( FILE* os, const ClassDeclType* cd, const string& alias, const char* superClass, size_t numProperties, PropertyDeclType** const properties ) { //////////////////////////////////////// // class definition { const char T[] = "class _Class : public \n" "{\n" "public:\n" " \n" " typedef Self;\n" " \n" " _Class() :\n" " (&_rtti)\n" " {\n" " }\n" " \n" " _Class(\n" " const * instanceName,\n" " bool keysOnly) :\n" " (\n" " &_rtti,\n" " &instanceName->__instance,\n" " keysOnly)\n" " {\n" " }\n" " \n" " _Class(\n" " const MI_ClassDecl* clDecl,\n" " const MI_Instance* instance,\n" " bool keysOnly) :\n" " (clDecl, instance, keysOnly)\n" " {\n" " }\n" " \n" " _Class(\n" " const MI_ClassDecl* clDecl) :\n" " (clDecl)\n" " {\n" " }\n" " \n" " _Class& operator=(\n" " const _Class& x)\n" " {\n" " CopyRef(x);\n" " return *this;\n" " }\n" " \n" " _Class(\n" " const _Class& x) :\n" " (x)\n" " {\n" " }\n" "\n"; const char S[] = " static const MI_ClassDecl* GetClassDecl()\n" " {\n" " return &_rtti;\n" " }\n" "\n"; string r = sub(T, "", alias); if (superClass) { string tmp = AliasOf(superClass) + "_Class"; r = sub(r, "", tmp); } else { r = sub(r, "", "Instance"); } puts(os, r); if (cd->flags & MI_FLAG_CLASS) { r = sub(S, "", alias); puts(os, r); } } /// inline funciotns for property access GenCppPropertiesAccessors( os,cd,alias,numProperties,properties); /// end class { const char T[] = "};\n" "\n" "typedef Array<_Class> _ClassA;\n" "\n" ; string r = sub(T, "", alias); puts(os, r); } } //============================================================================== // // SubRoles() // // Substitute , , , and with // property names and classnames for the first and second references // (roles) in this class. // //============================================================================== static void SubRoles(const MI_ClassDecl* cd, string& r) { size_t role = 1; for (size_t i = 0; i < cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; if (pd->type == MI_REFERENCE) { if (role == 1) { r = sub(r, "", pd->name); r = sub(r, "", AliasOf(pd->className).c_str()); role++; } else if (role == 2) { r = sub(r, "", pd->name); r = sub(r, "", AliasOf(pd->className).c_str()); role++; } else if (role == 3) { err(ID_INTERNAL_ERROR, "internal error: %s(%u)", __FILE__, __LINE__); } } } } //============================================================================== // // GenCppClassProviderHeaderNewFile // // Generate class provider declaration // used only to create a new file // //============================================================================== static void GenCppClassProviderHeaderNewFile( FILE* os, const MI_ClassDecl* cd) { string alias = AliasOf(cd->name); GenStatikGenLine(os); // Prevent multiple inclusion. putl(os, "#ifndef _%s_Class_Provider_h", alias.c_str()); putl(os, "#define _%s_Class_Provider_h", alias.c_str()); nl(os); // Include instance class putl(os, "#include \"%s.h\"", alias.c_str()); // standard starting part putl(os, "#ifdef __cplusplus"); putl(os, "# include "); putl(os, "# include \"module.h\""); nl(os); putl(os, "MI_BEGIN_NAMESPACE"); nl(os); // Write the intrinsic provider function prototypes. { PutCommentBox(os, alias + " provider class declaration"); nl(os); // Generate forward typedef for Self structure. string extraDataMemebers; if (cd->flags & MI_FLAG_ASSOCIATION) { string r; if (!s_options.association && CanGenerateAssocRoles(cd)) { r = ASSOCIATION_PROVIDER_CLASS_DECLARATION_ROLES; SubRoles(cd, r); } else r = ASSOCIATION_PROVIDER_CLASS_DECLARATION; r = sub(r, "", alias); r = sub(r, "", extraDataMemebers); puts(os, r); } else if (cd->flags & MI_FLAG_INDICATION) { string r = INDICATION_PROVIDER_CLASS_DECLARATION; extraDataMemebers = " MI_Context* m_IndicationsContext;\n"; r = sub(r, "", alias); r = sub(r, "", extraDataMemebers); puts(os, r); } else { string r = INSTANCE_PROVIDER_CLASS_DECLARATION; r = sub(r, "", alias); r = sub(r, "", extraDataMemebers); puts(os, r); } } // Write the extrinsic provider function prototypes. { for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; string r = sub(EXTRINSIC_METHOD_PROVIDER_CLASS_DECLARATION, "", alias); r = sub(r, "", md->name); puts(os, r); } } // close class declaration putl(os, COMMON_PROVIDER_CLASS_DECLARATION_END); putl(os,"};"); nl(os); // end c++ specific part putl(os, "MI_END_NAMESPACE"); nl(os); putl(os, "#endif /* __cplusplus */"); nl(os); putl(os, "#endif /* _%s_Class_Provider_h */", alias.c_str()); nl(os); } //============================================================================== // // GenCppClassProviderHeader // // Generate class provider declaration // Support patching of methods // //============================================================================== static void GenCppClassProviderHeader( const MI_ClassDecl* cd) { string alias = AliasOf(cd->name); // create/patch provider class declaration file. const string path = ExpandPath(alias + "_Class_Provider.h"); bool append; vector data; { append = Exists(path.c_str()); if (append) { if (!Inhale(path.c_str(), data)) { err(ID_FAILED_TO_READ_FILE, "failed to read file: %s", path.c_str()); } } else { FILE* os = Fopen(path.c_str(), "w"); if (!os) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); GenCppClassProviderHeaderNewFile(os,cd); fclose(os); return; } } // patch existing file data.push_back(0); string str_data = &data[0]; /* remove \r*/ str_data = sub(str_data, "\r", ""); if (str_data.find(COMMON_PROVIDER_CLASS_DECLARATION_END) == string::npos) { err(ID_FAILED_TO_FIND_PATCH_MARKER, "failed to find patch marker (%s) in file %s", COMMON_PROVIDER_CLASS_DECLARATION_END, path.c_str()); } bool patched = false; // Add Load/Unload functions if missing if (str_data.find("void Unload(") == string::npos) { if (!patched) { Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str()); patched = true; } str_data = sub(str_data, COMMON_PROVIDER_CLASS_DECLARATION_END, COMMON_PROVIDER_LOAD_UNLOAD_DECLARATION COMMON_PROVIDER_CLASS_DECLARATION_END); } // Generate extrinsic method declarations (only new one). for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; string r = sub(EXTRINSIC_METHOD_PROVIDER_CLASS_DECLARATION, "", alias); r = sub(r, "", md->name); string name = string("Invoke_") + md->name; // Skip methods already found in file. if (str_data.find(name) != string::npos) continue; if (!patched) { Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str()); patched = true; } str_data = sub(str_data, COMMON_PROVIDER_CLASS_DECLARATION_END, r + COMMON_PROVIDER_CLASS_DECLARATION_END); } if (!patched) { Fprintf(s_stdout, ID_CHECKING, "Checking %s\n", path.c_str()); } else { // Rewrite the file. FILE* os = Fopen(path.c_str(), "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s",path.c_str()); put(os, "%s", &str_data[0]); fclose(os); } } //============================================================================== // // GenCppClassHeader // // Generate C++ part of the header file for the given MOF class. This part // contains the c++ wrapper class and provider class definition. // //============================================================================== static void GenCppClassHeader( Parser& /*parser*/, const MI_ClassDecl* cd, FILE* os ) { string alias = AliasOf(cd->name); // Comment box introducing C++ class definiti9on { string tmp = alias + "_Class"; PutCommentBox(os, tmp); nl(os); } // standard starting part putl(os, "#ifdef __cplusplus"); putl(os, "# include "); nl(os); putl(os, "MI_BEGIN_NAMESPACE"); nl(os); // instance itself GenCppClassDeclaration(os, cd, alias, cd->superClass, cd->numProperties, cd->properties); // gen parameters classes // Put method definitions and setters for each method parameter. for (size_t i = 0; !s_options.noProviders && i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; string param_alias = alias + "_" + md->name; if (Strcasecmp(cd->name, md->propagator) == 0 || providerClasses.find(cd->name) != providerClasses.end()) { GenCppClassDeclaration(os, md, param_alias, 0, md->numParameters, md->parameters); } } // provider class definition - if required if (providerClasses.find(cd->name) != providerClasses.end() && !s_options.noProviders) { GenCppClassProviderHeader(cd); } // end c++ specific part putl(os, "MI_END_NAMESPACE"); nl(os); putl(os, "#endif /* __cplusplus */"); nl(os); } static void _PatchLoadSignature( const string& alias, const string& path, vector& data) { /* special case: patch Load funciton signature */ string old_load = sub(OLD_PROVIDER_LOAD_PROTOTYPES, "", alias); data.push_back(0); string str_data = &data[0]; /* remove \r*/ str_data = sub(str_data, "\r", ""); if (str_data.find(old_load) != string::npos) { string new_load = sub(NEW_PROVIDER_LOAD_PROTOTYPES, "", alias); str_data = sub(str_data, old_load, new_load); // Rewrite the file. { FILE* os = Fopen(path.c_str(), "w"); if (!os) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str()); put(os, "%s", &str_data[0]); fclose(os); } } } /* Patches old cpp skeletons with load/unload funcitons */ static void _PatchLoadUnloadCPP( const string& alias, const string& path, vector& data) { /* special case: check if Load/Unload are declared */ string old_load = sub("_Class_Provider::Load(", "", alias); data.push_back(0); string str_data = &data[0]; /* remove \r*/ str_data = sub(str_data, "\r", ""); if (str_data.find(old_load) == string::npos) { string new_load = sub(COMMON_PROVIDER_CLASS_LOAD_UNLOAD_CPP, "", alias); str_data += "MI_BEGIN_NAMESPACE\n"; str_data += new_load; str_data += "MI_END_NAMESPACE\n"; // Rewrite the file. { FILE* os = Fopen(path.c_str(), "w"); if (!os) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str()); put(os, "%s", &str_data[0]); fclose(os); } } } //============================================================================== // // GenCppClassSource // // Generate the cpp source file for the given MOF class. This file contains the // the provider function stubs. // //============================================================================== static void GenCppClassSource(const MI_ClassDecl* cd) { const string alias = AliasOf(cd->name); // Open source file (refuse if it already exists). bool append; vector data; const string path = ExpandPath(alias + "_Class_Provider.cpp"); FILE* os = 0; { append = Exists(path.c_str()); if (append) { if (!Inhale(path.c_str(), data)) { err(ID_FAILED_TO_READ_FILE, "failed to read file: %s", path.c_str()); } _PatchLoadUnloadCPP(alias, path, data); os = Fopen(path.c_str(), "a"); if (!os) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } } else { os = Fopen(path.c_str(), "w"); if (!os) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } GenStatikGenLine(os); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); } } // Include required headers. if (!append) { putl(os, "#include "); putl(os, "#include \"%s_Class_Provider.h\"", alias.c_str()); nl(os); putl(os, "MI_BEGIN_NAMESPACE"); nl(os); } // spil out provider class implementation (stubs) if (!append) { string r; if (cd->flags & MI_FLAG_ASSOCIATION) { if (!s_options.association && CanGenerateAssocRoles(cd)) { r = ASSOCIATION_PROVIDER_CLASS_STUBS_CPP_ROLES; SubRoles(cd, r); } else r = ASSOCIATION_PROVIDER_CLASS_STUBS_CPP; } else if (cd->flags & MI_FLAG_INDICATION) r = INDICATION_PROVIDER_CLASS_STUBS_CPP; else r = INSTANCE_PROVIDER_CLASS_STUBS_CPP; r = sub(r, "", alias); puts(os, r); } // spil out provider extrinsic method stubs if (!append) { for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; string r = sub(EXTRINSIC_METHOD_CLASS_STUB_CPP, "", alias); r = sub(r, "", md->name); puts(os, r); } } // close namespace if (!append) { nl(os); putl(os, "MI_END_NAMESPACE"); } // only if we are updating exisitng one if (append) { bool patched = false; // Generate extrinsic method stubs (not already found in file). for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; string r = sub( "MI_BEGIN_NAMESPACE\n\n" EXTRINSIC_METHOD_CLASS_STUB_CPP "\nMI_END_NAMESPACE\n", "", alias); r = sub(r, "", md->name); string name = string("::Invoke_") + md->name; // Skip methods already found in file. if (strstr(&data[0], name.c_str())) continue; else { if (!patched) { Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str()); patched = true; } puts(os, r); } } if (!patched) { Fprintf(s_stdout, ID_CHECKING, "Checking %s\n", path.c_str()); } } // Close file. fclose(os); } //============================================================================== // // GenerateClassStub // // Generate wrapper for provider class // //============================================================================== static void GenerateClassStub(FILE* os, const MI_ClassDecl* cd) { const string alias = AliasOf(cd->name); // Generate extrinsic method stubs. { if (cd->flags & MI_FLAG_ASSOCIATION) { string r; if (!s_options.association && CanGenerateAssocRoles(cd)) { r = ASSOCIATION_PROVIDER_STUBS_CPP_ROLES; SubRoles(cd, r); } else r = ASSOCIATION_PROVIDER_STUBS_CPP; r = sub(r, "", alias); puts(os, r); } else if (cd->flags & MI_FLAG_INDICATION) { string r = INDICATION_PROVIDER_STUBS_CPP; r = sub(r, "", alias); puts(os, r); } else { if (HasKeys(cd)) { string r = INSTANCE_PROVIDER_STUBS_CPP; r = sub(r, "", alias); puts(os, r); } else { string r = COMMON_PROVIDER_STUBS_CPP; r = sub(r, "", alias); puts(os, r); } } } // generate all extrinsic method stubs (if new one) { for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; string r = sub(EXTRINSIC_METHOD_STUB_CPP, "", alias); r = sub(r, "", md->name); puts(os, r); } } } //============================================================================== // // GenClassHeader // // Generate the header file for the given MOF class. This file contains the // C structure definition, setter functions, parameter structures, and // provider function prototypes. // //============================================================================== static void GenClassHeader( Parser& parser, const MI_ClassDecl* cd, set& classIdentifiers) { const string alias = AliasOf(cd->name); // Refuse to generate same class more than once. if (generated_headers.find(cd->name) != generated_headers.end()) return; generated_headers.insert(cd->name); // Find direct dependencies of this class. vector deps; FindDirectDependencies(cd, deps); // Recurse on dependencies. for (size_t i = 0; i < deps.size(); i++) { const MI_ClassDecl* tcd = parser.findClassDecl(deps[i].c_str()); if (!tcd) err(ID_UNKNOWN_CLASS, "unknown class: %s", deps[i].c_str()); GenClassHeader(parser, tcd, classIdentifiers); } // Open class header file. string path = ExpandPath(alias + ".h"); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); FILE* os = Fopen(path.c_str(), "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); GenStatikGenLine(os); // Put comment header. PutCommentBox(os, WARNING); // Prevent multiple inclusion. putl(os, "#ifndef _%s_h", alias.c_str()); putl(os, "#define _%s_h", alias.c_str()); nl(os); // Include putl(os, "#include "); // Generate includes for direct dependencies. for (size_t i = 0; i < deps.size(); i++) { string al = AliasOf(deps[i]); putl(os, "#include \"%s.h\"", al.c_str()); } nl(os); // Put comment box for the class structure. List the key names for this // class. { putl(os, "/*"); PutRule(os); putl(os, "**"); putl(os, "** %s [%s]", alias.c_str(), cd->name); putl(os, "**"); putl(os, "** Keys:"); for (size_t i = 0; i < cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; if (pd->flags & MI_FLAG_KEY) putl(os, "** %s", pd->name); } putl(os, "**"); PutRule(os); putl(os, "*/"); nl(os); } // Put class structure definition with all its properties. if (cd->superClass) { putl(os, "typedef struct _%s /* extends %s */", alias.c_str(), cd->superClass); } else { putl(os, "typedef struct _%s", alias.c_str()); } putl(os, "{"); putl(os, " MI_Instance __instance;"); NameClassMap map; GenProperties(os, parser, cd, cd, map); putl(os, "}"); putl(os, "%s;", alias.c_str()); nl(os); // Generate a reference of this type (if not an association or indication). #if 0 if (!(cd->flags & MI_FLAG_ASSOCIATION || cd->flags & MI_FLAG_INDICATION)) #endif // Associations can be used as endpoints in other associations. { { const char T[] = "typedef struct __Ref\n" "{\n" " * value;\n" " MI_Boolean exists;\n" " MI_Uint8 flags;\n" "}\n" "_Ref;\n" "\n" "typedef struct __ConstRef\n" "{\n" " MI_CONST * value;\n" " MI_Boolean exists;\n" " MI_Uint8 flags;\n" "}\n" "_ConstRef;\n" "\n"; string r = sub(T, "", alias); puts(os, r); } { const char T[] = "typedef struct __Array\n" "{\n" " struct _** data;\n" " MI_Uint32 size;\n" "}\n" "_Array;\n" "\n" "typedef struct __ConstArray\n" "{\n" " struct _ MI_CONST* MI_CONST* data;\n" " MI_Uint32 size;\n" "}\n" "_ConstArray;\n" "\n" "typedef struct __ArrayRef\n" "{\n" " _Array value;\n" " MI_Boolean exists;\n" " MI_Uint8 flags;\n" "}\n" "_ArrayRef;\n" "\n" "typedef struct __ConstArrayRef\n" "{\n" " _ConstArray value;\n" " MI_Boolean exists;\n" " MI_Uint8 flags;\n" "}\n" "_ConstArrayRef;\n" "\n"; string r = sub(T, "", alias); puts(os, r); } } // Generate an external reference to the class RTTI instance. if (s_options.cpp || !s_options.noProviders) { putl(os, "MI_EXTERN_C MI_CONST MI_ClassDecl %s_rtti;", alias.c_str()); nl(os); } // Generate Instance function if (!s_options.noProviders) GenInstanceFunctions(os,cd); // Gen setters. if (!s_options.noProviders) { for (size_t i = 0; i < cd->numProperties; i++) GenSetter(os, cd, NULL, (MI_ParameterDecl*)cd->properties[i]); } // Put method definitions and setters for each method parameter. for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; GenParametersStruct(os, cd, md); // Generate convenience functions. if (!s_options.noProviders) { if (Strcasecmp(cd->name, md->propagator) == 0 || providerClasses.find(cd->name) != providerClasses.end()) { GenMethodFunctions(os, cd, md); } } // Generate parameter setter for "MIReturn". if (!s_options.noProviders) { MI_ParameterDecl pd; memset(&pd, 0, sizeof(pd)); pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT; pd.name = (char*)"MIReturn"; pd.type = md->returnType; pd.offset = sizeof(MI_Instance); pd.numQualifiers = md->numQualifiers; pd.qualifiers = md->qualifiers; GenSetter(os, cd, md, &pd); } if (!s_options.noProviders) { for (size_t j = 0; j < md->numParameters; j++) { const MI_ParameterDecl* pd = md->parameters[j]; // Skip stream parameters: if (pd->flags & MI_FLAG_STREAM) continue; GenSetter(os, cd, md, pd); } } } if (providerClasses.find(cd->name) != providerClasses.end()) { // Write the intrinsic provider function prototypes. if (!s_options.noProviders) { PutCommentBox(os, alias + " provider function prototypes"); nl(os); // Generate forward typedef for Self structure. putl(os,"/* The developer may optionally define this structure */"); putl(os, "typedef struct _%s_Self %s_Self;\n", alias.c_str(), alias.c_str()); if (cd->flags & MI_FLAG_ASSOCIATION) { string r; if (s_options.association || !CanGenerateAssocRoles(cd)) r = ASSOCIATION_PROVIDER_PROTOTYPES; else { r = ROLE_PROVIDER_PROTOTYPES; SubRoles(cd, r); } r = sub(r, "", alias); puts(os, r); } else if (cd->flags & MI_FLAG_INDICATION) { string r; r = INDICATION_PROVIDER_PROTOTYPES; r = sub(r, "", alias); puts(os, r); } else { if (HasKeys(cd)) { string r = INSTANCE_PROVIDER_PROTOTYPES; r = sub(r, "", alias); puts(os, r); } else { string r = COMMON_PROVIDER_PROTOTYPES; r = sub(r, "", alias); puts(os, r); } } } // Write the extrinsic provider function prototypes. if (!s_options.noProviders) { for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; string r = sub(EXTRINSIC_METHOD_PROTOTYPE, "", alias); r = sub(r, "", md->name); puts(os, r); } } } // Generate the class identifier: #if 0 { char id[33]; _MakeID(id); string classIdentifier = alias + "_" + id; classIdentifiers.insert(classIdentifier); putl(os, "#define %s\n", classIdentifier.c_str()); } #endif nl(os); // c++ part if (s_options.cpp) GenCppClassHeader(parser, cd, os); // End ifdef that Prevents multiple inclusion. putl(os, "#endif /* _%s_h */", alias.c_str()); // Close file. fclose(os); } //============================================================================== // // GenClassSource // // Generate the source file for the given MOF class. This file contains the // the provider function stubs. // //============================================================================== static void GenClassSource(const MI_ClassDecl* cd) { const string alias = AliasOf(cd->name); // Open source file (refuse if it already exists). bool append; vector data; const string path = ExpandPath(alias + ".c"); FILE* os = 0; { append = Exists(path.c_str()); if (append) { if (!Inhale(path.c_str(), data)) { err(ID_FAILED_TO_READ_FILE, "failed to read file: %s", path.c_str()); } _PatchLoadSignature(alias, path, data); os = Fopen(path.c_str(), "a"); if (!os) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } } else { os = Fopen(path.c_str(), "w"); if (!os) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } GenStatikGenLine(os); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); } } // Include required headers. if (!append) { putl(os, "#include "); putl(os, "#include \"%s.h\"", alias.c_str()); nl(os); } // Generate extrinsic method stubs. if (!append) { if (cd->flags & MI_FLAG_ASSOCIATION) { string r; if (s_options.association || !CanGenerateAssocRoles(cd)) r = ASSOCIATION_PROVIDER_STUBS; else { r = ROLE_PROVIDER_STUBS; SubRoles(cd, r); } r = sub(r, "", alias); puts(os, r); } else if (cd->flags & MI_FLAG_INDICATION) { string r = INDICATION_PROVIDER_STUBS; r = sub(r, "", alias); puts(os, r); } else { if (HasKeys(cd)) { string r = INSTANCE_PROVIDER_STUBS; r = sub(r, "", alias); puts(os, r); } else { string r = COMMON_PROVIDER_STUBS; r = sub(r, "", alias); puts(os, r); } } } bool patched = false; // Generate extrinsic method stubs (not already found in file). for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; string r = sub(EXTRINSIC_METHOD_STUB, "", alias); r = sub(r, "", md->name); string name = alias + "_Invoke_" + md->name; // Skip methods already found in file. if (append && strstr(&data[0], name.c_str())) continue; else { if (!patched) { Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str()); patched = true; } puts(os, r); } } if (!patched) { Fprintf(s_stdout, ID_CHECKING, "Checking %s\n", path.c_str()); } // Close file. fclose(os); } //============================================================================== // // PutString() // // Write a string literal. // //============================================================================== static void PutStringLiteral(FILE* os, const char* value) { put(os, "MI_T(\""); for (const char* p = value; *p; p++) { unsigned char c = (unsigned char)*p; if (c >= 32 && c <= 127) put(os, "%c", c); else put(os, "\\%04o", c); } put(os, "\")"); } //============================================================================== // // Localize() // // Add the string to the localization table and return an integer // identifier for that string. The localization id is one greater // than its index in the s_localizations. // //============================================================================== static vector s_localizations; static MI_Uint32 Localize(const string& msg) { for (size_t i = 0; i < s_localizations.size(); i++) { if (s_localizations[i] == msg) return (MI_Uint32)(i + 1); } s_localizations.push_back(msg); return (MI_Uint32)s_localizations.size(); } //============================================================================== // // GenScalarValueInitializer // // Put the value initializer for a property or qualifier value. // //============================================================================== static void GenScalarValueInitializer( FILE* os, MI_Type type, const void* value, bool localize) { // Unsatisfiable condition. assert(value != NULL); switch (type) { case MI_BOOLEAN: { put(os, "%s", *((MI_Boolean*)value) ? "1" : "0"); break; } case MI_UINT8: { put(os, "%u", *((MI_Uint8*)value)); break; } case MI_SINT8: { put(os, "%d", *((MI_Sint8*)value)); break; } case MI_UINT16: { put(os, "%u", *((MI_Uint16*)value)); break; } case MI_SINT16: { put(os, "%d", *((MI_Sint16*)value)); break; } case MI_UINT32: { MI_Uint32 x = *((MI_Uint32*)value); put(os, "%uU", x); break; } case MI_SINT32: { MI_Sint32 x = *((MI_Sint32*)value); if (x == -2147483647-1) put(os, "-2147483647-1"); else put(os, "%d", x); break; } case MI_UINT64: { put(os, "MI_ULL(" UINT64_FMT ")", *((MI_Uint64*)value)); break; } case MI_SINT64: { MI_Sint64 x = *((MI_Sint64*)value); if (x == -MI_LL(9223372036854775807)-MI_LL(1)) put(os, "-MI_LL(9223372036854775807)-MI_LL(1)"); else { if (x >= 0) put(os, "MI_LL(" SINT64_FMT ")", x); else put(os, "-MI_LL(" SINT64_FMT ")", -x); } break; } case MI_REAL32: { put(os, "(float)%g", *((MI_Real32*)value)); break; } case MI_REAL64: { put(os, "(double)%g", *((MI_Real64*)value)); break; } case MI_CHAR16: { put(os, "%u", *((MI_Char16*)value)); break; } case MI_DATETIME: { const MI_Datetime& x = *((MI_Datetime*)value); if (x.isTimestamp) { put(os,"{1,{{%u,%u,%u,%u,%u,%u,%u,%d}}}", x.u.timestamp.year, x.u.timestamp.month, x.u.timestamp.day, x.u.timestamp.hour, x.u.timestamp.minute, x.u.timestamp.second, x.u.timestamp.microseconds, x.u.timestamp.utc); } else { put(os,"{0,{{%u,%u,%u,%u,%u}}}", x.u.interval.days, x.u.interval.hours, x.u.interval.minutes, x.u.interval.seconds, x.u.interval.microseconds); } break; } case MI_STRING: { if (localize && s_options.localize) { MI_Uint32 id = Localize((char*)value); char buf[9]; Snprintf(buf, MI_COUNT(buf), "%u", id); PutStringLiteral(os, buf); } else PutStringLiteral(os, (char*)value); break; } default: // Unreachable! assert(0); break; } } //============================================================================== // // GenValue() // // Generate the value for a property declaration. // //============================================================================== static void GenValue( FILE* os, const string& stem, MI_Uint32 type, const void* value, bool localize) { MI_Type stype = (MI_Type)(type & ~MI_ARRAY_BIT); string typenameof = sub( TypeNameOf(stype), "String", "Char*"); // If the value is null, just return. if (!value) return; // Encode array or scalar. if (type & MI_ARRAY_BIT) { // Write the array data elements. putl(os, "static MI_CONST MI_%s %s_data_value[] =", typenameof.c_str(), stem.c_str()); putl(os, "{"); if (type == MI_STRINGA) { MI_StringA* arr = (MI_StringA*)value; for (MI_Uint32 i = 0; i < arr->size; i++) { put(os, " "); GenScalarValueInitializer(os, stype, arr->data[i], localize); putl(os, ","); } } else { MI_Uint8A* arr = (MI_Uint8A*)value; MI_Uint8* p = arr->data; for (MI_Uint32 i = 0; i < arr->size; i++) { put(os, " "); GenScalarValueInitializer(os, stype, p, localize); p += ScalarSizeOf(stype); putl(os, ","); } } putl(os, "};"); nl(os); // Write the array itself. putl(os, "static MI_CONST MI_Const%sA %s_value =", TypeNameOf(stype), stem.c_str()); putl(os, "{"); putl(os, " %s_data_value,", stem.c_str()); putl(os, " MI_COUNT(%s_data_value),", stem.c_str()); putl(os, "};"); nl(os); } else { put(os, "static MI_CONST MI_%s %s_value = ", typenameof.c_str(), stem.c_str()); GenScalarValueInitializer(os, (MI_Type)type, value, localize); putl(os, ";"); nl(os); } } //============================================================================== // // MI_Qualifier // // This function generates a qualifier. // //============================================================================== static void GenQualifier( Parser& parser, FILE* os, const MI_Qualifier* q, const string& stem_) { string stem = stem_ + "_" + q->name + "_qual"; /* Find qualifier declaration */ const MI_QualifierDecl* qd = parser.findQualifierDecl(q->name); if (!qd) err(ID_INTERNAL_ERROR, "internal error: %s(%u)", __FILE__, __LINE__); /* Generate the value */ GenValue(os, stem, q->type, q->value, (q->flavor & MI_FLAG_TRANSLATABLE) ? true : false); const char T[] = "static MI_CONST MI_Qualifier =\n" "{\n" " MI_T(\"\"),\n" " ,\n" " ,\n" " \n" "};\n" "\n"; string r = T; r = sub(r, "", stem); r = sub(r, "", q->name); r = sub(r, "", MakeType(q->type)); r = sub(r, "", MakeFlavor(q->flavor)); if (q->value) r = sub(r, "", "&" + stem + "_value"); else r = sub(r, "", "NULL"); puts(os, r); } //============================================================================== // // GenQualifiers() // // Generate a list of qualifier definitions. Return the number of qualifiers // generated (which may be less than numQualifiers due to excluded // qualifiers, such as boolean). // //============================================================================== static size_t GenQualifiers( Parser& parser, FILE* os, MI_Qualifier** qualifiers, MI_Uint32 numQualifiers, const string& stem) { size_t count = 0; if (numQualifiers == 0) return 0; /* Check if qualifiers are ignored */ if (s_options.ignoreAllQualifiers) return 0; // Generate qualifiers. for (MI_Uint32 i = 0; i < numQualifiers; i++) { const MI_Qualifier* q = qualifiers[i]; if (q->type == MI_BOOLEAN && !s_options.booleanQualifiers) continue; // Skip Description qualifier if -D option was given. if (eqi(q->name, "Description") && !s_options.descriptions) continue; // Skip Values qualifier if -V option was given. if (eqi(q->name, "Values") && !s_options.values) continue; // Skip ValueMap qualifier if -V option was given. if (eqi(q->name, "ValueMap") && !s_options.values) continue; // Skip Values qualifier if -M option was given. if (eqi(q->name, "MappingStrings") && !s_options.mappingStrings) continue; GenQualifier(parser, os, q, stem); count++; } // If no qualifiers were generated, return now to avoid creating an // empty array of qualifiers. if (count == 0) return 0; // Generate the array of qualifiers. putl(os, "static MI_Qualifier MI_CONST* MI_CONST %s_quals[] =", stem.c_str()); putl(os, "{"); for (MI_Uint32 i = 0; i < numQualifiers; i++) { const MI_Qualifier* q = qualifiers[i]; if (q->type == MI_BOOLEAN && !s_options.booleanQualifiers) continue; // Skip Description qualifier if -D option was given. if (eqi(q->name, "Description") && !s_options.descriptions) continue; // Skip Values qualifier if -v option was given. if (eqi(q->name, "Values") && !s_options.values) continue; // Skip ValueMap qualifier if -v option was given. if (eqi(q->name, "ValueMap") && !s_options.values) continue; // Skip Values qualifier if -M option was given. if (eqi(q->name, "MappingStrings") && !s_options.mappingStrings) continue; putl(os, " &%s_%s_qual,", stem.c_str(), q->name); } putl(os, "};"); nl(os); return count; } //============================================================================== // // HashCode() // // Compute a hash code of the given CIM identifier as follows. // // (name[0] << 16) | (name[len-1] << 8) | len // //============================================================================== static MI_Uint32 HashCode(const string& s) { MI_Uint32 n = (MI_Uint32)s.size(); if (n == 0) err(ID_INTERNAL_ERROR, "internal error: %s(%u)", __FILE__, __LINE__); return tolower((MI_Uint32)s[0])<<16 | tolower((MI_Uint32)s[n-1])<<8 | n; } //============================================================================== // // GenPropertyDecl() // // This function generates a property declaration (i.e., a structure // initialization of the MI_PropertyDecl structure) for the given property. // //============================================================================== static void GenPropertyDecl( Parser& parser, FILE* os, const MI_ClassDecl* cd, const MI_PropertyDecl* pd) { const string alias = AliasOf(cd->name); // Generate the qualifiers first. size_t numQualifiers = GenQualifiers( parser, os, pd->qualifiers, pd->numQualifiers, AliasOf(cd->name) + "_" + pd->name); // Generate the value. if (pd->value) GenValue(os, alias + "_" + pd->name, pd->type, pd->value, false); static const char T[] = "/* property . */\n" "static MI_CONST MI_PropertyDecl __prop =\n" "{\n" " , /* flags */\n" " , /* code */\n" " MI_T(\"\"), /* name */\n" " , /* qualifiers */\n" " , /* numQualifiers */\n" " , /* type */\n" " , /* className */\n" " , /* subscript */\n" " offsetof(, ), /* offset */\n" " , /* origin */\n" " , /* propagator */\n"; string r = T; r = sub(r, "", alias); r = subx(r, "", HashCode(pd->name)); r = sub(r, "", pd->name); r = sub(r, "", MakeFlags(pd->flags)); /* check for embedded instances */ if (MI_STRING == (pd->type & ~MI_ARRAY_BIT) && IsPropertyRefOrInstance(pd)) { r = sub(r, "", ((pd->type & MI_ARRAY_BIT) != 0 ? "MI_INSTANCEA" : "MI_INSTANCE")); } else r = sub(r, "", MakeType(pd->type)); if (numQualifiers) { string s = AliasOf(cd->name) + "_" + pd->name + "_quals"; r = sub(r, "", s); r = sub(r, "", "MI_COUNT(" + s + ")"); } else { r = sub(r, "", "NULL"); r = sub(r, "", "0"); } if (!GetPropertyClassname(pd).empty()) r = sub(r, "", Quote(GetPropertyClassname(pd))); else r = sub(r, "", "NULL"); r = subu(r, "", pd->subscript); r = sub(r, "", Quote(pd->origin)); r = sub(r, "", Quote(pd->propagator)); puts(os, r); // Put the value if any. if (pd->value) putl(os, " &%s_%s_value,", alias.c_str(), pd->name); else putl(os, " NULL,"); putl(os, "};"); nl(os); } //============================================================================== // // GenPropertyDecls() // // This function generates an array of property declaration objects for // the given class. // //============================================================================== static void GenPropertyDecls( Parser& parser, FILE* os, const MI_ClassDecl* cd) { const string alias = AliasOf(cd->name); // Generate a property declaration for each property. for (size_t i = 0; i < cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; // Only generate property declarations if this class is the owner. if (Strcasecmp(cd->name, pd->propagator) == 0) { GenPropertyDecl(parser, os, cd, pd); } } // Generate the array of property declarations (if any) if (cd->numProperties) { putl(os, "static MI_PropertyDecl MI_CONST* MI_CONST %s_props[] =", alias.c_str()); putl(os, "{"); for (size_t i = 0; i < cd->numProperties; i++) { const MI_PropertyDecl* pd = cd->properties[i]; const string ownerAlias = AliasOf(pd->propagator); putl(os, " &%s_%s_prop,", ownerAlias.c_str(), pd->name); } putl(os, "};"); } nl(os); } //============================================================================== // // GenParameterDecl() // // This function generates a parameter declaration for the given method and // class. // //============================================================================== static void GenParameterDecl( Parser& parser, FILE* os, const MI_ClassDecl* cd, const MI_MethodDecl* md, const MI_ParameterDecl* pd) { const string alias = AliasOf(cd->name); // Generate the qualifiers first. size_t numQualifiers = GenQualifiers( parser, os, pd->qualifiers, pd->numQualifiers, AliasOf(cd->name) + "_" + md->name + "_" + pd->name); static const char T[] = "/* parameter .(): */\n" "static MI_CONST MI_ParameterDecl ___param =\n" "{\n" " , /* flags */\n" " , /* code */\n" " MI_T(\"\"), /* name */\n" " , /* qualifiers */\n" " , /* numQualifiers */\n" " , /* type */\n" " , /* className */\n" " , /* subscript */\n" " , /* offset */\n" "};\n" "\n"; string r = T; if (pd->flags & MI_FLAG_STREAM) r = sub(r, "", "0xFFFFFFFF"); else r = sub(r, "", "offsetof(_, )"); r = sub(r, "", alias); r = subx(r, "", HashCode(pd->name)); r = sub(r, "", md->name); r = sub(r, "", pd->name); r = sub(r, "", MakeFlags(pd->flags)); /* check for embedded instances */ if (MI_STRING == (pd->type & ~MI_ARRAY_BIT) && IsPropertyRefOrInstance(pd)) { r = sub(r, "", ((pd->type & MI_ARRAY_BIT) != 0 ? "MI_INSTANCEA" : "MI_INSTANCE")); } else r = sub(r, "", MakeType(pd->type)); if (numQualifiers) { string s = AliasOf(cd->name) + "_" + md->name + "_" +pd->name +"_quals"; r = sub(r, "", s); r = sub(r, "", "MI_COUNT(" + s + ")"); } else { r = sub(r, "", "NULL"); r = sub(r, "", "0"); } if (!GetPropertyClassname(pd).empty()) r = sub(r, "", Quote(GetPropertyClassname(pd))); else r = sub(r, "", "NULL"); r = subu(r, "", pd->subscript); puts(os, r); } //============================================================================== // // GenMethodDecl() // // This function generates a method declaration for the given class. // //============================================================================== static void GenMethodDecl( Parser& parser, FILE* os, const MI_ClassDecl* cd, const MI_MethodDecl* md) { // Generate the qualifiers first. size_t numQualifiers = GenQualifiers( parser, os, md->qualifiers, md->numQualifiers, AliasOf(cd->name) + "_" + md->name); const string alias = AliasOf(cd->name); // Generate each parameter declartions. for (size_t i = 0; i < md->numParameters; i++) { const MI_ParameterDecl* pd = md->parameters[i]; GenParameterDecl(parser, os, cd, md, pd); } // Generate the return parameter declarations. { MI_ParameterDecl pd; memset(&pd, 0, sizeof(pd)); pd.flags = MI_FLAG_PARAMETER|MI_FLAG_OUT; pd.name = (char*)"MIReturn"; pd.type = md->returnType; pd.offset = sizeof(MI_Instance); pd.numQualifiers = md->numQualifiers; pd.qualifiers = md->qualifiers; GenParameterDecl(parser, os, cd, md, &pd); } // Generate the parmaeter declaration array. { putl(os, "static MI_ParameterDecl MI_CONST* MI_CONST %s_%s_params[] =", alias.c_str(), md->name); putl(os, "{"); putl(os, " &%s_%s_MIReturn_param,", alias.c_str(), md->name); for (size_t i = 0; i < md->numParameters; i++) { const MI_ParameterDecl* pd = md->parameters[i]; putl(os, " &%s_%s_%s_param,", alias.c_str(), md->name, pd->name); } putl(os, "};"); nl(os); } static const char T[] = "/* method .() */\n" "MI_CONST MI_MethodDecl __rtti =\n" "{\n" " , /* flags */\n" " , /* code */\n" " MI_T(\"\"), /* name */\n" " , /* qualifiers */\n" " , /* numQualifiers */\n" " __params, /* parameters */\n" " MI_COUNT(__params), /* numParameters */\n" " sizeof(_), /* size */\n" " , /* returnType */\n" " , /* origin */\n" " , /* propagator */\n" " &, /* schema */\n" " , /* method */\n" "};\n" "\n"; string r = T; if (s_options.schema.size()) r = sub(r, "", s_options.schema.c_str()); else r = sub(r, "", "schemaDecl"); r = sub(r, "", alias); r = subx(r, "", HashCode(md->name)); r = sub(r, "", md->name); r = sub(r, "", MakeFlags(md->flags)); /* check for embedded instances */ if (MI_STRING == (md->returnType & ~MI_ARRAY_BIT) && ExistInstanceQualifier(md)) { r = sub(r, "", ((md->returnType & MI_ARRAY_BIT) != 0 ? "MI_INSTANCEA" : "MI_INSTANCE")); } else r = sub(r, "", MakeType(md->returnType)); r = sub(r, "", Quote(md->origin)); r = sub(r, "", Quote(md->propagator)); // If there is no provider for this class, set to NULL if (providerClasses.find(cd->name) == providerClasses.end()) { r = sub(r, "", "NULL"); } else { static const char T_template[] = "(MI_ProviderFT_Invoke)_Invoke_"; string t = T_template; t = sub(t, "", alias); t = sub(t, "", md->name); r = sub(r, "", t); } if (numQualifiers) { string s = AliasOf(cd->name) + "_" + md->name + "_quals"; r = sub(r, "", s); r = sub(r, "", "MI_COUNT(" + s + ")"); } else { r = sub(r, "", "NULL"); r = sub(r, "", "0"); } puts(os, r); } //============================================================================== // // GenMethodDecls() // // This function generates a method declaration array for the given class. // //============================================================================== static void GenMethodDecls( Parser& parser, FILE* os, const MI_ClassDecl* cd) { const string alias = AliasOf(cd->name); if (cd->numMethods == 0) return; // Generate a property declaration for each property. for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; // Only generate this definition for the propagating class unless // the derived class is a class for which there will be a provider. // In that case we must generate this declaration so it can hold // the extrinsic method stub for that provider. if (Strcasecmp(cd->name, md->propagator) == 0 || providerClasses.find(cd->name) != providerClasses.end()) { GenMethodDecl(parser, os, cd, md); } } // Generate the array of property declarations. putl(os, "static MI_MethodDecl MI_CONST* MI_CONST %s_meths[] =", alias.c_str()); putl(os, "{"); for (size_t i = 0; i < cd->numMethods; i++) { const MI_MethodDecl* md = cd->methods[i]; if (Strcasecmp(cd->name, md->propagator) == 0 || providerClasses.find(cd->name) != providerClasses.end()) { putl(os, " &%s_%s_rtti,", alias.c_str(), md->name); } else { const string ownerAlias = AliasOf(md->propagator); putl(os, " &%s_%s_rtti,", ownerAlias.c_str(), md->name); } } putl(os, "};"); nl(os); } //============================================================================== // // GenFunctionTable() // // This function generates the function table for the given class. This // table contains pointers to the provider stubs. // //============================================================================== static void GenFunctionTable( FILE* os, const MI_ClassDecl* cd) { const char ROLES[] = "static void MI_CALL _AssociatorInstances(\n" " _Self* self,\n" " MI_Context* context,\n" " const MI_Char* nameSpace,\n" " const MI_Char* className,\n" " const MI_Instance* instanceName,\n" " const MI_Char* resultClass,\n" " const MI_Char* role,\n" " const MI_Char* resultRole,\n" " const MI_PropertySet* propertySet,\n" " MI_Boolean keysOnly,\n" " const MI_Filter* filter)\n" "{\n" " if (_IsA(instanceName))\n" " {\n" " if (_Match(role, MI_T(\"\")) && \n" " _Match(resultRole, MI_T(\"\")))\n" " {\n" " _AssociatorInstances(\n" " self, \n" " context, \n" " nameSpace, \n" " className, \n" " (*)instanceName, \n" " resultClass, \n" " propertySet, \n" " keysOnly, \n" " filter);\n" " return;\n" " }\n" " }\n" "\n" " if (_IsA(instanceName))\n" " {\n" " if (_Match(role, MI_T(\"\")) && \n" " _Match(resultRole, MI_T(\"\")))\n" " {\n" " _AssociatorInstances(\n" " self, \n" " context, \n" " nameSpace, \n" " className, \n" " (*)instanceName, \n" " resultClass, \n" " propertySet, \n" " keysOnly, \n" " filter);\n" " return;\n" " }\n" " }\n" "\n" " MI_PostResult(context, MI_RESULT_OK);\n" "}\n" "\n" "static void MI_CALL _ReferenceInstances(\n" " _Self* self,\n" " MI_Context* context,\n" " const MI_Char* nameSpace,\n" " const MI_Char* className,\n" " const MI_Instance* instanceName,\n" " const MI_Char* role,\n" " const MI_PropertySet* propertySet,\n" " MI_Boolean keysOnly,\n" " const MI_Filter* filter)\n" "{\n" " if (_IsA(instanceName))\n" " {\n" " if (_Match(role, MI_T(\"\")))\n" " {\n" " _ReferenceInstances(\n" " self, \n" " context, \n" " nameSpace, \n" " className, \n" " (*)instanceName, \n" " propertySet, \n" " keysOnly, \n" " filter);\n" " return;\n" " }\n" " }\n" "\n" " if (_IsA(instanceName))\n" " {\n" " if (_Match(role, MI_T(\"\")))\n" " {\n" " _ReferenceInstances(\n" " self, \n" " context, \n" " nameSpace, \n" " className, \n" " (*)instanceName, \n" " propertySet, \n" " keysOnly, \n" " filter);\n" " return;\n" " }\n" " }\n" "\n" " MI_PostResult(context, MI_RESULT_OK);\n" "}\n" "\n"; const string alias = AliasOf(cd->name); // Generate the array of property declarations. if (cd->flags & MI_FLAG_ASSOCIATION) { if (!s_options.association && CanGenerateAssocRoles(cd)) { string r = ROLES; r = sub(r, "", alias); SubRoles(cd, r); puts(os, r); } const char T[] = "static MI_CONST MI_ProviderFT _funcs =\n" "{\n" " (MI_ProviderFT_Load)_Load,\n" " (MI_ProviderFT_Unload)_Unload,\n" " (MI_ProviderFT_GetInstance),\n" " (MI_ProviderFT_EnumerateInstances)_EnumerateInstances,\n" " (MI_ProviderFT_CreateInstance)_CreateInstance,\n" " (MI_ProviderFT_ModifyInstance)_ModifyInstance,\n" " (MI_ProviderFT_DeleteInstance)_DeleteInstance,\n" " (MI_ProviderFT_AssociatorInstances)_AssociatorInstances,\n" " (MI_ProviderFT_ReferenceInstances)_ReferenceInstances,\n" " (MI_ProviderFT_EnableIndications)NULL,\n" " (MI_ProviderFT_DisableIndications)NULL,\n" " (MI_ProviderFT_Subscribe)NULL,\n" " (MI_ProviderFT_Unsubscribe)NULL,\n" " (MI_ProviderFT_Invoke)NULL,\n" "};\n" "\n"; /* Create substitution for */ string gi; if (Contains(s_options.noGetInstance, cd->name)) gi = "NULL"; else gi = sub("_GetInstance", "", alias); string r = sub(T, "", alias); r = sub(r, "", gi); puts(os, r); } else if (cd->flags & MI_FLAG_INDICATION) { const char T[] = "static MI_CONST MI_ProviderFT _funcs =\n" "{\n" " (MI_ProviderFT_Load)_Load,\n" " (MI_ProviderFT_Unload)_Unload,\n" " (MI_ProviderFT_GetInstance)NULL,\n" " (MI_ProviderFT_EnumerateInstances)NULL,\n" " (MI_ProviderFT_CreateInstance)NULL,\n" " (MI_ProviderFT_ModifyInstance)NULL,\n" " (MI_ProviderFT_DeleteInstance)NULL,\n" " (MI_ProviderFT_AssociatorInstances)NULL,\n" " (MI_ProviderFT_ReferenceInstances)NULL,\n" " (MI_ProviderFT_EnableIndications)_EnableIndications,\n" " (MI_ProviderFT_DisableIndications)_DisableIndications,\n" " (MI_ProviderFT_Subscribe)_Subscribe,\n" " (MI_ProviderFT_Unsubscribe)_Unsubscribe,\n" " (MI_ProviderFT_Invoke)NULL,\n" "};\n" "\n"; string r = sub(T, "", alias); puts(os, r); } else { const char T1[] = "static MI_CONST MI_ProviderFT _funcs =\n" "{\n" " (MI_ProviderFT_Load)_Load,\n" " (MI_ProviderFT_Unload)_Unload,\n" " (MI_ProviderFT_GetInstance),\n" " (MI_ProviderFT_EnumerateInstances)_EnumerateInstances,\n" " (MI_ProviderFT_CreateInstance)_CreateInstance,\n" " (MI_ProviderFT_ModifyInstance)_ModifyInstance,\n" " (MI_ProviderFT_DeleteInstance)_DeleteInstance,\n" " (MI_ProviderFT_AssociatorInstances)NULL,\n" " (MI_ProviderFT_ReferenceInstances)NULL,\n" " (MI_ProviderFT_EnableIndications)NULL,\n" " (MI_ProviderFT_DisableIndications)NULL,\n" " (MI_ProviderFT_Subscribe)NULL,\n" " (MI_ProviderFT_Unsubscribe)NULL,\n" " (MI_ProviderFT_Invoke)NULL,\n" "};\n" "\n"; const char T2[] = "static MI_CONST MI_ProviderFT _funcs =\n" "{\n" " (MI_ProviderFT_Load)_Load,\n" " (MI_ProviderFT_Unload)_Unload,\n" " (MI_ProviderFT_GetInstance)NULL,\n" " (MI_ProviderFT_EnumerateInstances)NULL,\n" " (MI_ProviderFT_CreateInstance)NULL,\n" " (MI_ProviderFT_ModifyInstance)NULL,\n" " (MI_ProviderFT_DeleteInstance)NULL,\n" " (MI_ProviderFT_AssociatorInstances)NULL,\n" " (MI_ProviderFT_ReferenceInstances)NULL,\n" " (MI_ProviderFT_EnableIndications)NULL,\n" " (MI_ProviderFT_DisableIndications)NULL,\n" " (MI_ProviderFT_Subscribe)NULL,\n" " (MI_ProviderFT_Unsubscribe)NULL,\n" " (MI_ProviderFT_Invoke)NULL,\n" "};\n" "\n"; // Only generate intrinsics for keyless classes: if (HasKeys(cd)) { /* Create substitution for */ string gi; if (Contains(s_options.noGetInstance, cd->name)) gi = "NULL"; else gi = sub("_GetInstance", "", alias); string r = sub(T1, "", alias); r = sub(r, "", gi); puts(os, r); } else { string r = sub(T2, "", alias); puts(os, r); } } } //============================================================================== // // GenClassDecl() // // This function generates the class declaration for a MOF clas. // //============================================================================== static void GenClassDecl( Parser& parser, FILE* os, const MI_ClassDecl* cd) { const string alias = AliasOf(cd->name); // Generate the qualifiers first. size_t numQualifiers = GenQualifiers( parser, os, cd->qualifiers, cd->numQualifiers, AliasOf(cd->name)); const char T[] = "/* class */\n" "MI_CONST MI_ClassDecl _rtti =\n" "{\n" " , /* flags */\n" " , /* code */\n" " MI_T(\"\"), /* name */\n" " , /* qualifiers */\n" " , /* numQualifiers */\n" " , /* properties */\n" " , /* numProperties */\n" " sizeof(), /* size */\n" " , /* superClass */\n" " , /* superClassDecl */\n" "" " &, /* schema */\n" " , /* functions */\n" "};\n"; string r = T; r = sub(r, "", alias); r = subx(r, "", HashCode(cd->name)); r = sub(r, "", cd->name); r = sub(r, "", MakeFlags(cd->flags)); if (s_options.schema.size()) r = sub(r, "", s_options.schema.c_str()); else r = sub(r, "", "schemaDecl"); if (s_options.cpp || !s_options.noProviders) r = sub(r, "", ""); else r = sub(r, "", "static "); if (cd->numProperties) { string s = alias + "_props"; r = sub(r, "", s); r = sub(r, "", "MI_COUNT(" + s + ")"); } else { r = sub(r, "", "NULL"); r = sub(r, "", "0"); } if (numQualifiers) { string s = alias + "_quals"; r = sub(r, "", s); r = sub(r, "", "MI_COUNT(" + s + ")"); } else { r = sub(r, "", "NULL"); r = sub(r, "", "0"); } if (cd->superClass) { r = sub(r, "", Quote(cd->superClass)); string t = "&" + AliasOf(cd->superClass) + "_rtti"; r = sub(r, "", t); } else { r = sub(r, "", "NULL"); r = sub(r, "", "NULL"); } if (cd->numMethods) { const char T2[] = " _meths, /* methods */\n" " MI_COUNT(_meths), /* numMethods */\n"; string t2 = sub(T2, "", alias); r = sub(r, "", t2); } else { const char T2[] = " NULL, /* methods */\n" " 0, /* numMethods */\n"; r = sub(r, "", T2); } if (providerClasses.find(cd->name) == providerClasses.end()) { r = sub(r, "", "NULL"); } else { r = sub(r, "", "&" + alias + "_funcs"); } puts(os, r); nl(os); } //============================================================================== // // GenQualifierDecl() // // This function generates a single qualifier declaration. // //============================================================================== static void GenQualifierDecl(FILE* os, const MI_QualifierDecl* qd) { const char T[] = "static MI_CONST MI_QualifierDecl _qual_decl =\n" "{\n" " MI_T(\"\"), /* name */\n" " , /* type */\n" " , /* scope */\n" " , /* flavor */\n" " , /* subscript */\n" " , /* value */\n" "};\n" "\n"; string stem = string(qd->name) + "_qual_decl"; // Generate the value. if (qd->value) { if (qd->flavor & MI_FLAG_TRANSLATABLE) GenValue(os, stem, qd->type, qd->value, true); else GenValue(os, stem, qd->type, qd->value, false); } string r = T; r = sub(r, "", qd->name); r = sub(r, "", MakeType(qd->type)); r = subu(r, "", qd->subscript); r = sub(r, "", MakeFlavor(qd->flavor)); r = sub(r, "", MakeScope(qd->scope)); if (qd->value) r = sub(r, "", "&" + stem + "_value"); else r = sub(r, "", "NULL"); puts(os, r); } //============================================================================== // // GenQualifierDecls() // // This function generates an array of qualifier declarations. // //============================================================================== size_t GenQualifierDecls(Parser& parser, FILE* os) { size_t count = 0; /* Check if qualifiers are ignored */ if (s_options.ignoreAllQualifiers) return 0; // Put the comment box. PutCommentBox(os, "Qualifier declarations"); nl(os); vector names; parser.getQualifierDeclNames(names); // Generate the individual qualifier declarations. for (size_t i = 0; i < names.size(); i++) { const MI_QualifierDecl* qd = parser.findQualifierDecl(names[i]); if (!qd) { err(ID_UNKNOWN_QUALIFIER, "unknown qualifier: %s", names[i].c_str()); } // Do not generate standard qualifiers. if (!s_options.standardQualifiers && FindStandardQualifierDecl(qd->name)) { continue; } GenQualifierDecl(os, qd); count++; } // Generate the qualifier declaration array. if (count) { putl(os, "static MI_QualifierDecl MI_CONST* MI_CONST qualifierDecls[] ="); putl(os, "{"); for (size_t i = 0; i < names.size(); i++) { const MI_QualifierDecl* qd = parser.findQualifierDecl(names[i]); // Do not generate standard qualifiers. if (!s_options.standardQualifiers && FindStandardQualifierDecl(qd->name)) { continue; } if (!qd) { err(ID_UNKNOWN_QUALIFIER, "unknown qualifier: %s", names[i].c_str()); } put(os, " &%s_qual_decl,\n", qd->name); } putl(os, "};"); nl(os); } return count; } //============================================================================== // // GenClassSchema() // // This function generates one class for the schema source file. // //============================================================================== static void GenClassSchema( Parser& parser, FILE* os, const MI_ClassDecl* cd, const vector& classNames) { // Prevent recursion. { if (s_generated.find(cd->name) != s_generated.end()) return; s_generated.insert(cd->name); } // Find direct dependencies of this class. vector deps; FindDirectDependencies(cd, deps); // Recurse on dependencies. for (size_t i = 0; i < deps.size(); i++) { const MI_ClassDecl* tcd = parser.findClassDecl(deps[i].c_str()); if (!tcd) err(ID_UNKNOWN_CLASS, "unknown class: %s", deps[i].c_str()); GenClassSchema(parser, os, tcd, classNames); } // Refuse to generate same class more than once. if (generated_classes.find(cd->name) != generated_classes.end()) return; generated_classes.insert(cd->name); // Generate comment box for this class. const string al = AliasOf(cd->name); PutCommentBox(os, al); nl(os); // Generate declarations. GenPropertyDecls(parser, os, cd); // Generate method declarations. GenMethodDecls(parser, os, cd); // Generate provider function table. if (providerClasses.find(cd->name) != providerClasses.end()) GenFunctionTable(os, cd); // Generate the class declaration. GenClassDecl(parser, os, cd); } //============================================================================== // // GenSchemaSourceFile() // // This function generates the schema.c source file, which contains the // qualifier declarations, class declarations, and the schema object that // refers to arrays of each. // //============================================================================== static void GenSchemaSourceFile( Parser& parser, const vector& classNames, const set& /*classIdentifiers*/) { // Open the file. string path = ExpandPath("schema.c"); FILE* os = Fopen(path.c_str(), "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); GenStatikGenLine(os); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); // Print warning box. PutCommentBox(os, WARNING); // Include header. putl(os, "#include "); putl(os, "#include "); bool generateMatch = false; // Include each direct header file (headers will indirectly include others). for (size_t i = 0; i < classNames.size(); i++) { // Find the class. const MI_ClassDecl* cd = parser.findClassDecl(classNames[i].c_str()); if (!cd) err(ID_UNKNOWN_CLASS, "unknown class: %s", classNames[i].c_str()); if (!s_options.association && (cd->flags & MI_FLAG_ASSOCIATION) && CanGenerateAssocRoles(cd)) { generateMatch = true; } // Include the class header. const string alias = AliasOf(cd->name); putl(os, "#include \"%s.h\"", alias.c_str()); } nl(os); // Generate forward reference to schema declaration. { PutCommentBox(os, "Schema Declaration"); nl(os); if (s_options.schema.size()) putl(os, "extern MI_SchemaDecl %s;", s_options.schema.c_str()); else putl(os, "extern MI_SchemaDecl schemaDecl;"); nl(os); } // Generate match function (if necessary) if (generateMatch) { const char MATCH[] = "static int _Match(const MI_Char* p, const MI_Char* q)\n" "{\n" " if (!p || !q || !p[0] || !q[0])\n" " return 1;\n" "\n" " while (*p && *q)\n" " if (toupper((MI_Uint16)*p++) - toupper((MI_Uint16)*q++))\n" " return 0;\n" "\n" " return *p == '\\0' && *q == '\\0';\n" "}\n" "\n"; PutCommentBox(os, "_Match()"); nl(os); puts(os, MATCH); } // Gen qualifier declarations. size_t numQualifierDecls = GenQualifierDecls(parser, os); // Generate class declarations. for (size_t i = 0; i < classNames.size(); i++) { // Find the class. const MI_ClassDecl* cd = parser.findClassDecl(classNames[i].c_str()); if (!cd) err(ID_UNKNOWN_CLASS, "unknown class: %s", classNames[i].c_str()); GenClassSchema(parser, os, cd, classNames); } // Generate server declaration. PutCommentBox(os, "__mi_server"); nl(os); putl(os, "MI_Server* __mi_server;"); // Generate MI_SchemaDecl. PutCommentBox(os, "Schema"); nl(os); putl(os, "static MI_ClassDecl MI_CONST* MI_CONST classes[] ="); putl(os, "{"); set::const_iterator p = generated_classes.begin(); set::const_iterator end = generated_classes.end(); for (; p != end; p++) { // Find the class. const MI_ClassDecl* cd = parser.findClassDecl((*p).c_str()); if (!cd) err(ID_UNKNOWN_CLASS, "unknown class: %s", (*p).c_str()); const string alias = AliasOf(cd->name); putl(os, " &%s_rtti,", alias.c_str()); } putl(os, "};"); nl(os); { static const char T[] = "MI_SchemaDecl =\n" "{\n" " , /* qualifierDecls */\n" " , /* numQualifierDecls */\n" " classes, /* classDecls */\n" " MI_COUNT(classes), /* classDecls */\n" "};\n" "\n"; string r = T; if (s_options.schema.size()) r = sub(r, "", s_options.schema); else r = sub(r, "", "schemaDecl"); if (numQualifierDecls) { r = sub(r, "", "qualifierDecls"); r = sub(r, "", "MI_COUNT(qualifierDecls)"); } else { r = sub(r, "", "NULL"); r = sub(r, "", "0"); } puts(os, r); } // Generate MI_Server methods. { const char T[] = "MI_Result MI_CALL MI_Server_GetVersion(\n" " MI_Uint32* version)" "{\n" " return __mi_server->serverFT->GetVersion(version);\n" "}\n" "\n" "MI_Result MI_CALL MI_Server_GetSystemName(\n" " const MI_Char** systemName)\n" "{\n" " return __mi_server->serverFT->GetSystemName(systemName);\n" "}\n"; PutCommentBox(os, "MI_Server Methods"); nl(os); puts(os, T); nl(os); } #if 0 // Generate cross-check with class identifiers: { set::const_iterator first = classIdentifiers.begin(); set::const_iterator last = classIdentifiers.end(); while (first != last) { const string& s = *first++; putl(os, "#ifndef %s", s.c_str()); putl(os, "# error \"generational inconsistency: %s is undefined\"", s.c_str()); putl(os, "#endif\n"); } } #endif // Close the file. fclose(os); } //============================================================================== // // GenerateMI_Main() // // This function generates the MI_Main() entry point. It returns a // string instead of writing to the output stream directory. This is to // support patching of module.c. // //============================================================================== string GenerateMI_Main() { string result; // MI_Main() preamble: { string r = MODULE_C_TEMPLATE_2; if (s_options.schema.size()) r = sub(r, "", s_options.schema); else r = sub(r, "", "schemaDecl"); if (s_options.entryPoint.size()) r = sub(r, "", s_options.entryPoint); else r = sub(r, "", "MI_Main"); result += r; } // MI_Main() flags: { string r; if (!s_options.ignoreAllQualifiers) { if (!s_options.standardQualifiers) r += " module.flags |= MI_MODULE_FLAG_STANDARD_QUALIFIERS;\n"; if (s_options.descriptions) r += " module.flags |= MI_MODULE_FLAG_DESCRIPTIONS;\n"; if (s_options.values) r += " module.flags |= MI_MODULE_FLAG_VALUES;\n"; if (s_options.mappingStrings) r += " module.flags |= MI_MODULE_FLAG_MAPPING_STRINGS;\n"; if (s_options.booleanQualifiers) r += " module.flags |= MI_MODULE_FLAG_BOOLEANS;\n"; } if (s_options.cpp) r += " module.flags |= MI_MODULE_FLAG_CPLUSPLUS;\n"; if (s_options.localize) r += " module.flags |= MI_MODULE_FLAG_LOCALIZED;\n"; if (s_options.filterSupport) r += " module.flags |= MI_MODULE_FLAG_FILTER_SUPPORT;\n"; result += r; } // MI_Main() postamble: { string r = MODULE_C_TEMPLATE_3; if (s_options.schema.size()) r = sub(r, "", s_options.schema); else r = sub(r, "", "schemaDecl"); { char buf[64]; Snprintf(buf, MI_COUNT(buf), "MI_MAKE_VERSION(%u,%u,%u)", MI_MAJOR, MI_MINOR, MI_REVISON); r = sub(r, "", buf); } result += r; } return result; } //============================================================================== // // SkipSpace() // // Skip over whitespace. Return true when the '\0' character is found. // //============================================================================== static bool SkipSpace(const char*& p) { while (isspace((unsigned char)*p)) p++; return *p == '\0'; } //============================================================================== // // GenModuleSourceFile() // // This function generates the module.c source file, which contains the // MI_Main() entry point. // //============================================================================== static void GenModuleSourceFile() { // Open the file. const string path = ExpandPath("module.c"); if (Exists(path.c_str())) { // Read file into memory. vector data; if (!Inhale(path.c_str(), data)) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } // Replace MI_Main() body with new MI_Main() body. const char* start = &data[0]; const char* end = &data[data.size()-1]; const char* p = start; bool found = false; // Match "MI_EXTERN_C MI_EXPORT MI_Module* MI_MAIN_CALL MI_Main(...) {} while (p != end) { const char* first = p; // Expect 'MI_EXTERN_C' [optionally] if (strncmp(p, "MI_EXTERN_C", 11) == 0) { p += 11; // Skip whitespace: if (SkipSpace(p)) break; } // Expect 'MI_EXPORT' if (strncmp(p, "MI_EXPORT", 9) != 0) { p++; continue; } p += 9; // Skip whitespace: if (SkipSpace(p)) break; // Expect 'MI_Module' if (strncmp(p, "MI_Module", 9) != 0) { p++; continue; } p += 9; // Skip whitespace: if (SkipSpace(p)) break; // Expect '*' if (*p != '*') { p++; continue; } p++; // Skip whitespace: if (SkipSpace(p)) break; // Skip 'MI_MAIN_CALL' { const char TMP[] = "MI_MAIN_CALL"; if (strncmp(p, TMP, sizeof(TMP)-1) == 0) p += sizeof(TMP)-1; } // Skip whitespace: if (SkipSpace(p)) break; // Expect 'MI_Main' { const char *TMP = (s_options.entryPoint.empty() ? "MI_Main" : s_options.entryPoint.c_str()); if (strncmp(p, TMP, strlen(TMP)) != 0) { p++; continue; } p += strlen(TMP); } // Skip whitespace: if (SkipSpace(p)) break; // Expect '(' if (*p != '(') { p++; continue; } // Skip non ')' chars. while (*p && *p != ')') p++; // Expect ')' if (*p != ')') { p++; continue; } p++; // Skip whitespace: if (SkipSpace(p)) break; // Expect '{' if (*p != '{') { p++; continue; } // Skip non '}' chars. while (*p && *p != '}') p++; // Expect '}' if (*p != '}') { p++; continue; } p++; const char* last = p; found = true; string tmp = &data[0]; string r; r.append(start, first - start); r.append(GenerateMI_Main()); r.append(last); // Rewrite the file. { FILE* os = Fopen(path.c_str(), "w"); if (!os) { err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); } Fprintf(s_stdout, ID_PATCHING, "Patching %s\n", path.c_str()); put(os, "%s", r.c_str()); fclose(os); } break; } // If MI_Main() not found. if (!found) { err(ID_FAILED_TO_PATCH_MODULE, "Unable to patch module.c: cannot find %s() body: %s", (s_options.entryPoint.empty() ? "MI_Main" : s_options.entryPoint.c_str()), path.c_str()); } return; } FILE* os = Fopen(path.c_str(), "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); GenStatikGenLine(os); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); // Generate part 1: { string r = MODULE_C_TEMPLATE_1; if (s_options.schema.size()) r = sub(r, "", s_options.schema); else r = sub(r, "", "schemaDecl"); put(os, "%s", r.c_str()); } // Generate MI_Main() { string r = GenerateMI_Main(); put(os, "%s\n", r.c_str()); } // Close the file. fclose(os); } //============================================================================== // // GenModuleCppSourceFile() // // This function generates the module.cpp source file, which contains the // Module class definiiton. // //============================================================================== static void GenModuleCppSourceFile() { // Open the file. const string path = ExpandPath("module.cpp"); if (Exists(path.c_str())) { Fprintf(s_stdout, ID_SKIPPING, "Skipping %s\n", path.c_str()); return; } FILE* os = Fopen(path.c_str(), "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); // simple template - no parameters { put(os, "%s\n", MODULE_CPP_TEMPLATE); } // Close the file. fclose(os); } //============================================================================== // // GenModuleCppHeaderFile() // // This function generates the module.h header file, which contains the // Module class declaration. // //============================================================================== static void GenModuleCppHeaderFile() { // Open the file. const string path = ExpandPath("module.h"); if (Exists(path.c_str())) { Fprintf(s_stdout, ID_SKIPPING, "Skipping %s\n", path.c_str()); return; } FILE* os = Fopen(path.c_str(), "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); // simple template - no parameters { put(os, "%s\n", MODULE_H_TEMPLATE); } // Close the file. fclose(os); } //============================================================================== // // GenModuleStubsFile() // // This function generates the stubs.cpp source file, which contains the // wrapper functions to convert 'c' style server calls into provider class // calls // //============================================================================== static void GenModuleStubsFile( Parser& parser, const vector& classNames) { // Open the file. string path = ExpandPath("stubs.cpp"); FILE* os = Fopen(path.c_str(), "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); GenStatikGenLine(os); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); // Print warning box. PutCommentBox(os, WARNING); // Include header. putl(os, "#include "); putl(os, "#include \"module.h\""); // Include each direct header file (headers will indirectly include others). for (size_t i = 0; i < classNames.size(); i++) { // Find the class. const MI_ClassDecl* cd = parser.findClassDecl(classNames[i].c_str()); if (!cd) err(ID_UNKNOWN_CLASS, "unknown class: %s", classNames[i].c_str()); /* skip not-requested classes */ if (providerClasses.find(cd->name) == providerClasses.end()) continue; // Include the class header. const string alias = AliasOf(cd->name); putl(os, "#include \"%s_Class_Provider.h\"", alias.c_str()); } nl(os); putl(os, "using namespace mi;"); nl(os); // generate c++ wrappers for (size_t i = 0; i < classNames.size(); i++) { // Find the class. const MI_ClassDecl* cd = parser.findClassDecl(classNames[i].c_str()); if (!cd) err(ID_UNKNOWN_CLASS, "unknown class: %s", classNames[i].c_str()); /* skip not-requested classes */ if (providerClasses.find(cd->name) == providerClasses.end()) continue; // generate stub for the class GenerateClassStub( os, cd ); } // Generate module-level load/unload { string r = STUBS_LOAD_UNLOAD_TEMPLATE; if (s_options.schema.size()) r = sub(r, "", s_options.schema); else r = sub(r, "", "schemaDecl"); put(os, "%s", r.c_str()); } // Generate MI_Main() { string r = GenerateMI_Main(); put(os, "%s\n", r.c_str()); } nl(os); // Close the file. fclose(os); } //============================================================================== // // GenerateStringsFile() // // This function generates the string.rc file, which contains the // localized qualifier strings (only called if -l option present) // //============================================================================== static void GenerateStringsFile() { // Open the file. const string path = ExpandPath("strings.rc"); FILE* os = Fopen(path.c_str(), "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); GenStatikGenLine(os); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); // Generate file with the following format. // // STRINGTABLE // { // , // } { fprintf(os, "STRINGTABLE\n"); fprintf(os, "{\n"); for (size_t i = 0; i < s_localizations.size(); i++) { MI_Uint32 id = (MI_Uint32)(i + 1); const string& str = s_localizations[i]; fprintf(os, " %u, \"%s\"\n", id, str.c_str()); } fprintf(os, "}\n"); } // Close the file. fclose(os); } static string _GetClassInheritanceRegistrationEntry( const MI_ClassDecl* cd ) { string res = cd->name; while (cd->superClassDecl) { res += ","; cd = cd->superClassDecl; res += cd->name; } return res; } static string _GetClassRegistrationEntry( Parser& parser, const MI_ClassDecl* cd ) { string res; if (cd->flags & MI_FLAG_ASSOCIATION) { const MI_ClassDecl* cd_left = 0, *cd_right = 0; // find two ref members for (MI_Uint32 i = 0; i < cd->numProperties; i++) { if (cd->properties[i]->type == MI_REFERENCE) { const MI_ClassDecl* cd_ref = parser.findClassDecl(cd->properties[i]->className); if (!cd_ref) { err(ID_UNKNOWN_CLASS, "unknown class: %s", cd->properties[i]->className); } if (!cd_left) cd_left = cd_ref; else cd_right = cd_ref; } } if (!cd_right) { err(ID_INSUFFICIENT_REFERENCES, "insufficient references: " "class must have 2 or more: %s", cd->name); } res = _GetClassInheritanceRegistrationEntry(cd_left) + "+" + _GetClassInheritanceRegistrationEntry(cd) + "+" + _GetClassInheritanceRegistrationEntry(cd_right); } else { res = _GetClassInheritanceRegistrationEntry(cd); } return res; } //============================================================================== // // GenerateRegistryFile() // // This function generates skeleton of the provider registry file, // which contains information server will use to operate with provider // (only called if -reg option present) // //============================================================================== static void GenerateRegistryFile( Parser& parser, const vector& classNames) { // Open the file. const string path = ExpandPath(s_options.providerRegistryPath); FILE* os = Fopen(path.c_str(), "a"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", path.c_str()); Fprintf(s_stdout, ID_CREATING, "Creating %s\n", path.c_str()); // Generate file with the following format. // // statik:test/c:MSFT_Person,MSFT_Animal,MSFT_Base + MSFT_Friends + // MSFT_Person,MSFT_Animal,MSFT_Base:PersonProvider // { fprintf(os, "# auto-generated skeleton of registry file\n"); fprintf(os, "# please update it with correct namespace[s]\n"); for (size_t i = 0; i < classNames.size(); i++) { const char* cn = classNames[i].c_str(); const MI_ClassDecl* cd = parser.findClassDecl(cn); if (!cd) err(ID_UNKNOWN_CLASS, "unknown class: %s", cn); fprintf(os, "statik::%s:\n", _GetClassRegistrationEntry(parser,cd).c_str()); } for (size_t i = 0; i < s_localizations.size(); i++) { MI_Uint32 id = (MI_Uint32)(i + 1); const string& str = s_localizations[i]; fprintf(os, " %u, \"%s\"\n", id, str.c_str()); } fprintf(os, "\n"); } // Close the file. fclose(os); } //============================================================================== // // GenMakefile() // // This function generates a 'GNUmakefile' for the given provider. // //============================================================================== static void GenMakefile( const string& library, const vector& classNames, const string& cmdLine) { const char MAKEFILE[] = "GNUmakefile"; MI_UNUSED(library); // If makefile already exists, quit: if (Exists(MAKEFILE)) { Fprintf(s_stdout, ID_SKIPPING, "Skipping %s\n", MAKEFILE); return; } // Open Makefile: FILE* os = Fopen(MAKEFILE, "w"); if (!os) err(ID_FAILED_TO_OPEN_FILE, "failed to open file: %s", MAKEFILE); { // 'OMIMAK' variable. string OMIMAK = string(GetPath(ID_DATADIR)) + "/omi.mak"; // 'PROVIDER' variable. string PROVIDER = s_options.providerName; // 'SOURCES' variable. string SOURCES; { if (s_options.cpp) SOURCES = "$(wildcard *.c *.cpp)"; else SOURCES = "$(wildcard *.c)"; } // 'CLASSNAMES' variable. string CLASSES; { for (size_t i = 0; i < classNames.size(); i++) { CLASSES += classNames[i]; if (i + 1 == classNames.size()) CLASSES += ' '; } } string r; if (s_options.cpp) r = CXXMAKEFILE_TEMPLATE; else r = CMAKEFILE_TEMPLATE; r = sub(r, "", OMIMAK); r = sub(r, "", PROVIDER); r = sub(r, "", SOURCES); r = sub(r, "", CLASSES); r = sub(r, "", cmdLine); puts(os, r); } // Print creation message: Fprintf(s_stdout, ID_CREATING, "Creating %s\n", MAKEFILE); // Close file: fclose(os); } //============================================================================== // // main() // // This program generates source code from MOF definitions. The source // includes run-time type information for class declarations and qualifier // declarations as well as class provider stubs. // //============================================================================== int GeneratorMain( const std::string& programNameArg, const std::vector& mofFilesArg, const std::vector& classNamesArg, const GeneratorOptions& optionsArg) { arg0 = programNameArg.c_str(); // Make a copy of the vector whose strings we can later modify in place. vector localClassNamesArg; { for (size_t i = 0; i < classNamesArg.size(); i++) localClassNamesArg.push_back(classNamesArg[i].c_str()); } // WIndows trick to get compatible float format #ifdef WIN32 _set_output_format(_TWO_DIGIT_EXPONENT); #endif // clear global params generated_headers.clear(); generated_classes.clear(); providerClasses.clear(); s_generated.clear(); aliases.clear(); s_localizations.clear(); // Save command-line options. s_options = optionsArg; // Create directory given by -d option. if (s_options.dir.size()) Mkdir(s_options.dir.c_str(), 0777); // Check schema given by -s otpion. if (s_options.schema.size()) { /* Check whether this is a valid C identifier */ if (!ValidIdent(s_options.schema)) err(ID_INVALID_SCHEMA_OPTION, "invalid schema option: %s", s_options.schema.c_str()); } if ( s_options.quiet ) { s_stdout = Fopen(NULL_FILE, "a"); } else { s_stdout = stdout; } // Create the parser. Parser parser(s_options.paths, s_options.warnings); // Parse all the MOF files. for (size_t i = 0; i < mofFilesArg.size(); i++) { const char* path = mofFilesArg[i].c_str(); if (parser.parse(path) != 0) { err(ID_FAILED_TO_PARSE_MOF_FILE, "failed to parse MOF file: %s", path); } } // Build the alias table, which maps a MOF classname to an alias name. // Aliases are introduced by command-line classname arguments of the // form =. For each command line argument of this // form, put an entry in the alias table. Use the lexographical case // for the class define in MOF (rather than defined on the command line). for (size_t i = 0; i < localClassNamesArg.size(); i++) { const char* className = localClassNamesArg[i].c_str(); char* alias = (char*)strchr(className, '='); if (alias) { *alias++ = '\0'; const MI_ClassDecl* cd = parser.findClassDecl(className); if (!cd) err(ID_UNKNOWN_CLASS, "unknown class: %s", className); aliases[cd->name] = alias; } } // Form a complete list of class names (excluding duplicates). vector classNames; if (s_options.all) { parser.getClassNames(classNames); } else { for (size_t i = 0; i < localClassNamesArg.size(); i++) { const char* className = localClassNamesArg[i].c_str(); const MI_ClassDecl* cd = parser.findClassDecl(className); if (!cd) err(ID_UNKNOWN_CLASS, "unknown, class: %s", className); // Save class name. if (!Contains(classNames, cd->name)) classNames.push_back(cd->name); // Reject classes that are abstract. if (cd->flags & MI_FLAG_ABSTRACT) { err(ID_REFUSED_TO_GENERATE_PROVIDER_FOR_ABSTRACT_CLASS, "refused to generated provider for abstract class: %s", cd->name); } } } // Form the set of classes for which there are providers (partial // generation is performed on dependent classes (for which there is // no actual provider). if (!s_options.noProviders) { for (size_t i = 0; i < classNames.size(); i++) { providerClasses.insert(classNames[i]); } } // Add extra classes (given by -e option) to class list to be generated. for (size_t i = 0; i < s_options.extraClasses.size(); i++) { const MI_ClassDecl* cd = parser.findClassDecl( s_options.extraClasses[i].c_str()); if (!cd) { err(ID_UNKNOWN_CLASS, "unknown class: %s", s_options.extraClasses[i].c_str()); } classNames.push_back(cd->name); } // Generate the classes. set classIdentifiers; for (size_t i = 0; i < classNames.size(); i++) { const char* cn = classNames[i].c_str(); const MI_ClassDecl* cd = parser.findClassDecl(cn); if (!cd) err(ID_UNKNOWN_CLASS, "unknown class: %s", cn); GenClassHeader(parser, cd, classIdentifiers); if (providerClasses.find(cd->name) != providerClasses.end()) { if (s_options.cpp) GenCppClassSource(cd); else GenClassSource(cd); } } // Generate the schema.c file. GenSchemaSourceFile(parser, classNames, classIdentifiers); // generate c++ wrappers - stubs.cpp file if (!s_options.noProviders && s_options.cpp) GenModuleStubsFile(parser, classNames); // Generate the module.h and module.c files. if (!s_options.noProviders) { if (s_options.cpp) { GenModuleCppSourceFile(); GenModuleCppHeaderFile(); } else GenModuleSourceFile(); } // Generate the strings.rc. if (s_options.localize) GenerateStringsFile(); // Generate provider registry file. if (!s_options.providerRegistryPath.empty()) GenerateRegistryFile(parser, classNames); if ( s_options.quiet ) { fclose( s_stdout ); s_stdout = 0; } // Generate the GNUmakefile. if (s_options.providerName.size()) GenMakefile(s_options.providerName, classNamesArg, s_options.cmdLine); return 0; }