1 // Copyright 2023, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This library provides implementation for a few libc functions for building third party C
16 //! libraries.
17 
18 #![no_std]
19 
20 use core::ptr::null_mut;
21 
22 /// void *memchr(const void *ptr, int ch, size_t count);
23 #[no_mangle]
memchr( ptr: *const core::ffi::c_void, ch: core::ffi::c_int, count: core::ffi::c_ulong, ) -> *mut core::ffi::c_void24 pub extern "C" fn memchr(
25     ptr: *const core::ffi::c_void,
26     ch: core::ffi::c_int,
27     count: core::ffi::c_ulong,
28 ) -> *mut core::ffi::c_void {
29     assert!(!ptr.is_null());
30     let start = ptr as *const u8;
31     let target = (ch & 0xff) as u8;
32     for i in 0..count {
33         // SAFETY: Buffer is assumed valid and bounded by count.
34         let curr = unsafe { start.add(i.try_into().unwrap()) };
35         // SAFETY: Buffer is assumed valid and bounded by count.
36         if *unsafe { curr.as_ref().unwrap() } == target {
37             return curr as *mut _;
38         }
39     }
40     null_mut()
41 }
42 
43 /// char *strrchr(const char *str, int c);
44 #[no_mangle]
strrchr( ptr: *const core::ffi::c_char, ch: core::ffi::c_int, ) -> *mut core::ffi::c_char45 pub extern "C" fn strrchr(
46     ptr: *const core::ffi::c_char,
47     ch: core::ffi::c_int,
48 ) -> *mut core::ffi::c_char {
49     assert!(!ptr.is_null());
50     // SAFETY: Input is a valid null terminated string.
51     let bytes = unsafe { core::ffi::CStr::from_ptr(ptr).to_bytes_with_nul() };
52     let target = (ch & 0xff) as u8;
53     for c in bytes.iter().rev() {
54         if *c == target {
55             return c as *const _ as *mut _;
56         }
57     }
58     null_mut()
59 }
60 
61 /// size_t strnlen(const char *s, size_t maxlen);
62 #[no_mangle]
strnlen(s: *const core::ffi::c_char, maxlen: usize) -> usize63 pub fn strnlen(s: *const core::ffi::c_char, maxlen: usize) -> usize {
64     match memchr(s as *const _, 0, maxlen.try_into().unwrap()) {
65         p if p.is_null() => maxlen,
66         p => (p as usize) - (s as usize),
67     }
68 }
69