| // 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 |