<commit_before>#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>

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;
}

#endif
<commit_msg>misc: split_string: add count_strings(), free_strings()<commit_after>#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>

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);
}

#endif

{'fraction_non_alphanumeric': 0.13731433767808426, 'fraction_numerical': 0.011518642012731131, 'mean_word_length': 1.5267993874425727, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5068500', 'n_tokens_mistral': 1213, 'n_tokens_neox': 1180, 'n_words': 291}