Skip to content

Commit 4ffe09b

Browse files
authored
Merge branch 'main' into wc-perf
2 parents 913c5b3 + c229ff8 commit 4ffe09b

File tree

10 files changed

+122
-30
lines changed

10 files changed

+122
-30
lines changed

Cargo.lock

Lines changed: 7 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uu/csplit/src/csplit.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,19 +120,28 @@ where
120120
.enumerate();
121121
let mut input_iter = InputSplitter::new(enumerated_input_lines);
122122
let mut split_writer = SplitWriter::new(options);
123-
let patterns: Vec<patterns::Pattern> = patterns::get_patterns(patterns)?;
124-
let ret = do_csplit(&mut split_writer, patterns, &mut input_iter);
123+
let patterns_vec: Vec<patterns::Pattern> = patterns::get_patterns(patterns)?;
124+
let all_up_to_line = patterns_vec
125+
.iter()
126+
.all(|p| matches!(p, patterns::Pattern::UpToLine(_, _)));
127+
let ret = do_csplit(&mut split_writer, patterns_vec, &mut input_iter);
125128

126129
// consume the rest, unless there was an error
127130
if ret.is_ok() {
128131
input_iter.rewind_buffer();
129132
if let Some((_, line)) = input_iter.next() {
133+
// There is remaining input: create a final split and copy remainder
130134
split_writer.new_writer()?;
131135
split_writer.writeln(&line?)?;
132136
for (_, line) in input_iter {
133137
split_writer.writeln(&line?)?;
134138
}
135139
split_writer.finish_split();
140+
} else if all_up_to_line && options.suppress_matched {
141+
// GNU semantics for integer patterns with --suppress-matched:
142+
// even if no remaining input, create a final (possibly empty) split
143+
split_writer.new_writer()?;
144+
split_writer.finish_split();
136145
}
137146
}
138147
// delete files on error by default

