summaryrefslogtreecommitdiffstats
path: root/src/launcher/strsub.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/launcher/strsub.rs')
-rw-r--r--src/launcher/strsub.rs192
1 files changed, 0 insertions, 192 deletions
diff --git a/src/launcher/strsub.rs b/src/launcher/strsub.rs
deleted file mode 100644
index 5764405..0000000
--- a/src/launcher/strsub.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-// a cheap-o implementation of StrSubstitutor from apache commons
-// (does not need to support recursive evaluation or preserving escapes, it was never enabled in
-
-use std::borrow::Cow;
-
-const ESCAPE: char = '$';
-const VAR_BEGIN: &str = "${";
-const VAR_END: &str = "}";
-const VAR_DEFAULT: &str = ":-";
-
-pub trait SubFunc<'rep> {
- fn substitute(&self, key: &str) -> Option<Cow<'rep, str>>;
-}
-
-/* NOTE: the in-place implementation has been replaced for the following reasons:
- * - it was annoying to get lifetimes to work, so you could only either pass a trait implementation
- * or a closure
- * - it was probably slower than doing it out-of-place anyway, since you keep having to copy the
- * tail of the string for each replacement
- */
-
-// handles ${replacements} on this string IN-PLACE. Calls the "sub" function for each key it receives.
-// if "sub" returns None, it will use a default value or ignore the ${substitution}.
-// There are no "invalid inputs" and this function should never panic unless "sub" panics.
-/*pub fn replace_string(input: &mut String, sub: impl SubFunc) {
- let mut cursor = input.len();
- while let Some(idx) = input[..cursor].rfind(VAR_BEGIN) {
- // note: for some reason, apache processes escapes BEFORE checking if it's even a valid
- // replacement expression. strange behavior IMO.
- if let Some((pidx, ESCAPE)) = prev_char(input.as_ref(), idx) {
- // this "replacement" is escaped. remove the escape marker and continue.
- input.remove(pidx);
- cursor = pidx;
- continue;
- }
-
- let Some(endidx) = input[idx..cursor].find(VAR_END).map(|v| v + idx) else {
- // unclosed replacement expression. ignore.
- cursor = idx;
- continue;
- };
-
- let spec = &input[(idx + VAR_BEGIN.len())..endidx];
- let name;
- let def_opt;
-
- if let Some(def) = spec.find(VAR_DEFAULT) {
- name = &spec[..def];
- def_opt = Some(&spec[(def + VAR_DEFAULT.len())..]);
- } else {
- name = spec;
- def_opt = None;
- }
-
- if let Some(sub_val) = sub.substitute(name).map_or_else(|| def_opt.map(|d| Cow::Owned(d.to_owned())), |v| Some(v)) {
- input.replace_range(idx..(endidx + VAR_END.len()), sub_val.as_ref());
- }
-
- cursor = idx;
- }
-}*/
-
-pub fn replace_string<'inp, 'rep>(input: &'inp str, sub: &impl SubFunc<'rep>) -> Cow<'inp, str> {
- let mut ret: Option<String> = None;
- let mut cursor = 0usize;
-
- while let Some(idx) = input[cursor..].find(VAR_BEGIN) {
- let idx = idx + cursor; // make idx an absolute index into 'input'
- let spec_start = idx + VAR_BEGIN.len(); // the start of the "spec" (area inside {})
-
- // first, check if this is escaped
- if let Some((prev_idx, ESCAPE)) = input[..idx].char_indices().next_back() {
- let s = ret.get_or_insert_default();
- s.push_str(&input[cursor..prev_idx]);
-
- // advance past this so we don't match it again
- s.push_str(&input[idx..spec_start]);
- cursor = spec_start;
- continue;
- }
-
- // now, find the closing tag
- let Some(spec_end) = input[spec_start..].find(VAR_END).map(|v| v + spec_start) else {
- break; // reached the end of the string
- };
-
- let full_spec = &input[spec_start..spec_end];
-
- // check for a default argument
- let (name, def) = if let Some(defidx) = full_spec.find(VAR_DEFAULT) {
- (&full_spec[..defidx], Some(&full_spec[(defidx + VAR_DEFAULT.len())..]))
- } else {
- (full_spec, None)
- };
-
- let after = spec_end + VAR_END.len();
- if let Some(subst) = sub.substitute(name).map_or_else(|| def.map(Cow::Borrowed), Some) {
- let s = ret.get_or_insert_default();
- s.push_str(&input[cursor..idx]);
- s.push_str(subst.as_ref());
- } else {
- ret.get_or_insert_default().push_str(&input[cursor..after]);
- }
-
- cursor = after;
- }
-
- if let Some(ret) = ret.as_mut() {
- ret.push_str(&input[cursor..]);
- }
-
- ret.map_or(Cow::Borrowed(input), Cow::Owned)
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[derive(Clone, Copy)]
- struct TestSub;
- impl SubFunc<'static> for TestSub {
- fn substitute(&self, key: &str) -> Option<Cow<'static, str>> {
- match key {
- "exists" => Some(Cow::Borrowed("value123")),
- "empty" => None,
- "borger" => Some(Cow::Borrowed("\u{1f354}")),
- _ => panic!("replace_fun called with unexpected key: {}", key)
- }
- }
- }
-
- #[test]
- fn test_standard_replace() {
- assert_eq!(replace_string("this has ${exists} and more", &TestSub), "this has value123 and more");
- assert_eq!(replace_string("multiple ${exists} repl${exists}ace", &TestSub), "multiple value123 replvalue123ace");
- assert_eq!(replace_string("${exists}${exists}", &TestSub), "value123value123");
- }
-
- #[test]
- fn test_empty_replace() {
- assert_eq!(replace_string("this has ${empty} and more", &TestSub), "this has ${empty} and more");
- assert_eq!(replace_string("multiple ${empty} repl${empty}ace", &TestSub), "multiple ${empty} repl${empty}ace");
- assert_eq!(replace_string("${empty}${empty}", &TestSub), "${empty}${empty}");
- }
-
- #[test]
- fn test_homogenous_replace() {
- assert_eq!(replace_string("some ${exists} and ${empty} ...", &TestSub), "some value123 and ${empty} ...");
- assert_eq!(replace_string("some ${empty} and ${exists} ...", &TestSub), "some ${empty} and value123 ...");
- assert_eq!(replace_string("${exists}${empty}", &TestSub), "value123${empty}");
- assert_eq!(replace_string("${empty}${exists}", &TestSub), "${empty}value123");
- }
-
- #[test]
- fn test_default_replace() {
- assert_eq!(replace_string("some ${exists:-def1} and ${empty:-def2} ...", &TestSub), "some value123 and def2 ...");
- assert_eq!(replace_string("some ${empty:-def1} and ${exists:-def2} ...", &TestSub), "some def1 and value123 ...");
- assert_eq!(replace_string("abc${empty:-}def", &TestSub), "abcdef");
- assert_eq!(replace_string("${empty:-}${empty:-}", &TestSub), "");
- }
-
- #[test]
- fn test_escape() {
- assert_eq!(replace_string("an $${escaped} replacement (${exists})", &TestSub), "an ${escaped} replacement (value123)");
- assert_eq!(replace_string("${exists}$${escaped}${exists}", &TestSub), "value123${escaped}value123");
-
- // make sure this weird behavior is preserved... (the original code seemed to show it)
- assert_eq!(replace_string("some $${ else", &TestSub), "some ${ else");
- }
-
- #[test]
- fn test_weird() {
- assert_eq!(replace_string("${exists}", &TestSub), "value123");
- assert_eq!(replace_string("$${empty}", &TestSub), "${empty}");
- assert_eq!(replace_string("${empty:-a}", &TestSub), "a");
- assert_eq!(replace_string("${empty:-}", &TestSub), "");
- }
-
- // these make sure it doesn't chop up multibyte characters illegally
- #[test]
- fn test_multibyte_surround() {
- assert_eq!(replace_string("\u{1f354}$${}\u{1f354}", &TestSub), "\u{1f354}${}\u{1f354}");
- assert_eq!(replace_string("\u{1f354}${exists}\u{1f354}${empty:-}\u{1f354}", &TestSub), "\u{1f354}value123\u{1f354}\u{1f354}");
- }
-
- #[test]
- fn test_multibyte_replace() {
- assert_eq!(replace_string("borger ${borger}", &TestSub), "borger \u{1f354}");
- assert_eq!(replace_string("${exists:-\u{1f354}}${empty:-\u{1f354}}", &TestSub), "value123\u{1f354}");
- assert_eq!(replace_string("${borger}$${}${borger}", &TestSub), "\u{1f354}${}\u{1f354}");
- }
-}