diff -uprN -x *.o ../stk/Makefile ./Makefile
--- ../stk/Makefile	Wed Oct 29 22:37:52 1997
+++ ./Makefile	Mon Dec 15 23:35:02 1997
@@ -9,7 +9,7 @@ CC = gcc
 MYFLAGS = -Wall
 
 #flags for profiling (see hacker.doc for more information)
-PROFILE = 
+PROFILE = -pg
 
 ##############################################################################
 # Do Not Modify Anything Below This Line (unless you know what you're doing) #
@@ -24,14 +24,14 @@ OBJFILES = comm.o act.comm.o act.informa
 	castle.o class.o config.o constants.o db.o fight.o graph.o handler.o \
 	house.o interpreter.o limits.o magic.o mail.o mobact.o modify.o \
 	objsave.o olc.o random.o shop.o spec_assign.o spec_procs.o \
-	spell_parser.o spells.o utils.o weather.o
+	spell_parser.o spells.o utils.o weather.o buffer.o
 
 CXREF_FILES = act.comm.c act.informative.c act.item.c act.movement.c \
 	act.offensive.c act.other.c act.social.c act.wizard.c ban.c boards.c \
 	castle.c class.c comm.c config.c constants.c db.c fight.c graph.c \
 	handler.c house.c interpreter.c limits.c magic.c mail.c mobact.c \
 	modify.c objsave.c olc.c random.c shop.c spec_assign.c spec_procs.c \
-	spell_parser.c spells.c utils.c weather.c
+	spell_parser.c spells.c utils.c weather.c buffer.c
 
 default: all
 
@@ -48,7 +48,12 @@ circle:
 	$(MAKE) $(BINDIR)/circle
 
 $(BINDIR)/circle : $(OBJFILES)
-	$(CC) -o $(BINDIR)/circle $(PROFILE) $(OBJFILES)   -lsocket -lnsl 
+	$(CC) -o $(BINDIR)/circle $(PROFILE) $(OBJFILES)   -lsocket -lnsl -lpthread -ldl
+
+thread.o: thread.c conf.h sysdep.h structs.h utils.h buffer.h
+	$(CC) $(CFLAGS) -c thread.c
+thread: thread.o buffer.o
+	$(CC) $(CFLAGS) -o $(BINDIR)/thread thread.o buffer.o -lnsl -lpthread -ldl
 
 clean:
 	rm -f *.o
@@ -91,104 +96,109 @@ ref:
 # gcc -MM)
 
 act.comm.o: act.comm.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h \
-  handler.h db.h screen.h
+  handler.h db.h screen.h buffer.h
 	$(CC) -c $(CFLAGS) act.comm.c
 act.informative.o: act.informative.c conf.h sysdep.h structs.h utils.h comm.h \
-  interpreter.h handler.h db.h spells.h screen.h
+  interpreter.h handler.h db.h spells.h screen.h buffer.h
 	$(CC) -c $(CFLAGS) act.informative.c
 act.item.o: act.item.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h \
-  handler.h db.h spells.h
+  handler.h db.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) act.item.c
 act.movement.o: act.movement.c conf.h sysdep.h structs.h utils.h comm.h \
-  interpreter.h handler.h db.h spells.h house.h
+  interpreter.h handler.h db.h spells.h house.h buffer.h
 	$(CC) -c $(CFLAGS) act.movement.c
 act.offensive.o: act.offensive.c conf.h sysdep.h structs.h utils.h comm.h \
-  interpreter.h handler.h db.h spells.h
+  interpreter.h handler.h db.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) act.offensive.c
 act.other.o: act.other.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h \
-  handler.h db.h spells.h screen.h house.h
+  handler.h db.h spells.h screen.h house.h buffer.h
 	$(CC) -c $(CFLAGS) act.other.c
 act.social.o: act.social.c conf.h sysdep.h structs.h utils.h comm.h \
-  interpreter.h handler.h db.h spells.h
+  interpreter.h handler.h db.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) act.social.c
 act.wizard.o: act.wizard.c conf.h sysdep.h structs.h utils.h comm.h \
-  interpreter.h handler.h db.h spells.h house.h screen.h
+  interpreter.h handler.h db.h spells.h house.h screen.h buffer.h
 	$(CC) -c $(CFLAGS) act.wizard.c
-ban.o: ban.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h db.h
+ban.o: ban.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h \
+  db.h buffer.h
 	$(CC) -c $(CFLAGS) ban.c
 boards.o: boards.c conf.h sysdep.h structs.h utils.h comm.h db.h boards.h \
-  interpreter.h handler.h
+  interpreter.h handler.h buffer.h
 	$(CC) -c $(CFLAGS) boards.c
 castle.o: castle.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h \
-  handler.h db.h spells.h
+  handler.h db.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) castle.c
-class.o: class.c conf.h sysdep.h structs.h db.h utils.h spells.h interpreter.h
+class.o: class.c conf.h sysdep.h structs.h db.h utils.h spells.h \
+  interpreter.h buffer.h
 	$(CC) -c $(CFLAGS) class.c
 comm.o: comm.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h \
-  db.h house.h
+  db.h house.h buffer.h
 	$(CC) -c $(CFLAGS) comm.c
 config.o: config.c conf.h sysdep.h structs.h
 	$(CC) -c $(CFLAGS) config.c
 constants.o: constants.c conf.h sysdep.h structs.h
 	$(CC) -c $(CFLAGS) constants.c
 db.o: db.c conf.h sysdep.h structs.h utils.h db.h comm.h handler.h spells.h mail.h \
-  interpreter.h house.h
+  interpreter.h house.h buffer.h
 	$(CC) -c $(CFLAGS) db.c
 fight.o: fight.c conf.h sysdep.h structs.h utils.h comm.h handler.h interpreter.h \
-  db.h spells.h screen.h
+  db.h spells.h screen.h buffer.h
 	$(CC) -c $(CFLAGS) fight.c
 graph.o: graph.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h \
-  db.h spells.h
+  db.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) graph.c
 handler.o: handler.c conf.h sysdep.h structs.h utils.h comm.h db.h handler.h \
-  interpreter.h spells.h
+  interpreter.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) handler.c
 house.o: house.c conf.h sysdep.h structs.h comm.h handler.h db.h interpreter.h \
-  utils.h house.h
+  utils.h house.h buffer.h
 	$(CC) -c $(CFLAGS) house.c
 interpreter.o: interpreter.c conf.h sysdep.h structs.h comm.h interpreter.h db.h \
-  utils.h spells.h handler.h mail.h screen.h
+  utils.h spells.h handler.h mail.h screen.h buffer.h
 	$(CC) -c $(CFLAGS) interpreter.c
 limits.o: limits.c conf.h sysdep.h structs.h utils.h spells.h comm.h db.h \
-  handler.h
+  handler.h buffer.h
 	$(CC) -c $(CFLAGS) limits.c
-magic.o: magic.c conf.h sysdep.h structs.h utils.h comm.h spells.h handler.h db.h
+magic.o: magic.c conf.h sysdep.h structs.h utils.h comm.h spells.h handler.h \
+  db.h buffer.h
 	$(CC) -c $(CFLAGS) magic.c
 mail.o: mail.c conf.h sysdep.h structs.h utils.h comm.h db.h interpreter.h \
-  handler.h mail.h
+  handler.h mail.h buffer.h
 	$(CC) -c $(CFLAGS) mail.c
 mobact.o: mobact.c conf.h sysdep.h structs.h utils.h db.h comm.h interpreter.h \
-  handler.h spells.h
+  handler.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) mobact.c
 modify.o: modify.c conf.h sysdep.h structs.h utils.h interpreter.h handler.h db.h \
-  comm.h spells.h mail.h boards.h
+  comm.h spells.h mail.h boards.h buffer.h
 	$(CC) -c $(CFLAGS) modify.c
 objsave.o: objsave.c conf.h sysdep.h structs.h comm.h handler.h db.h \
-  interpreter.h utils.h spells.h
+  interpreter.h utils.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) objsave.c
 olc.o: olc.c conf.h sysdep.h structs.h utils.h comm.h interpreter.h handler.h db.h \
-  olc.h
+  olc.h buffer.h
 	$(CC) -c $(CFLAGS) olc.c
 random.o: random.c utils.h
 	$(CC) -c $(CFLAGS) random.c
 shop.o: shop.c conf.h sysdep.h structs.h comm.h handler.h db.h interpreter.h \
-  utils.h shop.h
+  utils.h shop.h buffer.h
 	$(CC) -c $(CFLAGS) shop.c
 spec_assign.o: spec_assign.c conf.h sysdep.h structs.h db.h interpreter.h \
-  utils.h
+  utils.h buffer.h
 	$(CC) -c $(CFLAGS) spec_assign.c
 spec_procs.o: spec_procs.c conf.h sysdep.h structs.h utils.h comm.h \
-  interpreter.h handler.h db.h spells.h
+  interpreter.h handler.h db.h spells.h buffer.h
 	$(CC) -c $(CFLAGS) spec_procs.c
 spell_parser.o: spell_parser.c conf.h sysdep.h structs.h utils.h interpreter.h \
-  spells.h handler.h comm.h db.h
+  spells.h handler.h comm.h db.h buffer.h
 	$(CC) -c $(CFLAGS) spell_parser.c
 spells.o: spells.c conf.h sysdep.h structs.h utils.h comm.h spells.h handler.h \
-  db.h
+  db.h buffer.h
 	$(CC) -c $(CFLAGS) spells.c
 utils.o: utils.c conf.h sysdep.h structs.h utils.h comm.h screen.h spells.h \
-  handler.h
+  handler.h buffer.h
 	$(CC) -c $(CFLAGS) utils.c
 weather.o: weather.c conf.h sysdep.h structs.h utils.h comm.h handler.h \
-  interpreter.h db.h
+  interpreter.h db.h buffer.h
 	$(CC) -c $(CFLAGS) weather.c
+buffer.o: buffer.c conf.h sysdep.h structs.h utils.h interpreter.h buffer.h
+	$(CC) -c $(CFLAGS) buffer.c
diff -uprN -x *.o ../stk/Makefile.in ./Makefile.in
--- ../stk/Makefile.in	Wed Oct 29 00:16:18 1997
+++ ./Makefile.in	Wed Nov 26 13:19:37 1997
@@ -23,14 +23,14 @@ OBJFILES = comm.o act.comm.o act.informa
 	castle.o class.o config.o constants.o db.o fight.o graph.o handler.o \
 	house.o interpreter.o limits.o magic.o mail.o mobact.o modify.o \
 	objsave.o olc.o random.o shop.o spec_assign.o spec_procs.o \
