1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

nl: fix calculation of line number lengths

This commit is contained in:
Daniel Hofstetter 2023-07-17 16:30:30 +02:00
parent 1d171b5166
commit 27ee279913
2 changed files with 54 additions and 17 deletions

View file

@ -263,13 +263,8 @@ pub fn uu_app() -> Command {
fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> { fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
let regexp: regex::Regex = regex::Regex::new(r".?").unwrap(); let regexp: regex::Regex = regex::Regex::new(r".?").unwrap();
let mut line_no = settings.starting_line_number; let mut line_no = settings.starting_line_number;
// The current line number's width as a string. Using to_string is inefficient let mut line_no_width = line_no.len();
// but since we only do it once, it should not hurt.
let mut line_no_width = line_no.to_string().len();
let line_no_width_initial = line_no_width; let line_no_width_initial = line_no_width;
// Stores the smallest integer with one more digit than line_no, so that
// when line_no >= line_no_threshold, we need to use one more digit.
let mut line_no_threshold = 10i64.pow(line_no_width as u32);
let mut empty_line_count: u64 = 0; let mut empty_line_count: u64 = 0;
let fill_char = match settings.number_format { let fill_char = match settings.number_format {
NumberFormat::RightZero => '0', NumberFormat::RightZero => '0',
@ -331,7 +326,6 @@ fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
if settings.renumber { if settings.renumber {
line_no = settings.starting_line_number; line_no = settings.starting_line_number;
line_no_width = line_no_width_initial; line_no_width = line_no_width_initial;
line_no_threshold = 10i64.pow(line_no_width as u32);
} }
&settings.header_numbering &settings.header_numbering
} }
@ -400,11 +394,7 @@ fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UResult<()> {
// Now update the variables for the (potential) next // Now update the variables for the (potential) next
// line. // line.
line_no += settings.line_increment; line_no += settings.line_increment;
while line_no >= line_no_threshold { line_no_width = line_no.len();
// The line number just got longer.
line_no_threshold *= 10;
line_no_width += 1;
}
} }
Ok(()) Ok(())
} }
@ -424,3 +414,39 @@ fn pass_none(_: &str, _: &regex::Regex) -> bool {
fn pass_all(_: &str, _: &regex::Regex) -> bool { fn pass_all(_: &str, _: &regex::Regex) -> bool {
true true
} }
trait Length {
fn len(&self) -> usize;
}
impl Length for i64 {
// Returns the length in `char`s.
fn len(&self) -> usize {
if *self == 0 {
return 1;
};
let sign_len = if *self < 0 { 1 } else { 0 };
(0..).take_while(|i| 10i64.pow(*i) <= self.abs()).count() + sign_len
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_len() {
assert_eq!((-1).len(), 2);
assert_eq!((-10).len(), 3);
assert_eq!((-100).len(), 4);
assert_eq!((-1000).len(), 5);
assert_eq!(0.len(), 1);
assert_eq!(1.len(), 1);
assert_eq!(10.len(), 2);
assert_eq!(100.len(), 3);
assert_eq!(1000.len(), 4);
}
}

View file

@ -213,14 +213,25 @@ fn test_line_increment() {
} }
#[test] #[test]
fn test_negative_line_increment() { fn test_line_increment_from_negative_starting_line() {
// TODO make this test work with -10 for arg in ["-i10", "--line-increment=10"] {
for arg in ["-i-1", "--line-increment=-1"] {
new_ucmd!() new_ucmd!()
.arg(arg) .arg(arg)
.pipe_in("a\nb") .arg("-v-19")
.pipe_in("a\nb\nc")
.succeeds() .succeeds()
.stdout_is(" 1\ta\n 0\tb\n"); .stdout_is(" -19\ta\n -9\tb\n 1\tc\n");
}
}
#[test]
fn test_negative_line_increment() {
for arg in ["-i-10", "--line-increment=-10"] {
new_ucmd!()
.arg(arg)
.pipe_in("a\nb\nc")
.succeeds()
.stdout_is(" 1\ta\n -9\tb\n -19\tc\n");
} }
} }