diff options
author | Evan Martin <evan.martin@gmail.com> | 2023-12-26 16:46:04 -0800 |
---|---|---|
committer | Evan Martin <evan.martin@gmail.com> | 2023-12-26 16:46:04 -0800 |
commit | 178bf19798a0e0454f53b5c3b4c3dc1a4dd97798 (patch) | |
tree | ea729fd30c014777a2109cf74aad801148805ae8 | |
parent | 54eeb86a2a0ab5b622837ea1447dfdea892d8f26 (diff) | |
download | n2-178bf19798a0e0454f53b5c3b4c3dc1a4dd97798.tar.gz |
move around nul-termination of input files
-rw-r--r-- | src/depfile.rs | 1 | ||||
-rw-r--r-- | src/load.rs | 14 | ||||
-rw-r--r-- | src/parse.rs | 16 | ||||
-rw-r--r-- | src/scanner.rs | 6 | ||||
-rw-r--r-- | src/task.rs | 3 |
5 files changed, 26 insertions, 14 deletions
diff --git a/src/depfile.rs b/src/depfile.rs index dd8c9f7..33144c6 100644 --- a/src/depfile.rs +++ b/src/depfile.rs @@ -84,6 +84,7 @@ mod tests { use super::*; fn must_parse(buf: &mut Vec<u8>) -> Deps { + buf.push(0); let mut scanner = Scanner::new(buf); match parse(&mut scanner) { Err(err) => { diff --git a/src/load.rs b/src/load.rs index 7029d4c..51c4c6f 100644 --- a/src/load.rs +++ b/src/load.rs @@ -159,17 +159,18 @@ impl Loader { fn read_file(&mut self, id: FileId) -> anyhow::Result<()> { let path = self.graph.file(id).path().to_path_buf(); - let bytes = match trace::scope("fs::read", || std::fs::read(&path)) { + let mut bytes = match trace::scope("fs::read", || std::fs::read(&path)) { Ok(b) => b, Err(e) => bail!("read {}: {}", path.display(), e), }; - self.parse(path, bytes) + bytes.push(0); + self.parse(path, &bytes) } - fn parse(&mut self, path: PathBuf, mut bytes: Vec<u8>) -> anyhow::Result<()> { + fn parse(&mut self, path: PathBuf, bytes: &[u8]) -> anyhow::Result<()> { let filename = std::rc::Rc::new(path); - let mut parser = parse::Parser::new(&mut bytes); + let mut parser = parse::Parser::new(&bytes); loop { let stmt = match parser .read(self) @@ -245,10 +246,11 @@ pub fn read(build_filename: &str) -> anyhow::Result<State> { /// Parse a single file's content. #[cfg(test)] -pub fn parse(name: &str, content: Vec<u8>) -> anyhow::Result<graph::Graph> { +pub fn parse(name: &str, mut content: Vec<u8>) -> anyhow::Result<graph::Graph> { + content.push(0); let mut loader = Loader::new(); trace::scope("loader.read_file", || { - loader.parse(PathBuf::from(name), content) + loader.parse(PathBuf::from(name), &content) })?; Ok(loader.graph) } diff --git a/src/parse.rs b/src/parse.rs index 22ead3c..35fb93e 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -70,7 +70,7 @@ pub trait Loader { } impl<'text> Parser<'text> { - pub fn new(buf: &'text mut Vec<u8>) -> Parser<'text> { + pub fn new(buf: &'text [u8]) -> Parser<'text> { Parser { scanner: Scanner::new(buf), vars: Vars::default(), @@ -455,6 +455,12 @@ impl Loader for StringLoader { mod tests { use super::*; + fn test_case_buffer(test_case: &str) -> Vec<u8> { + let mut buf = test_case.as_bytes().to_vec(); + buf.push(0); + buf + } + fn test_for_line_endings(input: &[&str], test: fn(&str)) { let test_case_lf = input.join("\n"); let test_case_crlf = input.join("\r\n"); @@ -466,7 +472,7 @@ mod tests { #[test] fn parse_defaults() { test_for_line_endings(&["var = 3", "default a b$var c", ""], |test_case| { - let mut buf = test_case.as_bytes().to_vec(); + let mut buf = test_case_buffer(test_case); let mut parser = Parser::new(&mut buf); let default = match parser.read(&mut StringLoader {}).unwrap().unwrap() { Statement::Default(d) => d, @@ -478,7 +484,7 @@ mod tests { #[test] fn parse_dot_in_eval() { - let mut buf = "x = $y.z\n".as_bytes().to_vec(); + let mut buf = test_case_buffer("x = $y.z\n"); let mut parser = Parser::new(&mut buf); parser.read(&mut StringLoader {}).unwrap(); let x = parser.vars.get("x").unwrap(); @@ -487,7 +493,7 @@ mod tests { #[test] fn parse_dot_in_rule() { - let mut buf = "rule x.y\n command = x\n".as_bytes().to_vec(); + let mut buf = test_case_buffer("rule x.y\n command = x\n"); let mut parser = Parser::new(&mut buf); let stmt = parser.read(&mut StringLoader {}).unwrap().unwrap(); assert!(matches!( @@ -501,7 +507,7 @@ mod tests { #[test] fn parse_trailing_newline() { - let mut buf = "build$\n foo$\n : $\n touch $\n\n".as_bytes().to_vec(); + let mut buf = test_case_buffer("build$\n foo$\n : $\n touch $\n\n"); let mut parser = Parser::new(&mut buf); let stmt = parser.read(&mut StringLoader {}).unwrap().unwrap(); assert!(matches!( diff --git a/src/scanner.rs b/src/scanner.rs index 57f3f25..435984b 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -16,8 +16,10 @@ pub struct Scanner<'a> { } impl<'a> Scanner<'a> { - pub fn new(buf: &'a mut Vec<u8>) -> Self { - buf.push(0); + pub fn new(buf: &'a [u8]) -> Self { + if !buf.ends_with(b"\0") { + panic!("Scanner requires nul-terminated buf"); + } Scanner { buf, ofs: 0, diff --git a/src/task.rs b/src/task.rs index d2d7d6a..ba86906 100644 --- a/src/task.rs +++ b/src/task.rs @@ -42,7 +42,8 @@ fn read_depfile(path: &Path) -> anyhow::Result<Vec<String>> { Ok(b) => b, Err(e) => bail!("read {}: {}", path.display(), e), }; - let mut scanner = Scanner::new(&mut bytes); + bytes.push(0); + let mut scanner = Scanner::new(&bytes); let parsed_deps = depfile::parse(&mut scanner) .map_err(|err| anyhow!(scanner.format_parse_error(path, err)))?; // TODO verify deps refers to correct output |