Better input parsing.

This commit is contained in:
shy 2021-04-06 15:22:16 +02:00
parent 7f941b7bfb
commit b69056c144
2 changed files with 39 additions and 26 deletions

View file

@ -85,21 +85,25 @@ impl AlarmRoster {
let mut time: u32 = 0;
// Parse input into seconds.
for sub in buffer.rsplit(':') {
if sub.len() > 0 {
let d = sub.parse::<u32>();
match d {
Ok(d) => time += d * 60u32.pow(index),
Err(_) => return Err("Could not parse number as <u32>."),
if buffer.find(':').is_some() {
for sub in buffer.rsplit(':') {
if sub.len() > 0 {
match sub.parse::<u32>() {
Ok(d) if d < 60 && index < 3 => time += d * 60u32.pow(index),
Ok(_) => return Err("Could not parse as time."),
Err(_) => return Err("Could not parse number as <u32>."),
}
}
index += 1;
}
} else {
match buffer.parse::<u32>() {
Ok(d) => time = d,
Err(_) => return Err("Could not parse as <u32>."),
}
index += 1;
// More than 3 fields are an error.
if index > 3 { return Err("Too many colons to parse.") };
}
// Skip if time evaluated to zero.
// Skip if time is out of boundaries.
if time == 0 { return Err("Evaluates to zero.") };
if time >= 24 * 60 * 60 { return Err("Values >24h not supported.") };
@ -143,7 +147,7 @@ impl AlarmRoster {
let mut index = 0;
for alarm in &mut self.list {
// Ignore alarms already marked exceeded.
// Ignore alarms marked exceeded.
if !alarm.exceeded {
if alarm.time <= clock.elapsed {
// Found alarm to raise.

View file

@ -74,8 +74,7 @@ fn main() {
// Register signal handlers.
let signal = Arc::new(AtomicUsize::new(0));
register_signal_handlers(&signal);
flag::register(SIGWINCH as i32, Arc::clone(&layout.force_recalc)).unwrap();
register_signal_handlers(&signal, &layout);
// Clear window and hide cursor.
write!(stdout,
@ -96,14 +95,17 @@ fn main() {
// Suspend execution on SIGTSTP.
SIGTSTP => {
suspend(&mut stdout);
// Clear SIGCONT and continue from here.
// Clear SIGCONT, as we have already taken care to reset the
// terminal.
signal.compare_and_swap(SIGCONT, 0, Ordering::Relaxed);
continue_after_suspend(&mut stdout);
layout.force_redraw = true;
// Jump to the start of the main loop.
continue;
},
// Continuing after SIGSTOP.
SIGCONT => {
continue_after_suspend(&mut stdout);
// This is reached when the process was suspended by SIGSTOP.
restore_after_suspend(&mut stdout);
layout.force_redraw = true;
},
// Exit main loop on SIGTERM and SIGINT.
@ -112,12 +114,11 @@ fn main() {
SIGUSR1 => {
clock.reset();
alarm_roster.reset_all();
layout.force_recalc.store(true, Ordering::Relaxed);
layout.force_redraw = true;
},
// (Un-)Pause clock on SIGUSR2.
SIGUSR2 => clock.toggle(),
// Window size changed.
//SIGWINCH => layout.force_recalc = true,
// We didn't register anything else.
_ => unreachable!(),
}
@ -129,6 +130,7 @@ fn main() {
Key::Char('r') => {
clock.reset();
alarm_roster.reset_all();
layout.force_recalc.store(true, Ordering::Relaxed);
layout.force_redraw = true;
},
// (Un-)Pause on space.
@ -156,10 +158,12 @@ fn main() {
// Suspend an ^Z.
Key::Ctrl('z') => {
suspend(&mut stdout);
// Clear SIGCONT and continue from here.
// Clear SIGCONT, as we have already taken care to reset
// the terminal.
signal.compare_and_swap(SIGCONT, 0, Ordering::Relaxed);
continue_after_suspend(&mut stdout);
layout.force_redraw = true;
// Jump to the start of the main loop.
continue;
},
// Enter.
Key::Char('\n') => {
@ -335,17 +339,21 @@ fn parse_args(config: &mut Config) {
}
}
fn register_signal_handlers(signal: &Arc<AtomicUsize>) {
fn register_signal_handlers(signal: &Arc<AtomicUsize>, layout: &Layout) {
flag::register_usize(SIGTSTP as i32, Arc::clone(&signal), SIGTSTP).unwrap();
flag::register_usize(SIGCONT as i32, Arc::clone(&signal), SIGCONT).unwrap();
flag::register_usize(SIGTERM as i32, Arc::clone(&signal), SIGTERM).unwrap();
flag::register_usize(SIGINT as i32, Arc::clone(&signal), SIGINT).unwrap();
flag::register_usize(SIGUSR1 as i32, Arc::clone(&signal), SIGUSR1).unwrap();
flag::register_usize(SIGUSR2 as i32, Arc::clone(&signal), SIGUSR2).unwrap();
// SIGWINCH sets "force_recalc" directly.
flag::register(SIGWINCH as i32, Arc::clone(&layout.force_recalc)).unwrap();
}
// Suspend execution on SIGTSTP.
fn suspend<W: Write>(stdout: &mut RawTerminal<W>) {
fn suspend<W: Write>(mut stdout: &mut RawTerminal<W>) {
write!(stdout,
"{}{}{}",
cursor::Goto(1,1),
@ -361,10 +369,12 @@ fn suspend<W: Write>(stdout: &mut RawTerminal<W>) {
if let Err(error) = signal_hook::low_level::emulate_default_handler(SIGTSTP as i32) {
eprintln!("Error raising SIGTSTP: {}", error);
}
restore_after_suspend(&mut stdout);
}
// Set up terminal when continuing from SIGTSTP or SIGSTOP.
fn continue_after_suspend<W: Write>(stdout: &mut RawTerminal<W>) {
// Set up terminal after SIGTSTP or SIGSTOP.
fn restore_after_suspend<W: Write>(stdout: &mut RawTerminal<W>) {
stdout.activate_raw_mode()
.unwrap_or_else(|error| {
eprintln!("Failed to re-enter raw terminal mode after suspend: {}", error);
@ -378,7 +388,6 @@ fn continue_after_suspend<W: Write>(stdout: &mut RawTerminal<W>) {
eprintln!("Error writing to stdout: {}", error);
std::process::exit(1);
});
stdout.flush().unwrap();
}
// Draw input buffer.