Browse Source

ENH: Adding KWSys component IOStream to provide help with broken C++ stream libraries.

Brad King 19 years ago
parent
commit
c500078dcc

+ 24 - 2
Source/kwsys/CMakeLists.txt

@@ -127,6 +127,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
   SET(KWSYS_USE_CommandLineArguments 1)
   SET(KWSYS_USE_FundamentalType 1)
   SET(KWSYS_USE_Terminal 1)
+  SET(KWSYS_USE_IOStream 1)
 ENDIF(KWSYS_STANDALONE OR CMake_SOURCE_DIR)
 
 #-----------------------------------------------------------------------------
@@ -144,6 +145,7 @@ ENDIF(KWSYS_STANDALONE)
 
 # Include helper macros.
 INCLUDE(${CMAKE_CURRENT_SOURCE_DIR}/kwsysPlatformCxxTests.cmake)
+INCLUDE(CheckTypeSize)
 
 # Do full dependency headers.
 INCLUDE_REGULAR_EXPRESSION("^.*$")
@@ -393,7 +395,6 @@ ENDIF(UNIX)
 
 IF(KWSYS_USE_FundamentalType)
   # Determine type sizes.
-  INCLUDE(CheckTypeSize)
   CHECK_TYPE_SIZE("char"      KWSYS_SIZEOF_CHAR)
   CHECK_TYPE_SIZE("short"     KWSYS_SIZEOF_SHORT)
   CHECK_TYPE_SIZE("int"       KWSYS_SIZEOF_INT)
@@ -447,6 +448,24 @@ IF(KWSYS_USE_FundamentalType)
     "Checking whether char is signed" DIRECT)
 ENDIF(KWSYS_USE_FundamentalType)
 
+IF(KWSYS_USE_IOStream)
+  # Determine whether iostreams support long long.
+  CHECK_TYPE_SIZE("long long" KWSYS_SIZEOF_LONG_LONG)
+  IF(KWSYS_SIZEOF_LONG_LONG)
+    SET(KWSYS_PLATFORM_CXX_TEST_DEFINES
+      -DKWSYS_IOS_USE_ANSI=${KWSYS_IOS_USE_ANSI}
+      -DKWSYS_IOS_HAVE_STD=${KWSYS_IOS_HAVE_STD})
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+      "Checking if istream supports long long" DIRECT)
+    KWSYS_PLATFORM_CXX_TEST(KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+      "Checking if ostream supports long long" DIRECT)
+    SET(KWSYS_PLATFORM_CXX_TEST_DEFINES)
+  ELSE(KWSYS_SIZEOF_LONG_LONG)
+    SET(KWSYS_IOS_HAS_ISTREAM_LONG_LONG 0)
+    SET(KWSYS_IOS_HAS_OSTREAM_LONG_LONG 0)
+  ENDIF(KWSYS_SIZEOF_LONG_LONG)
+ENDIF(KWSYS_USE_IOStream)
+
 IF(KWSYS_NAMESPACE MATCHES "^kwsys$")
   SET(KWSYS_NAME_IS_KWSYS 1)
 ELSE(KWSYS_NAMESPACE MATCHES "^kwsys$")
@@ -560,7 +579,10 @@ IF(KWSYS_USE_Glob)
 ENDIF(KWSYS_USE_Glob)
 
 # Add selected C++ classes.
-SET(cppclasses Directory DynamicLoader Glob RegularExpression SystemTools CommandLineArguments Registry)
+SET(cppclasses
+  Directory DynamicLoader Glob RegularExpression SystemTools
+  CommandLineArguments Registry IOStream
+  )
 FOREACH(cpp ${cppclasses})
   IF(KWSYS_USE_${cpp})
     SET(KWSYS_CLASSES ${KWSYS_CLASSES} ${cpp})

+ 270 - 0
Source/kwsys/IOStream.cxx

