Commit 61b200b
Changed files (3)
testing/tests/016_strings_and_slices.c
@@ -0,0 +1,93 @@
+#include "notlibc.c"
+
+void entry(void) {
+ STRING( hackunana, "hackunana" );
+ STRING( hack, "hack" );
+ STRING( hack2, "hack" );
+ STRING( una, "una" );
+
+ Arena a = {0};
+ Heap h = {0};
+ assert(S_OK( Arena_create( &a, KiB(4) ) ));
+ assert(S_OK( Heap_create( &h, KiB(4) ) ));
+
+ StrSlc hack_slc = {0};
+ assert(S_OK( StrSlc_from_Str( &hack_slc, (const Str*)&hack, 0, hack.len ) ));
+ assert( StrSlc_equals( hack_slc, hack_slc ) == 1);
+ assert( StrSlc_equals_by_ref( &hack_slc, &hack_slc ) == 1);
+
+ assert(S_OK( StrSlc_equals_Str( hack_slc, (const Str*)&hack ) ));
+ assert(S_OK( StrSlc_equals_Str_by_ref( &hack_slc, (const Str*)&hack ) ));
+
+ StrSlc hack2_slc = {0};
+ assert(S_OK( StrSlc_from_Str( &hack2_slc, (const Str*)&hack2, 0, hack.len ) ));
+ assert( StrSlc_equals( hack_slc, hack2_slc ) == 1);
+ assert( StrSlc_equals_by_ref( &hack_slc, &hack2_slc ) == 1);
+
+ StrSlc na_slc = {0};
+ assert(S_OK( StrSlc_from_Str( &na_slc, (const Str*)&una, 1, una.len - 1 ) ));
+
+ StrAsm sa = {0};
+ assert( S_OK( StrAsm_create( &sa, KiB(4) ) ));
+
+
+ assert( S_OK( StrAsm_cat_Str( &sa, (const Str*)&hack ) ));
+ assert( S_OK( StrAsm_cat_char( &sa, 'u' ) ));
+ assert( S_OK( StrAsm_cat_StrSlc( &sa, na_slc ) ) );
+ assert( S_OK( StrAsm_cat_StrSlc_by_ref( &sa, &na_slc ) ) );
+
+ Str *s_a = 0;
+ Str *s_h = 0;
+
+ assert( S_OK( StrAsm_store_into_arena( &sa, &a, &s_a ) ) );
+ assert( S_OK( StrAsm_store_onto_heap( &sa, &h, &s_h ) ) );
+
+ assert( Str_equals( s_a, s_h ) == 1 );
+ assert( Str_equals( s_a, (const Str*)&hackunana ) == 1);
+ assert( Str_equals( s_h, (const Str*)&hackunana ) == 1);
+
+ Heap_free( &h, (void**)&s_h );
+
+ assert( S_OK( StrAsm_reset( &sa ) ) );
+
+ STRING( numbers_hex, "0xfe" "0xffff" "0xffffffff" "0xffffffffffffffff" );
+ assert( S_OK( StrAsm_fmtx_u8( &sa, 0xfe ) ) );
+ assert( S_OK( StrAsm_fmtx_u16( &sa, 0xffff ) ) );
+ assert( S_OK( StrAsm_fmtx_u32( &sa, 0xffffffff) ) );
+ assert( S_OK( StrAsm_fmtx_u64( &sa, 0xffffffffffffffff ) ) );
+
+ assert( S_OK( StrAsm_store_onto_heap( &sa, &h, &s_h ) ) );
+ assert( Str_equals( s_h, (const Str*)&numbers_hex ) == 1 );
+ Heap_free( &h, (void**)&s_h );
+
+ assert( S_OK( StrAsm_reset( &sa ) ) );
+
+ STRING( numbers_dec, "255" "65535" "4294967295" "18446744073709551615" );
+ assert( S_OK( StrAsm_fmtd_u8( &sa, 255 ) ) );
+ assert( S_OK( StrAsm_fmtd_u16( &sa, 65535 ) ) );
+ assert( S_OK( StrAsm_fmtd_u32( &sa, 4294967295) ) );
+ assert( S_OK( StrAsm_fmtd_u64( &sa, 18446744073709551615u ) ) );
+
+ assert( S_OK( StrAsm_store_onto_heap( &sa, &h, &s_h ) ) );
+ assert( Str_equals( s_h, (const Str*)&numbers_dec ) == 1 );
+ Heap_free( &h, (void**)&s_h );
+
+ assert( S_OK( StrAsm_reset( &sa ) ) );
+
+ STRING( numbers_dec_s, "-128" "-32768" "-2147483648" "-9223372036854775808" );
+ assert( S_OK( StrAsm_fmtd_s8( &sa, -128 ) ) );
+ assert( S_OK( StrAsm_fmtd_s16( &sa, -32768 ) ) );
+ assert( S_OK( StrAsm_fmtd_s32( &sa, -2147483648 ) ) );
+ assert( S_OK( StrAsm_fmtd_s64( &sa, -9223372036854775807LL - 1 ) ) );
+
+ assert( S_OK( StrAsm_store_onto_heap( &sa, &h, &s_h ) ) );
+ assert( Str_equals( s_h, (const Str*)&numbers_dec_s ) == 1 );
+ Heap_free( &h, (void**)&s_h );
+
+ assert( S_OK( StrAsm_destroy( &sa ) ));
+ assert( S_OK( Arena_destroy( &a ) ));
+ assert( S_OK( Heap_destroy( &h ) ));
+
+
+ terminate(0);
+}
notlibc.c
@@ -576,6 +576,321 @@ Status AnyArr_dup( const AnyArr *arr, AnyArr **out_arr, Heap *h, usize elem_size
return S_SUCCESS;
}
+/*================================= String ===================================*/
+
+u8 Str_equals( const Str *s1, const Str *s2 ) {
+ if( s1->len != s2->len ) return 0;
+
+ for( usize i = 0; i < s1->len; ++i ) {
+ if( s1->data[i] != s2->data[i] ) return 0;
+ }
+ return 1;
+}
+
+Status StrSlc_from_Str( StrSlc *out, const Str *s, usize start, usize len ) {
+ if( start > s->len ) {
+ DEBUG( assert(0) );
+ return S_FAILURE | ERR_OUT_OF_BOUND | ERRSRC_ARG_3;
+ }
+
+ if( s->len >= len && s->len - len < start ) {
+ DEBUG( assert(0) );
+ return S_FAILURE | ERR_OUT_OF_BOUND | ERRSRC_ARG_3;
+ }
+
+ out->data = &s->data[start];
+ out->len = len;
+
+ return S_SUCCESS;
+}
+
+u8 StrSlc_equals( const StrSlc sl1, const StrSlc sl2 ) {
+ if( sl1.len != sl2.len ) {
+ return 0;
+ }
+
+ if( sl1.data == sl2.data ) return 1; /* If the pointers are the same
+ the data has got to be the same */
+
+ for( usize i = 0; i < sl1.len; ++i ) {
+ if( sl1.data[i] != sl2.data[i] ) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+u8 StrSlc_equals_by_ref( const StrSlc *sl1, const StrSlc *sl2 ) {
+ if( sl1->len != sl2->len ) {
+ return 0;
+ }
+
+ if( sl1->data == sl2->data ) return 1;
+
+ for( usize i = 0; i < sl1->len; ++i ) {
+ if( sl1->data[i] != sl2->data[i] ) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+
+u8 StrSlc_equals_Str( const StrSlc sl, const Str* s ) {
+ if( sl.len != s->len ) {
+ return 0;
+ }
+
+ for( usize i = 0; i < sl.len; ++i ) {
+ if( sl.data[i] != s->data[i] ) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+u8 StrSlc_equals_Str_by_ref( const StrSlc *sl, const Str *s ) {
+ if( sl->len != s->len ) {
+ return 0;
+ }
+
+ for( usize i = 0; i < sl->len; ++i ) {
+ if( sl->data[i] != s->data[i] ) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* String Assembler */
+
+Status StrAsm_create( StrAsm *out, usize max_size ) {
+ return Arena_create( &out->a, max_size );
+}
+
+Status StrAsm_reset( StrAsm *out ) {
+ return Arena_give( &out->a, out->a.taken );
+}
+
+Status StrAsm_destroy( StrAsm *out ) {
+ return Arena_destroy( &out->a );
+}
+
+Status StrAsm_store_into_arena( StrAsm *sa, Arena *dst, Str **out ) {
+ usize len = sa->a.taken;
+
+ #if OS != OS_NONE
+ len++;
+ #endif
+
+ u8 *p = 0;
+ TRY( Arena_take( dst, len, &p ) );
+
+ #if OS != OS_NONE
+ p[len] = 0; /* We need the NUL in case this string is used in a syscall
+ - it has to be an actual string */
+ #endif
+
+ *out = (Str*)p;
+
+ #if OS != OS_NONE
+ (*out)->len = len - 1;
+ #else
+ (*out)->len = len;
+ #endif
+
+ mem_copy( sa->a.start, &(*out)->data, len );
+
+ return S_SUCCESS;
+}
+
+Status StrAsm_store_onto_heap( StrAsm *sa, Heap *dst, Str **out ) {
+ usize len = sa->a.taken;
+
+ #if OS != OS_NONE
+ len++;
+ #endif
+
+ void *p = 0;
+ TRY( Heap_alloc( dst, len, &p ) );
+
+ #if OS != OS_NONE
+ ((u8*)p)[len] = 0;
+ #endif
+
+ *out = (Str*)p;
+
+ #if OS != OS_NONE
+ (*out)->len = len - 1;
+ #else
+ (*out)->len = len;
+ #endif
+
+ mem_copy( sa->a.start, &(*out)->data, len );
+
+ return S_SUCCESS;
+}
+
+Status StrAsm_cat_char ( StrAsm *sa, u8 value ) {
+ u8 *data = 0;
+ TRY( Arena_take( &sa->a, sizeof(value), &data ) );
+ *data = value;
+ return S_SUCCESS;
+}
+
+Status StrAsm_cat_Str( StrAsm *sa, const Str *s ) {
+ u8 *data = 0;
+ TRY( Arena_take( &sa->a, s->len, &data ) );
+ mem_copy( &s->data, data, s->len );
+ return S_SUCCESS;
+}
+
+Status StrAsm_cat_StrSlc( StrAsm *sa, StrSlc sl ) {
+ u8 *data = 0;
+ TRY( Arena_take( &sa->a, sl.len, &data ) );
+ mem_copy( sl.data, data, sl.len );
+ return S_SUCCESS;
+}
+
+Status StrAsm_cat_StrSlc_by_ref( StrAsm *sa, const StrSlc *sl ) {
+ u8 *data = 0;
+ TRY( Arena_take( &sa->a, sl->len, &data ) );
+ mem_copy( sl->data, data, sl->len );
+ return S_SUCCESS;
+}
+
+
+u8 _halfbyte_to_hex_ascii[] = {
+ [0x0] = '0',
+ [0x1] = '1',
+ [0x2] = '2',
+ [0x3] = '3',
+ [0x4] = '4',
+ [0x5] = '5',
+ [0x6] = '6',
+ [0x7] = '7',
+ [0x8] = '8',
+ [0x9] = '9',
+ [0xa] = 'a',
+ [0xb] = 'b',
+ [0xc] = 'c',
+ [0xd] = 'd',
+ [0xe] = 'e',
+ [0xf] = 'f',
+};
+
+static inline u8* _write_hex_prefix( u8* start ) {
+ start[0] = '0';
+ start[1] = 'x';
+ return start + 2;
+}
+
+static inline Status _write_bin_as_hex_into_arena( u8* data, Arena *a, usize len ) {
+ u8 *out = 0;
+ TRY( Arena_take( a, 2*len + 2, &out ) );
+ out = _write_hex_prefix( out );
+ _bin_to_hex_ascii( data, out, len );
+
+ return S_SUCCESS;
+}
+
+Status StrAsm_fmtx_u8 ( StrAsm *sa, u8 value) {
+ return _write_bin_as_hex_into_arena( &value, &sa->a, sizeof(value) );
+}
+
+Status StrAsm_fmtx_u16( StrAsm *sa, u16 value) {
+ return _write_bin_as_hex_into_arena( (u8*)&value, &sa->a, sizeof(value) );
+}
+
+Status StrAsm_fmtx_u32( StrAsm *sa, u32 value) {
+ return _write_bin_as_hex_into_arena( (u8*)&value, &sa->a, sizeof(value) );
+}
+
+Status StrAsm_fmtx_u64( StrAsm *sa, u64 value) {
+ return _write_bin_as_hex_into_arena( (u8*)&value, &sa->a, sizeof(value) );
+}
+
+static inline Status _write_u64_as_dec_into_arena( u64 value, Arena *a ) {
+ u8 digits[21] = {0};
+
+ u8 *p = &digits[21];
+
+ do {
+ *--p = '0' + value%10;
+ value /= 10;
+ } while(value);
+
+
+ u8 *out = 0;
+ usize n = &digits[21] - p;
+ TRY( Arena_take( a, n, &out ) );
+ mem_copy( p, out, n );
+
+ return S_SUCCESS;
+}
+
+Status StrAsm_fmtd_u8 ( StrAsm *sa, u8 value) {
+ return _write_u64_as_dec_into_arena( value, &sa->a );
+}
+
+Status StrAsm_fmtd_u16( StrAsm *sa, u16 value) {
+ return _write_u64_as_dec_into_arena( value, &sa->a );
+}
+
+Status StrAsm_fmtd_u32( StrAsm *sa, u32 value) {
+ return _write_u64_as_dec_into_arena( value, &sa->a );
+}
+
+Status StrAsm_fmtd_u64( StrAsm *sa, u64 value) {
+ return _write_u64_as_dec_into_arena( value, &sa->a );
+}
+
+static inline Status _write_s64_as_dec_into_arena( s64 value, Arena *a ) {
+ u8 negative = (value < 0);
+ u8 digits[21] = {0};
+
+ u8 *p = &digits[21];
+
+ do {
+ s8 digit = value%10;
+ *--p = '0' + ((digit < 0)? -digit : digit);
+ value /= 10;
+ } while(value);
+
+
+ u8 *out = 0;
+ usize n = &digits[21] - p;
+ if( negative ) {
+ n++;
+ *--p = '-';
+ }
+ TRY( Arena_take( a, n, &out ) );
+ mem_copy( p, out, n );
+
+ return S_SUCCESS;
+}
+
+Status StrAsm_fmtd_s8 ( StrAsm *sa, s8 value) {
+ return _write_s64_as_dec_into_arena( value, &sa->a );
+}
+
+Status StrAsm_fmtd_s16( StrAsm *sa, s16 value) {
+ return _write_s64_as_dec_into_arena( value, &sa->a );
+}
+
+Status StrAsm_fmtd_s32( StrAsm *sa, s32 value) {
+ return _write_s64_as_dec_into_arena( value, &sa->a );
+}
+
+Status StrAsm_fmtd_s64( StrAsm *sa, s64 value) {
+ return _write_s64_as_dec_into_arena( value, &sa->a );
+}
+
+
/******************************************************************************/
/* LINUX-SPECIFIC CODE */
@@ -584,14 +899,14 @@ Status AnyArr_dup( const AnyArr *arr, AnyArr **out_arr, Heap *h, usize elem_size
#if OS == OS_LINUX
/*============================= Entrypoint ===================================*/
#if ARCH == ARCH_X86_64
- u8* linux_startup_sp = 0;
+ u8* _linux_startup_sp = 0;
__asm__ (
".section .text\n"
".global _start\n"
".type _start, @function\n"
"_start:\n"
- "leaq linux_startup_sp(%rip), %rax\n"
+ "leaq _linux_startup_sp(%rip), %rax\n"
"movq %rsp, (%rax)\n" /* save original stack pointer */
"xor %rax, %rax\n"
"call entry\n"
notlibc.h
@@ -15,6 +15,7 @@
#define ARCH_I386 1
#define ARCH_X86_64 2
+#define OS_NONE 0
#define OS_LINUX 1
#define OS_WINDOWS 2
@@ -1273,7 +1274,7 @@ STRUCT( Str,
STRUCT( StrSlc,
usize len;
- u8 *data;
+ const u8 *data;
);
/* On typical platforms that already have/need nul-termination we keep the
@@ -1308,27 +1309,28 @@ STRUCT( StrSlc,
#endif
-
-/* String assembler */
-STRUCT( StrAsm,
- Arena *a;
-);
+u8 Str_equals( const Str *s1, const Str *s2 );
Status StrSlc_from_Str( StrSlc *out, const Str *s, usize start, usize len );
u8 StrSlc_equals( const StrSlc sl1, const StrSlc sl2 );
u8 StrSlc_equals_by_ref( const StrSlc *sl1, const StrSlc *sl2 );
-u8 StrSlc_equals_Str( const StrSlc sl, const Str* s2 );
-u8 StrSlc_equals_Str_by_ref( const StrSlc *s1, const StrSlc s2 );
+
+u8 StrSlc_equals_Str( const StrSlc sl, const Str* s );
+u8 StrSlc_equals_Str_by_ref( const StrSlc *sl, const Str *s );
/* String assembler */
+STRUCT( StrAsm,
+ Arena a;
+);
Status StrAsm_create( StrAsm *out, usize max_size );
+Status StrAsm_reset( StrAsm *out );
Status StrAsm_destroy( StrAsm *out );
-Status StrAsm_store_into_arena( StrAsm *sa, Arena *dst, void **out);
-Status StrAsm_store_onto_heap( StrAsm *sa, Heap *dst, void **out );
+Status StrAsm_store_into_arena( StrAsm *sa, Arena *dst, Str **out );
+Status StrAsm_store_onto_heap( StrAsm *sa, Heap *dst, Str **out );
/* String, character */
Status StrAsm_cat_char ( StrAsm *sa, u8 value );
@@ -1336,29 +1338,65 @@ Status StrAsm_cat_Str( StrAsm *sa, const Str *s );
Status StrAsm_cat_StrSlc( StrAsm *sa, StrSlc sl );
Status StrAsm_cat_StrSlc_by_ref( StrAsm *sa, const StrSlc *sl );
+extern u8 _halfbyte_to_hex_ascii[16];
+
+static inline void _bin_to_hex_ascii( u8 *data, u8 *out, usize count ) {
+ #if ARCH == ARCH_X86_64 || ARCH == ARCH_I386
+ for( u64 i = 0; i < count; ++i ) {
+ u8 byte = data[count - i - 1];
+
+ out[2 * i] = _halfbyte_to_hex_ascii[( byte >> 4 ) & 0x0f];
+ out[2 * i + 1] = _halfbyte_to_hex_ascii[byte & 0x0f];
+ }
+ #else
+ #error Unimpleneted for big endian.
+ #endif
+}
+
/* Hex */
Status StrAsm_fmtx_u8 ( StrAsm *sa, u8 value);
Status StrAsm_fmtx_u16( StrAsm *sa, u16 value);
Status StrAsm_fmtx_u32( StrAsm *sa, u32 value);
Status StrAsm_fmtx_u64( StrAsm *sa, u64 value);
-Status StrAsm_fmtx_usize( StrAsm *sa, usize value);
-Status StrAsm_fmtx_s8 ( StrAsm *sa, s8 value);
-Status StrAsm_fmtx_s16( StrAsm *sa, s16 value);
-Status StrAsm_fmtx_s32( StrAsm *sa, s32 value);
-Status StrAsm_fmtx_s64( StrAsm *sa, s64 value);
-Status StrAsm_fmtx_ssize( StrAsm *sa, ssize value);
+static inline Status StrAsm_fmtx_usize( StrAsm *sa, usize value) {
+ #if ARCH == ARCH_X86_64
+ return StrAsm_fmtx_u64( sa, value );
+ #elif ARCH == ARCH_I386
+ return StrAsm_fmtx_u32( sa, value );
+ #else
+ #error Unimplemented for current arch.
+ #endif
+}
/* Decimal */
Status StrAsm_fmtd_u8 ( StrAsm *sa, u8 value);
Status StrAsm_fmtd_u16( StrAsm *sa, u16 value);
Status StrAsm_fmtd_u32( StrAsm *sa, u32 value);
Status StrAsm_fmtd_u64( StrAsm *sa, u64 value);
-Status StrAsm_fmtd_usize( StrAsm *sa, usize value);
+Status StrAsm_fmtd_usize( StrAsm *sa, usize value) {
+ #if ARCH == ARCH_X86_64
+ return StrAsm_fmtd_u64( sa, value );
+ #elif ARCH == ARCH_I386
+ return StrAsm_fmtd_u32( sa, value );
+ #else
+ #error Unimplemented for current arch.
+ #endif
+}
+
Status StrAsm_fmtd_s8 ( StrAsm *sa, s8 value);
Status StrAsm_fmtd_s16( StrAsm *sa, s16 value);
Status StrAsm_fmtd_s32( StrAsm *sa, s32 value);
Status StrAsm_fmtd_s64( StrAsm *sa, s64 value);
-Status StrAsm_fmtd_ssize( StrAsm *sa, ssize value);
+Status StrAsm_fmtd_ssize( StrAsm *sa, ssize value) {
+ #if ARCH == ARCH_X86_64
+ return StrAsm_fmtd_s64( sa, value );
+ #elif ARCH == ARCH_I386
+ return StrAsm_fmtd_s32( sa, value );
+ #else
+ #error Unimplemented for current arch.
+ #endif
+}
+
/* File */