1 /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
2 /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
3 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
6 #include <msvcrt/stdio.h>
7 #include <msvcrt/stdlib.h>
8 #include <msvcrt/string.h>
9 #include <msvcrt/errno.h>
10 #include <msvcrt/process.h>
11 #include <msvcrt/ctype.h>
12 #include <msvcrt/io.h>
31 // information about crtdll file handles is not passed to child
32 int _fileinfo_dll = 0;
35 direct_exec_tail(const char* program, const char* args,
37 PROCESS_INFORMATION* ProcessInformation)
39 static STARTUPINFO StartupInfo;
41 StartupInfo.cb = sizeof(STARTUPINFO);
42 StartupInfo.lpReserved= NULL;
43 StartupInfo.dwFlags = 0;
44 StartupInfo.wShowWindow = SW_SHOWDEFAULT;
45 StartupInfo.lpReserved2 = NULL;
46 StartupInfo.cbReserved2 = 0;
47 if (!CreateProcessA((char*)program,(char*)args,NULL,NULL,FALSE,0,(char**)envp,NULL,&StartupInfo,ProcessInformation)) {
48 __set_errno( GetLastError() );
51 return (int)ProcessInformation->hProcess;
54 static int vdm_exec(const char* program, char** argv, char** envp,
55 PROCESS_INFORMATION* ProcessInformation)
57 static char args[1024];
61 strcpy(args, "vdm.exe ");
62 while (argv[i] != NULL) {
63 strcat(args, argv[i]);
67 return direct_exec_tail(program,args,envp,ProcessInformation);
70 static int go32_exec(const char* program, char** argv, char** envp,
71 PROCESS_INFORMATION* ProcessInformation)
73 static char args[1024];
74 static char envblock[2048];
80 while(envp[i] != NULL ) {
81 strcat(penvblock,envp[i]);
82 penvblock+=strlen(envp[i])+1;
88 while(argv[i] != NULL ) {
93 return direct_exec_tail(program,args,envp,ProcessInformation);
96 int command_exec(const char* program, char** argv, char** envp,
97 PROCESS_INFORMATION* ProcessInformation)
99 static char args[1024];
103 strcpy(args,"cmd.exe /c ");
104 while(argv[i] != NULL ) {
105 strcat(args,argv[i]);
109 return direct_exec_tail(program,args,envp,ProcessInformation);
112 static int script_exec(const char* program, char** argv, char** envp,
113 PROCESS_INFORMATION* ProcessInformation)
119 /* Note: the following list is not supposed to mention *every*
120 possible extension of an executable file. It only mentions
121 those extensions that can be *omitted* when you invoke the
122 executable from one of the shells used on MSDOS. */
124 const char* extension;
125 int (*interp)(const char*, char**, char**, PROCESS_INFORMATION*);
127 { ".com", vdm_exec },
128 { ".exe", go32_exec },
129 { ".dll", go32_exec },
130 { ".cmd", command_exec },
131 { ".bat", command_exec },
132 { ".btm", command_exec },
133 { ".sh", script_exec }, /* for compatibility with ms_sh */
134 { ".ksh", script_exec },
135 { ".pl", script_exec }, /* Perl */
136 { ".sed", script_exec },
138 { 0, script_exec }, /* every extension not mentioned above calls it */
142 /* This is the index into the above array of the interpreter
143 which is called when the program filename has no extension. */
144 #define INTERP_NO_EXT (sizeof(interpreters)/sizeof(interpreters[0]) - 3)
146 /*-------------------------------------------------*/
148 int _spawnve(int mode, const char* path, char* const argv[], char* const envp[])
150 /* This is the one that does the work! */
151 PROCESS_INFORMATION ProcessInformation;
152 union { char* const* x; char** p; } u;
156 char rpath[FILENAME_MAX], *rp, *rd = 0;
162 if (path == 0 || argv[0] == 0) {
166 if (strlen(path) > FILENAME_MAX - 1) {
167 errno = ENAMETOOLONG;
170 u.x = argv; argvp = u.p;
171 u.x = envp; envpp = u.p;
172 fflush(stdout); /* just in case */
173 for (rp=rpath; *path; *rp++ = *path++) {
176 if (*path == '\\' || *path == '/')
181 /* If LFN is supported on the volume where rpath resides, we
182 might have something like foo.bar.exe or even foo.exe.com.
183 If so, look for RPATH.ext before even trying RPATH itself. */
185 for (i=0; interpreters[i].extension; i++) {
186 strcpy(rp, interpreters[i].extension);
187 if (_access(rpath, F_OK) == 0 && !(is_dir = (_access(rpath, D_OK) == 0))) {
195 const char *rpath_ext;
204 for ( ; interpreters[i].extension; i++)
205 if (_stricmp(rpath_ext, interpreters[i].extension) == 0
206 && _access(rpath, F_OK) == 0
207 && !(is_dir = (_access(rpath, D_OK) == 0)))
214 errno = is_dir ? EISDIR : ENOENT;
218 i = interpreters[i].interp(rpath, argvp, envpp, &ProcessInformation);
219 if (mode == P_OVERLAY)
221 if (mode == P_WAIT) {
222 WaitForSingleObject(ProcessInformation.hProcess,INFINITE);
223 GetExitCodeProcess(ProcessInformation.hProcess,&ExitCode);
229 const char* find_exec(char* path, char* rpath)
238 if (strlen(path) > FILENAME_MAX - 1)
241 /* copy path in rpath */
242 for (rd=path,rp=rpath; *rd; *rp++ = *rd++)
245 /* try first with the name as is */
246 for (i=0; interpreters[i].extension; i++) {
247 strcpy(rp, interpreters[i].extension);
248 if (_access(rpath, F_OK) == 0 && !(is_dir = (_access(rpath, D_OK) == 0))) {
254 /* search in the PATH */
255 char winpath[MAX_PATH];
256 if (GetEnvironmentVariableA("PATH", winpath, MAX_PATH)) {
259 if (*ep == ';') ep++;
261 for ( ; *ep && (*ep != ';') ; *rp++ = *ep++)
264 for (rd = path ; *rd ; *rp++ = *rd++)
266 for (i = 0; interpreters[i].extension; i++) {
267 strcpy(rp, interpreters[i].extension);
268 if (_access(rpath, F_OK) == 0 && !(is_dir = (_access(rpath, D_OK) == 0))) {
282 int _spawnvpe(int nMode, const char* szPath, char* const* szaArgv, char* const* szaEnv)
284 char rpath[FILENAME_MAX];
286 return _spawnve(nMode, find_exec((char*)szPath,rpath), szaArgv, szaEnv);