Skip to content

Commit

Permalink
Pass the test
Browse files Browse the repository at this point in the history
  • Loading branch information
ryuichiueda committed Jan 18, 2025
1 parent e799d67 commit de6ab40
Show file tree
Hide file tree
Showing 24 changed files with 260 additions and 81 deletions.
39 changes: 20 additions & 19 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ type BuiltinFunc = fn(&mut ShellCore, &mut [String]) -> i32;

#[derive(Default)]
pub struct ShellCore {
pub data: Data,
pub flags: String,
pub db: Data,
rewritten_history: HashMap<usize, String>,
pub history: Vec<String>,
pub builtins: HashMap<String, BuiltinFunc>,
Expand All @@ -52,31 +53,31 @@ impl ShellCore {
core.set_builtins();

if is_interactive() {
core.data.flags += "i";
core.flags += "i";
let fd = fcntl::fcntl(2, fcntl::F_DUPFD_CLOEXEC(255))
.expect("sush(fatal): Can't allocate fd for tty FD");
core.tty_fd = Some(unsafe{OwnedFd::from_raw_fd(fd)});
}

let home = core.data.get_param("HOME").to_string();
core.data.set_param("HISTFILE", &(home + "/.sush_history"));
core.data.set_param("HISTFILESIZE", "2000");
let home = core.db.get_param("HOME").unwrap_or(String::new()).to_string();
core.db.set_param("HISTFILE", &(home + "/.sush_history"));
core.db.set_param("HISTFILESIZE", "2000");

core
}

fn set_initial_parameters(&mut self) {
self.data.set_param("$", &process::id().to_string());
self.data.set_param("BASHPID", &process::id().to_string());
self.data.set_param("BASH_SUBSHELL", "0");
self.data.set_param("?", "0");
self.data.set_param("PS1", "\\[\\033[01;36m\\]\\b\\[\\033[00m\\]\\[\\033[01;35m\\]\\w\\[\\033[00m\\](debug)🍣 ");
self.data.set_param("PS2", "> ");
self.data.set_param("HOME", &env::var("HOME").unwrap_or("/".to_string()));
self.db.set_param("$", &process::id().to_string());
self.db.set_param("BASHPID", &process::id().to_string());
self.db.set_param("BASH_SUBSHELL", "0");
self.db.set_param("?", "0");
self.db.set_param("PS1", "\\[\\033[01;36m\\]\\b\\[\\033[00m\\]\\[\\033[01;35m\\]\\w\\[\\033[00m\\](debug)🍣 ");
self.db.set_param("PS2", "> ");
self.db.set_param("HOME", &env::var("HOME").unwrap_or("/".to_string()));
}

pub fn has_flag(&self, flag: char) -> bool {
self.data.flags.find(flag).is_some()
self.flags.find(flag).is_some()
}

pub fn wait_process(&mut self, child: Pid) {
Expand All @@ -100,7 +101,7 @@ impl ShellCore {
if exit_status == 130 {
self.sigint.store(true, Relaxed);
}
self.data.parameters.insert("?".to_string(), exit_status.to_string()); //追加
self.db.parameters.insert("?".to_string(), exit_status.to_string()); //追加
}

fn set_foreground(&self) {
Expand Down Expand Up @@ -143,16 +144,16 @@ impl ShellCore {

let func = self.builtins[&args[0]];
let status = func(self, args);
self.data.parameters.insert("?".to_string(), status.to_string());
self.db.parameters.insert("?".to_string(), status.to_string());
true
}

fn set_subshell_parameters(&mut self) {
let pid = nix::unistd::getpid();
self.data.parameters.insert("BASHPID".to_string(), pid.to_string());
match self.data.parameters["BASH_SUBSHELL"].parse::<usize>() {
Ok(num) => self.data.parameters.insert("BASH_SUBSHELL".to_string(), (num+1).to_string()),
Err(_) => self.data.parameters.insert("BASH_SUBSHELL".to_string(), "0".to_string()),
self.db.parameters.insert("BASHPID".to_string(), pid.to_string());
match self.db.parameters["BASH_SUBSHELL"].parse::<usize>() {
Ok(num) => self.db.parameters.insert("BASH_SUBSHELL".to_string(), (num+1).to_string()),
Err(_) => self.db.parameters.insert("BASH_SUBSHELL".to_string(), "0".to_string()),
};
}

Expand Down
2 changes: 1 addition & 1 deletion src/core/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ impl ShellCore {
pub fn exit(core: &mut ShellCore, args: &mut [String]) -> i32 {
eprintln!("exit");
if args.len() > 1 {
core.data.parameters.insert("?".to_string(), args[1].clone());
core.db.parameters.insert("?".to_string(), args[1].clone());
}
exit::normal(core)
}
Expand Down
6 changes: 3 additions & 3 deletions src/core/builtins/cd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn cd_1arg(core: &mut ShellCore, args: &mut [String]) -> i32 {
}

fn cd_oldpwd(core: &mut ShellCore, args: &mut [String]) -> i32 {
if let Some(old) = core.data.parameters.get("OLDPWD") {
if let Some(old) = core.db.parameters.get("OLDPWD") {
println!("{}", &old);
args[1] = old.to_string();
}else {
Expand All @@ -46,14 +46,14 @@ fn cd_oldpwd(core: &mut ShellCore, args: &mut [String]) -> i32 {

fn set_oldpwd(core: &mut ShellCore) {
if let Some(old) = core.get_current_directory() {
core.data.parameters.insert("OLDPWD".to_string(), old.display().to_string());
core.db.parameters.insert("OLDPWD".to_string(), old.display().to_string());
};
}

fn change_directory(core: &mut ShellCore, args: &mut [String]) -> i32 {
let path = utils::make_canonical_path(core, &args[1]);
if core.set_current_directory(&path).is_ok() {
core.data.parameters.insert("PWD".to_string(), path.display().to_string());
core.db.parameters.insert("PWD".to_string(), path.display().to_string());
0
}else{
eprintln!("sush: cd: {:?}: No such file or directory", &path);
Expand Down
2 changes: 1 addition & 1 deletion src/core/builtins/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn make_absolute_path(core: &mut ShellCore, path_str: &str) -> PathBuf {
}

if path.starts_with("~") { // tilde -> $HOME
if let Some(home_dir) = core.data.parameters.get("HOME") {
if let Some(home_dir) = core.db.parameters.get("HOME") {
absolute.push(PathBuf::from(home_dir));
if path_str.len() > 1 && path_str.starts_with("~/") {
absolute.push(PathBuf::from(&path_str[2..]));
Expand Down
21 changes: 12 additions & 9 deletions src/core/data.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
//SPDXFileCopyrightText: 2024 Ryuichi Ueda [email protected]
//SPDXLicense-Identifier: BSD-3-Clause

use crate::error::exec::ExecError;
use std::collections::HashMap;
use std::env;

#[derive(Debug, Default)]
pub struct Data {
pub flags: String,
pub parameters: HashMap<String, String>,
}

impl Data {
pub fn get_param(&mut self, key: &str) -> String {
if ! self.parameters.contains_key(key) {
if let Ok(val) = env::var(key) {
self.set_param(key, &val);
pub fn get_param(&mut self, name: &str) -> Result<String, ExecError> {
if ! self.parameters.contains_key(name) {
if let Ok(val) = env::var(name) {
self.set_param(name, &val)?;
}
}

match self.parameters.get(key) {
let ans = match self.parameters.get(name) {
Some(val) => val,
None => "",
}.to_string()
}.to_string();

Ok(ans)
}

pub fn set_param(&mut self, key: &str, val: &str) {
self.parameters.insert(key.to_string(), val.to_string());
pub fn set_param(&mut self, name: &str, val: &str) -> Result<(), ExecError> {
self.parameters.insert(name.to_string(), val.to_string());
Ok(())
}
}
40 changes: 21 additions & 19 deletions src/core/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,65 +2,66 @@
//SPDXLicense-Identifier: BSD-3-Clause

use crate::ShellCore;
use crate::error::exec::ExecError;
use rev_lines::RevLines;
use std::fs::File;
use std::io::{BufReader, BufWriter, Write};
use std::fs::OpenOptions;

impl ShellCore {
pub fn fetch_history(&mut self, pos: usize, prev: usize, prev_str: String) -> String {
pub fn fetch_history(&mut self, pos: usize, prev: usize, prev_str: String) -> Result<String, ExecError> {
if prev < self.history.len() {
self.history[prev] = prev_str;
}else{
self.rewritten_history.insert(prev + 1 - self.history.len(), prev_str);
}

if pos < self.history.len() {
let ans = if pos < self.history.len() {
self.history[pos].clone()
}else{
self.fetch_history_file(pos + 1 - self.history.len())
}
self.fetch_history_file(pos + 1 - self.history.len())?
};

Ok(ans)
}

pub fn fetch_history_file(&mut self, pos: usize) -> String {
pub fn fetch_history_file(&mut self, pos: usize) -> Result<String, ExecError> {
if let Some(s) = self.rewritten_history.get(&pos) {
return s.to_string();
return Ok(s.to_string());
}
if pos == 0 {
return String::new();
return Ok(String::new());
}

let mut file_line = pos - 1;
if let Ok(n) = self.data.get_param("HISTFILESIZE").parse::<usize>() {
if let Ok(n) = self.db.get_param("HISTFILESIZE")?.parse::<usize>() {
file_line %= n;
}

if let Ok(hist_file) = File::open(self.data.get_param("HISTFILE")){
if let Ok(hist_file) = File::open(self.db.get_param("HISTFILE")?){
let mut rev_lines = RevLines::new(BufReader::new(hist_file));
if let Some(Ok(s)) = rev_lines.nth(file_line) {
return s;
return Ok(s);
}
}

String::new()
Ok(String::new())
}

pub fn write_history_to_file(&mut self) {
if ! self.data.flags.contains('i') || self.is_subshell {
return;
pub fn write_history_to_file(&mut self) -> Result<(), ExecError> {
if ! self.flags.contains('i') || self.is_subshell {
return Ok(());
}
let filename = self.data.get_param("HISTFILE");
let filename = self.db.get_param("HISTFILE")?;
if filename.is_empty() {
eprintln!("sush: HISTFILE is not set");
return;
return Err(ExecError::Other("sush: HISTFILE is not set".to_string()));
}

let file = match OpenOptions::new().create(true)
.append(true).open(&filename) {
Ok(f) => f,
_ => {
eprintln!("sush: invalid history file");
return;
return Err(ExecError::Other("sush: invalid history file".to_string()));
},
};

Expand All @@ -73,5 +74,6 @@ impl ShellCore {
let _ = f.write(&[0x0A]);
}
let _ = f.flush();
Ok(())
}
}
2 changes: 1 addition & 1 deletion src/elements/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub trait Command {
if self.get_redirects().iter_mut().all(|r| r.connect(true, core)){
self.run(core, false);
}else{
core.data.set_param("?", "1");
core.db.set_param("?", "1");
}
self.get_redirects().iter_mut().rev().for_each(|r| r.restore());
}
Expand Down
2 changes: 1 addition & 1 deletion src/elements/command/if.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl Command for IfCommand {
fn run(&mut self, core: &mut ShellCore, _: bool) {
for i in 0..self.if_elif_scripts.len() {
self.if_elif_scripts[i].exec(core);
if core.data.get_param("?") == "0" {
if core.db.get_param("?").unwrap() == "0" {
self.then_scripts[i].exec(core);
return;
}
Expand Down
2 changes: 1 addition & 1 deletion src/elements/command/while.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ impl Command for WhileCommand {
.expect("SUSH INTERNAL ERROR (no script)")
.exec(core);

if core.data.get_param("?") != "0" {
if core.db.get_param("?").unwrap() != "0" {
break;
}

Expand Down
2 changes: 1 addition & 1 deletion src/elements/job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl Job {
let pids = pipeline.exec(core, pgid);
core.wait_pipeline(pids);
}
do_next = (core.data.get_param("?") == "0") == (end == "&&");
do_next = (core.db.get_param("?").unwrap() == "0") == (end == "&&");
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/elements/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub struct Pipeline {
impl Pipeline {
pub fn exec(&mut self, core: &mut ShellCore, pgid: Pid) -> Vec<Option<Pid>> {
if core.sigint.load(Relaxed) { //以下4行追加
core.data.set_param("?", "130");
core.db.set_param("?", "130");
return vec![];
}

Expand Down
2 changes: 1 addition & 1 deletion src/elements/script.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ impl Script {
Status::NormalEnd => return Some(ans),
Status::UnexpectedSymbol(s) => {
eprintln!("Unexpected token: {}", s);
core.data.set_param("?", "2");
core.db.set_param("?", "2");
break;
},
Status::NeedMoreLine => {
Expand Down
3 changes: 2 additions & 1 deletion src/elements/subword.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod single_quoted;
mod varname;

use crate::{Feeder, ShellCore};
use crate::error::exec::ExecError;
use std::fmt;
use self::escaped_char::EscapedChar;
use self::parameter::Parameter;
Expand Down Expand Up @@ -56,7 +57,7 @@ pub trait Subword {
fn get_text(&self) -> &str;
fn set_text(&mut self, _: &str) {}
fn boxed_clone(&self) -> Box<dyn Subword>;
fn substitute(&mut self, _: &mut ShellCore) -> Result<(), String> {Ok(())}
fn substitute(&mut self, _: &mut ShellCore) -> Result<(), ExecError> {Ok(())}

fn split(&self) -> Vec<Box<dyn Subword>>{
let f = |s| Box::new( SimpleSubword {text: s}) as Box<dyn Subword>;
Expand Down
5 changes: 3 additions & 2 deletions src/elements/subword/parameter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//SPDX-License-Identifier: BSD-3-Clause

use crate::{ShellCore, Feeder};
use crate::error::exec::ExecError;
use super::Subword;

#[derive(Debug, Clone)]
Expand All @@ -13,8 +14,8 @@ impl Subword for Parameter {
fn get_text(&self) -> &str {self.text.as_ref()}
fn boxed_clone(&self) -> Box<dyn Subword> {Box::new(self.clone())}

fn substitute(&mut self, core: &mut ShellCore) -> Result<(), String> {
let value = core.data.get_param(&self.text[1..]);
fn substitute(&mut self, core: &mut ShellCore) -> Result<(), ExecError> {
let value = core.db.get_param(&self.text[1..])?;
self.text = value.to_string();
Ok(())
}
Expand Down
11 changes: 6 additions & 5 deletions src/elements/word/tilde_expansion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
//SPDX-License-Identifier: BSD-3-Clause

use crate::ShellCore;
use crate::error::exec::ExecError;
use crate::elements::word::Word;
use nix::unistd::User;
use super::subword::simple::SimpleSubword;
Expand All @@ -17,8 +18,8 @@ pub fn eval(word: &mut Word, core: &mut ShellCore) {
.collect::<Vec<String>>()
.concat();

let value = get_value(&text, core);
if value.is_empty() {
let value = get_value(&text, core).unwrap_or(String::new());
if value == "" {
return;
}
word.subwords[0] = Box::new( SimpleSubword{ text: value } );
Expand All @@ -36,15 +37,15 @@ fn prefix_length(word: &Word) -> usize {
}
}

fn get_value(text: &str, core: &mut ShellCore) -> String {
fn get_value(text: &str, core: &mut ShellCore) -> Result<String, ExecError> {
let key = match text {
"" => "HOME",
"+" => "PWD",
"-" => "OLDPWD",
_ => return get_home_dir(text),
_ => return Ok(get_home_dir(text)),
};

core.data.get_param(key).to_string()
core.db.get_param(key)
}

fn get_home_dir(user: &str) -> String {
Expand Down
Loading

0 comments on commit de6ab40

Please sign in to comment.