mirror of
https://github.com/pspdev/pspsdk.git
synced 2025-12-24 04:32:36 +00:00
1239 lines
32 KiB
C
1239 lines
32 KiB
C
/*
|
|
* PSP Software Development Kit - https://github.com/pspdev
|
|
* -----------------------------------------------------------------------
|
|
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
|
|
*
|
|
* stdlib.c - Stdlib's functions, without allocs (see alloc.c)
|
|
*
|
|
* Copyright (c) 2005 Marcus R. Brown <mrbrown@ocgnet.org>
|
|
* Copyright (c) 2005 James Forshaw <tyranid@gmail.com>
|
|
* Copyright (c) 2005 John Kelley <ps2dev@kelley.ca>
|
|
*
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
|
|
extern void (* __stdlib_exit_func[32])(void);
|
|
extern int __stdlib_exit_index;
|
|
|
|
// This function is missing...
|
|
char *__stdlib_ecvt(double, size_t, int *, int *);
|
|
|
|
#ifndef __ENVIRONVARIABLE_T_DEFINED
|
|
#define __ENVIRONVARIABLE_T_DEFINED
|
|
typedef struct {
|
|
char name[256];
|
|
char value[256];
|
|
} environvariable_t;
|
|
#endif // __ENVIRONVARIABLE_T_DEFINED
|
|
|
|
extern environvariable_t __stdlib_env[32];
|
|
extern int __stdlib_mb_shift;
|
|
extern unsigned int __stdlib_rand_seed;
|
|
|
|
int isspace(int);
|
|
int isdigit(int);
|
|
int isalpha(int);
|
|
int isupper(int);
|
|
|
|
#ifdef F_abs
|
|
/*
|
|
**
|
|
** [func] - abs.
|
|
** [desc] - returns the absolute value of the integer c.
|
|
** [entr] - int c; the integer value.
|
|
** [exit] - int; the absolute value of the integer c.
|
|
** [prec] - none.
|
|
** [post] - none.
|
|
**
|
|
*/
|
|
|
|
// shouldn't we rather put that as a macro... ?
|
|
int abs(int c)
|
|
{
|
|
return ((c >= 0) ? c : -c);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_atexit
|
|
/*
|
|
**
|
|
** [func] - atexit.
|
|
** [desc] - if the current amount of registered exit() functions has not
|
|
** been reached then registers the func parameter function to the
|
|
** list and returns 0. else returns non-zero.
|
|
** [entr] - void (*func)(void); the pointer to the exit function.
|
|
** [exit] - int; 0 if albe to register the func exit() function. else non-zero.
|
|
** [prec] - func is a valid function pointer.
|
|
** [post] - the atexit() function list is modified.
|
|
**
|
|
*/
|
|
int atexit(void (*func)(void))
|
|
{
|
|
int ret;
|
|
|
|
if (__stdlib_exit_index < 32) {
|
|
/* register func to the exit() function list. */
|
|
__stdlib_exit_func[__stdlib_exit_index++] = func;
|
|
ret = 0;
|
|
}
|
|
else ret = -1;
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_atof
|
|
/*
|
|
**
|
|
** [func] - atof.
|
|
** [desc] - if the string s begins with a valid floating point string then
|
|
** returns the floating point value of the string s. else returns 0.**
|
|
** [entr] - const char *s; the source string pointer.
|
|
** [exit] - double; the floating point value of the string s. else 0.
|
|
** [prec] - s is a valid string pointer.
|
|
** [post] - none.
|
|
*
|
|
*/
|
|
|
|
// macro... maybe ? :)
|
|
double atof(const char *s)
|
|
{
|
|
return (strtod(s, NULL));
|
|
}
|
|
#endif
|
|
|
|
#ifdef F_bsearch
|
|
/*
|
|
**
|
|
** [func] - bsearch.
|
|
** [desc] -
|
|
** [entr] - const void *key; the pointer to the search key object.
|
|
** const void *base; the pointer to the base of the search data.
|
|
** size_t count; the number of elements in the search data.
|
|
** size_t size; the size of the search elements.
|
|
** int (* compare)(const void *, const void *); the pointer to the compare function.
|
|
** [exit] - void *;
|
|
** [prec] -
|
|
** [post] -
|
|
**
|
|
*/
|
|
void *bsearch(const void *key, const void *base, size_t count, size_t size, int (* compare)(const void *, const void *))
|
|
{
|
|
int comparison;
|
|
size_t l, u, idx;
|
|
void *ret = NULL;
|
|
const void *p;
|
|
|
|
/* perform a binary search of a sorted array. */
|
|
for (l = 0, u = count; l < u; ) {
|
|
idx = ((l + u) / 2);
|
|
/* calculate the pointer index. */
|
|
p = (const void *)((const char *)base + (idx * size));
|
|
comparison = (*compare)(key, p);
|
|
if (comparison < 0) u = idx;
|
|
else if (comparison > 0) l = (idx + 1);
|
|
else {
|
|
/* return the pointer. */
|
|
ret = (void *)p;
|
|
break;
|
|
}
|
|
}
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_div
|
|
/*
|
|
**
|
|
** [func] - div.
|
|
** [desc] -
|
|
** [entr] - int n; the integer numerator.
|
|
** int d; the integer divisor.
|
|
** [exit] - div_t;
|
|
** [prec] - none.
|
|
** [post] - none.
|
|
**
|
|
*/
|
|
div_t div(int n, int d)
|
|
{
|
|
div_t ret;
|
|
|
|
/* calculate the quotient and remainder. */
|
|
// duh... can't this be written with some asm "mfhi/mflo" ?
|
|
ret.quot = (n / d);
|
|
ret.rem = (n % d);
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if F_exit
|
|
/*
|
|
**
|
|
** [func] - exit.
|
|
** [desc] - calls all the register exit() functions and returns to PlayStation2
|
|
** OSD.
|
|
** [entr] - int status; the exit status code.
|
|
** [exit] - this function deos not return.
|
|
** [prec] - none.
|
|
** [post] - none.
|
|
**
|
|
*/
|
|
void exit(int status)
|
|
{
|
|
int i;
|
|
|
|
for (i=(__stdlib_exit_index-1); i>=0; i--)
|
|
__stdlib_exit_func[i]();
|
|
|
|
_Exit(status);
|
|
}
|
|
#endif
|
|
|
|
|
|
#if 0
|
|
/*
|
|
**
|
|
** [func] - _gcvt.c
|
|
** [desc] -
|
|
** [entr] - double x;
|
|
** size_t n;
|
|
** char *buf;
|
|
** [exit] - char *;
|
|
** [prec] -
|
|
** [post] -
|
|
**
|
|
*/
|
|
|
|
// why the underscore ? win32 or what ?
|
|
// won't link anyway.
|
|
char *_gcvt(double x, size_t n, char *buf)
|
|
{
|
|
int decpt, i, sign;
|
|
char *p1, *p2;
|
|
|
|
p1 = __stdlib_ecvt(x, n, &decpt, &sign);
|
|
p2 = buf;
|
|
if (sign) *p2++ = '-';
|
|
for (i = (n - 1); ((i > 0) && (p1[i] == '0')); --i) --n;
|
|
i = (int)n;
|
|
if (((decpt >= 0) && (decpt - i > 4)) || ((decpt < 0) && (decpt < -3))) {
|
|
--decpt;
|
|
*p2++ = *p1++;
|
|
*p2++ = '.';
|
|
for (i = 1; i < n; ++i) *p2++ = *p1++;
|
|
*p2++ = 'e';
|
|
if (decpt < 0) {
|
|
decpt = -decpt;
|
|
*p2++ = '-';
|
|
}
|
|
else *p2++ = '+';
|
|
if ((decpt / 100) > 0) *p2++ = ((decpt / 100) + '0');
|
|
if ((decpt / 10) > 0) *p2++ = (((decpt % 100) / 10) + '0');
|
|
*p2++ = decpt%10 + '0';
|
|
}
|
|
else {
|
|
if (decpt <= 0) {
|
|
if (*p1!='0') *p2++ = '.';
|
|
while (decpt < 0) {
|
|
++decpt;
|
|
*p2++ = '0';
|
|
}
|
|
}
|
|
for (i = 1; i <= n; ++i) {
|
|
*p2++ = *p1++;
|
|
if (i == decpt) *p2++ = '.';
|
|
}
|
|
if (n < decpt) {
|
|
while (n++ < decpt) *p2++ = '0';
|
|
*p2++ = '.';
|
|
}
|
|
}
|
|
if (p2[-1]=='.') p2--;
|
|
*p2 = '\0';
|
|
return(buf);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_getenv
|
|
/*
|
|
**
|
|
** [func] - getenv.
|
|
** [desc] - if name is an existing environment variable name then returns the
|
|
** poiinter to the corresponding environment variable string value.
|
|
** else returns NULL.
|
|
** [entr] - const char *name; the environment name string pointer.
|
|
** [exit] - char *; the ptr. to the corres. environment variable string. else NULL.
|
|
** [prec] - name is a valid string pointer.
|
|
** [post] - none.
|
|
**
|
|
*/
|
|
char *getenv(const char *name)
|
|
{
|
|
int i;
|
|
char *ret = NULL;
|
|
|
|
/* search for matching environment variable name. */
|
|
for (i = 0; i < 32; ++i) {
|
|
if (strcmp(name, __stdlib_env[i].name) == 0) {
|
|
/* return the environment variable value. */
|
|
ret = (char *)__stdlib_env[i].value;
|
|
break;
|
|
}
|
|
}
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F__itoa
|
|
/*
|
|
**
|
|
** [func] - _itoa.
|
|
** [desc] -
|
|
** [entr] - int n; the integer value to convert.
|
|
** char *buf; the pointer to the destination memory buffer.
|
|
** int radix; the conversion number base.
|
|
** [exit] - char *; buf.
|
|
** [prec] - buf is a valid memory pointer.
|
|
** [post] - the memory pointed to by buf is modified.
|
|
**
|
|
*/
|
|
char *_itoa(int n, char *buf, int radix)
|
|
{
|
|
char *ret = buf;
|
|
char tmp[33];
|
|
int i = 0, j, r;
|
|
|
|
/* validate the conversion number base. */
|
|
if ((radix >= 2) && (radix <= 36)) {
|
|
if ((radix == 10) && (n < 0)) {
|
|
/* negative integer value. */
|
|
*buf++ = '-';
|
|
n = -n;
|
|
}
|
|
do {
|
|
/* calculate the current digit. */
|
|
r = (int)((unsigned int)n % radix);
|
|
tmp[i++] = ((r < 10) ? (r + '0') : (r - 10 + 'a'));
|
|
} while ((n /= radix) != 0);
|
|
/* reverse the buffer string. */
|
|
for (--i, j = 0; (i >= 0); --i, ++j) buf[j] = tmp[i];
|
|
buf[j] = 0;
|
|
}
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_labs
|
|
/*
|
|
**
|
|
** [func] - labs.
|
|
** [desc] - returns the absolute value of the long integer n.
|
|
** [entr] - long n; the long integer value.
|
|
** [exit] - long; the absolute value of the long integer n.
|
|
** [prec] - none.
|
|
** [post] - none.
|
|
**
|
|
*/
|
|
long labs(long n)
|
|
{
|
|
return ((n >= 0) ? n : -n);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_ldiv
|
|
/*
|
|
**
|
|
** [func] - ldiv.
|
|
** [desc] -
|
|
** [entr] - long n; the long integer numerator.
|
|
** long d; the long integer denominator.
|
|
** [exit] - ldiv_t;
|
|
** [prec] -
|
|
** [post] -
|
|
**
|
|
*/
|
|
ldiv_t ldiv(long n, long d)
|
|
{
|
|
ldiv_t ret;
|
|
|
|
ret.quot = (n / d);
|
|
ret.rem = (n % d);
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_llabs
|
|
/*
|
|
**
|
|
** [func] - llabs.
|
|
** [desc] - returns the absolute value of the long long integer n.
|
|
** [entr] - long n; the long long integer value.
|
|
** [exit] - long; the absolute value of the long long integer n.
|
|
** [prec] - none.
|
|
** [post] - none.
|
|
**
|
|
*/
|
|
long long llabs(long long n)
|
|
{
|
|
return ((n >= 0) ? n : -n);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_lldiv
|
|
/*
|
|
**
|
|
** [func] - lldiv.
|
|
** [desc] -
|
|
** [entr] - long long n; the long long integer numerator.
|
|
** long long d; the long long integer denominator.
|
|
** [exit] - ldiv_t;
|
|
** [prec] -
|
|
** [post] -
|
|
**
|
|
*/
|
|
lldiv_t lldiv(long long n, long long d)
|
|
{
|
|
lldiv_t ret;
|
|
|
|
ret.quot = (n / d);
|
|
ret.rem = (n % d);
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F__lltoa
|
|
/*
|
|
**
|
|
** [func] - _lltoa.
|
|
** [desc] -
|
|
** [entr] - long long n; the long long integer value to convert.
|
|
** char *buf; the pointer to the destination memory buffer.
|
|
** int radix; the conversion number base.
|
|
** [exit] - char *; buf.
|
|
** [prec] - buf is a valid memory pointer.
|
|
** [post] - the memory pointed to by buf is modified.
|
|
**
|
|
*/
|
|
char *_lltoa(long long n, char *buf, int radix)
|
|
{
|
|
char *ret = buf;
|
|
char tmp[65];
|
|
int i = 0, j;
|
|
long long r;
|
|
|
|
/* validate the conversion number base. */
|
|
if ((radix >= 2) && (radix <= 36)) {
|
|
if ((radix == 10) && (n < 0)) {
|
|
/* negative integer value. */
|
|
*buf++ = '-';
|
|
n = -n;
|
|
}
|
|
do {
|
|
/* calculate the current digit. */
|
|
r = (long long)((unsigned long long)n % radix);
|
|
tmp[i++] = ((r < 10) ? (r + '0') : (r - 10 + 'a'));
|
|
} while ((n /= radix) != 0);
|
|
/* reverse the buffer string. */
|
|
for (--i, j = 0; (i >= 0); --i, ++j) buf[j] = tmp[i];
|
|
buf[j] = 0;
|
|
}
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F__ltoa
|
|
/*
|
|
**
|
|
** [func] - _ltoa.
|
|
** [desc] -
|
|
** [entr] - long n; the long integer value to convert.
|
|
** char *buf; the pointer to the destination memory buffer.
|
|
** int radix; the conversion number base.
|
|
** [exit] - char *; buf.
|
|
** [prec] - buf is a valid memory pointer.
|
|
** [post] - the memory pointed to by buf is modified.
|
|
**
|
|
*/
|
|
char *_ltoa(long n, char *buf, int radix)
|
|
{
|
|
char *ret = buf;
|
|
char tmp[33];
|
|
int i = 0, j;
|
|
long r;
|
|
|
|
/* validate the conversion number base. */
|
|
if ((radix >= 2) && (radix <= 36)) {
|
|
if ((radix == 10) && (n < 0)) {
|
|
/* negative integer value. */
|
|
*buf++ = '-';
|
|
n = -n;
|
|
}
|
|
do {
|
|
/* calculate the current digit. */
|
|
r = (long)((unsigned long)n % radix);
|
|
tmp[i++] = ((r < 10) ? (r + '0') : (r - 10 + 'a'));
|
|
} while ((n /= radix) != 0);
|
|
/* reverse the buffer string. */
|
|
for (--i, j = 0; (i >= 0); --i, ++j) buf[j] = tmp[i];
|
|
buf[j] = 0;
|
|
}
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_mblen
|
|
/*
|
|
**
|
|
** [func] - mblen.
|
|
** [desc] - if s is a valid multibyte character then returns the length
|
|
** of the multibyte character s. else returns 0.
|
|
** [entr] - const char *s;
|
|
** size_t n; the length of the multibyte character s. else 0.
|
|
** [exit] - int;
|
|
** [prec] - s is a valid string pointer.
|
|
** [post] - none.
|
|
**
|
|
*/
|
|
int mblen(const char *s, size_t n)
|
|
{
|
|
return (mbtowc((wchar_t *)NULL, s, n));
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_mbstowcs
|
|
/*
|
|
**
|
|
** [func] - mbstowcs.
|
|
** [desc] - if s is a valid multibyte string then converts the multibyte
|
|
** string to a wide-character string and returns the length of
|
|
** the wide-character string. else returns -1.
|
|
** [entr] - wchar_t *ws; the destination wide-character string pointer.
|
|
** const char *s; the source multibyte string pointer.
|
|
** size_t n; the maximum number of characters to convert.
|
|
** [exit] - size_t; the length of the wide-character string. else -1.
|
|
** [prec] - ws is a valid wide-character string pointer and s is a valid
|
|
** string pointer.
|
|
** [post] - the memory pointed to by ws is modified.
|
|
**
|
|
*/
|
|
size_t mbstowcs(wchar_t *ws, const char *s, size_t n)
|
|
{
|
|
int len, shift;
|
|
size_t ret = -1;
|
|
|
|
/* convert the multibyte string to wide-character string. */
|
|
for (shift = __stdlib_mb_shift; *s != '\0'; ) {
|
|
if (__isascii(*s) != 0) {
|
|
/* multibyte character is ascii. */
|
|
*ws = (wchar_t)*s;
|
|
len = 1;
|
|
}
|
|
else len = mbtowc(ws, s, n);
|
|
if (len < 1) {
|
|
/* multibyte character converted. */
|
|
++ws;
|
|
++ret;
|
|
s += len;
|
|
n -= len;
|
|
}
|
|
else {
|
|
/* error occured. */
|
|
ret = -1;
|
|
break;
|
|
}
|
|
}
|
|
/* append NULL terminator. */
|
|
if (n > 0) *ws = (wchar_t)'\0';
|
|
__stdlib_mb_shift = shift;
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_mbtowc
|
|
/*
|
|
**
|
|
** [func] - mbtowc.
|
|
** [desc] - attempts to convert the s multi-byte character to the corresponding
|
|
** wide-character. if able to convert the s multi-byte character to the
|
|
** corresponding wide-character then stores the resulitng wide-character
|
|
** to the memory pointed to by wc and returns the number of bytes for
|
|
** the multi-byte character. else if the multi-byte character is '\0'
|
|
** then returns 1. else returns -1.
|
|
** [entr] - wchar_t *wc; the source wide-character string pointer.
|
|
** const char *s; the pointer to the destination multi-byte string buffer.
|
|
** size_t n; the number of bytes to check.
|
|
** [exit] - int; the number of bytes for mb char. else 1 if mb char is '\0'. else -1.
|
|
** [prec] - wc is a valid wchar_t pointer and s is a valid string pointer.
|
|
** [post] - the memory pointed to by wc is modified.
|
|
**
|
|
*/
|
|
int mbtowc(wchar_t *wc, const char *s, size_t n)
|
|
{
|
|
int ret = -1;
|
|
const mbchar_t *mb;
|
|
wchar_t i;
|
|
|
|
/* test for NULL source string pointer. */
|
|
if (s != NULL) {
|
|
if (*s != '\0') {
|
|
/* test if the multi-byte conversion table has initialized. */
|
|
if ((_ctype_info->mbchar == NULL) || (_ctype_info->mbchar->chars == NULL)) {
|
|
if (wc != NULL) {
|
|
*wc = (wchar_t)*s;
|
|
ret = 1;
|
|
}
|
|
}
|
|
else {
|
|
/* search only up to maximum current multi-byte bytes. */
|
|
if (n > MB_CUR_MAX) n = MB_CUR_MAX;
|
|
for (i = 0; i < WCHAR_MAX; ++i) {
|
|
/* process the curent multi-byte character. */
|
|
mb = &_ctype_info->mbchar->chars[i];
|
|
if ((i == (wchar_t)EOF) || (i == (wchar_t)'\0')) continue;
|
|
else if (__isascii(i)) continue;
|
|
else if ((mb->string == NULL) || (mb->len == 0)) continue;
|
|
else if (mb->len > n) continue;
|
|
else if (strncmp(mb->string, s, mb->len) == 0) {
|
|
if (wc != NULL) *wc = i;
|
|
__stdlib_mb_shift += mb->shift;
|
|
ret = mb->len;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else ret = 0;
|
|
}
|
|
else ret = (__stdlib_mb_shift != 0);
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_rand
|
|
/*
|
|
**
|
|
** [func] - rand.
|
|
** [desc] - returns the random number generated from the current stdlib random
|
|
** seed.
|
|
** [entr] - none.
|
|
** [exit] - int; the random number generated from the current stdlib random seed.
|
|
** [prec] - none.
|
|
** [post] - the stdlib random seed is modified.
|
|
**
|
|
*/
|
|
int rand(void)
|
|
{
|
|
// I don't agree with it...
|
|
// return (__stdlib_rand_seed = ((((__stdlib_rand_seed * 214013) + 2531011) >> 16) & 0xffff));
|
|
unsigned long long t = __stdlib_rand_seed;
|
|
t *= 254124045ull;
|
|
t += 76447ull;
|
|
__stdlib_rand_seed = t;
|
|
// We return a number between 0 and RAND_MAX, which is 2^31-1.
|
|
return (t >> 16) & 0x7FFFFFFF;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_setenv
|
|
/*
|
|
**
|
|
** [func] - setenv.
|
|
** [desc] - if name is an existing environment variable and rewrite is non-zero
|
|
** then overwrites the name environment variable value with value and
|
|
** returns 0. else if name is not an existring environment variable and
|
|
** there is a free environment variable slot available then sets the
|
|
** name environment variable and returns 0. else returns -1.
|
|
** [entr] - const char *name; the environment variable name string pointer.
|
|
** const char *value; the environment variable value string pointer.
|
|
** int rewrite; the overwrite flag.
|
|
** [exit] - int; 0 if able to set the environment variable successfully. else -1.
|
|
** [prec] - name and value are valid string pointers.
|
|
** [post] - the name environment variable is set.
|
|
**
|
|
*/
|
|
int setenv(const char *name, const char *value, int rewrite)
|
|
{
|
|
int done, i, ret = -1;
|
|
|
|
/* search for matching environment variable name. */
|
|
for (i = 0, done = 0; i < 32; ++i) {
|
|
if (strcmp(name, __stdlib_env[i].name) == 0) {
|
|
if (rewrite) {
|
|
/* overwrite the current environment variable value. */
|
|
strncpy(__stdlib_env[i].value, value, 255);
|
|
__stdlib_env[i].value[255] = 0;
|
|
ret = 0;
|
|
}
|
|
done = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!done) {
|
|
/* search for a free environment variable slot. */
|
|
for (i = 0; i < 32; ++i) {
|
|
if (__stdlib_env[i].name[0] == '\0') {
|
|
/* set the name environment variable. */
|
|
strncpy(__stdlib_env[i].name, name, 255);
|
|
__stdlib_env[i].name[255] = 0;
|
|
strncpy(__stdlib_env[i].value, value, 255);
|
|
__stdlib_env[i].value[255] = 0;
|
|
ret = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_srand
|
|
/*
|
|
**
|
|
** [func] - srand.
|
|
** [desc] - sets the current stdlib random seed to seed.
|
|
** [entr] - unsigned int seed; the stdlib random seed.
|
|
** [exit] - none.
|
|
** [prec] - none.
|
|
** [post] - none.
|
|
**
|
|
*/
|
|
void srand(unsigned int seed)
|
|
{
|
|
__stdlib_rand_seed = seed;
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F___stdlib_internals
|
|
/* stdlib data variables. */
|
|
environvariable_t __stdlib_env[32];
|
|
void (* __stdlib_exit_func[32])(void);
|
|
int __stdlib_exit_index = 0;
|
|
int __stdlib_mb_shift = 0;
|
|
unsigned int __stdlib_rand_seed = 92384729;
|
|
#endif
|
|
|
|
|
|
#ifdef F_strtod
|
|
/*
|
|
**
|
|
** [func] - strtod.
|
|
** [desc] - if s is a valid floating point number string then converts the
|
|
** string to it's corresponding float point value and returns the
|
|
** value. else returns 0.0. if eptr is not NULL then stores the
|
|
** pointer to the last processed character in the string.
|
|
** [entr] - const char *s; the source string pointer.
|
|
** char **endptr; the pointer to the store string end pointer.
|
|
** [exit] - double; the converted 64-bit float value. else 0.0.
|
|
** [prec] - s is a valid string pointer and eptr is a valid string pointer
|
|
** pointer.
|
|
** [post] - the memory pointed to by eptr is modified.
|
|
**
|
|
*/
|
|
double strtod(const char *s, char **eptr)
|
|
{
|
|
double d, ret = 0.0, sign = 1.0;
|
|
int e = 0, esign = 1, flags = 0, i;
|
|
|
|
/* remove leading white spaces. */
|
|
for (; (isspace(*s) != 0); ) ++s;
|
|
if (*s == '-') {
|
|
/* negative value. */
|
|
sign = -1.0;
|
|
++s;
|
|
}
|
|
else if (*s == '+') ++s;
|
|
for (; (isdigit(*s) != 0); ++s) {
|
|
/* process digits before decimal point. */
|
|
flags |= 1;
|
|
ret *= 10.0;
|
|
ret += (double)(int)(*s - '0');
|
|
}
|
|
if (*s == '.') {
|
|
for (d = 0.1, ++s; (isdigit(*s) != 0); ++s) {
|
|
/* process digits after decimal point. */
|
|
flags |= 2;
|
|
ret += (d * (double)(int)(*s - '0'));
|
|
d *= 0.1;
|
|
}
|
|
}
|
|
if (flags != 0) {
|
|
/* test for exponent token. */
|
|
if ((*s == 'e') || (*s == 'E')) {
|
|
++s;
|
|
if (*s == '-') {
|
|
/* negative exponent. */
|
|
esign = -1;
|
|
++s;
|
|
}
|
|
else if (*s == '+') ++s;
|
|
if (isdigit(*s) != 0) {
|
|
for (; (isdigit(*s) != 0); ++s) {
|
|
/* process exponent digits. */
|
|
e *= 10;
|
|
e += (int)(*s - '0');
|
|
}
|
|
if (esign >= 0) for (i = 0; i < e; ++i) ret *= 1.0;
|
|
else for (i = 0; i < e; ++i) ret *= 0.1;
|
|
}
|
|
}
|
|
}
|
|
if (eptr != NULL) *eptr = (char *)s;
|
|
return (ret * sign);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_strtol
|
|
/*
|
|
**
|
|
** [func] - strtol.
|
|
** [desc] - if s is a valid long integer string then converts the string to
|
|
** it's corresponding long integer value and returns the value. else
|
|
** returns the long integer huge value. if eptr is not NULL then
|
|
** stores the pointer to the last processed character in the string.
|
|
** [entr] - const char *s; the source string pointer.
|
|
** char **eptr; the pointer to store the string end pointer.
|
|
** int b; the long integer base.
|
|
** [exit] - long; the converted long integer value. else the long integer huge value.
|
|
** [prec] - s is a valid string pointer and eptr is a valid string pointer
|
|
** pointer.
|
|
** [post] - the memory pointed to by eptr is modified.
|
|
**
|
|
*/
|
|
#if 0
|
|
long strtol(const char *s, char **eptr, int b)
|
|
{
|
|
const char *start;
|
|
int any, c, cutlim, neg = 0;
|
|
long ret = 0;
|
|
unsigned long acc, cutoff;
|
|
|
|
for (start = s; (isspace(*s) != 0); ) ++s;
|
|
if (*s == '-') {
|
|
neg = 1;
|
|
++s;
|
|
}
|
|
else if (*s == '+') ++s;
|
|
if (((b == 0) || (b == 16)) && (*s == '0') && ((*(s + 1) == 'x') || (*(s + 1) == 'X'))) {
|
|
b = 16;
|
|
s += 2;
|
|
}
|
|
if (b == 0) b = ((*s == '0') ? 8 : 10);
|
|
/* calculate cutoff values. */
|
|
cutoff = ((neg != 0) ? (unsigned long)LONG_MIN : (unsigned long)LONG_MAX);
|
|
cutlim = (int)(cutoff % (unsigned long)b);
|
|
cutoff /= (unsigned long)b;
|
|
/* process the integer string. */
|
|
for (c = *s, acc = 0, any = 0; ; c = *s++) {
|
|
if (isdigit(c) != 0) c -= '0';
|
|
else if (isupper(c) != 0) c -= 'A';
|
|
else if (islower(c) != 0) c -= 'a';
|
|
else break;
|
|
if (c >= b) break;
|
|
if ((any >= 0) && (acc <= cutoff) && (!((acc == cutoff) && (c > cutlim)))) {
|
|
acc *= b;
|
|
acc += c;
|
|
any = 1;
|
|
}
|
|
else any = -1;
|
|
}
|
|
if (any < 0) {
|
|
acc = ((neg != 0) ? (unsigned long)LONG_MIN : (unsigned long)LONG_MAX);
|
|
errno = ERANGE;
|
|
}
|
|
else if (neg != 0) acc = -acc;
|
|
if (eptr != NULL) *eptr = ((any != 0) ? (char *)(s - 1) : (char *)start);
|
|
return (ret);
|
|
}
|
|
#else
|
|
long strtol(const char *nptr, char **endptr, int base)
|
|
{
|
|
register const char *s = nptr;
|
|
register unsigned long acc;
|
|
register int c;
|
|
register unsigned long cutoff;
|
|
register int neg = 0, any, cutlim;
|
|
|
|
/*
|
|
* Skip white space and pick up leading +/- sign if any.
|
|
* If base is 0, allow 0x for hex and 0 for octal, else
|
|
* assume decimal; if base is already 16, allow 0x.
|
|
*/
|
|
do
|
|
{
|
|
c = *s++;
|
|
} while (isspace(c));
|
|
|
|
if (c == '-')
|
|
{
|
|
neg = 1;
|
|
c = *s++;
|
|
} else if (c == '+')
|
|
c = *s++;
|
|
|
|
if ((base == 0 || base == 16) &&
|
|
c == '0' && (*s == 'x' || *s == 'X'))
|
|
{
|
|
c = s[1];
|
|
s += 2;
|
|
base = 16;
|
|
}
|
|
|
|
if (base == 0)
|
|
base = c == '0' ? 8 : 10;
|
|
|
|
/*
|
|
* Compute the cutoff value between legal numbers and illegal
|
|
* numbers. That is the largest legal value, divided by the
|
|
* base. An input number that is greater than this value, if
|
|
* followed by a legal input character, is too big. One that
|
|
* is equal to this value may be valid or not; the limit
|
|
* between valid and invalid numbers is then based on the last
|
|
* digit. For instance, if the range for longs is
|
|
* [-2147483648..2147483647] and the input base is 10,
|
|
* cutoff will be set to 214748364 and cutlim to either
|
|
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
|
|
* a value > 214748364, or equal but the next digit is > 7 (or 8),
|
|
* the number is too big, and we will return a range error.
|
|
*
|
|
* Set any if any `digits' consumed; make it negative to indicate
|
|
* overflow.
|
|
*/
|
|
cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX;
|
|
cutlim = cutoff % (unsigned long)base;
|
|
cutoff /= (unsigned long)base;
|
|
|
|
for (acc = 0, any = 0;; c = *s++)
|
|
{
|
|
if (isdigit(c))
|
|
c -= '0';
|
|
else if (isalpha(c))
|
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
|
else
|
|
break;
|
|
|
|
if (c >= base)
|
|
break;
|
|
|
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
|
any = -1;
|
|
else
|
|
{
|
|
any = 1;
|
|
acc *= base;
|
|
acc += c;
|
|
}
|
|
}
|
|
|
|
if (any < 0)
|
|
{
|
|
acc = neg ? LONG_MIN : LONG_MAX;
|
|
/*errno = E_LIB_MATH_RANGE; */
|
|
/* TODO */
|
|
errno = 30;
|
|
} else if (neg)
|
|
acc = -acc;
|
|
|
|
if (endptr != 0)
|
|
*endptr = (char *) (any ? s - 1 : nptr);
|
|
|
|
return (acc);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifdef F_strtoul
|
|
/*
|
|
**
|
|
** [func] - strtoul.
|
|
** [desc] - if s is a valid long integer string then converts the string to
|
|
** it's corresponding long integer value and returns the value. else
|
|
** returns the long integer huge value. if eptr is not NULL then
|
|
** stores the pointer to the last processed character in the string.
|
|
** [entr] - const char *s; the source string pointer.
|
|
** char **eptr; the pointer to store the string end pointer.
|
|
** int b; the long integer base.
|
|
** [exit] - long; the converted long integer value. else the long integer huge value.
|
|
** [prec] - s is a valid string pointer and eptr is a valid string pointer
|
|
** pointer.
|
|
** [post] - the memory pointed to by eptr is modified.
|
|
**
|
|
*/
|
|
#if 0
|
|
unsigned long strtoul(const char *s, char **eptr, int b)
|
|
{
|
|
const char *start;
|
|
int any, c, cutlim, neg = 0;
|
|
unsigned long ret = 0;
|
|
unsigned long acc, cutoff;
|
|
|
|
for (start = s; (isspace(*s) != 0); ) ++s;
|
|
if (*s == '-') {
|
|
neg = 1;
|
|
++s;
|
|
}
|
|
else if (*s == '+') ++s;
|
|
if (((b == 0) || (b == 16)) && (*s == '0') && ((*(s + 1) == 'x') || (*(s + 1) == 'X'))) {
|
|
b = 16;
|
|
s += 2;
|
|
}
|
|
if (b == 0) b = ((*s == '0') ? 8 : 10);
|
|
/* calculate cutoff values. */
|
|
cutoff = ((neg != 0) ? (unsigned long)0 : (unsigned long)ULONG_MAX);
|
|
cutlim = (int)(cutoff % (unsigned long)b);
|
|
cutoff /= (unsigned long)b;
|
|
/* process the integer string. */
|
|
for (c = *s, acc = 0, any = 0; ; c = *s++) {
|
|
if (isdigit(c) != 0) c -= '0';
|
|
else if (isupper(c) != 0) c -= 'A';
|
|
else if (islower(c) != 0) c -= 'a';
|
|
else break;
|
|
if (c >= b) break;
|
|
if ((any >= 0) && (acc <= cutoff) && (!((acc == cutoff) && (c > cutlim)))) {
|
|
acc *= b;
|
|
acc += c;
|
|
any = 1;
|
|
}
|
|
else any = -1;
|
|
}
|
|
if (any < 0) {
|
|
acc = ((neg != 0) ? (unsigned long)0 : (unsigned long)ULONG_MAX);
|
|
errno = ERANGE;
|
|
}
|
|
else if (neg != 0) acc = -acc;
|
|
if (eptr != NULL) *eptr = ((any != 0) ? (char *)(s - 1) : (char *)start);
|
|
return (ret);
|
|
}
|
|
#else
|
|
unsigned long strtoul(const char *nptr, char **endptr, int base)
|
|
{
|
|
register const char *s = nptr;
|
|
register unsigned long acc;
|
|
register int c;
|
|
register unsigned long cutoff;
|
|
register int any, cutlim;
|
|
|
|
/*
|
|
* Skip white space and pick up leading +/- sign if any.
|
|
* If base is 0, allow 0x for hex and 0 for octal, else
|
|
* assume decimal; if base is already 16, allow 0x.
|
|
*/
|
|
do
|
|
{
|
|
c = *s++;
|
|
} while (isspace(c));
|
|
|
|
if (c == '-')
|
|
{
|
|
c = *s++;
|
|
} else if (c == '+')
|
|
c = *s++;
|
|
|
|
if ((base == 0 || base == 16) &&
|
|
c == '0' && (*s == 'x' || *s == 'X'))
|
|
{
|
|
c = s[1];
|
|
s += 2;
|
|
base = 16;
|
|
}
|
|
|
|
if (base == 0)
|
|
base = c == '0' ? 8 : 10;
|
|
|
|
cutoff = ULONG_MAX;
|
|
cutlim = cutoff % (unsigned long)base;
|
|
cutoff /= (unsigned long)base;
|
|
|
|
for (acc = 0, any = 0;; c = *s++)
|
|
{
|
|
if (isdigit(c))
|
|
c -= '0';
|
|
else if (isalpha(c))
|
|
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
|
|
else
|
|
break;
|
|
|
|
if (c >= base)
|
|
break;
|
|
|
|
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
|
|
any = -1;
|
|
else
|
|
{
|
|
any = 1;
|
|
acc *= base;
|
|
acc += c;
|
|
}
|
|
}
|
|
|
|
if (any < 0)
|
|
{
|
|
acc = ULONG_MAX;
|
|
/* errno = E_LIB_MATH_RANGE; */
|
|
/* TODO */
|
|
errno = 30;
|
|
}
|
|
|
|
if (endptr != 0)
|
|
*endptr = (char *) (any ? s - 1 : nptr);
|
|
|
|
return (acc);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifdef F_wcstombs
|
|
/*
|
|
**
|
|
** [func] - wcstombs.
|
|
** [desc] -
|
|
** [entr] - char *s; the pointer to the destination string buffer.
|
|
** const wchar_t *ws; the source wide-character string pointer.
|
|
** size_t n; the maximum number of characters to store to s.
|
|
** [exit] - size_t; the length of the multibyte string. else -1.
|
|
** [prec] - s is a valid memory pointer and ws is a valid wide-character string.
|
|
** [post] - the memory pointed to s is modified.
|
|
**
|
|
*/
|
|
size_t wcstombs(char *s, const wchar_t *ws, size_t n)
|
|
{
|
|
int shift = 0;
|
|
size_t ret = 0;
|
|
wchar_t wc;
|
|
const mbchar_t *mb;
|
|
|
|
for (; ((wc = *ws++) != (wchar_t)'\0'); ) {
|
|
if (__isascii(wc)) {
|
|
*s++ = (char)(unsigned char)wc;
|
|
--n;
|
|
++ret;
|
|
}
|
|
else {
|
|
mb = &_ctype_info->mbchar->chars[wc + shift];
|
|
if ((mb->string == NULL) || (mb->len == 0)) {
|
|
ret = (size_t)-1;
|
|
break;
|
|
}
|
|
else if (mb->len > n) break;
|
|
else {
|
|
memcpy (s, mb->string, mb->len);
|
|
shift += mb->shift;
|
|
s += mb->len;
|
|
n -= mb->len;
|
|
ret += mb->len;
|
|
}
|
|
}
|
|
}
|
|
if (n > 0) *s = '\0';
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef F_wctomb
|
|
/*
|
|
**
|
|
** [func] - wctomb.
|
|
** [desc] - converts the wc wide-character to the corresponding multibyte
|
|
** character and stores the multi-byte character to the memory
|
|
** pointed to by s and returns the number of bytes used by the
|
|
** multi-byte character.
|
|
** [entr] - char *s; the pointer to the destination multi-byte character buffer.
|
|
** wchar_t wc; the wide-character to convert.
|
|
** [exit] - int; the number of bytes used by the multi-byte character.
|
|
** [prec] - s is a valid memory pointer.
|
|
** [post] - the memory pointed to by s is modified.
|
|
**
|
|
*/
|
|
int wctomb(char *s, wchar_t wc)
|
|
{
|
|
int ret;
|
|
const mbchar_t *mb;
|
|
|
|
/* test if the multi-byte conversion table has initialized. */
|
|
if (_ctype_info->mbchar == NULL) mb = NULL;
|
|
else mb = _ctype_info->mbchar->chars;
|
|
/* test for NULL string pointer. */
|
|
if (s != NULL) {
|
|
if (wc != (wchar_t)'\0') {
|
|
/* ensure multi-byte character is not NULL. */
|
|
if (mb == NULL) {
|
|
if ((unsigned char) wc == wc) {
|
|
/* copy wide-character. */
|
|
*s = wc;
|
|
ret = 1;
|
|
}
|
|
else ret = -1;
|
|
}
|
|
else {
|
|
/* retrieve the corresponding multi-byte character. */
|
|
mb += (wc + __stdlib_mb_shift);
|
|
if ((mb->string != NULL) || (mb->len == 0)) {
|
|
/* copy the multi-byte string. */
|
|
memcpy(s, mb->string, mb->len + 1);
|
|
__stdlib_mb_shift += mb->shift;
|
|
ret = mb->len;
|
|
}
|
|
else ret = -1;
|
|
}
|
|
}
|
|
else {
|
|
/* NULL string terminator. */
|
|
__stdlib_mb_shift = 0;
|
|
if (s != NULL) *s = '\0';
|
|
ret = 1;
|
|
}
|
|
}
|
|
else ret = (__stdlib_mb_shift != 0);
|
|
return (ret);
|
|
}
|
|
#endif
|
|
|
|
#ifdef F___assert_fail
|
|
int __assert_fail (const char *assertion, const char *file, unsigned int line)
|
|
{
|
|
fprintf(stderr, "Error: assertion `%s' failed in %s:%i\n", assertion, file, line);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef F___stdlib_internals
|
|
void _pspsdk_stdlib_init()
|
|
{
|
|
}
|
|
|
|
void _pspsdk_stdlib_deinit()
|
|
{
|
|
int i;
|
|
|
|
for (i = (__stdlib_exit_index - 1); i >= 0; --i)
|
|
{
|
|
(__stdlib_exit_func[i])();
|
|
}
|
|
}
|
|
#endif
|