[eggheads-patches] PATCH1.5: tcl_hash_overhaul.patch

Fabian Knittel fknittel at gmx.de
Mon Oct 23 16:32:00 CST 2000


[ tcl_hash_overhaul.patch ]

This patch cleans up the bind removal mess. Tcl procs can now
remove binds from bind-triggered procs as much as they want,
eggdrop won't crash anymore.

Instead of directly de-allocating the bind table's memory, we
mark it as `deleted' and delete it in the garbage collect routine
in eggdrop's main loop.

Fabian

--
Fabian Knittel <fknittel at gmx.de> -- http://www.esc-web.de/fabian/
Signed or encrypted mail preferred.    PGP DSA key ID: 0x838B4D20
-------------- next part --------------
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/doc/UPDATES1.5 eggdrop1.5/doc/UPDATES1.5
--- eggdrop1.5~/doc/UPDATES1.5	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/doc/UPDATES1.5	Mon Oct 23 23:17:28 2000
@@ -4,6 +4,9 @@
 
 1.5.5
 Found by  Fixed by  What...
+          Fabian    Don't actually delete the bind structures immediately, use
+                    centralised garbage collector instead. Cleaned up various
+                    aspects of the bind list handling.
 Sup       Fabian    Don't insist on proper domainname during hostname detection.
 Sup       Fabian    Properly call PART bind when removing channel and the bot
                     will therefore leave the channel shortly. Also slightly
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/dcc.c eggdrop1.5/src/dcc.c
--- eggdrop1.5~/src/dcc.c	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/dcc.c	Mon Oct 23 23:10:57 2000
@@ -420,18 +420,15 @@
     msg++;
   } else
     msg = "";
-  f = 0;
-  i = 0;
-  while ((C_bot[i].name != NULL) && (!f)) {
+  for (f = i = 0; C_bot[i].name && !f; i++) {
     int y = egg_strcasecmp(code, C_bot[i].name);
 
     if (y == 0) {
       /* Found a match */
-      (C_bot[i].func) (idx, msg);
+      (C_bot[i].func)(idx, msg);
       f = 1;
     } else if (y < 0)
       return;
-    i++;
   }
 }
 
@@ -1764,21 +1761,27 @@
 
 static void dcc_script(int idx, char *buf, int len)
 {
-  void *old = NULL;
-  long oldsock = dcc[idx].sock;
+  long oldsock;
 
   strip_telnet(dcc[idx].sock, buf, &len);
-  if (!len)
+  if (len == 0)
     return;
+
   dcc[idx].timeval = now;
+  oldsock = dcc[idx].sock;	/* Remember the socket number.	*/
   if (call_tcl_func(dcc[idx].u.script->command, dcc[idx].sock, buf)) {
+    void *old_other = NULL;
+
     Context;
-    if ((dcc[idx].sock != oldsock) || (idx>max_dcc))
-      return; /* drummer: this happen after killdcc */
-    old = dcc[idx].u.script->u.other;
+    /* Check whether the socket and dcc entry are still valid. They
+       might have been killed by `killdcc'. */
+    if (dcc[idx].sock != oldsock || idx > max_dcc)
+      return;
+
+    old_other = dcc[idx].u.script->u.other;
     dcc[idx].type = dcc[idx].u.script->type;
     nfree(dcc[idx].u.script);
-    dcc[idx].u.other = old;
+    dcc[idx].u.other = old_other;
     if (dcc[idx].type == &DCC_SOCKET) {
       /* Kill the whole thing off */
       killsock(dcc[idx].sock);
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/flags.c eggdrop1.5/src/flags.c
--- eggdrop1.5~/src/flags.c	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/flags.c	Mon Oct 23 22:55:23 2000
@@ -327,12 +327,12 @@
   return '-';
 }
 
-void break_down_flags(char *string, struct flag_record *plus,
+void break_down_flags(const char *string, struct flag_record *plus,
 		      struct flag_record *minus)
 {
-  struct flag_record *which = plus;
-  int mode = 0;			/* 0 = glob, 1 = chan, 2 = bot */
-  int flags = plus->match;
+  struct flag_record	*which = plus;
+  int			 mode = 0;	/* 0 = glob, 1 = chan, 2 = bot */
+  int			 flags = plus->match;
 
   if (!(flags & FR_GLOBAL)) {
     if (flags & FR_BOT)
@@ -604,7 +604,7 @@
 }
 
 void set_user_flagrec(struct userrec *u, struct flag_record *fr,
-		      char *chname)
+		      const char *chname)
 {
   struct chanuserrec *cr = NULL;
   int oldflags = fr->match;
@@ -656,7 +656,7 @@
 /* Always pass the dname (display name) to this function for chname <cybah>
  */
 void get_user_flagrec(struct userrec *u, struct flag_record *fr,
-		      char *chname)
+		      const char *chname)
 {
   struct chanuserrec *cr = NULL;
 
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/flags.h eggdrop1.5/src/flags.h
--- eggdrop1.5~/src/flags.h	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/flags.h	Mon Oct 23 22:55:23 2000
@@ -177,9 +177,9 @@
 
 #ifndef MAKING_MODS
 
-void get_user_flagrec(struct userrec *, struct flag_record *, char *);
-void set_user_flagrec(struct userrec *, struct flag_record *, char *);
-void break_down_flags(char *, struct flag_record *, struct flag_record *);
+void get_user_flagrec(struct userrec *, struct flag_record *, const char *);
+void set_user_flagrec(struct userrec *, struct flag_record *, const char *);
+void break_down_flags(const char *, struct flag_record *, struct flag_record *);
 int build_flags(char *, struct flag_record *, struct flag_record *);
 int flagrec_eq(struct flag_record *, struct flag_record *);
 int flagrec_ok(struct flag_record *, struct flag_record *);
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/main.c eggdrop1.5/src/main.c
--- eggdrop1.5~/src/main.c	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/main.c	Mon Oct 23 22:55:23 2000
@@ -654,6 +654,16 @@
   sprintf(&egg_xtra[strlen(egg_xtra)], " %s", str);
 }
 
+static inline void garbage_collect(void)
+{
+  static u_8bit_t	run_cnt = 0;
+
+  if (run_cnt == 3)
+    garbage_collect_tclhash();
+  else
+    run_cnt++;
+}
+
 int main(int argc, char **argv)
 {
   int xx, i;
@@ -883,6 +893,7 @@
     /* Process a single tcl event */
     Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
 #endif
+
     /* Lets move some of this here, reducing the numer of actual
      * calls to periodic_timers
      */
@@ -892,20 +903,27 @@
       call_hook(HOOK_SECONDLY);
       then = now;
     }
+
     Context;
-    /* Only do this every so often */
+    /* Only do this every so often. */
     if (!socket_cleanup) {
+      socket_cleanup = 5;
+
+      /* Remove dead dcc entries. */
       dcc_remove_lost();
-      /* Check for server or dcc activity */
+
+      /* Check for server or dcc activity. */
       dequeue_sockets();
-      socket_cleanup = 5;
     } else
       socket_cleanup--;
+
+    /* Free unused structures. */
+    garbage_collect();
+
     xx = sockgets(buf, &i);
     if (xx >= 0) {		/* Non-error */
       int idx;
 
-      Context;
       for (idx = 0; idx < dcc_total; idx++)
 	if (dcc[idx].sock == xx) {
 	  if (dcc[idx].type && dcc[idx].type->activity) {
@@ -936,7 +954,7 @@
     } else if (xx == -1) {	/* EOF from someone */
       int idx;
 
-      if ((i == STDOUT) && !backgrd)
+      if (i == STDOUT && !backgrd)
 	fatal("END OF FILE ON TERMINAL", 0);
       Context;
       for (idx = 0; idx < dcc_total; idx++)
@@ -958,7 +976,7 @@
 	close(i);
 	killsock(i);
       }
-    } else if ((xx == -2) && (errno != EINTR)) {	/* select() error */
+    } else if (xx == -2 && errno != EINTR) {	/* select() error */
       Context;
       putlog(LOG_MISC, "*", "* Socket error #%d; recovering.", errno);
       for (i = 0; i < dcc_total; i++) {
@@ -971,7 +989,7 @@
 	  i--;
 	}
       }
-    } else if (xx == (-3)) {
+    } else if (xx == -3) {
       call_hook(HOOK_IDLE);
       socket_cleanup = 0;	/* If we've been idle, cleanup & flush */
     }
@@ -1008,9 +1026,8 @@
 	}
 	p = module_list;
 	if (p && p->next && p->next->next)
-	  /* Should be only 2 modules now -
-	   * blowfish & eggdrop
-	   */
+	  /* Should be only 2 modules now - blowfish (or some other
+	     encryption module) and eggdrop. */
 	  putlog(LOG_MISC, "*", MOD_STAGNANT);
 	Context;
 	flushlogs();
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/mem.c eggdrop1.5/src/mem.c
--- eggdrop1.5~/src/mem.c	Thu Oct 19 19:25:38 2000
+++ eggdrop1.5/src/mem.c	Mon Oct 23 23:10:57 2000
@@ -290,7 +290,7 @@
   tell_netdebug(idx);
 }
 
-void *n_malloc(int size, char *file, int line)
+void *n_malloc(int size, const char *file, int line)
 {
   void	*x;
 #ifdef DEBUG_MEM
@@ -322,7 +322,7 @@
   return x;
 }
 
-void *n_realloc(void *ptr, int size, char *file, int line)
+void *n_realloc(void *ptr, int size, const char *file, int line)
 {
   void *x;
   int i = 0;
@@ -359,7 +359,7 @@
   return x;
 }
 
