xref: /drstd/dlibc/src/unix/header/string/mod.rs (revision 86982c5e9b2eaa583327251616ee822c36288824)
1 //! string implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/string.h.html
2 
3 use core::{mem, ptr, slice, usize};
4 use crate::unix::platform;
5 use cbitset::BitSet256;
6 use crate::unix::header::{errno::*, signal};
7 use crate::unix::header::string::slice::memchr;
8 
9 #[no_mangle]
10 pub unsafe extern "C" fn memccpy(
11     dest: *mut ::c_void,
12     src: *const ::c_void,
13     c: ::c_int,
14     n: ::size_t,
15 ) -> *mut ::c_void {
16     let to = memchr(src, c, n);
17     if to.is_null() {
18         return to;
19     }
20     let dist = (to as usize) - (src as usize);
21     if memcpy(dest, src, dist).is_null() {
22         return ptr::null_mut();
23     }
24     (dest as *mut u8).add(dist + 1) as *mut ::c_void
25 }
26 
27 #[no_mangle]
28 pub unsafe extern "C" fn memchr(
29     haystack: *const ::c_void,
30     needle: ::c_int,
31     len: ::size_t,
32 ) -> *mut ::c_void {
33     let haystack = slice::from_raw_parts(haystack as *const u8, len as usize);
34 
35     match memchr::memchr(needle as u8, haystack) {
36         Some(index) => haystack[index..].as_ptr() as *mut ::c_void,
37         None => ptr::null_mut(),
38     }
39 }
40 
41 #[no_mangle]
42 pub unsafe extern "C" fn memcmp(s1: *const ::c_void, s2: *const ::c_void, n: ::size_t) -> ::c_int {
43     let (div, rem) = (n / mem::size_of::<usize>(), n % mem::size_of::<usize>());
44     let mut a = s1 as *const usize;
45     let mut b = s2 as *const usize;
46     for _ in 0..div {
47         if *a != *b {
48             for i in 0..mem::size_of::<usize>() {
49                 let c = *(a as *const u8).add(i);
50                 let d = *(b as *const u8).add(i);
51                 if c != d {
52                     return c as ::c_int - d as ::c_int;
53                 }
54             }
55             unreachable!()
56         }
57         a = a.offset(1);
58         b = b.offset(1);
59     }
60 
61     let mut a = a as *const u8;
62     let mut b = b as *const u8;
63     for _ in 0..rem {
64         if *a != *b {
65             return *a as ::c_int - *b as ::c_int;
66         }
67         a = a.offset(1);
68         b = b.offset(1);
69     }
70     0
71 }
72 
73 #[no_mangle]
74 pub unsafe extern "C" fn memcpy(s1: *mut ::c_void, s2: *const ::c_void, n: ::size_t) -> *mut ::c_void {
75     let mut i = 0;
76     while i + 7 < n {
77         *(s1.add(i) as *mut u64) = *(s2.add(i) as *const u64);
78         i += 8;
79     }
80     while i < n {
81         *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i);
82         i += 1;
83     }
84     s1
85 }
86 
87 #[no_mangle]
88 pub unsafe extern "C" fn memmove(s1: *mut ::c_void, s2: *const ::c_void, n: ::size_t) -> *mut ::c_void {
89     if s2 < s1 as *const ::c_void {
90         // copy from end
91         let mut i = n;
92         while i != 0 {
93             i -= 1;
94             *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i);
95         }
96     } else {
97         // copy from beginning
98         let mut i = 0;
99         while i < n {
100             *(s1 as *mut u8).add(i) = *(s2 as *const u8).add(i);
101             i += 1;
102         }
103     }
104     s1
105 }
106 
107 #[no_mangle]
108 pub unsafe extern "C" fn memrchr(
109     haystack: *const ::c_void,
110     needle: ::c_int,
111     len: ::size_t,
112 ) -> *mut ::c_void {
113     let haystack = slice::from_raw_parts(haystack as *const u8, len as usize);
114 
115     match memchr::memrchr(needle as u8, haystack) {
116         Some(index) => haystack[index..].as_ptr() as *mut ::c_void,
117         None => ptr::null_mut(),
118     }
119 }
120 
121 #[no_mangle]
122 pub unsafe extern "C" fn memset(s: *mut ::c_void, c: ::c_int, n: ::size_t) -> *mut ::c_void {
123     for i in 0..n {
124         *(s as *mut u8).add(i) = c as u8;
125     }
126     s
127 }
128 
129 #[no_mangle]
130 pub unsafe extern "C" fn strchr(mut s: *const ::c_char, c: ::c_int) -> *mut ::c_char {
131     let c = c as ::c_char;
132     while *s != 0 {
133         if *s == c {
134             return s as *mut ::c_char;
135         }
136         s = s.offset(1);
137     }
138     ptr::null_mut()
139 }
140 
141 #[no_mangle]
142 pub unsafe extern "C" fn strcmp(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int {
143     strncmp(s1, s2, usize::MAX)
144 }
145 
146 #[no_mangle]
147 pub unsafe extern "C" fn strcoll(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int {
148     // relibc has no locale stuff (yet)
149     strcmp(s1, s2)
150 }
151 
152 #[no_mangle]
153 pub unsafe extern "C" fn strcpy(dst: *mut ::c_char, src: *const ::c_char) -> *mut ::c_char {
154     let mut i = 0;
155 
156     loop {
157         let byte = *src.offset(i);
158         *dst.offset(i) = byte;
159 
160         if byte == 0 {
161             break;
162         }
163 
164         i += 1;
165     }
166 
167     dst
168 }
169 
170 pub unsafe fn inner_strspn(s1: *const ::c_char, s2: *const ::c_char, cmp: bool) -> ::size_t {
171     let mut s1 = s1 as *const u8;
172     let mut s2 = s2 as *const u8;
173 
174     // The below logic is effectively ripped from the musl implementation. It
175     // works by placing each byte as it's own bit in an array of numbers. Each
176     // number can hold up to 8 * mem::size_of::<usize>() bits. We need 256 bits
177     // in total, to fit one byte.
178 
179     let mut set = BitSet256::new();
180 
181     while *s2 != 0 {
182         set.insert(*s2 as usize);
183         s2 = s2.offset(1);
184     }
185 
186     let mut i = 0;
187     while *s1 != 0 {
188         if set.contains(*s1 as usize) != cmp {
189             break;
190         }
191         i += 1;
192         s1 = s1.offset(1);
193     }
194     i
195 }
196 
197 #[no_mangle]
198 pub unsafe extern "C" fn strcspn(s1: *const ::c_char, s2: *const ::c_char) -> ::size_t {
199     inner_strspn(s1, s2, false)
200 }
201 
202 #[no_mangle]
203 pub unsafe extern "C" fn strdup(s1: *const ::c_char) -> *mut ::c_char {
204     strndup(s1, usize::MAX)
205 }
206 
207 #[no_mangle]
208 pub unsafe extern "C" fn strndup(s1: *const ::c_char, size: ::size_t) -> *mut ::c_char {
209     let len = strnlen(s1, size);
210 
211     // the "+ 1" is to account for the NUL byte
212     let buffer = platform::alloc(len + 1) as *mut ::c_char;
213     if buffer.is_null() {
214         platform::errno = ENOMEM as ::c_int;
215     } else {
216         //memcpy(buffer, s1, len)
217         for i in 0..len {
218             *buffer.add(i) = *s1.add(i);
219         }
220         *buffer.add(len) = 0;
221     }
222 
223     buffer
224 }
225 
226 #[no_mangle]
227 pub unsafe extern "C" fn strerror(errnum: ::c_int) -> *mut ::c_char {
228     use core::fmt::Write;
229 
230     static mut strerror_buf: [u8; 256] = [0; 256];
231 
232     let mut w = platform::StringWriter(strerror_buf.as_mut_ptr(), strerror_buf.len());
233 
234     if errnum >= 0 && errnum < STR_ERROR.len() as ::c_int {
235         let _ = w.write_str(STR_ERROR[errnum as usize]);
236     } else {
237         let _ = w.write_fmt(format_args!("Unknown error {}", errnum));
238     }
239 
240     strerror_buf.as_mut_ptr() as *mut ::c_char
241 }
242 
243 #[no_mangle]
244 pub unsafe extern "C" fn strerror_r(errnum: ::c_int, buf: *mut ::c_char, buflen: ::size_t) -> ::c_int {
245     let msg = strerror(errnum);
246     let len = strlen(msg);
247 
248     if len >= buflen {
249         if buflen != 0 {
250             memcpy(buf as *mut ::c_void, msg as *const ::c_void, buflen - 1);
251             *buf.add(buflen - 1) = 0;
252         }
253         return ERANGE as ::c_int;
254     }
255     memcpy(buf as *mut ::c_void, msg as *const ::c_void, len + 1);
256 
257     0
258 }
259 
260 #[no_mangle]
261 pub unsafe extern "C" fn strlen(s: *const ::c_char) -> ::size_t {
262     strnlen(s, usize::MAX)
263 }
264 
265 #[no_mangle]
266 pub unsafe extern "C" fn strnlen(s: *const ::c_char, size: ::size_t) -> ::size_t {
267     let mut i = 0;
268     while i < size {
269         if *s.add(i) == 0 {
270             break;
271         }
272         i += 1;
273     }
274     i as ::size_t
275 }
276 
277 #[no_mangle]
278 pub unsafe extern "C" fn strnlen_s(s: *const ::c_char, size: ::size_t) -> ::size_t {
279     if s.is_null() {
280         0
281     } else {
282         strnlen(s, size)
283     }
284 }
285 
286 #[no_mangle]
287 pub unsafe extern "C" fn strcat(s1: *mut ::c_char, s2: *const ::c_char) -> *mut ::c_char {
288     strncat(s1, s2, usize::MAX)
289 }
290 
291 #[no_mangle]
292 pub unsafe extern "C" fn strncat(s1: *mut ::c_char, s2: *const ::c_char, n: ::size_t) -> *mut ::c_char {
293     let len = strlen(s1 as *const ::c_char);
294     let mut i = 0;
295     while i < n {
296         let b = *s2.add(i);
297         if b == 0 {
298             break;
299         }
300 
301         *s1.add(len + i) = b;
302         i += 1;
303     }
304     *s1.add(len + i) = 0;
305 
306     s1
307 }
308 
309 #[no_mangle]
310 pub unsafe extern "C" fn strncmp(s1: *const ::c_char, s2: *const ::c_char, n: ::size_t) -> ::c_int {
311     let s1 = core::slice::from_raw_parts(s1 as *const ::c_uchar, n);
312     let s2 = core::slice::from_raw_parts(s2 as *const ::c_uchar, n);
313 
314     for (&a, &b) in s1.iter().zip(s2.iter()) {
315         let val = (a as ::c_int) - (b as ::c_int);
316         if a != b || a == 0 {
317             return val;
318         }
319     }
320 
321     0
322 }
323 
324 #[no_mangle]
325 pub unsafe extern "C" fn strncpy(dst: *mut ::c_char, src: *const ::c_char, n: ::size_t) -> *mut ::c_char {
326     let mut i = 0;
327 
328     while *src.add(i) != 0 && i < n {
329         *dst.add(i) = *src.add(i);
330         i += 1;
331     }
332 
333     for i in i..n {
334         *dst.add(i) = 0;
335     }
336 
337     dst
338 }
339 
340 #[no_mangle]
341 pub unsafe extern "C" fn strpbrk(s1: *const ::c_char, s2: *const ::c_char) -> *mut ::c_char {
342     let p = s1.add(strcspn(s1, s2));
343     if *p != 0 {
344         p as *mut ::c_char
345     } else {
346         ptr::null_mut()
347     }
348 }
349 
350 #[no_mangle]
351 pub unsafe extern "C" fn strrchr(s: *const ::c_char, c: ::c_int) -> *mut ::c_char {
352     let len = strlen(s) as isize;
353     let c = c as i8;
354     let mut i = len - 1;
355     while i >= 0 {
356         if *s.offset(i) == c {
357             return s.offset(i) as *mut ::c_char;
358         }
359         i -= 1;
360     }
361     ptr::null_mut()
362 }
363 
364 #[no_mangle]
365 pub unsafe extern "C" fn strsignal(sig: ::c_int) -> *const ::c_char {
366     signal::_signal_strings
367         .get(sig as usize)
368         .unwrap_or(&signal::_signal_strings[0]) // Unknown signal message
369         .as_ptr() as *const ::c_char
370 }
371 
372 #[no_mangle]
373 pub unsafe extern "C" fn strspn(s1: *const ::c_char, s2: *const ::c_char) -> ::size_t {
374     inner_strspn(s1, s2, true)
375 }
376 
377 unsafe fn inner_strstr(
378     mut haystack: *const ::c_char,
379     needle: *const ::c_char,
380     mask: ::c_char,
381 ) -> *mut ::c_char {
382     while *haystack != 0 {
383         let mut i = 0;
384         loop {
385             if *needle.offset(i) == 0 {
386                 // We reached the end of the needle, everything matches this far
387                 return haystack as *mut ::c_char;
388             }
389             if *haystack.offset(i) & mask != *needle.offset(i) & mask {
390                 break;
391             }
392 
393             i += 1;
394         }
395 
396         haystack = haystack.offset(1);
397     }
398     ptr::null_mut()
399 }
400 
401 #[no_mangle]
402 pub unsafe extern "C" fn strstr(haystack: *const ::c_char, needle: *const ::c_char) -> *mut ::c_char {
403     inner_strstr(haystack, needle, !0)
404 }
405 #[no_mangle]
406 pub unsafe extern "C" fn strcasestr(haystack: *const ::c_char, needle: *const ::c_char) -> *mut ::c_char {
407     inner_strstr(haystack, needle, !32)
408 }
409 
410 #[no_mangle]
411 pub unsafe extern "C" fn strtok(s1: *mut ::c_char, delimiter: *const ::c_char) -> *mut ::c_char {
412     static mut HAYSTACK: *mut ::c_char = ptr::null_mut();
413     strtok_r(s1, delimiter, &mut HAYSTACK)
414 }
415 
416 #[no_mangle]
417 pub unsafe extern "C" fn strtok_r(
418     s: *mut ::c_char,
419     delimiter: *const ::c_char,
420     lasts: *mut *mut ::c_char,
421 ) -> *mut ::c_char {
422     // Loosely based on GLIBC implementation
423     let mut haystack = s;
424     if haystack.is_null() {
425         if (*lasts).is_null() {
426             return ptr::null_mut();
427         }
428         haystack = *lasts;
429     }
430 
431     // Skip past any extra delimiter left over from previous call
432     haystack = haystack.add(strspn(haystack, delimiter));
433     if *haystack == 0 {
434         *lasts = ptr::null_mut();
435         return ptr::null_mut();
436     }
437 
438     // Build token by injecting null byte into delimiter
439     let token = haystack;
440     haystack = strpbrk(token, delimiter);
441     if !haystack.is_null() {
442         haystack.write(0);
443         haystack = haystack.add(1);
444         *lasts = haystack;
445     } else {
446         *lasts = ptr::null_mut();
447     }
448 
449     token
450 }
451 
452 #[no_mangle]
453 pub unsafe extern "C" fn strxfrm(s1: *mut ::c_char, s2: *const ::c_char, n: ::size_t) -> ::size_t {
454     // relibc has no locale stuff (yet)
455     let len = strlen(s2);
456     if len < n {
457         strcpy(s1, s2);
458     }
459     len
460 }
461 
462 #[no_mangle]
463 pub unsafe extern "C" fn strlcpy(dst: *mut ::c_char, src: *const ::c_char, n: ::size_t) -> ::size_t {
464     let mut i = 0;
465 
466     while *src.add(i) != 0 && i < n {
467         *dst.add(i) = *src.add(i);
468         i += 1;
469     }
470 
471     *dst.add(i) = 0;
472 
473     i as ::size_t
474 }
475 
476 #[no_mangle]
477 pub unsafe extern "C" fn strlcat(dst: *mut ::c_char, src: *const ::c_char, n: ::size_t) -> ::size_t {
478     let len = strlen(dst) as isize;
479     let mut d = dst.offset(len);
480 
481     strlcpy(d, src, n)
482 }
483