diff --git a/include/ChangeLog b/include/ChangeLog index 441ea3daded..d2d14721f09 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2014-10-28 Yury Gribov + + * libiberty.h (strtol, strtoul, strtoll, strtoull): New prototypes. + 2014-10-27 Phil Muldoon Jan Kratochvil Tom Tromey diff --git a/include/libiberty.h b/include/libiberty.h index d09c9a54811..571e85f1e9e 100644 --- a/include/libiberty.h +++ b/include/libiberty.h @@ -655,6 +655,33 @@ extern size_t strnlen (const char *, size_t); extern int strverscmp (const char *, const char *); #endif +#if defined(HAVE_DECL_STRTOL) && !HAVE_DECL_STRTOL +extern long int strtol (const char *nptr, + char **endptr, int base); +#endif + +#if defined(HAVE_DECL_STRTOUL) && !HAVE_DECL_STRTOUL +extern unsigned long int strtoul (const char *nptr, + char **endptr, int base); +#endif + +#if defined(HAVE_LONG_LONG) && defined(HAVE_DECL_STRTOLL) && !HAVE_DECL_STRTOLL +__extension__ +extern long long int strtoll (const char *nptr, + char **endptr, int base); +#endif + +#if defined(HAVE_LONG_LONG) && defined(HAVE_DECL_STRTOULL) && !HAVE_DECL_STRTOULL +__extension__ +extern unsigned long long int strtoull (const char *nptr, + char **endptr, int base); +#endif + +#if defined(HAVE_DECL_STRVERSCMP) && !HAVE_DECL_STRVERSCMP +/* Compare version strings. */ +extern int strverscmp (const char *, const char *); +#endif + /* Set the title of a process */ extern void setproctitle (const char *name, ...); diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 73dee14ad67..d30a80b22ab 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,18 @@ +2014-10-28 Yury Gribov + + * strtoll.c: New file. + * strtoull.c: New file. + * configure.ac: Add long long checks. Add harness for strtoll and + strtoull. Check decls for strtol, strtoul, strtoll, strtoull. + * Makefile.in (CFILES, CONFIGURED_OFILES): Add strtoll and strtoull. + * config.in: Regenerate. + * configure: Regenerate. + * functions.texi: Regenerate. + * testsuite/Makefile.in (check-strtol): New rule. + (test-strtol): Likewise. + (mostlyclean): Clean up strtol test. + * testsuite/test-strtol.c: New test. + 2014-10-15 David Malcolm * choose-temp.c (choose_tmpdir): Remove now-redundant local diff --git a/libiberty/Makefile.in b/libiberty/Makefile.in index 9b877209bd1..1b0d8ae782b 100644 --- a/libiberty/Makefile.in +++ b/libiberty/Makefile.in @@ -152,8 +152,8 @@ CFILES = alloca.c argv.c asprintf.c atexit.c \ spaces.c splay-tree.c stack-limit.c stpcpy.c stpncpy.c \ strcasecmp.c strchr.c strdup.c strerror.c strncasecmp.c \ strncmp.c strrchr.c strsignal.c strstr.c strtod.c strtol.c \ - strtoul.c strndup.c strnlen.c strverscmp.c \ - timeval-utils.c tmpnam.c \ + strtoll.c strtoul.c strtoull.c strndup.c strnlen.c \ + strverscmp.c timeval-utils.c tmpnam.c \ unlink-if-ordinary.c \ vasprintf.c vfork.c vfprintf.c vprintf.c vsnprintf.c vsprintf.c \ waitpid.c \ @@ -219,8 +219,8 @@ CONFIGURED_OFILES = ./asprintf.$(objext) ./atexit.$(objext) \ ./strchr.$(objext) ./strdup.$(objext) ./strncasecmp.$(objext) \ ./strncmp.$(objext) ./strndup.$(objext) ./strnlen.$(objext) \ ./strrchr.$(objext) ./strstr.$(objext) ./strtod.$(objext) \ - ./strtol.$(objext) ./strtoul.$(objext) ./strverscmp.$(objext) \ - ./tmpnam.$(objext) \ + ./strtol.$(objext) ./strtoul.$(objext) strtoll.$(objext) \ + ./strtoull.$(objext) ./tmpnam.$(objext) ./strverscmp.$(objext) \ ./vasprintf.$(objext) ./vfork.$(objext) ./vfprintf.$(objext) \ ./vprintf.$(objext) ./vsnprintf.$(objext) ./vsprintf.$(objext) \ ./waitpid.$(objext) @@ -694,6 +694,17 @@ $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir else true; fi $(COMPILE.c) $(srcdir)/crc32.c $(OUTPUT_OPTION) +./d-demangle.$(objext): $(srcdir)/d-demangle.c config.h $(INCDIR)/ansidecl.h \ + $(INCDIR)/demangle.h $(INCDIR)/libiberty.h \ + $(INCDIR)/safe-ctype.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/d-demangle.c -o pic/$@; \ + else true; fi + if [ x"$(NOASANFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/d-demangle.c -o noasan/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/d-demangle.c $(OUTPUT_OPTION) + ./dwarfnames.$(objext): $(srcdir)/dwarfnames.c $(INCDIR)/dwarf2.def \ $(INCDIR)/dwarf2.h if [ x"$(PICFLAG)" != x ]; then \ @@ -714,14 +725,6 @@ $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir else true; fi $(COMPILE.c) $(srcdir)/dyn-string.c $(OUTPUT_OPTION) -./d-demangle.$(objext): $(srcdir)/d-demangle.c config.h $(INCDIR)/ansidecl.h \ - $(srcdir)/cp-demangle.h $(INCDIR)/demangle.h \ - $(INCDIR)/dyn-string.h $(INCDIR)/getopt.h $(INCDIR)/libiberty.h - if [ x"$(PICFLAG)" != x ]; then \ - $(COMPILE.c) $(PICFLAG) $(srcdir)/d-demangle.c -o pic/$@; \ - else true; fi - $(COMPILE.c) $(srcdir)/d-demangle.c $(OUTPUT_OPTION) - ./fdmatch.$(objext): $(srcdir)/fdmatch.c config.h $(INCDIR)/ansidecl.h \ $(INCDIR)/libiberty.h if [ x"$(PICFLAG)" != x ]; then \ @@ -1471,6 +1474,15 @@ $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir else true; fi $(COMPILE.c) $(srcdir)/strtol.c $(OUTPUT_OPTION) +./strtoll.$(objext): $(srcdir)/strtoll.c config.h $(INCDIR)/safe-ctype.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/strtoll.c -o pic/$@; \ + else true; fi + if [ x"$(NOASANFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/strtoll.c -o noasan/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/strtoll.c $(OUTPUT_OPTION) + ./strtoul.$(objext): $(srcdir)/strtoul.c config.h $(INCDIR)/ansidecl.h \ $(INCDIR)/safe-ctype.h if [ x"$(PICFLAG)" != x ]; then \ @@ -1481,6 +1493,16 @@ $(CONFIGURED_OFILES): stamp-picdir stamp-noasandir else true; fi $(COMPILE.c) $(srcdir)/strtoul.c $(OUTPUT_OPTION) +./strtoull.$(objext): $(srcdir)/strtoull.c config.h $(INCDIR)/ansidecl.h \ + $(INCDIR)/safe-ctype.h + if [ x"$(PICFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(srcdir)/strtoull.c -o pic/$@; \ + else true; fi + if [ x"$(NOASANFLAG)" != x ]; then \ + $(COMPILE.c) $(PICFLAG) $(NOASANFLAG) $(srcdir)/strtoull.c -o noasan/$@; \ + else true; fi + $(COMPILE.c) $(srcdir)/strtoull.c $(OUTPUT_OPTION) + ./strverscmp.$(objext): $(srcdir)/strverscmp.c $(INCDIR)/ansidecl.h \ $(INCDIR)/libiberty.h $(INCDIR)/safe-ctype.h if [ x"$(PICFLAG)" != x ]; then \ diff --git a/libiberty/config.in b/libiberty/config.in index 1cf9c11b6ee..7c05b9d846e 100644 --- a/libiberty/config.in +++ b/libiberty/config.in @@ -79,6 +79,22 @@ don't. */ #undef HAVE_DECL_SNPRINTF +/* Define to 1 if you have the declaration of `strtol', and to 0 if you don't. + */ +#undef HAVE_DECL_STRTOL + +/* Define to 1 if you have the declaration of `strtoll', and to 0 if you + don't. */ +#undef HAVE_DECL_STRTOLL + +/* Define to 1 if you have the declaration of `strtoul', and to 0 if you + don't. */ +#undef HAVE_DECL_STRTOUL + +/* Define to 1 if you have the declaration of `strtoull', and to 0 if you + don't. */ +#undef HAVE_DECL_STRTOULL + /* Define to 1 if you have the declaration of `strverscmp', and to 0 if you don't. */ #undef HAVE_DECL_STRVERSCMP @@ -136,6 +152,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H +/* Define if you have the `long long' type. */ +#undef HAVE_LONG_LONG + /* Define to 1 if you have the header file. */ #undef HAVE_MACHINE_HAL_SYSINFO_H @@ -280,9 +299,15 @@ /* Define to 1 if you have the `strtol' function. */ #undef HAVE_STRTOL +/* Define to 1 if you have the `strtoll' function. */ +#undef HAVE_STRTOLL + /* Define to 1 if you have the `strtoul' function. */ #undef HAVE_STRTOUL +/* Define to 1 if you have the `strtoull' function. */ +#undef HAVE_STRTOULL + /* Define to 1 if you have the `strverscmp' function. */ #undef HAVE_STRVERSCMP @@ -439,6 +464,12 @@ /* The size of `int', as computed by sizeof. */ #undef SIZEOF_INT +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `long long', as computed by sizeof. */ +#undef SIZEOF_LONG_LONG + /* Define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses diff --git a/libiberty/configure b/libiberty/configure index 96feaedbeba..4a5e40ab8cc 100755 --- a/libiberty/configure +++ b/libiberty/configure @@ -5124,7 +5124,7 @@ $as_echo "#define NEED_DECLARATION_ERRNO 1" >>confdefs.h fi -# Determine the size of an int for struct fibnode. +# Determine sizes of some types. # The cast to long int works around a bug in the HP C Compiler # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. @@ -5159,6 +5159,82 @@ cat >>confdefs.h <<_ACEOF _ACEOF +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 +$as_echo_n "checking size of long... " >&6; } +if test "${ac_cv_sizeof_long+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (long) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 +$as_echo "$ac_cv_sizeof_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + + +# Check for presense of long long +ac_fn_c_check_type "$LINENO" "long long" "ac_cv_type_long_long" "$ac_includes_default" +if test "x$ac_cv_type_long_long" = x""yes; then : + +$as_echo "#define HAVE_LONG_LONG 1" >>confdefs.h + # The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long long" >&5 +$as_echo_n "checking size of long long... " >&6; } +if test "${ac_cv_sizeof_long_long+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long long))" "ac_cv_sizeof_long_long" "$ac_includes_default"; then : + +else + if test "$ac_cv_type_long_long" = yes; then + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (long long) +See \`config.log' for more details." "$LINENO" 5; }; } + else + ac_cv_sizeof_long_long=0 + fi +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long_long" >&5 +$as_echo "$ac_cv_sizeof_long_long" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG_LONG $ac_cv_sizeof_long_long +_ACEOF + + +fi + # Look for a 64-bit type. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a 64-bit type" >&5 @@ -5387,6 +5463,8 @@ funcs="$funcs strstr" funcs="$funcs strtod" funcs="$funcs strtol" funcs="$funcs strtoul" +funcs="$funcs strtoll" +funcs="$funcs strtoull" funcs="$funcs strverscmp" funcs="$funcs tmpnam" funcs="$funcs vasprintf" @@ -5423,7 +5501,7 @@ if test "x" = "y"; then sbrk setenv setproctitle setrlimit sigsetmask snprintf spawnve spawnvpe \ stpcpy stpncpy strcasecmp strchr strdup \ strerror strncasecmp strndup strnlen strrchr strsignal strstr strtod \ - strtol strtoul strverscmp sysconf sysctl sysmp \ + strtol strtoul strtoll strtoull strverscmp sysconf sysctl sysmp \ table times tmpnam \ vasprintf vfprintf vprintf vsprintf \ wait3 wait4 waitpid @@ -5499,6 +5577,46 @@ fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_VSNPRINTF $ac_have_decl _ACEOF +ac_fn_c_check_decl "$LINENO" "strtol" "ac_cv_have_decl_strtol" "$ac_includes_default" +if test "x$ac_cv_have_decl_strtol" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRTOL $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "strtoul" "ac_cv_have_decl_strtoul" "$ac_includes_default" +if test "x$ac_cv_have_decl_strtoul" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRTOUL $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "strtoll" "ac_cv_have_decl_strtoll" "$ac_includes_default" +if test "x$ac_cv_have_decl_strtoll" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRTOLL $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "strtoull" "ac_cv_have_decl_strtoull" "$ac_includes_default" +if test "x$ac_cv_have_decl_strtoull" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRTOULL $ac_have_decl +_ACEOF $as_echo "#define HAVE_SYS_ERRLIST 1" >>confdefs.h diff --git a/libiberty/configure.ac b/libiberty/configure.ac index 3380819ab3a..90adaea1ad2 100644 --- a/libiberty/configure.ac +++ b/libiberty/configure.ac @@ -272,8 +272,14 @@ AC_HEADER_TIME libiberty_AC_DECLARE_ERRNO -# Determine the size of an int for struct fibnode. +# Determine sizes of some types. AC_CHECK_SIZEOF([int]) +AC_CHECK_SIZEOF([long]) + +# Check for presense of long long +AC_CHECK_TYPE([long long], + [AC_DEFINE(HAVE_LONG_LONG, 1, [Define if you have the `long long' type.]) AC_CHECK_SIZEOF([long long])], + []) # Look for a 64-bit type. AC_MSG_CHECKING([for a 64-bit type]) @@ -365,6 +371,8 @@ funcs="$funcs strstr" funcs="$funcs strtod" funcs="$funcs strtol" funcs="$funcs strtoul" +funcs="$funcs strtoll" +funcs="$funcs strtoull" funcs="$funcs strverscmp" funcs="$funcs tmpnam" funcs="$funcs vasprintf" @@ -401,11 +409,11 @@ if test "x" = "y"; then sbrk setenv setproctitle setrlimit sigsetmask snprintf spawnve spawnvpe \ stpcpy stpncpy strcasecmp strchr strdup \ strerror strncasecmp strndup strnlen strrchr strsignal strstr strtod \ - strtol strtoul strverscmp sysconf sysctl sysmp \ + strtol strtoul strtoll strtoull strverscmp sysconf sysctl sysmp \ table times tmpnam \ vasprintf vfprintf vprintf vsprintf \ wait3 wait4 waitpid) - AC_CHECK_DECLS([basename(char *), ffs, asprintf, vasprintf, snprintf, vsnprintf]) + AC_CHECK_DECLS([basename(char *), ffs, asprintf, vasprintf, snprintf, vsnprintf, strtol, strtoul, strtoll, strtoull]) AC_DEFINE(HAVE_SYS_ERRLIST, 1, [Define if you have the sys_errlist variable.]) AC_DEFINE(HAVE_SYS_NERR, 1, [Define if you have the sys_nerr variable.]) AC_DEFINE(HAVE_SYS_SIGLIST, 1, [Define if you have the sys_siglist variable.]) diff --git a/libiberty/functions.texi b/libiberty/functions.texi index 387aee0bb9c..3627285f905 100644 --- a/libiberty/functions.texi +++ b/libiberty/functions.texi @@ -1714,6 +1714,24 @@ that the converted value is unsigned. @end deftypefn +@c strtoll.c:33 +@deftypefn Supplemental {long long int} strtoll (const char *@var{string}, @ + char **@var{endptr}, int @var{base}) +@deftypefnx Supplemental {unsigned long long int} strtoul (@ + const char *@var{string}, char **@var{endptr}, int @var{base}) + +The @code{strtoll} function converts the string in @var{string} to a +long long integer value according to the given @var{base}, which must be +between 2 and 36 inclusive, or be the special value 0. If @var{base} +is 0, @code{strtoll} will look for the prefixes @code{0} and @code{0x} +to indicate bases 8 and 16, respectively, else default to base 10. +When the base is 16 (either explicitly or implicitly), a prefix of +@code{0x} is allowed. The handling of @var{endptr} is as that of +@code{strtod} above. The @code{strtoull} function is the same, except +that the converted value is unsigned. + +@end deftypefn + @c strsignal.c:502 @deftypefn Extension int strtosigno (const char *@var{name}) diff --git a/libiberty/strtoll.c b/libiberty/strtoll.c new file mode 100644 index 00000000000..37ff8cd3d4c --- /dev/null +++ b/libiberty/strtoll.c @@ -0,0 +1,175 @@ +/*- + * Copyright (c) 2014 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. [rescinded 22 July 1999] + * 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. + */ + +/* + +@deftypefn Supplemental {long long int} strtoll (const char *@var{string}, @ + char **@var{endptr}, int @var{base}) +@deftypefnx Supplemental {unsigned long long int} strtoul (@ + const char *@var{string}, char **@var{endptr}, int @var{base}) + +The @code{strtoll} function converts the string in @var{string} to a +long long integer value according to the given @var{base}, which must be +between 2 and 36 inclusive, or be the special value 0. If @var{base} +is 0, @code{strtoll} will look for the prefixes @code{0} and @code{0x} +to indicate bases 8 and 16, respectively, else default to base 10. +When the base is 16 (either explicitly or implicitly), a prefix of +@code{0x} is allowed. The handling of @var{endptr} is as that of +@code{strtod} above. The @code{strtoull} function is the same, except +that the converted value is unsigned. + +@end deftypefn + +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#include "safe-ctype.h" + +#ifdef HAVE_LONG_LONG + +__extension__ +typedef unsigned long long ullong_type; + +__extension__ +typedef long long llong_type; + +/* FIXME: It'd be nice to configure around these, but the include files are too + painful. These macros should at least be more portable than hardwired hex + constants. */ + +#ifndef ULLONG_MAX +#define ULLONG_MAX (~(ullong_type)0) /* 0xFFFFFFFFFFFFFFFF */ +#endif + +#ifndef LLONG_MAX +#define LLONG_MAX ((llong_type)(ULLONG_MAX >> 1)) /* 0x7FFFFFFFFFFFFFFF */ +#endif + +#ifndef LLONG_MIN +#define LLONG_MIN (~LLONG_MAX) /* 0x8000000000000000 */ +#endif + +/* + * Convert a string to a long long integer. + * + * Ignores `locale' stuff. Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +llong_type +strtoll(const char *nptr, char **endptr, register int base) +{ + register const char *s = nptr; + register ullong_type acc; + register int c; + register ullong_type 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 ? -(ullong_type)LLONG_MIN : LLONG_MAX; + cutlim = cutoff % (ullong_type)base; + cutoff /= (ullong_type)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 ? LLONG_MIN : LLONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + +#endif /* ifdef HAVE_LONG_LONG */ diff --git a/libiberty/strtoull.c b/libiberty/strtoull.c new file mode 100644 index 00000000000..2f580fb3454 --- /dev/null +++ b/libiberty/strtoull.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2014 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. [rescinded 22 July 1999] + * 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 HAVE_CONFIG_H +#include "config.h" +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_SYS_PARAM_H +#include +#endif +#include +#ifdef NEED_DECLARATION_ERRNO +extern int errno; +#endif +#if 0 +#include +#endif +#include "ansidecl.h" +#include "safe-ctype.h" + +#ifdef HAVE_LONG_LONG + +__extension__ +typedef unsigned long long ullong_type; + +#ifndef ULLONG_MAX +#define ULLONG_MAX (~(ullong_type)0) /* 0xFFFFFFFFFFFFFFFF */ +#endif + +/* + * 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. + */ +ullong_type +strtoull(const char *nptr, char **endptr, register int base) +{ + register const char *s = nptr; + register ullong_type acc; + register int c; + register ullong_type 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 = (ullong_type)ULLONG_MAX / (ullong_type)base; + cutlim = (ullong_type)ULLONG_MAX % (ullong_type)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 = ULLONG_MAX; + errno = ERANGE; + } else if (neg) + acc = -acc; + if (endptr != 0) + *endptr = (char *) (any ? s - 1 : nptr); + return (acc); +} + +#endif /* ifdef HAVE_LONG_LONG */ diff --git a/libiberty/testsuite/Makefile.in b/libiberty/testsuite/Makefile.in index bb2db67fb66..4324a8f1dc4 100644 --- a/libiberty/testsuite/Makefile.in +++ b/libiberty/testsuite/Makefile.in @@ -45,7 +45,8 @@ all: # CHECK is set to "really_check" or the empty string by configure. check: @CHECK@ -really-check: check-cplus-dem check-d-demangle check-pexecute check-expandargv +really-check: check-cplus-dem check-d-demangle check-pexecute check-expandargv \ + check-strtol # Run some tests of the demangler. check-cplus-dem: test-demangle $(srcdir)/demangle-expected @@ -62,6 +63,10 @@ check-pexecute: test-pexecute check-expandargv: test-expandargv ./test-expandargv +# Check the strtol functionality +check-strtol: test-strtol + ./test-strtol + # Run the demangler fuzzer fuzz-demangler: demangler-fuzzer ./demangler-fuzzer @@ -79,6 +84,10 @@ test-expandargv: $(srcdir)/test-expandargv.c ../libiberty.a $(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-expandargv \ $(srcdir)/test-expandargv.c ../libiberty.a +test-strtol: $(srcdir)/test-strtol.c ../libiberty.a + $(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-strtol \ + $(srcdir)/test-strtol.c ../libiberty.a + demangler-fuzzer: $(srcdir)/demangler-fuzzer.c ../libiberty.a $(TEST_COMPILE) -o demangler-fuzzer \ $(srcdir)/demangler-fuzzer.c ../libiberty.a @@ -92,6 +101,7 @@ mostlyclean: rm -f test-demangle rm -f test-pexecute rm -f test-expandargv + rm -f test-strtol rm -f demangler-fuzzer rm -f core clean: mostlyclean diff --git a/libiberty/testsuite/test-strtol.c b/libiberty/testsuite/test-strtol.c new file mode 100644 index 00000000000..96d6871c777 --- /dev/null +++ b/libiberty/testsuite/test-strtol.c @@ -0,0 +1,184 @@ +/* Test program for strtol family of funtions, + Copyright (C) 2014 Free Software Foundation, Inc. + Written by Yury Gribov + + This file is part of the libiberty library, which is part of GCC. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "libiberty.h" +#include +#include +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + + +/* Test input data. */ + +enum conversion_fun +{ + STRTOL, + STRTOLL, + STRTOUL, + STRTOULL, +}; + +#ifdef HAVE_LONG_LONG +typedef unsigned long long integer_type; +#else +typedef unsigned long integer_type; +#endif + +struct test_data_t +{ + enum conversion_fun fun; + const char *nptr; + int base; + integer_type res; + int errnum; +}; + +const struct test_data_t test_data[] = { + { STRTOL, "0x123", 0, 0x123L, 0 }, + { STRTOL, "123", 0, 123L, 0 }, + { STRTOL, "0123", 0, 0123L, 0 }, + { STRTOL, "0x7FFFFFFF", 0, 0x7fffffffL, 0 }, + { STRTOL, "-0x80000000", 0, -0x80000000L, 0 }, + { STRTOUL, "0x123", 0, 0x123UL, 0 }, + { STRTOUL, "123", 0, 123UL, 0 }, + { STRTOUL, "0123", 0, 0123UL, 0 }, + { STRTOUL, "0xFFFFFFFF", 0, 0xffffffffUL, 0 }, +#if SIZEOF_LONG == 4 + { STRTOL, "0x80000000", 0, 0x7fffffffL, ERANGE }, + { STRTOL, "-0x80000001", 0, -0x80000000L, ERANGE }, + { STRTOUL, "0x100000000", 0, 0xffffffffUL, ERANGE }, +#endif +#ifdef HAVE_LONG_LONG + { STRTOLL, "0x123", 0, 0x123LL, 0 }, + { STRTOLL, "123", 0, 123LL, 0 }, + { STRTOLL, "0123", 0, 0123LL, 0 }, + { STRTOLL, "0x7FFFFFFFFFFFFFFF", 0, 0x7fffffffffffffffLL, 0 }, + { STRTOLL, "-0x8000000000000000", 0, -0x8000000000000000LL, 0 }, + { STRTOULL, "0x123", 0, 0x123ULL, 0 }, + { STRTOULL, "123", 0, 123ULL, 0 }, + { STRTOULL, "0123", 0, 0123ULL, 0 }, + { STRTOULL, "0xFFFFFFFFFFFFFFFF", 0, 0xffffffffffffffffULL, 0 }, +#if SIZEOF_LONG_LONG == 8 + { STRTOLL, "0x8000000000000000", 0, 0x7fffffffffffffffLL, ERANGE }, + { STRTOLL, "-0x8000000000000001", 0, -0x8000000000000000LL, ERANGE }, + { STRTOULL, "0x10000000000000000", 0, 0xffffffffffffffffULL, ERANGE }, +#endif +#endif +}; + +/* run_tests: + Run conversion function + Compare results + Return number of fails */ + +int +run_tests (const struct test_data_t *test_data, size_t ntests) +{ + int fails = 0, failed; + size_t i; + + for (i = 0; i < ntests; ++i) + { + integer_type res; + int saved_errno; + + errno = 0; + + switch (test_data[i].fun) + { + case STRTOL: + res = strtol (test_data[i].nptr, 0, test_data[i].base); + break; + case STRTOUL: + res = strtoul (test_data[i].nptr, 0, test_data[i].base); + break; +#ifdef HAVE_LONG_LONG + case STRTOLL: + res = strtoll (test_data[i].nptr, 0, test_data[i].base); + break; + case STRTOULL: + res = strtoull (test_data[i].nptr, 0, test_data[i].base); + break; +#endif + } + + saved_errno = errno; + + failed = 0; + + /* Compare result */ + if (res != test_data[i].res) + { + printf ("FAIL: test-strtol-%zd. Results don't match.\n", i); + failed++; + } + + /* Compare errno */ + if (saved_errno != test_data[i].errnum) + { + printf ("FAIL: test-strtol-%zd. Errnos don't match.\n", i); + failed++; + } + + if (!failed) + printf ("PASS: test-strtol-%zd.\n", i); + else + fails++; + } + + return fails; +} + +int +main(int argc, char **argv) +{ + int fails; + fails = run_tests (test_data, sizeof (test_data) / sizeof (test_data[0])); + exit (fails ? EXIT_FAILURE : EXIT_SUCCESS); +} +