2 * str.c - String implementation.
3 * Author: Saúl Valdelvira (2023)
8 #include <string.h> // memcpy, strnlen
11 #define INITIAL_SIZE 16
15 static_assert(GROW_FACTOR
> 1);
23 static void resize_buffer(String
*str
, size_t new_size
){
26 str
->buffer_size
= new_size
;
27 str
->buffer
= realloc(str
->buffer
, str
->buffer_size
* sizeof(char));
31 String
* str_empty(void){
32 return str_init(INITIAL_SIZE
);
35 String
* str_init(unsigned initial_size
){
36 String
*str
= malloc(sizeof(*str
));
39 resize_buffer(str
, initial_size
);
44 String
* str_from_cstr(const char *src
, unsigned n
){
47 size_t len
= strnlen(src
, n
);
48 String
*str
= str_init(len
);
49 str_concat_cstr(str
, src
, n
);
53 void str_reserve(String
*str
, unsigned n
){
54 if (str
&& str
->buffer_size
< n
)
55 resize_buffer(str
, n
);
58 int str_concat_cstr(String
*str
, const char *cat
, unsigned n
){
61 size_t len
= strnlen(cat
, n
);
62 if (str
->buffer_size
- str
->length
< len
){
63 size_t new_size
= str
->buffer_size
* GROW_FACTOR
;
64 if (new_size
- str
->length
< len
)
66 resize_buffer(str
, new_size
);
68 memcpy(&str
->buffer
[str
->length
], cat
, len
* sizeof(char));
73 int str_concat_str(String
*str
, String
*cat
){
76 return str_concat_cstr(str
, cat
->buffer
, cat
->length
);
79 int str_push_char(String
*str
, char c
){
80 return str_concat_cstr(str
, (char[]){c
,'\0'}, 2);
83 int str_pop(String
*str
){
86 return str_remove_at(str
, str
->length
- 1);
89 int str_remove_at(String
*str
, unsigned index
){
92 if (index
>= str
->length
)
94 if (index
< str
->length
- 1)
95 memcpy(&str
->buffer
[index
], &str
->buffer
[index
+ 1], (str
->length
- index
- 1) * sizeof(char));
100 int str_remove_range(String
*str
, unsigned start
, unsigned end
){
105 if (end
> str
->length
)
107 size_t len
= str
->length
- end
;
108 memmove(&str
->buffer
[start
], &str
->buffer
[end
], len
* sizeof(char));
109 str
->length
-= end
- start
;
113 char str_get_at(String
*str
, unsigned index
){
116 else if (index
>= str
->length
)
118 return str
->buffer
[index
];
121 int str_set_at(String
*str
, unsigned index
, char c
){
124 else if (index
>= str
->length
)
126 return str
->buffer
[index
] = c
;
129 int str_insert_cstr(String
*str
, const char *insert
, unsigned n
, unsigned index
){
132 if (index
> str
->length
)
134 size_t len
= strnlen(insert
, n
);
135 if (str
->length
+ len
> str
->buffer_size
){
136 size_t new_size
= str
->buffer_size
* 2;
137 if (str
->length
+ len
> new_size
)
139 resize_buffer(str
, new_size
);
141 memmove(&str
->buffer
[index
+ len
], &str
->buffer
[index
], (str
->length
- index
) * sizeof(char));
142 memcpy(&str
->buffer
[index
], insert
, len
* sizeof(char));
147 int str_insert(String
*str
, char c
, unsigned index
){
148 return str_insert_cstr(str
, (char[]){c
, '\0'}, 2, index
);
151 char* str_to_cstr(String
*str
){
154 char *cstr
= malloc(str
->length
+ 1);
155 memcpy(cstr
, str
->buffer
, str
->length
* sizeof(char));
156 cstr
[str
->length
] = '\0';
160 const char* str_get_buffer(String
*str
){
163 if (str
->length
== str
->buffer_size
)
164 resize_buffer(str
, str
->buffer_size
* GROW_FACTOR
);
165 str
->buffer
[str
->length
] = '\0';
169 char* str_substring(String
*str
, unsigned start
, unsigned end
){
170 if (!str
|| end
< start
)
172 if (end
> str
->length
)
174 size_t len
= end
- start
;
175 char *substring
= malloc((len
+ 1) * sizeof(char));
177 memcpy(substring
, &str
->buffer
[start
], len
* sizeof(char));
178 substring
[len
] = '\0';
182 int str_transform(String
*str
, char(*func
)(char)){
185 for (size_t i
= 0; i
< str
->length
; i
++)
186 str
->buffer
[i
] = func(str
->buffer
[i
]);
190 String
* str_dup(String
*str
){
193 String
*dup
= str_init(str
->length
);
194 memcpy(dup
->buffer
, str
->buffer
, str
->length
* sizeof(char));
195 dup
->length
= str
->length
;
199 size_t str_length(String
*str
){
205 char* str_tok(String
*str
, char *tokens
){
206 static char *prev_tok
= NULL
;
207 static size_t pos
= 0;
208 static String
*curr_str
= NULL
;
215 if (!curr_str
|| !tokens
|| pos
== curr_str
->length
)
217 for (size_t i
= pos
; i
< curr_str
->length
; i
++){
218 for (char *t
= tokens
; *t
!= '\0'; t
++){
219 if (curr_str
->buffer
[i
] == *t
){
220 size_t len
= i
- pos
;
221 prev_tok
= malloc((len
+ 1) * sizeof(char));
222 memcpy(prev_tok
, &curr_str
->buffer
[pos
], len
* sizeof(char));
223 prev_tok
[len
] = '\0';
229 size_t len
= curr_str
->length
- pos
;
230 prev_tok
= malloc(len
+ 1);
231 memcpy(prev_tok
, &curr_str
->buffer
[pos
], len
* sizeof(char));
232 prev_tok
[len
] = '\0';
233 pos
= curr_str
->length
;
237 char** str_split(String
*str
, char *delim
){
240 size_t delim_len
= strlen(delim
);
242 int i
= str_find_substring(str
, delim
, 0);
245 i
= str_find_substring(str
, delim
, i
+ delim_len
);
247 count
++; // For the NULL element at the end
248 char **split
= malloc(count
* sizeof(char*));
251 i
= str_find_substring(str
, delim
, 0);
253 *ptr
= str_substring(str
, prev_i
, i
);
258 prev_i
= i
+ delim_len
;
259 i
= str_find_substring(str
, delim
, prev_i
);
261 if ((size_t)prev_i
< str
->length
)
262 *ptr
= str_substring(str
, prev_i
, str
->length
);
263 split
[count
- 1] = NULL
;
267 int str_find_substring(String
*str
, const char *substr
, unsigned start_at
){
270 if (start_at
>= str
->length
)
272 for (size_t i
= start_at
; i
< str
->length
; i
++){
273 const char *c
= substr
;
274 for (size_t j
= i
; j
< str
->length
; j
++){
275 if (*c
!= str
->buffer
[j
])
285 int str_replace(String
*str
, const char *substr
, const char *replacement
){
286 size_t substr_len
= strlen(substr
);
287 size_t replacement_len
= strlen(replacement
);
288 int n_replacements
= 0;
289 int i
= str_find_substring(str
, substr
, 0);
292 str_remove_range(str
, i
, i
+ substr_len
);
293 str_insert_cstr(str
, replacement
, replacement_len
, i
);
294 i
= str_find_substring(str
, substr
, i
+ replacement_len
);
296 return n_replacements
;
299 void str_shrink(String
*str
){
300 if (str
&& str
->buffer_size
> str
->length
)
301 resize_buffer(str
, str
->length
);
304 void str_clear(String
*str
){
309 void str_free(String
*str
){
316 void str_free_all(unsigned int n
, ...){
320 String
*str
= va_arg(arg
, String
*);