-	spell_parser.o spells.o utils.o weather.o
+	spell_parser.o spells.o utils.o weather.o buffer.o
 
 CXREF_FILES = act.comm.c act.informative.c act.item.c act.movement.c \
 	act.offensive.c act.other.c act.social.c act.wizard.c ban.c boards.c \
 	castle.c class.c comm.c config.c constants.c db.c fight.c graph.c \
 	handler.c house.c interpreter.c limits.c magic.c mail.c mobact.c \
 	modify.c objsave.c olc.c random.c shop.c spec_assign.c spec_procs.c \
-	spell_parser.c spells.c utils.c weather.c
+	spell_parser.c spells.c utils.c weather.c buffer.c
 
 default: all
 
diff -uprN -x *.o ../stk/act.comm.c ./act.comm.c
--- ../stk/act.comm.c	Fri Apr 12 23:39:21 1996
+++ ./act.comm.c	Wed Nov 26 14:50:18 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/act.informative.c ./act.informative.c
--- ../stk/act.informative.c	Wed Oct 29 00:16:21 1997
+++ ./act.informative.c	Wed Nov 26 14:50:27 1997
@@ -12,6 +12,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/act.item.c ./act.item.c
--- ../stk/act.item.c	Wed Oct 29 00:16:21 1997
+++ ./act.item.c	Wed Nov 26 14:50:33 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/act.movement.c ./act.movement.c
--- ../stk/act.movement.c	Sat Apr 13 20:02:07 1996
+++ ./act.movement.c	Wed Nov 26 14:50:39 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/act.offensive.c ./act.offensive.c
--- ../stk/act.offensive.c	Wed Oct 29 00:16:21 1997
+++ ./act.offensive.c	Wed Nov 26 14:50:47 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/act.other.c ./act.other.c
--- ../stk/act.other.c	Wed Oct 29 00:16:21 1997
+++ ./act.other.c	Wed Nov 26 14:50:59 1997
@@ -14,6 +14,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/act.social.c ./act.social.c
--- ../stk/act.social.c	Wed Oct 29 00:16:21 1997
+++ ./act.social.c	Wed Nov 26 14:51:07 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/act.wizard.c ./act.wizard.c
--- ../stk/act.wizard.c	Wed Oct 29 00:16:22 1997
+++ ./act.wizard.c	Wed Nov 26 15:59:57 1997
@@ -12,6 +12,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
@@ -1901,6 +1902,7 @@ ACMD(do_show)
     { "godrooms",	LVL_GOD },
     { "shops",		LVL_IMMORT },
     { "houses",		LVL_GOD },
+    { "buffers",	LVL_GOD },			/* 10 */
     { "\n", 0 }
   };
 
@@ -2002,6 +2004,8 @@ ACMD(do_show)
     sprintf(buf, "%s  %5d large bufs\r\n", buf, buf_largecount);
     sprintf(buf, "%s  %5d buf switches     %5d overflows\r\n", buf,
 	    buf_switches, buf_overflows);
+    sprintf(buf, "%s  %5d buf cache hits   %5d buf cache misses\r\n", buf,
+	    buffer_cache_hits, buffer_cache_misses);
     send_to_char(buf, ch);
     break;
   case 5:
@@ -2033,6 +2037,9 @@ ACMD(do_show)
     break;
   case 9:
     hcontrol_list_houses(ch);
+    break;
+  case 10:
+    show_buffers(ch);
     break;
   default:
     send_to_char("Sorry, I don't understand that.\r\n", ch);
