Skip to content
Open
Show file tree
Hide file tree
Changes from all 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