bullet3/examples/Importers/ImportURDFDemo/urdfStringSplit.cpp

257 lines
5.3 KiB
C++
Raw Normal View History

#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, const 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);
}
}
void 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);
}
}
/* 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