| /* |
| * libkmod - interface to kernel module operations |
| * |
| * Copyright (C) 2011-2013 ProFUSION embedded systems |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <assert.h> |
| #include <errno.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include <shared/array.h> |
| |
| /* basic pointer array growing in steps */ |
| |
| |
| static int array_realloc(struct array *array, size_t new_total) |
| { |
| void *tmp = realloc(array->array, sizeof(void *) * new_total); |
| if (tmp == NULL) |
| return -ENOMEM; |
| array->array = tmp; |
| array->total = new_total; |
| return 0; |
| } |
| |
| void array_init(struct array *array, size_t step) |
| { |
| assert(step > 0); |
| array->array = NULL; |
| array->count = 0; |
| array->total = 0; |
| array->step = step; |
| } |
| |
| int array_append(struct array *array, const void *element) |
| { |
| size_t idx; |
| |
| if (array->count + 1 >= array->total) { |
| int r = array_realloc(array, array->total + array->step); |
| if (r < 0) |
| return r; |
| } |
| idx = array->count; |
| array->array[idx] = (void *)element; |
| array->count++; |
| return idx; |
| } |
| |
| int array_append_unique(struct array *array, const void *element) |
| { |
| void **itr = array->array; |
| void **itr_end = itr + array->count; |
| for (; itr < itr_end; itr++) |
| if (*itr == element) |
| return -EEXIST; |
| return array_append(array, element); |
| } |
| |
| void array_pop(struct array *array) { |
| array->count--; |
| if (array->count + array->step < array->total) { |
| int r = array_realloc(array, array->total - array->step); |
| if (r < 0) |
| return; |
| } |
| } |
| |
| void array_free_array(struct array *array) { |
| free(array->array); |
| array->count = 0; |
| array->total = 0; |
| } |
| |
| |
| void array_sort(struct array *array, int (*cmp)(const void *a, const void *b)) |
| { |
| qsort(array->array, array->count, sizeof(void *), cmp); |
| } |
| |
| int array_remove_at(struct array *array, unsigned int pos) |
| { |
| if (array->count <= pos) |
| return -ENOENT; |
| |
| array->count--; |
| if (pos < array->count) |
| memmove(array->array + pos, array->array + pos + 1, |
| sizeof(void *) * (array->count - pos)); |
| |
| if (array->count + array->step < array->total) { |
| int r = array_realloc(array, array->total - array->step); |
| /* ignore error */ |
| if (r < 0) |
| return 0; |
| } |
| |
| return 0; |
| } |