diff -uprN -x *.o ../stk/ban.c ./ban.c
--- ../stk/ban.c	Wed Oct 29 00:16:22 1997
+++ ./ban.c	Wed Nov 26 14:51:17 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/boards.c ./boards.c
--- ../stk/boards.c	Wed Oct 29 00:16:22 1997
+++ ./boards.c	Wed Nov 26 14:51:26 1997
@@ -47,8 +47,8 @@ TO ADD A NEW BOARD, simply follow our ea
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "db.h"
diff -uprN -x *.o ../stk/buffer.c ./buffer.c
--- ../stk/buffer.c	Wed Dec 31 19:00:00 1969
+++ ./buffer.c	Mon Dec 15 23:39:49 1997
@@ -0,0 +1,1215 @@
+/************************************************************************
+ * buffer.c - Advanced Buffer System				v1.7	*
+ *									*
+ * Designed for CircleMUD 3.0			November 26, 1997	*
+ ************************************************************************/
+
+#define _BUFFER_C_
+
+#include <stdarg.h>
+#include "conf.h"
+#include "sysdep.h"
+
+#include "structs.h"
+#include "buffer.h"
+#include "utils.h"
+#include "interpreter.h"
+
+#if defined(THREADED)
+#include <pthread.h>
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * Set	: Use a memset() to clear each buffer after use.
+ * Unset: Do a *buffer = '\0'					(recommended)
+ */
+#define BUF_NUKE	(1 << 0)
+/*
+ * Set	: Report how much of each buffer the functions used.
+ * Unset: Don't report.						(recommended)
+ */
+#define BUF_CHECK	(1 << 1)
+/*
+ * Set	: Reboot immediately on overflow...			(recommended)
+ * Unset: Reboot after MAX_OVERFLOW corruptions if we don't crash anyway.
+ */
+#define BUF_OVERBOOT	(1 << 2)
+/*
+ * Set	: Log everything.
+ * Unset: Log only error messages and useful things.		(recommended)
+ */
+#define BUF_VERBOSE	(1 << 3)
+#define BUF_DETAIL	(1 << 4)
+/*
+ * Example: ush_int buffer_top = BUF_OVERBOOT | BUF_VERBOSE | BUF_CHECK;
+ */
+ush_int buffer_opt = BUF_OVERBOOT;
+
+/*
+ * MAGIC_NUMBER - Any arbitrary hex value unlikely to show up in a string.
+ *	In this case, we use a NAK character. (0x06)
+ * MAX_OVERFLOW - How many times can we overflow a buffer before a reboot?
+ * MAX_ALLOC - The largest buffer allowed without griping.
+ * MIN_ALLOC - The lowest buffer ever handed.  If 20 bytes are requested,
+ *	we will allocate a 64 byte buffer anyway (with the defaults).
+ * BUFFER_LIFE - How long can a buffer be unused before it is free()'d?
+ * LEASE_LIFE - The amount of time a buffer can be used before it is
+ *	considered forgotten.  Only useful when we get multithreaded.
+ */
+#define BUFFER_LIFE	(600 RL_SEC)	/* 5 minutes */
+#define LEASE_LIFE	(60 RL_SEC)	/* 1 minute */
+#define MAGIC_NUMBER	(0x06)
+#define MAX_OVERFLOW	(3)
+#define MAX_ALLOC	(16)	/* 2**16 = 65536 bytes	*/
+#define MIN_ALLOC	(6)	/* 2**6  = 64 bytes	*/
+#define CACHE_SIZE	(3)
+
+/*
+ * Don't change these.
+ * B_FREELIFE - The buffer life in pulses.
+ * B_GIVELIFE - The lease life in pulses.
+ * ALLOC_RANGE - The maximum [] value in the buffer array.
+ */
+#define ALLOC_RANGE	(MAX_ALLOC - MIN_ALLOC)
+#if defined(THREADED)
+#define B_FREELIFE	(BUFFER_LIFE / PASSES_PER_SEC)
+#define B_GIVELIFE	(BUFFER_LIFE / PASSES_PER_SEC)
+#else
+#define B_FREELIFE	(BUFFER_LIFE / PULSE_BUFFER / PASSES_PER_SEC)
+#define B_GIVELIFE	(LEASE_LIFE / PULSE_BUFFER / PASSES_PER_SEC)	
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+struct wait_q {
+  int line;
+  int type;
+  const char *func;
+  struct wait_q *next;
+};
+
+/*
+ * Global variables.
+ *  buffers - head of the allocation linked list.
+ *  buffer_cache - pointer to last allocated structures, a cache for freeing.
+ *  buffer_overflow - how many times we've corrupted the buffer list.
+ *  buffer_cache_misses - How many times a buffer wasn't in the cache.
+ *  buffer_cache_hits - How many times the buffer was in cache.
+ *  buf_thread - Handle of the buffer thread.
+ *  buflockq - The next function to get the buffer lock.
+ *  buflocktail - Pointer to attach wait queues to.
+ */
+struct buf_data **buffers;
+struct buf_data **buffer_cache;
+int buffer_cache_misses = 0;
+int buffer_cache_hits = 0;
+byte buffer_overflow = 0;
+#if defined(THREADED)
+pthread_t buf_thread = 0;
+struct wait_q *buflockq = NULL;
+struct wait_q *buflocktail = NULL;
+#endif
+
+/* External functions and variables. */
+void send_to_char(char *, struct char_data *);
+void send_to_all(char *);
+void *buffer_thread(void *);
+extern int circle_shutdown;
+extern int circle_reboot;
+
+/* Private functions. */
+struct buf_data *new_buffer(size_t size, int type);
+struct buf_data *malloc_buffer(size_t size, int type);
+struct buf_data **get_buffer_head(void);
+struct buf_data *in_cache(const char *data);
+void set_buffer_head(struct buf_data **new_head);
+void free_buffer(struct buf_data *f);
+void clear_buffer(struct buf_data *clearme);
+void remove_buffer(struct buf_data *removeme);
+int remove_from_cache(struct buf_data *removeme);
+int add_to_cache(struct buf_data *addme);
+int get_used(struct buf_data *buf);
+int get_magnitude(ush_int number);
+#if defined(THREADED)
+void bufferlist_lock(int type, const char *func, ush_int line);
+void bufferlist_unlock(const char *func, ush_int line);
+void buffer_lock(struct buf_data *buf, int type, const char *func, ush_int line);
+void buffer_unlock(struct buf_data *buf, const char *func, ush_int line);
+#endif
+#if defined(BUFFER_MEMORY)
+void really_free(void *ptr);
+void *debug_calloc(size_t number, size_t size, char *func, int line);
+void *debug_realloc(void *ptr, size_t size, const char *func, int line);
+void debug_free(void *ptr);
+#endif
+
+            static struct buf_data *lastgive = NULL;
+
+#if defined(THREADED)
+/*
+ * Wrapper macros.
+ */
+#define lock_buffers(type)	(bufferlist_lock((type), __FUNCTION__, __LINE__))
+#define unlock_buffers()	(bufferlist_unlock(__FUNCTION__, __LINE__))
+#define LOCK(buf, type)		(buffer_lock((buf), (type), __FUNCTION__, __LINE__))
+#define UNLOCK(buf)		((buf)->locked = LOCK_NONE)
+#define LOCKED(buf)		((buf)->locked)
+#else
+#define lock_buffers(type)
+#define unlock_buffers()
+#define LOCK(buf, type)
+#define UNLOCK(buf)
+#define LOCKED(buf)		(FALSE)
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * Private: get_buffer_head()
+ */
+inline struct buf_data **get_buffer_head()
+{
+  return buffers;
+}
+
+/*
+ * Private: set_buffer_head(new buffer head)
+ */
+inline void set_buffer_head(struct buf_data **new_head)
+{
+  buffers = new_head;
+}
+
+#if 0
+/*
+ * Public: pow2(number)
+ * Simply function to avoid math library.
+ */
+int pow2(int y)
+{
+  int number = 2;
+  while(y-- > 1)
+    number *= 2;
+  return number;
+}
+#endif
+
+/*
+ * Public: get_magnitude(number)
+ * Simple function to avoid math library, and enforce maximum allocations.
+ * If it is not enforced here, we will overrun the bounds of the array.
+ */
+int get_magnitude(ush_int y)
+{
+  int number, x = y;
+
+  for (number = -1; y > 0; number++, y /= 2);
+  number = MIN(MAX_ALLOC, MAX(number, MIN_ALLOC));
+  number -= MIN_ALLOC;
+
+  if (number > ALLOC_RANGE)
+    log("get_magnitude: Oops.");
+
+  if (buffer_opt & BUF_VERBOSE) {
+    char gmbuf[128];
+    sprintf(gmbuf, "BUF: get_magnitude: Given:%d Returned:%d.", x, number);
+    log(gmbuf);
+  }
+
+  return number;
+}
+
+/*
+ * Private: add_to_cache(structure to add)
+ * Does what it says.
+ */
+int add_to_cache(struct buf_data *addme)
+{
+  int i;
+
+  /*
+   * Move everybody down.
+   */
+  for (i = (CACHE_SIZE - 1); i > 0; i--)
+    buffer_cache[i] = buffer_cache[i - 1];
+  /*
+   * Add the structure to the front.
+   */
+  buffer_cache[0] = addme;
+  return TRUE;
+}
+
+/*
+ * Private: remove_from_cache(structure to remove)
+ * Does what it says.
+ */
+int remove_from_cache(struct buf_data *removeme)
+{
+  int i;
+
+  for (i = 0; i < CACHE_SIZE; i++)
+    if (buffer_cache[i] == removeme) {
+      buffer_cache[i] = NULL;
+      return TRUE;
+    }
+  return FALSE;
+}
+
+/*
+ * Private: in_cache(data to search for)
+ * Used internally since the cache expanded complexity.
+ */
+struct buf_data *in_cache(const char *data)
+{
+  int i;
+  for (i = 0; i < CACHE_SIZE; i++)
+    if (buffer_cache[i] && buffer_cache[i]->data == data) {
+      buffer_cache_hits++;
+      if (buffer_opt & BUF_VERBOSE)
+	log("BUF: in_cache: Cache hit.");
+      if (LOCKED(buffer_cache[i]))
+	log("BUF: in_cache: Giving out locked buffer reference.");
+      return buffer_cache[i];
+    }
+  if (buffer_opt & BUF_VERBOSE)
+    log("BUF: in_cache: Cache miss.");
+
+  buffer_cache_misses++;
+  return NULL;
+}
+
+/*
+ * Public: exit_buffers()
+ * Called to clear out the buffer structures and log any BT_MALLOC's left.
+ */
+void exit_buffers(void)
+{
+  int magnitude;
+  struct buf_data **head, *clear, *next_clear;
+
+  log("BUF: Shutting down.");
+
+#if defined(THREADED)
+  pthread_join(buf_thread, NULL);
+#endif
+
+  show_buffers(NULL);
+
+  lock_buffers(LOCK_CLOSED);
+
+  head = get_buffer_head();
+  for (magnitude = 0; magnitude <= ALLOC_RANGE; magnitude++) {
+    for (clear = head[magnitude]; clear; clear = next_clear) {
+      next_clear = clear->next;
+      LOCK(clear, LOCK_WILL_FREE);
+      free_buffer(clear);
+    }
+  }
+
+  if (buffer_cache)
+    really_free(buffer_cache);
+  if (head)
+    really_free(head);
+}
+
+/*
+ * Public: init_buffers()
+ * This is called from main() to get everything started.
+ */
+void init_buffers(void)
+{
+#if defined(THREADED)
+  int error = 0;
+#endif
+
+  lock_buffers(LOCK_CLOSED);
+
+#if defined(THREADED)
+  /*
+   * If a buffer thread already exists, kill it.
+   */
+  if (buf_thread != 0)
+    pthread_cancel(buf_thread);
+
+  /*
+   * Initialize pthread information and start the thread.
+   */
+  if ((error = pthread_create(&buf_thread, NULL, buffer_thread, NULL)) < 0) {
+    perror("pthread_create");
+    printf("%d\n", error);
+    exit(1);
+  }
+#endif
+
+  /*
+   * Allocate room for the array of pointers.  We can't use the CREATE
+   * macro here because that uses the array we're trying to make!
+   */
+  set_buffer_head(calloc(ALLOC_RANGE + 1, sizeof(struct buf_data *)));
+  buffer_cache = calloc(CACHE_SIZE, sizeof(struct buf_data *));
+
+  if (buffer_opt & BUF_VERBOSE) {
+    char ibbuf[128];
+    sprintf(ibbuf, "BUF: min_alloc(%d) max_alloc(%d) alloc_range(%d)\n",
+	MIN_ALLOC, MAX_ALLOC, ALLOC_RANGE);
+    log(ibbuf);
+  }
+
+  /*
+   * Put any persistant buffers here.
+   * Ex: new_buffer(8192, BT_PERSIST);
+   */
+
+  unlock_buffers();
+}
+
+#if defined(THREADED)
+/*
+ * Private: decrement_all_buffers()
+ * Reduce the life on all buffers by 1.  This will eventually replace
+ * the functionality of release_all_buffers().
+ */
+void decrement_all_buffers(void)
+{
+  int magnitude;
+  struct buf_data *clear, **head = get_buffer_head();
+
+  for (magnitude = 0; magnitude <= ALLOC_RANGE; magnitude++)
+    for (clear = head[magnitude]; clear; clear = clear->next) {
+      if (clear->life <= 0)
+	continue;
+      clear->life--;
+    }
+}
+
+/*
+ * Private: release_old_buffers()
+ * Check for any used buffers that have no remaining life.
+ */
+void release_old_buffers(void)
+{
+  int magnitude;
+  struct buf_data *relbuf, **head = get_buffer_head();
+
+  for (magnitude = 0; magnitude <= ALLOC_RANGE; magnitude++)
+    for (relbuf = head[magnitude]; relbuf; relbuf = relbuf->next)
+      if (relbuf->type != BT_MALLOC && relbuf->life == 0 && relbuf->used && !LOCKED(relbuf)) {
+        char buf[128];
+	LOCK(relbuf, LOCK_WILL_CLEAR);
+        sprintf(buf, "BUF: %s:%d forgot to release %d bytes in %p.",
+		relbuf->who ? relbuf->who : "UNKNOWN", relbuf->line, relbuf->size, relbuf);
+        log(buf);
+        clear_buffer(relbuf);
+	UNLOCK(relbuf);
+      }
+}
+
+/*
+ * Private: free_old_buffers(void)
+ * Get rid of any old unused buffers.
+ */
+void free_old_buffers(void)
+{
+  int magnitude;
+  struct buf_data *freebuf, *next_free, **head = get_buffer_head();
+
+  lock_buffers(LOCK_CLOSED);
+
+  for (magnitude = 0; magnitude <= ALLOC_RANGE; magnitude++)
+    for (freebuf = head[magnitude]; freebuf; freebuf = next_free) {
+      next_free = freebuf->next;
+      if (!freebuf->used && freebuf->life == 0 && freebuf->type == BT_STACK && !LOCKED(freebuf)) {
+        LOCK(freebuf, LOCK_WILL_REMOVE);
+	remove_buffer(freebuf);
+	LOCK(freebuf, LOCK_WILL_FREE);
+        free_buffer(freebuf);
+      }
+    }
+  unlock_buffers();
+}
+
+#else
+
+/*
+ * Public: release_all_buffers()
+ * Forcibly release all buffers currently allocated.  This is useful to
+ * reclaim any forgotten buffers.  This will need a little bit of work
+ * to be thread safe.
+ * See structs.h for PULSE_BUFFER to change the release rate.
+ */
+void release_all_buffers(void)
+{
+  struct buf_data *clear, *next_clear, **head = get_buffer_head();
+  int magnitude;
+
+  lock_buffers(LOCK_CLOSED);
+
+  for (magnitude = 0; magnitude <= ALLOC_RANGE; magnitude++) {
+    for (clear = head[magnitude]; clear; clear = next_clear) {
+      next_clear = clear->next;
+      if (clear->type != BT_MALLOC && clear->used && clear->life == 0 && !LOCKED(clear)) {
+        char buf[128];
+	LOCK(clear, LOCK_WILL_CLEAR);
+        sprintf(buf, "BUF: %s:%d forgot to release %d bytes.",
+		clear->who, clear->line, clear->size);
+        log(buf);
+        clear_buffer(clear);
+	UNLOCK(clear);
+      } else if (!clear->used && clear->life == 0 && clear->type == BT_STACK && !LOCKED(clear)) {
+	LOCK(clear, LOCK_WILL_REMOVE);
+	remove_buffer(clear);
+	LOCK(clear, LOCK_WILL_FREE);
+        free_buffer(clear);
+      } else
+        clear->life--;
+    }
+  }
+  unlock_buffers();
+}
+
+#endif
+
+/*
+ * Private: remove_buffer(buffer to remove)
+ * Removes a buffer from the list without freeing it.
+ */
+void remove_buffer(struct buf_data *removeme)
+{
+  struct buf_data **head, *traverse, *prev = NULL;
+  int magnitude;
+
+  if (!removeme) {
+    log("BUF: SYSERR: NULL buf_data given to remove_buffer.");
+    return;
+  }
+
+  if (LOCKED(removeme) != LOCK_WILL_REMOVE)
+    log("BUF: SYSERR: remove_buffer: Lock bit not properly set!");
+
+  head = get_buffer_head();
+  magnitude = get_magnitude(removeme->size);
+
+  for (traverse = head[magnitude]; traverse; traverse = traverse->next) {
+    if (traverse == removeme) {
+      lock_buffers(LOCK_CLOSED);
+      if (traverse == head[magnitude])
+	head[magnitude] = traverse->next;
+      else if (prev)
+	prev->next = traverse->next;
+      else
+	log("BUF: SYSERR: remove_buffer: Don't know what to do.");
+      unlock_buffers();
+      if (LOCKED(removeme) != LOCK_WILL_REMOVE)
+	log("BUF: SYSERR: remove_buffer: Lock bit removed during operation!");
+
+      return;
+    }
+    prev = traverse;
+  }
+  log("BUF: SYSERR: remove_buffer: Couldn't find the buffer passed.");
+}
+
+/*
+ * Private: clear_buffer(buffer to clear)
+ * This is used to declare an allocated buffer unused.
+ */
+void clear_buffer(struct buf_data *clearme)
+{
+  if (!clearme) {
+    log("BUF: SYSERR: clear_buffer: NULL argument.");
+    return;
+  }
+
+  if (LOCKED(clearme) != LOCK_WILL_CLEAR)
+    log("BUF: SYSERR: clear_buffer: Lock not properly set!");
+
+  /*
+   * If the magic number we set in acquire_buffer() is not there then
+   * we have a suspected buffer overflow.
+   */
+  if (clearme->data[clearme->req_size] != MAGIC_NUMBER) {
+    char buf[128];
+    sprintf(buf, "BUF: SYSERR: clear_buffer: Overflow in buffer %p from %s:%d (%d/%d).",
+		clearme, clearme->who ? clearme->who : "UNKNOWN", clearme->line, strlen(clearme->data) + 1, clearme->req_size);
+    log(buf);
+    init_buffers();
+    if (buffer_opt & BUF_OVERBOOT || ++buffer_overflow > MAX_OVERFLOW) {
+      send_to_all("Emergency reboot.. come back in a minute or two.\r\n");
+      log("BUF: SYSERR: Emergency reboot, too many buffer corruptions!");
+      circle_shutdown = circle_reboot = 1;
+    } else
+      log("BUF: SYSERR: Buffer list cleared!");
+  } else if (clearme->type == BT_MALLOC) {
+    lock_buffers(LOCK_CLOSED);
+    LOCK(clearme, LOCK_WILL_REMOVE);
+    remove_buffer(clearme);
+    LOCK(clearme, LOCK_WILL_FREE);
+    free_buffer(clearme);
+    unlock_buffers();
+  } else {
+    if (buffer_opt & BUF_CHECK) {
+      char buf[128];
+      /*
+       * If nothing in clearme->data return 0, else if paranoid_buffer, return
+       * the result of get_used(), otherwise just strlen() the buffer.
+       */
+      sprintf(buf, "BUF: %s:%d used %d/%d bytes.",
+		clearme->who, clearme->line, (clearme->data && *clearme->data ?
+		((buffer_opt & BUF_NUKE) ? get_used(clearme) :
+		strlen(clearme->data)) : 0), clearme->req_size);
+      log(buf);
+    }
+    if (buffer_opt & BUF_NUKE)
+      memset(clearme->data, '\0', clearme->size);
+    else
+      *clearme->data = '\0';
+    clearme->who = NULL;
+    clearme->line = 0;
+#if defined(PICKY_BUFFERS)
+    clearme->req_size = 0;
+#endif
+    clearme->life = B_FREELIFE;
+    clearme->used = FALSE;
+  }
+
+  if (LOCKED(clearme) != LOCK_WILL_CLEAR)
+    log("BUF: SYSERR: clear_buffer: Ack! Someone cleared lock bit.");
+}
+
+/*
+ * Public: as release_buffer(buffer data pointer)
+ * Used throughout the code to finish their use of the buffer.
+ */
+int detach_buffer(buffer *data, const char *func, const int line_n)
+{
+  struct buf_data *clear, **b_head;
+  int magnitude;
+
+  if (data == NULL || func == NULL) {
+    log("BUF: SYSERR: detach_buffer: Invalid information passed.");
+    return FALSE;
+  }
+
+/*
+ * This search is useless when we're given the structure already.
+ */
+#if !defined(BUFFER_SNPRINTF)
+  /*
+   * We cache the last allocated buffer to speed up cases where
+   * we allocate a buffer and then free it shortly afterwards.
+   */
+  if (!(clear = in_cache(data))) {
+    if (buffer_opt & BUF_VERBOSE)
+      fprintf(stderr, "(detach_buffer");
+    b_head = get_buffer_head();
+    for (magnitude = 0; magnitude <= ALLOC_RANGE; magnitude++) {
+      if (buffer_opt & BUF_VERBOSE)
+        fprintf(stderr, ") %d(", magnitude);
+      for (clear = b_head[magnitude]; clear; clear = clear->next) {
+	if (buffer_opt & BUF_VERBOSE)
+	  fprintf(stderr, "%p ", clear->data);
+        if (clear->data == data)
+          break;
+      }
+      if (clear) /* Found one. */
+	break;
+    }
+    if (buffer_opt & BUF_VERBOSE)
+      fprintf(stderr, ")\n");
+  }
+#else
+  clear = data;
+#endif
+
+  if (clear == NULL) {
+    char buf[128];
+    sprintf(buf, "BUF: SYSERR: detach_buffer: No such buffer found at %s:%d.", func, line_n);
+    log(buf);
+  } else if (LOCKED(clear)) {
+    char dbbuf[128];
+    if (LOCKED(clear) == LOCK_WILL_FREE)
+      sprintf(dbbuf, "BUF: detach_buffer: Buffer %p slated to be freed.", clear);
+    else if (LOCKED(clear) == LOCK_WILL_CLEAR)
+      sprintf(dbbuf, "BUF: detach_buffer: Buffer %p already being detached.", clear);
+    else if (LOCKED(clear) == LOCK_WILL_REMOVE)
+      sprintf(dbbuf, "BUF: detach_buffer: Buffer %p being removed from list.", clear);
+    else
+      sprintf(dbbuf, "BUF: detach_buffer: Buffer %p already locked.", clear);
+    log(dbbuf);
+  } else if (clear->who == NULL) {
+    char dbbuf[128];
+    sprintf(dbbuf, "BUF: SYSERR: detach_buffer: Buffer %p already released. Used: %d Locked: %d", clear, clear->used, LOCKED(clear));
+    log(dbbuf);
+  } else {
+    LOCK(clear, LOCK_WILL_CLEAR);
+    if (buffer_opt & (BUF_VERBOSE | BUF_DETAIL)) {
+      char buf[128];
+      sprintf(buf, "BUF: %s:%d released %d bytes in %p from %s:%d.",
+		func, line_n, clear->size, clear, clear->who ? clear->who : "UNKNOWN", clear->line);
+      log(buf);
+    }
+    if (lastgive == clear) lastgive = NULL;
+    clear_buffer(clear);
+    UNLOCK(clear);
+    return TRUE;
+  }
+  return FALSE;
+}
+  
+/*
+ * Private: free_buffer(buffer)
+ * Internal function for getting rid of buffers.
+ */
+void free_buffer(struct buf_data *f)
+{
+  char buf[128];
+
+  if (!f) {
+    log("BUF: SYSERR: free_buffer: NULL pointer.");
+    return;
+  } else if (f->type == BT_PERSIST)
+    sprintf(buf, "BUF: SYSERR: free_buffer: Freeing %d byte persistant buffer!", f->size);
+  else
+    sprintf(buf, "BUF: free_buffer: Freeing %d bytes in expired buffer.", f->size);
+  if (f->type != BT_MALLOC)
+    log(buf);
+
+  if (LOCKED(f) != LOCK_WILL_FREE)
+    log("BUF: SYSERR: free_buffer: Lock not properly set!");
+
+  /*
+   * Would be very bad to reuse this buffer after it is free()'d.
+   */
+  remove_from_cache(f);
+
+  if (f->data)
+    really_free(f->data);
+  else
+    log("BUF: SYSERR: free_buffer: Hey, no data?");
+  really_free(f);
+}
+
+/*
+ * Private: new_buffer(size of buffer, type flag)
+ * Finds where it should place the new buffer it's trying to malloc.
+ */
+struct buf_data *new_buffer(size_t size, int type)
+{
+  struct buf_data **buflist, *buft, *potential, *prev = NULL;
+  int magnitude;
+
+  if (size <= 0) {
+    log("BUF: SYSERR: new_buffer: 0 byte (or less) buffer requested.");
+    return NULL;
+  }
+  buflist = get_buffer_head();
+  magnitude = get_magnitude(size);
+
+  /* There aren't any buffers. */
+  if (buflist[magnitude] == NULL) {
+    if (buffer_opt & BUF_VERBOSE)
+      log("BUF: new_buffer: Created the list.");
+    return (buflist[magnitude] = malloc_buffer(size, type));
+  }
+
+  /* Insert a buffer */
+  for (buft = buflist[magnitude]; buft; buft = buft->next) {
+    if (size <= buft->size) {		/* Found where to insert. */
+      potential = malloc_buffer(size, type);
+      potential->next = buft;
+      lock_buffers(LOCK_CLOSED);
+      if (buflist[magnitude] == buft)
+        buflist[magnitude] = potential;
+      else if (prev)
+        prev->next = potential;
+      else {
+	char nbbuf[128];
+	sprintf(nbbuf, "BUF: SYSERR: new_buffer: Oops, didn't insert buffer. (prev:%p, list:%p, pos:%p)",
+		prev, buflist[magnitude], buft);
+	log(nbbuf);
+	free_buffer(potential);
+	return NULL;
+      }
+      unlock_buffers();
+      if (buffer_opt & BUF_VERBOSE)
+	log("BUF: new_buffer: Inserted.");
+      return potential;
+    }
+    prev = buft;
+  }
+
+  /* Append. */
+  if (prev->next)
+    log("BUF: SYSERR: new_buffer: Overwrote a buffer.");
+  if (buffer_opt & BUF_VERBOSE)
+    log("BUF: new_buffer: Appended to list.");
+
+  prev->next = malloc_buffer(size, type);
+  return prev->next;  
+}
+
+/*
+ * Private: malloc_buffer(size of buffer, type flag)
+ * Creates a new buffer for use.
+ */
+struct buf_data *malloc_buffer(size_t size, int type)
+{
+  struct buf_data *new_buf;
+
+  if (!(new_buf = (struct buf_data *)malloc(sizeof(struct buf_data)))) {
+    log("BUF: SYSERR: malloc_buffer: Failed malloc.");
+    perror("malloc_buffer()");
+    return NULL;
+  }
+
+  LOCK(new_buf, LOCK_ACQUIRE);
+  new_buf->data = (char *)malloc(size + 1);
+  new_buf->used = FALSE;
+  new_buf->who = NULL;
+  new_buf->line = 0;
+  new_buf->life = B_FREELIFE;
+  new_buf->type = type;
+  new_buf->next = NULL;
+  new_buf->size = size;
+#if defined(PICKY_BUFFERS)
+  new_buf->req_size = 0;
+#endif
+
+  if (buffer_opt & (BUF_VERBOSE | BUF_DETAIL)) {
+    char buf[128];
+    sprintf(buf, "BUF: malloc_buffer: Allocated %d byte buffer, %d byte overhead.",
+		new_buf->size, sizeof(struct buf_data));
+    log(buf);
+  }
+  if (buffer_opt & BUF_NUKE)
+    memset(new_buf->data, '\0', new_buf->size);
+  else
+    *new_buf->data = '\0';
+
+  return new_buf;
+}
+
+/*
+ * Public: as get_buffer(size of buffer)
+ * Requests a buffer from the free pool.  If a buffer of the desired size
+ * is not available, one is created.
+ */
+buffer *acquire_buffer(size_t size, int type, const char *who, ush_int line)
+{
+  struct buf_data *give = NULL, **head = get_buffer_head();
+  int magnitude;
+
+  /*
+   * I'd like to avoid this lock but it causes the same buffer to be
+   * given out multiple times without it.
+   */
+  lock_buffers(LOCK_CLOSED);
+
+  /*
+   * Search the list for an unused buffer that is large enough.
+   */
+retry:
+  for (magnitude = get_magnitude(size); magnitude <= ALLOC_RANGE; magnitude++)
+    for (give = head[magnitude]; give; give = give->next)
+      if (!give->used && give->size >= size && give->type != BT_MALLOC && !LOCKED(give)) {
+	if (LOCKED(give) != LOCK_NONE)
+	  log("BUF: SYSERR: acquire_buffer: Dammit!");
+	LOCK(give, LOCK_ACQUIRE);
+	unlock_buffers();
+	goto grabbed_buffer;
+      }
+
+  unlock_buffers();
+
+  /*
+   * Everything big enough is being used, create a new one.
+   */
+  if (give == NULL) {
+    if (buffer_opt & (BUF_VERBOSE | BUF_DETAIL)) {
+      char buf[128];
+      sprintf(buf, "BUF: Didn't find %d byte buffer! Making a new one.", size);
+      log(buf);
+    }
+
+    /*
+     * If we don't have a valid pointer by now, we're out of memory so just
+     * return NULL and hope things don't crash too soon.
+     */
+    if ((give = new_buffer(size, FALSE)) == NULL) {
+      char buf[128];
+      sprintf(buf, "BUF: SYSERR: acquire_buffer: Couldn't get %d byte buffer for %s:%d.", size, who, line);
+      log(buf);
+      return NULL;
+    }
+    /* LOCK(give, LOCK_ACQUIRE); - We're already locked in malloc_buffer. */
+  }
+
+grabbed_buffer:
+
+#if defined(THREADED)
+  if (LOCKED(give) != LOCK_ACQUIRE) {
+    log("BUF: SYSERR: acquire_buffer: Someone stole my buffer.");
+    goto retry;
+  }
+#endif
+
+  if (give == lastgive) {
+    char abbuf[128];
+    sprintf(abbuf, "BUF: SYSERR: acquire_buffer: Giving out buffer again to %s:%d.", who, line);
+    log(abbuf);
+    exit(1);
+  }
+  lastgive = give;
+
+  give->used = TRUE;
+  give->who = who;
+  give->line = line;
+  if (type == BT_MALLOC)
+    give->type = BT_MALLOC;
+  give->life = B_GIVELIFE;
+#if defined(PICKY_BUFFERS)
+  give->req_size = size;
+#endif
+  if (buffer_opt & (BUF_VERBOSE | BUF_DETAIL)) {
+    char buf[128];
+    sprintf(buf, "BUF: %s:%d requested %d bytes, received %d in %p.", who, line, size, give->size, give);
+    log(buf);
+  }
+
+  /*
+   * Plant a magic number to see if someone overruns the buffer. If the first
+   * character of the buffer is not NUL then somehow our memory was
+   * overwritten...most likely by someone doing a release_buffer() and
+   * keeping a secondary pointer to the buffer.
+   */
+  give->data[give->req_size] = MAGIC_NUMBER;
+  if (*give->data != '\0') {
+    log("BUF: SYSERR: acquire_buffer: Buffer is not NULL as it ought to be!");
+    *give->data = '\0';
+  }
+
+  add_to_cache(give);	/* Cache this entry. */
+
+  UNLOCK(give);
+  lastgive = give;
+
+#if defined(BUFFER_SNPRINTF)
+  return give;	/* Hope they don't screw with anything. */
+#else
+  return give->data;
+#endif
+}
+
+/*
+ * Public: as 'show buffers'
+ * This is really only useful to see who has lingering buffers around
+ * or if you are curious.  It can't be called in the middle of a
+ * command run by a player so it'll usually show the same thing.
+ * You can call this with a NULL parameter to have it logged at any
+ * time though.
+ */
+void show_buffers(struct char_data *ch)
+{
+  struct buf_data *disp, **head = get_buffer_head();
+  char *buf = get_buffer(MAX_STRING_LENGTH * 4);
+  int i, magnitude;
+  char *buf_type[] = { "Stack", "Persist", "Malloc" };
+
+  for (magnitude = 0; magnitude <= ALLOC_RANGE; magnitude++)
+    for (i = 0, disp = head[magnitude]; disp; disp = disp->next) {
+      sprintf(buf, "%1d #%2d %5d bytes, Life: %5d, Type: %7s, Allocated: %s/%d.\r\n",
+		magnitude, ++i, disp->size, disp->life, buf_type[(int)disp->type],
+		disp->used ? disp->who : "unused", disp->used ? disp->line : 0);
+      if (ch)
+	send_to_char(buf, ch);
+      else
+	log(buf);
+    }
+
+  release_buffer(buf);
+}
+
+ACMD(do_overflow)
+{
+  buffer *buf = get_buffer(130);
+
+  strcpy(buf, "01234567890123489798494561613163164984981916513213216546947894"
+	"78949491613156194898191698132136484321321467897984132132156416879413"
+	"21321654897894651321321564789794446346892656843657843653846578436537");
+
+  release_buffer(buf);
+
+  if (ch)
+    send_to_char("Ok!\r\n", ch);
+}
+
+#if !defined(BUFFER_TEST)
+
+char *BUFFER_FORMAT =
+"buffer (add | delete) size (persistant | temporary)\r\n"
+"buffer verbose - toggle verbose mode.\r\n"
+"buffer paranoid - toggle between memset() or *buf = NUL.\r\n"
+"buffer check - toggle buffer usage checking.\r\n"
+"buffer overflow - toggle immediate reboot on overflow.\r\n";
+
+ACMD(do_buffer)
+{
+  buffer *arg1, *arg2, *arg3;
+  int size, persistant = FALSE;
+
+  /* This looks nifty. */
+  half_chop(argument, (arg1 = get_buffer(MAX_INPUT_LENGTH)), argument);
+  half_chop(argument, (arg2 = get_buffer(MAX_INPUT_LENGTH)), argument);
+  half_chop(argument, (arg3 = get_buffer(MAX_INPUT_LENGTH)), argument);
+
+  if (!*arg1)
+    size = -1;
+  else if (!*arg2 || !*arg3)
+    size = -2;
+  else if ((size = atoi(arg2)) == 0)
+    size = -1;
+  else if (is_abbrev(arg3, "persistant"))
+    persistant = TRUE;
+  else if (is_abbrev(arg3, "temporary"))
+    persistant = FALSE;
+  else
+    persistant = FALSE;
+
+  /* Don't need these now. */
+  release_buffer(arg2);
+  release_buffer(arg3);
+
+  if (size == -1)	/* Oops, error. */
+    send_to_char(BUFFER_FORMAT, ch);
+  else if (size == -2) {	/* -2 means a toggle command. */
+    if (is_abbrev(arg1, "verbose")) {
+      buffer_opt ^= BUF_VERBOSE;
+      send_to_char((buffer_opt & BUF_VERBOSE) ? "Verbose On.\r\n" : "Verbose Off.\r\n", ch);
+    } else if (is_abbrev(arg1, "paranoid")) {
+      buffer_opt ^= BUF_NUKE;
+      send_to_char((buffer_opt & BUF_NUKE) ? "Now paranoid.\r\n" : "No longer paranoid.\r\n", ch);
+    } else if (is_abbrev(arg1, "check")) {
+      buffer_opt ^= BUF_CHECK;
+      send_to_char((buffer_opt & BUF_CHECK) ? "Checking on.\r\n" : "Not checking.\r\n", ch);
+    } else if (is_abbrev(arg1, "overflow")) {
+      buffer_opt ^= BUF_OVERBOOT;
+      send_to_char((buffer_opt & BUF_OVERBOOT) ? "Reboot on overflow.\r\n" : "Will try to keep going.\r\n", ch);
+    } else
+      send_to_char(BUFFER_FORMAT, ch);
+  } else if (is_abbrev(arg1, "delete")) {
+    struct buf_data *toy, **b_head = get_buffer_head();
+    for (toy = b_head[get_magnitude(size)]; toy; toy = toy->next)
+      if (!toy->used && toy->size == size && persistant == toy->type && !LOCKED(toy)) {
+	LOCK(toy, LOCK_WILL_REMOVE);
+	remove_buffer(toy);
+	LOCK(toy, LOCK_WILL_FREE);
+	free_buffer(toy);
+        break;
+      }
+   if (!toy)
+     send_to_char("Not found.\r\n", ch);
+  } else if (is_abbrev(arg1, "add"))
+    new_buffer(size, persistant); /* So easy. :) */
+  else
+    send_to_char(BUFFER_FORMAT, ch);
+
+  release_buffer(arg1);
+}
+#endif
+
+/*
+ * Private: get_used(buffer to search)
+ * Used mainly in when releasing a buffer and check size is set.
+ * Does a backwards search for the first non-NUL character.
+ * Useful for when a function uses a large buffer and then uses
+ * it later for a smaller string, this will always return the
+ * most used value.
+ */
+int get_used(struct buf_data *buf)
+{
+  int cnt = buf->req_size - 1;
+
+  for (; cnt > 0 && buf->data[cnt] == '\0'; cnt--);
+
+  return cnt;
+
+}
+
+#if defined(BUFFER_MEMORY)
+void *debug_calloc(size_t number, size_t size, char *func, int line)
+{
+  return acquire_buffer(number * size, BT_MALLOC, func, line);
+}
+
+void debug_free(void *ptr)
+{
+  release_buffer(ptr);
+  really_free(ptr);
+}
+
+void *debug_realloc(void *ptr, size_t size, const char *func, int line)
+{
+  void *xtra = acquire_buffer(size, BT_MALLOC, func, line);
+  detach_buffer(ptr, func, line);
+  return xtra;
+}
+#endif
+
+#if defined(THREADED)
+/*
+ * Sanity functions.
+ */
+
+/*
+ * Add a function to the waiting queue.
+ */
+void add_to_wait_q(struct wait_q *std)
+{
+  struct wait_q *oldtail;
+
+  if (buflocktail == NULL) {
+    buflocktail = buflockq = std;
+    return;
+  }
+  oldtail = buflocktail;
+  buflocktail = std;
+  oldtail->next = std;
+}
+
+/*
+ * Remove item from the lock waiting queue.
+ */
+void remove_from_wait_q(const char *func, int line)
+{
+  struct wait_q *remove = buflockq;
+
+  if (strcmp(func, buflockq->func) != 0)
+    log("BUF: SYSERR: remove_from_wait_q: Ack! Removing wrong function.");
+
+  buflockq = buflockq->next;
+  if (buflockq == NULL)
+    buflocktail = NULL;
+  really_free(remove);
+}
+
+void bufferlist_lock(int type, const char *func, ush_int line)
+{
+  struct wait_q *bufwait = (struct wait_q *)malloc(sizeof(struct wait_q));
+  bufwait->line = line;
+  bufwait->type = type;
+  bufwait->func = func;
+  bufwait->next = NULL;
+  add_to_wait_q(bufwait);
+
+  if (buflockq != bufwait /* && buflockq->type > bufwait->type */ ) {
+    if (buffer_opt & (BUF_VERBOSE | BUF_DETAIL)) {
+      char blbuf[128];
+      sprintf(blbuf, "BUF: %s:%d:%p waiting on lock by %s:%d:%p.", func, line, bufwait, buflockq->func, buflockq->line, buflockq);
+      log(blbuf);
+    }
+    while (buflockq != bufwait /* && buflockq->type > bufwait->type */ )
+      sleep(1);
+    if (buffer_opt & BUF_VERBOSE) {
+      char blbuf[128];
+      sprintf(blbuf, "BUF: %s:%d:%p grabbed buffer lock.", func, line, bufwait);
+      log(blbuf);
+    }
+  }
+}
+
+void bufferlist_unlock(const char *func, ush_int line)
+{
+  remove_from_wait_q(func, line);
+}
+
+void buffer_lock(struct buf_data *buf, int type, const char *func, ush_int line)
+{
+  if (buf == NULL) {
+    char blbuf[128];
+    sprintf(blbuf, "BUF: SYSERR: buffer_lock: buf == NULL from %s:%d", func, line);
+    log(blbuf);
+  } else if (LOCKED(buf) != LOCK_NONE && LOCKED(buf) != LOCK_WILL_REMOVE && type != LOCK_WILL_FREE) {
+    char blbuf[128];
+    sprintf(blbuf, "BUF: SYSERR: buffer_lock: Trying to lock a buffer already locked, from %d to %d at %s:%d.", LOCKED(buf), type, func, line);
+    log(blbuf);
+  } else
+    buf->locked = type;
+}
+
+void buffer_unlock(struct buf_data *buf, const char *func, ush_int line)
+{
+  if (buf == NULL) {
+    char bubuf[128];
+    sprintf(bubuf, "BUF: SYSERR: buffer_unlock: buf == NULL from %s:%d.", func, line);
+    log(bubuf);
+  } else if (LOCKED(buf) == LOCK_NONE) {
+    char bubuf[128];
+    sprintf(bubuf, "BUF: SYSERR: buffer_unlock: Buffer %p isn't locked, from %s:%d.", buf, func, line);
+    log(bubuf);
+  } else
+    buf->locked = LOCK_NONE;
+}
+
+/*
+ * Public: buffer_thread()
+ * If we ever have a multithreaded base, this would be a very nice
+ * application for it.  I plan to add a timer on how long someone
+ * has used a buffer.
+ *
+ * Work in progress.
+ */
+void *buffer_thread(void *nothing)
+{
+  log("BUF: Started buffer thread.");
+
+  while (!circle_shutdown) {
+    /* This is a generic function to reduce the life on all buffers by 1. */
+    decrement_all_buffers();
+
+    /* This checks for any buffers which were never released. */
+    release_old_buffers();
+
+    /* Here we free() any buffer which has not been used in a while. */
+    free_old_buffers();
+
+    /* that gettimeofday() stuff is too complicated. */
+    sleep((PULSE_BUFFER / PASSES_PER_SEC));
+
+    pthread_testcancel();
+  }
+
+  log("BUF: Buffer thread exited.");
+  return NULL;
+}
+#endif
+
+#if defined(BUFFER_SNPRINTF)
+/*
+ * Buffer using sprintf() with bounds checking via snprintf()
+ */
+int bprintf(buffer *str, const char *format, ...)
+{
+  va_list args;
+  int chars;
+
+  va_start(args, format);
+  chars = vsnprintf(str->data, str->size, args);
+  va_end(args);
+  return chars;
+}
+
+/*
+ * Buffer wrapper.
+ */
+char *b2bcpy(buffer *str1, buffer *str2) { strcpy(str1->data, str2->data); }
+char *s2bcpy(buffer *str1, const char *str2) { strcpy(str1->data, str2); }
+char *b2scpy(char *str1, const buffer *str2) { strcpy(str1, str2->data; )
+char *bufcat(buffer *str1, const char *str2) { strcat(str1->data, str2); }
+#endif
+
+#if defined(BUFFER_MEMORY)
+#undef free
+void really_free(void *ptr) { free(ptr); }
+#endif
diff -uprN -x *.o ../stk/buffer.h ./buffer.h
--- ../stk/buffer.h	Wed Dec 31 19:00:00 1969
+++ ./buffer.h	Mon Dec 15 23:56:16 1997
@@ -0,0 +1,138 @@
+#if !defined(_BUFFER_H_)
+#define _BUFFER_H_
+
+/* Do NOT define this. */
+/* #define BUFFER_TEST	1 */
+
+/*
+ * #if 1 = use buffer system for memory allocations. (not done, don't use)
+ * #if 0 = use standard calloc/realloc
+ */
+#if 0
+#define BUFFER_MEMORY	1
+#endif
+
+/*
+ * #if 1 = use a threaded buffer system. (You must have pthreads.)
+ * #if 0 = use the standard heartbeat() method.
+ */
+#if 1
+#define THREADED	1
+#endif
+
+/*
+ * #if 1 = return a pointer to the buffer structures
+ * #if 0 = return only the data buffer (define this or all hell will break)
+ */
+#if 0
+#define BUFFER_SNPRINTF	1
+typedef struct buf_data buffer;
+#else
+typedef char buffer;
+#endif
+
+/*
+ * #if 1 = Include original CircleMUD buffers too.
+ * #if 0 = Use only new buffer system.
+ */
+#if 1
+#define USE_CIRCLE_BUFFERS 1
+#endif
+
+/*
+ * #if 1 = maintain a variable of how large a buffer the function requested.
+ *      This will keep better track of buffer overruns when we give them a
+ *      bigger buffer than requested.  An overrun with this on does not
+ *      necessarily mean anything has been corrupted, but it does mean that
+ *      it will happen and you have a serious problem. (recommended)
+ * #if 0 = save sizeof(int) bytes per buffer structure and only check for
+ *      overruns that corrupt memory past the buffer and do bad things.
+ *
+ * I'm thinking of removing this in favor of always being picky.
+ */
+#if 1
+#define PICKY_BUFFERS   1
+#else
+#define req_size	size
+#endif
+
+/* *** No tweakables below *** */
+
+/*
+ * Handle GCC-isms.
+ */
+#if !defined(__GNUC__)
+#define __attribute__(x)
+#define __FUNCTION__	__FILE__
+#endif
+
+/*
+ * Some macros to imitate C++ class styles. release_buffer() automatically
+ * NULL's a pointer to prevent further use.
+ */
+#define get_buffer(a)		acquire_buffer((a), BT_STACK, __FUNCTION__, __LINE__)
+#define release_buffer(a)	do { detach_buffer((a), __FUNCTION__, __LINE__); (a) = NULL; } while(0)
+#define release_my_buffers()	detach_my_buffers(__FUNCTION__, __LINE__)
+
+/*
+ * Types for the memory to allocate.
+ */
+#define BT_STACK	0	/* Stack type memory			*/
+#define BT_PERSIST	1	/* A buffer that doesn't time out	*/
+#define BT_MALLOC	2	/* A malloc() implementation		*/
+
+#define PULSE_BUFFER	(5 RL_SEC)
+
+/*
+ * Assorted lock types.
+ */
+#define LOCK_NONE	0
+#define LOCK_OPEN	0
+#define LOCK_RO		1
+#define LOCK_CLOSED	2
+#define LOCK_ACQUIRE	9
+#define LOCK_WILL_CLEAR	10
+#define LOCK_WILL_FREE	11
+#define LOCK_WILL_REMOVE	12
+
+/*
+ * Public functions for outside use.
+ */
+#if defined(BUFFER_SNPRINTF)
+buffer *str_cpy(buffer *d, buffer*s);
+int bprintf(buffer *buf, const char *format, ...);
+#endif
+#if defined(BUFFER_MEMORY)
+void *debug_calloc(size_t number, size_t size, char *func, int line);
+void *debug_realloc(void *ptr, size_t size, const char *func, int line);
+void debug_free(void *ptr);
+#endif
+void init_buffers(void);
+void exit_buffers(void);
+void release_all_buffers(void);
+int detach_buffer(buffer *data, const char *func, const int line_n);
+void detach_my_buffers(const char *func, const int line_n);
+buffer *acquire_buffer(size_t size, int type, const char *who, ush_int line);
+void show_buffers(struct char_data *ch);
+
+extern int buffer_cache_hits;
+extern int buffer_cache_misses;
+
+#if defined(BUFFER_SNPRINTF) || defined(_BUFFER_C_)
+struct buf_data {
+  bool locked;		/* Don't touch this buffer.		*/
+  bool used;            /* Is someone using this buffer?        */
+  byte type;		/* What type of buffer are we?		*/
+  size_t size;          /* How large is this buffer?            */
+  ush_int line;         /* What source code line is using this. */
+  sh_int life;          /* An idle counter to free unused ones. */
+#if defined(PICKY_BUFFERS)
+  sh_int req_size;      /* How much did the function request?   */
+#endif
+  char *data;           /* The buffer passed back to functions. */
+  const char *who;      /* Name of the function using this.     */
+  struct buf_data *next;        /* The next structure.          */
+};
+#endif
+
+#endif
diff -uprN -x *.o ../stk/buffer.txt ./buffer.txt
--- ../stk/buffer.txt	Wed Dec 31 19:00:00 1969
+++ ./buffer.txt	Wed Nov 26 15:39:16 1997
@@ -0,0 +1,70 @@
+				OVERVIEW
+
+Since the buffer system is really different from the current CircleMUD
+system, this file will help get you started with how to use it. 
+
+char *get_buffer(int size)
+	- You pass it a number, it will pass you a pointer to a buffer
+	- of the correct size.
+void release_buffer(char *buffer)
+	- When you are done with the buffer obtained by get_buffer(), pass
+	- it as the argument to release_buffer() so it is 'freed'.
+void release_my_buffers()
+	- Will release all buffers currently associated with the function
+	- that calls this or all buffers in the file in Windows.  Because
+	- of clearing all buffers in the file, this function is _not_
+	- recommended to be used unless absolutely necessary.  A separate
+	- call to release_buffer() for every buffer is preferred.
+
+				EXAMPLE
+
+ACMD(do_hi)
+{
+  char *buf = get_buffer(128);
+
+  sprintf(buf, "Hello, %s.\r\n", GET_NAME(ch));
+  send_to_char(buf);
+
+  release_buffer(buf);
+}
+
+If you forget to call release_buffer() on a buffer, it will time out in 10
+seconds and a notification message will be printed in the logs.  Any
+buffers that are not marked 'persistant' will be free()'d if not used for
+5 minutes.
+
+			CONFIGURABLE OPTIONS
+
+There are _many_ configurable options in buffer.c so take a look.  If you
+wish to still have the CircleMUD global buffers, take a look at buffer.h
+for the correct #define statement.  The only other option is in structs.h,
+PULSE_BUFFER defines how often the buffer list is checked for forgotten
+buffers. 
+
+			THE 'buffer' COMMAND
+
+Syntax: buf[fer] ( a[dd] | d[elete] ) size ( t[emporary] | p[ersistant] )
+
+So: buffer add 8192 persistant - creates an 8k buffer that won't time out.
+    buf a 8192 p	- does the same as above.
+
+ADD:
+
+The add function can be used to create new buffers of the specified size
+in the buffer chain.  Temporary buffers will be destroyed if they are not
+used in 5 minutes but persistant buffers will never do away unless
+explicitly killed by the delete function. 
+
+DELETE:
+
+The delete function will destroy any unused buffer in the chain that
+matches the size and type (temporary or persistant) specified on the
+command line.  This is useful to free up memory if too many buffers are
+around.
+
+			THE 'crash' COMMAND
+
+It causes a buffer overflow to test the detection code.  You probably do
+not want to use it too often. 
+
+-George Greer 8/20/97
diff -uprN -x *.o ../stk/castle.c ./castle.c
--- ../stk/castle.c	Fri Apr 12 23:39:21 1996
+++ ./castle.c	Wed Nov 26 14:52:19 1997
@@ -12,8 +12,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/class.c ./class.c
--- ../stk/class.c	Wed Oct 29 00:16:22 1997
+++ ./class.c	Wed Nov 26 19:51:43 1997
@@ -21,6 +21,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "db.h"
 #include "utils.h"
 #include "spells.h"
diff -uprN -x *.o ../stk/comm.c ./comm.c
--- ../stk/comm.c	Wed Oct 29 17:04:08 1997
+++ ./comm.c	Wed Nov 26 15:51:23 1997
@@ -43,6 +43,7 @@
 /* Note, includes for UNIX are in sysdep.h */
 
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
@@ -77,7 +78,6 @@ extern char help[];
 
 /* local globals */
 struct descriptor_data *descriptor_list = NULL;		/* master desc list */
-struct txt_block *bufpool = 0;	/* pool of large output buffers */
 int buf_largecount = 0;		/* # of large buffers which exist */
 int buf_overflows = 0;		/* # of overflows of output */
 int buf_switches = 0;		/* # of switches from small to large buf */
@@ -166,6 +166,8 @@ int main(int argc, char **argv)
   int pos = 1;
   char *dir;
 
+  init_buffers();
+
   port = DFLT_PORT;
   dir = DFLT_DIR;
 
@@ -237,6 +239,8 @@ int main(int argc, char **argv)
     init_game(port);
   }
 
