Implementation of spawnl and spawnlp.
diff --git a/dlls/msvcrt/msvcrt.spec b/dlls/msvcrt/msvcrt.spec
index 7c10e9f..5729933 100644
--- a/dlls/msvcrt/msvcrt.spec
+++ b/dlls/msvcrt/msvcrt.spec
@@ -442,9 +442,9 @@
@ varargs _snprintf(str long str) snprintf
@ forward -noimport _snwprintf ntdll._snwprintf
@ cdecl _sopen(str long long) MSVCRT__sopen
-@ stub _spawnl #(str str) varargs
+@ varargs _spawnl(str str) _spawnl
@ stub _spawnle #(str str) varargs
-@ stub _spawnlp #(str str) varargs
+@ varargs _spawnlp(str str) _spawnlp
@ stub _spawnlpe #(str str) varargs
@ cdecl _spawnv(long str ptr) _spawnv
@ cdecl _spawnve(long str ptr ptr) _spawnve
diff --git a/dlls/msvcrt/process.c b/dlls/msvcrt/process.c
index b9c805c..4f946a2 100644
--- a/dlls/msvcrt/process.c
+++ b/dlls/msvcrt/process.c
@@ -109,6 +109,45 @@
return ret;
}
+/* INTERNAL: Convert va_list to a single 'delim'-separated string */
+static char* msvcrt_valisttos(const char* arg0, va_list ap, char delim)
+{
+ va_list search = ap;
+ long size;
+ char *arg;
+ char *ret;
+ int strsize;
+
+ if (!arg0 && !delim)
+ return NULL;
+
+ /* get length */
+ size = strlen(arg0) + 1;
+ while((arg = va_arg(search, char *)) != NULL)
+ {
+ size += strlen(arg) + 1;
+ }
+
+ if (!(ret = (char *)MSVCRT_calloc(size + 1, 1)))
+ return NULL;
+
+ /* fill string */
+ search = ap;
+ size = 0;
+ strsize = strlen(arg0);
+ memcpy(ret+size,arg0,strsize);
+ ret[size+strsize] = delim;
+ size += strsize + 1;
+ while((arg = va_arg(search, char *)) != NULL)
+ {
+ strsize = strlen(search);
+ memcpy(ret+size,search,strsize);
+ ret[size+strsize] = delim;
+ size += strsize + 1;
+ }
+ return ret;
+}
+
/*********************************************************************
* _cwait (MSVCRT.@)
*/
@@ -143,6 +182,47 @@
}
/*********************************************************************
+ * _spawnl (MSVCRT.@)
+ */
+int _spawnl(int flags, const char* name, const char* arg0, ...)
+{
+ va_list ap;
+ char * args;
+ int ret;
+
+ va_start(ap, arg0);
+ args = msvcrt_valisttos(arg0, ap, ' ');
+ va_end(ap);
+
+ ret = msvcrt_spawn(flags, name, args, NULL);
+ MSVCRT_free(args);
+
+ return ret;
+}
+
+/*********************************************************************
+ * _spawnl (MSVCRT.@)
+ */
+int _spawnlp(int flags, const char* name, const char* arg0, ...)
+{
+ va_list ap;
+ char * args;
+ int ret;
+ char fullname[MAX_PATH];
+
+ _searchenv(name, "PATH", fullname);
+
+ va_start(ap, arg0);
+ args = msvcrt_valisttos(arg0, ap, ' ');
+ va_end(ap);
+
+ ret = msvcrt_spawn(flags, name, args, NULL);
+ MSVCRT_free(args);
+
+ return ret;
+}
+
+/*********************************************************************
* _spawnve (MSVCRT.@)
*/
int _spawnve(int flags, const char* name, const char* const* argv,