filenames on MS Windows: follow-up

Allin Cottrell <[email protected]>
Newsgroups gmane.comp.graphics.gnuplot.devel
Message-ID <[email protected]>
I'm attaching a patch against gnuplot git master which does what I 
mentioned in 
https://sourceforge.net/p/gnuplot/mailman/message/37141539/ That is, 
it allows wgnuplot.exe to accept via the Windows command-line 
unicode filenames that cannot be represented in the user's "system 
codepage", and to successfully to open such files.

This iteration of my patch uses native win32 APIs to perform the 
necessary recoding of filenames, as opposed to the previous 
iteration which used GLib.

I gave evidence in 
https://sourceforge.net/p/gnuplot/mailman/message/37143153/
that the patch is not disruptive of gnuplot's ability to open files 
named via the "load" command, in which case the encoding specified 
in the gnuplot script must be respected.

The patch is activated only when compiling the program for Windows, 
and then only when the symbol WIDE_ARGS is defined.

-- 
Allin Cottrell
Department of Economics
Wake Forest University

_______________________________________________
gnuplot-beta mailing list
[email protected]
Membership management via: https://lists.sourceforge.net/lists/listinfo/gnuplot-beta
wide_args.diff (text/plain, 3.8 KB)
diff --git a/src/misc.c b/src/misc.c
index b1fd32c5d..998f93be4 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -49,6 +49,9 @@
 # if defined(__WATCOMC__) || defined(_MSC_VER)
 #  include <io.h>        /* for setmode() */
 # endif
+# ifdef WIDE_ARGS
+#  include <windows.h>
+# endif
 #endif
 
 static void prepare_call(int calltype);
@@ -514,6 +517,49 @@ load_file_error()
     while (lf_pop());
 }
 
+#ifdef WIDE_ARGS
+
+wchar_t *win32_utf8_to_utf16 (const char *s)
+{
+    wchar_t *ret = NULL;
+    int len;
+
+    len = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0);
+    if (len > 0) {
+	ret = malloc(len * sizeof *ret);
+	MultiByteToWideChar(CP_UTF8, 0, s, -1, ret, len);
+    }
+
+    return ret;
+}
+
+#endif
+
+static FILE *
+alt_fopen(const char *filename, const char *mode)
+{
+    FILE *fp = fopen(filename, mode);
+
+#ifdef WIDE_ARGS
+    if (fp == NULL) {
+	wchar_t *wfname;
+
+	wfname = win32_utf8_to_utf16(filename);
+	if (wfname != NULL) {
+	    size_t len = strlen(mode) + 1;
+	    wchar_t *wmode = calloc(len, sizeof *wmode);
+
+	    mbstowcs(wmode, mode, len);
+	    fp = _wfopen(wfname, wmode);
+	    free(wmode);
+	    free(wfname);
+	}
+    }
+#endif
+
+    return fp;
+}
+
 FILE *
 loadpath_fopen(const char *filename, const char *mode)
 {
@@ -535,7 +581,7 @@ loadpath_fopen(const char *filename, const char *mode)
 	    return (FILE *) 0;
     } else
 #endif /* PIPES */
-    if ((fp = fopen(filename, mode)) == (FILE *) NULL) {
+    if ((fp = alt_fopen(filename, mode)) == (FILE *) NULL) {
 	/* try 'loadpath' variable */
 	char *fullname = NULL, *path;
 
@@ -544,7 +590,7 @@ loadpath_fopen(const char *filename, const char *mode)
 	    fullname = gp_realloc(fullname, strlen(path) + 1 + strlen(filename) + 1, "loadpath_fopen");
 	    strcpy(fullname, path);
 	    PATH_CONCAT(fullname, filename);
-	    if ((fp = fopen(fullname, mode)) != NULL) {
+	    if ((fp = alt_fopen(fullname, mode)) != NULL) {
 		/* free(fullname); */
 		loadpath_fontname = fullname;
 		fullname = NULL;
diff --git a/src/win/winmain.c b/src/win/winmain.c
index 0fd3de027..0efcd36ce 100644
--- a/src/win/winmain.c
+++ b/src/win/winmain.c
@@ -424,6 +424,56 @@ ReadMainIni(LPTSTR file, LPTSTR section)
     }
 }
 
+#ifdef WIDE_ARGS
+
+static char *win32_utf16_to_utf8 (wchar_t *w)
+{
+    char *ret = NULL;
+    int len;
+
+    len = WideCharToMultiByte(CP_UTF8, 0, w, -1, NULL, 0, NULL, NULL);
+    if (len > 0) {
+	ret = malloc(len);
+	WideCharToMultiByte(CP_UTF8, 0, w, -1, ret, len, NULL, NULL);
+    }
+
+    return ret;
+}
+
+static int alt_winargs (int *pargc, char ***pargv)
+{
+    int argc_w = 0;
+    LPWSTR *argv_w;
+    int err = 0;
+
+    /* get args as UTF-16 */
+    argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w);
+
+    if (argv_w == NULL) {
+	err = 1;
+    } else {
+	/* convert args to UTF-8, so they can be passed
+	   and read as char * by gnu_main()
+	*/
+	char **argv_u8 = calloc(argc_w, sizeof *argv_u8);
+	int i;
+
+	for (i=0; i<argc_w && !err; i++) {
+	    argv_u8[i] = win32_utf16_to_utf8(argv_w[i]);
+	    if (argv_u8[i] == NULL) {
+		err = 1;
+	    }
+	}
+	*pargc = argc_w;
+	*pargv = argv_u8;
+	/* we're done with this */
+	LocalFree(argv_w);
+    }
+
+    return err;
+}
+
+#endif
 
 #ifndef WGP_CONSOLE
 int WINAPI
@@ -441,10 +491,14 @@ main(int argc, char **argv)
 #endif
 
 #ifndef WGP_CONSOLE
-# if defined( __MINGW32__) && !defined(_W64)
+# if defined(__MINGW32__) && !defined(_W64)
 #  define argc _argc
 #  define argv _argv
-# else /* MSVC, WATCOM, MINGW-W64 */
+# elif defined(WIDE_ARGS)
+    int argc = 0;
+    char **argv = NULL;
+    alt_winargs(&argc, &argv);
+# else /* MSVC, WATCOM */
 #  define argc __argc
 #  define argv __argv
 # endif
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.