From 79a8041aacc7abe3e5fe226f074e4d5e514c4d5c Mon Sep 17 00:00:00 2001 From: Max Wash Date: Mon, 25 May 2026 17:20:15 +0100 Subject: [PATCH] fx: add wstr and wchar value types --- fx/cstr.h | 35 +++++ fx/include/fx/wstr.h | 32 ++++ fx/wchar.c | 257 ++++++++++++++++++++++++++++++++ fx/wstr.c | 341 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 665 insertions(+) create mode 100644 fx/cstr.h create mode 100644 fx/include/fx/wstr.h create mode 100644 fx/wchar.c create mode 100644 fx/wstr.c diff --git a/fx/cstr.h b/fx/cstr.h new file mode 100644 index 0000000..51b5613 --- /dev/null +++ b/fx/cstr.h @@ -0,0 +1,35 @@ +#ifndef CSTR_H_ +#define CSTR_H_ + +#include +#include + +extern fx_status cstr_to_char(const char *in, fx_wchar *out); + +extern fx_status cstr_to_bool(const char *in, bool *out); +extern fx_status cstr_to_i16(const char *in, i16 *out); +extern fx_status cstr_to_u16(const char *in, u16 *out); +extern fx_status cstr_to_i32(const char *in, i32 *out); +extern fx_status cstr_to_u32(const char *in, u32 *out); +extern fx_status cstr_to_i64(const char *in, i64 *out); +extern fx_status cstr_to_u64(const char *in, u64 *out); +extern fx_status cstr_to_iptr(const char *in, iptr *out); +extern fx_status cstr_to_uptr(const char *in, uptr *out); + +extern fx_status cstr_to_sbyte(const char *in, sbyte *out); +extern fx_status cstr_to_byte(const char *in, byte *out); +extern fx_status cstr_to_short(const char *in, short *out); +extern fx_status cstr_to_ushort(const char *in, unsigned short *out); +extern fx_status cstr_to_int(const char *in, int *out); +extern fx_status cstr_to_uint(const char *in, unsigned int *out); +extern fx_status cstr_to_long(const char *in, long *out); +extern fx_status cstr_to_ulong(const char *in, unsigned long *out); +extern fx_status cstr_to_longlong(const char *in, long long *out); +extern fx_status cstr_to_ulonglong(const char *in, unsigned long long *out); +extern fx_status cstr_to_size(const char *in, size_t *out); + +extern fx_status cstr_to_float(const char *in, float *out); +extern fx_status cstr_to_double(const char *in, double *out); +extern fx_status cstr_to_cstr(const char *in, const char **out); + +#endif diff --git a/fx/include/fx/wstr.h b/fx/include/fx/wstr.h new file mode 100644 index 0000000..3e42396 --- /dev/null +++ b/fx/include/fx/wstr.h @@ -0,0 +1,32 @@ +#ifndef FX_WSTR_H_ +#define FX_WSTR_H_ + +#include +#include + +FX_DECLS_BEGIN; + +#define FX_TYPE_WCHAR (fx_wchar_get_type()) +#define FX_TYPE_WSTR (fx_wstr_get_type()) + +typedef struct _fx_wchar_class fx_wchar_class; +typedef struct _fx_wstr_class fx_wstr_class; + +FX_TYPE_CLASS_DECLARATION_BEGIN(fx_wchar) +FX_TYPE_CLASS_DECLARATION_END(fx_wchar) + +FX_TYPE_CLASS_DECLARATION_BEGIN(fx_wstr) +FX_TYPE_CLASS_DECLARATION_END(fx_wstr) + +FX_API fx_type_id fx_wchar_get_type(void); +FX_API fx_type_id fx_wstr_get_type(void); + +FX_API int fx_wstrcmp(const fx_wchar *a, const fx_wchar *b); +FX_API int fx_wastrcmp(const char *a, const fx_wchar *b); +FX_API fx_wchar *fx_wstrdup(const fx_wchar *s); +FX_API size_t fx_wstrlen(const fx_wchar *s); +FX_API size_t fx_wstrcspn(const fx_wchar *dest, const fx_wchar *src); + +FX_DECLS_END; + +#endif diff --git a/fx/wchar.c b/fx/wchar.c new file mode 100644 index 0000000..706fd2b --- /dev/null +++ b/fx/wchar.c @@ -0,0 +1,257 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static fx_status to_string( + const fx_value *v, + fx_stream *out, + const char *format) +{ + const fx_wchar s[] = {v->v_wchar, 0}; + return fx_stream_write_wstr(out, s, NULL); +} + +static i32 compare(const fx_value *left, const fx_value *right) +{ + fx_wchar s; + if (!FX_OK(fx_value_get_wchar(right, &s))) { + return -1; + } + + return memcmp(&left->v_wchar, &s, sizeof s); +} + +static fx_status hash(const fx_value *v, uint64_t *out_hash) +{ + *out_hash = v->v_wchar; + return FX_SUCCESS; +} + +fx_status wchar_to_char(fx_wchar in, fx_wchar *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_bool(fx_wchar in, bool *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_i16(fx_wchar in, i16 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_u16(fx_wchar in, u16 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_i32(fx_wchar in, i32 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_u32(fx_wchar in, u32 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_i64(fx_wchar in, i64 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_u64(fx_wchar in, u64 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_iptr(fx_wchar in, iptr *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_uptr(fx_wchar in, uptr *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_sbyte(fx_wchar in, sbyte *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_byte(fx_wchar in, byte *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_short(fx_wchar in, short *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_ushort(fx_wchar in, unsigned short *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_int(fx_wchar in, int *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_uint(fx_wchar in, unsigned int *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_long(fx_wchar in, long *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_ulong(fx_wchar in, unsigned long *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_longlong(fx_wchar in, long long *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_ulonglong(fx_wchar in, unsigned long long *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_size(fx_wchar in, size_t *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_float(fx_wchar in, float *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_double(fx_wchar in, double *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wchar_to_wchar(fx_wchar in, fx_wchar *out) +{ + *out = in; + return FX_SUCCESS; +} + +#define WCHAR_CONVERTER(fx_type, c_type) \ + static fx_status to_##fx_type(const fx_value *in, c_type *out) \ + { \ + fx_wchar s = FX_WCHAR_INVALID; \ + fx_value_get_wchar(in, &s); \ + return wchar_to_##fx_type(s, out); \ + } + +WCHAR_CONVERTER(bool, bool) +WCHAR_CONVERTER(i16, i16) +WCHAR_CONVERTER(u16, u16) +WCHAR_CONVERTER(i32, i32) +WCHAR_CONVERTER(u32, u32) +WCHAR_CONVERTER(i64, i64) +WCHAR_CONVERTER(u64, u64) +WCHAR_CONVERTER(iptr, iptr) +WCHAR_CONVERTER(uptr, uptr) +WCHAR_CONVERTER(sbyte, sbyte) +WCHAR_CONVERTER(byte, byte) +WCHAR_CONVERTER(short, short) +WCHAR_CONVERTER(ushort, unsigned short) +WCHAR_CONVERTER(int, int) +WCHAR_CONVERTER(uint, unsigned int) +WCHAR_CONVERTER(long, long) +WCHAR_CONVERTER(ulong, unsigned long) +WCHAR_CONVERTER(longlong, long long) +WCHAR_CONVERTER(ulonglong, unsigned long long) +WCHAR_CONVERTER(size, size_t) +WCHAR_CONVERTER(float, float) +WCHAR_CONVERTER(double, double) + +static fx_status add(const fx_value *l, const fx_value *r, fx_value *out) +{ + fx_wchar left = l->v_wchar; + fx_wchar right = r->v_wchar; + fx_string *result = fx_string_create(); + if (!result) { + return FX_ERR_NO_MEMORY; + } + + fx_string_append_wc(result, left); + fx_string_append_wc(result, right); + *out = FX_VALUE_OBJECT(result); + + return FX_SUCCESS; +} + +/*** CLASS DEFINITION *********************************************************/ + +FX_TYPE_CLASS_BEGIN(fx_wchar) + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) + FX_INTERFACE_ENTRY(to_string) = to_string; + FX_INTERFACE_ENTRY(hash) = hash; + FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT) + + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_operable, FX_TYPE_OPERABLE) + FX_INTERFACE_ENTRY(op_add) = add; + FX_TYPE_VTABLE_INTERFACE_END(fx_operable, FX_TYPE_OPERABLE) + + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_comparable, FX_TYPE_COMPARABLE) + FX_INTERFACE_ENTRY(c_compare) = compare; + FX_TYPE_VTABLE_INTERFACE_END(fx_comparable, FX_TYPE_COMPARABLE) + + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_convertible, FX_TYPE_CONVERTIBLE) + FX_INTERFACE_ENTRY(c_to_bool) = to_bool; + FX_INTERFACE_ENTRY(c_to_bool) = to_bool; + FX_INTERFACE_ENTRY(c_to_i16) = to_i16; + FX_INTERFACE_ENTRY(c_to_u16) = to_u16; + FX_INTERFACE_ENTRY(c_to_u32) = to_u32; + FX_INTERFACE_ENTRY(c_to_i64) = to_i64; + FX_INTERFACE_ENTRY(c_to_u64) = to_u64; + FX_INTERFACE_ENTRY(c_to_iptr) = to_iptr; + FX_INTERFACE_ENTRY(c_to_uptr) = to_uptr; + FX_INTERFACE_ENTRY(c_to_sbyte) = to_sbyte; + FX_INTERFACE_ENTRY(c_to_byte) = to_byte; + FX_INTERFACE_ENTRY(c_to_short) = to_short; + FX_INTERFACE_ENTRY(c_to_ushort) = to_ushort; + FX_INTERFACE_ENTRY(c_to_int) = to_int; + FX_INTERFACE_ENTRY(c_to_uint) = to_uint; + FX_INTERFACE_ENTRY(c_to_long) = to_long; + FX_INTERFACE_ENTRY(c_to_ulong) = to_ulong; + FX_INTERFACE_ENTRY(c_to_longlong) = to_longlong; + FX_INTERFACE_ENTRY(c_to_ulonglong) = to_ulonglong; + FX_INTERFACE_ENTRY(c_to_size) = to_size; + FX_INTERFACE_ENTRY(c_to_float) = to_float; + FX_INTERFACE_ENTRY(c_to_double) = to_double; + FX_TYPE_VTABLE_INTERFACE_END(fx_convertible, FX_TYPE_CONVERTIBLE) +FX_TYPE_CLASS_END(fx_wchar) + +FX_TYPE_DEFINITION_BEGIN(fx_wchar) + __FX_VALUE_TYPE_ID(WCHAR); + FX_TYPE_EXTENDS(FX_TYPE_VALUE_TYPE); + FX_TYPE_IMPLEMENTS(FX_TYPE_CONVERTIBLE); + FX_TYPE_IMPLEMENTS(FX_TYPE_OPERABLE); + FX_TYPE_IMPLEMENTS(FX_TYPE_COMPARABLE); + FX_TYPE_NAME("fx.wchar"); + FX_TYPE_CLASS(fx_wchar_class); + FX_TYPE_INSTANCE_PRIVATE(char *); +FX_TYPE_DEFINITION_END(fx_wchar) diff --git a/fx/wstr.c b/fx/wstr.c new file mode 100644 index 0000000..1120525 --- /dev/null +++ b/fx/wstr.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static fx_status to_string( + const fx_value *v, + fx_stream *out, + const char *format) +{ + return fx_stream_write_fmt(out, NULL, "%s", v->v_wstr); +} + +static i32 compare(const fx_value *left, const fx_value *right) +{ + const fx_wchar *s; + if (!FX_OK(fx_value_get_wstr(right, &s))) { + return -1; + } + + return fx_wstrcmp(left->v_wstr, s); +} + +static fx_status hash(const fx_value *v, uint64_t *out_hash) +{ + *out_hash = fx_hash_wstr(v->v_wstr); + return FX_SUCCESS; +} + +fx_status wstr_to_char(const fx_wchar *in, fx_wchar *out) +{ + if (in[0] == '\0' || in[1] == '\0') { + *out = in[0]; + return FX_SUCCESS; + } + + return FX_ERR_BAD_STATE; +} + +fx_status wstr_to_bool(const fx_wchar *in, bool *out) +{ + if (!fx_wstrcmp(in, L"1") || !fx_wstrcmp(in, L"true") + || fx_wstrcmp(in, L"True")) { + *out = true; + return FX_SUCCESS; + } else if ( + !fx_wstrcmp(in, L"0") || !fx_wstrcmp(in, L"false") + || fx_wstrcmp(in, L"False")) { + *out = false; + return FX_SUCCESS; + } + + return FX_ERR_BAD_STATE; +} + +fx_status wstr_to_i16(const fx_wchar *in, i16 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_u16(const fx_wchar *in, u16 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_i32(const fx_wchar *in, i32 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_u32(const fx_wchar *in, u32 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_i64(const fx_wchar *in, i64 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_u64(const fx_wchar *in, u64 *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_iptr(const fx_wchar *in, iptr *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_uptr(const fx_wchar *in, uptr *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_sbyte(const fx_wchar *in, sbyte *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_byte(const fx_wchar *in, byte *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_short(const fx_wchar *in, short *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_ushort(const fx_wchar *in, unsigned short *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_int(const fx_wchar *in, int *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_uint(const fx_wchar *in, unsigned int *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_long(const fx_wchar *in, long *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_ulong(const fx_wchar *in, unsigned long *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_longlong(const fx_wchar *in, long long *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_ulonglong(const fx_wchar *in, unsigned long long *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_size(const fx_wchar *in, size_t *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_float(const fx_wchar *in, float *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_double(const fx_wchar *in, double *out) +{ + return FX_ERR_NOT_SUPPORTED; +} + +fx_status wstr_to_wstr(const fx_wchar *in, const fx_wchar **out) +{ + *out = in; + return FX_SUCCESS; +} + +#define WSTR_CONVERTER(fx_type, c_type) \ + static fx_status to_##fx_type(const fx_value *in, c_type *out) \ + { \ + const fx_wchar *s = NULL; \ + fx_value_get_wstr(in, &s); \ + return wstr_to_##fx_type(s, out); \ + } + +WSTR_CONVERTER(bool, bool) +WSTR_CONVERTER(i16, i16) +WSTR_CONVERTER(u16, u16) +WSTR_CONVERTER(i32, i32) +WSTR_CONVERTER(u32, u32) +WSTR_CONVERTER(i64, i64) +WSTR_CONVERTER(u64, u64) +WSTR_CONVERTER(iptr, iptr) +WSTR_CONVERTER(uptr, uptr) +WSTR_CONVERTER(sbyte, sbyte) +WSTR_CONVERTER(byte, byte) +WSTR_CONVERTER(short, short) +WSTR_CONVERTER(ushort, unsigned short) +WSTR_CONVERTER(int, int) +WSTR_CONVERTER(uint, unsigned int) +WSTR_CONVERTER(long, long) +WSTR_CONVERTER(ulong, unsigned long) +WSTR_CONVERTER(longlong, long long) +WSTR_CONVERTER(ulonglong, unsigned long long) +WSTR_CONVERTER(size, size_t) +WSTR_CONVERTER(float, float) +WSTR_CONVERTER(double, double) +WSTR_CONVERTER(wstr, const fx_wchar *) + +static fx_status add(const fx_value *l, const fx_value *r, fx_value *out) +{ + const fx_wchar *left = l->v_wstr; + const fx_wchar *right = r->v_wstr; + fx_string *result = fx_string_create(); + if (!result) { + return FX_ERR_NO_MEMORY; + } + + fx_string_append_wstr(result, left); + fx_string_append_wstr(result, right); + *out = FX_VALUE_OBJECT(result); + + return FX_SUCCESS; +} + +/*** CLASS DEFINITION *********************************************************/ + +FX_TYPE_CLASS_BEGIN(fx_wstr) + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_object, FX_TYPE_OBJECT) + FX_INTERFACE_ENTRY(to_string) = to_string; + FX_INTERFACE_ENTRY(hash) = hash; + FX_TYPE_VTABLE_INTERFACE_END(fx_object, FX_TYPE_OBJECT) + + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_operable, FX_TYPE_OPERABLE) + FX_INTERFACE_ENTRY(op_add) = add; + FX_TYPE_VTABLE_INTERFACE_END(fx_operable, FX_TYPE_OPERABLE) + + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_comparable, FX_TYPE_COMPARABLE) + FX_INTERFACE_ENTRY(c_compare) = compare; + FX_TYPE_VTABLE_INTERFACE_END(fx_comparable, FX_TYPE_COMPARABLE) + + FX_TYPE_VTABLE_INTERFACE_BEGIN(fx_convertible, FX_TYPE_CONVERTIBLE) + FX_INTERFACE_ENTRY(c_to_bool) = to_bool; + FX_INTERFACE_ENTRY(c_to_bool) = to_bool; + FX_INTERFACE_ENTRY(c_to_i16) = to_i16; + FX_INTERFACE_ENTRY(c_to_u16) = to_u16; + FX_INTERFACE_ENTRY(c_to_u32) = to_u32; + FX_INTERFACE_ENTRY(c_to_i64) = to_i64; + FX_INTERFACE_ENTRY(c_to_u64) = to_u64; + FX_INTERFACE_ENTRY(c_to_iptr) = to_iptr; + FX_INTERFACE_ENTRY(c_to_uptr) = to_uptr; + FX_INTERFACE_ENTRY(c_to_sbyte) = to_sbyte; + FX_INTERFACE_ENTRY(c_to_byte) = to_byte; + FX_INTERFACE_ENTRY(c_to_short) = to_short; + FX_INTERFACE_ENTRY(c_to_ushort) = to_ushort; + FX_INTERFACE_ENTRY(c_to_int) = to_int; + FX_INTERFACE_ENTRY(c_to_uint) = to_uint; + FX_INTERFACE_ENTRY(c_to_long) = to_long; + FX_INTERFACE_ENTRY(c_to_ulong) = to_ulong; + FX_INTERFACE_ENTRY(c_to_longlong) = to_longlong; + FX_INTERFACE_ENTRY(c_to_ulonglong) = to_ulonglong; + FX_INTERFACE_ENTRY(c_to_size) = to_size; + FX_INTERFACE_ENTRY(c_to_float) = to_float; + FX_INTERFACE_ENTRY(c_to_double) = to_double; + FX_TYPE_VTABLE_INTERFACE_END(fx_convertible, FX_TYPE_CONVERTIBLE) +FX_TYPE_CLASS_END(fx_wstr) + +FX_TYPE_DEFINITION_BEGIN(fx_wstr) + __FX_VALUE_TYPE_ID(WSTR); + FX_TYPE_EXTENDS(FX_TYPE_VALUE_TYPE); + FX_TYPE_IMPLEMENTS(FX_TYPE_CONVERTIBLE); + FX_TYPE_IMPLEMENTS(FX_TYPE_OPERABLE); + FX_TYPE_IMPLEMENTS(FX_TYPE_COMPARABLE); + FX_TYPE_NAME("fx.wstr"); + FX_TYPE_CLASS(fx_wstr_class); + FX_TYPE_INSTANCE_PRIVATE(char *); +FX_TYPE_DEFINITION_END(fx_wstr) + +/*** MISC FUNCTIONS ***********************************************************/ + +int fx_wstrcmp(const fx_wchar *a, const fx_wchar *b) +{ + int i; + for (i = 0; a[i] == b[i]; i++) + if (a[i] == '\0') + return 0; + + return a[i] - b[i]; +} + +int fx_wastrcmp(const char *a, const fx_wchar *b) +{ + while (1) { + fx_wchar ch_a = fx_wchar_utf8_codepoint_decode(a); + fx_wchar ch_b = *b; + + if (!ch_a && !ch_b) { + break; + } + + if (ch_a != ch_b) { + return ch_a - ch_b; + } + + a += fx_wchar_utf8_codepoint_stride(a); + b++; + } + + return 0; +} + +fx_wchar *fx_wstrdup(const fx_wchar *s) +{ + size_t len = fx_wstrlen(s); + fx_wchar *buf = calloc(len + 1, sizeof(fx_wchar)); + if (!buf) { + return NULL; + } + + memcpy(buf, s, len * sizeof(fx_wchar)); + + return buf; +} + +size_t fx_wstrlen(const fx_wchar *s) +{ + size_t len; + for (len = 0; s[len] != 0; len++) + ; + return len; +} + +size_t fx_wstrcspn(const fx_wchar *dest, const fx_wchar *src) +{ + size_t i = 0; + for (i = 0; dest[i]; i++) { + for (size_t ii = 0; src[ii]; ii++) { + if (dest[i] == src[ii]) { + return i; + } + } + } + + return i; +}