Commit 4e5ec035 authored by Michael Aaron Murphy's avatar Michael Aaron Murphy
Browse files

Make an ion_builtins workspace member

parent 9d2fc714
......@@ -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"
......
......@@ -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]
......
[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"
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() {
......
use shell::{status::*, Shell};
macro_rules! string_function {
($method:tt) => {
pub(crate) fn $method(args: &[String], _: &mut Shell) -> i32 {
pub fn $method(args: &[String]) -> 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
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 }
}
}
};
......
......@@ -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);
......
#[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;
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),
......
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) => {
......
# 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.
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
}
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