-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
head: head_backwards for non-seekable files like /proc/* or fifos (named pipes) #5732
Changes from 14 commits
185c8bb
37bf664
ef32af1
06c3329
1190ab8
effc313
937283b
71a3df1
98fa947
58c90d1
3fa05c5
1d08a70
d16d8b0
9f51541
4c58756
6e310b7
f279461
c7ef228
e0af0f3
2cc6e35
5d255be
e90e8bc
d9c1f4c
68e7cb2
d0ebc5a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -243,12 +243,23 @@ | |
Ok(()) | ||
} | ||
|
||
fn read_but_last_n_bytes(input: &mut impl std::io::BufRead, n: usize) -> std::io::Result<()> { | ||
fn read_but_last_n_bytes(input: &mut impl std::io::BufRead, n: u64) -> std::io::Result<()> { | ||
if n == 0 { | ||
//prints everything | ||
return read_n_bytes(input, std::u64::MAX); | ||
} | ||
|
||
let n = match usize::try_from(n) { | ||
Ok(value) => value, | ||
Err(e) => { | ||
show!(USimpleError::new( | ||
1, | ||
format!("{e}: number of bytes is too large") | ||
)); | ||
return Ok(()); | ||
} | ||
}; | ||
|
||
let stdout = std::io::stdout(); | ||
let mut stdout = stdout.lock(); | ||
|
||
|
@@ -293,9 +304,20 @@ | |
|
||
fn read_but_last_n_lines( | ||
input: impl std::io::BufRead, | ||
n: usize, | ||
n: u64, | ||
separator: u8, | ||
) -> std::io::Result<()> { | ||
let n = match usize::try_from(n) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as it seems to be the same, maybe create a function for this ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ping ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, i'll do some more experiments :-) |
||
Ok(value) => value, | ||
Err(e) => { | ||
show!(USimpleError::new( | ||
1, | ||
format!("{e}: number of bytes is too large") | ||
)); | ||
return Ok(()); | ||
} | ||
}; | ||
|
||
let stdout = std::io::stdout(); | ||
let mut stdout = stdout.lock(); | ||
for bytes in take_all_but(lines(input, separator), n) { | ||
|
@@ -380,7 +402,41 @@ | |
} | ||
} | ||
|
||
fn is_seekable(input: &mut std::fs::File) -> bool { | ||
let current_pos = input.stream_position(); | ||
current_pos.is_ok() | ||
&& input.seek(SeekFrom::End(0)).is_ok() | ||
&& input.seek(SeekFrom::Start(current_pos.unwrap())).is_ok() | ||
} | ||
|
||
fn head_backwards_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<()> { | ||
let seekable = is_seekable(input); | ||
if seekable { | ||
return head_backwards_on_seekable_file(input, options); | ||
} | ||
|
||
head_backwards_on_non_seekable_file(input, options) | ||
} | ||
|
||
fn head_backwards_on_non_seekable_file( | ||
input: &mut std::fs::File, | ||
options: &HeadOptions, | ||
) -> std::io::Result<()> { | ||
let reader = &mut std::io::BufReader::with_capacity(BUF_SIZE, &*input); | ||
|
||
match options.mode { | ||
Mode::AllButLastBytes(n) => read_but_last_n_bytes(reader, n)?, | ||
Mode::AllButLastLines(n) => read_but_last_n_lines(reader, n, options.line_ending.into())?, | ||
_ => unreachable!(), | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn head_backwards_on_seekable_file( | ||
input: &mut std::fs::File, | ||
options: &HeadOptions, | ||
) -> std::io::Result<()> { | ||
match options.mode { | ||
Mode::AllButLastBytes(n) => { | ||
let size = input.metadata()?.len(); | ||
|
@@ -434,32 +490,13 @@ | |
let stdin = std::io::stdin(); | ||
let mut stdin = stdin.lock(); | ||
|
||
// Outputting "all-but-last" requires us to use a ring buffer with size n, so n | ||
// must be converted from u64 to usize to fit in memory. If such conversion fails, | ||
// it means the platform doesn't have enough memory to hold the buffer, so we fail. | ||
if let Mode::AllButLastLines(n) | Mode::AllButLastBytes(n) = options.mode { | ||
if let Err(e) = usize::try_from(n) { | ||
show!(USimpleError::new( | ||
1, | ||
format!("{e}: number of bytes is too large") | ||
)); | ||
continue; | ||
}; | ||
}; | ||
|
||
match options.mode { | ||
Mode::FirstBytes(n) => read_n_bytes(&mut stdin, n), | ||
// unwrap is guaranteed to succeed because we checked the value of n above | ||
Mode::AllButLastBytes(n) => { | ||
read_but_last_n_bytes(&mut stdin, n.try_into().unwrap()) | ||
} | ||
Mode::AllButLastBytes(n) => read_but_last_n_bytes(&mut stdin, n), | ||
Mode::FirstLines(n) => read_n_lines(&mut stdin, n, options.line_ending.into()), | ||
// unwrap is guaranteed to succeed because we checked the value of n above | ||
Mode::AllButLastLines(n) => read_but_last_n_lines( | ||
&mut stdin, | ||
n.try_into().unwrap(), | ||
options.line_ending.into(), | ||
), | ||
Mode::AllButLastLines(n) => { | ||
read_but_last_n_lines(&mut stdin, n, options.line_ending.into()) | ||
} | ||
} | ||
} | ||
(name, false) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be simplify with something like
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I experimented with it. The problem: The proposed alternative is actually not 100% the same. It makes the function return with an Err(..) (which needs to be converted first). But originally it just prints the error and then returns with Ok().
I personally think this is a bit smelly anyway. But i moved this code just from a different location (cleanup commit will come soon).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
additionally: I actually can't test this part of code. On 64bit machine usize and u64 is the same. Thus this convertion will only fail on 32 bit (or lower if this exists here)