blob: b82c03eee7707dab63e6b384529c0be8713111a6 [file] [log] [blame]
// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
package str_utils_pkg;
`include "dv_macros.svh"
string msg_id = "str_utils_pkg";
// Returns 1 if string 's' has substring 'sub' within the given index range. 0 Otherwise.
function automatic bit str_has_substr(string s, string sub, int range_lo = 0, int range_hi = -1);
if (range_hi < 0 || range_hi >= s.len()) range_hi = s.len() - 1;
for (int i = range_lo; i <= (range_hi - sub.len() + 1); i++) begin
if (s.substr(i, i + sub.len() - 1) == sub) begin
return 1;
end
end
return 0;
endfunction : str_has_substr
// Returns the index of first occurrence of string 'sub' within string 's''s given index range.
// Returns -1 otherwise.
function automatic int str_find(string s, string sub, int range_lo = 0, int range_hi = -1);
if (range_hi < 0 || range_hi >= s.len()) range_hi = s.len() - 1;
for (int i = range_lo; i <= (range_hi - sub.len() + 1); i++) begin
if (s.substr(i, i + sub.len() - 1) == sub) begin
return i;
end
end
return -1;
endfunction : str_find
// Returns the index of last occurrence of string 'sub' within string 's''s given index range.
// Returns -1 otherwise.
function automatic int str_rfind(string s, string sub, int range_lo = 0, int range_hi = -1);
if (range_hi < 0 || range_hi >= s.len()) range_hi = s.len() - 1;
for (int i = (range_hi - sub.len() + 1); i >= range_lo; i--) begin
if (s.substr(i, i + sub.len() - 1) == sub) begin
return i;
end
end
return -1;
endfunction : str_rfind
// Find the first match string 'sub' in 's' and replace it with 'new_sub'.
// TODO: Add support for global replacement.
function automatic string str_replace(string s, string sub, string new_sub);
string str_before_sub, str_after_sub;
int lo_idx = str_find(s, sub);
// check sub string exists
`DV_CHECK_NE_FATAL(lo_idx, -1, $sformatf("sub string %s doesn't exist in %s", sub, s), msg_id)
// the new_str contains 3 portions {str_before_sub, new_sub, str_after_sub}
if (lo_idx > 0) str_before_sub = s.substr(0, lo_idx - 1);
if (lo_idx + sub.len() < s.len()) str_after_sub = s.substr(lo_idx + sub.len(), s.len() - 1);
return {str_before_sub, new_sub, str_after_sub};
endfunction : str_replace
// Strips a given set of characters in string 's'.
//
// The set of characters to strip is provided as a string. If not set, all whitespace characters
// are stripped by default. Stripping is done at both ends, unless the user turns off the
// stripping from one of the ends.
function automatic string str_strip(string s,
string chars = " \t\n",
bit lstrip = 1'b1,
bit rstrip = 1'b1);
byte chars_q[$];
if (chars == "") return s;
foreach (chars[i]) chars_q.push_back(chars.getc(i));
if (lstrip) begin
int i = 0;
while (s.getc(i) inside {chars_q}) i++;
s = s.substr(i, s.len() - 1);
end
if (rstrip) begin
int i = s.len() - 1;
while (s.getc(i) inside {chars_q}) i--;
s = s.substr(0, i);
end
return s;
endfunction : str_strip
// Splits the input `string` on the given single-character delimiter `delim`.
//
// The split tokens are pushed into the `result` queue. The whitespaces on each split token are
// stripped by default, which can be turned off.
// TODO: allow arbitrary length delimiter.
function automatic void str_split(input string s,
output string result[$],
input byte delim = " ",
input bit strip_whitespaces = 1'b1);
string sub;
bit in_quotes;
result = {};
foreach (s[i]) begin
if (s[i] == "\"") begin
in_quotes = !in_quotes;
end
if ((s.getc(i) == delim) && !in_quotes) begin
if (strip_whitespaces) sub = str_strip(sub);
if (sub != "") result.push_back(sub);
sub = "";
end else begin
sub = {sub, s[i]};
end
if (i == s.len() - 1) begin
if (strip_whitespaces) sub = str_strip(sub);
if (sub != "") result.push_back(sub);
end
end
endfunction : str_split
// Returns a string concatenated from the provided queue of strings 's'.
//
// The concatenation is performed using the 'delim' arg as the delimiter.
function automatic string str_join(string s[$], string delim = " ");
string str;
foreach (s[i]) begin
str = {str, s[i], delim};
end
if (str != "") begin
str = str.substr(0, str.len() - delim.len() - 1);
end
return str;
endfunction : str_join
// Converts a string to an array of bytes.
function automatic void str_to_bytes(string s, output byte bytes[]);
bytes = new[s.len()];
foreach (bytes[i]) begin
bytes[i] = s.getc(i);
end
endfunction : str_to_bytes
// Converts an array of bytes to a string.
function automatic string bytes_to_str(byte bytes[]);
string s;
foreach (bytes[i]) begin
s = {s, string'(bytes[i])};
end
return s;
endfunction
/************************/
/* File path functions. */
/************************/
// Returns the dirname of the file.
//
// Examples:
// path/to/foo.bar => path/to
// path/to/foo/bar => path/to/foo
// path/to/foo/bar/ => path/to/foo
// path/to/foo/bar/. => path/to/foo/bar
// / => /
function automatic string str_path_dirname(string filename);
int idx;
string dirname;
if (filename == "/") return filename;
filename = str_strip(.s(filename), .chars("/"), .lstrip(1'b0));
idx = str_rfind(.s(filename), .sub("/"));
if (idx == -1) idx = filename.len();
if (idx == 0) idx++;
dirname = filename.substr(0, idx - 1);
return dirname;
endfunction : str_path_dirname
// Returns the basename of the file.
//
// Optionally, it takes a bit flag to drop the extension from the basename if desired.
// Examples:
// path/to/foo.bar => (foo.bar, foo)
// path/to/foo/bar => (bar, bar)
// path/to/foo/bar/ => (bar, bar)
// path/to/foo/bar/. => (., .)
// / => (/, /)
function automatic string str_path_basename(string filename, bit drop_extn = 1'b0);
int idx;
string basename;
if (filename == "/") return filename;
filename = str_strip(.s(filename), .chars("/"), .lstrip(1'b0));
idx = str_rfind(.s(filename), .sub("/"));
basename = filename.substr(idx + 1, filename.len() - 1);
if (basename == ".") return basename;
if (drop_extn) begin
idx = str_find(.s(basename), .sub("."));
if (idx == -1) idx = basename.len();
basename = basename.substr(0, idx - 1);
end
return basename;
endfunction : str_path_basename
endpackage