diff -ruN /home/favorit/ldmud-3.3.719/src/actions.c ./actions.c
--- /home/favorit/ldmud-3.3.719/src/actions.c	2009-06-15 01:18:51.000000000 +0300
+++ ./actions.c	2009-09-03 12:30:44.000000000 +0300
@@ -128,7 +128,8 @@
    * command verb as specified in the action definition.
    */
 
-static char *last_command = NULL;
+//BAT static
+char *last_command = NULL;
   /* During a command execution, this points to a (stack) buffer with
    * the full command.
    */
@@ -620,6 +621,58 @@
     return MY_FALSE;
 } /* call_modify_command() */
 
+//ifdef BAT
+/*-------------------------------------------------------------------------*/
+static Bool
+call_post_command ()
+
+     /* Call the post_command hook if it is set..
+      *
+      * Return FALSE if everything is ok, and TRUE if something happened
+      * (like the command_giver selfdestructed or the hook had something to
+      * complain).
+      */
+
+{
+  svalue_t *svp;
+
+  svp = NULL;
+
+  if (driver_hook[H_POST_COMMAND].type == T_CLOSURE)
+    {
+      lambda_t *l;
+
+      l = driver_hook[H_POST_COMMAND].u.lambda;
+      if (driver_hook[H_POST_COMMAND].x.closure_type == CLOSURE_LAMBDA)
+        {
+	  free_object(l->ob, "call_post_command");
+	  l->ob = ref_object(command_giver, "call_post_command");
+        }
+      push_ref_object(inter_sp, command_giver, "call_post_command");
+      call_lambda(&driver_hook[H_POST_COMMAND], 1);
+      transfer_svalue(svp = &apply_return_value, inter_sp--);
+      if (!command_giver)
+	return MY_TRUE;
+    }
+  else if (driver_hook[H_POST_COMMAND].type == T_STRING
+	   && !(O_DESTRUCTED & command_giver->flags))
+    {
+        svp =
+	  sapply(driver_hook[H_POST_COMMAND].u.str, command_giver, 0);
+        if (!command_giver)
+	  return MY_TRUE;
+    }
+
+  /* If svp is integer and not zero, return true
+   */
+  if (svp && svp->type == T_NUMBER && svp->u.number) {
+    return MY_TRUE;
+  }
+
+  return MY_FALSE;
+} /* call_post_command() */
+//endif BAT
+
 /*-------------------------------------------------------------------------*/
 static int
 special_parse (char *buff)
@@ -732,7 +785,7 @@
     if (svp->type == T_STRING)
     {
         if (!useHook)
-            tell_object(command_giver, svp->u.str);
+            tell_object(command_giver, svp->u.str, 0);
         else
             push_svalue(svp);
     }
@@ -745,7 +798,7 @@
         {
             if (!useHook)
             {
-                tell_object(command_giver, inter_sp->u.str);
+                tell_object(command_giver, inter_sp->u.str, 0);
                 pop_stack();
             }
         }
@@ -758,7 +811,7 @@
     else if (driver_hook[H_NOTIFY_FAIL].type == T_STRING)
     {
         if (!useHook)
-            tell_object(command_giver, driver_hook[H_NOTIFY_FAIL].u.str);
+            tell_object(command_giver, driver_hook[H_NOTIFY_FAIL].u.str, 0);
         else
             push_svalue(&driver_hook[H_NOTIFY_FAIL]);
     }
@@ -776,7 +829,7 @@
         {
             if (!useHook)
             {
-                tell_object(command_giver, inter_sp->u.str);
+                tell_object(command_giver, inter_sp->u.str, 0);
                 pop_stack();
             }
         }
@@ -1185,6 +1238,17 @@
     marker_sent->shadow_ob = NULL;
     command_marker = marker_sent;
 
+//#ifdef BAT
+    save_current_object = current_object;
+    save_command_giver  = command_giver;
+
+    if (!from_efun && call_post_command())
+      return MY_TRUE;
+
+    current_object = save_current_object;
+    command_giver  = save_command_giver;
+//#endif BAT
+
     /* If the command was not found, notify the failure */
     if (s == 0)
     {
diff -ruN /home/favorit/ldmud-3.3.719/src/actions.h ./actions.h
--- /home/favorit/ldmud-3.3.719/src/actions.h	2009-06-15 01:18:51.000000000 +0300
+++ ./actions.h	2009-09-03 11:49:52.000000000 +0300
@@ -10,6 +10,10 @@
 extern object_t *command_giver;
 extern p_int alloc_action_sent;
 
+//#ifdef BAT /* Blitzer */
+extern char *last_command;
+//#endif
+
 /* --- Prototypes --- */
 
 extern void free_action_temporaries(void);
diff -ruN /home/favorit/ldmud-3.3.719/src/backend.c ./backend.c
--- /home/favorit/ldmud-3.3.719/src/backend.c	2009-06-15 01:18:52.000000000 +0300
+++ ./backend.c	2009-10-02 23:56:44.000000000 +0300
@@ -77,6 +77,12 @@
 #include "../mudlib/sys/driver_hook.h"
 #include "../mudlib/sys/debug_message.h"
 
+//#ifdef BAT
+#include "sockets.h"
+#include "bat.h"
+
+//#endif BAT
+
 /*-------------------------------------------------------------------------*/
 
 mp_int current_time;
@@ -346,7 +352,8 @@
 #ifdef __MWERKS__
 #    pragma unused(sig)
 #endif
-    reopen_debug_log = MY_TRUE;
+    eval_cost = max_eval_cost; // BAT eval cost to max
+//    reopen_debug_log = MY_TRUE;
     (void)signal(SIGUSR2, handle_usr2);
 #ifndef RETSIGTYPE_VOID
     return 0;
@@ -507,7 +514,6 @@
         }
 
         if (extra_jobs_to_do) {
-
             current_interactive = NULL;
             if (game_is_being_shut_down)
             {
@@ -599,7 +605,6 @@
             }
 
             extra_jobs_to_do = MY_FALSE;
-
         } /* if (extra_jobs_to_do */
 
         do_state_check(2, "before get_message()");
@@ -691,7 +696,6 @@
                     print_prompt();
                 }
             }
-
             do_state_check(2, "after handling message");
         }
         else
@@ -721,9 +725,9 @@
             next_call_out_cycle();
 
             /* Do the timed events */
-	    if (!synch_heart_beats
-             || time_of_last_hb + heart_beat_interval <= current_time)
-	    {
+			if (!synch_heart_beats
+				|| time_of_last_hb + heart_beat_interval <= current_time)
+			{
                 do_state_check(2, "before heartbeat");
                 call_heart_beat();
                 time_of_last_hb = current_time;
@@ -747,6 +751,10 @@
             mem_consolidate(MY_FALSE);
         }
 
+//#ifdef BAT
+		socket_poll();
+//#endif
+
     } /* end of main loop */
 
     /* NOTREACHED */
