Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/uu/uniq/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,39 @@ uniq-after-help = Filter adjacent matching lines from INPUT (or standard input),

Note: uniq does not detect repeated lines unless they are adjacent.
You may want to sort the input first, or use sort -u without uniq.

# Help messages
uniq-help-all-repeated = print all duplicate lines. Delimiting is done with blank lines. [default: none]
uniq-help-group = show all items, separating groups with an empty line. [default: separate]
uniq-help-check-chars = compare no more than N characters in lines
uniq-help-count = prefix lines by the number of occurrences
uniq-help-ignore-case = ignore differences in case when comparing
uniq-help-repeated = only print duplicate lines
uniq-help-skip-chars = avoid comparing the first N characters
uniq-help-skip-fields = avoid comparing the first N fields
uniq-help-unique = only print unique lines
uniq-help-zero-terminated = end lines with 0 byte, not newline

# Error messages
uniq-error-write-line-terminator = Could not write line terminator
uniq-error-write-error = write error
uniq-error-invalid-argument = Invalid argument for { $opt_name }: { $arg }
uniq-error-try-help = Try 'uniq --help' for more information.
uniq-error-group-mutually-exclusive = --group is mutually exclusive with -c/-d/-D/-u
uniq-error-group-badoption = invalid argument 'badoption' for '--group'
Valid arguments are:
- 'prepend'
- 'append'
- 'separate'
- 'both'

uniq-error-all-repeated-badoption = invalid argument 'badoption' for '--all-repeated'
Valid arguments are:
- 'none'
- 'prepend'
- 'separate'

uniq-error-counts-and-repeated-meaningless = printing all duplicated lines and repeat counts is meaningless
Try 'uniq --help' for more information.

uniq-error-could-not-open = Could not open { $path }
41 changes: 41 additions & 0 deletions src/uu/uniq/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
uniq-about = Signaler ou omettre les lignes répétées.
uniq-usage = uniq [OPTION]... [ENTRÉE [SORTIE]]
uniq-after-help = Filtrer les lignes adjacentes correspondantes de ENTRÉE (ou l'entrée standard),
en écrivant vers SORTIE (ou la sortie standard).
Note : uniq ne détecte les lignes répétées que si elles sont adjacentes.
Vous pourriez vouloir trier l'entrée d'abord, ou utiliser sort -u sans uniq.

# Messages d'aide
uniq-help-all-repeated = afficher toutes les lignes dupliquées. La délimitation se fait avec des lignes vides. [défaut : none]
uniq-help-group = afficher tous les éléments, en séparant les groupes avec une ligne vide. [défaut : separate]
uniq-help-check-chars = comparer au maximum N caractères dans les lignes
uniq-help-count = préfixer les lignes par le nombre d'occurrences
uniq-help-ignore-case = ignorer les différences de casse lors de la comparaison
uniq-help-repeated = afficher seulement les lignes dupliquées
uniq-help-skip-chars = éviter de comparer les N premiers caractères
uniq-help-skip-fields = éviter de comparer les N premiers champs
uniq-help-unique = afficher seulement les lignes uniques
uniq-help-zero-terminated = terminer les lignes avec un octet 0, pas une nouvelle ligne

# Messages d'erreur
uniq-error-write-line-terminator = Impossible d'écrire le terminateur de ligne
uniq-error-write-error = erreur d'écriture
uniq-error-invalid-argument = Argument invalide pour { $opt_name } : { $arg }
uniq-error-try-help = Essayez 'uniq --help' pour plus d'informations.
uniq-error-group-mutually-exclusive = --group est mutuellement exclusif avec -c/-d/-D/-u
uniq-error-group-badoption = argument invalide 'badoption' pour '--group'
Arguments valides :
- 'prepend'
- 'append'
- 'separate'
- 'both'

uniq-error-all-repeated-badoption = argument invalide 'badoption' pour '--all-repeated'
Arguments valides :
- 'none'
- 'prepend'
- 'separate'

uniq-error-counts-and-repeated-meaningless = afficher toutes les lignes dupliquées et les nombres de répétitions n'a pas de sens
Essayez 'uniq --help' pour plus d'informations.
uniq-error-could-not-open = Impossible d'ouvrir { $path }
84 changes: 47 additions & 37 deletions src/uu/uniq/src/uniq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use clap::{
Arg, ArgAction, ArgMatches, Command, builder::ValueParser, error::ContextKind, error::Error,
error::ErrorKind,
};
use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Write, stdin, stdout};
Expand All @@ -17,7 +18,7 @@ use uucore::format_usage;
use uucore::parser::shortcut_value_parser::ShortcutValueParser;
use uucore::posix::{OBSOLETE, posix_version};

