diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 32168565e..a656b688d 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,3 +1,15 @@ +2001-09-13 Jeff Johnston + + * libc/stdlib/Makefile.am: Add support to build strtoll_r.c + and strtoull_r.c. + * libc/stdlib/Makefile.in: Regenerated. + * libc/stdlib/strtoll_r.c: New file. + * libc/stdlib/strtoull_r.c: New file. + * libc/stdio/local.h: Add prototypes for long long string + conversion routines. + * libc/stdio/vfscanf.c (__svfscanf_r): Add optional long long support + tied to %L integer conversion specifier. + Thu Sep 13 08:49:49 2001 Jason Tishler * strftime.c (strftime): Fix "%W" implementation to properly handle diff --git a/newlib/libc/stdio/local.h b/newlib/libc/stdio/local.h index 8b55503c8..d8ae29d9f 100644 --- a/newlib/libc/stdio/local.h +++ b/newlib/libc/stdio/local.h @@ -86,6 +86,12 @@ char *_EXFUN(_licvt,(char *, long, char)); char *_EXFUN(_llicvt,(char *, long long, char)); #endif +/* The following are found in the stdlib directory, not here */ +#ifdef __GNUC__ +long long _EXFUN(__strtoll_r,(struct _reent *, const char *, char **, int)); +unsigned long long _EXFUN(__strtoull_r,(struct _reent *, const char *, char **, int)); +#endif + #define CVT_BUF_SIZE 128 #define NDYNAMIC 4 /* add four more whenever necessary */ diff --git a/newlib/libc/stdio/vfscanf.c b/newlib/libc/stdio/vfscanf.c index 662a92360..313a6b85b 100644 --- a/newlib/libc/stdio/vfscanf.c +++ b/newlib/libc/stdio/vfscanf.c @@ -130,6 +130,11 @@ Supporting OS subroutines required: extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr)); #endif +#define _NO_LONGLONG +#if defined WANT_PRINTF_LONG_LONG && defined __GNUC__ +# undef _NO_LONGLONG +#endif + #include "floatio.h" #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */ /* An upper bound for how long a long prints in decimal. 4 / 13 approximates @@ -144,7 +149,7 @@ extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr)); */ #define LONG 0x01 /* l: long or double */ -#define LONGDBL 0x02 /* L: long double */ +#define LONGDBL 0x02 /* L: long double or long long */ #define SHORT 0x04 /* h: short */ #define SUPPRESS 0x08 /* suppress assignment */ #define POINTER 0x10 /* weird %p pointer (`fake hex') */ @@ -181,6 +186,10 @@ extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr)); #define u_char char #define u_long unsigned long +#ifndef _NO_LONGLONG +typedef unsigned long long u_long_long; +#endif + /*static*/ u_char *__sccl (); /* @@ -257,6 +266,11 @@ __svfscanf_r (rptr, fp, fmt0, ap) _LONG_DOUBLE *ldp; double *dp; long *lp; +#ifndef _NO_LONGLONG + long long *llp; +#else + u_long _uquad; +#endif /* `basefix' is used to avoid `if' tests in the integer scanner */ static _CONST short basefix[17] = @@ -435,6 +449,13 @@ __svfscanf_r (rptr, fp, fmt0, ap) lp = va_arg (ap, long *); *lp = nread; } +#ifndef _NO_LONGLONG + else if (flags & LONGDBL) + { + llp = va_arg (ap, long long*); + *llp = nread; + } +#endif else { ip = va_arg (ap, int *); @@ -796,6 +817,18 @@ __svfscanf_r (rptr, fp, fmt0, ap) lp = va_arg (ap, long *); *lp = res; } +#ifndef _NO_LONGLONG + else if (flags & LONGDBL) + { + u_long_long resll; + if (ccfn == _strtoul_r) + resll = __strtoull_r (rptr, buf, (char **) NULL, base); + else + resll = __strtoll_r (rptr, buf, (char **) NULL, base); + llp = va_arg (ap, long long*); + *llp = resll; + } +#endif else { ip = va_arg (ap, int *); diff --git a/newlib/libc/stdlib/Makefile.am b/newlib/libc/stdlib/Makefile.am index 2c44d2cc9..1d41fe15f 100644 --- a/newlib/libc/stdlib/Makefile.am +++ b/newlib/libc/stdlib/Makefile.am @@ -70,7 +70,9 @@ lib_a_SOURCES = \ strdup_r.c \ strtod.c \ strtol.c \ + strtoll_r.c \ strtoul.c \ + strtoull_r.c \ system.c \ valloc.c \ wcstombs.c \ diff --git a/newlib/libc/stdlib/Makefile.in b/newlib/libc/stdlib/Makefile.in index 6ca4b0f0b..f7d1879ac 100644 --- a/newlib/libc/stdlib/Makefile.in +++ b/newlib/libc/stdlib/Makefile.in @@ -152,7 +152,9 @@ lib_a_SOURCES = \ strdup_r.c \ strtod.c \ strtol.c \ + strtoll_r.c \ strtoul.c \ + strtoull_r.c \ system.c \ valloc.c \ wcstombs.c \ @@ -229,8 +231,9 @@ labs.o lcong48.o ldiv.o ldtoa.o lrand48.o malign.o malloc.o mblen.o \ mblen_r.o mbstowcs.o mbstowcs_r.o mbtowc.o mbtowc_r.o mlock.o mprec.o \ mrand48.o msize.o mstats.o mtrim.o nrand48.o putenv.o putenv_r.o \ qsort.o rand.o rand48.o rand_r.o realloc.o seed48.o setenv.o setenv_r.o \ -srand48.o strdup.o strdup_r.o strtod.o strtol.o strtoul.o system.o \ -valloc.o wcstombs.o wcstombs_r.o wctomb.o wctomb_r.o +srand48.o strdup.o strdup_r.o strtod.o strtol.o strtoll_r.o strtoul.o \ +strtoull_r.o system.o valloc.o wcstombs.o wcstombs_r.o wctomb.o \ +wctomb_r.o CFLAGS = @CFLAGS@ COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) CCLD = $(CC) diff --git a/newlib/libc/stdlib/strtoll_r.c b/newlib/libc/stdlib/strtoll_r.c new file mode 100644 index 000000000..6181507a3 --- /dev/null +++ b/newlib/libc/stdlib/strtoll_r.c @@ -0,0 +1,140 @@ +/* + This code is based on strtoul.c which has the following copyright. + It is used to convert a string into a signed long long. + + long long __strtoll_r (struct _reent *rptr, const char *s, + char **ptr, int base); +*/ + +/*- + * Copyright (c) 1990 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __GNUC__ + +#define _GNU_SOURCE +#include <_ansi.h> +#include +#include +#include +#include +#include + +/* + * Convert a string to a long long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long long +_DEFUN (__strtoll_r, (rptr, nptr, endptr, base), + struct _reent *rptr _AND + _CONST char *nptr _AND + char **endptr _AND + int base) +{ + register const char *s = nptr; + register unsigned long long acc; + register int c; + register unsigned long long cutoff; + register int neg = 0, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for longs is + * [-2147483648..2147483647] and the input base is 10, + * cutoff will be set to 214748364 and cutlim to either + * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated + * a value > 214748364, or equal but the next digit is > 7 (or 8), + * the number is too big, and we will return a range error. + * + * Set any if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? -(unsigned long long)LONG_LONG_MIN : LONG_LONG_MAX; + cutlim = cutoff % (unsigned long long)base; + cutoff /= (unsigned long long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LONG_LONG_MIN : LONG_LONG_MAX; + rptr->_errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + +#endif /* __GNUC__ */ diff --git a/newlib/libc/stdlib/strtoull_r.c b/newlib/libc/stdlib/strtoull_r.c new file mode 100644 index 000000000..014e4b649 --- /dev/null +++ b/newlib/libc/stdlib/strtoull_r.c @@ -0,0 +1,120 @@ +/* + This code is based on strtoul.c which has the following copyright. + It is used to convert a string into an unsigned long long. + + long long __strtoull_r (struct _reent *rptr, const char *s, + char **ptr, int base); + +*/ + +/* + * Copyright (c) 1990 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifdef __GNUC__ + +#define _GNU_SOURCE +#include <_ansi.h> +#include +#include +#include +#include +#include + +/* + * Convert a string to an unsigned long long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +unsigned long long +_DEFUN (__strtoull_r, (rptr, nptr, endptr, base), + struct _reent *rptr _AND + _CONST char *nptr _AND + char **endptr _AND + int base) +{ + register const char *s = nptr; + register unsigned long long acc; + register int c; + register unsigned long long cutoff; + register int neg = 0, any, cutlim; + + /* + * See strtol for comments as to the logic used. + */ + do { + c = *s++; + } while (isspace(c)); + if (c == '-') { + neg = 1; + c = *s++; + } else if (c == '+') + c = *s++; + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + cutoff = (unsigned long long)ULONG_LONG_MAX / (unsigned long long)base; + cutlim = (unsigned long long)ULONG_LONG_MAX % (unsigned long long)base; + for (acc = 0, any = 0;; c = *s++) { + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c -= isupper(c) ? 'A' - 10 : 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = ULONG_LONG_MAX; + rptr->_errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + +#endif /* __GNUC__ */