Skip to content

Commit 0fe817f

Browse files
authored
Fix feature dependency (#17)
* Added additional `strtoX` functions * Ensure that functions are available to Rust code, even if the feature that controls the export of a C compatible name is turned off
1 parent e9a3798 commit 0fe817f

20 files changed

+411
-361
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ jobs:
103103
- uses: actions-rs/toolchain@v1
104104
with:
105105
profile: minimal
106-
toolchain: 1.64.0 # clippy is too much of a moving target at the moment
106+
toolchain: 1.75.0 # clippy is too much of a moving target at the moment
107107
override: true
108108
components: clippy
109109
- uses: actions-rs/clippy-check@v1

Cargo.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,20 @@ all = [
2424
"strlen",
2525
"strtol",
2626
"strtoul",
27+
"strtoll",
28+
"strtoull",
29+
"strtoimax",
30+
"strtoumax",
2731
"strstr",
2832
"strchr",
2933
"atoi",
34+
"utoa",
3035
"itoa",
3136
"snprintf",
37+
"isspace",
38+
"isdigit",
39+
"isalpha",
40+
"isupper",
3241
]
3342
abs = []
3443
strcmp = []
@@ -38,8 +47,17 @@ strncpy = []
3847
strlen = []
3948
strtol = []
4049
strtoul = []
50+
strtoll = []
51+
strtoull = []
52+
strtoimax = []
53+
strtoumax = []
4154
strstr = []
4255
strchr = []
4356
atoi = []
57+
utoa = []
4458
itoa = []
4559
snprintf = []
60+
isspace = []
61+
isdigit = []
62+
isalpha = []
63+
isupper = []

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,21 @@ This crate basically came about so that the [nrfxlib](https://github.com/NordicP
1111
* abs
1212
* strol
1313
* atoi
14+
* isspace
15+
* isdigit
16+
* isalpha
17+
* isupper
1418
* strcmp
1519
* strncmp
1620
* strcpy
1721
* strncpy
1822
* strlen
1923
* strtol
24+
* strtoll
2025
* strtoul
26+
* strtoull
27+
* strtoimax
28+
* strtoumax
2129
* strstr
2230
* strchr
2331
* snprintf

build.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,30 @@
11
fn main() {
22
if cfg!(feature = "snprintf") {
33
// Build our snprintf substitute (which has to be C as Rust doesn't do varargs)
4-
cc::Build::new()
4+
let mut build = cc::Build::new();
5+
6+
build
57
.warnings(true)
68
.extra_warnings(true)
79
.flag("-std=c99")
8-
.file("./src/snprintf.c")
9-
.compile("clocal");
10+
.file("./src/snprintf.c");
11+
12+
#[cfg(not(feature = "itoa"))]
13+
{
14+
build.define("itoa", "tinyrlibc_itoa");
15+
}
16+
#[cfg(not(feature = "utoa"))]
17+
{
18+
build.define("utoa", "tinyrlibc_utoa");
19+
}
20+
#[cfg(not(feature = "strtoul"))]
21+
{
22+
build.define("strtoul", "tinyrlibc_strtoul");
23+
}
24+
25+
build.compile("clocal");
1026
}
27+
28+
println!("cargo:rerun-if-changed=build.rs");
29+
println!("cargo:rerun-if-changed=src/snprintf.c");
1130
}

src/abs.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@
44
55
use crate::CInt;
66

7-
/// Calculates the integer absolute value
8-
///
9-
/// ```
10-
/// use tinyrlibc::abs;
11-
/// assert_eq!(abs(-2), 2);
12-
/// ```
13-
#[no_mangle]
7+
/// Rust implementation of C library function `abs`
8+
#[cfg_attr(feature = "abs", no_mangle)]
149
pub extern "C" fn abs(i: CInt) -> CInt {
1510
i.abs()
1611
}

src/atoi.rs

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/ctype.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//! A tiny C library, written in Rust.
2+
//!
3+
//! See README.md for more details.
4+
//!
5+
//! This file is Copyright (c) Jonathan 'theJPster' Pallant 2019
6+
//! Licensed under the Blue Oak Model Licence 1.0.0
7+
//!
8+
//! See each module for its respective licence.
9+
10+
/// `void`
11+
pub type CVoid = ::core::ffi::c_void;
12+
13+
/// `long long int`
14+
pub type CLongLong = ::core::ffi::c_longlong;
15+
16+
/// `unsigned long long int`
17+
pub type CULongLong = ::core::ffi::c_ulonglong;
18+
19+
/// `intmax_t`
20+
pub type CUIntMax = CULongLong;
21+
22+
/// `uintmax_t`
23+
pub type CIntMax = CLongLong;
24+
25+
/// `long int`
26+
pub type CLong = ::core::ffi::c_long;
27+
28+
/// `unsigned long int`
29+
pub type CULong = ::core::ffi::c_ulong;
30+
31+
/// `int`
32+
pub type CInt = ::core::ffi::c_int;
33+
34+
/// `unsigned int`
35+
pub type CUInt = ::core::ffi::c_uint;
36+
37+
/// Represents an 8-bit `char`. Rust does not (and will never) support
38+
/// platforms where `char` is not 8-bits long.
39+
pub type CChar = u8;
40+
41+
/// This allows you to iterate a null-terminated string in a relatively simple
42+
/// way.
43+
pub struct CStringIter {
44+
ptr: *const CChar,
45+
idx: isize,
46+
}
47+
48+
impl CStringIter {
49+
/// Create a new iterator from a pointer to a null-terminated string. The
50+
/// behaviour is undefined if the string is not null-terminated.
51+
pub fn new(s: *const CChar) -> CStringIter {
52+
CStringIter { ptr: s, idx: 0 }
53+
}
54+
}
55+
56+
impl core::iter::Iterator for CStringIter {
57+
type Item = CChar;
58+
fn next(&mut self) -> Option<Self::Item> {
59+
let c = unsafe { *self.ptr.offset(self.idx) };
60+
if c == 0 {
61+
None
62+
} else {
63+
self.idx += 1;
64+
Some(c)
65+
}
66+
}
67+
}

src/itoa.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
99
use crate::CChar;
1010

11-
#[no_mangle]
1211
/// Formats the given value `i`, with the given radix, into the given buffer (of the given length).
1312
///
1413
/// No prefixes (like 0x or 0b) are generated. Only radix values in the range
1514
/// 2..=16 are supported.
1615
///
1716
/// Returns the number of bytes written on success (not including the null),
1817
/// or -1 if the buffer wasn't large enough.
18+
#[cfg_attr(not(feature = "itoa"), export_name = "tinyrlibc_itoa")]
19+
#[cfg_attr(feature = "itoa", no_mangle)]
1920
pub unsafe extern "C" fn itoa(i: i64, s: *mut CChar, s_len: usize, radix: u8) -> i32 {
2021
let (is_negative, pos_i) = if i < 0 {
2122
(true, (-i) as u64)
@@ -31,14 +32,15 @@ pub unsafe extern "C" fn itoa(i: i64, s: *mut CChar, s_len: usize, radix: u8) ->
3132
}
3233
}
3334

34-
#[no_mangle]
3535
/// Formats the given value `u`, with the given radix, into the given buffer (of the given length).
3636
///
3737
/// No prefixes (like 0x or 0b) are generated. Only radix values in the range
3838
/// 2..=16 are supported. Negative numbers are not supported.
3939
///
4040
/// Returns the number of bytes written on success (not including the null),
4141
/// or -1 if the buffer wasn't large enough.
42+
#[cfg_attr(not(feature = "utoa"), export_name = "tinyrlibc_utoa")]
43+
#[cfg_attr(feature = "utoa", no_mangle)]
4244
pub unsafe extern "C" fn utoa(mut u: u64, s: *mut CChar, s_len: usize, radix: u8) -> i32 {
4345
let buffer_slice = core::slice::from_raw_parts_mut(s, s_len);
4446

src/lib.rs

Lines changed: 25 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,123 +5,74 @@
55
//! This file is Copyright (c) Jonathan 'theJPster' Pallant 2019
66
//! Licensed under the Blue Oak Model Licence 1.0.0
77
//!
8-
//! See each module for its respective licence.
8+
//! See each module for its respective license.
99
1010
#![cfg_attr(not(test), no_std)]
11+
#![allow(clippy::missing_safety_doc)]
1112

1213
#[cfg(test)]
1314
#[allow(unused_imports)]
1415
use std as core;
1516

16-
#[cfg(feature = "abs")]
17+
mod itoa;
18+
1719
mod abs;
1820
#[cfg(feature = "abs")]
1921
pub use self::abs::abs;
2022

21-
#[cfg(feature = "strcmp")]
2223
mod strcmp;
2324
#[cfg(feature = "strcmp")]
2425
pub use self::strcmp::strcmp;
2526

26-
#[cfg(feature = "strncmp")]
2727
mod strncmp;
2828
#[cfg(feature = "strncmp")]
2929
pub use self::strncmp::strncmp;
3030

31-
#[cfg(feature = "strcpy")]
3231
mod strcpy;
3332
#[cfg(feature = "strcpy")]
3433
pub use self::strcpy::strcpy;
3534

36-
#[cfg(feature = "strncpy")]
3735
mod strncpy;
3836
#[cfg(feature = "strncpy")]
3937
pub use self::strncpy::strncpy;
4038

41-
#[cfg(feature = "strlen")]
4239
mod strlen;
4340
#[cfg(feature = "strlen")]
4441
pub use self::strlen::strlen;
4542

46-
#[cfg(feature = "strtol")]
4743
mod strtol;
44+
#[cfg(feature = "atoi")]
45+
pub use self::strtol::atoi;
46+
#[cfg(feature = "isalpha")]
47+
pub use self::strtol::isalpha;
48+
#[cfg(feature = "isdigit")]
49+
pub use self::strtol::isdigit;
50+
#[cfg(feature = "isspace")]
51+
pub use self::strtol::isspace;
52+
#[cfg(feature = "isupper")]
53+
pub use self::strtol::isupper;
54+
#[cfg(feature = "strtoimax")]
55+
pub use self::strtol::strtoimax;
4856
#[cfg(feature = "strtol")]
4957
pub use self::strtol::strtol;
50-
58+
#[cfg(feature = "strtoll")]
59+
pub use self::strtol::strtoll;
5160
#[cfg(feature = "strtoul")]
52-
mod strtoul;
53-
#[cfg(feature = "strtoul")]
54-
pub use self::strtoul::strtoul;
61+
pub use self::strtol::strtoul;
62+
#[cfg(feature = "strtoull")]
63+
pub use self::strtol::strtoull;
64+
#[cfg(feature = "strtoumax")]
65+
pub use self::strtol::strtoumax;
5566

56-
#[cfg(feature = "strstr")]
5767
mod strstr;
5868
#[cfg(feature = "strstr")]
5969
pub use self::strstr::strstr;
6070

61-
#[cfg(feature = "strchr")]
6271
mod strchr;
6372
#[cfg(feature = "strchr")]
6473
pub use self::strchr::strchr;
6574

66-
#[cfg(feature = "atoi")]
67-
mod atoi;
68-
#[cfg(feature = "atoi")]
69-
pub use self::atoi::atoi;
70-
71-
#[cfg(feature = "itoa")]
72-
mod itoa;
73-
#[cfg(feature = "itoa")]
74-
pub use self::itoa::itoa;
75-
76-
#[cfg(feature = "snprintf")]
7775
mod snprintf;
7876

79-
/// `long long int`
80-
pub type CLongLong = ::core::ffi::c_longlong;
81-
82-
/// `unsigned long long int`
83-
pub type CULongLong = ::core::ffi::c_ulonglong;
84-
85-
/// `long int`
86-
pub type CLong = ::core::ffi::c_long;
87-
88-
/// `unsigned long int`
89-
pub type CULong = ::core::ffi::c_ulong;
90-
91-
/// `int`
92-
pub type CInt = ::core::ffi::c_int;
93-
94-
/// `unsigned int`
95-
pub type CUInt = ::core::ffi::c_uint;
96-
97-
/// Represents an 8-bit `char`. Rust does not (and will never) support
98-
/// platforms where `char` is not 8-bits long.
99-
pub type CChar = u8;
100-
101-
/// This allows you to iterate a null-terminated string in a relatively simple
102-
/// way.
103-
pub struct CStringIter {
104-
ptr: *const CChar,
105-
idx: isize,
106-
}
107-
108-
impl CStringIter {
109-
/// Create a new iterator from a pointer to a null-terminated string. The
110-
/// behaviour is undefined if the string is not null-terminated.
111-
pub fn new(s: *const CChar) -> CStringIter {
112-
CStringIter { ptr: s, idx: 0 }
113-
}
114-
}
115-
116-
impl core::iter::Iterator for CStringIter {
117-
type Item = CChar;
118-
fn next(&mut self) -> Option<Self::Item> {
119-
let c = unsafe { *self.ptr.offset(self.idx) };
120-
if c == 0 {
121-
None
122-
} else {
123-
self.idx += 1;
124-
Some(c)
125-
}
126-
}
127-
}
77+
mod ctype;
78+
pub use self::ctype::*;

0 commit comments

Comments
 (0)