diff --git a/configure.py b/configure.py index 64c41476..2191a5f8 100755 --- a/configure.py +++ b/configure.py @@ -476,58 +476,58 @@ def LinkedFor(*versions): "runtime", [*cflags_base, "-inline deferred"], [ - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "runtime/__mem.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "runtime/__va_arg.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "runtime/global_destructor_chain.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "runtime/runtime.c"), + Object(Linked, "runtime/__mem.c"), + Object(Linked, "runtime/__va_arg.c"), + Object(Linked, "runtime/global_destructor_chain.c"), + Object(Linked, "runtime/runtime.c"), ] ), GenericLib( "libc", - [*cflags_base, "-inline deferred"], + [*cflags_base, "-inline deferred", "-str pool,readonly"], [ - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/abort_exit.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/ansi_files.c"), - Object(NotLinked, "libc/ansi_fp.c", extra_cflags=["-inline noauto"]), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/buffer_io.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/critical_regions.ppc_eabi.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/ctype.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/direct_io.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/errno.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/mbstring.c"), - Object(NotLinked, "libc/mem.c"), - Object(NotLinked, "libc/mem_funcs.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/misc_io.c"), - Object(NotLinked, "libc/printf.c"), - Object(NotLinked, "libc/scanf.c"), - Object(NotLinked, "libc/string.c"), - Object(NotLinked, "libc/strtoul.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/uart_console_io.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/float.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/wchar_io.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/e_asin.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/e_pow.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/fminmaxdim.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/s_ceil.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/s_copysign.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/s_floor.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/s_frexp.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/s_ldexp.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/w_pow.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/hyperbolicsf.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/log10f.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/trigf.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/math_inlines.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "libc/common_float_tables.c"), + Object(Linked, "libc/abort_exit.c"), + Object(Linked, "libc/ansi_files.c"), + Object(Linked, "libc/ansi_fp.c", extra_cflags=["-inline noauto"]), + Object(Linked, "libc/buffer_io.c"), + Object(Linked, "libc/critical_regions.ppc_eabi.c"), + Object(Linked, "libc/ctype.c"), + Object(Linked, "libc/direct_io.c"), + Object(Linked, "libc/errno.c"), + Object(Linked, "libc/mbstring.c"), + Object(Linked, "libc/mem.c"), + Object(Linked, "libc/mem_funcs.c"), + Object(Linked, "libc/misc_io.c"), + Object(Linked, "libc/printf.c"), + Object(Linked, "libc/scanf.c"), + Object(Linked, "libc/string.c"), + Object(Linked, "libc/strtoul.c"), + Object(Linked, "libc/uart_console_io.c"), + Object(Linked, "libc/float.c"), + Object(Linked, "libc/wchar_io.c"), + Object(Linked, "libc/e_asin.c"), + Object(Linked, "libc/e_pow.c"), + Object(Linked, "libc/fminmaxdim.c"), + Object(Linked, "libc/s_ceil.c"), + Object(Linked, "libc/s_copysign.c"), + Object(Linked, "libc/s_floor.c"), + Object(Linked, "libc/s_frexp.c"), + Object(Linked, "libc/s_ldexp.c"), + Object(Linked, "libc/w_pow.c"), + Object(Linked, "libc/hyperbolicsf.c"), + Object(Linked, "libc/log10f.c"), + Object(Linked, "libc/trigf.c"), + Object(Linked, "libc/math_inlines.c"), + Object(Linked, "libc/common_float_tables.c"), ] ), GenericLib( "debugger", cflags_base, [ - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "debugger/AmcExi2Stubs.c"), + Object(Linked, "debugger/AmcExi2Stubs.c"), Object(NotLinked, "debugger/DebuggerDriver.c"), - Object(LinkedFor("mq-j", "mq-u", "ce-j", "ce-u"), "debugger/odenotstub.c"), + Object(Linked, "debugger/odenotstub.c"), ] ), ] diff --git a/libc/ansi_fp.h b/libc/ansi_fp.h new file mode 100644 index 00000000..e6ec4d59 --- /dev/null +++ b/libc/ansi_fp.h @@ -0,0 +1,25 @@ +#ifndef _ANSI_FP +#define _ANSI_FP + +#define SIGDIGLEN 36 + +typedef struct decimal { + char sign; + char unk1; + short exp; + struct { + unsigned char length; + unsigned char text[36]; + unsigned char unk41; + } sig; +} decimal; + +typedef struct decform { + char style; + char unk1; + short digits; +} decform; + +void __num2dec(const decform* f, double x, decimal* d); + +#endif diff --git a/libc/ctype.h b/libc/ctype.h index e22f2407..202f68bf 100644 --- a/libc/ctype.h +++ b/libc/ctype.h @@ -3,9 +3,6 @@ #include "dolphin/types.h" -// eof.h -#define EOF -1L - extern const u8 __ctype_map[]; extern const u8 __lower_map[]; extern const u8 __upper_map[]; diff --git a/libc/limits.h b/libc/limits.h index 8c0bc84c..9a3d21cd 100644 --- a/libc/limits.h +++ b/libc/limits.h @@ -1,18 +1,10 @@ #ifndef _LIMITS_H_ #define _LIMITS_H_ -#define SCHAR_MIN (-0x7F - 1) -#define SCHAR_MAX 0x7F +#define CHAR_MIN (-0x7F - 1) +#define CHAR_MAX 0x7F #define UCHAR_MAX 0xFFU -#if defined(__MWERKS__) && __option(unsigned_char) -#define CHAR_MIN 0U -#define CHAR_MAX UCHAR_MAX -#else -#define CHAR_MIN SCHAR_MIN -#define CHAR_MAX SCHAR_MAX -#endif - #define SHRT_MIN (-0x7FFF - 1) #define SHRT_MAX 0x7FFF #define USHRT_MAX 0xFFFFU @@ -21,7 +13,7 @@ #define INT_MAX 0x7FFFFFFF #define UINT_MAX 0xFFFFFFFFU -#define LONG_MIN (-0x7FFFFFFFFFFFFFFFL - 1) +#define LONG_MIN (-0x7FFFFFFFL - 1) #define LONG_MAX 0x7FFFFFFFL #define ULONG_MAX 0xFFFFFFFFUL diff --git a/libc/mem_funcs.h b/libc/mem_funcs.h index 0db0b7e3..5b8dae32 100644 --- a/libc/mem_funcs.h +++ b/libc/mem_funcs.h @@ -1,18 +1,8 @@ #ifndef _MEM_FUNCS_H_ #define _MEM_FUNCS_H_ -#include "macros.h" #include "stddef.h" -#define __min_bytes_for_long_copy 32 - -INIT int memcmp(void*, const void*, size_t); -INIT void* memcpy(void* dst, const void* src, size_t n); -INIT void* memset(void* dst, int val, size_t n); -INIT void __fill_mem(void* dst, int val, size_t n); - -void __copy_mem(void* dst, const void* src, unsigned long n); -void __move_mem(void* dst, const void* src, unsigned long n); void __copy_longs_aligned(void* dst, const void* src, unsigned long n); void __copy_longs_rev_aligned(void* dst, const void* src, unsigned long n); void __copy_longs_unaligned(void* dst, const void* src, unsigned long n); diff --git a/libc/stdarg.h b/libc/stdarg.h index 6ab7b444..e507bb71 100644 --- a/libc/stdarg.h +++ b/libc/stdarg.h @@ -14,6 +14,10 @@ extern void __builtin_va_info(void*); void* __va_arg(va_list v_list, unsigned char type); +#ifndef __MWERKS__ +#define _var_arg_typeof(e) 0 +#endif + #define va_start(ap, fmt) ((void)fmt, __builtin_va_info(&ap)) #define va_arg(ap, t) (*((t*)__va_arg(ap, _var_arg_typeof(t)))) #define va_end(ap) (void)0 diff --git a/libc/stdio.h b/libc/stdio.h index 6b0e7fcc..e231206a 100644 --- a/libc/stdio.h +++ b/libc/stdio.h @@ -104,23 +104,27 @@ typedef struct { #define EOF -1L enum __ReadProcActions { - __GetChar, - __UngetChar, - __CheckForError + __GetAChar, + __UngetAChar, + __TestForError, }; +int __StringRead(void* str, int ch, int behavior); + #define _IONBF 0 #define _IOLBF 1 #define _IOFBF 2 -int puts(const char* s); -int printf(const char*, ...); -size_t sprintf(char* s, const char* format, ...); -size_t vprintf(const char* format, va_list arg); -size_t vsprintf(char* s, const char* format, va_list arg); -size_t fread(const void*, size_t memb_size, size_t num_memb, FILE*); +extern FILE __files[3]; + +#define stdin (&__files[0]) +#define stdout (&__files[1]) +#define stderr (&__files[2]) + +int sprintf(char* s, const char* format, ...); +int vprintf(const char* format, va_list arg); +int vsprintf(char* s, const char* format, va_list arg); + size_t fwrite(const void*, size_t memb_size, size_t num_memb, FILE*); -int fseek(FILE* file, long offset, int mode); -size_t __fwrite(const void*, size_t, size_t, FILE*); #endif // _STDIO diff --git a/libc/string.h b/libc/string.h index fb3c7ee7..b2159ee6 100644 --- a/libc/string.h +++ b/libc/string.h @@ -1,15 +1,20 @@ #ifndef _STRING_H_ #define _STRING_H_ -#include "mem_funcs.h" #include "stddef.h" +char* strcpy(char* dst, const char* src); +char* strncpy(char* dst, const char* src, size_t num); +char* strncat(char* dest, const char* src, size_t n); size_t strlen(const char* s); -char* strcpy(char* dest, const char* src); -char* strncpy(char* dest, const char* src, size_t num); int strcmp(const char* s1, const char* s2); int strncmp(const char* s1, const char* s2, size_t n); -char* strncat(char* dest, const char* src, size_t n); char* strchr(const char* str, int chr); +void* memchr(const void* p, int val, size_t n); +int memcmp(const void* p1, const void* p2, size_t n); +void* memset(void* dst, int val, size_t n); +void* memcpy(void* dst, const void* src, size_t n); +void* memmove(void* dst, const void* src, size_t n); + #endif diff --git a/src/libc/ansi_fp.c b/src/libc/ansi_fp.c new file mode 100644 index 00000000..e7e9d45a --- /dev/null +++ b/src/libc/ansi_fp.c @@ -0,0 +1,165 @@ +#include "ansi_fp.h" + +#define __HI(x) (((int*)&x)[0]) +#define __LO(x) (((int*)&x)[1]) + +#define FP_NAN 1 +#define FP_INFINITE 2 +#define FP_ZERO 3 +#define FP_NORMAL 4 +#define FP_SUBNORMAL 5 + +// TODO: somehow make this work with math.h +inline int fpclassify(double x) { + switch (__HI(x) & 0x7FF00000) { + case 0x7FF00000: { + if ((__HI(x) & 0x000FFFFF) || (__LO(x) & 0xFFFFFFFF)) { + return FP_NAN; + } else { + return FP_INFINITE; + } + break; + } + case 0: { + if ((__HI(x) & 0x000FFFFF) || (__LO(x) & 0xFFFFFFFF)) { + return FP_SUBNORMAL; + } else { + return FP_ZERO; + } + break; + } + } + return FP_NORMAL; +} + +#define isnormal(x) (fpclassify(x) == FP_NORMAL) +#define isnan(x) (fpclassify(x) == FP_NAN) +#define isinf(x) (fpclassify(x) == FP_INFINITE) +#define isfinite(x) (fpclassify(x) > FP_INFINITE) + +const double bit_values[] = { + 1e1, 1e2, 1e4, 1e8, 1e16, 1e32, 1e64, 1e128, 1e256, +}; + +const double digit_values[] = { + 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, +}; + +void __num2dec(const decform* f, double x, decimal* d) { + int sp30; + int exp; + unsigned char* p; + int digits; + int var_r4; + double var_f1; + int var_r11; + int var_r12; + int temp_r5; + int var_r6; + int var_r6_2; + const double* var_r5; + + // fixes float ordering issue + (void)0.0; + (void)1.0; + (void)4503601774854144.0; + + digits = f->digits; + if (digits > 16) { + digits = 16; + } + + d->sign = 0; + d->exp = 0; + d->sig.length = 1; + + if (x == 0.0) { + d->sig.text[0] = '0'; + return; + } + + if (!isfinite(x)) { + d->sig.text[0] = isnan(x) ? 'N' : 'I'; + return; + } + + d->sig.length = 0; + if (x < 0.0) { + x = -x; + d->sign = 1; + } + + frexp(x, &sp30); + var_r4 = (sp30 * 301029) / 1000000; // log_10(2) + exp = var_r4; + var_r5 = bit_values; + if (var_r4 < 0) { + var_r4 = -var_r4; + while (var_r4 != 0) { + if (var_r4 & 1) { + x *= *var_r5; + } + var_r4 >>= 1; + var_r5++; + } + } else if (var_r4 > 0) { + var_f1 = 1.0f; + while (var_r4 != 0) { + if (var_r4 & 1) { + var_f1 *= *var_r5; + } + var_r4 >>= 1; + var_r5++; + } + x /= var_f1; + } + + while (x >= 1.0) { + x *= 0.1; + exp += 1; + } + + while (x < 0.1) { + x *= 10.0; + exp -= 1; + } + + p = d->sig.text; + while (digits != 0) { + var_r12 = digits; + if (digits > 8) { + var_r12 = 8; + } + d->sig.length += var_r12; + digits -= var_r12; + exp -= var_r12; + p += var_r12; + x *= digit_values[var_r12 - 1]; + var_r6 = (int)x; + x = x - var_r6; + + var_r11 = var_r12 + 1; + while (--var_r11 != 0) { + *--p = '0' + (var_r6 % 10); + var_r6 /= 10; + } + p += var_r12; + } + + digits = f->digits; + if (f->digits > 36) { + digits = 36; + } + + temp_r5 = digits - d->sig.length; + if (temp_r5 > 0) { + var_r6_2 = temp_r5 + 1; + while (--var_r6_2 != 0) { + *p++ = '0'; + } + exp -= temp_r5; + d->sig.length += temp_r5; + } + + d->exp = exp; +} diff --git a/src/libc/ctype.c b/src/libc/ctype.c index 52da813e..63d524a7 100644 --- a/src/libc/ctype.c +++ b/src/libc/ctype.c @@ -1,5 +1,6 @@ #include "ctype.h" #include "dolphin/types.h" +#include "stdio.h" const u8 __ctype_map[256] = { __control_char, diff --git a/src/libc/mem.c b/src/libc/mem.c new file mode 100644 index 00000000..1a20f0b1 --- /dev/null +++ b/src/libc/mem.c @@ -0,0 +1,73 @@ +#include "dolphin/types.h" +#include "mem_funcs.h" +#include "string.h" + +void* memmove(void* dst, const void* src, size_t n) { + const u8* p1; + u8* p2; + bool rev = (u32)src < (u32)dst; + + if (n >= 32) { + if ((((u32)dst ^ (u32)src) & 3) != 0) { + if (!rev) { + __copy_longs_unaligned(dst, src, n); + } else { + __copy_longs_rev_unaligned(dst, src, n); + } + } else { + if (!rev) { + __copy_longs_aligned(dst, src, n); + } else { + __copy_longs_rev_aligned(dst, src, n); + } + } + return dst; + } + + if (!rev) { + p1 = (u8*)src - 1; + p2 = (u8*)dst - 1; + n++; + while (--n) { + *++p2 = *++p1; + } + } else { + p1 = (u8*)src + n; + p2 = (u8*)dst + n; + n++; + while (--n) { + *--p2 = *--p1; + } + } + + return dst; +} + +void* memchr(const void* src, int val, size_t n) { + const u8* p; + u32 v = val & 0xFF; + + p = (u8*)src - 1; + n++; + while (--n) { + if (*++p == v) { + return (void*)p; + } + } + + return NULL; +} + +int memcmp(const void* src1, const void* src2, size_t n) { + const u8* p1 = (u8*)src1 - 1; + const u8* p2 = (u8*)src2 - 1; + + n++; + while (--n) { + if (*++p1 != *++p2) { + return *p1 < *p2 ? -1 : 1; + } + } + + return 0; +} diff --git a/src/libc/mem_funcs.c b/src/libc/mem_funcs.c new file mode 100644 index 00000000..06651505 --- /dev/null +++ b/src/libc/mem_funcs.c @@ -0,0 +1,209 @@ +#include "dolphin/types.h" + +#ifdef __MWERKS__ + +void __copy_longs_aligned(void* dst, const void* src, unsigned long n) { + u32 i; + + i = (-(u32)dst) & 3; + src = ((u8*)src) - 1; + dst = ((u8*)dst) - 1; + + if (i > 0) { + n -= i; + do { + *(++((u8*)dst)) = *(++((u8*)src)); + } while (--i); + } + + i = n >> 5; + src = (u32*)((u8*)src + 1) - 1; + dst = (u32*)((u8*)dst + 1) - 1; + + if (i > 0) { + do { + *(++((u32*)dst)) = *(++((u32*)src)); + *(++((u32*)dst)) = *(++((u32*)src)); + *(++((u32*)dst)) = *(++((u32*)src)); + *(++((u32*)dst)) = *(++((u32*)src)); + *(++((u32*)dst)) = *(++((u32*)src)); + *(++((u32*)dst)) = *(++((u32*)src)); + *(++((u32*)dst)) = *(++((u32*)src)); + *(++((u32*)dst)) = *(++((u32*)src)); + } while (--i); + } + + i = (n & 31) >> 2; + if (i > 0) { + do { + *(++((u32*)dst)) = *(++((u32*)src)); + } while (--i); + } + + src = (u8*)((u32*)src + 1) - 1; + dst = (u8*)((u32*)dst + 1) - 1; + + n &= 3; + if (n > 0) { + do { + *(++((u8*)dst)) = *(++((u8*)src)); + } while (--n); + } +} + +void __copy_longs_rev_aligned(void* dst, const void* src, unsigned long n) { + u32 i; + + src = ((u8*)src) + n; + dst = ((u8*)dst) + n; + i = ((u32)dst) & 3; + + if (i > 0) { + n -= i; + do { + *(--((u8*)dst)) = *(--((u8*)src)); + } while (--i); + } + + i = n >> 5; + + if (i > 0) { + do { + *(--((u32*)dst)) = *(--((u32*)src)); + *(--((u32*)dst)) = *(--((u32*)src)); + *(--((u32*)dst)) = *(--((u32*)src)); + *(--((u32*)dst)) = *(--((u32*)src)); + *(--((u32*)dst)) = *(--((u32*)src)); + *(--((u32*)dst)) = *(--((u32*)src)); + *(--((u32*)dst)) = *(--((u32*)src)); + *(--((u32*)dst)) = *(--((u32*)src)); + } while (--i); + } + + i = (n & 31) >> 2; + if (i > 0) { + do { + *(--((u32*)dst)) = *(--((u32*)src)); + } while (--i); + } + + n &= 3; + if (n > 0) { + do { + *(--((u8*)dst)) = *(--((u8*)src)); + } while (--n); + } +} + +void __copy_longs_unaligned(void* dst, const void* src, unsigned long n) { + u32 i; + u32 v1; + u32 v2; + u32 offset; + u32 shiftl; + u32 shiftr; + + i = (-(u32)dst) & 3; + src = ((u8*)src) - 1; + dst = ((u8*)dst) - 1; + + if (i > 0) { + n -= i; + do { + *(++((u8*)dst)) = *(++((u8*)src)); + } while (--i); + } + + offset = (u32)((u8*)src + 1) & 3; + shiftl = offset << 3; + shiftr = 32 - shiftl; + + (u8*)src -= offset; + src = (u32*)((u8*)src + 1) - 1; + dst = (u32*)((u8*)dst + 1) - 1; + + i = n >> 3; + v1 = *(++((u32*)src)); + do { + v2 = *(++((u32*)src)); + *(++((u32*)dst)) = (v1 << shiftl) | (v2 >> shiftr); + v1 = *(++((u32*)src)); + *(++((u32*)dst)) = (v2 << shiftl) | (v1 >> shiftr); + } while (--i); + + if ((n & 4) != 0) { + v2 = *(++((u32*)src)); + *(++((u32*)dst)) = (v1 << shiftl) | (v2 >> shiftr); + } + + src = (u8*)((u32*)src + 1) - 1; + dst = (u8*)((u32*)dst + 1) - 1; + + n &= 3; + if (n > 0) { + (u8*)src -= 4 - offset; + do { + *(++((u8*)dst)) = *(++((u8*)src)); + } while (--n); + } +} + +void __copy_longs_rev_unaligned(void* dst, const void* src, unsigned long n) { + u32 i; + u32 v1; + u32 v2; + u32 offset; + u32 shiftl; + u32 shiftr; + + src = ((u8*)src) + n; + dst = ((u8*)dst) + n; + i = (u32)dst & 3; + + if (i > 0) { + n -= i; + do { + *(--((u8*)dst)) = *(--((u8*)src)); + } while (--i); + } + + offset = (u32)src & 3; + shiftl = offset << 3; + shiftr = 32 - shiftl; + + (u8*)src += 4 - offset; + + i = n >> 3; + v1 = *(--((u32*)src)); + do { + v2 = *(--((u32*)src)); + *(--((u32*)dst)) = (v2 << shiftl) | (v1 >> shiftr); + v1 = *(--((u32*)src)); + *(--((u32*)dst)) = (v1 << shiftl) | (v2 >> shiftr); + } while (--i); + + if ((n & 4) != 0) { + v2 = *(--((u32*)src)); + *(--((u32*)dst)) = (v2 << shiftl) | (v1 >> shiftr); + } + + n &= 3; + if (n > 0) { + (u8*)src += offset; + do { + *(--((u8*)dst)) = *(--((u8*)src)); + } while (--n); + } +} + +#else + +void __copy_longs_aligned(void* dst, const void* src, unsigned long n) { memcpy(dst, src, n); } + +void __copy_longs_rev_aligned(void* dst, const void* src, unsigned long n) { memcpy(dst, src, n); } + +void __copy_longs_unaligned(void* dst, const void* src, unsigned long n) { memcpy(dst, src, n); } + +void __copy_longs_rev_unaligned(void* dst, const void* src, unsigned long n) { memcpy(dst, src, n); } + +#endif diff --git a/src/libc/printf.c b/src/libc/printf.c new file mode 100644 index 00000000..4dfe3100 --- /dev/null +++ b/src/libc/printf.c @@ -0,0 +1,1026 @@ +#include "ansi_fp.h" +#include "ctype.h" +#include "limits.h" +#include "stdarg.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "wchar.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, + long_double_argument, + wchar_argument +}; + +typedef struct { + unsigned char justification_options; + unsigned char sign_options; + unsigned char precision_specified; + unsigned char alternate_form; + unsigned char argument_options; + unsigned char conversion_char; + int field_width; + int precision; +} print_format; + +static 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; + 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': + if (f.argument_options == short_argument || f.argument_options == long_long_argument) { + f.conversion_char = 0xFF; + break; + } + + if (!f.precision_specified) { + f.precision = 6; + } + break; + + case 'g': + case 'G': + if (!f.precision) { + f.precision = 1; + } + + case 'e': + case 'E': + if (f.argument_options == short_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(signed 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) { + unsigned_num = -unsigned_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; +} + +static char* longlong2str(signed long long num, char* pBuf, print_format* format) { + 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 && !format->precision && !(format->alternate_form && format->conversion_char == 'o')) { + return p; + } + + switch (format->conversion_char) { + case 'd': + case 'i': + base = 10; + + if (num < 0) { + unsigned_num = -unsigned_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 (pBuf - 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; +} + +static void round_decimal(decimal* dec, int new_length) { + char c; + char* p; + int carry; + + if (new_length < 0) { + return_zero: + dec->sign = 0; + dec->exp = 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->exp += 1; + dec->sig.length = 1; + *dec->sig.text = '1'; + return; + } else if (new_length == 0) { + goto return_zero; + } + + dec->sig.length = new_length; +} + +static char* float2str(va_list arg, char* buff, print_format* format, int unused) { + decimal dec; + decform form; + char* p; + char* q; + int n, digits, sign; + int int_digits, frac_digits; + double num; + + if (format->argument_options == long_double_argument) { + num = va_arg(arg, long double); + } else { + num = va_arg(arg, double); + } + + 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.exp; + } + + switch (*dec.sig.text) { + case '0': + dec.exp = 0; + break; + case 'I': + if (num < 0) { + p = buff - 5; + strcpy(p, "-Inf"); + } else { + p = buff - 4; + strcpy(p, "Inf"); + } + + return p; + + case 'N': + p = buff - 4; + strcpy(p, "NaN"); + + return p; + } + + dec.exp += 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.exp < -4 || dec.exp >= 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.exp + 1; + } else { + if ((format->precision = dec.sig.length - (dec.exp + 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.exp; + 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 = '.'; + } + + *--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': + f_format: + + if ((frac_digits = -dec.exp + 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.exp + dec.sig.length - 1) < 0) { + frac_digits = 0; + } + } + + if ((int_digits = dec.exp + 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 = '.'; + } + + 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; +} + +static 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; + signed long long_num; + signed long long long_long_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, signed long); + } else if (format.argument_options == long_long_argument) { + long_long_num = va_arg(arg, signed long long); + } else { + long_num = va_arg(arg, int); + } + + if (format.argument_options == short_argument) { + long_num = (signed short)long_num; + } + + if (format.argument_options == char_argument) { + long_num = (signed char)long_num; + } + + if ((format.argument_options == long_long_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, signed long long); + } 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)) { + 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 'e': + case 'E': + case 'g': + case 'G': + if (!(buff_ptr = float2str(arg, buff + 512, &format, 0))) { + 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 == NULL) { + 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 == NULL) { + 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((unsigned char*)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: + *(signed short*)buff_ptr = chars_written; + break; + case long_argument: + *(signed long*)buff_ptr = chars_written; + break; + case long_long_argument: + *(signed 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 == '-')) && (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; +} + +static void* __FileWrite(void* pFile, const char* pBuffer, size_t char_num) { + return (fwrite(pBuffer, 1, char_num, (FILE*)pFile) == char_num ? pFile : 0); +} + +static void* __StringWrite(void* pCtrl, const char* pBuffer, size_t char_num) { + size_t chars; + __OutStrCtrl* ctrl = (__OutStrCtrl*)pCtrl; + void* res; + + chars = + ((ctrl->CharsWritten + char_num) <= ctrl->MaxCharCount) ? char_num : ctrl->MaxCharCount - ctrl->CharsWritten; + res = memcpy(ctrl->CharStr + ctrl->CharsWritten, pBuffer, chars); + ctrl->CharsWritten += chars; + return res; +} + +int vprintf(const char* format, va_list arg) { + int ret; + + if (fwide(stdout, -1) >= 0) { + return -1; + } + + ret = __pformatter(&__FileWrite, (void*)stdout, format, arg); + return ret; +} + +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); + s[(end < n) ? end : n - 1] = '\0'; + return end; +} + +int vsprintf(char* s, const char* format, va_list arg) { return vsnprintf(s, ULONG_MAX, format, arg); } + +int sprintf(char* s, const char* format, ...) { + va_list args; + va_start(args, format); + return vsnprintf(s, ULONG_MAX, format, args); +} diff --git a/src/libc/scanf.c b/src/libc/scanf.c new file mode 100644 index 00000000..02926de1 --- /dev/null +++ b/src/libc/scanf.c @@ -0,0 +1,33 @@ +#include "stdio.h" + +int __StringRead(void* str, int ch, int act) { + char ret; + __InStrCtrl* isc = (__InStrCtrl*)str; + + switch (act) { + case __GetAChar: + ret = *(isc->NextChar); + + if (ret == '\0') { + isc->NullCharDetected = 1; + return -1; + } else { + isc->NextChar++; + return ret; + } + + case __UngetAChar: + if (isc->NullCharDetected == 0) { + isc->NextChar--; + } else { + isc->NullCharDetected = 0; + } + + return ch; + + case __TestForError: + return isc->NullCharDetected; + } + + return 0; +} diff --git a/src/libc/string.c b/src/libc/string.c new file mode 100644 index 00000000..a62ea2ca --- /dev/null +++ b/src/libc/string.c @@ -0,0 +1,221 @@ +#include "string.h" +#include "dolphin/types.h" + +s32 K1 = 0x80808080; +s32 K2 = 0xFEFEFEFF; + +size_t strlen(const char* s) { + size_t len = -1; + const u8* p = (u8*)s - 1; + + do { + len++; + } while (*++p != 0); + + return len; +} + +char* strcpy(char* dst, const char* src) { + u8* p1 = (u8*)dst; + const u8* p2 = (u8*)src; + s32 w; + s32 t; + u32 align; + s32 k1; + s32 k2; + + if ((align = (u32)src & 3) != ((u32)dst & 3)) { + goto bytecopy; + } + + if (align != 0) { + if ((*p1 = *p2) == 0) { + return dst; + } + + align = 3 - align; + while (align != 0) { + if ((*++p1 = *++p2) == 0) { + return dst; + } + align--; + } + + p1++; + p2++; + } + + k1 = K1; + k2 = K2; + + w = *(s32*)p2; + t = w + k2; + t &= k1; + + if (t != 0) { + goto bytecopy; + } + + p1 -= 4; + + while (true) { +#if __MWERKS__ + *++((s32*)p1) = w; + w = *++((s32*)p2); +#else + p1 += 4; + p2 += 4; + *(s32*)p1 = w; + w = *(s32*)p2; +#endif + + t = w + k2; + t &= k1; + if (t != 0) { + break; + } + } + + p1 += 4; + +bytecopy: + if ((*p1 = *p2) == 0) { + return dst; + } + + align = 3 - align; + while (true) { + if ((*++p1 = *++p2) == 0) { + return dst; + } + } + + return dst; +} + +char* strncpy(char* dst, const char* src, size_t n) { + const u8* p = (const u8*)src - 1; + u8* q = (u8*)dst - 1; + + n++; + while (--n) { + if ((*++q = *++p) == 0) { + while (--n) { + *++q = 0; + } + break; + } + } + return dst; +} + +int strcmp(const char* str1, const char* str2) { + 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 = ((s32)left & 3)) != ((s32)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 = *(s32*)left; + r1 = *(s32*)right; + x = l1 + K2; + if (x & K1) { + goto adjust; + } + + while (l1 == r1) { + left += 4; + right += 4; + l1 = *(s32*)left; + r1 = *(s32*)right; + x = l1 + K2; + if (x & K1) { + goto adjust; + } + } + + if (l1 > r1) { + return 1; + } + return -1; + +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 (true); +} + +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 == 0) { + break; + } + } + + return 0; +} + +char* strchr(const char* str, int c) { + const u8* p = (u8*)str - 1; + u32 chr = (c & 0xFF); + + u32 ch; + while (ch = *++p) { + if (ch == chr) { + return (char*)p; + } + } + + return chr ? NULL : (char*)p; +} diff --git a/src/libc/strtoul.c b/src/libc/strtoul.c new file mode 100644 index 00000000..895326a6 --- /dev/null +++ b/src/libc/strtoul.c @@ -0,0 +1,175 @@ +#include "ctype.h" +#include "errno.h" +#include "limits.h" +#include "stdio.h" +#include "stdlib.h" + +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 & (finished | failure)) +#define success(scan_state) (scan_state & (leading_zero | digit_loop | finished)) +#define fetch() (count++, (*ReadProc)(ReadProcArg, 0, __GetAChar)) +#define unfetch(c) (*ReadProc)(ReadProcArg, c, __UngetAChar) + +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; + 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(); + 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)) { + value = 0; + count = 0; + } else { + count--; + } + + *chars_scanned = count; + + unfetch(c); + return value; +} + +long strtol(const char* str, char** end, int base) { + unsigned long uvalue; + long svalue; + int count, negative, overflow; + + __InStrCtrl isc; + isc.NextChar = (char*)str; + isc.NullCharDetected = 0; + + uvalue = __strtoul(base, INT_MAX, &__StringRead, (void*)&isc, &count, &negative, &overflow); + + if (end) { + *end = (char*)str + count; + } + + if (overflow || (!negative && uvalue > LONG_MAX) || (negative && uvalue > -LONG_MIN)) { + svalue = (negative ? -LONG_MIN : LONG_MAX); + errno = ERANGE; + } else { + svalue = (negative ? (long)-uvalue : (long)uvalue); + } + + return svalue; +} + +int atoi(const char* str) { return strtol(str, NULL, 10); } diff --git a/src/runtime/__mem.c b/src/runtime/__mem.c index 3e77aff5..55bca185 100644 --- a/src/runtime/__mem.c +++ b/src/runtime/__mem.c @@ -1,5 +1,6 @@ #include "dolphin/types.h" -#include "mem_funcs.h" +#include "macros.h" +#include "stddef.h" INIT void* memcpy(void* dst, const void* src, size_t n) { const char* p; @@ -7,17 +8,16 @@ INIT void* memcpy(void* dst, const void* src, size_t n) { int rev = ((u32)src < (u32)dst); if (!rev) { - for (p = (const char*)src - 1, q = (char*)dst - 1, n++; --n;) { *++q = *++p; } - } else { for (p = (const char*)src + n, q = (char*)dst + n, n++; --n;) { *--q = *--p; } } - return (dst); + + return dst; } INIT void __fill_mem(void* dst, int val, size_t n) { @@ -47,6 +47,7 @@ INIT void __fill_mem(void* dst, int val, size_t n) { if (i) { do { +#if __MWERKS__ *++(((u32*)dst)) = v; *++(((u32*)dst)) = v; *++(((u32*)dst)) = v; @@ -55,6 +56,24 @@ INIT void __fill_mem(void* dst, int val, size_t n) { *++(((u32*)dst)) = v; *++(((u32*)dst)) = v; *++(((u32*)dst)) = v; +#else + dst = (void*)((u32*)dst + 1); + *(u32*)dst = v; + dst = (void*)((u32*)dst + 1); + *(u32*)dst = v; + dst = (void*)((u32*)dst + 1); + *(u32*)dst = v; + dst = (void*)((u32*)dst + 1); + *(u32*)dst = v; + dst = (void*)((u32*)dst + 1); + *(u32*)dst = v; + dst = (void*)((u32*)dst + 1); + *(u32*)dst = v; + dst = (void*)((u32*)dst + 1); + *(u32*)dst = v; + dst = (void*)((u32*)dst + 1); + *(u32*)dst = v; +#endif } while (--i); } @@ -82,5 +101,5 @@ INIT void __fill_mem(void* dst, int val, size_t n) { INIT void* memset(void* dst, int val, size_t n) { __fill_mem(dst, val, n); - return (dst); + return dst; }