[project @ 2003-12-10 11:35:24 by wolfgang]
[ghc-hetmet.git] / ghc / driver / ghci / ghci.c
1 /*
2  *
3  * $Id: ghci.c,v 1.8 2003/06/12 09:48:17 simonpj Exp $
4  *
5  * ghci wrapper for Win32 only
6  * 
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.)
11  *
12  * (c) The GHC Team 2001
13  *
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).
17  *
18  * To compile:
19  *
20  *   MSVC:    cl /o ghci.exe /c ghciwrap.c
21  *   mingw:   gcc -mno-cygwin -o ghci.exe ghciwrap.c
22  *
23  * If you want to associate your own icon with the wrapper,
24  * here's how to do it:
25  *
26  *   * Create a one-line .rc file, ghci.rc (say), containing
27  *          0 ICON "hsicon.ico"
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
30  *     as the .rc file):
31  *
32  *         MSVC:    rc /i. /fo ghci.res ghci.rc 
33  *         mingw:   windres -o ghci.res -i ghci.rc -O coff
34  *
35  *   * Add the resulting .res file to the link line of the wrapper:
36  *
37  *     MSVC:    cl /o ghci.exe /c ghciwrap.c ghci.res
38  *     mingw:   gcc -mno-cygwin -o ghci.exe ghciwrap.c ghci.res
39  *
40  */
41
42 #include <windows.h>
43 #include <stdio.h>
44 #include <process.h>
45 #include <malloc.h>
46 #include <stdlib.h>
47
48 #define BINARY_NAME "ghc.exe"
49 #define IACTIVE_OPTION "--interactive"
50
51 #define errmsg(msg) fprintf(stderr, msg "\n"); fflush(stderr)
52
53 int
54 main(int argc, char** argv)
55 {
56   TCHAR  binPath[FILENAME_MAX+1];
57   TCHAR  binPathShort[MAX_PATH+1];
58   DWORD  dwSize = FILENAME_MAX;
59   DWORD  dwRes;
60   TCHAR* szEnd;
61   char** new_argv;
62   int    i;
63   
64   /* Locate the binary we want to start up */
65   dwRes = 
66     SearchPath(NULL,
67                BINARY_NAME,
68                NULL,
69                dwSize,
70                (char*)binPath,
71                &szEnd);
72                
73   if (dwRes == 0) {            
74     errmsg("Unable to locate ghc.exe");
75     return 1;
76   }
77   
78   dwSize = MAX_PATH;
79   /* Turn the path into short form - LFN form causes problems
80      when passed in argv[0]. */
81   if ( !(GetShortPathName(binPath, binPathShort, dwSize)) ) {
82     errmsg("Unable to locate ghc.exe");
83     return 1;
84   }
85   
86   new_argv = (char**)malloc(sizeof(char*) * (argc + 1 + 1));
87   if (new_argv == NULL) {
88     errmsg("failed to start up ghc.exe");
89     return 1;
90   }
91   new_argv[0] = binPathShort;
92
93   new_argv[1] = (char*)malloc(sizeof(char) * (strlen(IACTIVE_OPTION) + 1));
94   if (new_argv[1]) {
95     strcpy(new_argv[1], IACTIVE_OPTION);
96   } else {
97     errmsg("failed to start up ghc.exe");
98     return 1;
99   }
100
101   for ( i=1; i < argc; i++ ) {
102     int len = strlen(argv[i]);
103     /* to avoid quoting issues, surround each option in double quotes */
104     new_argv[i+1] = (char*)malloc(sizeof(char) * (len + 3));
105     if (new_argv[i+1] == NULL) {
106       errmsg("failed to start up ghc.exe");
107       return 1;
108     } else {
109       new_argv[i+1][0] = '"';
110       strcpy(1 + new_argv[i+1], argv[i]);
111       new_argv[i+1][len+1] = '"';
112       new_argv[i+1][len+2] = '\0';
113     }
114   }
115   new_argv[i+1] = NULL;
116   
117   /* I was hoping to be able to use execv() here, but
118      the MS implementation of said function doesn't appear to
119      be quite right (the 'parent' app seems to exit without
120      waiting, which is not a spec-fulfilling thing to do).
121      
122      Cygwin gives me the right behaviour, but does it by
123      implementing it in terms of spawnv(), so you pay
124      the cost of having to create an extra process.
125      Plus, of course, we aren't allowed to use Cygwin here, because
126      GHC does not assume Cygwin.
127      
128      ==> Just use spawnv(), which is provided by msvcrt.dll, the
129          Microsoft C runtime to which mingw delegates almost all
130          system calls
131
132          [Sigbjorn adds 12 Jun 03]
133      We probably ought to use CreateProcess() in ghci.c -- or better still an exec()-like
134      that didn't have to create a separate process from the wrapper (which is what that
135      code comment in there is driving at.) 
136       
137      CreateProcess() is a more wieldy function to invoke, which is probably why
138      I opted for spawnv(). spawnv() performs the equivalent of Prelude.unwords
139      (to look at the code itself, or at least an older version, see dospawn.c in the
140      vc98/crt/src/ directory of an MSVC6 installation.)
141       
142      CreateProcess() is a native Win32 API though, which has the merit that it is
143      guaranteed to work the same with both the mingw and cygwin ports.
144   */
145 #if 0
146   fprintf(stderr, "Invoking ghc: ");
147   i=0;
148   while (new_argv[i] != NULL) {
149     fprintf(stderr, "%s ", new_argv[i++]);
150   }
151   fprintf(stderr, "\n"); fflush(stderr);
152 #endif
153   return _spawnv(_P_WAIT, binPath, new_argv);
154 }