diff --git a/src/configure.in b/src/configure.in
index 62edf4fedd3195bfe2c6d9a563adf298be348386..67f0eeba883bd98ed5edf26373be96dc9cf35e4b 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1,4 +1,4 @@
-AC_REVISION("$Id: configure.in,v 1.150 1998/01/14 01:30:23 hubbe Exp $")
+AC_REVISION("$Id: configure.in,v 1.151 1998/01/16 21:40:13 hubbe Exp $")
 AC_INIT(interpret.c)
 AC_CONFIG_HEADER(machine.h)
 
@@ -951,6 +951,8 @@ AC_CHECK_FUNCS( \
  alarm \
  fork \
  fork1 \
+ setuid getuid seteuid geteuid \
+ setgid getgid setegid getegid \
 )
 
 if test $ac_cv_func_crypt$ac_cv_func__crypt = nono ; then
diff --git a/src/cpp.c b/src/cpp.c
index f7c13bb0f2baffa6d6f0fc9905aa30ffb9a1f4de..108c52f89aac5a5cab3060db3007c0600208a5ad 100644
--- a/src/cpp.c
+++ b/src/cpp.c
@@ -32,6 +32,7 @@
 #define CPP_REALLY_NO_OUTPUT 8
 #define CPP_END_AT_NEWLINE 16
 #define CPP_DO_IF 32
+#define CPP_NO_EXPAND 64
 
 #define OUTP() (!(flags & (CPP_NO_OUTPUT | CPP_REALLY_NO_OUTPUT)))
 #define PUTNL() low_my_putchar('\n', &this->buf)
