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}