diff -ruN /home/favorit/ldmud-3.3.719/src/bat.c ./bat.c
--- /home/favorit/ldmud-3.3.719/src/bat.c	1970-01-01 02:00:00.000000000 +0200
+++ ./bat.c	2009-10-02 23:51:18.000000000 +0300
@@ -0,0 +1,1541 @@
+
+#include <ctype.h>
+#include <stdio.h>
+
+#define BAT_C__
+
+#include "machine.h"
+
+#include "bat.h"
+#include "main.h"
+#include "object.h"
+#include "backend.h"
+#include "simulate.h"
+#include "interpret.h"
+#include "xalloc.h"
+#include "svalue.h"
+#include "array.h"
+#include "swap.h"
+#include "typedefs.h"
+#include "comm.h"
+#include "mstrings.h"
+#include "mapping.h"
+#include "stdstrings.h"
+#include "random.h"
+#include "dumpstat.h"
+#include "object.h"
+#include "exec.h"
+#include "closure.h"
+#include "ptrtable.h"
+#include "structs.h"
+#include "actions.h"
+#include "heartbeat.h"
+#include "../mudlib/sys/input_to.h"                                                                                                                                   
+
+
+#include <time.h>
+
+#if defined(__x86_64__) || defined(__i386__)
+#define USE_RDTSC
+#else
+#error too slow!
+#endif
+
+#define TYPE_TESTV1(arg1,type1) \
+  if ((arg1)->type != type1) \
+      efun_gen_arg_error(1, type1, arg1);
+
+#define TYPE_TESTV2(arg1,type1) \
+  if ((arg1)->type != type1) \
+      efun_gen_arg_error(2, type1, arg1);
+
+#define TYPE_TESTV3(arg1,type1) \
+  if ((arg1)->type != type1) \
+      efun_gen_arg_error(3, type1, arg1);
+
+#define TYPE_TESTV4(arg1,type1) \
+  if ((arg1)->type != type1) \
+      efun_gen_arg_error(4, type1, arg1);
+
+static int same_path(const char* p1, const char* p2, int len);
+static int count_objects(const char* name, int len);
+
+char catch_write_buf[CATCH_WRITE_MAX_RECURSION][CATCH_WRITE_BUF_LEN+1];
+int catching_write   = 0;
+int save_catching_write = 0;
+object_t* catch_write_cur_interactive = 0;
+int catch_write_len[CATCH_WRITE_MAX_RECURSION];
+typedef struct input_to_s input_to_t;
+struct input_to_s {                                                                                                                                                   
+    input_t     input;                                                                                                                                                
+    callback_t  fun;        /* The function to call, and its args */                                                                                                  
+    p_uint      eval_nr;    /* The thread number where this started. */                                                                                               
+};   
+
+void begin_catch_write()
+{
+	int i;
+
+    if(catching_write)
+    {
+		if (catching_write >= CATCH_WRITE_MAX_RECURSION)
+		{
+			catching_write = 0;
+
+			i = CATCH_WRITE_MAX_RECURSION;
+
+			while (i--)
+			{
+				catch_write_len [i] = 0;
+				catch_write_buf [i][0] = '\0';
+			}
+
+			catch_write_cur_interactive = 0;
+
+			errorf("Too long catch_write() recursion.\n");
+			return;
+		}
+    }
+
+    catch_write_len [catching_write] = 0;
+    catch_write_buf [catching_write][0] = '\0';
+    //    catch_write_cur_interactive = current_interactive;
+    catch_write_cur_interactive = command_giver;
+    catching_write++;
+}
+
+char* end_catch_write()
+{
+    char* tmp = 0;
+    int i;
+
+    if(catching_write == 0)
+		return 0;
+
+    i = catching_write - 1;
+    
+    catch_write_buf[i][CATCH_WRITE_BUF_LEN-1] = '\0';
+    catch_write_buf[i][catch_write_len [i]] = '\0';
+    tmp = string_copy(catch_write_buf [i]);
+
+    catch_write_buf [i][0] = '\0';
+    catch_write_len [i] = 0;
+    catching_write--;
+
+    if (catching_write == 0)
+		catch_write_cur_interactive = 0;
+
+    return tmp;
+}
+
+unsigned long long get_time ()
+{
+#ifdef USE_RDTSC
+	register unsigned long long ret;
+  
+	__asm__ __volatile__ ("rdtsc" : "=A"(ret));
+
+	return ret;
+#else
+  
+#if 1
+	struct timeval tv;
+	unsigned long long ret;
+  
+	gettimeofday (&tv, NULL);
+	ret= (unsigned long long) tv.tv_sec*1000*1000+ tv.tv_usec;
+  
+	return ret;
+  
+#else
+	struct timespec tp;
+	clock_gettime (CLOCK_REALTIME, &tp);
+	return tp.tv_sec*1000*1000+ tp.tv_nsec/1000;
+#endif
+  
+#endif
+}
+
+static double clocks_to_msec = 0;
+
+unsigned long long msec_to_time (double msec)
+{
+  time_to_msec (0);
+  
+  return msec* clocks_to_msec;
+}
+ 
+
+double time_to_msec(const unsigned long long proftime)
+{
+#ifdef USE_RDTSC
+  static unsigned int once= 1;
+
+  if (once)
+    {
+      FILE *f;
+      once= 0;
+      
+      if ( (f= fopen ("/proc/cpuinfo", "r")) )
+	{
+	  while (!feof (f))
+	    {
+	      char line [256];
+	      
+	      *line= 0;
+	      fgets (line, sizeof (line), f);
+	      
+	      if (!memcmp (line, "cpu MHz", strlen ("cpu MHz")) &&
+		  strchr (line, ':'))
+		{
+		  clocks_to_msec= strtod (strchr (line, ':')+1, NULL);
+		  clocks_to_msec *= 1000;
+		  
+		  fclose (f);
+		  
+		  return time_to_msec (proftime);
+		}
+	    }
+	  fclose (f);
+	}
+      
+#define CALIBRATE_TIME_SECS 1
+      
+      if (clocks_to_msec == 0)
+	{
+	  unsigned long long start, end;
+	  
+	  start= get_time ();
+	  sleep (CALIBRATE_TIME_SECS);
+	  end= get_time ();
+	  clocks_to_msec= (end-start)/(CALIBRATE_TIME_SECS* 1000);
+	  
+	  if (!clocks_to_msec)
+	    return 0;
+	}
+    }
+    
+  return proftime/clocks_to_msec;
+#else
+  return proftime/1000;
+#endif
+}
+
+double get_time_ms()
+{
+	return time_to_msec(get_time());
+}
+
+vector_t *all_objects(const char* name, int len)
+{
+    vector_t *v;
+    object_t *ob;
+    int count;
+    int i;
+    char *p, *cp;
+
+    if (len < 0)
+		return 0;
+    cp = string_copy(name);
+    if ((p = strrchr(cp, '#')) != 0)
+		*p = '\0';
+    p = cp;
+    if (*p == '/') {
+		p++;
+		if (len > 0)
+			len--;
+    }
+
+    count = count_objects(name, len);
+    
+    if (count == 0)
+    {
+		xfree(cp);
+		return allocate_array(0);
+    }
+    if (count >= MAX_ARRAY_SIZE)
+		count = MAX_ARRAY_SIZE;
+    
+    v = allocate_uninit_array(count);
+    
+    for (i = 0, ob = obj_list; ob && i < count; ob = ob->next_all) {
+		eval_cost++;
+		if ((ob->flags & O_DESTRUCTED) || !same_path(p, get_txt(ob->name), len))
+			continue;
+		if (ob->flags & O_SWAPPED)
+			load_ob_from_swap(ob);
+
+		v->item[i].type = T_OBJECT;
+		v->item[i].u.ob = ob;
+		put_ref_object(&v->item[i], ob, "all_objects");
+
+		i++;
+    }
+    
+    xfree(cp);
+    return v;
+}
+
+svalue_t *v_all_objects(svalue_t * sp, int n)
+{
+    svalue_t* arg;
+    char *str = 0;
+    vector_t* v;
+    
+    arg = sp - n + 1;
+    
+    switch(arg[0].type) 
+    {
+		case T_OBJECT: str = get_txt(arg[0].u.ob->name); break;
+		case T_STRING: str = get_txt(arg[0].u.str); break;
+		default: TYPE_TESTV1(&arg[0], T_STRING); break;
+    }
+    
+    if (n == 1)
+		v = all_objects(str, 0);
+    else {
+		TYPE_TESTV2(arg+1, T_NUMBER);
+		v = all_objects(str, arg[1].u.number);
+    }
+
+    sp = pop_n_elems(n, sp) + 1;
+    
+    if (v)
+		put_array(sp, v);
+    else
+		put_number(sp, 0);
+    
+    return sp;
+}
+
+static object_t* first_object(const char *name, int len)
+{
+    object_t *ob;
+    char *p;
+    char *cp;
+
+    if (len < 0)
+		return 0;
+    cp = string_copy(name);
+    if ((p = strrchr(cp, '#')) != 0)
+		*p = '\0';
+    p = cp;
+    if (*p == '/') {
+		p++;
+		if (len > 0)
+			len--;
+    }
+   
+    for (ob = obj_list; ob; ob = ob->next_all) {
+		eval_cost++;
+		if (!(ob->flags & O_DESTRUCTED) && same_path(p, get_txt(ob->name), len)) {
+			if (ob->flags & O_SWAPPED)
+				load_ob_from_swap(ob);
+      
+			xfree(cp);
+			return ob;
+		}
+    }
+  
+    xfree(cp);
+    return 0;
+}
+
+svalue_t *v_first_object(svalue_t * sp, int num_arg)
+{
+    object_t *ob;
+    svalue_t *arg;
+    char *str = 0;
+
+    arg = sp - num_arg + 1;
+
+    switch(arg[0].type) 
+    {
+		case T_OBJECT: str = get_txt(arg[0].u.ob->name); break;
+		case T_STRING: str = get_txt(arg[0].u.str); break;
+		default: TYPE_TESTV1(&arg[0], T_STRING); break;
+    }
+  
+    if (num_arg == 1)
+		ob = first_object(str, 0);
+    else {
+		TYPE_TESTV2(&arg[1], T_NUMBER);
+		ob = first_object(str, arg[1].u.number);
+    }
+
+    sp = pop_n_elems(num_arg, sp) + 1;
+  
+    if (ob)
+		put_ref_object(sp, ob, "first_object");
+    else
+		put_number(sp, 0);
+  
+    return sp;
+}
+
+static object_t* next_object(object_t* ob, int len)
+{
+    char *p, *cp;
+
+    if (len < 0)
+		return 0;
+    cp = string_copy(get_txt(ob->name));
+    if ((p = strrchr(cp, '#')) != 0)
+		*p = '\0';
+    p = cp;
+    if (*p == '/') {
+		p++;
+		if (len > 0)
+			len--;
+    }
+
+
+    for(ob = ob->next_all; ob; ob = ob->next_all) {
+		eval_cost++;
+		if (!(ob->flags & O_DESTRUCTED) &&
+			same_path(p, get_txt(ob->name), len)) {
+			if (ob->flags & O_SWAPPED)
+				load_ob_from_swap(ob);
+			xfree(cp);
+			return ob;
+		}
+    }
+    
+    xfree(cp);
+    return 0;
+}
+
+svalue_t *v_next_object(svalue_t * sp, int n)
+{
+    object_t *ob;
+    svalue_t *arg;
+    
+    arg = sp - n + 1;
+
+    TYPE_TESTV1(arg, T_OBJECT);
+    if (n == 1)
+		ob = next_object(arg[0].u.ob, 0);
+    else {
+		TYPE_TESTV2(arg+1, T_NUMBER);
+		ob = next_object(arg[0].u.ob, arg[1].u.number);
+    }
+    
+    sp = pop_n_elems(n, sp) + 1;
+
+    if (ob)
+		put_ref_object(sp, ob, "next_object");
+    else
+		put_number(sp, 0);
+
+    return sp;
+}
+
+svalue_t *f_all_shadow(svalue_t * sp)
+{
+    object_t *ob;
+    vector_t *v;
+    svalue_t *svp;
+    int i;
+
+    TYPE_TESTV1(sp, T_OBJECT);
+
+    ob = sp->u.ob;
+
+    if( !(ob->flags & O_SHADOW) )
+    {
+		i = 0;
+    }
+    else
+    {
+		while (O_GET_SHADOW(ob)->shadowed_by)
+			ob = O_GET_SHADOW(ob)->shadowed_by;
+  
+		for (i = 1; O_GET_SHADOW(ob)->shadowing; i++)
+			ob = O_GET_SHADOW(ob)->shadowing;
+    }
+  
+    v = allocate_uninit_array(i);
+    svp = v->item;
+  
+    while (i--)
+    {
+		put_ref_object(svp, ob, "all_shadow");
+		ob = O_GET_SHADOW(ob)->shadowed_by;
+		svp++;
+    }
+
+    free_svalue(sp);
+    put_array(sp, v);
+
+    return sp;
+}
+
+svalue_t *f_first_shadow(svalue_t * sp)
+{
+    object_t* ob;
+
+    TYPE_TESTV1(sp, T_OBJECT);
+    ob = sp->u.ob;
+
+    if( !(ob->flags & O_SHADOW) )
+    {
+		free_svalue(sp);
+		put_number(sp, 0);
+		return sp;
+    }
+    
+    while (O_GET_SHADOW(ob)->shadowed_by)
+    {
+		ob = O_GET_SHADOW(ob)->shadowed_by;
+		/*	
+		  fprintf(stderr, "FShadow: %s\n", get_txt(ob->name));
+		*/
+    }
+
+    free_svalue(sp);
+    put_ref_object(sp, ob, "first_shadow");
+
+    return sp;
+}
+
+svalue_t *f_last_shadow(svalue_t * sp)
+{
+    object_t* ob;
+
+    TYPE_TESTV1(sp, T_OBJECT);
+    ob = sp->u.ob;
+
+    if( !(ob->flags & O_SHADOW) )
+    {
+		free_svalue(sp);
+		put_number(sp, 0);
+		return sp;
+    }
+    
+    while (O_GET_SHADOW(ob)->shadowing)
+    {
+		ob = O_GET_SHADOW(ob)->shadowing;
+		/*
+		  fprintf(stderr, "LShadow: %s\n", get_txt(ob->name));
+		*/
+    }
+
+    free_svalue(sp);
+    put_ref_object(sp, ob, "last_shadow");
+
+    return sp;
+}
+
+svalue_t *f_next_shadow(svalue_t * sp)
+{
+    object_t* ob;
+    
+    TYPE_TESTV1(sp, T_OBJECT);
+    ob = sp->u.ob;
+
+    if( !(ob->flags & O_SHADOW) )
+    {
+		free_svalue(sp);
+		put_number(sp, 0);
+		return sp;
+    }
+    
+    if(O_GET_SHADOW(ob)->shadowing)
+    {
+		ob = O_GET_SHADOW(ob)->shadowing;
+    }
+    else
+    {
+		free_svalue(sp);
+		put_number(sp, 0);
+		return sp;
+    }
+
+    free_svalue(sp);
+    put_ref_object(sp, ob, "next_shadow");
+
+    return sp;
+}
+
+static int same_path(const char* p1, const char* p2, int len)
+{
+    int len1, len2;
+  
+    if (*p1 != *p2)
+		return 0;
+    len1 = strlen(p1);
+    len2 = strlen(p2);
+    if (len) {
+		if (len2 < len || len > len1)
+			return 0;
+		len1 = len;
+    } else {
+		if (len1 > len2)
+			return 0;
+    }
+    if (strncmp(p1, p2, len1))
+		return 0;
+    if (!len && p2[len1] != '#' && p2[len1] != '\0')
+		return 0;
+    return 1;
+}
+
+static int count_objects(const char* name, int len)
+{
+    int i;
+    object_t* ob;
+    char *p, *cp;
+  
+    if (len < 0)
+		return 0;
+    cp = string_copy(name);
+    if ((p = strrchr(cp, '#')) != 0)
+		*p = '\0';
+    p = cp;
+    if (*p == '/') {
+		p++;
+		if (len > 0)
+			len--;
+    }
+  
+    for (i = 0, ob = obj_list; ob; ob = ob->next_all)
+	{
+		eval_cost++;
+		if (!(ob->flags & O_DESTRUCTED) && same_path(p, get_txt(ob->name), len))
+			i++;
+    }
+	
+    xfree(cp);
+    return i;
+}
+
+
+svalue_t *v_count_objects(svalue_t * sp, int n)
+{
+    svalue_t* arg;
+    char *str = 0;
+    int ret;
+
+    arg = sp - n + 1;
+    
+    switch(arg[0].type) 
+    {
+		case T_OBJECT: str = get_txt(arg[0].u.ob->name); break;
+		case T_STRING: str = get_txt(arg[0].u.str); break;
+		default: TYPE_TESTV1(&arg[0], T_STRING); break;
+    }
+    
+    if (n == 1)
+		ret = count_objects(str, 0);
+    else {
+		TYPE_TESTV2(&arg[1], T_NUMBER);
+		ret = count_objects(str, arg[1].u.number);
+    }
+    
+    sp = pop_n_elems(n, sp) + 1;
+    put_number(sp, ret);
+    
+    return sp;
+}
+
+#define MAX_LINE_LEN    1024
+
+static int count_lines(string_t *file)
+{
+    FILE *f;
+    int ret;
+    static char buff[MAX_LINE_LEN];
+  
+    file = check_valid_path(file, current_object, STR_COUNT_LINES, MY_FALSE);
+    if (file == 0)
+		return 0;
+    f = fopen(get_txt(file), "r");
+    if (f == 0)
+		return -1;
+    ret = 0;
+    while (fgets(buff, MAX_LINE_LEN, f) != 0)
+		ret++;
+    fclose(f);
+    return ret;
+}
+
+svalue_t *f_count_lines(svalue_t *sp)
+{
+    int i;
+  
+    assign_eval_cost();
+    TYPE_TESTV1(sp, T_STRING);
+    i = count_lines(sp->u.str);
+
+    free_svalue(sp);
+   
+    put_number(sp, i);
+    
+    return sp;
+}
+
+
+
+#define MAX_SEND_LEN 16000
+
+static string_t *line_wrap_string(line, prompt, startline, linelen)
+    char *line, *prompt, *startline;
+    int linelen;
+{
+    char *tmp, buff[MAX_SEND_LEN+2];
+    char *srcpos;
+    enum {S_prompt, S_line} curstr;
+    int startlen, curlen, totlen, lastspace, wordlen;
+    int startpos;			/* tmp for startline-add */
+    string_t *new;
+
+    /* clear the first byte because it may be read in the end */
+    buff[0] = 0;
+
+    if (linelen < 21)
+		linelen = 21;
+    wordlen = linelen/4;
+    startlen = strlen(startline);
+    totlen = 0;
+    curlen = 0;
+    lastspace = -1;
+    tmp = buff+1;			/* space for lastspace */
+    srcpos = prompt;
+    curstr = S_prompt;
+
+    while(totlen < (MAX_SEND_LEN-4))
+    {
+		if(*srcpos == '\0')
+		{
+			if(curstr == S_prompt)
+			{
+				curstr = S_line;
+				srcpos = line;
+				continue;
+			}
+			else
+				break;		/* out from while */
+		}
+      
+		tmp[totlen] = *srcpos;
+		if (*srcpos == ' ') {
+			lastspace = totlen;
+		} else if (*srcpos == '\n') { /* reset to line start */
+			lastspace = totlen++;
+			srcpos++;
+			curlen = 0;
+			startpos =totlen;
+			goto startline_add;	/* jump, jump,... */
+		}
+		totlen++;
+		curlen++;
+		srcpos++;
+      
+		if(curlen >= linelen)	/* time to check wrap */
+		{
+			if(totlen-lastspace < wordlen) /* space in asseptable len */
+			{
+				tmp[lastspace] = '\n';
+				curlen = totlen - lastspace - 1;
+				startpos = lastspace + 1;
+			}
+			else			/* force wrap */
+				if(totlen < (MAX_SEND_LEN-4)) /* check there is space to insert */
+				{
+					tmp[totlen] = '\n';
+					lastspace = totlen; /* reset it to line end (\n) (safe place)*/
+					totlen++;
+					startpos = totlen;
+					curlen = 0;
+				}
+				else
+					break;		/* there wasn't space. out of while */
+
+			if(curstr == S_prompt || startlen == 0)
+				continue;
+	  
+			/*
+			 * Insert startline
+			 */
+		startline_add:
+			if(totlen+startlen < (MAX_SEND_LEN-4))
+			{
+				int i;
+				for(i = totlen-1 ; i>=startpos ; i--) /*move old to right place*/
+					tmp[i+startlen] = tmp[i];
+				for(i = 0 ; i<startlen ; i++, startpos++)	/* copy startline */
+					tmp[startpos] = startline[i];
+				curlen += startlen;
+				totlen += startlen;
+			}
+			else
+				break;		/* there wasn't space. out of while */
+		} /* if wrap */
+    } /* while totlen */
+
+    /*
+     * Insert possible last linefeed
+     */
+    if(tmp[totlen-1]!='\n')
+    {
+		tmp[totlen]='\n';
+		totlen++;
+    }
+    tmp[totlen]='\0';
+    totlen++;
+
+    /*
+     * Time to copy & return
+     */
+    
+    new = new_mstring(tmp);
+    return new;
+}
+
+#define DEFAULT_WRAP_LEN	79
+
+svalue_t *v_line_wrap (svalue_t *sp, int num_arg)
+{
+    svalue_t * args;
+    char *str, *first = "", *rest = "";
+    int len = DEFAULT_WRAP_LEN;
+    string_t *new;
+  
+    args = sp - num_arg + 1;
+
+    TYPE_TESTV1(args, T_STRING);
+    str = get_txt(args[0].u.str);
+
+    if(num_arg > 1 && !(args[1].type == T_NUMBER && args[1].u.number == 0))
+    {
+		TYPE_TESTV2(args+1, T_STRING);
+		first = get_txt(args[1].u.str);
+    }
+
+    if(num_arg > 2 && !(args[2].type == T_NUMBER && args[2].u.number == 0))
+    {
+		TYPE_TESTV3(args+2, T_STRING);
+		rest = get_txt(args[2].u.str);
+    }
+
+    if(num_arg > 3)
+    {
+		TYPE_TESTV4(args+3, T_NUMBER);
+		len = args[3].u.number;
+    }
+
+    new = line_wrap_string(str, first, rest, len);
+  
+    sp = pop_n_elems(num_arg, sp) + 1;
+
+    if (new)
+    {
+		put_string(sp, new);
+    } 
+    else
+    {
+		put_number(sp, 0);
+    }
+    
+    return sp;
+}
+
+
+svalue_t *f_nuke_controls (svalue_t *sp, int num_arg)
+{
+    char *s, *d;
+    unsigned char c;
+    string_t *new;
+    int len, i;
+
+    TYPE_TESTV1(sp, T_STRING);
+
+    len = 0;
+    s = get_txt(sp->u.str);
+
+    for(i = 0; i < mstrsize(sp->u.str); i++)
+    {
+		c = s[i];
+
+		if (isprint(c) && c != 0xff)
+			len++;
+    }
+
+    new = alloc_mstring(len);
+    d = get_txt(new);
+
+    for(i = 0; i < mstrsize(sp->u.str); i++)
+    {
+		c = s[i];
+
+		if (isprint(c) && c != 0xff)
+		{
+			*d = c;
+			d++;
+		}
+    }
+
+    free_mstring(sp->u.str);
+    sp->u.str = new;
+
+    return sp;
+}
+
+svalue_t *f_query_input_to(svalue_t * sp, int num_arg)
+{
+    object_t *ob;
+    interactive_t *ip;
+  
+    TYPE_TESTV1(sp, T_OBJECT);
+  
+    ob = sp->u.ob;
+    if (O_SET_INTERACTIVE(ip, ob) && 
+		ip->input_handler)
+    {
+		input_t *ih = ip->input_handler;
+		input_to_t *it = (input_to_t *) ih;
+
+		if(it->fun.is_lambda)
+		{
+			put_number(sp, 0);
+		}
+		else
+		{
+			sp->type = T_STRING;
+			sp->u.str = dup_mstring(it->fun.function.named.name);
+			//	  put_malloced_string(sp, string_copy(ip->input_to->fun.function.named.name));
+		}
+    }
+    else
+    {
+		put_number(sp, 0);
+    }
+  
+    deref_object(ob, "query_input_to");
+  
+    return sp;
+}
+
+svalue_t *
+f_get_backend_times (svalue_t *sp)
+{
+    vector_t* v = allocate_array(4);
+    
+    if (!v)
+		errorf("Out of memory: get_backend_times().\n");
+
+    put_number(v->item, 1);
+    put_number(v->item+1, 2);
+    put_number(v->item+2, 3);
+    put_number(v->item+3, 4);
+
+    sp++;
+    put_array(sp, v);
+
+    return sp;
+}
+
+
+
+/*-------------------------------------------------------------------------*/
+svalue_t *
+f_random_integer (svalue_t *sp)
+    
+/* EFUN random_integer()
+ *
+ *   int random_integer()
+ *
+ * Returns a number in the random range [INT_MIN .. INT_MAX].
+ *
+ * The random number generator is proven to deliver an equal
+ * distribution of numbers over a big range, with no repetition of
+ * number sequences for a long time.
+ */
+
+{
+    push_number(sp, random_integer());
+    return sp;
+} /* f_random_integer() */
+
+/*-------------------------------------------------------------------------*/
+svalue_t *
+f_random_float (svalue_t *sp)
+    
+/* EFUN random_float()
+ *
+ *   float random_float()
+ *
+ * Returns a random float.
+ */
+
+{
+    STORE_DOUBLE_USED
+
+		sp++;
+    sp->type = T_FLOAT;
+    STORE_DOUBLE(sp, random_double());
+
+    return sp;
+} /* f_random_float() */
+
+/*-------------------------------------------------------------------------*/
+svalue_t *
+f_random_gaussian (svalue_t *sp)
+    
+/* EFUN random_gaussian()
+ *
+ *   float random_gaussian()
+ *
+ * Returns a random Gaussian float.
+ */
+
+{
+    STORE_DOUBLE_USED
+
+		sp++;
+    sp->type = T_FLOAT;
+    STORE_DOUBLE(sp, random_gaussian());
+
+    return sp;
+} /* f_random_gaussian() */
+
+
+
+
+svalue_t *f_get_variable_sizes(svalue_t *sp)
+{
+	object_t* ob;
+	vector_t* arr;
+	
+	ob = sp->u.ob;
+
+	arr = get_variable_sizes(ob);
+
+	free_svalue(sp);
+	put_array(sp, arr);
+
+	return sp;
+}
+
+
+
+FILE *g_ref_file;
+static struct pointer_table *ptable;
+
+struct find_ref_map_struct
+{
+	char* thisob;
+	char* thisvar;
+	int num_values;
+};
+
+void find_ref(svalue_t* v, char* thisob, char* thisvar);
+
+void find_ref_map_func (svalue_t *key, svalue_t *values, void *extra)
+{
+	int i;
+
+	struct find_ref_map_struct* str = (struct find_ref_map_struct*)extra;
+	
+	find_ref(key, str->thisob, str->thisvar);
+	
+	for(i = str->num_values; --i >= 0; )
+	{
+		find_ref(values, str->thisob, str->thisvar);
+		values++;
+	}
+}
+
+
+void find_ref(svalue_t* v, char* thisob, char* thisvar)
+{
+	switch(v->type)
+	{
+		case T_OBJECT:
+		{
+			if(v->u.ob->flags & O_DESTRUCTED)
+			{
+				fprintf(g_ref_file,
+						"%s: %s = %s\n", thisob, thisvar,
+						get_txt(v->u.ob->name));
+			}
+			break;
+		}
+
+		case T_MAPPING:
+		{
+			struct find_ref_map_struct str;
+
+			if (NULL == register_pointer(ptable, v->u.map) )
+				break;
+		
+			str.thisob = thisob;
+			str.thisvar = thisvar;
+			str.num_values = v->u.map->num_values;			
+			walk_mapping(v->u.map, find_ref_map_func, &str);
+
+			break;
+		}
+		
+		case T_POINTER:
+		case T_QUOTED_ARRAY:
+		{
+			int i;
+
+			if (v->u.vec == &null_vector)
+				break;
+			
+			if (NULL == register_pointer(ptable, v->u.vec) )
+				break;
+		
+			for (i=0; i < (mp_int)VEC_SIZE(v->u.vec); i++)
+			{
+				find_ref(&v->u.vec->item[i], thisob, thisvar);
+			}
+			
+			break;
+		}
+
+        case T_STRUCT:
+		{
+			struct_t *st = v->u.strct;
+			int i;
+			
+			if (NULL == register_pointer(ptable, st) )
+				break;
+			
+			for (i=0; i < (mp_int)struct_size(st); i++)
+			{
+				find_ref(&st->member[i], thisob, thisvar);
+			}
+			
+            break;
+		}
+		
+		case T_CLOSURE:
+		{
+			int num_values;
+			svalue_t *svp;
+			lambda_t *l;
+			int i;
+
+			if (!CLOSURE_MALLOCED(v->x.closure_type))
+				break;
+			
+			if (!CLOSURE_REFERENCES_CODE(v->x.closure_type))
+				break;
+
+			/* CLOSURE_LAMBDA */
+			l = v->u.lambda;
+
+			if(l->ob != 0)
+			{
+				if(l->ob->flags & O_DESTRUCTED)
+				{
+					fprintf(g_ref_file,
+							"%s: %s L> %s\n", thisob, thisvar,
+							get_txt(l->ob->name));
+				}
+			}
+			
+			if (v->x.closure_type == CLOSURE_BOUND_LAMBDA)
+				l = l->function.lambda;
+
+			num_values = EXTRACT_UCHAR(&l->function.code[0]);
+			if (num_values == 0xff)
+				num_values = ((svalue_t *)l)[-0xff].u.number;
+			
+			svp = (svalue_t *)l - num_values;
+
+			if (NULL == register_pointer(ptable, svp))
+				break;
+			
+			for(i=0; i<num_values; i++)
+			{
+				find_ref(svp++, thisob, thisvar);
+			}
+
+			break;
+		}
+	}
+}
+
+svalue_t *f_dump_destr_ob_refs(svalue_t *sp)
+{
+	object_t* ob;
+
+	add_message("Dumping to DEST_OBJ_REF_DUMP...\n");
+	
+    g_ref_file = fopen("DEST_OBJ_REF_DUMP", "w");
+    if (!g_ref_file)
+	{
+		add_message("...failed!\n");
+        return sp;
+	}
+
+    ptable = new_pointer_table();
+	
+	for (ob = obj_list; ob; ob = ob->next_all)
+	{
+		svalue_t *svp;
+		variable_t* names;
+		int i;
+
+		i = ob->prog->num_variables;
+		svp = ob->variables;
+		names = ob->prog->variables;
+		
+		for (; --i >= 0; svp++, names++)
+		{
+			find_ref(svp, get_txt(ob->name), get_txt(names->name));
+		}
+	}
+
+    free_pointer_table(ptable);
+	
+	fclose(g_ref_file);
+
+	add_message("...done!\n");
+	
+	return sp;
+}
+
+svalue_t* f_query_total_player_commands(svalue_t* sp)
+{
+	push_number(sp, total_player_commands);
+	return sp;
+}
+
+struct profil_line_entry *profil_line_array = 0;
+program_t* profil_line_prog = 0; // program to profile
+object_t* profil_line_ob = 0;    // profile only this ob, or all if 0
+
+svalue_t *v_profil_line_start(svalue_t *sp, int num_arg)
+{
+	program_t* prog;
+	int size;
+
+	if(profil_line_prog)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		
+		push_number(sp, 0);
+		return sp;
+	}
+
+	profil_line_ob = 0;
+
+	if(num_arg == 2)
+	{
+		if(sp->type == T_OBJECT)
+		{
+			/* no deref */
+			profil_line_ob = sp->u.ob;
+		}
+		
+		sp--;
+	}
+	
+    if (sp->type == T_STRING)
+    {
+		object_t* ob = find_object(sp->u.str);
+		if(ob)
+		{
+			prog = ob->prog;
+		}
+		else
+		{
+			errorf("profil_line_start: cant find %s.", get_txt(sp->u.str));
+		}
+    }
+    else
+    {
+		prog = sp->u.ob->prog;
+    }
+
+	free_svalue(sp);
+	sp--;
+	
+	profil_line_prog = prog;
+	reference_prog(prog, "profil_line_start");
+	
+	if(profil_line_array)
+	{
+		free(profil_line_array);
+		profil_line_array = 0;
+	}
+
+	size = PROGRAM_END(*prog) - prog->program;
+	
+	profil_line_array = malloc(size * sizeof(struct profil_line_entry));
+	memset(profil_line_array, 0, size * sizeof(struct profil_line_entry));
+
+	printf("Allocated %d items, %d bytes\n",
+		   size,
+		   (int)(size * sizeof(struct profil_line_entry)));
+
+	
+	push_number(sp, 1);
+	
+	return sp;
+}
+
+
+svalue_t *f_profil_line_dump(svalue_t *sp)
+{
+    STORE_DOUBLE_USED
+	int i, t;
+	int item_count = 0;
+	vector_t* v;
+	
+	if(profil_line_prog == 0)
+	{
+		push_number(sp, 0);
+		return sp;
+	}
+	
+	for(i = 0; i < PROGRAM_END(*profil_line_prog) - profil_line_prog->program; i++)
+	{
+		if(profil_line_array[i].count != 0)
+		{
+			item_count++;
+		}
+	}
+
+    v = allocate_uninit_array(item_count * 8);
+
+	t = 0;
+	for(i = 0; i < PROGRAM_END(*profil_line_prog) - profil_line_prog->program; i++)
+	{
+		if(profil_line_array[i].count != 0)
+		{
+			string_t* filename;
+			int line;
+			
+			line = get_line_number(profil_line_prog->program + i,
+								   profil_line_prog,
+								   &filename);
+			
+			v->item[t].type = T_STRING;
+			v->item[t].u.str = filename;
+			t++;
+
+			v->item[t].type = T_NUMBER;
+			v->item[t].u.number = line;
+			t++;
+
+			v->item[t].type = T_STRING;
+            memcpy(&v->item[t].u.str, FUNCTION_NAMEP(profil_line_array[i].funstart), sizeof(string_t*));
+			ref_mstring(v->item[t].u.str);
+			t++;
+			
+			v->item[t].type = T_FLOAT;
+			STORE_DOUBLE(&v->item[t], time_to_msec(profil_line_array[i].time));
+			t++;
+
+			v->item[t].type = T_FLOAT;
+			STORE_DOUBLE(&v->item[t], time_to_msec(profil_line_array[i].max_time));
+			t++;
+			
+			v->item[t].type = T_FLOAT;
+			STORE_DOUBLE(&v->item[t], time_to_msec(profil_line_array[i].self_time));
+			t++;
+
+			v->item[t].type = T_FLOAT;
+			STORE_DOUBLE(&v->item[t], time_to_msec(profil_line_array[i].max_self_time));
+			t++;
+			
+			v->item[t].type = T_NUMBER;
+			v->item[t].u.number = profil_line_array[i].count;
+			t++;
+		}
+	}
+
+	push_array(sp, v);
+
+	return sp;
+}
+
+svalue_t *f_profil_line_stop(svalue_t *sp)
+{
+	if(profil_line_prog == 0)
+	{
+		return sp;
+	}
+	
+	free_prog(profil_line_prog, MY_TRUE);
+	profil_line_prog = 0;
+
+	if(profil_line_ob)
+	{
+		free_object(profil_line_ob, "profil_line_stop");
+		profil_line_ob = 0;
+	}
+	
+	if(profil_line_array)
+	{
+		free(profil_line_array);
+		profil_line_array = 0;
+	}
+
+	return sp;
+}
+
+svalue_t* f_debug_sleep (svalue_t *sp)
+{
+  time_t from, to;
+
+  time (&from);
+  to= from+ sp->u.number;
+
+  if (from < to)
+    while (time (NULL) < to)
+      ;
+
+  free_svalue (sp);
+  put_number (sp, 0);
+  return sp;
+}
+
+svalue_t* f_get_time_ms (svalue_t *sp)
+{
+  STORE_DOUBLE_USED
+    
+    sp++;
+  sp->type = T_FLOAT;
+  STORE_DOUBLE(sp, get_time_ms ());
+
+  return sp;
+}
+
+svalue_t* f_true_time (svalue_t *sp)
+{
+  sp++;
+  put_number (sp, time (NULL));
+  return sp;
+}
+  
+svalue_t *
+f_recompile_object (svalue_t * sp)
+{
+    object_t *this_ob, *ob;
+    string_t *name;
+    long ret;
+
+    this_ob = sp->u.ob;
+
+    ob = get_object(this_ob->load_name);
+
+    ret = 0;
+
+    if (ob != NULL)
+      {
+	/* If ob is a clone, try finding the blueprint first via the object's
+	 * program, then via the load_name.
+	 */
+	if (ob->flags & O_CLONE)
+	  {
+	    object_t *bp = NULL;
+	    
+	    /* If the object's program hasn't been replaced, it most likely
+	     * contains a pointer to the blueprint we're looking for.
+	     */
+	    if (!(ob->flags & O_REPLACED))
+	      {
+		bp = ob->prog->blueprint;
+		if (bp && (bp->flags & O_DESTRUCTED))
+		  {
+		    free_object(bp, "recompile_object");
+		    bp = ob->prog->blueprint = NULL;
+		  }
+	      }
+	    
+	    /* Fallback: find/load the blueprint by the load_name */
+	    if (!bp)
+	      bp = get_object(ob->load_name);
+	    if (bp)
+	      ob = bp;
+	  }
+	
+	if (ob->super)
+	  errorf("Recompiling a bad object: '%s' is contained in '%s'.\n"
+		, get_txt(ob->name), get_txt(ob->super->name));
+	
+	name = ob->name;
+	
+	/* If the ob is a clone, we have to test if its name is something
+	 * illegal like 'foobar#34'. In that case, we have to use the
+	 * load_name as template.
+	 */
+	if (ob->flags & O_CLONE)
+	  {
+	    char c;
+	    char *p;
+	    mp_int name_length, i;
+	    
+	    name_length = mstrsize(name);
+	    i = name_length;
+	    p = get_txt(ob->name)+name_length;
+	    while (--i > 0) {
+	      /* isdigit would need to check isascii first... */
+	      if ( (c = *--p) < '0' || c > '9' )
+		{
+		  if (c == '#' && name_length - i > 1)
+		    {
+		      /* Well, unusable name format - use the load_name */
+		      name = ob->load_name;
+		    }
+		  break;
+		}
+	    }
+	  }
+	
+	if ((ob->flags & O_SWAPPED) && load_ob_from_swap(ob) < 0)
+	  errorf("Out of memory: unswap object '%s'\n", get_txt(ob->name));
+	
+	if (ob->prog->flags & P_NO_CLONE)
+	  errorf("Cloning a bad object: '%s' sets '#pragma no_clone'.\n"
+		, get_txt(ob->name));
+
+	ob->time_of_ref = current_time;
+	
+	/* We do not want the heart beat to be running for unused copied objects */
+	
+	if (!(ob->flags & O_CLONE) && ob->flags & O_HEART_BEAT)
+	  set_heart_beat(ob, MY_FALSE);
+	
+	/* Got the blueprint */
+
+	free_prog (this_ob->prog, MY_FALSE);
+
+	this_ob->prog = ob->prog;
+
+	reference_prog (this_ob->prog, "recompile_object");
+
+	ret = 1;
+      }
+
+    free_svalue(sp);
+
+    put_number(sp, ret);
+
+    return sp;
+} /* f_recompile_object() */
+
+
+unsigned long long warning_eval_cost_ticks_amt;
+
+/* in milliseconds. use 0 to disable (default). */
+
+svalue_t *
+f_set_warning_eval_cost (svalue_t *sp)
+{
+
+  warning_eval_cost_ticks_amt= msec_to_time (sp->u.number);
+
+  free_svalue (sp);
+  
+  put_number (sp, 0);
+  return sp;
+}
diff -ruN /home/favorit/ldmud-3.3.719/src/bat.h ./bat.h
--- /home/favorit/ldmud-3.3.719/src/bat.h	1970-01-01 02:00:00.000000000 +0200
+++ ./bat.h	2009-09-03 11:49:52.000000000 +0300
@@ -0,0 +1,77 @@
+#ifndef BAT_H__
+#define BAT_H__
+
+#include "svalue.h"
+#include "exec.h"
+#include "profil2.h"
+
+svalue_t *f_all_shadow(svalue_t * sp);
+svalue_t *f_first_shadow(svalue_t * sp);
+svalue_t *f_last_shadow(svalue_t * sp);
+svalue_t *f_next_shadow(svalue_t * sp);
+
+svalue_t *v_all_objects(svalue_t * sp, int n);
+svalue_t *v_first_object(svalue_t * sp, int n);
+svalue_t *v_next_object(svalue_t * sp, int n);
+
+svalue_t *v_count_objects(svalue_t * sp, int n);
+svalue_t *f_count_lines(svalue_t *sp);
+
+/* catch_write() stuff */
+
+void   begin_catch_write();
+char*  end_catch_write();
+
+#define CATCH_WRITE_BUF_LEN  (10*16*1024) // x10 by blitzer jan.15.2004
+#define CATCH_WRITE_MAX_RECURSION 5
+
+#ifndef BAT_C__
+extern char catch_write_buf[CATCH_WRITE_MAX_RECURSION][CATCH_WRITE_BUF_LEN];
+extern int catching_write;
+extern int save_catching_write;
+extern int catch_write_len[CATCH_WRITE_MAX_RECURSION];
+extern object_t* catch_write_cur_interactive;
+#endif
+
+/* end of catch_write() stuff */
+
+/* time stuff */
+
+unsigned long long get_time ();
+double time_to_msec(const unsigned long long proftime);
+unsigned long long msec_to_time (double msec);
+
+double get_time_ms();
+
+/* word stuff */
+
+void word_init();
+
+extern svalue_t *f_random_integer(svalue_t *);
+extern svalue_t *f_random_float(svalue_t *);
+extern svalue_t *f_random_gaussian(svalue_t *);
+
+extern svalue_t *f_dump_variables(svalue_t *);
+extern svalue_t *f_dump_destr_ob_refs(svalue_t *);
+
+struct profil_line_entry
+{
+	unsigned long long time;
+	unsigned long long max_time;
+	unsigned long long self_time;
+	unsigned long long max_self_time;
+	unsigned int count;
+	fun_hdr_p funstart;
+};
+
+extern struct profil_line_entry *profil_line_array;
+extern program_t* profil_line_prog;
+extern object_t* profil_line_ob;
+
+
+extern unsigned long long warning_eval_cost_ticks_amt;
+
+svalue_t *f_set_warning_eval_cost_ticks (svalue_t *sp);
+
+
+#endif
diff -ruN /home/favorit/ldmud-3.3.719/src/comm.c ./comm.c
--- /home/favorit/ldmud-3.3.719/src/comm.c	2009-06-15 01:18:52.000000000 +0300
+++ ./comm.c	2009-09-03 13:21:06.000000000 +0300
@@ -130,6 +130,9 @@
 #include "swap.h"
 #include "wiz_list.h"
 #include "xalloc.h"
