dvitomp fix from Akira
[mplib] / src / texk / kpathsea / system.c
1 /* libc replacement functions for win32.
2
3 Copyright (C) 1998, 99 Free Software Foundation, Inc.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19 /*
20   This does make sense only under WIN32.
21   Functions:
22     - win32_system() rewritten
23   */
24
25 #ifdef __MINGW32__
26
27 #include <kpathsea/config.h>
28 #include <kpathsea/c-proto.h>
29 #include <kpathsea/win32lib.h>
30 #include <kpathsea/lib.h>
31 #include <errno.h>
32
33 /* from lookcmd.c */
34 extern void *parse_cmdline(char *line, char **input, char **output);
35 extern char *build_cmdline(char ***cmd, char *input, char *output);
36
37 /*
38   It has been proven that system() fails to retrieve exit codes
39   under Win9x. This is a workaround for this bug.
40 */
41
42 int __cdecl win32_system(const char *cmd, int async)
43 {
44   STARTUPINFO si;
45   PROCESS_INFORMATION pi;
46   DWORD ret = 0;
47   HANDLE hIn, hOut, hPipeIn, hPipeOut;
48   SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
49   int i;
50
51   char  *app_name, *new_cmd;
52   char  *red_input, *red_output, ***cmd_pipe;
53
54   /* Reset errno ??? */
55   errno = 0;
56
57   /* Admittedly, the command interpreter will allways be found. */
58   if (! cmd) {
59     errno = 0;
60 #ifdef _TRACE
61     fprintf(stderr, "system: (null) command.\n");
62 #endif
63     return 1;
64   }
65
66   if (look_for_cmd(cmd, &app_name, &new_cmd) == FALSE) {
67     /* Failed to find the command or malformed cmd */
68     errno = ENOEXEC;
69 #ifdef _TRACE
70     fprintf(stderr, "system: failed to find command.\n");
71 #endif
72     return -1;
73   }
74
75   cmd_pipe = parse_cmdline(new_cmd, &red_input, &red_output);
76
77   for (i = 0; cmd_pipe[i]; i++) {
78
79     /* free the cmd and build the current one */
80     if (new_cmd) free(new_cmd);
81
82     new_cmd = build_cmdline(&cmd_pipe[i], NULL, NULL);
83
84     /* First time, use red_input if available */
85     if (i == 0) {
86       if (red_input) {
87         hIn = CreateFile(red_input,
88                          GENERIC_READ,
89                          FILE_SHARE_READ | FILE_SHARE_WRITE,
90                          &sa,
91                          OPEN_EXISTING,
92                          FILE_ATTRIBUTE_NORMAL,
93                          NULL);
94         if (hIn == INVALID_HANDLE_VALUE) {
95 #ifdef _TRACE
96           fprintf(stderr, "system: failed to open hIn (%s) with error %d.\n", red_input, GetLastError());
97 #endif
98           errno = EIO;
99           return -1;
100         }
101       }
102       else {
103         hIn = GetStdHandle(STD_INPUT_HANDLE);
104       }
105     }
106     /* Last time, use red_output if available */
107     if (cmd_pipe[i+1] == NULL) {
108       if (red_output) {
109         hOut = CreateFile(red_output,
110                           GENERIC_WRITE,
111                           FILE_SHARE_READ | FILE_SHARE_WRITE,
112                           &sa,
113                           OPEN_ALWAYS,
114                           FILE_ATTRIBUTE_NORMAL,
115                           NULL);
116         if (hOut == INVALID_HANDLE_VALUE) {
117 #ifdef _TRACE
118           fprintf(stderr, "system: failed to open hOut (%s) with error %d.\n", red_output, GetLastError());
119 #endif
120           errno = EIO;
121           return -1;
122         }
123       }
124       else {
125         hOut = GetStdHandle(STD_OUTPUT_HANDLE);
126       }
127     }
128
129 #if 0
130     /* FIXME : implement pipes !!! */
131 #endif
132
133     ZeroMemory( &si, sizeof(STARTUPINFO) );
134     si.cb = sizeof(STARTUPINFO);
135     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
136     si.wShowWindow = SW_SHOW;
137     si.hStdInput = hIn;
138     si.hStdOutput = hOut;
139     si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
140
141 #ifdef _TRACE
142     fprintf(stderr, "Executing: %s\n", new_cmd);
143 #endif
144     if (CreateProcess(app_name,
145                       new_cmd,
146                       NULL,
147                       NULL,
148                       TRUE,
149                       0,
150                       NULL,
151                       NULL,
152                       &si,
153                       &pi) == 0) {
154       fprintf(stderr, "win32_system(%s) call failed (Error %d).\n", cmd, GetLastError());
155       return -1;
156     }
157     
158     /* Only the process handle is needed */
159     CloseHandle(pi.hThread);
160     
161     if (async == 0) {
162       if (WaitForSingleObject(pi.hProcess, INFINITE) == WAIT_OBJECT_0) {
163         if (GetExitCodeProcess(pi.hProcess, &ret) == 0) {
164           fprintf(stderr, "Failed to retrieve exit code: %s (Error %d)\n", cmd, GetLastError());
165           ret = -1;
166         }
167       }
168       else {
169         fprintf(stderr, "Failed to wait for process termination: %s (Error %d)\n", cmd, GetLastError());
170         ret = -1;
171       }
172     }
173
174     CloseHandle(pi.hProcess);
175
176     if (red_input) CloseHandle(hIn);
177     if (red_output) CloseHandle(hOut);
178   }
179
180   if (new_cmd) free(new_cmd);
181   if (app_name) free(app_name);
182     
183   return ret;
184 }
185
186 #endif