diff --git a/src/configure.in b/src/configure.in
index f336bea3daca1ea74dbbe1d15564bf537506c14d..ac63f3d79044fc0d95f1a4623210cfd0c8a7dd03 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1,4 +1,4 @@
-AC_REVISION("$Id: configure.in,v 1.146 1998/01/02 08:18:42 hubbe Exp $")
+AC_REVISION("$Id: configure.in,v 1.147 1998/01/08 17:20:05 hubbe Exp $")
 AC_INIT(interpret.c)
 AC_CONFIG_HEADER(machine.h)
 
@@ -927,6 +927,8 @@ AC_CHECK_FUNCS( \
  strdup \
  kill \
  alarm \
+ fork \
+ fork1 \
 )
 
 if test $ac_cv_func_crypt$ac_cv_func__crypt = nono ; then
@@ -1313,6 +1315,22 @@ int main()
 
 #############################################################################
 
+AC_MSG_CHECKING(if we can declare environ)
+AC_CACHE_VAL(pike_cv_declare_environ,[
+AC_TRY_COMPILE([
+#include <stdlib.h>
+],[
+  extern char **environ;
+  exit(0);
+],pike_cv_declare_environ=yes,pike_cv_declare_environ=no,pike_cv_declare_environ=yes)
+])
+
+AC_MSG_RESULT($pike_cv_declare_environ)
+if test "x$pike_cv_declare_environ" = xyes ; then
+  AC_DEFINE(DECLARE_ENVIRON)
+fi
+
+#############################################################################
 
 AC_MSG_CHECKING(how to extract an unsigned char)
 AC_CACHE_VAL(pike_cv_method_extract_uchar,
diff --git a/src/fdlib.c b/src/fdlib.c
index a6f5fadba48a442f4baed7fff675fbdf02f7f483..7395872c64b0a27520812778fd1c2f9cd63a73be 100644
--- a/src/fdlib.c
+++ b/src/fdlib.c
@@ -406,7 +406,7 @@ FD fd_dup(FD from)
 {
   FD fd;
   HANDLE x,p=GetCurrentProcess();
-  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,1,DUPLICATE_SAME_ACCESS))
+  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,0,DUPLICATE_SAME_ACCESS))
   {
     errno=GetLastError();
     return -1;
@@ -424,7 +424,7 @@ FD fd_dup(FD from)
 FD fd_dup2(FD from, FD to)
 {
   HANDLE x,p=GetCurrentProcess();
-  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,1,DUPLICATE_SAME_ACCESS))
+  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,0,DUPLICATE_SAME_ACCESS))
   {
     errno=GetLastError();
     return -1;
@@ -563,43 +563,1332 @@ void *fd_mapper_get(struct fd_mapper *x, FD fd)
 #endif
 
 
+#if 0
+struct fd_data_hash
+{
+  FD fd;
+  int key;
+  struct fd_data_hash *next;
+  void *data;
+};
+
+#define FD_DATA_PER_BLOCK 255
+
+struct fd_data_hash_block
+{
+  struct fd_data_hash_block *next;
+  struct fd_data_hash data[FD_DATA_PER_BLOCk];
+};
+
+static int keynum=0;
+static unsigned int num_stored_keys=0;
+static unsigned int hash_size=0;
+static struct fd_data_hash *free_blocks=0;
+static struct fd_data_hash **htable=0;
+static fd_data_hash_block *hash_blocks=0;
+
+int get_fd_data_key(void)
+{
+  return ++keynum;
+}
+
+void store_fd_data(FD fd, int key, void *data)
+{
+  struct fd_data_hash *p,**last;
+  unsigned int hval=(fd + key * 53) % hash_size;
+
+  for(last=htable[e];p=*last;last=&p->next)
+  {
+    if(p->fd == fd && p->key == key)
+    {
+      if(data)
+      {
+	p->data=data;
+      }else{
+	*last=p->next;
+	p->next=free_blocks;
+	free_blocks=p;
+	num_stored_keys--;
+      }
+      return;
+    }
+  }
+  if(!data) return;
+
+  num_stored_keys++;
+
+  if(num_stored_keys * 2 >= hash_size)
+  {
+    /* time to rehash */
+    unsigned int h;
+    unsigned int old_hsize=hash_size;
+    unsigned fd_data_hash **old_htable=htable;
+    if(!hash_size)
+      hash_size=127;
+    else
+      hash_size*=3;
+
+    htable=(struct fd_data_hash **)xalloc(hash_size * sizeof(struct fd_data_hash *));
+    
+    for(h=0;h<old_hsize;h++)
+    {
+      for(last=old_htable+e;p=*last;last=&p->next)
+	store_fd_data(p->fd, p->key, p->data);
+      *last=free_blocks;
+      free_blocks=old_htable[h];
+    }
+    if(old_htable)
+      free((char *)old_htable);
+  }
+
+
+  if(!free_blocks)
+  {
+    struct fd_data_hash_block *n;
+    int e;
+    n=ALLOC_STRUCT(fd_data_hash_block);
+    n->next=hash_blocks;
+    hash_blocks=n;
+    for(e=0;e<FD_DATA_PER_BLOCK;e++)
+    {
+      n->data[e].next=free_blocks;
+      free_blocks=n->data+e;
+    }
+  }
+  
+  p=free_blocks;
+  free_blocks=p->next;
+  p->fd=fd;
+  p->key=key;
+  p->data=data;
+  p->next=htable[hval];
+  htable[hval]=p;
+}
+
+void *get_fd_data(FD fd, int key)
+{
+  struct fd_data_hash *p,**last;
+  unsigned int hval=(fd + key * 53) % hash_size;
+
+  for(p=htable[hval];p;p=p->next)
+    if(p->fd == fd && p->key == key)
+      return p->data;
+
+  return 0;
+}
+
+
+#endif
+
+#ifdef FDLIB_USE_SELECT
+
+struct fd_waitor
+{
+  fd_FDSET storage;
+  fd_FDSET temporary;
+static long convert_filetime_to_time_t(FILETIME tmp)
+{
+  double t;
+  t=tmp.dwHighDateTime * pow(2.0,32.0) + (double)tmp.dwLowDateTime;
+  t/=10000000.0;
+  t-=11644473600.0;
+  return (long)floor(t);
+}
+
+int fd_fstat(FD fd, struct stat *s)
+{
+  DWORD x;
+  int ret;
+  FILETIME c,a,m;
+  FDDEBUG(fprintf(stderr,"fstat on %d (%d)\n",fd,da_handle[fd]));
+  if(fd_type[fd]!=FD_FILE)
+  {
+    errno=ENOTSUPP;
+    return -1;
+  }
+
+  MEMSET(s, 0, sizeof(struct stat));
+  s->st_nlink=1;
+
+  switch(fd_type[fd])
+  {
+    case FD_SOCKET:
+      s->st_mode=S_IFSOCK;
+      break;
+
+    default:
+      switch(GetFileType((HANDLE)da_handle[fd]))
+      {
+	default:
+	case FILE_TYPE_UNKNOWN: s->st_mode=0;        break;
+	case FILE_TYPE_DISK:
+	  s->st_mode=S_IFREG; 
+	  s->st_size=GetFileSize((HANDLE)da_handle[fd],&x);
+	  if(x)
+	  {
+	    s->st_size=0x7fffffff;
+	  }
+	  if(!GetFileTime((HANDLE)da_handle[fd], &c, &a, &m))
+	  {
+	    errno=GetLastError();
+	    return -1;
+	  }
+	  s->st_ctime=convert_filetime_to_time_t(c);
+	  s->st_atime=convert_filetime_to_time_t(a);
+	  s->st_mtime=convert_filetime_to_time_t(m);
+	  break;
+	case FILE_TYPE_CHAR:    s->st_mode=S_IFCHR;  break;
+	case FILE_TYPE_PIPE:    s->st_mode=S_IFFIFO; break;
+      }
+  }
+  s->st_mode |= 0666;
+  return 0;
+}
+
+int fd_select(int fds, FD_SET *a, FD_SET *b, FD_SET *c, struct timeval *t)
+{
+  int ret;
+  ret=select(fds,a,b,c,t);
+  if(ret==SOCKET_ERROR)
+  {
+    errno=WSAGetLastError();
+    return -1;
+  }
+  return ret;
+}
+
+
+int fd_ioctl(FD fd, int cmd, void *data)
+{
+  int ret;
+  switch(fd_type[fd])
+  {
+    case FD_SOCKET:
+      ret=ioctlsocket((SOCKET)da_handle[fd], cmd, data);
+      if(ret==SOCKET_ERROR)
+      {
+	errno=WSAGetLastError();
+	return -1;
+      }
+      return ret;
+
+    default:
+      errno=ENOTSUPP;
+      return -1;
+  }
+}
+
+
+FD fd_dup(FD from)
+{
+  FD fd;
+  HANDLE x,p=GetCurrentProcess();
+  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,0,DUPLICATE_SAME_ACCESS))
+  {
+    errno=GetLastError();
+    return -1;
+  }
+
+  fd=first_free_handle;
+  first_free_handle=fd_type[fd];
+  fd_type[fd]=fd_type[from];
+  da_handle[fd]=(long)x;
+  
+  FDDEBUG(fprintf(stderr,"Dup %d (%d) to %d (%d)\n",from,da_handle[from],fd,x));
+  return fd;
+}
+
+FD fd_dup2(FD from, FD to)
+{
+  HANDLE x,p=GetCurrentProcess();
+  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,0,DUPLICATE_SAME_ACCESS))
+  {
+    errno=GetLastError();
+    return -1;
+  }
+
+  if(fd_type[to] < FD_NO_MORE_FREE)
+  {
+    if(!CloseHandle((HANDLE)da_handle[to]))
+    {
+      errno=GetLastError();
+      return -1;
+    }
+  }else{
+    int *prev,next;
+    for(prev=&first_free_handle;(next=*prev) != FD_NO_MORE_FREE;prev=fd_type+next)
+    {
+      if(next==to)
+      {
+	*prev=fd_type[next];
+	break;
+      }
+    }
+  }
+  fd_type[to]=fd_type[from];
+  da_handle[to]=(long)x;
+
+  FDDEBUG(fprintf(stderr,"Dup2 %d (%d) to %d (%d)\n",from,da_handle[from],to,x));
+
+  return to;
+}
+
+#endif
+
+#if 0
+
+#ifdef FD_LINEAR
+struct fd_mapper
+{
+  int size;
+  void **data;
+};
+
+void init_fd_mapper(struct fd_mapper *x)
+{
+  x->size=64;
+  x->data=(void **)xalloc(x->size*sizeof(void *));
+}
+
+void exit_fd_mapper(struct fd_mapper *x)
+{
+  free((char *)x->data);
+}
+
+void fd_mapper_set(struct fd_mapper *x, FD fd, void *data)
+{
+  while(fd>=x->size)
+  {
+    x->size*=2;
+    x->data=(void **)realloc((char *)x->data, x->size*sizeof(void *));
+    if(!x->data)
+      fatal("Out of memory.\n");
+    x->data=nd;
+  }
+  x->data[fd]=data;
+  
+}
+
+void *fd_mapper_get(struct fd_mapper *x, FD fd)
+{
+  return x->data[fd];
+}
+#else
+struct fd_mapper_data
+{
+  FD x;
+  void *data;
+};
+struct fd_mapper
+{
+  int num;
+  int hsize;
+  struct fd_mapper_data *data;
+};
+
+void init_fd_mapper(struct fd_mapper *x)
+{
+  int i;
+  x->num=0;
+  x->hsize=127;
+  x->data=(struct fd_mapper_data *)xalloc(x->hsize*sizeof(struct fd_mapper_data));
+  for(i=0;i<x->hsize;i++) x->data[i].fd=-1;
+}
+
+void exit_fd_mapper(struct fd_mapper *x)
+{
+  free((char *)x->data);
+}
+
+void fd_mapper_set(struct fd_mapper *x, FD fd, void *data)
+{
+  int hval;
+  x->num++;
+  if(x->num*2 > x->hsize)
+  {
+    struct fd_mapper_data *old=x->data;
+    int i,old_size=x->hsize;
+    x->hsize*=3;
+    x->num=0;
+    x->data=(struct fd_mapper_data *)xalloc(x->size*sizeof(struct fd_mapper_data *));
+    for(i=0;i<x->size;i++) x->data[i].fd=-1;
+    for(i=0;i<old_size;i++)
+      if(old[i].fd!=-1)
+	fd_mapper_set(x, old[i].fd, old[i].data);
+  }
+
+  hval=fd % x->hsize;
+  while(x->data[hval].fd != -1)
+  {
+    hval++;
+    if(hval==x->hsize) hval=0;
+  }
+  x->data[hval].fd=fd;
+  x->data[hval].data=data;
+}
+
+void *fd_mapper_get(struct fd_mapper *x, FD fd)
+{
+  int hval=fd % x->hsize;
+  while(x->data[hval].fd != fd)
+  {
+    hval++;
+    if(hval==x->hsize) hval=0;
+  }
+  return x->data[hval].data;
+}
+#endif
+
+
+#if 0
+struct fd_data_hash
+{
+  FD fd;
+  int key;
+  struct fd_data_hash *next;
+  void *data;
+};
+
+#define FD_DATA_PER_BLOCK 255
+
+struct fd_data_hash_block
+{
+  struct fd_data_hash_block *next;
+  struct fd_data_hash data[FD_DATA_PER_BLOCk];
+};
+
+static int keynum=0;
+static unsigned int num_stored_keys=0;
+static unsigned int hash_size=0;
+static struct fd_data_hash *free_blocks=0;
+static struct fd_data_hash **htable=0;
+static fd_data_hash_block *hash_blocks=0;
+
+int get_fd_data_key(void)
+{
+  return ++keynum;
+}
+
+void store_fd_data(FD fd, int key, void *data)
+{
+  struct fd_data_hash *p,**last;
+  unsigned int hval=(fd + key * 53) % hash_size;
+
+  for(last=htable[e];p=*last;last=&p->next)
+  {
+    if(p->fd == fd && p->key == key)
+    {
+      if(data)
+      {
+	p->data=data;
+      }else{
+	*last=p->next;
+	p->next=free_blocks;
+	free_blocks=p;
+	num_stored_keys--;
+      }
+      return;
+    }
+  }
+  if(!data) return;
+
+  num_stored_keys++;
+
+  if(num_stored_keys * 2 >= hash_size)
+  {
+    /* time to rehash */
+    unsigned int h;
+    unsigned int old_hsize=hash_size;
+    unsigned fd_data_hash **old_htable=htable;
+    if(!hash_size)
+      hash_size=127;
+    else
+      hash_size*=3;
+
+    htable=(struct fd_data_hash **)xalloc(hash_size * sizeof(struct fd_data_hash *));
+    
+    for(h=0;h<old_hsize;h++)
+    {
+      for(last=old_htable+e;p=*last;last=&p->next)
+	store_fd_data(p->fd, p->key, p->data);
+      *last=free_blocks;
+      free_blocks=old_htable[h];
+    }
+    if(old_htable)
+      free((char *)old_htable);
+  }
+
+
+  if(!free_blocks)
+  {
+    struct fd_data_hash_block *n;
+    int e;
+    n=ALLOC_STRUCT(fd_data_hash_block);
+    n->next=hash_blocks;
+    hash_blocks=n;
+    for(e=0;e<FD_DATA_PER_BLOCK;e++)
+    {
+      n->data[e].next=free_blocks;
+      free_blocks=n->data+e;
+    }
+  }
+  
+  p=free_blocks;
+  free_blocks=p->next;
+  p->fd=fd;
+  p->key=key;
+  p->data=data;
+  p->next=htable[hval];
+  htable[hval]=p;
+}
+
+void *get_fd_data(FD fd, int key)
+{
+  struct fd_data_hash *p,**last;
+  unsigned int hval=(fd + key * 53) % hash_size;
+
+  for(p=htable[hval];p;p=p->next)
+    if(p->fd == fd && p->key == key)
+      return p->data;
+
+  return 0;
+}
+
+
+#endif
+
+#ifdef FDLIB_USE_SELECT
+
+struct fd_waitor
+{
+  fd_FDSET storage;
+  fd_FDSET temporary;
+static long convert_filetime_to_time_t(FILETIME tmp)
+{
+  double t;
+  t=tmp.dwHighDateTime * pow(2.0,32.0) + (double)tmp.dwLowDateTime;
+  t/=10000000.0;
+  t-=11644473600.0;
+  return (long)floor(t);
+}
+
+int fd_fstat(FD fd, struct stat *s)
+{
+  DWORD x;
+  int ret;
+  FILETIME c,a,m;
+  FDDEBUG(fprintf(stderr,"fstat on %d (%d)\n",fd,da_handle[fd]));
+  if(fd_type[fd]!=FD_FILE)
+  {
+    errno=ENOTSUPP;
+    return -1;
+  }
+
+  MEMSET(s, 0, sizeof(struct stat));
+  s->st_nlink=1;
+
+  switch(fd_type[fd])
+  {
+    case FD_SOCKET:
+      s->st_mode=S_IFSOCK;
+      break;
+
+    default:
+      switch(GetFileType((HANDLE)da_handle[fd]))
+      {
+	default:
+	case FILE_TYPE_UNKNOWN: s->st_mode=0;        break;
+	case FILE_TYPE_DISK:
+	  s->st_mode=S_IFREG; 
+	  s->st_size=GetFileSize((HANDLE)da_handle[fd],&x);
+	  if(x)
+	  {
+	    s->st_size=0x7fffffff;
+	  }
+	  if(!GetFileTime((HANDLE)da_handle[fd], &c, &a, &m))
+	  {
+	    errno=GetLastError();
+	    return -1;
+	  }
+	  s->st_ctime=convert_filetime_to_time_t(c);
+	  s->st_atime=convert_filetime_to_time_t(a);
+	  s->st_mtime=convert_filetime_to_time_t(m);
+	  break;
+	case FILE_TYPE_CHAR:    s->st_mode=S_IFCHR;  break;
+	case FILE_TYPE_PIPE:    s->st_mode=S_IFFIFO; break;
+      }
+  }
+  s->st_mode |= 0666;
+  return 0;
+}
+
+int fd_select(int fds, FD_SET *a, FD_SET *b, FD_SET *c, struct timeval *t)
+{
+  int ret;
+  ret=select(fds,a,b,c,t);
+  if(ret==SOCKET_ERROR)
+  {
+    errno=WSAGetLastError();
+    return -1;
+  }
+  return ret;
+}
+
+
+int fd_ioctl(FD fd, int cmd, void *data)
+{
+  int ret;
+  switch(fd_type[fd])
+  {
+    case FD_SOCKET:
+      ret=ioctlsocket((SOCKET)da_handle[fd], cmd, data);
+      if(ret==SOCKET_ERROR)
+      {
+	errno=WSAGetLastError();
+	return -1;
+      }
+      return ret;
+
+    default:
+      errno=ENOTSUPP;
+      return -1;
+  }
+}
+
+
+FD fd_dup(FD from)
+{
+  FD fd;
+  HANDLE x,p=GetCurrentProcess();
+  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,0,DUPLICATE_SAME_ACCESS))
+  {
+    errno=GetLastError();
+    return -1;
+  }
+
+  fd=first_free_handle;
+  first_free_handle=fd_type[fd];
+  fd_type[fd]=fd_type[from];
+  da_handle[fd]=(long)x;
+  
+  FDDEBUG(fprintf(stderr,"Dup %d (%d) to %d (%d)\n",from,da_handle[from],fd,x));
+  return fd;
+}
+
+FD fd_dup2(FD from, FD to)
+{
+  HANDLE x,p=GetCurrentProcess();
+  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,0,DUPLICATE_SAME_ACCESS))
+  {
+    errno=GetLastError();
+    return -1;
+  }
+
+  if(fd_type[to] < FD_NO_MORE_FREE)
+  {
+    if(!CloseHandle((HANDLE)da_handle[to]))
+    {
+      errno=GetLastError();
+      return -1;
+    }
+  }else{
+    int *prev,next;
+    for(prev=&first_free_handle;(next=*prev) != FD_NO_MORE_FREE;prev=fd_type+next)
+    {
+      if(next==to)
+      {
+	*prev=fd_type[next];
+	break;
+      }
+    }
+  }
+  fd_type[to]=fd_type[from];
+  da_handle[to]=(long)x;
+
+  FDDEBUG(fprintf(stderr,"Dup2 %d (%d) to %d (%d)\n",from,da_handle[from],to,x));
+
+  return to;
+}
+
+#endif
+
+#if 0
+
+#ifdef FD_LINEAR
+struct fd_mapper
+{
+  int size;
+  void **data;
+};
+
+void init_fd_mapper(struct fd_mapper *x)
+{
+  x->size=64;
+  x->data=(void **)xalloc(x->size*sizeof(void *));
+}
+
+void exit_fd_mapper(struct fd_mapper *x)
+{
+  free((char *)x->data);
+}
+
+void fd_mapper_set(struct fd_mapper *x, FD fd, void *data)
+{
+  while(fd>=x->size)
+  {
+    x->size*=2;
+    x->data=(void **)realloc((char *)x->data, x->size*sizeof(void *));
+    if(!x->data)
+      fatal("Out of memory.\n");
+    x->data=nd;
+  }
+  x->data[fd]=data;
+  
+}
+
+void *fd_mapper_get(struct fd_mapper *x, FD fd)
+{
+  return x->data[fd];
+}
+#else
+struct fd_mapper_data
+{
+  FD x;
+  void *data;
+};
+struct fd_mapper
+{
+  int num;
+  int hsize;
+  struct fd_mapper_data *data;
+};
+
+void init_fd_mapper(struct fd_mapper *x)
+{
+  int i;
+  x->num=0;
+  x->hsize=127;
+  x->data=(struct fd_mapper_data *)xalloc(x->hsize*sizeof(struct fd_mapper_data));
+  for(i=0;i<x->hsize;i++) x->data[i].fd=-1;
+}
+
+void exit_fd_mapper(struct fd_mapper *x)
+{
+  free((char *)x->data);
+}
+
+void fd_mapper_set(struct fd_mapper *x, FD fd, void *data)
+{
+  int hval;
+  x->num++;
+  if(x->num*2 > x->hsize)
+  {
+    struct fd_mapper_data *old=x->data;
+    int i,old_size=x->hsize;
+    x->hsize*=3;
+    x->num=0;
+    x->data=(struct fd_mapper_data *)xalloc(x->size*sizeof(struct fd_mapper_data *));
+    for(i=0;i<x->size;i++) x->data[i].fd=-1;
+    for(i=0;i<old_size;i++)
+      if(old[i].fd!=-1)
+	fd_mapper_set(x, old[i].fd, old[i].data);
+  }
+
+  hval=fd % x->hsize;
+  while(x->data[hval].fd != -1)
+  {
+    hval++;
+    if(hval==x->hsize) hval=0;
+  }
+  x->data[hval].fd=fd;
+  x->data[hval].data=data;
+}
+
+void *fd_mapper_get(struct fd_mapper *x, FD fd)
+{
+  int hval=fd % x->hsize;
+  while(x->data[hval].fd != fd)
+  {
+    hval++;
+    if(hval==x->hsize) hval=0;
+  }
+  return x->data[hval].data;
+}
+#endif
+
+
+#if 0
+struct fd_data_hash
+{
+  FD fd;
+  int key;
+  struct fd_data_hash *next;
+  void *data;
+};
+
+#define FD_DATA_PER_BLOCK 255
+
+struct fd_data_hash_block
+{
+  struct fd_data_hash_block *next;
+  struct fd_data_hash data[FD_DATA_PER_BLOCk];
+};
+
+static int keynum=0;
+static unsigned int num_stored_keys=0;
+static unsigned int hash_size=0;
+static struct fd_data_hash *free_blocks=0;
+static struct fd_data_hash **htable=0;
+static fd_data_hash_block *hash_blocks=0;
+
+int get_fd_data_key(void)
+{
+  return ++keynum;
+}
+
+void store_fd_data(FD fd, int key, void *data)
+{
+  struct fd_data_hash *p,**last;
+  unsigned int hval=(fd + key * 53) % hash_size;
+
+  for(last=htable[e];p=*last;last=&p->next)
+  {
+    if(p->fd == fd && p->key == key)
+    {
+      if(data)
+      {
+	p->data=data;
+      }else{
+	*last=p->next;
+	p->next=free_blocks;
+	free_blocks=p;
+	num_stored_keys--;
+      }
+      return;
+    }
+  }
+  if(!data) return;
+
+  num_stored_keys++;
+
+  if(num_stored_keys * 2 >= hash_size)
+  {
+    /* time to rehash */
+    unsigned int h;
+    unsigned int old_hsize=hash_size;
+    unsigned fd_data_hash **old_htable=htable;
+    if(!hash_size)
+      hash_size=127;
+    else
+      hash_size*=3;
+
+    htable=(struct fd_data_hash **)xalloc(hash_size * sizeof(struct fd_data_hash *));
+    
+    for(h=0;h<old_hsize;h++)
+    {
+      for(last=old_htable+e;p=*last;last=&p->next)
+	store_fd_data(p->fd, p->key, p->data);
+      *last=free_blocks;
+      free_blocks=old_htable[h];
+    }
+    if(old_htable)
+      free((char *)old_htable);
+  }
+
+
+  if(!free_blocks)
+  {
+    struct fd_data_hash_block *n;
+    int e;
+    n=ALLOC_STRUCT(fd_data_hash_block);
+    n->next=hash_blocks;
+    hash_blocks=n;
+    for(e=0;e<FD_DATA_PER_BLOCK;e++)
+    {
+      n->data[e].next=free_blocks;
+      free_blocks=n->data+e;
+    }
+  }
+  
+  p=free_blocks;
+  free_blocks=p->next;
+  p->fd=fd;
+  p->key=key;
+  p->data=data;
+  p->next=htable[hval];
+  htable[hval]=p;
+}
+
+void *get_fd_data(FD fd, int key)
+{
+  struct fd_data_hash *p,**last;
+  unsigned int hval=(fd + key * 53) % hash_size;
+
+  for(p=htable[hval];p;p=p->next)
+    if(p->fd == fd && p->key == key)
+      return p->data;
+
+  return 0;
+}
+
+
+#endif
+
+#ifdef FDLIB_USE_SELECT
+
+struct fd_waitor
+{
+  fd_FDSET storage;
+  fd_FDSET temporary;
+static long convert_filetime_to_time_t(FILETIME tmp)
+{
+  double t;
+  t=tmp.dwHighDateTime * pow(2.0,32.0) + (double)tmp.dwLowDateTime;
+  t/=10000000.0;
+  t-=11644473600.0;
+  return (long)floor(t);
+}
+
+int fd_fstat(FD fd, struct stat *s)
+{
+  DWORD x;
+  int ret;
+  FILETIME c,a,m;
+  FDDEBUG(fprintf(stderr,"fstat on %d (%d)\n",fd,da_handle[fd]));
+  if(fd_type[fd]!=FD_FILE)
+  {
+    errno=ENOTSUPP;
+    return -1;
+  }
+
+  MEMSET(s, 0, sizeof(struct stat));
+  s->st_nlink=1;
+
+  switch(fd_type[fd])
+  {
+    case FD_SOCKET:
+      s->st_mode=S_IFSOCK;
+      break;
+
+    default:
+      switch(GetFileType((HANDLE)da_handle[fd]))
+      {
+	default:
+	case FILE_TYPE_UNKNOWN: s->st_mode=0;        break;
+	case FILE_TYPE_DISK:
+	  s->st_mode=S_IFREG; 
+	  s->st_size=GetFileSize((HANDLE)da_handle[fd],&x);
+	  if(x)
+	  {
+	    s->st_size=0x7fffffff;
+	  }
+	  if(!GetFileTime((HANDLE)da_handle[fd], &c, &a, &m))
+	  {
+	    errno=GetLastError();
+	    return -1;
+	  }
+	  s->st_ctime=convert_filetime_to_time_t(c);
+	  s->st_atime=convert_filetime_to_time_t(a);
+	  s->st_mtime=convert_filetime_to_time_t(m);
+	  break;
+	case FILE_TYPE_CHAR:    s->st_mode=S_IFCHR;  break;
+	case FILE_TYPE_PIPE:    s->st_mode=S_IFFIFO; break;
+      }
+  }
+  s->st_mode |= 0666;
+  return 0;
+}
+
+int fd_select(int fds, FD_SET *a, FD_SET *b, FD_SET *c, struct timeval *t)
+{
+  int ret;
+  ret=select(fds,a,b,c,t);
+  if(ret==SOCKET_ERROR)
+  {
+    errno=WSAGetLastError();
+    return -1;
+  }
+  return ret;
+}
+
+
+int fd_ioctl(FD fd, int cmd, void *data)
+{
+  int ret;
+  switch(fd_type[fd])
+  {
+    case FD_SOCKET:
+      ret=ioctlsocket((SOCKET)da_handle[fd], cmd, data);
+      if(ret==SOCKET_ERROR)
+      {
+	errno=WSAGetLastError();
+	return -1;
+      }
+      return ret;
+
+    default:
+      errno=ENOTSUPP;
+      return -1;
+  }
+}
+
+
+FD fd_dup(FD from)
+{
+  FD fd;
+  HANDLE x,p=GetCurrentProcess();
+  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,0,DUPLICATE_SAME_ACCESS))
+  {
+    errno=GetLastError();
+    return -1;
+  }
+
+  fd=first_free_handle;
+  first_free_handle=fd_type[fd];
+  fd_type[fd]=fd_type[from];
+  da_handle[fd]=(long)x;
+  
+  FDDEBUG(fprintf(stderr,"Dup %d (%d) to %d (%d)\n",from,da_handle[from],fd,x));
+  return fd;
+}
+
+FD fd_dup2(FD from, FD to)
+{
+  HANDLE x,p=GetCurrentProcess();
+  if(!DuplicateHandle(p,(HANDLE)da_handle[from],p,&x,NULL,0,DUPLICATE_SAME_ACCESS))
+  {
+    errno=GetLastError();
+    return -1;
+  }
+
+  if(fd_type[to] < FD_NO_MORE_FREE)
+  {
+    if(!CloseHandle((HANDLE)da_handle[to]))
+    {
+      errno=GetLastError();
+      return -1;
+    }
+  }else{
+    int *prev,next;
+    for(prev=&first_free_handle;(next=*prev) != FD_NO_MORE_FREE;prev=fd_type+next)
+    {
+      if(next==to)
+      {
+	*prev=fd_type[next];
+	break;
+      }
+    }
+  }
+  fd_type[to]=fd_type[from];
+  da_handle[to]=(long)x;
+
+  FDDEBUG(fprintf(stderr,"Dup2 %d (%d) to %d (%d)\n",from,da_handle[from],to,x));
+
+  return to;
+}
+
+#endif
+
+#if 0
+
+#ifdef FD_LINEAR
+struct fd_mapper
+{
+  int size;
+  void **data;
+};
+
+void init_fd_mapper(struct fd_mapper *x)
+{
+  x->size=64;
+  x->data=(void **)xalloc(x->size*sizeof(void *));
+}
+
+void exit_fd_mapper(struct fd_mapper *x)
+{
+  free((char *)x->data);
+}
+
+void fd_mapper_set(struct fd_mapper *x, FD fd, void *data)
+{
+  while(fd>=x->size)
+  {
+    x->size*=2;
+    x->data=(void **)realloc((char *)x->data, x->size*sizeof(void *));
+    if(!x->data)
+      fatal("Out of memory.\n");
+    x->data=nd;
+  }
+  x->data[fd]=data;
+  
+}
+
+void *fd_mapper_get(struct fd_mapper *x, FD fd)
+{
+  return x->data[fd];
+}
+#else
+struct fd_mapper_data
+{
+  FD x;
+  void *data;
+};
+struct fd_mapper
+{
+  int num;
+  int hsize;
+  struct fd_mapper_data *data;
+};
+
+void init_fd_mapper(struct fd_mapper *x)
+{
+  int i;
+  x->num=0;
+  x->hsize=127;
+  x->data=(struct fd_mapper_data *)xalloc(x->hsize*sizeof(struct fd_mapper_data));
+  for(i=0;i<x->hsize;i++) x->data[i].fd=-1;
+}
+
+void exit_fd_mapper(struct fd_mapper *x)
+{
+  free((char *)x->data);
+}
+
+void fd_mapper_set(struct fd_mapper *x, FD fd, void *data)
+{
+  int hval;
+  x->num++;
+  if(x->num*2 > x->hsize)
+  {
+    struct fd_mapper_data *old=x->data;
+    int i,old_size=x->hsize;
+    x->hsize*=3;
+    x->num=0;
+    x->data=(struct fd_mapper_data *)xalloc(x->size*sizeof(struct fd_mapper_data *));
+    for(i=0;i<x->size;i++) x->data[i].fd=-1;
+    for(i=0;i<old_size;i++)
+      if(old[i].fd!=-1)
+	fd_mapper_set(x, old[i].fd, old[i].data);
+  }
+
+  hval=fd % x->hsize;
+  while(x->data[hval].fd != -1)
+  {
+    hval++;
+    if(hval==x->hsize) hval=0;
+  }
+  x->data[hval].fd=fd;
+  x->data[hval].data=data;
+}
+
+void *fd_mapper_get(struct fd_mapper *x, FD fd)
+{
+  int hval=fd % x->hsize;
+  while(x->data[hval].fd != fd)
+  {
+    hval++;
+    if(hval==x->hsize) hval=0;
+  }
+  return x->data[hval].data;
+}
+#endif
+
+
+#if 0
+struct fd_data_hash
+{
+  FD fd;
+  int key;
+  struct fd_data_hash *next;
+  void *data;
+};
+
+#define FD_DATA_PER_BLOCK 255
+
+struct fd_data_hash_block
+{
+  struct fd_data_hash_block *next;
+  struct fd_data_hash data[FD_DATA_PER_BLOCk];
+};
+
+static int keynum=0;
+static unsigned int num_stored_keys=0;
+static unsigned int hash_size=0;
+static struct fd_data_hash *free_blocks=0;
+static struct fd_data_hash **htable=0;
+static fd_data_hash_block *hash_blocks=0;
+
+int get_fd_data_key(void)
+{
+  return ++keynum;
+}
+
+void store_fd_data(FD fd, int key, void *data)
+{
+  struct fd_data_hash *p,**last;
+  unsigned int hval=(fd + key * 53) % hash_size;
+
+  for(last=htable[e];p=*last;last=&p->next)
+  {
+    if(p->fd == fd && p->key == key)
+    {
+      if(data)
+      {
+	p->data=data;
+      }else{
+	*last=p->next;
+	p->next=free_blocks;
+	free_blocks=p;
+	num_stored_keys--;
+      }
+      return;
+    }
+  }
+  if(!data) return;
+
+  num_stored_keys++;
+
+  if(num_stored_keys * 2 >= hash_size)
+  {
+    /* time to rehash */
+    unsigned int h;
+    unsigned int old_hsize=hash_size;
+    unsigned fd_data_hash **old_htable=htable;
+    if(!hash_size)
+      hash_size=127;
+    else
+      hash_size*=3;
+
+    htable=(struct fd_data_hash **)xalloc(hash_size * sizeof(struct fd_data_hash *));
+    
+    for(h=0;h<old_hsize;h++)
+    {
+      for(last=old_htable+e;p=*last;last=&p->next)
+	store_fd_data(p->fd, p->key, p->data);
+      *last=free_blocks;
+      free_blocks=old_htable[h];
+    }
+    if(old_htable)
+      free((char *)old_htable);
+  }
+
+
+  if(!free_blocks)
+  {
+    struct fd_data_hash_block *n;
+    int e;
+    n=ALLOC_STRUCT(fd_data_hash_block);
+    n->next=hash_blocks;
+    hash_blocks=n;
+    for(e=0;e<FD_DATA_PER_BLOCK;e++)
+    {
+      n->data[e].next=free_blocks;
+      free_blocks=n->data+e;
+    }
+  }
+  
+  p=free_blocks;
+  free_blocks=p->next;
+  p->fd=fd;
+  p->key=key;
+  p->data=data;
+  p->next=htable[hval];
+  htable[hval]=p;
+}
+
+void *get_fd_data(FD fd, int key)
+{
+  struct fd_data_hash *p,**last;
+  unsigned int hval=(fd + key * 53) % hash_size;
+
+  for(p=htable[hval];p;p=p->next)
+    if(p->fd == fd && p->key == key)
+      return p->data;
+
+  return 0;
+}
+
+
+#endif
+
+#define FD_EVENT_READ 1
+#define FD_EVENT_WRITE 2
+#define FD_EVENT_OOB 4
+
+struct event
+{
+  int fd;
+  int events;
+};
+
 #ifdef FDLIB_USE_SELECT
 
 struct fd_waitor
 {
-  fd_FDSET storage;
-  fd_FDSET temporary;
+  fd_FDSET rcustomers,wcustomers,xcustomers;
+  fd_FDSET rtmp,wtmp,xtmp;
   FD last;
   int numleft;
   int max;
 };
 