+#include "bat.h"
+
+#include "i-eval_cost.h"
 
 #include "i-eval_cost.h"
 
@@ -1800,6 +1803,38 @@
             srcstr = NULL;
         }
 
+//#ifdef BAT
+        if(catching_write &&
+           catch_write_cur_interactive == command_giver)
+		{
+            if(srclen > CATCH_WRITE_BUF_LEN -
+               catch_write_len [catching_write - 1])
+			{
+				int i;
+                catching_write = 0;
+				
+                i = CATCH_WRITE_MAX_RECURSION;
+				
+                while (i--)
+				{
+                    catch_write_len [i] = 0;
+                    catch_write_buf [i][0] = '\0';
+				}
+				
+                catch_write_cur_interactive = 0;
+				
+                errorf("catch_write buffer full.\n");
+                return;
+			}
+			
+            strncpy(&catch_write_buf [catching_write - 1][catch_write_len [catching_write - 1]],
+                    source, srclen);
+            catch_write_len [catching_write - 1] += srclen;
+			
+            return;
+		}
+//#endif
+
         /* If we're not sending a telnet command with this message,
          * pass on the new data to any snooper and/or shadow
          */
@@ -2288,7 +2323,7 @@
                     continue;
                 }
 
-                if (ip->tn_state == TS_READY)
+                if (ip->tn_state == TS_READY || ip->push_end > 0) // BAT
                 {
                     /* If telnet is ready for commands, react quickly. */
                     twait = 0;
@@ -3145,28 +3180,47 @@
              * a command is complete, the tn_state is TS_READY.
              */
             DTN(("tn complete, telnet machine state: %hhd\n", ip->tn_state));
-            if (ip->tn_state == TS_READY)
+            if (ip->tn_state == TS_READY || ip->push_end > 0) // BAT
             {
                 /* We have a command: copy it into buff, handle a
                  * possible snooper and return.
                  */
 
-                DTN(("telnet machine ready\n"));
-                /* buffer overflows here are impossible even with strcpy(),
-                 * because buff is allocated in backend() as MAX_TEXT+4 and
-                 * ip->text is allocated as MAX_TEXT+2. Ok, as long as nobody
-                 * changes buff in backend() withour changing ip->text ... */
-                strcpy(buff, ip->text);
-                command_giver = ip->ob;
-                trace_level = ip->trace_level;
-                ip->chars_ready = 0; /* for escaped charmode */
-
-                /* Reinitialize the telnet machine, possibly already
-                 * producing the next command in .text[].
-                 */
-                ip->tn_state = TS_DATA;
-                telnet_neg(ip);
-
+//#ifdef BAT
+				if(ip->push_end > 0)
+                {
+					int pushlen;
+					
+					/* Check for max size only in copying, because
+					   otherwise the shit has already hit the fan */
+					strncpy(buff, ip->push_buf, MAX_TEXT);
+					buff[MAX_TEXT-1] = '\0';
+					command_giver = ip->ob;
+					trace_level = ip->trace_level;
+					
+					pushlen = strlen(ip->push_buf)+1;
+					ip->push_end -= pushlen;
+					if(ip->push_end > 0)
+						memmove(ip->push_buf, ip->push_buf+pushlen, ip->push_end);
+                } else {
+//#endif
+					DTN(("telnet machine ready\n"));
+					/* buffer overflows here are impossible even with strcpy(),
+					* because buff is allocated in backend() as MAX_TEXT+4 and
+					* ip->text is allocated as MAX_TEXT+2. Ok, as long as nobody
+					* changes buff in backend() withour changing ip->text ... */
+					strcpy(buff, ip->text);
+					command_giver = ip->ob;
+					trace_level = ip->trace_level;
+					ip->chars_ready = 0; /* for escaped charmode */
+
+					/* Reinitialize the telnet machine, possibly already
+					 * producing the next command in .text[].
+					 */
+					ip->tn_state = TS_DATA;
+					telnet_neg(ip);
+				}
+				
                 /* If the user is not in ed, don't let him issue another command
                  * before the poll comes again.
                  */
@@ -3677,6 +3731,7 @@
     new_interactive->quote_iac = MY_TRUE;
     set_default_conn_charset(new_interactive->charset);
     set_default_combine_charset(new_interactive->combine_cset);
+    new_interactive->push_end = 0; // BAT
     new_interactive->text[0] = '\0';
     memcpy(&new_interactive->addr, addr, addrlen);
     new_interactive->access_class = class;
@@ -4420,6 +4475,19 @@
         print_prompt_string(STR_DEFAULT_PROMPT);
     }
 
+//#ifdef BAT
+	char msg[2];
+	
+	msg[0] = IAC;
+	msg[1] = GA;
+	SEND_TELNET_COMMAND(
+		add_message(FMT_BINARY, msg, 2);
+		add_message(message_flush);
+		);
+
+	//add_message("%c%c", IAC, GA); // BAT
+//#endif
+	
     current_object = save_current;
     previous_ob = save_previous;
 } /* print_prompt() */
@@ -5422,6 +5490,21 @@
                 DTN(("t_n: got NOP\n")); break;
             case GA:
                 DTN(("t_n: got GA\n")); break;
+//#ifdef BAT
+			case AYT:
+				command_giver = ip->ob;
+                DTN(("t_n: got AYT\n"));
+				char msg[2];
+				
+				msg[0] = IAC;
+				msg[1] = AYT;
+				SEND_TELNET_COMMAND(
+					add_message(FMT_BINARY, msg, 2);
+					add_message(message_flush);
+					);
+				
+				break;
+//#endif	
             default:
                 DTN(("t_n: got %02hhx\n", ch)); break;
                 break;
@@ -9210,3 +9293,60 @@
 } /* f_configure_interactive() */
 
 /***************************************************************************/
+
+//#ifdef BAT
+int push_line_to_player(object_t *ob, char *line)
+{
+  interactive_t *ip;
+  int x;
+  int linelen = 0;
+
+  if (strchr(line, '\n'))
+    return 0;
+  if (strchr(line, '\r'))
+    return 0;
+
+  for (x=0; x< MAX_PLAYERS; x++)
+    if (all_players[x] && all_players[x]->ob == ob)
+      break;
+
+  if (x == MAX_PLAYERS)
+    return 0;
+
+  ip = all_players[x];
+
+  linelen = strlen(line)+1;
+
+  if (linelen + ip->push_end > MAX_PUSH)
+    return 0;
+
+  if(ip->push_end > 0)
+    memmove(ip->push_buf + linelen, ip->push_buf, ip->push_end);
+  strcpy(ip->push_buf, line);
+  ip->push_end += linelen;
+
+  return 1;
+}
+
+svalue_t *
+f_push_line (svalue_t *sp)
+{
+  if (current_object->flags & O_DESTRUCTED)
+    {
+      free_svalue(sp);
+      put_number(sp, 0);
+    }
+  else
+    {
+      int i;
+
+      i = push_line_to_player(current_object, get_txt(sp[0].u.str));
+
+      free_svalue(sp);
+      put_number(sp, i);
+    }
+
+  return sp;
+} /* f_push_line() */
+
+//#endif
diff -ruN /home/favorit/ldmud-3.3.719/src/comm.h ./comm.h
--- /home/favorit/ldmud-3.3.719/src/comm.h	2009-06-15 01:18:52.000000000 +0300
+++ ./comm.h	2009-09-03 12:30:44.000000000 +0300
@@ -40,6 +40,10 @@
 #    endif /* irix */
 #endif /* MAX_SOCKET_PACKET_SIXE */
 
+#ifdef BAT
+#undef MAX_SOCKET_PACKET_SIZE
+#define MAX_SOCKET_PACKET_SIZE (1024*16)
+#endif
 
 /* --- IPv6 --- */
 
@@ -79,6 +83,13 @@
 
 #define MAX_TEXT  2048
 
+//#ifdef BAT
+/* Size of a users push buffer for pushed data.
+ * This is also the maximum size for a push.
+ */
+#define MAX_PUSH 2048
+//#endif
+
 /* 'Format string' to use with add_message() when sending
  * a string_t* string to the player.
  */
@@ -235,6 +246,7 @@
     string_t *trace_prefix;     /* Trace only objects which have this string
                                    as name prefix. NULL traces everything. */
     int message_length;         /* Current length of message in message_buf[] */
+	int push_end;               /* first free char in push_buf[] */ // BAT
 
     object_t *next_player_for_flush;
     object_t *previous_player_for_flush;
@@ -262,6 +274,12 @@
     char gobble_char;           /* Char to ignore at the next telnet_neg() */
     char ts_data;               /* Telnet suboption? */
 
+//#ifdef BAT
+	char push_buf[MAX_PUSH];
+	/* The push buffer. It contains command pushed from the mud side
+	   to the input queue. The commands are separated by '\0'.*/
+//#endif
+
     char text[MAX_TEXT+2];
       /* The receive buffer. It can contain two extra characters:
        * a '\r' that is recognized only after another character is read,
diff -ruN /home/favorit/ldmud-3.3.719/src/config.h.in ./config.h.in
--- /home/favorit/ldmud-3.3.719/src/config.h.in	2009-06-15 01:18:52.000000000 +0300
+++ ./config.h.in	2009-09-03 12:30:44.000000000 +0300
@@ -619,14 +619,14 @@
  * TODO: Remove if it doesn't help with the fragmentation, as it uses up
  * TODO:: a small, but measurable amount of time in the allocator.
  */
-#define MALLOC_ORDER_LARGE_FREELISTS
+#undef MALLOC_ORDER_LARGE_FREELISTS
 
 /* Order slaballoc partial-slab freelists by number of free blocks.
  * Supported by: MALLOC_slaballoc.
  * TODO: Remove if it doesn't help with the fragmentation, as it uses up
  * TODO:: a small, but measurable amount of time in the allocator.
  */
-#define MALLOC_ORDER_SLAB_FREELISTS
+#undef MALLOC_ORDER_SLAB_FREELISTS
 
 /* Allow slaballoc to use multiples of DESIRED_SLAB_SIZE when creating
  * new slabs.
diff -ruN /home/favorit/ldmud-3.3.719/src/crc32.c ./crc32.c
--- /home/favorit/ldmud-3.3.719/src/crc32.c	1970-01-01 02:00:00.000000000 +0200
+++ ./crc32.c	2009-09-03 11:49:52.000000000 +0300
@@ -0,0 +1,111 @@
+/*
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+ *  code or tables extracted from it, as desired without restriction.
+ *
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to hight-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera
+ *      tions for all combinations of data and CRC register values
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc
+ *      logic; the shift must be u_(bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions
+ *      polynomial $edb88320
+ */
+
+
+#include "crc32.h"
+
+static unsigned int crc32_tab[] = {
+	0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+	0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+	0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+	0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+	0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+	0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+	0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+	0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+	0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+	0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+	0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+	0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+	0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+	0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+	0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+	0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+	0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+	0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+	0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+	0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+	0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+	0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+	0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+	0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+	0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+	0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+	0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+	0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+	0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+	0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+	0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+	0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+	0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+	0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+	0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+	0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+	0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+	0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+	0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+	0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+	0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+	0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+	0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+	0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+	0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+	0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+	0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+	0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+	0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+	0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+	0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+	0x2d02ef8dL
+};
+
+/* Return a 32-bit CRC of the contents of the buffer. */
+
+unsigned int
+ssh_crc32(const unsigned char *s, unsigned int len)
+{
+  unsigned int i;
+  unsigned int crc32val;
+  
+  crc32val = 0;
+  for (i = 0;  i < len;  i ++) {
+    crc32val = crc32_tab[(crc32val ^ s[i]) & 0xff] ^ (crc32val >> 8);
+  }
+  return crc32val;
+}
diff -ruN /home/favorit/ldmud-3.3.719/src/crc32.h ./crc32.h
--- /home/favorit/ldmud-3.3.719/src/crc32.h	1970-01-01 02:00:00.000000000 +0200
+++ ./crc32.h	2009-09-03 11:49:52.000000000 +0300
@@ -0,0 +1,25 @@
+/*
+ * Author: Tatu Ylonen <ylo@cs.hut.fi>
+ * Copyright (c) 1992 Tatu Ylonen, Espoo, Finland
+ *                    All rights reserved
+ * Functions for computing 32-bit CRC.
+ *
+ * As far as I am concerned, the code I have written for this software
+ * can be used freely for any purpose.  Any derived versions of this
+ * software must be clearly marked as such, and if the derived work is
+ * incompatible with the protocol description in the RFC file, it must be
+ * called by a name other than "ssh" or "Secure Shell".
+ */
+
+/* RCSID("$OpenBSD: crc32.h,v 1.9 2000/12/19 23:17:56 markus Exp $"); */
+
+#ifndef CRC32_H
+#define CRC32_H
+
+/*
+ * This computes a 32 bit CRC of the data in the buffer, and returns the CRC.
+ * The polynomial used is 0xedb88320.
+ */
+unsigned int ssh_crc32(const unsigned char *buf, unsigned int len);
+
+#endif				/* CRC32_H */
diff -ruN /home/favorit/ldmud-3.3.719/src/dumpstat.c ./dumpstat.c
--- /home/favorit/ldmud-3.3.719/src/dumpstat.c	2009-06-15 01:18:52.000000000 +0300
+++ ./dumpstat.c	2009-09-03 12:20:24.000000000 +0300
@@ -429,3 +429,45 @@
 
 /***************************************************************************/
 
