@@ -3,10 +3,10 @@ use r_efi::protocols::loaded_image;
3
3
use crate :: env:: current_exe;
4
4
use crate :: ffi:: OsString ;
5
5
use crate :: fmt;
6
- use crate :: num:: NonZeroU16 ;
6
+ use crate :: iter:: Iterator ;
7
+ use crate :: mem:: size_of;
7
8
use crate :: os:: uefi:: ffi:: OsStringExt ;
8
9
use crate :: sys:: uefi:: helpers;
9
- use crate :: sys_common:: wstr:: WStrUnits ;
10
10
use crate :: vec;
11
11
12
12
pub struct Args {
@@ -19,10 +19,26 @@ pub fn args() -> Args {
19
19
helpers:: current_handle_protocol :: < loaded_image:: Protocol > ( loaded_image:: PROTOCOL_GUID )
20
20
. unwrap ( ) ;
21
21
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
26
42
} ;
27
43
28
44
Args { parsed_args_list : vec_args. into_iter ( ) }
@@ -62,30 +78,34 @@ impl DoubleEndedIterator for Args {
62
78
///
63
79
/// This implementation is based on what is defined in Section 3.4 of
64
80
/// [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 ;
69
86
70
87
let mut ret_val = Vec :: new ( ) ;
88
+ let mut code_units_iter = code_units. iter ( ) . peekable ( ) ;
71
89
72
90
// The executable name at the beginning is special.
73
91
let mut in_quotes = false ;
74
92
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 ,
77
97
// A quote mark always toggles `in_quotes` no matter what because
78
98
// there are no escape characters when parsing the executable name.
79
99
QUOTE => in_quotes = !in_quotes,
80
100
// If not `in_quotes` then whitespace ends argv[0].
81
101
SPACE if !in_quotes => break ,
82
102
// In all other cases the code unit is taken literally.
83
- _ => cur. push ( w . get ( ) ) ,
103
+ _ => cur. push ( * w ) ,
84
104
}
85
105
}
86
106
87
107
// Skip whitespace.
88
- code_units . advance_while ( |w| w == SPACE ) ;
108
+ while code_units_iter . next_if_eq ( & & SPACE ) . is_some ( ) { }
89
109
ret_val. push ( OsString :: from_wide ( & cur) ) ;
90
110
91
111
// Parse the arguments according to these rules:
@@ -98,25 +118,27 @@ fn parse_lp_cmd_line<'a>(mut code_units: WStrUnits<'a>) -> Vec<OsString> {
98
118
// * A caret can be escaped if preceded by caret.
99
119
let mut cur = Vec :: new ( ) ;
100
120
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 ,
103
125
// If not `in_quotes`, a space or tab ends the argument.
104
126
SPACE if !in_quotes => {
105
127
ret_val. push ( OsString :: from_wide ( & cur[ ..] ) ) ;
106
128
cur. truncate ( 0 ) ;
107
129
108
130
// Skip whitespace.
109
- code_units . advance_while ( |w| w == SPACE ) ;
131
+ while code_units_iter . next_if_eq ( & & SPACE ) . is_some ( ) { }
110
132
}
111
133
// Caret can escape quotes or carets
112
134
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 )
115
137
}
116
138
}
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
118
140
// 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 ( ) {
120
142
// Otherwise set `in_quotes`.
121
143
Some ( _) => in_quotes = false ,
122
144
// The end of the command line.
@@ -126,7 +148,7 @@ fn parse_lp_cmd_line<'a>(mut code_units: WStrUnits<'a>) -> Vec<OsString> {
126
148
// If not `in_quotes` and not BACKSLASH escaped (see above) then a quote sets `in_quote`.
127
149
QUOTE => in_quotes = true ,
128
150
// Everything else is always taken literally.
129
- _ => cur. push ( w . get ( ) ) ,
151
+ _ => cur. push ( * w ) ,
130
152
}
131
153
}
132
154
// Push the final argument, if any.
@@ -135,14 +157,3 @@ fn parse_lp_cmd_line<'a>(mut code_units: WStrUnits<'a>) -> Vec<OsString> {
135
157
}
136
158
ret_val
137
159
}
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