use uucore::locale::get_message;
use uucore::locale::{get_message, get_message_with_args};

pub mod options {
pub static ALL_REPEATED: &str = "all-repeated";
Expand Down Expand Up @@ -60,7 +61,7 @@ macro_rules! write_line_terminator {
($writer:expr, $line_terminator:expr) => {
$writer
.write_all(&[$line_terminator])
.map_err_context(|| "Could not write line terminator".to_string())
.map_err_context(|| get_message("uniq-error-write-line-terminator"))
};
}

Expand Down Expand Up @@ -108,7 +109,9 @@ impl Uniq {
{
write_line_terminator!(writer, line_terminator)?;
}
writer.flush().map_err_context(|| "write error".into())?;
writer
.flush()
.map_err_context(|| get_message("uniq-error-write-error"))?;
Ok(())
}

Expand Down Expand Up @@ -155,7 +158,7 @@ impl Uniq {

// Skip self.slice_start bytes (if -s was used).
// self.slice_start is how many characters to skip, but historically
// uniqs `-s N` means skip N *bytes*, so do that literally:
// uniq's `-s N` means "skip N *bytes*," so do that literally:
let skip_bytes = self.slice_start.unwrap_or(0);
let fields_to_check = if skip_bytes < fields_to_check.len() {
&fields_to_check[skip_bytes..]
Expand All @@ -167,7 +170,7 @@ impl Uniq {
// Convert the leftover bytes to UTF-8 for character-based -w
// If invalid UTF-8, just compare them as individual bytes (fallback).
let Ok(string_after_skip) = std::str::from_utf8(fields_to_check) else {
// Fallback: if invalid UTF-8, treat them as single-byte chars
// Fallback: if invalid UTF-8, treat them as single-byte "chars"
return closure(&mut fields_to_check.iter().map(|&b| b as char));
};

Expand Down Expand Up @@ -225,7 +228,7 @@ impl Uniq {
} else {
writer.write_all(line)
}
.map_err_context(|| "write error".to_string())?;
.map_err_context(|| get_message("uniq-error-write-error"))?;

write_line_terminator!(writer, line_terminator)
}
Expand All @@ -239,7 +242,13 @@ fn opt_parsed(opt_name: &str, matches: &ArgMatches) -> UResult<Option<usize>> {
IntErrorKind::PosOverflow => Ok(Some(usize::MAX)),
_ => Err(USimpleError::new(
1,
format!("Invalid argument for {opt_name}: {}", arg_str.maybe_quote()),
get_message_with_args(
"uniq-error-invalid-argument",
HashMap::from([
("opt_name".to_string(), opt_name.to_string()),
("arg".to_string(), arg_str.maybe_quote().to_string()),
]),
),
)),
},
},
Expand Down Expand Up @@ -509,11 +518,11 @@ fn handle_extract_obs_skip_chars(
/// for `uniq` hardcode and require the exact wording of the error message
/// and it is not compatible with how Clap formats and displays those error messages.
fn map_clap_errors(clap_error: Error) -> Box<dyn UError> {
let footer = "Try 'uniq --help' for more information.";
let override_arg_conflict =
"--group is mutually exclusive with -c/-d/-D/-u\n".to_string() + footer;
let override_group_badoption = "invalid argument 'badoption' for '--group'\nValid arguments are:\n - 'prepend'\n - 'append'\n - 'separate'\n - 'both'\n".to_string() + footer;
let override_all_repeated_badoption = "invalid argument 'badoption' for '--all-repeated'\nValid arguments are:\n - 'none'\n - 'prepend'\n - 'separate'\n".to_string() + footer;
let footer = get_message("uniq-error-try-help");
let override_arg_conflict = get_message("uniq-error-group-mutually-exclusive") + "\n" + &footer;
let override_group_badoption = get_message("uniq-error-group-badoption") + "\n" + &footer;
let override_all_repeated_badoption =
get_message("uniq-error-all-repeated-badoption") + "\n" + &footer;

let error_message = match clap_error.kind() {
ErrorKind::ArgumentConflict => override_arg_conflict,
Expand Down Expand Up @@ -578,7 +587,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
if uniq.show_counts && uniq.all_repeated {
return Err(USimpleError::new(
1,
"printing all duplicated lines and repeat counts is meaningless\nTry 'uniq --help' for more information.",
get_message("uniq-error-counts-and-repeated-meaningless"),
));
}

Expand All @@ -599,12 +608,8 @@ pub fn uu_app() -> Command {
Arg::new(options::ALL_REPEATED)
.short('D')
.long(options::ALL_REPEATED)
.value_parser(ShortcutValueParser::new([
"none",
"prepend",
"separate"
]))
.help("print all duplicate lines. Delimiting is done with blank lines. [default: none]")
.value_parser(ShortcutValueParser::new(["none", "prepend", "separate"]))
.help(get_message("uniq-help-all-repeated"))
.value_name("delimit-method")
.num_args(0..=1)
.default_missing_value("none")
Expand All @@ -614,12 +619,9 @@ pub fn uu_app() -> Command {
Arg::new(options::GROUP)
.long(options::GROUP)
.value_parser(ShortcutValueParser::new([
"separate",
"prepend",
"append",
"both",
"separate", "prepend", "append", "both",
]))
.help("show all items, separating groups with an empty line. [default: separate]")
.help(get_message("uniq-help-group"))
.value_name("group-method")
.num_args(0..=1)
.default_missing_value("separate")
Expand All @@ -628,63 +630,63 @@ pub fn uu_app() -> Command {
options::REPEATED,
options::ALL_REPEATED,
options::UNIQUE,
options::COUNT
options::COUNT,
]),
)
.arg(
Arg::new(options::CHECK_CHARS)
.short('w')
.long(options::CHECK_CHARS)
.help("compare no more than N characters in lines")
.help(get_message("uniq-help-check-chars"))
.value_name("N"),
)
.arg(
Arg::new(options::COUNT)
.short('c')
.long(options::COUNT)
.help("prefix lines by the number of occurrences")
.help(get_message("uniq-help-count"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::IGNORE_CASE)
.short('i')
.long(options::IGNORE_CASE)
.help("ignore differences in case when comparing")
.help(get_message("uniq-help-ignore-case"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::REPEATED)
.short('d')
.long(options::REPEATED)
.help("only print duplicate lines")
.help(get_message("uniq-help-repeated"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::SKIP_CHARS)
.short('s')
.long(options::SKIP_CHARS)
.help("avoid comparing the first N characters")
.help(get_message("uniq-help-skip-chars"))
.value_name("N"),
)
.arg(
Arg::new(options::SKIP_FIELDS)
.short('f')
.long(options::SKIP_FIELDS)
.help("avoid comparing the first N fields")
.help(get_message("uniq-help-skip-fields"))
.value_name("N"),
)
.arg(
Arg::new(options::UNIQUE)
.short('u')
.long(options::UNIQUE)
.help("only print unique lines")
.help(get_message("uniq-help-unique"))
.action(ArgAction::SetTrue),
)
.arg(
Arg::new(options::ZERO_TERMINATED)
.short('z')
.long(options::ZERO_TERMINATED)
.help("end lines with 0 byte, not newline")
.help(get_message("uniq-help-zero-terminated"))
.action(ArgAction::SetTrue),
)
.arg(
Expand Down Expand Up @@ -721,8 +723,12 @@ fn get_delimiter(matches: &ArgMatches) -> Delimiters {
fn open_input_file(in_file_name: Option<&OsStr>) -> UResult<Box<dyn BufRead>> {
Ok(match in_file_name {
Some(path) if path != "-" => {
let in_file = File::open(path)
.map_err_context(|| format!("Could not open {}", path.maybe_quote()))?;
let in_file = File::open(path).map_err_context(|| {
get_message_with_args(
"uniq-error-could-not-open",
HashMap::from([("path".to_string(), path.maybe_quote().to_string())]),
)
})?;
Box::new(BufReader::new(in_file))
}
_ => Box::new(stdin().lock()),
Expand All @@ -733,8 +739,12 @@ fn open_input_file(in_file_name: Option<&OsStr>) -> UResult<Box<dyn BufRead>> {
fn open_output_file(out_file_name: Option<&OsStr>) -> UResult<Box<dyn Write>> {
Ok(match out_file_name {
Some(path) if path != "-" => {
let out_file = File::create(path)
.map_err_context(|| format!("Could not open {}", path.maybe_quote()))?;
let out_file = File::create(path).map_err_context(|| {
get_message_with_args(
"uniq-error-could-not-open",
HashMap::from([("path".to_string(), path.maybe_quote().to_string())]),
)
})?;
Box::new(BufWriter::new(out_file))
}
_ => Box::new(stdout().lock()),
Expand Down
Loading