msvcrt: Return a per-thread buffer in localtime and gmtime.
[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  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * FIXME:
24  * -File handles need some special handling. Sometimes children get
25  *  open file handles, sometimes not. The docs are confusing
26  * -No check for maximum path/argument/environment size is done
27  */
28 #include "config.h"
29
30 #include <stdarg.h>
31
32 #include "msvcrt.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36
37 /* INTERNAL: Spawn a child process */
38 static MSVCRT_intptr_t msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
39 {
40   STARTUPINFOA si;
41   PROCESS_INFORMATION pi;
42
43   if ((unsigned)flags > MSVCRT__P_DETACH)
44   {
45     *MSVCRT__errno() = MSVCRT_EINVAL;
46     return -1;
47   }
48
49   memset(&si, 0, sizeof(si));
50   si.cb = sizeof(si);
51   msvcrt_create_io_inherit_block(&si);
52   if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
53                      flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
54                      env, NULL, &si, &pi))
55   {
56     msvcrt_set_errno(GetLastError());
57     MSVCRT_free(si.lpReserved2);
58     return -1;
59   }
60
61   MSVCRT_free(si.lpReserved2);
62   switch(flags)
63   {
64   case MSVCRT__P_WAIT:
65     WaitForSingleObject(pi.hProcess, INFINITE);
66     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
67     CloseHandle(pi.hProcess);
68     CloseHandle(pi.hThread);
69     return pi.dwProcessId;
70   case MSVCRT__P_DETACH:
71     CloseHandle(pi.hProcess);
72     pi.hProcess = 0;
73     /* fall through */
74   case MSVCRT__P_NOWAIT:
75   case MSVCRT__P_NOWAITO:
76     CloseHandle(pi.hThread);
77     return (MSVCRT_intptr_t)pi.hProcess;
78   case  MSVCRT__P_OVERLAY:
79     MSVCRT__exit(0);
80   }
81   return -1; /* can't reach here */
82 }
83
84 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
85  * extra '\0' to terminate it
86  */
87 static char* msvcrt_argvtos(const char* const* arg, char delim)
88 {
89   const char* const* a;
90   long size;
91   char* p;
92   char* ret;
93
94   if (!arg && !delim)
95   {
96       /* Return NULL for an empty environment list */
97       return NULL;
98   }
99
100   /* get length */
101   a = arg;
102   size = 0;
103   while (*a)
104   {
105     size += strlen(*a) + 1;
106     a++;
107   }
108
109   ret = (char*)MSVCRT_malloc(size + 1);
110   if (!ret)
111     return NULL;
112
113   /* fill string */
114   a = arg;
115   p = ret;
116   while (*a)
117   {
118     int len = strlen(*a);
119     memcpy(p,*a,len);
120     p += len;
121     *p++ = delim;
122     a++;
123   }
124   if (delim && p > ret) p[-1] = 0;
125   else *p = 0;
126   return ret;
127 }
128
129 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
130  * extra '\0' to terminate it
131  */
132 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
133 {
134   va_list alist2;
135   long size;
136   const char *arg;
137   char* p;
138   char *ret;
139
140 #ifdef HAVE_VA_COPY
141   va_copy(alist2,alist);
142 #else
143 # ifdef HAVE___VA_COPY
144   __va_copy(alist2,alist);
145 # else
146   alist2 = alist;
147 # endif
148 #endif
149
150   if (!arg0 && !delim)
151   {
152       /* Return NULL for an empty environment list */
153       return NULL;
154   }
155
156   /* get length */
157   arg = arg0;
158   size = 0;
159   do {
160       size += strlen(arg) + 1;
161       arg = va_arg(alist, char*);
162   } while (arg != NULL);
163
164   ret = (char*)MSVCRT_malloc(size + 1);
165   if (!ret)
166     return NULL;
167
168   /* fill string */
169   arg = arg0;
170   p = ret;
171   do {
172       int len = strlen(arg);
173       memcpy(p,arg,len);
174       p += len;
175       *p++ = delim;
176       arg = va_arg(alist2, char*);
177   } while (arg != NULL);
178   if (delim && p > ret) p[-1] = 0;
179   else *p = 0;
180   return ret;
181 }
182
183 /*********************************************************************
184  *              _cwait (MSVCRT.@)
185  */
186 MSVCRT_intptr_t _cwait(int *status, MSVCRT_intptr_t pid, int action)
187 {
188   HANDLE hPid = (HANDLE)pid;
189   int doserrno;
190
191   action = action; /* Remove warning */
192
193   if (!WaitForSingleObject(hPid, INFINITE))
194   {
195     if (status)
196     {
197       DWORD stat;
198       GetExitCodeProcess(hPid, &stat);
199       *status = (int)stat;
200     }
201     return pid;
202   }
203   doserrno = GetLastError();
204
205   if (doserrno == ERROR_INVALID_HANDLE)
206   {
207     *MSVCRT__errno() =  MSVCRT_ECHILD;
208     *MSVCRT___doserrno() = doserrno;
209   }
210   else
211     msvcrt_set_errno(doserrno);
212
213   return status ? *status = -1 : -1;
214 }
215
216 /*********************************************************************
217  *              _execl (MSVCRT.@)
218  *
219  * Like on Windows, this function does not handle arguments with spaces
220  * or double-quotes.
221  */
222 MSVCRT_intptr_t _execl(const char* name, const char* arg0, ...)
223 {
224   va_list ap;
225   char * args;
226   MSVCRT_intptr_t ret;
227
228   va_start(ap, arg0);
229   args = msvcrt_valisttos(arg0, ap, ' ');
230   va_end(ap);
231
232   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
233   MSVCRT_free(args);
234
235   return ret;
236 }
237
238 /*********************************************************************
239  *              _execle (MSVCRT.@)
240  */
241 MSVCRT_intptr_t _execle(const char* name, const char* arg0, ...)
242 {
243     FIXME("stub\n");
244     return -1;
245 }
246
247 /*********************************************************************
248  *              _execlp (MSVCRT.@)
249  *
250  * Like on Windows, this function does not handle arguments with spaces
251  * or double-quotes.
252  */
253 MSVCRT_intptr_t _execlp(const char* name, const char* arg0, ...)
254 {
255   va_list ap;
256   char * args;
257   MSVCRT_intptr_t ret;
258   char fullname[MAX_PATH];
259
260   _searchenv(name, "PATH", fullname);
261
262   va_start(ap, arg0);
263   args = msvcrt_valisttos(arg0, ap, ' ');
264   va_end(ap);
265
266   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
267   MSVCRT_free(args);
268
269   return ret;
270 }
271
272 /*********************************************************************
273  *              _execlpe (MSVCRT.@)
274  */
275 MSVCRT_intptr_t _execlpe(const char* name, const char* arg0, ...)
276 {
277     FIXME("stub\n");
278     return -1;
279 }
280
281 /*********************************************************************
282  *              _execv (MSVCRT.@)
283  *
284  * Like on Windows, this function does not handle arguments with spaces
285  * or double-quotes.
286  */
287 MSVCRT_intptr_t _execv(const char* name, char* const* argv)
288 {
289   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
290 }
291
292 /*********************************************************************
293  *              _execve (MSVCRT.@)
294  *
295  * Like on Windows, this function does not handle arguments with spaces
296  * or double-quotes.
297  */
298 MSVCRT_intptr_t _execve(const char* name, char* const* argv, const char* const* envv)
299 {
300   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
301 }
302
303 /*********************************************************************
304  *              _execvpe (MSVCRT.@)
305  *
306  * Like on Windows, this function does not handle arguments with spaces
307  * or double-quotes.
308  */
309 MSVCRT_intptr_t _execvpe(const char* name, char* const* argv, const char* const* envv)
310 {
311   char fullname[MAX_PATH];
312
313   _searchenv(name, "PATH", fullname);
314   return _spawnve(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name,
315                   (const char* const*) argv, envv);
316 }
317
318 /*********************************************************************
319  *              _execvp (MSVCRT.@)
320  *
321  * Like on Windows, this function does not handle arguments with spaces
322  * or double-quotes.
323  */
324 MSVCRT_intptr_t _execvp(const char* name, char* const* argv)
325 {
326   return _execvpe(name, argv, NULL);
327 }
328
329 /*********************************************************************
330  *              _spawnl (MSVCRT.@)
331  *
332  * Like on Windows, this function does not handle arguments with spaces
333  * or double-quotes.
334  */
335 MSVCRT_intptr_t _spawnl(int flags, const char* name, const char* arg0, ...)
336 {
337   va_list ap;
338   char * args;
339   MSVCRT_intptr_t ret;
340
341   va_start(ap, arg0);
342   args = msvcrt_valisttos(arg0, ap, ' ');
343   va_end(ap);
344
345   ret = msvcrt_spawn(flags, name, args, NULL);
346   MSVCRT_free(args);
347
348   return ret;
349 }
350
351 /*********************************************************************
352  *              _spawnle (MSVCRT.@)
353  */
354 MSVCRT_intptr_t _spawnle(int flags, const char* name, const char* arg0, ...)
355 {
356     va_list ap;
357     char *args, *envs = NULL;
358     const char * const *envp;
359     MSVCRT_intptr_t ret;
360
361     va_start(ap, arg0);
362     args = msvcrt_valisttos(arg0, ap, ' ');
363     va_end(ap);
364
365     va_start(ap, arg0);
366     while (va_arg( ap, char * ) != NULL) /*nothing*/;
367     envp = va_arg( ap, const char * const * );
368     if (envp) envs = msvcrt_argvtos(envp, 0);
369     va_end(ap);
370
371     ret = msvcrt_spawn(flags, name, args, envs);
372
373     MSVCRT_free(args);
374     if (envs) MSVCRT_free(envs);
375     return ret;
376 }
377
378
379 /*********************************************************************
380  *              _spawnlp (MSVCRT.@)
381  *
382  * Like on Windows, this function does not handle arguments with spaces
383  * or double-quotes.
384  */
385 MSVCRT_intptr_t _spawnlp(int flags, const char* name, const char* arg0, ...)
386 {
387   va_list ap;
388   char * args;
389   MSVCRT_intptr_t ret;
390   char fullname[MAX_PATH];
391
392   _searchenv(name, "PATH", fullname);
393
394   va_start(ap, arg0);
395   args = msvcrt_valisttos(arg0, ap, ' ');
396   va_end(ap);
397
398   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
399   MSVCRT_free(args);
400
401   return ret;
402 }
403
404 /*********************************************************************
405  *              _spawnlpe (MSVCRT.@)
406  */
407 MSVCRT_intptr_t _spawnlpe(int flags, const char* name, const char* arg0, ...)
408 {
409     va_list ap;
410     char *args, *envs = NULL;
411     const char * const *envp;
412     MSVCRT_intptr_t ret;
413     char fullname[MAX_PATH];
414
415     _searchenv(name, "PATH", fullname);
416
417     va_start(ap, arg0);
418     args = msvcrt_valisttos(arg0, ap, ' ');
419     va_end(ap);
420
421     va_start(ap, arg0);
422     while (va_arg( ap, char * ) != NULL) /*nothing*/;
423     envp = va_arg( ap, const char * const * );
424     if (envp) envs = msvcrt_argvtos(envp, 0);
425     va_end(ap);
426
427     ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, envs);
428
429     MSVCRT_free(args);
430     if (envs) MSVCRT_free(envs);
431     return ret;
432 }
433
434 /*********************************************************************
435  *              _spawnve (MSVCRT.@)
436  *
437  * Like on Windows, this function does not handle arguments with spaces
438  * or double-quotes.
439  */
440 MSVCRT_intptr_t _spawnve(int flags, const char* name, const char* const* argv,
441                             const char* const* envv)
442 {
443   char * args = msvcrt_argvtos(argv,' ');
444   char * envs = msvcrt_argvtos(envv,0);
445   const char *fullname = name;
446   MSVCRT_intptr_t ret = -1;
447
448   FIXME(":not translating name %s to locate program\n",fullname);
449   TRACE(":call (%s), params (%s), env (%s)\n",debugstr_a(name),debugstr_a(args),
450    envs?"Custom":"Null");
451
452   if (args)
453   {
454     ret = msvcrt_spawn(flags, fullname, args, envs);
455     MSVCRT_free(args);
456   }
457   if (envs)
458     MSVCRT_free(envs);
459
460   return ret;
461 }
462
463 /*********************************************************************
464  *              _spawnv (MSVCRT.@)
465  *
466  * Like on Windows, this function does not handle arguments with spaces
467  * or double-quotes.
468  */
469 MSVCRT_intptr_t _spawnv(int flags, const char* name, const char* const* argv)
470 {
471   return _spawnve(flags, name, argv, NULL);
472 }
473
474 /*********************************************************************
475  *              _spawnvpe (MSVCRT.@)
476  *
477  * Like on Windows, this function does not handle arguments with spaces
478  * or double-quotes.
479  */
480 MSVCRT_intptr_t _spawnvpe(int flags, const char* name, const char* const* argv,
481                             const char* const* envv)
482 {
483   char fullname[MAX_PATH];
484   _searchenv(name, "PATH", fullname);
485   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
486 }
487
488 /*********************************************************************
489  *              _spawnvp (MSVCRT.@)
490  *
491  * Like on Windows, this function does not handle arguments with spaces
492  * or double-quotes.
493  */
494 MSVCRT_intptr_t _spawnvp(int flags, const char* name, const char* const* argv)
495 {
496   return _spawnvpe(flags, name, argv, NULL);
497 }
498
499 /*********************************************************************
500  *              _popen (MSVCRT.@)
501  * FIXME: convert to _wpopen and call that from here instead?  But it
502  * would have to convert the command back to ANSI to call msvcrt_spawn,
503  * less than ideal.
504  */
505 MSVCRT_FILE* MSVCRT__popen(const char* command, const char* mode)
506 {
507   static const char wcmd[] = "wcmd", cmdFlag[] = " /C ", comSpec[] = "COMSPEC";
508   MSVCRT_FILE *ret;
509   BOOL readPipe = TRUE;
510   int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1, fdStdErr = -1;
511   const char *p;
512   char *cmdcopy;
513   DWORD comSpecLen;
514
515   TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
516
517   if (!command || !mode)
518     return NULL;
519
520   textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
521   for (p = mode; *p; p++)
522   {
523     switch (*p)
524     {
525       case 'W':
526       case 'w':
527         readPipe = FALSE;
528         break;
529       case 'B':
530       case 'b':
531         textmode |= MSVCRT__O_BINARY;
532         textmode &= ~MSVCRT__O_TEXT;
533         break;
534       case 'T':
535       case 't':
536         textmode |= MSVCRT__O_TEXT;
537         textmode &= ~MSVCRT__O_BINARY;
538         break;
539     }
540   }
541   if (_pipe(fds, 0, textmode) == -1)
542     return NULL;
543
544   fdToDup = readPipe ? 1 : 0;
545   fdToOpen = readPipe ? 0 : 1;
546
547   if ((fdStdHandle = _dup(fdToDup)) == -1)
548     goto error;
549   if (_dup2(fds[fdToDup], fdToDup) != 0)
550     goto error;
551   if (readPipe)
552   {
553     if ((fdStdErr = _dup(MSVCRT_STDERR_FILENO)) == -1)
554       goto error;
555     if (_dup2(fds[fdToDup], MSVCRT_STDERR_FILENO) != 0)
556       goto error;
557   }
558
559   _close(fds[fdToDup]);
560
561   comSpecLen = GetEnvironmentVariableA(comSpec, NULL, 0);
562   if (!comSpecLen)
563     comSpecLen = strlen(wcmd) + 1;
564   cmdcopy = HeapAlloc(GetProcessHeap(), 0, comSpecLen + strlen(cmdFlag)
565    + strlen(command));
566   if (!GetEnvironmentVariableA(comSpec, cmdcopy, comSpecLen))
567     strcpy(cmdcopy, wcmd);
568   strcat(cmdcopy, cmdFlag);
569   strcat(cmdcopy, command);
570   if (msvcrt_spawn(MSVCRT__P_NOWAIT, NULL, cmdcopy, NULL) == -1)
571   {
572     _close(fds[fdToOpen]);
573     ret = NULL;
574   }
575   else
576   {
577     ret = MSVCRT__fdopen(fds[fdToOpen], mode);
578     if (!ret)
579       _close(fds[fdToOpen]);
580   }
581   HeapFree(GetProcessHeap(), 0, cmdcopy);
582   _dup2(fdStdHandle, fdToDup);
583   _close(fdStdHandle);
584   if (readPipe)
585   {
586     _dup2(fdStdErr, MSVCRT_STDERR_FILENO);
587     _close(fdStdErr);
588   }
589   return ret;
590
591 error:
592   if (fdStdHandle != -1) _close(fdStdHandle);
593   if (fdStdErr != -1)    _close(fdStdErr);
594   _close(fds[0]);
595   _close(fds[1]);
596   return NULL;
597 }
598
599 /*********************************************************************
600  *              _wpopen (MSVCRT.@)
601  */
602 MSVCRT_FILE* MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
603 {
604   FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
605   return NULL;
606 }
607
608 /*********************************************************************
609  *              _pclose (MSVCRT.@)
610  */
611 int MSVCRT__pclose(MSVCRT_FILE* file)
612 {
613   return MSVCRT_fclose(file);
614 }
615
616 /*********************************************************************
617  *              system (MSVCRT.@)
618  */
619 int MSVCRT_system(const char* cmd)
620 {
621     char* cmdcopy;
622     int res;
623
624     /* Make a writable copy for CreateProcess */
625     cmdcopy=_strdup(cmd);
626     /* FIXME: should probably launch cmd interpreter in COMSPEC */
627     res=msvcrt_spawn(MSVCRT__P_WAIT, NULL, cmdcopy, NULL);
628     MSVCRT_free(cmdcopy);
629     return res;
630 }
631
632 /*********************************************************************
633  *              _loaddll (MSVCRT.@)
634  */
635 MSVCRT_intptr_t _loaddll(const char* dllname)
636 {
637   return (MSVCRT_intptr_t)LoadLibraryA(dllname);
638 }
639
640 /*********************************************************************
641  *              _unloaddll (MSVCRT.@)
642  */
643 int _unloaddll(MSVCRT_intptr_t dll)
644 {
645   if (FreeLibrary((HMODULE)dll))
646     return 0;
647   else
648   {
649     int err = GetLastError();
650     msvcrt_set_errno(err);
651     return err;
652   }
653 }
654
655 /*********************************************************************
656  *              _getdllprocaddr (MSVCRT.@)
657  */
658 void *_getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal)
659 {
660     if (name)
661     {
662         if (ordinal != -1) return NULL;
663         return GetProcAddress( (HMODULE)dll, name );
664     }
665     if (HIWORD(ordinal)) return NULL;
666     return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
667 }