Commit 8052b13a authored by LEFEBVREJP email's avatar LEFEBVREJP email
Browse files

Adding radixcore with system and string utility functions.

parent 12c4e5ec
Pipeline #10328 passed with stage
in 2 minutes and 11 seconds
TRIBITS_PACKAGE_DEFINE_DEPENDENCIES(
SUBPACKAGES_DIRS_CLASSIFICATIONS_OPTREQS
bug radixbug SS OPTIONAL
core radixcore SS OPTIONAL
dl radixdl SS OPTIONAL
pattern radixpattern SS OPTIONAL
algorithm radixalgorithm SS OPTIONAL
......
TRIBITS_SUBPACKAGE(core)
SET(HEADERS
system.hh
stringfunctions.i.hh
stringfunctions.hh
)
SET(SOURCES
system.cc
stringfunctions.cc
)
TRIBITS_ADD_LIBRARY(radixcore
SOURCES ${SOURCES}
NOINSTALLHEADERS ${HEADERS}
)
#
# Add testing directory
TRIBITS_ADD_TEST_DIRECTORIES(tests)
INSTALL(FILES ${HEADERS} DESTINATION "include/radixcore/")
TRIBITS_SUBPACKAGE_POSTPROCESS()
TRIBITS_PACKAGE_DEFINE_DEPENDENCIES(
LIB_REQUIRED_PACKAGES
LIB_OPTIONAL_PACKAGES
TEST_REQUIRED_PACKAGES testframework
TEST_OPTIONAL_PACKAGES
LIB_REQUIRED_TPLS
LIB_OPTIONAL_TPLS
TEST_REQUIRED_TPLS
TEST_OPTIONAL_TPLS
)
/*
* @file: stringfunctions.cc
* @author: Jordan P. Lefebvre
*
* Created on October 23, 2017, 16:34 PM
*/
#include "stringfunctions.hh"
#include <algorithm>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
namespace radix
{
std::string trim_string( const std::string& indata )
{
std::string data( indata );
data.erase( 0, data.find_first_not_of( " \t\n\r" ) ); // prefixing spaces
data.erase( data.find_last_not_of( " \t\n\r" ) + 1 ); // surfixing spaces
return data;
} // trim_string
std::string string_tolower( const std::string& indata )
{
std::string data( indata );
std::transform( data.begin(), data.end(), data.begin(), ::tolower );
return data;
}
std::string string_toupper( const std::string& indata )
{
std::string data( indata );
std::transform( data.begin(), data.end(), data.begin(), ::toupper );
return data;
}
std::string strip_quotes( const std::string& src )
{
std::string s = src;
// remove single quotes
if( s.size() > 2 && s[0] == '\'' && s[s.size() - 1] == '\'' )
{
s.erase( 0, 1 );
s.erase( s.size() - 1, 1 );
}
// remove double quotes
if( s.size() > 2 && s[0] == '"' && s[s.size() - 1] == '"' )
{
s.erase( 0, 1 );
s.erase( s.size() - 1, 1 );
}
return s;
}
std::vector<std::string> split_string( const std::string& delim,
const std::string& word )
{
std::vector<std::string> tokens;
size_t pos = 0;
std::string word0( word );
while( ( pos = word0.find( delim ) ) != std::string::npos )
{
tokens.push_back( word0.substr( 0, pos ) );
word0.erase( 0, pos + delim.length() );
}
tokens.push_back( word0 ); // remainder
// if last element is empty, delete it (only if it has more than 1)
if( tokens.size() > 1 && tokens[tokens.size() - 1].length() == 0 )
{
tokens.resize( tokens.size() - 1 );
}
return tokens;
} // splitString
std::string find_and_replace( const std::string& instr,
const std::string& find,
const std::string& replace )
{
size_t pos = 0;
std::string str( instr );
while( ( pos = str.find( find, pos ) ) != std::string::npos )
{
str.replace( pos, find.length(), replace );
pos += replace.length();
}
return str;
}
std::string remove_substring( const char* msg, const char* sub )
{
std::string str( msg );
const std::string target( sub );
std::size_t start_position = str.find( target );
while( start_position != std::string::npos )
{
str.erase( start_position, target.length() );
start_position = str.find( target );
}
return str;
} // removeSubstring
std::string remove_extra_whitespace( const std::string& inputStr )
{
// Remove newlines and tabs.
std::string str = find_and_replace( inputStr, "\n", " " );
str = find_and_replace( str, "\t", " " );
str = find_and_replace( str, "\r", " " );
// Collapse multiple spaces to a single space.
auto new_end = std::unique( str.begin(), str.end(),
[]( char lhs, char rhs )
{
return ( lhs == rhs ) && ( lhs == ' ' );
} );
str.erase( new_end, str.end() );
return trim_string( str );
}
} // namespace radix
#ifndef RADIX_RADIXCORE_STRINGFUNCTIONS_HH_
#define RADIX_RADIXCORE_STRINGFUNCTIONS_HH_
/*
* @file: stringfunctions.hh
* @author: Jordan P. Lefebvre
*
* Created on October 23, 2017, 16:34 PM
*/
#include <cstdio>
#include <fstream>
#include <string>
#include <type_traits>
#include <vector>
namespace radix
{
/**
* Convert a string to lowercase
* @param the string to be converted
*/
std::string string_tolower( const std::string& data );
/**
* Convert a string to uppercase
* @param the string to be converted
*/
std::string string_toupper( const std::string& data );
/**
* trim a leading and trailing whitespace
* @param the string to be converted
*/
std::string trim_string( const std::string& data );
/**
* @brief Remove double- and single- quotes from the string
*/
std::string strip_quotes( const std::string& src );
/**
* @brief Convert something to a string.
*/
template <typename T>
std::string to_string( const T& x, int prec = 6 );
/**
* @brief Convert something from a string using stream idioms.
*/
template <typename T>
T from_string( const std::string& val, const T& defVal );
/**
* @brief Join something like a vector to a single string with delimiter
*/
template <typename T>
std::string join( const std::string& delim, const T& x );
/**
* @brief Split a string into pieces using a delimiter
*/
std::vector<std::string> split_string( const std::string& delim,
const std::string& word );
/**
* @brief Find all instances and replace them
*/
std::string find_and_replace( const std::string& str,
const std::string& find,
const std::string& replace );
/**
* @brief remove a particular substring (multiple times) from a target string
*/
std::string remove_substring( const char* msg, const char* sub );
/**
* @brief remove extra whitespace (\t-->' ', \n-->' ', ' '-->' ')
*/
std::string remove_extra_whitespace( const std::string& str );
} // namespace radix
//! Templated functions
#include "stringfunctions.i.hh"
#endif /** RADIX_RADIXCORE_STRINGFUNCTIONS_HH_ */
#include <iomanip>
#include <limits>
#include <sstream>
#include "radixbug/bug.hh"
namespace radix
{
template <typename T>
std::string to_string( const T& x, int prec )
{
radix_require( prec >= 0 );
std::stringstream ss;
ss << std::setprecision( prec ) << std::boolalpha << x;
return ss.str();
}
template <typename T>
T from_string( const std::string& val, const T& defVal )
{
std::stringstream ss( val );
T result;
return ss >> result ? result : defVal;
}
template <typename T>
std::string join( const std::string& delim, const T& x )
{
std::stringstream ss;
for( size_t i = 0; i < x.size(); ++i )
{
ss << x[i];
if( i < ( x.size() - 1 ) ) ss << delim;
}
return ss.str();
}
} // namespace radix
/*
* @file: system.cc
* @author: Jordan P. Lefebvre
*
* Created on October 23, 2017, 16:34 PM
*/
#include "system.hh"
#include "stringfunctions.hh"
#include <algorithm>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#ifdef _WIN32
#include <direct.h>
#include <sys/stat.h>
#define getcwd _getcwd // MSFT "deprecation" warning
#define chdir _chdir // change directory
#define popen _popen
#define pclose _pclose
#else
#include <sys/stat.h>
#include <unistd.h>
#endif
namespace radix
{
FILE* pipe_open( const std::string& command, const std::string& mode )
{
return popen( command.c_str(), mode.c_str() );
} // pipeOpen
int pipe_close( FILE* pipe )
{
return pclose( pipe );
} // pipe_close
void set_env( const std::string& var, const std::string& value )
{
#ifndef _WIN32
setenv( var.c_str(), value.c_str(), 1 );
#else
std::string temp = var + "=" + value;
_putenv( temp.c_str() );
#endif
} // set_env
std::string env( const std::string& var )
{
char* result = getenv( var.c_str() );
if( result == nullptr ) return "";
std::string temp( result );
return temp;
} // env
std::string computer_name()
{
char* hostname;
#ifndef _WIN32
hostname = new char[256];
if( gethostname( hostname, 256 ) != 0 )
{
strcpy( hostname, "Unknown" );
}
std::string result( hostname );
delete[] hostname;
#else
hostname = getenv( "COMPUTERNAME" );
std::string result( hostname );
#endif
return result;
} // computer_name
std::string dirname( const std::string& path, char forceSep )
{
const char sep = separator_char( forceSep );
//
// Search back to find separator character
// this should provide for a terminate '/' so we don't find name/
// but instead find /name
size_t nonSepCharIndex = path.find_last_not_of( sep );
if( nonSepCharIndex == std::string::npos )
{
nonSepCharIndex = path.size();
}
//
// Search backward for nonsep char for a separator char
//
size_t sepCharIndex = path.find_last_of( sep, nonSepCharIndex );
if( sepCharIndex == std::string::npos )
{
return ".";
}
if( sepCharIndex == 0 )
{
++sepCharIndex;
};
std::string result = path.substr( 0, sepCharIndex );
return result;
} // dirname
std::string basename( const std::string& path,
bool removeExtension,
char forceSep )
{
const char sep = separator_char( forceSep );
//
// Search back to find separator character
// this should provide for a terminate '/' so we don't find name/
// but instead find /name
size_t nonSepCharIndex = path.find_last_not_of( sep );
if( nonSepCharIndex == std::string::npos )
{
nonSepCharIndex = path.size();
}
size_t startIndex = 0;
size_t sepCharIndex = path.find_last_of( sep, nonSepCharIndex );
//
// if 'name' or 'name/' with no '/' before a non '/' char
//
if( sepCharIndex == std::string::npos )
{
sepCharIndex = 0;
}
if( path.size() > 0 && path.at( sepCharIndex ) == sep )
{
++sepCharIndex;
}
startIndex = sepCharIndex;
//
// Check for '/', must return '/'
//
if( nonSepCharIndex > 0 && path.at( nonSepCharIndex - 1 ) == sep )
--startIndex;
std::string result =
path.substr( startIndex, nonSepCharIndex - sepCharIndex + 1 );
// remove extension
if( removeExtension )
{
std::string ext = file_extension( result );
if( ext != "" )
{
result = result.substr( 0, result.length() - ext.length() - 1 );
}
}
return result;
} // basename
std::string file_extension( const std::string& inpath )
{
std::string path =
basename( inpath, false ); // strip off all the directory stuff
auto tokens = split_string( ".", path );
if( tokens.size() == 1 || ( tokens.size() == 2 && tokens[0] == "" ) )
return "";
return tokens.back();
} // file_extension
char separator_char( char forceSep )
{
// to enable better unit testing of behavior
if( forceSep != ' ' ) return forceSep;
#ifdef _WIN32
return '\\';
#else
return '/';
#endif
} // separator_char
std::string current_dir()
{
// On windows this is _getcwd defined as such above
char* cwd = nullptr;
cwd = getcwd( nullptr, 0 );
std::string scwd( cwd );
free( cwd );
return scwd;
} // current_dir
bool get_paths( const std::string& spec,
std::vector<std::string>& paths,
bool append )
{
// initialize
if( !append ) paths.clear();
// open pipe
#ifdef _WIN32
auto f = pipe_open( "dir /B " + spec + " 2>NUL", "r" );
#else
auto f = pipe_open( "ls -1 " + spec + " 2>/dev/null", "r" );
#endif
if( f == nullptr )
{
paths.push_back( spec );
return false;
}
// read into std::string
const unsigned N = 1024;
char buf[N];
std::string all;
while( true )
{
size_t read = fread( (void*)&buf[0], 1, N, f );
if( read > 0 )
{
all.append( &buf[0], &buf[read] );
}
if( read < N )
{
break;
}
}
// close pipe
pipe_close( f );
// split on newlines
auto&& return_paths = split_string( "\n", all );
// only return non-empty paths
for( const auto& p : return_paths )
{
if( p != "" ) paths.push_back( p );
}
// if we got nothing then return the original spec
if( paths.size() == 0 )
{
paths.push_back( spec );
return false;
}
return true;
} // getPaths
bool expand_paths( std::vector<std::string>& paths )
{
std::vector<std::string> new_paths;
bool expand = false;
for( auto& p : paths )
{
bool expand1 = get_paths( p, new_paths, /*append=*/true );
expand = expand || expand1;
}
std::swap( paths, new_paths );
return expand;
} // expandPaths
bool expand_path( std::string& path )
{
std::vector<std::string> new_paths;
bool found = get_paths( path, new_paths, /*append=*/true );
if( found )path=new_paths[0];
return found;
} // expandPath
std::string current_dirname()
{
return basename( current_dir() );
} // current_dirname
bool set_current_dir( const std::string& directory )
{
if( dir_exists( directory ) == false ) return false;
int result = -1;
// On windows this is _chdir defined as such above
result = chdir( directory.c_str() );
if( result == 0 ) return true;
return false;
} // set_current_dir
bool path_exists( const std::string& path )
{
#if defined( _WIN32 )
return ( _access( (void*)path.c_str(), 0 ) == 0 );
#else
return ( access( path.c_str(), F_OK ) == 0 );
#endif
} // path_exists
bool file_exists( const std::string& path )
{
// it exists but it is not a directory (this handles
// symbolic links to files in a better way than could
// easily be done otherwise)
return ( path_exists( path ) && !dir_exists( path ) );
} // file_exists
bool dir_exists( const std::string& path )
{
if( path_exists( path ) )
{
#if defined( _WIN32 )
struct _stat status;
_stat( path.c_str(), &status );
return ( status.st_mode & S_IFDIR ) != 0;
#else
struct stat status;
stat( path.c_str(), &status );
return ( status.st_mode & S_IFDIR ) != 0;
#endif
}
return false;
} // dir_exists
bool make_dir( const std::string& path )