diff --git a/Cargo.toml b/Cargo.toml index 56eacfc..c035639 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,20 @@ [package] -name = "c_rs" +name = "pact" version = "0.1.0" authors = ["Jason Travis Smith "] description = "Rust bindings for standard C functions." license = "" -repository = "https://gitlab.com/CyberMages/c_rs.git" +repository = "https://gitlab.com/CyberMages/pact.git" documentation = "" -keywords = ["c", "libc", "binding", "ffi"] +keywords = ["c", "libc", "binding", "ffi", "pact", "nostd"] + + +[features] +default = ["c_lib"] +use_std = ["scribe/use_std", "binding/use_std"] +c_lib = [] +no_mem_manip = [] +weak = [] [dependencies.scribe] diff --git a/README.md b/README.md index c54eabc..57bd5b1 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,58 @@ -# C # -This library will provided binding for the standard C functions. Later, as a -stretch goal, this library will attempt to implement those functions in Rust. +# Pact # +This library will provided the binding for the standard 'C' functions. +Later, as a stretch goal, this library will attempt to implement those +functions in Rust. + +## Features ## +This library handles several different ways of providing what is needed +at the 'C' binding level. + +### Standard C Library ### + +This is the default feature set. Or you can add: + +``` + default-features = false + features = ["c_lib"] +``` + +It will provide a link to the 'C' standard library. This will make it so +that your code is executable and can call functions and use structures from +the standard 'C' library. + +### Rust C Library ### + +``` + default-features = false + features = ["rust_lib"] +``` + +Currently, this does not work. Later, this will provide a Rust version of +all the 'C' standard library functions. This is a **huge** stretch goal. +It may not happen, or it may take a really long time to get this done. +This will require alot of platform specific work. + +### No Memory Manipulation ### + +``` + default-features = false + features = ["no_mem_manip"] +``` + +This feature tells the library to not define the memory manipulation +functions that Rust requires for LLVM. These are: + + * memcpy + * memmove + * memset + * memcmp + +### Weak ### + +``` + default-features = false + features = ["no_mem_manip", "weak"] +``` + +Activates weak linkage on ELF objects. This is only useful when combined with +the 'no_mem_manip' feature. diff --git a/src/c/mod.rs b/src/c/mod.rs new file mode 100644 index 0000000..6c0a54a --- /dev/null +++ b/src/c/mod.rs @@ -0,0 +1,12 @@ +//! Handle defining the external functions from what ever C library is +//! being linked against. These will use the C99 definitions so that +//! this library is as up-to-date as it can be. + + +mod string; +mod time; + + + +pub use self::string::*; +pub use self::time::*; diff --git a/src/c/string.rs b/src/c/string.rs new file mode 100644 index 0000000..6b963f5 --- /dev/null +++ b/src/c/string.rs @@ -0,0 +1,56 @@ +#[link(name="c")] +extern +{ +} + +#[cfg(not(feature="no_mem_manip"))] +#[link(name="c")] +extern +{ + /// Copies the values of n bytes from the location pointed to by + /// src directly to the memory block pointed to by dest. + /// + /// The underlying type of the objects pointed to by both the src + /// and dest pointers are irrelevant for this function; The + /// result is a binary copy of the data. + /// + /// The function does not check for any terminating null character + /// in source - it always copies exactly n bytes. + /// + /// To avoid overflows, the size of the arrays pointed to by both + /// the dest and src parameters, shall be at least n bytes, + /// and should not overlap (for overlapping memory blocks, memmove + /// is a safer approach). + pub fn memcpy(dest: *mut u8, src: *const u8, n: usize); + + /// Copies the values of n bytes from the location pointed by src + /// to the memory block pointed by dest. Copying takes place + /// as if an intermediate buffer were used, allowing the dest + /// and src to overlap. + /// + /// The underlying type of the objects pointed by both the src and + /// dest pointers are irrelevant for this function; The result + /// is a binary copy of the data. + /// + /// The function does not check for any terminating null character + /// in source - it always copies exactly n bytes. + /// + /// To avoid overflows, the size of the arrays pointed by both + /// the dest and src parameters, shall be at least n bytes. + pub fn memmove(dest: *mut u8, src: *const u8, n: usize); + + + /// Compares the first n bytes of the block of memory pointed by + /// s1 to the first num bytes pointed by s2, returning zero if + /// they all match or a value different from zero representing which + /// is greater if they do not. + /// + /// Notice that, unlike strcmp, the function does not stop comparing + /// after finding a null character. + pub fn memcmp(s1: *const u8, s2: *const u8, n: usize); + + + /// Sets the first n bytes of the block of memory pointed by s + /// to the specified value c (interpreted as an unsigned char). + pub fn memset(s: *mut u8, c: i32, n: usize); +} diff --git a/src/c/time.rs b/src/c/time.rs new file mode 100644 index 0000000..9e159b4 --- /dev/null +++ b/src/c/time.rs @@ -0,0 +1,55 @@ +use binding::{CInt, CLong}; + + + +/// The type used for seconds in the time structures. +pub type Seconds = CLong; + + + +/// The local time of the system. This can be used +/// to get more specific calendar type information. +#[derive(Copy, Clone)] +#[repr(C)] +pub struct LocalTime +{ + /// Seconds [0-60] **Note** 1 leap second. + second: CInt, + + /// Minutes [0-59]. + minute: CInt, + + /// Hours [0-23]. + hour: CInt, + + /// Day of the month [1-31]. + day_of_month: CInt, + + /// Month of the year [0-11]. + month: CInt, + + /// Years since 1900. + year: CInt, + + /// Days since Sunday [0-6]. + day_of_week: CInt, + + /// Days since January 1 [0-365]. + day_of_year: CInt, + + /// DST [-1/0/1]. Greater than zero if DST is in effect, + /// zero if DST is not in effect, and less than zero if + /// the information is not available. + is_dst: CInt, +} + + + +#[link(name="c")] +extern +{ + /// Uses the value pointed by time to fill a LocalTime structure with + /// the values that represent the corresponding time, expressed + /// for the local timezone. + pub fn localtime(time: *const Seconds) -> *const LocalTime; +} diff --git a/src/lib.rs b/src/lib.rs index 3de4238..18c0e50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,41 @@ //! + +// Handle using the core or the std of Rust depending on the chosen feature. +#![cfg_attr(not(feature="use_std"), no_std)] + +// This crate can only use parts of Rust that are in both the core +// and the standard library. This way the logging system will work for +// libraries that use either. +// +// This is handled by coding using the std library and referencing the core +// library as the std library if the core library is desired. +#[cfg(not(feature="use_std"))] +extern crate core as std; + #[macro_use] extern crate scribe; #[macro_use] extern crate binding; + + + +#[cfg(feature="c_lib")] +mod c; + +#[cfg(not(feature="c_lib"))] +mod rust; + +#[cfg(feature="no_mem_manip")] +mod mem; + + + +#[cfg(feature="c_lib")] +pub use self::c::*; + +#[cfg(not(feature="c_lib"))] +pub use self::rust::*; + +#[cfg(feature="no_mem_manip")] +pub use self::mem::*; diff --git a/src/mem.rs b/src/mem.rs new file mode 100644 index 0000000..c630e5c --- /dev/null +++ b/src/mem.rs @@ -0,0 +1,144 @@ +//! This section deals with the memory manipulation functions. These should +//! be in the string module inside the rust module to more closely match +//! the 'C' library, but the no library feature needs them as well. +//! These functions are here so that there does not need to be +//! any duplication of the code. + +// There is nothing to do on windows or macos as weak linkage seems to +// only work with ELF objects. +#![cfg_attr(all(feature="weak", not(windows), not(target_os="macos")), + feature(linkage))] + + + +/// Copies the values of n bytes from the location pointed to by +/// src directly to the memory block pointed to by dest. +/// +/// The underlying type of the objects pointed to by both the src +/// and dest pointers are irrelevant for this function; The +/// result is a binary copy of the data. +/// +/// The function does not check for any terminating null character +/// in source - it always copies exactly n bytes. +/// +/// To avoid overflows, the size of the arrays pointed to by both +/// the dest and src parameters, shall be at least n bytes, +/// and should not overlap (for overlapping memory blocks, memmove +/// is a safer approach). +#[cfg_attr(all(feature="weak", not(windows), not(target_os="macos")), + linkage="weak")] +#[no_mangle] +pub unsafe extern fn memcpy(dest: *mut u8, src: *const u8, n: usize) + -> *mut u8 +{ + let mut i: usize; + + i = 0; + while i < n + { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + + return dest; +} + +/// Copies the values of n bytes from the location pointed by src +/// to the memory block pointed by dest. Copying takes place +/// as if an intermediate buffer were used, allowing the dest +/// and src to overlap. +/// +/// The underlying type of the objects pointed by both the src and +/// dest pointers are irrelevant for this function; The result +/// is a binary copy of the data. +/// +/// The function does not check for any terminating null character +/// in source - it always copies exactly n bytes. +/// +/// To avoid overflows, the size of the arrays pointed by both +/// the dest and src parameters, shall be at least n bytes. +#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), + linkage = "weak")] +#[no_mangle] +pub unsafe extern fn memmove(dest: *mut u8, src: *const u8, n: usize) + -> *mut u8 +{ + let mut i: usize; + + if src < dest as *const u8 + { + // copy from end + i = n; + while i != 0 + { + i -= 1; + *dest.offset(i as isize) = *src.offset(i as isize); + } + } + else + { + // copy from beginning + i = 0; + while i < n + { + *dest.offset(i as isize) = *src.offset(i as isize); + i += 1; + } + } + + return dest; +} + +/// Compares the first n bytes of the block of memory pointed by +/// s1 to the first num bytes pointed by s2, returning zero if +/// they all match or a value different from zero representing which +/// is greater if they do not. +/// +/// Notice that, unlike strcmp, the function does not stop comparing +/// after finding a null character. +#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), + linkage = "weak")] +#[no_mangle] +pub unsafe extern fn memcmp(s1: *const u8, s2: *const u8, n: usize) + -> i32 +{ + let mut a: u8; + let mut b: u8; + let mut i: usize; + + i = 0; + while i < n + { + a = *s1.offset(i as isize); + b = *s2.offset(i as isize); + + if a != b + { + return (a as i32) - (b as i32) + } + + i += 1; + } + + return 0; +} + +/// Sets the first n bytes of the block of memory pointed by s +/// to the specified value c (interpreted as an unsigned char). +#[cfg_attr(all(feature = "weak", not(windows), not(target_os = "macos")), + linkage = "weak")] +#[no_mangle] +pub unsafe extern fn memset(s: *mut u8, c: i32, n: usize) + -> *mut u8 +{ + let mut i: usize; + + i = 0; + while i < n + { + *s.offset(i as isize) = c as u8; + i += 1; + } + + return s; +} diff --git a/src/rust/mod.rs b/src/rust/mod.rs new file mode 100644 index 0000000..e69de29