diff options
Diffstat (limited to 'cpp/src/slice2freeze/Main.cpp')
-rw-r--r-- | cpp/src/slice2freeze/Main.cpp | 2084 |
1 files changed, 2084 insertions, 0 deletions
diff --git a/cpp/src/slice2freeze/Main.cpp b/cpp/src/slice2freeze/Main.cpp new file mode 100644 index 00000000000..7e2afb2414c --- /dev/null +++ b/cpp/src/slice2freeze/Main.cpp @@ -0,0 +1,2084 @@ +// ********************************************************************** +// +// Copyright (c) 2003-2011 ZeroC, Inc. All rights reserved. +// +// This copy of Ice is licensed to you under the terms described in the +// ICE_LICENSE file included in this distribution. +// +// ********************************************************************** + +#include <IceUtil/DisableWarnings.h> +#include <IceUtil/Options.h> +#include <IceUtil/CtrlCHandler.h> +#include <IceUtil/Mutex.h> +#include <IceUtil/MutexPtrLock.h> +#include <Slice/Preprocessor.h> +#include <Slice/CPlusPlusUtil.h> +#include <Slice/FileTracker.h> +#include <Slice/Util.h> +#include <IceUtil/OutputUtil.h> +#include <IceUtil/StringUtil.h> +#include <cstring> + +using namespace std; +using namespace IceUtil; +using namespace IceUtilInternal; +using namespace Slice; + +namespace +{ + +IceUtil::Mutex* mutex = 0; +bool interrupted = false; + +class Init +{ +public: + + Init() + { + mutex = new IceUtil::Mutex; + } + + ~Init() + { + delete mutex; + mutex = 0; + } +}; + +Init init; + +string ICE_ENCODING_COMPARE = "Freeze::IceEncodingCompare"; + +} + +void +interruptedCallback(int signal) +{ + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mutex); + + interrupted = true; +} + +class MetaDataVisitor : public ParserVisitor +{ +public: + + MetaDataVisitor() : + _useWstring(false) + { + } + + virtual bool visitModuleStart(const ModulePtr& p) + { + setUseWstring(p); + return true; + } + + virtual void visitModuleEnd(const ModulePtr& p) + { + resetUseWstring(); + } + + virtual bool visitClassDefStart(const ClassDefPtr& p) + { + setUseWstring(p); + checkMetaData(p->dataMembers()); + resetUseWstring(); + return true; + } + + virtual bool visitStructStart(const StructPtr& p) + { + setUseWstring(p); + checkMetaData(p->dataMembers()); + resetUseWstring(); + return true; + } + +private: + + void checkMetaData(const DataMemberList& dataMembers) + { + for(DataMemberList::const_iterator p = dataMembers.begin(); p != dataMembers.end(); ++p) + { + BuiltinPtr builtin = BuiltinPtr::dynamicCast((*p)->type()); + if(builtin && builtin->kind() == Builtin::KindString) + { + StringList metaData = (*p)->getMetaData(); + for(StringList::const_iterator q = metaData.begin(); q != metaData.end(); ++q) + { + if(*q == "cpp:type:string" || *q == "cpp:type:wstring") + { + continue; + } + } + metaData.push_back(_useWstring ? "cpp:type:wstring" : "cpp:type:string"); + (*p)->setMetaData(metaData); + } + } + } + + void setUseWstring(ContainedPtr p) + { + _useWstringHist.push_back(_useWstring); + StringList metaData = p->getMetaData(); + if(find(metaData.begin(), metaData.end(), "cpp:type:wstring") != metaData.end()) + { + _useWstring = true; + } + else if(find(metaData.begin(), metaData.end(), "cpp:type:string") != metaData.end()) + { + _useWstring = false; + } + } + + void resetUseWstring() + { + _useWstring = _useWstringHist.back(); + _useWstringHist.pop_back(); + } + + bool _useWstring; + std::list<bool> _useWstringHist; +}; + +struct DictIndex +{ + string member; + bool caseSensitive; + bool sort; + string userCompare; + + bool operator==(const DictIndex& rhs) const + { + return member == rhs.member; + } + + bool operator!=(const DictIndex& rhs) const + { + return member != rhs.member; + } +}; + +struct Dict +{ + string name; + string key; + StringList keyMetaData; + string value; + StringList valueMetaData; + bool sort; + string userCompare; + + vector<DictIndex> indices; +}; + +struct Index +{ + string name; + string type; + string member; + bool caseSensitive; +}; + +struct IndexType +{ + TypePtr type; + StringList metaData; +}; + +void +usage(const char* n) +{ + getErrorStream() << "Usage: " << n << " [options] file-base [slice-files...]\n"; + getErrorStream() << + "Options:\n" + "-h, --help Show this message.\n" + "-v, --version Display the Ice version.\n" + "--header-ext EXT Use EXT instead of the default `h' extension.\n" + "--source-ext EXT Use EXT instead of the default `cpp' extension.\n" + "--add-header HDR[,GUARD]\n" + " Add #include for HDR (with guard GUARD) to generated source file.\n" + "-DNAME Define NAME as 1.\n" + "-DNAME=DEF Define NAME as DEF.\n" + "-UNAME Remove any definition for NAME.\n" + "-IDIR Put DIR in the include file search path.\n" + "-E Print preprocessor output on stdout.\n" + "--include-dir DIR Use DIR as the header include directory in source files.\n" + "--dll-export SYMBOL Use SYMBOL for DLL exports.\n" + "--dict NAME,KEY,VALUE[,sort[,COMPARE]]\n" + " Create a Freeze dictionary with the name NAME,\n" + " using KEY as key, and VALUE as value. This\n" + " option may be specified multiple times for\n" + " different names. NAME may be a scoped name.\n" + " By default, keys are sorted using their binary\n" + " Ice-encoding representation. Use 'sort' to sort\n" + " with the COMPARE functor class. COMPARE's default\n" + " value is std::less<KEY>\n" + "--index NAME,TYPE,MEMBER[,{case-sensitive|case-insensitive}]\n" + " Create a Freeze evictor index with the name\n" + " NAME for member MEMBER of class TYPE. This\n" + " option may be specified multiple times for\n" + " different names. NAME may be a scoped name.\n" + " When member is a string, the case can be\n" + " sensitive or insensitive (default is sensitive).\n" + "--dict-index DICT[,MEMBER][,{case-sensitive|case-insensitive}]\n" + " [,sort[,COMPARE]]\n" + " Add an index to dictionary DICT. If MEMBER is \n" + " specified, then DICT's VALUE must be a class or\n" + " a struct, and MEMBER must designate a member of\n" + " VALUE. Otherwise, the entire VALUE is used for \n" + " indexing. When the secondary key is a string, \n" + " the case can be sensitive or insensitive (default\n" + " is sensitive).\n" + " By default, keys are sorted using their binary\n" + " Ice-encoding representation. Use 'sort' to sort\n" + " with the COMPARE functor class. COMPARE's default\n" + " value is std::less<secondary key type>.\n" + "--output-dir DIR Create files in the directory DIR.\n" + "-d, --debug Print debug messages.\n" + "--ice Permit `Ice' prefix (for building Ice source code only).\n" + "--underscore Permit underscores in Slice identifiers.\n" + ; +} + +void +checkIdentifier(string t, string s) +{ + if(s.empty() || (!IceUtilInternal::isAlpha(s[0]) && s[0] != '_')) + { + ostringstream os; + os << t << "' is not a valid type name"; + throw os.str(); + } + + for(unsigned int i = 1; i < s.size(); ++i) + { + if(!isalnum(static_cast<unsigned char>(s[i])) && s[i] != '_') + { + ostringstream os; + os << t << "' is not a valid type name"; + throw os.str(); + } + } +} + +void +printFreezeTypes(Output& out, const vector<Dict>& dicts, const vector<Index>& indices) +{ + out << '\n'; + out << "\n// Freeze types in this file:"; + for(vector<Dict>::const_iterator p = dicts.begin(); p != dicts.end(); ++p) + { + out << "\n// name=\"" << p->name << "\", key=\"" + << p->key << "\", value=\"" << p->value << "\""; + } + + for(vector<Index>::const_iterator q = indices.begin(); q != indices.end(); ++q) + { + out << "\n// name=\"" << q->name << "\", type=\"" << q->type + << "\", member=\"" << q->member << "\""; + if(q->caseSensitive == false) + { + out << " (case insensitive)"; + } + } + out << '\n'; +} + +template<class T> +inline string +getCompare(const T& t, const string& keyType) +{ + if(t.sort) + { + if(t.userCompare == "") + { + return "std::less< " + keyType + ">"; + } + else + { + return t.userCompare; + } + } + else + { + return ICE_ENCODING_COMPARE; + } +} + +void +writeCodecH(const TypePtr& type, const StringList& metaData, const string& name, const string& freezeType, Output& H, + const string& dllExport) +{ + H << sp << nl << "class " << dllExport << name; + H << sb; + H.dec(); + H << sp << nl << "public:"; + H << sp; + H.inc(); + H << nl << "static void write(" << inputTypeToString(type, metaData) + << ", Freeze::" << freezeType << "&, const ::Ice::CommunicatorPtr&);"; + H << nl << "static void read(" << typeToString(type, metaData) << "&, const Freeze::" << freezeType << "&, " + << "const ::Ice::CommunicatorPtr&);"; + H << nl << "static const std::string& typeId();"; + H << eb << ';'; +} + +void +writeCodecC(const TypePtr& type, const StringList& metaData, const string& name, const string& freezeType, bool encaps, + Output& C) +{ + string quotedFreezeType = "\"" + freezeType + "\""; + + C << sp << nl << "void" << nl << name << "::write(" << inputTypeToString(type, metaData) << " v, " + << "Freeze::" << freezeType << "& bytes, const ::Ice::CommunicatorPtr& communicator)"; + C << sb; + C << nl << "IceInternal::InstancePtr instance = IceInternal::getInstance(communicator);"; + C << nl << "IceInternal::BasicStream stream(instance.get());"; + if(encaps) + { + C << nl << "stream.startWriteEncaps();"; + } + writeMarshalUnmarshalCode(C, type, "v", true, "stream", false, metaData); + if(type->usesClasses()) + { + C << nl << "stream.writePendingObjects();"; + } + if(encaps) + { + C << nl << "stream.endWriteEncaps();"; + } + C << nl << "::std::vector<Ice::Byte>(stream.b.begin(), stream.b.end()).swap(bytes);"; + C << eb; + + C << sp << nl << "void" << nl << name << "::read(" << typeToString(type, metaData) << "& v, " + << "const Freeze::" << freezeType << "& bytes, const ::Ice::CommunicatorPtr& communicator)"; + C << sb; + C << nl << "IceInternal::InstancePtr instance = IceInternal::getInstance(communicator);"; + C << nl << "IceInternal::BasicStream stream(instance.get());"; + if(type->usesClasses()) + { + C << nl << "stream.sliceObjects(false);"; + } + C << nl << "stream.b.resize(bytes.size());"; + C << nl << "::memcpy(&stream.b[0], &bytes[0], bytes.size());"; + C << nl << "stream.i = stream.b.begin();"; + if(encaps) + { + C << nl << "stream.startReadEncaps();"; + } + writeMarshalUnmarshalCode(C, type, "v", false, "stream", false, metaData); + if(type->usesClasses()) + { + C << nl << "stream.readPendingObjects();"; + } + if(encaps) + { + C << nl << "stream.endReadEncaps();"; + } + C << eb; + + string staticName = "__"; + for(string::const_iterator p = name.begin(); p != name.end(); ++p) + { + if((*p) == ':') + { + staticName += '_'; + } + else + { + staticName += *p; + } + } + staticName += "_typeId"; + + string typeId = type->typeId(); + BuiltinPtr builtInType = BuiltinPtr::dynamicCast(type); + if(builtInType && builtInType->kind() == Builtin::KindString && metaData.size() != 0 && + metaData.front() == "cpp:type:wstring") + { + typeId = "wstring"; + } + C << sp << nl << "static const ::std::string " << staticName << " = \"" << typeId << "\";"; + + C << sp << nl << "const ::std::string&" << nl << name << "::typeId()"; + C << sb; + C << nl << "return " << staticName << ";"; + + C << eb; +} + +void +writeDictWithIndicesH(const string& name, const Dict& dict, + const vector<IndexType> indexTypes, + const TypePtr& keyType, const StringList& keyMetaData, const TypePtr& valueType, + const StringList& valueMetaData, Output& H, const string& dllExport) +{ + string compare = getCompare(dict, typeToString(keyType, keyMetaData)); + + string templateParams = string("< ") + typeToString(keyType, keyMetaData) + ", " + + typeToString(valueType, valueMetaData) + ", " + name + "KeyCodec, " + + name + "ValueCodec, " + compare + " >"; + + string keyCompareParams = + string("< ") + typeToString(keyType, keyMetaData) + ", " + + name + "KeyCodec, " + compare + " >"; + + vector<string> capitalizedMembers; + size_t i; + for(i = 0; i < dict.indices.size(); ++i) + { + const string& member = dict.indices[i].member; + if(!member.empty()) + { + string capitalizedMember = member; + capitalizedMember[0] = toupper(static_cast<unsigned char>(capitalizedMember[0])); + capitalizedMembers.push_back(capitalizedMember); + } + else + { + capitalizedMembers.push_back("Value"); + } + } + + H << sp << nl << "class " << dllExport << name + << " : public Freeze::Map" << templateParams; + H << sb; + H.dec(); + H << sp << nl << "public:"; + H << sp; + H.inc(); + + // + // Typedefs + // + /* + H << nl << "typedef std::pair<const " << typeToString(keyType, keyMetaData) + << ", const" << typeToString(valueType, valueMetaData) << "> value_type;"; + + H << nl << "typedef Freeze::Iterator" << templateParams << " iterator;"; + H << nl << "typedef Freeze::ConstIterator" << templateParams << " const_iterator;"; + H << nl << "typedef size_t size_type;"; + H << nl << "typedef ptrdiff_t difference_type;"; + */ + + // + // Nested index classes + // + + for(i = 0; i < capitalizedMembers.size(); ++i) + { + string className = capitalizedMembers[i] + "Index"; + + string indexCompare = + getCompare(dict.indices[i], typeToString(indexTypes[i].type, indexTypes[i].metaData)); + + string indexCompareParams = + string("< ") + typeToString(indexTypes[i].type, indexTypes[i].metaData) + ", " + + className + ", " + indexCompare + " >"; + + H << sp << nl << "class " << dllExport << className + << " : public Freeze::MapIndex" << indexCompareParams; + H << sb; + + H.dec(); + H << sp << nl << "public:"; + H << sp; + H.inc(); + H << nl << capitalizedMembers[i] << "Index(const std::string&, const " + << indexCompare << "& = " << indexCompare << "());"; + + H << sp; + + // + // Codec + // + H << nl << "static void write(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) + << ", Freeze::Key&, const Ice::CommunicatorPtr&);"; + + H << nl << "static void read(" + << typeToString(indexTypes[i].type, indexTypes[i].metaData) + << "&, const Freeze::Key&, const ::Ice::CommunicatorPtr&);"; + + H.dec(); + H << sp << nl << "protected:"; + H << sp; + H.inc(); + + H << nl << "virtual void marshalKey(const Freeze::Value&, Freeze::Key&) const;"; + + H << eb << ';'; + } + + // + // Constructors + // + H << sp; + H << nl << name << "(const Freeze::ConnectionPtr&, const std::string&, " + << "bool = true, const " << compare << "& = " << compare << "());"; + H << sp; + H << nl << "template <class _InputIterator>" + << nl << name << "(const Freeze::ConnectionPtr& __connection, " + << "const std::string& __dbName, bool __createDb, " + << "_InputIterator __first, _InputIterator __last, " + << "const " << compare << "& __compare = " << compare << "())"; + H.inc(); + H << nl << ": Freeze::Map" << templateParams <<"(__connection->getCommunicator())"; + H.dec(); + H << sb; + H << nl << "Freeze::KeyCompareBasePtr __keyCompare = " + << "new Freeze::KeyCompare" << keyCompareParams << "(__compare, this->_communicator);"; + H << nl << "std::vector<Freeze::MapIndexBasePtr> __indices;"; + for(i = 0; i < capitalizedMembers.size(); ++i) + { + string indexName = dict.indices[i].member; + if(indexName.empty()) + { + indexName = "index"; + } + indexName = string("\"") + indexName + "\""; + + H << nl << "__indices.push_back(new " << capitalizedMembers[i] << "Index(" << indexName << "));"; + } + H << nl << "this->_helper.reset(Freeze::MapHelper::create(__connection, __dbName, " + << name + "KeyCodec::typeId(), " + << name + "ValueCodec::typeId(), __keyCompare, __indices, __createDb));"; + H << nl << "while(__first != __last)"; + H << sb; + H << nl << "put(*__first);"; + H << nl << "++__first;"; + H << eb; + H << eb; + + // + // Recreate + // + H << nl << "static void recreate(const Freeze::ConnectionPtr&, const std::string&, " + << "const " << compare << "& = " << compare << "());"; + H << sp; + + // + // Find, begin, lowerBound, upperBound, equalRange and count functions + // + for(i = 0; i < capitalizedMembers.size(); ++i) + { + H << sp; + H << nl << "iterator findBy" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << ", bool = true);"; + H << nl << "const_iterator findBy" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << ", bool = true) const;"; + + H << nl << "iterator beginFor" << capitalizedMembers[i] << "();"; + H << nl << "const_iterator beginFor" << capitalizedMembers[i] << "() const;"; + + H << nl << "iterator endFor" << capitalizedMembers[i] << "();"; + H << nl << "const_iterator endFor" << capitalizedMembers[i] << "() const;"; + + H << nl << "iterator lowerBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << ");"; + H << nl << "const_iterator lowerBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << ") const;"; + + H << nl << "iterator upperBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << ");"; + H << nl << "const_iterator upperBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << ") const;"; + + H << nl << "std::pair<iterator, iterator> equalRangeFor" + << capitalizedMembers[i] << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) + << ");"; + + H << nl << "std::pair<const_iterator, const_iterator> equalRangeFor" + << capitalizedMembers[i] << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) + << ") const;"; + + string countFunction = dict.indices[i].member.empty() ? string("valueCount") + : dict.indices[i].member + "Count"; + + H << nl << "int " << countFunction + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << ") const;"; + + } + + H << eb << ';'; +} + +void +writeDictWithIndicesC(const string& name, const string& absolute, const Dict& dict, + const vector<IndexType> indexTypes, + const TypePtr& keyType, const StringList& keyMetaData, const TypePtr& valueType, + const StringList& valueMetaData, Output& C) +{ + string compare = getCompare(dict, typeToString(keyType, keyMetaData)); + + string templateParams = string("< ") + typeToString(keyType, keyMetaData) + ", " + + typeToString(valueType, valueMetaData) + ", " + name + "KeyCodec, " + + name + "ValueCodec, " + compare + " >"; + + string keyCompareParams = + string("< ") + typeToString(keyType, keyMetaData) + ", " + + name + "KeyCodec, " + compare + " >"; + + vector<string> capitalizedMembers; + size_t i; + for(i = 0; i < dict.indices.size(); ++i) + { + const string& member = dict.indices[i].member; + if(!member.empty()) + { + string capitalizedMember = member; + capitalizedMember[0] = toupper(static_cast<unsigned char>(capitalizedMember[0])); + capitalizedMembers.push_back(capitalizedMember); + } + else + { + capitalizedMembers.push_back("Value"); + } + } + + + // + // Nested index classes + // + for(i = 0; i < capitalizedMembers.size(); ++i) + { + string className = capitalizedMembers[i] + "Index"; + + string indexCompare = + getCompare(dict.indices[i], typeToString(indexTypes[i].type, indexTypes[i].metaData)); + + string indexCompareParams = + string("< ") + typeToString(indexTypes[i].type, indexTypes[i].metaData) + ", " + + className + ", " + indexCompare + " >"; + + C << sp << nl << absolute << "::" << className << "::" << className + << "(const std::string& __name, " + << "const " << indexCompare << "& __compare)"; + + C.inc(); + C << nl << ": Freeze::MapIndex" + << indexCompareParams << "(__name, __compare)"; + C.dec(); + C << sb; + C << eb; + + C << sp << nl << "void" + << nl << absolute << "::" << className << "::" + << "marshalKey(const Freeze::Value& __v, Freeze::Key& __k) const"; + C << sb; + + bool optimize = false; + + if(dict.indices[i].member.empty() && dict.indices[i].caseSensitive) + { + optimize = true; + C << nl << "__k = __v;"; + } + else + { + // + // Can't optimize + // + C << nl << typeToString(valueType, valueMetaData) << " __x;"; + C << nl << absolute << "ValueCodec::read(__x, __v, _communicator);"; + string param = "__x"; + + if(!dict.indices[i].member.empty()) + { + if(ClassDeclPtr::dynamicCast(valueType) != 0) + { + param += "->" + dict.indices[i].member; + } + else + { + param += "." + dict.indices[i].member; + } + } + C << nl << "write(" << param << ", __k, _communicator);"; + } + C << eb; + + C << sp << nl << "void" + << nl << absolute << "::" << className << "::" + << "write(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) + << " __index, Freeze::Key& __bytes, const Ice::CommunicatorPtr& __communicator)"; + C << sb; + + if(optimize) + { + C << nl << absolute << "ValueCodec::write(__index, __bytes, __communicator);"; + } + else + { + assert(!indexTypes[i].type->usesClasses()); + + C << nl << "IceInternal::InstancePtr __instance = IceInternal::getInstance(__communicator);"; + C << nl << "IceInternal::BasicStream __stream(__instance.get());"; + + string valueS; + if(dict.indices[i].caseSensitive) + { + valueS = "__index"; + } + else + { + C << nl << typeToString(indexTypes[i].type, indexTypes[i].metaData) + << " __lowerCaseIndex = IceUtilInternal::toLower(__index);"; + valueS = "__lowerCaseIndex"; + } + + writeMarshalUnmarshalCode(C, indexTypes[i].type, valueS, true, "__stream", false, indexTypes[i].metaData); + C << nl << "::std::vector<Ice::Byte>(__stream.b.begin(), __stream.b.end()).swap(__bytes);"; + } + C << eb; + + C << sp << nl << "void" + << nl << absolute << "::" << className << "::" + << "read(" << typeToString(indexTypes[i].type, indexTypes[i].metaData) + << "& __index, const Freeze::Key& __bytes, const Ice::CommunicatorPtr& __communicator)"; + C << sb; + + if(optimize) + { + C << nl << absolute << "ValueCodec::read(__index, __bytes, __communicator);"; + } + else + { + C << nl << "IceInternal::InstancePtr __instance = IceInternal::getInstance(__communicator);"; + C << nl << "IceInternal::BasicStream __stream(__instance.get());"; + + C << nl << "__stream.b.resize(__bytes.size());"; + C << nl << "::memcpy(&__stream.b[0], &__bytes[0], __bytes.size());"; + C << nl << "__stream.i = __stream.b.begin();"; + writeMarshalUnmarshalCode(C, indexTypes[i].type, "__index", false, "__stream", false, + indexTypes[i].metaData); + } + C << eb; + } + + // + // Constructor + // + C << sp << nl << absolute << "::" << name + << "(const Freeze::ConnectionPtr& __connection, const std::string& __dbName ," + << "bool __createDb, const " << compare << "& __compare)"; + C.inc(); + C << nl << ": Freeze::Map" << templateParams <<"(__connection->getCommunicator())"; + C.dec(); + C << sb; + C << nl << "Freeze::KeyCompareBasePtr __keyCompare = " + << "new Freeze::KeyCompare" << keyCompareParams << "(__compare, _communicator);"; + C << nl << "std::vector<Freeze::MapIndexBasePtr> __indices;"; + for(i = 0; i < capitalizedMembers.size(); ++i) + { + string indexName = dict.indices[i].member; + if(indexName.empty()) + { + indexName = "index"; + } + indexName = string("\"") + indexName + "\""; + + C << nl << "__indices.push_back(new " << capitalizedMembers[i] << "Index(" << indexName << "));"; + } + C << nl << "_helper.reset(Freeze::MapHelper::create(__connection, __dbName, " + << absolute + "KeyCodec::typeId(), " + << absolute + "ValueCodec::typeId(), __keyCompare, __indices, __createDb));"; + C << eb; + + // + // Recreate + // + C << sp << nl << "void" + << nl << absolute + << "::recreate(const Freeze::ConnectionPtr& __connection, const std::string& __dbName ," + << " const " << compare << "& __compare)"; + C << sb; + C << nl << "Freeze::KeyCompareBasePtr __keyCompare = " + << "new Freeze::KeyCompare" << keyCompareParams << "(__compare, __connection->getCommunicator());"; + C << nl << "std::vector<Freeze::MapIndexBasePtr> __indices;"; + for(i = 0; i < capitalizedMembers.size(); ++i) + { + string indexName = dict.indices[i].member; + if(indexName.empty()) + { + indexName = "index"; + } + indexName = string("\"") + indexName + "\""; + + C << nl << "__indices.push_back(new " << capitalizedMembers[i] << "Index(" << indexName << "));"; + } + C << nl << "Freeze::MapHelper::recreate(__connection, __dbName, " + << absolute + "KeyCodec::typeId(), " + << absolute + "ValueCodec::typeId(), __keyCompare, __indices);"; + C << eb; + + // + // Find and count functions + // + for(i = 0; i < capitalizedMembers.size(); ++i) + { + string indexClassName = capitalizedMembers[i] + "Index"; + + string indexName = dict.indices[i].member; + if(indexName.empty()) + { + indexName = "index"; + } + indexName = string("\"") + indexName + "\""; + + C << sp << nl << absolute << "::iterator" + << nl << absolute << "::" << "findBy" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) + << " __index, bool __onlyDups)"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return iterator(_helper->index(" << indexName + << ")->untypedFind(__bytes, false, __onlyDups), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::const_iterator" + << nl << absolute << "::" << "findBy" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) + << " __index, bool __onlyDups) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return const_iterator(_helper->index(" << indexName + << ")->untypedFind(__bytes, true, __onlyDups), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::iterator" + << nl << absolute << "::" << "beginFor" << capitalizedMembers[i] << "()"; + C << sb; + C << nl << "return iterator(_helper->index(" << indexName << ")->begin(false), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::const_iterator" + << nl << absolute << "::" << "beginFor" << capitalizedMembers[i] << "() const"; + C << sb; + C << nl << "return const_iterator(_helper->index(" << indexName << ")->begin(true), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::iterator" + << nl << absolute << "::" << "endFor" << capitalizedMembers[i] << "()"; + C << sb; + C << nl << "return iterator();"; + C << eb; + + C << sp << nl << absolute << "::const_iterator" + << nl << absolute << "::" << "endFor" << capitalizedMembers[i] << "() const"; + C << sb; + C << nl << "return const_iterator();"; + C << eb; + + C << sp << nl << absolute << "::iterator" + << nl << absolute << "::" << "lowerBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << " __index)"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return iterator(_helper->index(" << indexName + << ")->untypedLowerBound(__bytes, false), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::const_iterator" + << nl << absolute << "::" << "lowerBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << " __index) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return const_iterator(_helper->index(" << indexName + << ")->untypedLowerBound(__bytes, true), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::iterator" + << nl << absolute << "::" << "upperBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << " __index)"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return iterator(_helper->index(" << indexName + << ")->untypedUpperBound(__bytes, false), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::const_iterator" + << nl << absolute << "::" << "upperBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << " __index) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return const_iterator(_helper->index(" << indexName + << ")->untypedUpperBound(__bytes, true), _communicator);"; + C << eb; + + C << sp << nl << "std::pair<" << absolute << "::iterator, " + << absolute << "::iterator>" + << nl << absolute << "::" << "equalRangeFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << " __index)"; + C << sb; + C << nl << "return std::make_pair(lowerBoundFor" << capitalizedMembers[i] + << "(__index), upperBoundFor" << capitalizedMembers[i] << "(__index));"; + C << eb; + + C << sp << nl << "std::pair<" << absolute << "::const_iterator, " + << absolute << "::const_iterator>" + << nl << absolute << "::" << "equalRangeFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << " __index) const"; + C << sb; + C << nl << "return std::make_pair(lowerBoundFor" << capitalizedMembers[i] + << "(__index), upperBoundFor" << capitalizedMembers[i] << "(__index));"; + C << eb; + + string countFunction = dict.indices[i].member.empty() ? string("valueCount") + : dict.indices[i].member + "Count"; + + C << sp << nl << "int" + << nl << absolute << "::" << countFunction + << "(" << inputTypeToString(indexTypes[i].type, indexTypes[i].metaData) << " __index) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return _helper->index(" << indexName + << ")->untypedCount(__bytes);"; + C << eb; + } +} + +void +writeDict(const string& n, const UnitPtr& u, const Dict& dict, Output& H, Output& C, const string& dllExport) +{ + string absolute = dict.name; + if(absolute.find("::") == 0) + { + absolute.erase(0, 2); + } + string name = absolute; + vector<string> scope; + string::size_type pos; + while((pos = name.find("::")) != string::npos) + { + string s = name.substr(0, pos); + name.erase(0, pos + 2); + + checkIdentifier(absolute, s); + + scope.push_back(s); + } + + checkIdentifier(absolute, name); + + TypeList keyTypes = u->lookupType(dict.key, false); + if(keyTypes.empty()) + { + ostringstream os; + os << "`" << dict.key << "' is not a valid type"; + throw os.str(); + } + TypePtr keyType = keyTypes.front(); + + TypeList valueTypes = u->lookupType(dict.value, false); + if(valueTypes.empty()) + { + ostringstream os; + os << "`" << dict.value << "' is not a valid type"; + throw os.str(); + } + TypePtr valueType = valueTypes.front(); + + vector<string>::const_iterator q; + + for(q = scope.begin(); q != scope.end(); ++q) + { + H << sp; + H << nl << "namespace " << *q << nl << '{'; + } + + writeCodecH(keyType, dict.keyMetaData, name + "KeyCodec", "Key", H, dllExport); + writeCodecH(valueType, dict.valueMetaData, name + "ValueCodec", "Value", H, dllExport); + + vector<IndexType> indexTypes; + + if(dict.indices.size() == 0) + { + string compare = getCompare(dict, typeToString(keyType, dict.keyMetaData)); + + H << sp << nl << "typedef Freeze::Map< " << typeToString(keyType, dict.keyMetaData) + << ", " << typeToString(valueType, dict.valueMetaData) << ", " + << name << "KeyCodec, " << name << "ValueCodec, " << compare + << " > " << name << ";"; + } + else + { + for(vector<DictIndex>::const_iterator p = dict.indices.begin(); + p != dict.indices.end(); ++p) + { + const DictIndex& index = *p; + if(index.member.empty()) + { + if(dict.indices.size() > 1) + { + ostringstream os; + os << "bad index for dictionary `" << dict.name << "'"; + throw os.str(); + } + + bool containsSequence = false; + if(!Dictionary::legalKeyType(valueType, containsSequence)) + { + ostringstream os; + os << "`" << dict.value << "' is not a valid index type"; + throw os.str(); + } + if(containsSequence) + { + getErrorStream() << n << ": warning: use of sequences in dictionary keys has been deprecated"; + } + + if(index.caseSensitive == false) + { + // + // Let's check value is a string + // + + BuiltinPtr builtInType = BuiltinPtr::dynamicCast(valueType); + + if(builtInType == 0 || builtInType->kind() != Builtin::KindString) + { + ostringstream os; + os << "VALUE is a `" << dict.value << "', not a string"; + throw os.str(); + } + } + IndexType iType; + iType.type = valueType; + iType.metaData = dict.valueMetaData; + indexTypes.push_back(iType); + } + else + { + DataMemberPtr dataMember = 0; + DataMemberList dataMembers; + + ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(valueType); + if(classDecl != 0) + { + dataMembers = classDecl->definition()->allDataMembers(); + } + else + { + StructPtr structDecl = StructPtr::dynamicCast(valueType); + if(structDecl == 0) + { + ostringstream os; + os << "`" << dict.value << "' is neither a class nor a struct."; + throw os.str(); + } + dataMembers = structDecl->dataMembers(); + } + DataMemberList::const_iterator d = dataMembers.begin(); + while(d != dataMembers.end() && dataMember == 0) + { + if((*d)->name() == index.member) + { + dataMember = *d; + } + else + { + ++d; + } + } + + if(dataMember == 0) + { + ostringstream os; + os << "The value of `" << dict.name + << "' has no data member named `" << index.member << "'"; + throw os.str(); + } + + TypePtr dataMemberType = dataMember->type(); + + bool containsSequence = false; + if(!Dictionary::legalKeyType(dataMemberType, containsSequence)) + { + ostringstream os; + os << "`" << index.member << "' cannot be used as an index"; + throw os.str(); + } + if(containsSequence) + { + getErrorStream() << n << ": warning: use of sequences in dictionary keys has been deprecated"; + } + + if(index.caseSensitive == false) + { + // + // Let's check member is a string + // + BuiltinPtr memberType = BuiltinPtr::dynamicCast(dataMemberType); + if(memberType == 0 || memberType->kind() != Builtin::KindString) + { + ostringstream os; + os << "`" << index.member << "' is not a string "; + throw os.str(); + } + } + IndexType iType; + iType.type = dataMemberType; + iType.metaData = dataMember->getMetaData(); + indexTypes.push_back(iType); + } + } + writeDictWithIndicesH(name, dict, indexTypes, keyType, dict.keyMetaData, valueType, dict.valueMetaData, H, + dllExport); + } + + + for(q = scope.begin(); q != scope.end(); ++q) + { + H << sp; + H << nl << '}'; + } + + writeCodecC(keyType, dict.keyMetaData, absolute + "KeyCodec", "Key", false, C); + writeCodecC(valueType, dict.valueMetaData, absolute + "ValueCodec", "Value", true, C); + + if(indexTypes.size() > 0) + { + writeDictWithIndicesC(name, absolute, dict, indexTypes, keyType, dict.keyMetaData, valueType, + dict.valueMetaData, C); + } +} + +void +writeIndexH(const string& memberTypeString, const string& name, Output& H, const string& dllExport) +{ + H << sp << nl << "class " << dllExport << name + << " : public Freeze::Index"; + H << sb; + H.dec(); + H << sp << nl << "public:"; + H << sp; + H.inc(); + + H << nl << name << "(const std::string&, const std::string& = \"\");"; + H << sp << nl << "std::vector<Ice::Identity>"; + H << nl << "findFirst(" << memberTypeString << ", Ice::Int) const;"; + + H << sp << nl << "std::vector<Ice::Identity>"; + H << nl << "find(" << memberTypeString << ") const;"; + + H << sp << nl << "Ice::Int"; + H << nl << "count(" << memberTypeString << ") const;"; + H.dec(); + H << sp << nl << "private:"; + H << sp; + H.inc(); + + H << nl << "virtual bool"; + H << nl << "marshalKey(const Ice::ObjectPtr&, Freeze::Key&) const;"; + + H << sp << nl << "void"; + H << nl << "marshalKey(" << memberTypeString << ", Freeze::Key&) const;"; + + H << eb << ';'; + H << sp; + H << nl << "typedef IceUtil::Handle<" << name << "> " << name << "Ptr;"; +} + +void +writeIndexC(const TypePtr& type, const TypePtr& memberType, const string& memberName, + bool caseSensitive, const string& fullName, const string& name, Output& C) +{ + string inputType = inputTypeToString(memberType); + + C << sp << nl << fullName << "::" << name + << "(const ::std::string& __name, const ::std::string& __facet)"; + C.inc(); + C << nl << ": Freeze::Index(__name, __facet)"; + C.dec(); + C << sb; + C << eb; + + C << sp << nl << "std::vector<Ice::Identity>"; + C << nl << fullName << "::" << "findFirst(" << inputType << " __index, ::Ice::Int __firstN) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << "marshalKey(__index, __bytes);"; + C << nl << "return untypedFindFirst(__bytes, __firstN);"; + C << eb; + + C << sp << nl << "std::vector<Ice::Identity>"; + C << nl << fullName << "::" << "find(" << inputType << " __index) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << "marshalKey(__index, __bytes);"; + C << nl << "return untypedFind(__bytes);"; + C << eb; + + C << sp << nl << "Ice::Int"; + C << nl << fullName << "::" << "count(" << inputType << " __index) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << "marshalKey(__index, __bytes);"; + C << nl << "return untypedCount(__bytes);"; + C << eb; + + string typeString = typeToString(type); + + C << sp << nl << "bool"; + C << nl << fullName << "::" << "marshalKey(const Ice::ObjectPtr& __servant, Freeze::Key& __bytes) const"; + C << sb; + C << nl << typeString << " __s = " << typeString << "::dynamicCast(__servant);"; + C << nl << "if(__s != 0)"; + C << sb; + C << nl << "marshalKey(__s->" << memberName << ", __bytes);"; + C << nl << "return true;"; + C << eb; + C << nl << "else"; + C << sb; + C << nl << "return false;"; + C << eb; + C << eb; + + C << sp << nl << "void"; + C << nl << fullName << "::" << "marshalKey(" << inputType << " __index, Freeze::Key& __bytes) const"; + C << sb; + C << nl << "IceInternal::InstancePtr __instance = IceInternal::getInstance(_communicator);"; + C << nl << "IceInternal::BasicStream __stream(__instance.get());"; + + string valueS; + if(caseSensitive) + { + valueS = "__index"; + } + else + { + C << nl << typeToString(memberType) << " __lowerCaseIndex = IceUtilInternal::toLower(__index);"; + valueS = "__lowerCaseIndex"; + } + + writeMarshalUnmarshalCode(C, memberType, valueS, true, "__stream", false); + if(memberType->usesClasses()) + { + C << nl << "__stream.writePendingObjects();"; + } + C << nl << "::std::vector<Ice::Byte>(__stream.b.begin(), __stream.b.end()).swap(__bytes);"; + C << eb; +} + +void +writeIndex(const string& n, const UnitPtr& u, const Index& index, Output& H, Output& C, const string& dllExport) +{ + string absolute = index.name; + if(absolute.find("::") == 0) + { + absolute.erase(0, 2); + } + string name = absolute; + vector<string> scope; + string::size_type pos; + while((pos = name.find("::")) != string::npos) + { + string s = name.substr(0, pos); + name.erase(0, pos + 2); + + checkIdentifier(absolute, s); + + scope.push_back(s); + } + + checkIdentifier(absolute, name); + + TypeList types = u->lookupType(index.type, false); + if(types.empty()) + { + ostringstream os; + os << "`" << index.type << "' is not a valid type"; + throw os.str(); + } + TypePtr type = types.front(); + + ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type); + if(classDecl == 0) + { + ostringstream os; + os << "`" << index.type << "' is not a class"; + throw os.str(); + } + + DataMemberList dataMembers = classDecl->definition()->allDataMembers(); + DataMemberPtr dataMember = 0; + DataMemberList::const_iterator p = dataMembers.begin(); + while(p != dataMembers.end() && dataMember == 0) + { + if((*p)->name() == index.member) + { + dataMember = *p; + } + else + { + ++p; + } + } + + if(dataMember == 0) + { + ostringstream os; + os << "`" << index.type << "' has no data member named `" << index.member << "'"; + throw os.str(); + } + + if(index.caseSensitive == false) + { + // + // Let's check member is a string + // + BuiltinPtr memberType = BuiltinPtr::dynamicCast(dataMember->type()); + if(memberType == 0 || memberType->kind() != Builtin::KindString) + { + ostringstream os; + os << "`" << index.member << "'is not a string"; + throw os.str(); + } + } + + vector<string>::const_iterator q; + + for(q = scope.begin(); q != scope.end(); ++q) + { + H << sp; + H << nl << "namespace " << *q << nl << '{'; + } + + writeIndexH(inputTypeToString(dataMember->type()), name, H, dllExport); + + for(q = scope.begin(); q != scope.end(); ++q) + { + H << sp; + H << nl << '}'; + } + + writeIndexC(type, dataMember->type(), index.member, index.caseSensitive, absolute, name, C); +} + +void +gen(const string& name, const UnitPtr& u, const vector<string>& includePaths, const vector<string>& extraHeaders, + const vector<Dict>& dicts, const vector<Index>& indices, const string& include, const string& headerExtension, + const string& sourceExtension, string dllExport, const StringList& includes, const vector<string>& args, + const string& output) +{ + string fileH = args[0]; + fileH += "." + headerExtension; + string includeH = fileH; + string fileC = args[0]; + fileC += "." + sourceExtension; + + if(!output.empty()) + { + fileH = output + '/' + fileH; + fileC = output + '/' + fileC; + } + + u->mergeModules(); + u->sort(); + + IceUtilInternal::Output H; + H.open(fileH.c_str()); + if(!H) + { + ostringstream os; + os << "cannot open `" << fileH << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + + FileTracker::instance()->addFile(fileH); + + printHeader(H); + printGeneratedHeader(H, string(args[0]) + ".ice"); + + + printFreezeTypes(H, dicts, indices); + + IceUtilInternal::Output CPP; + CPP.open(fileC.c_str()); + if(!CPP) + { + ostringstream os; + os << "cannot open `" << fileC << "': " << strerror(errno); + throw FileException(__FILE__, __LINE__, os.str()); + } + FileTracker::instance()->addFile(fileC); + + printHeader(CPP); + printGeneratedHeader(CPP, string(args[0]) + ".ice"); + + printFreezeTypes(CPP, dicts, indices); + + for(vector<string>::const_iterator i = extraHeaders.begin(); i != extraHeaders.end(); ++i) + { + string hdr = *i; + string guard; + string::size_type pos = hdr.rfind(','); + if(pos != string::npos) + { + hdr = i->substr(0, pos); + guard = i->substr(pos + 1); + } + if(!guard.empty()) + { + CPP << "\n#ifndef " << guard; + CPP << "\n#define " << guard; + } + CPP << "\n#include <"; + if(!include.empty()) + { + CPP << include << '/'; + } + CPP << hdr << '>'; + if(!guard.empty()) + { + CPP << "\n#endif"; + } + } + + string s = fileH; + transform(s.begin(), s.end(), s.begin(), ToIfdef()); + H << "\n#ifndef __" << s << "__"; + H << "\n#define __" << s << "__"; + H << '\n'; + + if(dicts.size() > 0) + { + H << "\n#include <Freeze/Map.h>"; + } + + if(indices.size() > 0) + { + H << "\n#include <Freeze/Index.h>"; + } + + { + for(StringList::const_iterator p = includes.begin(); p != includes.end(); ++p) + { + H << "\n#include <" << changeInclude(*p, includePaths) << "." + headerExtension + ">"; + } + } + + CPP << "\n#include <Ice/BasicStream.h>"; + CPP << "\n#include <IceUtil/StringUtil.h>"; + CPP << "\n#include <"; + if(include.size()) + { + CPP << include << '/'; + } + CPP << includeH << '>'; + + printVersionCheck(H); + printVersionCheck(CPP); + + printDllExportStuff(H, dllExport); + if(dllExport.size()) + { + dllExport += " "; + } + + { + for(vector<Dict>::const_iterator p = dicts.begin(); p != dicts.end(); ++p) + { + writeDict(name, u, *p, H, CPP, dllExport); + } + + for(vector<Index>::const_iterator q = indices.begin(); q != indices.end(); ++q) + { + writeIndex(name, u, *q, H, CPP, dllExport); + } + } + + H << "\n\n#endif\n"; + CPP << '\n'; + + H.close(); + CPP.close(); +} + +int +compile(int argc, char* argv[]) +{ + IceUtilInternal::Options opts; + opts.addOpt("h", "help"); + opts.addOpt("v", "version"); + opts.addOpt("", "header-ext", IceUtilInternal::Options::NeedArg, "h"); + opts.addOpt("", "source-ext", IceUtilInternal::Options::NeedArg, "cpp"); + opts.addOpt("", "add-header", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("D", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("U", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("I", "", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("E"); + opts.addOpt("", "include-dir", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "dll-export", IceUtilInternal::Options::NeedArg); + opts.addOpt("", "dict", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("", "index", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("", "dict-index", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + opts.addOpt("", "output-dir", IceUtilInternal::Options::NeedArg); + opts.addOpt("d", "debug"); + opts.addOpt("", "ice"); + opts.addOpt("", "underscore"); + + vector<string> args; + try + { + args = opts.parse(argc, (const char**)argv); + } + catch(const IceUtilInternal::BadOptException& e) + { + getErrorStream() << argv[0] << ": error: " << e.reason << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(opts.isSet("help")) + { + usage(argv[0]); + return EXIT_SUCCESS; + } + + if(opts.isSet("version")) + { + getErrorStream() << ICE_STRING_VERSION << endl; + return EXIT_SUCCESS; + } + + string headerExtension = opts.optArg("header-ext"); + string sourceExtension = opts.optArg("source-ext"); + + vector<string> cppArgs; + vector<string> extraHeaders = opts.argVec("add-header"); + vector<string> optargs = opts.argVec("D"); + vector<string>::const_iterator i; + for(i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-D" + *i); + } + + optargs = opts.argVec("U"); + for(i = optargs.begin(); i != optargs.end(); ++i) + { + cppArgs.push_back("-U" + *i); + } + + vector<string> includePaths = opts.argVec("I"); + for(i = includePaths.begin(); i != includePaths.end(); ++i) + { + cppArgs.push_back("-I" + Preprocessor::normalizeIncludePath(*i)); + } + + // Convert include paths to full paths. + { + for(vector<string>::iterator p = includePaths.begin(); p != includePaths.end(); ++p) + { + *p = fullPath(*p); + } + } + + bool preprocess= opts.isSet("E"); + + string include = opts.optArg("include-dir"); + + string dllExport = opts.optArg("dll-export"); + + vector<Dict> dicts; + optargs = opts.argVec("dict"); + for(i = optargs.begin(); i != optargs.end(); ++i) + { + string s = IceUtilInternal::removeWhitespace(*i); + + Dict dict; + + string::size_type pos; + pos = s.find(','); + if(pos != string::npos) + { + dict.name = s.substr(0, pos); + s.erase(0, pos + 1); + } + pos = s.find(','); + if(pos != string::npos) + { + if(s.find("[\"") == 0) + { + string::size_type end = s.find("\"]"); + if(end != string::npos && end < pos) + { + dict.key = s.substr(end + 2, pos - end - 2); + dict.keyMetaData.push_back(s.substr(2, end - 2)); + } + else + { + dict.key = s.substr(0, pos); + } + } + else + { + dict.key = s.substr(0, pos); + } + s.erase(0, pos + 1); + } + pos = s.find(','); + if(pos == string::npos) + { + if(s.find("[\"") == 0) + { + string::size_type end = s.find("\"]"); + if(end != string::npos) + { + dict.value = s.substr(end + 2); + dict.valueMetaData.push_back(s.substr(2, end - 2)); + } + else + { + dict.value = s; + } + } + else + { + dict.value = s; + } + dict.sort = false; + } + else + { + if(s.find("[\"") == 0) + { + string::size_type end = s.find("\"]"); + if(end != string::npos && end < pos) + { + dict.value = s.substr(end + 2, pos - end - 2); + dict.valueMetaData.push_back(s.substr(2, end - 2)); + } + else + { + dict.value = s.substr(0, pos); + } + } + else + { + dict.value = s.substr(0, pos); + } + s.erase(0, pos + 1); + + pos = s.find(','); + if(pos == string::npos) + { + if(s != "sort") + { + getErrorStream() << argv[0] << ": error: " << *i << ": nothing or ',sort' expected after value-type" + << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + dict.sort = true; + } + else + { + string sort = s.substr(0, pos); + s.erase(0, pos + 1); + if(sort != "sort") + { + getErrorStream() << argv[0] << ": error: " << *i << ": nothing or ',sort' expected after value-type" + << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + dict.sort = true; + dict.userCompare = s; + } + } + + if(dict.name.empty()) + { + getErrorStream() << argv[0] << ": error: " << *i << ": no name specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(dict.key.empty()) + { + getErrorStream() << argv[0] << ": error: " << *i << ": no key specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(dict.value.empty()) + { + getErrorStream() << argv[0] << ": error: " << *i << ": no value specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + dicts.push_back(dict); + } + + vector<Index> indices; + optargs = opts.argVec("index"); + for(i = optargs.begin(); i != optargs.end(); ++i) + { + string s = IceUtilInternal::removeWhitespace(*i); + + Index index; + + string::size_type pos; + pos = s.find(','); + if(pos != string::npos) + { + index.name = s.substr(0, pos); + s.erase(0, pos + 1); + } + pos = s.find(','); + if(pos != string::npos) + { + index.type = s.substr(0, pos); + s.erase(0, pos + 1); + } + pos = s.find(','); + string caseString; + if(pos != string::npos) + { + index.member = s.substr(0, pos); + s.erase(0, pos + 1); + caseString = s; + } + else + { + index.member = s; + caseString = "case-sensitive"; + } + + if(index.name.empty()) + { + getErrorStream() << argv[0] << ": error: " << *i << ": no name specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(index.type.empty()) + { + getErrorStream() << argv[0] << ": error: " << *i << ": no type specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(index.member.empty()) + { + getErrorStream() << argv[0] << ": error: " << *i << ": no member specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(caseString != "case-sensitive" && caseString != "case-insensitive") + { + getErrorStream() << argv[0] << ": error: " << *i << ": the case can be `case-sensitive' or " + << "`case-insensitive'" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + index.caseSensitive = (caseString == "case-sensitive"); + + indices.push_back(index); + } + + optargs = opts.argVec("dict-index"); + for(i = optargs.begin(); i != optargs.end(); ++i) + { + string s = IceUtilInternal::removeWhitespace(*i); + + string dictName; + DictIndex index; + index.sort = false; + index.caseSensitive = true; + + string::size_type pos = s.find(','); + if(pos == string::npos) + { + dictName = s; + } + else + { + dictName = s.substr(0, pos); + s.erase(0, pos + 1); + + bool done = false; + while(!done) + { + pos = s.find(','); + if(pos == string::npos) + { + if(s == "sort") + { + index.sort = true; + } + else if(s == "case-sensitive") + { + index.caseSensitive = true; + } + else if(s == "case-insensitive") + { + index.caseSensitive = false; + } + else if(index.member.empty()) + { + if(s == "\\sort") + { + index.member = "sort"; + } + else + { + index.member = s; + } + } + else + { + getErrorStream() << argv[0] << ": error: " << *i << ": syntax error" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + done = true; + } + else + { + string subs = s.substr(0, pos); + s.erase(0, pos + 1); + + if(subs == "sort") + { + index.sort = true; + index.userCompare = s; + done = true; + } + else if(subs == "case-sensitive") + { + index.caseSensitive = true; + } + else if(subs == "case-insensitive") + { + index.caseSensitive = false; + } + else if(index.member.empty()) + { + if(subs == "\\sort") + { + index.member = "sort"; + } + else + { + index.member = subs; + } + } + else + { + getErrorStream() << argv[0] << ": error: " << *i << ": syntax error" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + } + } + } + + if(dictName.empty()) + { + getErrorStream() << argv[0] << ": error: " << *i << ": no dictionary specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + bool found = false; + for(vector<Dict>::iterator p = dicts.begin(); p != dicts.end(); ++p) + { + if(p->name == dictName) + { + if(find(p->indices.begin(), p->indices.end(), index) != p->indices.end()) + { + getErrorStream() << argv[0] << ": error: --dict-index " << *i + << ": this dict-index is defined twice" << endl; + return EXIT_FAILURE; + } + p->indices.push_back(index); + found = true; + break; + } + } + if(!found) + { + getErrorStream() << argv[0] << ": error: " << *i << ": unknown dictionary" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + } + + string output = opts.optArg("output-dir"); + + bool debug = opts.isSet("debug"); + + bool ice = opts.isSet("ice"); + + bool underscore = opts.isSet("underscore"); + + if(dicts.empty() && indices.empty()) + { + getErrorStream() << argv[0] << ": error: no Freeze types specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + if(args.empty()) + { + getErrorStream() << argv[0] << ": error: no file name base specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + UnitPtr u = Unit::createUnit(true, false, ice, underscore); + + StringList includes; + + int status = EXIT_SUCCESS; + + IceUtil::CtrlCHandler ctrlCHandler; + ctrlCHandler.setCallback(interruptedCallback); + + for(vector<string>::size_type idx = 1; idx < args.size(); ++idx) + { + PreprocessorPtr icecpp = Preprocessor::create(argv[0], args[idx], cppArgs); + + // + // Add an include file for each Slice file. Note that the .h extension + // is replaced with headerExtension later. + // + includes.push_back(icecpp->getBaseName() + ".h"); + + FILE* cppHandle = icecpp->preprocess(false); + + if(cppHandle == 0) + { + u->destroy(); + return EXIT_FAILURE; + } + + if(preprocess) + { + char buf[4096]; + while(fgets(buf, static_cast<int>(sizeof(buf)), cppHandle) != NULL) + { + if(fputs(buf, stdout) == EOF) + { + u->destroy(); + return EXIT_FAILURE; + } + } + } + else + { + status = u->parse(args[idx], cppHandle, debug); + + MetaDataVisitor visitor; + u->visit(&visitor, false); + } + + if(!icecpp->close()) + { + u->destroy(); + return EXIT_FAILURE; + } + + { + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mutex); + + if(interrupted) + { + return EXIT_FAILURE; + } + } + } + + + if(status == EXIT_SUCCESS && !preprocess) + { + try + { + gen(argv[0], u, includePaths, extraHeaders, dicts, indices, include, headerExtension, + sourceExtension, dllExport, includes, args, output); + } + catch(const string& ex) + { + // If a file could not be created, then cleanup any + // created files. + FileTracker::instance()->cleanup(); + u->destroy(); + getErrorStream() << argv[0] << ": error: " << ex << endl; + return EXIT_FAILURE; + } + catch(const Slice::FileException& ex) + { + // If a file could not be created, then cleanup any + // created files. + FileTracker::instance()->cleanup(); + u->destroy(); + getErrorStream() << argv[0] << ": error: " << ex.reason() << endl; + return EXIT_FAILURE; + } + catch(...) + { + getErrorStream() << argv[0] << ": error: unknown exception" << endl; + FileTracker::instance()->cleanup(); + u->destroy(); + return EXIT_FAILURE; + } + } + + u->destroy(); + + { + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mutex); + + if(interrupted) + { + FileTracker::instance()->cleanup(); + return EXIT_FAILURE; + } + } + + return status; +} + +int +main(int argc, char* argv[]) +{ + try + { + return compile(argc, argv); + } + catch(const std::exception& ex) + { + getErrorStream() << argv[0] << ": error:" << ex.what() << endl; + return EXIT_FAILURE; + } + catch(const std::string& msg) + { + getErrorStream() << argv[0] << ": error:" << msg << endl; + return EXIT_FAILURE; + } + catch(const char* msg) + { + getErrorStream() << argv[0] << ": error:" << msg << endl; + return EXIT_FAILURE; + } + catch(...) + { + getErrorStream() << argv[0] << ": error:" << "unknown exception" << endl; + return EXIT_FAILURE; + } +} |