libyml/
string.rs

1use crate::{
2    externs::memset,
3    libc,
4    memory::{yaml_realloc, yaml_strdup},
5    yaml::{size_t, yaml_char_t},
6};
7
8/// Extend a string buffer by reallocating and copying the existing data.
9///
10/// This function is used to grow a string buffer when more space is needed.
11///
12/// # Safety
13///
14/// - This function is unsafe because it directly calls the system's `realloc` and
15///   `memset` functions, which can lead to undefined behaviour if misused.
16/// - The caller must ensure that `start`, `pointer`, and `end` are valid pointers
17///   into the same allocated memory block.
18/// - The caller must ensure that the memory block being extended is large enough
19///   to accommodate the new size.
20/// - The caller is responsible for properly freeing the extended memory block using
21///   the corresponding `yaml_free` function when it is no longer needed.
22///
23pub unsafe fn yaml_string_extend(
24    start: *mut *mut yaml_char_t,
25    pointer: *mut *mut yaml_char_t,
26    end: *mut *mut yaml_char_t,
27) {
28    let current_size = (*end).offset_from(*start) as size_t;
29    let new_size = current_size * 2;
30
31    let new_start: *mut yaml_char_t =
32        yaml_realloc(*start as *mut libc::c_void, new_size)
33            as *mut yaml_char_t;
34    let _ = memset(
35        new_start.add(current_size.try_into().unwrap())
36            as *mut libc::c_void,
37        0,
38        current_size,
39    );
40
41    let offset = (*pointer).offset_from(*start);
42    *pointer = new_start.add(offset.try_into().unwrap());
43    *end = new_start.add((new_size as isize).try_into().unwrap());
44    *start = new_start;
45}
46
47/// Duplicate a null-terminated string.
48/// # Safety
49/// - This function is unsafe because it involves memory allocation.
50pub unsafe fn yaml_string_duplicate(
51    str: *const yaml_char_t,
52) -> *mut yaml_char_t {
53    yaml_strdup(str)
54}
55
56/// Join two string buffers by copying data from one to the other.
57///
58/// This function is used to concatenate two string buffers.
59///
60/// # Safety
61///
62/// - This function is unsafe because it directly calls the system's `memcpy` function,
63///   which can lead to undefined behaviour if misused.
64/// - The caller must ensure that `a_start`, `a_pointer`, `a_end`, `b_start`, `b_pointer`,
65///   and `b_end` are valid pointers into their respective allocated memory blocks.
66/// - The caller must ensure that the memory blocks being joined are large enough to
67///   accommodate the combined data.
68/// - The caller is responsible for properly freeing the joined memory block using
69///   the corresponding `yaml_free` function when it is no longer needed.
70///
71pub unsafe fn yaml_string_join(
72    a_start: *mut *mut yaml_char_t,
73    a_pointer: *mut *mut yaml_char_t,
74    a_end: *mut *mut yaml_char_t,
75    b_start: *mut *mut yaml_char_t,
76    b_pointer: *mut *mut yaml_char_t,
77    b_end: *mut *mut yaml_char_t,
78) {
79    // If b_start is equal to b_pointer, there's nothing to join
80    if *b_start == *b_pointer {
81        return;
82    }
83
84    // Calculate the length of the data in b
85    let b_length = ((*b_pointer).offset_from(*b_start))
86        .min((*b_end).offset_from(*b_start))
87        as usize;
88
89    // If the length of b is 0, there's nothing to copy
90    if b_length == 0 {
91        return;
92    }
93
94    // Ensure there's enough space in a to hold b's content
95    while ((*a_end).offset_from(*a_pointer) as usize) < b_length {
96        yaml_string_extend(a_start, a_pointer, a_end);
97    }
98
99    // Copy b's content to a
100    core::ptr::copy_nonoverlapping(*b_start, *a_pointer, b_length);
101
102    // Move a's pointer forward by the length of the copied data
103    *a_pointer = (*a_pointer).add(b_length);
104}