nstd_sys/core/cstr/raw.rs
1//! Raw C string processing.
2use crate::{NSTDBool, NSTDChar, NSTDUInt};
3use cfg_if::cfg_if;
4use nstdapi::nstdapi;
5
6/// Gets the length of a raw null terminated C string, not counting the C string's null byte.
7///
8/// # Parameters:
9///
10/// - `const NSTDChar *cstr` - The null terminated C string.
11///
12/// # Returns
13///
14/// `NSTDUInt len` - The length of the C string, not counting the C string's null byte.
15///
16/// # Safety
17///
18/// `cstr` must point to a character array that is valid for reads up until and including it's
19/// null-terminating byte.
20///
21/// # Example
22///
23/// ```
24/// use nstd_sys::core::cstr::raw::nstd_core_cstr_raw_len;
25///
26/// let cstr = b"Hello, world!\0";
27/// assert!(unsafe { nstd_core_cstr_raw_len(cstr.as_ptr().cast()) } == 13);
28/// ```
29#[inline]
30#[nstdapi]
31#[allow(unused_mut, clippy::missing_const_for_fn)]
32pub unsafe fn nstd_core_cstr_raw_len(mut cstr: *const NSTDChar) -> NSTDUInt {
33 cfg_if! {
34 if #[cfg(all(
35 any(
36 unix,
37 windows,
38 any(target_env = "wasi", target_os = "wasi"),
39 target_os = "solid_asp3",
40 target_os = "teeos"
41 ),
42 feature = "libc"
43 ))] {
44 libc::strlen(cstr)
45 } else {
46 let mut i = 0;
47 #[allow(clippy::arithmetic_side_effects)]
48 while *cstr != 0 {
49 cstr = cstr.offset(1);
50 i += 1;
51 }
52 i
53 }
54 }
55}
56
57/// Gets the length of a raw null terminated C string, counting the C string's null byte.
58///
59/// # Parameters:
60///
61/// - `const NSTDChar *cstr` - The null terminated C string.
62///
63/// # Returns
64///
65/// `NSTDUInt len` - The length of the C string, counting the C string's null byte.
66///
67/// # Safety
68///
69/// `cstr` must point to a character array that is valid for reads up until and including it's
70/// null-terminating byte.
71///
72/// # Example
73///
74/// ```
75/// use nstd_sys::core::cstr::raw::nstd_core_cstr_raw_len_with_null;
76///
77/// let cstr = b"Hello, world!\0";
78/// assert!(unsafe { nstd_core_cstr_raw_len_with_null(cstr.as_ptr().cast()) } == 14);
79/// ```
80#[inline]
81#[nstdapi]
82#[allow(clippy::arithmetic_side_effects)]
83pub unsafe fn nstd_core_cstr_raw_len_with_null(cstr: *const NSTDChar) -> NSTDUInt {
84 nstd_core_cstr_raw_len(cstr) + 1
85}
86
87/// Compares two raw null-terminated C strings, returning `NSTD_TRUE` if they are lexicographically
88/// equal.
89///
90/// # Parameters:
91///
92/// - `const NSTDChar *cstr1` - The first C string.
93///
94/// - `const NSTDChar *cstr2` - The second C string.
95///
96/// # Returns
97///
98/// `NSTDBool is_eq` - `NSTD_TRUE` if the two C strings are lexicographically equal.
99///
100/// # Safety
101///
102/// Both `cstr1` and `cstr2` must point to character arrays that are valid for reads up until and
103/// including their null-terminating bytes.
104///
105/// # Example
106///
107/// ```
108/// use nstd_sys::{core::cstr::raw::nstd_core_cstr_raw_compare, NSTD_FALSE};
109///
110/// let cstr1 = b"Hello, world!\0".as_ptr().cast();
111/// let cstr2 = b"Hello world!\0".as_ptr().cast();
112///
113/// assert!(unsafe { nstd_core_cstr_raw_compare(cstr1, cstr2) } == NSTD_FALSE);
114/// ```
115#[nstdapi]
116#[allow(unused_mut)]
117pub unsafe fn nstd_core_cstr_raw_compare(
118 mut cstr1: *const NSTDChar,
119 mut cstr2: *const NSTDChar,
120) -> NSTDBool {
121 cfg_if! {
122 if #[cfg(all(
123 any(
124 unix,
125 windows,
126 any(target_env = "wasi", target_os = "wasi"),
127 target_os = "solid_asp3",
128 target_os = "teeos"
129 ),
130 feature = "libc"
131 ))] {
132 libc::strcmp(cstr1, cstr2) == 0
133 } else {
134 use crate::{NSTD_FALSE, NSTD_TRUE};
135 // If the C strings point to the same data return true.
136 if cstr1 == cstr2 {
137 return NSTD_TRUE;
138 }
139 // Otherwise compare them lexicographically.
140 while *cstr1 == *cstr2 {
141 if *cstr1 == 0 {
142 return NSTD_TRUE;
143 }
144 cstr1 = cstr1.offset(1);
145 cstr2 = cstr2.offset(1);
146 }
147 NSTD_FALSE
148 }
149 }
150}
151
152/// Copies the contents of one raw C string to another, excluding the source's null-terminator.
153///
154/// # Note
155///
156/// If you already know how many bytes should be copied, `nstd_core_mem_copy[_overlapped]` should
157/// be used instead as it can minimize execution times.
158///
159/// # Parameters:
160///
161/// - `NSTDChar *dest` - The C string buffer to copy data to.
162///
163/// - `const NSTDChar *src` - The C string to copy data from.
164///
165/// # Safety
166///
167/// - `src` must point to a character array that is valid for reads up until and including it's
168/// null-terminating byte.
169///
170/// - `dest` must point to a character array that is valid for writes.
171///
172/// - `dest`'s buffer must be large enough to contain the contents of `src`.
173///
174/// # Example
175///
176/// ```
177/// use nstd_sys::core::cstr::raw::nstd_core_cstr_raw_copy;
178///
179/// let cstr = b"Hello, world!\0";
180/// let mut buffer = [0u8; 14];
181///
182/// unsafe { nstd_core_cstr_raw_copy(buffer.as_mut_ptr().cast(), cstr.as_ptr().cast()) };
183/// assert!(&buffer == cstr);
184/// ```
185#[inline]
186#[nstdapi]
187#[allow(clippy::missing_const_for_fn)]
188pub unsafe fn nstd_core_cstr_raw_copy(mut dest: *mut NSTDChar, mut src: *const NSTDChar) {
189 while *src != 0 {
190 *dest = *src;
191 dest = dest.offset(1);
192 src = src.offset(1);
193 }
194}
195
196/// Copies the contents of one raw C string to another, including the source's null-terminator.
197///
198/// # Note
199///
200/// If you already know how many bytes should be copied, `nstd_core_mem_copy[_overlapped]` should
201/// be used instead as it can minimize execution times.
202///
203/// # Parameters:
204///
205/// - `NSTDChar *dest` - The C string buffer to copy data to.
206///
207/// - `const NSTDChar *src` - The C string to copy data from.
208///
209/// # Safety
210///
211/// - `src` must point to a character array that is valid for reads up until and including it's
212/// null-terminating byte.
213///
214/// - `dest` must point to a character array that is valid for writes.
215///
216/// - `dest`'s buffer must be large enough to contain the contents of `src`, including it's
217/// null-terminating byte.
218///
219/// # Example
220///
221/// ```
222/// use nstd_sys::core::cstr::raw::nstd_core_cstr_raw_copy_with_null;
223///
224/// let cstr = b"Hello, world!\0";
225/// let mut buffer = [u8::MAX; 14];
226///
227/// let buf_ptr = buffer.as_mut_ptr().cast();
228/// unsafe { nstd_core_cstr_raw_copy_with_null(buf_ptr, cstr.as_ptr().cast()) };
229/// assert!(&buffer == cstr);
230/// ```
231#[inline]
232#[nstdapi]
233#[allow(unused_mut, clippy::missing_const_for_fn)]
234pub unsafe fn nstd_core_cstr_raw_copy_with_null(mut dest: *mut NSTDChar, mut src: *const NSTDChar) {
235 cfg_if! {
236 if #[cfg(all(
237 any(
238 unix,
239 windows,
240 any(target_env = "wasi", target_os = "wasi"),
241 target_os = "solid_asp3",
242 target_os = "teeos"
243 ),
244 feature = "libc"
245 ))] {
246 libc::strcpy(dest, src);
247 } else {
248 while {
249 *dest = *src;
250 *src != 0
251 } {
252 dest = dest.offset(1);
253 src = src.offset(1);
254 }
255 }
256 }
257}