Index: /trunk/src/kash/shfile.c
===================================================================
--- /trunk/src/kash/shfile.c	(revision 2292)
+++ /trunk/src/kash/shfile.c	(revision 2293)
@@ -451,4 +451,52 @@
 }
 
+#if K_OS == K_OS_WINDOWS && defined(SHFILE_IN_USE) //&& defined(SH_FORKED_MODE)
+/**
+ * Helper for shfork.
+ *
+ * @param   pfdtab  The file descriptor table.
+ * @param   set     Whether to make all handles inheritable (1) or
+ *                  to restore them to the rigth state (0).
+ * @param   hndls   Where to store the three standard handles.
+ */
+void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls)
+{
+    shmtxtmp tmp;
+    unsigned i;
+
+    shmtx_enter(&pfdtab->mtx, &tmp);
+
+    i = pfdtab->size;
+    while (i-- > 0)
+    {
+        if (pfdtab->tab[i].fd == i)
+        {
+            HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
+            DWORD  fFlag = set || !pfdtab->tab[i].cloexec ? HANDLE_FLAG_INHERIT : 0;
+            if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, fFlag))
+            {
+                DWORD err = GetLastError();
+                assert(0);
+            }
+        }
+    }
+
+    if (hndls)
+    {
+        for (i = 0; i < 3; i++)
+        {
+            if (    pfdtab->size > i
+                &&  pfdtab->tab[i].fd == 0)
+                hndls[i] = pfdtab->tab[i].native;
+            else
+                hndls[i] = (intptr_t)INVALID_HANDLE_VALUE;
+        }
+    }
+
+    shmtx_leave(&pfdtab->mtx, &tmp);
+}
+#endif
+
+
 /**
  * open().
Index: /trunk/src/kash/shfile.h
===================================================================
--- /trunk/src/kash/shfile.h	(revision 2292)
+++ /trunk/src/kash/shfile.h	(revision 2293)
@@ -119,4 +119,5 @@
 
 int shfile_init(shfdtab *, shfdtab *);
+void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls);
 
 int shfile_open(shfdtab *, const char *, unsigned, mode_t);
Index: /trunk/src/kash/shfork-win.c
===================================================================
--- /trunk/src/kash/shfork-win.c	(revision 2292)
+++ /trunk/src/kash/shfork-win.c	(revision 2293)
@@ -7,4 +7,11 @@
 #include <locale.h>
 #include "shinstance.h"
+#include <Windows.h>
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+/** The stack size. This is also defined in shforkA-win.asm. */
+#define SHFORK_STACK_SIZE (1*1024*1024)
 
 
@@ -26,5 +33,5 @@
 /* called by shforkA-win.asm: */
 void *shfork_maybe_forked(int argc, char **argv, char **envp);
-extern int shfork_body(uintptr_t stack_ptr);
+extern int shfork_body(shinstance *psh, void *stack_ptr);
 
 
@@ -56,6 +63,10 @@
         ||  strcmp(argv[6], "--stack-limit"))
     {
+        char *stack;
         shheap_init();
-        return (char *)sh_malloc(NULL, 1*1024*1024) + 1*1024*1024;
+        stack = (char *)sh_malloc(NULL, SHFORK_STACK_SIZE) + SHFORK_STACK_SIZE;
+        g_stack_base = stack + SHFORK_STACK_SIZE;
+        g_stack_limit = stack;
+        return stack;
     }
 
@@ -64,5 +75,5 @@
      * fork() call.
      */
-	setlocale(LC_ALL, "");
+    setlocale(LC_ALL, "");
 
     /*
@@ -121,4 +132,5 @@
         ptr <<= 4;
         ptr |= digit;
+        str++;
     }
     return (void *)ptr;
@@ -132,9 +144,118 @@
  *
  * @returns child pid on success, -1 and errno on failure.
+ * @param   psh             The shell that's forking.
  * @param   stack_ptr       The stack address at which the guest is suppost to resume.
  */
