CSTR v1.1.0-build
Simple yet powerful string manipulation in C
Loading...
Searching...
No Matches
cstr.h
Go to the documentation of this file.
1// cstr.h
2
3#pragma once
4
5#include "CSTRpredefines.h"
6
7#ifdef __CSTR_OK
8# undef __CSTR_OK
9#endif // defined(__CSTR_OK)
10
11#if __STDC_VERSION__ >= CSTR_DEFAULT_C_STD
12
13#ifdef CSTR_sys_strdup
14# undef CSTR_sys_strdup
15#endif
16
17#if defined(CSTR_OS_WIN32)
18# include <string.h>
19# define CSTR_sys_strdup _strdup
20#else
21# ifdef _POSIX_C_SOURCE
22# undef _POSIX_C_SOURCE
23# endif
24# define _POSIX_C_SOURCE 200809L
25# include <string.h>
26# define CSTR_sys_strdup strdup
27#endif // defined(CSTR_OS_WIN32)
28
29#include <stdbool.h>
30#include <stdlib.h>
31
32#define CSTR_NPOS -1
33#define CSTR_SUCCESS 0
34#define CSTR_FAIL 1
35#define CSTR_FORCECAP_LIMIT 2
36
37// NOTE: Dear developer, check all the available macros here
38#ifdef CSTR_RECOMMENDED
39# define CSTR_DYNAMIC_CAPACITY
40# define CSTR_ENABLE_GET_RETURN
41# define CSTR_ENABLE_GET_CONST_RETURN
42#endif // CSTR_RECOMMENDED
43
44// NOTE:
45// Other macros that are not recommended but available for flexibility are:
46// CSTR_DEFINE_INTERNAL : Define the internal files inside of the header file (cstr.h)
47// Check the definitions below the definition of the CSTR struct
48// CSTR_RECOMMENDED : Enable recommended macros, such as CSTR_DYNAMIC_CAPACITY, CSTR_ENABLE_GET_RETURN, ...
49
50/**
51 * @brief Custom dynamic string type
52 *
53 * The fields should typically be managed only through the cstr_* API
54 * Directly modifying them can lead to undefined behavior unless explicitly intended
55 */
56typedef struct
57{
58 /**
59 * @brief Tracks whether this CSTR has been initialized
60 * @note Should only be set by internal or initialization functions
61 */
63
64 /**
65 * @brief Pointer to the character buffer
66 * Always NULL terminated if properly managed through the API
67 */
68 char *data;
69
70 /**
71 * @brief If true, capacity is fixed and operations that exceed
72 * it return an error instead of reallocating the size
73 */
75
76 /**
77 * @brief Current string length (not counting the NULL terminator)
78 */
79 size_t len;
80
81 /**
82 * @brief Total allocated capacity (including NULL terminator)
83 */
84 size_t cap;
85} CSTR;
86
87#ifdef CSTR_DEFINE_INTERNAL
88/**
89 * @brief Update the capacity automatically
90 * IMPORTANT:
91 * This function won't do anything if macro `CSTR_DYNAMIC_CAPACITY` is NOT defined
92 *
93 * @return Return if fail or success
94 * @note Typically used in the other defined functions for CSTR inner API
95 */
97
98/**
99 * @brief Internal helper to format and set the string content.
100 *
101 * Uses a printf-style format string and variadic arguments to
102 * overwrite the content of a CSTR. The function computes the
103 * required buffer size, reallocates if needed (unless forceCap
104 * is active), formats the string, and updates length/capacity.
105 *
106 * @param _str Pointer to the CSTR to modify.
107 * @param _fmt printf-style format string.
108 * @param ... Variadic arguments corresponding to the format.
109 *
110 * @return
111 * - CSTR_SUCCESS on success
112 * - CSTR_FAIL if parameters are invalid, allocation fails,
113 * or vsnprintf reports an error
114 * - CSTR_FORCECAP_LIMIT if forceCap is enabled and the
115 * required size exceeds current capacity
116 *
117 * @note Typically used in the other defined functions for CSTR inner API
118 */
119static int __cstr_setFormat(CSTR *_str, const char *_fmt, ...);
120#endif // defined(CSTR_DEFINE_INTERNAL)
121
122/**
123 * @brief Initialize a new empty CSTR
124 *
125 * @return A new CSTR instance. Check `.initialized` or if CSTR is not NULL to confirm success
126 */
128
129/**
130 * @brief Initialize a CSTR with a copy of an original C-string
131 *
132 * @param _dest Pointer to the destination CSTR
133 * @param _src NULL terminated string to copy from
134 * @return CSTR_SUCCESS on success, otherwise CSTR_FAIL
135 */
136int cstr_initCopy(CSTR *_dest, const char *_src);
137
138/**
139 * @brief Destroy and clean up a CSTR and its allocated objects
140 *
141 * @param _str Pointer to the CSTR to destroy
142 * @return CSTR_SUCCESS on success, otherwise CSTR_FAIL
143 */
145
146/**
147 * @brief Set the content of a CSTR to a new C-string in `.data`
148 *
149 * @param _str Pointer to the CSTR to modify
150 * @param _data Null terminated string to set
151 * @return CSTR_SUCCESS, CSTR_FAIL, or CSTR_FORCECAP_LIMIT
152 */
153int cstr_set(CSTR *_str, const char *_data);
154
155/**
156 * @brief Append a suffix to the end of a CSTR
157 *
158 * @param _str Pointer to the CSTR to modify
159 * @param _suffix NULL terminated string to append
160 * @return CSTR_SUCCESS, CSTR_FAIL, or CSTR_FORCECAP_LIMIT
161 */
162int cstr_add(CSTR *_str, const char *_suffix);
163
164/**
165 * @brief Extract a substring in place from a CSTR
166 *
167 * @param _str Pointer to the CSTR to modify
168 * @param _start Starting index of the substring
169 * @param _len Length of the substring
170 * @return CSTR_SUCCESS or CSTR_FAIL
171 */
172int cstr_substr(CSTR *_str, size_t _start, size_t _len);
173
174/**
175 * @brief Clear a CSTR to an empty string without freeing memory
176 *
177 * @param _str Pointer to the CSTR to clear
178 * @return CSTR_SUCCESS or CSTR_FAIL
179 */
180int cstr_clear(CSTR *_str);
181
182/**
183 * @brief Convert all characters in a CSTR to uppercase
184 *
185 * @param _str Pointer to the CSTR to modify
186 * @return CSTR_SUCCESS or CSTR_FAIL
187 */
188int cstr_upper(CSTR *_str);
189
190/**
191 * @brief Convert all characters in a CSTR to lowercase
192 *
193 * @param _str Pointer to the CSTR to modify
194 * @return CSTR_SUCCESS or CSTR_FAIL
195 */
196int cstr_lower(CSTR *_str);
197
198/**
199 * @brief Insert a string at a specific position in a CSTR
200 *
201 * @param _str Pointer to the CSTR to modify
202 * @param _data NULL terminated string to insert
203 * @param _pos Position at which to insert, 0-based
204 * @return CSTR_SUCCESS, CSTR_FAIL, or CSTR_FORCECAP_LIMIT
205 */
206int cstr_insert(CSTR *_str, const char *_data, size_t _pos);
207
208/**
209 * @brief Reverse the content of a CSTR in place
210 *
211 * @param _str Pointer to the CSTR to modify
212 * @return CSTR_SUCCESS or CSTR_FAIL
213 */
215
216/**
217 * @brief Clear the content of a CSTR and optionally shrink capacity
218 *
219 * @param _str Pointer to the CSTR to shrink
220 * @param _len New length (characters to keep)
221 * @return CSTR_SUCCESS or CSTR_FAIL
222 */
223int cstr_shrink(CSTR *_str, const size_t _len);
224
225/**
226 * @brief Create a numeric string from an integer
227 */
228int cstr_fromInt(CSTR *_str, int _val);
229
230/**
231 * @brief Create a numeric string from a long
232 */
233int cstr_fromLong(CSTR *_str, long _val);
234
235/**
236 * @brief Create a numeric string from a float
237 */
238int cstr_fromFloat(CSTR *_str, float _val);
239
240/**
241 * @brief Create a numeric string from a double
242 */
243int cstr_fromDouble(CSTR *_str, double _val);
244
245/**
246 * @brief Create a hexadecimal string from an unsigned integer
247 */
248int cstr_fromHex(CSTR *_str, unsigned int _val);
249
250/**
251 * @brief Replace only the first occurrence of a substring
252 *
253 * @param _str Pointer to the CSTR
254 * @param _old Substring to locate
255 * @param _new Replacement string
256 * @return CSTR_SUCCESS or an error code (CSTR_FAIL, ...)
257 */
258int cstr_replace(CSTR *_str, const char *_old, const char *_new);
259
260/**
261 * @brief Replace all occurrences of a substring
262 *
263 * @param _str Pointer to the CSTR
264 * @param _old Substring to locate
265 * @param _new Replacement string
266 * @return CSTR_SUCCESS or CSTR_FAIL
267 */
268int cstr_replaceAll(CSTR *_str, const char *_old, const char *_new);
269
270/**
271 * @brief Erase a portion of the string
272 *
273 * @param _str Pointer to the CSTR
274 * @param _pos Starting position
275 * @param _len Number of characters to remove
276 * @return CSTR_SUCCESS or CSTR_FAIL
277 */
278int cstr_erase(CSTR *_str, int _pos, size_t _len);
279
280/**
281 * @brief Find the first occurrence of a substring
282 *
283 * @param _str Pointer to the CSTR to search
284 * @param _find Substring to locate
285 * @return Index of first match, or CSTR_NPOS if not found
286 */
287size_t cstr_find(const CSTR *_str, const char *_find);
288
289/**
290 * @brief Find a substring starting from a specific index
291 *
292 * @param _str Pointer to the CSTR to search
293 * @param _find Substring to locate
294 * @param pos Starting index
295 * @return Index of match, or CSTR_NPOS if not found
296 */
297size_t cstr_findFrom(const CSTR *_str, const char *_find, size_t pos);
298
299/**
300 * @brief Count occurrences of a single character within a CSTR
301 *
302 * Iterates through the string and counts how many times the specified
303 * character appears in the `.data` buffer.
304 *
305 * @param _str Pointer to the CSTR to inspect
306 * @param ch Character to count
307 *
308 * @return Number of occurrences of `ch` in the string
309 * Returns 0 if `_str` is NULL or not initialized
310 *
311 * @note This function performs a linear scan across all characters.
312 */
313size_t cstr_countChar(const CSTR *_str, const char ch);
314
315/**
316 * @brief Count occurrences of a substring within a CSTR
317 *
318 * Searches for non-overlapping occurrences of a null-terminated substring
319 * inside the CSTR’s `.data` buffer using strstr. Each found instance advances
320 * the scan position by the length of the substring, preventing overlapping matches.
321 *
322 * @param _str Pointer to the CSTR to inspect
323 * @param ch Null-terminated substring to count
324 *
325 * @return Number of non-overlapping occurrences found
326 * Returns 0 if parameters are invalid (`_str`, `.data`, `ch`, or `*ch`)
327 */
328size_t cstr_count(const CSTR *_str, const char *ch);
329
330/**
331 * @brief Check if a CSTR begins with the given prefix
332 *
333 * @param _str The CSTR to check by value
334 * @param _prefix The prefix string
335 * @return true if it starts with prefix, else return false
336 */
337bool cstr_startsWith(CSTR _str, const char *_prefix);
338
339/**
340 * @brief Check if a CSTR ends with the given suffix
341 *
342 * @param _str The CSTR to check (by value)
343 * @param _suffix The suffix string
344 * @return true if it ends with suffix, false otherwise
345 */
346bool cstr_endsWith(const CSTR _str, const char *_suffix);
347
348/**
349 * @brief Compare two CSTR instances for equality
350 *
351 * @param _s1 First CSTR (by value)
352 * @param _s2 Second CSTR (by value)
353 * @return true if equal, false otherwise
354 */
355bool cstr_comp(const CSTR _s1, const CSTR _s2);
356
357/**
358 * @brief Return "true" or "false" based on a boolean value
359 *
360 * @param _bool Boolean value
361 * @return "true" if _bool is true, otherwise "false".
362 */
363const char *cstr_bool(const bool _bool);
364
365/**
366 * @brief Get if the string is empty
367 * Return true if:
368 * `.len` smaller or equal to 0
369 * `.data` is empty ("")
370 * `.initialized` is false
371 * `_str` is NULL
372 * If none of the requirements are met, means that it's not empty, hence, return false
373 *
374 * @return Is the string empty? Yes (true), No (false)
375 */
376bool cstr_empty(const CSTR *_str);
377
378#define __CSTR_OK
379
380#ifdef __CSTR_OK
381# ifdef CSTR_ENABLE_GET_RETURN
382# define CSTR_GET_RETURN(_cstr, _call, ...) ((_call(&_cstr, __VA_ARGS__)), _cstr)
383# else
384# define CSTR_GET_RETURN(_cstr, _call, ...)
385# endif // defined(CSTR_ENABLE_GET_RETURN)
386
387# ifdef CSTR_CONST_RETURN_USE_PTR_METHOD
388# define CSTR_CONST_RETURN_PTR_METHOD ->
389# else
390# define CSTR_CONST_RETURN_PTR_METHOD .
391# endif
392
393# ifdef CSTR_ENABLE_GET_CONST_RETURN
394# define CSTR_GET_CONST_RETURN(_str, _call, ...) \
395 ({ \
396 CSTR tmpS; \
397 cstr_initCopy(&tmpS, _str CSTR_CONST_RETURN_PTR_METHOD data); \
398 _call(&tmpS, __VA_ARGS__); \
399 tmpS; \
400 })
401# else
402# define CSTR_GET_CONST_RETURN(_str, _call, ...)
403# endif // defined(CSTR_ENABLE_GET_CONST_RETURN)
404#endif // __CSTR_OK
405
406#else
407# error "Must use C11 as the minimum standard"
408#endif // __STDC_VERSION__
409
int cstr_insert(CSTR *_str, const char *_data, size_t _pos)
Insert a string at a specific position in a CSTR.
int cstr_reverse(CSTR *_str)
Reverse the content of a CSTR in place.
bool cstr_comp(const CSTR _s1, const CSTR _s2)
Compare two CSTR instances for equality.
int cstr_lower(CSTR *_str)
Convert all characters in a CSTR to lowercase.
int cstr_replaceAll(CSTR *_str, const char *_old, const char *_new)
Replace all occurrences of a substring.
int cstr_fromFloat(CSTR *_str, float _val)
Create a numeric string from a float.
int cstr_fromHex(CSTR *_str, unsigned int _val)
Create a hexadecimal string from an unsigned integer.
int cstr_shrink(CSTR *_str, const size_t _len)
Clear the content of a CSTR and optionally shrink capacity.
int cstr_destroy(CSTR *_str)
Destroy and clean up a CSTR and its allocated objects.
int cstr_substr(CSTR *_str, size_t _start, size_t _len)
Extract a substring in place from a CSTR.
int cstr_fromInt(CSTR *_str, int _val)
Create a numeric string from an integer.
int cstr_set(CSTR *_str, const char *_data)
Set the content of a CSTR to a new C-string in .data.
bool cstr_startsWith(CSTR _str, const char *_prefix)
Check if a CSTR begins with the given prefix.
int cstr_fromDouble(CSTR *_str, double _val)
Create a numeric string from a double.
int cstr_erase(CSTR *_str, int _pos, size_t _len)
Erase a portion of the string.
int cstr_add(CSTR *_str, const char *_suffix)
Append a suffix to the end of a CSTR.
int cstr_initCopy(CSTR *_dest, const char *_src)
Initialize a CSTR with a copy of an original C-string.
int cstr_upper(CSTR *_str)
Convert all characters in a CSTR to uppercase.
static int __cstr_setFormat(CSTR *_str, const char *_fmt,...)
Internal helper to format and set the string content.
int __cstr_updateCap(CSTR *_str)
Update the capacity automatically IMPORTANT: This function won't do anything if macro CSTR_DYNAMIC_CA...
bool cstr_empty(const CSTR *_str)
Get if the string is empty Return true if: .len smaller or equal to 0 .data is empty ("") ....
int cstr_fromLong(CSTR *_str, long _val)
Create a numeric string from a long.
size_t cstr_find(const CSTR *_str, const char *_find)
Find the first occurrence of a substring.
CSTR cstr_init(void)
Initialize a new empty CSTR.
const char * cstr_bool(const bool _bool)
Return "true" or "false" based on a boolean value.
size_t cstr_countChar(const CSTR *_str, const char ch)
Count occurrences of a single character within a CSTR.
int cstr_replace(CSTR *_str, const char *_old, const char *_new)
Replace only the first occurrence of a substring.
size_t cstr_count(const CSTR *_str, const char *ch)
Count occurrences of a substring within a CSTR.
size_t cstr_findFrom(const CSTR *_str, const char *_find, size_t pos)
Find a substring starting from a specific index.
int cstr_clear(CSTR *_str)
Clear a CSTR to an empty string without freeing memory.
bool cstr_endsWith(const CSTR _str, const char *_suffix)
Check if a CSTR ends with the given suffix.
Custom dynamic string type.
Definition cstr.h:57
bool initialized
Tracks whether this CSTR has been initialized.
Definition cstr.h:62
size_t len
Current string length (not counting the NULL terminator).
Definition cstr.h:79
size_t cap
Total allocated capacity (including NULL terminator).
Definition cstr.h:84
char * data
Pointer to the character buffer Always NULL terminated if properly managed through the API.
Definition cstr.h:68
bool forceCap
If true, capacity is fixed and operations that exceed it return an error instead of reallocating the ...
Definition cstr.h:74