platform_string.c (8347B)
1 ////////////////////////////////////////////////////////////////// 2 // platform_string.h 3 4 ////////////////////////////////////////////////////////////////// 5 // char 6 7 8 RV_READ_ONLY RV_INTERNAL u8 char_integer_symbol_reverse[128] = { 9 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 10 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 11 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 12 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 13 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 14 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 15 0xFF,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 16 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, 17 }; 18 19 RV_GLOBAL bool32 rv_char_is_space(u8 c) 20 { 21 return c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\f' || c == '\v'; 22 } 23 24 RV_GLOBAL bool32 rv_char_is_upper(u8 c) 25 { 26 return 'A' <= c && c <= 'Z'; 27 } 28 29 RV_GLOBAL bool32 rv_char_is_lower(u8 c) 30 { 31 return 'a' <= c && c <= 'z'; 32 } 33 34 RV_GLOBAL bool32 rv_char_is_alpha(u8 c) 35 { 36 return rv_char_is_upper(c) || rv_char_is_lower(c); 37 } 38 39 RV_GLOBAL bool32 rv_char_is_slash(u8 c) 40 { 41 return c == '/' || c == '\\'; 42 } 43 44 RV_GLOBAL bool32 rv_char_is_digit(u8 c, s32 base) 45 { 46 bool32 result = 0; 47 if (base >= 0 && base <= 16) { 48 u8 val = char_integer_symbol_reverse[c]; 49 if (val < base) { 50 result = 1; 51 } 52 } 53 return result; 54 } 55 56 RV_GLOBAL u8 rv_char_to_lower(u8 c) 57 { 58 if (rv_char_is_upper(c)) { 59 c += ('a' - 'A'); 60 } 61 return c; 62 } 63 64 RV_GLOBAL u8 rv_char_to_upper(u8 c) 65 { 66 if (rv_char_is_lower(c)) { 67 c += ('A' - 'a'); 68 } 69 return c; 70 } 71 72 RV_GLOBAL u8 rv_char_to_correct_slash(u8 c) 73 { 74 if(rv_char_is_slash(c)) { 75 c = '/'; 76 } 77 return c; 78 } 79 80 ////////////////////////////////////////////////////////////////// 81 // c strings 82 83 RV_GLOBAL s64 rv_cstrlen(const char* c_str) 84 { 85 s64 res = 0; 86 while (*c_str++) res++; 87 return res; 88 } 89 90 ////////////////////////////////////////////////////////////////// 91 // constructors 92 93 RV_GLOBAL rv_str8 rv_str8_range(u8* first, u8* one_past_last) 94 { 95 return rv_s8(first, (s64)(one_past_last - first)); 96 } 97 98 99 ////////////////////////////////////////////////////////////////// 100 // conversions 101 102 RV_GLOBAL s64 rv_sign_from_str8(rv_str8 string, rv_str8* string_tail) 103 { 104 // count negative signs 105 u64 neg_count = 0; 106 u64 i = 0; 107 for (; i < string.len; i += 1) { 108 if (string.str[i] == '-') { 109 neg_count += 1; 110 } 111 else if (string.str[i] != '+') { 112 break; 113 } 114 } 115 116 // output part of string after signs 117 *string_tail = rv_str8_skip(string, i); 118 119 // output integer sign 120 s64 sign = (neg_count & 1) ? -1 : +1; 121 return sign; 122 } 123 124 125 RV_GLOBAL u64 rv_u64_from_str8(rv_str8 string, u32 radix) 126 { 127 u64 x = 0; 128 if (1 < radix && radix <= 16) { 129 for (u64 i = 0; i < string.len; i += 1) { 130 x *= radix; 131 x += char_integer_symbol_reverse[string.str[i]&0x7F]; 132 } 133 } 134 return x; 135 } 136 137 138 RV_GLOBAL s64 rv_s64_from_str8(rv_str8 string, s32 radix) 139 { 140 s64 sign = rv_sign_from_str8(string, &string); 141 s64 x = (s64)rv_u64_from_str8(string, radix) * sign; 142 return x; 143 } 144 145 RV_GLOBAL rv_str8 str8_from_s64(rv_arena* arena, s64 integer, s32 radix, u8 min_digits, u8 digit_group_separator); 146 147 ////////////////////////////////////////////////////////////////// 148 // matching 149 150 RV_GLOBAL bool32 rv_str8_match(rv_str8 a, rv_str8 b, rv_str8_match_flags flags) 151 { 152 bool32 result = 0; 153 if (a.len == b.len || (flags & rv_str8_match_flag_right_side_sloppy)){ 154 bool32 case_insensitive = (flags & rv_str8_match_flag_case_insensetive); 155 bool32 slash_insensitive = (flags & rv_str8_match_flag_slash_insensetive); 156 s64 len = rv_min(a.len, b.len); 157 result = 1; 158 for (s64 i = 0; i < len; i += 1){ 159 u8 at = a.str[i]; 160 u8 bt = b.str[i]; 161 if (case_insensitive){ 162 at = rv_char_to_upper(at); 163 bt = rv_char_to_upper(bt); 164 } 165 if (slash_insensitive){ 166 at = rv_char_to_correct_slash(at); 167 bt = rv_char_to_correct_slash(bt); 168 } 169 if (at != bt){ 170 result = 0; 171 break; 172 } 173 } 174 } 175 return result; 176 } 177 178 RV_GLOBAL s64 rv_str8_find_needle(rv_str8 string, s64 start_pos, rv_str8 needle, rv_str8_match_flags flags) 179 { 180 u8* p = string.str + start_pos; 181 s64 stop_offset = rv_max(string.len + 1, needle.len) - needle.len; 182 u8* stop_p = string.str + stop_offset; 183 184 if (string.len > 0 && needle.len > 0) { 185 u8* string_opl = string.str + string.len; 186 187 rv_str8 needle_tail = rv_str8_skip(needle, 1); 188 rv_str8_match_flags adjusted_flags = flags | rv_str8_match_flag_right_side_sloppy; 189 u8 needle_first_rv_char_adjusted = needle.str[0]; 190 191 if (adjusted_flags & rv_str8_match_flag_case_insensetive) { 192 needle_first_rv_char_adjusted = rv_char_to_upper(needle_first_rv_char_adjusted); 193 } 194 195 for (;p < stop_p; p += 1) { 196 u8 haystack_rv_char_adjusted = *p; 197 198 if (adjusted_flags & rv_str8_match_flag_case_insensetive) { 199 haystack_rv_char_adjusted = rv_char_to_upper(haystack_rv_char_adjusted); 200 } 201 202 if (haystack_rv_char_adjusted == needle_first_rv_char_adjusted) { 203 if (rv_str8_match(rv_str8_range(p + 1, string_opl), needle_tail, adjusted_flags)) { 204 break; 205 } 206 } 207 } 208 } 209 s64 result = string.len; 210 if (p < stop_p) { 211 result = (s64)(p - string.str); 212 } 213 return result; 214 } 215 216 ////////////////////////////////////////////////////////////////// 217 // slicing 218 219 RV_GLOBAL rv_str8 rv_str8_substr(rv_str8 str, rv_range range) 220 { 221 range.min = rv_min(range.min, str.len); 222 range.max = rv_min(range.max, str.len); 223 str.str += range.min; 224 str.len = rv_range_diff(range); 225 return str; 226 } 227 228 RV_GLOBAL rv_str8 rv_str8_prefix(rv_str8 str, s64 len) 229 { 230 str.len = rv_min(len, str.len); 231 return str; 232 } 233 234 RV_GLOBAL rv_str8 rv_str8_skip(rv_str8 str, s64 amt) 235 { 236 amt = rv_min(amt, str.len); 237 str.str += amt; 238 str.len -= amt; 239 return str; 240 } 241 242 RV_GLOBAL rv_str8 rv_str8_postfix(rv_str8 str, s64 len) 243 { 244 len = rv_min(len, str.len); 245 str.str = (str.str + str.len) - len; 246 str.len = len; 247 return str; 248 } 249 250 RV_GLOBAL rv_str8 rv_str8_chop(rv_str8 str, s64 amt) 251 { 252 amt = rv_min(amt, str.len); 253 str.len -= amt; 254 return str; 255 } 256 257 RV_GLOBAL rv_str8 rv_str8_skip_chop_whitespace(rv_str8 string) 258 { 259 u8* first = string.str; 260 u8* opl = first + string.len; 261 for (;first < opl; first += 1) { 262 if (!rv_char_is_space(*first)) { 263 break; 264 } 265 } 266 for (;opl > first;) { 267 opl -= 1; 268 if (!rv_char_is_space(*opl)) { 269 opl += 1; 270 break; 271 } 272 } 273 rv_str8 result = rv_str8_range(first, opl); 274 return result; 275 } 276 277 ////////////////////////////////////////////////////////////////// 278 // misc 279 280 RV_GLOBAL rv_str8 rv_str8_copy(rv_arena* arena, rv_str8 s) 281 { 282 rv_str8 str; 283 str.len = s.len; 284 str.str = rv_push_array_no_zero(arena, u8, str.len + 1); 285 rv_mem_copy(str.str, s.str, s.len); 286 str.str[str.len] = 0; 287 return str; 288 } 289 290 RV_GLOBAL rv_str8 rv_read_file(rv_arena* arena, rv_str8 filename) 291 { 292 u8* buffer = NULL; 293 s64 len = 0; 294 295 FILE* fp = NULL; 296 { 297 rv_temp_arena scratch = rv_scratch_begin((rv_arena*[]){arena}, 1); 298 rv_str8 filename_copy = rv_str8_copy(scratch.arena, filename); 299 fp = fopen((char*)filename_copy.str, "rb"); 300 rv_scratch_end(scratch); 301 } 302 303 if (fp) { 304 fseek(fp, 0, SEEK_END); 305 len = ftell(fp); 306 fseek(fp, 0, SEEK_SET); 307 308 buffer = rv_push_array_no_zero(arena, u8, len + 1); 309 fread(buffer, 1, len, fp); 310 311 fclose(fp); 312 } else { 313 fprintf(stderr, "rv_read_file, unable to rad file '%.*s' (%d: %s)\n", rv_s8v(filename), errno, strerror(errno)); 314 rv_unreachable(); 315 } 316 317 return rv_s8(buffer, len); 318 }