Skip to content

Commit

Permalink
port shell_quote() to wchar_t and use it on Windows spawning my_perl
Browse files Browse the repository at this point in the history
  • Loading branch information
rschupp committed Feb 3, 2024
1 parent e8192fd commit 8697780
Showing 1 changed file with 76 additions and 76 deletions.
152 changes: 76 additions & 76 deletions myldr/boot.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#undef readdir

#ifdef _MSC_VER
#ifdef WIN32
#include <windows.h>
#include <wchar.h>
#include <stdio.h>
#include <shellapi.h>
#include <stringapiset.h>
Expand Down Expand Up @@ -151,48 +152,105 @@ void seek_to_subsystem( int fd ) {
}

/* algorithm stolen from Win32::ShellQuote, in particular quote_literal() */
char* shell_quote(const char *src)
wchar_t* shell_quote_wide(const wchar_t *src)
{
/* some characters from src may be replaced with two chars,
* add enclosing quotes and trailing \0 */
char *dst = malloc(2 * strlen(src) + 3);
wchar_t *dst = malloc((2 * wcslen(src) + 3) * sizeof(wchar_t));

const char *p = src;
char *q = dst;
char c;
const wchar_t *p = src;
wchar_t *q = dst;
wchar_t c;

*q++ = '"'; /* opening quote */
*q++ = L'"'; /* opening quote */

while (c = *p)
while ((c = *p))
{
if (c == '\\')
if (c == L'\\')
{
int n = strspn(p, "\\"); /* span of backslashes starting at p */
int n = wcsspn(p, L"\\"); /* span of backslashes starting at p */

memcpy(q, p, n); /* copy the span */
wmemcpy(q, p, n);
q += n;

if (p[n] == '\0' || p[n] == '"') /* span ends in quote or NUL */
if (p[n] == L'\0' || p[n] == L'"') /* span ends in quote or NUL */
{
memcpy(q, p, n); /* copy the span once more */
wmemcpy(q, p, n);
q += n;
}

p += n; /* advance over the span */
continue;
}

if (c == '"')
*q++ = '\\'; /* escape the following quote */
if (c == L'"')
*q++ = L'\\'; /* escape the following quote */
*q++ = c;
p++;
}

*q++ = '"'; /* closing quote */
*q++ = '\0';
*q++ = L'"'; /* closing quote */
*q++ = L'\0';

return dst;
}

void spawn_perl(const char *argv0, const char *my_perl, const char *stmpdir)
{
typedef BOOL (WINAPI *pALLOW)(DWORD);
HINSTANCE hinstLib;
pALLOW ProcAdd;
#ifndef ASFW_ANY
#define ASFW_ANY -1
#endif
LPWSTR *w_argv;
LPWSTR w_my_perl;
int w_argc, i, len, rc;

hinstLib = LoadLibrary("user32");
if (hinstLib != NULL) {
ProcAdd = (pALLOW) GetProcAddress(hinstLib, "AllowSetForegroundWindow");
if (ProcAdd != NULL)
{
(ProcAdd)(ASFW_ANY);
}
}

w_argv = CommandLineToArgvW(GetCommandLineW(), &w_argc);
if (w_argv == NULL)
par_die("%s: GetCommandLineW or CommandLineToArgvW failed: $^E=%u",
argv0, GetLastError());

/* convert my_perl from local codepage to UTF-16 */
len = MultiByteToWideChar(CP_THREAD_ACP, 0, my_perl, -1, NULL, 0);
if (len == 0)
par_die("%s: failed to convert string to UTF-16: $^E=%u",
argv0, GetLastError());
w_my_perl = malloc(len * sizeof(wchar_t)); /* len includes trailing NUL */
len = MultiByteToWideChar(CP_THREAD_ACP, 0, my_perl, -1, w_my_perl, len);
w_argv[0] = w_my_perl;

for (i = 0; i < w_argc; i++)
{
len = wcslen(w_argv[i]);
if (len == 0
|| w_argv[i][len-1] == L'\\'
|| wcspbrk(w_argv[i], L" \t\n\r\v\""))
{
w_argv[i] = shell_quote_wide(w_argv[i]);
}
}

par_setenv("PAR_SPAWNED", "1");

rc = _wspawnvp(P_WAIT, w_argv[0], (const wchar_t* const*)w_argv);

free(w_my_perl);
LocalFree(w_argv);

par_cleanup(stmpdir);
exit(rc);
}
#endif

char pp_version_info[] = "@(#) Packed by PAR::Packer " PAR_PACKER_VERSION;
Expand Down Expand Up @@ -345,65 +403,7 @@ int main ( int argc, char **argv, char **env )

/* finally spawn the custom Perl interpreter */
#ifdef WIN32
par_setenv("PAR_SPAWNED", "1");

{
typedef BOOL (WINAPI *pALLOW)(DWORD);
HINSTANCE hinstLib;
pALLOW ProcAdd;
#ifndef ASFW_ANY
#define ASFW_ANY -1
#endif
hinstLib = LoadLibrary("user32");
if (hinstLib != NULL) {
ProcAdd = (pALLOW) GetProcAddress(hinstLib, "AllowSetForegroundWindow");
if (ProcAdd != NULL)
{
(ProcAdd)(ASFW_ANY);
}
}
}

{
LPWSTR *w_argv;
LPWSTR w_my_perl;
int i, len;

w_argv = CommandLineToArgvW(GetCommandLineW(), &argc);
if (w_argv == NULL)
par_die("%s: CommandLineToArgvW failed", argv[0]); // TODO GetLastError

#if 0
TODO reimplement for wchar_t?
/* quote argv strings if necessary, cf. Win32::ShellQuote */
char **argp;
for (argp = argv; *argp; argp++)
{
int len = strlen(*argp);
if ( len == 0
|| (*argp)[len-1] == '\\'
|| strpbrk(*argp, " \t\n\r\v\"") )
{
*argp = shell_quote(*argp);
}
}
#endif

len = MultiByteToWideChar(CP_THREAD_ACP, 0, my_perl, -1, NULL, 0);
if (len == 0)
par_die("%s: failed to convert string to UTF-16", argv[0]); // TODO GetLastError
w_my_perl = malloc((len + 1) * sizeof(wchar_t)); // TODO +1 not required
len = MultiByteToWideChar(CP_THREAD_ACP, 0, my_perl, -1, w_my_perl, len);
w_argv[0] = w_my_perl;

rc = _wspawnvp(P_WAIT, w_my_perl, (char* const*)w_argv);

free(w_my_perl);
LocalFree(w_argv);
}

par_cleanup(stmpdir);
exit(rc);
spawn_perl(argv[0], my_perl, stmpdir); /* no return */
#else
argv[0] = my_perl;
execvp(my_perl, argv);
Expand Down

0 comments on commit 8697780

Please sign in to comment.