xref: /reactos/sdk/lib/crt/stdio/popen.c (revision 50cf16b3)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS C runtime library
4  * FILE:            lib/sdk/crt/stdio/popen.c
5  * PURPOSE:         Pipe Functions
6  * PROGRAMMERS:     Eric Kohl
7  *                  Hartmut Birr
8  *                  Also adapted from Wine team code by Andreas Maier.
9  */
10 
11 #include <precomp.h>
12 #include <tchar.h>
13 
14 #ifdef _UNICODE
15 #define sT "S"
16 #else
17 #define sT "s"
18 #endif
19 
20 #define MK_STR(s) #s
21 
22 int msvcrt_alloc_fd(HANDLE hand, int flag); //FIXME: Remove
23 unsigned split_oflags(unsigned oflags); //FIXME: Remove
24 
25 #ifndef _UNICODE
26 struct popen_handle *popen_handles = NULL;
27 DWORD popen_handles_size = 0;
28 
29 void msvcrt_free_popen_data(void)
30 {
31     free(popen_handles);
32 }
33 #endif
34 
35 /*
36  * @implemented
37  */
38 FILE *_tpopen (const _TCHAR *cm, const _TCHAR *md) /* program name, pipe mode */
39 {
40     _TCHAR *szCmdLine=NULL;
41     _TCHAR *szComSpec=NULL;
42     _TCHAR *s;
43     FILE *ret;
44     HANDLE hReadPipe, hWritePipe;
45     BOOL result;
46     STARTUPINFO StartupInfo;
47     PROCESS_INFORMATION ProcessInformation;
48     SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
49     struct popen_handle *container;
50     DWORD i;
51 
52     TRACE(MK_STR(_tpopen)"('%"sT"', '%"sT"')\n", cm, md);
53 
54     if (cm == NULL)
55         return NULL;
56 
57     szComSpec = _tgetenv(_T("COMSPEC"));
58     if (szComSpec == NULL)
59     {
60         szComSpec = _T("cmd.exe");
61     }
62 
63     s = max(_tcsrchr(szComSpec, '\\'), _tcsrchr(szComSpec, '/'));
64     if (s == NULL)
65         s = szComSpec;
66     else
67         s++;
68 
69     szCmdLine = malloc((_tcslen(s) + 4 + _tcslen(cm) + 1) * sizeof(_TCHAR));
70     if (szCmdLine == NULL)
71     {
72         return NULL;
73     }
74 
75     _tcscpy(szCmdLine, s);
76     s = _tcsrchr(szCmdLine, '.');
77     if (s)
78         *s = 0;
79     _tcscat(szCmdLine, _T(" /C "));
80     _tcscat(szCmdLine, cm);
81 
82     if ( !CreatePipe(&hReadPipe,&hWritePipe,&sa,1024))
83     {
84         free (szCmdLine);
85         return NULL;
86     }
87 
88     memset(&ProcessInformation, 0, sizeof(ProcessInformation));
89     memset(&StartupInfo, 0, sizeof(STARTUPINFO));
90     StartupInfo.cb = sizeof(STARTUPINFO);
91 
92     if (*md == 'r' ) {
93         StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
94         StartupInfo.hStdOutput = hWritePipe;
95         StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
96     }
97     else if ( *md == 'w' ) {
98         StartupInfo.hStdInput = hReadPipe;
99         StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
100         StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
101     }
102 
103     if (StartupInfo.dwFlags & STARTF_USESTDHANDLES)
104         StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
105 
106     result = CreateProcess(szComSpec,
107         szCmdLine,
108         NULL,
109         NULL,
110         TRUE,
111         0,
112         NULL,
113         NULL,
114         &StartupInfo,
115         &ProcessInformation);
116     free (szCmdLine);
117 
118     if (result == FALSE)
119     {
120         CloseHandle(hReadPipe);
121         CloseHandle(hWritePipe);
122         return NULL;
123     }
124 
125     CloseHandle(ProcessInformation.hThread);
126 
127     _mlock(_POPEN_LOCK);
128     for(i=0; i<popen_handles_size; i++)
129     {
130         if (!popen_handles[i].f)
131             break;
132     }
133     if (i==popen_handles_size)
134     {
135         i = (popen_handles_size ? popen_handles_size*2 : 8);
136         container = realloc(popen_handles, i*sizeof(*container));
137         if (!container) goto error;
138 
139         popen_handles = container;
140         container = popen_handles+popen_handles_size;
141         memset(container, 0, (i-popen_handles_size)*sizeof(*container));
142         popen_handles_size = i;
143     }
144     else container = popen_handles+i;
145 
146     if ( *md == 'r' )
147     {
148         ret = _tfdopen(msvcrt_alloc_fd(hReadPipe,  split_oflags(_fmode)) , _T("r"));
149         CloseHandle(hWritePipe);
150     }
151     else
152     {
153         ret = _tfdopen( msvcrt_alloc_fd(hWritePipe, split_oflags(_fmode)) , _T("w"));
154         CloseHandle(hReadPipe);
155     }
156 
157     container->f = ret;
158     container->proc = ProcessInformation.hProcess;
159     _munlock(_POPEN_LOCK);
160 
161     return ret;
162 
163 error:
164     _munlock(_POPEN_LOCK);
165     if (ProcessInformation.hProcess != 0)
166         CloseHandle(ProcessInformation.hProcess);
167     return NULL;
168 }
169 
170 #ifndef _UNICODE
171 
172 /*
173  * @implemented
174  */
175 int CDECL _pclose(FILE* file)
176 {
177     HANDLE h;
178     DWORD i;
179 
180     if (!MSVCRT_CHECK_PMT(file != NULL)) return -1;
181 
182     _mlock(_POPEN_LOCK);
183     for(i=0; i<popen_handles_size; i++)
184     {
185         if (popen_handles[i].f == file)
186             break;
187     }
188     if(i == popen_handles_size)
189     {
190         _munlock(_POPEN_LOCK);
191         *_errno() = EBADF;
192         return -1;
193     }
194 
195     h = popen_handles[i].proc;
196     popen_handles[i].f = NULL;
197     _munlock(_POPEN_LOCK);
198 
199     fclose(file);
200     if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i))
201     {
202         _dosmaperr(GetLastError());
203         CloseHandle(h);
204         return -1;
205     }
206 
207     CloseHandle(h);
208     return i;
209 }
210 
211 #endif
212