+//#ifdef BAT
+/*-------------------------------------------------------------------------*/
+vector_t*
+get_variable_sizes(object_t *ob)
+{
+  mp_int Total = 0;
+  mp_int total = sizeof(p_int); /* smalloc overhead */
+  int i;
+  svalue_t *svp;
+  variable_t* names;
+  vector_t* arr;
+
+  i = ob->prog->num_variables;
+
+  ptable = new_pointer_table();
+  if (!ptable)
+    errorf("(dumpstat) Out of memory for new pointer table.\n");
+
+  svp = ob->variables;
+  names = ob->prog->variables;
+
+  arr = allocate_array(i * 3);
+
+  for (; --i >= 0; svp++, names++)
+    {
+      mp_int tmp1, tmp2;
+
+      tmp1 = svalue_size(svp, &tmp2) + sizeof (svalue_t);
+      total += tmp1;
+      tmp2 += sizeof(svalue_t);
+      Total += tmp2;
+
+      put_ref_string(&(arr->item[(i-0)*3 + 0]), names->name);
+      put_number(&(arr->item[(i-0)*3 + 1]), tmp1);
+      put_number(&(arr->item[(i-0)*3 + 2]), tmp2);
+    }
+
+  free_pointer_table(ptable);
+
+  return arr;
+} /* get_variable_sizes() */
+//#endif
diff -ruN /home/favorit/ldmud-3.3.719/src/dumpstat.h ./dumpstat.h
--- /home/favorit/ldmud-3.3.719/src/dumpstat.h	2009-06-15 01:18:52.000000000 +0300
+++ ./dumpstat.h	2009-09-03 11:49:52.000000000 +0300
@@ -8,5 +8,6 @@
 extern mp_int program_string_size (program_t *prog, mp_int * pOverhead, mp_int * pData);
 extern Bool dumpstat(string_t *name);
 extern Bool dumpstat_dest(string_t *name);
+extern vector_t* get_variable_sizes (object_t *ob); // BAT
 
 #endif /* DUMPSTAT_H__ */
diff -ruN /home/favorit/ldmud-3.3.719/src/efuns.c ./efuns.c
--- /home/favorit/ldmud-3.3.719/src/efuns.c	2009-06-15 01:18:52.000000000 +0300
+++ ./efuns.c	2009-09-03 12:30:44.000000000 +0300
@@ -3420,6 +3420,7 @@
             *(nump = &info->min) = 0;
             continue;
 
+		case 'i': // BAT
         case 'd':
             /* Skip leading whitespace */
             while(isspace((unsigned char)*str))
@@ -5839,6 +5840,13 @@
     default:
         fatal("Bad arg 1 to to_array(): type %s\n", typename(sp->type));
         break;
+//#ifdef BAT
+    case T_NUMBER:
+      if(sp->type == T_NUMBER && sp->u.number == 0)
+        {
+          break;
+        }
+//#endif
     case T_STRING:
     case T_SYMBOL:
         /* Split the string into an array of ints */
@@ -6225,7 +6233,8 @@
         return sp;
 
     case T_STRING:
-        o = find_object(sp->u.str);
+        //o = find_object(sp->u.str);
+        o = get_object(sp->u.str);  // BAT
         free_svalue(sp);
         break;
     }
diff -ruN /home/favorit/ldmud-3.3.719/src/func_spec ./func_spec
--- /home/favorit/ldmud-3.3.719/src/func_spec	2009-06-15 01:18:52.000000000 +0300
+++ ./func_spec	2009-10-03 00:05:01.000000000 +0300
@@ -70,6 +70,7 @@
 #endif
         local
         catch
+        catch_write /* BAT */
 "++"    inc
 "--"    dec
 "x++"   post_inc
@@ -142,6 +143,7 @@
  * called from LPC.
  */
 
+        end_catch_write /* BAT */
         pop_value
         pop_second
         dup
@@ -296,6 +298,7 @@
 
         /* Functions and Closures */
 
+unknown call_shadow(object|string|object *|string *, string, ...); /* BAT */
 unknown call_other(object|string|object *|string *, string, ...);
 unknown call_direct(object|string|object *|string *, string, ...);
           /* The lexer switches the return type between 'unknown'
@@ -356,11 +359,11 @@
 string  to_string(mixed);
 #ifdef USE_STRUCTS
 int     baseof(struct, struct);
-mixed  *to_array(string|mixed*|symbol|quoted_array|struct);
+mixed  *to_array(string|mixed*|symbol|quoted_array|struct|null); /* BAT */
 mixed   to_struct(mapping|mixed*|struct, void|struct);
 mixed  *struct_info(struct, int);
 #else
-mixed  *to_array(string|mixed*|symbol|quoted_array);
+mixed  *to_array(string|mixed*|symbol|quoted_array|null); /* BAT */
 #endif /* USE_STRUCTS */
 object  to_object(null|object|string|closure);
 
@@ -542,9 +545,9 @@
 object  shadow(object, int);
 int     snoop(object, void|object);
 #ifdef USE_STRUCTS
-void    tell_object(object|string, string|mixed*|mapping|struct|object);
+void    tell_object(object|string, string|mixed*|mapping|struct|object, int default: F_CONST0); /* BAT */
 #else
-void    tell_object(object|string, string|mixed*|mapping|object);
+void    tell_object(object|string, string|mixed*|mapping|object, int default: F_CONST0); /* BAT */
 #endif /* USE_STRUCTS */
 void    unshadow();
 string  variable_exists(string, void|int|object, void|int);
@@ -796,5 +799,56 @@
 
 #endif /* USE_DEPRECATED */
 
+        /* BAT specific efuns */
+
+int     count_objects(object|string, void|int);
+int     count_lines(string);
+object  first_object(object|string, void|int);
+object  next_object(object, void|int);
+object  *all_objects(object|string, void|int);
+object  *all_shadow(object default: F_THIS_OBJECT);
+object  first_shadow(object default: F_THIS_OBJECT);
+object  last_shadow(object default: F_THIS_OBJECT);
+object  next_shadow(object default: F_THIS_OBJECT);
+string  line_wrap(string, void|null|string, void|null|string, void|int);
+string  nuke_controls(string);
+string  query_input_to(object default: F_THIS_OBJECT);
+int     push_line(string);
+
+int*    get_backend_times();
+
+
+/* mixed *erusage(int); */
+
+string  socket_strerror(int);
+void    socket_print_stats();
+int     socket_create(closure);
+int     socket_close(int);
+int     socket_connect(int, string, closure, closure);
+int     socket_bind(int, int);
+int     socket_listen(int, closure);
+int     socket_accept(int, closure, closure);
+int     socket_send(int, string);
+string  socket_address(int);
+
+int     random_integer();
+float   random_float();
+float   random_gaussian();
+
+mixed*  get_variable_sizes(object);
+void    dump_destr_ob_refs();
+
+int             query_total_player_commands();
+
+int     debug_sleep (int);
+float   get_time_ms ();
+int     true_time ();
+
+int     recompile_object (object);
+
+int     set_warning_eval_cost (int);
+
+/* end of BAT specific efuns */
+
 
 /***************************************************************************/
diff -ruN /home/favorit/ldmud-3.3.719/src/gcollect.c ./gcollect.c
--- /home/favorit/ldmud-3.3.719/src/gcollect.c	2009-06-15 01:18:52.000000000 +0300
+++ ./gcollect.c	2009-09-03 12:30:44.000000000 +0300
@@ -123,6 +123,9 @@
 #include "swap.h"
 #include "wiz_list.h"
 #include "xalloc.h"
+#include "sockets.h" // BAT
+
+#include "i-eval_cost.h"
 
 #include "i-eval_cost.h"
 
@@ -2053,6 +2056,8 @@
        * processing (and potentially swapping) the objects.
        */
 
+    clear_socket_refs(); // BAT
+	
     null_vector.ref = 0;
 
     /* Finally, walk the list of destructed objects and clear all references
@@ -2264,6 +2269,8 @@
 
     mb_note_refs();
 
+	clear_socket_refs(); // BAT
+
     if (reserved_user_area)
         note_ref(reserved_user_area);
     if (reserved_master_area)
Binary files /home/favorit/ldmud-3.3.719/src/hosts/amiga/ldmud.info and ./hosts/amiga/ldmud.info differ
Binary files /home/favorit/ldmud-3.3.719/src/hosts/amiga/README.Amiga.info and ./hosts/amiga/README.Amiga.info differ
Binary files /home/favorit/ldmud-3.3.719/src/hosts/amiga/StartMUD.info and ./hosts/amiga/StartMUD.info differ
Binary files /home/favorit/ldmud-3.3.719/src/hosts/be/driver.rsrc and ./hosts/be/driver.rsrc differ
Binary files /home/favorit/ldmud-3.3.719/src/hosts/be/icon-16x16.raw and ./hosts/be/icon-16x16.raw differ
Binary files /home/favorit/ldmud-3.3.719/src/hosts/be/icon-32x32.raw and ./hosts/be/icon-32x32.raw differ
Binary files /home/favorit/ldmud-3.3.719/src/hosts/win32/Readme.rtf and ./hosts/win32/Readme.rtf differ
Binary files /home/favorit/ldmud-3.3.719/src/hosts/win32/tubmud.bmp and ./hosts/win32/tubmud.bmp differ
diff -ruN /home/favorit/ldmud-3.3.719/src/i-eval_cost.h ./i-eval_cost.h
--- /home/favorit/ldmud-3.3.719/src/i-eval_cost.h	2009-06-15 01:18:52.000000000 +0300
+++ ./i-eval_cost.h	2009-09-03 13:02:18.000000000 +0300
@@ -64,7 +64,7 @@
 
 /* Reset the evaluation cost/time counter.
  */
-#define CLEAR_EVAL_COST (assigned_eval_cost = eval_cost = 0)
+//#define CLEAR_EVAL_COST (assigned_eval_cost = eval_cost = 0)
 
 /* Check if the current evaluation took too long
  */
diff -ruN /home/favorit/ldmud-3.3.719/src/interpret.c ./interpret.c
--- /home/favorit/ldmud-3.3.719/src/interpret.c	2009-06-15 01:18:52.000000000 +0300
+++ ./interpret.c	2009-10-02 23:50:30.000000000 +0300
@@ -307,6 +307,10 @@
     int variable_index_offset;
       /* Function and variable index offset.
        */
+
+//#ifdef BAT
+  char *class_name_for_this_function; /* true class in which this was defined */
+//#endif
 };
 
 /*-------------------------------------------------------------------------*/
@@ -559,6 +563,9 @@
    * assign_eval_cost().
    */
 
+unsigned long long eval_cost_warning_start_ticks;
+unsigned long long eval_cost_warning_total_ticks;
+
 svalue_t apply_return_value = { T_NUMBER };
   /* This variable holds the result from a call to apply(), transferred
    * properly from the interpreter stack where the called function
@@ -735,7 +742,7 @@
 /* Forward declarations */
 
 enum { APPLY_NOT_FOUND = 0, APPLY_FOUND, APPLY_DEFAULT_FOUND };
-static int int_apply(string_t *, object_t *, int, Bool, Bool);
+static int int_apply(string_t *, object_t *, int, Bool, Bool, Bool); // BAT
 static void call_simul_efun(unsigned int code, object_t *ob, int num_arg);
 #ifdef DEBUG
 static void check_extra_ref_in_vector(svalue_t *svp, size_t num);
