diff options
-rw-r--r-- | ChangeLog | 29 | ||||
-rw-r--r-- | Makefile.am | 9 | ||||
-rw-r--r-- | acconfig.h | 16 | ||||
-rw-r--r-- | configure.in | 13 | ||||
-rw-r--r-- | m4/Makefile.am | 11 | ||||
-rw-r--r-- | m4/decl.m4 | 37 | ||||
-rw-r--r-- | m4/inttypes_h.m4 | 22 | ||||
-rw-r--r-- | m4/uintmax_t.m4 | 22 | ||||
-rw-r--r-- | m4/ulonglong.m4 | 17 | ||||
-rw-r--r-- | m4/xstrtoumax.m4 | 34 | ||||
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/grep.c | 43 | ||||
-rw-r--r-- | src/strtol.c | 472 | ||||
-rw-r--r-- | src/strtoul.c | 22 | ||||
-rw-r--r-- | src/strtoull.c | 27 | ||||
-rw-r--r-- | src/strtoumax.c | 81 | ||||
-rw-r--r-- | src/xstrtol.c | 282 | ||||
-rw-r--r-- | src/xstrtol.h | 64 | ||||
-rw-r--r-- | src/xstrtoumax.c | 31 |
19 files changed, 1200 insertions, 40 deletions
@@ -1,3 +1,32 @@ +2000-03-26 Paul Eggert <eggert@twinsun.com> + + * Makefile.am (ACINCLUDE_INPUTS): Add decl.m4, inttypes_h.m4, + uintmax_t.m4, ulonglong.m4, xstrtoumax.m4. + * m4/Makefile.am (EXTRA_DIST): Likewise. + + * src/Makefile.am (base_sources): + Add xstrtol.c, xstrtol.h, xstrtoumax.c. + (EXTRA_DIST): Add strtol.c. + + * configure.in (jm_AC_TYPE_UINTMAX_T, jm_AC_PREREQ_XSTRTOUMAX, + HAVE_DECL_STRTOUL, HAVE_DECL_STRTOULL): Add. + (AC_REPLACE_FUNCS): Add strtoul. + + * src/grep.c: Include xstrtol.h. + (ck_atio): Use xstrtoumax and do proper overflow checking. + (max_count, outleft): Now off_t, not int. + (main): Likewise. Use xstrtoumax to convert max_count from string. + + * acconfig.h (HAVE_DECL_STRTOUL, HAVE_DECL_STRTOULL): New #undefs. + (HAVE_STPCPY, ENABLE_NLS, HAVE_CATGETS, HAVE_GETTEXT, + HAVE_LC_MESSAGES): Remove. + + * m4/decl.m4, m4/inttypes_h.m4, m4/uintmax_t.m4, m4/ulonglong.m4, + m4/xstrtoumax.m4, src/strtol.c, src/strtoul.c, src/strtoull.c, + src/strtoumax.c, src/xstrtol.c, src/xstrtol.h, src/xstrtoumax.c: + New files, taken unchanged from textutils, fileutils, sh-utils + and/or tar. + 2000-03-23 Paul Eggert <eggert@twinsun.com> * src/search.c (Pcompile): Add support for NUL bytes in diff --git a/Makefile.am b/Makefile.am index 76a8a408..64ac4439 100644 --- a/Makefile.am +++ b/Makefile.am @@ -10,11 +10,12 @@ EXTRA_DIST = TODO README PATCHES.AC PATCHES.AM # The following hack works around this bug by creating acinclude.m4 manually. ACLOCAL_AMFLAGS = M4DIR = $(srcdir)/m4 -ACINCLUDE_INPUTS = $(M4DIR)/djgpp.m4 $(M4DIR)/dosfile.m4 \ +ACINCLUDE_INPUTS = $(M4DIR)/decl.m4 $(M4DIR)/djgpp.m4 $(M4DIR)/dosfile.m4 \ $(M4DIR)/envsep.m4 $(M4DIR)/gettext.m4 $(M4DIR)/glibc.m4 \ $(M4DIR)/header.m4 $(M4DIR)/init.m4 $(M4DIR)/install.m4 \ - $(M4DIR)/isc-posix.m4 $(M4DIR)/largefile.m4 $(M4DIR)/lcmessage.m4 \ - $(M4DIR)/missing.m4 $(M4DIR)/progtest.m4 $(M4DIR)/regex.m4 \ - $(M4DIR)/sanity.m4 + $(M4DIR)/inttypes_h.m4 $(M4DIR)/isc-posix.m4 $(M4DIR)/largefile.m4 \ + $(M4DIR)/lcmessage.m4 $(M4DIR)/missing.m4 $(M4DIR)/progtest.m4 \ + $(M4DIR)/regex.m4 $(M4DIR)/sanity.m4 $(M4DIR)/uintmax_t.m4 \ + $(M4DIR)/ulonglong.m4 $(M4DIR)/xstrtoumax.m4 $(srcdir)/acinclude.m4 : $(ACINCLUDE_INPUTS) cat $(ACINCLUDE_INPUTS) >$(srcdir)/acinclude.m4 @@ -13,19 +13,11 @@ /* Hack for Visual C++ suggested by irox. */ #undef alloca -/* - * Internationalization stuffs. - */ - -#undef HAVE_STPCPY - -#undef ENABLE_NLS - -#undef HAVE_CATGETS - -#undef HAVE_GETTEXT +/* Define if <stdlib.h> declares strtoul. */ +#undef HAVE_DECL_STRTOUL -#undef HAVE_LC_MESSAGES +/* Define if <stdlib.h> declares strtoull. */ +#undef HAVE_DECL_STRTOULL /* * DOS specific diff --git a/configure.in b/configure.in index a0a524ae..d9cf5374 100644 --- a/configure.in +++ b/configure.in @@ -24,6 +24,7 @@ AM_C_PROTOTYPES AC_TYPE_SIZE_T AC_CHECK_TYPE(ssize_t, int) AC_C_CONST +jm_AC_TYPE_UINTMAX_T dnl Checks for header files. AC_HEADER_STDC @@ -38,7 +39,17 @@ AC_FUNC_CLOSEDIR_VOID AC_FUNC_MMAP dnl getpagesize is checked for by AC_FUNC_MMAP. AC_CHECK_FUNCS(btowc isascii memmove setmode strerror wctype) -AC_REPLACE_FUNCS(memchr stpcpy) +AC_REPLACE_FUNCS(memchr stpcpy strtoul) +jm_AC_PREREQ_XSTRTOUMAX + +dnl Replace this with jm_CHECK_DECLS once autoconf 2.15 is out. +jm_CHECK_DECLARATIONS([#include <stdlib.h>], strtoul strtoull) +test $jm_cv_func_decl_strtoul != yes +AC_DEFINE_UNQUOTED(HAVE_DECL_STRTOUL, $?, + [Define if <stdlib.h> declares strtoul.]) +test $jm_cv_func_decl_strtoull != yes +AC_DEFINE_UNQUOTED(HAVE_DECL_STRTOULL, $?, + [Define if <stdlib.h> declares strtoull.]) dnl for VC++ case "$ac_cv_prog_CC" in diff --git a/m4/Makefile.am b/m4/Makefile.am index 3be5753c..21cd7d19 100644 --- a/m4/Makefile.am +++ b/m4/Makefile.am @@ -1,7 +1,8 @@ ## Process this file with automake to create Makefile.in AUTOMAKE_OPTIONS = no-dependencies -EXTRA_DIST = djgpp.m4 \ +EXTRA_DIST = decl.m4 \ + djgpp.m4 \ dosfile.m4 \ envsep.m4 \ gettext.m4 \ @@ -9,10 +10,14 @@ EXTRA_DIST = djgpp.m4 \ header.m4 \ init.m4 \ install.m4 \ + inttypes_h.m4 \ isc-posix.m4 \ - lcmessage.m4 \ largefile.m4 \ + lcmessage.m4 \ missing.m4 \ progtest.m4 \ regex.m4 \ - sanity.m4 + sanity.m4 \ + uintmax_t.m4 \ + ulonglong.m4 \ + xstrtoumax.m4 diff --git a/m4/decl.m4 b/m4/decl.m4 new file mode 100644 index 00000000..4dd7e0d6 --- /dev/null +++ b/m4/decl.m4 @@ -0,0 +1,37 @@ +#serial 5 + +AC_DEFUN(jm_CHECK_DECLARATION, +[ + AC_MSG_CHECKING([whether $1 is declared]) + AC_CACHE_VAL(jm_cv_func_decl_$1, + [AC_TRY_COMPILE([$2], + [ +#ifndef $1 +char *(*pfn) = (char *(*)) $1 +#endif + ], + eval "jm_cv_func_decl_$1=yes", + eval "jm_cv_func_decl_$1=no")]) + + if eval "test \"`echo '$jm_cv_func_decl_'$1`\" = yes"; then + AC_MSG_RESULT(yes) + ifelse([$3], , :, [$3]) + else + AC_MSG_RESULT(no) + ifelse([$4], , , [$4 +])dnl + fi +])dnl + +dnl jm_CHECK_DECLARATIONS(INCLUDES, FUNCTION... [, ACTION-IF-DECLARED +dnl [, ACTION-IF-NOT-DECLARED]]) +AC_DEFUN(jm_CHECK_DECLARATIONS, +[ + for jm_func in $2 + do + jm_CHECK_DECLARATION($jm_func, [$1], + [ + jm_tr_func=HAVE_DECL_`echo $jm_func | tr abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ` + AC_DEFINE_UNQUOTED($jm_tr_func) $3], [$4])dnl + done +]) diff --git a/m4/inttypes_h.m4 b/m4/inttypes_h.m4 new file mode 100644 index 00000000..750639d6 --- /dev/null +++ b/m4/inttypes_h.m4 @@ -0,0 +1,22 @@ +#serial 3 + +dnl From Paul Eggert. + +# Define HAVE_INTTYPES_H if <inttypes.h> exists, +# doesn't clash with <sys/types.h>, and declares uintmax_t. + +AC_DEFUN(jm_AC_HEADER_INTTYPES_H, +[ + AC_CACHE_CHECK([for inttypes.h], jm_ac_cv_header_inttypes_h, + [AC_TRY_COMPILE( + [#include <sys/types.h> +#include <inttypes.h>], + [uintmax_t i = (uintmax_t) -1;], + jm_ac_cv_header_inttypes_h=yes, + jm_ac_cv_header_inttypes_h=no)]) + if test $jm_ac_cv_header_inttypes_h = yes; then + AC_DEFINE_UNQUOTED(HAVE_INTTYPES_H, 1, +[Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, + and declares uintmax_t. ]) + fi +]) diff --git a/m4/uintmax_t.m4 b/m4/uintmax_t.m4 new file mode 100644 index 00000000..222beffa --- /dev/null +++ b/m4/uintmax_t.m4 @@ -0,0 +1,22 @@ +#serial 5 + +dnl From Paul Eggert. + +AC_PREREQ(2.13) + +# Define uintmax_t to `unsigned long' or `unsigned long long' +# if <inttypes.h> does not exist. + +AC_DEFUN(jm_AC_TYPE_UINTMAX_T, +[ + AC_REQUIRE([jm_AC_HEADER_INTTYPES_H]) + if test $jm_ac_cv_header_inttypes_h = no; then + AC_REQUIRE([jm_AC_TYPE_UNSIGNED_LONG_LONG]) + test $ac_cv_type_unsigned_long_long = yes \ + && ac_type='unsigned long long' \ + || ac_type='unsigned long' + AC_DEFINE_UNQUOTED(uintmax_t, $ac_type, +[ Define to unsigned long or unsigned long long + if <inttypes.h> doesn't define.]) + fi +]) diff --git a/m4/ulonglong.m4 b/m4/ulonglong.m4 new file mode 100644 index 00000000..e2fbb552 --- /dev/null +++ b/m4/ulonglong.m4 @@ -0,0 +1,17 @@ +#serial 2 + +dnl From Paul Eggert. + +AC_DEFUN(jm_AC_TYPE_UNSIGNED_LONG_LONG, +[ + AC_CACHE_CHECK([for unsigned long long], ac_cv_type_unsigned_long_long, + [AC_TRY_LINK([unsigned long long ull = 1; int i = 63;], + [unsigned long long ullmax = (unsigned long long) -1; + return ull << i | ull >> i | ullmax / ull | ullmax % ull;], + ac_cv_type_unsigned_long_long=yes, + ac_cv_type_unsigned_long_long=no)]) + if test $ac_cv_type_unsigned_long_long = yes; then + AC_DEFINE(HAVE_UNSIGNED_LONG_LONG, 1, + [Define if you have the unsigned long long type.]) + fi +]) diff --git a/m4/xstrtoumax.m4 b/m4/xstrtoumax.m4 new file mode 100644 index 00000000..f6e31996 --- /dev/null +++ b/m4/xstrtoumax.m4 @@ -0,0 +1,34 @@ +#serial 2 + +# autoconf tests required for use of xstrtoumax.c + +AC_DEFUN(jm_AC_PREREQ_XSTRTOUMAX, +[ + AC_REQUIRE([jm_AC_HEADER_INTTYPES_H]) + AC_REQUIRE([jm_AC_TYPE_UNSIGNED_LONG_LONG]) + AC_CHECK_HEADERS(stdlib.h) + + AC_CACHE_CHECK([whether <inttypes.h> defines strtoumax as a macro], + jm_cv_func_strtoumax_macro, + AC_EGREP_CPP([inttypes_h_defines_strtoumax], [#include <inttypes.h> +#ifdef strtoumax + inttypes_h_defines_strtoumax +#endif], + jm_cv_func_strtoumax_macro=yes, + jm_cv_func_strtoumax_macro=no)) + + if test "$jm_cv_func_strtoumax_macro" != yes; then + AC_REPLACE_FUNCS(strtoumax) + fi + + dnl We don't need (and can't compile) the replacement strtoull + dnl unless the type `unsigned long long' exists. + dnl Also, only the replacement strtoumax invokes strtoull, + dnl so we need the replacement strtoull only if strtoumax does not exist. + case "$ac_cv_type_unsigned_long_long,$jm_cv_func_strtoumax_macro,$ac_cv_func_strtoumax" in + yes,no,no) + AC_REPLACE_FUNCS(strtoull) + ;; + esac + +]) diff --git a/src/Makefile.am b/src/Makefile.am index f2ecdc01..0b43d4d7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,15 +5,15 @@ SUBDIRS = posix LN = ln -# We let configure figure out if we need the regex.c or not -# it is provided in GNU/Linux system -# regex.c regex.h +# We let configure figure out whether we need +# regex.c, strtoul.c, strtoull.c, and strtoumax.c. bin_PROGRAMS = grep egrep fgrep base_sources = grep.c grep.h \ dfa.c dfa.h \ kwset.c kwset.h \ obstack.c obstack.h \ savedir.c savedir.h \ + xstrtol.c xstrtol.h xstrtoumax.c \ getopt.c getopt1.c getopt.h \ search.c getpagesize.h system.h egrep_SOURCES = $(base_sources) egrepmat.c @@ -28,4 +28,4 @@ INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\" EXTRA_DIST = \ dosbuf.c \ vms_fab.c vms_fab.h \ - regex.h + regex.h strtol.c @@ -36,6 +36,7 @@ #include "getpagesize.h" #include "grep.h" #include "savedir.h" +#include "xstrtol.h" #undef MAX #define MAX(A,B) ((A) > (B) ? (A) : (B)) @@ -204,17 +205,14 @@ xrealloc (char *ptr, size_t size) } /* Convert STR to a positive integer, storing the result in *OUT. - If STR is not a valid integer, return -1 (otherwise 0). */ + Return nonzero if STR is invalid or out of range. */ static int ck_atoi (char const *str, int *out) { - char const *p; - for (p = str; *p; p++) - if (*p < '0' || *p > '9') - return -1; - - *out = atoi (optarg); - return 0; + uintmax_t value; + return ! (xstrtoumax (str, 0, 10, &value, "") == LONGINT_OK + && 0 <= (*out = value) + && *out == value); } @@ -492,9 +490,8 @@ static int count_matches; /* Count matching lines. */ static int list_files; /* List matching files. */ static int no_filenames; /* Suppress file names. */ static int suppress_errors; /* Suppress diagnostics. */ -static int max_count; /* Stop after outputting this many - lines from an input file. - FIXME: should be off_t. */ +static off_t max_count; /* Stop after outputting this many + lines from an input file. */ /* Internal variables to keep track of byte count, context, etc. */ static off_t totalcc; /* Total character count before bufbeg. */ @@ -503,8 +500,7 @@ static char *lastout; /* Pointer after last character output; NULL if no character has been output or if it's conceptually before bufbeg. */ static off_t totalnl; /* Total newline count before lastnl. */ -static int outleft; /* Maximum number of lines to be output. - FIXME: should be off_t. */ +static off_t outleft; /* Maximum number of lines to be output. */ static int pending; /* Pending lines of output. Always kept 0 if out_quiet is true. */ static int done_on_match; /* Stop scanning file on first match */ @@ -1226,7 +1222,7 @@ main (int argc, char **argv) eolbyte = '\n'; filename_mask = ~0; - max_count = INT_MAX; + max_count = TYPE_MAXIMUM (off_t); /* The value -1 means to use DEFAULT_CONTEXT. */ out_after = out_before = -1; /* Default before/after context: chaged by -C/-NUM options */ @@ -1390,8 +1386,23 @@ main (int argc, char **argv) done_on_match = 1; break; case 'm': - if (ck_atoi (optarg, &max_count)) - fatal (_("invalid max count"), 0); + { + uintmax_t value; + switch (xstrtoumax (optarg, 0, 10, &value, "")) + { + case LONGINT_OK: + max_count = value; + if (0 <= max_count && max_count == value) + break; + /* Fall through. */ + case LONGINT_OVERFLOW: + max_count = TYPE_MAXIMUM (off_t); + break; + + default: + fatal (_("invalid max count"), 0); + } + } break; case 'n': out_line = 1; diff --git a/src/strtol.c b/src/strtol.c new file mode 100644 index 00000000..0c9c2767 --- /dev/null +++ b/src/strtol.c @@ -0,0 +1,472 @@ +/* Convert string representation of a number into an integer value. + Copyright (C) 1991, 92, 94, 95, 96, 97, 98, 99 Free Software Foundation, Inc. + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@gnu.org. + + This program 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, or (at your option) any + later version. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef _LIBC +# define USE_NUMBER_GROUPING +# define STDC_HEADERS +# define HAVE_LIMITS_H +#endif + +#include <ctype.h> +#include <errno.h> +#ifndef errno +extern int errno; +#endif +#ifndef __set_errno +# define __set_errno(Val) errno = (Val) +#endif + +#ifdef HAVE_LIMITS_H +# include <limits.h> +#endif + +#ifdef STDC_HEADERS +# include <stddef.h> +# include <stdlib.h> +# include <string.h> +#else +# ifndef NULL +# define NULL 0 +# endif +#endif + +#ifdef USE_NUMBER_GROUPING +# include "../locale/localeinfo.h" +#endif + +/* Nonzero if we are defining `strtoul' or `strtoull', operating on + unsigned integers. */ +#ifndef UNSIGNED +# define UNSIGNED 0 +# define INT LONG int +#else +# define INT unsigned LONG int +#endif + +/* Determine the name. */ +#ifdef USE_IN_EXTENDED_LOCALE_MODEL +# if UNSIGNED +# ifdef USE_WIDE_CHAR +# ifdef QUAD +# define strtol __wcstoull_l +# else +# define strtol __wcstoul_l +# endif +# else +# ifdef QUAD +# define strtol __strtoull_l +# else +# define strtol __strtoul_l +# endif +# endif +# else +# ifdef USE_WIDE_CHAR +# ifdef QUAD +# define strtol __wcstoll_l +# else +# define strtol __wcstol_l +# endif +# else +# ifdef QUAD +# define strtol __strtoll_l +# else +# define strtol __strtol_l +# endif +# endif +# endif +#else +# if UNSIGNED +# ifdef USE_WIDE_CHAR +# ifdef QUAD +# define strtol wcstoull +# else +# define strtol wcstoul +# endif +# else +# ifdef QUAD +# define strtol strtoull +# else +# define strtol strtoul +# endif +# endif +# else +# ifdef USE_WIDE_CHAR +# ifdef QUAD +# define strtol wcstoll +# else +# define strtol wcstol +# endif +# else +# ifdef QUAD +# define strtol strtoll +# endif +# endif +# endif +#endif + +/* If QUAD is defined, we are defining `strtoll' or `strtoull', + operating on `long long int's. */ +#ifdef QUAD +# define LONG long long +# define STRTOL_LONG_MIN LONG_LONG_MIN +# define STRTOL_LONG_MAX LONG_LONG_MAX +# define STRTOL_ULONG_MAX ULONG_LONG_MAX + +/* The extra casts work around common compiler bugs, + e.g. Cray C 5.0.3.0 when t == time_t. */ +# ifndef TYPE_SIGNED +# define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +# endif +# ifndef TYPE_MINIMUM +# define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) \ + : (t) 0)) +# endif +# ifndef TYPE_MAXIMUM +# define TYPE_MAXIMUM(t) ((t) (~ (t) 0 - TYPE_MINIMUM (t))) +# endif + +# ifndef ULONG_LONG_MAX +# define ULONG_LONG_MAX TYPE_MAXIMUM (unsigned long long) +# endif +# ifndef LONG_LONG_MAX +# define LONG_LONG_MAX TYPE_MAXIMUM (long long int) +# endif +# ifndef LONG_LONG_MIN +# define LONG_LONG_MIN TYPE_MINIMUM (long long int) +# endif + +# if __GNUC__ == 2 && __GNUC_MINOR__ < 7 + /* Work around gcc bug with using this constant. */ + static const unsigned long long int maxquad = ULONG_LONG_MAX; +# undef STRTOL_ULONG_MAX +# define STRTOL_ULONG_MAX maxquad +# endif +#else +# define LONG long + +# ifndef ULONG_MAX +# define ULONG_MAX ((unsigned long) ~(unsigned long) 0) +# endif +# ifndef LONG_MAX +# define LONG_MAX ((long int) (ULONG_MAX >> 1)) +# endif +# define STRTOL_LONG_MIN LONG_MIN +# define STRTOL_LONG_MAX LONG_MAX +# define STRTOL_ULONG_MAX ULONG_MAX +#endif + + +/* We use this code also for the extended locale handling where the + function gets as an additional argument the locale which has to be + used. To access the values we have to redefine the _NL_CURRENT + macro. */ +#ifdef USE_IN_EXTENDED_LOCALE_MODEL +# undef _NL_CURRENT +# define _NL_CURRENT(category, item) \ + (current->values[_NL_ITEM_INDEX (item)].string) +# define LOCALE_PARAM , loc +# define LOCALE_PARAM_DECL __locale_t loc; +#else +# define LOCALE_PARAM +# define LOCALE_PARAM_DECL +#endif + +#if defined _LIBC || defined HAVE_WCHAR_H +# include <wchar.h> +#endif + +#ifdef USE_WIDE_CHAR +# include <wctype.h> +# define L_(Ch) L##Ch +# define UCHAR_TYPE wint_t +# define STRING_TYPE wchar_t +# ifdef USE_IN_EXTENDED_LOCALE_MODEL +# define ISSPACE(Ch) __iswspace_l ((Ch), loc) +# define ISALPHA(Ch) __iswalpha_l ((Ch), loc) +# define TOUPPER(Ch) __towupper_l ((Ch), loc) +# else +# define ISSPACE(Ch) iswspace (Ch) +# define ISALPHA(Ch) iswalpha (Ch) +# define TOUPPER(Ch) towupper (Ch) +# endif +#else +# if defined STDC_HEADERS || (!defined isascii && !defined HAVE_ISASCII) +# define IN_CTYPE_DOMAIN(c) 1 +# else +# define IN_CTYPE_DOMAIN(c) isascii(c) +# endif +# define L_(Ch) Ch +# define UCHAR_TYPE unsigned char +# define STRING_TYPE char +# ifdef USE_IN_EXTENDED_LOCALE_MODEL +# define ISSPACE(Ch) __isspace_l ((Ch), loc) +# define ISALPHA(Ch) __isalpha_l ((Ch), loc) +# define TOUPPER(Ch) __toupper_l ((Ch), loc) +# else +# define ISSPACE(Ch) (IN_CTYPE_DOMAIN (Ch) && isspace (Ch)) +# define ISALPHA(Ch) (IN_CTYPE_DOMAIN (Ch) && isalpha (Ch)) +# define TOUPPER(Ch) (IN_CTYPE_DOMAIN (Ch) ? toupper (Ch) : (Ch)) +# endif +#endif + +/* For compilers which are ansi but don't define __STDC__, like SGI + Irix-4.0.5 cc, also check whether PROTOTYPES is defined. */ +#if defined (__STDC__) || defined (PROTOTYPES) +# define INTERNAL(X) INTERNAL1(X) +# define INTERNAL1(X) __##X##_internal +# define WEAKNAME(X) WEAKNAME1(X) +#else +# define INTERNAL(X) __/**/X/**/_internal +#endif + +#ifdef USE_NUMBER_GROUPING +/* This file defines a function to check for correct grouping. */ +# include "grouping.h" +#endif + + + +/* Convert NPTR to an `unsigned long int' or `long int' in base BASE. + If BASE is 0 the base is determined by the presence of a leading + zero, indicating octal or a leading "0x" or "0X", indicating hexadecimal. + If BASE is < 2 or > 36, it is reset to 10. + If ENDPTR is not NULL, a pointer to the character after the last + one converted is stored in *ENDPTR. */ + +INT +INTERNAL (strtol) (nptr, endptr, base, group LOCALE_PARAM) + const STRING_TYPE *nptr; + STRING_TYPE **endptr; + int base; + int group; + LOCALE_PARAM_DECL +{ + int negative; + register unsigned LONG int cutoff; + register unsigned int cutlim; + register unsigned LONG int i; + register const STRING_TYPE *s; + register UCHAR_TYPE c; + const STRING_TYPE *save, *end; + int overflow; + +#ifdef USE_NUMBER_GROUPING +# ifdef USE_IN_EXTENDED_LOCALE_MODEL + struct locale_data *current = loc->__locales[LC_NUMERIC]; +# endif + /* The thousands character of the current locale. */ + wchar_t thousands = L'\0'; + /* The numeric grouping specification of the current locale, + in the format described in <locale.h>. */ + const char *grouping; + + if (group) + { + grouping = _NL_CURRENT (LC_NUMERIC, GROUPING); + if (*grouping <= 0 || *grouping == CHAR_MAX) + grouping = NULL; + else + { + /* Figure out the thousands separator character. */ +# if defined _LIBC || defined _HAVE_BTOWC + thousands = __btowc (*_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP)); + if (thousands == WEOF) + thousands = L'\0'; +# endif + if (thousands == L'\0') + grouping = NULL; + } + } + else + grouping = NULL; +#endif + + if (base < 0 || base == 1 || base > 36) + { + __set_errno (EINVAL); + return 0; + } + + save = s = nptr; + + /* Skip white space. */ + while (ISSPACE (*s)) + ++s; + if (*s == L_('\0')) + goto noconv; + + /* Check for a sign. */ + if (*s == L_('-')) + { + negative = 1; + ++s; + } + else if (*s == L_('+')) + { + negative = 0; + ++s; + } + else + negative = 0; + + /* Recognize number prefix and if BASE is zero, figure it out ourselves. */ + if (*s == L_('0')) + { + if ((base == 0 || base == 16) && TOUPPER (s[1]) == L_('X')) + { + s += 2; + base = 16; + } + else if (base == 0) + base = 8; + } + else if (base == 0) + base = 10; + + /* Save the pointer so we can check later if anything happened. */ + save = s; + +#ifdef USE_NUMBER_GROUPING + if (group) + { + /* Find the end of the digit string and check its grouping. */ + end = s; + for (c = *end; c != L_('\0'); c = *++end) + if ((wchar_t) c != thousands + && ((wchar_t) c < L_('0') || (wchar_t) c > L_('9')) + && (!ISALPHA (c) || (int) (TOUPPER (c) - L_('A') + 10) >= base)) + break; + if (*s == thousands) + end = s; + else + end = correctly_grouped_prefix (s, end, thousands, grouping); + } + else +#endif + end = NULL; + + cutoff = STRTOL_ULONG_MAX / (unsigned LONG int) base; + cutlim = STRTOL_ULONG_MAX % (unsigned LONG int) base; + + overflow = 0; + i = 0; + for (c = *s; c != L_('\0'); c = *++s) + { + if (s == end) + break; + if (c >= L_('0') && c <= L_('9')) + c -= L_('0'); + else if (ISALPHA (c)) + c = TOUPPER (c) - L_('A') + 10; + else + break; + if ((int) c >= base) + break; + /* Check for overflow. */ + if (i > cutoff || (i == cutoff && c > cutlim)) + overflow = 1; + else + { + i *= (unsigned LONG int) base; + i += c; + } + } + + /* Check if anything actually happened. */ + if (s == save) + goto noconv; + + /* Store in ENDPTR the address of one character + past the last character we converted. */ + if (endptr != NULL) + *endptr = (STRING_TYPE *) s; + +#if !UNSIGNED + /* Check for a value that is within the range of + `unsigned LONG int', but outside the range of `LONG int'. */ + if (overflow == 0 + && i > (negative + ? -((unsigned LONG int) (STRTOL_LONG_MIN + 1)) + 1 + : (unsigned LONG int) STRTOL_LONG_MAX)) + overflow = 1; +#endif + + if (overflow) + { + __set_errno (ERANGE); +#if UNSIGNED + return STRTOL_ULONG_MAX; +#else + return negative ? STRTOL_LONG_MIN : STRTOL_LONG_MAX; +#endif + } + + /* Return the result of the appropriate sign. */ + return negative ? -i : i; + +noconv: + /* We must handle a special case here: the base is 0 or 16 and the + first two characters are '0' and 'x', but the rest are no + hexadecimal digits. This is no error case. We return 0 and + ENDPTR points to the `x`. */ + if (endptr != NULL) + { + if (save - nptr >= 2 && TOUPPER (save[-1]) == L_('X') + && save[-2] == L_('0')) + *endptr = (STRING_TYPE *) &save[-1]; + else + /* There was no number to convert. */ + *endptr = (STRING_TYPE *) nptr; + } + + return 0L; +} + +/* External user entry point. */ + +#if _LIBC - 0 == 0 +# undef PARAMS +# if defined (__STDC__) && __STDC__ +# define PARAMS(Args) Args +# else +# define PARAMS(Args) () +# endif + +/* Prototype. */ +INT strtol PARAMS ((const STRING_TYPE *nptr, STRING_TYPE **endptr, int base)); +#endif + + +INT +#ifdef weak_function +weak_function +#endif +strtol (nptr, endptr, base LOCALE_PARAM) + const STRING_TYPE *nptr; + STRING_TYPE **endptr; + int base; + LOCALE_PARAM_DECL +{ + return INTERNAL (strtol) (nptr, endptr, base, 0 LOCALE_PARAM); +} diff --git a/src/strtoul.c b/src/strtoul.c new file mode 100644 index 00000000..298ae9ea --- /dev/null +++ b/src/strtoul.c @@ -0,0 +1,22 @@ +/* Copyright (C) 1991, 1999 Free Software Foundation, Inc. + +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@prep.ai.mit.edu. + +This program 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, or (at your option) any +later version. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define UNSIGNED 1 + +#include <strtol.c> diff --git a/src/strtoull.c b/src/strtoull.c new file mode 100644 index 00000000..d6aa1f80 --- /dev/null +++ b/src/strtoull.c @@ -0,0 +1,27 @@ +/* Function to parse an `unsigned long long int' from text. + Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc. + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@gnu.org. + + This program 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, or (at your option) any + later version. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#define QUAD 1 + +#include "strtoul.c" + +#ifdef _LIBC +strong_alias (__strtoull_internal, __strtouq_internal) +weak_alias (strtoull, strtouq) +#endif diff --git a/src/strtoumax.c b/src/strtoumax.c new file mode 100644 index 00000000..a147604a --- /dev/null +++ b/src/strtoumax.c @@ -0,0 +1,81 @@ +/* Convert string representation of a number into an uintmax_t value. + Copyright 1999 Free Software Foundation, Inc. + + This program 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, or (at your option) + any later version. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Eggert. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#if HAVE_INTTYPES_H +# include <inttypes.h> +#endif + +#if HAVE_STDLIB_H +# include <stdlib.h> +#endif + +#ifndef PARAMS +# if defined PROTOTYPES || defined __STDC__ +# define PARAMS(Args) Args +# else +# define PARAMS(Args) () +# endif +#endif + +#ifndef HAVE_DECL_STRTOUL +"this configure-time declaration test was not run" +#endif +#if !HAVE_DECL_STRTOUL +unsigned long strtoul PARAMS ((char const *, char **, int)); +#endif + +#ifndef HAVE_DECL_STRTOULL +"this configure-time declaration test was not run" +#endif +#if !HAVE_DECL_STRTOULL && HAVE_UNSIGNED_LONG_LONG +unsigned long long strtoull PARAMS ((char const *, char **, int)); +#endif + +uintmax_t +strtoumax (char const *ptr, char **endptr, int base) +{ +#define USE_IF_EQUIVALENT(function) \ + if (sizeof (uintmax_t) == sizeof function (ptr, endptr, base)) \ + return function (ptr, endptr, base); + +#if HAVE_UNSIGNED_LONG_LONG + USE_IF_EQUIVALENT (strtoull) +#endif + + USE_IF_EQUIVALENT (strtoul) + + abort (); +} + +#ifdef TESTING +# include <stdio.h> +int +main () +{ + char *p, *endptr; + printf ("sizeof uintmax_t: %d\n", sizeof (uintmax_t)); + printf ("sizeof strtoull(): %d\n", sizeof strtoull(p, &endptr, 10)); + printf ("sizeof strtoul(): %d\n", sizeof strtoul(p, &endptr, 10)); + exit (0); +} +#endif diff --git a/src/xstrtol.c b/src/xstrtol.c new file mode 100644 index 00000000..07023d9f --- /dev/null +++ b/src/xstrtol.c @@ -0,0 +1,282 @@ +/* A more useful interface to strtol. + Copyright (C) 1995, 1996, 1998-2000 Free Software Foundation, Inc. + + This program 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, or (at your option) + any later version. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Jim Meyering. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#ifndef __strtol +# define __strtol strtol +# define __strtol_t long int +# define __xstrtol xstrtol +#endif + +/* Some pre-ANSI implementations (e.g. SunOS 4) + need stderr defined if assertion checking is enabled. */ +#include <stdio.h> + +#if STDC_HEADERS +# include <stdlib.h> +#endif + +#if HAVE_STRING_H +# include <string.h> +#else +# include <strings.h> +# ifndef strchr +# define strchr index +# endif +#endif + +#include <assert.h> +#include <ctype.h> + +#include <errno.h> +#ifndef errno +extern int errno; +#endif + +#if HAVE_LIMITS_H +# include <limits.h> +#endif + +#ifndef CHAR_BIT +# define CHAR_BIT 8 +#endif + +/* The extra casts work around common compiler bugs. */ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. + It is necessary at least when t == time_t. */ +#define TYPE_MINIMUM(t) ((t) (TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) +#define TYPE_MAXIMUM(t) (~ (t) 0 - TYPE_MINIMUM (t)) + +#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) +# define IN_CTYPE_DOMAIN(c) 1 +#else +# define IN_CTYPE_DOMAIN(c) isascii(c) +#endif + +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) + +#include "xstrtol.h" + +#ifndef strtol +long int strtol (); +#endif + +#ifndef strtoul +unsigned long int strtoul (); +#endif + +#ifndef strtoumax +uintmax_t strtoumax (); +#endif + +static int +bkm_scale (__strtol_t *x, int scale_factor) +{ + __strtol_t product = *x * scale_factor; + if (*x != product / scale_factor) + return 1; + *x = product; + return 0; +} + +static int +bkm_scale_by_power (__strtol_t *x, int base, int power) +{ + while (power--) + if (bkm_scale (x, base)) + return 1; + + return 0; +} + +/* FIXME: comment. */ + +strtol_error +__xstrtol (const char *s, char **ptr, int strtol_base, + __strtol_t *val, const char *valid_suffixes) +{ + char *t_ptr; + char **p; + __strtol_t tmp; + + assert (0 <= strtol_base && strtol_base <= 36); + + p = (ptr ? ptr : &t_ptr); + + if (! TYPE_SIGNED (__strtol_t)) + { + const char *q = s; + while (ISSPACE ((unsigned char) *q)) + ++q; + if (*q == '-') + return LONGINT_INVALID; + } + + errno = 0; + tmp = __strtol (s, p, strtol_base); + if (errno != 0) + return LONGINT_OVERFLOW; + if (*p == s) + return LONGINT_INVALID; + + /* Let valid_suffixes == NULL mean `allow any suffix'. */ + /* FIXME: update all callers except the ones that allow suffixes + after the number, changing last parameter NULL to `""'. */ + if (!valid_suffixes) + { + *val = tmp; + return LONGINT_OK; + } + + if (**p != '\0') + { + int base = 1024; + int suffixes = 1; + int overflow; + + if (!strchr (valid_suffixes, **p)) + { + *val = tmp; + return LONGINT_INVALID_SUFFIX_CHAR; + } + + if (strchr (valid_suffixes, '0')) + { + /* The ``valid suffix'' '0' is a special flag meaning that + an optional second suffix is allowed, which can change + the base, e.g. "100MD" for 100 megabytes decimal. */ + + switch (p[0][1]) + { + case 'B': + suffixes++; + break; + + case 'D': + base = 1000; + suffixes++; + break; + } + } + + switch (**p) + { + case 'b': + overflow = bkm_scale (&tmp, 512); + break; + + case 'B': + overflow = bkm_scale (&tmp, 1024); + break; + + case 'c': + overflow = 0; + break; + + case 'E': /* Exa */ + overflow = bkm_scale_by_power (&tmp, base, 6); + break; + + case 'G': /* Giga */ + overflow = bkm_scale_by_power (&tmp, base, 3); + break; + + case 'k': /* kilo */ + overflow = bkm_scale_by_power (&tmp, base, 1); + break; + + case 'M': /* Mega */ + case 'm': /* 'm' is undocumented; for backward compatibility only */ + overflow = bkm_scale_by_power (&tmp, base, 2); + break; + + case 'P': /* Peta */ + overflow = bkm_scale_by_power (&tmp, base, 5); + break; + + case 'T': /* Tera */ + overflow = bkm_scale_by_power (&tmp, base, 4); + break; + + case 'w': + overflow = bkm_scale (&tmp, 2); + break; + + case 'Y': /* Yotta */ + overflow = bkm_scale_by_power (&tmp, base, 8); + break; + + case 'Z': /* Zetta */ + overflow = bkm_scale_by_power (&tmp, base, 7); + break; + + default: + *val = tmp; + return LONGINT_INVALID_SUFFIX_CHAR; + break; + } + + if (overflow) + return LONGINT_OVERFLOW; + + (*p) += suffixes; + } + + *val = tmp; + return LONGINT_OK; +} + +#ifdef TESTING_XSTRTO + +# include <stdio.h> +# include "error.h" + +char *program_name; + +int +main (int argc, char** argv) +{ + strtol_error s_err; + int i; + + program_name = argv[0]; + for (i=1; i<argc; i++) + { + char *p; + __strtol_t val; + + s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw"); + if (s_err == LONGINT_OK) + { + printf ("%s->%lu (%s)\n", argv[i], val, p); + } + else + { + STRTOL_FATAL_ERROR (argv[i], "arg", s_err); + } + } + exit (0); +} + +#endif /* TESTING_XSTRTO */ diff --git a/src/xstrtol.h b/src/xstrtol.h new file mode 100644 index 00000000..7a9a0244 --- /dev/null +++ b/src/xstrtol.h @@ -0,0 +1,64 @@ +#ifndef XSTRTOL_H_ +# define XSTRTOL_H_ 1 + +# if HAVE_INTTYPES_H +# include <inttypes.h> /* for uintmax_t */ +# endif + +# ifndef PARAMS +# if defined PROTOTYPES || (defined __STDC__ && __STDC__) +# define PARAMS(Args) Args +# else +# define PARAMS(Args) () +# endif +# endif + +# ifndef _STRTOL_ERROR +enum strtol_error + { + LONGINT_OK, LONGINT_INVALID, LONGINT_INVALID_SUFFIX_CHAR, LONGINT_OVERFLOW + }; +typedef enum strtol_error strtol_error; +# endif + +# define _DECLARE_XSTRTOL(name, type) \ + strtol_error \ + name PARAMS ((const char *s, char **ptr, int base, \ + type *val, const char *valid_suffixes)); +_DECLARE_XSTRTOL (xstrtol, long int) +_DECLARE_XSTRTOL (xstrtoul, unsigned long int) +_DECLARE_XSTRTOL (xstrtoumax, uintmax_t) + +# define _STRTOL_ERROR(Exit_code, Str, Argument_type_string, Err) \ + do \ + { \ + switch ((Err)) \ + { \ + case LONGINT_OK: \ + abort (); \ + \ + case LONGINT_INVALID: \ + error ((Exit_code), 0, "invalid %s `%s'", \ + (Argument_type_string), (Str)); \ + break; \ + \ + case LONGINT_INVALID_SUFFIX_CHAR: \ + error ((Exit_code), 0, "invalid character following %s `%s'", \ + (Argument_type_string), (Str)); \ + break; \ + \ + case LONGINT_OVERFLOW: \ + error ((Exit_code), 0, "%s `%s' too large", \ + (Argument_type_string), (Str)); \ + break; \ + } \ + } \ + while (0) + +# define STRTOL_FATAL_ERROR(Str, Argument_type_string, Err) \ + _STRTOL_ERROR (2, Str, Argument_type_string, Err) + +# define STRTOL_FAIL_WARN(Str, Argument_type_string, Err) \ + _STRTOL_ERROR (0, Str, Argument_type_string, Err) + +#endif /* not XSTRTOL_H_ */ diff --git a/src/xstrtoumax.c b/src/xstrtoumax.c new file mode 100644 index 00000000..04d7cf98 --- /dev/null +++ b/src/xstrtoumax.c @@ -0,0 +1,31 @@ +/* xstrtoumax.c -- A more useful interface to strtoumax. + Copyright 1999 Free Software Foundation, Inc. + + This program 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, or (at your option) + any later version. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Written by Paul Eggert. */ + +#if HAVE_CONFIG_H +# include <config.h> +#endif + +#if HAVE_INTTYPES_H +# include <inttypes.h> +#endif + +#define __strtol strtoumax +#define __strtol_t uintmax_t +#define __xstrtol xstrtoumax +#include "xstrtol.c" |