#![doc(html_root_url="https://docs.rs/shell-escape/0.1")]
use std::borrow::Cow;
use std::env;
pub fn escape(s: Cow<str>) -> Cow<str> {
if cfg!(unix) || env::var("MSYSTEM").is_ok() {
unix::escape(s)
} else {
windows::escape(s)
}
}
pub mod windows {
use std::borrow::Cow;
use std::iter::repeat;
pub fn escape(s: Cow<str>) -> Cow<str> {
let mut needs_escape = s.is_empty();
for ch in s.chars() {
match ch {
'"' | '\t' | '\n' | ' ' => needs_escape = true,
_ => {}
}
}
if !needs_escape {
return s
}
let mut es = String::with_capacity(s.len());
es.push('"');
let mut chars = s.chars().peekable();
loop {
let mut nslashes = 0;
while let Some(&'\\') = chars.peek() {
chars.next();
nslashes += 1;
}
match chars.next() {
Some('"') => {
es.extend(repeat('\\').take(nslashes * 2 + 1));
es.push('"');
}
Some(c) => {
es.extend(repeat('\\').take(nslashes));
es.push(c);
}
None => {
es.extend(repeat('\\').take(nslashes * 2));
break;
}
}
}
es.push('"');
es.into()
}
#[test]
fn test_escape() {
assert_eq!(escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
assert_eq!(escape("linker=gcc -L/foo -Wl,bar".into()),
r#""linker=gcc -L/foo -Wl,bar""#);
assert_eq!(escape(r#"--features="default""#.into()),
r#""--features=\"default\"""#);
assert_eq!(escape(r#"\path\to\my documents\"#.into()),
r#""\path\to\my documents\\""#);
assert_eq!(escape("".into()), r#""""#);
}
}
pub mod unix {
use std::borrow::Cow;
fn non_whitelisted(ch: char) -> bool {
match ch {
'a'...'z' | 'A'...'Z' | '0'...'9' | '-' | '_' | '=' | '/' | ',' | '.' | '+' => false,
_ => true,
}
}
pub fn escape(s: Cow<str>) -> Cow<str> {
if !s.is_empty() && !s.contains(non_whitelisted) {
return s;
}
let mut es = String::with_capacity(s.len() + 2);
es.push('\'');
for ch in s.chars() {
match ch {
'\'' | '!' => {
es.push_str("'\\");
es.push(ch);
es.push('\'');
}
_ => es.push(ch),
}
}
es.push('\'');
es.into()
}
#[test]
fn test_escape() {
assert_eq!(
escape("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_=/,.+".into()),
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_=/,.+"
);
assert_eq!(escape("--aaa=bbb-ccc".into()), "--aaa=bbb-ccc");
assert_eq!(escape("linker=gcc -L/foo -Wl,bar".into()), r#"'linker=gcc -L/foo -Wl,bar'"#);
assert_eq!(escape(r#"--features="default""#.into()), r#"'--features="default"'"#);
assert_eq!(escape(r#"'!\$`\\\n "#.into()), r#"''\'''\!'\$`\\\n '"#);
assert_eq!(escape("".into()), r#"''"#);
}
}