src/uu/hashsum/src/hashsum.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,10 @@ fn create_algorithm_from_flags(matches: &ArgMatches) -> UResult<HashAlgorithm> {
9797
set_or_err(detect_algo("b3sum", None)?)?;
9898
}
9999
if matches.get_flag("sha3") {
100-
let bits = matches.get_one::<usize>("bits").copied();
101-
set_or_err(create_sha3(bits)?)?;
100+
match matches.get_one::<usize>("bits") {
101+
Some(bits) => set_or_err(create_sha3(*bits)?)?,
102+
None => return Err(ChecksumError::BitsRequiredForSha3.into()),
103+
}
102104
}
103105
if matches.get_flag("sha3-224") {
104106
set_or_err(HashAlgorithm {

src/uu/pinky/locales/en-US.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pinky-help-omit-headings = omit the line of column headings in short format
1919
pinky-help-omit-name = omit the user's full name in short format
2020
pinky-help-omit-name-host = omit the user's full name and remote host in short format
2121
pinky-help-omit-name-host-time = omit the user's full name, remote host and idle time in short format
22+
pinky-help-lookup = attempt to canonicalize hostnames via DNS
2223
pinky-help-help = Print help information
2324
2425
# Column headers for short format

src/uu/pinky/locales/fr-FR.ftl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pinky-help-omit-headings = omettre la ligne des en-têtes de colonnes en format
1919
pinky-help-omit-name = omettre le nom complet de l'utilisateur en format court
2020
pinky-help-omit-name-host = omettre le nom complet et l'hôte distant de l'utilisateur en format court
2121
pinky-help-omit-name-host-time = omettre le nom complet, l'hôte distant et le temps d'inactivité de l'utilisateur en format court
22+
pinky-help-lookup = tenter de donner un forme canonique aux noms d'hôte avec DNS
2223
pinky-help-help = Afficher les informations d'aide
2324
2425
# En-têtes de colonnes pour le format court

src/uu/pinky/src/pinky.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod platform;
1313

1414
mod options {
1515
pub const LONG_FORMAT: &str = "long_format";
16+
pub const LOOKUP: &str = "lookup";
1617
pub const OMIT_HOME_DIR: &str = "omit_home_dir";
1718
pub const OMIT_PROJECT_FILE: &str = "omit_project_file";
1819
pub const OMIT_PLAN_FILE: &str = "omit_plan_file";
@@ -101,6 +102,12 @@ pub fn uu_app() -> Command {
101102
.action(ArgAction::Append)
102103
.value_hint(clap::ValueHint::Username),
103104
)
105+
.arg(
106+
Arg::new(options::LOOKUP)
107+
.long(options::LOOKUP)
108+
.help(translate!("pinky-help-lookup"))
109+
.action(ArgAction::SetTrue),
110+
)
104111
.arg(
105112
// Redefine the help argument to not include the short flag
106113
// since that conflicts with omit_project_file.

src/uu/pinky/src/platform/unix.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
6464
// if true, use the "short" output format.
6565
let do_short_format = !matches.get_flag(options::LONG_FORMAT);
6666

67+
// If true, attempt to canonicalize hostname via a DNS lookup.
68+
let do_lookup = matches.get_flag(options::LOOKUP);
69+
6770
/* if true, display the ut_host field. */
6871
let mut include_where = true;
6972

@@ -81,6 +84,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
8184
}
8285

8386
let pk = Pinky {
87+
do_lookup,
8488
include_idle,
8589
include_heading,
8690
include_fullname,
@@ -103,6 +107,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
103107
}
104108

105109
struct Pinky {
110+
do_lookup: bool,
106111
include_idle: bool,
107112
include_heading: bool,
108113
include_fullname: bool,
@@ -136,11 +141,20 @@ fn idle_string(when: i64) -> String {
136141
}
137142

138143
fn time_string(ut: &UtmpxRecord) -> String {
139-
// "%b %e %H:%M"
140-
let time_format: Vec<time::format_description::FormatItem> =
144+
let lc_time: String = std::env::var("LC_ALL")
145+
.or_else(|_| std::env::var("LC_TIME"))
146+
.or_else(|_| std::env::var("LANG"))
147+
.unwrap_or_default();
148+
149+
let time_format: Vec<time::format_description::FormatItem> = if lc_time == "C" {
150+
// "%b %e %H:%M"
141151
time::format_description::parse("[month repr:short] [day padding:space] [hour]:[minute]")
142-
.unwrap();
143-
ut.login_time().format(&time_format).unwrap() // LC_ALL=C
152+
.unwrap()
153+
} else {
154+
// "%Y-%m-%d %H:%M"
155+
time::format_description::parse("[year]-[month]-[day] [hour]:[minute]").unwrap()
156+
};
157+
ut.login_time().format(&time_format).unwrap()
144158
}
145159

146160
fn gecos_to_fullname(pw: &Passwd) -> Option<String> {
@@ -206,10 +220,16 @@ impl Pinky {
206220

207221
print!(" {}", time_string(ut));
208222

209-
let mut s = ut.host();
210-
if self.include_where && !s.is_empty() {
211-
s = ut.canon_host()?;
212-
print!(" {s}");
223+
if self.include_where {
224+
let s: String = if self.do_lookup {
225+
ut.canon_host().unwrap_or(ut.host())
226+
} else {
227+
ut.host()
228+
};
229+
230+
if !s.is_empty() {
231+
print!(" {s}");
232+
}
213233
}
214234

215235
println!();

src/uucore/src/lib/features/checksum.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -249,34 +249,32 @@ impl UError for ChecksumError {
249249
///
250250
/// # Returns
251251
///
252-
/// Returns a UResult of a tuple containing the algorithm name, the hasher instance, and
253-
/// the output length in bits or an Err if an unsupported output size is provided, or if
254-
/// the `--bits` flag is missing.
255-
pub fn create_sha3(bits: Option<usize>) -> UResult<HashAlgorithm> {
252+
/// Returns a `UResult` with an `HashAlgorithm` or an `Err` if an unsupported
253+
/// output size is provided.
254+
pub fn create_sha3(bits: usize) -> UResult<HashAlgorithm> {
256255
match bits {
257-
Some(224) => Ok(HashAlgorithm {
256+
224 => Ok(HashAlgorithm {
258257
name: "SHA3_224",
259258
create_fn: Box::new(|| Box::new(Sha3_224::new())),
260259
bits: 224,
261260
}),
262-
Some(256) => Ok(HashAlgorithm {
261+
256 => Ok(HashAlgorithm {
263262
name: "SHA3_256",
264263
create_fn: Box::new(|| Box::new(Sha3_256::new())),
265264
bits: 256,
266265
}),
267-
Some(384) => Ok(HashAlgorithm {
266+
384 => Ok(HashAlgorithm {
268267
name: "SHA3_384",
269268
create_fn: Box::new(|| Box::new(Sha3_384::new())),
270269
bits: 384,
271270
}),
272-
Some(512) => Ok(HashAlgorithm {
271+
512 => Ok(HashAlgorithm {
273272
name: "SHA3_512",
274273
create_fn: Box::new(|| Box::new(Sha3_512::new())),
275274
bits: 512,
276275
}),
277276

278-
Some(_) => Err(ChecksumError::InvalidOutputSizeForSha3.into()),
279-
None => Err(ChecksumError::BitsRequiredForSha3.into()),
277+
_ => Err(ChecksumError::InvalidOutputSizeForSha3.into()),
280278
}
281279
}
282280

@@ -459,8 +457,10 @@ pub fn detect_algo(algo: &str, length: Option<usize>) -> UResult<HashAlgorithm>
459457
bits,
460458
})
461459
}
462-
//ALGORITHM_OPTIONS_SHA3 | "sha3" => (
463-
_ if algo.starts_with("sha3") => create_sha3(length),
460+
_ if algo.starts_with("sha3") => {
461+
let bits = length.ok_or(ChecksumError::BitsRequiredForSha3)?;
462+
create_sha3(bits)
463+
}
464464

465465
_ => Err(ChecksumError::UnknownAlgorithm.into()),
466466
}

tests/by-util/test_csplit.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,44 @@ fn generate(from: u32, to: u32) -> String {
1212
(from..to).fold(String::new(), |acc, v| format!("{acc}{v}\n"))
1313
}
1414

15+
#[test]
16+
fn test_line_numbers_suppress_matched_final_empty() {
17+
// Repro for #7286
18+
let (at, mut ucmd) = at_and_ucmd!();
19+
ucmd.args(&["--suppress-matched", "-", "2", "4", "6"]) // stdin, split at 2/4/6
20+
.pipe_in("1\n2\n3\n4\n5\n6\n")
21+
.succeeds()
22+
.stdout_only("2\n2\n2\n0\n");
23+
24+
// Expect four files: xx00:"1\n", xx01:"3\n", xx02:"5\n", xx03:""
25+
let count = glob(&at.plus_as_string("xx*"))
26+
.expect("there should be splits created")
27+
.count();
28+
assert_eq!(count, 4);
29+
assert_eq!(at.read("xx00"), "1\n");
30+
assert_eq!(at.read("xx01"), "3\n");
31+
assert_eq!(at.read("xx02"), "5\n");
32+
assert_eq!(at.read("xx03"), "");
33+
}
34+
35+
#[test]
36+
fn test_line_numbers_suppress_matched_final_empty_elided_with_z() {
37+
let (at, mut ucmd) = at_and_ucmd!();
38+
ucmd.args(&["--suppress-matched", "-z", "-", "2", "4", "6"]) // elide empty
39+
.pipe_in("1\n2\n3\n4\n5\n6\n")
40+
.succeeds()
41+
.stdout_only("2\n2\n2\n");
42+
43+
// Expect three files: xx00:"1\n", xx01:"3\n", xx02:"5\n"
44+
let count = glob(&at.plus_as_string("xx*"))
45+
.expect("there should be splits created")
46+
.count();
47+
assert_eq!(count, 3);
48+
assert_eq!(at.read("xx00"), "1\n");
49+
assert_eq!(at.read("xx01"), "3\n");
50+
assert_eq!(at.read("xx02"), "5\n");
51+
}
52+
1553
#[test]
1654
fn test_invalid_arg() {
1755
new_ucmd!().arg("--definitely-invalid").fails_with_code(1);

tests/by-util/test_pinky.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,19 @@ fn test_short_format_i() {
9090
assert_eq!(v_actual, v_expect);
9191
}
9292

93+
#[cfg(unix)]
94+
#[test]
95+
#[cfg(not(target_os = "openbsd"))]
96+
fn test_lookup() {
97+
let args = ["--lookup"];
98+
let ts = TestScenario::new(util_name!());
99+
let actual = ts.ucmd().args(&args).succeeds().stdout_move_str();
100+
let expect = unwrap_or_return!(expected_result(&ts, &[])).stdout_move_str();
101+
let v_actual: Vec<&str> = actual.split_whitespace().collect();
102+
let v_expect: Vec<&str> = expect.split_whitespace().collect();
103+
assert_eq!(v_actual, v_expect);
104+
}
105+
93106
#[cfg(unix)]
94107
#[test]
95108
#[cfg(not(target_os = "openbsd"))]

0 commit comments

Comments
 (0)