@@ -222,7 +223,7 @@ static void simple_add_define(struct cpp *this,
   int e=0;							\
   while(1)							\
   {								\
-    if(pos+1>=len)						\
+    if(pos>=len)						\
     {								\
       cpp_error(this,"End of file in character constant.");	\
       break;							\
@@ -259,10 +260,10 @@ static void simple_add_define(struct cpp *this,
     while(pos < len && data[pos]!='\n') pos++;	\
   } while(0)
 
-#define SKIPWHITE() do {			\
-    if(!isspace(data[pos])) break;		\
-    PUTNL();					\
-    pos++;					\
+#define SKIPWHITE() do {					\
+    if(!isspace(data[pos])) break;				\
+    if(data[pos]=='\n') { PUTNL(); this->current_line++; }	\
+    pos++;							\
   } while(0)
 
 #define SKIPSPACE() \
@@ -1763,6 +1764,49 @@ static void check_defined(struct cpp *this,
   }
 }
 
+static void dumpdef(struct cpp *this,
+		    struct define *def,
+		    struct define_argument *args,
+		    dynamic_buffer *tmp)
+{
+  struct pike_string *s;
+  struct define *d;
+  s=binary_findstring(args[0].arg, args[0].len);
+  if(s && (d=find_define(s)))
+  {
+    int e;
+    char buffer[42];
+    PUSH_STRING(d->link.s->str,d->link.s->len, tmp);
+    if(d->magic)
+    {
+      low_my_binary_strcat(" defined magically ",19, tmp);
+    }else{
+      low_my_binary_strcat(" defined as ",12, tmp);
+      
+      if(d->first)
+	PUSH_STRING(d->first->str, d->first->len, tmp);
+      for(e=0;e<d->num_parts;e++)
+      {
+	if(!(d->parts[e].argument & DEF_ARG_NOPRESPACE))
+	  low_my_putchar(' ',tmp);
+	
+	if(d->parts[e].argument & DEF_ARG_STRINGIFY)
+	  low_my_putchar('#',tmp);
+	
+	sprintf(buffer,"%ld",(long)(d->parts[e].argument & DEF_ARG_MASK));
+	
+	if(!(d->parts[e].argument & DEF_ARG_NOPOSTSPACE))
+	  low_my_putchar(' ',tmp);
+	
+	low_my_binary_strcat(buffer,strlen(buffer), tmp);
+	PUSH_STRING(d->parts[e].postfix->str, d->parts[e].postfix->len, 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,
@@ -1882,6 +1926,13 @@ void f_cpp(INT32 args)
   do_magic_define(&this,"__DATE__",insert_current_date_as_string);
   do_magic_define(&this,"__TIME__",insert_current_time_as_string);
 
+  {
+    struct define* def=alloc_empty_define(make_shared_string("__dumpdef"),0);
+    def->magic=dumpdef;
+    def->args=1;
+    this.defines=hash_insert(this.defines, & def->link);
+  }
+
   simple_add_define(&this,"__PIKE__"," 1 ");
 #ifdef __NT__
   simple_add_define(&this,"__NT__"," 1 ");
diff --git a/src/signal_handler.c b/src/signal_handler.c
index 31737f078565d7b7a31afff3e2fcc9551905b49c..265e5df035a75fd313b8fb568843a4682861bfe0 100644
--- a/src/signal_handler.c
+++ b/src/signal_handler.c
@@ -17,6 +17,8 @@
 #include "threads.h"
 #include "signal_handler.h"
 #include "module_support.h"
+#include "operators.h"
+#include "builtin_functions.h"
 #include <signal.h>
 
 #ifdef HAVE_WINBASE_H
@@ -535,6 +537,7 @@ void f_create_process(INT32 args)
     int ret;
     TCHAR *filename=NULL, *command_line=NULL, *dir=NULL;
     struct pike_string *p1,*p2;
+    void *env=NULL;
 
 
     /* FIX QUOTING LATER */
@@ -566,6 +569,38 @@ void f_create_process(INT32 args)
       t3=get_inheritable_handle(optional, "stderr");
       if(t3!=INVALID_HANDLE_VALUE) info.hStdError=t3;
 
+	if((tmp=simple_mapping_string_lookup(optional, "env")))
+	{
+	  if(tmp->type == T_MAPPING)
+	  {
+	    struct mapping *m=tmp->u.mapping;
+	    struct array *i,*v;
+	    int ptr=0;
+	    i=mapping_indices(m);
+	    v=mapping_indices(m);
+
+	    for(e=0;e<i->size;e++)
+	    {
+	      if(ITEM(i)[e].type == T_STRING && ITEM(v)[e].type == T_STRING)
+	      {
+		check_stack(3);
+		push_string(ITEM(i)[e].u.string);
+		push_string(make_shared_string("="));
+		push_string(ITEM(v)[e].u.string);
+		f_add(3);
+		ptr++;
+	      }
+	    }
+	    free_array(i);
+	    free_array(v);
+	    push_string(make_shared_binary_string("\0\0",1));
+	    f_aggregate(ptr+1);
+	    push_string(make_shared_binary_string("\0\0",1));
+	    o_multiply();
+	    env=(void *)sp[-1].u.string->str;
+	  }
+	}
+
       /* FIX: env, cleanup */
     }
 
@@ -576,7 +611,7 @@ void f_create_process(INT32 args)
 		      NULL,  /* thread security attribute */
 		      1,     /* inherithandles */
 		      0,     /* create flags */
-		      NULL,  /* environment */
+		      env,  /* environment */
 		      dir,   /* current dir */
 		      &info,
 		      &proc);
@@ -585,6 +620,7 @@ void f_create_process(INT32 args)
     if(dir) free((char *)dir);
     if(command_line) free((char *)command_line);
     if(filename) free((char *)filename);
+    if(env) pop_stack();
 
 #if 1
     if(t1!=INVALID_HANDLE_VALUE) CloseHandle(t1);
@@ -625,10 +661,12 @@ void f_create_process(INT32 args)
       mapping_insert(pid_mapping,sp-1, sp-2);
       pop_n_elems(2);
     }else{
+      int euid;
       char **argv;
 #ifdef DECLARE_ENVIRON
       extern char **environ;
 #endif
+      char **env;
       extern void my_set_close_on_exec(int,int);
       extern void do_set_close_on_exec(void);
 
@@ -645,17 +683,91 @@ void f_create_process(INT32 args)
 	argv[e]=ITEM(cmd)[e].u.string->str;
       
       argv[e]=0;
-      
+
+      euid=geteuid();
+
       if(optional)
       {
 	int toclose[3];
 	int fd;
 
+#ifdef HAVE_SETGID
+	if((tmp=simple_mapping_string_lookup(optional, "gid")))
+	{
+	  if(tmp->type == T_INT)
+	  {
+#ifdef HAVE_SETEUID
+	    seteuid(0);
+#endif
+	    if(!setgid(tmp->u.integer)
+#ifdef HAVE_SETEGID
+	       || !setegid(tmp->u.integer)
+#endif
+		 )
+	    {
+	      exit(69);
+	    }
+	  }
+	}
+#endif
+
+#ifdef HAVE_SETUID
+	if((tmp=simple_mapping_string_lookup(optional, "uid")))
+	{
+	  if(tmp->type == T_INT)
+	  {
+#ifdef HAVE_SETEUID
+	    seteuid(0);
+#endif
+	    if(!setuid(euid=tmp->u.integer) 
+#ifdef HAVE_SETEUID
+	       || ! seteuid(tmp->u.integer)
+#endif
+	      )
+	    {
+	      exit(69);
+	    }
+	  }
+	}
+#endif
+
 	if((tmp=simple_mapping_string_lookup(optional, "cwd")))
 	  if(tmp->type == T_STRING)
 	    if(!chdir(tmp->u.string->str))
 	      exit(69);
 
+
+	if((tmp=simple_mapping_string_lookup(optional, "env")))
+	{
+	  if(tmp->type == T_MAPPING)
+	  {
+	    struct mapping *m=tmp->u.mapping;
+	    struct array *i,*v;
+	    int ptr=0;
+	    i=mapping_indices(m);
+	    v=mapping_indices(m);
+
+	    env=(char **)xalloc((1+m_sizeof(m)) * sizeof(char *));
+	    for(e=0;e<i->size;e++)
+	    {
+	      if(ITEM(i)[e].type == T_STRING &&
+		 ITEM(v)[e].type == T_STRING)
+	      {
+		check_stack(3);
+		push_string(ITEM(i)[e].u.string);
+		push_string(make_shared_string("="));
+		push_string(ITEM(v)[e].u.string);
+		f_add(3);
+		env[ptr++]=sp[-1].u.string->str;
+	      }
+	    }
+	    env[ptr++]=0;
+	    free_array(i);
+	    free_array(v);
+	    environ=env;
+	  }
+	}
+
 	for(fd=0;fd<3;fd++)
 	{
 	  char *fdname;
@@ -689,11 +801,18 @@ void f_create_process(INT32 args)
 	  if(f2 == fd)
 	    close(toclose[fd]);
 	}
-	
-	/* Left to do: env, cleanup */
+
+	/* Left to do: cleanup? */
       }
-      
-      
+
+#if defined(HAVE_SETEUID) && defined(HAVE_GETEUID) && defined(HAVE_SETUID) && defined(HAVE_SETEUID)
+      /* Protect us from harm */
+      seteuid(0);
+      setgid(geteuid());
+      setuid(euid);
+      seteuid(euid);
+#endif
+
       my_set_close_on_exec(0,0);
       my_set_close_on_exec(1,0);
       my_set_close_on_exec(2,0);
diff --git a/src/testsuite.in b/src/testsuite.in
index d25d1e73db21614be3e387192f86223cd85cb20e..3f5e3c781cda611c2c80e49c276cb1f9bd9e52b2 100644
--- a/src/testsuite.in
+++ b/src/testsuite.in
@@ -1,4 +1,4 @@
-test_true([["$Id: testsuite.in,v 1.64 1998/01/13 22:56:51 hubbe Exp $"]])
+test_true([["$Id: testsuite.in,v 1.65 1998/01/16 21:40:17 hubbe Exp $"]])
 test_eq(1e1,10.0)
 test_eq(1E1,10.0)
 test_eq(1e+1,10.0)
@@ -6,7 +6,8 @@ test_eq(1.1e1,11.0)
 test_eq(1e-1,0.1)
 test_eq('\x20',32)
 test_eq("\x20","\040")
-
+test_eq(cpp("#define FOO(X,Y) (X) (Y)\nFOO( (A),(B) )"),"# 1 \"-\"\n\n( (A) ) ( (B) )")
+test_eq(cpp("#define F 'F'\nF"),"# 1 \"-\"\n\n'F'")
 
 test_any([[object o=class foo{int c;class bar{void create(){c++;};}}(); o->bar(); return o->c;]],1)
 test_do([[add_constant("GURKA2",class foo { int c; class bar{void create() {c+=17;}}}()); ]])