|
@@ -0,0 +1,448 @@
|
|
|
+
|
|
|
+ * 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.
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ *
|
|
|
+ * 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
|
|
|
+#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);
|
|
|
+
|
|
|
+
|
|
|
+ * the header for the problem cases? */
|
|
|
+#define HEADER_ALIAS_PROBLEM
|
|
|
+
|
|
|
+
|
|
|
+#ifdef L_abs
|
|
|
+
|
|
|
+#ifdef HEADER_ALIAS_PROBLEM
|
|
|
+
|
|
|
+
|
|
|
+int abs(int j)
|
|
|
+{
|
|
|
+ return (j >= 0) ? j : -j;
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef L_labs
|
|
|
+
|
|
|
+#ifndef HEADER_ALIAS_PROBLEM
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef L_atoi
|
|
|
+
|
|
|
+#ifdef HEADER_ALIAS_PROBLEM
|
|
|
+
|
|
|
+
|
|
|
+int atoi(const char *nptr)
|
|
|
+{
|
|
|
+ return (int) strtol(nptr, (char **) NULL, 10);
|
|
|
+}
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+#ifdef L_atol
|
|
|
+
|
|
|
+#ifndef HEADER_ALIAS_PROBLEM
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+#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
|
|
|
+
|
|
|
+#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
|
|
|
+
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#define _STRTO_ERRNO 1
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+#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))
|
|
|
+#endif
|
|
|
+
|
|
|
+
|
|
|
+#ifdef L__stdlib_strto_l
|
|
|
+
|
|
|
+
|
|
|
+ * 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))
|
|
|
+#endif
|
|
|
+ unsigned char negative, digit, cutoff_digit;
|
|
|
+
|
|
|
+ assert((sflag == 0) || (sflag == 1));
|
|
|
+
|
|
|
+ SET_FAIL(str);
|
|
|
+
|
|
|
+ while (isspace(*str)) {
|
|
|
+ ++str;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ negative = 0;
|
|
|
+ switch(*str) {
|
|
|
+ case '-': negative = 1;
|
|
|
+ case '+': ++str;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(base & ~0x10)) {
|
|
|
+ base += 10;
|
|
|
+ if (*str == '0') {
|
|
|
+ SET_FAIL(++str);
|
|
|
+ base -= 2;
|
|
|
+ if ((0x20|(*str)) == 'x') {
|
|
|
+ ++str;
|
|
|
+ base += base;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (base > 16) {
|
|
|
+ base = 16;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ number = 0;
|
|
|
+
|
|
|
+ if (((unsigned)(base - 2)) < 35) {
|
|
|
+ cutoff_digit = ULONG_MAX % base;
|
|
|
+ cutoff = ULONG_MAX / base;
|
|
|
+ do {
|
|
|
+ digit = (((unsigned char)(*str - '0')) <= 9)
|
|
|
+ ? (*str - '0')
|
|
|
+ : ((*str >= 'A')
|
|
|
+ ? (((0x20|(*str)) - 'a' + 10))
|
|
|
+ : 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)
|
|
|
+
|
|
|
+
|
|
|
+ * 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))
|
|
|
+#endif
|
|
|
+ unsigned int n1;
|
|
|
+ unsigned char negative, digit;
|
|
|
+
|
|
|
+ assert((sflag == 0) || (sflag == 1));
|
|
|
+
|
|
|
+ SET_FAIL(str);
|
|
|
+
|
|
|
+ while (isspace(*str)) {
|
|
|
+ ++str;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ negative = 0;
|
|
|
+ switch(*str) {
|
|
|
+ case '-': negative = 1;
|
|
|
+ case '+': ++str;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!(base & ~0x10)) {
|
|
|
+ base += 10;
|
|
|
+ if (*str == '0') {
|
|
|
+ SET_FAIL(++str);
|
|
|
+ base -= 2;
|
|
|
+ if ((0x20|(*str)) == 'x') {
|
|
|
+ ++str;
|
|
|
+ base += base;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (base > 16) {
|
|
|
+ base = 16;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ number = 0;
|
|
|
+
|
|
|
+ if (((unsigned)(base - 2)) < 35) {
|
|
|
+ do {
|
|
|
+ digit = (((unsigned char)(*str - '0')) <= 9)
|
|
|
+ ? (*str - '0')
|
|
|
+ : ((*str >= 'A')
|
|
|
+ ? (((0x20|(*str)) - 'a' + 10))
|
|
|
+ : 40);
|
|
|
+
|
|
|
+ if (digit >= base) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ SET_FAIL(++str);
|
|
|
+
|
|
|
+#if 1
|
|
|
+
|
|
|
+ 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 {
|
|
|
+ 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
|
|
|
+
|
|
|
+#endif
|
|
|
+
|