364 lines
9.0 KiB
C
364 lines
9.0 KiB
C
/* Launcher program for Windows. */
|
|
/* Builds a MzScheme starter if MZSTART is defined. */
|
|
/* Builds a MrEd starter if MRSTART is defined. */
|
|
/* If neither is defined, MZSTART is auto-defined */
|
|
|
|
#include <windows.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <process.h>
|
|
#include <ctype.h>
|
|
|
|
#ifndef MRSTART
|
|
# ifndef MZSTART
|
|
# define MZSTART
|
|
# endif
|
|
#endif
|
|
|
|
#ifdef MRSTART
|
|
# define GOSUBDIR "\\"
|
|
# define GOEXE "mred.exe"
|
|
# define GOEXE3M "mred3m.exe"
|
|
# define WAITTILLDONE 0
|
|
#endif
|
|
|
|
#ifdef MZSTART
|
|
# define GOSUBDIR "\\"
|
|
# define GOEXE "mzscheme.exe"
|
|
# define GOEXE3M "mzscheme3m.exe"
|
|
# define WAITTILDONE 1
|
|
#endif
|
|
|
|
#define MAXCOMMANDLEN 1024
|
|
#define MAX_ARGS 100
|
|
|
|
#if defined(_MSC_VER)
|
|
# define MSC_IZE(x) _ ## x
|
|
#else
|
|
# define MSC_IZE(x) x
|
|
#endif
|
|
#define DUPLICATE_INPUT
|
|
|
|
/* Win command lines limited to 1024 chars, so 1024 chars for
|
|
command tail is ample */
|
|
|
|
static char *input =
|
|
"<Command Line: Replace This ************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"****************************************************************"
|
|
"***************************************************************>";
|
|
|
|
/* Win long filenames limited to 255 chars, so 254 chars for
|
|
directory is ample */
|
|
|
|
static char *exedir = "<Executable Directory: Replace This ********"
|
|
"********************************************"
|
|
"********************************************"
|
|
"********************************************"
|
|
"********************************************"
|
|
"********************************************>";
|
|
|
|
static char *variant = "<Executable Variant: Replace This>";
|
|
|
|
static char *protect(char *s)
|
|
{
|
|
char *naya;
|
|
int has_space = 0, has_quote = 0, was_slash = 0;
|
|
|
|
for (naya = s; *naya; naya++) {
|
|
if (isspace(*naya) || (*naya == '\'')) {
|
|
has_space = 1;
|
|
was_slash = 0;
|
|
} else if (*naya == '"') {
|
|
has_quote += 1 + (2 * was_slash);
|
|
was_slash = 0;
|
|
} else if (*naya == '\\') {
|
|
was_slash++;
|
|
} else
|
|
was_slash = 0;
|
|
}
|
|
|
|
if (has_space || has_quote) {
|
|
char *p;
|
|
int wrote_slash = 0;
|
|
|
|
naya = malloc(strlen(s) + 3 + 3*has_quote);
|
|
naya[0] = '"';
|
|
for (p = naya + 1; *s; s++) {
|
|
if (*s == '"') {
|
|
while (wrote_slash--)
|
|
*(p++) = '\\';
|
|
*(p++) = '"'; /* endquote */
|
|
*(p++) = '\\';
|
|
*(p++) = '"'; /* protected */
|
|
*(p++) = '"'; /* start quote again */
|
|
wrote_slash = 0;
|
|
} else if (*s == '\\') {
|
|
*(p++) = '\\';
|
|
wrote_slash++;
|
|
} else {
|
|
*(p++) = *s;
|
|
wrote_slash = 0;
|
|
}
|
|
}
|
|
*(p++) = '"';
|
|
*p = 0;
|
|
|
|
return naya;
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
static int parse_command_line(int count, char **command,
|
|
char *buf, int maxargs)
|
|
|
|
{
|
|
char *parse, *created, *write;
|
|
int findquote = 0;
|
|
|
|
parse = created = write = buf;
|
|
while (*parse) {
|
|
while (*parse && isspace(*parse)) parse++;
|
|
while (*parse && (!isspace(*parse) || findquote)) {
|
|
if (*parse== '"') {
|
|
findquote = !findquote;
|
|
} else if (*parse== '\\') {
|
|
char *next;
|
|
for (next = parse; *next == '\\'; next++);
|
|
if (*next == '"') {
|
|
/* Special handling: */
|
|
int count = (next - parse), i;
|
|
for (i = 1; i < count; i += 2)
|
|
*(write++) = '\\';
|
|
parse += (count - 1);
|
|
if (count & 0x1) {
|
|
*(write++) = '\"';
|
|
parse++;
|
|
}
|
|
} else
|
|
*(write++) = *parse;
|
|
} else
|
|
*(write++) = *parse;
|
|
parse++;
|
|
}
|
|
if (*parse)
|
|
parse++;
|
|
*(write++) = 0;
|
|
|
|
if (*created) {
|
|
command[count++] = created;
|
|
if (count == maxargs)
|
|
return count;
|
|
}
|
|
created = write;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
static char *make_command_line(int argc, char **argv)
|
|
{
|
|
int i, len = 0;
|
|
char *r;
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
len += strlen(argv[i]) + 1;
|
|
}
|
|
r = malloc(len);
|
|
len = 0;
|
|
for (i = 0; i < argc; i++) {
|
|
int l = strlen(argv[i]);
|
|
if (len) r[len++] = ' ';
|
|
memcpy(r + len, argv[i], l);
|
|
len += l;
|
|
}
|
|
r[len] = 0;
|
|
return r;
|
|
}
|
|
|
|
#ifdef MZSTART
|
|
void WriteStr(HANDLE h, const char *s) {
|
|
DWORD done;
|
|
WriteFile(h, s, strlen(s), &done, NULL);
|
|
}
|
|
#endif
|
|
|
|
#ifdef DUPLICATE_INPUT
|
|
static char *copy_string(char *s)
|
|
{
|
|
int l = strlen(s);
|
|
char *d = malloc(l + 1);
|
|
memcpy(d, s, l + 1);
|
|
return d;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MRSTART
|
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
|
LPSTR m_lpCmdLine, int nCmdShow)
|
|
#else
|
|
int main(int argc_in, char **argv_in)
|
|
#endif
|
|
{
|
|
char go[MAXCOMMANDLEN * 2];
|
|
char *args[MAX_ARGS + 1];
|
|
char *command_line;
|
|
int count, i;
|
|
struct MSC_IZE(stat) st;
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
#ifdef MZSTART
|
|
HANDLE out;
|
|
|
|
out = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
#endif
|
|
|
|
#ifdef DUPLICATE_INPUT
|
|
/* gcc: input is read-only */
|
|
input = copy_string(input);
|
|
exedir = copy_string(exedir);
|
|
#endif
|
|
|
|
count = 1;
|
|
count = parse_command_line(count, args, input, MAX_ARGS);
|
|
|
|
/* exedir can be relative to the current executable */
|
|
if ((exedir[0] == '\\')
|
|
|| ((((exedir[0] >= 'a') && (exedir[0] <= 'z'))
|
|
|| ((exedir[0] >= 'A') && (exedir[0] <= 'Z')))
|
|
&& (exedir[1] == ':'))) {
|
|
/* Absolute path */
|
|
} else {
|
|
/* Make it absolute, relative to this executable */
|
|
int plen;
|
|
int mlen;
|
|
char *s2, *path;
|
|
|
|
path = (char *)malloc(1024);
|
|
GetModuleFileName(NULL, path, 1024);
|
|
|
|
plen = strlen(exedir);
|
|
mlen = strlen(path);
|
|
|
|
while (mlen && (path[mlen - 1] != '\\')) {
|
|
mlen--;
|
|
}
|
|
s2 = (char *)malloc(mlen + plen + 1);
|
|
memcpy(s2, path, mlen);
|
|
memcpy(s2 + mlen, exedir, plen + 1);
|
|
exedir = s2;
|
|
}
|
|
|
|
strcpy(go, exedir);
|
|
strcat(go, GOSUBDIR);
|
|
strcat(go, (variant[0] != '<') ? GOEXE3M : GOEXE);
|
|
|
|
if (_stat(go, &st)) {
|
|
char errbuff[MAXCOMMANDLEN * 2];
|
|
#ifdef MRSTART
|
|
sprintf(errbuff,"Can't find %s",go);
|
|
MessageBox(NULL,errbuff,"Error",MB_OK);
|
|
#else
|
|
sprintf(errbuff,"Can't find %s\n",go);
|
|
WriteStr(out,errbuff);
|
|
#endif
|
|
exit(-1);
|
|
}
|
|
|
|
args[0] = go;
|
|
|
|
#ifdef MRSTART
|
|
{
|
|
char *buf;
|
|
|
|
buf = malloc(strlen(m_lpCmdLine) + 1);
|
|
memcpy(buf, m_lpCmdLine, strlen(m_lpCmdLine) + 1);
|
|
count = parse_command_line(count, args, buf, MAX_ARGS);
|
|
}
|
|
#else
|
|
{
|
|
int i;
|
|
for (i = 1; i < argc_in; i++)
|
|
args[count++] = argv_in[i];
|
|
}
|
|
#endif
|
|
|
|
args[count] = NULL;
|
|
|
|
for (i = 0; i < count; i++) {
|
|
args[i] = protect(args[i]);
|
|
/* MessageBox(NULL, args[i], "Argument", MB_OK); */
|
|
}
|
|
|
|
for (i = 0; i < sizeof(si); i++)
|
|
((char *)&si)[i] = 0;
|
|
si.cb = sizeof(si);
|
|
|
|
command_line = make_command_line(count, args);
|
|
|
|
if (strlen(command_line) > MAXCOMMANDLEN) {
|
|
char errbuff[MAXCOMMANDLEN * 2];
|
|
#ifdef MRSTART
|
|
sprintf(errbuff,"Command line exceeds %d characters: %s",
|
|
MAXCOMMANDLEN,go);
|
|
MessageBox(NULL,errbuff,"Error",MB_OK);
|
|
#else
|
|
sprintf(errbuff,"Command line exceeds %d characters: %s\n",
|
|
MAXCOMMANDLEN,go);
|
|
WriteStr(out,errbuff);
|
|
#endif
|
|
exit(-1);
|
|
}
|
|
|
|
if (!CreateProcess(go,
|
|
command_line,
|
|
NULL, NULL, TRUE,
|
|
0, NULL, NULL, &si, &pi)) {
|
|
|
|
#ifdef MRSTART
|
|
MessageBox(NULL, "Can't start " GOEXE, "Error", MB_OK);
|
|
#else
|
|
WriteStr(out, "Can't start " GOEXE "\n");
|
|
#endif
|
|
return -1;
|
|
} else {
|
|
#if WAITTILDONE
|
|
DWORD result;
|
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
|
GetExitCodeProcess(pi.hProcess, &result);
|
|
return result;
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
}
|