diff --git a/src/Jamfile.v2 b/src/Jamfile.v2 index 2d03196..90f6772 100644 --- a/src/Jamfile.v2 +++ b/src/Jamfile.v2 @@ -8,6 +8,8 @@ # http://www.boost.org/LICENSE_1_0.txt) #============================================================================== +import os ; + project quickbook : requirements gcc:300 @@ -16,6 +18,11 @@ project quickbook darwin:-g0 ; +if [ os.name ] = NT +{ + lib shell32 ; +} + exe quickbook : quickbook.cpp @@ -50,4 +57,5 @@ exe quickbook msvc:/wd4800 msvc:_CRT_SECURE_NO_DEPRECATE msvc:_SCL_SECURE_NO_DEPRECATE + NT:shell32 ; diff --git a/src/actions.cpp b/src/actions.cpp index 5d6fab3..307e97a 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -20,6 +20,7 @@ #include "markups.hpp" #include "actions_class.hpp" #include "grammar.hpp" +#include "input_path.hpp" namespace quickbook { @@ -51,18 +52,19 @@ namespace quickbook { if(!actions.output_pre(phrase)) return; - position const pos = first.get_position(); - detail::outwarn(pos.file,pos.line) << "in column:" << pos.column << ", " + file_position const pos = first.get_position(); + detail::outwarn(actions.filename, pos.line) + << "in column:" << pos.column << ", " << "[br] and \\n are deprecated" << ".\n"; phrase << break_mark; } void error_action::operator()(iterator first, iterator /*last*/) const { - position const pos = first.get_position(); - detail::outerr(pos.file,pos.line) + file_position const pos = first.get_position(); + detail::outerr(actions.filename, pos.line) << "Syntax Error near column " << pos.column << ".\n"; - ++error_count; + ++actions.error_count; } void tagged_action::operator()(std::string const& str) const @@ -306,10 +308,10 @@ namespace quickbook if (mark != list_marks.top().first) // new_indent == list_indent { - position const pos = first.get_position(); - detail::outerr(pos.file,pos.line) + file_position const pos = first.get_position(); + detail::outerr(actions.filename, pos.line) << "Illegal change of list style near column " << pos.column << ".\n"; - detail::outwarn(pos.file,pos.line) + detail::outwarn(actions.filename, pos.line) << "Ignoring change of list style" << std::endl; ++error_count; } @@ -327,11 +329,11 @@ namespace quickbook void unexpected_char::operator()(iterator first, iterator last) const { - position const pos = first.get_position(); + file_position const pos = first.get_position(); - detail::outwarn(pos.file, pos.line) + detail::outwarn(actions.filename, pos.line) << "in column:" << pos.column - << ", unexpected character: " << std::string(first, last) + << ", unexpected character: " << detail::utf8(first, last) << "\n"; // print out an unexpected character @@ -402,9 +404,8 @@ namespace quickbook if (program.size() == 0) return; // Nothing left to do here. The program is empty. - iterator first_(program.begin(), program.end()); - iterator last_(program.end(), program.end()); - first_.set_position(first.get_position()); + iterator first_(program.begin(), first.get_position()); + iterator last_(program.end()); // TODO: Shouldn't phrase be empty here? Why would it be output // after the code block? @@ -489,14 +490,14 @@ namespace quickbook void attribute_action::operator()(iterator first, iterator last) const { - position const pos = first.get_position(); + file_position const pos = first.get_position(); if (!attributes.insert( attribute_map::value_type(attribute_name, std::string(first, last)) ).second) { - detail::outwarn(pos.file,pos.line) - << "Repeated attribute: " << attribute_name << ".\n"; + detail::outwarn(actions.filename, pos.line) + << "Repeated attribute: " << detail::utf8(attribute_name) << ".\n"; } } @@ -504,17 +505,38 @@ namespace quickbook { if(!actions.output_pre(phrase)) return; - fs::path const img_path(image_fileref); - + // Find the file basename and extension. + // + // Not using Boost.Filesystem because I want to stay in UTF-8. + // Need to think about uri encoding. + + std::string::size_type pos; + std::string stem,extension; + + pos = image_fileref.rfind('/'); + stem = pos == std::string::npos ? + image_fileref : + image_fileref.substr(pos + 1); + + pos = stem.rfind('.'); + if (pos != std::string::npos) + { + extension = stem.substr(pos + 1); + stem = stem.substr(0, pos); + } + + // Extract the alt tag, to use as a text description. + // Or if there isn't one, use the stem of the file name. + // TODO: IMO if there isn't an alt tag, then the description should + // be empty or missing. + attribute_map::iterator it = attributes.find("alt"); - std::string alt_text = it != attributes.end() ? - it->second : - img_path.stem().generic_string(); + std::string alt_text = it != attributes.end() ? it->second : stem; attributes.erase("alt"); attributes.insert(attribute_map::value_type("fileref", image_fileref)); - if(img_path.extension() == ".svg") + if(extension == ".svg") { // // SVG's need special handling: @@ -531,11 +553,12 @@ namespace quickbook // // Image paths are relative to the html subdirectory: // - fs::path img; - if(img_path.root_path().empty()) - img = "html" / img_path; // relative path - else - img = img_path; // absolute path + // TODO: This seems wrong to me. + // + fs::path img = detail::generic_to_path(image_fileref); + if(img.root_path().empty()) + img = "html" / img; // relative path + // // Now load the SVG file: // @@ -599,8 +622,8 @@ namespace quickbook phrase << ">"; - // Also add a textobject -- use the basename of the image file. - // This will mean we get "alt" attributes of the HTML img. + // Add a textobject containing the alt tag from earlier. + // This will be used for the alt tag in html. phrase << ""; detail::print_string(alt_text, phrase.get()); phrase << ""; @@ -630,13 +653,18 @@ namespace quickbook { if(actions.suppress) return; if (!actions.templates.add( - template_symbol(actions.template_identifier, actions.template_info, - std::string(first, last), first.get_position(), - actions.template_block, &actions.templates.top_scope()))) + template_symbol( + actions.template_identifier, + actions.template_info, + std::string(first, last), + actions.filename, + first.get_position(), + actions.template_block, + &actions.templates.top_scope()))) { - position const pos = first.get_position(); - detail::outerr(pos.file,pos.line) - << "Template Redefinition: " << actions.template_identifier << std::endl; + file_position const pos = first.get_position(); + detail::outerr(actions.filename, pos.line) + << "Template Redefinition: " << detail::utf8(actions.template_identifier) << std::endl; ++actions.error_count; } @@ -704,7 +732,8 @@ namespace quickbook bool break_arguments( std::vector& args , std::vector const& params - , position const& pos + , fs::path const& filename + , file_position const& pos ) { // Quickbook 1.4-: If there aren't enough parameters seperated by @@ -725,9 +754,8 @@ namespace quickbook // arguments, or if there are no more spaces left. template_body& body = args.back(); - iterator begin(body.content.begin(), body.content.end(), - position(body.position.file.c_str(), body.position.line, body.position.column)); - iterator end(body.content.end(), body.content.end()); + iterator begin(body.content.begin(), body.position); + iterator end(body.content.end()); iterator l_pos = find_first_seperator(begin, end); if (l_pos == end) @@ -738,7 +766,7 @@ namespace quickbook while(r_pos != end && std::find(whitespace, whitespace_end, *r_pos) != whitespace_end) ++r_pos; if (r_pos == end) break; - template_body second(std::string(r_pos, end), r_pos.get_position(), false); + template_body second(std::string(r_pos, end), body.filename, r_pos.get_position(), false); body.content = std::string(begin, l_pos); args.push_back(second); } @@ -746,7 +774,7 @@ namespace quickbook if (args.size() != params.size()) { - detail::outerr(pos.file, pos.line) + detail::outerr(filename, pos.line) << "Invalid number of arguments passed. Expecting: " << params.size() << " argument(s), got: " @@ -763,7 +791,7 @@ namespace quickbook std::vector& args , std::vector const& params , template_scope const& scope - , position const& pos + , file_position const& pos , quickbook::actions& actions ) { @@ -777,9 +805,9 @@ namespace quickbook { if (!actions.templates.add( template_symbol(*tpl, empty_params, arg->content, - arg->position, arg->is_block, &scope))) + arg->filename, arg->position, arg->is_block, &scope))) { - detail::outerr(pos.file,pos.line) + detail::outerr(actions.filename, pos.line) << "Duplicate Symbol Found" << std::endl; ++actions.error_count; return std::make_pair(false, tpl); @@ -814,9 +842,10 @@ namespace quickbook if (!body.is_block) { // do a phrase level parse - iterator first(body.content.begin(), body.content.end(), - position(body.position.file.c_str(), body.position.line, body.position.column)); - iterator last(body.content.end(), body.content.end()); + actions.filename = body.filename; + iterator first(body.content.begin(), body.position); + iterator last(body.content.end()); + return cl::parse(first, last, actions.grammar().simple_phrase).full; } else @@ -825,10 +854,11 @@ namespace quickbook // ensure that we have enough trailing newlines to eliminate // the need to check for end of file in the grammar. + actions.filename = body.filename; std::string content = body.content + "\n\n"; - iterator first(content.begin(), content.end(), - position(body.position.file.c_str(), body.position.line, body.position.column)); - iterator last(content.end(), content.end()); + iterator first(content.begin(), body.position); + iterator last(content.end()); + return cl::parse(first, last, actions.grammar().block).full; } } @@ -847,6 +877,7 @@ namespace quickbook actions.template_args.push_back( template_body( std::string(first, last), + actions.filename, first.get_position(), actions.template_block)); } @@ -861,12 +892,12 @@ namespace quickbook std::string identifier; std::swap(args, actions.template_args); std::swap(identifier, actions.template_identifier); - position const pos = first.get_position(); + file_position const pos = first.get_position(); ++actions.template_depth; if (actions.template_depth > actions.max_template_depth) { - detail::outerr(pos.file,pos.line) + detail::outerr(actions.filename, pos.line) << "Infinite loop detected" << std::endl; --actions.template_depth; ++actions.error_count; @@ -906,7 +937,7 @@ namespace quickbook { // Break the arguments for a template - if (!break_arguments(args, symbol->params, pos)) + if (!break_arguments(args, symbol->params, actions.filename, pos)) { actions.pop(); // restore the actions' states --actions.template_depth; @@ -918,7 +949,7 @@ namespace quickbook { if (!args.empty()) { - detail::outerr(pos.file, pos.line) + detail::outerr(actions.filename, pos.line) << "Arguments for code snippet." <"; code += "'''"; - args.push_back(template_body(code, first.get_position(), false)); + args.push_back(template_body(code, actions.filename, pos, false)); } } @@ -963,14 +994,14 @@ namespace quickbook if (!parse_template(symbol->body, actions.template_escape, actions)) { - position const pos = first.get_position(); - detail::outerr(pos.file,pos.line) + file_position const pos = first.get_position(); + detail::outerr(actions.filename, pos.line) << "Expanding " << (symbol->body.is_block ? "block" : "phrase") - << " template: " << symbol->identifier << std::endl + << " template: " << detail::utf8(symbol->identifier) << std::endl << std::endl << "------------------begin------------------" << std::endl - << symbol->body.content + << detail::utf8(symbol->body.content) << "------------------end--------------------" << std::endl << std::endl; actions.pop(); // restore the actions' states @@ -981,9 +1012,9 @@ namespace quickbook if (actions.section_level != actions.min_section_level) { - position const pos = first.get_position(); - detail::outerr(pos.file,pos.line) - << "Mismatched sections in template " << identifier << std::endl; + file_position const pos = first.get_position(); + detail::outerr(actions.filename, pos.line) + << "Mismatched sections in template " << detail::utf8(identifier) << std::endl; actions.pop(); // restore the actions' states --actions.template_depth; ++actions.error_count; @@ -1012,10 +1043,10 @@ namespace quickbook if(!r) { - detail::outerr(c.position.file, c.position.line) + detail::outerr(c.filename, c.position.line) << "Expanding callout." << std::endl << "------------------begin------------------" << std::endl - << c.content + << detail::utf8(c.content) << std::endl << "------------------end--------------------" << std::endl ; @@ -1241,8 +1272,8 @@ namespace quickbook if (section_level <= min_section_level) { - position const pos = first.get_position(); - detail::outerr(pos.file,pos.line) + file_position const pos = first.get_position(); + detail::outerr(actions.filename, pos.line) << "Mismatched [endsect] near column " << pos.column << ".\n"; ++error_count; @@ -1266,8 +1297,8 @@ namespace quickbook void element_id_warning_action::operator()(iterator first, iterator) const { - position const pos = first.get_position(); - detail::outwarn(pos.file,pos.line) << "Empty id.\n"; + file_position const pos = first.get_position(); + detail::outwarn(actions.filename, pos.line) << "Empty id.\n"; } fs::path path_difference(fs::path const& outdir, fs::path const& path) @@ -1293,7 +1324,7 @@ namespace quickbook { // Given a source file and the current filename, calculate the // path to the source file relative to the output directory. - fs::path path(std::string(first, last)); + fs::path path = detail::generic_to_path(std::string(first, last)); if (!path.is_complete()) { fs::path infile = fs::absolute(actions.filename).normalize(); @@ -1330,9 +1361,8 @@ namespace quickbook } // Search in each of the include path locations. - BOOST_FOREACH(std::string const & p, include_path) + BOOST_FOREACH(fs::path full, include_path) { - fs::path full(p); full /= path; if (fs::exists(full)) { @@ -1361,9 +1391,8 @@ namespace quickbook ts.parent = &actions.templates.top_scope(); if (!actions.templates.add(ts)) { - cl::file_position const pos = ts.body.position; - detail::outerr(pos.file, pos.line) - << "Template Redefinition: " << tname << std::endl; + detail::outerr(ts.body.filename, ts.body.position.line) + << "Template Redefinition: " << detail::utf8(tname) << std::endl; ++actions.error_count; } } @@ -1414,7 +1443,8 @@ namespace quickbook } // update the __FILENAME__ macro - *boost::spirit::classic::find(actions.macro, "__FILENAME__") = actions.filename.string(); + *boost::spirit::classic::find(actions.macro, "__FILENAME__") + = detail::path_to_generic(actions.filename); // parse the file quickbook::parse_file(actions.filename.string().c_str(), actions, true); diff --git a/src/actions.hpp b/src/actions.hpp index 6417f20..b4ad1fd 100644 --- a/src/actions.hpp +++ b/src/actions.hpp @@ -125,13 +125,12 @@ namespace quickbook { // Prints an error message to std::cerr - error_action( - int& error_count) - : error_count(error_count) {} + error_action(quickbook::actions& actions) + : actions(actions) {} void operator()(iterator first, iterator /*last*/) const; - int& error_count; + quickbook::actions& actions; }; struct tagged_action @@ -397,12 +396,16 @@ namespace quickbook { // Handles unexpected chars in c++ syntax - unexpected_char(collector& out) - : out(out) {} + unexpected_char( + collector& out + , quickbook::actions& actions) + : out(out) + , actions(actions) {} void operator()(iterator first, iterator last) const; collector& out; + quickbook::actions& actions; }; struct anchor_action @@ -523,16 +526,16 @@ namespace quickbook attribute_action( attribute_map& attributes , std::string& attribute_name - , int& error_count) + , quickbook::actions& actions) : attributes(attributes) , attribute_name(attribute_name) - , error_count(error_count) {} + , actions(actions) {} void operator()(iterator first, iterator last) const; attribute_map& attributes; std::string& attribute_name; - int& error_count; + quickbook::actions& actions; }; struct image_action @@ -826,7 +829,12 @@ namespace quickbook struct element_id_warning_action { - void operator()(iterator first, iterator last) const; + element_id_warning_action(quickbook::actions& actions_) + : actions(actions_) {} + + void operator()(iterator first, iterator last) const; + + quickbook::actions& actions; }; struct xinclude_action diff --git a/src/actions_class.cpp b/src/actions_class.cpp index 58d57eb..031cd94 100644 --- a/src/actions_class.cpp +++ b/src/actions_class.cpp @@ -12,6 +12,7 @@ #include "markups.hpp" #include "quickbook.hpp" #include "grammar.hpp" +#include "input_path.hpp" #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310)) #pragma warning(disable:4355) @@ -19,7 +20,7 @@ namespace quickbook { - actions::actions(char const* filein_, fs::path const& outdir_, string_stream& out_) + actions::actions(fs::path const& filein_, fs::path const& outdir_, string_stream& out_) : grammar_() // header info @@ -44,7 +45,7 @@ namespace quickbook , list_buffer() // state - , filename(fs::absolute(fs::path(filein_))) + , filename(fs::absolute(filein_)) , outdir(outdir_) , macro_change_depth(0) , macro() @@ -77,7 +78,7 @@ namespace quickbook , suppress(false) // actions - , error(error_count) + , error(*this) , extract_doc_title(doc_title, phrase, *this) , extract_doc_license(doc_license, phrase, *this) , extract_doc_purpose(doc_purpose, phrase, *this) @@ -117,7 +118,7 @@ namespace quickbook , plain_char(phrase, *this) , raw_char(phrase, *this) , escape_unicode(phrase, *this) - , attribute(attributes, attribute_name, error_count) + , attribute(attributes, attribute_name, *this) , image(phrase, attributes, image_fileref, *this) , cond_phrase_pre(condition, macro) , scoped_cond_phrase(*this) @@ -192,6 +193,7 @@ namespace quickbook , begin_section(out, phrase, doc_id, section_id, section_level, qualified_section_id, element_id, *this) , end_section(out, section_level, min_section_level, qualified_section_id, error_count, *this) + , element_id_warning(*this) , xinclude(out, *this) , include(*this) , import(out, *this) @@ -206,7 +208,7 @@ namespace quickbook // turn off __FILENAME__ macro on debug mode = true std::string filename_str = debug_mode ? std::string("NO_FILENAME_MACRO_GENERATED_IN_DEBUG_MODE") : - filename.string(); + detail::path_to_generic(filename); // add the predefined macros macro.add diff --git a/src/actions_class.hpp b/src/actions_class.hpp index d764a97..57bd619 100644 --- a/src/actions_class.hpp +++ b/src/actions_class.hpp @@ -22,7 +22,7 @@ namespace quickbook struct actions { - actions(char const* filein_, fs::path const& outdir, string_stream& out_); + actions(fs::path const& filein_, fs::path const& outdir, string_stream& out_); private: boost::scoped_ptr grammar_; diff --git a/src/code_snippet.cpp b/src/code_snippet.cpp index 01091ce..19d5e97 100644 --- a/src/code_snippet.cpp +++ b/src/code_snippet.cpp @@ -22,10 +22,12 @@ namespace quickbook struct code_snippet_actions { code_snippet_actions(std::vector& storage, + std::string const& filename, std::string const& doc_id, char const* source_type) : callout_id(0) , storage(storage) + , filename(filename) , doc_id(doc_id) , source_type(source_type) {} @@ -63,6 +65,7 @@ namespace quickbook std::string code; std::string id; std::vector& storage; + fs::path filename; std::string const doc_id; char const* const source_type; }; @@ -271,13 +274,13 @@ namespace quickbook if (err != 0) return err; // return early on error - iterator first(code.begin(), code.end(), file.c_str()); - iterator last(code.end(), code.end()); + iterator first(code.begin()); + iterator last(code.end()); size_t fname_len = file.size(); bool is_python = fname_len >= 3 && file[--fname_len]=='y' && file[--fname_len]=='p' && file[--fname_len]=='.'; - code_snippet_actions a(storage, doc_id, is_python ? "[python]" : "[c++]"); + code_snippet_actions a(storage, file, doc_id, is_python ? "[python]" : "[c++]"); // TODO: Should I check that parse succeeded? if(is_python) { boost::spirit::classic::parse(first, last, python_code_snippet_grammar(a)); @@ -346,7 +349,7 @@ namespace quickbook code += "``[[callout" + boost::lexical_cast(callout_id) + "]]``"; snippet_stack.top().callouts.push_back( - template_body(std::string(first, last), first.get_position(), true)); + template_body(std::string(first, last), filename, first.get_position(), true)); ++callout_id; } @@ -400,7 +403,7 @@ namespace quickbook } // TODO: Save position in start_snippet - template_symbol symbol(snippet.id, params, body, first.get_position(), true); + template_symbol symbol(snippet.id, params, body, filename, first.get_position(), true); symbol.callout = true; symbol.callouts = snippet.callouts; storage.push_back(symbol); diff --git a/src/doc_info_actions.cpp b/src/doc_info_actions.cpp index 2a4c81e..6a880d2 100644 --- a/src/doc_info_actions.cpp +++ b/src/doc_info_actions.cpp @@ -13,6 +13,7 @@ #include #include "quickbook.hpp" #include "utils.hpp" +#include "input_path.hpp" #include "actions_class.hpp" namespace quickbook @@ -77,7 +78,7 @@ namespace quickbook qbk_major_version = 1; qbk_minor_version = 1; qbk_version_n = 101; - detail::outwarn(actions.filename.string(),1) + detail::outwarn(actions.filename,1) << "Warning: Quickbook version undefined. " "Version 1.1 is assumed" << std::endl; } @@ -89,13 +90,13 @@ namespace quickbook if (qbk_version_n == 106) { - detail::outwarn(actions.filename.string(),1) + detail::outwarn(actions.filename,1) << "Quickbook 1.6 is still under development and is " "likely to change in the future." << std::endl; } else if(qbk_version_n < 100 || qbk_version_n > 106) { - detail::outerr(actions.filename.string(),1) + detail::outerr(actions.filename,1) << "Unknown version of quickbook: quickbook " << qbk_major_version << "." @@ -121,11 +122,11 @@ namespace quickbook if(!invalid_attributes.empty()) { - detail::outwarn(actions.filename.string(),1) + detail::outwarn(actions.filename,1) << (invalid_attributes.size() > 1 ? "Invalid attributes" : "Invalid attribute") - << " for '" << actions.doc_type << " document info': " - << boost::algorithm::join(invalid_attributes, ", ") + << " for '" << detail::utf8(actions.doc_type) << " document info': " + << detail::utf8(boost::algorithm::join(invalid_attributes, ", ")) << "\n" ; } diff --git a/src/fwd.hpp b/src/fwd.hpp index e98e15d..1e0926e 100644 --- a/src/fwd.hpp +++ b/src/fwd.hpp @@ -11,18 +11,14 @@ #if !defined(BOOST_SPIRIT_FWD_HPP) #define BOOST_SPIRIT_FWD_HPP -#include -#include -#include +#include "iterator.hpp" namespace quickbook { struct actions; struct quickbook_grammar; - typedef boost::spirit::classic::file_position_base position; - typedef boost::spirit::classic::position_iterator< - std::string::const_iterator, position> iterator; + typedef position_iterator iterator; } #endif diff --git a/src/input_path.cpp b/src/input_path.cpp index 287eaae..67da796 100644 --- a/src/input_path.cpp +++ b/src/input_path.cpp @@ -7,68 +7,240 @@ =============================================================================*/ #include +#include #include "input_path.hpp" +#include "utils.hpp" -#if !(defined(__cygwin__) || defined(__CYGWIN__)) +#if QUICKBOOK_WIDE_PATHS || QUICKBOOK_WIDE_STREAMS +#include +#include +#include +#include +#endif -// Everything but cygwin - -namespace quickbook { namespace detail -{ - void validate(boost::any& v, - const std::vector& values, - input_path*, int) - { - std::string path - = boost::program_options::validators::get_single_string(values); - - v = input_path(path); - } -}} - -#else - -// Cygwin 1.7.x - -#include +#if QUICKBOOK_CYGWIN_PATHS #include #include -#include #include - -namespace quickbook { namespace detail -{ - void validate(boost::any& v, - const std::vector& values, - input_path*, int) - { - std::string path - = boost::program_options::validators::get_single_string(values); - -#if defined(BOOST_WINDOWS_PATH) - cygwin_conv_path_t flags = CCP_POSIX_TO_WIN_A | CCP_RELATIVE; -#elif defined(BOOST_POSIX_PATH) - cygwin_conv_path_t flags = CCP_WIN_A_TO_POSIX | CCP_RELATIVE; -#else -# error "Boost filesystem path type doesn't seem to be set." #endif +namespace quickbook { + extern bool ms_errors; +} + +namespace quickbook { +namespace detail { + +// This is used for converting paths to UTF-8 on cygin. +// Might be better not to use a windows +#if QUICKBOOK_WIDE_PATHS || QUICKBOOK_WIDE_STREAMS + namespace { + std::string to_utf8(std::wstring const& x) + { + int buffer_count = WideCharToMultiByte(CP_UTF8, 0, x.c_str(), -1, 0, 0, 0, 0); + + if (!buffer_count) + throw conversion_error("Error converting wide string to utf-8."); + + boost::scoped_ptr buffer(new char[buffer_count]); + + if (!WideCharToMultiByte(CP_UTF8, 0, x.c_str(), -1, buffer.get(), buffer_count, 0, 0)) + throw conversion_error("Error converting wide string to utf-8."); + + return std::string(buffer.get()); + } + + std::wstring from_utf8(std::string const& x) + { + int buffer_count = MultiByteToWideChar(CP_UTF8, 0, x.c_str(), -1, 0, 0); + + if (!buffer_count) + throw conversion_error("Error converting utf-8 to wide string."); + + boost::scoped_ptr buffer(new wchar_t[buffer_count]); + + if (!MultiByteToWideChar(CP_UTF8, 0, x.c_str(), -1, buffer.get(), buffer_count)) + throw conversion_error("Error converting utf-8 to wide string."); + + return std::wstring(buffer.get()); + } + } +#endif + +#if QUICKBOOK_WIDE_PATHS + std::string input_to_utf8(input_string const& x) + { + return to_utf8(x); + } +#else + std::string input_to_utf8(input_string const& x) + { + return x; + } +#endif + +#if QUICKBOOK_WIDE_PATHS + fs::path generic_to_path(std::string const& x) + { + return fs::path(from_utf8(x)); + } + + std::string path_to_generic(fs::path const& x) + { + return to_utf8(x.generic_wstring()); + } +#else + fs::path generic_to_path(std::string const& x) + { + return fs::path(x); + } + + std::string path_to_generic(fs::path const& x) + { + return x.generic_string(); + } + +#endif + +#if QUICKBOOK_CYGWIN_PATHS + fs::path input_to_path(input_string const& path) + { + cygwin_conv_path_t flags = CCP_POSIX_TO_WIN_W | CCP_RELATIVE; + ssize_t size = cygwin_conv_path(flags, path.c_str(), NULL, 0); - if (size < 0) { - throw boost::program_options::validation_error( - boost::program_options::validation_error::invalid_option_value); - } + if (size < 0) + throw conversion_error("Error converting cygwin path to windows."); + + // TODO: size is in bytes. + boost::scoped_array result(new wchar_t[size]); + + if(cygwin_conv_path(flags, path.c_str(), result.get(), size)) + throw conversion_error("Error converting cygwin path to windows."); + + return fs::path(result.get()); + } + + stream_string path_to_stream(fs::path const& path) + { + cygwin_conv_path_t flags = CCP_WIN_W_TO_POSIX | CCP_RELATIVE; + + ssize_t size = cygwin_conv_path(flags, path.native().c_str(), NULL, 0); + + if (size < 0) + throw conversion_error("Error converting windows path to cygwin."); boost::scoped_array result(new char[size]); - if(cygwin_conv_path(flags, path.c_str(), result.get(), size)) { - throw boost::program_options::validation_error( - boost::program_options::validation_error::invalid_option_value); - } + if(cygwin_conv_path(flags, path.native().c_str(), result.get(), size)) + throw conversion_error("Error converting windows path to cygwin."); - v = input_path(result.get()); + return std::string(result.get()); + } +#else + fs::path input_to_path(input_string const& path) + { + return fs::path(path); + } + +#if QUICKBOOK_WIDE_PATHS && !QUICKBOOK_WIDE_STREAMS + stream_string path_to_stream(fs::path const& path) + { + return path.string(); + } +#else + stream_string path_to_stream(fs::path const& path) + { + return path.native(); + } +#endif + +#endif // QUICKBOOK_CYGWIN_PATHS + +#if QUICKBOOK_WIDE_STREAMS + + void initialise_output() + { + if (_isatty(_fileno(stdout))) _setmode(_fileno(stdout), _O_U16TEXT); + if (_isatty(_fileno(stderr))) _setmode(_fileno(stderr), _O_U16TEXT); + } + + void write_utf8(ostream& out, std::string const& x) + { + out << from_utf8(x); + } + + ostream& out() + { + return std::wcout; + } + + namespace + { + inline ostream& error_stream() + { + return std::wcerr; + } + } + +#else + + void initialise_output() + { + } + + void write_utf8(ostream& out, std::string const& x) + { + out << x; + } + + ostream& out() + { + return std::cout; + } + + namespace + { + inline ostream& error_stream() + { + return std::clog; + } } -}} #endif + + ostream& outerr() + { + return error_stream() << "Error: "; + } + + ostream& outerr(fs::path const& file, int line) + { + if (line >= 0) + { + if (ms_errors) + return error_stream() << path_to_stream(file) << "(" << line << "): error: "; + else + return error_stream() << path_to_stream(file) << ":" << line << ": error: "; + } + else + { + return error_stream() << path_to_stream(file) << ": error: "; + } + } + + ostream& outwarn(fs::path const& file, int line) + { + if (line >= 0) + { + if (ms_errors) + return error_stream() << path_to_stream(file) << "(" << line << "): warning: "; + else + return error_stream() << path_to_stream(file) << ":" << line << ": warning: "; + } + else + { + return error_stream() << path_to_stream(file) << ": warning: "; + } + } +}} diff --git a/src/input_path.hpp b/src/input_path.hpp index 91badca..0ecc6f1 100644 --- a/src/input_path.hpp +++ b/src/input_path.hpp @@ -9,31 +9,112 @@ #if !defined(BOOST_QUICKBOOK_DETAIL_INPUT_PATH_HPP) #define BOOST_QUICKBOOK_DETAIL_INPUT_PATH_HPP -#include -#include +#include +#include #include +#include +#include -namespace quickbook { namespace detail +#if defined(__cygwin__) || defined(__CYGWIN__) +# define QUICKBOOK_CYGWIN_PATHS 1 +#elif defined(_WIN32) +# define QUICKBOOK_WIDE_PATHS 1 +# if defined(BOOST_MSVC) && BOOST_MSVC >= 1400 +# define QUICKBOOK_WIDE_STREAMS 1 +# endif +#endif + +#if !defined(QUICKBOOK_WIDE_PATHS) +#define QUICKBOOK_WIDE_PATHS 0 +#endif + +#if !defined(QUICKBOOK_WIDE_STREAMS) +#define QUICKBOOK_WIDE_STREAMS 0 +#endif + +#if !defined(QUICKBOOK_CYGWIN_PATHS) +#define QUICKBOOK_CYGWIN_PATHS 0 +#endif + +namespace quickbook { - // Use this class with Boost.Program Options to convert paths to the format - // the Boost.Filesystem expects. This is needed on cygwin to convert cygwin - // paths to windows paths (or vice versa, depending on how filesystem is set - // up). - // - // Note that we don't want to convert paths in quickbook files, as they - // should be platform independent, and aren't necessarily relative to the - // current directory. + namespace fs = boost::filesystem; - class input_path { - std::string path_; - public: - explicit input_path(char const* c) : path_(c) {} - explicit input_path(std::string const& c) : path_(c) {} - operator std::string() const { return path_; } + namespace detail + { + struct conversion_error : std::runtime_error + { + conversion_error(char const* m) : std::runtime_error(m) {} + }; - friend void validate(boost::any&, const std::vector&, - input_path*, int); - }; -}} + // 'generic': Paths in quickbook source and the generated boostbook. + // Always UTF-8. + // 'input': Paths (or other parameters) from the command line and + // possibly other sources in the future. Wide strings on + // normal windows, UTF-8 for cygwin and other platforms + // (hopefully). + // 'stream': Strings to be written to a stream. + // 'path': Stored as a boost::filesystem::path. Since + // Boost.Filesystem doesn't support cygwin, this + // is always wide on windows. UTF-8 on other + // platforms (again, hopefully). + +#if QUICKBOOK_WIDE_PATHS + typedef std::wstring input_string; +#else + typedef std::string input_string; +#endif + +#if QUICKBOOK_WIDE_STREAMS + typedef std::wostream ostream; + typedef std::wstring stream_string; +#else + typedef std::ostream ostream; + typedef std::string stream_string; +#endif + + std::string input_to_utf8(input_string const&); + fs::path input_to_path(input_string const&); + stream_string path_to_stream(fs::path const&); + + std::string path_to_generic(fs::path const&); + fs::path generic_to_path(std::string const&); + + void initialise_output(); + + ostream& out(); + + // Preformats an error/warning message so that it can be parsed by + // common IDEs. Uses the ms_errors global to determine if VS format + // or GCC format. Returns the stream to continue ouput of the verbose + // error message. + ostream& outerr(); + ostream& outerr(fs::path const& file, int line = -1); + ostream& outwarn(fs::path const& file, int line = -1); + + struct utf8_proxy + { + std::string const& value; + + explicit utf8_proxy(std::string const& v) : value(v) {} + }; + + void write_utf8(ostream& out, std::string const&); + + inline ostream& operator<<(ostream& out, utf8_proxy const& p) { + write_utf8(out, p.value); + return out; + } + + inline utf8_proxy utf8(std::string const& value) { + return utf8_proxy(value); + } + + template + inline utf8_proxy utf8(It begin, It end) { + return utf8_proxy(std::string(begin, end)); + } + } +} #endif diff --git a/src/iterator.hpp b/src/iterator.hpp new file mode 100644 index 0000000..6d5192b --- /dev/null +++ b/src/iterator.hpp @@ -0,0 +1,93 @@ +/*============================================================================= + Copyright (c) 2010 Daniel James + + 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) +=============================================================================*/ + +#if !defined(BOOST_SPIRIT_QUICKBOOK_ITERATOR_HPP) +#define BOOST_SPIRIT_QUICKBOOK_ITERATOR_HPP + +#include +#include + +namespace quickbook +{ + struct file_position + { + file_position() : line(1), column(1) {} + file_position(int l, int c) : line(l), column(c) {} + + int line; + int column; + }; + + template + struct position_iterator + : boost::forward_iterator_helper< + position_iterator, + typename boost::iterator_value::type, + typename boost::iterator_difference::type, + typename boost::iterator_pointer::type, + typename boost::iterator_reference::type + > + { + position_iterator() {} + explicit position_iterator(Iterator base) + : base_(base), previous_('\0'), position_() {} + explicit position_iterator(Iterator base, file_position const& position) + : base_(base), previous_('\0'), position_(position) {} + + friend bool operator==( + position_iterator const& x, + position_iterator const& y) + { + return x.base_ == y.base_; + } + + position_iterator& operator++() + { + char val = *base_; + + if (val == '\r') { + ++position_.line; + position_.column = 1; + } + else if (val == '\n') { + if (previous_ != '\r') { + ++position_.line; + position_.column = 1; + } + } + else { + ++position_.column; + } + + previous_ = val; + ++base_; + + return *this; + } + + typename boost::iterator_reference::type operator*() const + { + return *base_; + } + + file_position const& get_position() const { + return position_; + } + + Iterator base() const { + return base_; + } + + private: + Iterator base_; + char previous_; + file_position position_; + }; +} + +#endif diff --git a/src/post_process.cpp b/src/post_process.cpp index 9c98aa2..d8a8dc1 100644 --- a/src/post_process.cpp +++ b/src/post_process.cpp @@ -7,7 +7,7 @@ http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #include "post_process.hpp" -#include "utils.hpp" +#include "input_path.hpp" #include #include #include @@ -444,7 +444,7 @@ namespace quickbook else { // fallback! - ::quickbook::detail::outerr("") + ::quickbook::detail::outerr() << "Warning: Post Processing Failed." << std::endl; out << in; @@ -455,7 +455,7 @@ namespace quickbook catch(...) { // fallback! - ::quickbook::detail::outerr("") + ::quickbook::detail::outerr() << "Post Processing Failed." << std::endl; out << in; diff --git a/src/quickbook.cpp b/src/quickbook.cpp index 7ea4002..c019f0f 100644 --- a/src/quickbook.cpp +++ b/src/quickbook.cpp @@ -13,16 +13,21 @@ #include "post_process.hpp" #include "utils.hpp" #include "input_path.hpp" -#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) @@ -39,7 +44,7 @@ namespace quickbook 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 include_path; std::vector preset_defines; static void set_macros(actions& actor) @@ -49,8 +54,9 @@ namespace quickbook end = preset_defines.end(); it != end; ++it) { - iterator first(it->begin(), it->end(), "command line parameter"); - iterator last(it->end(), it->end()); + // 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? @@ -63,9 +69,8 @@ namespace quickbook // /////////////////////////////////////////////////////////////////////////// int - parse_file(char const* filein_, actions& actor, bool ignore_docinfo) + parse_file(fs::path const& filein_, actions& actor, bool ignore_docinfo) { - using std::cerr; using std::vector; using std::string; @@ -76,8 +81,8 @@ namespace quickbook return err; } - iterator first(storage.begin(), storage.end(), filein_); - iterator last(storage.end(), storage.end()); + iterator first(storage.begin()); + iterator last(storage.end()); cl::parse_info info = cl::parse(first, last, actor.grammar().doc_info); @@ -94,8 +99,8 @@ namespace quickbook if (!info.full) { - position const pos = info.stop.get_position(); - detail::outerr(pos.file,pos.line) + file_position const& pos = info.stop.get_position(); + detail::outerr(actor.filename, pos.line) << "Syntax Error near column " << pos.column << ".\n"; ++actor.error_count; } @@ -104,7 +109,7 @@ namespace quickbook } static int - parse_document(char const* filein_, fs::path const& outdir, string_stream& out, bool ignore_docinfo = false) + parse_document(fs::path const& filein_, fs::path const& outdir, string_stream& out, bool ignore_docinfo = false) { actions actor(filein_, outdir, out); @@ -117,7 +122,7 @@ namespace quickbook if(actor.error_count) { - detail::outerr(filein_) + detail::outerr() << "Error count: " << actor.error_count << ".\n"; } @@ -126,14 +131,14 @@ namespace quickbook static int parse_document( - char const* filein_ - , char const* fileout_ + fs::path const& filein_ + , fs::path const& fileout_ , int indent , int linewidth , bool pretty_print) { int result = 0; - fs::path outdir = fs::path(fileout_).parent_path(); + fs::path outdir = fileout_.parent_path(); if (outdir.empty()) outdir = "."; string_stream buffer; @@ -141,7 +146,7 @@ namespace quickbook if (result == 0) { - std::ofstream fileout(fileout_); + fs::ofstream fileout(fileout_); if (pretty_print) { @@ -166,31 +171,46 @@ 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::value; using boost::program_options::positional_options_description; + + using quickbook::detail::input_string; // First thing, the filesystem should record the current working directory. - boost::filesystem::initial_path(); + 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", value(), "indent spaces") - ("linewidth", value(), "line width") - ("input-file", value(), "input file") - ("output-file", value(), "output file") + ("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", value< std::vector >(), "include path") - ("define,D", value< std::vector >(), "define macro") + ("include-path,I", PO_VALUE< std::vector >(), "include path") + ("define,D", PO_VALUE< std::vector >(), "define macro") ; positional_options_description p; @@ -200,18 +220,39 @@ main(int argc, char* argv[]) 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::cout << desc << "\n"; + std::ostringstream description_text; + description_text << desc; + + quickbook::detail::out() + << quickbook::detail::utf8(description_text.str()) << "\n"; + return 0; } if (vm.count("version")) { - std::cout << QUICKBOOK_VERSION << std::endl; + quickbook::detail::out() << QUICKBOOK_VERSION << std::endl; return 0; } @@ -252,60 +293,67 @@ main(int argc, char* argv[]) quickbook::debug_mode = false; } + quickbook::include_path.clear(); if (vm.count("include-path")) { - std::vector paths - = vm["include-path"].as< - std::vector >(); - quickbook::include_path - = std::vector(paths.begin(), paths.end()); + 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")) { - quickbook::preset_defines - = vm["define"].as >(); + boost::transform( + vm["define"].as >(), + std::back_inserter(quickbook::preset_defines), + quickbook::detail::input_to_utf8); } if (vm.count("input-file")) { - std::string filein - = vm["input-file"].as(); - std::string fileout; + fs::path filein = quickbook::detail::input_to_path( + vm["input-file"].as()); + fs::path fileout; if (vm.count("output-file")) { - fileout = vm["output-file"].as(); + fileout = quickbook::detail::input_to_path( + vm["output-file"].as()); } else { - fileout = quickbook::detail::remove_extension(filein.c_str()); - fileout += ".xml"; + fileout = filein; + fileout.replace_extension(".xml"); } - std::cout << "Generating Output File: " - << fileout + quickbook::detail::out() << "Generating Output File: " + << quickbook::detail::path_to_stream(fileout) << std::endl; - return quickbook::parse_document(filein.c_str(), fileout.c_str(), indent, linewidth, pretty_print); + return quickbook::parse_document(filein, fileout, indent, linewidth, pretty_print); } else { - quickbook::detail::outerr("") << "Error: No filename given\n\n" - << desc << std::endl; + 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("") << "Error: " << e.what() << "\n"; + quickbook::detail::outerr() << quickbook::detail::utf8(e.what()) << "\n"; return 1; } catch(...) { - quickbook::detail::outerr("") << "Error: Exception of unknown type caught\n"; + quickbook::detail::outerr() << "Exception of unknown type caught\n"; return 1; } diff --git a/src/quickbook.hpp b/src/quickbook.hpp index de480ef..36a83c9 100644 --- a/src/quickbook.hpp +++ b/src/quickbook.hpp @@ -15,17 +15,20 @@ #include #include #include +#include #include "fwd.hpp" namespace quickbook { + namespace fs = boost::filesystem; + extern tm* current_time; // the current time extern tm* current_gm_time; // the current UTC time extern bool debug_mode; - extern std::vector include_path; + extern std::vector include_path; extern std::vector preset_defines; - int parse_file(char const* filein_, actions& actor, bool ignore_docinfo = false); + int parse_file(fs::path const& filein_, actions& actor, bool ignore_docinfo = false); } #endif diff --git a/src/syntax_highlight.hpp b/src/syntax_highlight.hpp index 96aa425..264f886 100644 --- a/src/syntax_highlight.hpp +++ b/src/syntax_highlight.hpp @@ -57,7 +57,7 @@ namespace quickbook | char_ [Process("char", self.out)] | number [Process("number", self.out)] | cl::repeat_p(1)[cl::anychar_p] - [Unexpected(self.out)] + [Unexpected(self.out, self.escape_actions)] ) ; @@ -206,7 +206,7 @@ namespace quickbook | string_ [Process("string", self.out)] | number [Process("number", self.out)] | cl::repeat_p(1)[cl::anychar_p] - [Unexpected(self.out)] + [Unexpected(self.out, self.escape_actions)] ) ; diff --git a/src/template_stack.hpp b/src/template_stack.hpp index a343fe9..a776e16 100644 --- a/src/template_stack.hpp +++ b/src/template_stack.hpp @@ -14,41 +14,34 @@ #include #include #include -#include #include #include #include +#include +#include "fwd.hpp" namespace quickbook { + namespace fs = boost::filesystem; + struct template_body { template_body( std::string const& content, - boost::spirit::classic::file_position const& position, + fs::path const& filename, + file_position const& position, bool is_block ) : content(content) + , filename(filename) , position(position) , is_block(is_block) { } - template_body( - std::string const& content, - boost::spirit::classic::file_position_base const& position, - bool is_block - ) - : content(content) - , position(position.file, position.line, position.column) - , is_block(is_block) - { - } - std::string content; - // Note: Using file_position to store the filename after the file - // has been closed. - boost::spirit::classic::file_position position; + fs::path filename; + file_position position; bool is_block; }; @@ -60,26 +53,13 @@ namespace quickbook std::string const& identifier, std::vector const& params, std::string const& body, - boost::spirit::classic::file_position const& position, + fs::path const& filename, + file_position const& position, bool is_block, template_scope const* parent = 0) : identifier(identifier) , params(params) - , body(body, position, is_block) - , parent(parent) - , callout(false) - , callouts() {} - - template_symbol( - std::string const& identifier, - std::vector const& params, - std::string const& body, - boost::spirit::classic::file_position_base const& position, - bool is_block, - template_scope const* parent = 0) - : identifier(identifier) - , params(params) - , body(body, position, is_block) + , body(body, filename, position, is_block) , parent(parent) , callout(false) , callouts() {} diff --git a/src/utils.cpp b/src/utils.cpp index f78e054..bf8f064 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -8,19 +8,17 @@ http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ #include "utils.hpp" +#include "input_path.hpp" #include +#include #include #include #include #include -#include +#include #include -namespace quickbook { - extern bool ms_errors; -} - namespace quickbook { namespace detail { void print_char(char ch, std::ostream& out) @@ -118,21 +116,6 @@ namespace quickbook { namespace detail } } - // remove the extension from a filename - std::string - remove_extension(std::string const& filename) - { - std::string::size_type const n = filename.find_last_of('.'); - if(std::string::npos == n) - { - return filename; - } - else - { - return std::string(filename.begin(), filename.begin()+n); - } - } - std::string escape_uri(std::string uri) { for (std::string::size_type n = 0; n < uri.size(); ++n) @@ -151,36 +134,6 @@ namespace quickbook { namespace detail return uri; } - std::ostream& outerr(std::string const& file, int line) - { - if (line >= 0) - { - if (ms_errors) - return std::clog << file << "(" << line << "): error: "; - else - return std::clog << file << ":" << line << ": error: "; - } - else - { - return std::clog << file << ": error: "; - } - } - - std::ostream& outwarn(std::string const& file, int line) - { - if (line >= 0) - { - if (ms_errors) - return std::clog << file << "(" << line << "): warning: "; - else - return std::clog << file << ":" << line << ": warning: "; - } - else - { - return std::clog << file << ": warning: "; - } - } - // Read the first few bytes in a file to see it starts with a byte order // mark. If it doesn't, then write the characters we've already read in. // Although, given how UTF-8 works, if we've read anything in, the files @@ -238,12 +191,13 @@ namespace quickbook { namespace detail template bool normalize(InputIterator begin, InputIterator end, - OutputIterator out, std::string const& filename) + OutputIterator out, fs::path const& filename) { std::string encoding = read_bom(begin, end, out); if(encoding != "UTF-8" && encoding != "") { - outerr(filename) << encoding << " is not supported. Please use UTF-8." + outerr(filename) << encoding.c_str() + << " is not supported. Please use UTF-8." << std::endl; return false; @@ -263,15 +217,14 @@ namespace quickbook { namespace detail return true; } - int load(std::string const& filename, std::string& storage) + int load(fs::path const& filename, std::string& storage) { - using std::cerr; using std::endl; using std::ios; using std::ifstream; using std::istream_iterator; - ifstream in(filename.c_str(), std::ios_base::in); + fs::ifstream in(filename, std::ios_base::in); if (!in) { diff --git a/src/utils.hpp b/src/utils.hpp index e48a94f..995a76e 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -11,12 +11,16 @@ #define BOOST_SPIRIT_QUICKBOOK_UTILS_HPP #include -#include #include #include #include +#include -namespace quickbook { namespace detail +namespace quickbook { + + namespace fs = boost::filesystem; + +namespace detail { void print_char(char ch, std::ostream& out); void print_string(std::basic_string const& str, std::ostream& out); @@ -54,21 +58,11 @@ namespace quickbook { namespace detail // un-indent a code segment void unindent(std::string& program); - // remove the extension from a filename - std::string remove_extension(std::string const& filename); - std::string escape_uri(std::string uri); - // Preformats an error/warning message so that it can be parsed by - // common IDEs. Uses the ms_errors global to determine if VS format - // or GCC format. Returns the stream to continue ouput of the verbose - // error message. - std::ostream & outerr(std::string const& file, int line = -1); - std::ostream & outwarn(std::string const& file, int line = -1); - // load file into memory with extra trailing newlines to eliminate // the need to check for end of file in the grammar. - int load(std::string const& filename, std::string& storage); + int load(fs::path const& filename, std::string& storage); // given a file extension, return the type of the source file // we'll have an internal database for known file types.