marioparty4/src/MSL_C.PPCEABI.bare.H/strtoul.c
dbalatoni13 cdb1d1fc37
Import gx, PadClamp, rest of mtx, TRK 2.6 and MSL (#525)
* Match mtx and Padclamp.c

* Match the rest of GX

* Import TRK 2.6

* Import MSL headers and files

* Merge some MSL headers into ours
2025-01-12 08:11:23 -06:00

199 lines
4 KiB
C

#include "PowerPC_EABI_Support/Msl/MSL_C/MSL_Common/strtoul.h"
#include "PowerPC_EABI_Support/Msl/MSL_C/MSL_Common/ctype.h"
#include "PowerPC_EABI_Support/Msl/MSL_C/MSL_Common/errno.h"
#include "PowerPC_EABI_Support/Msl/MSL_C/MSL_Common/limits.h"
#include "PowerPC_EABI_Support/Msl/MSL_C/MSL_Common/scanf.h"
enum scan_states {
start = 0x01,
check_for_zero = 0x02,
leading_zero = 0x04,
need_digit = 0x08,
digit_loop = 0x10,
finished = 0x20,
failure = 0x40
};
#define final_state(scan_state) (scan_state & (finished | failure))
#define success(scan_state) \
(scan_state & (leading_zero | digit_loop | finished))
#define fetch() (count++, (*ReadProc)(ReadProcArg, 0, __GetAChar))
#define unfetch(c) (*ReadProc)(ReadProcArg, c, __UngetAChar)
unsigned long __strtoul(int base, int max_width,
int (*ReadProc)(void*, int, int), void* ReadProcArg,
int* chars_scanned, int* negative, int* overflow)
{
int scan_state = start;
int count = 0;
unsigned long value = 0;
unsigned long value_max = 0;
int c;
*negative = *overflow = 0;
if (base < 0 || base == 1 || base > 36 || max_width < 1) {
scan_state = failure;
} else {
c = fetch();
}
if (base != 0)
value_max = ULONG_MAX / base;
while (count <= max_width && c != -1 && !final_state(scan_state)) {
switch (scan_state) {
case start:
if (isspace(c)) {
c = fetch();
break;
}
if (c == '+') {
c = fetch();
} else if (c == '-') {
c = fetch();
*negative = 1;
}
scan_state = check_for_zero;
break;
case check_for_zero:
if (base == 0 || base == 16) {
if (c == '0') {
scan_state = leading_zero;
c = fetch();
break;
}
}
scan_state = need_digit;
break;
case 4:
if (c == 'X' || c == 'x') {
base = 16;
scan_state = need_digit;
c = fetch();
break;
}
if (base == 0)
base = 8;
scan_state = digit_loop;
break;
case need_digit:
case digit_loop:
if (base == 0)
base = 10;
if (!value_max) {
value_max = ULONG_MAX / base;
}
if (isdigit(c)) {
if ((c -= '0') >= base) {
if (scan_state == digit_loop)
scan_state = finished;
else
scan_state = failure;
c += '0';
break;
}
} else if (!isalpha(c) || (toupper(c) - 'A' + 10) >= base) {
if (scan_state == digit_loop)
scan_state = finished;
else
scan_state = failure;
break;
} else {
c = toupper(c) - 'A' + 10;
}
if (value > value_max)
*overflow = 1;
value *= base;
if (c > (ULONG_MAX - value))
*overflow = 1;
value += c;
scan_state = digit_loop;
c = fetch();
break;
}
}
if (!success(scan_state)) {
value = 0;
count = 0;
} else {
count--;
}
*chars_scanned = count;
unfetch(c);
return value;
}
unsigned long strtoul(const char* str, char** end, int base)
{
unsigned long value;
int count, negative, overflow;
__InStrCtrl isc;
isc.NextChar = (char*)str;
isc.NullCharDetected = 0;
value = __strtoul(base, 0x7FFFFFFF, &__StringRead, (void*)&isc, &count,
&negative, &overflow);
if (end) {
*end = (char*)str + count;
}
if (overflow) {
value = ULONG_MAX;
errno = 0x22;
} else if (negative) {
value = -value;
}
return value;
}
long strtol(const char* str, char** end, int base)
{
unsigned long uvalue;
long svalue;
int count, negative, overflow;
__InStrCtrl isc;
isc.NextChar = (char*)str;
isc.NullCharDetected = 0;
uvalue = __strtoul(base, 0x7FFFFFFF, &__StringRead, (void*)&isc, &count,
&negative, &overflow);
if (end) {
*end = (char*)str + count;
}
if (overflow || (!negative && uvalue > LONG_MAX)
|| (negative && uvalue > -LONG_MIN)) {
svalue = (negative ? -LONG_MIN : LONG_MAX);
errno = ERANGE;
} else {
svalue = (negative ? (long)-uvalue : (long)uvalue);
}
return svalue;
}