mirror of
https://github.com/cc65/cc65.git
synced 2024-12-24 11:31:31 +00:00
Added a (currently untested) strtoul implementation. strtol and strtoul should
probably get merged somehow, because they share quite some code. git-svn-id: svn://svn.cc65.org/cc65/trunk@4180 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
2f2bced531
commit
5e55e1c651
@ -74,6 +74,7 @@ C_OBJS = _afailed.o \
|
||||
strftime.o \
|
||||
strtok.o \
|
||||
strtol.o \
|
||||
strtoul.o \
|
||||
strxfrm.o \
|
||||
system.o \
|
||||
timezone.o
|
||||
|
119
libsrc/common/strtoul.c
Normal file
119
libsrc/common/strtoul.c
Normal file
@ -0,0 +1,119 @@
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
unsigned long __fastcall__ strtoul (const char* nptr, char** endptr, int base)
|
||||
/* Convert a string to a long unsigned int */
|
||||
{
|
||||
register const char* S = nptr;
|
||||
unsigned long Val = 0;
|
||||
unsigned char Minus = 0;
|
||||
unsigned char Ovf = 0;
|
||||
unsigned CvtCount = 0;
|
||||
unsigned char DigitVal;
|
||||
unsigned long MaxVal;
|
||||
unsigned char MaxDigit;
|
||||
|
||||
|
||||
/* Skip white space */
|
||||
while (isspace (*S)) {
|
||||
++S;
|
||||
}
|
||||
|
||||
/* Check for leading + or - sign */
|
||||
switch (*S) {
|
||||
case '-':
|
||||
Minus = 1;
|
||||
/* FALLTHROUGH */
|
||||
case '+':
|
||||
++S;
|
||||
}
|
||||
|
||||
/* If base is zero, we may have a 0 or 0x prefix. If base is 16, we may
|
||||
* have a 0x prefix.
|
||||
*/
|
||||
if (base == 0) {
|
||||
if (*S == '0') {
|
||||
++S;
|
||||
if (*S == 'x' || *S == 'X') {
|
||||
++S;
|
||||
base = 16;
|
||||
} else {
|
||||
base = 8;
|
||||
}
|
||||
} else {
|
||||
base = 10;
|
||||
}
|
||||
} else if (base == 16 && *S == '0' && (S[1] == 'x' || S[1] == 'X')) {
|
||||
S += 2;
|
||||
}
|
||||
|
||||
/* Determine the maximum valid number and (if the number is equal to this
|
||||
* value) the maximum valid digit.
|
||||
*/
|
||||
MaxDigit = ULONG_MAX % base;
|
||||
MaxVal = ULONG_MAX / base;
|
||||
|
||||
/* Convert the number */
|
||||
while (1) {
|
||||
|
||||
/* Convert the digit into a numeric value */
|
||||
if (isdigit (*S)) {
|
||||
DigitVal = *S - '0';
|
||||
} else if (isupper (*S)) {
|
||||
DigitVal = *S - ('A' - 10);
|
||||
} else if (islower (*S)) {
|
||||
DigitVal = *S - ('a' - 10);
|
||||
} else {
|
||||
/* Unknown character */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Don't accept a character that doesn't match base */
|
||||
if (DigitVal >= base) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Don't accept anything that makes the final value invalid */
|
||||
if (Val > MaxVal || (Val == MaxVal && DigitVal > MaxDigit)) {
|
||||
Ovf = 1;
|
||||
}
|
||||
|
||||
/* Calculate the next value if digit is not invalid */
|
||||
if (Ovf == 0) {
|
||||
Val = (Val * base) + DigitVal;
|
||||
++CvtCount;
|
||||
}
|
||||
|
||||
/* Next character from input */
|
||||
++S;
|
||||
}
|
||||
|
||||
/* Store the end pointer. If no conversion was performed, the value of
|
||||
* nptr is returned in endptr.
|
||||
*/
|
||||
if (endptr) {
|
||||
if (CvtCount > 0) {
|
||||
*endptr = (char*) S - 1;
|
||||
} else {
|
||||
*endptr = (char*) nptr;
|
||||
}
|
||||
}
|
||||
|
||||
/* Handle overflow */
|
||||
if (Ovf) {
|
||||
errno = ERANGE;
|
||||
return ULONG_MAX;
|
||||
}
|
||||
|
||||
/* Return the result */
|
||||
if (Minus) {
|
||||
return (unsigned long) -(long)Val;
|
||||
} else {
|
||||
return Val;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user