summaryrefslogtreecommitdiffstats
path: root/src/misc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:21:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:21:29 +0000
commit29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc (patch)
tree63ef546b10a81d461e5cf5ed9e98a68cd7dee1aa /src/misc
parentInitial commit. (diff)
downloadkbuild-29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc.tar.xz
kbuild-29cd838eab01ed7110f3ccb2e8c6a35c8a31dbcc.zip
Adding upstream version 1:0.1.9998svn3589+dfsg.upstream/1%0.1.9998svn3589+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/misc/Makefile.kmk73
-rw-r--r--src/misc/kmk_time.c437
-rw-r--r--src/misc/win_exec_wrapper.c120
3 files changed, 630 insertions, 0 deletions
diff --git a/src/misc/Makefile.kmk b/src/misc/Makefile.kmk
new file mode 100644
index 0000000..6c863bf
--- /dev/null
+++ b/src/misc/Makefile.kmk
@@ -0,0 +1,73 @@
+# $Id: Makefile.kmk 3538 2021-12-21 12:19:40Z bird $
+## @file
+# Sub-makefile for kmk_time.
+#
+
+#
+# Copyright (c) 2008-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+#
+# This file is part of kBuild.
+#
+# kBuild is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# kBuild is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with kBuild. If not, see <http://www.gnu.org/licenses/>
+#
+#
+
+SUB_DEPTH = ../..
+include $(PATH_KBUILD)/subheader.kmk
+
+PROGRAMS += kmk_time
+kmk_time_TEMPLATE = BIN
+kmk_time_DEFS = KBUILD_SVN_REV=$(KBUILD_SVN_REV)
+kmk_time_SOURCES = kmk_time.c
+kmk_time_SOURCES.win = ../lib/quote_argv.c
+
+
+#
+# Wrapper stubs for using the kBuild binaries as standard unixy ones on windows.
+#
+TEMPLATE_EXECWRAPPER = Windows exec wrapper
+TEMPLATE_EXECWRAPPER_EXTENDS = BIN
+TEMPLATE_EXECWRAPPER_INST = $(TEMPLATE_BIN_INST)wrappers/
+TEMPLATE_EXECWRAPPER_CFLAGS = $(TEMPLATE_BIN_CFLAGS) -GS-
+TEMPLATE_EXECWRAPPER_LDFLAGS = $(TEMPLATE_BIN_LDFLAGS) /Entry:BareBoneStart
+TEMPLATE_EXECWRAPPER_LIBS = $(NO_SUCH_VARIABLE)
+TEMPLATE_EXECWRAPPER_LIBS.x86 = $(NO_SUCH_VARIABLE)
+TEMPLATE_EXECWRAPPER_LIBS.amd64 = $(NO_SUCH_VARIABLE)
+TEMPLATE_EXECWRAPPER_SOURCES = win_exec_wrapper.c
+
+define def_WindowsWrapper
+PROGRAMS.win += $1
+$1_TEMPLATE = EXECWRAPPER
+$1_DEFS = TARGET_EXE_NAME=\"$2.exe\"
+endef
+
+$(evalcall2 def_WindowsWrapper,cat,kmk_cat)
+$(evalcall2 def_WindowsWrapper,cp,kmk_cp)
+$(evalcall2 def_WindowsWrapper,echo,kmk_echo)
+$(evalcall2 def_WindowsWrapper,expr,kmk_expr)
+$(evalcall2 def_WindowsWrapper,grep,kmk_grep)
+$(evalcall2 def_WindowsWrapper,ln,kmk_ln)
+$(evalcall2 def_WindowsWrapper,mkdir,kmk_mkdir)
+$(evalcall2 def_WindowsWrapper,mv,kmk_mv)
+$(evalcall2 def_WindowsWrapper,kkill,kmk_kill)
+$(evalcall2 def_WindowsWrapper,killall,kmk_kill)
+$(evalcall2 def_WindowsWrapper,printf,kmk_printf)
+$(evalcall2 def_WindowsWrapper,rm,kmk_rm)
+$(evalcall2 def_WindowsWrapper,rmdir,kmk_rmdir)
+$(evalcall2 def_WindowsWrapper,sed,kmk_sed)
+$(evalcall2 def_WindowsWrapper,sleep,kmk_sleep)
+$(evalcall2 def_WindowsWrapper,touch,kmk_touch)
+
+include $(KBUILD_PATH)/subfooter.kmk
+
diff --git a/src/misc/kmk_time.c b/src/misc/kmk_time.c
new file mode 100644
index 0000000..8f64fdb
--- /dev/null
+++ b/src/misc/kmk_time.c
@@ -0,0 +1,437 @@
+/* $Id: kmk_time.c 3336 2020-04-22 12:08:35Z bird $ */
+/** @file
+ * kmk_time - Time program execution.
+ *
+ * This is based on kmk/kmkbuiltin/redirect.c.
+ */
+
+/*
+ * Copyright (c) 2007-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#if defined(_MSC_VER)
+# include <io.h>
+# include <direct.h>
+# include <process.h>
+# include <Windows.h>
+# include "quote_argv.h"
+#else
+# include <unistd.h>
+# include <sys/time.h>
+# include <sys/wait.h>
+# include <signal.h>
+#endif
+
+#ifdef __OS2__
+# define INCL_BASE
+# include <os2.h>
+# ifndef LIBPATHSTRICT
+# define LIBPATHSTRICT 3
+# endif
+#endif
+
+#ifndef _MSC_VER
+static const char *my_strsignal(int signo)
+{
+#define CASE_SIG_RET_STR(sig) if (signo == SIG##sig) return #sig
+#ifdef SIGHUP
+ CASE_SIG_RET_STR(HUP);
+#endif
+#ifdef SIGINT
+ CASE_SIG_RET_STR(INT);
+#endif
+#ifdef SIGQUIT
+ CASE_SIG_RET_STR(QUIT);
+#endif
+#ifdef SIGILL
+ CASE_SIG_RET_STR(ILL);
+#endif
+#ifdef SIGTRAP
+ CASE_SIG_RET_STR(TRAP);
+#endif
+#ifdef SIGABRT
+ CASE_SIG_RET_STR(ABRT);
+#endif
+#ifdef SIGIOT
+ CASE_SIG_RET_STR(IOT);
+#endif
+#ifdef SIGBUS
+ CASE_SIG_RET_STR(BUS);
+#endif
+#ifdef SIGFPE
+ CASE_SIG_RET_STR(FPE);
+#endif
+#ifdef SIGKILL
+ CASE_SIG_RET_STR(KILL);
+#endif
+#ifdef SIGUSR1
+ CASE_SIG_RET_STR(USR1);
+#endif
+#ifdef SIGSEGV
+ CASE_SIG_RET_STR(SEGV);
+#endif
+#ifdef SIGUSR2
+ CASE_SIG_RET_STR(USR2);
+#endif
+#ifdef SIGPIPE
+ CASE_SIG_RET_STR(PIPE);
+#endif
+#ifdef SIGALRM
+ CASE_SIG_RET_STR(ALRM);
+#endif
+#ifdef SIGTERM
+ CASE_SIG_RET_STR(TERM);
+#endif
+#ifdef SIGSTKFLT
+ CASE_SIG_RET_STR(STKFLT);
+#endif
+#ifdef SIGCHLD
+ CASE_SIG_RET_STR(CHLD);
+#endif
+#ifdef SIGCONT
+ CASE_SIG_RET_STR(CONT);
+#endif
+#ifdef SIGSTOP
+ CASE_SIG_RET_STR(STOP);
+#endif
+#ifdef SIGTSTP
+ CASE_SIG_RET_STR(TSTP);
+#endif
+#ifdef SIGTTIN
+ CASE_SIG_RET_STR(TTIN);
+#endif
+#ifdef SIGTTOU
+ CASE_SIG_RET_STR(TTOU);
+#endif
+#ifdef SIGURG
+ CASE_SIG_RET_STR(URG);
+#endif
+#ifdef SIGXCPU
+ CASE_SIG_RET_STR(XCPU);
+#endif
+#ifdef SIGXFSZ
+ CASE_SIG_RET_STR(XFSZ);
+#endif
+#ifdef SIGVTALRM
+ CASE_SIG_RET_STR(VTALRM);
+#endif
+#ifdef SIGPROF
+ CASE_SIG_RET_STR(PROF);
+#endif
+#ifdef SIGWINCH
+ CASE_SIG_RET_STR(WINCH);
+#endif
+#ifdef SIGIO
+ CASE_SIG_RET_STR(IO);
+#endif
+#ifdef SIGPWR
+ CASE_SIG_RET_STR(PWR);
+#endif
+#ifdef SIGSYS
+ CASE_SIG_RET_STR(SYS);
+#endif
+#ifdef SIGBREAK
+ CASE_SIG_RET_STR(BREAK);
+#endif
+#undef CASE_SIG_RET_STR
+ return "???";
+}
+#endif /* unix */
+
+static const char *name(const char *pszName)
+{
+ const char *psz = strrchr(pszName, '/');
+#if defined(_MSC_VER) || defined(__OS2__)
+ const char *psz2 = strrchr(pszName, '\\');
+ if (!psz2)
+ psz2 = strrchr(pszName, ':');
+ if (psz2 && (!psz || psz2 > psz))
+ psz = psz2;
+#endif
+ return psz ? psz + 1 : pszName;
+}
+
+
+static int usage(FILE *pOut, const char *argv0)
+{
+ fprintf(pOut,
+ "usage: %s [options] [--] <program> [args]\n"
+ " or: %s --help\n"
+ " or: %s --version\n"
+ "\n"
+ "Options:\n"
+ " -i <count>, --iteration <count>\n"
+ " Run the program <count> times and display minium, maximum and average\n"
+ " run times at the end.\n"
+ ,
+ argv0, argv0, argv0);
+#ifdef _MSC_VER
+ fprintf(pOut,
+ " --unquoted\n"
+ " Windows only: No argument quoting, use them as-is.\n");
+#endif
+ return 1;
+}
+
+
+int main(int argc, char **argv)
+{
+ int i, j;
+ int cTimes = 1;
+#if defined(_MSC_VER)
+ int fUnquoted = 0;
+ FILETIME ftStart, ft;
+ unsigned _int64 usMin, usMax, usAvg, usTotal, usCur;
+ unsigned _int64 iStart;
+ intptr_t rc;
+#else
+ struct timeval tvStart, tv;
+ unsigned long long usMin, usMax, usAvg, usTotal, usCur;
+ pid_t pid;
+ int rc;
+#endif
+ int rcExit = 0;
+
+ /*
+ * Parse arguments.
+ */
+ if (argc <= 1)
+ return usage(stderr, name(argv[0]));
+ for (i = 1; i < argc; i++)
+ {
+ char *psz = &argv[i][0];
+ if (*psz++ != '-')
+ break;
+
+ if (*psz == '-')
+ {
+ /* '--' ? */
+ if (!psz[1])
+ {
+ i++;
+ break;
+ }
+
+ /* convert to short. */
+ if (!strcmp(psz, "-help"))
+ psz = "h";
+ else if (!strcmp(psz, "-version"))
+ psz = "V";
+ else if (!strcmp(psz, "-iterations"))
+ psz = "i";
+#if defined(_MSC_VER)
+ else if (!strcmp(psz, "-unquoted"))
+ {
+ fUnquoted = 1;
+ continue;
+ }
+#endif
+ }
+
+ switch (*psz)
+ {
+ case 'h':
+ usage(stdout, name(argv[0]));
+ return 0;
+
+ case 'V':
+ printf("kmk_time - kBuild version %d.%d.%d (r%u)\n"
+ "Copyright (C) 2007-2018 knut st. osmundsen\n",
+ KBUILD_VERSION_MAJOR, KBUILD_VERSION_MINOR, KBUILD_VERSION_PATCH,
+ KBUILD_SVN_REV);
+ return 0;
+
+ case 'i':
+ if (i + 1 >= argc)
+ {
+ fprintf(stderr, "%s: syntax error: missing iteration count\n", name(argv[0]));
+ return 1;
+ }
+ cTimes = atoi(argv[++i]);
+ if (cTimes <= 0)
+ {
+ fprintf(stderr, "%s: error: invalid interation count '%s'.\n", name(argv[0]), argv[i]);
+ return 1;
+ }
+ break;
+
+ default:
+ fprintf(stderr, "%s: error: syntax error '%s'\n", name(argv[0]), argv[i]);
+ return 1;
+ }
+ }
+
+ /*
+ * Make sure there's something to execute.
+ */
+ if (i >= argc)
+ {
+ fprintf(stderr, "%s: syntax error: nothing to execute!\n", name(argv[0]));
+ return usage(stderr, name(argv[0]));
+ }
+
+ /*
+ * Execute the program the specified number of times.
+ */
+ usMax = usMin = usTotal = 0;
+ usMin--; /* wraps to max value */
+ for (j = 0; j < cTimes; j++)
+ {
+ /*
+ * Execute the program (it's actually supposed to be a command I think, but wtf).
+ */
+#if defined(_MSC_VER)
+ if (!fUnquoted)
+ {
+ if (quote_argv(argc - i, &argv[i], 0 /*fWatcomBrainDamage*/, 0 /*fFreeOrLeak*/) != 0)
+ {
+ fprintf(stderr, "%s: error: quote_argv failed\n");
+ return 8;
+ }
+ fUnquoted = 1; /* Don't quote them again in the next iteration. */
+ }
+
+ GetSystemTimeAsFileTime(&ftStart);
+ rc = _spawnvp(_P_WAIT, argv[i], &argv[i]);
+ if (rc == -1)
+ {
+ fprintf(stderr, "%s: error: _spawnvp(_P_WAIT, \"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
+ return 8;
+ }
+
+ GetSystemTimeAsFileTime(&ft);
+
+ iStart = ftStart.dwLowDateTime | ((unsigned _int64)ftStart.dwHighDateTime << 32);
+ usCur = ft.dwLowDateTime | ((unsigned _int64)ft.dwHighDateTime << 32);
+ usCur -= iStart;
+ usCur /= 10; /* to usecs */
+
+ printf("%s: ", name(argv[0]));
+ if (cTimes != 1)
+ printf("#%02u ", j + 1);
+ printf("%um%u.%06us - exit code: %d\n",
+ (unsigned)(usCur / (60 * 1000000)),
+ (unsigned)(usCur % (60 * 1000000)) / 1000000,
+ (unsigned)(usCur % 1000000),
+ rc);
+
+#else /* unix: */
+ gettimeofday(&tvStart, NULL);
+ pid = fork();
+ if (!pid)
+ {
+ /* child */
+ execvp(argv[i], &argv[i]);
+ fprintf(stderr, "%s: error: _execvp(\"%s\", ...) failed: %s\n", name(argv[0]), argv[i], strerror(errno));
+ return 8;
+ }
+ if (pid < 0)
+ {
+ fprintf(stderr, "%s: error: fork() failed: %s\n", name(argv[0]), strerror(errno));
+ return 9;
+ }
+
+ /* parent, wait for child. */
+ rc = 9;
+ while (waitpid(pid, &rc, 0) == -1 && errno == EINTR)
+ /* nothing */;
+ gettimeofday(&tv, NULL);
+
+ /* calc elapsed time */
+ tv.tv_sec -= tvStart.tv_sec;
+ if (tv.tv_usec > tvStart.tv_usec)
+ tv.tv_usec -= tvStart.tv_usec;
+ else
+ {
+ tv.tv_sec--;
+ tv.tv_usec = tv.tv_usec + 1000000 - tvStart.tv_usec;
+ }
+ usCur = tv.tv_sec * 1000000ULL
+ + tv.tv_usec;
+
+ printf("%s: ", name(argv[0]));
+ if (cTimes != 1)
+ printf("#%02u ", j + 1);
+ printf("%um%u.%06us",
+ (unsigned)(tv.tv_sec / 60),
+ (unsigned)(tv.tv_sec % 60),
+ (unsigned)tv.tv_usec);
+ if (WIFEXITED(rc))
+ {
+ printf(" - normal exit: %d\n", WEXITSTATUS(rc));
+ rc = WEXITSTATUS(rc);
+ }
+# ifndef __HAIKU__ /**@todo figure how haiku signals that a core was dumped. */
+ else if (WIFSIGNALED(rc) && WCOREDUMP(rc))
+ {
+ printf(" - dumped core: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc));
+ rc = 10;
+ }
+# endif
+ else if (WIFSIGNALED(rc))
+ {
+ printf(" - killed by: %s (%d)\n", my_strsignal(WTERMSIG(rc)), WTERMSIG(rc));
+ rc = 11;
+ }
+ else if (WIFSTOPPED(rc))
+ {
+ printf(" - stopped by: %s (%d)\n", my_strsignal(WSTOPSIG(rc)), WSTOPSIG(rc));
+ rc = 12;
+ }
+ else
+ {
+ printf(" unknown exit status %#x (%d)\n", rc, rc);
+ rc = 13;
+ }
+#endif /* unix */
+ if (rc && !rcExit)
+ rcExit = (int)rc;
+
+ /* calc min/max/avg */
+ usTotal += usCur;
+ if (usMax < usCur)
+ usMax = usCur;
+ if (usMin > usCur)
+ usMin = usCur;
+ }
+
+ /*
+ * Summary if more than one run.
+ */
+ if (cTimes != 1)
+ {
+ usAvg = usTotal / cTimes;
+
+ printf("%s: avg %um%u.%06us\n", name(argv[0]), (unsigned)(usAvg / 60000000), (unsigned)(usAvg % 60000000) / 1000000, (unsigned)(usAvg % 1000000));
+ printf("%s: min %um%u.%06us\n", name(argv[0]), (unsigned)(usMin / 60000000), (unsigned)(usMin % 60000000) / 1000000, (unsigned)(usMin % 1000000));
+ printf("%s: max %um%u.%06us\n", name(argv[0]), (unsigned)(usMax / 60000000), (unsigned)(usMax % 60000000) / 1000000, (unsigned)(usMax % 1000000));
+ }
+
+ return rcExit;
+}
+
diff --git a/src/misc/win_exec_wrapper.c b/src/misc/win_exec_wrapper.c
new file mode 100644
index 0000000..0e1e851
--- /dev/null
+++ b/src/misc/win_exec_wrapper.c
@@ -0,0 +1,120 @@
+/* $Id: win_exec_wrapper.c 3528 2021-12-19 16:32:38Z bird $ */
+/** @file
+ * win_exec_wrapper - Stub for exec'ing a kmk_xxx program.
+ */
+
+/*
+ * Copyright (c) 2021 knut st. osmundsen <bird-kBuild-spamixx@anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <windows.h>
+
+
+VOID __stdcall BareBoneStart(VOID)
+{
+ DWORD dwIgnored;
+ PROCESS_INFORMATION ProcInfo = { NULL, NULL, 0, 0 };
+ WCHAR wszExec[260];
+ UINT cwcExec = GetModuleFileNameW(NULL, wszExec, 512);
+ BOOL fExecOk = FALSE;
+ WCHAR const * const pwszCommandLine = GetCommandLineW();
+ STARTUPINFOW StartInfo = { sizeof(StartInfo), NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
+ GetStartupInfoW(&StartInfo);
+
+ /*
+ * Make sure we've got the standard handles.
+ */
+ StartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
+ StartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ StartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
+ StartInfo.dwFlags |= STARTF_USESTDHANDLES;
+
+ /*
+ * Construct the executable path.
+ */
+ if (cwcExec > 10)
+ {
+ /* Strip the filename. */
+#define IS_SEP(a_wc) ( (a_wc) == '\\' || (a_wc) == ':' || (a_wc) == '\\' )
+ while (cwcExec > 3 && !IS_SEP(wszExec[cwcExec - 1]))
+ cwcExec--;
+ if (IS_SEP(wszExec[cwcExec - 1]))
+ {
+ /* Strip the separator. */
+ while (cwcExec > 3 && IS_SEP(wszExec[cwcExec - 1]))
+ cwcExec--;
+ if (!IS_SEP(wszExec[cwcExec - 1]))
+ {
+ /* Strip the path component: */
+ while (cwcExec > 3 && !IS_SEP(wszExec[cwcExec - 1]))
+ cwcExec--;
+ if (IS_SEP(wszExec[cwcExec - 1]))
+ {
+ /* Insert the target executable name: */
+ static char const s_szTargetName[] = TARGET_EXE_NAME;
+ unsigned off = 0;
+ while (off < sizeof(s_szTargetName))
+ wszExec[cwcExec++] = s_szTargetName[off++];
+ fExecOk = cwcExec <= 260;
+ }
+ }
+ }
+ }
+ if (fExecOk)
+ {
+ /*
+ * Create the real process.
+ */
+ if (CreateProcessW(wszExec, (WCHAR *)pwszCommandLine, NULL, NULL, TRUE /*bInheritHandles*/,
+ 0 /*fFlags*/, NULL /*pwszzEnv*/, NULL /*pwszCwd*/, &StartInfo, &ProcInfo))
+ {
+ /*
+ * Wait for it to complete.
+ */
+ CloseHandle(ProcInfo.hThread);
+ for (;;)
+ {
+ DWORD dwExitCode = 1;
+ WaitForSingleObject(ProcInfo.hProcess, INFINITE);
+ if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
+ for (;;)
+ ExitProcess(dwExitCode);
+ Sleep(1);
+ }
+ }
+ else
+ {
+ static const char s_szMsg[] = "error: CreateProcessW failed for " TARGET_EXE_NAME "\r\n";
+ WriteFile(StartInfo.hStdError, s_szMsg, sizeof(s_szMsg) - 1, &dwIgnored, NULL);
+ }
+ }
+ else
+ {
+ static const char s_szMsg[] = "error: path construction failed (" TARGET_EXE_NAME ")\r\n";
+ WriteFile(StartInfo.hStdError, s_szMsg, sizeof(s_szMsg) - 1, &dwIgnored, NULL);
+ }
+
+ for (;;)
+ ExitProcess(31);
+}
+