diff --git a/Cargo.toml b/Cargo.toml index 9cc42c3..c6ba0f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,18 +7,26 @@ license = "" repository = "https://gitlab.com/CyberMages/pact.git" documentation = "" keywords = ["c", "libc", "binding", "ffi", "pact", "nostd"] +build = "build.rs" [features] default = [] -use_std = ["scribe/use_std", "binding/use_std"] +use_std = ["scribe/use_std", "binding/use_std", "weave/use_std"] rust_lib = [] no_mem_manip = [] weak = [] +[build-dependencies.scribe] +git = "https://gitlab.com/CyberMages/scribe.git" + + [dependencies.scribe] git = "https://gitlab.com/CyberMages/scribe.git" [dependencies.binding] git = "https://gitlab.com/CyberMages/binding.git" + +[dependencies.weave] +git = "https://gitlab.com/CyberMages/weave.git" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..91183ef --- /dev/null +++ b/build.rs @@ -0,0 +1,202 @@ +#[macro_use] +extern crate scribe; + + + +use std::env; +use std::ffi::OsString; +use std::path::PathBuf; + + + +pub const BUILD_DIR: &'static str = "build"; + +pub const ERRNO_GENERATOR_FILENAME: &'static str = "errno.c"; +pub const ERRNO_GENERATOR_OUTPUT_FILENAME: &'static str = "errno.gen"; + +pub const GENERATED_ERRNO_FILENAME: &'static str = "errno_values.rs"; + + + +fn determine_base_dir() -> PathBuf +{ + // Get the cargo manifest directory. + match ::std::env::var_os("CARGO_MANIFEST_DIR") + { + Some(dir) => + { + PathBuf::from(dir) + } + + None => + { + PathBuf::new() + } + } +} + +fn determine_output_dir() -> PathBuf +{ + let output_dir: PathBuf; + + // Get the output directory for the build. + match ::std::env::var_os("OUT_DIR") + { + Some(dir) => + { + output_dir = PathBuf::from(dir); + } + + None => + { + // Try to just get the current directory. + match env::current_dir() + { + Ok(dir) => + { + output_dir = PathBuf::from(dir); + } + + Err(error) => + { + // Then just default to "". + warn!("{}", error); + output_dir = PathBuf::new(); + } + } + } + } + + output_dir +} + +fn determine_build_dir() -> PathBuf +{ + let mut build_dir: PathBuf; + + build_dir = determine_base_dir(); + build_dir.push(BUILD_DIR); + + build_dir +} + +fn determine_c_compiler() -> OsString +{ + match ::std::env::var_os("CC") + { + Some(compiler) => + { + OsString::from(compiler) + } + + None => + { + OsString::from("gcc") + } + } +} + +fn build_output_file(filename: &str) -> PathBuf +{ + let mut output_dir: PathBuf; + + output_dir = determine_output_dir(); + output_dir.push(filename); + + output_dir +} + +fn build_src_file(filename: &str) -> PathBuf +{ + let mut build_dir: PathBuf; + + build_dir = determine_build_dir(); + build_dir.push(filename); + + build_dir +} + +fn compile(src_files: &[PathBuf], output_name: &str) -> PathBuf +{ + let c_compiler: OsString; + let mut output_file: PathBuf; + let mut initial_command: ::std::process::Command; + let command: &mut ::std::process::Command; + let last_command: &mut ::std::process::Command; + let final_command: &mut ::std::process::Command; + + c_compiler = determine_c_compiler(); + output_file = build_output_file(output_name); + + initial_command = ::std::process::Command::new(c_compiler); + command = initial_command.args(src_files); + last_command = command.arg("-o"); + final_command = last_command.arg(output_file.clone()); + + match final_command.output() + { + Ok(output) => + { + if output.status.success() == false + { + error!("{:?}", output); + } + } + + Err(error) => + { + error!("{}", error); + } + } + + output_file +} + +fn run(executable: PathBuf, args: &[PathBuf]) +{ + let mut initial_command: ::std::process::Command; + let final_command: &mut ::std::process::Command; + + initial_command = ::std::process::Command::new(executable); + final_command = initial_command.args(args); + + match final_command.output() + { + Ok(output) => + { + if output.status.success() == false + { + error!("{:?}", output); + } + } + + Err(error) => + { + error!("{}", error); + } + } +} + +fn compile_and_run(output_name: &str, src_files: &[PathBuf], args: &[PathBuf]) +{ + let executable: PathBuf; + + executable = compile(src_files, output_name); + run(executable, args); +} + + + +pub fn main() +{ + let mut errno_file: PathBuf; + let mut gen_file: PathBuf; + let mut gen_errno_file: PathBuf; + + errno_file = build_src_file(ERRNO_GENERATOR_FILENAME); + gen_file = build_output_file(ERRNO_GENERATOR_OUTPUT_FILENAME); + gen_errno_file = build_output_file(GENERATED_ERRNO_FILENAME); + + compile_and_run(ERRNO_GENERATOR_OUTPUT_FILENAME, + &[errno_file], &[gen_errno_file]); +} diff --git a/build/errno.c b/build/errno.c new file mode 100644 index 0000000..b96a95e --- /dev/null +++ b/build/errno.c @@ -0,0 +1,51 @@ +#include +#include + + +// Writes a public constant value to the desired file. +void write_constant(FILE* file, const char* name, + const char* type, const int val) +{ + fprintf(file, "pub const %s: %s = %d;\n", name, type, val); +} + +// Writes the header of the errno file. +void write_file_header(FILE* file) +{ + fprintf(file, "// This was generated by a build script to obtain\n"); + fprintf(file, "// the correct values of C preprocessor values to\n"); + fprintf(file, "// be used as errno constant values.\n"); +} + + +int main(int argc, char *argv[]) +{ + char* filename; + FILE* output_file; + + // This requires a filename to be given for writing to. + if (argc == 2) + { + filename = argv[1]; + } + else if (argc > 2 || argc < 2) + { + printf("\nThis program requires a filename be given.\n\n"); + return 1; + } + + // Open a file for writing. + output_file = fopen(filename, "w"); + + // Write the errno file header. + write_file_header(output_file); + + // Write the errno constants we are trying to capture. + write_constant(output_file, "EDOM", "CInt", EDOM); + write_constant(output_file, "ERANGE", "CInt", ERANGE); + write_constant(output_file, "EILSEQ", "CInt", EILSEQ); + + // Close the file. + fclose(output_file); + return 0; +} diff --git a/src/c/errno.rs b/src/c/errno.rs new file mode 100644 index 0000000..fe8d29c --- /dev/null +++ b/src/c/errno.rs @@ -0,0 +1,167 @@ +use weave::Error; +use binding::CInt; + + + +/// This signifies that there is no current error. +/// This can be used for clearing an error. +pub const NO_ERROR: CInt = 0; + +/// Include the generated C error values. +include!(concat!(env!("OUT_DIR"), "/errno_values.rs")); + + + +/// +#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)] +pub enum CError +{ + /// There is no Error. + None, + + /// Some mathematical functions are only defined + /// for certain real values, which is called its domain, + /// for example the square root function is only defined for + /// non-negative numbers, therefore the sqrt function sets + /// errno to EDOM if called with a negative argument. + Domain, + + /// The range of values that can be represented + /// with a variable is limited. For example, mathematical functions + /// such as pow can easily outbound the range representable by a + /// floating point variable, or functions such as strtod can + /// encounter sequences of digits longer than the range + /// representable values. In these cases, errno is set to ERANGE. + Range, + + /// Multibyte character sequence may have a + /// restricted set of valid sequences. When a set of multibyte + /// characters is translated by functions such as mbrtowc, + /// errno is set to EILSEQ when an invalid sequence is encountered. + IllegalSequence, + + /// There was a detected error, but it + /// is not one handled by CError. + Unhandled +} + + + +impl CError +{ + /// Returns if the given value is a handled CError. + pub fn is_handled_error(errno: i32) -> bool + { + let error: CError; + + // Turn the error value into a CError and + // check if it is an Unhandled error. + error = CError::from(errno); + if error != CError::Unhandled + { + true + } + else + { + false + } + } + + /// Check the last Error that was posted. + pub fn get_current_error() -> CError + { + CError::from(get_errno()) + } + + /// Set the current Error for the system. + pub fn set_current_error(error: CError) + { + set_errno(error as i32); + } + + /// Clear the current Error. + pub fn clear() + { + CError::set_current_error(CError::None); + } +} + +impl ::std::fmt::Debug for CError +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result + { + ::std::fmt::Display::fmt(self, f) + } +} + +impl ::std::fmt::Display for CError +{ + fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result + { + //write!(f, "{}", self.to_str()) + write!(f, "{}", self.get_description()) + } +} + +impl From for CError +{ + fn from(val: i32) -> CError + { + match val + { + NO_ERROR => { CError::None } + EDOM => { CError::Domain } + ERANGE => { CError::Range } + EILSEQ => { CError::IllegalSequence } + _ => { CError::Unhandled } + } + } +} + +impl Error for CError +{ + fn get_description(&self) -> &str + { + match *self + { + CError::None => { "There was no error" } + CError::Domain => { "Math argument out of domain of function" } + CError::Range => { "Math result not representable" } + CError::IllegalSequence => { "Illegal byte sequence" } + CError::Unhandled => { "Detected an Error not handled by CError" } + } + } + + fn get_cause(&self) -> Option<&Error> + { + None + } +} + + + +/// A helper function for getting the current error. +fn get_errno() -> i32 +{ + unsafe + { + *__errno_location() as i32 + } +} + +/// A helper function for setting the current error. +fn set_errno(errnum: i32) +{ + unsafe + { + *__errno_location() = errnum as CInt; + } +} + + + +// The function to get the errno memory location. +extern +{ + fn __errno_location() -> *mut CInt; +} diff --git a/src/c/mod.rs b/src/c/mod.rs index 6c0a54a..b16efce 100644 --- a/src/c/mod.rs +++ b/src/c/mod.rs @@ -3,10 +3,12 @@ //! this library is as up-to-date as it can be. +mod errno; mod string; mod time; +pub use self::errno::*; pub use self::string::*; pub use self::time::*; diff --git a/src/lib.rs b/src/lib.rs index 1c34b5c..7c5b3ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,8 @@ extern crate scribe; #[macro_use] extern crate binding; +extern crate weave; + #[cfg(not(feature="rust_lib"))]