Files
TheRock/rocm-systems/projects/rocprofiler-systems/external/dyninst/dataflowAPI/rose/util/StringUtility.C
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

1906 lines
63 KiB
C++

// This avoids requiring the user to use rose_config.h and follows
// the automake manual request that we use <> instead of ""
//FIXBUILD
//#include <rose_config.h>
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
// DQ (3/22/2009): Added MSVS support for ROSE.
#include "external/rose/rose_msvc.h"
// DQ (1/21/2010): Use this to turn off the use of #line in ROSETTA generated code.
#define SKIP_HASH_LINE_NUMBER_DECLARATIONS_IN_GENERATED_FILES
#if !ROSE_MICROSOFT_OS
// AS added to support the function getAbsolutePathFromRelativePath
#include <sys/param.h>
#else
#include <windows.h>
#include "Shlwapi.h"
#ifndef snprintf
//#define snprintf _snprintf
#endif
#endif
#include <algorithm>
// AS added to support the function findfile
#include <stdlib.h>
#include <stdio.h> /* standard input/output routines. */
#if !ROSE_MICROSOFT_OS
#include <dirent.h> /* readdir(), etc. */
#include <sys/stat.h> /* stat(), etc. */
#include <libgen.h> /* basename(), dirame() */
#include <unistd.h> /* getcwd(), etc. */
#endif
#include <string.h> /* strstr(), etc. */
#include <iostream> /* std::cerr */
#include <sstream> /* std::ostringstream */
#include <fstream>
#include "StringUtility.h"
#include <dyncompat/foreach.hpp>
// DQ (8/31/2009): This now compiles properly (at least for analysis, it might still fail for the code generation).
// #ifndef USE_ROSE
#include <dyncompat/lexical_cast.hpp>
// #endif
// DQ (9/29/2006): This is required for 64-bit g++ 3.4.4 compiler.
#include <errno.h>
// Needed for base64 functions
#include "../integerOps.h"
// tps (11/10/2009): This include is needed in windows to find the realpath
#if ROSE_MICROSOFT_OS
#include <windows.h>
// DQ (11/27/2009): this is required for use of GetFullPathName() (below).
#else
#include <unistd.h>
#endif
// DQ (12/31/2005): This is allowed in C files where it can not
// effect the users applcation (just not in header files).
using namespace std;
/* Added htmlEscape necessary for QROSE work to this utility library - tps (9Oct2008) */
std::string
StringUtility::htmlEscape(const std::string& s) {
std::string s2;
for (size_t i = 0; i < s.size(); ++i) {
switch (s[i]) {
case '<': s2 += "&lt;"; break;
case '>': s2 += "&gt;"; break;
case '&': s2 += "&amp;"; break;
default: s2 += s[i]; break;
}
}
return s2;
}
std::list<std::string>
StringUtility::findfile(std::string patternString, std::string pathString)
{
std::list<std::string> patternMatches;
#if ROSE_MICROSOFT_OS
printf ("Error: MSVS implementation of StringUtility::findfile required (not implemented) \n");
#define __builtin_constant_p(exp) (0)
// tps: todo Windows: have not hit this assert yet.
ROSE_ASSERT(false);
#else
DIR* dir; /* pointer to the scanned directory. */
struct dirent* entry; /* pointer to one directory entry. */
// struct stat dir_stat; /* used by stat(). */
/* open the directory for reading */
dir = opendir(pathString.c_str());
if (!dir) {
std::cerr << "Cannot read directory:" << pathString << std::endl;
perror("");
return patternMatches;
}
/* scan the directory, traversing each sub-directory, and */
/* matching the pattern for each file name. */
while ((entry = readdir(dir))) {
/* check if the pattern matchs. */
/* MS: 11/22/2015: note that d_name is an array of char
* and testing it as pointer always gives true;
* removed this kind of testing code
*/
std::string entryName = entry->d_name;
if (entryName.find(patternString) != std::string::npos) {
patternMatches.push_back(pathString+"/"+entryName);
}
}
#endif
return patternMatches;
}
//Read all the words in a file into an vector of strings
std::vector<std::string>
StringUtility::readWordsInFile( std::string filename)
{
std::vector<std::string> variantsToUse;
std::fstream file_op(filename.c_str());
if (file_op.fail()) {
std::cout << "error: could not find file \"" << filename
<< "\" which is meant to include the styles to enforce with "
<< "the name checker." << std::endl;
exit(1); // abort program
}
std::string current_word;
while(file_op >> current_word){
//First word denotes what the regular expression should operate
//upon. Second word denotes the regular expression
variantsToUse.push_back(current_word);
}
return variantsToUse;
}
//
//Rama: 12/06/06
//We need a function getAbsolutePathFromRelativePath that takes any filename and returns the absolute file name (with path)
//AS suggested we use realpath that comes with stdlib. However, for a translator like ours,
//we need to have two versions of the file: silent and non-silent ones, depending on whether
//we need to check and print an error or not.
//That is done by the boolean parameter printErrorIfAny that is set to true by the caller
//The dafault version -- enforced by setting printErrorIfAny to false -- is the silent one.
//
//Also, look at the code added in function
//void SgFile::setupSourceFilename in file .../src/ROSETTA/Grammar/Support.code
//
std::string
StringUtility::getAbsolutePathFromRelativePath ( const std::string & relativePath, bool printErrorIfAny) //! get the absolute path from the relative path
{
string returnString;
char resolved_path[MAXPATHLEN];
resolved_path[0] = '\0';
#if ROSE_MICROSOFT_OS
// tps (08/19/2010): added this function
PathCanonicalize(resolved_path,relativePath.c_str());
string resultingPath=string(resolved_path);
#else
// DQ (9/3/2006): Note that "realpath()"
// can return an error if it processes a file or directory that does not exist. This is
// a problem for include paths that are specified on the commandline and which don't exist;
// most compilers silently ignore these and we have to at least ignore them.
// string resultingPath="";
// tps (01/08/2010) : This implementation was incorrect as it mixed char* and string. Fixed it.
char* rp = realpath( relativePath.c_str(), resolved_path);
string resultingPath = "";
if (rp!=NULL)
resultingPath = string(rp);
#endif
//printf("resultingPath == %s printErrorIfAny == %d \n",resultingPath.c_str(),printErrorIfAny);
// If there was an error then resultingPath is NULL, else it points to resolved_path.
if ( resultingPath.empty() == true ) //== NULL )
{
// DQ (9/4/2006): SgProject is not available within this code since it is used to compile
// ROSETTA before the IR nodes are defined! So we should just comment it out.
// DQ (9/4/2006): Only output such warnings if verbose is set to some value greater than zero.
if(printErrorIfAny == true)
{
//if (SgProject::get_verbose() > 0)
//{
// Output the kind of error that occured ...
//Ask DAN and add checks for 64 bit machines here
//extern int errno;
// Output the kind of error that occured ...
printf ("relativePath = %s errno = %d resolved_path is undefined \n",relativePath.c_str(),errno);
printf (" error = %s \n",strerror(errno));
// In case of error return the original relativePath
printf ("Error: StringUtility::getAbsolutePathFromRelativePath incured an error in use of realpath() and is returning the input relativePath. \n");
//}
}
// printf("returnString0 == %s relativePath == %s resolved_path == %s \n",returnString.c_str(),relativePath.c_str(),resolved_path);
returnString = relativePath;
}
else
{
// "realpath()" worked so return the corrected absolute path.
// printf("returnString1 == %s relativePath == %s resolved_path == %s \n",returnString.c_str(),relativePath.c_str(),resolved_path);
returnString = resolved_path;
}
//printf("returnString3 == %s relativePath == %s resolved_path == %s \n",returnString.c_str(),relativePath.c_str(),resolved_path);
ROSE_ASSERT(returnString.empty() == false);
return returnString;
}
string
StringUtility::listToString ( const list<string> & X, bool separateStrings )
{
// Build a string representing the concatination of the list of strings
string returnString;
// printf ("In listToString: Print out the list of variable names (X.size() = %" PRIuPTR "): \n",X.size());
list<string>::const_iterator listStringElementIterator;
for (listStringElementIterator = X.begin();
listStringElementIterator != X.end();
listStringElementIterator++)
{
// display each string representing a variable name
#if 0
printf (" string element (length=%d) in nameStringList = %s \n",
(*listStringElementIterator).length(),
(*listStringElementIterator).c_str());
#endif
// returnString += (*listStringElementIterator) + "\n";
returnString += *listStringElementIterator + " ";
if (separateStrings)
returnString += "\n";
}
// printf ("In listToString: returnString = %s \n",returnString.c_str());
return returnString;
}
string
StringUtility::listToString ( const vector<string> & X, bool separateStrings )
{
// Build a string representing the concatination of the vector of strings
string returnString;
vector<string>::const_iterator listStringElementIterator;
for (listStringElementIterator = X.begin();
listStringElementIterator != X.end();
listStringElementIterator++)
{
returnString += *listStringElementIterator + " ";
if (separateStrings)
returnString += "\n";
}
return returnString;
}
list<string>
StringUtility::stringToList ( const string & X )
{
// Build a list of strings representing the input string spearated at newline characters ("\n"'s)
// All CR are removed, the list returned has no CR in the list OR within the list elements
// Create a return value
list<string> returnStringList;
// Build a local copy of the input string
string remainingSubstring = X;
int currentPos = 0;
// std::string::size_type nextPos = remainingSubstring.find('\n');
size_t nextPos = remainingSubstring.find('\n');
// int subStringLength = 0;
#if 0
printf ("Initial value: currentPos = %d nextPos = %d remainingSubstring.length() = %d \n",
currentPos,nextPos,remainingSubstring.length());
#endif
// If there is no trailing '\n' then at least include the input X string into the list
if (nextPos == string::npos)
returnStringList.push_back(X);
while (nextPos != string::npos)
{
int nextSubStringLength = (nextPos - currentPos) + 0;
string substring = remainingSubstring.substr(0,nextSubStringLength+0);
#if 0
printf ("In stringToList: substring = [%s] \n",substring.c_str());
#endif
returnStringList.push_back(substring);
remainingSubstring =
remainingSubstring.substr(nextPos+1,(remainingSubstring.length()-nextSubStringLength)-0);
#if 0
printf ("nextSubStringLength = %d substring = %s\n",nextSubStringLength,substring.c_str());
printf ("remainingSubstring.length() = %d remainingSubstring = \n%s \n",
remainingSubstring.length(),remainingSubstring.c_str());
#endif
currentPos = 0;
nextPos = remainingSubstring.find('\n');
#if 0
printf ("Value in loop: currentPos = %d nextPos = %d \n",currentPos,nextPos);
#endif
}
// Remove any strings consisting of only CRs and null strings saved within the list
returnStringList.remove("\n");
returnStringList.remove("");
#if 0
printf ("Exiting in StringUtility::stringToList \n");
ROSE_ABORT();
#endif
// return by value (copy constructor will be called)
return returnStringList;
}
string
StringUtility::listToString ( const list<int> & X, bool separateStrings )
{
// Build a string representing the concatenation of the list of strings
string returnString;
list<int>::const_iterator listStringElementIterator;
for (listStringElementIterator = X.begin();
listStringElementIterator != X.end();
listStringElementIterator++)
{
// display each string representing a number
returnString += numberToString(*listStringElementIterator) + " ";
if (separateStrings)
returnString += "\n";
}
return returnString;
}
std::list<std::string>
StringUtility:: tokenize ( std::string X, char delim ) {
std::list<std::string> l;
std::string token;
std::istringstream iss(X);
while (getline(iss, token, delim)) {
l.push_back(token);
}
return l;
}
// DQ (8/31/2009): This now compiles properly (at least for analysis, it might still fail for the code generation).
// #ifdef USE_ROSE
#if 0
// Liao, 2/11/2009, Alternative to dyncompat::lexical_cast,
// since ROSE has problem in compiling it. Bug 313
// https://outreach.scidac.gov/tracker/index.php?func=detail&aid=313&group_id=24&atid=185
template <typename T>
static std::string numToString(T x)
{
std::ostringstream os;
os << x;
return os.str();
}
#endif
string
StringUtility::numberToString ( long long x )
{
// DQ (8/31/2009): This now compiles properly (at least for analysis, it might still fail for the code generation).
// #ifndef USE_ROSE
return dyncompat::lexical_cast<std::string>(x);
// #else
// return numToString<long long>(x);
//#endif
}
string
StringUtility::numberToString ( unsigned long long x )
{
// DQ (8/31/2009): This now compiles properly (at least for analysis, it might still fail for the code generation).
// #ifndef USE_ROSE
return dyncompat::lexical_cast<std::string>(x);
// #else
// return numToString<unsigned long long >(x);
// #endif
}
string
StringUtility::numberToString ( long x )
{
// DQ (8/31/2009): This now compiles properly (at least for analysis, it might still fail for the code generation).
// #ifndef USE_ROSE
return dyncompat::lexical_cast<std::string>(x);
// #else
// return numToString<long>(x);
// #endif
}
string
StringUtility::numberToString ( unsigned long x )
{
// DQ (8/31/2009): This now compiles properly (at least for analysis, it might still fail for the code generation).
// #ifndef USE_ROSE
return dyncompat::lexical_cast<std::string>(x);
// #else
// return numToString<unsigned long>(x);
// #endif
}
string
StringUtility::numberToString ( int x )
{
// DQ (8/31/2009): This now compiles properly (at least for analysis, it might still fail for the code generation).
// #ifndef USE_ROSE
return dyncompat::lexical_cast<std::string>(x);
// #else
// return numToString<int >(x);
// #endif
}
string
StringUtility::numberToString ( unsigned int x )
{
// DQ (8/31/2009): This now compiles properly (at least for analysis, it might still fail for the code generation).
// #ifndef USE_ROSE
return dyncompat::lexical_cast<std::string>(x);
// #else
// return numToString<unsigned int >(x);
// #endif
}
#if 0
string
// StringUtility::numberToString ( unsigned int x )
StringUtility::numberToString ( size_t x )
{
// Build a string representing the dimensionOfArrayStatement
char numberString[128];
sprintf (numberString,"%lu",x);
// printf ("numberString = %s \n",numberString);
return string(numberString);
}
#endif
// DQ (8/10/2010): Changed to take parameter as const.
string
StringUtility::numberToString ( const void* x )
{
// Build a string representing the dimensionOfArrayStatement
char numberString[128];
sprintf (numberString,"%p",x);
// printf ("numberString = %s \n",numberString);
return string(numberString);
}
string
StringUtility::numberToString ( double x )
{
// Build a string representing the dimensionOfArrayStatement
char numberString[128];
sprintf (numberString,"%2.2f",x);
// printf ("numberString = %s \n",numberString);
return string(numberString);
}
#ifndef _MSC_VER
// #if !defined(__STRICT_ANSI__) && defined(_GLIBCXX_USE_INT128)
// #if ((BACKEND_CXX_COMPILER_MAJOR_VERSION_NUMBER == 4) && (BACKEND_CXX_COMPILER_MINOR_VERSION_NUMBER > 6))
#if (defined(BACKEND_CXX_IS_GNU_COMPILER) && (((BACKEND_CXX_COMPILER_MAJOR_VERSION_NUMBER == 4) && (BACKEND_CXX_COMPILER_MINOR_VERSION_NUMBER > 6)) || (BACKEND_CXX_COMPILER_MAJOR_VERSION_NUMBER > 4)))
// DQ (2/22/2014): Required code for GNU versions greater than 4.6.
// #if (UINTMAX_MAX == ULONG_MAX)
#if (__WORDSIZE == 64)
// PHLin (10/12/2015): check if 64-bit support is enabled
string
StringUtility::numberToString ( __int128 x )
{
// DQ (2/22/2014): I don't think that the dyncompat::lexical_cast can support __int128 yet.
long long temp_x = (long long) x;
return dyncompat::lexical_cast<std::string>(temp_x);
}
string
StringUtility::numberToString ( unsigned __int128 x )
{
// DQ (2/22/2014): I don't think that the dyncompat::lexical_cast can support __int128 yet.
unsigned long long temp_x = (unsigned long long) x;
return dyncompat::lexical_cast<std::string>(temp_x);
}
#endif
#endif
#endif
std::string
StringUtility::cEscape(const std::string &s) {
std::string result;
DYN_FOREACH (char ch, s) {
switch (ch) {
case '\a':
result += "\\a";
break;
case '\b':
result += "\\b";
break;
case '\t':
result += "\\t";
break;
case '\n':
result += "\\n";
break;
case '\v':
result += "\\v";
break;
case '\f':
result += "\\f";
break;
case '\r':
result += "\\r";
break;
case '\"':
result += "\\\"";
break;
case '\\':
result += "\\\\";
break;
default:
if (isprint(ch)) {
result += ch;
} else {
char buf[8];
sprintf(buf, "\\%03o", (unsigned)(unsigned char)ch);
result += buf;
}
break;
}
}
return result;
}
unsigned
StringUtility::hexadecimalToInt(char ch) {
if (isxdigit(ch)) {
if (isdigit(ch))
return ch-'0';
if (isupper(ch))
return ch-'A'+10;
return ch-'a'+10;
}
return 0;
}
// DQ (2/23/2014): Fixed conflict in commit for 128 bit integer support.
// string StringUtility::addrToString(uint64_t value, size_t nbits, bool is_signed)
std::string
StringUtility::toHex2(uint64_t value, size_t nbits, bool show_unsigned_decimal, bool show_signed_decimal,
uint64_t decimal_threshold)
{
assert(nbits>0 && nbits<=8*sizeof value);
uint64_t sign_bit = ((uint64_t)1 << (nbits-1));
// Hexadecimal value
std::string retval;
int nnibbles = (nbits+3)/4;
char buf[64];
snprintf(buf, sizeof buf, "0x%0*" PRIx64, nnibbles, value);
buf[sizeof(buf)-1] = '\0';
retval = buf;
// unsigned decimal
bool showed_unsigned = false;
if (show_unsigned_decimal && value >= decimal_threshold) {
retval = appendAsmComment(retval, numberToString(value));
showed_unsigned = true;
}
// signed decimal
if (show_signed_decimal) {
if (0 == (value & sign_bit)) {
// This is a positive value. Don't show it if we did already.
if (!showed_unsigned && value >= decimal_threshold)
retval = appendAsmComment(retval, numberToString(value));
} else {
// This is a negative value, so show it as negative. We have to manually sign extend it first.
int64_t signed_value = (value | (-1ll & ~(sign_bit-1)));
retval = appendAsmComment(retval, numberToString(signed_value));
}
}
return retval;
}
std::string
StringUtility::signedToHex2(uint64_t value, size_t nbits)
{
return toHex2(value, nbits, false, true);
}
std::string
StringUtility::unsignedToHex2(uint64_t value, size_t nbits)
{
return toHex2(value, nbits, true, false);
}
string
StringUtility::addrToString(uint64_t value, size_t nbits)
{
if (0 == nbits)
nbits = value > 0xffffffff ? 64 : 32;
return toHex2(value, nbits, false, false);
}
string
StringUtility::removeRedundantSubstrings(const std::string &s) {
// Convert the string into a list of strings and separate out the redundant entries
list<string> XStringList = StringUtility::stringToList(s);
XStringList.sort();
XStringList.unique();
return StringUtility::listToString(XStringList);
}
// [Robb Matzke 2016-01-06]: deprecated (misspelled)
std::string
StringUtility::removeRedundentSubstrings(std::string X) {
return removeRedundantSubstrings(X);
}
//Rama: 12/06/06:
//Donot know where this function is used, but we should be using the stdlib function isdigit
bool
isNumber ( char c )
{
return (isdigit(c));
}
bool
isxNumber ( char c )
{
return (isxdigit(c));
}
bool
isMarker ( char c )
{
return (c == '$');
}
// [Robb Matzke 2016-01-06]: deprecated (misspelled)
std::string
StringUtility::removePseudoRedundentSubstrings ( std::string X ) {
return removePseudoRedundantSubstrings(X);
}
string
StringUtility::removePseudoRedundantSubstrings(const std::string &s) {
// Convert the string into a list of strings and separate out the redundant entries
list<string> XStringList = StringUtility::stringToList(s);
#if 0
printf ("XStringList.size() = %" PRIuPTR " \n",XStringList.size());
#endif
XStringList.sort();
#if 0
printf ("After sort(): XStringList.size() = %" PRIuPTR " \n",XStringList.size());
#endif
XStringList.unique();
#if 0
printf ("After unique(): XStringList.size() = %" PRIuPTR " \n",XStringList.size());
#endif
// Build a list of the strings that will be modified
list<string> modifiedStringList;
list<string> listOfStringsToRemove;
list<string>::iterator i;
#if 0
for (i = XStringList.begin(); i != XStringList.end(); i++)
{
printf ("AT TOP: (*i = %s) (size: %d) \n",(*i).c_str(),(*i).length());
}
#endif
// Two loops over the list of strings represents a quadratic complexity!
for (i = XStringList.begin(); i != XStringList.end(); i++)
{
string i_modifiedString;
// printf ("At top of loop over XStringList \n");
// Build list of the differences between strings
list<string> listOfDifferences;
for (list<string>::iterator j = XStringList.begin(); j != XStringList.end(); j++)
{
// compare *i and *j and check for pseudo-redundence
// printf ("top of loop through string: compare *i and *j and check for pseudo-redundence \n");
// build information about *i
string::const_iterator i_diffpos = find_if ( (*i).begin(), (*i).end(), isNumber );
// build information about *j
string::const_iterator j_diffpos = find_if ( (*j).begin(), (*j).end(), isNumber );
#if 0
printf ("Testing (*i = %s) == (*j = %s) ) (sizes are: %d and %d) \n",
(*i).c_str(),(*j).c_str(),(*i).length(),(*j).length());
#endif
unsigned int i_subStringLength = i_diffpos - (*i).begin();
unsigned int j_subStringLength = j_diffpos - (*j).begin();
// printf ("i_subStringLength = %d j_subStringLength = %d \n",i_subStringLength,j_subStringLength);
// Must be the same length string AND
// the same length substring occuring before the first number AND
// there must have been a number in the string
if ( ((*i).size() == (*j).size()) &&
(i_subStringLength == j_subStringLength) &&
(i_diffpos != (*i).end()) )
{
// printf ("substrings could be the same ... \n");
i_modifiedString = *i; i_modifiedString[i_subStringLength] = '$';
string j_modifiedString = *j; j_modifiedString[j_subStringLength] = '$';
#if 0
printf ("Testing (i_modifiedString = %s) == (j_modifiedString = %s) \n",
i_modifiedString.c_str(),j_modifiedString.c_str());
#endif
// After modifying the strings (uniformly) see if we have a match
if ( i_modifiedString == j_modifiedString )
{
// (*i) and (*j) match upto the value of the number
// record this as a modified string
// modifiedStringList.push_back(i_modifiedString);
// Remove these strings (after we finish these nested loops)
listOfStringsToRemove.push_back(*i);
// Build a string from the number that differentiates the two strings
string i_numberString(1, *i_diffpos);
string j_numberString(1, *j_diffpos);
#if 0
printf ("Found a pseudo match between two strings: diff = %s and %s between %s and %s \n",
i_numberString.c_str(),j_numberString.c_str(),(*i).c_str(),(*j).c_str());
#endif
// Save the differences between the pseudo matching strings
listOfDifferences.push_back(i_numberString);
listOfDifferences.push_back(j_numberString);
}
}
#if 0
else
{
printf ("No similar substrings found! \n");
}
printf ("bottom of loop through string: compare *i and *j and check for pseudo-redundence \n");
#endif
}
// printf ("listOfDifferences.size() = %" PRIuPTR " \n",listOfDifferences.size());
// If there are any elements then we can proceed
if (!listOfDifferences.empty())
{
#if 0
printf ("Base of test of *i and *j (before sort): listOfDifferences = \n%s \n",listToString(listOfDifferences).c_str());
#endif
listOfDifferences.sort();
#if 0
printf ("Base of test of *i and *j (after sort): listOfDifferences = \n%s \n",listToString(listOfDifferences).c_str());
#endif
listOfDifferences.unique();
#if 0
printf ("Base of test of *i and *j (after unique): listOfDifferences = \n%s \n",listToString(listOfDifferences).c_str());
#endif
string maxvalue = listOfDifferences.back();
ROSE_ASSERT (!maxvalue.empty());
#if 0
printf ("Max value = %s \n",maxvalue.c_str());
#endif
// char* diffpos = find_if ( modifiedString.c_str(), modifiedString.c_str()+modifiedString.length(), isMarker );
string::iterator diffpos = find_if (i_modifiedString.begin(), i_modifiedString.end(), isMarker );
#if 0
printf ("Before copyEdit: diffpos = %c final string = %s \n",*diffpos,modifiedString.c_str());
#endif
*diffpos = maxvalue[0];
// modifiedString = copyEdit(modifiedString,string("$Y"),maxvalue);
#if 0
printf ("Final string = %s \n",modifiedString.c_str());
#endif
modifiedStringList.push_back(i_modifiedString);
}
#if 0
else
{
printf ("No differences to process \n");
}
printf ("At base of loop over XStringList \n");
#endif
}
#if 0
printf ("Now sort and remove non-unique elements \n");
#endif
// Remove strings we identified for removal
listOfStringsToRemove.sort();
listOfStringsToRemove.unique();
#if 0
printf ("After loop: listOfStringsToRemove.size() = %" PRIuPTR " \n",listOfStringsToRemove.size());
#endif
for (i = listOfStringsToRemove.begin(); i != listOfStringsToRemove.end(); i++)
{
XStringList.remove(*i);
}
#if 0
printf ("After loop: XStringList.size() = %" PRIuPTR " \n",XStringList.size());
printf ("After loop: XStringList = %s \n",listToString(XStringList).c_str());
#endif
// Add the strings the we saved (the resort)
XStringList.insert(XStringList.end(), modifiedStringList.begin(), modifiedStringList.end());
#if 0
printf ("Before remove(): XStringList.size() = %" PRIuPTR " \n",XStringList.size());
printf ("Before remove(): XStringList = %s \n",listToString(XStringList).c_str());
#endif
XStringList.remove(string("\n"));
#if 0
printf ("Before sort(): XStringList.size() = %" PRIuPTR " \n",XStringList.size());
printf ("Before sort(): XStringList = %s \n",listToString(XStringList).c_str());
#endif
XStringList.sort();
#if 0
printf ("After sort(): XStringList.size() = %" PRIuPTR " \n",XStringList.size());
printf ("After sort(): XStringList = %s \n",listToString(XStringList).c_str());
#endif
XStringList.unique();
#if 0
printf ("After unique(): XStringList.size() = %" PRIuPTR " \n",XStringList.size());
printf ("After unique(): XStringList = %s \n",listToString(XStringList).c_str());
#endif
#if 0
for (i = XStringList.begin(); i != XStringList.end(); i++)
{
printf ("AT BOTTOM: (*i = %s) (size: %d) \n",(*i).c_str(),(*i).length());
}
printf ("Returning from StringUtility::removePseudoRedundentSubstrings() (calling listToString member function) \n");
#endif
return StringUtility::listToString(XStringList);
}
#if 0
int
StringUtility::isSameName ( const std::string& s1, const std::string& s2 )
{
int returnValue = false;
// return strcmp(fname, fileName) == 0;
// The strings are the same only if ZERO is the return value from strcmp()
if (s1 == s2)
{
returnValue = true;
}
return returnValue;
}
#endif
// Macro used only in the copyEdit function
#define DEBUG_COPY_EDIT false
// BP : 10/25/2001, a non recursive version that
// allocs memory only once
string
StringUtility::copyEdit (
const string& inputString,
const string& oldToken,
const string& newToken )
{
// std::cerr << "StringUtility::copyEdit '" << inputString << "' '" << oldToken << "' '" << newToken << "'" << std::endl;
string returnString;
std::string::size_type oldTokenSize = oldToken.size();
std::string::size_type position = 0;
std::string::size_type lastPosition = 0;
while (true) {
position = inputString.find(oldToken, position);
if (position == string::npos) {
returnString += inputString.substr(lastPosition);
break;
} else {
returnString += inputString.substr(lastPosition, position - lastPosition);
returnString += newToken;
position = lastPosition = position + oldTokenSize;
}
}
return returnString;
}
void
StringUtility::writeFile (
const string& outputString,
const string& fileNameString,
const string& directoryName)
{
// char* directoryName = strdup(directoryName);
#if 0
// char* filenamePrefix = "generatedCode.headers/";
char* filenamePrefix = new char [strlen(directoryName)+2];
strcpy(filenamePrefix,directoryName);
strcat(filenamePrefix,"/");
#else
// char* filenamePrefix = "";
#endif
string outputFileName = directoryName + fileNameString;
ofstream outputFile(outputFileName.c_str());
ROSE_ASSERT (outputFile.good() == true);
// Select an output stream for the program tree display (cout or <filename>.C.roseShow)
// Macro OUTPUT_SHOWFILE_TO_FILE is defined in the transformation_1.h header file
// ostream & outputStream = (OUTPUT_TO_FILE ? ((ostream&) outputFile) : ((ostream&) cout));
ROSE_ASSERT (outputFile.good() == true);
outputFile << outputString;
ROSE_ASSERT (outputFile.good() == true);
outputFile.close();
}
StringUtility::FileWithLineNumbers
StringUtility::copyEdit (
const StringUtility::FileWithLineNumbers& inputString,
const string& oldToken,
const string& newToken ) {
StringUtility::FileWithLineNumbers result = inputString;
for (unsigned int i = 0; i < result.size(); ++i) {
result[i].str = copyEdit(result[i].str, oldToken, newToken);
}
return result;
}
StringUtility::FileWithLineNumbers
StringUtility::copyEdit (
const StringUtility::FileWithLineNumbers& inputString,
const string& oldToken,
const StringUtility::FileWithLineNumbers& newToken ) {
StringUtility::FileWithLineNumbers result = inputString;
for (unsigned int i = 0; i < result.size(); ++i) {
string str = result[i].str;
std::string::size_type pos = str.find(oldToken);
if (pos != string::npos) {
// Split the line into the before-substitution and after-substitution regions
result[i].str = str.substr(0, pos);
result.insert(result.begin() + i + 1, StringUtility::StringWithLineNumber(str.substr(pos + oldToken.size()), result[i].filename + " after subst for " + oldToken, result[i].line));
// result[i].filename += " before subst for " + oldToken;
// Do the insertion
result.insert(result.begin() + i + 1, newToken.begin(), newToken.end());
i += newToken.size(); // Rescan the after-substitution part of the old line, but not any of the new text
}
}
return result;
}
string
StringUtility::readFile ( const string& fileName )
{
// Reads entire text file and places contents into a single string
// BP : 10/23/2001, rather than allocate fixed large blocks of memory (350K * sizeof(char) !!)
// allocate what is required.
// the code below is a slightly modified version of what I found at:
// http://www.cplusplus.com/ref/iostream/istream/read.html
char* buffer = NULL;
ifstream inputFile;
inputFile.open( fileName.c_str(), ios::binary );
if (inputFile.good() != true)
{
printf ("ERROR: File not found -- %s \n",fileName.c_str());
//ROSE_ABORT();
std::string s( "ERROR: File not found -- " );
s += fileName;
throw s;
}
ROSE_ASSERT (inputFile.good() == true);
// get length of file:
inputFile.seekg (0, ios::end);
std::streamoff length = inputFile.tellg();
inputFile.seekg (0, ios::beg);
// allocate memory:
buffer = new char [length+1];
ROSE_ASSERT(buffer != NULL);
// read data as a block:
inputFile.read(buffer,(int)length);
buffer[length] = '\0';
inputFile.close();
// DQ: (10/21/02) Sunjeev reported the following assertion as failing on
// his machine at UCSD (works for us, but i have made it more general)
// ROSE_ASSERT(strlen(buffer) <= length);
// MS: (12/11/02) added the strict test again
ROSE_ASSERT(strlen(buffer) == (unsigned) length);
string returnString = buffer;
return returnString;
}
StringUtility::FileWithLineNumbers
StringUtility::readFileWithPos ( const string& fileName )
{
// Reads entire text file and places contents into a single string
// BP : 10/23/2001, rather than allocate fixed large blocks of memory (350K * sizeof(char) !!)
// allocate what is required.
// the code below is a slightly modified version of what I found at:
// http://www.cplusplus.com/ref/iostream/istream/read.html
unsigned int line = 1;
char* buffer = NULL;
string fullFileName = StringUtility::getAbsolutePathFromRelativePath(fileName);
// printf("Opening file : %s\n",fullFileName.c_str());
ifstream inputFile;
inputFile.open( fileName.c_str(), ios::binary );
if (inputFile.good() != true)
{
printf ("ERROR: File not found -- %s \n",fileName.c_str());
// ROSE_ABORT();
std::string s( "ERROR: File not found -- " );
s += fileName;
throw s;
}
ROSE_ASSERT (inputFile.good() == true);
// get length of file:
inputFile.seekg (0, ios::end);
std::streamoff length = inputFile.tellg();
inputFile.seekg (0, ios::beg);
// allocate memory:
buffer = new char [length+1];
ROSE_ASSERT(buffer != NULL);
// read data as a block:
inputFile.read(buffer,(int)length);
buffer[length] = '\0';
inputFile.close();
// DQ: (10/21/02) Sunjeev reported the following assertion as failing on
// his machine at UCSD (works for us, but i have made it more general)
// ROSE_ASSERT(strlen(buffer) <= length);
// MS: (12/11/02) added the strict test again
ROSE_ASSERT(strlen(buffer) == (unsigned) length);
string returnString = buffer;
delete[] buffer;
StringUtility::FileWithLineNumbers result;
for (std::string::size_type pos = 0; pos != string::npos; )
{
std::string::size_type lastPos = pos;
pos = returnString.find('\n', lastPos);
result.push_back(StringUtility::StringWithLineNumber(returnString.substr(lastPos, pos - lastPos), fullFileName, line));
// cerr << "Added line '" << returnString.substr(lastPos, pos - lastPos) << "' at line " << line << endl;
++line;
++pos; // Skip newline
if (pos == returnString.size()) break;
}
result.push_back(StringUtility::StringWithLineNumber("", "", 1));
return result;
}
std::string
StringUtility::StringWithLineNumber::toString() const
{
std::ostringstream os;
// DQ (1/21/2010): Added support for skipping these when in makes it easer to debug ROSETTA generated files.
#ifdef SKIP_HASH_LINE_NUMBER_DECLARATIONS_IN_GENERATED_FILES
// os << str << std::endl;
os << "/* #line " << line << " \"" << (filename.empty() ? "" : getAbsolutePathFromRelativePath(filename)) << "\" */\n" << str << std::endl;
#else
os << "#line " << line << " \"" << (filename.empty() ? "" : getAbsolutePathFromRelativePath(filename)) << "\"\n" << str << std::endl;
#endif
return os.str();
}
std::string
StringUtility::toString(const StringUtility::FileWithLineNumbers& strings,
const std::string& filename,
int physicalLine /* Line number in output file */) {
std::string result;
unsigned int lastLineNumber = 1;
std::string lastFile = "";
bool inPhysicalFile = true; // Not in a specifically named file
bool needLineDirective = false;
for (unsigned int i = 0; i < strings.size(); ++i) {
// Determine if a #line directive is needed, if the last iteration did not
// force one to be added
bool newInPhysicalFile = (strings[i].filename == "");
if (inPhysicalFile != newInPhysicalFile)
needLineDirective = true;
if (!inPhysicalFile &&
(strings[i].filename != lastFile ||
strings[i].line != lastLineNumber))
needLineDirective = true;
if (strings[i].str == "" && i + 1 == strings.size()) { // Special case
needLineDirective = false;
}
// Print out the #line directive (if needed) and the actual line
if (needLineDirective) {
#ifdef SKIP_HASH_LINE_NUMBER_DECLARATIONS_IN_GENERATED_FILES
/* Nothing to do here! */
if (strings[i].filename == "") { // Reset to actual input file
result += "/* #line " + numberToString(physicalLine + 1 /* Increment because number is the line number of the NEXT line after the #line directive */) + " \"" + filename + "\" */\n";
} else {
result += "/* #line " + numberToString(strings[i].line) + " \"" + strings[i].filename + "\" */\n";
}
#else
if (strings[i].filename == "") { // Reset to actual input file
result += "#line " + numberToString(physicalLine + 1 /* Increment because number is the line number of the NEXT line after the #line directive */) + " \"" + filename + "\"\n";
} else {
result += "#line " + numberToString(strings[i].line) + " \"" + strings[i].filename + "\"\n";
}
#endif
// These are only updated when a #line directive is actually printed,
// largely because of the blank line exception above (so if a blank line
// starts a new file, the #line directive needs to be emitted on the
// first non-blank line)
lastLineNumber = strings[i].line + 1;
lastFile = strings[i].filename;
} else {
++lastLineNumber;
}
result += strings[i].str + "\n";
bool printedLineDirective = needLineDirective;
// Determine if a #line directive is needed for the next iteration
needLineDirective = false;
inPhysicalFile = newInPhysicalFile;
if (strings[i].str.find('\n') != std::string::npos && !inPhysicalFile) {
needLineDirective = true; // Ensure that the next line has a #line directive
}
// Update the physical line counter based on the number of lines output
if (printedLineDirective) ++physicalLine; // For #line directive
for (size_t pos = strings[i].str.find('\n');
pos != std::string::npos; pos = strings[i].str.find('\n', pos + 1)) {
++physicalLine; // Increment for \n in string
}
++physicalLine; // Increment for \n added at end of line
}
return result;
}
string
StringUtility::indentMultilineString ( const string& inputString, int statementColumnNumber )
{
// Indent the transformation to match the statement that it is transforming
string returnString;
// Put in linefeeds to avoid endless recursion in the copyEdit (I think)
ROSE_ASSERT (statementColumnNumber > 0);
string cr_and_added_space = string(statementColumnNumber, ' ');
cr_and_added_space[0] = '\t';
// returnString = copyEdit (inputString,"\n",cr_and_added_space);
returnString = copyEdit (inputString,"\n",cr_and_added_space);
// Now exchange the line feeds for carriage returns
// returnString = copyEdit (returnString,"\t","\n");
returnString = copyEdit (returnString,"\t","\n");
// Now indent the first line (since there was no CR) there
returnString = cr_and_added_space.substr(1) + returnString;
// printf ("In StringUtility::indentMultilineString(): returnString = %s \n",returnString);
return returnString;
}
void
StringUtility::splitStringIntoStrings(
const string& inputString,
char separator,
vector<string>& stringList )
{
// This function was written by Bobby Philip in support of the newer approach toward
// handling a broader number of back-end C++ compilers.
stringList.clear();
std::string::size_type pos = 0, lastPos = 0;
while (true) {
pos = inputString.find(separator, pos);
if (pos == string::npos) {
stringList.push_back(inputString.substr(lastPos));
return;
} else {
if (pos != lastPos) {
stringList.push_back(inputString.substr(lastPos, pos - lastPos));
}
lastPos = pos = pos + 1;
}
}
}
#if 0
// DQ (2/18/2006): Added simple checksum (good enough for short strings)
unsigned short int
StringUtility::chksum(char *buffer, int len)
{
// This is a simple checksum function (obtained off the web):
// This is a very inefficient routine that does the checksumming. The
// linux checksum is very much more powerful and quicker. However this
// gives you the general idea. Note that if you are going to checksum
// a checksummed packet that includes the checksum, you have to compliment
// the output. Also note that this works ONLY for an even number of bytes.
ROSE_ASSERT(len % 2 == 0);
unsigned short int *word;
unsigned long accum;
unsigned long chksm;
int i;
accum = 0;
word = (unsigned short *) buffer;
len >>= 1; /* Words only */
for (i=0; i< len; i++)
accum += (unsigned long) *word++;
chksm = (accum & 0xffff); /* Mask all but low word */
chksm += (accum >> 16); /* Sum all the carries */
if (chksm > 0xffff) /* If this also carried */
chksm++; /* Sum this too */
return (unsigned short) (chksm & 0xffff);
}
#endif
// DQ (2/18/2006): Added general name mangling for all declarations (and some other IR nodes).
// JJW (10/15/2007): Does this compute a ones-complement checksum like used for TCP?
unsigned long
StringUtility::generate_checksum( string s )
{
string uniqueName = s;
// The checksum function requires a even length string (so we have to fix it up)
if (uniqueName.size() % 2 != 0)
{
// printf ("Adding another character to make string an even valued length \n");
// Use a character that does not appear in mangled
// names so that no other mangled name could include it.
uniqueName += "#";
}
ROSE_ASSERT(uniqueName.size() % 2 == 0);
// Call a simple checksum function
// unsigned short int checksum = StringUtility::chksum(buffer,uniqueName.size());
unsigned long accum = 0;
unsigned long chksm;
accum = 0;
unsigned int len = uniqueName.size() / 2; /* Words only */
for (unsigned int i=0; i< len; i++)
accum += (unsigned long) (((unsigned short*)uniqueName.data())[i]);
chksm = (accum & 0xffff); /* Mask all but low word */
chksm += (accum >> 16); /* Sum all the carries */
if (chksm > 0xffff) /* If this also carried */
chksm++; /* Sum this too */
unsigned short checksum = (unsigned short) (chksm & 0xffff);
// printf ("Checksum = %d \n",checksum);
return (unsigned long) checksum;
}
//Rama: 12/06/06
//Replaced the functionality by a call to basename
string
StringUtility::stripPathFromFileName ( const string & fileNameWithPath )
{
// printf ("StringUtility::stripPathFromFileName(fileNameWithPath = %s) \n",fileNameWithPath.c_str());
#if 1
// DQ (9/6/2008): It seems that the problem might have been the stripFileSuffixFromFileName(), so this is put back!
// DQ (9/6/2008): This version does not work on paths that have "." in them (basename() function does not work well).
// Example of input that fails: ROSE/ROSE_CompileTree/svn-LINUX-64bit-4.2.2/tutorial/inputCode_binaryAST_1
// returns: svn-LINUX-64bit-4.2
string returnString;
char c_version[PATH_MAX];
ROSE_ASSERT (fileNameWithPath.size() + 1 < PATH_MAX);
strcpy(c_version, fileNameWithPath.c_str());
#if ROSE_MICROSOFT_OS
// printf ("Error: basename() not available in MSVS (work around not implemented) \n");
// ROSE_ASSERT(false);
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath(c_version,drive,dir,fname,ext);
// tps (08/17/2010) - Made this work under Windows.
string fnamestr(fname);
string extstr(ext);
returnString = fnamestr+extstr;
#else
returnString = basename(c_version);
#endif
return returnString;
#endif
#if 0
// DQ (9/6/2008): Use this version of the code which handles more complex patha names.
// Make it safe to input a filename without a path name (return the filename)
string::size_type positionOfLastSlash = fileNameWithPath.rfind('/');
string::size_type positionOfFirstSlash = fileNameWithPath.find('/');
printf ("positionOfLastSlash = %" PRIuPTR " \n",positionOfLastSlash);
printf ("positionOfFirstSlash = %" PRIuPTR " \n",positionOfFirstSlash);
string returnString;
if (positionOfLastSlash != string::npos)
{
returnString = fileNameWithPath.substr(positionOfLastSlash+1);
}
else
{
returnString = fileNameWithPath;
}
printf ("StringUtility::stripPathFromFileName() (after substr) returnString = %s \n",returnString.c_str());
if (positionOfFirstSlash < positionOfLastSlash)
{
printf (" Look for leading \'/\' from the front \n");
while (returnString[0] == '/')
{
returnString.erase(0,1);
}
printf ("StringUtility::stripPathFromFileName() (after erase) returnString = %s \n",returnString.c_str());
}
printf ("StringUtility::stripPathFromFileName() returnString = %s \n",returnString.c_str());
return returnString;
#endif
#if 0
// This is a older version using C style strings
const size_t len = fileNameWithPath.size();
const char *startOfString = &(fileNameWithPath[0]);
const char *search = &(fileNameWithPath[len]);
while ((search >= startOfString) && ('/' != *search))
{
--search;
}
++search;
char *returnString = new char[1 + len - (search - startOfString)];
ROSE_ASSERT(returnString != NULL);
return strcpy(returnString, search);
#endif
}
string
StringUtility::stripFileSuffixFromFileName ( const string & fileNameWithSuffix )
{
// Make it safe to input a filename without a suffix (return the filename)
string returnString;
#if 0
// This function is not sophisticated enough to handle binaries with paths such as:
// ROSE/ROSE_CompileTree/svn-LINUX-64bit-4.2.2/tutorial/inputCode_binaryAST_1
string::size_type positionOfDot = fileNameWithSuffix.rfind('.');
if (positionOfDot != string::npos)
returnString = fileNameWithSuffix.substr(0,positionOfDot);
else
returnString = fileNameWithSuffix;
#else
// Handle the case of files where the filename does not have a suffix
size_t lastSlashPos = fileNameWithSuffix.rfind('/');
size_t lastDotPos = fileNameWithSuffix.rfind('.');
// printf ("lastSlashPos = %" PRIuPTR " \n",lastSlashPos);
// printf ("lastDotPos = %" PRIuPTR " \n",lastDotPos);
if (lastSlashPos != string::npos && lastDotPos < lastSlashPos)
returnString = fileNameWithSuffix;
else
returnString = fileNameWithSuffix.substr(0, lastDotPos);
#endif
// printf ("fileNameWithSuffix = %s returnString = %s \n",fileNameWithSuffix.c_str(),returnString.c_str());
return returnString;
// Extra code not used but which was a part of StringUtility::stripFileSuffixFromFileName()
#if 0
const char *startOfString = &(fileNameWithPath[0]);
const char *lastDot = strrchr(startOfString, '.');
const size_t lengthOfFileWithoutSuffix = ((lastDot == NULL) ? fileNameWithPath.size() : (lastDot - fileNameWithSuffix));
string returnString = fileNameWithSuffix.substr(
char *returnString = new char[lengthOfFileWithoutSuffix + 1];
ROSE_ASSERT(NULL != returnString);
returnString[lengthOfFileWithoutSuffix] = '\0';
return (char *)memcpy(returnString, fileNameWithSuffix,
lengthOfFileWithoutSuffix);
#endif
}
//
//Rama: I am not sure if this mechanism can deal with files ending with .
//Like "test."
//I am not clear about the purpose of the function too. So, not modifying it.
string
StringUtility::fileNameSuffix ( const string & fileNameWithSuffix )
{
// Make it safe to input a filename without a suffix (return the filename)
string::size_type positionOfDot = fileNameWithSuffix.rfind('.');
string returnString = fileNameWithSuffix;
// allow input to not have an extension
if (positionOfDot != string::npos)
{
// Advance past the "."
positionOfDot++;
returnString = fileNameWithSuffix.substr(positionOfDot);
}
return returnString;
}
// DQ (3/15/2005): New, simpler and better implementation suggested function from Tom, thanks Tom!
string
StringUtility::getPathFromFileName ( const string & fileNameWithPath )
{
char c_version[PATH_MAX];
ROSE_ASSERT (fileNameWithPath.size() + 1 < PATH_MAX);
strcpy(c_version, fileNameWithPath.c_str());
#if ROSE_MICROSOFT_OS
char drive[_MAX_DRIVE];
char dir[_MAX_DIR];
char fname[_MAX_FNAME];
char ext[_MAX_EXT];
_splitpath(c_version,drive,dir,fname,ext);
// printf ("Error: dirname() not supported in MSVS 9work around not implemented) \n");
// printf ("dirname = %s \n",dir);
// tps (08/17/2010) - Made this work under Windows.
string drivestr(drive);
string dirstr(dir);
string returnString = drivestr+dirstr;
// ROSE_ASSERT(false);
#else
string returnString = dirname(c_version);
#endif
//dirname returns a "." if fileNameWithPath does not contain "/"'s
//I am not sure why this function was written and so, preserve the functionality using empty return string in such cases.
if(returnString == ".")
returnString = "";
return returnString;
#if 0
string::size_type positionOfSlash = fileNameWithPath.rfind('/');
string returnString;
if (positionOfSlash != string::npos)
returnString = fileNameWithPath.substr(0,positionOfSlash+1);
else
returnString = "";
return returnString;
#endif
#if 0
const char *lastSlash = strrchr(fileNameWithPath, '/');
const ptrdiff_t len = (lastSlash == NULL) ? 0 : (1 + lastSlash - fileNameWithPath);
char *result = new char[len + 1];
ROSE_ASSERT(NULL != result);
result[len] = '\0';
return (char *)memcpy(result, fileNameWithPath, len);
#endif
}
string
StringUtility::escapeNewLineCharaters ( const string & X )
{
string returnString;
int stringLength = X.length();
for (int i=0; i < stringLength; i++)
{
if ( X[i] == '\n' )
{
returnString += "\\l";
}
else
{
if ( X[i] == '\"' )
{
returnString += "\\\"";
}
else
{
returnString += X[i];
}
}
}
return returnString;
}
std::string StringUtility::intToHex(uint64_t i) {
ostringstream os;
os << "0x" << std::hex << i;
return os.str();
}
string
StringUtility::convertToLowerCase( const string & inputString )
{
// DQ (11/12/2008): Used to convert module names to lower case.
// printf ("Before conversion to lower case: inputString = %s \n",inputString.c_str());
string returnString = inputString;
for (size_t i=0; i < returnString.length(); i++)
{
returnString[i] = tolower(returnString[i]);
}
// printf ("After conversion to lower case: returnString = %s \n",returnString.c_str());
return returnString;
}
std::string
StringUtility::prefixLines(const std::string &lines, const std::string &prefix, bool prefixAtFront, bool prefixAtBack)
{
if (lines.empty())
return "";
std::string retval = prefixAtFront ? prefix : "";
size_t at=0;
while (at<lines.size()) {
size_t lfpos = lines.find_first_of("\r\n", at);
lfpos = lines.find_first_not_of("\r\n", lfpos);
retval += lines.substr(at, lfpos-at);
if (lfpos<lines.size())
retval += prefix;
at = lfpos;
}
if (prefixAtBack && isLineTerminated(lines))
retval += prefix;
return retval;
}
bool
StringUtility::isLineTerminated(const std::string &s)
{
return !s.empty() && ('\n'==s[s.size()-1] || '\r'==s[s.size()-1]);
}
std::string
StringUtility::fixLineTermination(const std::string &input)
{
std::string output;
size_t nchars = input.size();
for (size_t i=0; i<nchars; ++i) {
if ('\r'==input[i] && i+1<nchars && '\n'==input[i+1]) {
// CR+LF: Microsoft Windows, DEC TOPS-10, RT-11 and most other early non-Unix and non-IBM OSes, CP/M, MP/M, DOS
// (MS-DOS, PC-DOS, etc.), Atari TOS, OS/2, Symbian OS, Palm OS.
output += '\n';
++i;
} else if ('\n'==input[i] && i+1<nchars && '\r'==input[i+1]) {
// LF+CR: Acorn BBC and RISC OS spooled text output.
output += '\n';
++i;
} else if ('\r'==input[i]) {
// CR (only): Commodore 8-bit machines, Acorn BBC, TRS-80, Apple II family, Mac OS up to version 9 and OS-9
output += '\n';
} else {
output += input[i];
}
}
return output;
}
std::string
StringUtility::makeOneLine(const std::string &s, std::string replacement)
{
std::string result, spaces;
bool eat_spaces = false;
for (size_t i=0; i<s.size(); ++i) {
if ('\n'==s[i] || '\r'==s[i]) {
spaces = result.empty() ? "" : replacement;
eat_spaces = true;
} else if (isspace(s[i])) {
if (!eat_spaces)
spaces += s[i];
} else {
result += spaces + s[i];
spaces = "";
eat_spaces = false;
}
}
if (!eat_spaces)
result += spaces;
return result;
}
void
StringUtility::add_to_reason_string(std::string &result, bool isset, bool do_pad,
const std::string &abbr, const std::string &full)
{
if (isset) {
if (do_pad) {
result += abbr;
} else {
if (result.size()>0) result += ", ";
result += full;
}
} else if (do_pad) {
for (size_t i=0; i<abbr.size(); ++i)
result += ".";
}
}
std::string
StringUtility::encode_base64(const std::vector<uint8_t> &data, bool do_pad)
{
return encode_base64(&data[0], data.size(), do_pad);
}
std::string
StringUtility::encode_base64(const uint8_t *data, size_t nbytes, bool do_pad)
{
static const char *digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string s;
unsigned val = 0; // only low-order 24 bits used
for (size_t i=0; i<nbytes; ++i) {
switch (i%3) {
case 0:
val = IntegerOps::shiftLeft2<unsigned>(data[i], 16);
break;
case 1:
val |= IntegerOps::shiftLeft2<unsigned>(data[i], 8);
break;
case 2:
val |= data[i];
s += digits[IntegerOps::shiftRightLogical2(val, 18) & 0x3f];
s += digits[IntegerOps::shiftRightLogical2(val, 12) & 0x3f];
s += digits[IntegerOps::shiftRightLogical2(val, 6) & 0x3f];
s += digits[val & 0x3f];
break;
}
}
switch (nbytes % 3) {
case 0:
break;
case 1:
s += digits[IntegerOps::shiftRightLogical2(val, 18) & 0x3f];
s += digits[IntegerOps::shiftRightLogical2(val, 12) & 0x3f];
if (do_pad)
s += "==";
break;
case 2:
s += digits[IntegerOps::shiftRightLogical2(val, 18) & 0x3f];
s += digits[IntegerOps::shiftRightLogical2(val, 12) & 0x3f];
s += digits[IntegerOps::shiftRightLogical2(val, 6) & 0x3f];
if (do_pad)
s += "=";
break;
}
return s;
}
std::vector<uint8_t>
StringUtility::decode_base64(const std::string &s)
{
std::vector<uint8_t> retval;
retval.reserve((s.size()*3)/4+3);
unsigned val=0, ndigits=0;
for (size_t i=0; i<s.size(); ++i) {
unsigned digit;
if (s[i]>='A' && s[i]<='Z') {
digit = s[i]-'A';
} else if (s[i]>='a' && s[i]<='z') {
digit = s[i]-'a' + 26;
} else if (s[i]>='0' && s[i]<='9') {
digit = s[i]-'0' + 52;
} else if (s[i]=='+') {
digit = 62;
} else if (s[i]=='/') {
digit = 63;
} else {
continue;
}
// only reached for valid base64 characters
val |= IntegerOps::shiftLeft2(digit, 18-6*ndigits);
if (4==++ndigits) {
retval.push_back(IntegerOps::shiftRightLogical2(val, 16) & 0xff);
retval.push_back(IntegerOps::shiftRightLogical2(val, 8) & 0xff);
retval.push_back(val & 0xff);
val = ndigits = 0;
}
}
assert(0==ndigits || 2==ndigits || 3==ndigits);
if (ndigits>=2) {
retval.push_back(IntegerOps::shiftRightLogical2(val, 16) & 0xff);
if (ndigits==3)
retval.push_back(IntegerOps::shiftRightLogical2(val, 8) & 0xff);
}
return retval;
}
std::string
StringUtility::join(const std::string &separator, char *strings[], size_t nstrings)
{
return join_range(separator, strings, strings+nstrings);
}
std::string
StringUtility::join(const std::string &separator, const char *strings[], size_t nstrings)
{
return join_range(separator, strings, strings+nstrings);
}
std::vector<std::string>
StringUtility::split(char separator, const std::string &str, size_t maxparts, bool trim_white_space)
{
return split(std::string(1, separator), str, maxparts, trim_white_space);
}
std::vector<std::string>
StringUtility::split(const std::string &separator, const std::string &str, size_t maxparts, bool trim_white_space)
{
std::vector<std::string> retval;
if (0==maxparts || str.empty())
return retval;
if (separator.empty()) {
for (size_t i=0; i<str.size() && i<maxparts-1; ++i)
retval.push_back(str.substr(i, 1));
retval.push_back(str.substr(retval.size()));
} else {
size_t at = 0;
while (at<=str.size() && retval.size()+1<maxparts) {
if (at==str.size()) {
retval.push_back(""); // string ends with separator
break;
}
size_t sep_at = str.find(separator, at);
if (sep_at==std::string::npos) {
retval.push_back(str.substr(at));
at = str.size() + 1; // "+1" means string doesn't end with separator
break;
} else {
retval.push_back(str.substr(at, sep_at-at));
at = sep_at + separator.size();
}
}
if (at<str.size() && retval.size()<maxparts)
retval.push_back(str.substr(at));
}
if (trim_white_space) {
for (size_t i=0; i<retval.size(); ++i)
retval[i] = trim(retval[i]);
}
return retval;
}
std::string
StringUtility::trim(const std::string &str, const std::string &strip, bool at_beginning, bool at_end)
{
if (str.empty())
return str;
size_t first=0, last=str.size()-1;
if (at_beginning)
first = str.find_first_not_of(strip);
if (at_end && first!=std::string::npos)
last = str.find_last_not_of(strip);
if (first==std::string::npos || last==std::string::npos)
return "";
assert(last>=first);
return str.substr(first, last+1-first);
}
std::string
StringUtility::untab(const std::string &str, size_t tabstops, size_t colnum)
{
tabstops = std::max(tabstops, (size_t)1);
std::string retval;
for (size_t i=0; i<str.size(); ++i) {
switch (str[i]) {
case '\t': {
size_t nspc = tabstops - colnum % tabstops;
retval += std::string(nspc, ' ');
colnum += nspc;
break;
}
case '\n':
case '\r':
retval += str[i];
colnum = 0;
break;
default:
retval += str[i];
++colnum;
break;
}
}
return retval;
}
std::string
StringUtility::appendAsmComment(const std::string &s, const std::string &comment)
{
if (comment.empty())
return s;
if (s.empty())
return "<" + comment + ">";
if (s[s.size()-1] == '>')
return s.substr(0, s.size()-1) + "," + comment + ">";
return s + "<" + comment + ">";
}