diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt new file mode 100644 index 000000000..f5df8e2f8 --- /dev/null +++ b/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) diff --git a/Source/kwsys/Configure.hxx.in b/Source/kwsys/Configure.hxx.in new file mode 100644 index 000000000..baa9c743a --- /dev/null +++ b/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 diff --git a/Source/kwsys/Directory.cxx b/Source/kwsys/Directory.cxx new file mode 100644 index 000000000..3036081a3 --- /dev/null +++ b/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 + +// First microsoft compilers + +#ifdef _MSC_VER +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +#include + +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 diff --git a/Source/kwsys/Directory.hxx.in b/Source/kwsys/Directory.hxx.in new file mode 100644 index 000000000..7182a2832 --- /dev/null +++ b/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 +#include + +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 m_Files; // Array of Files + kwsys_std::string m_Path; // Path to Open'ed directory + +}; // End Class: Directory + +} // namespace @KWSYS_NAMESPACE@ + +#endif diff --git a/Source/kwsys/RegularExpression.cxx b/Source/kwsys/RegularExpression.cxx new file mode 100644 index 000000000..f9a3291a8 --- /dev/null +++ b/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 // Include class specification +#include + +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; ®dummy = 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 = ®dummy; + 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 == ®dummy) { + 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 != ®dummy) + *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 == ®dummy) { + 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 == ®dummy) + 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 == ®dummy || 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 == ®dummy) + 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 == ®dummy) + return (0); + + offset = NEXT(p); + if (offset == 0) + return (0); + + if (OP(p) == BACK) + return (p - offset); + else + return (p + offset); +} + +} // namespace KWSYS_NAMESPACE diff --git a/Source/kwsys/RegularExpression.hxx.in b/Source/kwsys/RegularExpression.hxx.in new file mode 100644 index 000000000..a76622501 --- /dev/null +++ b/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 + +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 diff --git a/Source/kwsys/StandardIncludes.hxx.in b/Source/kwsys/StandardIncludes.hxx.in new file mode 100644 index 000000000..f91cec1ae --- /dev/null +++ b/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 +# include +#else +# include +# include +#endif + +#if !defined(KWSYS_NO_ANSI_STRING_STREAM) +# include +#elif !defined(KWSYS_NO_ANSI_STREAM_HEADERS) +# include +#else +# include +#endif + +#if defined(KWSYS_NO_STD_NAMESPACE) +# define kwsys_std +#else +# define kwsys_std std +#endif + +#endif diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx new file mode 100644 index 000000000..fca3f46db --- /dev/null +++ b/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 +#include +#include + +#include + +#include +#include +#include +#include +#include + +// support for realpath call +#ifndef _WIN32 +#include +#include +#include +#include +#endif + +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__BORLANDC__)) +#include +#include +#include +#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 +#include +#include +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 +# 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 +# include +# 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& 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::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(finSource.gcount()) || + statSource.st_size != static_cast(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& userPaths) +{ + // Add the system search path to our path. + kwsys_std::vector path = userPaths; + SystemTools::GetPath(path); + + kwsys_std::string tryPath; + for(kwsys_std::vector::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& 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 path = userPaths; + if (!no_system_path) + { + SystemTools::GetPath(path); + } + + for(kwsys_std::vector::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& 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 path = userPaths; + SystemTools::GetPath(path); + + kwsys_std::string tryPath; + for(kwsys_std::vector::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& 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& 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& 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& 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 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(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 +# include +# include +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 diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in new file mode 100644 index 000000000..725e8ae1b --- /dev/null +++ b/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 +#include + +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& 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& path= kwsys_std::vector()); + + ///! Find an executable in the system PATH, with optional extra paths. + static kwsys_std::string FindProgram(const char* name, + const kwsys_std::vector& path = kwsys_std::vector(), + 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& 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& files); + static void GlobDirs(const char *fullPath, kwsys_std::vector& 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& 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& 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