/*============================================================================= 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 "actions_class.hpp" #include "post_process.hpp" #include "utils.hpp" #include "input_path.hpp" #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.5.4" 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 ms_errors = false; // output errors/warnings as if for VS std::vector include_path; std::vector preset_defines; static void set_macros(actions& actor) { for(std::vector::const_iterator it = preset_defines.begin(), end = preset_defines.end(); it != end; ++it) { // TODO: Set filename in actor??? iterator first(it->begin()); iterator last(it->end()); cl::parse(first, last, actor.grammar().command_line_macro); // TODO: Check result? } } /////////////////////////////////////////////////////////////////////////// // // Parse a file // /////////////////////////////////////////////////////////////////////////// int parse_file(fs::path const& filein_, actions& actor, bool ignore_docinfo) { using std::vector; using std::string; std::string storage; int err = detail::load(filein_, storage); if (err != 0) { ++actor.error_count; return err; } iterator first(storage.begin()); iterator last(storage.end()); cl::parse_info info = cl::parse(first, last, actor.grammar().doc_info); if (info.hit || ignore_docinfo) { pre(actor.out, actor, ignore_docinfo); info = cl::parse(info.hit ? info.stop : first, last, actor.grammar().block); if (info.full) { post(actor.out, actor, ignore_docinfo); } } if (!info.full) { file_position const& pos = info.stop.get_position(); detail::outerr(actor.filename, pos.line) << "Syntax Error near column " << pos.column << ".\n"; ++actor.error_count; } return actor.error_count ? 1 : 0; } static int parse_document(fs::path const& filein_, fs::path const& outdir, string_stream& out, bool ignore_docinfo = false) { actions actor(filein_, outdir, out); set_macros(actor); bool r = parse_file(filein_, actor); if (actor.section_level != 0) detail::outwarn(filein_) << "Warning missing [endsect] detected at end of file." << std::endl; if(actor.error_count) { detail::outerr() << "Error count: " << actor.error_count << ".\n"; } return r; } static int parse_document( fs::path const& filein_ , fs::path const& fileout_ , int indent , int linewidth , bool pretty_print) { int result = 0; fs::path outdir = fileout_.parent_path(); if (outdir.empty()) outdir = "."; string_stream buffer; result = parse_document(filein_, outdir, buffer); if (result == 0) { fs::ofstream fileout(fileout_); if (pretty_print) { result = post_process(buffer.str(), fileout, indent, linewidth); } else { fileout << buffer.str(); } } 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::input_string; // First thing, the filesystem should record the current working directory. fs::initial_path(); // Setup out output stream. quickbook::detail::initialise_output(); options_description desc("Allowed 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") ("indent", PO_VALUE(), "indent spaces") ("linewidth", PO_VALUE(), "line width") ("input-file", PO_VALUE(), "input file") ("output-file", PO_VALUE(), "output 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") ; positional_options_description p; p.add("input-file", -1); variables_map vm; int indent = -1; int linewidth = -1; bool pretty_print = true; #if QUICKBOOK_WIDE_PATHS 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(desc).positional(p).run(), vm); LocalFree(wide_argv); #else store(command_line_parser(argc, argv).options(desc).positional(p).run(), vm); #endif notify(vm); if (vm.count("help")) { std::ostringstream description_text; description_text << desc; quickbook::detail::out() << quickbook::detail::utf8(description_text.str()) << "\n"; return 0; } if (vm.count("version")) { quickbook::detail::out() << QUICKBOOK_VERSION << std::endl; return 0; } if (vm.count("ms-errors")) quickbook::ms_errors = true; if (vm.count("no-pretty-print")) pretty_print = false; if (vm.count("indent")) indent = vm["indent"].as(); if (vm.count("linewidth")) 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::input_to_path); } quickbook::preset_defines.clear(); if (vm.count("define")) { boost::transform( vm["define"].as >(), std::back_inserter(quickbook::preset_defines), quickbook::detail::input_to_utf8); } if (vm.count("input-file")) { fs::path filein = quickbook::detail::input_to_path( vm["input-file"].as()); fs::path fileout; if (vm.count("output-file")) { fileout = quickbook::detail::input_to_path( vm["output-file"].as()); } else { fileout = filein; fileout.replace_extension(".xml"); } quickbook::detail::out() << "Generating Output File: " << quickbook::detail::path_to_stream(fileout) << std::endl; return quickbook::parse_document(filein, fileout, indent, linewidth, pretty_print); } else { std::ostringstream description_text; description_text << desc; quickbook::detail::outerr() << "No filename given\n\n" << quickbook::detail::utf8(description_text.str()) << std::endl; return 1; } } catch(std::exception& e) { quickbook::detail::outerr() << quickbook::detail::utf8(e.what()) << "\n"; return 1; } catch(...) { quickbook::detail::outerr() << "Exception of unknown type caught\n"; return 1; } return 0; }