// -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* // DESCRIPTION: Verilator: String manipulation // // Code available from: https://verilator.org // //************************************************************************* // // This program is free software; you can redistribute it and/or modify it // under the terms of either the GNU Lesser General Public License Version 3 // or the Perl Artistic License Version 2.0. // SPDX-FileCopyrightText: 2003-2026 Wilson Snyder // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 // //************************************************************************* #ifndef VERILATOR_V3STRING_H_ #define VERILATOR_V3STRING_H_ #include "config_build.h" #include "verilatedos.h" // No V3 headers here - this is a base class for Vlc etc #include #include #include #include #include #include #include #include #include using VStringList = std::vector; using VStringSet = std::set; //###################################################################### // Global string-related functions template std::string cvtToStr(const T& t) VL_PURE { std::ostringstream os; os << t; return os.str(); } template typename std::enable_if::value, std::string>::type cvtToHex(const T tp) VL_PURE { std::ostringstream os; os << static_cast(tp); return os.str(); } template typename std::enable_if::value, std::string>::type cvtToHex(const T t) { std::ostringstream os; os << std::hex << std::setw(sizeof(T) * 8 / 4) << std::setfill('0') << t; return os.str(); } inline string ucfirst(const string& text) { string result = text; result[0] = std::toupper(result[0]); return result; } //###################################################################### // VString - String manipulation class VString final { static bool wildmatchi(const char* s, const char* p) VL_PURE; public: // METHODS (generic string utilities) // Return true if p with ? or *'s matches s static bool wildmatch(const char* s, const char* p) VL_PURE; // Return true if p with ? or *'s matches s static bool wildmatch(const string& s, const string& p) VL_PURE; // Return {a}{dot}{b}, omitting dot if a or b are empty static string dot(const string& a, const string& dot, const string& b); // Convert string to lowercase (tolower) static string downcase(const string& str) VL_PURE; // Convert string to upper case (toupper) static string upcase(const string& str) VL_PURE; // Insert esc just before tgt static string quoteAny(const string& str, char tgt, char esc) VL_PURE; // Replace any \'s with \\ (two consecutive backslashes) static string quoteBackslash(const string& str) VL_PURE { return quoteAny(str, '\\', '\\'); } // Replace any %'s with %% static string quotePercent(const string& str) VL_PURE { return quoteAny(str, '%', '%'); } // Replace any %%'s with % static string dequotePercent(const string& str); // Surround a raw string by double quote and escape if necessary // e.g. input abc's becomes "\"abc\'s\"" static string escapeStringForPath(const string& str); // Convert SV quoted string input from source code to normal form. // Reverse is V3OutFormatter::quoteNameControls(...) static string unquoteSVString(const string& text, string& errOut); // Escape path in Windows // e.g. input `C:\Program Files\My Program\My Program.exe` becomes // `C:\\Program\ Files\\My\ Program\\My\ Program.exe` static string quoteStringLiteralForShell(const string& str); // Replace any unprintable with space // This includes removing tabs, so column tracking is correct static string spaceUnprintable(const string& str) VL_PURE; // Remove any whitespace static string removeWhitespace(const string& str); // Trim leading/trailing whitespace on each line static string trimWhitespace(const string& str); // Return true if only identifer or "" static bool isIdentifier(const string& str); // Return true if char is valid character in C identifiers static bool isIdentifierChar(char c) { return isalnum(c) || c == '_'; } // Return true if only whitespace or "" static bool isWhitespace(const string& str); // Return number of spaces/tabs leading in string static string::size_type leadingWhitespaceCount(const string& str); // Return double by parsing string static double parseDouble(const string& str, bool* successp); // Replace substring. Often replaceWord is more appropriate. static string replaceSubstr(const string& str, const string& from, const string& to); // Replace all occurrences of the word 'from' in 'str' with 'to'. A word is considered // to be a consecutive sequence of the characters [a-zA-Z0-9_]. Sub-words are not replaced. // e.g.: replaceWords("one apple bad_apple", "apple", "banana") -> "one banana bad_apple" static string replaceWord(const string& str, const string& from, const string& to); // Return deque of strings split by the given delimiter static std::deque split(const string& str, char delimiter = ','); // Predicate to check if 'str' starts with 'prefix' static bool startsWith(const string& str, const char* prefixp) { return !str.rfind(prefixp, 0); // Faster than .find(_) == 0 } static bool startsWith(const string& str, const string& prefix) { return !str.rfind(prefix, 0); // Faster than .find(_) == 0 } // Predicate to check if 'str' ends with 'suffix' static bool endsWith(const string& str, const string& suffix); // Return proper article (a/an) for a word. May be inaccurate for some special words static string aOrAn(const char* word); static string aOrAn(const string& word) { return aOrAn(word.c_str()); } // Hash the string static uint64_t hashMurmur(const string& str) VL_PURE; // Base 64 encode static string base64Enc(const string& str) VL_PURE; static void selfTest(); // Test this class }; //###################################################################### // VHashSha512 - Compute Sha512 hashes class VHashSha512 final { // As blocks must be processed in 128 byte chunks, this does not at present // support calling input() on multiple non-128B chunks and getting the correct // hash. To do that first combine the string before calling here. // Or improve to store 0-127 bytes of data between calls to input(). // MEMBERS uint64_t m_inthash[8]; // Intermediate hash, in host order string m_remainder; // Unhashed data size_t m_totLength = 0; // Total all-chunk length as needed by output digest bool m_final = false; // Finalized public: // CONSTRUCTORS VHashSha512() { m_inthash[0] = 0x6a09e667f3bcc908ULL; m_inthash[1] = 0xbb67ae8584caa73bULL; m_inthash[2] = 0x3c6ef372fe94f82bULL; m_inthash[3] = 0xa54ff53a5f1d36f1ULL; m_inthash[4] = 0x510e527fade682d1ULL; m_inthash[5] = 0x9b05688c2b3e6c1fULL; m_inthash[6] = 0x1f83d9abfb41bd6bULL; m_inthash[7] = 0x5be0cd19137e2179ULL; } explicit VHashSha512(const string& data) : VHashSha512{} { insert(data); } ~VHashSha512() = default; // CONSTANTS // Characters digestSymbol24 keeps, 6 bits each, so 144 bits and no collisions in practice static constexpr size_t DIGEST_SYMBOL24_LENGTH = 24; // METHODS string digestBase64(); // Return digest formatted in Base64 (non-URL flavor) string digestBinary(); // Return digest as 64 character binary string digestHex(); // Return digest formatted as a hex string string digestSymbol24(); // Return non-reversable short-formatted as C symbol/base64ish uint64_t digestUInt64(); // Return 64-bits of digest static void selfTest(); // Test this class // Inserting hash data void insert(const void* datap, size_t length); // Process data into the digest void insert(const string& data) { insert(data.data(), data.length()); } // Process data into the digest void insert(uint64_t value) { insert(cvtToStr(value)); } void insertFile(const string& filename); private: static void selfTestOne(const string& data, const string& data2, const string& exp, const string& exp64, const string& exp24); void finalize(); // Process remaining data }; //###################################################################### // VName - string which contains a possibly hashed string // TODO use this wherever there is currently a "string m_name" class VName final { string m_name; // Pre-hashed symbol name string m_hashed; // Hashed version of symbol name static std::map s_dehashMap; // hashed -> original decoder static size_t s_maxLength; // Length at which to start hashing static size_t s_minLength; // Length to preserve if over maxLength public: // CONSTRUCTORS explicit VName(const string& name) : m_name{name} {} ~VName() = default; // METHODS void name(const string& name) { m_name = name; m_hashed = ""; } string name() const { return m_name; } string hashedName(); // CONFIG STATIC METHODS // Length at which to start hashing, 0=disable static void maxLength(size_t flag) { s_maxLength = flag; } static string dehash(const string& in); }; //###################################################################### // VSpellCheck - Find near-match spelling suggestions given list of possibilities class VSpellCheck final { // CONSTANTS static constexpr unsigned NUM_CANDIDATE_LIMIT = 10000; // Avoid searching huge netlists static constexpr unsigned LENGTH_LIMIT = 100; // Maximum string length to search // TYPES using EditDistance = unsigned int; // MEMBERS std::vector m_candidates; // Strings we try to match public: // CONSTRUCTORS VSpellCheck() = default; ~VSpellCheck() = default; // METHODS // Push a symbol table value to be considered as a candidate // The first item pushed has highest priority, all else being equal void pushCandidate(const string& s) { if (m_candidates.size() < NUM_CANDIDATE_LIMIT) m_candidates.push_back(s); } // Return candidate is closest to provided string, or "" for none string bestCandidate(const string& goal) const { EditDistance dist; return bestCandidateInfo(goal, dist /*ref*/); } // Return friendly message string bestCandidateMsg(const string& goal) const { const string candidate = bestCandidate(goal); if (candidate.empty()) return ""; return "... Suggested alternative: '"s + candidate + "'"; } static void selfTest(); const std::vector candidates() const { return m_candidates; } private: static EditDistance editDistance(const string& s, const string& t); static EditDistance cutoffDistance(size_t goal_len, size_t candidate_len); string bestCandidateInfo(const string& goal, EditDistance& distancer) const; static void selfTestDistanceOne(const string& a, const string& b, EditDistance expected); static void selfTestSuggestOne(bool matches, const string& c, const string& goal, EditDistance dist); }; //###################################################################### #endif // guard