|  |  |  | @ -14,6 +14,7 @@ use std::io; | 
			
		
	
		
			
				
					|  |  |  |  | use crsn::asm::instr::cond::Flag; | 
			
		
	
		
			
				
					|  |  |  |  | use std::fmt; | 
			
		
	
		
			
				
					|  |  |  |  | use crsn::asm::data::Wr; | 
			
		
	
		
			
				
					|  |  |  |  | use std::time::Instant; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  | mod console { | 
			
		
	
		
			
				
					|  |  |  |  |     use std::{io}; | 
			
		
	
	
		
			
				
					|  |  |  | @ -21,13 +22,29 @@ mod console { | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     use std::ffi::c_void; | 
			
		
	
		
			
				
					|  |  |  |  |     use std::mem::{self, MaybeUninit}; | 
			
		
	
		
			
				
					|  |  |  |  |     use crsn::runtime::fault::Fault; | 
			
		
	
		
			
				
					|  |  |  |  |     use std::time::{Duration, Instant}; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     fn setup_fd(fd: RawFd) -> io::Result<libc::termios> { | 
			
		
	
		
			
				
					|  |  |  |  |     struct ReadCharState { | 
			
		
	
		
			
				
					|  |  |  |  |         bytes: [u8; 4], | 
			
		
	
		
			
				
					|  |  |  |  |         cursor: usize, | 
			
		
	
		
			
				
					|  |  |  |  |         len: usize, | 
			
		
	
		
			
				
					|  |  |  |  |         last_timeout : u8, | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     static mut READ_CHAR_STATE: ReadCharState = ReadCharState { | 
			
		
	
		
			
				
					|  |  |  |  |         bytes: [0; 4], | 
			
		
	
		
			
				
					|  |  |  |  |         cursor: 0, | 
			
		
	
		
			
				
					|  |  |  |  |         len: 0, | 
			
		
	
		
			
				
					|  |  |  |  |         last_timeout : 0, | 
			
		
	
		
			
				
					|  |  |  |  |     }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     fn setup_fd(fd: RawFd) -> Result<libc::termios, Fault> { | 
			
		
	
		
			
				
					|  |  |  |  |         use libc::*; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let mut tio = MaybeUninit::uninit(); | 
			
		
	
		
			
				
					|  |  |  |  |         if 0 != unsafe { tcgetattr(fd, tio.as_mut_ptr()) } { | 
			
		
	
		
			
				
					|  |  |  |  |             return Err(io::Error::last_os_error()); | 
			
		
	
		
			
				
					|  |  |  |  |             return Err(Fault::IOError(io::Error::last_os_error())); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |         let mut tio = unsafe { MaybeUninit::assume_init(tio) }; | 
			
		
	
		
			
				
					|  |  |  |  |         let old_tio : termios = unsafe { mem::transmute_copy(&tio) }; | 
			
		
	
	
		
			
				
					|  |  |  | @ -39,36 +56,76 @@ mod console { | 
			
		
	
		
			
				
					|  |  |  |  |         tio.c_cc[VMIN] = 1; | 
			
		
	
		
			
				
					|  |  |  |  |         tio.c_cc[VTIME] = 0; | 
			
		
	
		
			
				
					|  |  |  |  |         if 0 != unsafe { tcsetattr(fd, TCSANOW, &tio) } { | 
			
		
	
		
			
				
					|  |  |  |  |             return Err(io::Error::last_os_error()); | 
			
		
	
		
			
				
					|  |  |  |  |             return Err(Fault::IOError(io::Error::last_os_error())); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         Ok(old_tio) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn init_io() -> io::Result<libc::termios> { | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn init_io() -> Result<libc::termios, Fault> { | 
			
		
	
		
			
				
					|  |  |  |  |         setup_fd(libc::STDIN_FILENO) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn read_byte() -> io::Result<u8> { | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn read_byte(deadline : Option<Instant>) -> Result<u8, Fault> { | 
			
		
	
		
			
				
					|  |  |  |  |         // Set TIO timeout
 | 
			
		
	
		
			
				
					|  |  |  |  |         let state = unsafe { &mut READ_CHAR_STATE }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if (state.last_timeout == 0) && deadline.is_none() { | 
			
		
	
		
			
				
					|  |  |  |  |             // Keep it like that
 | 
			
		
	
		
			
				
					|  |  |  |  |         }  else { | 
			
		
	
		
			
				
					|  |  |  |  |             let vtime = if let Some(dl) = deadline { | 
			
		
	
		
			
				
					|  |  |  |  |                 let timeout = dl.saturating_duration_since(Instant::now()); | 
			
		
	
		
			
				
					|  |  |  |  |                 ((timeout.as_secs_f32() * 10.0).round() as u32).min(255).max(1) as u8 | 
			
		
	
		
			
				
					|  |  |  |  |             } else { | 
			
		
	
		
			
				
					|  |  |  |  |                 0 | 
			
		
	
		
			
				
					|  |  |  |  |             }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             if state.last_timeout != vtime { | 
			
		
	
		
			
				
					|  |  |  |  |                 // vtime changes
 | 
			
		
	
		
			
				
					|  |  |  |  |                 state.last_timeout = vtime; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |                 let mut tio = MaybeUninit::uninit(); | 
			
		
	
		
			
				
					|  |  |  |  |                 if 0 != unsafe { libc::tcgetattr(libc::STDIN_FILENO, tio.as_mut_ptr()) } { | 
			
		
	
		
			
				
					|  |  |  |  |                     return Err(Fault::IOError(io::Error::last_os_error())); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 let mut tio = unsafe { MaybeUninit::assume_init(tio) }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |                 if vtime > 0 { | 
			
		
	
		
			
				
					|  |  |  |  |                     tio.c_cc[libc::VTIME] = vtime; /* unit = 0.1 */ | 
			
		
	
		
			
				
					|  |  |  |  |                     tio.c_cc[libc::VMIN] = 0; | 
			
		
	
		
			
				
					|  |  |  |  |                 } else { | 
			
		
	
		
			
				
					|  |  |  |  |                     tio.c_cc[libc::VTIME] = 0; // no counting
 | 
			
		
	
		
			
				
					|  |  |  |  |                     tio.c_cc[libc::VMIN] = 1; // want at least one character
 | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |                 unsafe { libc::tcsetattr(libc::STDIN_FILENO, libc::TCSANOW, &tio) }; | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let mut buf = 0u8; | 
			
		
	
		
			
				
					|  |  |  |  |         let len = unsafe { libc::read(libc::STDIN_FILENO, &mut buf as *mut u8 as *mut c_void, 1) }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if len == 0 && state.last_timeout != 0 { | 
			
		
	
		
			
				
					|  |  |  |  |             return Err(Fault::IOError(io::Error::new(std::io::ErrorKind::TimedOut, ""))); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if len <= 0 { | 
			
		
	
		
			
				
					|  |  |  |  |             Err(io::Error::last_os_error()) | 
			
		
	
		
			
				
					|  |  |  |  |             Err(Fault::IOError(io::Error::last_os_error())) | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             Ok(buf as u8) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn write_byte(b : u8) -> io::Result<()> { | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn write_byte(b : u8) -> Result<(), Fault> { | 
			
		
	
		
			
				
					|  |  |  |  |         let len = unsafe { libc::write(libc::STDOUT_FILENO, &b as *const u8 as *const c_void, 1) }; | 
			
		
	
		
			
				
					|  |  |  |  |         if len <= 0 { | 
			
		
	
		
			
				
					|  |  |  |  |             Err(io::Error::last_os_error()) | 
			
		
	
		
			
				
					|  |  |  |  |             Err(Fault::IOError(io::Error::last_os_error())) | 
			
		
	
		
			
				
					|  |  |  |  |         } else { | 
			
		
	
		
			
				
					|  |  |  |  |             Ok(()) | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn write_char(c : char) -> io::Result<()> { | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn write_char(c : char) -> Result<(), Fault> { | 
			
		
	
		
			
				
					|  |  |  |  |         let mut buf = [0u8; 4]; | 
			
		
	
		
			
				
					|  |  |  |  |         for b in c.encode_utf8(&mut buf).as_bytes() { | 
			
		
	
		
			
				
					|  |  |  |  |             write_byte(*b)?; | 
			
		
	
	
		
			
				
					|  |  |  | @ -76,30 +133,43 @@ mod console { | 
			
		
	
		
			
				
					|  |  |  |  |         Ok(()) | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn read_char() -> io::Result<char> { | 
			
		
	
		
			
				
					|  |  |  |  |         let first = read_byte()?; | 
			
		
	
		
			
				
					|  |  |  |  |     pub fn read_char(deadline : Option<Instant>) -> Result<char, Fault> { | 
			
		
	
		
			
				
					|  |  |  |  |         let state = unsafe { &mut READ_CHAR_STATE }; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if state.cursor == 0 { | 
			
		
	
		
			
				
					|  |  |  |  |             let first = read_byte(deadline)?; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |             if first & 0x80 == 0 { | 
			
		
	
		
			
				
					|  |  |  |  |                 return Ok(first as char); | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let mut bytes = [first, 0, 0, 0]; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let remain = if first & 0b1110_0000 == 0b1100_0000 { | 
			
		
	
		
			
				
					|  |  |  |  |             1 | 
			
		
	
		
			
				
					|  |  |  |  |         } else if first & 0b1111_0000 == 0b1110_0000 { | 
			
		
	
		
			
				
					|  |  |  |  |             state.bytes[0] = first; | 
			
		
	
		
			
				
					|  |  |  |  |             state.cursor = 1; | 
			
		
	
		
			
				
					|  |  |  |  |             state.len = if first & 0b1110_0000 == 0b1100_0000 { | 
			
		
	
		
			
				
					|  |  |  |  |                 2 | 
			
		
	
		
			
				
					|  |  |  |  |         } else /*if first & 0b1111_1000 == 0b1111_0000*/ { | 
			
		
	
		
			
				
					|  |  |  |  |             } else if first & 0b1111_0000 == 0b1110_0000 { | 
			
		
	
		
			
				
					|  |  |  |  |                 3 | 
			
		
	
		
			
				
					|  |  |  |  |             } else /*if first & 0b1111_1000 == 0b1111_0000*/ { | 
			
		
	
		
			
				
					|  |  |  |  |                 4 | 
			
		
	
		
			
				
					|  |  |  |  |             }; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         let len = state.len; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         for n in 1..=remain { | 
			
		
	
		
			
				
					|  |  |  |  |             bytes[n] = read_byte()?; | 
			
		
	
		
			
				
					|  |  |  |  |         while state.cursor < len { | 
			
		
	
		
			
				
					|  |  |  |  |             let b = read_byte(deadline)?; | 
			
		
	
		
			
				
					|  |  |  |  |             state.bytes[state.cursor] = b; | 
			
		
	
		
			
				
					|  |  |  |  |             state.cursor += 1; | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         std::str::from_utf8(&bytes[..=remain]) | 
			
		
	
		
			
				
					|  |  |  |  |         let rv = std::str::from_utf8(&state.bytes[..=len]) | 
			
		
	
		
			
				
					|  |  |  |  |             .map(|s| s.chars().nth(0).unwrap()) | 
			
		
	
		
			
				
					|  |  |  |  |             .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e)) | 
			
		
	
		
			
				
					|  |  |  |  |             .map_err(|e| Fault::IOError(io::Error::new(io::ErrorKind::InvalidData, e))); | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         state.cursor = 0; | 
			
		
	
		
			
				
					|  |  |  |  |         state.len = 0; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         rv | 
			
		
	
		
			
				
					|  |  |  |  |     } | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
	
		
			
				
					|  |  |  | @ -183,35 +253,47 @@ impl CrsnExtension for StdioOps { | 
			
		
	
		
			
				
					|  |  |  |  |     fn read_obj(&self, state: &mut RunState, handle: Value) | 
			
		
	
		
			
				
					|  |  |  |  |                 -> Result<Option<Value>, Fault> | 
			
		
	
		
			
				
					|  |  |  |  |     { | 
			
		
	
		
			
				
					|  |  |  |  |         let deadline = state.cr_deadline; | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if handle == self.hdl_stdin { | 
			
		
	
		
			
				
					|  |  |  |  |             match console::read_char() { | 
			
		
	
		
			
				
					|  |  |  |  |             match console::read_char(deadline) { | 
			
		
	
		
			
				
					|  |  |  |  |                 Ok(c) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     return Ok(Some(c as Value)); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Err(e) => { | 
			
		
	
		
			
				
					|  |  |  |  |                 Err(Fault::IOError(e)) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     if e.kind() == io::ErrorKind::TimedOut { | 
			
		
	
		
			
				
					|  |  |  |  |                         return Err(Fault::Blocked); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |                     state.set_flag(Flag::Invalid, true); | 
			
		
	
		
			
				
					|  |  |  |  |                     if e.kind() != io::ErrorKind::InvalidData { | 
			
		
	
		
			
				
					|  |  |  |  |                         state.set_flag(Flag::Eof, true); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                     return Ok(Some(0)); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Err(other) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     return Err(other); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if handle == self.hdl_stdin_raw { | 
			
		
	
		
			
				
					|  |  |  |  |             match console::read_byte() { | 
			
		
	
		
			
				
					|  |  |  |  |         } else if handle == self.hdl_stdin_raw { | 
			
		
	
		
			
				
					|  |  |  |  |             match console::read_byte(deadline) { | 
			
		
	
		
			
				
					|  |  |  |  |                 Ok(b) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     return Ok(Some(b as Value)); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Err(_e) => { | 
			
		
	
		
			
				
					|  |  |  |  |                 Err(Fault::IOError(e)) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     if e.kind() == io::ErrorKind::TimedOut { | 
			
		
	
		
			
				
					|  |  |  |  |                         return Err(Fault::Blocked); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |                     state.set_flag(Flag::Invalid, true); | 
			
		
	
		
			
				
					|  |  |  |  |                     state.set_flag(Flag::Eof, true); | 
			
		
	
		
			
				
					|  |  |  |  |                     return Ok(Some(0)); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |                 Err(other) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     return Err(other); | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if handle == self.hdl_stdout || handle == self.hdl_stdout_raw { | 
			
		
	
		
			
				
					|  |  |  |  |         } else if handle == self.hdl_stdout || handle == self.hdl_stdout_raw { | 
			
		
	
		
			
				
					|  |  |  |  |             state.set_flag(Flag::Invalid, true); | 
			
		
	
		
			
				
					|  |  |  |  |             return Ok(Some(0)); | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
	
		
			
				
					|  |  |  | @ -254,13 +336,15 @@ impl CrsnExtension for StdioOps { | 
			
		
	
		
			
				
					|  |  |  |  |     fn read_obj_all(&self, state: &mut RunState, whandle: Wr, rhandle: Value) | 
			
		
	
		
			
				
					|  |  |  |  |                     -> Result<Option<()>, Fault> | 
			
		
	
		
			
				
					|  |  |  |  |     { | 
			
		
	
		
			
				
					|  |  |  |  |         // XXX This is blocking, there is no sensible way to split it up.
 | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if rhandle == self.hdl_stdin { | 
			
		
	
		
			
				
					|  |  |  |  |             loop { | 
			
		
	
		
			
				
					|  |  |  |  |                 match console::read_char() { | 
			
		
	
		
			
				
					|  |  |  |  |                 match console::read_char(None) { | 
			
		
	
		
			
				
					|  |  |  |  |                     Ok(c) => { | 
			
		
	
		
			
				
					|  |  |  |  |                         state.write(whandle, c as Value)?; | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                     Err(e) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     Err(Fault::IOError(e)) => { | 
			
		
	
		
			
				
					|  |  |  |  |                         if e.kind() != io::ErrorKind::InvalidData { | 
			
		
	
		
			
				
					|  |  |  |  |                             state.set_flag(Flag::Eof, true); | 
			
		
	
		
			
				
					|  |  |  |  |                         } else { | 
			
		
	
	
		
			
				
					|  |  |  | @ -268,17 +352,20 @@ impl CrsnExtension for StdioOps { | 
			
		
	
		
			
				
					|  |  |  |  |                         } | 
			
		
	
		
			
				
					|  |  |  |  |                         return Ok(Some(())); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                     Err(other) => { | 
			
		
	
		
			
				
					|  |  |  |  |                         return Err(other); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  |         if rhandle == self.hdl_stdin_raw { | 
			
		
	
		
			
				
					|  |  |  |  |             loop { | 
			
		
	
		
			
				
					|  |  |  |  |                 match console::read_byte() { | 
			
		
	
		
			
				
					|  |  |  |  |                 match console::read_byte(None) { | 
			
		
	
		
			
				
					|  |  |  |  |                     Ok(c) => { | 
			
		
	
		
			
				
					|  |  |  |  |                         state.write(whandle, c as Value)?; | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                     Err(e) => { | 
			
		
	
		
			
				
					|  |  |  |  |                     Err(Fault::IOError(e)) => { | 
			
		
	
		
			
				
					|  |  |  |  |                         if e.kind() != io::ErrorKind::InvalidData { | 
			
		
	
		
			
				
					|  |  |  |  |                             state.set_flag(Flag::Eof, true); | 
			
		
	
		
			
				
					|  |  |  |  |                         } else { | 
			
		
	
	
		
			
				
					|  |  |  | @ -286,6 +373,9 @@ impl CrsnExtension for StdioOps { | 
			
		
	
		
			
				
					|  |  |  |  |                         } | 
			
		
	
		
			
				
					|  |  |  |  |                         return Ok(Some(())); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                     Err(other) => { | 
			
		
	
		
			
				
					|  |  |  |  |                         return Err(other); | 
			
		
	
		
			
				
					|  |  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |  |         } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |