From 57408873103c51aca8fa374aa9261b70f7afccf0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net>
Date: Thu, 1 Jan 1998 17:06:47 -0800
Subject: [PATCH] lots of updates for NT, threads and new cpp

Rev: src/ChangeLog:1.128
Rev: src/Makefile.in:1.49
Rev: src/backend.c:1.20
Rev: src/configure.in:1.145
Rev: src/cpp.c:1.2
Rev: src/cpp.h:1.2
Rev: src/fd_control.c:1.11
Rev: src/fdlib.c:1.1
Rev: src/fdlib.h:1.1
Rev: src/fsort.c:1.3
Rev: src/fsort_template.h:1.2
Rev: src/lex.c:1.36
Rev: src/lex.h:1.6
Rev: src/main.c:1.29
Rev: src/modules/files/file.c:1.63
Rev: src/modules/files/socket.c:1.20
Rev: src/modules/readline/readlinemod.c:1.4
Rev: src/object.c:1.30
Rev: src/object.h:1.12
Rev: src/port.c:1.13
Rev: src/program.c:1.47
Rev: src/program.h:1.23
Rev: src/stuff.c:1.4
Rev: src/stuff.h:1.4
Rev: src/threads.c:1.48
Rev: src/threads.h:1.22
Rev: src/time_stuff.h:1.5
---
 src/ChangeLog                      |    5 +
 src/Makefile.in                    |    2 +
 src/backend.c                      |   77 +-
 src/configure.in                   |    8 +-
 src/cpp.c                          | 1952 ++++++++++++++++++++++++++++
 src/cpp.h                          |   26 +
 src/fd_control.c                   |   10 +-
 src/fdlib.c                        |  355 +++++
 src/fdlib.h                        |  157 +++
 src/fsort.c                        |    2 +-
 src/fsort_template.h               |    2 +-
 src/lex.c                          |   16 +-
 src/lex.h                          |    4 -
 src/main.c                         |   33 +-
 src/modules/files/file.c           |   89 +-
 src/modules/files/socket.c         |   23 +-
 src/modules/readline/readlinemod.c |   10 +
 src/object.c                       |    8 +-
 src/object.h                       |    3 +
 src/port.c                         |   18 +
 src/program.c                      |   18 +-
 src/program.h                      |    3 +
 src/stuff.c                        |   11 +
 src/stuff.h                        |    1 +
 src/threads.c                      |   51 +-
 src/threads.h                      |   10 +-
 src/time_stuff.h                   |    1 -
 27 files changed, 2772 insertions(+), 123 deletions(-)
 create mode 100644 src/cpp.c
 create mode 100644 src/cpp.h
 create mode 100644 src/fdlib.c
 create mode 100644 src/fdlib.h

diff --git a/src/ChangeLog b/src/ChangeLog
index f081de6846..7bcfe69890 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+Thu Jan  1 16:56:09 1998  Fredrik Hubinette  <hubbe@cytocin.hubbe.net>
+
+	* threads.c: new methods added: wait and status
+	* cpp.c: new file
+
 Mon Dec 22 09:33:59 1997  Fredrik Hubinette  <hubbe@cytocin.hubbe.net>
 
 	* version.c: version now includes release number
diff --git a/src/Makefile.in b/src/Makefile.in
index 5c0c23fe70..630257312e 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -76,6 +76,8 @@ MAKE_FLAGS = $(MOST_MAKE_FLAGS) "OTHERFLAGS=$(OTHERFLAGS)"
 OBJ= \
  language.o \
  constants.o \
+ cpp.o \
+ fdlib.o \
  cyclic.o \
  array.o \
  backend.o \
diff --git a/src/backend.c b/src/backend.c
index 400641493a..e0d8b7ce84 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -4,7 +4,8 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: backend.c,v 1.19 1997/12/23 06:26:04 hubbe Exp $");
+RCSID("$Id: backend.c,v 1.20 1998/01/02 01:05:41 hubbe Exp $");
+#include "fdlib.h"
 #include "backend.h"
 #include <errno.h>
 #ifdef HAVE_SYS_TYPES_H
@@ -21,6 +22,7 @@ RCSID("$Id: backend.c,v 1.19 1997/12/23 06:26:04 hubbe Exp $");
 #include "main.h"
 #include "callback.h"
 #include "threads.h"
+#include "fdlib.h"
 
 #ifdef HAVE_SYS_SELECT_H
 #include <sys/select.h>
@@ -62,7 +64,7 @@ struct callback *add_backend_callback(callback_func call,
 static void wakeup_callback(int fd, void *foo)
 {
   char buffer[1024];
-  read(fd, buffer, sizeof(buffer)); /* Clear 'flag' */
+  fd_read(fd, buffer, sizeof(buffer)); /* Clear 'flag' */
 }
 
 /* This is used by threaded programs and signals to wake up the
@@ -72,17 +74,17 @@ void wake_up_backend(void)
 {
   char foo=0;
   if(may_need_wakeup)
-    write(wakeup_pipe[1], &foo ,1);
+    fd_write(wakeup_pipe[1], &foo ,1);
 }
 
 extern int pike_make_pipe(int *);
 
 void init_backend(void)
 {
-  FD_ZERO(&selectors.read);
-  FD_ZERO(&selectors.write);
+  fd_FD_ZERO(&selectors.read);
+  fd_FD_ZERO(&selectors.write);
   if(pike_make_pipe(wakeup_pipe) < 0)
-    fatal("Couldn't create backend wakup pipe, errno=%d.\n",errno);
+    fatal("Couldn't create backend wakup pipe! errno=%d.\n",errno);
   set_nonblocking(wakeup_pipe[0],1);
   set_nonblocking(wakeup_pipe[1],1);
   set_read_callback(wakeup_pipe[0], wakeup_callback, 0); 
@@ -103,18 +105,18 @@ void set_read_callback(int fd,file_callback cb,void *data)
 
   if(cb)
   {
-    FD_SET(fd, &selectors.read);
+    fd_FD_SET(fd, &selectors.read);
     if(max_fd < fd) max_fd = fd;
     wake_up_backend();
   }else{
     if(fd <= max_fd)
     {
-      FD_CLR(fd, &selectors.read);
+      fd_FD_CLR(fd, &selectors.read);
       if(fd == max_fd)
       {
 	while(max_fd >=0 &&
-	      !FD_ISSET(max_fd, &selectors.read) &&
-	      !FD_ISSET(max_fd, &selectors.write))
+	      !fd_FD_ISSET(max_fd, &selectors.read) &&
+	      !fd_FD_ISSET(max_fd, &selectors.write))
 	  max_fd--;
       }
     }
@@ -133,18 +135,18 @@ void set_write_callback(int fd,file_callback cb,void *data)
 
   if(cb)
   {
-    FD_SET(fd, &selectors.write);
+    fd_FD_SET(fd, &selectors.write);
     if(max_fd < fd) max_fd = fd;
     wake_up_backend();
   }else{
     if(fd <= max_fd)
     {
-      FD_CLR(fd, &selectors.write);
+      fd_FD_CLR(fd, &selectors.write);
       if(fd == max_fd)
       {
 	while(max_fd >=0 &&
-	      !FD_ISSET(max_fd, &selectors.read) &&
-	      !FD_ISSET(max_fd, &selectors.write))
+	      !fd_FD_ISSET(max_fd, &selectors.read) &&
+	      !fd_FD_ISSET(max_fd, &selectors.write))
 	  max_fd--;
       }
     }
@@ -217,11 +219,11 @@ void do_debug(void)
 
   for(e=0;e<=max_fd;e++)
   {
-    if(FD_ISSET(e,&selectors.read) || FD_ISSET(e,&selectors.write))
+    if(fd_FD_ISSET(e,&selectors.read) || fd_FD_ISSET(e,&selectors.write))
     {
       int ret;
       do {
-	ret=fstat(e, &tmp);
+	ret=fd_fstat(e, &tmp);
       }while(ret < 0 && errno == EINTR);
 
       if(ret<0)
@@ -286,7 +288,7 @@ void backend(void)
     }
 
     THREADS_ALLOW();
-    i=select(max_fd+1, &sets.read, &sets.write, 0, &next_timeout);
+    i=fd_select(max_fd+1, &sets.read, &sets.write, 0, &next_timeout);
     GETTIMEOFDAY(&current_time);
     THREADS_DISALLOW();
     may_need_wakeup=0;
@@ -295,10 +297,10 @@ void backend(void)
     {
       for(i=0; i<max_fd+1; i++)
       {
-	if(FD_ISSET(i, &sets.read) && read_callback[i])
+	if(fd_FD_ISSET(i, &sets.read) && read_callback[i])
 	  (*(read_callback[i]))(i,read_callback_data[i]);
 
-	if(FD_ISSET(i, &sets.write) && write_callback[i])
+	if(fd_FD_ISSET(i, &sets.write) && write_callback[i])
 	  (*(write_callback[i]))(i,write_callback_data[i]);
       }
     }else{
@@ -315,19 +317,19 @@ void backend(void)
 	sets=selectors;
 	next_timeout.tv_usec=0;
 	next_timeout.tv_sec=0;
-	if(select(max_fd+1, &sets.read, &sets.write, 0, &next_timeout) < 0 && errno == EBADF)
+	if(fd_select(max_fd+1, &sets.read, &sets.write, 0, &next_timeout) < 0 && errno == EBADF)
 	{
 	  int i;
 	  for(i=0;i<MAX_OPEN_FILEDESCRIPTORS;i++)
 	  {
-	    if(!FD_ISSET(i, &selectors.read) && !FD_ISSET(i,&selectors.write))
+	    if(!fd_FD_ISSET(i, &selectors.read) && !FD_ISSET(i,&selectors.write))
 	      continue;
 	    
-	    FD_ZERO(& sets.read);
-	    FD_ZERO(& sets.write);
+	    fd_FD_ZERO(& sets.read);
+	    fd_FD_ZERO(& sets.write);
 
-	    if(FD_ISSET(i, &selectors.read))  FD_SET(i, &sets.read);
-	    if(FD_ISSET(i, &selectors.write)) FD_SET(i, &sets.write);
+	    if(fd_FD_ISSET(i, &selectors.read))  fd_FD_SET(i, &sets.read);
+	    if(fd_FD_ISSET(i, &selectors.write)) fd_FD_SET(i, &sets.write);
 
 	    next_timeout.tv_usec=0;
 	    next_timeout.tv_sec=0;
@@ -354,19 +356,36 @@ void backend(void)
 
 int write_to_stderr(char *a, INT32 len)
 {
-  int nonblock;
+  int nonblock=0;
   INT32 pos, tmp;
 
-  if((nonblock=query_nonblocking(2)))
-    set_nonblocking(2,0);
+  if(!len) return 1;
 
   for(pos=0;pos<len;pos+=tmp)
   {
     tmp=write(2,a+pos,len-pos);
-    if(tmp<0) break;
+    if(tmp<0)
+    {
+      tmp=0;
+      switch(errno)
+      {
+#ifdef EWOULDBLOCK
+	case EWOULDBLOCK:
+	  nonblock=1;
+	  set_nonblocking(2,0);
+	  continue;
+#endif
+
+	case EINTR:
+	  continue;
+      }
+      break;
+    }
   }
+
   if(nonblock)
     set_nonblocking(2,1);
+
   return 1;
 }
 
diff --git a/src/configure.in b/src/configure.in
index 9cbfd81114..d5a2c84bed 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1,4 +1,4 @@
-AC_REVISION("$Id: configure.in,v 1.144 1997/12/28 09:29:08 hubbe Exp $")
+AC_REVISION("$Id: configure.in,v 1.145 1998/01/02 01:05:41 hubbe Exp $")
 AC_INIT(interpret.c)
 AC_CONFIG_HEADER(machine.h)
 
@@ -619,7 +619,7 @@ AC_CHECK_HEADERS(sys/rusage.h time.h sys/time.h sys/types.h unistd.h stdlib.h \
 memory.h values.h string.h strings.h fcntl.h sys/filio.h sys/sockio.h crypt.h \
 locale.h sys/resource.h sys/select.h sys/mman.h setjmp.h limits.h pthread.h \
 thread.h dlfcn.h dld.h sys/times.h sched.h sys/procfs.h sys/param.h winsock.h \
-sys/ioct.h sys/socket.h malloc.h netinet/in.h sys/wait.h)
+sys/ioct.h sys/socket.h malloc.h netinet/in.h sys/wait.h winbase.h)
 
 AC_CHECK_SIZEOF(char *,4)
 AC_CHECK_SIZEOF(long,4)
@@ -900,6 +900,8 @@ AC_CHECK_FUNCS( \
  setlocale \
  setrlimit \
  sigaction \
+ sigblock \
+ sigprocmask \
  sigvec \
  strcasecmp \
  strchr \
@@ -909,6 +911,8 @@ AC_CHECK_FUNCS( \
  strtod \
  strtok \
  strtol \
+ time \
+ GetSystemTimeAsFileTime \
  times \
  vfprintf \
  vsprintf \
diff --git a/src/cpp.c b/src/cpp.c
new file mode 100644
index 0000000000..55a84216ff
--- /dev/null
+++ b/src/cpp.c
@@ -0,0 +1,1952 @@
+/*\
+||| This file a part of Pike, and is copyright by Fredrik Hubinette
+||| Pike is distributed as GPL (General Public License)
+||| See the files COPYING and DISCLAIMER for more information.
+\*/
+#include "global.h"
+#include "dynamic_buffer.h"
+#include "lex.h"
+#include "language.h"
+#include "stralloc.h"
+#include "module_support.h"
+#include "interpret.h"
+#include "svalue.h"
+#include "pike_macros.h"
+#include "hashtable.h"
+#include "program.h"
+#include "object.h"
+#include "error.h"
+#include "array.h"
+#include "mapping.h"
+#include "builtin_functions.h"
+#include "operators.h"
+#include "opcodes.h"
+#include "constants.h"
+#include "time.h"
+#include "stuff.h"
+#include <ctype.h>
+
+#define CPP_NO_OUTPUT 1
+#define CPP_EXPECT_ELSE 2
+#define CPP_EXPECT_ENDIF 4
+#define CPP_REALLY_NO_OUTPUT 8
+#define CPP_END_AT_NEWLINE 16
+#define CPP_DO_IF 32
+
+#define OUTP() (!(flags & (CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT)))
+#define PUTNL() low_my_putchar('\n', &this->buf)
+#define GOBBLE(X) (data[pos]==(X)?++pos,1:0)
+#define PUTC(C) do { \
+ int c_=(C); if(OUTP() || c_=='\n') low_my_putchar(c_, &this->buf); }while(0)
+
+#define STRCAT(STR,LEN) do {				\
+  INT32 x_,len_=(LEN);					\
+  char *str_=(STR);					\
+  if(OUTP())						\
+    low_my_binary_strcat(str_,len_, &this->buf);	\
+  else							\
+    for(x_=0;x_<len_;x_++)				\
+      if(str_[x_]=='\n')				\
+        low_my_putchar('\n',&this->buf);		\
+}while(0)
+
+#define CHECKWORD(X) \
+ (!strncmp(X,data+pos,strlen(X)) && !isidchar(data[pos+strlen(X)]))
+#define WGOBBLE(X) (CHECKWORD(X) ? (pos+=strlen(X)),1 : 0)
+#define GOBBLEOP(X) \
+ ((!strncmp(X,data+pos,strlen(X))) ? (pos+=strlen(X)),1 : 0)
+
+#define MAX_ARGS            255
+#define DEF_ARG_STRINGIFY   0x100000
+#define DEF_ARG_NOPRESPACE  0x200000
+#define DEF_ARG_NOPOSTSPACE 0x400000
+#define DEF_ARG_MASK        0x0fffff
+
+
+struct pike_predef_s
+{
+  struct pike_predef_s *next;
+  char *name;
+  char *value;
+};
+
+static struct pike_predef_s *pike_predefs=0;
+struct define_part
+{
+  int argument;
+  struct pike_string *postfix;
+};
+
+struct define_argument {
+  char *arg;
+  INT32 len;
+};
+
+
+struct cpp;
+struct define;
+typedef void (*magic_define_fun)(struct cpp *,
+				 struct define *,
+				 struct define_argument *,
+				 dynamic_buffer *);
+
+
+struct define
+{
+  struct hash_entry link; /* must be first */
+  magic_define_fun magic;
+  int args;
+  int num_parts;
+  int inside;
+  struct pike_string *first;
+  struct define_part parts[1];
+};
+
+#define find_define(N) \
+  (this->defines?BASEOF(hash_lookup(this->defines, N), define, link):0)
+
+struct cpp
+{
+  struct hash_table *defines;
+  INT32 current_line;
+  INT32 compile_errors;
+  struct pike_string *current_file;
+  dynamic_buffer buf;
+};
+
+struct define *defined_macro =0;
+struct define *constant_macro =0;
+
+static INT32 calc(struct cpp *,char*,INT32,INT32);
+static INT32 calc1(struct cpp *,char*,INT32,INT32);
+
+void cpp_error(struct cpp *this,char *err)
+{
+  this->compile_errors++;
+  if(this->compile_errors > 10) return;
+  if(get_master())
+  {
+    ref_push_string(this->current_file);
+    push_int(this->current_line);
+    push_text(err);
+    SAFE_APPLY_MASTER("compile_error",3);
+    pop_stack();
+  }else{
+    (void)fprintf(stderr, "%s:%ld: %s",
+		  this->current_file->str,
+		  (long)this->current_line,
+		  err);
+    fflush(stderr);
+  }
+}
+
+/* devours one reference to 'name'! */
+static struct define *alloc_empty_define(struct pike_string *name, INT32 parts)
+{
+  struct define *def;
+  def=(struct define *)xalloc(sizeof(struct define)+
+			      sizeof(struct define_part) * (parts -1));
+  def->magic=0;
+  def->args=-1;
+  def->inside=0;
+  def->num_parts=parts;
+  def->first=0;
+  def->link.s=name;
+  return def;
+}
+
+static void undefine(struct cpp *this,
+		     struct pike_string *name)
+{
+  INT32 e;
+  struct define *d;
+
+  d=find_define(name);
+
+  if(!d) return;
+
+  this->defines=hash_unlink(this->defines, & d->link);
+
+  for(e=0;e<d->num_parts;e++)
+    free_string(d->parts[e].postfix);
+  free_string(d->link.s);
+  if(d->first)
+    free_string(d->first);
+  free((char *)d);
+}
+
+static void do_magic_define(struct cpp *this,
+			    char *name,
+			    magic_define_fun fun)
+{
+  struct define* def=alloc_empty_define(make_shared_string(name),0);
+  def->magic=fun;
+  this->defines=hash_insert(this->defines, & def->link);
+}
+
+static void simple_add_define(struct cpp *this,
+			    char *name,
+			    char *what)
+{
+  struct define* def=alloc_empty_define(make_shared_string(name),0);
+  def->first=make_shared_string(what);
+  this->defines=hash_insert(this->defines, & def->link);
+}
+
+
+/* Who needs inline functions anyway? /Hubbe */
+
+#define FIND_END_OF_STRING() do {					\
+  while(1)								\
+  {									\
+    if(pos>=len)							\
+    {									\
+      cpp_error(this,"End of file in string.");				\
+      break;								\
+    }									\
+    switch(data[pos++])							\
+    {									\
+    case '\n':								\
+      cpp_error(this,"Newline in string.");				\
+      this->current_line++;						\
+      break;								\
+    case '"': break;							\
+    case '\\': if(data[++pos]=='\n') this->current_line++;		\
+    default: continue;							\
+    }									\
+   break;								\
+  } } while(0)
+
+
+#define FIND_END_OF_CHAR() do {					\
+  int e=0;							\
+  while(1)							\
+  {								\
+    if(pos+1>=len)						\
+    {								\
+      cpp_error(this,"End of file in character constant.");	\
+      break;							\
+    }								\
+								\
+    if(e++>16)							\
+    {								\
+      cpp_error(this,"Too long character constant.");		\
+      break;							\
+    }								\
+								\
+    switch(data[pos++])						\
+    {								\
+    case '\n':							\
+      cpp_error(this,"Newline in char.");			\
+      this->current_line++;					\
+      break;							\
+    case '\'': break;						\
+    case '\\': if(data[++pos]=='\n') this->current_line++;	\
+    default: continue;						\
+    }								\
+    break;							\
+  } } while(0)
+
+#define DUMPPOS(X)					\
+		  fprintf(stderr,"\nPOS(%s):",X);	\
+		  fflush(stderr);			\
+		  write(2,data+pos,20);			\
+		  fprintf(stderr,"\n");			\
+		  fflush(stderr)
+
+#define FIND_EOL() do {				\
+    this->current_line++;			\
+    while(pos < len && data[pos]!='\n') pos++;	\
+  } while(0)
+
+#define SKIPWHITE() do {			\
+    if(!isspace(data[pos])) break;		\
+    PUTNL();					\
+    pos++;					\
+  } while(0)
+
+#define SKIPSPACE() \
+  do { while(isspace(data[pos]) && data[pos]!='\n') pos++; }while (0)
+
+#define SKIPCOMMENT()	do{				\
+  	pos++;						\
+	while(data[pos]!='*' || data[pos+1]!='/')	\
+	{						\
+	  if(pos+2>=len)				\
+	  {						\
+	    cpp_error(this,"End of file in comment.");	\
+	    break;					\
+	  }						\
+							\
+	  if(data[pos]=='\n')				\
+	  {						\
+	    this->current_line++;			\
+	    PUTNL();					\
+	  }						\
+							\
+	  pos++;					\
+	}						\
+	pos+=2;						\
+  }while(0)
+
+#define READCHAR(C) do {			\
+  switch(data[++pos])				\
+  {						\
+  case 'n': C='\n'; break;			\
+  case 'r': C='\r'; break;			\
+  case 'b': C='\b'; break;			\
+  case 't': C='\t'; break;			\
+    						\
+  case '0': case '1': case '2': case '3':	\
+  case '4': case '5': case '6': case '7':	\
+    C=data[pos]-'0';				\
+    if(data[pos+1]>='0' && data[pos+1]<='8')	\
+    {						\
+      C*=8;					\
+      C+=data[++pos]-'0';			\
+      						\
+      if(data[pos+1]>='0' && data[pos+1]<='8')	\
+      {						\
+	C*=8;					\
+	C+=data[++pos]-'0';			\
+      }						\
+    }						\
+    break;					\
+    						\
+  case '\n':					\
+    this->current_line++;			\
+    C='\n';					\
+    break;					\
+    						\
+  default:					\
+    C=data[pos];				\
+  }						\
+}while (0)
+
+
+#define READSTRING(nf)				\
+while(1)					\
+{						\
+  pos++;					\
+  if(pos>=len)					\
+  {						\
+    cpp_error(this,"End of file in string.");	\
+    break;					\
+  }						\
+						\
+  switch(data[pos])				\
+  {						\
+  case '\n':					\
+    cpp_error(this,"Newline in string.");	\
+    this->current_line++;			\
+    break;					\
+  case '"':  break;				\
+  case '\\':					\
+  {						\
+    int tmp;					\
+    READCHAR(tmp);				\
+    low_my_putchar(tmp, &nf);			\
+    continue;					\
+  }						\
+						\
+  default:					\
+    low_my_putchar(data[pos], &nf);		\
+    continue;					\
+  }						\
+  pos++;					\
+  break;					\
+}
+
+void PUSH_STRING(char *str,
+		 INT32 len,
+		 dynamic_buffer *buf)
+{
+  INT32 p2;
+  low_my_putchar('"', buf);
+  for(p2=0;p2<len;p2++)
+  {
+    switch(str[p2])
+    {
+    case '\n':
+      low_my_putchar('\\', buf);
+      low_my_putchar('n', buf);
+      break;
+      
+    case '\t':
+      low_my_putchar('\\', buf);
+      low_my_putchar('t', buf);
+      break;
+      
+    case '\r':
+      low_my_putchar('\\', buf);
+      low_my_putchar('r', buf);
+      break;
+      
+    case '\b':
+      low_my_putchar('\\', buf);
+      low_my_putchar('b', buf);
+      break;
+      
+    case '\\':
+    case '"':
+      low_my_putchar('\\', buf);
+      low_my_putchar(str[p2], buf);
+      break;
+      
+    default:
+      if(isprint(EXTRACT_UCHAR(str+p2)))
+      {
+	low_my_putchar(str[p2], buf);
+      }
+      else
+      {
+	int c=EXTRACT_UCHAR(str+p2);
+	low_my_putchar('\\', buf);
+	low_my_putchar(((c>>6)&7)+'0', buf);
+	low_my_putchar(((c>>3)&7)+'0', buf);
+	low_my_putchar((c&7)+'0', buf);
+      }
+      break;
+    }
+  }
+  low_my_putchar('"', buf);
+}
+
+#define FINDTOK() 				\
+  do {						\
+  SKIPSPACE();					\
+  if(data[pos]=='/')				\
+  {						\
+    INT32 tmp;					\
+    switch(data[pos+1])				\
+    {						\
+    case '/':					\
+      FIND_EOL();				\
+      break;					\
+      						\
+    case '*':					\
+      tmp=pos+2;				\
+      while(1)					\
+      {						\
+        if(data[tmp]=='*')			\
+	{					\
+	  if(data[tmp+1] == '/')		\
+	  {					\
+	    pos=tmp+2;				\
+	    break;				\
+	  }					\
+	  break;				\
+	}					\
+						\
+	if(data[tmp]=='\n')			\
+	  break;				\
+        tmp++;					\
+      }						\
+    }						\
+  }						\
+  break;					\
+  }while(1)
+
+static INLINE int find_end_parenthesis(struct cpp *this,
+				       char *data,
+				       INT32 len,
+				       INT32 pos) /* position of first " */
+{
+  while(1)
+  {
+    if(pos+1>=len)
+    {
+      cpp_error(this,"End of file while looking for end parenthesis.");
+      return pos;
+    }
+
+    switch(data[pos++])
+    {
+    case '\n': this->current_line++; break;
+    case '\'': FIND_END_OF_CHAR();  break;
+    case '"':  FIND_END_OF_STRING();  break;
+    case '(':  pos=find_end_parenthesis(this, data, len, pos); break;
+    case ')':  return pos;
+    }
+  }
+}
+
+static INT32 low_cpp(struct cpp *this,
+		    char *data,
+		    INT32 len,
+		    int flags)
+{
+  INT32 pos, tmp, e;
+  
+  for(pos=0;pos<len;)
+  {
+/*    fprintf(stderr,"%c",data[pos]);
+    fflush(stderr); */
+
+    switch(data[pos++])
+    {
+    case '\n':
+      if(flags & CPP_END_AT_NEWLINE) return pos-1;
+
+/*      fprintf(stderr,"CURRENT LINE: %d\n",this->current_line); */
+      this->current_line++;
+      PUTNL();
+      goto do_skipwhite;
+
+    case '\t':
+    case ' ':
+    case '\r':
+      PUTC(' ');
+      
+    do_skipwhite:
+      while(data[pos]==' ' || data[pos]=='\r' || data[pos]=='\t')
+	pos++;
+      break;
+
+      /* Minor optimization */
+    case '!': case '@': case '$': case '%': case '^': case '&':
+    case '*': case '(': case ')': case '-': case '=': case '+':
+    case '{': case '}': case ':': case '?': case '`': case ';':
+    case '<': case '>': case ',': case '.': case '~': case '[':
+    case ']': case '|':
+      PUTC(data[pos-1]);
+      break;
+      
+    default:
+      if(OUTP() && isidchar(data[pos-1]))
+      {
+	struct pike_string *s=0;
+	struct define *d=0;
+	tmp=pos-1;
+	while(isidchar(data[pos])) pos++;
+
+	if(flags & CPP_DO_IF)
+	{
+	  if(pos-tmp == 7 && !strncmp("defined",data+tmp, 7))
+	  {
+	    d=defined_macro;
+	  }
+	  else if((pos-tmp == 4 && !strncmp("efun",data+tmp, 4)) ||
+		  (pos-tmp == 8 && !strncmp("constant",data+tmp,8)))
+	  {
+	    d=constant_macro;
+	  }
+	  else
+	  {
+	    goto do_find_define;
+	  }
+	}else{
+	do_find_define:
+	  if((s=binary_findstring(data+tmp, pos-tmp)))
+	  {
+	    d=find_define(s);
+	  }
+	}
+	  
+	if(d && !d->inside)
+	{
+	  int arg=0;
+	  dynamic_buffer tmp;
+	  struct define_argument arguments [MAX_ARGS];
+	  
+	  if(s) s->refs++;
+	  
+	  if(d->args>=0)
+	  {
+	    SKIPWHITE();
+	    
+	    if(!GOBBLE('('))
+	    {
+	      cpp_error(this,"Missing '(' in macro call.");
+	      break;
+	    }
+	    
+	    for(arg=0;arg<d->args;arg++)
+	    {
+	      SKIPWHITE();
+	      arguments[arg].arg=data + pos;
+	      if(data[pos]==')')
+	      {
+		cpp_error(this,"Too few arguments to macro.");
+		break;
+	      }
+	      
+	      while(1)
+	      {
+		if(pos+1>len)
+		{
+		  cpp_error(this,"End of file in macro call.");
+		  break;
+		}
+		
+		switch(data[pos++])
+		{
+		case '\n':
+		  this->current_line++;
+		  PUTNL();
+		default: continue;
+		  
+		case '"':
+		  FIND_END_OF_STRING();
+		  continue;
+		  
+		case '\'':
+		  FIND_END_OF_CHAR();
+		  continue;
+		  
+		case '(':
+		  pos=find_end_parenthesis(this, data, len, pos);
+		  continue;
+		  
+		case ')': pos--;
+		case ',': 
+		  break;
+		}
+		break;
+	      }
+	      arguments[arg].len=data+pos-arguments[arg].arg;
+	    }
+	    SKIPWHITE();
+	    if(!GOBBLE(')'))
+	      cpp_error(this,"Missing ) in macro call.");
+	  }
+	  
+	  if(d->args >= 0 && arg != d->args)
+	    cpp_error(this,"Wrong number of arguments to macro.");
+	  
+	  initialize_buf(&tmp);
+	  if(d->magic)
+	  {
+	    d->magic(this, d, arguments, &tmp);
+	  }else{
+	    low_my_binary_strcat(d->first->str, d->first->len, &tmp);
+	    for(e=0;e<d->num_parts;e++)
+	    {
+	      char *a;
+	      INT32 l;
+	      
+	      if((d->parts[e].argument & DEF_ARG_MASK) < 0 || 
+		 (d->parts[e].argument & DEF_ARG_MASK) >= arg)
+	      {
+		cpp_error(this,"Macro not expanded correctly.");
+		continue;
+	      }
+	      
+	      a=arguments[d->parts[e].argument&DEF_ARG_MASK].arg;
+	      l=arguments[d->parts[e].argument&DEF_ARG_MASK].len;
+	      
+	      if(!(d->parts[e].argument & DEF_ARG_NOPRESPACE))
+		low_my_putchar(' ', &tmp);
+	      
+	      if(d->parts[e].argument & DEF_ARG_STRINGIFY)
+	      {
+		PUSH_STRING(a,l,&tmp);
+	      }else{
+		low_my_binary_strcat(a, l, &tmp);
+	      }
+	      
+	      if(!(d->parts[e].argument & DEF_ARG_NOPOSTSPACE))
+		low_my_putchar(' ', &tmp);
+	      
+	      low_my_binary_strcat(d->parts[e].postfix->str,
+				   d->parts[e].postfix->len,
+				   &tmp);
+	    }
+	  }
+	  
+	  /* FIXME */
+	  for(e=0;e<(long)tmp.s.len;e++)
+	    if(tmp.s.str[e]=='\n')
+	      tmp.s.str[e]=' ';
+
+	  if(s) d->inside=1;
+	  
+	  low_my_putchar(0, &tmp);
+	  tmp.s.len--;
+	  
+	  low_cpp(this, tmp.s.str, tmp.s.len, 
+		  flags & ~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE));
+	  
+	  if(s)
+	  {
+	    if((d=find_define(s)))
+	      d->inside=0;
+	    
+	    free_string(s);
+	  }
+
+	  toss_buffer(&tmp);
+	  break;
+	}else{
+	  if(flags & CPP_DO_IF)
+	  {
+	    STRCAT(" 0 ", 3);
+	  }else{
+	    STRCAT(data+tmp, pos-tmp);
+	  }
+	}
+      }else{
+	PUTC(data[pos-1]);
+      }
+      break;
+      
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+      PUTC(data[pos-1]);
+      while(data[pos]>='0' && data[pos]<='9') PUTC(data[pos++]);
+      break;
+
+    case '"':
+      tmp=pos-1;
+      FIND_END_OF_STRING();
+      STRCAT(data+tmp, pos-tmp);
+      break;
+
+    case '\'':
+      tmp=pos-1;
+      FIND_END_OF_CHAR();
+      STRCAT(data+tmp, pos-tmp);
+      break;
+
+    case '/':
+      if(data[pos]=='/')
+      {
+	FIND_EOL();
+	break;
+      }
+
+      if(data[pos]=='*')
+      {
+	PUTC(' ');
+	SKIPCOMMENT();
+	break;
+      }
+
+      PUTC(data[pos-1]);
+      break;
+
+  case '#':
+    if(GOBBLE('!'))
+    {
+      FIND_EOL();
+      break;
+    }
+    SKIPSPACE();
+
+    switch(data[pos])
+    {
+    case 'l':
+      if(WGOBBLE("line"))
+	{
+	  while(data[pos]==' ' || data[pos]=='\t') pos++;
+	}else{
+	  goto unknown_preprocessor_directive;
+	}
+      /* Fall through */
+      
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    {
+      char *foo=data+pos;
+      this->current_line=STRTOL(foo, &foo, 10)-1;
+      pos=foo-data;
+      SKIPSPACE();
+      
+      if(data[pos]=='"')
+      {
+	dynamic_buffer nf;
+	initialize_buf(&nf);
+	
+	READSTRING(nf);
+
+	free_string(this->current_file);
+	this->current_file=low_free_buf(&nf);
+      }
+      
+      FIND_EOL();
+      break;
+    }
+
+    case 'i': /* include, if, ifdef */
+      if(WGOBBLE("include"))
+	{
+	  struct svalue *save_sp=sp;
+	  SKIPSPACE();
+
+	  check_stack(3);
+
+	  switch(data[pos++])
+	    {
+	    case '"':
+	      {
+		dynamic_buffer nf;
+		initialize_buf(&nf);
+		pos--;
+		READSTRING(nf);
+		push_string(low_free_buf(&nf));
+		ref_push_string(this->current_file);
+		push_int(1);
+		break;
+	      }
+
+	    case '<':
+	      {
+		INT32 tmp=pos;
+		while(data[pos]!='>')
+		{
+		  if(data[pos]=='\n')
+		  {
+		    cpp_error(this,"Expecting '>' in include.");
+		    break;
+		  }
+		      
+		  pos++;
+		}
+		push_string(make_shared_binary_string(data+tmp, pos-tmp));
+		ref_push_string(this->current_file);
+		pos++;
+		push_int(0);
+		break;
+	      }
+
+	    default:
+	      cpp_error(this,"Expected file to include.");
+	      break;
+	    }
+
+	  if(sp==save_sp) break;
+
+	  if(OUTP())
+	  {
+	    struct pike_string *new_file;
+
+	    SAFE_APPLY_MASTER("handle_include",3);
+	  
+	    if(sp[-1].type != T_STRING)
+	    {
+	      cpp_error(this,"Couldn't include file.");
+	      pop_n_elems(sp-save_sp);
+	      break;
+	    }
+	    
+	    new_file=sp[-1].u.string;
+	    
+	    assign_svalue_no_free(sp,sp-1);
+	    sp++;
+	    
+	    SAFE_APPLY_MASTER("read_include",1);
+	    
+	    if(sp[-1].type != T_STRING)
+	    {
+	      cpp_error(this,"Couldn't read include file.");
+	      pop_n_elems(sp-save_sp);
+	      break;
+	    }
+	    
+	    
+	    {
+	      char buffer[47];
+	      struct pike_string *save_current_file;
+	      INT32 save_current_line;
+
+	      save_current_file=this->current_file;
+	      save_current_line=this->current_line;
+	      copy_shared_string(this->current_file,new_file);
+	      
+	      low_my_binary_strcat("# 1 ",4,&this->buf);
+	      PUSH_STRING(new_file->str,new_file->len, & this->buf);
+	      low_my_putchar('\n',&this->buf);
+	      
+	      
+	      low_cpp(this,
+		      sp[-1].u.string->str,
+		      sp[-1].u.string->len,
+		      flags&~(CPP_EXPECT_ENDIF | CPP_EXPECT_ELSE));
+	      
+	      free_string(this->current_file);
+	      this->current_file=save_current_file;
+	      this->current_line=save_current_line;
+	      
+	      sprintf(buffer,"# %d ",this->current_line);
+	      low_my_binary_strcat(buffer,strlen(buffer),&this->buf);
+	      PUSH_STRING(this->current_file->str,this->current_file->len,& this->buf);
+	      low_my_putchar('\n',&this->buf);
+	    }
+	  }
+
+	  pop_n_elems(sp-save_sp);
+	  
+	  break;
+	}
+
+      if(WGOBBLE("if"))
+      {
+	dynamic_buffer save,tmp;
+	INT32 nflags=CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF;
+	
+	if(!OUTP())
+	  nflags|=CPP_REALLY_NO_OUTPUT;
+	
+	save=this->buf;
+	initialize_buf(& this->buf);
+	pos+=low_cpp(this,data+pos,len-pos,CPP_END_AT_NEWLINE|CPP_DO_IF);
+	tmp=this->buf;
+	this->buf=save;
+	
+	low_my_putchar(0, &tmp);
+	tmp.s.len--;
+	
+	calc(this,tmp.s.str,tmp.s.len,0);
+	toss_buffer(&tmp);
+	if(IS_ZERO(sp-1)) nflags|=CPP_NO_OUTPUT;
+	pop_stack();
+	pos+=low_cpp(this,data+pos,len-pos,nflags);
+	break;
+      }
+
+      if(WGOBBLE("ifdef"))
+	{
+	  INT32 namestart,nflags;
+	  struct pike_string *s;
+	  SKIPSPACE();
+
+	  if(!isidchar(data[pos]))
+	    cpp_error(this,"#ifdef what?\n");
+
+	  namestart=pos;
+	  while(isidchar(data[pos])) pos++;
+	  nflags=CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF | CPP_NO_OUTPUT;
+
+	  if(!OUTP())
+	    nflags|=CPP_REALLY_NO_OUTPUT;
+
+	  if((s=binary_findstring(data+namestart,pos-namestart)))
+	    if(find_define(s))
+	      nflags&=~CPP_NO_OUTPUT;
+
+	  pos+=low_cpp(this,data+pos,len-pos,nflags);
+	  break;
+	}
+
+      if(WGOBBLE("ifndef"))
+	{
+	  INT32 namestart,nflags;
+	  struct pike_string *s;
+	  SKIPSPACE();
+
+	  if(!isidchar(data[pos]))
+	    cpp_error(this,"#ifndef what?");
+
+	  namestart=pos;
+	  while(isidchar(data[pos])) pos++;
+	  nflags=CPP_EXPECT_ELSE | CPP_EXPECT_ENDIF;
+
+	  if(!OUTP())
+	    nflags|=CPP_REALLY_NO_OUTPUT;
+
+	  if((s=binary_findstring(data+namestart,pos-namestart)))
+	    if(find_define(s))
+	      nflags|=CPP_NO_OUTPUT;
+
+	  pos+=low_cpp(this,data+pos,len-pos,nflags);
+	  break;
+	}
+
+      goto unknown_preprocessor_directive;
+
+    case 'e': /* endif, else, elif, error */
+      if(WGOBBLE("endif"))
+      {
+	if(!(flags & CPP_EXPECT_ENDIF))
+	  cpp_error(this,"Unmatched #endif");
+
+	return pos;
+      }
+
+      if(WGOBBLE("else"))
+	{
+	  if(!(flags & CPP_EXPECT_ELSE))
+	    cpp_error(this,"Unmatched #else");
+
+	  flags&=~CPP_EXPECT_ELSE;
+	  flags|=CPP_EXPECT_ENDIF;
+
+	  if(flags & CPP_NO_OUTPUT)
+	    flags&=~CPP_NO_OUTPUT;
+	  else
+	    flags|=CPP_NO_OUTPUT;
+
+	  break;
+	}
+
+      if(WGOBBLE("elif") || WGOBBLE("elseif"))
+      {
+	if(!(flags & CPP_EXPECT_ELSE))
+	  cpp_error(this,"Unmatched #elif");
+	
+	flags|=CPP_EXPECT_ENDIF;
+	
+	if(flags & CPP_NO_OUTPUT)
+	{
+	  dynamic_buffer save,tmp;
+	  save=this->buf;
+	  initialize_buf(& this->buf);
+	  pos+=low_cpp(this,data+pos,len-pos,CPP_END_AT_NEWLINE|CPP_DO_IF);
+	  tmp=this->buf;
+	  this->buf=save;
+	  
+	  low_my_putchar(0, &tmp);
+	  tmp.s.len--;
+	  
+	  calc(this,tmp.s.str,tmp.s.len,0);
+	  toss_buffer(&tmp);
+	  if(!IS_ZERO(sp-1)) flags&=~CPP_NO_OUTPUT;
+	  pop_stack();
+	}else{
+	  FIND_EOL();
+	  flags|= CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT;
+	}
+	break;
+      }
+
+      if(WGOBBLE("error"))
+	{
+          INT32 foo;
+          SKIPSPACE();
+          foo=pos;
+          FIND_EOL();
+	  pos++;
+	  if(OUTP())
+	  {
+	    push_string(make_shared_binary_string(data+foo,pos-foo));
+	    cpp_error(this,sp[-1].u.string->str);
+	  }
+	  break;
+	}
+      
+      goto unknown_preprocessor_directive;
+
+    case 'd': /* define */
+      if(WGOBBLE("define"))
+	{
+	  dynamic_buffer str;
+	  INT32 namestart, tmp3, nameend, argno=-1;
+	  struct define *def;
+	  struct svalue *partbase,*argbase=sp;
+
+	  SKIPSPACE();
+
+	  namestart=pos;
+	  if(!isidchar(data[pos]))
+	    cpp_error(this,"Define what?");
+
+	  while(isidchar(data[pos])) pos++;
+	  nameend=pos;
+
+	  if(GOBBLE('('))
+	    {
+	      argno=0;
+	      SKIPWHITE();
+
+	      while(data[pos]!=')')
+		{
+		  INT32 tmp2;
+		  if(argno)
+		    {
+		      if(!GOBBLE(','))
+			cpp_error(this,"Expecting comma in macro definition.");
+		      SKIPWHITE();
+		    }
+		  tmp2=pos;
+
+		  if(!isidchar(data[pos]))
+		  {
+		    cpp_error(this,"Expected argument for macro.");
+		    break;
+		  }
+
+		  while(isidchar(data[pos])) pos++;
+		  check_stack(1);
+		  push_string(make_shared_binary_string(data+tmp2, pos-tmp2));
+
+		  SKIPWHITE();
+		  argno++;
+		  if(argno>=MAX_ARGS)
+		  {
+		    cpp_error(this,"Too many arguments in macro definition.");
+		    pop_stack();
+		    argno--;
+		  }
+		}
+
+	      if(!GOBBLE(')'))
+		cpp_error(this,"Missing ) in macro definition.");
+	    }
+
+	  SKIPSPACE();
+
+	  partbase=sp;
+	  initialize_buf(&str);
+	  
+	  while(1)
+	  {
+	    INT32 extra=0;
+
+/*	    fprintf(stderr,"%c",data[pos]);
+	    fflush(stderr); */
+
+	    switch(data[pos++])
+	    {
+	    case '/':
+	      if(data[pos]=='/')
+	      {
+		low_my_putchar(' ',&str);
+		FIND_EOL();
+		continue;
+	      }
+	      
+	      if(data[pos]=='*')
+	      {
+		PUTC(' ');
+		SKIPCOMMENT();
+		continue;
+	      }
+	      
+	      low_my_putchar('/',&str);
+	      continue;
+	      
+	    case '0': case '1': case '2': case '3':	case '4':
+	    case '5': case '6': case '7': case '8':	case '9':
+	      low_my_putchar(data[pos-1],&str);
+	      while(data[pos]>='0' && data[pos]<='9')
+		low_my_putchar(data[pos++],&str);
+	      continue;
+	      
+	    case '#':
+	      if(GOBBLE('#'))
+	      {
+		extra=DEF_ARG_NOPRESPACE;
+		while(str.s.len && isspace(str.s.str[str.s.len-1]))
+		  str.s.len--;
+	      }else{
+		extra=DEF_ARG_STRINGIFY;
+	      }
+	      SKIPSPACE();
+	      
+	      /* fall through */
+	      
+	    default:
+	      if(isidchar(data[pos-1]))
+	      {
+		struct pike_string *s;
+		tmp3=pos-1;
+		while(isidchar(data[pos])) pos++;
+		if(argno>0)
+		{
+		  if((s=binary_findstring(data+tmp3,pos-tmp3)))
+		  {
+		    for(e=0;e<argno;e++)
+		    {
+		      if(argbase[e].u.string == s)
+		      {
+			check_stack(2);
+			push_string(low_free_buf(&str));
+			initialize_buf(&str);
+			push_int(e | extra);
+			extra=0;
+			break;
+		      }
+		    }
+		    if(e!=argno) continue;
+		  }
+		}
+		low_my_binary_strcat(data+tmp3,pos-tmp3, &str);
+	      }else{
+		low_my_putchar(data[pos-1],&str);
+	      }
+	      extra=0;
+	      continue;
+	      
+	    case '"':
+	      tmp3=pos-1;
+	      FIND_END_OF_STRING();
+	      low_my_binary_strcat(data+tmp3, pos-tmp3, &str);
+	      continue;
+	      
+	    case '\'':
+	      tmp3=pos-1;
+	      FIND_END_OF_CHAR();
+	      low_my_binary_strcat(data+tmp3, pos-tmp3, &str);
+	      continue;
+	      
+	    case '\\':
+	      if(GOBBLE('\n'))
+	      { 
+		this->current_line++;
+		PUTNL();
+	      }
+	      continue;
+	      
+	    case '\n':
+		PUTNL();
+		this->current_line++;
+	    case 0:
+		break;
+	    }
+	    push_string(low_free_buf(&str));
+	    break;
+	  }
+
+	  if(OUTP())
+	  {
+	    def=alloc_empty_define(make_shared_binary_string(data+namestart,
+						  nameend-namestart),
+				   (sp-partbase)/2);
+	    copy_shared_string(def->first, partbase->u.string);
+	    def->args=argno;
+	    
+	    for(e=0;e<def->num_parts;e++)
+	    {
+#if 1
+	      if(partbase[e*2+1].type != T_INT)
+		fatal("Cpp internal error, expected integer!\n");
+	      
+	      if(partbase[e*2+2].type != T_STRING)
+		fatal("Cpp internal error, expected string!\n");
+#endif
+	      def->parts[e].argument=partbase[e*2+1].u.integer;
+	      copy_shared_string(def->parts[e].postfix,
+				 partbase[e*2+2].u.string);
+	    }
+	    
+#ifdef DEBUG
+	    if(def->num_parts==1 &&
+	       (def->parts[0].argument & DEF_ARG_MASK) > MAX_ARGS)
+	      fatal("Internal error in define\n");
+#endif	  
+	    
+	    this->defines=hash_insert(this->defines, & def->link);
+	    
+	  }
+	  pop_n_elems(sp-argbase);
+	  break;
+	}
+      
+      goto unknown_preprocessor_directive;
+      
+    case 'u': /* undefine */
+      if(WGOBBLE("undefine") || WGOBBLE("undef"))
+	{
+	  INT32 tmp;
+	  struct pike_string *s;
+
+	  SKIPSPACE();
+
+	  tmp=pos;
+	  if(!isidchar(data[pos]))
+	    cpp_error(this,"Undefine what?");
+
+	  while(isidchar(data[pos])) pos++;
+
+	  if(OUTP())
+	  {
+	    if((s=binary_findstring(data+pos, pos-tmp)))
+	      undefine(this,s);
+	  }
+
+	  break;
+	}
+
+      goto unknown_preprocessor_directive;
+
+    case 'p': /* pragma */
+      if(WGOBBLE("pragma"))
+	{
+	  if(OUTP())
+	    STRCAT("#pragma", 7);
+	  else
+	    FIND_EOL();
+	  break;
+	}
+
+    default:
+    unknown_preprocessor_directive:
+      {
+      char buffer[180];
+      int i;
+      for(i=0;i<(long)sizeof(buffer)-1;i++)
+      {
+	if(!isidchar(data[pos])) break;
+	buffer[i]=data[pos++];
+      }
+      buffer[i]=0;
+	
+      cpp_error(this,"Unknown preprocessor directive.");
+      }
+    }
+    }
+  }
+
+  if(flags & CPP_EXPECT_ENDIF)
+    error("End of file while searching for #endif\n");
+
+  return pos;
+}
+
+static INT32 calcC(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  FINDTOK();
+
+/*  DUMPPOS("calcC"); */
+
+  switch(data[pos])
+  {
+  case '(':
+    pos=calc1(this,data,len,pos+1);
+    FINDTOK();
+    if(!GOBBLE(')'))
+      error("Missing ')'\n");
+    break;
+    
+  case '0':
+    if(data[pos+1]=='x' || data[pos+1]=='X')
+    {
+      char *p;
+      push_int(STRTOL(data+pos+2, &p, 16));
+      pos=p-data;
+      break;
+    }
+    
+  case '1': case '2': case '3': case '4':
+  case '5': case '6': case '7': case '8': case '9':
+  {
+    char *p1,*p2;
+    double f;
+    long l;
+    
+    f=my_strtod(data+pos, &p1);
+    l=STRTOL(data+pos, &p2, 0);
+    if(p1 > p2)
+    {
+      push_float(f);
+      pos=p1-data;
+    }else{
+      push_int(l);
+      pos=p2-data;
+    }
+    break;
+  }
+
+  case '\'':
+  {
+    int tmp;
+    READCHAR(tmp);
+    pos++;
+    if(!GOBBLE('\''))
+      error("Missing end quote in character constant.\n");
+    push_int(tmp);
+    break;
+  }
+
+  case '"':
+  {
+    dynamic_buffer s;
+    initialize_buf(&s);
+    READSTRING(s);
+    push_string(low_free_buf(&s));
+    break;
+  }
+  
+  default:
+#ifdef DEBUG
+    if(isidchar(data[pos]))
+      error("Syntax error in #if (should not happen)\n");
+#endif
+
+    error("Syntax error in #if.\n");
+  }
+  
+
+  FINDTOK();
+
+  while(GOBBLE('['))
+  {
+    pos=calc1(this,data,len,pos);
+    f_index(2);
+
+    FINDTOK();
+    if(!GOBBLE(']'))
+      error("Missing ']'");
+  }
+/*   DUMPPOS("after calcC"); */
+  return pos;
+}
+
+static INT32 calcB(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  FINDTOK();
+  switch(data[pos])
+  {
+    case '-': pos++; pos=calcB(this,data,len,pos); o_negate(); break;
+    case '!': pos++; pos=calcB(this,data,len,pos); o_not(); break;
+    case '~': pos++; pos=calcB(this,data,len,pos); o_compl(); break;
+    default: pos=calcC(this,data,len,pos);
+  }
+/*   DUMPPOS("after calcB"); */
+  return pos;
+}
+
+static INT32 calcA(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calcB(this,data,len,pos);
+  while(1)
+  {
+/*     DUMPPOS("inside calcA"); */
+    FINDTOK();
+    switch(data[pos])
+    {
+      case '/':
+	if(data[1]=='/' || data[1]=='*') return pos;
+	pos++;
+	pos=calcB(this,data,len,pos);
+	o_divide();
+	continue;
+
+      case '*':
+	pos++;
+	pos=calcB(this,data,len,pos);
+	o_multiply();
+	continue;
+
+      case '%':
+	pos++;
+	pos=calcB(this,data,len,pos);
+	o_mod();
+	continue;
+    }
+    break;
+  }
+/*   DUMPPOS("after calcA"); */
+  return pos;
+}
+
+static INT32 calc9(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calcA(this,data,len,pos);
+
+  while(1)
+  {
+    FINDTOK();
+    switch(data[pos])
+    {
+      case '+':
+	pos++;
+	pos=calcA(this,data,len,pos);
+	f_add(2);
+	continue;
+
+      case '-':
+	pos++;
+	pos=calcA(this,data,len,pos);
+	o_subtract();
+	continue;
+    }
+    break;
+  }
+
+/*   DUMPPOS("after calc9"); */
+  return pos;
+}
+
+static INT32 calc8(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc9(this,data,len,pos);
+
+  while(1)
+  {
+    FINDTOK();
+    if(GOBBLEOP("<<"))
+    {
+      pos=calc9(this,data,len,pos);
+      o_lsh();
+      break;
+    }
+
+    if(GOBBLEOP(">>"))
+    {
+      pos=calc9(this,data,len,pos);
+      o_rsh();
+      break;
+    }
+
+    break;
+  }
+  return pos;
+}
+
+static INT32 calc7b(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc8(this,data,len,pos);
+
+  while(1)
+  {
+    FINDTOK();
+    
+    switch(data[pos])
+    {
+      case '<':
+	if(data[pos]+1 == '<') break;
+	pos++;
+	if(GOBBLE('='))
+	{
+	   pos=calc8(this,data,len,pos);
+	   f_le(2);
+	}else{
+	   pos=calc8(this,data,len,pos);
+	   f_lt(2);
+	}
+	continue;
+
+      case '>':
+	if(data[pos]+1 == '>') break;
+	pos++;
+	if(GOBBLE('='))
+	{
+	   pos=calc8(this,data,len,pos);
+	   f_ge(2);
+	}else{
+	   pos=calc8(this,data,len,pos);
+	   f_gt(2);
+	}
+	continue;
+    }
+    break;
+  }
+  return pos;
+}
+
+static INT32 calc7(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc7b(this,data,len,pos);
+
+  while(1)
+  {
+    FINDTOK();
+    if(GOBBLEOP("=="))
+    {
+      pos=calc7b(this,data,len,pos);
+      f_eq(2);
+      continue;
+    }
+
+    if(GOBBLEOP("!="))
+    {
+      pos=calc7b(this,data,len,pos);
+      f_ne(2);
+      continue;
+    }
+
+    break;
+  }
+  return pos;
+}
+
+static INT32 calc6(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc7(this,data,len,pos);
+
+  FINDTOK();
+  while(data[pos] == '&' && data[pos+1]!='&')
+  {
+    pos++;
+    pos=calc7(this,data,len,pos);
+    o_and();
+  }
+  return pos;
+}
+
+static INT32 calc5(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc6(this,data,len,pos);
+
+  FINDTOK();
+  while(GOBBLE('^'))
+  {
+    pos=calc6(this,data,len,pos);
+    o_xor();
+  }
+  return pos;
+}
+
+static INT32 calc4(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc5(this,data,len,pos);
+
+  FINDTOK();
+  while(data[pos] == '|' && data[pos+1]!='|')
+  {
+    pos++;
+    pos=calc5(this,data,len,pos);
+    o_or();
+  }
+  return pos;
+}
+
+static INT32 calc3(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc4(this,data,len,pos);
+
+  FINDTOK();
+  while(GOBBLEOP("&&"))
+  {
+    check_destructed(sp-1);
+    if(IS_ZERO(sp-1))
+    {
+      pos=calc4(this,data,len,pos);
+      pop_stack();
+    }else{
+      pop_stack();
+      pos=calc4(this,data,len,pos);
+    }
+  }
+  return pos;
+}
+
+static INT32 calc2(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc3(this,data,len,pos);
+
+  FINDTOK();
+  while(GOBBLEOP("||"))
+  {
+    check_destructed(sp-1);
+    if(!IS_ZERO(sp-1))
+    {
+      pos=calc3(this,data,len,pos);
+      pop_stack();
+    }else{
+      pop_stack();
+      pos=calc3(this,data,len,pos);
+    }
+  }
+  return pos;
+}
+
+static INT32 calc1(struct cpp *this,char *data,INT32 len,INT32 pos)
+{
+  pos=calc2(this,data,len,pos);
+
+  FINDTOK();
+
+  if(GOBBLE('?'))
+  {
+    pos=calc1(this,data,len,pos);
+    if(!GOBBLE(':'))
+      error("Colon expected");
+    pos=calc1(this,data,len,pos);
+
+    check_destructed(sp-3);
+    assign_svalue(sp-3,IS_ZERO(sp-3)?sp-1:sp-2);
+    pop_n_elems(2);
+  }
+  return pos;
+}
+
+static int calc(struct cpp *this,char *data,INT32 len,INT32 tmp)
+{
+  JMP_BUF recovery;
+  INT32 pos;
+
+/*  fprintf(stderr,"Calculating\n"); */
+
+  if (SETJMP(recovery))
+  {
+    pos=tmp;
+    if(throw_value.type == T_ARRAY && throw_value.u.array->size)
+    {
+      union anything *a;
+      a=low_array_get_item_ptr(throw_value.u.array, 0, T_STRING);
+      if(a)
+      {
+	cpp_error(this,a->string->str);
+      }else{
+	cpp_error(this,"Nonstandard error format.");
+      }
+    }else{
+      cpp_error(this,"Nonstandard error format.");
+    }
+    FIND_EOL();
+    push_int(0);
+  }else{
+    pos=calc1(this,data,len,tmp);
+    check_destructed(sp-1);
+  }
+  UNSETJMP(recovery);
+
+/*  fprintf(stderr,"Done\n"); */
+
+  return pos;
+}
+
+void free_one_define(struct hash_entry *h)
+{
+  int e;
+  struct define *d=BASEOF(h, define, link);
+
+  for(e=0;e<d->num_parts;e++)
+    free_string(d->parts[e].postfix);
+  if(d->first)
+    free_string(d->first);
+  free((char *)d);
+}
+
+/*** Magic defines ***/
+static void insert_current_line(struct cpp *this,
+				struct define *def,
+				struct define_argument *args,
+				dynamic_buffer *tmp)
+{
+  char buf[20];
+  sprintf(buf," %ld ",(long)this->current_line);
+  low_my_binary_strcat(buf, strlen(buf),tmp);
+}
+
+static void insert_current_file_as_string(struct cpp *this,
+					  struct define *def,
+					  struct define_argument *args,
+					  dynamic_buffer *tmp)
+{
+  PUSH_STRING(this->current_file->str, this->current_file->len, tmp);
+}
+
+static void insert_current_time_as_string(struct cpp *this,
+					  struct define *def,
+					  struct define_argument *args,
+					  dynamic_buffer *tmp)
+{
+  time_t tmp2;
+  char *buf;
+  time(&tmp2);
+  buf=ctime(&tmp2);
+
+  PUSH_STRING(buf+11, 8, tmp);
+}
+
+static void insert_current_date_as_string(struct cpp *this,
+					  struct define *def,
+					  struct define_argument *args,
+					  dynamic_buffer *tmp)
+{
+  time_t tmp2;
+  char *buf;
+  time(&tmp2);
+  buf=ctime(&tmp2);
+
+  PUSH_STRING(buf+19, 5, tmp);
+  PUSH_STRING(buf+4, 6, tmp);
+}
+
+static void check_defined(struct cpp *this,
+			  struct define *def,
+			  struct define_argument *args,
+			  dynamic_buffer *tmp)
+{
+  struct pike_string *s;
+  s=binary_findstring(args[0].arg, args[0].len);
+  if(s && find_define(s))
+  {
+    low_my_binary_strcat(" 1 ", 3,tmp);
+  }else{
+    low_my_binary_strcat(" 0 ", 3,tmp);
+  }
+}
+
+static int do_safe_index_call(struct pike_string *s);
+
+static void check_constant(struct cpp *this,
+			  struct define *def,
+			  struct define_argument *args,
+			  dynamic_buffer *tmp)
+{
+  struct svalue *sv;
+  char *data=args[0].arg;
+  int res,dlen,len=args[0].len;
+
+  while(len && isspace(data[0])) { data++; len--; }
+
+  if(!len)
+    cpp_error(this,"#if constant() with empty argument.\n");
+
+  for(dlen=0;dlen<len;dlen++)
+    if(!isidchar(data[dlen]))
+      break;
+
+  push_string(binary_findstring(data, dlen));
+  if((sv=low_mapping_string_lookup(get_builtin_constants(),
+				   sp[-1].u.string)))
+  {
+    pop_stack();
+    push_svalue(sv);
+    res=1;
+    low_my_binary_strcat(" 1 ", 3,tmp);
+  }else if(get_master()) {
+    this->current_file->refs++;
+    push_string(this->current_file);
+    SAFE_APPLY_MASTER("resolv",2);
+
+    res=(throw_value.type!=T_STRING) &&
+      (!(IS_ZERO(sp-1) && sp[-1].subtype == NUMBER_UNDEFINED));
+  }else{
+    res=0;
+  }
+
+  while(1)
+  {
+    data+=dlen;
+    len-=dlen;
+  
+    while(len && isspace(data[0])) { data++; len--; }
+
+    if(!len) break;
+
+    if(data[0]=='.')
+    {
+      data++;
+      len--;
+      
+      while(len && isspace(data[0])) { data++; len--; }
+
+      for(dlen=0;dlen<len;dlen++)
+	if(!isidchar(data[dlen]))
+	  break;
+
+      if(res)
+      {
+	res=do_safe_index_call(binary_findstring(data, dlen));
+      }
+    }else{
+      cpp_error(this, "Garbage characters in constant()\n");
+    }
+  }
+    
+
+  low_my_binary_strcat(res?" 1 ":" 0 ", 3,tmp);
+}
+
+
+static int do_safe_index_call(struct pike_string *s)
+{
+  int res;
+  JMP_BUF recovery;
+  
+  if (SETJMP(recovery)) {
+    res = 0;
+  } else {
+    push_string(s);
+    f_index(2);
+    
+    res=!(IS_ZERO(sp-1) && sp[-1].subtype == NUMBER_UNDEFINED);
+  }
+  UNSETJMP(recovery);
+  return res;
+}
+
+
+void f_cpp(INT32 args)
+{
+  struct pike_predef_s *tmpf;
+  struct cpp this;
+  if(args<1)
+    error("Too few arguments to cpp()\n");
+
+  if(sp[-args].type != T_STRING)
+    error("Bad argument 1 to cpp()\n");
+
+  if(args>1)
+  {
+    if(sp[1-args].type != T_STRING)
+      error("Bad argument 2 to cpp()\n");
+    copy_shared_string(this.current_file, sp[1-args].u.string);
+  }else{
+    this.current_file=make_shared_string("-");
+  }
+  
+  initialize_buf(&this.buf);
+  this.current_line=1;
+  this.compile_errors=0;
+  this.defines=0;
+  do_magic_define(&this,"__LINE__",insert_current_line);
+  do_magic_define(&this,"__FILE__",insert_current_file_as_string);
+  do_magic_define(&this,"__DATE__",insert_current_date_as_string);
+  do_magic_define(&this,"__TIME__",insert_current_time_as_string);
+  simple_add_define(&this,"__PIKE__"," 1 ");
+
+  for (tmpf=pike_predefs; tmpf; tmpf=tmpf->next)
+    simple_add_define(&this, tmpf->name, tmpf->value);
+
+  low_my_binary_strcat("# 1 ",4,&this.buf);
+  PUSH_STRING(this.current_file->str,this.current_file->len,&this.buf);
+  low_my_putchar('\n',&this.buf);
+
+  low_cpp(&this, sp[-args].u.string->str, sp[-args].u.string->len,0);
+  if(this.defines)
+    free_hashtable(this.defines, free_one_define);
+
+  if(this.compile_errors)
+  {
+    error("Cpp() failed\n");
+  }else{
+    pop_n_elems(args);
+    free_string(this.current_file);
+    push_string(low_free_buf(&this.buf));
+  }
+}
+
+void init_cpp()
+{
+  defined_macro=alloc_empty_define(make_shared_string("defined"),0);
+  defined_macro->magic=check_defined;
+  defined_macro->args=1;
+
+  constant_macro=alloc_empty_define(make_shared_string("constant"),0);
+  constant_macro->magic=check_constant;
+  constant_macro->args=1;
+
+  add_efun("cpp",f_cpp,"function(string,string|void:string)",OPT_EXTERNAL_DEPEND);
+}
+
+
+void add_predefine(char *s)
+{
+  struct pike_predef_s *tmp=ALLOC_STRUCT(pike_predef_s);
+  char * pos=STRCHR(s,'=');
+  if(pos)
+  {
+    tmp->name=(char *)xalloc(pos-s+1);
+    MEMCPY(tmp->name,s,pos-s);
+    tmp->name[pos-s]=0;
+
+    tmp->value=(char *)xalloc(s+strlen(s)-pos);
+    MEMCPY(tmp->value,pos+1,s+strlen(s)-pos);
+  }else{
+    tmp->name=(char *)xalloc(strlen(s)+1);
+    MEMCPY(tmp->name,s,strlen(s)+1);
+
+    tmp->value=(char *)xalloc(4);
+    MEMCPY(tmp->value," 1 ",4);
+  }
+  tmp->next=pike_predefs;
+  pike_predefs=tmp;
+}
+
+void exit_cpp()
+{
+  struct pike_predef_s *tmp;
+  while((tmp=pike_predefs))
+  {
+    free(tmp->name);
+    free(tmp->value);
+    pike_predefs=tmp->next;
+    free((char *)tmp);
+  }
+}
diff --git a/src/cpp.h b/src/cpp.h
new file mode 100644
index 0000000000..7fcca20dba
--- /dev/null
+++ b/src/cpp.h
@@ -0,0 +1,26 @@
+#ifndef CPP_H
+#define CPP_H
+
+#ifndef STRUCT_HASH_ENTRY_DECLARED
+struct hash_entry;
+#define STRUCT_HASH_ENTRY_DECLARED
+#endif
+
+/* Prototypes begin here */
+struct pike_predef_s;
+struct define_part;
+struct define_argument;
+struct define;
+struct cpp;
+void cpp_error(struct cpp *this,char *err);
+void PUSH_STRING(char *str,
+		 INT32 len,
+		 dynamic_buffer *buf);
+void free_one_define(struct hash_entry *h);
+void f_cpp(INT32 args);
+void init_cpp();
+void add_predefine(char *s);
+void exit_cpp();
+/* Prototypes end here */
+
+#endif
diff --git a/src/fd_control.c b/src/fd_control.c
index 1183cb424d..11d940bca0 100644
--- a/src/fd_control.c
+++ b/src/fd_control.c
@@ -8,6 +8,7 @@
 #ifndef TESTING
 #include "global.h"
 #include "error.h"
