Bladeren bron

ENH: Added kwsys library for platform-independent system tools.

Brad King 22 jaren geleden
bovenliggende
commit
7dff3a7f69

+ 47 - 0
Source/kwsys/CMakeLists.txt

@@ -0,0 +1,47 @@
+PROJECT(${KWSYS_NAMESPACE})
+INCLUDE(${CMAKE_ROOT}/Modules/TestForANSIStreamHeaders.cmake)
+INCLUDE(${CMAKE_ROOT}/Modules/CheckIncludeFileCXX.cmake)
+INCLUDE(${CMAKE_ROOT}/Modules/TestForSTDNamespace.cmake)
+INCLUDE(${CMAKE_ROOT}/Modules/TestForANSIForScope.cmake)
+CHECK_INCLUDE_FILE_CXX("sstream" CMAKE_HAS_ANSI_STRING_STREAM)
+
+SET(KWSYS_NO_STD_NAMESPACE ${CMAKE_NO_STD_NAMESPACE})
+SET(KWSYS_NO_ANSI_STREAM_HEADERS ${CMAKE_NO_ANSI_STREAM_HEADERS})
+SET(KWSYS_NO_ANSI_STRING_STREAM ${CMAKE_NO_ANSI_STRING_STREAM})
+SET(KWSYS_NO_ANSI_FOR_SCOPE ${CMAKE_NO_ANSI_FOR_SCOPE})
+
+SET(CLASSES Directory RegularExpression SystemTools)
+SET(HEADERS Configure StandardIncludes)
+
+SET(SRCS)
+SET(KWSYS_INCLUDES)
+FOREACH(c ${CLASSES})
+  SET(SRCS ${SRCS} ${c}.cxx)
+  CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${c}.hxx.in
+                 ${PROJECT_BINARY_DIR}/../${KWSYS_NAMESPACE}/${c}.hxx
+                 @ONLY IMMEDIATE)
+  SET(KWSYS_INCLUDES ${KWSYS_INCLUDES}
+      ${PROJECT_BINARY_DIR}/../${KWSYS_NAMESPACE}/${c}.hxx)
+ENDFOREACH(c)
+
+FOREACH(h ${HEADERS})
+  CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/${h}.hxx.in
+                 ${PROJECT_BINARY_DIR}/../${KWSYS_NAMESPACE}/${h}.hxx
+                 @ONLY IMMEDIATE)
+  SET(KWSYS_INCLUDES ${KWSYS_INCLUDES}
+      ${PROJECT_BINARY_DIR}/../${KWSYS_NAMESPACE}/${h}.hxx)
+ENDFOREACH(h)
+
+ADD_LIBRARY(${KWSYS_NAMESPACE} ${SRCS})
+
+ADD_DEFINITIONS("-DKWSYS_NAMESPACE=${KWSYS_NAMESPACE}")
+INCLUDE_DIRECTORIES(BEFORE ${PROJECT_BINARY_DIR}/../${KWSYS_NAMESPACE})
+
+IF(KWSYS_LIBRARY_INSTALL_DIR)
+  INSTALL_TARGETS(${KWSYS_LIBRARY_INSTALL_DIR} ${KWSYS_NAMESPACE})
+ENDIF(KWSYS_LIBRARY_INSTALL_DIR)
+
+IF(KWSYS_INCLUDE_INSTALL_DIR)
+  INSTALL_FILES(${KWSYS_INCLUDE_INSTALL_DIR}/${KWSYS_NAMESPACE}
+                FILES ${KWSYS_INCLUDES})
+ENDIF(KWSYS_INCLUDE_INSTALL_DIR)

+ 10 - 0
Source/kwsys/Configure.hxx.in

@@ -0,0 +1,10 @@
+#ifndef @KWSYS_NAMESPACE@_Configure_hxx
+#define @KWSYS_NAMESPACE@_Configure_hxx
+
+/* This configuration should match for all instances of kwsys.  */
+#cmakedefine KWSYS_NO_STD_NAMESPACE
+#cmakedefine KWSYS_NO_ANSI_STREAM_HEADERS
+#cmakedefine KWSYS_NO_ANSI_STRING_STREAM
+#cmakedefine KWSYS_NO_ANSI_FOR_SCOPE
+
+#endif

+ 116 - 0
Source/kwsys/Directory.cxx

@@ -0,0 +1,116 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See http://www.cmake.org/HTML/Copyright.html 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 <Directory.hxx>
+
+// First microsoft compilers
+
+#ifdef _MSC_VER
+#include <windows.h>
+#include <io.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+namespace KWSYS_NAMESPACE
+{
+
+bool Directory::Load(const char* name)
+{
+  char* buf;
+  size_t n = strlen(name);
+  if ( name[n - 1] == '/' ) 
+    {
+    buf = new char[n + 1 + 1];
+    sprintf(buf, "%s*", name);
+    } 
+  else
+    {
+    buf = new char[n + 2 + 1];
+    sprintf(buf, "%s/*", name);
+    }
+  struct _finddata_t data;      // data of current file
+  
+  // Now put them into the file array
+  size_t srchHandle = _findfirst(buf, &data);
+  delete [] buf;
+  
+  if ( srchHandle == -1 )
+    {
+    return 0;
+    }
+  
+  // Loop through names
+  do 
+    {
+    m_Files.push_back(data.name);
+    } 
+  while ( _findnext(srchHandle, &data) != -1 );
+  m_Path = name;
+  return _findclose(srchHandle) != -1;
+}
+
+} // namespace KWSYS_NAMESPACE
+
+#else
+
+// Now the POSIX style directory access
+
+#include <sys/types.h>
+#include <dirent.h>
+  
+namespace KWSYS_NAMESPACE
+{
+
+bool Directory::Load(const char* name)
+{
+  DIR* dir = opendir(name);
+
+  if (!dir)
+    {
+    return 0;
+    }
+
+  for (dirent* d = readdir(dir); d; d = readdir(dir) )
+    {
+    m_Files.push_back(d->d_name);
+    }
+  m_Path = name;
+  closedir(dir);
+  return 1;
+}
+  
+} // namespace KWSYS_NAMESPACE
+
+#endif
+
+namespace KWSYS_NAMESPACE
+{
+
+const char* Directory::GetFile(size_t dindex)
+{
+  if ( dindex >= m_Files.size() )
+    {
+    return 0;
+    }
+  return m_Files[dindex].c_str();
+}
+
+} // namespace KWSYS_NAMESPACE

+ 65 - 0
Source/kwsys/Directory.hxx.in

@@ -0,0 +1,65 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See http://www.cmake.org/HTML/Copyright.html 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@_Directory_hxx
+#define @KWSYS_NAMESPACE@_Directory_hxx
+
+#include <@KWSYS_NAMESPACE@/StandardIncludes.hxx>
+
+#include <string>
+#include <vector>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+/** \class Directory
+ * \brief Portable directory/filename traversal.
+ * 
+ * Directory provides a portable way of finding the names of the files
+ * in a system directory.
+ *
+ * Directory currently works with Windows and Unix operating systems.
+ */
+
+class Directory 
+{
+public:
+  /**
+   * Load the specified directory and load the names of the files
+   * in that directory. 0 is returned if the directory can not be 
+   * opened, 1 if it is opened.   
+   */
+  bool Load(const char* dir);
+
+  /**
+   * Return the number of files in the current directory.
+   */
+  size_t GetNumberOfFiles() { return m_Files.size();}
+
+  /**
+   * Return the file at the given index, the indexing is 0 based
+   */
+  const char* GetFile(size_t );
+
+private:
+  kwsys_std::vector<kwsys_std::string> m_Files; // Array of Files
+  kwsys_std::string m_Path;               // Path to Open'ed directory
+
+}; // End Class: Directory
+  
+} // namespace @KWSYS_NAMESPACE@
+
+#endif

+ 1211 - 0
Source/kwsys/RegularExpression.cxx

