diff --git a/.gitattributes b/.gitattributes
index 48324099e0a5eb1aab9afd5cda258f00e56336f0..44186f8b6176abf31022ef38914483c37d6340fd 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -20,6 +20,7 @@ testfont binary
 /bin/mkpeep.pike foreign_ident
 /bin/test_pike.pike foreign_ident
 /lib/master.pike foreign_ident
+/lib/master.pike.in foreign_ident
 /lib/modules/ADT.pmod/Table.pmod foreign_ident
 /lib/modules/ADT.pmod/queue.pike foreign_ident
 /lib/modules/ADT.pmod/struct.pike foreign_ident
diff --git a/lib/master.pike.in b/lib/master.pike.in
new file mode 100644
index 0000000000000000000000000000000000000000..be9a242d2e77a9307b750a1681c30beb6a2e778c
--- /dev/null
+++ b/lib/master.pike.in
@@ -0,0 +1,838 @@
+/* $Id: master.pike.in,v 1.1 1998/03/28 16:36:56 grubba Exp $
+ *
+ * Master-file for Pike.
+ *
+ * Based on master.pike 1.67.
+ */
+
+int is_absolute_path(string p)
+{
+#ifdef __NT__
+  p=replace(p,"\\","/");
+  if(sscanf(p,"%[a-zA-Z]:",string s) && sizeof(s)==1)
+    return 1;
+#endif
+  return p[0]=='/';
+}
+
+string *explode_path(string p)
+{
+#ifdef __NT__
+  p=replace(p,"\\","/");
+#endif
+  return p/"/";
+}
+
+string dirname(string x)
+{
+  string *tmp=explode_path(x);
+  return tmp[..sizeof(tmp)-2]*"/";
+}
+
+string basename(string x)
+{
+  string *tmp=explode_path(x);
+  return tmp[-1];
+}
+
+
+#define GETCWD_CACHE
+#define FILE_STAT_CACHE
+
+#define UNDEFINED (([])[0])
+#define error(X) throw( ({ (X), backtrace()[0..sizeof(backtrace())-2] }) )
+
+string describe_backtrace(mixed *trace);
+object low_cast_to_object(string oname, string current_file);
+
+string _master_file_name;
+string pike_library_path;
+string *pike_include_path=({});
+string *pike_module_path=({});
+string *pike_program_path=({});
+int want_warnings;
+
+program compile_string(string data, void|string name)
+{
+  return compile(cpp(data,name||"-"));
+}
+
+program compile_file(string file)
+{
+  return compile(cpp(_static_modules.files()->file(file,"r")->read(),file));
+}
+
+
+#ifdef GETCWD_CACHE
+string current_path;
+int cd(string s)
+{
+  current_path=0;
+  return predef::cd(s);
+}
+
+string getcwd()
+{
+  return current_path || (current_path=predef::getcwd());
+}
+#endif
+
+string combine_path_with_cwd(string path)
+{
+  return combine_path(is_absolute_path(path)?"/":getcwd(),path);
+}
+
+#ifdef FILE_STAT_CACHE
+
+#define FILE_STAT_CACHE_TIME 20
+
+int invalidate_time;
+mapping(string:multiset(string)) dir_cache = ([]);
+
+mixed *master_file_stat(string x)
+{
+  string file, dir=combine_path_with_cwd(x);
+
+  file=basename(dir);
+  dir=dirname(dir);
+
+  multiset(string) d;
+  if(time() > invalidate_time)
+  {
+    dir_cache=([]);
+    invalidate_time=time()+FILE_STAT_CACHE_TIME;
+  }
+  if(zero_type(d=dir_cache[dir]))
+  {
+    if(string *tmp=get_dir(dir))
+    {
+      d=dir_cache[dir]=aggregate_multiset(@tmp);
+    }else{
+      dir_cache[dir]=0;
+    }
+  }
+  
+  if(d && !d[file]) return 0;
+
+  return predef::file_stat(x);
+}
+#else
+#define master_file_stat file_stat
+#endif
+
+mapping (string:string) environment=([]);
+
+
+mixed getenv(string|void s)
+{
+  if(!s) return environment;
+  return environment[s];
+}
+
+void putenv(string var, string val)
+{
+  environment[var]=val;
+}
+
+
+void add_include_path(string tmp)
+{
+  tmp=combine_path_with_cwd(tmp);
+  pike_include_path-=({tmp});
+  pike_include_path=({tmp})+pike_include_path;
+}
+
+void remove_include_path(string tmp)
+{
+  tmp=combine_path_with_cwd(tmp);
+  pike_include_path-=({tmp});
+}
+
+void add_module_path(string tmp)
+{
+  tmp=combine_path_with_cwd(tmp);
+  pike_module_path-=({tmp});
+  pike_module_path=({tmp})+pike_module_path;
+}
+
+
+void remove_module_path(string tmp)
+{
+  tmp=combine_path_with_cwd(tmp);
+  pike_module_path-=({tmp});
+}
+
+
+void add_program_path(string tmp)
+{
+  tmp=combine_path_with_cwd(tmp);
+  pike_program_path-=({tmp});
+  pike_program_path=({tmp})+pike_program_path;
+}
+
+
+void remove_program_path(string tmp)
+{
+  tmp=combine_path_with_cwd(tmp);
+  pike_program_path-=({tmp});
+}
+
+
+mapping (string:program) programs=(["/master":object_program(this_object())]);
+
+#define capitalize(X) (upper_case((X)[..0])+(X)[1..])
+
+static program low_findprog(string pname, string ext)
+{
+  program ret;
+  array s;
+  string fname=pname+ext;
+  if(ret=programs[fname]) return ret;
+  if( (s=master_file_stat(fname)) 
+      && s[1]>=0 )
+  {
+    switch(ext)
+    {
+    case "":
+    case ".pike":
+      if ( mixed e=catch { ret=compile_file(fname); } )
+      {
+	if(arrayp(e) &&
+	   sizeof(e)==2 &&
+	   arrayp(e[1]) &&
+	   sizeof(e[1]) == sizeof(backtrace()))
+	  e[1]=({});
+	throw(e);
+      }
+      break;
+#if constant(load_module)
+    case ".so":
+      ret=load_module(fname);
+#endif /* load_module */
+    }
+    return programs[fname]=ret;
+  }else{
+    return UNDEFINED;
+  }
+}
+
+static program findprog(string pname, string ext)
+{
+  switch(ext)
+  {
+  case ".pike":
+  case ".so":
+    return low_findprog(pname,ext);
+
+  default:
+    pname+=ext;
+    return
+      low_findprog(pname,"") ||
+      low_findprog(pname,".pike") ||
+      low_findprog(pname,".so");
+  }
+}
+
+/* This function is called when the driver wants to cast a string
+ * to a program, this might be because of an explicit cast, an inherit
+ * or a implict cast. In the future it might receive more arguments,
+ * to aid the master finding the right program.
+ */
+program cast_to_program(string pname, string current_file)
+{
+  string ext;
+  string nname;
+  array(string) tmp=explode_path(pname);
+
+  if(sscanf(reverse(tmp[-1]),"%s.%s",ext, nname))
+  {
+    ext="."+reverse(ext);
+    tmp[-1]=reverse(nname);
+    pname=tmp*"/";
+  }else{
+    ext="";
+  }
+  if(is_absolute_path(pname))
+  {
+    pname=combine_path("/",pname);
+    return findprog(pname,ext);
+  }else{
+    string cwd;
+    if(current_file)
+    {
+      cwd=dirname(current_file);
+    }else{
+      cwd=getcwd();
+    }
+
+    if(program ret=findprog(combine_path(cwd,pname),ext))
+      return ret;
+
+    foreach(pike_program_path, string path)
+      if(program ret=findprog(combine_path(path,pname),ext))
+	return ret;
+
+    return 0;
+  }
+}
+
+/* This function is called when an error occurs that is not caught
+ * with catch(). It's argument consists of:
+ * ({ error_string, backtrace }) where backtrace is the output from the
+ * backtrace() efun.
+ */
+void handle_error(mixed *trace)
+{
+  predef::trace(0);
+  werror(describe_backtrace(trace));
+}
+
+object new(mixed prog, mixed ... args)
+{
+  if(stringp(prog))
+    prog=cast_to_program(prog,backtrace()[-2][0]);
+  return prog(@args);
+}
+
+/* Note that create is called before add_precompiled_program
+ */
+void create()
+{
+  add_constant("basename",basename);
+  add_constant("dirname",dirname);
+  add_constant("is_absolute_path",is_absolute_path);
+  add_constant("explode_path",explode_path);
+
+  add_constant("compile_string",compile_string);
+  add_constant("compile_file",compile_file);
+  add_constant("add_include_path",add_include_path);
+  add_constant("remove_include_path",remove_include_path);
+  add_constant("add_module_path",add_module_path);
+  add_constant("remove_module_path",remove_module_path);
+  add_constant("add_program_path",add_program_path);
+  add_constant("remove_program_path",remove_program_path);
+  add_constant("describe_backtrace",describe_backtrace);
+  add_constant("mkmultiset",lambda(mixed *a) { return aggregate_multiset(@a); });
+  add_constant("strlen",sizeof);
+  add_constant("new",new);
+  add_constant("clone",new);
+  add_constant("UNDEFINED",UNDEFINED);
+
+#ifdef GETCWD_CACHE
+  add_constant("cd",cd);
+  add_constant("getcwd",getcwd);
+#endif
+
+  random_seed(time() + (getpid() * 0x11111111));
+}
+
+/*
+ * This function is called whenever a inherit is called for.
+ * It is supposed to return the program to inherit.
+ * The first argument is the argument given to inherit, and the second
+ * is the file name of the program currently compiling. Note that the
+ * file name can be changed with #line, or set by compile_string, so
+ * it can not be 100% trusted to be a filename.
+ * previous_object(), can be virtually anything in this function, as it
+ * is called from the compiler.
+ */
+program handle_inherit(string pname, string current_file)
+{
+  return cast_to_program(pname, current_file);
+}
+
+mapping (program:object) objects=([object_program(this_object()):this_object()]);
+
+object low_cast_to_object(string oname, string current_file)
+{
+  program p;
+  object o;
+
+  p=cast_to_program(oname, current_file);
+  if(!p) return 0;
+  if(!(o=objects[p])) o=objects[p]=p();
+  return o;
+}
+
+/* This function is called when the drivers wants to cast a string
+ * to an object because of an implict or explicit cast. This function
+ * may also receive more arguments in the future.
+ */
+object cast_to_object(string oname, string current_file)
+{
+  if(object o=low_cast_to_object(oname, current_file))
+    return o;
+  error("Cast to object failed\n");
+}
+
+class dirnode
+{
+  string dirname;
+  object tm;
+  mixed module;
+  mapping cache=([]);
+
+  void create(string name, object the_master)
+  {
+    dirname=name;
+    tm=the_master;
+
+    if(module=tm->findmodule(dirname+"/module"))
+      if(mixed tmp=module->_module_value)
+	module=tmp;
+  }
+
+  object|program ind(string index)
+  {
+    if(module) if(object o=module[index]) return o;
+
+    index = dirname+"/"+index;
+    if(object o=tm->findmodule(index))
+    {
+      if(mixed tmp=o->_module_value) o=tmp;
+      return o;
+    }
+    return (program) index;
+  }
+
+  object|program `[](string index)
+  {
+    mixed ret;
+    if(!zero_type(ret=cache[index]))
+    {
+      if(ret) return ret;
+      return UNDEFINED;
+    }
+    return cache[index]=ind(index);
+  }
+};
+
+static mapping(string:mixed) fc=([]);
+
+object findmodule(string fullname)
+{
+  mixed *stat;
+  object o;
+  if(!zero_type(o=fc[fullname]))
+  {
+    return o;
+  }
+
+  if(mixed *stat=master_file_stat(fullname+".pmod"))
+  {
+    if(stat[1]==-2)
+      return fc[fullname]=dirnode(fullname+".pmod",this_object());
+  }
+
+  if(o=low_cast_to_object(fullname+".pmod","/."))
+    return fc[fullname]=o;
+    
+#if constant(load_module)
+  if(master_file_stat(fullname+".so"))
+    return fc[fullname]=low_cast_to_object(fullname,"/.");
+#endif
+
+  return fc[fullname]=UNDEFINED;
+}
+
+mixed resolv(string identifier, string|void current_file)
+{
+  mixed ret;
+  string *tmp,path;
+
+  if(current_file)
+  {
+    tmp=explode_path(current_file);
+    tmp[-1]=identifier;
+    path=combine_path_with_cwd( tmp*"/");
+    ret=findmodule(path);
+  }
+
+  if(!ret)
+  {
+    foreach(pike_module_path, path)
+      {
+	string file=combine_path(path,identifier);
+	if(ret=findmodule(file)) break;
+      }
+    
+    if(!ret)
+    {
+      string path=combine_path(pike_library_path+"/modules",identifier);
+      ret=findmodule(path);
+    }
+  }
+
+
+  if(ret)
+  {
+    if(mixed tmp=ret->_module_value) ret=tmp;
+    return ret;
+  }
+  return UNDEFINED;
+}
+
+/* This function is called when all the driver is done with all setup
+ * of modules, efuns, tables etc. etc. and is ready to start executing
+ * _real_ programs. It receives the arguments not meant for the driver
+ * and an array containing the environment variables on the same form as
+ * a C program receives them.
+ */
+void _main(string *argv, string *env)
+{
+  int i;
+  object script;
+  object tmp;
+  string a,b;
+  mixed *q;
+
+  foreach(env,a) if(sscanf(a,"%s=%s",a,b)) environment[a]=b;
+  add_constant("getenv",getenv);
+  add_constant("putenv",putenv);
+
+  add_constant("write",_static_modules.files()->file("stdout")->write);
+
+  _master_file_name=backtrace()[-1][0];
+  q=explode_path(_master_file_name);
+  pike_library_path = combine_path_with_cwd(q[0..sizeof(q)-2] * "/");
+
+  add_include_path(pike_library_path+"/include");
+  add_module_path(pike_library_path+"/modules");
+
+  a = replace(pike_library_path+"/", "/lib/", "/share/");
+  if (a != pike_library_path+"/") {
+    array st;
+    if ((st = file_stat(a)) && (sizeof(st)) && (st[1] == -2)) {
+      add_include_path(a+"/include");
+      add_module_path(a+"/modules");
+    }
+  }
+
+  add_program_path(getcwd());
+  add_module_path(getcwd());
+
+  _master_file_name=combine_path(getcwd(), _master_file_name);
+
+  q=(getenv("PIKE_INCLUDE_PATH")||"")/":"-({""});
+  for(i=sizeof(q)-1;i>=0;i--) add_include_path(q[i]);
+
+  q=(getenv("PIKE_PROGRAM_PATH")||"")/":"-({""});
+  for(i=sizeof(q)-1;i>=0;i--) add_program_path(q[i]);
+
+  q=(getenv("PIKE_MODULE_PATH")||"")/":"-({""});
+  for(i=sizeof(q)-1;i>=0;i--) add_module_path(q[i]);
+
+  
+  if(sizeof(argv)>1 && sizeof(argv[1]) && argv[1][0]=='-')
+  {
+    tmp=resolv("Getopt");
+    
+    q=tmp->find_all_options(argv,({
+      ({"version",tmp->NO_ARG,({"-v","--version"})}),
+	({"help",tmp->NO_ARG,({"-h","--help"})}),
+	  ({"execute",tmp->HAS_ARG,({"-e","--execute"})}),
+	    ({"modpath",tmp->HAS_ARG,({"-M","--module-path"})}),
+	      ({"ipath",tmp->HAS_ARG,({"-I","--include-path"})}),
+		({"ppath",tmp->HAS_ARG,({"-P","--program-path"})}),
+		  ({"warnings",tmp->NO_ARG,({"-w","--warnings"})}),
+		    ({"ignore",tmp->HAS_ARG,"-ms"}),
+		      ({"ignore",tmp->MAY_HAVE_ARG,"-Ddatpl",0,1})
+			}), 1);
+    
+    /* Parse -M and -I backwards */
+    for(i=sizeof(q)-1;i>=0;i--)
+    {
+      switch(q[i][0])
+      {
+      case "modpath":
+	add_module_path(q[i][1]);
+	break;
+	
+      case "ipath":
+	add_include_path(q[i][1]);
+	break;
+	
+      case "ppath":
+	add_program_path(q[i][1]);
+	break;
+
+	case "warnings":
+	want_warnings++;
+	break;
+      }
+    }
+    
+    foreach(q, mixed *opts)
+    {
+      switch(opts[0])
+      {
+      case "version":
+	werror(version() + " Copyright (C) 1994-1997 Fredrik H�binette\n"
+	       "Pike comes with ABSOLUTELY NO WARRANTY; This is free software and you are\n"
+	       "welcome to redistribute it under certain conditions; Read the files\n"
+	       "COPYING and DISCLAIMER in the Pike distribution for more details.\n");
+	exit(0);
+	
+      case "help":
+	werror("Usage: pike [-driver options] script [script arguments]\n"
+	       "Driver options include:\n"
+	       " -I --include-path=<p>: Add <p> to the include path\n"
+	       " -M --module-path=<p> : Add <p> to the module path\n"
+	       " -P --program-path=<p>: Add <p> to the program path\n"
+	       " -e --execute=<cmd>   : Run the given command instead of a script.\n"
+	       " -h --help            : see this message\n"
+	       " -v --version         : See what version of pike you have.\n"
+	       " -s#                  : Set stack size\n"
+	       " -m <file>            : Use <file> as master object.\n"
+	       " -d -d#               : Increase debug (# is how much)\n"
+	       " -t -t#               : Increase trace level\n"
+	  );
+	exit(0);
+	
+      case "execute":
+	compile_string("#include <simulate.h>\nmixed create(){"+opts[1]+";}")();
+	exit(0);
+      }
+    }
+
+    argv=tmp->get_args(argv,1);
+  }
+
+  if(sizeof(argv)==1)
+  {
+    argv=explode_path(argv[0]);
+    argv[-1]="hilfe";
+    argv=({ argv*"/" });
+    if(!master_file_stat(argv[0]))
+    {
+      if(master_file_stat("�exec_prefix�/bin/hilfe"))
+	argv[0]="�exec_prefix�/bin/hilfe";
+      else if(master_file_stat("../bin/hilfe"))
+	argv[0]="../bin/hilfe";
+      else
+      {
+	werror("Couldn't find hilfe.\n");
+	exit(1);
+      }
+    }
+  }else{
+    argv=argv[1..];
+  }
+
+  program tmp=(program)argv[0];
+
+  if(!tmp)
+  {
+    werror("Pike: Couldn't find script to execute.\n");
+    exit(1);
+  }
+
+  object script=tmp();
+
+  if(!script->main)
+  {
+    werror("Error: "+argv[0]+" has no main().\n");
+    exit(1);
+  }
+
+  i=script->main(sizeof(argv),argv,env);
+  if(i >=0) exit(i);
+}
+
+mixed inhibit_compile_errors;
+
+void set_inhibit_compile_errors(mixed f)
+{
+  inhibit_compile_errors=f;
+}
+
+string trim_file_name(string s)
+{
+  if(getenv("SHORT_PIKE_ERRORS")) return basename(s);
+  return s;
+}
+
+/*
+ * This function is called whenever a compiling error occurs,
+ * Nothing strange about it.
+ * Note that previous_object cannot be trusted in ths function, because
+ * the compiler calls this function.
+ */
+void compile_error(string file,int line,string err)
+{
+  if(!inhibit_compile_errors)
+  {
+    werror(sprintf("%s:%d:%s\n",trim_file_name(file),line,err));
+  }
+  else if(functionp(inhibit_compile_errors))
+  {
+    inhibit_compile_errors(file,line,err);
+  }
+}
+
+/*
+ * This function is called whenever a compiling error occurs,
+ * Nothing strange about it.
+ * Note that previous_object cannot be trusted in ths function, because
+ * the compiler calls this function.
+ */
+void compile_warning(string file,int line,string err)
+{
+  if(!inhibit_compile_errors)
+  {
+    if(want_warnings)
+      werror(sprintf("%s:%d:%s\n",trim_file_name(file),line,err));
+  }
+}
+
+
+/* This function is called whenever an #include directive is encountered
+ * it receives the argument for #include and should return the file name
+ * of the file to include
+ * Note that previous_object cannot be trusted in ths function, because
+ * the compiler calls this function.
+ */
+string handle_include(string f,
+		      string current_file,
+		      int local_include)
+{
+  string *tmp, path;
+
+  if(local_include)
+  {
+    tmp=explode_path(current_file);
+    tmp[-1]=f;
+    path=combine_path_with_cwd(tmp*"/");
+    if(!master_file_stat(path)) return 0;
+  }
+  else
+  {
+    foreach(pike_include_path, path)
+      {
+	path=combine_path(path,f);
+	if(master_file_stat(path))
+	  break;
+	else
+	  path=0;
+      }
+    
+    if(!path)
+    {
+      path=combine_path(pike_library_path+"/include",f);
+      if(!master_file_stat(path)) path=0;
+    }
+  }
+
+  if(path)
+  {
+    /* Handle preload */
+
+    if(path[-1]=='h' && path[-2]=='.' &&
+       master_file_stat(path[0..sizeof(path)-2]+"pre.pike"))
+    {
+      cast_to_object(path[0..sizeof(path)-2]+"pre.pike","/");
+    }
+  }
+
+  return path;
+}
+
+string read_include(string f)
+{
+  return _static_modules->files()->file(f,"r")->read();
+}
+
+// FIXME
+string stupid_describe(mixed m)
+{
+  switch(string typ=sprintf("%t",m))
+  {
+  case "int":
+  case "float":
+    return (string)m;
+
+  case "string":
+    if(sizeof(m) < 60 && sscanf(m,"%*[-a-zAZ0-9.~`!@#$%^&*()_]%n",int i) && i==sizeof(m))
+    {
+      return "\""+m+"\"";
+    }
+
+  case "array":
+  case "mapping":
+  case "multiset":
+    return typ+"["+sizeof(m)+"]";
+
+  default:
+    return sprintf("%t",m);
+  }
+}
+
+/* It is possible that this should be a real efun,
+ * it is currently used by handle_error to convert a backtrace to a
+ * readable message.
+ */
+string describe_backtrace(mixed *trace)
+{
+  int e;
+  string ret;
+
+  if(arrayp(trace) && sizeof(trace)==2 && stringp(trace[0]))
+  {
+    ret=trace[0];
+    trace=trace[1];
+  }else{
+    ret="";
+  }
+
+  if(!arrayp(trace))
+  {
+    ret+="No backtrace.\n";
+  }else{
+    for(e=sizeof(trace)-1;e>=0;e--)
+    {
+      mixed tmp;
+      string row;
+
+      tmp=trace[e];
+      if(stringp(tmp))
+      {
+	row=tmp;
+      }
+      else if(arrayp(tmp))
+      {
+	row="";
+	if(sizeof(tmp)>=3)
+	{
+	  if(functionp(tmp[2]))
+	    row=function_name(tmp[2]);
+	  else
+	    row="unknown function";
+	    
+	  row+="(";
+	  for(int e=3;e<sizeof(tmp);e++)
+	  {
+	    row+=stupid_describe(tmp[e])+",";
+	  }
+
+	  if(sizeof(tmp)>3)
+	    row=row[..sizeof(row)-2];
+	  row+=") in ";
+	}
+
+	if(sizeof(tmp)>=2 && stringp(tmp[0]) && intp(tmp[1]))
+	{
+	  row+="line "+tmp[1]+" in "+trim_file_name(tmp[0]);
+	}else{
+	  row+="Unknown program";
+	}
+      }
+      else
+      {
+	row="Destructed object";
+      }
+      ret+=row+"\n";
+    }
+  }
+
+  return ret;
+}