Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b9978f911 | ||
|
|
a708e09a72 |
No files matched your search
+56
-6
@@ -29,6 +29,9 @@ use uucore::error::{UResult, USimpleError};
|
||||
|
||||
const DEFAULT_OUTPUT_WIDTH: usize = 60;
|
||||
|
||||
const ERR_ADDRESS_0_USAGE: &str =
|
||||
"address 0 can only be used with ~step, a second regular expression, or a read command";
|
||||
|
||||
// Handling required after processing a command
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum CommandHandling {
|
||||
@@ -380,11 +383,7 @@ fn compile_address_range(
|
||||
};
|
||||
|
||||
if is_line0 && !matches!(addr2, Address::Re(_)) && !is_step_match {
|
||||
return compilation_error(
|
||||
lines,
|
||||
line,
|
||||
"address 0 can only be used with a regular expression or ~step",
|
||||
);
|
||||
return compilation_error(lines, line, ERR_ADDRESS_0_USAGE);
|
||||
}
|
||||
|
||||
// If needed, transform Address::Line into Address::Step*.
|
||||
@@ -399,8 +398,14 @@ fn compile_address_range(
|
||||
}
|
||||
}
|
||||
|
||||
// Zero-address read 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.
|
||||
if line.eol() || !matches!(line.current(), 'r' | 'R') {
|
||||
return compilation_error(lines, line, ERR_ADDRESS_0_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(n_addr)
|
||||
@@ -1849,6 +1854,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(ERR_ADDRESS_0_USAGE)
|
||||
);
|
||||
}
|
||||
|
||||
// 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(ERR_ADDRESS_0_USAGE)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compile_sequence_empty_input() {
|
||||
let mut provider = make_line_provider(&[]);
|
||||
|
||||
@@ -415,6 +415,35 @@ fn list(output: &mut OutputBuffer, line: &IOChunk, max_width: usize) -> UResult<
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Handle address 0 read at the beginning of each file.
|
||||
fn address_0_process(
|
||||
commands: Option<Rc<RefCell<Command>>>,
|
||||
output: &mut OutputBuffer,
|
||||
) -> UResult<()> {
|
||||
// Prescan for zero-address which must produce output
|
||||
// before any input line is read.
|
||||
{
|
||||
let mut current = commands;
|
||||
while let Some(cmd_rc) = current {
|
||||
let next = {
|
||||
let cmd = cmd_rc.borrow();
|
||||
|
||||
if cmd.code == 'r'
|
||||
&& matches!(cmd.addr1, Some(Address::Line(0)))
|
||||
&& cmd.addr2.is_none()
|
||||
{
|
||||
let path = extract_variant!(cmd, Path);
|
||||
output.copy_file(path)?;
|
||||
}
|
||||
|
||||
cmd.next.clone()
|
||||
};
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
/// Process a single input file
|
||||
fn process_file(
|
||||
@@ -423,6 +452,8 @@ fn process_file(
|
||||
output: &mut OutputBuffer,
|
||||
context: &mut ProcessingContext,
|
||||
) -> UResult<()> {
|
||||
address_0_process(commands.clone(), output)?;
|
||||
|
||||
// Loop over the input lines as pattern space.
|
||||
'lines: while let Some(mut pattern) = reader.get_line()? {
|
||||
context.line_number += 1;
|
||||
|
||||
@@ -973,6 +973,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<()> {
|
||||
@@ -1339,7 +1347,7 @@ fn test_addr0_second_required() {
|
||||
.args(&["0p"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_is("sed: <script argument 1>:1:2: error: address 0 requires a second address\n");
|
||||
.stderr_is("sed: <script argument 1>:1:2: error: address 0 can only be used with ~step, a second regular expression, or a read command\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1348,7 +1356,7 @@ fn test_addr0_second_re_only() {
|
||||
.args(&["0,4p"])
|
||||
.fails()
|
||||
.code_is(1)
|
||||
.stderr_is("sed: <script argument 1>:1:4: error: address 0 can only be used with a regular expression or ~step\n");
|
||||
.stderr_is("sed: <script argument 1>:1:4: error: address 0 can only be used with ~step, a second regular expression, or a read command\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
+23
@@ -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
@@ -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
|
||||
Reference in new issue
Block a user