#include #include #include #include "request_list.h" typedef struct _rlist_node { request data; struct _rlist_node *next; struct _rlist_node *prev; } rlist_node; struct _rlist { int size; int max; rlist_node *head; rlist_node *tail; }; struct _rlist_iterator { rlist *el; rlist_node *curr; }; rlist *rlist_create(int max) { rlist *el = malloc(sizeof(rlist)); if (el != NULL) { // initialize size and max el->size = 0; el->max = max; // create two dummy nodes for head and tail (these dummy nodes // contain no data; always having a head and tail eliminates // special cases from add and remove) el->head = malloc(sizeof(rlist_node)); el->tail = malloc(sizeof(rlist_node)); // make sure malloc succeeded if (el->head == NULL || el->tail == NULL) { free(el->head); free(el->tail); free(el); return NULL; } // link dummy head and tail together el->head->next = el->tail; el->head->prev = NULL; el->tail->prev = el->head; el->tail->next = NULL; // NULL out data in dummy head and tail (so they don't need // special treatment in destroy) el->head->data.user = NULL; el->head->data.position = NULL; el->tail->data.user = NULL; el->tail->data.position = NULL; } return el; } void rlist_destroy(rlist *el) { if (el != NULL) { // iterate through all nodes still remaining rlist_node *curr = el->head; while (curr != NULL) { // free data in those nodes free(curr->data.user); free(curr->data.position); // remember a pointer to the next node rlist_node *next = curr->next; // free the current node free(curr); // go to the next node curr = next; } // zero out the list to make it more obviously wrong when // someone tries to use a list that has just been destroyed el->size = 0; el->head = NULL; el->tail = NULL; // free the list free(el); } } int rlist_size(const rlist *el) { if (el != NULL) { return el->size; } else { return 0; } } bool rlist_add(rlist *el, const request *r) { if (el == NULL || r == NULL || r->user == NULL || r->position == NULL) { return false; } else { // make new node rlist_node *node = malloc(sizeof(rlist_node)); // copy data into new node (with error checking on malloc) char *copy_user = malloc(sizeof(char) * (strlen(r->user) + 1)); char *copy_pos = malloc(sizeof(char) * (strlen(r->position) + 1)); if (node == NULL || copy_user == NULL || copy_pos == NULL) { free(node); free(copy_user); free(copy_pos); return false; } strcpy(copy_user, r->user); strcpy(copy_pos, r->position); node->data.user = copy_user; node->data.position = copy_pos; // link new node just before dummy taile node->next = el->tail; node->prev = el->tail->prev; el->tail->prev->next = node; el->tail->prev = node; // update size el->size++; return true; } } void rlist_get(const rlist *el, int i, request *r) { // check preconditions if (el == NULL || r == NULL || i < 0 || i >= el->size) { return; } // position pointer at desired node rlist_node *curr = el->head->next; for (int j = 0; j < i; j++) { curr = curr->next; } // copy data from that node into request pointed to by r r->user = malloc(strlen(curr->data.user) + 1); r->position = malloc(strlen(curr->data.position) + 1); if (r->user != NULL && r->position != NULL) { strcpy(r->position, curr->data.position); strcpy(r->user, curr->data.user); } else { // error allocating space for copy of data free(r->user); free(r->position); r->user = NULL; r->position = NULL; } } rlist_iterator *rlist_start(rlist *el) { // check preconditions if (el == NULL) { return NULL; } // allocate space and initialize to 1st data node (node after dummy head) rlist_iterator *i = malloc(sizeof(rlist_iterator)); if (i != NULL) { i->el = el; i->curr = el->head->next; } return i; } rlist_iterator *rlist_iterator_copy(rlist_iterator *i) { // check preconditions if (i == NULL) { return NULL; } // allocate space and copy from existing iterator rlist_iterator *j = malloc(sizeof(rlist_iterator)); if (j != NULL) { j->el = i->el; j->curr = i->curr; } return j; } bool rlist_iterator_at_end(const rlist_iterator *i) { return i == NULL || i->curr == i->el->tail; } void rlist_iterator_next(rlist_iterator *i) { if (!rlist_iterator_at_end(i)) { i->curr = i->curr->next; } } bool rlist_iterator_before_start(const rlist_iterator *i) { return i == NULL || i->curr == i->el->head; } void rlist_iterator_prev(rlist_iterator *i) { if (!rlist_iterator_before_start(i)) { i->curr = i->curr->prev; } } void rlist_iterator_destroy(rlist_iterator *i) { free(i); } void rlist_iterator_get(const rlist_iterator *i, request *r) { if (!rlist_iterator_at_end(i) && r != NULL) { r->user = malloc(strlen(i->curr->data.user) + 1); r->position = malloc(strlen(i->curr->data.position) + 1); if (r->user != NULL && r->position != NULL) { strcpy(r->user, i->curr->data.user); strcpy(r->position, i->curr->data.position); } else { // malloc failed free(r->user); free(r->position); r->user = NULL; r->position = NULL; } } } void rlist_iterator_remove(rlist_iterator *i) { if (!rlist_iterator_at_end(i)) { // set pointers to nodes before and after one to remove rlist_node *before = i->curr->prev; rlist_node *after = i->curr->next; // link around node to remove before->next = after; after->prev = before; i->el->size--; // free data in node to remove and the node itself free(i->curr->data.user); free(i->curr->data.position); free(i->curr); // move i to next item i->curr = after; } }