+  exit_buffers();
+
   return 0;
 }
 
@@ -689,6 +693,12 @@ void heartbeat(int pulse)
 {
   static int mins_since_crashsave = 0;
 
+#if !defined(THREADED)
+  /* Clear out all the global buffers now in case someone forgot. */
+  if (!(pulse % PULSE_BUFFER))
+    release_all_buffers();
+#endif
+
   if (!(pulse % PULSE_ZONE))
     zone_update();
 
@@ -925,10 +935,9 @@ void flush_queues(struct descriptor_data
 {
   int dummy;
 
-  if (d->large_outbuf) {
-    d->large_outbuf->next = bufpool;
-    bufpool = d->large_outbuf;
-  }
+  if (d->large_outbuf)
+    release_buffer(d->large_outbuf);
+
   while (get_from_q(&d->input, buf2, &dummy));
 }
 
@@ -961,22 +970,14 @@ void write_to_output(const char *txt, st
   }
   buf_switches++;
 
-  /* if the pool has a buffer in it, grab it */
-  if (bufpool != NULL) {
-    t->large_outbuf = bufpool;
-    bufpool = bufpool->next;
-  } else {			/* else create a new one */
-    CREATE(t->large_outbuf, struct txt_block, 1);
-    CREATE(t->large_outbuf->text, char, LARGE_BUFSIZE);
-    buf_largecount++;
-  }
-
-  strcpy(t->large_outbuf->text, t->output);	/* copy to big buffer */
-  t->output = t->large_outbuf->text;	/* make big buffer primary */
-  strcat(t->output, txt);	/* now add new text */
-
-  /* set the pointer for the next write */
-  t->bufptr = strlen(t->output);
+  /*
+   * Just request the buffer. Copy the contents of the old, and make it
+   * the primary buffer.
+   */
+  t->large_outbuf = get_buffer(LARGE_BUFSIZE);
+  strcpy(t->large_outbuf, t->output);
+  t->output = t->large_outbuf;
+  strcat(t->output, txt);
 
   /* calculate how much space is left in the buffer */
   t->bufspace = LARGE_BUFSIZE - 1 - t->bufptr;
@@ -1159,9 +1160,7 @@ int process_output(struct descriptor_dat
    * and switch back to the small one
    */
   if (t->large_outbuf) {
-    t->large_outbuf->next = bufpool;
-    bufpool = t->large_outbuf;
-    t->large_outbuf = NULL;
+    release_buffer(t->large_outbuf);
     t->output = t->small_outbuf;
   }
   /* reset total bufspace back to that of a small buffer */
Binary files ../stk/core and ./core differ
diff -uprN -x *.o ../stk/db.c ./db.c
--- ../stk/db.c	Wed Oct 29 00:16:24 1997
+++ ./db.c	Wed Nov 26 14:52:48 1997
@@ -13,8 +13,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "db.h"
 #include "comm.h"
diff -uprN -x *.o ../stk/fight.c ./fight.c
--- ../stk/fight.c	Wed Oct 29 00:16:24 1997
+++ ./fight.c	Wed Nov 26 14:52:54 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "handler.h"
diff -uprN -x *.o ../stk/graph.c ./graph.c
--- ../stk/graph.c	Fri Apr 12 23:39:21 1996
+++ ./graph.c	Wed Nov 26 14:53:03 1997
@@ -19,8 +19,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/handler.c ./handler.c
--- ../stk/handler.c	Wed Oct 29 00:16:25 1997
+++ ./handler.c	Wed Nov 26 14:53:09 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "db.h"
diff -uprN -x *.o ../stk/house.c ./house.c
--- ../stk/house.c	Wed Oct 29 00:16:26 1997
+++ ./house.c	Wed Nov 26 14:53:16 1997
@@ -11,9 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
-
 #include "structs.h"
+#include "buffer.h"
 #include "comm.h"
 #include "handler.h"
 #include "db.h"
diff -uprN -x *.o ../stk/interpreter.c ./interpreter.c
--- ../stk/interpreter.c	Wed Oct 29 00:16:27 1997
+++ ./interpreter.c	Wed Nov 26 15:56:09 1997
@@ -14,6 +14,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "comm.h"
 #include "interpreter.h"
 #include "db.h"
@@ -60,6 +61,7 @@ ACMD(do_at);
 ACMD(do_backstab);
 ACMD(do_ban);
 ACMD(do_bash);
+ACMD(do_buffer);
 ACMD(do_cast);
 ACMD(do_color);
 ACMD(do_commands);
@@ -228,6 +230,7 @@ const struct command_info cmd_info[] = {
   { "burp"     , POS_RESTING , do_action   , 0, 0 },
   { "buy"      , POS_STANDING, do_not_here , 0, 0 },
   { "bug"      , POS_DEAD    , do_gen_write, 0, SCMD_BUG },
+  { "buffer"   , POS_DEAD    , do_buffer   , LVL_IMPL, 0 },
 
   { "cast"     , POS_SITTING , do_cast     , 1, 0 },
   { "cackle"   , POS_RESTING , do_action   , 0, 0 },
diff -uprN -x *.o ../stk/limits.c ./limits.c
--- ../stk/limits.c	Wed Oct 29 00:16:27 1997
+++ ./limits.c	Wed Nov 26 14:53:28 1997
@@ -12,6 +12,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "spells.h"
 #include "comm.h"
diff -uprN -x *.o ../stk/magic.c ./magic.c
--- ../stk/magic.c	Wed Oct 29 00:16:27 1997
+++ ./magic.c	Wed Nov 26 14:53:33 1997
@@ -13,6 +13,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "spells.h"
diff -uprN -x *.o ../stk/mail.c ./mail.c
--- ../stk/mail.c	Fri Apr 12 23:39:21 1996
+++ ./mail.c	Wed Nov 26 14:53:40 1997
@@ -17,8 +17,8 @@ Written by Jeremy Elson (jelson@cs.jhu.e
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "db.h"
diff -uprN -x *.o ../stk/mobact.c ./mobact.c
--- ../stk/mobact.c	Wed Oct 29 00:16:27 1997
+++ ./mobact.c	Wed Nov 26 14:53:45 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "db.h"
 #include "comm.h"
diff -uprN -x *.o ../stk/modify.c ./modify.c
--- ../stk/modify.c	Wed Oct 29 00:16:28 1997
+++ ./modify.c	Wed Nov 26 14:53:50 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "interpreter.h"
 #include "handler.h"
diff -uprN -x *.o ../stk/objsave.c ./objsave.c
--- ../stk/objsave.c	Wed Oct 29 00:16:28 1997
+++ ./objsave.c	Wed Nov 26 14:53:57 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "comm.h"
 #include "handler.h"
 #include "db.h"
diff -uprN -x *.o ../stk/olc.c ./olc.c
--- ../stk/olc.c	Wed Oct 29 17:04:08 1997
+++ ./olc.c	Wed Nov 26 14:54:03 1997
@@ -18,6 +18,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/shop.c ./shop.c
--- ../stk/shop.c	Wed Oct 29 00:16:28 1997
+++ ./shop.c	Wed Nov 26 14:54:13 1997
@@ -16,6 +16,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "comm.h"
 #include "handler.h"
 #include "db.h"
diff -uprN -x *.o ../stk/spec_assign.c ./spec_assign.c
--- ../stk/spec_assign.c	Fri Apr 12 23:39:22 1996
+++ ./spec_assign.c	Wed Nov 26 14:54:18 1997
@@ -12,6 +12,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "db.h"
 #include "interpreter.h"
 #include "utils.h"
diff -uprN -x *.o ../stk/spec_procs.c ./spec_procs.c
--- ../stk/spec_procs.c	Fri Apr 12 23:39:22 1996
+++ ./spec_procs.c	Wed Nov 26 14:54:26 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "interpreter.h"
diff -uprN -x *.o ../stk/spell_parser.c ./spell_parser.c
--- ../stk/spell_parser.c	Wed Oct 29 00:16:29 1997
+++ ./spell_parser.c	Wed Nov 26 14:54:32 1997
@@ -12,8 +12,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "interpreter.h"
 #include "spells.h"
diff -uprN -x *.o ../stk/spells.c ./spells.c
--- ../stk/spells.c	Wed Oct 29 00:16:29 1997
+++ ./spells.c	Wed Nov 26 14:54:37 1997
@@ -13,6 +13,7 @@
 #include "sysdep.h"
 
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "spells.h"
diff -uprN -x *.o ../stk/structs.h ./structs.h
--- ../stk/structs.h	Wed Oct 29 00:16:29 1997
+++ ./structs.h	Wed Nov 26 15:45:48 1997
@@ -910,7 +910,7 @@ struct descriptor_data {
    char *output;		/* ptr to the current output buffer	*/
    int  bufptr;			/* ptr to end of current output		*/
    int	bufspace;		/* space left in the output buffer	*/
-   struct txt_block *large_outbuf; /* ptr to large buffer, if we need it */
+   char *large_outbuf;		/* ptr to large buffer, if we need it	*/
    struct txt_q input;		/* q of unprocessed input		*/
    struct char_data *character;	/* linked to char			*/
    struct char_data *original;	/* original char if switched		*/
diff -uprN -x *.o ../stk/thread.c ./thread.c
--- ../stk/thread.c	Wed Dec 31 19:00:00 1969
+++ ./thread.c	Mon Dec 15 23:40:25 1997
@@ -0,0 +1,101 @@
+/*
+ * thread.c - Testing stub for buffer.c
+ * Copyright 1997, George Greer
+ */
+
+#include "conf.h"
+#include "sysdep.h"
+#include <pthread.h>
+#include "structs.h"
+#include "buffer.h"
+#include "utils.h"
+
+void _thr_main() {}
+
+long random();
+void send_to_all(char *t) { printf("%s", t); }
+void send_to_char(char *t, struct char_data *ch) { printf("%s", t); }
+int MIN(int a, int b) { return a < b ? a : b; }
+int MAX(int a, int b) { return a > b ? a : b; }
+int number(int from, int to) { return ((random() % (to - from + 1)) + from); }
+
+int circle_shutdown = 0;
+int circle_reboot = 0;
+
+void log(char *str)
+{
+  time_t ct;
+  char *tmstr;
+
+  ct = time(0);
+  tmstr = asctime(localtime(&ct));
+  *(tmstr + strlen(tmstr) - 1) = '\0';
+  fprintf(stdout, "%-15.15s :: %s\n", tmstr + 4, str);
+  fflush(stdout);
+}
+
+void *thread(void *hi)
+{
+  FILE *dn;
+  int i;
+  char *tbuf, backup[128];;
+
+  sleep(1);
+  for (i = 0; i < INT_MAX; i++) {
+    tbuf = get_buffer(number(21,3000));
+    strcpy(tbuf, "12345678901234567890");
+    sprintf(tbuf, "%d ", i);
+    strcpy(backup, tbuf);
+    dn = fopen("/dev/null", "w");
+    fprintf(dn, "%s", tbuf);
+    fclose(dn);
+    if (strcmp(backup, tbuf)) { /* different */
+      sprintf(backup, "thread on %d: Someone changed my buffer!", i);
+      log(backup);
+    }
+    release_buffer(tbuf);
+    if (circle_shutdown)
+      return NULL;
+  }
+  log("thread: done.");
+  return NULL;
+}
+
+#define NUM_THREADS	60
+
+int main(void)
+{
+  int i;
+  char *mbuf;
+  pthread_t thread_id[NUM_THREADS];
+  extern ush_int buffer_opt;
+
+  buffer_opt |= (1 << 2);
+//  buffer_opt |= (1 << 4);
+
+  log("main: init_buffers();");
+  init_buffers();
+  sleep(1);
+
+  log("main: starting threads.");
+  for (i = 0; i < NUM_THREADS; i++) {
+    printf("%d ", i);
+    if (pthread_create(&thread_id[i], NULL, thread, NULL) < 0)
+      log("thread: Failed thread creation.");
+  }
+  printf("\n");
+
+  sleep(5);
+
+  log("main: waiting...");
+  for (i = 0; i < NUM_THREADS; i++)
+    pthread_join(thread_id[i], NULL);
+  circle_shutdown = 1;
+  log("main: done.");
+
+  sleep(5);
+
+  log("main: exit_buffers()");
+  exit_buffers();
+  return 0;
+}
diff -uprN -x *.o ../stk/utils.c ./utils.c
--- ../stk/utils.c	Wed Oct 29 00:16:30 1997
+++ ./utils.c	Wed Nov 26 14:54:42 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "screen.h"
diff -uprN -x *.o ../stk/utils.h ./utils.h
--- ../stk/utils.h	Wed Oct 29 17:04:08 1997
+++ ./utils.h	Sat Dec  6 21:34:24 1997
@@ -125,6 +125,19 @@ void	update_pos(struct char_data *victim
 /* memory utils **********************************************************/
 
 
+#if defined(BUFFER_MEMORY)
+#define CREATE(result, type, number)  do {\
+	if (!((result) = (type *) debug_calloc ((number), sizeof(type), __FUNCTION__, __LINE__)))\
+		{ perror("malloc failure"); abort(); } } while(0)
+
+#define RECREATE(result,type,number) do {\
+	if (!((result) = (type *) debug_realloc ((result), sizeof(type) * (number), __FUNCTION__, __LINE__)))\
+		{ perror("realloc failure"); abort(); } } while(0)
+
+#define free(variable)	debug_free((variable))
+
+#else
+
 #define CREATE(result, type, number)  do {\
 	if (!((result) = (type *) calloc ((number), sizeof(type))))\
 		{ perror("malloc failure"); abort(); } } while(0)
@@ -132,6 +145,9 @@ void	update_pos(struct char_data *victim
 #define RECREATE(result,type,number) do {\
   if (!((result) = (type *) realloc ((result), sizeof(type) * (number))))\
 		{ perror("realloc failure"); abort(); } } while(0)
+
+#define really_free(variable) free((variable))
+#endif
 
 /*
  * the source previously used the same code in many places to remove an item
diff -uprN -x *.o ../stk/weather.c ./weather.c
--- ../stk/weather.c	Fri Apr 12 23:39:22 1996
+++ ./weather.c	Wed Nov 26 14:54:49 1997
@@ -11,8 +11,8 @@
 #include "conf.h"
 #include "sysdep.h"
 
-
 #include "structs.h"
+#include "buffer.h"
 #include "utils.h"
 #include "comm.h"
 #include "handler.h"
