Skip to content

Commit

Permalink
Merge pull request kkawakam#412 from gwenn/escape_history_fix
Browse files Browse the repository at this point in the history
Fix History::load
  • Loading branch information
gwenn authored Jul 6, 2020
2 parents 03f981e + 441ed1b commit 7fe1925
Showing 1 changed file with 56 additions and 6 deletions.
62 changes: 56 additions & 6 deletions src/history.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! History API
use log::warn;
use std::collections::vec_deque;
use std::collections::VecDeque;
use std::fs::File;
Expand Down Expand Up @@ -141,7 +142,18 @@ impl History {
wtr.write_all(Self::FILE_VERSION_V2.as_bytes())?;
for entry in &self.entries {
wtr.write_all(b"\n")?;
wtr.write_all(entry.replace('\\', "\\\\").replace('\n', "\\n").as_bytes())?;
let mut bytes = entry.as_bytes();
while let Some(i) = memchr::memchr2(b'\\', b'\n', bytes) {
wtr.write_all(&bytes[..i])?;
if bytes[i] == b'\n' {
wtr.write_all(b"\\n")?; // escaped line feed
} else {
debug_assert_eq!(bytes[i], b'\\');
wtr.write_all(b"\\\\")?; // escaped backslash
}
bytes = &bytes[i + 1..];
}
wtr.write_all(bytes)?; // remaining bytes with no \n or \
}
wtr.write_all(b"\n")?;
// https://github.com/rust-lang/rust/issues/32677#issuecomment-204833485
Expand Down Expand Up @@ -169,14 +181,46 @@ impl History {
}
}
for line in lines {
let line = if v2 {
line?.replace("\\n", "\n").replace("\\\\", "\\")
} else {
line?
};
let mut line = line?;
if line.is_empty() {
continue;
}
if v2 {
let mut copy = None; // lazily copy line if unescaping is needed
let mut str = line.as_str();
while let Some(i) = str.find('\\') {
if copy.is_none() {
copy = Some(String::with_capacity(line.len()));
}
let s = copy.as_mut().unwrap();
s.push_str(&str[..i]);
let j = i + 1; // escaped char idx
let b = if j < str.len() {
str.as_bytes()[j]
} else {
0 // unexpected if History::save works properly
};
match b {
b'n' => {
s.push('\n'); // unescaped line feed
}
b'\\' => {
s.push('\\'); // unescaped back slash
}
_ => {
// only line feed and back slash should have been escaped
warn!(target: "rustyline", "bad escaped line: {}", line);
copy = None;
break;
}
}
str = &str[j + 1..];
}
if let Some(mut s) = copy {
s.push_str(str); // remaining bytes with no escaped char
line = s;
}
}
self.add(line); // TODO truncate to MAX_LINE
}
Ok(())
Expand Down Expand Up @@ -349,6 +393,12 @@ mod tests {
check_save("line\nfour \\ abc")
}

#[test]
fn save_windows_path() -> Result<()> {
let path = "cd source\\repos\\forks\\nushell\\";
check_save(path)
}

#[cfg_attr(miri, ignore)] // unsupported operation: `getcwd` not available when isolation is enabled
fn check_save(line: &str) -> Result<()> {
let mut history = init();
Expand Down

0 comments on commit 7fe1925

Please sign in to comment.