mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-08-02 05:57:46 +00:00
Merge branch 'master' of https://github.com/uutils/coreutils into hbina-tr-reimplement-expansion
This commit is contained in:
commit
02fd7176b7
6 changed files with 87 additions and 137 deletions
2
build.rs
2
build.rs
|
@ -46,6 +46,8 @@ pub fn main() {
|
||||||
"type UtilityMap<T> = HashMap<&'static str, (fn(T) -> i32, fn() -> App<'static, 'static>)>;\n\
|
"type UtilityMap<T> = HashMap<&'static str, (fn(T) -> i32, fn() -> App<'static, 'static>)>;\n\
|
||||||
\n\
|
\n\
|
||||||
fn util_map<T: uucore::Args>() -> UtilityMap<T> {\n\
|
fn util_map<T: uucore::Args>() -> UtilityMap<T> {\n\
|
||||||
|
\t#[allow(unused_mut)]\n\
|
||||||
|
\t#[allow(clippy::let_and_return)]\n\
|
||||||
\tlet mut map = UtilityMap::new();\n\
|
\tlet mut map = UtilityMap::new();\n\
|
||||||
"
|
"
|
||||||
.as_bytes(),
|
.as_bytes(),
|
||||||
|
|
|
@ -25,60 +25,15 @@ const NAME: &str = "cksum";
|
||||||
const SYNTAX: &str = "[OPTIONS] [FILE]...";
|
const SYNTAX: &str = "[OPTIONS] [FILE]...";
|
||||||
const SUMMARY: &str = "Print CRC and size for each file";
|
const SUMMARY: &str = "Print CRC and size for each file";
|
||||||
|
|
||||||
// this is basically a hack to get "loops" to work on Rust 1.33. Once we update to Rust 1.46 or
|
|
||||||
// greater, we can just use while loops
|
|
||||||
macro_rules! unroll {
|
|
||||||
(256, |$i:ident| $s:expr) => {{
|
|
||||||
unroll!(@ 32, 0 * 32, $i, $s);
|
|
||||||
unroll!(@ 32, 1 * 32, $i, $s);
|
|
||||||
unroll!(@ 32, 2 * 32, $i, $s);
|
|
||||||
unroll!(@ 32, 3 * 32, $i, $s);
|
|
||||||
unroll!(@ 32, 4 * 32, $i, $s);
|
|
||||||
unroll!(@ 32, 5 * 32, $i, $s);
|
|
||||||
unroll!(@ 32, 6 * 32, $i, $s);
|
|
||||||
unroll!(@ 32, 7 * 32, $i, $s);
|
|
||||||
}};
|
|
||||||
(8, |$i:ident| $s:expr) => {{
|
|
||||||
unroll!(@ 8, 0, $i, $s);
|
|
||||||
}};
|
|
||||||
|
|
||||||
(@ 32, $start:expr, $i:ident, $s:expr) => {{
|
|
||||||
unroll!(@ 8, $start + 0 * 8, $i, $s);
|
|
||||||
unroll!(@ 8, $start + 1 * 8, $i, $s);
|
|
||||||
unroll!(@ 8, $start + 2 * 8, $i, $s);
|
|
||||||
unroll!(@ 8, $start + 3 * 8, $i, $s);
|
|
||||||
}};
|
|
||||||
(@ 8, $start:expr, $i:ident, $s:expr) => {{
|
|
||||||
unroll!(@ 4, $start, $i, $s);
|
|
||||||
unroll!(@ 4, $start + 4, $i, $s);
|
|
||||||
}};
|
|
||||||
(@ 4, $start:expr, $i:ident, $s:expr) => {{
|
|
||||||
unroll!(@ 2, $start, $i, $s);
|
|
||||||
unroll!(@ 2, $start + 2, $i, $s);
|
|
||||||
}};
|
|
||||||
(@ 2, $start:expr, $i:ident, $s:expr) => {{
|
|
||||||
unroll!(@ 1, $start, $i, $s);
|
|
||||||
unroll!(@ 1, $start + 1, $i, $s);
|
|
||||||
}};
|
|
||||||
(@ 1, $start:expr, $i:ident, $s:expr) => {{
|
|
||||||
let $i = $start;
|
|
||||||
let _ = $s;
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] {
|
const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] {
|
||||||
let mut table = [0; CRC_TABLE_LEN];
|
let mut table = [0; CRC_TABLE_LEN];
|
||||||
|
|
||||||
// NOTE: works on Rust 1.46
|
let mut i = 0;
|
||||||
//let mut i = 0;
|
while i < CRC_TABLE_LEN {
|
||||||
//while i < CRC_TABLE_LEN {
|
|
||||||
// table[i] = crc_entry(i as u8) as u32;
|
|
||||||
//
|
|
||||||
// i += 1;
|
|
||||||
//}
|
|
||||||
unroll!(256, |i| {
|
|
||||||
table[i] = crc_entry(i as u8) as u32;
|
table[i] = crc_entry(i as u8) as u32;
|
||||||
});
|
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
table
|
table
|
||||||
}
|
}
|
||||||
|
@ -86,19 +41,8 @@ const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] {
|
||||||
const fn crc_entry(input: u8) -> u32 {
|
const fn crc_entry(input: u8) -> u32 {
|
||||||
let mut crc = (input as u32) << 24;
|
let mut crc = (input as u32) << 24;
|
||||||
|
|
||||||
// NOTE: this does not work on Rust 1.33, but *does* on 1.46
|
let mut i = 0;
|
||||||
//let mut i = 0;
|
while i < 8 {
|
||||||
//while i < 8 {
|
|
||||||
// if crc & 0x8000_0000 != 0 {
|
|
||||||
// crc <<= 1;
|
|
||||||
// crc ^= 0x04c1_1db7;
|
|
||||||
// } else {
|
|
||||||
// crc <<= 1;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// i += 1;
|
|
||||||
//}
|
|
||||||
unroll!(8, |_i| {
|
|
||||||
let if_condition = crc & 0x8000_0000;
|
let if_condition = crc & 0x8000_0000;
|
||||||
let if_body = (crc << 1) ^ 0x04c1_1db7;
|
let if_body = (crc << 1) ^ 0x04c1_1db7;
|
||||||
let else_body = crc << 1;
|
let else_body = crc << 1;
|
||||||
|
@ -108,7 +52,8 @@ const fn crc_entry(input: u8) -> u32 {
|
||||||
let condition_table = [else_body, if_body];
|
let condition_table = [else_body, if_body];
|
||||||
|
|
||||||
crc = condition_table[(if_condition != 0) as usize];
|
crc = condition_table[(if_condition != 0) as usize];
|
||||||
});
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
crc
|
crc
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,10 +171,6 @@ impl UError for SortError {
|
||||||
_ => 2,
|
_ => 2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SortError {
|
impl Display for SortError {
|
||||||
|
@ -663,10 +659,7 @@ impl<'a> Line<'a> {
|
||||||
" ".repeat(UnicodeWidthStr::width(&line[..selection.start]))
|
" ".repeat(UnicodeWidthStr::width(&line[..selection.start]))
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// TODO: Once our minimum supported rust version is at least 1.47, use selection.is_empty() instead.
|
if selection.is_empty() {
|
||||||
#[allow(clippy::len_zero)]
|
|
||||||
{
|
|
||||||
if selection.len() == 0 {
|
|
||||||
writeln!(writer, "^ no match for key")?;
|
writeln!(writer, "^ no match for key")?;
|
||||||
} else {
|
} else {
|
||||||
writeln!(
|
writeln!(
|
||||||
|
@ -676,7 +669,6 @@ impl<'a> Line<'a> {
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if settings.mode != SortMode::Random
|
if settings.mode != SortMode::Random
|
||||||
&& !settings.stable
|
&& !settings.stable
|
||||||
&& !settings.unique
|
&& !settings.unique
|
||||||
|
|
|
@ -5,17 +5,14 @@
|
||||||
// * For the full copyright and license information, please view the LICENSE
|
// * For the full copyright and license information, please view the LICENSE
|
||||||
// * file that was distributed with this source code.
|
// * file that was distributed with this source code.
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate uucore;
|
|
||||||
|
|
||||||
use clap::{crate_version, App, Arg, ArgMatches};
|
use clap::{crate_version, App, Arg, ArgMatches};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Result, Write};
|
use std::io::{self, stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use strum_macros::{AsRefStr, EnumString};
|
use strum_macros::{AsRefStr, EnumString};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
|
|
||||||
static ABOUT: &str = "Report or omit repeated lines.";
|
static ABOUT: &str = "Report or omit repeated lines.";
|
||||||
pub mod options {
|
pub mod options {
|
||||||
|
@ -56,36 +53,45 @@ struct Uniq {
|
||||||
zero_terminated: bool,
|
zero_terminated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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())
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl Uniq {
|
impl Uniq {
|
||||||
pub fn print_uniq<R: Read, W: Write>(
|
pub fn print_uniq<R: Read, W: Write>(
|
||||||
&self,
|
&self,
|
||||||
reader: &mut BufReader<R>,
|
reader: &mut BufReader<R>,
|
||||||
writer: &mut BufWriter<W>,
|
writer: &mut BufWriter<W>,
|
||||||
) {
|
) -> UResult<()> {
|
||||||
let mut first_line_printed = false;
|
let mut first_line_printed = false;
|
||||||
let mut group_count = 1;
|
let mut group_count = 1;
|
||||||
let line_terminator = self.get_line_terminator();
|
let line_terminator = self.get_line_terminator();
|
||||||
let mut lines = reader.split(line_terminator).map(get_line_string);
|
let mut lines = reader.split(line_terminator).map(get_line_string);
|
||||||
let mut line = match lines.next() {
|
let mut line = match lines.next() {
|
||||||
Some(l) => l,
|
Some(l) => l?,
|
||||||
None => return,
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
// compare current `line` with consecutive lines (`next_line`) of the input
|
// compare current `line` with consecutive lines (`next_line`) of the input
|
||||||
// and if needed, print `line` based on the command line options provided
|
// and if needed, print `line` based on the command line options provided
|
||||||
for next_line in lines {
|
for next_line in lines {
|
||||||
|
let next_line = next_line?;
|
||||||
if self.cmp_keys(&line, &next_line) {
|
if self.cmp_keys(&line, &next_line) {
|
||||||
if (group_count == 1 && !self.repeats_only)
|
if (group_count == 1 && !self.repeats_only)
|
||||||
|| (group_count > 1 && !self.uniques_only)
|
|| (group_count > 1 && !self.uniques_only)
|
||||||
{
|
{
|
||||||
self.print_line(writer, &line, group_count, first_line_printed);
|
self.print_line(writer, &line, group_count, first_line_printed)?;
|
||||||
first_line_printed = true;
|
first_line_printed = true;
|
||||||
}
|
}
|
||||||
line = next_line;
|
line = next_line;
|
||||||
group_count = 1;
|
group_count = 1;
|
||||||
} else {
|
} else {
|
||||||
if self.all_repeated {
|
if self.all_repeated {
|
||||||
self.print_line(writer, &line, group_count, first_line_printed);
|
self.print_line(writer, &line, group_count, first_line_printed)?;
|
||||||
first_line_printed = true;
|
first_line_printed = true;
|
||||||
line = next_line;
|
line = next_line;
|
||||||
}
|
}
|
||||||
|
@ -93,14 +99,15 @@ impl Uniq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) {
|
if (group_count == 1 && !self.repeats_only) || (group_count > 1 && !self.uniques_only) {
|
||||||
self.print_line(writer, &line, group_count, first_line_printed);
|
self.print_line(writer, &line, group_count, first_line_printed)?;
|
||||||
first_line_printed = true;
|
first_line_printed = true;
|
||||||
}
|
}
|
||||||
if (self.delimiters == Delimiters::Append || self.delimiters == Delimiters::Both)
|
if (self.delimiters == Delimiters::Append || self.delimiters == Delimiters::Both)
|
||||||
&& first_line_printed
|
&& first_line_printed
|
||||||
{
|
{
|
||||||
crash_if_err!(1, writer.write_all(&[line_terminator]));
|
write_line_terminator!(writer, line_terminator)?;
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
|
fn skip_fields<'a>(&self, line: &'a str) -> &'a str {
|
||||||
|
@ -192,41 +199,43 @@ impl Uniq {
|
||||||
line: &str,
|
line: &str,
|
||||||
count: usize,
|
count: usize,
|
||||||
first_line_printed: bool,
|
first_line_printed: bool,
|
||||||
) {
|
) -> UResult<()> {
|
||||||
let line_terminator = self.get_line_terminator();
|
let line_terminator = self.get_line_terminator();
|
||||||
|
|
||||||
if self.should_print_delimiter(count, first_line_printed) {
|
if self.should_print_delimiter(count, first_line_printed) {
|
||||||
crash_if_err!(1, writer.write_all(&[line_terminator]));
|
write_line_terminator!(writer, line_terminator)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
crash_if_err!(
|
|
||||||
1,
|
|
||||||
if self.show_counts {
|
if self.show_counts {
|
||||||
writer.write_all(format!("{:7} {}", count, line).as_bytes())
|
writer.write_all(format!("{:7} {}", count, line).as_bytes())
|
||||||
} else {
|
} else {
|
||||||
writer.write_all(line.as_bytes())
|
writer.write_all(line.as_bytes())
|
||||||
}
|
}
|
||||||
);
|
.map_err_context(|| "Failed to write line".to_string())?;
|
||||||
crash_if_err!(1, writer.write_all(&[line_terminator]));
|
|
||||||
|
write_line_terminator!(writer, line_terminator)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_line_string(io_line: Result<Vec<u8>>) -> String {
|
fn get_line_string(io_line: io::Result<Vec<u8>>) -> UResult<String> {
|
||||||
let line_bytes = crash_if_err!(1, io_line);
|
let line_bytes = io_line.map_err_context(|| "failed to split lines".to_string())?;
|
||||||
crash_if_err!(1, String::from_utf8(line_bytes))
|
String::from_utf8(line_bytes)
|
||||||
|
.map_err(|e| USimpleError::new(1, format!("failed to convert line to utf8: {}", e)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> Option<T> {
|
fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> UResult<Option<T>> {
|
||||||
matches.value_of(opt_name).map(|arg_str| {
|
Ok(match matches.value_of(opt_name) {
|
||||||
let opt_val: Option<T> = arg_str.parse().ok();
|
Some(arg_str) => Some(arg_str.parse().map_err(|_| {
|
||||||
opt_val.unwrap_or_else(|| {
|
USimpleError::new(
|
||||||
crash!(
|
|
||||||
1,
|
1,
|
||||||
|
format!(
|
||||||
"Invalid argument for {}: {}",
|
"Invalid argument for {}: {}",
|
||||||
opt_name,
|
opt_name,
|
||||||
arg_str.maybe_quote()
|
arg_str.maybe_quote()
|
||||||
|
),
|
||||||
)
|
)
|
||||||
})
|
})?),
|
||||||
|
None => None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,8 +275,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
1 => (files[0].clone(), "-".to_owned()),
|
1 => (files[0].clone(), "-".to_owned()),
|
||||||
2 => (files[0].clone(), files[1].clone()),
|
2 => (files[0].clone(), files[1].clone()),
|
||||||
_ => {
|
_ => {
|
||||||
// Cannot happen as clap will fail earlier
|
unreachable!() // Cannot happen as clap will fail earlier
|
||||||
return Err(USimpleError::new(1, format!("Extra operand: {}", files[2])));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -279,18 +287,16 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|| matches.is_present(options::GROUP),
|
|| matches.is_present(options::GROUP),
|
||||||
delimiters: get_delimiter(&matches),
|
delimiters: get_delimiter(&matches),
|
||||||
show_counts: matches.is_present(options::COUNT),
|
show_counts: matches.is_present(options::COUNT),
|
||||||
skip_fields: opt_parsed(options::SKIP_FIELDS, &matches),
|
skip_fields: opt_parsed(options::SKIP_FIELDS, &matches)?,
|
||||||
slice_start: opt_parsed(options::SKIP_CHARS, &matches),
|
slice_start: opt_parsed(options::SKIP_CHARS, &matches)?,
|
||||||
slice_stop: opt_parsed(options::CHECK_CHARS, &matches),
|
slice_stop: opt_parsed(options::CHECK_CHARS, &matches)?,
|
||||||
ignore_case: matches.is_present(options::IGNORE_CASE),
|
ignore_case: matches.is_present(options::IGNORE_CASE),
|
||||||
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
|
zero_terminated: matches.is_present(options::ZERO_TERMINATED),
|
||||||
};
|
};
|
||||||
uniq.print_uniq(
|
uniq.print_uniq(
|
||||||
&mut open_input_file(in_file_name),
|
&mut open_input_file(in_file_name)?,
|
||||||
&mut open_output_file(out_file_name),
|
&mut open_output_file(out_file_name)?,
|
||||||
);
|
)
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app() -> App<'static, 'static> {
|
pub fn uu_app() -> App<'static, 'static> {
|
||||||
|
@ -390,7 +396,7 @@ fn get_delimiter(matches: &ArgMatches) -> Delimiters {
|
||||||
.value_of(options::ALL_REPEATED)
|
.value_of(options::ALL_REPEATED)
|
||||||
.or_else(|| matches.value_of(options::GROUP));
|
.or_else(|| matches.value_of(options::GROUP));
|
||||||
if let Some(delimiter_arg) = value {
|
if let Some(delimiter_arg) = value {
|
||||||
crash_if_err!(1, Delimiters::from_str(delimiter_arg))
|
Delimiters::from_str(delimiter_arg).unwrap() // All possible values for ALL_REPEATED are &str's of Delimiters
|
||||||
} else if matches.is_present(options::GROUP) {
|
} else if matches.is_present(options::GROUP) {
|
||||||
Delimiters::Separate
|
Delimiters::Separate
|
||||||
} else {
|
} else {
|
||||||
|
@ -398,26 +404,26 @@ fn get_delimiter(matches: &ArgMatches) -> Delimiters {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_input_file(in_file_name: String) -> BufReader<Box<dyn Read + 'static>> {
|
fn open_input_file(in_file_name: String) -> UResult<BufReader<Box<dyn Read + 'static>>> {
|
||||||
let in_file = if in_file_name == "-" {
|
let in_file = if in_file_name == "-" {
|
||||||
Box::new(stdin()) as Box<dyn Read>
|
Box::new(stdin()) as Box<dyn Read>
|
||||||
} else {
|
} else {
|
||||||
let path = Path::new(&in_file_name[..]);
|
let path = Path::new(&in_file_name[..]);
|
||||||
let in_file = File::open(&path);
|
let in_file = File::open(&path)
|
||||||
let r = crash_if_err!(1, in_file);
|
.map_err_context(|| format!("Could not open {}", in_file_name.maybe_quote()))?;
|
||||||
Box::new(r) as Box<dyn Read>
|
Box::new(in_file) as Box<dyn Read>
|
||||||
};
|
};
|
||||||
BufReader::new(in_file)
|
Ok(BufReader::new(in_file))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_output_file(out_file_name: String) -> BufWriter<Box<dyn Write + 'static>> {
|
fn open_output_file(out_file_name: String) -> UResult<BufWriter<Box<dyn Write + 'static>>> {
|
||||||
let out_file = if out_file_name == "-" {
|
let out_file = if out_file_name == "-" {
|
||||||
Box::new(stdout()) as Box<dyn Write>
|
Box::new(stdout()) as Box<dyn Write>
|
||||||
} else {
|
} else {
|
||||||
let path = Path::new(&out_file_name[..]);
|
let path = Path::new(&out_file_name[..]);
|
||||||
let in_file = File::create(&path);
|
let out_file = File::create(&path)
|
||||||
let w = crash_if_err!(1, in_file);
|
.map_err_context(|| format!("Could not create {}", out_file_name.maybe_quote()))?;
|
||||||
Box::new(w) as Box<dyn Write>
|
Box::new(out_file) as Box<dyn Write>
|
||||||
};
|
};
|
||||||
BufWriter::new(out_file)
|
Ok(BufWriter::new(out_file))
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,9 @@ fn test_invalid_utf8() {
|
||||||
.arg("not-utf8-sequence.txt")
|
.arg("not-utf8-sequence.txt")
|
||||||
.run()
|
.run()
|
||||||
.failure()
|
.failure()
|
||||||
.stderr_only("uniq: invalid utf-8 sequence of 1 bytes from index 0");
|
.stderr_only(
|
||||||
|
"uniq: failed to convert line to utf8: invalid utf-8 sequence of 1 bytes from index 0",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#![allow(unused_imports)]
|
||||||
mod common;
|
mod common;
|
||||||
|
|
||||||
use common::util::TestScenario;
|
use common::util::TestScenario;
|
||||||
|
@ -25,6 +26,7 @@ fn execution_phrase_double() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "ls")]
|
#[cfg(feature = "ls")]
|
||||||
|
#[cfg(any(unix, windows))]
|
||||||
fn execution_phrase_single() {
|
fn execution_phrase_single() {
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
@ -63,6 +65,7 @@ fn util_name_double() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "sort")]
|
#[cfg(feature = "sort")]
|
||||||
|
#[cfg(any(unix, windows))]
|
||||||
fn util_name_single() {
|
fn util_name_single() {
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
io::Write,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue