1 use super::Status;
2 use crate as ion_shell;
3 use crate::{shell::Shell, types};
4 use builtins_proc::builtin;
5 
6 // TODO: Add support for multiple name in builtins man
7 #[builtin(
8     names = "eq, is",
9     desc = "checks if two arguments are the same",
10     man = "
11 SYNOPSIS
12     is [ -h | --help ] [not]
13 
14 DESCRIPTION
15     Returns 0 if the two arguments are equal
16 
17 OPTIONS
18     not
19         returns 0 if the two arguments are not equal."
20 )]
is(args: &[types::Str], shell: &mut Shell<'_>) -> Status21 pub fn is(args: &[types::Str], shell: &mut Shell<'_>) -> Status {
22     match args.len() {
23         4 => {
24             if args[1] != "not" {
25                 return Status::error(format!("Expected 'not' instead found '{}'", args[1]));
26             } else if eval_arg(&*args[2], shell) == eval_arg(&*args[3], shell) {
27                 return Status::error("");
28             }
29         }
30         3 => {
31             if eval_arg(&*args[1], shell) != eval_arg(&*args[2], shell) {
32                 return Status::error("");
33             }
34         }
35         _ => return Status::error("is needs 3 or 4 arguments"),
36     }
37 
38     Status::SUCCESS
39 }
40 
eval_arg(arg: &str, shell: &mut Shell<'_>) -> types::Str41 fn eval_arg(arg: &str, shell: &mut Shell<'_>) -> types::Str {
42     if let Some(value) = get_var_string(arg, shell) {
43         value
44     } else {
45         arg.into()
46     }
47 }
48 
49 // On error returns an empty String.
get_var_string(name: &str, shell: &mut Shell<'_>) -> Option<types::Str>50 fn get_var_string(name: &str, shell: &mut Shell<'_>) -> Option<types::Str> {
51     if name.chars().nth(0)? != '$' {
52         return None;
53     }
54 
55     match shell.variables().get_str(&name[1..]) {
56         Ok(s) => Some(s),
57         Err(why) => {
58             eprintln!("{}", why);
59             None
60         }
61     }
62 }
63 
64 #[test]
test_is()65 fn test_is() {
66     fn vec_string(args: &[&str]) -> Vec<types::Str> { args.iter().map(|&s| s.into()).collect() }
67     let mut shell = Shell::default();
68     shell.variables_mut().set("x", "value");
69     shell.variables_mut().set("y", "0");
70 
71     // Four arguments
72     assert!(builtin_is(&vec_string(&["is", " ", " ", " "]), &mut shell).is_failure());
73     assert!(builtin_is(&vec_string(&["is", "not", " ", " "]), &mut shell).is_failure());
74     assert!(builtin_is(&vec_string(&["is", "not", "$x", "$x"]), &mut shell).is_failure());
75     assert!(builtin_is(&vec_string(&["is", "not", "2", "1"]), &mut shell).is_success());
76     assert!(builtin_is(&vec_string(&["is", "not", "$x", "$y"]), &mut shell).is_success());
77 
78     // Three arguments
79     assert!(builtin_is(&vec_string(&["is", "1", "2"]), &mut shell).is_failure());
80     assert!(builtin_is(&vec_string(&["is", "$x", "$y"]), &mut shell).is_failure());
81     assert!(builtin_is(&vec_string(&["is", " ", " "]), &mut shell).is_success());
82     assert!(builtin_is(&vec_string(&["is", "$x", "$x"]), &mut shell).is_success());
83 
84     // Two arguments
85     assert!(builtin_is(&vec_string(&["is", " "]), &mut shell).is_failure());
86 
87     // One argument
88     assert!(builtin_is(&vec_string(&["is"]), &mut shell).is_failure());
89 }
90