19 # include "stb_sprintf.h"
20 # define CT_SPRINTF stbsp_snprintf
21 # define CT_SNPRINTF stbsp_snprintf
22 # define CT_VSNPRINTF stbsp_vsnprintf
26 # define CT_SPRINTF snprintf
27 # define CT_SNPRINTF snprintf
28 # define CT_VSNPRINTF vsnprintf
50 CTASSERTF(len < INT_MAX,
"len = %zu", len);
68 CTASSERTF(len > 0,
"text_vformat failed to format string: %s",
fmt);
70 char *out =
ARENA_MALLOC(len + 1,
"text_vformat", NULL, arena);
73 CTASSERTF(result == len,
"text_vformat failed to format string: %s expected (%zu == %zu)",
fmt, result, len);
125 for (; *chars; chars++)
249 if (lensuffix > lenstr)
254 return ctu_strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
270 return ctu_strncmp(str + len - lensuffix, suffix, lensuffix) == 0;
296 for (
size_t i = 0; i < all; i++)
299 CTASSERTF(part != NULL,
"part[%zu] = NULL", i);
309 CTASSERTF(len > 0,
"joined string would be empty, how did we get this far?");
311 char *out =
ARENA_MALLOC(len + 1,
"str_join", parts, arena);
314 size_t remaining = len;
315 for (
size_t i = 0; i < all; i++)
328 remaining -= part_len;
347 size_t outlen = len * times;
348 char *out =
ARENA_MALLOC(outlen + 1,
"str_repeat", str, arena);
349 size_t remaining = outlen;
350 for (
size_t i = 0; i < times; i++)
359 static const char kEscapeChars[] = {
360 '\n',
'\t',
'\f',
'\r',
'\v',
'\\',
'\0',
'\'',
'\"',
363 static bool is_escape_char(
char c)
365 for (
size_t i = 0; i <
sizeof(kEscapeChars); i++)
367 if (kEscapeChars[i] == c)
376 static bool ctu_isprint(
char c)
378 if (is_escape_char(c))
383 if (c > 0x1F && c != 0x7F)
391 static size_t normlen(
char c)
394 return ctu_isprint(c) ? 1 : 4;
397 static size_t normstr(
char *out,
char c)
436 int result =
CT_SNPRINTF(out, 5,
"\\x%02x", (c & 0xFF));
449 if (dstlen == 0)
CTASSERT(dst == NULL);
450 if (dst == NULL)
CTASSERT(dstlen == 0);
454 size_t outlength = 0;
455 for (
size_t i = 0; i < srclen; i++)
456 outlength += normlen(src[i]);
462 size_t avail =
CT_MIN(outlength, dstlen);
465 if (outlength == srclen)
472 const char *end = dst + avail;
473 while (*src !=
'\0' && result < end)
475 size_t inc = normstr(result, *src++);
481 return (result - dst) - 1;
490 size_t input_length = 0;
491 size_t result_length = 0;
496 const char *iter = str;
497 while (*iter !=
'\0')
499 size_t inc = normlen(*iter++);
500 result_length += inc;
506 if (input_length == result_length)
511 const char *iter = str;
512 char *buf =
ARENA_MALLOC(result_length + 1,
"str_normalize", str, arena);
514 while (*iter !=
'\0')
516 result += normstr(result, *iter++);
529 const char *str = text.text;
533 for (
size_t i = 0; i < len; i++)
535 length += normlen(str[i]);
544 char *buf =
ARENA_MALLOC(length + 1,
"str_normalizen", str, arena);
546 for (
size_t i = 0; i < len; i++)
548 size_t inc = normstr(buf + offset, str[i]);
585 const char *token = str;
586 const char *cursor = str;
597 token = cursor + seplen;
628 return str_join(repl, split, arena);
661 char *str = text->text;
662 size_t len = text->
length;
668 const char *found =
ctu_strstr(str + offset, search);
674 size_t found_offset = (size_t)(found - str);
678 ctu_memmove(str + offset + repl_len, found + search_len, found_len - search_len);
684 len -= search_len - repl_len;
687 offset = found_offset + repl_len;
703 size_t len = text->
length;
704 char *str = text->text;
721 for (
size_t i = 0; i < len; i++)
723 for (
size_t j = i + 1; j < len; j++)
745 const char *iter = str;
748 const map_entry_t *entry = find_matching_key(pairs, iter);
761 char *out =
ARENA_MALLOC(len + 1,
"str_replace_many", repl, arena);
764 for (
size_t i = 0; i < len;)
766 const map_entry_t *entry = find_matching_key(pairs, str + offset);
775 out[i++] = str[offset++];
798 const char *result =
"";
808 size_t size = len *
sizeof(
char *);
811 size_t lower = SIZE_MAX;
815 for (
size_t i = 0; i < len; i++)
818 CTASSERTF(arg != NULL,
"args[%zu] = NULL", i);
825 lower =
CT_MIN(lower, find);
829 if (lower == 0 || lower == SIZE_MAX)
834 for (
size_t i = 0; i < lower; i++)
836 for (
size_t j = 1; j < len; j++)
838 if (strings[j][i] != strings[0][i])
851 for (
size_t i = 0; i < len; i++)
853 CTASSERTF(strings[i] != NULL,
"strings[%zu] = NULL", i);
863 static size_t str_rfind_inner(
const char *str,
size_t len,
const char *sub,
size_t sublen)
868 if (len == 0) {
return SIZE_MAX; }
870 CTASSERTM(sublen > 0,
"sub must be non-empty");
892 return str_rfind_inner(str, len, sub, sublen);
902 return ptr == NULL ? SIZE_MAX : (size_t)(ptr - str);
906 char *
str_erase(
char *str,
size_t len,
const char *letters)
916 size_t remaining = len;
918 while (remaining > 0)
926 str[--offset] = str[--remaining];
972 if (c >=
'A' && c <=
'Z')
974 return (
char)((c +
'a' -
'A') & CHAR_MAX);
983 if (c >=
'a' && c <=
'z')
985 return (
char)((c +
'A' -
'a') & CHAR_MAX);
#define STA_DECL
sal2 annotation on function implementations to copy annotations from the declaration
#define IN_STRING
annotate a parameter as being a null terminated string
#define CT_NOALIAS
mark a function as only modifying pointers passed to it the same as CT_CONSTFN but allowed to modify/...
CT_NODISCARD CT_PUREFN CT_BASE_API int ctu_strncmp(const char *lhs, const char *rhs, size_t length)
compare two strings equivalent to strncmp but with safety checks
CT_CONSTFN CT_BASE_API text_t text_make(STA_READS(length) char *text, size_t length)
create a new owning text array text must be a valid string at least length bytes long
CT_BASE_API void * ctu_memmove(STA_WRITES(size) void *dst, STA_READS(size) const void *src, size_t size)
move memory from one location to another equivalent to memmove but with safety checks
CT_NOALIAS CT_BASE_API void * ctu_memcpy(STA_WRITES(size) void *CT_RESTRICT dst, STA_READS(size) const void *CT_RESTRICT src, size_t size)
copy memory from one location to another equivalent to memcpy but with safety checks
CT_NODISCARD CT_PUREFN CT_BASE_API bool ctu_string_empty(const char *str)
check if a string is empty equivalent to strlen(str) == 0
CT_NODISCARD CT_PUREFN CT_BASE_API size_t ctu_strlen(const char *str)
get the length of a string not including the null terminator equivalent to strlen but with safety che...
CT_NODISCARD CT_PUREFN CT_BASE_API char * ctu_strstr(const char *haystack, const char *needle)
find a substring in a string equivalent to strstr but with safety checks
STA_RET_STRING colour_t idx
#define CT_PATH_SEPERATORS
CT_NODISCARD CT_STD_API typevec_t * map_entries(map_t *map)
collect all key-value pairs in a map into a vector returns a typevec_t<map_entry_t>
#define CT_ALLOC_SIZE_UNKNOWN
unknown allocation size constant when freeing or reallocating memory, this can be used as the size to...
CT_NODISCARD CT_ARENA_API char * arena_strdup(const char *str, arena_t *arena)
allocate a copy of a string from a custom allocator
CT_NODISCARD CT_ARENA_API char * arena_strndup(STA_READS(len) const char *str, size_t len, arena_t *arena)
allocate a copy of a string with a maximum length from a custom allocator
#define ARENA_MALLOC(size, name, parent, arena)
allocate memory from a custom allocator
CT_ARENA_API void arena_free(STA_RELEASE void *ptr, size_t size, arena_t *arena)
release memory from a custom allocator
#define CTASSERT(expr)
assert a condition, prints the condition as a message
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
#define CTASSERTM(expr, msg)
assert a condition with a message
STA_DECL char * str_noext(const char *path, arena_t *arena)
remove the last file extension from a path
STA_DECL size_t str_rfind_any(const char *str, const char *letters)
find the first instance of a set of characters in a string
STA_DECL char * str_replace(const char *str, const char *search, const char *repl, arena_t *arena)
replace all instances of a substring in a string
STA_DECL bool text_view_equal(text_view_t lhs, text_view_t rhs)
check if two strings are equal
STA_DECL bool str_endswith(const char *str, const char *suffix)
check if a string ends with a substring
STA_DECL size_t str_find(const char *str, const char *sub)
find the first instance of a substring in a string
STA_DECL char * str_normalizen(text_view_t text, arena_t *arena)
turn a string with length into a C string literal
STA_DECL text_t text_vformat(arena_t *arena, const char *fmt, va_list args)
format a string
STA_DECL char * str_repeat(const char *str, size_t times, arena_t *arena)
repeat a string
STA_DECL char * str_upper(const char *str, arena_t *arena)
uppercase an ascii string
STA_DECL char * str_filename(const char *path, arena_t *arena)
get the filename from a path
STA_DECL bool char_is_any_of(char c, const char *chars)
check if a character is any of a set of characters
STA_DECL char * str_ext(const char *path, arena_t *arena)
get the last file extension from a path
STA_DECL vector_t * str_split(const char *str, const char *sep, arena_t *arena)
split a string into a vector by a separator
STA_DECL char * str_normalize(const char *str, arena_t *arena)
turn a string into a C string literal
STA_DECL char * str_join(const char *sep, const vector_t *parts, arena_t *arena)
join strings
CT_NODISCARD STA_FORMAT_STRING const char * fmt
STA_DECL char * str_directory(const char *path, arena_t *arena)
get the directory segment of a path
STA_DECL char * str_replace_many(const char *str, const map_t *repl, arena_t *arena)
replace all instances of a each substring in a string with provided replacement
STA_DECL const char * str_common_prefix(const vector_t *args, arena_t *arena)
find the longest common prefix of a vector of paths
STA_DECL size_t str_rfind(const char *str, const char *sub)
find the last instance of a substring in a string
STA_DECL char * str_lower(const char *str, arena_t *arena)
lowercase an ascii string this allocates a new string in the provided arena
STA_DECL bool str_contains(const char *str, const char *search)
check if a string contains a substring
STA_DECL char * str_basename(const char *path, arena_t *arena)
get the filename from a path
STA_DECL char * str_vformat(arena_t *arena, const char *fmt, va_list args)
format a string
STA_DECL char str_tolower(char c)
get the lowercase version of a character
STA_DECL char str_toupper(char c)
get the uppercase version of a character
STA_DECL bool str_startswith(const char *str, const char *prefix)
see if a string starts with a prefix
CT_NODISCARD CT_PUREFN CT_STD_API size_t typevec_len(const typevec_t *vec)
get the length of a vector
CT_NODISCARD CT_PUREFN CT_STD_API void * typevec_offset(const typevec_t *vec, size_t index)
get a pointer to the value at the given index
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
CT_NODISCARD CT_STD_API vector_t * vector_new(size_t size, arena_t *arena)
create a new vector with an initial capacity
CT_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
STA_DECL size_t str_normalize_into(char *dst, size_t dstlen, const char *src, size_t srclen)
STA_DECL void str_sort_inplace(char *str, size_t len)
STA_DECL text_t text_format(arena_t *arena, const char *fmt,...)
STA_DECL void str_trim_back_inplace(text_t *text, const char *chars)
STA_DECL size_t str_sprintf(char *str, size_t len, const char *fmt,...)
STA_DECL size_t str_vsprintf(char *str, size_t len, const char *fmt, va_list args)
STA_DECL bool str_endswithn(const char *str, size_t len, const char *suffix)
STA_DECL CT_NOALIAS char * str_erase(char *str, size_t len, const char *letters)
STA_DECL void str_replace_inplace(text_t *text, const char *search, const char *repl)
STA_DECL char * str_format(arena_t *arena, const char *fmt,...)
a key-value pair in a map
const void * key
the key of this entry
void * value
the value of this entry
size_t length
the number of characters in the text
a non-owning view of text
size_t length
the number of characters in the text
A vector with a fixed type size.
a generic vector of pointers