From 4e5ec035251bf3d8227cf180b445902cc6a033c9 Mon Sep 17 00:00:00 2001 From: Michael Murphy <mmstickman@gmail.com> Date: Fri, 22 Jun 2018 22:11:08 -0600 Subject: [PATCH] Make an ion_builtins workspace member --- Cargo.lock | 12 + Cargo.toml | 3 +- ion_builtins/Cargo.toml | 12 + .../lib/builtins => ion_builtins/src}/calc.rs | 4 +- ion_builtins/src/conditionals.rs | 18 ++ .../lib/builtins => ion_builtins/src}/echo.rs | 2 +- ion_builtins/src/lib.rs | 12 + .../builtins => ion_builtins/src}/random.rs | 13 +- .../lib/builtins => ion_builtins/src}/test.rs | 110 ++++++++- src/lib/builtins/README.md | 35 --- src/lib/builtins/conditionals.rs | 31 --- src/lib/builtins/ion.rs | 23 -- src/lib/builtins/man_pages.rs | 223 +++--------------- src/lib/builtins/mod.rs | 23 +- src/lib/builtins/status.rs | 4 +- src/lib/builtins/time.rs | 63 ----- src/lib/lib.rs | 1 + 17 files changed, 223 insertions(+), 366 deletions(-) create mode 100644 ion_builtins/Cargo.toml rename {src/lib/builtins => ion_builtins/src}/calc.rs (92%) create mode 100644 ion_builtins/src/conditionals.rs rename {src/lib/builtins => ion_builtins/src}/echo.rs (98%) create mode 100644 ion_builtins/src/lib.rs rename {src/lib/builtins => ion_builtins/src}/random.rs (85%) rename {src/lib/builtins => ion_builtins/src}/test.rs (84%) delete mode 100644 src/lib/builtins/README.md delete mode 100644 src/lib/builtins/conditionals.rs delete mode 100644 src/lib/builtins/ion.rs delete mode 100644 src/lib/builtins/time.rs diff --git a/Cargo.lock b/Cargo.lock index 25806ed1..68fe9b62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,6 +165,7 @@ dependencies = [ "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "ion_builtins 0.1.0", "ion_sys 0.1.0", "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -180,6 +181,17 @@ dependencies = [ "xdg 2.1.0 (git+https://github.com/whitequark/rust-xdg)", ] +[[package]] +name = "ion_builtins" +version = "0.1.0" +dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "calculate 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "smallstring 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ion_sys" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 496d6d1d..ee2c9710 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ repository = "https://gitlab.redox-os.org/redox-os/ion" version = "1.0.0-alpha" [workspace] -members = ["ion_sys"] +members = [ "ion_builtins", "ion_sys" ] [[bin]] name = "ion" @@ -44,6 +44,7 @@ smallstring = "0.1" smallvec = "0.6" unicode-segmentation = "1.2" xdg = { git = "https://github.com/whitequark/rust-xdg" } +ion_builtins = { path = "ion_builtins" } ion_sys = { path = "ion_sys" } [lib] diff --git a/ion_builtins/Cargo.toml b/ion_builtins/Cargo.toml new file mode 100644 index 00000000..25a796d1 --- /dev/null +++ b/ion_builtins/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "ion_builtins" +version = "0.1.0" +authors = ["Michael Murphy <mmstickman@gmail.com>"] +publish = false + +[dependencies] +bitflags = "1.0" +calculate = "0.5" +rand = "0.5" +smallstring = "0.1" +smallvec = "0.6" diff --git a/src/lib/builtins/calc.rs b/ion_builtins/src/calc.rs similarity index 92% rename from src/lib/builtins/calc.rs rename to ion_builtins/src/calc.rs index 95d90499..62edabd8 100644 --- a/src/lib/builtins/calc.rs +++ b/ion_builtins/src/calc.rs @@ -1,4 +1,4 @@ -use calc::{eval, eval_polish, CalcError, Value}; +use calculate::{eval, eval_polish, CalcError, Value}; use std::io::{self, Write}; fn calc_or_polish_calc(args: &str) -> Result<Value, CalcError> { @@ -8,7 +8,7 @@ fn calc_or_polish_calc(args: &str) -> Result<Value, CalcError> { } } -pub(crate) fn calc(args: &[String]) -> Result<(), String> { +pub fn calc(args: &[String]) -> Result<(), String> { let stdout = io::stdout(); let mut stdout = stdout.lock(); if !args.is_empty() { diff --git a/ion_builtins/src/conditionals.rs b/ion_builtins/src/conditionals.rs new file mode 100644 index 00000000..e4f5751c --- /dev/null +++ b/ion_builtins/src/conditionals.rs @@ -0,0 +1,18 @@ +macro_rules! string_function { + ($method:tt) => { + pub fn $method(args: &[String]) -> i32 { + match args.len() { + 0...2 => { + eprintln!("ion: {}: two arguments must be supplied", args[0]); + return 2; + } + 3 => if args[1].$method(&args[2]) { 0 } else { 1 }, + _ => if args[2..].iter().any(|arg| args[1].$method(arg)) { 0 } else { 1 } + } + } + }; +} + +string_function!(starts_with); +string_function!(ends_with); +string_function!(contains); diff --git a/src/lib/builtins/echo.rs b/ion_builtins/src/echo.rs similarity index 98% rename from src/lib/builtins/echo.rs rename to ion_builtins/src/echo.rs index 6b7f948d..52a2af0d 100644 --- a/src/lib/builtins/echo.rs +++ b/ion_builtins/src/echo.rs @@ -9,7 +9,7 @@ bitflags! { } } -pub(crate) fn echo(args: &[String]) -> Result<(), io::Error> { +pub fn echo(args: &[String]) -> Result<(), io::Error> { let mut flags = Flags::empty(); let mut data: SmallVec<[&str; 16]> = SmallVec::with_capacity(16); diff --git a/ion_builtins/src/lib.rs b/ion_builtins/src/lib.rs new file mode 100644 index 00000000..a2cce04c --- /dev/null +++ b/ion_builtins/src/lib.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate bitflags; +extern crate calc as calculate; +extern crate rand; +extern crate smallstring; +extern crate smallvec; + +pub mod calc; +pub mod conditionals; +pub mod echo; +pub mod random; +pub mod test; diff --git a/src/lib/builtins/random.rs b/ion_builtins/src/random.rs similarity index 85% rename from src/lib/builtins/random.rs rename to ion_builtins/src/random.rs index 9acedf41..fade40ba 100644 --- a/src/lib/builtins/random.rs +++ b/ion_builtins/src/random.rs @@ -1,5 +1,4 @@ -extern crate rand; -use self::rand::Rng; +use rand::{thread_rng, Rng}; use std::io::{self, Write}; #[allow(unused_must_use)] @@ -12,7 +11,7 @@ fn rand_list(args: &[String]) -> Result<(), String> { Err(_) => return Err(String::from("Invalid argument for random")), }; while output.len() < arg1 { - let rand_num = rand::thread_rng().gen_range(1, args.len()); + let rand_num = thread_rng().gen_range(1, args.len()); output.push(&*args[rand_num]); output.dedup(); } @@ -23,12 +22,12 @@ fn rand_list(args: &[String]) -> Result<(), String> { Ok(()) } #[allow(unused_must_use)] -pub(crate) fn random(args: &[String]) -> Result<(), String> { +pub fn random(args: &[String]) -> Result<(), String> { let stdout = io::stdout(); let mut stdout = stdout.lock(); match args.len() { 0 => { - let rand_num = rand::thread_rng().gen_range(0, 32767); + let rand_num = thread_rng().gen_range(0, 32767); writeln!(stdout, "{}", rand_num); } 1 => { @@ -49,7 +48,7 @@ pub(crate) fn random(args: &[String]) -> Result<(), String> { if arg2 <= arg1 { return Err(String::from("END must be greater than START")); } - let rand_num = rand::thread_rng().gen_range(arg1, arg2); + let rand_num = thread_rng().gen_range(arg1, arg2); writeln!(stdout, "{}", rand_num); } 3 => { @@ -70,7 +69,7 @@ pub(crate) fn random(args: &[String]) -> Result<(), String> { if arg1 / arg2 >= end { end += 1; } - let rand_num = rand::thread_rng().gen_range(arg1 / arg2, end); + let rand_num = thread_rng().gen_range(arg1 / arg2, end); writeln!(stdout, "{}", rand_num * arg2); } Err(_) => return rand_list(args), diff --git a/src/lib/builtins/test.rs b/ion_builtins/src/test.rs similarity index 84% rename from src/lib/builtins/test.rs rename to ion_builtins/src/test.rs index 0ed3d466..df246358 100644 --- a/src/lib/builtins/test.rs +++ b/ion_builtins/src/test.rs @@ -1,10 +1,114 @@ -use super::man_pages::{print_man, MAN_TEST}; use smallstring::SmallString; use std::{ fs, os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt}, path::Path, time::SystemTime, }; -pub(crate) fn test(args: &[String]) -> Result<bool, String> { +pub const MAN_TEST: &str = r#"NAME + test - perform tests on files and text + +SYNOPSIS + test [EXPRESSION] + +DESCRIPTION + Tests the expressions given and returns an exit status of 0 if true, else 1. + +OPTIONS + -n STRING + the length of STRING is nonzero + + STRING + equivalent to -n STRING + + -z STRING + the length of STRING is zero + + STRING = STRING + the strings are equivalent + + STRING != STRING + the strings are not equal + + INTEGER -eq INTEGER + the integers are equal + + INTEGER -ge INTEGER + the first INTEGER is greater than or equal to the first INTEGER + + INTEGER -gt INTEGER + the first INTEGER is greater than the first INTEGER + + INTEGER -le INTEGER + the first INTEGER is less than or equal to the first INTEGER + + INTEGER -lt INTEGER + the first INTEGER is less than the first INTEGER + + INTEGER -ne INTEGER + the first INTEGER is not equal to the first INTEGER + + FILE -ef FILE + both files have the same device and inode numbers + + FILE -nt FILE + the first FILE is newer than the second FILE + + FILE -ot FILE + the first file is older than the second FILE + + -b FILE + FILE exists and is a block device + + -c FILE + FILE exists and is a character device + + -d FILE + FILE exists and is a directory + + -e FILE + FILE exists + + -f FILE + FILE exists and is a regular file + + -h FILE + FILE exists and is a symbolic link (same as -L) + + -L FILE + FILE exists and is a symbolic link (same as -h) + + -r FILE + FILE exists and read permission is granted + + -s FILE + FILE exists and has a file size greater than zero + + -S FILE + FILE exists and is a socket + + -w FILE + FILE exists and write permission is granted + + -x FILE + FILE exists and execute (or search) permission is granted + +EXAMPLES + Test if the file exists: + test -e FILE && echo "The FILE exists" || echo "The FILE does not exist" + + Test if the file exists and is a regular file, and if so, write to it: + test -f FILE && echo "Hello, FILE" >> FILE || echo "Cannot write to a directory" + + Test if 10 is greater than 5: + test 10 -gt 5 && echo "10 is greater than 5" || echo "10 is not greater than 5" + + Test if the user is running a 64-bit OS (POSIX environment only): + test $(getconf LONG_BIT) = 64 && echo "64-bit OS" || echo "32-bit OS" + +AUTHOR + Written by Michael Murphy. +"#; + +pub fn test(args: &[String]) -> Result<bool, String> { let arguments = &args[1..]; evaluate_arguments(arguments) } @@ -26,7 +130,7 @@ fn evaluate_arguments(arguments: &[String]) -> Result<bool, String> { Some(ref s) if *s == "--help" => { // "--help" only makes sense if it is the first option. Only look for it // in the first position. - print_man(MAN_TEST); + println!("{}", MAN_TEST); Ok(true) } Some(arg) => { diff --git a/src/lib/builtins/README.md b/src/lib/builtins/README.md deleted file mode 100644 index 480ad68f..00000000 --- a/src/lib/builtins/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# Ion Shell Builtins - -This directory contains the source code of Ion's builtin commands and documentation for their usage. - -## calc.rs - -Source code for the calc command, which allows for basic command-line f32-based arithmetic. - -## echo.rs - -Source code for the echo command, included for performance reasons. - -## functions.rs - -Functions for printing a list of function when the fn keyword is called by itself. - -## source.rs - -The source command evaluates a supplied script. - -## test.rs - -Source code for the test command, which is also included for performance reasons. - -## time.rs - -Source code for the time command, which is used to evaluate the time spent running an external process. - -## variables.rs - -The **variables.rs** module contains commands relating to setting and removing aliases, variables, and exports. - -## status.rs - -The source for status command, which is used to get information at runtime about the shell. diff --git a/src/lib/builtins/conditionals.rs b/src/lib/builtins/conditionals.rs deleted file mode 100644 index 9f21e199..00000000 --- a/src/lib/builtins/conditionals.rs +++ /dev/null @@ -1,31 +0,0 @@ -use shell::{status::*, Shell}; - -macro_rules! string_function { - ($method:tt) => { - pub(crate) fn $method(args: &[String], _: &mut Shell) -> i32 { - match args.len() { - 0...2 => { - eprintln!("ion: {}: two arguments must be supplied", args[0]); - return BAD_ARG; - } - 3 => if args[1].$method(&args[2]) { - SUCCESS - } else { - FAILURE - }, - _ => { - for arg in args[2..].iter() { - if args[1].$method(arg) { - return SUCCESS; - } - } - FAILURE - } - } - } - }; -} - -string_function!(starts_with); -string_function!(ends_with); -string_function!(contains); diff --git a/src/lib/builtins/ion.rs b/src/lib/builtins/ion.rs deleted file mode 100644 index f2c5565a..00000000 --- a/src/lib/builtins/ion.rs +++ /dev/null @@ -1,23 +0,0 @@ -use shell::{status::*, Shell}; -use std::path::Path; - -use std::process::Command; - -const DOCPATH: &str = "/usr/share/ion/docs/index.html"; - -pub(crate) fn ion_docs(_: &[String], shell: &mut Shell) -> i32 { - if !Path::new(DOCPATH).exists() { - eprintln!("ion: ion shell documentation is not installed"); - return FAILURE; - } - - if let Some(cmd) = shell.get_var("BROWSER") { - if Command::new(&cmd).arg(DOCPATH).spawn().is_ok() { - return SUCCESS; - } - } else { - eprintln!("ion: BROWSER variable isn't defined"); - } - - FAILURE -} diff --git a/src/lib/builtins/man_pages.rs b/src/lib/builtins/man_pages.rs index 11dd2349..b0cabcd7 100644 --- a/src/lib/builtins/man_pages.rs +++ b/src/lib/builtins/man_pages.rs @@ -1,29 +1,14 @@ -use std::{ - error::Error, io::{stdout, Write}, -}; - -pub(crate) fn print_man(man_page: &'static str) { - let stdout = stdout(); - let mut stdout = stdout.lock(); - match stdout - .write_all(man_page.as_bytes()) - .and_then(|_| stdout.flush()) - { - Ok(_) => (), - Err(err) => panic!("{}", err.description().to_owned()), - } -} - pub(crate) fn check_help(args: &[String], man_page: &'static str) -> bool { for arg in args { if &**arg == "-h" || &**arg == "--help" { - print_man(man_page); + println!("{}", man_page); return true; } } false } + pub(crate) const MAN_STATUS: &str = r#"NAME status - Evaluates the current runtime status @@ -39,8 +24,7 @@ OPTIONS -i returns true if the shell is interactive. Also --is-interactive. -f - prints the filename of the currently running script or else stdio. Also --current-filename. -"#; + prints the filename of the currently running script or else stdio. Also --current-filename."#; pub(crate) const MAN_CD: &str = r#"NAME cd - Change directory. @@ -52,7 +36,6 @@ DESCRIPTION Without arguments cd changes the working directory to your home directory. With arguments cd changes the working directory to the directory you provided. - "#; pub(crate) const MAN_BOOL: &str = r#"NAME @@ -62,8 +45,7 @@ SYNOPSIS bool VALUE DESCRIPTION - Returns true if the value given to it is equal to '1' or 'true'. -"#; + Returns true if the value given to it is equal to '1' or 'true'."#; pub(crate) const MAN_IS: &str = r#"NAME is - Checks if two arguments are the same @@ -76,8 +58,7 @@ DESCRIPTION OPTIONS not - returns 0 if the two arguments are not equal. -"#; + returns 0 if the two arguments are not equal."#; pub(crate) const MAN_ISATTY: &str = r#" isatty - Checks if argument is a file descriptor @@ -86,8 +67,7 @@ SYNOPSIS isatty [FD] DESCRIPTION - Returns 0 exit status if the supplied file descriptor is a tty. -"#; + Returns 0 exit status if the supplied file descriptor is a tty."#; pub(crate) const MAN_DIRS: &str = r#"NAME dirs - prints the directory stack @@ -96,8 +76,7 @@ SYNOPSIS dirs DESCRIPTION - dirs prints the current directory stack. -"#; + dirs prints the current directory stack."#; pub(crate) const MAN_PUSHD: &str = r#"NAME pushd - push a directory to the directory stack @@ -106,8 +85,7 @@ SYNOPSIS pushd DIRECTORY DESCRIPTION - pushd pushes a directory to the directory stack. -"#; + pushd pushes a directory to the directory stack."#; pub(crate) const MAN_POPD: &str = r#"NAME popd - shift through the directory stack @@ -116,9 +94,8 @@ SYNOPSIS popd DESCRIPTION - popd removes the top directory from the directory stack and changes the working directory to the new top directory. - pushd adds directories to the stack. -"#; + popd removes the top directory from the directory stack and changes the working directory to the new top directory. + pushd adds directories to the stack."#; // pub(crate) const MAN_FN: &str = r#"NAME // fn - print a list of all functions or create a function @@ -146,7 +123,7 @@ DESCRIPTION // end // // example 1 -// "#; +//"#; pub(crate) const MAN_READ: &str = r#"NAME read - read a line of input into some variables @@ -155,8 +132,7 @@ SYNOPSIS read VARIABLES... DESCRIPTION - For each variable reads from standard input and stores the results in the variable. -"#; + For each variable reads from standard input and stores the results in the variable."#; pub(crate) const MAN_DROP: &str = r#"NAME drop - delete some variables or arrays @@ -170,8 +146,7 @@ DESCRIPTION OPTIONS -a - Instead of deleting variables deletes arrays. -"#; + Instead of deleting variables deletes arrays."#; pub(crate) const MAN_SET: &str = r#"NAME set - Set or unset values of shell options and positional parameters. @@ -194,8 +169,7 @@ OPTIONS If no argument are supplied, arguments will be unset. - Following arguments will be set as positional arguments in the shell. - If no arguments are suppled, arguments will not be unset. -"#; + If no arguments are suppled, arguments will not be unset."#; pub(crate) const MAN_EQ: &str = r#"NAME eq - Checks if two arguments are the same @@ -208,8 +182,7 @@ DESCRIPTION OPTIONS not - returns 0 if the two arguments are not equal. -"#; + returns 0 if the two arguments are not equal."#; pub(crate) const MAN_EVAL: &str = r#"NAME eval - evaluates the specified commands @@ -219,8 +192,7 @@ SYNOPSIS DESCRIPTION eval evaluates the given arguments as a command. If more than one argument is given, - all arguments are joined using a space as a separator. -"#; + all arguments are joined using a space as a separator."#; pub(crate) const MAN_EXEC: &str = r#"NAME exec - Replace the shell with the given command. @@ -234,8 +206,7 @@ DESCRIPTION <command>. OPTIONS - -c Execute command with an empty environment. -"#; + -c Execute command with an empty environment."#; pub(crate) const MAN_HISTORY: &str = r#"NAME history - print command history @@ -244,8 +215,7 @@ SYNOPSIS history DESCRIPTION - Prints the command history. -"#; + Prints the command history."#; pub(crate) const MAN_SOURCE: &str = r#"NAME source - evaluates given file @@ -254,9 +224,8 @@ SYNOPSIS source FILEPATH DESCRIPTION - Evaluates the commands in a specified file in the current shell. All changes in shell - variables will affect the current shell because of this. -"#; + Evaluates the commands in a specified file in the current shell. All changes in shell + variables will affect the current shell because of this."#; pub(crate) const MAN_ECHO: &str = r#"NAME echo - display a line of text @@ -286,113 +255,7 @@ OPTIONS \n new line \r carriage return \t horizontal tab (HT) - \v vertical tab (VT) -"#; - -pub(crate) const MAN_TEST: &str = r#"NAME - test - perform tests on files and text - -SYNOPSIS - test [EXPRESSION] - -DESCRIPTION - Tests the expressions given and returns an exit status of 0 if true, else 1. - -OPTIONS - -n STRING - the length of STRING is nonzero - - STRING - equivalent to -n STRING - - -z STRING - the length of STRING is zero - - STRING = STRING - the strings are equivalent - - STRING != STRING - the strings are not equal - - INTEGER -eq INTEGER - the integers are equal - - INTEGER -ge INTEGER - the first INTEGER is greater than or equal to the first INTEGER - - INTEGER -gt INTEGER - the first INTEGER is greater than the first INTEGER - - INTEGER -le INTEGER - the first INTEGER is less than or equal to the first INTEGER - - INTEGER -lt INTEGER - the first INTEGER is less than the first INTEGER - - INTEGER -ne INTEGER - the first INTEGER is not equal to the first INTEGER - - FILE -ef FILE - both files have the same device and inode numbers - - FILE -nt FILE - the first FILE is newer than the second FILE - - FILE -ot FILE - the first file is older than the second FILE - - -b FILE - FILE exists and is a block device - - -c FILE - FILE exists and is a character device - - -d FILE - FILE exists and is a directory - - -e FILE - FILE exists - - -f FILE - FILE exists and is a regular file - - -h FILE - FILE exists and is a symbolic link (same as -L) - - -L FILE - FILE exists and is a symbolic link (same as -h) - - -r FILE - FILE exists and read permission is granted - - -s FILE - FILE exists and has a file size greater than zero - - -S FILE - FILE exists and is a socket - - -w FILE - FILE exists and write permission is granted - - -x FILE - FILE exists and execute (or search) permission is granted - -EXAMPLES - Test if the file exists: - test -e FILE && echo "The FILE exists" || echo "The FILE does not exist" - - Test if the file exists and is a regular file, and if so, write to it: - test -f FILE && echo "Hello, FILE" >> FILE || echo "Cannot write to a directory" - - Test if 10 is greater than 5: - test 10 -gt 5 && echo "10 is greater than 5" || echo "10 is not greater than 5" - - Test if the user is running a 64-bit OS (POSIX environment only): - test $(getconf LONG_BIT) = 64 && echo "64-bit OS" || echo "32-bit OS" - -AUTHOR - Written by Michael Murphy. -"#; + \v vertical tab (VT)"#; pub(crate) const MAN_RANDOM: &str = r#"NAME random - generate a random number @@ -403,9 +266,8 @@ SYNOPSIS DESCRIPTION random generates a pseudo-random integer. IT IS NOT SECURE. - The range depends on what arguments you pass. If no arguments are given the range is [0, 32767]. - If two arguments are given the range is [START, END]. -"#; + The range depends on what arguments you pass. If no arguments are given the range is [0, 32767]. + If two arguments are given the range is [START, END]."#; pub(crate) const MAN_TRUE: &str = r#"NAME true - does nothing successfully @@ -414,8 +276,7 @@ SYNOPSIS true DESCRIPTION - Sets the exit status to 0. -"#; + Sets the exit status to 0."#; pub(crate) const MAN_FALSE: &str = r#"NAME false - does nothing unsuccessfully @@ -424,8 +285,7 @@ SYNOPSIS false DESCRIPTION - Sets the exit status to 1. -"#; + Sets the exit status to 1."#; pub(crate) const MAN_JOBS: &str = r#"NAME jobs - list all jobs running in the background @@ -434,8 +294,7 @@ SYNOPSIS jobs DESCRIPTION - Prints a list of all jobs running in the background. -"#; + Prints a list of all jobs running in the background."#; pub(crate) const MAN_BG: &str = r#"NAME bg - sends jobs to background @@ -444,8 +303,7 @@ SYNOPSIS bg PID DESCRIPTION - bg sends the job to the background resuming it if it has stopped. -"#; + bg sends the job to the background resuming it if it has stopped."#; pub(crate) const MAN_FG: &str = r#"NAME fg - bring job to foreground @@ -454,8 +312,7 @@ SYNOPSIS fg PID DESCRIPTION - fg brings the specified job to foreground resuming it if it has stopped. -"#; + fg brings the specified job to foreground resuming it if it has stopped."#; pub(crate) const MAN_SUSPEND: &str = r#"NAME suspend - suspend the current shell @@ -464,9 +321,8 @@ SYNOPSIS suspend DESCRIPTION - Suspends the current shell by sending it the SIGTSTP signal, - returning to the parent process. It can be resumed by sending it SIGCONT. -"#; + Suspends the current shell by sending it the SIGTSTP signal, + returning to the parent process. It can be resumed by sending it SIGCONT."#; pub(crate) const MAN_DISOWN: &str = r#"NAME disown - Disown processes @@ -480,8 +336,7 @@ DESCRIPTION OPTIONS -r Remove all running jobs from the background process list. -h Specifies that each job supplied will not receive the SIGHUP signal when the shell receives a SIGHUP. - -a If no job IDs were supplied, remove all jobs from the background process list. -"#; + -a If no job IDs were supplied, remove all jobs from the background process list."#; pub(crate) const MAN_EXIT: &str = r#"NAME exit - exit the shell @@ -490,8 +345,7 @@ SYNOPSIS exit DESCRIPTION - Makes ion exit. The exit status will be that of the last command executed. -"#; + Makes ion exit. The exit status will be that of the last command executed."#; pub(crate) const MAN_MATCHES: &str = r#"NAME matches - checks if the second argument contains any portion of the first. @@ -507,8 +361,7 @@ EXAMPLES Returns true: matches xs x Returns false: - matches x xs -"#; + matches x xs"#; pub(crate) const MAN_EXISTS: &str = r#"NAME exists - check whether items exist @@ -564,16 +417,14 @@ EXAMPLES AUTHOR Written by Fabian Würfl. - Heavily based on implementation of the test builtin, which was written by Michael Murph. -"#; + Heavily based on implementation of the test builtin, which was written by Michael Murph."#; pub(crate) const MAN_WHICH: &str = r#"NAME which - locate a program file in the current user's path SYNOPSIS - which PROGRAM + which PROGRAM DESCRIPTION - The which utility takes a list of command names and searches for the - alias/builtin/function/executable that would be executed if you ran that command. -"#; + The which utility takes a list of command names and searches for the + alias/builtin/function/executable that would be executed if you ran that command."#; diff --git a/src/lib/builtins/mod.rs b/src/lib/builtins/mod.rs index abe61c8d..4b7a9bf0 100644 --- a/src/lib/builtins/mod.rs +++ b/src/lib/builtins/mod.rs @@ -1,25 +1,21 @@ -pub mod calc; pub mod functions; -pub mod random; pub mod source; pub mod variables; mod command_info; -mod conditionals; -mod echo; mod exec; mod exists; -mod ion; mod is; mod job_control; mod man_pages; mod set; mod status; -mod test; + +use ion_builtins::{calc, conditionals, echo, random, test}; use self::{ - command_info::*, conditionals::{contains, ends_with, starts_with}, echo::echo, exec::exec, - exists::exists, functions::fn_, ion::ion_docs, is::is, man_pages::*, source::source, + command_info::*, echo::echo, exec::exec, + exists::exists, functions::fn_, is::is, man_pages::*, source::source, status::status, test::test, variables::{alias, drop_alias, drop_array, drop_variable}, }; @@ -83,7 +79,6 @@ pub const BUILTINS: &BuiltinMap = &map!( "fn" => builtin_fn : "Print list of functions", "help" => builtin_help : HELP_DESC, "history" => builtin_history : "Display a log of all commands previously executed", - "ion-docs" => ion_docs : "Opens the Ion manual", "is" => builtin_is : "Simple alternative to == and !=", "isatty" => builtin_isatty : "Returns 0 exit status if the supplied FD is a tty", "jobs" => builtin_jobs : "Displays all jobs that are attached to the background", @@ -136,6 +131,10 @@ impl BuiltinMap { } } +fn starts_with(args: &[String], _: &mut Shell) -> i32 { conditionals::starts_with(args) } +fn ends_with(args: &[String], _: &mut Shell) -> i32 { conditionals::ends_with(args) } +fn contains(args: &[String], _: &mut Shell) -> i32 { conditionals::contains(args) } + // Definitions of simple builtins go here fn builtin_status(args: &[String], shell: &mut Shell) -> i32 { match status(args, shell) { @@ -199,8 +198,8 @@ fn builtin_bool(args: &[String], shell: &mut Shell) -> i32 { _ => match &*args[1] { "1" => (), "true" => (), - "--help" => print_man(MAN_BOOL), - "-h" => print_man(MAN_BOOL), + "--help" => println!("{}", MAN_BOOL), + "-h" => println!("{}", MAN_BOOL), _ => return FAILURE, }, } @@ -453,7 +452,7 @@ fn builtin_suspend(args: &[String], _: &mut Shell) -> i32 { fn builtin_disown(args: &[String], shell: &mut Shell) -> i32 { for arg in args { if *arg == "--help" { - print_man(MAN_DISOWN); + println!("{}", MAN_DISOWN); return SUCCESS; } } diff --git a/src/lib/builtins/status.rs b/src/lib/builtins/status.rs index 0838f894..3063f716 100644 --- a/src/lib/builtins/status.rs +++ b/src/lib/builtins/status.rs @@ -1,4 +1,4 @@ -use builtins::man_pages::{print_man, MAN_STATUS}; +use builtins::man_pages::{MAN_STATUS}; use shell::Shell; use std::env; @@ -69,7 +69,7 @@ pub(crate) fn status(args: &[String], shell: &mut Shell) -> Result<(), String> { } if flags.contains(Flags::HELP) { - print_man(MAN_STATUS); + println!("{}", MAN_STATUS); } } Ok(()) diff --git a/src/lib/builtins/time.rs b/src/lib/builtins/time.rs deleted file mode 100644 index 5b73b28a..00000000 --- a/src/lib/builtins/time.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::error::Error; -use std::io::{Write, stdout}; -use std::process::Command; -use std::time::Instant; - -const MAN_PAGE: &'static str = r#"NAME - time - timer for commands - -SYNOPSIS - time [ -h | --help ][COMMAND] [ARGUEMENT]... - -DESCRIPTION - Runs the command taken as the first arguement and outputs the time the command took to execute. - -OPTIONS - -h - --help - display this help and exit -"#; - -pub(crate) fn time(args: &[&str]) -> Result<(), String> { - let stdout = stdout(); - let mut stdout = stdout.lock(); - - for arg in args { - if *arg == "-h" || *arg == "--help" { - return match stdout.write_all(MAN_PAGE.as_bytes()).and_then( - |_| stdout.flush(), - ) { - Ok(_) => Ok(()), - Err(err) => Err(err.description().to_owned()), - }; - } - } - - let time = Instant::now(); - - if !args.is_empty() { - let mut command = Command::new(&args[0]); - for arg in &args[1..] { - command.arg(arg); - } - command.spawn().and_then(|mut child| child.wait()).map_err( - |err| { - format!("time: {:?}", err) - }, - )?; - } - - let duration = time.elapsed(); - let seconds = duration.as_secs(); - let nanoseconds = duration.subsec_nanos(); - - if seconds > 60 { - write!(stdout, "real {}m{:02}.{:09}s\n", seconds / 60, seconds % 60, nanoseconds) - .map_err(|x| x.description().to_owned())?; - } else { - write!(stdout, "real {}.{:09}s\n", seconds, nanoseconds) - .map_err(|x| x.description().to_owned())?; - } - - Ok(()) -} diff --git a/src/lib/lib.rs b/src/lib/lib.rs index e98fe96a..731ea13c 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -31,6 +31,7 @@ extern crate unicode_segmentation; extern crate xdg; pub extern crate ion_sys as sys; +extern crate ion_builtins; #[macro_use] mod types; -- GitLab