// file : xsd/cxx/parser/generator.cxx // author : Boris Kolpackov // copyright : Copyright (c) 2005-2010 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-2010 Code Synthesis Tools CC\n" "//\n" "// This program was generated by CodeSynthesis XSD, an XML Schema to\n" "// C++ data binding compiler.\n" "//\n" "// This program is free software; you can redistribute it and/or modify\n" "// it under the terms of the GNU General Public License version 2 as\n" "// published by the Free Software Foundation.\n" "//\n" "// This program is distributed in the hope that it will be useful,\n" "// but WITHOUT ANY WARRANTY; without even the implied warranty of\n" "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" "// GNU General Public License for more details.\n" "//\n" "// You should have received a copy of the GNU General Public License\n" "// along with this program; if not, write to the Free Software\n" "// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" "//\n" "// In addition, as a special exception, Code Synthesis Tools CC gives\n" "// permission to link this program with the Xerces-C++ library (or with\n" "// modified versions of Xerces-C++ that use the same license as Xerces-C++),\n" "// and distribute linked combinations including the two. You must obey\n" "// the GNU General Public License version 2 in all respects for all of\n" "// the code used other than Xerces-C++. If you modify this copy of the\n" "// program, you may extend this exception to your version of the program,\n" "// but you are not obligated to do so. If you do not wish to do so, delete\n" "// this exception statement from your version.\n" "//\n" "// Furthermore, Code Synthesis Tools CC makes a special exception for\n" "// the Free/Libre and Open Source Software (FLOSS) which is described\n" "// in the accompanying FLOSSE file.\n" "//\n\n"; Char const copyright_proprietary[] = "// Copyright (C) 2005-2010 Code Synthesis Tools CC\n" "//\n" "// This program was generated by CodeSynthesis XSD, an XML Schema\n" "// to C++ data binding compiler, in the Proprietary License mode.\n" "// You should have received a proprietary license from Code Synthesis\n" "// Tools CC prior to generating this code. See the license text for\n" "// conditions.\n" "//\n\n"; Char const copyright_impl[] = "// Not copyrighted - public domain.\n" "//\n" "// This sample parser implementation was generated by CodeSynthesis XSD,\n" "// an XML Schema to C++ data binding compiler. You may use it in your\n" "// programs without any restrictions.\n" "//\n\n"; } namespace Parser { namespace CLI { extern Key type_map = "type-map"; extern Key char_type = "char-type"; extern Key char_encoding = "char-encoding"; extern Key output_dir = "output-dir"; extern Key xml_parser = "xml-parser"; extern Key generate_inline = "generate-inline"; extern Key generate_validation = "generate-validation"; extern Key suppress_validation = "suppress-validation"; extern Key generate_polymorphic = "generate-polymorphic"; extern Key generate_noop_impl = "generate-noop-impl"; extern Key generate_print_impl = "generate-print-impl"; extern Key generate_test_driver = "generate-test-driver"; extern Key force_overwrite = "force-overwrite"; extern Key root_element_first = "root-element-first"; extern Key root_element_last = "root-element-last"; extern Key root_element = "root-element"; extern Key generate_xml_schema = "generate-xml-schema"; extern Key extern_xml_schema = "extern-xml-schema"; extern Key skel_type_suffix = "skel-type-suffix"; extern Key skel_file_suffix = "skel-file-suffix"; extern Key impl_type_suffix = "impl-type-suffix"; extern Key impl_file_suffix = "impl-file-suffix"; extern Key namespace_map = "namespace-map"; extern Key namespace_regex = "namespace-regex"; extern Key namespace_regex_trace = "namespace-regex-trace"; extern Key reserved_name = "reserved-name"; extern Key include_with_brackets = "include-with-brackets"; extern Key include_prefix = "include-prefix"; extern Key include_regex = "include-regex"; extern Key include_regex_trace = "include-regex-trace"; extern Key guard_prefix = "guard-prefix"; extern Key hxx_suffix = "hxx-suffix"; extern Key ixx_suffix = "ixx-suffix"; extern Key cxx_suffix = "cxx-suffix"; extern Key hxx_regex = "hxx-regex"; extern Key ixx_regex = "ixx-regex"; extern Key cxx_regex = "cxx-regex"; extern Key hxx_prologue = "hxx-prologue"; extern Key ixx_prologue = "ixx-prologue"; extern Key cxx_prologue = "cxx-prologue"; extern Key prologue = "prologue"; extern Key hxx_epilogue = "hxx-epilogue"; extern Key ixx_epilogue = "ixx-epilogue"; extern Key cxx_epilogue = "cxx-epilogue"; extern Key epilogue = "epilogue"; extern Key hxx_prologue_file = "hxx-prologue-file"; extern Key ixx_prologue_file = "ixx-prologue-file"; extern Key cxx_prologue_file = "cxx-prologue-file"; extern Key prologue_file = "prologue-file"; extern Key hxx_epilogue_file = "hxx-epilogue-file"; extern Key ixx_epilogue_file = "ixx-epilogue-file"; extern Key cxx_epilogue_file = "cxx-epilogue-file"; extern Key epilogue_file = "epilogue-file"; extern Key export_symbol = "export-symbol"; extern Key export_maps = "export-maps"; extern Key import_maps = "import-maps"; extern Key show_anonymous = "show-anonymous"; extern Key show_sloc = "show-sloc"; extern Key proprietary_license = "proprietary-license"; } } Void Parser::Generator:: usage () { std::wostream& e (wcerr); ::CLI::Indent::Clip< ::CLI::OptionsUsage, WideChar> clip (e); e << "--type-map " << 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 << "--char-encoding " << endl << " Specify the character encoding that should be used\n" << " in the object model. Valid values for the 'char'\n" << " character type are 'utf8' (default), 'iso8859-1',\n" << " 'lcp', and 'custom'. For the 'wchar_t' character\n" << " type the only valid value is 'auto'." << endl; e << "--output-dir " << 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 << "--custom-literals " << endl << " Load custom XML string to C++ literal mappings\n" << " from ." << endl; 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, StringLiteralMap const& string_literal_map, Boolean gen_driver, const WarningSet& disabled_warnings, FileList& file_list, AutoUnlinks& unlinks) { using std::ios_base; namespace Indentation = BackendElements::Indentation; typedef BackendElements::Regex::Expression 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, string_literal_map); } 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, 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, &string_literal_map, &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, &string_literal_map, &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, &string_literal_map, &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, &string_literal_map, &hxx_expr, &ixx_expr, &hxx_impl_expr); String guard (guard_expr.merge (guard_prefix + hxx_impl_name)); guard = ctx.escape (guard); // Make it a C++ id. std::transform (guard.begin (), guard.end(), guard.begin (), upcase); hxx_impl << "#ifndef " << guard << endl << "#define " << guard << endl << endl; { // Set auto-indentation. // Indentation::Clip 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, &string_literal_map, &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, &string_literal_map, &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 (UnrepresentableCharacter const& e) { wcerr << "error: character at position " << e.position () << " " << "in string '" << e.string () << "' is unrepresentable in " << "the target encoding" << endl; wcerr << "info: use the --custom-literals option to provide custom " << "string literals mapping" << endl; throw Failed (); } catch (NoNamespaceMapping const& e) { wcerr << e.file () << ":" << e.line () << ":" << e.column () << ": error: unable to map XML Schema namespace '" << e.ns () << "' to C++ namespace" << endl; wcerr << e.file () << ":" << e.line () << ":" << e.column () << ": info: use the --namespace-map or --namespace-regex option " << "to provide custom mapping" << endl; throw Failed (); } catch (InvalidNamespaceMapping const& e) { wcerr << "error: invalid XML to C++ namespace mapping specified: " << "'" << e.mapping () << "': " << e.reason () << endl; throw Failed (); } catch (BackendElements::Regex::Format 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 (); } } }