/* 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 #include #include #include #include #include #include #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 = ""; /* Win long filenames limited to 255 chars, so 254 chars for directory is ample */ static char *exedir = ""; static char *variant = ""; 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 } }