Fix ghc-inplace.c on Windows; new code based on ghci.c
[ghc-hetmet.git] / compiler / ghc-inplace.c
1
2 #include <stdio.h>
3 #include <stdarg.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <unistd.h>
7
8 #ifdef WINDOWS
9 #include <windows.h>
10 #include <process.h>
11 #include <malloc.h>
12 #include <signal.h>
13 #include <io.h>
14 #endif
15
16 int run(char *this, char *program, int argc, char **argv);
17
18 void error(const char *fmt, ...) {
19     va_list argp;
20     va_start(argp, fmt);
21     vfprintf(stderr, fmt, argp);
22     va_end(argp);
23     fprintf(stderr, "\n");
24     fflush(stderr);
25 }
26
27 int main(int argc, char **argv) {
28     char **args;
29     args = malloc(sizeof(char *) * (argc + 3));
30     if (args == NULL) {
31         fprintf(stderr, "Malloc failed\n");
32         exit(1);
33     }
34     args[0] = GHC_PATH;
35     args[1] = "-B" TOP_ABS;
36     args[2] = "-fhardwire-lib-paths";
37     if ((argc >= 2) && (strcmp(argv[1], "-v") == 0)) {
38         printf("Using %s %s %s\n", args[0], args[1], args[2]);
39     }
40     memcpy(args + 3, argv + 1, sizeof(char *) * (argc - 1));
41     args[argc+2] = NULL;
42     return run(argv[0], GHC_PATH, argc + 2, args);
43 }
44
45 #ifndef WINDOWS
46 int run(char *this, char *program, int argc, char** argv) {
47     execv(program, argv);
48     return 1; /* Not reached */
49 }
50 #else
51 int run(char *this, char *program, int argc, char** argv) {
52     TCHAR  programShort[MAX_PATH+1];
53     DWORD  dwSize;
54     int    i;
55     char*  new_cmdline;
56     char   *ptr;
57     char   *src;
58     unsigned int cmdline_len;
59
60     STARTUPINFO si;
61     PROCESS_INFORMATION pi;
62   
63     ZeroMemory(&si, sizeof(STARTUPINFO));
64     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
65
66     si.cb = sizeof(STARTUPINFO);
67
68     dwSize = MAX_PATH;
69     /* Turn the path into short form - LFN form causes problems
70        when passed in argv[0]. */
71     if ( !(GetShortPathName(program, programShort, dwSize)) ) {
72         error("%s: Unable to locate %s", this, program);
73         return 1;
74     }
75   
76     /* Compute length of the flattened 'argv', including spaces! */
77     cmdline_len = 0;
78     for(i = 1; i < argc; i++) {
79         /* Note: play it safe and quote all argv strings */
80         cmdline_len += 1 + strlen(argv[i]) + 2;
81     }
82     new_cmdline = (char*)malloc(sizeof(char) * (cmdline_len + 1));
83     if (!new_cmdline) {
84         error("%s: failed to start up ghc.exe; insufficient memory", this);
85         return 1;
86     }
87   
88     ptr = new_cmdline;
89     for(i = 1; i < argc; i++) {
90         *ptr++ = ' ';
91         *ptr++ = '"';
92         src = argv[i];
93         while(*src) {
94             *ptr++ = *src++;
95         }
96         *ptr++ = '"';
97     }
98     *ptr = '\0';
99   
100     /* Note: Used to use _spawnv(_P_WAIT, ...) here, but it suffered
101        from the parent intercepting console events such as Ctrl-C,
102        which it shouldn't. Installing an ignore-all console handler
103        didn't do the trick either.
104
105        Irrespective of this issue, using CreateProcess() is preferable,
106        as it makes this wrapper work on both mingw and cygwin.
107     */
108 #if 0
109     fprintf(stderr, "Invoking ghc: %s %s\n", programShort, new_cmdline);
110     fflush(stderr);
111 #endif
112     if (!CreateProcess(programShort,
113                        new_cmdline,
114                        NULL,
115                        NULL,
116                        TRUE,
117                        0, /* dwCreationFlags */
118                        NULL, /* lpEnvironment */
119                        NULL, /* lpCurrentDirectory */
120                        &si,  /* lpStartupInfo */
121                        &pi) ) {
122         error("%s: Unable to start ghc.exe (error code: %lu)",
123               this, GetLastError());
124         return 1;
125     }
126     /* Disable handling of console events in the parent by dropping its
127      * connection to the console. This has the (minor) downside of not being
128      * able to subsequently emit any error messages to the console.
129      */
130     FreeConsole();
131
132     switch (WaitForSingleObject(pi.hProcess, INFINITE) ) {
133         case WAIT_OBJECT_0:
134             return 0;
135         case WAIT_ABANDONED:
136         case WAIT_FAILED:
137             /* in the event we get any hard errors, bring the child
138                to a halt. */
139             TerminateProcess(pi.hProcess, 1);
140             return 1;
141         default:
142             return 1;
143     }
144 }
145 #endif
146