3 * $Id: ghci.c,v 1.10 2005/05/05 00:58:38 sof Exp $
5 * ghci wrapper for Win32 only
7 * This wrapper invokes ghc.exe with the added command-line
8 * option "--interactive".
9 * (On Unix this is done by the ghci.sh shell script, but
10 * that does not work so well on Win32.)
12 * (c) The GHC Team 2001
14 * ghc.exe is searched for using the 'normal' search rules
15 * for DLLs / EXEs (i.e., first in the same dir as this wrapper,
16 * then system dirs, then PATH).
20 * MSVC: cl /o ghci.exe /c ghciwrap.c
21 * mingw: gcc -mno-cygwin -o ghci.exe ghciwrap.c
23 * If you want to associate your own icon with the wrapper,
24 * here's how to do it:
26 * * Create a one-line .rc file, ghci.rc (say), containing
28 * (subst the string literal for the name of your icon file).
29 * * Compile it up (assuming the .ico file is in the same dir
32 * MSVC: rc /i. /fo ghci.res ghci.rc
33 * mingw: windres -o ghci.res -i ghci.rc -O coff
35 * * Add the resulting .res file to the link line of the wrapper:
37 * MSVC: cl /o ghci.exe /c ghciwrap.c ghci.res
38 * mingw: gcc -mno-cygwin -o ghci.exe ghciwrap.c ghci.res
50 #define BINARY_NAME "ghc.exe"
51 #define IACTIVE_OPTION "--interactive"
53 #define errmsg(msg) fprintf(stderr, msg "\n"); fflush(stderr)
54 #define errmsg1(msg,val) fprintf(stderr, msg "\n",val); fflush(stderr)
57 main(int argc, char** argv)
59 TCHAR binPath[FILENAME_MAX+1];
60 TCHAR binPathShort[MAX_PATH+1];
61 DWORD dwSize = FILENAME_MAX;
66 unsigned int cmdline_len = 0;
71 PROCESS_INFORMATION pi;
73 ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
74 ZeroMemory(&si, sizeof(STARTUPINFO));
75 si.cb = sizeof(STARTUPINFO);
78 printf("WARNING: GHCi invoked via 'ghci.exe' in *nix-like shells (cygwin-bash, in particular)\n");
79 printf(" doesn't handle Ctrl-C well; use the 'ghcii.sh' shell wrapper instead\n");
83 /* Locate the binary we want to start up */
84 if ( !SearchPath(NULL,
90 errmsg1("%s: Unable to locate ghc.exe", argv[0]);
95 /* Turn the path into short form - LFN form causes problems
96 when passed in argv[0]. */
97 if ( !(GetShortPathName(binPath, binPathShort, dwSize)) ) {
98 errmsg1("%s: Unable to locate ghc.exe", argv[0]);
102 /* Compute length of the flattened 'argv', including extra IACTIVE_OPTION (and spaces!) */
103 cmdline_len += 1 + strlen(IACTIVE_OPTION);
104 for(i=1;i<argc;i++) {
105 /* Note: play it safe and quote all argv strings */
106 cmdline_len += 1 + strlen(argv[i]) + 2;
108 new_cmdline = (char*)malloc(sizeof(char) * (cmdline_len + 1));
110 errmsg1("%s: failed to start up ghc.exe; insufficient memory", argv[0]);
114 strcpy(new_cmdline, " " IACTIVE_OPTION);
115 ptr = new_cmdline + strlen(" " IACTIVE_OPTION);
116 for(i=1;i<argc;i++) {
127 /* Note: Used to use _spawnv(_P_WAIT, ...) here, but it suffered
128 from the parent intercepting console events such as Ctrl-C,
129 which it shouldn't. Installing an ignore-all console handler
130 didn't do the trick either.
132 Irrespective of this issue, using CreateProcess() is preferable,
133 as it makes this wrapper work on both mingw and cygwin.
136 fprintf(stderr, "Invoking ghc: %s %s\n", binPathShort, new_cmdline); fflush(stderr);
138 if (!CreateProcess(binPathShort,
143 0, /* dwCreationFlags */
144 NULL, /* lpEnvironment */
145 NULL, /* lpCurrentDirectory */
146 &si, /* lpStartupInfo */
148 errmsg1("Unable to start ghc.exe (error code: %lu)", GetLastError());
151 /* Disable handling of console events in the parent by dropping its
152 * connection to the console. This has the (minor) downside of not being
153 * able to subsequently emit any error messages to the console.
157 switch (WaitForSingleObject(pi.hProcess, INFINITE) ) {
162 /* in the event we get any hard errors, bring the child to a halt. */
163 TerminateProcess(pi.hProcess,1);