Skip to content

Commit f81c761

Browse files
NlightNFotisTGWDB
andcommitted
Add new C-style string splitting function to string_utils.
The motivation for this is that we need to split strings into C-style `**char`, to later pass them on to system calls that are based on that interface. Co-authored-by: Fotis Koutoulakis <[email protected]> Co-authored-by: Thomas Given-Wilson <[email protected]>
1 parent 9539a51 commit f81c761

File tree

4 files changed

+88
-0
lines changed

4 files changed

+88
-0
lines changed

src/util/string_utils.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
2+
13
/*******************************************************************\
24
35
Module:
@@ -12,6 +14,7 @@ Author: Daniel Poetzl
1214

1315
#include <algorithm>
1416
#include <cctype>
17+
#include <cstring>
1518
#include <iomanip>
1619

1720
/// Remove all whitespace characters from either end of a string. Whitespace
@@ -252,3 +255,23 @@ std::string wrap_line(
252255

253256
return result;
254257
}
258+
259+
char **string_to_cstr_array(const std::string &s, const char *delims)
260+
{
261+
char **res = NULL;
262+
int n_spaces = 0;
263+
char *p = strtok(strdup(s.c_str()), delims);
264+
265+
while(p)
266+
{
267+
res = reinterpret_cast<char **>(realloc(res, sizeof(char *) * ++n_spaces));
268+
INVARIANT(res != nullptr, "Memory allocation failed");
269+
res[n_spaces - 1] = p;
270+
p = strtok(NULL, delims);
271+
}
272+
273+
res =
274+
reinterpret_cast<char **>(realloc(res, sizeof(char *) * (n_spaces + 1)));
275+
res[n_spaces] = 0;
276+
return res;
277+
}

src/util/string_utils.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,14 @@ std::string wrap_line(
146146
const std::size_t left_margin = 0,
147147
const std::size_t width = 80);
148148

149+
/// Split a string into an array of char*.
150+
///
151+
/// This was motivated by string handling for passing arguments to low
152+
/// level system calls, that have C style signatures.
153+
/// \param s: The string to split
154+
/// \param delims: The delimiter characters to split on
155+
/// \return a NULL terminated char** that has each of the space delimited
156+
/// substrings of the input.
157+
char **string_to_cstr_array(const std::string &s, const char *delims);
158+
149159
#endif

unit/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ SRC += analyses/ai/ai.cpp \
142142
util/string_utils/join_string.cpp \
143143
util/string_utils/split_string.cpp \
144144
util/string_utils/strip_string.cpp \
145+
util/string_utils/string_to_cstyle_array.cpp \
145146
util/string_utils/wrap_line.cpp \
146147
util/symbol_table.cpp \
147148
util/symbol.cpp \
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/// \file string_to_cstr_array Unit Tests
2+
/// \author Diffblue Ltd.
3+
4+
#include <testing-utils/use_catch.h>
5+
#include <util/string_utils.h>
6+
7+
TEST_CASE(
8+
"Split a simple string into three parts",
9+
"[core][utils][string_utils][string_to_c_style_array]")
10+
{
11+
const std::string test_string = "The Jabberwocky bites";
12+
char **result = string_to_cstr_array(test_string, " ");
13+
14+
REQUIRE(strcmp(result[0], "The") == 0);
15+
REQUIRE(strcmp(result[1], "Jabberwocky") == 0);
16+
REQUIRE(strcmp(result[2], "bites") == 0);
17+
REQUIRE(result[3] == 0);
18+
}
19+
20+
TEST_CASE(
21+
"Split an empty string",
22+
"[core][utils][string_utils][string_to_c_style_array]")
23+
{
24+
const std::string test_string = "";
25+
char **result = string_to_cstr_array(test_string, " ");
26+
27+
REQUIRE(result[0] == 0);
28+
}
29+
30+
TEST_CASE(
31+
"Split a simple string into three parts with more spaces",
32+
"[core][utils][string_utils][string_to_c_style_array]")
33+
{
34+
const std::string test_string = "The Jabberwocky bites";
35+
char **result = string_to_cstr_array(test_string, " ");
36+
37+
REQUIRE(strcmp(result[0], "The") == 0);
38+
REQUIRE(strcmp(result[1], "Jabberwocky") == 0);
39+
REQUIRE(strcmp(result[2], "bites") == 0);
40+
REQUIRE(result[3] == 0);
41+
}
42+
43+
TEST_CASE(
44+
"Split a simple string into three parts with more spaces and tabs",
45+
"[core][utils][string_utils][string_to_c_style_array]")
46+
{
47+
const std::string test_string = "The \tJabberwocky \tbites";
48+
char **result = string_to_cstr_array(test_string, " \t");
49+
50+
REQUIRE(strcmp(result[0], "The") == 0);
51+
REQUIRE(strcmp(result[1], "Jabberwocky") == 0);
52+
REQUIRE(strcmp(result[2], "bites") == 0);
53+
REQUIRE(result[3] == 0);
54+
}

0 commit comments

Comments
 (0)