-#define init_waitor(X) do { (X)->numleft=0; (X)->max=0; fd_FDZERO(&X->storage); } while(0)
+#define init_waitor(X) do { (X)->numleft=0; (X)->max=0; \
+ fd_FDZERO(&X->rcustomers); \
+ fd_FDZERO(&X->wcustomers); \
+ fd_FDZERO(&X->xcustomers); \
+ } while(0)
 
-void fd_waitor_add_customer(fd_waitor *x, FD customer)
+void fd_waitor_set_customer(fd_waitor *x, FD customer, int flags)
 {
-  fd_FD_SET(& x->storage, customer);
-  if(customer>x->max) x->max=customer;
-}
+  if(flags & FD_EVENT_READ)
+  {
+    fd_FD_SET(& x->rcustomer, customer);
+  }else{
+    fd_FD_CLR(& x->rcustomer, customer);
+  }
 
-void fd_waitor_remove_customer(fd_waitor *x, FD customer)
-{
-  fd_FD_CLR(& x->storage, customer);
-  if(customer == x->max)
+  if(flags & FD_EVENT_WRITE)
+  {
+    fd_FD_SET(& x->wcustomer, customer);
+  }else{
+    fd_FD_CLR(& x->wcustomer, customer);
+  }
+
+  if(flags & FD_EVENT_OOB)
   {
-    x->max--;
-    while(!fd_ISSET(& x->storage), x->max) x->max--;
+    fd_FD_SET(& x->xcustomer, customer);
+  }else{
+    fd_FD_CLR(& x->xcustomer, customer);
   }
+
+  if(flags)
+    if(customer>x->max) x->max=customer;
+  else
+    if(customer == x->max)
+    {
+      x->max--;
+      while(
+	    !fd_ISSET(& x->rcustomers,x->max) &&
+	    !fd_ISSET(& x->wcustomers,x->max) &&
+	    !fd_ISSET(& x->xcustomers,x->max)
+	    )
+	x->max--;
+    }
 }
 
