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
796 lines
37 KiB
C++
796 lines
37 KiB
C++
#ifndef ROSE_StringUtility_H
|
|
#define ROSE_StringUtility_H
|
|
|
|
//#include "commandline_processing.h"
|
|
#include <ostream>
|
|
#include <stddef.h>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <list>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <stdint.h>
|
|
#include <limits.h>
|
|
|
|
#include "../rose.h"
|
|
|
|
|
|
/** Functions for operating on strings.
|
|
*
|
|
* This name space provides functions for operating on strings.
|
|
*
|
|
* It also provides some unrelated functions: functions for operating on file names (see also @ref rose::FileSystem and
|
|
* std::filesystem for better implementations), and functions for performing file I/O. These unrelated functions should
|
|
* eventually move to other name spaces. */
|
|
namespace StringUtility {
|
|
|
|
/** String with source location information.
|
|
*
|
|
* The location information is a file name string (empty means generated code) and a line number. Line numbers are one-origin;
|
|
* the first line of a file is numbered 1, not 0.
|
|
*
|
|
* @todo What does it mean to have a non-positive line number? What line number should be used for generated code when the @p
|
|
* filename member is empty? */
|
|
struct StringWithLineNumber {
|
|
std::string str; // DQ (1/23/2010): this name is difficult to trace within the code.
|
|
std::string filename; // Empty string means generated code
|
|
unsigned int line;
|
|
|
|
StringWithLineNumber(const std::string &str, const std::string &filename, unsigned int line)
|
|
: str(str), filename(filename), line(line) { }
|
|
|
|
std::string toString() const;
|
|
};
|
|
|
|
#ifndef USE_ROSE
|
|
typedef std::vector <StringWithLineNumber> FileWithLineNumbers;
|
|
#else
|
|
// workaround of bug 315, separating definitions for a namespace [Liao, 2/16/2009]
|
|
}
|
|
namespace StringUtility {
|
|
typedef std::vector<StringUtility::StringWithLineNumber> FileWithLineNumbers;
|
|
#endif
|
|
|
|
/** Prints a StringWithLineNumber. */
|
|
inline std::ostream &operator<<(std::ostream &os, const StringWithLineNumber &s) {
|
|
os << s.toString();
|
|
return os;
|
|
}
|
|
|
|
/** Generate C preprocessor #line directives.
|
|
*
|
|
* Given a vector of strings with source location information, print those strings with intervening C preprocessor #line
|
|
* directives. For strings that have no source location, use the specified @p filename argument as the name of the file. The
|
|
* @p physicalLine is the line number to assume for the first line of output (the return value). The #line directives are
|
|
* not emitted into the return value when they're not needed (e.g., two @p strings are at successive line numbers of the same
|
|
* source file) or if ROSE has been configured to not emit #line directivies (i.e., the @c
|
|
* SKIP_HASH_LINE_NUMBER_DECLARATIONS_IN_GENERATED_FILES preprocessor symbol is defined). The @p strings should not have
|
|
* trailing linefeeds or else the output will contain extra blank lines. */
|
|
std::string toString(const FileWithLineNumbers &strings, const std::string &filename = "<unknown>", int line = 1);
|
|
|
|
/** Append strings with source location information to vector of such.
|
|
*
|
|
* Modifies @p a by appending those strings from @p b. */
|
|
inline FileWithLineNumbers &operator+=(FileWithLineNumbers &a, const FileWithLineNumbers &b) {
|
|
a.insert(a.end(), b.begin(), b.end());
|
|
return a;
|
|
}
|
|
|
|
/** Concatenate vectors of strings with source location.
|
|
*
|
|
* Returns a new vector of strings with location information by concatenating vector @p a with @p b. */
|
|
inline FileWithLineNumbers operator+(const FileWithLineNumbers &a, const FileWithLineNumbers &b) {
|
|
FileWithLineNumbers f = a;
|
|
f += b;
|
|
return f;
|
|
}
|
|
|
|
/** Append string to vector of strings with location information.
|
|
*
|
|
* Appends @p str to the last string in the vector of strings with location information. If the vector is empty then a new
|
|
* element is created.
|
|
*
|
|
* The new code is marked as either generated (empty file name) or not generated (non-empty name) based on whether the vector
|
|
* was initially empty or whether the final element of the vector was generated. Adding a string to an empty vector makes it
|
|
* always be a generated string; adding it to a non-empty vector makes it generated or not generated depending on whether the
|
|
* last element of the vector is generated or not generated.
|
|
*
|
|
* The string @p str should not include line termination. (see @ref toString).
|
|
*
|
|
* @{ */
|
|
inline FileWithLineNumbers &operator<<(FileWithLineNumbers &f, const std::string &str) {
|
|
if (!f.empty() && f.back().filename == "") {
|
|
f.back().str += str;
|
|
} else {
|
|
f.push_back(StringWithLineNumber(str, "", 1));
|
|
}
|
|
return f;
|
|
}
|
|
|
|
inline FileWithLineNumbers &operator<<(FileWithLineNumbers &f, const char *str) {
|
|
f << std::string(str);
|
|
return f;
|
|
}
|
|
/** @} */
|
|
|
|
/** Replace all occurrences of a string with another string.
|
|
*
|
|
* Finds all occurrences of the @p oldToken string in @p inputString and replaces them each with @p newToken, returning the
|
|
* result.
|
|
*
|
|
* @{ */
|
|
std::string copyEdit(const std::string &inputString, const std::string &oldToken, const std::string &newToken);
|
|
|
|
FileWithLineNumbers copyEdit(const FileWithLineNumbers &inputString, const std::string &oldToken,
|
|
const std::string &newToken);
|
|
|
|
FileWithLineNumbers copyEdit(const FileWithLineNumbers &inputString, const std::string &oldToken,
|
|
const FileWithLineNumbers &newToken);
|
|
/** @} */
|
|
|
|
/** Convert an integer to a string.
|
|
*
|
|
* These functions are wrappers around <code>dyncompat::lexical_cast<std::string></code>.
|
|
*
|
|
* @{ */
|
|
std::string numberToString(long long);
|
|
|
|
std::string numberToString(unsigned long long);
|
|
|
|
std::string numberToString(long);
|
|
|
|
std::string numberToString(unsigned long);
|
|
|
|
std::string numberToString(int);
|
|
|
|
std::string numberToString(unsigned int);
|
|
/** @} */
|
|
|
|
/** Convert an integer to a hexadecimal string. */
|
|
std::string intToHex(uint64_t);
|
|
|
|
#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
|
|
std::string numberToString ( __int128 x );
|
|
std::string numberToString ( unsigned __int128 x );
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
/** Convert a pointer to a string. */
|
|
std::string numberToString(const void *);
|
|
|
|
/** Convert a floating-point number to a string.
|
|
*
|
|
* The returned string uses @c printf with "%2.2f" format. */
|
|
std::string numberToString(double);
|
|
|
|
/** Convert a virtual address to a string.
|
|
*
|
|
* Converts a virtual address to a hexadecimal string with a leading "0x". The string is zero-padded so that it explicitly
|
|
* represents at least @p nbits bits (four bits per hexadecimal digits). If @p nbits is zero then the function uses 32 bits
|
|
* for values that fit in 32 bits, otherwise 64 bits. */
|
|
std::string addrToString(uint64_t value, size_t nbits = 0);
|
|
|
|
/** Formatting support for generated code strings. */
|
|
std::string indentMultilineString(const std::string &inputString, int statementColumnNumber);
|
|
|
|
/** Generate a string from a list of integers.
|
|
*
|
|
* The return value is the concatenation of substrings. Each substring is formed by converting the corresponding integer from
|
|
* the list into a string via @ref numberToString and then adding a single space character and an optional line feed. The line
|
|
* feeds are added only if @p separateStrings is true. */
|
|
std::string listToString(const std::list<int> &, bool separateStrings = false);
|
|
|
|
/** Generate a string from a container of strings.
|
|
*
|
|
* The return value is the concatenation of substrings. Each substring is formed by adding a single space to the corresponding
|
|
* list element and an optional line feed. The line feeds are added only if @p separateStrings is true.
|
|
*
|
|
* @{ */
|
|
std::string listToString(const std::list <std::string> &, bool separateStrings = false);
|
|
|
|
std::string listToString(const std::vector <std::string> &, bool separateStrings = false);
|
|
/** @} */
|
|
|
|
/** Split a string into substrings at line feeds.
|
|
*
|
|
* Splits the input string into a list of substrings at the line-feed characters (the line feeds are at the end of the
|
|
* substrings). Substrings that are empty or consist of a single line-feed character are removed from the return value,
|
|
* although substrings that contain other sequences of only white space are not removed.
|
|
*
|
|
* Warning: This function is slow when invoked on a very large input string because it makes excessive copies of the input. */
|
|
std::list <std::string> stringToList(const std::string &);
|
|
|
|
/** Split a string into a list based on a separator character.
|
|
*
|
|
* Scans the input string for delimiter characters and splits the input into substrings at each delimiter positions. The
|
|
* delimiter is not included in the substring. Consecutive delimiter characters will result in an empty substring. */
|
|
std::list <std::string> tokenize(std::string X, char delim);
|
|
|
|
/** Splits string into substring based on a separator character.
|
|
*
|
|
* Empty strings are removed from the result, which is returned in the @p stringList argument. The return argument is cleared
|
|
* before the splitting begins. */
|
|
void splitStringIntoStrings(const std::string &inputString, char separator, std::vector <std::string> &stringList);
|
|
|
|
/** Remove redundant and blank lines.
|
|
*
|
|
* Splits the input string into substrings according to @ref listToString, sorts the substrings and removes duplicates and
|
|
* lines that are empty (a line of only horizontal white space is not considered to be empty), then concatenates the
|
|
* substrings in their sorted order into the return value using @ref listToString, inserting extra white space at the
|
|
* beginning of all but the first line. */
|
|
std::string removeRedundantSubstrings(const std::string &);
|
|
|
|
// [Robb Matzke 2016-01-06]: deprecated due to being misspelled
|
|
std::string removeRedundentSubstrings(std::string);
|
|
|
|
/** Remove redundant lines containing special substrings of form string#. */
|
|
std::string removePseudoRedundantSubstrings(const std::string &);
|
|
|
|
// [Robb Matzke 2016-01-06]: deprecated due to being misspelled
|
|
std::string removePseudoRedundentSubstrings(std::string);
|
|
|
|
/** Append an abbreviation or full name to a string. */
|
|
void add_to_reason_string(std::string &result, bool isset, bool do_pad,
|
|
const std::string &abbr, const std::string &full);
|
|
|
|
/** Determines whether one string contains another.
|
|
*
|
|
* Returns true if @p longString contains @p shortString as a subsequence. */
|
|
inline bool isContainedIn(const std::string &longString, const std::string &shortString) {
|
|
return longString.find(shortString) != std::string::npos;
|
|
}
|
|
|
|
/** Compute a checkshum.
|
|
*
|
|
* This function returns a unique checksum from the mangled name used it provides a simple means to obtain a unique value for
|
|
* any C++ declaration. At a later date was should use the MD5 Checksum implementation (but we can do that later).
|
|
*
|
|
* The declaration is the same under One-time Definition Rule (ODR) if and only if the checksum values for each declaration
|
|
* are the same. */
|
|
unsigned long generate_checksum(std::string s);
|
|
|
|
/** Convert to lower case.
|
|
*
|
|
* Returns a new string by converting each of the input characters to lower case with @c tolower. */
|
|
std::string convertToLowerCase(const std::string &inputString);
|
|
|
|
/** Escapes line feeds and double quotes.
|
|
*
|
|
* Scans the input string character by character and replaces line-feed characters with a backslash followed by the letter "l"
|
|
* and replaces double quotes by a backslash followed by a double qoute. */
|
|
std::string escapeNewLineCharaters(const std::string &);
|
|
|
|
/** Escapes HTML special characters.
|
|
*
|
|
* Replaces "<", ">", and "&" with HTML character names and returns the result. */
|
|
std::string htmlEscape(const std::string &);
|
|
|
|
/** Escapes characters that are special to C/C++.
|
|
*
|
|
* Replaces special characters in the input so that it is suitable for the contents of a C string literal. That is, things
|
|
* like double quotes, line-feeds, tabs, non-printables, etc. are replace by their C backslash escaped versions. Returns the
|
|
* resulting string. */
|
|
std::string cEscape(const std::string &);
|
|
|
|
/** Convert an ASCII hexadecimal character to an integer.
|
|
*
|
|
* Converts the characters 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f, A, B, C, D, E, and F into their hexadecimal integer
|
|
* equivalents. Returns zero if the input character is not in this set. */
|
|
unsigned hexadecimalToInt(char);
|
|
|
|
/** Convert a number to a hexadecimal and decimal string.
|
|
*
|
|
* The returned string starts with the hexadecimal representation of the number and an optional decimal representation
|
|
* in angle brackets. The decimal portion will contain a signed and/or unsigned value depending on whether the value
|
|
* is interpretted as signed and whether the sign bit is set. The signedToHex versions print the decimal value for only
|
|
* the signed interpretation; the unsignedToHex versions print only the decimal unsigned interpretation, and the toHex
|
|
* versions print both (but not redunantly).
|
|
*
|
|
* @{ */
|
|
std::string toHex2(uint64_t value, size_t nbits,
|
|
bool show_unsigned_decimal = true, bool show_signed_decimal = true,
|
|
uint64_t decimal_threshold = 256);
|
|
|
|
std::string signedToHex2(uint64_t value, size_t nbits);
|
|
|
|
std::string unsignedToHex2(uint64_t value, size_t nbits);
|
|
|
|
template<typename T>
|
|
std::string toHex(T value) { return toHex2((uint64_t) value, 8 * sizeof(T)); }
|
|
|
|
template<typename T>
|
|
std::string signedToHex(T value) { return signedToHex2((uint64_t) value, 8 * sizeof(T)); }
|
|
|
|
template<typename T>
|
|
std::string unsignedToHex(T value) { return unsignedToHex2((uint64_t) value, 8 * sizeof(T)); }
|
|
/** @} */
|
|
|
|
/** Append an assembly comment to a string. Assembly comments are surrounded by "<" and ">" characters. If the string
|
|
* already ends with an assembly comment, then the specified comment is inserted before the final ">" and separated from
|
|
* the previous comment with a comma. Assembly comments are usually used for things like printing a decimal representation
|
|
* of a hexadecimal value, etc.
|
|
*
|
|
* Example: after executing these statements:
|
|
*
|
|
* @code
|
|
* std::string s = "0xff";
|
|
* s = appendAsmComment(s, "255");
|
|
* s = appendAsmComment(s, "-1");
|
|
* @endcode
|
|
*
|
|
* The variable "s" will contain "0xff<255,-1>" */
|
|
std::string appendAsmComment(const std::string &s, const std::string &comment);
|
|
|
|
/** Insert a prefix string before every line.
|
|
*
|
|
* This function breaks the @p lines string into individual lines, inserts the @p prefix string at the beginning of each line,
|
|
* then concatenates the lines together into a return value. If @p prefixAtFront is true (the default) then the prefix is
|
|
* added to the first line of @p lines, otherwise the first line is unchanged. An empty @p lines string is considered to be a
|
|
* single line. If @p prefixAtBack is false (the default) then the prefix is not appended to the @p lines string if @p lines
|
|
* ends with a linefeed. */
|
|
std::string prefixLines(const std::string &lines, const std::string &prefix,
|
|
bool prefixAtFront = true, bool prefixAtBack = false);
|
|
|
|
/** Returns true if the string ends with line termination.
|
|
*
|
|
* Only common ASCII-based line terminations are recognized: CR+LF, LF+CR, CR (only), or LF (only). */
|
|
bool isLineTerminated(const std::string &s);
|
|
|
|
/** Normalizes line termination.
|
|
*
|
|
* Changes ASCII-based line termination conventions used by various operating systems into the LF (line-feed) termination used
|
|
* by Multics, Unix and Unix-like systems (GNU/Linux, Mac OS X, FreeBSD, AIX, Xenix, etc.), BeOS, Amiga, RISC OS and others.
|
|
* Any occurrance of CR+LF, LF+CR, or CR by itself (in that order of left-to-right matching) is replaced by a single LF
|
|
* character. */
|
|
std::string fixLineTermination(const std::string &input);
|
|
|
|
/** Converts a multi-line string to a single line.
|
|
*
|
|
* This function converts a multi-line string to a single line by replacing line-feeds and carriage-returns (and their
|
|
* surrounding white space) with a user-supplied replacement string (that defaults to a single space). Line termination (and
|
|
* it's surrounding white space) that appears at the front or back of the input string is removed without replacing it.
|
|
*
|
|
* See roseTests/utilTests/stringTests.C for lots of examples.
|
|
*
|
|
* A new string is returned. */
|
|
std::string makeOneLine(const std::string &s, std::string replacement = " ");
|
|
|
|
/** Convert binary data to base-64.
|
|
*
|
|
* The base64 number system uses the characters A-Z, a-z, 0-9, +, and / (in that order). The returned string does not include
|
|
* linefeeds. If @p do_pad is true then '=' characters may appear at the end to make the total length a multiple of four.
|
|
*
|
|
* @{ */
|
|
std::string encode_base64(const std::vector <uint8_t> &data, bool do_pad = true);
|
|
|
|
std::string encode_base64(const uint8_t *data, size_t nbytes, bool do_padd = true);
|
|
/** @} */
|
|
|
|
/** Convert base-64 to binary. */
|
|
std::vector <uint8_t> decode_base64(const std::string &encoded);
|
|
|
|
/** Join individual strings to form a single string.
|
|
*
|
|
* Unlike @ref listToString, this function allows the caller to indicate how the strings should be separated from one another:
|
|
* the @p separator (default SPC) is inserted between each pair of strings, but not at the beginning or end, even if strings
|
|
* are empty.
|
|
*
|
|
* @{ */
|
|
template<class Container>
|
|
std::string join(const std::string &separator, const Container &strings) {
|
|
std::string retval;
|
|
for (typename Container::const_iterator i = strings.begin(); i != strings.end(); ++i)
|
|
retval += (i == strings.begin() ? std::string() : separator) + *i;
|
|
return retval;
|
|
}
|
|
|
|
template<class Iterator>
|
|
std::string join_range(const std::string &separator, Iterator begin, Iterator end) {
|
|
std::string retval;
|
|
for (Iterator i = begin; i != end; ++i)
|
|
retval += (i == begin ? std::string() : separator) + *i;
|
|
return retval;
|
|
}
|
|
|
|
std::string join(const std::string &separator, char *strings[], size_t nstrings);
|
|
|
|
std::string join(const std::string &separator, const char *strings[], size_t nstrings);
|
|
/** @} */
|
|
|
|
/** Splits strings into parts.
|
|
*
|
|
* Unlink @ref stringToList, this function allows the caller to indicate where to split the string. The parts are the
|
|
* portions of the string on either side of the separator: if the separator appears at the beginning of the string, then the
|
|
* first part is empty; likewise if the separator appears at the end of the string then the last part is empty. At most @p
|
|
* maxparts are returned, the last of which may contain occurrences of the separator. If @p trim_white_space is true then
|
|
* white space is removed from the beginning and end of each part. Empty parts are never removed from the returned vector
|
|
* since the C++ library already has functions for that. The first few arguments are in the same order as for Perl's "split"
|
|
* operator.
|
|
*
|
|
* @{ */
|
|
std::vector <std::string> split(const std::string &separator, const std::string &str,
|
|
size_t maxparts = (size_t)(-1),
|
|
bool trim_white_space = false);
|
|
|
|
std::vector <std::string> split(char separator, const std::string &str, size_t maxparts = (size_t)(-1),
|
|
bool trim_white_space = false);
|
|
/** @} */
|
|
|
|
/** Trims white space from the beginning and end of a string.
|
|
*
|
|
* Caller may specify the characters to strip and whether the stripping occurs at the begining, the end, or both. */
|
|
std::string trim(const std::string &str, const std::string &strip = " \t\r\n",
|
|
bool at_beginning = true, bool at_end = true);
|
|
|
|
/** Expand horizontal tab characters. */
|
|
std::string untab(const std::string &str, size_t tabstops = 8, size_t firstcol = 0);
|
|
|
|
/** Converts a bunch of numbers to strings.
|
|
*
|
|
* This is convenient when one has a container of numbers and wants to call @ref join to turn it into a single string. For
|
|
* instance, here's how to convert a set of integers to a comma-separated list:
|
|
*
|
|
* @code
|
|
* using namespace StringUtility;
|
|
* std::set<int> numbers = ...;
|
|
* std::string s = join(", ", toStrings(numbers));
|
|
* @endcode
|
|
*
|
|
* Here's how to convert a vector of addresses to space-separated hexadecimal values:
|
|
* @code
|
|
* using namespace StringUtility;
|
|
* std::vector<rose_addr_t> addresses = ...;
|
|
* std::string s = join(" ", toStrings(addresses, addrToString));
|
|
* @endcode
|
|
*
|
|
* Here's how one could surround each address with angle brackets:
|
|
* @code
|
|
* using namespace StringUtility;
|
|
* struct AngleSurround {
|
|
* std::string operator()(rose_addr_t addr) {
|
|
* return "<" + addrToString(addr) + ">";
|
|
* }
|
|
* };
|
|
* std::string s = join(" ", toStrings(addresses, AngleSurround()));
|
|
* @endcode
|
|
* @{ */
|
|
template<class Container, class Stringifier>
|
|
std::vector <std::string> toStrings(const Container &numbers, const Stringifier &stringifier = numberToString) {
|
|
return toStrings_range(numbers.begin(), numbers.end(), stringifier);
|
|
}
|
|
|
|
template<class Iterator, class Stringifier>
|
|
std::vector <std::string> toStrings_range(Iterator begin, Iterator end,
|
|
const Stringifier &stringifier = numberToString) {
|
|
std::vector <std::string> retval;
|
|
for (/*void*/; begin != end; ++begin)
|
|
retval.push_back(stringifier(*begin));
|
|
return retval;
|
|
}
|
|
/** @} */
|
|
|
|
/** Helpful way to print singular or plural words.
|
|
*
|
|
* @code
|
|
* size_t n = ...;
|
|
* std::cout <<"received " <<plural(n, "values") <<"\n";
|
|
* @encode
|
|
*
|
|
* Output for various values of <em>n</em> will be:
|
|
*
|
|
* @code
|
|
* received 0 values
|
|
* received 1 value
|
|
* received 2 values
|
|
* @endcode
|
|
*
|
|
* This function uses a handful of grade-school rules for converting the supplied plural word to a singular word when
|
|
* necessary. If these are not enough, then the singular form can be supplied as the third argument.
|
|
*
|
|
* @code
|
|
* std::cout <<"graph contains " <<plural(nverts, "vertices", "vertex") <<"\n";
|
|
* @endcode
|
|
*/
|
|
template<typename T>
|
|
std::string plural(T n, const std::string &plural_word, const std::string &singular_word = "") {
|
|
//assert(!plural_word.empty());
|
|
std::string retval = numberToString(n) + " ";
|
|
if (1 == n) {
|
|
if (!singular_word.empty()) {
|
|
retval += singular_word;
|
|
} else if (plural_word.size() > 3 && 0 == plural_word.substr(plural_word.size() - 3).compare("ies")) {
|
|
// string ends with "ies", as in "parties", so emit "party" instead
|
|
retval += plural_word.substr(0, plural_word.size() - 3) + "y";
|
|
} else if (plural_word.size() > 1 && plural_word[plural_word.size() - 1] == 's') {
|
|
// just drop the final 's'
|
|
retval += plural_word.substr(0, plural_word.size() - 1);
|
|
} else {
|
|
// I give up. Use the plural and risk being grammatically incorrect.
|
|
retval += plural_word;
|
|
}
|
|
} else {
|
|
retval += plural_word;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
// demangledName is defined in rose_support.cpp
|
|
|
|
/** Compute demangled version of mangled name.
|
|
*
|
|
* Runs the c++filt command on the input string and returns the result. If c++filt cannot be run then it prints an error to
|
|
* standard error and another to standard output. The pipes opened to communicate with the c++filt subcommand might not be
|
|
* closed if there's an error. */
|
|
std::string demangledName(std::string);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// This part of the StringUtility API deals with operating system information. It has nothing to do with string utilities and
|
|
// should be moved elsewhere.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
enum OSType {
|
|
OS_TYPE_UNKNOWN,
|
|
OS_TYPE_LINUX,
|
|
OS_TYPE_OSX,
|
|
OS_TYPE_WINDOWS,
|
|
OS_TPYE_WINDOWSXP
|
|
};
|
|
|
|
/** Obtain operating system type information. */
|
|
OSType getOSType();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// This part of the StringUtility API deals with file names and should be moved to some other name space. In particular, it
|
|
// provides no definitions for "path", "filename", "extension", etc. and many of these functions won't work properly on a
|
|
// non-POSIX system. Therefore, consider using rose::FileSystem, which is mostly a thin wrapper around std::filesystem. The
|
|
// std::filesystem documentation has good definitions for what the various terms should mean and works on non-POSIX file
|
|
// systems.
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/** Create a file.
|
|
*
|
|
* Creates a new file, truncating any existing file with the same name, and writes the string @p outputString into the
|
|
* file. The name of the file is constructed by concatenating @p directoryName and @p fileNameString without any intervening
|
|
* component separator (e.g., no "/").
|
|
*
|
|
* If the file cannot be created then this function silently fails (or aborts if ROSE is compiled in debug mode). */
|
|
void writeFile(const std::string &outputString, const std::string &fileNameString,
|
|
const std::string &directoryName);
|
|
|
|
/** Reads entire text file.
|
|
*
|
|
* Opens the specified file, reads its contents into a string, closes the file, and returns that string.
|
|
*
|
|
* If the file cannot be opened then an std::string error message is thrown. The message reads "File not found" regardless of
|
|
* the actual error condition. */
|
|
std::string readFile(const std::string &fileName);
|
|
|
|
/** Reads an entire text file.
|
|
*
|
|
* Opens the specified file, reads its contents line by line into a vector of strings with location information, closes the
|
|
* file, and returns the vector. The file names in the returned value are absolute names. The strings in the return value
|
|
* have their final line-feeds removed.
|
|
*
|
|
* If the file cannot be opened then an std::string error message is thrown. The message reads "File not found" regardless of
|
|
* the actual error condition. */
|
|
FileWithLineNumbers readFileWithPos(const std::string &fileName);
|
|
|
|
/** Name of the home directory.
|
|
*
|
|
* Returns the value of the "HOME" environment variable by copying it into the @p dir argument. Will segfault if this
|
|
* environment variable is not set. */
|
|
void homeDir(std::string &dir);
|
|
|
|
/** Returns the last component of a path in a filesystem.
|
|
*
|
|
* Removes the "path" part of a "filename" (if there is one) and returns just the file name.
|
|
*
|
|
* Terms are loosely defined and not likely to work for non-POSIX systems; consider using std::filesystem instead. */
|
|
std::string stripPathFromFileName(const std::string &fileNameWithPath);
|
|
|
|
/** Returns all but the last component of a path in a filesystem.
|
|
*
|
|
* This function removes the filename from the combined path and filename if it includes a path and returns only the path.
|
|
* Make it safe to input a filename without a path name (return the filename).
|
|
*
|
|
* Terms are loosely defined and this function possibly doesn't work for non-POSIX file systems; consider using
|
|
* std::filesystem instead. */
|
|
std::string getPathFromFileName(const std::string &fileNameWithPath);
|
|
|
|
/** Get the file name without the ".suffix".
|
|
*
|
|
* Terms are loosely defined and it's not clear what happens for inputs like ".", ".foo", "..", ".foo.bar", "/.",
|
|
* etc. Consider using std::filesystem instead. */
|
|
std::string stripFileSuffixFromFileName(const std::string &fileNameWithSuffix);
|
|
|
|
/** Get the absolute path from the relative path.
|
|
*
|
|
* Terms are loosely defined and this function is not likely to work on non-POSIX systems. Consider using std::filesystem
|
|
* instead. */
|
|
std::string getAbsolutePathFromRelativePath(const std::string &relativePath, bool printErrorIfAny = false);
|
|
|
|
/** Get the file name suffix (extension) without the leading dot.
|
|
*
|
|
* Filename could be either base name or name with full path. If no dot is found in the input fileName, the function just
|
|
* returns the original fileName.
|
|
*
|
|
* Terms are loosely defined and this function is not likely to work correctly in some situations, such as when the "." is not
|
|
* in the last component of the file name. Consider using std::filesystem instead. */
|
|
std::string fileNameSuffix(const std::string &fileName);
|
|
|
|
/** Find file names non-recursively.
|
|
*
|
|
* Scans the directory named @p pathString and returns a list of files in that directory which have @p patternString as a
|
|
* substring of their name. Note that @p patternString is not a glob or regular expression. The return value strings are
|
|
* formed by concatenating the @p pathString and the file name with an intervening slash.
|
|
*
|
|
* This function does not work for non-POSIX systems. Consider using std::filesystem instead, which has a directory iterator
|
|
* that works for non-POSIX systems also. */
|
|
std::list <std::string> findfile(std::string patternString, std::string pathString);
|
|
|
|
/* File name location.
|
|
*
|
|
* Files can be classified as being in one of three locations: We don't know if it's user or system It is a user (application)
|
|
* file It is a system library This file does not exist */
|
|
enum FileNameLocation {
|
|
FILENAME_LOCATION_UNKNOWN,
|
|
FILENAME_LOCATION_USER,
|
|
FILENAME_LOCATION_LIBRARY,
|
|
FILENAME_LOCATION_NOT_EXIST
|
|
};
|
|
|
|
static const std::string FILENAME_LIBRARY_UNKNOWN = "Unknown";
|
|
static const std::string FILENAME_LIBRARY_USER = "User";
|
|
static const std::string FILENAME_LIBRARY_C = "C";
|
|
static const std::string FILENAME_LIBRARY_STDCXX = "C++";
|
|
static const std::string FILENAME_LIBRARY_STL = "STL";
|
|
static const std::string FILENAME_LIBRARY_LINUX = "Linux";
|
|
static const std::string FILENAME_LIBRARY_GCC = "GCC";
|
|
static const std::string FILENAME_LIBRARY_BOOST = "Boost";
|
|
static const std::string FILENAME_LIBRARY_ROSE = "Rose";
|
|
|
|
// CH (2/16/2010): Use this typedef to avoid following changes
|
|
typedef std::string FileNameLibrary;
|
|
|
|
/* This is the return type of classifyFileName, which provides all the details it infers */
|
|
class FileNameClassification {
|
|
private:
|
|
FileNameLocation location;
|
|
|
|
// CH (2/12/2010): Change 'library' type from enum to string to let user set it
|
|
FileNameLibrary library;
|
|
int distance;
|
|
|
|
public:
|
|
FileNameClassification(FileNameLocation loc, const FileNameLibrary &lib, int dist)
|
|
: location(loc), library(lib), distance(dist) { }
|
|
|
|
FileNameClassification()
|
|
: location(FILENAME_LOCATION_UNKNOWN), library("Unknown"), distance(0) { }
|
|
|
|
/* Return the FileNameLocation which is described above with the definition of the enum */
|
|
FileNameLocation getLocation() const {
|
|
return location;
|
|
}
|
|
|
|
/* Return the FileNameLibrary which is described above with the definition of the enum */
|
|
FileNameLibrary getLibrary() const {
|
|
return library;
|
|
}
|
|
|
|
/* Return the "distance" of the filename from the appPath that was supplied during the call. The distance is defined as
|
|
* the number of cd's that only move up or down one directory that it would take to move from the directory of the filename
|
|
* to the directory that was given by appPath. This is intended as a heuristic to gage whether or not one believes that
|
|
* the filename is related to the source (appPath) directory. Examples:
|
|
*
|
|
* Between /a/b/c/file.h and /a/b/d/e/ the distance is 3 because one must cd ..; cd d; cd e; to get to appPath
|
|
*
|
|
* *EXCEPTION*: if the appPath is an ancestor of filename then the distance will be 0. The idea being that this filename
|
|
* is "in" the appPath somewhere and thus part of the application. */
|
|
int getDistanceFromSourceDirectory() const {
|
|
return distance;
|
|
}
|
|
|
|
bool isUserCode() const {
|
|
return location == FILENAME_LOCATION_USER;
|
|
}
|
|
|
|
bool isLibraryCode() const {
|
|
return location == FILENAME_LOCATION_LIBRARY;
|
|
}
|
|
|
|
/* Return a string name for the library indicated by getLibrary() */
|
|
std::string getLibraryName() const {
|
|
return library;
|
|
}
|
|
};
|
|
|
|
/** Determine whether a file is source code or system library.
|
|
*
|
|
* Given a fileName and an appPath that is a path to some application's source code directory, return a FileNameClassification
|
|
* indicating whether the fileName is part of the source code or some system library and automatically determine the operating
|
|
* system from the host uname */
|
|
FileNameClassification classifyFileName(const std::string &fileName, const std::string &appPath);
|
|
|
|
/** Determine whether a file is source code or system library.
|
|
*
|
|
* Given a fileName and an appPath that is a path to some application's source code directory, return a FileNameClassification
|
|
* indicating whether the fileName is part of the source code or some system library */
|
|
FileNameClassification classifyFileName(const std::string &fileName, const std::string &appPath, OSType os);
|
|
|
|
/** Determine whether a file is source code or system library.
|
|
*
|
|
* Given a fileName and an appPath that is a path to some application's source code directory, and a collection of library
|
|
* paths, return a FileNameClassification indicating whether the fileName is part of the source code or some system library
|
|
* and automatically determine the operating system from the host uname */
|
|
FileNameClassification classifyFileName(const std::string &fileName, const std::string &appPath,
|
|
const std::map <std::string, std::string> &libPathCollection);
|
|
|
|
/** Determine whether a file is source code or system library.
|
|
*
|
|
* Given a fileName and an appPath that is a path to some application's source code directory, and a collection of library
|
|
* paths, return a FileNameClassification indicating whether the fileName is part of the source code or some system library */
|
|
FileNameClassification classifyFileName(const std::string &fileName, const std::string &appPath,
|
|
const std::map <std::string, std::string> &libPathCollection,
|
|
OSType os);
|
|
|
|
/** Remove leading dots.
|
|
*
|
|
* Removes leading dots plus a space from a header file name that is given in the format that g++ -H returns */
|
|
const std::string stripDotsFromHeaderFileName(const std::string &name);
|
|
|
|
/** Edit distance between two directory names.
|
|
*
|
|
* Essentially the edit distance without substituion in directory name tokens between two directories. Returns the "distance"
|
|
* between left and right. The distance is defined as the number of cd's that only move up or down one directory that it would
|
|
* take to move from the directory of the filename to the directory that was given by appPath. This is intended as a
|
|
* heuristic to gage whether or not one believes that the left is related to the right directory. Examples:
|
|
*
|
|
* Between /a/b/c/file.h and /a/b/d/e/ the distance is 3 because one must cd ..; cd d; cd e */
|
|
int directoryDistance(const std::string &left, const std::string &right);
|
|
|
|
/** Reads words from a file.
|
|
*
|
|
* Opens the specified file for reading and reads all words from the file using <code>std::istream</code>
|
|
* <code>operator>></code> into <code>std::string</code>. If the file cannot be opened then an error message is printed to
|
|
* standard output (not error) and the program exits with status 1. */
|
|
std::vector <std::string> readWordsInFile(std::string filename);
|
|
|
|
// popen_wrapper is defined in sage_support.cpp
|
|
|
|
/** Simple wrapper for Unix popen command.
|
|
*
|
|
* If there is a failure (cannot create pipes, command not found, command terminated abnormally, input buffer too small, etc),
|
|
* then an error is printed to standard error (with or without line termination) and false is returned. When an error occurs
|
|
* the pipes that were opened to communicate with the subcommand might not be closed. */
|
|
bool popen_wrapper(const std::string &command, std::vector <std::string> &result);
|
|
|
|
} // namespace
|
|
|
|
#endif
|