22
33//! EFI Shell Protocol v2.2
44
5- #![ cfg( feature = "alloc" ) ]
6-
7- use alloc:: vec:: Vec ;
85use uefi_macros:: unsafe_protocol;
96use uefi_raw:: Status ;
107
8+ use core:: marker:: PhantomData ;
119use core:: ptr;
1210
1311use uefi_raw:: protocol:: shell:: ShellProtocol ;
@@ -20,6 +18,35 @@ use crate::{CStr16, Char16};
2018#[ unsafe_protocol( ShellProtocol :: GUID ) ]
2119pub struct Shell ( ShellProtocol ) ;
2220
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+
2350impl Shell {
2451 /// Gets the value of the specified environment variable
2552 ///
@@ -50,36 +77,12 @@ impl Shell {
5077 ///
5178 /// * `Vec<env_names>` - Vector of environment variable names
5279 #[ 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 ,
8185 }
82- env_vec
8386 }
8487
8588 /// Sets the environment variable
@@ -100,3 +103,64 @@ impl Shell {
100103 unsafe { ( self . 0 . set_env ) ( name_ptr. cast ( ) , value_ptr. cast ( ) , volatile) }
101104 }
102105}
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