GCC Code Coverage Report


Directory: ./
File: cx/string.h
Date: 2025-12-31 16:19:05
Exec Total Coverage
Lines: 24 24 100.0%
Functions: 0 0 -%
Branches: 18 34 52.9%

Line Branch Exec Source
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 /**
29 * @file string.h
30 * @brief Strings that know their length.
31 * @author Mike Becker
32 * @author Olaf Wintermann
33 * @copyright 2-Clause BSD License
34 */
35
36 #ifndef UCX_STRING_H
37 #define UCX_STRING_H
38
39 #include "common.h"
40 #include "allocator.h"
41
42 #include <string.h>
43
44 /** Convenience macro for creating a null string */
45 #define CX_NULLSTR cx_mutstr(NULL)
46
47 /** Expands a UCX string as printf arguments. */
48 #define CX_SFMT(s) (int) (s).length, (s).ptr
49
50 /** Format specifier for a UCX string */
51 #define CX_PRIstr ".*s"
52
53 /**
54 * The maximum length of the "needle" in cx_strstr() that can use SBO.
55 */
56 CX_EXPORT extern const unsigned cx_strstr_sbo_size;
57
58 /**
59 * The UCX string structure.
60 */
61 struct cx_mutstr_s {
62 /**
63 * A pointer to the string.
64 * @note The string is not necessarily @c NULL terminated.
65 */
66 char *ptr;
67 /** The length of the string */
68 size_t length;
69 };
70
71 /**
72 * A mutable string.
73 */
74 typedef struct cx_mutstr_s cxmutstr;
75
76 /**
77 * The UCX string structure for immutable (constant) strings.
78 */
79 struct cx_string_s {
80 /**
81 * A pointer to the immutable string.
82 * @note The string is not necessarily @c NULL terminated.
83 */
84 const char *ptr;
85 /** The length of the string */
86 size_t length;
87 };
88
89 /**
90 * An immutable string.
91 */
92 typedef struct cx_string_s cxstring;
93
94 /**
95 * Context for string tokenizing.
96 */
97 struct cx_strtok_ctx_s {
98 /**
99 * The string to tokenize.
100 */
101 cxstring str;
102 /**
103 * The primary delimiter.
104 */
105 cxstring delim;
106 /**
107 * Optional array of more delimiters.
108 */
109 const cxstring *delim_more;
110 /**
111 * Length of the array containing more delimiters.
112 */
113 size_t delim_more_count;
114 /**
115 * Position of the currently active token in the source string.
116 */
117 size_t pos;
118 /**
119 * Position of the next delimiter in the source string.
120 *
121 * If the tokenizer has not yet returned a token, the content of this field
122 * is undefined. If the tokenizer reaches the end of the string, this field
123 * contains the length of the source string.
124 */
125 size_t delim_pos;
126 /**
127 * The position of the next token in the source string.
128 */
129 size_t next_pos;
130 /**
131 * The number of already found tokens.
132 */
133 size_t found;
134 /**
135 * The maximum number of tokens that shall be returned.
136 */
137 size_t limit;
138 };
139
140 /**
141 * A string tokenizing context.
142 */
143 typedef struct cx_strtok_ctx_s CxStrtokCtx;
144
145 /**
146 * Wraps a mutable string that must be zero-terminated.
147 *
148 * The length is implicitly inferred by using a call to @c strlen().
149 *
150 * When @c NULL is passed, the length will be set to zero.
151 *
152 * @note the wrapped string will share the specified pointer to the string.
153 * If you do want a copy, use cx_strdup() on the return value of this function.
154 *
155 * If you need to wrap a constant string, use cx_str().
156 *
157 * @param cstring the string to wrap (must be zero-terminated)
158 * @return the wrapped string
159 *
160 * @see cx_mutstrn()
161 */
162 CX_NODISCARD CX_CSTR_ARG(1)
163 CX_INLINE cxmutstr cx_mutstr(char *cstring) {
164 cxmutstr str;
165 1482 str.ptr = cstring;
166
10/24
✗ Branch 0 (6→7) not taken.
✗ Branch 1 (6→8) not taken.
✗ Branch 2 (17→18) not taken.
✓ Branch 3 (17→19) taken 1 times.
✓ Branch 4 (74→75) taken 60 times.
✗ Branch 5 (74→76) not taken.
✓ Branch 6 (90→91) taken 41 times.
✗ Branch 7 (90→92) not taken.
✓ Branch 8 (38→39) taken 2 times.
✗ Branch 9 (38→40) not taken.
✗ Branch 10 (31→32) not taken.
✓ Branch 11 (31→33) taken 742 times.
✗ Branch 12 (7→8) not taken.
✗ Branch 13 (7→9) not taken.
✗ Branch 14 (14→15) not taken.
✓ Branch 15 (14→16) taken 7 times.
✓ Branch 16 (22→23) taken 226 times.
✗ Branch 17 (22→24) not taken.
✓ Branch 18 (37→38) taken 207 times.
✗ Branch 19 (37→39) not taken.
✓ Branch 20 (52→53) taken 186 times.
✗ Branch 21 (52→54) not taken.
✗ Branch 22 (72→73) not taken.
✓ Branch 23 (72→74) taken 10 times.
1482 str.length = cstring == NULL ? 0 : strlen(cstring);
167 1482 return str;
168 }
169
170 /**
171 * Wraps a string that does not need to be zero-terminated.
172 *
173 * The argument may be @c NULL if the length is zero.
174 *
175 * @note the wrapped string will share the specified pointer to the string.
176 * If you do want a copy, use cx_strdup() on the return value of this function.
177 *
178 * If you need to wrap a constant string, use cx_strn().
179 *
180 * @param cstring the string to wrap (or @c NULL, only if the length is zero)
181 * @param length the length of the string
182 * @return the wrapped string
183 *
184 * @see cx_mutstr()
185 */
186 CX_NODISCARD CX_ACCESS_RW(1, 2)
187 CX_INLINE cxmutstr cx_mutstrn(char *cstring, size_t length) {
188 cxmutstr str;
189 846 str.ptr = cstring;
190 846 str.length = length;
191 846 return str;
192 }
193
194 /**
195 * Wraps a string that must be zero-terminated.
196 *
197 * The length is implicitly inferred by using a call to @c strlen().
198 *
199 * When @c NULL is passed, the length will be set to zero.
200 *
201 * @note the wrapped string will share the specified pointer to the string.
202 * If you do want a copy, use cx_strdup() on the return value of this function.
203 *
204 * If you need to wrap a non-constant string, use cx_mutstr().
205 *
206 * @param cstring the string to wrap (must be zero-terminated)
207 * @return the wrapped string
208 *
209 * @see cx_strn()
210 */
211 CX_NODISCARD CX_CSTR_ARG(1)
212 CX_INLINE cxstring cx_str(const char *cstring) {
213 cxstring str;
214 2 str.ptr = cstring;
215
1/2
✓ Branch 0 (6→7) taken 2 times.
✗ Branch 1 (6→8) not taken.
2 str.length = cstring == NULL ? 0 : strlen(cstring);
216 2 return str;
217 }
218
219
220 /**
221 * Wraps a string that does not need to be zero-terminated.
222 *
223 * The argument may be @c NULL if the length is zero.
224 *
225 * @note the wrapped string will share the specified pointer to the string.
226 * If you do want a copy, use cx_strdup() on the return value of this function.
227 *
228 * If you need to wrap a non-constant string, use cx_mutstrn().
229 *
230 * @param cstring the string to wrap (or @c NULL, only if the length is zero)
231 * @param length the length of the string
232 * @return the wrapped string
233 *
234 * @see cx_str()
235 */
236 CX_NODISCARD CX_ACCESS_R(1, 2)
237 CX_INLINE cxstring cx_strn(const char *cstring, size_t length) {
238 cxstring str;
239 1157 str.ptr = cstring;
240 1157 str.length = length;
241 1157 return str;
242 }
243
244 #ifdef __cplusplus
245 CX_NODISCARD
246 CX_CPPDECL cxmutstr cx_strcast_m(cxmutstr str) {
247 return str;
248 }
249 CX_NODISCARD
250 CX_CPPDECL cxstring cx_strcast_m(cxstring str) {
251 return str;
252 }
253 CX_NODISCARD
254 CX_CPPDECL cxmutstr cx_strcast_m(char *str) {
255 return cx_mutstr(str);
256 }
257 CX_NODISCARD
258 CX_CPPDECL cxmutstr cx_strcast_m(unsigned char *str) {
259 return cx_mutstr(reinterpret_cast<char*>(str));
260 }
261 CX_NODISCARD
262 CX_CPPDECL cxstring cx_strcast_m(const char *str) {
263 return cx_str(str);
264 }
265 CX_NODISCARD
266 CX_CPPDECL cxstring cx_strcast_m(const unsigned char *str) {
267 return cx_str(reinterpret_cast<const char*>(str));
268 }
269 CX_NODISCARD
270 CX_CPPDECL cxstring cx_strcast_(cxmutstr str) {
271 return cx_strn(str.ptr, str.length);
272 }
273 CX_NODISCARD
274 CX_CPPDECL cxstring cx_strcast_(cxstring str) {
275 return str;
276 }
277 #define cx_strcast(s) cx_strcast_(cx_strcast_m(s))
278 #else
279 /**
280 * Internal function, do not use.
281 * @param str
282 * @return
283 * @see cx_strcast_m()
284 * @see cx_strcast()
285 */
286 CX_NODISCARD
287 CX_INLINE cxmutstr cx_strcast_cxms(cxmutstr str) {
288 1040 return str;
289 }
290 /**
291 * Internal function, do not use.
292 * @param str
293 * @return
294 * @see cx_strcast_m()
295 * @see cx_strcast()
296 */
297 CX_NODISCARD
298 CX_INLINE cxstring cx_strcast_cxs(cxstring str) {
299 4754 return str;
300 }
301
302 /**
303 * Internal function, do not use.
304 * @param str
305 * @return
306 * @see cx_strcast_m()
307 * @see cx_strcast()
308 */
309 CX_NODISCARD
310 CX_INLINE cxmutstr cx_strcast_uc(unsigned char *str) {
311 return cx_mutstr((char*)str);
312 }
313
314 /**
315 * Internal function, do not use.
316 * @param str
317 * @return
318 * @see cx_strcast_m()
319 * @see cx_strcast()
320 */
321 CX_NODISCARD
322 CX_INLINE cxmutstr cx_strcast_c(char *str) {
323 722 return cx_mutstr(str);
324 }
325
326 /**
327 * Internal function, do not use.
328 * @param str
329 * @return
330 * @see cx_strcast_m()
331 * @see cx_strcast()
332 */
333 CX_NODISCARD
334 CX_INLINE cxstring cx_strcast_ucc(const unsigned char *str) {
335 return cx_str((const char*)str);
336 }
337
338 /**
339 * Internal function, do not use.
340 * @param str
341 * @return
342 * @see cx_strcast_m()
343 * @see cx_strcast()
344 */
345 CX_NODISCARD
346 CX_INLINE cxstring cx_strcast_cc(const char *str) {
347 2 return cx_str(str);
348 }
349
350 /**
351 * Wraps any string into an UCX string.
352 *
353 * @param str (any supported string type) the string to cast
354 * @return (@c cxstring) or (@c cxmutstr) the string wrapped as UCX string
355 */
356 #define cx_strcast_m(str) _Generic((str), \
357 cxstring: cx_strcast_cxs, \
358 cxmutstr: cx_strcast_cxms, \
359 const unsigned char*: cx_strcast_ucc, \
360 unsigned char *: cx_strcast_uc, \
361 const char*: cx_strcast_cc, \
362 char *: cx_strcast_c) (str)
363
364 /**
365 * Internal function, do not use.
366 * @param str
367 * @return
368 */
369 CX_INLINE cxstring cx_strcast_1(cxmutstr str) {
370 1762 return (cxstring){str.ptr, str.length};
371 }
372
373 /**
374 * Internal function, do not use.
375 * @param str
376 * @return
377 */
378 CX_INLINE cxstring cx_strcast_2(cxstring str) {
379 3390 return str;
380 }
381
382 /** internal conversion macro */
383 #define cx_strcast_(str) _Generic((str), \
384 cxmutstr: cx_strcast_1, \
385 cxstring: cx_strcast_2)(str)
386
387 /**
388 * Converts any string to a cxstring.
389 *
390 * @param str (any supported string type) the string to cast
391 * @return he string converted to a (@c cxstring)
392 */
393 #define cx_strcast(str) cx_strcast_(cx_strcast_m(str))
394 #endif
395
396 /**
397 * Casts away constness and converts a cxstring to a cxmutstr.
398 * For internal use only!
399 * @param str
400 * @return
401 */
402 CX_INLINE cxmutstr cx_mutstrcast(cxstring str) {
403 cxmutstr s;
404 s.ptr = (char*)str.ptr;
405 s.length = str.length;
406 return s;
407 }
408
409 /**
410 * Passes the pointer in this string to the cxDefaultAllocator's @c free() function.
411 *
412 * The pointer in the struct is set to @c NULL, and the length is set to zero,
413 * which means that this function protects you against double-free.
414 *
415 * @note There is no implementation for cxstring, because it is unlikely that
416 * you ever have a <code>const char*</code> you are really supposed to free.
417 * If you encounter such a situation, you should double-check your code.
418 *
419 * @param str the string to free
420 */
421 CX_EXTERN
422 void cx_strfree(cxmutstr *str);
423
424 /**
425 * Passes the pointer in this string to the allocator's free function.
426 *
427 * The pointer in the struct is set to @c NULL, and the length is set to zero,
428 * which means that this function protects you against double-free.
429 *
430 * @note There is no implementation for cxstring, because it is unlikely that
431 * you ever have a <code>const char*</code> you are really supposed to free.
432 * If you encounter such a situation, you should double-check your code.
433 *
434 * @param alloc the allocator
435 * @param str the string to free
436 */
437 CX_EXTERN CX_NONNULL_ARG(1)
438 void cx_strfree_a(const CxAllocator *alloc, cxmutstr *str);
439
440 /**
441 * Copies a string.
442 *
443 * Internal function - do not use.
444 *
445 * @param alloc the allocator
446 * @param dest a pointer to the structure where to copy the contents to
447 * @param src the source string
448 *
449 * @retval zero success
450 * @retval non-zero if re-allocation failed
451 * @see cx_strcpy_a()
452 */
453 CX_EXTERN CX_NONNULL_ARG(1)
454 int cx_strcpy_a_(const CxAllocator *alloc, cxmutstr *dest, cxstring src);
455
456 /**
457 * Copies a string.
458 *
459 * The memory in the @p dest structure is either allocated or re-allocated to fit the entire
460 * source string, including a zero-terminator.
461 *
462 * The string in @p dest is guaranteed to be zero-terminated, regardless of whether @p src is.
463 *
464 * @param alloc (@c CxAllocator*) the allocator
465 * @param dest (@c cxmutstr*) a pointer to the structure where to copy the contents to
466 * @param src the source string
467 * @retval zero success
468 * @retval non-zero if re-allocation failed
469 */
470 #define cx_strcpy_a(alloc, dest, src) cx_strcpy_a_(alloc, dest, cx_strcast(src))
471
472 /**
473 * Copies a string.
474 *
475 * The memory in the @p dest structure is either allocated or re-allocated to fit the entire
476 * source string, including a zero-terminator.
477 *
478 * The string in @p dest is guaranteed to be zero-terminated, regardless of whether @p src is.
479 *
480 * @param dest (@c cxmutstr*) a pointer to the structure where to copy the contents to
481 * @param src the source string
482 * @retval zero success
483 * @retval non-zero if re-allocation failed
484 */
485 #define cx_strcpy(dest, src) cx_strcpy_a(cxDefaultAllocator, dest, src)
486
487 /**
488 * Returns the accumulated length of all specified strings.
489 *
490 * If this sum overflows, errno is set to EOVERFLOW.
491 *
492 * @attention if the count argument is larger than the number of the
493 * specified strings, the behavior is undefined.
494 *
495 * @param count the total number of specified strings
496 * @param ... all strings
497 * @return the accumulated length of all strings
498 */
499 CX_EXTERN CX_NODISCARD
500 size_t cx_strlen(size_t count, ...);
501
502 /**
503 * Concatenates strings.
504 *
505 * The resulting string will be allocated by the specified allocator.
506 * So developers @em must pass the return value to cx_strfree_a() eventually.
507 *
508 * If @p str already contains a string, the memory will be reallocated and
509 * the other strings are appended. Otherwise, new memory is allocated.
510 *
511 * @note It is guaranteed that there is only one allocation for the
512 * resulting string.
513 * It is also guaranteed that the returned string is zero-terminated.
514 * If allocation fails, the @c ptr in the returned string will be @c NULL.
515 *
516 * @param alloc the allocator to use
517 * @param str the string the other strings shall be concatenated to
518 * @param count the number of the other following strings to concatenate
519 * @param ... all other UCX strings
520 * @return the concatenated string
521 */
522 CX_EXTERN CX_NONNULL
523 cxmutstr cx_strcat_a(const CxAllocator *alloc,
524 cxmutstr str, size_t count, ...);
525
526 /**
527 * Concatenates strings and returns a new string.
528 *
529 * The resulting string will be allocated by the cxDefaultAllocator.
530 * So developers @em must pass the return value to cx_strfree() eventually.
531 *
532 * @note It is guaranteed that there is only one allocation for the
533 * resulting string.
534 * It is also guaranteed that the returned string is zero-terminated.
535 * If allocation fails, the @c ptr in the returned string will be @c NULL.
536 *
537 * @param str (@c cxmutstr*) the string the other strings shall be concatenated to
538 * @param count (@c size_t) the number of the other following strings to concatenate
539 * @param ... all other UCX strings
540 * @return the concatenated string
541 */
542 #define cx_strcat(str, count, ...) \
543 cx_strcat_a(cxDefaultAllocator, str, count, __VA_ARGS__)
544
545 /**
546 * Returns a substring.
547 *
548 * Internal function - do not use.
549 *
550 * @param string input string
551 * @param start start location of the substring
552 * @param length the maximum length of the returned string
553 * @return a substring of @p string starting at @p start
554 * @see cx_strsubsl()
555 */
556 CX_EXTERN CX_NODISCARD
557 cxstring cx_strsubsl_(cxstring string, size_t start, size_t length);
558
559 /**
560 * Returns a substring.
561 *
562 * Internal function - do not use.
563 *
564 * @param string input string
565 * @param start start location of the substring
566 * @return a substring of @p string starting at @p start
567 * @see cx_strsubs()
568 */
569 CX_EXTERN CX_NODISCARD
570 cxstring cx_strsubs_(cxstring string, size_t start);
571
572 /**
573 * Internal conversion function - do not use.
574 * @param string
575 * @param start
576 * @return
577 */
578 CX_INLINE
579 cxmutstr cx_strsubs_m_(cxmutstr string, size_t start) {
580 return cx_mutstrcast(cx_strsubs_(cx_strcast(string), start));
581 }
582
583 /**
584 * Internal conversion function - do not use.
585 * @param string
586 * @param start
587 * @param length
588 * @return
589 */
590 CX_INLINE
591 cxmutstr cx_strsubsl_m_(cxmutstr string, size_t start, size_t length) {
592 return cx_mutstrcast(cx_strsubsl_(cx_strcast(string), start, length));
593 }
594
595 #ifdef __cplusplus
596 CX_CPPDECL cxstring cx_strsubs_cpp_(cxstring string, size_t start) {
597 return cx_strsubs_(string, start);
598 }
599 CX_CPPDECL cxstring cx_strsubsl_cpp_(cxstring string, size_t start, size_t length) {
600 return cx_strsubsl_(string, start, length);
601 }
602 CX_CPPDECL cxmutstr cx_strsubs_cpp_(cxmutstr string, size_t start) {
603 return cx_strsubs_m_(string, start);
604 }
605 CX_CPPDECL cxmutstr cx_strsubsl_cpp_(cxmutstr string, size_t start, size_t length) {
606 return cx_strsubsl_m_(string, start, length);
607 }
608 #define cx_strsubs(string, start) cx_strsubs_cpp_(cx_strcast_m(string), start)
609 #define cx_strsubsl(string, start, length) cx_strsubsl_cpp_(cx_strcast_m(string), start, length)
610 #else
611 /**
612 * Returns a substring starting at the specified location.
613 *
614 * @attention the new string references the same memory area as the
615 * input string and is @em not zero-terminated.
616 * Use cx_strdup() to get a copy.
617 *
618 * @param string input string
619 * @param start (@c size_t) start location of the substring
620 * @return (@c cxstring or @c cxmutstr) a substring of @p string starting at @p start
621 *
622 * @see cx_strsubsl()
623 */
624 #define cx_strsubs(string, start) _Generic(cx_strcast_m(string), \
625 cxstring: cx_strsubs_, \
626 cxmutstr: cx_strsubs_m_)(cx_strcast_m(string), start)
627
628 /**
629 * Returns a substring starting at the specified location.
630 *
631 * The returned string will be limited to @p length bytes or the number
632 * of bytes available in @p string, whichever is smaller.
633 *
634 * @attention the new string references the same memory area as the
635 * input string and is usually @em not zero-terminated.
636 * Use cx_strdup() to get a copy.
637 *
638 * @param string input string
639 * @param start start location of the substring
640 * @param length the maximum length of the returned string
641 * @return a substring of @p string starting at @p start
642 *
643 * @see cx_strsubs()
644 */
645 #define cx_strsubsl(string, start, length) _Generic(cx_strcast_m(string), \
646 cxstring: cx_strsubsl_, \
647 cxmutstr: cx_strsubsl_m_)(cx_strcast_m(string), start, length)
648 #endif
649
650 /**
651 * Returns the character at the specified index offset.
652 *
653 * Internal function - do not use.
654 *
655 * @param str the string
656 * @param index the index offset
657 * @return the character at the index
658 * @see cx_strat()
659 */
660 CX_INLINE
661 char cx_strat_(cxstring str, off_t index) {
662 size_t i;
663
3/4
✓ Branch 0 (8→9) taken 368 times.
✓ Branch 1 (8→10) taken 16 times.
✗ Branch 2 (21→22) not taken.
✓ Branch 3 (21→23) taken 327 times.
711 if (index >= 0) {
664 368 i = index;
665 } else {
666 343 i = (size_t) (str.length + index);
667 }
668
4/4
✓ Branch 0 (11→12) taken 76 times.
✓ Branch 1 (11→13) taken 308 times.
✓ Branch 2 (24→25) taken 76 times.
✓ Branch 3 (24→26) taken 251 times.
711 if (i >= str.length) {
669 152 return '\0';
670 }
671 559 return str.ptr[i];
672 }
673
674 /**
675 * Returns the character at the specified index offset.
676 *
677 * When the @p index is negative, the character is counted from the end of the
678 * string where -1 denotes the last character in the string.
679 *
680 * When the @p index is out of bounds, the function returns zero.
681 *
682 * @param str the string
683 * @param index the index offset
684 * @return the character at the index
685 * @see cx_strat()
686 */
687 #define cx_strat(str, index) cx_strat_(cx_strcast(str), index)
688
689 /**
690 * Searches for a character in a string.
691 * Internal function - do not use.
692 * @param string
693 * @param chr
694 * @return
695 * @see cx_strchr()
696 */
697 CX_EXTERN CX_NODISCARD
698 cxstring cx_strchr_(cxstring string, int chr);
699
700 /**
701 * Searches for a character in a string.
702 * Internal function - do not use.
703 * @param string
704 * @param chr
705 * @return
706 * @see cx_strrchr()
707 */
708 CX_EXTERN CX_NODISCARD
709 cxstring cx_strrchr_(cxstring string, int chr);
710
711 #ifdef __cplusplus
712 CX_CPPDECL cxstring cx_strchr_cpp_(cxstring string, int chr) {
713 return cx_strchr_(string, chr);
714 }
715 CX_CPPDECL cxmutstr cx_strchr_cpp_(cxmutstr string, int chr) {
716 return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr));
717 }
718 #define cx_strchr(s, chr) cx_strchr_cpp_(cx_strcast_m(s), chr)
719 CX_CPPDECL cxstring cx_strrchr_cpp_(cxstring string, int chr) {
720 return cx_strrchr_(string, chr);
721 }
722 CX_CPPDECL cxmutstr cx_strrchr_cpp_(cxmutstr string, int chr) {
723 return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr));
724 }
725 #define cx_strrchr(s, chr) cx_strrchr_cpp_(cx_strcast_m(s), chr)
726 #else
727 /**
728 * Internal conversion function - do not use.
729 * @param string
730 * @param chr
731 * @return
732 */
733 CX_INLINE cxmutstr cx_strchr_m_(cxmutstr string, int chr) {
734 return cx_mutstrcast(cx_strchr_(cx_strcast(string), chr));
735 }
736 /**
737 * Internal conversion function - do not use.
738 * @param string
739 * @param chr
740 * @return
741 */
742 CX_INLINE cxmutstr cx_strrchr_m_(cxmutstr string, int chr) {
743 return cx_mutstrcast(cx_strrchr_(cx_strcast(string), chr));
744 }
745
746 /**
747 * Returns a substring starting at the location of the first occurrence of the
748 * specified character.
749 *
750 * If the string does not contain the character, an empty string is returned.
751 *
752 * @param string the string where to locate the character
753 * @param chr (@c int) the character to locate
754 * @return (@c cxstring or @c cxmutstr) a substring starting at the first
755 * location of @p chr
756 */
757 #define cx_strchr(string, chr) _Generic(cx_strcast_m(string), \
758 cxstring: cx_strchr_, \
759 cxmutstr: cx_strchr_m_)(cx_strcast_m(string), chr)
760
761 /**
762 * Returns a substring starting at the location of the last occurrence of the
763 * specified character.
764 *
765 * If the string does not contain the character, an empty string is returned.
766 *
767 * @param string the string where to locate the character
768 * @param chr (@c int) the character to locate
769 * @return (@c cxstring or @c cxmutstr) a substring starting at the last
770 * location of @p chr
771 */
772 #define cx_strrchr(string, chr) _Generic(cx_strcast_m(string), \
773 cxstring: cx_strrchr_, \
774 cxmutstr: cx_strrchr_m_)(cx_strcast_m(string), chr)
775 #endif
776
777 /**
778 * Searches for a specific substring.
779 *
780 * Internal function - do not use.
781 *
782 * @param haystack the string to be scanned
783 * @param needle string containing the sequence of characters to match
784 * @return a substring starting at the first occurrence of @p needle,
785 * or an empty string, if the sequence is not contained
786 * @see cx_strstr()
787 */
788 CX_EXTERN CX_NODISCARD
789 cxstring cx_strstr_(cxstring haystack, cxstring needle);
790
791 #ifdef __cplusplus
792 CX_CPPDECL cxstring cx_strstr_cpp_(cxstring haystack, cxstring needle) {
793 return cx_strstr_(haystack, needle);
794 }
795 CX_CPPDECL cxmutstr cx_strstr_cpp_(cxmutstr haystack, cxstring needle) {
796 return cx_mutstrcast(cx_strstr_(cx_strcast(haystack), needle));
797 }
798 #define cx_strstr(h,n) cx_strstr_cpp_(cx_strcast_m(h), cx_strcast(n))
799 #else
800 /**
801 * Internal conversion - do not use.
802 * @param haystack
803 * @param needle
804 * @return
805 */
806 CX_INLINE cxmutstr cx_strstr_m_(cxmutstr haystack, cxstring needle) {
807 return cx_mutstrcast(cx_strstr_(cx_strcast(haystack), needle));
808 }
809
810 /**
811 * Returns a substring starting at the location of the first occurrence of the
812 * specified string.
813 *
814 * If @p haystack does not contain @p needle, an empty string is returned.
815 *
816 * If @p needle is an empty string, the complete @p haystack is
817 * returned.
818 *
819 * @param haystack the string to be scanned
820 * @param needle string containing the sequence of characters to match
821 * @return (@c cxstring or @c cxmutstr) a substring starting at the first
822 * occurrence of @p needle, or an empty string, if the sequence is not contained
823 */
824 #define cx_strstr(haystack, needle) _Generic(cx_strcast_m(haystack), \
825 cxstring: cx_strstr_,\
826 cxmutstr: cx_strstr_m_)(cx_strcast_m(haystack), cx_strcast(needle))
827 #endif
828
829 /**
830 * Splits a given string using a delimiter string.
831 *
832 * Internal function - do not use.
833 *
834 * @param string the string to split
835 * @param delim the delimiter
836 * @param limit the maximum number of split items
837 * @param output the output array
838 * @return the actual number of split items
839 * @see cx_strsplit()
840 */
841 CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(4, 3)
842 size_t cx_strsplit_(cxstring string, cxstring delim,
843 size_t limit, cxstring *output);
844
845 /**
846 * Splits a given string using a delimiter string.
847 *
848 * Internal function - do not use.
849 *
850 * @param allocator the allocator to use for allocating the resulting array
851 * @param string the string to split
852 * @param delim the delimiter
853 * @param limit the maximum number of split items
854 * @param output the output array
855 * @return the actual number of split items
856 * @see cx_strsplit_a()
857 */
858 CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(5)
859 size_t cx_strsplit_a_(const CxAllocator *allocator,
860 cxstring string, cxstring delim,
861 size_t limit, cxstring **output);
862
863
864 /**
865 * Splits a given string using a delimiter string.
866 *
867 * Internal function - do not use.
868 *
869 * @param string the string to split
870 * @param delim the delimiter
871 * @param limit the maximum number of split items
872 * @param output the output array
873 * @return the actual number of split items
874 * @see cx_strsplit_m()
875 */
876 CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(4, 3)
877 size_t cx_strsplit_m_(cxmutstr string, cxstring delim,
878 size_t limit, cxmutstr *output);
879
880 /**
881 * Splits a given string using a delimiter string.
882 *
883 * Internal function - do not use.
884 *
885 * @param allocator the allocator to use for allocating the resulting array
886 * @param string the string to split
887 * @param delim the delimiter
888 * @param limit the maximum number of split items
889 * @param output the output array
890 * @return the actual number of split items
891 * @see cx_strsplit_ma()
892 */
893 CX_EXTERN CX_NODISCARD CX_NONNULL CX_ACCESS_W(5)
894 size_t cx_strsplit_ma_(const CxAllocator *allocator,
895 cxmutstr string, cxstring delim, size_t limit,
896 cxmutstr **output);
897
898 #ifdef __cplusplus
899 CX_CPPDECL size_t cx_strsplit_cpp_(cxstring string, cxstring delim,
900 size_t limit, cxstring *output) {
901 return cx_strsplit_(string, delim, limit, output);
902 }
903 CX_CPPDECL size_t cx_strsplit_cpp_(cxmutstr string, cxstring delim,
904 size_t limit, cxmutstr *output) {
905 return cx_strsplit_m_(string, delim, limit, output);
906 }
907 CX_CPPDECL size_t cx_strsplit_a_cpp_(const CxAllocator *allocator,
908 cxstring string, cxstring delim, size_t limit, cxstring **output) {
909 return cx_strsplit_a_(allocator, string, delim, limit, output);
910 }
911 CX_CPPDECL size_t cx_strsplit_a_cpp_(const CxAllocator *allocator,
912 cxmutstr string, cxstring delim, size_t limit, cxmutstr **output) {
913 return cx_strsplit_ma_(allocator, string, delim, limit, output);
914 }
915 #define cx_strsplit(string, delim, limit, output) \
916 cx_strsplit_cpp_(cx_strcast_m(string), cx_strcast(delim), limit, output)
917 #define cx_strsplit_a(allocator, string, delim, limit, output) \
918 cx_strsplit_a_cpp_(allocator, cx_strcast_m(string), cx_strcast(delim), limit, output)
919 #else
920 /**
921 * Splits a given string using a delimiter string.
922 *
923 * @note The resulting array contains strings that point to the source
924 * @p string. Use cx_strdup() to get copies.
925 *
926 * @param string the string to split
927 * @param delim the delimiter
928 * @param limit (@c size_t) the maximum number of split items
929 * @param output (@c cxstring* or @c cxmutstr*) a preallocated array of at
930 * least @p limit length
931 * @return the actual number of split items
932 */
933 #define cx_strsplit(string, delim, limit, output) \
934 _Generic(cx_strcast_m(string), \
935 cxstring: cx_strsplit_, \
936 cxmutstr: cx_strsplit_m_)\
937 (cx_strcast_m(string), cx_strcast(delim), limit, output)
938
939 /**
940 * Splits a given string using a delimiter string.
941 *
942 * The array pointed to by @p output will be allocated by @p allocator.
943 *
944 * @note The resulting array contains strings that point to the source
945 * @p string. Use cx_strdup() to get copies.
946 *
947 * @attention If allocation fails, the @c NULL pointer will be written to
948 * @p output and the number returned will be zero.
949 *
950 * @param allocator (@c CxAllocator*) the allocator to use for allocating the resulting array
951 * @param string the string to split
952 * @param delim the delimiter
953 * @param limit (@c size_t) the maximum number of split items
954 * @param output (@c cxstring** or @c cxmutstr**) a pointer where the address
955 * of the allocated array shall be written to
956 * @return the actual number of split items
957 */
958 #define cx_strsplit_a(allocator, string, delim, limit, output) \
959 _Generic(cx_strcast_m(string), \
960 cxstring: cx_strsplit_a_, \
961 cxmutstr: cx_strsplit_ma_)\
962 (allocator, cx_strcast_m(string), cx_strcast(delim), limit, output)
963 #endif
964
965 /**
966 * Compares two strings.
967 *
968 * @param s1 the first string
969 * @param s2 the second string
970 * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
971 * than @p s2, zero if both strings equal
972 */
973 CX_EXTERN CX_NODISCARD
974 int cx_strcmp_(cxstring s1, cxstring s2);
975
976 /**
977 * Compares two strings.
978 *
979 * @param s1 the first string
980 * @param s2 the second string
981 * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
982 * than @p s2, zero if both strings equal
983 */
984 #define cx_strcmp(s1, s2) cx_strcmp_(cx_strcast(s1), cx_strcast(s2))
985
986 /**
987 * Compares two strings ignoring case.
988 *
989 * @param s1 the first string
990 * @param s2 the second string
991 * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
992 * than @p s2, zero if both strings equal ignoring case
993 */
994 CX_EXTERN CX_NODISCARD
995 int cx_strcasecmp_(cxstring s1, cxstring s2);
996
997 /**
998 * Compares two strings ignoring case.
999 *
1000 * @param s1 the first string
1001 * @param s2 the second string
1002 * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
1003 * than @p s2, zero if both strings equal ignoring case
1004 */
1005 #define cx_strcasecmp(s1, s2) cx_strcasecmp_(cx_strcast(s1), cx_strcast(s2))
1006
1007 /**
1008 * Compares two strings.
1009 *
1010 * This function has a compatible signature for the use as a cx_compare_func.
1011 *
1012 * @attention This function can @em only compare UCX strings. It is unsafe to
1013 * pass normal C-strings to this function.
1014 *
1015 * @param s1 the first string
1016 * @param s2 the second string
1017 * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
1018 * than @p s2, zero if both strings equal
1019 */
1020 CX_EXTERN CX_NODISCARD CX_NONNULL
1021 int cx_strcmp_p(const void *s1, const void *s2);
1022
1023 /**
1024 * Compares two strings ignoring case.
1025 *
1026 * This function has a compatible signature for the use as a cx_compare_func.
1027 *
1028 * @param s1 the first string
1029 * @param s2 the second string
1030 * @return negative if @p s1 is smaller than @p s2, positive if @p s1 is larger
1031 * than @p s2, zero if both strings equal ignoring case
1032 */
1033 CX_EXTERN CX_NODISCARD CX_NONNULL
1034 int cx_strcasecmp_p(const void *s1, const void *s2);
1035
1036 /**
1037 * Creates a duplicate of the specified string.
1038 *
1039 * The new string will contain a copy allocated by @p allocator.
1040 *
1041 * @note The returned string is guaranteed to be zero-terminated.
1042 *
1043 * @param allocator the allocator to use
1044 * @param string the string to duplicate
1045 * @return a duplicate of the string
1046 * @see cx_strdup()
1047 */
1048 CX_EXTERN CX_NODISCARD CX_NONNULL
1049 cxmutstr cx_strdup_a_(const CxAllocator *allocator, cxstring string);
1050
1051 /**
1052 * Creates a duplicate of the specified string.
1053 *
1054 * The new string will contain a copy allocated by @p allocator.
1055 *
1056 * @note The returned string is guaranteed to be zero-terminated.
1057 *
1058 * @param allocator (@c CxAllocator*) the allocator to use
1059 * @param string the string to duplicate
1060 * @return (@c cxmutstr) a duplicate of the string
1061 * @see cx_strdup()
1062 * @see cx_strfree_a()
1063 */
1064 #define cx_strdup_a(allocator, string) cx_strdup_a_((allocator), cx_strcast(string))
1065
1066 /**
1067 * Creates a duplicate of the specified string.
1068 *
1069 * The new string will contain a copy allocated by the cxDefaultAllocator.
1070 * So developers @em must pass the return value to cx_strfree().
1071 *
1072 * @note The returned string is guaranteed to be zero-terminated.
1073 *
1074 * @param string the string to duplicate
1075 * @return (@c cxmutstr) a duplicate of the string
1076 * @see cx_strdup_a()
1077 * @see cx_strfree()
1078 */
1079 #define cx_strdup(string) cx_strdup_a(cxDefaultAllocator, string)
1080
1081 /**
1082 * Trims a string.
1083 * Internal function - do not use.
1084 * @param string
1085 * @return
1086 */
1087 CX_EXTERN CX_NODISCARD
1088 cxstring cx_strtrim_(cxstring string);
1089
1090 #ifdef __cplusplus
1091 CX_CPPDECL cxstring cx_strtrim_cpp_(cxstring string) {
1092 return cx_strtrim_(string);
1093 }
1094 CX_CPPDECL cxmutstr cx_strtrim_cpp_(cxmutstr string) {
1095 return cx_mutstrcast(cx_strtrim_(cx_strcast(string)));
1096 }
1097 #define cx_strtrim(string) cx_strtrim_cpp_(cx_strcast_m(string))
1098 #else
1099 /**
1100 * Internal conversion function.
1101 * @param string
1102 * @return
1103 */
1104 CX_INLINE cxmutstr cx_strtrim_m_(cxmutstr string) {
1105 return cx_mutstrcast(cx_strtrim_(cx_strcast(string)));
1106 }
1107
1108 /**
1109 * Omits leading and trailing spaces.
1110 *
1111 * @note the returned string references the same memory, thus you
1112 * must @em not free the returned memory.
1113 *
1114 * @param string the string that shall be trimmed
1115 * @return (@c cxstring or @c cxmutstr) the trimmed string
1116 */
1117 #define cx_strtrim(string) _Generic(cx_strcast_m(string), \
1118 cxstring: cx_strtrim_, \
1119 cxmutstr: cx_strtrim_m_)(cx_strcast_m(string))
1120 #endif
1121
1122 /**
1123 * Checks if a string has a specific prefix.
1124 *
1125 * @param string the string to check
1126 * @param prefix the prefix the string should have
1127 * @return @c true, if and only if the string has the specified prefix,
1128 * @c false otherwise
1129 */
1130 CX_EXTERN CX_NODISCARD
1131 bool cx_strprefix_(cxstring string, cxstring prefix);
1132
1133 /**
1134 * Checks if a string has a specific prefix.
1135 *
1136 * @param string the string to check
1137 * @param prefix the prefix the string should have
1138 * @return @c true, if and only if the string has the specified prefix,
1139 * @c false otherwise
1140 */
1141 #define cx_strprefix(string, prefix) cx_strprefix_(cx_strcast(string), cx_strcast(prefix))
1142
1143 /**
1144 * Checks if a string has a specific suffix.
1145 *
1146 * @param string the string to check
1147 * @param suffix the suffix the string should have
1148 * @return @c true, if and only if the string has the specified suffix,
1149 * @c false otherwise
1150 */
1151 CX_EXTERN CX_NODISCARD
1152 bool cx_strsuffix_(cxstring string, cxstring suffix);
1153
1154 /**
1155 * Checks if a string has a specific suffix.
1156 *
1157 * @param string the string to check
1158 * @param suffix the suffix the string should have
1159 * @return @c true, if and only if the string has the specified suffix,
1160 * @c false otherwise
1161 */
1162 #define cx_strsuffix(string, suffix) cx_strsuffix_(cx_strcast(string), cx_strcast(suffix))
1163
1164 /**
1165 * Checks if a string has a specific prefix, ignoring the case.
1166 *
1167 * @param string the string to check
1168 * @param prefix the prefix the string should have
1169 * @return @c true, if and only if the string has the specified prefix,
1170 * @c false otherwise
1171 */
1172 CX_EXTERN CX_NODISCARD
1173 bool cx_strcaseprefix_(cxstring string, cxstring prefix);
1174
1175 /**
1176 * Checks if a string has a specific prefix, ignoring the case.
1177 *
1178 * @param string the string to check
1179 * @param prefix the prefix the string should have
1180 * @return @c true, if and only if the string has the specified prefix,
1181 * @c false otherwise
1182 */
1183 #define cx_strcaseprefix(string, prefix) cx_strcaseprefix_(cx_strcast(string), cx_strcast(prefix))
1184
1185 /**
1186 * Checks, if a string has a specific suffix, ignoring the case.
1187 *
1188 * @param string the string to check
1189 * @param suffix the suffix the string should have
1190 * @return @c true, if and only if the string has the specified suffix,
1191 * @c false otherwise
1192 */
1193 CX_EXTERN CX_NODISCARD
1194 bool cx_strcasesuffix_(cxstring string, cxstring suffix);
1195
1196 /**
1197 * Checks, if a string has a specific suffix, ignoring the case.
1198 *
1199 * @param string the string to check
1200 * @param suffix the suffix the string should have
1201 * @return @c true, if and only if the string has the specified suffix,
1202 * @c false otherwise
1203 */
1204 #define cx_strcasesuffix(string, suffix) cx_strcasesuffix_(cx_strcast(string), cx_strcast(suffix))
1205
1206 /**
1207 * Replaces a string with another string.
1208 *
1209 * Internal function - do not use.
1210 *
1211 * @param allocator
1212 * @param str
1213 * @param search
1214 * @param replacement
1215 * @param replmax
1216 * @return
1217 * @see cx_strreplace_a()
1218 * @see cx_strreplace()
1219 * @see cx_strreplacen_a()
1220 * @see cx_strreplacen()
1221 */
1222 CX_EXTERN CX_NODISCARD CX_NONNULL
1223 cxmutstr cx_strreplace_(const CxAllocator *allocator,
1224 cxstring str, cxstring search, cxstring replacement, size_t replmax);
1225
1226 /**
1227 * Replaces a string with another string.
1228 *
1229 * The function replaces at most @p replmax occurrences.
1230 *
1231 * The returned string will be allocated by @p allocator and is guaranteed
1232 * to be zero-terminated.
1233 *
1234 * If allocation fails, or the input string is empty,
1235 * the returned string will be empty.
1236 *
1237 * @param allocator (@c CxAllocator*) the allocator to use
1238 * @param str the string where replacements should be applied
1239 * @param search the string to search for
1240 * @param replacement the replacement string
1241 * @param replmax (@c size_t) maximum number of replacements
1242 * @return (@c cxmutstr) the resulting string after applying the replacements
1243 */
1244 #define cx_strreplacen_a(allocator, str, search, replacement, replmax) \
1245 cx_strreplace_(allocator, cx_strcast(str), cx_strcast(search), cx_strcast(replacement), replmax)
1246
1247 /**
1248 * Replaces a string with another string.
1249 *
1250 * The function replaces at most @p replmax occurrences.
1251 *
1252 * The returned string will be allocated by the cxDefaultAllocator and is guaranteed
1253 * to be zero-terminated.
1254 *
1255 * If allocation fails, or the input string is empty,
1256 * the returned string will be empty.
1257 *
1258 * @param str the string where replacements should be applied
1259 * @param search the string to search for
1260 * @param replacement the replacement string
1261 * @param replmax (@c size_t) maximum number of replacements
1262 * @return (@c cxmutstr) the resulting string after applying the replacements
1263 */
1264 #define cx_strreplacen(str, search, replacement, replmax) \
1265 cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, replmax)
1266
1267 /**
1268 * Replaces a string with another string.
1269 *
1270 * The returned string will be allocated by @p allocator and is guaranteed
1271 * to be zero-terminated.
1272 *
1273 * If allocation fails, or the input string is empty,
1274 * the returned string will be empty.
1275 *
1276 * @param allocator (@c CxAllocator*) the allocator to use
1277 * @param str the string where replacements should be applied
1278 * @param search the string to search for
1279 * @param replacement the replacement string
1280 * @return (@c cxmutstr) the resulting string after applying the replacements
1281 */
1282 #define cx_strreplace_a(allocator, str, search, replacement) \
1283 cx_strreplacen_a(allocator, str, search, replacement, SIZE_MAX)
1284
1285 /**
1286 * Replaces a string with another string.
1287 *
1288 * The returned string will be allocated by the cxDefaultAllocator and is guaranteed
1289 * to be zero-terminated.
1290 *
1291 * If allocation fails, or the input string is empty,
1292 * the returned string will be empty.
1293 *
1294 * @param str the string where replacements should be applied
1295 * @param search the string to search for
1296 * @param replacement the replacement string
1297 * @return (@c cxmutstr) the resulting string after applying the replacements
1298 */
1299 #define cx_strreplace(str, search, replacement) \
1300 cx_strreplacen_a(cxDefaultAllocator, str, search, replacement, SIZE_MAX)
1301
1302 /**
1303 * Creates a string tokenization context.
1304 *
1305 * @param str the string to tokenize
1306 * @param delim the delimiter (must not be empty)
1307 * @param limit the maximum number of tokens that shall be returned
1308 * @return a new string tokenization context
1309 */
1310 CX_EXTERN CX_NODISCARD
1311 CxStrtokCtx cx_strtok_(cxstring str, cxstring delim, size_t limit);
1312
1313 /**
1314 * Creates a string tokenization context.
1315 *
1316 * @param str the string to tokenize
1317 * @param delim the delimiter string (must not be empty)
1318 * @param limit (@c size_t) the maximum number of tokens that shall be returned
1319 * @return (@c CxStrtokCtx) a new string tokenization context
1320 */
1321 #define cx_strtok(str, delim, limit) \
1322 cx_strtok_(cx_strcast(str), cx_strcast(delim), (limit))
1323
1324 /**
1325 * Returns the next token.
1326 *
1327 * The token will point to the source string.
1328 *
1329 * @param ctx the tokenization context
1330 * @param token a pointer to memory where the next token shall be stored
1331 * @return true if successful, false if the limit or the end of the string
1332 * has been reached
1333 */
1334 CX_EXTERN CX_NONNULL CX_NODISCARD CX_ACCESS_W(2)
1335 bool cx_strtok_next_(CxStrtokCtx *ctx, cxstring *token);
1336
1337 #ifdef __cplusplus
1338 CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxstring *token) {
1339 return cx_strtok_next_(ctx, token);
1340 }
1341 CX_CPPDECL cx_strtok_next(CxStrtokCtx *ctx, cxmutstr *token) {
1342 // Note: this is actually UB - fixed with start_lifetime_as() in C++23
1343 // but it works on all supported platforms
1344 return cx_strtok_next_(ctx, reinterpret_cast<cxstring*>(token));
1345 }
1346 #else // ! __cplusplus
1347 /**
1348 * Returns the next token.
1349 *
1350 * The token will point to the source string.
1351 *
1352 * @param ctx (@c CxStrtokCtx*) the tokenization context
1353 * @param token a pointer to either a @c cxstring or @c cxmutstr
1354 * where the next token shall be stored
1355 * @return true if successful, false if the limit or the end of the string
1356 * has been reached
1357 */
1358 #define cx_strtok_next(ctx, token) _Generic((token), \
1359 cxstring*: cx_strtok_next_, \
1360 cxmutstr*: cx_strtok_next_)(ctx, (cxstring*)token)
1361 #endif
1362
1363 /**
1364 * Defines an array of more delimiters for the specified tokenization context.
1365 *
1366 * @param ctx the tokenization context
1367 * @param delim array of more delimiters
1368 * @param count number of elements in the array
1369 */
1370 CX_EXTERN CX_NONNULL CX_ACCESS_R(2, 3)
1371 void cx_strtok_delim(CxStrtokCtx *ctx, const cxstring *delim, size_t count);
1372
1373 /* ------------------------------------------------------------------------- *
1374 * string to number conversion functions *
1375 * ------------------------------------------------------------------------- */
1376
1377 /**
1378 * Converts a string to a number.
1379 *
1380 * The function returns non-zero when conversion is not possible.
1381 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1382 * It sets errno to ERANGE when the target datatype is too small.
1383 *
1384 * @param str the string to convert
1385 * @param output a pointer to the integer variable where the result shall be stored
1386 * @param base 2, 8, 10, or 16
1387 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1388 * @retval zero success
1389 * @retval non-zero conversion was not possible
1390 */
1391 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1392 int cx_strtos_lc_(cxstring str, short *output, int base, const char *groupsep);
1393
1394 /**
1395 * Converts a string to a number.
1396 *
1397 * The function returns non-zero when conversion is not possible.
1398 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1399 * It sets errno to ERANGE when the target datatype is too small.
1400 *
1401 * @param str the string to convert
1402 * @param output a pointer to the integer variable where the result shall be stored
1403 * @param base 2, 8, 10, or 16
1404 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1405 * @retval zero success
1406 * @retval non-zero conversion was not possible
1407 */
1408 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1409 int cx_strtoi_lc_(cxstring str, int *output, int base, const char *groupsep);
1410
1411 /**
1412 * Converts a string to a number.
1413 *
1414 * The function returns non-zero when conversion is not possible.
1415 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1416 * It sets errno to ERANGE when the target datatype is too small.
1417 *
1418 * @param str the string to convert
1419 * @param output a pointer to the integer variable where the result shall be stored
1420 * @param base 2, 8, 10, or 16
1421 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1422 * @retval zero success
1423 * @retval non-zero conversion was not possible
1424 */
1425 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1426 int cx_strtol_lc_(cxstring str, long *output, int base, const char *groupsep);
1427
1428 /**
1429 * Converts a string to a number.
1430 *
1431 * The function returns non-zero when conversion is not possible.
1432 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1433 * It sets errno to ERANGE when the target datatype is too small.
1434 *
1435 * @param str the string to convert
1436 * @param output a pointer to the integer variable where the result shall be stored
1437 * @param base 2, 8, 10, or 16
1438 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1439 * @retval zero success
1440 * @retval non-zero conversion was not possible
1441 */
1442 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1443 int cx_strtoll_lc_(cxstring str, long long *output, int base, const char *groupsep);
1444
1445 /**
1446 * Converts a string to a number.
1447 *
1448 * The function returns non-zero when conversion is not possible.
1449 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1450 * It sets errno to ERANGE when the target datatype is too small.
1451 *
1452 * @param str the string to convert
1453 * @param output a pointer to the integer variable where the result shall be stored
1454 * @param base 2, 8, 10, or 16
1455 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1456 * @retval zero success
1457 * @retval non-zero conversion was not possible
1458 */
1459 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1460 int cx_strtoi8_lc_(cxstring str, int8_t *output, int base, const char *groupsep);
1461
1462 /**
1463 * Converts a string to a number.
1464 *
1465 * The function returns non-zero when conversion is not possible.
1466 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1467 * It sets errno to ERANGE when the target datatype is too small.
1468 *
1469 * @param str the string to convert
1470 * @param output a pointer to the integer variable where the result shall be stored
1471 * @param base 2, 8, 10, or 16
1472 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1473 * @retval zero success
1474 * @retval non-zero conversion was not possible
1475 */
1476 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1477 int cx_strtoi16_lc_(cxstring str, int16_t *output, int base, const char *groupsep);
1478
1479 /**
1480 * Converts a string to a number.
1481 *
1482 * The function returns non-zero when conversion is not possible.
1483 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1484 * It sets errno to ERANGE when the target datatype is too small.
1485 *
1486 * @param str the string to convert
1487 * @param output a pointer to the integer variable where the result shall be stored
1488 * @param base 2, 8, 10, or 16
1489 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1490 * @retval zero success
1491 * @retval non-zero conversion was not possible
1492 */
1493 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1494 int cx_strtoi32_lc_(cxstring str, int32_t *output, int base, const char *groupsep);
1495
1496 /**
1497 * Converts a string to a number.
1498 *
1499 * The function returns non-zero when conversion is not possible.
1500 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1501 * It sets errno to ERANGE when the target datatype is too small.
1502 *
1503 * @param str the string to convert
1504 * @param output a pointer to the integer variable where the result shall be stored
1505 * @param base 2, 8, 10, or 16
1506 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1507 * @retval zero success
1508 * @retval non-zero conversion was not possible
1509 */
1510 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1511 int cx_strtoi64_lc_(cxstring str, int64_t *output, int base, const char *groupsep);
1512
1513 /**
1514 * Converts a string to a number.
1515 *
1516 * The function returns non-zero when conversion is not possible.
1517 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1518 * It sets errno to ERANGE when the target datatype is too small.
1519 *
1520 * @param str the string to convert
1521 * @param output a pointer to the integer variable where the result shall be stored
1522 * @param base 2, 8, 10, or 16
1523 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1524 * @retval zero success
1525 * @retval non-zero conversion was not possible
1526 */
1527 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1528 int cx_strtous_lc_(cxstring str, unsigned short *output, int base, const char *groupsep);
1529
1530 /**
1531 * Converts a string to a number.
1532 *
1533 * The function returns non-zero when conversion is not possible.
1534 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1535 * It sets errno to ERANGE when the target datatype is too small.
1536 *
1537 * @param str the string to convert
1538 * @param output a pointer to the integer variable where the result shall be stored
1539 * @param base 2, 8, 10, or 16
1540 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1541 * @retval zero success
1542 * @retval non-zero conversion was not possible
1543 */
1544 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1545 int cx_strtou_lc_(cxstring str, unsigned int *output, int base, const char *groupsep);
1546
1547 /**
1548 * Converts a string to a number.
1549 *
1550 * The function returns non-zero when conversion is not possible.
1551 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1552 * It sets errno to ERANGE when the target datatype is too small.
1553 *
1554 * @param str the string to convert
1555 * @param output a pointer to the integer variable where the result shall be stored
1556 * @param base 2, 8, 10, or 16
1557 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1558 * @retval zero success
1559 * @retval non-zero conversion was not possible
1560 */
1561 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1562 int cx_strtoul_lc_(cxstring str, unsigned long *output, int base, const char *groupsep);
1563
1564 /**
1565 * Converts a string to a number.
1566 *
1567 * The function returns non-zero when conversion is not possible.
1568 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1569 * It sets errno to ERANGE when the target datatype is too small.
1570 *
1571 * @param str the string to convert
1572 * @param output a pointer to the integer variable where the result shall be stored
1573 * @param base 2, 8, 10, or 16
1574 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1575 * @retval zero success
1576 * @retval non-zero conversion was not possible
1577 */
1578 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1579 int cx_strtoull_lc_(cxstring str, unsigned long long *output, int base, const char *groupsep);
1580
1581 /**
1582 * Converts a string to a number.
1583 *
1584 * The function returns non-zero when conversion is not possible.
1585 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1586 * It sets errno to ERANGE when the target datatype is too small.
1587 *
1588 * @param str the string to convert
1589 * @param output a pointer to the integer variable where the result shall be stored
1590 * @param base 2, 8, 10, or 16
1591 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1592 * @retval zero success
1593 * @retval non-zero conversion was not possible
1594 */
1595 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1596 int cx_strtou8_lc_(cxstring str, uint8_t *output, int base, const char *groupsep);
1597
1598 /**
1599 * Converts a string to a number.
1600 *
1601 * The function returns non-zero when conversion is not possible.
1602 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1603 * It sets errno to ERANGE when the target datatype is too small.
1604 *
1605 * @param str the string to convert
1606 * @param output a pointer to the integer variable where the result shall be stored
1607 * @param base 2, 8, 10, or 16
1608 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1609 * @retval zero success
1610 * @retval non-zero conversion was not possible
1611 */
1612 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1613 int cx_strtou16_lc_(cxstring str, uint16_t *output, int base, const char *groupsep);
1614
1615 /**
1616 * Converts a string to a number.
1617 *
1618 * The function returns non-zero when conversion is not possible.
1619 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1620 * It sets errno to ERANGE when the target datatype is too small.
1621 *
1622 * @param str the string to convert
1623 * @param output a pointer to the integer variable where the result shall be stored
1624 * @param base 2, 8, 10, or 16
1625 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1626 * @retval zero success
1627 * @retval non-zero conversion was not possible
1628 */
1629 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1630 int cx_strtou32_lc_(cxstring str, uint32_t *output, int base, const char *groupsep);
1631
1632 /**
1633 * Converts a string to a number.
1634 *
1635 * The function returns non-zero when conversion is not possible.
1636 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1637 * It sets errno to ERANGE when the target datatype is too small.
1638 *
1639 * @param str the string to convert
1640 * @param output a pointer to the integer variable where the result shall be stored
1641 * @param base 2, 8, 10, or 16
1642 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1643 * @retval zero success
1644 * @retval non-zero conversion was not possible
1645 */
1646 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1647 int cx_strtou64_lc_(cxstring str, uint64_t *output, int base, const char *groupsep);
1648
1649 /**
1650 * Converts a string to a number.
1651 *
1652 * The function returns non-zero when conversion is not possible.
1653 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1654 * It sets errno to ERANGE when the target datatype is too small.
1655 *
1656 * @param str the string to convert
1657 * @param output a pointer to the integer variable where the result shall be stored
1658 * @param base 2, 8, 10, or 16
1659 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1660 * @retval zero success
1661 * @retval non-zero conversion was not possible
1662 */
1663 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1664 int cx_strtoz_lc_(cxstring str, size_t *output, int base, const char *groupsep);
1665
1666 /**
1667 * Converts a string to a single precision floating-point number.
1668 *
1669 * The function returns non-zero when conversion is not possible.
1670 * In that case the function sets errno to EINVAL when the reason is an invalid character.
1671 * It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h.
1672 *
1673 * @param str the string to convert
1674 * @param output a pointer to the float variable where the result shall be stored
1675 * @param decsep the decimal separator
1676 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1677 * @retval zero success
1678 * @retval non-zero conversion was not possible
1679 */
1680 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1681 int cx_strtof_lc_(cxstring str, float *output, char decsep, const char *groupsep);
1682
1683 /**
1684 * Converts a string to a double precision floating-point number.
1685 *
1686 * The function returns non-zero when conversion is not possible.
1687 * In that case the function sets errno to EINVAL when the reason is an invalid character.
1688 * It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h.
1689 *
1690 * @param str the string to convert
1691 * @param output a pointer to the float variable where the result shall be stored
1692 * @param decsep the decimal separator
1693 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
1694 * @retval zero success
1695 * @retval non-zero conversion was not possible
1696 */
1697 CX_EXTERN CX_ACCESS_W(2) CX_NONNULL_ARG(2)
1698 int cx_strtod_lc_(cxstring str, double *output, char decsep, const char *groupsep);
1699
1700 /**
1701 * Converts a string to a number.
1702 *
1703 * The function returns non-zero when conversion is not possible.
1704 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1705 * It sets errno to ERANGE when the target datatype is too small.
1706 *
1707 * @param str the string to convert
1708 * @param output a pointer to the integer variable where the result shall be stored
1709 * @param base 2, 8, 10, or 16
1710 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1711 * @retval zero success
1712 * @retval non-zero conversion was not possible
1713 */
1714 #define cx_strtos_lc(str, output, base, groupsep) cx_strtos_lc_(cx_strcast(str), output, base, groupsep)
1715
1716 /**
1717 * Converts a string to a number.
1718 *
1719 * The function returns non-zero when conversion is not possible.
1720 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1721 * It sets errno to ERANGE when the target datatype is too small.
1722 *
1723 * @param str the string to convert
1724 * @param output a pointer to the integer variable where the result shall be stored
1725 * @param base 2, 8, 10, or 16
1726 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1727 * @retval zero success
1728 * @retval non-zero conversion was not possible
1729 */
1730 #define cx_strtoi_lc(str, output, base, groupsep) cx_strtoi_lc_(cx_strcast(str), output, base, groupsep)
1731
1732 /**
1733 * Converts a string to a number.
1734 *
1735 * The function returns non-zero when conversion is not possible.
1736 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1737 * It sets errno to ERANGE when the target datatype is too small.
1738 *
1739 * @param str the string to convert
1740 * @param output a pointer to the integer variable where the result shall be stored
1741 * @param base 2, 8, 10, or 16
1742 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1743 * @retval zero success
1744 * @retval non-zero conversion was not possible
1745 */
1746 #define cx_strtol_lc(str, output, base, groupsep) cx_strtol_lc_(cx_strcast(str), output, base, groupsep)
1747
1748 /**
1749 * Converts a string to a number.
1750 *
1751 * The function returns non-zero when conversion is not possible.
1752 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1753 * It sets errno to ERANGE when the target datatype is too small.
1754 *
1755 * @param str the string to convert
1756 * @param output a pointer to the integer variable where the result shall be stored
1757 * @param base 2, 8, 10, or 16
1758 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1759 * @retval zero success
1760 * @retval non-zero conversion was not possible
1761 */
1762 #define cx_strtoll_lc(str, output, base, groupsep) cx_strtoll_lc_(cx_strcast(str), output, base, groupsep)
1763
1764 /**
1765 * Converts a string to a number.
1766 *
1767 * The function returns non-zero when conversion is not possible.
1768 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1769 * It sets errno to ERANGE when the target datatype is too small.
1770 *
1771 * @param str the string to convert
1772 * @param output a pointer to the integer variable where the result shall be stored
1773 * @param base 2, 8, 10, or 16
1774 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1775 * @retval zero success
1776 * @retval non-zero conversion was not possible
1777 */
1778 #define cx_strtoi8_lc(str, output, base, groupsep) cx_strtoi8_lc_(cx_strcast(str), output, base, groupsep)
1779
1780 /**
1781 * Converts a string to a number.
1782 *
1783 * The function returns non-zero when conversion is not possible.
1784 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1785 * It sets errno to ERANGE when the target datatype is too small.
1786 *
1787 * @param str the string to convert
1788 * @param output a pointer to the integer variable where the result shall be stored
1789 * @param base 2, 8, 10, or 16
1790 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1791 * @retval zero success
1792 * @retval non-zero conversion was not possible
1793 */
1794 #define cx_strtoi16_lc(str, output, base, groupsep) cx_strtoi16_lc_(cx_strcast(str), output, base, groupsep)
1795
1796 /**
1797 * Converts a string to a number.
1798 *
1799 * The function returns non-zero when conversion is not possible.
1800 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1801 * It sets errno to ERANGE when the target datatype is too small.
1802 *
1803 * @param str the string to convert
1804 * @param output a pointer to the integer variable where the result shall be stored
1805 * @param base 2, 8, 10, or 16
1806 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1807 * @retval zero success
1808 * @retval non-zero conversion was not possible
1809 */
1810 #define cx_strtoi32_lc(str, output, base, groupsep) cx_strtoi32_lc_(cx_strcast(str), output, base, groupsep)
1811
1812 /**
1813 * Converts a string to a number.
1814 *
1815 * The function returns non-zero when conversion is not possible.
1816 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1817 * It sets errno to ERANGE when the target datatype is too small.
1818 *
1819 * @param str the string to convert
1820 * @param output a pointer to the integer variable where the result shall be stored
1821 * @param base 2, 8, 10, or 16
1822 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1823 * @retval zero success
1824 * @retval non-zero conversion was not possible
1825 */
1826 #define cx_strtoi64_lc(str, output, base, groupsep) cx_strtoi64_lc_(cx_strcast(str), output, base, groupsep)
1827
1828 /**
1829 * Converts a string to a number.
1830 *
1831 * The function returns non-zero when conversion is not possible.
1832 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1833 * It sets errno to ERANGE when the target datatype is too small.
1834 *
1835 * @param str the string to convert
1836 * @param output a pointer to the integer variable where the result shall be stored
1837 * @param base 2, 8, 10, or 16
1838 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1839 * @retval zero success
1840 * @retval non-zero conversion was not possible
1841 */
1842 #define cx_strtous_lc(str, output, base, groupsep) cx_strtous_lc_(cx_strcast(str), output, base, groupsep)
1843
1844 /**
1845 * Converts a string to a number.
1846 *
1847 * The function returns non-zero when conversion is not possible.
1848 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1849 * It sets errno to ERANGE when the target datatype is too small.
1850 *
1851 * @param str the string to convert
1852 * @param output a pointer to the integer variable where the result shall be stored
1853 * @param base 2, 8, 10, or 16
1854 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1855 * @retval zero success
1856 * @retval non-zero conversion was not possible
1857 */
1858 #define cx_strtou_lc(str, output, base, groupsep) cx_strtou_lc_(cx_strcast(str), output, base, groupsep)
1859
1860 /**
1861 * Converts a string to a number.
1862 *
1863 * The function returns non-zero when conversion is not possible.
1864 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1865 * It sets errno to ERANGE when the target datatype is too small.
1866 *
1867 * @param str the string to convert
1868 * @param output a pointer to the integer variable where the result shall be stored
1869 * @param base 2, 8, 10, or 16
1870 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1871 * @retval zero success
1872 * @retval non-zero conversion was not possible
1873 */
1874 #define cx_strtoul_lc(str, output, base, groupsep) cx_strtoul_lc_(cx_strcast(str), output, base, groupsep)
1875
1876 /**
1877 * Converts a string to a number.
1878 *
1879 * The function returns non-zero when conversion is not possible.
1880 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1881 * It sets errno to ERANGE when the target datatype is too small.
1882 *
1883 * @param str the string to convert
1884 * @param output a pointer to the integer variable where the result shall be stored
1885 * @param base 2, 8, 10, or 16
1886 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1887 * @retval zero success
1888 * @retval non-zero conversion was not possible
1889 */
1890 #define cx_strtoull_lc(str, output, base, groupsep) cx_strtoull_lc_(cx_strcast(str), output, base, groupsep)
1891
1892 /**
1893 * Converts a string to a number.
1894 *
1895 * The function returns non-zero when conversion is not possible.
1896 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1897 * It sets errno to ERANGE when the target datatype is too small.
1898 *
1899 * @param str the string to convert
1900 * @param output a pointer to the integer variable where the result shall be stored
1901 * @param base 2, 8, 10, or 16
1902 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1903 * @retval zero success
1904 * @retval non-zero conversion was not possible
1905 */
1906 #define cx_strtou8_lc(str, output, base, groupsep) cx_strtou8_lc_(cx_strcast(str), output, base, groupsep)
1907
1908 /**
1909 * Converts a string to a number.
1910 *
1911 * The function returns non-zero when conversion is not possible.
1912 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1913 * It sets errno to ERANGE when the target datatype is too small.
1914 *
1915 * @param str the string to convert
1916 * @param output a pointer to the integer variable where the result shall be stored
1917 * @param base 2, 8, 10, or 16
1918 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1919 * @retval zero success
1920 * @retval non-zero conversion was not possible
1921 */
1922 #define cx_strtou16_lc(str, output, base, groupsep) cx_strtou16_lc_(cx_strcast(str), output, base, groupsep)
1923
1924 /**
1925 * Converts a string to a number.
1926 *
1927 * The function returns non-zero when conversion is not possible.
1928 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1929 * It sets errno to ERANGE when the target datatype is too small.
1930 *
1931 * @param str the string to convert
1932 * @param output a pointer to the integer variable where the result shall be stored
1933 * @param base 2, 8, 10, or 16
1934 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1935 * @retval zero success
1936 * @retval non-zero conversion was not possible
1937 */
1938 #define cx_strtou32_lc(str, output, base, groupsep) cx_strtou32_lc_(cx_strcast(str), output, base, groupsep)
1939
1940 /**
1941 * Converts a string to a number.
1942 *
1943 * The function returns non-zero when conversion is not possible.
1944 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1945 * It sets errno to ERANGE when the target datatype is too small.
1946 *
1947 * @param str the string to convert
1948 * @param output a pointer to the integer variable where the result shall be stored
1949 * @param base 2, 8, 10, or 16
1950 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1951 * @retval zero success
1952 * @retval non-zero conversion was not possible
1953 */
1954 #define cx_strtou64_lc(str, output, base, groupsep) cx_strtou64_lc_(cx_strcast(str), output, base, groupsep)
1955
1956 /**
1957 * Converts a string to a number.
1958 *
1959 * The function returns non-zero when conversion is not possible.
1960 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1961 * It sets errno to ERANGE when the target datatype is too small.
1962 *
1963 * @param str the string to convert
1964 * @param output a pointer to the integer variable where the result shall be stored
1965 * @param base 2, 8, 10, or 16
1966 * @param groupsep (@c const @c char*) each character in this string is treated as a group separator and ignored during conversion
1967 * @retval zero success
1968 * @retval non-zero conversion was not possible
1969 */
1970 #define cx_strtoz_lc(str, output, base, groupsep) cx_strtoz_lc_(cx_strcast(str), output, base, groupsep)
1971
1972 /**
1973 * Converts a string to a number.
1974 *
1975 * The function returns non-zero when conversion is not possible.
1976 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1977 * It sets errno to ERANGE when the target datatype is too small.
1978 *
1979 * The comma character is treated as a group separator and ignored during parsing.
1980 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
1981 *
1982 * @param str the string to convert
1983 * @param output a pointer to the integer variable where the result shall be stored
1984 * @param base 2, 8, 10, or 16
1985 * @retval zero success
1986 * @retval non-zero conversion was not possible
1987 */
1988 #define cx_strtos(str, output, base) cx_strtos_lc_(cx_strcast(str), output, base, ",")
1989
1990 /**
1991 * Converts a string to a number.
1992 *
1993 * The function returns non-zero when conversion is not possible.
1994 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
1995 * It sets errno to ERANGE when the target datatype is too small.
1996 *
1997 * The comma character is treated as a group separator and ignored during parsing.
1998 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
1999 *
2000 * @param str the string to convert
2001 * @param output a pointer to the integer variable where the result shall be stored
2002 * @param base 2, 8, 10, or 16
2003 * @retval zero success
2004 * @retval non-zero conversion was not possible
2005 */
2006 #define cx_strtoi(str, output, base) cx_strtoi_lc_(cx_strcast(str), output, base, ",")
2007
2008 /**
2009 * Converts a string to a number.
2010 *
2011 * The function returns non-zero when conversion is not possible.
2012 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2013 * It sets errno to ERANGE when the target datatype is too small.
2014 *
2015 * The comma character is treated as a group separator and ignored during parsing.
2016 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2017 *
2018 * @param str the string to convert
2019 * @param output a pointer to the integer variable where the result shall be stored
2020 * @param base 2, 8, 10, or 16
2021 * @retval zero success
2022 * @retval non-zero conversion was not possible
2023 */
2024 #define cx_strtol(str, output, base) cx_strtol_lc_(cx_strcast(str), output, base, ",")
2025
2026 /**
2027 * Converts a string to a number.
2028 *
2029 * The function returns non-zero when conversion is not possible.
2030 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2031 * It sets errno to ERANGE when the target datatype is too small.
2032 *
2033 * The comma character is treated as a group separator and ignored during parsing.
2034 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2035 *
2036 * @param str the string to convert
2037 * @param output a pointer to the integer variable where the result shall be stored
2038 * @param base 2, 8, 10, or 16
2039 * @retval zero success
2040 * @retval non-zero conversion was not possible
2041 */
2042 #define cx_strtoll(str, output, base) cx_strtoll_lc_(cx_strcast(str), output, base, ",")
2043
2044 /**
2045 * Converts a string to a number.
2046 *
2047 * The function returns non-zero when conversion is not possible.
2048 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2049 * It sets errno to ERANGE when the target datatype is too small.
2050 *
2051 * The comma character is treated as a group separator and ignored during parsing.
2052 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2053 *
2054 * @param str the string to convert
2055 * @param output a pointer to the integer variable where the result shall be stored
2056 * @param base 2, 8, 10, or 16
2057 * @retval zero success
2058 * @retval non-zero conversion was not possible
2059 */
2060 #define cx_strtoi8(str, output, base) cx_strtoi8_lc_(cx_strcast(str), output, base, ",")
2061
2062 /**
2063 * Converts a string to a number.
2064 *
2065 * The function returns non-zero when conversion is not possible.
2066 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2067 * It sets errno to ERANGE when the target datatype is too small.
2068 *
2069 * The comma character is treated as a group separator and ignored during parsing.
2070 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2071 *
2072 * @param str the string to convert
2073 * @param output a pointer to the integer variable where the result shall be stored
2074 * @param base 2, 8, 10, or 16
2075 * @retval zero success
2076 * @retval non-zero conversion was not possible
2077 */
2078 #define cx_strtoi16(str, output, base) cx_strtoi16_lc_(cx_strcast(str), output, base, ",")
2079
2080 /**
2081 * Converts a string to a number.
2082 *
2083 * The function returns non-zero when conversion is not possible.
2084 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2085 * It sets errno to ERANGE when the target datatype is too small.
2086 *
2087 * The comma character is treated as a group separator and ignored during parsing.
2088 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2089 *
2090 * @param str the string to convert
2091 * @param output a pointer to the integer variable where the result shall be stored
2092 * @param base 2, 8, 10, or 16
2093 * @retval zero success
2094 * @retval non-zero conversion was not possible
2095 */
2096 #define cx_strtoi32(str, output, base) cx_strtoi32_lc_(cx_strcast(str), output, base, ",")
2097
2098 /**
2099 * Converts a string to a number.
2100 *
2101 * The function returns non-zero when conversion is not possible.
2102 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2103 * It sets errno to ERANGE when the target datatype is too small.
2104 *
2105 * The comma character is treated as a group separator and ignored during parsing.
2106 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2107 *
2108 * @param str the string to convert
2109 * @param output a pointer to the integer variable where the result shall be stored
2110 * @param base 2, 8, 10, or 16
2111 * @retval zero success
2112 * @retval non-zero conversion was not possible
2113 */
2114 #define cx_strtoi64(str, output, base) cx_strtoi64_lc_(cx_strcast(str), output, base, ",")
2115
2116 /**
2117 * Converts a string to a number.
2118 *
2119 * The function returns non-zero when conversion is not possible.
2120 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2121 * It sets errno to ERANGE when the target datatype is too small.
2122 *
2123 * The comma character is treated as a group separator and ignored during parsing.
2124 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2125 *
2126 * @param str the string to convert
2127 * @param output a pointer to the integer variable where the result shall be stored
2128 * @param base 2, 8, 10, or 16
2129 * @retval zero success
2130 * @retval non-zero conversion was not possible
2131 */
2132 #define cx_strtoz(str, output, base) cx_strtoz_lc_(cx_strcast(str), output, base, ",")
2133
2134 /**
2135 * Converts a string to a number.
2136 *
2137 * The function returns non-zero when conversion is not possible.
2138 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2139 * It sets errno to ERANGE when the target datatype is too small.
2140 *
2141 * The comma character is treated as a group separator and ignored during parsing.
2142 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2143 *
2144 * @param str the string to convert
2145 * @param output a pointer to the integer variable where the result shall be stored
2146 * @param base 2, 8, 10, or 16
2147 * @retval zero success
2148 * @retval non-zero conversion was not possible
2149 */
2150 #define cx_strtous(str, output, base) cx_strtous_lc_(cx_strcast(str), output, base, ",")
2151
2152 /**
2153 * Converts a string to a number.
2154 *
2155 * The function returns non-zero when conversion is not possible.
2156 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2157 * It sets errno to ERANGE when the target datatype is too small.
2158 *
2159 * The comma character is treated as a group separator and ignored during parsing.
2160 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2161 *
2162 * @param str the string to convert
2163 * @param output a pointer to the integer variable where the result shall be stored
2164 * @param base 2, 8, 10, or 16
2165 * @retval zero success
2166 * @retval non-zero conversion was not possible
2167 */
2168 #define cx_strtou(str, output, base) cx_strtou_lc_(cx_strcast(str), output, base, ",")
2169
2170 /**
2171 * Converts a string to a number.
2172 *
2173 * The function returns non-zero when conversion is not possible.
2174 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2175 * It sets errno to ERANGE when the target datatype is too small.
2176 *
2177 * The comma character is treated as a group separator and ignored during parsing.
2178 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2179 *
2180 * @param str the string to convert
2181 * @param output a pointer to the integer variable where the result shall be stored
2182 * @param base 2, 8, 10, or 16
2183 * @retval zero success
2184 * @retval non-zero conversion was not possible
2185 */
2186 #define cx_strtoul(str, output, base) cx_strtoul_lc_(cx_strcast(str), output, base, ",")
2187
2188 /**
2189 * Converts a string to a number.
2190 *
2191 * The function returns non-zero when conversion is not possible.
2192 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2193 * It sets errno to ERANGE when the target datatype is too small.
2194 *
2195 * The comma character is treated as a group separator and ignored during parsing.
2196 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2197 *
2198 * @param str the string to convert
2199 * @param output a pointer to the integer variable where the result shall be stored
2200 * @param base 2, 8, 10, or 16
2201 * @retval zero success
2202 * @retval non-zero conversion was not possible
2203 */
2204 #define cx_strtoull(str, output, base) cx_strtoull_lc_(cx_strcast(str), output, base, ",")
2205
2206 /**
2207 * Converts a string to a number.
2208 *
2209 * The function returns non-zero when conversion is not possible.
2210 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2211 * It sets errno to ERANGE when the target datatype is too small.
2212 *
2213 * The comma character is treated as a group separator and ignored during parsing.
2214 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2215 *
2216 * @param str the string to convert
2217 * @param output a pointer to the integer variable where the result shall be stored
2218 * @param base 2, 8, 10, or 16
2219 * @retval zero success
2220 * @retval non-zero conversion was not possible
2221 */
2222 #define cx_strtou8(str, output, base) cx_strtou8_lc_(cx_strcast(str), output, base, ",")
2223
2224 /**
2225 * Converts a string to a number.
2226 *
2227 * The function returns non-zero when conversion is not possible.
2228 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2229 * It sets errno to ERANGE when the target datatype is too small.
2230 *
2231 * The comma character is treated as a group separator and ignored during parsing.
2232 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2233 *
2234 * @param str the string to convert
2235 * @param output a pointer to the integer variable where the result shall be stored
2236 * @param base 2, 8, 10, or 16
2237 * @retval zero success
2238 * @retval non-zero conversion was not possible
2239 */
2240 #define cx_strtou16(str, output, base) cx_strtou16_lc_(cx_strcast(str), output, base, ",")
2241
2242 /**
2243 * Converts a string to a number.
2244 *
2245 * The function returns non-zero when conversion is not possible.
2246 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2247 * It sets errno to ERANGE when the target datatype is too small.
2248 *
2249 * The comma character is treated as a group separator and ignored during parsing.
2250 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2251 *
2252 * @param str the string to convert
2253 * @param output a pointer to the integer variable where the result shall be stored
2254 * @param base 2, 8, 10, or 16
2255 * @retval zero success
2256 * @retval non-zero conversion was not possible
2257 */
2258 #define cx_strtou32(str, output, base) cx_strtou32_lc_(cx_strcast(str), output, base, ",")
2259
2260 /**
2261 * Converts a string to a number.
2262 *
2263 * The function returns non-zero when conversion is not possible.
2264 * In that case the function sets errno to EINVAL when the reason is an invalid character or an unsupported base.
2265 * It sets errno to ERANGE when the target datatype is too small.
2266 *
2267 * The comma character is treated as a group separator and ignored during parsing.
2268 * If you want to choose the set of group separators, use the @c _lc variant of this function (e.g. cx_strtoz_lc()).
2269 *
2270 * @param str the string to convert
2271 * @param output a pointer to the integer variable where the result shall be stored
2272 * @param base 2, 8, 10, or 16
2273 * @retval zero success
2274 * @retval non-zero conversion was not possible
2275 */
2276 #define cx_strtou64(str, output, base) cx_strtou64_lc_(cx_strcast(str), output, base, ",")
2277
2278 /**
2279 * Converts a string to a single precision floating-point number.
2280 *
2281 * The function returns non-zero when conversion is not possible.
2282 * In that case the function sets errno to EINVAL when the reason is an invalid character.
2283 * It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h.
2284 *
2285 * @param str the string to convert
2286 * @param output a pointer to the float variable where the result shall be stored
2287 * @param decsep the decimal separator
2288 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
2289 * @retval zero success
2290 * @retval non-zero conversion was not possible
2291 */
2292 #define cx_strtof_lc(str, output, decsep, groupsep) cx_strtof_lc_(cx_strcast(str), output, decsep, groupsep)
2293
2294 /**
2295 * Converts a string to a double precision floating-point number.
2296 *
2297 * The function returns non-zero when conversion is not possible.
2298 * In that case the function sets errno to EINVAL when the reason is an invalid character.
2299 *
2300 * @param str the string to convert
2301 * @param output a pointer to the double variable where the result shall be stored
2302 * @param decsep the decimal separator
2303 * @param groupsep each character in this string is treated as a group separator and ignored during conversion
2304 * @retval zero success
2305 * @retval non-zero conversion was not possible
2306 */
2307 #define cx_strtod_lc(str, output, decsep, groupsep) cx_strtod_lc_(cx_strcast(str), output, decsep, groupsep)
2308
2309 /**
2310 * Converts a string to a single precision floating-point number.
2311 *
2312 * The function returns non-zero when conversion is not possible.
2313 * In that case the function sets errno to EINVAL when the reason is an invalid character.
2314 * It sets errno to ERANGE when the necessary representation would exceed the limits defined in libc's float.h.
2315 *
2316 * The decimal separator is assumed to be a dot character.
2317 * The comma character is treated as a group separator and ignored during parsing.
2318 * If you want to choose a different format, use cx_strtof_lc().
2319 *
2320 * @param str the string to convert
2321 * @param output a pointer to the float variable where the result shall be stored
2322 * @retval zero success
2323 * @retval non-zero conversion was not possible
2324 */
2325 #define cx_strtof(str, output) cx_strtof_lc_(cx_strcast(str), output, '.', ",")
2326
2327 /**
2328 * Converts a string to a double precision floating-point number.
2329 *
2330 * The function returns non-zero when conversion is not possible.
2331 * In that case the function sets errno to EINVAL when the reason is an invalid character.
2332 *
2333 * The decimal separator is assumed to be a dot character.
2334 * The comma character is treated as a group separator and ignored during parsing.
2335 * If you want to choose a different format, use cx_strtof_lc().
2336 *
2337 * @param str the string to convert
2338 * @param output a pointer to the double variable where the result shall be stored
2339 * @retval zero success
2340 * @retval non-zero conversion was not possible
2341 */
2342 #define cx_strtod(str, output) cx_strtod_lc_(cx_strcast(str), output, '.', ",")
2343
2344 #endif //UCX_STRING_H
2345