summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Martin <evan.martin@gmail.com>2024-01-08 10:57:35 -0800
committerEvan Martin <evan.martin@gmail.com>2024-01-08 11:08:47 -0800
commit738e5641f169d96ac634c9437373a9ce4f1f6c61 (patch)
tree9b71e6f1de5a41425d41461be7e351e87d3b163e
parent81ebd8649dd2fd7de8fa8dd06c13ee5b62efb912 (diff)
downloadn2-738e5641f169d96ac634c9437373a9ce4f1f6c61.tar.gz
allow windows drive letters in depfiles
See bug report context in #98. From a patch from Tobias Hieta <tobias.hieta@ubisoft.com>.
-rw-r--r--src/depfile.rs46
1 files changed, 39 insertions, 7 deletions
diff --git a/src/depfile.rs b/src/depfile.rs
index 33144c6..7ee5493 100644
--- a/src/depfile.rs
+++ b/src/depfile.rs
@@ -31,12 +31,15 @@ fn skip_spaces(scanner: &mut Scanner) -> ParseResult<()> {
}
/// Read one path from the input scanner.
+/// Note: treats colon as a valid character in a path because of Windows-style
+/// paths, but this means that the inital `output: ...` path will include the
+/// trailing colon.
fn read_path<'a>(scanner: &mut Scanner<'a>) -> ParseResult<Option<&'a str>> {
skip_spaces(scanner)?;
let start = scanner.ofs;
loop {
match scanner.read() {
- '\0' | ' ' | ':' | '\r' | '\n' => {
+ '\0' | ' ' | '\r' | '\n' => {
scanner.back();
break;
}
@@ -64,7 +67,13 @@ pub fn parse<'a>(scanner: &mut Scanner<'a>) -> ParseResult<Deps<'a>> {
Some(o) => o,
};
scanner.skip_spaces();
- scanner.expect(':')?;
+ let target = match target.strip_suffix(':') {
+ None => {
+ scanner.expect(':')?;
+ target
+ }
+ Some(target) => target,
+ };
let mut deps = Vec::new();
while let Some(p) = read_path(scanner)? {
deps.push(p);
@@ -79,16 +88,19 @@ pub fn parse<'a>(scanner: &mut Scanner<'a>) -> ParseResult<Deps<'a>> {
#[cfg(test)]
mod tests {
- use std::path::Path;
-
use super::*;
+ use std::path::Path;
- fn must_parse(buf: &mut Vec<u8>) -> Deps {
+ fn try_parse(buf: &mut Vec<u8>) -> Result<Deps, String> {
buf.push(0);
let mut scanner = Scanner::new(buf);
- match parse(&mut scanner) {
+ parse(&mut scanner).map_err(|err| scanner.format_parse_error(Path::new("test"), err))
+ }
+
+ fn must_parse(buf: &mut Vec<u8>) -> Deps {
+ match try_parse(buf) {
Err(err) => {
- println!("{}", scanner.format_parse_error(Path::new("test"), err));
+ println!("{}", err);
panic!("failed parse");
}
Ok(d) => d,
@@ -153,4 +165,24 @@ mod tests {
assert_eq!(deps.target, "build/browse.o");
assert_eq!(deps.deps.len(), 1);
}
+
+ #[test]
+ fn test_parse_windows_dep_path() {
+ let mut file = b"odd/path.o: C:/odd\\path.c".to_vec();
+ let deps = must_parse(&mut file);
+ assert_eq!(deps.target, "odd/path.o");
+ assert_eq!(deps.deps[0], "C:/odd\\path.c");
+ assert_eq!(deps.deps.len(), 1);
+ }
+
+ #[test]
+ fn test_parse_missing_colon() {
+ let mut file = b"foo bar".to_vec();
+ let err = try_parse(&mut file).unwrap_err();
+ assert!(
+ err.starts_with("parse error: expected ':'"),
+ "expected parse error, got {:?}",
+ err
+ );
+ }
}