Edit

kc3-lang/libxkbcommon/test/utils-text.c

Branch :

  • Show log

    Commit

  • Author : Pierre Le Marre
    Date : 2025-02-12 09:50:36
    Hash : a4038a47
    Message : Miscellaneous int types fixes

  • test/utils-text.c
  • /*
     * Copyright © 2024 Pierre Le Marre <dev@wismill.eu>
     * SPDX-License-Identifier: MIT
     */
    
    #include "config.h"
    
    #include <stdlib.h>
    #include <string.h>
    #include "src/darray.h"
    #include "src/utils.h"
    #include "test/utils-text.h"
    
    /* For each line, drop substring starting from a given needle, then drop
     * the line if the rest are only whitespaces. The needle must not contain
     * "\n". */
    char *
    strip_lines(const char *input, size_t input_length, const char *prefix)
    {
        darray_char buf = darray_new();
        const size_t prefix_len = strlen(prefix);
        const char *start = input;
        const char *end = input + input_length;
    
        const char *next = strstr(start, prefix);
        size_t count;
        while (start < end && next != NULL) {
            count = (size_t)(next - start);
            next = start + count + prefix_len;
            /* Find previous non-space */
            size_t i;
            for (i = count; i > 0; i--) {
                if (start[i - 1] != ' ' && start[i - 1] != '\t')
                    break;
            }
    
            bool dropped = false;
            /* Drop line if only whitespaces */
            if (i == 0 || start[i - 1] == '\n') {
                count = i;
                dropped = true;
            }
    
            /* Append string */
            darray_append_items(buf, start, count);
    
            /* Find end of line */
            if (next >= end) {
                start = end;
                break;
            }
            start = strchr(next, 0x0a);
            if (start == NULL) {
                start = end;
                break;
            }
    
            if (dropped)
                start++;
    
            next = strstr(start, prefix);
        }
    
        /* Append remaining */
        if (start < end) {
            count = (size_t)(end - start);
            darray_append_items(buf, start, count);
        }
    
        darray_append(buf, '\0');
        return buf.item;
    }
    
    char *
    uncomment(const char *input, size_t input_length, const char *prefix)
    {
        darray_char buf = darray_new();
        const size_t prefix_len = strlen(prefix);
        const char *start = input;
        const char *end = input + input_length;
    
        char *next = strstr(start, prefix);
        size_t count;
        while (start < end && next != NULL) {
            count = (size_t)(next - start);
            darray_append_items(buf, start, count);
    
            /* Skip prefix */
            start += count + prefix_len;
    
            /* Find end of line */
            if (start >= end)
                break;
            next = strchr(start, 0x0a);
            if (next == NULL)
                break;
            next = strstr(next, prefix);
        }
    
        /* Append remaining */
        if (start < end) {
            count = (size_t)(end - start);
            darray_append_items(buf, start, count);
        }
    
        darray_append(buf, '\0');
        return buf.item;
    }
    
    /* Split string into lines */
    size_t
    split_lines(const char *input, size_t input_length,
                struct text_line *output, size_t output_length)
    {
        const char *start = input;
        char *next;
        size_t l;
        size_t i = 0;
    
        for (l = 0; i < input_length && l < output_length && *start != '\0'; l++) {
            /* Look for newline character */
            next = strchr(start, 0x0a);
            output[l].start = start;
            if (next == NULL) {
                /* Not found: add the rest of the string */
                output[l++].length = strlen(start);
                break;
            }
            output[l].length = (size_t)(next - start) + 1;
            start = next + 1;
            i += output[l].length;
        }
        return l;
    }
    
    size_t
    concat_lines(struct text_line *lines, size_t length,
                 const char *sep, char *output)
    {
        char *out = output;
        size_t sep_len = strlen(sep);
        for (size_t i = 0; i < length; i++) {
            if (i > 0) {
                memcpy(out, sep, sep_len);
                out += sep_len;
            }
            memcpy(out, lines[i].start, lines[i].length);
            out += lines[i].length;
        }
        *out = '\0';
        return (size_t)(out - output);
    }
    
    size_t
    shuffle_lines(struct text_line *lines, size_t length, char *output)
    {
        /* Shuffle lines in-place using Fisher–Yates algorithm.
         * See: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle */
    
        assert(length < RAND_MAX);
        char *out = output;
        if (length > 1) {
            /* 1. Set the current i to the last line.
             * 2. Take a random line j before the current line i.
             * 3. Swap the lines i and j.
             * 4. Append line i to the output.
             * 5. If i is the first line, stop. Else decrease i and go to 2).
             */
            for (size_t i = length - 1; i > 0; i--) {
                /* Swap current line with random line before it */
                size_t j = rand() % (i+1);
                struct text_line tmp = lines[j];
                lines[j] = lines[i];
                lines[i] = tmp;
                /* Append current line */
                memcpy(out, lines[i].start, lines[i].length);
                out += lines[i].length;
                /* Ensure line ends with newline */
                if (out[-1] != '\n') {
                    out[0] = '\n';
                    out++;
                }
            }
        }
        return (size_t)(out - output);
    }