2012-08-27 03:13:47 +02:00
|
|
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
// DESCRIPTION: Verilator: String manipulation
|
|
|
|
|
//
|
2019-11-08 04:33:59 +01:00
|
|
|
// Code available from: https://verilator.org
|
2012-08-27 03:13:47 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
|
|
|
|
//
|
2024-01-01 09:19:59 +01:00
|
|
|
// Copyright 2003-2024 by Wilson Snyder. This program is free software; you
|
2020-03-21 16:24:24 +01:00
|
|
|
// can redistribute it and/or modify it under the terms of either the GNU
|
2012-08-27 03:13:47 +02:00
|
|
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
|
|
|
|
// Version 2.0.
|
2020-03-21 16:24:24 +01:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
2012-08-27 03:13:47 +02:00
|
|
|
//
|
|
|
|
|
//*************************************************************************
|
2019-10-05 02:17:11 +02:00
|
|
|
|
2021-03-04 03:57:07 +01:00
|
|
|
#ifndef VERILATOR_V3STRING_H_
|
|
|
|
|
#define VERILATOR_V3STRING_H_
|
2012-08-27 03:13:47 +02:00
|
|
|
|
|
|
|
|
#include "config_build.h"
|
|
|
|
|
#include "verilatedos.h"
|
2018-10-14 19:43:24 +02:00
|
|
|
|
2019-10-03 03:38:06 +02:00
|
|
|
// No V3 headers here - this is a base class for Vlc etc
|
|
|
|
|
|
2021-06-13 16:05:55 +02:00
|
|
|
#include <iomanip>
|
2020-11-17 00:11:27 +01:00
|
|
|
#include <map>
|
2019-10-03 03:38:06 +02:00
|
|
|
#include <sstream>
|
2020-11-26 02:57:30 +01:00
|
|
|
#include <string>
|
2021-06-13 16:05:55 +02:00
|
|
|
#include <type_traits>
|
2020-11-26 02:57:30 +01:00
|
|
|
#include <unordered_map>
|
2019-10-03 03:38:06 +02:00
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// Global string-related functions
|
|
|
|
|
|
2022-08-05 11:56:57 +02:00
|
|
|
template <class T>
|
2023-03-17 00:48:56 +01:00
|
|
|
std::string cvtToStr(const T& t) VL_PURE {
|
2020-04-14 04:51:35 +02:00
|
|
|
std::ostringstream os;
|
|
|
|
|
os << t;
|
|
|
|
|
return os.str();
|
2019-10-03 03:38:06 +02:00
|
|
|
}
|
2021-06-13 16:05:55 +02:00
|
|
|
template <class T>
|
2023-03-17 00:48:56 +01:00
|
|
|
typename std::enable_if<std::is_pointer<T>::value, std::string>::type
|
|
|
|
|
cvtToHex(const T tp) VL_PURE {
|
2020-04-14 04:51:35 +02:00
|
|
|
std::ostringstream os;
|
|
|
|
|
os << static_cast<const void*>(tp);
|
|
|
|
|
return os.str();
|
2019-10-03 03:38:06 +02:00
|
|
|
}
|
2021-06-13 16:05:55 +02:00
|
|
|
template <class T>
|
|
|
|
|
typename std::enable_if<std::is_integral<T>::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();
|
|
|
|
|
}
|
2019-10-03 03:38:06 +02:00
|
|
|
|
|
|
|
|
inline uint32_t cvtToHash(const void* vp) {
|
|
|
|
|
// We can shove a 64 bit pointer into a 32 bit bucket
|
|
|
|
|
// On 32-bit systems, lower is always 0, but who cares?
|
2020-04-14 04:51:35 +02:00
|
|
|
union {
|
|
|
|
|
const void* up;
|
|
|
|
|
struct {
|
|
|
|
|
uint32_t upper;
|
|
|
|
|
uint32_t lower;
|
|
|
|
|
} l;
|
|
|
|
|
} u;
|
|
|
|
|
u.l.upper = 0;
|
|
|
|
|
u.l.lower = 0;
|
|
|
|
|
u.up = vp;
|
|
|
|
|
return u.l.upper ^ u.l.lower;
|
2019-10-03 03:38:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline string ucfirst(const string& text) {
|
2023-04-09 04:11:28 +02:00
|
|
|
string result = text;
|
|
|
|
|
result[0] = std::toupper(result[0]);
|
|
|
|
|
return result;
|
2019-10-03 03:38:06 +02:00
|
|
|
}
|
2012-08-27 03:13:47 +02:00
|
|
|
|
|
|
|
|
//######################################################################
|
|
|
|
|
// VString - String manipulation
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VString final {
|
2023-03-17 00:48:56 +01:00
|
|
|
static bool wildmatchi(const char* s, const char* p) VL_PURE;
|
2020-04-14 04:51:35 +02:00
|
|
|
|
2012-08-27 03:13:47 +02:00
|
|
|
public:
|
|
|
|
|
// METHODS (generic string utilities)
|
2018-03-16 00:46:05 +01:00
|
|
|
// Return true if p with ? or *'s matches s
|
2023-03-17 00:48:56 +01:00
|
|
|
static bool wildmatch(const char* s, const char* p) VL_PURE;
|
2020-01-12 10:03:17 +01:00
|
|
|
// Return true if p with ? or *'s matches s
|
2023-03-17 00:48:56 +01:00
|
|
|
static bool wildmatch(const string& s, const string& p) VL_PURE;
|
2018-03-16 00:46:05 +01:00
|
|
|
// Return {a}{dot}{b}, omitting dot if a or b are empty
|
|
|
|
|
static string dot(const string& a, const string& dot, const string& b);
|
2019-12-24 01:00:17 +01:00
|
|
|
// Convert string to lowercase (tolower)
|
2024-07-14 21:28:00 +02:00
|
|
|
static string downcase(const string& str) VL_PURE;
|
2019-12-24 01:00:17 +01:00
|
|
|
// Convert string to upper case (toupper)
|
2024-07-14 21:28:00 +02:00
|
|
|
static string upcase(const string& str) VL_PURE;
|
2020-08-15 15:43:53 +02:00
|
|
|
// Insert esc just before tgt
|
|
|
|
|
static string quoteAny(const string& str, char tgt, char esc);
|
|
|
|
|
// Replace any \'s with \\ (two consecutive backslashes)
|
|
|
|
|
static string quoteBackslash(const string& str) { return quoteAny(str, '\\', '\\'); }
|
2018-03-16 00:46:05 +01:00
|
|
|
// Replace any %'s with %%
|
2020-08-15 15:43:53 +02:00
|
|
|
static string quotePercent(const string& str) { return quoteAny(str, '%', '%'); }
|
|
|
|
|
// Surround a raw string by double quote and escape if necessary
|
|
|
|
|
// e.g. input abc's becomes "\"abc\'s\""
|
2022-11-20 16:25:41 +01:00
|
|
|
static string escapeStringForPath(const string& str);
|
2023-09-26 21:42:15 +02:00
|
|
|
// Convert SV quoted string input from source code to normal form.
|
|
|
|
|
// Reverse is V3OutFormatter::quoteNameControls(...)
|
|
|
|
|
static string unquoteSVString(const string& text, string& errOut);
|
2022-11-20 16:25:41 +01:00
|
|
|
// Escape path in Windows
|
2022-11-20 16:26:23 +01:00
|
|
|
// e.g. input `C:\Program Files\My Program\My Program.exe` becomes
|
|
|
|
|
// `C:\\Program\ Files\\My\ Program\\My\ Program.exe`
|
2020-08-15 15:43:53 +02:00
|
|
|
static string quoteStringLiteralForShell(const string& str);
|
2019-07-15 03:42:03 +02:00
|
|
|
// Replace any unprintable with space
|
|
|
|
|
// This includes removing tabs, so column tracking is correct
|
2023-03-17 00:48:56 +01:00
|
|
|
static string spaceUnprintable(const string& str) VL_PURE;
|
2020-04-16 01:39:03 +02:00
|
|
|
// Remove any whitespace
|
|
|
|
|
static string removeWhitespace(const string& str);
|
2024-11-27 03:06:43 +01:00
|
|
|
// 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 == '_'; }
|
2020-01-11 15:16:26 +01:00
|
|
|
// Return true if only whitespace or ""
|
|
|
|
|
static bool isWhitespace(const string& str);
|
2023-07-01 16:45:25 +02:00
|
|
|
// Return number of spaces/tabs leading in string
|
|
|
|
|
static string::size_type leadingWhitespaceCount(const string& str);
|
2020-06-07 14:21:22 +02:00
|
|
|
// Return double by parsing string
|
|
|
|
|
static double parseDouble(const string& str, bool* successp);
|
2021-06-13 15:33:11 +02:00
|
|
|
// 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);
|
2021-07-20 15:18:35 +02:00
|
|
|
// Predicate to check if 'str' starts with 'prefix'
|
|
|
|
|
static bool startsWith(const string& str, const string& prefix);
|
2022-10-21 13:05:38 +02:00
|
|
|
// Predicate to check if 'str' ends with 'suffix'
|
|
|
|
|
static bool endsWith(const string& str, const string& suffix);
|
2023-10-15 18:59:36 +02:00
|
|
|
// 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()); }
|
2012-08-27 03:13:47 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//######################################################################
|
2019-09-28 19:32:28 +02:00
|
|
|
// VHashSha256 - Compute Sha256 hashes
|
2012-08-27 03:13:47 +02:00
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VHashSha256 final {
|
2015-09-20 00:49:54 +02:00
|
|
|
// As blocks must be processed in 64 byte chunks, this does not at present
|
|
|
|
|
// support calling input() on multiple non-64B chunks and getting the correct
|
|
|
|
|
// hash. To do that first combine the string before calling here.
|
|
|
|
|
// Or improve to store 0-63 bytes of data between calls to input().
|
2012-08-27 03:13:47 +02:00
|
|
|
|
2015-09-20 00:49:54 +02:00
|
|
|
// MEMBERS
|
2020-04-14 04:51:35 +02:00
|
|
|
uint32_t m_inthash[8]; // Intermediate hash, in host order
|
|
|
|
|
string m_remainder; // Unhashed data
|
2020-08-15 19:11:27 +02:00
|
|
|
size_t m_totLength = 0; // Total all-chunk length as needed by output digest
|
2022-11-13 15:26:46 +01:00
|
|
|
bool m_final = false; // Finalized
|
2012-08-27 03:13:47 +02:00
|
|
|
public:
|
2015-09-20 00:49:54 +02:00
|
|
|
// CONSTRUCTORS
|
2020-08-15 16:26:38 +02:00
|
|
|
VHashSha256() {
|
|
|
|
|
m_inthash[0] = 0x6a09e667;
|
|
|
|
|
m_inthash[1] = 0xbb67ae85;
|
|
|
|
|
m_inthash[2] = 0x3c6ef372;
|
|
|
|
|
m_inthash[3] = 0xa54ff53a;
|
|
|
|
|
m_inthash[4] = 0x510e527f;
|
|
|
|
|
m_inthash[5] = 0x9b05688c;
|
|
|
|
|
m_inthash[6] = 0x1f83d9ab;
|
|
|
|
|
m_inthash[7] = 0x5be0cd19;
|
|
|
|
|
}
|
|
|
|
|
explicit VHashSha256(const string& data)
|
2020-08-16 15:55:36 +02:00
|
|
|
: VHashSha256{} {
|
2020-04-14 04:51:35 +02:00
|
|
|
insert(data);
|
|
|
|
|
}
|
2020-11-17 01:56:16 +01:00
|
|
|
~VHashSha256() = default;
|
2015-09-20 02:12:35 +02:00
|
|
|
|
2015-09-20 00:49:54 +02:00
|
|
|
// METHODS
|
2019-09-28 19:32:28 +02:00
|
|
|
string digestBinary(); // Return digest as 32 character binary
|
2019-05-19 22:13:13 +02:00
|
|
|
string digestHex(); // Return digest formatted as a hex string
|
|
|
|
|
string digestSymbol(); // Return digest formatted as C symbol/base64ish
|
|
|
|
|
uint64_t digestUInt64(); // Return 64-bits of digest
|
|
|
|
|
static void selfTest(); // Test this class
|
2012-08-27 03:13:47 +02:00
|
|
|
|
2023-11-11 05:25:53 +01:00
|
|
|
// Inserting hash data
|
2015-09-20 00:49:54 +02:00
|
|
|
void insert(const void* datap, size_t length); // Process data into the digest
|
2020-04-14 04:51:35 +02:00
|
|
|
void insert(const string& data) {
|
|
|
|
|
insert(data.data(), data.length());
|
|
|
|
|
} // Process data into the digest
|
2015-09-20 00:49:54 +02:00
|
|
|
void insert(uint64_t value) { insert(cvtToStr(value)); }
|
2012-08-27 03:13:47 +02:00
|
|
|
|
2015-09-20 00:49:54 +02:00
|
|
|
private:
|
2020-04-14 04:51:35 +02:00
|
|
|
static void selfTestOne(const string& data, const string& data2, const string& exp,
|
|
|
|
|
const string& exp64);
|
2019-05-19 22:13:13 +02:00
|
|
|
void finalize(); // Process remaining data
|
2012-08-27 03:13:47 +02:00
|
|
|
};
|
|
|
|
|
|
2015-09-20 02:12:35 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// VName - string which contains a possibly hashed string
|
|
|
|
|
// TODO use this wherever there is currently a "string m_name"
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VName final {
|
2015-09-20 02:12:35 +02:00
|
|
|
string m_name;
|
|
|
|
|
string m_hashed;
|
2020-11-17 00:11:27 +01:00
|
|
|
static std::map<string, string> s_dehashMap; // hashed -> original decoder
|
2015-09-20 02:12:35 +02:00
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
static size_t s_maxLength; // Length at which to start hashing
|
|
|
|
|
static size_t s_minLength; // Length to preserve if over maxLength
|
2020-11-17 00:11:27 +01:00
|
|
|
|
2015-09-20 02:12:35 +02:00
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
2020-04-14 04:51:35 +02:00
|
|
|
explicit VName(const string& name)
|
2020-08-16 15:55:36 +02:00
|
|
|
: m_name{name} {}
|
2020-11-17 01:56:16 +01:00
|
|
|
~VName() = default;
|
2015-09-20 02:12:35 +02:00
|
|
|
// METHODS
|
2020-04-14 04:51:35 +02:00
|
|
|
void name(const string& name) {
|
|
|
|
|
m_name = name;
|
|
|
|
|
m_hashed = "";
|
|
|
|
|
}
|
2015-09-20 02:12:35 +02:00
|
|
|
string name() const { return m_name; }
|
|
|
|
|
string hashedName();
|
2019-09-12 13:22:22 +02:00
|
|
|
// CONFIG STATIC METHODS
|
2019-05-19 22:13:13 +02:00
|
|
|
// Length at which to start hashing, 0=disable
|
|
|
|
|
static void maxLength(size_t flag) { s_maxLength = flag; }
|
2015-09-20 02:12:35 +02:00
|
|
|
static size_t maxLength() { return s_maxLength; }
|
2020-11-17 00:11:27 +01:00
|
|
|
static string dehash(const string& in);
|
2015-09-20 02:12:35 +02:00
|
|
|
};
|
|
|
|
|
|
2019-07-14 02:30:32 +02:00
|
|
|
//######################################################################
|
|
|
|
|
// VSpellCheck - Find near-match spelling suggestions given list of possibilities
|
|
|
|
|
|
2020-11-19 03:32:16 +01:00
|
|
|
class VSpellCheck final {
|
2019-07-14 02:30:32 +02:00
|
|
|
// CONSTANTS
|
2020-08-16 20:19:12 +02:00
|
|
|
static constexpr unsigned NUM_CANDIDATE_LIMIT = 10000; // Avoid searching huge netlists
|
|
|
|
|
static constexpr unsigned LENGTH_LIMIT = 100; // Maximum string length to search
|
2019-07-14 02:30:32 +02:00
|
|
|
// TYPES
|
2021-03-13 00:10:45 +01:00
|
|
|
using EditDistance = unsigned int;
|
2019-07-14 02:30:32 +02:00
|
|
|
// MEMBERS
|
2021-03-12 23:26:53 +01:00
|
|
|
std::vector<std::string> m_candidates; // Strings we try to match
|
2019-07-14 02:30:32 +02:00
|
|
|
public:
|
|
|
|
|
// CONSTRUCTORS
|
2020-11-17 01:56:16 +01:00
|
|
|
VSpellCheck() = default;
|
|
|
|
|
~VSpellCheck() = default;
|
2019-07-14 02:30:32 +02:00
|
|
|
// 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
|
2021-03-04 14:08:44 +01:00
|
|
|
string bestCandidate(const string& goal) const {
|
2019-07-14 02:30:32 +02:00
|
|
|
EditDistance dist;
|
2020-04-14 04:51:35 +02:00
|
|
|
return bestCandidateInfo(goal, dist /*ref*/);
|
2019-07-14 02:30:32 +02:00
|
|
|
}
|
|
|
|
|
// Return friendly message
|
2021-03-04 14:08:44 +01:00
|
|
|
string bestCandidateMsg(const string& goal) const {
|
2021-06-21 00:32:57 +02:00
|
|
|
const string candidate = bestCandidate(goal);
|
2020-04-14 04:51:35 +02:00
|
|
|
if (candidate.empty()) {
|
|
|
|
|
return "";
|
|
|
|
|
} else {
|
2024-01-29 02:24:28 +01:00
|
|
|
return "... Suggested alternative: '"s + candidate + "'";
|
2020-04-14 04:51:35 +02:00
|
|
|
}
|
2019-07-14 02:30:32 +02:00
|
|
|
}
|
|
|
|
|
static void selfTest();
|
2020-04-14 04:51:35 +02:00
|
|
|
|
2019-07-14 02:30:32 +02:00
|
|
|
private:
|
|
|
|
|
static EditDistance editDistance(const string& s, const string& t);
|
|
|
|
|
static EditDistance cutoffDistance(size_t goal_len, size_t candidate_len);
|
2021-03-04 14:08:44 +01:00
|
|
|
string bestCandidateInfo(const string& goal, EditDistance& distancer) const;
|
2020-04-14 04:51:35 +02:00
|
|
|
static void selfTestDistanceOne(const string& a, const string& b, EditDistance expected);
|
2019-07-14 02:30:32 +02:00
|
|
|
static void selfTestSuggestOne(bool matches, const string& c, const string& goal,
|
|
|
|
|
EditDistance dist);
|
|
|
|
|
};
|
|
|
|
|
|
2012-08-27 03:13:47 +02:00
|
|
|
//######################################################################
|
|
|
|
|
|
2019-05-19 22:13:13 +02:00
|
|
|
#endif // guard
|