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; let mut time: u32 = 0;
// Parse input into seconds. // Parse input into seconds.
for sub in buffer.rsplit(':') { if buffer.find(':').is_some() {
if sub.len() > 0 { for sub in buffer.rsplit(':') {
let d = sub.parse::<u32>(); if sub.len() > 0 {
match d { match sub.parse::<u32>() {
Ok(d) => time += d * 60u32.pow(index), Ok(d) if d < 60 && index < 3 => time += d * 60u32.pow(index),
Err(_) => return Err("Could not parse number as <u32>."), 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 == 0 { return Err("Evaluates to zero.") };
if time >= 24 * 60 * 60 { return Err("Values >24h not supported.") }; if time >= 24 * 60 * 60 { return Err("Values >24h not supported.") };
@ -143,7 +147,7 @@ impl AlarmRoster {
let mut index = 0; let mut index = 0;
for alarm in &mut self.list { for alarm in &mut self.list {
// Ignore alarms already marked exceeded. // Ignore alarms marked exceeded.
if !alarm.exceeded { if !alarm.exceeded {
if alarm.time <= clock.elapsed { if alarm.time <= clock.elapsed {
// Found alarm to raise. // Found alarm to raise.

View file

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