use crate::split_off_front_inplace_mut;
use crate::ByteStringSlice;
#[cfg(test)]
#[path="posix-test.rs"]
mod test;
enum PosixEscapeMode
{
Outer,
OuterSlash,
SingleQuote,
SingleQuoteSlash,
DoubleQuote,
DoubleQuoteSlash,
}
pub struct PosixShellWords<'a,T:?Sized+ByteStringSlice>(&'a mut [u8], ::std::marker::PhantomData<T>);
impl<'a, T: ?Sized + ByteStringSlice> PosixShellWords<'a, T>
{
pub(crate) fn new(input_bytes: &mut [u8]) -> PosixShellWords<T> {
PosixShellWords(input_bytes, ::std::marker::PhantomData::<T>)
}
}
impl<'a, T: ?Sized + ByteStringSlice + 'a> Iterator for PosixShellWords<'a, T>
{
type Item = &'a T;
fn next(&mut self) -> Option<&'a T> {
if self.0.len() == 0 {
return None;
}
let mut outpos = 0;
let mut endpos = self.0.len();
let mut mode = PosixEscapeMode::Outer;
for i in 0 .. self.0.len()
{
let byte = self.0[i];
let out = match mode
{
PosixEscapeMode::Outer => match byte
{
b' ' => { endpos = i; break; },
b'\t' | b'\n' | b'\r' => { endpos = i; break; },
b'\\' => {
mode = PosixEscapeMode::OuterSlash;
None
},
b'\'' => {
mode = PosixEscapeMode::SingleQuote;
None
},
b'"' => {
mode = PosixEscapeMode::DoubleQuote;
None
},
v @ _ => Some(v),
},
PosixEscapeMode::OuterSlash => {
mode = PosixEscapeMode::Outer;
match byte
{
v @ b' ' => Some(v),
v @ b'\t' => Some(v),
v @ b'\n' => Some(v),
v @ b'\r' => Some(v),
v @ b'\'' => Some(v),
v @ b'\"' => Some(v),
v @ b'\\' => Some(v),
b'n' => Some(b'\n'),
b'r' => Some(b'\r'),
b't' => Some(b'\t'),
_ => None, }},
PosixEscapeMode::SingleQuote => match byte
{
b'\\' => {
mode = PosixEscapeMode::SingleQuoteSlash;
None
},
b'\'' => {
mode = PosixEscapeMode::Outer;
None
},
v @ _ => Some(v),
},
PosixEscapeMode::SingleQuoteSlash => {
mode = PosixEscapeMode::SingleQuote;
match byte
{
v @ b'\'' => Some(v),
v @ b'\\' => Some(v),
_ => None, }},
PosixEscapeMode::DoubleQuote => match byte
{
b'\\' => {
mode = PosixEscapeMode::DoubleQuoteSlash;
None
},
b'"' => {
mode = PosixEscapeMode::Outer;
None
},
v @ _ => Some(v),
},
PosixEscapeMode::DoubleQuoteSlash => {
mode = PosixEscapeMode::DoubleQuote;
match byte
{
v @ b'\'' => Some(v),
v @ b'\"' => Some(v),
v @ b'\\' => Some(v),
b'n' => Some(b'\n'),
b'r' => Some(b'\r'),
b't' => Some(b'\t'),
_ => None, }},
};
if let Some(b) = out {
if outpos != i {
assert!(outpos < i);
self.0[i] = 0; self.0[outpos] = b;
}
outpos += 1;
}
}
while endpos < self.0.len() && self.0[endpos] == b' ' {
self.0[endpos] = 0;
endpos += 1;
}
let ret = &split_off_front_inplace_mut(&mut self.0, endpos)[..outpos];
Some( T::from_bytes(ret).expect("POSIX Word spliting caused UTF-8 inconsistency") )
}
}