@@ -6,43 +6,49 @@ use crate::ptr::NonNull;
6
6
7
7
const MAX_BUFFER_SIZE : usize = 8192 ;
8
8
9
- pub struct Stdin ;
9
+ pub struct Stdin {
10
+ pending : Option < char > ,
11
+ }
12
+
10
13
pub struct Stdout ;
11
14
pub struct Stderr ;
12
15
13
16
impl Stdin {
14
17
pub const fn new ( ) -> Stdin {
15
- Stdin
18
+ Stdin { pending : None }
16
19
}
17
20
}
18
21
19
22
impl io:: Read for Stdin {
20
- fn read ( & mut self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
23
+ fn read ( & mut self , mut buf : & mut [ u8 ] ) -> io:: Result < usize > {
21
24
let st: NonNull < r_efi:: efi:: SystemTable > = uefi:: env:: system_table ( ) . cast ( ) ;
22
25
let stdin = unsafe { ( * st. as_ptr ( ) ) . con_in } ;
23
26
24
- // Try reading any pending data
25
- let inp = match read_key_stroke ( stdin) {
26
- Ok ( x) => x,
27
- Err ( e) if e == r_efi:: efi:: Status :: NOT_READY => {
28
- // Wait for keypress for new data
29
- wait_stdin ( stdin) ?;
30
- read_key_stroke ( stdin) . map_err ( |x| io:: Error :: from_raw_os_error ( x. as_usize ( ) ) ) ?
27
+ // Write any pending character
28
+ if let Some ( ch) = self . pending {
29
+ if ch. len_utf8 ( ) > buf. len ( ) {
30
+ return Ok ( 0 ) ;
31
31
}
32
- Err ( e) => {
33
- return Err ( io:: Error :: from_raw_os_error ( e. as_usize ( ) ) ) ;
34
- }
35
- } ;
32
+ ch. encode_utf8 ( buf) ;
33
+ buf = & mut buf[ ch. len_utf8 ( ) ..] ;
34
+ self . pending = None ;
35
+ }
36
+
37
+ // Try reading any pending data
38
+ let inp = read ( stdin) ?;
36
39
37
40
// Check if the key is printiable character
38
- if inp. scan_code ! = 0x00 {
41
+ if inp = = 0x00 {
39
42
return Err ( io:: const_io_error!( io:: ErrorKind :: Interrupted , "Special Key Press" ) ) ;
40
43
}
41
44
42
- // SAFETY: Iterator will have only 1 character since we are reading only 1 Key
43
- // SAFETY: This character will always be UCS-2 and thus no surrogates.
44
- let ch: char = char:: decode_utf16 ( [ inp. unicode_char ] ) . next ( ) . unwrap ( ) . unwrap ( ) ;
45
+ // The option unwrap is safe since iterator will have 1 element.
46
+ let ch: char = char:: decode_utf16 ( [ inp] )
47
+ . next ( )
48
+ . unwrap ( )
49
+ . map_err ( |_| io:: const_io_error!( io:: ErrorKind :: InvalidInput , "Invalid Input" ) ) ?;
45
50
if ch. len_utf8 ( ) > buf. len ( ) {
51
+ self . pending = Some ( ch) ;
46
52
return Ok ( 0 ) ;
47
53
}
48
54
@@ -93,8 +99,8 @@ impl io::Write for Stderr {
93
99
// UCS-2 character should occupy 3 bytes at most in UTF-8
94
100
pub const STDIN_BUF_SIZE : usize = 3 ;
95
101
96
- pub fn is_ebadf ( _err : & io:: Error ) -> bool {
97
- true
102
+ pub fn is_ebadf ( err : & io:: Error ) -> bool {
103
+ err . raw_os_error ( ) == Some ( r_efi :: efi :: Status :: UNSUPPORTED . as_usize ( ) )
98
104
}
99
105
100
106
pub fn panic_output ( ) -> Option < impl io:: Write > {
@@ -132,6 +138,16 @@ unsafe fn simple_text_output(
132
138
if res. is_error ( ) { Err ( io:: Error :: from_raw_os_error ( res. as_usize ( ) ) ) } else { Ok ( ( ) ) }
133
139
}
134
140
141
+ fn read ( stdin : * mut r_efi:: protocols:: simple_text_input:: Protocol ) -> io:: Result < u16 > {
142
+ loop {
143
+ match read_key_stroke ( stdin) {
144
+ Ok ( x) => return Ok ( x. unicode_char ) ,
145
+ Err ( e) if e == r_efi:: efi:: Status :: NOT_READY => wait_stdin ( stdin) ?,
146
+ Err ( e) => return Err ( io:: Error :: from_raw_os_error ( e. as_usize ( ) ) ) ,
147
+ }
148
+ }
149
+ }
150
+
135
151
fn wait_stdin ( stdin : * mut r_efi:: protocols:: simple_text_input:: Protocol ) -> io:: Result < ( ) > {
136
152
let boot_services: NonNull < r_efi:: efi:: BootServices > =
137
153
uefi:: env:: boot_services ( ) . unwrap ( ) . cast ( ) ;
0 commit comments