New debug channel mechanism allowing decentralized channel
declarations.

diff --git a/library/debug.c b/library/debug.c
new file mode 100644
index 0000000..3f38487
--- /dev/null
+++ b/library/debug.c
@@ -0,0 +1,118 @@
+/*
+ * Management of the debugging channels
+ *
+ * Copyright 2000 Alexandre Julliard
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+struct dll
+{
+    struct dll   *next;        /* linked list of dlls */
+    struct dll   *prev;
+    char * const *channels;    /* array of channels */
+    int           nb_channels; /* number of channels in array */
+};
+
+static struct dll *first_dll;
+
+struct option
+{
+    struct option *next;       /* next option in list */
+    unsigned char  set;        /* bits to set */
+    unsigned char  clear;      /* bits to clear */
+    char           name[14];   /* channel name, or empty for "all" */
+};
+
+static struct option *first_option;
+static struct option *last_option;
+
+
+static int cmp_name( const void *p1, const void *p2 )
+{
+    const char *name = p1;
+    const char * const *chan = p2;
+    return strcmp( name, *chan + 1 );
+}
+
+/* apply a debug option to the channels of a given dll */
+static void apply_option( struct dll *dll, const struct option *opt )
+{
+    if (opt->name[0])
+    {
+        char **dbch = bsearch( opt->name, dll->channels, dll->nb_channels,
+                               sizeof(*dll->channels), cmp_name );
+        if (dbch) **dbch = (**dbch & ~opt->clear) | opt->set;
+    }
+    else /* all */
+    {
+        int i;
+        for (i = 0; i < dll->nb_channels; i++)
+            dll->channels[i][0] = (dll->channels[i][0] & ~opt->clear) | opt->set;
+    }
+}
+
+/* register a new set of channels for a dll */
+void *wine_dbg_register( char * const *channels, int nb )
+{
+    struct option *opt = first_option;
+    struct dll *dll = malloc( sizeof(*dll) );
+    if (dll)
+    {
+        dll->channels = channels;
+        dll->nb_channels = nb;
+        dll->prev = NULL;
+        if ((dll->next = first_dll)) dll->next->prev = dll;
+        first_dll = dll;
+
+        /* apply existing options to this dll */
+        while (opt)
+        {
+            apply_option( dll, opt );
+            opt = opt->next;
+        }
+    }
+    return dll;
+}
+
+
+/* unregister a set of channels; must pass the pointer obtained from wine_dbg_register */
+void wine_dbg_unregister( void *channel )
+{
+    struct dll *dll = channel;
+    if (dll)
+    {
+        if (dll->next) dll->next->prev = dll->prev;
+        if (dll->prev) dll->prev->next = dll->next;
+        else first_dll = dll->next;
+        free( dll );
+    }
+}
+
+
+/* add a new debug option at the end of the option list */
+void wine_dbg_add_option( const char *name, unsigned char set, unsigned char clear )
+{
+    struct dll *dll = first_dll;
+    struct option *opt;
+
+    if (!(opt = malloc( sizeof(*opt) ))) return;
+    opt->next  = NULL;
+    opt->set   = set;
+    opt->clear = clear;
+    strncpy( opt->name, name, sizeof(opt->name) );
+    opt->name[sizeof(opt->name)-1] = 0;
+    if (last_option) last_option->next = opt;
+    else first_option = opt;
+    last_option = opt;
+
+    /* apply option to all existing dlls */
+    while (dll)
+    {
+        apply_option( dll, opt );
+        dll = dll->next;
+    }
+}