diff --git a/config/RSPE01_01/symbols.txt b/config/RSPE01_01/symbols.txt index 2ee24722..b6055209 100644 --- a/config/RSPE01_01/symbols.txt +++ b/config/RSPE01_01/symbols.txt @@ -14852,15 +14852,15 @@ lbl_8037B248 = .rodata:0x8037B248; // type:object size:0x10 data:4byte __constants = .rodata:0x8037B258; // type:object size:0x18 scope:global data:double @stringBase0 = .rodata:0x8037B270; // type:object size:0x6F scope:local data:string_table fix_pool_sizes = .rodata:0x8037B2E0; // type:object size:0x18 scope:global data:4byte -lbl_8037B2F8 = .rodata:0x8037B2F8; // type:object size:0xE0 +__fp_string_pool = .rodata:0x8037B2F8; // type:object size:0xE0 __ctype_mapC = .rodata:0x8037B3D8; // type:object size:0x200 scope:global __lower_mapC = .rodata:0x8037B5D8; // type:object size:0x100 scope:global __upper_mapC = .rodata:0x8037B6D8; // type:object size:0x100 scope:global -lbl_8037B7D8 = .rodata:0x8037B7D8; // type:object size:0x10 -lbl_8037B7E8 = .rodata:0x8037B7E8; // type:object size:0xC data:string -lbl_8037B7F4 = .rodata:0x8037B7F4; // type:object size:0xC -lbl_8037B800 = .rodata:0x8037B800; // type:object size:0x58 -lbl_8037B858 = .rodata:0x8037B858; // type:object size:0x88 +_DateTime_Format_C = .rodata:0x8037B7D8; // type:object size:0x10 +_Time_Format_12_C = .rodata:0x8037B7E8; // type:object size:0xC data:string +_Date_Format_C = .rodata:0x8037B7F4; // type:object size:0xC +_Day_Names_C = .rodata:0x8037B800; // type:object size:0x58 +_Month_Names_C = .rodata:0x8037B858; // type:object size:0x88 @stringBase0 = .rodata:0x8037B8E0; // type:object size:0x2B scope:local data:string_table gap_07_8037B90B_rodata = .rodata:0x8037B90B; // type:object size:0x5 scope:global lbl_8037B910 = .rodata:0x8037B910; // type:object size:0x28 data:4byte @@ -14868,7 +14868,7 @@ lbl_8037B938 = .rodata:0x8037B938; // type:object size:0x10 data:byte __wctype_mapC = .rodata:0x8037B948; // type:object size:0x200 scope:global __wlower_mapC = .rodata:0x8037BB48; // type:object size:0x200 scope:global __wupper_mapC = .rodata:0x8037BD48; // type:object size:0x200 scope:global -lbl_8037BF48 = .rodata:0x8037BF48; // type:object size:0x8 +@stringBase0 = .rodata:0x8037BF48; // type:object size:0x8 data:string_table Zero = .rodata:0x8037BF50; // type:object size:0x10 scope:local bp = .rodata:0x8037BF60; // type:object size:0x10 scope:local ...rodata.0 = .rodata:0x8037BF60; // type:label scope:local @@ -17307,10 +17307,10 @@ __vt__Q23EGG6MsgRes = .data:0x80398760; // type:object size:0xC scope:global @STRING@getDataBlkSize__Q23EGG6MsgResFPCv@0 = .data:0x80398778; // type:object size:0xE scope:weak data:string @STRING@getDataBlkSize__Q23EGG6MsgResFPCv = .data:0x80398788; // type:object size:0xC scope:weak data:string __files = .data:0x80398798; // type:object size:0x50 scope:global -lbl_803987E8 = .data:0x803987E8; // type:object size:0x50 -lbl_80398838 = .data:0x80398838; // type:object size:0x50 -lbl_80398888 = .data:0x80398888; // type:object size:0x50 -jumptable_803988D8 = .data:0x803988D8; // type:object size:0x124 scope:local +__stdout_FILE = .data:0x803987E8; // type:object size:0x50 +__stderr_FILE = .data:0x80398838; // type:object size:0x50 +__file_terminator = .data:0x80398888; // type:object size:0x50 +@233 = .data:0x803988D8; // type:object size:0x124 scope:local gap_08_803989FC_data = .data:0x803989FC; // type:object size:0x4 scope:global pow_10$933 = .data:0x80398A00; // type:object size:0x40 scope:global __lconv = .data:0x80398A40; // type:object size:0x38 scope:global data:4byte @@ -17321,22 +17321,22 @@ _loc_mon_C = .data:0x80398B7C; // type:object size:0x34 scope:global _loc_num_C = .data:0x80398BB0; // type:object size:0x18 scope:global _loc_tim_C = .data:0x80398BC8; // type:object size:0x28 scope:global _current_locale = .data:0x80398BF0; // type:object size:0x48 scope:global -jumptable_80398C38 = .data:0x80398C38; // type:object size:0xE0 scope:local -jumptable_80398D18 = .data:0x80398D18; // type:object size:0x44 scope:local -jumptable_80398D5C = .data:0x80398D5C; // type:object size:0x84 scope:local -@2337 = .data:0x80398DE0; // type:object size:0x84 scope:local -@2720 = .data:0x80398E64; // type:object size:0x24 scope:local +@245 = .data:0x80398C38; // type:object size:0xE0 scope:local +@244 = .data:0x80398D18; // type:object size:0x44 scope:local +@323 = .data:0x80398D5C; // type:object size:0x84 scope:local +@399 = .data:0x80398DE0; // type:object size:0x84 scope:local +@1071 = .data:0x80398E64; // type:object size:0x24 scope:local jumptable_80398E88 = .data:0x80398E88; // type:object size:0xE0 scope:local jumptable_80398F68 = .data:0x80398F68; // type:object size:0x20 scope:local jumptable_80398F88 = .data:0x80398F88; // type:object size:0x20 scope:local jumptable_80398FA8 = .data:0x80398FA8; // type:object size:0x44 scope:local jumptable_80398FEC = .data:0x80398FEC; // type:object size:0x44 scope:local -jumptable_80399030 = .data:0x80399030; // type:object size:0xE0 scope:local -jumptable_80399110 = .data:0x80399110; // type:object size:0x44 scope:local -jumptable_80399154 = .data:0x80399154; // type:object size:0x84 scope:local -jumptable_803991D8 = .data:0x803991D8; // type:object size:0x84 scope:local -jumptable_8039925C = .data:0x8039925C; // type:object size:0x24 scope:local -lbl_80399280 = .data:0x80399280; // type:object size:0x58 +@197 = .data:0x80399030; // type:object size:0xE0 scope:local +@196 = .data:0x80399110; // type:object size:0x44 scope:local +@275 = .data:0x80399154; // type:object size:0x84 scope:local +@351 = .data:0x803991D8; // type:object size:0x84 scope:local +@1029 = .data:0x8039925C; // type:object size:0x24 scope:local +@wstringBase0 = .data:0x80399280; // type:object size:0x58 @43 = .data:0x803992D8; // type:object size:0x6C scope:local jumptable_80399348 = .data:0x80399348; // type:object size:0x1C scope:local jumptable_80399364 = .data:0x80399364; // type:object size:0x1C scope:local @@ -22950,17 +22950,17 @@ gap_12_804C0A64_sdata2 = .sdata2:0x804C0A64; // type:object size:0x4 scope:globa @8659 = .sdata2:0x804C0AC0; // type:object size:0x4 scope:local align:4 data:float @8675 = .sdata2:0x804C0AC4; // type:object size:0x4 scope:local align:4 data:float @8678 = .sdata2:0x804C0AC8; // type:object size:0x8 scope:local align:8 data:double -lbl_804C0AD0 = .sdata2:0x804C0AD0; // type:object size:0x8 data:double -lbl_804C0AD8 = .sdata2:0x804C0AD8; // type:object size:0x8 data:double -lbl_804C0AE0 = .sdata2:0x804C0AE0; // type:object size:0x8 data:double -lbl_804C0AE8 = .sdata2:0x804C0AE8; // type:object size:0x8 data:double -lbl_804C0AF0 = .sdata2:0x804C0AF0; // type:object size:0x8 data:double -lbl_804C0AF8 = .sdata2:0x804C0AF8; // type:object size:0x8 data:double -lbl_804C0B00 = .sdata2:0x804C0B00; // type:object size:0x8 data:double -lbl_804C0B08 = .sdata2:0x804C0B08; // type:object size:0x4 -lbl_804C0B0C = .sdata2:0x804C0B0C; // type:object size:0x4 -lbl_804C0B10 = .sdata2:0x804C0B10; // type:object size:0x8 -lbl_804C0B18 = .sdata2:0x804C0B18; // type:object size:0x8 +@499 = .sdata2:0x804C0AD0; // type:object size:0x8 data:double +@724 = .sdata2:0x804C0AD8; // type:object size:0x8 data:double +@725 = .sdata2:0x804C0AE0; // type:object size:0x8 data:double +@726 = .sdata2:0x804C0AE8; // type:object size:0x8 data:double +@727 = .sdata2:0x804C0AF0; // type:object size:0x8 data:double +@731 = .sdata2:0x804C0AF8; // type:object size:0x8 data:double +@732 = .sdata2:0x804C0B00; // type:object size:0x8 data:double +_Decimal_Point_C = .sdata2:0x804C0B08; // type:object size:0x4 +_const_int_0 = .sdata2:0x804C0B0C; // type:object size:0x4 +_AmPm_Format_C = .sdata2:0x804C0B10; // type:object size:0x8 +_Time_Format_C = .sdata2:0x804C0B18; // type:object size:0x8 lbl_804C0B20 = .sdata2:0x804C0B20; // type:object size:0x8 data:double lbl_804C0B28 = .sdata2:0x804C0B28; // type:object size:0x1 data:byte lbl_804C0B29 = .sdata2:0x804C0B29; // type:object size:0x1 data:byte diff --git a/configure.py b/configure.py index 8f9b8327..181f3fb8 100755 --- a/configure.py +++ b/configure.py @@ -727,37 +727,37 @@ def MatchingFor(*versions): "progress_category": "sdk", "objects": [ Object(NonMatching, "MSL/alloc.c"), + Object(Matching, "MSL/errno.c"), Object(NonMatching, "MSL/ansi_files.c"), - Object(NonMatching, "MSL/ansi_fp.c"), - Object(NonMatching, "MSL/arith.c"), - Object(NonMatching, "MSL/buffer_io.c"), - Object(NonMatching, "MSL/direct_io.c"), - Object(NonMatching, "MSL/errno.c"), - Object(NonMatching, "MSL/file_io.c"), - Object(NonMatching, "MSL/FILE_POS.c"), + Object(Matching, "MSL/ansi_fp.c"), Object(NonMatching, "MSL/locale.c"), - Object(NonMatching, "MSL/mbstring.c"), - Object(NonMatching, "MSL/mem.c"), - Object(NonMatching, "MSL/mem_funcs.c"), - Object(NonMatching, "MSL/math_api.c"), - Object(NonMatching, "MSL/misc_io.c"), + Object(Matching, "MSL/arith.c"), + Object(Matching, "MSL/buffer_io.c"), + Object(Matching, "MSL/direct_io.c"), + Object(Matching, "MSL/file_io.c"), + Object(Matching, "MSL/FILE_POS.c"), + Object(Matching, "MSL/mbstring.c"), + Object(Matching, "MSL/mem.c"), + Object(Matching, "MSL/mem_funcs.c"), + Object(Matching, "MSL/math_api.c"), + Object(Matching, "MSL/misc_io.c"), Object(NonMatching, "MSL/printf.c"), - Object(NonMatching, "MSL/rand.c"), + Object(Matching, "MSL/rand.c"), + Object(Matching, "MSL/float.c"), Object(NonMatching, "MSL/scanf.c"), - Object(NonMatching, "MSL/string.c"), + Object(Matching, "MSL/string.c"), Object(NonMatching, "MSL/strtold.c"), + Object(Matching, "MSL/wctype.c"), Object(NonMatching, "MSL/strtoul.c"), - Object(NonMatching, "MSL/wctype.c"), - Object(NonMatching, "MSL/wmem.c"), + Object(Matching, "MSL/wmem.c"), Object(NonMatching, "MSL/wprintf.c"), - Object(NonMatching, "MSL/wstring.c"), - Object(NonMatching, "MSL/wchar_io.c"), - Object(NonMatching, "MSL/uart_console_io_gcn.c"), - Object(NonMatching, "MSL/abort_exit_ppc_eabi.c"), - Object(NonMatching, "MSL/math_sun.c"), - Object(NonMatching, "MSL/math_float.c"), - Object(NonMatching, "MSL/extras.c"), - Object(Matching, "MSL/float.c"), + Object(Matching, "MSL/wstring.c"), + Object(Matching, "MSL/wchar_io.c"), + Object(Matching, "MSL/uart_console_io_gcn.c"), + Object(Matching, "MSL/abort_exit_ppc_eabi.c"), + Object(Matching, "MSL/math_sun.c"), + Object(Matching, "MSL/math_float.c"), + Object(Matching, "MSL/extras.c"), Object(Matching, "MSL/e_acos.c"), Object(Matching, "MSL/e_asin.c"), Object(Matching, "MSL/e_atan2.c"), diff --git a/include/MSL/UART.h b/include/MSL/UART.h new file mode 100644 index 00000000..a1f00cbe --- /dev/null +++ b/include/MSL/UART.h @@ -0,0 +1,37 @@ +#ifndef UART_H +#define UART_H + +typedef int UARTError; + +enum { + kUARTNoError = 0, + kUARTUnknownBaudRate, + kUARTConfigurationError, + kUARTBufferOverflow, + kUARTNoData +}; + +typedef enum { + kBaudHWSet = -1, + kBaud300 = 300, + kBaud600 = 600, + kBaud1200 = 1200, + kBaud1800 = 1800, + kBaud2000 = 2000, + kBaud2400 = 2400, + kBaud3600 = 3600, + kBaud4800 = 4800, + kBaud7200 = 7200, + kBaud9600 = 9600, + kBaud19200 = 19200, + kBaud38400 = 38400, + kBaud57600 = 57600, + kBaud115200 = 115200, + kBaud230400 = 230400 +} UARTBaudRate; + +UARTError InitializeUART(UARTBaudRate); + +UARTError WriteUARTN(const void *, unsigned long); + +#endif // UART_H diff --git a/include/MSL/alloc.h b/include/MSL/alloc.h new file mode 100644 index 00000000..c5bfc6ab --- /dev/null +++ b/include/MSL/alloc.h @@ -0,0 +1,117 @@ +typedef struct Block { + struct Block* prev; + struct Block* next; + unsigned long max_size; + unsigned long size; +} Block; + +typedef struct SubBlock { + unsigned long size; + Block* block; + struct SubBlock* prev; + struct SubBlock* next; +} SubBlock; + +struct FixSubBlock; + +typedef struct FixBlock { + struct FixBlock* prev_; + struct FixBlock* next_; + unsigned long client_size_; + struct FixSubBlock* start_; + unsigned long n_allocated_; +} FixBlock; + +typedef struct FixSubBlock { + FixBlock* block_; + struct FixSubBlock* next_; +} FixSubBlock; + +typedef struct FixStart { + FixBlock* tail_; + FixBlock* head_; +} FixStart; + +typedef struct __mem_pool_obj { + Block* start_; + FixStart fix_start[6]; +} __mem_pool_obj; + +typedef struct __mem_pool { + void* reserved[14]; +} __mem_pool; + +typedef signed long tag_word; + +typedef struct block_header { + tag_word tag; + struct block_header* prev; + struct block_header* next; +} block_header; + +typedef struct list_header { + block_header* rover; + block_header header; +} list_header; + +typedef struct heap_header { + struct heap_header* prev; + struct heap_header* next; +} heap_header; + +struct mem_pool_obj; +typedef void* (*sys_alloc_ptr)(unsigned long, struct mem_pool_obj*); +typedef void (*sys_free_ptr)(void*, struct mem_pool_obj*); + +typedef struct pool_options { + sys_alloc_ptr sys_alloc_func; + sys_free_ptr sys_free_func; + unsigned long min_heap_size; + int always_search_first; +} pool_options; + +typedef struct mem_pool_obj { + list_header free_list; + pool_options options; + heap_header* heap_list; + void* userData; + +} mem_pool_obj; + +static const unsigned long fix_pool_sizes[] = {4, 12, 20, 36, 52, 68}; + +#define SubBlock_size(ths) ((ths)->size & 0xFFFFFFF8) +#define SubBlock_block(ths) ((Block*)((unsigned long)((ths)->block) & ~0x1)) +#define Block_size(ths) ((ths)->size & 0xFFFFFFF8) +#define Block_start(ths) \ + (*(SubBlock**)((char*)(ths) + Block_size((ths)) - sizeof(unsigned long))) + +#define SubBlock_set_free(ths) \ + unsigned long this_size = SubBlock_size((ths)); \ + (ths)->size &= ~0x2; \ + *(unsigned long*)((char*)(ths) + this_size) &= ~0x4; \ + *(unsigned long*)((char*)(ths) + this_size - sizeof(unsigned long)) = \ + this_size + +#define SubBlock_is_free(ths) !((ths)->size & 2) +#define SubBlock_set_size(ths, sz) \ + (ths)->size &= ~0xFFFFFFF8; \ + (ths)->size |= (sz)&0xFFFFFFF8; \ + if (SubBlock_is_free((ths))) \ + *(unsigned long*)((char*)(ths) + (sz) - sizeof(unsigned long)) = (sz) + +#define SubBlock_from_pointer(ptr) ((SubBlock*)((char*)(ptr)-8)) +#define FixSubBlock_from_pointer(ptr) ((FixSubBlock*)((char*)(ptr)-4)) + +#define FixBlock_client_size(ths) ((ths)->client_size_) +#define FixSubBlock_size(ths) (FixBlock_client_size((ths)->block_)) + +#define classify(ptr) \ + (*(unsigned long*)((char*)(ptr) - sizeof(unsigned long)) & 1) +#define __msize_inline(ptr) \ + (!classify(ptr) ? FixSubBlock_size(FixSubBlock_from_pointer(ptr)) \ + : SubBlock_size(SubBlock_from_pointer(ptr)) - 8) + +#define Block_empty(ths) \ + (_sb = (SubBlock*)((char*)(ths) + 16)), \ + SubBlock_is_free(_sb) && SubBlock_size(_sb) == Block_size((ths)) - 24 diff --git a/include/MSL/ansi_files.h b/include/MSL/ansi_files.h new file mode 100644 index 00000000..cf0fdfc6 --- /dev/null +++ b/include/MSL/ansi_files.h @@ -0,0 +1,27 @@ +#ifndef _ANSI_FILES_H +#define _ANSI_FILES_H + +#include "types.h" +#include "stdio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define console_buff_mode _IOLBF +#define console_buff_size 256 + +typedef unsigned char console_buff[console_buff_size]; + +extern console_buff stdin_buff; +extern console_buff stdout_buff; +extern console_buff stderr_buff; + +void __close_all(); +u32 __flush_all(); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/include/MSL/ansi_fp.h b/include/MSL/ansi_fp.h new file mode 100644 index 00000000..57d87b00 --- /dev/null +++ b/include/MSL/ansi_fp.h @@ -0,0 +1,44 @@ +#ifndef ANSI_FP_H +#define ANSI_FP_H +#include + +typedef struct decimal { + char sign; + char _1; + short exponent; + + struct { + unsigned char length; + unsigned char text[36]; + unsigned char pad; + } sig; +} decimal; + +typedef struct decform { + char style; + char _1; + short digits; +} decform; + +#ifdef __cplusplus +extern "C" { +#endif + +extern const char _AmPm_Format_C[]; +extern const char _DateTime_Format_C[]; +extern const char _Time_Format_12_C[]; +extern const char _Date_Format_C[]; +extern const char _Time_Format_C[]; +extern const char _Day_Names_C[]; +extern const char _Month_Names_C[]; + +extern const int _const_int_0; + +extern const unsigned short __ctype_mapC[0x100]; +extern const unsigned char __lower_mapC[0x100]; +extern const unsigned char __upper_mapC[0x100]; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/MSL/ansi_params.h b/include/MSL/ansi_params.h new file mode 100644 index 00000000..969bf9f5 --- /dev/null +++ b/include/MSL/ansi_params.h @@ -0,0 +1,14 @@ +#ifndef ANSI_PARAMS_H +#define ANSI_PARAMS_H + +#define _MSL_CANT_THROW __attribute__((nothrow)) + +#define _MSL_THROW throw() + +#ifndef _MSL_LOCALDATA +#define _MSL_LOCALDATA(_a) _a +#endif + +#define __std(ref) ref + +#endif // ANSI_PARAMS_H diff --git a/include/MSL/buffer_io.h b/include/MSL/buffer_io.h new file mode 100644 index 00000000..dec792b1 --- /dev/null +++ b/include/MSL/buffer_io.h @@ -0,0 +1,9 @@ +#ifndef BUFFER_IO_H +#define BUFFER_IO_H + +#include "file_struct.h" + +void __prep_buffer(FILE*); +int __flush_buffer(FILE*, size_t*); + +#endif // BUFFER_IO_H diff --git a/include/MSL/ctype.h b/include/MSL/ctype.h index 1a3d9807..6490acd5 100644 --- a/include/MSL/ctype.h +++ b/include/MSL/ctype.h @@ -1,34 +1,120 @@ #ifndef MSL_CTYPE_H #define MSL_CTYPE_H #include +#include #ifdef __cplusplus extern "C" { #endif -typedef struct __CMap { - char UNK_0x0[0x10]; - const u8* to_lower_table; // at 0x10 - const u8* to_upper_table; // at 0x14 -} __CMap; -typedef struct __Locale { - char UNK_0x0[0x38]; - struct __CMap* cmap; // at 0x38 - char UNK_0x3C[0x44 - 0x3C]; -} __Locale; +#define ctype_alpha 0x0001 +#define ctype_blank 0x0002 +#define ctype_cntrl 0x0004 +#define ctype_digit 0x0008 +#define ctype_graph 0x0010 +#define ctype_lower 0x0020 +#define ctype_print 0x0040 +#define ctype_punct 0x0080 +#define ctype_space 0x0100 +#define ctype_upper 0x0200 +#define ctype_xdigit 0x0400 -extern __Locale _current_locale; +#define ctype_alnum (ctype_alpha | ctype_digit) -inline int tolower(int x) { - return (x < 0 || x >= 256) - ? x - : (int)(&_current_locale)->cmap->to_lower_table[x]; +static inline int isalnum(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_alnum); } -inline int toupper(int x) { - return (x < 0 || x >= 256) - ? x - : (int)(&_current_locale)->cmap->to_upper_table[x]; +static inline int isalpha(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_alpha); +} + +static inline int isblank(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_blank); +} + +static inline int iscntrl(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_cntrl); +} + +static inline int isdigit(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_digit); +} + +static inline int isgraph(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_graph); +} + +static inline int islower(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_lower); +} + +static inline int isprint(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_print); +} + +static inline int ispunct(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_punct); +} + +static inline int isspace(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_space); +} + +static inline int isupper(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_upper); +} + +static inline int isxdigit(int c) { + return (c < 0 || c >= 256) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->ctype_map_ptr[c] & + ctype_xdigit); +} + +static inline int tolower(int c) { + return (c < 0 || c >= 256) + ? c + : (int)(&_current_locale)->ctype_cmpt_ptr->lower_map_ptr[c]; +} + +static inline int toupper(int c) { + return (c < 0 || c >= 256) + ? c + : (int)(&_current_locale)->ctype_cmpt_ptr->upper_map_ptr[c]; } #ifdef __cplusplus diff --git a/include/MSL/errno.h b/include/MSL/errno.h index c901fcca..02bbad19 100644 --- a/include/MSL/errno.h +++ b/include/MSL/errno.h @@ -7,7 +7,12 @@ extern "C" { extern int errno; +#define ENOERR 0 #define EDOM 33 +#define ERANGE 34 +#define ESIGPARM 36 +#define EFPOS 40 +#define EILSEQ 84 #ifdef __cplusplus } diff --git a/include/MSL/internal/file_io.h b/include/MSL/internal/file_io.h index 40ec5785..6fd55fd7 100644 --- a/include/MSL/internal/file_io.h +++ b/include/MSL/internal/file_io.h @@ -1,13 +1,11 @@ #ifndef MSL_FILE_IO_H #define MSL_FILE_IO_H -#include +#include #ifdef __cplusplus extern "C" { #endif -typedef struct FILE { - u8 dummy; -} FILE; + int fclose(FILE*); int fflush(FILE*); diff --git a/include/MSL/internal/file_struct.h b/include/MSL/internal/file_struct.h new file mode 100644 index 00000000..5bcd3a1f --- /dev/null +++ b/include/MSL/internal/file_struct.h @@ -0,0 +1,98 @@ +#ifndef FILE_STRUCT_H +#define FILE_STRUCT_H + +#include "ansi_params.h" +#include + +enum file_kinds { + file_closed, + file_disk, + file_console, + file_unavailable +}; + +enum open_modes { + must_exist, + create_if_needed, + create_or_truncate +}; + +enum file_orientation { + file_unoriented, + file_char_oriented, + file_wide_oriented +}; + +typedef struct { + unsigned int open : 2; + unsigned int io : 3; + unsigned int buffer : 2; + unsigned int file : 3; + unsigned int file_orientation : 2; + unsigned int binary : 1; +} file_modes; + +enum io_modes { + read = 1, + write = 2, + read_write = 3, + append = 4 +}; + +enum io_states { + neutral, + writing, + reading, + rereading +}; + +typedef struct +{ + unsigned int io_state : 3; + unsigned int free_buffer : 1; + unsigned char eof; + unsigned char error; +} file_state; + +typedef unsigned long file_handle; +typedef struct _FILE FILE; +typedef int (* __pos_proc)(unsigned long, long *, int, void *); +typedef int (* __io_proc)(unsigned long, unsigned char *, size_t *, void *); +typedef int (* __close_proc)(unsigned long); + +struct _FILE { + file_handle handle; + file_modes mode; + file_state state; + unsigned char is_dyn_alloc; + unsigned char char_buf; + unsigned char char_buf_of; + unsigned char unget_buffer[2]; + wchar_t ungetwc_buffer[2]; + unsigned long pos; + unsigned char* buffer; + unsigned long buffer_size; + unsigned char* buffer_ptr; + unsigned long buffer_len; + unsigned long buffer_alignment; + unsigned long unk; + unsigned long buffer_pos; + __pos_proc pos_proc; + __io_proc read_proc; + __io_proc write_proc; + __close_proc close_proc; + void* ref; + struct _FILE* next_file; +}; + +#define _IONBF 0 +#define _IOLBF 1 +#define _IOFBF 2 + +#define _STATIC_FILES 4 + +extern FILE __files[]; + +#define stdout (&__std(__files[1])) + +#endif // FILE_STRUCT_H diff --git a/include/MSL/internal/pformatter.h b/include/MSL/internal/pformatter.h new file mode 100644 index 00000000..ea41f65e --- /dev/null +++ b/include/MSL/internal/pformatter.h @@ -0,0 +1,48 @@ +#ifndef MSL_INTERNAL_PFORMATTER_H +#define MSL_INTERNAL_PFORMATTER_H + +#include "stddef.h" + +enum justification_options { + left_justification, + right_justification, + zero_fill +}; + +enum sign_options { only_minus, sign_always, space_holder }; + +enum argument_options { + normal_argument, + char_argument, + short_argument, + long_argument, + long_long_argument, + wchar_argument, + intmax_argument, + size_t_argument, + ptrdiff_argument, + long_double_argument +}; + +typedef struct { + char* CharStr; + size_t MaxCharCount; + size_t CharsWritten; +} __OutStrCtrl; + +#define LDBL_MANT_DIG 24 +#define LDBL_MAX_EXP 128 +#define TARGET_FLOAT_BITS 32 +#define TARGET_FLOAT_BYTES (TARGET_FLOAT_BITS / 8) +#define TARGET_FLOAT_MAX_EXP LDBL_MAX_EXP +#define TARGET_FLOAT_MANT_DIG LDBL_MANT_DIG +#define TARGET_FLOAT_IMPLICIT_J_BIT 1 +#define TARGET_FLOAT_MANT_BITS (TARGET_FLOAT_MANT_DIG - TARGET_FLOAT_IMPLICIT_J_BIT) +#define TARGET_FLOAT_EXP_BITS (TARGET_FLOAT_BITS - TARGET_FLOAT_MANT_BITS - 1) + +typedef long long intmax_t; + +#define PTRDIFF __typeof__((char*)0-(char*)0) +typedef PTRDIFF ptrdiff_t; + +#endif // MSL_INTERNAL_PFORMATTER_H diff --git a/include/MSL/internal/sformatter.h b/include/MSL/internal/sformatter.h new file mode 100644 index 00000000..0daf2079 --- /dev/null +++ b/include/MSL/internal/sformatter.h @@ -0,0 +1,34 @@ +#ifndef MSL_INTERNAL_SFORMATTER_H +#define MSL_INTERNAL_SFORMATTER_H + +#include "stddef.h" + +enum argument_options { + normal_argument, + char_argument, + short_argument, + long_argument, + intmax_argument, + size_t_argument, + ptrdiff_argument, + long_long_argument, + double_argument, + long_double_argument, + wchar_argument +}; + +typedef unsigned char char_map[32]; + +#define set_char_map(map, ch) ((map)[(unsigned char)(ch) >> 3] |= (1 << ((ch) & 7))) +#define tst_char_map(map, ch) ((map)[(unsigned char)(ch) >> 3] & (1 << ((ch) & 7))) + +typedef struct { + unsigned char suppress_assignment; + unsigned char field_width_specified; + unsigned char argument_options; + unsigned char conversion_char; + int field_width; + char_map char_set; +} scan_format; + +#endif // MSL_INTERNAL_SFORMATTER_H diff --git a/include/MSL/internal/wmem.h b/include/MSL/internal/wmem.h deleted file mode 100644 index 903e666e..00000000 --- a/include/MSL/internal/wmem.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef MSL_WMEM_H -#define MSL_WMEM_H -#include -#ifdef __cplusplus -extern "C" { -#endif - -void* wmemcpy(void*, const void*, size_t); -void* wmemchr(const void*, int, size_t); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/include/MSL/limits.h b/include/MSL/limits.h index 3524bf95..ffe2c07c 100644 --- a/include/MSL/limits.h +++ b/include/MSL/limits.h @@ -25,6 +25,24 @@ extern "C" { #define LONG_MAX INT_MAX #define ULONG_MAX 4294967295 +#define LLONG_MIN (-0x7FFFFFFFFFFFFFFFLL - 1) +#define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL +#define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL + +#define DBL_MIN 2.2250738585072014E-308L +#define DBL_MAX 1.7976931348623157E+308L + +#define LDBL_MIN 0x1.0000000000000P-1022L +#define LDBL_MAX 0x1.fffffffffffffP1023L +#define LDBL_EPSILON 0x1.0000000000000P-52L + +#define INFINITY (*(float*)__float_huge) + +// NAN and HUGE_VAL are redefined in a bunch of locations +//#define NAN (*(float*)__float_nan) +//#define HUGE_VAL (*(double*)__double_huge) + + #ifdef __cplusplus } #endif diff --git a/include/MSL/locale.h b/include/MSL/locale.h index b0fb693e..88901027 100644 --- a/include/MSL/locale.h +++ b/include/MSL/locale.h @@ -1,38 +1,115 @@ #ifndef MSL_LOCALE_H #define MSL_LOCALE_H -#include -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct lconv { - char* decimal_point; // at 0x0 - char* thousands_sep; // at 0x4 - char* grouping; // at 0x8 - char* currency_symbol; // at 0xC - char* mon_decimal_point; // at 0x10 - char* mon_thousands_sep; // at 0x14 - char* mon_grouping; // at 0x18 - char* positive_sign; // at 0x1C - char* negative_sign; // at 0x20 - char int_frac_digits; // at 0x24 - char frac_digits; // at 0x25 - char p_cs_precedes; // at 0x26 - char p_sep_by_space; // at 0x27 - char n_cs_precedes; // at 0x28 - char n_sep_by_space; // at 0x29 - char p_sign_posn; // at 0x2A - char n_sign_posn; // at 0x2B - char* int_curr_symbol; // at 0x2C - char int_p_cs_precedes; // at 0x30 - char int_n_cs_precedes; // at 0x31 - char int_p_sep_by_space; // at 0x32 - char int_n_sep_by_space; // at 0x33 - char int_p_sign_posn; // at 0x34 - char int_n_sign_posn; // at 0x35 -} lconv; - -#ifdef __cplusplus -} -#endif -#endif + +#include "ansi_params.h" +#include "wchar_io.h" + +typedef int (* __decode_mbyte) (wchar_t *, const char *, __std(size_t)); +typedef int (* __encode_mbyte) (char *, wchar_t); + +struct lconv { + char* decimal_point; + char* thousands_sep; + char* grouping; + char* mon_decimal_point; + char* mon_thousands_sep; + char* mon_grouping; + char* positive_sign; + char* negative_sign; + char* currency_symbol; + char frac_digits; + char p_cs_precedes; + char n_cs_precedes; + char p_sep_by_space; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char* int_curr_symbol; + char int_frac_digits; + char int_p_cs_precedes; + char int_n_cs_precedes; + char int_p_sep_by_space; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +}; + +struct _loc_mon_cmpt { + char CmptName[8]; + char* mon_decimal_point; + char* mon_thousands_sep; + char* mon_grouping; + char* positive_sign; + char* negative_sign; + char* currency_symbol; + char frac_digits; + char p_cs_precedes; + char n_cs_precedes; + char p_sep_by_space; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char* int_curr_symbol; + char int_frac_digits; + char int_p_cs_precedes; + char int_n_cs_precedes; + char int_p_sep_by_space; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; +}; + +struct _loc_num_cmpt { + char CmptName[8]; + char* decimal_point; + char* thousands_sep; + char* grouping; +}; + +struct _loc_time_cmpt { + char CmptName[8]; + const char* am_pm; + const char* DateTime_Format; + const char* Twelve_hr_format; + const char* Date_Format; + const char* Time_Format; + const char* Day_Names; + const char* MonthNames; + char* TimeZone; +}; + +struct _loc_coll_cmpt { + char name[8]; + int char_start; + int char_coll_tab_size; + short char_spec; + unsigned short* char_coll_table_ptr; + unsigned short* wchar_coll_seq_ptr; +}; + +struct _loc_ctype_cmpt { + char name[8]; // 0x0 + const unsigned short* ctype_map_ptr; // 0x8 + const unsigned char* upper_map_ptr; // 0xC + const unsigned char* lower_map_ptr; // 0x10 + const unsigned short* wctype_map_ptr; // 0x14 + const wchar_t* wupper_map_ptr; // 0x18 + const wchar_t* wlower_map_ptr; // 0x1C + __decode_mbyte decode_mb; + __encode_mbyte encode_wc; +}; + +struct __locale { + struct __locale* next_locale; // 0x0 + char name[0x30]; // 0x4 + struct _loc_coll_cmpt* coll_cmpt_ptr; // 0x34 + struct _loc_ctype_cmpt* ctype_cmpt_ptr; // 0x38 + struct _loc_mon_cmpt* mon_cmpt_ptr; // 0x3C + struct _loc_num_cmpt* num_cmpt_ptr; // 0x40 + struct _loc_time_cmpt* time_cmpt_ptr; // 0x44 +}; + +extern struct __locale _current_locale; +extern struct lconv __lconv; + +#endif // LOCALE_H diff --git a/include/MSL/math.h b/include/MSL/math.h index 58cea7b6..1be0a4c0 100644 --- a/include/MSL/math.h +++ b/include/MSL/math.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include diff --git a/include/MSL/internal/math_api.h b/include/MSL/math_api.h similarity index 59% rename from include/MSL/internal/math_api.h rename to include/MSL/math_api.h index a8b168c4..e90b22ee 100644 --- a/include/MSL/internal/math_api.h +++ b/include/MSL/math_api.h @@ -1,6 +1,5 @@ #ifndef MSL_MATH_API_H #define MSL_MATH_API_H -#include #ifdef __cplusplus extern "C" { #endif @@ -8,6 +7,12 @@ extern "C" { int __fpclassify(long double); int __fpclassifyd(double); int __fpclassifyf(float); +int __signbitd(double); + +double copysign(double, double); +double frexp(double, int *); +double ldexp(double, int); +double nan(const char *); #ifdef __cplusplus } diff --git a/include/MSL/internal/mbstring.h b/include/MSL/mbstring.h similarity index 70% rename from include/MSL/internal/mbstring.h rename to include/MSL/mbstring.h index e0cb5d5f..1a6e2651 100644 --- a/include/MSL/internal/mbstring.h +++ b/include/MSL/mbstring.h @@ -1,10 +1,14 @@ #ifndef MSL_MBSTRING_H #define MSL_MBSTRING_H -#include + +#include "types.h" + #ifdef __cplusplus extern "C" { #endif +int __mbtowc_noconv(wchar_t*, const char*, size_t); +int __wctomb_noconv(char*, wchar_t); int mbtowc(wchar_t*, const char*, size_t); size_t mbstowcs(wchar_t*, const char*, size_t); size_t wcstombs(char*, const wchar_t*, size_t); @@ -12,4 +16,5 @@ size_t wcstombs(char*, const wchar_t*, size_t); #ifdef __cplusplus } #endif + #endif diff --git a/include/MSL/mem_funcs.h b/include/MSL/mem_funcs.h new file mode 100644 index 00000000..23bdbcc2 --- /dev/null +++ b/include/MSL/mem_funcs.h @@ -0,0 +1,18 @@ +#ifndef MEM_FUNCS_H +#define MEM_FUNCS_H + +#ifdef __cplusplus +extern "C" { +#endif + +void __copy_longs_aligned(void* pDest, const void* pSrc, unsigned long len); +void __copy_longs_rev_aligned(void* pDest, const void* pSrc, unsigned long len); +void __copy_longs_unaligned(void* pDest, const void* pSrc, unsigned long len); +void __copy_longs_rev_unaligned(void* pDest, const void* pSrc, + unsigned long len); + +#ifdef __cplusplus +} +#endif + +#endif // MEM_FUNCS_H diff --git a/include/MSL/rand.h b/include/MSL/rand.h new file mode 100644 index 00000000..64192cfb --- /dev/null +++ b/include/MSL/rand.h @@ -0,0 +1,17 @@ +#ifndef _RAND_H +#define _RAND_H + +#include "types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int rand(); +void srand(u32 seed); + +#ifdef __cplusplus +}; +#endif + +#endif diff --git a/include/MSL/stdio.h b/include/MSL/stdio.h index 538fb215..44b8c44d 100644 --- a/include/MSL/stdio.h +++ b/include/MSL/stdio.h @@ -5,4 +5,5 @@ #include #include #include +#include "stdio_api.h" #endif diff --git a/include/MSL/stdio_api.h b/include/MSL/stdio_api.h new file mode 100644 index 00000000..ced5511d --- /dev/null +++ b/include/MSL/stdio_api.h @@ -0,0 +1,26 @@ +#ifndef STDIO_API_H +#define STDIO_API_H + +#include "types.h" + +enum __ReadProcActions { __GetAChar, __UngetAChar, __TestForError }; + +typedef struct { + char* NextChar; + int NullCharDetected; +} __InStrCtrl; + +typedef struct { + wchar_t* wCharStr; + size_t MaxCharCount; + size_t CharsWritten; +} __wOutStrCtrl; + +typedef struct { + wchar_t* wNextChar; + int wNullCharDetected; +} __wInStrCtrl; + +int __StringRead(void*, int, int); + +#endif // STDIO_API_H diff --git a/include/MSL/stdlib.h b/include/MSL/stdlib.h index 06827cb5..0b334830 100644 --- a/include/MSL/stdlib.h +++ b/include/MSL/stdlib.h @@ -1,7 +1,7 @@ #ifndef MSL_STDLIB_H #define MSL_STDLIB_H #include -#include +#include #include #include #endif diff --git a/include/MSL/strtoul.h b/include/MSL/strtoul.h new file mode 100644 index 00000000..c57dfb9f --- /dev/null +++ b/include/MSL/strtoul.h @@ -0,0 +1,18 @@ +#ifndef _STRTOUL_H +#define _STRTOUL_H + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned long __strtoul(int base, int max_width, int (*ReadProc)(void*, int, int), void* ReadProcArg, + int* chars_scanned, int* negative, int* overflow); +unsigned long long __strtoull(int base, int max_width, int (*ReadProc)(void*, int, int), void* ReadProcArg, + int* chars_scanned, int* negative, int* overflow); +int atoi(const char* str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/MSL/uart_console_io_gcn.h b/include/MSL/uart_console_io_gcn.h new file mode 100644 index 00000000..3bc9093e --- /dev/null +++ b/include/MSL/uart_console_io_gcn.h @@ -0,0 +1,21 @@ +#ifndef _UART_CONSOLE_IO_GCN_H +#define _UART_CONSOLE_IO_GCN_H + +#include "file_struct.h" +#include "types.h" +#include "stdio.h" +#include "UART.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int __read_console(unsigned long, unsigned char* buffer, size_t* count, void* ref); +int __write_console(unsigned long, unsigned char* buffer, size_t* count, void* ref); +int __close_console(unsigned long); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/include/MSL/va_list.h b/include/MSL/va_list.h new file mode 100644 index 00000000..20507db1 --- /dev/null +++ b/include/MSL/va_list.h @@ -0,0 +1,22 @@ +#ifndef VA_LIST_H +#define VA_LIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct __va_list_struct { + char gpr; + char fpr; + char reserved[2]; + char* input_arg_area; + char* reg_save_area; +} __va_list[1]; + +typedef __va_list va_list; + +#ifdef __cplusplus +} +#endif + +#endif // VA_LIST_H diff --git a/include/MSL/wchar.h b/include/MSL/wchar.h index 5bfd82ee..96981a68 100644 --- a/include/MSL/wchar.h +++ b/include/MSL/wchar.h @@ -1,8 +1,8 @@ #ifndef MSL_WCHAR_H #define MSL_WCHAR_H -#include +#include #include -#include +#include #include #include #ifdef __cplusplus @@ -12,6 +12,8 @@ extern "C" { #define WCHAR_MIN SHRT_MIN #define WCHAR_MAX USHRT_MAX +typedef wchar_t wint_t; + #ifdef __cplusplus } #endif diff --git a/include/MSL/wchar_io.h b/include/MSL/wchar_io.h new file mode 100644 index 00000000..1d74b3be --- /dev/null +++ b/include/MSL/wchar_io.h @@ -0,0 +1,8 @@ +#ifndef WCHAR_IO_H +#define WCHAR_IO_H + +#include "file_struct.h" + +int fwide(FILE *, int); + +#endif // WCHAR_IO_H diff --git a/include/MSL/wctype.h b/include/MSL/wctype.h new file mode 100644 index 00000000..6389ea31 --- /dev/null +++ b/include/MSL/wctype.h @@ -0,0 +1,25 @@ +#ifndef WCTYPE_H +#define WCTYPE_H + +#include "types.h" +#include "wchar.h" +#include "locale.h" + +extern const unsigned short __wctype_mapC[0x100]; +extern const wchar_t __wlower_mapC[0x100]; +extern const wchar_t __wupper_mapC[0x100]; + +inline int iswdigit(wint_t c) { + return ((c < 0) || (c >= 0x100)) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->wctype_map_ptr[c] & 0x8); +} + +inline int iswupper(wint_t c) { + return ((c < 0) || (c >= 0x100)) + ? 0 + : (int)(_current_locale.ctype_cmpt_ptr->wctype_map_ptr[c] & + 0x200); +} + +#endif // WCTYPE_H diff --git a/include/MSL/wmem.h b/include/MSL/wmem.h new file mode 100644 index 00000000..9d9ffb79 --- /dev/null +++ b/include/MSL/wmem.h @@ -0,0 +1,14 @@ +#ifndef MSL_WMEM_H +#define MSL_WMEM_H +#include "types.h" +#ifdef __cplusplus +extern "C" { +#endif + +wchar_t* wmemcpy(wchar_t*, const wchar_t*, size_t); +wchar_t* wmemchr(wchar_t*, wchar_t, size_t); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/MSL/internal/wstring.h b/include/MSL/wstring.h similarity index 94% rename from include/MSL/internal/wstring.h rename to include/MSL/wstring.h index bc977897..966db183 100644 --- a/include/MSL/internal/wstring.h +++ b/include/MSL/wstring.h @@ -1,6 +1,8 @@ #ifndef MSL_WSTRING_H #define MSL_WSTRING_H -#include + +#include "types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/include/types.h b/include/types.h index 4fd2c040..9cd4fb1a 100644 --- a/include/types.h +++ b/include/types.h @@ -35,6 +35,8 @@ typedef void UNKTYPE; enum { FALSE, TRUE }; typedef int BOOL; +#define nullptr 0 + typedef void (*funcptr_t)(void); #endif diff --git a/src/MSL/FILE_POS.c b/src/MSL/FILE_POS.c new file mode 100644 index 00000000..8619b385 --- /dev/null +++ b/src/MSL/FILE_POS.c @@ -0,0 +1,103 @@ +#include "buffer_io.h" +#include "file_struct.h" +#include "errno.h" + +#pragma exceptions on + +long _ftell(FILE* pFile) { + int buf = 0; + long pos; + + unsigned char file_kind = pFile->mode.file; + + if (!(file_kind == file_disk || file_kind == file_console) || + pFile->state.error) { + errno = 40; + return -1; + } + + if (pFile->state.io_state == neutral) { + return pFile->pos; + } + + pos = pFile->buffer_pos + (pFile->buffer_ptr - pFile->buffer); + + if (pFile->state.io_state >= rereading) { + buf = pFile->state.io_state - rereading + 1; + pos -= buf; + } + + if (!pFile->mode.binary) { + long dist = pFile->buffer_ptr - pFile->buffer - buf; + unsigned char* cur_buf = pFile->buffer; + + while (dist--) { + if (*cur_buf++ == '\n') { + pos++; + } + } + } + + return pos; +} + +long ftell(FILE* pFile) { + return _ftell(pFile); +} + +int _fseek(FILE* pFile, long offs, int file_mode) { + __pos_proc position_proc_func; + unsigned char file_kind = pFile->mode.file; + + if (!(file_kind == file_disk) || pFile->state.error) { + errno = 40; + return -1; + } + + if (pFile->state.io_state == writing) { + if (__flush_buffer(pFile, 0) != 0) { + pFile->state.error = 1; + pFile->buffer_len = 0; + errno = 40; + return -1; + } + } + + if (file_mode == 1) { + file_mode = 0; + offs += _ftell(pFile); + } + + if ((file_mode != 2) && (pFile->mode.io != 3) && + ((pFile->state.io_state == reading) || + (pFile->state.io_state == rereading))) { + if ((offs >= pFile->pos || offs < pFile->buffer_pos)) { + pFile->state.io_state = neutral; + } else { + pFile->buffer_ptr = pFile->buffer + (offs - pFile->buffer_pos); + pFile->buffer_len = pFile->pos - offs; + pFile->state.io_state = reading; + } + } else { + pFile->state.io_state = neutral; + } + + if (pFile->state.io_state == neutral) { + position_proc_func = pFile->pos_proc; + + if (position_proc_func != 0 && + (*position_proc_func)(pFile->handle, &offs, file_mode, + pFile->ref)) { + pFile->state.error = 1; + pFile->buffer_len = 0; + errno = 40; + return -1; + } + + pFile->state.eof = 0; + pFile->pos = offs; + pFile->buffer_len = 0; + } + + return 0; +} diff --git a/src/MSL/abort_exit_ppc_eabi.c b/src/MSL/abort_exit_ppc_eabi.c new file mode 100644 index 00000000..9ad5aa34 --- /dev/null +++ b/src/MSL/abort_exit_ppc_eabi.c @@ -0,0 +1 @@ +void (*__stdio_exit)(void); diff --git a/src/MSL/alloc.c b/src/MSL/alloc.c new file mode 100644 index 00000000..2397bbe4 --- /dev/null +++ b/src/MSL/alloc.c @@ -0,0 +1,210 @@ +#include "alloc.h" + +#pragma exceptions on + +void __sys_free(void* ptr); +void* memset(void*, int, int); + +static void SubBlock_merge_next(SubBlock*, SubBlock**); + +inline static SubBlock* SubBlock_merge_prev(SubBlock* ths, SubBlock** start) { + unsigned long prevsz; + SubBlock* p; + + if (!(ths->size & 0x04)) { + prevsz = *(unsigned long*)((char*)ths - sizeof(unsigned long)); + if (prevsz & 0x2) + return ths; + p = (SubBlock*)((char*)ths - prevsz); + SubBlock_set_size(p, prevsz + SubBlock_size(ths)); + + if (*start == ths) + *start = (*start)->next; + ths->next->prev = ths->prev; + ths->next->prev->next = ths->next; + return p; + } + return ths; +} + +void Block_link(Block* ths, SubBlock* sb) { + SubBlock** st; + SubBlock_set_free(sb); + st = &Block_start(ths); + + if (*st != 0) { + sb->prev = (*st)->prev; + sb->prev->next = sb; + sb->next = *st; + (*st)->prev = sb; + *st = sb; + *st = SubBlock_merge_prev(*st, st); + SubBlock_merge_next(*st, st); + } else { + *st = sb; + sb->prev = sb; + sb->next = sb; + } + if (ths->max_size < SubBlock_size(*st)) + ths->max_size = SubBlock_size(*st); +} + +static void SubBlock_merge_next(SubBlock* pBlock, SubBlock** pStart) { + SubBlock* next_sub_block; + unsigned long this_cur_size; + + next_sub_block = (SubBlock*)((char*)pBlock + (pBlock->size & 0xFFFFFFF8)); + + if (!(next_sub_block->size & 2)) { + this_cur_size = + (pBlock->size & 0xFFFFFFF8) + (next_sub_block->size & 0xFFFFFFF8); + + pBlock->size &= ~0xFFFFFFF8; + pBlock->size |= this_cur_size & 0xFFFFFFF8; + + if (!(pBlock->size & 2)) { + *(unsigned long*)((char*)(pBlock) + (this_cur_size)-4) = + (this_cur_size); + } + + if (!(pBlock->size & 2)) { + *(unsigned long*)((char*)pBlock + this_cur_size) &= ~4; + } else { + *(unsigned long*)((char*)pBlock + this_cur_size) |= 4; + } + + if (*pStart == next_sub_block) { + *pStart = (*pStart)->next; + } + + if (*pStart == next_sub_block) { + *pStart = 0; + } + + next_sub_block->next->prev = next_sub_block->prev; + next_sub_block->prev->next = next_sub_block->next; + } +} + +inline static Block* __unlink(__mem_pool_obj* pool_obj, Block* bp) { + Block* result = bp->next; + if (result == bp) { + result = 0; + } + + if (pool_obj->start_ == bp) { + pool_obj->start_ = result; + } + + if (result != 0) { + result->prev = bp->prev; + result->prev->next = result; + } + + bp->next = 0; + bp->prev = 0; + return result; +} + +inline static void deallocate_from_var_pools(__mem_pool_obj* pool_obj, + void* ptr) { + SubBlock* sb = SubBlock_from_pointer(ptr); + SubBlock* _sb; + + Block* bp = SubBlock_block(sb); + Block_link(bp, sb); + + if (Block_empty(bp)) { + __unlink(pool_obj, bp); + __sys_free(bp); + } +} + +void deallocate_from_fixed_pools(__mem_pool_obj* pool_obj, void* ptr, + unsigned long size) { + unsigned long i = 0; + FixSubBlock* p; + FixBlock* b; + FixStart* fs; + + while (size > fix_pool_sizes[i]) { + ++i; + } + + fs = &pool_obj->fix_start[i]; + p = FixSubBlock_from_pointer(ptr); + b = p->block_; + + if (b->start_ == 0 && fs->head_ != b) { + if (fs->tail_ == b) { + fs->head_ = fs->head_->prev_; + fs->tail_ = fs->tail_->prev_; + } else { + b->prev_->next_ = b->next_; + b->next_->prev_ = b->prev_; + b->next_ = fs->head_; + b->prev_ = b->next_->prev_; + b->prev_->next_ = b; + b->next_->prev_ = b; + fs->head_ = b; + } + } + + p->next_ = b->start_; + b->start_ = p; + + if (--b->n_allocated_ == 0) { + if (fs->head_ == b) { + fs->head_ = b->next_; + } + + if (fs->tail_ == b) { + fs->tail_ = b->prev_; + } + + b->prev_->next_ = b->next_; + b->next_->prev_ = b->prev_; + + if (fs->head_ == b) { + fs->head_ = 0; + } + + if (fs->tail_ == b) { + fs->tail_ = 0; + } + + deallocate_from_var_pools(pool_obj, b); + } +} + +inline void __pool_free(__mem_pool* pool, void* ptr) { + __mem_pool_obj* pool_obj; + unsigned long size; + + if (ptr == 0) { + return; + } + + pool_obj = (__mem_pool_obj*)pool; + size = __msize_inline(ptr); + + if (size <= 68) { + deallocate_from_fixed_pools(pool_obj, ptr, size); + } else { + deallocate_from_var_pools(pool_obj, ptr); + } +} + +void free(void* ptr) { + static unsigned char init = 0; + static __mem_pool protopool; + __mem_pool* pool; + + if (!init) { + memset(&protopool, 0, sizeof(__mem_pool_obj)); + init = 1; + } + + pool = &protopool; + __pool_free(pool, ptr); +} diff --git a/src/MSL/ansi_files.c b/src/MSL/ansi_files.c new file mode 100644 index 00000000..80991aa7 --- /dev/null +++ b/src/MSL/ansi_files.c @@ -0,0 +1,128 @@ +#include "ansi_files.h" + +#include "uart_console_io_gcn.h" +#include "stdio.h" +#include "stdlib.h" +#include "file_struct.h" + +FILE __stdout_FILE; +FILE __stderr_FILE; + +// Force __file_terminator to the .data section instead .bss +#pragma push +#pragma explicit_zero_data on +#pragma section data_type ".data" +FILE __file_terminator = {0}; // lbl_80398888 +#pragma pop + +#pragma exceptions on + +FILE __files[1] = {{ + 0, + { must_exist, read, _IOLBF, file_console, file_unoriented, 0 }, + { neutral, 0, 0, 0 }, + 0, + 0, + 0, + {0}, + {0}, + 0, + stdin_buff, + console_buff_size, + stdin_buff, + 0, + 0, + 0, + 0, + NULL, + __read_console, + __write_console, + __close_console, + NULL, + &__stdout_FILE + }}; + +FILE __stdout_FILE = { + 1, + { must_exist, write, _IOLBF, file_console, file_unoriented, 0 }, + { neutral, 0, 0, 0 }, + 0, + 0, + 0, + {0}, + {0}, + 0, + stdout_buff, + console_buff_size, + stdout_buff, + 0, + 0, + 0, + 0, + NULL, + __read_console, + __write_console, + __close_console, + NULL, + &__stderr_FILE +}; + +FILE __stderr_FILE = { + 2, + { must_exist, write, _IONBF, file_console, file_unoriented, 0 }, + { neutral, 0, 0, 0 }, + 0, + 0, + 0, + {0}, + {0}, + 0, + stderr_buff, + console_buff_size, + stderr_buff, + 0, + 0, + 0, + 0, + NULL, + __read_console, + __write_console, + __close_console, + NULL, + &__file_terminator +}; + +void __close_all() { + FILE* p = &__files[0]; + FILE* plast; + + while (p) { + if (p->mode.file != file_closed) { + fclose(p); + } + + plast = p; + p = p->next_file; + if (plast->is_dyn_alloc) { + free(plast); + } else { + plast->mode.file = file_unavailable; + if ((p != NULL) && p->is_dyn_alloc) { + plast->next_file = NULL; + } + } + } +} + +u32 __flush_all() { + u32 retval = 0; + FILE* __stream; + __stream = &__files[0]; + while (__stream) { + if ((__stream->mode.file) && (fflush(__stream))) { + retval = -1; + } + __stream = __stream->next_file; + }; + return retval; +} diff --git a/src/MSL/ansi_fp.c b/src/MSL/ansi_fp.c new file mode 100644 index 00000000..a63ebf42 --- /dev/null +++ b/src/MSL/ansi_fp.c @@ -0,0 +1,804 @@ +#include "ansi_fp.h" +#include "math_api.h" +#include "float.h" +#include "limits.h" + +#pragma exceptions on + +const signed char __fp_string_pool[] = + "542101086242752217003726400434970855712890625\000" + "11102230246251565404236316680908203125\000" + "23283064365386962890625\000" + "152587890625\000" + "390625\000" + "78125\000" + "15625\000" + "3125\000" + "625\000" + "125\000" + "25\000" + "5\000" + "1\000" + "2\000" + "4\000" + "8\000" + "16\000" + "32\000" + "64\000" + "128\000" + "256\000" + "179769313486231580793728714053034151\000\000\000"; + +const unsigned short __ctype_mapC[0x100] = { + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 0x106, 0x104, 0x104, 0x104, 0x104, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0x142, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0x458, 0x458, 0x458, 0x458, 0x458, 0x458, 0x458, 0x458, + 0x458, 0x458, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0x651, 0x651, 0x651, 0x651, 0x651, 0x651, 0x251, + 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, + 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, + 0x251, 0x251, 0x251, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0x471, 0x471, 0x471, 0x471, 0x471, 0x471, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0xd0, 0xd0, 0xd0, 0xd0, 4}; + +const unsigned char __lower_mapC[0x100] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\', ']', '^', '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF}; + +const unsigned char __upper_mapC[0x100] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + ' ', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 0x7F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF}; + +const char _DateTime_Format_C[] = "%a %b %e %T %Y\0"; +const char _Time_Format_12_C[] = "%I:%M:%S %p"; +const char _Date_Format_C[] = "%m/%d/%y\0\0\0"; +const char _Day_Names_C[] = "Sun|Sunday|Mon|Monday|Tue|Tuesday|Wed|Wednesday|Thu|Thursday|Fri|Friday|Sat|Saturday\0\0\0"; +const char _Month_Names_C[] = "Jan|January|Feb|February|Mar|March|Apr|April|May|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December\0\0"; + +#define SIGDIGLEN 36 +extern double pow(double, double); + +inline int count_trailing(double x) { + return __builtin___count_trailing_zero64(*(unsigned long long*)&x | 0x0010000000000000); +} + +static inline void __dorounddecup(decimal* d, int digits) { + u8* b = d->sig.text; + u8* i = b + digits - 1; + + while (1) { + if (*i < 9) { + *i += 1; + break; + } + if (i == b) { + *i = 1; + d->exponent++; + break; + } + *i-- = 0; + } +} + +static inline int __must_round(const decimal* d, int digits) { + // regswap fun here + u8 const* i = d->sig.text + digits; + + if (*i > 5) { + return 1; + } + + if (*i < 5) { + return -1; + } + + for (i++; i < d->sig.text + d->sig.length; i++) { + if (*i != 0) { + return 1; + } + } + + if (d->sig.text[digits - 1] & 1) { + return 1; + } + + return -1; +} + +static inline void __rounddec(decimal* d, int digits) { + u8* i; + u8* b; + + if (digits > 0 && digits < d->sig.length) { + int unkBool = __must_round(d, digits); + d->sig.length = digits; + + if (unkBool >= 0) { + // using __dorounddecup causes r4 and r5 registers to swap + // __dorounddecup(d, digits); + // manually inlined code from __dorounddecup: + + b = d->sig.text; + i = b + digits - 1; + + while (1) { + if (*i < 9) { + *i += 1; + break; + } + if (i == b) { + *i = 1; + d->exponent++; + break; + } + *i-- = 0; + } + } + } +} + +void __ull2dec(decimal* pDecimal, unsigned long long input) { + pDecimal->sign = 0; + pDecimal->sig.length = 0; + + for (; input != 0; input /= 10) { + pDecimal->sig.text[pDecimal->sig.length++] = + (unsigned char)(input % 10); + } + + /* regswap if these were declared at the top...only logic I can think of is making them valid in this block */ + { + unsigned char* start = pDecimal->sig.text; + unsigned char* end = pDecimal->sig.text + pDecimal->sig.length; + + for (; start < --end; ++start) { + unsigned char t = *start; + *start = *end; + *end = t; + } + } + + pDecimal->exponent = (short)(pDecimal->sig.length - 1); +} + +void __timesdec(decimal* pResult, const decimal* x, const decimal* y) { + unsigned long accumulator = 0; + unsigned char mant[72]; + int i = x->sig.length + y->sig.length - 1; + unsigned char* ip = mant + i + 1; + unsigned char* ep = ip; + pResult->sign = 0; + + for (; i > 0; --i) { + int k = y->sig.length - 1; + int j = i - k - 1; + int l; + int t; + unsigned char const *jp, *kp; + + if (j < 0) { + j = 0; + k = i - 1; + } + + jp = x->sig.text + j; + kp = y->sig.text + k; + l = k + 1; + t = x->sig.length - j; + + if (l > t) { + l = t; + } + + for (; l > 0; --l, ++jp, --kp) { + accumulator += (unsigned long)(*jp) * *kp; + } + + *--ip = (unsigned char)(accumulator % 10); + accumulator /= 10; + } + + pResult->exponent = (short)(x->exponent + y->exponent); + + if (accumulator > 0) { + *--ip = (unsigned char)accumulator; + pResult->exponent++; + } + + for (i = 0; i < 36 && ip < ep; ++i, ++ip) { + pResult->sig.text[i] = *ip; + } + + pResult->sig.length = i; + + if (ip < ep && *ip >= 5) { + if (*ip == 5) { + unsigned char* jp = ip + 1; + for (; jp < ep; ++jp) { + if (*jp != 0) { + goto round; + } + } + + if ((*(ip - 1) & 1) == 0) { + return; + } + } + round: + __dorounddecup(pResult, pResult->sig.length); + } +} + +void __str2dec(decimal* pDecimal, const char* pStr, short exp) { + int i; + pDecimal->exponent = exp; + pDecimal->sign = 0; + + for (i = 0; i < 36 && *pStr != 0;) { + pDecimal->sig.text[i++] = (unsigned char)(*pStr++ - '0'); + } + + pDecimal->sig.length = i; + + if (*pStr != 0) { + if (*pStr < 5) { + return; + } + + if (*pStr > 5) { + goto round; + } + + { + const char* p = pStr + 1; + for (; *p != 0; ++p) { + if (*p != '0') { + goto round; + } + } + + if ((pDecimal->sig.text[i - 1] & 1) == 0) { + return; + } + } + + round: + __dorounddecup(pDecimal, pDecimal->sig.length); + } +} + +static void __two_exp(decimal* pDecimal, long exp) { + switch (exp) { + case -64: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0], -20); + return; + case -53: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x2E], -16); + return; + case -32: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x55], -10); + return; + case -16: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x6D], -5); + return; + case -8: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x7A], -3); + return; + case -7: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x81], -3); + return; + case -6: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x87], -2); + return; + case -5: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x8D], -2); + return; + case -4: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x92], -2); + return; + case -3: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x96], -1); + return; + case -2: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x9A], -1); + return; + case -1: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x9D], -1); + return; + case 0: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0x9F], 0); + return; + case 1: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0xA1], 0); + return; + case 2: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0xA3], 0); + return; + case 3: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0xA5], 0); + return; + case 4: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0xA7], 1); + return; + case 5: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0xAA], 1); + return; + case 6: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0xAD], 1); + return; + case 7: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0xB0], 2); + return; + case 8: + __str2dec(pDecimal, (const char*)&__fp_string_pool[0xB4], 2); + return; + } + + { + decimal x2, temp; + __two_exp(&x2, ((long)((0x80000000UL & exp) >> 31) + exp) >> 1); + __timesdec(pDecimal, &x2, &x2); + if (exp & 1) { + temp = *pDecimal; + if (exp > 0) + __str2dec(&x2, (const char*)&__fp_string_pool[0xA1], 0); + else + __str2dec(&x2, (const char*)&__fp_string_pool[0x9D], -1); + __timesdec(pDecimal, &temp, &x2); + } + } +} + +int __equals_dec(const decimal* x, const decimal* y) { + if (x->sig.text[0] == 0) { + if (y->sig.text[0] == 0) { + return 1; + } + + return 0; + } + + if (y->sig.text[0] == 0) { + if (x->sig.text[0] == 0) { + return 1; + } + + return 0; + } + + if (x->exponent == y->exponent) { + int i; + int l = x->sig.length; + + if (l > y->sig.length) { + l = y->sig.length; + } + + for (i = 0; i < l; ++i) { + if (x->sig.text[i] != y->sig.text[i]) { + return 0; + } + } + + if (l == x->sig.length) { + x = y; + } + + for (; i < x->sig.length; ++i) { + if (x->sig.text[i] != 0) { + return 0; + } + } + + return 1; + } + + return 0; +} + +static int __less_dec(const decimal* x, const decimal* y) { + if (x->sig.text[0] == 0) { + if (y->sig.text[0] != 0) { + return 1; + } + + return 0; + } + + if (y->sig.text[0] == 0) { + return 0; + } + + if (x->exponent == y->exponent) { + int i; + int l = x->sig.length; + + if (l > y->sig.length) { + l = y->sig.length; + } + + for (i = 0; i < l; ++i) { + if (x->sig.text[i] < y->sig.text[i]) { + return 1; + } + + if (y->sig.text[i] < x->sig.text[i]) { + return 0; + } + } + + if (l == x->sig.length) { + for (; i < y->sig.length; ++i) { + if (y->sig.text[i] != 0) { + return 1; + } + } + } + + return 0; + } + + return x->exponent < y->exponent; +} + +void __minus_dec(decimal* z, const decimal* x, const decimal* y) { + int zlen, dexp; + unsigned char *ib, *i, *ie; + unsigned char const *jb, *j, *jn; + *z = *x; + + if (y->sig.text[0] == 0) { + return; + } + + zlen = z->sig.length; + + if (zlen < y->sig.length) { + zlen = y->sig.length; + } + + dexp = z->exponent - y->exponent; + zlen += dexp; + + if (zlen > 36) { + zlen = 36; + } + + while (z->sig.length < zlen) { + z->sig.text[z->sig.length++] = 0; + } + + ib = z->sig.text; + i = ib + zlen; + + if (y->sig.length + dexp < zlen) { + i = ib + (y->sig.length + dexp); + } + + jb = y->sig.text; + j = jb + (i - ib - dexp); + jn = j; + + while (i > ib && j > jb) { + --i; + --j; + if (*i < *j) { + unsigned char* k = i - 1; + while (*k == 0) { + --k; + } + while (k != i) { + --*k; + *++k += 10; + } + } + + *i -= *j; + } + + if (jn - jb < y->sig.length) { + BOOL round_down = FALSE; + if (*jn < 5) { + round_down = TRUE; + } else if (*jn == 5) { + unsigned char const* je = y->sig.text + y->sig.length; + + for (j = jn + 1; j < je; ++j) { + if (*j != 0) { + goto done; + } + } + + i = ib + (jn - jb) + dexp - 1; + + if (*i & 1) { + round_down = 1; + } + } + if (round_down) { + if (*i < 1) { + unsigned char* k = i - 1; + + while (*k == 0) { + --k; + } + while (k != i) { + --*k; + *++k += 10; + } + } + + *i -= 1; + } + } + +done: + for (i = ib; *i == 0; ++i) + ; + + if (i > ib) { + unsigned char dl = (unsigned char)(i - ib); + z->exponent -= dl; + ie = ib + z->sig.length; + for (; i < ie; ++i, ++ib) + *ib = *i; + z->sig.length -= dl; + } + + ib = z->sig.text; + + for (i = ib + z->sig.length; i > ib;) { + --i; + if (*i != 0) { + break; + } + } + + z->sig.length = (unsigned char)(i - ib + 1); +} + +void __num2dec_internal(decimal* pDecimal, double x) { + char sign = (char)(__signbitd(x) != 0); + if (x == 0.0) { + pDecimal->sign = sign; + pDecimal->exponent = 0; + pDecimal->sig.length = 1; + pDecimal->sig.text[0] = 0; + return; + } + + if (!(__fpclassifyd(x) > 2)) { + pDecimal->sign = sign; + pDecimal->exponent = 0; + pDecimal->sig.length = 1; + pDecimal->sig.text[0] = + (unsigned char)(__fpclassifyd(x) == 1 ? 'N' : 'I'); + return; + } + + if (sign) { + x = -x; + } + + { + int exp; + double frac = frexp(x, &exp); + long num_bits_extract = 53 - count_trailing(frac); + decimal int_d, pow2_d; + __two_exp(&pow2_d, exp - num_bits_extract); + __ull2dec(&int_d, + (unsigned long long)ldexp(frac, (int)num_bits_extract)); + __timesdec(pDecimal, &int_d, &pow2_d); + pDecimal->sign = sign; + } +} + +void __num2dec(const decform* form, double val, decimal* d) { + short digits = form->digits; + int i; + __num2dec_internal(d, val); + + if (d->sig.text[0] > 9) { + return; + } + + if (digits > SIGDIGLEN) { + digits = SIGDIGLEN; + } + + __rounddec(d, digits); + + while (d->sig.length < digits) { + d->sig.text[d->sig.length++] = 0; + } + + d->exponent -= d->sig.length - 1; + + for (i = 0; i < d->sig.length; i++) { + d->sig.text[i] += '0'; + } +} + +double __dec2num(const decimal* d) { + if (d->sig.length <= 0) { + return copysign(0.0, d->sign == 0 ? 1.0 : -1.0); + } + + switch (d->sig.text[0]) { + case '0': + return copysign(0.0, d->sign == 0 ? 1.0 : -1.0); + case 'I': + return copysign((double)INFINITY, d->sign == 0 ? 1.0 : -1.0); + case 'N': { + double result; + long long* ll = (long long*)&result; + *ll = 0x7FF0000000000000ULL; + if (d->sign) + *ll |= 0x8000000000000000ULL; + *ll |= 0x0008000000000000ULL; + + return result; + } + } + { + static double pow_10[8] = {1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8}; + decimal dec = *d; + unsigned char* i = dec.sig.text; + unsigned char* e = i + dec.sig.length; + double first_guess; + int exponent; + + for (; i < e; ++i) { + *i -= '0'; + } + + dec.exponent += dec.sig.length - 1; + exponent = dec.exponent; + { + decimal max; + __str2dec(&max, (const char*)&__fp_string_pool[0xB8], 308); + if (__less_dec(&max, &dec)) { + return copysign((double)INFINITY, d->sign == 0 ? 1.0 : -1.0); + } + } + + i = dec.sig.text; + first_guess = *i++; + + while (i < e) { + unsigned long ival = 0; + int j; + double temp1, temp2; + int ndig = (int)(e - i) % 8; + + if (ndig == 0) { + ndig = 8; + } + + for (j = 0; j < ndig; ++j, ++i) { + ival = ival * 10 + *i; + } + + temp1 = first_guess * pow_10[ndig - 1]; + temp2 = temp1 + ival; + + if (ival != 0 && temp1 == temp2) { + break; + } + + first_guess = temp2; + exponent -= ndig; + } + if (exponent < 0) { + first_guess /= pow(5.0, -exponent); + } else { + first_guess *= pow(5.0, exponent); + } + + first_guess = ldexp(first_guess, exponent); + + if (__fpclassifyd(first_guess) == 2) { + first_guess = DBL_MAX; + } + { + decimal feedback1, feedback2, difflow, diffhigh; + double next_guess; + long long* ull = (long long*)&next_guess; + int guessed_low = 0; + __num2dec_internal(&feedback1, first_guess); + + if (__equals_dec(&feedback1, &dec)) { + goto done; + } + + if (__less_dec(&feedback1, &dec)) { + guessed_low = 1; + } + + next_guess = first_guess; + while (1) { + if (guessed_low) { + ++*ull; + if (__fpclassifyd(next_guess) != 2) { + ; // this makes it match somehow + } else { + goto done; + } + } else { + --*ull; + } + + __num2dec_internal(&feedback2, next_guess); + if (guessed_low && !__less_dec(&feedback2, &dec)) { + break; + } else if (!guessed_low && !__less_dec(&dec, &feedback2)) { + difflow = feedback1; + feedback1 = feedback2; + feedback2 = difflow; + { + double temp = first_guess; + first_guess = next_guess; + next_guess = temp; + } + break; + } + feedback1 = feedback2; + first_guess = next_guess; + } + + __minus_dec(&difflow, &dec, &feedback1); + __minus_dec(&diffhigh, &feedback2, &dec); + if (__equals_dec(&difflow, &diffhigh)) { + if (*(long long*)&first_guess & 1) { + first_guess = next_guess; + } + } else if (!__less_dec(&difflow, &diffhigh)) { + first_guess = next_guess; + } + } + done: + if (dec.sign) { + first_guess = -first_guess; + } + return first_guess; + } +} + +const char _Decimal_Point_C[] = ".\0\0"; +const int _const_int_0 = 0; +const char _AmPm_Format_C[] = "AM|PM\0\0"; +const char _Time_Format_C[] = "%T\0\0\0\0\0"; diff --git a/src/MSL/arith.c b/src/MSL/arith.c new file mode 100644 index 00000000..fc272e35 --- /dev/null +++ b/src/MSL/arith.c @@ -0,0 +1,5 @@ +#include "arith.h" + +int abs(int x) { + return ((x >> 31) ^ x) - (x >> 31); +} diff --git a/src/MSL/buffer_io.c b/src/MSL/buffer_io.c new file mode 100644 index 00000000..842d302d --- /dev/null +++ b/src/MSL/buffer_io.c @@ -0,0 +1,37 @@ +#include "buffer_io.h" + +#pragma exceptions on + +void __prep_buffer(FILE* pFile) { + pFile->buffer_ptr = pFile->buffer; + pFile->buffer_len = pFile->buffer_size; + pFile->buffer_len -= pFile->pos & pFile->buffer_alignment; + pFile->buffer_pos = pFile->pos; +} + +int __flush_buffer(FILE* pFile, size_t* pFlushed) { + size_t len; + int res; + + len = pFile->buffer_ptr - pFile->buffer; + + if (len != 0) { + pFile->buffer_len = len; + + res = (*pFile->write_proc)(pFile->handle, pFile->buffer, + (size_t*)&pFile->buffer_len, pFile->ref); + + if (pFlushed != 0) { + *pFlushed = pFile->buffer_len; + } + + if (res != 0) { + return res; + } + + pFile->pos += pFile->buffer_len; + } + + __prep_buffer(pFile); + return 0; +} diff --git a/src/MSL/direct_io.c b/src/MSL/direct_io.c new file mode 100644 index 00000000..cc137c54 --- /dev/null +++ b/src/MSL/direct_io.c @@ -0,0 +1,116 @@ +#include "buffer_io.h" +#include "file_struct.h" +#include "wchar_io.h" + +#pragma exceptions on + +size_t __fwrite(const void *pPtr, size_t memb_size, size_t num_memb, FILE *pFile) { + unsigned char* cur_ptr; + size_t num_bytes, rem_bytes, bytes_written; + int res, buff; + + if (fwide(pFile, 0) == 0) { + fwide(pFile, -1); + } + + rem_bytes = memb_size * num_memb; + + if (rem_bytes == 0 || pFile->state.error || pFile->mode.file == 0) { + return 0; + } + + if (pFile->mode.file == 2) { + __stdio_atexit(); + } + + buff = (!pFile->mode.binary || pFile->mode.buffer == 2 || pFile->mode.buffer == 1); + + if (pFile->state.io_state == 0 && pFile->mode.io & 2) { + if (pFile->mode.io & 4) { + if (_fseek(pFile, 0, 2)) { + return 0; + } + } + + pFile->state.io_state = 1; + __prep_buffer(pFile); + } + + if (pFile->state.io_state != 1) { + pFile->state.error = 1; + pFile->buffer_len = 0; + return 0; + } + + cur_ptr = (unsigned char*)pPtr; + bytes_written = 0; + + if (rem_bytes && (pFile->buffer_ptr != pFile->buffer || buff)) { + pFile->buffer_len = pFile->buffer_size - (pFile->buffer_ptr - pFile->buffer); + + do { + unsigned char* nw = 0; + num_bytes = pFile->buffer_len; + + if (num_bytes > rem_bytes) { + num_bytes = rem_bytes; + } + + if (pFile->mode.buffer == 1 && num_bytes) { + if ((nw = (unsigned char*) __memrchr(cur_ptr, '\n', num_bytes)) != 0) { + num_bytes = nw + 1 - cur_ptr; + } + } + + if (num_bytes != 0) { + memcpy(pFile->buffer_ptr, cur_ptr, num_bytes); + cur_ptr += num_bytes; + rem_bytes -= num_bytes; + pFile->buffer_ptr += num_bytes; + pFile->buffer_len -= num_bytes; + } + + if (pFile->buffer_len == 0 || nw != 0 || (!pFile->mode.buffer)) { + res = __flush_buffer(pFile, 0); + + if (res != 0) { + pFile->state.error = 1; + pFile->buffer_len = 0; + rem_bytes = 0; + break; + } + } + + bytes_written += num_bytes; + + } while(rem_bytes && buff); + } + + if (rem_bytes && buff == 0) { + unsigned char* save_buf = pFile->buffer; + size_t save_size = pFile->buffer_size; + + pFile->buffer = cur_ptr; + pFile->buffer_size = rem_bytes; + pFile->buffer_ptr = cur_ptr + rem_bytes; + + if (__flush_buffer(pFile, &num_bytes) != 0) { + pFile->state.error = 1; + pFile->buffer_len = 0; + } + else { + bytes_written += num_bytes; + } + + pFile->buffer = save_buf; + pFile->buffer_size = save_size; + __prep_buffer(pFile); + pFile->buffer_len = 0; + } + + if (pFile->mode.buffer != 2) { + pFile->buffer_len = 0; + } + + return bytes_written / memb_size; +} diff --git a/src/MSL/errno.c b/src/MSL/errno.c new file mode 100644 index 00000000..6e7bb62b --- /dev/null +++ b/src/MSL/errno.c @@ -0,0 +1 @@ +int errno; diff --git a/src/MSL/extras.c b/src/MSL/extras.c new file mode 100644 index 00000000..1d76087c --- /dev/null +++ b/src/MSL/extras.c @@ -0,0 +1,28 @@ +#include "locale.h" + +inline int tolower_inline(int c) { + return ((c < 0) || (c >= 0x100)) + ? c + : (int)(_current_locale.ctype_cmpt_ptr->lower_map_ptr[c]); +} + +int stricmp(const char* s1, const char* s2) { + char c1, c2; + + while (1) { + c1 = tolower_inline(*s1++); + c2 = tolower_inline(*s2++); + + if (c1 < c2) { + return -1; + } + + if (c1 > c2) { + return 1; + } + + if (c1 == 0) { + return 0; + } + } +} diff --git a/src/MSL/file_io.c b/src/MSL/file_io.c new file mode 100644 index 00000000..078aa397 --- /dev/null +++ b/src/MSL/file_io.c @@ -0,0 +1,72 @@ +#include "file_io.h" + +#pragma exceptions on + +int fclose(FILE* pFile) { + int flush_res, close_res; + + if (pFile == 0) { + return -1; + } + + if (pFile->mode.file == file_closed) { + return 0; + } + + flush_res = fflush(pFile); + close_res = (*pFile->close_proc)(pFile->handle); + pFile->mode.file = file_closed; + pFile->handle = 0; + + if (pFile->state.free_buffer) { + free(pFile->buffer); + } + + return ((flush_res || close_res) ? -1 : 0); +} + +int fflush(FILE* pFile) { + long pos; + + if (pFile == 0) { + return __flush_all(); + } + + if (pFile->state.error || pFile->mode.file == file_closed) { + return -1; + } + + if (pFile->mode.io == read) { + return 0; + } + + if (pFile->state.io_state >= rereading) { + pFile->state.io_state = reading; + } + + if (pFile->state.io_state == reading) { + pFile->buffer_len = 0; + } + + if (pFile->state.io_state != writing) { + pFile->state.io_state = neutral; + return 0; + } + + if (pFile->mode.file != file_disk) { + pos = 0; + } else { + pos = ftell(pFile); + } + + if (__flush_buffer(pFile, 0)) { + pFile->state.error = 1; + pFile->buffer_len = 0; + return -1; + } + + pFile->state.io_state = neutral; + pFile->pos = pos; + pFile->buffer_len = 0; + return 0; +} diff --git a/src/MSL/locale.c b/src/MSL/locale.c new file mode 100644 index 00000000..1a3828bb --- /dev/null +++ b/src/MSL/locale.c @@ -0,0 +1,122 @@ +#include "locale.h" +#include "mbstring.h" +#include "ctype.h" +#include "wctype.h" +#include "ansi_fp.h" + +struct lconv __lconv = { + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 127, + 127, + 127, + 127, + 127, + 127, + 127, + 0, + 127, + 127, + 127, + 127, + 127, + 127, + 127 +}; + +typedef struct __CMap { + char UNK_0x0[0x10]; + const u8* to_lower_table; // at 0x10 + const u8* to_upper_table; // at 0x14 +} __CMap; + +struct _loc_ctype_cmpt _loc_ctyp_C = { + "C", + &__ctype_mapC[0], + &__upper_mapC[0], + &__lower_mapC[0], + &__wctype_mapC[0], + &__wupper_mapC[0], + &__wlower_mapC[0], + __mbtowc_noconv, + __wctomb_noconv +}; + +unsigned short char_coll_tableC[0x60] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x2b, 0x2d, 0x2f, 0x31, 0x33, 0x35, 0x37, 0x39, 0x3b, 0x3d, 0x3f, 0x41, 0x43, 0x45, 0x47, + 0x49, 0x4b, 0x4d, 0x4f, 0x51, 0x53, 0x55, 0x57, 0x59, 0x5b, 0x5d, 0x18, 0x19, 0x1a, 0x1b, 0x1c, + 0x00, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, + 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x1d, 0x1e, 0x1f, 0x20 +}; + +struct _loc_coll_cmpt _loc_coll_C = { + "C", + 0x20, + 0x6E, + 0, + (unsigned short*)&char_coll_tableC[0], + 0 +}; + +struct _loc_mon_cmpt _loc_mon_C = { + "C", + 0, + 0, + 0, + 0, + 0, + 0, + 127, + 127, + 127, + 127, + 127, + 127, + 127, + 0, + 127, + 127, + 127, + 127, + 127, + 127, + 127 +}; + +struct _loc_num_cmpt _loc_num_C = { + "C", + 0, + 0, + 0 +}; + +struct _loc_time_cmpt _loc_tim_C = { + "C", + _AmPm_Format_C, + _DateTime_Format_C, + _Time_Format_12_C, + _Date_Format_C, + _Time_Format_C, + _Day_Names_C, + _Month_Names_C, + 0 +}; + +struct __locale _current_locale = { + 0, + "C", + &_loc_coll_C, + &_loc_ctyp_C, + &_loc_mon_C, + &_loc_num_C, + &_loc_tim_C +}; diff --git a/src/MSL/math_api.c b/src/MSL/math_api.c new file mode 100644 index 00000000..78319ecc --- /dev/null +++ b/src/MSL/math_api.c @@ -0,0 +1,32 @@ +#include "math_api.h" + +#pragma exceptions on + +int __signbitd(double dbl) { + return (*(int*)&dbl) & 0x80000000; +} + +int __fpclassifyd(double dbl) { + switch ((*(int*)&dbl) & 0x7FF00000) { + case 0x7FF00000: + if (((*(int*)&dbl) & 0xFFFFF) || (*(1 + (int*)&dbl)) & 0xFFFFFFFF) { + return 1; + } + else { + return 2; + } + + break; + case 0: + if (((*(int*)&dbl) & 0xFFFFF) || (*(1 + (int*)&dbl)) & 0xFFFFFFFF) { + return 5; + } + else { + return 3; + } + + break; + } + + return 4; +} diff --git a/src/MSL/math_float.c b/src/MSL/math_float.c new file mode 100644 index 00000000..b71c85ac --- /dev/null +++ b/src/MSL/math_float.c @@ -0,0 +1,8 @@ +asm float fabsf(float x) { + nofralloc + + frsp f0, f1 + fabs f0, f0 + frsp f1, f0 + blr +} diff --git a/src/MSL/math_sun.c b/src/MSL/math_sun.c new file mode 100644 index 00000000..e5be11e3 --- /dev/null +++ b/src/MSL/math_sun.c @@ -0,0 +1,13 @@ +#include "math.h" + +#pragma exceptions on + +double scalbn(double x, int n) { + double value; + int exp; + + value = frexp(x, &exp); + exp += n; + + return ldexp(value, exp); +} diff --git a/src/MSL/mbstring.c b/src/MSL/mbstring.c new file mode 100644 index 00000000..68599878 --- /dev/null +++ b/src/MSL/mbstring.c @@ -0,0 +1,107 @@ +#include "mbstring.h" + +#include "locale.h" +#include "string.h" + +#pragma exceptions on + +int mbtowc(wchar_t* dest, const char* s, size_t num) { + return _current_locale.ctype_cmpt_ptr->decode_mb(dest, s, num); +} + +int __mbtowc_noconv(wchar_t* dest, const char* src, size_t n) { + if (src == 0) { + return 0; + } + + if (n == 0) { + return -1; + } + + if (dest) { + *dest = (unsigned char)*src; + } + + if (!*src) { + return 0; + } + + return 1; +} + +int __wctomb_noconv(char* src, wchar_t cr) { + if (src == 0) { + return 0; + } + + *src = cr; + return 1; +} + +static inline int wctomb(char* src, wchar_t wchar) { + return _current_locale.ctype_cmpt_ptr->encode_wc(src, wchar); +} + +size_t mbstowcs(wchar_t* pDest, const char* pSrc, size_t num) { + int res; + char* src; + int count; + size_t src_len; + + src_len = strlen(pSrc); + + if (pDest != 0) { + src = (char*)pSrc; + + for (count = 0; count < num; count++) { + if (*src) { + res = mbtowc(pDest++, src, src_len); + + if (res > 0) { + src += res; + src_len -= res; + } else { + return -1; + } + } else { + *pDest = 0; + break; + } + } + } else { + count = 0; + } + + return count; +} + +size_t wcstombs(char* src, const wchar_t* pwcs, size_t n) { + int chars_written = 0; + int result; + char temp[3]; + wchar_t* source; + + if (!src || !pwcs) { + return 0; + } + + source = (wchar_t*)pwcs; + + while (chars_written <= n) { + if (!*source) { + *(src + chars_written) = '\0'; + break; + } else { + result = wctomb(temp, *source++); + + if ((chars_written + result) <= n) { + strncpy(src + chars_written, temp, result); + chars_written += result; + } else { + break; + } + } + } + + return chars_written; +} diff --git a/src/MSL/mem.c b/src/MSL/mem.c new file mode 100644 index 00000000..f4d5ab2d --- /dev/null +++ b/src/MSL/mem.c @@ -0,0 +1,82 @@ +#include "mem_funcs.h" +#include "string.h" + +#pragma exceptions on + +void* memmove(void* dst, const void* src, size_t len) { + const char* csrc; + char* cdst; + + int reverse = (u32)src < (u32)dst; + + if (len >= 32) { + if (((int)dst ^ (int)src) & 3) { + if (!reverse) { + __copy_longs_unaligned(dst, src, len); + } else { + __copy_longs_rev_unaligned(dst, src, len); + } + } else { + if (!reverse) { + __copy_longs_aligned(dst, src, len); + } else { + __copy_longs_rev_aligned(dst, src, len); + } + } + + return dst; + } else { + if (!reverse) { + for (csrc = (const char*)src - 1, cdst = (char*)dst - 1, len++; + --len;) { + *++cdst = *++csrc; + } + } else { + for (csrc = (const char*)src + len, cdst = (char*)dst + len, len++; + --len;) { + *--cdst = *--csrc; + } + } + } + + return dst; +} + +void* memchr(const void* src, int val, size_t n) { + const u8* p; + u32 v = val & 0xFF; + + for (p = (u8*)src - 1, n++; --n;) { + if ((*++p & 0xFF) == v) { + return (void*)p; + } + } + + return NULL; +} + +void* __memrchr(const void* src, int val, size_t n) { + const u8* p; + u32 v = val & 0xFF; + + for (p = (u8*)src + n, n++; --n;) { + if (*--p == v) { + return (void*)p; + } + } + + return NULL; +} + +int memcmp(const void* src1, const void* src2, size_t n) { + const u8* p1; + const u8* p2; + + for (p1 = (const u8*)src1 - 1, p2 = (const u8*)src2 - 1, n++; --n;) { + if (*++p1 != *++p2) { + return (*p1 < *p2) ? -1 : 1; + } + } + + return 0; +} diff --git a/src/MSL/mem_funcs.c b/src/MSL/mem_funcs.c new file mode 100644 index 00000000..20e92d75 --- /dev/null +++ b/src/MSL/mem_funcs.c @@ -0,0 +1,204 @@ +#include "mem_funcs.h" + +#define srcCharPtr ((unsigned char*)pSrc) +#define destCharPtr ((unsigned char*)pDest) +#define srcLongPtr ((unsigned long*)pSrc) +#define destLongPtr ((unsigned long*)pDest) + +void __copy_longs_aligned(void* pDest, const void* pSrc, unsigned long len) { + unsigned long i = (-(unsigned long)pDest) & 3; + srcCharPtr = ((unsigned char*)pSrc) - 1; + destCharPtr = ((unsigned char*)pDest) - 1; + + if (i != 0) { + len -= i; + + do { + *++(destCharPtr) = *++(srcCharPtr); + } while (--i); + } + + srcLongPtr = ((unsigned long*)(srcCharPtr + 1)) - 1; + destLongPtr = ((unsigned long*)(destCharPtr + 1)) - 1; + + i = len >> 5; + + if (i != 0) { + do { + *++(destLongPtr) = *++(srcLongPtr); + *++(destLongPtr) = *++(srcLongPtr); + *++(destLongPtr) = *++(srcLongPtr); + *++(destLongPtr) = *++(srcLongPtr); + *++(destLongPtr) = *++(srcLongPtr); + *++(destLongPtr) = *++(srcLongPtr); + *++(destLongPtr) = *++(srcLongPtr); + *++(destLongPtr) = *++(srcLongPtr); + } while (--i); + } + + i = (len & 31) >> 2; + + if (i != 0) { + do { + *++(destLongPtr) = *++(srcLongPtr); + } while (--i); + } + + srcCharPtr = ((unsigned char*)(srcLongPtr + 1)) - 1; + destCharPtr = ((unsigned char*)(destLongPtr + 1)) - 1; + + len &= 3; + + if (len != 0) { + do + *++(destCharPtr) = *++(srcCharPtr); + while (--len); + } +} + +void __copy_longs_rev_aligned(void* pDest, const void* pSrc, + unsigned long len) { + unsigned long i; + srcCharPtr = ((unsigned char*)pSrc) + len; + destCharPtr = ((unsigned char*)pDest) + len; + i = ((unsigned long)destCharPtr) & 3; + + if (i != 0) { + len -= i; + + do { + *--destCharPtr = *--srcCharPtr; + } while (--i); + } + + i = len >> 5; + + if (i != 0) { + do { + *--destLongPtr = *--srcLongPtr; + *--destLongPtr = *--srcLongPtr; + *--destLongPtr = *--srcLongPtr; + *--destLongPtr = *--srcLongPtr; + *--destLongPtr = *--srcLongPtr; + *--destLongPtr = *--srcLongPtr; + *--destLongPtr = *--srcLongPtr; + *--destLongPtr = *--srcLongPtr; + } while (--i); + } + + i = (len & 31) >> 2; + + if (i != 0) { + do { + *--destLongPtr = *--srcLongPtr; + } while (--i); + } + + len &= 3; + + if (len != 0) { + do { + *--destCharPtr = *--srcCharPtr; + } while (--len); + } +} + +void __copy_longs_unaligned(void* pDest, const void* pSrc, unsigned long len) { + unsigned long i, v1, v2; + unsigned int src, ls, rs; + + i = (-(unsigned long)pDest) & 3; + srcCharPtr = ((unsigned char*)pSrc) - 1; + destCharPtr = ((unsigned char*)pDest) - 1; + + if (i != 0) { + len -= i; + + do { + *++destCharPtr = *++srcCharPtr; + } while (--i); + } + + src = ((unsigned int)(srcCharPtr + 1)) & 3; + ls = src << 3; + rs = 32 - ls; + + srcCharPtr -= src; + + srcLongPtr = ((unsigned long*)(srcCharPtr + 1)) - 1; + destLongPtr = ((unsigned long*)(destCharPtr + 1)) - 1; + + i = len >> 3; + v1 = *++srcLongPtr; + + do { + v2 = *++srcLongPtr; + *++destLongPtr = (v1 << ls) | (v2 >> rs); + v1 = *++srcLongPtr; + *++destLongPtr = (v2 << ls) | (v1 >> rs); + } while (--i); + + if (len & 4) { + v2 = *++srcLongPtr; + *++destLongPtr = (v1 << ls) | (v2 >> rs); + } + + srcCharPtr = ((unsigned char*)(srcLongPtr + 1)) - 1; + destCharPtr = ((unsigned char*)(destLongPtr + 1)) - 1; + + len &= 3; + + if (len != 0) { + srcCharPtr -= 4 - src; + do { + *++destCharPtr = *++srcCharPtr; + } while (--len); + } +} + +void __copy_longs_rev_unaligned(void* pDest, const void* pSrc, + unsigned long len) { + unsigned long i, v1, v2; + unsigned int src, ls, rs; + + srcCharPtr = ((unsigned char*)pSrc) + len; + destCharPtr = ((unsigned char*)pDest) + len; + i = ((unsigned long)pDest) & 3; + + if (i != 0) { + len -= i; + + do { + *--destCharPtr = *--srcCharPtr; + } while (--i); + } + + src = ((unsigned int)(srcCharPtr)) & 3; + ls = src << 3; + rs = 32 - ls; + + srcCharPtr += 4 - src; + i = len >> 3; + v1 = *--srcLongPtr; + + do { + v2 = *--srcLongPtr; + *--destLongPtr = (v2 << ls) | (v1 >> rs); + v1 = *--srcLongPtr; + *--destLongPtr = (v1 << ls) | (v2 >> rs); + } while (--i); + + if (len & 4) { + v2 = *--srcLongPtr; + *--destLongPtr = (v2 << ls) | (v1 >> rs); + } + + len &= 3; + + if (len != 0) { + srcCharPtr += src; + do { + *--destCharPtr = *--srcCharPtr; + } while (--len); + } +} diff --git a/src/MSL/misc_io.c b/src/MSL/misc_io.c new file mode 100644 index 00000000..b4d0329a --- /dev/null +++ b/src/MSL/misc_io.c @@ -0,0 +1,6 @@ +extern void (*__stdio_exit)(void); +void __close_all(void); + +void __stdio_atexit(void) { + __stdio_exit = __close_all; +} diff --git a/src/MSL/printf.c b/src/MSL/printf.c new file mode 100644 index 00000000..a223155d --- /dev/null +++ b/src/MSL/printf.c @@ -0,0 +1,1337 @@ +#include +#include "ansi_fp.h" +#include "string.h" +#include "internal/pformatter.h" + +#pragma exceptions on + +size_t __fwrite(const void *pPtr, size_t memb_size, size_t num_memb, FILE *pFile); + +typedef struct { + unsigned char justification_options; // 0x0 + unsigned char sign_options; // 0x1 + unsigned char precision_specified; // 0x2 + unsigned char alternate_form; // 0x3 + unsigned char argument_options; // 0x4 + unsigned char conversion_char; // 0x5 + int field_width; // 0x8 + int precision; // 0xC +} print_format; + +const char* parse_format(const char *format_string, va_list *arg, print_format *format) { + print_format f; + const char* s = format_string; + int c; + int flag_found; + f.justification_options = right_justification; + f.sign_options = only_minus; + f.precision_specified = 0; + f.alternate_form = 0; + f.argument_options = normal_argument; + f.field_width = 0; + f.precision = 0; + + if ((c = *++s) == '%') { + f.conversion_char = c; + *format = f; + return ((const char*)s + 1); + } + + for (;;) { + flag_found = 1; + + switch (c) { + case '-': + f.justification_options = left_justification; + break; + case '+': + f.sign_options = sign_always; + break; + case ' ': + if (f.sign_options != sign_always) { + f.sign_options = space_holder; + } + break; + case '#': + f.alternate_form = 1; + break; + case '0': + if (f.justification_options != left_justification) { + f.justification_options = zero_fill; + } + break; + default: + flag_found = 0; + break; + } + + if (flag_found) { + c = *++s; + } + else { + break; + } + } + + if (c == '*') { + if ((f.field_width = va_arg(*arg, int)) < 0) { + f.justification_options = left_justification; + f.field_width = -f.field_width; + } + + c = *++s; + } + else { + while (isdigit(c)) { + f.field_width = (f.field_width * 10) + (c - '0'); + c = *++s; + } + } + + if (f.field_width > 509) { + f.conversion_char = 0xFF; + *format = f; + return ((const char*)s + 1); + } + + if (c == '.') { + f.precision_specified = 1; + + if ((c = *++s) == '*') { + if ((f.precision = va_arg(*arg, int)) < 0) { + f.precision_specified = 0; + } + + c = *++s; + } + else { + while (isdigit(c)) { + f.precision = (f.precision * 10) + (c - '0'); + c = *++s; + } + } + } + + flag_found = 1; + + switch (c) { + case 'h': + f.argument_options = short_argument; + + if (s[1] == 'h') { + f.argument_options = char_argument; + c = *++s; + } + + break; + + case 'l': + f.argument_options = long_argument; + + if (s[1] == 'l') { + f.argument_options = long_long_argument; + c = *++s; + } + + break; + + case 'L': + f.argument_options = long_double_argument; + break; + case 'j': + f.argument_options = intmax_argument; + break; + case 't': + f.argument_options = ptrdiff_argument; + break; + case 'z': + f.argument_options = size_t_argument; + break; + default: + flag_found = 0; + break; + } + + if (flag_found) { + c = *++s; + } + + f.conversion_char = c; + + switch (c) { + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + if (f.argument_options == long_double_argument) { + f.conversion_char = 0xFF; + break; + } + + if (!f.precision_specified) { + f.precision = 1; + } + else if (f.justification_options == zero_fill) { + f.justification_options = right_justification; + } + break; + + case 'f': + case 'F': + if (f.argument_options == short_argument || f.argument_options == intmax_argument || f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || f.argument_options == long_long_argument) { + f.conversion_char = 0xFF; + break; + } + + if (!f.precision_specified) { + f.precision = 6; + } + break; + + case 'a': + case 'A': + if (!f.precision_specified) { + f.precision = 0xD; + } + + if (f.argument_options == short_argument || f.argument_options == intmax_argument || + f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || + f.argument_options == long_long_argument || f.argument_options == char_argument) { + f.conversion_char = 0xFF; + } + + break; + + case 'g': + case 'G': + if (!f.precision) { + f.precision = 1; + } + + case 'e': + case 'E': + if (f.argument_options == short_argument || f.argument_options == intmax_argument || f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || f.argument_options == long_long_argument || f.argument_options == char_argument) { + f.conversion_char = 0xFF; + break; + } + + if (!f.precision_specified) { + f.precision = 6; + } + break; + + case 'p': + f.conversion_char = 'x'; + f.alternate_form = 1; + f.argument_options = long_argument; + f.precision = 8; + break; + + case 'c': + if (f.argument_options == long_argument) { + f.argument_options = wchar_argument; + } + else { + if (f.precision_specified || f.argument_options != normal_argument) { + f.conversion_char = 0xFF; + } + } + + break; + + case 's': + if (f.argument_options == long_argument) { + f.argument_options = wchar_argument; + } + else { + if (f.argument_options != normal_argument) { + f.conversion_char = 0xFF; + } + } + + break; + + case 'n': + if (f.argument_options == long_double_argument) { + f.conversion_char = 0xFF; + } + + break; + + default: + f.conversion_char = 0xFF; + break; + } + + *format = f; + return ((const char*)s + 1); +} + +static char * long2str(long num, char * buff, print_format format) { + unsigned long unsigned_num, base; + char* p; + int n, digits; + int minus = 0; + unsigned_num = num; + minus = 0; + + p = buff; + *--p = 0; + digits = 0; + + if (!num && !format.precision && !(format.alternate_form && format.conversion_char == 'o')) { + return p; + } + + switch (format.conversion_char) { + case 'd': + case 'i': + base = 10; + + if (num < 0) { + if (num != 0x80000000) { + unsigned_num = -num; + } + + minus = 1; + } + break; + + case 'o': + base = 8; + format.sign_options = only_minus; + break; + + case 'u': + base = 10; + format.sign_options = only_minus; + break; + + case 'x': + case 'X': + base = 16; + format.sign_options = only_minus; + break; + } + + do { + n = unsigned_num % base; + unsigned_num /= base; + + if (n < 10) { + n += '0'; + } + else { + n -= 10; + + if (format.conversion_char == 'x') { + n += 'a'; + } + else { + n += 'A'; + } + } + + *--p = n; + ++digits; + } + while (unsigned_num != 0); + + if (base == 8 && format.alternate_form && *p != '0') { + *--p = '0'; + ++digits; + } + + if (format.justification_options == zero_fill) { + format.precision = format.field_width; + + if (minus || format.sign_options != only_minus) + --format.precision; + + if (base == 16 && format.alternate_form) + format.precision -= 2; + } + + if (buff - p + format.precision > 509) + return (0); + + while (digits < format.precision) { + *--p = '0'; + ++digits; + } + + if (base == 16 && format.alternate_form) { + *--p = format.conversion_char; + *--p = '0'; + } + + if (minus) { + *--p = '-'; + } + else if (format.sign_options == sign_always) { + *--p = '+'; + } + else if (format.sign_options == space_holder) { + *--p = ' '; + } + + return p; +} + +char* longlong2str(long long num, char *pBuf, print_format fmt) { + unsigned long long unsigned_num, base; + char* p; + int n, digits; + int minus = 0; + unsigned_num = num; + minus = 0; + p = pBuf; + *--p = 0; + digits = 0; + + if (!num && !fmt.precision && !(fmt.alternate_form && fmt.conversion_char == 'o')) { + return p; + } + + switch (fmt.conversion_char) { + case 'd': + case 'i': + base = 10; + + if (num < 0) { + if (num != 0x8000000000000000) { + unsigned_num = -num; + } + + minus = 1; + } + break; + case 'o': + base = 8; + fmt.sign_options = only_minus; + break; + case 'u': + base = 10; + fmt.sign_options = only_minus; + break; + case 'x': + case 'X': + base = 16; + fmt.sign_options = only_minus; + break; + } + + do { + n = unsigned_num % base; + unsigned_num /= base; + + if (n < 10) { + n += '0'; + } + else { + n -= 10; + if (fmt.conversion_char == 'x') { + n += 'a'; + } + else { + n += 'A'; + } + } + + *--p = n; + ++digits; + } while (unsigned_num != 0); + + if (base == 8 && fmt.alternate_form && *p != '0') { + *--p = '0'; + ++digits; + } + + if (fmt.justification_options == zero_fill) { + fmt.precision = fmt.field_width; + + if (minus || fmt.sign_options != only_minus) { + --fmt.precision; + } + + if (base == 16 && fmt.alternate_form) { + fmt.precision -= 2; + } + } + + if (pBuf - p + fmt.precision > 509) { + return 0; + } + + while (digits < fmt.precision) { + *--p = '0'; + ++digits; + } + + if (base == 16 && fmt.alternate_form) { + *--p = fmt.conversion_char; + *--p = '0'; + } + + if (minus) { + *--p = '-'; + } + else if (fmt.sign_options == sign_always) { + *--p = '+'; + } + else if (fmt.sign_options == space_holder) { + *--p = ' '; + } + + return p; +} + +char * double2hex(long double num, char * buff, print_format format) { + char *p; + unsigned char *q; + unsigned char working_byte; + long double ld; + int expbits, expmask; + unsigned snum; + long exp; + print_format exp_format; + int hex_precision; + int mantissa_bit; + decform form; + decimal dec; + int radix_marker; + + radix_marker = * (unsigned char *)(__lconv).decimal_point; + p = buff; + ld = num; + + if (format.precision > 509) { + return 0; + } + + form.style = (char)0; + form.digits = 0x20; + __num2dec(&form, num, &dec); + + if (fabsl(num) == 0.0) { + p = buff - 6; + strcpy(p, "0x0p0"); + return p; + } + + if (*dec.sig.text == 'I') { + if (dec.sign) { + p = buff - 5; + if (format.conversion_char == 'A') + strcpy(p, "-INF"); + else + strcpy(p, "-inf"); + } + else { + p = buff - 4; + if (format.conversion_char == 'A') + strcpy(p, "INF"); + else + strcpy(p, "inf"); + } + + return p; + } + else if (*dec.sig.text == 'N') { + if (dec.sign) { + p = buff - 5; + if (format.conversion_char == 'A') + strcpy(p, "-NAN"); + else + strcpy(p, "-nan"); + } + else { + p = buff - 4; + if (format.conversion_char == 'A') + strcpy(p, "NAN"); + else + strcpy(p, "nan"); + } + return p; + } + + exp_format.justification_options = 1; + exp_format.sign_options = 1; + exp_format.precision_specified = 0; + exp_format.alternate_form = 0; + exp_format.argument_options = 0; + exp_format.field_width = 0; + exp_format.precision = 1; + exp_format.conversion_char = 'd'; + + expbits = 11; + expmask = 0x7FF; + + snum = ((unsigned char *)&num)[0] << 25; + if (TARGET_FLOAT_EXP_BITS > 7) + snum |= ((unsigned char *)&num)[1] << 17; + if (TARGET_FLOAT_EXP_BITS > 15) + snum |= ((unsigned char *)&num)[2] << 9; + if (TARGET_FLOAT_EXP_BITS > 23) + snum |= ((unsigned char *)&num)[3] << 1; + + snum = (snum >> (32 - expbits)) & expmask; + exp = snum - 0x3FF; + + p = long2str(exp, buff, exp_format); + if (format.conversion_char == 'a') + *--p = 'p'; + else + *--p = 'P'; + q = (unsigned char *)# + + if (TARGET_FLOAT_IMPLICIT_J_BIT) { + mantissa_bit = (1 + expbits + format.precision * 4) - 1; + } + else { + mantissa_bit = (1 + expbits + format.precision * 4) - 4; + } + + for (hex_precision = format.precision; hex_precision >= 1; hex_precision--) { + if (mantissa_bit < 64) { + int mantissa_byte; + + mantissa_byte = mantissa_bit >> 3; + working_byte = (*(q + mantissa_byte)) >> (7 - (mantissa_bit & 7)); + + if ((mantissa_bit & ~7) != ((mantissa_bit - 4) & ~7)) { + working_byte |= ((*(q + (mantissa_byte - 1))) << 8) >> (7 - ((mantissa_bit) & 7)); + } + + if (!TARGET_FLOAT_IMPLICIT_J_BIT) { + if (mantissa_bit == 1 + expbits) { + *--p = radix_marker; + working_byte &= 0x1; + } + } + + if ((working_byte &= 0xF) < 10) { + working_byte += '0'; + } + else + if (format.conversion_char == 'a') { + working_byte += 'a' - 10; + } + else { + working_byte += 'A' - 10; + } + } + else { + working_byte = '0'; + } + + *--p = working_byte; + mantissa_bit -= 4; + } + + if (TARGET_FLOAT_IMPLICIT_J_BIT){ + if (format.precision || format.alternate_form) { + *--p = radix_marker; + } + + *--p = '1'; + } + + if (format.conversion_char == 'a') { + *--p = 'x'; + } + else { + *--p = 'X'; + } + + *--p = '0'; + + if (dec.sign) { + *--p = '-'; + } + else if (format.sign_options == 1) { + *--p = '+'; + } + else if (format.sign_options == 2) { + *--p = ' '; + } + + return p; +} + +void round_decimal(decimal *dec, int new_length) { + char c; + char* p; + int carry; + + if (new_length < 0) { +return_zero: + dec->exponent = 0; + dec->sig.length = 1; + *dec->sig.text = '0'; + return; + } + + if (new_length >= dec->sig.length) { + return; + } + + p = (char*)dec->sig.text + new_length + 1; + c = *--p - '0'; + + if (c == 5) { + char* q = &((char*)dec->sig.text)[dec->sig.length]; + + while (--q > p && *q == '0'); + carry = (q == p) ? p[-1] & 1 : 1; + } + else { + carry = (c > 5); + } + + while (new_length != 0) { + c = *--p - '0' + carry; + + if ((carry = (c > 9)) != 0 || c == 0) { + --new_length; + } + else { + *p = c + '0'; + break; + } + } + + if (carry != 0) { + dec->exponent += 1; + dec->sig.length = 1; + *dec->sig.text = '1'; + return; + } + else if (new_length == 0) { + goto return_zero; + } + + dec->sig.length = new_length; +} + +char* float2str(long double num, char *buff, print_format format) { + decimal dec; + decform form; + char* p; + char* q; + int n, digits, sign; + int int_digits, frac_digits; + int radix_marker; + + radix_marker = *(unsigned char*)__lconv.decimal_point; + + if (format.precision > 509) { + return 0; + } + + form.style = 0; + form.digits = 0x20; + __num2dec(&form, num, &dec); + p = (char*)dec.sig.text + dec.sig.length; + + while (dec.sig.length > 1 && *--p == '0') { + --dec.sig.length; + ++dec.exponent; + } + + switch (*dec.sig.text) { + case '0': + dec.exponent = 0; + break; + case 'I': + if (num < 0) { + p = buff - 5; + + if (isupper(format.conversion_char)) { + strcpy(p, "-INF"); + } + else { + strcpy(p, "-inf"); + } + } + else { + p = buff - 4; + if (isupper(format.conversion_char)) { + strcpy(p, "INF"); + } + else { + strcpy(p, "inf"); + } + } + + return p; + + case 'N': + if (dec.sign) { + p = buff - 5; + + if (isupper(format.conversion_char)) { + strcpy(p, "-NAN"); + } + else { + strcpy(p, "-nan"); + } + } + else { + p = buff - 4; + if (isupper(format.conversion_char)) { + strcpy(p, "NAN"); + } + else { + strcpy(p, "nan"); + } + } + + return p; + } + + dec.exponent += dec.sig.length - 1; + p = buff; + *--p = 0; + + switch (format.conversion_char) + { + case 'g': + case 'G': + + if (dec.sig.length > format.precision) { + round_decimal(&dec, format.precision); + } + + if (dec.exponent < -4 || dec.exponent >= format.precision) + { + if (format.alternate_form) { + --format.precision; + } + else { + format.precision = dec.sig.length - 1; + } + + if (format.conversion_char == 'g') { + format.conversion_char = 'e'; + } + else { + format.conversion_char = 'E'; + } + + goto e_format; + } + + if (format.alternate_form) { + format.precision -= dec.exponent + 1; + } + else { + if ((format.precision = dec.sig.length - (dec.exponent + 1)) < 0) { + format.precision = 0; + } + } + + goto f_format; + + case 'e': + case 'E': + e_format: + + if (dec.sig.length > format.precision + 1) { + round_decimal(&dec, format.precision + 1); + } + + n = dec.exponent; + sign = '+'; + + if (n < 0) { + n = -n; + sign = '-'; + } + + for (digits = 0; n || digits < 2; ++digits) { + *--p = n % 10 + '0'; + n /= 10; + } + + *--p = sign; + *--p = format.conversion_char; + + if (buff - p + format.precision > 509) { + return 0; + } + + if (dec.sig.length < format.precision + 1) { + for (n = format.precision + 1 - dec.sig.length + 1; --n;) { + *--p = '0'; + } + } + + for (n = dec.sig.length, q = (char*)dec.sig.text + dec.sig.length; --n;) { + *--p = *--q; + } + + if (format.precision || format.alternate_form) { + *--p = radix_marker; + } + + *--p = *dec.sig.text; + + if (dec.sign) + *--p = '-'; + else if (format.sign_options == sign_always) + *--p = '+'; + else if (format.sign_options == space_holder) + *--p = ' '; + + break; + + case 'f': + case 'F': + f_format: + + if ((frac_digits = -dec.exponent + dec.sig.length - 1) < 0) + frac_digits = 0; + + if (frac_digits > format.precision) { + round_decimal(&dec, dec.sig.length - (frac_digits - format.precision)); + + if ((frac_digits = -dec.exponent + dec.sig.length - 1) < 0) + frac_digits = 0; + } + + if ((int_digits = dec.exponent + 1) < 0) + int_digits = 0; + + if (int_digits + frac_digits > 509) + return 0; + + q = (char *) dec.sig.text + dec.sig.length; + + for (digits = 0; digits < (format.precision - frac_digits); ++digits) + *--p = '0'; + + for (digits = 0; digits < frac_digits && digits < dec.sig.length; ++digits) + *--p = *--q; + + for (; digits < frac_digits; ++digits) + *--p = '0'; + + if (format.precision || format.alternate_form) + *--p = radix_marker; + + if (int_digits) { + for (digits = 0; digits < int_digits - dec.sig.length; ++digits) { + *--p = '0'; + } + + for (; digits < int_digits; ++digits) { + *--p = *--q; + } + } + else { + *--p = '0'; + } + + if (dec.sign) { + *--p = '-'; + } + else if (format.sign_options == sign_always) { + *--p = '+'; + } + else if (format.sign_options == space_holder) { + *--p = ' '; + } + + break; + } + + return p; +} + +int __pformatter(void *(*WriteProc)(void *, const char *, size_t), void *WriteProcArg, const char * format_str, va_list arg) { + int num_chars, chars_written, field_width; + const char* format_ptr; + const char* curr_format; + print_format format; + long long_num; + long long long_long_num; + long double long_double_num; + char buff[512]; + char* buff_ptr; + char* string_end; + char fill_char = ' '; + + format_ptr = format_str; + chars_written = 0; + + while (*format_ptr) { + if (!(curr_format = strchr(format_ptr, '%'))) { + num_chars = strlen(format_ptr); + chars_written += num_chars; + + if (num_chars && !(*WriteProc)(WriteProcArg, format_ptr, num_chars)) { + return -1; + } + + break; + } + + num_chars = curr_format - format_ptr; + chars_written += num_chars; + + if (num_chars && !(*WriteProc)(WriteProcArg, format_ptr, num_chars)) { + return -1; + } + + format_ptr = curr_format; + format_ptr = parse_format(format_ptr, (va_list*)arg, &format); + + switch (format.conversion_char) { + case 'd': + case 'i': + if (format.argument_options == long_argument) { + long_num = va_arg(arg, long); + } + else if (format.argument_options == long_long_argument) { + long_long_num = va_arg(arg, long long); + } + else if (format.argument_options == intmax_argument) { + long_long_num = va_arg(arg, intmax_t); + } + else if (format.argument_options == size_t_argument) { + long_num = va_arg(arg, size_t); + } + else if (format.argument_options == ptrdiff_argument) { + long_num = va_arg(arg, ptrdiff_t); + } + else { + long_num = va_arg(arg, int); + } + + if (format.argument_options == short_argument) { + long_num = (short)long_num; + } + + if (format.argument_options == char_argument) { + long_num = (signed char)long_num; + } + + if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) { + if (!(buff_ptr = longlong2str(long_long_num, buff + 512, format))) { + goto conversion_error; + } + } + else { + if (!(buff_ptr = long2str(long_num, buff + 512, format))) { + goto conversion_error; + } + } + + num_chars = buff + 512 - 1 - buff_ptr; + break; + + case 'o': + case 'u': + case 'x': + case 'X': + if (format.argument_options == long_argument) { + long_num = va_arg(arg, unsigned long); + } + else if (format.argument_options == long_long_argument) { + long_long_num = va_arg(arg, long long); + } + else if (format.argument_options == intmax_argument) { + long_long_num = va_arg(arg, intmax_t); + } + else if (format.argument_options == size_t_argument) { + long_num = va_arg(arg, size_t); + } + else if (format.argument_options == ptrdiff_argument) { + long_num = va_arg(arg, ptrdiff_t); + } + else { + long_num = va_arg(arg, unsigned int); + } + + if (format.argument_options == short_argument) { + long_num = (unsigned short)long_num; + } + + if (format.argument_options == char_argument) { + long_num = (unsigned char)long_num; + } + + if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) { + if (!(buff_ptr = longlong2str(long_long_num, buff + 512, format))) { + goto conversion_error; + } + } + else { + if (!(buff_ptr = long2str(long_num, buff + 512, format))) { + goto conversion_error; + } + } + + num_chars = buff + 512 - 1 - buff_ptr; + break; + + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + if (format.argument_options == long_double_argument) { + long_double_num = va_arg(arg, long double); + } + else { + long_double_num = va_arg(arg, double); + } + + if (!(buff_ptr = float2str(long_double_num, buff + 512, format))) { + goto conversion_error; + } + + num_chars = buff + 512 - 1 - buff_ptr; + break; + + case 'a': + case 'A': + if (format.argument_options == long_double_argument) { + long_double_num = va_arg(arg, long double); + } + else { + long_double_num = va_arg(arg, double); + } + + if (!(buff_ptr = double2hex(long_double_num, buff + 512, format))) { + goto conversion_error; + } + + num_chars = buff + 512 - 1 - buff_ptr; + break; + + case 's': + if (format.argument_options == wchar_argument) { + wchar_t* wcs_ptr = va_arg(arg, wchar_t*); + + if (wcs_ptr == 0) { + wcs_ptr = L""; + } + + if ((num_chars = wcstombs(buff, wcs_ptr, sizeof(buff))) < 0) { + goto conversion_error; + } + + buff_ptr = &buff[0]; + } + else { + buff_ptr = va_arg(arg, char *); + } + + if (buff_ptr == 0) { + buff_ptr = ""; + } + + if (format.alternate_form) { + num_chars = (unsigned char)*buff_ptr++; + + if (format.precision_specified && num_chars > format.precision) { + num_chars = format.precision; + } + } + else if (format.precision_specified) { + num_chars = format.precision; + + if ((string_end = (char*)memchr(buff_ptr, 0, num_chars)) != 0) { + num_chars = string_end - buff_ptr; + } + } + else { + num_chars = strlen(buff_ptr); + } + + break; + + case 'n': + buff_ptr = va_arg(arg, char *); + + switch (format.argument_options) { + case normal_argument: + *(int*)buff_ptr = chars_written; + break; + case short_argument: + *(short*)buff_ptr = chars_written; + break; + case long_argument: + *(long*)buff_ptr = chars_written; + break; + case intmax_argument: + *(intmax_t*)buff_ptr = chars_written; + break; + case size_t_argument: + *(size_t*)buff_ptr = chars_written; + break; + case ptrdiff_argument: + *(ptrdiff_t*)buff_ptr = chars_written; + break; + case long_long_argument: + *(long long*)buff_ptr = chars_written; + break; + } + + continue; + + case 'c': + buff_ptr = buff; + *buff_ptr = va_arg(arg, int); + num_chars = 1; + break; + + case '%': + buff_ptr = buff; + *buff_ptr = '%'; + num_chars = 1; + break; + + case 0xFF: + default: + conversion_error: + num_chars = strlen(curr_format); + chars_written += num_chars; + + if (num_chars && !(*WriteProc)(WriteProcArg, curr_format, num_chars)) { + return -1; + } + + return chars_written; + break; + } + + field_width = num_chars; + + if (format.justification_options != left_justification) { + fill_char = (format.justification_options == zero_fill) ? '0' : ' '; + + if (((*buff_ptr == '+') || (*buff_ptr == '-') || (*buff_ptr == ' ')) && (fill_char == '0')) { + if ((*WriteProc)(WriteProcArg, buff_ptr, 1) == 0) { + return -1; + } + + ++buff_ptr; + num_chars--; + } + + while (field_width < format.field_width) { + if ((*WriteProc)(WriteProcArg, &fill_char, 1) == 0) { + return -1; + } + + ++field_width; + } + } + + if (num_chars && !(*WriteProc)(WriteProcArg, buff_ptr, num_chars)) { + return -1; + } + + if (format.justification_options == left_justification) { + while (field_width < format.field_width) { + char blank = ' '; + + if ((*WriteProc)(WriteProcArg, &blank, 1) == 0) { + return -1; + } + + ++field_width; + } + } + + chars_written += field_width; + } + + return chars_written; +} + +void* __FileWrite(void *pFile, const char *pBuffer, size_t char_num) { + return (__fwrite(pBuffer, 1, char_num, (FILE*)pFile) == char_num ? pFile : 0); +} + +void* __StringWrite(void *pCtrl, const char *pBuffer, size_t char_num) { + size_t chars; + void* res; + __OutStrCtrl* ctrl = (__OutStrCtrl*)pCtrl; + + chars = ((ctrl->CharsWritten + char_num) <= ctrl->MaxCharCount) ? char_num : ctrl->MaxCharCount - ctrl->CharsWritten; + res = (void*)memcpy(ctrl->CharStr + ctrl->CharsWritten, pBuffer, chars); + ctrl->CharsWritten += chars; + return (void*)1; +} + +inline int fprintf(FILE *pFile, const char *format, ...) { + int res; + + if (fwide(pFile, -1) >= 0) { + return -1; + } + + { + va_list args; + va_start(args, format); + res = __pformatter(&__FileWrite, (void*)pFile, format, args); + return res; + } +} + +int vsnprintf(char *s, size_t n, const char *format, va_list arg) { + int end; + __OutStrCtrl osc; + osc.CharStr = s; + osc.MaxCharCount = n; + osc.CharsWritten = 0; + + end = __pformatter(&__StringWrite, &osc, format, arg); + + if (s) { + if (end < n) { + s[end] = '\0'; + } + else { + if (n > 0) { + s[n - 1] = '\0'; + } + } + } + + return end; +} + +int vsprintf(char *s, const char *format, va_list arg) { + return vsnprintf(s, 0xFFFFFFFF, format, arg); +} + +int vprintf(const char *pFormat, va_list arg) { + int ret; + + if (fwide(stdout, -1) >= 0) { + return -1; + } + + ret = __pformatter(&__FileWrite, (void*)stdout, pFormat, arg); + return ret; +} + +int snprintf(char *s, size_t n, const char *format, ...) { + va_list args; + va_start(args, format); + return vsnprintf(s, n, format, args); +} + +int sprintf(char *s, const char *format, ...) { + va_list args; + va_start(args, format); + return vsnprintf(s, 0xFFFFFFFF, format, args); +} diff --git a/src/MSL/rand.c b/src/MSL/rand.c new file mode 100644 index 00000000..07c26e09 --- /dev/null +++ b/src/MSL/rand.c @@ -0,0 +1,9 @@ +#include "rand.h" + +static u32 random_next = 1; + +// LCG (linear congruential generator) RNG algorithm +int rand() { + random_next = random_next * 1103515245 + 12345; + return ((random_next >> 16) & 0x7fff); +} diff --git a/src/MSL/scanf.c b/src/MSL/scanf.c new file mode 100644 index 00000000..016d5fd5 --- /dev/null +++ b/src/MSL/scanf.c @@ -0,0 +1,827 @@ +#include "ctype.h" +#include "limits.h" +#include "sformatter.h" +#include "stdarg.h" +#include "stdio_api.h" + +#include + +#pragma exceptions on + +typedef long long intmax_t; +#define PTRDIFF __typeof__((char*)0 - (char*)0) +typedef PTRDIFF ptrdiff_t; + +#define conversion_buff_size 512 +#define conversion_max 509 +#define bad_conversion 0xFF +typedef size_t rsize_t; + +#define EOF -1L + +extern long double __strtold(int max_width, int (*ReadProc)(void*, int, int), void* ReadProcArg, int* chars_scanned, int* overflow); +extern unsigned long long __strtoull(int base, int max_width, int (*ReadProc)(void*, int, int), void* ReadProcArg, int* chars_scanned, int* negative, int* overflow); +extern unsigned long __strtoul(int base, int max_width, int (*ReadProc)(void*, int, int), void* ReadProcArg, int* chars_scanned, int* negative, int* overflow); + +int mbtowc(wchar_t* pDest, const char* s, size_t num); + +static const char* parse_format(const char* format_string, + scan_format* format) { + const char* s = format_string; + int c; + int invert; + + int flag_found; + + scan_format f = {0, 0, normal_argument, 0, INT_MAX, {0}}; + + if ((c = *++s) == '%') { + f.conversion_char = c; + *format = f; + return ((const char*)s + 1); + } + + if (c == '*') { + f.suppress_assignment = 1; + c = *++s; + } + + if (isdigit(c)) { + f.field_width = 0; + + do { + f.field_width = (f.field_width * 10) + (c - '0'); + c = *++s; + } while (isdigit(c)); + + if (f.field_width == 0) { + f.conversion_char = 0xFF; + *format = f; + return ((const char*)s + 1); + } + + f.field_width_specified = 1; + } + + flag_found = 1; + + switch (c) { + case 'h': + f.argument_options = short_argument; + + if (s[1] == 'h') { + f.argument_options = char_argument; + c = *++s; + } + + break; + case 'l': + f.argument_options = long_argument; + + if (s[1] == 'l') { + f.argument_options = long_long_argument; + c = *++s; + } + + break; + case 'L': + f.argument_options = long_double_argument; + break; + + case 'j': + f.argument_options = intmax_argument; + break; + case 'z': + f.argument_options = size_t_argument; + break; + case 't': + f.argument_options = ptrdiff_argument; + break; + default: + flag_found = 0; + } + + if (flag_found) { + c = *++s; + } + + f.conversion_char = c; + + switch (c) { + case 'd': + case 'i': + case 'u': + case 'o': + case 'x': + case 'X': + if (f.argument_options == long_double_argument) { + f.conversion_char = 0xFF; + break; + } + + break; + + case 'a': + case 'A': + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + if (f.argument_options == char_argument || + f.argument_options == short_argument || + f.argument_options == intmax_argument || + f.argument_options == size_t_argument || + f.argument_options == ptrdiff_argument || + f.argument_options == long_long_argument) { + f.conversion_char = 0xFF; + break; + } + + if (f.argument_options == long_argument) { + f.argument_options = double_argument; + } + + break; + + case 'p': + f.argument_options = long_argument; + f.conversion_char = 'x'; + break; + + case 'c': + if (f.argument_options == long_argument) { + f.argument_options = wchar_argument; + } else { + if (f.argument_options != normal_argument) { + f.conversion_char = 0xFF; + } + } + + break; + + case 's': + if (f.argument_options == long_argument) { + f.argument_options = wchar_argument; + } else { + if (f.argument_options != normal_argument) { + f.conversion_char = 0xFF; + } + } + + { + int i; + unsigned char* p; + + for (i = sizeof(f.char_set), p = f.char_set; i; --i) { + *p++ = 0xFF; + } + + f.char_set[1] = 0xC1; + f.char_set[4] = 0xFE; + } + + break; + + case 'n': + break; + + case '[': + if (f.argument_options == long_argument) { + f.argument_options = wchar_argument; + } else { + if (f.argument_options != normal_argument) { + f.conversion_char = 0xFF; + } + } + + c = *++s; + invert = 0; + + if (c == '^') { + invert = 1; + c = *++s; + } + + if (c == ']') { + set_char_map(f.char_set, ']'); + c = *++s; + } + + while (c && c != ']') { + int d; + set_char_map(f.char_set, c); + + if (*(s + 1) == '-' && (d = *(s + 2)) != 0 && d != ']') { + while (++c <= d) { + set_char_map(f.char_set, c); + } + + c = *(s += 3); + } else { + c = *++s; + } + } + + if (!c) { + f.conversion_char = 0xFF; + break; + } + + if (invert) { + int i; + unsigned char* p; + + for (i = sizeof(f.char_set), p = f.char_set; i; --i, ++p) { + *p = ~*p; + } + + break; + } + + break; + default: + f.conversion_char = 0xFF; + break; + } + + *format = f; + return ((const char*)s + 1); +} + +int __StringRead(void* pPtr, int ch, int act) { + char ret; + __InStrCtrl* Iscp = (__InStrCtrl*)pPtr; + + switch (act) { + case __GetAChar: + ret = *(Iscp->NextChar); + + if (ret == '\0') { + Iscp->NullCharDetected = 1; + return -1; + } else { + Iscp->NextChar++; + return (unsigned char)ret; + } + + case __UngetAChar: + if (Iscp->NullCharDetected == 0) { + Iscp->NextChar--; + } else { + Iscp->NullCharDetected = 0; + } + + return ch; + + case __TestForError: + return Iscp->NullCharDetected; + } + + return 0; +} + +static int __sformatter(int (*ReadProc)(void*, int, int), void* ReadProcArg, + const char* format_str, va_list arg, int is_secure) { + int num_chars, chars_read, items_assigned, conversions; + int base, negative, overflow; + int rval; + const char* format_ptr; + char format_char; + char c; + scan_format format; + long long_num; + unsigned long u_long_num; + long long long_long_num = 0; + unsigned long long u_long_long_num; + long double long_double_num; + char* arg_ptr; + int elem_valid; + size_t elem_maxsize; + int match_failure = 0; + int terminate = 0; + + format_ptr = format_str; + chars_read = 0; + items_assigned = 0; + conversions = 0; + + while (!terminate && (format_char = *format_ptr) != 0) { + if (isspace(format_char)) { + do { + format_char = *++format_ptr; + } while (isspace(format_char)); + + if (!match_failure) { + while (isspace(c = (*ReadProc)(ReadProcArg, 0, __GetAChar))) { + ++chars_read; + } + + (*ReadProc)(ReadProcArg, c, __UngetAChar); + } + continue; + } + + if ((format_char != '%') && (!match_failure)) { + if ((c = (*ReadProc)(ReadProcArg, 0, __GetAChar)) != + (unsigned char)format_char) { + (*ReadProc)(ReadProcArg, c, __UngetAChar); + if (!is_secure) { + goto exit; + } else { + match_failure = 1; + ++format_ptr; + continue; + } + } + + ++chars_read; + ++format_ptr; + + continue; + } + + format_ptr = parse_format(format_ptr, &format); + if (!format.suppress_assignment && format.conversion_char != '%') { + arg_ptr = va_arg(arg, char*); + } else { + arg_ptr = 0; + } + + if ((format.conversion_char != 'n') && (!match_failure) && + (*ReadProc)(ReadProcArg, 0, __TestForError)) { + if (!is_secure) { + goto exit; + } else { + match_failure = 1; + } + } + + switch (format.conversion_char) { + case 'd': + base = 10; + goto signed_int; + + case 'i': + base = 0; + + signed_int: + if (match_failure) { + long_num = 0; + long_long_num = 0; + } else { + if ((format.argument_options == long_long_argument) || + (format.argument_options == intmax_argument)) { + u_long_long_num = __strtoull( + base, format.field_width, ReadProc, ReadProcArg, + &num_chars, &negative, &overflow); + } else { + u_long_num = __strtoul(base, format.field_width, ReadProc, + ReadProcArg, &num_chars, &negative, + &overflow); + } + + if (!num_chars) { + if (!is_secure) { + goto exit; + } else { + match_failure = 1; + long_num = 0; + long_long_num = 0; + goto signed_int_assign; + } + } + + chars_read += num_chars; + + if ((format.argument_options == long_long_argument) || + (format.argument_options == intmax_argument)) { + long_long_num = + (negative ? -u_long_long_num : u_long_long_num); + } else { + long_num = (negative ? -u_long_num : u_long_num); + } + } + + signed_int_assign: + if (arg_ptr) { + switch (format.argument_options) { + case normal_argument: + *(int*)arg_ptr = long_num; + break; + case char_argument: + *(signed char*)arg_ptr = long_num; + break; + case short_argument: + *(short*)arg_ptr = long_num; + break; + case long_argument: + *(long*)arg_ptr = long_num; + break; + case intmax_argument: + *(intmax_t*)arg_ptr = long_long_num; + break; + case size_t_argument: + *(size_t*)arg_ptr = long_num; + break; + case ptrdiff_argument: + *(ptrdiff_t*)arg_ptr = long_num; + break; + case long_long_argument: + *(long long*)arg_ptr = long_long_num; + break; + } + if (!match_failure) { + ++items_assigned; + } + } + + ++conversions; + break; + + case 'o': + base = 8; + goto unsigned_int; + + case 'u': + base = 10; + goto unsigned_int; + + case 'x': + case 'X': + base = 16; + + unsigned_int: + + if (match_failure) { + u_long_num = 0; + u_long_long_num = 0; + } else { + if ((format.argument_options == long_long_argument) || + (format.argument_options == intmax_argument)) { + u_long_long_num = __strtoull( + base, format.field_width, ReadProc, ReadProcArg, + &num_chars, &negative, &overflow); + } else { + u_long_num = __strtoul(base, format.field_width, ReadProc, + ReadProcArg, &num_chars, &negative, + &overflow); + } + + if (!num_chars) { + if (!is_secure) { + goto exit; + } else { + match_failure = 1; + u_long_num = 0; + u_long_long_num = 0; + goto unsigned_int_assign; + } + } + + chars_read += num_chars; + + if (negative) + if (format.argument_options == long_long_argument) + u_long_long_num = -u_long_long_num; + else + + u_long_num = -u_long_num; + } + + unsigned_int_assign: + if (arg_ptr) { + switch (format.argument_options) { + case normal_argument: + *(unsigned int*)arg_ptr = u_long_num; + break; + case char_argument: + *(unsigned char*)arg_ptr = u_long_num; + break; + case short_argument: + *(unsigned short*)arg_ptr = u_long_num; + break; + case long_argument: + *(unsigned long*)arg_ptr = u_long_num; + break; + case intmax_argument: + *(intmax_t*)arg_ptr = u_long_long_num; + break; + case size_t_argument: + *(size_t*)arg_ptr = u_long_num; + break; + case ptrdiff_argument: + *(ptrdiff_t*)arg_ptr = u_long_num; + break; + case long_long_argument: + *(unsigned long long*)arg_ptr = u_long_long_num; + break; + } + + if (!match_failure) { + ++items_assigned; + } + } + + ++conversions; + + break; + + case 'a': + case 'A': + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': + flt: + if (match_failure) { + long_double_num = NAN; + } else { + long_double_num = __strtold(format.field_width, ReadProc, + ReadProcArg, &num_chars, &overflow); + + if (!num_chars) { + if (!is_secure) { + goto exit; + } else { + match_failure = 1; + long_double_num = NAN; + goto assign_float; + } + } + + chars_read += num_chars; + } + + assign_float: + if (arg_ptr) { + switch (format.argument_options) { + case normal_argument: + *(float*)arg_ptr = long_double_num; + break; + case double_argument: + *(double*)arg_ptr = long_double_num; + break; + case long_double_argument: + *(long double*)arg_ptr = long_double_num; + break; + } + + if (!match_failure) { + ++items_assigned; + } + } + + ++conversions; + + break; + case 'c': + if (!format.field_width_specified) { + format.field_width = 1; + } + + if (arg_ptr) { + if (is_secure) { + elem_valid = 1; + elem_maxsize = va_arg(arg, rsize_t); + } + + num_chars = 0; + + if (match_failure) { + if (elem_maxsize > 0) { + *arg_ptr = 0; + } + continue; + } else { + char* arg_start = arg_ptr; + while (format.field_width-- && + (!is_secure || + ((elem_valid = (elem_maxsize > num_chars)) != 0)) && + ((rval = ((*ReadProc)(ReadProcArg, 0, + __GetAChar))) != EOF)) { + c = rval; + if (format.argument_options == wchar_argument) { + mbtowc(((wchar_t*)arg_ptr), (char*)(&c), 1); + arg_ptr += 1; + } else { + *arg_ptr++ = c; + } + ++num_chars; + } + + c = rval; + if (!num_chars || (is_secure && !elem_valid)) { + if (!is_secure) { + goto exit; + } else { + match_failure = 1; + if (elem_maxsize > 0) { + *arg_start = 0; + } + continue; + } + } + + chars_read += num_chars; + ++items_assigned; + } + } else { + num_chars = 0; + + while (format.field_width-- && + ((rval = ((*ReadProc)(ReadProcArg, 0, __GetAChar))) != + EOF)) { + c = rval; + ++num_chars; + } + c = rval; + if (!num_chars) { + goto exit; + } + } + + ++conversions; + break; + + case '%': + if (match_failure) { + continue; + } else { + while (isspace(c = (*ReadProc)(ReadProcArg, 0, __GetAChar))) + ++chars_read; + + if (c != '%') { + (*ReadProc)(ReadProcArg, c, __UngetAChar); + if (!is_secure) { + goto exit; + } else { + match_failure = 1; + continue; + } + } + + ++chars_read; + } + break; + + case 's': + if (!match_failure) { + c = (*ReadProc)(ReadProcArg, 0, __GetAChar); + while (isspace(c)) { + ++chars_read; + c = (*ReadProc)(ReadProcArg, 0, __GetAChar); + } + + (*ReadProc)(ReadProcArg, c, __UngetAChar); + } + case '[': + if (arg_ptr) { + if (is_secure) { + elem_valid = 1; + elem_maxsize = va_arg(arg, rsize_t) - 1; + } + + num_chars = 0; + + if (match_failure) { + if (elem_maxsize > 0) { + *arg_ptr = 0; + } + continue; + } else { + char* arg_start = arg_ptr; + + while ( + format.field_width-- && + (!is_secure || + ((elem_valid = (elem_maxsize >= num_chars)) != 0)) && + ((rval = ((*ReadProc)(ReadProcArg, 0, __GetAChar))) != + EOF)) { + c = rval; + + if (!tst_char_map(format.char_set, c)) { + break; + } + + if (format.argument_options == wchar_argument) { + mbtowc(((wchar_t*)arg_ptr), (char*)&c, 1); + arg_ptr = (char*)((wchar_t*)arg_ptr + 1); + } else { + *arg_ptr++ = c; + } + ++num_chars; + } + c = rval; + + if (!num_chars || (is_secure && !elem_valid)) { + (*ReadProc)(ReadProcArg, c, __UngetAChar); + if (!is_secure) { + goto exit; + } else { + match_failure = 1; + if (elem_maxsize > 0) { + *arg_start = 0; + } + continue; + } + } + + chars_read += num_chars; + + if (format.argument_options == wchar_argument) { + *(wchar_t*)arg_ptr = L'\0'; + } else { + *arg_ptr = 0; + } + + ++items_assigned; + } + } else { + num_chars = 0; + + while (format.field_width-- && + ((rval = ((*ReadProc)(ReadProcArg, 0, __GetAChar))) != + EOF)) { + c = rval; + if (!tst_char_map(format.char_set, c)) { + break; + } + + ++num_chars; + } + c = rval; + + if (!num_chars) { + (*ReadProc)(ReadProcArg, c, __UngetAChar); + break; + } + chars_read += num_chars; + } + + if (format.field_width >= 0) { + (*ReadProc)(ReadProcArg, c, __UngetAChar); + } + + ++conversions; + break; + + case 'n': + if (arg_ptr) { + switch (format.argument_options) { + case normal_argument: + *(int*)arg_ptr = chars_read; + break; + case short_argument: + *(short*)arg_ptr = chars_read; + break; + case long_argument: + *(long*)arg_ptr = chars_read; + break; + case char_argument: + *(char*)arg_ptr = chars_read; + break; + case long_long_argument: + *(long long*)arg_ptr = chars_read; + break; + } + } + + continue; + + case bad_conversion: + default: + goto exit; + } + } + +exit: + + if ((*ReadProc)(ReadProcArg, 0, __TestForError) && conversions == 0) { + return EOF; + } + + return items_assigned; +} + +inline int vsscanf(const char* s, const char* format, va_list arg) { + __InStrCtrl isc; + isc.NextChar = (char*)s; + + if ((s == 0) || (*isc.NextChar == '\0')) { + return -1; + } + + isc.NullCharDetected = 0; + return __sformatter(&__StringRead, (void*)&isc, format, arg, 0); +} + +int sscanf(const char* s, const char* pFormat, ...) { + int ret; + va_list args; + va_start(args, pFormat); + return vsscanf(s, pFormat, args); +} diff --git a/src/MSL/string.c b/src/MSL/string.c new file mode 100644 index 00000000..58e1337a --- /dev/null +++ b/src/MSL/string.c @@ -0,0 +1,255 @@ +#include "string.h" + +#define K1 0x80808080 +#define K2 0xFEFEFEFF + +#define set_unk(x, y) \ + x[(unsigned char)(y) >> 3] |= (unsigned char)(1 << ((y)&7)) +#define cond_unk(x, y) \ + (x[(unsigned char)(y) >> 3] & (unsigned char)(1 << ((y)&7))) +typedef unsigned char unk[32]; + +// thanks metrowerks very cool +char* strcpy(char* dst, const char* src) { + register u8 *destb, *fromb; + register u32 w, t, align; + + fromb = (u8*)src; + destb = (u8*)dst; + + if ((align = ((int)fromb & 3)) != ((int)destb & 3)) { + goto bytecopy; + } + + if (align) { + if ((*destb = *fromb) == 0) { + return (dst); + } + for (align = 3 - align; align; align--) { + if ((*(++destb) = *(++fromb)) == 0) { + return (dst); + } + } + ++destb; + ++fromb; + } + + w = *((int*)(fromb)); + + t = w + K2; + t &= ~w; + t &= K1; + if (t) { + goto bytecopy; + } + --((int*)(destb)); + + do { + *(++((int*)(destb))) = w; + w = *(++((int*)(fromb))); + + t = w + K2; + t &= ~w; + t &= K1; + if (t) { + goto adjust; + } + } while (1); + +adjust: + ++((int*)(destb)); +bytecopy: + if ((*destb = *fromb) == 0) { + return dst; + } + do { + if ((*(++destb) = *(++fromb)) == 0) { + return dst; + } + } while (1); + + return dst; +} + +char* strncpy(char* dst, const char* src, size_t n) { + const unsigned char* p = (const unsigned char*)src - 1; + unsigned char* q = (unsigned char*)dst - 1; + unsigned char zero = 0; + + n++; + + while (--n) { + if (!(*++q = *++p)) { + while (--n) { + *++q = 0; + } + break; + } + } + return (dst); +} + +char* strcat(char* dst, const char* src) { + const u8* p = (u8*)src - 1; + u8* q = (u8*)dst - 1; + + while (*++q) + ; + + q--; + + while (*++q = *++p) + ; + + return (dst); +} + +char* strncat(char* dst, const char* src, size_t n) { + const u8* p = (u8*)src - 1; + u8* q = (u8*)dst - 1; + + while (*++q) + ; + + q--; + n++; + + while (--n) { + if (!(*++q = *++p)) { + q--; + break; + } + } + + *++q = 0; + + return dst; +} + +int strcmp(const char* str1, const char* str2) { + // bless metrowerks for this implementation + register u8* left = (u8*)str1; + register u8* right = (u8*)str2; + u32 align, l1, r1, x; + + l1 = *left; + r1 = *right; + if (l1 - r1) { + return (l1 - r1); + } + + if ((align = ((int)left & 3)) != ((int)right & 3)) { + goto bytecopy; + } + if (align) { + if (l1 == 0) { + return 0; + } + for (align = 3 - align; align; align--) { + l1 = *(++left); + r1 = *(++right); + if (l1 - r1) { + return (l1 - r1); + } + if (l1 == 0) { + return 0; + } + } + left++; + right++; + } + + l1 = *(int*)left; + r1 = *(int*)right; + x = l1 + K2; + x &= ~l1; + if (x & K1) { + goto adjust; + } + while (l1 == r1) { + l1 = *(++((int*)(left))); + r1 = *(++((int*)(right))); + x = l1 + K2; + if (x & K1) { + goto adjust; + } + } + +adjust: + l1 = *left; + r1 = *right; + if (l1 - r1) { + return (l1 - r1); + } +bytecopy: + if (l1 == 0) { + return 0; + } + do { + l1 = *(++left); + r1 = *(++right); + if (l1 - r1) { + return (l1 - r1); + } + if (l1 == 0) { + return 0; + } + } while (1); +} + +int strncmp(const char* str1, const char* str2, size_t n) { + const u8* p1 = (u8*)str1 - 1; + const u8* p2 = (u8*)str2 - 1; + u32 c1, c2; + + n++; + + while (--n) { + if ((c1 = *++p1) != (c2 = *++p2)) { + return (c1 - c2); + } else if (!c1) { + break; + } + } + return 0; +} + +char* strchr(const char* str, int chr) { + const u8* p = (u8*)str - 1; + u32 c = (chr & 0xFF); + u32 ch; + + while (ch = *++p) { + if (ch == c) { + return ((char*)p); + } + } + + return (c ? 0 : (char*)p); +} + +char* strstr(const char* str, const char* pat) { + u8* s1 = (u8*)str - 1; + u8* p1 = (u8*)pat - 1; + u32 firstc, c1, c2; + + if (pat == NULL || !(firstc = *++p1)) { + return (char*)str; + } + + while ((c1 = *++s1)) { + if (c1 == firstc) { + const u8* s2 = s1 - 1; + const u8* p2 = p1 - 1; + + while ((c1 = *(++s2)) == (c2 = *(++p2)) && c1) + ; + + if (!c2) { + return (char*)s1; + } + } + } + + return NULL; +} diff --git a/src/MSL/strtold.c b/src/MSL/strtold.c new file mode 100644 index 00000000..ebd2f8dc --- /dev/null +++ b/src/MSL/strtold.c @@ -0,0 +1,624 @@ +#include "ansi_fp.h" +#include "ctype.h" +#include "errno.h" +#include "float.h" +#include "limits.h" +#include "locale.h" +#include "mem.h" +#include "stdio_api.h" + +#pragma exceptions on + +extern double nan(const char*); +extern double __dec2num(const decimal*); + +#define HUGE_VAL (*(double*)__double_huge) + +#define success(scan_state) (scan_state & 3628) +#define hex_success(count, scan_state) (count - 1 > 2 && scan_state & (398)) +#define final_state(scan_state) ((scan_state) & (2048 | 4096)) +#define fetch() (count++, (*ReadProc)(ReadProcArg, 0, __GetAChar)) +#define unfetch(c) ((*ReadProc)(ReadProcArg, c, __UngetAChar)) + +long double __strtold(int max_width, int (*ReadProc)(void*, int, int), + void* ReadProcArg, int* chars_scanned, int* overflow) { + int scan_state = 1; + int hex_scan_state = 0; + int count = 0; + int spaces = 0; + int c; + decimal d = {0, 0, 0, {0, ""}}; + int sig_negative = 0; + int exp_negative = 0; + long exp_value = 0; + int exp_adjust = 0; + register long double result = 0.0; + int sign_detected = 0; + int radix_marker = *(unsigned char*)(__lconv).decimal_point; + + unsigned char* chptr; + unsigned char mantissa[8]; + unsigned mantissa_digits; + unsigned long exponent = 0; + + int ui; + unsigned char uch, uch1; + int NibbleIndex; + int expsign = 0; + int exp_digits = 0; + unsigned intdigits = 0; + + *overflow = 0; + c = fetch(); + + while (count <= max_width && c != -1 && !final_state(scan_state)) { + switch (scan_state) { + case 1: + if (isspace(c)) { + c = fetch(); + count--; + spaces++; + break; + } + + switch (toupper(c)) { + case '-': + sig_negative = 1; + + case '+': + c = fetch(); + sign_detected = 1; + break; + case 'I': + c = fetch(); + scan_state = 16384; + break; + + case 'N': + c = fetch(); + scan_state = 8192; + break; + + default: + scan_state = 2; + break; + } + break; + + case 16384: { + int i = 1; + char model[] = "INFINITY"; + + while ((i < 8) && (toupper(c) == model[i])) { + i++; + c = fetch(); + } + + if ((i == 3) || (i == 8)) { + if (sig_negative) { + result = -INFINITY; + /* TODO -- I AM A HACK */ + __asm { + frsp result, result + } + ; + } else { + result = INFINITY; + } + + *chars_scanned = spaces + i + sign_detected; + return result; + } else { + scan_state = 4096; + } + + break; + } + + case 8192: { + int i = 1, j = 0; + char model[] = "NAN("; + char nan_arg[32] = ""; + while ((i < 4) && (toupper(c) == model[i])) { + i++; + c = fetch(); + } + + if ((i == 3) || (i == 4)) { + if (i == 4) { + while ((j < 32) && + (isdigit(c) || isalpha(c) || (c == radix_marker))) { + nan_arg[j++] = (char)c; + c = fetch(); + } + + if (c != ')') { + scan_state = 4096; + break; + } else { + j++; + } + } + nan_arg[j] = '\0'; + + if (sig_negative) { + result = -nan(nan_arg); + } else { + result = nan(nan_arg); + } + + *chars_scanned = spaces + i + j + sign_detected; + return result; + } else { + scan_state = 4096; + } + break; + } + + case 2: + if (c == radix_marker) { + scan_state = 16; + c = fetch(); + break; + } + if (!isdigit(c)) { + scan_state = 4096; + break; + } + + if (c == '0') { + c = fetch(); + if (toupper(c) == 'X') { + scan_state = 32768; + hex_scan_state = 1; + } else { + scan_state = 4; + } + break; + } + + scan_state = 8; + break; + + case 4: + if (c == '0') { + c = fetch(); + + break; + } + scan_state = 8; + break; + + case 8: + if (!isdigit(c)) { + if (c == radix_marker) { + scan_state = 32; + c = fetch(); + } else { + scan_state = 64; + } + break; + } + if (d.sig.length < 20) { + d.sig.text[d.sig.length++] = (unsigned char)c; + } else { + exp_adjust++; + } + + c = fetch(); + break; + + case 16: + if (!isdigit(c)) { + scan_state = 4096; + break; + } + + scan_state = 32; + break; + + case 32: + if (!isdigit(c)) { + scan_state = 64; + break; + } + + if (d.sig.length < 20) { + if (c != '0' || d.sig.length) { + d.sig.text[d.sig.length++] = (unsigned char)c; + } + + exp_adjust--; + } + c = fetch(); + break; + + case 64: + if (toupper(c) == 'E') { + scan_state = 128; + c = fetch(); + break; + } + scan_state = 2048; + break; + + case 128: + if (c == '+') { + c = fetch(); + } else if (c == '-') { + c = fetch(); + exp_negative = 1; + } + + scan_state = 256; + break; + + case 256: + if (!isdigit(c)) { + scan_state = 4096; + break; + } + + if (c == '0') { + scan_state = 512; + c = fetch(); + break; + } + + scan_state = 1024; + break; + + case 512: + if (c == '0') { + c = fetch(); + break; + } + + scan_state = 1024; + break; + + case 1024: + if (!isdigit(c)) { + scan_state = 2048; + break; + } + + exp_value = exp_value * 10 + (c - '0'); + if (exp_value > SHRT_MAX) { + *overflow = 1; + } + + c = fetch(); + break; + + case 32768: { + switch (hex_scan_state) { + case 1: + memset(mantissa, 0, sizeof(mantissa)); + chptr = mantissa; + mantissa_digits = (53 + 3) / 4; + intdigits = 0; + NibbleIndex = 0; + hex_scan_state = 2; + c = fetch(); + break; + + case 2: + if (c == '0') { + c = fetch(); + break; + } + + hex_scan_state = 4; + break; + + case 4: + if (!isxdigit(c)) { + if (c == radix_marker) { + hex_scan_state = 8; + c = fetch(); + } + + else { + hex_scan_state = 16; + } + break; + } + + if (intdigits < mantissa_digits) { + intdigits++; + uch = *(chptr + NibbleIndex / 2); + + ui = toupper(c); + if (ui >= 'A') { + ui = ui - 'A' + 10; + } else { + ui -= '0'; + } + + uch1 = (unsigned char)ui; + + if ((NibbleIndex % 2) != 0) { + uch |= uch1; + } else { + uch |= (unsigned char)(uch1 << 4); + } + + *(chptr + NibbleIndex++ / 2) = uch; + c = fetch(); + } + + else { + c = fetch(); + } + + break; + + case 8: + if (!isxdigit(c)) { + hex_scan_state = 16; + break; + } + + if (intdigits < mantissa_digits) { + uch = *(chptr + NibbleIndex / 2); + ui = toupper(c); + + if (ui >= 'A') { + ui = ui - 'A' + 10; + } else { + ui -= '0'; + } + + uch1 = (unsigned char)ui; + + if ((NibbleIndex % 2) != 0) { + uch |= uch1; + } else { + uch |= (unsigned char)(uch1 << 4); + } + + *(chptr + NibbleIndex++ / 2) = uch; + c = fetch(); + } else { + c = fetch(); + } + break; + + case 16: + if (toupper(c) == 'P') { + hex_scan_state = 32; + exp_digits++; + c = fetch(); + } else { + scan_state = 2048; + } + + break; + + case 32: + exp_digits++; + if (c == '-') { + expsign = 1; + } else if (c != '+') { + c = unfetch(c); + count--; + exp_digits--; + } + + hex_scan_state = 64; + c = fetch(); + break; + + case 64: + if (!isdigit(c)) { + scan_state = 4096; + break; + } + + if (c == '0') { + exp_digits++; + hex_scan_state = 128; + c = fetch(); + break; + } + + hex_scan_state = 256; + break; + + case 128: + if (c == '0') { + c = fetch(); + break; + } + + hex_scan_state = 256; + break; + + case 256: + if (!isdigit(c)) { + scan_state = 2048; + break; + } + + exponent = exponent * 10 + (c - '0'); + + if (exp_value > SHRT_MAX) { + *overflow = 1; + } + + exp_digits++; + c = fetch(); + + break; + } + } break; + } + } + + if (scan_state != 32768 ? !success(scan_state) + : !hex_success(count, hex_scan_state)) { + count = 0; + *chars_scanned = 0; + } else { + count--; + *chars_scanned = count + spaces; + } + + unfetch(c); + + if (hex_scan_state == 0) { + if (exp_negative) { + exp_value = -exp_value; + } + + { + int n = d.sig.length; + unsigned char* p = &d.sig.text[n]; + + while (n-- && *--p == '0') { + exp_adjust++; + } + + d.sig.length = (unsigned char)(n + 1); + + if (d.sig.length == 0) { + d.sig.text[d.sig.length++] = '0'; + } + } + + exp_value += exp_adjust; + + // idk SHRT_MIN does not work... + if (-0x8000 > exp_value || SHRT_MAX < exp_value) { + *overflow = 1; + } + + if (*overflow) { + if (exp_negative) { + return 0.0; + } else { + return sig_negative ? -HUGE_VAL : HUGE_VAL; + } + } + + d.exponent = (short)exp_value; + + result = __dec2num(&d); + + if (result != 0.0 && result < LDBL_MIN) { + *overflow = 1; + } else if (result > LDBL_MAX) { + *overflow = 1; + result = HUGE_VAL; + } + + if (sig_negative && success(scan_state)) { + result = -result; + } + + return result; + } else { + unsigned mantissa_bit, dbl_bit; + unsigned one_bit; + long double dbl_bits_storage; + unsigned char* dbl_bits = (unsigned char*)&dbl_bits_storage; + + if (expsign) { + exponent = -exponent; + } + + exponent += intdigits * 4; + + one_bit = 0; + while (one_bit < 4 && !(mantissa[0] & (0x80 >> one_bit))) { + one_bit++; + exponent--; + } + + exponent--; + + if (1) { + one_bit++; + } + + if (one_bit) { + unsigned char carry = 0; + for (chptr = mantissa + sizeof(mantissa) - 1; chptr >= mantissa; + chptr--) { + unsigned char a = *chptr; + *chptr = (unsigned char)((a << one_bit) | carry); + carry = (unsigned char)(a >> (8 - one_bit)); + } + } + + memset(dbl_bits, 0, sizeof(dbl_bits_storage)); + dbl_bit = (64 - 52); + + for (mantissa_bit = 0; mantissa_bit < 52; mantissa_bit += 8) { + unsigned char ui = mantissa[mantissa_bit >> 3]; + int halfbits; + + if (mantissa_bit + 8 > 52) { + ui &= 0xff << (52 - mantissa_bit); + } + + halfbits = (dbl_bit & 7); + dbl_bits[dbl_bit >> 3] |= (unsigned char)(ui >> halfbits); + dbl_bit += 8; + dbl_bits[dbl_bit >> 3] |= (unsigned char)(ui << (8 - halfbits)); + } + + exponent += 1024 - 1; + + if ((exponent & ~(1024 * 2 - 1))) { + *overflow = 1; + return 0.0; + } + + exponent <<= 32 - 11; + + dbl_bits[0] |= exponent >> 25; + + if (11 > 7) { + dbl_bits[1] |= exponent >> 17; + } + + if (11 > 15) { + dbl_bits[2] |= exponent >> 9; + } + + if (11 > 23) { + dbl_bits[3] |= exponent >> 1; + } + + if (sig_negative) { + dbl_bits[0] |= 0x80; + } + + result = *(long double*)dbl_bits; + + return result; + } +} + +double atof(const char* str, char** end) { + double abs_value; + double value; + int overflow; + int count; + + __InStrCtrl isc; + isc.NextChar = (char*)str; + isc.NullCharDetected = 0; + + value = __strtold(INT_MAX, &__StringRead, (void*)&isc, &count, &overflow); + + abs_value = __fabs(value); + + if (overflow || + (value != 0.0 && (abs_value < DBL_MIN || abs_value > DBL_MAX))) + errno = ERANGE; + + return value; +} diff --git a/src/MSL/strtoul.c b/src/MSL/strtoul.c new file mode 100644 index 00000000..03e4ad58 --- /dev/null +++ b/src/MSL/strtoul.c @@ -0,0 +1,288 @@ +#include "strtoul.h" +#include "ctype.h" +#include "errno.h" +#include "limits.h" +#include "stdio.h" +#include "stdio_api.h" + +#pragma exceptions on + +enum scan_states { + start = 0x01, + check_for_zero = 0x02, + leading_zero = 0x04, + need_digit = 0x08, + digit_loop = 0x10, + finished = 0x20, + failure = 0x40 +}; + +#define final_state(scan_state) (scan_state & (0x20 | 0x40)) +#define success(scan_state) (scan_state & (0x4 | 0x10 | 0x20)) +#define fetch() (count++, (*ReadProc)(ReadProcArg, 0, __GetAChar)) +#define unfetch(c) ((*ReadProc)(ReadProcArg, c, __UngetAChar)) + +// jumptable_80398FEC located in scanf + +unsigned long __strtoul(int base, int max_width, int (*ReadProc)(void*, int, int), void* ReadProcArg, + int* chars_scanned, int* negative, int* overflow) { + int scan_state = start; + int count = 0; + int spaces = 0; + unsigned long value = 0; + unsigned long value_max = 0; + int c; + + *negative = *overflow = 0; + + if (base < 0 || base == 1 || base > 36 || max_width < 1) { + scan_state = failure; + } else { + c = fetch(); + } + + if (base != 0) { + value_max = ULONG_MAX / base; + } + + while (count <= max_width && c != -1 && !final_state(scan_state)) { + switch (scan_state) { + case start: + if (isspace(c)) { + c = fetch(); + count--; + spaces++; + break; + } + + if (c == '+') { + c = fetch(); + } else if (c == '-') { + c = fetch(); + *negative = 1; + } + + scan_state = check_for_zero; + break; + + case check_for_zero: + if (base == 0 || base == 16) { + if (c == '0') { + scan_state = leading_zero; + c = fetch(); + break; + } + } + + scan_state = need_digit; + break; + + case 4: + if (c == 'X' || c == 'x') { + base = 16; + scan_state = need_digit; + c = fetch(); + break; + } + + if (base == 0) { + base = 8; + } + + scan_state = digit_loop; + break; + + case need_digit: + case digit_loop: + if (base == 0) { + base = 10; + } + + if (!value_max) { + value_max = ULONG_MAX / base; + } + + if (isdigit(c)) { + if ((c -= '0') >= base) { + if (scan_state == digit_loop) { + scan_state = finished; + } else { + scan_state = failure; + } + + c += '0'; + break; + } + } else if (!isalpha(c) || (toupper(c) - 'A' + 10) >= base) { + if (scan_state == digit_loop) { + scan_state = finished; + } else { + scan_state = failure; + } + + break; + } else { + c = toupper(c) - 'A' + 10; + } + + if (value > value_max) { + *overflow = 1; + } + + value *= base; + + if (c > (ULONG_MAX - value)) { + *overflow = 1; + } + + value += c; + scan_state = digit_loop; + c = fetch(); + break; + } + } + + if (!success(scan_state)) { + count = 0; + value = 0; + *chars_scanned = 0; + } else { + count--; + *chars_scanned = count + spaces; + } + + unfetch(c); + return value; +} + +unsigned long long __strtoull(int base, int max_width, int (*ReadProc)(void*, int, int), void* ReadProcArg, + int* chars_scanned, int* negative, int* overflow) { + int scan_state = start; + int count = 0; + int spaces = 0; + unsigned long long value = 0; + unsigned long long value_max = 0; + unsigned long long ullmax = ULLONG_MAX; + int c; + + *negative = *overflow = 0; + + if (base < 0 || base == 1 || base > 36 || max_width < 1) { + scan_state = failure; + } else { + c = fetch(); + } + + if (base != 0) { + value_max = ullmax / base; + } + + while (count <= max_width && c != -1 && !final_state(scan_state)) { + switch (scan_state) { + case start: + if (isspace(c)) { + c = fetch(); + count--; + spaces++; + break; + } + + if (c == '+') { + c = fetch(); + } else if (c == '-') { + c = fetch(); + *negative = 1; + } + + scan_state = check_for_zero; + break; + + case check_for_zero: + if (base == 0 || base == 16) { + if (c == '0') { + scan_state = leading_zero; + c = fetch(); + break; + } + } + + scan_state = need_digit; + break; + + case leading_zero: + if (c == 'X' || c == 'x') { + base = 16; + scan_state = need_digit; + c = fetch(); + break; + } + + if (base == 0) { + base = 8; + } + + scan_state = digit_loop; + break; + + case need_digit: + case digit_loop: + if (base == 0) { + base = 10; + } + + if (!value_max) { + value_max = ullmax / base; + } + + if (isdigit(c)) { + if ((c -= '0') >= base) { + if (scan_state == digit_loop) { + scan_state = finished; + } else { + scan_state = failure; + } + + c += '0'; + break; + } + } else if (!isalpha(c) || (toupper(c) - 'A' + 10) >= base) { + if (scan_state == digit_loop) { + scan_state = finished; + } else { + scan_state = failure; + } + + break; + } else { + c = toupper(c) - 'A' + 10; + } + + if (value > value_max) { + *overflow = 1; + } + + value *= base; + + if (c > (ullmax - value)) { + *overflow = 1; + } + + value += c; + scan_state = digit_loop; + c = fetch(); + break; + } + } + + if (!success(scan_state)) { + count = 0; + value = 0; + *chars_scanned = 0; + } else { + count--; + *chars_scanned = count + spaces; + } + + unfetch(c); + return value; +} diff --git a/src/MSL/uart_console_io_gcn.c b/src/MSL/uart_console_io_gcn.c new file mode 100644 index 00000000..bcfe7be6 --- /dev/null +++ b/src/MSL/uart_console_io_gcn.c @@ -0,0 +1,40 @@ +#include "UART_console_io_gcn.h" + +int __TRK_write_console(unsigned long, unsigned char *, size_t *, void *); + +UARTError __init_uart_console(void) { + UARTError err = kUARTNoError; + static int initialized = 0; + + if (initialized == 0) { + err = InitializeUART(kBaud57600); + + if (err == kUARTNoError) { + initialized = 1; + } + } + + return err; +} + +#pragma exceptions on + +int __write_console(unsigned long handle, unsigned char *buffer, size_t *count, void *ref) { + if (!(OSGetConsoleType() & 0x20000000)) { + if (__init_uart_console() != kUARTNoError) { + return 1; + } + + if (WriteUARTN(buffer, *count) != kUARTNoError) { + *count = 0; + return 1; + } + } + + __TRK_write_console(handle, buffer, count, ref); + return 0; +} + +int __close_console(unsigned long handle) { + return 0; +} diff --git a/src/MSL/wchar_io.c b/src/MSL/wchar_io.c new file mode 100644 index 00000000..9f558daf --- /dev/null +++ b/src/MSL/wchar_io.c @@ -0,0 +1,35 @@ +#include + +int fwide(FILE *pFile, int file_mode) { + int orientation; + int res; + + if ((pFile == NULL) || (pFile->mode.file == file_closed)) { + return 0; + } + + orientation = pFile->mode.file_orientation; + + switch (orientation) { + case file_unoriented: + if (file_mode > 0) { + pFile->mode.file_orientation = file_wide_oriented; + } + else if (file_mode < 0) { + pFile->mode.file_orientation = file_char_oriented; + } + + res = file_mode; + break; + + case file_wide_oriented: + res = 1; + break; + + case file_char_oriented: + res = -1; + break; + } + + return res; +} diff --git a/src/MSL/wctype.c b/src/MSL/wctype.c new file mode 100644 index 00000000..60ac9ac3 --- /dev/null +++ b/src/MSL/wctype.c @@ -0,0 +1,77 @@ +#include "wctype.h" + +const unsigned short __wctype_mapC[0x100] = { + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x106, 0x104, + 0x104, 0x104, 0x104, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, + 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x4, 0x142, + 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, + 0xD0, 0xD0, 0xD0, 0xD0, 0x458, 0x458, 0x458, 0x458, 0x458, 0x458, 0x458, + 0x458, 0x458, 0x458, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0x651, + 0x651, 0x651, 0x651, 0x651, 0x651, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, + 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, 0x251, + 0x251, 0x251, 0x251, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0x471, 0x471, + 0x471, 0x471, 0x471, 0x471, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, + 0x71, 0x71, 0xD0, 0xD0, 0xD0, 0xD0, 0x4}; + +const wchar_t __wlower_mapC[0x100] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, + 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, L' ', L'!', L'"', L'#', + L'$', L'%', L'&', L'\'', L'(', L')', L'*', L'+', L',', + L'-', L'.', L'/', L'0', L'1', L'2', L'3', L'4', L'5', + L'6', L'7', L'8', L'9', L':', L';', L'<', L'=', L'>', + L'?', L'@', L'a', L'b', L'c', L'd', L'e', L'f', L'g', + L'h', L'i', L'j', L'k', L'l', L'm', L'n', L'o', L'p', + L'q', L'r', L's', L't', L'u', L'v', L'w', L'x', L'y', + L'z', L'[', L'\\', L']', L'^', L'_', L'`', L'a', L'b', + L'c', L'd', L'e', L'f', L'g', L'h', L'i', L'j', L'k', + L'l', L'm', L'n', L'o', L'p', L'q', L'r', L's', L't', + L'u', L'v', L'w', L'x', L'y', L'z', L'{', L'|', L'}', + L'~', 0x007F, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, + 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, + 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, 0x00A0, 0x00A1, + 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, + 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, + 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, + 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, + 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, + 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, + 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, + 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, + 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, + 0x00FC, 0x00FD, 0x00FE, 0x00FF}; + +const wchar_t __wupper_mapC[0x100] = { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, + 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, + 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, L' ', L'!', L'"', L'#', + L'$', L'%', L'&', L'\'', L'(', L')', L'*', L'+', L',', + L'-', L'.', L'/', L'0', L'1', L'2', L'3', L'4', L'5', + L'6', L'7', L'8', L'9', L':', L';', L'<', L'=', L'>', + L'?', L'@', L'A', L'B', L'C', L'D', L'E', L'F', L'G', + L'H', L'I', L'J', L'K', L'L', L'M', L'N', L'O', L'P', + L'Q', L'R', L'S', L'T', L'U', L'V', L'W', L'X', L'Y', + L'Z', L'[', L'\\', L']', L'^', L'_', L'`', L'A', L'B', + L'C', L'D', L'E', L'F', L'G', L'H', L'I', L'J', L'K', + L'L', L'M', L'N', L'O', L'P', L'Q', L'R', L'S', L'T', + L'U', L'V', L'W', L'X', L'Y', L'Z', L'{', L'|', L'}', + L'~', 0x007F, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, + 0x0087, 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, + 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, 0x00A0, 0x00A1, + 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, 0x00A8, 0x00A9, 0x00AA, + 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, 0x00B0, 0x00B1, 0x00B2, 0x00B3, + 0x00B4, 0x00B5, 0x00B6, 0x00B7, 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, + 0x00BD, 0x00BE, 0x00BF, 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, + 0x00C6, 0x00C7, 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, + 0x00CF, 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, 0x00E0, + 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, 0x00E8, 0x00E9, + 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, 0x00F0, 0x00F1, 0x00F2, + 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, 0x00F8, 0x00F9, 0x00FA, 0x00FB, + 0x00FC, 0x00FD, 0x00FE, 0x00FF}; diff --git a/src/MSL/wmem.c b/src/MSL/wmem.c new file mode 100644 index 00000000..d434f7f3 --- /dev/null +++ b/src/MSL/wmem.c @@ -0,0 +1,18 @@ +#include + +wchar_t* wmemcpy(wchar_t* dest, const wchar_t* src, size_t n) { + return (wchar_t*)memcpy(dest, src, n * sizeof(wchar_t)); +} + +wchar_t* wmemchr(wchar_t* s, wchar_t c, size_t n) { + while (n) { + if (*s == c) { + return s; + } + + s++; + n--; + } + + return NULL; +} diff --git a/src/MSL/wprintf.c b/src/MSL/wprintf.c new file mode 100644 index 00000000..fa6511a9 --- /dev/null +++ b/src/MSL/wprintf.c @@ -0,0 +1,1321 @@ +#include "ansi_fp.h" +#include "stdio_api.h" +#include "pformatter.h" +#include "wctype.h" + +#pragma exceptions on + +inline long double fabsl(long double x) { + return __fabs((double)x); +} + +wchar_t* wcscpy(wchar_t *pDest, const wchar_t *pSrc); +size_t strlen(const char *pStr); +void* memchr(const void *, int, size_t); +int mbtowc(wchar_t *pDest, const char *s, size_t num); + +typedef struct { + unsigned char justification_options; // 0x0 + unsigned char sign_options; // 0x1 + unsigned char precision_specified; // 0x2 + unsigned char alternate_form; // 0x3 + unsigned char argument_options; // 0x4 + wchar_t conversion_char; // 0x5 + int field_width; // 0x8 + int precision; // 0xC +} print_format; + +const wchar_t* parse_format(const wchar_t *format_string, va_list *arg, print_format *format) { + print_format f; + const wchar_t* s = format_string; + wchar_t c; + int flag_found; + f.justification_options = right_justification; + f.sign_options = only_minus; + f.precision_specified = 0; + f.alternate_form = 0; + f.argument_options = normal_argument; + f.field_width = 0; + f.precision = 0; + + if ((c = *++s) == L'%') { + f.conversion_char = c; + *format = f; + return ((const wchar_t*)s + 1); + } + + for (;;) { + flag_found = 1; + + switch (c) { + case L'-': + f.justification_options = left_justification; + break; + case L'+': + f.sign_options = sign_always; + break; + case L' ': + if (f.sign_options != sign_always) { + f.sign_options = space_holder; + } + break; + case L'#': + f.alternate_form = 1; + break; + case L'0': + if (f.justification_options != left_justification) { + f.justification_options = zero_fill; + } + break; + default: + flag_found = 0; + break; + } + + if (flag_found) { + c = *++s; + } + else { + break; + } + } + + if (c == L'*') { + if ((f.field_width = va_arg(*arg, int)) < 0) { + f.justification_options = left_justification; + f.field_width = -f.field_width; + } + + c = *++s; + } + else { + while (iswdigit(c)) { + f.field_width = (f.field_width * 10) + (c - L'0'); + c = *++s; + } + } + + if (f.field_width > 509) { + f.conversion_char = 0xFFFF; + *format = f; + return ((const wchar_t*)s + 1); + } + + if (c == L'.') { + f.precision_specified = 1; + + if ((c = *++s) == L'*') { + if ((f.precision = va_arg(*arg, int)) < 0) { + f.precision_specified = 0; + } + + c = *++s; + } + else { + while (iswdigit(c)) { + f.precision = (f.precision * 10) + (c - L'0'); + c = *++s; + } + } + } + + flag_found = 1; + + switch (c) { + case L'h': + f.argument_options = short_argument; + + if (s[1] == L'h') { + f.argument_options = char_argument; + c = *++s; + } + + break; + + case L'l': + f.argument_options = long_argument; + + if (s[1] == L'l') { + f.argument_options = long_long_argument; + c = *++s; + } + + break; + + case L'L': + f.argument_options = long_double_argument; + break; + case L'j': + f.argument_options = intmax_argument; + break; + case L't': + f.argument_options = ptrdiff_argument; + break; + case L'z': + f.argument_options = size_t_argument; + break; + default: + flag_found = 0; + break; + } + + if (flag_found) { + c = *++s; + } + + f.conversion_char = c; + + switch (c) { + case L'd': + case L'i': + case L'u': + case L'o': + case L'x': + case L'X': + if (f.argument_options == long_double_argument) { + f.argument_options = long_long_argument; + } + + if (!f.precision_specified) { + f.precision = 1; + } + else if (f.justification_options == zero_fill) { + f.justification_options = right_justification; + } + break; + + case L'f': + case L'F': + if (f.argument_options == short_argument || f.argument_options == intmax_argument || f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || f.argument_options == long_long_argument) { + f.conversion_char = 0xFFFF; + break; + } + + if (!f.precision_specified) { + f.precision = 6; + } + break; + + case L'a': + case L'A': + if (!f.precision_specified) { + f.precision = 0xD; + } + + if (f.argument_options == short_argument || f.argument_options == intmax_argument || + f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || + f.argument_options == long_long_argument || f.argument_options == char_argument) { + f.conversion_char = 0xFFFF; + } + + break; + + case L'g': + case L'G': + if (!f.precision) { + f.precision = 1; + } + + case L'e': + case L'E': + if (f.argument_options == short_argument || f.argument_options == intmax_argument || f.argument_options == size_t_argument || f.argument_options == ptrdiff_argument || f.argument_options == long_long_argument || f.argument_options == char_argument) { + f.conversion_char = 0xFFFF; + break; + } + + if (!f.precision_specified) { + f.precision = 6; + } + break; + + case L'p': + f.argument_options = long_argument; + f.alternate_form = 1; + f.conversion_char = L'x'; + f.precision = 8; + break; + + case L'c': + if (f.argument_options == long_argument) { + f.argument_options = wchar_argument; + } + else { + if (f.precision_specified || f.argument_options != normal_argument) { + f.conversion_char = 0xFFFF; + } + } + + break; + + case L's': + if (f.argument_options == long_argument) { + f.argument_options = wchar_argument; + } + else { + if (f.argument_options != normal_argument) { + f.conversion_char = 0xFFFF; + } + } + + break; + + case L'n': + if (f.argument_options == long_double_argument) { + f.argument_options = long_long_argument; + } + + break; + + default: + f.conversion_char = 0xFFFF; + break; + } + + *format = f; + return ((const wchar_t*)s + 1); +} + +wchar_t * long2str(long num, wchar_t * buff, print_format format) { + unsigned long unsigned_num, base; + wchar_t* p; + int n, digits; + int minus = 0; + unsigned_num = num; + minus = 0; + + p = buff; + *--p = 0; + digits = 0; + + if (!num && !format.precision && !(format.alternate_form && format.conversion_char == L'o')) { + return p; + } + + switch (format.conversion_char) { + case L'd': + case L'i': + base = 10; + + if (num < 0) { + if (num != 0x80000000) { + unsigned_num = -num; + } + + minus = 1; + } + break; + + case L'o': + base = 8; + format.sign_options = only_minus; + break; + + case L'u': + base = 10; + format.sign_options = only_minus; + break; + + case L'x': + case L'X': + base = 16; + format.sign_options = only_minus; + break; + } + + do { + n = unsigned_num % base; + unsigned_num /= base; + + if (n < 10) { + n += L'0'; + } + else { + n -= 10; + + if (format.conversion_char == L'x') { + n += L'a'; + } + else { + n += L'A'; + } + } + + *--p = n; + ++digits; + } + while (unsigned_num != 0); + + if (base == 8 && format.alternate_form && *p != L'0') { + *--p = L'0'; + ++digits; + } + + if (format.justification_options == zero_fill) { + format.precision = format.field_width; + + if (minus || format.sign_options != only_minus) + --format.precision; + + if (base == 16 && format.alternate_form) + format.precision -= 2; + } + + if (buff - p + format.precision > 509) + return 0; + + while (digits < format.precision) { + *--p = L'0'; + ++digits; + } + + if (base == 16 && format.alternate_form) { + *--p = format.conversion_char; + *--p = L'0'; + } + + if (minus) { + *--p = L'-'; + } + else if (format.sign_options == sign_always) { + *--p = L'+'; + } + else if (format.sign_options == space_holder) { + *--p = L' '; + } + + return p; +} + +wchar_t* longlong2str(long long num, wchar_t *pBuf, print_format fmt) { + unsigned long long unsigned_num, base; + wchar_t* p; + int n, digits; + int minus = 0; + unsigned_num = num; + minus = 0; + p = pBuf; + *--p = 0; + digits = 0; + + if (!num && !fmt.precision && !(fmt.alternate_form && fmt.conversion_char == L'o')) { + return p; + } + + switch (fmt.conversion_char) { + case L'd': + case L'i': + base = 10; + + if (num < 0) { + if (num != 0x8000000000000000) { + unsigned_num = -num; + } + + minus = 1; + } + break; + case L'o': + base = 8; + fmt.sign_options = only_minus; + break; + case L'u': + base = 10; + fmt.sign_options = only_minus; + break; + case L'x': + case L'X': + base = 16; + fmt.sign_options = only_minus; + break; + } + + do { + n = unsigned_num % base; + unsigned_num /= base; + + if (n < 10) { + n += L'0'; + } + else { + n -= 10; + if (fmt.conversion_char == L'x') { + n += L'a'; + } + else { + n += L'A'; + } + } + + *--p = n; + ++digits; + } while (unsigned_num != 0); + + if (base == 8 && fmt.alternate_form && *p != L'0') { + *--p = L'0'; + ++digits; + } + + if (fmt.justification_options == zero_fill) { + fmt.precision = fmt.field_width; + + if (minus || fmt.sign_options != only_minus) { + --fmt.precision; + } + + if (base == 16 && fmt.alternate_form) { + fmt.precision -= 2; + } + } + + if (pBuf - p + fmt.precision > 509) { + return 0; + } + + while (digits < fmt.precision) { + *--p = L'0'; + ++digits; + } + + if (base == 16 && fmt.alternate_form) { + *--p = fmt.conversion_char; + *--p = L'0'; + } + + if (minus) { + *--p = L'-'; + } + else if (fmt.sign_options == sign_always) { + *--p = L'+'; + } + else if (fmt.sign_options == space_holder) { + *--p = L' '; + } + + return p; +} + +wchar_t * double2hex(long double num, wchar_t * buff, print_format format) { + wchar_t *p; + unsigned char *q; + unsigned char working_byte; + long double ld; + int expbits, expmask; + unsigned snum; + long exp; + print_format exp_format; + int hex_precision; + int mantissa_bit; + decform form; + decimal dec; + int radix_marker; + + radix_marker = * (unsigned char *)(__lconv).decimal_point; + p = buff; + ld = num; + + if (format.precision > 509) { + return 0; + } + + form.style = (char)0; + form.digits = 0x20; + __num2dec(&form, num, &dec); + + if (fabsl(num) == 0.0) { + p = buff - 6; + wcscpy(p, L"0x0p0"); + return p; + } + + if (*dec.sig.text == 'I') { + if (dec.sign) { + p = buff - 5; + if (format.conversion_char == L'A') + wcscpy(p, L"-INF"); + else + wcscpy(p, L"-inf"); + } + else { + p = buff - 4; + if (format.conversion_char == L'A') + wcscpy(p, L"INF"); + else + wcscpy(p, L"inf"); + } + + return p; + } + else if (*dec.sig.text == 'N') { + if (dec.sign) { + p = buff - 5; + if (format.conversion_char == L'A') + wcscpy(p, L"-NAN"); + else + wcscpy(p, L"-nan"); + } + else { + p = buff - 4; + if (format.conversion_char == L'A') + wcscpy(p, L"NAN"); + else + wcscpy(p, L"nan"); + } + return p; + } + + exp_format.justification_options = 1; + exp_format.sign_options = 1; + exp_format.precision_specified = 0; + exp_format.alternate_form = 0; + exp_format.argument_options = 0; + exp_format.field_width = 0; + exp_format.precision = 1; + exp_format.conversion_char = 'd'; + + expbits = 11; + expmask = 0x7FF; + + snum = ((unsigned char *)&num)[0] << 25; + if (TARGET_FLOAT_EXP_BITS > 7) + snum |= ((unsigned char *)&num)[1] << 17; + if (TARGET_FLOAT_EXP_BITS > 15) + snum |= ((unsigned char *)&num)[2] << 9; + if (TARGET_FLOAT_EXP_BITS > 23) + snum |= ((unsigned char *)&num)[3] << 1; + + snum = (snum >> (32 - expbits)) & expmask; + exp = snum - 0x3FF; + + p = long2str(exp, buff, exp_format); + if (format.conversion_char == L'a') + *--p = L'p'; + else + *--p = L'P'; + q = (unsigned char *)# + + if (TARGET_FLOAT_IMPLICIT_J_BIT) { + mantissa_bit = (1 + expbits + format.precision * 4) - 1; + } + else { + mantissa_bit = (1 + expbits + format.precision * 4) - 4; + } + + for (hex_precision = format.precision; hex_precision >= 1; hex_precision--) { + if (mantissa_bit < 64) { + int mantissa_byte; + + mantissa_byte = mantissa_bit >> 3; + working_byte = (*(q + mantissa_byte)) >> (7 - (mantissa_bit & 7)); + + if ((mantissa_bit & ~7) != ((mantissa_bit - 4) & ~7)) { + working_byte |= ((*(q + (mantissa_byte - 1))) << 8) >> (7 - ((mantissa_bit) & 7)); + } + + if (!TARGET_FLOAT_IMPLICIT_J_BIT) { + if (mantissa_bit == 1 + expbits) { + *--p = radix_marker; + working_byte &= 0x1; + } + } + + if ((working_byte &= 0xF) < 10) { + working_byte += L'0'; + } + else + if (format.conversion_char == L'a') { + working_byte += L'a' - 10; + } + else { + working_byte += L'A' - 10; + } + } + else { + working_byte = L'0'; + } + + *--p = working_byte; + mantissa_bit -= 4; + } + + if (TARGET_FLOAT_IMPLICIT_J_BIT){ + if (format.precision || format.alternate_form) { + *--p = radix_marker; + } + + *--p = L'1'; + } + + if (format.conversion_char == L'a') { + *--p = L'x'; + } + else { + *--p = L'X'; + } + + *--p = L'0'; + + if (dec.sign) { + *--p = L'-'; + } + else if (format.sign_options == 1) { + *--p = L'+'; + } + else if (format.sign_options == 2) { + *--p = L' '; + } + + return p; +} + +void round_decimal(decimal *dec, int new_length) { + char c; + char* p; + int carry; + + if (new_length < 0) { +return_zero: + dec->exponent = 0; + dec->sig.length = 1; + *dec->sig.text = '0'; + return; + } + + if (new_length >= dec->sig.length) { + return; + } + + p = (char*)dec->sig.text + new_length + 1; + c = *--p - L'0'; + + if (c == 5) { + char* q = &((char*)dec->sig.text)[dec->sig.length]; + + while (--q > p && *q == '0'); + carry = (q == p) ? p[-1] & 1 : 1; + } + else { + carry = (c > 5); + } + + while (new_length != 0) { + c = *--p - L'0' + carry; + + if ((carry = (c > 9)) != 0 || c == 0) { + --new_length; + } + else { + *p = c + L'0'; + break; + } + } + + if (carry != 0) { + dec->exponent += 1; + dec->sig.length = 1; + *dec->sig.text = '1'; + return; + } + else if (new_length == 0) { + goto return_zero; + } + + dec->sig.length = new_length; +} + +wchar_t* float2str(long double num, wchar_t *wbuff, print_format format) { + decimal dec; + decform form; + wchar_t* pw; + char* p; + char buff[512]; + char* q; + int n, digits, sign; + int int_digits, frac_digits; + int radix_marker; + + radix_marker = *(unsigned char*)__lconv.decimal_point; + + if (format.precision > 509) { + return 0; + } + + form.style = 0; + form.digits = 0x20; + __num2dec(&form, num, &dec); + p = (char*)dec.sig.text + dec.sig.length; + + while (dec.sig.length > 1 && *--p == '0') { + --dec.sig.length; + ++dec.exponent; + } + + switch (*dec.sig.text) { + case '0': + dec.exponent = 0; + break; + case 'I': + if (num < 0) { + pw = wbuff - 5; + + if (iswupper(format.conversion_char)) { + wcscpy(pw, L"-INF"); + } + else { + wcscpy(pw, L"-inf"); + } + } + else { + pw = wbuff - 4; + if (iswupper(format.conversion_char)) { + wcscpy(pw, L"INF"); + } + else { + wcscpy(pw, L"inf"); + } + } + + return pw; + + case 'N': + if (dec.sign) { + pw = wbuff - 5; + + if (iswupper(format.conversion_char)) { + wcscpy(pw, L"-NAN"); + } + else { + wcscpy(pw, L"-nan"); + } + } + else { + pw = wbuff - 4; + if (iswupper(format.conversion_char)) { + wcscpy(pw, L"NAN"); + } + else { + wcscpy(pw, L"nan"); + } + } + + return pw; + } + + dec.exponent += dec.sig.length - 1; + p = buff + 512; + *--p = 0; + + switch (format.conversion_char) + { + case L'g': + case L'G': + + if (dec.sig.length > format.precision) { + round_decimal(&dec, format.precision); + } + + if (dec.exponent < -4 || dec.exponent >= format.precision) + { + if (format.alternate_form) { + --format.precision; + } + else { + format.precision = dec.sig.length - 1; + } + + if (format.conversion_char == L'g') { + format.conversion_char = L'e'; + } + else { + format.conversion_char = L'E'; + } + + goto e_format; + } + + if (format.alternate_form) { + format.precision -= dec.exponent + 1; + } + else { + if ((format.precision = dec.sig.length - (dec.exponent + 1)) < 0) { + format.precision = 0; + } + } + + goto f_format; + + case L'e': + case L'E': + e_format: + + if (dec.sig.length > format.precision + 1) { + round_decimal(&dec, format.precision + 1); + } + + n = dec.exponent; + sign = '+'; + + if (n < 0) { + n = -n; + sign = '-'; + } + + for (digits = 0; n || digits < 2; ++digits) { + *--p = n % 10 + '0'; + n /= 10; + } + + *--p = sign; + *--p = format.conversion_char; + + if (buff - p + format.precision > 509) { + return 0; + } + + if (dec.sig.length < format.precision + 1) { + for (n = format.precision + 1 - dec.sig.length + 1; --n;) { + *--p = '0'; + } + } + + for (n = dec.sig.length, q = (char*)dec.sig.text + dec.sig.length; --n;) { + *--p = *--q; + } + + if (format.precision || format.alternate_form) { + *--p = radix_marker; + } + + *--p = *dec.sig.text; + + if (dec.sign) + *--p = '-'; + else if (format.sign_options == sign_always) + *--p = '+'; + else if (format.sign_options == space_holder) + *--p = ' '; + + break; + + case L'f': + case L'F': + f_format: + + if ((frac_digits = -dec.exponent + dec.sig.length - 1) < 0) + frac_digits = 0; + + if (frac_digits > format.precision) { + round_decimal(&dec, dec.sig.length - (frac_digits - format.precision)); + + if ((frac_digits = -dec.exponent + dec.sig.length - 1) < 0) + frac_digits = 0; + } + + if ((int_digits = dec.exponent + 1) < 0) + int_digits = 0; + + if (int_digits + frac_digits > 509) + return 0; + + q = (char *) dec.sig.text + dec.sig.length; + + for (digits = 0; digits < (format.precision - frac_digits); ++digits) + *--p = '0'; + + for (digits = 0; digits < frac_digits && digits < dec.sig.length; ++digits) + *--p = *--q; + + for (; digits < frac_digits; ++digits) + *--p = '0'; + + if (format.precision || format.alternate_form) + *--p = radix_marker; + + if (int_digits) { + for (digits = 0; digits < int_digits - dec.sig.length; ++digits) { + *--p = '0'; + } + + for (; digits < int_digits; ++digits) { + *--p = *--q; + } + } + else { + *--p = '0'; + } + + if (dec.sign) { + *--p = '-'; + } + else if (format.sign_options == sign_always) { + *--p = '+'; + } + else if (format.sign_options == space_holder) { + *--p = ' '; + } + + break; + } + + pw = wbuff - strlen(p) - 1; + mbstowcs(pw, p, strlen(p)); + return pw; +} + +int __wpformatter(void *(*WriteProc)(void *, const wchar_t *, size_t), void *WriteProcArg, const wchar_t * format_str, va_list arg) { + int num_chars, chars_written, field_width; + const wchar_t* format_ptr; + const wchar_t* curr_format; + print_format format; + long long_num; + long long long_long_num; + long double long_double_num; + wchar_t buff[512]; + wchar_t* buff_ptr; + wchar_t* string_end; + char* cstring_end; + wchar_t fill_char = L' '; + char* strptr; + + format_ptr = format_str; + chars_written = 0; + + while (*format_ptr) { + if (!(curr_format = wcschr(format_ptr, L'%'))) { + num_chars = wcslen(format_ptr); + chars_written += num_chars; + + if (num_chars && !(*WriteProc)(WriteProcArg, format_ptr, num_chars)) { + return -1; + } + + break; + } + + num_chars = curr_format - format_ptr; + chars_written += num_chars; + + if (num_chars && !(*WriteProc)(WriteProcArg, format_ptr, num_chars)) { + return -1; + } + + format_ptr = curr_format; + format_ptr = parse_format(format_ptr, (va_list*)arg, &format); + + switch (format.conversion_char) { + case L'd': + case L'i': + if (format.argument_options == long_argument) { + long_num = va_arg(arg, long); + } + else if (format.argument_options == long_long_argument) { + long_long_num = va_arg(arg, long long); + } + else if (format.argument_options == intmax_argument) { + long_long_num = va_arg(arg, intmax_t); + } + else if (format.argument_options == size_t_argument) { + long_num = va_arg(arg, size_t); + } + else if (format.argument_options == ptrdiff_argument) { + long_num = va_arg(arg, ptrdiff_t); + } + else { + long_num = va_arg(arg, int); + } + + if (format.argument_options == short_argument) { + long_num = (short)long_num; + } + + if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) { + if (!(buff_ptr = longlong2str(long_long_num, buff + 512, format))) { + goto conversion_error; + } + } + else { + if (!(buff_ptr = long2str(long_num, buff + 512, format))) { + goto conversion_error; + } + } + + num_chars = buff + 512 - 1 - buff_ptr; + break; + + case L'o': + case L'u': + case L'x': + case L'X': + if (format.argument_options == long_argument) { + long_num = va_arg(arg, unsigned long); + } + else if (format.argument_options == long_long_argument) { + long_long_num = va_arg(arg, long long); + } + else if (format.argument_options == intmax_argument) { + long_long_num = va_arg(arg, intmax_t); + } + else if (format.argument_options == size_t_argument) { + long_num = va_arg(arg, size_t); + } + else if (format.argument_options == ptrdiff_argument) { + long_num = va_arg(arg, ptrdiff_t); + } + else { + long_num = va_arg(arg, unsigned int); + } + + if (format.argument_options == short_argument) { + long_num = (unsigned short)long_num; + } + + if ((format.argument_options == long_long_argument) || (format.argument_options == intmax_argument)) { + if (!(buff_ptr = longlong2str(long_long_num, buff + 512, format))) { + goto conversion_error; + } + } + else { + if (!(buff_ptr = long2str(long_num, buff + 512, format))) { + goto conversion_error; + } + } + + num_chars = buff + 512 - 1 - buff_ptr; + break; + + case L'f': + case L'F': + case L'e': + case L'E': + case L'g': + case L'G': + if (format.argument_options == long_double_argument) { + long_double_num = va_arg(arg, long double); + } + else { + long_double_num = va_arg(arg, double); + } + + if (!(buff_ptr = float2str(long_double_num, buff + 512, format))) { + goto conversion_error; + } + + num_chars = buff + 512 - 1 - buff_ptr; + break; + + case 'a': + case 'A': + if (format.argument_options == long_double_argument) { + long_double_num = va_arg(arg, long double); + } + else { + long_double_num = va_arg(arg, double); + } + + if (!(buff_ptr = double2hex(long_double_num, buff + 512, format))) { + goto conversion_error; + } + + num_chars = buff + 512 - 1 - buff_ptr; + break; + + case L's': + if (format.argument_options == wchar_argument) { + buff_ptr = va_arg(arg, wchar_t *); + + if (buff_ptr == 0) { + buff_ptr = L""; + } + + if (format.alternate_form) + { + num_chars = (unsigned char) *buff_ptr++; + + if (format.precision_specified && num_chars > format.precision) + num_chars = format.precision; + } + else if (format.precision_specified) + { + num_chars = format.precision; + + if ((string_end = (wchar_t *)wmemchr(buff_ptr, 0, num_chars)) != 0) { + num_chars = string_end - buff_ptr; + } + } + else + num_chars = wcslen(buff_ptr); + } + else { + strptr = va_arg(arg, char *); + if (strptr == 0) { + strptr = ""; + } + + if (format.alternate_form) { + num_chars = (unsigned char) *buff_ptr++; + + if (format.precision_specified && num_chars > format.precision) { + num_chars = format.precision; + } + } + else if (format.precision_specified) { + num_chars = format.precision; + + if ((cstring_end = (char *) memchr(strptr, 0, num_chars)) != 0) { + num_chars = cstring_end - strptr; + } + } + else + num_chars = strlen(strptr); + if ((num_chars = mbstowcs(buff, strptr, num_chars)) < 0) + goto conversion_error; + + buff_ptr = &buff[0]; + } + + break; + + case 'n': + buff_ptr = va_arg(arg, wchar_t *); + + switch (format.argument_options) { + case normal_argument: + *(int*)buff_ptr = chars_written; + break; + case short_argument: + *(short*)buff_ptr = chars_written; + break; + case long_argument: + *(long*)buff_ptr = chars_written; + break; + case intmax_argument: + *(intmax_t*)buff_ptr = chars_written; + break; + case size_t_argument: + *(size_t*)buff_ptr = chars_written; + break; + case ptrdiff_argument: + *(ptrdiff_t*)buff_ptr = chars_written; + break; + case long_long_argument: + *(long long*)buff_ptr = chars_written; + break; + } + + continue; + + case L'c': + buff_ptr = buff; + if (format.argument_options == wchar_argument) { + *buff_ptr = va_arg(arg, int); + num_chars = 1; + } + else { + char chint = va_arg(arg, int); + num_chars = mbtowc(buff, &chint, 1); + } + + break; + + case L'%': + buff_ptr = buff; + *buff_ptr = '%'; + num_chars = 1; + break; + + case 0xFFFF: + default: + conversion_error: + num_chars = wcslen(curr_format); + chars_written += num_chars; + + if (num_chars && !(*WriteProc)(WriteProcArg, curr_format, num_chars)) { + return -1; + } + + return chars_written; + break; + } + + field_width = num_chars; + + if (format.justification_options != left_justification) { + fill_char = (format.justification_options == zero_fill) ? L'0' : L' '; + + if (((*buff_ptr == L'+') || (*buff_ptr == L'-') || (*buff_ptr == L' ')) && (fill_char == L'0')) { + if ((*WriteProc)(WriteProcArg, buff_ptr, 1) == 0) { + return -1; + } + + ++buff_ptr; + num_chars--; + } + + while (field_width < format.field_width) { + if ((*WriteProc)(WriteProcArg, &fill_char, 1) == 0) { + return -1; + } + + ++field_width; + } + } + + if (num_chars && !(*WriteProc)(WriteProcArg, buff_ptr, num_chars)) { + return -1; + } + + if (format.justification_options == left_justification) { + while (field_width < format.field_width) { + wchar_t blank = L' '; + + if ((*WriteProc)(WriteProcArg, &blank, 1) == 0) { + return -1; + } + + ++field_width; + } + } + + chars_written += field_width; + } + + return chars_written; +} + +void* __wStringWrite(void *wosc, const wchar_t * buffer, size_t numchars) { + size_t tobewritten; + void* res; + __wOutStrCtrl * wOscp = (__wOutStrCtrl*)wosc; + tobewritten = ((wOscp->CharsWritten + numchars) <= wOscp->MaxCharCount) ? numchars : wOscp->MaxCharCount - wOscp->CharsWritten; + res = (void*)wmemcpy(wOscp->wCharStr + wOscp->CharsWritten, buffer, tobewritten); + wOscp->CharsWritten += tobewritten; + return res; +} + +inline int vswprintf(wchar_t *s, size_t n, const wchar_t *format, va_list arg) { + int count; + __wOutStrCtrl wosc; + wosc.wCharStr = s; + wosc.MaxCharCount = n; + wosc.CharsWritten = 0; + + count = __wpformatter(&__wStringWrite, &wosc, format, arg); + + if (count >= 0) { + if (count < n) { + s[count] = 0; + } + else { + s[n - 1] = 0; + count = -1; + } + } + + return count; +} + + +int swprintf(wchar_t *s, size_t n, const wchar_t *format, ...) { + va_list args; + va_start(args, format); + return vswprintf(s, n, format, args); +} diff --git a/src/MSL/wstring.c b/src/MSL/wstring.c new file mode 100644 index 00000000..e69c240d --- /dev/null +++ b/src/MSL/wstring.c @@ -0,0 +1,94 @@ +#include "wstring.h" + +size_t wcslen(const wchar_t* str) { + const wchar_t* str_ptr = str - 1; + size_t length = (size_t)-1; + wchar_t current_char; + + do { + current_char = *++str_ptr; + length++; + } while (current_char != 0); + + return length; +} + +wchar_t* wcscpy(wchar_t* dst, const wchar_t* src) { + wchar_t* original_dst = dst; + const wchar_t* src_ptr = src - 1; + wchar_t* dst_ptr = dst - 1; + wchar_t current_char; + + do { + current_char = *++src_ptr; + *++dst_ptr = current_char; + } while (current_char != 0); + + return original_dst; +} + +wchar_t* wcsncpy(wchar_t* dst, const wchar_t* src, unsigned long n) { + wchar_t* original_dst = dst; + const wchar_t* src_ptr = src - 1; + wchar_t* dst_ptr = dst - 1; + unsigned long count = n + 1; + wchar_t current_char; + + while (--count != 0) { + current_char = *++src_ptr; + *++dst_ptr = current_char; + + if (current_char == 0) { + while (--count != 0) { + *++dst_ptr = 0; + } + break; + } + } + + return original_dst; +} + +wchar_t* wcscat(wchar_t* dst, const wchar_t* src) { + const wchar_t* src_ptr = src - 1; + wchar_t* dst_ptr = dst - 1; + wchar_t* original_dst = dst; + wchar_t current_char; + do { + current_char = *++dst_ptr; + } while (current_char != 0); + + dst_ptr--; + + do { + current_char = *++src_ptr; + *++dst_ptr = current_char; + } while (current_char != 0); + return original_dst; +} + +int wcscmp(const wchar_t* str1, const wchar_t* str2) { + const wchar_t* str1_ptr = (wchar_t*)str1 - 1; + const wchar_t* str2_ptr = (wchar_t*)str2 - 1; + wchar_t char1, char2; + + while ((char1 = *++str1_ptr) == (char2 = *++str2_ptr)) + if (!char1) + return 0; + return char1 - char2; +} + +wchar_t* wcschr(const wchar_t* str, wchar_t chr) { + const wchar_t* str_ptr = str - 1; + wchar_t current_char; + + while (current_char = *++str_ptr) + if (current_char == chr) + return ((wchar_t*)str_ptr); + + if (chr != 0) { + return NULL; + } else { + return (wchar_t*)str_ptr; + } +}