Integrated the DKIM signer into serv_smtpclient, but disabled it
[citadel.git] / libcitadel / lib / array.c
1 // This is a simple implementation of an elastic array class in pure C language.
2 //
3 // Copyright (c) 2021-2023 by Art Cancro
4 //
5 // This program is open source software.  Use, duplication, or disclosure
6 // is subject to the terms of the GNU General Public License, version 3.
7
8
9 #include <stdlib.h>
10 #include <string.h>
11 #include <stdio.h>
12 #include "libcitadel.h"
13
14
15 // Constructor for elastic array
16 Array *array_new(size_t element_size) {
17         Array *newarr = malloc(sizeof(Array));
18         if (newarr) {
19                 memset(newarr, 0, sizeof(Array));
20         }
21         newarr->element_size = element_size;
22         return newarr;
23 }
24
25
26 // Destructor for elastic array
27 void array_free(Array *arr) {
28         free(arr->the_elements);
29         free(arr);
30 }
31
32
33 // Append an element to an array (we already know the element size because it's in the data type)
34 void array_append(Array *arr, void *new_element) {
35
36         if (!arr) {                                             // silently fail if they gave us a null array
37                 return;
38         }
39
40         if ( (arr->the_elements == NULL) || (arr->num_alloc == 0)) {
41                 arr->num_alloc = 1;
42                 arr->num_elements = 0;
43                 arr->the_elements = malloc(arr->element_size * arr->num_alloc);
44                 if (arr->the_elements == NULL) {
45                         abort();
46                 }
47         }
48
49         ++arr->num_elements;
50         if (arr->num_elements > arr->num_alloc) {
51                 arr->num_alloc = arr->num_alloc * 2;            // whenever we exceed the buffer size, we double it.
52                 arr->the_elements = realloc(arr->the_elements, (arr->element_size * arr->num_alloc));
53                 if (arr->the_elements == NULL) {
54                         abort();
55                 }
56         }
57
58         memcpy((arr->the_elements + ( (arr->num_elements-1) * arr->element_size )), new_element, arr->element_size);
59 }
60
61
62 // Return the element in an array at the specified index
63 void *array_get_element_at(Array *arr, int index) {
64         return (arr->the_elements + ( index * arr->element_size ));
65 }
66
67
68 // Return the number of elements in an array
69 int array_len(Array *arr) {
70         if (!arr) {
71                 return(0);
72         }
73
74         return arr->num_elements;
75 }
76
77
78 // Sort an array.  We already know the element size and number of elements, so all we need is
79 // a sort function, which we will pass along to qsort().
80 void array_sort(Array *arr, int (*compar)(const void *, const void *)) {
81         qsort(arr->the_elements, arr->num_elements, arr->element_size, compar);
82 }
83
84
85 // Delete an element from an array
86 void array_delete_element_at(Array *arr, int index) {
87
88         if (index >= arr->num_elements) {               // If the supplied index is out of bounds, return quietly.
89                 return;
90         }
91
92         if (index < 0) {                                // If the supplied index is invalid, return quietly.
93                 return;
94         }
95
96         --arr->num_elements;
97
98         if (index == arr->num_elements) {               // If we deleted the element at the end, there's no more to be done.
99                 return;
100         }
101
102         memmove(                                        // memmove() is supposed to be safer than memcpy()
103                 (arr->the_elements + (index * arr->element_size)),
104                 arr->the_elements + ((index+1) * arr->element_size),
105                 (arr->num_elements - index) * arr->element_size
106         );
107 }