| // Copyright 2023, The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| //! This library provides implementation for a few libc functions for building third party C |
| //! libraries. |
| |
| #![no_std] |
| |
| use core::ptr::null_mut; |
| |
| /// void *memchr(const void *ptr, int ch, size_t count); |
| #[no_mangle] |
| pub extern "C" fn memchr( |
| ptr: *const core::ffi::c_void, |
| ch: core::ffi::c_int, |
| count: core::ffi::c_ulong, |
| ) -> *mut core::ffi::c_void { |
| assert!(!ptr.is_null()); |
| let start = ptr as *const u8; |
| let target = (ch & 0xff) as u8; |
| for i in 0..count { |
| // SAFETY: Buffer is assumed valid and bounded by count. |
| let curr = unsafe { start.add(i.try_into().unwrap()) }; |
| // SAFETY: Buffer is assumed valid and bounded by count. |
| if *unsafe { curr.as_ref().unwrap() } == target { |
| return curr as *mut _; |
| } |
| } |
| null_mut() |
| } |
| |
| /// char *strrchr(const char *str, int c); |
| #[no_mangle] |
| pub extern "C" fn strrchr( |
| ptr: *const core::ffi::c_char, |
| ch: core::ffi::c_int, |
| ) -> *mut core::ffi::c_char { |
| assert!(!ptr.is_null()); |
| // SAFETY: Input is a valid null terminated string. |
| let bytes = unsafe { core::ffi::CStr::from_ptr(ptr).to_bytes_with_nul() }; |
| let target = (ch & 0xff) as u8; |
| for c in bytes.iter().rev() { |
| if *c == target { |
| return c as *const _ as *mut _; |
| } |
| } |
| null_mut() |
| } |
| |
| /// size_t strnlen(const char *s, size_t maxlen); |
| #[no_mangle] |
| pub fn strnlen(s: *const core::ffi::c_char, maxlen: usize) -> usize { |
| match memchr(s as *const _, 0, maxlen.try_into().unwrap()) { |
| p if p.is_null() => maxlen, |
| p => (p as usize) - (s as usize), |
| } |
| } |