@@ -0,0 +1,270 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+
+  Copyright (c) Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#include "kwsysPrivate.h"
+#include KWSYS_HEADER(Configure.hxx)
+
+// Configure the implementation for the current streams library.
+#if !KWSYS_IOS_USE_ANSI
+# define ios_base ios
+# if defined(__HP_aCC)
+#  define protected public
+#  include <iostream.h> // Hack access to some private stream methods.
+#  undef protected
+# endif
+#endif
+
+// Include the streams library.
+#include KWSYS_HEADER(ios/iostream)
+#include KWSYS_HEADER(IOStream.hxx)
+
+// Work-around CMake dependency scanning limitation.  This must
+// duplicate the above list of headers.
+#if 0
+# include "Configure.hxx.in"
+# include "kwsys_ios_iostream.hxx.in"
+# include "IOStream.hxx.in"
+#endif
+
+// Implement the rest of this file only if it is needed.
+#if KWSYS_IOS_NEED_OPERATORS_LL
+
+# include <stdio.h>  // sscanf, sprintf
+# include <string.h> // memchr
+
+# if defined(_MAX_INT_DIG)
+#  define KWSYS_IOS_INT64_MAX_DIG _MAX_INT_DIG
+# else
+#  define KWSYS_IOS_INT64_MAX_DIG 32
+# endif
+
+namespace KWSYS_NAMESPACE
+{
+
+// Scan an input stream for an integer value.
+static int IOStreamScanStream(kwsys_ios::istream& is, char* buffer)
+{
+  // Prepare to write to buffer.
+  char* out = buffer;
+  char* end = buffer + KWSYS_IOS_INT64_MAX_DIG - 1;
+
+  // Look for leading sign.
+  if(is.peek() == '+') { *out++ = '+'; is.ignore(); }
+  else if(is.peek() == '-') { *out++ = '-'; is.ignore(); }
+
+  // Determine the base.  If not specified in the stream, try to
+  // detect it from the input.  A leading 0x means hex, and a leading
+  // 0 alone means octal.
+  int base = 0;
+  int flags = is.flags() & kwsys_ios::ios_base::basefield;
+  if(flags == kwsys_ios::ios_base::oct) { base = 8; }
+  else if(flags == kwsys_ios::ios_base::dec) { base = 10; }
+  else if(flags == kwsys_ios::ios_base::hex) { base = 16; }
+  bool foundDigit = false;
+  bool foundNonZero = false;
+  if(is.peek() == '0')
+    {
+    foundDigit = true;
+    is.ignore();
+    if((is.peek() == 'x' || is.peek() == 'X') && (base == 0 || base == 16))
+      {
+      base = 16;
+      foundDigit = false;
+      is.ignore();
+      }
+    else if (base == 0)
+      {
+      base = 8;
+      }
+    }
+
+  // Determine the range of digits allowed for this number.
+  const char* digits = "0123456789abcdefABCDEF";
+  int maxDigitIndex = 10;
+  if(base == 8)
+    {
+    maxDigitIndex = 8;
+    }
+  else if(base == 16)
+    {
+    maxDigitIndex = 10+6+6;
+    }
+
+  // Scan until an invalid digit is found.
+  for(;is.peek() != EOF; is.ignore())
+    {
+    if(memchr(digits, *out = (char)is.peek(), maxDigitIndex) != 0)
+      {
+      if((foundNonZero || *out != '0') && out < end)
+        {
+        ++out;
+        foundNonZero = true;
+        }
+      foundDigit = true;
+      }
+    else
+      {
+      break;
+      }
+    }
+
+  // Correct the buffer contents for degenerate cases.
+  if(foundDigit && !foundNonZero)
+    {
+    *out++ = '0';
+    }
+  else if (!foundDigit)
+    {
+    out = buffer;
+    }
+
+  // Terminate the string in the buffer.
+  *out = '\0';
+
+  return base;
+}
+
+// Read an integer value from an input stream.
+template <class T>
+kwsys_ios::istream&
+IOStreamScanTemplate(kwsys_ios::istream& is, T& value, char type)
+{
+  int state = kwsys_ios::ios_base::goodbit;
+
+  // Skip leading whitespace.
+# if KWSYS_IOS_USE_ANSI
+  kwsys_ios::istream::sentry okay(is);
+# else
+  is.eatwhite();
+  kwsys_ios::istream& okay = is;
+# endif
+
+  if(okay)
+    {
+#   if KWSYS_IOS_USE_ANSI
+    try {
+#   endif
+    // Copy the string to a buffer and construct the format string.
+    char buffer[KWSYS_IOS_INT64_MAX_DIG];
+#   if defined(_MSC_VER)
+    char format[] = "%I64_";
+    const int typeIndex = 4;
+#   else
+    char format[] = "%ll_";
+    const int typeIndex = 3;
+#   endif
+    switch(IOStreamScanStream(is, buffer))
+      {
+      case 8: format[typeIndex] = 'o'; break;
+      case 0: // Default to decimal if not told otherwise.
+      case 10: format[typeIndex] = type; break;
+      case 16: format[typeIndex] = 'x'; break;
+      };
+
+    // Use sscanf to parse the number from the buffer.
+    T result;
+    int success = (sscanf(buffer, format, &result) == 1)?1:0;
+
+    // Set flags for resulting state.
+    if(is.peek() == EOF) { state |= kwsys_ios::ios_base::eofbit; }
+    if(!success) { state |= kwsys_ios::ios_base::failbit; }
+    else { value = result; }
+#   if KWSYS_IOS_USE_ANSI
+    } catch(...) { state |= kwsys_ios::ios_base::badbit; }
+#   endif
+    }
+
+# if KWSYS_IOS_USE_ANSI
+  is.setstate(kwsys_ios::ios_base::iostate(state));
+# else
+  is.clear(state);
+# endif
+  return is;
+}
+
+// Print an integer value to an output stream.
+template <class T>
+kwsys_ios::ostream&
+IOStreamPrintTemplate(kwsys_ios::ostream& os, T value, char type)
+{
+# if KWSYS_IOS_USE_ANSI
+  kwsys_ios::ostream::sentry okay(os);
+# else
+  kwsys_ios::ostream& okay = os;
+# endif
+  if(okay)
+    {
+#   if KWSYS_IOS_USE_ANSI
+    try {
+#   endif
+    // Construct the format string.
+    char format[8];
+    char* f = format;
+    *f++ = '%';
+    if(os.flags() & kwsys_ios::ios_base::showpos) { *f++ = '+'; }
+    if(os.flags() & kwsys_ios::ios_base::showbase) { *f++ = '#'; }
+#   if defined(_MSC_VER)
+    *f++ = 'I'; *f++ = '6'; *f++ = '4';
+#   else
+    *f++ = 'l'; *f++ = 'l';
+#   endif
+    long bflags = os.flags() & kwsys_ios::ios_base::basefield;
+    if(bflags == kwsys_ios::ios_base::oct) { *f++ = 'o'; }
+    else if(bflags != kwsys_ios::ios_base::hex) { *f++ = type; }
+    else if(os.flags() & kwsys_ios::ios_base::uppercase) { *f++ = 'X'; }
+    else { *f++ = 'x'; }
+    *f = '\0';
+
+    // Use sprintf to print to a buffer and then write the
+    // buffer to the stream.
+    char buffer[2*KWSYS_IOS_INT64_MAX_DIG];
+    sprintf(buffer, format, value);
+    os << buffer;
+#   if KWSYS_IOS_USE_ANSI
+    } catch(...) { os.clear(os.rdstate() | kwsys_ios::ios_base::badbit); }
+#   endif
+    }
+  return os;
+}
+
+# if !KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+// Implement input stream operator for IOStreamSLL.
+kwsys_ios::istream& IOStreamScan(kwsys_ios::istream& is, IOStreamSLL& value)
+{
+  return IOStreamScanTemplate(is, value, 'd');
+}
+
+// Implement input stream operator for IOStreamULL.
+kwsys_ios::istream& IOStreamScan(kwsys_ios::istream& is, IOStreamULL& value)
+{
+  return IOStreamScanTemplate(is, value, 'u');
+}
+# endif
+
+# if !KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+// Implement output stream operator for IOStreamSLL.
+kwsys_ios::ostream& IOStreamPrint(kwsys_ios::ostream& os, IOStreamSLL value)
+{
+  return IOStreamPrintTemplate(os, value, 'd');
+}
+
+// Implement output stream operator for IOStreamULL.
+kwsys_ios::ostream& IOStreamPrint(kwsys_ios::ostream& os, IOStreamULL value)
+{
+  return IOStreamPrintTemplate(os, value, 'u');
+}
+# endif
+
+} // namespace KWSYS_NAMESPACE
+
+#endif // KWSYS_IOS_NEED_OPERATORS_LL

