home *** CD-ROM | disk | FTP | other *** search
- /***( dllist.c )****************************************************************
- * *
- * Contains generic doubly-linked list functions. *
- * *
- ********************************************************************************
- * *
- * Written: Dec 7, 1989 - SBF *
- * Updated: Dec 14, 1989 - SBF ( added dll_getpos and dll_setpos ) *
- * Dec 27, 1989 - SBF ( added dll_rebuild ) *
- * MMM DD, YYYY - XXX ( ) *
- * *
- *******************************************************************************/
- #include <stdio.h>
- #include <bench.h>
- #include <dllist.h>
-
- #ifdef ANSI
- int rebuild_cmp(); /*generic **, generic **);*/
- #else
- int rebuild_cmp();
- #endif
-
- struct dll_cb *dll_cb[MAXNUMDLL];
-
- /*
- * dll_add() - Add an entry to the list, according to the comparison function
- * passed into dll_open(), or in un-sorted order
- */
- int dll_add(dll_d, ptr, add_mode)
- int dll_d; /* Handle for list to use */
- generic *ptr; /* Pointer to entry to add */
- int add_mode; /* ADD_SORT or ADD_NOSORT */
- {
- register struct dll_entry *deptr; /* Pointer to current or new list entry */
- struct dll_entry *denext; /* Pointer to next list entry */
- struct dll_entry *deprev; /* Pointer to previous list entry */
- register struct dll_cb *cb; /* Pointer to list control block */
-
- if ((cb = dll_cb[dll_d]) == NULL) /* Check validity of control block */
- return(-1);
-
- if (cb->dll_head == NULL) /* Add the first entry (head is NULL) */
- {
- cb->dll_head = deptr = (struct dll_entry *)alloc(sizeof(struct dll_entry));
- if (cb->dll_head == NULL) /* Alloc failed */
- return(-1);
-
- cb->dll_head->dll_ptr = (generic *)alloc(cb->dll_size);
- if (cb->dll_head->dll_ptr == NULL)
- return(-1);
-
- cb->dll_head->dll_next = NULL; /* Next of tail is NULL */
- cb->dll_head->dll_prev = cb->dll_head; /* Prev of head is tail */
- memcpy((char *)cb->dll_head->dll_ptr, (char *)ptr, cb->dll_size);
- }
- else /* Insert entry into list according to compare function */
- {
- if (add_mode == ADD_SORT)
- {
- for (deptr = cb->dll_head; deptr != NULL; deptr = deptr->dll_next)
- {
- if ((*cb->dll_cmp)(deptr->dll_ptr, ptr) < 0)
- continue;
- else
- {
- denext = deptr; /* Save prev and next */
- deprev = deptr->dll_prev;
- /* Allocate entry */
- deptr = (struct dll_entry *)alloc(sizeof(struct dll_entry));
- if (deptr == NULL)
- return(-1);
-
- deptr->dll_ptr = (generic *)alloc(cb->dll_size);
- if (deptr->dll_ptr == NULL)
- return(-1);
-
- if (denext == cb->dll_head) /* Is it a new head? */
- cb->dll_head = deptr;
-
- deptr->dll_next = denext; /* Set next and prev and save data */
- deptr->dll_prev = deprev;
- memcpy((char *)deptr->dll_ptr, (char *)ptr, cb->dll_size);
-
- denext->dll_prev = deptr;
-
- if (cb->dll_head != deptr)
- deprev->dll_next = deptr;
-
- break;
- }
- }
- }
- else
- deptr = NULL;
-
- if (deptr == NULL) /* This entry is a new tail */
- {
- deprev = cb->dll_head->dll_prev; /* Save prev and allocate an entry */
- deptr = (struct dll_entry *)alloc(sizeof(struct dll_entry));
- if (deptr == NULL)
- return(-1);
-
- deptr->dll_ptr = (generic *)alloc(cb->dll_size);
- if (deptr->dll_ptr == NULL)
- return(-1);
- /* Set tail pointer (head->prev) */
- cb->dll_head->dll_prev = deprev->dll_next = deptr;
-
- deptr->dll_next = NULL; /* Set next and prev and save data */
- deptr->dll_prev = deprev;
- memcpy((char *)deptr->dll_ptr, (char *)ptr, cb->dll_size);
- }
- }
-
- cb->dll_curr = deptr;
-
- return(0);
- }
-
- /*
- * dll_close() - Close a doubly-linked list
- */
- int dll_close(dll_d)
- int dll_d; /* Handle of control block for list to close */
- {
- register struct dll_cb *cb; /* Pointer to control block */
- register struct dll_entry *deptr; /* Pointer to current item in list */
- struct dll_entry *denext; /* Pointer to next item in list */
- struct dll_entry *detail = NULL; /* Pointer to tail of list */
- struct dll_entry *delast = NULL; /* Pointer to last entry freed */
-
- if ((cb = dll_cb[dll_d]) == NULL) /* Check for valid list handle */
- return(-1);
-
- if (cb->dll_head != NULL) /* Free the list if it has entries */
- {
- detail = cb->dll_head->dll_prev; /* Save the tail */
-
- for (deptr = cb->dll_head; deptr != NULL; deptr = denext)
- {
- denext = deptr->dll_next; /* Free one entry after another */
- free(deptr->dll_ptr);
- free(deptr);
- delast = deptr; /* Save last entry freed */
- }
- }
-
- free(cb); /* Free the actual control block */
- dll_cb[dll_d] = NULL; /* Make the pointer usable again */
-
- if (delast != detail) /* Consistancy check - was the tail the last freed? */
- return(-1);
- else
- return(0);
- }
-
- /*
- * dll_curr() - Get current list entry
- */
- generic *dll_curr(dll_d)
- int dll_d;
- {
- return(dll_seek(dll_d, 0, SEEK_CUR));
- }
-
- /*
- * dll_del() - Delete the current list item
- */
- int dll_del(dll_d)
- int dll_d; /* Handle for control block */
- {
- register struct dll_cb *cb; /* Pointer to control block */
- register struct dll_entry *decurr; /* Pointer to current entry */
- struct dll_entry *deprev; /* Pointer to previous entry */
- struct dll_entry *denext; /* Pointer to next entry */
-
- if ((cb = dll_cb[dll_d]) == NULL) /* Check for valid handle */
- return(-1);
-
- if (cb->dll_curr == NULL) /* Check for current entry */
- return(-1);
-
- decurr = cb->dll_curr; /* Save current, prev and next */
- deprev = decurr->dll_prev;
- denext = decurr->dll_next;
-
- if (decurr != cb->dll_head) /* Curr is not head so set prev->next */
- deprev->dll_next = decurr->dll_next;
-
- if (denext != NULL) /* Tail delete needs head->prev set */
- denext->dll_prev = decurr->dll_prev;
- else
- cb->dll_head->dll_prev = deprev;
-
- if (decurr == cb->dll_head) /* Head delete needs head reset */
- {
- cb->dll_head = denext;
- cb->dll_curr = NULL; /* Set curr to NULL (for dll_next()) */
- }
- else
- cb->dll_curr = deprev; /* Set curr to prev (for dll_next()) */
-
- free(decurr->dll_ptr); /* Actually free entry */
- free(decurr);
-
- return(0);
- }
-
- /*
- * dll_find() - Find a list entry with given data
- */
- generic *dll_find(dll_d, ptr)
- int dll_d; /* Handle for control block */
- generic *ptr; /* Pointer to data to find */
- {
- register struct dll_cb *cb; /* Pointer to control block */
- register struct dll_entry *deptr; /* Pointer to entry being compared */
-
- if ((cb = dll_cb[dll_d]) == NULL) /* Check for valid handle */
- return(NULL);
-
- /* Find an equal entry */
- for (deptr = cb->dll_head; deptr != NULL; deptr = deptr->dll_next)
- if ((*cb->dll_cmp)(deptr->dll_ptr, ptr) == 0)
- break;
-
- if (deptr == NULL) /* No entry found (return NULL) */
- return(NULL);
-
- cb->dll_curr = deptr; /* Set current entry to the found one */
- return(deptr->dll_ptr); /* Return pointer to data */
- }
-
- /*
- * dll_getpos() - Get current position (actual list pointer)
- */
- struct dll_entry *dll_getpos(dll_d)
- int dll_d; /* List handle */
- {
- if (dll_cb[dll_d] == NULL) /* Check for valid list handle */
- return(NULL);
-
- return(dll_cb[dll_d]->dll_curr); /* Return current entry pointer */
- }
-
- /*
- * dll_open() - Open a doubly-linked list
- */
- int dll_open(cmp, size)
- int (*cmp)(); /* Comparison function for add/find */
- int size; /* Size of data in list */
- {
- register int dll_d; /* Handle for control block */
- register struct dll_cb *cb; /* Pointer to control block */
-
- for (dll_d = 0; dll_d < MAXNUMDLL; dll_d++)
- if (dll_cb[dll_d] == NULL) /* Find a free control block */
- break;
-
- if (dll_d == MAXNUMDLL) /* No free ones left */
- return(-1);
-
- cb = dll_cb[dll_d] = (struct dll_cb *)alloc(sizeof(struct dll_cb));
- if (cb == NULL) /* Alloc failed */
- return(-1);
-
- cb->dll_head = NULL; /* Initialize control block */
- cb->dll_curr = NULL;
- cb->dll_cmp = cmp;
- cb->dll_size = size;
-
- return(dll_d); /* Return handle for control block used */
- }
-
- /*
- * dll_next() - Get next entry in list
- */
- generic *dll_next(dll_d)
- int dll_d; /* Handle for control block */
- {
- register struct dll_cb *cb; /* Pointer to control block */
-
- if ((cb = dll_cb[dll_d]) == NULL) /* Check for valid handle */
- return(NULL);
-
- if (cb->dll_head == NULL) /* Check for empty list */
- return(NULL);
-
- if (cb->dll_curr == NULL) /* New list or head deleted */
- cb->dll_curr = cb->dll_head; /* So... jump to head */
- else
- {
- if (cb->dll_curr->dll_next == NULL) /* At tail already (return NULL) */
- return(NULL);
-
- cb->dll_curr = cb->dll_curr->dll_next; /* Jump to next entry */
- }
-
- return(cb->dll_curr->dll_ptr); /* Return pointer to data */
- }
-
- /*
- * dll_prev() - Get previous entry in list
- */
- generic *dll_prev(dll_d)
- int dll_d; /* Handle of control block */
- {
- register struct dll_cb *cb; /* Pointer to control block */
-
- if ((cb = dll_cb[dll_d]) == NULL) /* Check for valid handle */
- return(NULL);
-
- /* List is empty or current entry isn't defined*/
- if (cb->dll_head == NULL || cb->dll_curr == NULL)
- return(NULL);
-
- if (cb->dll_curr == cb->dll_head) /* Already at head of list */
- return(NULL);
-
- cb->dll_curr = cb->dll_curr->dll_prev; /* Jump to previous entry */
- return(cb->dll_curr->dll_ptr); /* Return pointer to data */
- }
-
- /*
- * Stuff required by dll_rebuild
- */
- #ifdef ANSI
- static int (*new_cmp)(generic *, generic *);
- #else
- static int (*new_cmp)();
- #endif
-
- int rebuild_cmp(ptr1, ptr2)
- generic **ptr1, **ptr2;
- {
- return(new_cmp(*ptr1, *ptr2));
- }
-
- /*
- * dll_rebuild() - Sort a list using a new cmp() function and make the new
- * function the active comparison function
- */
- int dll_rebuild(dll_d, cmp)
- int dll_d;
- int (*cmp)();
- {
- register struct dll_cb *cb;
- generic **dat_array;
- struct dll_entry *dllptr;
- int numentries = 0;
- int datctr;
-
- if ((cb = dll_cb[dll_d]) == NULL)
- return(-1);
-
- for(dllptr = cb->dll_head; dllptr != NULL; dllptr = dllptr->dll_next)
- numentries++;
-
- if (numentries > 1)
- {
- dat_array = (generic **)alloc(numentries * sizeof(generic *));
- if (dat_array == NULL)
- return(-1);
-
- for(dllptr = cb->dll_head, datctr = 0; dllptr != NULL; dllptr = dllptr->dll_next, datctr++)
- dat_array[datctr] = dllptr->dll_ptr;
-
- new_cmp = cmp;
- qsort(dat_array, numentries, sizeof(generic *), rebuild_cmp);
-
- for(dllptr = cb->dll_head, datctr = 0; dllptr != NULL; dllptr = dllptr->dll_next, datctr++)
- dllptr->dll_ptr = dat_array[datctr];
-
- free(dat_array);
- }
-
- cb->dll_cmp = cmp;
- return(0);
- }
-
- /*
- * dll_seek() - Seek a given number of entries from a specified position
- */
- generic *dll_seek(dll_d, offset, origin)
- int dll_d; /* Handle for control block */
- int offset; /* Number of entries to seek */
- int origin; /* Origin to seek from */
- {
- register struct dll_cb *cb; /* Pointer to control block */
- generic *seekptr; /* Pointer to current data */
- int seekctr; /* Counter for number of next's or prev's */
- struct dll_entry *desave; /* Pointer to old current record */
-
- if ((cb = dll_cb[dll_d]) == NULL) /* Check for valid handle */
- return(NULL);
-
- if (cb->dll_head == NULL) /* Check for empty list */
- return(NULL);
-
- desave = cb->dll_curr; /* Save the current entry */
-
- switch(origin)
- {
- case SEEK_SET: /* Seek from head */
- cb->dll_curr = cb->dll_head;
- break;
- case SEEK_CUR: /* Seek from current entry */
- if (cb->dll_curr == NULL)
- return(NULL);
- break;
- case SEEK_END: /* Seek from tail */
- cb->dll_curr = cb->dll_head->dll_prev;
- break;
- default: /* Unrecognized origin */
- return(NULL);
- }
-
- seekptr = cb->dll_curr->dll_ptr; /* Current data here */
-
- for(seekctr = 0; seekctr < abs(offset); seekctr++)/* Seek 'offset' entries */
- {
- if (offset < 0) /* Negative offset is dll_prev() */
- seekptr = dll_prev(dll_d);
- else /* Positive offset is dll_next() */
- seekptr = dll_next(dll_d);
-
- if (seekptr == NULL) /* If error seeking restore current entry */
- {
- cb->dll_curr = desave;
- break;
- }
- }
-
- return(seekptr); /* Return pointer to data or NULL if error seeking */
- }
-
- /*
- * dll_setpos() - set current position (actual list pointer)
- */
- int dll_setpos(dll_d, dll_pos)
- int dll_d; /* List handle */
- struct dll_entry *dll_pos; /* Pointer to list entry */
- {
- if (dll_cb[dll_d] == NULL) /* Check for valid handle */
- return(-1);
-
- if (dll_pos == NULL)
- return(-1);
-
- dll_cb[dll_d]->dll_curr = dll_pos; /* Set current position */
-
- return(0);
- }
-