1#![cfg_attr(docsrs, feature(doc_cfg))]
2#[cfg(any(test, windows))]
22pub mod parser;
23
24#[cfg(any(test, windows))]
25mod globiter;
26
27#[cfg(any(test, windows))]
28mod argsiter;
29#[cfg(windows)]
30pub use crate::argsiter::*;
31
32#[cfg(not(windows))]
37pub type Args = std::env::Args;
38
39#[cfg(not(windows))]
41pub type ArgsOs = std::env::ArgsOs;
42
43#[cfg(not(windows))]
53#[must_use]
54pub fn args() -> Args {
55 std::env::args()
56}
57
58#[cfg(not(windows))]
59#[must_use]
60pub fn args_os() -> ArgsOs {
61 std::env::args_os()
62}
63
64#[cfg(windows)]
74#[must_use]
75pub fn args() -> Args {
76 Args { iter: args_os() }
77}
78
79#[cfg(windows)]
81#[must_use]
82pub fn args_os() -> ArgsOs {
83 ArgsOs::from_raw_command_line(raw_command_line())
84}
85
86#[cfg(windows)]
87extern "system" {
88 fn GetCommandLineW() -> *const u16;
89}
90
91#[cfg(windows)]
92fn raw_command_line() -> &'static [u16] {
93 unsafe {
94 let line_ptr = GetCommandLineW();
95 if line_ptr.is_null() {
96 return &[];
97 }
98 let mut len = 0;
99 while *line_ptr.add(len) != 0 {
100 len += 1;
101 }
102 std::slice::from_raw_parts(line_ptr, len)
103 }
104}
105
106#[cfg(test)]
107fn parsed(s: &str) -> String {
108 let t: Vec<_> = s.encode_utf16().collect();
109 let args: Vec<_> = globiter::GlobArgs::new(&t)
110 .map(|s| s.pattern.map(|p| format!("<glob {p}>")).unwrap_or(s.text.to_string_lossy().into_owned()))
111 .collect();
112 args.join(";")
113}
114
115#[cfg(test)]
116fn unquoted(s: &str) -> String {
117 let t: Vec<_> = s.encode_utf16().collect();
118 let args: Vec<_> = globiter::GlobArgs::new(&t)
119 .map(|s| s.text.to_string_lossy().to_string())
120 .collect();
121 args.join(";")
122}
123
124#[test]
125fn test_actual_args() {
126 assert!(args_os().count() >= 1);
127}
128
129#[test]
130fn test_parse_1() {
131 assert_eq!(r#"漢字"#, parsed("漢字"));
132 assert_eq!(r#"漢字"#, parsed("\"漢字\""));
133 assert_eq!(r#"漢\字"#, parsed("\"漢\\字\""));
134 assert_eq!(r#"unquoted"#, parsed("unquoted"));
135 assert_eq!(r#"<glob *>"#, parsed("*"));
136 assert_eq!(r#"<glob ?>"#, parsed("?"));
137 assert_eq!(r#"quoted"#, parsed("\"quoted\""));
138 assert_eq!(r#"quoted"#, unquoted("\"quoted\""));
139 assert_eq!(r#"*"#, unquoted("\"*\""));
140 assert_eq!(r#"?"#, unquoted("\"?\""));
141 assert_eq!(r#"]"#, unquoted("\"]\""));
142 assert_eq!(r#"quo"ted"#, parsed(r#" "quo\"ted" "#)); assert_eq!(r#"<glob quo"ted? >"#, parsed(r#" "quo""ted?" "#)); assert_eq!(r#"unquo"ted"#, parsed(r#" unquo\"ted "#)); assert_eq!(r#"<glob unquoted?>"#, parsed(r#" unquo""ted? "#)); assert_eq!(r#"""#, parsed(r#""""""#)); assert_eq!(r#"""#, parsed(r#"""""""#));
148 assert_eq!(r#""""#, parsed(r#""""""""#));
149 assert_eq!(r#""""#, parsed(r#"""""""""#)); assert_eq!(r#""""#, parsed(r#""""""""""#));
151 assert_eq!(r#"""""#, parsed(r#"""""""""""#));
152 assert_eq!(r#"\\server\share\path with spaces"#, parsed(r#""\\server\share\path with spaces""#)); assert_eq!("aba", parsed(r#""a"b"a""#)); assert_eq!("abac", parsed(r#""a"b"a"c"#)); assert_eq!(r#"\\"#, parsed(r#"\\\\""#));
156 assert_eq!(r#"<glob ?\\?>"#, parsed(r#"?\\\\"?"#)); assert_eq!(r#"\""#, parsed(r#"\\\""#));
158 assert_eq!(r#"<glob \"[a-z]>"#, parsed(r#"\\\"[a-z]"#));
159 assert_eq!(" ", parsed(r#"" "#)); assert_eq!("", parsed(r#""""#));
161 assert_eq!(r#"<glob [a-c][d-z]>"#, parsed(r#"[a-c]""[d-z]"#));
162 assert_eq!("", parsed(r#"""#));
163 assert_eq!("x", parsed(r#"x""#));
164 assert_eq!(r#"\;x;y"#, parsed(r"\ x y"));
165 assert_eq!(r#"\\;x;y"#, parsed(r"\\ x y"));
166 assert_eq!(r#"a\\\;x;y"#, parsed(r"a\\\ x y"));
167 assert_eq!(r#"<glob a\\\*>;x;y"#, parsed(r"a\\\* x y"));
168 assert_eq!(r#"a\\\ x;y"#, parsed(r#""a\\\ x" y"#));
169 assert_eq!(r#"\"#, parsed(r"\"));
170 assert_eq!(r#"\\"#, parsed(r"\\"));
171 assert_eq!(r#"\\\"#, parsed(r"\\\"));
172 assert_eq!(r#"\\\\"#, parsed(r"\\\\"));
173 assert_eq!(r#"\\a"#, parsed(r#"\\\\"a"#));
174 assert_eq!(r#"\\a"#, parsed(r#"\\\\"a""#));
175 assert_eq!(r#"¥¥"#, parsed(r#"¥¥""#)); assert_eq!(r#".\path\to\folder\;-rf"#, parsed(r#".\path\to\folder\ -rf"#));
177}
178
179#[test]
180#[cfg(not(feature = "glob-quoted-on-windows"))]
181fn test_unquoted() {
182 assert_eq!(r#"*"#, parsed("\"*\""));
183 assert_eq!(r#"?"#, parsed("\"?\""));
184 assert_eq!(r#"]"#, parsed("\"]\""));
185 assert_eq!("<glob c*a[*]b*a[*]c*>", parsed(r#"c*"a*"b*"a*"c*"#)); assert_eq!(r#"<glob [[]a-c[]]"[d-z]>"#, parsed(r#""[a-c]""[d-z]""#));
187}
188
189#[test]
190#[cfg(feature = "glob-quoted-on-windows")]
191fn test_unquoted() {
192 assert_eq!(r#"<glob *>"#, parsed("\"*\""));
193 assert_eq!(r#"<glob ?>"#, parsed("\"?\""));
194 assert_eq!(r#"<glob ]>"#, parsed("\"]\""));
195 assert_eq!("<glob c*a*b*a*c*>", parsed(r#"c*"a*"b*"a*"c*"#)); assert_eq!(r#"<glob [a-c]"[d-z]>"#, parsed(r#""[a-c]""[d-z]""#));
197}
198
199#[test]
200fn test_parse_multi() {
201 assert_eq!(r#"unquoted;quoted"#, parsed("unquoted \"quoted\""));
202 assert_eq!(r#"quo"ted;quo"ted "#, parsed(r#" "quo\"ted" "quo""ted" "#));
203 assert_eq!(r#"unquo"ted;""#, parsed(r#" unquo\"ted """"""#));
204 assert_eq!(r#"a;a"#, parsed(r#"a"" a"#));
205 assert_eq!(r#"a";a"#, parsed(r#"a""" a"#));
206 assert_eq!(r#"\\;\""#, parsed(r#"\\\\" \\\" "#));
207 assert_eq!("x; ", parsed(r#" x " "#));
208}