From e5996090f7145f782984544de7710b89022eb261 Mon Sep 17 00:00:00 2001 From: uz Date: Tue, 15 Sep 2009 20:56:08 +0000 Subject: [PATCH] Added an implementation of strtol (stdlib.h). git-svn-id: svn://svn.cc65.org/cc65/trunk@4177 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- libsrc/common/Makefile | 3 +- libsrc/common/strtol.c | 128 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 libsrc/common/strtol.c diff --git a/libsrc/common/Makefile b/libsrc/common/Makefile index 5860d40d3..0a792b59b 100644 --- a/libsrc/common/Makefile +++ b/libsrc/common/Makefile @@ -72,8 +72,9 @@ C_OBJS = _afailed.o \ rewind.o \ sleep.o \ strftime.o \ - strxfrm.o \ strtok.o \ + strtol.o \ + strxfrm.o \ system.o \ timezone.o diff --git a/libsrc/common/strtol.c b/libsrc/common/strtol.c new file mode 100644 index 000000000..b36dd8932 --- /dev/null +++ b/libsrc/common/strtol.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include + + + +long __fastcall__ strtol (const char* nptr, char** endptr, int base) +/* Convert a string to a long 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. + */ + if (Minus) { + MaxVal = LONG_MIN; + } else { + MaxVal = LONG_MAX; + } + MaxDigit = MaxVal % base; + MaxVal /= 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; + if (Minus) { + return LONG_MIN; + } else { + return LONG_MAX; + } + } + + /* Return the result */ + if (Minus) { + return -(long)Val; + } else { + return Val; + } +} + -- 2.39.5