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
54 changes: 53 additions & 1 deletion src/sed/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,15 @@ fn compile_address_range(
}
}

// zero-address r command check
if is_line0 && n_addr == 1 {
return compilation_error(lines, line, "address 0 requires a second address");
// after retrieval of first address, subsequent spaces
// are consumed unconditionally. By now, the position
// must be in non-whitespace character or eol.
let next_cmd = if line.eol() { '\0' } else { line.current() };
if !matches!(next_cmd, 'r') {
return compilation_error(lines, line, "address 0 requires a second address");
}
}

Ok(n_addr)
Expand Down Expand Up @@ -1804,6 +1811,51 @@ mod tests {
ScriptCharProvider::new("")
}

#[test]
fn test_zero_addr_r_accepted() {
for input in ["0r", "0 r"] {
let (lines, mut chars) = make_providers(input);
let mut cmd = Rc::new(RefCell::new(Command::default()));
let n_addr = compile_address_range(&lines, &mut chars, &mut cmd, &ctx()).unwrap();

assert_eq!(n_addr, 1);
assert!(matches!(cmd.borrow().addr1, Some(Address::Line(0))));
assert_eq!(chars.current(), 'r');
}
}

// Zero-address with no commands
#[test]
fn test_zero_addr_no_commands() {
let (lines, mut chars) = make_providers("0");
let mut cmd = Rc::new(RefCell::new(Command::default()));
let result = compile_address_range(&lines, &mut chars, &mut cmd, &ctx());

assert!(result.is_err());
assert!(
result
.unwrap_err()
.to_string()
.contains("address 0 requires a second addres")
);
}

// Zero-address with a command other than 'r' must still be rejected.
#[test]
fn test_zero_addr_non_r_rejected() {
let (lines, mut chars) = make_providers("0p");
let mut cmd = Rc::new(RefCell::new(Command::default()));
let result = compile_address_range(&lines, &mut chars, &mut cmd, &ctx());

assert!(result.is_err());
assert!(
result
.unwrap_err()
.to_string()
.contains("address 0 requires a second addres")
);
}

#[test]
fn test_compile_sequence_empty_input() {
let mut provider = make_line_provider(&[]);
Expand Down
20 changes: 20 additions & 0 deletions src/sed/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,26 @@ fn process_file(
output: &mut OutputBuffer,
context: &mut ProcessingContext,
) -> UResult<()> {
// Prescan for zero-address which must produce output
// before any input line is read.
{
let mut current = commands.clone();
while let Some(cmd_rc) = current {
let cmd = cmd_rc.borrow();
if matches!(cmd.code, 'r')
&& matches!(&cmd.addr1, Some(Address::Line(0)))
&& cmd.addr2.is_none()
{
let path = extract_variant!(cmd, Path);
output.copy_file(path)?;
}
let next = cmd.next.clone();
// Release RefCell borrow before reassigning to 'current'
drop(cmd);
current = next;
}
}

// Loop over the input lines as pattern space.
'lines: while let Some(mut pattern) = reader.get_line()? {
context.line_number += 1;
Expand Down
8 changes: 8 additions & 0 deletions tests/by-util/test_sed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,14 @@ check_output!(
check_output!(read_ok, [format!("4r {LINES2}"), LINES1.to_string()]);
check_output!(read_missing, ["5r /xyzzyxyzy42", LINES1]);
check_output!(read_empty, ["6r input/empty", LINES1]);
check_output!(
cmd_read_zero_addr,
[format!("0r {LINES2}"), LINES1.to_string()]
);
check_output!(
cmd_read_one_addr,
[format!("1r {LINES2}"), LINES1.to_string()]
);

#[test]
fn write_single_file() -> std::io::Result<()> {
Expand Down
23 changes: 23 additions & 0 deletions tests/fixtures/sed/output/cmd_read_one_addr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
l1_1
l2_1
l2_2
l2_3
l2_4
l2_5
l2_6
l2_7
l2_8
l2_9
l1_2
l1_3
l1_4
l1_5
l1_6
l1_7
l1_8
l1_9
l1_10
l1_11
l1_12
l1_13
l1_14
23 changes: 23 additions & 0 deletions tests/fixtures/sed/output/cmd_read_zero_addr
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
l2_1
l2_2
l2_3
l2_4
l2_5
l2_6
l2_7
l2_8
l2_9
l1_1
l1_2
l1_3
l1_4
l1_5
l1_6
l1_7
l1_8
l1_9
l1_10
l1_11
l1_12
l1_13
l1_14
Loading