summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Martin <evan.martin@gmail.com>2023-12-26 16:46:04 -0800
committerEvan Martin <evan.martin@gmail.com>2023-12-26 16:46:04 -0800
commit178bf19798a0e0454f53b5c3b4c3dc1a4dd97798 (patch)
treeea729fd30c014777a2109cf74aad801148805ae8
parent54eeb86a2a0ab5b622837ea1447dfdea892d8f26 (diff)
downloadn2-178bf19798a0e0454f53b5c3b4c3dc1a4dd97798.tar.gz
move around nul-termination of input files
-rw-r--r--src/depfile.rs1
-rw-r--r--src/load.rs14
-rw-r--r--src/parse.rs16
-rw-r--r--src/scanner.rs6
-rw-r--r--src/task.rs3
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