summaryrefslogtreecommitdiff
path: root/ext/hyperwave/dlist.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/hyperwave/dlist.c')
-rw-r--r--ext/hyperwave/dlist.c410
1 files changed, 410 insertions, 0 deletions
diff --git a/ext/hyperwave/dlist.c b/ext/hyperwave/dlist.c
new file mode 100644
index 0000000000..27c1305664
--- /dev/null
+++ b/ext/hyperwave/dlist.c
@@ -0,0 +1,410 @@
+/****************************************************************************
+*
+* Copyright (C) 1991 Kendall Bennett.
+* All rights reserved.
+*
+* Filename: $RCSfile$
+* Version: $Revision$
+*
+* Language: ANSI C
+* Environment: any
+*
+* Description: Module to implement doubly linked lists. Includes a routine
+* to peform a mergesort on the doubly linked list.
+*
+* $Id$
+*
+* Revision History:
+* -----------------
+*
+* $Log$
+* Revision 1.1.1.1 1999/04/07 21:03:31 zeev
+* PHP 4.0
+*
+* Revision 1.1.1.1 1999/03/17 04:29:11 andi
+* PHP4
+*
+* Revision 1.1.1.1 1998/12/21 07:56:22 andi
+* Trying to start the zend CVS tree
+*
+* Revision 1.1 1998/08/12 09:29:16 steinm
+* First version of Hyperwave module.
+*
+* Revision 1.5 91/12/31 19:39:49 kjb
+* Modified include file directories.
+*
+* Revision 1.4 91/10/28 03:16:39 kjb
+* Ported to the Iris.
+*
+* Revision 1.3 91/09/27 03:09:18 kjb
+* Cosmetic change.
+*
+* Revision 1.2 91/09/03 18:27:42 ROOT_DOS
+* Ported to UNIX.
+*
+* Revision 1.1 91/09/01 18:35:23 ROOT_DOS
+* Initial revision
+*
+****************************************************************************/
+
+#ifndef MSVC5
+#include "config.h"
+#endif
+
+#if HYPERWAVE
+
+#include <stdio.h>
+#include <malloc.h>
+#include <signal.h>
+#include "debug.h"
+#include "DList.h"
+
+PUBLIC void *dlst_newnode(int size)
+/****************************************************************************
+*
+* Function: dlst_newnode
+* Parameters: size - Amount of memory to allocate for node
+* Returns: Pointer to the allocated node's user space.
+*
+* Description: Allocates the memory required for a node, adding a small
+* header at the start of the node. We return a reference to
+* the user space of the node, as if it had been allocated via
+* malloc().
+*
+****************************************************************************/
+{
+ DLST_BUCKET *node;
+
+ if ( !(node = (DLST_BUCKET*)malloc(size + sizeof(DLST_BUCKET))) ) {
+ fprintf(stderr,"Not enough memory to allocate list node.\n");
+/* raise(SIGABRT);*/
+ return NULL;
+ }
+
+ return DLST_USERSPACE(node); /* Return pointer to user space */
+}
+
+PUBLIC void dlst_freenode(void *node)
+/****************************************************************************
+*
+* Function: dlst_freenode
+* Parameters: node - Node to free.
+*
+* Description: Frees a node previously allocated with lst_newnode().
+*
+****************************************************************************/
+{
+ free(DLST_HEADER(node));
+}
+
+PUBLIC DLIST *dlst_init(void)
+/****************************************************************************
+*
+* Function: dlst_init
+* Returns: Pointer to a newly created list.
+*
+* Description: Initialises a list and returns a pointer to it.
+*
+****************************************************************************/
+{
+ DLIST *l;
+
+ if ((l = (DLIST*)malloc(sizeof(DLIST))) != NULL) {
+ l->count = 0;
+ l->head = &(l->hz[0]);
+ l->z = &(l->hz[1]);
+ l->head->next = l->z->next = l->z;
+ l->z->prev = l->head->prev = l->head;
+ }
+ else {
+ fprintf(stderr,"Insufficient memory to allocate list\n");
+ /*raise(SIGABRT);*/
+ return NULL;
+ }
+
+ return l;
+}
+
+PUBLIC void dlst_kill(DLIST *l,void (*freeNode)(void *node))
+/****************************************************************************
+*
+* Function: dlst_kill
+* Parameters: l - List to kill
+* freeNode - Pointer to user routine to free a node
+*
+* Description: Kills the list l, by deleting all of the elements contained
+* within the list one by one and then deleting the list
+* itself. Note that we call the user supplied routine
+* (*freeNode)() to free each list node. This allows the user
+* program to perform any extra processing needed to kill each
+* node (if each node contains pointers to other items on the
+* heap for example). If no extra processing is required, just
+* pass the address of dlst_freenode(), ie:
+*
+* dlst_kill(myList,dlst_freenode);
+*
+****************************************************************************/
+{
+ DLST_BUCKET *n,*p;
+
+ n = l->head->next;
+ while (n != l->z) { /* Free all nodes in list */
+ p = n;
+ n = n->next;
+ (*freeNode)(DLST_USERSPACE(p));
+ }
+ free(l); /* Free the list itself */
+}
+
+PUBLIC void dlst_insertafter(DLIST *l,void *node,void *after)
+/****************************************************************************
+*
+* Function: lst_insertafter
+* Parameters: l - List to insert node into
+* node - Pointer to user space of node to insert
+* after - Pointer to user space of node to insert node after
+*
+* Description: Inserts a new node into the list after the node 'after'. To
+* insert a new node at the beginning of the list, user the
+* macro DLST_HEAD in place of 'after'. ie:
+*
+* dlst_insertafter(mylist,node,DLST_HEAD(mylist));
+*
+****************************************************************************/
+{
+ DLST_BUCKET *n = DLST_HEADER(node),*a = DLST_HEADER(after);
+
+ n->next = a->next;
+ a->next = n;
+ n->prev = a;
+ n->next->prev = n;
+ l->count++;
+}
+
+PUBLIC void *dlst_deletenext(DLIST *l,void *node)
+/****************************************************************************
+*
+* Function: lst_deletenext
+* Parameters: l - List to delete node from.
+* node - Node to delete the next node from
+* Returns: Pointer to the deleted node's userspace.
+*
+* Description: Removes the node AFTER 'node' from the list l.
+*
+****************************************************************************/
+{
+ DLST_BUCKET *n = DLST_HEADER(node);
+
+ node = DLST_USERSPACE(n->next);
+ n->next->next->prev = n;
+ n->next = n->next->next;
+ l->count--;
+ return node;
+}
+
+PUBLIC void *dlst_first(DLIST *l)
+/****************************************************************************
+*
+* Function: dlst_first
+* Parameters: l - List to obtain first node from
+* Returns: Pointer to first node in list, NULL if list is empty.
+*
+* Description: Returns a pointer to the user space of the first node in
+* the list. If the list is empty, we return NULL.
+*
+****************************************************************************/
+{
+ DLST_BUCKET *n;
+
+ n = l->head->next;
+ return (n == l->z ? NULL : DLST_USERSPACE(n));
+}
+
+PUBLIC void *dlst_last(DLIST *l)
+/****************************************************************************
+*
+* Function: dlst_last
+* Parameters: l - List to obtain last node from
+* Returns: Pointer to last node in list, NULL if list is empty.
+*
+* Description: Returns a pointer to the user space of the last node in
+* the list. If the list is empty, we return NULL.
+*
+****************************************************************************/
+{
+ DLST_BUCKET *n;
+
+ n = l->z->prev;
+ return (n == l->head ? NULL : DLST_USERSPACE(n));
+}
+
+PUBLIC void *dlst_next(void *prev)
+/****************************************************************************
+*
+* Function: dlst_next
+* Parameters: prev - Previous node in list to obtain next node from
+* Returns: Pointer to the next node in the list, NULL at end of list.
+*
+* Description: Returns a pointer to the user space of the next node in the
+* list given a pointer to the user space of the previous node.
+* If we have reached the end of the list, we return NULL. The
+* end of the list is detected when the next pointer of a node
+* points back to itself, as does the dummy last node's next
+* pointer. This enables us to detect the end of the list
+* without needed access to the list data structure itself.
+*
+* NOTE: We do no checking to ensure that 'prev' is NOT a
+* NULL pointer.
+*
+****************************************************************************/
+{
+ DLST_BUCKET *n = DLST_HEADER(prev);
+
+ n = n->next;
+ return (n == n->next ? NULL : DLST_USERSPACE(n));
+}
+
+PUBLIC void *dlst_prev(void *next)
+/****************************************************************************
+*
+* Function: dlst_prev
+* Parameters: next - Next node in list to obtain previous node from
+* Returns: Pointer to the previous node in the list, NULL at start list.
+*
+* Description: Returns a pointer to the user space of the prev node in the
+* list given a pointer to the user space of the next node.
+* If we have reached the start of the list, we return NULL. The
+* start of the list is detected when the prev pointer of a node
+* points back to itself, as does the dummy head node's prev
+* pointer. This enables us to detect the start of the list
+* without needed access to the list data structure itself.
+*
+* NOTE: We do no checking to ensure that 'next' is NOT a
+* NULL pointer.
+*
+****************************************************************************/
+{
+ DLST_BUCKET *n = DLST_HEADER(next);
+
+ n = n->prev;
+ return (n == n->prev ? NULL : DLST_USERSPACE(n));
+}
+
+/* Static globals required by merge() */
+
+static DLST_BUCKET *z;
+static int (*cmp)(void*,void*);
+
+PRIVATE DLST_BUCKET *merge(DLST_BUCKET *a,DLST_BUCKET *b,DLST_BUCKET **end)
+/****************************************************************************
+*
+* Function: merge
+* Parameters: a,b - Sublist's to merge
+* Returns: Pointer to the merged sublists.
+*
+* Description: Merges two sorted lists of nodes together into a single
+* sorted list.
+*
+****************************************************************************/
+{
+ DLST_BUCKET *c;
+
+ /* Go through the lists, merging them together in sorted order */
+
+ c = z;
+ while (a != z && b != z) {
+ if ((*cmp)(DLST_USERSPACE(a),DLST_USERSPACE(b)) <= 0) {
+ c->next = a; c = a; a = a->next;
+ }
+ else {
+ c->next = b; c = b; b = b->next;
+ }
+ };
+
+ /* If one of the lists is not exhausted, then re-attach it to the end
+ * of the newly merged list
+ */
+
+ if (a != z) c->next = a;
+ if (b != z) c->next = b;
+
+ /* Set *end to point to the end of the newly merged list */
+
+ while (c->next != z) c = c->next;
+ *end = c;
+
+ /* Determine the start of the merged lists, and reset z to point to
+ * itself
+ */
+
+ c = z->next; z->next = z;
+ return c;
+}
+
+PUBLIC void dlst_mergesort(DLIST *l,int (*cmp_func)(void*,void*))
+/****************************************************************************
+*
+* Function: dlst_mergesort
+* Parameters: l - List to merge sort
+* cmp_func - Function to compare two user spaces
+*
+* Description: Mergesort's all the nodes in the list. 'cmp' must point to
+* a comparison function that can compare the user spaces of
+* two different nodes. 'cmp' should work the same as
+* strcmp(), in terms of the values it returns. Rather than
+* waste processing time keeping the previous pointers up to
+* date while performing the mergesort, we simply run through
+* the list at the end of the sort to fix the previous pointers.
+*
+****************************************************************************/
+{
+ int i,N;
+ DLST_BUCKET *a,*b; /* Pointers to sublists to merge */
+ DLST_BUCKET *c; /* Pointer to end of sorted sublists */
+ DLST_BUCKET *head; /* Pointer to dummy head node for list */
+ DLST_BUCKET *todo; /* Pointer to sublists yet to be sorted */
+ DLST_BUCKET *t; /* Temporary */
+
+ /* Set up globals required by merge() and pointer to head */
+
+ z = l->z; cmp = cmp_func; head = l->head;
+
+ for (N = 1,a = z; a != head->next; N = N + N) {
+ todo = head->next; c = head;
+ while (todo != z) {
+
+ /* Build first sublist to be merged, and splice from main list
+ */
+
+ a = t = todo;
+ for (i = 1; i < N; i++) t = t->next;
+ b = t->next; t->next = z; t = b;
+
+ /* Build second sublist to be merged and splice from main list
+ */
+
+ for (i = 1; i < N; i++) t = t->next;
+ todo = t->next; t->next = z;
+
+ /* Merge the two sublists created, and set 'c' to point to the
+ * end of the newly merged sublists.
+ */
+
+ c->next = merge(a,b,&t); c = t;
+ }
+ }
+
+ /* Fix the previous pointers for the list */
+
+ a = b = l->head;
+ b = b->next;
+ while (1) {
+ b->prev = a;
+ if (b == z)
+ break;
+ a = a->next;
+ b = b->next;
+ }
+}
+
+#endif