Update string_swap
[libstring.git] / src / libstring.c
blob192c8f8d688ed6e669beaa62663284506c0c28d1
1 /*
2 * libstring
3 * https://github.com/carmesim/libstring
5 * Copyright (c) 2020 Vinícius R. Miguel, Ivan dos Santos Muniz
6 * <vinicius.miguel at unifesp.br>
7 * <ivan.muniz at unifesp.br>
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included in all
17 * copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
28 #include "libstring.h"
29 #include <stdio.h>
31 void * __malloc(size_t size)
33 void * ptr = malloc(size);
34 if(!ptr)
36 fprintf(stderr, "Fatal error: malloc failed.\n");
37 // TODO: exit?
39 return ptr;
43 * Portable and simple reimplementation of strlen
44 * Does not totally conform to the C ISO standard, but is good enough for our uses.
46 size_t __strlen(const char *s) {
47 size_t i;
48 for (i = 0; s[i] != '\0'; i++) ;
49 return i;
52 char * __memcpy(char * dest, const char *src, size_t n) {
53 while (n--)
55 *dest++ = *src++;
57 return dest;
60 void __strcpy(char *dest, const char *src, size_t size)
62 if(!size)
64 fprintf(stderr, "__strcpy should not be called with size==0\n");
65 return;
68 size_t source_len = __strlen(src);
69 size_t n;
71 if (size-1 < source_len) // Truncate to the size of the smaller string
73 n = size-1;
74 } else
76 n = source_len;
79 __memcpy(dest, src, n); // Copy the contents of src to dest
80 dest[n] = '\0'; // Null-terminate dest.
83 /*!
84 * \struct alloc_node A single node of the allocation linked list.
85 * \param nbytes The number of bytes to be allocated.
86 * \property val A pointer to struct cstr.
87 * \property next A pointer to the next node in the allocation list.
89 struct alloc_node
91 cstr_t * val;
92 struct alloc_node * next;
95 /* We'll keep a simple linked list of heap allocations as to allow for string_free_all() */
96 struct alloc_node * alloc_list_head = NULL;
98 /*!
99 * \brief Allocates memory for a cstr_t * and adds it to the allocation list.
100 * \param nbytes The number of bytes to be allocated.
102 cstr_t * string_alloc (size_t nbytes)
104 if (!alloc_list_head) // If the list's head hasn't been initialized
106 alloc_list_head = __malloc(sizeof(struct alloc_node));
107 alloc_list_head->val = __malloc(sizeof(struct cstr));
108 alloc_list_head->val->value = __malloc(nbytes * sizeof(char));
109 alloc_list_head->val->size = nbytes;
110 alloc_list_head->val->reserved = nbytes;
111 alloc_list_head->next = NULL;
112 return alloc_list_head->val;
115 struct alloc_node * current = alloc_list_head;
116 while (current->next)
117 current = current->next;
119 current->next = __malloc(sizeof(struct alloc_node));
120 current->next->val = __malloc(sizeof(struct cstr));
121 current->next->val->value = __malloc(nbytes);
122 current->next->val->size = nbytes;
123 current->next->val->reserved = nbytes;
124 current->next->next = NULL;
125 return current->next->val;
129 * \brief Frees all heap memory allocated by libstring.
131 void string_free_all (void)
133 struct alloc_node * current = alloc_list_head;
134 while (current)
136 struct alloc_node * temp = current;
137 current = current->next;
138 free(temp->val->value);
139 free(temp->val);
140 free(temp);
145 * \brief Alters a string to contain only lower-case characters.
146 * \param origin The string whose value will be converted to lower-case characters. This parameters does not get modified.
147 * \retval lower A brand new cstr_t * that contains the altered value.
148 * Makes use of bit manipulation to alter the ASCII values.
150 cstr_t * string_to_lower_case(cstr_t * origin)
152 cstr_t* lower;
153 lower = string_init(origin->value);
154 __strcpy(lower->value, origin->value, origin->size);
156 size_t i;
157 for(i=0; i<lower->size; i++)
159 if ((lower->value[i] >= 'A') && (lower->value[i] <= 'Z'))
161 lower->value[i] |= ' ';
164 return lower;
168 * \brief Alters a string to contain only lower-case characters.
169 * \param origin The string whose value will be converted to upper-case characters. This parameters does not get modified.
170 * \retval upper A brand new cstr_t * that contains the altered value.
171 * Makes use of bit manipulation to alter the ASCII values.
173 cstr_t * string_to_upper_case(cstr_t * origin)
175 cstr_t* upper;
176 upper = string_init(origin->value);
177 __strcpy(upper->value, origin->value, origin->size);
179 size_t i;
180 for(i=0; i<upper->size; i++)
182 if ((upper->value[i] >= 'a') && (upper->value[i] <= 'z'))
184 upper->value[i] &= '_';
187 return upper;
191 * \brief Initializes a new string, a poitner to cstr_t
192 * \param origin The char array to be the value of the new string.
193 * \retval upper A brand new cstr_t *.
194 * Adds to the allocation list.
196 cstr_t * string_init(const char * origin)
198 cstr_t * new = string_alloc(__strlen(origin)+1);
199 __strcpy(new->value, origin, __strlen(origin));
200 return new;
204 * \brief Initializes a new string, a poitner to cstr_t
205 * \param str The cstr_t * whose capacity will be altered.
206 * \param capacity The new memory reserve of the cstr_t *.
207 * \retval bool Returns true if the operation was succesful, false otherwise.
209 bool string_reserve(cstr_t *str, size_t capacity)
211 if (!str)
213 fprintf(stderr, "String not initialized.\n");
214 return false;
217 if (capacity < str->size)
219 //! TODO: Implement truncation?
220 fprintf(stderr, "New capacity supplied is smaller than the string's current size.\n");
221 return false;
224 char * val_backup = __malloc(str->size + 1);
225 str->value = realloc(str->value, capacity);
226 if(!str->value) // realloc failed
228 //! TODO: needs testing
229 //! I couldn't get realloc to fail in order to test
230 fprintf(stderr, "Reallocation failed with capacity %zu\n", capacity);
231 str->value = val_backup;
232 return false;
235 //! In this case, reallocation worked
236 free (val_backup); //! Get rid of the backup
237 str->reserved = capacity;
238 return true;
241 //! \brief string_swap Swaps the content of str1 with str2.
242 //! \param str1 An initialized cstr_t *.
243 //! \param str2 An initialized cstr_t *.
244 //! \return A success-run boolean.
246 bool string_swap(cstr_t * str1, cstr_t * str2)
248 if (!str1)
250 fprintf(stderr, "In string_swap: str1 unitialized.\n");
251 return false;
253 if (!str2)
255 fprintf(stderr, "In string_swap: str2 unitialized.\n");
256 return false;
259 size_t str1_val_size = str1->size;
260 char * str1_val_backup = malloc(str1_val_size + 1);
261 if(!str1_val_backup)
263 fprintf(stderr, "In string_swap: malloc failed.\n");
264 return false;
267 __strcpy(str1_val_backup, str1->value, str1_val_size);
268 size_t str1_res_backup = str1->reserved;
269 free(str1->value);
270 str1->value = str2->value;
271 str1->size = str2->size;
272 str1->reserved = str2->reserved;
274 str2->value = str1_val_backup;
275 str2->size = str1_val_size;
276 str2->reserved = str1_res_backup;
278 return true;