#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <sys/_process.h>

void search_path(char *file, char *path);

struct _new_proc {
    unsigned long arg_off;
    unsigned long env_off;
    unsigned long fname_off;
    unsigned short arg_sel;
    unsigned short env_sel;
    unsigned short fname_sel;
    unsigned short arg_count;
    unsigned short arg_size;
    unsigned short env_count;
    unsigned short env_size;
    unsigned short mode;
};

int __spawnve(struct _new_proc * np)
{
    int ret_v;

    __asm__("movl   %1, %%edx \n\t"
	    "movw   $0x7F06, %%ax \n\t"
	    "int    $0x21 \n\t"
	    "jc     1f \n\t"
	    "jmp    2f \n\t"
	    "1: \n\t"
	    "movl   %0, _errno \n\t"
	    "movl   $-1, %0 \n\t"
	    "2:\n\t"
  : "=a"(ret_v):"m"(np));
    return ret_v;
}

int spawnve(int mode, const char *name, const char *const * argv,
	     const char *const * envp)
{
    struct _new_proc np;
    int i, size, n;
    const char *const * p;
    char *d;
    char exe[512];

    np.mode = mode;
    strcpy(exe, name);
    np.fname_off = (unsigned long) exe;

    if (envp == NULL)
	envp = (const char *const *) environ;

    for (size = 1, n = 0, p = envp; *p != NULL; ++p) {
	++n;
	size += 1 + strlen(*p);
    }

    d = alloca(size);
    np.env_count = n;
    np.env_size = size;
    np.env_off = (unsigned long) d;

    for (p = envp; *p != NULL; ++p) {
	i = strlen(*p);
	(void) memcpy(d, *p, i + 1);
	d += i + 1;
    }

    *d = 0;
    size = 0;
    n = 0;
    for (p = argv; *p != NULL; ++p) {
	++n;
	size += 2 + strlen(*p);
    }
    d = alloca(size);

    np.arg_count = n;
    np.arg_size = size;
    np.arg_off = (unsigned long) d;

    for (p = argv; *p != NULL; ++p) {
	i = strlen(*p);
	*d++ = 0xff;
	(void) memcpy(d, *p, i + 1);
	d += i + 1;
    }

    i = __spawnve(&np);
    return (i);
}

int spawnvpe(int mode, const char *name, const char *const * argv,
	      const char *const * envp)
{
    char exe[512];
    char path[512];

    strcpy(exe, name);
    search_path(exe, path);
    return (spawnve(mode, path, argv, envp));
}

int spawnl(int mode, const char *name, const char *arg0,...)
{
    va_list vl;
    int r;

    va_start(vl, name);
    r = spawnv(mode, name, (const char *const *) vl);
    va_end(vl);
    return (r);
}

int spawnle(int mode, const char *name, const char *arg0,...)
{
    va_list vl;
    const char *const * env_ptr;
    int r;

    va_start(vl, name);
    while (va_arg(vl, char *) !=NULL)
	;
    env_ptr = va_arg(vl, const char *const *);
    va_end(vl);
    va_start(vl, name);
    r = spawnve(mode, name, (const char *const *) vl, env_ptr);
    va_end(vl);
    return (r);
}

int spawnlp(int mode, const char *name, const char *arg0,...)
{
    va_list vl;
    int r;

    va_start(vl, name);
    r = spawnvp(mode, name, (const char *const *) vl);
    va_end(vl);
    return (r);
}

int spawnlpe(int mode, const char *name, const char *arg0,...)
{
    va_list vl;
    const char *const * env_ptr;
    int r;

    va_start(vl, name);
    while (va_arg(vl, char *) !=NULL)
	 /* do nothing */ ;
    env_ptr = va_arg(vl, const char *const *);
    va_end(vl);
    va_start(vl, name);
    r = spawnvpe(mode, name, (const char *const *) vl, env_ptr);
    va_end(vl);
    return (r);
}
int spawnv(int mode, const char *name, const char *const * argv)
{
    return (spawnve(mode, name, argv, NULL));
}
int spawnvp(int mode, const char *name, const char *const * argv)
{
    return (spawnvpe(mode, name, argv, NULL));
}

void search_path(char *file, char *path)
{
    char *envp, *end;
    int i, len;
  
    strcpy (path, file);
    len = strlen (file);
    if (access (path, 4) == 0)
	return;
    envp = getenv("PATH");
    if (envp != NULL)
	for (;;) {
	    while (*envp == ' ' || *envp == '\t')
		++envp;
	    if (*envp == 0)
		break;
	    end = envp;
	    while (*end != 0 && *end != ';')
		++end;
	    i = end - envp;
	    while (i>0 && (envp[i-1] == ' ' || envp[i-1] == '\t'))
		--i;
	    if (i != 0) {
		memcpy (path, envp, i);
		if (envp[i-1] != '/' && envp[i-1] != '\\' && envp[i-1] != ':')
		    path[i++] = '\\';
		strcpy (path+i, file);
		if (access (path, 4) == 0)
		    return;
		strcat (path+i+len, ".exe");
		if (access (path, 4) == 0)
		    return;
	    }
	    if (*end == 0) break;
	    envp = end + 1;
	}
    path[0] = 0;
}