-FD fd_waitor_idle(fd_waitor *x)
+int fd_waitor_idle(fd_waitor *x,
+		  struct timeval *t,
+		  struct event *e)
 {
   int tmp;
   if(!x->numleft)
   {
-    x->temporary=x->storage;
-    tmp=select(x->max, & x->temporary, 0, 0, 0);
-    if(tmp<0) return -1;
+    x->rtmp=x->rcustomers;
+    x->wtmp=x->wcustomers;
+    x->xtmp=x->xcustomers;
+
+    tmp=select(x->max, & x->rtmp, & x->wtmp, & x->xtmp, &t);
+    if(tmp<0) return 0;
 
     x->last=0;
     x->numleft=tmp;
@@ -608,18 +1897,27 @@ FD fd_waitor_idle(fd_waitor *x)
   {
     while(x->last<x->max)
     {
-      if(fd_FD_ISSET(& x->temporary, x->last))
+      int flags=
+	(fd_FD_ISSET(& x->rtmp, x->last) ? FD_EVENT_READ : 0) |
+	(fd_FD_ISSET(& x->wtmp, x->last) ? FD_EVENT_WRITE : 0) |
+	(fd_FD_ISSET(& x->xtmp, x->last) ? FD_EVENT_OOB: 0);
+
+      if(flags)
       {
 	numleft--;
+
+	e->fd=x->last
+	e->event=flags;
 	return 1;
       }
     }
   }
+  return 0;
 }
 
 #endif
 
-#ifdef FDLIB_USE_WAITFORMULTIPLEOBJECTSEX
+#ifdef FDLIB_USE_WAITFORMULTIPLEOBJECTS
 
 #define FD_MAX 16384
 
@@ -628,22 +1926,68 @@ struct fd_waitor
   int occupied;
   HANDLE customers[FD_MAX];
   FD pos_to_fd[FD_MAX];
+  int fd_to_pos_key;
+  int last_swap;
 };
 
