/* ============================== dl.c ============================== */ #include "dl.h" void *malloc(); char *getnode(size) { DL_NODE *n; if (n = (DL_NODE *) malloc(size)) { memset(n, '\0', size); n->size = size; } return(n); } freenode(n) DL_NODE *n; { free(n); } /* * Create an empty list */ DLIST dl_create(flags) int flags; { DLIST l; if ((l = (DLIST) malloc(sizeof(struct dl))) == NULL) return NULL; l->head = l->tail = l->curr = NULL; l->size = 0; l->flags = flags; return(l); } /* * Free entire list */ dl_destroy(l) DLIST l; { while (dl_shead(l)) dl_delete(l); /* * it is assumed that the list head structure itself was * from dl_create, thus will always be free'd. */ free(l); } /* * Delete specific node */ dl_delete_node(l, n) DLIST l; DL_NODE *n; { if (n) { dl_detach_node(l, n); if ((l->flags & DL_FREE) == DL_FREE) freenode(n); } } /* * Delete node, but leave memory alone */ dl_detach_node(l, n) DLIST l; DL_NODE *n; { l->size--; l->curr = n->next; if (n->prev) n->prev->next = n->next; else l->head = n->next; if (n->next) n->next->prev = n->prev; else l->tail = n->prev; } /* * Insert node n before the current location in list l */ dl_ins_before_node(l, n_on_list, new_n) DLIST l; DL_NODE *n_on_list, *new_n; { l->size++; if (l->head == NULL) { l->head = l->tail = l->curr = new_n; new_n->next = new_n->prev = NULL; return; } dl_set(l, n_on_list); if (l->curr == NULL) l->curr = l->head; new_n->prev = l->curr->prev; new_n->next = l->curr; if (l->curr->prev) l->curr->prev->next = new_n; else l->head = new_n; /* else l->curr == l->head */ l->curr->prev = new_n; l->curr = new_n; } dl_ins_after_node(l, n_on_list, new_n) DLIST l; DL_NODE *n_on_list, *new_n; { l->size++; if (l->head == NULL) { l->head = l->tail = l->curr = new_n; new_n->next = new_n->prev = NULL; return; } dl_set(l, n_on_list); if (l->curr == NULL) l->curr = l->tail; new_n->prev = l->curr; new_n->next = l->curr->next; if (l->curr->next) l->curr->next->prev = new_n; else l->tail = new_n; /* else l->curr == l->tail */ l->curr->next = new_n; l->curr = new_n; } /* * Join l2 to the end of l1; l2 is no longer usable */ dl_cat(l1, l2) DLIST l1, l2; { l1->size += l2->size; l1->tail->next = l2->head; l2->head->prev = l1->tail; l1->tail = l2->tail; free(l2); } /* * Split list 'l' into two, so that 'n' is the first node of the new list, * return pointer to new list. */ /* Uncomment and do as exercise DLIST dl_split_at_node(l, n) DLIST l; DL_NODE *n; { DLIST newl; if ((newl = dl_create(dl_flags(l))) == NULL) return(NULL); newl->size = count from current pos to end l->size = count up to current pos (l->size - newl->size) adjust pointers (last of l, first of newl (i.e., n)) return newl } */ DLIST dl_copy(l) DLIST l; { DLIST newl; DL_NODE *n, *newn; if ((newl = dl_create(dl_flags(l))) == NULL) return(NULL); foreachnode(l, n) { newn = getnode(n->size); if (newn == NULL) { dl_destroy(newl); return(NULL); } memcpy(newn, n, n->size); /* copies ptrs, but is ok */ dl_append(newl, newn); } return(newl); } dl_compare(l1, l2, func) DLIST l1, l2; int (*func)(); { int comp; for (dl_shead(l1), dl_shead(l2); dl_curr(l1) && dl_curr(l2); dl_snext(l1), dl_snext(l2)) if ((comp = (*func)(dl_curr(l1), dl_curr(l2))) != 0) return(comp); if (dl_curr(l1)) return(1); /* l2 ran out first */ else if (dl_curr(l2)) return(-1); /* l1 ran out first */ else return(0); /* both ran out at same time */ } dl_apply(l, func, arg) DLIST l; int (*func)(); char *arg; { foreach(l) (*func)(dl_curr(l), arg); } /* * Do a linear search on the list, given a start/end point */ dl_lsearch(l, begin, end, key, func) DLIST l; DL_NODE *begin, *end; void *key; int (*func)(); { DL_NODE *n; for (n = begin; n != end; n = n->next) if ((*func)(n, key)) { l->curr = n; return(TRUE); } return(FALSE); } /* * dl_sort - take a list and a 'qsort' type cmp func & sort * * since we make an array of ptrs, qsort really needs a cmp func * that follows a pointer to pointer to user struct; but this is * ugly for users, so dl_sort_cmp_fun does one indirection then * calls the users cmp func. */ static int (*dl_sort_user_cmp_fun)(); dl_sort_cmp_fun(p1, p2) DL_NODE **p1, **p2; { return((*dl_sort_user_cmp_fun)(*p1, *p2)); } dl_sort(l, func) DLIST l; int (*func)(); { DL_NODE **array; int i, last; if (l->size <= 1) return(0); if ((array = dl_l2a(l)) == NULL) return(-1); dl_sort_user_cmp_fun = func; qsort(array, l->size, sizeof(DL_NODE *), dl_sort_cmp_fun); dl_a2l(l, array); free(array); return(0); } /* from a list, make an array of pointers to the list items */ DL_NODE ** dl_l2a(l) DLIST l; { DL_NODE *n, **array, **a; array = (DL_NODE **) malloc(l->size*sizeof(DL_NODE *)); if (array == NULL) return(NULL); for (n = l->head, a = array; n != NULL; n = n->next, a++) *a = n; return(array); } /* turn an array of pointers to the list items into a list */ dl_a2l(l, array) DLIST l; DL_NODE **array; { int i, last; l->head = array[0]; l->head->prev = NULL; l->head->next = array[1]; last = l->size - 1; for (i = 1; i < last; i++) { array[i]->next = array[i+1]; array[i]->prev = array[i-1]; } l->tail = array[last]; l->tail->next = NULL; l->tail->prev = array[last-1]; }