From 3a5b1da9387dd4f1654c4322a16accf51af63e77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fredrik=20H=C3=BCbinette=20=28Hubbe=29?= <hubbe@hubbe.net>
Date: Wed, 24 May 2000 19:18:35 -0700
Subject: [PATCH] module precompiler v0.1 added

Rev: bin/precompile.pike:1.1
Rev: src/Makefile.in:1.193
Rev: src/builtin.cmod:1.1
Rev: src/builtin_functions.c:1.276
Rev: src/configure.in:1.376
Rev: src/error.c:1.51
Rev: src/error.h:1.42
Rev: src/fd_control.c:1.30
Rev: src/precompile.sh.in:1.1
---
 bin/precompile.pike     | 433 ++++++++++++++++++++++++++++++++++++++++
 src/Makefile.in         |  29 ++-
 src/builtin.cmod        |  76 +++++++
 src/builtin_functions.c |  69 +------
 src/configure.in        |   4 +-
 src/error.c             |  15 +-
 src/error.h             |   4 +-
 src/fd_control.c        |   7 +-
 src/precompile.sh.in    | 107 ++++++++++
 9 files changed, 671 insertions(+), 73 deletions(-)
 create mode 100644 bin/precompile.pike
 create mode 100644 src/builtin.cmod
 create mode 100644 src/precompile.sh.in