@@ -3071,6 +3078,10 @@
     else
     {
         ind = i->u.number;
+//#ifdef BAT
+		if(ind < 0)
+			ind = VEC_SIZE(vec) + ind;
+//#endif
         if (ind < 0)
         {
             ERROR("Illegal index for []: not a positive number.\n");
@@ -3212,6 +3223,10 @@
     else
     {
         ind = i->u.number;
+//#ifdef BAT
+		if(ind < 0)
+			ind = mstrsize(svp->u.str) + ind;
+//#endif
         if (ind < 0)
         {
             ERROR("Illegal index for []: not a positive number.\n");
@@ -7715,6 +7730,31 @@
     }
 } /* put_default_argument() */
 
+//#ifdef BAT
+static void
+bat_check_eval_cost_warning ()
+{
+  unsigned long long this_ticks= get_time ();
+
+
+  if (warning_eval_cost_ticks_amt &&
+      this_ticks >= eval_cost_warning_start_ticks+ warning_eval_cost_ticks_amt)
+    {
+      debug_message("\n\n"
+                    "WARNING: Evaluation time %.1f seconds"
+                    "\n",
+                    time_to_msec (this_ticks- eval_cost_warning_total_ticks)/
+                    1000.0);
+      dump_trace(MY_FALSE, 0);
+
+      /* next warning after a second */
+
+      eval_cost_warning_start_ticks= this_ticks- warning_eval_cost_ticks_amt+
+        msec_to_time (1000);
+    }
+}
+//#endif
+
 /*-------------------------------------------------------------------------*/
 Bool
 eval_instruction (bytecode_p first_instruction
@@ -7773,7 +7813,6 @@
        * of eval_instruction().
        */
 
-
     /* Handy macros:
      *
      *   GET_NUM_ARG: Get the number of arguments, resp. check if the
@@ -7969,6 +8008,10 @@
     {
         rt_context_t * context;
 
+//#ifdef BAT
+        bat_check_eval_cost_warning ();
+//#endif
+	
         /* Evaluation too long. Restore some globals and throw
          * an error.
          */
@@ -8004,6 +8047,7 @@
     if (instrs[instruction].min_arg != instrs[instruction].max_arg
      && instruction != F_CALL_OTHER
      && instruction != F_CALL_DIRECT
+     && instruction != F_CALL_SHADOW // BAT
        )
     {
         num_arg = GET_UINT8(pc);
@@ -8737,6 +8781,9 @@
         svalue_t *pResult;  /* Return value on stack */
         svalue_t *efp = fp+csp->num_local_variables; /* Expected end of frame */
 
+//#ifdef BAT
+        bat_check_eval_cost_warning ();
+//#endif
         pResult = sp;
 
         /* Remove any intermediate error contexts */
@@ -9450,6 +9497,18 @@
         inter_sp = sp;
         inter_pc = pc;
         arg = sp - num_arg + 1;
+
+//#ifdef BAT
+		/* stupid zero check */
+		if(arg[0].type == T_NUMBER && arg[0].u.number == 0)
+		{
+			pop_n_elems(num_arg-1);
+			free_svalue(sp);
+			put_number(sp, 0);
+			break;
+		}
+//#endif
+		
         if (arg[0].type != T_STRING)
             BAD_ARG_ERROR(1, T_STRING, arg[0].type);
         if (arg[1].type != T_STRING)
@@ -9609,7 +9668,7 @@
 #endif /* CHECK_OBJECT_REF */
             return MY_FALSE; /* Guarded code terminated with 'return' itself */
         }
-
+		
         /* Restore the important variables */
         pc = inter_pc;
         sp = inter_sp;
@@ -9625,6 +9684,30 @@
 #endif
         break;
     }
+	
+//#ifdef BAT
+    CASE(F_CATCH_WRITE);
+    {
+		begin_catch_write();
+		break;
+    }
+    
+    CASE(F_END_CATCH_WRITE);
+    {
+		char *tmpStr = end_catch_write();
+		sp--;
+		
+		if(tmpStr)
+		{
+			string_t *new = new_mstring(tmpStr);
+			push_string(sp, new);
+		}
+		else
+			push_number(sp, 0);
+		
+		break;
+    }
+//#endif
 
     CASE(F_INC);                    /* --- inc                 --- */
     {
@@ -16334,6 +16417,7 @@
 
     CASE(F_CALL_DIRECT);            /* --- call_direct         --- */
     CASE(F_CALL_OTHER);             /* --- call_other          --- */
+    CASE(F_CALL_SHADOW); /* BAT */
     {
         /* EFUN call_other(), call_direct()
          *
@@ -16438,10 +16522,11 @@
                 }
                 traceing_recursion--;
             }
-
+			
             /* Call the function with the remaining args on the stack.
              */
-            if (!int_apply(arg[1].u.str, ob, num_arg-2, MY_FALSE, b_use_default))
+            if (!int_apply(arg[1].u.str, ob, num_arg-2, MY_FALSE, b_use_default,
+						   instruction == F_CALL_SHADOW ? MY_TRUE : MY_FALSE))  // BAT
             {
                 /* Function not found */
                 if (b_use_default) /* int_apply() removed the args */
@@ -16452,6 +16537,7 @@
                 push_number(sp, 0);
                 break;
             }
+
             sp -= num_arg - 3;
 
             /* The result of the function call is on the stack. But so
@@ -16562,7 +16648,8 @@
                 /* Call the function with the remaining args on the stack.
                  */
                 inter_sp = sp; /* update to new setting */
-                if (!int_apply(arg[1].u.str, ob, num_arg-2, MY_FALSE, b_use_default))
+                if (!int_apply(arg[1].u.str, ob, num_arg-2, MY_FALSE, b_use_default,
+							   instruction == F_CALL_SHADOW ? MY_TRUE : MY_FALSE)) // BAT
                 {
                     /* Function not found, Assign 0 as result.
                      */
@@ -16825,10 +16912,32 @@
 
 } /* eval_instruction() */
 
+//#ifdef BAT
+/* dura */
+char*
+find_function_name (unsigned int fx, program_t *progp)
+{
+	funflag_t flags;
+	
+	flags = progp->functions[fx];
+	
+	while (flags & NAME_INHERITED) {
+		inherit_t *inheritp;
+		
+		inheritp = &progp->inherit[flags & INHERIT_MASK];
+		fx -= inheritp->function_index_offset;
+		progp = inheritp->prog;
+		flags = progp->functions[fx];
+	}
+	
+	return progp->name->txt;
+}
+//#endif
+
 /*-------------------------------------------------------------------------*/
 static Bool
 apply_low ( string_t *fun, object_t *ob, int num_arg
-          , Bool b_ign_prot, Bool allowRefs)
+			, Bool b_ign_prot, Bool allowRefs, Bool b_ign_shadows) // BAT
 
 /* The low-level implementation of function calls.
  *
@@ -16858,7 +16967,7 @@
     program_t *progp;
     struct control_stack *save_csp;
     p_int ix;
-
+	
     /* This object will now be used, and is thus a target for
      * reset later on (when time due).
      */
@@ -16874,7 +16983,7 @@
     /* If there is a chain of objects shadowing, start with the first
      * of these.
      */
-    if (ob->flags & O_SHADOW)
+    if (!b_ign_shadows && (ob->flags & O_SHADOW)) // BAT (ob->flags & O_SHADOW)
     {
         object_t *shadow;
 
@@ -16980,7 +17089,9 @@
             previous_ob = current_object;
             current_object = ob;
             save_csp = csp;
+			
             eval_instruction(FUNCTION_CODE(funstart), inter_sp);
+
 #ifdef DEBUG
             if (save_csp-1 != csp)
                 fatal("Bad csp after execution in apply_low\n");
@@ -17061,7 +17172,6 @@
                 cache[ix].funstart = funstart;
                 cache[ix].flags = progp->functions[fx]
                                   & (TYPE_MOD_STATIC|TYPE_MOD_PROTECTED);
-
                 /* Static functions may not be called from outside,
                  * Protected functions not even from the inside.
                  */
@@ -17076,7 +17186,7 @@
                     previous_ob = csp->prev_ob;
                     current_object = csp->ob;
                     pop_control_stack();
-                    if (ob->flags & O_SHADOW && O_GET_SHADOW(ob)->shadowing)
+                    if (!b_ign_shadows && (ob->flags & O_SHADOW && O_GET_SHADOW(ob)->shadowing)) // BAT
                     {
                         /* This is an object shadowing another. The function
                          * was not found, but can maybe be found in the object
@@ -17093,6 +17203,7 @@
                 previous_ob = current_object;
                 current_object = ob;
                 save_csp = csp;
+
                 eval_instruction(FUNCTION_CODE(funstart), inter_sp);
 #ifdef DEBUG
                 if (save_csp-1 != csp)
@@ -17120,7 +17231,7 @@
      * shadowed object.
      */
 
-    if (ob->flags & O_SHADOW && O_GET_SHADOW(ob)->shadowing)
+    if (!b_ign_shadows && (ob->flags & O_SHADOW && O_GET_SHADOW(ob)->shadowing)) // BAT
     {
         ob = O_GET_SHADOW(ob)->shadowing;
         goto retry_for_shadow;
@@ -17138,7 +17249,7 @@
 /*-------------------------------------------------------------------------*/
 static int
 int_apply (string_t *fun, object_t *ob, int num_arg
-          , Bool b_ign_prot, Bool b_use_default
+		   , Bool b_ign_prot, Bool b_use_default, Bool b_ign_shadows // BAT
           )
 
 /* The wrapper around apply_low() to handle default methods.
@@ -17171,7 +17282,7 @@
  */
 
 {
-    if (apply_low(fun, ob, num_arg, b_ign_prot, MY_FALSE))
+    if (apply_low(fun, ob, num_arg, b_ign_prot, MY_FALSE, b_ign_shadows))  // BAT
         return APPLY_FOUND;
 
     if (b_use_default)
@@ -17213,7 +17324,7 @@
             /* Call the function */
             if (hook->type == T_STRING)
             {
-                rc = apply_low(hook->u.str, ob, num_arg+num_extra, b_ign_prot, MY_TRUE);
+                rc = apply_low(hook->u.str, ob, num_arg+num_extra, b_ign_prot, MY_TRUE, b_ign_shadows); // BAT
             }
             else /* hook->type == T_CLOSURE */
             {
@@ -17332,7 +17443,7 @@
 #endif
 
     /* Do the call */
-    if (!int_apply(fun, ob, num_arg, b_find_static, b_use_default))
+    if (!int_apply(fun, ob, num_arg, b_find_static, b_use_default, MY_FALSE)) // BAT
     {
         if (!b_use_default) /* int_apply() did not clean up the stack */
             inter_sp = _pop_n_elems(num_arg, inter_sp);
@@ -18476,7 +18587,7 @@
     function_name = simul_efunp[code].name;
 
     /* First, try calling the function in the given object */
-    if (!int_apply(function_name, ob, num_arg, MY_FALSE, MY_FALSE))
+    if (!int_apply(function_name, ob, num_arg, MY_FALSE, MY_FALSE, MY_FALSE)) // BAT
     {
         /* Function not found: try the alternative sefun objects */
         if (simul_efun_vector)
@@ -18494,7 +18605,7 @@
                 }
                 if ( !(ob = get_object(v->u.str)) )
                     continue;
-                if (int_apply(function_name, ob, num_arg, MY_FALSE, MY_FALSE))
+                if (int_apply(function_name, ob, num_arg, MY_FALSE, MY_FALSE, MY_FALSE)) // BAT
                     return;
             }
             return;
@@ -20725,7 +20836,7 @@
      */
     if (ob == master_ob)
         b_use_default = MY_FALSE;
-    rc = int_apply(arg[2].u.str, ob, num_arg-3, MY_FALSE, b_use_default);
+    rc = int_apply(arg[2].u.str, ob, num_arg-3, MY_FALSE, b_use_default, MY_FALSE); // BAT
     if (rc == APPLY_NOT_FOUND)
     {
         /* Function not found */
diff -ruN /home/favorit/ldmud-3.3.719/src/interpret.h ./interpret.h
--- /home/favorit/ldmud-3.3.719/src/interpret.h	2009-06-15 01:18:52.000000000 +0300
+++ ./interpret.h	2009-09-03 12:30:44.000000000 +0300
@@ -15,6 +15,8 @@
 #include "bytecode.h"
 #include "svalue.h"
 
+#include "bat.h"
+
 /* --- Types --- */
 
 /* --- struct control_stack: one control stack element
@@ -79,27 +81,48 @@
        * TODO:: to avoid accesses to wrong functions/variables.
        */
 #ifdef EVAL_COST_TRACE
-    int32 eval_cost;
-      /* The eval cost at that moment. */
+	int32 eval_cost;
+	/* The eval cost at that moment. */
 #endif
-};
-
-/* a general error handler structure. head is assigned as payload to an 
- * T_LVALUE svalue of type T_ERROR_HANDLER and pushed onto the value stack.
- * If the stack is unrolled during runtime errors the error_handler function
- * is called and frees buff. */
-typedef struct errorhandler_s {
-  svalue_t head;        /* The T_ERROR_HANDLER structure */
-  char     * buff;      /* The allocated buffer to free. */
-} errorhandler_t;
 
+//#ifdef BAT
+	unsigned long long call_time;
+	p_uint profil_line_offset;
+//#endif
 
-/* --- Constants --- */
-
+};
+/* a general error handler structure. head is assigned as payload to an                                                                                             
+ * T_LVALUE svalue of type T_ERROR_HANDLER and pushed onto the value stack.                                                                                         
+ * If the stack is unrolled during runtime errors the error_handler function                                                                                        
+ * is called and frees buff. */                                                                                                                                     
+typedef struct errorhandler_s {                                                                                                                                     
+  svalue_t head;        /* The T_ERROR_HANDLER structure */                                                                                                         
+  char     * buff;      /* The allocated buffer to free. */                                                                                                         
+} errorhandler_t;                                                                                                                                                   
+                                                                                                                                                                    
+                                                                                                                                                                    
+/* --- Constants --- */                                                                                                                                             
+                                                                                                                                                                      
 static const short MAX_SHIFT = (sizeof(p_int) << 3) - 1;
   /* The maximally useful shift (left or right) of a number in LPC.
    */
 
+/* Reset the evaluation cost/time counter.
+ */
+
+//#ifdef BAT
+#define CLEAR_EVAL_COST ((assigned_eval_cost = eval_cost = 0),(eval_cost_warning_start_ticks= eval_cost_warning_total_ticks= get_time ()))
+extern unsigned long long eval_cost_warning_start_ticks;
+extern unsigned long long eval_cost_warning_total_ticks;
+//#endif
+// #define CLEAR_EVAL_COST (assigned_eval_cost = eval_cost = 0)
+
+
+/* Check if the current evaluation took too long
+ */
+#define EVALUATION_TOO_LONG() \
+    (max_eval_cost && (eval_cost >= max_eval_cost || eval_cost < 0))
+
 /* --- Variables --- */
 
 extern program_t *current_prog;
diff -ruN /home/favorit/ldmud-3.3.719/src/lex.c ./lex.c
--- /home/favorit/ldmud-3.3.719/src/lex.c	2009-06-15 01:18:52.000000000 +0300
+++ ./lex.c	2009-09-03 12:30:44.000000000 +0300
@@ -475,6 +475,7 @@
  = { { "break",          L_BREAK         }
    , { "case",           L_CASE          }
    , { "catch",          L_CATCH         }
+   , { "catch_write",    L_CATCH_WRITE   } // BAT
    , { "closure",        L_CLOSURE_DECL  }
    , { "continue",       L_CONTINUE      }
    , { "default",        L_DEFAULT       }
@@ -1429,11 +1430,17 @@
         code = F_PARSE_COMMAND;
         break;
 #endif
+//#ifdef BAT
+    case L_CATCH_WRITE:
+		code = F_CATCH_WRITE + CLOSURE_EFUN_OFFS;
+		break;
+//#endif
+
     case L_CATCH:
         code = F_CATCH;
         break;
     }
-
+	
     return code;
 } /* symbol_resword() */
 
@@ -5780,7 +5787,7 @@
     pragma_no_inherit = MY_FALSE;
     pragma_no_shadow = MY_FALSE;
     pragma_pedantic = MY_FALSE;
-    pragma_warn_missing_return = MY_TRUE;
+    pragma_warn_missing_return = MY_FALSE; // BAT MY_TRUE;
     pragma_warn_deprecated = MY_FALSE;
     pragma_range_check = MY_FALSE;
     pragma_warn_empty_casts = MY_TRUE;
diff -ruN /home/favorit/ldmud-3.3.719/src/main.c ./main.c
--- /home/favorit/ldmud-3.3.719/src/main.c	2009-06-15 01:18:52.000000000 +0300
+++ ./main.c	2009-09-03 12:30:45.000000000 +0300
@@ -77,6 +77,13 @@
 #include "pkg-mysql.h"
 #endif
 
+//#ifdef BAT
+#include <locale.h>
+#include "bat.h"
+#include "actions.h" /* Blitzer */
+#include "sockets.h"
+//#endif
+
 #ifdef USE_XML
 #    if defined(HAS_XML2) && defined(HAS_IKSEMEL)
 #        error Both, libxml2 and iksemel enabled.
@@ -95,6 +102,8 @@
 
 #include "i-eval_cost.h"
 
+#include "i-eval_cost.h"
+
 #include "../mudlib/sys/regexp.h"
 
 /*-------------------------------------------------------------------------*/
@@ -269,6 +278,12 @@
     sigset_t set;
     volatile int rc;
 
+//#ifdef BAT
+    unsetenv("LANG");
+    setlocale(LC_ALL, "");
+    socket_init();
+//#endif
+
     rc = 0;
 
     /* On some systems, SIGALRM is sometimes blocked.
@@ -766,6 +781,20 @@
             set_cloexec_flag(fileno(fp));
     }
     (void)vfprintf(fp, fmt, va);
+//#ifdef BAT /* Blitzer */
+    if (command_giver != NULL)
+      {
+        (void) fprintf (fp, "Command giver: '%s'\n",
+                        get_txt (command_giver->name));
+
+        if (command_giver->super != NULL)
+          (void) fprintf (fp, "Environment: '%s'\n",
+                          get_txt (command_giver->super->name));
+
+        if (last_command != NULL)
+          (void) fprintf (fp, "Last command: '%s'\n", last_command);
+      }
+//#endif
     (void)fflush(fp);
 } /* vdebug_message() */
 
@@ -1774,6 +1803,10 @@
         "\nRelease:  " PROJ_VERSION
        , stdout);
 
+//#ifdef BAT
+  fputs(" (BatMud edition)", stdout);
+//#endif
+
   fputs(drivertag(), stdout);
 
   fputs("; " RELEASE_DATE
diff -ruN /home/favorit/ldmud-3.3.719/src/Makefile.in ./Makefile.in
--- /home/favorit/ldmud-3.3.719/src/Makefile.in	2009-06-15 01:18:52.000000000 +0300
+++ ./Makefile.in	2009-10-02 23:45:53.000000000 +0300
@@ -100,13 +100,14 @@
       interpret.c \
       lex.c main.c mapping.c md5.c mempools.c mregex.c mstrings.c object.c \
       otable.c\
-      parser.c parse.c pkg-alists.c pkg-iksemel.c pkg-xml2.c pkg-idna.c \
+      parser.c parse.c pkg-alists.c pgk-iksemel.c pkg-xml2.c pkg-idna.c \
       pkg-mccp.c pkg-mysql.c pkg-pcre.c pkg-gcrypt.c \
       pkg-pgsql.c pkg-sqlite.c pkg-tls.c pkg-openssl.c pkg-gnutls.c \
       ptmalloc.c port.c ptrtable.c \
       random.c regexp.c sha1.c simulate.c simul_efun.c stdstrings.c \
+      bat.c sockets.c \
       strfuns.c structs.c sprintf.c swap.c wiz_list.c xalloc.c 
-OBJ = access_check.o actions.o array.o arraylist.o backend.o bitstrings.o \
+OBJ = access_check.o actions.o array.o arraylist.o  backend.o bitstrings.o \
       call_out.o closure.o comm.o \
       dumpstat.o ed.o efuns.o files.o gcollect.o hash.o heartbeat.o \
       interpret.o \
@@ -117,6 +118,7 @@
       pkg-pgsql.o pkg-sqlite.o pkg-tls.o pkg-openssl.o pkg-gnutls.o \
       ptmalloc.o port.o ptrtable.o \
       random.o regexp.o sha1.o simulate.o simul_efun.o stdstrings.o \
+      bat.o sockets.o \
       strfuns.o structs.o sprintf.o swap.o wiz_list.o xalloc.o @ALLOCA@ 
 
 all: make-patchlevel ldmud@EXEEXT@
@@ -248,6 +250,15 @@
 #--------------------------------------------------------
 # Dependencies, manual and automatic.
 
+bat.o : svalue.h exec.h bat.h main.h object.h backend.h simulate.h \
+    interpret.h xalloc.h svalue.h array.h swap.h typedefs.h comm.h mstrings.h \
+    mapping.h stdstrings.h random.h dumpstat.h closure.h ptrtable.h structs.h
+
+#profil2.o : crc32.c profil2.h bat.h
+
+sockets.o : main.h svalue.h interpret.h simulate.h object.h mstrings.h comm.h \
+    actions.h gcollect.h
+
 # --- DO NOT MODIFY THIS LINE -- AUTO-DEPENDS FOLLOW ---
 access_check.o : xalloc.h filestat.h comm.h access_check.h driver.h \
     svalue.h strfuns.h pkg-tls.h simulate.h typedefs.h config.h port.h \
diff -ruN /home/favorit/ldmud-3.3.719/src/make_func.y ./make_func.y
--- /home/favorit/ldmud-3.3.719/src/make_func.y	2009-06-15 01:18:52.000000000 +0300
+++ ./make_func.y	2009-09-03 13:14:09.000000000 +0300
@@ -266,7 +266,7 @@
   /* Maximum number of functions and tokens we care to handle.
    */
 
-#define MAX_ARGTYPES  500
+#define MAX_ARGTYPES  600
   /* Size of the arg_types[] array.
    */
 
@@ -1653,7 +1653,11 @@
     if ( !strcmp(name, "REGEXP_PACKAGE") )
         return H_REGEXP_PACKAGE;
     if ( !strcmp(name, "MSG_DISCARDED") )
-        return H_MSG_DISCARDED;
+    	return H_MSG_DISCARDED;
+//#ifdef BAT
+    if ( !strcmp(name, "POST_COMMAND") )
+        return H_POST_COMMAND;
+//#endif
     return -1;
 }
 
diff -ruN /home/favorit/ldmud-3.3.719/src/object.c ./object.c
--- /home/favorit/ldmud-3.3.719/src/object.c	2009-06-15 01:18:52.000000000 +0300
+++ ./object.c	2009-09-03 13:15:51.000000000 +0300
@@ -200,6 +200,7 @@
 #include "svalue.h"
 #include "wiz_list.h"
 #include "xalloc.h"
+#include "bat.h"
 
 #include "../mudlib/sys/driver_hook.h"
 #include "../mudlib/sys/functionlist.h"
@@ -1279,7 +1280,7 @@
 
 /*-------------------------------------------------------------------------*/
 void
-tell_object (object_t *ob, string_t *str)
+tell_object (object_t *ob, string_t *str, int no_catch) // BAT
 
 /* Send message <str> to object <ob>. If <ob> is an interactive player,
  * it will go to his screen (unless a shadow catches it - see shadow_catch_
@@ -1298,7 +1299,15 @@
     {
         save_command_giver = command_giver;
         command_giver = ob;
-        add_message(FMT_STRING, str);
+//#ifdef BAT
+        save_catching_write = catching_write;
+        if (no_catch)
+          catching_write = 0;
+//#endif
+    	add_message(FMT_STRING, str);    
+//#ifdef BAT
+        catching_write = save_catching_write;
+//#endif
         command_giver = save_command_giver;
         return;
     }
@@ -3652,6 +3661,7 @@
 
 {
     object_t * ob = NULL;
+	int skip_catch_tell = (sp--)->u.number;
     svalue_t *arg = sp - 1;
 
     /* Get the arguments */
@@ -3666,7 +3676,7 @@
 
     if (arg[1].type == T_STRING)
     {
-        tell_object(ob, sp->u.str);
+        tell_object(ob, sp->u.str, skip_catch_tell); // BAT
         free_svalue(sp);
     }
     else
@@ -3678,7 +3688,7 @@
     sp--;
     free_svalue(sp);
     sp--;
-
+	
     return sp;
 } /* f_tell_object() */
 
@@ -4807,7 +4817,7 @@
         stmp.u.ob = ob;
         if (lookup_key(&stmp, avoid) >= 0)
             continue;
-        tell_object (ob, message);
+        tell_object (ob, message, 0);
     }
 
     pop_stack(); /* free avoid alist */
@@ -5030,7 +5040,7 @@
         if (ob->flags & O_DESTRUCTED) continue;
         stmp.u.ob = ob;
         if (lookup_key(&stmp, avoid) >= 0) continue;
-        tell_object(ob, message);
+        tell_object(ob, message, 0);
     }
 } /* e_tell_room() */
 
@@ -6739,9 +6749,9 @@
 
         /* Open the file */
 
