@@ -3,21 +3,38 @@
33use std::ffi::OsStr;
44use std::process::Command;
55
6−pub fn retrieve_less_version(less_path: &dyn AsRef<OsStr>) -> Option<usize> {
6+#[derive(Debug, PartialEq)]
7+pub enum LessVersion {
8+ Less(usize),
9+ BusyBox,
10+}
11+
12+pub fn retrieve_less_version(less_path: &dyn AsRef<OsStr>) -> Option<LessVersion> {
713 let resolved_path = grep_cli::resolve_binary(less_path.as_ref()).ok()?;
814
915 let cmd = Command::new(resolved_path).arg("--version").output().ok()?;
10− parse_less_version(&cmd.stdout)
16+ if cmd.status.success() {
17+ parse_less_version(&cmd.stdout)
18+ } else {
19+ parse_less_version_busybox(&cmd.stderr)
20+ }
1121}
1222
13−fn parse_less_version(output: &[u8]) -> Option<usize> {
23+fn parse_less_version(output: &[u8]) -> Option<LessVersion> {
1424 if !output.starts_with(b"less ") {
1525 return None;
1626 }
1727
1828 let version = std::str::from_utf8(&output[5..]).ok()?;
1929 let end = version.find(|c: char| !c.is_ascii_digit())?;
20− version[..end].parse::<usize>().ok()
30+ Some(LessVersion::Less(version[..end].parse::<usize>().ok()?))
31+}
32+
33+fn parse_less_version_busybox(output: &[u8]) -> Option<LessVersion> {
34+ match std::str::from_utf8(output) {
35+ Ok(version) if version.contains("BusyBox ") => Some(LessVersion::BusyBox),
36+ _ => None,
37+ }
2138}
2239
2340#[test]
@@ -30,7 +47,7 @@ For information about the terms of redistribution,
3047see the file named README in the less distribution.
3148Homepage: http://www.greenwoodsoftware.com/less";
3249
33− assert_eq!(Some(487), parse_less_version(output));
50+ assert_eq!(Some(LessVersion::Less(487)), parse_less_version(output));
3451}
3552
3653#[test]
@@ -43,7 +60,7 @@ For information about the terms of redistribution,
4360see the file named README in the less distribution.
4461Homepage: http://www.greenwoodsoftware.com/less";
4562
46− assert_eq!(Some(529), parse_less_version(output));
63+ assert_eq!(Some(LessVersion::Less(529)), parse_less_version(output));
4764}
4865
4966#[test]
@@ -56,7 +73,7 @@ For information about the terms of redistribution,
5673see the file named README in the less distribution.
5774Home page: http://www.greenwoodsoftware.com/less";
5875
59− assert_eq!(Some(551), parse_less_version(output));
76+ assert_eq!(Some(LessVersion::Less(551)), parse_less_version(output));
6077}
6178
6279#[test]
@@ -69,7 +86,7 @@ For information about the terms of redistribution,
6986see the file named README in the less distribution.
7087Home page: https://greenwoodsoftware.com/less";
7188
72− assert_eq!(Some(581), parse_less_version(output));
89+ assert_eq!(Some(LessVersion::Less(581)), parse_less_version(output));
7390}
7491
7592#[test]
@@ -77,4 +94,38 @@ fn test_parse_less_version_wrong_program() {
7794 let output = b"more from util-linux 2.34";
7895
7996 assert_eq!(None, parse_less_version(output));
97+ assert_eq!(None, parse_less_version_busybox(output));
98+}
99+
100+#[test]
101+fn test_parse_less_version_busybox() {
102+ let output = b"pkg/less: unrecognized option '--version'
103+BusyBox v1.35.0 (2022-04-21 10:38:11 EDT) multi-call binary.
104+
105+Usage: less [-EFIMmNSRh~] [FILE]...
106+
107+View FILE (or stdin) one screenful at a time
108+
109+ -E Quit once the end of a file is reached
110+ -F Quit if entire file fits on first screen
111+ -I Ignore case in all searches
112+ -M,-m Display status line with line numbers
113+ and percentage through the file
114+ -N Prefix line number to each line
115+ -S Truncate long lines
116+ -R Remove color escape codes in input
117+ -~ Suppress ~s displayed past EOF";
118+
119+ assert_eq!(
120+ Some(LessVersion::BusyBox),
121+ parse_less_version_busybox(output)
122+ );
123+}
124+
125+#[test]
126+fn test_parse_less_version_invalid_utf_8() {
127+ let output = b"\xff";
128+
129+ assert_eq!(None, parse_less_version(output));
130+ assert_eq!(None, parse_less_version_busybox(output));
80131}