summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJesse Luehrs <doy@tozt.net>2022-01-08 08:06:05 -0500
committerJesse Luehrs <doy@tozt.net>2022-01-08 08:06:05 -0500
commit27a911d8e22518503cb926d3c545cdde0c582a2e (patch)
tree96e8ec35f362468575df94eb6e337977db12fd36 /src
parent778b1f751a036fc025026be883e336074bde7d9b (diff)
downloadnbsh-27a911d8e22518503cb926d3c545cdde0c582a2e.tar.gz
nbsh-27a911d8e22518503cb926d3c545cdde0c582a2e.zip
implement read builtin
Diffstat (limited to 'src')
-rw-r--r--src/pipeline/builtins/command.rs15
-rw-r--r--src/pipeline/builtins/mod.rs34
2 files changed, 43 insertions, 6 deletions
diff --git a/src/pipeline/builtins/command.rs b/src/pipeline/builtins/command.rs
index 8119a55..2e6b4af 100644
--- a/src/pipeline/builtins/command.rs
+++ b/src/pipeline/builtins/command.rs
@@ -1,5 +1,7 @@
use crate::pipeline::prelude::*;
+use async_std::io::prelude::BufReadExt as _;
+
pub struct Command {
exe: crate::parse::Exe,
f: super::Builtin,
@@ -196,16 +198,17 @@ impl Io {
}
}
- pub async fn read_stdin(&self, buf: &mut [u8]) -> anyhow::Result<usize> {
+ pub async fn read_line_stdin(&self) -> anyhow::Result<String> {
+ let mut buf = String::new();
if let Some(fh) = self.stdin() {
if let File::In(fh) = &mut *fh.lock_arc().await {
- Ok(fh.read(buf).await?)
- } else {
- Ok(0)
+ fh.read_line(&mut buf).await?;
}
- } else {
- Ok(0)
}
+ if buf.ends_with('\n') {
+ buf.truncate(buf.len() - 1);
+ }
+ Ok(buf)
}
pub async fn write_stdout(&self, buf: &[u8]) -> anyhow::Result<()> {
diff --git a/src/pipeline/builtins/mod.rs b/src/pipeline/builtins/mod.rs
index 9670c0f..4e9cf2a 100644
--- a/src/pipeline/builtins/mod.rs
+++ b/src/pipeline/builtins/mod.rs
@@ -20,6 +20,7 @@ static BUILTINS: once_cell::sync::Lazy<
builtins.insert("setenv", &setenv);
builtins.insert("unsetenv", &unsetenv);
builtins.insert("echo", &echo);
+ builtins.insert("read", &read);
builtins.insert("and", &and);
builtins.insert("or", &or);
builtins.insert("command", &command);
@@ -217,6 +218,39 @@ fn echo(
}))
}
+#[allow(clippy::unnecessary_wraps)]
+fn read(
+ exe: crate::parse::Exe,
+ env: &Env,
+ cfg: command::Cfg,
+) -> anyhow::Result<command::Child> {
+ async fn async_read(
+ exe: crate::parse::Exe,
+ _env: &Env,
+ cfg: command::Cfg,
+ ) -> std::process::ExitStatus {
+ let var = if let Some(var) = exe.args().get(0).map(String::as_str) {
+ var
+ } else {
+ bail!(cfg, exe, "usage: read var");
+ };
+
+ let val = match cfg.io().read_line_stdin().await {
+ Ok(line) => line,
+ Err(e) => {
+ bail!(cfg, exe, e);
+ }
+ };
+
+ std::env::set_var(var, val);
+ async_std::process::ExitStatus::from_raw(0)
+ }
+
+ Ok(command::Child::new_fut(async move {
+ async_read(exe, env, cfg).await
+ }))
+}
+
fn and(
mut exe: crate::parse::Exe,
env: &Env,