From 68f980c90d914e5fd6f7512e00dec334dbb71bed Mon Sep 17 00:00:00 2001 From: Aaron Dierking Date: Thu, 5 Jul 2018 14:47:47 -0700 Subject: Provide a default progname on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [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 --- src/progname.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) 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 + * 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 @@ * . */ +#include #include #include #include +#ifdef _WIN32 +#include +#include +#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; -- cgit v1.2.3