+#include "fdlib.h"
 #else
 #undef DEBUG
 #endif
@@ -47,8 +48,8 @@ void set_nonblocking(int fd,int which)
     fatal("Filedescriptor out of range.\n");
 #endif
 
-#ifdef USE_IOCTL_FIONBIO
-  ioctl(fd, FIONBIO, &which);
+#if defined(USE_IOCTL_FIONBIO) || __NT__
+  fd_ioctl(fd, FIONBIO, &which);
 #else
 
 #ifdef USE_FCNTL_O_NDELAY
@@ -63,17 +64,12 @@ void set_nonblocking(int fd,int which)
   fcntl(fd, F_SETFL, which?FNDELAY:0);
 #else
 
-#ifdef USE_IOCTLSOCKET_FIONBIO
-  ioctlsocket(fd, FIONBIO, (void *)&which);
-#else
-
 #error Do not know how to set your filedescriptors nonblocking.
 
 #endif
 #endif
 #endif
 #endif
-#endif
 }
 
 int query_nonblocking(int fd)
diff --git a/src/fdlib.c b/src/fdlib.c
new file mode 100644
index 0000000000..99c68614eb
--- /dev/null
+++ b/src/fdlib.c
@@ -0,0 +1,355 @@
+#include "fdlib.h"
+
+#ifdef HAVE_WINSOCK_H
+
+#define FD_SOCKET -4
+#define FD_CONSOLE -3
+#define FD_FILE -2
+#define FD_NO_MORE_FREE -1
+
+long da_handle[MAX_OPEN_FILEDESCRIPTORS];
+static int fd_type[MAX_OPEN_FILEDESCRIPTORS];
+int first_free_handle;
+
+void fd_init()
+{
+  int e;
+  WSADATA wsadata;
+  
+  if(WSAStartup(MAKEWORD(2,0), &wsadata) != 0)
+  {
+    fatal("No winsock available.\n");
+  }
+/*  fprintf(stderr,"Using %s\n",wsadata.szDescription); */
+  
+  fd_type[0]=FD_CONSOLE;
+  da_handle[0]=GetStdHandle(STD_INPUT_HANDLE);
+  fd_type[1]=FD_CONSOLE;
+  da_handle[1]=GetStdHandle(STD_OUTPUT_HANDLE);
+  fd_type[2]=FD_CONSOLE;
+  da_handle[2]=GetStdHandle(STD_ERROR_HANDLE);
+
+  first_free_handle=3;
+  for(e=3;e<MAX_OPEN_FILEDESCRIPTORS-1;e++)
+    fd_type[e]=e+1;
+  fd_type[e]=FD_NO_MORE_FREE;
+}
+
+void fd_exit()
+{
+  WSACleanup();
+}
+
+FD fd_open(char *file, int open_mode, int create_mode)
+{
+  HANDLE x;
+  FD fd;
+  DWORD omode,cmode,amode;
+  omode=0;
+  if(first_free_handle == FD_NO_MORE_FREE)
+  {
+    errno=EMFILE;
+    return -1;
+  }
+
+  if(open_mode & fd_RDONLY) omode|=GENERIC_READ;
+  if(open_mode & fd_WRONLY) omode|=GENERIC_WRITE;
+  
+  switch(open_mode & (fd_CREAT | fd_TRUNC | fd_EXCL))
+  {
+    case fd_CREAT | fd_TRUNC:
+      cmode=CREATE_ALWAYS;
+      break;
+
+    case fd_TRUNC:
+    case fd_TRUNC | fd_EXCL:
+      cmode=TRUNCATE_EXISTING;
+      break;
+
+    case fd_CREAT:
+      cmode=OPEN_ALWAYS; break;
+
+    case fd_CREAT | fd_EXCL:
+    case fd_CREAT | fd_EXCL | fd_TRUNC:
+      cmode=CREATE_NEW;
+      break;
+
+    case 0:
+    case fd_EXCL:
+      cmode=OPEN_EXISTING;
+      break;
+  }
+
+  if(create_mode & 4)
+  {
+    amode=FILE_ATTRIBUTE_NORMAL;
+  }else{
+    amode=FILE_ATTRIBUTE_READONLY;
+  }
+    
+  x=CreateFile(file,
+	       omode,
+	       FILE_SHARE_READ | FILE_SHARE_WRITE,
+	       NULL,
+	       cmode,
+	       amode,
+	       NULL);
+
+  if(x==INVALID_HANDLE_VALUE)
+  {
+    errno=GetLastError();
+    return -1;
+  }
+
+  fd=first_free_handle;
+  first_free_handle=fd_type[fd];
+  fd_type[fd]=FD_FILE;
+  da_handle[fd]=x;
+
+  return fd;
+}
+
+FD fd_socket(int domain, int type, int proto)
+{
+  FD fd;
+  SOCKET s;
+  if(first_free_handle == FD_NO_MORE_FREE)
+  {
+    errno=EMFILE;
+    return -1;
+  }
+  s=socket(domain, type, proto);
+  if(s==INVALID_SOCKET)
+  {
+    errno=WSAGetLastError();
+    return -1;
+  }
+  
+  fd=first_free_handle;
+  first_free_handle=fd_type[fd];
+  fd_type[fd]=FD_SOCKET;
+  da_handle[fd]=(HANDLE)s;
+
+  return fd;
+}
+
+FD fd_accept(FD fd, struct sockaddr *addr, int *addrlen)
+{
+  FD new_fd;
+  SOCKET s;
+  if(first_free_handle == FD_NO_MORE_FREE)
+  {
+    errno=EMFILE;
+    return -1;
+  }
+  if(fd_type[fd]!=FD_SOCKET)
+  {
+    errno=ENOTSUPP;
+    return -1;
+  }
+  s=accept((SOCKET)da_handle[fd], addr, addrlen);
+  if(s==INVALID_SOCKET)
+  {
+    errno=WSAGetLastError();
+    return -1;
+  }
+  
+  fd=first_free_handle;
+  first_free_handle=fd_type[fd];
+  fd_type[fd]=FD_SOCKET;
+  da_handle[fd]=(HANDLE)s;
+  return fd;
+}
+
+#define SOCKFUN(NAME,X1,X2) \
+int PIKE_CONCAT(fd_,NAME) X1 { int ret; \
+  if(fd_type[fd] != FD_SOCKET) { \
+     errno=ENOTSUPP; \
+     return -1; \
+   } \
+   ret=NAME X2; \
+   if(ret == SOCKET_ERROR) errno=WSAGetLastError(); \
+   return ret; \
+}
+
+#define SOCKFUN1(NAME,T1) \
+   SOCKFUN(NAME, (FD fd, T1 a), ((SOCKET)da_handle[fd], a) )
+
+#define SOCKFUN2(NAME,T1,T2) \
+   SOCKFUN(NAME, (FD fd, T1 a, T2 b), ((SOCKET)da_handle[fd], a, b) )
+
+#define SOCKFUN3(NAME,T1,T2,T3) \
+   SOCKFUN(NAME, (FD fd, T1 a, T2 b, T3 c), ((SOCKET)da_handle[fd], a, b, c) )
+
+#define SOCKFUN4(NAME,T1,T2,T3,T4) \
+   SOCKFUN(NAME, (FD fd,T1 a,T2 b,T3 c,T4 d), ((SOCKET)da_handle[fd],a,b,c,d) )
+
+#define SOCKFUN5(NAME,T1,T2,T3,T4,T5) \
+   SOCKFUN(NAME, (FD fd,T1 a,T2 b,T3 c,T4 d,T5 e), ((SOCKET)da_handle[fd],a,b,c,d,e))
+
+
+SOCKFUN2(bind, struct sockaddr *, int)
+SOCKFUN2(connect, struct sockaddr *, int)
+SOCKFUN4(getsockopt,int,int,void*,int*)
+SOCKFUN4(setsockopt,int,int,void*,int)
+SOCKFUN2(getsockname,struct sockaddr *,int*)
+SOCKFUN2(getpeername,struct sockaddr *,int*)
+SOCKFUN3(recv,void *,int,int)
+SOCKFUN5(recvfrom,void *,int,int,struct sockaddr *,int*)
+SOCKFUN5(sendto,void *,int,int,struct sockaddr *,int*)
+SOCKFUN1(shutdown, int)
+SOCKFUN1(listen, int)
+
+int fd_close(FD fd)
+{
+  if(!CloseHandle(da_handle[fd]))
+  {
+    errno=GetLastError();
+    return -1;
+  }
+  fd_type[fd]=first_free_handle;
+  first_free_handle=fd;
+  return 0;
+}
+
+long fd_write(FD fd, void *buf, long len)
+{
+  DWORD ret;
+  switch(fd_type[fd])
+  {
+    case FD_SOCKET:
+      ret=send((SOCKET)da_handle[fd], buf, len, 0);
+      if(ret<0)
+      {
+	errno=WSAGetLastError();
+	return -1;
+      }
+      return ret;
+
+    case FD_CONSOLE:
+    case FD_FILE:
+      if(!WriteFile(da_handle[fd], buf, len, &ret,0) && !ret)
+      {
+	errno=GetLastError();
+	return -1;
+      }
+      return ret;
+
+    default:
+      errno=ENOTSUPP;
+      return -1;
+  }
+}
+
+long fd_read(FD fd, void *buf, long len)
+{
+  DWORD ret;
+  switch(fd_type[fd])
+  {
+    case FD_SOCKET:
+      ret=recv((SOCKET)da_handle[fd], buf, len, 0);
+      if(ret<0)
+      {
+	errno=WSAGetLastError();
+	return -1;
+      }
+      return ret;
+
+    case FD_CONSOLE:
+    case FD_FILE:
+      if(!ReadFile(da_handle[fd], buf, len, &ret,0) && !ret)
+      {
+	errno=GetLastError();
+	return -1;
+      }
+      return ret;
+
+    default:
+      errno=ENOTSUPP;
+      return -1;
+  }
+}
+
+long fd_lseek(FD fd, long pos, int where)
+{
+  long ret;
+  if(fd_type[fd]!=FD_FILE)
+  {
+    errno=ENOTSUPP;
+    return -1;
+  }
+
+  ret=LZSeek(da_handle[fd], pos, where);
+  if(ret<0)
+  {
+    errno=GetLastError();
+    return -1;
+  }
+  return ret;
+}
+
+int fd_fstat(FD fd, struct stat *s)
+{
+  int ret;
+  if(fd_type[fd]!=FD_FILE)
+  {
+    errno=ENOTSUPP;
+    return -1;
+  }
+
+  ret=fstat(da_handle[fd], s);
+  if(ret<0)
+  {
+    errno=GetLastError();
+    return -1;
+  }
+  return ret;
+}
+
+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 fd)
+{
+  errno=ENOTSUPP;
+  return -1;
+}
+
+FD fd_dup2(FD to, FD from)
+{
+  errno=ENOTSUPP;
+  return -1;
+}
+
+#endif
diff --git a/src/fdlib.h b/src/fdlib.h
new file mode 100644
index 0000000000..1159c41d05
--- /dev/null
+++ b/src/fdlib.h
@@ -0,0 +1,157 @@
+#ifndef FDLIB_H
+#define FDLIB_H
+
+#include "global.h"
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_WINSOCK_H
+
+
+#ifndef FD_SETSIZE
+#define FD_SETSIZE MAX_OPEN_FILEDESCRIPTORS
+#endif
+
+#include <winsock.h>
+#include <winbase.h>
+
+typedef int FD;
+
+#define SOCKFUN1(NAME,T1) int PIKE_CONCAT(fd_,NAME) (FD,T1);
+#define SOCKFUN2(NAME,T1,T2) int PIKE_CONCAT(fd_,NAME) (FD,T1,T2);
+#define SOCKFUN3(NAME,T1,T2,T3) int PIKE_CONCAT(fd_,NAME) (FD,T1,T2,T3);
+#define SOCKFUN4(NAME,T1,T2,T3,T4) int PIKE_CONCAT(fd_,NAME) (FD,T1,T2,T3,T4);
+#define SOCKFUN5(NAME,T1,T2,T3,T4,T5) int PIKE_CONCAT(fd_,NAME) (FD,T1,T2,T3,T4,T5);
+
+/* Prototypes begin here */
+void fd_init();
+void fd_exit();
+FD fd_open(char *file, int open_mode, int create_mode);
+FD fd_socket(int domain, int type, int proto);
+FD fd_accept(FD fd, struct sockaddr *addr, int *addrlen);
+SOCKFUN2(bind, struct sockaddr *, int)
+SOCKFUN2(connect, struct sockaddr *, int)
+SOCKFUN4(getsockopt,int,int,void*,int*)
+SOCKFUN4(setsockopt,int,int,void*,int)
+SOCKFUN2(getsockname,struct sockaddr *,int*)
+SOCKFUN2(getpeername,struct sockaddr *,int*)
+SOCKFUN3(recv,void *,int,int)
+SOCKFUN5(recvfrom,void *,int,int,struct sockaddr *,int*)
+SOCKFUN5(sendto,void *,int,int,struct sockaddr *,int*)
+SOCKFUN1(shutdown, int)
+SOCKFUN1(listen, int)
+int fd_close(FD fd);
+long fd_write(FD fd, void *buf, long len);
+long fd_read(FD fd, void *buf, long len);
+long fd_lseek(FD fd, long pos, int where);
+int fd_fstat(FD fd, struct stat *s);
+int fd_select(int fds, FD_SET *a, FD_SET *b, FD_SET *c, struct timeval *t);
+int fd_ioctl(FD fd, int cmd, void *data);
+FD fd_dup(FD fd);
+FD fd_dup2(FD to, FD from);
+/* Prototypes end here */
+
+#undef SOCKFUN1
+#undef SOCKFUN2
+#undef SOCKFUN3
+#undef SOCKFUN4
+#undef SOCKFUN5
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+#ifndef EWOULDBLOCK
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+
+#ifndef EADDRINUSE
+#define EADDRINUSE WSAEADDRINUSE
+#endif
+
+#ifndef ENOTSUPP
+#define ENOTSUPP WSAEOPNOTSUPP
+#endif
+
+#define fd_RDONLY 1
+#define fd_WRONLY 2
+#define fd_RDWR 3
+#define fd_APPEND 4
+#define fd_CREAT 8
+#define fd_TRUNC 16
+#define fd_EXCL 32
+
+#define fd_shutdown_read SD_RECEIVE
+#define fd_shutdown_write SD_SEND
+#define fd_shutdown_both SD_BOTH
+
+extern long da_handle[MAX_OPEN_FILEDESCRIPTORS];
+
+#define fd_FD_CLR(X,Y) FD_CLR((SOCKET)da_handle[X],Y)
+#define fd_FD_SET(X,Y) FD_SET((SOCKET)da_handle[X],Y)
+#define fd_FD_ISSET(X,Y) FD_ISSET((SOCKET)da_handle[X],Y)
+#define fd_FD_ZERO(X) FD_ZERO(X)
+
+#else
+
+
+typedef int FD;
+
+#define fd_init()
+#define fd_exit()
+
+#define fd_RDONLY O_RDONLY
+#define fd_WRONLY O_WRONLY
+#define fd_RDWR O_RDWR
+#define fd_APPEND O_APPEND
+#define fd_CREAT O_CREAT
+#define fd_TRUNC O_TRUC
+#define fd_EXCL O_EXCL
+
+#define fd_open open
+#define fd_close close
+#define fd_read read
+#define fd_write write
+#define fd_ioctl ioctl
+
+#define fd_socket socket
+#define fd_bind bind
+#define fd_connect connect
+#define fd_getsockopt getsockopt
+#define fd_setsockopt setsockopt
+#define fd_getsockname getsockname
+#define fd_getpeername getpeername
+#define fd_recv recv
+#define fd_sendto sendto
+#define fd_recvfrom recvfrom
+#define fd_shutdown shutdown
+#define fd_accept accept
+#define fd_lseek lseek
+#define fd_fstat fstat
+#define fd_dup dup
+#define fd_dup2 dup2
+#define fd_listen listen
+
+#define fd_select select
+#define fd_FD_CLR FD_CLR
+#define fd_FD_SET FD_SET
+#define fd_FD_ISSET FD_ISSET
+#define fd_FD_ZERO FD_ZERO
+
+#define fd_shutdown_read 0
+#define fd_shutdown_write 1
+#define fd_shutdown_both 2
+
+#endif
+
+#endif
diff --git a/src/fsort.c b/src/fsort.c
index 71256c7121..a463b22779 100644
--- a/src/fsort.c
+++ b/src/fsort.c
@@ -14,7 +14,7 @@ static long size;
 static char *tmp_area;
 
 #define SWAP(X,Y) { tmp=*(X); *(X)=*(Y); *(Y)=tmp; }
