ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/common/win_popen.c
Revision: 1.2
Committed: Mon Oct 27 10:19:31 2003 UTC (20 years, 6 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 1.1: +3 -3 lines
Log Message:
Added gethomedir.c and various compatibility fixes.

File Contents

# User Rev Content
1 schorsch 1.1 #ifndef lint
2 schorsch 1.2 static const char RCSid[] = "$Id: win_popen.c,v 1.1 2003/10/21 19:20:37 schorsch Exp $";
3 schorsch 1.1 #endif
4     /*
5     Replacement for the posix popen() on Windows
6    
7     We don't just let the shell do the work like the original.
8     Since per default there's no decent shell around, we implement
9     the most basic functionality right here.
10    
11     currently supports mode "r" and | to chain several processes.
12     Substrings between matching quotes are considered one word,
13     ignoring any | within. Quotes don't nest.
14    
15     */
16    
17     #include <windows.h>
18     #include <stdlib.h>
19     #include <stdio.h>
20     #include <string.h>
21     #include <ctype.h>
22     #include <io.h> /* _open_osfhandle() */
23     #include <fcntl.h> /* _O_RDONLY */
24    
25     #include "paths.h"
26     #include "rtio.h"
27     #include "rterror.h"
28    
29    
30     #define RAD_MAX_PIPES 32 /* maximum number of pipes */
31    
32     static int parse_pipes(char*, char**, int);
33     static BOOL createPipes(HANDLE*, HANDLE*, HANDLE*, HANDLE*);
34     static BOOL runChild(char*, char*, HANDLE, HANDLE, HANDLE);
35     static void resetStdHandles(HANDLE stdoutOrig, HANDLE stdinOrig);
36    
37    
38     int
39 schorsch 1.2 win_pclose( /* posix pclose replacement */
40 schorsch 1.1 FILE* p
41     )
42     {
43     fclose(p);
44     /* not sure if it's useful to wait for anything on Windows */
45     return 0;
46     }
47    
48    
49     FILE *
50 schorsch 1.2 win_popen( /* posix popen replacement */
51 schorsch 1.1 char* command,
52     char* type
53     )
54     {
55     char *execfile, *args;
56     char *cmdlines[RAD_MAX_PIPES];
57     char executable[512];
58     int n, i;
59     int ncmds = 0;
60     HANDLE stdoutRd = NULL, stdoutWr = NULL;
61     HANDLE stdinRd = NULL, stdinWr = NULL;
62     HANDLE stderrWr = NULL;
63     HANDLE stdoutOrig, stdinOrig;
64    
65     stdoutOrig = GetStdHandle(STD_OUTPUT_HANDLE);
66     stdinOrig = GetStdHandle(STD_INPUT_HANDLE);
67     /* if we have a console, use it for error output */
68     stderrWr = GetStdHandle(STD_ERROR_HANDLE);
69    
70     if((ncmds = parse_pipes(command, cmdlines, RAD_MAX_PIPES)) <= 0) {
71     eputs("Too many pipes or malformed command.");
72     goto error;
73     }
74    
75     for(n = 0; n < ncmds; ++n) {
76     if(!createPipes(&stdoutRd, &stdoutWr,
77     &stdinRd, &stdinWr)) {
78     eputs("Error creating pipe");
79     goto error;
80     }
81     /* find the executable on the PATH */
82     args = nextword(executable, sizeof(executable), cmdlines[n]);
83     if (args == NULL) {
84     eputs("Empty command.");
85     goto error;
86     }
87     execfile = getpath(executable, getenv("PATH"), X_OK);
88     if(execfile == NULL) {
89     char estr[512];
90     _snprintf(estr, sizeof(estr),
91     "Can't find executable for \"%s\".", executable);
92     eputs(estr);
93     goto error;
94     }
95     if(!runChild(execfile, cmdlines[n], stdinRd, stdoutWr, stderrWr)) {
96     char estr[512];
97     _snprintf(estr, sizeof(estr),
98     "Unable to execute executable \"%s\".", executable);
99     eputs(estr);
100     goto error;
101     }
102     /* close the stdout end just passed to the last process,
103     or the final read will block */
104     CloseHandle(stdoutWr);
105     }
106     /* clean up */
107     resetStdHandles(stdinOrig, stdoutOrig);
108     for (i = 0; i < ncmds; i++) free(cmdlines[i]);
109    
110     /* return a standard C file pointer for reading the output */
111     return _fdopen(_open_osfhandle((long)stdoutRd, _O_RDONLY), "r");
112    
113     error:
114     resetStdHandles(stdinOrig, stdoutOrig);
115     for (i = 0; i < ncmds; i++) free(cmdlines[i]);
116     return NULL;
117     }
118    
119    
120     static BOOL
121     createPipes( /* establish matching pipes for a subprocess */
122     HANDLE* stdoutRd,
123     HANDLE* stdoutWr,
124     HANDLE* stdinRd,
125     HANDLE* stdinWr
126     )
127     {
128     HANDLE stdoutRdInh = NULL;
129     HANDLE stdinWrInh = NULL;
130     HANDLE curproc;
131     SECURITY_ATTRIBUTES sAttr;
132    
133     curproc = GetCurrentProcess();
134    
135     /* The rules of inheritance for handles are a mess.
136     Just to be safe, make all handles we pass to the
137     child processes inheritable */
138     sAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
139     sAttr.bInheritHandle = TRUE;
140     sAttr.lpSecurityDescriptor = NULL;
141    
142     if(*stdoutRd != NULL){
143     /* if we have a previous stdout pipe,
144     assign the other end to stdin for the new process */
145     CloseHandle(*stdinRd);
146     if(!DuplicateHandle(curproc, *stdoutRd,
147     curproc, stdinRd, 0,
148     TRUE, DUPLICATE_SAME_ACCESS))
149     return FALSE;
150     CloseHandle(*stdoutRd);
151     if(!SetStdHandle(STD_INPUT_HANDLE, *stdinRd))
152     return FALSE;
153     } else {
154     /* there's no previous stdout, create a new stdin pipe */
155     if(!CreatePipe(stdinRd, &stdinWrInh, &sAttr, 0))
156     return FALSE;
157     if(!SetStdHandle(STD_INPUT_HANDLE, *stdinRd))
158     return FALSE;
159     CloseHandle(stdinWrInh);
160     }
161    
162     /* create the stdout pipe for the new process */
163     if(!CreatePipe(&stdoutRdInh, stdoutWr, &sAttr, 0))
164     return FALSE;
165     if(!SetStdHandle(STD_OUTPUT_HANDLE, *stdoutWr))
166     return FALSE;
167     if(!DuplicateHandle(curproc, stdoutRdInh,
168     curproc, stdoutRd, 0,
169     FALSE, DUPLICATE_SAME_ACCESS))
170     return FALSE;
171     CloseHandle(stdoutRdInh);
172    
173     return TRUE;
174     }
175    
176    
177     static void
178     resetStdHandles( /* clean up our std streams */
179     HANDLE stdoutOrig,
180     HANDLE stdinOrig
181     )
182     {
183     SetStdHandle(STD_OUTPUT_HANDLE, stdoutOrig);
184     SetStdHandle(STD_INPUT_HANDLE, stdinOrig);
185     }
186    
187    
188     static int
189     parse_pipes( /* split a shell command pipe sequence */
190     char* s,
191     char* lines[],
192     int maxl
193     )
194     {
195     int n = 0, i;
196     char *se, *ws;
197     int llen = 0;
198     int quote = 0;
199    
200     if (maxl<= 0) return 0;
201     if (s == NULL) {
202     return 0;
203     }
204     while (isspace(*s)) s++; /* leading whitespace */
205     se = s;
206     while (n < maxl) {
207     switch (*se) {
208     case '"':
209     if (quote == '"') quote = 0;
210     else if (quote == 0) quote = '"';
211     break;
212     case '\'':
213     if (quote == '\'') quote = 0;
214     else if (quote == 0) quote = '\'';
215     break;
216     case '|':
217     case '\0':
218     if (*se == '|' && quote)
219     break;
220     llen = se - s;
221     lines[n] = malloc(llen+1);
222     strncpy(lines[n], s, llen);
223     /* remove unix style line-end escapes */
224     while((ws = strstr(lines[n], "\\\n")) != NULL)
225     *ws = *(ws+1) = ' ';
226     /* remove DOS style line-end escapes */
227     while((ws = strstr(lines[n], "\\\r\n")) != NULL)
228     *ws = *(ws+1) = *(ws+2) = ' ';
229     while (isspace(*(lines[n] + llen - 1)))
230     llen--; /* trailing whitespace */
231     lines[n][llen] = '\0';
232     n++;
233     if (*se == '\0') return n;
234     s = se + 1;
235     while (isspace(*s)) s++; /* leading whitespace */
236     se = s;
237     break;
238     default:
239     break;
240     }
241     se++;
242     }
243     /* more jobs than slots */
244     for (i = 0; i < n; i++) free(lines[i]);
245     return -1;
246     }
247    
248    
249     static BOOL
250     runChild( /* start a child process with the right std streams */
251     char* executable,
252     char* cmdline,
253     HANDLE stdinRd,
254     HANDLE stdoutWr,
255     HANDLE stderrWr
256     )
257     {
258     PROCESS_INFORMATION procInfo;
259     STARTUPINFO startupInfo;
260    
261     /* use the given handles and don't display the console window */
262     ZeroMemory(&startupInfo, sizeof(STARTUPINFO));
263     startupInfo.cb = sizeof(STARTUPINFO);
264     startupInfo.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
265     startupInfo.wShowWindow = SW_HIDE;
266     startupInfo.hStdInput = stdinRd;
267     startupInfo.hStdOutput = stdoutWr;
268     startupInfo.hStdError = stderrWr;
269    
270     return CreateProcess(executable, cmdline, NULL, NULL,
271     TRUE, 0,
272     NULL, NULL, &startupInfo, &procInfo);
273     }
274    
275    
276