diff --git a/bin/precompile.pike b/bin/precompile.pike
new file mode 100644
index 0000000000..6a05a37fa3
--- /dev/null
+++ b/bin/precompile.pike
@@ -0,0 +1,433 @@
+#!/usr/local/bin/pike
+
+/*
+ * This script is used to process *.cmod files into *.c files, it 
+ * reads Pike style prototypes and converts them into C code.
+ *
+ * The input can look something like this:
+ *
+ * PIKEFUNC int function_name (int x)
+ *  attribute;
+ *  attribute value;
+ * {
+ *   C code using 'x'.
+ *
+ *   RETURN x;
+ * }
+ *
+ * All the ADD_EFUN/ADD_FUNCTION calls will be inserted instead of the
+ * word INIT in your code.
+ *
+ * Currently, the following attributes are understood:
+ *   efun;     makes this function a global constant (no value)
+ *   flags;    ID_STATIC | ID_NOMASK etc.
+ *   optflags; OPT_TRY_OPTIMIZE | OPT_SIDE_EFFECT etc.
+ *   type;     tInt, tMix etc. use this type instead of automatically
+ *             generating type from the prototype
+ *
+ *
+ * BUGS/LIMITATIONS
+ *  o Parenthesis must match, even within #if 0
+ *  o Not all Pike types are supported yet
+ */
+
+#define PC Parser.C
+
+#ifdef OLD
+import ".";
+#define PC .C
+#endif
+
+int parse_type(array x, int pos)
+{
+  while(1)
+  {
+    while(x[pos]=="!") pos++;
+    pos++;
+    if(arrayp(x[pos])) pos++;
+    switch(x[pos])
+    {
+      default:
+	return pos;
+
+      case "&":
+      case "|":
+	pos++;
+    }
+  }
+}
+
+array(PC.Token) strip(array(PC.Token) t)
+{
+  array ret=({});
+  foreach(t, mixed x)
+    {
+      if(objectp(x))
+      {
+	switch(x->text[0])
+	{
+	  case ' ':
+	  case '\t':
+	  case '\n':
+	  case '\r':
+	    continue;
+	}
+      }else{
+	x=strip(x);
+      }
+      ret+=({x});
+    }
+  return ret;
+}
+
+string merge(array x)
+{
+  string ret="";
+  foreach(x,x)
+    ret+=arrayp(x)?merge(x):objectp(x)?x->text:x;
+  return ret;
+}
+
+string cname(mixed type)
+{
+  mixed btype;
+  if(arrayp(type))
+    btype=type[0];
+  else
+    btype=type;
+
+  switch(objectp(btype) ? btype->text : btype)
+  {
+    case "int": return "INT32";
+    case "float": return "FLOAT_NUMBER";
+    case "string": return "struct pike_string *";
+
+    case "array":
+    case "multiset":
+    case "mapping":
+
+    case "object":
+    case "program": return "struct "+btype+" *";
+
+    case "function":
+    case "mixed":  return "struct svalue *";
+
+    default:
+      werror("Unknown type %s\n",objectp(btype) ? btype->text : btype);
+      exit(1);
+  }
+}
+
+string uname(mixed type)
+{
+  switch(objectp(type) ? type->text : type)
+  {
+    case "int": return "integer";
+    case "float":
+    case "string":
+
+    case "array":
+    case "multiset":
+    case "mapping":
+
+    case "object":
+    case "program": return "struct "+type+" *";
+
+    case "function":
+    case "mixed":  return "struct svalue *";
+
+    default:
+      werror("Unknown type %s\n",type);
+      exit(1);
+  }
+}
+
+mapping(string:string) parse_arg(array x)
+{
+  mapping ret=(["name":x[-1]]);
+  ret->type=x[..sizeof(x)-2];
+  ret->basetype=x[0];
+  if(sizeof(ret->type/({"|"}))>1)
+    ret->basetype="mixed";
+  ret->ctype=cname(ret->basetype);
+  return ret;
+}
+
+/* FIXME: this is not finished yet */
+string convert_type(array s)
+{
+//  werror("%O\n",s);
+  switch(objectp(s[0])?s[0]->text:s[0])
+  {
+    case "0": case "1": case "2": case "3": case "4":
+    case "5": case "6": case "7": case "8": case "9":
+      if(sizeof(s)>1 && s[1]=="=")
+      {
+	return sprintf("tSetvar(%s,%s)",s[0],convert_type(s[2..]));
+      }else{
+	return sprintf("tVar(%s)",s[0]);
+      }
+
+    case "int": return "tInt";
+    case "float": return "tFlt";
+    case "string": return "tStr";
+    case "array": 
+      if(sizeof(s)<2) return "tArray";
+      return "tArr("+convert_type(s[1][1..sizeof(s[1])-2])+")";
+    case "multiset": 
+      if(sizeof(s)<2) return "tMultiset";
+      return "tSet("+convert_type(s[1][1..sizeof(s[1])-2])+")";
+    case "mapping": 
+      if(sizeof(s)<2) return "tMapping";
+      return "tMap("+
+	convert_type((s[1]/({":"}))[0])+","+
+	  convert_type((s[1]/({":"}))[1])+")";
+    case "object": 
+      return "tObj";
+
+    case "program": 
+      return "tProg";
+    case "function": 
+      return "tFunc";
+    case "mixed": 
+      return "tMix";
+  }
+}
+
+string make_pop(mixed howmany)
+{
+  switch(howmany)
+  {
+    default:
+      return "pop_n_elems("+howmany+");";
+      
+    case "0": case 0: return "";
+    case "1": case 1: return "pop_stack();";
+  }
+}
+
+array fix_return(array body, string rettype, string ctype, mixed args)
+{
+  int pos=0;
+  
+  while( (pos=search(body,PC.Token("RETURN",0),pos)) != -1)
+  {
+    int pos2=search(body,PC.Token(";",0),pos+1);
+    body[pos]=sprintf("do { %s ret_=(",ctype);
+    body[pos2]=sprintf("); %s push_%s(ret_); return; }while(0);",make_pop(args),rettype);
+    pos=pos2+1;
+  }
+
+  pos=0;
+  while( (pos=search(body,PC.Token("REF_RETURN",0),pos)) != -1)
+  {
+    int pos2=search(body,PC.Token(";",0),pos+1);
+    body[pos]=sprintf("do { %s ret_=(",ctype);
+    body[pos2]=sprintf("); add_ref(ret_); %s push_%s(ret_); return; }while(0);",make_pop(args),rettype);
+    pos=pos2+1;
+  }
+  return body;
+}
+
+array strip_type_assignments(array data)
+{
+  int pos;
+
+  while( (pos=search(data,PC.Token("=",0))) != -1)
+    data=data[pos-2]+data[pos+1];
+  return data;
+}
+
+array recursive(mixed func, array data, mixed ... args)
+{
+  array ret=({});
+
+  data=func(data, @args);
+
+  foreach(data, mixed foo)
+    {
+      if(arrayp(foo))
+      {
+	ret+=({ recursive(func, foo, @args) });
+      }else{
+	ret+=({ foo });
+      }
+    }
+
+  return ret;
+}
+
+int main(int argc, array(string) argv)
+{
+  mixed x;
+  string file=argv[1];
+  x=Stdio.read_file(file);
+  x=PC.split(x);
+  x=PC.tokenize(x);
+  x=PC.group(x);
+
+  x=x/({"PIKEFUN"});
+  array ret=x[0];
+  array addfuncs=({});
+
+  for(int f=1;f<sizeof(x);f++)
+  {
+    array func=x[f];
+    int p;
+    for(p=0;p<sizeof(func);p++)
+      if(arrayp(func[p]) && func[p][0]=="{")
+	break;
+
+    array proto=strip(func[..p-1]);
+    array body=func[p];
+    array rest=func[p+1..];
+
+    p=parse_type(proto,0);
+    array rettype=proto[..p-1];
+    string name=proto[p]->text;
+    array args=proto[p+1];
+
+    array attr=strip(proto[p+2..]);
+
+    mapping attributes=([]);
+    foreach(attr/ ({";"}), attr)
+      {
+	switch(sizeof(attr))
+	{
+	  case 0: break;
+	  case 1:
+	    attributes[attr[0]->text]=1;
+	    break;
+	  default:
+	  array tmp=attr[1..];
+	  if(sizeof(tmp) == 1 && arrayp(tmp[0]) && tmp[0][0]=="(")
+	    tmp=tmp[0][1..sizeof(tmp[0])-2];
+
+	  attributes[attr[0]->text]=merge(tmp);
+	}
+      }
+
+//    werror("%O\n",attributes);
+
+
+    args=args[1..sizeof(args)-2]/({","});
+
+//    werror("FIX RETURN: %O\n",body);
+    body=recursive(fix_return,body, rettype[0], cname(rettype), sizeof(args)); 
+    
+//    werror("name=%s\n",name);
+//    werror("  rettype=%O\n",rettype);
+//    werror("  args=%O\n",args);
+
+    ret+=({
+      sprintf("\n#line %d %O\n",rettype[0]->line,file),
+      sprintf("void f_%s(INT32 args)\n{\n",name),
+    });
+
+    args=map(args,parse_arg);
+
+    foreach(args, mapping arg)
+      ret+=({  sprintf("%s%s;\n",arg->ctype, arg->name) });
+
+
+    addfuncs+=({
+      sprintf("  %s(%O,f_%s,tFunc(%s,%s),%s);\n",
+	      attributes->efun ? "ADD_EFUN" : "ADD_FUNCTION",
+	      name,
+	      name,
+	      attributes->type ? attributes->type :
+	      Array.map(args->type,convert_type)*" ",
+	      convert_type(rettype),
+	      (attributes->efun ? attributes->optflags : 
+	        attributes->flags )|| "0" ,
+	      )
+    });
+
+    int argnum;
+
+    argnum=0;
+    ret+=({
+      sprintf("if(args != %d) wrong_number_of_args_error(%O,args,%d);\n",
+	      sizeof(args),
+	      name,
+	      sizeof(args))
+    });
+
+    int sp=-sizeof(args);
+    foreach(args, mapping arg)
+      {
+	if(arg->basetype != "mixed")
+	{
+	  ret+=({
+	    sprintf("if(sp[%d].type != PIKE_T_%s)\n",
+		    sp,upper_case(arg->basetype->text)),
+	    sprintf("  SIMPLE_BAD_ARG_ERROR(%O,%d,%O);\n",
+		    name,
+		    argnum+1,
+		    merge(arg->type)),
+	  });
+	}
+
+	switch(objectp(arg->basetype) ? arg->basetype->text : arg->basetype )
+	{
+	  case "int":
+	    ret+=({
+	      sprintf("%s=sp[%d].integer;\n",
+		      arg->name,
+		      sp)
+	    });
+	    break;
+
+	  case "float":
+	    ret+=({
+	      sprintf("%s=sp[%d].float_number;\n",
+		      arg->name,
+		      sp)
+	    });
+	    break;
+
+	  case "mixed":
+	    ret+=({
+	      sprintf("%s=sp%+d;\n",
+		      arg->name,
+		      sp)
+	    });
+	    break;
+
+	  default:
+	    ret+=({
+	      sprintf("%s=sp[%d].u.%s;\n",
+		      arg->name,
+		      sp,
+		      arg->basetype)
+	    });
+	  
+	}
+        argnum++;
+	sp++;
+      }
+    
+    if(sizeof(body))
+    {
+      ret+=({
+	sprintf("#line %d %O\n",body[0]->line,file),
+	body,
+      });
+    }
+    ret+=({
+      "}\n"
+    });
+
+    if(sizeof(rest))
+    {
+      ret+=({
+	sprintf("#line %d %O\n",rest[0]->line,file),
+      })+
+	recursive(replace,rest,PC.Token("INIT",0),addfuncs);
+    }
+      
+  }
+
+
+  write(merge(ret));
+}
diff --git a/src/Makefile.in b/src/Makefile.in
index 023a13b2fc..62ed0a8cd1 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -1,5 +1,5 @@
 #
