// file : xsde/cxx/hybrid/generator.cxx // author : Boris Kolpackov // copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC // license : GNU GPL v2 + exceptions; see accompanying LICENSE file #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../../../libxsde/xsde/cxx/version.hxx" using std::endl; using std::wcerr; using std::wcout; using namespace XSDFrontend::SemanticGraph; namespace Indentation = BackendElements::Indentation; // // 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-2011 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-2011 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 char_encoding = "char-encoding"; 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 omit_default_attributes = "omit-default-attributes"; extern Key suppress_enum = "suppress-enum"; extern Key generate_clone = "generate-clone"; extern Key generate_detach = "generate-detach"; extern Key generate_insertion = "generate-insertion"; extern Key generate_extraction = "generate-extraction"; 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 custom_allocator = "custom-allocator"; extern Key generate_polymorphic = "generate-polymorphic"; extern Key runtime_polymorphic = "runtime-polymorphic"; extern Key polymorphic_type = "polymorphic-type"; extern Key generate_typeinfo = "generate-typeinfo"; extern Key polymorphic_schema = "polymorphic-schema"; extern Key reuse_style_mixin = "reuse-style-mixin"; extern Key custom_data = "custom-data"; extern Key custom_type = "custom-type"; 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& o (wcout); ::CLI::Indent::Clip< ::CLI::OptionsUsage, WideChar> clip (o); o << "--char-encoding " << endl << " Specify the character encoding that should be\n" << " used in the object model. Valid values are 'utf8'\n" << " (default) and 'iso8859-1'." << endl; o << "--no-stl" << endl << " Generate code that does not use STL." << endl; o << "--no-iostream" << endl << " Generate code that does not use the iostream\n" << " library." << endl; o << "--no-exceptions" << endl << " Generate code that does not use C++ exceptions." << endl; o << "--no-long-long" << endl << " Generate code that does not use the long long\n" << " and unsigned long long types." << endl; o << "--generate-parser" << endl << " Generate XML parsing code." << endl; o << "--generate-serializer" << endl << " Generate XML serialization code." << endl; o << "--generate-aggregate" << endl << " Generate parser/serializer aggregates for root\n" << " elements and/or types." << endl; o << "--suppress-validation" << endl << " Suppress the generation of validation code in\n" << " parser and serializer." << endl; o << "--suppress-parser-val" << endl << " Suppress the generation of validation code in\n" << " parser." << endl; o << "--suppress-serializer-val" << endl << " Suppress the generation of validation code in\n" << " serializer." << endl; o << "--omit-default-attributes" << endl << " Omit attributes with default and fixed values\n" << " from serialized XML documents." << endl; o << "--suppress-enum" << endl << " Suppress the generation of the XML Schema\n" << " enumeration to C++ enum mapping." << endl; o << "--generate-clone" << endl << " Generate clone functions for variable-length\n" << " types." << endl; o << "--generate-detach" << endl << " Generate detach functions for elements and\n" << " attributes of variable-length types." << endl; o << "--generate-insertion " << endl << " Generate data representation stream insertion\n" << " operators for the output stream type." << endl; o << "--generate-extraction " << endl << " Generate data representation stream extraction\n" << " operators for the input stream type." << endl; o << "--generate-inline" << endl << " Generate certain functions inline." << endl; o << "--generate-forward" << endl << " Generate forward declaration file." << endl; o << "--generate-xml-schema" << endl << " Generate C++ header files as if the schema being\n" << " compiled defines the XML Schema namespace." << endl; o << "--extern-xml-schema " << endl << " Generate code as if the XML Schema namespace was\n" << " defined in and xsd:included in the schema\n" << " being compiled." << endl; o << "--suppress-reset" << endl << " Suppress the generation of parser and serializer\n" << " reset code." << endl; o << "--custom-allocator" << endl << " Generate code that uses custom allocator functions\n" << " instead of operator new/delete." << endl; o << "--generate-polymorphic" << endl << " Generate polymorphism-aware code. Specify this\n" << " option if you use substitution groups or xsi:type." << endl; o << "--runtime-polymorphic" << endl << " Generate non-polymorphic code that uses the\n" << " runtime library configured with polymorphism\n" << " support." << endl; o << "--polymorphic-type " << endl << " Indicate that is a root of a polymorphic\n" << " type hierarchy." << endl; o << "--generate-typeinfo" << endl << " Generate type information functions for\n" << " polymorphic object model types." << endl; o << "--polymorphic-schema " << endl << " Indicate that contains derivations of\n" << " polymorphic types." << endl; o << "--reuse-style-mixin" << endl << " Generate code that supports the mixin base\n" << " parser/serializer implementation reuse style." << endl; o << "--custom-data " << endl << " Add custom data to the C++ class generated for\n" << " XML Schema type ." << endl; o << "--custom-type " << endl << " Use a custom type implementation instead of the\n" << " generated version. The argument is in the\n" << " form name[=[flags][/[type][/[base][/include]]]],\n" << " where is an XML Schema type name,\n" << " optional specify whether the custom type\n" << " is fixed or variable-length, optional is\n" << " a C++ type name that should be used instead,\n" << " optional is a C++ name that should be\n" << " given to the generated version, and optional\n" << " is the header file that defines the\n" << " custom implementation." << endl; o << "--custom-parser " << endl << " Use a custom parser implementation instead of the\n" << " generated version. The argument is in the\n" << " form name[=[base][/include]], where is an\n" << " XML Schema type name, optional is a C++\n" << " name that should be given to the generated\n" << " version, and optional is the header\n" << " file that defines the custom implementation." << endl; o << "--custom-serializer " << endl << " Use a custom serializer implementation instead of\n" << " the generated version. The argument is in\n" << " the form name[=[base][/include]], where is\n" << " an XML Schema type name, optional is a C++\n" << " name that should be given to the generated\n" << " version, and optional is the header\n" << " file that defines the custom implementation." << endl; o << "--root-element-first" << endl << " Treat only the first global element as a document\n" << " root." << endl; o << "--root-element-last" << endl << " Treat only the last global element as a document\n" << " root." << endl; o << "--root-element-all" << endl << " Treat all global elements as document roots." << endl; o << "--root-element-none" << endl << " Don't treat any global elements as document roots." << endl; o << "--root-element " << endl << " Treat only as a document root. Repeat\n" << " this option to specify more than one root element." << endl; o << "--root-type " << endl << " Generate parser/serializer aggregate for .\n" << " Repeat this option to specify more than one type." << endl; o << "--output-dir " << endl << " Write generated files to instead of the\n" << " current directory." << endl; o << "--pskel-type-suffix " << endl << " Use instead of the default '_pskel' suffix\n" << " to construct the names of generated parser\n" << " skeletons." << endl; o << "--sskel-type-suffix " << endl << " Use instead of the default '_sskel' suffix\n" << " to construct the names of generated serializer\n" << " skeletons." << endl; o << "--pskel-file-suffix " << endl << " Use instead of the default '-pskel' suffix\n" << " to construct the names of generated parser\n" << " skeleton files." << endl; o << "--sskel-file-suffix " << endl << " Use instead of the default '-sskel' suffix\n" << " to construct the names of generated serializer\n" << " skeleton files." << endl; o << "--pimpl-type-suffix " << endl << " Use instead of the default '_pimpl' suffix\n" << " to construct the names of generated parser\n" << " implementations." << endl; o << "--simpl-type-suffix " << endl << " Use instead of the default '_simpl' suffix\n" << " to construct the names of generated serializer\n" << " implementations." << endl; o << "--pimpl-file-suffix " << endl << " Use instead of the default '-pimpl' suffix\n" << " to construct the names of generated parser\n" << " implementation files." << endl; o << "--simpl-file-suffix " << endl << " Use instead of the default '-simpl' suffix\n" << " to construct the names of generated serializer\n" << " implementation files." << endl; o << "--paggr-type-suffix " << endl << " Use instead of the default '_paggs' suffix\n" << " to construct the names of generated parser\n" << " aggregates." << endl; o << "--saggr-type-suffix " << endl << " Use instead of the default '_saggr' suffix\n" << " to construct the names of generated serializer\n" << " aggregates." << endl; o << "--namespace-map =" << endl << " Map XML Schema namespace to C++ namespace\n" << " . Repeat this option to specify mapping for\n" << " more than one XML Schema namespace." << endl; o << "--namespace-regex " << endl << " Add to the list of regular expressions\n" << " used to translate XML Schema namespace names to\n" << " C++ namespace names." << endl; o << "--namespace-regex-trace" << endl << " Trace the process of applying regular expressions\n" << " specified with the --namespace-regex option." << endl; o << "--reserved-name " << endl << " Add 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; o << "--include-with-brackets" << endl << " Use angle brackets (<>) instead of quotes (\"\") in\n" << " generated #include directives." << endl; o << "--include-prefix " << endl << " Add to generated #include directive\n" << " paths." << endl; o << "--include-regex " << endl << " Add to the list of regular expressions\n" << " used to transform #include directive paths." << endl; o << "--include-regex-trace" << endl << " Trace the process of applying regular expressions\n" << " specified with the --include-regex option." << endl; o << "--guard-prefix " << endl << " Add to generated header inclusion guards." << endl; // File suffix. // o << "--hxx-suffix " << endl << " Use instead of the default '.hxx' to\n" << " construct the name of the header files." << endl; o << "--ixx-suffix " << endl << " Use instead of the default '.ixx' to\n" << " construct the name of the inline files." << endl; o << "--cxx-suffix " << endl << " Use instead of the default '.cxx' to\n" << " construct the name of the source files." << endl; o << "--fwd-suffix " << endl << " Use instead of the default '-fwd.hxx'\n" << " to construct the name of the forward declaration\n" << " file." << endl; // File regex. // o << "--hxx-regex " << endl << " Use to construct the names of the header\n" << " files." << endl; o << "--ixx-regex " << endl << " Use to construct the names of the inline\n" << " files." << endl; o << "--cxx-regex " << endl << " Use to construct the names of the source\n" << " files." << endl; o << "--fwd-regex " << endl << " Use to construct the name of the forward\n" << " declaration file." << endl; // Prologues. // o << "--hxx-prologue " << endl << " Insert at the beginning of the header\n" << " files." << endl; o << "--ixx-prologue " << endl << " Insert at the beginning of the inline\n" << " files." << endl; o << "--cxx-prologue " << endl << " Insert at the beginning of the source\n" << " files." << endl; o << "--fwd-prologue " << endl << " Insert at the beginning of the forward\n" << " declaration file." << endl; o << "--prologue " << endl << " Insert at the beginning of each generated\n" << " file for which there is no file-specific prologue." << endl; // Epilogues. // o << "--hxx-epilogue " << endl << " Insert at the end of the header files." << endl; o << "--ixx-epilogue " << endl << " Insert at the end of the inline files." << endl; o << "--cxx-epilogue " << endl << " Insert at the end of the source files." << endl; o << "--fwd-epilogue " << endl << " Insert at the end of the forward\n" << " declaration file." << endl; o << "--epilogue " << endl << " Insert at the end of each generated file\n" << " for which there is no file-specific epilogue." << endl; // Prologue files. // o << "--hxx-prologue-file " << endl << " Insert the content of the at the beginning\n" << " of the header files." << endl; o << "--ixx-prologue-file " << endl << " Insert the content of the at the beginning\n" << " of the inline files." << endl; o << "--cxx-prologue-file " << endl << " Insert the content of the at the beginning\n" << " of the source files." << endl; o << "--fwd-prologue-file " << endl << " Insert the content of the at the beginning\n" << " of the forward declaration file." << endl; o << "--prologue-file " << endl << " Insert the content of the at the beginning\n" << " of each generated file for which there is no file-\n" << " specific prologue file." << endl; // Epilogue files. // o << "--hxx-epilogue-file " << endl << " Insert the content of the at the end of\n" << " the header files." << endl; o << "--ixx-epilogue-file " << endl << " Insert the content of the at the end of\n" << " the inline files." << endl; o << "--cxx-epilogue-file " << endl << " Insert the content of the at the end of\n" << " the source files." << endl; o << "--fwd-epilogue-file " << endl << " Insert the content of the at the end of\n" << " the forward declaration file." << endl; o << "--epilogue-file " << endl << " Insert the content of the at the end of\n" << " each generated file for which there is no file-\n" << " specific epilogue file." << endl; // Misc. // o << "--show-anonymous" << endl << " Show elements and attributes that are of anonymous\n" << " types." << endl; o << "--show-sloc" << endl << " Show the number of generated physical source lines\n" << " of code (SLOC)." << endl; o << "--sloc-limit " << endl << " Check that the number of generated physical source\n" << " lines of code (SLOC) does not exceed ." << endl; o << "--options-file " << endl << " Read additional options from . Each option\n" << " should appear on a separate line optionally\n" << " followed by space and an argument." << endl; o << "--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 ().default_value ("utf8"); spec.option ().default_value ("-pskel"); spec.option ().default_value ("-sskel"); spec.option ().default_value ("_pskel"); spec.option ().default_value ("_sskel"); spec.option ().default_value ("-pimpl"); spec.option ().default_value ("-simpl"); spec.option ().default_value ("_pimpl"); spec.option ().default_value ("_simpl"); spec.option ().default_value ("_paggr"); spec.option ().default_value ("_saggr"); spec.option ().default_value (".hxx"); spec.option ().default_value (".ixx"); spec.option ().default_value (".cxx"); spec.option ().default_value ("-fwd.hxx"); return spec; } namespace { NarrowString find_value (Cult::Containers::Vector const& v, Char const* key) { typedef Cult::Containers::Vector 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& dst, Cult::Containers::Vector const& src, Char const* key) { typedef Cult::Containers::Vector 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)); } } struct FundNamespace: Namespace, Hybrid::Context { FundNamespace (Hybrid::Context& c, Char type) : Namespace (c), Hybrid::Context (c), type_ (type) { } void traverse (Type& ns) { namespace CLI = Hybrid::CLI; pre (ns); os << "using ::xsde::cxx::hybrid::any_type;" << endl; Boolean us, ui; String skel, impl; if (type_ == 'p') { skel = options.value (); impl = options.value (); us = skel == L"_pskel"; ui = impl == L"_pimpl"; } else { skel = options.value (); impl = options.value (); us = skel == L"_sskel"; ui = impl == L"_simpl"; } if (us) os << "using ::xsde::cxx::hybrid::any_type_" << type_ << "skel;"; else os << "using ::xsde::cxx::hybrid::any_type_" << type_ << "skel " << "any_type" << skel << ";"; if (ui) os << "using ::xsde::cxx::hybrid::any_type_" << type_ << "impl;"; else os << "using ::xsde::cxx::hybrid::any_type_" << type_ << "impl " << "any_type" << impl << ";"; post (ns); } private: Char type_; }; } Parser::CLI::Options* Hybrid::Generator:: parser_options (CLI::Options const& h, Schema& schema, Path const& path) { namespace H = CLI; namespace P = Parser::CLI; Evptr r (new P::Options); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = false; r->value () = h.value (); r->value () = h.value () || h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); Char const* k = "pskel"; r->value () = find_value (h.value (), k); r->value () = find_value (h.value (), k); r->value () = find_value (h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); r->value () = h.value (); r->value () = h.value (); // Add the anyType parser. // { std::wostringstream os; Context ctx (os, schema, path, h, 0, 0, 0); os << endl << "#include " << endl << "#include " << endl << "#include " << endl << endl; { Indentation::Clip clip (os); FundNamespace ns (ctx, 'p'); ns.dispatch (ctx.xs_ns ()); } r->value ().push_back (String (os.str ()).to_narrow ()); } return r.release (); } Serializer::CLI::Options* Hybrid::Generator:: serializer_options (CLI::Options const& h, Schema& schema, Path const& path) { namespace H = CLI; namespace S = Serializer::CLI; Evptr r (new S::Options); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = false; r->value () = h.value (); r->value () = h.value () || h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); r->value () = h.value (); Char const* k = "sskel"; r->value () = find_value (h.value (), k); r->value () = find_value (h.value (), k); r->value () = find_value (h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); r->value () = find_value ( h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); copy_values (r->value (), h.value (), k); r->value () = h.value (); r->value () = h.value (); // Add the anyType parser. // { std::wostringstream os; Context ctx (os, schema, path, h, 0, 0, 0); os << endl << "#include " << endl << "#include " << endl << "#include " << endl << endl; { Indentation::Clip clip (os); FundNamespace ns (ctx, 's'); ns.dispatch (ctx.xs_ns ()); } r->value ().push_back (String (os.str ()).to_narrow ()); } return r.release (); } Void Hybrid::Generator:: calculate_size (CLI::Options const& ops, XSDFrontend::SemanticGraph::Schema& schema, XSDFrontend::SemanticGraph::Path const& file, const WarningSet& disabled_warnings) { // Determine which types are fixed/variable-sized. // TreeSizeProcessor proc; if (!proc.process (ops, schema, file, disabled_warnings)) throw Failed (); } Void Hybrid::Generator:: process_tree_names (CLI::Options const& ops, XSDFrontend::SemanticGraph::Schema& schema, XSDFrontend::SemanticGraph::Path const& file) { TreeNameProcessor proc; proc.process (ops, schema, file, false); } Void Hybrid::Generator:: process_parser_names (CLI::Options const& ops, XSDFrontend::SemanticGraph::Schema& schema, XSDFrontend::SemanticGraph::Path const& file) { ParserNameProcessor proc; if (!proc.process (ops, schema, file, false)) throw Failed (); } Void Hybrid::Generator:: process_serializer_names (CLI::Options const& ops, XSDFrontend::SemanticGraph::Schema& schema, XSDFrontend::SemanticGraph::Path const& file) { SerializerNameProcessor proc; if (!proc.process (ops, schema, file, false)) throw Failed (); } namespace { template 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 const& primary, Cult::Containers::Vector const& def, Char const* primary_key, Char const* def_key) { typedef Cult::Containers::Vector 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 const& primary, Cult::Containers::Vector 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, Boolean fpt, const WarningSet& disabled_warnings, TypeMap::Namespaces& parser_type_map, TypeMap::Namespaces& serializer_type_map, FileList& file_list, AutoUnlinks& unlinks) { using std::ios_base; typedef Context::Regex Regex; try { Boolean generate_xml_schema (ops.value ()); // 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 ()) { 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, true); } // Generate code. // Boolean inline_ (ops.value () && !generate_xml_schema); Boolean forward (ops.value () && !generate_xml_schema); Boolean source (!generate_xml_schema); NarrowString name (file_path.leaf ()); NarrowString hxx_suffix (ops.value ()); NarrowString ixx_suffix (ops.value ()); NarrowString cxx_suffix (ops.value ()); NarrowString fwd_suffix (ops.value ()); NarrowString hxx_regex (find_value (ops.value (), "")); NarrowString ixx_regex (find_value (ops.value (), "")); NarrowString cxx_regex (find_value (ops.value (), "")); 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 ().empty () ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + fwd_suffix + "#" : ops.value ()); 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); Path out_dir; if (NarrowString dir = ops.value ()) { try { out_dir = Path (dir, boost::filesystem::native); } 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; fwd_path = out_dir / fwd_path; } // 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 () ? 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 (), "")); if (name) open (prologue, name); } // Epilogue. // WideInputFileStream epilogue; { NarrowString name ( find_value (ops.value (), "")); if (name) open (epilogue, name); } // SLOC counter. // UnsignedLong sloc (0); Boolean show_sloc (ops.value ()); // // Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. NarrowString guard_prefix (ops.value ()); if (!guard_prefix) guard_prefix = file_path.branch_path ().native_directory_string (); if (guard_prefix) guard_prefix += '_'; // FWD // if (forward) { Context ctx ( fwd, schema, file_path, ops, &fwd_expr, &hxx_expr, &ixx_expr); Indentation::Clip 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; // Version check. // fwd << "#include " << endl << endl << "#if (XSDE_INT_VERSION != " << XSDE_INT_VERSION << "L)" << endl << "#error XSD/e runtime version mismatch" << endl << "#endif" << endl << endl; fwd << "#include " << endl << endl; // Copy prologue. // fwd << "// Begin prologue." << endl << "//" << endl; append (fwd, ops.value (), ops.value (), 0, ""); append (fwd, ops.value (), prologue); fwd << "//" << endl << "// End prologue." << endl << endl; { // Set auto-indentation. // Indentation::Clip fwd_clip (fwd); // Generate. // generate_tree_forward (ctx, false); } // Copy epilogue. // fwd << "// Begin epilogue." << endl << "//" << endl; append (fwd, ops.value (), epilogue); append (fwd, ops.value (), ops.value (), 0, ""); fwd << "//" << endl << "// End epilogue." << endl << endl; fwd << "#include " << endl << endl; fwd << "#endif // " << guard << endl; if (show_sloc) wcerr << fwd_path << ": " << fwd_sloc.buffer ().count () << endl; sloc += fwd_sloc.buffer ().count (); } // C++ namespace mapping for the XML Schema namespace. // String xs_ns; // HXX // { Context ctx ( hxx, schema, file_path, ops, &fwd_expr, &hxx_expr, &ixx_expr); xs_ns = ctx.xs_ns_name (); Indentation::Clip 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; // Version check. // hxx << "#include " << 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 " << endl << endl; if (ops.value () == "iso8859-1") { hxx << "#ifndef XSDE_ENCODING_ISO8859_1" << endl << "#error the generated code uses the ISO-8859-1 encoding" << "while the XSD/e runtime does not (reconfigure the runtime " << "or change the --char-encoding value)" << endl << "#endif" << endl << endl; } else { hxx << "#ifndef XSDE_ENCODING_UTF8" << endl << "#error the generated code uses the UTF-8 encoding" << "while the XSD/e runtime does not (reconfigure the runtime " << "or change the --char-encoding value)" << endl << "#endif" << endl << endl; } if (ops.value ()) { 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 ()) { 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 ()) { 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; } if (ops.value ()) { hxx << "#ifndef XSDE_CUSTOM_ALLOCATOR" << endl << "#error the generated code uses custom allocator while " << "the XSD/e runtime does not (reconfigure the runtime or " << "remove --custom-allocator)" << endl << "#endif" << endl << endl; } else { hxx << "#ifdef XSDE_CUSTOM_ALLOCATOR" << endl << "#error the XSD/e runtime uses custom allocator while " << "the generated code does not (reconfigure the runtime or " << "add --custom-allocator)" << endl << "#endif" << endl << endl; } // // hxx << "#include " << endl << endl; // Copy prologue. // hxx << "// Begin prologue." << endl << "//" << endl; append (hxx, ops.value (), ops.value (), ""); append (hxx, find_value (ops.value (), ""), prologue); hxx << "//" << endl << "// End prologue." << endl << endl; { // Set auto-indentation. // Indentation::Clip 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); if (!ops.value ().empty ()) generate_insertion_header (ctx); if (!ops.value ().empty ()) generate_extraction_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; } } // Copy epilogue. // hxx << "// Begin epilogue." << endl << "//" << endl; append (hxx, find_value (ops.value (), ""), epilogue); append (hxx, ops.value (), ops.value (), ""); hxx << "//" << endl << "// End epilogue." << endl << endl; hxx << "#include " << 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, &fwd_expr, &hxx_expr, &ixx_expr); Indentation::Clip 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 (), ops.value (), ""); append (ixx, find_value (ops.value (), ""), prologue); ixx << "//" << endl << "// End prologue." << endl << endl; { // Set auto-indentation. // Indentation::Clip ixx_clip (ixx); // Generate. // generate_tree_inline (ctx); } // Copy epilogue. // ixx << "// Begin epilogue." << endl << "//" << endl; append (ixx, find_value (ops.value (), ""), epilogue); append (ixx, ops.value (), ops.value (), ""); 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, file_path, ops, &fwd_expr, &hxx_expr, &ixx_expr); Indentation::Clip cxx_sloc (cxx); cxx << "#include " << endl << endl; // Copy prologue. // cxx << "// Begin prologue." << endl << "//" << endl; append (cxx, ops.value (), ops.value (), ""); append (cxx, find_value (ops.value (), ""), prologue); cxx << "//" << endl << "// End prologue." << endl << endl; { // Set auto-indentation. // Indentation::Clip cxx_clip (cxx); cxx << "#include " << ctx.process_include_path (hxx_name) << endl << endl; if (!inline_) generate_tree_inline (ctx); generate_tree_source (ctx); if (!ops.value ().empty ()) generate_insertion_source (ctx); if (!ops.value ().empty ()) generate_extraction_source (ctx); } // Copy epilogue. // cxx << "// Begin epilogue." << endl << "//" << endl; append (cxx, find_value (ops.value (), ""), epilogue); append (cxx, ops.value (), ops.value (), ""); cxx << "//" << endl << "// End epilogue." << endl << endl; cxx << "#include " << 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 () || ops.value ()) { generate_tree_type_map (ops, schema, file_path, hxx_name, parser_type_map, serializer_type_map); // Re-map anyType. // if (ops.value ()) { parser_type_map.push_back ( TypeMap::Namespace ("http://www.w3.org/2001/XMLSchema")); TypeMap::Namespace& xs (parser_type_map.back ()); xs.types_push_back ("anyType", xs_ns + L"::any_type*"); } if (ops.value ()) { serializer_type_map.push_back ( TypeMap::Namespace ("http://www.w3.org/2001/XMLSchema")); TypeMap::Namespace& xs (serializer_type_map.back ()); xs.types_push_back ("anyType", L"const " + xs_ns + L"::any_type&"); } } 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 const& e) { wcerr << "error: invalid regex: '" << e.expression ().c_str () << "': " << e.description ().c_str () << endl; throw Failed (); } catch (BackendElements::Regex::Format 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, Boolean fpt, const WarningSet&, FileList& file_list, AutoUnlinks& unlinks) { using std::ios_base; typedef BackendElements::Regex::Expression Regex; try { { Boolean gen_xml_schema (ops.value ()); // 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 ()) { if (file_path.native_file_string () != name) gen_xml_schema = false; } } if (gen_xml_schema) return 0; } // Process names. // { ParserNameProcessor proc; if (!proc.process (ops, schema, file_path, true)) throw Failed (); } NarrowString name (file_path.leaf ()); NarrowString skel_suffix (ops.value ()); NarrowString impl_suffix (ops.value ()); NarrowString hxx_suffix (ops.value ()); NarrowString cxx_suffix (ops.value ()); NarrowString hxx_obj_regex ( find_value (ops.value (), "")); NarrowString hxx_skel_regex ( find_value (ops.value (), "pskel")); NarrowString hxx_regex ( find_value (ops.value (), "pimpl")); NarrowString cxx_regex ( find_value (ops.value (), "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); Path out_dir; if (NarrowString dir = ops.value ()) { try { out_dir = Path (dir, boost::filesystem::native); } catch (InvalidPath const&) { wcerr << dir.c_str () << ": error: invalid path" << endl; throw Failed (); } } if (fpt) { // 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; cxx_path = out_dir / cxx_path; } 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 () ? copyright_proprietary : copyright_gpl); hxx << copyright; cxx << copyright; // Prologue. // WideInputFileStream prologue; { NarrowString name ( find_value (ops.value (), "pimpl")); if (name) open (prologue, name); } // Epilogue. // WideInputFileStream epilogue; { NarrowString name ( find_value (ops.value (), "pimpl")); if (name) open (epilogue, name); } // SLOC counter. // UnsignedLong sloc (0); Boolean show_sloc (ops.value ()); // // Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. NarrowString guard_prefix (ops.value ()); if (!guard_prefix) guard_prefix = file_path.branch_path ().native_directory_string (); if (guard_prefix) guard_prefix += '_'; Boolean aggr (ops.value ()); // HXX // { Context ctx (hxx, schema, file_path, ops, 0, &hxx_expr, 0); Indentation::Clip 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; hxx << "#include " << endl << endl; // Copy prologue. // hxx << "// Begin prologue." << endl << "//" << endl; append (hxx, ops.value (), ops.value (), "pimpl"); append (hxx, find_value (ops.value (), "pimpl"), prologue); hxx << "//" << endl << "// End prologue." << endl << endl; { // Define omit aggregate macro. // hxx << "#ifndef XSDE_OMIT_PAGGR" << endl << "# define XSDE_OMIT_PAGGR" << endl << "# define " << guard << "_CLEAR_OMIT_PAGGR" << endl << "#endif" << endl << endl; // Set auto-indentation. // Indentation::Clip hxx_clip (hxx); hxx << "#include " << ctx.process_include_path (hxx_skel_name) << endl << endl; generate_parser_header (ctx); // Clear omit aggregate macro. // hxx << "#ifdef " << guard << "_CLEAR_OMIT_PAGGR" << endl << "# undef XSDE_OMIT_PAGGR" << endl << "#endif" << endl << endl; if (aggr) { hxx << "#ifndef XSDE_OMIT_PAGGR" << endl << endl; generate_parser_aggregate_header (ctx); hxx << "#endif // XSDE_OMIT_PAGGR" << endl << endl; } } // Copy epilogue. // hxx << "// Begin epilogue." << endl << "//" << endl; append (hxx, find_value (ops.value (), "pimpl"), epilogue); append (hxx, ops.value (), ops.value (), "pimpl"); hxx << "//" << endl << "// End epilogue." << endl << endl; hxx << "#include " << 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, file_path, ops, 0, &hxx_expr, 0); Indentation::Clip cxx_sloc (cxx); // Copy prologue. // cxx << "// Begin prologue." << endl << "//" << endl; append (cxx, ops.value (), ops.value (), "pimpl"); append (cxx, find_value (ops.value (), "pimpl"), prologue); cxx << "//" << endl << "// End prologue." << endl << endl; { // Set auto-indentation. // Indentation::Clip cxx_clip (cxx); cxx << "#include " << ctx.process_include_path (hxx_name) << endl << endl; generate_parser_source (ctx, hxx_obj_expr); if (aggr) generate_parser_aggregate_source (ctx); } // Copy epilogue. // cxx << "// Begin epilogue." << endl << "//" << endl; append (cxx, find_value (ops.value (), "pimpl"), epilogue); append (cxx, ops.value (), ops.value (), "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 const& e) { wcerr << "error: invalid regex: '" << e.expression ().c_str () << "': " << e.description ().c_str () << endl; throw Failed (); } catch (BackendElements::Regex::Format 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, Boolean fpt, const WarningSet&, FileList& file_list, AutoUnlinks& unlinks) { using std::ios_base; typedef BackendElements::Regex::Expression Regex; try { { Boolean gen_xml_schema (ops.value ()); // 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 ()) { if (file_path.native_file_string () != name) gen_xml_schema = false; } } if (gen_xml_schema) return 0; } // Process names. // { SerializerNameProcessor proc; if (!proc.process (ops, schema, file_path, true)) throw Failed (); } NarrowString name (file_path.leaf ()); NarrowString skel_suffix (ops.value ()); NarrowString impl_suffix (ops.value ()); NarrowString hxx_suffix (ops.value ()); NarrowString cxx_suffix (ops.value ()); NarrowString hxx_obj_regex ( find_value (ops.value (), "")); NarrowString hxx_skel_regex ( find_value (ops.value (), "sskel")); NarrowString hxx_regex ( find_value (ops.value (), "simpl")); NarrowString cxx_regex ( find_value (ops.value (), "simpl")); // 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++/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); Path out_dir; if (NarrowString dir = ops.value ()) { try { out_dir = Path (dir, boost::filesystem::native); } catch (InvalidPath const&) { wcerr << dir.c_str () << ": error: invalid path" << endl; throw Failed (); } } if (fpt) { // 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; cxx_path = out_dir / cxx_path; } 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 () ? copyright_proprietary : copyright_gpl); hxx << copyright; cxx << copyright; // Prologue. // WideInputFileStream prologue; { NarrowString name ( find_value (ops.value (), "simpl")); if (name) open (prologue, name); } // Epilogue. // WideInputFileStream epilogue; { NarrowString name ( find_value (ops.value (), "simpl")); if (name) open (epilogue, name); } // SLOC counter. // UnsignedLong sloc (0); Boolean show_sloc (ops.value ()); // // Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. NarrowString guard_prefix (ops.value ()); if (!guard_prefix) guard_prefix = file_path.branch_path ().native_directory_string (); if (guard_prefix) guard_prefix += '_'; Boolean aggr (ops.value ()); // HXX // { Context ctx (hxx, schema, file_path, ops, 0, &hxx_expr, 0); Indentation::Clip 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; hxx << "#include " << endl << endl; // Copy prologue. // hxx << "// Begin prologue." << endl << "//" << endl; append (hxx, ops.value (), ops.value (), "simpl"); append (hxx, find_value (ops.value (), "simpl"), prologue); hxx << "//" << endl << "// End prologue." << endl << endl; { // Define omit aggregate macro. // hxx << "#ifndef XSDE_OMIT_SAGGR" << endl << "# define XSDE_OMIT_SAGGR" << endl << "# define " << guard << "_CLEAR_OMIT_SAGGR" << endl << "#endif" << endl << endl; // Set auto-indentation. // Indentation::Clip hxx_clip (hxx); hxx << "#include " << ctx.process_include_path (hxx_skel_name) << endl << endl; generate_serializer_header (ctx); // Clear omit aggregate macro. // hxx << "#ifdef " << guard << "_CLEAR_OMIT_SAGGR" << endl << "# undef XSDE_OMIT_SAGGR" << endl << "#endif" << endl << endl; if (aggr) { hxx << "#ifndef XSDE_OMIT_SAGGR" << endl << endl; generate_serializer_aggregate_header (ctx); hxx << "#endif // XSDE_OMIT_SAGGR" << endl << endl; } } // Copy epilogue. // hxx << "// Begin epilogue." << endl << "//" << endl; append (hxx, find_value (ops.value (), "simpl"), epilogue); append (hxx, ops.value (), ops.value (), "simpl"); hxx << "//" << endl << "// End epilogue." << endl << endl; hxx << "#include " << 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, file_path, ops, 0, &hxx_expr, 0); Indentation::Clip cxx_sloc (cxx); // Copy prologue. // cxx << "// Begin prologue." << endl << "//" << endl; append (cxx, ops.value (), ops.value (), "simpl"); append (cxx, find_value (ops.value (), "simpl"), prologue); cxx << "//" << endl << "// End prologue." << endl << endl; { // Set auto-indentation. // Indentation::Clip cxx_clip (cxx); cxx << "#include " << ctx.process_include_path (hxx_name) << endl << endl; generate_serializer_source (ctx, hxx_obj_expr); if (aggr) generate_serializer_aggregate_source (ctx); } // Copy epilogue. // cxx << "// Begin epilogue." << endl << "//" << endl; append (cxx, find_value (ops.value (), "simpl"), epilogue); append (cxx, ops.value (), ops.value (), "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 (UnrepresentableCharacter const& e) { wcerr << "error: character at position " << e.position () << " " << "in string '" << e.string () << "' is unrepresentable in " << "the target encoding" << 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 const& e) { wcerr << "error: invalid regex: '" << e.expression ().c_str () << "': " << e.description ().c_str () << endl; throw Failed (); } catch (BackendElements::Regex::Format const& e) { wcerr << "error: invalid regex: '" << e.expression () << "': " << e.description () << endl; throw Failed (); } } }