@@ -0,0 +1,1211 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See http://www.cmake.org/HTML/Copyright.html 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.
+
+=========================================================================*/
+//
+// Copyright (C) 1991 Texas Instruments Incorporated.
+//
+// Permission is granted to any individual or institution to use, copy, modify,
+// and distribute this software, provided that this complete copyright and
+// permission notice is maintained, intact, in all copies and supporting
+// documentation.
+//
+// Texas Instruments Incorporated provides this software "as is" without
+// express or implied warranty.
+//
+//
+// Created: MNF 06/13/89  Initial Design and Implementation
+// Updated: LGO 08/09/89  Inherit from Generic
+// Updated: MBN 09/07/89  Added conditional exception handling
+// Updated: MBN 12/15/89  Sprinkled "const" qualifiers all over the place!
+// Updated: DLS 03/22/91  New lite version
+//
+
+#include <RegularExpression.hxx>        // Include class specification 
+#include <stdio.h>
+
+namespace KWSYS_NAMESPACE
+{
+
+// RegularExpression -- Copies the given regular expression.
+RegularExpression::RegularExpression (const RegularExpression& rxp) {
+  if ( !rxp.program )
+    {
+    this->program = 0;
+    return;
+    }
+  int ind; 
+  this->progsize = rxp.progsize;                // Copy regular expression size
+  this->program = new char[this->progsize];     // Allocate storage
+  for(ind=this->progsize; ind-- != 0;)          // Copy regular expresion
+    this->program[ind] = rxp.program[ind];
+  this->startp[0] = rxp.startp[0];              // Copy pointers into last
+  this->endp[0] = rxp.endp[0];                  // Successful "find" operation
+  this->regmust = rxp.regmust;                  // Copy field
+  if (rxp.regmust != 0) {
+    char* dum = rxp.program;
+    ind = 0;
+    while (dum != rxp.regmust) {
+      ++dum;
+      ++ind;
+    }
+    this->regmust = this->program + ind;
+  }
+  this->regstart = rxp.regstart;                // Copy starting index
+  this->reganch = rxp.reganch;                  // Copy remaining private data
+  this->regmlen = rxp.regmlen;                  // Copy remaining private data
+}
+
+// operator== -- Returns true if two regular expressions have the same
+// compiled program for pattern matching.
+bool RegularExpression::operator== (const RegularExpression& rxp) const {
+  if (this != &rxp) {                           // Same address?
+    int ind = this->progsize;                   // Get regular expression size
+    if (ind != rxp.progsize)                    // If different size regexp
+      return false;                             // Return failure
+    while(ind-- != 0)                           // Else while still characters
+      if(this->program[ind] != rxp.program[ind]) // If regexp are different    
+        return false;                            // Return failure             
+  }
+  return true;                                  // Else same, return success  
+}
+
+
+// deep_equal -- Returns true if have the same compiled regular expressions
+// and the same start and end pointers.
+
+bool RegularExpression::deep_equal (const RegularExpression& rxp) const {
+  int ind = this->progsize;                     // Get regular expression size
+  if (ind != rxp.progsize)                      // If different size regexp
+    return false;                               // Return failure
+  while(ind-- != 0)                             // Else while still characters
+    if(this->program[ind] != rxp.program[ind])  // If regexp are different    
+      return false;                             // Return failure             
+  return (this->startp[0] == rxp.startp[0] &&   // Else if same start/end ptrs,
+          this->endp[0] == rxp.endp[0]);        // Return true
+}   
+
+// The remaining code in this file is derived from the  regular expression code
+// whose  copyright statement appears  below.  It has been  changed to work
+// with the class concepts of C++ and COOL.
+
+/*
+ * compile and find 
+ *
+ *      Copyright (c) 1986 by University of Toronto.
+ *      Written by Henry Spencer.  Not derived from licensed software.
+ *
+ *      Permission is granted to anyone to use this software for any
+ *      purpose on any computer system, and to redistribute it freely,
+ *      subject to the following restrictions:
+ *
+ *      1. The author is not responsible for the consequences of use of
+ *              this software, no matter how awful, even if they arise
+ *              from defects in it.
+ *
+ *      2. The origin of this software must not be misrepresented, either
+ *              by explicit claim or by omission.
+ *
+ *      3. Altered versions must be plainly marked as such, and must not
+ *              be misrepresented as being the original software.
+ *
+ * Beware that some of this code is subtly aware of the way operator
+ * precedence is structured in regular expressions.  Serious changes in
+ * regular-expression syntax might require a total rethink.
+ */
+
+/*
+ * The "internal use only" fields in regexp.h are present to pass info from
+ * compile to execute that permits the execute phase to run lots faster on
+ * simple cases.  They are:
+ *
+ * regstart     char that must begin a match; '\0' if none obvious
+ * reganch      is the match anchored (at beginning-of-line only)?
+ * regmust      string (pointer into program) that match must include, or NULL
+ * regmlen      length of regmust string
+ *
+ * Regstart and reganch permit very fast decisions on suitable starting points
+ * for a match, cutting down the work a lot.  Regmust permits fast rejection
+ * of lines that cannot possibly match.  The regmust tests are costly enough
+ * that compile() supplies a regmust only if the r.e. contains something
+ * potentially expensive (at present, the only such thing detected is * or +
+ * at the start of the r.e., which can involve a lot of backup).  Regmlen is
+ * supplied because the test in find() needs it and compile() is computing
+ * it anyway.
+ */
+
+/*
+ * Structure for regexp "program".  This is essentially a linear encoding
+ * of a nondeterministic finite-state machine (aka syntax charts or
+ * "railroad normal form" in parsing technology).  Each node is an opcode
+ * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
+ * all nodes except BRANCH implement concatenation; a "next" pointer with
+ * a BRANCH on both ends of it is connecting two alternatives.  (Here we
+ * have one of the subtle syntax dependencies:  an individual BRANCH (as
+ * opposed to a collection of them) is never concatenated with anything
+ * because of operator precedence.)  The operand of some types of node is
+ * a literal string; for others, it is a node leading into a sub-FSM.  In
+ * particular, the operand of a BRANCH node is the first node of the branch.
+ * (NB this is *not* a tree structure:  the tail of the branch connects
+ * to the thing following the set of BRANCHes.)  The opcodes are:
+ */
+
+// definition   number  opnd?   meaning
+#define END     0               // no   End of program.
+#define BOL     1               // no   Match "" at beginning of line.
+#define EOL     2               // no   Match "" at end of line.
+#define ANY     3               // no   Match any one character.
+#define ANYOF   4               // str  Match any character in this string.
+#define ANYBUT  5               // str  Match any character not in this
+                                // string.
+#define BRANCH  6               // node Match this alternative, or the
+                                // next...
+#define BACK    7               // no   Match "", "next" ptr points backward.
+#define EXACTLY 8               // str  Match this string.
+#define NOTHING 9               // no   Match empty string.
+#define STAR    10              // node Match this (simple) thing 0 or more
+                                // times.
+#define PLUS    11              // node Match this (simple) thing 1 or more
+                                // times.
+#define OPEN    20              // no   Mark this point in input as start of
+                                // #n.
+// OPEN+1 is number 1, etc.
+#define CLOSE   30              // no   Analogous to OPEN.
+
+/*
+ * Opcode notes:
+ *
+ * BRANCH       The set of branches constituting a single choice are hooked
+ *              together with their "next" pointers, since precedence prevents
+ *              anything being concatenated to any individual branch.  The
+ *              "next" pointer of the last BRANCH in a choice points to the
+ *              thing following the whole choice.  This is also where the
+ *              final "next" pointer of each individual branch points; each
+ *              branch starts with the operand node of a BRANCH node.
+ *
+ * BACK         Normal "next" pointers all implicitly point forward; BACK
+ *              exists to make loop structures possible.
+ *
+ * STAR,PLUS    '?', and complex '*' and '+', are implemented as circular
+ *              BRANCH structures using BACK.  Simple cases (one character
+ *              per match) are implemented with STAR and PLUS for speed
+ *              and to minimize recursive plunges.
+ *
+ * OPEN,CLOSE   ...are numbered at compile time.
+ */
+
+/*
+ * A node is one char of opcode followed by two chars of "next" pointer.
+ * "Next" pointers are stored as two 8-bit pieces, high order first.  The
+ * value is a positive offset from the opcode of the node containing it.
+ * An operand, if any, simply follows the node.  (Note that much of the
+ * code generation knows about this implicit relationship.)
+ *
+ * Using two bytes for the "next" pointer is vast overkill for most things,
+ * but allows patterns to get big without disasters.
+ */
+
+#define OP(p)           (*(p))
+#define NEXT(p)         (((*((p)+1)&0377)<<8) + (*((p)+2)&0377))
+#define OPERAND(p)      ((p) + 3)
+
+const unsigned char MAGIC = 0234;
+/*
+ * Utility definitions.
+ */
+
+#define UCHARAT(p)      ((const unsigned char*)(p))[0]
+
+
+#define FAIL(m) { regerror(m); return(0); }
+#define ISMULT(c)       ((c) == '*' || (c) == '+' || (c) == '?')
+#define META    "^$.[()|?+*\\"
+
+
+/*
+ * Flags to be passed up and down.
+ */
+#define HASWIDTH        01      // Known never to match null string.
+#define SIMPLE          02      // Simple enough to be STAR/PLUS operand.
+#define SPSTART         04      // Starts with * or +.
+#define WORST           0       // Worst case.
+
+
+
+/////////////////////////////////////////////////////////////////////////
+//
+//  COMPILE AND ASSOCIATED FUNCTIONS
+//
+/////////////////////////////////////////////////////////////////////////
+
+
+/*
+ * Global work variables for compile().
+ */
+static const char* regparse;    // Input-scan pointer.
+static       int   regnpar;     // () count.
+static       char  regdummy;
+static       char* regcode;     // Code-emit pointer; &regdummy = don't.
+static       long  regsize;     // Code size.
+
+/*
+ * Forward declarations for compile()'s friends.
+ */
+// #ifndef static
+// #define      static  static
+// #endif
+static       char* reg (int, int*);
+static       char* regbranch (int*);
+static       char* regpiece (int*);
+static       char* regatom (int*);
+static       char* regnode (char);
+static const char* regnext (register const char*);
+static       char* regnext (register char*);
+static void        regc (unsigned char);
+static void        reginsert (char, char*);
+static void        regtail (char*, const char*);
+static void        regoptail (char*, const char*);
+
+#ifdef STRCSPN
+static int strcspn ();
+#endif
+
+
+
+/*
+ * We can't allocate space until we know how big the compiled form will be,
+ * but we can't compile it (and thus know how big it is) until we've got a
+ * place to put the code.  So we cheat:  we compile it twice, once with code
+ * generation turned off and size counting turned on, and once "for real".
+ * This also means that we don't allocate space until we are sure that the
+ * thing really will compile successfully, and we never have to move the
+ * code and thus invalidate pointers into it.  (Note that it has to be in
+ * one piece because free() must be able to free it all.)
+ *
+ * Beware that the optimization-preparation code in here knows about some
+ * of the structure of the compiled regexp.
+ */
+
+
+// compile -- compile a regular expression into internal code
+// for later pattern matching.
+
+bool RegularExpression::compile (const char* exp) {
+    register const char* scan;
+    register const char* longest;
+    register unsigned long len;
+             int         flags;
+
+    if (exp == 0) {
+      //RAISE Error, SYM(RegularExpression), SYM(No_Expr),
+      printf ("RegularExpression::compile(): No expression supplied.\n");
+      return false;
+    }
+
+    // First pass: determine size, legality.
+    regparse = exp;
+    regnpar = 1;
+    regsize = 0L;
+    regcode = &regdummy;
+    regc(MAGIC);
+    if(!reg(0, &flags))
+      {
+        printf ("RegularExpression::compile(): Error in compile.\n");
+        return false;
+      }
+    this->startp[0] = this->endp[0] = this->searchstring = 0;
+
+    // Small enough for pointer-storage convention? 
+    if (regsize >= 32767L) {    // Probably could be 65535L. 
+      //RAISE Error, SYM(RegularExpression), SYM(Expr_Too_Big),
+      printf ("RegularExpression::compile(): Expression too big.\n");
+      return false;
+    }
+
+    // Allocate space. 
+//#ifndef WIN32
+    if (this->program != 0) delete [] this->program;  
+//#endif
+    this->program = new char[regsize];
+    this->progsize = (int) regsize;
+
+    if (this->program == 0) {
+      //RAISE Error, SYM(RegularExpression), SYM(Out_Of_Memory),
+      printf ("RegularExpression::compile(): Out of memory.\n"); 
+      return false;
+    }
+
+    // Second pass: emit code.
+    regparse = exp;
+    regnpar = 1;
+    regcode = this->program;
+    regc(MAGIC);
+    reg(0, &flags);
+
+    // Dig out information for optimizations.
+    this->regstart = '\0';              // Worst-case defaults.
+    this->reganch = 0;
+    this->regmust = 0;
+    this->regmlen = 0;
+    scan = this->program + 1;   // First BRANCH.
+    if (OP(regnext(scan)) == END) {     // Only one top-level choice.
+        scan = OPERAND(scan);
+
+        // Starting-point info.
+        if (OP(scan) == EXACTLY)
+            this->regstart = *OPERAND(scan);
+        else if (OP(scan) == BOL)
+            this->reganch++;
+
+         //
+         // If there's something expensive in the r.e., find the longest
+         // literal string that must appear and make it the regmust.  Resolve
+         // ties in favor of later strings, since the regstart check works
+         // with the beginning of the r.e. and avoiding duplication
+         // strengthens checking.  Not a strong reason, but sufficient in the
+         // absence of others. 
+         //
+        if (flags & SPSTART) {
+            longest = 0;
+            len = 0;
+            for (; scan != 0; scan = regnext(scan))
+                if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len) {
+                    longest = OPERAND(scan);
+                    len = int(strlen(OPERAND(scan)));
+                }
+            this->regmust = longest;
+            this->regmlen = len;
+        }
+    }
+    return true;
+}
+
+
+/*
+ - reg - regular expression, i.e. main body or parenthesized thing
+ *
+ * Caller must absorb opening parenthesis.
+ *
+ * Combining parenthesis handling with the base level of regular expression
+ * is a trifle forced, but the need to tie the tails of the branches to what
+ * follows makes it hard to avoid.
+ */
+static char* reg (int paren, int *flagp) {
+    register char* ret;
+    register char* br;
+    register char* ender;
+    register int   parno =0;
+             int   flags;
+
+    *flagp = HASWIDTH;          // Tentatively.
+
+    // Make an OPEN node, if parenthesized.
+    if (paren) {
+        if (regnpar >= RegularExpressionNSUBEXP) {
+          //RAISE Error, SYM(RegularExpression), SYM(Too_Many_Parens),
+          printf ("RegularExpression::compile(): Too many parentheses.\n");
+          return 0;
+        }
+        parno = regnpar;
+        regnpar++;
+        ret = regnode(OPEN + parno);
+    }
+    else
+        ret = 0;
+
+    // Pick up the branches, linking them together.
+    br = regbranch(&flags);
+    if (br == 0)
+        return (0);
+    if (ret != 0)
+        regtail(ret, br);       // OPEN -> first.
+    else
+        ret = br;
+    if (!(flags & HASWIDTH))
+        *flagp &= ~HASWIDTH;
+    *flagp |= flags & SPSTART;
+    while (*regparse == '|') {
+        regparse++;
+        br = regbranch(&flags);
+        if (br == 0)
+            return (0);
+        regtail(ret, br);       // BRANCH -> BRANCH.
+        if (!(flags & HASWIDTH))
+            *flagp &= ~HASWIDTH;
+        *flagp |= flags & SPSTART;
+      }
+
+    // Make a closing node, and hook it on the end.
+    ender = regnode((paren) ? CLOSE + parno : END);
+    regtail(ret, ender);
+
+    // Hook the tails of the branches to the closing node.
+    for (br = ret; br != 0; br = regnext(br))
+        regoptail(br, ender);
+
+    // Check for proper termination.
+    if (paren && *regparse++ != ')') {
+        //RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
+        printf ("RegularExpression::compile(): Unmatched parentheses.\n");
+        return 0;
+    }
+    else if (!paren && *regparse != '\0') {
+        if (*regparse == ')') {
+            //RAISE Error, SYM(RegularExpression), SYM(Unmatched_Parens),
+            printf ("RegularExpression::compile(): Unmatched parentheses.\n");
+            return 0;
+        }
+        else {
+            //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+            printf ("RegularExpression::compile(): Internal error.\n");
+            return 0;
+        }
+        // NOTREACHED
+    }
+    return (ret);
+}
+
+
+/*
+ - regbranch - one alternative of an | operator
+ *
+ * Implements the concatenation operator.
+ */
+static char* regbranch (int *flagp) {
+    register char* ret;
+    register char* chain;
+    register char* latest;
+    int                  flags;
+
+    *flagp = WORST;             // Tentatively.
+
+    ret = regnode(BRANCH);
+    chain = 0;
+    while (*regparse != '\0' && *regparse != '|' && *regparse != ')') {
+        latest = regpiece(&flags);
+        if (latest == 0)
+            return (0);
+        *flagp |= flags & HASWIDTH;
+        if (chain == 0) // First piece.
+            *flagp |= flags & SPSTART;
+        else
+            regtail(chain, latest);
+        chain = latest;
+    }
+    if (chain == 0)             // Loop ran zero times.
+        regnode(NOTHING);
+
+    return (ret);
+}
+
+
+/*
+ - regpiece - something followed by possible [*+?]
+ *
+ * Note that the branching code sequences used for ? and the general cases
+ * of * and + are somewhat optimized:  they use the same NOTHING node as
+ * both the endmarker for their branch list and the body of the last branch.
+ * It might seem that this node could be dispensed with entirely, but the
+ * endmarker role is not redundant.
+ */
+static char* regpiece (int *flagp) {
+    register char* ret;
+    register char  op;
+    register char* next;
+    int            flags;
+
+    ret = regatom(&flags);
+    if (ret == 0)
+        return (0);
+
+    op = *regparse;
+    if (!ISMULT(op)) {
+        *flagp = flags;
+        return (ret);
+    }
+
+    if (!(flags & HASWIDTH) && op != '?') {
+        //RAISE Error, SYM(RegularExpression), SYM(Empty_Operand),
+        printf ("RegularExpression::compile() : *+ operand could be empty.\n");
+        return 0;
+    }
+    *flagp = (op != '+') ? (WORST | SPSTART) : (WORST | HASWIDTH);
+
+    if (op == '*' && (flags & SIMPLE))
+        reginsert(STAR, ret);
+    else if (op == '*') {
+        // Emit x* as (x&|), where & means "self".
+        reginsert(BRANCH, ret); // Either x
+        regoptail(ret, regnode(BACK));  // and loop
+        regoptail(ret, ret);    // back
+        regtail(ret, regnode(BRANCH));  // or
+        regtail(ret, regnode(NOTHING)); // null.
+    }
+    else if (op == '+' && (flags & SIMPLE))
+        reginsert(PLUS, ret);
+    else if (op == '+') {
+        // Emit x+ as x(&|), where & means "self".
+        next = regnode(BRANCH); // Either
+        regtail(ret, next);
+        regtail(regnode(BACK), ret);    // loop back
+        regtail(next, regnode(BRANCH)); // or
+        regtail(ret, regnode(NOTHING)); // null.
+    }
+    else if (op == '?') {
+        // Emit x? as (x|)
+        reginsert(BRANCH, ret); // Either x
+        regtail(ret, regnode(BRANCH));  // or
+        next = regnode(NOTHING);// null.
+        regtail(ret, next);
+        regoptail(ret, next);
+    }
+    regparse++;
+    if (ISMULT(*regparse)) {
+        //RAISE Error, SYM(RegularExpression), SYM(Nested_Operand),
+        printf ("RegularExpression::compile(): Nested *?+.\n");
+        return 0;
+    }
+    return (ret);
+}
+
+
+/*
+ - regatom - the lowest level
+ *
+ * Optimization:  gobbles an entire sequence of ordinary characters so that
+ * it can turn them into a single node, which is smaller to store and
+ * faster to run.  Backslashed characters are exceptions, each becoming a
+ * separate node; the code is simpler that way and it's not worth fixing.
+ */
+static char* regatom (int *flagp) {
+    register char* ret;
+             int   flags;
+
+    *flagp = WORST;             // Tentatively.
+
+    switch (*regparse++) {
+        case '^':
+            ret = regnode(BOL);
+            break;
+        case '$':
+            ret = regnode(EOL);
+            break;
+        case '.':
+            ret = regnode(ANY);
+            *flagp |= HASWIDTH | SIMPLE;
+            break;
+        case '[':{
+                register int    rxpclass;
+                register int    rxpclassend;
+
+                if (*regparse == '^') { // Complement of range.
+                    ret = regnode(ANYBUT);
+                    regparse++;
+                }
+                else
+                    ret = regnode(ANYOF);
+                if (*regparse == ']' || *regparse == '-')
+                    regc(*regparse++);
+                while (*regparse != '\0' && *regparse != ']') {
+                    if (*regparse == '-') {
+                        regparse++;
+                        if (*regparse == ']' || *regparse == '\0')
+                            regc('-');
+                        else {
+                            rxpclass = UCHARAT(regparse - 2) + 1;
+                            rxpclassend = UCHARAT(regparse);
+                            if (rxpclass > rxpclassend + 1) {
+                               //RAISE Error, SYM(RegularExpression), SYM(Invalid_Range),
+                               printf ("RegularExpression::compile(): Invalid range in [].\n");
+                               return 0;
+                            }
+                            for (; rxpclass <= rxpclassend; rxpclass++)
+                                regc(rxpclass);
+                            regparse++;
+                        }
+                    }
+                    else
+                        regc(*regparse++);
+                }
+                regc('\0');
+                if (*regparse != ']') {
+                    //RAISE Error, SYM(RegularExpression), SYM(Unmatched_Bracket),
+                    printf ("RegularExpression::compile(): Unmatched [].\n");
+                    return 0;
+                }
+                regparse++;
+                *flagp |= HASWIDTH | SIMPLE;
+            }
+            break;
+        case '(':
+            ret = reg(1, &flags);
+            if (ret == 0)
+                return (0);
+            *flagp |= flags & (HASWIDTH | SPSTART);
+            break;
+        case '\0':
+        case '|':
+        case ')':
+            //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+            printf ("RegularExpression::compile(): Internal error.\n"); // Never here
+            return 0;
+        case '?':
+        case '+':
+        case '*':
+            //RAISE Error, SYM(RegularExpression), SYM(No_Operand),
+            printf ("RegularExpression::compile(): ?+* follows nothing.\n");
+            return 0;
+        case '\\':
+            if (*regparse == '\0') {
+                //RAISE Error, SYM(RegularExpression), SYM(Trailing_Backslash),
+                printf ("RegularExpression::compile(): Trailing backslash.\n");
+                return 0;
+            }
+            ret = regnode(EXACTLY);
+            regc(*regparse++);
+            regc('\0');
+            *flagp |= HASWIDTH | SIMPLE;
+            break;
+        default:{
+                register int    len;
+                register char   ender;
+
+                regparse--;
+                len = int(strcspn(regparse, META));
+                if (len <= 0) {
+                    //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+                    printf ("RegularExpression::compile(): Internal error.\n");
+                    return 0;
+                }
+                ender = *(regparse + len);
+                if (len > 1 && ISMULT(ender))
+                    len--;      // Back off clear of ?+* operand.
+                *flagp |= HASWIDTH;
+                if (len == 1)
+                    *flagp |= SIMPLE;
+                ret = regnode(EXACTLY);
+                while (len > 0) {
+                    regc(*regparse++);
+                    len--;
+                }
+                regc('\0');
+            }
+            break;
+    }
+    return (ret);
+}
+
+
+/*
+ - regnode - emit a node
+   Location.
+ */
+static char* regnode (char op) {
+    register char* ret;
+    register char* ptr;
+
+    ret = regcode;
+    if (ret == &regdummy) {
+        regsize += 3;
+        return (ret);
+    }
+
+    ptr = ret;
+    *ptr++ = op;
+    *ptr++ = '\0';              // Null "next" pointer.
+    *ptr++ = '\0';
+    regcode = ptr;
+
+    return (ret);
+}
+
+
+/*
+ - regc - emit (if appropriate) a byte of code
+ */
+static void regc (unsigned char b) {
+    if (regcode != &regdummy)
+        *regcode++ = b;
+    else
+        regsize++;
+}
+
+
+/*
+ - reginsert - insert an operator in front of already-emitted operand
+ *
+ * Means relocating the operand.
+ */
+static void reginsert (char op, char* opnd) {
+    register char* src;
+    register char* dst;
+    register char* place;
+
+    if (regcode == &regdummy) {
+        regsize += 3;
+        return;
+    }
+
+    src = regcode;
+    regcode += 3;
+    dst = regcode;
+    while (src > opnd)
+        *--dst = *--src;
+
+    place = opnd;               // Op node, where operand used to be.
+    *place++ = op;
+    *place++ = '\0';
+    *place++ = '\0';
+}
+
+
+/*
+ - regtail - set the next-pointer at the end of a node chain
+ */
+static void regtail (char* p, const char* val) {
+    register char* scan;
+    register char* temp;
+    register int   offset;
+
+    if (p == &regdummy)
+        return;
+
+    // Find last node.
+    scan = p;
+    for (;;) {
+        temp = regnext(scan);
+        if (temp == 0)
+            break;
+        scan = temp;
+    }
+
+    if (OP(scan) == BACK)
+        offset = int(scan - val);
+    else
+        offset = int(val - scan);
+    *(scan + 1) = (offset >> 8) & 0377;
+    *(scan + 2) = offset & 0377;
+}
+
+
+/*
+ - regoptail - regtail on operand of first argument; nop if operandless
+ */
+static void regoptail (char* p, const char* val) {
+    // "Operandless" and "op != BRANCH" are synonymous in practice.
+    if (p == 0 || p == &regdummy || OP(p) != BRANCH)
+        return;
+    regtail(OPERAND(p), val);
+}
+
+
+
+////////////////////////////////////////////////////////////////////////
+// 
+//  find and friends
+// 
+////////////////////////////////////////////////////////////////////////
+
+
+/*
+ * Global work variables for find().
+ */
+static const char*  reginput;   // String-input pointer.
+static const char*  regbol;     // Beginning of input, for ^ check.
+static const char* *regstartp;  // Pointer to startp array.
+static const char* *regendp;    // Ditto for endp.
+
+/*
+ * Forwards.
+ */
+static int regtry (const char*, const char* *,
+                   const char* *, const char*);
+static int regmatch (const char*);
+static int regrepeat (const char*);
+
+#ifdef DEBUG
+int          regnarrate = 0;
+void         regdump ();
+static char* regprop ();
+#endif
+
+bool RegularExpression::find (kwsys_std::string const& s) 
+{
+  return find(s.c_str());
+}
+
+
+
+// find -- Matches the regular expression to the given string.
+// Returns true if found, and sets start and end indexes accordingly.
+
+bool RegularExpression::find (const char* string) {
+    register const char* s;
+
+    this->searchstring = string;
+
+    if (!this->program)
+      {
+      return false;
+      }
+    
+    // Check validity of program.
+    if (UCHARAT(this->program) != MAGIC) {
+        //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+        printf ("RegularExpression::find(): Compiled regular expression corrupted.\n");
+        return 0;
+    }
+    
+    // If there is a "must appear" string, look for it.
+    if (this->regmust != 0) {
+        s = string;
+        while ((s = strchr(s, this->regmust[0])) != 0) {
+            if (strncmp(s, this->regmust, this->regmlen) == 0)
+                break;          // Found it.
+            s++;
+        }
+        if (s == 0)             // Not present.
+            return (0);
+    }
+     
+    // Mark beginning of line for ^ .
+    regbol = string;
+
+    // Simplest case:  anchored match need be tried only once.
+    if (this->reganch)
+        return (regtry(string, this->startp, this->endp, this->program) != 0);
+    
+    // Messy cases:  unanchored match.
+    s = string;
+    if (this->regstart != '\0')
+        // We know what char it must start with.
+        while ((s = strchr(s, this->regstart)) != 0) {
+            if (regtry(s, this->startp, this->endp, this->program))
+                return (1);
+            s++;
+          
+        }
+    else
+        // We don't -- general case.
+        do {
+            if (regtry(s, this->startp, this->endp, this->program))
+                return (1);
+        } while (*s++ != '\0');
+    
+    // Failure.
+    return (0);
+}
+
+
+/*
+ - regtry - try match at specific point
+   0 failure, 1 success
+ */
+static int regtry (const char* string, const char* *start,
+                   const char* *end, const char* prog) {
+    register       int    i;
+    register const char* *sp1;
+    register const char* *ep;
+
+    reginput = string;
+    regstartp = start;
+    regendp = end;
+
+    sp1 = start;
+    ep = end;
+    for (i = RegularExpressionNSUBEXP; i > 0; i--) {
+        *sp1++ = 0;
+        *ep++ = 0;
+    }
+    if (regmatch(prog + 1)) {
+        start[0] = string;
+        end[0] = reginput;
+        return (1);
+    }
+    else
+        return (0);
+}
+
+
+/*
+ - regmatch - main matching routine
+ *
+ * Conceptually the strategy is simple:  check to see whether the current
+ * node matches, call self recursively to see whether the rest matches,
+ * and then act accordingly.  In practice we make some effort to avoid
+ * recursion, in particular by going through "ordinary" nodes (that don't
+ * need to know whether the rest of the match failed) by a loop instead of
+ * by recursion.
+ * 0 failure, 1 success
+ */
+static int regmatch (const char* prog) {
+    register const char* scan;  // Current node.
+             const char* next;  // Next node.
+
+    scan = prog;
+
+    while (scan != 0) {
+
+        next = regnext(scan);
+
+        switch (OP(scan)) {
+            case BOL:
+                if (reginput != regbol)
+                    return (0);
+                break;
+            case EOL:
+                if (*reginput != '\0')
+                    return (0);
+                break;
+            case ANY:
+                if (*reginput == '\0')
+                    return (0);
+                reginput++;
+                break;
+            case EXACTLY:{
+                    register int         len;
+                    register const char* opnd;
+
+                    opnd = OPERAND(scan);
+                    // Inline the first character, for speed.
+                    if (*opnd != *reginput)
+                        return (0);
+                    len = int(strlen(opnd));
+                    if (len > 1 && strncmp(opnd, reginput, len) != 0)
+                        return (0);
+                    reginput += len;
+                }
+                break;
+            case ANYOF:
+                if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == 0)
+                    return (0);
+                reginput++;
+                break;
+            case ANYBUT:
+                if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != 0)
+                    return (0);
+                reginput++;
+                break;
+            case NOTHING:
+                break;
+            case BACK:
+                break;
+            case OPEN + 1:
+            case OPEN + 2:
+            case OPEN + 3:
+            case OPEN + 4:
+            case OPEN + 5:
+            case OPEN + 6:
+            case OPEN + 7:
+            case OPEN + 8:
+            case OPEN + 9:{
+                    register       int    no;
+                    register const char* save;
+
+                    no = OP(scan) - OPEN;
+                    save = reginput;
+
+                    if (regmatch(next)) {
+
+                        //
+                        // Don't set startp if some later invocation of the
+                        // same parentheses already has. 
+                        //
+                        if (regstartp[no] == 0)
+                            regstartp[no] = save;
+                        return (1);
+                    }
+                    else
+                        return (0);
+                }
+//              break;
+            case CLOSE + 1:
+            case CLOSE + 2:
+            case CLOSE + 3:
+            case CLOSE + 4:
+            case CLOSE + 5:
+            case CLOSE + 6:
+            case CLOSE + 7:
+            case CLOSE + 8:
+            case CLOSE + 9:{
+                    register       int    no;
+                    register const char* save;
+
+                    no = OP(scan) - CLOSE;
+                    save = reginput;
+
+                    if (regmatch(next)) {
+
+                        //
+                        // Don't set endp if some later invocation of the
+                        // same parentheses already has. 
+                        //
+                        if (regendp[no] == 0)
+                            regendp[no] = save;
+                        return (1);
+                    }
+                    else
+                        return (0);
+                }
+//              break;
+            case BRANCH:{
+              
+              register const char* save;
+
+                    if (OP(next) != BRANCH)     // No choice.
+                        next = OPERAND(scan);   // Avoid recursion.
+                    else {
+                        do {
+                            save = reginput;
+                            if (regmatch(OPERAND(scan)))
+                                return (1);
+                            reginput = save;
+                            scan = regnext(scan);
+                        } while (scan != 0 && OP(scan) == BRANCH);
+                        return (0);
+                        // NOTREACHED
+                    }
+                }
+                break;
+            case STAR:
+            case PLUS:{
+              register char   nextch;
+                    register int        no;
+                    register const char* save;
+                    register int        min_no;
+
+                    //
+                    // Lookahead to avoid useless match attempts when we know
+                    // what character comes next. 
+                    //
+                    nextch = '\0';
+                    if (OP(next) == EXACTLY)
+                        nextch = *OPERAND(next);
+                    min_no = (OP(scan) == STAR) ? 0 : 1;
+                    save = reginput;
+                    no = regrepeat(OPERAND(scan));
+                    while (no >= min_no) {
+                        // If it could work, try it.
+                        if (nextch == '\0' || *reginput == nextch)
+                            if (regmatch(next))
+                                return (1);
+                        // Couldn't or didn't -- back up.
+                        no--;
+                        reginput = save + no;
+                    }
+                    return (0);
+                }
+//              break;
+            case END:
+                return (1);     // Success!
+
+            default:
+                //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+                printf ("RegularExpression::find(): Internal error -- memory corrupted.\n");
+                return 0;
+        }
+        scan = next;
+    }
+
+    // 
+    //  We get here only if there's trouble -- normally "case END" is the
+    //  terminating point. 
+    // 
+    //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+    printf ("RegularExpression::find(): Internal error -- corrupted pointers.\n");
+    return (0);
+}
+
+
+/*
+ - regrepeat - repeatedly match something simple, report how many
+ */
+static int regrepeat (const char* p) {
+    register       int   count = 0;
+    register const char* scan;
+    register const char* opnd;
+
+    scan = reginput;
+    opnd = OPERAND(p);
+    switch (OP(p)) {
+        case ANY:
+            count = int(strlen(scan));
+            scan += count;
+            break;
+        case EXACTLY:
+            while (*opnd == *scan) {
+                count++;
+                scan++;
+            }
+            break;
+        case ANYOF:
+            while (*scan != '\0' && strchr(opnd, *scan) != 0) {
+                count++;
+                scan++;
+            }
+            break;
+        case ANYBUT:
+            while (*scan != '\0' && strchr(opnd, *scan) == 0) {
+                count++;
+                scan++;
+            }
+            break;
+        default:                // Oh dear.  Called inappropriately.
+            //RAISE Error, SYM(RegularExpression), SYM(Internal_Error),
+            printf ("cm RegularExpression::find(): Internal error.\n");
+            return 0;
+    }
+    reginput = scan;
+    return (count);
+}
+
+
+/*
+ - regnext - dig the "next" pointer out of a node
+ */
+static const char* regnext (register const char* p) {
+    register int offset;
+
+    if (p == &regdummy)
+        return (0);
+
+    offset = NEXT(p);
+    if (offset == 0)
+        return (0);
+
+    if (OP(p) == BACK)
+        return (p - offset);
+    else
+        return (p + offset);
+}
+
+
+static char* regnext (register char* p) {
+    register int offset;
+
+    if (p == &regdummy)
+        return (0);
+
+    offset = NEXT(p);
+    if (offset == 0)
+        return (0);
+
+    if (OP(p) == BACK)
+        return (p - offset);
+    else
+        return (p + offset);
+}
+
+} // namespace KWSYS_NAMESPACE

