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