Add commandline conversion for Windows (no-op on other platforms)
- add Fl::args_to_utf8() to convert commandline arguments to UTF-8 This new function closes the gap that previously only Visual Studio applications converted their commandlines to UTF-8. Tested with MinGW, MSYS2/MinGW-w64, and Visual Studio (2019).
This commit is contained in:
parent
a0e4a3fd5d
commit
727bd94560
3
FL/Fl.H
3
FL/Fl.H
@ -1398,6 +1398,9 @@ public:
|
||||
|
||||
static int system(const char *command);
|
||||
|
||||
// Convert Windows commandline arguments to UTF-8 (documented in src/Fl.cxx)
|
||||
static int args_to_utf8(int argc, char ** &argv);
|
||||
|
||||
#ifdef FLTK_HAVE_CAIRO
|
||||
/** \defgroup group_cairo Cairo Support Functions and Classes
|
||||
@{
|
||||
|
@ -11,7 +11,16 @@
|
||||
// usual *nix idiom of "option=value", and provides no validation nor
|
||||
// conversion of the parameter string into ints or floats.
|
||||
//
|
||||
// Copyright 1998-2020 by Bill Spitzak and others.
|
||||
// Example 1:
|
||||
//
|
||||
// ./howto-parse-args -ti "FLTK is great" -o "FLTK is a great GUI tool"
|
||||
//
|
||||
// Example 2: translated to Japanese and simplified Chinese, respectively,
|
||||
// by a well known internet translation service.
|
||||
//
|
||||
// ./howto-parse-args -ti "FLTKは素晴らしいです" -o "FLTK 是一个很棒的 GUI 工具"
|
||||
//
|
||||
// Copyright 1998-2023 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
@ -42,13 +51,14 @@ char *optionString = 0;
|
||||
* returns 1 if argv[i] matches on its own,
|
||||
* returns 0 if argv[i] does not match.
|
||||
*/
|
||||
int arg(int argc, char **argv, int &i)
|
||||
{
|
||||
int arg(int argc, char **argv, int &i) {
|
||||
|
||||
if (strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
|
||||
helpFlag = 1;
|
||||
i += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strcmp("-o", argv[i]) == 0 || strcmp("--option", argv[i]) == 0) {
|
||||
if (i < argc-1 && argv[i+1] != 0) {
|
||||
optionString = argv[i+1];
|
||||
@ -59,8 +69,13 @@ int arg(int argc, char **argv, int &i)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
// Convert commandline arguments in 'argv' to UTF-8 on Windows.
|
||||
// This is a no-op on all other platforms (see documentation).
|
||||
|
||||
Fl::args_to_utf8(argc, argv);
|
||||
|
||||
int i = 1;
|
||||
if (Fl::args(argc, argv, i, arg) < argc)
|
||||
// note the concatenated strings to give a single format string!
|
||||
@ -84,6 +99,8 @@ int main(int argc, char** argv)
|
||||
textBox->label(optionString);
|
||||
else
|
||||
textBox->label("re-run with [-o|--option] text");
|
||||
|
||||
mainWin->resizable(mainWin);
|
||||
mainWin->show(argc, argv);
|
||||
return Fl::run();
|
||||
}
|
||||
|
@ -578,9 +578,14 @@ list (APPEND SHARED_FILES ${HEADER_FILES} ${DRIVER_HEADER_FILES})
|
||||
|
||||
set (STATIC_FILES ${SHARED_FILES})
|
||||
|
||||
if (MSVC)
|
||||
# Visual Studio (MSVC) is known to need WinMain() and maybe BORLAND
|
||||
# needs it as well, hence we include it on all Windows platforms.
|
||||
# The GNU compilers (MinGW, MSYS2, Cygwin) disable compilation inside
|
||||
# the source file which is what we finally want and need.
|
||||
|
||||
if (WIN32)
|
||||
list (APPEND STATIC_FILES fl_call_main.c)
|
||||
endif (MSVC)
|
||||
endif ()
|
||||
|
||||
#######################################################################
|
||||
|
||||
|
73
src/Fl.cxx
73
src/Fl.cxx
@ -2281,3 +2281,76 @@ FL_EXPORT const char* fl_local_shift = Fl::system_driver()->shift_name();
|
||||
FL_EXPORT const char* fl_local_meta = Fl::system_driver()->meta_name();
|
||||
FL_EXPORT const char* fl_local_alt = Fl::system_driver()->alt_name();
|
||||
FL_EXPORT const char* fl_local_ctrl = Fl::system_driver()->control_name();
|
||||
|
||||
/**
|
||||
Convert Windows commandline arguments to UTF-8.
|
||||
|
||||
\note This function does nothing on other (non-Windows) platforms, hence
|
||||
you may call it on all platforms or only on Windows by using platform
|
||||
specific code like <tt>'\#ifdef _WIN32'</tt> etc. - it's your choice.
|
||||
Calling it on other platforms returns quickly w/o wasting much CPU time.
|
||||
|
||||
This function <i>must be called <b>on Windows platforms</b></i> in \c main()
|
||||
before the array \c argv is used if your program uses any commandline
|
||||
argument strings (these should be UTF-8 encoded).
|
||||
This applies also to standard FLTK commandline arguments like
|
||||
"-name" (class name) and "-title" (window title in the title bar).
|
||||
|
||||
Unfortunately Windows \b neither provides commandline arguments in UTF-8
|
||||
encoding \b nor as Windows "Wide Character" strings in the standard
|
||||
\c main() and/or the Windows specific \c WinMain() function.
|
||||
|
||||
On Windows platforms (no matter which build system) this function calls
|
||||
a Windows specific function to retrieve commandline arguments as Windows
|
||||
"Wide Character" strings, converts these strings to an internally allocated
|
||||
buffer (or multiple buffers) and returns the result in \c argv.
|
||||
For implementation details please refer to the source code; however these
|
||||
details may be changed in the future.
|
||||
|
||||
Note that \c argv is provided by reference so it can be overwritten.
|
||||
|
||||
In the recommended simple form the function overwrites the variable
|
||||
\c argv and allocates a new array of strings pointed to by \c argv.
|
||||
You may use this form on all platforms and it is as simple as adding
|
||||
one line to old programs to make them work with international (UTF-8)
|
||||
commandline arguments.
|
||||
|
||||
\code
|
||||
int main(int argc, char **argv) {
|
||||
Fl::args_to_utf8(argc, argv); // add this line
|
||||
// ... use argc and argv, e.g. for commandline parsing
|
||||
window->show(argc, argv);
|
||||
return Fl::run();
|
||||
}
|
||||
\endcode
|
||||
|
||||
For an example see 'examples/howto-parse-args.cxx' in the FLTK sources.
|
||||
|
||||
If you want to retain the original \c argc and \c argv variables the
|
||||
following slightly longer and more complicated code works as well on
|
||||
all platforms.
|
||||
|
||||
\code
|
||||
int main(int argc, char **argv) {
|
||||
char **argvn = argv; // must copy argv to work on all platforms
|
||||
int argcn = Fl::args_to_utf8(argc, argvn);
|
||||
// ... use argcn and argvn, e.g. for commandline parsing
|
||||
window->show(argcn, argvn);
|
||||
return Fl::run();
|
||||
}
|
||||
\endcode
|
||||
|
||||
\param[in] argc used only on non-Windows platforms
|
||||
\param[out] argv modified only on Windows platforms
|
||||
\returns argument count (always the same as argc)
|
||||
|
||||
\since 1.4.0
|
||||
|
||||
\internal This function must not open the display, otherwise
|
||||
commandline processing (e.g. by fluid) would open the display.
|
||||
OTOH calling it when the display is opened wouldn't work either
|
||||
for the same reasons ('fluid -c' doesn't open the display).
|
||||
*/
|
||||
int Fl::args_to_utf8(int argc, char ** &argv) {
|
||||
return Fl::system_driver()->args_to_utf8(argc, argv);
|
||||
}
|
||||
|
@ -110,6 +110,10 @@ public:
|
||||
virtual int rmdir(const char*) {return -1;}
|
||||
virtual int rename(const char* /*f*/, const char * /*n*/) {return -1;}
|
||||
|
||||
// Windows commandline argument conversion to UTF-8.
|
||||
// Default implementation: no-op, overridden only on Windows
|
||||
virtual int args_to_utf8(int argc, char ** &argv) { return argc; }
|
||||
|
||||
// the default implementation of these utf8... functions should be enough
|
||||
virtual unsigned utf8towc(const char* src, unsigned srclen, wchar_t* dst, unsigned dstlen);
|
||||
virtual unsigned utf8fromwc(char* dst, unsigned dstlen, const wchar_t* src, unsigned srclen);
|
||||
@ -124,9 +128,9 @@ public:
|
||||
virtual int filename_list(const char * /*d*/, dirent ***,
|
||||
int (* /*sort*/)(struct dirent **, struct dirent **),
|
||||
char *errmsg=NULL, int errmsg_sz=0) {
|
||||
(void)errmsg; (void)errmsg_sz;
|
||||
return -1;
|
||||
}
|
||||
(void)errmsg; (void)errmsg_sz;
|
||||
return -1;
|
||||
}
|
||||
// the default implementation of filename_expand() may be enough
|
||||
virtual int filename_expand(char *to, int tolen, const char *from);
|
||||
// to implement
|
||||
|
@ -61,11 +61,15 @@ public:
|
||||
int mkdir(const char *fnam, int mode) FL_OVERRIDE;
|
||||
int rmdir(const char *fnam) FL_OVERRIDE;
|
||||
int rename(const char *fnam, const char *newnam) FL_OVERRIDE;
|
||||
// Windows commandline argument conversion to UTF-8
|
||||
int args_to_utf8(int argc, char ** &argv) FL_OVERRIDE;
|
||||
// Windows specific UTF-8 conversions
|
||||
unsigned utf8towc(const char *src, unsigned srclen, wchar_t* dst, unsigned dstlen) FL_OVERRIDE;
|
||||
unsigned utf8fromwc(char *dst, unsigned dstlen, const wchar_t* src, unsigned srclen) FL_OVERRIDE;
|
||||
int utf8locale() FL_OVERRIDE;
|
||||
unsigned utf8to_mb(const char *src, unsigned srclen, char *dst, unsigned dstlen) FL_OVERRIDE;
|
||||
unsigned utf8from_mb(char *dst, unsigned dstlen, const char *src, unsigned srclen) FL_OVERRIDE;
|
||||
|
||||
int clocale_vprintf(FILE *output, const char *format, va_list args) FL_OVERRIDE;
|
||||
int clocale_vsnprintf(char *output, size_t output_size, const char *format, va_list args) FL_OVERRIDE;
|
||||
int clocale_vsscanf(const char *input, const char *format, va_list args) FL_OVERRIDE;
|
||||
|
@ -299,6 +299,40 @@ int Fl_WinAPI_System_Driver::rename(const char *fnam, const char *newnam) {
|
||||
return _wrename(wbuf, wbuf1);
|
||||
}
|
||||
|
||||
// See Fl::args_to_utf8()
|
||||
int Fl_WinAPI_System_Driver::args_to_utf8(int argc, char ** &argv) {
|
||||
int i;
|
||||
char strbuf[2048]; // FIXME: allocate argv and strings dynamically
|
||||
|
||||
// Convert the command line arguments to UTF-8
|
||||
LPWSTR *wideArgv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
argv = (char **)malloc((argc + 1) * sizeof(char *));
|
||||
for (i = 0; i < argc; i++) {
|
||||
int ret = WideCharToMultiByte(CP_UTF8, // CodePage
|
||||
0, // dwFlags
|
||||
wideArgv[i], // lpWideCharStr
|
||||
-1, // cchWideChar
|
||||
strbuf, // lpMultiByteStr
|
||||
sizeof(strbuf), // cbMultiByte
|
||||
NULL, // lpDefaultChar
|
||||
NULL); // lpUsedDefaultChar
|
||||
|
||||
if (!ret)
|
||||
strbuf[0] = '\0'; // return empty string
|
||||
argv[i] = fl_strdup(strbuf);
|
||||
}
|
||||
argv[argc] = NULL; // required NULL pointer at end of list
|
||||
|
||||
// Free the wide character string array
|
||||
LocalFree(wideArgv);
|
||||
|
||||
// Note: the allocated memory or argv[] will not be free'd by the system
|
||||
// on exit. This does not constitute a memory leak.
|
||||
|
||||
return argc;
|
||||
}
|
||||
|
||||
|
||||
// Two Windows-specific functions fl_utf8_to_locale() and fl_locale_to_utf8()
|
||||
// from file fl_utf8.cxx are put here for API compatibility
|
||||
|
||||
|
@ -22,29 +22,40 @@
|
||||
* "main()". This will allow you to build a Windows Application
|
||||
* without any special settings.
|
||||
*
|
||||
* Because of problems with the Microsoft Visual C++ header files
|
||||
* and/or compiler, you cannot have a WinMain function in a DLL.
|
||||
* I don't know why. Thus, this nifty feature is only available
|
||||
* if you link to the static library.
|
||||
* You cannot have this WinMain() function in a DLL because it would have
|
||||
* to call \c main() outside the DLL. Thus, this nifty feature is only
|
||||
* available if you link to the static library.
|
||||
*
|
||||
* Currently the debug version of this library will create a
|
||||
* console window for your application so you can put printf()
|
||||
* statements for debugging or informational purposes. Ultimately
|
||||
* we want to update this to always use the parent's console,
|
||||
* but at present we have not identified a function or API in
|
||||
* Microsoft(r) Windows(r) that allows for it.
|
||||
* However, it is possible to build this module separately so you can
|
||||
* use it in progams that link to the shared library.
|
||||
*
|
||||
* Currently the debug version of this library will create a console window
|
||||
* for your application so you can put printf() statements for debugging or
|
||||
* informational purposes. Ultimately we want to update this to always use
|
||||
* the parent's console, but at present we have not identified a function
|
||||
* or API in Microsoft(r) Windows(r) that allows for it.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file is compiled only on Windows platforms (since FLTK 1.4.0).
|
||||
* Therefore we don't need to test the _WIN32 macro anymore.
|
||||
* The _MSC_VER macro is tested to compile it only for Visual Studio
|
||||
* platforms because GNU platforms (MinGW, MSYS) don't need it.
|
||||
* Notes for FLTK developers:
|
||||
*
|
||||
* 1) Since FLTK 1.4.0 this file is compiled only on Windows, hence we don't
|
||||
* need to test the _WIN32 macro.
|
||||
* 2) This file must not call any FLTK library functions because this would
|
||||
* not work with /both/ the DLL /and/ the static library (linkage stuff).
|
||||
* 3) Converting the commandline arguments to UTF-8 is therefore implemented
|
||||
* here *and* in the library but this seems to be an acceptable compromise.
|
||||
* 4) (Unless someone finds a better solution, of course. Albrecht)
|
||||
* 5) The condition "!defined(FL_DLL)" prevents building this in the shared
|
||||
* library, i.e. "WinMain()" will not be defined in the shared lib (DLL).
|
||||
* 6) The condition "!defined (__GNUC__)" prevents compilation of this
|
||||
* module with MinGW, MSYS, and Cygwin which don't use WinMain().
|
||||
* 7) It is unclear if there are other build systems on Windows that need a
|
||||
* WinMain() entry point. Earlier comments and code seem to indicate that
|
||||
* Borland C++ would require it.
|
||||
*/
|
||||
#if !defined(FL_DLL) && !defined (__GNUC__)
|
||||
|
||||
#include <FL/fl_utf8.h>
|
||||
#include <FL/fl_string_functions.h>
|
||||
#if !defined(FL_DLL) && !defined (__GNUC__)
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
@ -78,9 +89,13 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
freopen("conout$", "w", stderr);
|
||||
#endif /* _DEBUG */
|
||||
|
||||
/* Convert the command line arguments to UTF-8 */
|
||||
/* Get the command line arguments as Windows Wide Character strings */
|
||||
LPWSTR *wideArgv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
|
||||
/* Allocate an array of 'argc + 1' string pointers */
|
||||
argv = (char **)malloc((argc + 1) * sizeof(char *));
|
||||
|
||||
/* Convert the command line arguments to UTF-8 */
|
||||
for (i = 0; i < argc; i++) {
|
||||
int ret = WideCharToMultiByte(CP_UTF8, /* CodePage */
|
||||
0, /* dwFlags */
|
||||
@ -90,7 +105,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
sizeof(strbuf), /* cbMultiByte */
|
||||
NULL, /* lpDefaultChar */
|
||||
NULL); /* lpUsedDefaultChar */
|
||||
argv[i] = fl_strdup(strbuf);
|
||||
argv[i] = _strdup(strbuf);
|
||||
}
|
||||
argv[argc] = NULL; // required by C standard at end of list
|
||||
|
||||
@ -118,6 +133,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* STR# 2973: solves "empty translation unit" error */
|
||||
typedef int dummy;
|
||||
|
||||
#endif /* !defined(FL_DLL) && !defined (__GNUC__) */
|
||||
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// A shared image test program for the Fast Light Tool Kit (FLTK).
|
||||
//
|
||||
// Copyright 1998-2022 by Bill Spitzak and others.
|
||||
// Copyright 1998-2023 by Bill Spitzak and others.
|
||||
//
|
||||
// This library is free software. Distribution and use rights are outlined in
|
||||
// the file "COPYING" which should have been included with this file. If this
|
||||
@ -143,7 +143,8 @@ int main(int argc, char **argv) {
|
||||
setlocale(LC_ALL, ""); // enable multilanguage errors in file chooser
|
||||
fl_register_images();
|
||||
|
||||
Fl::args(argc,argv,i,arg);
|
||||
Fl::args_to_utf8(argc, argv); // enable multilanguage commandlines on Windows
|
||||
Fl::args(argc, argv, i, arg); // parse commandline
|
||||
|
||||
if (animate)
|
||||
Fl_GIF_Image::animate = true; // create animated shared .GIF images (e.g. file chooser)
|
||||
|
Loading…
Reference in New Issue
Block a user