+ 385 - 0
Source/kwsys/RegularExpression.hxx.in

@@ -0,0 +1,385 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See http://www.cmake.org/HTML/Copyright.html 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.
+
+=========================================================================*/
+// Original Copyright notice:
+// Copyright (C) 1991 Texas Instruments Incorporated.
+//
+// Permission is granted to any individual or institution to use, copy, modify,
+// and distribute this software, provided that this complete copyright and
+// permission notice is maintained, intact, in all copies and supporting
+// documentation.
+//
+// Texas Instruments Incorporated provides this software "as is" without
+// express or implied warranty.
+//
+// Created: MNF 06/13/89  Initial Design and Implementation
+// Updated: LGO 08/09/89  Inherit from Generic
+// Updated: MBN 09/07/89  Added conditional exception handling
+// Updated: MBN 12/15/89  Sprinkled "const" qualifiers all over the place!
+// Updated: DLS 03/22/91  New lite version
+//
+
+#ifndef @KWSYS_NAMESPACE@_RegularExpression_hxx
+#define @KWSYS_NAMESPACE@_RegularExpression_hxx
+
+#include <@KWSYS_NAMESPACE@/StandardIncludes.hxx>
+
+#include <string>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+const int RegularExpressionNSUBEXP = 10;
+
+/** \class cmRegularExpression
+ * \brief Implements pattern matching with regular expressions.
+ *
+ * This is the header file for the regular expression class.  An object of
+ * this class contains a regular expression, in a special "compiled" format.
+ * This compiled format consists of several slots all kept as the objects
+ * private data.  The cmRegularExpression class provides a convenient way to
+ * represent regular expressions.  It makes it easy to search for the same
+ * regular expression in many different strings without having to compile a
+ * string to regular expression format more than necessary.
+ *
+ * This class implements pattern matching via regular expressions.
+ * A regular expression allows a programmer to specify  complex
+ * patterns  that  can  be searched for and matched against the
+ * character string of a string object. In its simplest form, a
+ * regular  expression  is  a  sequence  of  characters used to
+ * search for exact character matches. However, many times  the
+ * exact  sequence to be found is not known, or only a match at
+ * the beginning or end of a string is desired. The cmRegularExpression regu-
+ * lar  expression  class implements regular expression pattern
+ * matching as is found and implemented in many  UNIX  commands
+ * and utilities.
+ *
+ * Example: The perl code
+ * 
+ *    $filename =~ m"([a-z]+)\.cc";
+ *    print $1;
+ *    
+ * Is written as follows in C++
+ *
+ *    cmRegularExpression re("([a-z]+)\\.cc");
+ *    re.find(filename);
+ *    cerr << re.match(1);
+ *
+ *
+ * The regular expression class provides a convenient mechanism
+ * for  specifying  and  manipulating  regular expressions. The
+ * regular expression object allows specification of such  pat-
+ * terns  by using the following regular expression metacharac-
+ * ters:
+ *
+ *  ^        Matches at beginning of a line
+ *
+ *  $        Matches at end of a line
+ *
+ * .         Matches any single character
+ *
+ * [ ]       Matches any character(s) inside the brackets
+ *
+ * [^ ]      Matches any character(s) not inside the brackets
+ *
+ *  -        Matches any character in range on either side of a dash
+ *
+ *  *        Matches preceding pattern zero or more times
+ *
+ *  +        Matches preceding pattern one or more times
+ *
+ *  ?        Matches preceding pattern zero or once only
+ *
+ * ()        Saves a matched expression and uses it in a  later match
+ *
+ * Note that more than one of these metacharacters can be  used
+ * in  a  single  regular expression in order to create complex
+ * search patterns. For example, the pattern [^ab1-9]  says  to
+ * match  any  character  sequence that does not begin with the
+ * characters "ab"  followed  by  numbers  in  the  series  one
+ * through nine.
+ *
+ * There are three constructors for cmRegularExpression.  One just creates an
+ * empty cmRegularExpression object.  Another creates a cmRegularExpression
+ * object and initializes it with a regular expression that is given in the
+ * form of a char*.  The third takes a reference to a cmRegularExpression
+ * object as an argument and creates an object initialized with the
+ * information from the given cmRegularExpression object.
+ *
+ * The  find  member function  finds   the  first  occurence   of  the regualr
+ * expression of that object in the string given to find as an argument.  Find
+ * returns a boolean, and  if true,  mutates  the private  data appropriately.
+ * Find sets pointers to the beginning and end of  the thing last  found, they
+ * are pointers into the actual string  that was searched.   The start and end
+ * member functions return indicies  into the searched string that  correspond
+ * to the beginning   and  end pointers  respectively.   The    compile member
+ * function takes a char* and puts the  compiled version of the char* argument
+ * into the object's private data fields.  The == and  != operators only check
+ * the  to see  if   the compiled  regular  expression   is the same, and  the
+ * deep_equal functions also checks  to see if the  start and end pointers are
+ * the same.  The is_valid  function returns false if  program is set to NULL,
+ * (i.e. there is no valid compiled exression).  The set_invalid function sets
+ * the  program to NULL  (Warning: this deletes the compiled  expression). The
+ * following examples may help clarify regular expression usage:
+ *
+ *   *  The regular expression  "^hello" matches  a "hello"  only at  the
+ *      beginning of a  line.  It would match "hello  there" but not "hi,
+ *      hello there".
+ *
+ *   *  The regular expression "long$" matches a  "long"  only at the end
+ *      of a line. It would match "so long\0", but not "long ago".
+ *
+ *   *  The regular expression "t..t..g"  will match anything that  has a
+ *      "t" then any two characters, another "t", any  two characters and
+ *      then a "g".   It will match  "testing", or "test again" but would
+ *      not match "toasting"
+ *
+ *   *  The regular  expression "[1-9ab]" matches any  number one through
+ *      nine, and the characters  "a" and  "b".  It would match "hello 1"
+ *      or "begin", but would not match "no-match".
+ *
+ *   *  The  regular expression "[^1-9ab]"  matches any character that is
+ *      not a number one  through nine, or  an "a" or "b".   It would NOT
+ *      match "hello 1" or "begin", but would match "no-match".
+ *
+ *   *  The regular expression "br* " matches  something that begins with
+ *      a "b", is followed by zero or more "r"s, and ends in a space.  It
+ *      would match "brrrrr ", and "b ", but would not match "brrh ".
+ *
+ *   *  The regular expression "br+ " matches something  that begins with
+ *      a "b", is followed by one or more "r"s, and ends in  a space.  It
+ *      would match "brrrrr ",  and  "br ", but would not  match "b  " or
+ *      "brrh ".
+ *
+ *   *  The regular expression "br? " matches  something that begins with
+ *      a "b", is followed by zero or one "r"s, and ends in  a space.  It
+ *      would  match  "br ", and "b  ", but would not match  "brrrr "  or
+ *      "brrh ".
+ *
+ *   *  The regular expression "(..p)b" matches  something ending with pb
+ *      and beginning with whatever the two characters before the first p
+ *      encounterd in the line were.  It would find  "repb" in "rep drepa
+ *      qrepb".  The regular expression "(..p)a"  would find "repa qrepb"
+ *      in "rep drepa qrepb"
+ *
+ *   *  The regular expression "d(..p)" matches something ending  with p,
+ *      beginning with d, and having  two characters  in between that are
+ *      the same as the two characters before  the first p  encounterd in
+ *      the line.  It would match "drepa qrepb" in "rep drepa qrepb".
+ *
+ */
+class RegularExpression 
+{
+public:
+  /**
+   * Instantiate RegularExpression with program=NULL.
+   */
+  inline RegularExpression ();        
+
+  /**
+   * Instantiate RegularExpression with compiled char*.
+   */
+  inline RegularExpression (char const*);
+  
+  /**
+   * Instantiate RegularExpression as a copy of another regular expression.
+   */
+  RegularExpression (RegularExpression const&);
+
+  /**
+   * Destructor.
+   */
+  inline ~RegularExpression();
+
+  /**
+   * Compile a regular expression into internal code
+   * for later pattern matching.
+   */
+  bool compile (char const*);
+
+  /**
+   * Matches the regular expression to the given string.
+   * Returns true if found, and sets start and end indexes accordingly.
+   */
+  bool find (char const*);
+
+  /**
+   * Matches the regular expression to the given std string.
+   * Returns true if found, and sets start and end indexes accordingly.
+   */
+  bool find (kwsys_std::string const&);               
+
+  /**
+   * Index to start of first find.
+   */
+  inline kwsys_std::string::size_type start() const;
+
+  /**
+   * Index to end of first find.
+   */
+  inline kwsys_std::string::size_type end() const;
+
+  /**
+   * Returns true if two regular expressions have the same
+   * compiled program for pattern matching.
+   */
+  bool operator== (RegularExpression const&) const;
+
+  /**
+   * Returns true if two regular expressions have different
+   * compiled program for pattern matching.
+   */
+  inline bool operator!= (RegularExpression const&) const;
+
+  /**
+   * Returns true if have the same compiled regular expressions
+   * and the same start and end pointers.
+   */
+  bool deep_equal (RegularExpression const&) const;
+  
+  /**
+   * True if the compiled regexp is valid.
+   */
+  inline bool is_valid() const;
+
+  /**
+   * Marks the regular expression as invalid.
+   */
+  inline void set_invalid();            
+
+  /**
+   * Destructor.
+   */
+  // awf added
+  kwsys_std::string::size_type start(int n) const;
+  kwsys_std::string::size_type end(int n) const;
+  kwsys_std::string match(int n) const;
+  
+private: 
+  const char* startp[RegularExpressionNSUBEXP];
+  const char* endp[RegularExpressionNSUBEXP];
+  char  regstart;                       // Internal use only
+  char  reganch;                        // Internal use only
+  const char* regmust;                  // Internal use only
+  int   regmlen;                        // Internal use only
+  char* program;   
+  int   progsize;
+  const char* searchstring;
+};
+
+/**
+ * Create an empty regular expression.
+ */
+inline RegularExpression::RegularExpression () 
+{ 
+  this->program = 0;
+}
+
+/**
+ * Creates a regular expression from string s, and
+ * compiles s.
+ */
+inline RegularExpression::RegularExpression (const char* s) 
+{  
+  this->program = 0;
+  if ( s )
+    {
+    this->compile(s);
+    }
+}
+
+/**
+ * Destroys and frees space allocated for the regular expression.
+ */
+inline RegularExpression::~RegularExpression () 
+{
+//#ifndef WIN32
+  delete [] this->program;
+//#endif
+}
+
+/**
+ * Set the start position for the regular expression.
+ */
+inline kwsys_std::string::size_type RegularExpression::start () const 
+{
+  return(this->startp[0] - searchstring);
+}
+
+
+/**
+ * Returns the start/end index of the last item found.
+ */
+inline kwsys_std::string::size_type RegularExpression::end () const 
+{
+  return(this->endp[0] - searchstring);
+}
+
+/**
+ * Returns true if two regular expressions have different
+ * compiled program for pattern matching.
+ */
+inline bool RegularExpression::operator!= (const RegularExpression& r) const 
+{
+  return(!(*this == r));
+}
+
+/**
+ * Returns true if a valid regular expression is compiled
+ * and ready for pattern matching.
+ */
+inline bool RegularExpression::is_valid () const 
+{
+  return (this->program != 0);
+}
+
+
+inline void RegularExpression::set_invalid () 
+{
+//#ifndef WIN32
+  delete [] this->program;
+//#endif
+  this->program = 0;
+}
+
+/**
+ * Return start index of nth submatch. start(0) is the start of the full match.
+ */
+inline kwsys_std::string::size_type RegularExpression::start(int n) const
+{
+  return this->startp[n] - searchstring;
+}
+
+
+/**
+ * Return end index of nth submatch. end(0) is the end of the full match.
+ */
+inline kwsys_std::string::size_type RegularExpression::end(int n) const
+{
+  return this->endp[n] - searchstring;
+}
+
+/**
+ * Return nth submatch as a string.
+ */
+inline kwsys_std::string RegularExpression::match(int n) const
+{
+  return kwsys_std::string(this->startp[n], this->endp[n] - this->startp[n]);
+}
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif

+ 44 - 0
Source/kwsys/StandardIncludes.hxx.in

@@ -0,0 +1,44 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See http://www.cmake.org/HTML/Copyright.html 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@_StandardIncludes_hxx
+#define @KWSYS_NAMESPACE@_StandardIncludes_hxx
+
+#include <@KWSYS_NAMESPACE@/Configure.hxx>
+
+#ifndef KWSYS_NO_ANSI_STREAM_HEADERS
+#  include <fstream>
+#  include <iostream>
+#else
+#  include <fstream.h>
+#  include <iostream.h>
+#endif
+
+#if !defined(KWSYS_NO_ANSI_STRING_STREAM)
+#  include <sstream>
+#elif !defined(KWSYS_NO_ANSI_STREAM_HEADERS)
+#  include <strstream>
+#else
+#  include <strstream.h>
+#endif
+
+#if defined(KWSYS_NO_STD_NAMESPACE)
+# define kwsys_std
+#else
+# define kwsys_std std
+#endif
+
+#endif

+ 1793 - 0
Source/kwsys/SystemTools.cxx

@@ -0,0 +1,1793 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See http://www.cmake.org/HTML/Copyright.html 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 <SystemTools.hxx>
+#include <RegularExpression.hxx>
+#include <Directory.hxx>
+
+#include <fstream>
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+
+// support for realpath call
+#ifndef _WIN32
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#endif
+
+#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__))
+#include <string.h>
+#include <windows.h>
+#include <direct.h>
+#define _unlink unlink
+inline int Mkdir(const char* dir)
+{
+  return _mkdir(dir);
+}
+inline const char* Getcwd(char* buf, unsigned int len)
+{
+  return _getcwd(buf, len);
+}
+inline int Chdir(const char* dir)
+{
+  #if defined(__BORLANDC__)
+  return chdir(dir);
+  #else
+  return _chdir(dir);
+  #endif
+}
+#else
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+inline int Mkdir(const char* dir)
+{
+  return mkdir(dir, 00777);
+}
+inline const char* Getcwd(char* buf, unsigned int len)
+{
+  return getcwd(buf, len);
+}
+inline int Chdir(const char* dir)
+{
+  return chdir(dir);
+}
+#endif
+
+
+/* Implement floattime() for various platforms */
+// Taken from Python 2.1.3
+
+#if defined( _WIN32 ) && !defined( __CYGWIN__ )
+#  include <sys/timeb.h>
+#  define HAVE_FTIME
+#  if defined( __BORLANDC__)
+#    define FTIME ftime
+#    define TIMEB timeb
+#  else // Visual studio?
+#    define FTIME _ftime
+#    define TIMEB _timeb
+#  endif
+#elif defined( __CYGWIN__ ) || defined( __linux__ )
+#  include <sys/time.h>
+#  include <time.h>
+#  define HAVE_GETTIMEOFDAY
+#endif
+
+namespace KWSYS_NAMESPACE
+{
+
+double
+SystemTools::GetTime(void)
+{
+  /* There are three ways to get the time:
+     (1) gettimeofday() -- resolution in microseconds
+     (2) ftime() -- resolution in milliseconds
+     (3) time() -- resolution in seconds
+     In all cases the return value is a float in seconds.
+     Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
+     fail, so we fall back on ftime() or time().
+     Note: clock resolution does not imply clock accuracy! */
+#ifdef HAVE_GETTIMEOFDAY
+  {
+  struct timeval t;
+#ifdef GETTIMEOFDAY_NO_TZ
+  if (gettimeofday(&t) == 0)
+    return (double)t.tv_sec + t.tv_usec*0.000001;
+#else /* !GETTIMEOFDAY_NO_TZ */
+  if (gettimeofday(&t, (struct timezone *)NULL) == 0)
+    return (double)t.tv_sec + t.tv_usec*0.000001;
+#endif /* !GETTIMEOFDAY_NO_TZ */
+  }
+#endif /* !HAVE_GETTIMEOFDAY */
+  {
+#if defined(HAVE_FTIME)
+  struct TIMEB t;
+  FTIME(&t);
+  return (double)t.time + (double)t.millitm * (double)0.001;
+#else /* !HAVE_FTIME */
+  time_t secs;
+  time(&secs);
+  return (double)secs;
+#endif /* !HAVE_FTIME */
+  }
+}
+
+// adds the elements of the env variable path to the arg passed in
+void SystemTools::GetPath(kwsys_std::vector<kwsys_std::string>& path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  const char* pathSep = ";";
+#else
+  const char* pathSep = ":";
+#endif
+  kwsys_std::string pathEnv = getenv("PATH");
+  // A hack to make the below algorithm work.  
+  if(pathEnv[pathEnv.length()-1] != ':')
+    {
+    pathEnv += pathSep;
+    }
+  kwsys_std::string::size_type start =0;
+  bool done = false;
+  while(!done)
+    {
+    kwsys_std::string::size_type endpos = pathEnv.find(pathSep, start);
+    if(endpos != kwsys_std::string::npos)
+      {
+      path.push_back(pathEnv.substr(start, endpos-start));
+      start = endpos+1;
+      }
+    else
+      {
+      done = true;
+      }
+    }
+  for(kwsys_std::vector<kwsys_std::string>::iterator i = path.begin();
+      i != path.end(); ++i)
+    {
+    SystemTools::ConvertToUnixSlashes(*i);
+    }
+}
+
+
+const char* SystemTools::GetExecutableExtension()
+{
+#if defined(_WIN32) || defined(__CYGWIN__)
+  return ".exe";
+#else
+  return "";
+#endif  
+}
+
+
+bool SystemTools::MakeDirectory(const char* path)
+{
+  if(SystemTools::FileExists(path))
+    {
+    return true;
+    }
+  kwsys_std::string dir = path;
+  if(dir.size() == 0)
+    {
+    return false;
+    }
+  SystemTools::ConvertToUnixSlashes(dir);
+
+  kwsys_std::string::size_type pos = dir.find(':');
+  if(pos == kwsys_std::string::npos)
+    {
+    pos = 0;
+    }
+  kwsys_std::string topdir;
+  while((pos = dir.find('/', pos)) != kwsys_std::string::npos)
+    {
+    topdir = dir.substr(0, pos);
+    Mkdir(topdir.c_str());
+    pos++;
+    }
+  if(dir[dir.size()-1] == '/')
+    {
+    topdir = dir.substr(0, dir.size());
+    }
+  else
+    {
+    topdir = dir;
+    }
+  if(Mkdir(topdir.c_str()) != 0)
+    {
+    // There is a bug in the Borland Run time library which makes MKDIR
+    // return EACCES when it should return EEXISTS
+    // if it is some other error besides directory exists
+    // then return false
+    if( (errno != EEXIST) 
+#ifdef __BORLANDC__
+        && (errno != EACCES) 
+#endif      
+      )
+      {
+      return false;
+      }
+    }
+  return true;
+}
+
+
+// replace replace with with as many times as it shows up in source.
+// write the result into source.
+void SystemTools::ReplaceString(kwsys_std::string& source,
+                                   const char* replace,
+                                   const char* with)
+{
+  // get out quick if string is not found
+  kwsys_std::string::size_type start = source.find(replace);
+  if(start ==  kwsys_std::string::npos)
+    {
+    return;
+    }
+  kwsys_std::string rest;
+  kwsys_std::string::size_type lengthReplace = strlen(replace);
+  kwsys_std::string::size_type lengthWith = strlen(with);
+  while(start != kwsys_std::string::npos)
+    {
+    rest = source.substr(start+lengthReplace);
+    source = source.substr(0, start);
+    source += with;
+    source += rest;
+    start = source.find(replace, start + lengthWith );
+    }
+}
+
+// Read a registry value.
+// Example : 
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+//      =>  will return the data of the "default" value of the key
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+//      =>  will return the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::ReadRegistryValue(const char *key, kwsys_std::string &value)
+{
+
+  kwsys_std::string primary = key;
+  kwsys_std::string second;
+  kwsys_std::string valuename;
+ 
+  size_t start = primary.find("\\");
+  if (start == kwsys_std::string::npos)
+    {
+    return false;
+    }
+
+  size_t valuenamepos = primary.find(";");
+  if (valuenamepos != kwsys_std::string::npos)
+    {
+    valuename = primary.substr(valuenamepos+1);
+    }
+
+  second = primary.substr(start+1, valuenamepos-start-1);
+  primary = primary.substr(0, start);
+  
+  HKEY primaryKey;
+  if (primary == "HKEY_CURRENT_USER")
+    {
+    primaryKey = HKEY_CURRENT_USER;
+    }
+  if (primary == "HKEY_CURRENT_CONFIG")
+    {
+    primaryKey = HKEY_CURRENT_CONFIG;
+    }
+  if (primary == "HKEY_CLASSES_ROOT")
+    {
+    primaryKey = HKEY_CLASSES_ROOT;
+    }
+  if (primary == "HKEY_LOCAL_MACHINE")
+    {
+    primaryKey = HKEY_LOCAL_MACHINE;
+    }
+  if (primary == "HKEY_USERS")
+    {
+    primaryKey = HKEY_USERS;
+    }
+  
+  HKEY hKey;
+  if(RegOpenKeyEx(primaryKey, 
+                  second.c_str(), 
+                  0, 
+                  KEY_READ, 
+                  &hKey) != ERROR_SUCCESS)
+    {
+    return false;
+    }
+  else
+    {
+    DWORD dwType, dwSize;
+    dwSize = 1023;
+    char data[1024];
+    if(RegQueryValueEx(hKey, 
+                       (LPTSTR)valuename.c_str(), 
+                       NULL, 
+                       &dwType, 
+                       (BYTE *)data, 
+                       &dwSize) == ERROR_SUCCESS)
+      {
+      if (dwType == REG_SZ)
+        {
+        value = data;
+        return true;
+        }
+      }
+    }
+  return false;
+}
+#else
+bool SystemTools::ReadRegistryValue(const char *, kwsys_std::string &)
+{
+  return false;
+}
+#endif
+
+
+// Write a registry value.
+// Example : 
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+//      =>  will set the data of the "default" value of the key
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+//      =>  will set the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::WriteRegistryValue(const char *key, const char *value)
+{
+  kwsys_std::string primary = key;
+  kwsys_std::string second;
+  kwsys_std::string valuename;
+ 
+  size_t start = primary.find("\\");
+  if (start == kwsys_std::string::npos)
+    {
+    return false;
+    }
+
+  size_t valuenamepos = primary.find(";");
+  if (valuenamepos != kwsys_std::string::npos)
+    {
+    valuename = primary.substr(valuenamepos+1);
+    }
+
+  second = primary.substr(start+1, valuenamepos-start-1);
+  primary = primary.substr(0, start);
+  
+  HKEY primaryKey;
+  if (primary == "HKEY_CURRENT_USER")
+    {
+    primaryKey = HKEY_CURRENT_USER;
+    }
+  if (primary == "HKEY_CURRENT_CONFIG")
+    {
+    primaryKey = HKEY_CURRENT_CONFIG;
+    }
+  if (primary == "HKEY_CLASSES_ROOT")
+    {
+    primaryKey = HKEY_CLASSES_ROOT;
+    }
+  if (primary == "HKEY_LOCAL_MACHINE")
+    {
+    primaryKey = HKEY_LOCAL_MACHINE;
+    }
+  if (primary == "HKEY_USERS")
+    {
+    primaryKey = HKEY_USERS;
+    }
+  
+  HKEY hKey;
+  DWORD dwDummy;
+  if(RegCreateKeyEx(primaryKey, 
+                    second.c_str(), 
+                    0, 
+                    "",
+                    REG_OPTION_NON_VOLATILE,
+                    KEY_WRITE,
+                    NULL,
+                    &hKey,
+                    &dwDummy) != ERROR_SUCCESS)
+    {
+    return false;
+    }
+
+  if(RegSetValueEx(hKey, 
+                   (LPTSTR)valuename.c_str(), 
+                   0, 
+                   REG_SZ, 
+                   (CONST BYTE *)value, 
+                   (DWORD)(strlen(value) + 1)) == ERROR_SUCCESS)
+    {
+    return true;
+    }
+  return false;
+}
+#else
+bool SystemTools::WriteRegistryValue(const char *, const char *)
+{
+  return false;
+}
+#endif
+
+// Delete a registry value.
+// Example : 
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Python\PythonCore\2.1\InstallPath
+//      =>  will delete the data of the "default" value of the key
+//      HKEY_LOCAL_MACHINE\SOFTWARE\Scriptics\Tcl\8.4;Root
+//      =>  will delete  the data of the "Root" value of the key
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+bool SystemTools::DeleteRegistryValue(const char *key)
+{
+  kwsys_std::string primary = key;
+  kwsys_std::string second;
+  kwsys_std::string valuename;
+ 
+  size_t start = primary.find("\\");
+  if (start == kwsys_std::string::npos)
+    {
+    return false;
+    }
+
+  size_t valuenamepos = primary.find(";");
+  if (valuenamepos != kwsys_std::string::npos)
+    {
+    valuename = primary.substr(valuenamepos+1);
+    }
+
+  second = primary.substr(start+1, valuenamepos-start-1);
+  primary = primary.substr(0, start);
+  
+  HKEY primaryKey;
+  if (primary == "HKEY_CURRENT_USER")
+    {
+    primaryKey = HKEY_CURRENT_USER;
+    }
+  if (primary == "HKEY_CURRENT_CONFIG")
+    {
+    primaryKey = HKEY_CURRENT_CONFIG;
+    }
+  if (primary == "HKEY_CLASSES_ROOT")
+    {
+    primaryKey = HKEY_CLASSES_ROOT;
+    }
+  if (primary == "HKEY_LOCAL_MACHINE")
+    {
+    primaryKey = HKEY_LOCAL_MACHINE;
+    }
+  if (primary == "HKEY_USERS")
+    {
+    primaryKey = HKEY_USERS;
+    }
+  
+  HKEY hKey;
+  if(RegOpenKeyEx(primaryKey, 
+                  second.c_str(), 
+                  0, 
+                  KEY_WRITE, 
+                  &hKey) != ERROR_SUCCESS)
+    {
+    return false;
+    }
+  else
+    {
+    if(RegDeleteValue(hKey, 
+                      (LPTSTR)valuename.c_str()) == ERROR_SUCCESS)
+      {
+      return true;
+      }
+    }
+  return false;
+}
+#else
+bool SystemTools::DeleteRegistryValue(const char *)
+{
+  return false;
+}
+#endif
+
+// replace replace with with as many times as it shows up in source.
+// write the result into source.
+#if defined(_WIN32) && !defined(__CYGWIN__)
+void SystemTools::ExpandRegistryValues(kwsys_std::string& source)
+{
+  // Regular expression to match anything inside [...] that begins in HKEY.
+  // Note that there is a special rule for regular expressions to match a
+  // close square-bracket inside a list delimited by square brackets.
+  // The "[^]]" part of this expression will match any character except
+  // a close square-bracket.  The ']' character must be the first in the
+  // list of characters inside the [^...] block of the expression.
+  cmRegularExpression regEntry("\\[(HKEY[^]]*)\\]");
+  
+  // check for black line or comment
+  while (regEntry.find(source))
+    {
+    // the arguments are the second match
+    kwsys_std::string key = regEntry.match(1);
+    kwsys_std::string val;
+    if (ReadRegistryValue(key.c_str(), val))
+      {
+      kwsys_std::string reg = "[";
+      reg += key + "]";
+      SystemTools::ReplaceString(source, reg.c_str(), val.c_str());
+      }
+    else
+      {
+      kwsys_std::string reg = "[";
+      reg += key + "]";
+      SystemTools::ReplaceString(source, reg.c_str(), "/registry");
+      }
+    }
+}
+#else
+void SystemTools::ExpandRegistryValues(kwsys_std::string&)
+{
+}
+#endif  
+
+
+kwsys_std::string SystemTools::EscapeQuotes(const char* str)
+{
+  kwsys_std::string result = "";
+  for(const char* ch = str; *ch != '\0'; ++ch)
+    {
+    if(*ch == '"')
+      {
+      result += '\\';
+      }
+    result += *ch;
+    }
+  return result;
+}
+
+bool SystemTools::SameFile(const char* file1, const char* file2)
+{
+#ifdef _WIN32
+  HANDLE hFile1, hFile2;
+
+  hFile1 = CreateFile( file1, 
+                      GENERIC_READ, 
+                      FILE_SHARE_READ ,
+                      NULL,
+                      OPEN_EXISTING,
+                      FILE_FLAG_BACKUP_SEMANTICS,
+                      NULL
+    );
+  hFile2 = CreateFile( file2, 
+                      GENERIC_READ, 
+                      FILE_SHARE_READ, 
+                      NULL,
+                      OPEN_EXISTING,
+                      FILE_FLAG_BACKUP_SEMANTICS,
+                      NULL
+    );
+  if( hFile1 == INVALID_HANDLE_VALUE || hFile2 == INVALID_HANDLE_VALUE)
+    {
+    if(hFile1 != INVALID_HANDLE_VALUE)
+      {
+      CloseHandle(hFile1);
+      }
+    if(hFile2 != INVALID_HANDLE_VALUE)
+      {
+      CloseHandle(hFile2);
+      }
+    return false;
+    }
+
+   BY_HANDLE_FILE_INFORMATION fiBuf1;
+   BY_HANDLE_FILE_INFORMATION fiBuf2;
+   GetFileInformationByHandle( hFile1, &fiBuf1 );
+   GetFileInformationByHandle( hFile2, &fiBuf2 );
+   CloseHandle(hFile1);
+   CloseHandle(hFile2);
+   return (fiBuf1.nFileIndexHigh == fiBuf2.nFileIndexHigh &&
+           fiBuf1.nFileIndexLow == fiBuf2.nFileIndexLow);
+#else
+  struct stat fileStat1, fileStat2;
+  if (stat(file1, &fileStat1) == 0 && stat(file2, &fileStat2) == 0)
+    {
+    // see if the files are the same file
+    // check the device inode and size
+    if(memcmp(&fileStat2.st_dev, &fileStat1.st_dev, sizeof(fileStat1.st_dev)) == 0 && 
+       memcmp(&fileStat2.st_ino, &fileStat1.st_ino, sizeof(fileStat1.st_ino)) == 0 &&
+       fileStat2.st_size == fileStat1.st_size 
+      ) 
+      {
+      return true;
+      }
+    }
+  return false;
+#endif
+}
+
+
+// return true if the file exists
+bool SystemTools::FileExists(const char* filename)
+{
+  struct stat fs;
+  if (stat(filename, &fs) != 0) 
+    {
+    return false;
+    }
+  else
+    {
+    return true;
+    }
+}
+
+
+// Return a capitalized string (i.e the first letter is uppercased, all other
+// are lowercased)
+kwsys_std::string SystemTools::Capitalized(const kwsys_std::string& s)
+{
+  kwsys_std::string n;
+  n.resize(s.size());
+  n[0] = toupper(s[0]);
+  for (size_t i = 1; i < s.size(); i++)
+    {
+    n[i] = tolower(s[i]);
+    }
+  return n;
+}
+
+
+// Return a lower case string 
+kwsys_std::string SystemTools::LowerCase(const kwsys_std::string& s)
+{
+  kwsys_std::string n;
+  n.resize(s.size());
+  for (size_t i = 0; i < s.size(); i++)
+    {
+    n[i] = tolower(s[i]);
+    }
+  return n;
+}
+
+// Return a lower case string 
+kwsys_std::string SystemTools::UpperCase(const kwsys_std::string& s)
+{
+  kwsys_std::string n;
+  n.resize(s.size());
+  for (size_t i = 0; i < s.size(); i++)
+    {
+    n[i] = toupper(s[i]);
+    }
+  return n;
+}
+
+
+// convert windows slashes to unix slashes 
+void SystemTools::ConvertToUnixSlashes(kwsys_std::string& path)
+{
+  kwsys_std::string::size_type pos = 0;
+  while((pos = path.find('\\', pos)) != kwsys_std::string::npos)
+    {
+    path[pos] = '/';
+    pos++;
+    }
+  // Remove all // from the path just like most unix shells
+  int start_find = 0;
+
+#ifdef _WIN32
+  // However, on windows if the first characters are both slashes,
+  // then keep them that way, so that network paths can be handled.
+  start_find = 1;
+#endif
+
+  while((pos = path.find("//", start_find)) != kwsys_std::string::npos)
+    {
+    SystemTools::ReplaceString(path, "//", "/");
+    }
+  
+  // remove any trailing slash
+  if(path.size() && path[path.size()-1] == '/')
+    {
+    path = path.substr(0, path.size()-1);
+    }
+
+  // if there is a tilda ~ then replace it with HOME
+  if(path.find("~") == 0)
+    {
+    if (getenv("HOME"))
+      {
+      path = kwsys_std::string(getenv("HOME")) + path.substr(1);
+      }
+    }
+  
+  // if there is a /tmp_mnt in a path get rid of it!
+  // stupid sgi's 
+  if(path.find("/tmp_mnt") == 0)
+    {
+    path = path.substr(8);
+    }
+}
+
+
+// change // to /, and escape any spaces in the path
+kwsys_std::string SystemTools::ConvertToUnixOutputPath(const char* path)
+{
+  kwsys_std::string ret = path;
+  
+  // remove // except at the beginning might be a cygwin drive
+  kwsys_std::string::size_type pos = 1;
+  while((pos = ret.find("//", pos)) != kwsys_std::string::npos)
+    {
+    ret.erase(pos, 1);
+    }
+  // now escape spaces if there is a space in the path
+  if(ret.find(" ") != kwsys_std::string::npos)
+    {
+    kwsys_std::string result = "";
+    char lastch = 1;
+    for(const char* ch = ret.c_str(); *ch != '\0'; ++ch)
+      {
+        // if it is already escaped then don't try to escape it again
+      if(*ch == ' ' && lastch != '\\')
+        {
+        result += '\\';
+        }
+      result += *ch;
+      lastch = *ch;
+      }
+    ret = result;
+    }
+  return ret;
+}
+
+
+
+kwsys_std::string SystemTools::EscapeSpaces(const char* str)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  kwsys_std::string result;
+  
+  // if there are spaces
+  kwsys_std::string temp = str;
+  if (temp.find(" ") != kwsys_std::string::npos && 
+      temp.find("\"")==kwsys_std::string::npos)
+    {
+    result = "\"";
+    result += str;
+    result += "\"";
+    return result;
+    }
+  return str;
+#else
+  kwsys_std::string result = "";
+  for(const char* ch = str; *ch != '\0'; ++ch)
+    {
+    if(*ch == ' ')
+      {
+      result += '\\';
+      }
+    result += *ch;
+    }
+  return result;
+#endif
+}
+
+kwsys_std::string SystemTools::ConvertToOutputPath(const char* path)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+  return SystemTools::ConvertToWindowsOutputPath(path);
+#else
+  return SystemTools::ConvertToUnixOutputPath(path);
+#endif
+}
+
+
+// remove double slashes not at the start
+kwsys_std::string SystemTools::ConvertToWindowsOutputPath(const char* path)
+{  
+  kwsys_std::string ret = path;
+  kwsys_std::string::size_type pos = 0;
+  // first convert all of the slashes
+  while((pos = ret.find('/', pos)) != kwsys_std::string::npos)
+    {
+    ret[pos] = '\\';
+    pos++;
+    }
+  // check for really small paths
+  if(ret.size() < 2)
+    {
+    return ret;
+    }
+  // now clean up a bit and remove double slashes
+  // Only if it is not the first position in the path which is a network
+  // path on windows
+  pos = 1; // start at position 1
+  if(ret[0] == '\"')
+    {
+    pos = 2;  // if the string is already quoted then start at 2
+    if(ret.size() < 3)
+      {
+      return ret;
+      }
+    }
+  while((pos = ret.find("\\\\", pos)) != kwsys_std::string::npos)
+    {
+    ret.erase(pos, 1);
+    }
+  // now double quote the path if it has spaces in it
+  // and is not already double quoted
+  if(ret.find(" ") != kwsys_std::string::npos
+     && ret[0] != '\"')
+    {
+    kwsys_std::string result;
+    result = "\"" + ret + "\"";
+    ret = result;
+    }
+  return ret;
+}
+
+bool SystemTools::CopyFileIfDifferent(const char* source,
+                                        const char* destination)
+{
+  if(SystemTools::FilesDiffer(source, destination))
+    {
+    SystemTools::CopyFileAlways(source, destination);
+    return true;
+    }
+  return false;
+}
+
+  
+bool SystemTools::FilesDiffer(const char* source,
+                                const char* destination)
+{
+  struct stat statSource;
+  if (stat(source, &statSource) != 0) 
+    {
+    return true;
+    }
+
+  struct stat statDestination;
+  if (stat(destination, &statDestination) != 0) 
+    {
+    return true;
+    }
+
+  if(statSource.st_size != statDestination.st_size)
+    {
+    return true;
+    }
+
+  if(statSource.st_size == 0)
+    {
+    return false;
+    }
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+  kwsys_std::ifstream finSource(source, 
+                          kwsys_std::ios::binary | kwsys_std::ios::in);
+  kwsys_std::ifstream finDestination(destination, 
+                               kwsys_std::ios::binary | kwsys_std::ios::in);
+#else
+  kwsys_std::ifstream finSource(source);
+  kwsys_std::ifstream finDestination(destination);
+#endif
+  if(!finSource || !finDestination)
+    {
+    return true;
+    }
+
+  char* source_buf = new char[statSource.st_size];
+  char* dest_buf = new char[statSource.st_size];
+
+  finSource.read(source_buf, statSource.st_size);
+  finDestination.read(dest_buf, statSource.st_size);
+
+  if(statSource.st_size != static_cast<long>(finSource.gcount()) ||
+     statSource.st_size != static_cast<long>(finDestination.gcount()))
+    {
+    // Failed to read files.
+    delete [] source_buf;
+    delete [] dest_buf;
+    return true;
+    }
+  int ret = memcmp((const void*)source_buf, 
+                   (const void*)dest_buf, 
+                   statSource.st_size);
+
+  delete [] dest_buf;
+  delete [] source_buf;
+
+  return ret != 0;
+}
+
+
+/**
+ * Copy a file named by "source" to the file named by "destination".
+ */
+bool SystemTools::CopyFileAlways(const char* source, const char* destination)
+{
+  const int bufferSize = 4096;
+  char buffer[bufferSize];
+
+  // If destination is a directory, try to create a file with the same
+  // name as the source in that directory.
+
+  kwsys_std::string new_destination;
+  if(SystemTools::FileExists(destination) &&
+     SystemTools::FileIsDirectory(destination))
+    {
+    new_destination = destination;
+    SystemTools::ConvertToUnixSlashes(new_destination);
+    new_destination += '/';
+    kwsys_std::string source_name = source;
+    new_destination += SystemTools::GetFilenameName(source_name);
+    destination = new_destination.c_str();
+    }
+
+  // Create destination directory
+
+  kwsys_std::string destination_dir = destination;
+  destination_dir = SystemTools::GetFilenamePath(destination_dir);
+  SystemTools::MakeDirectory(destination_dir.c_str());
+
+  // Open files
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+  kwsys_std::ifstream fin(source, 
+                    kwsys_std::ios::binary | kwsys_std::ios::in);
+#else
+  kwsys_std::ifstream fin(source);
+#endif
+  if(!fin)
+    {
+    return false;
+    }
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+  kwsys_std::ofstream fout(destination, 
+                     kwsys_std::ios::binary | kwsys_std::ios::out | kwsys_std::ios::trunc);
+#else
+  kwsys_std::ofstream fout(destination, 
+                     kwsys_std::ios::out | kwsys_std::ios::trunc);
+#endif
+  if(!fout)
+    {
+    return false;
+    }
+  
+  // This copy loop is very sensitive on certain platforms with
+  // slightly broken stream libraries (like HPUX).  Normally, it is
+  // incorrect to not check the error condition on the fin.read()
+  // before using the data, but the fin.gcount() will be zero if an
+  // error occurred.  Therefore, the loop should be safe everywhere.
+  while(fin)
+    {
+    fin.read(buffer, bufferSize);
+    if(fin.gcount())
+      {
+      fout.write(buffer, fin.gcount());
+      }
+    }
+  
+  // Make sure the operating system has finished writing the file
+  // before closing it.  This will ensure the file is finished before
+  // the check below.
+  fout.flush();
+  
+  fin.close();
+  fout.close();
+
+  // More checks.
+  struct stat statSource, statDestination;
+  statSource.st_size = 12345;
+  statDestination.st_size = 12345;
+  if(stat(source, &statSource) != 0)
+    {
+    return false;
+    }
+  else if(stat(destination, &statDestination) != 0)
+    {
+    return false;
+    }
+  else if(statSource.st_size != statDestination.st_size)
+    {
+    return false;
+    }
+  return true;
+}
+
+// return true if the file exists
+long int SystemTools::ModifiedTime(const char* filename)
+{
+  struct stat fs;
+  if (stat(filename, &fs) != 0) 
+    {
+    return 0;
+    }
+  else
+    {
+    return (long int)fs.st_mtime;
+    }
+}
+
+
+kwsys_std::string SystemTools::GetLastSystemError()
+{
+  int e = errno;
+  return strerror(e);
+}
+
+bool SystemTools::RemoveFile(const char* source)
+{
+  return unlink(source) != 0 ? false : true;
+}
+
+/**
+ * Find the file the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the file if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+kwsys_std::string SystemTools::FindFile(const char* name, 
+                                       const kwsys_std::vector<kwsys_std::string>& userPaths)
+{
+  // Add the system search path to our path.
+  kwsys_std::vector<kwsys_std::string> path = userPaths;
+  SystemTools::GetPath(path);
+
+  kwsys_std::string tryPath;
+  for(kwsys_std::vector<kwsys_std::string>::const_iterator p = path.begin();
+      p != path.end(); ++p)
+    {
+    tryPath = *p;
+    tryPath += "/";
+    tryPath += name;
+    if(SystemTools::FileExists(tryPath.c_str()) &&
+      !SystemTools::FileIsDirectory(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+    }
+  // Couldn't find the file.
+  return "";
+}
+
+/**
+ * Find the executable with the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the executable if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+kwsys_std::string SystemTools::FindProgram(const char* name,
+                                       const kwsys_std::vector<kwsys_std::string>& userPaths,
+                                       bool no_system_path)
+{
+  if(!name)
+    {
+    return "";
+    }
+  // See if the executable exists as written.
+  if(SystemTools::FileExists(name) &&
+      !SystemTools::FileIsDirectory(name))
+    {
+    return SystemTools::CollapseFullPath(name);
+    }
+  kwsys_std::string tryPath = name;
+  tryPath += SystemTools::GetExecutableExtension();
+  if(SystemTools::FileExists(tryPath.c_str()) &&
+     !SystemTools::FileIsDirectory(tryPath.c_str()))
+    {
+    return SystemTools::CollapseFullPath(tryPath.c_str());
+    }
+
+  // Add the system search path to our path.
+  kwsys_std::vector<kwsys_std::string> path = userPaths;
+  if (!no_system_path)
+    {
+    SystemTools::GetPath(path);
+    }
+
+  for(kwsys_std::vector<kwsys_std::string>::const_iterator p = path.begin();
+      p != path.end(); ++p)
+    {
+    tryPath = *p;
+    tryPath += "/";
+    tryPath += name;
+    if(SystemTools::FileExists(tryPath.c_str()) &&
+      !SystemTools::FileIsDirectory(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+#ifdef _WIN32
+    tryPath += ".com";
+    if(SystemTools::FileExists(tryPath.c_str()) &&
+       !SystemTools::FileIsDirectory(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+    tryPath = *p;
+    tryPath += "/";
+    tryPath += name;
+#endif
+    tryPath += SystemTools::GetExecutableExtension();
+    if(SystemTools::FileExists(tryPath.c_str()) &&
+       !SystemTools::FileIsDirectory(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+    }
+
+  // Couldn't find the program.
+  return "";
+}
+
+
+/**
+ * Find the library with the given name.  Searches the given path and then
+ * the system search path.  Returns the full path to the library if it is
+ * found.  Otherwise, the empty string is returned.
+ */
+kwsys_std::string SystemTools::FindLibrary(const char* name,
+                                       const kwsys_std::vector<kwsys_std::string>& userPaths)
+{
+  // See if the executable exists as written.
+  if(SystemTools::FileExists(name) &&
+     !SystemTools::FileIsDirectory(name))
+    {
+    return SystemTools::CollapseFullPath(name);
+    }
+  
+  // Add the system search path to our path.
+  kwsys_std::vector<kwsys_std::string> path = userPaths;
+  SystemTools::GetPath(path);
+  
+  kwsys_std::string tryPath;
+  for(kwsys_std::vector<kwsys_std::string>::const_iterator p = path.begin();
+      p != path.end(); ++p)
+    {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+    tryPath = *p;
+    tryPath += "/";
+    tryPath += name;
+    tryPath += ".lib";
+    if(SystemTools::FileExists(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+#else
+    tryPath = *p;
+    tryPath += "/lib";
+    tryPath += name;
+    tryPath += ".so";
+    if(SystemTools::FileExists(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+    tryPath = *p;
+    tryPath += "/lib";
+    tryPath += name;
+    tryPath += ".a";
+    if(SystemTools::FileExists(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+    tryPath = *p;
+    tryPath += "/lib";
+    tryPath += name;
+    tryPath += ".sl";
+    if(SystemTools::FileExists(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+    tryPath = *p;
+    tryPath += "/lib";
+    tryPath += name;
+    tryPath += ".dylib";
+    if(SystemTools::FileExists(tryPath.c_str()))
+      {
+      return SystemTools::CollapseFullPath(tryPath.c_str());
+      }
+#endif
+    }
+  
+  // Couldn't find the library.
+  return "";
+}
+
+bool SystemTools::FileIsDirectory(const char* name)
+{  
+  struct stat fs;
+  if(stat(name, &fs) == 0)
+    {
+#if _WIN32
+    return ((fs.st_mode & _S_IFDIR) != 0);
+#else
+    return S_ISDIR(fs.st_mode);
+#endif
+    }
+  else
+    {
+    return false;
+    }
+}
+
+int SystemTools::ChangeDirectory(const char *dir)
+{
+  return Chdir(dir);
+}
+
+kwsys_std::string SystemTools::GetCurrentWorkingDirectory()
+{
+  char buf[2048];
+  kwsys_std::string path = Getcwd(buf, 2048);
+  return path;
+}
+
+kwsys_std::string SystemTools::GetProgramPath(const char* in_name)
+{
+  kwsys_std::string dir, file;
+  SystemTools::SplitProgramPath(in_name, dir, file);
+  return dir;
+}
+
+bool SystemTools::SplitProgramPath(const char* in_name,
+                                   kwsys_std::string& dir,
+                                   kwsys_std::string& file,
+                                   bool errorReport)
+{
+  dir = in_name;
+  file = "";
+  SystemTools::ConvertToUnixSlashes(dir);
+  
+  if(!SystemTools::FileIsDirectory(dir.c_str()))
+    {
+    kwsys_std::string::size_type slashPos = dir.rfind("/");
+    if(slashPos != kwsys_std::string::npos)
+      {
+      file = dir.substr(slashPos+1);
+      dir = dir.substr(0, slashPos);
+      }
+    else
+      {
+      file = dir;
+      dir = "";
+      }
+    }
+  if((dir != "") && !SystemTools::FileIsDirectory(dir.c_str()))
+    {
+    kwsys_std::string oldDir = in_name;
+    SystemTools::ConvertToUnixSlashes(oldDir);
+    dir = in_name;
+    return false;
+    }
+  return true;
+}
+
+kwsys_std::string SystemTools::CollapseFullPath(const char* in_relative)
+{
+  return SystemTools::CollapseFullPath(in_relative, 0);
+}
+
+kwsys_std::string SystemTools::CollapseFullPath(const char* in_relative,
+                                            const char* in_base)
+{
+  kwsys_std::string dir, file;
+  SystemTools::SplitProgramPath(in_relative, dir, file, false);
+  
+  // Save original working directory.
+  kwsys_std::string orig = SystemTools::GetCurrentWorkingDirectory();
+  
+  // Change to base of relative path.
+  if(in_base)
+    {
+    Chdir(in_base);
+    }
+  
+#ifdef _WIN32
+  // Follow relative path.
+  if(dir != "")
+    {
+    Chdir(dir.c_str());
+    }
+  
+  // Get the resulting directory.
+  kwsys_std::string newDir = SystemTools::GetCurrentWorkingDirectory();
+  
+  // Add the file back on to the directory.
+  SystemTools::ConvertToUnixSlashes(newDir);
+#else
+# ifdef MAXPATHLEN
+  char resolved_name[MAXPATHLEN];
+# else
+#  ifdef PATH_MAX
+  char resolved_name[PATH_MAX];
+#  else
+  char resolved_name[5024];
+#  endif
+# endif
+  
+  // Resolve relative path.
+  kwsys_std::string newDir;
+  if(dir != "")
+    {
+    realpath(dir.c_str(), resolved_name);
+    newDir = resolved_name;
+    }
+  else
+    {
+    newDir = SystemTools::GetCurrentWorkingDirectory();
+    }
+#endif
+  
+  // Restore original working directory.
+  Chdir(orig.c_str());
+  
+  // Construct and return the full path.
+  kwsys_std::string newPath = newDir;
+  if(file != "")
+    {
+    newPath += "/";
+    newPath += file;
+    }
+  return newPath;
+}
+
+bool SystemTools::Split(const char* str, kwsys_std::vector<kwsys_std::string>& lines)
+{
+  kwsys_std::string data(str);
+  kwsys_std::string::size_type lpos = 0;
+  while(lpos < data.length())
+    {
+    kwsys_std::string::size_type rpos = data.find_first_of("\n", lpos);
+    if(rpos == kwsys_std::string::npos)
+      {
+      // Line ends at end of string without a newline.
+      lines.push_back(data.substr(lpos));
+      return false;
+      }
+    if((rpos > lpos) && (data[rpos-1] == '\r'))
+      {
+      // Line ends in a "\r\n" pair, remove both characters.
+      lines.push_back(data.substr(lpos, (rpos-1)-lpos));
+      }
+    else
+      {
+      // Line ends in a "\n", remove the character.
+      lines.push_back(data.substr(lpos, rpos-lpos));
+      }
+    lpos = rpos+1;
+    }
+  return true;
+}
+
+/**
+ * Return path of a full filename (no trailing slashes).
+ * Warning: returned path is converted to Unix slashes format.
+ */
+kwsys_std::string SystemTools::GetFilenamePath(const kwsys_std::string& filename)
+{
+  kwsys_std::string fn = filename;
+  SystemTools::ConvertToUnixSlashes(fn);
+  
+  kwsys_std::string::size_type slash_pos = fn.rfind("/");
+  if(slash_pos != kwsys_std::string::npos)
+    {
+    return fn.substr(0, slash_pos);
+    }
+  else
+    {
+    return "";
+    }
+}
+
+
+/**
+ * Return file name of a full filename (i.e. file name without path).
+ */
+kwsys_std::string SystemTools::GetFilenameName(const kwsys_std::string& filename)
+{
+  kwsys_std::string fn = filename;
+  SystemTools::ConvertToUnixSlashes(fn);
+  
+  kwsys_std::string::size_type slash_pos = fn.rfind("/");
+  if(slash_pos != kwsys_std::string::npos)
+    {
+    return fn.substr(slash_pos + 1);
+    }
+  else
+    {
+    return filename;
+    }
+}
+
+
+/**
+ * Return file extension of a full filename (dot included).
+ * Warning: this is the longest extension (for example: .tar.gz)
+ */
+kwsys_std::string SystemTools::GetFilenameExtension(const kwsys_std::string& filename)
+{
+  kwsys_std::string name = SystemTools::GetFilenameName(filename);
+  kwsys_std::string::size_type dot_pos = name.find(".");
+  if(dot_pos != kwsys_std::string::npos)
+    {
+    return name.substr(dot_pos);
+    }
+  else
+    {
+    return "";
+    }
+}
+
+
+/**
+ * Return file name without extension of a full filename (i.e. without path).
+ * Warning: it considers the longest extension (for example: .tar.gz)
+ */
+kwsys_std::string SystemTools::GetFilenameWithoutExtension(const kwsys_std::string& filename)
+{
+  kwsys_std::string name = SystemTools::GetFilenameName(filename);
+  kwsys_std::string::size_type dot_pos = name.find(".");
+  if(dot_pos != kwsys_std::string::npos)
+    {
+    return name.substr(0, dot_pos);
+    }
+  else
+    {
+    return name;
+    }
+}
+
+
+/**
+ * Return file name without extension of a full filename (i.e. without path).
+ * Warning: it considers the last extension (for example: removes .gz
+ * from .tar.gz)
+ */
+kwsys_std::string
+SystemTools::GetFilenameWithoutLastExtension(const kwsys_std::string& filename)
+{
+  kwsys_std::string name = SystemTools::GetFilenameName(filename);
+  kwsys_std::string::size_type dot_pos = name.rfind(".");
+  if(dot_pos != kwsys_std::string::npos)
+    {
+    return name.substr(0, dot_pos);
+    }
+  else
+    {
+    return name;
+    }
+}
+
+bool SystemTools::FileIsFullPath(const char* in_name)
+{
+  kwsys_std::string name = in_name;
+#if defined(_WIN32)
+  // On Windows, the name must be at least two characters long.
+  if(name.length() < 2)
+    {
+    return false;
+    }
+  if(name[1] == ':')
+    {
+    return true;
+    }
+  if(name[0] == '\\')
+    {
+    return true;
+    }
+#else
+  // On UNIX, the name must be at least one character long.
+  if(name.length() < 1)
+    {
+    return false;
+    }
+#endif
+  // On UNIX, the name must begin in a '/'.
+  // On Windows, if the name begins in a '/', then it is a full
+  // network path.
+  if(name[0] == '/')
+    {
+    return true;
+    }
+  return false;
+}
+
+void SystemTools::Glob(const char *directory, const char *regexp,
+                         kwsys_std::vector<kwsys_std::string>& files)
+{
+  Directory d;
+  RegularExpression reg(regexp);
+  
+  if (d.Load(directory))
+    {
+    size_t numf;
+        unsigned int i;
+    numf = d.GetNumberOfFiles();
+    for (i = 0; i < numf; i++)
+      {
+      kwsys_std::string fname = d.GetFile(i);
+      if (reg.find(fname))
+        {
+        files.push_back(fname);
+        }
+      }
+    }
+}
+
+
+void SystemTools::GlobDirs(const char *fullPath,
+                             kwsys_std::vector<kwsys_std::string>& files)
+{
+  kwsys_std::string path = fullPath;
+  kwsys_std::string::size_type pos = path.find("/*");
+  if(pos == kwsys_std::string::npos)
+    {
+    files.push_back(fullPath);
+    return;
+    }
+  kwsys_std::string startPath = path.substr(0, pos);
+  kwsys_std::string finishPath = path.substr(pos+2);
+
+  Directory d;
+  if (d.Load(startPath.c_str()))
+    {
+    for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i)
+      {
+      if((kwsys_std::string(d.GetFile(i)) != ".")
+         && (kwsys_std::string(d.GetFile(i)) != ".."))
+        {
+        kwsys_std::string fname = startPath;
+        fname +="/";
+        fname += d.GetFile(i);
+        if(SystemTools::FileIsDirectory(fname.c_str()))
+          {
+          fname += finishPath;
+          SystemTools::GlobDirs(fname.c_str(), files);
+          }
+        }
+      }
+    }
+}
+
+bool SystemTools::GetShortPath(const char* path, kwsys_std::string& shortPath)
+{
+#if defined(WIN32) && !defined(__CYGWIN__)  
+  const int size = int(strlen(path)) +1; // size of return
+  char *buffer = new char[size];  // create a buffer
+  char *tempPath = new char[size];  // create a buffer
+  int ret;
+  
+  // if the path passed in has quotes around it, first remove the quotes
+  if (path[0] == '"' && path[strlen(path)-1] == '"')
+    {
+    strcpy(tempPath,path+1);
+    tempPath[strlen(tempPath)-1] = '\0';
+    }
+  else
+    {
+    strcpy(tempPath,path);
+    }
+  
+  buffer[0] = 0;
+  ret = GetShortPathName(tempPath, buffer, size);
+
+  if(buffer[0] == 0 || ret > size)
+    {
+    delete [] buffer;
+    delete [] tempPath;
+    return false;
+    }
+  else
+    {
+    shortPath = buffer;
+    delete [] buffer;
+    delete [] tempPath;
+    return true;
+    }
+#else
+  shortPath = path;
+  return true;
+#endif
+}
+
+bool SystemTools::SimpleGlob(const kwsys_std::string& glob, 
+                               kwsys_std::vector<kwsys_std::string>& files, 
+                               int type /* = 0 */)
+{
+  files.clear();
+  if ( glob[glob.size()-1] != '*' )
+    {
+    return false;
+    }
+  kwsys_std::string path = SystemTools::GetFilenamePath(glob);
+  kwsys_std::string ppath = SystemTools::GetFilenameName(glob);
+  ppath = ppath.substr(0, ppath.size()-1);
+  if ( path.size() == 0 )
+    {
+    path = "/";
+    }
+
+  bool res = false;
+  Directory d;
+  if (d.Load(path.c_str()))
+    {
+    for (unsigned int i = 0; i < d.GetNumberOfFiles(); ++i)
+      {
+      if((kwsys_std::string(d.GetFile(i)) != ".")
+         && (kwsys_std::string(d.GetFile(i)) != ".."))
+        {
+        kwsys_std::string fname = path;
+        if ( path[path.size()-1] != '/' )
+          {
+          fname +="/";
+          }
+        fname += d.GetFile(i);
+        kwsys_std::string sfname = d.GetFile(i);
+        if ( type > 0 && SystemTools::FileIsDirectory(fname.c_str()) )
+          {
+          continue;
+          }
+        if ( type < 0 && !SystemTools::FileIsDirectory(fname.c_str()) )
+          {
+          continue;
+          }
+        if ( sfname.size() >= ppath.size() && 
+             sfname.substr(0, ppath.size()) == 
+             ppath )
+          {
+          files.push_back(fname);
+          res = true;
+          }
+        }
+      }
+    }
+  return res;
+}
+
+
+void SystemTools::SplitProgramFromArgs(const char* path, 
+                                         kwsys_std::string& program, kwsys_std::string& args)
+{
+  if(SystemTools::FileExists(path))
+    {
+    program = path;
+    args = "";
+    return;
+    }
+  kwsys_std::vector<kwsys_std::string> e;
+  kwsys_std::string findProg = SystemTools::FindProgram(path, e);
+  if(findProg.size())
+    {
+    program = findProg;
+    args = "";
+    return;
+    }
+  kwsys_std::string dir = path;
+  kwsys_std::string::size_type spacePos = dir.rfind(' ');
+  if(spacePos == kwsys_std::string::npos)
+    {
+    program = "";
+    args = "";
+    return;
+    }
+  while(spacePos != kwsys_std::string::npos)
+    {
+    kwsys_std::string tryProg = dir.substr(0, spacePos);
+    if(SystemTools::FileExists(tryProg.c_str()))
+      {
+      program = tryProg;
+      args = dir.substr(spacePos, dir.size()-spacePos);
+      return;
+      } 
+    findProg = SystemTools::FindProgram(tryProg.c_str(), e);
+    if(findProg.size())
+      {
+      program = findProg;
+      args = dir.substr(spacePos, dir.size()-spacePos);
+      return;
+      }
+    spacePos = dir.rfind(' ', spacePos--);
+    }
+  program = "";
+  args = "";
+}
+
+kwsys_std::string SystemTools::GetCurrentDateTime(const char* format)
+{
+  char buf[1024];
+  time_t t;
+  time(&t);
+  strftime(buf, sizeof(buf), format, localtime(&t));
+  return buf;
+}
+
+kwsys_std::string SystemTools::MakeCindentifier(const char* s)
+{
+  kwsys_std::string str(s);
+  if (str.find_first_of("0123456789") == 0)
+    {
+    str = "_" + str;
+    }
+
+  kwsys_std::string permited_chars("_"
+                             "abcdefghijklmnopqrstuvwxyz"
+                             "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                             "0123456789");
+  kwsys_std::string::size_type pos = 0;
+  while ((pos = str.find_first_not_of(permited_chars, pos)) != kwsys_std::string::npos)
+    {
+    str[pos] = '_';
+    }
+  return str;
+}
+
+// Due to a buggy stream library on the HP and another on Mac OSX, we
+// need this very carefully written version of getline.  Returns true
+// if any data were read before the end-of-file was reached.
+bool SystemTools::GetLineFromStream(kwsys_std::istream& is, kwsys_std::string& line)
+{
+  const int bufferSize = 1024;
+  char buffer[bufferSize];
+  line = "";
+  bool haveData = false;
+
+  // If no characters are read from the stream, the end of file has
+  // been reached.
+  while((is.getline(buffer, bufferSize), is.gcount() > 0))
+    {
+    haveData = true;
+    line.append(buffer);
+
+    // If newline character was read, the gcount includes the
+    // character, but the buffer does not.  The end of line has been
+    // reached.
+    if(strlen(buffer) < static_cast<size_t>(is.gcount()))
+      {
+      break;
+      }
+
+    // The fail bit may be set.  Clear it.
+    is.clear(is.rdstate() & ~kwsys_std::ios::failbit);
+    }
+  return haveData;
+}
+
+#if defined(_MSC_VER) && defined(_DEBUG)
+# include <crtdbg.h>
+# include <stdio.h>
+# include <stdlib.h>
+static int SystemToolsDebugReport(int, char* message, int*)
+{
+  fprintf(stderr, message);
+  exit(1);
+  return 0;
+}
+void SystemTools::EnableMSVCDebugHook()
+{
+  if(getenv("DART_TEST_FROM_DART"))
+    {
+    _CrtSetReportHook(SystemToolsDebugReport);
+    }
+}
+#else
+void SystemTools::EnableMSVCDebugHook()
+{
+}
+#endif
+
+} // namespace KWSYS_NAMESPACE

+ 285 - 0
Source/kwsys/SystemTools.hxx.in

@@ -0,0 +1,285 @@
+/*=========================================================================
+
+  Program:   KWSys - Kitware System Library
+  Module:    $RCSfile$
+  Language:  C++
+  Date:      $Date$
+  Version:   $Revision$
+
+  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.
+  See http://www.cmake.org/HTML/Copyright.html 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@_SystemTools_hxx
+#define @KWSYS_NAMESPACE@_SystemTools_hxx
+
+#include <@KWSYS_NAMESPACE@/StandardIncludes.hxx>
+
+#include <string>
+#include <vector>
+
+namespace @KWSYS_NAMESPACE@
+{
+
+/** \class SystemTools
+ * \brief A collection of useful platform-independent system functions.
+ */
+class SystemTools
+{
+public:
+  /**
+   * Replace symbols in str that are not valid in C identifiers as
+   * defined by the 1999 standard, ie. anything except [A-Za-z0-9_].
+   * They are replaced with `_' and if the first character is a digit
+   * then an underscore is prepended.  Note that this can produce
+   * identifiers that the standard reserves (_[A-Z].* and __.*).
+   */
+  static kwsys_std::string MakeCindentifier(const char* s);
+  
+  /**
+   * Make a new directory if it is not there.  This function
+   * can make a full path even if none of the directories existed
+   * prior to calling this function.  
+   */
+  static bool MakeDirectory(const char* path);
+
+  /**
+   * Get current time as a double. On certain platforms this will
+   * return higher resolution than seconds:
+   * (1) gettimeofday() -- resolution in microseconds
+   * (2) ftime() -- resolution in milliseconds
+   * (3) time() -- resolution in seconds
+   */
+  static double GetTime();
+
+  /**
+   * Replace replace all occurances of the string in
+   * the source string.
+   */
+  static void ReplaceString(kwsys_std::string& source,
+                            const char* replace,
+                            const char* with);
+
+  /**
+   * Read a registry value
+   */
+  static bool ReadRegistryValue(const char *key, kwsys_std::string &value);
+
+  /**
+   * Write a registry value
+   */
+  static bool WriteRegistryValue(const char *key, const char *value);
+
+  /**
+   * Delete a registry value
+   */
+  static bool DeleteRegistryValue(const char *key);
+
+  /**
+   * Look for and replace registry values in a string
+   */
+  static void ExpandRegistryValues(kwsys_std::string& source);
+
+  /**
+   * Return a capitalized string (i.e the first letter is uppercased,
+   * all other are lowercased).
+   */
+  static kwsys_std::string Capitalized(const kwsys_std::string&);
+  
+  /**
+   * Return a lower case string
+   */
+  static kwsys_std::string LowerCase(const kwsys_std::string&);
+  
+  /**
+   * Return a lower case string
+   */
+  static kwsys_std::string UpperCase(const kwsys_std::string&);
+  
+  /**
+   * Replace Windows file system slashes with Unix-style slashes.
+   */
+  static void ConvertToUnixSlashes(kwsys_std::string& path);
+  
+  /**
+   * Platform independent escape spaces, unix uses backslash,
+   * windows double quotes the string.
+   */
+  static kwsys_std::string EscapeSpaces(const char* str);
+
+  /** Escape quotes in a string.  */
+  static kwsys_std::string EscapeQuotes(const char* str);
+
+  /**
+   * For windows this calles ConvertToWindowsOutputPath and for unix
+   * it calls ConvertToUnixOutputPath
+   */
+  static kwsys_std::string ConvertToOutputPath(const char*);
+  
+  /** Return true if a file exists in the current directory.  */
+  static bool FileExists(const char* filename);
+  
+  /**
+   *  Add the paths from the environment variable PATH to the 
+   *  string vector passed in.
+   */
+  static void GetPath(kwsys_std::vector<kwsys_std::string>& path);
+
+  /**
+   *  Get the file extension (including ".") needed for an executable
+   *  on the current platform ("" for unix, ".exe" for Windows).
+   */
+  static const char* GetExecutableExtension();
+
+  /**
+   * Copy the source file to the destination file only
+   * if the two files differ.  
+   */
+  static bool CopyFileIfDifferent(const char* source,
+                                  const char* destination);
+  
+  ///! Compare the contents of two files.  Return true if different.
+  static bool FilesDiffer(const char* source,
+                          const char* destination);
+  
+  ///! return true if the two files are the same file
+  static bool SameFile(const char* file1, const char* file2);
+
+  ///! Copy a file.
+  static bool CopyFileAlways(const char* source, const char* destination);
+  
+  ///! Remove a file.
+  static bool RemoveFile(const char* source);
+  
+  ///! Find a file in the system PATH, with optional extra paths.
+  static kwsys_std::string FindFile(const char* name,
+                              const kwsys_std::vector<kwsys_std::string>& path= kwsys_std::vector<kwsys_std::string>());
+
+  ///! Find an executable in the system PATH, with optional extra paths.
+  static kwsys_std::string FindProgram(const char* name,
+                                 const kwsys_std::vector<kwsys_std::string>& path = kwsys_std::vector<kwsys_std::string>(),
+                                 bool no_system_path = false);
+
+  ///! Find a library in the system PATH, with optional extra paths.
+  static kwsys_std::string FindLibrary(const char* name,
+                                 const kwsys_std::vector<kwsys_std::string>& path);
+  
+  ///! return true if the file is a directory.
+  static bool FileIsDirectory(const char* name);
+  static void Glob(const char *directory, const char *regexp,
+                   kwsys_std::vector<kwsys_std::string>& files);
+  static void GlobDirs(const char *fullPath, kwsys_std::vector<kwsys_std::string>& files);
+
+  /**
+   * Try to find a list of files that match the "simple" globbing
+   * expression. At this point in time the globbing expressions have
+   * to be in form: /directory/partial_file_name*. The * character has
+   * to be at the end of the string and it does not support ?
+   * []... The optional argument type specifies what kind of files you
+   * want to find. 0 means all files, -1 means directories, 1 means
+   * files only. This method returns true if search was succesfull.
+   */
+  static bool SimpleGlob(const kwsys_std::string& glob, kwsys_std::vector<kwsys_std::string>& files, 
+                         int type = 0);
+  
+  static kwsys_std::string GetCurrentWorkingDirectory();
+  
+  /**
+   * Given the path to a program executable, get the directory part of
+   * the path with the file stripped off.  If there is no directory
+   * part, the empty string is returned.
+   */
+  static kwsys_std::string GetProgramPath(const char*);
+  static bool SplitProgramPath(const char* in_name, 
+                               kwsys_std::string& dir, 
+                               kwsys_std::string& file,
+                               bool errorReport = true);
+  
+  /**
+   * Given a path to a file or directory, convert it to a full path.
+   * This collapses away relative paths relative to the cwd argument
+   * (which defaults to the current working directory).  The full path
+   * is returned.
+   */
+  static kwsys_std::string CollapseFullPath(const char* in_relative);
+  static kwsys_std::string CollapseFullPath(const char* in_relative,
+                                      const char* in_base);
+  
+  ///! return path of a full filename (no trailing slashes).
+  static kwsys_std::string GetFilenamePath(const kwsys_std::string&);
+
+  
+  ///! return file name of a full filename (i.e. file name without path).
+  static kwsys_std::string GetFilenameName(const kwsys_std::string&);
+  
+  ///! Split a program from its arguments and handle spaces in the paths.
+  static void SplitProgramFromArgs(const char* path, 
+                                   kwsys_std::string& program, kwsys_std::string& args);
+  
+  ///! return file extension of a full filename (dot included).
+  static kwsys_std::string GetFilenameExtension(const kwsys_std::string&);
+  
+  ///! return file name without extension of a full filename.
+  static kwsys_std::string GetFilenameWithoutExtension(const kwsys_std::string&);
+  
+  ///! return file name without its last (shortest) extension.
+  static kwsys_std::string GetFilenameWithoutLastExtension(const kwsys_std::string&);
+  
+  /** Return whether the path represents a full path (not relative).  */
+  static bool FileIsFullPath(const char*);
+  
+  static long int ModifiedTime(const char* filename);
+
+  ///! for windows return the short path for the given path, unix just a pass through
+  static bool GetShortPath(const char* path, kwsys_std::string& result);
+  
+  ///! change directory the the directory specified
+  static int ChangeDirectory(const char* dir);
+
+  /** Split a string on its newlines into multiple lines.  Returns
+      false only if the last line stored had no newline.  */
+  static bool Split(const char* s, kwsys_std::vector<kwsys_std::string>& l);
+  
+  static kwsys_std::string GetCurrentDateTime(const char* format);
+
+  /** Get the result of strerror(errno).  */
+  static kwsys_std::string GetLastSystemError();
+  
+  /** When building DEBUG with MSVC, this enables a hook that prevents
+   * error dialogs from popping up if the program is being run from
+   * DART.
+   */
+  static void EnableMSVCDebugHook();
+
+  /**
+   * Read line from file. Make sure to get everything. Due to a buggy stream
+   * library on the HP and another on Mac OSX, we need this very carefully
+   * written version of getline. Returns true if any data were read before the
+   * end-of-file was reached.
+   */
+  static bool GetLineFromStream(kwsys_std::istream& istr, kwsys_std::string& line);
+  
+protected:
+  // these two functions can be called from ConvertToOutputPath
+  /**
+   * Convert the path to a string that can be used in a unix makefile.
+   * double slashes are removed, and spaces are escaped.
+   */
+  static kwsys_std::string ConvertToUnixOutputPath(const char*);
+  
+  /**
+   * Convert the path to string that can be used in a windows project or
+   * makefile.   Double slashes are removed if they are not at the start of
+   * the string, the slashes are converted to windows style backslashes, and
+   * if there are spaces in the string it is double quoted.
+   */
+  static kwsys_std::string ConvertToWindowsOutputPath(const char*);
+};
+
+} // namespace @KWSYS_NAMESPACE@
+
+#endif