[project @ 2003-06-11 07:23:06 by simonpj]
[ghc-hetmet.git] / ghc / driver / ghci / ghci.c
1 /*
2  *
3  * $Id: ghci.c,v 1.7 2003/06/11 07:23:06 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 #if 0
133   fprintf(stderr, "Invoking ghc: ");
134   i=0;
135   while (new_argv[i] != NULL) {
136     fprintf(stderr, "%s ", new_argv[i++]);
137   }
138   fprintf(stderr, "\n"); fflush(stderr);
139 #endif
140   return _spawnv(_P_WAIT, binPath, new_argv);
141 }