use core::arch::asm;
mod sys;
use sys::{PEB, PWSTR};
const BACKSLASH: u16 = b'\\' as u16;
const QUOTE: u16 = b'"' as u16;
const TAB: u16 = b'\t' as u16;
const SPACE: u16 = b' ' as u16;
pub type StaticArgsWindows = ArgsWindows<'static>;
pub struct ArgsWindows<'a> {
code_units: &'a [u16],
first: bool,
index: usize,
}
impl<'a> ArgsWindows<'a> {
pub const unsafe fn new(code_units: &'a [u16]) -> Self {
Self {
code_units,
first: true,
index: 0,
}
}
pub const fn empty() -> Self {
Self {
code_units: &[],
first: false,
index: 0,
}
}
pub fn skip_whitespace(&mut self) {
for point in &self.code_units[self.index..] {
if !(*point == SPACE || *point == TAB) {
break;
}
self.index += 1
}
}
}
impl<'a> Iterator for ArgsWindows<'a> {
type Item = &'a [u16];
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.code_units.len() {
return None;
}
if self.first {
self.first = false;
let mut quoted = false;
let mut index = 0usize;
for point in self.code_units {
match *point {
QUOTE => quoted = !quoted,
SPACE | TAB if !quoted => {
break;
}
_ => {}
}
index += 1;
}
self.index = index;
self.skip_whitespace();
return Some(&self.code_units[1..index - 1]);
}
let mut quoted = false;
let initial_index = self.index;
let mut index = self.index;
let mut points_iter = self.code_units[self.index..].iter();
while let Some(point) = points_iter.next() {
match *point {
SPACE | TAB if !quoted => {
break;
}
BACKSLASH => {
let backlash_count = 1;
if points_iter.next() == Some("E) {
} else {
}
}
QUOTE if quoted => match points_iter.next() {
Some("E) => {
}
Some(_) => quoted = false,
None => break,
},
QUOTE => quoted = true,
_ => {}
}
index += 1
}
self.index = index;
self.skip_whitespace();
return Some(&self.code_units[initial_index..index]);
let mut quoted = false;
let raw = self.code_units;
let mut iter = raw.iter().enumerate();
let mut final_index = 0;
while let Some((index, w)) = iter.next() {
let w = *w;
match w {
SPACE | TAB if !quoted => {
final_index = index;
break;
}
BACKSLASH => {
}
QUOTE if quoted => match iter.next() {
Some((_, "E)) => {
iter.next();
}
Some(_) => quoted = false,
None => break,
},
QUOTE => quoted = true,
_ => continue,
}
}
self.index += 1;
Some(&raw[self.index..final_index])
}
}
static mut COMMAND_LINE_BUFFER: PWSTR = PWSTR::null();
#[used]
#[link_section = ".CRT$XCU"]
static ARGS_INIT: extern "C" fn() = {
extern "C" fn init_args() {
let peb: *mut PEB;
unsafe {
asm!(
"mov {}, gs:[0x60]",
out(reg) peb,
options(pure, nomem, nostack)
);
}
unsafe { COMMAND_LINE_BUFFER = (*(*peb).ProcessParameters).CommandLine.Buffer }
}
init_args
};
#[cfg(all(target_os = "windows"))]
pub fn static_args_windows() -> StaticArgsWindows {
if unsafe { COMMAND_LINE_BUFFER.is_null() } {
ArgsWindows::empty()
} else {
unsafe { ArgsWindows::new(COMMAND_LINE_BUFFER.as_wide()) }
}
}