diff --git a/src/Jamfile.v2 b/src/Jamfile.v2 index 8d84712..21e17bf 100644 --- a/src/Jamfile.v2 +++ b/src/Jamfile.v2 @@ -29,7 +29,9 @@ exe quickbook utils.cpp files.cpp native_text.cpp + stream.cpp glob.cpp + path.cpp include_paths.cpp values.cpp document_state.cpp diff --git a/src/actions.cpp b/src/actions.cpp index 06e8070..a83f33a 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -30,11 +30,11 @@ #include "state.hpp" #include "state_save.hpp" #include "grammar.hpp" -#include "native_text.hpp" +#include "stream.hpp" #include "block_tags.hpp" #include "phrase_tags.hpp" #include "document_state.hpp" -#include "include_paths.hpp" +#include "path.hpp" namespace quickbook { diff --git a/src/code_snippet.cpp b/src/code_snippet.cpp index bfbd5e0..b01e3a4 100644 --- a/src/code_snippet.cpp +++ b/src/code_snippet.cpp @@ -18,7 +18,7 @@ #include "state.hpp" #include "values.hpp" #include "files.hpp" -#include "native_text.hpp" +#include "stream.hpp" namespace quickbook { diff --git a/src/dependency_tracker.cpp b/src/dependency_tracker.cpp index 12b2a75..233ffe6 100644 --- a/src/dependency_tracker.cpp +++ b/src/dependency_tracker.cpp @@ -7,7 +7,7 @@ =============================================================================*/ #include "dependency_tracker.hpp" -#include "native_text.hpp" +#include "path.hpp" #include #include #include diff --git a/src/doc_info_actions.cpp b/src/doc_info_actions.cpp index b1e2aa5..494b238 100644 --- a/src/doc_info_actions.cpp +++ b/src/doc_info_actions.cpp @@ -16,11 +16,11 @@ #include "quickbook.hpp" #include "utils.hpp" #include "files.hpp" -#include "native_text.hpp" +#include "stream.hpp" #include "state.hpp" #include "doc_info_tags.hpp" #include "document_state.hpp" -#include "include_paths.hpp" +#include "path.hpp" namespace quickbook { diff --git a/src/include_paths.cpp b/src/include_paths.cpp index c1c0343..c1fd3c9 100644 --- a/src/include_paths.cpp +++ b/src/include_paths.cpp @@ -9,9 +9,10 @@ http://www.boost.org/LICENSE_1_0.txt) =============================================================================*/ -#include "native_text.hpp" +#include "stream.hpp" #include "glob.hpp" #include "include_paths.hpp" +#include "path.hpp" #include "state.hpp" #include "utils.hpp" #include "quickbook.hpp" // For the include_path global (yuck) @@ -324,128 +325,6 @@ namespace quickbook abstract_file_path.parent_path()); } - // Not a general purpose normalization function, just - // from paths from the root directory. It strips the excess - // ".." parts from a path like: "x/../../y", leaving "y". - std::vector normalize_path_from_root(fs::path const& path) - { - assert(!path.has_root_directory() && !path.has_root_name()); - - std::vector parts; - - BOOST_FOREACH(fs::path const& part, path) - { - if (part.empty() || part == ".") { - } - else if (part == "..") { - if (!parts.empty()) parts.pop_back(); - } - else { - parts.push_back(part); - } - } - - return parts; - } - - // The relative path from base to path - fs::path path_difference(fs::path const& base, fs::path const& path) - { - fs::path - absolute_base = fs::absolute(base), - absolute_path = fs::absolute(path); - - // Remove '.', '..' and empty parts from the remaining path - std::vector - base_parts = normalize_path_from_root(absolute_base.relative_path()), - path_parts = normalize_path_from_root(absolute_path.relative_path()); - - std::vector::iterator - base_it = base_parts.begin(), - base_end = base_parts.end(), - path_it = path_parts.begin(), - path_end = path_parts.end(); - - // Build up the two paths in these variables, checking for the first - // difference. - fs::path - base_tmp = absolute_base.root_path(), - path_tmp = absolute_path.root_path(); - - fs::path result; - - // If they have different roots then there's no relative path so - // just build an absolute path. - if (!fs::equivalent(base_tmp, path_tmp)) - { - result = path_tmp; - } - else - { - // Find the point at which the paths differ - for(; base_it != base_end && path_it != path_end; ++base_it, ++path_it) - { - if(!fs::equivalent(base_tmp /= *base_it, path_tmp /= *path_it)) - break; - } - - // Build a relative path to that point - for(; base_it != base_end; ++base_it) result /= ".."; - } - - // Build the rest of our path - for(; path_it != path_end; ++path_it) result /= *path_it; - - return result; - } - - // Convert a Boost.Filesystem path to a URL. - // - // I'm really not sure about this, as the meaning of root_name and - // root_directory are only clear for windows. - // - // Some info on file URLs at: - // https://en.wikipedia.org/wiki/File_URI_scheme - std::string file_path_to_url(fs::path const& x) - { - // TODO: Maybe some kind of error if this doesn't understand the path. - // TODO: Might need a special cygwin implementation. - // TODO: What if x.has_root_name() && !x.has_root_directory()? - // TODO: What does Boost.Filesystem do for '//localhost/c:/path'? - // Is that event allowed by windows? - - if (x.has_root_name()) { - std::string root_name = detail::path_to_generic(x.root_name()); - - if (root_name.size() > 2 && root_name[0] == '/' && root_name[1] == '/') { - // root_name is a network location. - return "file:" + detail::escape_uri(detail::path_to_generic(x)); - } - else if (root_name.size() >= 2 && root_name[root_name.size() - 1] == ':') { - // root_name is a drive. - return "file:///" - + detail::escape_uri(root_name.substr(0, root_name.size() - 1)) - + ":/" // TODO: Or maybe "|/". - + detail::escape_uri(detail::path_to_generic(x.relative_path())); - } - else { - // Not sure what root_name is. - return detail::escape_uri(detail::path_to_generic(x)); - } - } - else if (x.has_root_directory()) { - return "file://" + detail::escape_uri(detail::path_to_generic(x)); - } - else { - return detail::escape_uri(detail::path_to_generic(x)); - } - } - - std::string dir_path_to_url(fs::path const& x) - { - return file_path_to_url(x) + "/"; - } - quickbook_path resolve_xinclude_path(std::string const& x, quickbook::state& state) { fs::path path = detail::generic_to_path(x); fs::path full_path = path; diff --git a/src/include_paths.hpp b/src/include_paths.hpp index 5882092..82462af 100644 --- a/src/include_paths.hpp +++ b/src/include_paths.hpp @@ -66,8 +66,6 @@ namespace quickbook quickbook::state& state, string_iterator pos); quickbook_path resolve_xinclude_path(std::string const&, quickbook::state&); - std::string file_path_to_url(fs::path const&); - std::string dir_path_to_url(fs::path const&); } #endif diff --git a/src/main_grammar.cpp b/src/main_grammar.cpp index 65d668c..7b6399b 100644 --- a/src/main_grammar.cpp +++ b/src/main_grammar.cpp @@ -17,7 +17,7 @@ #include "phrase_tags.hpp" #include "parsers.hpp" #include "scoped.hpp" -#include "native_text.hpp" +#include "stream.hpp" #include #include #include diff --git a/src/native_text.cpp b/src/native_text.cpp index 62ff520..5b41aaf 100644 --- a/src/native_text.cpp +++ b/src/native_text.cpp @@ -10,13 +10,10 @@ #include #include "native_text.hpp" #include "utils.hpp" -#include "files.hpp" #if QUICKBOOK_WIDE_PATHS || QUICKBOOK_WIDE_STREAMS #include #include -#include -#include #endif #if QUICKBOOK_CYGWIN_PATHS @@ -27,314 +24,38 @@ namespace quickbook { namespace detail { - namespace { - bool ms_errors = false; - } - - void set_ms_errors(bool x) { - ms_errors = x; - } - // 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); + 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."); - if (!buffer_count) - throw conversion_error("Error converting wide string to utf-8."); + return std::string(buffer.get()); + } + + std::wstring from_utf8(quickbook::string_view text) + { + std::string x(text.begin(), text.end()); + int buffer_count = MultiByteToWideChar(CP_UTF8, 0, x.c_str(), -1, 0, 0); - 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()); - } + if (!buffer_count) + throw conversion_error("Error converting utf-8 to wide string."); - std::wstring from_utf8(quickbook::string_view text) - { - std::string x(text.begin(), text.end()); - 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()); - } + 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 command_line_to_utf8(command_line_string const& x) - { - return to_utf8(x); - } -#else - std::string command_line_to_utf8(command_line_string const& x) - { - return x; - } -#endif - -#if QUICKBOOK_WIDE_PATHS - fs::path generic_to_path(quickbook::string_view 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(quickbook::string_view x) - { - return fs::path(x.begin(), x.end()); - } - - std::string path_to_generic(fs::path const& x) - { - return x.generic_string(); - } - -#endif - - -#if QUICKBOOK_CYGWIN_PATHS - fs::path command_line_to_path(command_line_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 conversion_error("Error converting cygwin path to windows."); - - boost::scoped_array result(new char[size]); - void* ptr = result.get(); - - if(cygwin_conv_path(flags, path.c_str(), ptr, size)) - throw conversion_error("Error converting cygwin path to windows."); - - return fs::path(static_cast(ptr)); - } - - ostream::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.native().c_str(), result.get(), size)) - throw conversion_error("Error converting windows path to cygwin."); - - return std::string(result.get()); - } -#else - fs::path command_line_to_path(command_line_string const& path) - { - return fs::path(path); - } - -#if QUICKBOOK_WIDE_PATHS && !QUICKBOOK_WIDE_STREAMS - ostream::string path_to_stream(fs::path const& path) - { - return path.string(); - } -#else - ostream::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::base_ostream& out, quickbook::string_view x) - { - out << from_utf8(x); - } - - ostream& out() - { - static ostream x(std::wcout); - return x; - } - - namespace - { - inline ostream& error_stream() - { - static ostream x(std::wcerr); - return x; - } - } - -#else - - void initialise_output() - { - } - - void write_utf8(ostream::base_ostream& out, quickbook::string_view x) - { - out << x; - } - - ostream& out() - { - static ostream x(std::cout); - return x; - } - - namespace - { - inline ostream& error_stream() - { - static ostream x(std::clog); - return x; - } - } - -#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& outerr(file_ptr const& f, string_iterator pos) - { - return outerr(f->path, f->position_of(pos).line); - } - - 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: "; - } - } - - ostream& outwarn(file_ptr const& f, string_iterator pos) - { - return outwarn(f->path, f->position_of(pos).line); - } - - ostream& ostream::operator<<(char c) { - assert(c > 0 && c <= 127); - base << c; - return *this; - } - - inline bool check_ascii(char const* x) { - for(;*x;++x) if(*x <= 0 || *x > 127) return false; - return true; - } - - ostream& ostream::operator<<(char const* x) { - assert(check_ascii(x)); - base << x; - return *this; - } - - ostream& ostream::operator<<(std::string const& x) { - write_utf8(base, x); - return *this; - } - - ostream& ostream::operator<<(quickbook::string_view x) { - write_utf8(base, x); - return *this; - } - - ostream& ostream::operator<<(int x) { - base << x; - return *this; - } - - ostream& ostream::operator<<(unsigned int x) { - base << x; - return *this; - } - - ostream& ostream::operator<<(long x) { - base << x; - return *this; - } - - ostream& ostream::operator<<(unsigned long x) { - base << x; - return *this; - } - -#if !defined(BOOST_NO_LONG_LONG) - ostream& ostream::operator<<(long long x) { - base << x; - return *this; - } - - ostream& ostream::operator<<(unsigned long long x) { - base << x; - return *this; - } -#endif - - ostream& ostream::operator<<(fs::path const& x) { - base << path_to_stream(x); - return *this; - } - - ostream& ostream::operator<<(base_ostream& (*x)(base_ostream&)) { - base << x; - return *this; - } - - ostream& ostream::operator<<(base_ios& (*x)(base_ios&)) { - base << x; - return *this; - } }} diff --git a/src/native_text.hpp b/src/native_text.hpp index 0e262d9..e138c3a 100644 --- a/src/native_text.hpp +++ b/src/native_text.hpp @@ -12,11 +12,9 @@ #define BOOST_QUICKBOOK_DETAIL_NATIVE_TEXT_HPP #include -#include -#include "string_view.hpp" #include #include -#include +#include "string_view.hpp" #include "fwd.hpp" #if defined(__cygwin__) || defined(__CYGWIN__) @@ -45,8 +43,6 @@ namespace quickbook { - namespace fs = boost::filesystem; - namespace detail { struct conversion_error : std::runtime_error @@ -54,92 +50,16 @@ namespace quickbook conversion_error(char const* m) : std::runtime_error(m) {} }; - // 'generic': Paths in quickbook source and the generated boostbook. - // Always UTF-8. - // 'command_line': - // 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). - // '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 command_line_string; -#else - typedef std::string command_line_string; -#endif - - // A light wrapper around C++'s streams that gets things right - // in the quickbook context. - // - // This is far from perfect but it fixes some issues. - struct ostream - { #if QUICKBOOK_WIDE_STREAMS - typedef std::wostream base_ostream; - typedef std::wios base_ios; - typedef std::wstring string; - typedef boost::wstring_view string_ref; + typedef std::wstring stream_string; #else - typedef std::ostream base_ostream; - typedef std::ios base_ios; - typedef std::string string; - typedef quickbook::string_view string_ref; -#endif - base_ostream& base; - - explicit ostream(base_ostream& x) : base(x) {} - - // C strings should always be ascii. - ostream& operator<<(char); - ostream& operator<<(char const*); - - // std::string should be UTF-8 (what a mess!) - ostream& operator<<(std::string const&); - ostream& operator<<(quickbook::string_view); - - // Other value types. - ostream& operator<<(int x); - ostream& operator<<(unsigned int x); - ostream& operator<<(long x); - ostream& operator<<(unsigned long x); - -#if !defined(BOOST_NO_LONG_LONG) - ostream& operator<<(long long x); - ostream& operator<<(unsigned long long x); + typedef std::string stream_string; #endif - ostream& operator<<(fs::path const&); - - // Modifiers - ostream& operator<<(base_ostream& (*)(base_ostream&)); - ostream& operator<<(base_ios& (*)(base_ios&)); - }; - - - std::string command_line_to_utf8(command_line_string const&); - fs::path command_line_to_path(command_line_string const&); - - std::string path_to_generic(fs::path const&); - fs::path generic_to_path(quickbook::string_view); - - void initialise_output(); - - ostream& out(); - - // Preformats an error/warning message so that it can be parsed by - // common IDEs. Set 'ms_errors' to determine if VS format - // or GCC format. Returns the stream to continue ouput of the verbose - // error message. - void set_ms_errors(bool); - ostream& outerr(); - ostream& outerr(fs::path const& file, int line = -1); - ostream& outwarn(fs::path const& file, int line = -1); - ostream& outerr(file_ptr const&, string_iterator); - ostream& outwarn(file_ptr const&, string_iterator); +#if QUICKBOOK_WIDE_PATHS || QUICKBOOK_WIDE_STREAMS + std::string to_utf8(std::wstring const& x); + std::wstring from_utf8(string_view x); +#endif } } diff --git a/src/path.cpp b/src/path.cpp new file mode 100644 index 0000000..987d29b --- /dev/null +++ b/src/path.cpp @@ -0,0 +1,236 @@ +/*============================================================================= + Copyright (c) 2002 2004 2006 Joel de Guzman + Copyright (c) 2004 Eric Niebler + Copyright (c) 2005 Thomas Guest + Copyright (c) 2013, 2017 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) +=============================================================================*/ + +#include "path.hpp" +#include "glob.hpp" +#include "include_paths.hpp" +#include "state.hpp" +#include "utils.hpp" +#include +#include +#include +#include + +namespace quickbook +{ + // Not a general purpose normalization function, just + // from paths from the root directory. It strips the excess + // ".." parts from a path like: "x/../../y", leaving "y". + std::vector normalize_path_from_root(fs::path const& path) + { + assert(!path.has_root_directory() && !path.has_root_name()); + + std::vector parts; + + BOOST_FOREACH(fs::path const& part, path) + { + if (part.empty() || part == ".") { + } + else if (part == "..") { + if (!parts.empty()) parts.pop_back(); + } + else { + parts.push_back(part); + } + } + + return parts; + } + + // The relative path from base to path + fs::path path_difference(fs::path const& base, fs::path const& path) + { + fs::path + absolute_base = fs::absolute(base), + absolute_path = fs::absolute(path); + + // Remove '.', '..' and empty parts from the remaining path + std::vector + base_parts = normalize_path_from_root(absolute_base.relative_path()), + path_parts = normalize_path_from_root(absolute_path.relative_path()); + + std::vector::iterator + base_it = base_parts.begin(), + base_end = base_parts.end(), + path_it = path_parts.begin(), + path_end = path_parts.end(); + + // Build up the two paths in these variables, checking for the first + // difference. + fs::path + base_tmp = absolute_base.root_path(), + path_tmp = absolute_path.root_path(); + + fs::path result; + + // If they have different roots then there's no relative path so + // just build an absolute path. + if (!fs::equivalent(base_tmp, path_tmp)) + { + result = path_tmp; + } + else + { + // Find the point at which the paths differ + for(; base_it != base_end && path_it != path_end; ++base_it, ++path_it) + { + if(!fs::equivalent(base_tmp /= *base_it, path_tmp /= *path_it)) + break; + } + + // Build a relative path to that point + for(; base_it != base_end; ++base_it) result /= ".."; + } + + // Build the rest of our path + for(; path_it != path_end; ++path_it) result /= *path_it; + + return result; + } + + // Convert a Boost.Filesystem path to a URL. + // + // I'm really not sure about this, as the meaning of root_name and + // root_directory are only clear for windows. + // + // Some info on file URLs at: + // https://en.wikipedia.org/wiki/File_URI_scheme + std::string file_path_to_url(fs::path const& x) + { + // TODO: Maybe some kind of error if this doesn't understand the path. + // TODO: Might need a special cygwin implementation. + // TODO: What if x.has_root_name() && !x.has_root_directory()? + // TODO: What does Boost.Filesystem do for '//localhost/c:/path'? + // Is that event allowed by windows? + + if (x.has_root_name()) { + std::string root_name = detail::path_to_generic(x.root_name()); + + if (root_name.size() > 2 && root_name[0] == '/' && root_name[1] == '/') { + // root_name is a network location. + return "file:" + detail::escape_uri(detail::path_to_generic(x)); + } + else if (root_name.size() >= 2 && root_name[root_name.size() - 1] == ':') { + // root_name is a drive. + return "file:///" + + detail::escape_uri(root_name.substr(0, root_name.size() - 1)) + + ":/" // TODO: Or maybe "|/". + + detail::escape_uri(detail::path_to_generic(x.relative_path())); + } + else { + // Not sure what root_name is. + return detail::escape_uri(detail::path_to_generic(x)); + } + } + else if (x.has_root_directory()) { + return "file://" + detail::escape_uri(detail::path_to_generic(x)); + } + else { + return detail::escape_uri(detail::path_to_generic(x)); + } + } + + std::string dir_path_to_url(fs::path const& x) + { + return file_path_to_url(x) + "/"; + } + + namespace detail { +#if QUICKBOOK_WIDE_PATHS + std::string command_line_to_utf8(command_line_string const& x) + { + return to_utf8(x); + } +#else + std::string command_line_to_utf8(command_line_string const& x) + { + return x; + } +#endif + +#if QUICKBOOK_WIDE_PATHS + fs::path generic_to_path(quickbook::string_view 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(quickbook::string_view x) + { + return fs::path(x.begin(), x.end()); + } + + std::string path_to_generic(fs::path const& x) + { + return x.generic_string(); + } +#endif + +#if QUICKBOOK_CYGWIN_PATHS + fs::path command_line_to_path(command_line_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 conversion_error("Error converting cygwin path to windows."); + + boost::scoped_array result(new char[size]); + void* ptr = result.get(); + + if(cygwin_conv_path(flags, path.c_str(), ptr, size)) + throw conversion_error("Error converting cygwin path to windows."); + + return fs::path(static_cast(ptr)); + } + + 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.native().c_str(), result.get(), size)) + throw conversion_error("Error converting windows path to cygwin."); + + return std::string(result.get()); + } +#else + fs::path command_line_to_path(command_line_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 + } +} diff --git a/src/path.hpp b/src/path.hpp new file mode 100644 index 0000000..2ba71ec --- /dev/null +++ b/src/path.hpp @@ -0,0 +1,58 @@ +/*============================================================================= + Copyright (c) 2002 2004 2006 Joel de Guzman + Copyright (c) 2004 Eric Niebler + Copyright (c) 2005 Thomas Guest + Copyright (c) 2013, 2017 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_QUICKBOOK_DETAIL_PATH_HPP) +#define BOOST_QUICKBOOK_DETAIL_PATH_HPP + +#include +#include "native_text.hpp" + +namespace quickbook +{ + namespace fs = boost::filesystem; + + // The relative path from base to path + fs::path path_difference(fs::path const& base, fs::path const& path); + + // Convert a Boost.Filesystem path to a URL. + std::string file_path_to_url(fs::path const&); + std::string dir_path_to_url(fs::path const&); + + namespace detail { + // 'generic': Paths in quickbook source and the generated boostbook. + // Always UTF-8. + // 'command_line': + // 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). + // '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 command_line_string; +#else + typedef std::string command_line_string; +#endif + + std::string command_line_to_utf8(command_line_string const&); + fs::path command_line_to_path(command_line_string const&); + + std::string path_to_generic(fs::path const&); + fs::path generic_to_path(quickbook::string_view); + + stream_string path_to_stream(fs::path const& path); + } +} + +#endif \ No newline at end of file diff --git a/src/quickbook.cpp b/src/quickbook.cpp index d36d6be..645cdd9 100644 --- a/src/quickbook.cpp +++ b/src/quickbook.cpp @@ -14,7 +14,8 @@ #include "post_process.hpp" #include "utils.hpp" #include "files.hpp" -#include "native_text.hpp" +#include "stream.hpp" +#include "path.hpp" #include "document_state.hpp" #include #include diff --git a/src/state.cpp b/src/state.cpp index 790933a..8be117b 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -13,7 +13,7 @@ #include "document_state.hpp" #include "quickbook.hpp" #include "grammar.hpp" -#include "native_text.hpp" +#include "path.hpp" #include "utils.hpp" #include "phrase_tags.hpp" #include diff --git a/src/stream.cpp b/src/stream.cpp new file mode 100644 index 0000000..22b457a --- /dev/null +++ b/src/stream.cpp @@ -0,0 +1,202 @@ +/*============================================================================= + Copyright (c) 2009 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) +=============================================================================*/ + +#include "stream.hpp" +#include "path.hpp" +#include "files.hpp" + +#if QUICKBOOK_WIDE_PATHS || QUICKBOOK_WIDE_STREAMS +#include +#include +#endif + +namespace quickbook { +namespace detail { + namespace { + bool ms_errors = false; + } + + void set_ms_errors(bool x) { + ms_errors = x; + } + +#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::base_ostream& out, quickbook::string_view x) + { + out << from_utf8(x); + } + + ostream& out() + { + static ostream x(std::wcout); + return x; + } + + namespace + { + inline ostream& error_stream() + { + static ostream x(std::wcerr); + return x; + } + } + +#else + + void initialise_output() + { + } + + void write_utf8(ostream::base_ostream& out, quickbook::string_view x) + { + out << x; + } + + ostream& out() + { + static ostream x(std::cout); + return x; + } + + namespace + { + inline ostream& error_stream() + { + static ostream x(std::clog); + return x; + } + } + +#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& outerr(file_ptr const& f, string_iterator pos) + { + return outerr(f->path, f->position_of(pos).line); + } + + 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: "; + } + } + + ostream& outwarn(file_ptr const& f, string_iterator pos) + { + return outwarn(f->path, f->position_of(pos).line); + } + + ostream& ostream::operator<<(char c) { + assert(c > 0 && c <= 127); + base << c; + return *this; + } + + inline bool check_ascii(char const* x) { + for(;*x;++x) if(*x <= 0 || *x > 127) return false; + return true; + } + + ostream& ostream::operator<<(char const* x) { + assert(check_ascii(x)); + base << x; + return *this; + } + + ostream& ostream::operator<<(std::string const& x) { + write_utf8(base, x); + return *this; + } + + ostream& ostream::operator<<(quickbook::string_view x) { + write_utf8(base, x); + return *this; + } + + ostream& ostream::operator<<(int x) { + base << x; + return *this; + } + + ostream& ostream::operator<<(unsigned int x) { + base << x; + return *this; + } + + ostream& ostream::operator<<(long x) { + base << x; + return *this; + } + + ostream& ostream::operator<<(unsigned long x) { + base << x; + return *this; + } + +#if !defined(BOOST_NO_LONG_LONG) + ostream& ostream::operator<<(long long x) { + base << x; + return *this; + } + + ostream& ostream::operator<<(unsigned long long x) { + base << x; + return *this; + } +#endif + + ostream& ostream::operator<<(fs::path const& x) { + base << path_to_stream(x); + return *this; + } + + ostream& ostream::operator<<(base_ostream& (*x)(base_ostream&)) { + base << x; + return *this; + } + + ostream& ostream::operator<<(base_ios& (*x)(base_ios&)) { + base << x; + return *this; + } +}} \ No newline at end of file diff --git a/src/stream.hpp b/src/stream.hpp new file mode 100644 index 0000000..3a40933 --- /dev/null +++ b/src/stream.hpp @@ -0,0 +1,88 @@ +/*============================================================================= + Copyright (c) 2009 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) +=============================================================================*/ + +// For handling native strings and streams. + +#if !defined(BOOST_QUICKBOOK_DETAIL_STREAM_HPP) +#define BOOST_QUICKBOOK_DETAIL_STREAM_HPP + +#include "native_text.hpp" +#include +#include + +namespace quickbook +{ + namespace fs = boost::filesystem; + + namespace detail + { + // A light wrapper around C++'s streams that gets things right + // in the quickbook context. + // + // This is far from perfect but it fixes some issues. + struct ostream + { +#if QUICKBOOK_WIDE_STREAMS + typedef std::wostream base_ostream; + typedef std::wios base_ios; + typedef std::wstring string; + typedef boost::wstring_view string_ref; +#else + typedef std::ostream base_ostream; + typedef std::ios base_ios; + typedef std::string string; + typedef quickbook::string_view string_ref; +#endif + base_ostream& base; + + explicit ostream(base_ostream& x) : base(x) {} + + // C strings should always be ascii. + ostream& operator<<(char); + ostream& operator<<(char const*); + + // std::string should be UTF-8 (what a mess!) + ostream& operator<<(std::string const&); + ostream& operator<<(quickbook::string_view); + + // Other value types. + ostream& operator<<(int x); + ostream& operator<<(unsigned int x); + ostream& operator<<(long x); + ostream& operator<<(unsigned long x); + +#if !defined(BOOST_NO_LONG_LONG) + ostream& operator<<(long long x); + ostream& operator<<(unsigned long long x); +#endif + + ostream& operator<<(fs::path const&); + + // Modifiers + ostream& operator<<(base_ostream& (*)(base_ostream&)); + ostream& operator<<(base_ios& (*)(base_ios&)); + }; + + void initialise_output(); + + ostream& out(); + + // Preformats an error/warning message so that it can be parsed by + // common IDEs. Set 'ms_errors' to determine if VS format + // or GCC format. Returns the stream to continue ouput of the verbose + // error message. + void set_ms_errors(bool); + ostream& outerr(); + ostream& outerr(fs::path const& file, int line = -1); + ostream& outwarn(fs::path const& file, int line = -1); + ostream& outerr(file_ptr const&, string_iterator); + ostream& outwarn(file_ptr const&, string_iterator); + } +} + +#endif \ No newline at end of file diff --git a/src/syntax_highlight.cpp b/src/syntax_highlight.cpp index 3036733..c4c8e19 100644 --- a/src/syntax_highlight.cpp +++ b/src/syntax_highlight.cpp @@ -18,7 +18,7 @@ #include "syntax_highlight.hpp" #include "utils.hpp" #include "files.hpp" -#include "native_text.hpp" +#include "stream.hpp" #include "phrase_tags.hpp" namespace quickbook