-# $Id: Makefile.in,v 1.192 2000/05/18 19:50:12 mast Exp $
+# $Id: Makefile.in,v 1.193 2000/05/25 02:18:35 hubbe Exp $
 #
 
 # This line is needed on some machines.
@@ -132,8 +132,14 @@ OBJ= \
  threads.o \
  version.o \
  queue.o \
+ builtin.o \
  svalue.o @EXTRA_OBJS@
 
+
+DEPEND= \
+ $(SRCDIR)/language.c \
+ $(SRCDIR)/builtin.c
+
 #
 # The following objectfiles differ between tpike & pike:
 #
@@ -253,7 +259,7 @@ hilfe: $(TMP_BINDIR)/hilfe Makefile
 	@echo "Done."
 
 
-.SUFFIXES: .c .o
+.SUFFIXES: .c .o .cmod
 
 # Several optimizers have problems with interpret.c
 # First try compiling with optimization and if that doesn't work, without.
@@ -269,6 +275,14 @@ hilfe: $(TMP_BINDIR)/hilfe Makefile
 	  NO_ULIMIT=yes $(CC) $(PREFLAGS) $(NOOPTFLAGS) -c $< -o $@ ;\
 	fi
 
+#
+# Please note that this must be accompanied by a dependency rule as
+# The .c file will not be created in the SOURCE directory otherwise.
+# -Hubbe
+#
+.cmod.c:
+	./precompile.sh "$<" "$@"
+
 force :
 	@:
 
