summaryrefslogtreecommitdiff
path: root/cpp/src/FreezeScript/DumpDB.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/FreezeScript/DumpDB.cpp')
-rw-r--r--cpp/src/FreezeScript/DumpDB.cpp972
1 files changed, 972 insertions, 0 deletions
diff --git a/cpp/src/FreezeScript/DumpDB.cpp b/cpp/src/FreezeScript/DumpDB.cpp
new file mode 100644
index 00000000000..95a6ebb7983
--- /dev/null
+++ b/cpp/src/FreezeScript/DumpDB.cpp
@@ -0,0 +1,972 @@
+// **********************************************************************
+//
+// 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 <FreezeScript/DumpDescriptors.h>
+#include <FreezeScript/Util.h>
+#include <FreezeScript/Exception.h>
+#include <Freeze/Initialize.h>
+#include <Freeze/Connection.h>
+#include <IceUtil/OutputUtil.h>
+#include <IceUtil/Options.h>
+#include <IceUtil/FileUtil.h>
+#include <db_cxx.h>
+#include <sys/stat.h>
+#include <algorithm>
+
+using namespace std;
+using namespace IceUtil;
+using namespace IceUtilInternal;
+
+#ifdef _WIN32
+# define FREEZE_SCRIPT_DB_MODE 0
+#else
+# define FREEZE_SCRIPT_DB_MODE (S_IRUSR | S_IWUSR)
+#endif
+
+namespace FreezeScript
+{
+
+//
+// SliceVisitor generates default descriptors.
+//
+class SliceVisitor : public Slice::ParserVisitor
+{
+public:
+
+ SliceVisitor(IceUtilInternal::XMLOutput&, const Slice::TypePtr&, const Slice::TypePtr&, const string&);
+
+ virtual bool visitClassDefStart(const Slice::ClassDefPtr&);
+ virtual bool visitStructStart(const Slice::StructPtr&);
+ virtual void visitSequence(const Slice::SequencePtr&);
+ virtual void visitDictionary(const Slice::DictionaryPtr&);
+ virtual void visitEnum(const Slice::EnumPtr&);
+
+private:
+
+ IceUtilInternal::XMLOutput& _out;
+};
+
+class DescriptorHandler : public IceXML::Handler
+{
+public:
+
+ DescriptorHandler(const DataFactoryPtr&, const Slice::UnitPtr&, const ErrorReporterPtr&,
+ const FreezeScript::ObjectFactoryPtr&);
+
+ virtual void startElement(const std::string&, const IceXML::Attributes&, int, int);
+ virtual void endElement(const std::string&, int, int);
+ virtual void characters(const std::string&, int, int);
+ virtual void error(const std::string&, int, int);
+
+ DumpDBDescriptorPtr descriptor() const;
+
+private:
+
+ DataFactoryPtr _factory;
+ Slice::UnitPtr _unit;
+ ErrorReporterPtr _errorReporter;
+ DescriptorPtr _current;
+ DumpDBDescriptorPtr _descriptor;
+ FreezeScript::ObjectFactoryPtr _objectFactory;
+};
+
+}
+
+static void
+usage(const string& n)
+{
+ cerr << "Usage:\n";
+ cerr << "\n";
+ cerr << n << " [options] dbenv db\n";
+ cerr << n << " -c dbenv [db]\n";
+ cerr << "\n";
+ cerr <<
+ "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"
+ "-d, --debug Print debug messages.\n"
+ "--ice Permit `Ice' prefix (for building Ice source code only).\n"
+ "--underscore Permit underscores in Slice identifiers.\n"
+ "-o FILE Output sample descriptors into the file FILE.\n"
+ "-f FILE Execute the descriptors in the file FILE.\n"
+ "--load SLICE Load Slice definitions from the file SLICE.\n"
+ "-e Indicates the database is an Evictor database.\n"
+ "--key TYPE Specifies the Slice type of the database key.\n"
+ "--value TYPE Specifies the Slice type of the database value.\n"
+ "--select EXPR Dump a record only if EXPR is true.\n"
+ "-c, --catalog Display information about the databases in an\n"
+ " environment, or about a particular database.\n"
+ ;
+}
+
+static void
+printCatalogData(const string& dbName, const Freeze::CatalogData& data)
+{
+ cout << dbName << ": ";
+ if(data.evictor)
+ {
+ cout << "Evictor database" << endl;
+ }
+ else
+ {
+ cout << "Map database" << endl;
+ cout << " key type = " << data.key << endl;
+ cout << " value type = " << data.value << endl;
+ }
+}
+
+static int
+run(const Ice::StringSeq& originalArgs, const Ice::CommunicatorPtr& communicator)
+{
+ vector<string> cppArgs;
+ bool debug;
+ bool ice = true; // Needs to be true in order to create default definitions.
+ bool underscore;
+ string outputFile;
+ string inputFile;
+ vector<string> slice;
+ bool evictor;
+ string keyTypeName;
+ string valueTypeName;
+ string selectExpr;
+ string dbEnvName, dbName;
+ const string appName = originalArgs[0];
+ 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("d", "debug");
+ opts.addOpt("", "ice");
+ opts.addOpt("", "underscore");
+ opts.addOpt("o", "", IceUtilInternal::Options::NeedArg);
+ opts.addOpt("f", "", IceUtilInternal::Options::NeedArg);
+ opts.addOpt("", "load", IceUtilInternal::Options::NeedArg, "", IceUtilInternal::Options::Repeat);
+ opts.addOpt("e");
+ opts.addOpt("", "key", IceUtilInternal::Options::NeedArg);
+ opts.addOpt("", "value", IceUtilInternal::Options::NeedArg);
+ opts.addOpt("", "select", IceUtilInternal::Options::NeedArg);
+ opts.addOpt("c", "catalog");
+
+ vector<string> args;
+ try
+ {
+ args = opts.parse(originalArgs);
+ }
+ catch(const IceUtilInternal::BadOptException& e)
+ {
+ cerr << appName << ": " << e.reason << endl;
+ usage(appName);
+ return EXIT_FAILURE;
+ }
+
+ //
+ // Freeze creates a lock file by default to prevent multiple processes from opening
+ // the same database environment simultaneously. In the case of a read-only program
+ // such as dumpdb, however, we still want to be able to open the environment despite
+ // the lock. This assumes of course that the other process has opened the environment
+ // with DbPrivate=0. If DbPrivate=0 is also set for dumpdb, we disable the lock.
+ //
+ if(!args.empty())
+ {
+ //
+ // If an argument is present, we assume it is the name of the database environment.
+ //
+ Ice::PropertiesPtr props = communicator->getProperties();
+ string prefix = "Freeze.DbEnv." + args[0];
+ if(props->getPropertyAsIntWithDefault(prefix + ".DbPrivate", 1) == 0)
+ {
+ props->setProperty(prefix + ".LockFile", "0");
+ }
+ }
+
+ if(opts.isSet("h"))
+ {
+ usage(appName);
+ return EXIT_SUCCESS;
+ }
+ if(opts.isSet("version"))
+ {
+ cout << ICE_STRING_VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+ if(opts.isSet("c"))
+ {
+ if(args.empty())
+ {
+ cerr << appName << ": no database environment specified." << endl;
+ usage(appName);
+ return EXIT_FAILURE;
+ }
+ else if(args.size() > 2)
+ {
+ usage(appName);
+ return EXIT_FAILURE;
+ }
+ try
+ {
+ FreezeScript::CatalogDataMap catalog = FreezeScript::readCatalog(communicator, args[0]);
+ if(args.size() == 1)
+ {
+ if(catalog.empty())
+ {
+ cout << "Catalog is empty." << endl;
+ }
+ else
+ {
+ cout << "Catalog contents:" << endl;
+ for(FreezeScript::CatalogDataMap::const_iterator p = catalog.begin(); p != catalog.end(); ++p)
+ {
+ cout << endl;
+ printCatalogData(p->first, p->second);
+ }
+ }
+ }
+ else
+ {
+ FreezeScript::CatalogDataMap::const_iterator p = catalog.find(args[1]);
+ if(p == catalog.end())
+ {
+ cerr << appName << ": database `" << args[1] << "' not found in environment `" << args[0] << "'."
+ << endl;
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ printCatalogData(p->first, p->second);
+ }
+ }
+ return EXIT_SUCCESS;
+ }
+ catch(const FreezeScript::FailureException& ex)
+ {
+ cerr << appName << ": " << ex.reason() << endl;
+ return EXIT_FAILURE;
+ }
+ }
+ if(opts.isSet("D"))
+ {
+ vector<string> optargs = opts.argVec("D");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs.push_back("-D" + *i);
+ }
+ }
+ if(opts.isSet("U"))
+ {
+ vector<string> optargs = opts.argVec("U");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs.push_back("-U" + *i);
+ }
+ }
+ if(opts.isSet("I"))
+ {
+ vector<string> optargs = opts.argVec("I");
+ for(vector<string>::const_iterator i = optargs.begin(); i != optargs.end(); ++i)
+ {
+ cppArgs.push_back("-I" + *i);
+ }
+ }
+ debug = opts.isSet("debug");
+
+ // No need to set --ice option here -- it is always true.
+
+ underscore = opts.isSet("underscore");
+
+ if(opts.isSet("o"))
+ {
+ outputFile = opts.optArg("o");
+ }
+ if(opts.isSet("f"))
+ {
+ inputFile = opts.optArg("f");
+ }
+ if(opts.isSet("load"))
+ {
+ vector<string> optArgs = opts.argVec("load");
+ for(vector<string>::const_iterator i = optArgs.begin(); i != optArgs.end(); ++i)
+ {
+ slice.push_back(*i);
+ }
+ }
+ evictor = opts.isSet("e");
+ if(opts.isSet("key"))
+ {
+ keyTypeName = opts.optArg("key");
+ }
+ if(opts.isSet("value"))
+ {
+ valueTypeName = opts.optArg("value");
+ }
+ if(opts.isSet("select"))
+ {
+ selectExpr = opts.optArg("select");
+ }
+
+ if(outputFile.empty() && args.size() != 2)
+ {
+ usage(appName);
+ return EXIT_FAILURE;
+ }
+
+ if(!args.empty())
+ {
+ dbEnvName = args[0];
+ }
+ if(args.size() == 2)
+ {
+ dbName = args[1];
+ }
+ else
+ {
+ usage(appName);
+ return EXIT_FAILURE;
+ }
+
+ if(!inputFile.empty() && !selectExpr.empty())
+ {
+ cerr << appName << ": an input file cannot be specified with --select" << endl;
+ return EXIT_FAILURE;
+ }
+
+ Slice::UnitPtr unit = Slice::Unit::createUnit(true, true, ice, underscore);
+ FreezeScript::Destroyer<Slice::UnitPtr> unitD(unit);
+ if(!FreezeScript::parseSlice(appName, unit, slice, cppArgs, debug))
+ {
+ return EXIT_FAILURE;
+ }
+
+ FreezeScript::createEvictorSliceTypes(unit);
+
+ //
+ // If no input file was provided, then we need to generate default descriptors.
+ //
+ string descriptors;
+ if(inputFile.empty())
+ {
+ const string evictorKeyTypeName = "::Ice::Identity";
+ const string evictorValueTypeName = "::Freeze::ObjectRecord";
+
+ if((!keyTypeName.empty() && valueTypeName.empty()) || (keyTypeName.empty() && !valueTypeName.empty()))
+ {
+ cerr << appName << ": a key type and a value type must be specified" << endl;
+ usage(appName);
+ return EXIT_FAILURE;
+ }
+ else if(!evictor && keyTypeName.empty() && valueTypeName.empty())
+ {
+ try
+ {
+ FreezeScript::CatalogDataMap catalog = FreezeScript::readCatalog(communicator, dbEnvName);
+ FreezeScript::CatalogDataMap::iterator p = catalog.find(dbName);
+ if(p == catalog.end())
+ {
+ cerr << appName << ": database `" << dbName << "' not found in catalog." << endl;
+ cerr << "Current catalog databases:" << endl;
+ for(p = catalog.begin(); p != catalog.end(); ++p)
+ {
+ cerr << " " << p->first << endl;
+ }
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ if(p->second.evictor)
+ {
+ evictor = true;
+ }
+ else
+ {
+ keyTypeName = p->second.key;
+ valueTypeName = p->second.value;
+ }
+ }
+ }
+ catch(const FreezeScript::FailureException& ex)
+ {
+ cerr << appName << ": " << ex.reason() << endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ if(evictor)
+ {
+ keyTypeName = evictorKeyTypeName;
+ valueTypeName = evictorValueTypeName;
+ }
+
+ Slice::TypePtr keyType, valueType;
+ Slice::TypeList l;
+
+ l = unit->lookupType(keyTypeName, false);
+ if(l.empty())
+ {
+ cerr << appName << ": unknown key type `" << keyTypeName << "'" << endl;
+ return EXIT_FAILURE;
+ }
+ keyType = l.front();
+
+ l = unit->lookupType(valueTypeName, false);
+ if(l.empty())
+ {
+ cerr << appName << ": unknown value type `" << valueTypeName << "'" << endl;
+ return EXIT_FAILURE;
+ }
+ valueType = l.front();
+
+ ostringstream os;
+ IceUtilInternal::XMLOutput out(os);
+
+ out << se("dumpdb");
+
+ FreezeScript::SliceVisitor visitor(out, keyType, valueType, selectExpr);
+ unit->visit(&visitor, false);
+
+ out << ee;
+
+ descriptors = os.str();
+
+ if(!outputFile.empty())
+ {
+ //
+ // No nativeToUTF8 conversion necessary here, no string converter is installed
+ // by wmain() on Windows and args are assumbed to be UTF8 on Unix platforms.
+ //
+ IceUtilInternal::ofstream of(outputFile);
+ if(!of.good())
+ {
+ cerr << appName << ": unable to open file `" << outputFile << "'" << endl;
+ return EXIT_FAILURE;
+ }
+ of << descriptors << endl;
+ of.close();
+ return EXIT_SUCCESS;
+ }
+ }
+ else
+ {
+ //
+ // No nativeToUTF8 conversion necessary here, no string converter is installed
+ // by wmain() on Windows and args are assumbed to be UTF8 on Unix platforms.
+ //
+ IceUtilInternal::ifstream in(inputFile);
+ char buff[1024];
+ while(true)
+ {
+ in.read(buff, 1024);
+ descriptors.append(buff, static_cast<size_t>(in.gcount()));
+ if(in.gcount() < 1024)
+ {
+ break;
+ }
+ }
+ in.close();
+ }
+ FreezeScript::ObjectFactoryPtr objectFactory = new FreezeScript::ObjectFactory;
+ communicator->addObjectFactory(objectFactory, "");
+
+ DbEnv dbEnv(0);
+ DbTxn* txn = 0;
+ Freeze::ConnectionPtr connection;
+ int status = EXIT_SUCCESS;
+ try
+ {
+#ifdef _WIN32
+ //
+ // Berkeley DB may use a different C++ runtime.
+ //
+ dbEnv.set_alloc(::malloc, ::realloc, ::free);
+#endif
+
+ //
+ // Open the database environment and start a transaction.
+ //
+ {
+ u_int32_t flags = DB_THREAD | DB_CREATE | DB_INIT_TXN | DB_INIT_MPOOL;
+ dbEnv.open(dbEnvName.c_str(), flags, FREEZE_SCRIPT_DB_MODE);
+ }
+
+ //
+ // We're creating a connection just to make sure the database environment
+ // isn't locked.
+ //
+ connection = Freeze::createConnection(communicator, dbEnvName, dbEnv);
+
+ dbEnv.txn_begin(0, &txn, 0);
+
+ FreezeScript::ErrorReporterPtr errorReporter = new FreezeScript::ErrorReporter(cerr, false);
+ try
+ {
+ FreezeScript::DataFactoryPtr factory = new FreezeScript::DataFactory(communicator, unit, errorReporter);
+ FreezeScript::DescriptorHandler dh(factory, unit, errorReporter, objectFactory);
+
+ istringstream istr(descriptors);
+ IceXML::Parser::parse(istr, dh);
+
+ FreezeScript::DumpDBDescriptorPtr descriptor = dh.descriptor();
+ descriptor->validate();
+
+ if(evictor)
+ {
+ //
+ // The evictor database file contains multiple databases. We must first
+ // determine the names of those databases, ignoring any whose names
+ // begin with "$index:". Each database represents a separate facet, with
+ // the facet name used as the database name. The database named "$default"
+ // represents the main object.
+ //
+ vector<string> dbNames;
+ {
+ Db db(&dbEnv, 0);
+ db.open(txn, dbName.c_str(), 0, DB_UNKNOWN, DB_RDONLY, 0);
+ Dbt dbKey, dbValue;
+ dbKey.set_flags(DB_DBT_MALLOC);
+ dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
+
+ Dbc* dbc = 0;
+ db.cursor(0, &dbc, 0);
+
+ while(dbc->get(&dbKey, &dbValue, DB_NEXT) == 0)
+ {
+ string s(static_cast<char*>(dbKey.get_data()), dbKey.get_size());
+ if(s.find("$index:") != 0)
+ {
+ dbNames.push_back(s);
+ }
+ free(dbKey.get_data());
+ }
+
+ dbc->close();
+ db.close(0);
+ }
+
+ //
+ // Dump each database.
+ //
+ for(vector<string>::iterator p = dbNames.begin(); p != dbNames.end(); ++p)
+ {
+ string name = *p;
+ string facet = (name == "$default" ? string("") : name);
+ Db db(&dbEnv, 0);
+ db.open(txn, dbName.c_str(), name.c_str(), DB_BTREE, DB_RDONLY, FREEZE_SCRIPT_DB_MODE);
+ descriptor->dump(communicator, &db, txn, facet);
+ db.close(0);
+ }
+ }
+ else
+ {
+ //
+ // Dump a map database.
+ //
+ Db db(&dbEnv, 0);
+ db.open(txn, dbName.c_str(), 0, DB_BTREE, DB_RDONLY, FREEZE_SCRIPT_DB_MODE);
+ descriptor->dump(communicator, &db, txn, "");
+ db.close(0);
+ }
+ }
+ catch(const IceXML::ParserException& ex)
+ {
+ errorReporter->error(ex.reason());
+ }
+ }
+ catch(const DbException& ex)
+ {
+ cerr << appName << ": database error: " << ex.what() << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ try
+ {
+ if(txn)
+ {
+ txn->abort();
+ }
+ dbEnv.close(0);
+ }
+ catch(const DbException& ex)
+ {
+ cerr << appName << ": database error: " << ex.what() << endl;
+ }
+ if(connection)
+ {
+ connection->close();
+ connection = 0;
+ }
+ throw;
+ }
+
+ try
+ {
+ if(txn)
+ {
+ txn->abort();
+ }
+ if(connection)
+ {
+ connection->close();
+ }
+ dbEnv.close(0);
+ }
+ catch(const DbException& ex)
+ {
+ cerr << appName << ": database error: " << ex.what() << endl;
+ status = EXIT_FAILURE;
+ }
+
+ return status;
+}
+
+//COMPILERFIX: Borland C++ 2010 doesn't support wmain for console applications.
+#if defined(_WIN32 ) && !defined(__BCPLUSPLUS__)
+
+int
+wmain(int argc, wchar_t* argv[])
+
+#else
+
+int
+main(int argc, char* argv[])
+
+#endif
+{
+ Ice::StringSeq args = Ice::argsToStringSeq(argc, argv);
+ assert(args.size() > 0);
+ const string appName = args[0];
+ Ice::CommunicatorPtr communicator;
+ int status = EXIT_SUCCESS;
+ try
+ {
+ communicator = Ice::initialize(args);
+ status = run(args, communicator);
+ }
+ catch(const FreezeScript::FailureException& ex)
+ {
+ string reason = ex.reason();
+ cerr << appName << ": " << reason;
+ if(reason[reason.size() - 1] != '\n')
+ {
+ cerr << endl;
+ }
+ return EXIT_FAILURE;
+ }
+ catch(const std::exception& ex)
+ {
+ cerr << appName << ": " << ex.what() << endl;
+ status = EXIT_FAILURE;
+ }
+ catch(...)
+ {
+ cerr << appName << ": unknown error" << endl;
+ return EXIT_FAILURE;
+ }
+
+ if(communicator)
+ {
+ communicator->destroy();
+ }
+
+ return status;
+}
+
+//
+// SliceVisitor
+//
+FreezeScript::SliceVisitor::SliceVisitor(IceUtilInternal::XMLOutput& out, const Slice::TypePtr& keyType,
+ const Slice::TypePtr& valueType, const string& selectExpr) :
+ _out(out)
+{
+ out << se("database") << attr("key", typeToString(keyType)) << attr("value", typeToString(valueType));
+ out << se("record");
+ if(!selectExpr.empty())
+ {
+ out << se("if") << attr("test", selectExpr);
+ out << se("echo") << attr("message", "Key: ") << attr("value", "key") << ee;
+ out << se("echo") << attr("message", "Value: ") << attr("value", "value") << ee;
+ out << ee;
+ }
+ else
+ {
+ out << se("echo") << attr("message", "Key: ") << attr("value", "key") << ee;
+ out << se("echo") << attr("message", "Value: ") << attr("value", "value") << ee;
+ }
+ out << ee;
+ out << ee;
+}
+
+bool
+FreezeScript::SliceVisitor::visitClassDefStart(const Slice::ClassDefPtr& v)
+{
+ if(v->isInterface() || v->isLocal())
+ {
+ return false;
+ }
+
+ string scoped = v->scoped();
+ if(ignoreType(scoped))
+ {
+ return false;
+ }
+
+ _out.newline();
+ _out.newline();
+ _out << "<!-- class " << scoped << " -->";
+ _out << se("dump") << attr("type", scoped) << ee;
+
+ return false;
+}
+
+bool
+FreezeScript::SliceVisitor::visitStructStart(const Slice::StructPtr& v)
+{
+ if(v->isLocal())
+ {
+ return false;
+ }
+
+ string scoped = v->scoped();
+ if(ignoreType(scoped))
+ {
+ return false;
+ }
+
+ _out.newline();
+ _out.newline();
+ _out << "<!-- struct " << scoped << " -->";
+ _out << se("dump") << attr("type", scoped) << ee;
+
+ return false;
+}
+
+void
+FreezeScript::SliceVisitor::visitSequence(const Slice::SequencePtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ if(ignoreType(scoped))
+ {
+ return;
+ }
+
+ _out.newline();
+ _out.newline();
+ _out << "<!-- sequence " << scoped << " -->";
+ _out << se("dump") << attr("type", scoped) << ee;
+}
+
+void
+FreezeScript::SliceVisitor::visitDictionary(const Slice::DictionaryPtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ if(ignoreType(scoped))
+ {
+ return;
+ }
+
+ _out.newline();
+ _out.newline();
+ _out << "<!-- dictionary " << scoped << " -->";
+ _out << se("dump") << attr("type", scoped) << ee;
+}
+
+void
+FreezeScript::SliceVisitor::visitEnum(const Slice::EnumPtr& v)
+{
+ if(v->isLocal())
+ {
+ return;
+ }
+
+ string scoped = v->scoped();
+ if(ignoreType(scoped))
+ {
+ return;
+ }
+
+ _out.newline();
+ _out.newline();
+ _out << "<!-- enum " << scoped << " -->";
+ _out << se("dump") << attr("type", scoped) << ee;
+}
+
+//
+// DescriptorHandler
+//
+FreezeScript::DescriptorHandler::DescriptorHandler(const DataFactoryPtr& factory, const Slice::UnitPtr& unit,
+ const ErrorReporterPtr& errorReporter,
+ const FreezeScript::ObjectFactoryPtr& objectFactory) :
+ _factory(factory), _unit(unit), _errorReporter(errorReporter), _objectFactory(objectFactory)
+{
+}
+
+void
+FreezeScript::DescriptorHandler::startElement(const string& name, const IceXML::Attributes& attributes, int line,
+ int column)
+{
+ DescriptorPtr d;
+
+ if(name == "dumpdb")
+ {
+ if(_current)
+ {
+ _errorReporter->descriptorError("<dumpdb> must be the top-level element", line);
+ }
+
+ _descriptor = new DumpDBDescriptor(line, _factory, _errorReporter, attributes, _unit);
+ d = _descriptor;
+ }
+ else if(name == "database")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<database> must be a child of <dumpdb>", line);
+ }
+
+ d = new DatabaseDescriptor(_current, line, _factory, _errorReporter, attributes, _unit);
+ }
+ else if(name == "record")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<record> must be a child of <database>", line);
+ }
+
+ d = new RecordDescriptor(_current, line, _factory, _errorReporter, attributes, _unit, _objectFactory);
+ }
+ else if(name == "dump")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<dump> must be a child of <dumpdb>", line);
+ }
+
+ d = new DumpDescriptor(_current, line, _factory, _errorReporter, attributes, _unit);
+ }
+ else if(name == "set")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<set> cannot be a top-level element", line);
+ }
+
+ d = new SetDescriptor(_current, line, _factory, _errorReporter, attributes);
+ }
+ else if(name == "define")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<define> cannot be a top-level element", line);
+ }
+
+ d = new DefineDescriptor(_current, line, _factory, _errorReporter, attributes, _unit);
+ }
+ else if(name == "add")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<add> cannot be a top-level element", line);
+ }
+
+ d = new AddDescriptor(_current, line, _factory, _errorReporter, attributes);
+ }
+ else if(name == "remove")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<remove> cannot be a top-level element", line);
+ }
+
+ d = new RemoveDescriptor(_current, line, _factory, _errorReporter, attributes);
+ }
+ else if(name == "fail")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<fail> cannot be a top-level element", line);
+ }
+
+ d = new FailDescriptor(_current, line, _factory, _errorReporter, attributes);
+ }
+ else if(name == "echo")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<echo> cannot be a top-level element", line);
+ }
+
+ d = new EchoDescriptor(_current, line, _factory, _errorReporter, attributes, cout);
+ }
+ else if(name == "if")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<if> cannot be a top-level element", line);
+ }
+
+ d = new IfDescriptor(_current, line, _factory, _errorReporter, attributes);
+ }
+ else if(name == "iterate")
+ {
+ if(!_current)
+ {
+ _errorReporter->descriptorError("<iterate> cannot be a top-level element", line);
+ }
+
+ d = new IterateDescriptor(_current, line, _factory, _errorReporter, attributes);
+ }
+ else
+ {
+ _errorReporter->descriptorError("unknown descriptor `" + name + "'", line);
+ }
+
+ if(_current)
+ {
+ _current->addChild(d);
+ }
+ _current = d;
+}
+
+void
+FreezeScript::DescriptorHandler::endElement(const std::string& name, int, int)
+{
+ assert(_current);
+ _current = _current->parent();
+}
+
+void
+FreezeScript::DescriptorHandler::characters(const std::string&, int, int)
+{
+}
+
+void
+FreezeScript::DescriptorHandler::error(const std::string& msg, int line, int col)
+{
+ _errorReporter->descriptorError(msg, line);
+}
+
+FreezeScript::DumpDBDescriptorPtr
+FreezeScript::DescriptorHandler::descriptor() const
+{
+ return _descriptor;
+}