Creation of the libpsplibc library:

- Implement callback functions needed by newlib
- POSIX environment
- Thread safe alloc/dealloc open/close files
- Changed the way that HEAP is allocated, now by default it uses all available RAM except 512KB/
- Implement a lot of missing functions for having a real POSIX environment (some implementations are dummy because are impossible to do in the PSP OS)
- Adding specific inet changes that previously where in the PSP newlib patch
- Deleting the uncompleted & custom libc library
- Create some weak functions during init of libc process to save some KB if we want to have tiny apps
- Other I/O improvements
This commit is contained in:
Francisco Javier Trujillo Mata
2021-11-13 16:39:14 +01:00
parent 35e407e8f1
commit 1857e98f0d
38 changed files with 3242 additions and 6419 deletions

View File

@@ -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 ?

View File

@@ -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 $@

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
/* This code is based on code contributed by Philip Joaqiun (jenova0). */
#include <psptypes.h>
#include <pspkernel.h>
#include <malloc.h>
#include <string.h>
#ifdef DEBUG_ALLOC
#include <stdio.h>
#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

26
src/libc/arpa/inet.h Normal file
View File

@@ -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 <netinet/in.h>
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_ */

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#ifndef __ASSERT_H__
#define __ASSERT_H__
#include <pspkernel.h>
#include <stdio.h>
#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

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#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

192
src/libc/cwd.c Normal file
View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/param.h>
#include <dirent.h>
#include <errno.h>
#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

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#include <stdlib.h>
#include <malloc.h>
__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();
}

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#ifndef __UNISTD_H__
#define __UNISTD_H__
#include <stdio.h>
#include <errno.h>
#endif
#ifdef F___set_errno
int __set_errno(int code)
{
if ((code & 0x80010000) == 0x80010000) {
errno = code & 0xFFFF;
return -1;
}
return code;
}
#endif

142
src/libc/fdman.c Normal file
View File

@@ -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 <fjtrujy@gmail.com>
*
*/
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <pspstdio.h>
#include <psptypes.h>
#include <pspsdk.h>
#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

48
src/libc/fdman.h Normal file
View File

@@ -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 <rafpsp@gmail.com>
*/
#ifndef _FDMAN_H_
#include <sys/types.h>
#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

865
src/libc/glue.c Normal file
View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
* Copyright (c) 2021 Francisco J Trujillo <fjtrujy@gmail.com>
*
*/
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/times.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <psptypes.h>
#include <pspiofilemgr.h>
#include <pspmodulemgr.h>
#include <pspsysmem.h>
#include <pspthreadman.h>
#include <psputils.h>
#include <pspsdk.h>
#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

View File

@@ -10,25 +10,38 @@
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
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 <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/param.h>
__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

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
* Copyright (c) 2005 Jim Paris <jim@jtan.com>
*
*/
#include <errno.h>
#include <malloc.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/unistd.h>
#include <sys/param.h>
#include <psptypes.h>
#include <pspiofilemgr.h>
#include <pspmodulemgr.h>
#include <pspsysmem.h>
#include <pspthreadman.h>
#include <psputils.h>
/* 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

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#ifndef _MALLOC_H
#define _MALLOC_H
#include <pspkernel.h>
#include <stddef.h>
#include <stdarg.h>
#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

45
src/libc/mutexman.c Normal file
View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <pspthreadman.h>
#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

115
src/libc/netdb.c Normal file
View File

@@ -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 <fjtrujy@gmail.com>
*
*/
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pspkerneltypes.h>
#include <pspnet_resolver.h>
#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

36
src/libc/netdb.h Normal file
View File

@@ -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

280
src/libc/netinet/in.h Normal file
View File

@@ -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 <sys/socket.h>
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_ */

12
src/libc/netinet/tcp.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef __NETINET_TCP_H__
#define __NETINET_TCP_H__
#include <netinet/in.h>
#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

324
src/libc/pipe.c Normal file
View File

@@ -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 <rafpsp@gmail.com>
*
* - 20070630 Alper Akcan "anhanguera" <distchx@yahoo.com>
* [non]blocking read/write() fix
* illegal size fix for read/write()
*
*/
#include <stdio.h>
#include <errno.h>
#include <sys/syslimits.h>
#include <sys/types.h>
#include <psptypes.h>
#include <pspthreadman.h>
#include <pspmodulemgr.h>
#include <pspkerror.h>
#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

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
/*-
* 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 <stdlib.h>
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;
}
}

200
src/libc/select.c Normal file
View File

@@ -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 <rafpsp@gmail.com>
*
* - 20070701 Alper Akcan "anhanguera" <distchx@yahoo.com>
* select EBADF fix
*
*/
#include <fcntl.h>
#include <errno.h>
#include <sys/select.h>
#include <psptypes.h>
#include <pspthreadman.h>
#include <pspnet_inet.h>
#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