-#define STEP(X,Y) ((X)+(Y))
+#define STEP(X,Y) (&((X)[(Y)]))
 
 #define ID fsort_1
 typedef struct a1 { char b[1]; } b1;
diff --git a/src/fsort_template.h b/src/fsort_template.h
index 6c0e9fc612..0f1ba47a2f 100644
--- a/src/fsort_template.h
+++ b/src/fsort_template.h
@@ -1,6 +1,6 @@
 #define INC(X) X=STEP(X,1)
 #define DEC(X) X=STEP(X,-1)
-#define SIZE ((long)STEP((TYPE *)0,1))
+#define SIZE ((long)(char *)STEP((TYPE *)0,1))
 
 static void ID(register TYPE *bas, register TYPE *last)
 {
diff --git a/src/lex.c b/src/lex.c
index d877f0e32e..859bbfabdd 100644
--- a/src/lex.c
+++ b/src/lex.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: lex.c,v 1.35 1997/12/23 06:26:07 hubbe Exp $");
+RCSID("$Id: lex.c,v 1.36 1998/01/02 01:05:47 hubbe Exp $");
 #include "language.h"
 #include "array.h"
 #include "lex.h"
@@ -52,7 +52,7 @@ struct pike_predef_s
   struct pike_predef_s *next;
 };
 
