mirror of
https://github.com/bulletphysics/bullet3
synced 2024-12-14 22:00:05 +00:00
251 lines
6.3 KiB
C++
251 lines
6.3 KiB
C++
|
|
|
|
#include <assert.h>
|
|
//#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "urdfStringSplit.h"
|
|
|
|
void urdfStringSplit( btAlignedObjectArray<std::string>&pieces, const std::string& vector_str, btAlignedObjectArray<std::string> separators)
|
|
{
|
|
assert(separators.size()==1);
|
|
if (separators.size()==1)
|
|
{
|
|
char** strArray = urdfStrSplit(vector_str.c_str(),separators[0].c_str());
|
|
int numSubStr = urdfStrArrayLen(strArray);
|
|
for (int i=0;i<numSubStr;i++)
|
|
pieces.push_back(std::string(strArray[i]));
|
|
urdfStrArrayFree(strArray);
|
|
}
|
|
}
|
|
btAlignedObjectArray<std::string> urdfIsAnyOf(const char* seps)
|
|
{
|
|
btAlignedObjectArray<std::string> strArray;
|
|
|
|
int numSeps = strlen(seps);
|
|
for (int i=0;i<numSeps;i++)
|
|
{
|
|
char sep2[2] = {0,0};
|
|
|
|
sep2[0] = seps[i];
|
|
strArray.push_back(sep2);
|
|
}
|
|
return strArray;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Append an item to a dynamically allocated array of strings. On failure,
|
|
return NULL, in which case the original array is intact. The item
|
|
string is dynamically copied. If the array is NULL, allocate a new
|
|
array. Otherwise, extend the array. Make sure the array is always
|
|
NULL-terminated. Input string might not be '\0'-terminated. */
|
|
char **urdfStrArrayAppend(char **array, size_t nitems, const char *item,
|
|
size_t itemlen)
|
|
{
|
|
/* Make a dynamic copy of the item. */
|
|
char *copy;
|
|
if (item == NULL)
|
|
copy = NULL;
|
|
else {
|
|
copy = (char*)malloc(itemlen + 1);
|
|
if (copy == NULL)
|
|
return NULL;
|
|
memcpy(copy, item, itemlen);
|
|
copy[itemlen] = '\0';
|
|
}
|
|
|
|
/* Extend array with one element. Except extend it by two elements,
|
|
in case it did not yet exist. This might mean it is a teeny bit
|
|
too big, but we don't care. */
|
|
array = (char**)realloc(array, (nitems + 2) * sizeof(array[0]));
|
|
if (array == NULL) {
|
|
free(copy);
|
|
return NULL;
|
|
}
|
|
|
|
/* Add copy of item to array, and return it. */
|
|
array[nitems] = copy;
|
|
array[nitems+1] = NULL;
|
|
return array;
|
|
}
|
|
|
|
|
|
/* Free a dynamic array of dynamic strings. */
|
|
void urdfStrArrayFree(char **array)
|
|
{
|
|
if (array == NULL)
|
|
return;
|
|
for (size_t i = 0; array[i] != NULL; ++i)
|
|
free(array[i]);
|
|
free(array);
|
|
}
|
|
|
|
|
|
/* Split a string into substrings. Return dynamic array of dynamically
|
|
allocated substrings, or NULL if there was an error. Caller is
|
|
expected to free the memory, for example with str_array_free. */
|
|
char **urdfStrSplit(const char *input, const char *sep)
|
|
{
|
|
size_t nitems = 0;
|
|
char **array = NULL;
|
|
const char *start = input;
|
|
const char *next = strstr(start, sep);
|
|
size_t seplen = strlen(sep);
|
|
const char *item;
|
|
size_t itemlen;
|
|
|
|
for (;;) {
|
|
next = strstr(start, sep);
|
|
if (next == NULL) {
|
|
/* Add the remaining string (or empty string, if input ends with
|
|
separator. */
|
|
char **newstr = urdfStrArrayAppend(array, nitems, start, strlen(start));
|
|
if (newstr == NULL) {
|
|
urdfStrArrayFree(array);
|
|
return NULL;
|
|
}
|
|
array = newstr;
|
|
++nitems;
|
|
break;
|
|
} else if (next == input) {
|
|
/* Input starts with separator. */
|
|
item = "";
|
|
itemlen = 0;
|
|
} else {
|
|
item = start;
|
|
itemlen = next - item;
|
|
}
|
|
char **newstr = urdfStrArrayAppend(array, nitems, item, itemlen);
|
|
if (newstr == NULL) {
|
|
urdfStrArrayFree(array);
|
|
return NULL;
|
|
}
|
|
array = newstr;
|
|
++nitems;
|
|
start = next + seplen;
|
|
}
|
|
|
|
if (nitems == 0) {
|
|
/* Input does not contain separator at all. */
|
|
assert(array == NULL);
|
|
array = urdfStrArrayAppend(array, nitems, input, strlen(input));
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
|
|
/* Return length of a NULL-delimited array of strings. */
|
|
size_t urdfStrArrayLen(char **array)
|
|
{
|
|
size_t len;
|
|
|
|
for (len = 0; array[len] != NULL; ++len)
|
|
continue;
|
|
return len;
|
|
}
|
|
|
|
#ifdef UNIT_TEST_STRING_SPLIT
|
|
|
|
#define MAX_OUTPUT 20
|
|
|
|
|
|
int main(void)
|
|
{
|
|
struct {
|
|
const char *input;
|
|
const char *sep;
|
|
char *output[MAX_OUTPUT];
|
|
} tab[] = {
|
|
/* Input is empty string. Output should be a list with an empty
|
|
string. */
|
|
{
|
|
"",
|
|
"and",
|
|
{
|
|
"",
|
|
NULL,
|
|
},
|
|
},
|
|
/* Input is exactly the separator. Output should be two empty
|
|
strings. */
|
|
{
|
|
"and",
|
|
"and",
|
|
{
|
|
"",
|
|
"",
|
|
NULL,
|
|
},
|
|
},
|
|
/* Input is non-empty, but does not have separator. Output should
|
|
be the same string. */
|
|
{
|
|
"foo",
|
|
"and",
|
|
{
|
|
"foo",
|
|
NULL,
|
|
},
|
|
},
|
|
/* Input is non-empty, and does have separator. */
|
|
{
|
|
"foo bar 1 and foo bar 2",
|
|
" and ",
|
|
{
|
|
"foo bar 1",
|
|
"foo bar 2",
|
|
NULL,
|
|
},
|
|
},
|
|
};
|
|
const int tab_len = sizeof(tab) / sizeof(tab[0]);
|
|
bool errors;
|
|
|
|
errors = false;
|
|
|
|
for (int i = 0; i < tab_len; ++i) {
|
|
printf("test %d\n", i);
|
|
|
|
char **output = str_split(tab[i].input, tab[i].sep);
|
|
if (output == NULL) {
|
|
fprintf(stderr, "output is NULL\n");
|
|
errors = true;
|
|
break;
|
|
}
|
|
size_t num_output = str_array_len(output);
|
|
printf("num_output %lu\n", (unsigned long) num_output);
|
|
|
|
size_t num_correct = str_array_len(tab[i].output);
|
|
if (num_output != num_correct) {
|
|
fprintf(stderr, "wrong number of outputs (%lu, not %lu)\n",
|
|
(unsigned long) num_output, (unsigned long) num_correct);
|
|
errors = true;
|
|
} else {
|
|
for (size_t j = 0; j < num_output; ++j) {
|
|
if (strcmp(tab[i].output[j], output[j]) != 0) {
|
|
fprintf(stderr, "output[%lu] is '%s' not '%s'\n",
|
|
(unsigned long) j, output[j], tab[i].output[j]);
|
|
errors = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
str_array_free(output);
|
|
printf("\n");
|
|
}
|
|
|
|
if (errors)
|
|
return EXIT_FAILURE;
|
|
return 0;
|
|
}
|
|
#endif//UNIT_TEST_STRING_SPLIT
|
|
|
|
|