Implement strtoll on all systems that lack it

Hrvoje Niksic <[email protected]> Thu, 11 Aug 2005 23:18:16 +0200
Newsgroups gmane.comp.web.wget.patches
Message-ID <[email protected]>
This simply moves the existing str_to_int64 function to cmpt.c.  A
similar patch will be applied on the 1.10 branch.

2005-08-11  Hrvoje Niksic  <[email protected]>

	* cmpt.c (strtoll): Define it if missing on the system and if Wget
	needs it.

	* mswindows.c (str_to_int64): Move to cmpt.c and rename to strtoll.

Index: configure.in
===================================================================
--- configure.in	(revision 2026)
+++ configure.in	(working copy)
@@ -205,7 +205,7 @@
 AC_FUNC_MMAP
 AC_FUNC_FSEEKO
 AC_CHECK_FUNCS(strptime timegm snprintf vsnprintf vasprintf drand48)
-AC_CHECK_FUNCS(usleep ftello sigblock sigsetjmp)
+AC_CHECK_FUNCS(strtoll strtoimax usleep ftello sigblock sigsetjmp)
 
 dnl We expect to have these functions on Unix-like systems configure
 dnl runs on.  The defines are provided to get them in config.h.in so
Index: src/mswindows.c
===================================================================
--- src/mswindows.c	(revision 2043)
+++ src/mswindows.c	(working copy)
@@ -72,116 +72,6 @@
 #endif /* not HAVE_USLEEP */
 }
 
