[PATCH 1/2] Provide a method to use unicode command line arguments on Windows

Lubomir I. Ivanov neolit123 at gmail.com
Wed Oct 3 07:28:11 PDT 2012


From: "Lubomir I. Ivanov" <neolit123 at gmail.com>

For unicode command line characters Windows uses UTF-16, while Glib
and GTK use UTF-8. To solve that we retrieve the command line
as LPWSTR via CommandLineToArgvW() and use g_utf16_to_utf8()
to convert each argument.

Two new, OS abstracted functions appear in linux.c (NOP),
macos.c (NOP), windows.c:
subsurface_command_line_init(...)
subsurface_command_line_exit(...)
which are being called in main()

Signed-off-by: Lubomir I. Ivanov <neolit123 at gmail.com>
---
 dive.h    |  2 ++
 linux.c   | 10 ++++++++++
 macos.c   | 10 ++++++++++
 main.c    |  2 ++
 windows.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 66 insertions(+)

diff --git a/dive.h b/dive.h
index d05f1d1..b580b51 100644
--- a/dive.h
+++ b/dive.h
@@ -434,6 +434,8 @@ extern const char *star_strings[];
 extern const char *default_filename;
 extern const char *existing_filename;
 extern const char *subsurface_default_filename(void);
+extern void subsurface_command_line_init(int, char **);
+extern void subsurface_command_line_exit(int, char **);
 #define AIR_PERMILLE 209
 
 #define FRACTION(n,x) ((unsigned)(n)/(x)),((unsigned)(n)%(x))
diff --git a/linux.c b/linux.c
index 47a00a0..ee5c9e5 100644
--- a/linux.c
+++ b/linux.c
@@ -91,3 +91,13 @@ void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar,
 		divelist_font = DIVELIST_DEFAULT_FONT;
 	gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
 }
+
+void subsurface_command_line_init(int argc, char **argv)
+{
+	/* this is a no-op */
+}
+
+void subsurface_command_line_exit(int argc, char **argv)
+{
+	/* this is a no-op */
+}
diff --git a/macos.c b/macos.c
index d0d7a74..67cd0be 100644
--- a/macos.c
+++ b/macos.c
@@ -149,3 +149,13 @@ void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar,
 
 	gtk_osxapplication_ready(osx_app);
 }
+
+void subsurface_command_line_init(int argc, char **argv)
+{
+	/* this is a no-op */
+}
+
+void subsurface_command_line_exit(int argc, char **argv)
+{
+	/* this is a no-op */
+}
diff --git a/main.c b/main.c
index 7101b8b..aa0bcb7 100644
--- a/main.c
+++ b/main.c
@@ -223,6 +223,7 @@ int main(int argc, char **argv)
 
 	output_units = SI_units;
 
+	subsurface_command_line_init(argc, argv);
 	parse_xml_init();
 
 	init_ui(&argc, &argv);
@@ -268,6 +269,7 @@ int main(int argc, char **argv)
 	exit_ui();
 
 	parse_xml_exit();
+	subsurface_command_line_exit(argc, argv);
 
 #ifdef DEBUGFILE
 	if (debugfile)
diff --git a/windows.c b/windows.c
index b6e10bb..cc3f02f 100644
--- a/windows.c
+++ b/windows.c
@@ -124,3 +124,45 @@ void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar,
 		divelist_font = DIVELIST_DEFAULT_FONT;
 	gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
 }
+
+static LPWSTR *wargv;
+
+/* we retrieve the unicode command line as UTF-16 and store each argument
+ * in place of the old one as Glib's UTF-8 */
+void subsurface_command_line_init(int argc, char **argv)
+{
+	int wargc, i;
+	gchar *s;
+
+	wargv = CommandLineToArgvW(GetCommandLineW(), &wargc);
+	if (argc == wargc && wargv) {
+		for (i = 0; i < wargc; i++) {
+			s = g_utf16_to_utf8(wargv[i], -1, NULL, NULL, NULL);
+			if (!g_utf8_validate(s, -1, NULL)) {
+				g_warning("Cannot validate command line argument %s (%d)", s, (i + 1));
+				continue;
+			}
+			/* The standard allows us to modify the argument list - C90, 5.1.2.2.1.
+			 * Another question is how safe and moral it actually is. In general
+			 * its not much of a protection term to put this memory in a read-only
+			 * VAS area, anyway. If someone can write in a program's address space
+			 * on runtime overwriting the command line arguments becomes almost
+			 * irrelevant. */
+			if (argv[i])
+				free(argv[i]);
+			argv[i] = s;
+		}
+		LocalFree(wargv);
+		return;
+	}
+	g_warning("Cannot convert command line");
+}
+
+/* once done, free the argument list */
+void subsurface_command_line_exit(int argc, char **argv)
+{
+	int i;
+	for (i = 0; i < argc; i++)
+		if (argv[i])
+			free(argv[i]);
+}
-- 
1.7.11.msysgit.0



More information about the subsurface mailing list