Early work on scripting features
This commit is contained in:
@@ -1,20 +1,14 @@
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::{ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, state::write_vars};
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::{ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, state::{self, write_vars}};
|
||||
|
||||
use super::setup_builtin;
|
||||
|
||||
pub fn cd(node: Node, job: &mut JobBldr) -> ShResult<()> {
|
||||
let NdRule::Command { assignments: _, argv } = node.class else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let child = ChildProc::new(Pid::this(), Some("cd"), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
let (argv,_) = setup_builtin(argv,job,None)?;
|
||||
|
||||
let argv = prepare_argv(argv);
|
||||
let new_dir = if let Some((arg,_)) = argv.into_iter().skip(1).next() {
|
||||
PathBuf::from(arg)
|
||||
} else {
|
||||
@@ -25,5 +19,6 @@ pub fn cd(node: Node, job: &mut JobBldr) -> ShResult<()> {
|
||||
let new_dir = env::current_dir().unwrap();
|
||||
env::set_var("PWD", new_dir);
|
||||
|
||||
state::set_status(0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::ShResult, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, procio::{borrow_fd, IoStack}};
|
||||
use crate::{builtin::setup_builtin, jobs::{ChildProc, JobBldr}, libsh::error::ShResult, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, procio::{borrow_fd, IoStack}, state};
|
||||
|
||||
pub fn echo(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<()> {
|
||||
let NdRule::Command { assignments: _, argv } = node.class else {
|
||||
@@ -6,33 +6,22 @@ pub fn echo(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<(
|
||||
};
|
||||
assert!(!argv.is_empty());
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let child = ChildProc::new(Pid::this(), Some("echo"), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
|
||||
io_stack.append_to_frame(node.redirs);
|
||||
let mut io_frame = io_stack.pop_frame();
|
||||
|
||||
io_frame.redirect()?;
|
||||
let (argv,io_frame) = setup_builtin(argv, job, Some((io_stack,node.redirs)))?;
|
||||
|
||||
let stdout = borrow_fd(STDOUT_FILENO);
|
||||
flog!(DEBUG, argv);
|
||||
|
||||
let mut echo_output = prepare_argv(argv)
|
||||
.into_iter()
|
||||
let mut echo_output = argv.into_iter()
|
||||
.map(|a| a.0) // Extract the String from the tuple of (String,Span)
|
||||
.skip(1) // Skip 'echo'
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
echo_output.push('\n');
|
||||
flog!(DEBUG, echo_output);
|
||||
|
||||
write(stdout, echo_output.as_bytes())?;
|
||||
|
||||
io_frame.restore()?;
|
||||
io_frame.unwrap().restore()?;
|
||||
state::set_status(0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,32 +1,40 @@
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::{ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, NdRule, Node}, prelude::*};
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::{ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, procio::{borrow_fd, IoStack}, state};
|
||||
|
||||
pub fn export(node: Node, job: &mut JobBldr) -> ShResult<()> {
|
||||
use super::setup_builtin;
|
||||
|
||||
pub fn export(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<()> {
|
||||
let NdRule::Command { assignments: _, argv } = node.class else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
let (argv,io_frame) = setup_builtin(argv, job, Some((io_stack,node.redirs)))?;
|
||||
|
||||
if argv.is_empty() {
|
||||
// Display the environment variables
|
||||
let mut env_output = env::vars()
|
||||
.map(|var| format!("{}={}",var.0,var.1)) // Get all of them, zip them into one string
|
||||
.collect::<Vec<_>>();
|
||||
env_output.sort(); // Sort them alphabetically
|
||||
let mut env_output = env_output.join("\n"); // Join them with newlines
|
||||
env_output.push('\n'); // Push a final newline
|
||||
|
||||
let stdout = borrow_fd(STDOUT_FILENO);
|
||||
write(stdout, env_output.as_bytes())?; // Write it
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let child = ChildProc::new(Pid::this(), Some("export"), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
|
||||
let argv = prepare_argv(argv);
|
||||
|
||||
for (arg,span) in argv {
|
||||
let Some((var,val)) = arg.split_once('=') else {
|
||||
return Err(
|
||||
ShErr::full(
|
||||
ShErrKind::ExecFail,
|
||||
"Expected an assignment in export args",
|
||||
span.into()
|
||||
for (arg,span) in argv {
|
||||
let Some((var,val)) = arg.split_once('=') else {
|
||||
return Err(
|
||||
ShErr::full(
|
||||
ShErrKind::SyntaxErr,
|
||||
"export: Expected an assignment in export args",
|
||||
span.into()
|
||||
)
|
||||
)
|
||||
)
|
||||
};
|
||||
env::set_var(var, val);
|
||||
};
|
||||
env::set_var(var, val);
|
||||
}
|
||||
}
|
||||
io_frame.unwrap().restore()?;
|
||||
state::set_status(0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use crate::{jobs::{ChildProc, JobBldr, JobCmdFlags, JobID}, libsh::error::{ErrSpan, ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, lex::Span, NdRule, Node}, prelude::*, procio::{borrow_fd, IoStack}, state::{self, read_jobs, write_jobs}};
|
||||
|
||||
use super::setup_builtin;
|
||||
|
||||
pub enum JobBehavior {
|
||||
Foregound,
|
||||
Background
|
||||
@@ -11,22 +13,12 @@ pub fn continue_job(node: Node, job: &mut JobBldr, behavior: JobBehavior) -> ShR
|
||||
JobBehavior::Foregound => "fg",
|
||||
JobBehavior::Background => "bg"
|
||||
};
|
||||
let NdRule::Command { assignments, argv } = node.class else {
|
||||
let NdRule::Command { assignments: _, argv } = node.class else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let child = ChildProc::new(Pid::this(), Some(cmd), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
|
||||
let mut argv = prepare_argv(argv)
|
||||
.into_iter()
|
||||
.skip(1);
|
||||
let (argv,_) = setup_builtin(argv, job, None)?;
|
||||
let mut argv = argv.into_iter();
|
||||
|
||||
if read_jobs(|j| j.get_fg().is_some()) {
|
||||
return Err(
|
||||
@@ -145,28 +137,14 @@ fn parse_job_id(arg: &str, blame: Span) -> ShResult<usize> {
|
||||
}
|
||||
|
||||
pub fn jobs(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<()> {
|
||||
let NdRule::Command { assignments, argv } = node.class else {
|
||||
let NdRule::Command { assignments: _, argv } = node.class else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let child = ChildProc::new(Pid::this(), Some("jobs"), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
|
||||
let mut argv = prepare_argv(argv)
|
||||
.into_iter()
|
||||
.skip(1);
|
||||
|
||||
let mut io_frame = io_stack.pop_frame();
|
||||
io_frame.redirect()?;
|
||||
let (argv,io_frame) = setup_builtin(argv, job, Some((io_stack,node.redirs)))?;
|
||||
|
||||
let mut flags = JobCmdFlags::empty();
|
||||
while let Some((arg,span)) = argv.next() {
|
||||
for (arg,span) in argv {
|
||||
let mut chars = arg.chars().peekable();
|
||||
if chars.peek().is_none_or(|ch| *ch != '-') {
|
||||
return Err(
|
||||
@@ -198,7 +176,7 @@ pub fn jobs(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<(
|
||||
}
|
||||
}
|
||||
write_jobs(|j| j.print_jobs(flags))?;
|
||||
io_frame.restore()?;
|
||||
io_frame.unwrap().restore()?;
|
||||
state::set_status(0);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
use nix::unistd::Pid;
|
||||
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::ShResult, parse::{execute::prepare_argv, lex::{Span, Tk}, Redir}, procio::{IoFrame, IoStack}};
|
||||
|
||||
pub mod echo;
|
||||
pub mod cd;
|
||||
pub mod export;
|
||||
@@ -17,3 +21,55 @@ pub const BUILTINS: [&str;9] = [
|
||||
"fg",
|
||||
"bg"
|
||||
];
|
||||
|
||||
/// Sets up a builtin command
|
||||
///
|
||||
/// Prepares a builtin for execution by processing arguments, setting up redirections, and registering the command as a child process in the given `JobBldr`
|
||||
///
|
||||
/// # Parameters
|
||||
/// * argv - The vector of raw argument tokens
|
||||
/// * job - A mutable reference to a `JobBldr`
|
||||
/// * io_info - An optional 2-tuple consisting of a mutable reference to an `IoStack` and a vector of `Redirs`
|
||||
///
|
||||
/// # Behavior
|
||||
/// * Cleans, expands, and word splits the arg vector
|
||||
/// * Adds a new `ChildProc` to the job builder
|
||||
/// * Performs redirections, if any.
|
||||
///
|
||||
/// # Returns
|
||||
/// * The processed arg vector
|
||||
/// * The popped `IoFrame`, if any
|
||||
///
|
||||
/// # Notes
|
||||
/// * If redirections are given to this function, the caller must call `IoFrame.restore()` on the returned `IoFrame`
|
||||
/// * If redirections are given, the second field of the resulting tuple will *always* be `Some()`
|
||||
/// * If no redirections are given, the second field will *always* be `None`
|
||||
pub fn setup_builtin<'t>(
|
||||
argv: Vec<Tk<'t>>,
|
||||
job: &'t mut JobBldr,
|
||||
io_info: Option<(&mut IoStack,Vec<Redir>)>,
|
||||
) -> ShResult<(Vec<(String,Span<'t>)>, Option<IoFrame>)> {
|
||||
let mut argv: Vec<(String,Span)> = prepare_argv(argv);
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let cmd_name = argv.remove(0).0;
|
||||
let child = ChildProc::new(Pid::this(), Some(&cmd_name), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
|
||||
let io_frame = if let Some((io_stack,redirs)) = io_info {
|
||||
io_stack.append_to_frame(redirs);
|
||||
let mut io_frame = io_stack.pop_frame();
|
||||
io_frame.redirect()?;
|
||||
Some(io_frame)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// We return the io_frame because the caller needs to also call io_frame.restore()
|
||||
Ok((argv,io_frame))
|
||||
}
|
||||
|
||||
@@ -1,30 +1,21 @@
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::ShResult, parse::{NdRule, Node}, prelude::*, procio::{borrow_fd, IoStack}};
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::ShResult, parse::{NdRule, Node}, prelude::*, procio::{borrow_fd, IoStack}, state};
|
||||
|
||||
use super::setup_builtin;
|
||||
|
||||
pub fn pwd(node: Node, io_stack: &mut IoStack, job: &mut JobBldr) -> ShResult<()> {
|
||||
let NdRule::Command { assignments, argv } = node.class else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let child = ChildProc::new(Pid::this(), Some("pwd"), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
|
||||
io_stack.append_to_frame(node.redirs);
|
||||
let mut io_frame = io_stack.pop_frame();
|
||||
|
||||
io_frame.redirect()?;
|
||||
let (_,io_frame) = setup_builtin(argv, job, Some((io_stack,node.redirs)))?;
|
||||
|
||||
let stdout = borrow_fd(STDOUT_FILENO);
|
||||
|
||||
let mut curr_dir = env::current_dir().unwrap().to_str().unwrap().to_string();
|
||||
curr_dir.push('\n');
|
||||
write(stdout, curr_dir.as_bytes())?;
|
||||
io_frame.restore().unwrap();
|
||||
|
||||
io_frame.unwrap().restore().unwrap();
|
||||
state::set_status(0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::{ErrSpan, ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, state::write_vars};
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::{ErrSpan, ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, state::{self, write_vars}};
|
||||
|
||||
use super::setup_builtin;
|
||||
|
||||
pub fn shift(node: Node, job: &mut JobBldr) -> ShResult<()> {
|
||||
let NdRule::Command { assignments: _, argv } = node.class else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let child = ChildProc::new(Pid::this(), Some("shift"), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
|
||||
let mut argv = prepare_argv(argv).into_iter().skip(1);
|
||||
let (argv,_) = setup_builtin(argv, job, None)?;
|
||||
let mut argv = argv.into_iter();
|
||||
|
||||
if let Some((arg,span)) = argv.next() {
|
||||
let Ok(count) = arg.parse::<usize>() else {
|
||||
@@ -31,5 +25,6 @@ pub fn shift(node: Node, job: &mut JobBldr) -> ShResult<()> {
|
||||
}
|
||||
}
|
||||
|
||||
state::set_status(0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,20 +1,13 @@
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::{ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, state::source_file};
|
||||
use crate::{jobs::{ChildProc, JobBldr}, libsh::error::{ShErr, ShErrKind, ShResult}, parse::{execute::prepare_argv, NdRule, Node}, prelude::*, state::{self, source_file}};
|
||||
|
||||
use super::setup_builtin;
|
||||
|
||||
pub fn source(node: Node, job: &mut JobBldr) -> ShResult<()> {
|
||||
let NdRule::Command { assignments: _, argv } = node.class else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let child_pgid = if let Some(pgid) = job.pgid() {
|
||||
pgid
|
||||
} else {
|
||||
job.set_pgid(Pid::this());
|
||||
Pid::this()
|
||||
};
|
||||
let child = ChildProc::new(Pid::this(), Some("source"), Some(child_pgid))?;
|
||||
job.push_child(child);
|
||||
|
||||
let argv = prepare_argv(argv).into_iter().skip(1);
|
||||
let (argv,_) = setup_builtin(argv, job, None)?;
|
||||
|
||||
for (arg,span) in argv {
|
||||
let path = PathBuf::from(arg);
|
||||
@@ -39,5 +32,6 @@ pub fn source(node: Node, job: &mut JobBldr) -> ShResult<()> {
|
||||
source_file(path)?;
|
||||
}
|
||||
|
||||
state::set_status(0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user