8
8
use clap:: { Arg , ArgAction , Command } ;
9
9
use std:: collections:: HashMap ;
10
10
use std:: fs:: File ;
11
- use std:: io:: { BufRead , BufReader , Read , stdin} ;
11
+ use std:: io:: { BufRead , BufReader , Read , Write , stdin, stdout } ;
12
12
use std:: path:: Path ;
13
13
use uucore:: display:: Quotable ;
14
14
use uucore:: error:: { FromIo , UResult , USimpleError } ;
15
15
use uucore:: format_usage;
16
16
use uucore:: locale:: { get_message, get_message_with_args} ;
17
17
18
18
const TAB_WIDTH : usize = 8 ;
19
+ const NL : u8 = b'\n' ;
20
+ const CR : u8 = b'\r' ;
21
+ const TAB : u8 = b'\t' ;
19
22
20
23
mod options {
21
24
pub const BYTES : & str = "bytes" ;
@@ -141,18 +144,18 @@ fn fold(filenames: &[String], bytes: bool, spaces: bool, width: usize) -> UResul
141
144
///
142
145
/// If `spaces` is `true`, attempt to break lines at whitespace boundaries.
143
146
fn fold_file_bytewise < T : Read > ( mut file : BufReader < T > , spaces : bool , width : usize ) -> UResult < ( ) > {
144
- let mut line = String :: new ( ) ;
147
+ let mut line = Vec :: new ( ) ;
145
148
146
149
loop {
147
150
if file
148
- . read_line ( & mut line)
151
+ . read_until ( NL , & mut line)
149
152
. map_err_context ( || get_message ( "fold-error-readline" ) ) ?
150
153
== 0
151
154
{
152
155
break ;
153
156
}
154
157
155
- if line == " \n " {
158
+ if line == [ NL ] {
156
159
println ! ( ) ;
157
160
line. truncate ( 0 ) ;
158
161
continue ;
@@ -166,8 +169,13 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
166
169
let slice = {
167
170
let slice = & line[ i..i + width] ;
168
171
if spaces && i + width < len {
169
- match slice. rfind ( |c : char | c. is_whitespace ( ) && c != '\r' ) {
170
- Some ( m) => & slice[ ..=m] ,
172
+ match slice
173
+ . iter ( )
174
+ . enumerate ( )
175
+ . rev ( )
176
+ . find ( |( _, c) | c. is_ascii_whitespace ( ) && * * c != CR )
177
+ {
178
+ Some ( ( m, _) ) => & slice[ ..=m] ,
171
179
None => slice,
172
180
}
173
181
} else {
@@ -178,7 +186,7 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
178
186
// Don't duplicate trailing newlines: if the slice is "\n", the
179
187
// previous iteration folded just before the end of the line and
180
188
// has already printed this newline.
181
- if slice == " \n " {
189
+ if slice == [ NL ] {
182
190
break ;
183
191
}
184
192
@@ -187,9 +195,10 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
187
195
let at_eol = i >= len;
188
196
189
197
if at_eol {
190
- print ! ( "{ slice}" ) ;
198
+ stdout ( ) . write_all ( slice) ? ;
191
199
} else {
192
- println ! ( "{slice}" ) ;
200
+ stdout ( ) . write_all ( slice) ?;
201
+ stdout ( ) . write_all ( & [ NL ] ) ?;
193
202
}
194
203
}
195
204
@@ -209,8 +218,8 @@ fn fold_file_bytewise<T: Read>(mut file: BufReader<T>, spaces: bool, width: usiz
209
218
#[ allow( unused_assignments) ]
210
219
#[ allow( clippy:: cognitive_complexity) ]
211
220
fn fold_file < T : Read > ( mut file : BufReader < T > , spaces : bool , width : usize ) -> UResult < ( ) > {
212
- let mut line = String :: new ( ) ;
213
- let mut output = String :: new ( ) ;
221
+ let mut line = Vec :: new ( ) ;
222
+ let mut output = Vec :: new ( ) ;
214
223
let mut col_count = 0 ;
215
224
let mut last_space = None ;
216
225
@@ -226,8 +235,9 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
226
235
None => output. len( ) ,
227
236
} ;
228
237
229
- println!( "{}" , & output[ ..consume] ) ;
230
- output. replace_range( ..consume, "" ) ;
238
+ stdout( ) . write_all( & output[ ..consume] ) ?;
239
+ stdout( ) . write_all( & [ NL ] ) ?;
240
+ output. drain( ..consume) ;
231
241
232
242
// we know there are no tabs left in output, so each char counts
233
243
// as 1 column
@@ -239,15 +249,15 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
239
249
240
250
loop {
241
251
if file
242
- . read_line ( & mut line)
252
+ . read_until ( NL , & mut line)
243
253
. map_err_context ( || get_message ( "fold-error-readline" ) ) ?
244
254
== 0
245
255
{
246
256
break ;
247
257
}
248
258
249
- for ch in line. chars ( ) {
250
- if ch == '\n' {
259
+ for ch in & line {
260
+ if * ch == NL {
251
261
// make sure to _not_ split output at whitespace, since we
252
262
// know the entire output will fit
253
263
last_space = None ;
@@ -259,9 +269,9 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
259
269
emit_output ! ( ) ;
260
270
}
261
271
262
- match ch {
263
- '\r' => col_count = 0 ,
264
- '\t' => {
272
+ match * ch {
273
+ CR => col_count = 0 ,
274
+ TAB => {
265
275
let next_tab_stop = col_count + TAB_WIDTH - col_count % TAB_WIDTH ;
266
276
267
277
if next_tab_stop > width && !output. is_empty ( ) {
@@ -271,21 +281,21 @@ fn fold_file<T: Read>(mut file: BufReader<T>, spaces: bool, width: usize) -> URe
271
281
col_count = next_tab_stop;
272
282
last_space = if spaces { Some ( output. len ( ) ) } else { None } ;
273
283
}
274
- '\x08' => {
284
+ 0x08 => {
275
285
col_count = col_count. saturating_sub ( 1 ) ;
276
286
}
277
- _ if spaces && ch. is_whitespace ( ) => {
287
+ _ if spaces && ch. is_ascii_whitespace ( ) => {
278
288
last_space = Some ( output. len ( ) ) ;
279
289
col_count += 1 ;
280
290
}
281
291
_ => col_count += 1 ,
282
292
}
283
293
284
- output. push ( ch) ;
294
+ output. push ( * ch) ;
285
295
}
286
296
287
297
if !output. is_empty ( ) {
288
- print ! ( "{ output}" ) ;
298
+ stdout ( ) . write_all ( & output) ? ;
289
299
output. truncate ( 0 ) ;
290
300
}
291
301
0 commit comments