wild-2.0.2/.appveyor.yml010064400007650000120000000015331330306647300133430ustar0000000000000000os: Visual Studio 2015 environment: matrix: # Stable 64-bit MSVC - channel: stable target: x86_64-pc-windows-msvc # Nightly 32-bit MSVC - channel: nightly target: i686-pc-windows-msvc # Beta 32-bit GNU - channel: beta target: i686-pc-windows-gnu matrix: allow_failures: - channel: nightly - channel: beta install: - appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - rustup-init -yv --default-toolchain %channel% --default-host %target% - set PATH=%PATH%;%USERPROFILE%\.cargo\bin - rustc -vV - cargo -vV # Uses 'cargo test' to run tests and build. Alternatively, the project may call compiled programs # directly or perform other testing commands. Rust will automatically be placed in the PATH # environment variable. build: false test_script: - cargo test --all --verbose wild-2.0.2/.gitignore010070000007650000120000000000371320357620000126450ustar0000000000000000/target/ **/*.rs.bk Cargo.lock wild-2.0.2/.gitlab-ci.yml010064400007650000120000000005731323020205400133160ustar0000000000000000# This file is a template, and might need editing before it works on your project. # Official language image. Look for the different tagged releases at: # https://hub.docker.com/r/library/rust/tags/ image: "rust:latest" # Use cargo to test the project test:cargo: script: - rustc --version && cargo --version # Print version info for debugging - cargo test --verbose wild-2.0.2/Cargo.toml.orig010064400007650000120000000011571351515035100135600ustar0000000000000000[package] authors = ["Kornel "] categories = ["command-line-interface"] description = "Glob (wildcard) expanded command-line arguments on Windows" documentation = "https://docs.rs/wild" homepage = "https://crates.rs/crates/wild" keywords = ["wildcards", "glob", "windows", "shell", "CommandLineToArgvW"] license = "MIT" name = "wild" readme = "README.md" repository = "https://gitlab.com/kornelski/wild" version = "2.0.2" [badges] gitlab = { repository = "kornelski/wild" } appveyor = { repository = "pornel/wild" } [target.'cfg(windows)'.dependencies] glob = "0.3" [dev-dependencies] glob = "0.3" wild-2.0.2/Cargo.toml0000644000000022050000000000000100300ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g. crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "wild" version = "2.0.2" authors = ["Kornel "] description = "Glob (wildcard) expanded command-line arguments on Windows" homepage = "https://crates.rs/crates/wild" documentation = "https://docs.rs/wild" readme = "README.md" keywords = ["wildcards", "glob", "windows", "shell", "CommandLineToArgvW"] categories = ["command-line-interface"] license = "MIT" repository = "https://gitlab.com/kornelski/wild" [dev-dependencies.glob] version = "0.3" [target."cfg(windows)".dependencies.glob] version = "0.3" [badges.appveyor] repository = "pornel/wild" [badges.gitlab] repository = "kornelski/wild" wild-2.0.2/Cargo.toml.orig0000644000000022060000000000000107700ustar00# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] name = "wild" version = "2.0.2" authors = ["Kornel "] description = "Glob (wildcard) expanded command-line arguments on Windows" homepage = "https://crates.rs/crates/wild" documentation = "https://docs.rs/wild" readme = "README.md" keywords = ["wildcards", "glob", "windows", "shell", "CommandLineToArgvW"] categories = ["command-line-interface"] license = "MIT" repository = "https://gitlab.com/kornelski/wild" [dev-dependencies.glob] version = "0.3" [target."cfg(windows)".dependencies.glob] version = "0.3" [badges.appveyor] repository = "pornel/wild" [badges.gitlab] repository = "kornelski/wild" wild-2.0.2/LICENSE010064400007650000120000000020401336762447600117110ustar0000000000000000Copyright 2018 Kornel Lesiński Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. wild-2.0.2/README.md010064400007650000120000000030321334222356700121520ustar0000000000000000# [`Wild::args`](https://crates.rs/crates/wild) for [Rust](https://www.rust-lang.org) Allows Rust applications support wildcard arguments (`*foo*`, `file.???`, `*.log.[0-9]`, etc.) on command-line, uniformly on all platforms, including Windows. Unix shells automatically interpret wildcard arguments and pass them expanded (already converted to file names) to applications, but Windows' `cmd.exe` doesn't do that. For consistent cross-platform behavior, this crate emulates Unix-like expansion on Windows. You only need to use `wild::args()` instead of `std::env::args()`. It is more robust than using [`glob()`](https://crates.rs/crates/glob) on values from `std::env::args()`, because this crate is aware of argument quoting, and special characteres in quotes (`"*"`) are intentionally not expanded. The glob syntax on Windows is limited to `*`, `?`, and `[a-z]`/`[!a-z]` ranges, as supported by the glob crate. Parsing of quoted arguments precisely follows Windows' native syntax ([`CommandLineToArgvW`][1], specifically). [1]: https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-commandlinetoargvw ## Usage `wild::args()` is a drop-in replacement for `std::env::args()`. ```rust extern crate wild; fn main() { let args = wild::args(); println!("The args are: {:?}", args.collect::>()); } ``` ## Usage with [Clap](https://crates.rs/crates/clap) ```rust let matches = clap::App::new("your_app") .arg(…) .arg(…) .arg(…) // .get_matches(); change to: .get_matches_from(wild::args()); ``` wild-2.0.2/src/argsiter.rs010064400007650000120000000115521350566341500136570ustar0000000000000000use globiter::*; use std::ffi::OsString; use glob; use std::fmt; /// Windows replacement for `std::env::ArgsOs` #[cfg_attr(test, allow(dead_code))] pub struct ArgsOs { pub(crate) args: Option>, pub(crate) current_arg_globs: Option, } /// Windows replacement for `std::env::Args` pub struct Args { pub(crate) iter: ArgsOs, } fn first_non_error(iter: &mut I) -> Option where I: Iterator> { loop { match iter.next() { Some(Ok(item)) => return Some(item), None => return None, Some(Err(_)) => {}, } } } impl Iterator for Args { type Item = String; fn next(&mut self) -> Option { self.iter.next().map(|s| s.to_string_lossy().to_string()) } } impl Iterator for ArgsOs { type Item = OsString; fn next(&mut self) -> Option { let glob_options = glob::MatchOptions { case_sensitive: false, ..Default::default() }; match self.current_arg_globs.as_mut().and_then(first_non_error) { Some(path) => Some(path.into_os_string()), None => match self.args { Some(ref mut args) => match args.next() { // lossy: https://github.com/rust-lang-nursery/glob/issues/23 Some(arg) => if arg.contains_glob { match glob::glob_with(&arg.pattern.to_string_lossy(), glob_options) { Ok(mut glob_iter) => { let first_glob = first_non_error(&mut glob_iter); self.current_arg_globs = Some(glob_iter); match first_glob { Some(path) => Some(path.into_os_string()), None => { // non-matching patterns are passed as regular strings self.current_arg_globs = None; Some(arg.text) }, } } Err(_) => { // Invalid patterns are passed as regular strings Some(arg.text) }, } } else { // valid, but non-wildcard args passed as is, in order to avoid normalizing slashes Some(arg.text) }, None => None, // end of args }, None => None, // error: no args available at all }, } } } impl fmt::Debug for Args { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.iter.fmt(f) } } impl fmt::Debug for ArgsOs { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.args.as_ref().map(|args| args.fmt(f)) .unwrap_or_else(|| "".fmt(f)) } } #[test] fn finds_cargo_toml() { let cmd = "foo.exe _not_?a?_[f]ilename_ \"_not_?a?_[p]attern_\" Cargo.tom?".chars().map(|c| c as u16).collect::>(); let args = GlobArgs::new(Box::leak(cmd.into_boxed_slice())); let iter = Args { iter: ArgsOs { args: Some(args), current_arg_globs: None, }, }; assert_eq!("\"foo.exe _not_?a?_[f]ilename_ \\\"_not_?a?_[p]attern_\\\" Cargo.tom?\"", format!("{:?}", iter)); let args: Vec<_> = iter.collect(); assert_eq!(4, args.len()); assert_eq!("foo.exe", &args[0]); assert_eq!("_not_?a?_[f]ilename_", &args[1]); assert_eq!("_not_?a?_[p]attern_", &args[2]); assert_eq!("Cargo.toml", &args[3]); } #[test] fn unquoted_slashes_unchanged() { let cmd = r#"foo.exe //// .. ./ \\\\"#.chars().map(|c| c as u16).collect::>(); let args = GlobArgs::new(Box::leak(cmd.into_boxed_slice())); let iter = Args { iter: ArgsOs { args: Some(args), current_arg_globs: None, }, }; let args: Vec<_> = iter.collect(); assert_eq!(5, args.len()); assert_eq!("foo.exe", &args[0]); assert_eq!("////", &args[1]); assert_eq!("..", &args[2]); assert_eq!("./", &args[3]); assert_eq!(r#"\\\\"#, &args[4]); } #[test] fn finds_readme_case_insensitive() { let cmd = "foo.exe _not_?a?_[f]ilename_ \"_not_?a?_[p]attern_\" read*.MD".chars().map(|c| c as u16).collect::>(); let args = GlobArgs::new(Box::leak(cmd.into_boxed_slice())); let iter = ArgsOs { args: Some(args), current_arg_globs: None, }; let args: Vec<_> = iter.map(|c| c.to_string_lossy().to_string()).collect(); assert_eq!(4, args.len()); assert_eq!("foo.exe", &args[0]); assert_eq!("_not_?a?_[f]ilename_", &args[1]); assert_eq!("_not_?a?_[p]attern_", &args[2]); assert_eq!("README.md", &args[3]); } wild-2.0.2/src/globiter.rs010064400007650000120000000036631336762447500136630ustar0000000000000000use std::ffi::OsString; use parser; use std::fmt; pub(crate) struct ArgOs { pub pattern: OsString, pub text: OsString, pub contains_glob: bool, } /// Iterator retuning glob-escaped arguments. Call `args()` to obtain it. #[must_use] pub(crate) struct GlobArgs<'a> { line: &'a [u16], } impl<'a> fmt::Debug for GlobArgs<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { String::from_utf16_lossy(self.line).fmt(f) } } #[cfg(windows)] use std::os::windows::ffi::OsStringExt; /// This is used only in tests on non-Windows #[cfg(not(windows))] trait LossyOsStringExt { fn from_wide(wide: &[u16]) -> OsString { OsString::from(String::from_utf16_lossy(wide)) } } #[cfg(not(windows))] impl LossyOsStringExt for OsString {} impl<'a> Iterator for GlobArgs<'a> { type Item = ArgOs; fn next(&mut self) -> Option { let state = (vec![], vec![], false); let (state, rest) = parser::next_arg(self.line, state, |&mut (ref mut arg, ref mut text, ref mut contains_glob), c, quoted| { text.push(c); match c as u8 { b'?' | b'*' | b'[' | b']' if c < 256 => { if quoted { arg.push(u16::from(b'[')); arg.push(c); arg.push(u16::from(b']')); } else { arg.push(c); *contains_glob = true; } }, _ => arg.push(c), }; }); self.line = rest; state.map(|(pattern, text, contains_glob)| ArgOs { pattern: OsString::from_wide(&pattern), text: OsString::from_wide(&text), contains_glob, }) } } impl<'a> GlobArgs<'a> { /// UTF-16/UCS2 string from `GetCommandLineW` #[allow(dead_code)] pub(crate) fn new(line: &'a [u16]) -> Self { Self { line } } } wild-2.0.2/src/lib.rs010064400007650000120000000162511334222622100125730ustar0000000000000000//! Emulates glob (wildcard) argument expansion on Windows. No-op on other platforms. //! //! Unix shells expand command-line arguments like `a*`, `file.???` and pass them expanded to applications. //! On Windows `cmd.exe` doesn't do that, so this crate emulates the expansion there. //! Instead of `std::env::args()` use `wild::args()`. //! //! The glob syntax on Windows is limited to `*`, `?`, and `[a-z]`/`[!a-z]` ranges. //! Glob characters in quotes (`"*"`) are not expanded. //! //! Parsing of quoted arguments precisely follows Windows native syntax (`CommandLineToArgvW`, specifically) //! with all its weirdness. //! //! ## Usage //! //! Use `wild::args()` instead of `std::env::args()` (or `wild::args_os()` instead of `std::env::args_os()`). //! //! If you use [Clap](https://crates.rs/crates/clap), use `.get_matches_from(wild::args())` instead of `.get_matches()`. #[cfg(any(test,windows))] extern crate glob; #[cfg(any(test,windows))] mod parser; #[cfg(any(test,windows))] mod argsiter; #[cfg(windows)] pub use argsiter::*; #[cfg(any(test,windows))] mod globiter; /// Iterator of arguments. Equivalent to `std::env::Args`. See `args()` for details. /// /// On unix it's an alias for `std::env::Args`. /// On Windows it's a custom iterator that implements glog expansion. #[cfg(not(windows))] pub type Args = std::env::Args; #[cfg(not(windows))] pub type ArgsOs = std::env::ArgsOs; /// Returns an iterator of glob-expanded command-line arguments. Equivalent of `std::env::args()`. /// /// On non-Windows platforms it returns `env::args()` as-is, /// assuming expansion has already been done by the shell. /// /// On Windows it emulates the glob expansion itself. /// The iterator will parse arguments incrementally and access /// the file system as it parses. This allows reading potentially huge lists of /// filenames, but it's not an atomic snapshot (use `.collect()` if you need that). #[cfg(not(windows))] pub fn args() -> Args { std::env::args() } #[cfg(not(windows))] pub fn args_os() -> ArgsOs { std::env::args_os() } /// Returns an iterator of glob-expanded command-line arguments. Equivalent of `std::env::args()`. /// /// On Windows it emulates the glob expansion itself. /// The iterator will parse arguments incermentally and access /// the file system as it parses. This allows reading potentially huge lists of /// filenames, but it's not an atomic snapshot (use `.collect()` if you need that). /// /// On non-Windows platforms it returns `env::args()` as-is, /// assuming expansion has already been done by the shell. #[cfg(windows)] pub fn args() -> Args { Args { iter: args_os(), } } /// Same as `args()`, but returns `OsString` #[cfg(windows)] pub fn args_os() -> ArgsOs { ArgsOs { args: globs(), current_arg_globs: None, } } /// Parses `GetCommandLineW` the same way as `CommandLineToArgvW`, /// but escapes quoted glob metacharacters `*`, `?`, `[`, `]` using `[*]` syntax. /// /// Windows-only, unstable. #[cfg(windows)] #[inline] fn globs() -> Option> { raw_command_line().map(|cmd| globiter::GlobArgs::new(cmd)) } #[cfg(windows)] extern "system" { fn GetCommandLineW() -> *const u16; } #[cfg(windows)] fn raw_command_line() -> Option<&'static [u16]> { unsafe { let line_ptr = GetCommandLineW(); if line_ptr.is_null() { return None; } let mut len = 0; while *line_ptr.offset(len as isize) != 0 { len += 1; } Some(std::slice::from_raw_parts(line_ptr, len)) } } #[cfg(test)] fn parsed(s: &str) -> String { let t: Vec<_> = s.encode_utf16().collect(); let args: Vec<_> = globiter::GlobArgs::new(&t) .map(|s| s.pattern.to_string_lossy().to_string()) .collect(); args.join(";") } #[cfg(test)] fn unquoted(s: &str) -> String { let t: Vec<_> = s.encode_utf16().collect(); let args: Vec<_> = globiter::GlobArgs::new(&t) .map(|s| s.text.to_string_lossy().to_string()) .collect(); args.join(";") } #[test] #[cfg(windows)] fn test_actual_args() { assert!(globs().expect("args found").count() >= 1); } #[test] fn test_parse_1() { assert_eq!(r#"漢字"#, parsed("漢字")); assert_eq!(r#"漢字"#, parsed("\"漢字\"")); assert_eq!(r#"漢\字"#, parsed("\"漢\\字\"")); assert_eq!(r#"unquoted"#, parsed("unquoted")); assert_eq!(r#"*"#, parsed("*")); assert_eq!(r#"?"#, parsed("?")); assert_eq!(r#"quoted"#, parsed("\"quoted\"")); assert_eq!(r#"quoted"#, unquoted("\"quoted\"")); assert_eq!(r#"[*]"#, parsed("\"*\"")); assert_eq!(r#"*"#, unquoted("\"*\"")); assert_eq!(r#"[?]"#, parsed("\"?\"")); assert_eq!(r#"?"#, unquoted("\"?\"")); assert_eq!(r#"[]]"#, parsed("\"]\"")); assert_eq!(r#"]"#, unquoted("\"]\"")); assert_eq!(r#"quo"ted"#, parsed(r#" "quo\"ted" "#)); // backslash can escape quotes assert_eq!(r#"quo"ted? "#, parsed(r#" "quo""ted?" "#)); // and quote can escape quotes assert_eq!(r#"unquo"ted"#, parsed(r#" unquo\"ted "#)); // backslash can escape quotes, even outside quotes assert_eq!(r#"unquoted?"#, parsed(r#" unquo""ted? "#)); // quote escaping does not work outside quotes assert_eq!(r#"""#, parsed(r#""""""#)); // quote escapes quote in quoted string assert_eq!(r#"""#, parsed(r#"""""""#)); assert_eq!(r#""""#, parsed(r#""""""""#)); assert_eq!(r#""""#, parsed(r#"""""""""#)); // """ == "X", """""" = "X""X" assert_eq!(r#""""#, parsed(r#""""""""""#)); assert_eq!(r#"""""#, parsed(r#"""""""""""#)); assert_eq!(r#"\\server\share\path with spaces"#, parsed(r#""\\server\share\path with spaces""#)); // lone double backslash is not special assert_eq!("aba", parsed(r#""a"b"a""#)); // quotes can go in and out assert_eq!("abac", parsed(r#""a"b"a"c"#)); // quotes can go in and out assert_eq!("c*a[*]b*a[*]c*", parsed(r#"c*"a*"b*"a*"c*"#)); // quotes can go in and out assert_eq!(r#"\\"#, parsed(r#"\\\\""#)); assert_eq!(r#"?\\?"#, parsed(r#"?\\\\"?"#)); // unpaired quote is interpreted like an end quote assert_eq!(r#"\""#, parsed(r#"\\\""#)); assert_eq!(r#"\"[a-z]"#, parsed(r#"\\\"[a-z]"#)); assert_eq!(" ", parsed(r#"" "#)); // unterminated quotes are OK assert_eq!("", parsed(r#""""#)); assert_eq!(r#"[a-c][d-z]"#, parsed(r#"[a-c]""[d-z]"#)); assert_eq!(r#"[[]a-c[]]"[d-z]"#, parsed(r#""[a-c]""[d-z]""#)); assert_eq!("", parsed(r#"""#)); assert_eq!("x", parsed(r#"x""#)); assert_eq!(r#"\"#, parsed(r"\")); assert_eq!(r#"\\"#, parsed(r"\\")); assert_eq!(r#"\\\"#, parsed(r"\\\")); assert_eq!(r#"\\\\"#, parsed(r"\\\\")); assert_eq!(r#"\\a"#, parsed(r#"\\\\"a"#)); assert_eq!(r#"\\a"#, parsed(r#"\\\\"a""#)); assert_eq!(r#"¥¥"#, parsed(r#"¥¥""#)); // in Unicode this isn't backslash } #[test] fn test_parse_multi() { assert_eq!(r#"unquoted;quoted"#, parsed("unquoted \"quoted\"")); assert_eq!(r#"quo"ted;quo"ted "#, parsed(r#" "quo\"ted" "quo""ted" "#)); assert_eq!(r#"unquo"ted;""#, parsed(r#" unquo\"ted """"""#)); assert_eq!(r#"a;a"#, parsed(r#"a"" a"#)); assert_eq!(r#"a";a"#, parsed(r#"a""" a"#)); assert_eq!(r#"\\;\""#, parsed(r#"\\\\" \\\" "#)); assert_eq!("x; ", parsed(r#" x " "#)); } wild-2.0.2/src/parser.rs010064400007650000120000000102051323020060600133050ustar0000000000000000 #[derive(Debug)] enum State { BetweenArgs, InArg(bool), OnQuote, Backslashes(usize, bool), } /// Given UCS2/potentially-broken-UTF-16 string parses one argument, following /// the absolutely bizarre quoting rules of `CommandLineToArgvW`, and returns /// parsed argument as well as a slice of the remaining arguments. /// /// Calling this repeatedly until rest is empty will parse all arguments. /// /// `arg` is an empty pre-allocated argument to be returned, and the callback adds a new code unit to it. /// The last callback argument is whether the unit was quoted or not. /// /// This parses u16 code units, rather than code points. /// This allows supporting unpaired surrogates and ensures they won't "eat" any control characters. pub fn next_arg(line: &[u16], mut arg: ArgVec, push: AddC) -> (Option, &[u16]) where AddC: Fn(&mut ArgVec, u16, bool), { use self::State::*; let mut state = BetweenArgs; for (i, &cu) in line.iter().enumerate() { state = match state { BetweenArgs => match cu { c if c == u16::from(b' ') => BetweenArgs, c if c == u16::from(b'"') => InArg(true), c if c == u16::from(b'\\') => Backslashes(1, false), c => { push(&mut arg, c, false); InArg(false) }, }, InArg(quoted) => match cu { c if c == u16::from(b'\\') => Backslashes(1, quoted), c if quoted && c == u16::from(b'"') => OnQuote, c if !quoted && c == u16::from(b'"') => InArg(true), c if !quoted && c == u16::from(b' ') => { return (Some(arg), &line[i+1..]); }, c => { push(&mut arg, c, quoted); InArg(quoted) }, }, OnQuote => match cu { c if c == u16::from(b'"') => { // In quoted arg "" means literal quote and the end of the quoted string (but not arg) push(&mut arg, u16::from(b'"'), true); InArg(false) }, c if c == u16::from(b' ') => { return (Some(arg), &line[i+1..]); }, c => { push(&mut arg, c, false); InArg(false) }, }, Backslashes(count, quoted) => match cu { c if c == u16::from(b'\\') => Backslashes(count + 1, quoted), c if c == u16::from(b'"') => { // backslashes followed by a quotation mark are treated as pairs of protected backslashes for _ in 0..count/2 { push(&mut arg, u16::from(b'\\'), quoted); } if count & 1 != 0 { // An odd number of backslashes is treated as followed by a protected quotation mark. push(&mut arg, u16::from(b'"'), quoted); InArg(quoted) } else if quoted { // An even number of backslashes is treated as followed by a word terminator. return (Some(arg), &line[i+1..]); } else { InArg(quoted) } }, c => { // A string of backslashes not followed by a quotation mark has no special meaning. for _ in 0..count { push(&mut arg, u16::from(b'\\'), quoted); } push(&mut arg, c, quoted); InArg(quoted) }, }, } } let arg = match state { BetweenArgs => None, OnQuote | InArg(..) => Some(arg), Backslashes(count, quoted) => { // A string of backslashes not followed by a quotation mark has no special meaning. for _ in 0..count { push(&mut arg, u16::from(b'\\'), quoted); } Some(arg) }, }; (arg, &line[..0]) } wild-2.0.2/.cargo_vcs_info.json0000644000000001120000000000000120250ustar00{ "git": { "sha1": "bb3ffd6bf97436c0363a7f63fb00cc1620272ee9" } }