66use clap:: { Arg , ArgAction , Command } ;
77use std:: ffi:: { OsStr , OsString } ;
88use std:: fs:: File ;
9- use std:: io:: { BufRead , BufReader , BufWriter , Read , Write , stdin, stdout} ;
9+ use std:: io:: { self , BufRead , BufReader , BufWriter , Read , Write , stdin, stdout} ;
1010use std:: path:: Path ;
1111use uucore:: display:: Quotable ;
1212use uucore:: error:: { FromIo , UResult , USimpleError , set_exit_code} ;
@@ -122,13 +122,41 @@ impl<T: AsRef<str>> From<T> for NumberFormat {
122122impl NumberFormat {
123123 /// Turns a line number into a `String` with at least `min_width` chars,
124124 /// formatted according to the `NumberFormat`s variant.
125- fn format ( & self , number : i64 , min_width : usize ) -> String {
125+ fn format_to < W : Write > ( & self , writer : & mut W , number : i64 , min_width : usize ) -> io:: Result < ( ) > {
126+ let mut buffer = itoa:: Buffer :: new ( ) ;
127+
126128 match self {
127- Self :: Left => format ! ( "{number:<min_width$}" ) ,
128- Self :: Right => format ! ( "{number:>min_width$}" ) ,
129- Self :: RightZero if number < 0 => format ! ( "-{0:0>1$}" , number. abs( ) , min_width - 1 ) ,
130- Self :: RightZero => format ! ( "{number:0>min_width$}" ) ,
129+ Self :: Left => {
130+ let num = buffer. format ( number) ;
131+ writer. write_all ( num. as_bytes ( ) ) ?;
132+ for _ in num. len ( ) ..min_width {
133+ writer. write_all ( b" " ) ?;
134+ }
135+ }
136+ Self :: Right => {
137+ let num = buffer. format ( number) ;
138+ for _ in num. len ( ) ..min_width {
139+ writer. write_all ( b" " ) ?;
140+ }
141+ writer. write_all ( num. as_bytes ( ) ) ?;
142+ }
143+ Self :: RightZero if number < 0 => {
144+ writer. write_all ( b"-" ) ?;
145+ let num = buffer. format ( number. abs ( ) ) ;
146+ for _ in num. len ( ) ..min_width. saturating_sub ( 1 ) {
147+ writer. write_all ( b"0" ) ?;
148+ }
149+ writer. write_all ( num. as_bytes ( ) ) ?;
150+ }
151+ Self :: RightZero => {
152+ let num = buffer. format ( number) ;
153+ for _ in num. len ( ) ..min_width {
154+ writer. write_all ( b"0" ) ?;
155+ }
156+ writer. write_all ( num. as_bytes ( ) ) ?;
157+ }
131158 }
159+ Ok ( ( ) )
132160 }
133161}
134162
@@ -346,8 +374,7 @@ pub fn uu_app() -> Command {
346374}
347375
348376/// Helper to write: prefix bytes + line bytes + newline
349- fn write_line ( writer : & mut impl Write , prefix : & [ u8 ] , line : & [ u8 ] ) -> std:: io:: Result < ( ) > {
350- writer. write_all ( prefix) ?;
377+ fn write_line ( writer : & mut impl Write , line : & [ u8 ] ) -> io:: Result < ( ) > {
351378 writer. write_all ( line) ?;
352379 writeln ! ( writer)
353380}
@@ -416,19 +443,22 @@ fn nl<T: Read>(reader: &mut BufReader<T>, stats: &mut Stats, settings: &Settings
416443 translate ! ( "nl-error-line-number-overflow" ) ,
417444 ) ) ;
418445 } ;
419- let mut prefix = settings
446+ settings
420447 . number_format
421- . format ( line_number, settings. number_width )
422- . into_bytes ( ) ;
423- prefix . extend_from_slice ( settings . number_separator . as_encoded_bytes ( ) ) ;
424- write_line ( & mut writer , & prefix , & line )
448+ . format_to ( & mut writer , line_number, settings. number_width )
449+ . map_err_context ( || translate ! ( "nl-error-could-not-write" ) ) ? ;
450+ writer
451+ . write_all ( settings . number_separator . as_encoded_bytes ( ) )
425452 . map_err_context ( || translate ! ( "nl-error-could-not-write" ) ) ?;
426453 stats. line_number = line_number. checked_add ( settings. line_increment ) ;
427454 } else {
428455 let prefix = " " . repeat ( settings. number_width + 1 ) ;
429- write_line ( & mut writer, prefix. as_bytes ( ) , & line)
456+ writer
457+ . write_all ( prefix. as_bytes ( ) )
430458 . map_err_context ( || translate ! ( "nl-error-could-not-write" ) ) ?;
431459 }
460+ write_line ( & mut writer, & line)
461+ . map_err_context ( || translate ! ( "nl-error-could-not-write" ) ) ?;
432462 }
433463 }
434464 writer
@@ -442,21 +472,26 @@ mod test {
442472 use super :: * ;
443473
444474 #[ test]
445- #[ allow( clippy:: cognitive_complexity) ]
446475 fn test_format ( ) {
447- assert_eq ! ( NumberFormat :: Left . format( 12 , 1 ) , "12" ) ;
448- assert_eq ! ( NumberFormat :: Left . format( -12 , 1 ) , "-12" ) ;
449- assert_eq ! ( NumberFormat :: Left . format( 12 , 4 ) , "12 " ) ;
450- assert_eq ! ( NumberFormat :: Left . format( -12 , 4 ) , "-12 " ) ;
451-
452- assert_eq ! ( NumberFormat :: Right . format( 12 , 1 ) , "12" ) ;
453- assert_eq ! ( NumberFormat :: Right . format( -12 , 1 ) , "-12" ) ;
454- assert_eq ! ( NumberFormat :: Right . format( 12 , 4 ) , " 12" ) ;
455- assert_eq ! ( NumberFormat :: Right . format( -12 , 4 ) , " -12" ) ;
456-
457- assert_eq ! ( NumberFormat :: RightZero . format( 12 , 1 ) , "12" ) ;
458- assert_eq ! ( NumberFormat :: RightZero . format( -12 , 1 ) , "-12" ) ;
459- assert_eq ! ( NumberFormat :: RightZero . format( 12 , 4 ) , "0012" ) ;
460- assert_eq ! ( NumberFormat :: RightZero . format( -12 , 4 ) , "-012" ) ;
476+ let helper = |fmt : NumberFormat , num : i64 , width : usize | -> String {
477+ let mut buf = Vec :: new ( ) ;
478+ fmt. format_to ( & mut buf, num, width) . unwrap ( ) ;
479+ String :: from_utf8 ( buf) . unwrap ( )
480+ } ;
481+
482+ assert_eq ! ( helper( NumberFormat :: Left , 12 , 1 ) , "12" ) ;
483+ assert_eq ! ( helper( NumberFormat :: Left , -12 , 1 ) , "-12" ) ;
484+ assert_eq ! ( helper( NumberFormat :: Left , 12 , 4 ) , "12 " ) ;
485+ assert_eq ! ( helper( NumberFormat :: Left , -12 , 4 ) , "-12 " ) ;
486+
487+ assert_eq ! ( helper( NumberFormat :: Right , 12 , 1 ) , "12" ) ;
488+ assert_eq ! ( helper( NumberFormat :: Right , -12 , 1 ) , "-12" ) ;
489+ assert_eq ! ( helper( NumberFormat :: Right , 12 , 4 ) , " 12" ) ;
490+ assert_eq ! ( helper( NumberFormat :: Right , -12 , 4 ) , " -12" ) ;
491+
492+ assert_eq ! ( helper( NumberFormat :: RightZero , 12 , 1 ) , "12" ) ;
493+ assert_eq ! ( helper( NumberFormat :: RightZero , -12 , 1 ) , "-12" ) ;
494+ assert_eq ! ( helper( NumberFormat :: RightZero , 12 , 4 ) , "0012" ) ;
495+ assert_eq ! ( helper( NumberFormat :: RightZero , -12 , 4 ) , "-012" ) ;
461496 }
462497}
0 commit comments