cscript: Correct forming cmd for forwarding to wscript.
[wine] / dlls / msvcrt / process.c
1 /*
2  * msvcrt.dll spawn/exec functions
3  *
4  * Copyright 1996,1998 Marcus Meissner
5  * Copyright 1996 Jukka Iivonen
6  * Copyright 1997,2000 Uwe Bonnes
7  * Copyright 2000 Jon Griffiths
8  * Copyright 2007 Hans Leidekker
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  *
24  * FIXME:
25  * -File handles need some special handling. Sometimes children get
26  *  open file handles, sometimes not. The docs are confusing
27  * -No check for maximum path/argument/environment size is done
28  */
29 #include "config.h"
30
31 #include <stdarg.h>
32
33 #include "msvcrt.h"
34 #include "mtdll.h"
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
39
40 static void msvcrt_search_executable(const MSVCRT_wchar_t *name, MSVCRT_wchar_t *fullname, int use_path)
41 {
42   static const MSVCRT_wchar_t path[] = {'P','A','T','H',0};
43   static const MSVCRT_wchar_t suffix[][5] =
44     {{'.','c','o','m',0}, {'.','e','x','e',0}, {'.','b','a','t',0}, {'.','c','m','d',0}};
45
46   MSVCRT_wchar_t buffer[MAX_PATH];
47   const MSVCRT_wchar_t *env, *p;
48   unsigned int i, name_len, path_len;
49   int extension = 1;
50
51   *fullname = '\0';
52   msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
53
54   p = memchrW(name, '\0', MAX_PATH);
55   if (!p) p = name + MAX_PATH - 1;
56   name_len = p - name;
57
58   /* FIXME extra-long names are silently truncated */
59   memcpy(buffer, name, name_len * sizeof(MSVCRT_wchar_t));
60   buffer[name_len] = '\0';
61
62   /* try current dir first */
63   if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
64   {
65     strcpyW(fullname, buffer);
66     return;
67   }
68
69   for (p--; p >= name; p--)
70     if (*p == '\\' || *p == '/' || *p == ':' || *p == '.') break;
71
72   /* if there's no extension, try some well-known extensions */
73   if ((p < name || *p != '.') && name_len <= MAX_PATH - 5)
74   {
75     for (i = 0; i < 4; i++)
76     {
77       memcpy(buffer + name_len, suffix[i], 5 * sizeof(MSVCRT_wchar_t));
78       if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
79       {
80         strcpyW(fullname, buffer);
81         return;
82       }
83     }
84     extension = 0;
85   }
86
87   if (!use_path || !(env = MSVCRT__wgetenv(path))) return;
88
89   /* now try search path */
90   do
91   {
92     p = env;
93     while (*p && *p != ';') p++;
94     if (p == env) return;
95
96     path_len = p - env;
97     if (path_len + name_len <= MAX_PATH - 2)
98     {
99       memcpy(buffer, env, path_len * sizeof(MSVCRT_wchar_t));
100       if (buffer[path_len] != '/' && buffer[path_len] != '\\')
101       {
102         buffer[path_len++] = '\\';
103         buffer[path_len] = '\0';
104       }
105       else buffer[path_len] = '\0';
106
107       strcatW(buffer, name);
108       if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
109       {
110         strcpyW(fullname, buffer);
111         return;
112       }
113     }
114     /* again, if there's no extension, try some well-known extensions */
115     if (!extension && path_len + name_len <= MAX_PATH - 5)
116     {
117       for (i = 0; i < 4; i++)
118       {
119         memcpy(buffer + path_len + name_len, suffix[i], 5 * sizeof(MSVCRT_wchar_t));
120         if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
121         {
122           strcpyW(fullname, buffer);
123           return;
124         }
125       }
126     }
127     env = *p ? p + 1 : p;
128   } while(1);
129 }
130
131 static MSVCRT_intptr_t msvcrt_spawn(int flags, const MSVCRT_wchar_t* exe, MSVCRT_wchar_t* cmdline,
132                                     MSVCRT_wchar_t* env, int use_path)
133 {
134   STARTUPINFOW si;
135   PROCESS_INFORMATION pi;
136   MSVCRT_wchar_t fullname[MAX_PATH];
137
138   TRACE("%x %s %s %s %d\n", flags, debugstr_w(exe), debugstr_w(cmdline), debugstr_w(env), use_path);
139
140   if ((unsigned)flags > MSVCRT__P_DETACH)
141   {
142     *MSVCRT__errno() = MSVCRT_EINVAL;
143     return -1;
144   }
145
146   msvcrt_search_executable(exe, fullname, use_path);
147
148   memset(&si, 0, sizeof(si));
149   si.cb = sizeof(si);
150   msvcrt_create_io_inherit_block(&si.cbReserved2, &si.lpReserved2);
151   if (!CreateProcessW(fullname, cmdline, NULL, NULL, TRUE,
152                      flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
153                      env, NULL, &si, &pi))
154   {
155     msvcrt_set_errno(GetLastError());
156     MSVCRT_free(si.lpReserved2);
157     return -1;
158   }
159
160   MSVCRT_free(si.lpReserved2);
161   switch(flags)
162   {
163   case MSVCRT__P_WAIT:
164     WaitForSingleObject(pi.hProcess, INFINITE);
165     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
166     CloseHandle(pi.hProcess);
167     CloseHandle(pi.hThread);
168     return pi.dwProcessId;
169   case MSVCRT__P_DETACH:
170     CloseHandle(pi.hProcess);
171     pi.hProcess = 0;
172     /* fall through */
173   case MSVCRT__P_NOWAIT:
174   case MSVCRT__P_NOWAITO:
175     CloseHandle(pi.hThread);
176     return (MSVCRT_intptr_t)pi.hProcess;
177   case  MSVCRT__P_OVERLAY:
178     MSVCRT__exit(0);
179   }
180   return -1; /* can't reach here */
181 }
182
183 /* INTERNAL: Convert wide argv list to a single 'delim'-separated wide string, with an
184  * extra '\0' to terminate it.
185  */
186 static MSVCRT_wchar_t* msvcrt_argvtos(const MSVCRT_wchar_t* const* arg, MSVCRT_wchar_t delim)
187 {
188   const MSVCRT_wchar_t* const* a;
189   int size;
190   MSVCRT_wchar_t* p;
191   MSVCRT_wchar_t* ret;
192
193   if (!arg)
194   {
195       /* Return NULL for an empty environment list */
196       return NULL;
197   }
198
199   /* get length */
200   a = arg;
201   size = 0;
202   while (*a)
203   {
204     size += strlenW(*a) + 1;
205     a++;
206   }
207
208   ret = MSVCRT_malloc((size + 1) * sizeof(MSVCRT_wchar_t));
209   if (!ret)
210     return NULL;
211
212   /* fill string */
213   a = arg;
214   p = ret;
215   while (*a)
216   {
217     int len = strlenW(*a);
218     memcpy(p,*a,len * sizeof(MSVCRT_wchar_t));
219     p += len;
220     *p++ = delim;
221     a++;
222   }
223   if (delim && p > ret) p[-1] = 0;
224   else *p = 0;
225   return ret;
226 }
227
228 /* INTERNAL: Convert ansi argv list to a single 'delim'-separated wide string, with an
229  * extra '\0' to terminate it.
230  */
231 static MSVCRT_wchar_t *msvcrt_argvtos_aw(const char * const *arg, MSVCRT_wchar_t delim)
232 {
233   const char * const *a;
234   unsigned int len;
235   MSVCRT_wchar_t *p, *ret;
236
237   if (!arg)
238   {
239       /* Return NULL for an empty environment list */
240       return NULL;
241   }
242
243   /* get length */
244   a = arg;
245   len = 0;
246   while (*a)
247   {
248     len += MultiByteToWideChar(CP_ACP, 0, *a, -1, NULL, 0);
249     a++;
250   }
251
252   ret = MSVCRT_malloc((len + 1) * sizeof(MSVCRT_wchar_t));
253   if (!ret)
254     return NULL;
255
256   /* fill string */
257   a = arg;
258   p = ret;
259   while (*a)
260   {
261     p += MultiByteToWideChar(CP_ACP, 0, *a, strlen(*a), p, len - (p - ret));
262     *p++ = delim;
263     a++;
264   }
265   if (delim && p > ret) p[-1] = 0;
266   else *p = 0;
267   return ret;
268 }
269
270 /* INTERNAL: Convert wide va_list to a single 'delim'-separated wide string, with an
271  * extra '\0' to terminate it.
272  */
273 static MSVCRT_wchar_t *msvcrt_valisttos(const MSVCRT_wchar_t *arg0, __ms_va_list alist, MSVCRT_wchar_t delim)
274 {
275     unsigned int size = 0, pos = 0;
276     const MSVCRT_wchar_t *arg;
277     MSVCRT_wchar_t *new, *ret = NULL;
278
279     for (arg = arg0; arg; arg = va_arg( alist, MSVCRT_wchar_t * ))
280     {
281         unsigned int len = strlenW( arg ) + 1;
282         if (pos + len >= size)
283         {
284             size = max( 256, size * 2 );
285             size = max( size, pos + len + 1 );
286             if (!(new = MSVCRT_realloc( ret, size * sizeof(MSVCRT_wchar_t) )))
287             {
288                 MSVCRT_free( ret );
289                 return NULL;
290             }
291             ret = new;
292         }
293         strcpyW( ret + pos, arg );
294         pos += len;
295         ret[pos - 1] = delim;
296     }
297     if (pos)
298     {
299         if (delim) ret[pos - 1] = 0;
300         else ret[pos] = 0;
301     }
302     return ret;
303 }
304
305 /* INTERNAL: Convert ansi va_list to a single 'delim'-separated wide string, with an
306  * extra '\0' to terminate it.
307  */
308 static MSVCRT_wchar_t *msvcrt_valisttos_aw(const char *arg0, __ms_va_list alist, MSVCRT_wchar_t delim)
309 {
310     unsigned int size = 0, pos = 0;
311     const char *arg;
312     MSVCRT_wchar_t *new, *ret = NULL;
313
314     for (arg = arg0; arg; arg = va_arg( alist, char * ))
315     {
316         unsigned int len = MultiByteToWideChar( CP_ACP, 0, arg, -1, NULL, 0 );
317         if (pos + len >= size)
318         {
319             size = max( 256, size * 2 );
320             size = max( size, pos + len + 1 );
321             if (!(new = MSVCRT_realloc( ret, size * sizeof(MSVCRT_wchar_t) )))
322             {
323                 MSVCRT_free( ret );
324                 return NULL;
325             }
326             ret = new;
327         }
328         pos += MultiByteToWideChar( CP_ACP, 0, arg, -1, ret + pos, size - pos );
329         ret[pos - 1] = delim;
330     }
331     if (pos)
332     {
333         if (delim) ret[pos - 1] = 0;
334         else ret[pos] = 0;
335     }
336     return ret;
337 }
338
339 /* INTERNAL: retrieve COMSPEC environment variable */
340 static MSVCRT_wchar_t *msvcrt_get_comspec(void)
341 {
342   static const MSVCRT_wchar_t cmd[] = {'c','m','d',0};
343   static const MSVCRT_wchar_t comspec[] = {'C','O','M','S','P','E','C',0};
344   MSVCRT_wchar_t *ret;
345   unsigned int len;
346
347   if (!(len = GetEnvironmentVariableW(comspec, NULL, 0))) len = sizeof(cmd)/sizeof(MSVCRT_wchar_t);
348   if ((ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t))))
349   {
350     if (!GetEnvironmentVariableW(comspec, ret, len)) strcpyW(ret, cmd);
351   }
352   return ret;
353 }
354
355 /*********************************************************************
356  *              _cwait (MSVCRT.@)
357  */
358 MSVCRT_intptr_t CDECL _cwait(int *status, MSVCRT_intptr_t pid, int action)
359 {
360   HANDLE hPid = (HANDLE)pid;
361   int doserrno;
362
363   action = action; /* Remove warning */
364
365   if (!WaitForSingleObject(hPid, INFINITE))
366   {
367     if (status)
368     {
369       DWORD stat;
370       GetExitCodeProcess(hPid, &stat);
371       *status = (int)stat;
372     }
373     return pid;
374   }
375   doserrno = GetLastError();
376
377   if (doserrno == ERROR_INVALID_HANDLE)
378   {
379     *MSVCRT__errno() =  MSVCRT_ECHILD;
380     *MSVCRT___doserrno() = doserrno;
381   }
382   else
383     msvcrt_set_errno(doserrno);
384
385   return status ? *status = -1 : -1;
386 }
387
388 /*********************************************************************
389  *      _wexecl (MSVCRT.@)
390  *
391  * Unicode version of _execl
392  */
393 MSVCRT_intptr_t CDECL _wexecl(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
394 {
395   __ms_va_list ap;
396   MSVCRT_wchar_t *args;
397   MSVCRT_intptr_t ret;
398
399   __ms_va_start(ap, arg0);
400   args = msvcrt_valisttos(arg0, ap, ' ');
401   __ms_va_end(ap);
402
403   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL, 0);
404
405   MSVCRT_free(args);
406   return ret;
407 }
408
409 /*********************************************************************
410  *              _execl (MSVCRT.@)
411  *
412  * Like on Windows, this function does not handle arguments with spaces
413  * or double-quotes.
414  */
415 MSVCRT_intptr_t CDECL _execl(const char* name, const char* arg0, ...)
416 {
417   __ms_va_list ap;
418   MSVCRT_wchar_t *nameW, *args;
419   MSVCRT_intptr_t ret;
420
421   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
422
423   __ms_va_start(ap, arg0);
424   args = msvcrt_valisttos_aw(arg0, ap, ' ');
425   __ms_va_end(ap);
426
427   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, NULL, 0);
428
429   MSVCRT_free(nameW);
430   MSVCRT_free(args);
431   return ret;
432 }
433
434 /*********************************************************************
435  *      _wexecle (MSVCRT.@)
436  *
437  * Unicode version of _execle
438  */
439 MSVCRT_intptr_t CDECL _wexecle(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
440 {
441   __ms_va_list ap;
442   MSVCRT_wchar_t *args, *envs = NULL;
443   const MSVCRT_wchar_t * const *envp;
444   MSVCRT_intptr_t ret;
445
446   __ms_va_start(ap, arg0);
447   args = msvcrt_valisttos(arg0, ap, ' ');
448   __ms_va_end(ap);
449
450   __ms_va_start(ap, arg0);
451   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
452   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
453   if (envp) envs = msvcrt_argvtos(envp, 0);
454   __ms_va_end(ap);
455
456   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, envs, 0);
457
458   MSVCRT_free(args);
459   MSVCRT_free(envs);
460   return ret;
461 }
462
463 /*********************************************************************
464  *              _execle (MSVCRT.@)
465  */
466 MSVCRT_intptr_t CDECL _execle(const char* name, const char* arg0, ...)
467 {
468   __ms_va_list ap;
469   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
470   const char * const *envp;
471   MSVCRT_intptr_t ret;
472
473   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
474
475   __ms_va_start(ap, arg0);
476   args = msvcrt_valisttos_aw(arg0, ap, ' ');
477   __ms_va_end(ap);
478
479   __ms_va_start(ap, arg0);
480   while (va_arg( ap, char * ) != NULL) /*nothing*/;
481   envp = va_arg( ap, const char * const * );
482   if (envp) envs = msvcrt_argvtos_aw(envp, 0);
483   __ms_va_end(ap);
484
485   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, envs, 0);
486
487   MSVCRT_free(nameW);
488   MSVCRT_free(args);
489   MSVCRT_free(envs);
490   return ret;
491 }
492
493 /*********************************************************************
494  *      _wexeclp (MSVCRT.@)
495  *
496  * Unicode version of _execlp
497  */
498 MSVCRT_intptr_t CDECL _wexeclp(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
499 {
500   __ms_va_list ap;
501   MSVCRT_wchar_t *args;
502   MSVCRT_intptr_t ret;
503
504   __ms_va_start(ap, arg0);
505   args = msvcrt_valisttos(arg0, ap, ' ');
506   __ms_va_end(ap);
507
508   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL, 1);
509
510   MSVCRT_free(args);
511   return ret;
512 }
513
514 /*********************************************************************
515  *              _execlp (MSVCRT.@)
516  *
517  * Like on Windows, this function does not handle arguments with spaces
518  * or double-quotes.
519  */
520 MSVCRT_intptr_t CDECL _execlp(const char* name, const char* arg0, ...)
521 {
522   __ms_va_list ap;
523   MSVCRT_wchar_t *nameW, *args;
524   MSVCRT_intptr_t ret;
525
526   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
527
528   __ms_va_start(ap, arg0);
529   args = msvcrt_valisttos_aw(arg0, ap, ' ');
530   __ms_va_end(ap);
531
532   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, NULL, 1);
533
534   MSVCRT_free(nameW);
535   MSVCRT_free(args);
536   return ret;
537 }
538
539 /*********************************************************************
540  *      _wexeclpe (MSVCRT.@)
541  *
542  * Unicode version of _execlpe
543  */
544 MSVCRT_intptr_t CDECL _wexeclpe(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
545 {
546   __ms_va_list ap;
547   MSVCRT_wchar_t *args, *envs = NULL;
548   const MSVCRT_wchar_t * const *envp;
549   MSVCRT_intptr_t ret;
550
551   __ms_va_start(ap, arg0);
552   args = msvcrt_valisttos(arg0, ap, ' ');
553   __ms_va_end(ap);
554
555   __ms_va_start(ap, arg0);
556   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
557   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
558   if (envp) envs = msvcrt_argvtos(envp, 0);
559   __ms_va_end(ap);
560
561   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, envs, 1);
562
563   MSVCRT_free(args);
564   MSVCRT_free(envs);
565   return ret;
566 }
567
568 /*********************************************************************
569  *              _execlpe (MSVCRT.@)
570  */
571 MSVCRT_intptr_t CDECL _execlpe(const char* name, const char* arg0, ...)
572 {
573   __ms_va_list ap;
574   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
575   const char * const *envp;
576   MSVCRT_intptr_t ret;
577
578   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
579
580   __ms_va_start(ap, arg0);
581   args = msvcrt_valisttos_aw(arg0, ap, ' ');
582   __ms_va_end(ap);
583
584   __ms_va_start(ap, arg0);
585   while (va_arg( ap, char * ) != NULL) /*nothing*/;
586   envp = va_arg( ap, const char * const * );
587   if (envp) envs = msvcrt_argvtos_aw(envp, 0);
588   __ms_va_end(ap);
589
590   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, envs, 1);
591
592   MSVCRT_free(nameW);
593   MSVCRT_free(args);
594   MSVCRT_free(envs);
595   return ret;
596 }
597
598 /*********************************************************************
599  *      _wexecv (MSVCRT.@)
600  *
601  * Unicode version of _execv
602  */
603 MSVCRT_intptr_t CDECL _wexecv(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv)
604 {
605   return MSVCRT__wspawnve(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, NULL);
606 }
607
608 /*********************************************************************
609  *              _execv (MSVCRT.@)
610  *
611  * Like on Windows, this function does not handle arguments with spaces
612  * or double-quotes.
613  */
614 MSVCRT_intptr_t CDECL _execv(const char* name, char* const* argv)
615 {
616   return MSVCRT__spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
617 }
618
619 /*********************************************************************
620  *      _wexecve (MSVCRT.@)
621  *
622  * Unicode version of _execve
623  */
624 MSVCRT_intptr_t CDECL _wexecve(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv, const MSVCRT_wchar_t* const* envv)
625 {
626   return MSVCRT__wspawnve(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, envv);
627 }
628
629 /*********************************************************************
630  *              _execve (MSVCRT.@)
631  *
632  * Like on Windows, this function does not handle arguments with spaces
633  * or double-quotes.
634  */
635 MSVCRT_intptr_t CDECL MSVCRT__execve(const char* name, char* const* argv, const char* const* envv)
636 {
637   return MSVCRT__spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
638 }
639
640 /*********************************************************************
641  *      _wexecvpe (MSVCRT.@)
642  *
643  * Unicode version of _execvpe
644  */
645 MSVCRT_intptr_t CDECL _wexecvpe(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv, const MSVCRT_wchar_t* const* envv)
646 {
647   return MSVCRT__wspawnvpe(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, envv);
648 }
649
650 /*********************************************************************
651  *              _execvpe (MSVCRT.@)
652  *
653  * Like on Windows, this function does not handle arguments with spaces
654  * or double-quotes.
655  */
656 MSVCRT_intptr_t CDECL _execvpe(const char* name, char* const* argv, const char* const* envv)
657 {
658   return MSVCRT__spawnvpe(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
659 }
660
661 /*********************************************************************
662  *      _wexecvp (MSVCRT.@)
663  *
664  * Unicode version of _execvp
665  */
666 MSVCRT_intptr_t CDECL _wexecvp(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv)
667 {
668   return _wexecvpe(name, argv, NULL);
669 }
670
671 /*********************************************************************
672  *              _execvp (MSVCRT.@)
673  *
674  * Like on Windows, this function does not handle arguments with spaces
675  * or double-quotes.
676  */
677 MSVCRT_intptr_t CDECL _execvp(const char* name, char* const* argv)
678 {
679   return _execvpe(name, argv, NULL);
680 }
681
682 /*********************************************************************
683  *      _wspawnl (MSVCRT.@)
684  *
685  * Unicode version of _spawnl
686  */
687 MSVCRT_intptr_t CDECL _wspawnl(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
688 {
689   __ms_va_list ap;
690   MSVCRT_wchar_t *args;
691   MSVCRT_intptr_t ret;
692
693   __ms_va_start(ap, arg0);
694   args = msvcrt_valisttos(arg0, ap, ' ');
695   __ms_va_end(ap);
696
697   ret = msvcrt_spawn(flags, name, args, NULL, 0);
698
699   MSVCRT_free(args);
700   return ret;
701 }
702
703 /*********************************************************************
704  *              _spawnl (MSVCRT.@)
705  *
706  * Like on Windows, this function does not handle arguments with spaces
707  * or double-quotes.
708  */
709 MSVCRT_intptr_t CDECL _spawnl(int flags, const char* name, const char* arg0, ...)
710 {
711   __ms_va_list ap;
712   MSVCRT_wchar_t *nameW, *args;
713   MSVCRT_intptr_t ret;
714
715   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
716
717   __ms_va_start(ap, arg0);
718   args = msvcrt_valisttos_aw(arg0, ap, ' ');
719   __ms_va_end(ap);
720
721   ret = msvcrt_spawn(flags, nameW, args, NULL, 0);
722
723   MSVCRT_free(nameW);
724   MSVCRT_free(args);
725   return ret;
726 }
727
728 /*********************************************************************
729  *      _wspawnle (MSVCRT.@)
730  *
731  * Unicode version of _spawnle
732  */
733 MSVCRT_intptr_t CDECL _wspawnle(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
734 {
735   __ms_va_list ap;
736   MSVCRT_wchar_t *args, *envs = NULL;
737   const MSVCRT_wchar_t * const *envp;
738   MSVCRT_intptr_t ret;
739
740   __ms_va_start(ap, arg0);
741   args = msvcrt_valisttos(arg0, ap, ' ');
742   __ms_va_end(ap);
743
744   __ms_va_start(ap, arg0);
745   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
746   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
747   if (envp) envs = msvcrt_argvtos(envp, 0);
748   __ms_va_end(ap);
749
750   ret = msvcrt_spawn(flags, name, args, envs, 0);
751
752   MSVCRT_free(args);
753   MSVCRT_free(envs);
754   return ret;
755 }
756
757 /*********************************************************************
758  *              _spawnle (MSVCRT.@)
759  */
760 MSVCRT_intptr_t CDECL _spawnle(int flags, const char* name, const char* arg0, ...)
761 {
762   __ms_va_list ap;
763   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
764   const char * const *envp;
765   MSVCRT_intptr_t ret;
766
767   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
768
769   __ms_va_start(ap, arg0);
770   args = msvcrt_valisttos_aw(arg0, ap, ' ');
771   __ms_va_end(ap);
772
773   __ms_va_start(ap, arg0);
774   while (va_arg( ap, char * ) != NULL) /*nothing*/;
775   envp = va_arg( ap, const char * const * );
776   if (envp) envs = msvcrt_argvtos_aw(envp, 0);
777   __ms_va_end(ap);
778
779   ret = msvcrt_spawn(flags, nameW, args, envs, 0);
780
781   MSVCRT_free(nameW);
782   MSVCRT_free(args);
783   MSVCRT_free(envs);
784   return ret;
785 }
786
787 /*********************************************************************
788  *      _wspawnlp (MSVCRT.@)
789  *
790  * Unicode version of _spawnlp
791  */
792 MSVCRT_intptr_t CDECL _wspawnlp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
793 {
794   __ms_va_list ap;
795   MSVCRT_wchar_t *args;
796   MSVCRT_intptr_t ret;
797
798   __ms_va_start(ap, arg0);
799   args = msvcrt_valisttos(arg0, ap, ' ');
800   __ms_va_end(ap);
801
802   ret = msvcrt_spawn(flags, name, args, NULL, 1);
803
804   MSVCRT_free(args);
805   return ret;
806 }
807
808 /*********************************************************************
809  *              _spawnlp (MSVCRT.@)
810  *
811  * Like on Windows, this function does not handle arguments with spaces
812  * or double-quotes.
813  */
814 MSVCRT_intptr_t CDECL _spawnlp(int flags, const char* name, const char* arg0, ...)
815 {
816   __ms_va_list ap;
817   MSVCRT_wchar_t *nameW, *args;
818   MSVCRT_intptr_t ret;
819
820   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
821
822   __ms_va_start(ap, arg0);
823   args = msvcrt_valisttos_aw(arg0, ap, ' ');
824   __ms_va_end(ap);
825
826   ret = msvcrt_spawn(flags, nameW, args, NULL, 1);
827
828   MSVCRT_free(nameW);
829   MSVCRT_free(args);
830   return ret;
831 }
832
833 /*********************************************************************
834  *      _wspawnlpe (MSVCRT.@)
835  *
836  * Unicode version of _spawnlpe
837  */
838 MSVCRT_intptr_t CDECL _wspawnlpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
839 {
840   __ms_va_list ap;
841   MSVCRT_wchar_t *args, *envs = NULL;
842   const MSVCRT_wchar_t * const *envp;
843   MSVCRT_intptr_t ret;
844
845   __ms_va_start(ap, arg0);
846   args = msvcrt_valisttos(arg0, ap, ' ');
847   __ms_va_end(ap);
848
849   __ms_va_start(ap, arg0);
850   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
851   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
852   if (envp) envs = msvcrt_argvtos(envp, 0);
853   __ms_va_end(ap);
854
855   ret = msvcrt_spawn(flags, name, args, envs, 1);
856
857   MSVCRT_free(args);
858   MSVCRT_free(envs);
859   return ret;
860 }
861
862 /*********************************************************************
863  *              _spawnlpe (MSVCRT.@)
864  */
865 MSVCRT_intptr_t CDECL _spawnlpe(int flags, const char* name, const char* arg0, ...)
866 {
867   __ms_va_list ap;
868   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
869   const char * const *envp;
870   MSVCRT_intptr_t ret;
871
872   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
873
874   __ms_va_start(ap, arg0);
875   args = msvcrt_valisttos_aw(arg0, ap, ' ');
876   __ms_va_end(ap);
877
878   __ms_va_start(ap, arg0);
879   while (va_arg( ap, char * ) != NULL) /*nothing*/;
880   envp = va_arg( ap, const char * const * );
881   if (envp) envs = msvcrt_argvtos_aw(envp, 0);
882   __ms_va_end(ap);
883
884   ret = msvcrt_spawn(flags, nameW, args, envs, 1);
885
886   MSVCRT_free(nameW);
887   MSVCRT_free(args);
888   MSVCRT_free(envs);
889   return ret;
890 }
891
892 /*********************************************************************
893  *              _spawnve (MSVCRT.@)
894  *
895  * Like on Windows, this function does not handle arguments with spaces
896  * or double-quotes.
897  */
898 MSVCRT_intptr_t CDECL MSVCRT__spawnve(int flags, const char* name, const char* const* argv,
899                                const char* const* envv)
900 {
901   MSVCRT_wchar_t *nameW, *args, *envs;
902   MSVCRT_intptr_t ret;
903
904   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
905
906   args = msvcrt_argvtos_aw(argv, ' ');
907   envs = msvcrt_argvtos_aw(envv, 0);
908
909   ret = msvcrt_spawn(flags, nameW, args, envs, 0);
910
911   MSVCRT_free(nameW);
912   MSVCRT_free(args);
913   MSVCRT_free(envs);
914   return ret;
915 }
916
917 /*********************************************************************
918  *      _wspawnve (MSVCRT.@)
919  *
920  * Unicode version of _spawnve
921  */
922 MSVCRT_intptr_t CDECL MSVCRT__wspawnve(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv,
923                                 const MSVCRT_wchar_t* const* envv)
924 {
925   MSVCRT_wchar_t *args, *envs;
926   MSVCRT_intptr_t ret;
927
928   args = msvcrt_argvtos(argv, ' ');
929   envs = msvcrt_argvtos(envv, 0);
930
931   ret = msvcrt_spawn(flags, name, args, envs, 0);
932
933   MSVCRT_free(args);
934   MSVCRT_free(envs);
935   return ret;
936 }
937
938 /*********************************************************************
939  *              _spawnv (MSVCRT.@)
940  *
941  * Like on Windows, this function does not handle arguments with spaces
942  * or double-quotes.
943  */
944 MSVCRT_intptr_t CDECL _spawnv(int flags, const char* name, const char* const* argv)
945 {
946   return MSVCRT__spawnve(flags, name, argv, NULL);
947 }
948
949 /*********************************************************************
950  *      _wspawnv (MSVCRT.@)
951  *
952  * Unicode version of _spawnv
953  */
954 MSVCRT_intptr_t CDECL _wspawnv(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv)
955 {
956   return MSVCRT__wspawnve(flags, name, argv, NULL);
957 }
958
959 /*********************************************************************
960  *              _spawnvpe (MSVCRT.@)
961  *
962  * Like on Windows, this function does not handle arguments with spaces
963  * or double-quotes.
964  */
965 MSVCRT_intptr_t CDECL MSVCRT__spawnvpe(int flags, const char* name, const char* const* argv,
966                                 const char* const* envv)
967 {
968   MSVCRT_wchar_t *nameW, *args, *envs;
969   MSVCRT_intptr_t ret;
970
971   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
972
973   args = msvcrt_argvtos_aw(argv, ' ');
974   envs = msvcrt_argvtos_aw(envv, 0);
975
976   ret = msvcrt_spawn(flags, nameW, args, envs, 1);
977
978   MSVCRT_free(nameW);
979   MSVCRT_free(args);
980   MSVCRT_free(envs);
981   return ret;
982 }
983
984 /*********************************************************************
985  *      _wspawnvpe (MSVCRT.@)
986  *
987  * Unicode version of _spawnvpe
988  */
989 MSVCRT_intptr_t CDECL MSVCRT__wspawnvpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv,
990                                  const MSVCRT_wchar_t* const* envv)
991 {
992   MSVCRT_wchar_t *args, *envs;
993   MSVCRT_intptr_t ret;
994
995   args = msvcrt_argvtos(argv, ' ');
996   envs = msvcrt_argvtos(envv, 0);
997
998   ret = msvcrt_spawn(flags, name, args, envs, 1);
999
1000   MSVCRT_free(args);
1001   MSVCRT_free(envs);
1002   return ret;
1003 }
1004
1005 /*********************************************************************
1006  *              _spawnvp (MSVCRT.@)
1007  *
1008  * Like on Windows, this function does not handle arguments with spaces
1009  * or double-quotes.
1010  */
1011 MSVCRT_intptr_t CDECL _spawnvp(int flags, const char* name, const char* const* argv)
1012 {
1013   return MSVCRT__spawnvpe(flags, name, argv, NULL);
1014 }
1015
1016 /*********************************************************************
1017  *      _wspawnvp (MSVCRT.@)
1018  *
1019  * Unicode version of _spawnvp
1020  */
1021 MSVCRT_intptr_t CDECL _wspawnvp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv)
1022 {
1023   return MSVCRT__wspawnvpe(flags, name, argv, NULL);
1024 }
1025
1026 static struct popen_handle {
1027     MSVCRT_FILE *f;
1028     HANDLE proc;
1029 } *popen_handles;
1030 static DWORD popen_handles_size;
1031
1032 void msvcrt_free_popen_data(void)
1033 {
1034     MSVCRT_free(popen_handles);
1035 }
1036
1037 /*********************************************************************
1038  *              _wpopen (MSVCRT.@)
1039  *
1040  * Unicode version of _popen
1041  */
1042 MSVCRT_FILE* CDECL MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
1043 {
1044   MSVCRT_FILE *ret;
1045   BOOL readPipe = TRUE;
1046   int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1;
1047   const MSVCRT_wchar_t *p;
1048   MSVCRT_wchar_t *comspec, *fullcmd;
1049   unsigned int len;
1050   static const MSVCRT_wchar_t flag[] = {' ','/','c',' ',0};
1051   struct popen_handle *container;
1052   DWORD i;
1053
1054   TRACE("(command=%s, mode=%s)\n", debugstr_w(command), debugstr_w(mode));
1055
1056   if (!command || !mode)
1057     return NULL;
1058
1059   textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
1060   for (p = mode; *p; p++)
1061   {
1062     switch (*p)
1063     {
1064       case 'W':
1065       case 'w':
1066         readPipe = FALSE;
1067         break;
1068       case 'B':
1069       case 'b':
1070         textmode |= MSVCRT__O_BINARY;
1071         textmode &= ~MSVCRT__O_TEXT;
1072         break;
1073       case 'T':
1074       case 't':
1075         textmode |= MSVCRT__O_TEXT;
1076         textmode &= ~MSVCRT__O_BINARY;
1077         break;
1078     }
1079   }
1080   if (MSVCRT__pipe(fds, 0, textmode) == -1)
1081     return NULL;
1082
1083   fdToDup = readPipe ? 1 : 0;
1084   fdToOpen = readPipe ? 0 : 1;
1085
1086   _mlock(_POPEN_LOCK);
1087   for(i=0; i<popen_handles_size; i++)
1088   {
1089     if (!popen_handles[i].f)
1090       break;
1091   }
1092   if (i==popen_handles_size)
1093   {
1094     i = (popen_handles_size ? popen_handles_size*2 : 8);
1095     container = MSVCRT_realloc(popen_handles, i*sizeof(*container));
1096     if (!container) goto error;
1097
1098     popen_handles = container;
1099     container = popen_handles+popen_handles_size;
1100     memset(container, 0, (i-popen_handles_size)*sizeof(*container));
1101     popen_handles_size = i;
1102   }
1103   else container = popen_handles+i;
1104
1105   if ((fdStdHandle = MSVCRT__dup(fdToDup)) == -1)
1106     goto error;
1107   if (MSVCRT__dup2(fds[fdToDup], fdToDup) != 0)
1108     goto error;
1109
1110   MSVCRT__close(fds[fdToDup]);
1111
1112   if (!(comspec = msvcrt_get_comspec())) goto error;
1113   len = strlenW(comspec) + strlenW(flag) + strlenW(command) + 1;
1114
1115   if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t))))
1116   {
1117     HeapFree(GetProcessHeap(), 0, comspec);
1118     goto error;
1119   }
1120
1121   strcpyW(fullcmd, comspec);
1122   strcatW(fullcmd, flag);
1123   strcatW(fullcmd, command);
1124
1125   if ((container->proc = (HANDLE)msvcrt_spawn(MSVCRT__P_NOWAIT, comspec, fullcmd, NULL, 1))
1126           == INVALID_HANDLE_VALUE)
1127   {
1128     MSVCRT__close(fds[fdToOpen]);
1129     ret = NULL;
1130   }
1131   else
1132   {
1133     ret = MSVCRT__wfdopen(fds[fdToOpen], mode);
1134     if (!ret)
1135       MSVCRT__close(fds[fdToOpen]);
1136     container->f = ret;
1137   }
1138   _munlock(_POPEN_LOCK);
1139   HeapFree(GetProcessHeap(), 0, comspec);
1140   HeapFree(GetProcessHeap(), 0, fullcmd);
1141   MSVCRT__dup2(fdStdHandle, fdToDup);
1142   MSVCRT__close(fdStdHandle);
1143   return ret;
1144
1145 error:
1146   _munlock(_POPEN_LOCK);
1147   if (fdStdHandle != -1) MSVCRT__close(fdStdHandle);
1148   MSVCRT__close(fds[0]);
1149   MSVCRT__close(fds[1]);
1150   return NULL;
1151 }
1152
1153 /*********************************************************************
1154  *      _popen (MSVCRT.@)
1155  */
1156 MSVCRT_FILE* CDECL MSVCRT__popen(const char* command, const char* mode)
1157 {
1158   MSVCRT_FILE *ret;
1159   MSVCRT_wchar_t *cmdW, *modeW;
1160
1161   TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
1162
1163   if (!command || !mode)
1164     return NULL;
1165
1166   if (!(cmdW = msvcrt_wstrdupa(command))) return NULL;
1167   if (!(modeW = msvcrt_wstrdupa(mode)))
1168   {
1169     HeapFree(GetProcessHeap(), 0, cmdW);
1170     return NULL;
1171   }
1172
1173   ret = MSVCRT__wpopen(cmdW, modeW);
1174
1175   HeapFree(GetProcessHeap(), 0, cmdW);
1176   HeapFree(GetProcessHeap(), 0, modeW);
1177   return ret;
1178 }
1179
1180 /*********************************************************************
1181  *              _pclose (MSVCRT.@)
1182  */
1183 int CDECL MSVCRT__pclose(MSVCRT_FILE* file)
1184 {
1185   HANDLE h;
1186   DWORD i;
1187
1188   if (!MSVCRT_CHECK_PMT(file != NULL)) return -1;
1189
1190   _mlock(_POPEN_LOCK);
1191   for(i=0; i<popen_handles_size; i++)
1192   {
1193     if (popen_handles[i].f == file)
1194       break;
1195   }
1196   if(i == popen_handles_size)
1197   {
1198     _munlock(_POPEN_LOCK);
1199     *MSVCRT__errno() = MSVCRT_EBADF;
1200     return -1;
1201   }
1202
1203   h = popen_handles[i].proc;
1204   popen_handles[i].f = NULL;
1205   _munlock(_POPEN_LOCK);
1206
1207   MSVCRT_fclose(file);
1208   if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i))
1209   {
1210     msvcrt_set_errno(GetLastError());
1211     CloseHandle(h);
1212     return -1;
1213   }
1214
1215   CloseHandle(h);
1216   return i;
1217 }
1218
1219 /*********************************************************************
1220  *      _wsystem (MSVCRT.@)
1221  *
1222  * Unicode version of system
1223  */
1224 int CDECL _wsystem(const MSVCRT_wchar_t* cmd)
1225 {
1226   int res;
1227   MSVCRT_wchar_t *comspec, *fullcmd;
1228   unsigned int len;
1229   static const MSVCRT_wchar_t flag[] = {' ','/','c',' ',0};
1230
1231   comspec = msvcrt_get_comspec();
1232
1233   if (cmd == NULL)
1234   {
1235     if (comspec == NULL)
1236     {
1237         *MSVCRT__errno() = MSVCRT_ENOENT;
1238         return 0;
1239     }
1240     HeapFree(GetProcessHeap(), 0, comspec);
1241     return 1;
1242   }
1243
1244   if ( comspec == NULL)
1245     return -1;
1246
1247   len = strlenW(comspec) + strlenW(flag) + strlenW(cmd) + 1;
1248
1249   if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t))))
1250   {
1251     HeapFree(GetProcessHeap(), 0, comspec);
1252     return -1;
1253   }
1254   strcpyW(fullcmd, comspec);
1255   strcatW(fullcmd, flag);
1256   strcatW(fullcmd, cmd);
1257
1258   res = msvcrt_spawn(MSVCRT__P_WAIT, comspec, fullcmd, NULL, 1);
1259
1260   HeapFree(GetProcessHeap(), 0, comspec);
1261   HeapFree(GetProcessHeap(), 0, fullcmd);
1262   return res;
1263 }
1264
1265 /*********************************************************************
1266  *              system (MSVCRT.@)
1267  */
1268 int CDECL MSVCRT_system(const char* cmd)
1269 {
1270   int res = -1;
1271   MSVCRT_wchar_t *cmdW;
1272
1273   if (cmd == NULL)
1274     return _wsystem(NULL);
1275
1276   if ((cmdW = msvcrt_wstrdupa(cmd)))
1277   {
1278     res = _wsystem(cmdW);
1279     HeapFree(GetProcessHeap(), 0, cmdW);
1280   }
1281   return res;
1282 }
1283
1284 /*********************************************************************
1285  *              _loaddll (MSVCRT.@)
1286  */
1287 MSVCRT_intptr_t CDECL _loaddll(const char* dllname)
1288 {
1289   return (MSVCRT_intptr_t)LoadLibraryA(dllname);
1290 }
1291
1292 /*********************************************************************
1293  *              _unloaddll (MSVCRT.@)
1294  */
1295 int CDECL _unloaddll(MSVCRT_intptr_t dll)
1296 {
1297   if (FreeLibrary((HMODULE)dll))
1298     return 0;
1299   else
1300   {
1301     int err = GetLastError();
1302     msvcrt_set_errno(err);
1303     return err;
1304   }
1305 }
1306
1307 /*********************************************************************
1308  *              _getdllprocaddr (MSVCRT.@)
1309  */
1310 void * CDECL _getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal)
1311 {
1312     if (name)
1313     {
1314         if (ordinal != -1) return NULL;
1315         return GetProcAddress( (HMODULE)dll, name );
1316     }
1317     if (HIWORD(ordinal)) return NULL;
1318     return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
1319 }