From 5e55e1c65199b41f31286a78e4bb577806056afa Mon Sep 17 00:00:00 2001 From: uz Date: Tue, 15 Sep 2009 21:45:25 +0000 Subject: [PATCH] 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 --- libsrc/common/Makefile | 1 + libsrc/common/strtoul.c | 119 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 libsrc/common/strtoul.c diff --git a/libsrc/common/Makefile b/libsrc/common/Makefile index 0a792b59b..0ef066888 100644 --- a/libsrc/common/Makefile +++ b/libsrc/common/Makefile @@ -74,6 +74,7 @@ C_OBJS = _afailed.o \ strftime.o \ strtok.o \ strtol.o \ + strtoul.o \ strxfrm.o \ system.o \ timezone.o diff --git a/libsrc/common/strtoul.c b/libsrc/common/strtoul.c new file mode 100644 index 000000000..15b01ec23 --- /dev/null +++ b/libsrc/common/strtoul.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include + + + +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; + } +} + -- 2.39.2