diff --git a/src/libc/LIB.status b/src/libc/LIB.status deleted file mode 100644 index dad9b052..00000000 --- a/src/libc/LIB.status +++ /dev/null @@ -1,180 +0,0 @@ -Stdlib: ------- - -What should stdlib contain, and current status. - -atof - ok -atoi - ok -atol - ok -strtod - ok -strtof - ok -strtold - missing (do we want to support long double anyway?) -strtol - ok -strtoul - ok -strtoq - missing -strtouq - missing -strtoll - missing (same as strtoq, different "standard") -strtoull - missing (same as strtouq, different "standard") - - -no locale function at all (__strtol_l, etc...) - - -random - missing -srandom - missing -initstate - missing -setstate - missing -rand - ok (should be...) -srand - ok -drand48 - missing - -all *rand48 missing - -malloc, calloc, realloc, free, are defined in alloc.c. - -abort - clean ? should call atexit functions ? -atexit - ok -exit - ok - -getenv - ok -setenv - ok - -system - missing, and won't be here anyway I think... - -bsearch - ok -qsort - ok -abs - ok -labs - ok -llabs - ok -div - ok, but shouldn't it use some asm ? -ldiv - ok, same -lldiv - ok, same -frexp - missing -ldexp - missing - -ecvt - missing -fcvt - missing -gcvt - won't compile - -Multibyte function disabled... I don't trust them. Somebody please advice. -mblen, mbtowc, wctomb, mbstowcs, wcstombs - - -Stdio: ------ - -stdin, stdout, stderr, ok. Maybe some specific ps2 function to switch stderr -to SIO could be an idea. - -Also, should have buffering... - -remove - missing -rename - missing -tmp* - missing -fclose - ok -fflush - ok (memory card) -fcloseall - ok -fopen - ok -freopen - missing -fdopen - ok -setbuf - missing -setvbuf - missing - -*printf - ok (f, s, vf, v, vs, sn, vsn, vas, as) -*dprintf - missing -*scanf - missing -*getc - ok -getchar - ok -*putc - ok -putchar - ok -{get,put}w - missing -*gets - ok -getdelim - missing, gnu replacement to gets -getline - missing, gnu replacement to gets -*puts - ok -ungetc - missing, buffering needed -fread - ok, buffering needed -fwrite - ok, buffering needed -fseek - ok -ftell - ok -rewind - ok -fgetpos - ok -fsetpos - ok -clearerr - ok -feof - ok -ferror - ok - -perror - ok -fileno - ok -pipe funcs - missing, can we make them ? -lock funcs - missing, can we make them ? - - -String: ------- - -memcpy - ok, asm version -memmove - ok, asm -memset - ok, asm -memcmp - ok, asm -memchr - ok, asm - -strcpy - ok, asm -strncpy - ok, asm -strcat - ok, asm -strncat - ok, asm -strcmp - ok, asm -strncmp - ok, asm - -strcoll - ok, binded to strcmp (will we ever support locales ?) -strxfrm - ok, binded to strncpy (will we ever support locales ?) - -strdup - ok - -strchr - ok, asm -strrchr - ok - -strcspn - ok -strspn - ok -strpbrk - ok -strstr - ok -strcasestr - missing -strtok - ok - -strlen - ok -strerror - ok (but in stdio) - -bzero - ok (macro, in string.h) -bcopy - ok (macro, in string.h) -bcmp - ok (macro, in string.h) -index - ok (macro, in string.h) -rindex - ok (macro, in string.h) - -stricmp - ok (macro) -strcasecmp - ok -strnicmp - ok (macro) -strncasecmp - ok - -isalnum - ok -iscntrl - ok -isdigit - ok -isgraph - ok -islower - ok -isprint - ok -ispunct - ok -isspace - ok -isupper - ok -isxdigit - ok - -asctime - missing -clock - missing -ctime - missing -difftime - missing -gmtime - missing -localtime - missing -mktime - missing - -longjmp - ok -setjmp - ok - -raise - missing, can we build signals ? diff --git a/src/libc/Makefile.am b/src/libc/Makefile.am index 172a05cf..c767b16c 100644 --- a/src/libc/Makefile.am +++ b/src/libc/Makefile.am @@ -2,72 +2,119 @@ libdir = @PSPSDK_LIBDIR@ CC = @PSP_CC@ -CXX = @PSP_CXX@ CCAS = $(CC) AR = @PSP_AR@ RANLIB = @PSP_RANLIB@ -CPPFLAGS = -I$(top_srcdir)/src/libc/include -I$(top_srcdir)/src/base -I$(top_srcdir)/src/kernel -I$(top_srcdir)/src/user -I$(top_srcdir)/src/debug +CPPFLAGS = -I$(top_srcdir)/src/base \ + -I$(top_srcdir)/src/debug \ + -I$(top_srcdir)/src/kernel \ + -I$(top_srcdir)/src/net \ + -I$(top_srcdir)/src/sdk \ + -I$(top_srcdir)/src/user \ + -I$(top_srcdir)/src/utility CFLAGS = @PSPSDK_CFLAGS@ -CXXFLAGS = @PSPSDK_CXXFLAGS@ CCASFLAGS = $(CFLAGS) -EXTRA_DIST = LIB.status +CWD_OBJS = __cwd.o getcwd.o __path_absolute.o __init_cwd.o + +ERRNO_OBJS = __set_errno.o + +FDMAN_OBJS = __descriptor_data_pool.o __descriptormap.o __fdman_init.o __fdman_get_new_descriptor.o __fdman_get_dup_descriptor.o \ + __fdman_release_descriptor.o + +GLUE_OBJS = __fill_stat.o __psp_heap_blockid.o __psp_free_heap.o _fork.o _wait.o _open.o _close.o _read.o _write.o _fstat.o \ + _stat.o lstat.o access.o _fcntl.o _lseek.o chdir.o mkdir.o rmdir.o getdents.o _seekdir.o _link.o _unlink.o \ + _rename.o getcwd.o _getpid.o _kill.o _sbrk.o _gettimeofday.o _times.o _internal_malloc_lock.o _internal_malloc_unlock.o \ + _isatty.o symlink.o truncate.o chmod.o fchmod.o fchmodat.o pathconf.o readlink.o utime.o fchown.o getentropy.o + + +INIT_OBJS = __psp_libc_init.o + +MUTEXMAN_OBJS = __malloc_mutex.o __sbrk_mutex.o __fdman_mutex.o __init_mutex.o + +NETDB_OBJS = h_errno.o gethostbyaddr.o gethostbyname.o + +PIPE_OBJS = __pipe_peekmsgsize.o pipe.o __pipe_close.o __pipe_nonblocking_read.o __pipe_read.o __pipe_write.o \ + __pipe_nonblocking_write.o + +SELECT_OBJS = select.o + +SLEEP_OBJS = nanosleep.o + +SOCKET_OBJS = socket.o __socket_close.o accept.o bind.o connect.o getsockopt.o listen.o recv.o recvfrom.o send.o sendto.o \ + setsockopt.o shutdown.o getpeername.o getsockname.o inet_ntoa.o sendmsg.o recvmsg.o + +TERMINATE_OBJS = _exit.o abort.o exit.o + +TIMEZONE_OBJS = __timezone_update.o lib_LIBRARIES = libpsplibc.a -## libpsplibc.a sources. -CORE_SOURCES = terminate.c setjmp.S qsort.c init.c cxx.cpp -MULT_SOURCES = xprintf.c alloc.c string.c stdio.c stdlib.c libcglue.c +netdb_nobase_includedir = @PSPSDK_INCLUDEDIR@ +netdb_nobase_include_HEADERS = netdb.h -ALLOC_OBJS = malloc.o realloc.o calloc.o memalign.o free.o __builtin_alloc.o __alloc_internals.o __mem_walk.o +netinet_nobase_includedir = @PSPSDK_INCLUDEDIR@/netinet +netinet_nobase_include_HEADERS = netinet/in.h netinet/tcp.h -STRING_C_OBJS = strdup.o strcasecmp.o strncasecmp.o strtok.o strrchr.o strstr.o \ - strupr.o strlwr.o _sjis_internals.o strcpy_ascii.o strcpy_sjis.o \ - strpbrk.o strspn.o strcspn.o memchr.o memcmp.o memcpy.o memmove.o \ - memset.o strcat.o strchr.o strcmp.o strcpy.o strlen.o strncat.o strncmp.o strncpy.o \ - tolower.o toupper.o isupper.o islower.o isalpha.o isdigit.o isalnum.o iscntrl.o \ - isgraph.o isprint.o ispunct.o isspace.o isxdigit.o +arpa_nobase_includedir = @PSPSDK_INCLUDEDIR@/arpa +arpa_nobase_include_HEADERS = arpa/inet.h -XPRINTF_OBJS = vxprintf.o _xprintf.o __sout.o vsnprintf.o snprintf.o vsprintf.o sprintf.o \ - __mout.o mprintf.o vmprintf.o __fout.o fprintf.o vfprintf.o printf.o vprintf.o putchar.o \ - asprintf.o vasprintf.o +sys_nobase_includedir = @PSPSDK_INCLUDEDIR@/sys +sys_nobase_include_HEADERS = sys/socket.h sys/ioctl.h -STDIO_OBJS = clearerr.o fclose.o fcloseall.o feof.o ferror.o fflush.o fflushall.o fgetc.o \ - fgetpos.o fgets.o fopen.o fputc.o fputs.o fread.o fseek.o fsetpos.o ftell.o fwrite.o fileno.o \ - getc.o getchar.o getfdtype.o gets.o perror.o putc.o puts.o remove.o rename.o fdopen.o \ - rewind.o skipatoi.o sscanf.o _stdio.o tmpfile.o tmpnam.o ungetc.o updatestdoutxy.o strerror.o \ - __stdio_internals.o +libpsplibc_a_SOURCES = \ + cwd.o \ + errno.o \ + fdman.c \ + glue.c \ + init.c \ + netdb.c \ + pipe.c \ + select.c \ + sleep.c \ + socket.c \ + terminate.c \ + timezone.c -STDLIB_OBJS = abs.o atexit.o atof.o bsearch.o div.o exit.o getenv.o _itoa.o labs.o \ - ldiv.o llabs.o lldiv.o _lltoa.o _ltoa.o rand.o setenv.o srand.o \ - strtod.o strtol.o strtoul.o __assert_fail.o \ - __stdlib_internals.o +libpsplibc_a_LIBADD = $(CWD_OBJS) $(ERRNO_OBJS) $(FDMAN_OBJS) $(INIT_OBJS) $(GLUE_OBJS) $(MUTEXMAN_OBJS) $(NETDB_OBJS) $(PIPE_OBJS) \ + $(SELECT_OBJS) $(SOCKET_OBJS) $(SLEEP_OBJS) $(TERMINATE_OBJS) $(TIMEZONE_OBJS) -## Use a few functions from libpspglue.a. -GLUE_OBJS = glue__exit.o glue__sbrk.o glue_clock.o glue_gettimeofday.o glue_time.o glue___errno.o +$(CWD_OBJS): cwd.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ -MULT_OBJS = $(XPRINTF_OBJS) $(ALLOC_OBJS) $(STRING_C_OBJS) $(STDIO_OBJS) $(STDLIB_OBJS) $(GLUE_OBJS) +$(ERRNO_OBJS): errno.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ -libpsplibcincludedir = @PSPSDK_INCLUDEDIR@/libc -libpsplibcinclude_HEADERS = assert.h ctype.h malloc.h stdio.h stdlib.h string.h time.h unistd.h -libpsplibc_a_SOURCES = $(CORE_SOURCES) $(MULT_SOURCES) -libpsplibc_a_LIBADD = $(MULT_OBJS) +$(FDMAN_OBJS): fdman.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ -$(XPRINTF_OBJS): xprintf.c - $(AM_V_CPPAS)$(CPPASCOMPILE) -DF_$* $< -c -o $@ +$(INIT_OBJS): init.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ -$(ALLOC_OBJS): alloc.c - $(AM_V_CPPAS)$(CPPASCOMPILE) -DF_$* $< -c -o $@ +$(GLUE_OBJS): glue.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ -$(STRING_C_OBJS): string.c - $(AM_V_CPPAS)$(CPPASCOMPILE) -DF_$* $< -c -o $@ +$(MUTEXMAN_OBJS): mutexman.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ -$(STDIO_OBJS): stdio.c - $(AM_V_CPPAS)$(CPPASCOMPILE) -DF_$* $< -c -o $@ +$(NETDB_OBJS): netdb.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ -$(STDLIB_OBJS): stdlib.c - $(AM_V_CPPAS)$(CPPASCOMPILE) -DF_$* $< -c -o $@ +$(PIPE_OBJS): pipe.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ -$(GLUE_OBJS): libcglue.c - $(AM_V_CPPAS)$(CPPASCOMPILE) -DF_$* $< -c -o $@ +$(SELECT_OBJS): select.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ + +$(SLEEP_OBJS): sleep.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ + +$(SOCKET_OBJS): socket.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ + +$(TERMINATE_OBJS): terminate.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ + +$(TIMEZONE_OBJS): timezone.c + $(AM_V_CC)$(COMPILE) -DF_$* $< -c -o $@ diff --git a/src/libc/alloc.c b/src/libc/alloc.c deleted file mode 100644 index b2123c83..00000000 --- a/src/libc/alloc.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * alloc.c - Standard C library heap allocation routines. - * - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ -/* This code is based on code contributed by Philip Joaqiun (jenova0). */ -#include -#include -#include -#include -#ifdef DEBUG_ALLOC -#include -#endif - -/* Use this to set the default malloc() alignment. */ -#define DEFAULT_ALIGNMENT 16 - -#ifndef ALIGN -#define ALIGN(x, align) (((x)+((align)-1))&~((align)-1)) -#endif - -#ifdef DEBUG_ALLOC -#define ALLOC_MAGIC 0xa110ca73 -#endif - -extern void * _sbrk(ptrdiff_t incr); - -void _pspsdk_alloc_init(); -void _pspsdk_alloc_deinit(); -void _pspsdk_alloc_lock(); -void _pspsdk_alloc_unlock(); - -#ifdef F___alloc_internals -/*static vs32 alloc_sema = -1;*/ -void _pspsdk_alloc_init() -{ -/* ee_sema_t alloc_sema_struct;*/ -/* alloc_sema_struct.init_count = 1;*/ -/* alloc_sema_struct.max_count = 1;*/ -/* alloc_sema = CreateSema(&alloc_sema_struct);*/ -} - -void _pspsdk_alloc_deinit() -{ -/* if (alloc_sema >= 0) {*/ -/* DeleteSema(alloc_sema);*/ -/* }*/ -} - -void _pspsdk_alloc_lock() -{ -/* if (alloc_sema >= 0) {*/ -/* WaitSema(alloc_sema);*/ -/* }*/ -} - -void _pspsdk_alloc_unlock() -{ -/* if (alloc_sema >= 0) {*/ -/* SignalSema(alloc_sema);*/ -/* }*/ -} -#endif - -/* _heap_mem_block_header structure. */ -typedef struct _heap_mem_header { -#ifdef DEBUG_ALLOC - u32 magic; -#endif - void * ptr; - size_t size; - struct _heap_mem_header * prev; - struct _heap_mem_header * next; -} heap_mem_header_t; - -extern void * __alloc_heap_base; -extern heap_mem_header_t *__alloc_heap_head; -extern heap_mem_header_t *__alloc_heap_tail; - -heap_mem_header_t * _heap_mem_fit(heap_mem_header_t *head, size_t size); - -#ifdef F_malloc - -void * __alloc_heap_base = NULL; -heap_mem_header_t *__alloc_heap_head = NULL; -heap_mem_header_t *__alloc_heap_tail = NULL; - -/* Find a the lowest block that we can allocate AFTER, returning NULL if there - are none. */ -heap_mem_header_t * _heap_mem_fit(heap_mem_header_t *head, size_t size) -{ - heap_mem_header_t *prev_mem = head; - u32 prev_top, next_bot; - - while (prev_mem != NULL) { - if (prev_mem->next != NULL) { - prev_top = (u32)prev_mem->ptr + prev_mem->size; - next_bot = (u32)prev_mem->next - prev_top; - if (next_bot >= size) - return prev_mem; - } - - prev_mem = prev_mem->next; - } - - return prev_mem; -} - -__attribute__((weak)) -void * malloc(size_t size) -{ - void *ptr = NULL, *mem_ptr; - heap_mem_header_t *new_mem, *prev_mem; - size_t mem_sz, heap_align_bytes; - - mem_sz = size + sizeof(heap_mem_header_t); - - if ((mem_sz & (DEFAULT_ALIGNMENT - 1)) != 0) - mem_sz = ALIGN(mem_sz, DEFAULT_ALIGNMENT); - - _pspsdk_alloc_lock(); - - /* If we don't have any allocated blocks, reserve the first block from - the OS and initialize __alloc_heap_tail. */ - if (__alloc_heap_head == NULL) { - /* Align the bottom of the heap to our default alignment. */ - if (__alloc_heap_base == NULL) { - heap_align_bytes = (u32) _sbrk(0) & (DEFAULT_ALIGNMENT - 1); - _sbrk(heap_align_bytes); - __alloc_heap_base = _sbrk(0); - } - - /* Allocate the physical heap and setup the head block. */ - if ((mem_ptr = _sbrk(mem_sz)) == (void *)-1) - return ptr; /* NULL */ - - ptr = (void *)((u32)mem_ptr + sizeof(heap_mem_header_t)); - - __alloc_heap_head = (heap_mem_header_t *)mem_ptr; -#ifdef DEBUG_ALLOC - __alloc_heap_head->magic = ALLOC_MAGIC; -#endif - __alloc_heap_head->ptr = ptr; - __alloc_heap_head->size = mem_sz - sizeof(heap_mem_header_t); - __alloc_heap_head->prev = NULL; - __alloc_heap_head->next = NULL; - - __alloc_heap_tail = __alloc_heap_head; - - _pspsdk_alloc_unlock(); - return ptr; - } - - /* Check to see if there's free space at the bottom of the heap. */ - if ((__alloc_heap_base + mem_sz) < (void *)__alloc_heap_head) { - new_mem = (heap_mem_header_t *)__alloc_heap_base; - ptr = (void *)((u32)new_mem + sizeof(heap_mem_header_t)); - -#ifdef DEBUG_ALLOC - new_mem->magic = ALLOC_MAGIC; -#endif - new_mem->ptr = ptr; - new_mem->size = mem_sz - sizeof(heap_mem_header_t); - new_mem->prev = NULL; - new_mem->next = __alloc_heap_head; - new_mem->next->prev = new_mem; - __alloc_heap_head = new_mem; - - _pspsdk_alloc_unlock(); - return ptr; - } - - /* See if we can allocate the block without extending the heap. */ - prev_mem = _heap_mem_fit(__alloc_heap_head, mem_sz); - if (prev_mem != NULL) { - new_mem = (heap_mem_header_t *)((u32)prev_mem->ptr + prev_mem->size); - ptr = (void *)((u32)new_mem + sizeof(heap_mem_header_t)); - -#ifdef DEBUG_ALLOC - new_mem->magic = ALLOC_MAGIC; -#endif - new_mem->ptr = ptr; - new_mem->size = mem_sz - sizeof(heap_mem_header_t); - new_mem->prev = prev_mem; - new_mem->next = prev_mem->next; - new_mem->next->prev = new_mem; - prev_mem->next = new_mem; - - _pspsdk_alloc_unlock(); - return ptr; - } - - /* Extend the heap, but make certain the block is inserted in - order. */ - if ((mem_ptr = _sbrk(mem_sz)) == (void *)-1) { - _pspsdk_alloc_unlock(); - return ptr; /* NULL */ - } - - ptr = (void *)((u32)mem_ptr + sizeof(heap_mem_header_t)); - - new_mem = (heap_mem_header_t *)mem_ptr; -#ifdef DEBUG_ALLOC - new_mem->magic = ALLOC_MAGIC; -#endif - new_mem->ptr = ptr; - new_mem->size = mem_sz - sizeof(heap_mem_header_t); - new_mem->prev = __alloc_heap_tail; - new_mem->next = NULL; - - __alloc_heap_tail->next = new_mem; - __alloc_heap_tail = new_mem; - - _pspsdk_alloc_unlock(); - return ptr; -} -#endif - -#ifdef F_realloc -__attribute__((weak)) -void * realloc(void *ptr, size_t size) -{ - heap_mem_header_t *prev_mem; - void *new_ptr = NULL; - - if (!size && ptr != NULL) { - free(ptr); - return new_ptr; - } - - if (ptr == NULL) - return malloc(size); - - if ((size & (DEFAULT_ALIGNMENT - 1)) != 0) - size = ALIGN(size, DEFAULT_ALIGNMENT); - - _pspsdk_alloc_lock(); - prev_mem = (heap_mem_header_t *)((u32)ptr - sizeof(heap_mem_header_t)); - -#ifdef DEBUG_ALLOC - if (prev_mem->magic != ALLOC_MAGIC) { - fprintf(stderr, "realloc: Pointer at %p was not malloc()ed before, or got overwritten.\n", ptr); - - _pspsdk_alloc_unlock(); - return NULL; - } -#endif - - /* Don't do anything if asked for same sized block. */ - /* If the new size is shorter, let's just shorten the block. */ - if (prev_mem->size >= size) { - /* However, if this is the last block, we have to shrink the heap. */ - if (!prev_mem->next) - _sbrk(ptr + size - _sbrk(0)); - prev_mem->size = size; - - _pspsdk_alloc_unlock(); - return ptr; - } - - - /* We are asked for a larger block of memory. */ - - /* Are we the last memory block ? */ - if (!prev_mem->next) { - /* Yes, let's just extend the heap then. */ - if (_sbrk(size - prev_mem->size) == (void*) -1) - return NULL; - prev_mem->size = size; - - _pspsdk_alloc_unlock(); - return ptr; - } - - /* Is the next block far enough so we can extend the current block ? */ - if ((prev_mem->next->ptr - ptr) > size) { - prev_mem->size = size; - - _pspsdk_alloc_unlock(); - return ptr; - } - - _pspsdk_alloc_unlock(); - - /* We got out of luck, let's allocate a new block of memory. */ - if ((new_ptr = malloc(size)) == NULL) - return new_ptr; - - /* New block is larger, we only copy the old data. */ - memcpy(new_ptr, ptr, prev_mem->size); - - free(ptr); - return new_ptr; -} -#endif - -#ifdef F_calloc -__attribute__((weak)) -void * calloc(size_t n, size_t size) -{ - void *ptr = NULL; - size_t sz = n * size; - - if ((ptr = malloc(sz)) == NULL) - return ptr; - - memset(ptr, 0, sz); - return ptr; -} -#endif - -#ifdef F_memalign -__attribute__((weak)) -void * memalign(size_t align, size_t size) -{ - heap_mem_header_t new_mem; - heap_mem_header_t *cur_mem; - heap_mem_header_t *old_mem; - void *ptr = NULL; - - if (align <= DEFAULT_ALIGNMENT) - return malloc(size); - - /* Allocate with extra alignment bytes just in case it isn't aligned - properly by malloc. */ - if ((ptr = malloc(size + align)) == NULL) - return ptr; /* NULL */ - - /* If malloc returned it aligned for us we're fine. */ - if (((u32)ptr & (align - 1)) == 0) - return ptr; - - _pspsdk_alloc_lock(); - cur_mem = (heap_mem_header_t *)((u32)ptr - sizeof(heap_mem_header_t)); - cur_mem->size -= align; - - /* Otherwise, align the pointer and fixup our hearder accordingly. */ - ptr = (void *)ALIGN((u32)ptr, align); - - old_mem = cur_mem; - - /* Copy the heap_mem_header_t locally, before repositioning (to make - sure we don't overwrite ourselves. */ - memcpy(&new_mem, cur_mem, sizeof(heap_mem_header_t)); - cur_mem = (heap_mem_header_t *)((u32)ptr - sizeof(heap_mem_header_t)); - memcpy(cur_mem, &new_mem, sizeof(heap_mem_header_t)); - - if (cur_mem->prev) - cur_mem->prev->next = cur_mem; - if (cur_mem->next) - cur_mem->next->prev = cur_mem; - - if (__alloc_heap_head == old_mem) - __alloc_heap_head = cur_mem; - - if (__alloc_heap_tail == old_mem) - __alloc_heap_tail = cur_mem; - - cur_mem->ptr = ptr; - - _pspsdk_alloc_unlock(); - return ptr; -} -#endif - -#ifdef F_free -__attribute__((weak)) -void free(void *ptr) -{ - heap_mem_header_t *cur; - void *heap_top; - size_t size; - - if (!ptr) - return; - - _pspsdk_alloc_lock(); - - if (!__alloc_heap_head) { - _pspsdk_alloc_unlock(); - return; - } - -#ifdef DEBUG_ALLOC - cur = (heap_mem_header_t *)((u32)ptr - sizeof(heap_mem_header_t)); - if (cur->magic != ALLOC_MAGIC) { - fprintf(stderr, "free: Pointer at %p was not malloc()ed before, or got overwritten.\n", ptr); - - _pspsdk_alloc_unlock(); - return; - } -#endif - - /* Freeing the head pointer is a special case. */ - if (ptr == __alloc_heap_head->ptr) { - size = __alloc_heap_head->size + - (size_t)(__alloc_heap_head->ptr - (void *)__alloc_heap_head); - - __alloc_heap_head = __alloc_heap_head->next; - - if (__alloc_heap_head != NULL) { - __alloc_heap_head->prev = NULL; - } else { - __alloc_heap_tail = NULL; - - _sbrk(-size); - } - - _pspsdk_alloc_unlock(); - return; - } - - cur = __alloc_heap_head; - while (ptr != cur->ptr) { - /* ptr isn't in our list */ - if (cur->next == NULL) { - _pspsdk_alloc_unlock(); - return; - } - - cur = cur->next; - } - - /* Deallocate the block. */ - if (cur->next != NULL) { - cur->next->prev = cur->prev; - } else { - /* If this block was the last one in the list, shrink the heap. */ - __alloc_heap_tail = cur->prev; - - /* We need to free (heap top) - (prev->ptr + prev->size), or else - we'll end up with an unallocatable block of heap. */ - heap_top = _sbrk(0); - size = (u32)heap_top - (u32)(cur->prev->ptr + cur->prev->size); - _sbrk(-size); - } - - cur->prev->next = cur->next; - - _pspsdk_alloc_unlock(); -} -#endif - -/* These are here in case C++ needs them. */ -#ifdef F___builtin_alloc -__attribute__((weak)) -void * __builtin_new(size_t size) { return malloc(size); } - -__attribute__((weak)) -void __builtin_delete(void *ptr) { free(ptr); } -#endif - -#ifdef F___mem_walk -void * __mem_walk_begin() { - return __alloc_heap_head; -} - -void __mem_walk_read(void * token, u32 * size, void ** ptr, int * valid) { - heap_mem_header_t * cur = (heap_mem_header_t *) token; - -#ifdef DEBUG_ALLOC - if (cur->magic != ALLOC_MAGIC) { - *valid = 0; - return; - } -#endif - *valid = 1; - - *size = cur->size; - *ptr = cur->ptr; -} - -void * __mem_walk_inc(void * token) { - heap_mem_header_t * cur = (heap_mem_header_t *) token; - - return cur->next; -} - -int __mem_walk_end(void * token) { - return token == NULL; -} -#endif diff --git a/src/libc/arpa/inet.h b/src/libc/arpa/inet.h new file mode 100644 index 00000000..f441b9cb --- /dev/null +++ b/src/libc/arpa/inet.h @@ -0,0 +1,26 @@ +/* arpa/inet.h - Functions for converting IP addresses between strings and numbers */ + +#ifndef _ARPA_INET_H_ +#define _ARPA_INET_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +in_addr_t sceNetInetInetAddr(const char *ip); +int sceNetInetInetAton(const char *ip, struct in_addr *in); +const char* sceNetInetInetNtop(int af, const void *src, char *dst, socklen_t cnt); +int sceNetInetInetPton(int af, const char *src, void *dst); + +char *inet_ntoa(struct in_addr in); +#define inet_addr sceNetInetInetAddr +#define inet_aton sceNetInetInetAton +#define inet_ntop sceNetInetInetNtop +#define inet_pton sceNetInetInetPton + +#ifdef __cplusplus +} +#endif +#endif /* _ARPA_INET_H_ */ diff --git a/src/libc/assert.h b/src/libc/assert.h deleted file mode 100644 index 1cf4b482..00000000 --- a/src/libc/assert.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * assert.h - * - * Copyright (c) 2002-2004 PS2DEV - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ -#ifndef __ASSERT_H__ -#define __ASSERT_H__ - -#include -#include - -#ifdef NDEBUG -#define assert(cond) -#else -#ifdef __cplusplus -extern "C" { -#endif - int __assert_fail (const char *assertion, const char *file, unsigned int line) __attribute__((noreturn)); -#ifdef __cplusplus -} -#endif -#define assert(cond) (void)((cond)?0:__assert_fail(#cond, __FILE__, __LINE__)) -#endif - -#endif diff --git a/src/libc/ctype.h b/src/libc/ctype.h deleted file mode 100644 index e6a56551..00000000 --- a/src/libc/ctype.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * ctype.h - * - * Copyright (c) 2002-2004 PS2DEV - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ - -#ifndef __CTYPE_H__ -#define __CTYPE_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -int isalnum(int); -int isalpha(int); -int iscntrl(int); -int isdigit(int); -int isgraph(int); -int islower(int); -int isprint(int); -int ispunct(int); -int isspace(int); -int isupper(int); -int isxdigit(int); -int tolower(int); -int toupper(int); - -#ifdef __cplusplus -} - - -/* To be compatible with C++'s ctype_base.h */ - -namespace std { - enum { - _U = 01, - _L = 02, - _N = 04, - _S = 010, - _P = 020, - _C = 040, - _X = 0100, - _B = 0200 - }; -}; -#endif - -#endif diff --git a/src/libc/cwd.c b/src/libc/cwd.c new file mode 100644 index 00000000..17bf3471 --- /dev/null +++ b/src/libc/cwd.c @@ -0,0 +1,192 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * init.c - The global init/deinit code for our crt0. + * + * Copyright (c) 2005 Marcus R. Brown + * Copyright (c) 2005 James Forshaw + * Copyright (c) 2005 John Kelley + * + */ + +#include +#include +#include +#include +#include +#include + +#ifdef F___cwd +/* the present working directory variable. */ +char __cwd[MAXNAMLEN + 1] = { 0 }; +#else +extern char __cwd[MAXNAMLEN + 1]; +#endif + +#ifdef F_getcwd +char *getcwd(char *buf, size_t size) +{ + if(!buf) { + errno = EINVAL; + return NULL; + } + + if(strlen(__cwd) >= size) { + errno = ERANGE; + return NULL; + } + + strcpy(buf, __cwd); + return buf; +} +#endif + +#ifdef F___path_absolute +/* Like strcpy, but returns 0 if the string doesn't fit */ +static int __safe_strcpy(char *out, const char *in, int maxlen) +{ + for( ; maxlen > 0 && *in ; maxlen-- ) + *(out++) = *(in++); + if(maxlen < 1) return 0; + *out = 0; + return 1; +} + +/* Like strcat, but returns 0 if the string doesn't fit */ +static int __safe_strcat(char *out, const char *in, int maxlen) +{ + for( ; *out ; out++,maxlen-- ) + continue; + return __safe_strcpy(out, in, maxlen); +} + +/* Normalize a pathname (without leading "drive:") by removing + . and .. components, duplicated /, etc. */ +static int __path_normalize(char *out, int len) +{ + int i, j; + int first, next; + + /* First append "/" to make the rest easier */ + if(!__safe_strcat(out,"/",len)) return -10; + + /* Convert "//" to "/" */ + for(i=0; out[i+1]; i++) { + if(out[i]=='/' && out[i+1]=='/') { + for(j=i+1; out[j]; j++) + out[j] = out[j+1]; + i--; + } + } + + /* Convert "/./" to "/" */ + for(i=0; out[i] && out[i+1] && out[i+2]; i++) { + if(out[i]=='/' && out[i+1]=='.' && out[i+2]=='/') { + for(j=i+1; out[j]; j++) + out[j] = out[j+2]; + i--; + } + } + + /* Convert "/asdf/../" to "/" until we can't anymore. Also + * convert leading "/../" to "/" */ + first = next = 0; + while(1) { + /* If a "../" follows, remove it and the parent */ + if(out[next+1] && out[next+1]=='.' && + out[next+2] && out[next+2]=='.' && + out[next+3] && out[next+3]=='/') { + for(j=0; out[first+j+1]; j++) + out[first+j+1] = out[next+j+4]; + first = next = 0; + continue; + } + + /* Find next slash */ + first = next; + for(next=first+1; out[next] && out[next] != '/'; next++) + continue; + if(!out[next]) break; + } + + /* Remove trailing "/" */ + for(i=1; out[i]; i++) + continue; + if(i >= 1 && out[i-1] == '/') + out[i-1] = 0; + + return 0; +} + +/* Return the number of bytes taken up by the "drive:" prefix, + or -1 if it's not found */ +static int __get_drive(const char *d) +{ + int i; + for(i=0; d[i]; i++) { + if(! ((d[i] >= 'a' && d[i] <= 'z') || + (d[i] >= '0' && d[i] <= '9') )) + break; + } + if(d[i] == ':') return i+1; + return -1; +} + +/* Convert relative path to absolute path. */ +int __path_absolute(const char *in, char *out, int len) +{ + int dr; + + /* See what the relative URL starts with */ + dr = __get_drive(in); + if(dr > 0 && in[dr] == '/') { + /* It starts with "drive:/", so it's already absolute */ + if(!__safe_strcpy(out, in, len)) + return -1; + } else if(in[0] == '/') { + /* It's absolute, but missing the drive, so use cwd's drive */ + if(strlen(__cwd) >= len) + return -2; + strcpy(out, __cwd); + dr = __get_drive(out); + out[dr] = 0; + if(!__safe_strcat(out, in, len)) + return -3; + } else { + /* It's not absolute, so append it to the current cwd */ + if(strlen(__cwd) >= len) + return -4; + strcpy(out, __cwd); + if(!__safe_strcat(out, "/", len)) + return -6; + if(!__safe_strcat(out, in, len)) + return -7; + } + + /* Now normalize the pathname portion */ + dr = __get_drive(out); + if(dr < 0) dr = 0; + return __path_normalize(out + dr, len - dr); +} +#endif + +#ifdef F___init_cwd +/* Set the current working directory (CWD) to the path where the module was launched. */ +void __init_cwd(char *argv_0) +{ + if (argv_0 != NULL) { + char base_path[MAXPATHLEN + 1]; + char *end; + + strncpy(base_path, argv_0, sizeof(base_path) - 1); + base_path[sizeof(base_path) - 1] = '\0'; + end = strrchr(base_path, '/'); + if (end != NULL) { + *(end + 1) = '\0'; + chdir(base_path); + } + } +} +#endif \ No newline at end of file diff --git a/src/libc/cxx.cpp b/src/libc/cxx.cpp deleted file mode 100644 index 76f98b6e..00000000 --- a/src/libc/cxx.cpp +++ /dev/null @@ -1,49 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * cxx.cpp - Simple C++ memory allocation operators. - * - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ -#include -#include - -__attribute__((weak)) -void operator delete(void *ptr) -{ - if (ptr) - { - free(ptr); - } -} - -__attribute__((weak)) -void* operator new(size_t len) -{ - return malloc(len); -} - -__attribute__((weak)) -void operator delete[](void *ptr) -{ - ::operator delete(ptr); -} - -__attribute__((weak)) -void* operator new[](size_t len) -{ - return ::operator new(len); -} - -extern "C" -__attribute__((weak)) -void __cxa_pure_virtual() -{ - /* perror("Pure virtual method called"); */ - abort(); -} diff --git a/src/libc/unistd.h b/src/libc/errno.c similarity index 64% rename from src/libc/unistd.h rename to src/libc/errno.c index ade53982..fabbcf47 100644 --- a/src/libc/unistd.h +++ b/src/libc/errno.c @@ -3,18 +3,24 @@ * ----------------------------------------------------------------------- * Licensed under the BSD license, see LICENSE in PSPSDK root for details. * - * unistd.h + * init.c - The global init/deinit code for our crt0. * - * Copyright (c) 2002-2004 PS2DEV * Copyright (c) 2005 Marcus R. Brown * Copyright (c) 2005 James Forshaw * Copyright (c) 2005 John Kelley * */ -#ifndef __UNISTD_H__ -#define __UNISTD_H__ - #include +#include -#endif +#ifdef F___set_errno +int __set_errno(int code) +{ + if ((code & 0x80010000) == 0x80010000) { + errno = code & 0xFFFF; + return -1; + } + return code; +} +#endif \ No newline at end of file diff --git a/src/libc/fdman.c b/src/libc/fdman.c new file mode 100644 index 00000000..feede236 --- /dev/null +++ b/src/libc/fdman.c @@ -0,0 +1,142 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * fdman.c - Manager for fd. + * + * Copyright (c) 2021 Francisco Javier Trujillo Mata + * + */ + +#include +#include +#include + +#include +#include +#include + +#include "fdman.h" + +/* Functions from mutexman.c */ +extern SceLwMutexWorkarea __fdman_mutex; + +#ifdef F___descriptor_data_pool +__descriptormap_type __descriptor_data_pool[__FILENO_MAX]; +#else +extern __descriptormap_type __descriptor_data_pool[__FILENO_MAX]; +#endif + +#ifdef F___descriptormap +__descriptormap_type *__descriptormap[__FILENO_MAX]; +#else +extern __descriptormap_type *__descriptormap[__FILENO_MAX]; +#endif + + +#ifdef F___fdman_init +void __fdman_init() +{ + int scefd; + + /* Initialize descriptor data*/ + memset(__descriptor_data_pool, 0, sizeof(__descriptormap_type) *__FILENO_MAX); + /* Initialize descriptor map*/ + memset(__descriptormap, 0, sizeof(__descriptormap_type*)*__FILENO_MAX); + + scefd = sceKernelStdin(); + if (scefd >= 0) { + __descriptormap[0] = &__descriptor_data_pool[0]; + __descriptormap[0]->descriptor = scefd; + __descriptormap[0]->type = __DESCRIPTOR_TYPE_TTY; + } + scefd = sceKernelStdout(); + if (scefd >= 0) { + __descriptormap[1] = &__descriptor_data_pool[1]; + __descriptormap[1]->descriptor = scefd; + __descriptormap[1]->type = __DESCRIPTOR_TYPE_TTY; + } + scefd = sceKernelStderr(); + if (scefd >= 0) { + __descriptormap[2] = &__descriptor_data_pool[2]; + __descriptormap[2]->descriptor = scefd; + __descriptormap[2]->type = __DESCRIPTOR_TYPE_TTY; + } +} +#endif + + +#ifdef F___fdman_get_new_descriptor +int __fdman_get_new_descriptor() +{ + int i = 0; + + sceKernelLockLwMutex(&__fdman_mutex, 1, 0); /* lock here to make thread safe */ + for (i = 0; i < __FILENO_MAX; i++) { + if (__descriptormap[i] == NULL) { + __descriptormap[i] = &__descriptor_data_pool[i]; + __descriptormap[i]->ref_count++; + sceKernelUnlockLwMutex(&__fdman_mutex, 1);; /* release lock */ + return i; + } + } + sceKernelUnlockLwMutex(&__fdman_mutex, 1);; /* release lock */ + + errno = ENOMEM; + return -1; +} +#endif + + +#ifdef F___fdman_get_dup_descriptor +int __fdman_get_dup_descriptor(int fd) +{ + int i = 0; + + if (!__IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + sceKernelLockLwMutex(&__fdman_mutex, 1, 0); /* lock here to make thread safe */ + for (i = 0; i < __FILENO_MAX; i++) { + if (__descriptormap[i] == NULL) { + __descriptormap[i] = &__descriptor_data_pool[fd]; + __descriptormap[i]->ref_count++; + sceKernelUnlockLwMutex(&__fdman_mutex, 1);; /* release lock */ + return i; + } + } + sceKernelUnlockLwMutex(&__fdman_mutex, 1);; /* release lock */ + + errno = ENOMEM; + return -1; +} +#endif + + +#ifdef F___fdman_release_descriptor +void __fdman_release_descriptor(int fd) +{ + if (!__IS_FD_VALID(fd)) { + errno = EBADF; + return; + } + + __descriptormap[fd]->ref_count--; + + if (__descriptormap[fd]->ref_count == 0) { + + if (__descriptormap[fd]->filename != NULL) { + free(__descriptormap[fd]->filename); + } + __descriptormap[fd]->filename = NULL; + __descriptormap[fd]->descriptor = 0; + __descriptormap[fd]->type = 0; + __descriptormap[fd]->flags = 0; + + } + __descriptormap[fd] = NULL; +} +#endif \ No newline at end of file diff --git a/src/libc/fdman.h b/src/libc/fdman.h new file mode 100644 index 00000000..f2de1156 --- /dev/null +++ b/src/libc/fdman.h @@ -0,0 +1,48 @@ +/* + * PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * fdman.h - File descriptor management. + * + * Copyright (c) 2006 Rafael Cabezas + */ + +#ifndef _FDMAN_H_ + +#include + +#define _FDMAN_H_ + +#define __FILENO_MAX 1024 + +#define __IS_FD_VALID(FD) \ + ( (FD >= 0) && (FD < __FILENO_MAX) && (__descriptormap[FD] != NULL) ) + +#define __IS_FD_OF_TYPE(FD, TYPE) \ + ( (__IS_FD_VALID(FD)) && (__descriptormap[FD]->type == TYPE) ) + +typedef enum { + __DESCRIPTOR_TYPE_FILE, + __DESCRIPTOR_TYPE_FOLDER, + __DESCRIPTOR_TYPE_PIPE, + __DESCRIPTOR_TYPE_SOCKET, + __DESCRIPTOR_TYPE_TTY +} __fdman_fd_types; + +typedef struct { + u_int32_t descriptor; + u_int32_t flags; + u_int32_t ref_count; + char *filename; + u_int8_t type; +} __descriptormap_type; + +extern __descriptormap_type *__descriptormap[__FILENO_MAX]; + +void __fdman_init(); +int __fdman_get_new_descriptor(); +int __fdman_get_dup_descriptor(int fd); +void __fdman_release_descriptor(int fd); + +#endif diff --git a/src/libc/glue.c b/src/libc/glue.c new file mode 100644 index 00000000..d58bac7d --- /dev/null +++ b/src/libc/glue.c @@ -0,0 +1,865 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * libcglue.c - Newlib-compatible system calls. + * + * Copyright (c) 2005 Marcus R. Brown + * Copyright (c) 2005 James Forshaw + * Copyright (c) 2005 John Kelley + * Copyright (c) 2005 Jim Paris + * Copyright (c) 2021 Francisco J Trujillo + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "fdman.h" + +#define DEFAULT_PRX_HEAP_SIZE_KB 64 +#define DEFAULT_HEAP_THRESHOLD_SIZE_KB 512 + +/* If defined it specifies the desired size of the heap, in KB. */ +extern unsigned int sce_newlib_heap_kb_size __attribute__((weak)); +extern unsigned int sce_newlib_heap_threshold_kb_size __attribute__((weak)); +extern int __pspsdk_is_prx __attribute__((weak)); + +/* Functions from cwd.c */ +extern char __cwd[MAXNAMLEN + 1]; +int __path_absolute(const char *in, char *out, int len); + +/* Functions from mutexman.c */ +extern SceLwMutexWorkarea __malloc_mutex; +extern SceLwMutexWorkarea __sbrk_mutex; + +/* Fuctions from errno.c */ +int __set_errno(int code); + +/* Functions from pipe.c */ +int __pipe_read(int fd, void *buf, size_t len); +int __pipe_close(int fd); +int __pipe_write(int fd, const void *buf, size_t len); +int __pipe_nonblocking_read(int fd, void *buf, size_t len); +int __pipe_nonblocking_write(int fd, const void *buf, size_t len); + +/* Functions from socket.c */ +int __socket_close(int sock); + +#ifdef F___fill_stat +static time_t psp_to_posix_time(ScePspDateTime psp_time) +{ + struct tm conv_time; + conv_time.tm_year = psp_time.year; + conv_time.tm_mon = psp_time.month; + conv_time.tm_mday = psp_time.day; + conv_time.tm_hour = psp_time.hour; + conv_time.tm_min = psp_time.minute; + conv_time.tm_sec = psp_time.second; + conv_time.tm_isdst = -1; + return mktime(&conv_time); +} + +static mode_t io_to_posix_mode(SceMode sceMode) +{ + mode_t posixmode = 0; + if (sceMode & FIO_SO_IFREG) posixmode |= S_IFREG; + if (sceMode & FIO_SO_IFDIR) posixmode |= S_IFDIR; + if (sceMode & FIO_SO_IROTH) posixmode |= S_IRUSR|S_IRGRP|S_IROTH; + if (sceMode & FIO_SO_IWOTH) posixmode |= S_IWUSR|S_IWGRP|S_IWOTH; + if (sceMode & FIO_SO_IXOTH) posixmode |= S_IXUSR|S_IXGRP|S_IXOTH; + return posixmode; +} + + +void __fill_stat(struct stat *stat, const SceIoStat *sce_stat) +{ + stat->st_dev = 0; + stat->st_ino = 0; + stat->st_mode = io_to_posix_mode(sce_stat->st_attr); + stat->st_nlink = 0; + stat->st_uid = 0; + stat->st_gid = 0; + stat->st_rdev = 0; + stat->st_size = sce_stat->st_size; + stat->st_atime = psp_to_posix_time(sce_stat->sce_st_atime); + stat->st_mtime = psp_to_posix_time(sce_stat->sce_st_mtime); + stat->st_ctime = psp_to_posix_time(sce_stat->sce_st_ctime); + stat->st_blksize = 16*1024; + stat->st_blocks = stat->st_size / 512; +} +#else +void __fill_stat(struct stat *stat, const SceIoStat *sce_stat); +#endif + +#ifdef F___psp_heap_blockid +/* UID of the memory block that represents the heap. */ +SceUID __psp_heap_blockid; +#else +extern SceUID __psp_heap_blockid; +#endif + +#ifdef F___psp_free_heap +/* Free the heap. */ +int __psp_free_heap(void) +{ + if (__psp_heap_blockid > 0) { + return sceKernelFreePartitionMemory(__psp_heap_blockid); + } + + return __psp_heap_blockid; +} +#endif + +#ifdef F__open +int _open(const char *buf, int flags, int mode) { + int scefd, fd, sce_flags, is_dir; + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(buf, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + is_dir = 0; + /* O_RDONLY starts at 0, where PSP_O_RDONLY starts at 1, so remap the read/write + flags by adding 1. */ + sce_flags = (flags & O_ACCMODE) + 1; + + /* Translate standard open flags into the flags understood by the PSP kernel. */ + if (flags & O_APPEND) { + sce_flags |= PSP_O_APPEND; + } + if (flags & O_CREAT) { + sce_flags |= PSP_O_CREAT; + } + if (flags & O_TRUNC) { + sce_flags |= PSP_O_TRUNC; + } + if (flags & O_EXCL) { + sce_flags |= PSP_O_EXCL; + } + if (flags & O_NONBLOCK) { + sce_flags |= PSP_O_NBLOCK; + } + if (flags & O_DIRECTORY) { + sce_flags |= PSP_O_DIR; + is_dir = 1; + } + + scefd = is_dir ? sceIoDopen(dest) : sceIoOpen(dest, sce_flags, mode); + if (scefd >= 0) { + fd = __fdman_get_new_descriptor(); + if (fd != -1) { + __descriptormap[fd]->descriptor = scefd; + __descriptormap[fd]->type = is_dir ? __DESCRIPTOR_TYPE_FOLDER : __DESCRIPTOR_TYPE_FILE; + __descriptormap[fd]->flags = flags; + __descriptormap[fd]->filename = strdup(dest); + return fd; + } + else { + is_dir ? sceIoDclose(scefd) : sceIoClose(scefd); + errno = ENOMEM; + return -1; + } + } + else { + return __set_errno(scefd); + } +} + +#endif + +#ifdef F__close +int _close(int fd) { + int ret = 0; + + if (!__IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__descriptormap[fd]->type) + { + case __DESCRIPTOR_TYPE_FILE: + case __DESCRIPTOR_TYPE_TTY: + if (__descriptormap[fd]->ref_count == 1) { + ret = __set_errno(sceIoClose(__descriptormap[fd]->descriptor)); + } + __fdman_release_descriptor(fd); + return ret; + break; + case __DESCRIPTOR_TYPE_FOLDER: + if (__descriptormap[fd]->ref_count == 1) { + ret = __set_errno(sceIoDclose(__descriptormap[fd]->descriptor)); + } + __fdman_release_descriptor(fd); + return ret; + break; + case __DESCRIPTOR_TYPE_PIPE: + return __pipe_close(fd); + break; + case __DESCRIPTOR_TYPE_SOCKET: + return __socket_close(fd); + break; + default: + break; + } + + errno = EBADF; + return -1; +} +#endif + +#ifdef F__read +int _read(int fd, void *buf, size_t nbytes) { + if (!__IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__descriptormap[fd]->type) + { + case __DESCRIPTOR_TYPE_FILE: + case __DESCRIPTOR_TYPE_TTY: + return __set_errno(sceIoRead(__descriptormap[fd]->descriptor, buf, nbytes)); + break; + case __DESCRIPTOR_TYPE_PIPE: + if (__descriptormap[fd]->flags & O_NONBLOCK) { + return __pipe_nonblocking_read(fd, buf, nbytes); + } + else { + return __pipe_read(fd, buf, nbytes); + } + break; + case __DESCRIPTOR_TYPE_SOCKET: + return recv(fd, buf, nbytes, 0); + break; + default: + break; + } + + errno = EBADF; + return -1; +} +#endif + +#ifdef F__write +int _write(int fd, const void *buf, size_t nbytes) { + if (!__IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__descriptormap[fd]->type) + { + case __DESCRIPTOR_TYPE_FILE: + case __DESCRIPTOR_TYPE_TTY: + return __set_errno(sceIoWrite(__descriptormap[fd]->descriptor, buf, nbytes)); + break; + case __DESCRIPTOR_TYPE_PIPE: + if (__descriptormap[fd]->flags & O_NONBLOCK) { + return __pipe_nonblocking_write(fd, buf, nbytes); + } + else { + return __pipe_write(fd, buf, nbytes); + } + break; + break; + case __DESCRIPTOR_TYPE_SOCKET: + return send(fd, buf, nbytes, 0); + break; + default: + break; + } + + errno = EBADF; + return -1; +} +#endif + +#ifdef F__stat +int _stat(const char *filename, struct stat *buf) +{ + SceIoStat psp_stat; + char dest[MAXNAMLEN + 1]; + int ret; + + if(__path_absolute(filename, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + memset(buf, '\0', sizeof(struct stat)); + ret = sceIoGetstat(dest, &psp_stat); + if (ret < 0) { + return __set_errno(ret); + } + + __fill_stat(buf, &psp_stat); + return 0; +} +#else +int _stat(const char *filename, struct stat *buf); +#endif + +#ifdef F_lstat +int lstat(const char *filename, struct stat *buf) +{ + return stat(filename, buf); +} +#endif + +#ifdef F__fstat +int _fstat(int fd, struct stat *buf) { + int ret; + SceOff oldpos; + if (!__IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__descriptormap[fd]->type) + { + case __DESCRIPTOR_TYPE_TTY: + memset(buf, '\0', sizeof(struct stat)); + buf->st_mode = S_IFCHR; + return 0; + break; + case __DESCRIPTOR_TYPE_FILE: + if (__descriptormap[fd]->filename != NULL) { + ret = _stat(__descriptormap[fd]->filename, buf); + + /* Find true size of the open file */ + oldpos = sceIoLseek(__descriptormap[fd]->descriptor, 0, SEEK_CUR); + if (oldpos != (off_t) -1) { + buf->st_size = (off_t) sceIoLseek(__descriptormap[fd]->descriptor, 0, SEEK_END); + sceIoLseek(__descriptormap[fd]->descriptor, oldpos, SEEK_SET); + } + return ret; + } + break; + case __DESCRIPTOR_TYPE_PIPE: + case __DESCRIPTOR_TYPE_SOCKET: + default: + break; + } + + errno = EBADF; + return -1; +} +#endif + +#ifdef F_access +int access(const char *fn, int flags) +{ + struct stat s; + if (stat(fn, &s)) + return -1; + if (s.st_mode & S_IFDIR) + return 0; + if (flags & W_OK) + { + if (s.st_mode & S_IWRITE) + return 0; + errno = EACCES; + return -1; + } + return 0; +} +#endif + +#ifdef F__fcntl +int _fcntl(int fd, int cmd, ...) +{ + if (!__IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch (cmd) + { + case F_DUPFD: + { + return __fdman_get_dup_descriptor(fd); + break; + } + case F_GETFL: + { + return __descriptormap[fd]->flags; + break; + } + case F_SETFL: + { + int newfl; + va_list args; + + va_start (args, cmd); /* Initialize the argument list. */ + newfl = va_arg(args, int); + va_end (args); /* Clean up. */ + + __descriptormap[fd]->flags = newfl; + + switch(__descriptormap[fd]->type) + { + case __DESCRIPTOR_TYPE_FILE: + break; + case __DESCRIPTOR_TYPE_PIPE: + break; + case __DESCRIPTOR_TYPE_SOCKET: + if (newfl & O_NONBLOCK) + { + int one = 1; + return setsockopt(fd, SOL_SOCKET, SO_NONBLOCK, (char *)&one, sizeof(one)); + } + else + { + int zero = 0; + return setsockopt(fd, SOL_SOCKET, SO_NONBLOCK, (char *)&zero, sizeof(zero)); + } + break; + default: + break; + } + return 0; + break; + } + } + + errno = EBADF; + return -1; +} +#endif /* F__fcntl */ + +#ifdef F_getdents +int getdents(int fd, void *dd_buf, int count) +{ + struct dirent *dirp; + int rv, read; + SceIoDirent sceiode; + + read = 0; + // NEEDED otherwise it will crash!!! + memset(&sceiode, 0, sizeof(SceIoDirent)); + rv = sceIoDread(__descriptormap[fd]->descriptor, &sceiode); + if (rv < 0) { + return __set_errno(rv); + } else if (rv == 0) { + return read; + } + + read += sizeof(struct dirent); + dirp = (struct dirent *)dd_buf; + + dirp->d_fileno = rv; + strncpy(dirp->d_name, sceiode.d_name, MAXNAMLEN); + dirp->d_name[MAXNAMLEN] = 0; + dirp->d_reclen = count; + + return read; +} +#endif + +#ifdef F__seekdir +void _seekdir(DIR *dirp, long loc) +{ + int i; + SceUID uid; + SceIoDirent sceiode; + + if (__descriptormap[dirp->dd_fd]->filename != NULL) { + sceIoDclose(__descriptormap[dirp->dd_fd]->descriptor); + uid = sceIoDopen(__descriptormap[dirp->dd_fd]->filename); + __descriptormap[dirp->dd_fd]->descriptor = uid; + for (i = 0; i < loc; i++) { + // NEEDED otherwise it will crash!!! + memset(&sceiode, 0, sizeof(SceIoDirent)); + sceIoDread(uid, &sceiode); + } + } +} +#endif + +#ifdef F__lseek +off_t _lseek(int fd, off_t offset, int whence) +{ + if (!__IS_FD_VALID(fd)) { + errno = EBADF; + return -1; + } + + switch(__descriptormap[fd]->type) + { + case __DESCRIPTOR_TYPE_FILE: + /* We don't have to do anything with the whence argument because SEEK_* == PSP_SEEK_*. */ + return (off_t) __set_errno(sceIoLseek(__descriptormap[fd]->descriptor, offset, whence)); + break; + case __DESCRIPTOR_TYPE_PIPE: + break; + case __DESCRIPTOR_TYPE_SOCKET: + break; + default: + break; + } + + errno = EBADF; + return -1; +} +#endif + +#ifdef F_chdir +int chdir(const char *path) +{ + char dest[MAXNAMLEN + 1]; + SceUID uid; + + if(__path_absolute(path, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + /* sceIoChdir doesn't give an indication of whether it worked, + so test for existence by attempting to open the dir */ + uid = sceIoDopen(dest); + if(uid < 0) { + errno = ENOTDIR; + return -1; + } + sceIoDclose(uid); + + sceIoChdir(dest); + strcpy(__cwd, dest); + return 0; +} +#endif + +#ifdef F_mkdir +int mkdir(const char *pathname, mode_t mode) +{ + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(pathname, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __set_errno(sceIoMkdir(dest, mode)); +} +#endif + +#ifdef F_rmdir +int rmdir(const char *pathname) +{ + char dest[MAXNAMLEN + 1]; + + if(__path_absolute(pathname, dest, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __set_errno(sceIoRmdir(dest)); +} +#endif + +#ifdef F__link +int _link(const char *old, const char *new) { + errno = ENOSYS; + return -1; /* not supported */ +} +#endif + +#ifdef F__unlink +int _unlink(const char *path) { + errno = ENOSYS; + return -1; /* not supported */ +} +#endif + +#ifdef F__rename +int _rename(const char *old, const char *new) +{ + char oldname[MAXNAMLEN + 1]; + char newname[MAXNAMLEN + 1]; + + if(__path_absolute(old, oldname, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + if(__path_absolute(new, newname, MAXNAMLEN) < 0) { + errno = ENAMETOOLONG; + return -1; + } + + return __set_errno(sceIoRename(oldname, newname)); +} +#endif + +#ifdef F_getcwd +char *getcwd(char *buf, size_t len) { + strncpy(buf, __cwd, len); + return buf; +} +#endif + +#ifdef F__getpid +pid_t _getpid(void) +{ + return (pid_t)__set_errno(sceKernelGetThreadId()); +} +#endif + +#ifdef F__kill +int _kill(pid_t pid, int sig) +{ + return __set_errno(sceKernelDeleteThread((SceUID)pid)); +} +#endif + +#ifdef F__fork +pid_t _fork(void) +{ + errno = ENOSYS; + return (pid_t) -1; +} +#endif + +#ifdef F__wait +pid_t _wait(int *unused) +{ + errno = ENOSYS; + return (pid_t) -1; +} +#endif + +#ifdef F__sbrk +#define TO_KB(value) (value * 1024) +void * _sbrk(ptrdiff_t incr) +{ + static void * heap_bottom = NULL; + static void * heap_top = NULL; + static void * heap_ptr = NULL; + + sceKernelLockLwMutex(&__sbrk_mutex, 1, 0); + + /* Has our heap been initialized? */ + if (heap_bottom == NULL) { + /* No, initialize the heap. */ + SceSize heap_size = (SceSize) -1; + + if (&sce_newlib_heap_kb_size != NULL) { + heap_size = TO_KB(sce_newlib_heap_kb_size); + } else if(&__pspsdk_is_prx != NULL) { + heap_size = TO_KB(DEFAULT_PRX_HEAP_SIZE_KB); + } + + if ((int)heap_size < 0) { + heap_size = sceKernelMaxFreeMemSize(); + if(&sce_newlib_heap_threshold_kb_size != NULL) + heap_size -= TO_KB(sce_newlib_heap_threshold_kb_size); + else + heap_size -= TO_KB(DEFAULT_HEAP_THRESHOLD_SIZE_KB); + } + + if (heap_size != 0) { + __psp_heap_blockid = sceKernelAllocPartitionMemory(PSP_MEMORY_PARTITION_USER, "heap_block", PSP_SMEM_Low, heap_size, NULL); + if (__psp_heap_blockid > 0) { + heap_bottom = sceKernelGetBlockHeadAddr(__psp_heap_blockid); + heap_ptr = heap_bottom; + heap_top = (unsigned char *) heap_bottom + heap_size; + } + } + } + + void * heap_addr = (void *) -1; + void * next_heap_ptr = (void *) ((ptrdiff_t) heap_ptr + incr); + if ((heap_bottom != NULL) && (next_heap_ptr >= heap_bottom) && (next_heap_ptr < heap_top)) { + heap_addr = heap_ptr; + heap_ptr = next_heap_ptr; + } + + sceKernelUnlockLwMutex(&__sbrk_mutex, 1); + + return heap_addr; +} +#endif + +#ifdef F__gettimeofday +int _gettimeofday(struct timeval *tp, struct timezone *tzp) +{ + return __set_errno(sceKernelLibcGettimeofday(tp, tzp)); +} +#endif + +#ifdef F__times +clock_t _times(struct tms *buffer) +{ + clock_t clk = sceKernelGetSystemTimeWide(); + + if (buffer != NULL) { + buffer->tms_utime = clk; + buffer->tms_stime = 0; + buffer->tms_cutime = clk; + buffer->tms_cstime = 0; + } + + return clk; +} +#endif + +#ifdef F__internal_malloc_lock +void _internal_malloc_lock(struct _reent *ptr) +{ + sceKernelLockLwMutex(&__malloc_mutex, 1, 0); +} +#endif + +#ifdef F__internal_malloc_unlock +void _internal_malloc_unlock(struct _reent *ptr) +{ + sceKernelUnlockLwMutex(&__malloc_mutex, 1); +} +#endif + +// Some POSIX functions that are missing in NEWLIB + +#ifdef F_symlink +int symlink(const char *path1, const char *path2) +{ + return link(path1, path2); +} +#endif + +#ifdef F_truncate +int truncate(const char *path, off_t length) +{ + ssize_t bytes_read; + int fd; + char buff[length]; + + fd = open(path, O_RDONLY); + if (fd < 0) { + return -1; + } + + bytes_read = read(fd, &buff, length); + close(fd); + if (bytes_read < length) { + errno = EFBIG; + return -1; + } + + fd = open (path, O_TRUNC|O_WRONLY); + if (fd < 0) { + return -1; + } + + write(fd, &buff, length); + close(fd); + return 0; +} +#endif + +#ifdef F__isatty +int _isatty(int fd) +{ + errno = ENOTTY; + return 0; +} +#endif + +#ifdef F_chmod +int chmod(const char *pathname, mode_t mode) +{ + // TODO: Implement proper functionality + return 0; +} +#endif + +#ifdef F_fchmod +int fchmod(int filedes, mode_t mode) +{ + // TODO: Implement proper functionality + return 0; +} +#endif + +#ifdef F_fchmodat +int fchmodat(int fd, const char *path, mode_t mode, int flag) +{ + // TODO: Implement proper functionality + return 0; +} +#endif + +#ifdef F_pathconf +long int pathconf(const char *path, int name) { + // TODO: Implement proper functionality + return 0; +} +#endif + +#ifdef F_readlink +ssize_t readlink(const char *path, char *buf, size_t bufsiz) { + // TODO: Implement proper functionality + return 0; +} +#endif + +#ifdef F_utime +struct utimbuf { + time_t actime; /* Access time */ + time_t modtime; /* Modification time */ +}; + +int utime(const char *path, const struct utimbuf *times) +{ + // TODO: Implement proper functionality + return 0; +} +#endif + +#ifdef F_fchown +int fchown(int fd, uid_t owner, gid_t group) +{ + // TODO: Implement proper functionality + return 0; +} +#endif + +#ifdef F_getentropy +int getentropy(void *buffer, size_t length) { + size_t i; + SceKernelUtilsMt19937Context ctx; + sceKernelUtilsMt19937Init(&ctx, time(NULL)); + uint8_t *source = (uint8_t *)buffer; + for (i = 0; i < length; i++) { + uint8_t rand_val = sceKernelUtilsMt19937UInt(&ctx) & 0xFF; + source[i] = rand_val; + } + + return 0; +} +#endif \ No newline at end of file diff --git a/src/libc/init.c b/src/libc/init.c index 1ebe1e46..4e9aefd4 100644 --- a/src/libc/init.c +++ b/src/libc/init.c @@ -10,25 +10,38 @@ * Copyright (c) 2005 John Kelley * */ -void _pspsdk_alloc_init(); -void _pspsdk_alloc_deinit(); -void _pspsdk_stdio_init(); -void _pspsdk_stdio_deinit(); -void _pspsdk_stdlib_init(); -void _pspsdk_stdlib_deinit(); -__attribute__((weak, constructor)) -void _pspsdk_libc_init() -{ - _pspsdk_alloc_init(); - _pspsdk_stdio_init(); - _pspsdk_stdlib_init(); -} +#include +#include +#include +#include -__attribute__((weak, destructor)) -void _pspsdk_libc_deinit() +void __init_cwd(char *argv_0); +void __timezone_update(); +void __fdman_init(); +void __init_mutex(); + +#ifdef F___psp_libc_init +/* Note: This function is being called from crt0.c/crt0_prx.c. +* It is a weak function because can be override by user program, +* saving a lot of space in your binary, however you will loose + all the basic libc operation +*/ +__attribute__((weak)) +void __psp_libc_init(int argc, char *argv[]) { - _pspsdk_stdlib_deinit(); - _pspsdk_stdio_deinit(); - _pspsdk_alloc_deinit(); + (void) argc; + + /* Initialize mutex used in malloc and fdman */ + __init_mutex(); + + /* Initialize filedescriptor management */ + __fdman_init(); + + /* Initialize cwd from this program's path */ + __init_cwd(argv[0]); + + /* Initialize timezone */ + __timezone_update(); } +#endif \ No newline at end of file diff --git a/src/libc/libcglue.c b/src/libc/libcglue.c deleted file mode 100644 index 19752b5a..00000000 --- a/src/libc/libcglue.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * libcglue.c - Newlib-compatible system calls. - * - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * Copyright (c) 2005 Jim Paris - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* These functions aren't exposed in any public headers, and they probably don't need to be. */ -int sceKernelStdin(void); -int sceKernelStdout(void); -int sceKernelStderr(void); - -extern char * __psp_argv_0; -extern int __psp_cwd_initialized; -extern char __psp_cwd[MAXPATHLEN + 1]; -extern void __psp_init_cwd(void); -extern int __psp_path_absolute(const char *in, char *out, int len); - -/* If we're being built for PSPSDK's libc this function isn't defined. */ -#ifdef F_glue_gettimeofday -int gettimeofday(struct timeval *tp, void *tzp) -{ - return sceKernelLibcGettimeofday(tp, tzp); -} -#endif - -#if defined(F_clock) || defined(F_glue_clock) -clock_t clock(void) -{ - return sceKernelLibcClock(); -} -#endif - -#if defined(F_time) || defined(F_glue_time) -time_t time(time_t *t) -{ - return sceKernelLibcTime(t); -} -#endif - -/* PSP-compatible sbrk(). */ -#if defined(F__sbrk) || defined(F_glue__sbrk) - -#define DEFAULT_PRX_HEAP_SIZE_KB 64 - -/* If defined it specifies the desired size of the heap, in KB. */ -extern unsigned int sce_newlib_heap_kb_size __attribute__((weak)); -extern int __pspsdk_is_prx __attribute__((weak)); - -/* UID of the memory block that represents the heap. */ -static SceUID __psp_heap_blockid; - -void * _sbrk(ptrdiff_t incr) -{ - static void * heap_bottom = NULL; - static void * heap_top = NULL; - static void * heap_ptr = NULL; - - /* Has our heap been initialized? */ - if (heap_bottom == NULL) { - /* No, initialize the heap. */ - SceSize heap_size = (SceSize) -1; - - if (&sce_newlib_heap_kb_size != NULL) { - heap_size = sce_newlib_heap_kb_size; - } else if(&__pspsdk_is_prx != NULL) { - heap_size = DEFAULT_PRX_HEAP_SIZE_KB; - } - - if (heap_size == (unsigned int) -1) { - heap_size = sceKernelMaxFreeMemSize(); - } else { - heap_size *= 1024; - } - - if (heap_size != 0) { - __psp_heap_blockid = sceKernelAllocPartitionMemory(2, "block", PSP_SMEM_Low, heap_size, NULL); - if (__psp_heap_blockid > 0) { - heap_bottom = sceKernelGetBlockHeadAddr(__psp_heap_blockid); - heap_ptr = heap_bottom; - heap_top = (unsigned char *) heap_bottom + heap_size; - } - } - } - - void * heap_addr = (void *) -1; - void * next_heap_ptr = (void *) ((ptrdiff_t) heap_ptr + incr); - if ((heap_bottom != NULL) && (next_heap_ptr >= heap_bottom) && (next_heap_ptr < heap_top)) { - heap_addr = heap_ptr; - heap_ptr = next_heap_ptr; - } - - return heap_addr; -} - -/* Free the heap. */ -int __psp_free_heap(void) -{ - if (__psp_heap_blockid > 0) { - return sceKernelFreePartitionMemory(__psp_heap_blockid); - } - - return __psp_heap_blockid; -} -#endif - -#if defined(F__exit) || defined(F_glue__exit) -extern int sce_newlib_nocreate_thread_in_start __attribute__((weak)); - -extern int __psp_free_heap(void); - -void _exit(int status) -{ - if (&sce_newlib_nocreate_thread_in_start != NULL) { - /* Free the heap created by _sbrk(). */ - __psp_free_heap(); - - sceKernelSelfStopUnloadModule(1, 0, NULL); - } else { - if (status == 0) { - /* Free the heap created by _sbrk(). */ - __psp_free_heap(); - } - - sceKernelExitThread(status); - } - - while (1) ; -} -#endif - -/* newlib's errno.h wants a function that returns a pointer to errno. */ -#ifdef F_glue___errno -#undef errno - -int errno; - -/* TODO: Should this be made reentrant (wrapping interrupt disable/enable - around it should do it)? */ -int * __errno(void) -{ - return &errno; -} -#endif diff --git a/src/libc/malloc.h b/src/libc/malloc.h deleted file mode 100644 index bdb1c227..00000000 --- a/src/libc/malloc.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * malloc.h - * - * Copyright (c) 2002-2004 PS2DEV - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ - -#ifndef _MALLOC_H -#define _MALLOC_H - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* stdlib/malloc */ -void * malloc(size_t size); -void * realloc(void *ptr, size_t size); -void * calloc(size_t n, size_t size); -void * memalign(size_t align, size_t size); -void free(void * ptr); - -/* Memory walkers. Used for debugging/profiling purposes. */ -void * __mem_walk_begin(void); -void __mem_walk_read(void * token, u32 * size, void ** ptr, int * valid); -void * __mem_walk_inc(void * token); -int __mem_walk_end(void * token); - -/* Example of use: - - void * i; - - for (i = __mem_walk_begin(); !__mem_walk_end(i); i = __mem_walk_inc(i)) { - u32 block_size; - void * block_ptr; - int valid; - - __mem_walk_read(i, &block_size, &block_ptr, &valid); - if (!valid) { - fprintf(stderr, "Block at token %p is invalid.\n", i); - break; - } - printf("Block at token %p points at a memory block of %i bytes at %p.\n", i, block_size, block_ptr); - } - - note that 'valid' will be always true if DEBUG_ALLOC was not defined when alloc.c got compiled. - -*/ - -#ifdef __cplusplus -} -#endif - -#endif // _MALLOC_H - diff --git a/src/libc/mutexman.c b/src/libc/mutexman.c new file mode 100644 index 00000000..995ef5d4 --- /dev/null +++ b/src/libc/mutexman.c @@ -0,0 +1,45 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * init.c - The global init/deinit code for our crt0. + * + * Copyright (c) 2005 Marcus R. Brown + * Copyright (c) 2005 James Forshaw + * Copyright (c) 2005 John Kelley + * + */ + +#include +#include +#include +#include + +#ifdef F___malloc_mutex +SceLwMutexWorkarea __malloc_mutex; +#else +extern SceLwMutexWorkarea __malloc_mutex; +#endif + +#ifdef F___sbrk_mutex +SceLwMutexWorkarea __sbrk_mutex; +#else +extern SceLwMutexWorkarea __sbrk_mutex; +#endif + +#ifdef F___fdman_mutex +SceLwMutexWorkarea __fdman_mutex; +#else +extern SceLwMutexWorkarea __fdman_mutex; +#endif + +#ifdef F___init_mutex +/* Create mutex used for making thread safe mallock and get fd */ +void __init_mutex() +{ + sceKernelCreateLwMutex(&__malloc_mutex, "malloc mutex", 0, 0, 0); + sceKernelCreateLwMutex(&__sbrk_mutex, "sbrk mutex", 0, 0, 0); + sceKernelCreateLwMutex(&__fdman_mutex, "fdman mutex", 0, 0, 0); +} +#endif \ No newline at end of file diff --git a/src/libc/netdb.c b/src/libc/netdb.c new file mode 100644 index 00000000..73ec2c74 --- /dev/null +++ b/src/libc/netdb.c @@ -0,0 +1,115 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * netdb.c - Simple gethostbyname and gethostbyaddr replacements using the resolver lib + * + * Copyright (c) 2021 Francisco Javier Trujillo Mata + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#define MAX_NAME 512 + +#ifdef F_h_errno +int h_errno = NETDB_SUCCESS; +#endif + +#ifdef F_gethostbyaddr +struct hostent *gethostbyaddr(const void *addr, int len, int type) +{ + static struct hostent ent; + static char * aliases[1] = { NULL }; + char buf[1024]; + static char sname[MAX_NAME] = ""; + static struct in_addr saddr = { 0 }; + static char *addrlist[2] = { (char *) &saddr, NULL }; + int rid; + int err; + + if((len != sizeof(struct in_addr)) || (type != AF_INET) || (addr == NULL)) + { + h_errno = HOST_NOT_FOUND; + return NULL; + } + + memcpy(&saddr, addr, len); + + if(sceNetResolverCreate(&rid, buf, sizeof(buf)) < 0) + { + h_errno = NO_RECOVERY; + return NULL; + } + + err = sceNetResolverStartAtoN(rid, &saddr, sname, sizeof(sname), 2, 3); + sceNetResolverStop(rid); + sceNetResolverDelete(rid); + if(err < 0) + { + h_errno = HOST_NOT_FOUND; + return NULL; + } + + ent.h_name = sname; + ent.h_aliases = aliases; + ent.h_addrtype = AF_INET; + ent.h_length = sizeof(struct in_addr); + ent.h_addr_list = addrlist; + ent.h_addr = (char *) &saddr; + + return &ent; +} +#endif + +#ifdef F_gethostbyname +struct hostent *gethostbyname(const char *name) +{ + static struct hostent ent; + char buf[1024]; + static char sname[MAX_NAME] = ""; + static struct in_addr saddr = { 0 }; + static char *addrlist[2] = { (char *) &saddr, NULL }; + int rid; + + if(sceNetInetInetAton(name, &saddr) == 0) + { + int err; + + if(sceNetResolverCreate(&rid, buf, sizeof(buf)) < 0) + { + h_errno = NO_RECOVERY; + return NULL; + } + + err = sceNetResolverStartNtoA(rid, name, &saddr, 2, 3); + sceNetResolverDelete(rid); + if(err < 0) + { + h_errno = HOST_NOT_FOUND; + return NULL; + } + + } + + snprintf(sname, MAX_NAME, "%s", name); + ent.h_name = sname; + ent.h_aliases = 0; + ent.h_addrtype = AF_INET; + ent.h_length = sizeof(struct in_addr); + ent.h_addr_list = addrlist; + ent.h_addr = (char *) &saddr; + + return &ent; +} + +#endif diff --git a/src/libc/netdb.h b/src/libc/netdb.h new file mode 100644 index 00000000..bb8cdb4d --- /dev/null +++ b/src/libc/netdb.h @@ -0,0 +1,36 @@ +/* Simple gethostbyname and gethostbyaddr replacements, note not thread safe */ +#ifndef __NETDB_H__ +#define __NETDB_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NETDB_INTERNAL -1 /* see errno */ +#define NETDB_SUCCESS 0 /* no problem */ +#define HOST_NOT_FOUND 1 /* Authoritative Answer Host not found */ +#define TRY_AGAIN 2 /* Non-Authoritative Host not found, or SERVERFAIL */ +#define NO_RECOVERY 3 /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */ +#define NO_DATA 4 /* Valid name, no data record of requested type */ +#define NO_ADDRESS NO_DATA /* no address, look for MX record */ + +extern int h_errno; + +struct hostent +{ + char *h_name; + char **h_aliases; + int h_addrtype; + int h_length; + char **h_addr_list; + char *h_addr; +}; + +struct hostent *gethostbyaddr(const void *addr, int len, int type); +struct hostent *gethostbyname(const char *name); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libc/netinet/in.h b/src/libc/netinet/in.h new file mode 100644 index 00000000..86134a9b --- /dev/null +++ b/src/libc/netinet/in.h @@ -0,0 +1,280 @@ +/* $NetBSD: in.h,v 1.71 2005/08/05 09:21:25 elad Exp $ */ + +/* + * Copyright (c) 1982, 1986, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)in.h 8.3 (Berkeley) 1/3/94 + */ + +/* + * Constants and structures defined by the internet system, + * Per RFC 790, September 1981, and numerous additions. + */ + +#ifndef _NETINET_IN_H_ +#define _NETINET_IN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef uint32_t in_addr_t; +typedef uint16_t in_port_t; + +/* + * Protocols + */ +#define IPPROTO_IP 0 /* dummy for IP */ +#define IPPROTO_HOPOPTS 0 /* IP6 hop-by-hop options */ +#define IPPROTO_ICMP 1 /* control message protocol */ +#define IPPROTO_IGMP 2 /* group mgmt protocol */ +#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ +#define IPPROTO_IPV4 4 /* IP header */ +#define IPPROTO_IPIP 4 /* IP inside IP */ +#define IPPROTO_TCP 6 /* tcp */ +#define IPPROTO_EGP 8 /* exterior gateway protocol */ +#define IPPROTO_PUP 12 /* pup */ +#define IPPROTO_UDP 17 /* user datagram protocol */ +#define IPPROTO_IDP 22 /* xns idp */ +#define IPPROTO_TP 29 /* tp-4 w/ class negotiation */ +#define IPPROTO_IPV6 41 /* IP6 header */ +#define IPPROTO_ROUTING 43 /* IP6 routing header */ +#define IPPROTO_FRAGMENT 44 /* IP6 fragmentation header */ +#define IPPROTO_RSVP 46 /* resource reservation */ +#define IPPROTO_GRE 47 /* GRE encaps RFC 1701 */ +#define IPPROTO_ESP 50 /* encap. security payload */ +#define IPPROTO_AH 51 /* authentication header */ +#define IPPROTO_MOBILE 55 /* IP Mobility RFC 2004 */ +#define IPPROTO_IPV6_ICMP 58 /* IPv6 ICMP */ +#define IPPROTO_ICMPV6 58 /* ICMP6 */ +#define IPPROTO_NONE 59 /* IP6 no next header */ +#define IPPROTO_DSTOPTS 60 /* IP6 destination option */ +#define IPPROTO_EON 80 /* ISO cnlp */ +#define IPPROTO_ETHERIP 97 /* Ethernet-in-IP */ +#define IPPROTO_ENCAP 98 /* encapsulation header */ +#define IPPROTO_PIM 103 /* Protocol indep. multicast */ +#define IPPROTO_IPCOMP 108 /* IP Payload Comp. Protocol */ +#define IPPROTO_VRRP 112 /* VRRP RFC 2338 */ + +#define IPPROTO_RAW 255 /* raw IP packet */ +#define IPPROTO_MAX 256 + +/* last return value of *_input(), meaning "all job for this pkt is done". */ +#define IPPROTO_DONE 257 + +/* sysctl placeholder for (FAST_)IPSEC */ +#define CTL_IPPROTO_IPSEC 258 + + +/* + * Local port number conventions: + * + * Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root), + * unless a kernel is compiled with IPNOPRIVPORTS defined. + * + * When a user does a bind(2) or connect(2) with a port number of zero, + * a non-conflicting local port address is chosen. + * + * The default range is IPPORT_ANONMIN to IPPORT_ANONMAX, although + * that is settable by sysctl(3); net.inet.ip.anonportmin and + * net.inet.ip.anonportmax respectively. + * + * A user may set the IPPROTO_IP option IP_PORTRANGE to change this + * default assignment range. + * + * The value IP_PORTRANGE_DEFAULT causes the default behavior. + * + * The value IP_PORTRANGE_HIGH is the same as IP_PORTRANGE_DEFAULT, + * and exists only for FreeBSD compatibility purposes. + * + * The value IP_PORTRANGE_LOW changes the range to the "low" are + * that is (by convention) restricted to privileged processes. + * This convention is based on "vouchsafe" principles only. + * It is only secure if you trust the remote host to restrict these ports. + * The range is IPPORT_RESERVEDMIN to IPPORT_RESERVEDMAX. + */ + +#define IPPORT_RESERVED 1024 +#define IPPORT_ANONMIN 49152 +#define IPPORT_ANONMAX 65535 +#define IPPORT_RESERVEDMIN 600 +#define IPPORT_RESERVEDMAX (IPPORT_RESERVED-1) + +/* + * Internet address (a structure for historical reasons) + */ +struct in_addr { + in_addr_t s_addr; +} __attribute__((__packed__)); + +#define __IPADDR(x) ((uint32_t)(x)) + +#define IN_CLASSA(i) (((uint32_t)(i) & __IPADDR(0x80000000)) == \ + __IPADDR(0x00000000)) +#define IN_CLASSA_NET __IPADDR(0xff000000) +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST __IPADDR(0x00ffffff) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(i) (((uint32_t)(i) & __IPADDR(0xc0000000)) == \ + __IPADDR(0x80000000)) +#define IN_CLASSB_NET __IPADDR(0xffff0000) +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST __IPADDR(0x0000ffff) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(i) (((uint32_t)(i) & __IPADDR(0xe0000000)) == \ + __IPADDR(0xc0000000)) +#define IN_CLASSC_NET __IPADDR(0xffffff00) +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST __IPADDR(0x000000ff) + +#define IN_CLASSD(i) (((uint32_t)(i) & __IPADDR(0xf0000000)) == \ + __IPADDR(0xe0000000)) +/* These ones aren't really net and host fields, but routing needn't know. */ +#define IN_CLASSD_NET __IPADDR(0xf0000000) +#define IN_CLASSD_NSHIFT 28 +#define IN_CLASSD_HOST __IPADDR(0x0fffffff) +#define IN_MULTICAST(i) IN_CLASSD(i) + +#define IN_EXPERIMENTAL(i) (((uint32_t)(i) & __IPADDR(0xf0000000)) == \ + __IPADDR(0xf0000000)) +#define IN_BADCLASS(i) (((uint32_t)(i) & __IPADDR(0xf0000000)) == \ + __IPADDR(0xf0000000)) + +#define IN_LOCAL_GROUP(i) (((uint32_t)(i) & __IPADDR(0xffffff00)) == \ + __IPADDR(0xe0000000)) + +#define INADDR_ANY __IPADDR(0x00000000) +#define INADDR_LOOPBACK __IPADDR(0x7f000001) +#define INADDR_BROADCAST __IPADDR(0xffffffff) /* must be masked */ + +#define INADDR_UNSPEC_GROUP __IPADDR(0xe0000000) /* 224.0.0.0 */ +#define INADDR_ALLHOSTS_GROUP __IPADDR(0xe0000001) /* 224.0.0.1 */ +#define INADDR_ALLRTRS_GROUP __IPADDR(0xe0000002) /* 224.0.0.2 */ +#define INADDR_MAX_LOCAL_GROUP __IPADDR(0xe00000ff) /* 224.0.0.255 */ + +#define IN_LOOPBACKNET 127 /* official! */ + +/* + * Socket address, internet style. + */ +struct sockaddr_in { + uint8_t sin_len; + sa_family_t sin_family; + in_port_t sin_port; + struct in_addr sin_addr; + int8_t sin_zero[8]; +}; + +#define INET_ADDRSTRLEN 16 + +/* + * Structure used to describe IP options. + * Used to store options internally, to pass them to a process, + * or to restore options retrieved earlier. + * The ip_dst is used for the first-hop gateway when using a source route + * (this gets put into the header proper). + */ +struct ip_opts { + struct in_addr ip_dst; /* first hop, 0 w/o src rt */ +#if defined(__cplusplus) + int8_t Ip_opts[40]; /* actually variable in size */ +#else + int8_t ip_opts[40]; /* actually variable in size */ +#endif +}; + +/* + * Options for use with [gs]etsockopt at the IP level. + * First word of comment is data type; bool is stored in int. + */ +#define IP_OPTIONS 1 /* buf/ip_opts; set/get IP options */ +#define IP_HDRINCL 2 /* int; header is included with data */ +#define IP_TOS 3 /* int; IP type of service and preced. */ +#define IP_TTL 4 /* int; IP time to live */ +#define IP_RECVOPTS 5 /* bool; receive all IP opts w/dgram */ +#define IP_RECVRETOPTS 6 /* bool; receive IP opts for response */ +#define IP_RECVDSTADDR 7 /* bool; receive IP dst addr w/dgram */ +#define IP_RETOPTS 8 /* ip_opts; set/get IP options */ +#define IP_MULTICAST_IF 9 /* in_addr; set/get IP multicast i/f */ +#define IP_MULTICAST_TTL 10 /* u_char; set/get IP multicast ttl */ +#define IP_MULTICAST_LOOP 11 /* u_char; set/get IP multicast loopback */ +#define IP_ADD_MEMBERSHIP 12 /* ip_mreq; add an IP group membership */ +#define IP_DROP_MEMBERSHIP 13 /* ip_mreq; drop an IP group membership */ +#define IP_PORTRANGE 19 /* int; range to use for ephemeral port */ +#define IP_RECVIF 20 /* bool; receive reception if w/dgram */ +#define IP_ERRORMTU 21 /* int; get MTU of last xmit = EMSGSIZE */ +#if 1 /*IPSEC*/ +#define IP_IPSEC_POLICY 22 /* struct; get/set security policy */ +#endif + +/* + * Defaults and limits for options + */ +#define IP_DEFAULT_MULTICAST_TTL 1 /* normally limit m'casts to 1 hop */ +#define IP_DEFAULT_MULTICAST_LOOP 1 /* normally hear sends if a member */ +#define IP_MAX_MEMBERSHIPS 20 /* per socket; must fit in one mbuf */ + +/* + * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP. + */ +struct ip_mreq { + struct in_addr imr_multiaddr; /* IP multicast address of group */ + struct in_addr imr_interface; /* local IP address of interface */ +}; + +/* + * Argument for IP_PORTRANGE: + * - which range to search when port is unspecified at bind() or connect() + */ +#define IP_PORTRANGE_DEFAULT 0 /* default range */ +#define IP_PORTRANGE_HIGH 1 /* same as DEFAULT (FreeBSD compat) */ +#define IP_PORTRANGE_LOW 2 /* use privileged range */ + + +#if 0 +// FIXME: These are optimized (one instruction), but currently not part of psp-gcc +#define ntohs(x) __builtin_allegrex_wsbh(x) +#define ntohl(x) __builtin_allegrex_wsbw(x) +#define htons(x) __builtin_allegrex_wsbh(x) +#define htonl(x) __builtin_allegrex_wsbw(x) +#else +#define ntohs(x) __builtin_bswap16(x) +#define ntohl(x) __builtin_bswap32(x) +#define htons(x) __builtin_bswap16(x) +#define htonl(x) __builtin_bswap32(x) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !_NETINET_IN_H_ */ diff --git a/src/libc/netinet/tcp.h b/src/libc/netinet/tcp.h new file mode 100644 index 00000000..deda3f2f --- /dev/null +++ b/src/libc/netinet/tcp.h @@ -0,0 +1,12 @@ +#ifndef __NETINET_TCP_H__ +#define __NETINET_TCP_H__ + +#include + +#define SOL_TCP IPPROTO_TCP + +/* Socket options */ +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#define TCP_MAXSEG 0x02 /* set maximum segment size */ + +#endif diff --git a/src/libc/pipe.c b/src/libc/pipe.c new file mode 100644 index 00000000..3bdc5938 --- /dev/null +++ b/src/libc/pipe.c @@ -0,0 +1,324 @@ +/* + * PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * pipe.c - Socket wrappers to provide similar functions to normal unix + * + * Copyright (c) 2006 Rafael Cabezas + * + * - 20070630 Alper Akcan "anhanguera" + * [non]blocking read/write() fix + * illegal size fix for read/write() + * + */ +#include +#include +#include +#include + +#include +#include +#include +#include +#include "fdman.h" + +int __set_errno(int code); + +#ifdef F___pipe_peekmsgsize +/* Pipe functions */ +/* Returns how many bytes are in the pipe -- waiting to be read */ +size_t __pipe_peekmsgsize(int fd) +{ + SceKernelMppInfo info; + info.size = sizeof(info); + + if (!__IS_FD_OF_TYPE(fd, __DESCRIPTOR_TYPE_PIPE)) { + errno = EBADF; + return -1; + } + + if (sceKernelReferMsgPipeStatus(__descriptormap[fd]->descriptor, &info) == 0) { + return (info.bufSize - info.freeSize); + } + else { + return -1; + } +} +#else +size_t __pipe_peekmsgsize(int fd); +#endif + +#ifdef D_pipe +int pipe(int fildes[2]) +{ + static int iIndex = 0; + char name[32]; + iIndex++; + + sprintf(name, "__pipe_%02d", iIndex); + + SceUID uid = sceKernelCreateMsgPipe(name, PSP_MEMORY_PARTITION_USER, 0, (void *)PIPE_BUF, NULL); + + if (uid >= 0) { + fildes[0] = __fdman_get_new_descriptor(); + if (fildes[0] != -1) { + __descriptormap[fildes[0]]->descriptor = uid; + __descriptormap[fildes[0]]->type = __DESCRIPTOR_TYPE_PIPE; + } + else { + sceKernelDeleteMsgPipe(uid); + errno = EFAULT; + return -1; + } + + fildes[1] = __fdman_get_dup_descriptor(fildes[0]); + if (fildes[1] != -1) { + __descriptormap[fildes[1]]->descriptor = uid; + return 0; + } + else { + sceKernelDeleteMsgPipe(uid); + errno = EFAULT; + return -1; + } + + } + else { + errno = EFAULT; + return -1; + } +} +#endif + +#ifdef F___pipe_close +int __pipe_close(int fd) +{ + int ret = 0; + + if (!__IS_FD_OF_TYPE(fd, __DESCRIPTOR_TYPE_PIPE)) { + errno = EBADF; + return -1; + } + + + if ( __descriptormap[fd]->ref_count == 1 ) { + /** + * Delete a message pipe + * + * @param uid - The UID of the pipe + * + * @return 0 on success, < 0 on error + */ + ret = sceKernelDeleteMsgPipe(__descriptormap[fd]->descriptor); + } + + __fdman_release_descriptor(fd); + + if(ret < 0) { + return __set_errno(ret); + } + + return 0; +} +#endif + +#ifdef F___pipe_nonblocking_read +int __pipe_nonblocking_read(int fd, void *buf, size_t len) +{ + int ret; + int sceuid; + int size; + + if (!__IS_FD_OF_TYPE(fd, __DESCRIPTOR_TYPE_PIPE)) { + errno = EBADF; + return -1; + } + + sceuid = __descriptormap[fd]->descriptor; + + size = __pipe_peekmsgsize(fd); + if (size > 0) { + if (size < len) { + len = size; + } + } + else if (size == 0) { + errno = EAGAIN; + return -1; + } + else { + errno = EBADF; + return -1; + } + + /** + * Receive a message from a pipe + * + * @param uid - The UID of the pipe + * @param message - Pointer to the message + * @param size - Size of the message + * @param unk1 - Unknown + * @param unk2 - Unknown + * @param timeout - Timeout for receive + * + * @return 0 on success, < 0 on error + */ + ret = sceKernelTryReceiveMsgPipe(sceuid, buf, len, 0, 0); + + if (ret == 0) {/* Success - Data */ + return len; + } + else if (ret == SCE_KERNEL_ERROR_MPP_EMPTY) {/* No data */ + errno = EAGAIN; + return -1; + } + else {/* Error */ + return __set_errno(ret); + } +} +#endif + +#ifdef F___pipe_read +int __pipe_read(int fd, void *buf, size_t len) +{ + int ret; + int sceuid; + + if (!__IS_FD_OF_TYPE(fd, __DESCRIPTOR_TYPE_PIPE)) { + errno = EBADF; + return -1; + } + + sceuid = __descriptormap[fd]->descriptor; + +#if 0 + int size; + + /* we should block until there is some data (or maybe for enough data), + * peeking the msg size should be only for nonblocking reads + */ + size = __pipe_peekmsgsize(fd); + if (size > 0) { + if (size < len) { + len = size; + } + } + else { + errno = EBADF; + return -1; + } +#endif + /* if len is greater than PIPE_BUF then, MsgPipe functions returns + * SCE_KERNEL_ERROR_ILLEGAL_SIZE, but it should read at least + * PIPE_BUF bytes, and return the number of bytes read. + */ + if (len > PIPE_BUF) { + len = PIPE_BUF; + } + + /** + * Receive a message from a pipe + * + * @param uid - The UID of the pipe + * @param message - Pointer to the message + * @param size - Size of the message + * @param unk1 - Unknown + * @param unk2 - Unknown + * @param timeout - Timeout for receive + * + * @return 0 on success, < 0 on error + */ + ret = sceKernelReceiveMsgPipe(sceuid, buf, len, 0, NULL, NULL); + + if (ret == 0) {/* Success - Data */ + return len; + } + else {/* Error */ + return __set_errno(ret); + } +} +#endif + +#ifdef F___pipe_write +int __pipe_write(int fd, const void *buf, size_t len) +{ + int ret; + int sceuid; + char *cbuf; + + if (!__IS_FD_OF_TYPE(fd, __DESCRIPTOR_TYPE_PIPE)) { + errno = EBADF; + return -1; + } + + sceuid = __descriptormap[fd]->descriptor; + + /* if len is greater than PIPE_BUF then, MsgPipe functions returns + * SCE_KERNEL_ERROR_ILLEGAL_SIZE, but it should write at least + * PIPE_BUF bytes, and return the number of bytes written. + */ + if (len > PIPE_BUF) { + len = PIPE_BUF; + } + + /** + * Send a message to a pipe + * + * @param uid - The UID of the pipe + * @param message - Pointer to the message + * @param size - Size of the message + * @param unk1 - Unknown + * @param unk2 - Unknown + * @param timeout - Timeout for send + * + * @return 0 on success, < 0 on error + */ + cbuf = (char *)buf; + ret = sceKernelSendMsgPipe(sceuid, cbuf, len, 0, NULL, NULL); + if (ret == 0) {/* Success - Data */ + return len; + } + else {/* Error */ + return __set_errno(ret); + } +} +#endif + +#ifdef F___pipe_nonblocking_write +int __pipe_nonblocking_write(int fd, const void *buf, size_t len) +{ + int ret; + int sceuid; + char *cbuf; + + if (!__IS_FD_OF_TYPE(fd, __DESCRIPTOR_TYPE_PIPE)) { + errno = EBADF; + return -1; + } + + sceuid = __descriptormap[fd]->descriptor; + + /* if len is greater than PIPE_BUF then, MsgPipe functions returns + * SCE_KERNEL_ERROR_ILLEGAL_SIZE, but it should write at least + * PIPE_BUF bytes, and return the number of bytes written. + */ + if (len > PIPE_BUF) { + len = PIPE_BUF; + } + + cbuf = (char *)buf; + ret = sceKernelTrySendMsgPipe(sceuid, cbuf, len, 0, 0); + + if (ret == 0) {/* Success - Data */ + return len; + } + else if (ret == SCE_KERNEL_ERROR_MPP_FULL) { + errno = EAGAIN; + return -1; + } + else {/* Error */ + return __set_errno(ret); + } +} +#endif diff --git a/src/libc/qsort.c b/src/libc/qsort.c deleted file mode 100644 index 359b4700..00000000 --- a/src/libc/qsort.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * qsort.c - QSort algorithm implementation. - * - * Copyright (c) 1992, 1993 The Regents of the University of California. - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ - - /*- - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include - -typedef int cmp_t(const void *, const void *); -static __inline char *med3(char *, char *, char *, cmp_t *, void *); -static __inline void swapfunc(char *, char *, int, int); - -#define min(a, b) (a) < (b) ? (a) : (b) - -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) { \ - long i = (n) / sizeof (TYPE); \ - register TYPE *pi = (TYPE *) (parmi); \ - register TYPE *pj = (TYPE *) (parmj); \ - do { \ - register TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} - -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; - -static __inline void -swapfunc(char *a, char *b, int n, int swaptype) -{ - if(swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -} - -#define swap(a, b) \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype) - -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) - -#define CMP(t, x, y) (cmp((x), (y))) - -static __inline char * -med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk -) -{ - return CMP(thunk, a, b) < 0 ? - (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a )) - :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c )); -} - -#define thunk NULL -void -qsort(void *a, size_t n, size_t es, cmp_t *cmp) -{ - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) { - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; pl > (char *)a && CMP(thunk, pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pm = (char *)a + (n / 2) * es; - if (n > 7) { - pl = a; - pn = (char *)a + (n - 1) * es; - if (n > 40) { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk); - pm = med3(pm - d, pm, pm + d, cmp, thunk); - pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk); - } - pm = med3(pl, pm, pn, cmp, thunk); - } - swap(a, pm); - pa = pb = (char *)a + es; - - pc = pd = (char *)a + (n - 1) * es; - for (;;) { - while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - break; - swap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) - for (pl = pm; pl > (char *)a && CMP(thunk, pl - es, pl) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - - pn = (char *)a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min(pd - pc, pn - pd - es); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > es) - qsort(a, r / es, es, cmp); - if ((r = pd - pc) > es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -} diff --git a/src/libc/select.c b/src/libc/select.c new file mode 100644 index 00000000..439f2ffe --- /dev/null +++ b/src/libc/select.c @@ -0,0 +1,200 @@ +/* + * PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * select.c - Socket wrappers to provide similar functions to normal unix + * + * Copyright (c) 2006 Rafael Cabezas + * + * - 20070701 Alper Akcan "anhanguera" + * select EBADF fix + * + */ +#include +#include +#include +#include +#include +#include + +#include "fdman.h" + +#define SELECT_POLLING_DELAY_IN_us 100 +#define SCE_FD_SET(n, p) \ + ((p)->fds_bits[((n) & 0xFF) /_NFDBITS] |= (1 << ((n) % _NFDBITS))) + +#ifdef F_select +static int __poll_select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds) +{ + int fd, count; + fd_set ready_readfds, ready_writefds, ready_exceptfds; + fd_set scereadfds, scewritefds; + SceKernelMppInfo info; + struct timeval scetv; + + FD_ZERO(&ready_readfds); + FD_ZERO(&ready_writefds); + FD_ZERO(&ready_exceptfds); + + info.size = sizeof(info); + scetv.tv_sec = 0; + scetv.tv_usec = 0; + count = 0; + + for (fd = 0; fd < n; fd++) + { + if (__descriptormap[fd] != NULL) { + switch(__descriptormap[fd]->type) + { + case __DESCRIPTOR_TYPE_PIPE: + if (readfds && FD_ISSET(fd, readfds)) { + if (sceKernelReferMsgPipeStatus(__descriptormap[fd]->descriptor, &info) == 0) { + if (info.bufSize != info.freeSize) { + FD_SET(fd, &ready_readfds); + count++; + } + } + else { + FD_SET(fd, &ready_exceptfds); + count++; + } + } + if (writefds && FD_ISSET(fd, writefds)) { + if (sceKernelReferMsgPipeStatus(__descriptormap[fd]->descriptor, &info) == 0) { + if (info.freeSize > 0) { + FD_SET(fd, &ready_writefds); + count++; + } + } + else { + FD_SET(fd, &ready_exceptfds); + count++; + } + } + break; + case __DESCRIPTOR_TYPE_FILE: + if (readfds && FD_ISSET(fd, readfds)) { + if (readfds && FD_ISSET(fd, readfds)) { + /** Just set it for now */ + FD_SET(fd, &ready_readfds); + count++; + } + } + break; + case __DESCRIPTOR_TYPE_SOCKET: + if (readfds && FD_ISSET(fd, readfds)) { + int sce_ret, sce_fd; + sce_fd = __descriptormap[fd]->descriptor; + FD_ZERO(&scereadfds); + SCE_FD_SET(sce_fd, &scereadfds); + errno = 0; + sce_ret = sceNetInetSelect (sce_fd+1, &scereadfds, NULL, NULL, &scetv); + if (sce_ret>0) { + FD_SET(fd, &ready_readfds); + count++; + } + else if (sce_ret == -1) { + errno = sceNetInetGetErrno(); + if (exceptfds && FD_ISSET(fd, exceptfds)) { + FD_SET(fd, &ready_exceptfds); + count++; + } else { + count = -1; + } + } + } + if (writefds && FD_ISSET(fd, writefds)) { + int sce_ret; + FD_ZERO(&scewritefds); + SCE_FD_SET(__descriptormap[fd]->descriptor, &scewritefds); + sce_ret = sceNetInetSelect (__descriptormap[fd]->descriptor+1, NULL, &scewritefds, NULL, &scetv); + if (sce_ret>0) { + FD_SET(fd, &ready_writefds); + count++; + } + else if (sce_ret == -1) { + if (exceptfds && FD_ISSET(fd, exceptfds)) { + FD_SET(fd, &ready_exceptfds); + count++; + } + else { + count = -1; + } + } + } + break; + } + } else { + /* anhanguera - 20070701 + * + * here we know that, system has no idea about 'fd'. if caller requested + * information about 'fd', return '-1' and set errno to 'EBADF'. we should + * increse the count and set exceptfd for fd, but it is safe to obey select + * manual. + * + * from manual; + * On error, -1 is returned, and errno is set appropriately; the sets and + * timeout become undefined, so do not rely on their contents after an error. + */ + if ((readfds && FD_ISSET(fd, readfds)) || + (writefds && FD_ISSET(fd, writefds)) || + (exceptfds && FD_ISSET(fd, exceptfds))) { + errno = EBADF; + return -1; + } + } + } + + if (count > 0) { + if (readfds) + *readfds = ready_readfds; + if (writefds) + *writefds = ready_writefds; + if (exceptfds) + *exceptfds = ready_exceptfds; + } + + return count; +} + +int select(int n, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) +{ + int count; + clock_t start_time, time; + + start_time = clock(); + + count = 0; + + if (timeout) { + time = (timeout->tv_sec * CLOCKS_PER_SEC) + (timeout->tv_usec * (1*1000*1000/CLOCKS_PER_SEC)); + } + else { + time = 0; + } + + for (;;) { + count = __poll_select(n, readfds, writefds, exceptfds); + /* If timeout == NULL, then don't timeout! */ + if ( (count > 0) || ((timeout != NULL) && ((clock() - start_time) >= time)) ) { + break; + } + if (count < 0) { + /* anhanguera - 20070701 + * error, lets let the caller to handle error state + */ + break; + } + else { + /* Nothing found, and not timed-out yet; let's yield for SELECT_POLLING_DELAY_IN_us, so we're not in a busy loop */ + sceKernelDelayThread(SELECT_POLLING_DELAY_IN_us); + } + } + + return count; +} +#endif + + diff --git a/src/libc/setjmp.S b/src/libc/setjmp.S deleted file mode 100644 index b8144869..00000000 --- a/src/libc/setjmp.S +++ /dev/null @@ -1,116 +0,0 @@ -/* -# _____ ___ ____ ___ ____ -# ____| | ____| | | |____| -# | ___| |____ ___| ____| | \ PS2DEV Open Source Project. -#----------------------------------------------------------------------- -# Copyright 2001-2004, ps2dev - http://www.ps2dev.org -# Licenced under Academic Free License version 2.0 -# Review ps2sdk README & LICENSE files for further details. -# -# This is a simple version of setjmp and longjmp. -# Floating point support in. -*/ - -#include - -#define O_S0 0x00 -#define O_S1 0x04 -#define O_S2 0x08 -#define O_S3 0x0c -#define O_S4 0x10 -#define O_S5 0x14 -#define O_S6 0x18 -#define O_S7 0x1c -#define O_FP 0x20 -#define O_SP 0x24 -#define O_RA 0x28 -#define O_F20 0x2c -#define O_F21 0x30 -#define O_F22 0x34 -#define O_F23 0x38 -#define O_F24 0x3c -#define O_F25 0x40 -#define O_F26 0x44 -#define O_F27 0x48 -#define O_F28 0x4c -#define O_F29 0x50 -#define O_F30 0x54 -#define O_F31 0x58 - -/* int setjmp (jmp_buf); */ - .globl setjmp - .ent setjmp -setjmp: - .frame $sp,0,$31 - - sw $s0, O_S0($a0) - sw $s1, O_S1($a0) - sw $s2, O_S2($a0) - sw $s3, O_S3($a0) - sw $s4, O_S4($a0) - sw $s5, O_S5($a0) - sw $s6, O_S6($a0) - sw $s7, O_S7($a0) - sw $fp, O_FP($a0) - sw $sp, O_SP($a0) - sw $ra, O_RA($a0) - - swc1 $f20, O_F20($a0) - swc1 $f21, O_F21($a0) - swc1 $f22, O_F22($a0) - swc1 $f23, O_F23($a0) - swc1 $f24, O_F24($a0) - swc1 $f25, O_F25($a0) - swc1 $f26, O_F26($a0) - swc1 $f27, O_F27($a0) - swc1 $f28, O_F28($a0) - swc1 $f29, O_F29($a0) - swc1 $f30, O_F30($a0) - swc1 $f31, O_F31($a0) - - - move $v0, $0 - - jr $ra - - .end setjmp - -/* volatile void longjmp (jmp_buf, int); */ - .globl longjmp - .ent longjmp -longjmp: - .frame $sp,0,$31 - - lw $s0, O_S0($a0) - lw $s1, O_S1($a0) - lw $s2, O_S2($a0) - lw $s3, O_S3($a0) - lw $s4, O_S4($a0) - lw $s5, O_S5($a0) - lw $s6, O_S6($a0) - lw $s7, O_S7($a0) - lw $fp, O_FP($a0) - lw $sp, O_SP($a0) - lw $ra, O_RA($a0) - - lwc1 $f20, O_F20($a0) - lwc1 $f21, O_F21($a0) - lwc1 $f22, O_F22($a0) - lwc1 $f23, O_F23($a0) - lwc1 $f24, O_F24($a0) - lwc1 $f25, O_F25($a0) - lwc1 $f26, O_F26($a0) - lwc1 $f27, O_F27($a0) - lwc1 $f28, O_F28($a0) - lwc1 $f29, O_F29($a0) - lwc1 $f30, O_F30($a0) - lwc1 $f31, O_F31($a0) - - bne $a0, $0, 1f - li $a0, 1 -1: - move $v0, $a0 - - jr $ra - - .end longjmp diff --git a/src/libc/sleep.c b/src/libc/sleep.c new file mode 100644 index 00000000..7c156a1c --- /dev/null +++ b/src/libc/sleep.c @@ -0,0 +1,31 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * sleep.c - Sleep functions needed by newlib. + * + * Copyright (c) 2021 Francisco Javier Trujillo Mata + * + */ + +#include + +#include +#include +#include + +#ifdef F_nanosleep +/* note: we don't use rem as we have no signals */ +int nanosleep(const struct timespec *req, struct timespec *rem) +{ + sceKernelDelayThreadCB( 1000000 * req->tv_sec + (req->tv_nsec / 1000) ); + + if( rem != NULL ) { + rem->tv_sec = 0; + rem->tv_nsec = 0; + } + + return 0; +} +#endif \ No newline at end of file diff --git a/src/libc/socket.c b/src/libc/socket.c new file mode 100644 index 00000000..f9b9c8c3 --- /dev/null +++ b/src/libc/socket.c @@ -0,0 +1,446 @@ +/* + * PSP Software Development Kit - http://www.pspdev.org + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * socket.c - Socket wrappers to provide similar functions to normal unix + * + * Copyright (c) 2005 Marcus R. Brown + * Copyright (c) 2005 James Forshaw + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "fdman.h" + +// To avoid warnings +int sceNetInetAccept(int s, struct sockaddr *addr, socklen_t *addrlen); +int sceNetInetBind(int s, const struct sockaddr *my_addr, socklen_t addrlen); +int sceNetInetConnect(int s, const struct sockaddr *serv_addr, socklen_t addrlen); +int sceNetInetGetsockopt(int s, int level, int optname, void *optval, socklen_t *optlen); +int sceNetInetListen(int s, int backlog); +size_t sceNetInetRecv(int s, void *buf, size_t len, int flags); +size_t sceNetInetRecvfrom(int s, void *buf, size_t flags, int, struct sockaddr *from, socklen_t *fromlen); +size_t sceNetInetSend(int s, const void *buf, size_t len, int flags); +size_t sceNetInetSendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen); +int sceNetInetSetsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); +int sceNetInetShutdown(int s, int how); +int sceNetInetSocket(int domain, int type, int protocol); +int sceNetInetClose(int s); +int sceNetInetGetErrno(void); +int sceNetInetGetpeername(int s, struct sockaddr *name, socklen_t *namelen); +int sceNetInetGetsockname(int s, struct sockaddr *name, socklen_t *namelen); +ssize_t sceNetInetSendmsg(int s, const struct msghdr *msg, int flags); +ssize_t sceNetInetRecvmsg(int s, struct msghdr *msg, int flags); + +#ifdef F_socket +int socket(int domain, int type, int protocol) +{ + int sock, scesock; + + scesock = sceNetInetSocket(domain, type, protocol); + if(scesock < 0) { + errno = sceNetInetGetErrno(); + return -1; + } + + sock = __fdman_get_new_descriptor(); + if( sock != -1 ) { + __descriptormap[sock]->descriptor = scesock; + __descriptormap[sock]->type = __DESCRIPTOR_TYPE_SOCKET; + } + else { + sceNetInetClose(scesock); + errno = ENOENT; + return -1; + } + + return sock; +} +#endif + +/* These are glue routines that are called from _close(), _read(), and + _write(). They are here so that any program that uses socket() will pull + them in and have expanded socket capability. */ + +#ifdef F___socket_close +int __socket_close(int sock) +{ + int ret = 0; + + if (__descriptormap[sock]->ref_count == 1) { + ret = sceNetInetClose(__descriptormap[sock]->descriptor); + } + + __fdman_release_descriptor(sock); + + if(ret < 0) + { + /* If close is defined likely errno is */ + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_accept +int accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ + int newscesock, newsock; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + newscesock = sceNetInetAccept(__descriptormap[s]->descriptor, addr, addrlen); + if( (newscesock >= 0) ) { + newsock = __fdman_get_new_descriptor(); + if ( newsock != -1 ) { + __descriptormap[newsock]->descriptor = newscesock; + __descriptormap[newsock]->type = __DESCRIPTOR_TYPE_SOCKET; + } + else { + sceNetInetClose(newscesock); + errno = ENOENT; + return -1; + } + } + else { + errno = ENOENT; + return -1; + } + + return newsock; +} +#endif + +#ifdef F_bind +int bind(int s, const struct sockaddr *my_addr, socklen_t addrlen) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetBind(__descriptormap[s]->descriptor, my_addr, addrlen); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_connect +int connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetConnect(__descriptormap[s]->descriptor, serv_addr, addrlen); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_listen +int listen(int s, int backlog) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetListen(__descriptormap[s]->descriptor, backlog); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_recv +ssize_t recv(int s, void *buf, size_t len, int flags) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetRecv(__descriptormap[s]->descriptor, buf, len, flags); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return ret; +} +#endif + +#ifdef F_recvfrom +ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetRecvfrom(__descriptormap[s]->descriptor, buf, len, flags, from, fromlen); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return ret; +} +#endif + +#ifdef F_send +ssize_t send(int s, const void *buf, size_t len, int flags) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetSend(__descriptormap[s]->descriptor, buf, len, flags); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return ret; +} +#endif + +#ifdef F_sendto +ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetSendto(__descriptormap[s]->descriptor, buf, len, flags, to, tolen); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return ret; +} +#endif + +#ifdef F_getsockopt +int getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetGetsockopt(__descriptormap[s]->descriptor, level, optname, optval, optlen); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_setsockopt +int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetSetsockopt(__descriptormap[s]->descriptor, level, optname, optval, optlen); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + else + { + if ( (level == SOL_SOCKET) && (optname == SO_NONBLOCK) ) { + if (*((int*)optval) == 1) { + __descriptormap[s]->flags |= O_NONBLOCK; + } + else { + __descriptormap[s]->flags &= ~O_NONBLOCK; + } + } + } + + return 0; +} +#endif + +#ifdef F_shutdown +int shutdown(int s, int how) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetShutdown(__descriptormap[s]->descriptor, how); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_getpeername +int getpeername(int s, struct sockaddr *name, socklen_t *namelen) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetGetpeername(__descriptormap[s]->descriptor, name, namelen); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_getsockname +int getsockname(int s, struct sockaddr *name, socklen_t *namelen) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetGetsockname(__descriptormap[s]->descriptor, name, namelen); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_inet_ntoa +char *inet_ntoa(struct in_addr in) +{ + static char ip_addr[INET_ADDRSTRLEN+1]; + + if(sceNetInetInetNtop(AF_INET, &in, ip_addr, INET_ADDRSTRLEN) == NULL) + { + strcpy(ip_addr, "Invalid"); + } + + return ip_addr; +} +#endif + +#ifdef F_sendmsg +ssize_t sendmsg(int s, const struct msghdr *msg, int flags) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetSendmsg(__descriptormap[s]->descriptor, msg, flags); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif + +#ifdef F_recvmsg +ssize_t recvmsg(int s, struct msghdr *msg, int flags) +{ + int ret; + + if (!__IS_FD_OF_TYPE(s, __DESCRIPTOR_TYPE_SOCKET)) { + errno = EBADF; + return -1; + } + + ret = sceNetInetRecvmsg(__descriptormap[s]->descriptor, msg, flags); + if(ret < 0) + { + errno = sceNetInetGetErrno(); + return -1; + } + + return 0; +} +#endif \ No newline at end of file diff --git a/src/libc/stdio.c b/src/libc/stdio.c deleted file mode 100644 index 9bc056b1..00000000 --- a/src/libc/stdio.c +++ /dev/null @@ -1,1443 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * stdio.c - Simple standard C library implementation. - * - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ -#include -#include -#include -#include -#include -#include -#include - -/* std I/O buffer type constants. */ -#define STD_IOBUF_TYPE_NONE 0 -#define STD_IOBUF_TYPE_GE 1 -#define STD_IOBUF_TYPE_MS 2 -#define STD_IOBUF_TYPE_UMD 4 -#define STD_IOBUF_TYPE_HOST 8 -#define STD_IOBUF_TYPE_STDOUTHOST 16 - -#define _NFILE 16 - -#define _IOEOF 0x0020 -#define _IOERR 0x0040 - -#define _IOREAD 0x0001 -#define _IOWRT 0x0002 -#define _IORW 0x0200 -#define _IOMYBUF 0x0010 - -/* ensure FILE is defined. */ -/* This is specific to psplibc, so we have to make sure it doesn't conflict with - newlib's FILE definition. */; -/* -#ifndef __FILE_DEFINED -#define __FILE_DEFINED -*/ -typedef struct { - int type; - int fd; - int cnt; - int flag; - int has_putback; - u8 putback; -} __psplibc_FILE; -//#endif // __FILE_DEFINED - -/* Override newlib's definition of a FILE. */ -#define LOCAL_FILE(f) ((__psplibc_FILE *) (f)) - -extern FILE __iob[_NFILE]; - -/* Don't pull in macros from newlib's ctype.h that we don't support. */ -int isdigit(int); - -#ifdef F_clearerr -/* Get rid of the newlib macro definition. */ -#ifdef clearerr -#undef clearerr -#endif -/* -** -** [func] - clearerr. -** [desc] - clears the stream file stream error condition. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - none. -** [prec] - stream is a valid FILE pointer. -** [post] - the stream file stream error condition is cleared. -** -*/ -void clearerr(FILE *stream) -{ - LOCAL_FILE(stream)->flag &= (~_IOERR); -} -#endif - - -#ifdef F_fclose -/* -** -** [func] - fclose. -** [desc] - if stream is a valid FILE stream and able to close the stream file -** then returns 0. else returns EOF. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - int; 0 if able to close the stream file. else EOF. -** [prec] - stream is a valid FILE pointer. -** [post] - the stream file is closed. -** -*/ -int fclose(FILE *stream) -{ - int ret; - - /* test the file stream type. */ - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_NONE: - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* cannot close stdin, stdout, or stderr. */ - // duh.. this is wrong. One SHOULD be able to close - // std*. That's a common unix doing. However, I doubt - // allowing this madness could be a good idea. - ret = EOF; - break; - default: - if ((LOCAL_FILE(stream)->fd >= 0) && (sceIoClose(LOCAL_FILE(stream)->fd) >= 0)) { - LOCAL_FILE(stream)->type = STD_IOBUF_TYPE_NONE; - LOCAL_FILE(stream)->fd = -1; - LOCAL_FILE(stream)->cnt = 0; - LOCAL_FILE(stream)->flag = 0; - ret = 0; - } - else ret = EOF; - } - return (ret); -} -#endif - - -#ifdef F_fcloseall -/* -** -** [func] - fcloseall. -** [desc] - attempts to close all the open files. if able to close all the open -** files then returns the number of files closed. else returns -1. -** [entr] - none. -** [exit] - int; the number of files closed if successful. else -1. -** [prec] - none. -** [post] - all open non-system files are closed. -** -*/ -int fcloseall(void) -{ - int i, ret = 0; - FILE *iob; - - /* process all open files except for stdout, stdin and stderr. */ - for (i = 3, iob = &__iob[3]; i < _NFILE; ++i, ++iob) { - if (LOCAL_FILE(iob)->fd >= 0) { - /* attempt to close the current file. */ - if ((fclose(iob) == 0) && (ret >= 0)) ++ret; - else ret = EOF; - } - } - return (ret); -} -#endif - - -#ifdef F_feof -/* Get rid of the newlib macro definition. */ -#ifdef feof -#undef feof -#endif -/* -** -** [func] - feof. -** [desc] - if the stream file stream has reached the end of the file then -** returns non-zero. else returns 0. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - int; non-zero if the stream file has reached EOF. else 0. -** [prec] - stream is a valid FILE pointer. -** [post] - none. -** -*/ -int feof(FILE *stream) -{ - return ((LOCAL_FILE(stream)->flag & _IOEOF) != 0); -} -#endif - - -#ifdef F_ferror -/* Get rid of the newlib macro definition. */ -#ifdef ferror -#undef ferror -#endif -/* -** -** [func] - ferror. -** [desc] - if an error has occured for the stream file stream then returns -** non-zero. else returns 0. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - int; non-zero if error has occured for the stream file. else 0. -** [prec] - stream is a valid FILE pointer. -** [post] - none. -** -*/ -int ferror(FILE *stream) -{ - return ((LOCAL_FILE(stream)->flag & _IOERR) != 0); -} -#endif - - -#ifdef F_fflush -int mcFlush(int fd); -int mcSync(int mode, int *cmd, int *result); - -/* -** -** [func] - fflush. -** [desc] - if the stream file is opened as read-only then returns 0. else -** if stream is a valid FILE stream and able to flush the stream -** file write buffer then returns 0. else returns EOF. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - int; 0 if able to flush the write buffer or file is read-only. else EOF. -** [prec] - stream is a valid FILE pointer. -** [post] - the stream FILE stream write buffer is flushed. -** -*/ -int fflush(FILE *stream) -{ - int ret = EOF; // Same as default case below. - - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* stdout & stderr are never buffered. */ - case STD_IOBUF_TYPE_UMD: - /* cd-rom files are read-only so no write buffer to flush. */ - ret = 0; - break; - case STD_IOBUF_TYPE_MS: - if (LOCAL_FILE(stream)->flag & (_IOWRT | _IORW)) { - //if (ret != 0) ret = EOF; - /* Need to implement sync or something */ - } - else ret = 0; - break; - case STD_IOBUF_TYPE_HOST: - /* flush host file write buffer. */ - if (LOCAL_FILE(stream)->flag & (_IOWRT | _IORW)) ret = 0; - else ret = 0; - break; - default: - /* unknown/invalid I/O buffer type. */ - ret = EOF; - } - return (ret); -} -#endif - - -#ifdef F_fflushall -/* -** -** [func] - _fcloseall. -** [desc] - attempts to flush all the open files with write-access. if able -** to flush all the open files with write-access then returns the -** number of files flushed. else returns -1. -** [entr] - none. -** [exit] - int; the number of files flushed if successful. else -1. -** [prec] - none. -** [post] - all open non-system files with write-access are flushed. -** -*/ -int _fflushall(void) -{ - int i, ret = 0; - FILE *iob; - - /* process all open files except for stdout, stdin and stderr. */ - for (i = 3, iob = &__iob[3]; i < _NFILE; ++i, ++iob) { - if (LOCAL_FILE(iob)->fd >= 0) { - /* attempt to flush the current file. */ - if ((fflush(iob) == 0) && (ret >= 0)) ++ret; - else ret = EOF; - } - } - return (ret); -} -#endif - - -#ifdef F_fgetc -/* -** -** [func] - fgetc. -** [desc] - attempts to read one character from the stream file. if able to -** read one character from the file then returns the chaaracter -** read. else EOF. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - int; the character read from the stream file. else -1. -** [prec] - stream is a valid FILE pointer. -** [post] - the stream file is modified. -** -*/ -int fgetc(FILE *stream) -{ - char c; - int ret; - - if (LOCAL_FILE(stream)->has_putback) { - LOCAL_FILE(stream)->has_putback = 0; - return LOCAL_FILE(stream)->putback; - } - - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* cannot read from stdout or stderr. */ - ret = EOF; - break; - default: - ret = ((fread(&c, 1, 1, stream) == 1) ? (int)c : EOF); - } - return (ret); -} -#endif - - -#ifdef F_fgetpos -/* -** -** [func] - fgetpos. -** [desc] - attempts to retrieve the stream file stream pointer position. -** if able to retrieve the stream file stream pointer position -** then stores the position to pos and returns 0. else returns -1. -** [entr] - FILE *stream; the pointer to the file stream. -** fpos_t *pos; the pointer to the destination file position buffer. -** [exit] - int; 0 if able to retrieve the stream file pointer position. else -1. -** [prec] - stream is a valid FILE pointer and pos is a valid fpos_t pointer. -** [post] - the memory pointed to by pos is modified. -** -*/ -int fgetpos(FILE *stream, fpos_t *pos) -{ - long n; - - if ((n = ftell(stream)) >= 0) *pos = (fpos_t)n; - return ((n >= 0) ? 0 : -1); -} - -int fgetpos64(FILE *stream, int64_t *pos) -{ - int64_t n; - - if ((n = ftello64(stream)) >= 0) *pos = n; - return ((n >= 0) ? 0 : -1); -} -#endif - - -#ifdef F_fgets -/* -** -** [func] - fgets. -** [desc] - attempts to read a string from the stream file. if able to read -** a string from the stream file stdin then stores the string up to -** n characters to the memory pointed by buf and returns buf. else -** returns NULL. -** [entr] - char *buf; the pointer to the destination string buffer. -** int n; the maximum number of characters to write to buf. -** FILE *stream; the pointer to the FILE stream. -** [exit] - char *; buf if the string is read successfully. else NULL. -** [prec] - buf is a valid memory pointer of n size in bytes and stream is a -** valid FILE pointer. -** [post] - the memory pointed to by buf is modified and the stream file -** pointer is modified. -** -*/ -char *fgets(char *buf, int n, FILE *stream) -{ - char *ret = buf; - int c, done; - - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* cannot read from stdout or stderr. */ - ret = NULL; - break; - default: - for (done = 0; (!done); ) { - switch(c = fgetc(stream)) { - case '\r': - case '\n': - if (n > 0) { - /* newline terminates fgets. */ - *buf++ = '\0'; - --n; - done = 1; - break; - } - break; - case EOF: - /* end of file or error. */ - ret = NULL; - done = 1; - break; - default: - if (n > 0) { - /* store the current character to buf. */ - *buf++ = (char)c; - --n; - } - } - } - } - return (ret); -} -#endif - - -#ifdef F_fopen -/* std I/O internal function. */ -int __stdio_get_fd_type(const char *); - -/* -** -** [func] - fopen. -** [desc] - attempts to open the fname file using the mode file mode. if able -** open the fname then returns the pointer to the FILE stream. else -** returns NULL. -** [entr] - const char *fname; the filename string pointer. -** const char *mode; the file mode string pointer. -** [exit] - FILE *; the pointer the fname FILE stream. else NULL. -** [prec] - fname and mode are valid string pointers. -** [post] - the fname file is opened. -** -*/ -FILE *fopen(const char *fname, const char *mode) -{ - FILE *ret = NULL; - int fd, flag = 0, i, iomode = 0; - - /* ensure file name and mode are not NULL strings. */ - if ((fname != NULL) && (*fname != '\0')) { - if ((mode != NULL) && (*mode != '\0')) { - /* test the file mode. */ - switch(*mode++) { - case 'r': - flag = _IOREAD; - iomode = PSP_O_RDONLY; - break; - case 'w': - flag = _IOWRT; - iomode = (PSP_O_WRONLY | PSP_O_CREAT); - break; - case 'a': - flag = _IORW; - iomode = PSP_O_APPEND; - break; - } - /* test the extended file mode. */ - for (; (*mode++ != '\0'); ) { - switch(*mode) { - case 'b': - continue; - case '+': - flag |= (_IOREAD | _IOWRT); - iomode |= (PSP_O_RDWR | PSP_O_CREAT | PSP_O_TRUNC); - continue; - default: - break; - } - } - /* search for an available fd slot. */ - for (i = 2; i < _NFILE; ++i) if (LOCAL_FILE(&__iob[i])->fd < 0) break; - if (i < _NFILE) { - /* attempt to open the fname file. */ - if ((fd = sceIoOpen((char *)fname, iomode, 0777)) >= 0) { - LOCAL_FILE(&__iob[i])->type = __stdio_get_fd_type(fname); - LOCAL_FILE(&__iob[i])->fd = fd; - LOCAL_FILE(&__iob[i])->cnt = 0; - LOCAL_FILE(&__iob[i])->flag = flag; - LOCAL_FILE(&__iob[i])->has_putback = 0; - ret = (__iob + i); - } - } - } - } - return (ret); -} - -FILE *fopen64(const char *fname, const char *mode) { - return fopen(fname, mode); -} - -#endif - -#ifdef F_fdopen -/* -** -** [func] - fdopen. -** [desc] - produces a file descriptor of type `FILE *', from a -** descriptor for an already-open file (returned, for -** example, by the system subroutine `open' rather than by `fopen'). -** The MODE argument has the same meanings as in `fopen'. -** [entr] - int fd; file descriptor returned by 'open'. -** const char *mode; the file mode string pointer. -** [exit] - file pointer or `NULL', as for `fopen'. -** -*/ -FILE *fdopen(int fd, const char *mode) -{ - FILE *ret = NULL; - int flag = 0, i, iomode = 0; - - /* ensure valid descriptor, and that mode is not a NULL string. */ - if (fd >= 0) { - if ((mode != NULL) && (*mode != '\0')) { - /* test the file mode. */ - switch(*mode++) { - case 'r': - flag = _IOREAD; - iomode = PSP_O_RDONLY; - break; - case 'w': - flag = _IOWRT; - iomode = (PSP_O_WRONLY | PSP_O_CREAT); - break; - case 'a': - flag = _IORW; - iomode = PSP_O_APPEND; - break; - } - /* test the extended file mode. */ - for (; (*mode++ != '\0'); ) { - switch(*mode) { - case 'b': - continue; - case '+': - flag |= (_IOREAD | _IOWRT); - iomode |= (PSP_O_RDWR | PSP_O_CREAT | PSP_O_TRUNC); - continue; - default: - break; - } - } - /* search for an available fd slot. */ - for (i = 2; i < _NFILE; ++i) if (LOCAL_FILE(&__iob[i])->fd < 0) break; - if (i < _NFILE) { - /* attempt to open the fname file. */ - LOCAL_FILE(&__iob[i])->type = STD_IOBUF_TYPE_NONE; - LOCAL_FILE(&__iob[i])->fd = fd; - LOCAL_FILE(&__iob[i])->cnt = 0; - LOCAL_FILE(&__iob[i])->flag = flag; - LOCAL_FILE(&__iob[i])->has_putback = 0; - ret = (__iob + i); - } - } - } - return (ret); -} -#endif - -#ifdef F_fileno -int fileno(FILE * f) { - return LOCAL_FILE(f)->fd; -} -#endif - -#ifdef F_fputc -/* -** -** [func] - fputc. -** [desc] - attempts to write the c character to the stream file. if able to -** write the character to the stream file then returns the character -** written. else returns -1. -** [entr] - int c; the character to write to the file. -** FILE *stream; the pointer to the FILE stream. -** [exit] - int; the character written to the file if successful. else -1. -** [prec] - stream is a valid FILE pointer. -** [post] - the stream file is modified. -** -*/ -int fputc(int c, FILE *stream) -{ - char ch; - - ch = (char)c; - return ((fwrite(&ch, 1, 1, stream) == 1) ? 0 : EOF); -} -#endif - - -#ifdef F_fputs -/* -** -** [func] - fputs. -** [desc] - attempts to write the s string to the stream file. if able to -** successfully write the string to the stream file then returns -** the number of characters written to the file. else returns -1. -** [entr] - const char *s; the source string pointer. -** [exit] - int; the number of chars. written to file if successful. else -1. -** [prec] - stream is a valid FILE pointer and s is a valid string pointer. -** [post] - the stream file is modified. -** -*/ -int fputs(const char *s, FILE *stream) -{ - size_t len; - - int temp = strlen(s); - - len = ((fwrite(s, 1, temp, stream) == temp) ? temp : EOF); - - if (len != EOF) { - fputc('\n', stream); - } - return len + 1; -} -#endif - - -#ifdef F_fread -/* -** -** [func] - fread. -** [desc] - attempts to read n number of records of r size to the stream file -** and returns the number of records successfully read from the file. -** [entr] - void *buf; the pointer to the destination data buffer. -** size_t r; the size of the records to read. -** size_t n; the number of records to read. -** FILE *stream; the pointer to the FILE stream. -** [exit] - size_t; the number of records successfully read from the stream file. -** [prec] - buf is a valid memory pointer of (r * n) size in bytes and stream -** is a valid FILE pointer. -** [post] - the stream file is modified. -** -*/ -size_t fread(void *buf, size_t r, size_t n, FILE *stream) -{ - size_t ret; - - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_NONE: - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* cannot read from stdout or stderr. */ - ret = 0; - break; - default: - /* attempt to read from the stream file. */ - ret = (sceIoRead(LOCAL_FILE(stream)->fd, buf, (int)(r * n)) / (int)r); - } - return (ret); -} -#endif - - -#ifdef F_fseek - -/* -** -** [func] - fseek. -** [desc] - attempts to seek the stream file pointer to offset from origin. -** if able to seek the stream file pointer to offset from origin -** returns 0. else returns -1. -** [entr] - FILE *stream; the pointer to the FILE stream. -** long offset; the seek offset. -** int origin; the seek origin. -** [exit] - int; 0 if able to seek to offset from origin successfully. else -1. -** [prec] - stream is a valid FILE pointer and origin is a valid seek origin -** type. -** [post] - the stream file pointer position is modified. -** -*/ -int fseeko64(FILE *stream, int64_t offset, int origin) -{ - int ret; - - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_NONE: - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* cannot seek stdout or stderr. */ - ret = -1; - break; - default: - /* attempt to seek to offset from origin. */ - ret = ((sceIoLseek(LOCAL_FILE(stream)->fd, offset, origin) >= 0) ? 0 : -1); - } - return (ret); -} - -int fseek(FILE *stream, long offset, int origin) -{ - return fseeko64(stream, (int64_t)offset, origin); -} -#endif - - -#ifdef F_fsetpos -/* -** -** [func] - fsetpos. -** [desc] - attempts to set the stream file pointer position to the pos offset. -** if able to set the stream file pointer position to pos then returns -** 0. else returns -1. -** [entr] - FILE *stream; the pointer to the FILE stream. -** const fpos_t *pos; the pointer to the source file position buffer. -** [exit] - 0 if able to set the stream file pointer position. else -1. -** [prec] - stream is a valid FILE pointer and pos is a valid fpos_t pointer. -** [post] - the stream file pointer position is modified. -** -*/ -int fsetpos(FILE *stream, const fpos_t *pos) -{ - return (fseek(stream, (long)*pos, SEEK_SET)); -} -#endif - - -#ifdef F_ftell -/* -** -** [func] - ftell. -** [desc] - attempts to retrieve the stream file stream pointer position. -** if able to retrieve the stream file stream pointer position -** then returns the position. else sets error code and returns -1. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - long; the stream file pointer position if successful. else -1. -** [prec] - stream is a valid FILE pointer. -** [post] - none. -** -*/ -long ftell(FILE *stream) -{ - long n, ret; - - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_NONE: - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* stdout or stderr is an invalid seek stream argument. */ - errno = EINVAL; - ret = -1L; - break; - default: - if (LOCAL_FILE(stream)->fd < 0) { - /* file is not open. */ - errno = EBADF; - ret = -1L; - } - else ret = (((n = sceIoLseek(LOCAL_FILE(stream)->fd, 0, SEEK_CUR)) >= 0) ? (long)n : -1L); - } - return (ret); -} - -int64_t ftello64(FILE *stream) -{ - int64_t n, ret; - - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_NONE: - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* stdout or stderr is an invalid seek stream argument. */ - errno = EINVAL; - ret = -1L; - break; - default: - if (LOCAL_FILE(stream)->fd < 0) { - /* file is not open. */ - errno = EBADF; - ret = -1L; - } - else ret = (((n = sceIoLseek(LOCAL_FILE(stream)->fd, 0, SEEK_CUR)) >= 0) ? (int64_t)n : -1); - } - return (ret); -} -#endif - - -#ifdef F_fwrite -/* -** -** [func] - fwrite. -** [desc] - attempts to write n number of records of r size to the stream file -** and returns the number of records successfully written to the file. -** [entr] - const void *buf; the pointer to the source data buffer. -** size_t r; the size of the records to write. -** size_t n the number of records to write. -** FILE *stream; the pointer to the FILE stream. -** [exit] - size_t; the number of records successfully written to the stream file. -** [prec] - buf is a valid memory pointer of (r * n) size in bytes and stream -** is a valid FILE pointer. -** [post] - the stream file is modified. -** -*/ -size_t fwrite(const void *buf, size_t r, size_t n, FILE *stream) -{ - size_t ret; - - /* attempt to write the stream file. */ - //ret = (sceIoWrite(stream->fd, (void *)buf, (int)(r * n)) / (int)r); - ret = (sceIoWrite(LOCAL_FILE(stream)->fd, (void *)buf, (int)(r * n)) / (int) r); - - return (ret); -} -#endif - - -#ifdef F_getc -/* Get rid of the newlib macro definition. */ -#ifdef getc -#undef getc -#endif -/* -** -** [func] - getc. -** [desc] - attempts to read one character from the stream file. if able to -** read one character from the file then returns the chaaracter -** read. else EOF. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - int; the character read from the stream file. else -1. -** [prec] - stream is a valid FILE pointer. -** [post] - the stream file is modified. -** -*/ -int getc(FILE *stream) -{ - char c; - int ret; - - switch(LOCAL_FILE(stream)->type) { - case STD_IOBUF_TYPE_NONE: - case STD_IOBUF_TYPE_GE: - case STD_IOBUF_TYPE_STDOUTHOST: - /* cannot read from stdout or stderr. */ - ret = EOF; - break; - default: - ret = ((fread(&c, 1, 1, stream) == 1) ? (int)c : EOF); - } - return (ret); -} -#endif - - -#ifdef F_getchar -/* Get rid of the newlib macro definition. */ -#ifdef getchar -#undef getchar -#endif -/* We can't use the macro version of getc provided in newlib's stdio.h. */ -#ifdef getc -#undef getc -#endif -/* -** -** [func] - getchar. -** [desc] - attempts to read one character from the stdin file stream. if able -** to read one character from the stdin file stream then returns the -** character read. else returns -1. -** [entr] - none. -** [exit] - int; the character read from stdin if successful. else -1. -** [prec] - none. -** [post] - the stdin file stream is modified. -** -*/ -int getchar(void) -{ - return (getc(stdin)); -} -#endif - - -#ifdef F_getfdtype -/* the present working directory variable. */ -#if 0 -char __direct_pwd[256]; -#endif - -/* -** -** [func] - __stdio_get_fd_type. -** [desc] - if s or the present working directory begins with a valid file -** device name then returns the corresponding file descriptor type. -** else returns -1. -** [entr] - const char *s; the source string pointer. -** [exit] - int; the device name file descriptor type if determined. else -1. -** [prec] - s is a valid string pointer. -** [post] - none. -** -*/ -int __stdio_get_fd_type(const char *s) -{ - return (-1); -} -#endif - - -#ifdef F_gets -/* -** -** [func] - gets. -** [desc] - attempts to read a string from stdin. if able to read a string -** from stdin then stores the string to the memory pointed by buf -** and returns buf. else returns NULL. -** [entr] - char *buf; the pointer to the destination string buffer. -** [exit] - char *; buf if string is read successfully. else NULL. -** [prec] - buf is a valid memory pointer. -** [post] - the memory pointed to by buf is modified. -** -*/ -char *gets(char *buf) -{ - return (fgets(buf, INT_MAX, stdin)); -} -#endif - - -#ifdef F_strerror -static const char * file_errors[] = { -"", // 0 -"Not super-user", // 1 -"No such file or directory", // 2 -"No such process", // 3 -"Interrupted system call", // 4 -"I/O error", // 5 -"No such device or address", // 6 -"Arg list too long", // 7 -"Exec format error", // 8 -"Bad file number", // 9 -"No children", // 10 -"No more processes", // 11 -"Not enough core", // 12 -"Permission denied", // 13 -"Bad address", // 14 -"Block device required", // 15 -"Mount device busy", // 16 -"File exists", // 17 -"Cross-device link", // 18 -"No such device", // 19 -"Not a directory", // 20 -"Is a directory", // 21 -"Invalid argument", // 22 -"Too many open files in system", // 23 -"Too many open files", // 24 -"Not a typewriter", // 25 -"Text file busy", // 26 -"File too large", // 27 -"No space left on device", // 28 -"Illegal seek", // 29 -"Read only file system", // 30 -"Too many links", // 31 -"Broken pipe", // 32 -"Math arg out of domain of func", // 33 -"Math result not representable", // 34 -"No message of desired type", // 35 -"Identifier removed", // 36 -"Channel number out of range", // 37 -"Level 2 not synchronized", // 38 -"Level 3 halted", // 39 -"Level 3 reset", // 40 -"Link number out of range", // 41 -"Protocol driver not attached", // 42 -"No CSI structure available", // 43 -"Level 2 halted", // 44 -"Deadlock condition", // 45 -"No record locks available", // 46 -"", // 47 -"", // 48 -"", // 49 -"Invalid exchange", // 50 -"Invalid request descriptor", // 51 -"Exchange full", // 52 -"No anode", // 53 -"Invalid request code", // 54 -"Invalid slot", // 55 -"File locking deadlock error", // 56 -"Bad font file fmt", // 57 -"", // 58 -"", // 59 -"Device not a stream", // 60 -"No data (for no delay io)", // 61 -"Timer expired", // 62 -"Out of streams resources", // 63 -"Machine is not on the network", // 64 -"Package not installed", // 65 -"The object is remote", // 66 -"The link has been severed", // 67 -"Advertise error", // 68 -"Srmount error", // 69 -"Communication error on send", // 70 -"Protocol error", // 71 -"", // 72 -"", // 73 -"Multihop attempted", // 74 -"Inode is remote (not really error)", // 75 - - -"Cross mount point (not really error)", // 76 -"Trying to read unreadable message", // 77 -"", // 78 -"Inappropriate file type or format", // 79 -"Given log. name not unique", // 80 -"f.d. invalid for this operation", // 81 -"Remote address changed", // 82 -"Can't access a needed shared lib", // 83 -"Accessing a corrupted shared lib", // 84 -".lib section in a.out corrupted", // 85 -"Attempting to link in too many libs", // 86 -"Attempting to exec a shared library", // 87 -"Function not implemented", // 88 -"No more files", // 89 -"Directory not empty", // 90 -"File or path name too long", // 91 -"Too many symbolic links", // 92 -"", // 93 -"", // 94 -"Operation not supported on transport endpoint", // 95 -"Protocol family not supported", // 96 -"", // 97 -"", // 98 -"", // 99 -"", // 100 -"", // 101 -"", // 102 -"", // 103 -"Connection reset by peer", // 104 -"No buffer space available", // 105 -"Address family not supported by protocol family", // 106 -"Protocol wrong type for socket", // 107 -"Socket operation on non-socket", // 108 -"Protocol not available", // 109 -"Can't send after socket shutdown", // 110 -"Connection refused", // 111 -"Address already in use", // 112 -"Connection aborted", // 113 -"Network is unreachable", // 114 -"Network interface is not configured", // 115 -"Connection timed out", // 116 -"Host is down", // 117 -"Host is unreachable", // 118 -"Connection already in progress", // 119 -"Socket already connected", // 120 -"Destination address required", // 121 -"Message too long", // 122 -"Unknown protocol", // 123 -"Socket type not supported", // 124 -"Address not available", // 125 -"", // 126 -"Socket is already connected", // 127 -"Socket is not connected", // 128 -"", // 129 -"EPROCLIM", // 130 -"EUSERS", // 131 -"EDQUOT", // 132 -"ESTALE", // 133 -"Not supported", // 134 -"No medium (in tape drive)", // 135 -"No such host or network path", // 136 -"Filename exists with different case", // 137 -"EILSEQ", // 138 -"Value too large for defined data type", // 139 -""}; -#define error_to_string(errnum) (file_errors[errnum*-1]) - -char * strerror(int err) { - return (char *) error_to_string(err); -} -#endif - - -#ifdef F_perror -/* -** -** [func] - perror. -** [desc] - if there is a current error then prints the corresponding error -** and then prints s to stderr. else prints s to stderr. -** [entr] - const char *s; the error string pointer. -** [exit] - none. -** [prec] - s is a valid string pointer. -** [post] - none. -** -*/ -void perror(const char *s) -{ - char *err; - - /* print to stderr output. */ - if ((err = strerror(errno)) != NULL) fprintf(stderr, "%s : ", err); - fputs(s, stderr); -} -#endif - - -#ifdef F_putc -/* Get rid of the newlib macro definition. */ -#ifdef putc -#undef putc -#endif -/* std I/O data variable. */ -#ifdef USE_GS -extern int __stdio_stdout_xy[2]; - - -/* stdio internal function. */ -void __stdio_update_stdout_xy(int, int); -#endif - -/* -** -** [func] - putc. -** [desc] - attempts to write the c character to the stream file. if able to -** write the character to the stream file then returns the character -** written. else returns -1. -** [entr] - int c; the character to write to the file. -** FILE *stream; the pointer to the FILE stream. -** [exit] - int; the character written to the file if successful. else -1. -** [prec] - stream is a valid FILE pointer. -** [post] - the stream file is modified. -** -*/ -int putc(int c, FILE *stream) -{ - char ch; - int ret = 0; - - switch(LOCAL_FILE(stream)->type) { - break; - default: - /* write one character to the stream file. */ - ch = (char)c; - ret = ((fwrite(&ch, 1, 1, stream) == 1) ? c : EOF); - } - return (ret); -} -#endif - - -#ifdef F_putchar -/* We can't use the macro version of putc provided in newlib's stdio.h. */ -#ifdef putc -#undef putc -#endif -/* -** -** [func] - putchar. -** [desc] - attempts to write the c character to stdout. if able to write -** the character to stdout then returns the character written. -** else returns -1. -** [entr] - int c; the character to write to stdout. -** [exit] - int; the character written to stdout. else -1. -** [prec] - none. -** [post] - the stdout file stream is modified. -** -*/ -int putchar(int c) -{ - return (putc(c, stdout)); -} -#endif - - -#ifdef F_puts -/* We can't use the macro version of putc provided in newlib's stdio.h. */ -#ifdef putc -#undef putc -#undef putchar -#endif -/* -** -** [func] - puts. -** [desc] - attempts to write the s string to stdout. if able to write the s -** string to stdout then returns the number of characters written. -** else returns -1. -** [entr] - const char *s; the source string pointer. -** [exit] - int; the number of characters written to stdout. else -1. -** [prec] - s is a valid string pointer. -** [post] - the stdout file stream is modified. -** -*/ -int puts(const char *s) -{ - int ret; - - for (ret = 0; (*s != '\0'); ++s) { - /* attempt to print the current character to stdout. */ - if ((putchar(*s) == (int)*s) && (ret >= 0)) ++ret; - else ret = EOF; - } - if ((putchar('\n') == '\n') && (ret >= 0)) ++ret; - else ret = EOF; - return (ret); -} -#endif - - -#ifdef F_remove -/* -** -** [func] - remove. -** [desc] - if the s named file exists then deletes the s named file and -** returns 0. else returns -1. -** [entr] - const char *s; the filename string pointer. -** [exit] - int; 0 if able to delete the s file. else -1. -** [prec] - s is a valid string pointer. -** [post] - the s file is deleted. -** -*/ -int remove(const char *s) -{ - int ret = sceIoRemove(s); - - return (ret); -} -#endif - - -#ifdef F_rename -/* -** -** [func] - rename. -** [desc] - -** [entr] - const char *name; the filename string pointer. -** const char *newname; the new filename string pointer. -** [exit] - int; -** [prec] - name and newname are valid string pointers. -** [post] - the name filen name is modified. -** -*/ -int rename(const char *name, const char *newname) -{ - int ret = sceIoRename(name, newname); - - return (ret); -} -#endif - - -#ifdef F_rewind -/* -** -** [func] - rewind. -** [desc] - resets the stream file pointer to 0. -** [entr] - FILE *stream; the pointer to the FILE stream. -** [exit] - none. -** [prec] - stream is a valid FILE pointer. -** [post] - the stream file pointer is modified. -** -*/ -void rewind(FILE *stream) -{ - fseek(stream, 0, SEEK_SET); -} -#endif - - -#ifdef F_skipatoi -/* -** -** [func] - __stdio_skip_atoi. -** [desc] - -** [entr] - const char **s; the pointer to the source string pointer. -** [exit] - int; -** [prec] - s is a valid pointer to string pointer. -** [post] - the memory pointed to by s is modified. -** -*/ -int __stdio_skip_atoi(const char **s) -{ - int ret = 0; - - for (; (isdigit(**s) != 0); ) ret = ((ret * 10) + (*((*s)++) - '0')); - return (ret); -} -#endif - -//Do not uncomment until vsscanf is implemented - Warren -//#ifdef F_sscanf -/* -** -** [func] - sscanf. -** [desc] - -** [entr] - const char *buf; -** const char *format; the format string pointer. -** ...; -** [exit] - int; -** [prec] - buf and format are valid string pointers. -** [post] - the memory pointed to by format string arguments are -** -*/ -/* -int sscanf(const char *buf, const char *format, ...) -{ - int ret; - va_list va; - - va_start(va, format); - ret = vsscanf(buf, format, va); - va_end(va); - return (ret); -}*/ -//#endif - - -#ifdef F__stdio -/* stdio data variables. */ -FILE __iob[_NFILE] = { - { -1, 0, 0, 0 }, // stdin - { STD_IOBUF_TYPE_STDOUTHOST, 1, 0, 0 }, // stdout - { STD_IOBUF_TYPE_STDOUTHOST, 2, 0, 0 }, // stdout - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 }, - { 0, -1, 0, 0 } -}; -char __stdio_tmpnam[256]; -#ifdef USE_GS -int __stdio_stdout_xy[2]; -#endif -#endif - - -#ifdef F_tmpfile -/* stdio temp name variable. */ -extern char __stdio_tmpnam[256]; - - -/* -** -** [func] - tmpfile. -** [desc] - attempts to create a temporary file. if able to create a temporary -** file then returns the pointer to the FILE stream. else returns NULL. -** [entr] - none. -** [exit] - FILE *; the ptr. to the opened temp. file if successful. else NULL. -** [prec] - none. -** [post] - a temporary is opened. -** -*/ -FILE *tmpfile(void) -{ - return ((tmpnam(NULL) != NULL) ? fopen(__stdio_tmpnam, "rw+") : NULL); -} -#endif - - -#ifdef F_tmpnam -/* stdio temp name variable. */ -extern char __stdio_tmpnam[256]; - - -/* -** -** [func] - tmpnam. -** [desc] - creates a temporary filename string, -** [entr] - char *name; the pointer to the destination string pointer. -** [exit] - char *; -** [prec] - -** [post] - -** -*/ -char *tmpnam(char *name) -{ - char *ret = NULL; - - return (ret); -} -#endif - - -#ifdef F_ungetc -/* -** -** [func] - ungetc. -** [desc] - -** [entr] - int c; -** FILE *stream; the pointer to the FILE stream. -** [exit] - int; -** [prec] - stream is a valid FILE pointer. -** [post] - the stream FILE stream is modified. -** -*/ -int ungetc(int c, FILE *stream) -{ - // int ret = EOF; - - if (c == EOF || LOCAL_FILE(stream)->has_putback) { - /* invalid input, or putback queue full */ - return EOF; - } - - LOCAL_FILE(stream)->putback = (u8)c; - LOCAL_FILE(stream)->has_putback = 1; - return c; -} -#endif - - -#ifdef F_updatestdoutxy -/* std I/O data variable. */ -#ifdef USE_GS -extern int __stdio_stdout_xy[2]; -#endif - -/* -** -** [func] - __stdio_update_stdout_xy. -** [desc] - updates the stdout (x, y) screen coordinates. -** [entr] - int x; the x screen coordinate. -** int y; the y screen coordinate. -** [exit] - none. -** [prec] - none. -** [post] - the stdout screen coordinates are modified. -** -*/ -void __stdio_update_stdout_xy(int x, int y) -{ -#ifdef USE_GS - if ((x * 16) >= gsGetDisplayWidth()) { - x = 0; - ++y; - } - if ((y * 16) >= gsGetDisplayHeight()) y = 0; - __stdio_stdout_xy[0] = x; - __stdio_stdout_xy[1] = y; -#endif -} -#endif - - -#ifdef F___stdio_internals -void _pspsdk_stdio_init() -{ -} - -void _pspsdk_stdio_deinit() -{ -} -#endif diff --git a/src/libc/stdio.h b/src/libc/stdio.h deleted file mode 100644 index e6cecc28..00000000 --- a/src/libc/stdio.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * stdio.h - * - * Copyright (c) 2002-2004 PS2DEV - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ - -#ifndef __STDIO_H__ -#define __STDIO_H__ - -#include -#include -#include -#define STDIN_FILENO 0 -#define STDOUT_FILENO 1 -#define STDERR_FILENO 2 - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Some aliases for the unix 'unistd' functions */ -static __inline__ int open(const char *fname, int flags, ...) { return sceIoOpen(fname, flags, 0777); } -static __inline__ int close(int handle) { return sceIoClose(handle); } -static __inline__ ssize_t read(int handle, void * buffer, size_t size) { return sceIoRead(handle, buffer, size); } -static __inline__ ssize_t write(int handle, const void * buffer, size_t size) { return sceIoWrite(handle, buffer, size); } -static __inline__ off_t lseek(int handle, off_t position, int wheel) { return sceIoLseek(handle, position, wheel); } -static __inline__ off_t tell(int handle) { return sceIoLseek(handle, 0, 1); } - -/* Some win32 equivalents... baaah */ -#define _open open -#define _close close -#define _read read -#define _write write -#define _lseek lseek - -#define _O_APPEND O_APPEND -#define _O_BINARY O_BINARY -#define _O_CREAT O_CREAT -#define _O_RDONKY O_RDONKY -#define _O_RDWR O_RDWR -#define _O_TEXT O_TEXT -#define _O_TRUNC O_TRUNC -#define _O_WRONLY O_WRONLY - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifndef O_TEXT -#define O_TEXT 0 -#endif - - -#define BUFSIZ 1024 - -#define _NFILE 16 - - -#define _IOFBF 0x0000 -#define _IOLBF 0x0100 -#define _IONBF 0x0004 -#define _IOEOF 0x0020 -#define _IOERR 0x0040 - -#define _IOREAD 0x0001 -#define _IOWRT 0x0002 -#define _IORW 0x0200 -#define _IOMYBUF 0x0010 - - -/* ensure EOF is defined. */ -#ifndef EOF -#define EOF (-1) -#endif - - -#define FOPEN_MAX _NFILE -#define FILENAME_MAX 1024 - - -#define SEEK_SET 0 -#define SEEK_CUR 1 -#define SEEK_END 2 - - -/* ensure fpos_t is defined. */ -#ifndef __FPOS_T_DEFINED -#define __FPOS_T_DEFINED -typedef long fpos_t; -#endif // __FPOS_T_DEFINED - - -/* ensure FILE is defined. */ -#ifndef __FILE_DEFINED -#define __FILE_DEFINED -typedef struct { - int type; - int fd; - int cnt; - int flag; - int has_putback; - u8 putback; -} FILE; -#endif // __FILE_DEFINED - - -extern FILE __iob[_NFILE]; - - -#define stdin (&__iob[0]) -#define stdout (&__iob[1]) -#define stderr (&__iob[2]) - - -/* function declarations. */ -void clearerr(FILE *); -int feof(FILE *); -int ferror(FILE *); -FILE *fopen(const char *, const char *); -FILE *fopen64(const char *, const char *); -FILE *fdopen(int, const char *); -int fclose(FILE *); -int fflush(FILE *); -int fgetc(FILE *); -int fgetpos(FILE *, fpos_t *); -int fgetpos64(FILE *, int64_t *); -char *fgets(char *, int, FILE *); -int fileno(FILE *); -int fputc(int, FILE *); -int fputs(const char *, FILE *); -size_t fread(void *, size_t, size_t, FILE *); -FILE *freopen(const char *, const char *, FILE *); -int fscanf(FILE *, const char *, ...); -int fseek(FILE *, long, int); -int fseeko64(FILE *, int64_t, int); -int fsetpos(FILE *, const fpos_t *); -long ftell(FILE *); -int64_t ftello64(FILE *); -size_t fwrite(const void *, size_t, size_t, FILE *); -int getc(FILE *); -int getchar(void); -char *gets(char *); -void perror(const char *); -int putc(int, FILE *); -int puts(const char *); -int remove(const char *); -int rename(const char *, const char *); -void rewind(FILE *); -int scanf(const char *, ...); -int setbuf(FILE *, char *); -int setvbuf(FILE *, char *, int, size_t); -int sscanf(const char *, const char *, ...); -FILE *tmpfile(void); -char *tmpnam(char *); -int vfscanf(FILE *, const char *, va_list); -int vscanf(const char *, va_list); -int vsscanf(const char *, const char *, va_list); -int vxscanf(int (*xgetc)(void **), void (*xungetc)(int, void **), void *stream, const char *, va_list); -int xscanf(int (*xgetc)(void **), void (*xungetc)(int, void **), void *stream, const char *, ...); - -int ungetc(int, FILE *); - -int _fcloseall(void); -int _fflushall(void); - -int chdir(const char *path); - - -/* from xprintf */ -int vxprintf(void (*func)(char*, int, void *), void * arg, const char * format, va_list ap); -int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap); -int vsprintf(char *buf, const char *fmt, va_list ap); -char *vmprintf(const char *zFormat, va_list ap); -int vfprintf(FILE *pOut, const char *zFormat, va_list ap); -int vprintf(const char *format, va_list ap); -int vasprintf(char **strp, const char *format, va_list ap); - -int xprintf(void (*func)(char*, int, void *), void * arg, const char * format, ...) - __attribute__((format(printf,3,4))); -int snprintf(char *str, size_t sz, const char *format, ...) - __attribute__((format(printf,3,4))); -int sprintf(char *buf, const char *fmt, ...) - __attribute__((format(printf,2,3))); -char *mprintf(const char *zFormat, ...) - __attribute__((format(printf,1,2))); -int fprintf(FILE *pOut, const char *zFormat, ...) - __attribute__((format(printf,2,3))); -int printf(const char *format, ...) - __attribute__((format(printf,1,2))); -int asprintf(char **strp, const char *format, ...) - __attribute__((format(printf,2,3))); - -int putchar(int); - -int npmPuts(const char *buf); -int nprintf(const char *format, ...); -int vnprintf(const char *format, va_list args); -int sio_printf(const char *format, ...); - -#ifdef __cplusplus -} -#endif - - -#endif // __STDIO_H__ diff --git a/src/libc/stdlib.c b/src/libc/stdlib.c deleted file mode 100644 index e807b72a..00000000 --- a/src/libc/stdlib.c +++ /dev/null @@ -1,1238 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * stdlib.c - Stdlib's functions, without allocs (see alloc.c) - * - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ -#include -#include -#include -#include -#include - -extern void (* __stdlib_exit_func[32])(void); -extern int __stdlib_exit_index; - -// This function is missing... -char *__stdlib_ecvt(double, size_t, int *, int *); - -#ifndef __ENVIRONVARIABLE_T_DEFINED -#define __ENVIRONVARIABLE_T_DEFINED -typedef struct { - char name[256]; - char value[256]; -} environvariable_t; -#endif // __ENVIRONVARIABLE_T_DEFINED - -extern environvariable_t __stdlib_env[32]; -extern int __stdlib_mb_shift; -extern unsigned int __stdlib_rand_seed; - -int isspace(int); -int isdigit(int); -int isalpha(int); -int isupper(int); - -#ifdef F_abs -/* -** -** [func] - abs. -** [desc] - returns the absolute value of the integer c. -** [entr] - int c; the integer value. -** [exit] - int; the absolute value of the integer c. -** [prec] - none. -** [post] - none. -** -*/ - -// shouldn't we rather put that as a macro... ? -int abs(int c) -{ - return ((c >= 0) ? c : -c); -} -#endif - - -#ifdef F_atexit -/* -** -** [func] - atexit. -** [desc] - if the current amount of registered exit() functions has not -** been reached then registers the func parameter function to the -** list and returns 0. else returns non-zero. -** [entr] - void (*func)(void); the pointer to the exit function. -** [exit] - int; 0 if albe to register the func exit() function. else non-zero. -** [prec] - func is a valid function pointer. -** [post] - the atexit() function list is modified. -** -*/ -int atexit(void (*func)(void)) -{ - int ret; - - if (__stdlib_exit_index < 32) { - /* register func to the exit() function list. */ - __stdlib_exit_func[__stdlib_exit_index++] = func; - ret = 0; - } - else ret = -1; - return (ret); -} -#endif - - -#ifdef F_atof -/* -** -** [func] - atof. -** [desc] - if the string s begins with a valid floating point string then -** returns the floating point value of the string s. else returns 0.** -** [entr] - const char *s; the source string pointer. -** [exit] - double; the floating point value of the string s. else 0. -** [prec] - s is a valid string pointer. -** [post] - none. -* -*/ - -// macro... maybe ? :) -double atof(const char *s) -{ - return (strtod(s, NULL)); -} -#endif - -#ifdef F_bsearch -/* -** -** [func] - bsearch. -** [desc] - -** [entr] - const void *key; the pointer to the search key object. -** const void *base; the pointer to the base of the search data. -** size_t count; the number of elements in the search data. -** size_t size; the size of the search elements. -** int (* compare)(const void *, const void *); the pointer to the compare function. -** [exit] - void *; -** [prec] - -** [post] - -** -*/ -void *bsearch(const void *key, const void *base, size_t count, size_t size, int (* compare)(const void *, const void *)) -{ - int comparison; - size_t l, u, idx; - void *ret = NULL; - const void *p; - - /* perform a binary search of a sorted array. */ - for (l = 0, u = count; l < u; ) { - idx = ((l + u) / 2); - /* calculate the pointer index. */ - p = (const void *)((const char *)base + (idx * size)); - comparison = (*compare)(key, p); - if (comparison < 0) u = idx; - else if (comparison > 0) l = (idx + 1); - else { - /* return the pointer. */ - ret = (void *)p; - break; - } - } - return (ret); -} -#endif - - -#ifdef F_div -/* -** -** [func] - div. -** [desc] - -** [entr] - int n; the integer numerator. -** int d; the integer divisor. -** [exit] - div_t; -** [prec] - none. -** [post] - none. -** -*/ -div_t div(int n, int d) -{ - div_t ret; - - /* calculate the quotient and remainder. */ - // duh... can't this be written with some asm "mfhi/mflo" ? - ret.quot = (n / d); - ret.rem = (n % d); - return (ret); -} -#endif - - -#if F_exit -/* -** -** [func] - exit. -** [desc] - calls all the register exit() functions and returns to PlayStation2 -** OSD. -** [entr] - int status; the exit status code. -** [exit] - this function deos not return. -** [prec] - none. -** [post] - none. -** -*/ -void exit(int status) -{ - int i; - - for (i=(__stdlib_exit_index-1); i>=0; i--) - __stdlib_exit_func[i](); - - _Exit(status); -} -#endif - - -#if 0 -/* -** -** [func] - _gcvt.c -** [desc] - -** [entr] - double x; -** size_t n; -** char *buf; -** [exit] - char *; -** [prec] - -** [post] - -** -*/ - -// why the underscore ? win32 or what ? -// won't link anyway. -char *_gcvt(double x, size_t n, char *buf) -{ - int decpt, i, sign; - char *p1, *p2; - - p1 = __stdlib_ecvt(x, n, &decpt, &sign); - p2 = buf; - if (sign) *p2++ = '-'; - for (i = (n - 1); ((i > 0) && (p1[i] == '0')); --i) --n; - i = (int)n; - if (((decpt >= 0) && (decpt - i > 4)) || ((decpt < 0) && (decpt < -3))) { - --decpt; - *p2++ = *p1++; - *p2++ = '.'; - for (i = 1; i < n; ++i) *p2++ = *p1++; - *p2++ = 'e'; - if (decpt < 0) { - decpt = -decpt; - *p2++ = '-'; - } - else *p2++ = '+'; - if ((decpt / 100) > 0) *p2++ = ((decpt / 100) + '0'); - if ((decpt / 10) > 0) *p2++ = (((decpt % 100) / 10) + '0'); - *p2++ = decpt%10 + '0'; - } - else { - if (decpt <= 0) { - if (*p1!='0') *p2++ = '.'; - while (decpt < 0) { - ++decpt; - *p2++ = '0'; - } - } - for (i = 1; i <= n; ++i) { - *p2++ = *p1++; - if (i == decpt) *p2++ = '.'; - } - if (n < decpt) { - while (n++ < decpt) *p2++ = '0'; - *p2++ = '.'; - } - } - if (p2[-1]=='.') p2--; - *p2 = '\0'; - return(buf); -} -#endif - - -#ifdef F_getenv -/* -** -** [func] - getenv. -** [desc] - if name is an existing environment variable name then returns the -** poiinter to the corresponding environment variable string value. -** else returns NULL. -** [entr] - const char *name; the environment name string pointer. -** [exit] - char *; the ptr. to the corres. environment variable string. else NULL. -** [prec] - name is a valid string pointer. -** [post] - none. -** -*/ -char *getenv(const char *name) -{ - int i; - char *ret = NULL; - - /* search for matching environment variable name. */ - for (i = 0; i < 32; ++i) { - if (strcmp(name, __stdlib_env[i].name) == 0) { - /* return the environment variable value. */ - ret = (char *)__stdlib_env[i].value; - break; - } - } - return (ret); -} -#endif - - -#ifdef F__itoa -/* -** -** [func] - _itoa. -** [desc] - -** [entr] - int n; the integer value to convert. -** char *buf; the pointer to the destination memory buffer. -** int radix; the conversion number base. -** [exit] - char *; buf. -** [prec] - buf is a valid memory pointer. -** [post] - the memory pointed to by buf is modified. -** -*/ -char *_itoa(int n, char *buf, int radix) -{ - char *ret = buf; - char tmp[33]; - int i = 0, j, r; - - /* validate the conversion number base. */ - if ((radix >= 2) && (radix <= 36)) { - if ((radix == 10) && (n < 0)) { - /* negative integer value. */ - *buf++ = '-'; - n = -n; - } - do { - /* calculate the current digit. */ - r = (int)((unsigned int)n % radix); - tmp[i++] = ((r < 10) ? (r + '0') : (r - 10 + 'a')); - } while ((n /= radix) != 0); - /* reverse the buffer string. */ - for (--i, j = 0; (i >= 0); --i, ++j) buf[j] = tmp[i]; - buf[j] = 0; - } - return (ret); -} -#endif - - -#ifdef F_labs -/* -** -** [func] - labs. -** [desc] - returns the absolute value of the long integer n. -** [entr] - long n; the long integer value. -** [exit] - long; the absolute value of the long integer n. -** [prec] - none. -** [post] - none. -** -*/ -long labs(long n) -{ - return ((n >= 0) ? n : -n); -} -#endif - - -#ifdef F_ldiv -/* -** -** [func] - ldiv. -** [desc] - -** [entr] - long n; the long integer numerator. -** long d; the long integer denominator. -** [exit] - ldiv_t; -** [prec] - -** [post] - -** -*/ -ldiv_t ldiv(long n, long d) -{ - ldiv_t ret; - - ret.quot = (n / d); - ret.rem = (n % d); - return (ret); -} -#endif - - -#ifdef F_llabs -/* -** -** [func] - llabs. -** [desc] - returns the absolute value of the long long integer n. -** [entr] - long n; the long long integer value. -** [exit] - long; the absolute value of the long long integer n. -** [prec] - none. -** [post] - none. -** -*/ -long long llabs(long long n) -{ - return ((n >= 0) ? n : -n); -} -#endif - - -#ifdef F_lldiv -/* -** -** [func] - lldiv. -** [desc] - -** [entr] - long long n; the long long integer numerator. -** long long d; the long long integer denominator. -** [exit] - ldiv_t; -** [prec] - -** [post] - -** -*/ -lldiv_t lldiv(long long n, long long d) -{ - lldiv_t ret; - - ret.quot = (n / d); - ret.rem = (n % d); - return (ret); -} -#endif - - -#ifdef F__lltoa -/* -** -** [func] - _lltoa. -** [desc] - -** [entr] - long long n; the long long integer value to convert. -** char *buf; the pointer to the destination memory buffer. -** int radix; the conversion number base. -** [exit] - char *; buf. -** [prec] - buf is a valid memory pointer. -** [post] - the memory pointed to by buf is modified. -** -*/ -char *_lltoa(long long n, char *buf, int radix) -{ - char *ret = buf; - char tmp[65]; - int i = 0, j; - long long r; - - /* validate the conversion number base. */ - if ((radix >= 2) && (radix <= 36)) { - if ((radix == 10) && (n < 0)) { - /* negative integer value. */ - *buf++ = '-'; - n = -n; - } - do { - /* calculate the current digit. */ - r = (long long)((unsigned long long)n % radix); - tmp[i++] = ((r < 10) ? (r + '0') : (r - 10 + 'a')); - } while ((n /= radix) != 0); - /* reverse the buffer string. */ - for (--i, j = 0; (i >= 0); --i, ++j) buf[j] = tmp[i]; - buf[j] = 0; - } - return (ret); -} -#endif - - -#ifdef F__ltoa -/* -** -** [func] - _ltoa. -** [desc] - -** [entr] - long n; the long integer value to convert. -** char *buf; the pointer to the destination memory buffer. -** int radix; the conversion number base. -** [exit] - char *; buf. -** [prec] - buf is a valid memory pointer. -** [post] - the memory pointed to by buf is modified. -** -*/ -char *_ltoa(long n, char *buf, int radix) -{ - char *ret = buf; - char tmp[33]; - int i = 0, j; - long r; - - /* validate the conversion number base. */ - if ((radix >= 2) && (radix <= 36)) { - if ((radix == 10) && (n < 0)) { - /* negative integer value. */ - *buf++ = '-'; - n = -n; - } - do { - /* calculate the current digit. */ - r = (long)((unsigned long)n % radix); - tmp[i++] = ((r < 10) ? (r + '0') : (r - 10 + 'a')); - } while ((n /= radix) != 0); - /* reverse the buffer string. */ - for (--i, j = 0; (i >= 0); --i, ++j) buf[j] = tmp[i]; - buf[j] = 0; - } - return (ret); -} -#endif - - -#ifdef F_mblen -/* -** -** [func] - mblen. -** [desc] - if s is a valid multibyte character then returns the length -** of the multibyte character s. else returns 0. -** [entr] - const char *s; -** size_t n; the length of the multibyte character s. else 0. -** [exit] - int; -** [prec] - s is a valid string pointer. -** [post] - none. -** -*/ -int mblen(const char *s, size_t n) -{ - return (mbtowc((wchar_t *)NULL, s, n)); -} -#endif - - -#ifdef F_mbstowcs -/* -** -** [func] - mbstowcs. -** [desc] - if s is a valid multibyte string then converts the multibyte -** string to a wide-character string and returns the length of -** the wide-character string. else returns -1. -** [entr] - wchar_t *ws; the destination wide-character string pointer. -** const char *s; the source multibyte string pointer. -** size_t n; the maximum number of characters to convert. -** [exit] - size_t; the length of the wide-character string. else -1. -** [prec] - ws is a valid wide-character string pointer and s is a valid -** string pointer. -** [post] - the memory pointed to by ws is modified. -** -*/ -size_t mbstowcs(wchar_t *ws, const char *s, size_t n) -{ - int len, shift; - size_t ret = -1; - - /* convert the multibyte string to wide-character string. */ - for (shift = __stdlib_mb_shift; *s != '\0'; ) { - if (__isascii(*s) != 0) { - /* multibyte character is ascii. */ - *ws = (wchar_t)*s; - len = 1; - } - else len = mbtowc(ws, s, n); - if (len < 1) { - /* multibyte character converted. */ - ++ws; - ++ret; - s += len; - n -= len; - } - else { - /* error occured. */ - ret = -1; - break; - } - } - /* append NULL terminator. */ - if (n > 0) *ws = (wchar_t)'\0'; - __stdlib_mb_shift = shift; - return (ret); -} -#endif - - -#ifdef F_mbtowc -/* -** -** [func] - mbtowc. -** [desc] - attempts to convert the s multi-byte character to the corresponding -** wide-character. if able to convert the s multi-byte character to the -** corresponding wide-character then stores the resulitng wide-character -** to the memory pointed to by wc and returns the number of bytes for -** the multi-byte character. else if the multi-byte character is '\0' -** then returns 1. else returns -1. -** [entr] - wchar_t *wc; the source wide-character string pointer. -** const char *s; the pointer to the destination multi-byte string buffer. -** size_t n; the number of bytes to check. -** [exit] - int; the number of bytes for mb char. else 1 if mb char is '\0'. else -1. -** [prec] - wc is a valid wchar_t pointer and s is a valid string pointer. -** [post] - the memory pointed to by wc is modified. -** -*/ -int mbtowc(wchar_t *wc, const char *s, size_t n) -{ - int ret = -1; - const mbchar_t *mb; - wchar_t i; - - /* test for NULL source string pointer. */ - if (s != NULL) { - if (*s != '\0') { - /* test if the multi-byte conversion table has initialized. */ - if ((_ctype_info->mbchar == NULL) || (_ctype_info->mbchar->chars == NULL)) { - if (wc != NULL) { - *wc = (wchar_t)*s; - ret = 1; - } - } - else { - /* search only up to maximum current multi-byte bytes. */ - if (n > MB_CUR_MAX) n = MB_CUR_MAX; - for (i = 0; i < WCHAR_MAX; ++i) { - /* process the curent multi-byte character. */ - mb = &_ctype_info->mbchar->chars[i]; - if ((i == (wchar_t)EOF) || (i == (wchar_t)'\0')) continue; - else if (__isascii(i)) continue; - else if ((mb->string == NULL) || (mb->len == 0)) continue; - else if (mb->len > n) continue; - else if (strncmp(mb->string, s, mb->len) == 0) { - if (wc != NULL) *wc = i; - __stdlib_mb_shift += mb->shift; - ret = mb->len; - break; - } - } - } - } - else ret = 0; - } - else ret = (__stdlib_mb_shift != 0); - return (ret); -} -#endif - - -#ifdef F_rand -/* -** -** [func] - rand. -** [desc] - returns the random number generated from the current stdlib random -** seed. -** [entr] - none. -** [exit] - int; the random number generated from the current stdlib random seed. -** [prec] - none. -** [post] - the stdlib random seed is modified. -** -*/ -int rand(void) -{ -// I don't agree with it... -// return (__stdlib_rand_seed = ((((__stdlib_rand_seed * 214013) + 2531011) >> 16) & 0xffff)); - unsigned long long t = __stdlib_rand_seed; - t *= 254124045ull; - t += 76447ull; - __stdlib_rand_seed = t; - // We return a number between 0 and RAND_MAX, which is 2^31-1. - return (t >> 16) & 0x7FFFFFFF; -} -#endif - - -#ifdef F_setenv -/* -** -** [func] - setenv. -** [desc] - if name is an existing environment variable and rewrite is non-zero -** then overwrites the name environment variable value with value and -** returns 0. else if name is not an existring environment variable and -** there is a free environment variable slot available then sets the -** name environment variable and returns 0. else returns -1. -** [entr] - const char *name; the environment variable name string pointer. -** const char *value; the environment variable value string pointer. -** int rewrite; the overwrite flag. -** [exit] - int; 0 if able to set the environment variable successfully. else -1. -** [prec] - name and value are valid string pointers. -** [post] - the name environment variable is set. -** -*/ -int setenv(const char *name, const char *value, int rewrite) -{ - int done, i, ret = -1; - - /* search for matching environment variable name. */ - for (i = 0, done = 0; i < 32; ++i) { - if (strcmp(name, __stdlib_env[i].name) == 0) { - if (rewrite) { - /* overwrite the current environment variable value. */ - strncpy(__stdlib_env[i].value, value, 255); - __stdlib_env[i].value[255] = 0; - ret = 0; - } - done = 1; - break; - } - } - if (!done) { - /* search for a free environment variable slot. */ - for (i = 0; i < 32; ++i) { - if (__stdlib_env[i].name[0] == '\0') { - /* set the name environment variable. */ - strncpy(__stdlib_env[i].name, name, 255); - __stdlib_env[i].name[255] = 0; - strncpy(__stdlib_env[i].value, value, 255); - __stdlib_env[i].value[255] = 0; - ret = 0; - break; - } - } - } - return (ret); -} -#endif - - -#ifdef F_srand -/* -** -** [func] - srand. -** [desc] - sets the current stdlib random seed to seed. -** [entr] - unsigned int seed; the stdlib random seed. -** [exit] - none. -** [prec] - none. -** [post] - none. -** -*/ -void srand(unsigned int seed) -{ - __stdlib_rand_seed = seed; -} -#endif - - -#ifdef F___stdlib_internals -/* stdlib data variables. */ -environvariable_t __stdlib_env[32]; -void (* __stdlib_exit_func[32])(void); -int __stdlib_exit_index = 0; -int __stdlib_mb_shift = 0; -unsigned int __stdlib_rand_seed = 92384729; -#endif - - -#ifdef F_strtod -/* -** -** [func] - strtod. -** [desc] - if s is a valid floating point number string then converts the -** string to it's corresponding float point value and returns the -** value. else returns 0.0. if eptr is not NULL then stores the -** pointer to the last processed character in the string. -** [entr] - const char *s; the source string pointer. -** char **endptr; the pointer to the store string end pointer. -** [exit] - double; the converted 64-bit float value. else 0.0. -** [prec] - s is a valid string pointer and eptr is a valid string pointer -** pointer. -** [post] - the memory pointed to by eptr is modified. -** -*/ -double strtod(const char *s, char **eptr) -{ - double d, ret = 0.0, sign = 1.0; - int e = 0, esign = 1, flags = 0, i; - - /* remove leading white spaces. */ - for (; (isspace(*s) != 0); ) ++s; - if (*s == '-') { - /* negative value. */ - sign = -1.0; - ++s; - } - else if (*s == '+') ++s; - for (; (isdigit(*s) != 0); ++s) { - /* process digits before decimal point. */ - flags |= 1; - ret *= 10.0; - ret += (double)(int)(*s - '0'); - } - if (*s == '.') { - for (d = 0.1, ++s; (isdigit(*s) != 0); ++s) { - /* process digits after decimal point. */ - flags |= 2; - ret += (d * (double)(int)(*s - '0')); - d *= 0.1; - } - } - if (flags != 0) { - /* test for exponent token. */ - if ((*s == 'e') || (*s == 'E')) { - ++s; - if (*s == '-') { - /* negative exponent. */ - esign = -1; - ++s; - } - else if (*s == '+') ++s; - if (isdigit(*s) != 0) { - for (; (isdigit(*s) != 0); ++s) { - /* process exponent digits. */ - e *= 10; - e += (int)(*s - '0'); - } - if (esign >= 0) for (i = 0; i < e; ++i) ret *= 1.0; - else for (i = 0; i < e; ++i) ret *= 0.1; - } - } - } - if (eptr != NULL) *eptr = (char *)s; - return (ret * sign); -} -#endif - - -#ifdef F_strtol -/* -** -** [func] - strtol. -** [desc] - if s is a valid long integer string then converts the string to -** it's corresponding long integer value and returns the value. else -** returns the long integer huge value. if eptr is not NULL then -** stores the pointer to the last processed character in the string. -** [entr] - const char *s; the source string pointer. -** char **eptr; the pointer to store the string end pointer. -** int b; the long integer base. -** [exit] - long; the converted long integer value. else the long integer huge value. -** [prec] - s is a valid string pointer and eptr is a valid string pointer -** pointer. -** [post] - the memory pointed to by eptr is modified. -** -*/ -#if 0 -long strtol(const char *s, char **eptr, int b) -{ - const char *start; - int any, c, cutlim, neg = 0; - long ret = 0; - unsigned long acc, cutoff; - - for (start = s; (isspace(*s) != 0); ) ++s; - if (*s == '-') { - neg = 1; - ++s; - } - else if (*s == '+') ++s; - if (((b == 0) || (b == 16)) && (*s == '0') && ((*(s + 1) == 'x') || (*(s + 1) == 'X'))) { - b = 16; - s += 2; - } - if (b == 0) b = ((*s == '0') ? 8 : 10); - /* calculate cutoff values. */ - cutoff = ((neg != 0) ? (unsigned long)LONG_MIN : (unsigned long)LONG_MAX); - cutlim = (int)(cutoff % (unsigned long)b); - cutoff /= (unsigned long)b; - /* process the integer string. */ - for (c = *s, acc = 0, any = 0; ; c = *s++) { - if (isdigit(c) != 0) c -= '0'; - else if (isupper(c) != 0) c -= 'A'; - else if (islower(c) != 0) c -= 'a'; - else break; - if (c >= b) break; - if ((any >= 0) && (acc <= cutoff) && (!((acc == cutoff) && (c > cutlim)))) { - acc *= b; - acc += c; - any = 1; - } - else any = -1; - } - if (any < 0) { - acc = ((neg != 0) ? (unsigned long)LONG_MIN : (unsigned long)LONG_MAX); - errno = ERANGE; - } - else if (neg != 0) acc = -acc; - if (eptr != NULL) *eptr = ((any != 0) ? (char *)(s - 1) : (char *)start); - return (ret); -} -#else - long strtol(const char *nptr, char **endptr, int base) - { - register const char *s = nptr; - register unsigned long acc; - register int c; - register unsigned long cutoff; - register int neg = 0, any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - do - { - c = *s++; - } while (isspace(c)); - - if (c == '-') - { - neg = 1; - c = *s++; - } else if (c == '+') - c = *s++; - - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) - { - c = s[1]; - s += 2; - base = 16; - } - - if (base == 0) - base = c == '0' ? 8 : 10; - - /* - * Compute the cutoff value between legal numbers and illegal - * numbers. That is the largest legal value, divided by the - * base. An input number that is greater than this value, if - * followed by a legal input character, is too big. One that - * is equal to this value may be valid or not; the limit - * between valid and invalid numbers is then based on the last - * digit. For instance, if the range for longs is - * [-2147483648..2147483647] and the input base is 10, - * cutoff will be set to 214748364 and cutlim to either - * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated - * a value > 214748364, or equal but the next digit is > 7 (or 8), - * the number is too big, and we will return a range error. - * - * Set any if any `digits' consumed; make it negative to indicate - * overflow. - */ - cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; - cutlim = cutoff % (unsigned long)base; - cutoff /= (unsigned long)base; - - for (acc = 0, any = 0;; c = *s++) - { - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - - if (c >= base) - break; - - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else - { - any = 1; - acc *= base; - acc += c; - } - } - - if (any < 0) - { - acc = neg ? LONG_MIN : LONG_MAX; - /*errno = E_LIB_MATH_RANGE; */ - /* TODO */ - errno = 30; - } else if (neg) - acc = -acc; - - if (endptr != 0) - *endptr = (char *) (any ? s - 1 : nptr); - - return (acc); - } -#endif -#endif - - -#ifdef F_strtoul -/* -** -** [func] - strtoul. -** [desc] - if s is a valid long integer string then converts the string to -** it's corresponding long integer value and returns the value. else -** returns the long integer huge value. if eptr is not NULL then -** stores the pointer to the last processed character in the string. -** [entr] - const char *s; the source string pointer. -** char **eptr; the pointer to store the string end pointer. -** int b; the long integer base. -** [exit] - long; the converted long integer value. else the long integer huge value. -** [prec] - s is a valid string pointer and eptr is a valid string pointer -** pointer. -** [post] - the memory pointed to by eptr is modified. -** -*/ -#if 0 -unsigned long strtoul(const char *s, char **eptr, int b) -{ - const char *start; - int any, c, cutlim, neg = 0; - unsigned long ret = 0; - unsigned long acc, cutoff; - - for (start = s; (isspace(*s) != 0); ) ++s; - if (*s == '-') { - neg = 1; - ++s; - } - else if (*s == '+') ++s; - if (((b == 0) || (b == 16)) && (*s == '0') && ((*(s + 1) == 'x') || (*(s + 1) == 'X'))) { - b = 16; - s += 2; - } - if (b == 0) b = ((*s == '0') ? 8 : 10); - /* calculate cutoff values. */ - cutoff = ((neg != 0) ? (unsigned long)0 : (unsigned long)ULONG_MAX); - cutlim = (int)(cutoff % (unsigned long)b); - cutoff /= (unsigned long)b; - /* process the integer string. */ - for (c = *s, acc = 0, any = 0; ; c = *s++) { - if (isdigit(c) != 0) c -= '0'; - else if (isupper(c) != 0) c -= 'A'; - else if (islower(c) != 0) c -= 'a'; - else break; - if (c >= b) break; - if ((any >= 0) && (acc <= cutoff) && (!((acc == cutoff) && (c > cutlim)))) { - acc *= b; - acc += c; - any = 1; - } - else any = -1; - } - if (any < 0) { - acc = ((neg != 0) ? (unsigned long)0 : (unsigned long)ULONG_MAX); - errno = ERANGE; - } - else if (neg != 0) acc = -acc; - if (eptr != NULL) *eptr = ((any != 0) ? (char *)(s - 1) : (char *)start); - return (ret); -} -#else -unsigned long strtoul(const char *nptr, char **endptr, int base) - { - register const char *s = nptr; - register unsigned long acc; - register int c; - register unsigned long cutoff; - register int any, cutlim; - - /* - * Skip white space and pick up leading +/- sign if any. - * If base is 0, allow 0x for hex and 0 for octal, else - * assume decimal; if base is already 16, allow 0x. - */ - do - { - c = *s++; - } while (isspace(c)); - - if (c == '-') - { - c = *s++; - } else if (c == '+') - c = *s++; - - if ((base == 0 || base == 16) && - c == '0' && (*s == 'x' || *s == 'X')) - { - c = s[1]; - s += 2; - base = 16; - } - - if (base == 0) - base = c == '0' ? 8 : 10; - - cutoff = ULONG_MAX; - cutlim = cutoff % (unsigned long)base; - cutoff /= (unsigned long)base; - - for (acc = 0, any = 0;; c = *s++) - { - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c -= isupper(c) ? 'A' - 10 : 'a' - 10; - else - break; - - if (c >= base) - break; - - if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) - any = -1; - else - { - any = 1; - acc *= base; - acc += c; - } - } - - if (any < 0) - { - acc = ULONG_MAX; -/* errno = E_LIB_MATH_RANGE; */ - /* TODO */ - errno = 30; - } - - if (endptr != 0) - *endptr = (char *) (any ? s - 1 : nptr); - - return (acc); - } -#endif -#endif - - -#ifdef F_wcstombs -/* -** -** [func] - wcstombs. -** [desc] - -** [entr] - char *s; the pointer to the destination string buffer. -** const wchar_t *ws; the source wide-character string pointer. -** size_t n; the maximum number of characters to store to s. -** [exit] - size_t; the length of the multibyte string. else -1. -** [prec] - s is a valid memory pointer and ws is a valid wide-character string. -** [post] - the memory pointed to s is modified. -** -*/ -size_t wcstombs(char *s, const wchar_t *ws, size_t n) -{ - int shift = 0; - size_t ret = 0; - wchar_t wc; - const mbchar_t *mb; - - for (; ((wc = *ws++) != (wchar_t)'\0'); ) { - if (__isascii(wc)) { - *s++ = (char)(unsigned char)wc; - --n; - ++ret; - } - else { - mb = &_ctype_info->mbchar->chars[wc + shift]; - if ((mb->string == NULL) || (mb->len == 0)) { - ret = (size_t)-1; - break; - } - else if (mb->len > n) break; - else { - memcpy (s, mb->string, mb->len); - shift += mb->shift; - s += mb->len; - n -= mb->len; - ret += mb->len; - } - } - } - if (n > 0) *s = '\0'; - return (ret); -} -#endif - - -#ifdef F_wctomb -/* -** -** [func] - wctomb. -** [desc] - converts the wc wide-character to the corresponding multibyte -** character and stores the multi-byte character to the memory -** pointed to by s and returns the number of bytes used by the -** multi-byte character. -** [entr] - char *s; the pointer to the destination multi-byte character buffer. -** wchar_t wc; the wide-character to convert. -** [exit] - int; the number of bytes used by the multi-byte character. -** [prec] - s is a valid memory pointer. -** [post] - the memory pointed to by s is modified. -** -*/ -int wctomb(char *s, wchar_t wc) -{ - int ret; - const mbchar_t *mb; - - /* test if the multi-byte conversion table has initialized. */ - if (_ctype_info->mbchar == NULL) mb = NULL; - else mb = _ctype_info->mbchar->chars; - /* test for NULL string pointer. */ - if (s != NULL) { - if (wc != (wchar_t)'\0') { - /* ensure multi-byte character is not NULL. */ - if (mb == NULL) { - if ((unsigned char) wc == wc) { - /* copy wide-character. */ - *s = wc; - ret = 1; - } - else ret = -1; - } - else { - /* retrieve the corresponding multi-byte character. */ - mb += (wc + __stdlib_mb_shift); - if ((mb->string != NULL) || (mb->len == 0)) { - /* copy the multi-byte string. */ - memcpy(s, mb->string, mb->len + 1); - __stdlib_mb_shift += mb->shift; - ret = mb->len; - } - else ret = -1; - } - } - else { - /* NULL string terminator. */ - __stdlib_mb_shift = 0; - if (s != NULL) *s = '\0'; - ret = 1; - } - } - else ret = (__stdlib_mb_shift != 0); - return (ret); -} -#endif - -#ifdef F___assert_fail -int __assert_fail (const char *assertion, const char *file, unsigned int line) -{ - fprintf(stderr, "Error: assertion `%s' failed in %s:%i\n", assertion, file, line); - return 0; -} -#endif - -#ifdef F___stdlib_internals -void _pspsdk_stdlib_init() -{ -} - -void _pspsdk_stdlib_deinit() -{ - int i; - - for (i = (__stdlib_exit_index - 1); i >= 0; --i) - { - (__stdlib_exit_func[i])(); - } -} -#endif diff --git a/src/libc/stdlib.h b/src/libc/stdlib.h deleted file mode 100644 index 3a235153..00000000 --- a/src/libc/stdlib.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * stdlib.h - * - * Copyright (c) 2002-2004 PS2DEV - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ - -#ifndef __STDLIB_H__ -#define __STDLIB_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* ensure NULL is defined. */ -#ifndef NULL -#define NULL (void *)0 -#endif - - -/* exit status constants. */ -#define EXIT_SUCCESS 0 -#define EXIT_FAILURE 1 - - -/* multibyte maximum character constant. */ -#define MB_CUR_MAX 1 - -/* ensure div_t is defined. */ -#ifndef __DIV_T_DEFINED -#define __DIV_T_DEFINED -typedef struct { - int quot; - int rem; -} div_t; -#endif // __DIV_T_DEFINED - - -/* ensure ldiv_t is defined. */ -#ifndef __LDIV_T_DEFINED -#define __LDIV_T_DEFINED -typedef struct { - long quot; - long rem; -} ldiv_t; -#endif // __LDIV_T_DEFINED - - -#ifndef __STRICT_ANSI__ -#ifndef __LLDIV_T_DEFINED -#define __LLDIV_T_DEFINED -typedef struct { - long long quot; - long long rem; -} lldiv_t; -#endif // __LLDIV_T_DEFINED -#endif // __STRICT_ANSI__ - -/* we don't check for any previously defined value. This HAS to be that. */ -#define RAND_MAX 2147483647 - - -/* function declarations. */ -void abort(void) __attribute__ ((noreturn)); -int abs(int); -int atexit(void (*)(void)); -double atof(const char *); -void exit(int); -//int atoi(const char *); -//long atol(const char *); -//#define atoi(x) strtol(x, NULL, 10) -//#define atol atoi -void *bsearch(const void *, const void *, size_t, size_t, int (*)(const void *, const void *)); -div_t div(int, int); -char *getenv(const char *); -long labs(long); -ldiv_t ldiv(long, long); -#ifndef __STRICT_ANSI__ -long long llabs(long long); -lldiv_t lldiv(long long, long long); -#endif -int rand(void); -int setenv(const char *, const char *, int); -void srand(unsigned int); -double strtod(const char *, char **); -long strtol(const char *, char **, int); -unsigned long strtoul(const char *, char **, int); -static __inline__ int atoi(const char * x) { return strtol(x, NULL, 10); } -static __inline__ long atol(const char * x) { return strtol(x, NULL, 10); } - - -void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *)); - - -/* Multibyte disabled, but prototyped for C++... */ -int mblen(const char *, size_t); -size_t mbstowcs(wchar_t *, const char *, size_t); -int mbtowc(wchar_t *, const char *, size_t); -size_t wcstombs(char *, const wchar_t *, size_t); -int wctomb(char *, wchar_t); - -//char *_gcvt(double, size_t, char *); -char *_itoa(int, char *, int); -char *_ltoa(long, char *, int); -#ifndef __STRICT_ANSI__ -char *_lltoa(long long, char *, int); -#endif - -// blah! C++ is evil. -int system (const char * string); - -#ifdef __cplusplus -} - -/* C++ is evil, let's defeat it... */ -#define _CPP_CSTDLIB 1 - -#endif - - -#endif // __STDLIB_H__ diff --git a/src/libc/string.c b/src/libc/string.c deleted file mode 100644 index cf9f7e3e..00000000 --- a/src/libc/string.c +++ /dev/null @@ -1,839 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * string.c - Standard ANSI string functions to complement the ASM funcs - * - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ -#include -#include -#include -#include - -/* Until a _ctype_ array exists in psplibc, don't include ctype.h and declare ctype.h - function prototypes. */ -int isalnum(int); -int isalpha(int); -int iscntrl(int); -int isdigit(int); -int isgraph(int); -int islower(int); -int isprint(int); -int ispunct(int); -int isspace(int); -int isupper(int); -int isxdigit(int); -int tolower(int); -int toupper(int); - -#ifdef F_strlen -unsigned int strlen(const char *s) -{ - int len = 0; - while(*s) - { - s++; - len++; - } - - return len; -} -#endif - -#ifdef F_strcat -char *strcat(char *s, const char *append) -{ - char *pRet = s; - while(*s) - { - s++; - } - - while(*append) - { - *s++ = *append++; - } - - *s = 0; - - return pRet; -} -#endif - -#ifdef F_strncat -char *strncat(char *s, const char *append, size_t count) -{ - char *pRet = s; - - while(*s) - { - s++; - } - - while((*append) && (count > 0)) - { - *s++ = *append++; - count--; - } - - *s = 0; - - return pRet; -} -#endif - -#ifdef F_strcmp -int strcmp(const char *s1, const char *s2) -{ - int val = 0; - const unsigned char *u1, *u2; - - u1 = (unsigned char *) s1; - u2 = (unsigned char *) s2; - - while(1) - { - if(*u1 != *u2) - { - val = (int) *u1 - (int) *u2; - break; - } - - if((*u1 == 0) && (*u2 == 0)) - { - break; - } - - u1++; - u2++; - } - - return val; -} -#endif - -#ifdef F_strncmp -int strncmp(const char *s1, const char *s2, size_t count) -{ - int val = 0; - const unsigned char *u1, *u2; - - u1 = (unsigned char *) s1; - u2 = (unsigned char *) s2; - - while(count > 0) - { - if(*u1 != *u2) - { - val = (int) *u1 - (int) *u2; - break; - } - - if((*u1 == 0) && (*u2 == 0)) - { - break; - } - - u1++; - u2++; - count--; - } - - return val; -} -#endif - -#ifdef F_strcpy -char *strcpy(char *dst, const char *src) -{ - char *pRet = dst; - - while(*src) - { - *dst++ = *src++; - } - - *dst = 0; - - return pRet; -} -#endif - -#ifdef F_strncpy -char *strncpy(char *dst, const char *src, size_t count) -{ - char *pRet = dst; - - while(count > 0) - { - if(*src) - { - *dst++ = *src++; - } - else - { - *dst++ = 0; - } - - count--; - } - - return pRet; -} -#endif - -#ifdef F_memcmp -int memcmp(const void *b1, const void *b2, size_t len) -{ - int val = 0; - const unsigned char *u1, *u2; - - u1 = (const unsigned char *) b1; - u2 = (const unsigned char *) b2; - - while(len > 0) - { - if(*u1 != *u2) - { - val = (int) *u1 - (int) *u2; - break; - } - u1++; - u2++; - len--; - } - - return val; -} -#endif - -#ifdef F_memcpy -void *memcpy(void *dst, const void *src, size_t len) -{ - void *pRet = dst; - const char *usrc = (const char *) src; - char *udst = (char *) dst; - - while(len > 0) - { - *udst++ = *usrc++; - len--; - } - - return pRet; -} -#endif - -#ifdef F_memmove -void *memmove(void *dst, const void* src, size_t len) -{ - void *pRet = dst; - char *udst; - const char *usrc; - - if(dst < src) - { - /* Copy forwards */ - udst = (char *) dst; - usrc = (const char *) src; - while(len > 0) - { - *udst++ = *usrc++; - len--; - } - } - else - { - /* Copy backwards */ - udst = ((char *) dst) + len; - usrc = ((const char *) src) + len; - while(len > 0) - { - *--udst = *--usrc; - len--; - } - } - - return pRet; -} -#endif - -#ifdef F_memset -void *memset(void *b, int c, size_t len) -{ - void *pRet = b; - unsigned char *ub = (unsigned char *) b; - - while(len > 0) - { - *ub++ = (unsigned char) c; - len--; - } - - return pRet; -} -#endif - -#ifdef F_memchr -void *memchr(const void *b, int c, size_t len) -{ - void *pRet = NULL; - const unsigned char *ub; - - ub = (void *) b; - while(len > 0) - { - if(*ub == (unsigned char) c) - { - pRet = (void *) &ub[0]; - break; - } - - ub++; - len--; - } - - return pRet; -} -#endif - -#ifdef F_strchr -char *strchr(const char *s, int c) -{ - char *pRet = NULL; - - do - { - if(*s == (char) c) - { - pRet = (char *) &s[0]; - break; - } - } - while(*s++); - - return pRet; -} -#endif - -#ifdef F_strdup -char *strdup(const char *s) { - size_t str_size = strlen(s); - char * r = (char *)malloc(str_size + 1); - - return strcpy(r, s); -} -#endif - -#ifdef F_strcasecmp -int strcasecmp(const char * string1, const char * string2) -{ - while (*string1 != '\0' && tolower(*string1) == tolower(*string2)) - { - string1++; - string2++; - } - - return tolower(*(unsigned char *) string1) - tolower(*(unsigned char *) string2); -} -#endif - - -#ifdef F_strncasecmp -int strncasecmp(const char * string1, const char * string2, size_t n) -{ - if (n == 0) - return 0; - - while ((n-- != 0) && (tolower(*string1) == tolower(*string2))) - { - if ((n == 0) || (*string1 == '\0') || (*string2 == '\0')) - break; - - string1++; - string2++; - } - - return tolower(*(unsigned char *) string1) - tolower(*(unsigned char *) string2); -} -#endif - -#ifdef F_strtok -char* strtok(char * strToken, const char * strDelimit) -{ - static char* start; - static char* end; - - if (strToken != NULL) - start = strToken; - else - { - if (*end == 0) - return 0; - - start=end; - } - - if(*start == 0) - { - return 0; - } - - // Strip out any leading delimiters - while (strchr(strDelimit, *start)) - { - // If a character from the delimiting string - // then skip past it - - start++; - - if (*start == 0) - return 0; - } - - if (*start == 0) - return 0; - - end=start; - - - while (*end != 0) - { - if (strchr(strDelimit, *end)) - { - // if we find a delimiting character - // before the end of the string, then - // terminate the token and move the end - // pointer to the next character - *end = 0; - end++; - return start; - } - - end++; - } - - - // reached the end of the string before finding a delimiter - // so dont move on to the next character - return start; -} -#endif - -#ifdef F_strrchr -char* strrchr(const char * string, int c) -{ - /* use the asm strchr to do strrchr */ - char* lastmatch; - char* result; - - /* if char is never found then this will return 0 */ - /* if char is found then this will return the last matched location - before strchr returned 0 */ - - lastmatch = 0; - result = strchr(string,c); - - while ((int)result != 0) - { - lastmatch=result; - result = strchr(lastmatch+1,c); - } - - return lastmatch; -} -#endif - -#ifdef F_strstr -char * strstr(const char * string, const char * substring) -{ - char* strpos; - - if (*string == 0) - return 0; - - if (strlen(substring)==0) - return (char*)string; - - strpos = (char*)string; - - while (*strpos != 0) - { - if (strncmp(strpos, substring, strlen(substring)) == 0) - { - return strpos; - } - - strpos++; - } - - return 0; -} -#endif - - -#ifdef F_strupr -char * strupr(char *str) -{ - char * strptr = str; - - // loop thru each char in string - while (*strptr != '\0') - { - // if char is lowercase, convert to uppercase - if(islower(*strptr)) - *strptr = toupper(*strptr); - strptr++; - } - - return str; -} -#endif - -#ifdef F_strlwr -char * strlwr(char *str) -{ - char * strptr = str; - - // loop thru each char in string - while (*strptr != '\0') - { - // if char is uppercase, convert to lowercase - if(isupper(*strptr)) - *strptr = tolower(*strptr); - strptr++; - } - - return str; -} -#endif - - -#ifdef F_tolower -int tolower(int c) -{ - if (isupper(c)) - c+=32; - - return c; -} -#endif - -#ifdef F_toupper -int toupper(int c) -{ - if (islower(c)) - c-=32; - - return c; -} -#endif - -#ifdef F_isupper -int isupper(int c) -{ - if (c < 'A') - return 0; - - if (c > 'Z') - return 0; - - // passed both criteria, so it - // is an upper case alpha char - return 1; -} -#endif - -#ifdef F_islower -int islower(int c) -{ - if (c < 'a') - return 0; - - if (c > 'z') - return 0; - - // passed both criteria, so it - // is a lower case alpha char - return 1; -} -#endif - -#ifdef F_isalpha -int isalpha(int c) -{ - if (islower(c) || isupper(c)) - return 1; - - return 0; -} -#endif - -#ifdef F_isdigit -int isdigit(int c) -{ - if (c < '0') - return 0; - - if (c > '9') - return 0; - - // passed both criteria, so it - // is a numerical char - return 1; -} -#endif - -#ifdef F_isalnum -int isalnum(int c) -{ - if (isalpha(c) || isdigit(c)) - return 1; - - return 0; -} -#endif - -#ifdef F_iscntrl -int iscntrl(int c) -{ - if (c < 0x20) - return 1; - - if (c == 0x7F) - return 1; - - return 0; -} -#endif - -#ifdef F_isgraph -int isgraph(int c) -{ - if (iscntrl(c)) - return 0; - - if (isspace(c)) - return 0; - - return 1; -} -#endif - -#ifdef F_isprint -int isprint(int c) -{ - if (iscntrl(c)) - return 0; - - return 1; -} -#endif - -#ifdef F_ispunct -int ispunct(int c) -{ - if (iscntrl(c)) - return 0; - - if (isalnum(c)) - return 0; - - if (isspace(c)) - return 0; - - // It's a printable character - // thats not alpha-numeric, or a space - // so its a punctuation character - return 1; -} -#endif - -#ifdef F_isspace -int isspace(int c) -{ - if ((c>=0x09) && (c<=0x0D)) - return 1; - - if (c==0x20) - return 1; - - return 0; -} -#endif - -#ifdef F_isxdigit -int isxdigit(int c) -{ - if (isdigit(c)) - return 1; - - if ((c>='a') && (c<='f')) - return 1; - - if ((c>='A') && (c<='F')) - return 1; - - return 0; -} -#endif - - -// sjis<->ascii conversion routines by Peter Sandström - -struct charmap_t { - unsigned short sjis; - unsigned char ascii; -}; - -#ifdef F__sjis_internals -struct charmap_t sjis_conversion[] = { - { 0x4081, ' ' }, - { 0x6d81, '[' }, - { 0x6e81, ']' }, - { 0x7c81, '-' }, - { 0x5b81, '°' }, - { 0x4581, '¥' }, - { 0x4481, '.' }, - { 0x7B81, '+' }, - { 0x9681, '*' }, - { 0x5E81, '/' }, - { 0x4981, '!' }, - { 0x6881, '"' }, - { 0x9481, '#' }, - { 0x9081, '$' }, - { 0x9381, '%' }, - { 0x9581, '&' }, - { 0x6681, '\'' }, - { 0x6981, '(' }, - { 0x6a81, ')' }, - { 0x8181, '=' }, - { 0x6281, '|' }, - { 0x8f81, '\\' }, - { 0x4881, '?' }, - { 0x5181, '_' }, - { 0x6f81, '{' }, - { 0x7081, '}' }, - { 0x9781, '@' }, - { 0x4781, ';' }, - { 0x4681, ':' }, - { 0x8381, '<' }, - { 0x8481, '>' }, - { 0x4d81, '`' }, - { 0, 0 } -}; - -unsigned char isSpecialSJIS(short sjis) -{ - struct charmap_t *s = &sjis_conversion[0]; - do { - if (s->sjis == sjis) return s->ascii; - s++; - } while (s->sjis != 0); - return 0; -} - -short isSpecialASCII(unsigned char ascii) -{ - struct charmap_t *s = &sjis_conversion[0]; - do { - if (s->ascii == ascii) return s->sjis; - s++; - } while (s->ascii != 0); - return 0; -} -#else -extern struct charmap_t * sjis_conversion; -unsigned char isSpecialSJIS(short sjis); -short isSpecialASCII(unsigned char ascii); -#endif - -#ifdef F_strcpy_ascii -int strcpy_ascii(char* ascii_buff, const short* sjis_buff) -{ - int i; - short ascii, sjis; - - int len = strlen((const char *)sjis_buff)/2; - - for (i=0;i> 8) - 0x1f; - if (ascii>96) ascii--; - } - ascii_buff[i] = ascii; - } - ascii_buff[i+1]=0; - return len; -} -#endif - -#ifdef F_strcpy_sjis -int strcpy_sjis(short* sjis_buff, const char* ascii_buff) -{ - int i; - short ascii, sjis; - - int len = strlen(ascii_buff); - - for (i=0;i96) ascii++; - sjis = ((ascii + 0x1f) << 8) | 0x82; - } - sjis_buff[i] = sjis; - } - sjis_buff[i+1]=0; - return len; -} -#endif - -#ifdef F_strpbrk -char *strpbrk(const char *s, const char *accept) -{ - const char *needle; - for (; *s; s++) { - for (needle = accept; *needle; needle++) { - if (*s == *needle) - return (char *) s; - } - } - - return NULL; -} -#endif - -#ifdef F_strspn -size_t strspn(const char *s, const char *accept) { - const char *c; - - for (c = s; *c; c++) { - if (!strchr(accept, *c)) - return c - s; - } - - return c - s; -} -#endif - -#ifdef F_strcspn -size_t strcspn(const char *s, const char *reject) { - const char *c; - - for (c = s; *c; c++) { - if (strchr(reject, *c)) - return c - s; - } - - return c - s; -} -#endif diff --git a/src/libc/string.h b/src/libc/string.h deleted file mode 100644 index 3bb9221d..00000000 --- a/src/libc/string.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * string.h - * - * Copyright (c) 2002-2004 PS2DEV - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ - -#ifndef _STRING_H -#define _STRING_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* ASM String functions by Jeff Johnston of Cygnus Solutions */ -void * memchr(const void *, int, size_t); -void * memcpy(void *, const void *, size_t); -void * memmove(void *, const void *, size_t); -void * memset(void *, int, size_t); - -int memcmp(const void *, const void *, size_t); - -int strcmp(const char *, const char *); -int strncmp(const char *, const char *, size_t); - -unsigned int strlen(const char *); - -char * strdup(const char *s); - -char * strcat(char *, const char *); -char * strchr(const char *, int); -char * strcpy(char *, const char *); -char * strncat(char *, const char *, size_t); -char * strncpy(char *, const char *, size_t); - -char * strpbrk(const char *s, const char *accept); -size_t strspn(const char *s, const char *accept); -size_t strcspn(const char *s, const char *reject); - -static __inline__ int strcoll(const char *s1, const char *s2) { return strcmp(s1, s2); } -static __inline__ size_t strxfrm(char *dest, const char *src, size_t n) { strncpy(dest, src, n); return n; } - -char * strerror(int); - -// copies ascii string to sjis string -// -// args: dest sjis string buffer -// source ascii string buffer -// returns: length of ascii string copied -int strcpy_sjis(short* sjis_buff, const char* ascii_buff); - -// copies sjis string to ascii string -// -// args: dest ascii string buffer -// source sjis string buffer -// returns: length of sjis string copied -int strcpy_ascii(char* ascii_buff, const short* sjis_buff); - - -/* C String functions by Hiryu (A.Lee) */ -#define stricmp strcasecmp -#define strnicmp strncasecmp - -int strcasecmp(const char *, const char *); -int strncasecmp(const char *, const char *, size_t); - -char * strtok(char *, const char *); -char * strrchr(const char *, int); - -char * strstr(const char *, const char *); - -char * strupr(char *); -char * strlwr(char *); - -static __inline__ void bzero(void * p, size_t n) { memset(p, 0, n); } -static __inline__ void bcopy(const void * s, void * d, size_t n) { memcpy(d, s, n); } -static __inline__ int bcmp(const void * s1, const void * s2, size_t n) { return memcmp(s1, s2, n); } -static __inline__ char * index(const char * s, int c) { return strchr(s, c); } -static __inline__ char * rindex(const char * s, int c) { return strrchr(s, c); } - -/* Backward compatibility... */ -#include - -#ifdef __cplusplus -} -#endif - -#endif // _STRING_H diff --git a/src/libc/sys/ioctl.h b/src/libc/sys/ioctl.h new file mode 100644 index 00000000..0465938b --- /dev/null +++ b/src/libc/sys/ioctl.h @@ -0,0 +1 @@ +/* Empty file, here for compatibility */ \ No newline at end of file diff --git a/src/libc/sys/socket.h b/src/libc/sys/socket.h new file mode 100644 index 00000000..aa1036c8 --- /dev/null +++ b/src/libc/sys/socket.h @@ -0,0 +1,279 @@ +/* $NetBSD: socket.h,v 1.77 2005/11/29 03:12:16 christos Exp $ */ + +/* + * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Copyright (c) 1982, 1985, 1986, 1988, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)socket.h 8.6 (Berkeley) 5/3/95 + */ + +#ifndef _SYS_SOCKET_H_ +#define _SYS_SOCKET_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +typedef uint8_t sa_family_t; +typedef uint32_t socklen_t; + +/* + * Socket types. + */ +#define SOCK_STREAM 1 /* stream socket */ +#define SOCK_DGRAM 2 /* datagram socket */ +#define SOCK_RAW 3 /* raw-protocol interface */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequenced packet stream */ + +/* + * Option flags per-socket. + */ +#define SO_DEBUG 0x0001 /* turn on debugging info recording */ +#define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ +#define SO_REUSEADDR 0x0004 /* allow local address reuse */ +#define SO_KEEPALIVE 0x0008 /* keep connections alive */ +#define SO_DONTROUTE 0x0010 /* just use interface addresses */ +#define SO_BROADCAST 0x0020 /* permit sending of broadcast msgs */ +#define SO_USELOOPBACK 0x0040 /* bypass hardware when possible */ +#define SO_LINGER 0x0080 /* linger on close if data present */ +#define SO_OOBINLINE 0x0100 /* leave received OOB data in line */ +#define SO_REUSEPORT 0x0200 /* allow local address & port reuse */ +#define SO_TIMESTAMP 0x0400 /* timestamp received dgram traffic */ + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF 0x1001 /* send buffer size */ +#define SO_RCVBUF 0x1002 /* receive buffer size */ +#define SO_SNDLOWAT 0x1003 /* send low-water mark */ +#define SO_RCVLOWAT 0x1004 /* receive low-water mark */ +#define SO_SNDTIMEO 0x1005 /* send timeout */ +#define SO_RCVTIMEO 0x1006 /* receive timeout */ +#define SO_ERROR 0x1007 /* get error status and clear */ +#define SO_TYPE 0x1008 /* get socket type */ +#define SO_OVERFLOWED 0x1009 /* datagrams: return packets dropped */ +#define SO_NONBLOCK 0x1009 /* non-blocking I/O */ + +/* + * Structure used for manipulating linger option. + */ +struct linger { + int l_onoff; /* option on/off */ + int l_linger; /* linger time in seconds */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define SOL_SOCKET 0xffff /* options for socket level */ + +/* + * Address families. + */ +#define AF_UNSPEC 0 /* unspecified */ +#define AF_LOCAL 1 /* local to host (pipes, portals) */ +#define AF_UNIX AF_LOCAL /* backward compatibility */ +#define AF_INET 2 /* internetwork: UDP, TCP, etc. */ +#define AF_IMPLINK 3 /* arpanet imp addresses */ +#define AF_PUP 4 /* pup protocols: e.g. BSP */ +#define AF_CHAOS 5 /* mit CHAOS protocols */ +#define AF_NS 6 /* XEROX NS protocols */ +#define AF_ISO 7 /* ISO protocols */ +#define AF_OSI AF_ISO +#define AF_ECMA 8 /* european computer manufacturers */ +#define AF_DATAKIT 9 /* datakit protocols */ +#define AF_CCITT 10 /* CCITT protocols, X.25 etc */ +#define AF_SNA 11 /* IBM SNA */ +#define AF_DECnet 12 /* DECnet */ +#define AF_DLI 13 /* DEC Direct data link interface */ +#define AF_LAT 14 /* LAT */ +#define AF_HYLINK 15 /* NSC Hyperchannel */ +#define AF_APPLETALK 16 /* Apple Talk */ +#define AF_ROUTE 17 /* Internal Routing Protocol */ +#define AF_LINK 18 /* Link layer interface */ +#define AF_COIP 20 /* connection-oriented IP, aka ST II */ +#define AF_CNT 21 /* Computer Network Technology */ +#define AF_IPX 23 /* Novell Internet Protocol */ +#define AF_INET6 24 /* IP version 6 */ +#define AF_ISDN 26 /* Integrated Services Digital Network*/ +#define AF_E164 AF_ISDN /* CCITT E.164 recommendation */ +#define AF_NATM 27 /* native ATM access */ +#define AF_ARP 28 /* (rev.) addr. res. prot. (RFC 826) */ +#define AF_MAX 31 + +/* + * Structure used by kernel to store most + * addresses. + */ +struct sockaddr { + uint8_t sa_len; /* total length */ + sa_family_t sa_family; /* address family */ + char sa_data[14]; /* actually longer; address value */ +}; + +/* + * Protocol families, same as address families for now. + */ +#define PF_UNSPEC AF_UNSPEC +#define PF_LOCAL AF_LOCAL +#define PF_UNIX PF_LOCAL /* backward compatibility */ +#define PF_INET AF_INET +#define PF_IMPLINK AF_IMPLINK +#define PF_PUP AF_PUP +#define PF_CHAOS AF_CHAOS +#define PF_NS AF_NS +#define PF_ISO AF_ISO +#define PF_OSI AF_ISO +#define PF_ECMA AF_ECMA +#define PF_DATAKIT AF_DATAKIT +#define PF_CCITT AF_CCITT +#define PF_SNA AF_SNA +#define PF_DECnet AF_DECnet +#define PF_DLI AF_DLI +#define PF_LAT AF_LAT +#define PF_HYLINK AF_HYLINK +#define PF_APPLETALK AF_APPLETALK +#define PF_ROUTE AF_ROUTE +#define PF_LINK AF_LINK +#if defined(_NETBSD_SOURCE) +#define PF_XTP pseudo_AF_XTP /* really just proto family, no AF */ +#endif +#define PF_COIP AF_COIP +#define PF_CNT AF_CNT +#define PF_INET6 AF_INET6 +#define PF_IPX AF_IPX /* same format as AF_NS */ +#if defined(_NETBSD_SOURCE) +#define PF_RTIP pseudo_AF_RTIP /* same format as AF_INET */ +#define PF_PIP pseudo_AF_PIP +#endif +#define PF_ISDN AF_ISDN /* same as E164 */ +#define PF_E164 AF_E164 +#define PF_NATM AF_NATM +#define PF_ARP AF_ARP +#if defined(_NETBSD_SOURCE) +#define PF_KEY pseudo_AF_KEY /* like PF_ROUTE, only for key mgmt */ +#endif + +#define PF_MAX AF_MAX + +#define MSG_OOB 0x1 /* process out-of-band data */ +#define MSG_PEEK 0x2 /* peek at incoming message */ +#define MSG_DONTROUTE 0x4 /* send without using routing tables */ +#define MSG_EOR 0x8 /* data completes record */ +#define MSG_TRUNC 0x10 /* data discarded before delivery */ +#define MSG_CTRUNC 0x20 /* control data lost before delivery */ +#define MSG_WAITALL 0x40 /* wait for full request or error */ +#define MSG_DONTWAIT 0x80 /* this message should be nonblocking */ +#define MSG_BCAST 0x100 /* this message was rcvd using link-level brdcst */ +#define MSG_MCAST 0x200 /* this message was rcvd using link-level mcast */ + +/* + * Types of socket shutdown(2). + */ +#define SHUT_RD 0 /* Disallow further receives. */ +#define SHUT_WR 1 /* Disallow further sends. */ +#define SHUT_RDWR 2 /* Disallow further sends/receives. */ + +struct iovec { + void *iov_base; /* Base address. */ + size_t iov_len; /* Length. */ +}; + +/* + * Maximum queue length specifiable by listen. + */ +#define SOMAXCONN 128 + +struct msghdr { + void *msg_name; /* optional address */ + socklen_t msg_namelen; /* size of address */ + struct iovec *msg_iov; /* scatter/gather array */ + int msg_iovlen; /* # elements in msg_iov */ + void *msg_control; /* ancillary data, see below */ + socklen_t msg_controllen; /* ancillary data buffer len */ + int msg_flags; /* flags on received message */ +}; + +/* BSD-compatible socket API. */ +int accept(int, struct sockaddr * __restrict, socklen_t * __restrict); +int bind(int, const struct sockaddr *, socklen_t); +int connect(int, const struct sockaddr *, socklen_t); +int getpeername(int, struct sockaddr * __restrict, socklen_t * __restrict); +int getsockname(int, struct sockaddr * __restrict, socklen_t * __restrict); +int getsockopt(int, int, int, void * __restrict, socklen_t * __restrict); +int listen(int, int); +ssize_t recv(int, void *, size_t, int); +ssize_t recvfrom(int, void * __restrict, size_t, int, + struct sockaddr * __restrict, socklen_t * __restrict); +ssize_t recvmsg(int s, struct msghdr *msg, int flags); +ssize_t send(int, const void *, size_t, int); +ssize_t sendto(int, const void *, + size_t, int, const struct sockaddr *, socklen_t); +ssize_t sendmsg(int s, const struct msghdr *msg, int flags); +int setsockopt(int, int, int, const void *, socklen_t); +int shutdown(int, int); +int socket(int, int, int); + +#ifdef __cplusplus +} +#endif + +#endif /* !_SYS_SOCKET_H_ */ diff --git a/src/libc/terminate.c b/src/libc/terminate.c index 588d0110..a3eb0b25 100644 --- a/src/libc/terminate.c +++ b/src/libc/terminate.c @@ -14,18 +14,47 @@ #include #include -extern void _exit(int code); +#ifdef F__exit +extern int sce_newlib_nocreate_thread_in_start __attribute__((weak)); +int __psp_free_heap(void); + +void _exit(int status) +{ + if (&sce_newlib_nocreate_thread_in_start != NULL) { + /* Free the heap created by _sbrk(). */ + __psp_free_heap(); + + sceKernelSelfStopUnloadModule(1, 0, NULL); + } else { + if (status == 0) { + /* Free the heap created by _sbrk(). */ + __psp_free_heap(); + } + + sceKernelExitThread(status); + } + + while (1) ; +} +#else +void _exit(int status); +#endif + +#ifdef F_abort __attribute__((weak)) void abort() { while (1) _exit(1); } +#endif +#ifdef F_exit __attribute__((weak)) -void _Exit(int retval) +void exit(int retval) { while (1) _exit(retval); } +#endif diff --git a/src/libc/time.h b/src/libc/time.h deleted file mode 100644 index 842a0f03..00000000 --- a/src/libc/time.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * time.h - * - * Copyright (c) 2002-2004 PS2DEV - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ - -#ifndef _TIME_H -#define _TIME_H - -#include - -#ifndef __clock_t_defined -typedef unsigned long clock_t; -#define __clock_t_defined -#endif - -#ifndef __time_t_defined -typedef unsigned long time_t; -#define __time_t_defined -#endif - -struct tm -{ - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -#ifdef __cplusplus -extern "C" { -#endif - -clock_t clock(); -time_t time(time_t *t); - -// to be implemented... -double difftime(time_t time1, time_t time0); -time_t mktime(struct tm *timeptr); -char *asctime(const struct tm *timeptr); -char *ctime(const time_t *timep); -struct tm *gmtime(const time_t *timep); -struct tm *localtime(const time_t *timep); -size_t strftime(char *s, size_t max, const char *format, const struct tm *tm); - -#ifdef __cplusplus -} -#endif - -#endif // TIME_H diff --git a/src/libc/timezone.c b/src/libc/timezone.c new file mode 100644 index 00000000..6ba43de6 --- /dev/null +++ b/src/libc/timezone.c @@ -0,0 +1,34 @@ +/* + * PSP Software Development Kit - https://github.com/pspdev + * ----------------------------------------------------------------------- + * Licensed under the BSD license, see LICENSE in PSPSDK root for details. + * + * timezon.c - Set proper timezone needed by newlib. + * + * Copyright (c) 2021 Francisco Javier Trujillo Mata + * + */ + +#include + +#include +#include +#include + +#ifdef F___timezone_update +__attribute__((weak)) +void __timezone_update() +{ + /* Initialize timezone from PSP configuration */ + int tzOffset = 0; + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_TIMEZONE, &tzOffset); + int tzOffsetAbs = tzOffset < 0 ? -tzOffset : tzOffset; + int hours = tzOffsetAbs / 60; + int minutes = tzOffsetAbs - hours * 60; + int pspDaylight = 0; + sceUtilityGetSystemParamInt(PSP_SYSTEMPARAM_ID_INT_DAYLIGHTSAVINGS, &pspDaylight); + static char tz[18]; + sprintf(tz, "GMT%s%02i:%02i%s", tzOffset < 0 ? "+" : "-", hours, minutes, pspDaylight ? "daylight" : ""); + setenv("TZ", tz, 1); +} +#endif \ No newline at end of file diff --git a/src/libc/xprintf.c b/src/libc/xprintf.c deleted file mode 100644 index 021ae176..00000000 --- a/src/libc/xprintf.c +++ /dev/null @@ -1,987 +0,0 @@ -/* - * PSP Software Development Kit - https://github.com/pspdev - * ----------------------------------------------------------------------- - * Licensed under the BSD license, see LICENSE in PSPSDK root for details. - * - * xprintf.c - Various *printf functions. - * - * Copyright (c) 2005 Marcus R. Brown - * Copyright (c) 2005 James Forshaw - * Copyright (c) 2005 John Kelley - * - */ -/* Code borrowed from mysql's xprintf.c, by Richard Hipp */ -/* This xprintf.c file on which this one is based is in public domain. */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* -** The maximum number of digits of accuracy in a floating-point conversion. -*/ -#define MAXDIG 20 - -/* The maximum string length. */ -#define PS2LIB_STR_MAX 4096 - -/* Instead of including ctype.h, use the isdigit() prototype because psplibc doesn't - know about newlib, and newlib defines isdigit as a macro that uses _ctype_. */ -int isdigit(int __c); - -int vxprintf(void (*func)(char *, int, void *), void *arg, const char *format, va_list ap); - -#ifdef F_vxprintf -/* -** Conversion types fall into various categories as defined by the -** following enumeration. -*/ - -enum e_type { /* The type of the format field */ - RADIX, /* Integer types. %d, %x, %o, and so forth */ - FLOAT, /* Floating point. %f */ - EXP, /* Exponentional notation. %e and %E */ - GENERIC, /* Floating or exponential, depending on exponent. %g */ - SIZE, /* Return number of characters processed so far. %n */ - STRING, /* Strings. %s */ - PERCENT, /* Percent symbol. %% */ - CHAR, /* Characters. %c */ - ERROR, /* Used to indicate no such conversion type */ -/* The rest are extensions, not normally found in printf() */ - CHARLIT, /* Literal characters. %' */ - SEEIT, /* Strings with visible control characters. %S */ - MEM_STRING, /* A string which should be deleted after use. %z */ - ORDINAL, /* 1st, 2nd, 3rd and so forth */ -}; - -/* -** Each builtin conversion character (ex: the 'd' in "%d") is described -** by an instance of the following structure -*/ -typedef struct s_info { /* Information about each format field */ - int fmttype; /* The format field code letter */ - int base; /* The base for radix conversion */ - char *charset; /* The character set for conversion */ - int flag_signed; /* Is the quantity signed? */ - char *prefix; /* Prefix on non-zero values in alt format */ - enum e_type type; /* Conversion paradigm */ -} info; - -/* -** The following table is searched linearly, so it is good to put the -** most frequently used conversion types first. -*/ -static info fmtinfo[] = { - { 'd', 10, "0123456789", 1, 0, RADIX, }, - { 's', 0, 0, 0, 0, STRING, }, - { 'S', 0, 0, 0, 0, SEEIT, }, - { 'z', 0, 0, 0, 0, MEM_STRING, }, - { 'c', 0, 0, 0, 0, CHAR, }, - { 'o', 8, "01234567", 0, "0", RADIX, }, - { 'u', 10, "0123456789", 0, 0, RADIX, }, - { 'x', 16, "0123456789abcdef", 0, "x0", RADIX, }, - { 'X', 16, "0123456789ABCDEF", 0, "X0", RADIX, }, - { 'r', 10, "0123456789", 0, 0, ORDINAL, }, - { 'f', 0, 0, 1, 0, FLOAT, }, - { 'e', 0, "e", 1, 0, EXP, }, - { 'E', 0, "E", 1, 0, EXP, }, - { 'g', 0, "e", 1, 0, GENERIC, }, - { 'G', 0, "E", 1, 0, GENERIC, }, - { 'i', 10, "0123456789", 1, 0, RADIX, }, - { 'n', 0, 0, 0, 0, SIZE, }, - { 'S', 0, 0, 0, 0, SEEIT, }, - { '%', 0, 0, 0, 0, PERCENT, }, - { 'b', 2, "01", 0, "b0", RADIX, }, /* Binary notation */ - { 'p', 16, "0123456789ABCDEF", 0, "x0", RADIX, }, /* Pointers */ - { '\'', 0, 0, 0, 0, CHARLIT, }, /* Literal char */ -}; -#define NINFO (sizeof(fmtinfo)/sizeof(info)) /* Size of the fmtinfo table */ - -/* -** If NOFLOATINGPOINT is defined, then none of the floating point -** conversions will work. -*/ -#ifndef NOFLOATINGPOINT -/* -** "*val" is a double such that 0.1 <= *val < 10.0 -** Return the ascii code for the leading digit of *val, then -** multiply "*val" by 10.0 to renormalize. -** -** Example: -** input: *val = 3.14159 -** output: *val = 1.4159 function return = '3' -** -** The counter *cnt is incremented each time. After counter exceeds -** 16 (the number of significant digits in a 64-bit float) '0' is -** always returned. -*/ -static int getdigit(long double *val, int *cnt){ - int digit; - long double d; - if( (*cnt)++ >= MAXDIG ) return '0'; - digit = (int)*val; - d = digit; - digit += '0'; - *val = (*val - d)*10.0; - return digit; -} -#endif - -/* -** Setting the size of the BUFFER involves trade-offs. No %d or %f -** conversion can have more than BUFSIZE characters. If the field -** width is larger than BUFSIZE, it is silently shortened. On the -** other hand, this routine consumes more stack space with larger -** BUFSIZEs. If you have some threads for which you want to minimize -** stack space, you should keep BUFSIZE small. -*/ -#define BUFSIZE 100 /* Size of the output buffer */ - -/* -** The root program. All variations call this core. -** -** INPUTS: -** func This is a pointer to a function taking three arguments -** 1. A pointer to the list of characters to be output -** (Note, this list is NOT null terminated.) -** 2. An integer number of characters to be output. -** (Note: This number might be zero.) -** 3. A pointer to anything. Same as the "arg" parameter. -** -** arg This is the pointer to anything which will be passed as the -** third argument to "func". Use it for whatever you like. -** -** fmt This is the format string, as in the usual print. -** -** ap This is a pointer to a list of arguments. Same as in -** vfprint. -** -** OUTPUTS: -** The return value is the total number of characters sent to -** the function "func". Returns -1 on a error. -** -** Note that the order in which automatic variables are declared below -** seems to make a big difference in determining how fast this beast -** will run. -*/ - -int vxprintf(func,arg,format,ap) - void (*func)(char*,int,void*); - void *arg; - const char *format; - va_list ap; -{ - register const char *fmt; /* The format string. */ - register int c; /* Next character in the format string */ - register char *bufpt; /* Pointer to the conversion buffer */ - register int precision; /* Precision of the current field */ - register int length; /* Length of the field */ - register int idx; /* A general purpose loop counter */ - int count; /* Total number of characters output */ - int width; /* Width of the current field */ - int flag_leftjustify; /* True if "-" flag is present */ - int flag_plussign; /* True if "+" flag is present */ - int flag_blanksign; /* True if " " flag is present */ - int flag_alternateform; /* True if "#" flag is present */ - int flag_zeropad; /* True if field width constant starts with zero */ - int flag_long; /* True if "l" flag is present */ - int flag_center; /* True if "=" flag is present */ - unsigned long long longvalue; /* Value for integer types */ - - long double realvalue; /* Value for real types */ - info *infop; /* Pointer to the appropriate info structure */ - char buf[BUFSIZE]; /* Conversion buffer */ - char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ - int errorflag = 0; /* True if an error is encountered */ - enum e_type xtype; /* Conversion paradigm */ - char *zMem = 0; /* String to be freed */ - static char spaces[] = - " "; -#define SPACESIZE (sizeof(spaces)-1) -#ifndef NOFLOATINGPOINT - int exp; /* exponent of real numbers */ - long double rounder; /* Used for rounding floating point values */ - int flag_dp; /* True if decimal point should be shown */ - int flag_rtz; /* True if trailing zeros should be removed */ - int flag_exp; /* True to force display of the exponent */ - int nsd; /* Number of significant digits returned */ -#endif - - fmt = format; /* Put in a register for speed */ - count = length = 0; - bufpt = 0; - for(; (c=(*fmt))!=0; ++fmt){ - if( c!='%' ){ - register int amt; - bufpt = (char *)fmt; - amt = 1; - while( (c=(*++fmt))!='%' && c!=0 ) amt++; - (*func)(bufpt,amt,arg); - count += amt; - if( c==0 ) break; - } - if( (c=(*++fmt))==0 ){ - errorflag = 1; - (*func)("%",1,arg); - count++; - break; - } - /* Find out what flags are present */ - flag_leftjustify = flag_plussign = flag_blanksign = - flag_alternateform = flag_zeropad = flag_center = 0; - do{ - switch( c ){ - case '-': flag_leftjustify = 1; c = 0; break; - case '+': flag_plussign = 1; c = 0; break; - case ' ': flag_blanksign = 1; c = 0; break; - case '#': flag_alternateform = 1; c = 0; break; - case '0': flag_zeropad = 1; c = 0; break; - case '=': flag_center = 1; c = 0; break; - default: break; - } - }while( c==0 && (c=(*++fmt))!=0 ); - if( flag_center ) flag_leftjustify = 0; - /* Get the field width */ - width = 0; - if( c=='*' ){ - width = va_arg(ap,int); - if( width<0 ){ - flag_leftjustify = 1; - width = -width; - } - c = *++fmt; - }else{ - while( isdigit(c) ){ - width = width*10 + c - '0'; - c = *++fmt; - } - } - if( width > BUFSIZE-10 ){ - width = BUFSIZE-10; - } - /* Get the precision */ - if( c=='.' ){ - precision = 0; - c = *++fmt; - if( c=='*' ){ - precision = va_arg(ap,int); -#ifndef COMPATIBILITY - /* This is sensible, but SUN OS 4.1 doesn't do it. */ - if( precision<0 ) precision = -precision; -#endif - c = *++fmt; - }else{ - while( isdigit(c) ){ - precision = precision*10 + c - '0'; - c = *++fmt; - } - } - /* Limit the precision to prevent overflowing buf[] during conversion */ - if( precision>BUFSIZE-40 ) precision = BUFSIZE-40; - }else{ - precision = -1; - } - /* Get the conversion type modifier */ - if( c=='l' ){ - flag_long = 1; - c = *++fmt; - if( c == 'l' ){ - flag_long = 2; - c = *++fmt; - } - }else{ - flag_long = 0; - } - /* Fetch the info entry for the field */ - infop = 0; - for(idx=0; idxtype; - } - - /* - ** At this point, variables are initialized as follows: - ** - ** flag_alternateform TRUE if a '#' is present. - ** flag_plussign TRUE if a '+' is present. - ** flag_leftjustify TRUE if a '-' is present or if the - ** field width was negative. - ** flag_zeropad TRUE if the width began with 0. - ** flag_long TRUE if the letter 'l' (ell) prefixed - ** the conversion character. - ** flag_blanksign TRUE if a ' ' is present. - ** width The specified field width. This is - ** always non-negative. Zero is the default. - ** precision The specified precision. The default - ** is -1. - ** xtype The class of the conversion. - ** infop Pointer to the appropriate info struct. - */ - switch( xtype ){ - case ORDINAL: - case RADIX: - if(( flag_long>1 )&&( infop->flag_signed )){ - signed long long t = va_arg(ap,signed long long); - longvalue = t; - }else if(( flag_long>1 )&&( !infop->flag_signed )){ - unsigned long long t = va_arg(ap,unsigned long long); - longvalue = t; - }else if(( flag_long )&&( infop->flag_signed )){ - signed long t = va_arg(ap,signed long); - longvalue = t; - }else if(( flag_long )&&( !infop->flag_signed )){ - unsigned long t = va_arg(ap,unsigned long); - longvalue = t; - }else if(( !flag_long )&&( infop->flag_signed )){ - signed int t = va_arg(ap,signed int) & ((unsigned long) 0xffffffff); - longvalue = t; - }else{ - unsigned int t = va_arg(ap,unsigned int) & ((unsigned long) 0xffffffff); - longvalue = t; - } -#ifdef COMPATIBILITY - /* For the format %#x, the value zero is printed "0" not "0x0". - ** I think this is stupid. */ - if( longvalue==0 ) flag_alternateform = 0; -#else - /* More sensible: turn off the prefix for octal (to prevent "00"), - ** but leave the prefix for hex. */ - if( longvalue==0 && infop->base==8 ) flag_alternateform = 0; -#endif - if( infop->flag_signed ){ - if( *(long long*)&longvalue<0 ){ - longvalue = -*(long long*)&longvalue; - prefix = '-'; - }else if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; - }else prefix = 0; - if( flag_zeropad && precision3 || (b>10 && b<14) ){ - bufpt[0] = 't'; - bufpt[1] = 'h'; - }else if( a==1 ){ - bufpt[0] = 's'; - bufpt[1] = 't'; - }else if( a==2 ){ - bufpt[0] = 'n'; - bufpt[1] = 'd'; - }else if( a==3 ){ - bufpt[0] = 'r'; - bufpt[1] = 'd'; - } - } - { - register char *cset; /* Use registers for speed */ - register int base; - cset = infop->charset; - base = infop->base; - do{ /* Convert to ascii */ - *(--bufpt) = cset[longvalue%base]; - longvalue = longvalue/base; - }while( longvalue>0 ); - } - length = (int)(&buf[BUFSIZE]-bufpt); - if(infop->fmttype == 'p') - { - precision = 8; - flag_alternateform = 1; - } - - for(idx=precision-length; idx>0; idx--){ - *(--bufpt) = '0'; /* Zero pad */ - } - if( prefix ) *(--bufpt) = prefix; /* Add sign */ - if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ - char *pre, x; - pre = infop->prefix; - if( *bufpt!=pre[0] ){ - for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x; - } - } - - length = (int)(&buf[BUFSIZE]-bufpt); - break; - case FLOAT: - case EXP: - case GENERIC: - realvalue = va_arg(ap,double); -#ifndef NOFLOATINGPOINT - if( precision<0 ) precision = 6; /* Set default precision */ - if( precision>BUFSIZE-10 ) precision = BUFSIZE-10; - if( realvalue<0.0 ){ - realvalue = -realvalue; - prefix = '-'; - }else{ - if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; - } - if( infop->type==GENERIC && precision>0 ) precision--; - rounder = 0.0; -#ifdef COMPATIBILITY - /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ - for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); -#else - /* It makes more sense to use 0.5 */ - if( precision>MAXDIG-1 ) idx = MAXDIG-1; - else idx = precision; - for(rounder=0.5; idx>0; idx--, rounder*=0.1); -#endif - if( infop->type==FLOAT ) realvalue += rounder; - /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ - exp = 0; - if( realvalue>0.0 ){ - int k = 0; - while( realvalue>=1e8 && k++<100 ){ realvalue *= 1e-8; exp+=8; } - while( realvalue>=10.0 && k++<100 ){ realvalue *= 0.1; exp++; } - while( realvalue<1e-8 && k++<100 ){ realvalue *= 1e8; exp-=8; } - while( realvalue<1.0 && k++<100 ){ realvalue *= 10.0; exp--; } - if( k>=100 ){ - bufpt = "NaN"; - length = 3; - break; - } - } - bufpt = buf; - /* - ** If the field type is GENERIC, then convert to either EXP - ** or FLOAT, as appropriate. - */ - flag_exp = xtype==EXP; - if( xtype!=FLOAT ){ - realvalue += rounder; - if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } - } - if( xtype==GENERIC ){ - flag_rtz = !flag_alternateform; - if( exp<-4 || exp>precision ){ - xtype = EXP; - }else{ - precision = precision - exp; - xtype = FLOAT; - } - }else{ - flag_rtz = 0; - } - /* - ** The "exp+precision" test causes output to be of type EXP if - ** the precision is too large to fit in buf[]. - */ - nsd = 0; - if( xtype==FLOAT && exp+precision0 || flag_alternateform); - if( prefix ) *(bufpt++) = prefix; /* Sign */ - if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */ - else for(; exp>=0; exp--) *(bufpt++) = getdigit(&realvalue,&nsd); - if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */ - for(exp++; exp<0 && precision>0; precision--, exp++){ - *(bufpt++) = '0'; - } - while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd); - *(bufpt--) = 0; /* Null terminate */ - if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ - while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; - if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; - } - bufpt++; /* point to next free slot */ - }else{ /* EXP or GENERIC */ - flag_dp = (precision>0 || flag_alternateform); - if( prefix ) *(bufpt++) = prefix; /* Sign */ - *(bufpt++) = getdigit(&realvalue,&nsd); /* First digit */ - if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */ - while( (precision--)>0 ) *(bufpt++) = getdigit(&realvalue,&nsd); - bufpt--; /* point to last digit */ - if( flag_rtz && flag_dp ){ /* Remove tail zeros */ - while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; - if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; - } - bufpt++; /* point to next free slot */ - if( exp || flag_exp ){ - *(bufpt++) = infop->charset[0]; - if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ - else { *(bufpt++) = '+'; } - if( exp>=100 ){ - *(bufpt++) = (exp/100)+'0'; /* 100's digit */ - exp %= 100; - } - *(bufpt++) = exp/10+'0'; /* 10's digit */ - *(bufpt++) = exp%10+'0'; /* 1's digit */ - } - } - /* The converted number is in buf[] and zero terminated. Output it. - ** Note that the number is in the usual order, not reversed as with - ** integer conversions. */ - length = (int)(bufpt-buf); - bufpt = buf; - - /* Special case: Add leading zeros if the flag_zeropad flag is - ** set and we are not left justified */ - if( flag_zeropad && !flag_leftjustify && length < width){ - int i; - int nPad = width - length; - for(i=width; i>=nPad; i--){ - bufpt[i] = bufpt[i-nPad]; - } - i = prefix!=0; - while( nPad-- ) bufpt[i++] = '0'; - length = width; - } -#endif - break; - case SIZE: - *(va_arg(ap,int*)) = count; - length = width = 0; - break; - case PERCENT: - buf[0] = '%'; - bufpt = buf; - length = 1; - break; - case CHARLIT: - case CHAR: - c = buf[0] = (xtype==CHAR ? va_arg(ap,int) : *++fmt); - if( precision>=0 ){ - for(idx=1; idx=0 && precision=0x7f ){ - buf[i++] = '^'; - buf[i] = (c&0x1f)+0x40; - }else{ - buf[i] = c; - } - } - bufpt = buf; - length = i; - if( precision>=0 && precision0 ){ - if( flag_center ){ - nspace = nspace/2; - width -= nspace; - flag_leftjustify = 1; - } - count += nspace; - while( nspace>=SPACESIZE ){ - (*func)(spaces,SPACESIZE,arg); - nspace -= SPACESIZE; - } - if( nspace>0 ) (*func)(spaces,nspace,arg); - } - } - if( length>0 ){ - (*func)(bufpt,length,arg); - count += length; - } - if( xtype==MEM_STRING && zMem ){ - free(zMem); - } - if( flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - count += nspace; - while( nspace>=SPACESIZE ){ - (*func)(spaces,SPACESIZE,arg); - nspace -= SPACESIZE; - } - if( nspace>0 ) (*func)(spaces,nspace,arg); - } - } - }/* End for loop over the format string */ - return errorflag ? -1 : count; -} /* End of function */ -#endif - -#ifdef F__xprintf -/* -** This non-standard function is still occasionally useful.... -*/ -int xprintf( - void (*func)(char*,int,void*), - void *arg, - const char *format, - ... -){ - va_list ap; - va_start(ap,format); - return vxprintf(func,arg,format,ap); -} -#endif - -/* -** Now for string-print, also as found in any standard library. -** Add to this the snprint function which stops added characters -** to the string at a given length. -** -** Note that snprint returns the length of the string as it would -** be if there were no limit on the output. -*/ -struct s_strargument { /* Describes the string being written to */ - char *next; /* Next free slot in the string */ - char *last; /* Last available slot in the string */ -}; - -void __sout(char *, int, void *); -#ifdef F___sout -void __sout(txt,amt,arg) - char *txt; - int amt; - void *arg; -{ - register char *head; - register const char *t; - register int a; - register char *tail; - a = amt; - t = txt; - head = ((struct s_strargument*)arg)->next; - tail = ((struct s_strargument*)arg)->last; - if( tail ){ - while( a-- >0 && head0 ) *(head++) = *(t++); - } - *head = 0; - ((struct s_strargument*)arg)->next = head; -} -#endif - -#ifdef F_vsnprintf -int vsnprintf(char *buf, size_t n, const char *fmt, va_list ap){ - struct s_strargument arg; - arg.next = buf; - arg.last = &buf[n-1]; - *buf = 0; - return vxprintf(__sout,&arg,fmt,ap); -} -#endif - -#ifdef F_snprintf -int snprintf(char *str, size_t sz, const char *format, ...) -{ - va_list args; - struct s_strargument arg; - int ret; - - arg.next = str; - arg.last = &str[sz-1]; - - va_start(args, format); - ret = vxprintf(__sout, &arg, format, args); - va_end(args); - - return ret; -} -#endif - -#ifdef F_vsprintf -int vsprintf(char *buf, const char *fmt, va_list ap){ - struct s_strargument arg; - arg.next = buf; - arg.last = NULL; - *buf = 0; - return vxprintf(__sout,&arg,fmt,ap); -} -#endif - -#ifdef F_sprintf -__attribute__((weak)) -int sprintf (char *str, const char *format, ...) -{ - va_list args; - struct s_strargument arg; - int ret; - - arg.next = str; - arg.last = NULL; - - va_start(args, format); - ret = vxprintf(__sout, &arg, format, args); - va_end(args); - - return ret; -} -#endif - -/* -** The following section of code handles the mprintf routine, that -** writes to memory obtained from malloc(). -*/ - -/* This structure is used to store state information about the -** write in progress -*/ -__attribute__((weak)) -struct sgMprintf { - char *zBase; /* A base allocation */ - char *zText; /* The string collected so far */ - int nChar; /* Length of the string so far */ - int nAlloc; /* Amount of space allocated in zText */ -}; - -void __mout(char *, int, void*); - -#ifdef F___mout -/* The xprintf callback function. */ -void __mout(zNewText,nNewChar,arg) - char *zNewText; - int nNewChar; - void *arg; -{ - struct sgMprintf *pM = (struct sgMprintf*)arg; - if( pM->nChar + nNewChar + 1 > pM->nAlloc ){ - pM->nAlloc = pM->nChar + nNewChar*2 + 1; - if( pM->zText==pM->zBase ){ - pM->zText = malloc(pM->nAlloc); - if( pM->zText && pM->nChar ) memcpy(pM->zText,pM->zBase,pM->nChar); - }else{ - pM->zText = realloc(pM->zText, pM->nAlloc); - } - } - if( pM->zText ){ - memcpy(&pM->zText[pM->nChar], zNewText, nNewChar); - pM->nChar += nNewChar; - pM->zText[pM->nChar] = 0; - } -} -#endif - -/* -** mprintf() works like printf(), but allocations memory to hold the -** resulting string and returns a pointer to the allocated memory. -** -** We changed the name to TclMPrint() to conform with the Tcl private -** routine naming conventions. -*/ - -#ifdef F_mprintf -char *mprintf(const char *zFormat, ...){ - va_list ap; - struct sgMprintf sMprintf; - char *zNew; - char zBuf[200]; - - va_start(ap,zFormat); - sMprintf.nChar = 0; - sMprintf.nAlloc = sizeof(zBuf); - sMprintf.zText = zBuf; - sMprintf.zBase = zBuf; - vxprintf(__mout,&sMprintf,zFormat,ap); - va_end(ap); - if( sMprintf.zText==sMprintf.zBase ){ - zNew = malloc( sMprintf.nChar+1 ); - if( zNew ) strcpy(zNew,zBuf); - }else{ - zNew = realloc(sMprintf.zText,sMprintf.nChar+1); - } - - return zNew; -} -#endif - -/* This is the varargs version of mprintf. -** -** The name is changed to TclVMPrintf() to conform with Tcl naming -** conventions. -*/ -#ifdef F_vmprintf -char *vmprintf(const char *zFormat,va_list ap){ - struct sgMprintf sMprintf; - char zBuf[200]; - sMprintf.nChar = 0; - sMprintf.zText = zBuf; - sMprintf.nAlloc = sizeof(zBuf); - sMprintf.zBase = zBuf; - vxprintf(__mout,&sMprintf,zFormat,ap); - if( sMprintf.zText==sMprintf.zBase ){ - sMprintf.zText = malloc( strlen(zBuf)+1 ); - if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf); - }else{ - sMprintf.zText = realloc(sMprintf.zText,sMprintf.nChar+1); - } - return sMprintf.zText; -} -#endif - -#ifdef F_asprintf -int asprintf(char ** strp, const char *zFormat, ...){ - va_list ap; - struct sgMprintf sMprintf; - char *zNew; - char zBuf[200]; - - va_start(ap,zFormat); - sMprintf.nChar = 0; - sMprintf.nAlloc = sizeof(zBuf); - sMprintf.zText = zBuf; - sMprintf.zBase = zBuf; - vxprintf(__mout,&sMprintf,zFormat,ap); - va_end(ap); - if( sMprintf.zText==sMprintf.zBase ){ - zNew = malloc( sMprintf.nChar+1 ); - if( zNew ) strcpy(zNew,zBuf); - }else{ - zNew = realloc(sMprintf.zText,sMprintf.nChar+1); - } - - *strp = zNew; - - return sMprintf.nChar+1; -} -#endif - -#ifdef F_vasprintf -int vasprintf(char **strp, const char *format, va_list ap) { - struct sgMprintf sMprintf; - char zBuf[200]; - sMprintf.nChar = 0; - sMprintf.zText = zBuf; - sMprintf.nAlloc = sizeof(zBuf); - sMprintf.zBase = zBuf; - vxprintf(__mout,&sMprintf,format,ap); - if( sMprintf.zText==sMprintf.zBase ){ - sMprintf.zText = malloc( strlen(zBuf)+1 ); - if( sMprintf.zText ) strcpy(sMprintf.zText,zBuf); - }else{ - sMprintf.zText = realloc(sMprintf.zText,sMprintf.nChar+1); - } - *strp = sMprintf.zText; - return sMprintf.nChar; -} -#endif - -/* -** The following section of code handles the standard fprintf routines -** for pthreads. -*/ - -void __fout(char *, int, void *); - -#ifdef F___fout -void __fout(zNewText,nNewChar,arg) - char *zNewText; - int nNewChar; - void *arg; -{ - fwrite(zNewText,1,nNewChar,(FILE*)arg); -} -#endif - -#ifdef F_fprintf -/* The public interface routines */ -int fprintf(FILE *pOut, const char *zFormat, ...){ - va_list ap; - int retc; - - va_start(ap,zFormat); - retc = vxprintf(__fout,pOut,zFormat,ap); - va_end(ap); - return retc; -} -#endif - -#ifdef F_vfprintf -int vfprintf(FILE *pOut, const char *zFormat, va_list ap){ - return vxprintf(__fout,pOut,zFormat,ap); -} -#endif - - -#ifdef F_printf -int printf(const char *format, ...) -{ - va_list args; - int ret; - - va_start(args, format); - ret = vprintf(format, args); - va_end(args); - - return ret; -} -#endif - -#ifdef F_vprintf -int vprintf(const char *format, va_list args) -{ - static char buf[PS2LIB_STR_MAX]; - int ret; - - ret = vsnprintf(buf, PS2LIB_STR_MAX, format, args); - - sceIoWrite(1, buf, ret); - return ret; -} -#endif - -#ifdef F_putchar -/* Get rid of the newlib macro definition. */ -#ifdef putchar -#undef putchar -#endif -int putchar( int chr ) -{ - sceIoWrite(1, &chr, 1); - return chr; -} -#endif