-void n_free(void *ptr, char *file, int line)
+void n_free(void *ptr, const char *file, int line)
 {
   int i = 0;
 
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/mod/irc.mod/chan.c eggdrop1.5/src/mod/irc.mod/chan.c
--- eggdrop1.5~/src/mod/irc.mod/chan.c	Thu Oct 19 19:25:39 2000
+++ eggdrop1.5/src/mod/irc.mod/chan.c	Mon Oct 23 23:10:57 2000
@@ -1960,8 +1960,10 @@
 	!chan_friend(fr) && !glob_friend(fr) &&
 	!(channel_dontkickops(chan) &&
 	  (chan_op(fr) || (glob_op(fr) && !chan_deop(fr)))) &&	/* arthur2 */
-	!(use_exempts && ban_fun && /* don't kickban if permanent exempted -- Eule */
-	  (u_match_mask(global_exempts,from) || u_match_mask(chan->exempts, from)))) {
+	!(use_exempts && ban_fun &&
+	  /* don't kickban if permanent exempted -- Eule */
+	  (u_match_mask(global_exempts, from) ||
+	   u_match_mask(chan->exempts, from)))) {
       if (ban_fun) {
 	check_exemptlist(chan, from);
 	u_addban(chan, quickban(chan, uhost), origbotname,
@@ -2085,7 +2087,7 @@
   fixcolon(msg);
   strcpy(uhost, from);
   nick = splitnick(&uhost);
-    u = get_user_by_host(from);
+  u = get_user_by_host(from);
   if (flud_ctcp_thr && detect_avalanche(msg)) {
     get_user_flagrec(u, &fr, chan->dname);
     m = ismember(chan, nick);
@@ -2094,8 +2096,10 @@
 	!chan_friend(fr) && !glob_friend(fr) &&
 	!(channel_dontkickops(chan) &&
 	  (chan_op(fr) || (glob_op(fr) && !chan_deop(fr)))) &&	/* arthur2 */
-	!(use_exempts && ban_fun && /* don't kickban if permanent exempted -- Eule */
-	  (u_match_mask(global_exempts,from) || u_match_mask(chan->exempts, from)))) {
+	!(use_exempts && ban_fun &&
+	  /* don't kickban if permanent exempted -- Eule */
+	  (u_match_mask(global_exempts,from) ||
+	   u_match_mask(chan->exempts, from)))) {
       if (ban_fun) {
 	check_exemptlist(chan, from);
 	u_addban(chan, quickban(chan, uhost), origbotname,
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/mod/module.h eggdrop1.5/src/mod/module.h
--- eggdrop1.5~/src/mod/module.h	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/mod/module.h	Mon Oct 23 22:55:23 2000
@@ -97,10 +97,10 @@
 #define module_depend ((Function *(*)(char *,char *,int,int))global[6])
 #define module_undepend ((int(*)(char *))global[7])
 /* 8 - 11 */
-#define add_bind_table ((p_tcl_bind_list(*)(char *,int,Function))global[8])
+#define add_bind_table ((p_tcl_bind_list(*)(const char *,int,Function))global[8])
 #define del_bind_table ((void (*) (p_tcl_bind_list))global[9])
-#define find_bind_table ((p_tcl_bind_list(*)(char *))global[10])
-#define check_tcl_bind ((int (*) (p_tcl_bind_list,char *,struct flag_record *,char *, int))global[11])
+#define find_bind_table ((p_tcl_bind_list(*)(const char *))global[10])
+#define check_tcl_bind ((int (*) (p_tcl_bind_list,const char *,struct flag_record *,const char *, int))global[11])
 /* 12 - 15 */
 #define add_builtins ((int (*) (p_tcl_bind_list, cmd_t *))global[12])
 #define rem_builtins ((int (*) (p_tcl_bind_list, cmd_t *))global[13])
@@ -142,8 +142,8 @@
 #define add_entry_type ((int (*) ( struct user_entry_type * ))global[42])
 #define del_entry_type ((int (*) ( struct user_entry_type * ))global[43])
 /* 44 - 47 */
-#define get_user_flagrec ((void (*)(struct userrec *, struct flag_record *, char *))global[44])
-#define set_user_flagrec ((void (*)(struct userrec *, struct flag_record *, char *))global[45])
+#define get_user_flagrec ((void (*)(struct userrec *, struct flag_record *, const char *))global[44])
+#define set_user_flagrec ((void (*)(struct userrec *, struct flag_record *, const char *))global[45])
 #define get_user_by_host ((struct userrec * (*)(char *))global[46])
 #define get_user_by_handle ((struct userrec *(*)(struct userrec *,char *))global[47])
 /* 48 - 51 */
@@ -167,7 +167,7 @@
 #define count_users ((int(*)(struct userrec *))global[62])
 #define sanity_check ((int(*)(int))global[63])
 /* 64 - 67 */
-#define break_down_flags ((void (*)(char *,struct flag_record *,struct flag_record *))global[64])
+#define break_down_flags ((void (*)(const char *,struct flag_record *,struct flag_record *))global[64])
 #define build_flags ((void (*)(char *, struct flag_record *, struct flag_record *))global[65])
 #define flagrec_eq ((int(*)(struct flag_record*,struct flag_record *))global[66])
 #define flagrec_ok ((int(*)(struct flag_record*,struct flag_record *))global[67])
@@ -197,7 +197,7 @@
 #define get_data_ptr(x) ((void *(*)(int,char*,int))global[86])(x,__FILE__,__LINE__)
 #define open_telnet ((int (*) (char *, int))global[87])
 /* 88 - 91 */
-#define check_tcl_event ((void * (*) (char *))global[88])
+#define check_tcl_event ((void * (*) (const char *))global[88])
 #define my_memcpy ((void * (*) (void *, const void *, size_t))global[89])
 #define my_atoul ((IP(*)(char *))global[90])
 #define my_strcpy ((int (*)(char *, const char *))global[91])
@@ -300,7 +300,7 @@
 #define expected_memory ((int(*)(void))global[168])
 #define tell_mem_status ((void(*)(char *))global[169])
 #define do_restart (*(int *)(global[170]))
-#define check_tcl_filt ((char *(*)(int, char *))global[171])
+#define check_tcl_filt ((const char *(*)(int, const char *))global[171])
 /* 172 - 175 */
 #define add_hook(a,b) (((void (*) (int, Function))global[172])(a,b))
 #define del_hook(a,b) (((void (*) (int, Function))global[173])(a,b))
@@ -353,7 +353,7 @@
 #define botname ((char *)(global[211]))
 /* 212 - 215 */
 #define remove_gunk ((void(*)(char *))global[212])
-#define check_tcl_chjn ((void (*) (char *,char *,int,char,int,char *))global[213])
+#define check_tcl_chjn ((void (*) (const char *,const char *,int,char,int,const char *))global[213])
 #define sanitycheck_dcc ((int (*)(char *, char *, char *, char *))global[214])
 #define isowner ((int (*)(char *))global[215])
 /* 216 - 219 */
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/mod/server.mod/servmsg.c eggdrop1.5/src/mod/server.mod/servmsg.c
--- eggdrop1.5~/src/mod/server.mod/servmsg.c	Thu Oct 19 19:25:39 2000
+++ eggdrop1.5/src/mod/server.mod/servmsg.c	Mon Oct 23 23:10:57 2000
@@ -696,7 +696,6 @@
   int r;
 
   Context;
-
   fixcolon(msg);
   p = strchr(from, '!');
   if (p && (p == strrchr(from, '!'))) {
@@ -851,7 +850,7 @@
 static int got433(char *from, char *msg)
 {
   char *tmp;
-  Context;
+
   if (server_online) {
     /* We are online and have a nickname, we'll keep it */
     newsplit(&msg);
@@ -860,7 +859,6 @@
     nick_juped = 0;
     return 0;
   }
-  Context;
   gotfake433(from);
   return 0;
 }
@@ -902,7 +900,6 @@
  */
 static int got438(char *from, char *msg)
 {
-  Context;
   newsplit(&msg);
   newsplit(&msg);
   fixcolon(msg);
@@ -917,8 +914,8 @@
    * hoping the next server will work :) -poptix
    */
   /* Um, this does occur on a lagged anti-spoof server connection if the
-   * (minutely) sending of joins occurs before the bot does its ping reply
-   * probably should do something about it some time - beldin
+   * (minutely) sending of joins occurs before the bot does its ping reply.
+   * Probably should do something about it some time - beldin
    */
   putlog(LOG_MISC, "*", IRC_NOTREGISTERED1, from);
   nuke_server(IRC_NOTREGISTERED2);
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/mod/share.mod/share.c eggdrop1.5/src/mod/share.mod/share.c
--- eggdrop1.5~/src/mod/share.mod/share.c	Thu Oct 19 19:25:39 2000
+++ eggdrop1.5/src/mod/share.mod/share.c	Mon Oct 23 23:10:57 2000
@@ -1211,7 +1211,7 @@
 
     if (!y)
       /* Found a match */
-      (C_share[i].func) (idx, msg);
+      (C_share[i].func)(idx, msg);
     if (y < 0)
       f = 1;
   }
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/modules.c eggdrop1.5/src/modules.c
--- eggdrop1.5~/src/modules.c	Thu Oct 19 19:25:38 2000
+++ eggdrop1.5/src/modules.c	Mon Oct 23 23:10:57 2000
@@ -875,27 +875,36 @@
   return ok;
 }
 
-void *mod_malloc(int size, char *modname, char *filename, int line)
+void *mod_malloc(int size, const char *modname, const char *filename, int line)
 {
+#ifdef DEBUG_MEM
   char x[100], *p;
 
   p = strrchr(filename, '/');
   sprintf(x, "%s:%s", modname, p ? p + 1 : filename);
   x[19] = 0;
   return n_malloc(size, x, line);
+#else
+  return nmalloc(size);
+#endif
 }
 
-void *mod_realloc(void *ptr, int size, char *modname, char *filename, int line)
+void *mod_realloc(void *ptr, int size, const char *modname,
+		  const char *filename, int line)
 {
+#ifdef DEBUG_MEM
   char x[100], *p;
 
   p = strrchr(filename, '/');
   sprintf(x, "%s:%s", modname, p ? p + 1 : filename);
   x[19] = 0;
   return n_realloc(ptr, size, x, line);
+#else
+  return nrealloc(ptr, size);
+#endif
 }
 
-void mod_free(void *ptr, char *modname, char *filename, int line)
+void mod_free(void *ptr, const char *modname, const char *filename, int line)
 {
   char x[100], *p;
 
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/modules.h eggdrop1.5/src/modules.h
--- eggdrop1.5~/src/modules.h	Thu Oct 19 19:25:38 2000
+++ eggdrop1.5/src/modules.h	Mon Oct 23 23:10:57 2000
@@ -46,9 +46,10 @@
 module_entry *module_find(char *name, int, int);
 Function *module_depend(char *, char *, int major, int minor);
 int module_undepend(char *);
-void *mod_malloc(int, char *, char *, int);
-void *mod_realloc(void *, int, char *, char *, int);
-void mod_free(void *ptr, char *modname, char *filename, int line);
+void *mod_malloc(int size, const char *modname, const char *filename, int line);
+void *mod_realloc(void *ptr, int size, const char *modname,
+		  const char *filename, int line);
+void mod_free(void *ptr, const char *modname, const char *filename, int line);
 void add_hook(int hook_num, Function func);
 void del_hook(int hook_num, Function func);
 void *get_next_hook(int hook_num, void *func);
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/proto.h eggdrop1.5/src/proto.h
--- eggdrop1.5~/src/proto.h	Mon Oct 23 22:42:37 2000
+++ eggdrop1.5/src/proto.h	Mon Oct 23 23:10:57 2000
@@ -187,9 +187,9 @@
 #define wild_match(a,b) _wild_match((unsigned char *)(a),(unsigned char *)(b))
 
 /* mem.c */
-void *n_malloc(int, char *, int);
-void *n_realloc(void *, int, char *, int);
-void n_free(void *, char *, int);
+void *n_malloc(int, const char *, int);
+void *n_realloc(void *, int, const char *, int);
+void n_free(void *, const char *, int);
 void tell_mem_status(char *);
 void tell_mem_status_dcc(int);
 void debug_mem_to_dcc(int);
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/tclhash.c eggdrop1.5/src/tclhash.c
--- eggdrop1.5~/src/tclhash.c	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/tclhash.c	Mon Oct 23 23:14:17 2000
@@ -39,7 +39,7 @@
 extern int		 debug_tcl, dcc_total;
 extern time_t		 now;
 
-p_tcl_bind_list	bind_table_list;
+p_tcl_bind_list		bind_table_list;
 p_tcl_bind_list		H_chat, H_act, H_bcst, H_chon, H_chof,
 			H_load, H_unld, H_link, H_disc, H_dcc, H_chjn, H_chpt,
 			H_bot, H_time, H_nkch, H_away, H_note, H_filt, H_event;
@@ -56,34 +56,157 @@
 static int builtin_dcc();
 
 
-int expmem_tclhash()
+/* Allocate and initialise a chunk of memory.
+ */
+static inline void *n_malloc_null(int size, const char *file, int line)
+{
+#ifdef DEBUG_MEM
+# define	nmalloc_null(size)	n_malloc_null(size, __FILE__, __LINE__)
+  void	*ptr = n_malloc(size, file, line);
+#else
+# define	nmalloc_null(size)	n_malloc_null(size, NULL, 0)
+  void	*ptr = nmalloc(size);
+#endif
+
+  egg_memset(ptr, 0, size);
+  return ptr;
+}
+
+
+/* Delete trigger/command.
+ */
+static inline void tcl_cmd_delete(tcl_cmd_t *tc)
+{
+  nfree(tc->func_name);
+  nfree(tc);
+}
+
+/* Delete bind and its elements.
+ */
+static inline void tcl_bind_mask_delete(tcl_bind_mask_t *tm)
 {
-  struct tcl_bind_list *p = bind_table_list;
-  struct tcl_bind_mask *q;
-  tcl_cmd_t *c;
-  int tot = 0;
-
-  while (p) {
-    tot += sizeof(struct tcl_bind_list);
-
-    for (q = p->first; q; q = q->next) {
-      tot += sizeof(struct tcl_bind_mask);
-
-      tot += strlen(q->mask) + 1;
-      for (c = q->first; c; c = c->next) {
-	tot += sizeof(tcl_cmd_t);
-	tot += strlen(c->func_name) + 1;
+  tcl_cmd_t		*tc, *tc_next;
+
+  for (tc = tm->first; tc; tc = tc_next) {
+    tc_next = tc->next;
+    tcl_cmd_delete(tc);
+  }
+  nfree(tm->mask);
+  nfree(tm);
+}
+
+/* Delete bind list and its elements.
+ */
+static inline void tcl_bind_list_delete(tcl_bind_list_t *tl)
+{
+  tcl_bind_mask_t	*tm, *tm_next;
+
+  for (tm = tl->first; tm; tm = tm_next) {
+    tm_next = tm->next;
+    tcl_bind_mask_delete(tm);
+  }
+  nfree(tl);
+}
+
+inline void garbage_collect_tclhash(void)
+{
+  tcl_bind_list_t	*tl, *tl_next, *tl_prev;
+  tcl_bind_mask_t	*tm, *tm_next, *tm_prev;
+  tcl_cmd_t		*tc, *tc_next, *tc_prev;
+
+  for (tl = bind_table_list, tl_prev = NULL; tl; tl = tl_next) {
+    tl_next = tl->next;
+
+    if (tl->flags & HT_DELETED) {
+      if (tl_prev)
+	tl_prev->next = tl->next;
+      else
+	bind_table_list = tl->next;
+      tcl_bind_list_delete(tl);
+    } else {
+      for (tm = tl->first, tm_prev = NULL; tm; tm = tm_next) {
+	tm_next = tm->next;
+
+	if (!(tm->flags & TBM_DELETED)) {
+	  for (tc = tm->first, tc_prev = NULL; tc; tc = tc_next) {
+	    tc_next = tc->next;
+
+	    if (tc->attributes & TC_DELETED) {
+	      if (tc_prev)
+		tc_prev->next = tc->next;
+	      else
+		tm->first = tc->next;
+	      tcl_cmd_delete(tc);
+	    } else
+	      tc_prev = tc;
+	  }
+	}
+
+	/* Delete the bind when it's marked as deleted or
+	   when it's empty. */
+	if ((tm->flags & TBM_DELETED) || tm->first == NULL) {
+	  if (tm_prev)
+	    tm_prev->next = tm->next;
+	  else
+	    tl->first = tm_next;
+	  tcl_bind_mask_delete(tm);
+	} else
+	  tm_prev = tm;
       }
+      tl_prev = tl;
     }
-    p = p->next;
   }
+}
+
+static inline int tcl_cmd_expmem(tcl_cmd_t *tc)
+{
+  int			tot;
+
+  tot = sizeof(*tc);
+  if (tc->func_name)
+    tot += strlen(tc->func_name) + 1;
   return tot;
 }
 
+static inline int tcl_bind_mask_expmem(tcl_bind_mask_t *tm)
+{
+  int			 tot = 0;
+  tcl_cmd_t		*tc;
+
+  for (tc = tm->first; tc; tc = tc->next)
+    tot += tcl_cmd_expmem(tc);
+  if (tm->mask)
+    tot += strlen(tm->mask) + 1;
+  tot += sizeof(*tm);
+  return tot;
+}
+
+static inline int tcl_bind_list_expmem(tcl_bind_list_t *tl)
+{
+  int			 tot = 0;
+  tcl_bind_mask_t	*tm;
+
+  for (tm = tl->first; tm; tm = tm->next)
+    tot += tcl_bind_mask_expmem(tm);
+  tot += sizeof(*tl);
+  return tot;
+}
+
+int expmem_tclhash(void)
+{
+  int			 tot = 0;
+  tcl_bind_list_t	*tl;
+
+  for (tl = bind_table_list; tl; tl = tl->next)
+    tot += tcl_bind_list_expmem(tl);
+  return tot;
+}
+
+
 extern cmd_t C_dcc[];
 static int tcl_bind();
 
-void init_bind()
+void init_bind(void)
 {
   bind_table_list = NULL;
   Context;
@@ -112,230 +235,223 @@
   add_builtins(H_dcc, C_dcc);
 }
 
-void kill_bind()
+void kill_bind(void)
 {
+  tcl_bind_list_t	*tl, *tl_next;
+
   rem_builtins(H_dcc, C_dcc);
-  while (bind_table_list) {
-    del_bind_table(bind_table_list);
+  for (tl = bind_table_list; tl; tl = tl_next) {
+    tl_next = tl->next;
+
+    if (!(tl->flags |= HT_DELETED))
+      putlog(LOG_DEBUG, "*", "De-Allocated bind table %s", tl->name);
+    tcl_bind_list_delete(tl);
   }
+  bind_table_list = NULL;
 }
 
-p_tcl_bind_list add_bind_table(char *nme, int flg, Function f)
+tcl_bind_list_t *add_bind_table(const char *nme, int flg, Function func)
 {
-  p_tcl_bind_list p = bind_table_list, o = NULL;
+  tcl_bind_list_t	*tl, *tl_prev;
+  int			 v;
 
   /* Do not allow coders to use bind table names longer than
-   * 4 characters.
-   */
+     4 characters. */
   Assert(strlen(nme) <= 4); 
 
-  while (p) {
-    int v = egg_strcasecmp(p->name, nme);
-
+  for (tl = bind_table_list, tl_prev = NULL; tl; tl_prev = tl, tl = tl->next) {
+    if (tl->flags & HT_DELETED)
+      continue;
+    v = egg_strcasecmp(tl->name, nme);
     if (v == 0)
-      /* Repeat, just return old value */
-      return p;
-    /* Insert at start of list */
-    if (v > 0) {
-      break;
-    } else {
-      o = p;
-      p = p->next;
-    }
+      return tl;	/* Duplicate, just return old value.	*/
+    if (v > 0)
+      break;		/* New. Insert at start of list.	*/
   }
-  p = nmalloc(sizeof(struct tcl_bind_list));
 
-  p->first = NULL;
-  strcpy(p->name, nme);
-  p->flags = flg;
-  p->func = f;
-  if (o) {
-    p->next = o->next;
-    o->next = p;
+  tl = nmalloc_null(sizeof(tcl_bind_list_t));
+  strcpy(tl->name, nme);
+  tl->flags = flg;
+  tl->func = func;
+
+  if (tl_prev) {
+    tl->next = tl_prev->next;
+    tl_prev->next = tl;
   } else {
-    p->next = bind_table_list;
-    bind_table_list = p;
+    tl->next = bind_table_list;
+    bind_table_list = tl;
   }
+
   putlog(LOG_DEBUG, "*", "Allocated bind table %s (flags %d)", nme, flg);
-  return p;
+  return tl;
 }
 
-void del_bind_table(p_tcl_bind_list which)
+void del_bind_table(tcl_bind_list_t *tl_which)
 {
-  p_tcl_bind_list p = bind_table_list, o = NULL;
+  tcl_bind_list_t	*tl;
 
-  while (p) {
-    if (p == which) {
-      tcl_cmd_t *tt, *tt1;
-      struct tcl_bind_mask *ht, *ht1;
-
-      if (o) {
-	o->next = p->next;
-      } else {
-	bind_table_list = p->next;
-      }
-      /* Cleanup code goes here */
-      for (ht = p->first; ht; ht = ht1) {
-	ht1 = ht->next;
-	for (tt = ht->first; tt; tt = tt1) {
-	  tt1 = tt->next;
-	  nfree(tt->func_name);
-	  nfree(tt);
-	}
-	nfree(ht->mask);
-	nfree(ht);
-      }
-      putlog(LOG_DEBUG, "*", "De-Allocated bind table %s", p->name);
-      nfree(p);
+  for (tl = bind_table_list; tl; tl = tl->next) {
+    if (tl->flags & HT_DELETED)
+      continue;
+    if (tl == tl_which) {
+      tl->flags |= HT_DELETED;
+      putlog(LOG_DEBUG, "*", "De-Allocated bind table %s", tl->name);
       return;
     }
-    o = p;
-    p = p->next;
   }
-  putlog(LOG_DEBUG, "*", "??? Tried to delete no listed bind table ???");
+  putlog(LOG_DEBUG, "*", "??? Tried to delete not listed bind table ???");
 }
 
-p_tcl_bind_list find_bind_table(char *nme)
+tcl_bind_list_t *find_bind_table(const char *nme)
 {
-  p_tcl_bind_list p = bind_table_list;
-
-  while (p) {
-    int v = egg_strcasecmp(p->name, nme);
+  tcl_bind_list_t	*tl;
+  int			 v;
 
+  for (tl = bind_table_list; tl; tl = tl->next) {
+    if (tl->flags & HT_DELETED)
+      continue;
+    v = egg_strcasecmp(tl->name, nme);
     if (v == 0)
-      return p;
+      return tl;
     if (v > 0)
       return NULL;
-    p = p->next;
   }
   return NULL;
 }
 
-static void dump_bind_tables(Tcl_Interp * irp)
+static void dump_bind_tables(Tcl_Interp *irp)
 {
-  p_tcl_bind_list p = bind_table_list;
-  int i = 0;
+  tcl_bind_list_t	*tl;
+  u_8bit_t		 i;
 
-  while (p) {
+  for (tl = bind_table_list, i = 0; tl; tl = tl->next) {
+    if (tl->flags & HT_DELETED)
+      continue;
     if (i)
       Tcl_AppendResult(irp, ", ", NULL);
     else
-      i++;
-    Tcl_AppendResult(irp, p->name, NULL);
-    p = p->next;
+      i = 1;
+    Tcl_AppendResult(irp, tl->name, NULL);
   }
 }
 
-static int unbind_bind_entry(p_tcl_bind_list typ, char *flags, char *cmd,
-			     char *proc)
+static int unbind_bind_entry(tcl_bind_list_t *tl, const char *flags,
+			     const char *cmd, const char *proc)
 {
-  tcl_cmd_t *tt, *last;
-  struct tcl_bind_mask *ma, *ma1 = NULL;
-
-  for (ma = typ->first; ma; ma = ma->next) {
-    int i = strcmp(cmd, ma->mask);
+  tcl_bind_mask_t	*tm;
 
-    if (!i)
+  /* Search for matching bind in bind list. */
+  for (tm = tl->first; tm; tm = tm->next) {
+    if (tm->flags & TBM_DELETED)
+      continue;
+    if (!strcmp(cmd, tm->mask))
       break;			/* Found it! fall out! */
-    ma1 = ma;
   }
-  if (ma) {
-    last = NULL;
-    for (tt = ma->first; tt; tt = tt->next) {
-      /* If procs are same, erase regardless of flags */
-      if (!egg_strcasecmp(tt->func_name, proc)) {
-	/* Erase it */
-	if (last) {
-	  last->next = tt->next;
-	} else if (tt->next) {
-	  ma->first = tt->next;
-	} else {
-	  if (ma1)
-	    ma1->next = ma->next;
-	  else
-	    typ->first = ma->next;
-	  nfree(ma->mask);
-	  nfree(ma);
-	}
-	nfree(tt->func_name);
-	nfree(tt);
-	return 1;
+
+  if (tm) {
+    tcl_cmd_t		*tc;
+
+    /* Search for matching proc in bind. */
+    for (tc = tm->first; tc; tc = tc->next) {
+      if (tc->attributes & TC_DELETED)
+	continue;
+      if (!egg_strcasecmp(tc->func_name, proc)) {
+	/* Erase proc regardless of flags. */
+	tc->attributes |= TC_DELETED;
+	return 1;		/* Match.	*/
       }
-      last = tt;
     }
   }
-  return 0;			/* no match */
+  return 0;			/* No match.	*/
 }
 
 /* Add command (remove old one if necessary)
  */
-static int bind_bind_entry(p_tcl_bind_list typ, char *flags, char *cmd,
-			   char *proc)
+static int bind_bind_entry(tcl_bind_list_t *tl, const char *flags,
+			   const char *cmd, const char *proc)
 {
-  tcl_cmd_t *tt;
-  struct tcl_bind_mask *ma, *ma1 = NULL;
+  tcl_cmd_t		*tc;
+  tcl_bind_mask_t	*tm, *tm_last;
 
   if (proc[0] == '#') {
     putlog(LOG_MISC, "*", "Note: binding to '#' is obsolete.");
     return 0;
   }
   Context;
-  for (ma = typ->first; ma; ma = ma->next) {
-    int i = strcmp(cmd, ma->mask);
 
-    if (!i)
+  /* Search for matching bind in bind list. */
+  for (tm = tl->first, tm_last = NULL; tm; tm_last = tm, tm = tm->next) {
+    if (tm->flags & TBM_DELETED)
+      continue;
+    if (!strcmp(cmd, tm->mask))
       break;			/* Found it! fall out! */
-    ma1 = ma;
   }
-  Context;
-  if (!ma) {
-    ma = nmalloc(sizeof(struct tcl_bind_mask));
 
-    ma->mask = nmalloc(strlen(cmd) + 1);
-    strcpy(ma->mask, cmd);
-    ma->first = NULL;
-    ma->next = typ->first;
-    typ->first = ma;
-  }
-  Context;
-  for (tt = ma->first; tt; tt = tt->next) {
-    /* Already defined? If so replace */
-    if (!egg_strcasecmp(tt->func_name, proc)) {
-      tt->flags.match = FR_GLOBAL | FR_CHAN;
-      break_down_flags(flags, &(tt->flags), NULL);
+  /* Create bind if it doesn't exist yet. */
+  if (!tm) {
+    tm = nmalloc_null(sizeof(tcl_bind_mask_t));
+    tm->mask = nmalloc(strlen(cmd) + 1);
+    strcpy(tm->mask, cmd);
+
+    /* Link into linked list of binds. */
+    tm->next = tl->first;
+    tl->first = tm;
+  }
+
+  /* Proc already defined? If so, replace. */
+  for (tc = tm->first; tc; tc = tc->next) {
+    if (tc->attributes & TC_DELETED)
+      continue;
+    if (!egg_strcasecmp(tc->func_name, proc)) {
+      tc->flags.match = FR_GLOBAL | FR_CHAN;
+      break_down_flags(flags, &(tc->flags), NULL);
       return 1;
     }
   }
-  Context;
-  if (!(typ->flags & HT_STACKABLE) && ma->first) {
-    nfree(ma->first->func_name);
-    nfree(ma->first);
-    ma->first = NULL;
+
+  /* If this bind list is not stackable, remove the
+     old entry from this bind. */
+  if (!(tl->flags & HT_STACKABLE)) {
+    for (tc = tm->first; tc; tc = tc->next) {
+      if (tc->attributes & TC_DELETED)
+	continue;
+      /* NOTE: We assume there's only one not-yet-deleted
+               entry. */
+      tc->attributes |= TC_DELETED;
+      break;
+    }
   }
-  Context;
-  tt = nmalloc(sizeof(tcl_cmd_t));
-  tt->func_name = nmalloc(strlen(proc) + 1);
-  tt->next = NULL;
-  tt->hits = 0;
-  tt->flags.match = FR_GLOBAL | FR_CHAN;
-  break_down_flags(flags, &(tt->flags), NULL);
-  strcpy(tt->func_name, proc);
-  tt->next = ma->first;
-  ma->first = tt;
+
+  tc = nmalloc_null(sizeof(tcl_cmd_t));
+  tc->flags.match = FR_GLOBAL | FR_CHAN;
+  break_down_flags(flags, &(tc->flags), NULL);
+  tc->func_name = nmalloc(strlen(proc) + 1);
+  strcpy(tc->func_name, proc);
+
+  /* Link into linked list of the bind's command list. */
+  tc->next = tm->first;
+  tm->first = tc;
+
   Context;
   return 1;
 }
 
-static int tcl_getbinds(p_tcl_bind_list kind, char *name)
+static int tcl_getbinds(tcl_bind_list_t *tl_kind, const char *name)
 {
-  tcl_cmd_t *tt;
-  struct tcl_bind_mask *be;
+  tcl_bind_mask_t	*tm;
 
-  for (be = kind->first; be; be = be->next) {
-    if (!egg_strcasecmp(be->mask, name)) {
-      for (tt = be->first; tt; tt = tt->next)
-	Tcl_AppendElement(interp, tt->func_name);
-      return TCL_OK;
+  for (tm = tl_kind->first; tm; tm = tm->next) {
+    if (tm->flags & TBM_DELETED)
+      continue;
+    if (!egg_strcasecmp(tm->mask, name)) {
+      tcl_cmd_t		*tc;
+
+      for (tc = tm->first; tc; tc = tc->next) {
+	if (tc->attributes & TC_DELETED)
+	  continue;
+	Tcl_AppendElement(interp, tc->func_name);
+      }
+      break;
     }
   }
   return TCL_OK;
@@ -343,20 +459,24 @@
 
 static int tcl_bind STDVAR
 {
-  p_tcl_bind_list tp;
+  tcl_bind_list_t	*tl;
 
+  /* Note: `cd' defines what tcl_bind is supposed do: 0 stands for
+           bind and 1 stands for unbind. */
   if ((long int) cd == 1)
     BADARGS(5, 5, " type flags cmd/mask procname");
   else
     BADARGS(4, 5, " type flags cmd/mask ?procname?");
-  tp = find_bind_table(argv[1]);
-  if (!tp) {
+
+  tl = find_bind_table(argv[1]);
+  if (!tl) {
     Tcl_AppendResult(irp, "bad type, should be one of: ", NULL);
     dump_bind_tables(irp);
     return TCL_ERROR;
   }
+
   if ((long int) cd == 1) {
-    if (!unbind_bind_entry(tp, argv[2], argv[3], argv[4])) {
+    if (!unbind_bind_entry(tl, argv[2], argv[3], argv[4])) {
       /* Don't error if trying to re-unbind a builtin */
       if (argv[4][0] != '*' || argv[4][4] != ':' ||
 	  strcmp(argv[3], &argv[4][5]) || strncmp(argv[1], &argv[4][1], 3)) {
@@ -366,33 +486,35 @@
     }
   } else {
     if (argc == 4)
-      return tcl_getbinds(tp, argv[3]);
-    bind_bind_entry(tp, argv[2], argv[3], argv[4]);
+      return tcl_getbinds(tl, argv[3]);
+    bind_bind_entry(tl, argv[2], argv[3], argv[4]);
   }
   Tcl_AppendResult(irp, argv[3], NULL);
   return TCL_OK;
 }
 
-int check_validity(char *nme, Function f)
+int check_validity(char *nme, Function func)
 {
-  char *p;
-  p_tcl_bind_list t;
+  char			*p;
+  tcl_bind_list_t	*tl;
 
   if (*nme != '*')
     return 0;
-  if (!(p = strchr(nme + 1, ':')))
+  p = strchr(nme + 1, ':');
+  if (p == NULL)
     return 0;
   *p = 0;
-  t = find_bind_table(nme + 1);
+  tl = find_bind_table(nme + 1);
   *p = ':';
-  if (!t)
+  if (!tl)
     return 0;
-  if (t->func != f)
+  if (tl->func != func)
     return 0;
   return 1;
 }
 
-static int builtin_3char STDVAR {
+static int builtin_3char STDVAR
+{
   Function F = (Function) cd;
 
   BADARGS(4, 4, " from to args");
@@ -401,7 +523,8 @@
   return TCL_OK;
 }
 
-static int builtin_2char STDVAR {
+static int builtin_2char STDVAR
+{
   Function F = (Function) cd;
 
   BADARGS(3, 3, " nick msg");
@@ -410,7 +533,8 @@
   return TCL_OK;
 }
 
-static int builtin_5int STDVAR {
+static int builtin_5int STDVAR
+{
   Function F = (Function) cd;
 
   BADARGS(6, 6, " min hrs dom mon year");
@@ -419,7 +543,8 @@
   return TCL_OK;
 }
 
-static int builtin_char STDVAR {
+static int builtin_char STDVAR
+{
   Function F = (Function) cd;
 
   BADARGS(2, 2, " handle");
@@ -428,7 +553,8 @@
   return TCL_OK;
 }
 
-static int builtin_chpt STDVAR {
+static int builtin_chpt STDVAR
+{
   Function F = (Function) cd;
 
   BADARGS(3, 3, " bot nick sock");
@@ -437,7 +563,8 @@
   return TCL_OK;
 }
 
-static int builtin_chjn STDVAR {
+static int builtin_chjn STDVAR
+{
   Function F = (Function) cd;
 
   BADARGS(6, 6, " bot nick chan# flag&sock host");
@@ -447,7 +574,8 @@
   return TCL_OK;
 }
 
-static int builtin_idxchar STDVAR {
+static int builtin_idxchar STDVAR
+{
   Function F = (Function) cd;
   int idx;
   char *r;
@@ -466,9 +594,9 @@
   return TCL_OK;
 }
 
-int findanyidx(int z)
+int findanyidx(register int z)
 {
-  int j;
+  register int j;
 
   for (j = 0; j < dcc_total; j++)
     if (dcc[j].sock == z)
@@ -476,7 +604,8 @@
   return -1;
 }
 
-static int builtin_charidx STDVAR {
+static int builtin_charidx STDVAR
+{
   Function F = (Function) cd;
   int idx;
 
@@ -491,7 +620,8 @@
   return TCL_OK;
 }
 
-static int builtin_chat STDVAR {
+static int builtin_chat STDVAR
+{
   Function F = (Function) cd;
   int ch;
 
@@ -502,7 +632,8 @@
   return TCL_OK;
 }
 
-static int builtin_dcc STDVAR {
+static int builtin_dcc STDVAR
+{
   int idx;
   Function F = (Function) cd;
 
@@ -533,7 +664,7 @@
 }
 
 /* trigger (execute) a proc */
-static int trigger_bind(char *proc, char *param)
+static int trigger_bind(const char *proc, const char *param)
 {
   int x;
   FILE *f = 0;
@@ -548,7 +679,8 @@
      * the called proc name and it's parameters. This should render us a bit
      * less helpless when we see context dumps.
      */
-    char *buf, *msg = "TCL proc: %s, param: %s";
+    const char *msg = "TCL proc: %s, param: %s";
+    char *buf;
 
     Context;
     buf = nmalloc(strlen(msg) + (proc ? strlen(proc) : 6)
@@ -580,103 +712,131 @@
   }
 }
 
-int check_tcl_bind(p_tcl_bind_list bind, char *match,
-		   struct flag_record *atr, char *param, int match_type)
+int check_tcl_bind(tcl_bind_list_t *tl, const char *match,
+		   struct flag_record *atr, const char *param, int match_type)
 {
-  struct tcl_bind_mask *hm, *ohm = NULL, *hmp = NULL;
-  int cnt = 0;
-  char *proc = NULL, *fullmatch = NULL;
-  tcl_cmd_t *tt, *htt = NULL;
-  int f = 0, atrok, x;
-
-  Context;
-  for (hm = bind->first; hm && !f && bind->first; ohm = hm, hm = hm->next) {
-    int ok = 0;
-
+  tcl_bind_mask_t	*tm, *tm_last = NULL, *tm_p = NULL;
+  int			 cnt = 0;
+  char			*proc = NULL, *fullmatch = NULL;
+  tcl_cmd_t		*tc, *htc = NULL;
+  int			 finish = 0, atrok, x, ok;
+
+  Context;
+  for (tm = tl->first; tm && !finish; tm_last = tm, tm = tm->next) {
+    if (tm->flags & TBM_DELETED)
+      continue;
+    /* Find out whether this bind matches the mask or provides
+       the the requested atcributes, depending on the specified
+       requirements. */
     switch (match_type & 0x03) {
     case MATCH_PARTIAL:
-      ok = !egg_strncasecmp(match, hm->mask, strlen(match));
+      ok = !egg_strncasecmp(match, tm->mask, strlen(match));
       break;
     case MATCH_EXACT:
-      ok = !egg_strcasecmp(match, hm->mask);
+      ok = !egg_strcasecmp(match, tm->mask);
       break;
     case MATCH_CASE:
-      ok = !strcmp(match, hm->mask);
+      ok = !strcmp(match, tm->mask);
       break;
     case MATCH_MASK:
-      ok = wild_match_per((unsigned char *) hm->mask, (unsigned char *) match);
+      ok = wild_match_per((unsigned char *) tm->mask, (unsigned char *) match);
       break;
+    default:
+      ok = 0;
     }
-    if (ok) {
-      tt = hm->first;
-      if (match_type & BIND_STACKABLE) {
-	/* Could be multiple triggers */
-	while (tt) {
-	  if (match_type & BIND_USE_ATTR) {
-	    if (match_type & BIND_HAS_BUILTINS)
-	      atrok = flagrec_ok(&tt->flags, atr);
-	    else
-	      atrok = flagrec_eq(&tt->flags, atr);
-	  } else
-	    atrok = 1;
-	  if (atrok) {
-	    cnt++;
-	    tt->hits++;
-	    hmp = ohm;
-	    Tcl_SetVar(interp, "lastbind", hm->mask, TCL_GLOBAL_ONLY);
-	    x = trigger_bind(tt->func_name, param);
-	    if ((match_type & BIND_WANTRET) &&
-		!(match_type & BIND_ALTER_ARGS) && (x == BIND_EXEC_LOG))
+    if (ok == 0)
+      continue;	/* This bind does not match. */
+
+    if (match_type & BIND_STACKABLE) {
+      /* Could be multiple commands/triggers. */
+      for (tc = tm->first; tc; tc = tc->next) {
+	if (match_type & BIND_USE_ATTR) {
+	  /* Check whether the provided flags suffice for
+	     this command/trigger. */
+	  if (match_type & BIND_HAS_BUILTINS)
+	    atrok = flagrec_ok(&tc->flags, atr);
+	  else
+	    atrok = flagrec_eq(&tc->flags, atr);
+	} else
+	  atrok = 1;
+
+	if (atrok) {
+	  cnt++;
+	  tc->hits++;
+	  tm_p = tm_last;
+	  Tcl_SetVar(interp, "lastbind", tm->mask, TCL_GLOBAL_ONLY);
+	  x = trigger_bind(tc->func_name, param);
+	  if (match_type & BIND_ALTER_ARGS) {
+	    if (interp->result == NULL || !interp->result[0])
 	      return x;
-	    if (match_type & BIND_ALTER_ARGS) {
-	      if ((interp->result == NULL) || !(interp->result[0]))
-		return x;
-	      /* This is such an amazingly ugly hack: */
-	      Tcl_SetVar(interp, "_a", interp->result, 0);
-	    }
-	  }
-	  tt = tt->next;
+	    /* This is such an amazingly ugly hack: */
+	    Tcl_SetVar(interp, "_a", interp->result, 0);
+	    /* Note: If someone knows what the above tries to
+	       achieve, please tell me! (Fabian, 2000-10-14) */
+	  } else if ((match_type & BIND_WANTRET) && x == BIND_EXEC_LOG)
+	    return x;
 	}
-	if ((match_type & 3) != MATCH_MASK)
-	  f = 1;		/* This will suffice until we have
-				 * stackable partials */
-      } else {
-	if (match_type & BIND_USE_ATTR) {
+      }
+
+      /* Apart from MATCH_MASK, currently no match type allows us to match
+         against more than one bind. So if this isn't MATCH_MASK then exit
+	 the loop now. */
+      /* This will suffice until we have stackable partials. */
+      if ((match_type & 3) != MATCH_MASK)
+	finish = 1;
+    } else {
+      /* Search for valid entry. */
+      for (tc = tm->first; tc; tc = tc->next)
+	if (!(tc->attributes & TC_DELETED))
+	  break;
+      if (tc) {
+        /* Check whether the provided flags suffice for this
+           command/trigger. */
+        if (match_type & BIND_USE_ATTR) {
 	  if (match_type & BIND_HAS_BUILTINS)
-	    atrok = flagrec_ok(&tt->flags, atr);
+	    atrok = flagrec_ok(&tc->flags, atr);
 	  else
-	    atrok = flagrec_eq(&tt->flags, atr);
+	    atrok = flagrec_eq(&tc->flags, atr);
 	} else
 	  atrok = 1;
+
 	if (atrok) {
 	  cnt++;
-	  proc = tt->func_name;
-         fullmatch = hm->mask;	  
-	  htt = tt;
-	  hmp = ohm;
-	  if (((match_type & 3) != MATCH_PARTIAL) ||
-	      !egg_strcasecmp(match, hm->mask))
-	    cnt = f = 1;
+	  /* Remember information about this bind and its only
+	     command/trigger. */
+	  proc = tc->func_name;
+	  fullmatch = tm->mask;
+	  htc = tc;
+	  tm_p = tm_last;
+
+	  /* Either this is a non-partial match, which means we
+	     only want to execute _one_ bind ... */
+	  if ((match_type & 3) != MATCH_PARTIAL ||
+	      /* ... or this is happens to be an exact match. */
+	      !egg_strcasecmp(match, tm->mask))
+	    cnt = finish = 1;
 	}
       }
     }
   }
-  Context;
+
   if (cnt == 0)
     return BIND_NOMATCH;
-  if (((match_type & 0x03) == MATCH_MASK) ||
-      ((match_type & 0x03) == MATCH_CASE))
+  if ((match_type & 0x03) == MATCH_MASK ||
+      (match_type & 0x03) == MATCH_CASE)
     return BIND_EXECUTED;
-  if ((match_type & 0x3) != MATCH_CASE) {
-    if (htt)
-      htt->hits++;
-    if (hmp) {
-      ohm = hmp->next;
-      hmp->next = ohm->next;
-      ohm->next = bind->first;
-      bind->first = ohm;
-    }
+
+  /* Now that we have found at least one bind, we can update the
+     preferred entries information. */
+  if (htc)
+    htc->hits++;
+  if (tm_p) {
+    tm_last = tm_p->next;
+    tm_p->next = tm_last->next;
+    tm_last->next = tl->first;
+    tl->first = tm_last;
   }
+
   if (cnt > 1)
     return BIND_AMBIGUOUS;
   Tcl_SetVar(interp, "lastbind", fullmatch, TCL_GLOBAL_ONLY);
@@ -686,11 +846,11 @@
 /* Check for tcl-bound dcc command, return 1 if found
  * dcc: proc-name <handle> <sock> <args...>
  */
-int check_tcl_dcc(char *cmd, int idx, char *args)
+int check_tcl_dcc(const char *cmd, int idx, const char *args)
 {
-  struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
-  int x;
-  char s[5];
+  struct flag_record	fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
+  int			x;
+  char			s[20];
 
   Context;
   get_user_flagrec(dcc[idx].user, &fr, dcc[idx].u.chat->con_chan);
@@ -717,7 +877,7 @@
   return 0;
 }
 
-void check_tcl_bot(char *nick, char *code, char *param)
+void check_tcl_bot(const char *nick, const char *code, const char *param)
 {
   Context;
   Tcl_SetVar(interp, "_bot1", nick, 0);
@@ -726,40 +886,41 @@
   check_tcl_bind(H_bot, code, 0, " $_bot1 $_bot2 $_bot3", MATCH_EXACT);
 }
 
-void check_tcl_chonof(char *hand, int sock, p_tcl_bind_list table)
+void check_tcl_chonof(char *hand, int sock, tcl_bind_list_t *tl)
 {
-  struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
-  char s[20];
-  struct userrec *u = get_user_by_handle(userlist, hand);
+  struct flag_record	 fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
+  char			 s[20];
+  struct userrec	*u;
 
   Context;
+  u = get_user_by_handle(userlist, hand);
   touch_laston(u, "partyline", now);
   get_user_flagrec(u, &fr, NULL);
   Tcl_SetVar(interp, "_chonof1", hand, 0);
   simple_sprintf(s, "%d", sock);
   Tcl_SetVar(interp, "_chonof2", s, 0);
   Context;
-  check_tcl_bind(table, hand, &fr, " $_chonof1 $_chonof2", MATCH_MASK |
+  check_tcl_bind(tl, hand, &fr, " $_chonof1 $_chonof2", MATCH_MASK |
 		 BIND_USE_ATTR | BIND_STACKABLE | BIND_WANTRET);
   Context;
 }
 
-void check_tcl_chatactbcst(char *from, int chan, char *text,
-			   p_tcl_bind_list ht)
+void check_tcl_chatactbcst(const char *from, int chan, const char *text,
+			   tcl_bind_list_t *tl)
 {
-  char s[10];
+  char s[20];
 
   Context;
   simple_sprintf(s, "%d", chan);
   Tcl_SetVar(interp, "_cab1", from, 0);
   Tcl_SetVar(interp, "_cab2", s, 0);
   Tcl_SetVar(interp, "_cab3", text, 0);
-  check_tcl_bind(ht, text, 0, " $_cab1 $_cab2 $_cab3",
+  check_tcl_bind(tl, text, 0, " $_cab1 $_cab2 $_cab3",
 		 MATCH_MASK | BIND_STACKABLE);
   Context;
 }
 
-void check_tcl_nkch(char *ohand, char *nhand)
+void check_tcl_nkch(const char *ohand, const char *nhand)
 {
   Context;
   Tcl_SetVar(interp, "_nkch1", ohand, 0);
@@ -769,7 +930,7 @@
   Context;
 }
 
-void check_tcl_link(char *bot, char *via)
+void check_tcl_link(const char *bot, const char *via)
 {
   Context;
   Tcl_SetVar(interp, "_link1", bot, 0);
@@ -780,7 +941,7 @@
   Context;
 }
 
-void check_tcl_disc(char *bot)
+void check_tcl_disc(const char *bot)
 {
   Context;
   Tcl_SetVar(interp, "_disc1", bot, 0);
@@ -789,20 +950,20 @@
   Context;
 }
 
-void check_tcl_loadunld(char *mod, p_tcl_bind_list table)
+void check_tcl_loadunld(const char *mod, tcl_bind_list_t *tl)
 {
   Context;
   Tcl_SetVar(interp, "_lu1", mod, 0);
   Context;
-  check_tcl_bind(table, mod, 0, " $_lu1", MATCH_MASK | BIND_STACKABLE);
+  check_tcl_bind(tl, mod, 0, " $_lu1", MATCH_MASK | BIND_STACKABLE);
   Context;
 }
 
-char *check_tcl_filt(int idx, char *text)
+const char *check_tcl_filt(int idx, const char *text)
 {
-  char s[10];
-  int x;
-  struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
+  char			s[20];
+  int			x;
+  struct flag_record	fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0};
 
   Context;
   sprintf(s, "%ld", dcc[idx].sock);
@@ -814,8 +975,8 @@
 		     MATCH_MASK | BIND_USE_ATTR | BIND_STACKABLE |
 		     BIND_WANTRET | BIND_ALTER_ARGS);
   Context;
-  if ((x == BIND_EXECUTED) || (x == BIND_EXEC_LOG)) {
-    if ((interp->result == NULL) || (!interp->result[0]))
+  if (x == BIND_EXECUTED || x == BIND_EXEC_LOG) {
+    if (interp->result == NULL || !interp->result[0])
       return "";
     else
       return interp->result;
@@ -823,23 +984,22 @@
     return text;
 }
 
-int check_tcl_note(char *from, char *to, char *text)
+int check_tcl_note(const char *from, const char *to, const char *text)
 {
-  int x;
+  int	x;
 
   Context;
   Tcl_SetVar(interp, "_note1", from, 0);
   Tcl_SetVar(interp, "_note2", to, 0);
   Tcl_SetVar(interp, "_note3", text, 0);
   x = check_tcl_bind(H_note, to, 0, " $_note1 $_note2 $_note3", MATCH_EXACT);
-  return ((x == BIND_MATCHED) || (x == BIND_EXECUTED) ||
-	  (x == BIND_EXEC_LOG));
+  return (x == BIND_MATCHED || x == BIND_EXECUTED || x == BIND_EXEC_LOG);
 }
 
-void check_tcl_listen(char *cmd, int idx)
+void check_tcl_listen(const char *cmd, int idx)
 {
-  char s[10];
-  int x;
+  char	s[20];
+  int	x;
 
   Context;
   simple_sprintf(s, "%d", idx);
@@ -851,12 +1011,11 @@
     putlog(LOG_MISC, "*", "error on listen: %s", interp->result);
 }
 
-void check_tcl_chjn(char *bot, char *nick, int chan, char type,
-		    int sock, char *host)
+void check_tcl_chjn(const char *bot, const char *nick, int chan,
+		    const char type, int sock, const char *host)
 {
-  struct flag_record fr =
-  {FR_GLOBAL, 0, 0, 0, 0, 0};
-  char s[20], t[2], u[20];
+  struct flag_record	fr = {FR_GLOBAL, 0, 0, 0, 0, 0};
+  char			s[20], t[2], u[20];
 
   Context;
   t[0] = type;
@@ -864,21 +1023,18 @@
   switch (type) {
   case '*':
     fr.global = USER_OWNER;
-
     break;
   case '+':
     fr.global = USER_MASTER;
-
     break;
   case '@':
     fr.global = USER_OP;
-
     break;
   case '%':
     fr.global = USER_BOTMAST;
   }
-  simple_sprintf(s, "%d", chan);
-  simple_sprintf(u, "%d", sock);
+  sprintf(s, "%d", chan);
+  sprintf(u, "%d", sock);
   Tcl_SetVar(interp, "_chjn1", bot, 0);
   Tcl_SetVar(interp, "_chjn2", nick, 0);
   Tcl_SetVar(interp, "_chjn3", s, 0);
@@ -892,9 +1048,9 @@
   Context;
 }
 
-void check_tcl_chpt(char *bot, char *hand, int sock, int chan)
+void check_tcl_chpt(const char *bot, const char *hand, int sock, int chan)
 {
-  char u[20], v[20];
+  char	u[20], v[20];
 
   Context;
   simple_sprintf(u, "%d", sock);
@@ -909,9 +1065,9 @@
   Context;
 }
 
-void check_tcl_away(char *bot, int idx, char *msg)
+void check_tcl_away(const char *bot, int idx, const char *msg)
 {
-  char u[20];
+  char	u[20];
 
   Context;
   simple_sprintf(u, "%d", idx);
@@ -947,7 +1103,7 @@
   Context;
 }
 
-void check_tcl_event(char *event)
+void check_tcl_event(const char *event)
 {
   Context;
   Tcl_SetVar(interp, "_event1", event, 0);
@@ -958,44 +1114,62 @@
 
 void tell_binds(int idx, char *par)
 {
-  struct tcl_bind_mask *hm;
-  p_tcl_bind_list p, kind;
-  int fnd = 0, showall = 0, patmatc = 0;
-  tcl_cmd_t *tt;
-  char *name = "", *proc, *s = "", flg[100];
+  tcl_bind_list_t	*tl, *tl_kind;
+  tcl_bind_mask_t	*tm;
+  int			 fnd = 0, showall = 0, patmatc = 0;
+  tcl_cmd_t		*tc;
+  char			*name, *proc, *s, flg[100];
 
   Context;
   if (par[0])
     name = newsplit(&par);
+  else
+    name = NULL;
   if (par[0])
     s = newsplit(&par);
-  kind = find_bind_table(name);
-  if (!egg_strcasecmp(s, "all") || !egg_strcasecmp(name, "all"))
+  else
+    s = NULL;
+
+  if (name)
+    tl_kind = find_bind_table(name);
+  else
+    tl_kind = NULL;
+  if (s && (!egg_strcasecmp(s, "all") || !egg_strcasecmp(name, "all")))
     showall = 1;
-  if (kind == NULL && egg_strcasecmp(name, "all") && name[0]) {
+
+  if (tl_kind == NULL && name && name[0] && egg_strcasecmp(name, "all")) {
     patmatc = 1;
     dprintf(idx, "Bind type %s not found, using wild card match.\n", name);
   }
   dprintf(idx, MISC_CMDBINDS);
   dprintf(idx, "  TYPE FLGS     COMMAND              HITS BINDING (TCL)\n");
-  for (p = kind ? kind : bind_table_list; p; p = kind ? 0 : p->next) {
-    for (hm = p->first; hm; hm = hm->next) {
-      for (tt = hm->first; tt; tt = tt->next) {
-	proc = tt->func_name;
-	build_flags(flg, &(tt->flags), NULL);
-	Context;
-	if ((showall) || (proc[0] != '*') || !strchr(proc, ':')) {
+
+  for (tl = tl_kind ? tl_kind : bind_table_list; tl;
+       tl = tl_kind ? 0 : tl->next) {
+    if (tl->flags & HT_DELETED)
+      continue;
+    for (tm = tl->first; tm; tm = tm->next) {
+      if (tm->flags & TBM_DELETED)
+	continue;
+      for (tc = tm->first; tc; tc = tc->next) {
+	if (tc->attributes & TC_DELETED)
+	  continue;
+	proc = tc->func_name;
+	build_flags(flg, &(tc->flags), NULL);
+	if (showall || proc[0] != '*' || !strchr(proc, ':')) {
+	  int	ok = 0;
+
           if (patmatc == 1) {
-            if (wild_match(name, p->name) || 
-                wild_match(name, hm->mask) ||
-                wild_match(name, tt->func_name)) {
-	      dprintf(idx, "  %-4s %-8s %-20s %4d %s\n", p->name, flg,
-		  		hm->mask, tt->hits, tt->func_name);
-              fnd = 1;
-            }
-          } else {
-            dprintf(idx, "  %-4s %-8s %-20s %4d %s\n", p->name, flg,
-                              hm->mask, tt->hits, tt->func_name);
+            if (wild_match(name, tl->name) || 
+                wild_match(name, tm->mask) ||
+                wild_match(name, tc->func_name))
+	      ok = 1;
+          } else
+	    ok = 1;
+
+	  if (ok) {
+            dprintf(idx, "  %-4s %-8s %-20s %4d %s\n", tl->name, flg, tm->mask,
+		    tc->hits, tc->func_name);
             fnd = 1;
           }
         }
@@ -1005,7 +1179,7 @@
   if (!fnd) {
     if (patmatc)
       dprintf(idx, "No command bindings found that match %s\n", name);
-    else if (kind)
+    else if (tl_kind)
       dprintf(idx, "No command bindings for type: %s.\n", name);
     else
       dprintf(idx, "No command bindings exist.\n");
@@ -1013,34 +1187,32 @@
 }
 
 /* Bring the default msg/dcc/fil commands into the Tcl interpreter */
-void add_builtins(p_tcl_bind_list table, cmd_t * cc)
+void add_builtins(tcl_bind_list_t *tl, cmd_t *cc)
 {
-  int k, i;
-  char p[1024], *l;
+  int	k, i;
+  char	p[1024], *l;
 
   Context;
   for (i = 0; cc[i].name; i++) {
-    simple_sprintf(p, "*%s:%s", table->name,
-	       cc[i].funcname ? cc[i].funcname : cc[i].name);
+    simple_sprintf(p, "*%s:%s", tl->name,
+		   cc[i].funcname ? cc[i].funcname : cc[i].name);
     l = (char *) nmalloc(Tcl_ScanElement(p, &k));
     Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES);
-    Tcl_CreateCommand(interp, p, table->func,
-		      (ClientData) cc[i].func, NULL);
-    bind_bind_entry(table, cc[i].flags, cc[i].name, l);
+    Tcl_CreateCommand(interp, p, tl->func, (ClientData) cc[i].func, NULL);
+    bind_bind_entry(tl, cc[i].flags, cc[i].name, l);
     nfree(l);
   }
 }
 
 /* Remove the default msg/dcc/fil commands from the Tcl interpreter */
-void rem_builtins(p_tcl_bind_list table, cmd_t * cc)
+void rem_builtins(tcl_bind_list_t *table, cmd_t *cc)
 {
-  int k, i;
-  char p[1024], *l;
+  int	k, i;
+  char	p[1024], *l;
 
-  for (i = 0;cc[i].name; i++) {
+  for (i = 0; cc[i].name; i++) {
     simple_sprintf(p, "*%s:%s", table->name,
-		   cc[i].funcname ? cc[i].funcname :
-		   cc[i].name);
+		   cc[i].funcname ? cc[i].funcname : cc[i].name);
     l = (char *) nmalloc(Tcl_ScanElement(p, &k));
     Tcl_ConvertElement(p, l, k | TCL_DONT_USE_BRACES);
     Tcl_DeleteCommand(interp, p);
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/tclhash.h eggdrop1.5/src/tclhash.h
--- eggdrop1.5~/src/tclhash.h	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/tclhash.h	Mon Oct 23 23:10:57 2000
@@ -25,72 +25,95 @@
 #ifndef _EGG_TCLHASH_H
 #define _EGG_TCLHASH_H
 
-#define HT_STACKABLE 1
 
-typedef struct tct {
-  struct flag_record flags;
-  char *func_name;
-  struct tct *next;
-  int hits;
+#define TC_DELETED	0x0001	/* This command/trigger was deleted.	*/
+
+typedef struct tcl_cmd_b {
+  struct tcl_cmd_b	*next;
+
+  struct flag_record	 flags;
+  char			*func_name;	/* Proc name.			*/
+  int			 hits;		/* Number of times this proc
+					   was triggered.		*/
+  u_8bit_t		 attributes;	/* Flags for this entry. TC_*	*/
 } tcl_cmd_t;
 
-struct tcl_bind_mask {
-  struct tcl_bind_mask *next;
-  tcl_cmd_t *first;
-  char *mask;
-};
-
-typedef struct tcl_bind_list {
-  struct tcl_bind_list *next;
-  struct tcl_bind_mask *first;
-  char name[5];
-  int flags;
-  Function func;
-} *p_tcl_bind_list;
+
+#define TBM_DELETED	0x0001	/* This mask was deleted.		*/
+
+typedef struct tcl_bind_mask_b {
+  struct tcl_bind_mask_b *next;
+
+  tcl_cmd_t		 *first;	/* List of commands registered
+					   for this bind.		*/
+  char			 *mask;
+  u_8bit_t		  flags;	/* Flags for this entry. TBM_*	*/
+} tcl_bind_mask_t;
+
+
+#define HT_STACKABLE	0x0001	/* Triggers in this bind list may be
+				   stacked.				*/
+#define HT_DELETED	0x0002	/* This bind list was already deleted.
+				   Do not use it anymore.		*/
+
+typedef struct tcl_bind_list_b {
+  struct tcl_bind_list_b *next;
+
+  tcl_bind_mask_t	 *first;	/* Pointer to registered binds
+					   for this list.		*/
+  char			  name[5];	/* Name of the bind.		*/
+  u_8bit_t		  flags;	/* Flags for this element. HT_*	*/
+  Function		  func;		/* Function used as the Tcl
+					   calling interface for procs
+					   actually representing C
+					   functions.			*/
+} tcl_bind_list_t, *p_tcl_bind_list;
 
 
 #ifndef MAKING_MODS
 
-void init_bind();
-void kill_bind();
-int expmem_tclhash();
-
-p_tcl_bind_list add_bind_table(char *, int, Function);
-void del_bind_table(p_tcl_bind_list);
-
-p_tcl_bind_list find_bind_table(char *);
-
-int check_tcl_bind(p_tcl_bind_list, char *, struct flag_record *, char *, int);
-int check_tcl_dcc(char *, int, char *);
-void check_tcl_chjn(char *, char *, int, char, int, char *);
-void check_tcl_chpt(char *, char *, int, int);
-void check_tcl_bot(char *, char *, char *);
-void check_tcl_link(char *, char *);
-void check_tcl_disc(char *);
-char *check_tcl_filt(int, char *);
-int check_tcl_note(char *, char *, char *);
-void check_tcl_listen(char *, int);
+inline void garbage_collect_tclhash(void);
+
+void init_bind(void);
+void kill_bind(void);
+int expmem_tclhash(void);
+
+tcl_bind_list_t *add_bind_table(const char *nme, int flg, Function func);
+void del_bind_table(tcl_bind_list_t *tl_which);
+
+tcl_bind_list_t *find_bind_table(const char *nme);
+
+int check_tcl_bind(tcl_bind_list_t *, const char *, struct flag_record *, const char *, int);
+int check_tcl_dcc(const char *, int, const char *);
+void check_tcl_chjn(const char *, const char *, int, char, int, const char *);
+void check_tcl_chpt(const char *, const char *, int, int);
+void check_tcl_bot(const char *, const char *, const char *);
+void check_tcl_link(const char *, const char *);
+void check_tcl_disc(const char *);
+const char *check_tcl_filt(int, const char *);
+int check_tcl_note(const char *, const char *, const char *);
+void check_tcl_listen(const char *, int);
 void check_tcl_time(struct tm *);
 void tell_binds(int, char *);
-void check_tcl_nkch(char *, char *);
-void check_tcl_away(char *, int, char *);
-void check_tcl_chatactbcst(char *, int, char *, p_tcl_bind_list);
-void check_tcl_event(char *);
-
-#define check_tcl_chat(a,b,c) check_tcl_chatactbcst(a,b,c,H_chat)
-#define check_tcl_act(a,b,c) check_tcl_chatactbcst(a,b,c,H_act)
-#define check_tcl_bcst(a,b,c) check_tcl_chatactbcst(a,b,c,H_bcst)
-void check_tcl_chonof(char *, int, p_tcl_bind_list);
-
-#define check_tcl_chon(a,b) check_tcl_chonof(a,b,H_chon)
-#define check_tcl_chof(a,b) check_tcl_chonof(a,b,H_chof)
-void check_tcl_loadunld(char *, p_tcl_bind_list);
+void check_tcl_nkch(const char *, const char *);
+void check_tcl_away(const char *, int, const char *);
+void check_tcl_chatactbcst(const char *, int, const char *, tcl_bind_list_t *);
+void check_tcl_event(const char *);
+
+#define check_tcl_chat(a, b, c) check_tcl_chatactbcst(a ,b, c, H_chat)
+#define check_tcl_act(a, b, c) check_tcl_chatactbcst(a, b, c, H_act)
+#define check_tcl_bcst(a, b, c) check_tcl_chatactbcst(a, b, c, H_bcst)
+void check_tcl_chonof(char *, int, tcl_bind_list_t *);
+
+#define check_tcl_chon(a, b) check_tcl_chonof(a, b, H_chon)
+#define check_tcl_chof(a, b) check_tcl_chonof(a, b, H_chof)
+void check_tcl_loadunld(const char *, tcl_bind_list_t *);
 
-#define check_tcl_load(a) check_tcl_loadunld(a,H_load)
-#define check_tcl_unld(a) check_tcl_loadunld(a,H_unld)
+#define check_tcl_load(a) check_tcl_loadunld(a, H_load)
+#define check_tcl_unld(a) check_tcl_loadunld(a, H_unld)
 
-void rem_builtins(p_tcl_bind_list, cmd_t *);
-void add_builtins(p_tcl_bind_list, cmd_t *);
+void rem_builtins(tcl_bind_list_t *, cmd_t *);
+void add_builtins(tcl_bind_list_t *, cmd_t *);
 
 int check_validity(char *, Function);
 extern p_tcl_bind_list H_chat, H_act, H_bcst, H_chon, H_chof;
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/tclmisc.c eggdrop1.5/src/tclmisc.c
--- eggdrop1.5~/src/tclmisc.c	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/tclmisc.c	Mon Oct 23 22:55:23 2000
@@ -119,33 +119,44 @@
 
 static int tcl_binds STDVAR
 {
-  struct tcl_bind_mask *hm;
-  p_tcl_bind_list p, kind;
-  tcl_cmd_t *tt;
-  char *list[5], *g, flg[100], hits[160];
-  int matching = 0;
+  tcl_bind_list_t	*tl, *tl_kind;
+  tcl_bind_mask_t	*tm;
+  tcl_cmd_t		*tc;
+  char			*list[5], *g, flg[100], hits[160];
+  int			 matching = 0;
 
   BADARGS(1, 2, " ?type/mask?");
 
-  kind = find_bind_table(argv[1] ? argv[1] : "");
-  if (!kind && argv[1])
+  if (argv[1])
+    tl_kind = find_bind_table(argv[1]);
+  else
+    tl_kind = NULL;
+  if (!tl_kind && argv[1])
     matching = 1;
 
-  for (p = kind ? kind : bind_table_list; p; p = kind ? 0 : p->next) {
-    Context;
-    for (hm = p->first; hm; hm = hm->next) {
-      for (tt = hm->first; tt; tt = tt->next) {
-        if (matching && !wild_match(argv[1], p->name) && 
-            !wild_match(argv[1], hm->mask) && 
-            !wild_match(argv[1], tt->func_name))
+  for (tl = tl_kind ? tl_kind : bind_table_list; tl;
+       tl = tl_kind ? 0 : tl->next) {
+    if (tl->flags & HT_DELETED)
+      continue;
+    for (tm = tl->first; tm; tm = tm->next) {
+      if (tm->flags & TBM_DELETED)
+	continue;
+      for (tc = tm->first; tc; tc = tc->next) {
+	if (tc->attributes & TC_DELETED)
+	  continue;
+        if (matching &&
+	    !wild_match(argv[1], tl->name) && 
+            !wild_match(argv[1], tm->mask) && 
+            !wild_match(argv[1], tc->func_name))
           continue;
-	build_flags(flg, &(tt->flags), NULL);
-        sprintf(hits, "%i", (int) tt->hits);
-        list[0] = p->name;
+
+	build_flags(flg, &(tc->flags), NULL);
+        sprintf(hits, "%i", (int) tc->hits);
+        list[0] = tl->name;
         list[1] = flg;
-        list[2] = hm->mask;
+        list[2] = tm->mask;
         list[3] = hits;
-        list[4] = tt->func_name;
+        list[4] = tc->func_name;
         g = Tcl_Merge(5, list);
         Tcl_AppendElement(irp, g);
         Tcl_Free((char *) g);
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/userrec.c eggdrop1.5/src/userrec.c
--- eggdrop1.5~/src/userrec.c	Mon Oct 23 23:10:50 2000
+++ eggdrop1.5/src/userrec.c	Mon Oct 23 23:10:57 2000
@@ -54,35 +54,33 @@
 					   default rw-------		    */
 
 
-#ifdef DEBUG_MEM
-void *_user_malloc(int size, char *file, int line)
+void *_user_malloc(int size, const char *file, int line)
 {
-  char x[1024], *p;
+#ifdef DEBUG_MEM
+  char		 x[1024];
+  const char	*p;
 
   p = strrchr(file, '/');
   simple_sprintf(x, "userrec.c:%s", p ? p + 1 : file);
   return n_malloc(size, x, line);
+#else
+  return nmalloc(size);
+#endif
 }
 
-void *_user_realloc(void *ptr, int size, char *file, int line)
+void *_user_realloc(void *ptr, int size, const char *file, int line)
 {
-  char x[1024], *p;
+#ifdef DEBUG_MEM
+  char		 x[1024];
+  const char	*p;
 
   p = strrchr(file, '/');
   simple_sprintf(x, "userrec.c:%s", p ? p + 1 : file);
   return n_realloc(ptr, size, x, line);
-}
 #else
-void *_user_malloc(int size, char *file, int line)
-{
-  return nmalloc(size);
-}
-
-void *_user_realloc(void *ptr, int size, char *file, int line)
-{
   return nrealloc(ptr, size);
-}
 #endif
+}
 
 inline int expmem_mask(struct maskrec *m)
 {
@@ -222,6 +220,7 @@
 
   if (!handle)
     return NULL;
+  /* FIXME: This should be done outside of this function. */
   rmspace(handle);
   if (!handle[0] || (handle[0] == '*'))
     return NULL;
diff -urN --exclude-from=/home/fabian/.diffex eggdrop1.5~/src/users.h eggdrop1.5/src/users.h
--- eggdrop1.5~/src/users.h	Thu Oct 19 19:25:38 2000
+++ eggdrop1.5/src/users.h	Mon Oct 23 23:10:57 2000
@@ -109,12 +109,12 @@
   int dnload_ks;
 };
 
-void *_user_malloc(int, char *, int);
-void *_user_realloc(void *, int, char *, int);
+void *_user_malloc(int size, const char *file, int line);
+void *_user_realloc(void *ptr, int size, const char *file, int line);
 
 #ifndef MAKING_MODS
-#  define user_malloc(x) _user_malloc(x,__FILE__,__LINE__)
-#  define user_realloc(x,y) _user_realloc(x,y,__FILE__,__LINE__)
+#  define user_malloc(x)	_user_malloc(x, __FILE__, __LINE__)
+#  define user_realloc(x, y)	_user_realloc(x, y, __FILE__, __LINE__)
 #endif
 
 int add_entry_type(struct user_entry_type *);




More information about the Patches mailing list