Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
466 commits
Select commit Hold shift + click to select a range
4e2e1fd
sh: fix command lexer
grisenti Mar 7, 2025
d384020
sh: parse here document contents as word
grisenti Mar 7, 2025
06e9f34
sh: fix test
grisenti Mar 7, 2025
65f13e6
sh: implement opening files for read-write
grisenti Mar 7, 2025
b4d4824
sh: remove quotes from here-document start
grisenti Mar 8, 2025
aa3cbf2
sh: implement here-document
grisenti Mar 8, 2025
51d0e3e
sh: don't expand contents of quoted here-document
grisenti Mar 8, 2025
d561eea
sh: don't panic while parsing invalid words
grisenti Mar 8, 2025
1f3a699
sh: fix wrong condition
grisenti Mar 8, 2025
f0201db
sh: remove useless variable
grisenti Mar 8, 2025
06003e8
sh: remove rollback from command lexer
grisenti Mar 8, 2025
80b76c8
sh: implement LINENO special var
grisenti Mar 9, 2025
8432b2b
sh: implement redirection errors
grisenti Mar 10, 2025
9083967
sh: add test
grisenti Mar 10, 2025
9f67041
sh: use PS1 and PS2 in interactive mode
grisenti Mar 10, 2025
a89bfc1
sh: properly handle system errors in the shell
grisenti Mar 10, 2025
47cb420
sh: handle errors in tilde expansion
grisenti Mar 10, 2025
3e63fe3
sh: factor out common expression
grisenti Mar 10, 2025
9829873
sh: correctly print to stderr in parameter expansion
grisenti Mar 10, 2025
4776c2a
sh: implement error handling in word expansion
grisenti Mar 10, 2025
c23eda2
sh: make runtime error a syntax error
grisenti Mar 10, 2025
53a56fe
sh: fix handling of syntax errors
grisenti Mar 10, 2025
e31a918
sh: fix error messages for interactive shell
grisenti Mar 10, 2025
f79f0dc
sh: support more file descriptors
grisenti Mar 10, 2025
cc43f03
sh: fix ignored error
grisenti Mar 10, 2025
54ca0cd
sh: fail expansion with unset parameter
grisenti Mar 10, 2025
9a92df5
sh: implement test
grisenti Mar 10, 2025
870baed
sh: truncate files opened for writing if not in append mode
grisenti Mar 10, 2025
bb9e4ad
sh: fix test
grisenti Mar 10, 2025
8a0a1bf
sh: remove unused error variants
grisenti Mar 10, 2025
3231be7
sh: properly report errors for cd builtin
grisenti Mar 10, 2025
1598cb3
sh: fix integration test
grisenti Mar 10, 2025
467f40b
sh: correctly set shell member var in cd
grisenti Mar 10, 2025
2c16844
sh: match . and .. in pathname expansion
grisenti Mar 11, 2025
8f10099
sh: fix path pattern
grisenti Mar 11, 2025
3e75800
sh: fix incorrect string
grisenti Mar 11, 2025
602bc64
sh: fix pathname expansion
grisenti Mar 11, 2025
c7a50df
sh: improve test
grisenti Mar 11, 2025
76c1505
sh: fix pattern parsing
grisenti Mar 11, 2025
befaaca
sh: move function to utils module
grisenti Mar 11, 2025
84f572c
sh: improve code
grisenti Mar 11, 2025
a51a0a6
sh: remove extra newline
grisenti Mar 11, 2025
6e55ca0
sh: rework errors for special builtin utilities
grisenti Mar 11, 2025
f4cd01d
sh: add dot builtin
grisenti Mar 11, 2025
761f702
sh: improve test
grisenti Mar 11, 2025
2d2a1e9
sh: rename variable
grisenti Mar 11, 2025
30dafb0
sh: improve dot builtin
grisenti Mar 11, 2025
5cddbf9
sh: change function signature
grisenti Mar 11, 2025
5ae8e5c
sh: correctly use redirection in dot builtin
grisenti Mar 11, 2025
cb57f2c
sh: rename functions
grisenti Mar 11, 2025
fb14e91
sh: improve integration tests
grisenti Mar 11, 2025
9aef0aa
sh: implement eval builtin
grisenti Mar 12, 2025
6ca2ef0
sh: improve test
grisenti Mar 12, 2025
8d2da22
sh: fix lineno for builtin dot
grisenti Mar 12, 2025
b4f2dc5
sh: refactor code to free function
grisenti Mar 12, 2025
7c00c54
sh: cleanup simple command execution
grisenti Mar 12, 2025
50fcbc8
sh: cleanup builtin dot
grisenti Mar 12, 2025
8dbf007
sh: execute subshell in different process
grisenti Mar 12, 2025
4dcea86
sh: implement builtin exec
grisenti Mar 12, 2025
3911eb2
sh: implement builtin exit
grisenti Mar 12, 2025
1af5fd7
sh: implement builtin times
grisenti Mar 13, 2025
5327222
sh: fix readonly
grisenti Mar 13, 2025
897d2cf
sh: implement builtin export
grisenti Mar 13, 2025
786eaef
sh: remove extra newline characters
grisenti Mar 13, 2025
b23fe5e
sh: implement builtin return
grisenti Mar 13, 2025
7eb3308
sh: rework assignments
grisenti Mar 13, 2025
046de60
sh: improve builtin errors
grisenti Mar 13, 2025
96254d7
sh: refactor code
grisenti Mar 13, 2025
b6a38a4
sh: improve errors for builtin utilities
grisenti Mar 13, 2025
cfcf806
sh: standardize assignments
grisenti Mar 13, 2025
e4cd9de
sh: add integration test
grisenti Mar 13, 2025
299c33e
sh: implement set -e
grisenti Mar 13, 2025
d8ff655
sh: implement set -f
grisenti Mar 13, 2025
b35b7a0
sh: fix unwrap
grisenti Mar 13, 2025
411a274
sh: implement set -n
grisenti Mar 13, 2025
e787520
sh: add integration test
grisenti Mar 13, 2025
4688157
sh: implement set -v
grisenti Mar 13, 2025
64f86c0
sh: implement set -x
grisenti Mar 13, 2025
7f7d234
sh: implement builtin shift
grisenti Mar 14, 2025
fae0424
sh: implement builtin trap
grisenti Mar 14, 2025
9045c0b
sh: fix trap action printing
grisenti Mar 14, 2025
8035548
sh: restore $? after trap executes
grisenti Mar 14, 2025
aef1846
sh: add additional signals to trap
grisenti Mar 14, 2025
4ec4f34
sh: add integration test for trap builtin
grisenti Mar 15, 2025
fc773ef
sh: correctly parse cd args
grisenti Mar 15, 2025
8f0137a
sh: correctly skip '--' in break and continue
grisenti Mar 15, 2025
e5333d1
sh: correctly skip '--' in builtin utilities
grisenti Mar 15, 2025
d0c194b
sh: simplify api
grisenti Mar 15, 2025
34e7415
sh: rework environment
grisenti Mar 16, 2025
f558ed2
sh: locals are implicitly exported
grisenti Mar 16, 2025
c901f7d
sh: make assignments before function local to function
grisenti Mar 16, 2025
849b8e3
sh: make assignments before builtin locals
grisenti Mar 16, 2025
9778c3c
sh: fix unset
grisenti Mar 16, 2025
bf60888
sh: correctly gather exported variables
grisenti Mar 16, 2025
0681434
sh: implement builtin command
grisenti Mar 16, 2025
4594ce0
sh: implement builtin type
grisenti Mar 16, 2025
d394658
sh: add default path to command builtin
grisenti Mar 16, 2025
ab75f33
sh: implement builtin unalias
grisenti Mar 16, 2025
3c643ba
sh: implement getopts builtin
grisenti Mar 16, 2025
f43c4a7
sh: implement builtin ulimit
grisenti Mar 17, 2025
ce8ea83
sh: move signal handling to separate module
grisenti Mar 17, 2025
03de423
sh: exit is not a signal
grisenti Mar 17, 2025
a8485b7
sh: fix environment
grisenti Mar 17, 2025
37afdef
sh: remove unused dependency (clap)
grisenti Mar 17, 2025
945b310
sh: implement builtin kill
grisenti Mar 17, 2025
a6f660f
sh: fix parsing of async conjunctions
grisenti Mar 17, 2025
cab7b93
sh: implement basic background jobs
grisenti Mar 17, 2025
a4bb9c0
sh: fix parser bug
grisenti Mar 17, 2025
9cd8920
sh: periodically check background jobs
grisenti Mar 17, 2025
5085973
sh: handle signal exit
grisenti Mar 17, 2025
3ed43af
sh: fix kill builtin
grisenti Mar 17, 2025
7291468
sh: allow converting commands to string
grisenti Mar 18, 2025
67289f2
sh: add NonEmpty type
grisenti Mar 18, 2025
981f4bb
sh: improve display for SimpleCommand
grisenti Mar 18, 2025
e19932f
sh: improve display for CompleteCommand
grisenti Mar 18, 2025
3ed1eba
sh: cleanup
grisenti Mar 18, 2025
1723a5c
sh: improve display for CompoundCommand
grisenti Mar 18, 2025
cdcf9bd
sh: remove unused type alias
grisenti Mar 18, 2025
e2179ec
sh: implement display for Conjunction
grisenti Mar 18, 2025
c4affb0
sh: change how jobs are represented in shell
grisenti Mar 18, 2025
0f804f6
sh: put common code in method
grisenti Mar 18, 2025
2ed7b44
sh: make signal handling safer
grisenti Mar 18, 2025
fafbed8
sh: fix arg parsing for builtin unset
grisenti Mar 18, 2025
6f5db5d
sh: kill utility can use job ids
grisenti Mar 18, 2025
d65c404
sh: improve OsError
grisenti Mar 18, 2025
8b3eafd
sh: make shell method public
grisenti Mar 18, 2025
0b55c8b
sh: implement builtin wait
grisenti Mar 18, 2025
75116fb
sh: improve formatting for conjunction
grisenti Mar 19, 2025
435c1d1
sh: add job_state to Job
grisenti Mar 19, 2025
cf6e9db
sh: fix job id parsing
grisenti Mar 19, 2025
544bd2b
sh: fix setting of job state
grisenti Mar 19, 2025
dfa730b
sh: add options parser
grisenti Mar 19, 2025
4b29963
sh: implement builtin jobs utility
grisenti Mar 19, 2025
eb53ba7
sh: cleanup unset builtin
grisenti Mar 19, 2025
01fa0d6
sh: improve errors for unalias
grisenti Mar 19, 2025
489ffbd
sh: cleanup ulimit
grisenti Mar 19, 2025
a093c1e
sh: cleanup cd
grisenti Mar 19, 2025
e6b7736
sh: cleanup builtin command
grisenti Mar 19, 2025
b062a47
sh: add new method to option parser
grisenti Mar 19, 2025
8f7fb06
sh: add command history
grisenti Mar 20, 2025
596cd21
sh: add additional shell api
grisenti Mar 20, 2025
b10c904
sh: remove O_NONBLOCK from stdin when executing utility
grisenti Mar 20, 2025
2171e15
sh: implement builtin fc
grisenti Mar 20, 2025
f9cb935
sh: rename Environment -> Variables
grisenti Mar 20, 2025
83c0212
sh: implement umask builtin
grisenti Mar 20, 2025
8c221f3
sh: correctly set default global variables
grisenti Mar 21, 2025
5e8a0e6
sh: fix typo
grisenti Mar 21, 2025
b410712
sh: set -h is on by default
grisenti Mar 21, 2025
6c35b89
sh: save command locations
grisenti Mar 21, 2025
7cb7ffe
sh: change method arguments
grisenti Mar 21, 2025
6941e5e
sh: implement builtin hash
grisenti Mar 21, 2025
4d98437
sh: fix TODOs
grisenti Mar 21, 2025
fd1b6d5
sh: fix command builtin
grisenti Mar 21, 2025
490286e
sh: fix TODO
grisenti Mar 21, 2025
50eaf21
sh: rename Variables -> Environment
grisenti Mar 21, 2025
773eb66
sh: execute command as script after ENOEXEC
grisenti Mar 21, 2025
7eb4377
sh: make method private
grisenti Mar 21, 2025
c6f411a
sh: report if a job has been stopped
grisenti Mar 22, 2025
fc30e9a
sh: change output format for job utility
grisenti Mar 22, 2025
494db49
sh: setup job control for interactive shells
grisenti Mar 22, 2025
ab949d9
sh: fix error message
grisenti Mar 22, 2025
2be9d8d
sh: fix Signal::from_str
grisenti Mar 22, 2025
b34ae75
sh: implement bg
grisenti Mar 22, 2025
2b07500
sh: create JobManager to manage jobs
grisenti Mar 22, 2025
6262c3f
sh: cleanup terminated jobs
grisenti Mar 22, 2025
6a40632
sh: fix JobManager
grisenti Mar 22, 2025
c9dbdf2
sh: implement builtin fg
grisenti Mar 22, 2025
b59bf4f
sh: fix bg
grisenti Mar 22, 2025
419b1d2
sh: bg returns error if the shell is not interactive
grisenti Mar 22, 2025
a3f8e8a
sh: improve formatting of jobs
grisenti Mar 22, 2025
c3c92cb
sh: don't update completed jobs
grisenti Mar 22, 2025
1eeeea6
sh: background jobs have a different process group
grisenti Mar 22, 2025
234659d
sh: pipeline commands executed in the foreground have the same pgid
grisenti Mar 22, 2025
77d7790
sh: refactor signal handling
grisenti Mar 22, 2025
0ae46c8
sh: ignore signal actions are not reset
grisenti Mar 22, 2025
2464ee5
sh: reset traps in subshell environments
grisenti Mar 22, 2025
c936099
sh: bg and fg return error in a subshell environment
grisenti Mar 22, 2025
b6fdbcf
sh: also reset default trap actions
grisenti Mar 22, 2025
a27cac6
sh: correctly print here documents
grisenti Mar 22, 2025
87e5434
sh: properly handle simple commands getting stopped
grisenti Mar 22, 2025
79a63d2
sh: properly handle pipelines getting stopped
grisenti Mar 22, 2025
2cdcff2
sh: add comment
grisenti Mar 23, 2025
45d759f
sh: don't set foreground pgid if the shell is not running in the fore…
grisenti Mar 23, 2025
931542b
sh: remove incorrect comment
grisenti Mar 23, 2025
b87e0b1
sh: correctly set foreground process command for the shell in fg builtin
grisenti Mar 23, 2025
05db067
sh: don't change terminal foreground process in fg
grisenti Mar 23, 2025
8933350
sh: remove conditional
grisenti Mar 23, 2025
9c90e5e
sh: delete empty file
grisenti Mar 23, 2025
91e56a3
sh: report job status
grisenti Mar 23, 2025
b51c0f4
sh: remove static global
grisenti Mar 23, 2025
67fe178
sh: apply cargo fix
grisenti Mar 23, 2025
e58a0a2
sh: fix warnings
grisenti Mar 23, 2025
8046fd1
sh: fix trap builtin
grisenti Mar 23, 2025
d53c612
sh: simplify command lexer
grisenti Mar 23, 2025
c8f6223
sh: add vi module
grisenti Mar 23, 2025
d2b5d67
sh: implement word motion commands
grisenti Mar 24, 2025
47c0a7f
sh: finish motion commands
grisenti Mar 25, 2025
2bc07b9
sh: implement simple commands
grisenti Mar 25, 2025
d22db12
sh: implement expansion commands for vi mode
grisenti Mar 25, 2025
b309627
sh: implement _ command for vi mode
grisenti Mar 25, 2025
3c0babc
sh: fix cursor vi expansion commands
grisenti Mar 25, 2025
1089690
sh: fix cursor for '_' command in vi mode
grisenti Mar 25, 2025
a94e73a
sh: hookup vi mode to main loop
grisenti Mar 25, 2025
130e89a
sh: restructure modules
grisenti Mar 26, 2025
5b06671
sh: reset terminal settings before executing external utility
grisenti Mar 26, 2025
c65d0ed
sh: fix builtin exec
grisenti Mar 26, 2025
6bf9dab
sh: don't save terminal settings if process is not attached to terminal
grisenti Mar 26, 2025
eea35ea
sh: refactor common code to function
grisenti Mar 26, 2025
4c5bad3
sh: correctly handle EOF
grisenti Mar 26, 2025
959629b
sh: ignore control characters
grisenti Mar 26, 2025
266a671
sh: fix line printing in vi mode
grisenti Mar 26, 2025
5187cb0
sh: fix todo
grisenti Mar 26, 2025
0770301
sh: print alert on vi error
grisenti Mar 26, 2025
4e4aba1
sh: collapse cascading ifs into single if
grisenti Mar 26, 2025
2915201
sh: fix '_' command in vi mode
grisenti Mar 26, 2025
a88cb59
sh: manage terminal in main
grisenti Mar 26, 2025
dd8c66f
sh: implement history navigation
grisenti Mar 26, 2025
28d84ec
sh: fix cursor for history navigation in vi mode
grisenti Mar 26, 2025
7c0718b
sh: fix command execution in vi mode
grisenti Mar 26, 2025
986d76d
sh: fix multi line input in interactive mode
grisenti Mar 26, 2025
b421d0e
sh: move module
grisenti Mar 26, 2025
57aba13
sh: implement remaining history navigation commands
grisenti Mar 26, 2025
688fbc4
sh: implement builtin read
grisenti Mar 26, 2025
c630a15
sh: fix warnings
grisenti Mar 26, 2025
17d7674
sh: add license to files
grisenti Mar 26, 2025
219adc0
sh: fix package errors
grisenti Mar 26, 2025
1f69ad1
sh: use gettext-rs
grisenti Mar 26, 2025
bfe05b8
sh: fix test warnings
grisenti Mar 26, 2025
dc726f9
sh: fix tests
grisenti Mar 26, 2025
e91f23b
sh: bypass REG_EMPTY for empty regexes on macos
grisenti Mar 27, 2025
d35376d
sh: replace wc with awk in test
grisenti Mar 27, 2025
c440f81
sh: correctly handle error
grisenti Mar 27, 2025
8209d9e
sh: handle count too large in vi mode
grisenti Mar 27, 2025
24c0d86
sh: getopts fails with invalid optstring
grisenti Mar 27, 2025
59c4c04
sh: fix todo
grisenti Mar 27, 2025
c28410d
sh: write history on exit
grisenti Mar 27, 2025
18339dc
sh: fix todo
grisenti Mar 27, 2025
02549fa
sh: fix todo
grisenti Mar 27, 2025
2bee62c
sh: fix todo
grisenti Mar 27, 2025
b4690b6
sh: handle errors properly
grisenti Mar 27, 2025
86e7856
sh: fix clippy errors
grisenti Mar 27, 2025
c7e4e62
sh: fix unwrap
grisenti Mar 27, 2025
47936d3
sh: cleanup main
grisenti Mar 27, 2025
4e708ef
sh: fix clippy warnings
grisenti Mar 27, 2025
b93f7d1
sh: cleanup write_history_to_file
grisenti Mar 27, 2025
3c83c6a
sh: cleanup read_history_from_file
grisenti Mar 27, 2025
e188d0b
sh: collapse nested if
grisenti Mar 27, 2025
f2e1ba4
sh: add comment
grisenti Mar 27, 2025
0fffea1
sh: implement <control>-V input in vi mode
grisenti Mar 27, 2025
92b36f6
sh: fix searching command history in vi mode
grisenti Mar 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
627 changes: 397 additions & 230 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ members = [
"process",
"sccs",
"screen",
"sh",
"sys",
"text",
"tree",
Expand Down
14 changes: 14 additions & 0 deletions sh/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[package]
name = "posixutils-sh"
version = "0.1.7"
edition = "2021"

[dependencies]
plib = { path = "../plib" }
gettext-rs.workspace = true
nix = { version = "0.29", features = ["process", "fs", "resource", "signal", "user", "term"] }
atty = "0.2"

[[bin]]
name = "sh"
path = "src/main.rs"
45 changes: 45 additions & 0 deletions sh/src/builtin/alias.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// Copyright (c) 2024 Hemi Labs, Inc.
//
// This file is part of the posixutils-rs project covered under
// the MIT License. For the full license text, please see the LICENSE
// file in the root directory of this project.
// SPDX-License-Identifier: MIT
//

use crate::builtin::{BuiltinResult, BuiltinUtility};
use crate::shell::opened_files::OpenedFiles;
use crate::shell::Shell;

pub struct AliasBuiltin;

impl BuiltinUtility for AliasBuiltin {
fn exec(
&self,
args: &[String],
shell: &mut Shell,
opened_files: &mut OpenedFiles,
) -> BuiltinResult {
if args.is_empty() {
for (alias, command) in &shell.alias_table {
opened_files.write_out(format!("alias {}='{}'", alias, command));
}
return Ok(0);
}

for arg in args {
if let Some(eq_pos) = arg.find('=') {
let (alias, command) = arg.split_at(eq_pos);
let command = &command[1..];
shell
.alias_table
.insert(alias.to_string(), command.to_string());
} else if let Some(command) = shell.alias_table.get(arg) {
opened_files.write_out(format!("alias {}='{}'", arg, command));
} else {
return Err(format!("alias: {}: not found", arg).into());
}
}
Ok(0)
}
}
87 changes: 87 additions & 0 deletions sh/src/builtin/bg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//
// Copyright (c) 2024 Hemi Labs, Inc.
//
// This file is part of the posixutils-rs project covered under
// the MIT License. For the full license text, please see the LICENSE
// file in the root directory of this project.
// SPDX-License-Identifier: MIT
//

use crate::builtin::{skip_option_terminator, BuiltinResult, BuiltinUtility};
use crate::jobs::{parse_job_id, Job, JobState};
use crate::shell::opened_files::OpenedFiles;
use crate::shell::Shell;
use nix::sys::signal::kill;

fn run_background_job(
arg: &str,
job: &mut Job,
opened_files: &mut OpenedFiles,
) -> Result<(), String> {
if job.state != JobState::Stopped {
return Err(format!(
"bg: job {arg} is already running in the background"
));
}
kill(job.pid, nix::sys::signal::SIGCONT)
.map_err(|err| format!("bg: failed to resume job {arg} ({err})"))?;
opened_files.write_out(format!("[{}] {}\n", job.number, job.command));
job.state = JobState::Running;
Ok(())
}
pub struct Bg;

impl BuiltinUtility for Bg {
fn exec(
&self,
args: &[String],
shell: &mut Shell,
opened_files: &mut OpenedFiles,
) -> BuiltinResult {
if !shell.set_options.monitor {
return Err("bg: cannot use bg when job control is disabled".into());
}
if !shell.is_interactive {
return Err("bg: cannot use bg in a non-interactive shell".into());
}
if shell.is_subshell {
return Err("bg: cannot use bg in a subshell environment".into());
}

let mut status = 0;
let args = skip_option_terminator(args);
if args.is_empty() {
if let Some(job) = shell.background_jobs.current_mut() {
if let Err(err) = run_background_job("current", job, opened_files) {
opened_files.write_err(err);
status = 1;
}
} else {
opened_files.write_err("bg: no background jobs");
status = 1;
}
} else {
for arg in args {
match parse_job_id(arg) {
Ok(job_id) => {
if let Some(job) = shell.background_jobs.get_job_mut(job_id) {
if let Err(err) = run_background_job(arg, job, opened_files) {
opened_files.write_err(err);
status = 1;
}
} else {
opened_files.write_err(format!("bg: '{arg}' no such job"));
status = 1;
}
}
Err(_) => {
opened_files.write_err(format!("bg: '{arg}' no such job"));
status = 1
}
}
}
}

Ok(status)
}
}
Loading