@@ -62,6 +62,8 @@ pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params,
6262 let mut format = None ;
6363 let mut context_count = None ;
6464 let tabsize_re = Regex :: new ( r"^--tabsize=(?<num>\d+)$" ) . unwrap ( ) ;
65+ let context_re =
66+ Regex :: new ( r"^(-[cC](?<num1>\d*)|--context(=(?<num2>\d*))?|-(?<num3>\d+)c)$" ) . unwrap ( ) ;
6567 let unified_re =
6668 Regex :: new ( r"^(-[uU](?<num1>\d*)|--unified(=(?<num2>\d*))?|-(?<num3>\d+)u)$" ) . unwrap ( ) ;
6769 while let Some ( param) = opts. next ( ) {
@@ -106,6 +108,40 @@ pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params,
106108 } ;
107109 continue ;
108110 }
111+ if context_re. is_match ( param. to_string_lossy ( ) . as_ref ( ) ) {
112+ if format. is_some ( ) && format != Some ( Format :: Context ) {
113+ return Err ( "Conflicting output style options" . to_string ( ) ) ;
114+ }
115+ format = Some ( Format :: Context ) ;
116+ let captures = context_re. captures ( param. to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
117+ let num = captures
118+ . name ( "num1" )
119+ . or ( captures. name ( "num2" ) )
120+ . or ( captures. name ( "num3" ) ) ;
121+ if num. is_some ( ) && !num. unwrap ( ) . as_str ( ) . is_empty ( ) {
122+ context_count = Some ( num. unwrap ( ) . as_str ( ) . parse :: < usize > ( ) . unwrap ( ) ) ;
123+ }
124+ if param == "-C" {
125+ let next_param = opts. peek ( ) ;
126+ if next_param. is_some ( ) {
127+ let next_value = next_param
128+ . unwrap ( )
129+ . to_string_lossy ( )
130+ . as_ref ( )
131+ . parse :: < usize > ( ) ;
132+ if next_value. is_ok ( ) {
133+ context_count = Some ( next_value. unwrap ( ) ) ;
134+ opts. next ( ) ;
135+ } else {
136+ return Err ( format ! (
137+ "invalid context length '{}'" ,
138+ next_param. unwrap( ) . to_string_lossy( )
139+ ) ) ;
140+ }
141+ }
142+ }
143+ continue ;
144+ }
109145 if unified_re. is_match ( param. to_string_lossy ( ) . as_ref ( ) ) {
110146 if format. is_some ( ) && format != Some ( Format :: Unified ) {
111147 return Err ( "Conflicting output style options" . to_string ( ) ) ;
@@ -143,25 +179,8 @@ pub fn parse_params<I: IntoIterator<Item = OsString>>(opts: I) -> Result<Params,
143179 let p = osstr_bytes ( & param) ;
144180 if p. first ( ) == Some ( & b'-' ) && p. get ( 1 ) != Some ( & b'-' ) {
145181 let mut bit = p[ 1 ..] . iter ( ) . copied ( ) . peekable ( ) ;
146- // Can't use a for loop because `diff -30u` is supposed to make a diff
147- // with 30 lines of context.
148182 while let Some ( b) = bit. next ( ) {
149183 match b {
150- b'0' ..=b'9' => {
151- context_count = Some ( ( b - b'0' ) as usize ) ;
152- while let Some ( b'0' ..=b'9' ) = bit. peek ( ) {
153- context_count = Some ( context_count. unwrap ( ) * 10 ) ;
154- context_count = Some (
155- context_count. unwrap ( ) + ( bit. next ( ) . unwrap ( ) - b'0' ) as usize ,
156- ) ;
157- }
158- }
159- b'c' => {
160- if format. is_some ( ) && format != Some ( Format :: Context ) {
161- return Err ( "Conflicting output style options" . to_string ( ) ) ;
162- }
163- format = Some ( Format :: Context ) ;
164- }
165184 b'e' => {
166185 if format. is_some ( ) && format != Some ( Format :: Ed ) {
167186 return Err ( "Conflicting output style options" . to_string ( ) ) ;
@@ -230,6 +249,63 @@ mod tests {
230249 ) ;
231250 }
232251 #[ test]
252+ fn context_valid ( ) {
253+ for args in [ vec ! [ "-c" ] , vec ! [ "--context" ] , vec ! [ "--context=" ] ] {
254+ let mut params = vec ! [ "diff" ] ;
255+ params. extend ( args) ;
256+ params. extend ( [ "foo" , "bar" ] ) ;
257+ assert_eq ! (
258+ Ok ( Params {
259+ from: os( "foo" ) ,
260+ to: os( "bar" ) ,
261+ format: Format :: Context ,
262+ ..Default :: default ( )
263+ } ) ,
264+ parse_params( params. iter( ) . map( |x| os( x) ) )
265+ ) ;
266+ }
267+ for args in [
268+ vec ! [ "-c42" ] ,
269+ vec ! [ "-C42" ] ,
270+ vec ! [ "-C" , "42" ] ,
271+ vec ! [ "--context=42" ] ,
272+ vec ! [ "-42c" ] ,
273+ ] {
274+ let mut params = vec ! [ "diff" ] ;
275+ params. extend ( args) ;
276+ params. extend ( [ "foo" , "bar" ] ) ;
277+ assert_eq ! (
278+ Ok ( Params {
279+ from: os( "foo" ) ,
280+ to: os( "bar" ) ,
281+ format: Format :: Context ,
282+ context_count: 42 ,
283+ ..Default :: default ( )
284+ } ) ,
285+ parse_params( params. iter( ) . map( |x| os( x) ) )
286+ ) ;
287+ }
288+ }
289+ #[ test]
290+ fn context_invalid ( ) {
291+ for args in [
292+ vec ! [ "-c" , "42" ] ,
293+ vec ! [ "-c=42" ] ,
294+ vec ! [ "-c=" ] ,
295+ vec ! [ "-C" ] ,
296+ vec ! [ "-C=42" ] ,
297+ vec ! [ "-C=" ] ,
298+ vec ! [ "--context42" ] ,
299+ vec ! [ "--context" , "42" ] ,
300+ vec ! [ "-42C" ] ,
301+ ] {
302+ let mut params = vec ! [ "diff" ] ;
303+ params. extend ( args) ;
304+ params. extend ( [ "foo" , "bar" ] ) ;
305+ assert ! ( parse_params( params. iter( ) . map( |x| os( x) ) ) . is_err( ) ) ;
306+ }
307+ }
308+ #[ test]
233309 fn unified_valid ( ) {
234310 for args in [ vec ! [ "-u" ] , vec ! [ "--unified" ] , vec ! [ "--unified=" ] ] {
235311 let mut params = vec ! [ "diff" ] ;
0 commit comments