@@ -3,10 +3,10 @@ use r_efi::protocols::loaded_image;
33use crate :: env:: current_exe;
44use crate :: ffi:: OsString ;
55use crate :: fmt;
6- use crate :: num:: NonZeroU16 ;
6+ use crate :: iter:: Iterator ;
7+ use crate :: mem:: size_of;
78use crate :: os:: uefi:: ffi:: OsStringExt ;
89use crate :: sys:: uefi:: helpers;
9- use crate :: sys_common:: wstr:: WStrUnits ;
1010use crate :: vec;
1111
1212pub struct Args {
@@ -19,10 +19,26 @@ pub fn args() -> Args {
1919 helpers:: current_handle_protocol :: < loaded_image:: Protocol > ( loaded_image:: PROTOCOL_GUID )
2020 . unwrap ( ) ;
2121
22- let lp_cmd_line = unsafe { ( * protocol. as_ptr ( ) ) . load_options as * const u16 } ;
23- let vec_args = match unsafe { WStrUnits :: new ( lp_cmd_line) } {
24- Some ( code_units) => parse_lp_cmd_line ( code_units) ,
25- None => Vec :: from ( [ current_exe ( ) . map ( Into :: into) . unwrap_or_default ( ) ] ) ,
22+ let lp_size = unsafe { ( * protocol. as_ptr ( ) ) . load_options_size } as usize ;
23+ let lp_size: usize = lp_size / size_of :: < u16 > ( ) ;
24+
25+ if lp_size <= 0 {
26+ return Args {
27+ parsed_args_list : Vec :: from ( [ current_exe ( ) . map ( Into :: into) . unwrap_or_default ( ) ] )
28+ . into_iter ( ) ,
29+ } ;
30+ }
31+
32+ let lp_cmd_line = unsafe {
33+ let temp = ( * protocol. as_ptr ( ) ) . load_options as * const u16 ;
34+ crate :: slice:: from_raw_parts ( temp, lp_size)
35+ } ;
36+
37+ let vec_args = parse_lp_cmd_line ( lp_cmd_line) ;
38+ let vec_args = if vec_args. is_empty ( ) {
39+ Vec :: from ( [ current_exe ( ) . map ( Into :: into) . unwrap_or_default ( ) ] )
40+ } else {
41+ vec_args
2642 } ;
2743
2844 Args { parsed_args_list : vec_args. into_iter ( ) }
@@ -62,30 +78,34 @@ impl DoubleEndedIterator for Args {
6278///
6379/// This implementation is based on what is defined in Section 3.4 of
6480/// [UEFI Shell Specification](https://uefi.org/sites/default/files/resources/UEFI_Shell_Spec_2_0.pdf)
65- fn parse_lp_cmd_line < ' a > ( mut code_units : WStrUnits < ' a > ) -> Vec < OsString > {
66- const QUOTE : NonZeroU16 = non_zero_u16 ( b'"' as u16 ) ;
67- const SPACE : NonZeroU16 = non_zero_u16 ( b' ' as u16 ) ;
68- const CARET : NonZeroU16 = non_zero_u16 ( b'^' as u16 ) ;
81+ fn parse_lp_cmd_line ( code_units : & [ u16 ] ) -> Vec < OsString > {
82+ const QUOTE : u16 = b'"' as u16 ;
83+ const SPACE : u16 = b' ' as u16 ;
84+ const CARET : u16 = b'^' as u16 ;
85+ const NULL : u16 = 0 ;
6986
7087 let mut ret_val = Vec :: new ( ) ;
88+ let mut code_units_iter = code_units. iter ( ) . peekable ( ) ;
7189
7290 // The executable name at the beginning is special.
7391 let mut in_quotes = false ;
7492 let mut cur = Vec :: new ( ) ;
75- for w in & mut code_units {
76- match w {
93+ while let Some ( w) = code_units_iter. next ( ) {
94+ match * w {
95+ // break on NULL
96+ NULL => break ,
7797 // A quote mark always toggles `in_quotes` no matter what because
7898 // there are no escape characters when parsing the executable name.
7999 QUOTE => in_quotes = !in_quotes,
80100 // If not `in_quotes` then whitespace ends argv[0].
81101 SPACE if !in_quotes => break ,
82102 // In all other cases the code unit is taken literally.
83- _ => cur. push ( w . get ( ) ) ,
103+ _ => cur. push ( * w ) ,
84104 }
85105 }
86106
87107 // Skip whitespace.
88- code_units . advance_while ( |w| w == SPACE ) ;
108+ while code_units_iter . next_if_eq ( & & SPACE ) . is_some ( ) { }
89109 ret_val. push ( OsString :: from_wide ( & cur) ) ;
90110
91111 // Parse the arguments according to these rules:
@@ -98,25 +118,27 @@ fn parse_lp_cmd_line<'a>(mut code_units: WStrUnits<'a>) -> Vec<OsString> {
98118 // * A caret can be escaped if preceded by caret.
99119 let mut cur = Vec :: new ( ) ;
100120 let mut in_quotes = false ;
101- while let Some ( w) = code_units. next ( ) {
102- match w {
121+ while let Some ( w) = code_units_iter. next ( ) {
122+ match * w {
123+ // break on NULL
124+ NULL => break ,
103125 // If not `in_quotes`, a space or tab ends the argument.
104126 SPACE if !in_quotes => {
105127 ret_val. push ( OsString :: from_wide ( & cur[ ..] ) ) ;
106128 cur. truncate ( 0 ) ;
107129
108130 // Skip whitespace.
109- code_units . advance_while ( |w| w == SPACE ) ;
131+ while code_units_iter . next_if_eq ( & & SPACE ) . is_some ( ) { }
110132 }
111133 // Caret can escape quotes or carets
112134 CARET if in_quotes => {
113- if let Some ( x) = code_units . next ( ) {
114- cur. push ( x . get ( ) )
135+ if let Some ( x) = code_units_iter . next ( ) {
136+ cur. push ( * x )
115137 }
116138 }
117- // If `in_quotes` and not backslash escaped (see above) then a quote either
139+ // If `in_quotes` and not caret escaped (see above) then a quote either
118140 // unsets `in_quote` or is escaped by another quote.
119- QUOTE if in_quotes => match code_units . peek ( ) {
141+ QUOTE if in_quotes => match code_units_iter . peek ( ) {
120142 // Otherwise set `in_quotes`.
121143 Some ( _) => in_quotes = false ,
122144 // The end of the command line.
@@ -126,7 +148,7 @@ fn parse_lp_cmd_line<'a>(mut code_units: WStrUnits<'a>) -> Vec<OsString> {
126148 // If not `in_quotes` and not BACKSLASH escaped (see above) then a quote sets `in_quote`.
127149 QUOTE => in_quotes = true ,
128150 // Everything else is always taken literally.
129- _ => cur. push ( w . get ( ) ) ,
151+ _ => cur. push ( * w ) ,
130152 }
131153 }
132154 // Push the final argument, if any.
@@ -135,14 +157,3 @@ fn parse_lp_cmd_line<'a>(mut code_units: WStrUnits<'a>) -> Vec<OsString> {
135157 }
136158 ret_val
137159}
138-
139- /// This is the const equivalent to `NonZeroU16::new(n).unwrap()`
140- ///
141- /// FIXME: This can be removed once `Option::unwrap` is stably const.
142- /// See the `const_option` feature (#67441).
143- const fn non_zero_u16 ( n : u16 ) -> NonZeroU16 {
144- match NonZeroU16 :: new ( n) {
145- Some ( n) => n,
146- None => panic ! ( "called `unwrap` on a `None` value" ) ,
147- }
148- }
0 commit comments