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