Skip to content

Commit 83fe6e4

Browse files
committed
Use iterators instead of raw offsets in Windows argument parser
1 parent 55420f0 commit 83fe6e4

File tree

1 file changed

+45
-49
lines changed

1 file changed

+45
-49
lines changed

src/libstd/sys/windows/args.rs

+45-49
Original file line numberDiff line numberDiff line change
@@ -55,38 +55,35 @@ unsafe fn parse_lp_cmd_line<F: Fn() -> OsString>(lp_cmd_line: *const u16, exe_na
5555
const QUOTE: u16 = '"' as u16;
5656
const TAB: u16 = '\t' as u16;
5757
const SPACE: u16 = ' ' as u16;
58-
let mut in_quotes = false;
59-
let mut was_in_quotes = false;
60-
let mut backslash_count: usize = 0;
6158
let mut ret_val = Vec::new();
62-
let mut cur = Vec::new();
6359
if lp_cmd_line.is_null() || *lp_cmd_line == 0 {
6460
ret_val.push(exe_name());
6561
return ret_val;
6662
}
67-
let mut i = 0;
63+
let mut cmd_line = {
64+
let mut end = 0;
65+
while *lp_cmd_line.offset(end) != 0 {
66+
end += 1;
67+
}
68+
slice::from_raw_parts(lp_cmd_line, end as usize)
69+
};
6870
// The executable name at the beginning is special.
69-
match *lp_cmd_line {
71+
cmd_line = match cmd_line[0] {
7072
// The executable name ends at the next quote mark,
7173
// no matter what.
7274
QUOTE => {
73-
loop {
74-
i += 1;
75-
let c = *lp_cmd_line.offset(i);
76-
if c == 0 {
77-
ret_val.push(OsString::from_wide(
78-
slice::from_raw_parts(lp_cmd_line.offset(1), i as usize - 1)
79-
));
80-
return ret_val;
81-
}
82-
if c == QUOTE {
83-
break;
75+
let args = {
76+
let mut cut = cmd_line[1..].splitn(2, |&c| c == QUOTE);
77+
if let Some(exe) = cut.next() {
78+
ret_val.push(OsString::from_wide(exe));
8479
}
80+
cut.next()
81+
};
82+
if let Some(args) = args {
83+
args
84+
} else {
85+
return ret_val;
8586
}
86-
ret_val.push(OsString::from_wide(
87-
slice::from_raw_parts(lp_cmd_line.offset(1), i as usize - 1)
88-
));
89-
i += 1;
9087
}
9188
// Implement quirk: when they say whitespace here,
9289
// they include the entire ASCII control plane:
@@ -95,32 +92,30 @@ unsafe fn parse_lp_cmd_line<F: Fn() -> OsString>(lp_cmd_line: *const u16, exe_na
9592
// end of lpCmdLine is ignored."
9693
0...SPACE => {
9794
ret_val.push(OsString::new());
98-
i += 1;
95+
&cmd_line[1..]
9996
},
10097
// The executable name ends at the next whitespace,
10198
// no matter what.
10299
_ => {
103-
loop {
104-
i += 1;
105-
let c = *lp_cmd_line.offset(i);
106-
if c == 0 {
107-
ret_val.push(OsString::from_wide(
108-
slice::from_raw_parts(lp_cmd_line, i as usize)
109-
));
110-
return ret_val;
111-
}
112-
if c > 0 && c <= SPACE {
113-
break;
100+
let args = {
101+
let mut cut = cmd_line.splitn(2, |&c| c > 0 && c <= SPACE);
102+
if let Some(exe) = cut.next() {
103+
ret_val.push(OsString::from_wide(exe));
114104
}
105+
cut.next()
106+
};
107+
if let Some(args) = args {
108+
args
109+
} else {
110+
return ret_val;
115111
}
116-
ret_val.push(OsString::from_wide(
117-
slice::from_raw_parts(lp_cmd_line, i as usize)
118-
));
119-
i += 1;
120112
}
121-
}
122-
loop {
123-
let c = *lp_cmd_line.offset(i);
113+
};
114+
let mut cur = Vec::new();
115+
let mut in_quotes = false;
116+
let mut was_in_quotes = false;
117+
let mut backslash_count: usize = 0;
118+
for &c in cmd_line {
124119
match c {
125120
// backslash
126121
BACKSLASH => {
@@ -153,22 +148,18 @@ unsafe fn parse_lp_cmd_line<F: Fn() -> OsString>(lp_cmd_line: *const u16, exe_na
153148
backslash_count = 0;
154149
was_in_quotes = false;
155150
}
156-
0x00 => {
157-
cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
158-
// include empty quoted strings at the end of the arguments list
159-
if !cur.is_empty() || was_in_quotes || in_quotes {
160-
ret_val.push(OsString::from_wide(&cur[..]));
161-
}
162-
break;
163-
}
164151
_ => {
165152
cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
166153
backslash_count = 0;
167154
was_in_quotes = false;
168155
cur.push(c);
169156
}
170157
}
171-
i += 1;
158+
}
159+
cur.extend(iter::repeat(b'\\' as u16).take(backslash_count));
160+
// include empty quoted strings at the end of the arguments list
161+
if !cur.is_empty() || was_in_quotes || in_quotes {
162+
ret_val.push(OsString::from_wide(&cur[..]));
172163
}
173164
ret_val
174165
}
@@ -267,5 +258,10 @@ mod tests {
267258
);
268259
chk(r#"EXE "a"""#, &["EXE", "a\""]);
269260
chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]);
261+
// quotes cannot be escaped in command names
262+
chk(r#""EXE" check"#, &["EXE", "check"]);
263+
chk(r#""EXE check""#, &["EXE check"]);
264+
chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]);
265+
chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]);
270266
}
271267
}

0 commit comments

Comments
 (0)