aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/parse/mod.rs25
-rw-r--r--src/parse/test.rs13
2 files changed, 27 insertions, 11 deletions
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index f418600..8682f04 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -663,23 +663,26 @@ impl StringDelimiter {
}
}
-fn parse_escape_code(b: &mut Cursor<'_>) -> Result<u8> {
- let x = b.peek();
+fn parse_escape_code(b: &mut Cursor<'_>) -> Result<Option<u8>> {
+ if !b.has() {
+ return Err(ParseError::Eof);
+ }
+
+ let x = b.adv();
let y = match x {
+ b'\n' => return Ok(None),
b'n' => b'\n',
b'r' => b'\r',
b't' => b'\t',
b'e' => 0x1b, // escape
b'x' => {
// parse two hex digits
- b.adv();
if b.buf.len() < 2 {
Err(ParseError::Eof)?;
}
- let x1 = b.peek();
- b.adv();
- let x2 = b.peek();
+ let x1 = b.adv();
+ let x2 = b.adv();
if !x1.is_ascii_hexdigit() || !x2.is_ascii_hexdigit() {
Err(ParseError::NotHexDigit)?;
@@ -693,9 +696,7 @@ fn parse_escape_code(b: &mut Cursor<'_>) -> Result<u8> {
_ => x,
};
- b.adv();
-
- Ok(y)
+ Ok(Some(y))
}
impl Parse for ExpString {
@@ -733,7 +734,9 @@ impl Parse for ExpString {
let x = b.adv();
if x == b'\\' {
- add_char(p, parse_escape_code(b)?);
+ if let Some(x) = parse_escape_code(b)? {
+ add_char(p, x);
+ }
} else if x == b'$' && !delim.is_strict() {
if !b.has() {
add_char(p, b'$');
@@ -865,7 +868,7 @@ impl Command<PreExpansion> {
}
#[allow(unused)]
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub enum ParseError {
/// "clean" EOF, i.e. not in the middle of something
Eof,
diff --git a/src/parse/test.rs b/src/parse/test.rs
index 3058730..91a3fda 100644
--- a/src/parse/test.rs
+++ b/src/parse/test.rs
@@ -329,3 +329,16 @@ fn dollar_non_var() {
pipes([cmd([estr(b"echo"), estr(b"$_")]),])
)
}
+
+#[test]
+fn backslash_eof() {
+ assert_eq!(do_parse(b"echo \\").unwrap_err().0, ParseError::Eof);
+}
+
+#[test]
+fn backslash_joins_lines() {
+ parse_test!(
+ parse(b"echo \\\nhello"),
+ pipes([cmd([estr(b"echo"), estr(b"hello")]),])
+ )
+}