summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Dierking <aarond@fb.com>2018-07-05 14:47:47 -0700
committerGuillem Jover <guillem@hadrons.org>2021-02-07 01:28:27 +0100
commit68f980c90d914e5fd6f7512e00dec334dbb71bed (patch)
treed28e353bdbb92179bdf34d904600b1e753043602
parent37a9b56c05339301510213c41fc507ea31cc2464 (diff)
Provide a default progname on Windows
[guillem@hadrons.org: - Remove .exe extension from default program name. - Call reallocarray() once by switching to a «do {} while» loop. - Minor coding style fixes. ] Signed-off-by: Guillem Jover <guillem@hadrons.org>
-rw-r--r--src/progname.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/src/progname.c b/src/progname.c
index 3edbf24..bebf714 100644
--- a/src/progname.c
+++ b/src/progname.c
@@ -1,6 +1,7 @@
/*
* Copyright © 2006 Robert Millan
* Copyright © 2010-2012 Guillem Jover <guillem@hadrons.org>
+ * Copyright © 2018 Facebook, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,11 +31,16 @@
* <https://sourceware.org/ml/libc-alpha/2006-03/msg00125.html>.
*/
+#include <sys/param.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#ifdef _WIN32
+#include <Windows.h>
+#include <shlwapi.h>
+#endif
-#if defined(_WIN32) || defined(__WIN32__) || defined(__WINDOWS__)
+#ifdef _WIN32
#define LIBBSD_IS_PATHNAME_SEPARATOR(c) ((c) == '/' || (c) == '\\')
#else
#define LIBBSD_IS_PATHNAME_SEPARATOR(c) ((c) == '/')
@@ -56,6 +62,70 @@ getprogname(void)
/* getexecname(3) returns an absolute pathname, normalize it. */
if (__progname == NULL)
setprogname(getexecname());
+#elif defined(_WIN32)
+ if (__progname == NULL) {
+ WCHAR *wpath = NULL;
+ WCHAR *wname = NULL;
+ WCHAR *wext = NULL;
+ DWORD wpathsiz = MAX_PATH / 2;
+ DWORD len, i;
+ char *mbname = NULL;
+ int mbnamesiz;
+
+ /* Use the Unicode version of this function to support long
+ * paths. MAX_PATH isn't actually the maximum length of a
+ * path in this case. */
+ do {
+ WCHAR *wpathnew;
+
+ wpathsiz *= 2;
+ wpathsiz = MIN(wpathsiz, UNICODE_STRING_MAX_CHARS);
+ wpathnew = reallocarray(wpath, wpathsiz, sizeof(*wpath));
+ if (wpathnew == NULL)
+ goto done;
+ wpath = wpathnew;
+
+ len = GetModuleFileNameW(NULL, wpath, wpathsiz);
+ if (wpathsiz == UNICODE_STRING_MAX_CHARS)
+ goto done;
+ } while (wpathsiz == len);
+ if (len == 0)
+ goto done;
+
+ /* GetModuleFileNameW() retrieves an absolute path. Locate the
+ * filename now to only convert necessary characters and save
+ * memory. */
+ wname = wpath;
+ for (i = len; i > 0; i--) {
+ if (LIBBSD_IS_PATHNAME_SEPARATOR(wpath[i - 1])) {
+ wname = wpath + i;
+ break;
+ }
+ }
+
+ /* Remove any trailing extension, such as '.exe', to make the
+ * behavior mach the non-Windows systems. */
+ wext = PathFindExtensionW(wname);
+ wext[0] = '\0';
+
+ mbnamesiz = WideCharToMultiByte(CP_UTF8, 0, wname, -1, NULL,
+ 0, NULL, NULL);
+ if (mbnamesiz == 0)
+ goto done;
+ mbname = malloc(mbnamesiz);
+ if (mbname == NULL)
+ goto done;
+ mbnamesiz = WideCharToMultiByte(CP_UTF8, 0, wname, -1, mbname,
+ mbnamesiz, NULL, NULL);
+ if (mbnamesiz == 0)
+ goto done;
+ __progname = mbname;
+ mbname = NULL;
+
+done:
+ free(wpath);
+ free(mbname);
+ }
#endif
return __progname;