1 // file : xsd/cxx/parser/generator.cxx 2 // copyright : Copyright (c) 2005-2017 Code Synthesis Tools CC 3 // license : GNU GPL v2 + exceptions; see accompanying LICENSE file 4 5 #include <algorithm> 6 #include <iostream> 7 #include <fstream> 8 9 #include <cutl/re.hxx> 10 11 #include <cutl/compiler/code-stream.hxx> 12 #include <cutl/compiler/cxx-indenter.hxx> 13 #include <cutl/compiler/sloc-counter.hxx> 14 15 #include <xsd-frontend/semantic-graph.hxx> 16 17 #include <type-map/lexer.hxx> 18 #include <type-map/parser.hxx> 19 #include <type-map/type-map.hxx> 20 21 #include <cxx/parser/elements.hxx> 22 #include <cxx/parser/generator.hxx> 23 24 #include <cxx/parser/validator.hxx> 25 #include <cxx/parser/name-processor.hxx> 26 #include <cxx/parser/state-processor.hxx> 27 #include <cxx/parser/type-processor.hxx> 28 29 #include <cxx/parser/parser-header.hxx> 30 #include <cxx/parser/parser-inline.hxx> 31 #include <cxx/parser/parser-source.hxx> 32 #include <cxx/parser/parser-forward.hxx> 33 34 #include <cxx/parser/impl-header.hxx> 35 #include <cxx/parser/impl-source.hxx> 36 #include <cxx/parser/driver-source.hxx> 37 38 #include <cxx/parser/element-validation-source.hxx> 39 #include <cxx/parser/attribute-validation-source.hxx> 40 #include <cxx/parser/characters-validation-source.hxx> 41 42 #include <cxx/parser/options.hxx> 43 44 #include "../../../libxsd/xsd/cxx/version.hxx" 45 46 using std::endl; 47 using std::wcerr; 48 using std::wcout; 49 50 using namespace XSDFrontend::SemanticGraph; 51 52 // 53 // 54 typedef std::wifstream WideInputFileStream; 55 typedef std::wofstream WideOutputFileStream; 56 typedef std::ifstream NarrowInputFileStream; 57 58 namespace CXX 59 { 60 namespace 61 { 62 char const copyright_gpl[] = 63 "// Copyright (c) 2005-2017 Code Synthesis Tools CC\n" 64 "//\n" 65 "// This program was generated by CodeSynthesis XSD, an XML Schema to\n" 66 "// C++ data binding compiler.\n" 67 "//\n" 68 "// This program is free software; you can redistribute it and/or modify\n" 69 "// it under the terms of the GNU General Public License version 2 as\n" 70 "// published by the Free Software Foundation.\n" 71 "//\n" 72 "// This program is distributed in the hope that it will be useful,\n" 73 "// but WITHOUT ANY WARRANTY; without even the implied warranty of\n" 74 "// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" 75 "// GNU General Public License for more details.\n" 76 "//\n" 77 "// You should have received a copy of the GNU General Public License\n" 78 "// along with this program; if not, write to the Free Software\n" 79 "// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n" 80 "//\n" 81 "// In addition, as a special exception, Code Synthesis Tools CC gives\n" 82 "// permission to link this program with the Xerces-C++ library (or with\n" 83 "// modified versions of Xerces-C++ that use the same license as Xerces-C++),\n" 84 "// and distribute linked combinations including the two. You must obey\n" 85 "// the GNU General Public License version 2 in all respects for all of\n" 86 "// the code used other than Xerces-C++. If you modify this copy of the\n" 87 "// program, you may extend this exception to your version of the program,\n" 88 "// but you are not obligated to do so. If you do not wish to do so, delete\n" 89 "// this exception statement from your version.\n" 90 "//\n" 91 "// Furthermore, Code Synthesis Tools CC makes a special exception for\n" 92 "// the Free/Libre and Open Source Software (FLOSS) which is described\n" 93 "// in the accompanying FLOSSE file.\n" 94 "//\n\n"; 95 96 char const copyright_proprietary[] = 97 "// Copyright (c) 2005-2017 Code Synthesis Tools CC\n" 98 "//\n" 99 "// This program was generated by CodeSynthesis XSD, an XML Schema\n" 100 "// to C++ data binding compiler, in the Proprietary License mode.\n" 101 "// You should have received a proprietary license from Code Synthesis\n" 102 "// Tools CC prior to generating this code. See the license text for\n" 103 "// conditions.\n" 104 "//\n\n"; 105 106 char const copyright_impl[] = 107 "// Not copyrighted - public domain.\n" 108 "//\n" 109 "// This sample parser implementation was generated by CodeSynthesis XSD,\n" 110 "// an XML Schema to C++ data binding compiler. You may use it in your\n" 111 "// programs without any restrictions.\n" 112 "//\n\n"; 113 } 114 115 void Parser::Generator:: usage()116 usage () 117 { 118 CXX::Parser::options::print_usage (wcout); 119 CXX::options::print_usage (wcout); 120 } 121 122 namespace 123 { 124 template <typename S> 125 void open(S & ifs,NarrowString const & path)126 open (S& ifs, NarrowString const& path) 127 { 128 try 129 { 130 Path fs_path (path); 131 ifs.open (fs_path.string ().c_str (), 132 std::ios_base::in | std::ios_base::binary); 133 134 if (!ifs.is_open ()) 135 { 136 wcerr << path.c_str () << ": error: unable to open in read mode" 137 << endl; 138 139 throw Parser::Generator::Failed (); 140 } 141 } 142 catch (InvalidPath const&) 143 { 144 wcerr << "error: '" << path.c_str () << "' is not a valid " 145 << "filesystem path" << endl; 146 147 throw Parser::Generator::Failed (); 148 } 149 } 150 151 void append(WideOutputFileStream & os,NarrowString const & path,WideInputFileStream & default_is)152 append (WideOutputFileStream& os, 153 NarrowString const& path, 154 WideInputFileStream& default_is) 155 { 156 using std::ios_base; 157 158 if (path) 159 { 160 WideInputFileStream is; 161 open (is, path); 162 os << is.rdbuf (); 163 } 164 else if (default_is.is_open ()) 165 { 166 os << default_is.rdbuf (); 167 default_is.seekg (0, ios_base::beg); 168 } 169 } 170 171 void append(WideOutputFileStream & os,NarrowStrings const & primary,NarrowStrings const & def)172 append (WideOutputFileStream& os, 173 NarrowStrings const& primary, 174 NarrowStrings const& def) 175 { 176 NarrowStrings const& v (primary.empty () ? def : primary); 177 178 for (NarrowStrings::const_iterator i (v.begin ()), e (v.end ()); 179 i != e; ++i) 180 { 181 os << i->c_str () << endl; 182 } 183 } 184 } 185 186 187 size_t Parser::Generator:: generate(Parser::options const & ops,Schema & schema,Path const & file_path,bool fpt,StringLiteralMap const & string_literal_map,bool gen_driver,const WarningSet & disabled_warnings,FileList & file_list,AutoUnlinks & unlinks)188 generate (Parser::options const& ops, 189 Schema& schema, 190 Path const& file_path, 191 bool fpt, 192 StringLiteralMap const& string_literal_map, 193 bool gen_driver, 194 const WarningSet& disabled_warnings, 195 FileList& file_list, 196 AutoUnlinks& unlinks) 197 { 198 using std::ios_base; 199 200 typedef cutl::re::regexsub Regex; 201 202 try 203 { 204 bool generate_xml_schema (ops.generate_xml_schema ()); 205 206 // We could be compiling several schemas at once in which case 207 // handling of the --generate-xml-schema option gets tricky: we 208 // will need to rely on the presence of the --extern-xml-schema 209 // to tell us which (fake) schema file corresponds to XML Schema. 210 // 211 if (generate_xml_schema) 212 { 213 if (NarrowString name = ops.extern_xml_schema ()) 214 { 215 if (file_path.string () != name) 216 generate_xml_schema = false; 217 } 218 } 219 220 bool impl (!generate_xml_schema && 221 (ops.generate_noop_impl () || 222 ops.generate_print_impl ())); 223 224 bool driver (gen_driver && !generate_xml_schema && 225 ops.generate_test_driver ()); 226 227 // Evaluate the graph for possibility of generating something useful. 228 // 229 { 230 Validator validator; 231 if (!validator.validate ( 232 ops, schema, file_path, driver, disabled_warnings)) 233 throw Failed (); 234 } 235 236 // Process names. 237 // 238 { 239 NameProcessor proc; 240 proc.process (ops, schema, file_path, string_literal_map); 241 } 242 243 bool validation ((ops.xml_parser () == "expat" || 244 ops.generate_validation ()) && 245 !ops.suppress_validation ()); 246 247 // Compute state machine info. 248 // 249 if (validation) 250 { 251 StateProcessor proc; 252 proc.process (schema, file_path); 253 } 254 255 // Read-in type maps. 256 // 257 TypeMap::Namespaces type_map; 258 { 259 using namespace TypeMap; 260 261 NarrowStrings const& files (ops.type_map ()); 262 263 for (NarrowStrings::const_iterator f (files.begin ()); 264 f != files.end (); ++f ) 265 { 266 NarrowInputFileStream ifs; 267 open (ifs, *f); 268 269 Lexer l (ifs, *f); 270 TypeMap::Parser p (l, *f); 271 272 if (!p.parse (type_map)) 273 throw Failed (); 274 } 275 276 // Add the built-in mappings at the end. 277 // 278 279 // String-based types. 280 // 281 String char_type (ops.char_type ()); 282 String string_type; 283 284 if (char_type == L"char") 285 string_type = L"::std::string"; 286 else if (char_type == L"wchar_t") 287 string_type = L"::std::wstring"; 288 else 289 string_type = L"::std::basic_string< " + char_type + L" >"; 290 291 String xns; 292 String auto_ptr; 293 { 294 Context ctx (std::wcerr, schema, file_path, ops, 0, 0, 0, 0); 295 xns = ctx.xs_ns_name (); 296 auto_ptr = ctx.auto_ptr; 297 } 298 299 String buffer (auto_ptr + L"< " + xns + L"::buffer >"); 300 TypeMap::Namespace xsd ("http://www\\.w3\\.org/2001/XMLSchema"); 301 302 xsd.types_push_back ("string", string_type); 303 xsd.types_push_back ("normalizedString", string_type); 304 xsd.types_push_back ("token", string_type); 305 xsd.types_push_back ("Name", string_type); 306 xsd.types_push_back ("NMTOKEN", string_type); 307 xsd.types_push_back ("NMTOKENS", xns + L"::string_sequence"); 308 xsd.types_push_back ("NCName", string_type); 309 310 xsd.types_push_back ("ID", string_type); 311 xsd.types_push_back ("IDREF", string_type); 312 xsd.types_push_back ("IDREFS", xns + L"::string_sequence"); 313 314 xsd.types_push_back ("language", string_type); 315 xsd.types_push_back ("anyURI", string_type); 316 xsd.types_push_back ("QName", xns + L"::qname"); 317 318 xsd.types_push_back ("base64Binary", buffer, buffer); 319 xsd.types_push_back ("hexBinary", buffer, buffer); 320 321 xsd.types_push_back ("gDay", xns + L"::gday"); 322 xsd.types_push_back ("gMonth", xns + L"::gmonth"); 323 xsd.types_push_back ("gYear", xns + L"::gyear"); 324 xsd.types_push_back ("gMonthDay", xns + L"::gmonth_day"); 325 xsd.types_push_back ("gYearMonth", xns + L"::gyear_month"); 326 xsd.types_push_back ("date", xns + L"::date"); 327 xsd.types_push_back ("time", xns + L"::time"); 328 xsd.types_push_back ("dateTime", xns + L"::date_time"); 329 xsd.types_push_back ("duration", xns + L"::duration"); 330 331 // Fundamental C++ types. 332 // 333 xsd.types_push_back ("boolean", "bool", "bool"); 334 335 xsd.types_push_back ("byte", "signed char", "signed char"); 336 xsd.types_push_back ("unsignedByte", 337 "unsigned char", 338 "unsigned char"); 339 340 xsd.types_push_back ("short", "short", "short"); 341 xsd.types_push_back ("unsignedShort", 342 "unsigned short", 343 "unsigned short"); 344 345 xsd.types_push_back ("int", "int", "int"); 346 xsd.types_push_back ("unsignedInt", "unsigned int", "unsigned int"); 347 348 xsd.types_push_back ("long", "long long", "long long"); 349 xsd.types_push_back ("unsignedLong", 350 "unsigned long long", 351 "unsigned long long"); 352 353 xsd.types_push_back ("integer", "long long", "long long"); 354 355 xsd.types_push_back ("negativeInteger", "long long", "long long"); 356 xsd.types_push_back ("nonPositiveInteger", "long long", "long long"); 357 358 xsd.types_push_back ("positiveInteger", 359 "unsigned long long", 360 "unsigned long long"); 361 xsd.types_push_back ("nonNegativeInteger", 362 "unsigned long long", 363 "unsigned long long"); 364 365 xsd.types_push_back ("float", "float", "float"); 366 xsd.types_push_back ("double", "double", "double"); 367 xsd.types_push_back ("decimal", "double", "double"); 368 369 type_map.push_back (xsd); 370 371 // Everything else maps to void. 372 // 373 TypeMap::Namespace rest (".*"); 374 rest.types_push_back (".*", "void", "void"); 375 type_map.push_back (rest); 376 } 377 378 // Process types. 379 // 380 { 381 TypeProcessor proc; 382 proc.process (ops, schema, gen_driver, type_map); 383 } 384 385 // 386 // 387 bool inline_ (ops.generate_inline () && !generate_xml_schema); 388 bool source (!generate_xml_schema); 389 390 // Generate code. 391 // 392 NarrowString name (file_path.leaf ().string ()); 393 NarrowString skel_suffix (ops.skel_file_suffix ()); 394 NarrowString impl_suffix (ops.impl_file_suffix ()); 395 396 NarrowString hxx_suffix (ops.hxx_suffix ()); 397 NarrowString ixx_suffix (ops.ixx_suffix ()); 398 NarrowString cxx_suffix (ops.cxx_suffix ()); 399 400 Regex hxx_expr ( 401 ops.hxx_regex ().empty () 402 ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + hxx_suffix + "#" 403 : ops.hxx_regex ()); 404 405 Regex ixx_expr ( 406 ops.ixx_regex ().empty () 407 ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + ixx_suffix + "#" 408 : ops.ixx_regex ()); 409 410 Regex cxx_expr ( 411 ops.cxx_regex ().empty () 412 ? "#^(.+?)(\\.[^./\\\\]+)?$#$1" + skel_suffix + cxx_suffix + "#" 413 : ops.cxx_regex ()); 414 415 416 Regex hxx_impl_expr; 417 Regex cxx_impl_expr; 418 Regex cxx_driver_expr; 419 420 if (impl || driver) 421 { 422 hxx_impl_expr = 423 "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + hxx_suffix + "#"; 424 425 cxx_impl_expr = 426 "#^(.+?)(\\.[^./\\\\]+)?$#$1" + impl_suffix + cxx_suffix + "#"; 427 428 cxx_driver_expr = 429 "#^(.+?)(\\.[^./\\\\]+)?$#$1-driver" + cxx_suffix + "#"; 430 } 431 432 if (!hxx_expr.match (name)) 433 { 434 wcerr << "error: header expression '" << 435 hxx_expr.regex ().str ().c_str () << "' does not match '" << 436 name.c_str () << "'" << endl; 437 throw Failed (); 438 } 439 440 if (inline_ && !ixx_expr.match (name)) 441 { 442 wcerr << "error: inline expression '" << 443 ixx_expr.regex ().str ().c_str () << "' does not match '" << 444 name.c_str () << "'" << endl; 445 throw Failed (); 446 } 447 448 if (source && !cxx_expr.match (name)) 449 { 450 wcerr << "error: source expression '" << 451 cxx_expr.regex ().str ().c_str () << "' does not match '" << 452 name.c_str () << "'" << endl; 453 throw Failed (); 454 } 455 456 if (impl || driver) 457 { 458 if (!hxx_impl_expr.match (name)) 459 { 460 wcerr << "error: implementation header expression '" << 461 hxx_impl_expr.regex ().str ().c_str () << "' does not match '" << 462 name.c_str () << "'" << endl; 463 throw Failed (); 464 } 465 466 if (!cxx_impl_expr.match (name)) 467 { 468 wcerr << "error: implementation source expression '" << 469 cxx_impl_expr.regex ().str ().c_str () << "' does not match '" << 470 name.c_str () << "'" << endl; 471 throw Failed (); 472 } 473 474 if (!cxx_driver_expr.match (name)) 475 { 476 wcerr << "error: driver source expression '" << 477 cxx_driver_expr.regex ().str ().c_str () << "' does not match '" << 478 name.c_str () << "'" << endl; 479 throw Failed (); 480 } 481 } 482 483 NarrowString hxx_name (hxx_expr.replace (name)); 484 NarrowString ixx_name (inline_ ? ixx_expr.replace (name) : NarrowString ()); 485 NarrowString cxx_name (source ? cxx_expr.replace (name) : NarrowString ()); 486 487 NarrowString hxx_impl_name; 488 NarrowString cxx_impl_name; 489 NarrowString cxx_driver_name; 490 491 if (impl || driver) 492 { 493 hxx_impl_name = hxx_impl_expr.replace (name); 494 cxx_impl_name = cxx_impl_expr.replace (name); 495 cxx_driver_name = cxx_driver_expr.replace (name); 496 } 497 498 Path hxx_path (hxx_name); 499 Path ixx_path (ixx_name); 500 Path cxx_path (cxx_name); 501 502 Path hxx_impl_path; 503 Path cxx_impl_path; 504 Path cxx_driver_path; 505 506 if (impl || driver) 507 { 508 hxx_impl_path = Path (hxx_impl_name); 509 cxx_impl_path = Path (cxx_impl_name); 510 cxx_driver_path = Path (cxx_driver_name); 511 } 512 513 Path out_dir; 514 515 if (NarrowString dir = ops.output_dir ()) 516 { 517 try 518 { 519 out_dir = Path (dir); 520 } 521 catch (InvalidPath const&) 522 { 523 wcerr << dir.c_str () << ": error: invalid path" << endl; 524 throw Failed (); 525 } 526 } 527 528 if (fpt && !generate_xml_schema) 529 { 530 // In the file-per-type mode the schema files are always local 531 // unless the user added the directory so that we propagate this 532 // to the output files. 533 // 534 Path fpt_dir (file_path.directory ()); 535 536 if (!fpt_dir.empty ()) 537 out_dir /= fpt_dir; 538 } 539 540 if (!out_dir.empty ()) 541 { 542 hxx_path = out_dir / hxx_path; 543 ixx_path = out_dir / ixx_path; 544 cxx_path = out_dir / cxx_path; 545 546 if (impl || driver) 547 { 548 hxx_impl_path = out_dir / hxx_impl_path; 549 cxx_impl_path = out_dir / cxx_impl_path; 550 cxx_driver_path = out_dir /cxx_driver_path; 551 } 552 } 553 554 // Open the impl files first so that if open fails, the skel files 555 // are not deleted. 556 // 557 WideOutputFileStream hxx_impl; 558 WideOutputFileStream cxx_impl; 559 WideOutputFileStream cxx_driver; 560 561 if (impl) 562 { 563 if (!ops.force_overwrite ()) 564 { 565 WideInputFileStream tmp ( 566 hxx_impl_path.string ().c_str (), ios_base::in); 567 568 if (tmp.is_open ()) 569 { 570 wcerr << hxx_impl_path << ": error: cowardly refusing to " << 571 "overwrite an existing file" << endl; 572 throw Failed (); 573 } 574 575 tmp.close (); 576 } 577 578 hxx_impl.open (hxx_impl_path.string ().c_str (), ios_base::out); 579 580 if (!hxx_impl.is_open ()) 581 { 582 wcerr << hxx_impl_path << ": error: unable to open in write mode" 583 << endl; 584 throw Failed (); 585 } 586 587 unlinks.add (hxx_impl_path); 588 file_list.push_back (hxx_impl_path.string ()); 589 590 if (!ops.force_overwrite ()) 591 { 592 WideInputFileStream tmp ( 593 cxx_impl_path.string ().c_str (), ios_base::in); 594 595 if (tmp.is_open ()) 596 { 597 wcerr << cxx_impl_path << ": error: cowardly refusing to " << 598 "overwrite an existing file" << endl; 599 throw Failed (); 600 } 601 602 tmp.close (); 603 } 604 605 cxx_impl.open (cxx_impl_path.string ().c_str (), ios_base::out); 606 607 if (!cxx_impl.is_open ()) 608 { 609 wcerr << cxx_impl_path << ": error: unable to open in write mode" 610 << endl; 611 throw Failed (); 612 } 613 614 unlinks.add (cxx_impl_path); 615 file_list.push_back (cxx_impl_path.string ()); 616 } 617 618 if (driver) 619 { 620 if (!ops.force_overwrite ()) 621 { 622 WideInputFileStream tmp ( 623 cxx_driver_path.string ().c_str (), ios_base::in); 624 625 if (tmp.is_open ()) 626 { 627 wcerr << cxx_driver_path << ": error: cowardly refusing to " << 628 "overwrite an existing file" << endl; 629 throw Failed (); 630 } 631 632 tmp.close (); 633 } 634 635 cxx_driver.open (cxx_driver_path.string ().c_str (), ios_base::out); 636 637 if (!cxx_driver.is_open ()) 638 { 639 wcerr << cxx_driver_path << ": error: unable to open in write " << 640 "mode" << endl; 641 throw Failed (); 642 } 643 644 unlinks.add (cxx_driver_path); 645 file_list.push_back (cxx_driver_path.string ()); 646 } 647 648 // Open the skel files. 649 // 650 WideOutputFileStream hxx (hxx_path.string ().c_str (), ios_base::out); 651 WideOutputFileStream ixx; 652 WideOutputFileStream cxx; 653 654 if (!hxx.is_open ()) 655 { 656 wcerr << hxx_path << ": error: unable to open in write mode" << endl; 657 throw Failed (); 658 } 659 660 unlinks.add (hxx_path); 661 file_list.push_back (hxx_path.string ()); 662 663 if (inline_) 664 { 665 ixx.open (ixx_path.string ().c_str (), ios_base::out); 666 667 if (!ixx.is_open ()) 668 { 669 wcerr << ixx_path << ": error: unable to open in write mode" << endl; 670 throw Failed (); 671 } 672 673 unlinks.add (ixx_path); 674 file_list.push_back (ixx_path.string ()); 675 } 676 677 678 if (source) 679 { 680 cxx.open (cxx_path.string ().c_str (), ios_base::out); 681 682 if (!cxx.is_open ()) 683 { 684 wcerr << cxx_path << ": error: unable to open in write mode" << endl; 685 throw Failed (); 686 } 687 688 unlinks.add (cxx_path); 689 file_list.push_back (cxx_path.string ()); 690 } 691 692 // Print copyright and license. 693 // 694 char const* copyright ( 695 ops.proprietary_license () ? copyright_proprietary : copyright_gpl); 696 697 hxx << copyright; 698 699 if (inline_) 700 ixx << copyright; 701 702 if (source) 703 cxx << copyright; 704 705 if (impl) 706 { 707 hxx_impl << copyright_impl; 708 cxx_impl << copyright_impl; 709 } 710 711 if (driver) 712 cxx_driver << copyright_impl; 713 714 // Prologue. 715 // 716 WideInputFileStream prologue; 717 { 718 NarrowString name (ops.prologue_file ()); 719 720 if (name) 721 open (prologue, name); 722 } 723 724 // Epilogue. 725 // 726 WideInputFileStream epilogue; 727 { 728 NarrowString name (ops.epilogue_file ()); 729 730 if (name) 731 open (epilogue, name); 732 } 733 734 // SLOC counter. 735 // 736 size_t sloc_total (0); 737 bool show_sloc (ops.show_sloc ()); 738 739 typedef 740 compiler::ostream_filter<compiler::cxx_indenter, wchar_t> 741 ind_filter; 742 743 typedef 744 compiler::ostream_filter<compiler::sloc_counter, wchar_t> 745 sloc_filter; 746 747 // 748 // 749 Regex guard_expr ("/([a-z])([A-Z])/$1_$2/"); // Split words. 750 751 NarrowString guard_prefix (ops.guard_prefix ()); 752 753 if (!guard_prefix) 754 guard_prefix = file_path.directory ().string (); 755 756 if (guard_prefix) 757 guard_prefix += '_'; 758 759 // HXX 760 // 761 { 762 Context ctx (hxx, 763 schema, 764 file_path, 765 ops, 766 &string_literal_map, 767 &hxx_expr, 768 &ixx_expr, 769 &hxx_impl_expr); 770 771 sloc_filter sloc (hxx); 772 773 String guard (guard_expr.replace (guard_prefix + hxx_name)); 774 guard = ctx.escape (guard); // Make it a C++ id. 775 std::transform (guard.begin (), guard.end(), guard.begin (), upcase); 776 777 hxx << "#ifndef " << guard << endl 778 << "#define " << guard << endl 779 << endl; 780 781 if (ctx.std >= cxx_version::cxx11) 782 { 783 hxx << "#ifndef XSD_CXX11" << endl 784 << "#define XSD_CXX11" << endl 785 << "#endif" << endl 786 << endl; 787 } 788 789 // Copy prologue. 790 // 791 hxx << "// Begin prologue." << endl 792 << "//" << endl; 793 794 append (hxx, ops.hxx_prologue (), ops.prologue ()); 795 append (hxx, ops.hxx_prologue_file (), prologue); 796 797 hxx << "//" << endl 798 << "// End prologue." << endl 799 << endl; 800 801 // Version check. 802 // 803 hxx << "#include <xsd/cxx/config.hxx>" << endl 804 << endl 805 << "#if (XSD_INT_VERSION != " << XSD_INT_VERSION << "L)" << endl 806 << "#error XSD runtime version mismatch" << endl 807 << "#endif" << endl 808 << endl; 809 810 hxx << "#include <xsd/cxx/pre.hxx>" << endl 811 << endl; 812 813 // Generate. 814 // 815 { 816 ind_filter ind (hxx); // We don't want to indent prologues/epilogues. 817 818 if (!generate_xml_schema) 819 generate_parser_forward (ctx); 820 821 generate_parser_header (ctx, generate_xml_schema); 822 } 823 824 if (inline_) 825 hxx << "#include " << ctx.process_include_path (ixx_name) << endl; 826 827 hxx << "#include <xsd/cxx/post.hxx>" << endl 828 << endl; 829 830 // Copy epilogue. 831 // 832 hxx << "// Begin epilogue." << endl 833 << "//" << endl; 834 835 append (hxx, ops.hxx_epilogue_file (), epilogue); 836 append (hxx, ops.hxx_epilogue (), ops.epilogue ()); 837 838 hxx << "//" << endl 839 << "// End epilogue." << endl 840 << endl; 841 842 hxx << "#endif // " << guard << endl; 843 844 if (show_sloc) 845 wcerr << hxx_path << ": " << sloc.stream ().count () << endl; 846 847 sloc_total += sloc.stream ().count (); 848 } 849 850 851 // IXX 852 // 853 if (inline_) 854 { 855 Context ctx (ixx, 856 schema, 857 file_path, 858 ops, 859 &string_literal_map, 860 &hxx_expr, 861 &ixx_expr, 862 &hxx_impl_expr); 863 864 sloc_filter sloc (ixx); 865 866 // Copy prologue. 867 // 868 ixx << "// Begin prologue." << endl 869 << "//" << endl; 870 871 append (ixx, ops.ixx_prologue (), ops.prologue ()); 872 append (ixx, ops.ixx_prologue_file (), prologue); 873 874 ixx << "//" << endl 875 << "// End prologue." << endl 876 << endl; 877 878 // Generate. 879 // 880 { 881 ind_filter ind (ixx); // We don't want to indent prologues/epilogues. 882 generate_parser_inline (ctx); 883 } 884 885 // Copy epilogue. 886 // 887 ixx << "// Begin epilogue." << endl 888 << "//" << endl; 889 890 append (ixx, ops.ixx_epilogue_file (), epilogue); 891 append (ixx, ops.ixx_epilogue (), ops.epilogue ()); 892 893 ixx << "//" << endl 894 << "// End epilogue." << endl 895 << endl; 896 897 if (show_sloc) 898 wcerr << ixx_path << ": " << sloc.stream ().count () << endl; 899 900 sloc_total += sloc.stream ().count (); 901 } 902 903 904 // CXX 905 // 906 if (source) 907 { 908 Context ctx (cxx, 909 schema, 910 file_path, 911 ops, 912 &string_literal_map, 913 &hxx_expr, 914 &ixx_expr, 915 &hxx_impl_expr); 916 917 sloc_filter sloc (cxx); 918 919 // Copy prologue. 920 // 921 cxx << "// Begin prologue." << endl 922 << "//" << endl; 923 924 append (cxx, ops.cxx_prologue (), ops.prologue ()); 925 append (cxx, ops.cxx_prologue_file (), prologue); 926 927 cxx << "//" << endl 928 << "// End prologue." << endl 929 << endl; 930 931 cxx << "#include <xsd/cxx/pre.hxx>" << endl 932 << endl; 933 934 cxx << "#include " << ctx.process_include_path (hxx_name) << endl 935 << endl; 936 937 // Generate. 938 // 939 { 940 ind_filter ind (cxx); // We don't want to indent prologues/epilogues. 941 942 if (!inline_) 943 generate_parser_inline (ctx); 944 945 generate_parser_source (ctx); 946 947 if (validation) 948 { 949 generate_element_validation_source (ctx); 950 generate_attribute_validation_source (ctx); 951 generate_characters_validation_source (ctx); 952 } 953 } 954 955 cxx << "#include <xsd/cxx/post.hxx>" << endl 956 << endl; 957 958 // Copy epilogue. 959 // 960 cxx << "// Begin epilogue." << endl 961 << "//" << endl; 962 963 append (cxx, ops.cxx_epilogue_file (), epilogue); 964 append (cxx, ops.cxx_epilogue (), ops.epilogue ()); 965 966 cxx << "//" << endl 967 << "// End epilogue." << endl 968 << endl; 969 970 if (show_sloc) 971 wcerr << cxx_path << ": " << sloc.stream ().count () << endl; 972 973 sloc_total += sloc.stream ().count (); 974 } 975 976 // HXX impl 977 // 978 if (impl) 979 { 980 Context ctx (hxx_impl, 981 schema, 982 file_path, 983 ops, 984 &string_literal_map, 985 &hxx_expr, 986 &ixx_expr, 987 &hxx_impl_expr); 988 989 String guard (guard_expr.replace (guard_prefix + hxx_impl_name)); 990 guard = ctx.escape (guard); // Make it a C++ id. 991 std::transform (guard.begin (), guard.end(), guard.begin (), upcase); 992 993 hxx_impl << "#ifndef " << guard << endl 994 << "#define " << guard << endl 995 << endl; 996 997 hxx_impl << "#include " << ctx.process_include_path (hxx_name) 998 << endl << endl; 999 1000 { 1001 ind_filter ind (hxx_impl); 1002 generate_impl_header (ctx); 1003 } 1004 1005 hxx_impl << "#endif // " << guard << endl; 1006 } 1007 1008 // CXX impl 1009 // 1010 if (impl) 1011 { 1012 Context ctx (cxx_impl, 1013 schema, 1014 file_path, 1015 ops, 1016 &string_literal_map, 1017 &hxx_expr, 1018 &ixx_expr, 1019 &hxx_impl_expr); 1020 1021 cxx_impl << "#include " << ctx.process_include_path (hxx_impl_name) 1022 << endl << endl; 1023 1024 { 1025 ind_filter ind (cxx_impl); 1026 generate_impl_source (ctx); 1027 } 1028 } 1029 1030 // CXX driver 1031 // 1032 if (driver) 1033 { 1034 Context ctx (cxx_driver, 1035 schema, 1036 file_path, 1037 ops, 1038 &string_literal_map, 1039 &hxx_expr, 1040 &ixx_expr, 1041 &hxx_impl_expr); 1042 1043 cxx_driver << "#include " << ctx.process_include_path (hxx_impl_name) 1044 << endl << endl; 1045 1046 { 1047 ind_filter ind (cxx_driver); 1048 generate_driver_source (ctx); 1049 } 1050 } 1051 1052 return sloc_total; 1053 } 1054 catch (UnrepresentableCharacter const& e) 1055 { 1056 wcerr << "error: character at position " << e.position () << " " 1057 << "in string '" << e.string () << "' is unrepresentable in " 1058 << "the target encoding" << endl; 1059 1060 wcerr << "info: use the --custom-literals option to provide custom " 1061 << "string literals mapping" << endl; 1062 1063 throw Failed (); 1064 } 1065 catch (NoNamespaceMapping const& e) 1066 { 1067 wcerr << e.file () << ":" << e.line () << ":" << e.column () 1068 << ": error: unable to map XML Schema namespace '" << e.ns () 1069 << "' to C++ namespace" << endl; 1070 1071 wcerr << e.file () << ":" << e.line () << ":" << e.column () 1072 << ": info: use the --namespace-map or --namespace-regex option " 1073 << "to provide custom mapping" << endl; 1074 1075 throw Failed (); 1076 } 1077 catch (InvalidNamespaceMapping const& e) 1078 { 1079 wcerr << "error: invalid XML to C++ namespace mapping specified: " 1080 << "'" << e.mapping () << "': " << e.reason () << endl; 1081 1082 throw Failed (); 1083 } 1084 catch (cutl::re::format const& e) 1085 { 1086 wcerr << "error: invalid regex: '" << 1087 e.regex ().c_str () << "': " << 1088 e.description ().c_str () << endl; 1089 1090 throw Failed (); 1091 } 1092 catch (cutl::re::wformat const& e) 1093 { 1094 wcerr << "error: invalid regex: '" << 1095 e.regex () << "': " << e.description ().c_str () << endl; 1096 1097 throw Failed (); 1098 } 1099 } 1100 } 1101