2
2
3
3
//! EFI Shell Protocol v2.2
4
4
5
- #![ cfg( feature = "alloc" ) ]
6
-
7
- use alloc:: vec:: Vec ;
8
5
use uefi_macros:: unsafe_protocol;
9
6
use uefi_raw:: Status ;
10
7
8
+ use core:: marker:: PhantomData ;
11
9
use core:: ptr;
12
10
13
11
use uefi_raw:: protocol:: shell:: ShellProtocol ;
@@ -20,6 +18,35 @@ use crate::{CStr16, Char16};
20
18
#[ unsafe_protocol( ShellProtocol :: GUID ) ]
21
19
pub struct Shell ( ShellProtocol ) ;
22
20
21
+ /// Iterator over the names of environmental variables obtained from the Shell protocol.
22
+ #[ derive( Debug ) ]
23
+ pub struct Vars < ' a > {
24
+ /// Char16 containing names of environment variables
25
+ inner : * const Char16 ,
26
+ /// Placeholder to attach a lifetime to `Vars`
27
+ placeholder : PhantomData < & ' a CStr16 > ,
28
+ }
29
+
30
+ impl < ' a > Iterator for Vars < ' a > {
31
+ type Item = & ' a CStr16 ;
32
+ // We iterate a list of NUL terminated CStr16s.
33
+ // The list is terminated with a double NUL.
34
+ fn next ( & mut self ) -> Option < Self :: Item > {
35
+ let cur_start = self . inner ;
36
+ let mut cur_len = 0 ;
37
+ unsafe {
38
+ if * ( cur_start) == Char16 :: from_u16_unchecked ( 0 ) {
39
+ return None ;
40
+ }
41
+ while * ( cur_start. add ( cur_len) ) != Char16 :: from_u16_unchecked ( 0 ) {
42
+ cur_len += 1 ;
43
+ }
44
+ self . inner = self . inner . add ( cur_len + 1 ) ;
45
+ Some ( CStr16 :: from_ptr ( cur_start) )
46
+ }
47
+ }
48
+ }
49
+
23
50
impl Shell {
24
51
/// Gets the value of the specified environment variable
25
52
///
@@ -50,36 +77,12 @@ impl Shell {
50
77
///
51
78
/// * `Vec<env_names>` - Vector of environment variable names
52
79
#[ must_use]
53
- pub fn get_envs ( & self ) -> Vec < & CStr16 > {
54
- let mut env_vec: Vec < & CStr16 > = Vec :: new ( ) ;
55
- let cur_env_ptr = unsafe { ( self . 0 . get_env ) ( ptr:: null ( ) ) } ;
56
-
57
- let mut cur_start = cur_env_ptr;
58
- let mut cur_len = 0 ;
59
-
60
- let mut i = 0 ;
61
- let mut null_count = 0 ;
62
- unsafe {
63
- while null_count <= 1 {
64
- if ( * ( cur_env_ptr. add ( i) ) ) == Char16 :: from_u16_unchecked ( 0 ) . into ( ) {
65
- if cur_len > 0 {
66
- env_vec. push ( CStr16 :: from_char16_with_nul (
67
- & ( * ptr:: slice_from_raw_parts ( cur_start. cast ( ) , cur_len + 1 ) ) ,
68
- ) . unwrap ( ) ) ;
69
- }
70
- cur_len = 0 ;
71
- null_count += 1 ;
72
- } else {
73
- if null_count > 0 {
74
- cur_start = cur_env_ptr. add ( i) ;
75
- }
76
- null_count = 0 ;
77
- cur_len += 1 ;
78
- }
79
- i += 1 ;
80
- }
80
+ pub fn get_envs ( & self ) -> Vars {
81
+ let env_ptr = unsafe { ( self . 0 . get_env ) ( ptr:: null ( ) ) } ;
82
+ Vars {
83
+ inner : env_ptr. cast :: < Char16 > ( ) ,
84
+ placeholder : PhantomData ,
81
85
}
82
- env_vec
83
86
}
84
87
85
88
/// Sets the environment variable
@@ -100,3 +103,64 @@ impl Shell {
100
103
unsafe { ( self . 0 . set_env ) ( name_ptr. cast ( ) , value_ptr. cast ( ) , volatile) }
101
104
}
102
105
}
106
+
107
+ #[ cfg( test) ]
108
+ mod tests {
109
+ use super :: * ;
110
+ use alloc:: vec:: Vec ;
111
+ use uefi:: cstr16;
112
+
113
+ /// Testing Vars struct
114
+ #[ test]
115
+ fn test_vars ( ) {
116
+ // Empty Vars
117
+ let mut vars_mock = Vec :: < u16 > :: new ( ) ;
118
+ vars_mock. push ( 0 ) ;
119
+ vars_mock. push ( 0 ) ;
120
+ let mut vars = Vars {
121
+ inner : vars_mock. as_ptr ( ) . cast ( ) ,
122
+ placeholder : PhantomData ,
123
+ } ;
124
+ assert ! ( vars. next( ) . is_none( ) ) ;
125
+
126
+ // One environment variable in Vars
127
+ let mut vars_mock = Vec :: < u16 > :: new ( ) ;
128
+ vars_mock. push ( b'f' as u16 ) ;
129
+ vars_mock. push ( b'o' as u16 ) ;
130
+ vars_mock. push ( b'o' as u16 ) ;
131
+ vars_mock. push ( 0 ) ;
132
+ vars_mock. push ( 0 ) ;
133
+ let vars = Vars {
134
+ inner : vars_mock. as_ptr ( ) . cast ( ) ,
135
+ placeholder : PhantomData ,
136
+ } ;
137
+ assert_eq ! ( vars. collect:: <Vec <_>>( ) , Vec :: from( [ cstr16!( "foo" ) ] ) ) ;
138
+
139
+ // Multiple environment variables in Vars
140
+ let mut vars_mock = Vec :: < u16 > :: new ( ) ;
141
+ vars_mock. push ( b'f' as u16 ) ;
142
+ vars_mock. push ( b'o' as u16 ) ;
143
+ vars_mock. push ( b'o' as u16 ) ;
144
+ vars_mock. push ( b'1' as u16 ) ;
145
+ vars_mock. push ( 0 ) ;
146
+ vars_mock. push ( b'b' as u16 ) ;
147
+ vars_mock. push ( b'a' as u16 ) ;
148
+ vars_mock. push ( b'r' as u16 ) ;
149
+ vars_mock. push ( 0 ) ;
150
+ vars_mock. push ( b'b' as u16 ) ;
151
+ vars_mock. push ( b'a' as u16 ) ;
152
+ vars_mock. push ( b'z' as u16 ) ;
153
+ vars_mock. push ( b'2' as u16 ) ;
154
+ vars_mock. push ( 0 ) ;
155
+ vars_mock. push ( 0 ) ;
156
+
157
+ let vars = Vars {
158
+ inner : vars_mock. as_ptr ( ) . cast ( ) ,
159
+ placeholder : PhantomData ,
160
+ } ;
161
+ assert_eq ! (
162
+ vars. collect:: <Vec <_>>( ) ,
163
+ Vec :: from( [ cstr16!( "foo1" ) , cstr16!( "bar" ) , cstr16!( "baz2" ) ] )
164
+ ) ;
165
+ }
166
+ }
0 commit comments