convert to use System.FilePath
[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         fflush(stdout);
40     }
41     memcpy(args + 3, argv + 1, sizeof(char *) * (argc - 1));
42     args[argc+2] = NULL;
43     return run(argv[0], GHC_PATH, argc + 2, args);
44 }
45
46 #ifndef WINDOWS
47 int run(char *this, char *program, int argc, char** argv) {
48     execv(program, argv);
49     return 1; /* Not reached */
50 }
51 #else
52 int run(char *this, char *program, int argc, char** argv) {
53     TCHAR  programShort[MAX_PATH+1];
54     DWORD  dwSize;
55     DWORD  dwExitCode;
56     int    i;
57     char*  new_cmdline;
58     char   *ptr;
59     char   *src;
60     unsigned int cmdline_len;
61
62     STARTUPINFO si;
63     PROCESS_INFORMATION pi;
64   
65     ZeroMemory(&si, sizeof(STARTUPINFO));
66     ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
67
68     si.cb = sizeof(STARTUPINFO);
69
70     dwSize = MAX_PATH;
71     /* Turn the path into short form - LFN form causes problems
72        when passed in argv[0]. */
73     if ( !(GetShortPathName(program, programShort, dwSize)) ) {
74         error("%s: Unable to locate %s", this, program);
75         return 1;
76     }
77   
78     /* Compute length of the flattened 'argv', including spaces! */
79     cmdline_len = 0;
80     for(i = 1; i < argc; i++) {
81         /* Note: play it safe and quote all argv strings */
82         cmdline_len += 1 + strlen(argv[i]) + 2;
83     }
84     new_cmdline = (char*)malloc(sizeof(char) * (cmdline_len + 1));
85     if (!new_cmdline) {
86         error("%s: failed to start up ghc.exe; insufficient memory", this);
87         return 1;
88     }
89   
90     ptr = new_cmdline;
91     for(i = 1; i < argc; i++) {
92         *ptr++ = ' ';
93         *ptr++ = '"';
94         src = argv[i];
95         while(*src) {
96             *ptr++ = *src++;
97         }
98         *ptr++ = '"';
99     }
100     *ptr = '\0';
101   
102     /* Note: Used to use _spawnv(_P_WAIT, ...) here, but it suffered
103        from the parent intercepting console events such as Ctrl-C,
104        which it shouldn't. Installing an ignore-all console handler
105        didn't do the trick either.
106
107        Irrespective of this issue, using CreateProcess() is preferable,
108        as it makes this wrapper work on both mingw and cygwin.
109     */
110 #if 0
111     fprintf(stderr, "Invoking ghc: %s %s\n", programShort, new_cmdline);
112     fflush(stderr);
113 #endif
114     if (!CreateProcess(programShort,
115                        new_cmdline,
116                        NULL,
117                        NULL,
118                        TRUE,
119                        0, /* dwCreationFlags */
120                        NULL, /* lpEnvironment */
121                        NULL, /* lpCurrentDirectory */
122                        &si,  /* lpStartupInfo */
123                        &pi) ) {
124         error("%s: Unable to start ghc.exe (error code: %lu)",
125               this, GetLastError());
126         return 1;
127     }
128     /* Disable handling of console events in the parent by dropping its
129      * connection to the console. This has the (minor) downside of not being
130      * able to subsequently emit any error messages to the console.
131      */
132     FreeConsole();
133
134     switch (WaitForSingleObject(pi.hProcess, INFINITE) ) {
135         case WAIT_OBJECT_0:
136             if (GetExitCodeProcess(pi.hProcess, &dwExitCode)) {
137                 return dwExitCode;
138             }
139             else {
140                 return 1;
141             }
142         case WAIT_ABANDONED:
143         case WAIT_FAILED:
144             /* in the event we get any hard errors, bring the child
145                to a halt. */
146             TerminateProcess(pi.hProcess, 1);
147             return 1;
148         default:
149             return 1;
150     }
151 }
152 #endif
153