Skip to content

Commit 524c1b1

Browse files
committed
numfmt: fix clippy errors, remove ---debug alias, rename write_line to format_and_write
1 parent 46f0bb1 commit 524c1b1

4 files changed

Lines changed: 114 additions & 6 deletions

File tree

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,9 @@ numfmt-error-invalid-format-width-overflow = invalid format '{ $format }' (width
7777
numfmt-error-invalid-precision = invalid precision in format '{ $format }'
7878
numfmt-error-format-too-many-percent = format '{ $format }' has too many % directives
7979
numfmt-error-unknown-invalid-mode = Unknown invalid mode: { $mode }
80+
81+
# Debug messages
82+
numfmt-debug-no-conversion = no conversion option specified
83+
numfmt-debug-grouping-no-effect = grouping has no effect in this locale
84+
numfmt-debug-failed-to-convert = failed to convert some of the input numbers
85+
numfmt-debug-header-ignored = --header ignored with command-line input

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ numfmt-after-help = Options d'UNITÉ :
3636
Une précision optionnelle (%.1f) remplacera la précision déterminée par l'entrée.
3737
3838
# Messages d'aide
39+
numfmt-help-debug = afficher des avertissements sur les entrées invalides
3940
numfmt-help-delimiter = utiliser X au lieu d'espaces pour le délimiteur de champ
4041
numfmt-help-field = remplacer les nombres dans ces champs d'entrée ; voir FIELDS ci-dessous
4142
numfmt-help-format = utiliser le FORMAT à virgule flottante de style printf ; voir FORMAT ci-dessous pour les détails
@@ -75,3 +76,9 @@ numfmt-error-invalid-format-width-overflow = format invalide '{ $format }' (déb
7576
numfmt-error-invalid-precision = précision invalide dans le format '{ $format }'
7677
numfmt-error-format-too-many-percent = le format '{ $format }' a trop de directives %
7778
numfmt-error-unknown-invalid-mode = Mode invalide inconnu : { $mode }
79+
80+
# Messages de débogage
81+
numfmt-debug-no-conversion = aucune option de conversion spécifiée
82+
numfmt-debug-grouping-no-effect = le groupement n'a aucun effet dans cette locale
83+
numfmt-debug-failed-to-convert = échec de conversion d'une partie des nombres en entrée
84+
numfmt-debug-header-ignored = --header ignoré avec une entrée en ligne de commande

src/uu/numfmt/src/format.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
55

6-
// spell-checker:ignore powf
6+
// spell-checker:ignore powf seps
77

88
use uucore::display::Quotable;
99
use uucore::i18n::decimal::locale_grouping_separator;

src/uu/numfmt/src/numfmt.rs

Lines changed: 100 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//
33
// For the full copyright and license information, please view the LICENSE
44
// file that was distributed with this source code.
5+
// spell-checker:ignore behaviour
56

67
use crate::errors::NumfmtError;
78
use crate::format::{escape_line, write_formatted_with_delimiter, write_formatted_with_whitespace};
@@ -64,19 +65,20 @@ fn format_and_write<W: std::io::Write>(
6465
}
6566
};
6667

67-
if let Err(error_message) = handled_line {
68+
if let Err(msg) = result {
6869
match options.invalid {
6970
InvalidModes::Abort => {
70-
return Err(Box::new(NumfmtError::FormattingError(error_message)));
71+
return Err(Box::new(NumfmtError::FormattingError(msg)));
7172
}
7273
InvalidModes::Fail => {
73-
show!(NumfmtError::FormattingError(error_message));
74+
show!(NumfmtError::FormattingError(msg));
7475
}
7576
InvalidModes::Warn => {
76-
let _ = writeln!(stderr(), "numfmt: {error_message}");
77+
let _ = writeln!(stderr(), "numfmt: {msg}");
7778
}
7879
InvalidModes::Ignore => {}
7980
}
81+
// On error, echo the original line unchanged.
8082
writer.write_all(input_line)?;
8183
if let Some(eol) = eol {
8284
writer.write_all(&[eol])?;
@@ -90,6 +92,64 @@ fn format_and_write<W: std::io::Write>(
9092
Ok(false)
9193
}
9294

95+
/// Process command-line number arguments.
96+
///
97+
/// Returns `true` if any line contained invalid input.
98+
fn handle_args<'a>(args: impl Iterator<Item = &'a [u8]>, options: &NumfmtOptions) -> UResult<bool> {
99+
let mut stdout = std::io::stdout().lock();
100+
let terminator = if options.zero_terminated { 0u8 } else { b'\n' };
101+
let mut saw_invalid = false;
102+
for l in args {
103+
saw_invalid |= format_and_write(&mut stdout, l, options, Some(terminator))?;
104+
}
105+
Ok(saw_invalid)
106+
}
107+
108+
/// Process lines read from stdin.
109+
///
110+
/// Returns `true` if any line contained invalid input.
111+
fn handle_buffer<R: BufRead>(mut input: R, options: &NumfmtOptions) -> UResult<bool> {
112+
let terminator = if options.zero_terminated { 0u8 } else { b'\n' };
113+
let mut stdout = std::io::stdout().lock();
114+
let mut buf = Vec::new();
115+
let mut line_idx = 0;
116+
let mut saw_invalid = false;
117+
118+
loop {
119+
buf.clear();
120+
let n = input
121+
.read_until(terminator, &mut buf)
122+
.map_err(|e| NumfmtError::IoError(e.to_string()))?;
123+
if n == 0 {
124+
break;
125+
}
126+
127+
let has_terminator = buf.last() == Some(&terminator);
128+
let line = if has_terminator {
129+
&buf[..buf.len() - 1]
130+
} else {
131+
&buf[..]
132+
};
133+
// Emit the terminator only when the input line had one (preserve
134+
// missing final newline).
135+
let eol = has_terminator.then_some(terminator);
136+
137+
if line_idx < options.header {
138+
// Pass header lines through unchanged.
139+
stdout.write_all(line)?;
140+
if let Some(t) = eol {
141+
stdout.write_all(&[t])?;
142+
}
143+
} else {
144+
saw_invalid |= format_and_write(&mut stdout, line, options, eol)?;
145+
}
146+
147+
line_idx += 1;
148+
}
149+
150+
Ok(saw_invalid)
151+
}
152+
93153
fn parse_unit(s: &str) -> Result<Unit> {
94154
match s {
95155
"auto" => Ok(Unit::Auto),
@@ -285,6 +345,34 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
285345
})
286346
}
287347

348+
fn print_debug_warnings(options: &NumfmtOptions, matches: &ArgMatches) {
349+
fn print_warning(msg_key: &str) {
350+
let _ = writeln!(stderr(), "numfmt: {}", translate!(msg_key));
351+
}
352+
353+
// Warn if no conversion option is specified
354+
// 2>/dev/full does not abort
355+
if options.transform.from == Unit::None
356+
&& options.transform.to == Unit::None
357+
&& options.padding == 0
358+
&& !options.grouping
359+
{
360+
print_warning("numfmt-debug-no-conversion");
361+
}
362+
363+
if options.grouping && locale_grouping_separator().is_empty() {
364+
print_warning("numfmt-debug-grouping-no-effect");
365+
}
366+
367+
// Warn if --header is used with command-line input
368+
if options.header > 0 && matches.get_many::<OsString>(NUMBER).is_some() {
369+
print_warning("numfmt-debug-header-ignored");
370+
}
371+
}
372+
373+
#[uucore::main]
374+
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
375+
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
288376
let options = parse_options(&matches).map_err(NumfmtError::IllegalArgument)?;
289377

290378
if options.debug {
@@ -296,10 +384,17 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
296384
.map(|s| os_str_as_bytes(s).map_err(|e| e.to_string()))
297385
.collect::<std::result::Result<Vec<_>, _>>()
298386
.map_err(NumfmtError::IllegalArgument)?;
387+
handle_args(byte_args.into_iter(), &options)
388+
} else {
389+
let stdin = std::io::stdin();
390+
handle_buffer(stdin.lock(), &options)
391+
};
299392

300393
match result {
301394
Err(e) => {
302-
std::io::stdout().flush().expect("error flushing stdout");
395+
// Flush stdout before returning the error so any partial output is
396+
// visible (matches GNU behaviour).
397+
let _ = std::io::stdout().flush();
303398
Err(e)
304399
}
305400
Ok(saw_invalid) => {

0 commit comments

Comments
 (0)