diff --git a/Cargo.toml b/Cargo.toml index 568b822..a461341 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Jonathan 'theJPster' Pallant "] edition = "2021" description = "Tiny, incomplete C library for bare-metal targets, written in Stable (but Unsafe) Rust" license-file = "LICENCES.md" +rust-version = "1.77" readme = "README.md" repository = "https://github.com/rust-embedded-community/tinyrlibc" diff --git a/src/abs.rs b/src/abs.rs index f42f4ec..cc9cf36 100644 --- a/src/abs.rs +++ b/src/abs.rs @@ -2,11 +2,11 @@ //! //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::CInt; +use core::ffi::c_int; /// Rust implementation of C library function `abs` #[cfg_attr(feature = "abs", no_mangle)] -pub extern "C" fn abs(i: CInt) -> CInt { +pub extern "C" fn abs(i: c_int) -> c_int { i.abs() } diff --git a/src/ctype.rs b/src/ctype.rs deleted file mode 100644 index e3655c0..0000000 --- a/src/ctype.rs +++ /dev/null @@ -1,73 +0,0 @@ -//! A tiny C library, written in Rust. -//! -//! See README.md for more details. -//! -//! This file is Copyright (c) Jonathan 'theJPster' Pallant 2019 -//! Licensed under the Blue Oak Model Licence 1.0.0 -//! -//! See each module for its respective licence. - -/// `void` -pub type CVoid = ::core::ffi::c_void; - -/// `size_t` -pub type CSizeT = usize; - -/// `long long int` -pub type CLongLong = ::core::ffi::c_longlong; - -/// `unsigned long long int` -pub type CULongLong = ::core::ffi::c_ulonglong; - -/// `intmax_t` -pub type CUIntMax = CULongLong; - -/// `uintmax_t` -pub type CIntMax = CLongLong; - -/// `long int` -pub type CLong = ::core::ffi::c_long; - -/// `unsigned long int` -pub type CULong = ::core::ffi::c_ulong; - -/// `int` -pub type CInt = ::core::ffi::c_int; - -/// `unsigned int` -pub type CUInt = ::core::ffi::c_uint; - -/// Represents an 8-bit `char`. -/// -/// Rust does not (and will never) support platforms where `char` is not 8-bits -/// long. -pub type CChar = u8; - -/// This allows you to iterate a null-terminated string in a relatively simple -/// way. -pub struct CStringIter { - ptr: *const CChar, - idx: isize, -} - -impl CStringIter { - /// Create a new iterator from a pointer to a null-terminated string. - /// - /// The behaviour is undefined if the string is not null-terminated. - pub fn new(s: *const CChar) -> CStringIter { - CStringIter { ptr: s, idx: 0 } - } -} - -impl core::iter::Iterator for CStringIter { - type Item = CChar; - fn next(&mut self) -> Option { - let c = unsafe { *self.ptr.offset(self.idx) }; - if c == 0 { - None - } else { - self.idx += 1; - Some(c) - } - } -} diff --git a/src/itoa.rs b/src/itoa.rs index 9d484ed..be727df 100644 --- a/src/itoa.rs +++ b/src/itoa.rs @@ -6,7 +6,7 @@ //! Copyright (c) Jonathan 'theJPster' Pallant 2019 //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::CChar; +use core::ffi::c_char; /// Formats the given value `i`, with the given radix, into the given buffer (of the given length). /// @@ -17,7 +17,7 @@ use crate::CChar; /// or -1 if the buffer wasn't large enough. #[cfg_attr(not(feature = "itoa"), export_name = "tinyrlibc_itoa")] #[cfg_attr(feature = "itoa", no_mangle)] -pub unsafe extern "C" fn itoa(i: i64, s: *mut CChar, s_len: usize, radix: u8) -> i32 { +pub unsafe extern "C" fn itoa(i: i64, s: *mut c_char, s_len: usize, radix: u8) -> i32 { let (is_negative, pos_i) = if i < 0 { (true, (-i) as u64) } else { @@ -25,7 +25,7 @@ pub unsafe extern "C" fn itoa(i: i64, s: *mut CChar, s_len: usize, radix: u8) -> }; if is_negative && (s_len > 0) { - core::ptr::write(s, b'-'); + core::ptr::write(s, b'-' as c_char); utoa(pos_i, s.offset(1), s_len - 1, radix) } else { utoa(pos_i, s, s_len, radix) @@ -41,17 +41,17 @@ pub unsafe extern "C" fn itoa(i: i64, s: *mut CChar, s_len: usize, radix: u8) -> /// or -1 if the buffer wasn't large enough. #[cfg_attr(not(feature = "utoa"), export_name = "tinyrlibc_utoa")] #[cfg_attr(feature = "utoa", no_mangle)] -pub unsafe extern "C" fn utoa(mut u: u64, s: *mut CChar, s_len: usize, radix: u8) -> i32 { +pub unsafe extern "C" fn utoa(mut u: u64, s: *mut c_char, s_len: usize, radix: u8) -> i32 { let buffer_slice = core::slice::from_raw_parts_mut(s, s_len); // Build the number up in buffer s in reverse order let mut index = 0usize; for slot in buffer_slice.iter_mut() { - let digit = (u % radix as u64) as u8; + let digit = (u % radix as u64) as c_char; if digit <= 9 { - *slot = digit + b'0'; + *slot = digit + (b'0' as c_char); } else { - *slot = digit - 10 + b'a'; + *slot = digit - 10 + (b'a' as c_char); } index += 1; u /= radix as u64; @@ -66,7 +66,7 @@ pub unsafe extern "C" fn utoa(mut u: u64, s: *mut CChar, s_len: usize, radix: u8 // Null-terminate if index < buffer_slice.len() { - buffer_slice[index] = b'\0'; + buffer_slice[index] = 0; } // Reverse buffer into correct order @@ -82,155 +82,116 @@ mod test { #[test] fn zero() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!(unsafe { itoa(0, buf.as_mut_ptr(), buf.len(), 10) }, 1); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"0\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"0".as_ptr()) }, 0); } #[test] fn one() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!(unsafe { itoa(1, buf.as_mut_ptr(), buf.len(), 10) }, 1); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"1\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"1".as_ptr()) }, 0); } #[test] fn hundredish() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!(unsafe { itoa(123, buf.as_mut_ptr(), buf.len(), 10) }, 3); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"123\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"123".as_ptr()) }, 0); } #[test] fn too_small() { - let mut buf = [b'\0'; 1]; + let mut buf = [0; 1]; assert_eq!(unsafe { itoa(10, buf.as_mut_ptr(), buf.len(), 10) }, -1); } #[test] fn hex() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!( unsafe { itoa(0xDEADBEEF, buf.as_mut_ptr(), buf.len(), 16) }, 8 ); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"deadbeef\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"deadbeef".as_ptr()) }, 0); } #[test] fn octal() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!(unsafe { itoa(0o774, buf.as_mut_ptr(), buf.len(), 8) }, 3); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"774\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"774".as_ptr()) }, 0); } #[test] fn binary() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!( unsafe { itoa(0b11100010, buf.as_mut_ptr(), buf.len(), 2) }, 8 ); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"11100010\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"11100010".as_ptr()) }, 0); } #[test] fn negative() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; unsafe { itoa(-123, buf.as_mut_ptr(), buf.len(), 10) }; - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"-123\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"-123".as_ptr()) }, 0); } #[test] fn unsigned_zero() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!(unsafe { utoa(0, buf.as_mut_ptr(), buf.len(), 10) }, 1); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"0\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"0".as_ptr()) }, 0); } #[test] fn unsigned_one() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!(unsafe { utoa(1, buf.as_mut_ptr(), buf.len(), 10) }, 1); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"1\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"1".as_ptr()) }, 0); } #[test] fn unsigned_hundredish() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!(unsafe { utoa(123, buf.as_mut_ptr(), buf.len(), 10) }, 3); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"123\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"123".as_ptr()) }, 0); } #[test] fn unsigned_too_small() { - let mut buf = [b'\0'; 1]; + let mut buf = [0; 1]; assert_eq!(unsafe { utoa(10, buf.as_mut_ptr(), buf.len(), 10) }, -1); } #[test] fn unsigned_hex() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!( unsafe { utoa(0xDEADBEEF, buf.as_mut_ptr(), buf.len(), 16) }, 8 ); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"deadbeef\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"deadbeef".as_ptr()) }, 0); } #[test] fn unsigned_octal() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!(unsafe { utoa(0o774, buf.as_mut_ptr(), buf.len(), 8) }, 3); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"774\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"774".as_ptr()) }, 0); } #[test] fn unsigned_binary() { - let mut buf = [b'\0'; 32]; + let mut buf = [0; 32]; assert_eq!( unsafe { utoa(0b11100010, buf.as_mut_ptr(), buf.len(), 2) }, 8 ); - assert_eq!( - unsafe { strcmp(buf.as_ptr() as *const u8, b"11100010\0" as *const u8) }, - 0 - ); + assert_eq!(unsafe { strcmp(buf.as_ptr(), c"11100010".as_ptr()) }, 0); } } diff --git a/src/lib.rs b/src/lib.rs index fd656ef..177d877 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,6 @@ #![allow(clippy::missing_safety_doc)] #![allow(unused_imports)] -// Useful imports -mod ctype; -pub use self::ctype::*; - // Stateless implementations. // rustfmt will keep these in alphabetical order. mod abs; diff --git a/src/malloc.rs b/src/malloc.rs index e37dd24..028b7e5 100644 --- a/src/malloc.rs +++ b/src/malloc.rs @@ -4,7 +4,6 @@ //! This file is licensed under the Blue Oak Model Licence 1.0.0 extern crate alloc; -use crate::CSizeT; // The maximum alignment of any fundamental type. Equivalent to max_align_t const MAX_ALIGN: usize = 16; @@ -13,7 +12,7 @@ const MAX_ALIGN: usize = 16; /// /// See [malloc](https://linux.die.net/man/3/malloc) for alignment details. #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn malloc(size: CSizeT) -> *mut u8 { +pub unsafe extern "C" fn malloc(size: usize) -> *mut u8 { // size + MAX_ALIGN for to store the size of the allocated memory. let layout = alloc::alloc::Layout::from_size_align(size + MAX_ALIGN, MAX_ALIGN).unwrap(); let ptr = unsafe { alloc::alloc::alloc(layout) }; @@ -21,7 +20,7 @@ pub unsafe extern "C" fn malloc(size: CSizeT) -> *mut u8 { return ptr; } unsafe { - *(ptr as *mut CSizeT) = size; + *(ptr as *mut usize) = size; } unsafe { ptr.add(MAX_ALIGN) } } @@ -30,7 +29,7 @@ pub unsafe extern "C" fn malloc(size: CSizeT) -> *mut u8 { /// /// See [calloc](https://linux.die.net/man/3/calloc) for alignment details. #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn calloc(nmemb: CSizeT, size: CSizeT) -> *mut u8 { +pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut u8 { let total_size = nmemb * size; let layout = alloc::alloc::Layout::from_size_align(total_size + MAX_ALIGN, MAX_ALIGN).unwrap(); let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) }; @@ -38,7 +37,7 @@ pub unsafe extern "C" fn calloc(nmemb: CSizeT, size: CSizeT) -> *mut u8 { return ptr; } unsafe { - *(ptr as *mut CSizeT) = total_size; + *(ptr as *mut usize) = total_size; } unsafe { ptr.add(MAX_ALIGN) } } @@ -47,18 +46,18 @@ pub unsafe extern "C" fn calloc(nmemb: CSizeT, size: CSizeT) -> *mut u8 { /// /// See [realloc](https://linux.die.net/man/3/realloc) for alignment details. #[cfg_attr(not(test), no_mangle)] -pub unsafe extern "C" fn realloc(ptr: *mut u8, size: CSizeT) -> *mut u8 { +pub unsafe extern "C" fn realloc(ptr: *mut u8, size: usize) -> *mut u8 { if ptr.is_null() { return malloc(size); } - let old_size = unsafe { *(ptr.sub(MAX_ALIGN) as *mut CSizeT) }; + let old_size = unsafe { *(ptr.sub(MAX_ALIGN) as *mut usize) }; let layout = alloc::alloc::Layout::from_size_align(old_size + MAX_ALIGN, MAX_ALIGN).unwrap(); let new_ptr = unsafe { alloc::alloc::realloc(ptr.sub(MAX_ALIGN), layout, size + MAX_ALIGN) }; if new_ptr.is_null() { return new_ptr; } unsafe { - *(new_ptr as *mut CSizeT) = size; + *(new_ptr as *mut usize) = size; } unsafe { new_ptr.add(MAX_ALIGN) } } @@ -69,7 +68,7 @@ pub unsafe extern "C" fn free(ptr: *mut u8) { if ptr.is_null() { return; } - let old_size = unsafe { *(ptr.sub(MAX_ALIGN) as *mut CSizeT) }; + let old_size = unsafe { *(ptr.sub(MAX_ALIGN) as *mut usize) }; let layout = alloc::alloc::Layout::from_size_align(old_size + MAX_ALIGN, MAX_ALIGN).unwrap(); unsafe { alloc::alloc::dealloc(ptr.sub(MAX_ALIGN), layout) }; } @@ -83,7 +82,7 @@ mod test { let ptr = unsafe { malloc(10) }; assert!(!ptr.is_null()); unsafe { - assert_eq!(*(ptr.sub(MAX_ALIGN) as *mut CSizeT), 10); + assert_eq!(*(ptr.sub(MAX_ALIGN) as *mut usize), 10); (0..10).for_each(|i| { *ptr.add(i) = i as u8; }); @@ -99,7 +98,7 @@ mod test { let ptr = unsafe { calloc(10, 10) }; assert!(!ptr.is_null()); unsafe { - assert_eq!(*(ptr.sub(MAX_ALIGN) as *mut CSizeT), 100); + assert_eq!(*(ptr.sub(MAX_ALIGN) as *mut usize), 100); (0..100).for_each(|i| { assert_eq!(*ptr.add(i), 0); }); @@ -118,7 +117,7 @@ mod test { let ptr = unsafe { malloc(10) }; assert!(!ptr.is_null()); unsafe { - assert_eq!(*(ptr.sub(MAX_ALIGN) as *mut CSizeT), 10); + assert_eq!(*(ptr.sub(MAX_ALIGN) as *mut usize), 10); (0..10).for_each(|i| { *ptr.add(i) = i as u8; }); @@ -129,7 +128,7 @@ mod test { let ptr = unsafe { realloc(ptr, 20) }; assert!(!ptr.is_null()); unsafe { - assert_eq!(*(ptr.sub(MAX_ALIGN) as *mut CSizeT), 20); + assert_eq!(*(ptr.sub(MAX_ALIGN) as *mut usize), 20); (0..10).for_each(|i| { assert_eq!(*ptr.add(i), i as u8); }); diff --git a/src/memchr.rs b/src/memchr.rs index b25b98c..6c8aee0 100644 --- a/src/memchr.rs +++ b/src/memchr.rs @@ -2,15 +2,15 @@ //! //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CInt, CSizeT, CVoid}; +use core::ffi::{c_char, c_int, c_void}; /// Rust implementation of C library function `memchr` #[cfg_attr(feature = "memchr", no_mangle)] -pub unsafe extern "C" fn memchr(s: *const CVoid, c: CInt, n: CSizeT) -> *const CVoid { - let s = s as *const CChar; +pub unsafe extern "C" fn memchr(s: *const c_void, c: c_int, n: usize) -> *const c_void { + let s = s as *const c_char; for i in 0..n { - if *s.add(i) as CInt == c { - return s.add(i) as *const CVoid; + if *s.add(i) as c_int == c { + return s.add(i) as *const c_void; } } core::ptr::null() @@ -29,8 +29,8 @@ mod test { fn normal() { let s = b"hello world"; assert_eq!( - unsafe { memchr(s.as_ptr() as *const CVoid, b'w' as CInt, s.len() as CSizeT) }, - unsafe { s.as_ptr().offset(6) } as *const CVoid + unsafe { memchr(s.as_ptr() as *const c_void, b'w' as c_int, s.len() as usize) }, + unsafe { s.as_ptr().offset(6) } as *const c_void ); } @@ -38,7 +38,7 @@ mod test { fn not_found() { let s = b"hello world"; assert_eq!( - unsafe { memchr(s.as_ptr() as *const CVoid, b'x' as CInt, s.len() as CSizeT) }, + unsafe { memchr(s.as_ptr() as *const c_void, b'x' as c_int, s.len() as usize) }, core::ptr::null() ) } diff --git a/src/qsort.rs b/src/qsort.rs index 6b53002..e2782c6 100644 --- a/src/qsort.rs +++ b/src/qsort.rs @@ -5,11 +5,11 @@ use core::num::NonZeroUsize; -use crate::{CChar, CInt, CSizeT, CVoid}; +use core::ffi::{c_char, c_int, c_void}; -const MAXDEPTH_MULTIPLIER: CSizeT = 2; -const INSERTION_THRESHOLD: CSizeT = 16; -const SWAP_BUFFER_SIZE: CSizeT = 128; +const MAXDEPTH_MULTIPLIER: usize = 2; +const INSERTION_THRESHOLD: usize = 16; +const SWAP_BUFFER_SIZE: usize = 128; /// Rust implementation of C library function `qsort` /// @@ -19,25 +19,25 @@ const SWAP_BUFFER_SIZE: CSizeT = 128; /// fast average performance and (asymptotically) optimal worst-case performance. #[cfg_attr(feature = "qsort", no_mangle)] pub unsafe extern "C" fn qsort( - base: *mut CVoid, - nel: CSizeT, - width: CSizeT, - compar: Option CInt>, + base: *mut c_void, + nel: usize, + width: usize, + compar: Option c_int>, ) { if let Some(comp) = compar { if nel > 0 { - let maxdepth = MAXDEPTH_MULTIPLIER * nel.ilog2() as CSizeT; + let maxdepth = MAXDEPTH_MULTIPLIER * nel.ilog2() as usize; introsort_helper(base, nel, width, maxdepth, comp); } } } fn introsort_helper( - mut base: *mut CVoid, - mut nel: CSizeT, - width: CSizeT, - mut maxdepth: CSizeT, - comp: extern "C" fn(*const CVoid, *const CVoid) -> CInt, + mut base: *mut c_void, + mut nel: usize, + width: usize, + mut maxdepth: usize, + comp: extern "C" fn(*const c_void, *const c_void) -> c_int, ) { // This loop is a trick to save stack space because TCO is not a thing in Rustland. // Basically, we just change the arguments and loop rather than recursing for the second call @@ -69,16 +69,16 @@ fn introsort_helper( } fn insertion_sort( - base: *mut CVoid, - nel: CSizeT, - width: CSizeT, - comp: extern "C" fn(*const CVoid, *const CVoid) -> CInt, + base: *mut c_void, + nel: usize, + width: usize, + comp: extern "C" fn(*const c_void, *const c_void) -> c_int, ) { for i in 0..nel { for j in (0..i).rev() { let current = unsafe { base.add(j * width) }; let prev = unsafe { base.add((j + 1) * width) }; - if comp(current as *const CVoid, prev as *const CVoid) > 0 { + if comp(current as *const c_void, prev as *const c_void) > 0 { swap(current, prev, width); } else { break; @@ -88,10 +88,10 @@ fn insertion_sort( } fn heapsort( - base: *mut CVoid, - nel: CSizeT, - width: CSizeT, - comp: extern "C" fn(*const CVoid, *const CVoid) -> CInt, + base: *mut c_void, + nel: usize, + width: usize, + comp: extern "C" fn(*const c_void, *const c_void) -> c_int, ) { heapify(base, nel, width, comp); @@ -105,10 +105,10 @@ fn heapsort( } fn heapify( - base: *mut CVoid, - nel: CSizeT, - width: CSizeT, - comp: extern "C" fn(*const CVoid, *const CVoid) -> CInt, + base: *mut c_void, + nel: usize, + width: usize, + comp: extern "C" fn(*const c_void, *const c_void) -> c_int, ) { // we start at the last parent in the heap (the parent of the last child) let last_parent = (nel - 2) / 2; @@ -119,11 +119,11 @@ fn heapify( } fn heap_sift_down( - base: *mut CVoid, - start: CSizeT, - end: CSizeT, - width: CSizeT, - comp: extern "C" fn(*const CVoid, *const CVoid) -> CInt, + base: *mut c_void, + start: usize, + end: usize, + width: usize, + comp: extern "C" fn(*const c_void, *const c_void) -> c_int, ) { // get the left child of the node at the given index let left_child = |idx| 2 * idx + 1; @@ -139,11 +139,11 @@ fn heap_sift_down( let first_child_ptr = unsafe { base.add(child * width) }; let second_child_ptr = unsafe { base.add((child + 1) * width) }; - if comp(swap_ptr as *const CVoid, first_child_ptr as *const CVoid) < 0 { + if comp(swap_ptr as *const c_void, first_child_ptr as *const c_void) < 0 { swap_idx = child; swap_ptr = first_child_ptr; } - if child < end && comp(swap_ptr as *const CVoid, second_child_ptr as *const CVoid) < 0 { + if child < end && comp(swap_ptr as *const c_void, second_child_ptr as *const c_void) < 0 { swap_idx = child + 1; swap_ptr = second_child_ptr; } @@ -159,11 +159,11 @@ fn heap_sift_down( #[inline] fn partition( - base: *mut CVoid, - nel: CSizeT, - width: CSizeT, - comp: extern "C" fn(*const CVoid, *const CVoid) -> CInt, -) -> (CSizeT, CSizeT) { + base: *mut c_void, + nel: usize, + width: usize, + comp: extern "C" fn(*const c_void, *const c_void) -> c_int, +) -> (usize, usize) { // calculate the median of the first, middle, and last elements and use it as the pivot // to do fewer comparisons, also swap the elements into their correct positions let mut pivot = median_of_three(base, nel, width, comp); @@ -179,7 +179,7 @@ fn partition( let n_ptr = unsafe { base.add(n * width) }; let pivot_ptr = unsafe { base.add(pivot * width) }; - let comparison = comp(j_ptr as *const CVoid, pivot_ptr as *const CVoid); + let comparison = comp(j_ptr as *const c_void, pivot_ptr as *const c_void); match comparison.cmp(&0) { core::cmp::Ordering::Less => { swap(i_ptr, j_ptr, width); @@ -206,21 +206,21 @@ fn partition( } fn median_of_three( - base: *mut CVoid, - nel: CSizeT, - width: CSizeT, - comp: extern "C" fn(*const CVoid, *const CVoid) -> CInt, -) -> CSizeT { + base: *mut c_void, + nel: usize, + width: usize, + comp: extern "C" fn(*const c_void, *const c_void) -> c_int, +) -> usize { let pivot = nel / 2; let mid = unsafe { base.add(pivot * width) }; let last = unsafe { base.add((nel - 1) * width) }; - if comp(mid as *const CVoid, base as *const CVoid) < 0 { + if comp(mid as *const c_void, base as *const c_void) < 0 { swap(mid, base, width); } - if comp(last as *const CVoid, mid as *const CVoid) < 0 { + if comp(last as *const c_void, mid as *const c_void) < 0 { swap(mid, last, width); - if comp(mid as *const CVoid, base as *const CVoid) < 0 { + if comp(mid as *const c_void, base as *const c_void) < 0 { swap(mid, base, width); } } @@ -229,20 +229,20 @@ fn median_of_three( } #[inline] -fn swap(ptr1: *mut CVoid, ptr2: *mut CVoid, mut width: CSizeT) { +fn swap(ptr1: *mut c_void, ptr2: *mut c_void, mut width: usize) { use core::mem; - let mut ptr1 = ptr1 as *mut CChar; - let mut ptr2 = ptr2 as *mut CChar; + let mut ptr1 = ptr1 as *mut c_char; + let mut ptr2 = ptr2 as *mut c_char; if ptr1 == ptr2 { return; } - let mut buffer = mem::MaybeUninit::<[CChar; SWAP_BUFFER_SIZE]>::uninit(); + let mut buffer = mem::MaybeUninit::<[c_char; SWAP_BUFFER_SIZE]>::uninit(); while width > 0 { let copy_size = SWAP_BUFFER_SIZE.min(width); - let buf = buffer.as_mut_ptr() as *mut CChar; + let buf = buffer.as_mut_ptr() as *mut c_char; unsafe { buf.copy_from_nonoverlapping(ptr1, copy_size); @@ -252,7 +252,7 @@ fn swap(ptr1: *mut CVoid, ptr2: *mut CVoid, mut width: CSizeT) { ptr1 = ptr1.add(copy_size); ptr2 = ptr2.add(copy_size); } - width -= copy_size as CSizeT; + width -= copy_size as usize; } } @@ -260,7 +260,7 @@ fn swap(ptr1: *mut CVoid, ptr2: *mut CVoid, mut width: CSizeT) { mod tests { use super::*; - extern "C" fn comp(a: *const CVoid, b: *const CVoid) -> CInt { + extern "C" fn comp(a: *const c_void, b: *const c_void) -> c_int { unsafe { *(a as *const i32) - *(b as *const i32) } } @@ -271,9 +271,9 @@ mod tests { unsafe { qsort( - array.as_mut_ptr() as *mut CVoid, - array.len() as CSizeT, - std::mem::size_of::() as CSizeT, + array.as_mut_ptr() as *mut c_void, + array.len() as usize, + std::mem::size_of::() as usize, Some(comp), ); } @@ -287,9 +287,9 @@ mod tests { let orig = array.clone(); heapsort( - array.as_mut_ptr() as *mut CVoid, - array.len() as CSizeT, - std::mem::size_of::() as CSizeT, + array.as_mut_ptr() as *mut c_void, + array.len() as usize, + std::mem::size_of::() as usize, comp, ); @@ -304,9 +304,9 @@ mod tests { unsafe { qsort( - array.as_mut_ptr() as *mut CVoid, - array.len() as CSizeT, - std::mem::size_of::() as CSizeT, + array.as_mut_ptr() as *mut c_void, + array.len() as usize, + std::mem::size_of::() as usize, Some(comp), ) } @@ -321,9 +321,9 @@ mod tests { let orig: Vec<_> = (0..1000).collect(); heapsort( - array.as_mut_ptr() as *mut CVoid, - array.len() as CSizeT, - std::mem::size_of::() as CSizeT, + array.as_mut_ptr() as *mut c_void, + array.len() as usize, + std::mem::size_of::() as usize, comp, ); @@ -343,9 +343,9 @@ mod tests { let mut array = RAND_ARRAY.clone(); unsafe { qsort( - array.as_mut_ptr() as *mut CVoid, - array.len() as CSizeT, - std::mem::size_of::() as CSizeT, + array.as_mut_ptr() as *mut c_void, + array.len() as usize, + std::mem::size_of::() as usize, Some(comp), ) } @@ -357,9 +357,9 @@ mod tests { fn random_heapsort() { let mut array = RAND_ARRAY.clone(); heapsort( - array.as_mut_ptr() as *mut CVoid, - array.len() as CSizeT, - std::mem::size_of::() as CSizeT, + array.as_mut_ptr() as *mut c_void, + array.len() as usize, + std::mem::size_of::() as usize, comp, ); diff --git a/src/signal.rs b/src/signal.rs index ec83fec..9ea41bc 100644 --- a/src/signal.rs +++ b/src/signal.rs @@ -126,7 +126,7 @@ mod tests { } impl State { - fn lock(&self) -> std::sync::MutexGuard<()> { + fn lock(&self) -> std::sync::MutexGuard<'_, ()> { // Ensure we have exclusive access let guard = self.inner.lock().unwrap(); // Reset the global signal handler list to defaults @@ -167,10 +167,17 @@ mod tests { #[test] fn test_abort() { let _guard = TEST_LOCK.lock(); - let result = std::panic::catch_unwind(|| { - abort(); - }); - assert!(result.is_err()); + static COUNT: AtomicUsize = AtomicUsize::new(0); + extern "C" fn count_handler(_sig: i32) { + COUNT.fetch_add(1, Ordering::Relaxed); + } + let count_handler_ptr = count_handler as *const fn(i32) as usize; + let old_handler = unsafe { signal(SIGABRT, count_handler_ptr) }; + assert_eq!(old_handler, SIG_DFL); + abort(); + let old_handler = unsafe { signal(SIGABRT, SIG_DFL) }; + assert_eq!(COUNT.load(Ordering::Relaxed), 1); + assert_eq!(old_handler, count_handler_ptr); } #[test] @@ -180,12 +187,6 @@ mod tests { assert_eq!(err, SIG_ERR); } - #[test] - fn test_raise() { - let result = std::panic::catch_unwind(|| raise(SIGTERM)); - assert!(result.is_err()); - } - #[test] fn test_ignore() { let _guard = TEST_LOCK.lock(); diff --git a/src/snprintf.rs b/src/snprintf.rs index ec1031c..838ad6f 100644 --- a/src/snprintf.rs +++ b/src/snprintf.rs @@ -6,34 +6,24 @@ #[cfg(test)] mod test { extern "C" { - fn snprintf(buf: *mut CChar, len: usize, fmt: *const CChar, ...) -> i32; + fn snprintf(buf: *mut c_char, len: usize, fmt: *const c_char, ...) -> i32; } use core::{ffi::CStr, fmt}; use std::fmt::format; - use crate::{strcmp::strcmp, CChar, CInt, CLong, CLongLong, CUInt, CULong, CULongLong}; - - /// Make it easier to turn `c"Hello"` into a `*const CChar` - trait ToByte { - fn cp(&self) -> *const CChar; - } - - impl ToByte for &std::ffi::CStr { - fn cp(&self) -> *const CChar { - self.as_ptr().cast() - } - } + use crate::strcmp::strcmp; + use core::ffi::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ulonglong}; /// Handle the buffer that `snprintf` needs #[track_caller] fn asprintf(fmt: &str, expected: &str, f: F) where - F: FnOnce(*mut CChar, usize, *const CChar) -> i32, + F: FnOnce(*mut c_char, usize, *const c_char) -> i32, { let mut buf = vec![0u8; 128]; let cfmt = std::ffi::CString::new(fmt).unwrap(); - let res = f(buf.as_mut_ptr(), buf.len(), cfmt.as_ptr().cast()); + let res = f(buf.as_mut_ptr().cast(), buf.len(), cfmt.as_ptr().cast()); if res < 0 { panic!("closure returned {}", res); } @@ -59,7 +49,7 @@ mod test { #[test] fn strings() { asprintf("%s, %s!", "Hello, World!", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, c"Hello".cp(), c"World".cp()) + snprintf(buf, len, fmt, c"Hello".as_ptr(), c"World".as_ptr()) }); } @@ -80,15 +70,15 @@ mod test { buf, len, fmt, - CUInt::from(100u8), - CULong::from(100u8), - CULongLong::from(100u8), - CInt::from(-100i8), - CLong::from(-100i8), - CLongLong::from(-100i8), - CUInt::from(0xcafe1234u32), - CULong::from(0xcafe1234u32), - CULongLong::from(0xcafe1234u32), + c_uint::from(100u8), + c_ulong::from(100u8), + c_ulonglong::from(100u8), + c_int::from(-100i8), + c_long::from(-100i8), + c_longlong::from(-100i8), + c_uint::from(0xcafe1234u32), + c_ulong::from(0xcafe1234u32), + c_ulonglong::from(0xcafe1234u32), ) }, ); @@ -98,13 +88,13 @@ mod test { fn int_min() { asprintf( "%d", - &format!("{}", CInt::min_value()), - |buf, len, fmt| unsafe { snprintf(buf, len, fmt, CInt::min_value()) }, + &format!("{}", c_int::min_value()), + |buf, len, fmt| unsafe { snprintf(buf, len, fmt, c_int::min_value()) }, ); asprintf( "%lld", - &format!("{}", CLongLong::min_value()), - |buf, len, fmt| unsafe { snprintf(buf, len, fmt, CLongLong::min_value()) }, + &format!("{}", c_longlong::min_value()), + |buf, len, fmt| unsafe { snprintf(buf, len, fmt, c_longlong::min_value()) }, ); } @@ -112,177 +102,177 @@ mod test { fn int_max() { asprintf( "%d", - &format!("{}", CInt::max_value()), - |buf, len, fmt| unsafe { snprintf(buf, len, fmt, CInt::max_value()) }, + &format!("{}", c_int::max_value()), + |buf, len, fmt| unsafe { snprintf(buf, len, fmt, c_int::max_value()) }, ); asprintf( "%lld", - &format!("{}", CLongLong::max_value()), - |buf, len, fmt| unsafe { snprintf(buf, len, fmt, CLongLong::max_value()) }, + &format!("{}", c_longlong::max_value()), + |buf, len, fmt| unsafe { snprintf(buf, len, fmt, c_longlong::max_value()) }, ); } #[test] fn non_null_terminated_with_length() { - asprintf("%.*s", "01234", |buf, len, fmt: *const u8| unsafe { - snprintf(buf, len, fmt, 5, c"01234567890123456789".cp()) + asprintf("%.*s", "01234", |buf, len, fmt| unsafe { + snprintf(buf, len, fmt, 5, c"01234567890123456789".as_ptr()) }); asprintf("%.10s", "0123456789", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, c"01234567890123456789".cp()) + snprintf(buf, len, fmt, c"01234567890123456789".as_ptr()) }); } #[test] fn number_with_padding() { asprintf("%5u", " 123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%5lu", " 123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CULong::from(123u8)) + snprintf(buf, len, fmt, c_ulong::from(123u8)) }); asprintf("%5llu", " 123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CULongLong::from(123u8)) + snprintf(buf, len, fmt, c_ulonglong::from(123u8)) }); asprintf("%5d", " -123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%5ld", " -123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CLong::from(-123i8)) + snprintf(buf, len, fmt, c_long::from(-123i8)) }); asprintf("%5lld", " -123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CLongLong::from(-123i8)) + snprintf(buf, len, fmt, c_longlong::from(-123i8)) }); asprintf("%10x", " cafe1234", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(0xcafe1234u32)) + snprintf(buf, len, fmt, c_uint::from(0xcafe1234u32)) }); asprintf("%10lx", " cafe1234", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CULong::from(0xcafe1234u32)) + snprintf(buf, len, fmt, c_ulong::from(0xcafe1234u32)) }); asprintf("%10llX", " CAFE1234", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CULongLong::from(0xcafe1234u32)) + snprintf(buf, len, fmt, c_ulonglong::from(0xcafe1234u32)) }); } #[test] fn number_with_zero_padding() { asprintf("%05u", "00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%05lu", "00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CULong::from(123u8)) + snprintf(buf, len, fmt, c_ulong::from(123u8)) }); asprintf("%05llu", "00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CULongLong::from(123u8)) + snprintf(buf, len, fmt, c_ulonglong::from(123u8)) }); asprintf("%05d", "-0123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%05ld", "-0123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CLong::from(-123i8)) + snprintf(buf, len, fmt, c_long::from(-123i8)) }); asprintf("%05lld", "-0123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CLongLong::from(-123i8)) + snprintf(buf, len, fmt, c_longlong::from(-123i8)) }); asprintf("%010x", "00cafe1234", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(0xcafe1234u32)) + snprintf(buf, len, fmt, c_uint::from(0xcafe1234u32)) }); asprintf("%010lx", "00cafe1234", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CULong::from(0xcafe1234u32)) + snprintf(buf, len, fmt, c_ulong::from(0xcafe1234u32)) }); asprintf("%010llX", "00CAFE1234", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CULongLong::from(0xcafe1234u32)) + snprintf(buf, len, fmt, c_ulonglong::from(0xcafe1234u32)) }); } #[test] fn number_with_precision() { asprintf("%.5u", "00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%.5d", "-00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%.10x", "00cafe1234", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(0xcafe1234u32)) + snprintf(buf, len, fmt, c_uint::from(0xcafe1234u32)) }); asprintf("%.4d", "-0123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%.3d", "-123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%.2u", "123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%.0u", "123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); } #[test] fn number_with_width_and_precision() { asprintf("%10.5u", " 00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%10.5d", " -00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%15.10x", " 00cafe1234", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(0xcafe1234u32)) + snprintf(buf, len, fmt, c_uint::from(0xcafe1234u32)) }); asprintf("%5.5u", "00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%4.5u", "00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%2.5u", "00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%0.5u", "00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%5.4u", " 0123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%5.3u", " 123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%5.0u", " 123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CUInt::from(123u8)) + snprintf(buf, len, fmt, c_uint::from(123u8)) }); asprintf("%5.5d", "-00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%4.5d", "-00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%2.5d", "-00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%0.5d", "-00123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%5.4d", "-0123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%5.3d", " -123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%5.0d", " -123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%05.4d", "-0123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%05.3d", " -123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); asprintf("%05.0d", " -123", |buf, len, fmt| unsafe { - snprintf(buf, len, fmt, CInt::from(-123i8)) + snprintf(buf, len, fmt, c_int::from(-123i8)) }); } } diff --git a/src/strcat.rs b/src/strcat.rs index aa61021..8ce5299 100644 --- a/src/strcat.rs +++ b/src/strcat.rs @@ -2,13 +2,13 @@ //! //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::CChar; +use core::ffi::c_char; /// Rust implementation of C library function `strcat`. /// /// Passing NULL (core::ptr::null()) gives undefined behaviour. #[cfg_attr(feature = "strcat", no_mangle)] -pub unsafe extern "C" fn strcat(dest: *mut CChar, src: *const CChar) -> *const CChar { +pub unsafe extern "C" fn strcat(dest: *mut c_char, src: *const c_char) -> *const c_char { crate::strcpy::strcpy(dest.add(crate::strlen::strlen(dest)), src); dest } @@ -21,9 +21,9 @@ mod test { fn simple() { let mut dest = *b"hello\0\0\0\0\0\0\0\0"; let src = *b" world\0"; - let result = unsafe { strcat(dest.as_mut_ptr(), src.as_ptr()) }; + let result = unsafe { strcat(dest.as_mut_ptr().cast(), src.as_ptr().cast()) }; assert_eq!( - unsafe { core::slice::from_raw_parts(result, 12) }, + unsafe { core::slice::from_raw_parts(result as *const u8, 12) }, b"hello world\0" ); } diff --git a/src/strchr.rs b/src/strchr.rs index 23efe0a..d7d0d99 100644 --- a/src/strchr.rs +++ b/src/strchr.rs @@ -3,14 +3,14 @@ //! Copyright (c) 42 Technology Ltd //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CInt}; +use core::ffi::{c_char, c_int}; /// Rust implementation of C library function `strchr` #[cfg_attr(feature = "strchr", no_mangle)] -pub unsafe extern "C" fn strchr(haystack: *const CChar, needle: CInt) -> *const CChar { +pub unsafe extern "C" fn strchr(haystack: *const c_char, needle: c_int) -> *const c_char { for idx in 0.. { let ptr = haystack.offset(idx); - if needle == (*ptr) as CInt { + if needle == (*ptr) as c_int { return ptr; } if (*ptr) == 0 { @@ -26,36 +26,36 @@ mod test { #[test] fn strchr_no_match() { - let haystack = b"hayyystack\0".as_ptr(); - let result = unsafe { strchr(haystack, b'X' as CInt) }; + let haystack = c"hayyystack".as_ptr(); + let result = unsafe { strchr(haystack, b'X' as c_int) }; assert_eq!(result, core::ptr::null()); } #[test] fn strchr_null() { - let haystack = b"hayyystack\0".as_ptr(); + let haystack = c"hayyystack".as_ptr(); let result = unsafe { strchr(haystack, 0) }; assert_eq!(result, unsafe { haystack.offset(10) }); } #[test] fn strchr_start() { - let haystack = b"hayyystack\0".as_ptr(); - let result = unsafe { strchr(haystack, b'h' as CInt) }; + let haystack = c"hayyystack".as_ptr(); + let result = unsafe { strchr(haystack, b'h' as c_int) }; assert_eq!(result, haystack); } #[test] fn strchr_middle() { - let haystack = b"hayyystack\0".as_ptr(); - let result = unsafe { strchr(haystack, b'y' as CInt) }; + let haystack = c"hayyystack".as_ptr(); + let result = unsafe { strchr(haystack, b'y' as c_int) }; assert_eq!(result, unsafe { haystack.offset(2) }); } #[test] fn strchr_end() { - let haystack = b"hayyystack\0".as_ptr(); - let result = unsafe { strchr(haystack, b'k' as CInt) }; + let haystack = c"hayyystack".as_ptr(); + let result = unsafe { strchr(haystack, b'k' as c_int) }; assert_eq!(result, unsafe { haystack.offset(9) }); } } diff --git a/src/strcmp.rs b/src/strcmp.rs index c170463..eb85e30 100644 --- a/src/strcmp.rs +++ b/src/strcmp.rs @@ -3,16 +3,16 @@ //! Copyright (c) Jonathan 'theJPster' Pallant 2019 //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CInt}; +use core::ffi::{c_char, c_int}; /// Rust implementation of C library function `strcmp` #[cfg_attr(feature = "strcmp", no_mangle)] -pub unsafe extern "C" fn strcmp(s1: *const CChar, s2: *const CChar) -> CInt { +pub unsafe extern "C" fn strcmp(s1: *const c_char, s2: *const c_char) -> c_int { for i in 0.. { let s1_i = s1.offset(i); let s2_i = s2.offset(i); - let val = *s1_i as CInt - *s2_i as CInt; + let val = *s1_i as c_int - *s2_i as c_int; if val != 0 || *s1_i == 0 { return val; } @@ -26,26 +26,26 @@ mod test { #[test] fn test1() { - assert!(unsafe { strcmp(b"Hello\0" as *const CChar, b"Hello\0" as *const CChar) } == 0); + assert!(unsafe { strcmp(c"Hello".as_ptr(), c"Hello".as_ptr()) } == 0); } #[test] fn test2() { - assert!(unsafe { strcmp(b"Hello\0" as *const CChar, b"Hello1\0" as *const CChar) } < 0); + assert!(unsafe { strcmp(c"Hello".as_ptr(), c"Hello1".as_ptr()) } < 0); } #[test] fn test3() { - assert!(unsafe { strcmp(b"Hello1\0" as *const CChar, b"Hello\0" as *const CChar) } > 0); + assert!(unsafe { strcmp(c"Hello1".as_ptr(), c"Hello".as_ptr()) } > 0); } #[test] fn test4() { - assert!(unsafe { strcmp(b"\0" as *const CChar, b"Hello\0" as *const CChar) } < 0); + assert!(unsafe { strcmp(c"".as_ptr(), c"Hello".as_ptr()) } < 0); } #[test] fn test5() { - assert!(unsafe { strcmp(b"Hello\0" as *const CChar, b"\0" as *const CChar) } > 0); + assert!(unsafe { strcmp(c"Hello".as_ptr(), c"".as_ptr()) } > 0); } } diff --git a/src/strcpy.rs b/src/strcpy.rs index a9ed875..7a6ae1d 100644 --- a/src/strcpy.rs +++ b/src/strcpy.rs @@ -2,13 +2,13 @@ //! //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::CChar; +use core::ffi::c_char; /// Rust implementation of C library function `strcpy`. /// /// Passing NULL (core::ptr::null()) gives undefined behaviour. #[cfg_attr(feature = "strcpy", no_mangle)] -pub unsafe extern "C" fn strcpy(dest: *mut CChar, src: *const CChar) -> *const CChar { +pub unsafe extern "C" fn strcpy(dest: *mut c_char, src: *const c_char) -> *const c_char { let mut i = 0; loop { *dest.offset(i) = *src.offset(i); @@ -27,11 +27,11 @@ mod test { #[test] fn short() { - let src = b"hi\0"; + let src = c"hi"; let mut dest = *b"abcdef"; // no null terminator - let result = unsafe { strcpy(dest.as_mut_ptr(), src.as_ptr()) }; + let result = unsafe { strcpy(dest.as_mut_ptr().cast(), src.as_ptr()) }; assert_eq!( - unsafe { core::slice::from_raw_parts(result, 6) }, + unsafe { core::slice::from_raw_parts(result as *const u8, 6) }, *b"hi\0def" ); } diff --git a/src/strcspn.rs b/src/strcspn.rs index 39a0cc6..908be12 100644 --- a/src/strcspn.rs +++ b/src/strcspn.rs @@ -3,11 +3,11 @@ //! Copyright (c) Ferrous Systems UK Ltd //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CInt}; +use core::ffi::{c_char, c_int}; /// Rust implementation of C library function `strcspn` #[cfg_attr(feature = "strcspn", no_mangle)] -pub unsafe extern "C" fn strcspn(s: *const CChar, charset: *const CChar) -> usize { +pub unsafe extern "C" fn strcspn(s: *const c_char, charset: *const c_char) -> usize { if s.is_null() { return 0; } diff --git a/src/strlen.rs b/src/strlen.rs index a81ed3d..a42dc4b 100644 --- a/src/strlen.rs +++ b/src/strlen.rs @@ -3,11 +3,11 @@ //! Copyright (c) Jonathan 'theJPster' Pallant 2019 //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::CChar; +use core::ffi::c_char; /// Rust implementation of C library function `strlen` #[cfg_attr(feature = "strlen", no_mangle)] -pub unsafe extern "C" fn strlen(mut s: *const CChar) -> usize { +pub unsafe extern "C" fn strlen(mut s: *const c_char) -> usize { let mut result = 0; while *s != 0 { s = s.offset(1); @@ -22,16 +22,16 @@ mod test { #[test] fn test1() { - assert_eq!(unsafe { strlen(b"Hello\0" as *const CChar) }, 5); + assert_eq!(unsafe { strlen(c"Hello".as_ptr()) }, 5); } #[test] fn test2() { - assert_eq!(unsafe { strlen(b"\0" as *const CChar) }, 0); + assert_eq!(unsafe { strlen(c"".as_ptr()) }, 0); } #[test] fn test3() { - assert_eq!(unsafe { strlen(b"X\0" as *const CChar) }, 1); + assert_eq!(unsafe { strlen(c"X".as_ptr()) }, 1); } } diff --git a/src/strncasecmp.rs b/src/strncasecmp.rs index 3420e8f..203f8b5 100644 --- a/src/strncasecmp.rs +++ b/src/strncasecmp.rs @@ -2,19 +2,21 @@ //! //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CInt}; +use core::ffi::{c_char, c_int}; /// Rust implementation of C library function `strncasecmp`. /// /// Passing NULL (core::ptr::null()) gives undefined behaviour. #[cfg_attr(feature = "strncasecmp", no_mangle)] -pub unsafe extern "C" fn strncasecmp(s1: *const CChar, s2: *const CChar, n: usize) -> CInt { +pub unsafe extern "C" fn strncasecmp(s1: *const c_char, s2: *const c_char, n: usize) -> c_int { for i in 0..n { let s1_i = s1.add(i); let s2_i = s2.add(i); - let val = (*s1_i).to_ascii_lowercase() as CInt - (*s2_i).to_ascii_lowercase() as CInt; - if val != 0 || *s1_i == 0 { + let c1 = *s1_i as u8; + let c2 = *s2_i as u8; + let val = c1.to_ascii_lowercase() as c_int - c2.to_ascii_lowercase() as c_int; + if val != 0 || c1 == 0 { return val; } } @@ -27,8 +29,8 @@ mod test { #[test] fn matches() { - let a = b"abc\0"; - let b = b"AbCDEF\0"; + let a = c"abc"; + let b = c"AbCDEF"; let result = unsafe { strncasecmp(a.as_ptr(), b.as_ptr(), 3) }; // Match! assert_eq!(result, 0); @@ -36,8 +38,8 @@ mod test { #[test] fn no_match() { - let a = b"123\0"; - let b = b"x1234\0"; + let a = c"123"; + let b = c"x1234"; let result = unsafe { strncasecmp(a.as_ptr(), b.as_ptr(), 3) }; // No match, first string first assert!(result < 0); @@ -45,8 +47,8 @@ mod test { #[test] fn no_match2() { - let a = b"bbbbb\0"; - let b = b"aaaaa\0"; + let a = c"bbbbb"; + let b = c"aaaaa"; let result = unsafe { strncasecmp(a.as_ptr(), b.as_ptr(), 3) }; // No match, second string first assert!(result > 0); diff --git a/src/strncmp.rs b/src/strncmp.rs index 9912e4a..d9900e1 100644 --- a/src/strncmp.rs +++ b/src/strncmp.rs @@ -3,18 +3,18 @@ //! Copyright (c) Jonathan 'theJPster' Pallant 2019 //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CInt}; +use core::ffi::{c_char, c_int}; /// Rust implementation of C library function `strncmp`. /// /// Passing NULL (core::ptr::null()) gives undefined behaviour. #[cfg_attr(feature = "strncmp", no_mangle)] -pub unsafe extern "C" fn strncmp(s1: *const CChar, s2: *const CChar, n: usize) -> crate::CInt { +pub unsafe extern "C" fn strncmp(s1: *const c_char, s2: *const c_char, n: usize) -> c_int { for i in 0..n as isize { let s1_i = s1.offset(i); let s2_i = s2.offset(i); - let val = *s1_i as CInt - *s2_i as CInt; + let val = *s1_i as c_int - *s2_i as c_int; if val != 0 || *s1_i == 0 { return val; } @@ -28,8 +28,8 @@ mod test { #[test] fn matches() { - let a = b"123\0"; - let b = b"1234\0"; + let a = c"123"; + let b = c"1234"; let result = unsafe { strncmp(a.as_ptr(), b.as_ptr(), 3) }; // Match! assert_eq!(result, 0); @@ -37,8 +37,8 @@ mod test { #[test] fn no_match() { - let a = b"123\0"; - let b = b"x1234\0"; + let a = c"123"; + let b = c"x1234"; let result = unsafe { strncmp(a.as_ptr(), b.as_ptr(), 3) }; // No match, first string first assert!(result < 0); @@ -46,8 +46,8 @@ mod test { #[test] fn no_match2() { - let a = b"bbbbb\0"; - let b = b"aaaaa\0"; + let a = c"bbbbb"; + let b = c"aaaaa"; let result = unsafe { strncmp(a.as_ptr(), b.as_ptr(), 3) }; // No match, second string first assert!(result > 0); diff --git a/src/strncpy.rs b/src/strncpy.rs index 147f409..d8af978 100644 --- a/src/strncpy.rs +++ b/src/strncpy.rs @@ -3,17 +3,17 @@ //! Copyright (c) Wouter 'Wassasin' Geraedts 2021 //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::CChar; +use core::ffi::c_char; /// Rust implementation of C library function `strncmp`. /// /// Passing NULL (core::ptr::null()) gives undefined behaviour. #[cfg_attr(feature = "strncpy", no_mangle)] pub unsafe extern "C" fn strncpy( - dest: *mut CChar, - src: *const CChar, + dest: *mut c_char, + src: *const c_char, count: usize, -) -> *const CChar { +) -> *const c_char { let mut i = 0; while i < count { let c = *src.add(i); @@ -35,23 +35,26 @@ mod test { #[test] fn short() { - let src = b"hi\0"; + let src = c"hi"; // no null terminator let mut dest = *b"abcdef"; // pass in less than full length of dest, to see which bytes get zeroed - let result = unsafe { strncpy(dest.as_mut_ptr(), src.as_ptr(), 5) }; + let result = unsafe { strncpy(dest.as_mut_ptr().cast(), src.as_ptr(), 5) }; // two bytes of data, 3 bytes of zeros (= 5 bytes total), plus one byte unchanged assert_eq!( - unsafe { core::slice::from_raw_parts(result, 6) }, + unsafe { core::slice::from_raw_parts(result as *const u8, 6) }, *b"hi\0\0\0f" ); } #[test] fn two() { - let src = b"hello\0"; + let src = c"hello"; let mut dest = [0u8; 2]; // buffer deliberately too small - let result = unsafe { strncpy(dest.as_mut_ptr(), src.as_ptr(), dest.len()) }; - assert_eq!(unsafe { core::slice::from_raw_parts(result, 2) }, b"he"); + let result = unsafe { strncpy(dest.as_mut_ptr().cast(), src.as_ptr(), dest.len()) }; + assert_eq!( + unsafe { core::slice::from_raw_parts(result as *const u8, 2) }, + b"he" + ); } } diff --git a/src/strrchr.rs b/src/strrchr.rs index 2cf42fb..8c1521a 100644 --- a/src/strrchr.rs +++ b/src/strrchr.rs @@ -3,15 +3,15 @@ //! Copyright (c) 42 Technology Ltd //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CInt}; +use core::ffi::{c_char, c_int}; /// Rust implementation of C library function `strrchr` #[cfg_attr(feature = "strrchr", no_mangle)] -pub unsafe extern "C" fn strrchr(haystack: *const CChar, needle: CInt) -> *const CChar { +pub unsafe extern "C" fn strrchr(haystack: *const c_char, needle: c_int) -> *const c_char { let mut last = core::ptr::null(); for idx in 0.. { let ptr = haystack.offset(idx); - if needle == (*ptr) as CInt { + if needle == (*ptr) as c_int { last = ptr; } if (*ptr) == 0 { @@ -27,36 +27,36 @@ mod test { #[test] fn strrchr_no_match() { - let haystack = b"hayyystack\0".as_ptr(); - let result = unsafe { strrchr(haystack, b'X' as CInt) }; + let haystack = c"hayyystack".as_ptr(); + let result = unsafe { strrchr(haystack, b'X' as c_int) }; assert_eq!(result, core::ptr::null()); } #[test] fn strrchr_null() { - let haystack = b"hayyystack\0".as_ptr(); + let haystack = c"hayyystack".as_ptr(); let result = unsafe { strrchr(haystack, 0) }; assert_eq!(result, unsafe { haystack.offset(10) }); } #[test] fn strrchr_start() { - let haystack = b"hayhay\0".as_ptr(); - let result = unsafe { strrchr(haystack, b'h' as CInt) }; + let haystack = c"hayhay".as_ptr(); + let result = unsafe { strrchr(haystack, b'h' as c_int) }; assert_eq!(result, unsafe { haystack.offset(3) }); } #[test] fn strrchr_middle() { - let haystack = b"hayyystack\0".as_ptr(); - let result = unsafe { strrchr(haystack, b'y' as CInt) }; + let haystack = c"hayyystack".as_ptr(); + let result = unsafe { strrchr(haystack, b'y' as c_int) }; assert_eq!(result, unsafe { haystack.offset(4) }); } #[test] fn strrchr_end() { - let haystack = b"hayyystack\0".as_ptr(); - let result = unsafe { strrchr(haystack, b'k' as CInt) }; + let haystack = c"hayyystack".as_ptr(); + let result = unsafe { strrchr(haystack, b'k' as c_int) }; assert_eq!(result, unsafe { haystack.offset(9) }); } } diff --git a/src/strspn.rs b/src/strspn.rs index 3a634ed..7bf856b 100644 --- a/src/strspn.rs +++ b/src/strspn.rs @@ -3,11 +3,11 @@ //! Copyright (c) Ferrous Systems UK Ltd //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CInt}; +use core::ffi::{c_char, c_int}; /// Rust implementation of C library function `strspn` #[cfg_attr(feature = "strspn", no_mangle)] -pub unsafe extern "C" fn strspn(s: *const CChar, charset: *const CChar) -> usize { +pub unsafe extern "C" fn strspn(s: *const c_char, charset: *const c_char) -> usize { if s.is_null() { return 0; } diff --git a/src/strstr.rs b/src/strstr.rs index 692962f..0d06d34 100644 --- a/src/strstr.rs +++ b/src/strstr.rs @@ -3,11 +3,11 @@ //! Copyright (c) Jonathan 'theJPster' Pallant 2019 //! Licensed under the Blue Oak Model Licence 1.0.0 -use crate::{CChar, CStringIter}; +use core::ffi::c_char; /// Rust implementation of C library function `strstr` #[cfg_attr(feature = "strstr", no_mangle)] -pub unsafe extern "C" fn strstr(haystack: *const CChar, needle: *const CChar) -> *const CChar { +pub unsafe extern "C" fn strstr(haystack: *const c_char, needle: *const c_char) -> *const c_char { if *needle.offset(0) == 0 { return haystack; } @@ -16,13 +16,18 @@ pub unsafe extern "C" fn strstr(haystack: *const CChar, needle: *const CChar) -> break; } let mut len = 0; - for (inner_idx, nec) in CStringIter::new(needle).enumerate() { - let hsc = *haystack_trim.add(inner_idx); + loop { + let nec = unsafe { needle.offset(len).read() }; + let hsc = unsafe { haystack_trim.offset(len).read() }; + if nec == 0 { + break; + } if hsc != nec { break; } len += 1; } + if *needle.offset(len) == 0 { return haystack_trim; } @@ -36,40 +41,40 @@ mod test { #[test] fn no_match() { - let needle = b"needle\0".as_ptr(); - let haystack = b"haystack\0".as_ptr(); + let needle = c"needle".as_ptr(); + let haystack = c"haystack".as_ptr(); let result = unsafe { strstr(haystack, needle) }; assert_eq!(result, core::ptr::null()); } #[test] fn start() { - let needle = b"hay\0".as_ptr(); - let haystack = b"haystack\0".as_ptr(); + let needle = c"hay".as_ptr(); + let haystack = c"haystack".as_ptr(); let result = unsafe { strstr(haystack, needle) }; assert_eq!(result, haystack); } #[test] fn middle() { - let needle = b"yst\0".as_ptr(); - let haystack = b"haystack\0".as_ptr(); + let needle = c"yst".as_ptr(); + let haystack = c"haystack".as_ptr(); let result = unsafe { strstr(haystack, needle) }; assert_eq!(result, unsafe { haystack.offset(2) }); } #[test] fn end() { - let needle = b"stack\0".as_ptr(); - let haystack = b"haystack\0".as_ptr(); + let needle = c"stack".as_ptr(); + let haystack = c"haystack".as_ptr(); let result = unsafe { strstr(haystack, needle) }; assert_eq!(result, unsafe { haystack.offset(3) }); } #[test] fn partial() { - let needle = b"haystacka\0".as_ptr(); - let haystack = b"haystack\0".as_ptr(); + let needle = c"haystacka".as_ptr(); + let haystack = c"haystack".as_ptr(); let result = unsafe { strstr(haystack, needle) }; assert_eq!(result, core::ptr::null()); } diff --git a/src/strtol.rs b/src/strtol.rs index 1de8973..6384182 100644 --- a/src/strtol.rs +++ b/src/strtol.rs @@ -3,74 +3,82 @@ //! Original code from the `c-ward` project. //! Licensed under the MIT license. -use crate::{CChar, CInt, CIntMax, CLong, CLongLong, CUIntMax, CULong, CULongLong}; +use core::ffi::{c_char, c_int, c_long, c_longlong, c_ulong, c_ulonglong}; /// Rust implementation of C library function `atoi` #[cfg_attr(feature = "atoi", no_mangle)] -pub unsafe extern "C" fn atoi(s: *const CChar) -> CInt { - strtol(s, core::ptr::null_mut(), 10) as CInt +pub unsafe extern "C" fn atoi(s: *const c_char) -> c_int { + strtol(s, core::ptr::null_mut(), 10) as c_int } /// Rust implementation of C library function `atol` #[cfg_attr(feature = "strtol", no_mangle)] -pub unsafe extern "C" fn strtol(s: *const CChar, endptr: *mut *const CChar, base: CInt) -> CLong { - strtox(s, endptr, base, CLong::MIN as _, CLong::MAX as _) as CLong +pub unsafe extern "C" fn strtol( + s: *const c_char, + endptr: *mut *const c_char, + base: c_int, +) -> c_long { + strtox(s, endptr, base, c_long::MIN as _, c_long::MAX as _) as c_long } /// Rust implementation of C library function `strtoul` #[cfg_attr(not(feature = "strtoul"), export_name = "tinyrlibc_strtoul")] #[cfg_attr(feature = "strtoul", no_mangle)] -pub unsafe extern "C" fn strtoul(s: *const CChar, endptr: *mut *const CChar, base: CInt) -> CULong { - strtox(s, endptr, base, 0, CULong::MAX as _) as CULong +pub unsafe extern "C" fn strtoul( + s: *const c_char, + endptr: *mut *const c_char, + base: c_int, +) -> c_ulong { + strtox(s, endptr, base, 0, c_ulong::MAX as _) as c_ulong } /// Rust implementation of C library function `strtoll` #[cfg_attr(feature = "strtoll", no_mangle)] pub unsafe extern "C" fn strtoll( - s: *const CChar, - endptr: *mut *const CChar, - base: CInt, -) -> CLongLong { - strtox(s, endptr, base, CLongLong::MIN, CLongLong::MAX as _) as CLongLong + s: *const c_char, + endptr: *mut *const c_char, + base: c_int, +) -> c_longlong { + strtox(s, endptr, base, c_longlong::MIN, c_longlong::MAX as _) as c_longlong } /// Rust implementation of C library function `strtoull` #[cfg_attr(feature = "strtoull", no_mangle)] pub unsafe extern "C" fn strtoull( - s: *const CChar, - endptr: *mut *const CChar, - base: CInt, -) -> CULongLong { - strtox(s, endptr, base, 0, CULongLong::MAX) as CULongLong + s: *const c_char, + endptr: *mut *const c_char, + base: c_int, +) -> c_ulonglong { + strtox(s, endptr, base, 0, c_ulonglong::MAX) as c_ulonglong } /// Rust implementation of C library function `strtoimax` #[cfg_attr(feature = "strtoimax", no_mangle)] pub unsafe extern "C" fn strtoimax( - s: *const CChar, - endptr: *mut *const CChar, - base: CInt, -) -> CIntMax { - strtox(s, endptr, base, CIntMax::MIN, CIntMax::MAX as _) as CIntMax + s: *const c_char, + endptr: *mut *const c_char, + base: c_int, +) -> c_longlong { + strtox(s, endptr, base, c_longlong::MIN, c_ulonglong::MAX) as c_longlong } /// Rust implementation of C library function `strtoumax` #[cfg_attr(feature = "strtoumax", no_mangle)] pub unsafe extern "C" fn strtoumax( - s: *const CChar, - endptr: *mut *const CChar, - base: CInt, -) -> CUIntMax { - strtox(s, endptr, base, 0, CUIntMax::MAX) as CUIntMax + s: *const c_char, + endptr: *mut *const c_char, + base: c_int, +) -> c_ulonglong { + strtox(s, endptr, base, 0, c_ulonglong::MAX) as c_ulonglong } pub unsafe fn strtox( - s: *const CChar, - endptr: *mut *const CChar, - base: CInt, - min: CIntMax, - max: CUIntMax, -) -> CUIntMax { + s: *const c_char, + endptr: *mut *const c_char, + base: c_int, + min: c_longlong, + max: c_ulonglong, +) -> c_ulonglong { if !(0..=36).contains(&base) { // TODO: set errno to EINVAL return 0; @@ -78,25 +86,29 @@ pub unsafe fn strtox( // Skip leading whitespace. let mut s = s; - while isspace(CInt::from(*s)) != 0 { + while isspace(c_int::from(*s)) != 0 { s = s.add(1); } // Parse an optional +/- sign. let mut negate = false; - if *s == b'+' as CChar { + if *s == b'+' as c_char { s = s.add(1); - } else if *s == b'-' as CChar { + } else if *s == b'-' as c_char { negate = true; s = s.add(1); } + const LITTLE_X: c_char = b'x' as c_char; + const BIG_X: c_char = b'X' as c_char; + const ZERO: c_char = b'0' as c_char; + // Parse an optional base prefix. - let mut base: CUIntMax = base as CUIntMax; + let mut base: c_ulonglong = base as c_ulonglong; if base == 0 { - if *s == b'0' as CChar { + if *s == ZERO { s = s.add(1); - if (*s == b'x' as CChar || *s == b'X' as CChar) && (*s.add(1)).is_ascii_hexdigit() { + if (*s == LITTLE_X || *s == BIG_X) && (*s.add(1) as u8).is_ascii_hexdigit() { s = s.add(1); base = 16; } else { @@ -106,18 +118,18 @@ pub unsafe fn strtox( base = 10; } } else if base == 16 - && *s == b'0' as CChar - && (*s.add(1) == b'x' as CChar || *s.add(1) == b'X' as CChar) - && (*s.add(2)).is_ascii_hexdigit() + && *s == ZERO + && (*s.add(1) == LITTLE_X || *s.add(1) == BIG_X) + && (*s.add(2) as u8).is_ascii_hexdigit() { s = s.add(2); } // Parse the digits. let mut overflow = false; - let mut num: CUIntMax = 0; + let mut num: c_ulonglong = 0; loop { - let digit: CUIntMax = match *s { + let digit: c_ulonglong = match *s as u8 { x @ b'0'..=b'9' => x - b'0', x @ b'a'..=b'z' => x - b'a' + 10, x @ b'A'..=b'Z' => x - b'A' + 10, @@ -129,7 +141,7 @@ pub unsafe fn strtox( } if negate && min != 0 { - if (num as CIntMax) < min / base as CIntMax { + if (num as c_longlong) < min / base as c_longlong { overflow = true; } } else if num > max / base { @@ -138,7 +150,7 @@ pub unsafe fn strtox( num = num.wrapping_mul(base); if negate && min != 0 { - if (num as CIntMax) < min + digit as CIntMax { + if (num as c_longlong) < min + digit as c_longlong { overflow = true; } num = num.wrapping_sub(digit); @@ -161,7 +173,7 @@ pub unsafe fn strtox( if overflow { // TODO: set errno to ERANGE return if negate && min != 0 { - min as CUIntMax + min as c_ulonglong } else { max }; @@ -173,13 +185,13 @@ pub unsafe fn strtox( } // Return a successful result. - num as CUIntMax + num as c_ulonglong } /// Rust implementation of C library function `isspace` #[cfg_attr(feature = "isspace", no_mangle)] -pub extern "C" fn isspace(argument: CInt) -> CInt { - match argument as CChar { +pub extern "C" fn isspace(argument: c_int) -> c_int { + match argument as u8 { b' ' | b'\t' | b'\n' | b'\r' | 0x0b | 0x0c => 1, _ => 0, } @@ -187,20 +199,20 @@ pub extern "C" fn isspace(argument: CInt) -> CInt { /// Rust implementation of C library function `isdigit` #[cfg_attr(feature = "isdigit", no_mangle)] -pub extern "C" fn isdigit(argument: CInt) -> CInt { - (argument as CChar).is_ascii_digit() as CInt +pub extern "C" fn isdigit(argument: c_int) -> c_int { + (argument as u8).is_ascii_digit() as c_int } /// Rust implementation of C library function `isalpha` #[cfg_attr(feature = "isalpha", no_mangle)] -pub extern "C" fn isalpha(argument: CInt) -> CInt { - (argument as CChar).is_ascii_alphabetic() as CInt +pub extern "C" fn isalpha(argument: c_int) -> c_int { + (argument as u8).is_ascii_alphabetic() as c_int } /// Rust implementation of C library function `isupper` #[cfg_attr(feature = "isupper", no_mangle)] -pub extern "C" fn isupper(argument: CInt) -> CInt { - (argument as CChar).is_ascii_uppercase() as CInt +pub extern "C" fn isupper(argument: c_int) -> c_int { + (argument as u8).is_ascii_uppercase() as c_int } #[cfg(test)] @@ -211,33 +223,75 @@ mod tests { #[test] fn parse_multi_string() { - let string = b"10 200000000000000000000000000000 30 -40\0"; + let string = c"10 200000000000000000000000000000 30 -40"; let mut s = string.as_ptr(); let results = [ (10, unsafe { s.offset(2) }), - (CULong::MAX, unsafe { s.offset(33) }), + (c_ulong::MAX, unsafe { s.offset(33) }), (30, unsafe { s.offset(36) }), - (-40i32 as CULong, unsafe { s.offset(40) }), + (-40i32 as c_ulong, unsafe { s.offset(40) }), ]; for (result_number, result_ptr) in results { - let number = unsafe { strtoul(s, &mut s as *mut _, 10) }; + let number = unsafe { strtoul(s, &mut s, 10) }; assert_eq!(s, result_ptr); assert_eq!(number, result_number); } } + #[test] + fn strtol_min() { + let string = c"-9223372036854775808"; + let value = unsafe { strtol(string.as_ptr(), core::ptr::null_mut(), 10) }; + assert_eq!(value, i64::MIN); + } + + #[test] + fn strtol_max() { + let string = c"9223372036854775807"; + let value = unsafe { strtol(string.as_ptr(), core::ptr::null_mut(), 10) }; + assert_eq!(value, i64::MAX); + } + + #[test] + fn strtoul_max() { + let string = c"18446744073709551616"; + let value = unsafe { strtoul(string.as_ptr(), core::ptr::null_mut(), 10) }; + assert_eq!(value, u64::MAX); + } + + #[test] + fn strtoll_min() { + let string = c"-9223372036854775808"; + let value = unsafe { strtoll(string.as_ptr(), core::ptr::null_mut(), 10) }; + assert_eq!(value, i64::MIN); + } + + #[test] + fn strtoll_max() { + let string = c"9223372036854775807"; + let value = unsafe { strtoll(string.as_ptr(), core::ptr::null_mut(), 10) }; + assert_eq!(value, i64::MAX); + } + + #[test] + fn strtoull_max() { + let string = c"18446744073709551616"; + let value = unsafe { strtoull(string.as_ptr(), core::ptr::null_mut(), 10) }; + assert_eq!(value, u64::MAX); + } + #[test] fn parse_hex() { assert_eq!( - unsafe { strtoul(b"0xAA123\0".as_ptr(), null_mut(), 0) }, + unsafe { strtoul(c"0xAA123".as_ptr(), null_mut(), 0) }, 0xAA123 ); - assert_eq!(unsafe { strtoul(b"0X00\0".as_ptr(), null_mut(), 0) }, 0x00); + assert_eq!(unsafe { strtoul(c"0X00".as_ptr(), null_mut(), 0) }, 0x00); assert_eq!( - unsafe { strtoul(b"-0x123456F\0".as_ptr(), null_mut(), 0) }, + unsafe { strtoul(c"-0x123456F".as_ptr(), null_mut(), 0) }, (-0x123456Fi32) as _ ); }