@@ -472,7 +486,7 @@ stamp-tpike-predep: $(SRCDIR)/peep.in $(TMP_BINDIR)/mkpeep.pike peep.c $(SRCDIR)
 	@echo foo > stamp-tpike-predep
 
 # make dependencies
-depend: $(SRCDIR)/language.c
+depend: $(DEPEND)
 	gcc -MM -MG $(PREFLAGS) $(SRCDIR)/*.c | $(TMP_BINDIR)/fixdepends.sh $(SRCDIR)
 	( cd modules && $(MAKE) $(MAKE_FLAGS) depend )
 	( cd post_modules && $(MAKE) $(MAKE_FLAGS) depend )
@@ -543,6 +557,12 @@ $(SRCDIR)/language.h: $(SRCDIR)/language.yacc
 $(SRCDIR)/language.c: $(SRCDIR)/language.h
 	touch $(SRCDIR)/language.c
 
+
+#
+# This rule makes sure that builtin.c is created in the source dir.
+#
+$(SRCDIR)/builtin.c: $(SRCDIR)/builtin.cmod ./precompile.sh $(TMP_BINDIR)/precompile.pike
+
 # Internal testing target
 run_yacc: $(SRCDIR)/language.c
 
@@ -572,6 +592,9 @@ Makefile: $(SRCDIR)/Makefile.in $(SRCDIR)/dependencies config.status
 	@echo "Run make again"
 	@exit 1
 
+precompile.sh: $(SRCDIR)/precompile.sh.in ./config.status
+	CONFIG_FILES=precompile.sh CONFIG_HEADERS="" ./config.status
+
 $(SRCDIR)/machine.h.in: $(SRCDIR)/stamp-h.in
 	@if test -f $(SRCDIR)/machine.h.in; then :; else \
 	  rm $(SRCDIR)/stamp-h.in; $(MAKE) $(SRCDIR)/stamp-h.in; \
diff --git a/src/builtin.cmod b/src/builtin.cmod
new file mode 100644
index 0000000000..0082d1ad23
--- /dev/null
+++ b/src/builtin.cmod
@@ -0,0 +1,76 @@
+#include "global.h"
+#include "interpret.h"
+#include "svalue.h"
+#include "opcodes.h"
+#include "pike_macros.h"
+#include "object.h"
+#include "program.h"
+#include "array.h"
+#include "error.h"
+#include "constants.h"
+#include "mapping.h"
+#include "stralloc.h"
+#include "multiset.h"
+#include "pike_types.h"
+#include "pike_memory.h"
+#include "threads.h"
+#include <math.h>
+#include <ctype.h>
+#include "module_support.h"
+#include "cyclic.h"
+#include "bignum.h"
+
+
+PIKEFUN array column(array tmp, mixed val)
+  efun;
+  optflags OPT_TRY_OPTIMIZE;
+{
+  INT32 e;
+  struct array *a;
+
+  DECLARE_CYCLIC();
+
+  /* Optimization */
+  if(tmp->refs == 1)
+  {
+    /* An array with one ref cannot possibly be cyclic */
+    struct svalue sval;
+    tmp->type_field = BIT_MIXED | BIT_UNFINISHED;
+    for(e=0;e<tmp->size;e++)
+    {
+      index_no_free(&sval, ITEM(tmp)+e, val);
+      free_svalue(ITEM(tmp)+e);
+      ITEM(tmp)[e]=sval;
+    }
+    pop_stack();
+    return;
+  }
+
+  if((a=(struct array *)BEGIN_CYCLIC(tmp,0)))
+  {
+    add_ref(a);
+  }else{
+    push_array(a=allocate_array(tmp->size));
+    SET_CYCLIC_RET(a);
+
+    for(e=0;e<a->size;e++)
+      index_no_free(ITEM(a)+e, ITEM(tmp)+e, val);
+
+    sp--;
+  }
+  END_CYCLIC();
+  RETURN a;
+}
+
+PIKEFUN multiset(1) mkmultiset(array(1=mixed) a)
+  efun;
+  optflags OPT_TRY_OPTIMIZE;
+{
+  RETURN mkmultiset(a);
+}
+
+
+void init_builtin(void)
+{
+  INIT;
+}
diff --git a/src/builtin_functions.c b/src/builtin_functions.c
index d21d1dae5d..11cbe15543 100644
--- a/src/builtin_functions.c
+++ b/src/builtin_functions.c
@@ -5,7 +5,7 @@
 \*/
 /**/
 #include "global.h"