-#if !defined(HAVE_STRTOLL) && !defined(HAVE__STRTOI64)
-
-static inline int
-char_value (char c, int base)
-{
-  int value;
-  if (c < '0')
-    return -1;
-  if ('0' <= c && c <= '9')
-    value = c - '0';
-  else if ('a' <= c && c <= 'z')
-    value = c - 'a' + 10;
-  else if ('A' <= c && c <= 'Z')
-    value = c - 'A' + 10;
-  else
-    return -1;
-  if (value >= base)
-    return -1;
-  return value;
-}
-
-/* A fairly simple strtoll replacement for MS VC versions that don't
-   supply _strtoi64.  */
-
-__int64
-str_to_int64 (const char *nptr, char **endptr, int base)
-{
-#define INT64_OVERFLOW 9223372036854775807I64
-#define INT64_UNDERFLOW (-INT64_OVERFLOW - 1)
-
-  __int64 result = 0;
-  bool negative;
-
-  if (base != 0 && (base < 2 || base > 36))
-    {
-      errno = EINVAL;
-      return 0;
-    }
-
-  while (*nptr == ' ' || *nptr == '\t')
-    ++nptr;
-  if (*nptr == '-')
-    {
-      negative = true;
-      ++nptr;
-    }
-  else if (*nptr == '+')
-    {
-      negative = false;
-      ++nptr;
-    }
-  else
-    negative = false;
-
-  /* If base is 0, determine the real base based on the beginning on
-     the number; octal numbers begin with "0", hexadecimal with "0x",
-     and the others are considered octal.  */
-  if (*nptr == '0')
-    {
-      if ((base == 0 || base == 16)
-	  &&
-	  (*(nptr + 1) == 'x' || *(nptr + 1) == 'X'))
-	{
-	  base = 16;
-	  nptr += 2;
-	}
-      else if (base == 0)
-	base = 8;
-    }
-  else if (base == 0)
-    base = 10;
-
-  if (!negative)
-    {
-      /* Parse positive number, checking for overflow. */
-      int val;
-      for (; (val = char_value (*nptr, base)) != -1; ++nptr)
-	{
-	  __int64 newresult = base * result + val;
-	  if (newresult < result)
-	    {
-	      result = INT64_OVERFLOW;
-	      errno = ERANGE;
-	      break;
-	    }
-	  result = newresult;
-	}
-    }
-  else
-    {
-      /* Parse negative number, checking for underflow. */
-      int val;
-      for (; (val = char_value (*nptr, base)) != -1; ++nptr)
-	{
-	  __int64 newresult = base * result - val;
-	  if (newresult > result)
-	    {
-	      result = INT64_UNDERFLOW;
-	      errno = ERANGE;
-	      break;
-	    }
-	  result = newresult;
-	}
-    }
-  if (endptr)
-    *endptr = (char *) nptr;
-  return result;
-}
-#endif
-
 void
 windows_main (int *argc, char **argv, char **exec_name)
 {
Index: src/mswindows.h
===================================================================
--- src/mswindows.h	(revision 2029)
+++ src/mswindows.h	(working copy)
@@ -86,15 +86,16 @@
 #define SIZEOF_WGINT 8
 #define WGINT_MAX LL (9223372036854775807)
 
-/* str_to_wgint is a function with the semantics of strtol, but which
-   works on wgint.  */
+/* str_to_wgint is a function with the semantics of strtol[l], but
+   which works on wgint.  */
 #if defined HAVE_STRTOLL
 # define str_to_wgint strtoll
 #elif defined HAVE__STRTOI64
 # define str_to_wgint _strtoi64
 #else
-__int64 str_to_int64 (const char *, char **, int);
-# define str_to_wgint str_to_int64
+# define str_to_wgint strtoll
+# define NEED_STRTOLL
+# define strtoll_return __int64
 #endif
 
 /* Windows has no symlink, therefore no lstat.  Without symlinks lstat
Index: src/wget.h
===================================================================
--- src/wget.h	(revision 2008)
+++ src/wget.h	(working copy)
@@ -133,11 +133,24 @@
 #  define str_to_wgint strtol
 #  define WGINT_MAX LONG_MAX
 # else
-#  define str_to_wgint strtoll
 #  define WGINT_MAX LLONG_MAX
+#  ifdef HAVE_STRTOLL
+#   define str_to_wgint strtoll
+#  elif HAVE_STRTOIMAX
+#   define str_to_wgint strtoimax
+#  else
+#   define str_to_wgint strtoll
+#   define NEED_STRTOLL
+#   define strtoll_return long long
+#  endif
 # endif
 #endif
 
+/* Declare our strtoll replacement. */
+#ifdef NEED_STRTOLL
+strtoll_return strtoll (const char *, char **, int);
+#endif
+
 /* Now define a large integral type useful for storing sizes of *sums*
    of downloads, such as the value of the --quota option.  This should
    be a type able to hold 2G+ values even on systems without large
Index: src/cmpt.c
===================================================================
--- src/cmpt.c	(revision 2015)
+++ src/cmpt.c	(working copy)
@@ -1266,3 +1266,128 @@
   return (time_t) secs;
 }
 #endif /* HAVE_TIMEGM */
+
+#ifdef NEED_STRTOLL
+/* strtoll is required by C99 and used by Wget only on systems with
+   LFS.  Unfortunately, some systems have LFS, but no strtoll or
+   equivalent.  These include HPUX 11.0 and Windows.
+
+   We use #ifdef NEED_STRTOLL instead of #ifndef HAVE_STRTOLL because
+   of the systems which have a suitable replacement (e.g. _strtoi64 on
+   Windows), on which Wget's str_to_wgint is instructed to use that
+   instead.  */
+
+static inline int
+char_value (char c, int base)
+{
+  int value;
+  if (c < '0')
+    return -1;
+  if ('0' <= c && c <= '9')
+    value = c - '0';
+  else if ('a' <= c && c <= 'z')
+    value = c - 'a' + 10;
+  else if ('A' <= c && c <= 'Z')
+    value = c - 'A' + 10;
+  else
+    return -1;
+  if (value >= base)
+    return -1;
+  return value;
+}
+
+#define LL strtoll_return	/* long long or __int64 */
+
+/* These constants assume 64-bit strtoll_return. */
+
+/* A roundabout way of writing 2**63-1 = 9223372036854775807 */
+#define STRTOLL_OVERFLOW (((LL) 1 << 62) - 1 + ((LL) 1 << 62))
+/* A roundabout way of writing -2**63 = -9223372036854775808 */
+#define STRTOLL_UNDERFLOW (-STRTOLL_OVERFLOW - 1)
+
+/* A strtoll replacement for systems that have LFS but don't supply
+   strtoll.  The headers typedef strtoll_return to long long or to
+   __int64.  */
+
+strtoll_return
+strtoll (const char *nptr, char **endptr, int base)
+{
+  strtoll_return result = 0;
+  bool negative;
+
+  if (base != 0 && (base < 2 || base > 36))
+    {
+      errno = EINVAL;
+      return 0;
+    }
+
+  while (*nptr == ' ' || *nptr == '\t')
+    ++nptr;
+  if (*nptr == '-')
+    {
+      negative = true;
+      ++nptr;
+    }
+  else if (*nptr == '+')
+    {
+      negative = false;
+      ++nptr;
+    }
+  else
+    negative = false;
+
+  /* If base is 0, determine the real base based on the beginning on
+     the number; octal numbers begin with "0", hexadecimal with "0x",
+     and the others are considered octal.  */
+  if (*nptr == '0')
+    {
+      if ((base == 0 || base == 16)
+	  &&
+	  (*(nptr + 1) == 'x' || *(nptr + 1) == 'X'))
+	{
+	  base = 16;
+	  nptr += 2;
+	}
+      else if (base == 0)
+	base = 8;
+    }
+  else if (base == 0)
+    base = 10;
+
+  if (!negative)
+    {
+      /* Parse positive number, checking for overflow. */
+      int val;
+      for (; (val = char_value (*nptr, base)) != -1; ++nptr)
+	{
+	  strtoll_return newresult = base * result + val;
+	  if (newresult < result)
+	    {
+	      result = STRTOLL_OVERFLOW;
+	      errno = ERANGE;
+	      break;
+	    }
+	  result = newresult;
+	}
+    }
+  else
+    {
+      /* Parse negative number, checking for underflow. */
+      int val;
+      for (; (val = char_value (*nptr, base)) != -1; ++nptr)
+	{
+	  strtoll_return newresult = base * result - val;
+	  if (newresult > result)
+	    {
+	      result = STRTOLL_UNDERFLOW;
+	      errno = ERANGE;
+	      break;
+	    }
+	  result = newresult;
+	}
+    }
+  if (endptr)
+    *endptr = (char *) nptr;
+  return result;
+}
+#endif	/* NEED_STRTOLL */