4coder/4coder_lib/4coder_string.h

2499 lines
63 KiB
C

/*
4coder_string.h - Version 1.0.121
no warranty implied; use at your own risk
This software is in the public domain. Where that dedication is not
recognized, you are granted a perpetual, irrevocable license to copy,
distribute, and modify this file as you see fit.
To include implementation: #define FSTRING_IMPLEMENTATION
To use in C mode: #define FSTRING_C
*/
// TOP
#if !defined(REMOVE_OLD_STRING)
#if !defined(FSTRING_LINK)
# define FSTRING_LINK static
#endif
#if !defined(FSTRING_INLINE)
# define FSTRING_INLINE static
#endif
#if !defined(FSTRING_GUARD)
#define literal(s) (s), (sizeof(s) - 1)
struct CString_Array{
char **strings;
i32 count;
};
typedef struct String{
char *str;
i32 size;
i32 memory_size;
} String;
static String null_string = {};
#endif
#if !defined(FCODER_STRING_H)
#define FCODER_STRING_H
FSTRING_INLINE b32 char_is_slash(char c);
FSTRING_INLINE b32 char_is_upper(char c);
FSTRING_INLINE b32 char_is_upper_utf8(char c);
FSTRING_INLINE b32 char_is_lower(char c);
FSTRING_INLINE b32 char_is_lower_utf8(u8 c);
FSTRING_INLINE char char_to_upper(char c);
FSTRING_INLINE char char_to_lower(char c);
FSTRING_INLINE b32 char_is_whitespace(char c);
FSTRING_INLINE b32 char_is_alpha_numeric(char c);
FSTRING_INLINE b32 char_is_alpha_numeric_utf8(u8 c);
FSTRING_INLINE b32 char_is_alpha_numeric_true(char c);
FSTRING_INLINE b32 char_is_alpha_numeric_true_utf8(u8 c);
FSTRING_INLINE b32 char_is_alpha(char c);
FSTRING_INLINE b32 char_is_alpha_utf8(u8 c);
FSTRING_INLINE b32 char_is_alpha_true(char c);
FSTRING_INLINE b32 char_is_alpha_true_utf8(u8 c);
FSTRING_INLINE b32 char_is_hex(char c);
FSTRING_INLINE b32 char_is_hex_utf8(u8 c);
FSTRING_INLINE b32 char_is_numeric(char c);
FSTRING_INLINE b32 char_is_numeric_utf8(u8 c);
FSTRING_INLINE String make_string_cap(void *str, i32 size, i32 mem_size);
FSTRING_INLINE String make_string(void *str, i32 size);
#ifndef make_lit_string
# define make_lit_string(s) (make_string_cap((char*)(s), sizeof(s)-1, sizeof(s)))
#endif
#ifndef lit
# define lit(s) make_lit_string(s)
#endif
#ifndef make_fixed_width_string
# define make_fixed_width_string(s) (make_string_cap((char*)(s), 0, sizeof(s)))
#endif
#ifndef expand_str
# define expand_str(s) ((s).str), ((s).size)
#endif
FSTRING_LINK i32 str_size(char *str);
FSTRING_INLINE String make_string_slowly(void *str);
FSTRING_INLINE String substr_tail(String str, i32 start);
FSTRING_INLINE String substr(String str, i32 start, i32 size);
FSTRING_LINK String skip_whitespace(String str);
FSTRING_LINK String skip_whitespace_measure(String str, i32 *skip_length);
FSTRING_LINK String chop_whitespace(String str);
FSTRING_LINK String skip_chop_whitespace(String str);
FSTRING_LINK String skip_chop_whitespace_measure(String str, i32 *skip_length);
FSTRING_INLINE String tailstr(String str);
FSTRING_LINK b32 match_cc(char *a, char *b);
FSTRING_LINK b32 match_sc(String a, char *b);
FSTRING_INLINE b32 match_cs(char *a, String b);
FSTRING_LINK b32 match_ss(String a, String b);
FSTRING_LINK b32 match_part_ccl(char *a, char *b, i32 *len);
FSTRING_LINK b32 match_part_scl(String a, char *b, i32 *len);
FSTRING_INLINE b32 match_part_cc(char *a, char *b);
FSTRING_INLINE b32 match_part_sc(String a, char *b);
FSTRING_LINK b32 match_part_cs(char *a, String b);
FSTRING_LINK b32 match_part_ss(String a, String b);
FSTRING_LINK b32 match_insensitive_cc(char *a, char *b);
FSTRING_LINK b32 match_insensitive_sc(String a, char *b);
FSTRING_INLINE b32 match_insensitive_cs(char *a, String b);
FSTRING_LINK b32 match_insensitive_ss(String a, String b);
FSTRING_LINK b32 match_part_insensitive_ccl(char *a, char *b, i32 *len);
FSTRING_LINK b32 match_part_insensitive_scl(String a, char *b, i32 *len);
FSTRING_INLINE b32 match_part_insensitive_cc(char *a, char *b);
FSTRING_INLINE b32 match_part_insensitive_sc(String a, char *b);
FSTRING_LINK b32 match_part_insensitive_cs(char *a, String b);
FSTRING_LINK b32 match_part_insensitive_ss(String a, String b);
FSTRING_LINK i32 compare_cc(char *a, char *b);
FSTRING_LINK i32 compare_sc(String a, char *b);
FSTRING_INLINE i32 compare_cs(char *a, String b);
FSTRING_LINK i32 compare_ss(String a, String b);
FSTRING_LINK i32 find_c_char(char *str, i32 start, char character);
FSTRING_LINK i32 find_s_char(String str, i32 start, char character);
FSTRING_LINK i32 rfind_s_char(String str, i32 start, char character);
FSTRING_LINK i32 find_c_chars(char *str, i32 start, char *characters);
FSTRING_LINK i32 find_s_chars(String str, i32 start, char *characters);
FSTRING_LINK i32 find_substr_c(char *str, i32 start, String seek);
FSTRING_LINK i32 find_substr_s(String str, i32 start, String seek);
FSTRING_LINK i32 rfind_substr_s(String str, i32 start, String seek);
FSTRING_LINK i32 find_substr_insensitive_c(char *str, i32 start, String seek);
FSTRING_LINK i32 find_substr_insensitive_s(String str, i32 start, String seek);
FSTRING_INLINE b32 has_substr_c(char *s, String seek);
FSTRING_INLINE b32 has_substr_s(String s, String seek);
FSTRING_INLINE b32 has_substr_insensitive_c(char *s, String seek);
FSTRING_INLINE b32 has_substr_insensitive_s(String s, String seek);
FSTRING_LINK i32 copy_fast_unsafe_cc(char *dest, char *src);
FSTRING_LINK i32 copy_fast_unsafe_cs(char *dest, String src);
FSTRING_LINK b32 copy_checked_ss(String *dest, String src);
FSTRING_LINK b32 copy_checked_cs(char *dest, i32 dest_cap, String src);
FSTRING_LINK b32 copy_partial_sc(String *dest, char *src);
FSTRING_LINK b32 copy_partial_ss(String *dest, String src);
FSTRING_LINK b32 copy_partial_cs(char *dest, i32 dest_cap, String src);
FSTRING_INLINE i32 copy_cc(char *dest, char *src);
FSTRING_INLINE void copy_ss(String *dest, String src);
FSTRING_INLINE void copy_sc(String *dest, char *src);
FSTRING_LINK b32 append_checked_ss(String *dest, String src);
FSTRING_LINK b32 append_partial_sc(String *dest, char *src);
FSTRING_LINK b32 append_partial_ss(String *dest, String src);
FSTRING_LINK b32 append_s_char(String *dest, char c);
FSTRING_INLINE b32 append_ss(String *dest, String src);
FSTRING_INLINE b32 append_sc(String *dest, char *src);
FSTRING_LINK b32 terminate_with_null(String *str);
FSTRING_LINK b32 append_padding(String *dest, char c, i32 target_size);
FSTRING_LINK void string_interpret_escapes(String src, char *dst);
FSTRING_LINK void replace_char(String *str, char replace, char with);
FSTRING_LINK void replace_str_ss(String *str, String replace, String with);
FSTRING_LINK void replace_str_sc(String *str, String replace, char *with);
FSTRING_LINK void replace_str_cs(String *str, char *replace, String with);
FSTRING_LINK void replace_str_cc(String *str, char *replace, char *with);
FSTRING_LINK void to_lower_cc(char *src, char *dst);
FSTRING_LINK void to_lower_ss(String *dst, String src);
FSTRING_LINK void to_lower_s(String *str);
FSTRING_LINK void to_upper_cc(char *src, char *dst);
FSTRING_LINK void to_upper_ss(String *dst, String src);
FSTRING_LINK void to_upper_s(String *str);
FSTRING_LINK void to_camel_cc(char *src, char *dst);
FSTRING_LINK i32 int_to_str_size(i32 x);
FSTRING_LINK b32 int_to_str(String *dest, i32 x);
FSTRING_LINK b32 append_int_to_str(String *dest, i32 x);
FSTRING_LINK i32 u64_to_str_size(uint64_t x);
FSTRING_LINK b32 u64_to_str(String *dest, uint64_t x);
FSTRING_LINK b32 append_u64_to_str(String *dest, uint64_t x);
FSTRING_LINK i32 float_to_str_size(float x);
FSTRING_LINK b32 append_float_to_str(String *dest, float x);
FSTRING_LINK b32 float_to_str(String *dest, float x);
FSTRING_LINK i32 str_is_int_c(char *str);
FSTRING_LINK b32 str_is_int_s(String str);
FSTRING_LINK i32 str_to_int_c(char *str);
FSTRING_LINK i32 str_to_int_s(String str);
FSTRING_LINK i32 hexchar_to_int(char c);
FSTRING_LINK char int_to_hexchar(i32 x);
FSTRING_LINK u32 hexstr_to_int(String str);
FSTRING_LINK b32 color_to_hexstr(String *s, u32 color);
FSTRING_LINK b32 hexstr_to_color(String s, u32 *out);
FSTRING_LINK i32 reverse_seek_slash_pos(String str, i32 pos);
FSTRING_INLINE i32 reverse_seek_slash(String str);
FSTRING_INLINE String front_of_directory(String dir);
FSTRING_INLINE String path_of_directory(String dir);
FSTRING_LINK b32 set_last_folder_sc(String *dir, char *folder_name, char slash);
FSTRING_LINK b32 set_last_folder_ss(String *dir, String folder_name, char slash);
FSTRING_LINK String file_extension(String str);
FSTRING_LINK b32 remove_extension(String *str);
FSTRING_LINK b32 remove_last_folder(String *str);
FSTRING_LINK b32 string_set_match_table(void *str_set, i32 item_size, i32 count, String str, i32 *match_index);
FSTRING_LINK b32 string_set_match(String *str_set, i32 count, String str, i32 *match_index);
FSTRING_LINK String get_first_double_line(String source);
FSTRING_LINK String get_next_double_line(String source, String line);
FSTRING_LINK String get_next_word(String source, String prev_word);
FSTRING_LINK String get_first_word(String source);
FSTRING_LINK String string_push(Cursor *cursor, i32 size);
FSTRING_LINK String string_push_copy(Cursor *cursor, String str);
FSTRING_LINK String string_push(Arena *arena, i32 size);
FSTRING_LINK String string_push_copy(Arena *arena, String str);
FSTRING_LINK char* get_null_terminated(Arena *arena, String str);
#endif
#if !defined(FSTRING_C) && !defined(FSTRING_GUARD)
FSTRING_INLINE String make_string(void *str, i32 size, i32 mem_size){return(make_string_cap(str,size,mem_size));}
FSTRING_INLINE String substr(String str, i32 start){return(substr_tail(str,start));}
FSTRING_LINK String skip_whitespace(String str, i32 *skip_length){return(skip_whitespace_measure(str,skip_length));}
FSTRING_LINK String skip_chop_whitespace(String str, i32 *skip_length){return(skip_chop_whitespace_measure(str,skip_length));}
FSTRING_LINK b32 match(char *a, char *b){return(match_cc(a,b));}
FSTRING_LINK b32 match(String a, char *b){return(match_sc(a,b));}
FSTRING_INLINE b32 match(char *a, String b){return(match_cs(a,b));}
FSTRING_LINK b32 match(String a, String b){return(match_ss(a,b));}
FSTRING_LINK b32 match_part(char *a, char *b, i32 *len){return(match_part_ccl(a,b,len));}
FSTRING_LINK b32 match_part(String a, char *b, i32 *len){return(match_part_scl(a,b,len));}
FSTRING_INLINE b32 match_part(char *a, char *b){return(match_part_cc(a,b));}
FSTRING_INLINE b32 match_part(String a, char *b){return(match_part_sc(a,b));}
FSTRING_LINK b32 match_part(char *a, String b){return(match_part_cs(a,b));}
FSTRING_LINK b32 match_part(String a, String b){return(match_part_ss(a,b));}
FSTRING_LINK b32 match_insensitive(char *a, char *b){return(match_insensitive_cc(a,b));}
FSTRING_LINK b32 match_insensitive(String a, char *b){return(match_insensitive_sc(a,b));}
FSTRING_INLINE b32 match_insensitive(char *a, String b){return(match_insensitive_cs(a,b));}
FSTRING_LINK b32 match_insensitive(String a, String b){return(match_insensitive_ss(a,b));}
FSTRING_LINK b32 match_part_insensitive(char *a, char *b, i32 *len){return(match_part_insensitive_ccl(a,b,len));}
FSTRING_LINK b32 match_part_insensitive(String a, char *b, i32 *len){return(match_part_insensitive_scl(a,b,len));}
FSTRING_INLINE b32 match_part_insensitive(char *a, char *b){return(match_part_insensitive_cc(a,b));}
FSTRING_INLINE b32 match_part_insensitive(String a, char *b){return(match_part_insensitive_sc(a,b));}
FSTRING_LINK b32 match_part_insensitive(char *a, String b){return(match_part_insensitive_cs(a,b));}
FSTRING_LINK b32 match_part_insensitive(String a, String b){return(match_part_insensitive_ss(a,b));}
FSTRING_LINK i32 compare(char *a, char *b){return(compare_cc(a,b));}
FSTRING_LINK i32 compare(String a, char *b){return(compare_sc(a,b));}
FSTRING_INLINE i32 compare(char *a, String b){return(compare_cs(a,b));}
FSTRING_LINK i32 compare(String a, String b){return(compare_ss(a,b));}
FSTRING_LINK i32 find(char *str, i32 start, char character){return(find_c_char(str,start,character));}
FSTRING_LINK i32 find(String str, i32 start, char character){return(find_s_char(str,start,character));}
FSTRING_LINK i32 rfind(String str, i32 start, char character){return(rfind_s_char(str,start,character));}
FSTRING_LINK i32 find(char *str, i32 start, char *characters){return(find_c_chars(str,start,characters));}
FSTRING_LINK i32 find(String str, i32 start, char *characters){return(find_s_chars(str,start,characters));}
FSTRING_LINK i32 find_substr(char *str, i32 start, String seek){return(find_substr_c(str,start,seek));}
FSTRING_LINK i32 find_substr(String str, i32 start, String seek){return(find_substr_s(str,start,seek));}
FSTRING_LINK i32 rfind_substr(String str, i32 start, String seek){return(rfind_substr_s(str,start,seek));}
FSTRING_LINK i32 find_substr_insensitive(char *str, i32 start, String seek){return(find_substr_insensitive_c(str,start,seek));}
FSTRING_LINK i32 find_substr_insensitive(String str, i32 start, String seek){return(find_substr_insensitive_s(str,start,seek));}
FSTRING_INLINE b32 has_substr(char *s, String seek){return(has_substr_c(s,seek));}
FSTRING_INLINE b32 has_substr(String s, String seek){return(has_substr_s(s,seek));}
FSTRING_INLINE b32 has_substr_insensitive(char *s, String seek){return(has_substr_insensitive_c(s,seek));}
FSTRING_INLINE b32 has_substr_insensitive(String s, String seek){return(has_substr_insensitive_s(s,seek));}
FSTRING_LINK i32 copy_fast_unsafe(char *dest, char *src){return(copy_fast_unsafe_cc(dest,src));}
FSTRING_LINK i32 copy_fast_unsafe(char *dest, String src){return(copy_fast_unsafe_cs(dest,src));}
FSTRING_LINK b32 copy_checked(String *dest, String src){return(copy_checked_ss(dest,src));}
FSTRING_LINK b32 copy_checked(char *dest, i32 dest_cap, String src){return(copy_checked_cs(dest,dest_cap,src));}
FSTRING_LINK b32 copy_partial(String *dest, char *src){return(copy_partial_sc(dest,src));}
FSTRING_LINK b32 copy_partial(String *dest, String src){return(copy_partial_ss(dest,src));}
FSTRING_LINK b32 copy_partial(char *dest, i32 dest_cap, String src){return(copy_partial_cs(dest,dest_cap,src));}
FSTRING_INLINE i32 copy(char *dest, char *src){return(copy_cc(dest,src));}
FSTRING_INLINE void copy(String *dest, String src){return(copy_ss(dest,src));}
FSTRING_INLINE void copy(String *dest, char *src){return(copy_sc(dest,src));}
FSTRING_LINK b32 append_checked(String *dest, String src){return(append_checked_ss(dest,src));}
FSTRING_LINK b32 append_partial(String *dest, char *src){return(append_partial_sc(dest,src));}
FSTRING_LINK b32 append_partial(String *dest, String src){return(append_partial_ss(dest,src));}
FSTRING_LINK b32 append(String *dest, char c){return(append_s_char(dest,c));}
FSTRING_INLINE b32 append(String *dest, String src){return(append_ss(dest,src));}
FSTRING_INLINE b32 append(String *dest, char *src){return(append_sc(dest,src));}
FSTRING_LINK void replace_str(String *str, String replace, String with){return(replace_str_ss(str,replace,with));}
FSTRING_LINK void replace_str(String *str, String replace, char *with){return(replace_str_sc(str,replace,with));}
FSTRING_LINK void replace_str(String *str, char *replace, String with){return(replace_str_cs(str,replace,with));}
FSTRING_LINK void replace_str(String *str, char *replace, char *with){return(replace_str_cc(str,replace,with));}
FSTRING_LINK void to_lower(char *src, char *dst){return(to_lower_cc(src,dst));}
FSTRING_LINK void to_lower(String *dst, String src){return(to_lower_ss(dst,src));}
FSTRING_LINK void to_lower(String *str){return(to_lower_s(str));}
FSTRING_LINK void to_upper(char *src, char *dst){return(to_upper_cc(src,dst));}
FSTRING_LINK void to_upper(String *dst, String src){return(to_upper_ss(dst,src));}
FSTRING_LINK void to_upper(String *str){return(to_upper_s(str));}
FSTRING_LINK void to_camel(char *src, char *dst){return(to_camel_cc(src,dst));}
FSTRING_LINK i32 str_is_int(char *str){return(str_is_int_c(str));}
FSTRING_LINK b32 str_is_int(String str){return(str_is_int_s(str));}
FSTRING_LINK i32 str_to_int(char *str){return(str_to_int_c(str));}
FSTRING_LINK i32 str_to_int(String str){return(str_to_int_s(str));}
FSTRING_LINK i32 reverse_seek_slash(String str, i32 pos){return(reverse_seek_slash_pos(str,pos));}
FSTRING_LINK b32 set_last_folder(String *dir, char *folder_name, char slash){return(set_last_folder_sc(dir,folder_name,slash));}
FSTRING_LINK b32 set_last_folder(String *dir, String folder_name, char slash){return(set_last_folder_ss(dir,folder_name,slash));}
FSTRING_LINK b32 string_set_match(void *str_set, i32 item_size, i32 count, String str, i32 *match_index){return(string_set_match_table(str_set,item_size,count,str,match_index));}
#endif
//
// Character Helpers
//
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_slash(char c)
{
return (c == '\\' || c == '/');
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_upper(char c)
{
return (c >= 'A' && c <= 'Z');
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_upper_utf8(char c)
{
return ((c >= 'A' && c <= 'Z') || (unsigned char)c >= 128);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_lower(char c)
{
return (c >= 'a' && c <= 'z');
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_lower_utf8(u8 c)
{
return ((c >= 'a' && c <= 'z') || (unsigned char)c >= 128);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE char
char_to_upper(char c)
{
return (c >= 'a' && c <= 'z') ? c + (char)('A' - 'a') : c;
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE char
char_to_lower(char c)
{
return (c >= 'A' && c <= 'Z') ? c - (char)('A' - 'a') : c;
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_whitespace(char c)
{
return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_alpha_numeric(char c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_');
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_alpha_numeric_utf8(u8 c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || (unsigned char)c >= 128);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_alpha_numeric_true(char c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'));
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_alpha_numeric_true_utf8(u8 c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (unsigned char)c >= 128);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_alpha(char c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_alpha_utf8(u8 c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (unsigned char)c >= 128);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_alpha_true(char c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_alpha_true_utf8(u8 c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (unsigned char)c >= 128);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_hex(char c)
{
return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'));
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_hex_utf8(u8 c)
{
return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f') || (unsigned char)c >= 128);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_numeric(char c)
{
return (c >= '0' && c <= '9');
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
char_is_numeric_utf8(u8 c)
{
return ((c >= '0' && c <= '9') || (unsigned char)c >= 128);
}
#endif
//
// String Making Functions
//
#if !defined(FSTRING_GUARD)
FSTRING_INLINE String
make_string_cap(void *str, i32 size, i32 mem_size){
String result;
result.str = (char*)str;
result.size = size;
result.memory_size = mem_size;
return(result);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE String
make_string(void *str, i32 size){
return(make_string(str, size, size));
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
str_size(char *str)
{
i32 i = 0;
if (str != 0){
for (;str[i];++i);
}
return(i);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE String
make_string_slowly(void *str)
{
String result;
result.str = (char*)str;
result.size = str_size((char*)str);
result.memory_size = result.size + 1;
return(result);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE String
substr_tail(String str, i32 start)
{
String result;
result.str = str.str + start;
result.size = str.size - start;
result.memory_size = 0;
return(result);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE String
substr(String str, i32 start, i32 size)
{
String result;
result.str = str.str + start;
result.size = size;
if (start + size > str.size){
result.size = str.size - start;
}
result.memory_size = 0;
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
skip_whitespace(String str)
{
String result = {};
i32 i = 0;
for (; i < str.size && char_is_whitespace(str.str[i]); ++i);
result = substr(str, i, str.size - i);
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
skip_whitespace_measure(String str, i32 *skip_length)
{
String result = {};
i32 i = 0;
for (; i < str.size && char_is_whitespace(str.str[i]); ++i);
result = substr(str, i, str.size - i);
*skip_length = i;
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
chop_whitespace(String str)
{
String result = {};
i32 i = str.size;
for (; i > 0 && char_is_whitespace(str.str[i-1]); --i);
result = substr(str, 0, i);
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
skip_chop_whitespace(String str)
{
str = skip_whitespace(str);
str = chop_whitespace(str);
return(str);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
skip_chop_whitespace_measure(String str, i32 *skip_length)
{
str = skip_whitespace_measure(str, skip_length);
str = chop_whitespace(str);
return(str);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE String
tailstr(String str)
{
String result;
result.str = str.str + str.size;
result.memory_size = str.memory_size - str.size;
result.size = 0;
return(result);
}
#endif
//
// String Comparison
//
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_cc(char *a, char *b){
for (i32 i = 0;; ++i){
if (a[i] != b[i]){
return 0;
}
if (a[i] == 0){
return 1;
}
}
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_sc(String a, char *b){
i32 i = 0;
for (; i < a.size; ++i){
if (a.str[i] != b[i]){
return 0;
}
}
if (b[i] != 0){
return 0;
}
return 1;
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
match_cs(char *a, String b){
return(match_sc(b,a));
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_ss(String a, String b){
if (a.size != b.size){
return 0;
}
for (i32 i = 0; i < b.size; ++i){
if (a.str[i] != b.str[i]){
return 0;
}
}
return 1;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_part_ccl(char *a, char *b, i32 *len){
if (a == 0){
a = "";
}
if (b == 0){
b = "";
}
i32 i;
for (i = 0; b[i] != 0; ++i){
if (a[i] != b[i]){
return(0);
}
}
*len = i;
return(1);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_part_scl(String a, char *b, i32 *len){
if (b == 0){
b = "";
}
i32 i;
for (i = 0; b[i] != 0; ++i){
if (i == a.size || a.str[i] != b[i]){
return(0);
}
}
*len = i;
return(1);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
match_part_cc(char *a, char *b){
i32 x;
return match_part_ccl(a,b,&x);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
match_part_sc(String a, char *b){
i32 x;
return match_part_scl(a,b,&x);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_part_cs(char *a, String b){
for (i32 i = 0; i != b.size; ++i){
if (a[i] != b.str[i]){
return 0;
}
}
return 1;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_part_ss(String a, String b){
if (a.size < b.size){
return(0);
}
for (i32 i = 0; i < b.size; ++i){
if (a.str[i] != b.str[i]){
return(0);
}
}
return(1);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_insensitive_cc(char *a, char *b){
for (i32 i = 0;; ++i){
if (char_to_upper(a[i]) !=
char_to_upper(b[i])){
return 0;
}
if (a[i] == 0){
return 1;
}
}
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_insensitive_sc(String a, char *b){
i32 i = 0;
for (; i < a.size; ++i){
if (char_to_upper(a.str[i]) !=
char_to_upper(b[i])){
return 0;
}
}
if (b[i] != 0){
return 0;
}
return 1;
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
match_insensitive_cs(char *a, String b){
return match_insensitive_sc(b,a);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_insensitive_ss(String a, String b){
if (a.size != b.size){
return 0;
}
for (i32 i = 0; i < b.size; ++i){
if (char_to_upper(a.str[i]) !=
char_to_upper(b.str[i])){
return 0;
}
}
return 1;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_part_insensitive_ccl(char *a, char *b, i32 *len){
i32 i;
for (i = 0; b[i] != 0; ++i){
if (char_to_upper(a[i]) != char_to_upper(b[i])){
return 0;
}
}
*len = i;
return 1;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_part_insensitive_scl(String a, char *b, i32 *len){
i32 i;
for (i = 0; b[i] != 0; ++i){
if (char_to_upper(a.str[i]) != char_to_upper(b[i]) ||
i == a.size){
return 0;
}
}
*len = i;
return 1;
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
match_part_insensitive_cc(char *a, char *b){
i32 x;
return match_part_insensitive_ccl(a,b,&x);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
match_part_insensitive_sc(String a, char *b){
i32 x;
return match_part_insensitive_scl(a,b,&x);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_part_insensitive_cs(char *a, String b){
for (i32 i = 0; i != b.size; ++i){
if (char_to_upper(a[i]) != char_to_upper(b.str[i])){
return(0);
}
}
return(1);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
match_part_insensitive_ss(String a, String b){
if (a.size < b.size){
return(0);
}
for (i32 i = 0; i < b.size; ++i){
if (char_to_upper(a.str[i]) != char_to_upper(b.str[i])){
return(0);
}
}
return(1);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
compare_cc(char *a, char *b){
i32 i = 0, r = 0;
while (a[i] == b[i] && a[i] != 0){
++i;
}
r = (a[i] > b[i]) - (a[i] < b[i]);
return(r);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
compare_sc(String a, char *b){
i32 i = 0, r = 0;
while (i < a.size && a.str[i] == b[i]){
++i;
}
if (i < a.size){
r = (a.str[i] > b[i]) - (a.str[i] < b[i]);
}
else{
if (b[i] == 0){
r = 0;
}
else{
r = -1;
}
}
return(r);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE i32
compare_cs(char *a, String b){
i32 r = -compare_sc(b,a);
return(r);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
compare_ss(String a, String b){
i32 i = 0, r = 0;
i32 m = a.size;
if (b.size < m){
m = b.size;
}
while (i < m && a.str[i] == b.str[i]){
++i;
}
if (i < m){
r = (a.str[i] > b.str[i]) - (b.str[i] > a.str[i]);
}
else{
r = (a.size > b.size) - (b.size > a.size);
}
return(r);
}
#endif
//
// Finding Characters and Substrings
//
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
find_c_char(char *str, i32 start, char character){
i32 i = start;
while (str[i] != character && str[i] != 0) ++i;
return(i);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
find_s_char(String str, i32 start, char character){
i32 i = start;
while (i < str.size && str.str[i] != character) ++i;
return(i);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
rfind_s_char(String str, i32 start, char character){
i32 i = start;
while (i >= 0 && str.str[i] != character) --i;
return(i);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
find_c_chars(char *str, i32 start, char *characters){
i32 i = start, j;
while (str[i] != 0){
for (j = 0; characters[j]; ++j){
if (str[i] == characters[j]){
return(i);
}
}
++i;
}
return(i);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
find_s_chars(String str, i32 start, char *characters){
i32 i = start, j;
while (i < str.size){
for (j = 0; characters[j]; ++j){
if (str.str[i] == characters[j]){
return(i);
}
}
++i;
}
return(i);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
find_substr_c(char *str, i32 start, String seek){
i32 i, j, k;
b32 hit;
if (seek.size == 0){
i = str_size(str);
return(i);
}
for (i = start; str[i]; ++i){
if (str[i] == seek.str[0]){
hit = 1;
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
if (str[k] != seek.str[j]){
hit = 0;
break;
}
}
if (hit){
return(i);
}
}
}
return(i);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
find_substr_s(String str, i32 start, String seek){
i32 stop_at, i, j, k;
b32 hit;
if (seek.size == 0){
return str.size;
}
stop_at = str.size - seek.size + 1;
for (i = start; i < stop_at; ++i){
if (str.str[i] == seek.str[0]){
hit = 1;
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
if (str.str[k] != seek.str[j]){
hit = 0;
break;
}
}
if (hit){
return i;
}
}
}
return(str.size);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
rfind_substr_s(String str, i32 start, String seek){
i32 i, j, k;
b32 hit;
if (seek.size == 0){
return -1;
}
if (start + seek.size > str.size){
start = str.size - seek.size;
}
for (i = start; i >= 0; --i){
if (str.str[i] == seek.str[0]){
hit = 1;
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
if (str.str[k] != seek.str[j]){
hit = 0;
break;
}
}
if (hit){
return i;
}
}
}
return -1;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
find_substr_insensitive_c(char *str, i32 start, String seek){
i32 i, j, k;
b32 hit;
char a_upper, b_upper;
char first_test_char;
if (seek.size == 0){
return str_size(str);
}
first_test_char = char_to_upper(seek.str[0]);
for (i = start; str[i]; ++i){
a_upper = char_to_upper(str[i]);
if (a_upper == first_test_char){
hit = 1;
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
a_upper = char_to_upper(str[k]);
b_upper = char_to_upper(seek.str[j]);
if (a_upper != b_upper){
hit = 0;
break;
}
}
if (hit){
return i;
}
}
}
return i;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
find_substr_insensitive_s(String str, i32 start, String seek){
i32 i, j, k;
i32 stop_at;
b32 hit;
char a_upper, b_upper;
char first_test_char;
if (seek.size == 0){
return str.size;
}
stop_at = str.size - seek.size + 1;
first_test_char = char_to_upper(seek.str[0]);
for (i = start; i < stop_at; ++i){
a_upper = char_to_upper(str.str[i]);
if (a_upper == first_test_char){
hit = 1;
for (j = 1, k = i+1; j < seek.size; ++j, ++k){
a_upper = char_to_upper(str.str[k]);
b_upper = char_to_upper(seek.str[j]);
if (a_upper != b_upper){
hit = 0;
break;
}
}
if (hit){
return i;
}
}
}
return str.size;
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
has_substr_c(char *s, String seek){
return (s[find_substr_c(s, 0, seek)] != 0);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
has_substr_s(String s, String seek){
return (find_substr_s(s, 0, seek) < s.size);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
has_substr_insensitive_c(char *s, String seek){
return (s[find_substr_insensitive_c(s, 0, seek)] != 0);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
has_substr_insensitive_s(String s, String seek){
return (find_substr_insensitive_s(s, 0, seek) < s.size);
}
#endif
//
// String Copies and Appends
//
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
copy_fast_unsafe_cc(char *dest, char *src){
char *start = dest;
while (*src != 0){
*dest = *src;
++dest;
++src;
}
return (i32)(dest - start);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
copy_fast_unsafe_cs(char *dest, String src){
i32 i = 0;
while (i != src.size){
dest[i] = src.str[i];
++i;
}
return(src.size);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
copy_checked_ss(String *dest, String src){
char *dest_str;
i32 i;
if (dest->memory_size < src.size){
return 0;
}
dest_str = dest->str;
for (i = 0; i < src.size; ++i){
dest_str[i] = src.str[i];
}
dest->size = src.size;
return 1;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
copy_checked_cs(char *dest, i32 dest_cap, String src){
i32 i;
if (dest_cap < src.size){
return 0;
}
for (i = 0; i < src.size; ++i){
dest[i] = src.str[i];
}
return 1;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
copy_partial_sc(String *dest, char *src){
i32 i = 0;
i32 memory_size = dest->memory_size;
char *dest_str = dest->str;
while (src[i] != 0){
if (i >= memory_size){
return 0;
}
dest_str[i] = src[i];
++i;
}
dest->size = i;
return 1;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
copy_partial_ss(String *dest, String src){
char *dest_str = dest->str;
i32 memory_size = dest->memory_size;
b32 result = 0;
if (memory_size >= src.size){
result = 1;
memory_size = src.size;
}
for (i32 i = 0; i < memory_size; ++i){
dest_str[i] = src.str[i];
}
dest->size = memory_size;
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
copy_partial_cs(char *dest, i32 dest_cap, String src){
b32 result = 0;
i32 copy_size = dest_cap;
i32 i;
if (dest_cap >= src.size){
result = 1;
copy_size = src.size;
}
for (i = 0; i < copy_size; ++i){
dest[i] = src.str[i];
}
return(result);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE i32
copy_cc(char *dest, char *src){
return copy_fast_unsafe_cc(dest, src);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE void
copy_ss(String *dest, String src){
copy_checked_ss(dest, src);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE void
copy_sc(String *dest, char *src){
copy_partial_sc(dest, src);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
append_checked_ss(String *dest, String src){
String end;
end = tailstr(*dest);
b32 result = copy_checked_ss(&end, src);
// NOTE(allen): This depends on end.size still being 0 if
// the check failed and no coppy occurred.
dest->size += end.size;
return result;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
append_partial_sc(String *dest, char *src){
String end = tailstr(*dest);
b32 result = copy_partial_sc(&end, src);
dest->size += end.size;
return result;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
append_partial_ss(String *dest, String src){
String end = tailstr(*dest);
b32 result = copy_partial_ss(&end, src);
dest->size += end.size;
return result;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
append_s_char(String *dest, char c){
b32 result = 0;
if (dest->size < dest->memory_size){
dest->str[dest->size++] = c;
result = 1;
}
return result;
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
append_ss(String *dest, String src){
return append_partial_ss(dest, src);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE b32
append_sc(String *dest, char *src){
return append_partial_sc(dest, src);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
terminate_with_null(String *str){
b32 result = 0;
if (str->size < str->memory_size){
str->str[str->size] = 0;
result = 1;
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
append_padding(String *dest, char c, i32 target_size){
b32 result = 1;
i32 offset = target_size - dest->size;
i32 r = 0;
if (offset > 0){
for (r = 0; r < offset; ++r){
if (append_s_char(dest, c) == 0){
result = 0;
break;
}
}
}
return(result);
}
#endif
//
// Other Edits
//
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
string_interpret_escapes(String src, char *dst)
{
i32 mode = 0;
i32 j = 0;
for (i32 i = 0; i < src.size; ++i){
switch (mode){
case 0:
{
if (src.str[i] == '\\'){
mode = 1;
}
else{
dst[j++] = src.str[i];
}
}break;
case 1:
{
char c = src.str[i];
switch (c){
case '\\':{dst[j++] = '\\';} break;
case 'n': {dst[j++] = '\n';} break;
case 't': {dst[j++] = '\t';} break;
case '"': {dst[j++] = '"'; } break;
case '0': {dst[j++] = '\0';} break;
default: {dst[j++] = '\\'; dst[j++] = c;}break;
}
mode = 0;
}break;
}
}
dst[j] = 0;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
replace_char(String *str, char replace, char with){
char *s = str->str;
i32 i = 0;
for (i = 0; i < str->size; ++i, ++s){
if (*s == replace) *s = with;
}
}
#endif
#if !defined(FSTRING_GUARD)
void
block_move(void *a_ptr, void *b_ptr, i32 s){
u8 *a = (u8*)a_ptr;
u8 *b = (u8*)b_ptr;
if (a < b){
for (i32 i = 0; i < s; ++i, ++a, ++b){
*a = *b;
}
}
else if (a > b){
a = a + s - 1;
b = b + s - 1;
for (i32 i = 0; i < s; ++i, --a, --b){
*a = *b;
}
}
}
void
replace_range_str(String *str, i32 first, i32 one_past_last, String with){
i32 shift = with.size - (one_past_last - first);
i32 new_size = str->size + shift;
if (new_size <= str->memory_size){
if (shift != 0){
char *tail = str->str + one_past_last;
char *new_tail_pos = tail + shift;
block_move(new_tail_pos, tail, str->size - one_past_last);
}
block_move(str->str + first, with.str, with.size);
str->size += shift;
}
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
replace_str_ss(String *str, String replace, String with){
i32 i = 0;
for (;;){
i = find_substr_s(*str, i, replace);
if (i >= str->size){
break;
}
replace_range_str(str, i, i + replace.size, with);
i += with.size;
}
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
replace_str_sc(String *str, String replace, char *with){
String w = make_string_slowly(with);
replace_str_ss(str, replace, w);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
replace_str_cs(String *str, char *replace, String with){
String r = make_string_slowly(replace);
replace_str_ss(str, r, with);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
replace_str_cc(String *str, char *replace, char *with){
String r = make_string_slowly(replace);
String w = make_string_slowly(with);
replace_str_ss(str, r, w);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
to_lower_cc(char *src, char *dst){
for (; *src != 0; ++src){
*dst++ = char_to_lower(*src);
}
*dst++ = 0;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
to_lower_ss(String *dst, String src){
i32 i = 0;
i32 size = src.size;
char *c = src.str;
char *d = dst->str;
if (dst->memory_size >= size){
for (; i < size; ++i){
*d++ = char_to_lower(*c++);
}
dst->size = size;
}
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
to_lower_s(String *str){
i32 i = 0;
i32 size = str->size;
char *c = str->str;
for (; i < size; ++c, ++i){
*c = char_to_lower(*c);
}
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
to_upper_cc(char *src, char *dst){
for (; *src != 0; ++src){
*dst++ = char_to_upper(*src);
}
*dst++ = 0;
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
to_upper_ss(String *dst, String src){
i32 i = 0;
i32 size = src.size;
char *c = src.str;
char *d = dst->str;
if (dst->memory_size >= size){
for (; i < size; ++i){
*d++ = char_to_upper(*c++);
}
dst->size = size;
}
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
to_upper_s(String *str){
i32 i = 0;
i32 size = str->size;
char *c = str->str;
for (; i < size; ++c, ++i){
*c = char_to_upper(*c);
}
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK void
to_camel_cc(char *src, char *dst){
char *c, ch;
i32 is_first = 1;
for (c = src; *c != 0; ++c){
ch = *c;
if (char_is_alpha_numeric_true(ch)){
if (is_first){
is_first = 0;
ch = char_to_upper(ch);
}
else{
ch = char_to_lower(ch);
}
}
else{
is_first = 1;
}
*dst++ = ch;
}
*dst = 0;
}
#endif
//
// String <-> Number Conversions
//
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
int_to_str_size(i32 x){
i32 size = 1;
if (x < 0){
size = 2;
}
x /= 10;
while (x != 0){
x /= 10;
++size;
}
return(size);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
int_to_str(String *dest, i32 x){
b32 result = 1;
char *str = dest->str;
i32 memory_size = dest->memory_size;
i32 size, i, j;
b32 negative;
if (x == 0){
str[0] = '0';
dest->size = 1;
}
else{
size = 0;
negative = 0;
if (x < 0){
negative = 1;
x = -x;
str[size++] = '-';
}
while (x != 0){
if (size == memory_size){
result = 0;
break;
}
i = x % 10;
x /= 10;
str[size++] = (char)('0' + i);
}
if (result){
// NOTE(allen): Start i = 0 if not negative, start i = 1 if is negative because - should not be flipped if it is negative :)
for (i = negative, j = size-1; i < j; ++i, --j){
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
dest->size = size;
}
else{
dest->size = 0;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
append_int_to_str(String *dest, i32 x){
String last_part = tailstr(*dest);
b32 result = int_to_str(&last_part, x);
if (result){
dest->size += last_part.size;
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
u64_to_str_size(uint64_t x){
i32 size = 1;
x /= 10;
while (x != 0){
x /= 10;
++size;
}
return(size);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
u64_to_str(String *dest, uint64_t x){
b32 result = 1;
char *str = dest->str;
i32 memory_size = dest->memory_size;
i32 size, i, j;
if (x == 0){
str[0] = '0';
dest->size = 1;
}
else{
size = 0;
while (x != 0){
if (size == memory_size){
result = 0;
break;
}
i = x % 10;
x /= 10;
str[size++] = (char)('0' + i);
}
if (result){
for (i = 0, j = size-1; i < j; ++i, --j){
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
dest->size = size;
}
else{
dest->size = 0;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
append_u64_to_str(String *dest, uint64_t x){
String last_part = tailstr(*dest);
b32 result = u64_to_str(&last_part, x);
if (result){
dest->size += last_part.size;
}
return(result);
}
#endif
#if !defined(FSTRING_GUARD)
typedef struct Float_To_Str_Variables{
b32 negative;
i32 int_part;
i32 dec_part;
} Float_To_Str_Variables;
static Float_To_Str_Variables
get_float_vars(float x){
Float_To_Str_Variables vars = {};
if (x < 0){
vars.negative = 1;
x = -x;
}
vars.int_part = (i32)(x);
vars.dec_part = (i32)((x - vars.int_part) * 1000);
return(vars);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
float_to_str_size(float x){
Float_To_Str_Variables vars = get_float_vars(x);
i32 size = vars.negative + int_to_str_size(vars.int_part) + 1 + int_to_str_size(vars.dec_part);
return(size);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
append_float_to_str(String *dest, float x){
b32 result = 1;
Float_To_Str_Variables vars = get_float_vars(x);
if (vars.negative){
append_s_char(dest, '-');
}
append_int_to_str(dest, vars.int_part);
append_s_char(dest, '.');
append_int_to_str(dest, vars.dec_part);
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
float_to_str(String *dest, float x){
b32 result = 1;
dest->size = 0;
append_float_to_str(dest, x);
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
str_is_int_c(char *str){
b32 result = 1;
for (; *str; ++str){
if (!char_is_numeric(*str)){
result = 0;
break;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
str_is_int_s(String str){
b32 result = 1;
for (i32 i = 0; i < str.size; ++i){
if (!char_is_numeric(str.str[i])){
result = 0;
break;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
str_to_int_c(char *str){
i32 x = 0;
for (; *str; ++str){
if (*str >= '0' && *str <= '9'){
x *= 10;
x += *str - '0';
}
else{
x = 0;
break;
}
}
return(x);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
str_to_int_s(String str){
i32 x, i;
if (str.size == 0){
x = 0;
}
else{
x = str.str[0] - '0';
for (i = 1; i < str.size; ++i){
x *= 10;
x += str.str[i] - '0';
}
}
return(x);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
hexchar_to_int(char c){
i32 x = 0;
if (c >= '0' && c <= '9'){
x = c-'0';
}
else if (c > 'F'){
x = c+(10-'a');
}
else{
x = c+(10-'A');
}
return(x);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK char
int_to_hexchar(i32 x){
return (x<10)?((char)x+'0'):((char)x+'a'-10);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK u32
hexstr_to_int(String str){
u32 x;
i32 i;
if (str.size == 0){
x = 0;
}
else{
x = hexchar_to_int(str.str[0]);
for (i = 1; i < str.size; ++i){
x *= 0x10;
x += hexchar_to_int(str.str[i]);
}
}
return(x);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
color_to_hexstr(String *s, u32 color){
b32 result = 0;
i32 i;
if (s->memory_size == 7 || s->memory_size == 8){
result = 1;
s->size = 6;
s->str[6] = 0;
color = color & 0x00FFFFFF;
for (i = 5; i >= 0; --i){
s->str[i] = int_to_hexchar(color & 0xF);
color >>= 4;
}
}
else if (s->memory_size > 8){
result = 1;
s->size = 8;
s->str[8] = 0;
for (i = 7; i >= 0; --i){
s->str[i] = int_to_hexchar(color & 0xF);
color >>= 4;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
hexstr_to_color(String s, u32 *out){
b32 result = 0;
u32 color = 0;
if (s.size == 6){
result = 1;
color = (u32)hexstr_to_int(s);
color |= (0xFF << 24);
*out = color;
}
else if (s.size == 8){
result = 1;
color = (u32)hexstr_to_int(s);
*out = color;
}
return(result);
}
#endif
//
// Directory String Management
//
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK i32
reverse_seek_slash_pos(String str, i32 pos){
i32 i = str.size - 1 - pos;
while (i >= 0 && !char_is_slash(str.str[i])){
--i;
}
return i;
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE i32
reverse_seek_slash(String str){
return(reverse_seek_slash_pos(str, 0));
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE String
front_of_directory(String dir){
return substr_tail(dir, reverse_seek_slash(dir) + 1);
}
#endif
#if !defined(FSTRING_GUARD)
FSTRING_INLINE String
path_of_directory(String dir){
return substr(dir, 0, reverse_seek_slash(dir) + 1);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
set_last_folder_sc(String *dir, char *folder_name, char slash){
b32 result = 0;
i32 size = reverse_seek_slash(*dir) + 1;
dir->size = size;
if (append_sc(dir, folder_name)){
if (append_s_char(dir, slash)){
result = 1;
}
}
if (!result){
dir->size = size;
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
set_last_folder_ss(String *dir, String folder_name, char slash){
b32 result = 0;
i32 size = reverse_seek_slash(*dir) + 1;
dir->size = size;
if (append_ss(dir, folder_name)){
if (append_s_char(dir, slash)){
result = 1;
}
}
if (!result){
dir->size = size;
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
file_extension(String str){
i32 i;
for (i = str.size - 1; i >= 0; --i){
if (str.str[i] == '.') break;
}
++i;
return(make_string(str.str+i, str.size-i));
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
remove_extension(String *str){
b32 result = 0;
i32 i;
for (i = str->size - 1; i >= 0; --i){
if (str->str[i] == '.') break;
}
if (i >= 0){
result = 1;
str->size = i + 1;
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
remove_last_folder(String *str){
b32 result = 0;
i32 end = reverse_seek_slash_pos(*str, 1);
if (end >= 0){
result = 1;
str->size = end + 1;
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
string_set_match_table(void *str_set, i32 item_size, i32 count, String str, i32 *match_index){
b32 result = 0;
i32 i = 0;
uint8_t *ptr = (uint8_t*)str_set;
for (; i < count; ++i, ptr += item_size){
if (match_ss(*(String*)ptr, str)){
*match_index = i;
result = 1;
break;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK b32
string_set_match(String *str_set, i32 count, String str, i32 *match_index){
b32 result = string_set_match_table(str_set, sizeof(String), count, str, match_index);
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
get_first_double_line(String source){
String line = {};
i32 pos0 = find_substr_s(source, 0, make_lit_string("\n\n"));
i32 pos1 = find_substr_s(source, 0, make_lit_string("\r\n\r\n"));
if (pos1 < pos0){
pos0 = pos1;
}
line = substr(source, 0, pos0);
return(line);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
get_next_double_line(String source, String line){
String next = {};
i32 pos = (i32)(line.str - source.str) + line.size;
i32 start = 0, pos0 = 0, pos1 = 0;
if (pos < source.size){
//Assert(source.str[pos] == '\n' || source.str[pos] == '\r');
start = pos + 1;
if (start < source.size){
pos0 = find_substr_s(source, start, make_lit_string("\n\n"));
pos1 = find_substr_s(source, start, make_lit_string("\r\n\r\n"));
if (pos1 < pos0){
pos0 = pos1;
}
next = substr(source, start, pos0 - start);
}
}
return(next);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
get_next_word(String source, String prev_word){
String word = {};
i32 pos0 = (i32)(prev_word.str - source.str) + prev_word.size;
i32 pos1 = 0;
char c = 0;
for (; pos0 < source.size; ++pos0){
c = source.str[pos0];
if (!(char_is_whitespace(c) || c == '(' || c == ')')){
break;
}
}
if (pos0 < source.size){
for (pos1 = pos0; pos1 < source.size; ++pos1){
c = source.str[pos1];
if (char_is_whitespace(c) || c == '(' || c == ')'){
break;
}
}
word = substr(source, pos0, pos1 - pos0);
}
return(word);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
get_first_word(String source){
String start_str = make_string(source.str, 0);
String word = get_next_word(source, start_str);
return(word);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
string_push(Cursor *cursor, i32 size){
String result = {};
if (size > 0){
result.str = push_array(cursor, char, size);
if (result.str != 0){
result.memory_size = size;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
string_push_copy(Cursor *cursor, String str){
String result = {};
if (str.str != 0){
result.str = push_array(cursor, char, str.size + 1);
if (result.str != 0){
result.memory_size = str.size + 1;
copy(&result, str);
result.str[result.size] = 0;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
string_push(Arena *arena, i32 size){
String result = {};
if (size > 0){
result.str = push_array(arena, char, size);
if (result.str != 0){
result.memory_size = size;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK String
string_push_copy(Arena *arena, String str){
String result = {};
if (str.str != 0){
result.str = push_array(arena, char, str.size + 1);
if (result.str != 0){
result.memory_size = str.size + 1;
copy(&result, str);
result.str[result.size] = 0;
}
}
return(result);
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
FSTRING_LINK char*
get_null_terminated(Arena *arena, String str){
char *str_terminated = 0;
if (str.size < str.memory_size){
if (str.str[str.size] != 0){
str.str[str.size] = 0;
}
str_terminated = str.str;
}
else{
str_terminated = push_array(arena, char, str.size + 1);
if (str_terminated != 0){
String builder = make_string_cap(str_terminated, 0, str.size + 1);
append(&builder, str);
str_terminated[str.size] = 0;
}
}
return(str_terminated);
}
#endif
// TODO(allen): eliminate this.
#ifndef FSTRING_EXPERIMENTAL
#define FSTRING_EXPERIMENTAL
// NOTE(allen): experimental section, things below here are
// not promoted to public API level yet.
typedef struct Absolutes{
String a[8];
i32 count;
} Absolutes;
static void
get_absolutes(String name, Absolutes *absolutes, b32 implicit_first, b32 implicit_last){
if (name.size != 0){
i32 count = 0;
i32 max = (sizeof(absolutes->a)/sizeof(*absolutes->a)) - 1;
if (implicit_last) --max;
String str;
str.str = name.str;
str.size = 0;
str.memory_size = 0;
b32 prev_was_wild = 0;
if (implicit_first){
absolutes->a[count++] = str;
prev_was_wild = 1;
}
i32 i;
for (i = 0; i < name.size; ++i){
if (name.str[i] == '*' && count < max){
if (!prev_was_wild){
str.memory_size = str.size;
absolutes->a[count++] = str;
str.size = 0;
}
str.str = name.str + i + 1;
prev_was_wild = 1;
}
else{
++str.size;
prev_was_wild = 0;
}
}
str.memory_size = str.size;
absolutes->a[count++] = str;
if (implicit_last){
str.size = 0;
str.memory_size = 0;
absolutes->a[count++] = str;
}
absolutes->count = count;
}
else{
absolutes->count = 0;
}
}
static b32
wildcard_match_c(Absolutes *absolutes, char *x, i32 case_sensitive){
b32 r = 1;
if (absolutes->count > 0){
String *a = absolutes->a;
b32 (*match_func)(char*, String);
b32 (*match_part_func)(char*, String);
if (case_sensitive){
match_func = match_cs;
match_part_func = match_part_cs;
}
else{
match_func = match_insensitive_cs;
match_part_func = match_part_insensitive_cs;
}
if (absolutes->count == 1){
r = match_func(x, *a);
}
else{
if (!match_part_func(x, *a)){
r = 0;
}
else{
String *max = a + absolutes->count - 1;
x += a->size;
++a;
while (a < max){
if (*x == 0){
r = 0;
break;
}
if (match_part_func(x, *a)){
x += a->size;
++a;
}
else{
++x;
}
}
if (r && a->size > 0){
r = 0;
while (*x != 0){
if (match_part_func(x, *a) && *(x + a->size) == 0){
r = 1;
break;
}
else{
++x;
}
}
}
}
}
}
return(r);
}
static b32
wildcard_match_s(Absolutes *absolutes, String x, i32 case_sensitive){
terminate_with_null(&x);
return(wildcard_match_c(absolutes, x.str, case_sensitive));
}
#endif
#if defined(FSTRING_IMPLEMENTATION)
#undef FSTRING_IMPLEMENTATION
#define FSTRING_IMPL_GUARD
#endif
#if !defined(FSTRING_GUARD)
#define FSTRING_GUARD
#endif
#endif
// BOTTOM