-RCSID("$Id: builtin_functions.c,v 1.275 2000/05/17 18:27:50 grubba Exp $");
+RCSID("$Id: builtin_functions.c,v 1.276 2000/05/25 02:18:35 hubbe Exp $");
 #include "interpret.h"
 #include "svalue.h"
 #include "pike_macros.h"
@@ -2382,17 +2382,6 @@ void f_mkmapping(INT32 args)
   push_mapping(m);
 }
 
-void f_mkmultiset(INT32 args)
-{
-  struct multiset *m;
-  struct array *a;
-  get_all_args("mkmultiset",args,"%a",&a);
-
-  m=mkmultiset(sp[-args].u.array);
-  pop_n_elems(args);
-  push_multiset(m);
-}
-
 #define SETFLAG(FLAGS,FLAG,ONOFF) \
   FLAGS = (FLAGS & ~FLAG) | ( ONOFF ? FLAG : 0 )
 void f_set_weak_flag(INT32 args)
@@ -2710,50 +2699,6 @@ void f_rows(INT32 args)
   push_array(a);
 }
 
-void f_column(INT32 args)
-{
-  INT32 e;
-  struct array *a,*tmp;
-  struct svalue *val;
-
-  DECLARE_CYCLIC();
-
-  get_all_args("column", args, "%a%*", &tmp, &val);
-
-  /* Optimization */
-  if(tmp->refs == 1)
-  {
-    /* An array with one ref cannot possibly be cyclic */
-    struct svalue sval;
-    tmp->type_field = BIT_MIXED | BIT_UNFINISHED;
-    for(e=0;e<tmp->size;e++)
-    {
-      index_no_free(&sval, ITEM(tmp)+e, val);
-      free_svalue(ITEM(tmp)+e);
-      ITEM(tmp)[e]=sval;
-    }
-    pop_stack();
-    return;
-  }
-
-  if((a=(struct array *)BEGIN_CYCLIC(tmp,0)))
-  {
-    pop_n_elems(args);
-    ref_push_array(a);
-  }else{
-    push_array(a=allocate_array(tmp->size));
-    SET_CYCLIC_RET(a);
-
-    for(e=0;e<a->size;e++)
-      index_no_free(ITEM(a)+e, ITEM(tmp)+e, val);
-
-    sp--;
-    dmalloc_touch_svalue(sp);
-    pop_n_elems(args);
-    push_array(a);
-  }
-  END_CYCLIC();
-}
 
 #ifdef PIKE_DEBUG
 void f__verify_internals(INT32 args)