-        /* Always write savefiles in 'binary mode'. (O_BINARY is 0 on all platforms
-         * except of Cygwin and therefore ignored. Cygwin may need it, if the
-         * volume with the mudlib is mounted in textmode. */
+	/* Always write savefiles in 'binary mode'. (O_BINARY is 0 on all platforms
+	 * except of Cygwin and therefore ignored. Cygwin may need it, if the
+	 * volume with the mudlib is mounted in textmode. */
         f = ixopen3(tmp_name, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0640);
 
         if (f < 0) {
diff -ruN /home/favorit/ldmud-3.3.719/src/object.h ./object.h
--- /home/favorit/ldmud-3.3.719/src/object.h	2009-06-15 01:18:52.000000000 +0300
+++ ./object.h	2009-09-03 12:20:25.000000000 +0300
@@ -264,7 +264,7 @@
 /* --- Prototypes --- */
 
 extern int32 renumber_programs(void);
-extern void tell_object(object_t *, string_t *);
+extern void tell_object(object_t *, string_t *, int); // BAT
 extern void tell_object_str(object_t *, const char *);
 extern void tell_npc(object_t *, string_t *);
 extern void tell_npc_str(object_t *, const char *);
diff -ruN /home/favorit/ldmud-3.3.719/src/patchlevel.h ./patchlevel.h
--- /home/favorit/ldmud-3.3.719/src/patchlevel.h	1970-01-01 02:00:00.000000000 +0200
+++ ./patchlevel.h	2009-09-03 12:59:14.000000000 +0300
@@ -0,0 +1,30 @@
+#ifndef PATCHLEVEL_H__
+#define PATCHLEVEL_H__ 1
+
+/*--------------------------------------------------------------------------
+ * Various version numbers and strings, collected here so that we have
+ * to modify only one file.
+ *--------------------------------------------------------------------------
+ */
+
+#define RELEASE_TYPE "stable"
+#define RELEASE_LONGTYPE "stable"
+
+#define RELEASE_DATE "2009-05-30"
+
+#define PROJ_VERSION "Build 2618"
+
+#define DRIVER_VERSION "3.3.719"
+
+#define VERSION_MAJOR "3"
+
+#define VERSION_MINOR "3"
+
+#define VERSION_MICRO "719"
+
+#define LOCAL_LEVEL ""
+
+/* TODO: Add something like the perl local patchlevel management. */
+/* TODO: Add LPC defines for the various version number parts */
+
+#endif /* PATCHLEVEL_H__ */
diff -ruN /home/favorit/ldmud-3.3.719/src/pkg-xml2.c ./pkg-xml2.c
--- /home/favorit/ldmud-3.3.719/src/pkg-xml2.c	2009-06-15 01:18:52.000000000 +0300
+++ ./pkg-xml2.c	2009-09-12 22:04:26.000000000 +0300
@@ -63,7 +63,7 @@
  * Realize malloc with the driver-internal xalloc rather than a direct malloc()
  */
 {
-    return xalloc(size);
+    return pxalloc(size);
 }
 
 static void
@@ -73,7 +73,7 @@
  * Realize free with the driver-internal xfree rather than a direct free()
  */
 {
-    xfree(ptr);
+    pfree(ptr);
 }
 
 static void *
@@ -84,7 +84,7 @@
  * and line rather the direct realloc()
  */
 {
-    return rexalloc(ptr, size);
+    return prexalloc(ptr, size);
 }
 
 static char *
@@ -95,7 +95,16 @@
  * strdup()
  */
 {
-    return string_copy(str);
+    char *p;
+    size_t len;
+
+    len = strlen(str)+1;
+    memsafe(p = pxalloc(len), len, "xml_pkg_strdup");
+    if (p)
+    {
+        memcpy(p, str, len);
+    }
+    return p;
 }
 
 static void
@@ -390,10 +399,12 @@
 void
 pkg_xml2_init ()
 {
-    /* Check for correct libxml version. */
+    // First override the default memory access functions
+    xmlMemSetup(xml_pkg_free, xml_pkg_malloc, xml_pkg_realloc, xml_pkg_strdup);
+
+    // Check for correct libxml version.
     LIBXML_TEST_VERSION
 
-    xmlMemSetup(xml_pkg_free, xml_pkg_malloc, xml_pkg_realloc, xml_pkg_strdup);
 }
 
 /*=========================================================================*/
diff -ruN /home/favorit/ldmud-3.3.719/src/profil2.c ./profil2.c
--- /home/favorit/ldmud-3.3.719/src/profil2.c	1970-01-01 02:00:00.000000000 +0200
+++ ./profil2.c	2009-09-03 11:49:53.000000000 +0300
@@ -0,0 +1,696 @@
+/*
+ * Copyright (c) 2001 matti.suomalainen@iki.fi
+ * Free for non-commercial use.
+ *
+ * All rights reserved.
+ */
+
+
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "crc32.c"
+#include "profil2.h"
+#include "bat.h"
+
+
+/*
+ * pool alloc
+ */
+
+#define POOL_SIZE (1024*1024)
+
+struct pool
+{
+  struct pool *prev;
+
+  unsigned char pool [POOL_SIZE];
+  unsigned int space_left;
+};
+
+static struct pool *pool= NULL;
+
+static void
+_add_pool ()
+{
+  struct pool *p;
+
+  p= (struct pool*) calloc (1, sizeof (*p));
+  p->prev= pool;
+  pool= p;
+
+  p->space_left= POOL_SIZE;
+}
+
+static char*
+_pool_strdup (const char *txt)
+{
+#if 0
+  return txt;
+#else
+  unsigned int len= strlen (txt)+1;
+  char *p;
+
+  if (pool== NULL || pool->space_left <len)
+    _add_pool ();
+
+  p= &pool->pool [POOL_SIZE- pool->space_left];
+  pool->space_left -= len;
+  
+  strcpy (p, txt);
+  return p;
+#endif
+}
+
+static void
+_pool_free ()
+{
+  struct pool *p, *prev;
+
+  p= pool;
+
+  while (p)
+    {
+      prev= p->prev;
+      free (p);
+      p= prev;
+    }
+  pool= NULL;
+}
+  
+
+
+/*
+ * gathering data
+ */
+
+static unsigned int active_profiling;
+static profil_sample_t started;
+static profil_sample_t total_overhead;
+
+void
+profil_sample_add (profil_sample_t *to, const profil_sample_t *by)
+{
+  unsigned int idx;
+  
+  for (idx= 0; idx < PROFIL_MAX_COUNTER; idx++)
+    to->c [idx] += by->c [idx];
+}
+
+void
+profil_sample_sub (profil_sample_t *to, const profil_sample_t *by)
+{
+  unsigned int idx;
+
+  for (idx= 0; idx < PROFIL_MAX_COUNTER; idx++)
+    to->c [idx] -= by->c [idx];
+}
+
+void
+profil_sample_mul (profil_sample_t *to, int by)
+{
+  unsigned int idx;
+
+  for (idx= 0; idx < PROFIL_MAX_COUNTER; idx++)
+    to->c [idx] *= by;
+}
+
+void
+profil_sample_copy (profil_sample_t *to, profil_sample_t *from)
+{
+  memcpy (to, from, sizeof (profil_sample_t));
+}
+
+unsigned int
+profil_sample_gt (profil_sample_t *a, profil_sample_t *b)
+{
+  /* if any value in a is > b */
+  
+  unsigned int idx;
+
+  for (idx= 0; idx < PROFIL_MAX_COUNTER; idx++)
+    if (a->c [idx] > b->c [idx])
+      return 1;
+
+  return 0;
+}
+
+static unsigned long long
+_profil_timeval_to_longlong (struct timeval tv)
+{
+  return 
+    (unsigned long long) tv.tv_sec*1000+ 
+    (unsigned long long) tv.tv_usec/1000;
+}
+
+void
+_profil_get_sample (profil_sample_t *sample)
+{
+  memset (sample, 0, sizeof (profil_sample_t));
+
+  if (active_profiling & PROFILE_TIME)
+	  sample->c [PROFIL_SAMPLE_TIME] = get_time ();
+
+  if (active_profiling & PROFILE_RUSAGE)
+    {
+      struct rusage ru;
+
+      getrusage (RUSAGE_SELF, &ru);
+      
+      sample->c [PROFIL_SAMPLE_UTIME]=_profil_timeval_to_longlong(ru.ru_utime);
+      sample->c [PROFIL_SAMPLE_STIME]=_profil_timeval_to_longlong(ru.ru_stime);
+      sample->c [PROFIL_SAMPLE_RSS]= ru.ru_maxrss;
+      sample->c [PROFIL_SAMPLE_IXRSS]= ru.ru_ixrss;
+      sample->c [PROFIL_SAMPLE_IDRSS]= ru.ru_idrss;
+      sample->c [PROFIL_SAMPLE_ISRSS]= ru.ru_isrss;
+      sample->c [PROFIL_SAMPLE_MINFLT]= ru.ru_minflt;
+      sample->c [PROFIL_SAMPLE_MAJFLT]= ru.ru_majflt;
+      sample->c [PROFIL_SAMPLE_NSWAP]= ru.ru_nswap;
+      sample->c [PROFIL_SAMPLE_INBLOCK]= ru.ru_inblock;
+      sample->c [PROFIL_SAMPLE_OUBLOCK]= ru.ru_oublock;
+      sample->c [PROFIL_SAMPLE_MSGSND]= ru.ru_msgsnd;
+      sample->c [PROFIL_SAMPLE_MSGRCV]= ru.ru_msgrcv;
+      sample->c [PROFIL_SAMPLE_NSIGNALS]= ru.ru_nsignals;
+      sample->c [PROFIL_SAMPLE_NVCSW]= ru.ru_nvcsw;
+      sample->c [PROFIL_SAMPLE_NIVCSW]= ru.ru_nivcsw;
+    }
+}
+
+void
+profil_start_sample (profil_sample_t *sample)
+{
+  _profil_get_sample (sample);
+}
+
+void
+profil_end_sample (profil_sample_t *sample)
+{
+  if (active_profiling)
+    {
+      profil_sample_t tmp;
+      profil_sample_copy (&tmp, sample);
+      _profil_get_sample (sample);
+      profil_sample_sub (sample, &tmp);
+    }
+}
+
+/*
+ * updating and storing samples
+ */
+
+
+#define CACHE_SLOTS 1000000
+
+struct profil_entry
+{
+  profil_sample_t samples[2]; /* self, recur */
+
+  unsigned int owns_fun_name;
+  unsigned int fun_hash;
+  char *fun_name;
+
+  unsigned int owns_class_name;
+  unsigned int class_hash;
+  char *class_name;
+};
+
+struct hash
+{
+  struct profil_entry *data;
+  unsigned int len;
+  unsigned int len_in_use;
+};
+
+static struct hash sample_lookup;
+static struct hash class_lookup;
+static struct hash fun_lookup;
+
+
+void
+_hash_init (struct hash *h)
+{
+  memset (h, 0, sizeof (*h));
+}
+
+struct profil_entry*
+_hash_find (struct hash *h, const char *class_name, const char *fun_name)
+{
+  unsigned int class_hash= 
+    class_name? ssh_crc32 (class_name, strlen (class_name)): 0;
+
+  unsigned int fun_hash= 
+    fun_name? ssh_crc32 (fun_name, strlen (fun_name)): 0;
+
+  unsigned int idx;
+
+  if (h->len== 0 || h->len_in_use== 0)
+    return NULL;
+
+  idx= class_hash;
+
+  if (fun_name)
+    idx ^= fun_hash;
+
+  idx %= h->len;
+
+
+  while (h->data [idx].class_name != 0)
+    {
+      if (h->data [idx].class_hash== class_hash &&
+	  !strcmp (h->data [idx].class_name, class_name))
+	{
+	  if (!fun_name ||
+	      (h->data [idx].fun_hash== fun_hash &&
+	       !strcmp (h->data [idx].fun_name, fun_name)))
+	    {
+	      return &h->data [idx];
+	    }
+	}
+
+      idx++;
+      idx %= h->len;
+
+   }
+  
+  return NULL;
+}
+
+
+struct profil_entry*
+_hash_next (struct hash *h, struct profil_entry *from)
+{
+  if (h->len== 0)
+    return NULL;
+
+  if (from== NULL)
+    from= h->data;
+
+  from++;
+
+  if (from== &h->data [h->len])
+    return NULL;
+
+  if (from->class_name)
+    return from;
+
+  return _hash_next (h, from);
+}
+
+
+void
+_hash_insert (struct hash *h, struct profil_entry *entry)
+{
+  if (h->len_in_use >= h->len*2/3)
+    {
+      /* regrow */
+
+      struct hash h2;
+      struct profil_entry *iter;
+
+      //      fprintf (stderr, "REGROW %p, len=%d, use= %d\n",  h, h->len, h->len_in_use);
+
+      _hash_init (&h2);
+      h2.len= (h->len* 2)+1024;
+      h2.len_in_use= 0;
+      h2.data= (struct profil_entry*) calloc (1, 
+					      sizeof (struct profil_entry)*
+					      h2.len);
+
+      iter= NULL;
+
+      while ( (iter= _hash_next (h, iter)) )
+	_hash_insert (&h2, iter);
+      
+      free (h->data);
+      *h= h2;
+    }
+
+  {
+    unsigned int idx;
+
+    entry->class_hash= 
+      entry->class_name? ssh_crc32 (entry->class_name, strlen (entry->class_name)): 0;
+
+    entry->fun_hash= entry->fun_name? ssh_crc32 (entry->fun_name, strlen (entry->fun_name)): 0;
+
+
+    idx= entry->class_hash;
+    
+    if (entry->fun_name)
+      idx ^= entry->fun_hash;
+
+    idx %= h->len;
+
+    while (h->data [idx].class_name != 0)
+      {
+	if (h->data [idx].class_hash== entry->class_hash &&
+	    !strcmp (h->data [idx].class_name, entry->class_name))
+	  {
+	    if (!entry->fun_name ||
+	      (h->data [idx].fun_hash== entry->fun_hash &&
+	       !strcmp (h->data [idx].fun_name, entry->fun_name)))
+	      {
+		h->data [idx]= *entry;
+		return;
+	      }
+	  }
+      
+	idx++;
+	idx %= h->len;
+	
+      }
+
+    h->len_in_use++;
+    h->data [idx]= *entry;
+  }
+}  
+
+void		
+profil_enable (unsigned int how)
+{
+  active_profiling= how;
+  profil_reset ();
+}
+
+unsigned int	
+profil_is_enabled ()
+{
+  return active_profiling;
+}
+
+struct profil_entry*
+_profil_find_entry (const char *class_name, const char *fun_name)
+{
+  struct profil_entry *e;
+  struct profil_entry tmp;
+
+  if ( (e= _hash_find (&sample_lookup, class_name, fun_name)))
+    return e;
+
+  memset (&tmp, 0, sizeof (tmp));
+
+  if ( (e= _hash_find (&class_lookup, class_name, NULL)) )
+    {
+      tmp.class_name= e->class_name;
+      tmp.owns_class_name= 0;
+    }
+  else
+    {
+      tmp.class_name= _pool_strdup (class_name);
+      tmp.owns_class_name= 1;
+
+      _hash_insert (&class_lookup, &tmp);
+    }
+
+
+  if ( (e= _hash_find (&fun_lookup, fun_name, NULL)) )
+    {
+      tmp.fun_name= e->class_name;
+      tmp.owns_fun_name= 0;
+    }
+  else
+    {
+      tmp.class_name= _pool_strdup (fun_name);
+      _hash_insert (&fun_lookup, &tmp);
+
+      tmp.fun_name= tmp.class_name;
+      tmp.class_name= NULL;
+      tmp.owns_fun_name= 1;
+    }
+
+  _hash_insert (&sample_lookup, &tmp);
+
+  return _profil_find_entry (class_name, fun_name);
+}
+
+void
+profil_register_sample (const char *class_name, 
+			const char *fun_name,
+			profil_sample_t *self,
+			 profil_sample_t *recur,
+			int sample_mul)
+{
+  if (profil_is_enabled ())
+    {
+      profil_sample_t this_overhead;
+      struct profil_entry *e;
+
+      profil_start_sample (&this_overhead);
+
+      e= _profil_find_entry (class_name, fun_name);
+
+      if (self)
+	{
+	  self->c [PROFIL_SAMPLE_CALLS]++;
+  
+	  profil_sample_mul (self, sample_mul);
+	  profil_sample_add (&e->samples [PROFIL_SELF], self);
+	  
+	}
+
+      if (recur)
+	{
+	  recur->c [PROFIL_SAMPLE_CALLS]++;
+
+	  profil_sample_mul (recur, sample_mul);
+	  profil_sample_add (&e->samples [PROFIL_WCHILDREN], recur);
+	}
+
+
+
+
+      profil_end_sample (&this_overhead);
+      profil_sample_add (&total_overhead, &this_overhead);
+    }
+}
+
+/*
+ * output & reset
+ */
+
+static unsigned int profil_sorter_arg= 0;
+static unsigned int profil_sorter_self_time= 0;
+
+static int
+_profil_sorter (const void *_a, const void *_b)
+{
+  struct profil_entry *a= (struct profil_entry*) _a;
+  struct profil_entry *b= (struct profil_entry*) _b;
+
+  if (a->samples [profil_sorter_self_time].c [profil_sorter_arg]== 
+      b->samples [profil_sorter_self_time].c [profil_sorter_arg])
+    return 0;
+  
+  if (a->samples [profil_sorter_self_time].c [profil_sorter_arg] > 
+      b->samples [profil_sorter_self_time].c [profil_sorter_arg])
+    return -1;
+  else 
+    return 1;
+}
+
+static unsigned int
+_profil_output_entry (char *store_to, unsigned int max_len, 
+		      unsigned long long total_time,
+		      const char *class_name, const char *fun_name,
+		      profil_sample_t *sample)
+{
+  char buf [10*1024];
+
+  snprintf (buf, sizeof (buf), 
+	    "%s::%s %.1f %.2f %.2f %.2f %.2f "
+#if 1
+	    "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f"
+#endif
+	    "\n", 
+	    class_name, fun_name,
+
+	   sample->c [PROFIL_SAMPLE_TIME]?
+	   (double)sample->c [PROFIL_SAMPLE_TIME]*100/total_time: 0,
+
+	   time_to_msec (sample->c [PROFIL_SAMPLE_TIME])/1000.0
+	    ,
+	   sample->c [PROFIL_SAMPLE_UTIME]/1000.0,
+	   sample->c [PROFIL_SAMPLE_STIME]/1000.0,
+	   sample->c [PROFIL_SAMPLE_RSS]/1000.0
+#if 1
+	    ,
+	   sample->c [PROFIL_SAMPLE_IXRSS]/1000.0,
+	   sample->c [PROFIL_SAMPLE_IDRSS]/1000.0,
+	   sample->c [PROFIL_SAMPLE_ISRSS]/1000.0,
+	   (double) sample->c [PROFIL_SAMPLE_MINFLT],
+	   (double) sample->c [PROFIL_SAMPLE_MAJFLT],
+	   (double) sample->c [PROFIL_SAMPLE_NSWAP],
+	   (double) sample->c [PROFIL_SAMPLE_INBLOCK],
+	   (double) sample->c [PROFIL_SAMPLE_OUBLOCK],
+	   (double) sample->c [PROFIL_SAMPLE_MSGSND],
+	   (double) sample->c [PROFIL_SAMPLE_MSGRCV],
+	   (double) sample->c [PROFIL_SAMPLE_NSIGNALS],
+	   (double) sample->c [PROFIL_SAMPLE_NVCSW],
+	   (double) sample->c [PROFIL_SAMPLE_NIVCSW],
+	    (double) sample->c [PROFIL_SAMPLE_ECOST],
+	   (double) sample->c [PROFIL_SAMPLE_CALLS]
+#endif
+	    );
+  
+
+
+  if (strlen (buf) < max_len)
+    strcpy (store_to, buf);
+  return strlen (buf);
+}
+
+
+unsigned int
+profil_query_results (char *store_to, unsigned int max_len,
+		      unsigned int self_time,
+		      unsigned int sort_order, 
+		      unsigned int max_entries)
+{
+  struct profil_entry *entries;
+  struct profil_entry *iter;
+  unsigned int idx;
+  unsigned long long low_water= 0;
+  unsigned int total_len= 0;
+  unsigned int len= 0;
+
+  profil_sample_t total_time;
+
+  if (self_time != PROFIL_SELF && self_time != PROFIL_WCHILDREN)
+    self_time= PROFIL_SELF;
+
+  entries= (struct profil_entry*) alloca (max_entries* 
+					  sizeof (struct profil_entry));
+  memset (entries, 0, max_entries* sizeof (struct profil_entry));
+
+  if (sort_order >= PROFIL_MAX_COUNTER)
+    return 0+1;
+
+  iter= NULL;
+
+  while ( (iter= _hash_next (&sample_lookup, iter)) )
+    if (iter->samples [self_time].c [sort_order] >= low_water)
+      {
+	entries [max_entries-1]= *iter;
+
+	profil_sorter_arg= sort_order;
+	profil_sorter_self_time= self_time;
+
+	qsort (entries, max_entries, sizeof (struct profil_entry), 
+	       _profil_sorter);
+	low_water= entries [max_entries-1].samples [self_time].c [sort_order];
+      }
+
+
+
+  profil_start_sample (&total_time);
+  profil_sample_sub (&total_time, &started);
+
+  len= _profil_output_entry (store_to, max_len, 
+			     total_time.c [PROFIL_SAMPLE_TIME],
+			     "total", "", &total_time);
+  
+    if (len <= max_len)
+      {
+	store_to+= len;
+	max_len -= len;
+      }
+    total_len += len;
+
+    len= _profil_output_entry (store_to, max_len,
+			     total_time.c [PROFIL_SAMPLE_TIME],
+
+			       "overhead", "", &total_overhead);
+    
+    if (len <= max_len)
+      {
+	store_to+= len;
+	max_len -= len;
+      }
+
+    total_len += len;
+
+
+    for (idx= 0; idx < max_entries; idx++)
+      if (entries [idx].class_name)
+	{
+	  len= _profil_output_entry (store_to, max_len,
+				     total_time.c [PROFIL_SAMPLE_TIME],
+				     entries [idx].class_name,
+				     entries [idx].fun_name,
+				     &entries [idx].samples [self_time]);
+	
+    if (len <= max_len)
+      {
+	store_to+= len;
+	max_len -= len;
+      }
+
+	total_len += len;
+      }
+
+  return total_len+1;
+}
+
+void
+profil_reset ()
+{
+
+#if 0
+  while ( (iter= _hash_next (&sample_lookup, iter)) )
+    {
+      if (iter->owns_fun_name)
+	free (iter->fun_name);
+
+      if (iter->owns_class_name)
+	free (iter->class_name);
+    }
+#endif
+
+  free (sample_lookup.data);
+  free (class_lookup.data);
+  free (fun_lookup.data);
+
+  memset (&sample_lookup, 0, sizeof (sample_lookup));
+  memset (&class_lookup, 0, sizeof (sample_lookup));
+  memset (&fun_lookup, 0, sizeof (sample_lookup));
+
+  _pool_free ();
+
+  profil_start_sample (&started);
+  memset (&total_overhead, 0, sizeof (total_overhead));
+}
+
+static profil_sample_t _sample;
+
+void profil_start()
+{
+	if(profil_is_enabled())
+	{
+		memset (&_sample, 0, sizeof (_sample));
+		
+		profil_start_sample(&_sample);
+	}
+}
+
+void profil_stop(const char* class_name, const char* func_name)
+{
+	if(profil_is_enabled() && _sample.c [1])
+	{
+		profil_end_sample (&_sample);
+		
+		profil_register_sample ( class_name,
+								 func_name,
+								 &_sample, NULL, 1);
+		
+	}
+}
+
diff -ruN /home/favorit/ldmud-3.3.719/src/profil2.h ./profil2.h
--- /home/favorit/ldmud-3.3.719/src/profil2.h	1970-01-01 02:00:00.000000000 +0200
+++ ./profil2.h	2009-09-03 11:49:53.000000000 +0300
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2001 matti.suomalainen@iki.fi
+ * Free for non-commercial use.
+ *
+ * All rights reserved.
+ */
+
+#ifndef _PROFIL_H_
+#define _PROFIL_H_
+
+#ifdef __cplusplus
+extern"C" {
+#endif
+
+
+#define PROFIL_MAX_COUNTER 31
+
+#define PROFIL_WCHILDREN		0
+#define PROFIL_SELF			1
+
+#define PROFIL_SAMPLE_ALL 		((unsigned) -1)
+#define PROFIL_SAMPLE_TIME		 1
+#define PROFIL_SAMPLE_UTIME		 2
+#define PROFIL_SAMPLE_STIME		 3
+#define PROFIL_SAMPLE_RSS		 4
+#define PROFIL_SAMPLE_IXRSS		 5
+#define PROFIL_SAMPLE_IDRSS		 6
+#define PROFIL_SAMPLE_ISRSS		 7
+#define PROFIL_SAMPLE_MINFLT		 8
+#define PROFIL_SAMPLE_MAJFLT		 9
+#define PROFIL_SAMPLE_NSWAP		10
+#define PROFIL_SAMPLE_INBLOCK		11
+#define PROFIL_SAMPLE_OUBLOCK		12
+#define PROFIL_SAMPLE_MSGSND		13
+#define PROFIL_SAMPLE_MSGRCV		14
+#define PROFIL_SAMPLE_NSIGNALS		15
+#define PROFIL_SAMPLE_NVCSW		16
+#define PROFIL_SAMPLE_NIVCSW		17
+#define PROFIL_SAMPLE_ECOST		18
+#define PROFIL_SAMPLE_CALLS		19
+
+#define PROFILE_TIME            (1 << 0)
+#define PROFILE_RUSAGE          (1 << 1)
+#define PROFILE_FUNCALLS        (1 << 2)
+#define PROFILE_BACKEND         (1 << 3)
+
+struct profil_sample
+{
+  unsigned long long c[PROFIL_MAX_COUNTER+1];
+};
+
+typedef struct profil_sample profil_sample_t;
+
+void	profil_sample_copy (profil_sample_t *to, profil_sample_t *from);
+void	profil_sample_add (profil_sample_t *to, const profil_sample_t *by);
+void	profil_sample_sub (profil_sample_t *to, const profil_sample_t *by);
+void	profil_sample_mul (profil_sample_t *to, int by);
+
+unsigned int	profil_sample_gt (profil_sample_t *a, profil_sample_t *b);
+
+
+void		profil_start_sample (profil_sample_t *sample);
+void		profil_end_sample (profil_sample_t *sample);
+
+void		profil_enable (unsigned int mask);
+unsigned int	profil_is_enabled ();
+
+void		profil_register_sample ( const char *class_name, 
+					 const char *func_name,
+					profil_sample_t *self,
+					profil_sample_t *recur,
+					int sample_mul);
+
+unsigned int	profil_query_results (char *store_to, unsigned int max_len,
+				      unsigned int self_time,
+				      unsigned int sort_order, 
+				      unsigned int max_entries);
+void		profil_reset ();
+
+void        profil_start();
+void        profil_stop(const char* class_name, const char* func_name);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
diff -ruN /home/favorit/ldmud-3.3.719/src/prolang.y ./prolang.y
--- /home/favorit/ldmud-3.3.719/src/prolang.y	2009-06-15 01:18:52.000000000 +0300
+++ ./prolang.y	2009-09-03 12:50:05.000000000 +0300
@@ -208,6 +208,7 @@
     H_PRINT_PROMPT:   SH(T_CLOSURE) SH(T_STRING), \
     H_REGEXP_PACKAGE: SH(T_NUMBER), \
     H_MSG_DISCARDED:  SH(T_CLOSURE) SH(T_STRING), \
+    H_POST_COMMAND:   SH(T_CLOSURE) SH(T_STRING), \ /* BAT */
 
 #undef SH
 
@@ -3907,6 +3908,11 @@
     if (returntype.typeflags & TYPE_MOD_MASK)
     {
         exact_types = returntype;
+		
+//#ifdef BAT
+		if (pragma_strict_types == PRAGMA_WEAK_TYPES)
+			exact_types.typeflags = 0;
+//#endif
     }
     else
     {
@@ -5641,6 +5647,7 @@
 %token L_BREAK
 %token L_CASE
 %token L_CATCH
+%token L_CATCH_WRITE /* BAT */
 %token L_CLOSURE
 %token L_CLOSURE_DECL
 %token L_COLON_COLON
@@ -5931,6 +5938,7 @@
 %type <lrvalue>      inline_fun
 %endif /* USE_NEW_INLINES */
 %type <lrvalue>      catch sscanf
+%type <lrvalue>      catch_write /* BAT */
 %type <lrvalue>      for_init_expr for_expr
 %type <lrvalue>      comma_expr_decl expr_decl
 %ifdef USE_PARSE_COMMAND
@@ -9782,11 +9790,18 @@
       {
           $$ = $2;
           $$.type = $1;
+
+//#ifdef BAT
+          if ($2.type.typeflags != TYPE_UNKNOWN
+           && $1.typeflags != TYPE_VOID)
+//#else
+/*		  
           if ($2.type.typeflags != TYPE_ANY
            && $2.type.typeflags != TYPE_UNKNOWN
            && $1.typeflags != TYPE_VOID
            && !equal_types($1, $2.type)
              )
+*/
           {
               switch($1.typeflags)
               {
@@ -9795,6 +9810,13 @@
                   if (IS_TYPE_STRUCT($1))
                       break; /* Do nothing, just adapt the type information */
 #endif /* USE_STRUCTS */
+//#ifdef BAT
+                if($1.typeflags & TYPE_MOD_POINTER)
+                  {
+                    ins_f_code(F_TO_ARRAY);
+                    break;
+                  }
+//#endif
                   type_error("Illegal cast", $1);
                   break;
               case TYPE_ANY:
@@ -9815,6 +9837,11 @@
               case TYPE_NUMBER|TYPE_MOD_POINTER:
                   ins_f_code(F_TO_ARRAY);
                   break;
+//#ifdef BAT
+              case TYPE_MAPPING:
+				  /* fall through. hope it works */
+				  break;
+//#endif
               }
           }
           else if (pragma_warn_empty_casts)
@@ -10253,6 +10280,7 @@
 %ifdef USE_PARSE_COMMAND
     | parse_command  %prec '~'
 %endif /* USE_PARSE_COMMAND */
+    | catch_write    %prec '~' /* BAT */
 
     /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
     | L_STRING
@@ -11875,7 +11903,7 @@
 
           /* Return the data */
 
-          $$.inst  = F_RANGE;
+          $$.inst  = F_AA_RANGE; // BAT F_RANGE;
           $$.start = $3.start;
           $$.end   = $3.end;
           $$.type1 = Type_Number;
@@ -11977,7 +12005,7 @@
               $4.end++;
           }
 
-          $$.inst  = F_RANGE;
+          $$.inst  = F_AA_RANGE; // BAT F_RANGE;
           $$.start = $2.start;
           $$.end   = $4.end;
           $$.type1 = $2.type;
@@ -12121,7 +12149,7 @@
               $2.end++;
           }
 
-          $$.inst  = F_NX_RANGE;
+          $$.inst  = F_AX_RANGE; // BAT F_NX_RANGE;
           $$.start = $2.start;
           $$.end   = $2.end;
           $$.type1 = $2.type;
@@ -13750,6 +13778,30 @@
       }
 ; /* opt_catch_modifier */
 
+//%ifdef BAT
+/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
+/* catch_write()
+ *
+ */
+catch_write:
+      L_CATCH_WRITE
+{
+  $<number>$ = CURRENT_PROGRAM_SIZE;
+  ins_byte(F_CATCH_WRITE);
+  /*  ins_byte(0); */
+}
+'(' comma_expr ')'
+{
+%line
+   ins_f_code(F_END_CATCH_WRITE);
+
+ $$.start = $<number>2;
+ $$.type = Type_String;
+ /*.typeflags  = TYPE_STRING;*/
+ $$.code = -1;
+};
+//%endif
+
 /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
 /* sscanf() and parse_command()
  *
diff -ruN /home/favorit/ldmud-3.3.719/src/random.c ./random.c
--- /home/favorit/ldmud-3.3.719/src/random.c	2009-06-15 01:18:52.000000000 +0300
+++ ./random.c	2009-09-03 16:32:48.000000000 +0300
@@ -107,3 +107,56 @@
 } /* seed_random() */
 
 /***************************************************************************/
+
+//#ifdef BAT
+/*-------------------------------------------------------------------------*/
+uint32
+random_integer (void)
+
+     /* Return a random integer (uint32). */
+
+{
+    return gen_rand64();
+}
+
+/*-------------------------------------------------------------------------*/
+double
+random_double (void)
+
+     /* Return a random double (32 bits of randomness). */
+
+{
+  return ((double)random_integer() / (double)0xFFFFFFFF);
+}
+
+/*-------------------------------------------------------------------------*/
+double
+random_gaussian (void)
+
+     /* Return a Gaussian random number. */
+
+{
+  double x1, x2, w;
+  static double y2;
+  static int use_last = 0;
+
+  if (use_last)                   /* use value from previous call */
+    {
+      use_last = 0;
+      return y2;
+    }
+  else
+    {
+      do {
+	x1 = 2.0 * random_double() - 1.0;
+	x2 = 2.0 * random_double() - 1.0;
+	w = x1 * x1 + x2 * x2;
+      } while ( w >= 1.0 );
+
+      w = sqrt( (-2.0 * log( w ) ) / w );
+      y2 = x2 * w;
+      use_last = 1;
+      return x1 * w;
+    }
+}
+//#endif
diff -ruN /home/favorit/ldmud-3.3.719/src/random.h ./random.h
--- /home/favorit/ldmud-3.3.719/src/random.h	2009-06-15 01:18:52.000000000 +0300
+++ ./random.h	2009-09-03 12:20:25.000000000 +0300
@@ -26,4 +26,10 @@
   svalue number type.
 #endif
 
+//#ifdef BAT
+extern uint32 random_integer(void);
+extern double random_double(void);
+extern double random_gaussian(void);
+//#endif
+
 #endif  /* RANDOM_H__ */
diff -ruN /home/favorit/ldmud-3.3.719/src/settings/bat ./settings/bat
--- /home/favorit/ldmud-3.3.719/src/settings/bat	2009-06-15 01:18:24.000000000 +0300
+++ ./settings/bat	2009-10-02 23:53:59.000000000 +0300
@@ -4,10 +4,17 @@
 #
 # configure will strip this part from the script.
 
-exec ./configure --prefix=/bat --libdir=/bat/mudlib --with-setting=bat $*
+exec ./configure --prefix=/bat --with-setting=bat $*
 
 exit 1
 
+# Debugging enabled
+enable_malloc_check=yes
+enable_malloc_trace=yes
+enable_malloc_lpc_trace=yes
+enable_trace_code=yes
+enable_debug=yes
+
 # --- The actual settings ---
 
 #
@@ -24,31 +31,42 @@
 enable_use_mysql=1
 enable_malloc_sbrk=no
 
-enable_use_parse_command=0
+enable_use_parse_command=yes
 enable_compat_mode=no
 enable_strict_euids=no
 enable_use_deprecated=yes
 enable_use_alists=yes
-enable_use_pcre=no
+enable_use_pcre=yes
+enable_use_xml=xml2
 with_time_to_reset=3600
 with_time_to_clean_up=7200
 
+enable_use_structs=yes
+enable_use_tls=no
 
+with_alarm_time=1
+with_heart_beat_interval=3
 
 #
 # debug
 #
-enable_malloc_trace=1
-enable_malloc_lpc_trace=1
+enable_malloc_trace=0
+enable_malloc_lpc_trace=0
+enable_trace_code=no
+enable_debug=no
+enable_debug_telnet=no
 # /debug
 
-with_malloc=sysmalloc
-
+enable_malloc_check=no
+with_malloc=smalloc
 
 #
 # performance options
 #
 
+with_optimize=no
+enable_use_pthreads=yes
+
 #no swapping
 with_time_to_swap=0
 with_time_to_swap_variables=0
@@ -67,10 +85,15 @@
 with_max_trace=125
 with_hard_malloc_limit=0
 
-with_max_cost=20000000
+with_max_cost=25000000
 with_catch_reserved_cost=150000
 
 with_max_array_size=50000
-with_max_mapping_keys=50000
+with_max_mapping_keys=100000
 with_max_mapping_size=150000
 with_max_bits=20000
+with_read_file_max_size=100000
+
+# preallocation
+with_min_malloced=671088640
+with_min_small_malloced=536870912
diff -ruN /home/favorit/ldmud-3.3.719/src/settings/bat.orig ./settings/bat.orig
--- /home/favorit/ldmud-3.3.719/src/settings/bat.orig	1970-01-01 02:00:00.000000000 +0200
+++ ./settings/bat.orig	2009-09-03 11:49:53.000000000 +0300
@@ -0,0 +1,91 @@
+#!/bin/sh
+#
+# Settings for the BatMUD
+#
+# configure will strip this part from the script.
+
+exec ./configure --prefix=/bat --with-setting=bat $*
+
+exit 1
+
+# --- The actual settings ---
+
+#
+# mudlib compatibility etc options
+#
+
+with_portno=1234
+with_max_players=1000
+
+with_master_name=secure/master
+with_input_escape="@"
+
+enable_erq=erq
+enable_use_mysql=1
+enable_malloc_sbrk=no
+
+enable_use_parse_command=yes
+enable_compat_mode=no
+enable_strict_euids=no
+enable_use_deprecated=yes
+enable_use_alists=yes
+enable_use_pcre=yes
+with_time_to_reset=3600
+with_time_to_clean_up=7200
+
+enable_use_structs=yes
+enable_use_tls=no
+
+with_alarm_time=1
+with_heart_beat_interval=3
+
+#
+# debug
+#
+enable_malloc_trace=0
+enable_malloc_lpc_trace=0
+enable_trace_code=no
+enable_debug=no
+enable_debug_telnet=no
+# /debug
+
+enable_malloc_check=no
+with_malloc=smalloc
+
+#
+# performance options
+#
+
+with_optimize=med
+enable_use_pthreads=yes
+
+#no swapping
+with_time_to_swap=0
+with_time_to_swap_variables=0
+
+# 1/5 of distinct strings
+with_htable_size=274566
+
+with_itable_size=16384
+
+# 1/4 of objects
+with_otable_size=32768
+
+with_evaluator_stack_size=3000
+with_compiler_stack_size=600
+with_max_user_trace=120
+with_max_trace=125
+with_max_malloced=0
+
+with_max_cost=25000000
+with_catch_reserved_cost=150000
+
+with_max_array_size=50000
+with_max_mapping_keys=100000
+with_max_mapping_size=150000
+with_max_bits=20000
+with_read_file_max_size=100000
+
+# preallocation
+with_min_malloced=671088640
+with_min_small_malloced=536870912
diff -ruN /home/favorit/ldmud-3.3.719/src/simulate.c ./simulate.c
--- /home/favorit/ldmud-3.3.719/src/simulate.c	2009-06-15 01:18:52.000000000 +0300
+++ ./simulate.c	2009-10-02 23:51:50.000000000 +0300
@@ -71,6 +71,10 @@
 #include "wiz_list.h"
 #include "xalloc.h"
 
+//#ifdef BAT
+#include "sockets.h"
+//#endif
+
 #include "i-eval_cost.h"
 
 #include "../mudlib/sys/debug_info.h"
@@ -1689,6 +1693,20 @@
     strbuf_free(&sbuf);
 
     fprintf(stderr, "%s %s", time_stamp(), buf);
+//#ifdef BAT /* Blitzer */
+    if (command_giver != NULL)
+      {
+        fprintf (stderr, "Command giver: '%s'\n",
+                 get_txt (command_giver->name));
+
+        if (command_giver->super != NULL)
+          fprintf (stderr, "Environment: '%s'\n",
+                   get_txt (command_giver->super->name));
+
+        if (last_command != NULL)
+          fprintf (stderr, "Last command: '%s'\n", last_command);
+      }
+//#endif
     errorf("%.*s", MIN(ERROR_BUF_LEN - 200, (int)strlen(buf)), buf);
 } /* load_object_error() */
 
