#ifndef ROSE_StringUtility_H #define ROSE_StringUtility_H //#include "commandline_processing.h" #include #include #include #include #include #include #include #include #include #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 FileWithLineNumbers; #else // workaround of bug 315, separating definitions for a namespace [Liao, 2/16/2009] } namespace StringUtility { typedef std::vector 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 = "", 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 dyncompat::lexical_cast. * * @{ */ 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 &, 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 &, bool separateStrings = false); std::string listToString(const std::vector &, 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 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 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 &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 std::string toHex(T value) { return toHex2((uint64_t) value, 8 * sizeof(T)); } template std::string signedToHex(T value) { return signedToHex2((uint64_t) value, 8 * sizeof(T)); } template 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 &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 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 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 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 split(const std::string &separator, const std::string &str, size_t maxparts = (size_t)(-1), bool trim_white_space = false); std::vector 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 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 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 std::vector toStrings(const Container &numbers, const Stringifier &stringifier = numberToString) { return toStrings_range(numbers.begin(), numbers.end(), stringifier); } template std::vector toStrings_range(Iterator begin, Iterator end, const Stringifier &stringifier = numberToString) { std::vector 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 " <n 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 " < 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 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 &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 &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 std::istream * operator>> into std::string. 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 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 &result); } // namespace #endif