diff --git a/src/alarm.rs b/src/alarm.rs index dfbef04..b6c48f2 100644 --- a/src/alarm.rs +++ b/src/alarm.rs @@ -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::(); - match d { - Ok(d) => time += d * 60u32.pow(index), - Err(_) => return Err("Could not parse number as ."), + if buffer.find(':').is_some() { + for sub in buffer.rsplit(':') { + if sub.len() > 0 { + match sub.parse::() { + 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 ."), + } } + index += 1; + } + } else { + match buffer.parse::() { + Ok(d) => time = d, + Err(_) => return Err("Could not parse as ."), } - 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. diff --git a/src/main.rs b/src/main.rs index 19b7628..6a30628 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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) { +fn register_signal_handlers(signal: &Arc, 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(stdout: &mut RawTerminal) { +fn suspend(mut stdout: &mut RawTerminal) { write!(stdout, "{}{}{}", cursor::Goto(1,1), @@ -361,10 +369,12 @@ fn suspend(stdout: &mut RawTerminal) { 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(stdout: &mut RawTerminal) { +// Set up terminal after SIGTSTP or SIGSTOP. +fn restore_after_suspend(stdout: &mut RawTerminal) { 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(stdout: &mut RawTerminal) { eprintln!("Error writing to stdout: {}", error); std::process::exit(1); }); - stdout.flush().unwrap(); } // Draw input buffer.