Skip to content

Commit

Permalink
escape: add quote detection
Browse files Browse the repository at this point in the history
  • Loading branch information
trou committed Nov 3, 2024
1 parent 1d78306 commit 7909f90
Showing 1 changed file with 34 additions and 8 deletions.
42 changes: 34 additions & 8 deletions src/escapeapp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum EscType {
}

const SHELL_CHARS: &[u8; 4] = b"`$\"\\";

// Note that bash is crazy regarding '!'
// echo "\!" will output \!
// ref: https://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html
Expand Down Expand Up @@ -65,6 +66,7 @@ impl SliceEsc for [u8] {
pub struct EscapeApplet {
esc_type: EscType,
no_quote: bool,
no_detect: bool,
multiline: bool,
}

Expand All @@ -80,6 +82,7 @@ impl Applet for EscapeApplet {
Command::new(self.command())
.about(self.description())
.arg(arg!(-m --multiline "expect multiline string, do not trim input"))
.arg(arg!(-d --"no-detect" "do not detect surrounding quotes"))
.arg(arg!(-n --"no-quote" "do not wrap output in quotes"))
.arg(
arg!(-t --type [type] "type of escape")
Expand All @@ -93,6 +96,7 @@ impl Applet for EscapeApplet {
Ok(Box::new(Self {
esc_type: args.get_one::<EscType>("type").unwrap().clone(),
no_quote: args.get_flag("no-quote"),
no_detect: args.get_flag("no-detect"),
multiline: args.get_flag("multiline"),
}))
}
Expand All @@ -103,18 +107,39 @@ impl Applet for EscapeApplet {
} else {
val.trim().into()
};
let escaped = to_escape.escape(&self.esc_type);
if self.no_quote {

// Detect (unless no_detect) surrounding quotes to:
// - remove them
// - escape
// - restore them
let (quote, to_escape_nq) = if !self.no_detect {
let first = *to_escape.first().unwrap_or(&b' ');
let last = *to_escape.last().unwrap_or(&b'*');

if first != last {
(None, to_escape.clone())
} else {
let end_pos = to_escape.len() - 1;
match first {
b'\'' => (Some(b'\''), to_escape[1..end_pos].to_vec()),
b'"' => (Some(b'"'), to_escape[1..end_pos].to_vec()),
_ => (None, to_escape),
}
}
} else {
match self.esc_type {
EscType::BashSingle | EscType::Single => (Some(b'\''), to_escape),
_ => (Some(b'"'), to_escape),
}
};
let escaped = to_escape_nq.escape(&self.esc_type);
if self.no_quote || quote.is_none() {
Ok(escaped)
} else {
let quote = match self.esc_type {
EscType::BashSingle | EscType::Single => b'\'',
_ => b'"',
};
let mut res = Vec::<u8>::with_capacity(escaped.len() + 2);
res.push(quote);
res.push(quote.unwrap());
res.extend(escaped);
res.push(quote);
res.push(quote.unwrap());
Ok(res)
}
}
Expand All @@ -123,6 +148,7 @@ impl Applet for EscapeApplet {
Box::new(Self {
esc_type: EscType::Generic,
no_quote: false,
no_detect: false,
multiline: false,
})
}
Expand Down

0 comments on commit 7909f90

Please # to comment.