-
-
Save justinas/6b6192a187738a30dd77a08ff1ae44fe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> // TODO remove all these includes, define all function signatures and types manually | |
#include <stdlib.h> | |
#include <signal.h> | |
#include <stdarg.h> // for va_list | |
#include <inttypes.h> // int64_t etc | |
#include <string.h> // memcpy | |
#ifndef _WIN32 | |
#include <ctype.h> | |
#include <locale.h> // tolower | |
#include <sys/time.h> | |
#include <unistd.h> // sleep | |
#endif | |
#ifdef __APPLE__ | |
#include <libproc.h> // proc_pidpath | |
#include <execinfo.h> // backtrace and backtrace_symbols_fd | |
#endif | |
#ifdef __linux__ | |
#ifndef __BIONIC__ | |
#include <execinfo.h> // backtrace and backtrace_symbols_fd | |
#endif | |
#pragma weak backtrace | |
#pragma weak backtrace_symbols_fd | |
#endif | |
#ifdef __linux__ | |
#include <sys/types.h> | |
#include <sys/wait.h> // os__wait uses wait on nix | |
#endif | |
#define EMPTY_STRUCT_DECLARATION | |
#define EMPTY_STRUCT_INITIALIZATION 0 | |
#ifdef __TINYC__ | |
#undef EMPTY_STRUCT_INITIALIZATION | |
#define EMPTY_STRUCT_INITIALIZATION | |
#endif | |
#define OPTION_CAST(x) (x) | |
#ifdef _WIN32 | |
#define WINVER 0x0600 | |
#define _WIN32_WINNT 0x0600 | |
#define WIN32_LEAN_AND_MEAN | |
#define _UNICODE | |
#define UNICODE | |
#include <windows.h> | |
// must be included after <windows.h> | |
#ifndef __TINYC__ | |
#include <shellapi.h> | |
#endif | |
#include <io.h> // _waccess | |
#include <fcntl.h> // _O_U8TEXT | |
#include <direct.h> // _wgetcwd | |
//#include <WinSock2.h> | |
#ifdef _MSC_VER | |
// On MSVC these are the same (as long as /volatile:ms is passed) | |
#define _Atomic volatile | |
// MSVC cannot parse some things properly | |
#undef EMPTY_STRUCT_DECLARATION | |
#undef OPTION_CAST | |
#define EMPTY_STRUCT_DECLARATION int ____dummy_variable | |
#define OPTION_CAST(x) | |
#endif | |
void pthread_mutex_lock(HANDLE *m) { | |
WaitForSingleObject(*m, INFINITE); | |
} | |
void pthread_mutex_unlock(HANDLE *m) { | |
ReleaseMutex(*m); | |
} | |
#else | |
#include <pthread.h> | |
#endif | |
//================================== TYPEDEFS ================================*/ | |
typedef int64_t i64; | |
typedef int16_t i16; | |
typedef int8_t i8; | |
typedef uint64_t u64; | |
typedef uint32_t u32; | |
typedef uint16_t u16; | |
typedef uint8_t byte; | |
typedef uint32_t rune; | |
typedef float f32; | |
typedef double f64; | |
typedef unsigned char* byteptr; | |
typedef int* intptr; | |
typedef void* voidptr; | |
typedef struct array array; | |
typedef struct map map; | |
typedef array array_string; | |
typedef array array_int; | |
typedef array array_byte; | |
typedef array array_f32; | |
typedef array array_f64; | |
typedef map map_int; | |
typedef map map_string; | |
#ifndef bool | |
typedef int bool; | |
#define true 1 | |
#define false 0 | |
#endif | |
//============================== HELPER C MACROS =============================*/ | |
#define _PUSH(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push(arr, &tmp);} | |
#define _PUSH_MANY(arr, val, tmp, tmp_typ) {tmp_typ tmp = (val); array__push_many(arr, tmp.data, tmp.len);} | |
#define _IN(typ, val, arr) array_##typ##_contains(arr, val) | |
#define _IN_MAP(val, m) map__exists(m, val) | |
#define DEFAULT_EQUAL(a, b) (a == b) | |
//================================== GLOBALS =================================*/ | |
byteptr g_str_buf; | |
int load_so(byteptr); | |
void reload_so(); | |
void init_consts(); | |
int g_test_ok = 1; | |
#include <float.h> | |
#include <math.h> | |
typedef struct array array; | |
typedef array array_string; | |
typedef array array_byte; | |
typedef array array_int; | |
typedef struct string string; | |
typedef struct ustring ustring; | |
typedef struct map map; | |
typedef struct mapnode mapnode; | |
typedef struct Option Option; | |
typedef struct strings__Builder strings__Builder; | |
struct string { | |
byte* str; | |
int len; | |
}; | |
struct array { | |
void* data; | |
int len; | |
int cap; | |
int element_size; | |
}; | |
struct map { | |
int element_size; | |
mapnode* root; | |
int size; | |
}; | |
struct Option { | |
byte data [255 ]; | |
string error; | |
bool ok; | |
bool is_none; | |
}; | |
//---- | |
struct mapnode { | |
mapnode* left; | |
mapnode* right; | |
bool is_empty; | |
string key; | |
void* val; | |
}; | |
struct strings__Builder { | |
array_byte buf; | |
int len; | |
}; | |
struct ustring { | |
string s; | |
array_int runes; | |
int len; | |
}; | |
string _STR(const char*, ...); | |
string _STR_TMP(const char*, ...); | |
array new_array(int mylen, int cap, int elm_size); | |
array _make(int len, int cap, int elm_size); | |
array new_array_from_c_array(int len, int cap, int elm_size, void* c_array); | |
array new_array_from_c_array_no_alloc(int len, int cap, int elm_size, void* c_array); | |
array array_repeat_old(void* val, int nr_repeats, int elm_size); | |
array array_repeat(array a, int nr_repeats); | |
void array_sort_with_compare(array* a, void* compare); | |
void array_insert(array* a, int i, void* val); | |
void array_prepend(array* a, void* val); | |
void v_array_delete(array* a, int idx); | |
void* array__get(array a, int i); | |
void* array_first(array a); | |
void* array_last(array a); | |
array array_left(array s, int n); | |
array array_right(array s, int n); | |
array array_slice(array s, int start, int _end); | |
void array_set(array* a, int idx, void* val); | |
void array__push(array* arr, void* val); | |
void array__push_many(array* arr, void* val, int size); | |
array array_reverse(array a); | |
array array_clone(array a); | |
void v_array_free(array a); | |
string array_string_str(array_string a); | |
string array_byte_hex(array_byte b); | |
int copy(array_byte dst, array_byte src); | |
int compare_ints(int* a, int* b); | |
void array_int_sort(array_int* a); | |
int vstrlen(byte* s); | |
void todo(); | |
string tos(byte* s, int len); | |
string tos_clone(byte* s); | |
string tos2(byte* s); | |
string string_clone(string a); | |
string string_replace(string s, string rep, string with); | |
int v_string_int(string s); | |
i64 string_i64(string s); | |
f32 string_f32(string s); | |
f64 string_f64(string s); | |
u32 string_u32(string s); | |
u64 string_u64(string s); | |
bool string_eq(string s, string a); | |
bool string_ne(string s, string a); | |
bool string_lt(string s, string a); | |
bool string_le(string s, string a); | |
bool string_gt(string s, string a); | |
bool string_ge(string s, string a); | |
string string_add(string s, string a); | |
array_string string_split(string s, string delim); | |
array_string string_split_single(string s, byte delim); | |
array_string string_split_into_lines(string s); | |
string string_left(string s, int n); | |
string string_right(string s, int n); | |
string string_substr(string s, int start, int end); | |
int string_index(string s, string p); | |
int string_index_kmp(string s, string p); | |
int string_index_any(string s, string chars); | |
int string_last_index(string s, string p); | |
int string_index_after(string s, string p, int start); | |
int string_count(string s, string substr); | |
bool string_contains(string s, string p); | |
bool string_starts_with(string s, string p); | |
bool string_ends_with(string s, string p); | |
string string_to_lower(string s); | |
string string_to_upper(string s); | |
string string_capitalize(string s); | |
string string_title(string s); | |
string string_find_between(string s, string start, string end); | |
bool array_string_contains(array_string ar, string val); | |
bool array_int_contains(array_int ar, int val); | |
bool is_space(byte c); | |
bool byte_is_space(byte c); | |
string string_trim_space(string s); | |
string string_trim(string s, string cutset); | |
string string_trim_left(string s, string cutset); | |
string string_trim_right(string s, string cutset); | |
int compare_strings(string* a, string* b); | |
int compare_strings_by_len(string* a, string* b); | |
int compare_lower_strings(string* a, string* b); | |
void array_string_sort(array_string* s); | |
void array_string_sort_ignore_case(array_string* s); | |
void array_string_sort_by_len(array_string* s); | |
ustring string_ustring(string s); | |
ustring string_ustring_tmp(string s); | |
bool ustring_eq(ustring u, ustring a); | |
bool ustring_ne(ustring u, ustring a); | |
bool ustring_lt(ustring u, ustring a); | |
bool ustring_le(ustring u, ustring a); | |
bool ustring_gt(ustring u, ustring a); | |
bool ustring_ge(ustring u, ustring a); | |
ustring ustring_add(ustring u, ustring a); | |
int ustring_index_after(ustring u, ustring p, int start); | |
int ustring_count(ustring u, ustring substr); | |
string ustring_substr(ustring u, int _start, int _end); | |
string ustring_left(ustring u, int pos); | |
string ustring_right(ustring u, int pos); | |
byte string_at(string s, int idx); | |
string ustring_at(ustring u, int idx); | |
void v_ustring_free(ustring u); | |
bool byte_is_digit(byte c); | |
bool byte_is_hex_digit(byte c); | |
bool byte_is_oct_digit(byte c); | |
bool byte_is_letter(byte c); | |
void v_string_free(string s); | |
string string_all_before(string s, string dot); | |
string string_all_before_last(string s, string dot); | |
string string_all_after(string s, string dot); | |
string array_string_join(array_string a, string del); | |
string array_string_join_lines(array_string s); | |
string string_reverse(string s); | |
string string_limit(string s, int max); | |
bool byte_is_white(byte c); | |
int string_hash(string s); | |
array_byte string_bytes(string s); | |
string string_repeat(string s, int count); | |
void v_exit(int code); | |
bool isnil(void* v); | |
void on_panic(int (*f)( int /*FFF*/ )); | |
void print_backtrace_skipping_top_frames(int skipframes); | |
void print_backtrace(); | |
void _panic_debug(int line_no, string file, string mod, string fn_name, string s); | |
void v_panic(string s); | |
void println(string s); | |
void eprintln(string s); | |
void print(string s); | |
byte* v_malloc(int n); | |
byte* v_calloc(int n); | |
void v_free(void* ptr); | |
void* memdup(void* src, int sz); | |
void v_ptr_free(void* ptr); | |
string f64_str(f64 d); | |
string f32_str(f32 d); | |
string ptr_str(void* ptr); | |
bool f64_eq(f64 a, f64 b); | |
bool f32_eq(f32 a, f32 b); | |
bool f64_eqbit(f64 a, f64 b); | |
bool f32_eqbit(f32 a, f32 b); | |
string int_str(int nn); | |
string u32_str(u32 nn); | |
string i64_str(i64 nn); | |
string u64_str(u64 nn); | |
string bool_str(bool b); | |
string int_hex(int n); | |
string i64_hex(i64 n); | |
bool array_byte_contains(array_byte a, byte val); | |
string rune_str(rune c); | |
string byte_str(byte c); | |
bool byte_is_capital(byte c); | |
array_byte array_byte_clone(array_byte b); | |
int utf8_char_len(byte b); | |
string utf32_to_str(u32 code); | |
string utf32_to_str_no_malloc(u32 code, void* buf); | |
int string_utf32_code(string _rune); | |
u16* string_to_wide(string _str); | |
string string_from_wide(u16* _wstr); | |
string string_from_wide2(u16* _wstr, int len); | |
int utf8_len(byte c); | |
int utf8_getchar(); | |
map new_map(int cap, int elm_size); | |
map new_map_init(int cap, int elm_size, string* keys, void* vals); | |
mapnode* new_node(string key, void* val, int element_size); | |
void map_insert(map* m, mapnode* n, string key, void* val); | |
bool mapnode_find(mapnode* n, string key, void* out, int element_size); | |
bool mapnode_find2(mapnode* n, string key, int element_size); | |
void map__set(map* m, string key, void* val); | |
int preorder_keys(mapnode* node, array_string* keys, int key_i); | |
array_string map_keys(map* m); | |
bool map_get(map m, string key, void* out); | |
void v_mapnode_delete(mapnode* n, string key, int element_size); | |
void v_map_delete(map* m, string key); | |
void map_exists(map m, string key); | |
bool map__exists(map m, string key); | |
void map_print(map m); | |
void v_mapnode_free(mapnode* n); | |
void v_map_free(map* m); | |
string map_string_str(map_string m); | |
Option opt_ok(void* data, int size); | |
Option opt_none(); | |
Option v_error(string s); | |
strings__Builder strings__new_builder(int initial_size); | |
void strings__Builder_write(strings__Builder* b, string s); | |
void strings__Builder_writeln(strings__Builder* b, string s); | |
string strings__Builder_str(strings__Builder b); | |
void strings__Builder_cut(strings__Builder* b, int n); | |
void strings__Builder_free(strings__Builder* b); | |
int strings__levenshtein_distance(string a, string b); | |
f32 strings__levenshtein_distance_percentage(string a, string b); | |
f32 strings__dice_coefficient(string s1, string s2); | |
string strings__repeat(byte c, int n); | |
void main__draw_text(string s, int x, int y); | |
void main__draw_scene(); | |
void main__main(); | |
array_int g_ustring_runes; // global | |
i64 total_m = 0; // global | |
#define builtin__CP_UTF8 65001 | |
array new_array(int mylen, int cap, int elm_size) { | |
int a= 3 ; | |
a ; ; | |
array arr= (array) { .len = mylen , .cap = cap , .element_size = elm_size , .data = v_calloc ( cap * elm_size ) } ; | |
return arr ; | |
} | |
array _make(int len, int cap, int elm_size) { | |
return new_array ( len , cap , elm_size ) ; | |
} | |
array new_array_from_c_array(int len, int cap, int elm_size, void* c_array) { | |
array arr= (array) { .len = len , .cap = cap , .element_size = elm_size , .data = v_calloc ( cap * elm_size ) } ; | |
memcpy ( arr .data , c_array , len * elm_size ) ; | |
return arr ; | |
} | |
array new_array_from_c_array_no_alloc(int len, int cap, int elm_size, void* c_array) { | |
array arr= (array) { .len = len , .cap = cap , .element_size = elm_size , .data = c_array } ; | |
return arr ; | |
} | |
array array_repeat_old(void* val, int nr_repeats, int elm_size) { | |
array arr= (array) { .len = nr_repeats , .cap = nr_repeats , .element_size = elm_size , .data = v_calloc ( nr_repeats * elm_size ) } ; | |
for ( | |
int i= 0 ; i < nr_repeats ; i ++ ) { | |
memcpy ((byte*) arr .data + i * elm_size , val , elm_size ) ; | |
} | |
; | |
return arr ; | |
} | |
array array_repeat(array a, int nr_repeats) { | |
array arr= (array) { .len = nr_repeats , .cap = nr_repeats , .element_size = a .element_size , .data = v_calloc ( nr_repeats * a .element_size ) } ; | |
void* val=(byte*) a .data + 0 ; | |
for ( | |
int i= 0 ; i < nr_repeats ; i ++ ) { | |
memcpy ((byte*) arr .data + i * a .element_size , val , a .element_size ) ; | |
} | |
; | |
return arr ; | |
} | |
void array_sort_with_compare(array* a, void* compare) { | |
qsort ( a ->data , a ->len , a ->element_size , compare ) ; | |
} | |
void array_insert(array* a, int i, void* val) { | |
if ( i >= a ->len ) { | |
v_panic ( tos2((byte*)"array.insert: index larger than length") ) ; | |
} | |
; | |
array__push( a , val ) ; | |
int size= a ->element_size ; | |
memmove ((byte*) a ->data + ( i + 1 ) * size , (byte*) a ->data + i * size , ( a ->len - i ) * size ) ; | |
array_set( a , i , val ) ; | |
} | |
void array_prepend(array* a, void* val) { | |
array_insert( a , 0 , val ) ; | |
} | |
void v_array_delete(array* a, int idx) { | |
int size= a ->element_size ; | |
memmove ((byte*) a ->data + idx * size , (byte*) a ->data + ( idx + 1 ) * size , ( a ->len - idx ) * size ) ; | |
a ->len -- ; | |
a ->cap -- ; | |
} | |
void* array__get(array a, int i) { | |
if ( i < 0 || i >= a .len ) { | |
v_panic ( _STR("array index out of range: %d/%d", i, a .len) ) ; | |
} | |
; | |
return (byte*) a .data + i * a .element_size ; | |
} | |
void* array_first(array a) { | |
if ( a .len == 0 ) { | |
v_panic ( tos2((byte*)"array.first: empty array") ) ; | |
} | |
; | |
return (byte*) a .data + 0 ; | |
} | |
void* array_last(array a) { | |
if ( a .len == 0 ) { | |
v_panic ( tos2((byte*)"array.last: empty array") ) ; | |
} | |
; | |
return (byte*) a .data + ( a .len - 1 ) * a .element_size ; | |
} | |
array array_left(array s, int n) { | |
if ( n >= s .len ) { | |
return s ; | |
} | |
; | |
return array_slice( s , 0 , n ) ; | |
} | |
array array_right(array s, int n) { | |
if ( n >= s .len ) { | |
return s ; | |
} | |
; | |
return array_slice( s , n , s .len ) ; | |
} | |
array array_slice(array s, int start, int _end) { | |
int end= _end ; | |
if ( start > end ) { | |
v_panic ( _STR("invalid slice index: %d > %d", start, end) ) ; | |
} | |
; | |
if ( end > s .len ) { | |
v_panic ( _STR("runtime error: slice bounds out of range (%d >= %d)", end, s .len) ) ; | |
} | |
; | |
if ( start < 0 ) { | |
v_panic ( _STR("runtime error: slice bounds out of range (%d < 0)", start) ) ; | |
} | |
; | |
int l= end - start ; | |
array res= (array) { .element_size = s .element_size , .data = (byte*) s .data + start * s .element_size , .len = l , .cap = l } ; | |
return res ; | |
} | |
void array_set(array* a, int idx, void* val) { | |
if ( idx < 0 || idx >= a ->len ) { | |
v_panic ( _STR("array index out of range: %d / %d", idx, a ->len) ) ; | |
} | |
; | |
memcpy ((byte*) a ->data + a ->element_size * idx , val , a ->element_size ) ; | |
} | |
void array__push(array* arr, void* val) { | |
if ( arr ->len >= arr ->cap - 1 ) { | |
int cap= ( arr ->len + 1 ) * 2 ; | |
if ( arr ->cap == 0 ) { | |
arr ->data = v_calloc ( cap * arr ->element_size ) ; | |
} | |
else { | |
arr ->data = realloc ( arr ->data , cap * arr ->element_size ) ; | |
} | |
; | |
arr ->cap = cap ; | |
} | |
; | |
memcpy ((byte*) arr ->data + arr ->element_size * arr ->len , val , arr ->element_size ) ; | |
arr ->len ++ ; | |
} | |
void array__push_many(array* arr, void* val, int size) { | |
if ( arr ->len >= arr ->cap - size ) { | |
int cap= ( arr ->len + size ) * 2 ; | |
if ( arr ->cap == 0 ) { | |
arr ->data = v_calloc ( cap * arr ->element_size ) ; | |
} | |
else { | |
arr ->data = realloc ( arr ->data , cap * arr ->element_size ) ; | |
} | |
; | |
arr ->cap = cap ; | |
} | |
; | |
memcpy ((byte*) arr ->data + arr ->element_size * arr ->len , val , arr ->element_size * size ) ; | |
arr ->len += size ; | |
} | |
array array_reverse(array a) { | |
array arr= (array) { .len = a .len , .cap = a .cap , .element_size = a .element_size , .data = v_calloc ( a .cap * a .element_size ) } ; | |
for ( | |
int i= 0 ; i < a .len ; i ++ ) { | |
memcpy ((byte*) arr .data + i * arr .element_size , & /*v*/ ( *(array*) array__get( a , a .len - 1 - i) ) , arr .element_size ) ; | |
} | |
; | |
return arr ; | |
} | |
array array_clone(array a) { | |
array arr= (array) { .len = a .len , .cap = a .cap , .element_size = a .element_size , .data = v_calloc ( a .cap * a .element_size ) } ; | |
memcpy ( arr .data , a .data , a .cap * a .element_size ) ; | |
return arr ; | |
} | |
void v_array_free(array a) { | |
free ( a .data ) ; | |
} | |
string array_string_str(array_string a) { | |
strings__Builder sb= strings__new_builder ( a .len * 3 ) ; | |
strings__Builder_write(& /* ? */ sb , tos2((byte*)"[") ) ; | |
for ( | |
int i= 0 ; i < a .len ; i ++ ) { | |
string val= ( *(string*) array__get( a , i) ) ; | |
strings__Builder_write(& /* ? */ sb , tos2((byte*)"\"") ) ; | |
strings__Builder_write(& /* ? */ sb , val ) ; | |
strings__Builder_write(& /* ? */ sb , tos2((byte*)"\"") ) ; | |
if ( i < a .len - 1 ) { | |
strings__Builder_write(& /* ? */ sb , tos2((byte*)", ") ) ; | |
} | |
; | |
} | |
; | |
strings__Builder_write(& /* ? */ sb , tos2((byte*)"]") ) ; | |
return strings__Builder_str( sb ) ; | |
} | |
string array_byte_hex(array_byte b) { | |
byte* hex= v_malloc ( b .len * 2 + 1 ) ; | |
byte* ptr= & /*v*/ hex [/*ptr*/ 0 ]/*rbyte 1*/ ; | |
for ( | |
int i= 0 ; i < b .len ; i ++ ) { | |
ptr += sprintf ( ((char*)( ptr ) ) , "%02x" , ( *(byte*) array__get( b , i) ) ) ; | |
} | |
; | |
return (tos2((byte *) hex ) ) ; | |
} | |
int copy(array_byte dst, array_byte src) { | |
if ( dst .len > 0 && src .len > 0 ) { | |
int min= ( dst .len < src .len ) ? ( dst .len ) : ( src .len ) ; | |
memcpy ( dst .data , array_left( src , min ) .data , dst .element_size * min ) ; | |
return min ; | |
} | |
; | |
return 0 ; | |
} | |
int compare_ints(int* a, int* b) { | |
if ( a < b ) { | |
return - 1 ; | |
} | |
; | |
if ( a > b ) { | |
return 1 ; | |
} | |
; | |
return 0 ; | |
} | |
void array_int_sort(array_int* a) { | |
array_sort_with_compare( a ,& /*112 EXP:"void*" GOT:"fn (int*,int*) int" */ compare_ints ) ; | |
} | |
int vstrlen(byte* s) { | |
return strlen ( ((char*)( s ) ) ) ; | |
} | |
void todo() { | |
} | |
string tos(byte* s, int len) { | |
if ( isnil ( s ) ) { | |
v_panic ( tos2((byte*)"tos(): nil string") ) ; | |
} | |
; | |
return (string) { .str = s , .len = len } ; | |
} | |
string tos_clone(byte* s) { | |
if ( isnil ( s ) ) { | |
v_panic ( tos2((byte*)"tos: nil string") ) ; | |
} | |
; | |
return string_clone( tos2 ( s ) ) ; | |
} | |
string tos2(byte* s) { | |
if ( isnil ( s ) ) { | |
v_panic ( tos2((byte*)"tos2: nil string") ) ; | |
} | |
; | |
int len= vstrlen ( s ) ; | |
string res= tos ( s , len ) ; | |
return res ; | |
} | |
string string_clone(string a) { | |
string b= (string) { .len = a .len , .str = v_malloc ( a .len + 1 ) } ; | |
for ( | |
int i= 0 ; i < a .len ; i ++ ) { | |
b .str[ i ]/*rbyte 1*/ = a .str[ i ]/*rbyte 0*/ ; | |
} | |
; | |
b .str[ a .len ]/*rbyte 1*/ = '\0' ; | |
return b ; | |
} | |
string string_replace(string s, string rep, string with) { | |
if ( s .len == 0 || rep .len == 0 ) { | |
return s ; | |
} | |
; | |
array_int idxs=new_array_from_c_array(0, 0, sizeof(int), (int[]) { 0 }) ; | |
string rem= s ; | |
int rstart= 0 ; | |
while (1) { | |
int i= string_index( rem , rep ) ; | |
if ( i < 0 ) { | |
break | |
; | |
} | |
; | |
_PUSH(& idxs , ( /*typ = array_int tmp_typ=int*/ rstart + i ), tmp9, int) ; | |
i += rep .len ; | |
rstart += i ; | |
rem = string_substr( rem , i , rem .len ) ; | |
} | |
; | |
if ( idxs .len == 0 ) { | |
return s ; | |
} | |
; | |
int new_len= s .len + idxs .len * ( with .len - rep .len ) ; | |
byte* b= v_malloc ( new_len + 1 ) ; | |
int idx_pos= 0 ; | |
int cur_idx= ( *(int*) array__get( idxs , idx_pos) ) ; | |
int b_i= 0 ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
if ( i == cur_idx ) { | |
for ( | |
int j= 0 ; j < with .len ; j ++ ) { | |
b [/*ptr*/ b_i ]/*rbyte 1*/ = with .str[ j ]/*rbyte 0*/ ; | |
b_i ++ ; | |
} | |
; | |
i += rep .len - 1 ; | |
idx_pos ++ ; | |
if ( idx_pos < idxs .len ) { | |
cur_idx = ( *(int*) array__get( idxs , idx_pos) ) ; | |
} | |
; | |
} | |
else { | |
b [/*ptr*/ b_i ]/*rbyte 1*/ = s .str[ i ]/*rbyte 0*/ ; | |
b_i ++ ; | |
} | |
; | |
} | |
; | |
b [/*ptr*/ new_len ]/*rbyte 1*/ = '\0' ; | |
return tos ( b , new_len ) ; | |
} | |
int v_string_int(string s) { | |
return atoi ( ((char*)( s .str ) ) ) ; | |
} | |
i64 string_i64(string s) { | |
return atoll ( ((char*)( s .str ) ) ) ; | |
} | |
f32 string_f32(string s) { | |
return atof ( ((char*)( s .str ) ) ) ; | |
} | |
f64 string_f64(string s) { | |
return atof ( ((char*)( s .str ) ) ) ; | |
} | |
u32 string_u32(string s) { | |
return strtoul ( ((char*)( s .str ) ) , 0 , 0 ) ; | |
} | |
u64 string_u64(string s) { | |
return strtoull ( ((char*)( s .str ) ) , 0 , 0 ) ; | |
} | |
bool string_eq(string s, string a) { | |
if ( isnil ( s .str ) ) { | |
v_panic ( tos2((byte*)"string.eq(): nil string") ) ; | |
} | |
; | |
if ( s .len != a .len ) { | |
return 0 ; | |
} | |
; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
if ( s .str[ i ]/*rbyte 0*/ != a .str[ i ]/*rbyte 0*/ ) { | |
return 0 ; | |
} | |
; | |
} | |
; | |
return 1 ; | |
} | |
bool string_ne(string s, string a) { | |
return ! string_eq( s , a ) ; | |
} | |
bool string_lt(string s, string a) { | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
if ( i >= a .len || s .str[ i ]/*rbyte 0*/ > a .str[ i ]/*rbyte 0*/ ) { | |
return 0 ; | |
} | |
else if ( s .str[ i ]/*rbyte 0*/ < a .str[ i ]/*rbyte 0*/ ) { | |
return 1 ; | |
} | |
; | |
} | |
; | |
if ( s .len < a .len ) { | |
return 1 ; | |
} | |
; | |
return 0 ; | |
} | |
bool string_le(string s, string a) { | |
return string_lt( s , a ) || string_eq( s , a ) ; | |
} | |
bool string_gt(string s, string a) { | |
return ! string_le( s , a ) ; | |
} | |
bool string_ge(string s, string a) { | |
return ! string_lt( s , a ) ; | |
} | |
string string_add(string s, string a) { | |
int new_len= a .len + s .len ; | |
string res= (string) { .len = new_len , .str = v_malloc ( new_len + 1 ) } ; | |
for ( | |
int j= 0 ; j < s .len ; j ++ ) { | |
res .str[ j ]/*rbyte 1*/ = s .str[ j ]/*rbyte 0*/ ; | |
} | |
; | |
for ( | |
int j= 0 ; j < a .len ; j ++ ) { | |
res .str[ s .len + j ]/*rbyte 1*/ = a .str[ j ]/*rbyte 0*/ ; | |
} | |
; | |
res .str[ new_len ]/*rbyte 1*/ = '\0' ; | |
return res ; | |
} | |
array_string string_split(string s, string delim) { | |
array_string res=new_array_from_c_array(0, 0, sizeof(string), (string[]) { 0 }) ; | |
if ( delim .len == 0 ) { | |
_PUSH(& res , ( /*typ = array_string tmp_typ=string*/ s ), tmp28, string) ; | |
return res ; | |
} | |
; | |
if ( delim .len == 1 ) { | |
return string_split_single( s , delim .str[ 0 ]/*rbyte 0*/ ) ; | |
} | |
; | |
int i= 0 ; | |
int start= 0 ; | |
while ( i < s .len ) { | |
bool a= s .str[ i ]/*rbyte 0*/ == delim .str[ 0 ]/*rbyte 0*/ ; | |
int j= 1 ; | |
while ( j < delim .len && a ) { | |
a = a && s .str[ i + j ]/*rbyte 0*/ == delim .str[ j ]/*rbyte 0*/ ; | |
j ++ ; | |
} | |
; | |
bool last= i == s .len - 1 ; | |
if ( a || last ) { | |
if ( last ) { | |
i ++ ; | |
} | |
; | |
string val= string_substr( s , start , i ) ; | |
if ( val .len > 0 ) { | |
if ( string_starts_with( val , delim ) ) { | |
val = string_right( val , delim .len ) ; | |
} | |
; | |
_PUSH(& res , ( /*typ = array_string tmp_typ=string*/ string_trim_space( val ) ), tmp35, string) ; | |
} | |
; | |
start = i ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return res ; | |
} | |
array_string string_split_single(string s, byte delim) { | |
array_string res=new_array_from_c_array(0, 0, sizeof(string), (string[]) { 0 }) ; | |
if ( ((int)( delim ) ) == 0 ) { | |
_PUSH(& res , ( /*typ = array_string tmp_typ=string*/ s ), tmp37, string) ; | |
return res ; | |
} | |
; | |
int i= 0 ; | |
int start= 0 ; | |
while ( i < s .len ) { | |
bool is_delim= s .str[ i ]/*rbyte 0*/ == delim ; | |
bool last= i == s .len - 1 ; | |
if ( is_delim || last ) { | |
if ( ! is_delim && i == s .len - 1 ) { | |
i ++ ; | |
} | |
; | |
string val= string_substr( s , start , i ) ; | |
if ( val .len > 0 ) { | |
_PUSH(& res , ( /*typ = array_string tmp_typ=string*/ val ), tmp43, string) ; | |
} | |
; | |
start = i + 1 ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return res ; | |
} | |
array_string string_split_into_lines(string s) { | |
array_string res=new_array_from_c_array(0, 0, sizeof(string), (string[]) { 0 }) ; | |
if ( s .len == 0 ) { | |
return res ; | |
} | |
; | |
int start= 0 ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
bool last= i == s .len - 1 ; | |
if ( ((int)( s .str[ i ]/*rbyte 0*/ ) ) == 10 || last ) { | |
if ( last ) { | |
i ++ ; | |
} | |
; | |
string line= string_substr( s , start , i ) ; | |
_PUSH(& res , ( /*typ = array_string tmp_typ=string*/ line ), tmp49, string) ; | |
start = i + 1 ; | |
} | |
; | |
} | |
; | |
return res ; | |
} | |
string string_left(string s, int n) { | |
if ( n >= s .len ) { | |
return s ; | |
} | |
; | |
return string_substr( s , 0 , n ) ; | |
} | |
string string_right(string s, int n) { | |
if ( n >= s .len ) { | |
return tos2((byte*)"") ; | |
} | |
; | |
return string_substr( s , n , s .len ) ; | |
} | |
string string_substr(string s, int start, int end) { | |
if ( start > end || start > s .len || end > s .len || start < 0 || end < 0 ) { | |
v_panic ( _STR("substr(%d, %d) out of bounds (len=%d)", start, end, s .len) ) ; | |
} | |
; | |
int len= end - start ; | |
string res= (string) { .len = len , .str = v_malloc ( len + 1 ) } ; | |
for ( | |
int i= 0 ; i < len ; i ++ ) { | |
res .str [/*ptr*/ i ]/*rbyte 1*/ = s .str [/*ptr*/ start + i ]/*rbyte 0*/ ; | |
} | |
; | |
res .str [/*ptr*/ len ]/*rbyte 1*/ = '\0' ; | |
return res ; | |
} | |
int string_index(string s, string p) { | |
if ( p .len > s .len ) { | |
return - 1 ; | |
} | |
; | |
int i= 0 ; | |
while ( i < s .len ) { | |
int j= 0 ; | |
while ( j < p .len && s .str[ i + j ]/*rbyte 0*/ == p .str[ j ]/*rbyte 0*/ ) { | |
j ++ ; | |
} | |
; | |
if ( j == p .len ) { | |
return i ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return - 1 ; | |
} | |
int string_index_kmp(string s, string p) { | |
if ( p .len > s .len ) { | |
return - 1 ; | |
} | |
; | |
array_int prefix= array_repeat(new_array_from_c_array(1, 1, sizeof(int), (int[]) { 0 }) , p .len ) ; | |
int j= 0 ; | |
for ( | |
int i= 1 ; i < p .len ; i ++ ) { | |
while ( p .str[ j ]/*rbyte 0*/ != p .str[ i ]/*rbyte 0*/ && j > 0 ) { | |
j = ( *(int*) array__get( prefix , j - 1) ) ; | |
} | |
; | |
if ( p .str[ j ]/*rbyte 0*/ == p .str[ i ]/*rbyte 0*/ ) { | |
j ++ ; | |
} | |
; | |
array_set(&/*q*/ prefix , i , & (int []) { j }) ; | |
} | |
; | |
j = 0 ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
while ( p .str[ j ]/*rbyte 0*/ != s .str[ i ]/*rbyte 0*/ && j > 0 ) { | |
j = ( *(int*) array__get( prefix , j - 1) ) ; | |
} | |
; | |
if ( p .str[ j ]/*rbyte 0*/ == s .str[ i ]/*rbyte 0*/ ) { | |
j ++ ; | |
} | |
; | |
if ( j == p .len ) { | |
return i - p .len + 1 ; | |
} | |
; | |
} | |
; | |
return - 1 ; | |
} | |
int string_index_any(string s, string chars) { | |
string tmp63 = chars; | |
array_byte bytes_tmp63 = string_bytes( tmp63 ); | |
; | |
for (int tmp64 = 0; tmp64 < tmp63 .len; tmp64 ++) { | |
byte c = ((byte *) bytes_tmp63 . data)[tmp64]; | |
int index= string_index( s , byte_str( c ) ) ; | |
if ( index != - 1 ) { | |
return index ; | |
} | |
; | |
} | |
; | |
return - 1 ; | |
} | |
int string_last_index(string s, string p) { | |
if ( p .len > s .len ) { | |
return - 1 ; | |
} | |
; | |
int i= s .len - p .len ; | |
while ( i >= 0 ) { | |
int j= 0 ; | |
while ( j < p .len && s .str[ i + j ]/*rbyte 0*/ == p .str[ j ]/*rbyte 0*/ ) { | |
j ++ ; | |
} | |
; | |
if ( j == p .len ) { | |
return i ; | |
} | |
; | |
i -- ; | |
} | |
; | |
return - 1 ; | |
} | |
int string_index_after(string s, string p, int start) { | |
if ( p .len > s .len ) { | |
return - 1 ; | |
} | |
; | |
int strt= start ; | |
if ( start < 0 ) { | |
strt = 0 ; | |
} | |
; | |
if ( start >= s .len ) { | |
return - 1 ; | |
} | |
; | |
int i= strt ; | |
while ( i < s .len ) { | |
int j= 0 ; | |
int ii= i ; | |
while ( j < p .len && s .str[ ii ]/*rbyte 0*/ == p .str[ j ]/*rbyte 0*/ ) { | |
j ++ ; | |
ii ++ ; | |
} | |
; | |
if ( j == p .len ) { | |
return i ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return - 1 ; | |
} | |
int string_count(string s, string substr) { | |
if ( s .len == 0 || substr .len == 0 ) { | |
return 0 ; | |
} | |
; | |
if ( substr .len > s .len ) { | |
return 0 ; | |
} | |
; | |
int n= 0 ; | |
int i= 0 ; | |
while (1) { | |
i = string_index_after( s , substr , i ) ; | |
if ( i == - 1 ) { | |
return n ; | |
} | |
; | |
i += substr .len ; | |
n ++ ; | |
} | |
; | |
return 0 ; | |
} | |
bool string_contains(string s, string p) { | |
bool res= string_index( s , p ) > 0 - 1 ; | |
return res ; | |
} | |
bool string_starts_with(string s, string p) { | |
bool res= string_index( s , p ) == 0 ; | |
return res ; | |
} | |
bool string_ends_with(string s, string p) { | |
if ( p .len > s .len ) { | |
return 0 ; | |
} | |
; | |
bool res= string_last_index( s , p ) == s .len - p .len ; | |
return res ; | |
} | |
string string_to_lower(string s) { | |
byte* b= v_malloc ( s .len + 1 ) ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
b [/*ptr*/ i ]/*rbyte 1*/ = tolower ( s .str [/*ptr*/ i ]/*rbyte 0*/ ) ; | |
} | |
; | |
return tos ( b , s .len ) ; | |
} | |
string string_to_upper(string s) { | |
byte* b= v_malloc ( s .len + 1 ) ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
b [/*ptr*/ i ]/*rbyte 1*/ = toupper ( s .str [/*ptr*/ i ]/*rbyte 0*/ ) ; | |
} | |
; | |
return tos ( b , s .len ) ; | |
} | |
string string_capitalize(string s) { | |
string sl= string_to_lower( s ) ; | |
string cap=string_add( string_to_upper( byte_str( sl .str[ 0 ]/*rbyte 0*/ ) ) , string_right( sl , 1 ) ) ; | |
return cap ; | |
} | |
string string_title(string s) { | |
array_string words= string_split( s , tos2((byte*)" ") ) ; | |
array_string tit=new_array_from_c_array(0, 0, sizeof(string), (string[]) { 0 }) ; | |
array_string tmp85 = words; | |
for (int tmp86 = 0; tmp86 < tmp85.len; tmp86++) { | |
string word = ((string *) tmp85 . data)[tmp86]; | |
_PUSH(& tit , ( /*typ = array_string tmp_typ=string*/ string_capitalize( word ) ), tmp87, string) ; | |
} | |
; | |
string title= array_string_join( tit , tos2((byte*)" ") ) ; | |
return title ; | |
} | |
string string_find_between(string s, string start, string end) { | |
int start_pos= string_index( s , start ) ; | |
if ( start_pos == - 1 ) { | |
return tos2((byte*)"") ; | |
} | |
; | |
string val= string_right( s , start_pos + start .len ) ; | |
int end_pos= string_index( val , end ) ; | |
if ( end_pos == - 1 ) { | |
return val ; | |
} | |
; | |
return string_left( val , end_pos ) ; | |
} | |
bool array_string_contains(array_string ar, string val) { | |
array_string tmp92 = ar; | |
for (int tmp93 = 0; tmp93 < tmp92.len; tmp93++) { | |
string s = ((string *) tmp92 . data)[tmp93]; | |
if (string_eq( s , val ) ) { | |
return 1 ; | |
} | |
; | |
} | |
; | |
return 0 ; | |
} | |
bool array_int_contains(array_int ar, int val) { | |
array_int tmp94 = ar; | |
for (int i = 0; i < tmp94.len; i++) { | |
int s = ((int *) tmp94 . data)[i]; | |
if ( s == val ) { | |
return 1 ; | |
} | |
; | |
} | |
; | |
return 0 ; | |
} | |
bool is_space(byte c) { | |
return _IN(byte, ( c ), new_array_from_c_array(6, 6, sizeof(byte), (byte[]) { ' ' , '\n' , '\t' , '\v' , '\f' , '\r' }) ) ; | |
} | |
bool byte_is_space(byte c) { | |
return is_space ( c ) ; | |
} | |
string string_trim_space(string s) { | |
return string_trim( s , tos2((byte*)" \n\t\v\f\r") ) ; | |
} | |
string string_trim(string s, string cutset) { | |
if ( s .len < 1 || cutset .len < 1 ) { | |
return s ; | |
} | |
; | |
array_byte cs_arr= string_bytes( cutset ) ; | |
int pos_left= 0 ; | |
int pos_right= s .len - 1 ; | |
bool cs_match= 1 ; | |
while ( pos_left <= s .len && pos_right >= - 1 && cs_match ) { | |
cs_match = 0 ; | |
if (_IN(byte, ( s .str[ pos_left ]/*rbyte 0*/ ), cs_arr ) ) { | |
pos_left ++ ; | |
cs_match = 1 ; | |
} | |
; | |
if (_IN(byte, ( s .str[ pos_right ]/*rbyte 0*/ ), cs_arr ) ) { | |
pos_right -- ; | |
cs_match = 1 ; | |
} | |
; | |
if ( pos_left > pos_right ) { | |
return tos2((byte*)"") ; | |
} | |
; | |
} | |
; | |
return string_substr( s , pos_left , pos_right + 1 ) ; | |
} | |
string string_trim_left(string s, string cutset) { | |
if ( s .len < 1 || cutset .len < 1 ) { | |
return s ; | |
} | |
; | |
array_byte cs_arr= string_bytes( cutset ) ; | |
int pos= 0 ; | |
while ( pos <= s .len && _IN(byte, ( s .str[ pos ]/*rbyte 0*/ ), cs_arr ) ) { | |
pos ++ ; | |
} | |
; | |
return string_right( s , pos ) ; | |
} | |
string string_trim_right(string s, string cutset) { | |
if ( s .len < 1 || cutset .len < 1 ) { | |
return s ; | |
} | |
; | |
array_byte cs_arr= string_bytes( cutset ) ; | |
int pos= s .len - 1 ; | |
while ( pos >= - 1 && _IN(byte, ( s .str[ pos ]/*rbyte 0*/ ), cs_arr ) ) { | |
pos -- ; | |
} | |
; | |
return string_left( s , pos + 1 ) ; | |
} | |
int compare_strings(string* a, string* b) { | |
if ( string_lt(* a ,* b ) ) { | |
return - 1 ; | |
} | |
; | |
if ( string_gt(* a ,* b ) ) { | |
return 1 ; | |
} | |
; | |
return 0 ; | |
} | |
int compare_strings_by_len(string* a, string* b) { | |
if ( a ->len < b ->len ) { | |
return - 1 ; | |
} | |
; | |
if ( a ->len > b ->len ) { | |
return 1 ; | |
} | |
; | |
return 0 ; | |
} | |
int compare_lower_strings(string* a, string* b) { | |
string aa= string_to_lower(* a ) ; | |
string bb= string_to_lower(* b ) ; | |
return compare_strings (& /*112 EXP:"string*" GOT:"string" */ aa ,& /*112 EXP:"string*" GOT:"string" */ bb ) ; | |
} | |
void array_string_sort(array_string* s) { | |
array_sort_with_compare( s ,& /*112 EXP:"void*" GOT:"fn (string*,string*) int" */ compare_strings ) ; | |
} | |
void array_string_sort_ignore_case(array_string* s) { | |
array_sort_with_compare( s ,& /*112 EXP:"void*" GOT:"fn (string*,string*) int" */ compare_lower_strings ) ; | |
} | |
void array_string_sort_by_len(array_string* s) { | |
array_sort_with_compare( s ,& /*112 EXP:"void*" GOT:"fn (string*,string*) int" */ compare_strings_by_len ) ; | |
} | |
ustring string_ustring(string s) { | |
ustring res= (ustring) { .s = s , .runes = new_array ( 0 , s .len , sizeof( int) ) , .len = 0 } ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
int char_len= utf8_char_len ( s .str [/*ptr*/ i ]/*rbyte 0*/ ) ; | |
_PUSH(& res .runes , ( /*typ = array_int tmp_typ=int*/ i ), tmp108, int) ; | |
i += char_len - 1 ; | |
res .len ++ ; | |
} | |
; | |
return res ; | |
} | |
ustring string_ustring_tmp(string s) { | |
if ( g_ustring_runes .len == 0 ) { | |
g_ustring_runes = new_array ( 0 , 128 , sizeof( int) ) ; | |
} | |
; | |
ustring res= (ustring) { .s = s , .runes = new_array(0, 1, sizeof( int )) , .len = 0 } ; | |
res .runes = g_ustring_runes ; | |
res .runes .len = s .len ; | |
int j= 0 ; | |
for ( | |
int i= 0 ; i < s .len ; i ++ ) { | |
int char_len= utf8_char_len ( s .str [/*ptr*/ i ]/*rbyte 0*/ ) ; | |
array_set(&/*q*/ res .runes , j , & (int []) { i }) ; | |
j ++ ; | |
i += char_len - 1 ; | |
res .len ++ ; | |
} | |
; | |
return res ; | |
} | |
bool ustring_eq(ustring u, ustring a) { | |
if ( u .len != a .len || string_ne( u .s , a .s ) ) { | |
return 0 ; | |
} | |
; | |
return 1 ; | |
} | |
bool ustring_ne(ustring u, ustring a) { | |
return ! ustring_eq( u , a ) ; | |
} | |
bool ustring_lt(ustring u, ustring a) { | |
return string_lt( u .s , a .s ) ; | |
} | |
bool ustring_le(ustring u, ustring a) { | |
return ustring_lt( u , a ) || ustring_eq( u , a ) ; | |
} | |
bool ustring_gt(ustring u, ustring a) { | |
return ! ustring_le( u , a ) ; | |
} | |
bool ustring_ge(ustring u, ustring a) { | |
return ! ustring_lt( u , a ) ; | |
} | |
ustring ustring_add(ustring u, ustring a) { | |
ustring res= (ustring) { .s = string_add( u .s , a .s ) , .runes = new_array ( 0 , u .s .len + a .s .len , sizeof( int) ) , .len = 0 } ; | |
int j= 0 ; | |
for ( | |
int i= 0 ; i < u .s .len ; i ++ ) { | |
int char_len= utf8_char_len ( u .s .str [/*ptr*/ i ]/*rbyte 0*/ ) ; | |
_PUSH(& res .runes , ( /*typ = array_int tmp_typ=int*/ j ), tmp117, int) ; | |
i += char_len - 1 ; | |
j += char_len ; | |
res .len ++ ; | |
} | |
; | |
for ( | |
int i= 0 ; i < a .s .len ; i ++ ) { | |
int char_len= utf8_char_len ( a .s .str [/*ptr*/ i ]/*rbyte 0*/ ) ; | |
_PUSH(& res .runes , ( /*typ = array_int tmp_typ=int*/ j ), tmp120, int) ; | |
i += char_len - 1 ; | |
j += char_len ; | |
res .len ++ ; | |
} | |
; | |
return res ; | |
} | |
int ustring_index_after(ustring u, ustring p, int start) { | |
if ( p .len > u .len ) { | |
return - 1 ; | |
} | |
; | |
int strt= start ; | |
if ( start < 0 ) { | |
strt = 0 ; | |
} | |
; | |
if ( start > u .len ) { | |
return - 1 ; | |
} | |
; | |
int i= strt ; | |
while ( i < u .len ) { | |
int j= 0 ; | |
int ii= i ; | |
while ( j < p .len && string_eq( ustring_at( u , ii ) , ustring_at( p , j ) ) ) { | |
j ++ ; | |
ii ++ ; | |
} | |
; | |
if ( j == p .len ) { | |
return i ; | |
} | |
; | |
i ++ ; | |
} | |
; | |
return - 1 ; | |
} | |
int ustring_count(ustring u, ustring substr) { | |
if ( u .len == 0 || substr .len == 0 ) { | |
return 0 ; | |
} | |
; | |
if ( substr .len > u .len ) { | |
return 0 ; | |
} | |
; | |
int n= 0 ; | |
int i= 0 ; | |
while (1) { | |
i = ustring_index_after( u , substr , i ) ; | |
if ( i == - 1 ) { | |
return n ; | |
} | |
; | |
i += substr .len ; | |
n ++ ; | |
} | |
; | |
return 0 ; | |
} | |
string ustring_substr(ustring u, int _start, int _end) { | |
if ( _start > _end || _start > u .len || _end > u .len || _start < 0 || _end < 0 ) { | |
v_panic ( _STR("substr(%d, %d) out of bounds (len=%d)", _start, _end, u .len) ) ; | |
} | |
; | |
int end= ( _end >= u .len ) ? ( u .s .len ) : ( ( *(int*) array__get( u .runes , _end) ) ) ; | |
return string_substr( u .s , ( *(int*) array__get( u .runes , _start) ) , end ) ; | |
} | |
string ustring_left(ustring u, int pos) { | |
if ( pos >= u .len ) { | |
return u .s ; | |
} | |
; | |
return ustring_substr( u , 0 , pos ) ; | |
} | |
string ustring_right(ustring u, int pos) { | |
if ( pos >= u .len ) { | |
return tos2((byte*)"") ; | |
} | |
; | |
return ustring_substr( u , pos , u .len ) ; | |
} | |
byte string_at(string s, int idx) { | |
if ( idx < 0 || idx >= s .len ) { | |
v_panic ( _STR("string index out of range: %d / %d", idx, s .len) ) ; | |
} | |
; | |
return s .str [/*ptr*/ idx ]/*rbyte 0*/ ; | |
} | |
string ustring_at(ustring u, int idx) { | |
if ( idx < 0 || idx >= u .len ) { | |
v_panic ( _STR("string index out of range: %d / %d", idx, u .runes .len) ) ; | |
} | |
; | |
return ustring_substr( u , idx , idx + 1 ) ; | |
} | |
void v_ustring_free(ustring u) { | |
v_array_free( u .runes ) ; | |
} | |
bool byte_is_digit(byte c) { | |
return c >= '0' && c <= '9' ; | |
} | |
bool byte_is_hex_digit(byte c) { | |
return byte_is_digit( c ) || ( c >= 'a' && c <= 'f' ) || ( c >= 'A' && c <= 'F' ) ; | |
} | |
bool byte_is_oct_digit(byte c) { | |
return c >= '0' && c <= '7' ; | |
} | |
bool byte_is_letter(byte c) { | |
return ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) ; | |
} | |
void v_string_free(string s) { | |
v_free ( s .str ) ; | |
} | |
string string_all_before(string s, string dot) { | |
int pos= string_index( s , dot ) ; | |
if ( pos == - 1 ) { | |
return s ; | |
} | |
; | |
return string_left( s , pos ) ; | |
} | |
string string_all_before_last(string s, string dot) { | |
int pos= string_last_index( s , dot ) ; | |
if ( pos == - 1 ) { | |
return s ; | |
} | |
; | |
return string_left( s , pos ) ; | |
} | |
string string_all_after(string s, string dot) { | |
int pos= string_last_index( s , dot ) ; | |
if ( pos == - 1 ) { | |
return s ; | |
} | |
; | |
return string_right( s , pos + dot .len ) ; | |
} | |
string array_string_join(array_string a, string del) { | |
if ( a .len == 0 ) { | |
return tos2((byte*)"") ; | |
} | |
; | |
int len= 0 ; | |
array_string tmp136 = a; | |
for (int i = 0; i < tmp136.len; i++) { | |
string val = ((string *) tmp136 . data)[i]; | |
len += val .len + del .len ; | |
} | |
; | |
len -= del .len ; | |
string res= tos2((byte*)"") ; | |
res .len = len ; | |
res .str = v_malloc ( res .len + 1 ) ; | |
int idx= 0 ; | |
array_string tmp139 = a; | |
for (int i = 0; i < tmp139.len; i++) { | |
string val = ((string *) tmp139 . data)[i]; | |
for ( | |
int j= 0 ; j < val .len ; j ++ ) { | |
byte c= val .str[ j ]/*rbyte 0*/ ; | |
res .str [/*ptr*/ idx ]/*rbyte 1*/ = val .str [/*ptr*/ j ]/*rbyte 0*/ ; | |
idx ++ ; | |
} | |
; | |
if ( i != a .len - 1 ) { | |
for ( | |
int k= 0 ; k < del .len ; k ++ ) { | |
res .str [/*ptr*/ idx ]/*rbyte 1*/ = del .str [/*ptr*/ k ]/*rbyte 0*/ ; | |
idx ++ ; | |
} | |
; | |
} | |
; | |
} | |
; | |
res .str [/*ptr*/ res .len ]/*rbyte 1*/ = '\0' ; | |
return res ; | |
} | |
string array_string_join_lines(array_string s) { | |
return array_string_join( s , tos2((byte*)"\n") ) ; | |
} | |
string string_reverse(string s) { | |
string res= (string) { .len = s .len , .str = v_malloc ( s .len ) } ; | |
for ( | |
int i= s .len - 1 ; i >= 0 ; i -- ) { | |
res .str[ s .len - i - 1 ]/*rbyte 1*/ = s .str[ i ]/*rbyte 0*/ ; | |
} | |
; | |
return res ; | |
} | |
string string_limit(string s, int max) { | |
ustring u= string_ustring( s ) ; | |
if ( u .len <= max ) { | |
return s ; | |
} | |
; | |
return ustring_substr( u , 0 , max ) ; | |
} | |
bool byte_is_white(byte c) { | |
int i= ((int)( c ) ) ; | |
return i == 10 || i == 32 || i == 9 || i == 13 || c == '\r' ; | |
} | |
int string_hash(string s) { | |
int h= 0 ; | |
if ( h == 0 && s .len > 0 ) { | |
string tmp148 = s; | |
array_byte bytes_tmp148 = string_bytes( tmp148 ); | |
; | |
for (int tmp149 = 0; tmp149 < tmp148 .len; tmp149 ++) { | |
byte c = ((byte *) bytes_tmp148 . data)[tmp149]; | |
h = h * 31 + ((int)( c ) ) ; | |
} | |
; | |
} | |
; | |
return h ; | |
} | |
array_byte string_bytes(string s) { | |
if ( s .len == 0 ) { | |
return new_array_from_c_array(0, 0, sizeof(byte), (byte[]) { 0 }) ; | |
} | |
; | |
array_byte buf= array_repeat(new_array_from_c_array(1, 1, sizeof(byte), (byte[]) { ((byte)( 0 ) ) }) , s .len ) ; | |
memcpy ( buf .data , (char*) s .str , s .len ) ; | |
return buf ; | |
} | |
string string_repeat(string s, int count) { | |
if ( count <= 1 ) { | |
return s ; | |
} | |
; | |
byte* ret= v_malloc ( s .len * count + 1 ) ; | |
int tmp152 = 0; | |
; | |
for (int tmp153 = tmp152; tmp153 < count; tmp153++) { | |
int i = tmp153; | |
int tmp154 = 0; | |
; | |
for (int tmp155 = tmp154; tmp155 < s .len; tmp155++) { | |
int j = tmp155; | |
ret [/*ptr*/ i * s .len + j ]/*rbyte 1*/ = s .str[ j ]/*rbyte 0*/ ; | |
} | |
; | |
} | |
; | |
ret [/*ptr*/ s .len * count ]/*rbyte 1*/ = 0 ; | |
return (tos2((byte *) ret ) ) ; | |
} | |
void v_exit(int code) { | |
exit ( code ) ; | |
} | |
bool isnil(void* v) { | |
return v == 0 ; | |
} | |
void on_panic(int (*f)( int /*FFF*/ )) { | |
} | |
void print_backtrace_skipping_top_frames(int skipframes) { | |
#ifdef __APPLE__ | |
byte* buffer [100 ] ; | |
int nr_ptrs= backtrace ( ((voidptr*)( buffer ) ) , 100 ) ; | |
backtrace_symbols_fd ( ((voidptr*)( & /*v*/ buffer [ skipframes ]/*rbyte* 0*/ ) ) , nr_ptrs - skipframes , 1 ) ; | |
return ; | |
#endif | |
; | |
#ifdef __linux__ | |
#ifndef __BIONIC__ | |
if ( backtrace_symbols_fd != 0 ) { | |
byte* buffer [100 ] ; | |
int nr_ptrs= backtrace ( ((voidptr*)( buffer ) ) , 100 ) ; | |
backtrace_symbols_fd ( & /*v*/ buffer [ skipframes ]/*rbyte* 0*/ , nr_ptrs - skipframes , 1 ) ; | |
return ; | |
} | |
else { | |
printf ( "backtrace_symbols_fd is missing, so printing backtraces is not available.\n" ) ; | |
printf ( "Some libc implementations like musl simply do not provide it.\n" ) ; | |
} | |
; | |
#endif | |
; | |
#endif | |
; | |
println ( tos2((byte*)"print_backtrace_skipping_top_frames is not implemented on this platform for now...\n") ) ; | |
} | |
void print_backtrace() { | |
print_backtrace_skipping_top_frames ( 2 ) ; | |
} | |
void _panic_debug(int line_no, string file, string mod, string fn_name, string s) { | |
println ( tos2((byte*)"================ V panic ================") ) ; | |
printf( " module: %.*s\n", mod.len, mod.str ) ; | |
printf( " function: %.*s()\n", fn_name.len, fn_name.str ) ; | |
printf( " file: %.*s\n", file.len, file.str ) ; | |
println (string_add( tos2((byte*)" line: ") , int_str( line_no ) ) ) ; | |
printf( " message: %.*s\n", s.len, s.str ) ; | |
println ( tos2((byte*)"=========================================") ) ; | |
print_backtrace_skipping_top_frames ( 1 ) ; | |
exit ( 1 ) ; | |
} | |
void v_panic(string s) { | |
printf( "V panic: %.*s\n", s.len, s.str ) ; | |
print_backtrace ( ) ; | |
exit ( 1 ) ; | |
} | |
void println(string s) { | |
if ( isnil ( s .str ) ) { | |
v_panic ( tos2((byte*)"println(NIL)") ) ; | |
} | |
; | |
#ifdef _WIN32 | |
_putws ( string_to_wide( s ) ) ; | |
#else | |
printf ( "%.*s\n" , s .len , (char*) s .str ) ; | |
#endif | |
; | |
} | |
void eprintln(string s) { | |
if ( isnil ( s .str ) ) { | |
v_panic ( tos2((byte*)"eprintln(NIL)") ) ; | |
} | |
; | |
#ifdef __APPLE__ | |
fprintf ( stderr , "%.*s\n" , s .len , (char*) s .str ) ; | |
fflush ( stderr ) ; | |
return ; | |
#endif | |
; | |
#ifdef __linux__ | |
fprintf ( stderr , "%.*s\n" , s .len , (char*) s .str ) ; | |
fflush ( stderr ) ; | |
return ; | |
#endif | |
; | |
println ( s ) ; | |
} | |
void print(string s) { | |
#ifdef _WIN32 | |
wprintf ( string_to_wide( s ) ) ; | |
#else | |
printf ( "%.*s" , s .len , (char*) s .str ) ; | |
#endif | |
; | |
} | |
byte* v_malloc(int n) { | |
if ( n < 0 ) { | |
v_panic ( tos2((byte*)"malloc(<0)") ) ; | |
} | |
; | |
byte* ptr= malloc ( n ) ; | |
if ( isnil ( ptr ) ) { | |
v_panic ( _STR("malloc(%d) failed", n) ) ; | |
} | |
; | |
return ptr ; | |
} | |
byte* v_calloc(int n) { | |
if ( n < 0 ) { | |
v_panic ( tos2((byte*)"calloc(<0)") ) ; | |
} | |
; | |
return calloc ( n , 1 ) ; | |
} | |
void v_free(void* ptr) { | |
free ( ptr ) ; | |
} | |
void* memdup(void* src, int sz) { | |
byte* mem= v_malloc ( sz ) ; | |
return memcpy ((char*) mem , src , sz ) ; | |
} | |
void v_ptr_free(void* ptr) { | |
free ( ptr ) ; | |
} | |
string f64_str(f64 d) { | |
byte* buf= v_malloc ( sizeof( double) * 5 + 1 ) ; | |
sprintf ( ((char*)( buf ) ) , "%f" , d ) ; | |
return tos ( buf , vstrlen ( buf ) ) ; | |
} | |
string f32_str(f32 d) { | |
byte* buf= v_malloc ( sizeof( double) * 5 + 1 ) ; | |
sprintf ( ((char*)( buf ) ) , "%f" , d ) ; | |
return tos ( buf , vstrlen ( buf ) ) ; | |
} | |
string ptr_str(void* ptr) { | |
byte* buf= v_malloc ( sizeof( double) * 5 + 1 ) ; | |
sprintf ( ((char*)( buf ) ) , "%p" , ptr ) ; | |
return tos ( buf , vstrlen ( buf ) ) ; | |
} | |
bool f64_eq(f64 a, f64 b) { | |
return fabs ( a - b ) <= DBL_EPSILON ; | |
} | |
bool f32_eq(f32 a, f32 b) { | |
return fabsf ( a - b ) <= FLT_EPSILON ; | |
} | |
bool f64_eqbit(f64 a, f64 b) { | |
return DEFAULT_EQUAL ( a , b ) ; | |
} | |
bool f32_eqbit(f32 a, f32 b) { | |
return DEFAULT_EQUAL ( a , b ) ; | |
} | |
string int_str(int nn) { | |
int n= nn ; | |
if ( n == 0 ) { | |
return tos2((byte*)"0") ; | |
} | |
; | |
int max= 16 ; | |
byte* buf= v_calloc ( max ) ; | |
int len= 0 ; | |
bool is_neg= 0 ; | |
if ( n < 0 ) { | |
n = - n ; | |
is_neg = 1 ; | |
} | |
; | |
while ( n > 0 ) { | |
int d= n % 10 ; | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = d + ((int)( '0' ) ) ; | |
len ++ ; | |
n = n / 10 ; | |
} | |
; | |
if ( is_neg ) { | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = '-' ; | |
len ++ ; | |
} | |
; | |
return tos ( buf + max - len , len ) ; | |
} | |
string u32_str(u32 nn) { | |
u32 n= nn ; | |
if ( n == ((u32)( 0 ) ) ) { | |
return tos2((byte*)"0") ; | |
} | |
; | |
int max= 16 ; | |
byte* buf= v_malloc ( max ) ; | |
int len= 0 ; | |
while ( n > ((u32)( 0 ) ) ) { | |
u32 d= n % ((u32)( 10 ) ) ; | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = d + ((u32)( '0' ) ) ; | |
len ++ ; | |
n = n / ((u32)( 10 ) ) ; | |
} | |
; | |
return tos ( buf + max - len , len ) ; | |
} | |
string i64_str(i64 nn) { | |
i64 n= nn ; | |
if ( n == ((i64)( 0 ) ) ) { | |
return tos2((byte*)"0") ; | |
} | |
; | |
int max= 32 ; | |
byte* buf= v_malloc ( max ) ; | |
int len= 0 ; | |
bool is_neg= 0 ; | |
if ( n < ((i64)( 0 ) ) ) { | |
n = - n ; | |
is_neg = 1 ; | |
} | |
; | |
while ( n > ((i64)( 0 ) ) ) { | |
int d= ((int)( n % ((i64)( 10 ) ) ) ) ; | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = d + ((int)( '0' ) ) ; | |
len ++ ; | |
n = n / ((i64)( 10 ) ) ; | |
} | |
; | |
if ( is_neg ) { | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = '-' ; | |
len ++ ; | |
} | |
; | |
return tos ( buf + max - len , len ) ; | |
} | |
string u64_str(u64 nn) { | |
u64 n= nn ; | |
if ( n == ((u64)( 0 ) ) ) { | |
return tos2((byte*)"0") ; | |
} | |
; | |
int max= 32 ; | |
byte* buf= v_malloc ( max ) ; | |
int len= 0 ; | |
while ( n > ((u64)( 0 ) ) ) { | |
u64 d= n % ((u64)( 10 ) ) ; | |
buf [/*ptr*/ max - len - 1 ]/*rbyte 1*/ = d + ((u64)( '0' ) ) ; | |
len ++ ; | |
n = n / ((u64)( 10 ) ) ; | |
} | |
; | |
return tos ( buf + max - len , len ) ; | |
} | |
string bool_str(bool b) { | |
if ( b ) { | |
return tos2((byte*)"true") ; | |
} | |
; | |
return tos2((byte*)"false") ; | |
} | |
string int_hex(int n) { | |
int len= ( n >= 0 ) ? ( int_str( n ) .len + 3 ) : ( 11 ) ; | |
byte* hex= v_malloc ( len ) ; | |
int count= ((int)( sprintf ( ((char*)( hex ) ) , "0x%x" , n ) ) ) ; | |
return tos ( hex , count ) ; | |
} | |
string i64_hex(i64 n) { | |
int len= ( n >= ((i64)( 0 ) ) ) ? ( i64_str( n ) .len + 3 ) : ( 19 ) ; | |
byte* hex= v_malloc ( len ) ; | |
int count= ((int)( sprintf ( ((char*)( hex ) ) , "0x%llx" , n ) ) ) ; | |
return tos ( hex , count ) ; | |
} | |
bool array_byte_contains(array_byte a, byte val) { | |
array_byte tmp32 = a; | |
for (int tmp33 = 0; tmp33 < tmp32.len; tmp33++) { | |
byte aa = ((byte *) tmp32 . data)[tmp33]; | |
if ( aa == val ) { | |
return 1 ; | |
} | |
; | |
} | |
; | |
return 0 ; | |
} | |
string rune_str(rune c) { | |
int fst_byte= ((int)( c ) ) >> 8 * 3 & 0xff ; | |
int len= utf8_char_len ( fst_byte ) ; | |
string str= (string) { .len = len , .str = v_malloc ( len + 1 ) } ; | |
for ( | |
int i= 0 ; i < len ; i ++ ) { | |
str .str [/*ptr*/ i ]/*rbyte 1*/ = ((int)( c ) ) >> 8 * ( 3 - i ) & 0xff ; | |
} | |
; | |
str .str[ len ]/*rbyte 1*/ = '\0' ; | |
return str ; | |
} | |
string byte_str(byte c) { | |
string str= (string) { .len = 1 , .str = v_malloc ( 2 ) } ; | |
str .str [/*ptr*/ 0 ]/*rbyte 1*/ = c ; | |
str .str [/*ptr*/ 1 ]/*rbyte 1*/ = '\0' ; | |
return str ; | |
} | |
bool byte_is_capital(byte c) { | |
return c >= 'A' && c <= 'Z' ; | |
} | |
array_byte array_byte_clone(array_byte b) { | |
array_byte res= array_repeat(new_array_from_c_array(1, 1, sizeof(byte), (byte[]) { ((byte)( 0 ) ) }) , b .len ) ; | |
for ( | |
int i= 0 ; i < b .len ; i ++ ) { | |
array_set(&/*q*/ res , i , & (byte []) { ( *(byte*) array__get( b , i) ) }) ; | |
} | |
; | |
return res ; | |
} | |
int utf8_char_len(byte b) { | |
return ( ( 0xe5000000 >> ( ( b >> 3 ) & 0x1e ) ) & 3 ) + 1 ; | |
} | |
string utf32_to_str(u32 code) { | |
int icode= ((int)( code ) ) ; | |
byte* buffer= v_malloc ( 5 ) ; | |
if ( icode <= 127 ) { | |
buffer [/*ptr*/ 0 ]/*rbyte 1*/ = icode ; | |
return tos ( buffer , 1 ) ; | |
} | |
; | |
if ( ( icode <= 2047 ) ) { | |
buffer [/*ptr*/ 0 ]/*rbyte 1*/ = 192 | ( icode >> 6 ) ; | |
buffer [/*ptr*/ 1 ]/*rbyte 1*/ = 128 | ( icode & 63 ) ; | |
return tos ( buffer , 2 ) ; | |
} | |
; | |
if ( ( icode <= 65535 ) ) { | |
buffer [/*ptr*/ 0 ]/*rbyte 1*/ = 224 | ( icode >> 12 ) ; | |
buffer [/*ptr*/ 1 ]/*rbyte 1*/ = 128 | ( ( icode >> 6 ) & 63 ) ; | |
buffer [/*ptr*/ 2 ]/*rbyte 1*/ = 128 | ( icode & 63 ) ; | |
return tos ( buffer , 3 ) ; | |
} | |
; | |
if ( ( icode <= 1114111 ) ) { | |
buffer [/*ptr*/ 0 ]/*rbyte 1*/ = 240 | ( icode >> 18 ) ; | |
buffer [/*ptr*/ 1 ]/*rbyte 1*/ = 128 | ( ( icode >> 12 ) & 63 ) ; | |
buffer [/*ptr*/ 2 ]/*rbyte 1*/ = 128 | ( ( icode >> 6 ) & 63 ) ; | |
buffer [/*ptr*/ 3 ]/*rbyte 1*/ = 128 | ( icode & 63 ) ; | |
return tos ( buffer , 4 ) ; | |
} | |
; | |
return tos2((byte*)"") ; | |
} | |
string utf32_to_str_no_malloc(u32 code, void* buf) { | |
int icode= ((int)( code ) ) ; | |
byteptr buffer= ((byteptr)( buf ) ) ; | |
if ( icode <= 127 ) { | |
buffer [/*ptr*/ 0 ]/*rbyteptr 1*/ = icode ; | |
return tos ( buffer , 1 ) ; | |
} | |
; | |
if ( ( icode <= 2047 ) ) { | |
buffer [/*ptr*/ 0 ]/*rbyteptr 1*/ = 192 | ( icode >> 6 ) ; | |
buffer [/*ptr*/ 1 ]/*rbyteptr 1*/ = 128 | ( icode & 63 ) ; | |
return tos ( buffer , 2 ) ; | |
} | |
; | |
if ( ( icode <= 65535 ) ) { | |
buffer [/*ptr*/ 0 ]/*rbyteptr 1*/ = 224 | ( icode >> 12 ) ; | |
buffer [/*ptr*/ 1 ]/*rbyteptr 1*/ = 128 | ( ( icode >> 6 ) & 63 ) ; | |
buffer [/*ptr*/ 2 ]/*rbyteptr 1*/ = 128 | ( icode & 63 ) ; | |
return tos ( buffer , 3 ) ; | |
} | |
; | |
if ( ( icode <= 1114111 ) ) { | |
buffer [/*ptr*/ 0 ]/*rbyteptr 1*/ = 240 | ( icode >> 18 ) ; | |
buffer [/*ptr*/ 1 ]/*rbyteptr 1*/ = 128 | ( ( icode >> 12 ) & 63 ) ; | |
buffer [/*ptr*/ 2 ]/*rbyteptr 1*/ = 128 | ( ( icode >> 6 ) & 63 ) ; | |
buffer [/*ptr*/ 3 ]/*rbyteptr 1*/ = 128 | ( icode & 63 ) ; | |
return tos ( buffer , 4 ) ; | |
} | |
; | |
return tos2((byte*)"") ; | |
} | |
int string_utf32_code(string _rune) { | |
if ( _rune .len == 0 ) { | |
return 0 ; | |
} | |
; | |
if ( _rune .len == 1 ) { | |
return ((int)( _rune .str[ 0 ]/*rbyte 0*/ ) ) ; | |
} | |
; | |
byte b= ((byte)( ((int)( _rune .str[ 0 ]/*rbyte 0*/ ) ) ) ) ; | |
b = b << _rune .len ; | |
int res= ((int)( b ) ) ; | |
int shift= 6 - _rune .len ; | |
for ( | |
int i= 1 ; i < _rune .len ; i ++ ) { | |
int c= ((int)( _rune .str[ i ]/*rbyte 0*/ ) ) ; | |
res = res << shift ; | |
res |= c & 63 ; | |
shift = 6 ; | |
} | |
; | |
return res ; | |
} | |
u16* string_to_wide(string _str) { | |
#ifdef _WIN32 | |
int num_chars= ((int)( MultiByteToWideChar ( builtin__CP_UTF8 , 0 , (char*) _str .str , _str .len , 0 , 0 ) ) ) ; | |
u16* wstr= ((u16*)( v_malloc ( ( num_chars + 1 ) * 2 ) ) ) ; | |
if ( wstr > 0 ) { | |
MultiByteToWideChar ( builtin__CP_UTF8 , 0 , (char*) _str .str , _str .len , wstr , num_chars ) ; | |
memset ((char*) ((byte*)( wstr ) ) + num_chars * 2 , 0 , 2 ) ; | |
} | |
; | |
return wstr ; | |
#else | |
return 0 ; | |
#endif | |
; | |
} | |
string string_from_wide(u16* _wstr) { | |
#ifdef _WIN32 | |
int wstr_len= ((int)( wcslen ( _wstr ) ) ) ; | |
return string_from_wide2 ( _wstr , wstr_len ) ; | |
#else | |
return tos2((byte*)"") ; | |
#endif | |
; | |
} | |
string string_from_wide2(u16* _wstr, int len) { | |
#ifdef _WIN32 | |
int num_chars= ((int)( WideCharToMultiByte ( builtin__CP_UTF8 , 0 , _wstr , len , 0 , 0 , 0 , 0 ) ) ) ; | |
byte* str_to= ((byte*)( v_malloc ( num_chars + 1 ) ) ) ; | |
if ( str_to > 0 ) { | |
WideCharToMultiByte ( builtin__CP_UTF8 , 0 , _wstr , len , (char*) str_to , num_chars , 0 , 0 ) ; | |
memset ((char*) ((byte*)( str_to ) ) + num_chars , 0 , 1 ) ; | |
} | |
; | |
return tos2 ( str_to ) ; | |
#else | |
return tos2((byte*)"") ; | |
#endif | |
; | |
} | |
int utf8_len(byte c) { | |
int b= 0 ; | |
byte x= c ; | |
if ( ( ( x & 240 ) != 0 ) ) { | |
x >>= 4 ; | |
} | |
else { | |
b += 4 ; | |
} | |
; | |
if ( ( ( x & 12 ) != 0 ) ) { | |
x >>= 2 ; | |
} | |
else { | |
b += 2 ; | |