| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- /*
- * Copyright © 2024 Pierre Le Marre <dev@wismill.eu>
- * SPDX-License-Identifier: MIT
- */
- #include "config.h"
- #include "test-config.h"
- #include <stdlib.h>
- #include <string.h>
- #include "src/darray.h"
- #include "src/utils.h"
- #include "src/utils-random.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, (darray_size_t) 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, (darray_size_t) count);
- }
- darray_append(buf, '\0');
- return darray_items(buf);
- }
- 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;
- const char *next = strstr(start, prefix);
- size_t count;
- while (start < end && next != NULL) {
- count = (size_t)(next - start);
- darray_append_items(buf, start, (darray_size_t) 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, (darray_size_t) count);
- }
- darray_append(buf, '\0');
- return darray_items(buf);
- }
- /* 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;
- const 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 = random() % (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);
- }
|