freebsd-ports/devel/psptoolchain-newlib/files/patch-newlib-libc-sys-psp-libcglue.c
Marcelo Araujo 8cbd3957fb The PlayStation Portable Toolchain is a collection of tools and utilities
for homebrew PSP development.

WWW: http://www.ps2dev.org

PR:		ports/132323, ports/132324, ports/132325, ports/132326
		ports/132327, ports/132328, ports/132329, ports/132330
Submitted by:	Tassilo Philipp <tphilipp@potion-studios.com>
2009-08-21 00:54:33 +00:00

939 lines
21 KiB
C

--- newlib/libc/sys/psp/libcglue.c.orig 1970-01-01 02:00:00.000000000 +0200
+++ newlib/libc/sys/psp/libcglue.c 2007-06-01 12:22:26.000000000 +0300
@@ -0,0 +1,936 @@
+/*
+ * PSP Software Development Kit - http://www.pspdev.org
+ * -----------------------------------------------------------------------
+ * 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 <reent.h>
+#include <stdarg.h>
+#include <stdlib.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/dirent.h>
+#include <sys/socket.h>
+
+#include <psptypes.h>
+#include <pspiofilemgr.h>
+#include <pspmodulemgr.h>
+#include <pspsysmem.h>
+#include <pspthreadman.h>
+#include <psputils.h>
+#include <psputility.h>
+#include <pspstdio.h>
+#include <pspintrman.h>
+#include "fdman.h"
+
+extern char __psp_cwd[MAXPATHLEN + 1];
+extern void __psp_init_cwd(char *argv_0);
+extern int __psp_path_absolute(const char *in, char *out, int len);
+extern int pspDisableInterrupts();
+extern void pspEnableInterrupts(int);
+
+/* The following functions are defined in socket.c. They have weak linkage so
+ that the user doesn't have to link against the PSP network libraries if they
+ don't use the sockets API. */
+extern int __psp_socket_close(int s) __attribute__((weak));
+extern ssize_t __psp_socket_recv(int s, void *buf, size_t len, int flags) __attribute__((weak));
+extern ssize_t __psp_socket_send(int s, const void *buf, size_t len, int flags) __attribute__((weak));
+
+extern int pipe(int fildes[2]);
+extern int __psp_pipe_close(int filedes);
+extern int __psp_pipe_nonblocking_read(int fd, void *buf, size_t len);
+extern int __psp_pipe_read(int fd, void *buf, size_t len);
+extern int __psp_pipe_write(int fd, const void *buf, size_t size);
+extern int __psp_pipe_nonblocking_write(int fd, const void *buf, size_t len);
+
+int __psp_set_errno(int code);
+
+#ifdef F___psp_set_errno
+int __psp_set_errno(int code)
+{
+ if ((code & 0x80010000) == 0x80010000) {
+ errno = code & 0xFFFF;
+ return -1;
+ }
+ return code;
+}
+#endif
+
+#ifdef F_getcwd
+char *getcwd(char *buf, size_t size)
+{
+ if(!buf) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if(strlen(__psp_cwd) >= size) {
+ errno = ERANGE;
+ return NULL;
+ }
+
+ strcpy(buf, __psp_cwd);
+ return buf;
+}
+#endif
+
+#ifdef F_chdir
+int chdir(const char *path)
+{
+ char dest[MAXPATHLEN + 1];
+ SceUID uid;
+
+ if(__psp_path_absolute(path, dest, MAXPATHLEN) < 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(__psp_cwd, dest);
+ return 0;
+}
+#endif
+
+#ifdef F_mkdir
+int mkdir(const char *pathname, mode_t mode)
+{
+ char dest[MAXPATHLEN + 1];
+
+ if(__psp_path_absolute(pathname, dest, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ return __psp_set_errno(sceIoMkdir(dest, mode));
+}
+#endif
+
+#ifdef F_rmdir
+int rmdir(const char *pathname)
+{
+ char dest[MAXPATHLEN + 1];
+
+ if(__psp_path_absolute(pathname, dest, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ return __psp_set_errno(sceIoRmdir(dest));
+}
+#endif
+
+#ifdef F_realpath
+char *realpath(const char *path, char *resolved_path)
+{
+ if(!path || !resolved_path) {
+ errno = EINVAL;
+ return NULL;
+ }
+ if(__psp_path_absolute(path, resolved_path, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return NULL;
+ }
+ if(access(resolved_path, F_OK) < 0) {
+ errno = ENOENT;
+ return NULL;
+ }
+ return resolved_path;
+}
+#endif
+
+/* Wrappers of the standard open(), close(), read(), write(), unlink() and lseek() routines. */
+#ifdef F__open
+int _open(const char *name, int flags, int mode)
+{
+ int scefd, fd;
+ int sce_flags;
+ char dest[MAXPATHLEN + 1];
+
+ if(__psp_path_absolute(name, dest, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ /* 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;
+ }
+
+ scefd = sceIoOpen(dest, sce_flags, mode);
+ if (scefd >= 0) {
+ fd = __psp_fdman_get_new_descriptor();
+ if (fd != -1) {
+ __psp_descriptormap[fd]->sce_descriptor = scefd;
+ __psp_descriptormap[fd]->type = __PSP_DESCRIPTOR_TYPE_FILE;
+ __psp_descriptormap[fd]->flags = flags;
+ __psp_descriptormap[fd]->filename = strdup(dest);
+ return fd;
+ }
+ else {
+ sceIoClose(scefd);
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ else {
+ return __psp_set_errno(scefd);
+ }
+
+}
+#endif
+
+#ifdef F__close
+int _close(int fd)
+{
+ int ret = 0;
+
+ if (!__PSP_IS_FD_VALID(fd)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch(__psp_descriptormap[fd]->type)
+ {
+ case __PSP_DESCRIPTOR_TYPE_FILE:
+ case __PSP_DESCRIPTOR_TYPE_TTY:
+ if (__psp_descriptormap[fd]->ref_count == 1) {
+ ret = __psp_set_errno(sceIoClose(__psp_descriptormap[fd]->sce_descriptor));
+ }
+ __psp_fdman_release_descriptor(fd);
+ return ret;
+ break;
+ case __PSP_DESCRIPTOR_TYPE_PIPE:
+ return __psp_pipe_close(fd);
+ break;
+ case __PSP_DESCRIPTOR_TYPE_SOCKET:
+ if (__psp_socket_close != NULL) {
+ ret = __psp_socket_close(fd);
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+
+ errno = EBADF;
+ return -1;
+}
+#endif
+
+#ifdef F__read
+int _read(int fd, void *buf, size_t size)
+{
+ if (!__PSP_IS_FD_VALID(fd)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch(__psp_descriptormap[fd]->type)
+ {
+ case __PSP_DESCRIPTOR_TYPE_FILE:
+ case __PSP_DESCRIPTOR_TYPE_TTY:
+ return __psp_set_errno(sceIoRead(__psp_descriptormap[fd]->sce_descriptor, buf, size));
+ break;
+ case __PSP_DESCRIPTOR_TYPE_PIPE:
+ if (__psp_descriptormap[fd]->flags & O_NONBLOCK) {
+ return __psp_pipe_nonblocking_read(fd, buf, size);
+ }
+ else {
+ return __psp_pipe_read(fd, buf, size);
+ }
+ break;
+ case __PSP_DESCRIPTOR_TYPE_SOCKET:
+ if (__psp_socket_recv != NULL) {
+ return __psp_socket_recv(fd, buf, size, 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ errno = EBADF;
+ return -1;
+
+}
+#endif
+
+#ifdef F__write
+int _write(int fd, const void *buf, size_t size)
+{
+ if (!__PSP_IS_FD_VALID(fd)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch(__psp_descriptormap[fd]->type)
+ {
+ case __PSP_DESCRIPTOR_TYPE_FILE:
+ case __PSP_DESCRIPTOR_TYPE_TTY:
+ return __psp_set_errno(sceIoWrite(__psp_descriptormap[fd]->sce_descriptor, buf, size));
+ break;
+ case __PSP_DESCRIPTOR_TYPE_PIPE:
+ if (__psp_descriptormap[fd]->flags & O_NONBLOCK) {
+ return __psp_pipe_nonblocking_write(fd, buf, size);
+ }
+ else {
+ return __psp_pipe_write(fd, buf, size);
+ }
+ break;
+ break;
+ case __PSP_DESCRIPTOR_TYPE_SOCKET:
+ if (__psp_socket_send != NULL) {
+ return __psp_socket_send(fd, buf, size, 0);
+ }
+ break;
+ default:
+ break;
+ }
+
+ errno = EBADF;
+ return -1;
+}
+#endif
+
+#ifdef F__lseek
+off_t _lseek(int fd, off_t offset, int whence)
+{
+ if (!__PSP_IS_FD_VALID(fd)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch(__psp_descriptormap[fd]->type)
+ {
+ case __PSP_DESCRIPTOR_TYPE_FILE:
+ /* We don't have to do anything with the whence argument because SEEK_* == PSP_SEEK_*. */
+ return (off_t) __psp_set_errno(sceIoLseek(__psp_descriptormap[fd]->sce_descriptor, offset, whence));
+ break;
+ case __PSP_DESCRIPTOR_TYPE_PIPE:
+ break;
+ case __PSP_DESCRIPTOR_TYPE_SOCKET:
+ break;
+ default:
+ break;
+ }
+
+ errno = EBADF;
+ return -1;
+
+}
+#endif
+
+#ifdef F__unlink
+int _unlink(const char *path)
+{
+ char dest[MAXPATHLEN + 1];
+
+ if(__psp_path_absolute(path, dest, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ return __psp_set_errno(sceIoRemove(dest));
+}
+#endif
+
+#ifdef F__link
+int _link(const char *name1, const char *name2)
+{
+ errno = ENOSYS;
+ return -1; /* not supported */
+}
+#endif
+
+#ifdef F_opendir
+DIR *opendir(const char *filename)
+{
+ char dest[MAXPATHLEN + 1];
+ DIR *dirp;
+ SceUID uid;
+
+ /* Normalize pathname so that opendir(".") works */
+ if(__psp_path_absolute(filename, dest, MAXPATHLEN) < 0) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ dirp = (DIR *)malloc(sizeof(DIR));
+
+ uid = sceIoDopen(dest);
+
+ if (uid < 0)
+ {
+ free(dirp);
+ (void) __psp_set_errno(uid);
+ return NULL;
+ }
+
+ dirp->uid = uid;
+
+ return dirp;
+}
+#endif
+
+#ifdef F_readdir
+struct dirent *readdir(DIR *dirp)
+{
+ int ret;
+
+ /* Zero the dirent, to avoid possible problems with sceIoDread */
+ memset(&dirp->de, 0, sizeof(struct dirent));
+
+ ret = sceIoDread(dirp->uid, (SceIoDirent *)&dirp->de);
+ if (ret == 0) {
+ /* EOF */
+ errno = 0;
+ return NULL;
+ }
+ if (ret < 0) {
+ (void) __psp_set_errno(ret);
+ return NULL;
+ }
+
+ return &dirp->de;
+}
+#endif
+
+#ifdef F_closedir
+int closedir(DIR *dirp)
+{
+ if (dirp != NULL)
+ {
+ int uid;
+ uid = dirp->uid;
+ free (dirp);
+ return __psp_set_errno(sceIoDclose(uid));
+ }
+ errno = EBADF;
+ return -1;
+}
+#endif
+
+/* Time routines. These wrap around the routines provided by the kernel. */
+#ifdef F__gettimeofday
+int _gettimeofday(struct timeval *tp, struct timezone *tzp)
+{
+ return __psp_set_errno(sceKernelLibcGettimeofday(tp, tzp));
+}
+
+#endif
+
+#if defined(F_clock)
+clock_t clock(void)
+{
+ return sceKernelLibcClock();
+}
+#endif
+
+#if defined(F_time)
+time_t time(time_t *t)
+{
+ return __psp_set_errno(sceKernelLibcTime(t));
+}
+#endif
+
+#if defined(F_sleep)
+unsigned int sleep(unsigned int secs) {
+ while(secs--) {
+ sceKernelDelayThreadCB(1000000);
+ }
+ return 0;
+}
+#endif
+
+/* PSP-compatible sbrk(). */
+#if defined(F__sbrk) || defined(F_glue__sbrk)
+/* TODO: Currently our default heap is set to the maximum available block size
+ when sbrk() is first called. Sony seems to always use a default of 64KB,
+ with the expectation that user programs will override the default size with
+ their own desired size. The only reason I can think of them doing this is
+ to allow each PRX to have their own seperate heap. I think that their
+ method is overkill for most user programs.
+
+ What I'd like to do instead is to use the default of 64KB for PRXes as Sony
+ does, but use the maximum available block size for executables. This avoids
+ the requirement of specifying the heap size manually in user programs.
+ However, we currently don't have a clean way to distinguish PRXes and normal
+ executables, so this code needs to be revisited once we do come up with a
+ way. */
+#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;
+
+ if (&sce_newlib_heap_kb_size != NULL) {
+ heap_size = sce_newlib_heap_kb_size * 1024;
+ } else {
+ if (&__pspsdk_is_prx != NULL) {
+ heap_size = DEFAULT_PRX_HEAP_SIZE_KB * 1024;
+ } else {
+ heap_size = sceKernelMaxFreeMemSize();
+ }
+ }
+
+ __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
+
+/* Other POSIX routines that must be defined. */
+#ifdef F__fstat
+int _fstat(int fd, struct stat *sbuf)
+{
+ int ret;
+ SceOff oldpos;
+ if (!__PSP_IS_FD_VALID(fd)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch(__psp_descriptormap[fd]->type)
+ {
+ case __PSP_DESCRIPTOR_TYPE_TTY:
+ memset(sbuf, '\0', sizeof(struct stat));
+ sbuf->st_mode = S_IFCHR;
+ return 0;
+ break;
+ case __PSP_DESCRIPTOR_TYPE_FILE:
+ if (__psp_descriptormap[fd]->filename != NULL) {
+ ret = stat(__psp_descriptormap[fd]->filename, sbuf);
+
+ /* Find true size of the open file */
+ oldpos = sceIoLseek(__psp_descriptormap[fd]->sce_descriptor, 0, SEEK_CUR);
+ if (oldpos != (off_t) -1) {
+ sbuf->st_size = (off_t) sceIoLseek(__psp_descriptormap[fd]->sce_descriptor, 0, SEEK_END);
+ sceIoLseek(__psp_descriptormap[fd]->sce_descriptor, oldpos, SEEK_SET);
+ }
+ return ret;
+ }
+ break;
+ case __PSP_DESCRIPTOR_TYPE_PIPE:
+ case __PSP_DESCRIPTOR_TYPE_SOCKET:
+ default:
+ break;
+ }
+
+ errno = EBADF;
+ return -1;
+}
+#endif
+
+#ifdef F_isatty
+int isatty(int fd)
+{
+ if (!__PSP_IS_FD_VALID(fd)) {
+ errno = EBADF;
+ return 0;
+ }
+
+ if (__psp_descriptormap[fd]->type == __PSP_DESCRIPTOR_TYPE_TTY) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+#endif
+
+#ifdef F__stat
+static time_t psp_to_epoch_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);
+}
+
+int _stat(const char *filename, struct stat *buf)
+{
+ SceIoStat psp_stat;
+ char dest[MAXPATHLEN + 1];
+ int ret;
+
+ if(__psp_path_absolute(filename, dest, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ memset(buf, '\0', sizeof(struct stat));
+ ret = sceIoGetstat(dest, &psp_stat);
+ if (ret < 0) {
+ return __psp_set_errno(ret);
+ }
+
+ buf->st_ctime = psp_to_epoch_time(psp_stat.st_ctime);
+ buf->st_atime = psp_to_epoch_time(psp_stat.st_atime);
+ buf->st_mtime = psp_to_epoch_time(psp_stat.st_mtime);
+
+ buf->st_mode = (psp_stat.st_mode & 0xfff) |
+ ((FIO_S_ISLNK(psp_stat.st_mode))?(S_IFLNK):(0)) |
+ ((FIO_S_ISREG(psp_stat.st_mode))?(S_IFREG):(0)) |
+ ((FIO_S_ISDIR(psp_stat.st_mode))?(S_IFDIR):(0));
+ buf->st_size = psp_stat.st_size;
+ return 0;
+}
+#endif
+
+/* from stat.h in ps2sdk, this function may be correct */
+#define FIO_CST_SIZE 0x0004
+
+#ifdef F_truncate
+int truncate(const char *filename, off_t length)
+{
+ SceIoStat psp_stat;
+ char dest[MAXPATHLEN + 1];
+
+ if(__psp_path_absolute(filename, dest, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ psp_stat.st_size = length;
+ if(length < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ return __psp_set_errno(sceIoChstat(dest, &psp_stat, FIO_CST_SIZE));
+}
+#endif
+
+/* Unsupported newlib system calls. */
+#ifdef F__fork
+pid_t fork(void)
+{
+ errno = ENOSYS;
+ return (pid_t) -1;
+}
+#endif
+
+#ifdef F__getpid
+pid_t _getpid(void)
+{
+ errno = ENOSYS;
+ return (pid_t) -1;
+}
+#endif
+
+#ifdef F__kill
+int _kill(int unused, int unused2)
+{
+ errno = ENOSYS;
+ return -1;
+}
+#endif
+
+#ifdef F__wait
+pid_t _wait(int *unused)
+{
+ errno = ENOSYS;
+ return (pid_t) -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 (!__PSP_IS_FD_VALID(fd)) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch (cmd)
+ {
+ case F_DUPFD:
+ {
+ return __psp_fdman_get_dup_descriptor(fd);
+ break;
+ }
+ case F_GETFL:
+ {
+ return __psp_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. */
+
+ __psp_descriptormap[fd]->flags = newfl;
+
+ switch(__psp_descriptormap[fd]->type)
+ {
+ case __PSP_DESCRIPTOR_TYPE_FILE:
+ break;
+ case __PSP_DESCRIPTOR_TYPE_PIPE:
+ break;
+ case __PSP_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_tzset
+void tzset(void)
+{
+ static int initialized = 0;
+
+ if (!initialized)
+ {
+ initialized = 1;
+
+ /* Don't init if TZ has already been set once, this probably means the user
+ wanted to override what we would set below. */
+ if (getenv("TZ") == NULL)
+ {
+ /* 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);
+ }
+ }
+
+ _tzset_r(_REENT);
+}
+#endif
+
+#ifdef F_mlock
+static unsigned int lock_count = 0;
+static unsigned int intr_flags = 0;
+
+void __malloc_lock(struct _reent *ptr)
+{
+ unsigned int flags = pspDisableInterrupts();
+
+ if (lock_count == 0) {
+ intr_flags = flags;
+ }
+
+ lock_count++;
+}
+
+void __malloc_unlock(struct _reent *ptr)
+{
+ if (--lock_count == 0) {
+ pspEnableInterrupts(intr_flags);
+ }
+}
+#endif
+
+/* Exit. */
+#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) ;
+}
+
+/* Note: This function is being linked into _exit.o.
+
+ Because __psp_libc_init is a weak import in crt0.c, the linker
+ chooses to ignore an object file in libc.a that contains just this
+ function, since it's not necessary for successful compilation.
+
+ By putting it instead in _exit.o, which is already used by crt0.c,
+ the linker sees __psp_libc_init and resolves the symbol properly.
+*/
+void __psp_libc_init(int argc, char *argv[])
+{
+ (void) argc;
+
+ /* Initialize cwd from this program's path */
+ __psp_init_cwd(argv[0]);
+
+ /* Initialize filedescriptor management */
+ __psp_fdman_init();
+}
+
+#endif /* F__exit */
+
+#ifdef F__rename
+int _rename(const char *old, const char *new)
+{
+ char oldname[MAXPATHLEN + 1];
+ char newname[MAXPATHLEN + 1];
+
+ if(__psp_path_absolute(old, oldname, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ if(__psp_path_absolute(new, newname, MAXPATHLEN) < 0) {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ return __psp_set_errno(sceIoRename(oldname, newname));
+}
+#endif
+
+#ifdef F_nanosleep
+/* note: we don't use rem as we have no signals */
+int nanosleep(const struct timespec *req, struct timespec *rem)
+{
+ if( req == NULL )
+ return EFAULT;
+
+ if( rem != NULL ) {
+ rem->tv_sec = 0;
+ rem->tv_nsec = 0;
+ }
+
+ sceKernelDelayThreadCB( 1000000 * req->tv_sec + (req->tv_nsec / 1000) );
+
+ return 0;
+}
+#endif
+