SELKIELogger  1.0.0
strarray.c
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <stdbool.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "strarray.h"
26 
37 strarray *sa_new(int entries) {
38  strarray *newarray = calloc(1, sizeof(strarray));
39  if (newarray == NULL) { return NULL; }
40  if (!sa_init(newarray, entries)) {
41  //LCOV_EXCL_START
42  free(newarray);
43  return NULL;
44  //LCOV_EXCL_STOP
45  }
46  return newarray;
47 }
48 
59 bool sa_init(strarray *dst, const int entries) {
60  if (dst->entries) { sa_destroy(dst); }
61  dst->entries = entries;
62  dst->strings = calloc(entries, sizeof(string));
63  if (dst->strings == NULL) { return false; }
64  return true;
65 }
66 
76 bool sa_copy(strarray *dst, const strarray *src) {
77  if (dst == NULL || src == NULL) { return false; }
78  sa_destroy(dst);
79  dst->entries = src->entries;
80  dst->strings = calloc(dst->entries, sizeof(string));
81  if (dst->strings == NULL) {
82  //LCOV_EXCL_START
83  dst->entries = 0;
84  return false;
85  //LCOV_EXCL_STOP
86  }
87  bool success = true;
88  for (int ix = 0; ix < dst->entries; ix++) {
89  success &= str_copy(&(dst->strings[ix]), &(src->strings[ix]));
90  }
91  if (!success) {
92  //LCOV_EXCL_START
93  sa_destroy(dst);
94  return false;
95  //LCOV_EXCL_STOP
96  }
97  return true;
98 }
99 
112 bool sa_move(strarray *dst, strarray *src) {
113  if (dst == NULL || src == NULL) { return false; }
114  sa_destroy(dst);
115  dst->entries = src->entries;
116  dst->strings = src->strings;
117  src->strings = NULL;
118  src->entries = 0;
119  return true;
120 }
121 
131 bool sa_set_entry(strarray *array, const int index, string *str) {
132  if (array == NULL) { return false; }
133 
134  if (index >= array->entries) { return false; }
135 
136  return str_copy(&(array->strings[index]), str);
137 }
138 
149 bool sa_create_entry(strarray *array, const int index, const size_t len, const char *src) {
150  if (array == NULL) { return false; }
151  if (index >= array->entries) { return false; }
152 
153  return str_update(&(array->strings[index]), len, src);
154 }
155 
163 void sa_clear_entry(strarray *array, const int index) {
164  if (array == NULL) { return; }
165  if (index >= array->entries) { return; }
166 
167  str_destroy(&(array->strings[index]));
168 }
169 
182 void sa_destroy(strarray *sa) {
183  if (sa == NULL) { return; }
184  if (sa->entries == 0) {
185  // Why did we allocate a zero length array?
186  if (sa->strings) {
187  free(sa->strings);
188  sa->strings = NULL;
189  }
190  return;
191  }
192  if (sa->strings == NULL) {
193  // Bonus - we don't have an array here at all
194  sa->entries = 0;
195  return;
196  }
197 
198  for (int ix = 0; ix < sa->entries; ix++) {
199  str_destroy(&(sa->strings[ix]));
200  }
201  free(sa->strings);
202  sa->strings = NULL;
203  sa->entries = 0;
204 }
205 
217 string *str_new(const size_t len, const char *ca) {
218  string *ns = calloc(1, sizeof(string));
219  if (ns == NULL) { return NULL; }
220 
221  if (len == 0) {
222  ns->length = 0;
223  ns->data = NULL;
224  return ns;
225  }
226 
227  ns->length = len;
228  int alen = len;
229  if (ca[len - 1] != 0) { alen++; }
230  ns->data = malloc(alen);
231  if (ns->data == NULL) {
232  //LCOV_EXCL_START
233  free(ns);
234  return NULL;
235  //LCOV_EXCL_STOP
236  }
237 
238  strncpy(ns->data, ca, len);
239  ns->data[alen - 1] = 0; // Force last byte to zero
240  return ns;
241 }
242 
253 bool str_copy(string *dst, const string *src) {
254  str_destroy(dst);
255  dst->length = src->length;
256  dst->data = malloc(dst->length + 1);
257  if (dst->data == NULL) {
258  //LCOV_EXCL_START
259  dst->length = 0;
260  return false;
261  //LCOV_EXCL_STOP
262  }
263  if (src->data == NULL) {
264  dst->length = 0;
265  free(dst->data);
266  dst->data = NULL;
267  return true; // Odd scenario, but still a valid string
268  }
269  strncpy(dst->data, src->data, dst->length);
270  dst->data[dst->length] = 0;
271  return true;
272 }
273 
281 string *str_duplicate(const string *src) {
282  return str_new(src->length, src->data);
283 }
284 
294 bool str_update(string *str, const size_t len, const char *src) {
295  str_destroy(str);
296  if (len == 0 || src == NULL) {
297  str->data = NULL;
298  str->length = 0;
299  return true;
300  }
301  size_t checklen = strnlen(src, len);
302  str->length = checklen + 1;
303  str->data = malloc(str->length);
304  if (str->data == NULL) {
305  //LCOV_EXCL_START
306  str->length = 0;
307  return false;
308  //LCOV_EXCL_STOP
309  }
310  strncpy(str->data, src, checklen);
311  str->data[str->length - 1] = 0;
312  str->length = strlen(str->data);
313  return true;
314 }
315 
323 void str_destroy(string *str) {
324  if (str == NULL) { return; }
325  str->length = 0;
326  if (str->data) { free(str->data); }
327  str->data = NULL;
328 }
void sa_destroy(strarray *sa)
Destroy array and contents.
Definition: strarray.c:182
bool sa_copy(strarray *dst, const strarray *src)
Copy an array of strings from src to dst.
Definition: strarray.c:76
bool str_copy(string *dst, const string *src)
Update an existing string by copying the contents from another.
Definition: strarray.c:253
bool sa_init(strarray *dst, const int entries)
Initialise an already allocated array.
Definition: strarray.c:59
bool sa_move(strarray *dst, strarray *src)
Move strings from one array to another.
Definition: strarray.c:112
bool str_update(string *str, const size_t len, const char *src)
Update an existing string from a character array of given length.
Definition: strarray.c:294
bool sa_set_entry(strarray *array, const int index, string *str)
Copy a string to a given position in the array.
Definition: strarray.c:131
string * str_duplicate(const string *src)
Allocate a new string containing the contents of another.
Definition: strarray.c:281
string * str_new(const size_t len, const char *ca)
Create new string from character array.
Definition: strarray.c:217
void str_destroy(string *str)
Destroy a string and free its contents.
Definition: strarray.c:323
strarray * sa_new(int entries)
Allocate storage for a new array.
Definition: strarray.c:37
void sa_clear_entry(strarray *array, const int index)
Clear an array entry.
Definition: strarray.c:163
bool sa_create_entry(strarray *array, const int index, const size_t len, const char *src)
Create an string in a given position from a character array and length.
Definition: strarray.c:149
Array of strings.
Definition: strarray.h:43
int entries
Maximum number of strings in array, set when calling sa_new()
Definition: strarray.h:44
string * strings
Simple array of string structures.
Definition: strarray.h:45
char * data
Character array, should be null terminated.
Definition: strarray.h:39
size_t length
This should include a terminating null byte where possible.
Definition: strarray.h:38