-void fd_waitor_add_customer(fd_waitor *x, FD customer)
+void fd_waitor_set_customer(fd_waitor *x, FD customer, int flags)
 {
   HANDLE h=CreateEvent();
-  customers[x->occupied]=h;
-  pos_to_fd[x->occupied]=customer;
+  x->customers[x->occupied]=h;
+  x->pos_to_fd[x->occupied]=customer;
+  fd_mapper_store(customer, x->fd_to_pos_key, x->occupied);
   x->occupied++;
 }
 
 void fd_waitor_remove_customer(fd_waitor *x, FD customer)
 {
-  CloseHandle(customers[x]);
+  int pos=(int)fd_mapper_get(customer, x->fd_to_pos_key);
+
+  CloseHandle(x->customers[pos]);
   
-  customers[x]=
-  pos_to_fd[x
+  fd_mapper_store(customer, x->fd_to_pos_key, (void *)0);
+  x->occupied--;
+  if(x->occupied != pos)
+  {
+    x->customer[pos]=x->customer[x->occupied];
+    x->pos_to_fd[pos]=x->pos_to_fd[x->occupied];
+    fd_mapper_store(x->pos_to_fd[pos], x->fd_to_pos_key, (void *)pos);
+  }
+}
+
+FD fd_waitor_idle(fd_waitor *x, struct timeval delay)
+{
+  DWORD ret,d=delay.tv_usec/1000;
+  d+=MINIMUM(100000,delay.tv_sec) *1000;
+
+  ret=WaitForMultipleObjects(x->occupied,
+			     x->customers,
+			     0,
+			     delay);
+
+  if(ret>= WAIT_OBJECT_0 && ret< WAIT_OBJECT_0 + x->occupied)
+  {
+    long tmp;
+    ret-=WAIT_OBJECT_0;
+    if(-- (x->last_swap) <= ret)
+    {
+      x->last_swap=x->occupied;
+      if(x->occupied == ret) return ret;
+    }
+    tmp=customers[ret];
+    customers[ret]=customers[x->last_swap];
+    customers[x->last_swap]=tmp;
+
+    tmp=pos_to_fd[ret];
+    pos_to_fd[ret]=pos_to_fd[x->last_swap];
+    pos_to_fd[x->last_swap]=tmp;
+
+    fd_mapper_store(x->pos_to_fd[ret], x->fd_to_pos_key, ret);
+    fd_mapper_store(x->pos_to_fd[x->last_swap], x->fd_to_pos_key, x->last_swap);
+    return x->pos_to_fd[ret];
+  }else{
+    return -1;
+  }
 }
 
 #endif
diff --git a/src/main.c b/src/main.c
index c4c53ef9c964c14f1aeda4a287baef2ab173a0d9..8a83f044624be5493694c6fe89c682174ee9ce71 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: main.c,v 1.29 1998/01/02 01:05:48 hubbe Exp $");
+RCSID("$Id: main.c,v 1.30 1998/01/08 17:20:07 hubbe Exp $");
 #include "fdlib.h"
 #include "backend.h"
 #include "module.h"
@@ -68,6 +68,9 @@ void main(int argc, char **argv)
   int e, num;
   char *p;
   struct array *a;
+#ifdef DECLARE_ENVIRON
+  extern char **environ;
+#endif
 
   ARGV=argv;
 
diff --git a/src/mapping.c b/src/mapping.c
index b0663a51a7fe546e9417e8c304e3ee4babaf57ed..fedde3d49623cd71d2eceebe9e87a352e391232c 100644
--- a/src/mapping.c
+++ b/src/mapping.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: mapping.c,v 1.24 1997/11/08 01:34:41 hubbe Exp $");
+RCSID("$Id: mapping.c,v 1.25 1998/01/08 17:20:07 hubbe Exp $");
 #include "main.h"
 #include "object.h"
 #include "mapping.h"
@@ -494,6 +494,15 @@ struct svalue *low_mapping_string_lookup(struct mapping *m,
   return low_mapping_lookup(m, &tmp);
 }
 
+struct svalue *simple_mapping_string_lookup(struct mapping *m,
+					    char *p)
+{
+  struct pike_string *tmp;
+  if((tmp=findstring(p)))
+    return low_mapping_string_lookup(m,tmp);
+  return 0;
+}
+
 void mapping_index_no_free(struct svalue *dest,
 			   struct mapping *m,
 			   struct svalue *key)
diff --git a/src/mapping.h b/src/mapping.h
index 5d7fce75bace51fd3baf29e6c0ee8a82e1b23ecd..4e50607b52821f7c6d2305272e97b7bd11875cdb 100644
--- a/src/mapping.h
+++ b/src/mapping.h
@@ -41,6 +41,8 @@ struct svalue *low_mapping_lookup(struct mapping *m,
 				  struct svalue *key);
 struct svalue *low_mapping_string_lookup(struct mapping *m,
 					 struct pike_string *p);
+struct svalue *simple_mapping_string_lookup(struct mapping *m,
+					    char *p);
 void mapping_index_no_free(struct svalue *dest,
 			   struct mapping *m,
 			   struct svalue *key);
diff --git a/src/modules/files/acconfig.h b/src/modules/files/acconfig.h
index d4e6e3124f8dadd60a8c825d1e387e5ba852d086..b203e40dd68ac34c7e9a66e144398cf4acc421e9 100644
--- a/src/modules/files/acconfig.h
+++ b/src/modules/files/acconfig.h
@@ -1,5 +1,5 @@
 /*
- * $Id: acconfig.h,v 1.5 1997/12/23 06:26:09 hubbe Exp $
+ * $Id: acconfig.h,v 1.6 1998/01/08 17:21:14 hubbe Exp $
  */
 
 #ifndef FILE_MACHINE_H
@@ -44,8 +44,5 @@
 /* Number of args to mkdir() */
 #define MKDIR_ARGS 2
 
-/* Can we declare 'extern char ** environ;' ? */
-#undef DECLARE_ENVIRON
-
 #endif
 
diff --git a/src/modules/files/configure.in b/src/modules/files/configure.in
index eb6d1352056eedb996295a64cee065177a746b3e..3f5e9a02aec5de0c44b47e21ea3e25a08a933556 100644
--- a/src/modules/files/configure.in
+++ b/src/modules/files/configure.in
@@ -11,22 +11,7 @@ AC_HEADER_DIRENT
 AC_CHECK_LIB(bind, __inet_ntoa)
 AC_CHECK_LIB(socket, socket)
 
-AC_HAVE_FUNCS(getwd perror fork1 readdir_r statvfs statfs ustat fork lstat)
-
-AC_MSG_CHECKING(if we can declare environ)
-AC_CACHE_VAL(pike_cv_declare_environ,[
-AC_TRY_COMPILE([
-#include <stdlib.h>
-],[
-  extern char **environ;
-  exit(0);
-],pike_cv_declare_environ=yes,pike_cv_declare_environ=no)
-])
-
-AC_MSG_RESULT($pike_cv_declare_environ)
-if test "x$pike_cv_declare_environ" = xyes ; then
-  AC_DEFINE(DECLARE_ENVIRON)
-fi
+AC_HAVE_FUNCS(getwd perror readdir_r statvfs statfs ustat lstat)
 
 AC_MSG_CHECKING(if mkdir takes 1 or 2 arguments)
 AC_CACHE_VAL(pike_cv_func_mkdir_args,[
diff --git a/src/modules/files/efuns.c b/src/modules/files/efuns.c
index 7a1cfba574149b082d723b204010362043d0a3f2..fdb99d8b7ad2fb954324f5dcba85fd201caac8b0 100644
--- a/src/modules/files/efuns.c
+++ b/src/modules/files/efuns.c
@@ -563,40 +563,15 @@ void f_getcwd(INT32 args)
   free(e);
 }
 
-#ifdef HAVE_FORK
-void f_fork(INT32 args)
-{
-  int res;
-  do_set_close_on_exec();
-  pop_n_elems(args);
-#if defined(HAVE_FORK1) && defined(_REENTRANT)
-  push_int(res=fork1());
-#else
-  push_int(res=fork());
-#endif
-  if(!res && res!=-1)
-  {
-    call_callback(&fork_child_callback, 0);
-  }
-#if defined(_REENTRANT)
-  if(!res)
-  {
-    /* forked copy. there is now only one thread running, this one. */
-    num_threads=1;
-  }
-#endif
-}
-#endif
-
 void f_exece(INT32 args)
 {
   INT32 e;
   char **argv, **env;
+  struct svalue *save_sp;
+  struct mapping *en;
 #ifdef DECLARE_ENVIRON
   extern char **environ;
 #endif
-  struct svalue *save_sp;
-  struct mapping *en;
 
   save_sp=sp-args;
 
@@ -750,9 +725,6 @@ void init_files_efuns(void)
   add_efun("get_dir",f_get_dir,"function(string:string *)",OPT_EXTERNAL_DEPEND);
   add_efun("cd",f_cd,"function(string:int)",OPT_SIDE_EFFECT);
   add_efun("getcwd",f_getcwd,"function(:string)",OPT_EXTERNAL_DEPEND);
-#ifdef HAVE_FORK
-  add_efun("fork",f_fork,"function(:int)",OPT_SIDE_EFFECT);
-#endif
   add_efun("exece",f_exece,"function(string,mixed*,void|mapping(string:string):int)",OPT_SIDE_EFFECT); 
 
 #ifdef HAVE_STRERROR
diff --git a/src/modules/files/file.c b/src/modules/files/file.c
index 9daad37195613623cba995b831c5f3bd7d0657d3..ee5a71cf261f8344d333dbc27c379a0b2bbdf605 100644
--- a/src/modules/files/file.c
+++ b/src/modules/files/file.c
@@ -6,7 +6,7 @@
 #define READ_BUFFER 8192
 
 #include "global.h"
-RCSID("$Id: file.c,v 1.64 1998/01/03 07:13:05 hubbe Exp $");
+RCSID("$Id: file.c,v 1.65 1998/01/08 17:21:16 hubbe Exp $");
 #include "fdlib.h"
 #include "interpret.h"
 #include "svalue.h"
@@ -1261,7 +1261,7 @@ static void file_dup2(INT32 args)
    * /precompiled/file
    */
   if(!o->prog || o->prog->inherits[0].prog != file_program)
-    error("Argument 1 to file->assign() must be a clone of Stdio.File\n");
+    error("Argument 1 to file->dup2() must be a clone of Stdio.File\n");
 
   fd=((struct file_struct *)(o->storage))->fd;
 
diff --git a/src/modules/files/testsuite.in b/src/modules/files/testsuite.in
index 03dec921ca44f185c3ff91d51a13131e7da30470..890210ffb1315ff20146a15a2727b84f3a044f3b 100644
--- a/src/modules/files/testsuite.in
+++ b/src/modules/files/testsuite.in
@@ -69,7 +69,7 @@ test_any([[object o=clone(Stdio.File); o->open("conftest","r"); o=o->dup(); retu
 est_any([[object o=clone(Stdio.File),o2=clone(Stdio.File); o->open("conftest","r"); o2->assign(o); return o2->read(100)]] ,sprintf("%'+-*'100s",""))
 
 // - file->dup2
-test_any([[object o=clone(Stdio.File),o2=clone(Stdio.File); o2->pipe(); o->open("conftest","r"); o2->dup2(o); return o2->read(100)]] ,sprintf("%'+-*'100s",""))
+test_any([[object o=clone(Stdio.File),o2=clone(Stdio.File); o2->pipe(); o->open("conftest","r"); o->dup2(o2); return o2->read(100)]] ,sprintf("%'+-*'100s",""))
 
 test_eq(Process.popen("echo foo"),"foo\n")
 
diff --git a/src/signal_handler.c b/src/signal_handler.c
index a3a4a801d14a9c7a8cf6d32469f7937b9409b78f..6281ccdb07ddbaae5809cafc16ad38ca5c42939a 100644
--- a/src/signal_handler.c
+++ b/src/signal_handler.c
@@ -4,6 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
+#include "fdlib.h"
 #include "svalue.h"
 #include "interpret.h"
 #include "stralloc.h"
@@ -12,7 +13,16 @@
 #include "backend.h"
 #include "error.h"
 #include "callback.h"
+#include "mapping.h"
+#include "threads.h"
+#include "signal_handler.h"
+#include "module_support.h"
 #include <signal.h>
+
+#ifdef HAVE_WINBASE_H
+#include <winbase.h>
+#endif
+
 #ifdef HAVE_SYS_WAIT_H
 #include <sys/wait.h>
 #endif
@@ -35,6 +45,7 @@
 #endif
 
 #define SIGNAL_BUFFER 16384
+#define WAIT_BUFFER 4096
 
 static struct svalue signal_callbacks[MAX_SIGNALS];
 
@@ -42,6 +53,16 @@ static unsigned char sigbuf[SIGNAL_BUFFER];
 static int firstsig, lastsig;
 static struct callback *signal_evaluator_callback =0;
 
+#ifndef __NT__
+struct wait_data {
+  pid_t pid;
+  int status;
+};
+
+static struct wait_data wait_buf[WAIT_BUFFER];
+static int firstwait=0, lastwait=0;
+
+#endif /* ! NT */
 
 struct sigdesc
 {
@@ -205,52 +226,560 @@ static void my_signal(int sig, sigfunctype fun)
 #endif
 }
 
-static RETSIGTYPE sig_child(int arg)
+static RETSIGTYPE receive_signal(int signum)
 {
-  /* We carefully reap what we saw */
+  int tmp;
+
+  tmp=firstsig+1;
+  if(tmp == SIGNAL_BUFFER) tmp=0;
+  if(tmp != lastsig)
+  {
+    sigbuf[tmp]=signum;
+    firstsig=tmp;
+  }
+
+#ifndef __NT__
+  if(signum==SIGCHLD)
+  {
+    pid_t pid;
+    int status;
+    /* We carefully reap what we saw */
 #ifdef HAVE_WAITPID
-  while(waitpid(-1,0,WNOHANG) > 0); 
+    pid=waitpid(-1,& status,WNOHANG);
 #else
 #ifdef HAVE_WAIT3
-  while( wait3(0,WNOHANG,0) > 0);
+    pid=wait3(&status,WNOHANG,0);
 #else
 #ifdef HAVE_WAIT4
-  while( wait4(-1,0,WNOHANG,0) > 0);
+    pid=wait4(-1,&status,WNOHANG,0);
 #else
+    pid=-1;
+#endif
+#endif
+#endif
+    if(pid>0)
+    {
+      int tmp2=firstwait+1;
+      if(tmp2 == WAIT_BUFFER) tmp=0;
+      if(tmp2 != lastwait)
+      {
+	wait_buf[tmp2].pid=pid;
+	wait_buf[tmp2].status=status;
+	firstwait=tmp2;
+      }
+    }
+  }
+#endif
+
+  wake_up_backend();
+
+#ifndef SIGNAL_ONESHOT
+  my_signal(signum, receive_signal);
+#endif
+}
 
-  /* Leave'em hanging */
+#define PROCESS_UNKNOWN -1
+#define PROCESS_RUNNING 0
+#define PROCESS_EXITED 2
 
-#endif /* HAVE_WAIT4 */
-#endif /* HAVE_WAIT3 */
-#endif /* HAVE_WAITPID */
+#undef THIS
+#define THIS ((struct pid_status *)fp->current_storage)
 
-#ifdef SIGNAL_ONESHOT
-#ifdef SIGCHLD
-  my_signal(SIGCHLD, sig_child);
+struct pid_status
+{
+  int pid;
+#ifdef __NT__
+  HANDLE handle;
+#else
+  int state;
+  int result;
+#endif
+};
+
+#ifndef __NT__
+static struct mapping *pid_mapping=0;
 #endif
+static struct program *pid_status_program=0;
+
+
+static void init_pid_status(struct object *o)
+{
+  THIS->pid=-1;
+#ifdef __NT__
+  THIS->handle=INVALID_HANDLE_VALUE;
+#else
+  THIS->state=PROCESS_UNKNOWN;
+  THIS->result=-1;
 #endif
 }
 
-static RETSIGTYPE receive_signal(int signum)
+static void exit_pid_status(struct object *o)
 {
-  int tmp;
+#ifndef __NT__
+  if(pid_mapping)
+  {
+    struct svalue key;
+    key.type=T_INT;
+    key.u.integer=THIS->pid;
+    map_delete(pid_mapping, &key);
+  }
+#else
+  CloseHandle(THIS->handle);
+#endif
+}
 
-  tmp=firstsig+1;
-  if(tmp == SIGNAL_BUFFER) tmp=0;
-  if(tmp != lastsig)
-    sigbuf[firstsig=tmp]=signum;
+#ifndef __NT__
+static void report_child(int pid,
+			 int status)
+{
+/*  fprintf(stderr,"pid %d exited with status %d\n",pid,status); */
 
-#ifdef SIGCHLD
-  if(signum==SIGCHLD) sig_child(signum);
+  if(pid_mapping)
+  {
+    struct svalue *s, key;
+    key.type=T_INT;
+    key.u.integer=pid;
+    if((s=low_mapping_lookup(pid_mapping, &key)))
+    {
+      if(s->type == T_OBJECT)
+      {
+	struct pid_status *p;
+	if((p=(struct pid_status *)get_storage(s->u.object,
+					       pid_status_program)))
+	{
+	  p->state = PROCESS_EXITED;
+	  p->result = WEXITSTATUS(status);
+	}
+      }
+      map_delete(pid_mapping, &key);
+    }
+  }
+}
 #endif
 
-  wake_up_backend();
+static void f_pid_status_wait(INT32 args)
+{
+  pop_n_elems(args);
+  if(THIS->pid == -1)
+    error("This process object has no process associated with it.\n");
+#ifdef __NT__
+  {
+    int err=0;
+    DWORD xcode;
+    HANDLE h=THIS->handle;
+    THREADS_ALLOW();
+    while(1)
+    {
+      if(GetExitCodeProcess(h, &xcode))
+      {
+	if(xcode == STILL_ACTIVE)
+	{
+	  WaitForSingleObject(h, INFINITE);
+	}else{
+	  break;
+	}
+      }else{
+	err=1;
+	break;
+      }
+    }
+    THREADS_DISALLOW();
+    if(err)
+      error("Failed to get status of process.\n");
+    push_int(xcode);
+  }
+#else
 
-#ifndef SIGNAL_ONESHOT
-  my_signal(signum, receive_signal);
+#if 1
+  while(THIS->state == PROCESS_RUNNING)
+  {
+    int pid, status;
+    pid=THIS->pid;
+    THREADS_ALLOW();
+#ifdef HAVE_WAITPID
+    pid=waitpid(pid,& status,0);
+#else
+#ifdef HAVE_WAIT4
+    pid=wait4(pid,&status,0,0);
+#else
+    pid=-1;
 #endif
+#endif
+    THREADS_DISALLOW();
+    if(pid >= -1)
+      report_child(pid, status);
+    check_signals(0,0,0);
+  }
+#else
+  init_signal_wait();
+  while(THIS->state == PROCESS_RUNNING)
+  {
+    wait_for_signal();
+    check_threads_etc();
+  }
+  exit_signal_wait();
+#endif
+  push_int(THIS->result);
+#endif /* __NT__ */
 }
 
+static void f_pid_status_status(INT32 args)
+{
+  pop_n_elems(args);
+#ifdef __NT__
+  {
+    DWORD x;
+    if(GetExitCodeProcess(THIS->handle, &x))
+    {
+      push_int( x == STILL_ACTIVE ? PROCESS_RUNNING : PROCESS_EXITED);
+    }else{
+      push_int(PROCESS_UNKNOWN);
+    }
+  }
+#else
+  push_int(THIS->state);
+#endif
+}
+
+static void f_pid_status_pid(INT32 args)
+{
+  pop_n_elems(args);
+  push_int(THIS->pid);
+}
+
+#ifdef __NT__
+static TCHAR *convert_string(char *str, int len)
+{
+  int e;
+  TCHAR *ret=(TCHAR *)xalloc((len+1) * sizeof(TCHAR));
+  for(e=0;e<len;e++) ret[e]=EXTRACT_UCHAR(str+e);
+  ret[e]=0;
+  return ret;
+}
+
+static HANDLE get_inheritable_handle(struct mapping *optional, char *name)
+{
+  HANDLE ret=INVALID_HANDLE_VALUE;
+  struct svalue *tmp;
+  if((tmp=simple_mapping_string_lookup(optional, name)))
+  {
+    if(tmp->type == T_OBJECT)
+    {
+      apply(tmp->u.object,"query_fd",0);
+      if(sp[-1].type == T_INT)
+      {
+	DuplicateHandle(GetCurrentProcess(),
+			(HANDLE)da_handle[sp[-1].u.integer],
+			GetCurrentProcess(),
+			&ret,
+			NULL,
+			1,
+			0);
+      }
+    }
+  }
+  return ret;
+}
+#endif
+
+/*
+ * create_process(string *arguments, mapping optional_data);
+ */
+void f_create_process(INT32 args)
+{
+  struct array *cmd=0;
+  struct mapping *optional=0;
+  struct svalue *tmp;
+  int e;
+
+  if(!args) return;
+
+  check_all_args("create_process",args, BIT_ARRAY, BIT_MAPPING | BIT_VOID, 0);
+
+  switch(args)
+  {
+    default:
+      optional=sp[1-args].u.mapping;
+      mapping_fix_type_field(optional);
+
+      if(m_ind_types(optional) & ~BIT_STRING)
+	error("Bad index type in argument 2 to Process->create()\n");
+
+    case 1: cmd=sp[-args].u.array;
+      if(cmd->size < 1)
+	error("Too few elements in argument array.\n");
+      
+      for(e=0;e<cmd->size;e++)
+	if(ITEM(cmd)[e].type!=T_STRING)
+	  error("Argument is not a string.\n");
+
+      array_fix_type_field(cmd);
+
+      if(cmd->type_field & ~BIT_STRING)
+	error("Bad argument 1 to Process().\n");
+  }
+
+
+#ifdef __NT__
+  {
+    HANDLE t1=INVALID_HANDLE_VALUE;
+    HANDLE t2=INVALID_HANDLE_VALUE;
+    HANDLE t3=INVALID_HANDLE_VALUE;
+    STARTUPINFO info;
+    PROCESS_INFORMATION proc;
+    int ret;
+    TCHAR *filename=NULL, *command_line=NULL, *dir=NULL;
+    struct pike_string *p1,*p2;
+
+
+    /* FIX QUOTING LATER */
+    p1=make_shared_string(" ");
+    p2=implode(cmd, p1);
+    command_line=convert_string(p2->str, p2->len);
+    free_string(p1);
+    free_string(p2);
+    
+    GetStartupInfo(&info);
+
+    info.dwFlags|=STARTF_USESTDHANDLES;
+    info.hStdInput=GetStdHandle(STD_INPUT_HANDLE);
+    info.hStdOutput=GetStdHandle(STD_OUTPUT_HANDLE);
+    info.hStdError=GetStdHandle(STD_ERROR_HANDLE);
+
+    if(optional)
+    {
+      if(tmp=simple_mapping_string_lookup(optional, "cwd"))
+	if(tmp->type == T_STRING)
+	  dir=convert_string(tmp->u.string->str, tmp->u.string->len);
+
+      t1=get_inheritable_handle(optional, "stdin");
+      if(t1!=INVALID_HANDLE_VALUE) info.hStdInput=t1;
+
+      t2=get_inheritable_handle(optional, "stdout");
+      if(t1!=INVALID_HANDLE_VALUE) info.hStdOutput=t2;
+
+      t3=get_inheritable_handle(optional, "stdout");
+      if(t1!=INVALID_HANDLE_VALUE) info.hStdError=t3;
+
+      /* FIX: env, cleanup */
+    }
+
+    THREADS_ALLOW();
+    ret=CreateProcess(filename,
+		      command_line,
+		      NULL,  /* process security attribute */
+		      NULL,  /* thread security attribute */
+		      1,     /* inherithandles */
+		      0,     /* create flags */
+		      NULL,  /* environment */
+		      dir,   /* current dir */
+		      &info,
+		      &proc);
+    THREADS_DISALLOW();
+    
+    if(dir) free((char *)dir);
+    if(command_line) free((char *)command_line);
+    if(filename) free((char *)filename);
+    if(t1!=INVALID_HANDLE_VALUE) CloseHandle(t1);
+    if(t2!=INVALID_HANDLE_VALUE) CloseHandle(t2);
+    if(t3!=INVALID_HANDLE_VALUE) CloseHandle(t3);
+    
+    if(ret)
+    {
+      CloseHandle(proc.hThread);
+      THIS->handle=proc.hProcess;
+      THIS->pid=proc.dwProcessId;
+    }else{
+      error("Failed to start process (%d).\n",GetLastError());
+    }
+  }
+#else /* __NT__ */
+  {
+    pid_t pid;
+#if defined(HAVE_FORK1) && defined(_REENTRANT)
+    pid=fork1();
+#else
+    pid=fork();
+#endif
+    if(pid==-1) error("Failed to start process.\n");
+    if(pid)
+    {
+      if(!signal_evaluator_callback)
+      {
+	signal_evaluator_callback=add_to_callback(&evaluator_callbacks,
+						  check_signals,
+						  0,0);
+      }
+      THIS->pid=pid;
+      THIS->state=PROCESS_RUNNING;
+      ref_push_object(fp->current_object);
+      push_int(pid);
+      mapping_insert(pid_mapping,sp-1, sp-2);
+      pop_n_elems(2);
+    }else{
+      char **argv;
+#ifdef DECLARE_ENVIRON
+      extern char **environ;
+#endif
+      extern void my_set_close_on_exec(int,int);
+      extern void do_set_close_on_exec(void);
+
+#ifdef _REENTRANT
+      /* forked copy. there is now only one thread running, this one. */
+      num_threads=1;
+#endif
+      call_callback(&fork_child_callback, 0);
+      
+      
+      argv=(char **)xalloc((1+cmd->size) * sizeof(char *));
+      
+      for(e=0;e<cmd->size;e++)
+	argv[e]=ITEM(cmd)[e].u.string->str;
+      
+      argv[e]=0;
+      
+      if(optional)
+      {
+	int toclose[3];
+	int fd;
+
+	if((tmp=simple_mapping_string_lookup(optional, "cwd")))
+	  if(tmp->type == T_STRING)
+	    if(!chdir(tmp->u.string->str))
+	      exit(69);
+
+	for(fd=0;fd<3;fd++)
+	{
+	  char *fdname;
+	  switch(fd)
+	  {
+	    case 0: fdname="stdin"; break;
+	    case 1: fdname="stdout"; break;
+	    default: fdname="stderr"; break;
+	  }
+	  
+	  if((tmp=simple_mapping_string_lookup(optional, fdname)))
+	  {
+	    if(tmp->type == T_OBJECT)
+	    {
+	      apply(tmp->u.object,"query_fd",0);
+	      if(sp[-1].type == T_INT)
+		dup2(toclose[fd]=sp[-1].u.integer, fd);
+	    }
+	  }
+	}
+
+	for(fd=0;fd<3;fd++)
+	{
+	  int f2;
+	  if(toclose[fd]<0) continue;
+
+	  for(f2=0;f2<fd;f2++)
+	    if(toclose[fd]==toclose[f2])
+	      break;
+
+	  if(f2 == fd)
+	    close(toclose[fd]);
+	}
+	
+	/* Left to do: env, cleanup */
+      }
+      
+      
+      my_set_close_on_exec(0,0);
+      my_set_close_on_exec(1,0);
+      my_set_close_on_exec(2,0);
+      do_set_close_on_exec();
+      
+      execvp(argv[0],argv);
+      exit(69);
+    }
+  }
+#endif /* __NT__ */
+  pop_n_elems(args);
+  push_int(0);
+}
+
+#ifdef HAVE_FORK
+void f_fork(INT32 args)
+{
+  struct object *o;
+  pid_t pid;
+  pop_n_elems(args);
+#if defined(HAVE_FORK1) && defined(_REENTRANT)
+  pid=fork1();
+#else
+  pid=fork();
+#endif
+  if(pid==-1) error("Fork failed\n");
+
+  if(pid)
+  {
+    struct pid_status *p;
+    if(!signal_evaluator_callback)
+    {
+      signal_evaluator_callback=add_to_callback(&evaluator_callbacks,
+						check_signals,
+						0,0);
+    }
+    o=clone_object(pid_status_program,0);
+    p=(struct pid_status *)get_storage(o,pid_status_program);
+    p->pid=pid;
+    p->state=PROCESS_RUNNING;
+    push_object(o);
+    push_int(pid);
+    mapping_insert(pid_mapping,sp-1, sp-2);
+    pop_stack();
+  }else{
+#ifdef _REENTRANT
+    /* forked copy. there is now only one thread running, this one. */
+    num_threads=1;
+#endif
+    call_callback(&fork_child_callback, 0);
+    push_int(0);
+  }
+}
+#endif /* HAVE_FORK */
+
+
+#ifdef HAVE_KILL
+static void f_kill(INT32 args)
+{
+  pid_t pid;
+  if(args < 2)
+    error("Too few arguments to kill().\n");
+  switch(sp[-args].type)
+  {
+  case T_INT:
+    pid=sp[-args].u.integer;
+    break;
+
+  case T_OBJECT:
+  {
+    struct pid_status *p;
+    if((p=(struct pid_status *)get_storage(sp[-args].u.object,
+					  pid_status_program)))
+    {
+      pid=p->pid;
+      break;
+    }
+  }
+  default:
+    error("Bad argument 1 to kill().\n");
+  }
+    
+  if(sp[-args].type != T_INT)
+  if(sp[1-args].type != T_INT)
+    error("Bad argument 1 to kill().\n");
+
+  sp[-args].u.integer=!kill(sp[-args].u.integer,sp[1-args].u.integer);
+  check_signals(0,0,0);
+  pop_n_elems(args-1);
+}
+
+#endif
+
+
 static int signalling=0;
 
 static void unset_signalling(void *notused) { signalling=0; }
@@ -353,7 +882,7 @@ static void f_signal(int args)
     {
 #ifdef SIGCHLD
     case SIGCHLD:
-      func=sig_child;
+      func=receive_signal;
       break;
 #endif
 
@@ -410,20 +939,6 @@ static void f_signame(int args)
     push_int(0);
 }
 
-#ifdef HAVE_KILL
-static void f_kill(INT32 args)
-{
-  if(args < 2)
-    error("Too few arguments to kill().\n");
-  if(sp[-args].type != T_INT)
-    error("Bad argument 1 to kill().\n");
-  if(sp[1-args].type != T_INT)
-    error("Bad argument 1 to kill().\n");
-
-  sp[-args].u.integer=!kill(sp[-args].u.integer,sp[1-args].u.integer);
-  pop_n_elems(args-1);
-}
-#endif
 
 static void f_getpid(INT32 args)
 {
@@ -476,7 +991,7 @@ void init_signals(void)
   int e;
 
 #ifdef SIGCHLD
-  my_signal(SIGCHLD, sig_child);
+  my_signal(SIGCHLD, receive_signal);
 #endif
 
 #ifdef SIGPIPE
@@ -488,10 +1003,29 @@ void init_signals(void)
 
   firstsig=lastsig=0;
 
+#ifndef __NT__
+  pid_mapping=allocate_mapping(2);
+#endif
+
+  start_new_program();
+  add_storage(sizeof(struct pid_status));
+  set_init_callback(init_pid_status);
+  set_exit_callback(exit_pid_status);
+  add_function("wait",f_pid_status_wait,"function(:int)",0);
+  add_function("status",f_pid_status_status,"function(:int)",0);
+  add_function("pid",f_pid_status_pid,"function(:int)",0);
+  add_function("create",f_create_process,"function(array(string),void|mapping(string:mixed):object)",0);
+  pid_status_program=end_program();
+  add_program_constant("create_process",pid_status_program,0);
+
   add_efun("signal",f_signal,"function(int,mixed|void:void)",OPT_SIDE_EFFECT);
 #ifdef HAVE_KILL
-  add_efun("kill",f_kill,"function(int,int:int)",OPT_SIDE_EFFECT);
+  add_efun("kill",f_kill,"function(int|object,int:int)",OPT_SIDE_EFFECT);
 #endif
+#ifdef HAVE_FORK
+  add_efun("fork",f_fork,"function(void:object)",OPT_SIDE_EFFECT);
+#endif
+
   add_efun("signame",f_signame,"function(int:string)",0);
   add_efun("signum",f_signum,"function(string:int)",0);
   add_efun("getpid",f_getpid,"function(:int)",0);
@@ -506,6 +1040,20 @@ void init_signals(void)
 void exit_signals(void)
 {
   int e;
+#ifndef __NT__
+  if(pid_mapping)
+  {
+    free_mapping(pid_mapping);
+    pid_mapping=0;
+  }
+#endif
+  if(pid_status_program)
+  {
+    free_program(pid_status_program);
+    pid_status_program=0;
+  }
+
+
   for(e=0;e<MAX_SIGNALS;e++)
   {
     free_svalue(signal_callbacks+e);
diff --git a/src/signal_handler.h b/src/signal_handler.h
index 9a83975b45f1e42c129940c742c4529ac44135a5..4436a1ecc5e9547bd0d030f2b9d93b70148b9afb 100644
--- a/src/signal_handler.h
+++ b/src/signal_handler.h
@@ -7,7 +7,11 @@
 #define SIGNAL_H
 
 /* Prototypes begin here */
+struct wait_data;
 struct sigdesc;
+struct pid_status;
+void f_create_process(INT32 args);
+void f_fork(INT32 args);
 void check_signals(struct callback *foo, void *bar, void *gazonk);
 void init_signals(void);
 void exit_signals(void);
diff --git a/src/stralloc.c b/src/stralloc.c
index 5f4c51d6996ccc1b3bdd3bb590afb6d26843299b..68a80f4517e600b450b62a76c17a651308696ee1 100644
--- a/src/stralloc.c
+++ b/src/stralloc.c
@@ -576,7 +576,7 @@ struct pike_string *string_replace(struct pike_string *str,
 /*** init/exit memory ***/
 void init_shared_string_table(void)
 {
-  for(hashprimes_entry;hashprimes[hashprimes_entry]<BEGIN_HASH_SIZE;hashprimes_entry++);
+  for(hashprimes_entry=0;hashprimes[hashprimes_entry]<BEGIN_HASH_SIZE;hashprimes_entry++);
   htable_size=hashprimes[hashprimes_entry];
   base_table=(struct pike_string **)xalloc(sizeof(struct pike_string *)*htable_size);
   MEMSET((char *)base_table,0,sizeof(struct pike_string *)*htable_size);