@@ -115,42 +115,74 @@ impl<'a> FormatArguments<'a> {
115115 }
116116 }
117117
118- fn get_num < T > ( os : & OsStr ) -> T
118+ // Parse an OsStr that we know to start with a '/"
119+ fn parse_quote_start < T > ( os : & OsStr ) -> Result < T , ExtendedParserError < T > >
119120 where
120121 T : ExtendedParser + From < u8 > + From < u32 > + Default ,
121122 {
122- // FIXME: Remove unwrap
123- let s = os_str_as_bytes ( os) . unwrap ( ) ;
124- // Check if the string begins with a quote, and is therefore a literal
125- if let Some ( ( & first, bytes) ) = s. split_first ( ) {
126- if ( first == b'"' || first == b'\'' ) && !bytes. is_empty ( ) {
127- let ( val, len) = if let Some ( c) = bytes
128- . utf8_chunks ( )
129- . next ( )
130- . expect ( "bytes should not be empty" )
131- . valid ( )
132- . chars ( )
133- . next ( )
134- {
135- // Valid UTF-8 character, cast the codepoint to u32 then T
136- // (largest unicode codepoint is only 3 bytes, so this is safe)
137- ( ( c as u32 ) . into ( ) , c. len_utf8 ( ) )
138- } else {
139- // Not a valid UTF-8 character, use the first byte
140- ( bytes[ 0 ] . into ( ) , 1 )
141- } ;
142- // Emit a warning if there are additional characters
143- if bytes. len ( ) > len {
144- show_warning ! (
145- "{}: character(s) following character constant have been ignored" ,
146- String :: from_utf8_lossy( & bytes[ len..] )
147- ) ;
148- }
149- return val;
123+ // If this fails (this can only happens on Windows), then just
124+ // return NotNumeric.
125+ let s = match os_str_as_bytes ( os) {
126+ Ok ( s) => s,
127+ Err ( _) => return Err ( ExtendedParserError :: NotNumeric ) ,
128+ } ;
129+
130+ let bytes = match s. split_first ( ) {
131+ Some ( ( b'"' , bytes) ) | Some ( ( b'\'' , bytes) ) => bytes,
132+ _ => {
133+ // This really can't happen, the string we are given must start with '/".
134+ debug_assert ! ( false ) ;
135+ return Err ( ExtendedParserError :: NotNumeric ) ;
150136 }
137+ } ;
138+
139+ if bytes. is_empty ( ) {
140+ return Err ( ExtendedParserError :: NotNumeric ) ;
151141 }
142+
143+ let ( val, len) = if let Some ( c) = bytes
144+ . utf8_chunks ( )
145+ . next ( )
146+ . expect ( "bytes should not be empty" )
147+ . valid ( )
148+ . chars ( )
149+ . next ( )
150+ {
151+ // Valid UTF-8 character, cast the codepoint to u32 then T
152+ // (largest unicode codepoint is only 3 bytes, so this is safe)
153+ ( ( c as u32 ) . into ( ) , c. len_utf8 ( ) )
154+ } else {
155+ // Not a valid UTF-8 character, use the first byte
156+ ( bytes[ 0 ] . into ( ) , 1 )
157+ } ;
158+ // Emit a warning if there are additional characters
159+ if bytes. len ( ) > len {
160+ return Err ( ExtendedParserError :: PartialMatch (
161+ val,
162+ String :: from_utf8_lossy ( & bytes[ len..] ) . to_string ( ) ,
163+ ) ) ;
164+ }
165+
166+ Ok ( val)
167+ }
168+
169+ fn get_num < T > ( os : & OsStr ) -> T
170+ where
171+ T : ExtendedParser + From < u8 > + From < u32 > + Default ,
172+ {
152173 let s = os. to_string_lossy ( ) ;
153- extract_value ( T :: extended_parse ( & s) , & s)
174+ let first = s. as_bytes ( ) . first ( ) . copied ( ) ;
175+
176+ let quote_start = first == Some ( b'"' ) || first == Some ( b'\'' ) ;
177+ let parsed = if quote_start {
178+ // The string begins with a quote
179+ Self :: parse_quote_start ( os)
180+ } else {
181+ T :: extended_parse ( & s)
182+ } ;
183+
184+ // Get the best possible value, even if parsed was an error.
185+ extract_value ( parsed, & s, quote_start)
154186 }
155187
156188 fn get_at_relative_position ( & mut self , pos : NonZero < usize > ) -> Option < & ' a FormatArgument > {
@@ -172,7 +204,11 @@ impl<'a> FormatArguments<'a> {
172204 }
173205}
174206
175- fn extract_value < T : Default > ( p : Result < T , ExtendedParserError < T > > , input : & str ) -> T {
207+ fn extract_value < T : Default > (
208+ p : Result < T , ExtendedParserError < T > > ,
209+ input : & str ,
210+ quote_start : bool ,
211+ ) -> T {
176212 match p {
177213 Ok ( v) => v,
178214 Err ( e) => {
@@ -192,8 +228,8 @@ fn extract_value<T: Default>(p: Result<T, ExtendedParserError<T>>, input: &str)
192228 Default :: default ( )
193229 }
194230 ExtendedParserError :: PartialMatch ( v, rest) => {
195- let bytes = input . as_encoded_bytes ( ) ;
196- if !bytes . is_empty ( ) && ( bytes [ 0 ] == b'\'' || bytes [ 0 ] == b'"' ) {
231+ if quote_start {
232+ set_exit_code ( 0 ) ;
197233 show_warning ! (
198234 "{rest}: character(s) following character constant have been ignored"
199235 ) ;
0 commit comments