From f928be5061744bb38c3aff8ea41dbd0c42851cbc Mon Sep 17 00:00:00 2001 From: "Lubomir I. Ivanov" Date: Thu, 4 Oct 2012 03:44:47 +0300 Subject: Provide a method to use unicode command line arguments on Windows For unicode command line characters Windows uses UTF-16, while Glib and GTK use UTF-8. To solve that we retrieve the command line via __wgetmainargs() and use g_utf16_to_utf8() to convert each argument. The used method should support wildcards passed as arguments (e.g. *.xml). 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 Signed-off-by: Dirk Hohndel --- dive.h | 2 ++ linux.c | 10 ++++++++++ macos.c | 10 ++++++++++ main.c | 2 ++ windows.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 78 insertions(+) diff --git a/dive.h b/dive.h index d05f1d1b4..2c224a12d 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(gint *, gchar ***); +extern void subsurface_command_line_exit(gint *, gchar ***); #define AIR_PERMILLE 209 #define FRACTION(n,x) ((unsigned)(n)/(x)),((unsigned)(n)%(x)) diff --git a/linux.c b/linux.c index 47a00a059..4e7e61c7c 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(gint *argc, gchar ***argv) +{ + /* this is a no-op */ +} + +void subsurface_command_line_exit(gint *argc, gchar ***argv) +{ + /* this is a no-op */ +} diff --git a/macos.c b/macos.c index d0d7a742b..17ae4a411 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(gint *argc, gchar ***argv) +{ + /* this is a no-op */ +} + +void subsurface_command_line_exit(gint *argc, gchar ***argv) +{ + /* this is a no-op */ +} diff --git a/main.c b/main.c index 7101b8b87..bc7bf7af1 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 b6e10bb71..f2f06f9a0 100644 --- a/windows.c +++ b/windows.c @@ -124,3 +124,57 @@ void subsurface_ui_setup(GtkSettings *settings, GtkWidget *menubar, divelist_font = DIVELIST_DEFAULT_FONT; gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0); } + +/* barely documented API */ +extern int __wgetmainargs(int *, wchar_t ***, wchar_t ***, int, int *); + +/* expand-convert the UTF-16 argument list to a list of UTF-8 strings */ +void subsurface_command_line_init(gint *argc, gchar ***argv) +{ + wchar_t **wargv, **wenviron; + gchar **argv_new; + gchar *s; + /* for si we assume that a struct address will equal the address + * of its first and only int member */ + gint i, n, ret, si; + + /* memory leak tools may reports a potential issue here at a call + * to strcpy_s in msvcrt, wich should be a false positive. but even if there + * is some kind of a leak, it should be unique and have the same + * lifespan as the process heap. */ + ret = __wgetmainargs(&n, &wargv, &wenviron, TRUE, &si); + if (ret < 0) { + g_warning("Cannot convert command line"); + return; + } + argv_new = g_malloc(sizeof(gchar *) * (n + 1)); + + for (i = 0; i < n; ++i) { + s = g_utf16_to_utf8((gunichar2 *)wargv[i], -1, NULL, NULL, NULL); + if (!s) { + g_warning("Cannot convert command line argument (%d) to UTF-8", (i + 1)); + s = "\0"; + } else if (!g_utf8_validate(s, -1, NULL)) { + g_warning("Cannot validate command line argument '%s' (%d)", s, (i + 1)); + g_free(s); + s = "\0"; + } + argv_new[i] = s; + } + argv_new[n] = NULL; + + /* update the argument list and count */ + if (argv && argc) { + *argv = argv_new; + *argc = n; + } +} + +/* once done, free the argument list */ +void subsurface_command_line_exit(gint *argc, gchar ***argv) +{ + int i; + for (i = 0; i < *argc; i++) + g_free((*argv)[i]); + g_free(*argv); +} -- cgit v1.2.3-70-g09d2