@@ -5711,6 +5656,10 @@ void init_builtin_efuns(void)
 {
   struct program *pike___master_program;
 
+  extern init_builtin(void);
+
+  init_builtin();
+
   ADD_EFUN("gethrtime", f_gethrtime,
 	   tFunc(tOr(tInt,tVoid),tInt), OPT_EXTERNAL_DEPEND);
 
@@ -5813,9 +5762,6 @@ void init_builtin_efuns(void)
 	   tFunc(tNone,tArr(tArray)),OPT_EXTERNAL_DEPEND);
 
   
-/* function(array,mixed:array) */
-  ADD_EFUN("column",f_column,tFunc(tArray tMix,tArray),0);
-  
 /* function(string...:string) */
   ADD_EFUN("combine_path",f_combine_path,tFuncV(tNone,tStr,tStr),0);
   
@@ -5901,10 +5847,7 @@ void init_builtin_efuns(void)
 	   tFunc(tArr(tSetvar(1,tMix)) tArr(tSetvar(2,tMix)),
 		 tMap(tVar(1),tVar(2))),OPT_TRY_OPTIMIZE);
 
-  ADD_EFUN("mkmultiset",f_mkmultiset,
-	   tFunc(tArr(tSetvar(1,tMix)), tSet(tVar(1))),
-	   OPT_TRY_OPTIMIZE);
-  
+
 /* function(1=mixed,int:1) */
   ADD_EFUN("set_weak_flag",f_set_weak_flag,
 	   tFunc(tSetvar(1,tMix) tInt,tVar(1)),OPT_SIDE_EFFECT);
diff --git a/src/configure.in b/src/configure.in
index db7939f43b..82b532170a 100644
--- a/src/configure.in
+++ b/src/configure.in
@@ -1,4 +1,4 @@
-AC_REVISION("$Id: configure.in,v 1.375 2000/05/20 13:40:05 grubba Exp $")
+AC_REVISION("$Id: configure.in,v 1.376 2000/05/25 02:18:35 hubbe Exp $")
 AC_INIT(interpret.c)
 AC_CONFIG_HEADER(machine.h)
 
