| /* $Header: /usr/sctpCVS/APPS/baselib/llist.c,v 1.3 2008-12-26 14:45:12 randall Exp $ */ |
| |
| /* |
| * Copyright (C) 2002 Cisco Systems Inc, |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of the project nor the names of its contributors |
| * may be used to endorse or promote products derived from this software |
| * without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
| * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
| * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
| * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
| * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| */ |
| |
| #include "llist.h" |
| |
| llist_t * |
| llist_create() |
| { |
| llist_t *o; |
| |
| o = (llist_t *) CALLOC(1, sizeof(llist_t)); |
| if (o == NULL) |
| return (NULL); |
| o->curr = o->currm1 = NULL; |
| o->cntIn = 0; |
| o->n2last = o->last = NULL; |
| o->wrapFlag = 0; |
| return (o); |
| } |
| |
| void |
| llist_destroy(llist_t * o) |
| { |
| if (o == NULL) |
| return; |
| |
| llist_clear(o); |
| FREE(o); |
| } |
| |
| int |
| llist_append(llist_t * o, void *a) |
| { |
| llist_slink *tmp; |
| |
| if (o == NULL) |
| return (LIB_STATUS_BAD); |
| |
| if (o->last) { |
| /* entries in the list */ |
| o->n2last = o->last; |
| tmp = (llist_slink *) CALLOC(1, sizeof(llist_slink)); |
| if (tmp == NULL) { |
| return (LIB_STATUS_BAD); |
| } |
| tmp->ent = a; |
| tmp->next = o->last->next; |
| o->last->next = tmp; |
| o->last = tmp; |
| } else { |
| /* no entires in the list */ |
| o->n2last = o->last = (llist_slink *) CALLOC(1, sizeof(llist_slink)); |
| if (o->last == NULL) { |
| return (LIB_STATUS_BAD); |
| } |
| o->last->ent = a; |
| o->last->next = NULL; |
| o->last->next = o->last; |
| } |
| o->cntIn++; |
| return (LIB_STATUS_GOOD); |
| } |
| |
| int |
| llist_appendslink(llist_t * o, llist_slink * a) |
| { |
| if (o == NULL) |
| return (LIB_STATUS_BAD); |
| |
| if (a == NULL) |
| /* |
| * We don't allow a NULL llist_slink struct to be entered in |
| * the list |
| */ |
| return (LIB_STATUS_BAD); |
| |
| if (o->last) { |
| /* one or more entries in the list */ |
| o->n2last = o->last; |
| a->next = o->last->next; |
| o->last->next = a; |
| o->last = a; |
| } else { |
| /* no entries in list. */ |
| o->n2last = o->last = a; |
| o->last->next = o->last; |
| } |
| o->cntIn++; |
| return (LIB_STATUS_GOOD); |
| } |
| |
| int |
| llist_insert(llist_t * o, void *a) |
| { |
| llist_slink *tmp; |
| |
| if (o == NULL) |
| return (LIB_STATUS_BAD); |
| |
| if (o->last) { |
| tmp = (llist_slink *) CALLOC(1, sizeof(llist_slink)); |
| if (tmp == NULL) { |
| return (LIB_STATUS_BAD); |
| } |
| tmp->ent = a; |
| tmp->next = o->last->next; |
| o->last->next = tmp; |
| } else { |
| o->n2last = o->last = (llist_slink *) CALLOC(1, sizeof(llist_slink)); |
| if (o->last == NULL) { |
| return (LIB_STATUS_BAD); |
| } |
| o->last->ent = a; |
| o->last->next = NULL; |
| o->last->next = o->last; |
| } |
| o->cntIn++; |
| return (LIB_STATUS_GOOD); |
| } |
| |
| void |
| llist_clear(llist_t * o) |
| { |
| void *pp; |
| |
| if (o == NULL) |
| return; |
| |
| while ((pp = llist_getNext(o)) != NULL) { |
| pp = NULL; |
| } |
| o->n2last = o->last = NULL; |
| o->curr = o->currm1 = NULL; |
| } |
| |
| void * |
| llist_getNext(llist_t * o) |
| { |
| llist_slink *f; |
| void *r; |
| |
| if (o == NULL) |
| return (NULL); |
| |
| /* check if we have any in the list */ |
| if (o->last == NULL) |
| return (NULL); |
| |
| /* ok save off some pointers */ |
| f = o->last->next; |
| r = f->ent; |
| f->ent = NULL; |
| |
| /* now is this the last one? */ |
| if (f == o->last) { |
| /* yep, none left after this */ |
| o->n2last = o->last = NULL; |
| o->curr = o->currm1 = NULL; |
| } else { |
| if (o->n2last == o->last->next) { |
| /* |
| * Yes, Removing next to last one. We cheat here and |
| * just move n2last to the last one. |
| */ |
| o->n2last = o->last; |
| } |
| o->last->next = f->next; |
| f->next = NULL; |
| } |
| /* FREE up the memory */ |
| FREE(f); |
| f = NULL; |
| /* reduce number in */ |
| o->cntIn--; |
| /* and out goes the stored entry */ |
| return (r); |
| } |
| |
| llist_slink * |
| llist_getNextSlist(llist_t * o) |
| { |
| llist_slink *f; |
| |
| if (o == NULL) |
| return (NULL); |
| |
| /* is there one to pull? */ |
| if (o->last == NULL) |
| return (NULL); |
| |
| f = o->last->next; |
| if (f == o->last) { |
| /* last one turn off the lights */ |
| o->n2last = o->curr = o->currm1 = o->last = NULL; |
| } else { |
| if (o->last->next == o->n2last) { |
| /* cheat again */ |
| o->n2last = o->last; |
| } |
| o->last->next = f->next; |
| } |
| f->next = NULL; |
| o->cntIn--; |
| return (f); |
| } |
| |
| |
| void * |
| llist_get(llist_t * o) |
| { |
| if (o == NULL) |
| return (NULL); |
| |
| /* any in the list? */ |
| if (o->last == NULL) |
| /* no */ |
| return (NULL); |
| |
| if (o->wrapFlag) { |
| /* we have wrapped. we only return NULL once at wrap. */ |
| o->wrapFlag = 0; |
| /* setup so we will rewind to start */ |
| o->curr = o->currm1 = NULL; |
| return (NULL); |
| } |
| if ((o->curr == NULL) || (o->currm1 == NULL)) { |
| /* rewind to start */ |
| o->curr = o->last->next; |
| o->currm1 = o->last; |
| if (o->curr == o->last) { |
| /* only one in list so set the wrapFlag */ |
| o->wrapFlag = 1; |
| } |
| return (o->curr->ent); |
| } |
| /* ok setup to return the next value */ |
| o->currm1 = o->curr; |
| o->curr = o->curr->next; |
| if (o->curr == NULL) { |
| return (NULL); |
| } |
| if (o->curr == o->last) { |
| /* gotten all the way around so set the flag */ |
| o->wrapFlag = 1; |
| } |
| return (o->curr->ent); |
| } |
| |
| void * |
| llist_getThis(llist_t * o) |
| { |
| void *r; |
| |
| if (o == NULL) |
| return (NULL); |
| |
| /* some in list? */ |
| if (o->last == NULL) |
| /* no */ |
| return (NULL); |
| |
| if ((o->curr == NULL) || (o->currm1 == NULL)) { |
| /* start at the beginning */ |
| o->curr = o->last->next; |
| o->currm1 = o->last; |
| } |
| /* get off the entry to return */ |
| r = o->curr->ent; |
| /* null it */ |
| o->curr->ent = NULL; |
| |
| if (o->currm1 == o->curr) { |
| /* only one item in list */ |
| FREE(o->last); |
| o->n2last = o->curr = o->currm1 = o->last = NULL; |
| } else { |
| if (o->last == o->curr) { |
| /* reset to next to last one. */ |
| o->last = o->currm1; |
| if ((o->cntIn - 1) > 1) { |
| llist_slink *temp; |
| |
| /* Special case I must fix n2last */ |
| for (temp = o->last->next; temp != o->last; temp = temp->next) { |
| /* |
| * Hunt until we get temp->next is |
| * last then we are at last -1. |
| */ |
| if (temp->next == o->last) { |
| o->n2last = temp; |
| break; |
| } |
| } |
| } |
| } |
| o->currm1->next = o->curr->next; |
| o->curr->next = NULL; |
| FREE(o->curr); |
| o->curr = o->currm1->next; |
| } |
| o->cntIn--; |
| return (r); |
| } |
| |
| int |
| llist_backUpOne(llist_t * o) |
| { |
| llist_slink *temp; |
| |
| if (o == NULL) |
| return (LIB_STATUS_BAD); |
| |
| if (o->cntIn < 2) { |
| /* can't back up if there are not at least 2. */ |
| return (LIB_STATUS_BAD); |
| } |
| for (temp = o->curr; temp->next != o->curr; temp = temp->next) { |
| /* move through list. */ |
| if (temp->next == o->currm1) { |
| o->curr = o->currm1; |
| o->currm1 = temp; |
| return (LIB_STATUS_GOOD); |
| } |
| } |
| return (LIB_STATUS_BAD); |
| } |
| |
| void * |
| llist_replaceThis(llist_t * o, void *e) |
| { |
| void *r; |
| |
| if (o == NULL) |
| return (NULL); |
| |
| /* Any in the list? */ |
| if (o->last == NULL) |
| /* no */ |
| return (NULL); |
| |
| if ((o->curr == NULL) || (o->currm1 == NULL)) { |
| o->curr = o->last->next; |
| o->currm1 = o->last; |
| } |
| r = o->curr->ent; |
| o->curr->ent = e; |
| return (r); |
| } |
| |
| llist_slink * |
| llist_getThisSlist(llist_t * o) |
| { |
| llist_slink *r; |
| |
| /* any in list? */ |
| if (o->last == NULL) |
| return (NULL); |
| |
| /* setup the pointers as necessary */ |
| if ((o->curr == NULL) || (o->currm1 == NULL)) { |
| o->curr = o->last->next; |
| o->currm1 = o->last; |
| } |
| r = o->curr; |
| if (o->currm1 == o->curr) { |
| /* only one item in list */ |
| o->curr = o->currm1 = o->last = NULL; |
| } else { |
| if (o->last == o->curr) { |
| /* reset to next to last one. */ |
| o->last = o->currm1; |
| if ((o->cntIn - 1) > 1) { |
| llist_slink *temp; |
| |
| /* Special case I must fix n2last */ |
| for (temp = o->last->next; temp != o->last; temp = temp->next) { |
| /* |
| * Hunt until we get temp->next is |
| * last then we are at last -1. |
| */ |
| if (temp->next == o->last) { |
| o->n2last = temp; |
| break; |
| } |
| } |
| } |
| } |
| o->currm1->next = o->curr->next; |
| o->curr->next = NULL; |
| o->curr = o->currm1->next; |
| } |
| o->cntIn--; |
| return (r); |
| } |
| |
| void |
| llist_reset(llist_t * o) |
| { |
| if (o == NULL) |
| return; |
| |
| o->curr = o->currm1 = NULL; |
| o->wrapFlag = 0; |
| return; |
| } |
| |
| int |
| llist_insertHere(llist_t * o, void *a) |
| { |
| llist_slink *tmp; |
| |
| if (o == NULL) |
| return (LIB_STATUS_BAD); |
| |
| if (o->currm1) { |
| tmp = (llist_slink *) CALLOC(1, sizeof(llist_slink)); |
| if (tmp == NULL) { |
| return (LIB_STATUS_BAD); |
| } |
| tmp->ent = a; |
| tmp->next = o->currm1->next; |
| if (o->currm1 == o->n2last) { |
| /* Put in right before last. */ |
| o->n2last = tmp; |
| } |
| o->currm1->next = tmp; |
| } else { |
| /* |
| * List is reset so we drop to a typical insert. |
| */ |
| return (llist_insert(o, a)); |
| } |
| o->cntIn++; |
| return (LIB_STATUS_GOOD); |
| } |
| |
| int |
| llist_appendHere(llist_t * o, void *a) |
| { |
| llist_slink *tmp; |
| |
| if (o == NULL) |
| return (LIB_STATUS_BAD); |
| |
| if (o->curr) { |
| if (o->curr == o->currm1) { |
| /* |
| * special case for only one item on list just do a |
| * append. |
| */ |
| return (llist_append(o, a)); |
| } else if (o->curr == o->last) { |
| /* |
| * special case where the pointers are set to the |
| * last one so it degenerates to a simple append |
| */ |
| return (llist_append(o, a)); |
| } else { |
| /* |
| * ok the curr is out in the list somewhere. Append |
| * at where we are. |
| */ |
| tmp = (llist_slink *) CALLOC(1, sizeof(struct llist_slink)); |
| if (tmp == NULL) { |
| return (LIB_STATUS_BAD); |
| } |
| tmp->ent = a; |
| tmp->next = o->curr->next; |
| if (o->curr == o->n2last) |
| /* putting it after n2last. */ |
| o->n2last = tmp; |
| o->curr->next = tmp; |
| } |
| } else { |
| /* |
| * degenerate to an append if list as not been touched |
| */ |
| return (llist_append(o, a)); |
| |
| } |
| o->cntIn++; |
| return (LIB_STATUS_GOOD); |
| } |
| |
| void |
| llist_printCnt(llist_t * o) |
| { |
| if (o == NULL) |
| return; |
| |
| printf("On queue %d\n", o->cntIn); |
| } |
| |
| void |
| llist_printList(llist_t * o) |
| { |
| llist_slink *ll, *pp; |
| int i; |
| |
| if (o == NULL) |
| return; |
| |
| if (o->last == NULL) { |
| printf("List is empty\n"); |
| return; |
| } else { |
| printf("There are %d items on the list\n", o->cntIn); |
| } |
| ll = o->last->next; |
| i = 0; |
| do { |
| printf("%d:Me %p Entry %p Next->%p\n", |
| i, ll, ll->ent, ll->next); |
| pp = ll->next; |
| ll = pp; |
| i++; |
| } while (ll != o->last); |
| printf("%d:Me %p Entry %p Next->%p\n", |
| i, o->last, o->last->ent, o->last->next); |
| printf("List ends\n"); |
| } |
| |
| int |
| llist_getToTheEnd(llist_t * o) |
| { |
| if (o == NULL) |
| return (LIB_STATUS_BAD); |
| |
| if (o->last == NULL) |
| return (0); |
| o->wrapFlag = 0; |
| o->curr = o->last; |
| if ((o->n2last == o->curr) && (o->cntIn > 1)) { |
| llist_slink *temp; |
| |
| /* Special case I must fix n2last */ |
| for (temp = o->last->next; temp != o->last; temp = temp->next) { |
| /* |
| * Hunt until we get temp->next is last then we are |
| * at last -1. |
| */ |
| if (temp->next == o->last) { |
| o->n2last = temp; |
| break; |
| } |
| } |
| } |
| o->currm1 = o->n2last; |
| return (1); |
| } |
| |
| void * |
| llist_lookLastOne(llist_t * o) |
| { |
| if (o == NULL) |
| return (NULL); |
| |
| if (o->last == NULL) |
| return (NULL); |
| return (o->last->ent); |
| } |
| |
| void * |
| llist_lookN2LastOne(llist_t * o) |
| { |
| if (o == NULL) |
| return (NULL); |
| |
| if (o->n2last == NULL) |
| return (NULL); |
| return (o->n2last->ent); |
| } |
| |
| int |
| llist_getCnt(llist_t * o) |
| { |
| if (o == NULL) |
| return (0); |
| |
| return o->cntIn; |
| } |