@@ -2553,6 +2571,8 @@
     if (ob->flags & O_DESTRUCTED)
         return;
 
+	socket_object_destructed(ob); // BAT
+
 #ifdef CHECK_OBJECT_REF
     xallocate(shadow, sizeof(*shadow), "destructed object shadow");
 #endif /* CHECK_OBJECT_REF */
diff -ruN /home/favorit/ldmud-3.3.719/src/slaballoc.c ./slaballoc.c
--- /home/favorit/ldmud-3.3.719/src/slaballoc.c	2009-06-15 01:18:52.000000000 +0300
+++ ./slaballoc.c	2009-09-03 12:30:45.000000000 +0300
@@ -1056,7 +1056,11 @@
              * as mem_alloc() does it.
              */
                 unsigned long numObjects = getNumBlocks(i);
-                unsigned long avgNumObjects = extstats[i].cur_alloc
+                unsigned long avgNumObjects;
+				if(slabtable[i].numSlabs - slabtable[i].numFreeSlabs == 0)
+					avgNumObjects = 0;
+				else
+					avgNumObjects = extstats[i].cur_alloc
                                               / (slabtable[i].numSlabs - slabtable[i].numFreeSlabs);
 
                 strbuf_addf(sbuf, "            "
diff -ruN /home/favorit/ldmud-3.3.719/src/sockets.c ./sockets.c
--- /home/favorit/ldmud-3.3.719/src/sockets.c	1970-01-01 02:00:00.000000000 +0200
+++ ./sockets.c	2009-09-03 11:49:53.000000000 +0300
@@ -0,0 +1,1146 @@
+/*
+ * Sockets for ldmud 3.3
+ *
+ * 5-July-2002 - Tomba @ Batmud (tomba@bat.org)
+ *   * First version
+ *
+ * 20-July-2002 - Tomba @ Batmud (tomba@bat.org)
+ *   * Added ECONNRESET
+ *   * Fixed socket_address to return empty string on error
+ *   * sock->send_buffer was not always cleared when freed
+ *   * removed a few debug printfs
+ *
+ * 26-September-2002 - Tomba @ Batmud (tomba@bat.org)
+ *   * Sockets now send all the data in their buffer before actually
+ *     closing
+ *   * Some minor fixes
+ *
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+#include "main.h"
+#include "svalue.h"
+#include "interpret.h"
+#include "simulate.h"
+#include "object.h"
+#include "mstrings.h"
+#include "comm.h"
+#include "actions.h"
+#include "gcollect.h"
+
+#define SE_SUCCESS 0
+#define SE_UNKNOWN -1
+#define SE_CONNREFUSED -2
+#define SE_HOSTDOWN -3
+#define SE_HOSTUNREACH -4
+#define SE_NOMORESOCKETS -5
+#define SE_CREATESOCKET -6
+#define SE_SETNONBLOCKING -7
+#define SE_SETSOCKOPT -8
+#define SE_BADFD -9
+#define SE_ILLEGALADDR -10
+#define SE_INVALIDPORT -11
+#define SE_PIPE -12
+#define SE_ADDRINUSE -13
+#define SE_INVAL -14
+#define SE_CONNRESET -15
+#define SE_ILLEGAL_SOCKET_STATE -16
+#define SE_ALREADYBOUND -17
+
+static char *socket_errors[] = {
+	"Success",
+	"Unknown error",
+	"Connection refused",
+	"Host is down",
+	"No route to host",
+	"No more mud sockets available",
+	"Failed to create socket",
+	"Failed to set socket to non-blocking mode",
+	"Failed to set socket options",
+	"Bad socket descriptor",
+	"Illegal address",
+	"Invalid port",
+	"Broken pipe",
+	"Address already in use",
+	"Invalid argument",
+	"Connection reset by peer",
+	"Illegal socket state",
+	"Socket is already bound"
+};
+
+enum socket_state
+{
+	STATE_UNUSED = 0,
+	STATE_ALLOCATED,
+	STATE_READY,
+	STATE_LISTENING,
+	STATE_CONNECTING,
+	STATE_CONNECTED,
+	STATE_CLOSING
+};
+
+static char* socket_state_strs[] = { "unused", "allocated", "ready",
+									 "listening", "connecting", "connected",
+									 "closing" };
+
+struct socket_struct
+{
+	int fd;
+	int lpc_fd;				   /* "fd" shown to lpc */
+	enum socket_state state;
+	object_t* object;
+	int bound;
+	struct sockaddr_in local_addr;
+	struct sockaddr_in remote_addr;
+
+	svalue_t read_callback;
+	svalue_t close_callback;
+	svalue_t connect_callback;
+	svalue_t listen_callback;
+
+	char* send_buffer;
+	int send_buffer_size;
+	int send_buffer_used;
+} typedef socket_t;
+
+
+#define MAX_LPC_FD 100
+
+static socket_t g_socket_table[MAX_LPC_FD];
+static struct pollfd g_poll_table[MAX_LPC_FD];
+
+#define READ_BUFFER_SIZE 10240
+static char g_read_buffer[READ_BUFFER_SIZE];
+
+void socket_process_events(socket_t* sock, short events);
+
+
+
+void socket_init()
+{
+	int i;
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		struct socket_struct* sock = &g_socket_table[i];
+	
+		sock->state = STATE_UNUSED;
+		sock->lpc_fd = i;
+
+		g_poll_table[i].fd = -1;
+		g_poll_table[i].events = POLLIN | POLLOUT;
+		g_poll_table[i].revents = 0;
+
+	}
+}
+
+#if defined(GC_SUPPORT)
+
+void clear_socket_refs(void)
+{
+	int i;
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		socket_t* sock = &g_socket_table[i];
+		
+		if(sock->state != STATE_UNUSED)
+		{
+			clear_ref_in_vector(&sock->read_callback, 1);
+			clear_ref_in_vector(&sock->close_callback, 1);
+			clear_ref_in_vector(&sock->connect_callback, 1);
+			clear_ref_in_vector(&sock->listen_callback, 1);
+		}
+	}
+}
+
+void count_socket_refs(void)
+{
+	int i;
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		socket_t* sock = &g_socket_table[i];
+		
+		if(sock->state != STATE_UNUSED)
+		{
+			count_ref_in_vector(&sock->read_callback, 1);
+			count_ref_in_vector(&sock->close_callback, 1);
+			count_ref_in_vector(&sock->connect_callback, 1);
+			count_ref_in_vector(&sock->listen_callback, 1);
+		}
+	}
+}
+
+#endif
+
+int socket_conv_errno(int err)
+{
+	switch(err)
+	{
+		case ECONNREFUSED:
+			return SE_CONNREFUSED;
+
+		case EHOSTDOWN:
+			return SE_HOSTDOWN;
+
+		case EHOSTUNREACH:
+			return SE_HOSTUNREACH;
+
+		case EPIPE:
+			return SE_PIPE;
+
+		case EADDRINUSE:
+			return SE_ADDRINUSE;
+
+		case EINVAL:
+			return SE_INVAL;
+
+		case ECONNRESET:
+			return SE_CONNRESET;
+
+		default:
+			fprintf(stderr, "socket_conv_errno: unknown system error %d, %s\n", err, strerror(err));
+			return SE_UNKNOWN;
+	}
+}
+
+struct socket_struct* new_socket_entry()
+{
+	int i;
+	
+	for (i = 0; i < MAX_LPC_FD; i++)
+	{
+		struct socket_struct* sock = &g_socket_table[i];
+		
+		if (sock->state == STATE_UNUSED)
+		{
+			sock->fd = -1;
+			sock->state = STATE_ALLOCATED;
+			sock->object = 0;
+			sock->bound = 0;
+			memset(&sock->local_addr, 0, sizeof(sock->local_addr));
+			memset(&sock->remote_addr, 0, sizeof(sock->remote_addr));
+			
+			put_number(&sock->read_callback, 0);
+			put_number(&sock->close_callback, 0);
+			put_number(&sock->connect_callback, 0);
+			put_number(&sock->listen_callback, 0);
+			
+			sock->send_buffer = 0;
+			sock->send_buffer_size = 0;
+			sock->send_buffer_used = 0;
+			
+			return sock;
+		}
+	}
+	
+	return 0;
+}
+
+void free_socket_entry(socket_t* sock)
+{
+	if(sock != 0)
+	{
+//		printf("Freeing fd %d, lpcfd %d\n", sock->fd, sock->lpc_fd);
+		if(sock->fd != -1)
+		{
+			if(close(sock->fd) == -1)
+			{
+				perror("free_socket_entry: close");
+			}
+
+			sock->fd = -1;
+		}
+	
+		sock->state = STATE_UNUSED;
+		sock->object = 0;
+		
+		free_svalue(&sock->read_callback);
+		free_svalue(&sock->close_callback);
+		free_svalue(&sock->connect_callback);
+		free_svalue(&sock->listen_callback);
+		put_number(&sock->read_callback, 0);
+		put_number(&sock->close_callback, 0);
+		put_number(&sock->connect_callback, 0);
+		put_number(&sock->listen_callback, 0);
+		
+		if(sock->send_buffer)
+		{
+			free(sock->send_buffer);
+			sock->send_buffer = 0;
+			sock->send_buffer_size = 0;
+			sock->send_buffer_used = 0;
+		}
+
+		g_poll_table[sock->lpc_fd].fd = -1;
+	}
+}
+
+socket_t* get_socket_entry(int lpc_fd)
+{
+	if(lpc_fd < 0 || lpc_fd >= MAX_LPC_FD ||
+	   g_socket_table[lpc_fd].state == STATE_UNUSED)
+	{
+		return 0;
+	}
+
+	return &g_socket_table[lpc_fd];
+}
+
+void socket_object_destructed(object_t* ob)
+{
+	int i;
+	
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		struct socket_struct* sock = &g_socket_table[i];
+
+		if(sock->state != STATE_UNUSED)
+		{
+			if(sock->object == ob)
+			{
+				free_socket_entry(sock);
+			}
+		}
+	}
+}
+
+
+
+
+
+
+svalue_t* f_socket_strerror(svalue_t* sp)
+{
+	int err = 0 - sp->u.number;
+	sp--;
+
+	if(err < 0 || err > sizeof(socket_errors))
+	{
+		push_string(sp, new_mstring("Unspecified error"));
+	}
+	else
+	{	
+		push_string(sp, new_mstring(socket_errors[err]));
+	}
+	
+	return sp;
+}
+
+svalue_t* f_socket_print_stats(svalue_t* sp)
+{
+	int i;
+	
+	add_message("-- Socket stats --\n");
+		
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		socket_t* sock = &g_socket_table[i];
+	
+		if(sock->state != STATE_UNUSED)
+		{
+			add_message("lpc_fd %d, fd %d, state %s, buf %d, ob %s\n",
+						i, sock->fd,
+						socket_state_strs[sock->state],
+						sock->send_buffer ? sock->send_buffer_used : 0,
+						get_txt(sock->object->name));
+		}
+	}
+
+	return sp;
+}
+
+int socket_init_socket(socket_t* sock, int fd, svalue_t* close_callback,
+					   object_t* object)
+{
+	int tmp;
+	
+	if(fcntl(fd, F_SETFL, O_NDELAY) == -1)
+	{
+		perror("socket_init_socket: fcntl O_NDELAY");
+
+		return SE_SETNONBLOCKING;
+	}
+
+	tmp = 1;
+	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+				  (char *)&tmp, sizeof(tmp)) == -1)
+	{
+		perror("socket_init_socket: setsockopt SO_REUSEADDR");
+
+		return SE_SETSOCKOPT;
+	}
+
+	sock->fd = fd;
+	sock->state = STATE_READY;
+	sock->object = object;
+
+	assign_svalue(&sock->close_callback, close_callback);
+	
+	g_poll_table[sock->lpc_fd].fd = sock->fd;
+
+	return 0;
+}
+
+int socket_string_to_sockaddr(char* name, struct sockaddr_in* saddr)
+{
+#define ADDR_BUF_SIZE 512
+	int port;
+	char *cp, addr[ADDR_BUF_SIZE];
+
+	strncpy(addr, name, ADDR_BUF_SIZE);
+
+	cp = strchr(addr, ':');
+	if (cp == NULL)
+	{
+		return 0;
+	}
+	
+	*cp = '\0';
+	port = atoi(cp + 1);
+
+	saddr->sin_family = AF_INET;
+	saddr->sin_port = htons((unsigned short)port);
+	if(inet_aton(addr, &saddr->sin_addr) == 0)
+	{
+		return 0;
+	}
+
+	return 1;
+#undef ADDR_BUF_SIZE
+}
+
+
+
+svalue_t* f_socket_create(svalue_t* sp)
+{
+	int err, fd;
+	socket_t* sock;
+	
+	if(current_object->flags & O_DESTRUCTED)
+	{
+		errorf("socket_create: this_object has been destructed");
+	}
+
+	sock = new_socket_entry();
+	
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		push_number(sp, SE_NOMORESOCKETS);
+		return sp;
+	}
+
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+
+	if(fd == -1)
+	{
+		perror("socket_create: socket");
+	
+		free_socket_entry(sock);
+	
+		free_svalue(sp--);
+		push_number(sp, SE_CREATESOCKET);
+		return sp;
+	}
+	
+	err = socket_init_socket(sock, fd, &sp[0], current_object);
+	
+	free_svalue(sp--);
+	
+	if(err != 0)
+	{
+		close(fd);
+	
+		free_socket_entry(sock);
+
+		push_number(sp, err);
+
+		return sp;
+	}
+	
+	push_number(sp, sock->lpc_fd);
+
+	return sp;
+}
+
+svalue_t* f_socket_close(svalue_t* sp)
+{
+	int lpc_fd = (sp--)->u.number;
+	
+	socket_t* sock = get_socket_entry(lpc_fd);
+
+	if(sock == 0)
+	{
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	if(shutdown(sock->fd, 0) == -1)
+	{
+		fprintf(stderr, "socket_close: shutdown failed: %s\n", strerror(errno));
+	}
+	
+	sock->state = STATE_CLOSING;
+
+	push_number(sp, SE_SUCCESS);
+		
+	return sp;
+}
+
+svalue_t* f_socket_connect(svalue_t* sp)
+{
+	int lpc_fd, myerrno;
+	int ret;
+	socket_t* sock;
+
+	lpc_fd = sp[-3].u.number;
+
+	sock = get_socket_entry(lpc_fd);
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	if(sock->state != STATE_READY)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_ILLEGAL_SOCKET_STATE);
+		return sp;
+	}
+
+	if(socket_string_to_sockaddr(get_txt(sp[-2].u.str), &sock->remote_addr) == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_ILLEGALADDR);
+		return sp;
+	}
+	
+	ret = connect(sock->fd, (struct sockaddr *)&sock->remote_addr,
+				  sizeof(sock->remote_addr));
+	myerrno = errno;
+	
+	if(ret == -1 && myerrno != EINPROGRESS)
+	{
+		fprintf(stderr, "socket_connect: connect failed: %s\n", strerror(myerrno));
+
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		
+		push_number(sp, socket_conv_errno(myerrno));
+	}
+	else
+	{
+		sock->state = STATE_CONNECTING;
+
+		transfer_svalue(&sock->connect_callback, &sp[-1]);
+		transfer_svalue(&sock->read_callback, &sp[0]);
+
+		sp--;
+		sp--;
+		free_svalue(sp--);
+		free_svalue(sp--);
+
+		push_number(sp, SE_SUCCESS);
+	}
+	
+	return sp;
+}
+
+svalue_t* f_socket_bind(svalue_t* sp)
+{
+	socket_t* sock;
+	int myerrno;
+   
+	int port = (sp--)->u.number;
+	int lpc_fd = (sp--)->u.number;
+
+	sock = get_socket_entry(lpc_fd);
+	if(sock == 0)
+	{
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	if(sock->state != STATE_READY)
+	{
+		push_number(sp, SE_ILLEGAL_SOCKET_STATE);
+		return sp;
+	}
+
+	if(sock->bound)
+	{
+		push_number(sp, SE_ALREADYBOUND);
+		return sp;
+	}
+
+	if(port < 0)
+	{
+		push_number(sp, SE_INVALIDPORT);
+		return sp;
+	}
+
+	sock->local_addr.sin_port = htons((unsigned short)port);
+	sock->local_addr.sin_addr.s_addr = INADDR_ANY;
+	sock->local_addr.sin_family = AF_INET;
+
+	if(bind(sock->fd, (struct sockaddr*)&sock->local_addr,
+			sizeof(sock->local_addr)) == -1)
+	{
+		myerrno = errno;
+	
+		perror("socket_bind: bind");
+		push_number(sp, socket_conv_errno(myerrno));
+	}
+	else
+	{
+		sock->bound = 1;
+		push_number(sp, SE_SUCCESS);
+	}
+	 
+	return sp;
+}
+
+svalue_t* f_socket_listen(svalue_t* sp)
+{
+	socket_t* sock;
+	int myerrno;
+   
+	int lpc_fd = sp[-1].u.number;
+
+	sock = get_socket_entry(lpc_fd);
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	if(sock->state != STATE_READY || !sock->bound)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		push_number(sp, SE_ILLEGAL_SOCKET_STATE);
+		return sp;
+	}
+	
+	if(listen(sock->fd, 10) == -1)
+	{
+		myerrno = errno;
+		perror("socket_listen: listen");
+		
+		free_svalue(sp--);
+		free_svalue(sp--);
+		push_number(sp, socket_conv_errno(myerrno));
+		return sp;
+	}
+	
+	assign_svalue(&sock->listen_callback, &sp[0]);
+	
+	free_svalue(sp--);
+	free_svalue(sp--);
+
+	sock->state = STATE_LISTENING;
+	push_number(sp, SE_SUCCESS);
+	
+	return sp;
+}
+
+svalue_t* f_socket_accept(svalue_t* sp)
+{
+	socket_t* sock;
+	socket_t* new_sock;
+	int new_fd;
+	struct sockaddr_in addr;
+	socklen_t addr_size = sizeof(addr);
+	int err;
+	int myerrno;
+   
+	int lpc_fd = sp[-2].u.number;
+	
+	sock = get_socket_entry(lpc_fd);
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	if(sock->state != STATE_LISTENING)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		push_number(sp, SE_ILLEGAL_SOCKET_STATE);
+		return sp;
+	}
+	
+	new_fd = accept(sock->fd, (struct sockaddr*)&addr, &addr_size);
+	myerrno = errno;
+	if(new_fd < 0)
+	{
+		perror("socket_accept: accept");
+	
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+
+		push_number(sp, socket_conv_errno(myerrno));
+		return sp;
+	}
+
+	new_sock = new_socket_entry();
+	
+	if(new_sock == 0)
+	{
+		close(new_fd);
+	
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_NOMORESOCKETS);
+		return sp;
+	}
+
+	err = socket_init_socket(new_sock, new_fd, &sp[0], current_object);
+
+	if(err != 0)
+	{
+		close(new_fd);
+
+		free_socket_entry(new_sock);
+	
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+
+		push_number(sp, err);
+	}
+
+	assign_svalue(&new_sock->read_callback, &sp[-1]);
+
+	memcpy(&new_sock->remote_addr, &addr, sizeof(addr));
+	
+	free_svalue(sp--);
+	free_svalue(sp--);
+	free_svalue(sp--);
+
+	new_sock->state = STATE_CONNECTED;
+	
+	push_number(sp, new_sock->lpc_fd);
+
+	return sp;
+}
+
+svalue_t* f_socket_address(svalue_t* sp)
+{
+#define ADDR_BUF_SIZE 512
+	char addrstr[ADDR_BUF_SIZE];
+	socket_t* sock;
+	
+	int lpc_fd = sp[0].u.number;
+	
+	sock = get_socket_entry(lpc_fd);
+	
+	free_svalue(sp--);
+	
+	if(sock == 0)
+	{
+		push_string(sp, new_mstring(""));
+		return sp;
+	}
+
+	if(sock->state != STATE_CONNECTED)
+	{
+		push_string(sp, new_mstring(""));
+		return sp;
+	}
+	
+	snprintf(addrstr, 511, "%s:%d",
+			 inet_ntoa(sock->remote_addr.sin_addr),
+			 ntohs(sock->remote_addr.sin_port));
+	addrstr[ADDR_BUF_SIZE-1] = 0;
+
+	push_string(sp, new_mstring(addrstr));
+
+	return sp;
+#undef ADDR_BUF_SIZE
+}
+
+void socket_flush_send_buffer(socket_t* sock)
+{
+	if( (sock->state == STATE_CONNECTED || sock->state == STATE_CLOSING) &&
+		sock->send_buffer_used > 0)
+	{
+		int len, myerrno;
+
+		len = send(sock->fd, sock->send_buffer, sock->send_buffer_used, 0);
+		myerrno = errno;
+
+		if(len == -1)
+		{
+			fprintf(stderr, "socket_flush_send_buffer: send failed %s\n", strerror(myerrno));
+
+			/* error -> clear buffer */
+			free(sock->send_buffer);
+			sock->send_buffer = 0;
+			sock->send_buffer_size = 0;
+			sock->send_buffer_used = 0;
+		}
+		else if(len < sock->send_buffer_used)
+		{
+			memmove(sock->send_buffer, sock->send_buffer + len,
+					sock->send_buffer_used - len);
+		
+			sock->send_buffer_used = sock->send_buffer_used - len;
+/*
+			printf("socket: sent %d of %d. %d in buffer\n", len, sock->send_buffer_used+len,
+				   sock->send_buffer_used);
+*/		
+		}
+		else
+		{
+/*
+			printf("socket: sent %d of %d. %d in buffer\n", len, sock->send_buffer_used,
+				   0);
+*/		
+			free(sock->send_buffer);
+			sock->send_buffer = 0;
+			sock->send_buffer_size = 0;
+			sock->send_buffer_used = 0;
+		}
+	}
+}
+
+svalue_t* f_socket_send(svalue_t* sp)
+{
+	int lpc_fd, len, myerrno;
+	socket_t* sock;
+	char* buf;
+	int buflen;
+	
+	lpc_fd = sp[-1].u.number;
+	
+	sock = get_socket_entry(lpc_fd);
+
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	if(sock->state != STATE_CONNECTED)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		push_number(sp, SE_ILLEGAL_SOCKET_STATE);
+		return sp;
+	}
+	
+	buf =  get_txt(sp[0].u.str);
+	buflen = mstrsize(sp[0].u.str);
+
+	socket_flush_send_buffer(sock);
+	
+	if(sock->send_buffer_used == 0)
+	{
+		len = send(sock->fd, buf, buflen, 0);
+		myerrno = errno;
+	}
+	else
+	{
+		myerrno = 0;
+		len = 0;
+	}
+
+	if(len == -1 && (myerrno == EAGAIN || myerrno == EWOULDBLOCK))
+	{
+		len = 0;
+	}
+	
+	if(len == -1)
+	{
+		fprintf(stderr, "socket_send: send failed %s\n", strerror(myerrno));
+
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, socket_conv_errno(myerrno));
+	}
+	else if(len < buflen)
+	{
+		if(buflen - len > sock->send_buffer_size - sock->send_buffer_used)
+		{
+			sock->send_buffer = realloc(sock->send_buffer,
+										sock->send_buffer_used + buflen - len);
+
+			if(!sock->send_buffer)
+			{
+				errorf("out of memory");
+			}
+			else
+			{
+				sock->send_buffer_size = sock->send_buffer_used + buflen - len;
+			}
+		}
+
+		memcpy(sock->send_buffer + sock->send_buffer_used,
+			   buf + len,
+			   buflen - len);
+
+		sock->send_buffer_used += buflen - len;
+
+//		printf("socket_send(): sent %d of %d. %d in buffer\n", len, buflen, sock->send_buffer_used);
+
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, len);
+	}
+	else
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_SUCCESS);
+	}
+	
+	return sp;
+}
+
+void socket_poll()
+{
+	int ret, i, myerrno;
+
+	object_t* hide_current_object = current_object;
+	program_t* hide_current_prog = current_prog;
+	object_t* hide_interactive = current_interactive;
+	object_t* hide_command_giver = command_giver;
+
+	current_interactive = 0;
+	command_giver = 0;
+
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		socket_t* sock = &g_socket_table[i];
+
+		/* if socket is closing and we have sent all the stuff out,
+		   free it */
+		if(sock->state == STATE_CLOSING && sock->send_buffer == 0)
+		{
+			free_socket_entry(sock);
+		}
+	}
+
+	ret = poll(g_poll_table, MAX_LPC_FD, 0);
+	myerrno = errno;
+	
+	if(ret == -1)
+	{
+		perror("socket_poll: poll");
+	}
+	else
+	{
+		for(i = 0; i < MAX_LPC_FD; i++)
+		{
+			if(g_poll_table[i].revents)
+			{
+				socket_t* sock = get_socket_entry(i);
+		
+				if(sock == 0)
+				{
+					errorf("Internal error in socket_poll()");
+				}
+		
+				socket_process_events(sock, g_poll_table[i].revents);
+			}
+		}
+	}
+	
+	current_interactive = hide_interactive;
+	command_giver = hide_command_giver;
+	current_object = hide_current_object;
+	current_prog = hide_current_prog;
+}
+
+
+void socket_process_events(socket_t* sock, short events)
+{
+	int err;
+	socklen_t errlen;
+	int myerrno;
+
+	if(events & POLLNVAL)
+	{
+//		printf("NVAL %d\n", sock->lpc_fd);
+		
+		push_number(inter_sp, sock->lpc_fd);
+		push_number(inter_sp, SE_UNKNOWN);
+		secure_callback_lambda(&sock->close_callback, 2);
+		free_socket_entry(sock);
+		return;
+	}
+	
+	if(events & POLLERR)
+	{
+//		printf("ERR %d\n", sock->lpc_fd);
+	
+		errlen = sizeof(err);
+		if(getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1)
+		{
+			perror("socket_process_events: getsockopt");
+		}
+	
+		if(sock->state == STATE_CONNECTING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, socket_conv_errno(err));
+			secure_callback_lambda(&sock->connect_callback, 2);
+		}
+		else
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, socket_conv_errno(err));
+			secure_callback_lambda(&sock->close_callback, 2);
+			free_socket_entry(sock);
+		}
+		
+		return;
+	}
+		
+	if(events & POLLHUP)
+	{
+//		printf("HUP %d\n", sock->lpc_fd);
+	
+		errlen = sizeof(err);
+		if(getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1)
+		{
+			perror("socket_process_events: getsockopt");
+		}
+
+		if(sock->state == STATE_CONNECTING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, err);
+			secure_callback_lambda(&sock->connect_callback, 2);
+		}
+		else
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, err);
+			secure_callback_lambda(&sock->close_callback, 2);
+			free_socket_entry(sock);
+		}
+				
+		return;
+	}
+
+	if(events & POLLOUT)
+	{
+//		printf("OUT %d\n", sock->lpc_fd);
+
+		if(sock->state == STATE_CONNECTING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, 0);
+			secure_callback_lambda(&sock->connect_callback, 2);
+
+			sock->state = STATE_CONNECTED;
+		}
+		else if(sock->state == STATE_CONNECTED ||
+				sock->state == STATE_CLOSING)
+		{
+			socket_flush_send_buffer(sock);
+		}
+		else
+		{
+			fprintf(stderr, "Illegal socket state in POLLOUT. fd: %d, state %d\n", sock->fd, sock->state);
+		}
+	}
+	
+	if(events & POLLIN)
+	{
+//		printf("IN %d\n", sock->lpc_fd);
+		
+		if(sock->state == STATE_CONNECTED)
+		{
+			int len;
+			
+			len = recv(sock->fd, &g_read_buffer, READ_BUFFER_SIZE, 0);
+			myerrno = errno;
+
+			if(len == -1)
+			{
+				perror("socket_process_events: recv");
+		
+				push_number(inter_sp, sock->lpc_fd);
+				push_number(inter_sp, 0);
+				push_number(inter_sp, socket_conv_errno(myerrno));
+		
+				secure_callback_lambda(&sock->read_callback, 3);
+			}
+			else if(len == 0)
+			{
+				push_number(inter_sp, sock->lpc_fd);
+				push_number(inter_sp, 0);
+		
+				secure_callback_lambda(&sock->close_callback, 2);
+		
+				free_socket_entry(sock);
+			}
+			else
+			{
+				push_number(inter_sp, sock->lpc_fd);
+				push_string(inter_sp, mstring_new_n_string(g_read_buffer, len));
+				push_number(inter_sp, len);
+		
+				secure_callback_lambda(&sock->read_callback, 3);
+			}
+		}
+		else if(sock->state == STATE_LISTENING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+		
+			secure_callback_lambda(&sock->listen_callback, 1);
+		}
+		else if(sock->state == STATE_CLOSING)
+		{
+			
+		}
+		else
+		{
+			fprintf(stderr, "socket_poll: read event in unknown state. fd: %d, state %d\n", sock->fd, sock->state);
+		}
+	}
+}
diff -ruN /home/favorit/ldmud-3.3.719/src/sockets.h ./sockets.h
--- /home/favorit/ldmud-3.3.719/src/sockets.h	1970-01-01 02:00:00.000000000 +0200
+++ ./sockets.h	2009-09-03 11:49:53.000000000 +0300
@@ -0,0 +1,9 @@
+
+extern void socket_init();
+
+extern void socket_object_destructed(object_t* ob);
+
+extern void socket_poll();
+
+extern void clear_socket_refs(void);
+extern void count_socket_refs(void);
diff -ruN /home/favorit/ldmud-3.3.719/src/sprintf.c ./sprintf.c
--- /home/favorit/ldmud-3.3.719/src/sprintf.c	2009-06-15 01:18:52.000000000 +0300
+++ ./sprintf.c	2009-09-03 12:30:45.000000000 +0300
@@ -2443,7 +2443,7 @@
     str = string_print_formatted(get_txt((sp-num_arg+1)->u.str)
                                 , num_arg-1, sp-num_arg+2);
     if (command_giver)