@@ -3638,6 +3638,6 @@ fi
 
 AC_SUBST(dmmsrc)
 
-AC_OUTPUT(Makefile modules/static_module_makefile  post_modules/static_module_makefile:modules/static_module_makefile.in modules/dynamic_module_makefile:$dmmsrc post_modules/dynamic_module_makefile:$dmmsrc,[echo foo >stamp-h])
+AC_OUTPUT(Makefile modules/static_module_makefile  post_modules/static_module_makefile:modules/static_module_makefile.in modules/dynamic_module_makefile:$dmmsrc post_modules/dynamic_module_makefile:$dmmsrc precompile.sh,[echo foo >stamp-h ; chmod +x precompile.sh])
 
 
diff --git a/src/error.c b/src/error.c
index 914f8635d8..bb0aa28d70 100644
--- a/src/error.c
+++ b/src/error.c
@@ -20,7 +20,7 @@
 #include "threads.h"
 #include "gc.h"
 
-RCSID("$Id: error.c,v 1.50 2000/04/19 21:26:19 mast Exp $");
+RCSID("$Id: error.c,v 1.51 2000/05/25 02:18:35 hubbe Exp $");
 
 #undef ATTRIBUTE
 #define ATTRIBUTE(X)
@@ -552,6 +552,19 @@ void permission_error(
   ERROR_DONE(generic);
 }
 