-int shfork_body(uintptr_t stack_ptr)
+int shfork_body(shinstance *psh, void *stack_ptr)
 {
-    errno = ENOSYS;
-    return -1;
+    PROCESS_INFORMATION ProcInfo;
+    STARTUPINFO StrtInfo;
+    intptr_t hndls[3];
+    char szExeName[1024];
+    char szCmdLine[1024+256];
+    DWORD cch;
+    int rc = 0;
+
+    /*
+     * Mark all handles inheritable and get the three standard handles.
+     */
+    shfile_fork_win(&psh->fdtab, 1 /* set */, &hndls[0]);
+
+    /*
+     * Create the process.
+     */
+    cch = GetModuleFileName(GetModuleHandle(NULL), szExeName, sizeof(szExeName));
+    if (cch > 0)
+    {
+#if 0 /* quoting the program name doesn't seems to be working :/ */
+        szCmdLine[0] = '"';
+        memcpy(&szCmdLine[1], szExeName, cch);
+        szCmdLine[++cch] = '"';
+#else
+        memcpy(&szCmdLine[0], szExeName, cch);
+#endif
+        cch += sprintf(&szCmdLine[cch], " --!forked!-- --stack-address %p --stack-base %p --stack-limit %p",
+                       stack_ptr, g_stack_base, g_stack_limit);
+        szCmdLine[cch+1] = '\0';
+
+        memset(&StrtInfo, '\0', sizeof(StrtInfo)); /* just in case. */
+        StrtInfo.cb = sizeof(StrtInfo);
+        StrtInfo.lpReserved = NULL;
+        StrtInfo.lpDesktop = NULL;
+        StrtInfo.lpTitle = NULL;
+        StrtInfo.dwX = 0;
+        StrtInfo.dwY = 0;
+        StrtInfo.dwXSize = 0;
+        StrtInfo.dwYSize = 0;
+        StrtInfo.dwXCountChars = 0;
+        StrtInfo.dwYCountChars = 0;
+        StrtInfo.dwFillAttribute = 0;
+        StrtInfo.dwFlags = 0;
+        StrtInfo.wShowWindow = 0;
+        StrtInfo.cbReserved2 = 0;
+        StrtInfo.lpReserved2 = NULL;
+        StrtInfo.hStdInput  = (HANDLE)hndls[0];
+        StrtInfo.hStdOutput = (HANDLE)hndls[1];
+        StrtInfo.hStdError  = (HANDLE)hndls[2];
+        if (CreateProcess(szExeName,
+                          szCmdLine,
+                          NULL,         /* pProcessAttributes */
+                          NULL,         /* pThreadAttributes */
+                          TRUE,         /* bInheritHandles */
+                          CREATE_SUSPENDED,
+                          NULL,         /* pEnvironment */
+                          NULL,         /* pCurrentDirectory */
+                          &StrtInfo,
+                          &ProcInfo))
+        {
+            /*
+             * Copy the memory to the child.
+             */
+            rc = shheap_fork_copy_to_child(ProcInfo.hProcess);
+            if (!rc)
+            {
+                if (ResumeThread(ProcInfo.hThread) != (DWORD)-1)
+                {
+                    rc = sh_add_child(psh, ProcInfo.dwProcessId, ProcInfo.hProcess);
+                    if (!rc)
+                        rc = (int)ProcInfo.dwProcessId;
+                }
+                else
+                {
+                    DWORD dwErr = GetLastError();
+                    fprintf(stderr, "shfork: ResumeThread() -> %d\n", dwErr);
+                    errno = EINVAL;
+                    rc = -1;
+                }
+            }
+            if (rc == -1)
+            {
+                TerminateProcess(ProcInfo.hProcess, 127);
+                /* needed?: ResumeThread(ProcInfo.hThread); */
+                CloseHandle(ProcInfo.hProcess);
+            }
+            CloseHandle(ProcInfo.hThread);
+        }
+        else
+        {
+            DWORD dwErr = GetLastError();
+            fprintf(stderr, "shfork: CreateProcess(%s) -> %d\n", szExeName, dwErr);
+            errno = EINVAL;
+            rc = -1;
+        }
+    }
+    else
+    {
+        DWORD dwErr = GetLastError();
+        fprintf(stderr, "shfork: GetModuleFileName() -> %d\n", dwErr);
+        errno = EINVAL;
+        rc = -1;
+    }
+
+    /*
+     * Restore the handle inherit property.
+     */
+    shfile_fork_win(&psh->fdtab, 0 /* restore */, NULL);
+
+    return rc;
 }
Index: /trunk/src/kash/shforkA-win.asm
===================================================================
--- /trunk/src/kash/shforkA-win.asm	(revision 2292)
+++ /trunk/src/kash/shforkA-win.asm	(revision 2293)
@@ -32,4 +32,7 @@
  %define NAME(name) _ %+ name
 %endif
