Skip to content

Commit cd5e626

Browse files
committed
Added initial implementation of get_env()
1 parent 36e28a4 commit cd5e626

File tree

2 files changed

+93
-20
lines changed

2 files changed

+93
-20
lines changed

uefi-test-runner/src/proto/shell.rs

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,42 @@
11
use uefi::boot;
22
use uefi::proto::shell::{Shell, ShellFileHandle};
33
use uefi::CStr16;
4+
use uefi::data_types::Char16;
45

56
pub fn test() {
67
info!("Running shell protocol tests");
78

89
let handle = boot::get_handle_for_protocol::<Shell>().expect("No Shell handles");
9-
// let mut fs = uefi::fs::FileSystem::new(sfs
10-
// let (fs_handle, mut sfs) = find_test_disk();
1110

1211
let mut shell =
1312
boot::open_protocol_exclusive::<Shell>(handle).expect("Failed to open Shell protocol");
1413

1514
// create some files
16-
let mut test_buf = [0u16; 12];
17-
let test_str = CStr16::from_str_with_buf("test", &mut test_buf).unwrap();
15+
// let mut test_buf = [0u16; 12];
16+
// let test_str = CStr16::from_str_with_buf("test", &mut test_buf).unwrap();
1817

19-
let cur_env_str = shell.get_env(None).expect("Could not get environment variable");
20-
info!("cur_env_str size: {}", cur_env_str.num_chars());
21-
info!("cur_env_str: {}", cur_env_str);
18+
/* Test retrieving list of environment variable names (null input) */
19+
let cur_env_vec = shell.get_env(None).expect("Could not get environment variable").vec().unwrap();
20+
let mut test_buf = [0u16; 64];
21+
assert_eq!(*cur_env_vec.get(0).unwrap(), CStr16::from_str_with_buf("path", &mut test_buf).unwrap());
22+
assert_eq!(*cur_env_vec.get(1).unwrap(), CStr16::from_str_with_buf("nonesting", &mut test_buf).unwrap());
2223

23-
/* Testing setting and getting a specific environment variable */
24+
// Debug statements TODO: Remove
25+
info!("cur_env_vec size: {}", cur_env_vec.len());
26+
for (i, env_var) in cur_env_vec.iter().enumerate() {
27+
info!("i: {}, env_var: {}", i, env_var);
28+
}
29+
30+
/* Test setting and getting a specific environment variable */
2431
let mut test_env_buf = [0u16; 32];
2532
let test_var = CStr16::from_str_with_buf("test_var", &mut test_env_buf).unwrap();
2633
let mut test_val_buf = [0u16; 32];
2734
let test_val = CStr16::from_str_with_buf("test_val", &mut test_val_buf).unwrap();
2835
assert!(shell.get_env(Some(test_var)).is_none());
2936
shell.set_env(test_var, test_val, false);
30-
let cur_env_str = shell.get_env(Some(test_var)).expect("Could not get environment variable");
37+
let cur_env_str = shell.get_env(Some(test_var)).expect("Could not get environment variable").val().unwrap();
3138
assert_eq!(cur_env_str, test_val);
3239

33-
// for (i, c) in cur_env_str.iter().enumerate() {
34-
// info!("cur_env_str: i: {}, c: {}", i, c);
35-
// }
36-
3740
// let mut cur_fs_buf = [0u16; 32];
3841
// let cur_fs_str = CStr16::from_str_with_buf("", &mut cur_fs_buf).unwrap();
3942
// info!("cur_fs_str size 1: {}", cur_fs_str.num_chars());

uefi/src/proto/shell/mod.rs

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
//! EFI Shell Protocol v2.2
22
3+
#![cfg(feature = "alloc")]
4+
5+
use alloc::vec::Vec;
6+
37
use core::{ffi::c_void, marker::PhantomData, mem::MaybeUninit, ptr};
48

59
use uefi_macros::unsafe_protocol;
@@ -96,6 +100,36 @@ impl core::fmt::Debug for Shell {
96100
}
97101
}
98102

103+
/// Enum describing output options for get_env()
104+
///
105+
/// `EnvOutput::Val` - Value for a given variable
106+
/// `EnvOutput::VarVec` - Vec of current environment variables
107+
#[derive(Debug)]
108+
pub enum EnvOutput<'a> {
109+
/// Value for a given variable
110+
Val(&'a CStr16),
111+
/// Vec of current environment variable names
112+
Vec(Vec<&'a CStr16>),
113+
}
114+
115+
impl<'a> EnvOutput<'a> {
116+
/// Extracts the env var value from EnvOutput
117+
pub fn val(self) -> Option<&'a CStr16> {
118+
match self {
119+
EnvOutput::Val(v) => Some(v),
120+
_ => None,
121+
}
122+
}
123+
124+
/// Extracts the vector of variable names from EnvOutput
125+
pub fn vec(self) -> Option<Vec<&'a CStr16>> {
126+
match self {
127+
EnvOutput::Vec(v) => Some(v),
128+
_ => None,
129+
}
130+
}
131+
}
132+
99133
impl Shell {
100134
/// TODO
101135
pub fn execute(
@@ -131,13 +165,49 @@ impl Shell {
131165
///
132166
/// * `Some(env_value)` - Value of the environment variable
133167
/// * `None` - Environment variable doesn't exist
134-
pub fn get_env<'a>(&'a self, name: Option<&CStr16>) -> Option<&'a CStr16> {
135-
let name_ptr: *const Char16 = name.map_or(core::ptr::null(), |x| (x as *const CStr16).cast());
136-
let var_val = (self.get_env)(name_ptr);
137-
if var_val.is_null() {
138-
None
139-
} else {
140-
unsafe { Some(CStr16::from_ptr(var_val)) }
168+
pub fn get_env<'a>(&'a self, name: Option<&CStr16>) -> Option<EnvOutput<'a>> {
169+
match name {
170+
Some(n) => {
171+
let name_ptr: *const Char16 = (n as *const CStr16).cast();
172+
let var_val = (self.get_env)(name_ptr);
173+
if var_val.is_null() {
174+
None
175+
} else {
176+
unsafe { Some(EnvOutput::Val(CStr16::from_ptr(var_val))) }
177+
}
178+
}
179+
None => {
180+
let mut env_vec = Vec::new();
181+
let cur_env_ptr = (self.get_env)(core::ptr::null());
182+
183+
let mut cur_start = cur_env_ptr;
184+
let mut cur_len = 0;
185+
186+
let mut i = 0;
187+
let mut null_count = 0;
188+
unsafe {
189+
while null_count <= 1 {
190+
if (*(cur_env_ptr.add(i))) == Char16::from_u16_unchecked(0) {
191+
if cur_len > 0 {
192+
// TODO: Optimize this to directly convert a
193+
// Char16 slice to CStr16
194+
env_vec.push(CStr16::from_ptr(cur_start));
195+
}
196+
cur_len = 0;
197+
null_count += 1;
198+
}
199+
else {
200+
if null_count > 0 {
201+
cur_start = cur_env_ptr.add(i);
202+
}
203+
null_count = 0;
204+
cur_len += 1;
205+
}
206+
i += 1;
207+
}
208+
}
209+
Some(EnvOutput::Vec(env_vec))
210+
}
141211
}
142212
}
143213

0 commit comments

Comments
 (0)