mirror of
https://github.com/uutils/coreutils.git
synced 2026-06-10 15:48:22 -07:00
Merge branch 'uutils:main' into uucore-memory
This commit is contained in:
@@ -379,6 +379,11 @@ jobs:
|
||||
set -x
|
||||
# Regression-test for https://github.com/uutils/coreutils/issues/8701
|
||||
make UTILS="rm chmod chown chgrp mv du"
|
||||
# Verifies that
|
||||
# 1. there is no "error: none of the selected packages contains this
|
||||
# feature: feat_external_libstdbuf"
|
||||
# 2. the makefile doesn't try to install libstdbuf even though stdbuf is skipped
|
||||
DESTDIR=/tmp/ make SKIP_UTILS="stdbuf" install
|
||||
|
||||
build_rust_stable:
|
||||
name: Build/stable
|
||||
|
||||
+10
-10
@@ -107,6 +107,7 @@ PROGS := \
|
||||
dir \
|
||||
dircolors \
|
||||
dirname \
|
||||
du \
|
||||
echo \
|
||||
env \
|
||||
expand \
|
||||
@@ -117,6 +118,7 @@ PROGS := \
|
||||
fold \
|
||||
hashsum \
|
||||
head \
|
||||
hostname \
|
||||
join \
|
||||
link \
|
||||
ln \
|
||||
@@ -145,17 +147,18 @@ PROGS := \
|
||||
sleep \
|
||||
sort \
|
||||
split \
|
||||
stty \
|
||||
sum \
|
||||
sync \
|
||||
tac \
|
||||
tail \
|
||||
tee \
|
||||
test \
|
||||
touch \
|
||||
tr \
|
||||
true \
|
||||
truncate \
|
||||
tsort \
|
||||
uname \
|
||||
unexpand \
|
||||
uniq \
|
||||
vdir \
|
||||
@@ -169,10 +172,8 @@ UNIX_PROGS := \
|
||||
chmod \
|
||||
chown \
|
||||
chroot \
|
||||
du \
|
||||
groups \
|
||||
hostid \
|
||||
hostname \
|
||||
id \
|
||||
install \
|
||||
kill \
|
||||
@@ -185,10 +186,9 @@ UNIX_PROGS := \
|
||||
pinky \
|
||||
stat \
|
||||
stdbuf \
|
||||
stty \
|
||||
timeout \
|
||||
touch \
|
||||
tty \
|
||||
uname \
|
||||
unlink \
|
||||
uptime \
|
||||
users \
|
||||
@@ -228,7 +228,7 @@ ifneq ($(OS),Windows_NT)
|
||||
PROGS := $(PROGS) $(SELINUX_PROGS)
|
||||
endif
|
||||
|
||||
UTILS ?= $(PROGS)
|
||||
UTILS ?= $(filter-out $(SKIP_UTILS),$(PROGS))
|
||||
|
||||
ifneq ($(findstring stdbuf,$(UTILS)),)
|
||||
# Use external libstdbuf per default. It is more robust than embedding libstdbuf.
|
||||
@@ -306,7 +306,7 @@ TEST_PROGS := \
|
||||
who
|
||||
|
||||
TESTS := \
|
||||
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(TEST_PROGS))))
|
||||
$(sort $(filter $(UTILS),$(TEST_PROGS)))
|
||||
|
||||
TEST_NO_FAIL_FAST :=
|
||||
TEST_SPEC_FEATURE :=
|
||||
@@ -326,7 +326,7 @@ endef
|
||||
|
||||
# Output names
|
||||
EXES := \
|
||||
$(sort $(filter $(UTILS),$(filter-out $(SKIP_UTILS),$(PROGS))))
|
||||
$(sort $(UTILS))
|
||||
|
||||
INSTALLEES := ${EXES}
|
||||
ifeq (${MULTICALL}, y)
|
||||
@@ -352,7 +352,7 @@ build-coreutils:
|
||||
|
||||
build: build-coreutils build-pkgs locales
|
||||
|
||||
$(foreach test,$(filter-out $(SKIP_UTILS),$(PROGS)),$(eval $(call TEST_BUSYBOX,$(test))))
|
||||
$(foreach test,$(UTILS),$(eval $(call TEST_BUSYBOX,$(test))))
|
||||
|
||||
test:
|
||||
${CARGO} test ${CARGOFLAGS} --features "$(TESTS) $(TEST_SPEC_FEATURE)" --no-default-features $(TEST_NO_FAIL_FAST)
|
||||
@@ -482,7 +482,7 @@ endif
|
||||
|
||||
install: build install-manpages install-completions install-locales
|
||||
mkdir -p $(INSTALLDIR_BIN)
|
||||
ifneq ($(OS),Windows_NT)
|
||||
ifneq (,$(and $(findstring stdbuf,$(UTILS)),$(findstring feat_external_libstdbuf,$(CARGOFLAGS))))
|
||||
mkdir -p $(DESTDIR)$(LIBSTDBUF_DIR)
|
||||
$(INSTALL) -m 755 $(BUILDDIR)/deps/libstdbuf* $(DESTDIR)$(LIBSTDBUF_DIR)/
|
||||
endif
|
||||
|
||||
@@ -18,6 +18,11 @@ license = "MIT"
|
||||
[package.metadata]
|
||||
cargo-fuzz = true
|
||||
|
||||
# Enable debug symbols in release builds for readable backtraces
|
||||
# when fuzzing discovers crashes. This addresses issue #5343.
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
||||
[dependencies]
|
||||
libfuzzer-sys = "0.4.7"
|
||||
rand = { version = "0.9.0", features = ["small_rng"] }
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::{env, fmt};
|
||||
|
||||
use uucore::{
|
||||
display::Quotable,
|
||||
parser::parse_size::{ParseSizeError, parse_size_u64},
|
||||
parser::parse_size::{ParseSizeError, parse_size_non_zero_u64, parse_size_u64},
|
||||
};
|
||||
|
||||
/// The first ten powers of 1024.
|
||||
@@ -213,7 +213,7 @@ pub(crate) fn read_block_size(matches: &ArgMatches) -> Result<BlockSize, ParseSi
|
||||
fn block_size_from_env() -> Option<u64> {
|
||||
for env_var in ["DF_BLOCK_SIZE", "BLOCK_SIZE", "BLOCKSIZE"] {
|
||||
if let Ok(env_size) = env::var(env_var) {
|
||||
return parse_size_u64(&env_size).ok();
|
||||
return parse_size_non_zero_u64(&env_size).ok();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -68,7 +68,7 @@ use uucore::{
|
||||
line_ending::LineEnding,
|
||||
os_str_as_bytes_lossy,
|
||||
parser::parse_glob,
|
||||
parser::parse_size::parse_size_u64,
|
||||
parser::parse_size::parse_size_non_zero_u64,
|
||||
parser::shortcut_value_parser::ShortcutValueParser,
|
||||
quoting_style::{QuotingStyle, locale_aware_escape_dir_name, locale_aware_escape_name},
|
||||
show, show_error, show_warning,
|
||||
@@ -902,7 +902,7 @@ impl Config {
|
||||
|
||||
let (file_size_block_size, block_size) = if !opt_si && !opt_hr && !raw_block_size.is_empty()
|
||||
{
|
||||
match parse_size_u64(&raw_block_size.to_string_lossy()) {
|
||||
match parse_size_non_zero_u64(&raw_block_size.to_string_lossy()) {
|
||||
Ok(size) => match (is_env_var_blocksize, opt_kb) {
|
||||
(true, true) => (DEFAULT_FILE_SIZE_BLOCK_SIZE, DEFAULT_BLOCK_SIZE),
|
||||
(true, false) => (DEFAULT_FILE_SIZE_BLOCK_SIZE, size),
|
||||
|
||||
@@ -66,6 +66,7 @@ od-help-address-radix = Select the base in which file offsets are printed.
|
||||
od-help-skip-bytes = Skip bytes input bytes before formatting and writing.
|
||||
od-help-read-bytes = limit dump to BYTES input bytes
|
||||
od-help-endian = byte order to use for multi-byte formats
|
||||
od-help-strings = output strings of at least BYTES graphic chars. 3 is assumed when BYTES is not specified.
|
||||
od-help-a = named characters, ignoring high-order bit
|
||||
od-help-b = octal bytes
|
||||
od-help-c = ASCII characters or backslash escapes
|
||||
@@ -76,3 +77,17 @@ od-help-output-duplicates = do not use * to mark line suppression
|
||||
od-help-width = output BYTES bytes per output line. 32 is implied when BYTES is not
|
||||
specified.
|
||||
od-help-traditional = compatibility mode with one input, offset and label.
|
||||
od-help-o = octal 2-byte units
|
||||
od-help-capital-i = decimal 8-byte units
|
||||
od-help-capital-l = decimal 8-byte units
|
||||
od-help-i = decimal 4-byte units
|
||||
od-help-l = decimal 8-byte units
|
||||
od-help-x = hexadecimal 2-byte units
|
||||
od-help-h = hexadecimal 2-byte units
|
||||
od-help-capital-o = octal 4-byte units
|
||||
od-help-s = decimal 2-byte units
|
||||
od-help-capital-x = hexadecimal 4-byte units
|
||||
od-help-capital-h = hexadecimal 4-byte units
|
||||
od-help-e = floating point double precision (64-bit) units
|
||||
od-help-f = floating point double precision (32-bit) units
|
||||
od-help-capital-f = floating point double precision (64-bit) units
|
||||
|
||||
@@ -67,6 +67,7 @@ od-help-address-radix = Sélectionner la base dans laquelle les décalages de fi
|
||||
od-help-skip-bytes = Ignorer les octets d'entrée avant le formatage et l'écriture.
|
||||
od-help-read-bytes = limiter le dump à OCTETS octets d'entrée
|
||||
od-help-endian = ordre des octets à utiliser pour les formats multi-octets
|
||||
od-help-strings = afficher les chaînes d'au moins OCTETS caractères graphiques. 3 est supposé quand OCTETS n'est pas spécifié.
|
||||
od-help-a = caractères nommés, ignorant le bit d'ordre supérieur
|
||||
od-help-b = octets octaux
|
||||
od-help-c = caractères ASCII ou échappements antislash
|
||||
@@ -77,3 +78,17 @@ od-help-output-duplicates = ne pas utiliser * pour marquer la suppression de lig
|
||||
od-help-width = sortir OCTETS octets par ligne de sortie. 32 est impliqué quand OCTETS n'est pas
|
||||
spécifié.
|
||||
od-help-traditional = mode de compatibilité avec une entrée, décalage et étiquette.
|
||||
od-help-o = unités octales 2-octets
|
||||
od-help-capital-i = unités décimales 8-octets
|
||||
od-help-capital-l = unités décimales 8-octets
|
||||
od-help-i = unités décimales 4-octets
|
||||
od-help-l = unités décimales 8-octets
|
||||
od-help-x = unités hexadécimales 2-octets
|
||||
od-help-h = unités hexadécimales 2-octets
|
||||
od-help-capital-o = unités octales 4-octets
|
||||
od-help-s = unités décimales 2-octets
|
||||
od-help-capital-x = unités hexadécimales 4-octets
|
||||
od-help-capital-h = unités hexadécimales 4-octets
|
||||
od-help-e = unités virgule flottante double précision (64-bits)
|
||||
od-help-f = unités virgule flottante double précision (32-bits)
|
||||
od-help-capital-f = unités virgule flottante double précision (64-bits)
|
||||
|
||||
+186
-70
@@ -26,7 +26,7 @@ mod prn_int;
|
||||
|
||||
use std::cmp;
|
||||
use std::fmt::Write;
|
||||
use std::io::BufReader;
|
||||
use std::io::{BufReader, Read};
|
||||
|
||||
use crate::byteorder_io::ByteOrder;
|
||||
use crate::formatter_item_info::FormatWriter;
|
||||
@@ -76,6 +76,21 @@ struct OdOptions {
|
||||
line_bytes: usize,
|
||||
output_duplicates: bool,
|
||||
radix: Radix,
|
||||
string_min_length: Option<usize>,
|
||||
}
|
||||
|
||||
/// Helper function to parse bytes with error handling
|
||||
fn parse_bytes_option(matches: &ArgMatches, option_name: &str) -> UResult<Option<u64>> {
|
||||
match matches.get_one::<String>(option_name) {
|
||||
None => Ok(None),
|
||||
Some(s) => match parse_number_of_bytes(s) {
|
||||
Ok(n) => Ok(Some(n)),
|
||||
Err(e) => Err(USimpleError::new(
|
||||
1,
|
||||
format_error_message(&e, s, option_name),
|
||||
)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
impl OdOptions {
|
||||
@@ -95,18 +110,7 @@ impl OdOptions {
|
||||
ByteOrder::Native
|
||||
};
|
||||
|
||||
let mut skip_bytes = match matches.get_one::<String>(options::SKIP_BYTES) {
|
||||
None => 0,
|
||||
Some(s) => match parse_number_of_bytes(s) {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format_error_message(&e, s, options::SKIP_BYTES),
|
||||
));
|
||||
}
|
||||
},
|
||||
};
|
||||
let mut skip_bytes = parse_bytes_option(matches, options::SKIP_BYTES)?.unwrap_or(0);
|
||||
|
||||
let mut label: Option<u64> = None;
|
||||
|
||||
@@ -156,17 +160,16 @@ impl OdOptions {
|
||||
|
||||
let output_duplicates = matches.get_flag(options::OUTPUT_DUPLICATES);
|
||||
|
||||
let read_bytes = match matches.get_one::<String>(options::READ_BYTES) {
|
||||
let read_bytes = parse_bytes_option(matches, options::READ_BYTES)?;
|
||||
|
||||
let string_min_length = match parse_bytes_option(matches, options::STRINGS)? {
|
||||
None => None,
|
||||
Some(s) => match parse_number_of_bytes(s) {
|
||||
Ok(n) => Some(n),
|
||||
Err(e) => {
|
||||
return Err(USimpleError::new(
|
||||
1,
|
||||
format_error_message(&e, s, options::READ_BYTES),
|
||||
));
|
||||
}
|
||||
},
|
||||
Some(n) => Some(usize::try_from(n).map_err(|_| {
|
||||
USimpleError::new(
|
||||
1,
|
||||
translate!("od-error-argument-too-large", "option" => "-S", "value" => n.to_string()),
|
||||
)
|
||||
})?),
|
||||
};
|
||||
|
||||
let radix = match matches.get_one::<String>(options::ADDRESS_RADIX) {
|
||||
@@ -208,6 +211,7 @@ impl OdOptions {
|
||||
line_bytes,
|
||||
output_duplicates,
|
||||
radix,
|
||||
string_min_length,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -224,28 +228,39 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
|
||||
let od_options = OdOptions::new(&clap_matches, &args)?;
|
||||
|
||||
let mut input_offset =
|
||||
InputOffset::new(od_options.radix, od_options.skip_bytes, od_options.label);
|
||||
// Check if we're in strings mode
|
||||
if let Some(min_length) = od_options.string_min_length {
|
||||
extract_strings_from_input(
|
||||
&od_options.input_strings,
|
||||
od_options.skip_bytes,
|
||||
od_options.read_bytes,
|
||||
min_length,
|
||||
od_options.radix,
|
||||
)
|
||||
} else {
|
||||
let mut input_offset =
|
||||
InputOffset::new(od_options.radix, od_options.skip_bytes, od_options.label);
|
||||
|
||||
let mut input = open_input_peek_reader(
|
||||
&od_options.input_strings,
|
||||
od_options.skip_bytes,
|
||||
od_options.read_bytes,
|
||||
);
|
||||
let mut input_decoder = InputDecoder::new(
|
||||
&mut input,
|
||||
od_options.line_bytes,
|
||||
PEEK_BUFFER_SIZE,
|
||||
od_options.byte_order,
|
||||
);
|
||||
let mut input = open_input_peek_reader(
|
||||
&od_options.input_strings,
|
||||
od_options.skip_bytes,
|
||||
od_options.read_bytes,
|
||||
);
|
||||
let mut input_decoder = InputDecoder::new(
|
||||
&mut input,
|
||||
od_options.line_bytes,
|
||||
PEEK_BUFFER_SIZE,
|
||||
od_options.byte_order,
|
||||
);
|
||||
|
||||
let output_info = OutputInfo::new(
|
||||
od_options.line_bytes,
|
||||
&od_options.formats[..],
|
||||
od_options.output_duplicates,
|
||||
);
|
||||
let output_info = OutputInfo::new(
|
||||
od_options.line_bytes,
|
||||
&od_options.formats[..],
|
||||
od_options.output_duplicates,
|
||||
);
|
||||
|
||||
odfunc(&mut input_offset, &mut input_decoder, &output_info)
|
||||
odfunc(&mut input_offset, &mut input_decoder, &output_info)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
@@ -263,7 +278,7 @@ pub fn uu_app() -> Command {
|
||||
Arg::new(options::HELP)
|
||||
.long(options::HELP)
|
||||
.help(translate!("od-help-help"))
|
||||
.action(ArgAction::Help)
|
||||
.action(ArgAction::Help),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::ADDRESS_RADIX)
|
||||
@@ -297,10 +312,8 @@ pub fn uu_app() -> Command {
|
||||
Arg::new(options::STRINGS)
|
||||
.short('S')
|
||||
.long(options::STRINGS)
|
||||
.help(
|
||||
"NotImplemented: output strings of at least BYTES graphic chars. 3 is assumed when \
|
||||
BYTES is not specified.",
|
||||
)
|
||||
.help(translate!("od-help-strings"))
|
||||
.num_args(0..=1)
|
||||
.default_missing_value("3")
|
||||
.value_name("BYTES"),
|
||||
)
|
||||
@@ -337,85 +350,85 @@ pub fn uu_app() -> Command {
|
||||
.arg(
|
||||
Arg::new("o")
|
||||
.short('o')
|
||||
.help("octal 2-byte units")
|
||||
.help(translate!("od-help-o"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("I")
|
||||
.short('I')
|
||||
.help("decimal 8-byte units")
|
||||
.help(translate!("od-help-capital-i"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("L")
|
||||
.short('L')
|
||||
.help("decimal 8-byte units")
|
||||
.help(translate!("od-help-capital-l"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("i")
|
||||
.short('i')
|
||||
.help("decimal 4-byte units")
|
||||
.help(translate!("od-help-i"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("l")
|
||||
.short('l')
|
||||
.help("decimal 8-byte units")
|
||||
.help(translate!("od-help-l"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("x")
|
||||
.short('x')
|
||||
.help("hexadecimal 2-byte units")
|
||||
.help(translate!("od-help-x"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("h")
|
||||
.short('h')
|
||||
.help("hexadecimal 2-byte units")
|
||||
.help(translate!("od-help-h"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("O")
|
||||
.short('O')
|
||||
.help("octal 4-byte units")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help(translate!("od-help-capital-o"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("s")
|
||||
.short('s')
|
||||
.help("decimal 2-byte units")
|
||||
.help(translate!("od-help-s"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("X")
|
||||
.short('X')
|
||||
.help("hexadecimal 4-byte units")
|
||||
.help(translate!("od-help-capital-x"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("H")
|
||||
.short('H')
|
||||
.help("hexadecimal 4-byte units")
|
||||
.help(translate!("od-help-capital-h"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("e")
|
||||
.short('e')
|
||||
.help("floating point double precision (64-bit) units")
|
||||
.help(translate!("od-help-e"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("f")
|
||||
.short('f')
|
||||
.help("floating point double precision (32-bit) units")
|
||||
.help(translate!("od-help-f"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("F")
|
||||
.short('F')
|
||||
.help("floating point double precision (64-bit) units")
|
||||
.help(translate!("od-help-capital-f"))
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
@@ -532,6 +545,105 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract and display printable strings from input (od -S option)
|
||||
fn extract_strings_from_input(
|
||||
input_strings: &[String],
|
||||
skip_bytes: u64,
|
||||
read_bytes: Option<u64>,
|
||||
min_length: usize,
|
||||
radix: Radix,
|
||||
) -> UResult<()> {
|
||||
let inputs = map_input_strings(input_strings);
|
||||
let mut mf = MultifileReader::new(inputs);
|
||||
|
||||
// Apply skip_bytes by reading and discarding
|
||||
let mut skipped = 0u64;
|
||||
while skipped < skip_bytes {
|
||||
let to_skip = std::cmp::min(8192, skip_bytes - skipped);
|
||||
let mut skip_buf = vec![0u8; to_skip as usize];
|
||||
match mf.read(&mut skip_buf) {
|
||||
Ok(0) => break, // EOF reached
|
||||
Ok(n) => skipped += n as u64,
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to format and print a string
|
||||
let print_string = |offset: u64, string: &[u8]| {
|
||||
let string_content = String::from_utf8_lossy(string);
|
||||
match radix {
|
||||
Radix::NoPrefix => println!("{string_content}"),
|
||||
Radix::Decimal => println!("{offset:07} {string_content}"),
|
||||
Radix::Hexadecimal => println!("{offset:07x} {string_content}"),
|
||||
Radix::Octal => println!("{offset:07o} {string_content}"),
|
||||
}
|
||||
};
|
||||
|
||||
let mut current_string = Vec::new();
|
||||
let mut string_start_offset = 0u64;
|
||||
let mut current_offset = skip_bytes;
|
||||
let mut bytes_read = 0u64;
|
||||
let mut buf = [0u8; 1];
|
||||
|
||||
loop {
|
||||
// Check if we've reached the read_bytes limit
|
||||
if let Some(limit) = read_bytes {
|
||||
if bytes_read >= limit {
|
||||
// Special case: when -N limit is reached with a pending string
|
||||
// that meets min_length, output it even without null terminator
|
||||
if current_string.len() >= min_length {
|
||||
print_string(string_start_offset, ¤t_string);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Read one byte at a time
|
||||
match mf.read(&mut buf) {
|
||||
Ok(0) => break, // EOF
|
||||
Ok(_) => {
|
||||
bytes_read += 1;
|
||||
let byte = buf[0];
|
||||
|
||||
// Check if it's a printable character (including space)
|
||||
if (0x20..=0x7E).contains(&byte) {
|
||||
if current_string.is_empty() {
|
||||
string_start_offset = current_offset;
|
||||
}
|
||||
current_string.push(byte);
|
||||
} else {
|
||||
// Either null terminator or non-printable character
|
||||
if byte == 0 && current_string.len() >= min_length {
|
||||
// Null terminator found with valid string
|
||||
print_string(string_start_offset, ¤t_string);
|
||||
}
|
||||
current_string.clear();
|
||||
}
|
||||
|
||||
current_offset += 1;
|
||||
}
|
||||
Err(e) => {
|
||||
// Note: GNU od does not output unterminated strings at EOF
|
||||
// Strings must be null-terminated to be output
|
||||
if mf.has_error() {
|
||||
show_error!("{}", e);
|
||||
return Err(1.into());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// GNU od doesn't output an offset when strings mode finds no valid strings
|
||||
// This includes cases with only unterminated or too-short strings
|
||||
|
||||
if mf.has_error() {
|
||||
Err(1.into())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Outputs a single line of input, into one or more lines human readable output.
|
||||
fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &OutputInfo) {
|
||||
let mut first = true; // First line of a multi-format raster.
|
||||
@@ -595,6 +707,17 @@ fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &Output
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function to convert input strings to InputSource
|
||||
fn map_input_strings(input_strings: &[String]) -> Vec<InputSource<'_>> {
|
||||
input_strings
|
||||
.iter()
|
||||
.map(|w| match w as &str {
|
||||
"-" => InputSource::Stdin,
|
||||
x => InputSource::FileName(x),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// returns a reader implementing `PeekRead + Read + HasError` providing the combined input
|
||||
///
|
||||
/// `skip_bytes` is the number of bytes skipped from the input
|
||||
@@ -605,14 +728,7 @@ fn open_input_peek_reader(
|
||||
read_bytes: Option<u64>,
|
||||
) -> PeekReader<BufReader<PartialReader<MultifileReader<'_>>>> {
|
||||
// should return "impl PeekRead + Read + HasError" when supported in (stable) rust
|
||||
let inputs = input_strings
|
||||
.iter()
|
||||
.map(|w| match w as &str {
|
||||
"-" => InputSource::Stdin,
|
||||
x => InputSource::FileName(x),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let inputs = map_input_strings(input_strings);
|
||||
let mf = MultifileReader::new(inputs);
|
||||
let pr = PartialReader::new(mf, skip_bytes, read_bytes);
|
||||
// Add a BufReader over the top of the PartialReader. This will have the
|
||||
|
||||
@@ -14,16 +14,17 @@ use uucore::benchmark::{run_util_function, setup_test_file, text_data};
|
||||
fn sort_ascii_c_locale(bencher: Bencher) {
|
||||
let data = text_data::generate_ascii_data_simple(100_000);
|
||||
let file_path = setup_test_file(&data);
|
||||
// Reuse the same output file across iterations to reduce filesystem variance
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap().to_string();
|
||||
|
||||
bencher.bench(|| {
|
||||
unsafe {
|
||||
env::set_var("LC_ALL", "C");
|
||||
}
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap();
|
||||
black_box(run_util_function(
|
||||
uumain,
|
||||
&["-o", output_path, file_path.to_str().unwrap()],
|
||||
&["-o", &output_path, file_path.to_str().unwrap()],
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -33,16 +34,17 @@ fn sort_ascii_c_locale(bencher: Bencher) {
|
||||
fn sort_ascii_utf8_locale(bencher: Bencher) {
|
||||
let data = text_data::generate_ascii_data_simple(200_000);
|
||||
let file_path = setup_test_file(&data);
|
||||
// Reuse the same output file across iterations to reduce filesystem variance
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap().to_string();
|
||||
|
||||
bencher.bench(|| {
|
||||
unsafe {
|
||||
env::set_var("LC_ALL", "en_US.UTF-8");
|
||||
}
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap();
|
||||
black_box(run_util_function(
|
||||
uumain,
|
||||
&["-o", output_path, file_path.to_str().unwrap()],
|
||||
&["-o", &output_path, file_path.to_str().unwrap()],
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -52,16 +54,17 @@ fn sort_ascii_utf8_locale(bencher: Bencher) {
|
||||
fn sort_mixed_c_locale(bencher: Bencher) {
|
||||
let data = text_data::generate_mixed_locale_data(50_000);
|
||||
let file_path = setup_test_file(&data);
|
||||
// Reuse the same output file across iterations to reduce filesystem variance
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap().to_string();
|
||||
|
||||
bencher.bench(|| {
|
||||
unsafe {
|
||||
env::set_var("LC_ALL", "C");
|
||||
}
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap();
|
||||
black_box(run_util_function(
|
||||
uumain,
|
||||
&["-o", output_path, file_path.to_str().unwrap()],
|
||||
&["-o", &output_path, file_path.to_str().unwrap()],
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -71,16 +74,17 @@ fn sort_mixed_c_locale(bencher: Bencher) {
|
||||
fn sort_mixed_utf8_locale(bencher: Bencher) {
|
||||
let data = text_data::generate_mixed_locale_data(50_000);
|
||||
let file_path = setup_test_file(&data);
|
||||
// Reuse the same output file across iterations to reduce filesystem variance
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap().to_string();
|
||||
|
||||
bencher.bench(|| {
|
||||
unsafe {
|
||||
env::set_var("LC_ALL", "en_US.UTF-8");
|
||||
}
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap();
|
||||
black_box(run_util_function(
|
||||
uumain,
|
||||
&["-o", output_path, file_path.to_str().unwrap()],
|
||||
&["-o", &output_path, file_path.to_str().unwrap()],
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -90,16 +94,17 @@ fn sort_mixed_utf8_locale(bencher: Bencher) {
|
||||
fn sort_german_c_locale(bencher: Bencher) {
|
||||
let data = text_data::generate_german_locale_data(50_000);
|
||||
let file_path = setup_test_file(&data);
|
||||
// Reuse the same output file across iterations to reduce filesystem variance
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap().to_string();
|
||||
|
||||
bencher.bench(|| {
|
||||
unsafe {
|
||||
env::set_var("LC_ALL", "C");
|
||||
}
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap();
|
||||
black_box(run_util_function(
|
||||
uumain,
|
||||
&["-o", output_path, file_path.to_str().unwrap()],
|
||||
&["-o", &output_path, file_path.to_str().unwrap()],
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -109,16 +114,17 @@ fn sort_german_c_locale(bencher: Bencher) {
|
||||
fn sort_german_locale(bencher: Bencher) {
|
||||
let data = text_data::generate_german_locale_data(50_000);
|
||||
let file_path = setup_test_file(&data);
|
||||
// Reuse the same output file across iterations to reduce filesystem variance
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap().to_string();
|
||||
|
||||
bencher.bench(|| {
|
||||
unsafe {
|
||||
env::set_var("LC_ALL", "de_DE.UTF-8");
|
||||
}
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap();
|
||||
black_box(run_util_function(
|
||||
uumain,
|
||||
&["-o", output_path, file_path.to_str().unwrap()],
|
||||
&["-o", &output_path, file_path.to_str().unwrap()],
|
||||
));
|
||||
});
|
||||
}
|
||||
@@ -128,16 +134,17 @@ fn sort_german_locale(bencher: Bencher) {
|
||||
fn sort_random_strings(bencher: Bencher) {
|
||||
let data = text_data::generate_random_strings(50_000, 50);
|
||||
let file_path = setup_test_file(&data);
|
||||
// Reuse the same output file across iterations to reduce filesystem variance
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap().to_string();
|
||||
|
||||
bencher.bench(|| {
|
||||
unsafe {
|
||||
env::set_var("LC_ALL", "en_US.UTF-8");
|
||||
}
|
||||
let output_file = NamedTempFile::new().unwrap();
|
||||
let output_path = output_file.path().to_str().unwrap();
|
||||
black_box(run_util_function(
|
||||
uumain,
|
||||
&["-o", output_path, file_path.to_str().unwrap()],
|
||||
&["-o", &output_path, file_path.to_str().unwrap()],
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -690,6 +690,24 @@ fn test_block_size_from_env() {
|
||||
assert_eq!(get_header("BLOCKSIZE", "333"), "333B-blocks");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_size_from_env_zero() {
|
||||
fn get_header(env_var: &str, env_value: &str) -> String {
|
||||
let output = new_ucmd!()
|
||||
.arg("--output=size")
|
||||
.env(env_var, env_value)
|
||||
.succeeds()
|
||||
.stdout_str_lossy();
|
||||
output.lines().next().unwrap().trim().to_string()
|
||||
}
|
||||
|
||||
let default_block_size_header = "1K-blocks";
|
||||
|
||||
assert_eq!(get_header("DF_BLOCK_SIZE", "0"), default_block_size_header);
|
||||
assert_eq!(get_header("BLOCK_SIZE", "0"), default_block_size_header);
|
||||
assert_eq!(get_header("BLOCKSIZE", "0"), default_block_size_header);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_size_from_env_precedences() {
|
||||
fn get_header(one: (&str, &str), two: (&str, &str)) -> String {
|
||||
@@ -747,6 +765,16 @@ fn test_invalid_block_size_from_env() {
|
||||
let header = output.lines().next().unwrap().trim().to_string();
|
||||
|
||||
assert_eq!(header, default_block_size_header);
|
||||
|
||||
let output = new_ucmd!()
|
||||
.arg("--output=size")
|
||||
.env("DF_BLOCK_SIZE", "0")
|
||||
.env("BLOCK_SIZE", "222")
|
||||
.succeeds()
|
||||
.stdout_str_lossy();
|
||||
let header = output.lines().next().unwrap().trim().to_string();
|
||||
|
||||
assert_eq!(header, default_block_size_header);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -5355,6 +5355,12 @@ fn test_ls_invalid_block_size() {
|
||||
.fails_with_code(2)
|
||||
.no_stdout()
|
||||
.stderr_is("ls: invalid --block-size argument 'invalid'\n");
|
||||
|
||||
new_ucmd!()
|
||||
.arg("--block-size=0")
|
||||
.fails_with_code(2)
|
||||
.no_stdout()
|
||||
.stderr_is("ls: invalid --block-size argument '0'\n");
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "dd"))]
|
||||
@@ -5394,6 +5400,14 @@ fn test_ls_invalid_block_size_in_env_var() {
|
||||
.succeeds()
|
||||
.stdout_contains_line("total 4")
|
||||
.stdout_contains(" 1024 ");
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-og")
|
||||
.env("BLOCKSIZE", "0")
|
||||
.succeeds()
|
||||
.stdout_contains_line("total 4")
|
||||
.stdout_contains(" 1024 ");
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "dd"))]
|
||||
|
||||
+119
-102
@@ -3,16 +3,14 @@
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore abcdefghijklmnopqrstuvwxyz Anone fdbb
|
||||
// spell-checker:ignore abcdefghijklmnopqrstuvwxyz Anone fdbb littl
|
||||
|
||||
#[cfg(unix)]
|
||||
use std::io::Read;
|
||||
|
||||
use unindent::unindent;
|
||||
use uutests::at_and_ucmd;
|
||||
use uutests::new_ucmd;
|
||||
use uutests::util::TestScenario;
|
||||
use uutests::util_name;
|
||||
use uutests::{at_and_ucmd, new_ucmd, util_name};
|
||||
|
||||
// octal dump of 'abcdefghijklmnopqrstuvwxyz\n'
|
||||
static ALPHA_OUT: &str = "
|
||||
@@ -32,39 +30,30 @@ fn test_file() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
let at = &scene.fixtures;
|
||||
at.write("test", "abcdefghijklmnopqrstuvwxyz\n");
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--endian=little")
|
||||
.arg("test")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(ALPHA_OUT));
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--endian=littl") // spell-checker:disable-line
|
||||
.arg("test")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(ALPHA_OUT));
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--endian=l")
|
||||
.arg("test")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(ALPHA_OUT));
|
||||
|
||||
for arg in ["--endian=little", "--endian=littl", "--endian=l"] {
|
||||
scene
|
||||
.ucmd()
|
||||
.arg(arg)
|
||||
.arg("test")
|
||||
.succeeds()
|
||||
.stdout_only(unindent(ALPHA_OUT));
|
||||
}
|
||||
|
||||
// Ensure that default format matches `-t o2`, and that `-t` does not absorb file argument
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("--endian=little")
|
||||
.arg("-t")
|
||||
.arg("o2")
|
||||
.arg("test");
|
||||
.arg("test")
|
||||
.succeeds()
|
||||
.stdout_only(unindent(ALPHA_OUT));
|
||||
}
|
||||
|
||||
// Test that od can read 2 files and concatenate the contents
|
||||
#[test]
|
||||
fn test_2files() {
|
||||
fn test_two_files() {
|
||||
let (at, mut ucmd) = at_and_ucmd!();
|
||||
at.write("test1", "abcdefghijklmnop");
|
||||
at.write("test2", "qrstuvwxyz\n"); // spell-checker:disable-line
|
||||
@@ -72,15 +61,13 @@ fn test_2files() {
|
||||
.arg("test1")
|
||||
.arg("test2")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(ALPHA_OUT));
|
||||
.stdout_only(unindent(ALPHA_OUT));
|
||||
}
|
||||
|
||||
// Test that od gives non-0 exit val for filename that doesn't exist.
|
||||
#[test]
|
||||
fn test_no_file() {
|
||||
let (_at, mut ucmd) = at_and_ucmd!();
|
||||
ucmd.arg("}surely'none'would'thus'a'file'name").fails();
|
||||
fn test_non_existing_file() {
|
||||
new_ucmd!().arg("non_existing_file").fails();
|
||||
}
|
||||
|
||||
// Test that od reads from stdin instead of a file
|
||||
@@ -91,8 +78,7 @@ fn test_from_stdin() {
|
||||
.arg("--endian=little")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(ALPHA_OUT));
|
||||
.stdout_only(unindent(ALPHA_OUT));
|
||||
}
|
||||
|
||||
// Test that od reads from stdin and also from files
|
||||
@@ -110,8 +96,7 @@ fn test_from_mixed() {
|
||||
.arg("test-3")
|
||||
.run_piped_stdin(data2.as_bytes())
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(ALPHA_OUT));
|
||||
.stdout_only(unindent(ALPHA_OUT));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -122,8 +107,7 @@ fn test_multiple_formats() {
|
||||
.arg("-b")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
"
|
||||
0000000 a b c d e f g h i j k l m n o p
|
||||
141 142 143 144 145 146 147 150 151 152 153 154 155 156 157 160
|
||||
@@ -151,8 +135,7 @@ fn test_dec() {
|
||||
.arg("-s")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -171,8 +154,7 @@ fn test_hex16() {
|
||||
.arg("-x")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -189,8 +171,7 @@ fn test_hex32() {
|
||||
.arg("-X")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -217,8 +198,7 @@ fn test_f16() {
|
||||
.arg("-w8")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -245,8 +225,7 @@ fn test_fh() {
|
||||
.arg("-w8")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -273,8 +252,7 @@ fn test_fb() {
|
||||
.arg("-w8")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -300,8 +278,7 @@ fn test_f32() {
|
||||
.arg("-f")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -329,8 +306,7 @@ fn test_f64() {
|
||||
.arg("-F")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -340,8 +316,7 @@ fn test_multibyte() {
|
||||
.args(&["-t", "c"])
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
r"
|
||||
0000000 342 200 231 342 200 220 313 206 342 200 230 313 234 350 252 236
|
||||
0000020 360 237 231 202 342 234 205 360 237 220 266 360 235 233 221 U
|
||||
@@ -368,8 +343,7 @@ fn test_width() {
|
||||
.arg("-v")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -425,8 +399,7 @@ fn test_width_without_value() {
|
||||
.arg("-w")
|
||||
.run_piped_stdin(&input[..])
|
||||
.success()
|
||||
.no_stderr()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -456,9 +429,8 @@ fn test_suppress_duplicates() {
|
||||
.arg("-O")
|
||||
.arg("-x")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -482,9 +454,8 @@ fn test_big_endian() {
|
||||
.arg("-X")
|
||||
.arg("-x")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(&expected_output);
|
||||
.stdout_only(&expected_output);
|
||||
new_ucmd!()
|
||||
.arg("--endian=b")
|
||||
.arg("-F")
|
||||
@@ -492,9 +463,8 @@ fn test_big_endian() {
|
||||
.arg("-X")
|
||||
.arg("-x")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -518,9 +488,8 @@ fn test_alignment_Xxa() {
|
||||
.arg("-x")
|
||||
.arg("-a")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -542,9 +511,8 @@ fn test_alignment_Fx() {
|
||||
.arg("-F")
|
||||
.arg("-x")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -570,9 +538,8 @@ fn test_max_uint() {
|
||||
.arg("-Dd")
|
||||
.arg("--format=u1")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -593,9 +560,8 @@ fn test_hex_offset() {
|
||||
.arg("-X")
|
||||
.arg("-X")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -616,9 +582,8 @@ fn test_dec_offset() {
|
||||
.arg("-X")
|
||||
.arg("-X")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -632,9 +597,8 @@ fn test_no_offset() {
|
||||
.arg("-X")
|
||||
.arg("-X")
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(expected_output);
|
||||
.stdout_only(expected_output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -670,9 +634,8 @@ fn test_skip_bytes() {
|
||||
.arg("-c")
|
||||
.arg("--skip-bytes=5")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
"
|
||||
0000005 f g h i j k l m n o p q
|
||||
0000021
|
||||
@@ -687,9 +650,8 @@ fn test_skip_bytes_hex() {
|
||||
.arg("-c")
|
||||
.arg("--skip-bytes=0xB")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
"
|
||||
0000013 l m n o p q
|
||||
0000021
|
||||
@@ -699,9 +661,8 @@ fn test_skip_bytes_hex() {
|
||||
.arg("-c")
|
||||
.arg("--skip-bytes=0xE")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
"
|
||||
0000016 o p q
|
||||
0000021
|
||||
@@ -765,9 +726,8 @@ fn test_ascii_dump() {
|
||||
new_ucmd!()
|
||||
.arg("-tx1zacz") // spell-checker:disable-line
|
||||
.run_piped_stdin(&input[..])
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
r"
|
||||
0000000 00 01 0a 0d 10 1f 20 61 62 63 7d 7e 7f 80 90 a0 >...... abc}~....<
|
||||
nul soh nl cr dle us sp a b c } ~ del nul dle sp
|
||||
@@ -793,8 +753,7 @@ fn test_filename_parsing() {
|
||||
.arg("--")
|
||||
.arg("-f")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
"
|
||||
000000 m i n u s sp l o w e r c a s e sp
|
||||
000010 f nl
|
||||
@@ -810,9 +769,8 @@ fn test_stdin_offset() {
|
||||
.arg("-c")
|
||||
.arg("+5")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
"
|
||||
0000005 f g h i j k l m n o p q
|
||||
0000021
|
||||
@@ -828,8 +786,7 @@ fn test_file_offset() {
|
||||
.arg("-f")
|
||||
.arg("10")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
r"
|
||||
0000010 w e r c a s e f \n
|
||||
0000022
|
||||
@@ -849,9 +806,8 @@ fn test_traditional() {
|
||||
.arg("10")
|
||||
.arg("0")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
r"
|
||||
0000010 (0000000) i j k l m n o p q
|
||||
i j k l m n o p q
|
||||
@@ -870,9 +826,8 @@ fn test_traditional_with_skip_bytes_override() {
|
||||
.arg("-c")
|
||||
.arg("0")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
r"
|
||||
0000000 a b c d e f g h i j k l m n o p
|
||||
0000020
|
||||
@@ -889,9 +844,8 @@ fn test_traditional_with_skip_bytes_non_override() {
|
||||
.arg("--skip-bytes=10")
|
||||
.arg("-c")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
r"
|
||||
0000012 k l m n o p
|
||||
0000020
|
||||
@@ -923,9 +877,8 @@ fn test_traditional_only_label() {
|
||||
.arg("10")
|
||||
.arg("0x10")
|
||||
.run_piped_stdin(input.as_bytes())
|
||||
.no_stderr()
|
||||
.success()
|
||||
.stdout_is(unindent(
|
||||
.stdout_only(unindent(
|
||||
r"
|
||||
(0000020) i j k l m n o p q r s t u v w x
|
||||
i j k l m n o p q r s t u v w x
|
||||
@@ -989,6 +942,70 @@ fn test_od_options_after_filename() {
|
||||
.arg("-t")
|
||||
.arg("x2")
|
||||
.succeeds()
|
||||
.no_stderr()
|
||||
.stdout_is(" 1c68 fdbb\n");
|
||||
.stdout_only(" 1c68 fdbb\n");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_od_strings_option() {
|
||||
// Test -S option: output strings of at least N graphic chars
|
||||
|
||||
// Test -S0: output all null-terminated strings regardless of length
|
||||
new_ucmd!()
|
||||
.arg("-S0")
|
||||
.pipe_in(b"hello\x00world\x00")
|
||||
.succeeds()
|
||||
.stdout_is("0000000 hello\n0000006 world\n");
|
||||
|
||||
// Test -S0 with single character strings
|
||||
new_ucmd!()
|
||||
.arg("-S0")
|
||||
.pipe_in(b"a\x00b\x00cd\x00")
|
||||
.succeeds()
|
||||
.stdout_is("0000000 a\n0000002 b\n0000004 cd\n");
|
||||
|
||||
// Test with null-terminated strings
|
||||
new_ucmd!()
|
||||
.arg("-S3")
|
||||
.pipe_in(b"\x01hello\x00world\x00ab\x00")
|
||||
.succeeds()
|
||||
.stdout_is("0000001 hello\n0000007 world\n");
|
||||
|
||||
// Test with -S10 to show only strings with minimum length
|
||||
new_ucmd!()
|
||||
.arg("-S10")
|
||||
.pipe_in(b"\x01 \x00 \x00")
|
||||
.succeeds()
|
||||
.stdout_is("0000001 \n0000014 \n");
|
||||
|
||||
// Test with unterminated string at EOF (should not output)
|
||||
new_ucmd!()
|
||||
.arg("-S10")
|
||||
.pipe_in(b" ")
|
||||
.succeeds()
|
||||
.no_output();
|
||||
|
||||
// Test with -N limit and pending string (should output even without null)
|
||||
let expected = "0000000 \n";
|
||||
new_ucmd!()
|
||||
.arg("-N2")
|
||||
.arg("-S1")
|
||||
.pipe_in(" ")
|
||||
.succeeds()
|
||||
.stdout_is(expected);
|
||||
|
||||
// Test with -N limit and string too short
|
||||
new_ucmd!()
|
||||
.arg("-N11")
|
||||
.arg("-S11")
|
||||
.pipe_in(b" \x00")
|
||||
.succeeds()
|
||||
.no_output();
|
||||
|
||||
// Test with no address prefix (-An)
|
||||
new_ucmd!()
|
||||
.arg("-S3")
|
||||
.arg("-An")
|
||||
.pipe_in(b"hello\x00world\x00")
|
||||
.succeeds()
|
||||
.stdout_is("hello\nworld\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user