$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r68397 - branches/quickbook-filenames/tools/quickbook/src
From: dnljms_at_[hidden]
Date: 2011-01-23 11:49:39
Author: danieljames
Date: 2011-01-23 11:49:34 EST (Sun, 23 Jan 2011)
New Revision: 68397
URL: http://svn.boost.org/trac/boost/changeset/68397
Log:
Windows support for unicode filenames.
Text files modified: 
   branches/quickbook-filenames/tools/quickbook/src/Jamfile.v2     |     8 ++                                      
   branches/quickbook-filenames/tools/quickbook/src/input_path.cpp |   113 ++++++++++++++++++++++++--------------- 
   branches/quickbook-filenames/tools/quickbook/src/input_path.hpp |    35 +++++++++--                             
   branches/quickbook-filenames/tools/quickbook/src/quickbook.cpp  |    74 +++++++++++++++++++------               
   4 files changed, 161 insertions(+), 69 deletions(-)
Modified: branches/quickbook-filenames/tools/quickbook/src/Jamfile.v2
==============================================================================
--- branches/quickbook-filenames/tools/quickbook/src/Jamfile.v2	(original)
+++ branches/quickbook-filenames/tools/quickbook/src/Jamfile.v2	2011-01-23 11:49:34 EST (Sun, 23 Jan 2011)
@@ -8,6 +8,8 @@
 #   http://www.boost.org/LICENSE_1_0.txt)
 #==============================================================================
 
+import os ;
+
 project quickbook
     : requirements
         <toolset>gcc:<c++-template-depth>300
@@ -16,6 +18,11 @@
         <toolset>darwin:<cflags>-g0
     ;
 
+if [ os.name ] = NT
+{
+  lib shell32 ;
+}
+
 exe quickbook
     :
     quickbook.cpp
@@ -50,4 +57,5 @@
       <toolset>msvc:<cxxflags>/wd4800
       <toolset>msvc:<define>_CRT_SECURE_NO_DEPRECATE
       <toolset>msvc:<define>_SCL_SECURE_NO_DEPRECATE
+      <os>NT:<library>shell32
     ;
Modified: branches/quickbook-filenames/tools/quickbook/src/input_path.cpp
==============================================================================
--- branches/quickbook-filenames/tools/quickbook/src/input_path.cpp	(original)
+++ branches/quickbook-filenames/tools/quickbook/src/input_path.cpp	2011-01-23 11:49:34 EST (Sun, 23 Jan 2011)
@@ -8,73 +8,100 @@
 
 #include <boost/program_options.hpp>
 #include "input_path.hpp"
+#include "utils.hpp"
+
+#if defined(_WIN32)
+#include <boost/scoped_ptr.hpp>
+#include <windows.h>
+#endif
+
+#if (defined(__cygwin__) || defined(__CYGWIN__))
+#include <boost/scoped_array.hpp>
+#include <boost/program_options/errors.hpp>
+#include <sys/cygwin.h>
+#endif
 
 namespace quickbook {
 namespace detail {
-    // TODO: These don't work for unicode strings on windows.
+#if defined(_WIN32)
+    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<char> 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<wchar_t> 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 native_string(buffer.get());
+        }
+    }
+#endif
+
+    std::string native_to_utf8(native_string const& x)
+    {
+#if QUICKBOOK_WIDE_NATIVE
+        return to_utf8(x);
+#else
+        return x;
+#endif
+    }
 
     fs::path generic_to_path(std::string const& x)
     {
+#if defined(_WIN32)
+        return fs::path(from_utf8(x));
+#else
         return fs::path(x);
+#endif
     }
 
     std::string path_to_generic(fs::path const& x)
     {
+#if defined(_WIN32)
+        return to_utf8(x.generic_wstring());
+#else
         return x.generic_string();
+#endif
     }
-}
-}
 
+    fs::path native_to_path(native_string const& path)
+    {
 #if !(defined(__cygwin__) || defined(__CYGWIN__))
-
-// Everything but cygwin
-
-namespace quickbook {
-namespace detail {
-    fs::path native_to_path(fs::path::string_type const& path) {
         return fs::path(path);
-    }
-}}
-
-#else
-
-// Cygwin 1.7.x
-    
-#include <boost/filesystem/v3/config.hpp>
-#include <boost/scoped_array.hpp>
-#include <boost/program_options/errors.hpp>
-#include <windows.h>
-#include <sys/cygwin.h>
-
-namespace quickbook {
-namespace detail {
-    fs::path native_to_path(fs::path::string_type const& path) {
-        // TODO: Use unicode version
-#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
+        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) {
-            // TODO: Better error.
-            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.");
 
         boost::scoped_array<char> 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.c_str(), result.get(), size))
+            throw conversion_error("Error converting cygwin path to windows.");
 
         return fs::path(result.get());
+#endif
     }
 }}
-
-#endif
Modified: branches/quickbook-filenames/tools/quickbook/src/input_path.hpp
==============================================================================
--- branches/quickbook-filenames/tools/quickbook/src/input_path.hpp	(original)
+++ branches/quickbook-filenames/tools/quickbook/src/input_path.hpp	2011-01-23 11:49:34 EST (Sun, 23 Jan 2011)
@@ -11,6 +11,7 @@
 
 #include <boost/filesystem/v3/path.hpp>
 #include <string>