-struct pike_predef_s *pike_predefs=0;
+static struct pike_predef_s *pike_predefs=0;
 
 static int calc(void);
 static void calc1(void);
@@ -797,7 +797,7 @@ static void simple_add_define(char *name,char *as,void (*magic)(void))
   }
 }
 
-void free_one_define(struct hash_entry *h)
+static void free_one_define(struct hash_entry *h)
 {
   struct define *d;
   d=BASEOF(h, define, link);
@@ -2195,21 +2195,21 @@ static int calc(void)
 }
 
 /*** Magic defines ***/
-void insert_current_line(void)
+static void insert_current_line(void)
 {
   char buf[20];
   sprintf(buf," %ld ",(long)current_line);
   UNGETSTR(buf,strlen(buf));
 }
 
-void insert_current_file_as_string(void)
+static void insert_current_file_as_string(void)
 {
   UNGETSTR("\"",1);
   UNGETSTR(current_file->str, current_file->len);
   UNGETSTR("\"",1);
 }
 
-void insert_current_time_as_string(void)
+static void insert_current_time_as_string(void)
 {
   time_t tmp;
   char *buf;
@@ -2221,7 +2221,7 @@ void insert_current_time_as_string(void)
   UNGETSTR("\"",1);
 }
 
-void insert_current_date_as_string(void)
+static void insert_current_date_as_string(void)
 {
   time_t tmp;
   char *buf;
@@ -2294,6 +2294,7 @@ void end_new_file(void)
 }
 
 
