diff --git a/common/list.c b/common/list.c index b4530e8e..83fde45a 100644 --- a/common/list.c +++ b/common/list.c @@ -22,23 +22,53 @@ #include #endif +#include + #include "arch.h" #include "os_calls.h" #include "string_calls.h" #include "list.h" #include "log.h" +enum +{ + DEFAULT_LIST_SIZE = 10, + DEFAULT_GROW_BY_SIZE = 10 +}; + +/*****************************************************************************/ +struct list * +list_create_sized(unsigned int size) +{ + struct list *self; + + if (size < DEFAULT_LIST_SIZE) + { + size = DEFAULT_LIST_SIZE; + } + self = (struct list *)calloc(sizeof(struct list), 1); + if (self != NULL) + { + self->items = (tbus *)malloc(sizeof(tbus) * size); + if (self->items == NULL) + { + free(self); + self = NULL; + } + else + { + self->grow_by = DEFAULT_GROW_BY_SIZE; + self->alloc_size = size; + } + } + return self; +} + /*****************************************************************************/ struct list * list_create(void) { - struct list *self; - - self = (struct list *)g_malloc(sizeof(struct list), 1); - self->grow_by = 10; - self->alloc_size = 10; - self->items = (tbus *)g_malloc(sizeof(tbus) * 10, 1); - return self; + return list_create_sized(DEFAULT_LIST_SIZE); } /*****************************************************************************/ @@ -56,34 +86,46 @@ list_delete(struct list *self) { for (i = 0; i < self->count; i++) { - g_free((void *)self->items[i]); + free((void *)self->items[i]); self->items[i] = 0; } } - g_free(self->items); - g_free(self); + free(self->items); + free(self); } /*****************************************************************************/ -void +static int +grow_list(struct list *self) +{ + int rv = 1; + unsigned int new_alloc_size = self->alloc_size + self->grow_by; + tbus *p = (tbus *)realloc(self->items, sizeof(tbus) * new_alloc_size); + if (p == NULL) + { + rv = 0; + } + else + { + self->alloc_size = new_alloc_size; + self->items = p; + } + return rv; +} + +/*****************************************************************************/ +int list_add_item(struct list *self, tbus item) { - tbus *p; - int i; - - if (self->count >= self->alloc_size) + if (self->count == self->alloc_size && !grow_list(self)) { - i = self->alloc_size; - self->alloc_size += self->grow_by; - p = (tbus *)g_malloc(sizeof(tbus) * self->alloc_size, 1); - g_memcpy(p, self->items, sizeof(tbus) * i); - g_free(self->items); - self->items = p; + return 0; } self->items[self->count] = item; self->count++; + return 1; } /*****************************************************************************/ @@ -108,16 +150,15 @@ list_clear(struct list *self) { for (i = 0; i < self->count; i++) { - g_free((void *)self->items[i]); + free((void *)self->items[i]); self->items[i] = 0; } } - g_free(self->items); self->count = 0; - self->grow_by = 10; - self->alloc_size = 10; - self->items = (tbus *)g_malloc(sizeof(tbus) * 10, 1); + self->grow_by = DEFAULT_GROW_BY_SIZE; + self->alloc_size = DEFAULT_LIST_SIZE; + self->items = (tbus *)realloc(self->items, sizeof(tbus) * self->alloc_size); } /*****************************************************************************/ @@ -147,7 +188,7 @@ list_remove_item(struct list *self, int index) { if (self->auto_free) { - g_free((void *)self->items[index]); + free((void *)self->items[index]); self->items[index] = 0; } @@ -161,57 +202,84 @@ list_remove_item(struct list *self, int index) } /*****************************************************************************/ -void +int list_insert_item(struct list *self, int index, tbus item) { - tbus *p; - int i; - if (index == self->count) + if (index > self->count) { - list_add_item(self, item); - return; + index = self->count; + } + else if (index < 0) + { + index = 0; } - if (index >= 0 && index < self->count) + if (self->count == self->alloc_size && !grow_list(self)) { - self->count++; + return 0; + } - if (self->count > self->alloc_size) - { - i = self->alloc_size; - self->alloc_size += self->grow_by; - p = (tbus *)g_malloc(sizeof(tbus) * self->alloc_size, 1); - g_memcpy(p, self->items, sizeof(tbus) * i); - g_free(self->items); - self->items = p; - } - - for (i = (self->count - 2); i >= index; i--) + self->count++; + if (self->count >= 2) + { + unsigned int i; + for (i = (self->count - 2); i >= (unsigned int)index; i--) { self->items[i + 1] = self->items[i]; } - - self->items[index] = item; } + + self->items[index] = item; + return 1; } /*****************************************************************************/ /* append one list to another using strdup for each item in the list */ /* begins copy at start_index, a zero based index on the source list */ -void +int list_append_list_strdup(struct list *self, struct list *dest, int start_index) { int index; - tbus item; - char *dup; + int rv = 1; + int entry_dest_count = dest->count; for (index = start_index; index < self->count; index++) { - item = list_get_item(self, index); - dup = g_strdup((char *)item); - list_add_item(dest, (tbus)dup); + const char *item = (const char *)list_get_item(self, index); + char *dup; + if (item == NULL) + { + // This shouldn't really happen, but if it does we'll + // copy the item anyway. + dup = NULL; + } + else + { + dup = g_strdup(item); + if (dup == NULL) + { + rv = 0; + break; + } + } + if (!list_add_item(dest, (tbus)dup)) + { + rv = 0; + break; + } } + + if (rv == 0) + { + // Remove the additional items we added + while (dest->count > entry_dest_count) + { + list_remove_item(dest, dest->count - 1); + } + } + + return rv; } /*****************************************************************************/ diff --git a/common/list.h b/common/list.h index 1f562105..7536a171 100644 --- a/common/list.h +++ b/common/list.h @@ -35,9 +35,27 @@ struct list struct list * list_create(void); +/** + * Creates a list with at least the specified number of items + * reserved + * @param size Number of items to reserve + * @return list, or NULL if no memory + */ +struct list * +list_create_sized(unsigned int size); void list_delete(struct list *self); -void +/** + * Adds an item to a list + * @param self The list + * @param item The item to add + * @result 0 if a memory allocation failure occurred. In this + * case the item is not added + * + * Memory allocation failures will not occur if the list is + * sized appropriately when created. + */ +int list_add_item(struct list *self, tintptr item); tintptr list_get_item(const struct list *self, int index); @@ -47,9 +65,32 @@ int list_index_of(struct list *self, tintptr item); void list_remove_item(struct list *self, int index); -void +/** + * Inserts an item into a list + * @param self The list + * @param index The location to insert the item before + * @param item The item to add + * @result 0 if a memory allocation failure occurred. In this + * case the item is not added + * + * Memory allocation failures will not occur if the list is + * sized appropriately when created. + */ +int list_insert_item(struct list *self, int index, tintptr item); -void +/** + * Adds strings to a list from another list + * @param self The source list + * @param dest Destination list + * @param start_index Index to start on the source list (zero based) + * + * @result 0 if a memory allocation failure occurred. In this + * case the destination list is unaltered. + * + * Strings from the source list are copied with strdup() + * The dest list should have auto_free set, or memory leaks will occur + */ +int list_append_list_strdup(struct list *self, struct list *dest, int start_index); void list_dump_items(struct list *self);