diff options
Diffstat (limited to 'cpp/src/slice2freezej/Main.cpp')
-rw-r--r-- | cpp/src/slice2freezej/Main.cpp | 1965 |
1 files changed, 1965 insertions, 0 deletions
diff --git a/cpp/src/slice2freezej/Main.cpp b/cpp/src/slice2freezej/Main.cpp new file mode 100644 index 00000000000..a31d935482b --- /dev/null +++ b/cpp/src/slice2freezej/Main.cpp @@ -0,0 +1,1965 @@ +// ********************************************************************** +// +// 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/Options.h> +#include <IceUtil/StringUtil.h> +#include <IceUtil/CtrlCHandler.h> +#include <IceUtil/Mutex.h> +#include <IceUtil/MutexPtrLock.h> +#include <Slice/Preprocessor.h> +#include <Slice/FileTracker.h> +#include <Slice/JavaUtil.h> +#include <Slice/Util.h> +#include <iterator> + +using namespace std; +using namespace Slice; +using namespace IceUtil; +using namespace IceUtilInternal; + +namespace +{ + +IceUtil::Mutex* mutex = 0; +bool interrupted = false; + +class Init +{ +public: + + Init() + { + mutex = new IceUtil::Mutex; + } + + ~Init() + { + delete mutex; + mutex = 0; + } +}; + +Init init; + +} + +void +interruptedCallback(int signal) +{ + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> lock(mutex); + + interrupted = true; +} + +struct DictIndex +{ + string member; + bool caseSensitive; + + 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; + string value; + + vector<DictIndex> indices; +}; + +struct Index +{ + string name; + string type; + string member; + bool caseSensitive; +}; + +class FreezeGenerator : public JavaGenerator +{ +public: + FreezeGenerator(const string&, const string&); + virtual ~FreezeGenerator(); + + void generate(UnitPtr&, const Dict&); + + void generate(UnitPtr&, const Index&); + +private: + string typeToObjectString(const TypePtr&); + string varToObject(const TypePtr&, const string&); + string objectToVar(const TypePtr&, const string&); + + const string _prog; +}; + +FreezeGenerator::FreezeGenerator(const string& prog, const string& dir) + : JavaGenerator(dir), + _prog(prog) +{ +} + +FreezeGenerator::~FreezeGenerator() +{ +} + +string +FreezeGenerator::typeToObjectString(const TypePtr& type) +{ + static const char* builtinTable[] = + { + "java.lang.Byte", + "java.lang.Boolean", + "java.lang.Short", + "java.lang.Integer", + "java.lang.Long", + "java.lang.Float", + "java.lang.Double", + "java.lang.String", + "Ice.Object", + "Ice.ObjectPrx", + "Ice.LocalObject" + }; + + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(b) + { + return builtinTable[b->kind()]; + } + else + { + return typeToString(type, TypeModeIn); + } +} + +string +FreezeGenerator::varToObject(const TypePtr& type, const string& param) +{ + string result = param; + + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(b != 0) + { + switch(b->kind()) + { + case Builtin::KindByte: + { + result = string("java.lang.Byte.valueOf(") + param + ")"; + break; + } + case Builtin::KindBool: + { + result = string("java.lang.Boolean.valueOf(") + param + ")"; + break; + } + case Builtin::KindShort: + { + result = string("java.lang.Short.valueOf(") + param + ")"; + break; + } + case Builtin::KindInt: + { + result = string("java.lang.Integer.valueOf(") + param + ")"; + break; + } + case Builtin::KindLong: + { + result = string("java.lang.Long.valueOf(") + param + ")"; + break; + } + case Builtin::KindFloat: + { + result = string("java.lang.Float.valueOf(") + param + ")"; + break; + } + case Builtin::KindDouble: + { + result = string("java.lang.Double.valueOf(") + param + ")"; + break; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + break; + } + } + return result; +} + +string +FreezeGenerator::objectToVar(const TypePtr& type, const string& param) +{ + string result = param; + + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if(b != 0) + { + switch(b->kind()) + { + case Builtin::KindByte: + { + result = param + ".byteValue()"; + break; + } + case Builtin::KindBool: + { + result = param + ".booleanValue()"; + break; + } + case Builtin::KindShort: + { + result = param + ".shortValue()"; + break; + } + case Builtin::KindInt: + { + result = param + ".intValue()"; + break; + } + case Builtin::KindLong: + { + result = param + ".longValue()"; + break; + } + case Builtin::KindFloat: + { + result = param + ".floatValue()"; + break; + } + case Builtin::KindDouble: + { + result = param + ".doubleValue()"; + break; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + break; + } + } + return result; +} + +void +FreezeGenerator::generate(UnitPtr& u, const Dict& dict) +{ + // + // The dictionary name may include a package. + // + string name; + string::size_type pos = dict.name.rfind('.'); + if(pos == string::npos) + { + name = dict.name; + } + else + { + name = dict.name.substr(pos + 1); + } + + TypeList keyTypes = u->lookupType(dict.key, false); + if(keyTypes.empty()) + { + ostringstream os; + os << "`" << dict.key << "' is not a valid type" << endl; + 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" << endl; + throw os.str(); + } + TypePtr valueType = valueTypes.front(); + + vector<TypePtr> indexTypes; + vector<string> members; + vector<string> capitalizedMembers; + vector<string> indexNames; + size_t i; + + for(i = 0; i < dict.indices.size(); ++i) + { + const DictIndex& index = dict.indices[i]; + const string& member = index.member; + + if(index.member.empty()) + { + // + // No member was specified, which means we use the map's value type as the index key. + // + + if(dict.indices.size() > 1) + { + ostringstream os; + os << "bad index for dictionary `" << dict.name << "'" << endl; + throw os.str(); + } + + bool containsSequence = false; + if(!Dictionary::legalKeyType(valueType, containsSequence)) + { + ostringstream os; + os << "`" << dict.value << "' is not a valid index type" << endl; + throw os.str(); + } + if(containsSequence) + { + getErrorStream() << _prog << ": warning: use of sequences in dictionary keys has been deprecated" + << endl; + } + + if(index.caseSensitive == false) + { + // + // Verify that value type is a string. + // + BuiltinPtr b = BuiltinPtr::dynamicCast(valueType); + if(b == 0 || b->kind() != Builtin::KindString) + { + ostringstream os; + os << "VALUE is a `" << dict.value << "', not a string" << endl; + throw os.str(); + } + } + indexTypes.push_back(valueType); + members.push_back("value"); + capitalizedMembers.push_back("Value"); + indexNames.push_back("index"); + } + 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" << endl; + throw os.str(); + } + dataMembers = structDecl->dataMembers(); + } + + DataMemberList::const_iterator q = dataMembers.begin(); + while(q != dataMembers.end() && dataMember == 0) + { + if((*q)->name() == index.member) + { + dataMember = *q; + } + else + { + ++q; + } + } + + if(dataMember == 0) + { + ostringstream os; + os << "The value of `" << dict.name << "' has no data member named `" << index.member << "'" << endl; + 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 key" << endl; + throw os.str(); + } + if(containsSequence) + { + getErrorStream() << _prog << ": warning: use of sequences in dictionary keys has been deprecated" + << endl; + } + + if(index.caseSensitive == false) + { + // + // Verify that member type is a string. + // + BuiltinPtr b = BuiltinPtr::dynamicCast(dataMemberType); + if(b == 0 || b->kind() != Builtin::KindString) + { + ostringstream os; + os << "`" << index.member << "' is not a string" << endl; + throw os.str(); + } + } + indexTypes.push_back(dataMemberType); + + members.push_back(member); + string capitalizedMember = member; + capitalizedMember[0] = toupper(static_cast<unsigned char>(capitalizedMember[0])); + capitalizedMembers.push_back(capitalizedMember); + indexNames.push_back(member); + } + } + + open(dict.name, u->currentFile()); + + Output& out = output(); + + string keyTypeS = typeToObjectString(keyType); + string valueTypeS = typeToObjectString(valueType); + + out << sp << nl << "public class " << name << " extends Freeze.MapInternal.MapI<" << keyTypeS << ", " + << valueTypeS << ">"; + out << sb; + + if(dict.indices.size() > 0) + { + out << sp; + out << nl << "/**" + << nl << " * Supplies a comparator for each index key." + << nl << " */"; + out << nl << "public static class IndexComparators"; + out << sb; + out << sp; + out << nl << "/**" + << nl << " * Default constructor assigns null to the comparator for each index key." + << nl << " */"; + out << nl << "public" << nl << "IndexComparators()"; + out << sb; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * This constructor accepts a comparator for each index key."; + for(i = 0; i < dict.indices.size(); ++i) + { + out << nl << " * @param " << members[i] << "Comparator Comparator for <code>" << members[i] << "</code>."; + } + out << nl << " */"; + out << nl << "public" << nl << "IndexComparators("; + for(i = 0; i < dict.indices.size(); ++i) + { + if(i > 0) + { + out << ", "; + } + out << "java.util.Comparator<" << typeToObjectString(indexTypes[i]) << "> " << members[i] + << "Comparator"; + } + out << ")"; + out << sb; + for(i = 0; i < dict.indices.size(); ++i) + { + out << nl << "this." << members[i] << "Comparator = " << members[i] << "Comparator;"; + } + out << eb; + + out << sp; + for(i = 0; i < dict.indices.size(); ++i) + { + out << nl << "/** Comparator for <code>" << members[i] << "</code>. */"; + out << nl << "public java.util.Comparator<" << typeToObjectString(indexTypes[i]) << "> " << members[i] + << "Comparator;"; + } + out << eb; + } + + // + // Constructors + // + + out << sp << nl << "private" << nl << name + << "(Freeze.Connection __connection, String __dbName, java.util.Comparator<" << keyTypeS << "> __comparator"; + if(dict.indices.size() > 0) + { + out << ", IndexComparators __indexComparators"; + } + out << ")"; + out << sb; + + out << nl << "super(__connection, __dbName, __comparator);"; + if(dict.indices.size() > 0) + { + out << nl << "_indices = new Freeze.MapIndex[" << dict.indices.size() << "];"; + for(i = 0; i < dict.indices.size(); ++i) + { + out << nl << "_" << members[i] << "Index = new " << capitalizedMembers[i] << "Index(\"" << indexNames[i] + << "\", __indexComparators == null ? null : __indexComparators." << members[i] << "Comparator);"; + out << nl << "_indices[" << i << "] = _" << members[i] << "Index;"; + } + } + out << eb; + + if(dict.indices.size() > 0) + { + out << sp; + out << nl << "/**" + << nl << " * Instantiates a Freeze map using the given connection. If the database" + << nl << " * named in <code>__dbName</code> does not exist and <code>__createDb</code>" + << nl << " * is true, the database is created automatically, otherwise this constructor" + << nl << " * raises <code>DatabaseException</code>." + << nl << " * @param __connection The Freeze connection associated with this map." + << nl << " * @param __dbName The name of the Berkeley DB database." + << nl << " * @param __createDb True if the database should be created if it does not" + << nl << " * already exist, false otherwise." + << nl << " * @param __comparator A comparator for the map's main key, or null to use the" + << nl << " * default key comparison strategy." + << nl << " * @param __indexComparators A map of string to comparator, representing the" + << nl << " * key comparator for each of the map's indices. The map uses the default" + << nl << " * key comparison strategy for an index if <code>__indexComparators</code>" + << nl << " * is null, or if no entry can be found in the comparators map for an index." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */" + << nl << "public" << nl << name + << "(Freeze.Connection __connection, String __dbName, boolean __createDb, " + << "java.util.Comparator<" << keyTypeS << "> __comparator, " + << "IndexComparators __indexComparators)"; + out << sb; + out << nl << "this(__connection, __dbName, __comparator, __indexComparators);"; + out << nl << "init(_indices, __dbName, \"" << keyType->typeId() << "\", \"" << valueType->typeId() + << "\", __createDb);"; + out << eb; + } + + out << sp; + out << nl << "/**" + << nl << " * Instantiates a Freeze map using the given connection. If the database" + << nl << " * named in <code>__dbName</code> does not exist and <code>__createDb</code>" + << nl << " * is true, the database is created automatically, otherwise this constructor" + << nl << " * raises <code>DatabaseException</code>." + << nl << " * @param __connection The Freeze connection associated with this map." + << nl << " * @param __dbName The name of the Berkeley DB database." + << nl << " * @param __createDb True if the database should be created if it does not" + << nl << " * already exist, false otherwise." + << nl << " * @param __comparator A comparator for the map's main key, or null to use the" + << nl << " * default key comparison strategy." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public" << nl << name + << "(Freeze.Connection __connection, String __dbName, boolean __createDb, " + << "java.util.Comparator<" << keyTypeS << "> __comparator)"; + out << sb; + if(dict.indices.size() > 0) + { + out << nl << "this(__connection, __dbName, __createDb, __comparator, null);"; + } + else + { + out << nl << "super(__connection, __dbName, \"" << keyType->typeId() << "\", \"" + << valueType->typeId() << "\", __createDb, __comparator);"; + } + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Instantiates a Freeze map using the given connection. If the database" + << nl << " * named in <code>__dbName</code> does not exist and <code>__createDb</code>" + << nl << " * is true, the database is created automatically, otherwise this constructor" + << nl << " * raises <code>DatabaseException</code>. The map uses the default key" + << nl << " * comparison strategy." + << nl << " * @param __connection The Freeze connection associated with this map." + << nl << " * @param __dbName The name of the Berkeley DB database." + << nl << " * @param __createDb True if the database should be created if it does not" + << nl << " * already exist, false otherwise." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public" << nl << name + << "(Freeze.Connection __connection, String __dbName, boolean __createDb)"; + out << sb; + out << nl << "this(__connection, __dbName, __createDb, null);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Instantiates a Freeze map using the given connection. If the database" + << nl << " * named in <code>__dbName</code> does not exist, it is created automatically." + << nl << " * The map uses the default key comparison strategy." + << nl << " * @param __connection The Freeze connection associated with this map." + << nl << " * @param __dbName The name of the Berkeley DB database." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public" << nl << name << "(Freeze.Connection __connection, String __dbName)"; + out << sb; + out << nl << "this(__connection, __dbName, true);"; + out << eb; + + // + // recreate + // + if(dict.indices.size() > 0) + { + out << sp; + out << nl << "/**" + << nl << " * Copies an existing database. The new database has the name given in" + << nl << " * <code>__dbName</code>, and the old database is renamed with a UUID" + << nl << " * suffix." + << nl << " * @param __connection The Freeze connection associated with this map." + << nl << " * @param __dbName The name of the Berkeley DB database." + << nl << " * @param __comparator A comparator for the map's main key, or null to use the" + << nl << " * default key comparison strategy." + << nl << " * @param __indexComparators A map of string to comparator, representing the" + << nl << " * key comparator for each of the map's indices. The map uses the default" + << nl << " * key comparison strategy for an index if <code>__indexComparators</code>" + << nl << " * is null, or if no entry can be found in the comparators map for an index." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public static void" << nl + << "recreate(Freeze.Connection __connection, String __dbName, " + << "java.util.Comparator<" << keyTypeS << "> __comparator, " + << "IndexComparators __indexComparators)"; + out << sb; + out << nl << name << " __tmpMap = new " << name + << "(__connection, __dbName, __comparator, __indexComparators);"; + out << nl << "recreate(__tmpMap, __dbName, \"" << keyType->typeId() << "\", \"" + << valueType->typeId() << "\", __tmpMap._indices);"; + out << eb; + } + + out << sp; + out << nl << "/**" + << nl << " * Copies an existing database. The new database has the name given in" + << nl << " * <code>__dbName</code>, and the old database is renamed with a UUID" + << nl << " * suffix." + << nl << " * @param __connection The Freeze connection associated with this map." + << nl << " * @param __dbName The name of the Berkeley DB database." + << nl << " * @param __comparator A comparator for the map's main key, or null to use the" + << nl << " * default key comparison strategy." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public static void" << nl + << "recreate(Freeze.Connection __connection, String __dbName, " + << "java.util.Comparator<" << keyTypeS << "> __comparator)"; + out << sb; + if(dict.indices.size() > 0) + { + out << nl << "recreate(__connection, __dbName, __comparator, null);"; + } + else + { + out << nl << name << " __tmpMap = new " << name << "(__connection, __dbName, __comparator);"; + out << nl << "recreate(__tmpMap, __dbName, \"" << keyType->typeId() << "\", \"" + << valueType->typeId() << "\", null);"; + } + out << eb; + + // + // Index methods + // + for(i = 0; i < capitalizedMembers.size(); ++i) + { + string indexClassName = capitalizedMembers[i] + "Index"; + string indexTypeS = typeToString(indexTypes[i], TypeModeIn); + string indexObjTypeS = typeToObjectString(indexTypes[i]); + string indexObj = varToObject(indexTypes[i], "__key"); + + out << sp; + out << nl << "/**" + << nl << " * Obtains an iterator ordered using the index value." + << nl << " * The iterator's initial position is an element whose key matches <code>__key</code>; if" + << nl << " * no such element exists, the returned iterator is empty (<code>hasNext</code> returns" + << nl << " * false). If <code>__onlyDups</code> is true, the iterator only returns elements whose" + << nl << " * key exactly matches <code>__key</code>; otherwise, the iterator continues to iterate over" + << nl << " * the remaining elements in the map." + << nl << " * @param __key The value at which the iterator begins." + << nl << " * @param __onlyDups True if the iterator should be limited to elements whose key" + << nl << " * exactly matches <code>__key</code>, false otherwise." + << nl << " * @return A new iterator." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public Freeze.Map.EntryIterator<java.util.Map.Entry<" << keyTypeS << ", " << valueTypeS + << ">>"; + out << nl << "findBy" << capitalizedMembers[i] << "(" << indexTypeS << " __key, boolean __onlyDups)"; + out << sb; + out << nl << "return _" << members[i] << "Index.find(" << indexObj << ", __onlyDups);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Obtains an iterator ordered using the values of member <code>" << members[i] << "</code>." + << nl << " * The iterator's initial position is an element whose key matches <code>__key</code>; if" + << nl << " * no such element exists, the returned iterator is empty (<code>hasNext</code> returns" + << nl << " * false). This iterator only returns elements whose key exactly matches <code>__key</code>." + << nl << " * @param __key The value at which the iterator begins." + << nl << " * @return A new iterator." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public Freeze.Map.EntryIterator<java.util.Map.Entry<" << keyTypeS << ", " << valueTypeS + << ">>"; + out << nl << "findBy" << capitalizedMembers[i] << "(" << indexTypeS << " __key)"; + out << sb; + out << nl << "return _" << members[i] << "Index.find(" << indexObj << ", true);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Determines the number of elements whose index values match <code>__key</code>." + << nl << " * @return The number of matching elements." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + string countMethod = dict.indices[i].member.empty() ? string("valueCount") : dict.indices[i].member + "Count"; + out << nl << "public int"; + out << nl << countMethod << "(" << indexTypeS << " __key)"; + out << sb; + out << nl << "return _" << members[i] << "Index.count(" << indexObj << ");"; + out << eb; + + string subMap = "Freeze.NavigableMap<" + indexObjTypeS + ", java.util.Set<java.util.Map.Entry<" + keyTypeS + + ", " + valueTypeS + ">>>"; + + out << sp; + out << nl << "/**" + << nl << " * Returns a view of the portion of this map whose keys are strictly less than" + << nl << " * <code>__toKey</code>, or less than or equal to <code>__toKey</code> if" + << nl << " * <code>__inclusive</code> is true. Insertions and removals via this map are" + << nl << " * not supported." + << nl << " * @param __toKey High endpoint of the keys in the returned map." + << nl << " * @param __inclusive If true, the endpoint is included in the returned map;" + << nl << " * otherwise, the endpoint is excluded." + << nl << " * @return A view of the portion of this map whose keys are strictly less than" + << nl << " * <code>__toKey</code>, or less than or equal to <code>__toKey</code> if" + << nl << " * <code>__inclusive</code> is true." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public " + subMap; + out << nl << "headMapFor" << capitalizedMembers[i] << "(" << indexTypeS << " __toKey, boolean __inclusive)"; + out << sb; + out << nl << "return _" << members[i] << "Index.createHeadMap(" << varToObject(indexTypes[i], "__toKey") + << ", __inclusive);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Returns a view of the portion of this map whose keys are strictly less than" + << nl << " * <code>__toKey</code>. Insertions and removals via this map are not supported." + << nl << " * @param __toKey High endpoint of the keys in the returned map." + << nl << " * @return A view of the portion of this map whose keys are strictly less than" + << nl << " * <code>__toKey</code>>" + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public " + subMap; + out << nl << "headMapFor" << capitalizedMembers[i] << "(" << indexTypeS << " __toKey)"; + out << sb; + out << nl << "return headMapFor" << capitalizedMembers[i] << "(__toKey, false);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Returns a view of the portion of this map whose keys are strictly greater than" + << nl << " * <code>__fromKey</code>, or greater than or equal to <code>__fromKey</code> if" + << nl << " * <code>__inclusive</code> is true. Insertions and removals via this map are" + << nl << " * not supported." + << nl << " * @param __fromKey Low endpoint of the keys in the returned map." + << nl << " * @param __inclusive If true, the endpoint is included in the returned map;" + << nl << " * otherwise, the endpoint is excluded." + << nl << " * @return A view of the portion of this map whose keys are strictly greater than" + << nl << " * <code>__fromKey</code>, or greater than or equal to <code>__fromKey</code> if" + << nl << " * <code>__inclusive</code> is true." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public " + subMap; + out << nl << "tailMapFor" << capitalizedMembers[i] << "(" << indexTypeS << " __fromKey, boolean __inclusive)"; + out << sb; + out << nl << "return _" << members[i] << "Index.createTailMap(" << varToObject(indexTypes[i], "__fromKey") + << ", __inclusive);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Returns a view of the portion of this map whose keys are greater than or equal" + << nl << " * to <code>__fromKey</code>. Insertions and removals via this map are not supported." + << nl << " * @param __fromKey Low endpoint of the keys in the returned map." + << nl << " * @return A view of the portion of this map whose keys are greater than or equal" + << nl << " * to <code>__fromKey</code>." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public " + subMap; + out << nl << "tailMapFor" << capitalizedMembers[i] << "(" << indexTypeS << " __fromKey)"; + out << sb; + out << nl << "return tailMapFor" << capitalizedMembers[i] << "(__fromKey, true);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Returns a view of the portion of this map whose keys range from" + << nl << " * <code>__fromKey</code> to <code>__toKey</code>. If <code>__fromKey</code>" + << nl << " * and <code>__toKey</code> are equal, the returned map is empty unless" + << nl << " * <code>__fromInclusive</code> and <code>__toInclusive</code> are both true." + << nl << " * Insertions and removals via this map are not supported." + << nl << " * @param __fromKey Low endpoint of the keys in the returned map." + << nl << " * @param __fromInclusive If true, the low endpoint is included in the returned map;" + << nl << " * otherwise, the endpoint is excluded." + << nl << " * @param __toKey High endpoint of the keys in the returned map." + << nl << " * @param __toInclusive If true, the high endpoint is included in the returned map;" + << nl << " * otherwise, the endpoint is excluded." + << nl << " * @return A view of the portion of this map whose keys range from" + << nl << " * <code>__fromKey</code> to <code>__toKey</code>." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public " + subMap; + out << nl << "subMapFor" << capitalizedMembers[i] << "(" << indexTypeS + << " __fromKey, boolean __fromInclusive, " << indexTypeS << " __toKey, boolean __toInclusive)"; + out << sb; + out << nl << "return _" << members[i] << "Index.createSubMap(" << varToObject(indexTypes[i], "__fromKey") + << ", __fromInclusive, " << varToObject(indexTypes[i], "__toKey") << ", __toInclusive);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Returns a view of the portion of this map whose keys are greater than" + << nl << " * or equal to <code>__fromKey</code> and strictly less than <code>__toKey</code>." + << nl << " * Insertions and removals via this map are not supported." + << nl << " * @param __fromKey Low endpoint of the keys in the returned map." + << nl << " * @param __toKey High endpoint of the keys in the returned map." + << nl << " * @return A view of the portion of this map whose keys range from" + << nl << " * <code>__fromKey</code> to <code>__toKey</code>." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public " + subMap; + out << nl << "subMapFor" << capitalizedMembers[i] << "(" << indexTypeS << " __fromKey, " << indexTypeS + << " __toKey)"; + out << sb; + out << nl << "return subMapFor" << capitalizedMembers[i] << "(__fromKey, true, __toKey, false);"; + out << eb; + + out << sp; + out << nl << "/**" + << nl << " * Returns a view of this map whose keys are ordered by the index value." + << nl << " * Insertions and removals via this map are not supported." + << nl << " * @return A view of this map whose keys range are ordered by the index value." + << nl << " * @throws Freeze.DatabaseException If an error occurs during database operations." + << nl << " */"; + out << nl << "public " + subMap; + out << nl << "mapFor" << capitalizedMembers[i] << "()"; + out << sb; + out << nl << "return _" << members[i] << "Index.createMap();"; + out << eb; + } + + // + // Top-level encode/decode + // + for(i = 0; i < 2; i++) + { + string keyValue; + TypePtr type; + bool encaps; + string typeS; + + if(i == 0) + { + keyValue = "Key"; + type = keyType; + typeS = keyTypeS; + encaps = false; // Do not encapsulate keys. + } + else + { + keyValue = "Value"; + type = valueType; + typeS = valueTypeS; + encaps = true; + } + + string valS = objectToVar(type, "v"); + + int iter; + + // + // encode + // + out << sp << nl << "public byte[]" << nl << "encode" << keyValue << "(" << typeS + << " v, Ice.Communicator communicator)"; + out << sb; + out << nl << "IceInternal.BasicStream __os = " + << "new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator), false, false);"; + if(encaps) + { + out << nl << "__os.startWriteEncaps();"; + } + iter = 0; + writeMarshalUnmarshalCode(out, "", type, valS, true, iter, false); + if(type->usesClasses()) + { + out << nl << "__os.writePendingObjects();"; + } + if(encaps) + { + out << nl << "__os.endWriteEncaps();"; + } + out << nl << "IceInternal.Buffer __buf = __os.prepareWrite();"; + out << nl << "byte[] __r = new byte[__buf.size()];"; + out << nl << "__buf.b.get(__r);"; + out << nl << "return __r;"; + out << eb; + + // + // decode + // + out << sp << nl << "public " << typeS << nl << "decode" << keyValue + << "(byte[] b, Ice.Communicator communicator)"; + out << sb; + out << nl << "IceInternal.BasicStream __is = " + << "new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator), false, false);"; + if(type->usesClasses()) + { + out << nl << "__is.sliceObjects(false);"; + } + out << nl << "__is.resize(b.length, true);"; + out << nl << "IceInternal.Buffer __buf = __is.getBuffer();"; + out << nl << "__buf.b.position(0);"; + out << nl << "__buf.b.put(b);"; + out << nl << "__buf.b.position(0);"; + if(encaps) + { + out << nl << "__is.startReadEncaps();"; + } + iter = 0; + list<string> metaData; + string patchParams; + BuiltinPtr b = BuiltinPtr::dynamicCast(type); + if((b && b->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(type)) + { + out << nl << "Patcher __p = new Patcher();"; + patchParams = "__p"; + } + else + { + out << nl << typeS << " __r;"; + } + if(b) + { + switch(b->kind()) + { + case Builtin::KindByte: + { + out << nl << "__r = java.lang.Byte.valueOf(__is.readByte());"; + break; + } + case Builtin::KindBool: + { + out << nl << "__r = java.lang.Boolean.valueOf(__is.readBool());"; + break; + } + case Builtin::KindShort: + { + out << nl << "__r = java.lang.Short.valueOf(__is.readShort());"; + break; + } + case Builtin::KindInt: + { + out << nl << "__r = java.lang.Integer.valueOf(__is.readInt());"; + break; + } + case Builtin::KindLong: + { + out << nl << "__r = java.lang.Long.valueOf(__is.readLong());"; + break; + } + case Builtin::KindFloat: + { + out << nl << "__r = java.lang.Float.valueOf(__is.readFloat());"; + break; + } + case Builtin::KindDouble: + { + out << nl << "__r = java.lang.Double.valueOf(__is.readDouble());"; + break; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + writeMarshalUnmarshalCode(out, "", type, "__r", false, iter, false, metaData, patchParams); + break; + } + } + } + else + { + writeMarshalUnmarshalCode(out, "", type, "__r", false, iter, false, metaData, patchParams); + } + if(type->usesClasses()) + { + out << nl << "__is.readPendingObjects();"; + } + if(encaps) + { + out << nl << "__is.endReadEncaps();"; + } + if((b && b->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(type)) + { + out << nl << "return __p.value;"; + } + else + { + out << nl << "return __r;"; + } + out << eb; + } + + // + // Inner index classes + // + for(i = 0; i < capitalizedMembers.size(); ++i) + { + string indexClassName = capitalizedMembers[i] + "Index"; + string indexKeyTypeS = typeToObjectString(indexTypes[i]); + + out << sp << nl << "private class " << indexClassName << " extends Freeze.MapInternal.Index<" << keyTypeS + << ", " << valueTypeS << ", " << indexKeyTypeS << ">"; + out << sb; + + // + // encodeKey + // + out << sp << nl << "public byte[]"; + out << nl << "encodeKey(" << indexKeyTypeS << " key, Ice.Communicator communicator)"; + out << sb; + if(dict.indices[i].member.empty()) + { + // + // Encode the full value (with an encaps!) + // + string keyS = "key"; + if(!dict.indices[i].caseSensitive) + { + keyS = "key.toLowerCase()"; + } + + out << nl << "return encodeValue(" << keyS << ", communicator);"; + } + else + { + // + // No encaps + // + string keyS = dict.indices[i].caseSensitive ? "key" : "key.toLowerCase()"; + + keyS = objectToVar(indexTypes[i], keyS); + + out << nl << "IceInternal.BasicStream __os = " + << "new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator), false, false);"; + int iter = 0; + writeMarshalUnmarshalCode(out, "", indexTypes[i], keyS, true, iter, false); + assert(!indexTypes[i]->usesClasses()); + + out << nl << "IceInternal.Buffer buf = __os.prepareWrite();"; + out << nl << "byte[] r = new byte[buf.size()];"; + out << nl << "buf.b.get(r);"; + out << nl << "return r;"; + } + out << eb; + + // + // decodeKey + // + out << sp << nl << "public " << indexKeyTypeS; + out << nl << "decodeKey(byte[] bytes, Ice.Communicator communicator)"; + out << sb; + if(dict.indices[i].member.empty()) + { + // + // Decode the full value (with an encaps!) + // + out << nl << "return decodeValue(bytes, communicator);"; + } + else + { + out << nl << "IceInternal.BasicStream __is = " + << "new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator), false, false);"; + out << nl << "__is.resize(bytes.length, true);"; + out << nl << "IceInternal.Buffer buf = __is.getBuffer();"; + out << nl << "buf.b.position(0);"; + out << nl << "buf.b.put(bytes);"; + out << nl << "buf.b.position(0);"; + + int iter = 0; + list<string> metaData; + string patchParams; + + out << nl << indexKeyTypeS << " r;"; + + BuiltinPtr b = BuiltinPtr::dynamicCast(indexTypes[i]); + if(b != 0) + { + switch(b->kind()) + { + case Builtin::KindByte: + { + out << nl << "r = java.lang.Byte.valueOf(__is.readByte());"; + break; + } + case Builtin::KindBool: + { + out << nl << "r = java.lang.Boolean.valueOf(__is.readBool());"; + break; + } + case Builtin::KindShort: + { + out << nl << "r = java.lang.Short.valueOf(__is.readShort());"; + break; + } + case Builtin::KindInt: + { + out << nl << "r = java.lang.Integer.valueOf(__is.readInt());"; + break; + } + case Builtin::KindLong: + { + out << nl << "r = java.lang.Long.valueOf(__is.readLong());"; + break; + } + case Builtin::KindFloat: + { + out << nl << "r = java.lang.Float.valueOf(__is.readFloat());"; + break; + } + case Builtin::KindDouble: + { + out << nl << "r = java.lang.Double.valueOf(__is.readDouble());"; + break; + } + case Builtin::KindString: + case Builtin::KindObject: + case Builtin::KindObjectProxy: + case Builtin::KindLocalObject: + { + writeMarshalUnmarshalCode(out, "", indexTypes[i], "r", false, iter, false, metaData, patchParams); + break; + } + } + } + else + { + writeMarshalUnmarshalCode(out, "", indexTypes[i], "r", false, iter, false, metaData, patchParams); + } + out << nl << "return r;"; + } + out << eb; + + // + // extractKey + // + out << sp << nl << "protected " << indexKeyTypeS; + out << nl << "extractKey(" << valueTypeS << " value)"; + out << sb; + if(dict.indices[i].member.empty()) + { + if(dict.indices[i].caseSensitive) + { + out << nl << "return value;"; + } + else + { + out << nl << "return value.toLowerCase();"; + } + } + else + { + string member = "value." + dict.indices[i].member; + if(!dict.indices[i].caseSensitive) + { + member += ".toLowerCase()"; + } + out << nl << "return " << varToObject(indexTypes[i], member) << ";"; + } + out << eb; + + // + // marshalKey optimization + // + if(dict.indices[i].member.empty() && dict.indices[i].caseSensitive) + { + out << sp << nl << "protected byte[]"; + out << nl << "marshalKey(byte[] value)"; + out << sb; + out << nl << "return value;"; + out << eb; + } + + // + // Constructor + // + out << sp << nl << "private" << nl << indexClassName << "(String name, java.util.Comparator<" << indexKeyTypeS + << "> comparator)"; + out << sb; + out << nl << "super(" << name << ".this, name, comparator);"; + out << eb; + out << eb; + } + + // + // Patcher class. + // + BuiltinPtr b = BuiltinPtr::dynamicCast(valueType); + if((b && b->kind() == Builtin::KindObject) || ClassDeclPtr::dynamicCast(valueType)) + { + string typeS = typeToString(valueType, TypeModeIn); + out << sp << nl << "private static class Patcher implements IceInternal.Patcher"; + out << sb; + out << sp << nl << "public void" << nl << "patch(Ice.Object v)"; + out << sb; + if(b) + { + out << nl << "value = v;"; + } + else + { + out << nl << "value = (" << typeS << ")v;"; + } + out << eb; + out << sp << nl << "public String" << nl << "type()"; + out << sb; + if(b) + { + out << nl << "return \"::Ice::Object\";"; + } + else + { + ClassDeclPtr decl = ClassDeclPtr::dynamicCast(valueType); + out << nl << "return \"" << decl->scoped() << "\";"; + } + out << eb; + out << sp << nl << typeS << " value;"; + out << eb; + } + + // + // Fields + // + if(!dict.indices.empty()) + { + out << sp << nl << "private Freeze.MapIndex[] _indices;"; + } + for(i = 0; i < dict.indices.size(); ++i) + { + out << nl << "private " << capitalizedMembers[i] << "Index _" << members[i] << "Index;"; + } + + out << eb; + + close(); +} + +void +FreezeGenerator::generate(UnitPtr& u, const Index& index) +{ + string name; + string::size_type pos = index.name.rfind('.'); + if(pos == string::npos) + { + name = index.name; + } + else + { + name = index.name.substr(pos + 1); + } + + TypeList types = u->lookupType(index.type, false); + if(types.empty()) + { + ostringstream os; + os << "`" << index.type << "' is not a valid type" << endl; + throw os.str(); + } + TypePtr type = types.front(); + + ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(type); + if(classDecl == 0) + { + ostringstream os; + os << "`" << index.type << "' is not a class" << endl; + 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 << "'" << endl; + 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 " << endl; + throw os.str(); + } + } + + string memberTypeString = typeToString(dataMember->type(), TypeModeIn); + + open(index.name, u->currentFile()); + + Output& out = output(); + + out << sp << nl << "public class " << name << " extends Freeze.Index"; + out << sb; + + // + // Constructors + // + out << sp << nl << "public" << nl << name << "(String __indexName, String __facet)"; + out << sb; + out << nl << "super(__indexName, __facet);"; + out << eb; + + out << sp << nl << "public" << nl << name << "(String __indexName)"; + out << sb; + out << nl << "super(__indexName, \"\");"; + out << eb; + + // + // find and count + // + out << sp << nl << "public Ice.Identity[]" << nl + << "findFirst(" << memberTypeString << " __index, int __firstN)"; + out << sb; + out << nl << "return untypedFindFirst(marshalKey(__index), __firstN);"; + out << eb; + + out << sp << nl << "public Ice.Identity[]" << nl + << "find(" << memberTypeString << " __index)"; + out << sb; + out << nl << "return untypedFind(marshalKey(__index));"; + out << eb; + + out << sp << nl << "public int" << nl + << "count(" << memberTypeString << " __index)"; + out << sb; + out << nl << "return untypedCount(marshalKey(__index));"; + out << eb; + + // + // Key marshalling + // + string typeString = typeToString(type, TypeModeIn); + + out << sp << nl << "protected byte[]" << nl + << "marshalKey(Ice.Object __servant)"; + out << sb; + out << nl << "if(__servant instanceof " << typeString << ")"; + out << sb; + out << nl << memberTypeString << " __key = ((" << typeString << ")__servant)." << index.member << ";"; + out << nl << "return marshalKey(__key);"; + out << eb; + out << nl << "else"; + out << sb; + out << nl << "return null;"; + out << eb; + out << eb; + + string valueS = index.caseSensitive ? "__key" : "__key.toLowerCase()"; + + out << sp << nl << "private byte[]" << nl + << "marshalKey(" << memberTypeString << " __key)"; + out << sb; + out << nl << "IceInternal.BasicStream __os = " + << "new IceInternal.BasicStream(IceInternal.Util.getInstance(communicator()), false, false);"; + int iter = 0; + writeMarshalUnmarshalCode(out, "", dataMember->type(), valueS, true, iter, false); + if(type->usesClasses()) + { + out << nl << "__os.writePendingObjects();"; + } + out << nl << "IceInternal.Buffer __buf = __os.prepareWrite();"; + out << nl << "byte[] __r = new byte[__buf.size()];"; + out << nl << "__buf.b.get(__r);"; + out << nl << "return __r;"; + out << eb; + + out << eb; + + close(); +} + +void +usage(const char* n) +{ + getErrorStream() << "Usage: " << n << " [options] [slice-files...]\n"; + getErrorStream() << + "Options:\n" + "-h, --help Show this message.\n" + "-v, --version Display the Ice version.\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.\n" + "--dict NAME,KEY,VALUE 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" + "--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" + " 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" + "--output-dir DIR Create files in the directory DIR.\n" + "--depend Generate Makefile dependencies.\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" + "--meta META Define global metadata directive META.\n" + ; +} + +int +compile(int argc, char* argv[]) +{ + IceUtilInternal::Options opts; + opts.addOpt("h", "help"); + opts.addOpt("v", "version"); + 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("", "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("", "depend"); + opts.addOpt("d", "debug"); + opts.addOpt("", "ice"); + opts.addOpt("", "underscore"); + opts.addOpt("", "meta", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat); + + 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; + } + + vector<string> cppArgs; + 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)); + } + + bool preprocess = opts.isSet("E"); + + string include = opts.optArg("include-dir"); + + 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) + { + dict.key = s.substr(0, pos); + s.erase(0, pos + 1); + } + dict.value = 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); + } + + if(opts.isSet("dict-index")) + { + vector<string> optargs = opts.argVec("dict-index"); + for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i) + { + string s = IceUtilInternal::removeWhitespace(*i); + + string dictName; + DictIndex index; + string::size_type pos; + + string caseString = "case-sensitive"; + pos = s.find(','); + if(pos != string::npos) + { + dictName = s.substr(0, pos); + s.erase(0, pos + 1); + + pos = s.find(','); + if(pos != string::npos) + { + index.member = s.substr(0, pos); + s.erase(0, pos + 1); + caseString = s; + } + else + { + if(s == "case-sensitive" || s == "case-insensitive") + { + caseString = s; + } + else + { + index.member = s; + } + } + } + else + { + dictName = s; + } + + if(dictName.empty()) + { + getErrorStream() << argv[0] << ": error: " << *i << ": no dictionary 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"); + + 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 depend = opts.isSet("depend"); + + bool debug = opts.isSet("debug"); + + bool ice = opts.isSet("ice"); + + bool underscore = opts.isSet("underscore"); + + StringList globalMetadata; + vector<string> v = opts.argVec("meta"); + copy(v.begin(), v.end(), back_inserter(globalMetadata)); + + if(dicts.empty() && indices.empty()) + { + getErrorStream() << argv[0] << ": error: no Freeze types specified" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + + UnitPtr u = Unit::createUnit(true, false, ice, underscore, globalMetadata); + + int status = EXIT_SUCCESS; + + IceUtil::CtrlCHandler ctrlCHandler; + ctrlCHandler.setCallback(interruptedCallback); + + for(vector<string>::size_type idx = 0; idx < args.size(); ++idx) + { + if(depend) + { + PreprocessorPtr icecpp = Preprocessor::create(argv[0], args[idx], cppArgs); + FILE* cppHandle = icecpp->preprocess(false); + + if(cppHandle == 0) + { + u->destroy(); + return EXIT_FAILURE; + } + + status = u->parse(args[idx], cppHandle, debug); + + if(status == EXIT_FAILURE) + { + u->destroy(); + return EXIT_FAILURE; + } + + if(!icecpp->printMakefileDependencies(Preprocessor::Java, includePaths)) + { + u->destroy(); + return EXIT_FAILURE; + } + + if(!icecpp->close()) + { + u->destroy(); + return EXIT_FAILURE; + } + } + else + { + PreprocessorPtr icecpp = Preprocessor::create(argv[0], args[idx], cppArgs); + 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); + } + + if(!icecpp->close()) + { + u->destroy(); + return EXIT_FAILURE; + } + } + + { + IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(mutex); + + if(interrupted) + { + return EXIT_FAILURE; + } + } + } + + if(depend) + { + u->destroy(); + return EXIT_SUCCESS; + } + + if(status == EXIT_SUCCESS && !preprocess) + { + u->mergeModules(); + u->sort(); + + FreezeGenerator gen(argv[0], output); + + JavaGenerator::validateMetaData(u); + + for(vector<Dict>::const_iterator p = dicts.begin(); p != dicts.end(); ++p) + { + try + { + gen.generate(u, *p); + } + 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(...) + { + FileTracker::instance()->cleanup(); + getErrorStream() << argv[0] << ": error: unknown exception" << endl; + u->destroy(); + return EXIT_FAILURE; + } + } + + for(vector<Index>::const_iterator q = indices.begin(); q != indices.end(); ++q) + { + try + { + gen.generate(u, *q); + } + 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; + } +} |