+#if 0
 void add_predefine(char *s)
 {
   char buffer1[100],buffer2[10000];
@@ -2314,3 +2315,4 @@ void add_predefine(char *s)
   tmp->next=pike_predefs;
   pike_predefs=tmp;
 }
+#endif
diff --git a/src/lex.h b/src/lex.h
index e74f2a789f..f26e42c470 100644
--- a/src/lex.h
+++ b/src/lex.h
@@ -78,10 +78,6 @@ char *get_token_name(int n);
 struct inputstate;
 struct define;
 void free_one_define(struct hash_entry *h);
-void insert_current_line(void);
-void insert_current_file_as_string(void);
-void insert_current_time_as_string(void);
-void insert_current_date_as_string(void);
 void start_new_file(int fd,struct pike_string *filename);
 void start_new_string(char *s,INT32 len,struct pike_string *name);
 void end_new_file(void);
diff --git a/src/main.c b/src/main.c
index aafafd9593..c4c53ef9c9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -4,7 +4,8 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: main.c,v 1.28 1997/12/28 09:29:10 hubbe Exp $");
+RCSID("$Id: main.c,v 1.29 1998/01/02 01:05:48 hubbe Exp $");
+#include "fdlib.h"
 #include "backend.h"
 #include "module.h"
 #include "object.h"
