diff options
Diffstat (limited to 'xsde/cxx/hybrid/generator.cxx')
-rw-r--r-- | xsde/cxx/hybrid/generator.cxx | 2476 |
1 files changed, 2476 insertions, 0 deletions
diff --git a/xsde/cxx/hybrid/generator.cxx b/xsde/cxx/hybrid/generator.cxx new file mode 100644 index 0000000..b6215f9 --- /dev/null +++ b/xsde/cxx/hybrid/generator.cxx @@ -0,0 +1,2476 @@ +// file : xsde/cxx/hybrid/generator.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2009 Code Synthesis Tools CC +// license : GNU GPL v2 + exceptions; see accompanying LICENSE file + +#include <cxx/hybrid/elements.hxx> +#include <cxx/hybrid/generator.hxx> + +#include <cxx/hybrid/validator.hxx> + +#include <cxx/hybrid/tree-size-processor.hxx> +#include <cxx/hybrid/tree-name-processor.hxx> + + +#include <cxx/hybrid/tree-forward.hxx> +#include <cxx/hybrid/tree-header.hxx> +#include <cxx/hybrid/tree-inline.hxx> +#include <cxx/hybrid/tree-source.hxx> +#include <cxx/hybrid/tree-type-map.hxx> + +#include <cxx/hybrid/parser-name-processor.hxx> +#include <cxx/hybrid/parser-header.hxx> +#include <cxx/hybrid/parser-source.hxx> +#include <cxx/hybrid/parser-aggregate-header.hxx> +#include <cxx/hybrid/parser-aggregate-source.hxx> + +#include <cxx/hybrid/serializer-name-processor.hxx> +#include <cxx/hybrid/serializer-header.hxx> +#include <cxx/hybrid/serializer-source.hxx> +#include <cxx/hybrid/serializer-aggregate-header.hxx> +#include <cxx/hybrid/serializer-aggregate-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 "../../../libxsde/xsde/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-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD/e, an XML Schema\n" + "// to C++ data binding compiler for embedded systems.\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" + "//\n\n"; + + Char const copyright_proprietary[] = + "// Copyright (C) 2005-2009 Code Synthesis Tools CC\n" + "//\n" + "// This program was generated by CodeSynthesis XSD/e, an XML Schema to\n" + "// C++ data binding compiler for embedded systems, in the Proprietary\n" + "// License mode. You should have received a proprietary license from\n" + "// Code Synthesis Tools CC prior to generating this code. See the\n" + "// license text for conditions.\n" + "//\n\n"; + } + + namespace Hybrid + { + namespace CLI + { + extern Key no_stl = "no-stl"; + extern Key no_iostream = "no-iostream"; + extern Key no_exceptions = "no-exceptions"; + extern Key no_long_long = "no-long-long"; + extern Key generate_parser = "generate-parser"; + extern Key generate_serializer = "generate-serializer"; + extern Key generate_aggregate = "generate-aggregate"; + extern Key suppress_validation = "suppress-validation"; + extern Key suppress_parser_val = "suppress-parser-val"; + extern Key suppress_serializer_val = "suppress-serializer-val"; + extern Key generate_inline = "generate-inline"; + extern Key generate_forward = "generate-forward"; + extern Key generate_xml_schema = "generate-xml-schema"; + extern Key extern_xml_schema = "extern-xml-schema"; + extern Key suppress_reset = "suppress-reset"; + extern Key reuse_style_mixin = "reuse-style-mixin"; + extern Key custom_data = "custom-data"; + extern Key custom_parser = "custom-parser"; + extern Key custom_serializer = "custom-serializer"; + extern Key root_element_first = "root-element-first"; + extern Key root_element_last = "root-element-last"; + extern Key root_element_all = "root-element-all"; + extern Key root_element_none = "root-element-none"; + extern Key root_element = "root-element"; + extern Key root_type = "root-type"; + extern Key output_dir = "output-dir"; + extern Key pskel_type_suffix = "pskel-type-suffix"; + extern Key sskel_type_suffix = "sskel-type-suffix"; + extern Key pskel_file_suffix = "pskel-file-suffix"; + extern Key sskel_file_suffix = "sskel-file-suffix"; + extern Key pimpl_type_suffix = "pimpl-type-suffix"; + extern Key simpl_type_suffix = "simpl-type-suffix"; + extern Key pimpl_file_suffix = "pimpl-file-suffix"; + extern Key simpl_file_suffix = "simpl-file-suffix"; + extern Key paggr_type_suffix = "paggr-type-suffix"; + extern Key saggr_type_suffix = "saggr-type-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 fwd_suffix = "fwd-suffix"; + extern Key hxx_regex = "hxx-regex"; + extern Key ixx_regex = "ixx-regex"; + extern Key cxx_regex = "cxx-regex"; + extern Key fwd_regex = "fwd-regex"; + extern Key hxx_prologue = "hxx-prologue"; + extern Key ixx_prologue = "ixx-prologue"; + extern Key cxx_prologue = "cxx-prologue"; + extern Key fwd_prologue = "fwd-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 fwd_epilogue = "fwd-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 fwd_prologue_file = "fwd-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 fwd_epilogue_file = "fwd-epilogue-file"; + extern Key epilogue_file = "epilogue-file"; + extern Key show_anonymous = "show-anonymous"; + extern Key show_sloc = "show-sloc"; + extern Key proprietary_license = "proprietary-license"; + } + } + + Void Hybrid::Generator:: + usage () + { + std::wostream& e (wcerr); + ::CLI::Indent::Clip< ::CLI::OptionsUsage, WideChar> clip (e); + + e << "--no-stl" << endl + << " Generate code that does not use STL." + << endl; + + e << "--no-iostream" << endl + << " Generate code that does not use the iostream\n" + << " library." + << endl; + + e << "--no-exceptions" << endl + << " Generate code that does not use C++ exceptions." + << endl; + + e << "--no-long-long" << endl + << " Generate code that does not use the long long\n" + << " and unsigned long long types." + << endl; + + e << "--generate-parser" << endl + << " Generate XML parsing code." + << endl; + + e << "--generate-serializer" << endl + << " Generate XML serialization code." + << endl; + + e << "--generate-aggregate" << endl + << " Generate parser/serializer aggregates for root\n" + << " elements and/or types." + << endl; + + e << "--suppress-validation" << endl + << " Suppress the generation of validation code in\n" + << " parser and serializer." + << endl; + + e << "--suppress-parser-val" << endl + << " Suppress the generation of validation code in\n" + << " parser." + << endl; + + e << "--suppress-serializer-val" << endl + << " Suppress the generation of validation code in\n" + << " serializer." + << endl; + + e << "--generate-inline" << endl + << " Generate certain functions inline." + << endl; + + e << "--generate-forward" << endl + << " Generate forward declaration file." + << endl; + + e << "--generate-xml-schema" << endl + << " Generate C++ header files 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 << "--suppress-reset" << endl + << " Suppress the generation of parser and serializer\n" + << " reset code." + << endl; + + e << "--reuse-style-mixin" << endl + << " Generate code that supports the mixin base\n" + << " parser/serializer implementation reuse style." + << endl; + + e << "--custom-data <type>" << endl + << " Add custom data to the C++ class generated for\n" + << " XML Schema type <type>." + << endl; + + e << "--custom-parser <map>" << endl + << " Use a custom parser implementation instead of the\n" + << " generated version. The <map> argument is in the\n" + << " form type[=base[/include]], where <type> is an XML\n" + << " Schema type name, optional <base> is a C++ name\n" + << " that should be given to the generated version,\n" + << " and optional <include> is the header file that\n" + << " defines the custom implementation." + << endl; + + e << "--custom-serializer <map>" << endl + << " Use a custom serializer implementation instead of\n" + << " the generated version. The <map> argument is in\n" + << " the form type[=base[/include]], where <type> is\n" + << " an XML Schema type name, optional <base> is a C++\n" + << " name that should be given to the generated\n" + << " version, and optional <include> is the header\n" + << " file that defines the custom implementation." + << endl; + + e << "--root-element-first" << endl + << " Treat only the first global element as a document\n" + << " root." + << endl; + + e << "--root-element-last" << endl + << " Treat only the last global element as a document\n" + << " root." + << endl; + + e << "--root-element-all" << endl + << " Treat all global elements as document roots." + << endl; + + e << "--root-element-none" << endl + << " Don't treat any global elements as document roots." + << endl; + + e << "--root-element <element>" << endl + << " Treat only <element> as a document root. Repeat\n" + << " this option to specify more than one root element." + << endl; + + e << "--root-type <type>" << endl + << " Generate parser/serializer aggregate for <type>.\n" + << " Repeat this option to specify more than one type." + << endl; + + e << "--output-dir <dir>" << endl + << " Write generated files to <dir> instead of the\n" + << " current directory." + << endl; + + e << "--pskel-type-suffix <sfx>" << endl + << " Use <sfx> instead of the default '_pskel' suffix\n" + << " to construct the names of generated parser\n" + << " skeletons." + << endl; + + e << "--sskel-type-suffix <sfx>" << endl + << " Use <sfx> instead of the default '_sskel' suffix\n" + << " to construct the names of generated serializer\n" + << " skeletons." + << endl; + + e << "--pskel-file-suffix <sfx>" << endl + << " Use <sfx> instead of the default '-pskel' suffix\n" + << " to construct the names of generated parser\n" + << " skeleton files." + << endl; + + e << "--sskel-file-suffix <sfx>" << endl + << " Use <sfx> instead of the default '-sskel' suffix\n" + << " to construct the names of generated serializer\n" + << " skeleton files." + << endl; + + e << "--pimpl-type-suffix <sfx>" << endl + << " Use <sfx> instead of the default '_pimpl' suffix\n" + << " to construct the names of generated parser\n" + << " implementations." + << endl; + + e << "--simpl-type-suffix <sfx>" << endl + << " Use <sfx> instead of the default '_simpl' suffix\n" + << " to construct the names of generated serializer\n" + << " implementations." + << endl; + + e << "--pimpl-file-suffix <sfx>" << endl + << " Use <sfx> instead of the default '-pimpl' suffix\n" + << " to construct the names of generated parser\n" + << " implementation files." + << endl; + + e << "--simpl-file-suffix <sfx>" << endl + << " Use <sfx> instead of the default '-simpl' suffix\n" + << " to construct the names of generated serializer\n" + << " implementation files." + << endl; + + e << "--paggr-type-suffix <sfx>" << endl + << " Use <sfx> instead of the default '_paggs' suffix\n" + << " to construct the names of generated parser\n" + << " aggregates." + << endl; + + e << "--saggr-type-suffix <sfx>" << endl + << " Use <sfx> instead of the default '_saggr' suffix\n" + << " to construct the names of generated serializer\n" + << " aggregates." + << 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; + + // File suffix. + // + e << "--hxx-suffix <suffix>" << endl + << " Use <suffix> instead of the default '.hxx' to\n" + << " construct the name of the header files." + << endl; + + e << "--ixx-suffix <suffix>" << endl + << " Use <suffix> instead of the default '.ixx' to\n" + << " construct the name of the inline files." + << endl; + + e << "--cxx-suffix <suffix>" << endl + << " Use <suffix> instead of the default '.cxx' to\n" + << " construct the name of the source files." + << endl; + + e << "--fwd-suffix <suffix>" << endl + << " Use <suffix> instead of the default '-fwd.hxx'\n" + << " to construct the name of the forward declaration\n" + << " file." + << endl; + + // File regex. + // + e << "--hxx-regex <regex>" << endl + << " Use <regex> to construct the names of the header\n" + << " files." + << endl; + + e << "--ixx-regex <regex>" << endl + << " Use <regex> to construct the names of the inline\n" + << " files." + << endl; + + e << "--cxx-regex <regex>" << endl + << " Use <regex> to construct the names of the source\n" + << " files." + << endl; + + e << "--fwd-regex <regex>" << endl + << " Use <regex> to construct the name of the forward\n" + << " declaration file." + << endl; + + + // Prologues. + // + e << "--hxx-prologue <text>" << endl + << " Insert <text> at the beginning of the header\n" + << " files." + << endl; + + e << "--ixx-prologue <text>" << endl + << " Insert <text> at the beginning of the inline\n" + << " files." + << endl; + + e << "--cxx-prologue <text>" << endl + << " Insert <text> at the beginning of the source\n" + << " files." + << endl; + + e << "--fwd-prologue <text>" << endl + << " Insert <text> at the beginning of the forward\n" + << " declaration 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 files." + << endl; + + e << "--ixx-epilogue <text>" << endl + << " Insert <text> at the end of the inline files." + << endl; + + e << "--cxx-epilogue <text>" << endl + << " Insert <text> at the end of the source files." + << endl; + + e << "--fwd-epilogue <text>" << endl + << " Insert <text> at the end of the forward\n" + << " declaration 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 files." + << endl; + + e << "--ixx-prologue-file <file>" << endl + << " Insert the content of the <file> at the beginning\n" + << " of the inline files." + << endl; + + e << "--cxx-prologue-file <file>" << endl + << " Insert the content of the <file> at the beginning\n" + << " of the source files." + << endl; + + e << "--fwd-prologue-file <file>" << endl + << " Insert the content of the <file> at the beginning\n" + << " of the forward declaration 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 files." + << endl; + + e << "--ixx-epilogue-file <file>" << endl + << " Insert the content of the <file> at the end of\n" + << " the inline files." + << endl; + + e << "--cxx-epilogue-file <file>" << endl + << " Insert the content of the <file> at the end of\n" + << " the source files." + << endl; + + e << "--fwd-epilogue-file <file>" << endl + << " Insert the content of the <file> at the end of\n" + << " the forward declaration 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 << "--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; + } + + Hybrid::CLI::OptionsSpec Hybrid::Generator:: + options_spec () + { + CLI::OptionsSpec spec; + + spec.option<CLI::pskel_file_suffix> ().default_value ("-pskel"); + spec.option<CLI::sskel_file_suffix> ().default_value ("-sskel"); + spec.option<CLI::pskel_type_suffix> ().default_value ("_pskel"); + spec.option<CLI::sskel_type_suffix> ().default_value ("_sskel"); + + spec.option<CLI::pimpl_file_suffix> ().default_value ("-pimpl"); + spec.option<CLI::simpl_file_suffix> ().default_value ("-simpl"); + spec.option<CLI::pimpl_type_suffix> ().default_value ("_pimpl"); + spec.option<CLI::simpl_type_suffix> ().default_value ("_simpl"); + + spec.option<CLI::paggr_type_suffix> ().default_value ("_paggr"); + spec.option<CLI::saggr_type_suffix> ().default_value ("_saggr"); + + spec.option<CLI::hxx_suffix> ().default_value (".hxx"); + spec.option<CLI::ixx_suffix> ().default_value (".ixx"); + spec.option<CLI::cxx_suffix> ().default_value (".cxx"); + spec.option<CLI::fwd_suffix> ().default_value ("-fwd.hxx"); + + return spec; + } + + namespace + { + NarrowString + find_value (Cult::Containers::Vector<NarrowString> const& v, + Char const* key) + { + typedef Cult::Containers::Vector<NarrowString> Values; + + for (Values::ConstIterator i (v.begin ()), e (v.end ()); i != e; ++i) + { + Size p (i->find ('=')); + + if (p == NarrowString::npos) + { + if (key[0] != '\0') + continue; + } + else + { + NarrowString k (*i, 0, p); + + // Unless it is one of the valid keys, assume there is no key. + // + if (!(k.empty () || k == "*" || k == "pskel" || + k == "pimpl" || k == "sskel" || k == "simpl")) + { + k.clear (); + p = NarrowString::npos; + } + + if (k != key && k != "*") + continue; + } + + return NarrowString ( + *i, p == NarrowString::npos ? 0 : p + 1, NarrowString::npos); + } + + return NarrowString (); + } + + Void + copy_values (Cult::Containers::Vector<NarrowString>& dst, + Cult::Containers::Vector<NarrowString> const& src, + Char const* key) + { + typedef Cult::Containers::Vector<NarrowString> Values; + + for (Values::ConstIterator i (src.begin ()), e (src.end ()); i != e; ++i) + { + Size p (i->find ('=')); + + if (p == NarrowString::npos) + { + if (key[0] != '\0') + continue; + } + else + { + NarrowString k (*i, 0, p); + + // Unless it is one of the valid keys, assume there is no key. + // + if (!(k.empty () || k == "*" || k == "pskel" || + k == "pimpl" || k == "sskel" || k == "simpl")) + { + k.clear (); + p = NarrowString::npos; + } + + if (k != key && k != "*") + continue; + } + + dst.push_back ( + NarrowString ( + *i, p == NarrowString::npos ? 0 : p + 1, NarrowString::npos)); + } + } + } + + Parser::CLI::Options* Hybrid::Generator:: + parser_options (CLI::Options const& h) + { + namespace H = CLI; + namespace P = Parser::CLI; + + Evptr<P::Options> r (new P::Options); + + r->value<P::no_stl> () = h.value<H::no_stl> (); + r->value<P::no_iostream> () = h.value<H::no_iostream> (); + r->value<P::no_exceptions> () = h.value<H::no_exceptions> (); + r->value<P::no_long_long> () = h.value<H::no_long_long> (); + r->value<P::reuse_style_mixin> () = h.value<H::reuse_style_mixin> (); + r->value<P::reuse_style_none> () = false; + r->value<P::generate_inline> () = h.value<H::generate_inline> (); + r->value<P::suppress_validation> () = h.value<H::suppress_validation> () + || h.value<H::suppress_parser_val> (); + r->value<P::generate_xml_schema> () = h.value<H::generate_xml_schema> (); + r->value<P::extern_xml_schema> () = h.value<H::extern_xml_schema> (); + r->value<P::suppress_reset> () = h.value<H::suppress_reset> (); + r->value<P::output_dir> () = h.value<H::output_dir> (); + r->value<P::skel_file_suffix> () = h.value<H::pskel_file_suffix> (); + r->value<P::skel_type_suffix> () = h.value<H::pskel_type_suffix> (); + r->value<P::impl_type_suffix> () = h.value<H::pimpl_type_suffix> (); + r->value<P::namespace_map> () = h.value<H::namespace_map> (); + r->value<P::namespace_regex> () = h.value<H::namespace_regex> (); + r->value<P::namespace_regex_trace> () = h.value<H::namespace_regex_trace> (); + r->value<P::reserved_name> () = h.value<H::reserved_name> (); + r->value<P::include_with_brackets> () = h.value<H::include_with_brackets> (); + r->value<P::include_prefix> () = h.value<H::include_prefix> (); + r->value<P::include_regex> () = h.value<H::include_regex> (); + r->value<P::include_regex_trace> () = h.value<H::include_regex_trace> (); + r->value<P::guard_prefix> () = h.value<H::guard_prefix> (); + + r->value<P::hxx_suffix> () = h.value<H::hxx_suffix> (); + r->value<P::ixx_suffix> () = h.value<H::ixx_suffix> (); + r->value<P::cxx_suffix> () = h.value<H::cxx_suffix> (); + + Char const* k = "pskel"; + + r->value<P::hxx_regex> () = + find_value (h.value<H::hxx_regex> (), k); + r->value<P::ixx_regex> () = + find_value (h.value<H::ixx_regex> (), k); + r->value<P::cxx_regex> () = + find_value (h.value<H::cxx_regex> (), k); + + r->value<P::hxx_prologue_file> () = find_value ( + h.value<H::hxx_prologue_file> (), k); + r->value<P::ixx_prologue_file> () = find_value ( + h.value<H::ixx_prologue_file> (), k); + r->value<P::cxx_prologue_file> () = find_value ( + h.value<H::cxx_prologue_file> (), k); + r->value<P::prologue_file> () = find_value ( + h.value<H::prologue_file> (), k); + r->value<P::hxx_epilogue_file> () = find_value ( + h.value<H::hxx_epilogue_file> (), k); + r->value<P::ixx_epilogue_file> () = find_value ( + h.value<H::ixx_epilogue_file> (), k); + r->value<P::cxx_epilogue_file> () = find_value ( + h.value<H::cxx_epilogue_file> (), k); + r->value<P::epilogue_file> () = find_value ( + h.value<H::epilogue_file> (), k); + + copy_values (r->value<P::hxx_prologue> (), h.value<H::hxx_prologue> (), k); + copy_values (r->value<P::ixx_prologue> (), h.value<H::ixx_prologue> (), k); + copy_values (r->value<P::cxx_prologue> (), h.value<H::cxx_prologue> (), k); + copy_values (r->value<P::prologue> (), h.value<H::prologue> (), k); + copy_values (r->value<P::hxx_epilogue> (), h.value<H::hxx_epilogue> (), k); + copy_values (r->value<P::ixx_epilogue> (), h.value<H::ixx_epilogue> (), k); + copy_values (r->value<P::cxx_epilogue> (), h.value<H::cxx_epilogue> (), k); + copy_values (r->value<P::epilogue> (), h.value<H::epilogue> (), k); + + r->value<P::show_sloc> () = h.value<H::show_sloc> (); + r->value<P::proprietary_license> () = h.value<H::proprietary_license> (); + + return r.release (); + } + + Serializer::CLI::Options* Hybrid::Generator:: + serializer_options (CLI::Options const& h) + { + namespace H = CLI; + namespace S = Serializer::CLI; + + Evptr<S::Options> r (new S::Options); + + r->value<S::no_stl> () = h.value<H::no_stl> (); + r->value<S::no_iostream> () = h.value<H::no_iostream> (); + r->value<S::no_exceptions> () = h.value<H::no_exceptions> (); + r->value<S::no_long_long> () = h.value<H::no_long_long> (); + r->value<S::reuse_style_mixin> () = h.value<H::reuse_style_mixin> (); + r->value<S::reuse_style_none> () = false; + r->value<S::generate_inline> () = h.value<H::generate_inline> (); + r->value<S::suppress_validation> () = h.value<H::suppress_validation> () + || h.value<H::suppress_serializer_val> (); + r->value<S::generate_xml_schema> () = h.value<H::generate_xml_schema> (); + r->value<S::extern_xml_schema> () = h.value<H::extern_xml_schema> (); + r->value<S::suppress_reset> () = h.value<H::suppress_reset> (); + r->value<S::output_dir> () = h.value<H::output_dir> (); + r->value<S::skel_file_suffix> () = h.value<H::sskel_file_suffix> (); + r->value<S::skel_type_suffix> () = h.value<H::sskel_type_suffix> (); + r->value<S::impl_type_suffix> () = h.value<H::simpl_type_suffix> (); + r->value<S::namespace_map> () = h.value<H::namespace_map> (); + r->value<S::namespace_regex> () = h.value<H::namespace_regex> (); + r->value<S::namespace_regex_trace> () = h.value<H::namespace_regex_trace> (); + r->value<S::reserved_name> () = h.value<H::reserved_name> (); + r->value<S::include_with_brackets> () = h.value<H::include_with_brackets> (); + r->value<S::include_prefix> () = h.value<H::include_prefix> (); + r->value<S::include_regex> () = h.value<H::include_regex> (); + r->value<S::include_regex_trace> () = h.value<H::include_regex_trace> (); + r->value<S::guard_prefix> () = h.value<H::guard_prefix> (); + + r->value<S::hxx_suffix> () = h.value<H::hxx_suffix> (); + r->value<S::ixx_suffix> () = h.value<H::ixx_suffix> (); + r->value<S::cxx_suffix> () = h.value<H::cxx_suffix> (); + + Char const* k = "sskel"; + + r->value<S::hxx_regex> () = + find_value (h.value<H::hxx_regex> (), k); + r->value<S::ixx_regex> () = + find_value (h.value<H::ixx_regex> (), k); + r->value<S::cxx_regex> () = + find_value (h.value<H::cxx_regex> (), k); + + r->value<S::hxx_prologue_file> () = find_value ( + h.value<H::hxx_prologue_file> (), k); + r->value<S::ixx_prologue_file> () = find_value ( + h.value<H::ixx_prologue_file> (), k); + r->value<S::cxx_prologue_file> () = find_value ( + h.value<H::cxx_prologue_file> (), k); + r->value<S::prologue_file> () = find_value ( + h.value<H::prologue_file> (), k); + r->value<S::hxx_epilogue_file> () = find_value ( + h.value<H::hxx_epilogue_file> (), k); + r->value<S::ixx_epilogue_file> () = find_value ( + h.value<H::ixx_epilogue_file> (), k); + r->value<S::cxx_epilogue_file> () = find_value ( + h.value<H::cxx_epilogue_file> (), k); + r->value<S::epilogue_file> () = find_value ( + h.value<H::epilogue_file> (), k); + + copy_values (r->value<S::hxx_prologue> (), h.value<H::hxx_prologue> (), k); + copy_values (r->value<S::ixx_prologue> (), h.value<H::ixx_prologue> (), k); + copy_values (r->value<S::cxx_prologue> (), h.value<H::cxx_prologue> (), k); + copy_values (r->value<S::prologue> (), h.value<H::prologue> (), k); + copy_values (r->value<S::hxx_epilogue> (), h.value<H::hxx_epilogue> (), k); + copy_values (r->value<S::ixx_epilogue> (), h.value<H::ixx_epilogue> (), k); + copy_values (r->value<S::cxx_epilogue> (), h.value<H::cxx_epilogue> (), k); + copy_values (r->value<S::epilogue> (), h.value<H::epilogue> (), k); + + r->value<S::show_sloc> () = h.value<H::show_sloc> (); + r->value<S::proprietary_license> () = h.value<H::proprietary_license> (); + + return r.release (); + } + + Void Hybrid::Generator:: + calculate_size (CLI::Options const& ops, + XSDFrontend::SemanticGraph::Schema& schema, + XSDFrontend::SemanticGraph::Path const& file) + { + // Determine which types are fixed/variable-sized. + // + TreeSizeProcessor proc; + proc.process (ops, schema, file); + } + + namespace + { + template <typename S> + Void + open (S& ifs, NarrowString const& path) + { + try + { + Path fs_path (path, boost::filesystem::native); + 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 Hybrid::Generator::Failed (); + } + } + catch (InvalidPath const&) + { + wcerr << "error: '" << path.c_str () << "' is not a valid " + << "filesystem path" << endl; + + throw Hybrid::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, + Char const* primary_key, + Char const* def_key) + { + typedef Cult::Containers::Vector<NarrowString> Values; + + for (Values const* v = &primary; v != 0; v = (v == &def ? 0 : &def)) + { + Boolean found (false); + Char const* key (v == &primary ? primary_key : def_key); + + for (Values::ConstIterator i (v->begin ()), e (v->end ()); i != e; ++i) + { + if (key == 0) + os << i->c_str () << endl; + else + { + Size p (i->find ('=')); + + if (p == NarrowString::npos) + { + if (key[0] != '\0') + continue; + } + else + { + NarrowString k (*i, 0, p); + + // Unless it is one of the valid keys, assume there is no key. + // + if (!(k.empty () || k == "*" || k == "pskel" || + k == "pimpl" || k == "sskel" || k == "simpl")) + { + k.clear (); + p = NarrowString::npos; + } + + if (k != key && k != "*") + continue; + } + + NarrowString s ( + *i, p == NarrowString::npos ? 0 : p + 1, NarrowString::npos); + os << s.c_str () << endl; + } + + found = true; + } + + if (found) + break; + } + } + + Void + append (WideOutputFileStream& os, + Cult::Containers::Vector<NarrowString> const& primary, + Cult::Containers::Vector<NarrowString> const& def, + Char const* key) + { + append (os, primary, def, key, key); + } + } + + + UnsignedLong Hybrid::Generator:: + generate_tree (Hybrid::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + const WarningSet& disabled_warnings, + TypeMap::Namespaces& parser_type_map, + TypeMap::Namespaces& serializer_type_map, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef Context::Regex 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 (file_path.native_file_string () != name) + generate_xml_schema = false; + } + } + + // Evaluate the graph for possibility of generating something useful. + // + { + Validator validator; + if (!validator.validate (ops, schema, file_path, disabled_warnings)) + throw Failed (); + } + + // Process names. + // + { + TreeNameProcessor proc; + proc.process (ops, schema, file_path); + } + + // Generate code. + // + Boolean inline_ (ops.value<CLI::generate_inline> () && + !generate_xml_schema); + + Boolean forward (ops.value<CLI::generate_forward> () && + !generate_xml_schema); + + Boolean source (!generate_xml_schema); + + NarrowString name (file_path.leaf ()); + + NarrowString hxx_suffix (ops.value <CLI::hxx_suffix> ()); + NarrowString ixx_suffix (ops.value <CLI::ixx_suffix> ()); + NarrowString cxx_suffix (ops.value <CLI::cxx_suffix> ()); + NarrowString fwd_suffix (ops.value <CLI::fwd_suffix> ()); + + NarrowString hxx_regex (find_value (ops.value <CLI::hxx_regex> (), "")); + NarrowString ixx_regex (find_value (ops.value <CLI::ixx_regex> (), "")); + NarrowString cxx_regex (find_value (ops.value <CLI::cxx_regex> (), "")); + + Regex hxx_expr ( + hxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + hxx_suffix + "#" + : hxx_regex); + + Regex ixx_expr ( + ixx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + ixx_suffix + "#" + : ixx_regex); + + Regex cxx_expr ( + cxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + cxx_suffix + "#" + : cxx_regex); + + Regex fwd_expr ( + ops.value <CLI::fwd_regex> ().empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + fwd_suffix + "#" + : ops.value <CLI::fwd_regex> ()); + + 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 (forward && !fwd_expr.match (name)) + { + wcerr << "error: forward expression '" << + fwd_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 fwd_name (forward ? fwd_expr.merge (name) : NarrowString ()); + + Path hxx_path (hxx_name, boost::filesystem::native); + Path ixx_path (ixx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); + Path fwd_path (fwd_name, boost::filesystem::native); + + if (NarrowString dir = ops.value<CLI::output_dir> ()) + { + try + { + Path path (dir, boost::filesystem::native); + + hxx_path = path / hxx_path; + ixx_path = path / ixx_path; + cxx_path = path / cxx_path; + fwd_path = path / fwd_path; + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + // Open the tree files. + // + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream ixx; + WideOutputFileStream cxx; + WideOutputFileStream fwd; + + // FWD + // + if (forward) + { + fwd.open (fwd_path, ios_base::out); + + if (!fwd.is_open ()) + { + wcerr << fwd_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (fwd_path); + file_list.push_back (fwd_path.native_file_string ()); + } + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); + file_list.push_back (hxx_path.native_file_string ()); + + 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); + file_list.push_back (ixx_path.native_file_string ()); + } + + 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); + file_list.push_back (cxx_path.native_file_string ()); + } + + // Print copyright and license. + // + Char const* copyright ( + ops.value<CLI::proprietary_license> () + ? copyright_proprietary + : copyright_gpl); + + if (forward) + fwd << copyright; + + hxx << copyright; + + if (inline_) + ixx << copyright; + + if (source) + cxx << copyright; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name ( + find_value (ops.value<CLI::prologue_file> (), "")); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name ( + find_value (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) + guard_prefix = file_path.branch_path ().native_directory_string (); + + if (guard_prefix) + guard_prefix += '_'; + + + // FWD + // + if (forward) + { + Context ctx (fwd, schema, ops, &fwd_expr, &hxx_expr, &ixx_expr); + + Indentation::Clip<Indentation::SLOC, WideChar> fwd_sloc (fwd); + + String guard (guard_expr.merge (guard_prefix + fwd_name)); + guard = ctx.escape (guard); // Make it a C++ id. + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + fwd << "#ifndef " << guard << endl + << "#define " << guard << endl + << endl; + + // Copy prologue. + // + fwd << "// Begin prologue." << endl + << "//" << endl; + + append (fwd, + ops.value<CLI::fwd_prologue> (), + ops.value<CLI::prologue> (), + 0, + ""); + append (fwd, ops.value<CLI::fwd_prologue_file> (), prologue); + + fwd << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Version check. + // + fwd << "#include <xsde/cxx/version.hxx>" << endl + << endl + << "#if (XSDE_INT_VERSION != " << XSDE_INT_VERSION << "L)" << endl + << "#error XSD/e runtime version mismatch" << endl + << "#endif" << endl + << endl; + + fwd << "#include <xsde/cxx/pre.hxx>" << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> fwd_clip (fwd); + + // Generate. + // + generate_tree_forward (ctx, false); + + fwd << "#include <xsde/cxx/post.hxx>" << endl + << endl; + } + + // Copy epilogue. + // + fwd << "// Begin epilogue." << endl + << "//" << endl; + + append (fwd, ops.value<CLI::fwd_epilogue_file> (), epilogue); + append (fwd, + ops.value<CLI::fwd_epilogue> (), + ops.value<CLI::epilogue> (), + 0, + ""); + + fwd << "//" << endl + << "// End epilogue." << endl + << endl; + + fwd << "#endif // " << guard << endl; + + if (show_sloc) + { + wcerr << fwd_path << ": " + << fwd_sloc.buffer ().count () << endl; + + sloc += fwd_sloc.buffer ().count (); + } + } + + + // HXX + // + { + Context ctx (hxx, schema, ops, &fwd_expr, &hxx_expr, &ixx_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, + find_value (ops.value<CLI::hxx_prologue_file> (), ""), + prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + // Version check. + // + hxx << "#include <xsde/cxx/version.hxx>" << endl + << endl + << "#if (XSDE_INT_VERSION != " << XSDE_INT_VERSION << "L)" << endl + << "#error XSD/e runtime version mismatch" << endl + << "#endif" << endl + << endl; + + // Runtime/generated code compatibility checks. + // + + hxx << "#include <xsde/cxx/config.hxx>" << endl + << endl; + + if (ops.value<CLI::no_stl> ()) + { + hxx << "#ifdef XSDE_STL" << endl + << "#error the XSD/e runtime uses STL while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-stl)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_STL" << endl + << "#error the generated code uses STL while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-stl)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value<CLI::no_exceptions> ()) + { + hxx << "#ifdef XSDE_EXCEPTIONS" << endl + << "#error the XSD/e runtime uses exceptions while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-exceptions)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_EXCEPTIONS" << endl + << "#error the generated code uses exceptions while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-exceptions)" << endl + << "#endif" << endl + << endl; + } + + if (ops.value<CLI::no_long_long> ()) + { + hxx << "#ifdef XSDE_LONGLONG" << endl + << "#error the XSD/e runtime uses long long while the " << + "generated code does not (reconfigure the runtime or " << + "remove --no-long-long)" << endl + << "#endif" << endl + << endl; + } + else + { + hxx << "#ifndef XSDE_LONGLONG" << endl + << "#error the generated code uses long long while the " << + "XSD/e runtime does not (reconfigure the runtime or " << + "add --no-long-long)" << endl + << "#endif" << endl + << endl; + } + + // + // + + hxx << "#include <xsde/cxx/pre.hxx>" << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> hxx_clip (hxx); + + // Generate. + // + if (!generate_xml_schema) + { + if (forward) + hxx << "#include " << ctx.process_include_path (fwd_name) + << endl << endl; + else + generate_tree_forward (ctx, false); + + generate_tree_header (ctx); + } + else + generate_tree_forward (ctx, true); + + if (inline_) + { + hxx << "#ifndef XSDE_DONT_INCLUDE_INLINE" << endl + << "#include " << ctx.process_include_path (ixx_name) << endl + << "#endif // XSDE_DONT_INCLUDE_INLINE" << endl + << endl; + } + + hxx << "#include <xsde/cxx/post.hxx>" << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, + find_value (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, ops, &fwd_expr, &hxx_expr, &ixx_expr); + + Indentation::Clip<Indentation::SLOC, WideChar> ixx_sloc (ixx); + // Guard + // + String guard (guard_expr.merge (guard_prefix + ixx_name)); + guard = ctx.escape (guard); // make a c++ id + std::transform (guard.begin (), guard.end(), guard.begin (), upcase); + + ixx << "#ifndef " << guard.c_str () << endl + << "#define " << guard.c_str () << endl + << endl; + + // Copy prologue. + // + ixx << "// Begin prologue." << endl + << "//" << endl; + + append (ixx, + ops.value<CLI::ixx_prologue> (), + ops.value<CLI::prologue> (), + ""); + append (ixx, + find_value (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_tree_inline (ctx); + } + + // Copy epilogue. + // + ixx << "// Begin epilogue." << endl + << "//" << endl; + + append (ixx, + find_value (ops.value<CLI::ixx_epilogue_file> (), ""), + epilogue); + append (ixx, + ops.value<CLI::ixx_epilogue> (), + ops.value<CLI::epilogue> (), + ""); + + ixx << "//" << endl + << "// End epilogue." << endl + << endl; + + ixx << "#endif // " << guard.c_str () << endl; + + if (show_sloc) + { + wcerr << ixx_path << ": " + << ixx_sloc.buffer ().count () << endl; + + sloc += ixx_sloc.buffer ().count (); + } + } + + + // CXX + // + if (source) + { + Context ctx (cxx, schema, ops, &fwd_expr, &hxx_expr, &ixx_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, + find_value (ops.value<CLI::cxx_prologue_file> (), ""), + prologue); + + cxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + cxx << "#include <xsde/cxx/pre.hxx>" << 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_tree_inline (ctx); + + generate_tree_source (ctx); + + cxx << "#include <xsde/cxx/post.hxx>" << endl + << endl; + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, + find_value (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 (); + } + } + + // Populate the type maps if we are generating parsing or + // serialization code. + // + if (ops.value<CLI::generate_parser> () || + ops.value<CLI::generate_serializer> ()) + { + generate_tree_type_map ( + ops, schema, hxx_name, parser_type_map, serializer_type_map); + } + + return sloc; + } + 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 (); + } + } + + UnsignedLong Hybrid::Generator:: + generate_parser (Hybrid::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + const WarningSet&, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef BackendElements::Regex::Expression<Char> Regex; + + try + { + { + Boolean gen_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 (gen_xml_schema) + { + if (NarrowString name = ops.value<CLI::extern_xml_schema> ()) + { + if (file_path.native_file_string () != name) + gen_xml_schema = false; + } + } + + if (gen_xml_schema) + return 0; + } + + // Process names. + // + { + ParserNameProcessor proc; + proc.process (ops, schema, file_path); + } + + NarrowString name (file_path.leaf ()); + NarrowString skel_suffix (ops.value <CLI::pskel_file_suffix> ()); + NarrowString impl_suffix (ops.value <CLI::pimpl_file_suffix> ()); + + NarrowString hxx_suffix (ops.value <CLI::hxx_suffix> ()); + NarrowString cxx_suffix (ops.value <CLI::cxx_suffix> ()); + + NarrowString hxx_obj_regex ( + find_value (ops.value <CLI::hxx_regex> (), "")); + + NarrowString hxx_skel_regex ( + find_value (ops.value <CLI::hxx_regex> (), "pskel")); + + NarrowString hxx_regex ( + find_value (ops.value <CLI::hxx_regex> (), "pimpl")); + NarrowString cxx_regex ( + find_value (ops.value <CLI::cxx_regex> (), "pimpl")); + + // Here we need to make sure that hxx_obj_expr is the same + // as in generate(). + // + Regex hxx_obj_expr ( + hxx_obj_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + hxx_suffix + "#" + : hxx_obj_regex); + + // Here we need to make sure that hxx_skel_expr is the same + // as in the C++/Parser generator. + // + Regex hxx_skel_expr ( + hxx_skel_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + hxx_suffix + "#" + : hxx_skel_regex); + + Regex hxx_expr ( + hxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + hxx_suffix + "#" + : hxx_regex); + + Regex cxx_expr ( + cxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + cxx_suffix + "#" + : cxx_regex); + + if (!hxx_expr.match (name)) + { + wcerr << "error: parser implementation header expression '" << + hxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_expr.match (name)) + { + wcerr << "error: parser implementation source expression '" << + cxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + NarrowString hxx_skel_name (hxx_skel_expr.merge (name)); + NarrowString hxx_name (hxx_expr.merge (name)); + NarrowString cxx_name (cxx_expr.merge (name)); + + Path hxx_path (hxx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); + + if (NarrowString dir = ops.value<CLI::output_dir> ()) + { + try + { + Path path (dir, boost::filesystem::native); + + hxx_path = path / hxx_path; + cxx_path = path / cxx_path; + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream cxx (cxx_path, ios_base::out); + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); + file_list.push_back (hxx_path.native_file_string ()); + + if (!cxx.is_open ()) + { + wcerr << cxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_path); + file_list.push_back (cxx_path.native_file_string ()); + + // Print copyright and license. + // + Char const* copyright ( + ops.value<CLI::proprietary_license> () + ? copyright_proprietary + : copyright_gpl); + + hxx << copyright; + cxx << copyright; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name ( + find_value (ops.value<CLI::prologue_file> (), "pimpl")); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name ( + find_value (ops.value<CLI::epilogue_file> (), "pimpl")); + + 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) + guard_prefix = file_path.branch_path ().native_directory_string (); + + if (guard_prefix) + guard_prefix += '_'; + + + // HXX + // + { + Context ctx (hxx, schema, ops, 0, &hxx_expr, 0); + + 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> (), + "pimpl"); + append (hxx, + find_value (ops.value<CLI::hxx_prologue_file> (), "pimpl"), + prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + hxx << "#include <xsde/cxx/pre.hxx>" << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> hxx_clip (hxx); + + hxx << "#include " << ctx.process_include_path (hxx_skel_name) + << endl << endl; + + generate_parser_header (ctx); + + if (ops.value<CLI::generate_aggregate> ()) + generate_parser_aggregate_header (ctx); + + hxx << "#include <xsde/cxx/post.hxx>" << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, + find_value (ops.value<CLI::hxx_epilogue_file> (), "pimpl"), + epilogue); + append (hxx, + ops.value<CLI::hxx_epilogue> (), + ops.value<CLI::epilogue> (), + "pimpl"); + + 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 (); + } + } + + // CXX + // + { + Context ctx (cxx, schema, ops, 0, &hxx_obj_expr, 0); + + 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> (), + "pimpl"); + append (cxx, + find_value (ops.value<CLI::cxx_prologue_file> (), "pimpl"), + 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; + + generate_parser_source (ctx); + + if (ops.value<CLI::generate_aggregate> ()) + generate_parser_aggregate_source (ctx); + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, + find_value (ops.value<CLI::cxx_epilogue_file> (), "pimpl"), + epilogue); + append (cxx, + ops.value<CLI::cxx_epilogue> (), + ops.value<CLI::epilogue> (), + "pimpl"); + + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << cxx_path << ": " + << cxx_sloc.buffer ().count () << endl; + + sloc += cxx_sloc.buffer ().count (); + } + } + + return sloc; + } + 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 (); + } + } + + UnsignedLong Hybrid::Generator:: + generate_serializer (Hybrid::CLI::Options const& ops, + Schema& schema, + Path const& file_path, + const WarningSet&, + FileList& file_list, + AutoUnlinks& unlinks) + { + using std::ios_base; + namespace Indentation = BackendElements::Indentation; + + typedef BackendElements::Regex::Expression<Char> Regex; + + try + { + { + Boolean gen_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 (gen_xml_schema) + { + if (NarrowString name = ops.value<CLI::extern_xml_schema> ()) + { + if (file_path.native_file_string () != name) + gen_xml_schema = false; + } + } + + if (gen_xml_schema) + return 0; + } + + // Process names. + // + { + SerializerNameProcessor proc; + proc.process (ops, schema, file_path); + } + + NarrowString name (file_path.leaf ()); + NarrowString skel_suffix (ops.value <CLI::sskel_file_suffix> ()); + NarrowString impl_suffix (ops.value <CLI::simpl_file_suffix> ()); + + NarrowString hxx_suffix (ops.value <CLI::hxx_suffix> ()); + NarrowString cxx_suffix (ops.value <CLI::cxx_suffix> ()); + + NarrowString hxx_skel_regex ( + find_value (ops.value <CLI::hxx_regex> (), "sskel")); + NarrowString hxx_regex ( + find_value (ops.value <CLI::hxx_regex> (), "simpl")); + NarrowString cxx_regex ( + find_value (ops.value <CLI::cxx_regex> (), "simpl")); + + // Here we need to make sure that hxx_skel_expr is the same + // as in the C++/Serializer generator. + // + Regex hxx_skel_expr ( + hxx_skel_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + hxx_suffix + "#" + : hxx_skel_regex); + + Regex hxx_expr ( + hxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + hxx_suffix + "#" + : hxx_regex); + + Regex cxx_expr ( + cxx_regex.empty () + ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + cxx_suffix + "#" + : cxx_regex); + + if (!hxx_expr.match (name)) + { + wcerr << "error: serializer implementation header expression '" << + hxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + if (!cxx_expr.match (name)) + { + wcerr << "error: serializer implementation source expression '" << + cxx_expr.pattern () << "' does not match '" << + name.c_str () << "'" << endl; + throw Failed (); + } + + NarrowString hxx_skel_name (hxx_skel_expr.merge (name)); + NarrowString hxx_name (hxx_expr.merge (name)); + NarrowString cxx_name (cxx_expr.merge (name)); + + Path hxx_path (hxx_name, boost::filesystem::native); + Path cxx_path (cxx_name, boost::filesystem::native); + + if (NarrowString dir = ops.value<CLI::output_dir> ()) + { + try + { + Path path (dir, boost::filesystem::native); + + hxx_path = path / hxx_path; + cxx_path = path / cxx_path; + } + catch (InvalidPath const&) + { + wcerr << dir.c_str () << ": error: invalid path" << endl; + throw Failed (); + } + } + + WideOutputFileStream hxx (hxx_path, ios_base::out); + WideOutputFileStream cxx (cxx_path, ios_base::out); + + if (!hxx.is_open ()) + { + wcerr << hxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (hxx_path); + file_list.push_back (hxx_path.native_file_string ()); + + if (!cxx.is_open ()) + { + wcerr << cxx_path << ": error: unable to open in write mode" << endl; + throw Failed (); + } + + unlinks.add (cxx_path); + file_list.push_back (cxx_path.native_file_string ()); + + // Print copyright and license. + // + Char const* copyright ( + ops.value<CLI::proprietary_license> () + ? copyright_proprietary + : copyright_gpl); + + hxx << copyright; + cxx << copyright; + + // Prologue. + // + WideInputFileStream prologue; + { + NarrowString name ( + find_value (ops.value<CLI::prologue_file> (), "simpl")); + + if (name) + open (prologue, name); + } + + // Epilogue. + // + WideInputFileStream epilogue; + { + NarrowString name ( + find_value (ops.value<CLI::epilogue_file> (), "simpl")); + + 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) + guard_prefix = file_path.branch_path ().native_directory_string (); + + if (guard_prefix) + guard_prefix += '_'; + + + // HXX + // + { + Context ctx (hxx, schema, ops, 0, &hxx_expr, 0); + + 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> (), + "simpl"); + append (hxx, + find_value (ops.value<CLI::hxx_prologue_file> (), "simpl"), + prologue); + + hxx << "//" << endl + << "// End prologue." << endl + << endl; + + { + hxx << "#include <xsde/cxx/pre.hxx>" << endl + << endl; + + // Set auto-indentation. + // + Indentation::Clip<Indentation::CXX, WideChar> hxx_clip (hxx); + + hxx << "#include " << ctx.process_include_path (hxx_skel_name) + << endl << endl; + + generate_serializer_header (ctx); + + if (ops.value<CLI::generate_aggregate> ()) + generate_serializer_aggregate_header (ctx); + + hxx << "#include <xsde/cxx/post.hxx>" << endl + << endl; + } + + // Copy epilogue. + // + hxx << "// Begin epilogue." << endl + << "//" << endl; + + append (hxx, + find_value (ops.value<CLI::hxx_epilogue_file> (), "simpl"), + epilogue); + append (hxx, + ops.value<CLI::hxx_epilogue> (), + ops.value<CLI::epilogue> (), + "simpl"); + + 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 (); + } + } + + // CXX + // + { + Context ctx (cxx, schema, ops, 0, &hxx_expr, 0); + + 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> (), + "simpl"); + append (cxx, + find_value (ops.value<CLI::cxx_prologue_file> (), "simpl"), + 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; + + generate_serializer_source (ctx); + + if (ops.value<CLI::generate_aggregate> ()) + generate_serializer_aggregate_source (ctx); + } + + // Copy epilogue. + // + cxx << "// Begin epilogue." << endl + << "//" << endl; + + append (cxx, + find_value (ops.value<CLI::cxx_epilogue_file> (), "simpl"), + epilogue); + append (cxx, + ops.value<CLI::cxx_epilogue> (), + ops.value<CLI::epilogue> (), + "simpl"); + + cxx << "//" << endl + << "// End epilogue." << endl + << endl; + + if (show_sloc) + { + wcerr << cxx_path << ": " + << cxx_sloc.buffer ().count () << endl; + + sloc += cxx_sloc.buffer ().count (); + } + } + + return sloc; + } + 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 (); + } + } +} |