+ 148 - 0
Source/kwsys/IOStream.hxx.in

@@ -0,0 +1,148 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+
+  Copyright (c) Kitware, Inc., Insight Consortium.  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notices for more information.
+
+=========================================================================*/
+#ifndef @KWSYS_NAMESPACE@_IOStream_hxx
+#define @KWSYS_NAMESPACE@_IOStream_hxx
+
+#include <@KWSYS_NAMESPACE@/ios/iosfwd>
+
+/* Define these macros temporarily to keep the code readable.  */
+#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# define kwsysEXPORT @KWSYS_NAMESPACE@_EXPORT
+# define kwsys_ios @KWSYS_NAMESPACE@_ios
+#endif
+
+/* Whether istream supports long long.  */
+#define @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG @KWSYS_IOS_HAS_ISTREAM_LONG_LONG@
+
+/* Whether ostream supports long long.  */
+#define @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG @KWSYS_IOS_HAS_OSTREAM_LONG_LONG@
+
+/* Size of type long long and 0 if not available.  */
+#define @KWSYS_NAMESPACE@_IOS_SIZEOF_LONG_LONG @KWSYS_SIZEOF_LONG_LONG@
+
+/* Determine whether we need to define the streaming operators for
+   long long or __int64.  */
+#if @KWSYS_NAMESPACE@_IOS_SIZEOF_LONG_LONG
+# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG || \
+     !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1
+  namespace @KWSYS_NAMESPACE@
+  {
+    typedef long long IOStreamSLL;
+    typedef unsigned long long IOStreamULL;
+  }
+# endif
+#elif defined(_MSC_VER) && _MSC_VER < 1300
+# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 1
+  namespace @KWSYS_NAMESPACE@
+  {
+    typedef __int64 IOStreamSLL;
+    typedef unsigned __int64 IOStreamULL;
+  }
+#endif
+#if !defined(@KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL)
+# define @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL 0
+#endif
+
+#if @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL
+# if !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG
+
+/* Input stream operator implementation functions.  */
+namespace @KWSYS_NAMESPACE@
+{
+kwsysEXPORT kwsys_ios::istream& IOStreamScan(kwsys_ios::istream&,
+                                             IOStreamSLL&);
+kwsysEXPORT kwsys_ios::istream& IOStreamScan(kwsys_ios::istream&,
+                                             IOStreamULL&);
+}
+
+/* Provide input stream operator for long long.  */
+#  if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_LONG_LONG) && \
+      !defined(KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED)
+#   define KWSYS_IOS_ISTREAM_LONG_LONG_DEFINED
+#   define @KWSYS_NAMESPACE@_IOS_ISTREAM_LONG_LONG_DEFINED
+inline kwsys_ios::istream&
+operator>>(kwsys_ios::istream& is, @KWSYS_NAMESPACE@::IOStreamSLL& value)
+{
+  return @KWSYS_NAMESPACE@::IOStreamScan(is, value);
+}
+#  endif
+
+/* Provide input stream operator for unsigned long long.  */
+#  if !defined(@KWSYS_NAMESPACE@_IOS_NO_ISTREAM_UNSIGNED_LONG_LONG) && \
+      !defined(KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED)
+#   define KWSYS_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED
+#   define @KWSYS_NAMESPACE@_IOS_ISTREAM_UNSIGNED_LONG_LONG_DEFINED
+inline kwsys_ios::istream&
+operator>>(kwsys_ios::istream& is, @KWSYS_NAMESPACE@::IOStreamULL& value)
+{
+  return @KWSYS_NAMESPACE@::IOStreamScan(is, value);
+}
+#  endif
+# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG */
+
+# if !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+
+/* Output stream operator implementation functions.  */
+namespace @KWSYS_NAMESPACE@
+{
+kwsysEXPORT kwsys_ios::ostream& IOStreamPrint(kwsys_ios::ostream&,
+                                              IOStreamSLL);
+kwsysEXPORT kwsys_ios::ostream& IOStreamPrint(kwsys_ios::ostream&,
+                                              IOStreamULL);
+}
+
+/* Provide output stream operator for long long.  */
+#  if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_LONG_LONG) && \
+      !defined(KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED)
+#   define KWSYS_IOS_OSTREAM_LONG_LONG_DEFINED
+#   define @KWSYS_NAMESPACE@_IOS_OSTREAM_LONG_LONG_DEFINED
+inline kwsys_ios::ostream&
+operator<<(kwsys_ios::ostream& os, @KWSYS_NAMESPACE@::IOStreamSLL value)
+{
+  return @KWSYS_NAMESPACE@::IOStreamPrint(os, value);
+}
+#  endif
+
+/* Provide output stream operator for unsigned long long.  */
+#  if !defined(@KWSYS_NAMESPACE@_IOS_NO_OSTREAM_UNSIGNED_LONG_LONG) && \
+      !defined(KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED)
+#   define KWSYS_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED
+#   define @KWSYS_NAMESPACE@_IOS_OSTREAM_UNSIGNED_LONG_LONG_DEFINED
+inline kwsys_ios::ostream&
+operator<<(kwsys_ios::ostream& os, @KWSYS_NAMESPACE@::IOStreamULL value)
+{
+  return @KWSYS_NAMESPACE@::IOStreamPrint(os, value);
+}
+#  endif
+# endif /* !@KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG */
+#endif /* @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL */
+
+/* Undefine temporary macros.  */
+#if !defined (KWSYS_NAMESPACE) && !@KWSYS_NAMESPACE@_NAME_IS_KWSYS
+# undef kwsysEXPORT
+# undef kwsys_ios
+#endif
+
+/* If building a C++ file in kwsys itself, give the source file
+   access to the macros without a configured namespace.  */
+#if defined(KWSYS_NAMESPACE)
+# define KWSYS_IOS_SIZEOF_LONG_LONG      @KWSYS_NAMESPACE@_IOS_SIZEOF_LONG_LONG
+# define KWSYS_IOS_HAS_ISTREAM_LONG_LONG @KWSYS_NAMESPACE@_IOS_HAS_ISTREAM_LONG_LONG
+# define KWSYS_IOS_HAS_OSTREAM_LONG_LONG @KWSYS_NAMESPACE@_IOS_HAS_OSTREAM_LONG_LONG
+# define KWSYS_IOS_NEED_OPERATORS_LL     @KWSYS_NAMESPACE@_IOS_NEED_OPERATORS_LL
+#endif
+
+#endif
+