-        tell_object(command_giver, str);
+        tell_object(command_giver, str, 0); // BAT
     else
         add_message(FMT_STRING, str);
     free_mstring(str);
diff -ruN /home/favorit/ldmud-3.3.719/src/string_spec ./string_spec
--- /home/favorit/ldmud-3.3.719/src/string_spec	2009-06-15 01:18:52.000000000 +0300
+++ ./string_spec	2009-09-03 12:30:45.000000000 +0300
@@ -116,6 +116,7 @@
 TAIL               "tail"
 WRITE_BYTES        "write_bytes"
 WRITE_FILE         "write_file"
+COUNT_LINES        "count_lines" /* BAT */
 
     /* Editor strings */
 
diff -ruN /home/favorit/ldmud-3.3.719/src/version.sh ./version.sh
--- /home/favorit/ldmud-3.3.719/src/version.sh	2009-06-15 01:18:52.000000000 +0300
+++ ./version.sh	2009-10-03 00:05:30.000000000 +0300
@@ -17,7 +17,7 @@
 # A timestamp, to be used by bumpversion and other scripts.
 # It can be used, for example, to 'touch' this file on every build, thus
 # forcing revision control systems to add it on every checkin automatically.
-version_stamp="2009-05-30 12:00:00"
+version_stamp="Sat Oct  3 00:05:30 EEST 2009"
 
 # The version number information
 version_micro=719
