Revised parsing of command line arguments.
This commit is contained in:
parent
066b88eeee
commit
1e3e3d9fea
4 changed files with 78 additions and 42 deletions
|
@ -279,9 +279,9 @@ pub fn alarm_exec(config: &Config, elapsed: u32) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(exec) = &config.alarm_exec {
|
if let Some(exec) = &config.alarm_exec {
|
||||||
// Replace every occurrence of "%s".
|
// Replace every occurrence of "{}".
|
||||||
for s in exec {
|
for s in exec {
|
||||||
args.push(s.replace("%s", &time));
|
args.push(s.replace("{}", &time));
|
||||||
}
|
}
|
||||||
|
|
||||||
if Command::new(&exec[0])
|
if Command::new(&exec[0])
|
||||||
|
|
|
@ -101,7 +101,7 @@ impl Clock {
|
||||||
let day_count = format!(
|
let day_count = format!(
|
||||||
"+ {} {}",
|
"+ {} {}",
|
||||||
self.days,
|
self.days,
|
||||||
if self.days == 1 { "day" } else { "days" });
|
if self.days == 1 { "DAY" } else { "DAYS" });
|
||||||
|
|
||||||
write!(stdout,
|
write!(stdout,
|
||||||
"{}{:>11}",
|
"{}{:>11}",
|
||||||
|
|
|
@ -108,7 +108,7 @@ impl Layout {
|
||||||
|
|
||||||
// Days (based on position of seconds).
|
// Days (based on position of seconds).
|
||||||
self.clock_days = Position {
|
self.clock_days = Position {
|
||||||
line: self.clock_sec.line + DIGIT_HEIGHT + 1,
|
line: self.clock_sec.line + DIGIT_HEIGHT,
|
||||||
col: self.clock_sec.col,
|
col: self.clock_sec.col,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
112
src/main.rs
112
src/main.rs
|
@ -22,18 +22,19 @@ use layout::{Layout, Position};
|
||||||
const NAME: &str = env!("CARGO_PKG_NAME");
|
const NAME: &str = env!("CARGO_PKG_NAME");
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
const USAGE: &str = concat!("USAGE: ", env!("CARGO_PKG_NAME"),
|
const USAGE: &str = concat!("USAGE: ", env!("CARGO_PKG_NAME"),
|
||||||
" [-h|-v] [-p] [-q] [ALARM TIME(s)] [-e|--exec COMMAND [...]]
|
" [-h|-v] [-e|--exec COMMAND] [-p] [-q] [ALARM TIME(s)]
|
||||||
|
|
||||||
PARAMETERS:
|
PARAMETERS:
|
||||||
[ALARM TIME] None or multiple alarm times (HH:MM:SS).
|
[ALARM TIME] None or multiple alarm times (HH:MM:SS).
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
-h, --help Display this help.
|
-h, --help Show this help and exit.
|
||||||
-v, --version Display version information.
|
-v, --version Show version information and exit.
|
||||||
|
-e, --exec [COMMAND] Execute COMMAND on alarm. Every occurrence of {}
|
||||||
|
will be replaced by the elapsed time in (HH:)MM:SS
|
||||||
|
format.
|
||||||
-p, --plain Use simpler block chars.
|
-p, --plain Use simpler block chars.
|
||||||
-q, --quit Quit program after last alarm.
|
-q, --quit Quit program after last alarm.
|
||||||
-e, --exec [COMMAND] Execute COMMAND on alarm. Must be the last flag on
|
|
||||||
the command line. Everything after it is passed as
|
|
||||||
argument to COMMAND. Every \"{}\" will be replaced
|
|
||||||
by the elapsed time in (HH:)MM:SS format.
|
|
||||||
|
|
||||||
SIGNALS: <SIGUSR1> Reset clock.
|
SIGNALS: <SIGUSR1> Reset clock.
|
||||||
<SIGUSR2> Pause or un-pause clock.");
|
<SIGUSR2> Pause or un-pause clock.");
|
||||||
|
@ -314,42 +315,77 @@ fn usage() {
|
||||||
|
|
||||||
// Parse command line arguments into "config".
|
// Parse command line arguments into "config".
|
||||||
fn parse_args(config: &mut Config, alarm_roster: &mut AlarmRoster) {
|
fn parse_args(config: &mut Config, alarm_roster: &mut AlarmRoster) {
|
||||||
for arg in env::args().skip(1) {
|
let mut iter = env::args().skip(1);
|
||||||
match arg.as_str() {
|
|
||||||
"-h" | "--help" => usage(),
|
loop {
|
||||||
"-v" | "--version" => {
|
if let Some(arg) = iter.next() {
|
||||||
println!("{} {}", NAME, VERSION);
|
match arg.as_str() {
|
||||||
std::process::exit(0);
|
"-h" | "--help" => usage(),
|
||||||
},
|
"-v" | "--version" => {
|
||||||
"-p" | "--plain" => { config.plain = true; },
|
println!("{} {}", NAME, VERSION);
|
||||||
"-q" | "--quit" => { config.auto_quit = true; },
|
std::process::exit(0);
|
||||||
"-e" | "--exec" => {
|
},
|
||||||
// Find position of this flag.
|
"-p" | "--plain" => config.plain = true,
|
||||||
let i = env::args().position(|s| { s == "-e" || s == "--exec" }).unwrap();
|
"-q" | "--quit" => config.auto_quit = true,
|
||||||
// Copy everything thereafter.
|
"-e" | "--exec" => {
|
||||||
let exec: Vec<String> = env::args().skip(i + 1).collect();
|
if let Some(e) = iter.next() {
|
||||||
if exec.is_empty() {
|
config.alarm_exec = Some(input_to_exec(&e));
|
||||||
usage();
|
} else {
|
||||||
} else {
|
println!("Missing parameter to \"{}\".", arg);
|
||||||
config.alarm_exec = Some(exec);
|
std::process::exit(1);
|
||||||
// Ignore everything after this flag.
|
}
|
||||||
break;
|
},
|
||||||
}
|
any if any.starts_with('-') => {
|
||||||
},
|
// Unrecognized flag.
|
||||||
any if any.starts_with('-') => {
|
println!("Unrecognized option: \"{}\"", any);
|
||||||
// Unrecognized flag.
|
println!("Use \"-h\" or \"--help\" for a list of valid command line options");
|
||||||
println!("Unrecognized option: \"{}\"", any);
|
|
||||||
println!("Use \"-h\" or \"--help\" for a list of valid command line options");
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
any => {
|
|
||||||
if let Err(error) = alarm_roster.add(&String::from(any)) {
|
|
||||||
println!("Error adding \"{}\" as alarm. ({})", any, error);
|
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
|
},
|
||||||
|
any => {
|
||||||
|
// Alarm to add.
|
||||||
|
if let Err(error) = alarm_roster.add(&String::from(any)) {
|
||||||
|
println!("Error adding \"{}\" as alarm. ({})", any, error);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else { break; } // All command line parameters processed.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse command line argument to --command into a vector of strings suitable
|
||||||
|
// for process::Command::spawn.
|
||||||
|
fn input_to_exec(input: &str) -> Vec<String> {
|
||||||
|
let mut exec: Vec<String> = Vec::new();
|
||||||
|
let mut subs: String = String::new();
|
||||||
|
let mut quoted = false;
|
||||||
|
let mut escaped = false;
|
||||||
|
|
||||||
|
for byte in input.chars() {
|
||||||
|
match byte {
|
||||||
|
'\\' if !escaped => {
|
||||||
|
// Next char is escaped.
|
||||||
|
escaped = true;
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
' ' if escaped || quoted => { &subs.push(' '); },
|
||||||
|
' ' => {
|
||||||
|
if !&subs.is_empty() {
|
||||||
|
exec.push(subs.clone());
|
||||||
|
&subs.clear();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
'"' | '\'' if !escaped => quoted = !quoted,
|
||||||
|
_ => {
|
||||||
|
if escaped { &subs.push('\\'); }
|
||||||
|
&subs.push(byte);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
escaped = false;
|
||||||
}
|
}
|
||||||
|
exec.push(subs.clone());
|
||||||
|
|
||||||
|
exec
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_signal_handlers(signal: &Arc<AtomicUsize>, layout: &Layout) {
|
fn register_signal_handlers(signal: &Arc<AtomicUsize>, layout: &Layout) {
|
||||||
|
|
Loading…
Reference in a new issue