@@ -22,6 +23,11 @@ RCSID("$Id: main.c,v 1.28 1997/12/28 09:29:10 hubbe Exp $");
 #include "dynamic_load.h"
 #include "gc.h"
 #include "mapping.h"
+#include "cpp.h"
+
+#ifdef HAVE_WINSOCK_H
+#include "winsock.h"
+#endif
 
 #include <errno.h>
 
@@ -56,7 +62,7 @@ struct callback *add_post_master_callback(callback_func call,
 }
 
 
-void main(int argc, char **argv, char **env)
+void main(int argc, char **argv)
 {
   JMP_BUF back;
   int e, num;
@@ -65,12 +71,15 @@ void main(int argc, char **argv, char **env)
 
   ARGV=argv;
 
-#ifndef __NT__
-  /* Close extra fds (if any) */
-  for (e=3; e < MAX_OPEN_FILEDESCRIPTORS; e++) {
-    do {
-      num = close(e);
-    } while ((num < 0) && (errno == EINTR));
+  fd_init();
+
+#ifdef HAVE_WINSOCK_H
+  {
+    WSADATA wsadata;
+    if(WSAStartup(MAKEWORD(2,0), &wsadata) != 0)
+    {
+      fatal("No winsock available.\n");
+    }
   }
 #endif
 
@@ -218,6 +227,7 @@ void main(int argc, char **argv, char **env)
 
   init_shared_string_table();
   init_interpreter();
+  init_cpp();
   init_lex();
   init_types();
 
@@ -234,11 +244,11 @@ void main(int argc, char **argv, char **env)
   }
   push_array(a);
 
-  for(num=0;env[num];num++);
+  for(num=0;environ[num];num++);
   a=allocate_array_no_init(num,0);
-  for(num=0;env[num];num++)
+  for(num=0;environ[num];num++)
   {
-    ITEM(a)[num].u.string=make_shared_string(env[num]);
+    ITEM(a)[num].u.string=make_shared_string(environ[num]);
     ITEM(a)[num].type=T_STRING;
   }
   push_array(a);
@@ -294,6 +304,7 @@ void low_exit_main(void)
   exit_dynamic_load();
   exit_signals();
   exit_lex();
+  exit_cpp();
   cleanup_interpret();
   cleanup_added_efuns();
   cleanup_pike_types();
diff --git a/src/modules/files/file.c b/src/modules/files/file.c
index 47721c4f1d..2953bf0776 100644
--- a/src/modules/files/file.c
+++ b/src/modules/files/file.c
@@ -6,7 +6,8 @@
 #define READ_BUFFER 8192
 
 #include "global.h"
-RCSID("$Id: file.c,v 1.62 1997/12/23 06:26:10 hubbe Exp $");
+RCSID("$Id: file.c,v 1.63 1998/01/02 01:06:33 hubbe Exp $");
+#include "fdlib.h"
 #include "interpret.h"
 #include "svalue.h"
 #include "stralloc.h"
@@ -147,7 +148,7 @@ static int close_fd(int fd)
     {
       int i;
       THREADS_ALLOW();
-      i=close(fd);
+      i=fd_close(fd);
       THREADS_DISALLOW();
       
       if(i < 0)
@@ -161,7 +162,7 @@ static int close_fd(int fd)
 	  /* Try waiting it out in blocking mode */
 	  set_nonblocking(fd,0);
 	  THREADS_ALLOW();
-	  i=close(fd);
+	  i=fd_close(fd);
 	  THREADS_DISALLOW();
 	  if(i>= 0 || errno==EBADF)  break; /* It was actually closed, good! */
 	  
@@ -513,7 +514,7 @@ static int do_close(int fd, int flags)
     if(files[fd].open_mode & FILE_WRITE)
     {
       set_read_callback(fd,0,0);
-      shutdown(fd, 0);
+      fd_shutdown(fd, 0);
       files[fd].open_mode &=~ FILE_READ;
       return 0;
     }else{
@@ -525,7 +526,7 @@ static int do_close(int fd, int flags)
     if(files[fd].open_mode & FILE_READ)
     {
       set_write_callback(fd,0,0);
-      shutdown(fd, 1);
+      fd_shutdown(fd, 1);
       files[fd].open_mode &=~ FILE_WRITE;
       return 0;
     }else{
@@ -595,7 +596,7 @@ static void file_open(INT32 args)
 
   THREADS_ALLOW();
   do {
-    fd=open(str->str,map(flags), access);
+    fd=fd_open(str->str,map(flags), access);
   } while(fd < 0 && errno == EINTR);
   THREADS_DISALLOW();
 
@@ -639,7 +640,7 @@ static void file_seek(INT32 args)
 
   ERRNO=0;
 
-  to=lseek(FD,to,to<0 ? SEEK_END : SEEK_SET);
+  to=fd_lseek(FD,to,to<0 ? SEEK_END : SEEK_SET);
 
   if(to<0) ERRNO=errno;
 
@@ -655,7 +656,7 @@ static void file_tell(INT32 args)
     error("File not open.\n");
   
   ERRNO=0;
-  to=lseek(FD, 0L, SEEK_CUR);
+  to=fd_lseek(FD, 0L, SEEK_CUR);
 
   if(to<0) ERRNO=errno;
 
@@ -680,7 +681,7 @@ static void file_stat(INT32 args)
 
  retry:
   THREADS_ALLOW();
-  tmp=fstat(fd, &s);
+  tmp=fd_fstat(fd, &s);
   THREADS_DISALLOW();
 
   if(tmp < 0)
@@ -708,7 +709,7 @@ static void file_errno(INT32 args)
 static struct pike_string *simple_do_read(INT32 *amount,int fd)
 {
   char buffer[READ_BUFFER];
-  *amount = read(fd, buffer, READ_BUFFER);
+  *amount = fd_read(fd, buffer, READ_BUFFER);
   if(*amount>0) return make_shared_binary_string(buffer,*amount);
   return 0;
 }
@@ -961,13 +962,13 @@ static void file_set_buffer(INT32 args)
   if(flags & FILE_READ)
   {
     int tmp=bufsize;
-    setsockopt(FD,SOL_SOCKET, SO_RCVBUF, (char *)&tmp, sizeof(tmp));
+    fd_setsockopt(FD,SOL_SOCKET, SO_RCVBUF, (char *)&tmp, sizeof(tmp));
   }
 
   if(flags & FILE_WRITE)
   {
     int tmp=bufsize;
-    setsockopt(FD,SOL_SOCKET, SO_SNDBUF, (char *)&tmp, sizeof(tmp));
+    fd_setsockopt(FD,SOL_SOCKET, SO_SNDBUF, (char *)&tmp, sizeof(tmp));
   }
 #endif
 }
@@ -1014,67 +1015,72 @@ int my_socketpair(int family, int type, int protocol, int sv[2])
 
   if(fd==-1)
   {
-    if((fd=socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1;
+    if((fd=fd_socket(AF_INET, SOCK_STREAM, 0)) < 0) return -1;
     
     /* I wonder what is most common a loopback on ip# 127.0.0.1 or
      * a loopback with the name "localhost"?
      * Let's hope those few people who don't have socketpair have
      * a loopback on 127.0.0.1
      */
+    MEMSET((char *)&my_addr,0,sizeof(struct sockaddr_in));
+    my_addr.sin_family=AF_INET;
     my_addr.sin_addr.s_addr=htonl(INADDR_ANY);
     my_addr.sin_port=htons(0);
-    
+
+
     /* Bind our sockets on any port */
-    if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+    if(fd_bind(fd, (struct sockaddr *)&my_addr, sizeof(addr)) < 0)
     {
-      close(fd);
+      fd_close(fd);
       fd=-1;
       return -1;
     }
 
     /* Check what ports we got.. */
     len=sizeof(my_addr);
-    if(getsockname(fd,(struct sockaddr *)&my_addr,&len) < 0)
+    if(fd_getsockname(fd,(struct sockaddr *)&my_addr,&len) < 0)
     {
-      close(fd);
+      fd_close(fd);
       fd=-1;
       return -1;
     }
 
     /* Listen to connections on our new socket */
-    if(listen(fd, 5) < 0)
+    if(fd_listen(fd, 5) < 0)
     {
-      close(fd);
+      fd_close(fd);
       fd=-1;
       return -1;
     }
+
+    my_addr.sin_addr.s_addr=inet_addr("127.0.0.1");
   }
   
-  if((sv[1]=socket(AF_INET, SOCK_STREAM, 0)) <0) return -1;
 
-  addr.sin_addr.s_addr=inet_addr("127.0.0.1");
+  if((sv[1]=fd_socket(AF_INET, SOCK_STREAM, 0)) <0) return -1;
 
 /*  set_nonblocking(sv[1],1); */
-  
-  if(connect(sv[1], (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
+
+  if(fd_connect(sv[1], (struct sockaddr *)&my_addr, sizeof(addr)) < 0)
   {
     int tmp2;
     for(tmp2=0;tmp2<20;tmp2++)
     {
       int tmp;
       len=sizeof(addr);
-      tmp=accept(fd,(struct sockaddr *)&addr,&len);
+      tmp=fd_accept(fd,(struct sockaddr *)&addr,&len);
 
-      if(tmp!=-1) close(tmp);
-      if(connect(sv[1], (struct sockaddr *)&my_addr, sizeof(my_addr))>=0)
+      if(tmp!=-1) fd_close(tmp);
+      if(fd_connect(sv[1], (struct sockaddr *)&my_addr, sizeof(my_addr))>=0)
 	break;
     }
     if(tmp2>=20)
       return -1;
   }
 
+
   len=sizeof(addr);
-  if(getsockname(sv[1],(struct sockaddr *)&addr2,&len) < 0) return -1;
+  if(fd_getsockname(sv[1],(struct sockaddr *)&addr2,&len) < 0) return -1;
 
   /* Accept connection
    * Make sure this connection was our OWN connection,
@@ -1086,22 +1092,23 @@ int my_socketpair(int family, int type, int protocol, int sv[2])
   do
   {
     len=sizeof(addr);
-    sv[0]=accept(fd,(struct sockaddr *)&addr,&len);
+    sv[0]=fd_accept(fd,(struct sockaddr *)&addr,&len);
 
     if(sv[0] < 0) {
-      close(sv[1]);
+      fd_close(sv[1]);
       return -1;
     }
 
     /* We do not trust accept */
     len=sizeof(addr);
-    if(getpeername(sv[0], (struct sockaddr *)&addr,&len)) return -1;
+    if(fd_getpeername(sv[0], (struct sockaddr *)&addr,&len)) return -1;
   }while(len < (int)sizeof(addr) ||
 	 addr2.sin_addr.s_addr != addr.sin_addr.s_addr ||
 	 addr2.sin_port != addr.sin_port);
 
 /*   set_nonblocking(sv[1],0); */
 
+
   return 0;
 }
 
@@ -1149,8 +1156,8 @@ static void file_pipe(INT32 args)
 	  (inout[1] >= MAX_OPEN_FILEDESCRIPTORS))
   {
     ERRNO=EBADF;
-    close(inout[0]);
-    close(inout[1]);
+    fd_close(inout[0]);
+    fd_close(inout[1]);
     push_int(0);
   }
   else
@@ -1302,7 +1309,7 @@ static void file_open_socket(INT32 args)
 
   do_close(FD, FILE_READ | FILE_WRITE);
   FD=-1;
-  fd=socket(AF_INET, SOCK_STREAM, 0);
+  fd=fd_socket(AF_INET, SOCK_STREAM, 0);
   if(fd >= MAX_OPEN_FILEDESCRIPTORS)
   {
     ERRNO=EBADF;
@@ -1323,7 +1330,7 @@ static void file_open_socket(INT32 args)
     int o;
 
     if (sp[-args].type != T_INT) {
-      close(fd);
+      fd_close(fd);
       error("Bad argument 1 to open_socket(), expected int\n");
     }
     if (args > 1) {
@@ -1339,14 +1346,14 @@ static void file_open_socket(INT32 args)
     addr.sin_port = htons( ((u_short)sp[-args].u.integer) );
 
     o=1;
-    if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(int)) < 0) {
+    if(fd_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(int)) < 0) {
       ERRNO=errno;
       close(fd);
       pop_n_elems(args);
       push_int(0);
       return;
     }
-    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+    if (fd_bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
       ERRNO=errno;
       close(fd);
       pop_n_elems(args);
@@ -1369,7 +1376,7 @@ static void file_set_keepalive(INT32 args)
   int tmp, i;
   check_all_args("file->set_keepalive",args, T_INT,0);
   tmp=sp[-args].u.integer;
-  i=setsockopt(FD,SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
+  i=fd_setsockopt(FD,SOL_SOCKET, SO_KEEPALIVE, (char *)&tmp, sizeof(tmp));
   if(i)
   {
     ERRNO=errno;
@@ -1407,7 +1414,7 @@ static void file_connect(INT32 args)
 
   tmp=FD;
   THREADS_ALLOW();
-  tmp=connect(tmp, (struct sockaddr *)&addr, sizeof(addr));
+  tmp=fd_connect(tmp, (struct sockaddr *)&addr, sizeof(addr));
   THREADS_DISALLOW();
 
   if(tmp < 0)
@@ -1458,9 +1465,9 @@ static void file_query_address(INT32 args)
   len=sizeof(addr);
   if(args > 0 && !IS_ZERO(sp-args))
   {
-    i=getsockname(FD,(struct sockaddr *)&addr,&len);
+    i=fd_getsockname(FD,(struct sockaddr *)&addr,&len);
   }else{
-    i=getpeername(FD,(struct sockaddr *)&addr,&len);
+    i=fd_getpeername(FD,(struct sockaddr *)&addr,&len);
   }
   pop_n_elems(args);
   if(i < 0 || len < (int)sizeof(addr))
diff --git a/src/modules/files/socket.c b/src/modules/files/socket.c
index 5ed4210345..ce609254b9 100644
--- a/src/modules/files/socket.c
+++ b/src/modules/files/socket.c
@@ -4,6 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
+#include "fdlib.h"
 #include "interpret.h"
 #include "svalue.h"
 #include "stralloc.h"
@@ -73,7 +74,7 @@ static void do_close(struct port *p, struct object *o)
  retry:
   if(p->fd >= 0)
   {
-    if(close(p->fd) < 0)
+    if(fd_close(p->fd) < 0)
       if(errno == EINTR)
 	goto retry;
 
@@ -141,7 +142,7 @@ static void port_listen_fd(INT32 args)
     return;
   }
 
-  if(listen(fd, 16384) < 0)
+  if(fd_listen(fd, 16384) < 0)
   {
     THIS->my_errno=errno;
     pop_n_elems(args);
@@ -180,7 +181,7 @@ static void port_bind(INT32 args)
   if(sp[-args].type != T_INT)
     error("Bad argument 1 to port->bind()\n");
 
-  fd=socket(AF_INET, SOCK_STREAM, 0);
+  fd=fd_socket(AF_INET, SOCK_STREAM, 0);
 
   if(fd < 0)
   {
@@ -192,14 +193,14 @@ static void port_bind(INT32 args)
   if(fd >= MAX_OPEN_FILEDESCRIPTORS)
   {
     THIS->my_errno=EBADF;
-    close(fd);
+    fd_close(fd);
     pop_n_elems(args);
     push_int(0);
     return;
   }
 
   o=1;
-  if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(int)) < 0)
+  if(fd_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(int)) < 0)
   {
     THIS->my_errno=errno;
     close(fd);
@@ -222,13 +223,13 @@ static void port_bind(INT32 args)
   addr.sin_family = AF_INET;
 
   THREADS_ALLOW();
-  tmp=bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 || listen(fd, 16384) < 0;
+  tmp=fd_bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0 || listen(fd, 16384) < 0;
   THREADS_DISALLOW();
 
   if(tmp)
   {
     THIS->my_errno=errno;
-    close(fd);
+    fd_close(fd);
     pop_n_elems(args);
     push_int(0);
     return;
@@ -270,7 +271,7 @@ static void port_create(INT32 args)
       do_close(THIS,fp->current_object);
       THIS->fd=0;
 
-      if(listen(THIS->fd, 16384) < 0)
+      if(fd_listen(THIS->fd, 16384) < 0)
       {
 	THIS->my_errno=errno;
       }else{
@@ -304,7 +305,7 @@ static void port_accept(INT32 args)
 
 
   THREADS_ALLOW();
-  fd=accept(this->fd, 0, &len);
+  fd=fd_accept(this->fd, 0, &len);
   THREADS_DISALLOW();
 
   if(fd < 0)
@@ -319,7 +320,7 @@ static void port_accept(INT32 args)
     THIS->my_errno=EBADF;
     pop_n_elems(args);
     push_int(0);
-    close(fd);
+    fd_close(fd);
     return;
   }
 
@@ -340,7 +341,7 @@ static void socket_query_address(INT32 args)
     error("socket->query_address(): Socket not bound yet.\n");
 
   len=sizeof(addr);
-  i=getsockname(THIS->fd,(struct sockaddr *)&addr,&len);
+  i=fd_getsockname(THIS->fd,(struct sockaddr *)&addr,&len);
   pop_n_elems(args);
   if(i < 0 || len < (int)sizeof(addr))
   {
diff --git a/src/modules/readline/readlinemod.c b/src/modules/readline/readlinemod.c
index d77e7d8819..cb7418fd04 100644
--- a/src/modules/readline/readlinemod.c
+++ b/src/modules/readline/readlinemod.c
@@ -58,10 +58,20 @@ static void f_readline(INT32 args)
     error("Bad argument 1 to readline()\n");
 
   str=sp[-args].u.string;
+retry:
   THREADS_ALLOW();
   r=readline(str->str);
   THREADS_DISALLOW();
 
+#ifdef _REENTRANT
+  /* Kluge! /Hubbe */
+  if(!r && errno==EINTR)
+  {
+    check_threads_etc();
+    goto retry;
+  }
+#endif
+
   pop_n_elems(args);
   if(r)
   {
diff --git a/src/object.c b/src/object.c
index ee5160f98c..fa6d5ef972 100644
--- a/src/object.c
+++ b/src/object.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: object.c,v 1.29 1997/11/08 01:34:42 hubbe Exp $");
+RCSID("$Id: object.c,v 1.30 1998/01/02 01:05:48 hubbe Exp $");
 #include "object.h"
 #include "dynamic_buffer.h"
 #include "interpret.h"
@@ -431,9 +431,9 @@ void object_index_no_free(struct svalue *to,
 }
 
 
-static void object_low_set_index(struct object *o,
-				 int f,
-				 struct svalue *from)
+void object_low_set_index(struct object *o,
+			  int f,
+			  struct svalue *from)
 {
   struct identifier *i;
   struct program *p;
diff --git a/src/object.h b/src/object.h
index b184357d31..90bf3280e8 100644
--- a/src/object.h
+++ b/src/object.h
@@ -54,6 +54,9 @@ void object_index_no_free2(struct svalue *to,
 void object_index_no_free(struct svalue *to,
 			   struct object *o,
 			   struct svalue *index);
+void object_low_set_index(struct object *o,
+			  int f,
+			  struct svalue *from);
 void object_set_index2(struct object *o,
 		      struct svalue *index,
 		      struct svalue *from);
diff --git a/src/port.c b/src/port.c
index 3f2e45e0ad..4c9d28a907 100644
--- a/src/port.c
+++ b/src/port.c
@@ -20,12 +20,30 @@ time_t time PROT((time_t *));
 #endif
 
 #ifndef HAVE_GETTIMEOFDAY
+
+#ifdef HAVE_GETSYSTEMTIMEASFILETIME
+#include <winbase.h>
+
+void GETTIMEOFDAY(struct timeval *t)
+{
+  double t;
+  FILETIME tmp;
+  GetSystemTimeAsFileTime(&tmp);
+  t=tmp.dwHighDateTime * pow(2.0,32) + (double)tmp.dwLowDateTime;
+  t/=10000000.0;
+  t+=11644473600.0;
+  t->tv_sec=floor(t);
+  t->tv_usec=(t - t->tv_sec)*1000000.0;
+}
+
+#else
 void GETTIMEOFDAY(struct timeval *t)
 {
   t->tv_sec=(long)time(0);
   t->tv_usec=0;
 }
 #endif
+#endif
 
 #ifndef HAVE_TIME
 time_t TIME(time_t *t)
diff --git a/src/program.c b/src/program.c
index 791f3ddfe3..da209785ff 100644
--- a/src/program.c
+++ b/src/program.c
@@ -4,7 +4,7 @@
 ||| See the files COPYING and DISCLAIMER for more information.
 \*/
 #include "global.h"
-RCSID("$Id: program.c,v 1.46 1997/11/08 01:34:43 hubbe Exp $");
+RCSID("$Id: program.c,v 1.47 1998/01/02 01:05:51 hubbe Exp $");
 #include "program.h"
 #include "object.h"
 #include "dynamic_buffer.h"
@@ -1094,6 +1094,22 @@ int define_variable(struct pike_string *name,
   return n;
 }
 
+int simple_add_variable(char *name,
+			char *type,
+			INT32 flags)
+{
+  INT32 ret;
+  struct pike_string *name_s, *type_s;
+  name_s=make_shared_string(name);
+  type_s=parse_type(type);
+  
+  ret=define_variable(name_s, type_s, flags);
+  free_string(name_s);
+  free_string(type_s);
+  return ret;
+}
+
+
 int add_constant(struct pike_string *name,
 		 struct svalue *c,
 		 INT32 flags)
diff --git a/src/program.h b/src/program.h
index 82c6fe9a20..d545499b18 100644
--- a/src/program.h
+++ b/src/program.h
@@ -233,6 +233,9 @@ int map_variable(char *name,
 int define_variable(struct pike_string *name,
 		    struct pike_string *type,
 		    INT32 flags);
+int simple_add_variable(char *name,
+			char *type,
+			INT32 flags);
 int add_constant(struct pike_string *name,
 		 struct svalue *c,
 		 INT32 flags);
diff --git a/src/stuff.c b/src/stuff.c
index 3f999acabc..9a72d3351a 100644
--- a/src/stuff.c
+++ b/src/stuff.c
@@ -108,3 +108,14 @@ int is_more_than_one_bit(unsigned INT32 x)
          ((x & 0xff00ff00UL) && (x & 0x00ff00ffUL)) ||
          ((x & 0xffff0000UL) && (x & 0x0000ffffUL));
 }
+
+double my_strtod(char *nptr, char **endptr)
+{
+  double tmp=STRTOD(nptr,endptr);
+  if(*endptr>nptr)
+  {
+    if(endptr[0][-1]=='.')
+      endptr[0]--;
+  }
+  return tmp;
+}
diff --git a/src/stuff.h b/src/stuff.h
index a277b5aca2..9b534da1ff 100644
--- a/src/stuff.h
+++ b/src/stuff.h
@@ -12,6 +12,7 @@
 int my_log2(unsigned INT32 x);
 int count_bits(unsigned INT32 x);
 int is_more_than_one_bit(unsigned INT32 x);
+double my_strtod(char *nptr, char **endptr);
 /* Prototypes end here */
 
 extern INT32 hashprimes[32];
diff --git a/src/threads.c b/src/threads.c
index 6b5caf684b..487f5c970a 100644
--- a/src/threads.c
+++ b/src/threads.c
@@ -1,5 +1,5 @@
 #include "global.h"
-RCSID("$Id: threads.c,v 1.47 1997/11/11 04:02:45 grubba Exp $");
+RCSID("$Id: threads.c,v 1.48 1998/01/02 01:05:54 hubbe Exp $");
 
 int num_threads = 1;
 int threads_disabled = 0;
@@ -15,8 +15,11 @@ int threads_disabled = 0;
 #include "program.h"
 #include "gc.h"
 
+#define THIS_THREAD ((struct thread_state *)fp->current_storage)
+
 struct object *thread_id;
 static struct callback *threads_evaluator_callback=0;
+int thread_id_result_variable;
 
 MUTEX_T interpreter_lock;
 struct program *mutex_key = 0;
@@ -73,9 +76,17 @@ void *new_thread_func(void * data)
     push_array_items(arg.args);
     arg.args=0;
     f_call_function(args);
-    pop_stack(); /* Discard the return value. /Per */
+
+    /* copy return value to the thread_id here */
+    object_low_set_index(thread_id,
+			 thread_id_result_variable,
+			 sp-1);
+    pop_stack();
   }
 
+   ((struct thread_state *)(thread_id->storage))->status=THREAD_EXITED;
+   co_signal(& ((struct thread_state *)(thread_id->storage))->status_change);
+
   free((char *)data); /* Moved by per, to avoid some bugs.... */
   UNSETJMP(back);
 
@@ -110,6 +121,7 @@ void f_thread_create(INT32 args)
   arg=ALLOC_STRUCT(thread_starter);
   arg->args=aggregate_array(args);
   arg->id=clone_object(thread_id_prog,0);
+  ((struct thread_state *)arg->id->storage)->status=THREAD_RUNNING;
 
   tmp=th_create(&dummy,new_thread_func,arg);
 
@@ -395,9 +407,40 @@ void f_thread_backtrace(INT32 args)
   }
 }
 
+void f_thread_id_status(INT32 args)
+{
+  pop_n_elems(args);
+  push_int(THIS_THREAD->status);
+}
+
+static void f_thread_id_result(INT32 args)
+{
+  struct thread_state *th=THIS_THREAD;
+
+  SWAP_OUT_CURRENT_THREAD();
+
+  while(th->status != THREAD_EXITED)
+    co_wait(&th->status_change, &interpreter_lock);
+
+  SWAP_IN_CURRENT_THREAD();
+
+  low_object_index_no_free(sp,
+			   fp->current_object, 
+			   thread_id_result_variable);
+  sp++;
+}
+
 void init_thread_obj(struct object *o)
 {
   MEMSET(o->storage, 0, sizeof(struct thread_state));
+  THIS_THREAD->status=THREAD_NOT_STARTED;
+  co_init(& THIS_THREAD->status_change);
+}
+
+
+void exit_thread_obj(struct object *o)
+{
+  co_destroy(& THIS_THREAD->status_change);
 }
 
 #ifdef DEBUG
@@ -481,11 +524,15 @@ void th_init(void)
 
   start_new_program();
   add_storage(sizeof(struct thread_state));
+  thread_id_result_variable=simple_add_variable("result","mixed",0);
   add_function("backtrace",f_thread_backtrace,"function(:array)",0);
+  add_function("wait",f_thread_id_result,"function(:mixed)",0);
+  add_function("status",f_thread_id_status,"function(:int)",0);
 #ifdef DEBUG
   set_gc_mark_callback(thread_was_marked);
 #endif
   set_init_callback(init_thread_obj);
+  set_init_callback(exit_thread_obj);
   thread_id_prog=end_program();
   if(!mutex_key)
     fatal("Failed to initialize thread program!\n");
diff --git a/src/threads.h b/src/threads.h
index d89c7cd2a6..6f6dc16604 100644
--- a/src/threads.h
+++ b/src/threads.h
@@ -157,8 +157,16 @@ extern MUTEX_T interpreter_lock;
 struct svalue;
 struct frame;
 
+#define THREAD_NOT_STARTED -1
+#define THREAD_RUNNING 0
+#define THREAD_EXITED 1
+
 struct thread_state {
-  int swapped;
+  char swapped;
+  char status;
+  COND_T status_change;
+
+  /* Swapped variables */
   struct svalue *sp,*evaluator_stack;
   struct svalue **mark_sp,**mark_stack;
   struct frame *fp;
diff --git a/src/time_stuff.h b/src/time_stuff.h
index 49900b51bc..459adef8d4 100644
--- a/src/time_stuff.h
+++ b/src/time_stuff.h
@@ -23,7 +23,6 @@
 
 #ifdef HAVE_WINSOCK_H
 # include <winsock.h>
-# undef HAVE_WINSOCK_H
 #endif
 
 #undef HAVE_SYS_TIME_H
-- 
GitLab