+void wrong_number_of_args_error(char *name, int args, int expected)
+{
+  char *msg;
+  if(expected>args)
+  {
+    msg="Too few arguments";
+  }else{
+    msg="Too many arguments";
+  }
+
+  new_error(name, msg, sp-args, args, 0,0);
+}
+
 #ifdef PIKE_DEBUG
 static void gc_check_throw_value(struct callback *foo, void *bar, void *gazonk)
 {
diff --git a/src/error.h b/src/error.h
index 2aa412db11..9639d5e7d7 100644
--- a/src/error.h
+++ b/src/error.h
@@ -5,7 +5,7 @@
 \*/
 
 /*
- * $Id: error.h,v 1.41 2000/04/20 02:41:44 hubbe Exp $
+ * $Id: error.h,v 1.42 2000/05/25 02:18:35 hubbe Exp $
  */
 #ifndef ERROR_H
 #define ERROR_H
@@ -170,6 +170,7 @@ extern int throw_severity;
 
 /* Prototypes begin here */
 void check_recovery_context(void);
+void pike_gdb_breakpoint(void);
 JMP_BUF *init_recovery(JMP_BUF *r DEBUG_LINE_ARGS);
 void pike_throw(void) ATTRIBUTE((noreturn));
 void push_error(char *description);
@@ -224,6 +225,7 @@ void permission_error(
   struct svalue *base_sp, int args,
   char *permission_type,
   char *desc, ...) ATTRIBUTE((noreturn, format(printf, 5, 6)));
+void wrong_number_of_args_error(char *name, int args, int expected);
 void init_error(void);
 void cleanup_error(void);
 /* Prototypes end here */
diff --git a/src/fd_control.c b/src/fd_control.c
index dc76a178a2..07aaaba95a 100644
--- a/src/fd_control.c
+++ b/src/fd_control.c
@@ -10,7 +10,7 @@
 #include "error.h"
 #include "fdlib.h"
 
-RCSID("$Id: fd_control.c,v 1.29 2000/05/20 18:58:53 grubba Exp $");
+RCSID("$Id: fd_control.c,v 1.30 2000/05/25 02:18:35 hubbe Exp $");
 
 #else /* TESTING */
 
@@ -141,11 +141,12 @@ int query_nonblocking(int fd)
 #ifdef HAVE_BROKEN_F_SETFD
 static int *fds_to_close;
 static int fds_to_close_size = 0;
+static int num_fds_to_close=0;
 
 #define ASSURE_FDS_TO_CLOSE_SIZE(X) \
 do{while(fds_to_close_size-1 < X) grow_fds_to_close();}while(0)
 
-static void grow_fds_to_close( )
+static void grow_fds_to_close(void)
 {
   if(!fds_to_close_size)
     fds_to_close_size = 1;
@@ -154,7 +155,7 @@ static void grow_fds_to_close( )
   if(!fds_to_close)
     fatal("Out of memory in fd_control::grow_fds_to_close()\n"
           "Tried to allocate %d fd_datum structs\n", fds_to_close_size);
-  MEMSET( fds+(fds_to_close_size/2), 0, fds_to_close_size*sizeof(int)/2 );
+  MEMSET( fds_to_close+(fds_to_close_size/2), 0, fds_to_close_size*sizeof(int)/2 );
 }
 
 void do_close_on_exec(void)
diff --git a/src/precompile.sh.in b/src/precompile.sh.in
new file mode 100644
index 0000000000..177d538c8b
--- /dev/null
+++ b/src/precompile.sh.in
@@ -0,0 +1,107 @@
+#!/bin/sh
+
+#set -x
+
+TMP_BUILDDIR="@BUILDDIR@"
+TMP_BINDIR="@BINDIR@"
+LIBDIR_SRC="@LIBDIR@"
+
+if test -f "$TMP_BUILDDIR/precompile-method" ; then
+  . "$TMP_BUILDDIR/precompile-method"
+else
+  :
+fi
+
+old_method="${method-}"
+
+retries=.
+while test "$retries" != .......... ; do
+
+RUNPIKE=
+case $method in
+  Q)
+    RUNPIKE="$TMP_BUILDDIR/pike -DNOT_INSTALLED -m$TMP_BUILDDIR/master.pike $PIKEOPTS"
+  ;;
+  QQ)
+    RUNPIKE="$TMP_BUILDDIR/tpike -DNOT_INSTALLED -m$TMP_BUILDDIR/master.pike $PIKEOPTS"
+  ;;
+  QQQ)
+    RUNPIKE=$TMP_BUILDDIR/test-pike
+  ;;
+  QQQQ)
+    LAST_PIKE=pike
+    method=QQQQQ
+    RUNPIKE="$LAST_PIKE -DOLD"
+  ;;
+  QQQQQ)
+    RUNPIKE="$LAST_PIKE -DOLD"
+  ;;
+  QQQQQQ)
+    ifs_save="${IFS- 	}"
+    IFS=" :"
+    for dir in $PATH
+    do
+      for p in pike pike7 pike07 pike06
+      do
+        if [ -x $dir/$p ]; then
+          if [ "x$LAST_PIKE" = xpike ] ; then
+            LAST_PIKE=$dir/$p
+            RUNPIKE="$dir/$p -DOLD"
+            break
+          fi
+
+          if [ "x$LAST_PIKE" = "x$dir/$p" ]; then
+            LAST_PIKE=pike
+          fi
+        fi
+      done
+      if [ "x$RUNPIKE" != x ]; then
+        method=QQQQQ
+        break
+      fi
+    done
+    IFS="${ifs_save}"
+  ;;
+  QQQQQQQ)
+    method=
+  ;;
+esac
+
+#
+# By linking these two files to the current directory I can make
+# precompile.pike work with older versions of Pike - Hubbe
+#
+
+if test -f ./precompile.pike ; then
+  :
+else
+  ln -s "$TMP_BINDIR/precompile.pike"  ./precompile.pike
+fi
+
+if test -f ./C.pmod ; then
+  :
+else
+  ln -s "$LIBDIR_SRC/modules/Parser.pmod/C.pmod"  ./C.pmod
+fi
+
+
+
+if test "x${RUNPIKE-}" != x ; then
+echo "precompile: $RUNPIKE ./precompile.pike $1 >$2 (method=$method)"
+if $RUNPIKE ./precompile.pike "$1" >"$2" ; then
+
+cat > "$TMP_BUILDDIR/precompile-method" <<EOF
+LAST_PIKE=$LAST_PIKE
+method=$method
+EOF
+
+exit 0
+fi
+fi
+
+method=Q$method
+retries=.$retries
+
+done # retry
+# Total failure
+rm "$2"
\ No newline at end of file
-- 
GitLab