Mercurial > octave
changeset 29540:b6f80b1d448f
Windows: Support non-ASCII characters in command line arguments.
* configure.ac: Define macros necessary for Unicode support on Windows. Add
linker flags for Unicode executables with mingw.
* src/main-cli.cc, src/main-gui.cc, src/main.in.cc, src/mkoctfile.in.cc,
src/octave-config.in.cc, src/octave-svgconvert.cc: Optionally use "wmain"
instead of "main" as primary entry function.
* src/mkoctfile.in.cc (main, wmain): Use Unicode API to open pipe on Windows if
possible.
* src/module.mk: Use flags for linking with Unicode "wmain" function.
author | Markus Mützel <markus.muetzel@gmx.de> |
---|---|
date | Sat, 17 Apr 2021 12:21:48 +0200 |
parents | b51ba0fdd513 |
children | ebf68dde5579 |
files | configure.ac src/main-cli.cc src/main-gui.cc src/main.in.cc src/mkoctfile.in.cc src/module.mk src/octave-config.in.cc src/octave-svgconvert.cc |
diffstat | 8 files changed, 235 insertions(+), 59 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.ac Sat Apr 17 12:21:35 2021 +0200 +++ b/configure.ac Sat Apr 17 12:21:48 2021 +0200 @@ -1251,6 +1251,23 @@ AC_MSG_ERROR([MATH DEFINES in math.h such as M_PI are required to build Octave]) fi +## Use Unicode aware functions on Windows +case $host_os in + msdosmsvc | mingw*) + AC_DEFINE(_UNICODE, 1, [Use Unicode CRT functions on Windows by default.]) + AC_DEFINE(UNICODE, 1, [Use Windows Unicode API by default.]) + ;; +esac + +OCTAVE_UNICODE_EXE_LDFLAGS="" +case $host_os in + mingw*) + OCTAVE_UNICODE_EXE_LDFLAGS="-municode" + ;; +esac + +AC_SUBST(OCTAVE_UNICODE_EXE_LDFLAGS) + ## Windows-specific use of functions case $host_os in msdosmsvc | mingw*)
--- a/src/main-cli.cc Sat Apr 17 12:21:35 2021 +0200 +++ b/src/main-cli.cc Sat Apr 17 12:21:48 2021 +0200 @@ -32,6 +32,12 @@ #include <iostream> #include <string> +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +# include <vector> +# include <locale> +# include <codecvt> +#endif + #include "liboctave-build-info.h" #include "liboctinterp-build-info.h" @@ -81,9 +87,28 @@ exit (1); } +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +extern "C" +int +wmain (int argc, wchar_t **wargv) +{ + static char **argv = new char * [argc + 1]; + std::vector<std::string> argv_str; + + // convert wide character strings to multibyte UTF-8 strings + std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; + for (int i_arg = 0; i_arg < argc; i_arg++) + { + argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg])); + argv[i_arg] = &argv_str[i_arg][0]; + } + argv[argc] = nullptr; + +#else int main (int argc, char **argv) { +#endif check_hg_versions (); octave_block_async_signals ();
--- a/src/main-gui.cc Sat Apr 17 12:21:35 2021 +0200 +++ b/src/main-gui.cc Sat Apr 17 12:21:48 2021 +0200 @@ -32,6 +32,12 @@ #include <iostream> #include <string> +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +# include <vector> +# include <locale> +# include <codecvt> +#endif + #include "liboctave-build-info.h" #include "liboctinterp-build-info.h" @@ -94,9 +100,28 @@ exit (1); } +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +extern "C" +int +wmain (int argc, wchar_t **wargv) +{ + static char **argv = new char * [argc + 1]; + std::vector<std::string> argv_str; + + // convert wide character strings to multibyte UTF-8 strings + std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; + for (int i_arg = 0; i_arg < argc; i_arg++) + { + argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg])); + argv[i_arg] = &argv_str[i_arg][0]; + } + argv[argc] = nullptr; + +#else int main (int argc, char **argv) { +#endif check_hg_versions (); octave::sys::env::set_program_name (argv[0]);
--- a/src/main.in.cc Sat Apr 17 12:21:35 2021 +0200 +++ b/src/main.in.cc Sat Apr 17 12:21:48 2021 +0200 @@ -43,6 +43,12 @@ #include <iostream> #include <string> +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +# include <vector> +# include <locale> +# include <codecvt> +#endif + // We are linking against static libs so do not decorate with dllimport. // FIXME: This should be done by the build system. #undef OCTAVE_API @@ -210,9 +216,28 @@ return tmp; } +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +extern "C" +int +wmain (int argc, wchar_t **wargv) +{ + static char **argv = new char * [argc + 1]; + std::vector<std::string> argv_str; + + // convert wide character strings to multibyte UTF-8 strings + std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; + for (int i_arg = 0; i_arg < argc; i_arg++) + { + argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg])); + argv[i_arg] = &argv_str[i_arg][0]; + } + argv[argc] = nullptr; + +#else int main (int argc, char **argv) { +#endif int retval = 0; int idx_gui = -1;
--- a/src/mkoctfile.in.cc Sat Apr 17 12:21:35 2021 +0200 +++ b/src/mkoctfile.in.cc Sat Apr 17 12:21:48 2021 +0200 @@ -40,6 +40,11 @@ #include <vector> #include <cstdlib> +#if defined (OCTAVE_USE_WINDOWS_API) +# include <locale> +# include <codecvt> +#endif + // Programming note: The CROSS macro here refers to building a // cross-compiler aware version of mkoctfile that can be used to cross // compile .oct file for Windows builds of Octave, not that mkoctfile @@ -92,14 +97,6 @@ return mkostemps (tmpl, suffixlen, 0); } -static char * -octave_u8_conv_to_encoding (const char *tocode, const uint8_t *src, - size_t srclen, size_t *lengthp) -{ - // FIXME: Do we need to provide the conversion here? - return nullptr; -} - static int octave_unlink_wrapper (const char *nm) { @@ -702,9 +699,28 @@ octave_unlink_wrapper (file.c_str ()); } +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +extern "C" +int +wmain (int argc, wchar_t **wargv) +{ + static char **argv = new char * [argc + 1]; + std::vector<std::string> argv_str; + + // convert wide character strings to multibyte UTF-8 strings + std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; + for (int i_arg = 0; i_arg < argc; i_arg++) + { + argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg])); + argv[i_arg] = &argv_str[i_arg][0]; + } + argv[argc] = nullptr; + +#else int main (int argc, char **argv) { +#endif if (argc == 1) { std::cout << usage_msg << std::endl; @@ -1032,6 +1048,10 @@ if (depend) { +#if defined (OCTAVE_USE_WINDOWS_API) && ! defined (_UNICODE) + std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; +#endif + for (const auto& f : cfiles) { std::string dfile = basename (f, true) + ".d", line; @@ -1043,33 +1063,34 @@ + vars["CPPFLAGS"] + ' ' + vars["ALL_CFLAGS"] + ' ' + incflags + ' ' + defs + ' ' + quote_path (f)); - // FIXME: Use wide character API for popen on Windows. +#if defined (OCTAVE_USE_WINDOWS_API) + FILE *fd; + try + { + std::wstring wcmd = wchar_conv.from_bytes (cmd); + fd = ::_wpopen (wcmd.c_str (), L"r"); + } + catch (const std::range_error& e) + { + fd = ::popen (cmd.c_str (), "r"); + } + + std::ofstream fo; + try + { + std::wstring wfile = wchar_conv.from_bytes (dfile); + fo.open (wfile.c_str ()); + } + catch (const std::range_error& e) + { + fo.open (dfile.c_str ()); + } +#else FILE *fd = popen (cmd.c_str (), "r"); -#if defined (OCTAVE_USE_WINDOWS_API) - // FIXME: liboctinterp isn't linked in to mkoctfile. - // So we cannot use octave::sys::ofstream. Instead we fall back - // on using the functions available from libwrappers. - size_t srclen = dfile.length (); - const uint8_t *src = reinterpret_cast<const uint8_t *> - (dfile.c_str ()); - - size_t length = 0; - wchar_t *wchar = reinterpret_cast<wchar_t *> - (octave_u8_conv_to_encoding ("wchar_t", src, srclen, - &length)); - - std::ofstream fo; - if (wchar != nullptr) - { - fo.open (wchar); - free (static_cast<void *> (wchar)); - } - else - fo.open (dfile.c_str ()); -#else std::ofstream fo (dfile.c_str ()); #endif + size_t pos; while (! feof (fd)) { @@ -1102,33 +1123,34 @@ + vars["CPPFLAGS"] + ' ' + vars["ALL_CXXFLAGS"] + ' ' + incflags + ' ' + defs + ' ' + quote_path (f)); - // FIXME: Use wide character API for popen on Windows. +#if defined (OCTAVE_USE_WINDOWS_API) + FILE *fd; + try + { + std::wstring wcmd = wchar_conv.from_bytes (cmd); + fd = ::_wpopen (wcmd.c_str (), L"r"); + } + catch (const std::range_error& e) + { + fd = ::popen (cmd.c_str (), "r"); + } + + std::ofstream fo; + try + { + std::wstring wfile = wchar_conv.from_bytes (dfile); + fo.open (wfile.c_str ()); + } + catch (const std::range_error& e) + { + fo.open (dfile.c_str ()); + } +#else FILE *fd = popen (cmd.c_str (), "r"); -#if defined (OCTAVE_USE_WINDOWS_API) - // FIXME: liboctinterp isn't linked in to mkoctfile. - // So we cannot use octave::sys::ofstream. Instead we fall back - // on using the functions available from libwrappers. - size_t srclen = dfile.length (); - const uint8_t *src = reinterpret_cast<const uint8_t *> - (dfile.c_str ()); - - size_t length = 0; - wchar_t *wchar = reinterpret_cast<wchar_t *> - (octave_u8_conv_to_encoding ("wchar_t", src, srclen, - &length)); - - std::ofstream fo; - if (wchar != nullptr) - { - fo.open (wchar); - free (static_cast<void *> (wchar)); - } - else - fo.open (dfile.c_str ()); -#else std::ofstream fo (dfile.c_str ()); #endif + size_t pos; while (! feof (fd)) {
--- a/src/module.mk Sat Apr 17 12:21:35 2021 +0200 +++ b/src/module.mk Sat Apr 17 12:21:48 2021 +0200 @@ -74,7 +74,8 @@ %canon_reldir%_octave_LDFLAGS = \ $(NO_UNDEFINED_LDFLAG) \ $(OCTAVE_LINK_OPTS) \ - $(WARN_LDFLAGS) + $(WARN_LDFLAGS) \ + $(OCTAVE_UNICODE_EXE_LDFLAGS) if AMCOND_BUILD_QT_GUI OCTAVE_CPPFLAGS = -DHAVE_OCTAVE_QT_GUI @@ -94,7 +95,8 @@ %canon_reldir%_octave_cli_LDFLAGS = \ $(NO_UNDEFINED_LDFLAG) \ $(OCTAVE_LINK_OPTS) \ - $(WARN_LDFLAGS) + $(WARN_LDFLAGS) \ + $(OCTAVE_UNICODE_EXE_LDFLAGS) %canon_reldir%_octave_cli_CPPFLAGS = \ $(SRC_DIR_CPPFLAGS) \ @@ -119,7 +121,8 @@ %canon_reldir%_octave_gui_LDFLAGS = \ $(NO_UNDEFINED_LDFLAG) \ $(OCTAVE_GUI_LINK_OPTS) \ - $(WARN_LDFLAGS) + $(WARN_LDFLAGS) \ + $(OCTAVE_UNICODE_EXE_LDFLAGS) %canon_reldir%_octave_svgconvert_SOURCES = %reldir%/octave-svgconvert.cc @@ -127,7 +130,9 @@ %canon_reldir%_octave_svgconvert_LDADD = $(QT_LIBS) -%canon_reldir%_octave_svgconvert_LDFLAGS = $(QT_LDFLAGS) +%canon_reldir%_octave_svgconvert_LDFLAGS = \ + $(QT_LDFLAGS) \ + $(OCTAVE_UNICODE_EXE_LDFLAGS) %canon_reldir%_mkoctfile_SOURCES = @@ -137,6 +142,9 @@ liboctave/wrappers/libwrappers.la \ libgnu/libgnu.la $(LIBS) +%canon_reldir%_mkoctfile_LDFLAGS = \ + $(OCTAVE_UNICODE_EXE_LDFLAGS) + %canon_reldir%_mkoctfile_CPPFLAGS = \ $(SRC_DIR_CPPFLAGS) \ $(OCTAVE_CPPFLAGS) @@ -150,6 +158,9 @@ libgnu/libgnu.la \ $(LIBS) +%canon_reldir%_octave_config_LDFLAGS = \ + $(OCTAVE_UNICODE_EXE_LDFLAGS) + %canon_reldir%_octave_config_CPPFLAGS = \ $(SRC_DIR_CPPFLAGS) \ $(OCTAVE_CPPFLAGS)
--- a/src/octave-config.in.cc Sat Apr 17 12:21:35 2021 +0200 +++ b/src/octave-config.in.cc Sat Apr 17 12:21:48 2021 +0200 @@ -35,6 +35,12 @@ #include <algorithm> #include <cstdlib> +#if defined (OCTAVE_USE_WINDOWS_API) +# include <vector> +# include <locale> +# include <codecvt> +#endif + #if ! defined (OCTAVE_PREFIX) # define OCTAVE_PREFIX %OCTAVE_PREFIX% #endif @@ -139,9 +145,28 @@ vars["STARTUPFILEDIR"] = prepend_octave_home (%OCTAVE_STARTUPFILEDIR%); } +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +extern "C" +int +wmain (int argc, wchar_t **wargv) +{ + static char **argv = new char * [argc + 1]; + std::vector<std::string> argv_str; + + // convert wide character strings to multibyte UTF-8 strings + std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; + for (int i_arg = 0; i_arg < argc; i_arg++) + { + argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg])); + argv[i_arg] = &argv_str[i_arg][0]; + } + argv[argc] = nullptr; + +#else int main (int argc, char **argv) { +#endif initialize (); if (argc == 1)
--- a/src/octave-svgconvert.cc Sat Apr 17 12:21:35 2021 +0200 +++ b/src/octave-svgconvert.cc Sat Apr 17 12:21:48 2021 +0200 @@ -29,6 +29,12 @@ #include <iostream> +#if defined (OCTAVE_USE_WINDOWS_API) +# include <vector> +# include <locale> +# include <codecvt> +#endif + #include <QtCore> #include <QtXml> @@ -815,8 +821,28 @@ replace_polygons (parent_elt, collection[ii].first, collection[ii].second); } -int main(int argc, char *argv[]) +#if defined (OCTAVE_USE_WINDOWS_API) && defined (_UNICODE) +extern "C" +int +wmain (int argc, wchar_t **wargv) { + static char **argv = new char * [argc + 1]; + std::vector<std::string> argv_str; + + // convert wide character strings to multibyte UTF-8 strings + std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> wchar_conv; + for (int i_arg = 0; i_arg < argc; i_arg++) + { + argv_str.push_back (wchar_conv.to_bytes (wargv[i_arg])); + argv[i_arg] = &argv_str[i_arg][0]; + } + argv[argc] = nullptr; + +#else +int +main (int argc, char **argv) +{ +#endif const char *doc = "See \"octave-svgconvert -h\""; const char *help = "Usage:\n\ octave-svgconvert infile fmt dpi font reconstruct outfile\n\n\