+
+;; The stack size. This is also defined in shfork-win.c.
+%define SHFORK_STACK_SIZE (1*1024*1024)
 
 
@@ -108,5 +111,5 @@
         mov     [gs:08h], rax
 .below:
-        lea     r9, [rax - 1*1024*1024]
+        lea     r9, [rax - SHFORK_STACK_SIZE]
         cmp     r9, r11
         ja      .above
@@ -132,5 +135,5 @@
         mov     [fs:04h], rax
 .below:
-        lea     edx, [eax - 1*1024*1024]
+        lea     edx, [eax - SHFORK_STACK_SIZE]
         cmp     edx, ecx
         ja      .above
@@ -175,4 +178,7 @@
 ;;
 ; sh_fork() worker
+;
+; @returns      See fork().
+; @param        psh
 ;
 NAME(shfork_do_it):
@@ -230,12 +236,16 @@
         ;
 %ifdef KBUILD_ARCH_AMD64
-        mov     rcx, rsp
-%else
-        mov     ecx, esp
+        ;mov     rcx, rcx               ; psh
+        mov     rdx, rsp                ; stack_ptr
+        sub     rsp, 20h
+        call    NAME(shfork_body)
+        lea     rsp, [rsp + 20h]
+%else
+        mov     edx, esp
+        mov     ecx, [ebp + 8h]         ; psh
         sub     esp, 20h
-        mov     [esp], ecx
-%endif
+        mov     [esp    ], edx
+        mov     [esp + 4], ecx          ; stack_ptr
         call    NAME(shfork_body)
-%ifdef KBUILD_ARCH_AMD64
         lea     esp, [esp + 20h]
 %endif
Index: /trunk/src/kash/shheap.c
===================================================================
--- /trunk/src/kash/shheap.c	(revision 2292)
+++ /trunk/src/kash/shheap.c	(revision 2293)
@@ -137,4 +137,50 @@
 #ifdef SHHEAP_IN_USE
 
+# if K_OS == K_OS_WINDOWS
+/**
+ * Copies the heap into the child process.
+ *
+ * @returns 0 on success, -1 and errno on failure.
+ * @param   hChild      Handle to the child process.
+ */
+int shheap_fork_copy_to_child(void *hChild)
+{
+    shmemchunk *chunk;
+    shmtxtmp tmp;
+    int err = 0;
+
+    shmtx_enter(&g_sh_heap_mtx, &tmp);
+
+    for (chunk = g_sh_heap; chunk; chunk = chunk->next)
+    {
+        void *chld_chnk;
+
+        chld_chnk = (shmemchunk *)VirtualAllocEx(hChild, chunk, chunk->size,
+                                                 MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
+        if (chld_chnk != chunk)
+        {
+            err = GetLastError();
+            fprintf(stderr, "shfork: VirtualAllocEx(,%p,%p,) -> %d\n", chunk, chunk->size, err);
+            break;
+        }
+
+        if (!WriteProcessMemory(hChild, chunk, chunk, chunk->size, NULL /* pNumberOfBytesWritten */))
+        {
+            err = GetLastError();
+            fprintf(stderr, "shfork: WriteProcessMemory(,%p,,%p,) -> %d\n", chunk, chunk->size, err);
+            break;
+        }
+    }
+
+    shmtx_leave(&g_sh_heap_mtx, &tmp);
+
+    if (!err)
+        return 0;
+    errno = EINVAL;
+    return -1;
+}
+# endif
+
+
 /**
  * Checks a heap chunk.
Index: /trunk/src/kash/shheap.h
===================================================================
--- /trunk/src/kash/shheap.h	(revision 2292)
+++ /trunk/src/kash/shheap.h	(revision 2293)
@@ -33,4 +33,6 @@
 /* heap */
 int shheap_init(void);
+int shheap_fork_copy_to_child(void *);
+
 void *sh_malloc(shinstance *, size_t);
 void *sh_calloc(shinstance *, size_t, size_t);
Index: /trunk/src/kash/shinstance.c
===================================================================
--- /trunk/src/kash/shinstance.c	(revision 2292)
+++ /trunk/src/kash/shinstance.c	(revision 2293)
@@ -38,8 +38,11 @@
 # include <pwd.h>
 #endif
+#if K_OS == K_OS_WINDOWS
+# include <Windows.h>
+#endif
 #include "shinstance.h"
 
 #if K_OS == K_OS_WINDOWS
-extern pid_t shfork_do_it(void); /* shforkA-win.asm */
+extern pid_t shfork_do_it(shinstance *psh); /* shforkA-win.asm */
 #endif
 
@@ -308,4 +311,5 @@
 }
 
