#ifndef BADVPN_SPLIT_STRING_H #define BADVPN_SPLIT_STRING_H #include #include #include #include #include #include #include /** * 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