first cut of client
[spider.git] / src / chain.c
diff --git a/src/chain.c b/src/chain.c
new file mode 100755 (executable)
index 0000000..4e36b3e
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * routines to operate on double linked circular chains
+ *
+ * chain_init() - initialise a chain
+ * chain_add() - add an item after the ref provided
+ * chain_delete() - delete the item
+ * chainins() - insert an item before the ref
+ * chainnext() - get the next item on chain returning NULL if eof
+ * chainprev() - get the previous item on chain returning NULL if eof
+ * chain_empty_test() - is the chain empty?
+ * chain_movebase() - move a chain of things onto (the end of) another base
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.1  2000-03-26 00:03:30  djk
+ * first cut of client
+ *
+ * Revision 1.4  1998/01/02 19:39:58  djk
+ * made various changes to cope with glibc
+ * fixed problem with extended status in etsi_router
+ *
+ * Revision 1.3  1997/01/02 18:46:46  djk
+ * Added conv.c from ETSI router
+ * Changed qerror.c to use syslog rather than qerror.log
+ * removed all the map27 stuff into a separate directory
+ * added dump.c (a debugging tool for dumping frames of data)
+ *
+ * Revision 1.1  1996/08/08 11:33:44  djk
+ * Initial revision
+ *
+ * Revision 1.2  1995/04/21  16:02:51  djk
+ * remove rcs id
+ *
+ * Revision 1.1  1995/03/04  11:46:26  djk
+ * Initial revision
+ *
+ * Revision 1.2  1995/01/24  15:09:39  djk
+ * Changed Indent to Id in rcsid
+ *
+ * Revision 1.1  1995/01/24  15:06:28  djk
+ * Initial revision
+ *
+ * Revision 1.3  91/03/08  13:21:56  dlp
+ * changed the chain broken checks to dlpabort for dlperror
+ * 
+ * Revision 1.2  90/09/15  22:37:39  dlp
+ * checked in with -k by dirk at 91.02.20.15.53.51.
+ * 
+ * Revision 1.2  90/09/15  22:37:39  dlp
+ * *** empty log message ***
+ * 
+ * Revision 1.1  90/09/15  22:18:23  dlp
+ * Initial revision
+ * 
+ */
+
+#include <stdlib.h>
+
+/* chain definitions */
+typedef struct _reft {
+       struct _reft *next, *prev;
+} reft;
+
+static char erm[] = "chain broken in %s";
+#define check(p, ss) if (p == (struct _reft *) 0 || p->prev->next != p || p->next->prev != p) die(erm, ss);
+
+/*
+ * chain_init()
+ */
+
+void chain_init(p)
+struct _reft *p;
+{
+       p->next = p->prev = p;
+}
+
+/*
+ * chain_insert() - insert an item before the ref provided
+ */
+
+void chain_insert(p, q)
+struct _reft *p, *q;
+{
+       check(p, "ins");
+       q->prev = p->prev;
+       q->next = p;
+       p->prev->next = q;
+       p->prev = q;
+}
+/*
+ * chain_movebase() - insert an chain of items from one base to another
+ */
+
+void chain_movebase(p, q)
+struct _reft *p, *q;
+{
+       check(p, "movebase");
+       q->prev->prev = p->prev;
+       q->next->next = p;
+       p->prev->next = q->next;
+       p->prev = q->prev;
+       q->next = q->prev = q;
+}
+
+/*
+ * chain_add() - add an item after the ref
+ */
+
+void chain_add(p, q)
+struct _reft *p, *q;
+{
+       check(p, "add");
+       p = p->next;
+       chain_insert(p, q);
+}
+
+/*
+ * chain_delete() - delete an item in a chain
+ */
+
+struct _reft *chain_delete(p)
+struct _reft *p;
+{
+       check(p, "del");
+       p->prev->next = p->next;
+       p->next->prev = p->prev;
+       return p->prev;
+}
+
+/*
+ * chain_empty_test() - test to see if the chain is empty
+ */
+
+int chain_empty_test(base)
+struct _reft *base;
+{
+       check(base, "chain_empty_test")
+               return base->next == base;
+}
+
+/*
+ * chainnext() - get next item in chain
+ */
+
+struct _reft *chain_get_next(base, p)
+struct _reft *base, *p;
+{
+
+       check(base, "next base");
+       
+       if (!p)
+               return (chain_empty_test(base)) ? 0 : base->next;
+
+       check(p, "next last ref");
+       if (p->next != base)
+               return p->next;
+       else
+               return (struct _reft *) 0;
+}
+
+/*
+ * chainprev() - get previous item in chain
+ */
+
+struct _reft *chain_get_prev(base, p)
+struct _reft *base, *p;
+{
+       check(base, "prev base");
+       if (!p)
+               return (chain_empty_test(base)) ? 0 : base->prev;
+
+       check(p, "prev last ref");
+       if (p->prev != base)
+               return p->prev;
+       else
+               return (struct _reft *) 0;
+}
+
+/*
+ * rechain() - re-chain an item at this point (usually after the chain base)
+ */
+
+void chain_rechain(base, p)
+struct _reft *base, *p;
+{
+       check(base, "rechain base");
+       check(p, "rechain last ref");
+       chain_delete(p);
+       chain_add(base, p);
+}
+
+/*
+ * emptychain() - remove all the elements in a chain, this frees all elements
+ *                in a chain leaving just the base.
+ */
+
+void chain_flush(base)
+struct _reft *base;
+{
+       struct _reft *p;
+
+       while (!chain_empty_test(base)) {
+               p = base->next;
+               chain_delete(p);
+               free(p);
+       }
+}
+
+/*
+ * newchain() - create a new chain base in the heap
+ */
+
+reft *chain_new()
+{
+       reft *p = malloc(sizeof(reft));
+       if (!p)
+               die("out of room in chain_new");
+       chain_init(p);
+       return p;
+}
+