/*============================================================================= Copyright (c) 2002 2004 2006 Joel de Guzman Copyright (c) 2004 Eric Niebler http://spirit.sourceforge.net/ Use, modification and distribution is subject to the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #include "grammar.hpp" #include "quickbook.hpp" #include "state.hpp" #include "actions.hpp" #include "post_process.hpp" #include "utils.hpp" #include "files.hpp" #include "native_text.hpp" #include "document_state.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(_WIN32) #include #include #endif #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)) #pragma warning(disable:4355) #endif #define QUICKBOOK_VERSION "Quickbook Version 1.6.1 beta 1" namespace quickbook { namespace cl = boost::spirit::classic; namespace fs = boost::filesystem; tm* current_time; // the current time tm* current_gm_time; // the current UTC time bool debug_mode; // for quickbook developers only bool self_linked_headers; bool ms_errors = false; // output errors/warnings as if for VS std::vector include_path; std::vector preset_defines; fs::path image_location; static void set_macros(quickbook::state& state) { for(std::vector::const_iterator it = preset_defines.begin(), end = preset_defines.end(); it != end; ++it) { boost::string_ref val(*it); parse_iterator first(val.begin()); parse_iterator last(val.end()); cl::parse_info info = cl::parse(first, last, state.grammar().command_line_macro); if (!info.full) { detail::outerr() << "Error parsing command line definition: '" << *it << "'" << std::endl; ++state.error_count; } } } /////////////////////////////////////////////////////////////////////////// // // Parse a file // /////////////////////////////////////////////////////////////////////////// void parse_file(quickbook::state& state, value include_doc_id, bool nested_file) { parse_iterator first(state.current_file->source().begin()); parse_iterator last(state.current_file->source().end()); cl::parse_info info = cl::parse(first, last, state.grammar().doc_info); assert(info.hit); if (!state.error_count) { parse_iterator pos = info.stop; std::string doc_type = pre(state, pos, include_doc_id, nested_file); info = cl::parse(info.hit ? info.stop : first, last, state.grammar().block_start); post(state, doc_type); if (!info.full) { file_position const& pos = state.current_file->position_of(info.stop.base()); detail::outerr(state.current_file->path, pos.line) << "Syntax Error near column " << pos.column << ".\n"; ++state.error_count; } } } struct parse_document_options { parse_document_options() : indent(-1), linewidth(-1), pretty_print(true), deps_out_flags(quickbook::dependency_tracker::default_) {} int indent; int linewidth; bool pretty_print; fs::path deps_out; quickbook::dependency_tracker::flags deps_out_flags; fs::path locations_out; fs::path xinclude_base; }; static int parse_document( fs::path const& filein_ , fs::path const& fileout_ , parse_document_options const& options_) { string_stream buffer; document_state output; int result = 0; try { quickbook::state state(filein_, options_.xinclude_base, buffer, output); set_macros(state); if (state.error_count == 0) { state.dependencies.add_dependency(filein_); state.current_file = load(filein_); // Throws load_error parse_file(state); if(state.error_count) { detail::outerr() << "Error count: " << state.error_count << ".\n"; } } result = state.error_count ? 1 : 0; if (!options_.deps_out.empty()) { state.dependencies.write_dependencies(options_.deps_out, options_.deps_out_flags); } if (!options_.locations_out.empty()) { fs::ofstream out(options_.locations_out); state.dependencies.write_dependencies(options_.locations_out, dependency_tracker::checked); } } catch (load_error& e) { detail::outerr(filein_) << e.what() << std::endl; result = 1; } catch (std::runtime_error& e) { detail::outerr() << e.what() << std::endl; result = 1; } if (!fileout_.empty() && result == 0) { std::string stage2 = output.replace_placeholders(buffer.str()); fs::ofstream fileout(fileout_); if (fileout.fail()) { ::quickbook::detail::outerr() << "Error opening output file " << fileout_ << std::endl; return 1; } if (options_.pretty_print) { try { fileout << post_process(stage2, options_.indent, options_.linewidth); } catch (quickbook::post_process_failure&) { // fallback! ::quickbook::detail::outerr() << "Post Processing Failed." << std::endl; fileout << stage2; return 1; } } else { fileout << stage2; } if (fileout.fail()) { ::quickbook::detail::outerr() << "Error writing to output file " << fileout_ << std::endl; return 1; } } return result; } } /////////////////////////////////////////////////////////////////////////// // // Main program // /////////////////////////////////////////////////////////////////////////// int main(int argc, char* argv[]) { try { namespace fs = boost::filesystem; namespace po = boost::program_options; using boost::program_options::options_description; using boost::program_options::variables_map; using boost::program_options::store; using boost::program_options::parse_command_line; using boost::program_options::wcommand_line_parser; using boost::program_options::command_line_parser; using boost::program_options::notify; using boost::program_options::positional_options_description; using quickbook::detail::command_line_string; // First thing, the filesystem should record the current working directory. fs::initial_path(); // Various initialisation methods quickbook::detail::initialise_output(); quickbook::detail::initialise_markups(); // Declare the program options options_description desc("Allowed options"); options_description hidden("Hidden options"); options_description all("All options"); #if QUICKBOOK_WIDE_PATHS #define PO_VALUE po::wvalue #else #define PO_VALUE po::value #endif desc.add_options() ("help", "produce help message") ("version", "print version string") ("no-pretty-print", "disable XML pretty printing") ("no-self-linked-headers", "stop headers linking to themselves") ("indent", PO_VALUE(), "indent spaces") ("linewidth", PO_VALUE(), "line width") ("input-file", PO_VALUE(), "input file") ("output-file", PO_VALUE(), "output file") ("output-deps", PO_VALUE(), "output dependency file") ("debug", "debug mode (for developers)") ("ms-errors", "use Microsoft Visual Studio style error & warn message format") ("include-path,I", PO_VALUE< std::vector >(), "include path") ("define,D", PO_VALUE< std::vector >(), "define macro") ("image-location", PO_VALUE(), "image location") ; hidden.add_options() ("expect-errors", "Succeed if the input file contains a correctly handled " "error, fail otherwise.") ("xinclude-base", PO_VALUE(), "Generate xincludes as if generating for this target " "directory.") ("output-deps-format", PO_VALUE(), "Comma separated list of formatting options for output-deps, " "options are: escaped, checked") ("output-checked-locations", PO_VALUE(), "Writes a file listing all the file locations that were " "checked, starting with '+' if they were found, or '-' " "if they weren't.\n" "This is deprecated, use 'output-deps-format=checked' to " "write the deps file in this format.") ; all.add(desc).add(hidden); positional_options_description p; p.add("input-file", -1); // Read option from the command line variables_map vm; #if QUICKBOOK_WIDE_PATHS quickbook::ignore_variable(&argc); quickbook::ignore_variable(&argv); int wide_argc; LPWSTR* wide_argv = CommandLineToArgvW(GetCommandLineW(), &wide_argc); if (!wide_argv) { quickbook::detail::outerr() << "Error getting argument values." << std::endl; return 1; } store( wcommand_line_parser(wide_argc, wide_argv) .options(all) .positional(p) .run(), vm); LocalFree(wide_argv); #else store(command_line_parser(argc, argv) .options(all) .positional(p) .run(), vm); #endif notify(vm); // Process the command line options quickbook::parse_document_options parse_document_options; bool expect_errors = vm.count("expect-errors"); int error_count = 0; if (vm.count("help")) { std::ostringstream description_text; description_text << desc; quickbook::detail::out() << description_text.str() << "\n"; return 0; } if (vm.count("version")) { std::string boost_version = BOOST_LIB_VERSION; boost::replace(boost_version, '_', '.'); quickbook::detail::out() << QUICKBOOK_VERSION << " (Boost " << boost_version << ")" << std::endl; return 0; } if (vm.count("ms-errors")) quickbook::ms_errors = true; if (vm.count("no-pretty-print")) parse_document_options.pretty_print = false; quickbook::self_linked_headers = !vm.count("no-self-link-headers"); if (vm.count("indent")) parse_document_options.indent = vm["indent"].as(); if (vm.count("linewidth")) parse_document_options.linewidth = vm["linewidth"].as(); if (vm.count("debug")) { static tm timeinfo; timeinfo.tm_year = 2000 - 1900; timeinfo.tm_mon = 12 - 1; timeinfo.tm_mday = 20; timeinfo.tm_hour = 12; timeinfo.tm_min = 0; timeinfo.tm_sec = 0; timeinfo.tm_isdst = -1; mktime(&timeinfo); quickbook::current_time = &timeinfo; quickbook::current_gm_time = &timeinfo; quickbook::debug_mode = true; } else { time_t t = std::time(0); static tm lt = *localtime(&t); static tm gmt = *gmtime(&t); quickbook::current_time = < quickbook::current_gm_time = &gmt; quickbook::debug_mode = false; } quickbook::include_path.clear(); if (vm.count("include-path")) { boost::transform( vm["include-path"].as >(), std::back_inserter(quickbook::include_path), quickbook::detail::command_line_to_path); } quickbook::preset_defines.clear(); if (vm.count("define")) { boost::transform( vm["define"].as >(), std::back_inserter(quickbook::preset_defines), quickbook::detail::command_line_to_utf8); } if (vm.count("input-file")) { fs::path filein = quickbook::detail::command_line_to_path( vm["input-file"].as()); fs::path fileout; bool default_output = true; if (vm.count("output-deps")) { parse_document_options.deps_out = quickbook::detail::command_line_to_path( vm["output-deps"].as()); default_output = false; } if (vm.count("output-deps-format")) { std::string format_flags = quickbook::detail::command_line_to_utf8( vm["output-deps-format"].as()); std::vector flag_names; boost::algorithm::split(flag_names, format_flags, boost::algorithm::is_any_of(", "), boost::algorithm::token_compress_on); unsigned flags = 0; BOOST_FOREACH(std::string const& flag, flag_names) { if (flag == "checked") { flags |= quickbook::dependency_tracker::checked; } else if (flag == "escaped") { flags |= quickbook::dependency_tracker::escaped; } else if (!flag.empty()) { quickbook::detail::outerr() << "Unknown dependency format flag: " << flag <()); default_output = false; } if (vm.count("output-file")) { fileout = quickbook::detail::command_line_to_path( vm["output-file"].as()); } else if (default_output) { fileout = filein; fileout.replace_extension(".xml"); } if (vm.count("xinclude-base")) { parse_document_options.xinclude_base = quickbook::detail::command_line_to_path( vm["xinclude-base"].as()); } else { parse_document_options.xinclude_base = fileout.parent_path(); if (parse_document_options.xinclude_base.empty()) parse_document_options.xinclude_base = "."; } if (!fs::is_directory(parse_document_options.xinclude_base)) { quickbook::detail::outerr() << (vm.count("xinclude-base") ? "xinclude-base is not a directory" : "parent directory not found for output file"); ++error_count; } if (vm.count("image-location")) { quickbook::image_location = quickbook::detail::command_line_to_path( vm["image-location"].as()); } else { quickbook::image_location = filein.parent_path() / "html"; } if (!fileout.empty()) { quickbook::detail::out() << "Generating Output File: " << fileout << std::endl; } if (!error_count) error_count += quickbook::parse_document( filein, fileout, parse_document_options); if (expect_errors) { if (!error_count) quickbook::detail::outerr() << "No errors detected for --expect-errors." << std::endl; return !error_count; } else { return error_count; } } else { std::ostringstream description_text; description_text << desc; quickbook::detail::outerr() << "No filename given\n\n" << description_text.str() << std::endl; return 1; } } catch(std::exception& e) { quickbook::detail::outerr() << e.what() << "\n"; return 1; } catch(...) { quickbook::detail::outerr() << "Exception of unknown type caught\n"; return 1; } return 0; }