Correctly use the returned value from GetTimeZoneInformation.
[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 int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
39 {
40   STARTUPINFOA si;
41   PROCESS_INFORMATION pi;
42
43   if (sizeof(HANDLE) != sizeof(int))
44     WARN("This call is unsuitable for your architecture\n");
45
46   if ((unsigned)flags > MSVCRT__P_DETACH)
47   {
48     *MSVCRT__errno() = MSVCRT_EINVAL;
49     return -1;
50   }
51
52   memset(&si, 0, sizeof(si));
53   si.cb = sizeof(si);
54   msvcrt_create_io_inherit_block(&si);
55   if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
56                      flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
57                      env, NULL, &si, &pi))
58   {
59     msvcrt_set_errno(GetLastError());
60     MSVCRT_free(&si.lpReserved2);
61     return -1;
62   }
63
64   MSVCRT_free(&si.lpReserved2);
65   switch(flags)
66   {
67   case MSVCRT__P_WAIT:
68     WaitForSingleObject(pi.hProcess, INFINITE);
69     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
70     CloseHandle(pi.hProcess);
71     CloseHandle(pi.hThread);
72     return (int)pi.dwProcessId;
73   case MSVCRT__P_DETACH:
74     CloseHandle(pi.hProcess);
75     pi.hProcess = 0;
76     /* fall through */
77   case MSVCRT__P_NOWAIT:
78   case MSVCRT__P_NOWAITO:
79     CloseHandle(pi.hThread);
80     return (int)pi.hProcess;
81   case  MSVCRT__P_OVERLAY:
82     MSVCRT__exit(0);
83   }
84   return -1; /* can't reach here */
85 }
86
87 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
88  * extra '\0' to terminate it
89  */
90 static char* msvcrt_argvtos(const char* const* arg, char delim)
91 {
92   const char* const* a;
93   long size;
94   char* p;
95   char* ret;
96
97   if (!arg && !delim)
98   {
99       /* Return NULL for an empty environment list */
100       return NULL;
101   }
102
103   /* get length */
104   a = arg;
105   size = 0;
106   while (*a)
107   {
108     size += strlen(*a) + 1;
109     a++;
110   }
111
112   ret = (char*)MSVCRT_malloc(size + 1);
113   if (!ret)
114     return NULL;
115
116   /* fill string */
117   a = arg;
118   p = ret;
119   while (*a)
120   {
121     int len = strlen(*a);
122     memcpy(p,*a,len);
123     p += len;
124     *p++ = delim;
125     a++;
126   }
127   if (delim && p > ret) p[-1] = 0;
128   else *p = 0;
129   return ret;
130 }
131
132 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
133  * extra '\0' to terminate it
134  */
135 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
136 {
137   va_list alist2;
138   long size;
139   const char *arg;
140   char* p;
141   char *ret;
142
143 #ifdef HAVE_VA_COPY
144   va_copy(alist2,alist);
145 #else
146 # ifdef HAVE___VA_COPY
147   __va_copy(alist2,alist);
148 # else
149   alist2 = alist;
150 # endif
151 #endif
152
153   if (!arg0 && !delim)
154   {
155       /* Return NULL for an empty environment list */
156       return NULL;
157   }
158
159   /* get length */
160   arg = arg0;
161   size = 0;
162   do {
163       size += strlen(arg) + 1;
164       arg = va_arg(alist, char*);
165   } while (arg != NULL);
166
167   ret = (char*)MSVCRT_malloc(size + 1);
168   if (!ret)
169     return NULL;
170
171   /* fill string */
172   arg = arg0;
173   p = ret;
174   do {
175       int len = strlen(arg);
176       memcpy(p,arg,len);
177       p += len;
178       *p++ = delim;
179       arg = va_arg(alist2, char*);
180   } while (arg != NULL);
181   if (delim && p > ret) p[-1] = 0;
182   else *p = 0;
183   return ret;
184 }
185
186 /*********************************************************************
187  *              _cwait (MSVCRT.@)
188  */
189 int _cwait(int *status, int pid, int action)
190 {
191   HANDLE hPid = (HANDLE)pid;
192   int doserrno;
193
194   action = action; /* Remove warning */
195
196   if (!WaitForSingleObject(hPid, INFINITE))
197   {
198     if (status)
199     {
200       DWORD stat;
201       GetExitCodeProcess(hPid, &stat);
202       *status = (int)stat;
203     }
204     return (int)pid;
205   }
206   doserrno = GetLastError();
207
208   if (doserrno == ERROR_INVALID_HANDLE)
209   {
210     *MSVCRT__errno() =  MSVCRT_ECHILD;
211     *MSVCRT___doserrno() = doserrno;
212   }
213   else
214     msvcrt_set_errno(doserrno);
215
216   return status ? *status = -1 : -1;
217 }
218
219 /*********************************************************************
220  *              _execl (MSVCRT.@)
221  *
222  * Like on Windows, this function does not handle arguments with spaces
223  * or double-quotes.
224  */
225 int _execl(const char* name, const char* arg0, ...)
226 {
227   va_list ap;
228   char * args;
229   int ret;
230
231   va_start(ap, arg0);
232   args = msvcrt_valisttos(arg0, ap, ' ');
233   va_end(ap);
234
235   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
236   MSVCRT_free(args);
237
238   return ret;
239 }
240
241 /*********************************************************************
242  *              _execle (MSVCRT.@)
243  */
244 int _execle(const char* name, const char* arg0, ...)
245 {
246     FIXME("stub\n");
247     return -1;
248 }
249
250 /*********************************************************************
251  *              _execlp (MSVCRT.@)
252  *
253  * Like on Windows, this function does not handle arguments with spaces
254  * or double-quotes.
255  */
256 int _execlp(const char* name, const char* arg0, ...)
257 {
258   va_list ap;
259   char * args;
260   int ret;
261   char fullname[MAX_PATH];
262
263   _searchenv(name, "PATH", fullname);
264
265   va_start(ap, arg0);
266   args = msvcrt_valisttos(arg0, ap, ' ');
267   va_end(ap);
268
269   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
270   MSVCRT_free(args);
271
272   return ret;
273 }
274
275 /*********************************************************************
276  *              _execlpe (MSVCRT.@)
277  */
278 int _execlpe(const char* name, const char* arg0, ...)
279 {
280     FIXME("stub\n");
281     return -1;
282 }
283
284 /*********************************************************************
285  *              _execv (MSVCRT.@)
286  *
287  * Like on Windows, this function does not handle arguments with spaces
288  * or double-quotes.
289  */
290 int _execv(const char* name, char* const* argv)
291 {
292   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
293 }
294
295 /*********************************************************************
296  *              _execve (MSVCRT.@)
297  *
298  * Like on Windows, this function does not handle arguments with spaces
299  * or double-quotes.
300  */
301 int _execve(const char* name, char* const* argv, const char* const* envv)
302 {
303   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
304 }
305
306 /*********************************************************************
307  *              _execvpe (MSVCRT.@)
308  *
309  * Like on Windows, this function does not handle arguments with spaces
310  * or double-quotes.
311  */
312 int _execvpe(const char* name, char* const* argv, const char* const* envv)
313 {
314   char fullname[MAX_PATH];
315
316   _searchenv(name, "PATH", fullname);
317   return _spawnve(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name,
318                   (const char* const*) argv, envv);
319 }
320
321 /*********************************************************************
322  *              _execvp (MSVCRT.@)
323  *
324  * Like on Windows, this function does not handle arguments with spaces
325  * or double-quotes.
326  */
327 int _execvp(const char* name, char* const* argv)
328 {
329   return _execvpe(name, argv, NULL);
330 }
331
332 /*********************************************************************
333  *              _spawnl (MSVCRT.@)
334  *
335  * Like on Windows, this function does not handle arguments with spaces
336  * or double-quotes.
337  */
338 int _spawnl(int flags, const char* name, const char* arg0, ...)
339 {
340   va_list ap;
341   char * args;
342   int ret;
343
344   va_start(ap, arg0);
345   args = msvcrt_valisttos(arg0, ap, ' ');
346   va_end(ap);
347
348   ret = msvcrt_spawn(flags, name, args, NULL);
349   MSVCRT_free(args);
350
351   return ret;
352 }
353
354 /*********************************************************************
355  *              _spawnle (MSVCRT.@)
356  */
357 int _spawnle(int flags, const char* name, const char* arg0, ...)
358 {
359     va_list ap;
360     char *args, *envs = NULL;
361     const char * const *envp;
362     int ret;
363
364     va_start(ap, arg0);
365     args = msvcrt_valisttos(arg0, ap, ' ');
366     va_end(ap);
367
368     va_start(ap, arg0);
369     while (va_arg( ap, char * ) != NULL) /*nothing*/;
370     envp = va_arg( ap, const char * const * );
371     if (envp) envs = msvcrt_argvtos(envp, 0);
372     va_end(ap);
373
374     ret = msvcrt_spawn(flags, name, args, envs);
375
376     MSVCRT_free(args);
377     if (envs) MSVCRT_free(envs);
378     return ret;
379 }
380
381
382 /*********************************************************************
383  *              _spawnlp (MSVCRT.@)
384  *
385  * Like on Windows, this function does not handle arguments with spaces
386  * or double-quotes.
387  */
388 int _spawnlp(int flags, const char* name, const char* arg0, ...)
389 {
390   va_list ap;
391   char * args;
392   int ret;
393   char fullname[MAX_PATH];
394
395   _searchenv(name, "PATH", fullname);
396
397   va_start(ap, arg0);
398   args = msvcrt_valisttos(arg0, ap, ' ');
399   va_end(ap);
400
401   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
402   MSVCRT_free(args);
403
404   return ret;
405 }
406
407 /*********************************************************************
408  *              _spawnlpe (MSVCRT.@)
409  */
410 int _spawnlpe(int flags, const char* name, const char* arg0, ...)
411 {
412     va_list ap;
413     char *args, *envs = NULL;
414     const char * const *envp;
415     int ret;
416     char fullname[MAX_PATH];
417
418     _searchenv(name, "PATH", fullname);
419
420     va_start(ap, arg0);
421     args = msvcrt_valisttos(arg0, ap, ' ');
422     va_end(ap);
423
424     va_start(ap, arg0);
425     while (va_arg( ap, char * ) != NULL) /*nothing*/;
426     envp = va_arg( ap, const char * const * );
427     if (envp) envs = msvcrt_argvtos(envp, 0);
428     va_end(ap);
429
430     ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, envs);
431
432     MSVCRT_free(args);
433     if (envs) MSVCRT_free(envs);
434     return ret;
435 }
436
437 /*********************************************************************
438  *              _spawnve (MSVCRT.@)
439  *
440  * Like on Windows, this function does not handle arguments with spaces
441  * or double-quotes.
442  */
443 int _spawnve(int flags, const char* name, const char* const* argv,
444                             const char* const* envv)
445 {
446   char * args = msvcrt_argvtos(argv,' ');
447   char * envs = msvcrt_argvtos(envv,0);
448   const char *fullname = name;
449   int ret = -1;
450
451   FIXME(":not translating name %s to locate program\n",fullname);
452   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
453
454   if (args)
455   {
456     ret = msvcrt_spawn(flags, fullname, args, envs);
457     MSVCRT_free(args);
458   }
459   if (envs)
460     MSVCRT_free(envs);
461
462   return ret;
463 }
464
465 /*********************************************************************
466  *              _spawnv (MSVCRT.@)
467  *
468  * Like on Windows, this function does not handle arguments with spaces
469  * or double-quotes.
470  */
471 int _spawnv(int flags, const char* name, const char* const* argv)
472 {
473   return _spawnve(flags, name, argv, NULL);
474 }
475
476 /*********************************************************************
477  *              _spawnvpe (MSVCRT.@)
478  *
479  * Like on Windows, this function does not handle arguments with spaces
480  * or double-quotes.
481  */
482 int _spawnvpe(int flags, const char* name, const char* const* argv,
483                             const char* const* envv)
484 {
485   char fullname[MAX_PATH];
486   _searchenv(name, "PATH", fullname);
487   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
488 }
489
490 /*********************************************************************
491  *              _spawnvp (MSVCRT.@)
492  *
493  * Like on Windows, this function does not handle arguments with spaces
494  * or double-quotes.
495  */
496 int _spawnvp(int flags, const char* name, const char* const* argv)
497 {
498   return _spawnvpe(flags, name, argv, NULL);
499 }
500
501 /*********************************************************************
502  *              _popen (MSVCRT.@)
503  */
504 MSVCRT_FILE* MSVCRT__popen(const char* command, const char* mode)
505 {
506   FIXME("(command=%s, mode=%s): stub\n", debugstr_a(command), debugstr_a(mode));
507   return NULL;
508 }
509
510 /*********************************************************************
511  *              _wpopen (MSVCRT.@)
512  */
513 MSVCRT_FILE* MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
514 {
515   FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
516   return NULL;
517 }
518
519 /*********************************************************************
520  *              _pclose (MSVCRT.@)
521  */
522 int MSVCRT__pclose(MSVCRT_FILE* file)
523 {
524   FIXME("(file=%p): stub\n", file);
525   return 0;
526 }
527
528 /*********************************************************************
529  *              system (MSVCRT.@)
530  */
531 int MSVCRT_system(const char* cmd)
532 {
533     char* cmdcopy;
534     int res;
535
536     /* Make a writable copy for CreateProcess */
537     cmdcopy=_strdup(cmd);
538     /* FIXME: should probably launch cmd interpreter in COMSPEC */
539     res=msvcrt_spawn(MSVCRT__P_WAIT, NULL, cmdcopy, NULL);
540     MSVCRT_free(cmdcopy);
541     return res;
542 }
543
544 /*********************************************************************
545  *              _loaddll (MSVCRT.@)
546  */
547 int _loaddll(const char* dllname)
548 {
549   return (int)LoadLibraryA(dllname);
550 }
551
552 /*********************************************************************
553  *              _unloaddll (MSVCRT.@)
554  */
555 int _unloaddll(int dll)
556 {
557   if (FreeLibrary((HMODULE)dll))
558     return 0;
559   else
560   {
561     int err = GetLastError();
562     msvcrt_set_errno(err);
563     return err;
564   }
565 }
566
567 /*********************************************************************
568  *              _getdllprocaddr (MSVCRT.@)
569  */
570 void *_getdllprocaddr(int dll, const char *name, int ordinal)
571 {
572     if (name)
573     {
574         if (ordinal != -1) return NULL;
575         return GetProcAddress( (HMODULE)dll, name );
576     }
577     if (HIWORD(ordinal)) return NULL;
578     return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
579 }