summaryrefslogtreecommitdiff
path: root/libc
diff options
context:
space:
mode:
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
-
-
-