From fa0b4861b91c53333dd1de72247d95c76caf1c0d Mon Sep 17 00:00:00 2001 From: Andreas Hartmann Date: Sat, 26 Jun 2021 20:13:51 +0200 Subject: [PATCH] backup_control: Match abbreviated backup options Add a function that takes a user-supplied backup option and checks if it matches any of the valid backup options. This is because GNU allows to abbreviate backup options, as long as they are valid and unambiguous. In case a backup option is either invalid or ambiguous, an error type is returned that contains a formatted error string for output to the user. --- src/uucore/src/lib/mods/backup_control.rs | 46 ++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/uucore/src/lib/mods/backup_control.rs b/src/uucore/src/lib/mods/backup_control.rs index 4f1e2d00a..6af2b3534 100644 --- a/src/uucore/src/lib/mods/backup_control.rs +++ b/src/uucore/src/lib/mods/backup_control.rs @@ -7,7 +7,7 @@ pub static BACKUP_CONTROL_VALUES: &[&str] = &[ "simple", "never", "numbered", "t", "existing", "nil", "none", "off", ]; -pub static BACKUP_CONTROL_LONG_HELP: &str = +pub static BACKUP_CONTROL_LONG_HELP: &str = "The backup suffix is '~', unless set with --suffix or SIMPLE_BACKUP_SUFFIX. The version control method may be selected via the --backup option or through the VERSION_CONTROL environment variable. Here are the values: @@ -65,6 +65,50 @@ pub fn determine_backup_mode(backup_opt_exists: bool, backup_opt: Option<&str>) } } +/// Match a backup option string to a `BackupMode`. +/// +/// The GNU manual specifies that abbreviations to options are valid as long as +/// they aren't ambiguous. This function matches the given `method` argument +/// against all valid backup options (via `starts_with`), and returns a valid +/// [`BackupMode`] if exactly one backup option matches the `method` given. +/// +/// `origin` is required in order to format the generated error message +/// properly, when an error occurs. +/// +/// +/// # Errors +/// +/// If `method` is ambiguous (i.e. may resolve to multiple backup modes) or +/// invalid, an error is returned. The error contains the formatted error string +/// which may then be passed to the [`show_usage_error`] macro. +fn match_method(method: &str, origin: &str) -> Result { + let x = vec!["simple", "never", "numbered", "t", + "existing", "nil", "none", "off"]; + + let matches: Vec<&&str> = x.iter() + .filter(|val| val.starts_with(method)) + .collect(); + if matches.len() == 1 { + match *matches[0] { + "simple" | "never" => Ok(BackupMode::SimpleBackup), + "numbered" | "t" => Ok(BackupMode::NumberedBackup), + "existing" | "nil" => Ok(BackupMode::ExistingBackup), + "none" | "off" => Ok(BackupMode::NoBackup), + _ => panic!(), // cannot happen as we must have exactly one match + // from the list above. + } + } else { + let error_type = if matches.len() == 0 { "invalid" } else { "ambiguous" }; + Err(format!( +"{0} argument ‘{1}’ for ‘{2}’ +Valid arguments are: + - ‘none’, ‘off’ + - ‘simple’, ‘never’ + - ‘existing’, ‘nil’ + - ‘numbered’, ‘t’", error_type, method, origin)) + } +} + pub fn get_backup_path( backup_mode: BackupMode, backup_path: &Path,