+ 44 - 0
Source/kwsys/kwsysPlatformCxxTests.cxx

@@ -7,6 +7,26 @@
 # endif
 #endif
 
+// Setup for tests that use iostreams.
+#if defined(KWSYS_IOS_USE_ANSI) && defined(KWSYS_IOS_HAVE_STD)
+# if defined(_MSC_VER)
+#  pragma warning (push,1)
+# endif
+# if KWSYS_IOS_USE_ANSI
+#  include <iostream>
+# else
+#  include <iostream.h>
+# endif
+# if defined(_MSC_VER)
+#  pragma warning (pop)
+# endif
+# if KWSYS_IOS_HAVE_STD
+#  define kwsys_ios std
+# else
+#  define kwsys_ios
+# endif
+#endif
+
 #ifdef TEST_KWSYS_STL_HAVE_STD
 #include <list>
 void f(std::list<int>*) {}
@@ -266,6 +286,30 @@ int main()
 }
 #endif
 
+#ifdef TEST_KWSYS_IOS_HAS_ISTREAM_LONG_LONG
+int test_istream(kwsys_ios::istream& is, long long& x)
+{
+  return (is >> x)? 1:0;
+}
+int main()
+{
+  long long x = 0;
+  return test_istream(kwsys_ios::cin, x);
+}
+#endif
+
+#ifdef TEST_KWSYS_IOS_HAS_OSTREAM_LONG_LONG
+int test_ostream(kwsys_ios::ostream& os, long long x)
+{
+  return (os << x)? 1:0;
+}
+int main()
+{
+  long long x = 0;
+  return test_ostream(kwsys_ios::cout, x);
+}
+#endif
+
 #ifdef TEST_KWSYS_CHAR_IS_SIGNED
 /* Return 0 for char signed and 1 for char unsigned.  */
 int main()