Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
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
7 changes: 7 additions & 0 deletions src/runtime/shell/Builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,13 @@ impl Builtin {
&self.args
}

/// Index of the first operand, skipping a leading `--` end-of-options
/// delimiter (POSIX Utility Syntax Guideline 10).
#[inline]
pub fn operand_start(&self) -> usize {
(!self.args.is_empty() && self.arg_bytes(0) == b"--") as usize
}

/// Borrow `argv[1..][idx]` as `&[u8]` (NUL excluded).
///
/// Every entry in `self.args` borrows into the owning `Cmd`'s
Expand Down
5 changes: 3 additions & 2 deletions src/runtime/shell/builtin/basename.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ impl Basename {
let buf = {
let bltn = Builtin::of(interp, cmd);
let argc = bltn.args_slice().len();
if argc == 0 {
let start = bltn.operand_start();
if start >= argc {
return Self::fail(interp, cmd, Kind::Basename.usage_string());
}
let mut buf = Vec::new();
for i in 0..argc {
for i in start..argc {
buf.extend_from_slice(bun_paths::resolve_path::basename(bltn.arg_bytes(i)));
buf.push(b'\n');
}
Expand Down
7 changes: 4 additions & 3 deletions src/runtime/shell/builtin/cd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@ enum State {
impl Cd {
pub(crate) fn start(interp: &Interpreter, cmd: NodeId) -> Yield {
let args = Builtin::of(interp, cmd).args_slice();
if args.len() > 1 {
let skip = Builtin::of(interp, cmd).operand_start();
if args.len() - skip > 1 {
return Self::write_stderr_non_blocking(
interp,
cmd,
format_args!("too many arguments\n"),
);
}

if args.len() == 1 {
let first_arg = Builtin::of(interp, cmd).arg_bytes(0);
if args.len() - skip == 1 {
let first_arg = Builtin::of(interp, cmd).arg_bytes(skip);
if first_arg == b"-" {
let prev = Builtin::shell(interp, cmd).prev_cwd().to_vec();
if let Err(err) = interp.as_cmd_mut(cmd).base.shell_mut().change_prev_cwd() {
Expand Down
5 changes: 3 additions & 2 deletions src/runtime/shell/builtin/dirname.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ impl Dirname {
pub(crate) fn start(interp: &Interpreter, cmd: NodeId) -> Yield {
let bltn = Builtin::of(interp, cmd);
let argc = bltn.args_slice().len();
if argc == 0 {
let start = bltn.operand_start();
if start >= argc {
return Self::fail(interp, cmd, b"usage: dirname string\n");
}

let stdout_needs_io = bltn.stdout.needs_io();
let mut buf = Vec::new();
for i in 0..argc {
for i in start..argc {
let path = bltn.arg_bytes(i);
let dir = bun_paths::resolve_path::dirname::<bun_paths::platform::Posix>(path);
let dir: &[u8] = if dir.is_empty() { b"." } else { dir };
Expand Down
5 changes: 3 additions & 2 deletions src/runtime/shell/builtin/exit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ enum State {
impl Exit {
pub(crate) fn start(interp: &Interpreter, cmd: NodeId) -> Yield {
let bltn = Builtin::of(interp, cmd);
let code: crate::shell::ExitCode = match bltn.args_slice().len() {
let start = bltn.operand_start();
let code: crate::shell::ExitCode = match bltn.args_slice().len() - start {
0 => 0,
1 => {
let s = bltn.arg_bytes(0);
let s = bltn.arg_bytes(start);
match parse_exit_code(s) {
Some(c) => c,
None => {
Expand Down
5 changes: 3 additions & 2 deletions src/runtime/shell/builtin/export.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ enum State {
impl Export {
pub(crate) fn start(interp: &Interpreter, cmd: NodeId) -> Yield {
let argc = Builtin::of(interp, cmd).args_slice().len();
if argc == 0 {
let start = Builtin::of(interp, cmd).operand_start();
if start >= argc {
// No args: print all exported vars.
return Self::print_all(interp, cmd);
}
for i in 0..argc {
for i in start..argc {
let s = Builtin::of(interp, cmd).arg_bytes(i);
if s.is_empty() {
continue;
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/shell/builtin/ls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,10 @@ impl Ls {
let mut idx = 0usize;
while idx < argc {
let flag = Builtin::of(interp, cmd).arg_bytes(idx);
if flag == b"--" {
idx += 1;
return Ok(if idx < argc { Some(idx) } else { None });
}
match Self::parse_flag(&mut Self::state_mut(interp, cmd).opts, flag) {
ParseFlag::Done => return Ok(Some(idx)),
ParseFlag::ContinueParsing => {}
Expand Down
27 changes: 14 additions & 13 deletions src/runtime/shell/builtin/mv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,23 +350,24 @@ impl Mv {
let mut idx = 0usize;
while idx < argc {
let flag = Builtin::of(interp, cmd).arg_bytes(idx);
if flag == b"--" {
idx += 1;
break;
}
match Self::parse_flag(&mut Self::state_mut(interp, cmd).opts, flag) {
MvFlag::Done => {
let filepath_args = argc - idx;
if filepath_args < 2 {
return Err(MvParseError::ShowUsage);
}
let me = Self::state_mut(interp, cmd);
me.args.sources_start = idx;
me.args.target_idx = argc - 1;
return Ok(());
}
MvFlag::ContinueParsing => {}
MvFlag::Done => break,
MvFlag::ContinueParsing => idx += 1,
MvFlag::IllegalOption(s) => return Err(MvParseError::IllegalOption(s)),
}
idx += 1;
}
Err(MvParseError::ShowUsage)
let filepath_args = argc - idx;
if filepath_args < 2 {
return Err(MvParseError::ShowUsage);
}
let me = Self::state_mut(interp, cmd);
me.args.sources_start = idx;
me.args.target_idx = argc - 1;
Ok(())
}

fn parse_flag(opts: &mut Opts, flag: &[u8]) -> MvFlag {
Expand Down
3 changes: 2 additions & 1 deletion src/runtime/shell/builtin/pwd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ enum WaitKind {

impl Pwd {
pub(crate) fn start(interp: &Interpreter, cmd: NodeId) -> Yield {
if !Builtin::of(interp, cmd).args_slice().is_empty() {
let bltn = Builtin::of(interp, cmd);
if bltn.args_slice().len() > bltn.operand_start() {
let msg: &[u8] = b"pwd: too many arguments\n";
if let Some(safeguard) = Builtin::of(interp, cmd).stderr.needs_io() {
Self::state_mut(interp, cmd).state = State::WaitingIo {
Expand Down
14 changes: 12 additions & 2 deletions src/runtime/shell/builtin/rm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,13 @@ impl Rm {
}

let arg = Builtin::of(interp, cmd).arg_bytes(idx as usize).to_vec();
match Self::parse_flag(&mut Self::state_mut(interp, cmd).opts, &arg) {
let is_end_of_options = arg == b"--";
let parsed = if is_end_of_options {
RmParseFlag::Done
} else {
Self::parse_flag(&mut Self::state_mut(interp, cmd).opts, &arg)
};
match parsed {
RmParseFlag::ContinueParsing => {
if let RmState::ParseOpts { idx: i, .. } =
&mut Self::state_mut(interp, cmd).state
Expand All @@ -174,7 +180,11 @@ impl Rm {
return Self::write_err_literal(interp, cmd, idx, buf);
}

let args_start = idx as usize;
let args_start = idx as usize + is_end_of_options as usize;
if args_start >= argc {
let usage = Kind::Rm.usage_string();
return Self::write_err_literal(interp, cmd, idx, usage);
}

// Check that none of the paths will delete the root.
{
Expand Down
3 changes: 3 additions & 0 deletions src/runtime/shell/builtin/seq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ impl Seq {
idx += 1;
continue;
}
if arg == b"--" {
idx += 1;
}
break;
}

Expand Down
7 changes: 4 additions & 3 deletions src/runtime/shell/builtin/which.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ pub enum State {
impl Which {
pub(crate) fn start(interp: &Interpreter, cmd: NodeId) -> Yield {
let argc = Builtin::of(interp, cmd).args_slice().len();
if argc == 0 {
let start = Builtin::of(interp, cmd).operand_start();
if start >= argc {
if let Some(safeguard) = Builtin::of(interp, cmd).stdout.needs_io() {
Self::state_mut(interp, cmd).state = State::OneArg;
let child = ChildPtr::new(cmd, WriterTag::Builtin);
Expand All @@ -49,7 +50,7 @@ impl Which {
// captured buffer, then finish.
let (path_env, cwd) = Self::path_and_cwd(interp, cmd);
let mut had_not_found = false;
for i in 0..argc {
for i in start..argc {
let arg = Self::arg(interp, cmd, i);
match Self::resolve(&path_env, &cwd, &arg) {
Some(resolved) => {
Expand Down Expand Up @@ -79,7 +80,7 @@ impl Which {
}

Self::state_mut(interp, cmd).state = State::MultiArgs {
arg_idx: 0,
arg_idx: start,
had_not_found: false,
waiting_write: false,
};
Expand Down
7 changes: 4 additions & 3 deletions src/runtime/shell/builtin/yes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,13 @@ impl Yes {
pub(crate) fn start(interp: &Interpreter, cmd: NodeId) -> Yield {
// Build one copy of the output line.
let argc = Builtin::of(interp, cmd).args_slice().len();
let start = Builtin::of(interp, cmd).operand_start();
let mut one = Vec::new();
if argc == 0 {
if start >= argc {
one.extend_from_slice(b"y\n");
} else {
for i in 0..argc {
if i > 0 {
for i in start..argc {
if i > start {
one.push(b' ');
}
one.extend_from_slice(Builtin::of(interp, cmd).arg_bytes(i));
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/shell/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2577,6 +2577,10 @@ pub fn parse_flags<'a, O: FlagParser>(
while idx < args.len() {
// SAFETY: argv entries are NUL-terminated C strings (see Builtin::init).
let flag = unsafe { bun_core::ffi::cstr(args[idx]) }.to_bytes();
if flag == b"--" {
let rest = &args[idx + 1..];
return Ok(if rest.is_empty() { None } else { Some(rest) });
}
Comment thread
robobun marked this conversation as resolved.
match parse_one_flag(opts, flag) {
ParseFlagResult::Done => return Ok(Some(&args[idx..])),
ParseFlagResult::ContinueParsing => {}
Expand Down
Loading
Loading