summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
authorManuel Novoa III <mjn3@codepoet.org>2002-03-13 23:28:57 +0000
committerManuel Novoa III <mjn3@codepoet.org>2002-03-13 23:28:57 +0000
commit29d3e23bab8e53ed8653aafb8af9d2999769f17f (patch)
treeac0e55fc8f2894d00686e2048df3b0fadf38980d /libc
parent347b1fc3b66b3fcffdc9da6f928b0e6caaf9de9d (diff)
New versions of the various string to int functions which are smaller
than the old ones, even with errno setting turned on now. Also, at least on i386, we no longer need the long long helper functions for division and mod from libgcc.a.
Diffstat (limited to 'libc')
-rw-r--r--libc/stdlib/Makefile20
-rw-r--r--libc/stdlib/abs.c13
-rw-r--r--libc/stdlib/stdlib.c448
-rw-r--r--libc/stdlib/strto_l.c207
-rw-r--r--libc/stdlib/strto_ll.c203
5 files changed, 454 insertions, 437 deletions
diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile
index aaf959bcc..63f2298e9 100644
--- a/libc/stdlib/Makefile
+++ b/libc/stdlib/Makefile
@@ -27,17 +27,17 @@ include $(TOPDIR)Rules.mak
DIRS = $(MALLOC)
ALL_SUBDIRS = malloc malloc-930716 malloc-simple
-MSRC=strto_l.c
-MOBJ=strtol.o strtoul.o strto_l.o atoi.o atol.o
+MSRC = stdlib.c
+MOBJ = abs.o labs.o atoi.o atol.o strtol.o strtoul.o _stdlib_strto_l.o
-MSRC1=strto_ll.c
-MOBJ1=strtoll.o strtoull.o strto_ll.o atoll.o
+ifeq ($(HAS_LONG_LONG),true)
+ MOBJ += llabs.o atoll.o strtoll.o strtoull.o _stdlib_strto_ll.o
+endif
MSRC2=atexit.c
MOBJ2=atexit.o on_exit.o __exit_handler.o exit.o
-
-CSRC = abort.c getenv.c mktemp.c qsort.c realpath.c abs.c bsearch.c \
+CSRC = abort.c getenv.c mktemp.c qsort.c realpath.c bsearch.c \
mkstemp.c putenv.c rand.c random.c setenv.c system.c div.c ldiv.c \
getpt.c ptsname.c grantpt.c unlockpt.c gcvt.c
ifeq ($(HAS_FLOATING_POINT),true)
@@ -45,11 +45,7 @@ ifeq ($(HAS_FLOATING_POINT),true)
endif
COBJS=$(patsubst %.c,%.o, $(CSRC))
-
OBJS=$(MOBJ) $(MOBJ2) $(COBJS)
-ifeq ($(HAS_LONG_LONG),true)
- OBJS += $(MOBJ1)
-endif
all: $(OBJS) $(LIBC)
@@ -62,10 +58,6 @@ $(MOBJ): $(MSRC)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
-$(MOBJ1): $(MSRC1)
- $(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
- $(STRIPTOOL) -x -R .note -R .comment $*.o
-
$(MOBJ2): $(MSRC2)
$(CC) $(CFLAGS) -DL_$* $< -c -o $*.o
$(STRIPTOOL) -x -R .note -R .comment $*.o
diff --git a/libc/stdlib/abs.c b/libc/stdlib/abs.c
deleted file mode 100644
index 044a334b1..000000000
--- a/libc/stdlib/abs.c
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
- * This file is part of the Linux-8086 C library and is distributed
- * under the GNU Library General Public License.
- */
-#include <unistd.h>
-#include <string.h>
-#include <sys/types.h>
-
-int abs(int arg1)
-{
- return arg1 > 0 ? arg1 : -arg1;
-}
-
diff --git a/libc/stdlib/stdlib.c b/libc/stdlib/stdlib.c
new file mode 100644
index 000000000..40286f0e5
--- /dev/null
+++ b/libc/stdlib/stdlib.c
@@ -0,0 +1,448 @@
+/* Copyright (C) 2002 Manuel Novoa III
+ * From my (incomplete) stdlib library for linux and (soon) elks.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION!
+ *
+ * This code is currently under development. Also, I plan to port
+ * it to elks which is a 16-bit environment with a fairly limited
+ * compiler. Therefore, please refrain from modifying this code
+ * and, instead, pass any bug-fixes, etc. to me. Thanks. Manuel
+ *
+ * ATTENTION! ATTENTION! ATTENTION! ATTENTION! ATTENTION! */
+
+#define _ISOC99_SOURCE /* for ULLONG primarily... */
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <limits.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <errno.h>
+#include <assert.h>
+
+extern unsigned long
+_stdlib_strto_l(register const char * __restrict str,
+ char ** __restrict endptr, int base, int sflag);
+extern unsigned long long
+_stdlib_strto_ll(register const char * __restrict str,
+ char ** __restrict endptr, int base, int sflag);
+
+/* TODO: gcc reports an error due to prototype conflicts. Don't include
+ * the header for the problem cases? */
+#define HEADER_ALIAS_PROBLEM
+
+/**********************************************************************/
+#ifdef L_abs
+
+#ifdef HEADER_ALIAS_PROBLEM
+/* #if UINT_MAX < ULONG_MAX */
+
+int abs(int j)
+{
+ return (j >= 0) ? j : -j;
+}
+
+#endif /* UINT_MAX < ULONG_MAX */
+
+#endif
+/**********************************************************************/
+#ifdef L_labs
+
+#ifndef HEADER_ALIAS_PROBLEM
+/* #if UINT_MAX == ULONG_MAX */
+strong_alias(labs,abs)
+#endif
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
+strong_alias(labs,llabs)
+#endif
+
+#if ULONG_MAX == UINTMAX_MAX
+strong_alias(labs,imaxabs)
+#endif
+
+long int labs(long int j)
+{
+ return (j >= 0) ? j : -j;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_llabs
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX)
+
+#if (ULLONG_MAX == UINTMAX_MAX)
+strong_alias(llabs,imaxabs)
+#endif
+
+long long int llabs(long long int j)
+{
+ return (j >= 0) ? j : -j;
+}
+
+#endif /* defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX) */
+
+#endif
+/**********************************************************************/
+#ifdef L_atoi
+
+#ifdef HEADER_ALIAS_PROBLEM
+/* #if UINT_MAX < ULONG_MAX */
+
+int atoi(const char *nptr)
+{
+ return (int) strtol(nptr, (char **) NULL, 10);
+}
+
+#endif /* UINT_MAX < ULONG_MAX */
+
+#endif
+/**********************************************************************/
+#ifdef L_atol
+
+#ifndef HEADER_ALIAS_PROBLEM
+/* #if UINT_MAX == ULONG_MAX */
+strong_alias(atol,atoi)
+#endif
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
+strong_alias(atol,atoll)
+#endif
+
+long atol(const char *nptr)
+{
+ return strtol(nptr, (char **) NULL, 10);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_atoll
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX)
+
+long long atoll(const char *nptr)
+{
+ return strtoll(nptr, (char **) NULL, 10);
+}
+
+#endif /* defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX) */
+
+#endif
+/**********************************************************************/
+#ifdef L_strtol
+
+#if ULONG_MAX == UINTMAX_MAX
+strong_alias(strtol,strtoimax)
+#endif
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
+strong_alias(strtol,strtoll)
+#endif
+
+long strtol(const char * __restrict str, char ** __restrict endptr, int base)
+{
+ return _stdlib_strto_l(str, endptr, base, 1);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_strtoll
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX)
+
+#if (ULLONG_MAX == UINTMAX_MAX)
+strong_alias(strtoll,strtoimax)
+#endif
+
+long long strtoll(const char * __restrict str,
+ char ** __restrict endptr, int base)
+{
+ return (long long) _stdlib_strto_ll(str, endptr, base, 1);
+}
+
+#endif /* defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX) */
+
+#endif
+/**********************************************************************/
+#ifdef L_strtoul
+
+#if ULONG_MAX == UINTMAX_MAX
+strong_alias(strtoul,strtoumax)
+#endif
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX == ULONG_MAX)
+strong_alias(strtoul,strtoull)
+#endif
+
+unsigned long strtoul(const char * __restrict str,
+ char ** __restrict endptr, int base)
+{
+ return _stdlib_strto_l(str, endptr, base, 0);
+}
+
+#endif
+/**********************************************************************/
+#ifdef L_strtoull
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX)
+
+#if (ULLONG_MAX == UINTMAX_MAX)
+strong_alias(strtoull,strtoumax)
+#endif
+
+unsigned long long strtoull(const char * __restrict str,
+ char ** __restrict endptr, int base)
+{
+ return _stdlib_strto_ll(str, endptr, base, 0);
+}
+
+#endif /* defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX) */
+
+#endif
+/**********************************************************************/
+/* Support routines follow */
+/**********************************************************************/
+/* Set if we want errno set appropriately. */
+/* NOTE: Implies _STRTO_ENDPTR below */
+#define _STRTO_ERRNO 1
+
+/* Set if we want support for the endptr arg. */
+/* Implied by _STRTO_ERRNO. */
+#define _STRTO_ENDPTR 1
+
+#if _STRTO_ERRNO
+#undef _STRTO_ENDPTR
+#define _STRTO_ENDPTR 1
+#define SET_ERRNO(X) __set_errno(X)
+#else
+#define SET_ERRNO(X) ((void)(X)) /* keep side effects */
+#endif
+
+/**********************************************************************/
+#ifdef L__stdlib_strto_l
+
+/* This is the main work fuction which handles both strtol (sflag = 1) and
+ * strtoul (sflag = 0). */
+
+unsigned long _stdlib_strto_l(register const char * __restrict str,
+ char ** __restrict endptr, int base, int sflag)
+{
+ unsigned long number, cutoff;
+#if _STRTO_ENDPTR
+ const char *fail_char;
+#define SET_FAIL(X) fail_char = (X)
+#else
+#define SET_FAIL(X) ((void)(X)) /* Keep side effects. */
+#endif
+ unsigned char negative, digit, cutoff_digit;
+
+ assert((sflag == 0) || (sflag == 1));
+
+ SET_FAIL(str);
+
+ while (isspace(*str)) { /* Skip leading whitespace. */
+ ++str;
+ }
+
+ /* Handle optional sign. */
+ negative = 0;
+ switch(*str) {
+ case '-': negative = 1; /* Fall through to increment str. */
+ case '+': ++str;
+ }
+
+ if (!(base & ~0x10)) { /* Either dynamic (base = 0) or base 16. */
+ base += 10; /* Default is 10 (26). */
+ if (*str == '0') {
+ SET_FAIL(++str);
+ base -= 2; /* Now base is 8 or 16 (24). */
+ if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */
+ ++str;
+ base += base; /* Base is 16 (16 or 48). */
+ }
+ }
+
+ if (base > 16) { /* Adjust in case base wasn't dynamic. */
+ base = 16;
+ }
+ }
+
+ number = 0;
+
+ if (((unsigned)(base - 2)) < 35) { /* Legal base. */
+ cutoff_digit = ULONG_MAX % base;
+ cutoff = ULONG_MAX / base;
+ do {
+ digit = (((unsigned char)(*str - '0')) <= 9)
+ ? (*str - '0')
+ : ((*str >= 'A')
+ ? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */
+ : 40);
+
+ if (digit >= base) {
+ break;
+ }
+
+ SET_FAIL(++str);
+
+ if ((number > cutoff)
+ || ((number == cutoff) && (digit > cutoff_digit))) {
+ number = ULONG_MAX;
+ negative &= sflag;
+ SET_ERRNO(ERANGE);
+ } else {
+ number = number * base + digit;
+ }
+ } while (1);
+ }
+
+#if _STRTO_ENDPTR
+ if (endptr) {
+ *endptr = (char *) fail_char;
+ }
+#endif
+
+ {
+ unsigned long tmp = ((negative)
+ ? ((unsigned long)(-(1+LONG_MIN)))+1
+ : LONG_MAX);
+ if (sflag && (number > tmp)) {
+ number = tmp;
+ SET_ERRNO(ERANGE);
+ }
+ }
+
+ return negative ? (unsigned long)(-((long)number)) : number;
+}
+
+#endif
+/**********************************************************************/
+#ifdef L__stdlib_strto_ll
+
+#if defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX)
+
+/* This is the main work fuction which handles both strtoll (sflag = 1) and
+ * strtoull (sflag = 0). */
+
+unsigned long long _stdlib_strto_ll(register const char * __restrict str,
+ char ** __restrict endptr, int base,
+ int sflag)
+{
+ unsigned long long number;
+#if _STRTO_ENDPTR
+ const char *fail_char;
+#define SET_FAIL(X) fail_char = (X)
+#else
+#define SET_FAIL(X) ((void)(X)) /* Keep side effects. */
+#endif
+ unsigned int n1;
+ unsigned char negative, digit;
+
+ assert((sflag == 0) || (sflag == 1));
+
+ SET_FAIL(str);
+
+ while (isspace(*str)) { /* Skip leading whitespace. */
+ ++str;
+ }
+
+ /* Handle optional sign. */
+ negative = 0;
+ switch(*str) {
+ case '-': negative = 1; /* Fall through to increment str. */
+ case '+': ++str;
+ }
+
+ if (!(base & ~0x10)) { /* Either dynamic (base = 0) or base 16. */
+ base += 10; /* Default is 10 (26). */
+ if (*str == '0') {
+ SET_FAIL(++str);
+ base -= 2; /* Now base is 8 or 16 (24). */
+ if ((0x20|(*str)) == 'x') { /* WARNING: assumes ascii. */
+ ++str;
+ base += base; /* Base is 16 (16 or 48). */
+ }
+ }
+
+ if (base > 16) { /* Adjust in case base wasn't dynamic. */
+ base = 16;
+ }
+ }
+
+ number = 0;
+
+ if (((unsigned)(base - 2)) < 35) { /* Legal base. */
+ do {
+ digit = (((unsigned char)(*str - '0')) <= 9)
+ ? (*str - '0')
+ : ((*str >= 'A')
+ ? (((0x20|(*str)) - 'a' + 10)) /* WARNING: assumes ascii. */
+ : 40);
+
+ if (digit >= base) {
+ break;
+ }
+
+ SET_FAIL(++str);
+
+#if 1
+ /* Optional, but speeds things up in the usual case. */
+ if (number <= (ULLONG_MAX >> 6)) {
+ number = number * base + digit;
+ } else
+#endif
+ {
+ n1 = ((unsigned char) number) * base + digit;
+ number = (number >> CHAR_BIT) * base;
+
+ if (number + (n1 >> CHAR_BIT) <= (ULLONG_MAX >> CHAR_BIT)) {
+ number = (number << CHAR_BIT) + n1;
+ } else { /* Overflow. */
+ number = ULLONG_MAX;
+ negative &= sflag;
+ SET_ERRNO(ERANGE);
+ }
+ }
+
+ } while (1);
+ }
+
+#if _STRTO_ENDPTR
+ if (endptr) {
+ *endptr = (char *) fail_char;
+ }
+#endif
+
+ {
+ unsigned long long tmp = ((negative)
+ ? ((unsigned long long)(-(1+LLONG_MIN)))+1
+ : LLONG_MAX);
+ if (sflag && (number > tmp)) {
+ number = tmp;
+ SET_ERRNO(ERANGE);
+ }
+ }
+
+ return negative ? (unsigned long long)(-((long long)number)) : number;
+}
+
+#endif /* defined(ULLONG_MAX) && (ULLONG_MAX > ULONG_MAX) */
+
+#endif
+/**********************************************************************/
diff --git a/libc/stdlib/strto_l.c b/libc/stdlib/strto_l.c
deleted file mode 100644
index 666433927..000000000
--- a/libc/stdlib/strto_l.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2000 Manuel Novoa III
- *
- * Notes:
- *
- * The primary objective of this implementation was minimal size.
- *
- * Note: Assumes char layout 0-9.*A-Z.*a-z for ordinals values.
- *
- * There are a couple of compile-time options below.
- *
- */
-
-/*****************************************************************************/
-/* OPTIONS */
-/*****************************************************************************/
-
-/* Set if we want errno set appropriately. */
-/* NOTE: Implies _STRTO_ENDPTR below */
-#define _STRTO_ERRNO 0
-
-/* Set if we want support for the endptr arg. */
-/* Implied by _STRTO_ERRNO. */
-#define _STRTO_ENDPTR 1
-
-/*****************************************************************************/
-/* Don't change anything that follows. */
-/*****************************************************************************/
-
-#if _STRTO_ERRNO
-#undef _STRTO_ENDPTR
-#define _STRTO_ENDPTR 1
-#endif
-
-/*****************************************************************************/
-
-/* Are there actually any machines where this might fail? */
-#if 'A' > 'a'
-#error ordering assumption violated : 'A' > 'a'
-#endif
-
-#include <stdlib.h>
-#include <limits.h>
-#include <ctype.h>
-
-#if _STRTO_ERRNO
-#include <errno.h>
-#endif
-
-unsigned long _strto_l(const char *str, char **endptr, int base, int uflag);
-
-#if L_strto_l
-
-/*
- * This is the main work fuction which handles both strtol (uflag = 0) and
- * strtoul (uflag = 1).
- */
-
-unsigned long _strto_l(const char *str, char **endptr, int base, int uflag)
-{
- unsigned long number = 0;
- unsigned long cutoff;
- char *pos = (char *) str;
-#if _STRTO_ENDPTR
- char *fail_char = (char *) str;
-#endif
- int digit, cutoff_digit;
- int negative;
-
- while (isspace(*pos)) { /* skip leading whitespace */
- ++pos;
- }
-
- /* handle optional sign */
- negative = 0;
- switch(*pos) {
- case '-': negative = 1; /* fall through to increment pos */
- case '+': ++pos;
- }
-
- if ((base == 16) && (*pos == '0')) { /* handle option prefix */
- ++pos;
-#if _STRTO_ENDPTR
- fail_char = pos;
-#endif
- if ((*pos == 'x') || (*pos == 'X')) {
- ++pos;
- }
- }
-
- if (base == 0) { /* dynamic base */
- base = 10; /* default is 10 */
- if (*pos == '0') {
- ++pos;
- base -= 2; /* now base is 8 (or 16) */
-#if _STRTO_ENDPTR
- fail_char = pos;
-#endif
- if ((*pos == 'x') || (*pos == 'X')) {
- base += 8; /* base is 16 */
- ++pos;
- }
- }
- }
-
- if ((base < 2) || (base > 36)) { /* illegal base */
- goto DONE;
- }
-
- cutoff_digit = ULONG_MAX % base;
- cutoff = ULONG_MAX / base;
-
- while (1) {
- digit = 40;
- if ((*pos >= '0') && (*pos <= '9')) {
- digit = (*pos - '0');
- } else if (*pos >= 'a') {
- digit = (*pos - 'a' + 10);
- } else if (*pos >= 'A') {
- digit = (*pos - 'A' + 10);
- } else break;
-
- if (digit >= base) {
- break;
- }
-
- ++pos;
-#if _STRTO_ENDPTR
- fail_char = pos;
-#endif
-
- /* adjust number, with overflow check */
- if ((number > cutoff)
- || ((number == cutoff) && (digit > cutoff_digit))) {
- number = ULONG_MAX;
- if (uflag) {
- negative = 0; /* since unsigned returns ULONG_MAX */
- }
-#if _STRTO_ERRNO
- __set_errno(ERANGE);
-#endif
- } else {
- number = number * base + digit;
- }
-
- }
-
- DONE:
-#if _STRTO_ENDPTR
- if (endptr) {
- *endptr = fail_char;
- }
-#endif
-
- if (negative) {
- if (!uflag && (number > ((unsigned long)(-(1+LONG_MIN)))+1)) {
-#if _STRTO_ERRNO
- __set_errno(ERANGE);
-#endif
- return (unsigned long) LONG_MIN;
- }
- return (unsigned long)(-((long)number));
- } else {
- if (!uflag && (number > (unsigned long) LONG_MAX)) {
-#if _STRTO_ERRNO
- __set_errno(ERANGE);
-#endif
- return LONG_MAX;
- }
- return number;
- }
-}
-
-#endif
-
-#if L_strtoul
-
-unsigned long strtoul(const char *str, char **endptr, int base)
-{
- return _strto_l(str, endptr, base, 1);
-}
-
-#endif
-
-#if L_strtol
-long strtol(const char *str, char **endptr, int base)
-{
- return _strto_l(str, endptr, base, 0);
-}
-
-#endif
-
-#ifdef L_atoi
-int atoi(const char *str)
-{
- return((int)_strto_l((str),(char**)0,10, 0));
-
-}
-#endif
-
-#ifdef L_atol
-long atol(const char *str)
-{
- return(_strto_l((str),(char**)0,10, 0));
-}
-#endif
-
diff --git a/libc/stdlib/strto_ll.c b/libc/stdlib/strto_ll.c
deleted file mode 100644
index 76a1a95b3..000000000
--- a/libc/stdlib/strto_ll.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2000 Manuel Novoa III
- *
- * Notes:
- *
- * The primary objective of this implementation was minimal size.
- *
- * Note: Assumes char layout 0-9.*A-Z.*a-z for ordinals values.
- *
- * There are a couple of compile-time options below.
- *
- */
-
-/*****************************************************************************/
-/* OPTIONS */
-/*****************************************************************************/
-
-/* Set if we want errno set appropriately. */
-/* NOTE: Implies _STRTO_ENDPTR below */
-#define _STRTO_ERRNO 0
-
-/* Set if we want support for the endptr arg. */
-/* Implied by _STRTO_ERRNO. */
-#define _STRTO_ENDPTR 1
-
-/*****************************************************************************/
-/* Don't change anything that follows. */
-/*****************************************************************************/
-
-#if _STRTO_ERRNO
-#undef _STRTO_ENDPTR
-#define _STRTO_ENDPTR 1
-#endif
-
-/*****************************************************************************/
-
-/* Are there actually any machines where this might fail? */
-#if 'A' > 'a'
-#error ordering assumption violated : 'A' > 'a'
-#endif
-
-#include <stdlib.h>
-#define __USE_GNU
-#include <limits.h>
-#include <ctype.h>
-
-#if _STRTO_ERRNO
-#include <errno.h>
-#endif
-
-unsigned long long _strto_ll(const char *str, char **endptr, int base, int uflag);
-
-#if L_strto_ll
-
-/*
- * This is the main work fuction which handles both strtol (uflag = 0) and
- * strtoul (uflag = 1).
- */
-
-unsigned long long _strto_ll(const char *str, char **endptr, int base, int uflag)
-{
- unsigned long long number = 0;
- unsigned long long cutoff;
- char *pos = (char *) str;
-#if _STRTO_ENDPTR
- char *fail_char = (char *) str;
-#endif
- int digit, cutoff_digit;
- int negative;
-
- while (isspace(*pos)) { /* skip leading whitespace */
- ++pos;
- }
-
- /* handle optional sign */
- negative = 0;
- switch(*pos) {
- case '-': negative = 1; /* fall through to increment pos */
- case '+': ++pos;
- }
-
- if ((base == 16) && (*pos == '0')) { /* handle option prefix */
- ++pos;
-#if _STRTO_ENDPTR
- fail_char = pos;
-#endif
- if ((*pos == 'x') || (*pos == 'X')) {
- ++pos;
- }
- }
-
- if (base == 0) { /* dynamic base */
- base = 10; /* default is 10 */
- if (*pos == '0') {
- ++pos;
- base -= 2; /* now base is 8 (or 16) */
-#if _STRTO_ENDPTR
- fail_char = pos;
-#endif
- if ((*pos == 'x') || (*pos == 'X')) {
- base += 8; /* base is 16 */
- ++pos;
- }
- }
- }
-
- if ((base < 2) || (base > 36)) { /* illegal base */
- goto DONE;
- }
-
- cutoff_digit = ULONG_LONG_MAX % base;
- cutoff = ULONG_LONG_MAX / base;
-
- while (1) {
- digit = 40;
- if ((*pos >= '0') && (*pos <= '9')) {
- digit = (*pos - '0');
- } else if (*pos >= 'a') {
- digit = (*pos - 'a' + 10);
- } else if (*pos >= 'A') {
- digit = (*pos - 'A' + 10);
- } else break;
-
- if (digit >= base) {
- break;
- }
-
- ++pos;
-#if _STRTO_ENDPTR
- fail_char = pos;
-#endif
-
- /* adjust number, with overflow check */
- if ((number > cutoff)
- || ((number == cutoff) && (digit > cutoff_digit))) {
- number = ULONG_LONG_MAX;
- if (uflag) {
- negative = 0; /* since unsigned returns ULONG_LONG_MAX */
- }
-#if _STRTO_ERRNO
- __set_errno(ERANGE);
-#endif
- } else {
- number = number * base + digit;
- }
-
- }
-
- DONE:
-#if _STRTO_ENDPTR
- if (endptr) {
- *endptr = fail_char;
- }
-#endif
-
- if (negative) {
- if (!uflag && (number > ((unsigned long long)(-(1+LONG_LONG_MIN)))+1)) {
-#if _STRTO_ERRNO
- __set_errno(ERANGE);
-#endif
- return (unsigned long long) LONG_LONG_MIN;
- }
- return (unsigned long long)(-((long long)number));
- } else {
- if (!uflag && (number > (unsigned long long) LONG_LONG_MAX)) {
-#if _STRTO_ERRNO
- __set_errno(ERANGE);
-#endif
- return LONG_LONG_MAX;
- }
- return number;
- }
-}
-
-#endif
-
-#if L_strtoull
-
-unsigned long long strtoull(const char *str, char **endptr, int base)
-{
- return _strto_ll(str, endptr, base, 1);
-}
-
-#endif
-
-#if L_strtoll
-
-long long strtoll(const char *str, char **endptr, int base)
-{
- return _strto_ll(str, endptr, base, 0);
-}
-
-#endif
-
-#ifdef L_atoll
-long long atoll(const char *str)
-{
- return(_strto_ll((str),(char**)0,10,0));
-}
-#endif
-
-
-