+/** getenv() */
 char *sh_getenv(shinstance *psh, const char *var)
 {
@@ -868,4 +872,38 @@
 }
 
+/**
+ * Adds a child to the shell
+ *
+ * @returns 0 on success, on failure -1 and errno set to ENOMEM.
+ *
+ * @param   psh     The shell instance.
+ * @param   pid     The child pid.
+ * @param   hChild  Windows child handle.
+ */
+int sh_add_child(shinstance *psh, pid_t pid, void *hChild)
+{
+    /* get a free table entry. */
+    int i = psh->num_children++;
+    if (!(i % 32))
+    {
+        void *ptr = sh_realloc(psh, psh->children, sizeof(*psh->children) * (i + 32));
+        if (!ptr)
+        {
+            psh->num_children--;
+            errno = ENOMEM;
+            return -1;
+        }
+        psh->children = ptr;
+    }
+
+    /* add it */
+    psh->children[i].pid = pid;
+#if K_OS == K_OS_WINDOWS
+    psh->children[i].hChild = hChild;
+#endif
+    (void)hChild;
+    return 0;
+}
+
 pid_t sh_fork(shinstance *psh)
 {
@@ -877,5 +915,5 @@
 
 #elif K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
-    pid = shfork_do_it();
+    pid = shfork_do_it(psh);
 
 #elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
@@ -896,13 +934,106 @@
 }
 