+#include <stdexcept>
 
 namespace quickbook
 {
@@ -18,15 +19,35 @@
 
     namespace detail
     {
-        // Convert paths from the command line, or other native sources to
-        // our internal path type. Mainly used to convert cygwin paths, but
-        // might be useful elsewhere.
-        fs::path native_to_path(fs::path::string_type const&);
+        struct conversion_error : std::runtime_error
+        {
+            conversion_error(char const* m) : std::runtime_error(m) {}
+        };
+
+        // 'generic':   Paths in quickbook source and the generated boostbook.
+        //              Always UTF-8.
+        // 'native':    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 defined(_WIN32) && !(defined(__cygwin__) || defined(__CYGWIN__))
+#define QUICKBOOK_WIDE_NATIVE 1
+        typedef std::wstring native_string;
+#else
+#define QUICKBOOK_WIDE_NATIVE 0
+        typedef std::string native_string;
+#endif
+
+        std::string native_to_utf8(native_string const&);
+        fs::path native_to_path(native_string const& x);
     
-        // Conversion of filenames to and from genertic utf-8 paths
-        // (such as those used in quickbook and the generated boostbook)
-        fs::path generic_to_path(std::string const&);
         std::string path_to_generic(fs::path const&);
+        fs::path generic_to_path(std::string const&);
     }
 }
 
Modified: branches/quickbook-filenames/tools/quickbook/src/quickbook.cpp
==============================================================================
--- branches/quickbook-filenames/tools/quickbook/src/quickbook.cpp	(original)
+++ branches/quickbook-filenames/tools/quickbook/src/quickbook.cpp	2011-01-23 11:49:34 EST (Sun, 23 Jan 2011)
@@ -17,10 +17,17 @@
 #include <boost/filesystem/v3/path.hpp>
 #include <boost/filesystem/v3/operations.hpp>
 #include <boost/filesystem/v3/fstream.hpp>
+#include <boost/range/algorithm.hpp>
 #include <boost/ref.hpp>
 
 #include <stdexcept>
 #include <vector>
+#include <iterator>
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <shellapi.h>
+#endif
 
 #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
 #pragma warning(disable:4355)
@@ -166,32 +173,42 @@
     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::native_string;
 
         // First thing, the filesystem should record the current working directory.
         fs::initial_path<fs::path>();
 
         options_description desc("Allowed options");
+
+#if QUICKBOOK_WIDE_NATIVE
+#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<int>(), "indent spaces")
-            ("linewidth", value<int>(), "line width")
-            ("input-file", value<fs::path::string_type>(), "input file")
-            ("output-file", value<fs::path::string_type>(), "output file")
+            ("indent", PO_VALUE<int>(), "indent spaces")
+            ("linewidth", PO_VALUE<int>(), "line width")
+            ("input-file", PO_VALUE<native_string>(), "input file")
+            ("output-file", PO_VALUE<native_string>(), "output file")
             ("debug", "debug mode (for developers)")
             ("ms-errors", "use Microsoft Visual Studio style error & warn message format")
-            ("include-path,I", value< std::vector<fs::path::string_type> >(), "include path")
-            ("define,D", value< std::vector<std::string> >(), "define macro")
+            ("include-path,I", PO_VALUE< std::vector<native_string> >(), "include path")
+            ("define,D", PO_VALUE< std::vector<native_string> >(), "define macro")
         ;
 
         positional_options_description p;
@@ -201,7 +218,23 @@
         int indent = -1;
         int linewidth = -1;
         bool pretty_print = true;
+
+#if QUICKBOOK_WIDE_NATIVE
+        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"))
@@ -253,31 +286,34 @@
             quickbook::debug_mode = false;
         }
         
+        quickbook::include_path.clear();
         if (vm.count("include-path"))
         {
-            std::vector<fs::path::string_type> paths
-                = vm["include-path"].as<
-                    std::vector<fs::path::string_type> >();
-            quickbook::include_path
-                = std::vector<fs::path>(paths.begin(), paths.end());
+            boost::transform(
+                vm["include-path"].as<std::vector<native_string> >(),
+                std::back_inserter(quickbook::include_path),
+                quickbook::detail::native_to_path);
         }
 
+        quickbook::preset_defines.clear();
         if (vm.count("define"))
         {
-            quickbook::preset_defines
-                = vm["define"].as<std::vector<std::string> >();
+            boost::transform(
+                vm["define"].as<std::vector<native_string> >(),
+                std::back_inserter(quickbook::preset_defines),
+                quickbook::detail::native_to_utf8);
         }
 
         if (vm.count("input-file"))
         {
-            // TODO: Convert cygwin paths
-            fs::path filein(
-                vm["input-file"].as<fs::path::string_type>());
+            fs::path filein = quickbook::detail::native_to_path(
+                vm["input-file"].as<native_string>());
             fs::path fileout;
 
             if (vm.count("output-file"))
             {
-                fileout = vm["output-file"].as<fs::path::string_type>();
+                fileout = quickbook::detail::native_to_path(
+                    vm["output-file"].as<native_string>());
             }
             else
             {
@@ -286,7 +322,7 @@
             }
 
             std::cout << "Generating Output File: "
-                << fileout.string() // TODO
+                << fileout.string()
                 << std::endl;
 
             return quickbook::parse_document(filein, fileout, indent, linewidth, pretty_print);