| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246 |
- #ifndef BADVPN_SPLIT_STRING_H
- #define BADVPN_SPLIT_STRING_H
- #include <string.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <limits.h>
- #include <misc/balloc.h>
- #include <misc/debug.h>
- #include <misc/expstring.h>
- /**
- * Splits the given string by a character, and returns the result
- * as a malloc'd array of char pointers, each malloc'd. The array
- * is terminated by a NULL pointer.
- *
- * @param str string to split
- * @param del delimiter character
- * @return pointer to array of strings, or NULL on failure. On success,
- * at least one string will always be returned.
- */
- static char ** split_string (const char *str, char del);
- /**
- * Counts the number of strings in an array (same format as used by
- * {@link split_string}).
- *
- * @param names pointer to array of strings; must not be NULL.
- * @return number of strings
- */
- static size_t count_strings (char **names);
- /**
- * Frees an array of strings (same format as used by
- * {@link split_string}). This first frees the individual strings,
- * then the whole array.
- *
- * @param names pointer to array of strings; must not be NULL.
- */
- static void free_strings (char **names);
- /**
- * Concatenates the given strings, inserting a delimiter character
- * in between. The result is returned as a newly malloc'd string.
- * If there are no strings, an empty string is produced.
- * If there is just one string, this string is copied.
- *
- * @param names pointer to array of strings; must not be NULL.
- * Format is as returned by {@link split_string}.
- * @param del delimiter to insert between strings
- * @return resulting malloc'd string, or NULL on failure.
- */
- static char * implode_strings (char **names, char del);
- /**
- * Splits the given string by a character in-place by replacing
- * all delimiting characters with nulls, and returns the number
- * of such replacements.
- *
- * @param str string to split in-place; must not be NULL.
- * @param del delimiter character
- * @return number of replaced characters, or equivalently, number
- * of resulting strings minus one
- */
- static size_t split_string_inplace2 (char *str, char del);
- /**
- * Concatenates the given strings, inserting a delimiter character
- * in between. The result is returned as a newly malloc'd string.
- * If there are no strings, an empty string is produced.
- * If there is just one string, this string is copied.
- *
- * @param names pointer to a character array containing the
- * null-terinated strings one after another, i.e.
- * as produced by {@link split_string_inplace2}.
- * Must not be NULL.
- * @param num_names number of strings, e.g. the return value of
- * {@link split_string_inplace2} plus one
- * @param del delimiter to insert between strings
- * @return resulting malloc'd string, or NULL on failure.
- */
- static char * implode_compact_strings (const char *names, size_t num_names, char del);
- static char ** split_string (const char *str, char del)
- {
- size_t len = strlen(str);
-
- // count parts
- size_t num_parts = 0;
- size_t i = 0;
- while (1) {
- size_t j = i;
- while (j < len && str[j] != del) j++;
-
- num_parts++;
-
- if (num_parts == SIZE_MAX) { // need to allocate +1 pointer
- goto fail0;
- }
-
- if (j == len) {
- break;
- }
-
- i = j + 1;
- }
-
- // allocate array for part pointers
- char **result = BAllocArray(num_parts + 1, sizeof(*result));
- if (!result) {
- goto fail0;
- }
-
- num_parts = 0;
- i = 0;
- while (1) {
- size_t j = i;
- while (j < len && str[j] != del) j++;
-
- if (!(result[num_parts] = malloc(j - i + 1))) {
- goto fail1;
- }
- memcpy(result[num_parts], str + i, j - i);
- result[num_parts][j - i] = '\0';
-
- num_parts++;
-
- if (j == len) {
- break;
- }
-
- i = j + 1;
- }
-
- result[num_parts] = NULL;
-
- return result;
-
- fail1:
- while (num_parts-- > 0) {
- free(result[num_parts]);
- }
- BFree(result);
- fail0:
- return NULL;
- }
- static size_t count_strings (char **names)
- {
- ASSERT(names)
-
- size_t i;
- for (i = 0; names[i]; i++);
-
- return i;
- }
- static void free_strings (char **names)
- {
- ASSERT(names)
-
- size_t i = count_strings(names);
-
- while (i-- > 0) {
- free(names[i]);
- }
-
- BFree(names);
- }
- static char * implode_strings (char **names, char del)
- {
- ASSERT(names)
-
- ExpString str;
- if (!ExpString_Init(&str)) {
- goto fail0;
- }
-
- for (size_t i = 0; names[i]; i++) {
- if (i > 0 && !ExpString_AppendChar(&str, del)) {
- goto fail1;
- }
- if (!ExpString_Append(&str, names[i])) {
- goto fail1;
- }
- }
-
- return ExpString_Get(&str);
-
- fail1:
- ExpString_Free(&str);
- fail0:
- return NULL;
- }
- static size_t split_string_inplace2 (char *str, char del)
- {
- ASSERT(str)
-
- size_t num_extra_parts = 0;
-
- while (*str) {
- if (*str == del) {
- *str = '\0';
- num_extra_parts++;
- }
- str++;
- }
-
- return num_extra_parts;
- }
- static char * implode_compact_strings (const char *names, size_t num_names, char del)
- {
- ASSERT(names)
-
- ExpString str;
- if (!ExpString_Init(&str)) {
- goto fail0;
- }
-
- int is_first = 1;
-
- while (num_names > 0) {
- if (!is_first && !ExpString_AppendChar(&str, del)) {
- goto fail1;
- }
- if (!ExpString_Append(&str, names)) {
- goto fail1;
- }
- names += strlen(names) + 1;
- num_names--;
- is_first = 0;
- }
-
- return ExpString_Get(&str);
-
- fail1:
- ExpString_Free(&str);
- fail0:
- return NULL;
- }
- #endif
|