+/** waitpid() */
 pid_t sh_waitpid(shinstance *psh, pid_t pid, int *statusp, int flags)
 {
     pid_t pidret;
-
+#ifdef SH_PURE_STUB_MODE
     *statusp = 0;
-#ifdef SH_PURE_STUB_MODE
     pidret = -1;
 
-#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
+#elif K_OS == K_OS_WINDOWS //&& defined(SH_FORKED_MODE)
+    DWORD   dwRet;
+    HANDLE  hChild = INVALID_HANDLE_VALUE;
+    int     i;
+
+    *statusp = 0;
+    pidret = -1;
+    if (pid != -1)
+    {
+        /*
+         * A specific child, try look it up in the child process table
+         * and wait for it.
+         */
+        for (i = 0; i < psh->num_children; i++)
+            if (psh->children[i].pid == pid)
+                break;
+        if (i < psh->num_children)
+        {
+            dwRet = WaitForSingleObject(psh->children[i].hChild,
+                                        flags & WNOHANG ? 0 : INFINITE);
+            if (dwRet == WAIT_OBJECT_0)
+                hChild = psh->children[i].hChild;
+            else if (dwRet == WAIT_TIMEOUT)
+            {
+                i = -1; /* don't try close anything */
+                pidret = 0;
+            }
+            else
+                errno = ECHILD;
+        }
+        else
+            errno = ECHILD;
+    }
+    else if (psh->num_children <= MAXIMUM_WAIT_OBJECTS)
+    {
+        HANDLE ahChildren[64];
+        for (i = 0; i < psh->num_children; i++)
+            ahChildren[i] = psh->children[i].hChild;
+        dwRet = WaitForMultipleObjects(psh->num_children, &ahChildren[0],
+                                       FALSE,
+                                       flags & WNOHANG ? 0 : INFINITE);
+        i = dwRet - WAIT_OBJECT_0;
+        if ((unsigned)i < (unsigned)psh->num_children)
+        {
+            hChild = psh->children[i].hChild;
+        }
+        else if (dwRet == WAIT_TIMEOUT)
+        {
+            i = -1; /* don't try close anything */
+            pidret = 0;
+        }
+        else
+        {
+            i = -1; /* don't try close anything */
+            errno = EINVAL;
+        }
+    }
+    else
+    {
+        fprintf(stderr, "panic! too many children!\n");
+        i = -1;
+        *(char *)1 = '\0'; /** @todo implement this! */
+    }
+
+    /*
+     * Close the handle, and if we succeeded collect the exit code first.
+     */
+    if (    i >= 0
+        &&  i < psh->num_children)
+    {
+        if (hChild != INVALID_HANDLE_VALUE)
+        {
+            DWORD dwExitCode = 127;
+            if (GetExitCodeProcess(hChild, &dwExitCode))
+            {
+                pidret = psh->children[i].pid;
+                if (dwExitCode && !W_EXITCODE(dwExitCode, 0))
+                    dwExitCode |= 16;
+                *statusp = W_EXITCODE(dwExitCode, 0);
+            }
+            else
+                errno = EINVAL;
+        }
+
+        /* remove and close */
+        hChild = psh->children[i].hChild;
+        psh->num_children--;
+        if (i < psh->num_children)
+            psh->children[i] = psh->children[psh->num_children];
+        i = CloseHandle(hChild); assert(i);
+    }
+
+#elif defined(SH_STUB_MODE) || defined(SH_FORKED_MODE)
+    *statusp = 0;
 # ifdef _MSC_VER
     pidret = -1;
Index: /trunk/src/kash/shinstance.h
===================================================================
--- /trunk/src/kash/shinstance.h	(revision 2292)
+++ /trunk/src/kash/shinstance.h	(revision 2293)
@@ -59,4 +59,14 @@
 #endif
 
+/**
+ * A child process.
+ */
+typedef struct shchild
+{
+    pid_t       pid;                    /**< The pid. */
+#if K_OS == K_OS_WINDOWS
+    void       *hChild;                 /**< The process handle. */
+#endif
+} shchild;
 
 /* memalloc.c */
@@ -135,4 +145,6 @@
     shsigset_t          sigmask;        /**< Our signal mask. */
     char              **shenviron;      /**< The environment vector. */
+    int                 num_children;   /**< Number of children in the array. */
+    shchild            *children;       /**< The child array. */
 
     /* alias.c */
@@ -396,4 +408,5 @@
 
 /* wait / process */
+int sh_add_child(shinstance *psh, pid_t pid, void *hChild);
 #ifdef _MSC_VER
 #   include <process.h>
Index: /trunk/src/kash/show.c
===================================================================
--- /trunk/src/kash/show.c	(revision 2292)
+++ /trunk/src/kash/show.c	(revision 2293)
@@ -274,5 +274,5 @@
 trputc(shinstance *psh, int c)
 {
-	if (debug(psh) != 1)
+	if (psh && debug(psh) != 1)
 		return;
 	putc(c, tracefile);
@@ -287,7 +287,7 @@
 	va_list va;
 
-	if ((psh || !tracefile) && debug(psh) != 1)
-		return;
-        fprintf(tracefile, "[%d] ", sh_getpid(psh));
+	if (!tracefile || (psh && debug(psh) != 1))
+		return;
+	fprintf(tracefile, "[%d] ", sh_getpid(psh));
 	va_start(va, fmt);
 	(void) vfprintf(tracefile, fmt, va);
@@ -304,7 +304,7 @@
 	int savederrno = errno;
 
-	if ((psh || !tracefile) && debug(psh) != 1)
-		return;
-        fprintf(tracefile, "[%d] ", sh_getpid(psh));
+	if (!tracefile || (psh && debug(psh) != 1))
+		return;
+	fprintf(tracefile, "[%d] ", sh_getpid(psh));
 	(void) vfprintf(tracefile, fmt, va);
 
@@ -320,5 +320,5 @@
 	int savederrno = errno;
 
-	if ((psh || !tracefile) && debug(psh) != 1)
+	if (!tracefile || (psh && debug(psh) != 1))
 		return;
 	fputs(s, tracefile);
@@ -335,5 +335,5 @@
 	char c;
 
-	if ((psh || !tracefile) && debug(psh) != 1)
+	if (!tracefile || (psh && debug(psh) != 1))
 		return;
 	putc('"', tracefile);
@@ -378,5 +378,5 @@
 	int savederrno = errno;
 
-	if ((psh || !tracefile) && debug(psh) != 1)
+	if (!tracefile || (psh && debug(psh) != 1))
 		return;
 	while (*ap) {
@@ -400,5 +400,5 @@
 	int fd;
 
-	if (debug(psh) != 1) {
+	if (psh && debug(psh) != 1) {
 		if (tracefile)
 			fflush(tracefile);