View File

@@ -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 <as_reg_compat.h>
#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

31
src/libc/sleep.c Normal file
View File

@@ -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 <fjtrujy@gmail.com>
*
*/
#include <pspthreadman.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#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

446
src/libc/socket.c Normal file
View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
*
*/
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <psptypes.h>
#include <pspnet_inet.h>
#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

File diff suppressed because it is too large Load Diff

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#ifndef __STDIO_H__
#define __STDIO_H__
#include <pspkernel.h>
#include <stdarg.h>
#include <sys/types.h>
#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__

File diff suppressed because it is too large Load Diff

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#ifndef __STDLIB_H__
#define __STDLIB_H__
#include <pspkernel.h>
#include <stddef.h>
#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__

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#include <psptypes.h>
#include <limits.h>
#include <string.h>
#include <malloc.h>
/* 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<74>m
struct charmap_t {
unsigned short sjis;
unsigned char ascii;
};
#ifdef F__sjis_internals
struct charmap_t sjis_conversion[] = {
{ 0x4081, ' ' },
{ 0x6d81, '[' },
{ 0x6e81, ']' },
{ 0x7c81, '-' },
{ 0x5b81, '<EFBFBD>' },
{ 0x4581, '<EFBFBD>' },
{ 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<len;i++) {
sjis = sjis_buff[i];
if ((ascii = isSpecialSJIS(sjis)) != 0) {
} else {
ascii = ((sjis & 0xFF00) >> 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;i<len;i++) {
ascii = ascii_buff[i];
if ((sjis = isSpecialASCII(ascii)) != 0) {
} else {
if (ascii>96) 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

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#ifndef _STRING_H
#define _STRING_H
#include <stddef.h>
#include <stdarg.h>
#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 <ctype.h>
#ifdef __cplusplus
}
#endif
#endif // _STRING_H

1
src/libc/sys/ioctl.h Normal file
View File

@@ -0,0 +1 @@
/* Empty file, here for compatibility */

279
src/libc/sys/socket.h Normal file
View File

@@ -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 <stdint.h>
#include <stddef.h>
#include <sys/types.h>
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_ */

View File

@@ -14,18 +14,47 @@
#include <psptypes.h>
#include <pspkernel.h>
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

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
#ifndef _TIME_H
#define _TIME_H
#include <stddef.h>
#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

34
src/libc/timezone.c Normal file
View File

@@ -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 <fjtrujy@gmail.com>
*
*/
#include <psputility_sysparam.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#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

View File

@@ -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 <mrbrown@ocgnet.org>
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
*
*/
/* 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 <stdio.h>
#include <psptypes.h>
#include <pspkernel.h>
#include <pspiofilemgr.h>
#include <string.h>
#include <malloc.h>
#include <stdarg.h>
#include <stddef.h>
/*
** 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; idx<NINFO; idx++){
if( c==fmtinfo[idx].fmttype ){
infop = &fmtinfo[idx];
break;
}
}
/* No info entry found. It must be an error. */
if( infop==0 ){
xtype = ERROR;
}else{
xtype = infop->type;
}
/*
** 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 && precision<width-(prefix!=0) ){
precision = width-(prefix!=0);
}
bufpt = &buf[BUFSIZE];
if( xtype==ORDINAL ){
long a,b;
a = longvalue%10;
b = longvalue%100;
bufpt -= 2;
if( a==0 || a>3 || (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+precision<BUFSIZE-30 ){
flag_dp = (precision>0 || 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<precision; idx++) buf[idx] = c;
length = precision;
}else{
length =1;
}
bufpt = buf;
break;
case STRING:
case MEM_STRING:
zMem = bufpt = va_arg(ap,char*);
if( bufpt==0 ) bufpt = "(null)";
length = strlen(bufpt);
if( precision>=0 && precision<length ) length = precision;
break;
case SEEIT:
{
int i;
int c;
char *arg = va_arg(ap,char*);
for(i=0; i<BUFSIZE-1 && (c = *arg++)!=0; i++){
if( c<0x20 || c>=0x7f ){
buf[i++] = '^';
buf[i] = (c&0x1f)+0x40;
}else{
buf[i] = c;
}
}
bufpt = buf;
length = i;
if( precision>=0 && precision<length ) length = precision;
}
break;
case ERROR:
buf[0] = '%';
buf[1] = c;
errorflag = 0;
idx = 1+(c!=0);
(*func)("%",idx,arg);
count += idx;
if( c==0 ) fmt--;
break;
}/* End switch over the format type */
/*
** The text of the conversion is pointed to by "bufpt" and is
** "length" characters long. The field width is "width". Do
** the output.
*/
if( !flag_leftjustify ){
register int nspace;
nspace = width-length;
if( nspace>0 ){
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 && head<tail ) *(head++) = *(t++);
}else{
while( a-- >0 ) *(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