diff options
Diffstat (limited to 'xsd/xsd/cxx/parser/generator.cxx')
-rw-r--r-- | xsd/xsd/cxx/parser/generator.cxx | 1588 |
1 files changed, 1588 insertions, 0 deletions
diff --git a/xsd/xsd/cxx/parser/generator.cxx b/xsd/xsd/cxx/parser/generator.cxx new file mode 100644 index 0000000..b3aee76 --- /dev/null +++ b/xsd/xsd/cxx/parser/generator.cxx @@ -0,0 +1,1588 @@ +// file : xsd/cxx/parser/generator.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <type-map/lexer.hxx> +#include <type-map/parser.hxx> +#include <type-map/type-map.hxx> + +#include <cxx/parser/elements.hxx> +#include <cxx/parser/generator.hxx> + +#include <cxx/parser/validator.hxx> +#include <cxx/parser/name-processor.hxx> +#include <cxx/parser/state-processor.hxx> +#include <cxx/parser/type-processor.hxx> + +#include <cxx/parser/parser-header.hxx> +#include <cxx/parser/parser-inline.hxx> +#include <cxx/parser/parser-source.hxx> +#include <cxx/parser/parser-forward.hxx> + +#include <cxx/parser/impl-header.hxx> +#include <cxx/parser/impl-source.hxx> +#include <cxx/parser/driver-source.hxx> + +#include <cxx/parser/element-validation-source.hxx> +#include <cxx/parser/attribute-validation-source.hxx> +#include <cxx/parser/characters-validation-source.hxx> + +#include <xsd-frontend/semantic-graph.hxx> + +#include <backend-elements/regex.hxx> +#include <backend-elements/indentation/cxx.hxx> +#include <backend-elements/indentation/sloc.hxx> +#include <backend-elements/indentation/clip.hxx> + +#include <cult/containers/set.hxx> +#include <cult/containers/vector.hxx> + +#include <boost/filesystem/fstream.hpp> + +#include <iostream> + +#include <usage.hxx> + +#include "../../../libxsd/xsd/cxx/version.hxx" + +using std::endl; +using std::wcerr; + +using namespace XSDFrontend::SemanticGraph; + +// +// +typedef +boost::filesystem::wifstream +WideInputFileStream; + +typedef +boost::filesystem::wofstream +WideOutputFileStream; + +typedef +boost::filesystem::ifstream +NarrowInputFileStream; + +namespace CXX +{ + namespace + { + Char const copyright_gpl[] = + "// Copyright (C) 2005-2010 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD, an XML Schema to\n" + "// C++ data binding compiler.\n" + "//\n" + "// This program is free software; you can redistribute it and/or modify\n" + "// it under the terms of the GNU General Public License version 2 as\n" + "// published by the Free Software Foundation.\n" + "//\n" + "// This program is distributed in the hope that it will be useful,\n" + "// but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "// GNU General Public License for more details.\n" + "//\n" + "// You should have received a copy of the GNU General Public License\n" + "// along with this program; if not, write to the Free Software\n" + "// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" + "//\n" + "// In addition, as a special exception, Code Synthesis Tools CC gives\n" + "// permission to link this program with the Xerces-C++ library (or with\n" + "// modified versions of Xerces-C++ that use the same license as Xerces-C++),\n" + "// and distribute linked combinations including the two. You must obey\n" + "// the GNU General Public License version 2 in all respects for all of\n" + "// the code used other than Xerces-C++. If you modify this copy of the\n" + "// program, you may extend this exception to your version of the program,\n" + "// but you are not obligated to do so. If you do not wish to do so, delete\n" + "// this exception statement from your version.\n" + "//\n" + "// Furthermore, Code Synthesis Tools CC makes a special exception for\n" + "// the Free/Libre and Open Source Software (FLOSS) which is described\n" + "// in the accompanying FLOSSE file.\n" + "//\n\n"; + + Char const copyright_proprietary[] = + "// Copyright (C) 2005-2010 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD, an XML Schema\n" + "// to C++ data binding compiler, in the Proprietary License mode.\n" + "// You should have received a proprietary license from Code Synthesis\n" + "// Tools CC prior to generating this code. See the license text for\n" + "// conditions.\n" + "//\n\n"; + + Char const copyright_impl[] = + "// Not copyrighted - public domain.\n" + "//\n" + "// This sample parser implementation was generated by CodeSynthesis XSD,\n" + "// an XML Schema to C++ data binding compiler. You may use it in your\n" + "// programs without any restrictions.\n" + "//\n\n"; + } + + namespace Parser + { + namespace CLI + { + extern Key type_map = "type-map"; + extern Key char_type = "char-type"; + extern Key char_encoding = "char-encoding"; + extern Key output_dir = "output-dir"; + extern Key xml_parser = "xml-parser"; + extern Key generate_inline = "generate-inline"; + extern Key generate_validation = "generate-validation"; + extern Key suppress_validation = "suppress-validation"; + extern Key generate_polymorphic = "generate-polymorphic"; + extern Key generate_noop_impl = "generate-noop-impl"; + extern Key generate_print_impl = "generate-print-impl"; + extern Key generate_test_driver = "generate-test-driver"; + extern Key force_overwrite = "force-overwrite"; + extern Key root_element_first = "root-element-first"; + extern Key root_element_last = "root-element-last"; + extern Key root_element = "root-element"; + extern Key generate_xml_schema = "generate-xml-schema"; + extern Key extern_xml_schema = "extern-xml-schema"; + extern Key skel_type_suffix = "skel-type-suffix"; + extern Key skel_file_suffix = "skel-file-suffix"; + extern Key impl_type_suffix = "impl-type-suffix"; + extern Key impl_file_suffix = "impl-file-suffix"; + extern Key namespace_map = "namespace-map"; + extern Key namespace_regex = "namespace-regex"; + extern Key namespace_regex_trace = "namespace-regex-trace"; + extern Key reserved_name = "reserved-name"; + extern Key include_with_brackets = "include-with-brackets"; + extern Key include_prefix = "include-prefix"; + extern Key include_regex = "include-regex"; + extern Key include_regex_trace = "include-regex-trace"; + extern Key guard_prefix = "guard-prefix"; + extern Key hxx_suffix = "hxx-suffix"; + extern Key ixx_suffix = "ixx-suffix"; + extern Key cxx_suffix = "cxx-suffix"; + extern Key hxx_regex = "hxx-regex"; + extern Key ixx_regex = "ixx-regex"; + extern Key cxx_regex = "cxx-regex"; + extern Key hxx_prologue = "hxx-prologue"; + extern Key ixx_prologue = "ixx-prologue"; + extern Key cxx_prologue = "cxx-prologue"; + extern Key prologue = "prologue"; + extern Key hxx_epilogue = "hxx-epilogue"; + extern Key ixx_epilogue = "ixx-epilogue"; + extern Key cxx_epilogue = "cxx-epilogue"; + extern Key epilogue = "epilogue"; + extern Key hxx_prologue_file = "hxx-prologue-file"; + extern Key ixx_prologue_file = "ixx-prologue-file"; + extern Key cxx_prologue_file = "cxx-prologue-file"; + extern Key prologue_file = "prologue-file"; + extern Key hxx_epilogue_file = "hxx-epilogue-file"; + extern Key ixx_epilogue_file = "ixx-epilogue-file"; + extern Key cxx_epilogue_file = "cxx-epilogue-file"; + extern Key epilogue_file = "epilogue-file"; + extern Key export_symbol = "export-symbol"; + extern Key export_maps = "export-maps"; + extern Key import_maps = "import-maps"; + extern Key show_anonymous = "show-anonymous"; + extern Key show_sloc = "show-sloc"; + extern Key proprietary_license = "proprietary-license"; + } + } + + Void Parser::Generator:: + usage () + { + std::wostream& e (wcerr); + ::CLI::Indent::Clip< ::CLI::OptionsUsage, WideChar> clip (e); + + e << "--type-map <mapfile>" << endl + << " Read XML Schema to C++ type mapping information\n" + << " from <mapfile>. Repeat this option to specify\n" + << " several type maps. Type maps are considered in\n" + << " order of appearance and the first match is used." + << endl; + + e << "--char-type <type>" << endl + << " Use <type> as the base character type. Valid\n" + << " values are 'char' (default) and 'wchar_t'." + << endl; + + e << "--char-encoding <enc>" << endl + << " Specify the character encoding that should be used\n" + << " in the object model. Valid values for the 'char'\n" + << " character type are 'utf8' (default), 'iso8859-1',\n" + << " 'lcp', and 'custom'. For the 'wchar_t' character\n" + << " type the only valid value is 'auto'." + << endl; + + e << "--output-dir <dir>" << endl + << " Write generated files to <dir> instead of current\n" + << " directory." + << endl; + + e << "--xml-parser <parser>" << endl + << " Use <parser> as the underlying XML parser. Valid\n" + << " values are 'xerces' (default) and 'expat'." + << endl; + + e << "--generate-inline" << endl + << " Generate certain functions inline." + << endl; + + e << "--generate-validation" << endl + << " Generate validation code." + << endl; + + e << "--suppress-validation" << endl + << " Suppress the generation of validation code." + << endl; + + e << "--generate-polymorphic" << endl + << " Generate polymorphism-aware code. Specify this\n" + << " option if you use substitution groups or xsi:type." + << endl; + + e << "--generate-noop-impl" << endl + << " Generate a sample parser implementation that\n" + << " does nothing (no operation)." + << endl; + + e << "--generate-print-impl" << endl + << " Generate a sample parser implementation that\n" + << " prints the XML data to STDOUT." + << endl; + + e << "--generate-test-driver" << endl + << " Generate a test driver for the sample parser\n" + << " implementation." + << endl; + + e << "--force-overwrite" << endl + << " Force overwriting of the existing implementation\n" + << " and test driver files." + << endl; + + e << "--root-element-first" << endl + << " Indicate that the first global element is the\n" + << " document root." + << endl; + + e << "--root-element-last" << endl + << " Indicate that the last global element is the\n" + << " document root." + << endl; + + e << "--root-element <element>" << endl + << " Indicate that <element> is the document root." + << endl; + + e << "--generate-xml-schema" << endl + << " Generate a C++ header file as if the schema being\n" + << " compiled defines the XML Schema namespace." + << endl; + + e << "--extern-xml-schema <file>" << endl + << " Generate code as if the XML Schema namespace was\n" + << " defined in <file> and xsd:included in the schema\n" + << " being compiled." + << endl; + + e << "--skel-type-suffix <suffix>" << endl + << " Use <suffix> instead of the default '_pskel' to\n" + << " construct the names of generated parser skeletons." + << endl; + + e << "--skel-file-suffix <suffix>" << endl + << " Use <suffix> instead of the default '-pskel' to\n" + << " construct the names of generated parser skeleton\n" + << " files." + << endl; + + e << "--impl-type-suffix <suffix>" << endl + << " Use <suffix> instead of the default '_pimpl' to\n" + << " construct the names of parser implementations for\n" + << " the built-in XML Schema types and sample parser\n" + << " implementations." + << endl; + + e << "--impl-file-suffix <suffix>" << endl + << " Use <suffix> instead of the default '-pimpl' to\n" + << " construct the names of generated sample parser\n" + << " implementation files." + << endl; + + e << "--namespace-map <xns>=<cns>" << endl + << " Map XML Schema namespace <xns> to C++ namespace\n" + << " <cns>. Repeat this option to specify mapping for\n" + << " more than one XML Schema namespace." + << endl; + + e << "--namespace-regex <regex>" << endl + << " Add <regex> to the list of regular expressions\n" + << " used to translate XML Schema namespace names to\n" + << " C++ namespace names." + << endl; + + e << "--namespace-regex-trace" << endl + << " Trace the process of applying regular expressions\n" + << " specified with the --namespace-regex option." + << endl; + + e << "--reserved-name <name>" << endl + << " Add <name> to the list of names that should not\n" + << " be used as identifiers. The name can optionally\n" + << " be followed by '=' and the replacement name that\n" + << " should be used instead." + << endl; + + e << "--include-with-brackets" << endl + << " Use angle brackets (<>) instead of quotes (\"\") in\n" + << " generated #include directives." + << endl; + + e << "--include-prefix <prefix>" << endl + << " Add <prefix> to generated #include directive\n" + << " paths." + << endl; + + e << "--include-regex <regex>" << endl + << " Add <regex> to the list of regular expressions\n" + << " used to transform #include directive paths." + << endl; + + e << "--include-regex-trace" << endl + << " Trace the process of applying regular expressions\n" + << " specified with the --include-regex option." + << endl; + + e << "--guard-prefix <prefix>" << endl + << " Add <prefix> to generated header inclusion guards." + << endl; + + e << "--hxx-suffix <suffix>" << endl + << " Use <suffix> instead of the default '.hxx' to\n" + << " construct the name of the header file." + << endl; + + e << "--ixx-suffix <suffix>" << endl + << " Use <suffix> instead of the default '.ixx' to\n" + << " construct the name of the inline file." + << endl; + + e << "--cxx-suffix <suffix>" << endl + << " Use <suffix> instead of the default '.cxx' to\n" + << " construct the name of the source file." + << endl; + + e << "--hxx-regex <regex>" << endl + << " Use <regex> to construct the name of the header\n" + << " file." + << endl; + + e << "--ixx-regex <regex>" << endl + << " Use <regex> to construct the name of the inline\n" + << " file." + << endl; + + e << "--cxx-regex <regex>" << endl + << " Use <regex> to construct the name of the source\n" + << " file." + << endl; + + + // Prologues. + // + e << "--hxx-prologue <text>" << endl + << " Insert <text> at the beginning of the header file." + << endl; + + e << "--ixx-prologue <text>" << endl + << " Insert <text> at the beginning of the inline file." + << endl; + + e << "--cxx-prologue <text>" << endl + << " Insert <text> at the beginning of the source file." + << endl; + + e << "--prologue <text>" << endl + << " Insert <text> at the beginning of each generated\n" + << " file for which there is no file-specific prologue." + << endl; + + + // Epilogues. + // + e << "--hxx-epilogue <text>" << endl + << " Insert <text> at the end of the header file." + << endl; + + e << "--ixx-epilogue <text>" << endl + << " Insert <text> at the end of the inline file." + << endl; + + e << "--cxx-epilogue <text>" << endl + << " Insert <text> at the end of the source file." + << endl; + + e << "--epilogue <text>" << endl + << " Insert <text> at the end of each generated file\n" + << " for which there is no file-specific epilogue." + << endl; + + + // Prologue files. + // + e << "--hxx-prologue-file <file>" << endl + << " Insert the content of the <file> at the beginning\n" + << " of the header file." + << endl; + + e << "--ixx-prologue-file <file>" << endl + << " Insert the content of the <file> at the beginning\n" + << " of the inline file." + << endl; + + e << "--cxx-prologue-file <file>" << endl + << " Insert the content of the <file> at the beginning\n" + << " of the source file." + << endl; + + e << "--prologue-file <file>" << endl + << " Insert the content of the <file> at the beginning\n" + << " of each generated file for which there is no file-\n" + << " specific prologue file." + << endl; + + + // Epilogue files. + // + e << "--hxx-epilogue-file <file>" << endl + << " Insert the content of the <file> at the end of\n" + << " the header file." + << endl; + + e << "--ixx-epilogue-file <file>" << endl + << " Insert the content of the <file> at the end of\n" + << " the inline file." + << endl; + + e << "--cxx-epilogue-file <file>" << endl + << " Insert the content of the <file> at the end of\n" + << " the source file." + << endl; + + e << "--epilogue-file <file>" << endl + << " Insert the content of the <file> at the end of\n" + << " each generated file for which there is no file-\n" + << " specific epilogue file." + << endl; + + + // Misc. + // + e << "--custom-literals <file>" << endl + << " Load custom XML string to C++ literal mappings\n" + << " from <file>." + << endl; + + e << "--export-symbol <symbol>" << endl + << " Export symbol for Win32 DLL export/import control." + << endl; + + e << "--export-maps" << endl + << " Export polymorphism support maps from Win32 DLL." + << endl; + + e << "--import-maps" << endl + << " Import polymorphism support maps from Win32 DLL." + << endl; + + e << "--show-anonymous" << endl + << " Show elements and attributes that are of anonymous\n" + << " types." + << endl; + + e << "--show-sloc" << endl + << " Show the number of generated physical source lines\n" + << " of code (SLOC)." + << endl; + + e << "--sloc-limit <num>" << endl + << " Check that the number of generated physical source\n" + << " lines of code (SLOC) does not exceed <num>." + << endl; + + e << "--options-file <file>" << endl + << " Read additional options from <file>. Each option\n" + << " should appear on a separate line optionally\n" + << " followed by space and an argument." + << endl; + + e << "--proprietary-license" << endl + << " Indicate that the generated code is licensed under\n" + << " a proprietary license instead of the GPL." + << endl; + } + + Parser::CLI::OptionsSpec Parser::Generator:: + options_spec () + { + CLI::OptionsSpec spec; + + spec.option<CLI::char_type> ().default_value ("char"); + spec.option<CLI::xml_parser> ().default_value ("xerces"); + + spec.option<CLI::skel_file_suffix> ().default_value ("-pskel"); + spec.option<CLI::skel_type_suffix> ().default_value ("_pskel"); + spec.option<CLI::impl_file_suffix> ().default_value ("-pimpl"); + spec.option<CLI::impl_type_suffix> ().default_value ("_pimpl"); + + spec.option<CLI::hxx_suffix> ().default_value (".hxx"); + spec.option<CLI::ixx_suffix> ().default_value (".ixx"); + spec.option<CLI::cxx_suffix> ().default_value (".cxx"); + + return spec; + } + + + namespace + { + template <typename S> + Void + open (S& ifs, NarrowString const& path) + { + try + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + Path fs_path (path, boost::filesystem::native); +#else + Path fs_path (path.c_str()); +#endif + ifs.open (fs_path, std::ios_base::in | std::ios_base::binary); + + if (!ifs.is_open ()) + { + wcerr << path.c_str () << ": error: unable to open in read mode" + << endl; + + throw Parser::Generator::Failed (); + } + } + catch (InvalidPath const&) + { + wcerr << "error: '" << path.c_str () << "' is not a valid " + << "filesystem path" << endl; + + throw Parser::Generator::Failed (); + } + } + + Void + append (WideOutputFileStream& os, + NarrowString const& path, + WideInputFileStream& default_is) + { + using std::ios_base; + + if (path) + { + WideInputFileStream is; + open (is, path); + os << is.rdbuf (); + } + else if (default_is.is_open ()) + { + os << default_is.rdbuf (); + default_is.seekg (0, ios_base::beg); + } + } + + Void + append (WideOutputFileStream& os, + Cult::Containers::Vector<NarrowString> const& primary, + Cult::Containers::Vector<NarrowString> const& def) + { + Cult::Containers::Vector<NarrowString> const& v ( + primary.empty () ? def : primary); + + for (Containers::Vector<NarrowString>::ConstIterator + i (v.begin ()), e (v.end ()); i != e; ++i) + { + os << i->c_str () << endl; + } + } + } + + + UnsignedLong Parser::Generator:: + generate (Parser::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + Boolean fpt, + StringLiteralMap const& string_literal_map, + Boolean gen_driver, + const WarningSet& disabled_warnings, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef BackendElements::Regex::Expression<Char> Regex; + + try + { + Boolean generate_xml_schema (ops.value<CLI::generate_xml_schema> ()); + + // We could be compiling several schemas at once in which case + // handling of the --generate-xml-schema option gets tricky: we + // will need to rely on the presence of the --extern-xml-schema + // to tell us which (fake) schema file corresponds to XML Schema. + // + if (generate_xml_schema) + { + if (NarrowString name = ops.value<CLI::extern_xml_schema> ()) + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + if (file_path.native_file_string () != name) +#else + if (file_path.string () != name) +#endif + generate_xml_schema = false; + } + } + + Boolean impl (!generate_xml_schema && + (ops.value<CLI::generate_noop_impl> () || + ops.value<CLI::generate_print_impl> ())); + + Boolean driver (gen_driver && !generate_xml_schema && + ops.value<CLI::generate_test_driver> ()); + + // Evaluate the graph for possibility of generating something useful. + // + { + Validator validator; + if (!validator.validate ( + ops, schema, file_path, driver, disabled_warnings)) + throw Failed (); + } + + // Process names. + // + { + NameProcessor proc; + proc.process (ops, schema, file_path, string_literal_map); + } + + Boolean validation ((ops.value<CLI::xml_parser> () == "expat" || + ops.value<CLI::generate_validation> ()) && + !ops.value<CLI::suppress_validation> ()); + + // Compute state machine info. + // + if (validation) + { + StateProcessor proc; + proc.process (schema, file_path); + } + + // Read-in type maps. + // + TypeMap::Namespaces type_map; + { + using namespace TypeMap; + typedef Containers::Vector<NarrowString> Files; + + Files const& files (ops.value<CLI::type_map> ()); + + for (Files::ConstIterator f (files.begin ()); f != files.end (); ++f ) + { + NarrowInputFileStream ifs; + open (ifs, *f); + + Lexer l (ifs, *f); + TypeMap::Parser p (l, *f); + + if (!p.parse (type_map)) + throw Failed (); + } + + // Add the built-in mappings at the end. + // + + // String-based types. + // + String char_type (ops.value<CLI::char_type> ()); + String string_type; + + if (char_type == L"char") + string_type = L"::std::string"; + else if (char_type == L"wchar_t") + string_type = L"::std::wstring"; + else + string_type = L"::std::basic_string< " + char_type + L" >"; + + String xns; + { + Context ctx (std::wcerr, schema, file_path, ops, 0, 0, 0, 0); + xns = ctx.xs_ns_name (); + } + + String buffer (L"::std::auto_ptr< " + xns + L"::buffer >"); + TypeMap::Namespace xsd ("http://www\\.w3\\.org/2001/XMLSchema"); + + xsd.types_push_back ("string", string_type); + xsd.types_push_back ("normalizedString", string_type); + xsd.types_push_back ("token", string_type); + xsd.types_push_back ("Name", string_type); + xsd.types_push_back ("NMTOKEN", string_type); + xsd.types_push_back ("NMTOKENS", xns + L"::string_sequence"); + xsd.types_push_back ("NCName", string_type); + + xsd.types_push_back ("ID", string_type); + xsd.types_push_back ("IDREF", string_type); + xsd.types_push_back ("IDREFS", xns + L"::string_sequence"); + + xsd.types_push_back ("language", string_type); + xsd.types_push_back ("anyURI", string_type); + xsd.types_push_back ("QName", xns + L"::qname"); + + xsd.types_push_back ("base64Binary", buffer, buffer); + xsd.types_push_back ("hexBinary", buffer, buffer); + + xsd.types_push_back ("gDay", xns + L"::gday"); + xsd.types_push_back ("gMonth", xns + L"::gmonth"); + xsd.types_push_back ("gYear", xns + L"::gyear"); + xsd.types_push_back ("gMonthDay", xns + L"::gmonth_day"); + xsd.types_push_back ("gYearMonth", xns + L"::gyear_month"); + xsd.types_push_back ("date", xns + L"::date"); + xsd.types_push_back ("time", xns + L"::time"); + xsd.types_push_back ("dateTime", xns + L"::date_time"); + xsd.types_push_back ("duration", xns + L"::duration"); + + // Fundamental C++ types. + // + xsd.types_push_back ("boolean", "bool", "bool"); + + xsd.types_push_back ("byte", "signed char", "signed char"); + xsd.types_push_back ("unsignedByte", + "unsigned char", + "unsigned char"); + + xsd.types_push_back ("short", "short", "short"); + xsd.types_push_back ("unsignedShort", + "unsigned short", + "unsigned short"); + + xsd.types_push_back ("int", "int", "int"); + xsd.types_push_back ("unsignedInt", "unsigned int", "unsigned int"); + + xsd.types_push_back ("long", "long long", "long long"); + xsd.types_push_back ("unsignedLong", + "unsigned long long", + "unsigned long long"); + + xsd.types_push_back ("integer", "long long", "long long"); + + xsd.types_push_back ("negativeInteger", "long long", "long long"); + xsd.types_push_back ("nonPositiveInteger", "long long", "long long"); + + xsd.types_push_back ("positiveInteger", + "unsigned long long", + "unsigned long long"); + xsd.types_push_back ("nonNegativeInteger", + "unsigned long long", + "unsigned long long"); + + xsd.types_push_back ("float", "float", "float"); + xsd.types_push_back ("double", "double", "double"); + xsd.types_push_back ("decimal", "double", "double"); + + type_map.push_back (xsd); + + // Everyhting else maps to void. + // + TypeMap::Namespace rest (".*"); + rest.types_push_back (".*", "void", "void"); + type_map.push_back (rest); + } + + // Process types. + // + { + TypeProcessor proc; + proc.process (ops, schema, gen_driver, type_map); + } + + // + // + Boolean inline_ (ops.value<CLI::generate_inline> () && + !generate_xml_schema); + + Boolean source (!generate_xml_schema); + + // Generate code. + // +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + NarrowString name (file_path.leaf ()); +#else + NarrowString name (file_path.filename().string()); +#endif + NarrowString skel_suffix (ops.value <CLI::skel_file_suffix> ()); + NarrowString impl_suffix (ops.value <CLI::impl_file_suffix> ()); + + NarrowString hxx_suffix (ops.value <CLI::hxx_suffix> ()); + NarrowString ixx_suffix (ops.value <CLI::ixx_suffix> ()); + NarrowString cxx_suffix (ops.value <CLI::cxx_suffix> ()); + + Regex hxx_expr ( + ops.value <CLI::hxx_regex> ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + hxx_suffix + "#" + : ops.value <CLI::hxx_regex> ()); + + Regex ixx_expr ( + ops.value <CLI::ixx_regex> ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + ixx_suffix + "#" + : ops.value <CLI::ixx_regex> ()); + + Regex cxx_expr ( + ops.value <CLI::cxx_regex> ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + cxx_suffix + "#" + : ops.value <CLI::cxx_regex> ()); + + + Regex hxx_impl_expr; + Regex cxx_impl_expr; + Regex cxx_driver_expr; + + if (impl || driver) + { + hxx_impl_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + hxx_suffix + "#"; + + cxx_impl_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + cxx_suffix + "#"; + + cxx_driver_expr = + "#^(.+?)(\\.[^./\\\\]+)?$#$1-driver" + cxx_suffix + "#"; + } + + if (!hxx_expr.match (name)) + { + wcerr << "error: header expression '" << + hxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (inline_ && !ixx_expr.match (name)) + { + wcerr << "error: inline expression '" << + ixx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (source && !cxx_expr.match (name)) + { + wcerr << "error: source expression '" << + cxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (impl || driver) + { + if (!hxx_impl_expr.match (name)) + { + wcerr << "error: implementation header expression '" << + hxx_impl_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_impl_expr.match (name)) + { + wcerr << "error: implementation source expression '" << + cxx_impl_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_driver_expr.match (name)) + { + wcerr << "error: driver source expression '" << + cxx_driver_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + } + + NarrowString hxx_name (hxx_expr.merge (name)); + NarrowString ixx_name (inline_ ? ixx_expr.merge (name) : NarrowString ()); + NarrowString cxx_name (source ? cxx_expr.merge (name) : NarrowString ()); + + NarrowString hxx_impl_name; + NarrowString cxx_impl_name; + NarrowString cxx_driver_name; + + if (impl || driver) + { + hxx_impl_name = hxx_impl_expr.merge (name); + cxx_impl_name = cxx_impl_expr.merge (name); + cxx_driver_name = cxx_driver_expr.merge (name); + } + +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + Path hxx_path (hxx_name, boost::filesystem::native); + Path ixx_path (ixx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); +#else + Path hxx_path (hxx_name.c_str()); + Path ixx_path (ixx_name.c_str()); + Path cxx_path (cxx_name.c_str()); +#endif + + Path hxx_impl_path; + Path cxx_impl_path; + Path cxx_driver_path; + + if (impl || driver) + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + hxx_impl_path = Path (hxx_impl_name, boost::filesystem::native); + cxx_impl_path = Path (cxx_impl_name, boost::filesystem::native); + cxx_driver_path = Path (cxx_driver_name, boost::filesystem::native); +#else + hxx_impl_path = Path (hxx_impl_name.c_str()); + cxx_impl_path = Path (cxx_impl_name.c_str()); + cxx_driver_path = Path (cxx_driver_name.c_str()); +#endif + } + + Path out_dir; + + if (NarrowString dir = ops.value<CLI::output_dir> ()) + { + try + { +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + out_dir = Path (dir, boost::filesystem::native); +#else + out_dir = Path (dir.c_str()); +#endif + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + if (fpt && !generate_xml_schema) + { + // In the file-per-type mode the schema files are always local + // unless the user added the directory so that we propagate this + // to the output files. + // + Path fpt_dir (file_path.branch_path ()); + + if (!fpt_dir.empty ()) + out_dir /= fpt_dir; + } + + if (!out_dir.empty ()) + { + hxx_path = out_dir / hxx_path; + ixx_path = out_dir / ixx_path; + cxx_path = out_dir / cxx_path; + + if (impl || driver) + { + hxx_impl_path = out_dir / hxx_impl_path; + cxx_impl_path = out_dir / cxx_impl_path; + cxx_driver_path = out_dir /cxx_driver_path; + } + } + + // Open the impl files first so that if open fails, the skel files + // are not deleted. + // + WideOutputFileStream hxx_impl; + WideOutputFileStream cxx_impl; + WideOutputFileStream cxx_driver; + + if (impl) + { + if (!ops.value<CLI::force_overwrite> ()) + { + WideInputFileStream tmp (hxx_impl_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << hxx_impl_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + hxx_impl.open (hxx_impl_path, ios_base::out); + + if (!hxx_impl.is_open ()) + { + wcerr << hxx_impl_path << ": error: unable to open in write mode" + << endl; + throw Failed (); + } + + unlinks.add (hxx_impl_path); +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_list.push_back (hxx_impl_path.native_file_string ()); +#else + file_list.push_back (hxx_impl_path.string ()); +#endif + + if (!ops.value<CLI::force_overwrite> ()) + { + WideInputFileStream tmp (cxx_impl_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << cxx_impl_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + cxx_impl.open (cxx_impl_path, ios_base::out); + + if (!cxx_impl.is_open ()) + { + wcerr << cxx_impl_path << ": error: unable to open in write mode" + << endl; + throw Failed (); + } + + unlinks.add (cxx_impl_path); +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_list.push_back (cxx_impl_path.native_file_string ()); +#else + file_list.push_back (cxx_impl_path.string ()); +#endif + } + + if (driver) + { + if (!ops.value<CLI::force_overwrite> ()) + { + WideInputFileStream tmp (cxx_driver_path, ios_base::in); + + if (tmp.is_open ()) + { + wcerr << cxx_driver_path << ": error: cowardly refusing to " << + "overwrite an existing file" << endl; + throw Failed (); + } + + tmp.close (); + } + + cxx_driver.open (cxx_driver_path, ios_base::out); + + if (!cxx_driver.is_open ()) + { + wcerr << cxx_driver_path << ": error: unable to open in write " << + "mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_driver_path); +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_list.push_back (cxx_driver_path.native_file_string ()); +#else + file_list.push_back (cxx_driver_path.string ()); +#endif + } + + // Open the skel files. + // + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream ixx; + WideOutputFileStream cxx; + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_list.push_back (hxx_path.native_file_string ()); +#else + file_list.push_back (hxx_path.string ()); +#endif + + if (inline_) + { + ixx.open (ixx_path, ios_base::out); + + if (!ixx.is_open ()) + { + wcerr << ixx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (ixx_path); +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_list.push_back (ixx_path.native_file_string ()); +#else + file_list.push_back (ixx_path.string ()); +#endif + } + + + if (source) + { + cxx.open (cxx_path, ios_base::out); + + if (!cxx.is_open ()) + { + wcerr << cxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_path); +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + file_list.push_back (cxx_path.native_file_string ()); +#else + file_list.push_back (cxx_path.string ()); +#endif + } + + // Print copyright and license. + // + Char const* copyright ( + ops.value<CLI::proprietary_license> () + ? copyright_proprietary + : copyright_gpl); + + hxx << copyright; + + if (inline_) + ixx << copyright; + + if (source) + cxx << copyright; + + if (impl) + { + hxx_impl << copyright_impl; + cxx_impl << copyright_impl; + } + + if (driver) + cxx_driver << copyright_impl; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name (ops.value<CLI::prologue_file> ()); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name (ops.value<CLI::epilogue_file> ()); + + if (name) + open (epilogue, name); + } + + // SLOC counter. + // + UnsignedLong sloc (0); + Boolean show_sloc (ops.value<CLI::show_sloc> ()); + + // + // + Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. + + NarrowString guard_prefix (ops.value<CLI::guard_prefix> ()); + + if (!guard_prefix) +#if !defined(BOOST_FILESYSTEM_VERSION) || BOOST_FILESYSTEM_VERSION == 2 + guard_prefix = file_path.branch_path ().native_directory_string (); +#else + guard_prefix = file_path.branch_path ().string (); +#endif + + if (guard_prefix) + guard_prefix += '_'; + + // HXX + // + { + Context ctx (hxx, + schema, + file_path, + ops, + &string_literal_map, + &hxx_expr, + &ixx_expr, + &hxx_impl_expr); + + Indentation::Clip<Indentation::SLOC, WideChar> hxx_sloc (hxx); + + String guard (guard_expr.merge (guard_prefix + hxx_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + hxx << "// Begin prologue." << endl + << "//" << endl; + + append ( + hxx, ops.value<CLI::hxx_prologue> (), ops.value<CLI::prologue> ()); + append (hxx, ops.value<CLI::hxx_prologue_file> (), prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + // Version check. + // + hxx << "#include <xsd/cxx/config.hxx>" << endl + << endl + << "#if (XSD_INT_VERSION != " << XSD_INT_VERSION << "L)" << endl + << "#error XSD runtime version mismatch" << endl + << "#endif" << endl + << endl; + + { + hxx << "#include <xsd/cxx/pre.hxx>" << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> hxx_clip (hxx); + + + // Generate. + // + if (!generate_xml_schema) + generate_parser_forward (ctx); + + generate_parser_header (ctx, generate_xml_schema); + + + if (inline_) + hxx << "#include " << ctx.process_include_path (ixx_name) << endl; + + hxx << "#include <xsd/cxx/post.hxx>" << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, ops.value<CLI::hxx_epilogue_file> (), epilogue); + append ( + hxx, ops.value<CLI::hxx_epilogue> (), ops.value<CLI::epilogue> ()); + + hxx << "//" << endl + << "// End epilogue." << endl + << endl; + + hxx << "#endif // " << guard << endl; + + if (show_sloc) + { + wcerr << hxx_path << ": " + << hxx_sloc.buffer ().count () << endl; + + sloc += hxx_sloc.buffer ().count (); + } + } + + + // IXX + // + if (inline_) + { + Context ctx (ixx, + schema, + file_path, + ops, + &string_literal_map, + &hxx_expr, + &ixx_expr, + &hxx_impl_expr); + + Indentation::Clip<Indentation::SLOC, WideChar> ixx_sloc (ixx); + + + // Copy prologue. + // + ixx << "// Begin prologue." << endl + << "//" << endl; + + append ( + ixx, ops.value<CLI::ixx_prologue> (), ops.value<CLI::prologue> ()); + append (ixx, ops.value<CLI::ixx_prologue_file> (), prologue); + + ixx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> ixx_clip (ixx); + + + // Generate. + // + generate_parser_inline (ctx); + } + + // Copy epilogue. + // + ixx << "// Begin epilogue." << endl + << "//" << endl; + + append (ixx, ops.value<CLI::ixx_epilogue_file> (), epilogue); + append ( + ixx, ops.value<CLI::ixx_epilogue> (), ops.value<CLI::epilogue> ()); + + ixx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << ixx_path << ": " + << ixx_sloc.buffer ().count () << endl; + + sloc += ixx_sloc.buffer ().count (); + } + } + + + // CXX + // + if (source) + { + Context ctx (cxx, + schema, + file_path, + ops, + &string_literal_map, + &hxx_expr, + &ixx_expr, + &hxx_impl_expr); + + Indentation::Clip<Indentation::SLOC, WideChar> cxx_sloc (cxx); + + // Copy prologue. + // + cxx << "// Begin prologue." << endl + << "//" << endl; + + append ( + cxx, ops.value<CLI::cxx_prologue> (), ops.value<CLI::prologue> ()); + append (cxx, ops.value<CLI::cxx_prologue_file> (), prologue); + + cxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> cxx_clip (cxx); + + cxx << "#include " << ctx.process_include_path (hxx_name) << endl + << endl; + + if (!inline_) + generate_parser_inline (ctx); + + generate_parser_source (ctx); + + if (validation) + { + generate_element_validation_source (ctx); + generate_attribute_validation_source (ctx); + generate_characters_validation_source (ctx); + } + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, ops.value<CLI::cxx_epilogue_file> (), epilogue); + append ( + cxx, ops.value<CLI::cxx_epilogue> (), ops.value<CLI::epilogue> ()); + + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << cxx_path << ": " + << cxx_sloc.buffer ().count () << endl; + + sloc += cxx_sloc.buffer ().count (); + } + } + + // HXX impl + // + if (impl) + { + Context ctx (hxx_impl, + schema, + file_path, + ops, + &string_literal_map, + &hxx_expr, + &ixx_expr, + &hxx_impl_expr); + + String guard (guard_expr.merge (guard_prefix + hxx_impl_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + hxx_impl << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + { + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> clip (hxx_impl); + + hxx_impl << "#include " << ctx.process_include_path (hxx_name) + << endl << endl; + + generate_impl_header (ctx); + } + + hxx_impl << "#endif // " << guard << endl; + } + + // CXX impl + // + if (impl) + { + Context ctx (cxx_impl, + schema, + file_path, + ops, + &string_literal_map, + &hxx_expr, + &ixx_expr, + &hxx_impl_expr); + + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> clip (cxx_impl); + + cxx_impl << "#include " << ctx.process_include_path (hxx_impl_name) + << endl << endl; + + generate_impl_source (ctx); + } + + // CXX driver + // + if (driver) + { + Context ctx (cxx_driver, + schema, + file_path, + ops, + &string_literal_map, + &hxx_expr, + &ixx_expr, + &hxx_impl_expr); + + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> clip (cxx_driver); + + cxx_driver << "#include " << ctx.process_include_path (hxx_impl_name) + << endl << endl; + + generate_driver_source (ctx); + } + + return sloc; + } + catch (UnrepresentableCharacter const& e) + { + wcerr << "error: character at position " << e.position () << " " + << "in string '" << e.string () << "' is unrepresentable in " + << "the target encoding" << endl; + + wcerr << "info: use the --custom-literals option to provide custom " + << "string literals mapping" << endl; + + throw Failed (); + } + catch (NoNamespaceMapping const& e) + { + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": error: unable to map XML Schema namespace '" << e.ns () + << "' to C++ namespace" << endl; + + wcerr << e.file () << ":" << e.line () << ":" << e.column () + << ": info: use the --namespace-map or --namespace-regex option " + << "to provide custom mapping" << endl; + + throw Failed (); + } + catch (InvalidNamespaceMapping const& e) + { + wcerr << "error: invalid XML to C++ namespace mapping specified: " + << "'" << e.mapping () << "': " << e.reason () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format<Char> const& e) + { + wcerr << "error: invalid regex: '" << + e.expression ().c_str () << "': " << + e.description ().c_str () << endl; + + throw Failed (); + } + catch (BackendElements::Regex::Format<WideChar> const& e) + { + wcerr << "error: invalid regex: '" << + e.expression () << "': " << e.description () << endl; + + throw Failed (); + } + } +} |