summaryrefslogtreecommitdiff
path: root/libpsx/src/libc
diff options
context:
space:
mode:
authorXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
committerXavi Del Campo <xavi.dcr@tutanota.com>2020-01-31 10:32:23 +0100
commit7c24e9a9b02b04dcaf9507acb94091ea70a2c02d (patch)
treec28d0748652ad4b4222309e46e6cfc82c0906220 /libpsx/src/libc
parenta2b7b6bb1cc2f4a3258b7b2dbc92399d151f864d (diff)
downloadpsxsdk-7c24e9a9b02b04dcaf9507acb94091ea70a2c02d.tar.gz
Imported pristine psxsdk-20190410 from official repo
Diffstat (limited to 'libpsx/src/libc')
-rw-r--r--libpsx/src/libc/error.c19
-rw-r--r--libpsx/src/libc/misc.c106
-rw-r--r--libpsx/src/libc/printf.c899
-rw-r--r--libpsx/src/libc/qsort.c65
-rw-r--r--libpsx/src/libc/scanf.c425
-rw-r--r--libpsx/src/libc/stat.c31
-rw-r--r--libpsx/src/libc/string.c706
-rw-r--r--libpsx/src/libc/strings.c41
-rw-r--r--libpsx/src/libc/unistd.c17
9 files changed, 2309 insertions, 0 deletions
diff --git a/libpsx/src/libc/error.c b/libpsx/src/libc/error.c
new file mode 100644
index 0000000..6863b2f
--- /dev/null
+++ b/libpsx/src/libc/error.c
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include <string.h>
+
+static char strerror_not_implemented[64];
+
+char *strerror(int errnum)
+{
+ strerror_r(errnum, strerror_not_implemented, 64);
+
+ return strerror_not_implemented;
+}
+
+int strerror_r(int errnum, char *strerrbuf, size_t buflen)
+{
+ snprintf(strerrbuf, buflen,
+ "strerror(%d)", errnum);
+
+ return 0;
+}
diff --git a/libpsx/src/libc/misc.c b/libpsx/src/libc/misc.c
new file mode 100644
index 0000000..f3a1326
--- /dev/null
+++ b/libpsx/src/libc/misc.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+static unsigned int rand_seed = 0;
+static unsigned int rand_next = 0;
+
+int abs(int x)
+{
+ if(x<0)return -x;
+
+ return x;
+}
+
+void srand(unsigned int seed)
+{
+ rand_seed = seed;
+}
+
+int rand()
+{
+ rand_next = (rand_next ^ 0x98765432)*0x1357;
+
+ return rand_next % RAND_MAX;
+}
+
+static char *__ulltoa_internal__(unsigned long long value, char *str, int base, int minus_sign,
+ unsigned long long maxp )
+{
+ unsigned long long p;
+ unsigned long long p3;
+ int c;
+ int a;
+
+ p = 1;
+
+ do
+ {
+ p3 = p;
+ p *= base;
+
+ if(maxp && p > maxp)
+ break;
+ }while((p >= p3) && !(p % p3));
+
+ if(minus_sign)
+ *(str++) = '-';
+
+ for(a = 0;p3 > 0;p3/=base)
+ {
+ c = value / p3;
+ value %= p3;
+
+ if(c)
+ a = 1;
+
+ if(a)
+ {
+ if(c <= 9)
+ c += '0';
+ else
+ c = (c - 10) + 'A';
+
+ *(str++) = c;
+ }
+ }
+
+ *str = '\0';
+
+ return str;
+}
+
+char *ulltoa(unsigned long long value, char *str, int base)
+{
+ return __ulltoa_internal__(value, str, base, 0, 0);
+}
+
+char *ultoa(unsigned long value, char *str, int base)
+{
+ return __ulltoa_internal__(value, str, base, 0, (sizeof(long)==8)?0:0xFFFFFFFF);
+}
+
+char *utoa(unsigned int value, char *str, int base)
+{
+ return __ulltoa_internal__(value, str, base, 0, 0xFFFFFFFF);
+}
+
+char *lltoa(long long value, char *str, int base)
+{
+ return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, 0);
+}
+
+char *ltoa(long value, char *str, int base)
+{
+ return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, (sizeof(long)==8)?0:0xFFFFFFFF);
+}
+
+char *itoa(int value, char *str, int base)
+{
+ return __ulltoa_internal__((value<0)?-value:value, str, base, value<0, 0xFFFFFFFF);
+}
+
+void abort(void)
+{
+ printf("abort(): Abnormal program termination\n");
+ exit(1);
+}
diff --git a/libpsx/src/libc/printf.c b/libpsx/src/libc/printf.c
new file mode 100644
index 0000000..ce8ffcd
--- /dev/null
+++ b/libpsx/src/libc/printf.c
@@ -0,0 +1,899 @@
+/*
+ * printf.c
+ *
+ * Part of the PSXSDK C library
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define SPRINTF_ALT_FLAG (1<<0)
+#define SPRINTF_ZERO_FLAG (1<<1)
+#define SPRINTF_NEGFIELD_FLAG (1<<2)
+#define SPRINTF_SPACE_FLAG (1<<3)
+#define SPRINTF_SIGN_FLAG (1<<4)
+
+// sprintf() macros to calculate the real padding and to write it
+// these were made to not repeat the code in the function
+// they can only be used in sprintf()
+
+// sprintf macros START
+
+#define calculate_real_padding() \
+ y = 1; \
+ \
+ for(x=0;x<=19;x++) \
+ { \
+ if(x == 0) \
+ pad_quantity--; \
+ else \
+ { \
+ if(arg / y) \
+ pad_quantity--; \
+ } \
+ \
+ y *= 10; \
+ } \
+ \
+ if(pad_quantity < 0) pad_quantity = 0;
+
+/*#define calculate_real_padding_hex() \
+ for (x = 0; x < 8; x++) \
+ { \
+ if(x == 0) \
+ pad_quantity--; \
+ else \
+ { \
+ if((arg >> (x * 4)) & 0xf) \
+ pad_quantity--; \
+ } \
+ }*/
+
+#define calculate_real_padding_hex() \
+ last = 0; \
+ for (x = 0; x < 16; x++) \
+ if((arg >> (x * 4)) & 0xf) \
+ last = x; \
+ \
+ pad_quantity = (pad_quantity - 1) - last; \
+ if(pad_quantity < 0) pad_quantity = 0;
+
+#define write_padding() \
+ if(!(flags & SPRINTF_NEGFIELD_FLAG)) \
+ for(x = 0; x < pad_quantity; x++) \
+ { \
+ if(flags & SPRINTF_ZERO_FLAG) \
+ put_in_string(string, ssz, '0', string_pos++); \
+ else \
+ put_in_string(string, ssz, ' ', string_pos++); \
+ }
+
+#define write_neg_padding() \
+ if(flags & SPRINTF_NEGFIELD_FLAG) \
+ { \
+ for(x = 0; x < pad_quantity; x++) \
+ put_in_string(string, ssz, ' ', string_pos++);\
+ }
+
+// sprintf macros END
+
+enum
+{
+ SPRINTF_SIZE_CHAR,
+ SPRINTF_SIZE_SHORT,
+ SPRINTF_SIZE_INT,
+ SPRINTF_SIZE_LONG,
+ SPRINTF_SIZE_LONG_LONG,
+};
+
+static unsigned int get_arg_in_size(int size, unsigned long long *arg, unsigned int check_sign)
+{
+ int s = 0;
+
+ switch(size)
+ {
+ case SPRINTF_SIZE_CHAR:
+ *arg &= 0xff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<7))
+ {
+ *arg |= 0xffffff00;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+ case SPRINTF_SIZE_SHORT:
+ *arg &= 0xffff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<15))
+ {
+ *arg |= 0xffff0000;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+
+// sizeof(long) == sizeof(int) on 32bit, so this will suffice for the psx
+
+ case SPRINTF_SIZE_INT:
+ case SPRINTF_SIZE_LONG:
+ *arg &= 0xffffffff;
+
+ if(check_sign)
+ {
+ if(*arg & (1<<31))
+ {
+ *arg |= (long long)0xffffffff00000000;
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+
+ case SPRINTF_SIZE_LONG_LONG:
+ if(check_sign)
+ {
+ if(*arg & ((long long)1<<63))
+ {
+ *arg = ~(*arg - 1);
+ s = 1;
+ }
+ }
+ break;
+ }
+
+ return s;
+}
+
+static int libc_ulltoa(unsigned long long i, char *dst, int n, int nopad)
+{
+ int x, y;
+ unsigned long long a, b;
+ int empty_digit = 1;
+ int sp=0;
+ int n2=0;
+
+ if(n<=0)
+ return 0;
+
+ for(x=18;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+ b = (i/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0 || nopad == 1)
+ {
+ i -= b*a;
+
+ //put_in_string(string, ssz, b + '0', string_pos++);
+ if(n2!=(n-1))
+ {
+ //printf("n2=%d\n",n2);
+ dst[sp++] = b + '0';
+ n2++;
+ }
+ }
+ }
+
+ dst[sp] = 0;
+
+ return n2;
+}
+
+/*static void libc_float_to_string(float fl, char *dst, int n)
+{
+ unsigned int *p = (unsigned int*)&fl;
+ unsigned long long i = 0;
+ unsigned long long f = 0;
+ int e, m, s;
+ int x, y;
+ unsigned long long z;
+
+ s = *p >> 31;
+
+ e = (*p >> 23) & 0xff;
+
+ m = *p & 0x7fffff;
+
+ if(e == 255 && m == 0) // Infinity
+ {
+ if(s) strncpy(dst, "-inf", n);
+ else strncpy(dst, "inf", n);
+ }else if(e == 255 && m != 0) // NaN
+ {
+ strncpy(dst, "nan", n);
+ }
+ else
+ {
+ e -= 127;
+ m |= 1<<23;
+
+
+
+ for(x = 23; x >= 0; x--)
+ {
+ if(m & (1<<x))
+ {
+ if(e >= 0)
+ {
+ z = 1;
+ for(y=0;y<e;y++)
+ z*=2;
+
+ i+=z;
+ }
+ else
+ {
+ z = 5000000000000000000;
+ for(y = 1; y < -e; y++)
+ z /= 2;
+
+ f+=z;
+ }
+ }
+ e--;
+ }
+
+ if(s && (n>0))
+ {
+ *(dst++) = '-';
+ n--;
+ }
+
+ x = libc_ulltoa(i, dst, n, 0);
+ n-=x+1;
+ dst+=x;
+
+ if(n>0)
+ {
+ *(dst++) = '.';
+ n--;
+ if(n>0)
+ {
+ x = libc_ulltoa(f, dst, n<6?n:6, 1);
+ n-=x;
+ dst+=x;
+
+ if(n>0)
+ *dst=0;
+ }
+ }
+ }
+}*/
+
+static void libc_double_to_string(double fl, char *dst, int n, int prec)
+{
+ unsigned long long *p = (unsigned long long *)&fl;
+ unsigned long long i = 0;
+ unsigned long long f = 0;
+ unsigned long long m, s;
+ long long e;
+ int x;
+ unsigned long long z;
+
+ s = *p >> 63;
+
+ e = (*p >> 52) & 0x7ff;
+ //printf("%d\n", e);
+
+ m = *p & 0xfffffffffffff;
+
+ for(x=0;x<52;x++)
+ if(m&((unsigned long long)1<<(52-x))) putchar('1'); else putchar('0');
+
+ if(e == 255 && m == 0) // Infinity
+ {
+ if(s) strncpy(dst, "-inf", n);
+ else strncpy(dst, "inf", n);
+ }else if(e == 255 && m != 0) // NaN
+ {
+ strncpy(dst, "nan", n);
+ }
+ else
+ {
+ e -= 1023;
+ m |= (unsigned long long)1<<52;
+
+ for(x = 52; x >= 0; x--)
+ {
+ if(m & ((unsigned long long)1<<x))
+ {
+ if(e >= 0)
+ {
+ z = (long long)1<<e;
+
+ i+=z;
+ }
+ else
+ {
+ z = 5000000000000000000;
+ z >>= -(e + 1);
+
+ f+=z;
+ }
+ }
+ e--;
+ }
+
+ if(s && (n>0))
+ {
+ *(dst++) = '-';
+ n--;
+ }
+
+ x = libc_ulltoa(i, dst, n, 0);
+ n-=x+1;
+ dst+=x;
+
+ dprintf("N = %d\n", n);
+
+ if(n>0)
+ {
+ *(dst++) = '.';
+
+ if(n>0)
+ libc_ulltoa(f, dst, (n<(prec+1))?n:(prec+1), 1);
+ }
+ }
+}
+
+static char libc_sprintf_floatbuf[64];
+
+static int __vsnprintf_internal(char *string, size_t size, const char *fmt, va_list ap, int (put_in_string(char *string, unsigned int sz, char c, int pos)))
+{
+ int string_pos,fmt_pos;
+ int l;
+ unsigned long long arg;
+ char *argcp;
+ char *argcp_tmp;
+ int directive_coming = 0;
+ int flags = 0;
+ int argsize = 2; // int
+ int x, y;
+ unsigned long long a, b;
+ int empty_digit;
+ int ssz = size - 1;
+ int zero_flag_imp = 0;
+ int pad_quantity = 0;
+ int pad_quantity_f = -1;
+ int last;
+
+ if(size == 0)
+ ssz = 0;
+
+ l = strlen(fmt);
+
+ string_pos = 0;
+
+ for(fmt_pos=0;fmt_pos<l;fmt_pos++)
+ {
+ if(directive_coming)
+ {
+ switch(fmt[fmt_pos])
+ {
+ case '%':
+ put_in_string(string, ssz, '%', string_pos++);
+ directive_coming = 0;
+ break;
+ case ' ':
+ flags |= SPRINTF_SPACE_FLAG;
+ break;
+ case '#': // Specify alternate form
+ flags |= SPRINTF_ALT_FLAG;
+ break;
+ case '+': // Specify sign in signed conversions
+ flags |= SPRINTF_SIGN_FLAG;
+ break;
+ case '0': // Padding with zeros...
+ if(zero_flag_imp == 0)
+ {
+ flags |= SPRINTF_ZERO_FLAG;
+ zero_flag_imp = 1;
+ //printf("Zero padding enabled!\n");
+ }
+ else
+ {
+ pad_quantity *= 10;
+ //printf("pad_quantity = %d\n", pad_quantity);
+ }
+ break;
+ case '1' ... '9': // '...' cases are a GNU extension,
+ // but they simplify a lot
+
+ pad_quantity *= 10;
+ pad_quantity += fmt[fmt_pos] - '0';
+ zero_flag_imp = 1;
+
+ //printf("pad_quantity = %d\n", pad_quantity);
+ break;
+ case '-': // Negative field flag
+ if(flags & SPRINTF_ZERO_FLAG)
+ flags &= ~SPRINTF_ZERO_FLAG;
+
+ flags |= SPRINTF_NEGFIELD_FLAG;
+ break;
+ case '.': // Floating point precision
+ pad_quantity_f = pad_quantity;
+ pad_quantity = 0;
+ break;
+ case 'h': // Half argument size
+ if(argsize) argsize--;
+ break;
+ case 'l': // Double argument size
+ if(argsize < 2) argsize = 2;
+ else if(argsize < SPRINTF_SIZE_LONG_LONG) argsize++;
+ break;
+
+// 'j', 't', 'z', 'q' added 2013-10-26 by nextvolume
+
+ case 'j': // Maximum integer size
+ argsize = SPRINTF_SIZE_LONG_LONG;
+ break;
+
+ case 't': // Size of ptrdiff_t (i.e. long on 32-bit, long long on 64-bit)
+ argsize = (sizeof(void*)==8)?
+ SPRINTF_SIZE_LONG_LONG:SPRINTF_SIZE_LONG;
+ break;
+
+ case 'z': // Size of size_t (int)
+ argsize = SPRINTF_SIZE_INT;
+ break;
+
+ case 'q': // Size of quad_t
+ argsize = SPRINTF_SIZE_LONG_LONG;
+ break;
+
+ case 'd': // signed decimal
+ case 'i':
+ empty_digit = 1;
+
+ //printf("argsize = %d\n", argsize);
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ if(flags & SPRINTF_SPACE_FLAG)
+ put_in_string(string, ssz, ' ', string_pos++);
+
+ if(get_arg_in_size(argsize, &arg, 1))
+ {
+ put_in_string(string, ssz, '-', string_pos++);
+ pad_quantity--;
+ }
+ else
+ {
+ if(flags & SPRINTF_SIGN_FLAG)
+ {
+ put_in_string(string, ssz, '+', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ /* Calculate how much padding we have to write */
+
+ /*y = 1;
+
+ for(x=0;x<=9;x++)
+ {
+ if(x == 0)
+ pad_quantity--;
+ else
+ {
+ if(arg / y)
+ pad_quantity--;
+ }
+
+ y *= 10;
+ }
+ if(pad_quantity < 0) pad_quantity = 0;*/
+
+ calculate_real_padding();
+
+ //printf("Actual pad quantity = %d\n", pad_quantity);
+
+
+
+ /*if(!(flags & SPRINTF_NEGFIELD_FLAG))
+ {
+ for(x = 0; x < pad_quantity; x++)
+ {
+ if(flags & SPRINTF_ZERO_FLAG)
+ put_in_string(string, ssz, '0', string_pos++);
+ else
+ put_in_string(string, ssz, ' ', string_pos++);
+ }
+ }*/
+
+ write_padding();
+
+ for(x=19;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+ b = (arg/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ arg -= b*a;
+
+ put_in_string(string, ssz, b + '0', string_pos++);
+ }
+ }
+
+ /*if(flags & SPRINTF_NEGFIELD_FLAG)
+ {
+ for(x = 0; x < pad_quantity; x++)
+ put_in_string(string, ssz, ' ', string_pos++);
+ }*/
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'u': // unsigned decimal
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ get_arg_in_size(argsize, &arg, 0);
+
+ calculate_real_padding();
+ write_padding();
+
+ for(x=19;x>=0;x--)
+ {
+ a = 1;
+ for(y = 0; y<x; y++)
+ a *= 10;
+
+
+
+ b = (arg/a);
+
+ if(b>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ arg -= b*a;
+
+ put_in_string(string, ssz, b + '0', string_pos++);
+ }
+ }
+
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'x': // Hexadecimal
+ case 'X': // Hexadecimal with big letters
+ case 'p': // Hexadecimal with small letters with '0x' prefix
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long int);
+
+ get_arg_in_size(argsize, &arg, 0);
+
+ if(fmt_pos == 'p')
+ flags |= SPRINTF_ALT_FLAG;
+
+ if(flags & SPRINTF_ALT_FLAG)
+ {
+ put_in_string(string, ssz, '0', string_pos++);
+
+ if(fmt[fmt_pos] == 'X')
+ put_in_string(string, ssz, 'X', string_pos++);
+ else
+ put_in_string(string, ssz, 'x', string_pos++);
+ }
+
+ calculate_real_padding_hex();
+ write_padding();
+
+ for(x=15;x>=0;x--)
+ {
+ y = arg >> (x << 2);
+ y &= 0xf;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ {
+ if(y>=0 && y<=9)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ else if(y>=0xA && y<=0xF)
+ {
+ if(fmt[fmt_pos] == 'X')
+ put_in_string(string, ssz, (y - 0xa) + 'A', string_pos++);
+ else
+ put_in_string(string, ssz, (y - 0xa) + 'a', string_pos++);
+ }
+ }
+ }
+
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'c': // character
+ arg = va_arg(ap, int);
+
+ put_in_string(string, ssz, arg & 0xff, string_pos++);
+
+ directive_coming = 0;
+ break;
+ case 's': // string
+ argcp = va_arg(ap, char *);
+ argcp_tmp = argcp;
+
+ if(argcp == NULL)
+ {
+ // Non standard extension, but supported by Linux and the BSDs.
+
+ put_in_string(string, ssz, '(', string_pos++);
+ put_in_string(string, ssz, 'n', string_pos++);
+ put_in_string(string, ssz, 'u', string_pos++);
+ put_in_string(string, ssz, 'l', string_pos++);
+ put_in_string(string, ssz, 'l', string_pos++);
+ put_in_string(string, ssz, ')', string_pos++);
+
+ directive_coming = 0;
+ break;
+ }
+
+ while(*argcp_tmp)
+ {
+ if(pad_quantity > 0) pad_quantity--;
+ argcp_tmp++;
+ }
+
+ if(!(flags & SPRINTF_NEGFIELD_FLAG))
+ {
+ while(pad_quantity > 0)
+ {
+ put_in_string(string,ssz, ' ', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ while(*argcp)
+ {
+ put_in_string(string, ssz, *argcp, string_pos++);
+
+ argcp++;
+ }
+
+ if(flags & SPRINTF_NEGFIELD_FLAG)
+ {
+ while(pad_quantity > 0)
+ {
+ put_in_string(string,ssz, ' ', string_pos++);
+ pad_quantity--;
+ }
+ }
+
+ directive_coming = 0;
+ break;
+ case 'o': // Octal
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ for(x=21;x>=0;x--)
+ {
+ y = arg >> (x * 3);
+ y &= 0x7;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ }
+
+ directive_coming = 0;
+ break;
+ case '@': // Binary
+ empty_digit = 1;
+
+ if(argsize < SPRINTF_SIZE_LONG_LONG)
+ arg = (unsigned long long)va_arg(ap, unsigned int);
+ else
+ arg = va_arg(ap, unsigned long long);
+
+ for(x=63;x>=0;x--)
+ {
+ y = (arg >> x);
+ y &= 1;
+
+ if(y>=1)
+ empty_digit = 0;
+
+ if(empty_digit == 0 || x == 0)
+ put_in_string(string, ssz, y + '0', string_pos++);
+ }
+
+ directive_coming = 0;
+ break;
+
+ case 'f':
+ if(pad_quantity_f == -1)
+ pad_quantity_f = 6;
+ else
+ {
+ x = pad_quantity_f;
+ pad_quantity_f = pad_quantity;
+ pad_quantity = x;
+ }
+
+ dprintf("PRECISION = %d\n", pad_quantity_f);
+
+ libc_double_to_string(va_arg(ap, double), libc_sprintf_floatbuf, 64, pad_quantity_f);
+
+ // calculate padding
+ pad_quantity -= strlen(libc_sprintf_floatbuf);
+
+ write_padding();
+
+ for(x=0;libc_sprintf_floatbuf[x]!=0;x++)
+ put_in_string(string, ssz, libc_sprintf_floatbuf[x], string_pos++);
+
+ write_neg_padding();
+
+ directive_coming = 0;
+ break;
+ case 'n': // Number of characters written
+ *(va_arg(ap,unsigned int*)) = string_pos;
+
+ directive_coming = 0;
+ break;
+
+ default:
+ put_in_string(string, ssz, fmt[fmt_pos], string_pos++);
+ directive_coming = 0;
+ }
+ }
+ else
+ {
+ if(fmt[fmt_pos] == '%')
+ {
+ directive_coming = 1;
+ flags = 0;
+ argsize = 2;
+ pad_quantity = 0;
+ pad_quantity_f = -1;
+ zero_flag_imp = 0;
+ }
+ else
+ {
+ put_in_string(string, ssz, fmt[fmt_pos], string_pos++);
+ }
+ }
+ }
+
+ /*if(((size-1) < string_pos) && (size>0))
+ string[size - 1] = 0;
+ else
+ string[string_pos] = 0;*/
+ put_in_string(string, ssz, '\0', string_pos);
+
+ return string_pos;
+}
+
+static int vsnprintf_put_in_string(char *string, unsigned int sz, char c, int pos)
+{
+ if(pos>=sz)
+ return 0;
+ else
+ string[pos] = c;
+
+ return 1;
+}
+
+int vsnprintf(char *string, size_t size, const char *fmt, va_list ap)
+{
+ return __vsnprintf_internal(string, size, fmt, ap, vsnprintf_put_in_string);
+}
+
+static int sio_put_in_string(char *string, unsigned int sz, char c, int pos)
+{
+ sio_putchar(c);
+
+ return 1;
+}
+
+int sio_vprintf(const char *fmt, va_list ap)
+{
+ return __vsnprintf_internal(NULL, -1, fmt, ap, sio_put_in_string);
+}
+
+static int out_put_in_string(char *string, unsigned int sz, char c, int pos)
+{
+ putchar(c);
+
+ return 1;
+}
+
+int vprintf(char *fmt, va_list ap)
+{
+ return __vsnprintf_internal(NULL, -1, fmt, ap, out_put_in_string);
+}
+
+int vsprintf(char *string, const char *fmt, va_list ap)
+{
+ return vsnprintf(string, 0xffffffff, fmt, ap);
+}
+
+int sprintf(char *string, const char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = vsprintf(string, fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
+
+int snprintf(char *string, size_t size, const char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = vsnprintf(string, size, fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
+
+int sio_printf(const char *fmt, ...)
+{
+ int r;
+
+ va_list ap;
+
+ va_start(ap, fmt);
+
+ r = sio_vprintf(fmt, ap);
+
+ va_end(ap);
+
+ return r;
+}
diff --git a/libpsx/src/libc/qsort.c b/libpsx/src/libc/qsort.c
new file mode 100644
index 0000000..0cb1d24
--- /dev/null
+++ b/libpsx/src/libc/qsort.c
@@ -0,0 +1,65 @@
+// quickSort
+//
+// This public-domain C implementation by Darel Rex Finley.
+//
+// Modified by Giuseppe Gatta
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *))
+{
+ #define QSORT_MAX_LEVELS 300
+
+
+ int beg[QSORT_MAX_LEVELS], end[QSORT_MAX_LEVELS], i=0, L, R, swap ;
+ char piv[size];
+
+ beg[0]=0; end[0]=nmemb;
+
+ while (i>=0)
+ {
+ L=beg[i]; R=end[i]-1;
+
+ if (L<R)
+ {
+ memcpy(piv, base + (size * L), size);
+
+ while (L<R)
+ {
+ while(compar(base + (R*size), piv) > 0 && L<R) R--;
+
+ if (L<R)
+ {
+ memcpy(base + (size *L), base + (size * R), size);
+ L++;
+ }
+
+ while(compar(base + (L*size), piv) <= 0 && L<R) L++;
+
+ if (L<R)
+ {
+ memcpy(base + (size *R), base + (size * L), size);
+ R--;
+ }
+ }
+
+ memcpy(base + (size*L), piv, size);
+
+ beg[i+1]=L+1;
+ end[i+1]=end[i];
+ end[i++]=L;
+
+ if (end[i]-beg[i]>end[i-1]-beg[i-1])
+ {
+ swap=beg[i]; beg[i]=beg[i-1]; beg[i-1]=swap;
+ swap=end[i]; end[i]=end[i-1]; end[i-1]=swap;
+ }
+ }
+ else
+ {
+ i--;
+ }
+ }
+}
diff --git a/libpsx/src/libc/scanf.c b/libpsx/src/libc/scanf.c
new file mode 100644
index 0000000..d419030
--- /dev/null
+++ b/libpsx/src/libc/scanf.c
@@ -0,0 +1,425 @@
+// vsscanf
+// Programmed by Giuseppe Gatta, 2011
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+char libc_vsscanf_buf[512];
+char libc_vsscanf_allow[256];
+
+enum
+{
+ elem_skip_space = 1,
+};
+
+int libc_vsscanf_get_element(char *dst, const char *src, int flag, int s)
+{
+ int i;
+ const char *osrc = src;
+
+ if(flag & elem_skip_space)
+ {
+ while(*src == ' ')
+ src++;
+ }
+
+ for(i=0;i<s;i++)
+ {
+ if((flag & elem_skip_space) && *src == ' ')
+ break;
+
+ if(*src != 0)
+ *(dst++) = *(src++);
+ else
+ break;
+ }
+
+ *dst = 0;
+
+ return src - osrc;
+}
+
+enum
+{
+ scanf_s_char, scanf_s_short, scanf_s_int,
+ scanf_s_long,
+ scanf_s_long_long
+};
+
+int vsscanf(const char *str, const char *format, va_list ap)
+{
+ int fp = 0;
+ int sp = 0;
+ int conv = 0;
+ int sz = scanf_s_int; // size for numbers defaults to 32-bit
+ int i,x,y,z;// h;
+ int suppress = 0;
+// int neg = 0;
+ int fsz = 512;
+ int def_fsz = 1;
+ int exspace = 0;
+// int alt = 0;
+ int r = 0;
+ int exit_loop=0;
+ char *ep;
+ long long buf;
+ double fbuf;
+
+
+ while(format[fp] && str[sp] && !exit_loop)
+ {
+ if(conv)
+ {
+ switch(format[fp])
+ {
+ case '%': // Percent, assignment does not occur
+ conv = 0;
+ break;
+
+ case 'h': // Halve size
+ sz--;
+ break;
+
+ case 'l': // Double size
+ sz++;
+ break;
+
+ case '*': // Suppress
+ suppress = 1;
+ break;
+
+ case ' ': // Explicit space
+ exspace = 1;
+ break;
+
+ case '#': // Alternate format
+ //alt = 1;
+ break;
+
+ case '0' ... '9': // '0' ... '9' is a GNU C extension!
+ if(def_fsz)
+ {
+ def_fsz = 0;
+ fsz = 0;
+ }
+
+ fsz *= 10;
+ fsz+=format[fp]-'0';
+
+ if(fsz > 512)
+ fsz = 512; // 512 is the maximum.
+ break;
+
+ case '@': // Binary. Non-standard extension
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 2);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'D':
+ sz++;
+ case 'd': // Decimal
+ case 'u':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 10);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf;break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 's': // String
+ sp += libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+
+ if(!suppress)
+ {
+ strcpy(va_arg(ap, char*), libc_vsscanf_buf);
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'c':
+ if(def_fsz)
+ fsz = 1;
+
+ sp += (i = libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], (exspace ? elem_skip_space : 0), fsz));
+ if(!suppress)
+ {
+ memcpy(va_arg(ap, char*), libc_vsscanf_buf, (fsz>i)?i:fsz);
+ r++;
+ }
+ break;
+
+ case 'n':
+ if(!suppress)
+ {
+ *(va_arg(ap, int*)) = sp;
+ r++;
+ }
+ break;
+
+ case 'p':
+ case 'x':
+ case 'X':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 16);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf; break;
+ case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break;
+ case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf; break;
+ case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'O':
+ sz++;
+ case 'o': // Octal integer
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ buf = strtoll(libc_vsscanf_buf, &ep, 8);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, unsigned char*)) = (unsigned char)buf;break;
+ case scanf_s_short: *(va_arg(ap, unsigned short*)) = (unsigned short)buf; break;
+ case scanf_s_int: *(va_arg(ap, unsigned int*)) = (unsigned int)buf;break;
+ case scanf_s_long: *(va_arg(ap, unsigned long*)) = (unsigned long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, unsigned long long*)) = (unsigned long long)buf;break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case 'i':
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+
+ if(libc_vsscanf_buf[0] == '0')
+ {
+ if(libc_vsscanf_buf[1] == 'x' || libc_vsscanf_buf[1] == 'X')
+ i = 16;
+ else
+ i = 8;
+ }
+ else
+ i = 10;
+
+ buf = strtoll(libc_vsscanf_buf, &ep, i);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char: *(va_arg(ap, signed char*)) = (signed char)buf; break;
+ case scanf_s_short: *(va_arg(ap, short*)) = (short)buf; break;
+ case scanf_s_int: *(va_arg(ap, int*)) = (int)buf; break;
+ case scanf_s_long: *(va_arg(ap, long*)) = (long)buf; break;
+ case scanf_s_long_long: *(va_arg(ap, long long*)) = (long long)buf; break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ case '[':
+ i=0;
+ x=0; // Exclusion?
+ //h=0; // Hyphen?
+
+ fp++;
+ i++;
+
+ while(format[fp])
+ {
+ if(format[fp] == '^' && i==1)
+ {
+ memset(libc_vsscanf_allow, 1, 256);
+ x = 1;
+ fp++; i++; continue;
+ }
+
+ if(x)
+ {
+ if(format[fp] == ']' && i>=3)
+ break;
+ }
+ else
+ {
+ if(format[fp] == ']' && i>=2)
+ break;
+ }
+
+ if(format[fp] == '-')
+ {
+ if(format[fp+1] != ']')
+ y = 1;
+ else
+ libc_vsscanf_allow['-'] = x^1;
+ }
+ else
+ {
+ if(y == 1)
+ {
+ if(format[fp] < format[fp-2])
+ libc_vsscanf_allow[(unsigned char)format[fp]] = x^1;
+ else
+ for(z = format[fp-2]; z <= format[fp]; z++)
+ libc_vsscanf_allow[z] = x^1;
+
+ y = 0;
+
+ //printf("%s all chars from %c to %c\n", x?"Excluding":"Including",format[fp-2], format[fp]);
+ }
+ else
+ libc_vsscanf_allow[(unsigned char)format[fp]] = x^1;
+ }
+
+ fp++;
+ i++;
+ }
+
+// Now as we know what our character set is, let's get data from the string
+ /* puts("Character set:");
+
+ for(y=0;y<16;y++)
+ {
+ for(x=0;x<16;x++)
+ if(libc_vsscanf_allow[(y*16) + x])
+ putchar((y*16)+x);
+ else
+ putchar('*');
+
+ putchar('\n');
+ }
+ */
+ i = 0;
+
+ while(libc_vsscanf_allow[(unsigned char)str[sp]] && i<512)
+ libc_vsscanf_buf[i++] = str[sp++];
+
+ libc_vsscanf_buf[i] = 0;
+
+ if(!suppress)
+ {
+ strcpy(va_arg(ap, char*), libc_vsscanf_buf);
+ r++;
+ }
+ break;
+
+ case 'f': // Floating point number
+ libc_vsscanf_get_element(libc_vsscanf_buf, &str[sp], elem_skip_space, fsz);
+ fbuf = strtod(libc_vsscanf_buf, &ep);
+ sp += ep - libc_vsscanf_buf;
+
+ if(!suppress)
+ {
+ switch(sz)
+ {
+ case scanf_s_char:
+ case scanf_s_short:
+ case scanf_s_int:
+ *(va_arg(ap, float*)) = (float)fbuf;
+ break;
+
+ case scanf_s_long:
+ case scanf_s_long_long:
+ *(va_arg(ap, double*)) = fbuf;
+ break;
+ }
+ r++;
+ }
+
+ conv = 0;
+ break;
+
+ }
+ }
+ else
+ {
+ if(format[fp] == '%')
+ {
+ // conv = 1;
+ // neg = 0;
+ suppress = 0;
+ sz = scanf_s_int;
+ fsz = 512;
+ def_fsz = 1;
+ exspace = 0;
+ // alt = 0;
+ bzero(libc_vsscanf_allow, 256);
+ //chset = 0;
+ }
+ else if(format[fp] != ' ')
+ {
+ if(format[fp] != str[sp])
+ exit_loop=1;
+
+ sp++;
+ }
+
+ }
+
+ fp++;
+ }
+
+ return r;
+}
+
+int sscanf(const char *str, const char *fmt, ...)
+{
+ int r;
+ va_list ap;
+
+ va_start(ap, fmt);
+ r = vsscanf(str, fmt, ap);
+
+ va_end(ap);
+ return r;
+}
diff --git a/libpsx/src/libc/stat.c b/libpsx/src/libc/stat.c
new file mode 100644
index 0000000..1c43b92
--- /dev/null
+++ b/libpsx/src/libc/stat.c
@@ -0,0 +1,31 @@
+#include <psx.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+int stat(const char *path, struct stat *sb)
+{
+ struct DIRENTRY dir_e;
+
+ if(firstfile((char*)path, &dir_e) == NULL)
+ return -1;
+
+ sb->st_size = dir_e.size;
+
+ if(strncmp(path, "cdrom:", 6) == 0)
+ sb->st_blksize = 2048;
+ else if(strncmp(path, "bu00:", 5) == 0 ||
+ strncmp(path, "bu10:", 5) == 0)
+ sb->st_blksize = 128;
+ else
+// not a real blocksize, will be there just as a placeholder
+ sb->st_blksize = 1024;
+
+ sb->st_blocks =
+ sb->st_size / sb->st_blksize;
+
+ if(sb->st_size % sb->st_blksize)
+ sb->st_blocks++;
+
+ return 0;
+}
diff --git a/libpsx/src/libc/string.c b/libpsx/src/libc/string.c
new file mode 100644
index 0000000..ea59b91
--- /dev/null
+++ b/libpsx/src/libc/string.c
@@ -0,0 +1,706 @@
+/*
+ * string.c
+ *
+ * Part of the PSXSDK C library
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+
+void *memcpy(void *dst, const void *src, size_t len)
+{
+ void *dst2 = dst;
+
+ while(len--)
+ *(((unsigned char*)dst++)) = *(((unsigned char*)src++));
+
+ return dst2;
+}
+
+void *memccpy(void *dst, const void *src, int c, size_t len)
+{
+ unsigned char c2;
+
+ while(len--)
+ {
+ *(((unsigned char*)dst++)) = ( c2 = *(((unsigned char*)src++)) );
+
+ if(c2 == c)
+ return (void*)src;
+ }
+
+ return NULL;
+}
+
+void *memset(void *dst , char c , size_t n)
+{
+ unsigned char *dstc = (unsigned char*)dst;
+ int x;
+
+ for(x = 0; x < n; x++)
+ dstc[x] = c;
+
+ return dst;
+}
+
+int memcmp(const void *b1, const void *b2, size_t n)
+{
+ int x;
+ unsigned char *bp1 = (unsigned char*)b1;
+ unsigned char *bp2 = (unsigned char*)b2;
+
+ for(x = 0; x < n; x++)
+ if(bp1[x] != bp2[x])
+ return (bp1[x] - bp2[x]);
+
+ return 0;
+}
+
+void *memmove(void *dst, const void *src, size_t len)
+{
+ void *dst2 = dst;
+
+ dst+=len-1;
+ src+=len-1;
+
+ while(len--)
+ *(((unsigned char*)dst--)) = *(((unsigned char*)src--));
+
+ return dst2;
+}
+
+void *memchr(void *s , int c , size_t n)
+{
+ while(n--)
+ {
+ if(*((unsigned char*)s) == (unsigned char)c)
+ return s;
+
+ s++;
+ }
+
+ return NULL;
+}
+
+char *strncpy(char *dst, const char *src, size_t len)
+{
+ char *odst=dst;
+
+ while(*src && len)
+ {
+ *(dst++) = *(src++);
+ len--;
+ }
+
+ if(len)*dst = 0;
+
+ return odst;
+}
+
+char *strcpy(char *dst, const char *src)
+{
+ char *odst = dst;
+
+ while((*(dst++) = *(src++)));
+ return odst;
+}
+
+int strlen(const char *str)
+{
+ int i = 0;
+ while(*(str++))i++;
+ return i;
+}
+
+char *strchr(const char *s, int c)
+{
+ int x;
+ int l = strlen(s);
+
+ for(x = 0; x <= l; x++)
+ if(s[x] == c) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strrchr(const char *s, int c)
+{
+ int x;
+ int l = strlen(s);
+
+ for(x = l; x>=0; x--)
+ if(s[x] == c) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strpbrk(const char *s, const char *charset)
+{
+ int x,y;
+
+ for(x = 0; s[x] != 0; x++)
+ for(y = 0; charset[y] != 0; y++)
+ if(s[x] == charset[y]) return (char*)&s[x];
+
+ return NULL;
+}
+
+char *strstr(const char *big, const char *little)
+{
+ int ls = strlen(little);
+ int bs = strlen(big);
+ int x;
+
+ if(ls == 0)
+ return (char*)big;
+
+ if(ls > bs)
+ return NULL;
+
+ for(x = 0; x <= bs-ls; x++)
+ if(memcmp(little, &big[x], ls) == 0)
+ return (char*)&big[x];
+
+ return NULL;
+}
+
+int strcmp(const char *s1, const char *s2)
+{
+ while(*s1 && *s2 && (*s1 == *s2))
+ {
+ s1++;
+ s2++;
+ }
+
+ return *s1-*s2;
+}
+
+int strncmp(const char *s1, const char *s2, size_t len)
+{
+ int p = 0;
+
+ while(*s1 && *s2 && (*s1 == *s2) && p<len)
+ {
+ p++;
+
+ if(p<len)
+ {
+ s1++;
+ s2++;
+ }
+ }
+
+ return *s1-*s2;
+}
+
+int strcoll(const char *s1, const char *s2)
+{
+ return strcmp(s1, s2);
+}
+
+char *strdup(const char *str)
+{
+ char *ns = (void*)malloc(strlen(str) + 1);
+
+ if(ns == NULL)
+ return NULL;
+
+ strcpy(ns, str);
+ return ns;
+}
+
+char *strndup(const char *str, size_t len)
+{
+ int n=strlen(str);
+ char *ns = (void*)malloc((n+1)>len?len:(n+1));
+
+ if(ns == NULL)
+ return NULL;
+
+ strncpy(ns, str, (n+1)>len?len:(n+1));
+ return ns;
+}
+
+long long strtoll(const char *nptr, char **endptr, int base)
+{
+ int r = 0;
+ int t = 0;
+ int n = 0;
+
+ while(*nptr && isspace(*nptr))
+ nptr++;
+
+ if(*nptr == '-')
+ {
+ nptr++;
+ n = 1;
+ }
+
+ if(base == 0)
+ {
+ if(*nptr == '0')
+ base = 8;
+ else
+ base = 10;
+ }
+
+ if(!(base >= 2 && base <= 36))
+ return 0;
+
+ if(base == 16 && *nptr == '0')
+ {
+ if(*(nptr+1) == 'x' || *(nptr+1) == 'X')
+ nptr+=2;
+ }
+
+ while(*nptr)
+ {
+ switch(*nptr)
+ {
+ case '0'...'9':
+ t = *nptr - '0';
+ break;
+ case 'a' ... 'z':
+ t = (*nptr - 'a') + 10;
+ break;
+ case 'A' ... 'Z':
+ t = (*nptr - 'A') + 10;
+ break;
+ default:
+ t = 1000;
+ break;
+ }
+
+ if(t>=base)
+ break;
+
+ r*=base;
+ r+=t;
+ nptr++;
+ }
+
+ if(endptr)*endptr = (char*)nptr;
+ return n?-r:r;
+}
+
+long strtol(const char *nptr, char **endptr, int base)
+{
+ return (long)strtoll(nptr, endptr, base);
+}
+
+double strtod(const char *nptr, char **endptr)
+{
+ char strbuf[64];
+ int x = 0;
+ int y;
+ double i=0, d=0;
+ int s=1;
+
+ if(*nptr == '-')
+ {
+ nptr++;
+ s=-1;
+ }
+
+ while(*nptr >= '0' && *nptr <= '9' && x < 18)
+ strbuf[x++] = *(nptr++);
+
+ strbuf[x] = 0;
+
+ i = (double)strtoll(strbuf, NULL, 10);
+
+ if(*nptr == '.')
+ {
+ nptr++;
+ x = 0;
+
+ while(*nptr >= '0' && *nptr <= '9' && x < 7)
+ strbuf[x++] = *(nptr++);
+
+ strbuf[x] = 0;
+
+ if(endptr != NULL) *endptr = (char*)nptr;
+
+ y=1;
+
+ for(x=0;strbuf[x]!=0;x++)
+ y*=10;
+
+ d = (double)strtoll(strbuf, NULL, 10);
+ d /= y;
+ }
+ else
+ {
+ if(endptr != NULL)
+ *endptr = (char*)nptr;
+ }
+
+ return (i + d)*s;
+}
+
+long double strtold(const char *nptr, char **endptr)
+{
+ return (long double)strtod(nptr, endptr);
+}
+
+float strtof(const char *nptr, char **endptr)
+{
+ return (float)strtod(nptr, endptr);
+}
+
+char *strcat(char *s, const char *append)
+{
+ strcpy(&s[strlen(s)], append);
+
+ return s;
+}
+
+char *strncat(char *s, const char *append, size_t count)
+{
+ strncpy(&s[strlen(s)], append, count);
+
+ return s;
+}
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ while(tolower(*s1) && tolower(*s2) && (tolower(*s1) == tolower(*s2)))
+ {
+ s1++;
+ s2++;
+ }
+
+ return tolower(*s1)-tolower(*s2);
+}
+
+int strncasecmp(const char *s1, const char *s2, size_t len)
+{
+ int p = 0;
+
+ while(tolower(*s1) && tolower(*s2) && (tolower(*s1) == tolower(*s2)) && p<len)
+ {
+ p++;
+
+ if(p<len)
+ {
+ s1++;
+ s2++;
+ }
+ }
+
+ return tolower(*s1)-tolower(*s2);
+}
+
+int stricmp(const char *s1, const char *s2)
+{
+ return strcasecmp(s1,s2);
+}
+
+int strnicmp(const char *s1, const char *s2, size_t len)
+{
+ return strncasecmp(s1, s2, len);
+}
+
+//static char *strtok_string;
+
+char *strsep(char **stringp, const char *delim)
+{
+ //int x,y;
+ char *old = *stringp;
+ const char *s;
+ int ok = 0;
+
+ while(**stringp && !ok)
+ {
+ s = delim;
+
+ while(*delim)
+ {
+ if(**stringp == *delim)
+ {
+ **stringp = 0;
+ ok = 1;
+ break;
+ }
+
+ delim++;
+ }
+
+ delim = s;
+
+ *stringp+=1;
+ }
+
+ if(!ok)*stringp = NULL;
+
+ return old;
+}
+
+char *strtok(char *str, const char *sep)
+{
+ int x, y;
+ static char *strtok_string;
+ static int strtok_len;
+ static int strtok_pos;
+ //int strtok_oldpos = 0;
+
+ if(str != NULL)
+ {
+ strtok_string = str;
+ strtok_len = strlen(str);
+
+ for(x = 0; x < strtok_len; x++)
+ {
+ for(y = 0; sep[y] != 0; y++)
+ {
+ if(strtok_string[x] == sep[y])
+ {
+ strtok_string[x] = 0;
+ break;
+ }
+ }
+ }
+
+ strtok_pos = 0;
+
+ while(strtok_pos < strtok_len)
+ {
+ if(strtok_string[strtok_pos])
+ return &strtok_string[strtok_pos];
+
+ strtok_pos++;
+ }
+ }
+
+ while(strtok_pos < strtok_len)
+ {
+ if(!strtok_string[strtok_pos])
+ {
+ strtok_pos++;
+ break;
+ }
+
+ strtok_pos++;
+ }
+
+ while(strtok_pos < strtok_len)
+ {
+
+ if(strtok_string[strtok_pos])
+ return &strtok_string[strtok_pos];
+
+ strtok_pos++;
+ }
+
+ return NULL;
+}
+
+int strspn(const char *s, const char *charset)
+{
+ int x, y;
+ int appears;
+
+ for(x = 0; s[x] != 0; x++)
+ {
+ appears = 0;
+
+ for(y = 0; charset[y] != 0; y++)
+ {
+ if(s[x] == charset[y])
+ {
+ appears = 1;
+ break;
+ }
+ }
+
+ if(!appears)break;
+ }
+
+ return x;
+}
+
+int strcspn(const char *s, const char *charset)
+{
+ int x, y;
+ int appears;
+
+ for(x = 0; s[x] != 0; x++)
+ {
+ appears = 0;
+
+ for(y = 0; charset[y] != 0; y++)
+ {
+ if(s[x] == charset[y])
+ {
+ appears = 1;
+ break;
+ }
+ }
+
+ if(appears)break;
+ }
+
+ return x;
+}
+
+char *strlwr(char *string)
+{
+ char *old = string;
+
+ while(*string)
+ {
+ *string = tolower(*string);
+ string++;
+ }
+
+ return old;
+}
+
+char *strupr(char *string)
+{
+ char *old = string;
+
+ while(*string)
+ {
+ *string = toupper(*string);
+ string++;
+ }
+
+ return old;
+}
+
+int atoi(const char *string)
+{
+ return (int)strtol(string, NULL, 10);
+}
+
+long atol(const char *string)
+{
+ return strtol(string, NULL, 10);
+}
+
+int strnlen(const char *s, size_t maxlen)
+{
+ int l=0;
+
+ while(*(s++) && l<maxlen)
+ l++;
+
+ return l;
+}
+
+void *memrchr(void *b, int c, size_t len)
+{
+ int i = len - 1;
+ unsigned char *p = b;
+
+ for(i = len - 1; p[i] != (unsigned char)c && i >= 0;i--);
+
+ return (i>=0)?&p[i]:NULL;
+}
+
+char *stpcpy(char *dst, const char *src)
+{
+ do
+ {
+ *(dst++) = *src;
+ }while(*(src++));
+
+ return dst-1;
+}
+
+char *stpncpy(char *dst, const char *src, int len)
+{
+ int c = 0;
+
+ do
+ {
+ if(c < len)
+ *(dst++) = *src;
+
+ c++;
+ }while(*(src++) && c < len);
+
+ return dst-1;
+}
+
+char *strcasestr(const char *big, const char *little)
+{
+ while(*big)
+ {
+ const char *pbig = big;
+ const char *plittle = little;
+ int ok = 1;
+
+ while(*pbig)
+ {
+ if(tolower(*pbig) != tolower(*plittle))
+ {
+ ok = 0;
+ break;
+ }
+
+ pbig++;
+ plittle++;
+ }
+
+ if(ok)
+ return (char*)big;
+
+ big++;
+ }
+
+ return NULL;
+}
+
+int strlcpy(char *dst, const char *src, size_t size)
+{
+ char *src_end = memchr((void*)src, '\0', size);
+
+ if(src_end == NULL)
+ return 0;
+
+ memcpy(dst, src, src_end - src);
+
+ return (src_end - src);
+}
+
+int strlcat(char *dst, const char *src, size_t size)
+{
+ int dstl = strlen(dst);
+ char *q = dst + dstl;
+ int real_size = size;
+
+ if(memchr((void*)src, '\0', size))
+ real_size = strlen(src);
+
+ memcpy(q, src, real_size-dstl-1);
+ if(real_size != size) q[real_size-dstl-1] = '\0';
+
+ return size-dstl;
+}
+
+void *memmem(const void *big, size_t big_len, const void *little,
+ size_t little_len)
+{
+ int i, j, l;
+ unsigned char *bigp = (unsigned char*)big;
+ unsigned char *littlep = (unsigned char*)little;
+
+ for(i = 0, l = (int)(big_len - little_len); i <= l; i++, bigp++)
+ {
+ for(j = 0; j < little_len; j++)
+ {
+ if(littlep[j] != bigp[j])
+ break;
+ }
+
+ if(j == little_len)
+ return bigp;
+ }
+
+ return NULL;
+}
diff --git a/libpsx/src/libc/strings.c b/libpsx/src/libc/strings.c
new file mode 100644
index 0000000..76a5f9f
--- /dev/null
+++ b/libpsx/src/libc/strings.c
@@ -0,0 +1,41 @@
+#include <stdlib.h>
+#include <strings.h>
+#include <stdint.h>
+
+#define ffs_func(func_name, type) \
+\
+int func_name(type value) \
+{ \
+ int i; \
+ int nbits = sizeof(type) * 8;\
+ \
+ for(i = 0; i < nbits && !(value & ((type)1 << i) ); i++);\
+ \
+ return (i == nbits) ? 0 : (i + 1);\
+}
+
+ffs_func(ffs, int);
+ffs_func(ffsl, long);
+ffs_func(ffsll, long long);
+
+#define popcount_func(func_name, type) \
+\
+unsigned int func_name(type value) \
+{ \
+ int i, bitcnt; \
+ int nbits = sizeof(type) * 8; \
+ \
+ for(i = 0, bitcnt = 0; i < nbits; i++) \
+ {\
+ if( value & ((type)1 << i) )\
+ bitcnt++;\
+ }\
+ \
+ return bitcnt;\
+}
+
+popcount_func(popcount, unsigned int);
+popcount_func(popcountl, unsigned long);
+popcount_func(popcountll, unsigned long long);
+popcount_func(popcount32, uint32_t);
+popcount_func(popcount64, uint64_t);
diff --git a/libpsx/src/libc/unistd.c b/libpsx/src/libc/unistd.c
new file mode 100644
index 0000000..f64096b
--- /dev/null
+++ b/libpsx/src/libc/unistd.c
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+#include <unistd.h>
+
+void swab(const void *src, void *dst, ssize_t len)
+{
+ ssize_t x;
+ const unsigned char *srcp = src;
+ unsigned char *dstp = dst;
+
+ for(x = 0; x < len; x+=2)
+ {
+ dstp[x] = srcp[x + 1];
+
+ if( (x+1) < len )
+ dstp[x+1] = srcp[x];
+ }
+}