Skip to content

Commit c93d107

Browse files
committed
feat: support zero-address file insertion
Signed-off-by: PranavRJoshi <pranavrjoshi1@gmail.com>
1 parent f083fa0 commit c93d107

5 files changed

Lines changed: 124 additions & 1 deletion

File tree

src/sed/compiler.rs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,15 @@ fn compile_address_range(
403403
}
404404
}
405405

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

410417
Ok(n_addr)
@@ -1804,6 +1811,51 @@ mod tests {
18041811
ScriptCharProvider::new("")
18051812
}
18061813

1814+
#[test]
1815+
fn test_zero_addr_r_accepted() {
1816+
for input in ["0r", "0 r"] {
1817+
let (lines, mut chars) = make_providers(input);
1818+
let mut cmd = Rc::new(RefCell::new(Command::default()));
1819+
let n_addr = compile_address_range(&lines, &mut chars, &mut cmd, &ctx()).unwrap();
1820+
1821+
assert_eq!(n_addr, 1);
1822+
assert!(matches!(cmd.borrow().addr1, Some(Address::Line(0))));
1823+
assert_eq!(chars.current(), 'r');
1824+
}
1825+
}
1826+
1827+
// Zero-address with no commands
1828+
#[test]
1829+
fn test_zero_addr_no_commands() {
1830+
let (lines, mut chars) = make_providers("0");
1831+
let mut cmd = Rc::new(RefCell::new(Command::default()));
1832+
let result = compile_address_range(&lines, &mut chars, &mut cmd, &ctx());
1833+
1834+
assert!(result.is_err());
1835+
assert!(
1836+
result
1837+
.unwrap_err()
1838+
.to_string()
1839+
.contains("address 0 requires a second addres")
1840+
);
1841+
}
1842+
1843+
// Zero-address with a command other than 'r' must still be rejected.
1844+
#[test]
1845+
fn test_zero_addr_non_r_rejected() {
1846+
let (lines, mut chars) = make_providers("0p");
1847+
let mut cmd = Rc::new(RefCell::new(Command::default()));
1848+
let result = compile_address_range(&lines, &mut chars, &mut cmd, &ctx());
1849+
1850+
assert!(result.is_err());
1851+
assert!(
1852+
result
1853+
.unwrap_err()
1854+
.to_string()
1855+
.contains("address 0 requires a second addres")
1856+
);
1857+
}
1858+
18071859
#[test]
18081860
fn test_compile_sequence_empty_input() {
18091861
let mut provider = make_line_provider(&[]);

src/sed/processor.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,23 @@ fn process_file(
423423
output: &mut OutputBuffer,
424424
context: &mut ProcessingContext,
425425
) -> UResult<()> {
426+
// Prescan for zero-address which must produce output
427+
// before any input line is read.
428+
{
429+
let mut current = commands.clone();
430+
while let Some(cmd_rc) = current {
431+
let cmd = cmd_rc.borrow();
432+
if matches!(cmd.code, 'r')
433+
&& matches!(&cmd.addr1, Some(Address::Line(0)))
434+
&& cmd.addr2.is_none()
435+
{
436+
let path = extract_variant!(cmd, Path);
437+
output.copy_file(path)?;
438+
}
439+
current = cmd.next.clone();
440+
}
441+
}
442+
426443
// Loop over the input lines as pattern space.
427444
'lines: while let Some(mut pattern) = reader.get_line()? {
428445
context.line_number += 1;

tests/by-util/test_sed.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,14 @@ check_output!(
774774
check_output!(read_ok, [format!("4r {LINES2}"), LINES1.to_string()]);
775775
check_output!(read_missing, ["5r /xyzzyxyzy42", LINES1]);
776776
check_output!(read_empty, ["6r input/empty", LINES1]);
777+
check_output!(
778+
cmd_read_zero_addr,
779+
[format!("0r {LINES2}"), LINES1.to_string()]
780+
);
781+
check_output!(
782+
cmd_read_one_addr,
783+
[format!("1r {LINES2}"), LINES1.to_string()]
784+
);
777785

778786
#[test]
779787
fn write_single_file() -> std::io::Result<()> {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
l1_1
2+
l2_1
3+
l2_2
4+
l2_3
5+
l2_4
6+
l2_5
7+
l2_6
8+
l2_7
9+
l2_8
10+
l2_9
11+
l1_2
12+
l1_3
13+
l1_4
14+
l1_5
15+
l1_6
16+
l1_7
17+
l1_8
18+
l1_9
19+
l1_10
20+
l1_11
21+
l1_12
22+
l1_13
23+
l1_14
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
l2_1
2+
l2_2
3+
l2_3
4+
l2_4
5+
l2_5
6+
l2_6
7+
l2_7
8+
l2_8
9+
l2_9
10+
l1_1
11+
l1_2
12+
l1_3
13+
l1_4
14+
l1_5
15+
l1_6
16+
l1_7
17+
l1_8
18+
l1_9
19+
l1_10
20+
l1_11
21+
l1_12
22+
l1_13
23+
l1_14

0 commit comments

Comments
 (0)