diff --git a/src/expand.rs b/src/expand.rs index 7c694f1..a7197a5 100644 --- a/src/expand.rs +++ b/src/expand.rs @@ -803,7 +803,7 @@ pub fn expand_cmd_sub(raw: &str) -> ShResult { flog!(DEBUG, "filling buffer"); io_buf.fill_buffer()?; flog!(DEBUG, "done"); - Ok(io_buf.as_str()?.trim().to_string()) + Ok(io_buf.as_str()?.trim_end().to_string()) } _ => Err(ShErr::simple(ShErrKind::InternalErr, "Command sub failed")), } @@ -1615,7 +1615,7 @@ pub fn format_cmd_runtime(dur: std::time::Duration) -> String { let string = format!("{}s", seconds); result.push(string); } - if millis > 0 { + if result.is_empty() && millis > 0 { let string = format!("{}ms", millis); result.push(string); } @@ -1780,13 +1780,13 @@ pub fn expand_prompt(raw: &str) -> ShResult { PromptTk::Text(txt) => result.push_str(&txt), PromptTk::AnsiSeq(params) => result.push_str(¶ms), PromptTk::RuntimeMillis => { - if let Some(runtime) = write_meta(|m| m.stop_timer()) { + if let Some(runtime) = write_meta(|m| m.get_time()) { let runtime_millis = runtime.as_millis().to_string(); result.push_str(&runtime_millis); } } PromptTk::RuntimeFormatted => { - if let Some(runtime) = write_meta(|m| m.stop_timer()) { + if let Some(runtime) = write_meta(|m| m.get_time()) { let runtime_fmt = format_cmd_runtime(runtime); result.push_str(&runtime_fmt); } diff --git a/src/main.rs b/src/main.rs index 0b0fccd..c00cbf3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ use crate::libsh::sys::TermiosGuard; use crate::parse::execute::exec_input; use crate::prelude::*; use crate::signal::{QUIT_CODE, check_signals, sig_setup, signals_pending}; -use crate::state::source_rc; +use crate::state::{source_rc, write_meta}; use clap::Parser; use shopt::FernEditMode; use state::{read_vars, write_shopts, write_vars}; @@ -178,6 +178,7 @@ fn fern_interactive() { } }; + write_meta(|m| m.start_timer()); if let Err(e) = exec_input(input, None) { match e.kind() { ShErrKind::CleanExit(code) => { @@ -189,5 +190,6 @@ fn fern_interactive() { } } } + write_meta(|m| m.stop_timer()); } } diff --git a/src/parse/execute.rs b/src/parse/execute.rs index 0e4dd31..449f4eb 100644 --- a/src/parse/execute.rs +++ b/src/parse/execute.rs @@ -117,7 +117,6 @@ impl ExecArgs { } pub fn exec_input(input: String, io_stack: Option) -> ShResult<()> { - write_meta(|m| m.start_timer()); let log_tab = read_logic(|l| l.clone()); let input = expand_aliases(input, HashSet::new(), &log_tab); let mut parser = ParsedSrc::new(Arc::new(input)); @@ -471,6 +470,7 @@ impl Dispatcher { cond_frame.extend(in_redirs); // Condition gets input redirs body_frame.extend(out_redirs); // Body gets output redirs + let mut matched = false; for node in cond_nodes { let CondNode { cond, body } = node; self.io_stack.push(cond_frame.clone()); @@ -482,16 +482,18 @@ impl Dispatcher { match state::get_status() { 0 => { + matched = true; for body_node in body { self.io_stack.push(body_frame.clone()); self.dispatch_node(body_node)?; } + break; // Don't check remaining elif conditions } _ => continue, } } - if !else_block.is_empty() { + if !matched && !else_block.is_empty() { for node in else_block { self.io_stack.push(body_frame.clone()); self.dispatch_node(node)?; diff --git a/src/procio.rs b/src/procio.rs index 694ed19..d9f5bb8 100644 --- a/src/procio.rs +++ b/src/procio.rs @@ -19,7 +19,11 @@ use crate::{ pub enum IoMode { Fd { tgt_fd: RawFd, - src_fd: Arc, + src_fd: RawFd, // Just the fd number - dup2 will handle it at execution time + }, + OpenedFile { + tgt_fd: RawFd, + file: Arc, // Owns the opened file descriptor }, File { tgt_fd: RawFd, @@ -38,7 +42,7 @@ pub enum IoMode { impl IoMode { pub fn fd(tgt_fd: RawFd, src_fd: RawFd) -> Self { - let src_fd = unsafe { OwnedFd::from_raw_fd(src_fd).into() }; + // Just store the fd number - dup2 will use it directly at execution time Self::Fd { tgt_fd, src_fd } } pub fn file(tgt_fd: RawFd, path: PathBuf, mode: RedirType) -> Self { @@ -50,26 +54,28 @@ impl IoMode { } pub fn tgt_fd(&self) -> RawFd { match self { - IoMode::Fd { tgt_fd, .. } | IoMode::File { tgt_fd, .. } | IoMode::Pipe { tgt_fd, .. } => { - *tgt_fd - } + IoMode::Fd { tgt_fd, .. } + | IoMode::OpenedFile { tgt_fd, .. } + | IoMode::File { tgt_fd, .. } + | IoMode::Pipe { tgt_fd, .. } => *tgt_fd, _ => panic!(), } } pub fn src_fd(&self) -> RawFd { match self { - IoMode::Fd { tgt_fd: _, src_fd } => src_fd.as_raw_fd(), + IoMode::Fd { src_fd, .. } => *src_fd, + IoMode::OpenedFile { file, .. } => file.as_raw_fd(), IoMode::File { .. } => panic!("Attempted to obtain src_fd from file before opening"), - IoMode::Pipe { tgt_fd: _, pipe } => pipe.as_raw_fd(), + IoMode::Pipe { pipe, .. } => pipe.as_raw_fd(), _ => panic!(), } } pub fn open_file(mut self) -> ShResult { if let IoMode::File { tgt_fd, path, mode } = self { let file = get_redir_file(mode, path)?; - self = IoMode::Fd { + self = IoMode::OpenedFile { tgt_fd, - src_fd: Arc::new(OwnedFd::from(file)), + file: Arc::new(OwnedFd::from(file)), } } Ok(self) diff --git a/src/state.rs b/src/state.rs index b6d54af..bc22e7d 100644 --- a/src/state.rs +++ b/src/state.rs @@ -57,6 +57,15 @@ pub enum ShellParam { ArgCount } +impl ShellParam { + pub fn is_global(&self) -> bool { + matches!( + self, + Self::Status | Self::ShPid | Self::LastJob | Self::ShellName + ) + } +} + impl Display for ShellParam { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -158,6 +167,9 @@ impl ScopeStack { return true; } } + if let Ok(param) = var_name.parse::() { + return self.global_params.contains_key(¶m.to_string()); + } false } pub fn flatten_vars(&self) -> HashMap { @@ -187,6 +199,9 @@ impl ScopeStack { } } pub fn get_var(&self, var_name: &str) -> String { + if let Ok(param) = var_name.parse::() { + return self.get_param(param); + } for scope in self.scopes.iter().rev() { if scope.var_exists(var_name) { return scope.get_var(var_name); @@ -196,6 +211,9 @@ impl ScopeStack { std::env::var(var_name).unwrap_or_default() } pub fn get_param(&self, param: ShellParam) -> String { + if param.is_global() && let Some(val) = self.global_params.get(¶m.to_string()) { + return val.clone(); + } for scope in self.scopes.iter().rev() { let val = scope.get_param(param); if !val.is_empty() { @@ -637,6 +655,7 @@ impl VarTab { } } pub fn var_exists(&self, var_name: &str) -> bool { + flog!(DEBUG, "checking existence of {}",var_name); if let Ok(param) = var_name.parse::() { return self.params.contains_key(¶m); } @@ -674,6 +693,7 @@ impl VarTab { #[derive(Default, Debug)] pub struct MetaTab { runtime_start: Option, + runtime_stop: Option, } impl MetaTab { @@ -683,11 +703,16 @@ impl MetaTab { pub fn start_timer(&mut self) { self.runtime_start = Some(Instant::now()); } - pub fn stop_timer(&mut self) -> Option { - self - .runtime_start - .map(|start| start.elapsed()) // return the duration, if any + pub fn stop_timer(&mut self) { + self.runtime_stop = Some(Instant::now()); } + pub fn get_time(&self) -> Option { + if let (Some(start), Some(stop)) = (self.runtime_start, self.runtime_stop) { + Some(stop.duration_since(start)) + } else { + None + } + } } /// Read from the job table