Merge branch 'master' into polish-gnu-tests

This commit is contained in:
James Robson 2021-03-18 20:59:41 +00:00
commit c804ec3ba3
199 changed files with 3136 additions and 1824 deletions

View file

@ -154,6 +154,33 @@ jobs:
env:
RUSTFLAGS: '-Awarnings'
busybox_test:
name: Busybox test suite
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
- { os: ubuntu-latest }
steps:
- uses: actions/checkout@v1
- name: Install `rust` toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
default: true
profile: minimal # minimal component installation (ie, no documentation)
- name: "prepare busytest"
shell: bash
run: |
make prepare-busytest
- name: "run busybox testsuite"
shell: bash
run: |
bindir=$(pwd)/target/debug
cd tmp/busybox-*/testsuite
S=$(bindir=$bindir ./runtest) && printf "%s\n" "$S" || { printf "%s\n" "$S" | grep "FAIL:" | sed -e "s/FAIL: /::warning ::Test failure:/g" ; }
build:
name: Build
runs-on: ${{ matrix.job.os }}

View file

@ -18,7 +18,7 @@ matrix:
- rust: nightly
fast_finish: true
include:
- rust: 1.32.0
- rust: 1.33.0
env: FEATURES=unix
# - rust: stable
# os: linux

841
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -3,7 +3,7 @@
[package]
name = "coreutils"
version = "0.0.3" # "0.0.3.1"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust"
@ -226,104 +226,104 @@ test = [ "uu_test" ]
[dependencies]
lazy_static = { version="1.3" }
textwrap = { version="=0.11.0", features=["term_size"] } # !maint: [2020-05-10; rivy] unstable crate using undocumented features; pinned currently, will review
uucore = { version=">=0.0.6", package="uucore", path="src/uucore" }
uucore = { version=">=0.0.7", package="uucore", path="src/uucore" }
# * uutils
uu_test = { optional=true, version="0.0.3", package="uu_test", path="src/uu/test" }
uu_test = { optional=true, version="0.0.4", package="uu_test", path="src/uu/test" }
#
arch = { optional=true, version="0.0.3", package="uu_arch", path="src/uu/arch" }
base32 = { optional=true, version="0.0.3", package="uu_base32", path="src/uu/base32" }
base64 = { optional=true, version="0.0.3", package="uu_base64", path="src/uu/base64" }
basename = { optional=true, version="0.0.3", package="uu_basename", path="src/uu/basename" }
cat = { optional=true, version="0.0.3", package="uu_cat", path="src/uu/cat" }
chgrp = { optional=true, version="0.0.3", package="uu_chgrp", path="src/uu/chgrp" }
chmod = { optional=true, version="0.0.3", package="uu_chmod", path="src/uu/chmod" }
chown = { optional=true, version="0.0.3", package="uu_chown", path="src/uu/chown" }
chroot = { optional=true, version="0.0.3", package="uu_chroot", path="src/uu/chroot" }
cksum = { optional=true, version="0.0.3", package="uu_cksum", path="src/uu/cksum" }
comm = { optional=true, version="0.0.3", package="uu_comm", path="src/uu/comm" }
cp = { optional=true, version="0.0.3", package="uu_cp", path="src/uu/cp" }
csplit = { optional=true, version="0.0.3", package="uu_csplit", path="src/uu/csplit" }
cut = { optional=true, version="0.0.3", package="uu_cut", path="src/uu/cut" }
date = { optional=true, version="0.0.3", package="uu_date", path="src/uu/date" }
df = { optional=true, version="0.0.3", package="uu_df", path="src/uu/df" }
dircolors= { optional=true, version="0.0.3", package="uu_dircolors", path="src/uu/dircolors" }
dirname = { optional=true, version="0.0.3", package="uu_dirname", path="src/uu/dirname" }
du = { optional=true, version="0.0.3", package="uu_du", path="src/uu/du" }
echo = { optional=true, version="0.0.3", package="uu_echo", path="src/uu/echo" }
env = { optional=true, version="0.0.3", package="uu_env", path="src/uu/env" }
expand = { optional=true, version="0.0.3", package="uu_expand", path="src/uu/expand" }
expr = { optional=true, version="0.0.3", package="uu_expr", path="src/uu/expr" }
factor = { optional=true, version="0.0.3", package="uu_factor", path="src/uu/factor" }
false = { optional=true, version="0.0.3", package="uu_false", path="src/uu/false" }
fmt = { optional=true, version="0.0.3", package="uu_fmt", path="src/uu/fmt" }
fold = { optional=true, version="0.0.3", package="uu_fold", path="src/uu/fold" }
groups = { optional=true, version="0.0.3", package="uu_groups", path="src/uu/groups" }
hashsum = { optional=true, version="0.0.3", package="uu_hashsum", path="src/uu/hashsum" }
head = { optional=true, version="0.0.3", package="uu_head", path="src/uu/head" }
hostid = { optional=true, version="0.0.3", package="uu_hostid", path="src/uu/hostid" }
hostname = { optional=true, version="0.0.3", package="uu_hostname", path="src/uu/hostname" }
id = { optional=true, version="0.0.3", package="uu_id", path="src/uu/id" }
install = { optional=true, version="0.0.3", package="uu_install", path="src/uu/install" }
join = { optional=true, version="0.0.3", package="uu_join", path="src/uu/join" }
kill = { optional=true, version="0.0.3", package="uu_kill", path="src/uu/kill" }
link = { optional=true, version="0.0.3", package="uu_link", path="src/uu/link" }
ln = { optional=true, version="0.0.3", package="uu_ln", path="src/uu/ln" }
ls = { optional=true, version="0.0.3", package="uu_ls", path="src/uu/ls" }
logname = { optional=true, version="0.0.3", package="uu_logname", path="src/uu/logname" }
mkdir = { optional=true, version="0.0.3", package="uu_mkdir", path="src/uu/mkdir" }
mkfifo = { optional=true, version="0.0.3", package="uu_mkfifo", path="src/uu/mkfifo" }
mknod = { optional=true, version="0.0.3", package="uu_mknod", path="src/uu/mknod" }
mktemp = { optional=true, version="0.0.3", package="uu_mktemp", path="src/uu/mktemp" }
more = { optional=true, version="0.0.3", package="uu_more", path="src/uu/more" }
mv = { optional=true, version="0.0.3", package="uu_mv", path="src/uu/mv" }
nice = { optional=true, version="0.0.3", package="uu_nice", path="src/uu/nice" }
nl = { optional=true, version="0.0.3", package="uu_nl", path="src/uu/nl" }
nohup = { optional=true, version="0.0.3", package="uu_nohup", path="src/uu/nohup" }
nproc = { optional=true, version="0.0.3", package="uu_nproc", path="src/uu/nproc" }
numfmt = { optional=true, version="0.0.3", package="uu_numfmt", path="src/uu/numfmt" }
od = { optional=true, version="0.0.3", package="uu_od", path="src/uu/od" }
paste = { optional=true, version="0.0.3", package="uu_paste", path="src/uu/paste" }
pathchk = { optional=true, version="0.0.3", package="uu_pathchk", path="src/uu/pathchk" }
pinky = { optional=true, version="0.0.3", package="uu_pinky", path="src/uu/pinky" }
printenv = { optional=true, version="0.0.3", package="uu_printenv", path="src/uu/printenv" }
printf = { optional=true, version="0.0.3", package="uu_printf", path="src/uu/printf" }
ptx = { optional=true, version="0.0.3", package="uu_ptx", path="src/uu/ptx" }
pwd = { optional=true, version="0.0.3", package="uu_pwd", path="src/uu/pwd" }
readlink = { optional=true, version="0.0.3", package="uu_readlink", path="src/uu/readlink" }
realpath = { optional=true, version="0.0.3", package="uu_realpath", path="src/uu/realpath" }
relpath = { optional=true, version="0.0.3", package="uu_relpath", path="src/uu/relpath" }
rm = { optional=true, version="0.0.3", package="uu_rm", path="src/uu/rm" }
rmdir = { optional=true, version="0.0.3", package="uu_rmdir", path="src/uu/rmdir" }
seq = { optional=true, version="0.0.3", package="uu_seq", path="src/uu/seq" }
shred = { optional=true, version="0.0.3", package="uu_shred", path="src/uu/shred" }
shuf = { optional=true, version="0.0.3", package="uu_shuf", path="src/uu/shuf" }
sleep = { optional=true, version="0.0.3", package="uu_sleep", path="src/uu/sleep" }
sort = { optional=true, version="0.0.3", package="uu_sort", path="src/uu/sort" }
split = { optional=true, version="0.0.3", package="uu_split", path="src/uu/split" }
stat = { optional=true, version="0.0.3", package="uu_stat", path="src/uu/stat" }
stdbuf = { optional=true, version="0.0.3", package="uu_stdbuf", path="src/uu/stdbuf" }
sum = { optional=true, version="0.0.3", package="uu_sum", path="src/uu/sum" }
sync = { optional=true, version="0.0.3", package="uu_sync", path="src/uu/sync" }
tac = { optional=true, version="0.0.3", package="uu_tac", path="src/uu/tac" }
tail = { optional=true, version="0.0.3", package="uu_tail", path="src/uu/tail" }
tee = { optional=true, version="0.0.3", package="uu_tee", path="src/uu/tee" }
timeout = { optional=true, version="0.0.3", package="uu_timeout", path="src/uu/timeout" }
touch = { optional=true, version="0.0.3", package="uu_touch", path="src/uu/touch" }
tr = { optional=true, version="0.0.3", package="uu_tr", path="src/uu/tr" }
true = { optional=true, version="0.0.3", package="uu_true", path="src/uu/true" }
truncate = { optional=true, version="0.0.3", package="uu_truncate", path="src/uu/truncate" }
tsort = { optional=true, version="0.0.3", package="uu_tsort", path="src/uu/tsort" }
tty = { optional=true, version="0.0.3", package="uu_tty", path="src/uu/tty" }
uname = { optional=true, version="0.0.3", package="uu_uname", path="src/uu/uname" }
unexpand = { optional=true, version="0.0.3", package="uu_unexpand", path="src/uu/unexpand" }
uniq = { optional=true, version="0.0.3", package="uu_uniq", path="src/uu/uniq" }
unlink = { optional=true, version="0.0.3", package="uu_unlink", path="src/uu/unlink" }
uptime = { optional=true, version="0.0.3", package="uu_uptime", path="src/uu/uptime" }
users = { optional=true, version="0.0.3", package="uu_users", path="src/uu/users" }
wc = { optional=true, version="0.0.3", package="uu_wc", path="src/uu/wc" }
who = { optional=true, version="0.0.3", package="uu_who", path="src/uu/who" }
whoami = { optional=true, version="0.0.3", package="uu_whoami", path="src/uu/whoami" }
yes = { optional=true, version="0.0.3", package="uu_yes", path="src/uu/yes" }
arch = { optional=true, version="0.0.4", package="uu_arch", path="src/uu/arch" }
base32 = { optional=true, version="0.0.4", package="uu_base32", path="src/uu/base32" }
base64 = { optional=true, version="0.0.4", package="uu_base64", path="src/uu/base64" }
basename = { optional=true, version="0.0.4", package="uu_basename", path="src/uu/basename" }
cat = { optional=true, version="0.0.4", package="uu_cat", path="src/uu/cat" }
chgrp = { optional=true, version="0.0.4", package="uu_chgrp", path="src/uu/chgrp" }
chmod = { optional=true, version="0.0.4", package="uu_chmod", path="src/uu/chmod" }
chown = { optional=true, version="0.0.4", package="uu_chown", path="src/uu/chown" }
chroot = { optional=true, version="0.0.4", package="uu_chroot", path="src/uu/chroot" }
cksum = { optional=true, version="0.0.4", package="uu_cksum", path="src/uu/cksum" }
comm = { optional=true, version="0.0.4", package="uu_comm", path="src/uu/comm" }
cp = { optional=true, version="0.0.4", package="uu_cp", path="src/uu/cp" }
csplit = { optional=true, version="0.0.4", package="uu_csplit", path="src/uu/csplit" }
cut = { optional=true, version="0.0.4", package="uu_cut", path="src/uu/cut" }
date = { optional=true, version="0.0.4", package="uu_date", path="src/uu/date" }
df = { optional=true, version="0.0.4", package="uu_df", path="src/uu/df" }
dircolors= { optional=true, version="0.0.4", package="uu_dircolors", path="src/uu/dircolors" }
dirname = { optional=true, version="0.0.4", package="uu_dirname", path="src/uu/dirname" }
du = { optional=true, version="0.0.4", package="uu_du", path="src/uu/du" }
echo = { optional=true, version="0.0.4", package="uu_echo", path="src/uu/echo" }
env = { optional=true, version="0.0.4", package="uu_env", path="src/uu/env" }
expand = { optional=true, version="0.0.4", package="uu_expand", path="src/uu/expand" }
expr = { optional=true, version="0.0.4", package="uu_expr", path="src/uu/expr" }
factor = { optional=true, version="0.0.4", package="uu_factor", path="src/uu/factor" }
false = { optional=true, version="0.0.4", package="uu_false", path="src/uu/false" }
fmt = { optional=true, version="0.0.4", package="uu_fmt", path="src/uu/fmt" }
fold = { optional=true, version="0.0.4", package="uu_fold", path="src/uu/fold" }
groups = { optional=true, version="0.0.4", package="uu_groups", path="src/uu/groups" }
hashsum = { optional=true, version="0.0.4", package="uu_hashsum", path="src/uu/hashsum" }
head = { optional=true, version="0.0.4", package="uu_head", path="src/uu/head" }
hostid = { optional=true, version="0.0.4", package="uu_hostid", path="src/uu/hostid" }
hostname = { optional=true, version="0.0.4", package="uu_hostname", path="src/uu/hostname" }
id = { optional=true, version="0.0.4", package="uu_id", path="src/uu/id" }
install = { optional=true, version="0.0.4", package="uu_install", path="src/uu/install" }
join = { optional=true, version="0.0.4", package="uu_join", path="src/uu/join" }
kill = { optional=true, version="0.0.4", package="uu_kill", path="src/uu/kill" }
link = { optional=true, version="0.0.4", package="uu_link", path="src/uu/link" }
ln = { optional=true, version="0.0.4", package="uu_ln", path="src/uu/ln" }
ls = { optional=true, version="0.0.4", package="uu_ls", path="src/uu/ls" }
logname = { optional=true, version="0.0.4", package="uu_logname", path="src/uu/logname" }
mkdir = { optional=true, version="0.0.4", package="uu_mkdir", path="src/uu/mkdir" }
mkfifo = { optional=true, version="0.0.4", package="uu_mkfifo", path="src/uu/mkfifo" }
mknod = { optional=true, version="0.0.4", package="uu_mknod", path="src/uu/mknod" }
mktemp = { optional=true, version="0.0.4", package="uu_mktemp", path="src/uu/mktemp" }
more = { optional=true, version="0.0.4", package="uu_more", path="src/uu/more" }
mv = { optional=true, version="0.0.4", package="uu_mv", path="src/uu/mv" }
nice = { optional=true, version="0.0.4", package="uu_nice", path="src/uu/nice" }
nl = { optional=true, version="0.0.4", package="uu_nl", path="src/uu/nl" }
nohup = { optional=true, version="0.0.4", package="uu_nohup", path="src/uu/nohup" }
nproc = { optional=true, version="0.0.4", package="uu_nproc", path="src/uu/nproc" }
numfmt = { optional=true, version="0.0.4", package="uu_numfmt", path="src/uu/numfmt" }
od = { optional=true, version="0.0.4", package="uu_od", path="src/uu/od" }
paste = { optional=true, version="0.0.4", package="uu_paste", path="src/uu/paste" }
pathchk = { optional=true, version="0.0.4", package="uu_pathchk", path="src/uu/pathchk" }
pinky = { optional=true, version="0.0.4", package="uu_pinky", path="src/uu/pinky" }
printenv = { optional=true, version="0.0.4", package="uu_printenv", path="src/uu/printenv" }
printf = { optional=true, version="0.0.4", package="uu_printf", path="src/uu/printf" }
ptx = { optional=true, version="0.0.4", package="uu_ptx", path="src/uu/ptx" }
pwd = { optional=true, version="0.0.4", package="uu_pwd", path="src/uu/pwd" }
readlink = { optional=true, version="0.0.4", package="uu_readlink", path="src/uu/readlink" }
realpath = { optional=true, version="0.0.4", package="uu_realpath", path="src/uu/realpath" }
relpath = { optional=true, version="0.0.4", package="uu_relpath", path="src/uu/relpath" }
rm = { optional=true, version="0.0.4", package="uu_rm", path="src/uu/rm" }
rmdir = { optional=true, version="0.0.4", package="uu_rmdir", path="src/uu/rmdir" }
seq = { optional=true, version="0.0.4", package="uu_seq", path="src/uu/seq" }
shred = { optional=true, version="0.0.4", package="uu_shred", path="src/uu/shred" }
shuf = { optional=true, version="0.0.4", package="uu_shuf", path="src/uu/shuf" }
sleep = { optional=true, version="0.0.4", package="uu_sleep", path="src/uu/sleep" }
sort = { optional=true, version="0.0.4", package="uu_sort", path="src/uu/sort" }
split = { optional=true, version="0.0.4", package="uu_split", path="src/uu/split" }
stat = { optional=true, version="0.0.4", package="uu_stat", path="src/uu/stat" }
stdbuf = { optional=true, version="0.0.4", package="uu_stdbuf", path="src/uu/stdbuf" }
sum = { optional=true, version="0.0.4", package="uu_sum", path="src/uu/sum" }
sync = { optional=true, version="0.0.4", package="uu_sync", path="src/uu/sync" }
tac = { optional=true, version="0.0.4", package="uu_tac", path="src/uu/tac" }
tail = { optional=true, version="0.0.4", package="uu_tail", path="src/uu/tail" }
tee = { optional=true, version="0.0.4", package="uu_tee", path="src/uu/tee" }
timeout = { optional=true, version="0.0.4", package="uu_timeout", path="src/uu/timeout" }
touch = { optional=true, version="0.0.4", package="uu_touch", path="src/uu/touch" }
tr = { optional=true, version="0.0.4", package="uu_tr", path="src/uu/tr" }
true = { optional=true, version="0.0.4", package="uu_true", path="src/uu/true" }
truncate = { optional=true, version="0.0.4", package="uu_truncate", path="src/uu/truncate" }
tsort = { optional=true, version="0.0.4", package="uu_tsort", path="src/uu/tsort" }
tty = { optional=true, version="0.0.4", package="uu_tty", path="src/uu/tty" }
uname = { optional=true, version="0.0.4", package="uu_uname", path="src/uu/uname" }
unexpand = { optional=true, version="0.0.4", package="uu_unexpand", path="src/uu/unexpand" }
uniq = { optional=true, version="0.0.4", package="uu_uniq", path="src/uu/uniq" }
unlink = { optional=true, version="0.0.4", package="uu_unlink", path="src/uu/unlink" }
uptime = { optional=true, version="0.0.4", package="uu_uptime", path="src/uu/uptime" }
users = { optional=true, version="0.0.4", package="uu_users", path="src/uu/users" }
wc = { optional=true, version="0.0.4", package="uu_wc", path="src/uu/wc" }
who = { optional=true, version="0.0.4", package="uu_who", path="src/uu/who" }
whoami = { optional=true, version="0.0.4", package="uu_whoami", path="src/uu/whoami" }
yes = { optional=true, version="0.0.4", package="uu_yes", path="src/uu/yes" }
#
# * pinned transitive dependencies
pin_cc = { version="1.0.61, < 1.0.62", package="cc" } ## cc v1.0.62 has compiler errors for MinRustV v1.32.0, requires 1.34 (for `std::str::split_ascii_whitespace()`)
@ -346,7 +346,7 @@ sha1 = { version="0.6", features=["std"] }
tempfile = "= 3.1.0"
time = "0.1"
unindent = "0.1"
uucore = { version=">=0.0.6", package="uucore", path="src/uucore", features=["entries"] }
uucore = { version=">=0.0.7", package="uucore", path="src/uucore", features=["entries"] }
[target.'cfg(unix)'.dev-dependencies]
rust-users = { version="0.10", package="users" }

View file

@ -41,7 +41,7 @@ PKG_BUILDDIR := $(BUILDDIR)/deps
DOCSDIR := $(BASEDIR)/docs
BUSYBOX_ROOT := $(BASEDIR)/tmp
BUSYBOX_VER := 1.24.1
BUSYBOX_VER := 1.32.1
BUSYBOX_SRC := $(BUSYBOX_ROOT)/busybox-$(BUSYBOX_VER)
# Possible programs
@ -228,7 +228,7 @@ endif
define TEST_BUSYBOX
test_busybox_$(1):
(cd $(BUSYBOX_SRC)/testsuite && bindir=$(BUILDDIR) ./runtest $(RUNTEST_ARGS) $(1) )
-(cd $(BUSYBOX_SRC)/testsuite && bindir=$(BUILDDIR) ./runtest $(RUNTEST_ARGS) $(1))
endef
# Output names
@ -276,9 +276,11 @@ $(BUILDDIR)/.config: $(BASEDIR)/.busybox-config
# Test under the busybox testsuite
$(BUILDDIR)/busybox: busybox-src build-uutils $(BUILDDIR)/.config
cp $(BUILDDIR)/uutils $(BUILDDIR)/busybox; \
cp $(BUILDDIR)/coreutils $(BUILDDIR)/busybox; \
chmod +x $@;
prepare-busytest: $(BUILDDIR)/busybox
ifeq ($(EXES),)
busytest:
else

View file

@ -1,14 +1,13 @@
uutils coreutils
================
[![Crates.io](https://img.shields.io/crates/v/coreutils.svg)](https://crates.io/crates/coreutils)
[![Discord](https://img.shields.io/badge/discord-join-7289DA.svg?logo=discord&longCache=true&style=flat)](https://discord.gg/wQVJbvJ)
[![License](http://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/uutils/coreutils/blob/master/LICENSE)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fuutils%2Fcoreutils.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fuutils%2Fcoreutils?ref=badge_shield)
[![LOC](https://tokei.rs/b1/github/uutils/coreutils?category=code)](https://github.com/Aaronepower/tokei)
[![dependency status](https://deps.rs/repo/github/uutils/coreutils/status.svg)](https://deps.rs/repo/github/uutils/coreutils)
[![Build Status](https://api.travis-ci.org/uutils/coreutils.svg?branch=master)](https://travis-ci.org/uutils/coreutils)
[![Build Status (Windows)](https://ci.appveyor.com/api/projects/status/787ltcxgy86r20le?svg=true)](https://ci.appveyor.com/project/Arcterus/coreutils)
[![Build Status (FreeBSD)](https://api.cirrus-ci.com/github/uutils/coreutils.svg)](https://cirrus-ci.com/github/uutils/coreutils/master)
[![codecov](https://codecov.io/gh/uutils/coreutils/branch/master/graph/badge.svg)](https://codecov.io/gh/uutils/coreutils)
@ -115,7 +114,7 @@ Installation Instructions
Likewise, installing can simply be done using:
```bash
$ cargo install
$ cargo install --path .
```
This command will install uutils into Cargo's *bin* folder (*e.g.* `$HOME/.cargo/bin`).
@ -380,4 +379,4 @@ License
uutils is licensed under the MIT License - see the `LICENSE` file for details
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fuutils%2Fcoreutils.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fuutils%2Fcoreutils?ref=badge_large)
GNU Coreutils is licensed under the GPL 3.0 or later.

View file

@ -19,7 +19,7 @@ include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));
fn usage<T>(utils: &UtilityMap<T>, name: &str) {
println!("{} {} (multi-call binary)\n", name, VERSION);
println!("Usage: {} [function [arguments...]]\n", name);
println!("Currently defined functions/utilities:\n");
println!("Currently defined functions:\n");
#[allow(clippy::map_clone)]
let mut utils: Vec<&str> = utils.keys().map(|&s| s).collect();
utils.sort_unstable();

View file

@ -1,6 +1,6 @@
[package]
name = "uu_arch"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "arch ~ (uutils) display machine architecture"
@ -15,8 +15,8 @@ edition = "2018"
path = "src/arch.rs"
[dependencies]
platform-info = "0.0.1"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
platform-info = "0.1"
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_base32"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "base32 ~ (uutils) decode/encode input (base32-encoding)"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/base32.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features = ["encoding"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features = ["encoding"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_base64"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "base64 ~ (uutils) decode/encode input (base64-encoding)"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/base64.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features = ["encoding"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features = ["encoding"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_basename"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "basename ~ (uutils) display PATHNAME with leading directory components removed"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/basename.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_cat"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "cat ~ (uutils) concatenate and display input"
@ -16,7 +16,7 @@ path = "src/cat.rs"
[dependencies]
quick-error = "1.2.3"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[target.'cfg(unix)'.dependencies]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_chgrp"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "chgrp ~ (uutils) change the group ownership of FILE"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/chgrp.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
walkdir = "2.2"

View file

@ -1,6 +1,6 @@
[package]
name = "uu_chmod"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "chmod ~ (uutils) change mode of FILE"
@ -16,7 +16,7 @@ path = "src/chmod.rs"
[dependencies]
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs", "mode"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs", "mode"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
walkdir = "2.2"

View file

@ -1,6 +1,6 @@
[package]
name = "uu_chown"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "chown ~ (uutils) change the ownership of FILE"
@ -17,7 +17,7 @@ path = "src/chown.rs"
[dependencies]
clap = "2.33"
glob = "0.3.0"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries", "fs", "perms"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
walkdir = "2.2"

View file

@ -27,20 +27,30 @@ use std::path::Path;
static ABOUT: &str = "change file owner and group";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static OPT_CHANGES: &str = "changes";
static OPT_DEREFERENCE: &str = "dereference";
static OPT_NO_DEREFERENCE: &str = "no-dereference";
static OPT_FROM: &str = "from";
static OPT_PRESERVE_ROOT: &str = "preserve-root";
static OPT_NO_PRESERVE_ROOT: &str = "no-preserve-root";
static OPT_QUIET: &str = "quiet";
static OPT_RECURSIVE: &str = "recursive";
static OPT_REFERENCE: &str = "reference";
static OPT_SILENT: &str = "silent";
static OPT_TRAVERSE: &str = "H";
static OPT_NO_TRAVERSE: &str = "P";
static OPT_TRAVERSE_EVERY: &str = "L";
static OPT_VERBOSE: &str = "verbose";
pub mod options {
pub mod verbosity {
pub static CHANGES: &str = "changes";
pub static QUIET: &str = "quiet";
pub static SILENT: &str = "silent";
pub static VERBOSE: &str = "verbose";
}
pub mod preserve_root {
pub static PRESERVE: &str = "preserve-root";
pub static NO_PRESERVE: &str = "no-preserve-root";
}
pub mod dereference {
pub static DEREFERENCE: &str = "dereference";
pub static NO_DEREFERENCE: &str = "no-dereference";
}
pub static FROM: &str = "from";
pub static RECURSIVE: &str = "recursive";
pub mod traverse {
pub static TRAVERSE: &str = "H";
pub static NO_TRAVERSE: &str = "P";
pub static EVERY: &str = "L";
}
pub static REFERENCE: &str = "reference";
}
static ARG_OWNER: &str = "owner";
static ARG_FILES: &str = "files";
@ -66,80 +76,80 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.about(ABOUT)
.usage(&usage[..])
.arg(
Arg::with_name(OPT_CHANGES)
Arg::with_name(options::verbosity::CHANGES)
.short("c")
.long(OPT_CHANGES)
.long(options::verbosity::CHANGES)
.help("like verbose but report only when a change is made"),
)
.arg(Arg::with_name(OPT_DEREFERENCE).long(OPT_DEREFERENCE).help(
.arg(Arg::with_name(options::dereference::DEREFERENCE).long(options::dereference::DEREFERENCE).help(
"affect the referent of each symbolic link (this is the default), rather than the symbolic link itself",
))
.arg(
Arg::with_name(OPT_NO_DEREFERENCE)
Arg::with_name(options::dereference::NO_DEREFERENCE)
.short("h")
.long(OPT_NO_DEREFERENCE)
.long(options::dereference::NO_DEREFERENCE)
.help(
"affect symbolic links instead of any referenced file (useful only on systems that can change the ownership of a symlink)",
),
)
.arg(
Arg::with_name(OPT_FROM)
.long(OPT_FROM)
Arg::with_name(options::FROM)
.long(options::FROM)
.help(
"change the owner and/or group of each file only if its current owner and/or group match those specified here. Either may be omitted, in which case a match is not required for the omitted attribute",
)
.value_name("CURRENT_OWNER:CURRENT_GROUP"),
)
.arg(
Arg::with_name(OPT_PRESERVE_ROOT)
.long(OPT_PRESERVE_ROOT)
Arg::with_name(options::preserve_root::PRESERVE)
.long(options::preserve_root::PRESERVE)
.help("fail to operate recursively on '/'"),
)
.arg(
Arg::with_name(OPT_NO_PRESERVE_ROOT)
.long(OPT_NO_PRESERVE_ROOT)
Arg::with_name(options::preserve_root::NO_PRESERVE)
.long(options::preserve_root::NO_PRESERVE)
.help("do not treat '/' specially (the default)"),
)
.arg(
Arg::with_name(OPT_QUIET)
.long(OPT_QUIET)
Arg::with_name(options::verbosity::QUIET)
.long(options::verbosity::QUIET)
.help("suppress most error messages"),
)
.arg(
Arg::with_name(OPT_RECURSIVE)
Arg::with_name(options::RECURSIVE)
.short("R")
.long(OPT_RECURSIVE)
.long(options::RECURSIVE)
.help("operate on files and directories recursively"),
)
.arg(
Arg::with_name(OPT_REFERENCE)
.long(OPT_REFERENCE)
Arg::with_name(options::REFERENCE)
.long(options::REFERENCE)
.help("use RFILE's owner and group rather than specifying OWNER:GROUP values")
.value_name("RFILE")
.min_values(1),
)
.arg(Arg::with_name(OPT_SILENT).short("f").long(OPT_SILENT))
.arg(Arg::with_name(options::verbosity::SILENT).short("f").long(options::verbosity::SILENT))
.arg(
Arg::with_name(OPT_TRAVERSE)
.short(OPT_TRAVERSE)
Arg::with_name(options::traverse::TRAVERSE)
.short(options::traverse::TRAVERSE)
.help("if a command line argument is a symbolic link to a directory, traverse it")
.overrides_with_all(&[OPT_TRAVERSE_EVERY, OPT_NO_TRAVERSE]),
.overrides_with_all(&[options::traverse::EVERY, options::traverse::NO_TRAVERSE]),
)
.arg(
Arg::with_name(OPT_TRAVERSE_EVERY)
.short(OPT_TRAVERSE_EVERY)
Arg::with_name(options::traverse::EVERY)
.short(options::traverse::EVERY)
.help("traverse every symbolic link to a directory encountered")
.overrides_with_all(&[OPT_TRAVERSE, OPT_NO_TRAVERSE]),
.overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::NO_TRAVERSE]),
)
.arg(
Arg::with_name(OPT_NO_TRAVERSE)
.short(OPT_NO_TRAVERSE)
Arg::with_name(options::traverse::NO_TRAVERSE)
.short(options::traverse::NO_TRAVERSE)
.help("do not traverse any symbolic links (default)")
.overrides_with_all(&[OPT_TRAVERSE, OPT_TRAVERSE_EVERY]),
.overrides_with_all(&[options::traverse::TRAVERSE, options::traverse::EVERY]),
)
.arg(
Arg::with_name(OPT_VERBOSE)
.long(OPT_VERBOSE)
Arg::with_name(options::verbosity::VERBOSE)
.long(options::verbosity::VERBOSE)
.help("output a diagnostic for every file processed"),
)
.arg(
@ -166,23 +176,23 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.map(|v| v.map(ToString::to_string).collect())
.unwrap_or_default();
let preserve_root = matches.is_present(OPT_PRESERVE_ROOT);
let preserve_root = matches.is_present(options::preserve_root::PRESERVE);
let mut derefer = if matches.is_present(OPT_NO_DEREFERENCE) {
let mut derefer = if matches.is_present(options::dereference::NO_DEREFERENCE) {
1
} else {
0
};
let mut bit_flag = if matches.is_present(OPT_TRAVERSE) {
let mut bit_flag = if matches.is_present(options::traverse::TRAVERSE) {
FTS_COMFOLLOW | FTS_PHYSICAL
} else if matches.is_present(OPT_TRAVERSE_EVERY) {
} else if matches.is_present(options::traverse::EVERY) {
FTS_LOGICAL
} else {
FTS_PHYSICAL
};
let recursive = matches.is_present(OPT_RECURSIVE);
let recursive = matches.is_present(options::RECURSIVE);
if recursive {
if bit_flag == FTS_PHYSICAL {
if derefer == 1 {
@ -195,17 +205,19 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
bit_flag = FTS_PHYSICAL;
}
let verbosity = if matches.is_present(OPT_CHANGES) {
let verbosity = if matches.is_present(options::verbosity::CHANGES) {
Verbosity::Changes
} else if matches.is_present(OPT_SILENT) || matches.is_present(OPT_QUIET) {
} else if matches.is_present(options::verbosity::SILENT)
|| matches.is_present(options::verbosity::QUIET)
{
Verbosity::Silent
} else if matches.is_present(OPT_VERBOSE) {
} else if matches.is_present(options::verbosity::VERBOSE) {
Verbosity::Verbose
} else {
Verbosity::Normal
};
let filter = if let Some(spec) = matches.value_of(OPT_FROM) {
let filter = if let Some(spec) = matches.value_of(options::FROM) {
match parse_spec(&spec) {
Ok((Some(uid), None)) => IfFrom::User(uid),
Ok((None, Some(gid))) => IfFrom::Group(gid),
@ -222,7 +234,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let dest_uid: Option<u32>;
let dest_gid: Option<u32>;
if let Some(file) = matches.value_of(OPT_REFERENCE) {
if let Some(file) = matches.value_of(options::REFERENCE) {
match fs::metadata(&file) {
Ok(meta) => {
dest_gid = Some(meta.gid());

View file

@ -1,6 +1,6 @@
[package]
name = "uu_chroot"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "chroot ~ (uutils) run COMMAND under a new root directory"
@ -16,7 +16,7 @@ path = "src/chroot.rs"
[dependencies]
getopts = "0.2.18"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["entries"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -164,7 +164,7 @@ fn set_main_group(group: &str) {
}
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
unsafe { setgroups(groups.len() as libc::c_int, groups.as_ptr()) }
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_cksum"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "cksum ~ (uutils) display CRC and size of input"
@ -16,7 +16,7 @@ path = "src/cksum.rs"
[dependencies]
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_comm"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "comm ~ (uutils) compare sorted inputs"
@ -17,7 +17,7 @@ path = "src/comm.rs"
[dependencies]
getopts = "0.2.18"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_cp"
version = "0.0.3"
version = "0.0.4"
authors = [
"Jordy Dickinson <jordy.dickinson@gmail.com>",
"Joshua S. Miller <jsmiller@uchicago.edu>",
@ -23,7 +23,7 @@ clap = "2.33"
filetime = "0.2"
libc = "0.2.85"
quick-error = "1.2.3"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
walkdir = "2.2"

View file

@ -207,6 +207,7 @@ pub struct Options {
one_file_system: bool,
overwrite: OverwriteMode,
parents: bool,
strip_trailing_slashes: bool,
reflink: bool,
reflink_mode: ReflinkMode,
preserve_attributes: Vec<Attribute>,
@ -248,6 +249,7 @@ static OPT_NO_DEREFERENCE_PRESERVE_LINKS: &str = "no-dereference-preserve-linkgs
static OPT_NO_PRESERVE: &str = "no-preserve";
static OPT_NO_TARGET_DIRECTORY: &str = "no-target-directory";
static OPT_ONE_FILE_SYSTEM: &str = "one-file-system";
static OPT_PARENT: &str = "parent";
static OPT_PARENTS: &str = "parents";
static OPT_PATHS: &str = "paths";
static OPT_PRESERVE: &str = "preserve";
@ -333,6 +335,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.arg(Arg::with_name(OPT_RECURSIVE_ALIAS)
.short("R")
.help("same as -r"))
.arg(Arg::with_name(OPT_STRIP_TRAILING_SLASHES)
.long(OPT_STRIP_TRAILING_SLASHES)
.help("remove any trailing slashes from each SOURCE argument"))
.arg(Arg::with_name(OPT_VERBOSE)
.short("v")
.long(OPT_VERBOSE)
@ -403,6 +408,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.value_name("ATTR_LIST")
.conflicts_with_all(&[OPT_PRESERVE_DEFAULT_ATTRIBUTES, OPT_PRESERVE, OPT_ARCHIVE])
.help("don't preserve the specified attributes"))
.arg(Arg::with_name(OPT_PARENTS)
.long(OPT_PARENTS)
.alias(OPT_PARENT)
.help("use full source file name under DIRECTORY"))
.arg(Arg::with_name(OPT_NO_DEREFERENCE)
.short("-P")
.long(OPT_NO_DEREFERENCE)
@ -428,17 +437,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.long(OPT_COPY_CONTENTS)
.conflicts_with(OPT_ATTRIBUTES_ONLY)
.help("NotImplemented: copy contents of special files when recursive"))
.arg(Arg::with_name(OPT_PARENTS)
.long(OPT_PARENTS)
.help("NotImplemented: use full source file name under DIRECTORY"))
.arg(Arg::with_name(OPT_SPARSE)
.long(OPT_SPARSE)
.takes_value(true)
.value_name("WHEN")
.help("NotImplemented: control creation of sparse files. See below"))
.arg(Arg::with_name(OPT_STRIP_TRAILING_SLASHES)
.long(OPT_STRIP_TRAILING_SLASHES)
.help("NotImplemented: remove any trailing slashes from each SOURCE argument"))
.arg(Arg::with_name(OPT_ONE_FILE_SYSTEM)
.short("x")
.long(OPT_ONE_FILE_SYSTEM)
@ -559,9 +562,7 @@ impl Options {
fn from_matches(matches: &ArgMatches) -> CopyResult<Options> {
let not_implemented_opts = vec![
OPT_COPY_CONTENTS,
OPT_PARENTS,
OPT_SPARSE,
OPT_STRIP_TRAILING_SLASHES,
OPT_ONE_FILE_SYSTEM,
OPT_CONTEXT,
#[cfg(windows)]
@ -629,6 +630,7 @@ impl Options {
backup_suffix: matches.value_of(OPT_SUFFIX).unwrap().to_string(),
update: matches.is_present(OPT_UPDATE),
verbose: matches.is_present(OPT_VERBOSE),
strip_trailing_slashes: matches.is_present(OPT_STRIP_TRAILING_SLASHES),
reflink: matches.is_present(OPT_REFLINK),
reflink_mode: {
if let Some(reflink) = matches.value_of(OPT_REFLINK) {
@ -686,7 +688,7 @@ fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec<S
return Err(format!("extra operand {:?}", paths[2]).into());
}
let (sources, target) = match options.target_dir {
let (mut sources, target) = match options.target_dir {
Some(ref target) => {
// All path args are sources, and the target dir was
// specified separately
@ -700,6 +702,12 @@ fn parse_path_args(path_args: &[String], options: &Options) -> CopyResult<(Vec<S
}
};
if options.strip_trailing_slashes {
for source in sources.iter_mut() {
*source = source.components().as_path().to_owned()
}
}
Ok((sources, target))
}
@ -843,9 +851,17 @@ fn construct_dest_path(
.into());
}
if options.parents && !target.is_dir() {
return Err("with --parents, the destination must be a directory".into());
}
Ok(match *target_type {
TargetType::Directory => {
let root = source_path.parent().unwrap_or(source_path);
let root = if options.parents {
Path::new("")
} else {
source_path.parent().unwrap_or(source_path)
};
localize_to_target(root, source_path, target)?
}
TargetType::File => target.to_path_buf(),
@ -938,7 +954,7 @@ fn copy_directory(root: &Path, target: &Target, options: &Options) -> CopyResult
Some(parent) => {
#[cfg(windows)]
{
// On Windows, some pathes are starting with \\?
// On Windows, some paths are starting with \\?
// but not always, so, make sure that we are consistent for strip_prefix
// See https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file for more info
let parent_can = adjust_canonicalization(parent);
@ -1231,15 +1247,17 @@ fn copy_helper(source: &Path, dest: &Path, options: &Options) -> CopyResult<()>
dest.into()
};
symlink_file(&link, &dest, &*context_for(&link, &dest))?;
} else if source.to_string_lossy() == "/dev/null" {
/* workaround a limitation of fs::copy
* https://github.com/rust-lang/rust/issues/79390
*/
File::create(dest)?;
} else {
if source.to_string_lossy() == "/dev/null" {
/* workaround a limitation of fs::copy
* https://github.com/rust-lang/rust/issues/79390
*/
File::create(dest)?;
} else {
fs::copy(source, dest).context(&*context_for(source, dest))?;
if options.parents {
let parent = dest.parent().unwrap_or(dest);
fs::create_dir_all(parent)?;
}
fs::copy(source, dest).context(&*context_for(source, dest))?;
}
Ok(())

View file

@ -1,6 +1,6 @@
[package]
name = "uu_csplit"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "csplit ~ (uutils) Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output"
@ -19,7 +19,7 @@ getopts = "0.2.17"
thiserror = "1.0"
regex = "1.0.0"
glob = "0.2.11"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["entries", "fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries", "fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -344,7 +344,7 @@ impl<'a> SplitWriter<'a> {
///
/// In addition to errors reading/writing from/to a file, the following errors may be returned:
/// - if no line matched, an [`::CsplitError::MatchNotFound`].
/// - if there are not enough lines to accomodate the offset, an
/// - if there are not enough lines to accommodate the offset, an
/// [`::CsplitError::LineOutOfRange`].
fn do_to_match<I>(
&mut self,
@ -471,14 +471,14 @@ where
}
}
/// Rewind the iteration by outputing the buffer's content.
/// Rewind the iteration by outputting the buffer's content.
fn rewind_buffer(&mut self) {
self.rewind = true;
}
/// Shrink the buffer so that its length is equal to the set size, returning an iterator for
/// the elements that were too much.
fn shrink_buffer_to_size<'a>(&'a mut self) -> impl Iterator<Item = String> + 'a {
fn shrink_buffer_to_size(&mut self) -> impl Iterator<Item = String> + '_ {
let mut shrink_offset = 0;
if self.buffer.len() > self.size {
shrink_offset = self.buffer.len() - self.size;
@ -489,7 +489,7 @@ where
}
/// Drain the content of the buffer.
fn drain_buffer<'a>(&'a mut self) -> impl Iterator<Item = String> + 'a {
fn drain_buffer(&mut self) -> impl Iterator<Item = String> + '_ {
self.buffer.drain(..).map(|(_, line)| line.unwrap())
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_cut"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "cut ~ (uutils) display byte/field columns of input lines"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/cut.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -14,11 +14,10 @@ use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, Read, Stdout, Write};
use std::path::Path;
use self::ranges::Range;
use self::searcher::Searcher;
use uucore::ranges::Range;
mod buffer;
mod ranges;
mod searcher;
static SYNTAX: &str =
@ -125,7 +124,7 @@ enum Mode {
fn list_to_ranges(list: &str, complement: bool) -> Result<Vec<Range>, String> {
if complement {
Range::from_list(list).map(|r| ranges::complement(&r))
Range::from_list(list).map(|r| uucore::ranges::complement(&r))
} else {
Range::from_list(list)
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_date"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "date ~ (uutils) display or set the current time"
@ -17,7 +17,7 @@ path = "src/date.rs"
[dependencies]
chrono = "0.4.4"
clap = "2.33"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_df"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "df ~ (uutils) display file system information"
@ -18,7 +18,7 @@ path = "src/df.rs"
clap = "2.33"
libc = "0.2"
number_prefix = "0.4"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[target.'cfg(target_os = "windows")'.dependencies]

View file

@ -32,15 +32,15 @@ use std::ffi::CString;
#[cfg(unix)]
use std::mem;
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
use libc::c_int;
#[cfg(target_os = "macos")]
#[cfg(target_vendor = "apple")]
use libc::statfs;
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
use std::ffi::CStr;
#[cfg(any(target_os = "macos", target_os = "freebsd", target_os = "windows"))]
#[cfg(any(target_vendor = "apple", target_os = "freebsd", target_os = "windows"))]
use std::ptr;
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
use std::slice;
#[cfg(target_os = "freebsd")]
@ -137,7 +137,7 @@ struct MountInfo {
#[cfg(all(
target_os = "freebsd",
not(all(target_os = "macos", target_arch = "x86_64"))
not(all(target_vendor = "apple", target_arch = "x86_64"))
))]
#[repr(C)]
#[derive(Copy, Clone)]
@ -209,20 +209,20 @@ fn get_usage() -> String {
format!("{0} [OPTION]... [FILE]...", executable!())
}
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
#[cfg(any(target_os = "freebsd", target_vendor = "apple"))]
extern "C" {
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
#[cfg(all(target_vendor = "apple", target_arch = "x86_64"))]
#[link_name = "getmntinfo$INODE64"]
fn getmntinfo(mntbufp: *mut *mut statfs, flags: c_int) -> c_int;
#[cfg(any(
all(target_os = "freebsd"),
all(target_os = "macos", target_arch = "aarch64")
all(target_vendor = "apple", target_arch = "aarch64")
))]
fn getmntinfo(mntbufp: *mut *mut statfs, flags: c_int) -> c_int;
}
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
#[cfg(any(target_os = "freebsd", target_vendor = "apple"))]
impl From<statfs> for MountInfo {
fn from(statfs: statfs) -> Self {
let mut info = MountInfo {
@ -585,7 +585,7 @@ fn read_fs_list() -> Vec<MountInfo> {
})
.collect::<Vec<_>>()
}
#[cfg(any(target_os = "freebsd", target_os = "macos"))]
#[cfg(any(target_os = "freebsd", target_vendor = "apple"))]
{
let mut mptr: *mut statfs = ptr::null_mut();
let len = unsafe { getmntinfo(&mut mptr, 1 as c_int) };

View file

@ -1,6 +1,6 @@
[package]
name = "uu_dircolors"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "dircolors ~ (uutils) display commands to set LS_COLORS"
@ -16,7 +16,7 @@ path = "src/dircolors.rs"
[dependencies]
glob = "0.3.0"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_dirname"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "dirname ~ (uutils) display parent directory of PATHNAME"
@ -16,7 +16,7 @@ path = "src/dirname.rs"
[dependencies]
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_du"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "du ~ (uutils) display disk usage"
@ -16,7 +16,7 @@ path = "src/du.rs"
[dependencies]
time = "0.1.40"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_echo"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "echo ~ (uutils) display TEXT"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/echo.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_env"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND"
@ -18,7 +18,7 @@ path = "src/env.rs"
clap = "2.33"
libc = "0.2.42"
rust-ini = "0.13.0"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_expand"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "expand ~ (uutils) convert input tabs to spaces"
@ -15,9 +15,9 @@ edition = "2018"
path = "src/expand.rs"
[dependencies]
getopts = "0.2.18"
clap = "2.33"
unicode-width = "0.1.5"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -12,19 +12,32 @@
#[macro_use]
extern crate uucore;
use clap::{App, Arg, ArgMatches};
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::iter::repeat;
use std::str::from_utf8;
use unicode_width::UnicodeWidthChar;
static SYNTAX: &str = "[OPTION]... [FILE]...";
static SUMMARY: &str = "Convert tabs in each FILE to spaces, writing to standard output.
static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Convert tabs in each FILE to spaces, writing to standard output.
With no FILE, or when FILE is -, read standard input.";
pub mod options {
pub static TABS: &str = "tabs";
pub static INITIAL: &str = "initial";
pub static NO_UTF8: &str = "no-utf8";
pub static FILES: &str = "FILES";
}
static LONG_HELP: &str = "";
static DEFAULT_TABSTOP: usize = 8;
fn get_usage() -> String {
format!("{0} [OPTION]... [FILE]...", executable!())
}
fn tabstops_parse(s: String) -> Vec<usize> {
let words = s.split(',');
@ -58,14 +71,14 @@ struct Options {
}
impl Options {
fn new(matches: getopts::Matches) -> Options {
let tabstops = match matches.opt_str("t") {
fn new(matches: &ArgMatches) -> Options {
let tabstops = match matches.value_of(options::TABS) {
Some(s) => tabstops_parse(s.to_string()),
None => vec![DEFAULT_TABSTOP],
Some(s) => tabstops_parse(s),
};
let iflag = matches.opt_present("i");
let uflag = !matches.opt_present("U");
let iflag = matches.is_present(options::INITIAL);
let uflag = !matches.is_present(options::NO_UTF8);
// avoid allocations when dumping out long sequences of spaces
// by precomputing the longest string of spaces we will ever need
@ -80,10 +93,9 @@ impl Options {
.unwrap(); // length of tabstops is guaranteed >= 1
let tspaces = repeat(' ').take(nspaces).collect();
let files = if matches.free.is_empty() {
vec!["-".to_owned()]
} else {
matches.free
let files: Vec<String> = match matches.values_of(options::FILES) {
Some(s) => s.map(|v| v.to_string()).collect(),
None => vec!["-".to_owned()],
};
Options {
@ -97,31 +109,40 @@ impl Options {
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let args = args.collect_str();
let matches = app!(SYNTAX, SUMMARY, LONG_HELP)
.optflag("i", "initial", "do not convert tabs after non blanks")
.optopt(
"t",
"tabs",
"have tabs NUMBER characters apart, not 8",
"NUMBER",
let usage = get_usage();
let matches = App::new(executable!())
.version(VERSION)
.about(ABOUT)
.usage(&usage[..])
.after_help(LONG_HELP)
.arg(
Arg::with_name(options::INITIAL)
.long(options::INITIAL)
.short("i")
.help("do not convert tabs after non blanks"),
)
.optopt(
"t",
"tabs",
"use comma separated list of explicit tab positions",
"LIST",
.arg(
Arg::with_name(options::TABS)
.long(options::TABS)
.short("t")
.value_name("N, LIST")
.takes_value(true)
.help("have tabs N characters apart, not 8 or use comma separated list of explicit tab positions"),
)
.optflag(
"U",
"no-utf8",
"interpret input file as 8-bit ASCII rather than UTF-8",
.arg(
Arg::with_name(options::NO_UTF8)
.long(options::NO_UTF8)
.short("U")
.help("interpret input file as 8-bit ASCII rather than UTF-8"),
).arg(
Arg::with_name(options::FILES)
.multiple(true)
.hidden(true)
.takes_value(true)
)
.parse(args);
expand(Options::new(matches));
.get_matches_from(args);
expand(Options::new(&matches));
0
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_expr"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "expr ~ (uutils) display the value of EXPRESSION"
@ -17,7 +17,7 @@ path = "src/expr.rs"
[dependencies]
libc = "0.2.42"
onig = "~4.3.2"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_factor"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "factor ~ (uutils) display the prime factors of each NUMBER"
@ -19,7 +19,7 @@ num-traits = "0.2.13" # used in src/numerics.rs, which is included by build.rs
num-traits = "0.2.13" # Needs at least version 0.2.13 for "OverflowingAdd"
rand = { version="0.7", features=["small_rng"] }
smallvec = { version="0.6.14, < 1.0" }
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[dev-dependencies]

View file

@ -225,20 +225,19 @@ pub fn factor(num: u64) -> Factors {
#[cfg(test)]
mod tests {
use super::{factor, Factors};
use super::{factor, Decomposition, Exponent, Factors};
use quickcheck::quickcheck;
use smallvec::smallvec;
use std::cell::RefCell;
#[test]
fn factor_correctly_recombines_prior_test_failures() {
let prior_failures = [
// * integers with duplicate factors (ie, N.pow(M))
4566769_u64, // == 2137.pow(2)
2044854919485649_u64,
18446739546814299361_u64,
18446738440860217487_u64,
18446736729316206481_u64,
];
assert!(prior_failures.iter().all(|i| factor(*i).product() == *i));
fn factor_2044854919485649() {
let f = Factors(RefCell::new(Decomposition(smallvec![
(503, 1),
(2423, 1),
(40961, 2)
])));
assert_eq!(factor(f.product()), f);
}
#[test]
@ -248,15 +247,6 @@ mod tests {
.all(|i| factor(i).product() == i));
}
#[test]
fn factor_recombines_small_squares() {
// factor(18446736729316206481) == 4294966441 ** 2 ; causes debug_assert fault for repeated decomposition factor in add()
// ToDO: explain/combine with factor_18446736729316206481 and factor_18446739546814299361 tests
assert!((1..10_000)
.map(|i| (2 * i + 1) * (2 * i + 1))
.all(|i| factor(i).product() == i));
}
#[test]
fn factor_recombines_overflowing() {
assert!((0..250)
@ -282,9 +272,15 @@ mod tests {
i == 0 || factor(i).product() == i
}
fn recombines_factors(f: Factors) -> bool {
fn recombines_factors(f: Factors) -> () {
assert_eq!(factor(f.product()), f);
true
}
fn exponentiate_factors(f: Factors, e: Exponent) -> () {
if e == 0 { return; }
if let Some(fe) = f.product().checked_pow(e.into()) {
assert_eq!(factor(fe), f ^ e);
}
}
}
}
@ -319,3 +315,19 @@ impl quickcheck::Arbitrary for Factors {
}
}
}
#[cfg(test)]
impl std::ops::BitXor<Exponent> for Factors {
type Output = Self;
fn bitxor(self, rhs: Exponent) -> Factors {
debug_assert_ne!(rhs, 0);
let mut r = Factors::one();
for (p, e) in self.0.borrow().0.iter() {
r.add(*p, rhs * e);
}
debug_assert_eq!(r.product(), self.product().pow(rhs.into()));
return r;
}
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_false"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "false ~ (uutils) do nothing and fail"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/false.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_fmt"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "fmt ~ (uutils) reformat each paragraph of input"
@ -18,7 +18,7 @@ path = "src/fmt.rs"
clap = "2.33"
libc = "0.2.42"
unicode-width = "0.1.5"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_fold"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "fold ~ (uutils) wrap each line of input"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/fold.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_groups"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "groups ~ (uutils) display group memberships for USERNAME"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/groups.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["entries"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
clap = "2.33"

View file

@ -1,6 +1,6 @@
[package]
name = "uu_hashsum"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "hashsum ~ (uutils) display or check input digests"
@ -26,7 +26,7 @@ sha1 = "0.6.0"
sha2 = "0.6.0"
sha3 = "0.6.0"
blake2-rfc = "0.2.18"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_head"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "head ~ (uutils) display the first lines of input"
@ -16,7 +16,7 @@ path = "src/head.rs"
[dependencies]
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -29,6 +29,7 @@ enum FilterMode {
struct Settings {
mode: FilterMode,
verbose: bool,
zero_terminated: bool,
}
impl Default for Settings {
@ -36,6 +37,7 @@ impl Default for Settings {
Settings {
mode: FilterMode::Lines(10),
verbose: false,
zero_terminated: false,
}
}
}
@ -69,6 +71,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
)
.optflag("q", "quiet", "never print headers giving file names")
.optflag("v", "verbose", "always print headers giving file names")
.optflag("z", "zero-terminated", "line delimiter is NUL, not newline")
.optflag("h", "help", "display this help and exit")
.optflag("V", "version", "output version information and exit")
.parse(new_args);
@ -113,6 +116,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let quiet = matches.opt_present("q");
let verbose = matches.opt_present("v");
settings.zero_terminated = matches.opt_present("z");
let files = matches.free;
// GNU implementation allows multiple declarations of "-q" and "-v" with the
@ -203,8 +207,14 @@ fn head<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> bool {
}
}
FilterMode::Lines(count) => {
for line in reader.lines().take(count) {
println!("{}", line.unwrap());
if settings.zero_terminated {
for line in reader.split(0).take(count) {
print!("{}\0", String::from_utf8(line.unwrap()).unwrap())
}
} else {
for line in reader.lines().take(count) {
println!("{}", line.unwrap());
}
}
}
FilterMode::NLines(count) => {

View file

@ -1,6 +1,6 @@
[package]
name = "uu_hostid"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "hostid ~ (uutils) display the numeric identifier of the current host"
@ -16,7 +16,7 @@ path = "src/hostid.rs"
[dependencies]
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_hostname"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "hostname ~ (uutils) display or set the host name of the current host"
@ -18,7 +18,7 @@ path = "src/hostname.rs"
clap = "2.33"
libc = "0.2.42"
hostname = { version = "0.3", features = ["set"] }
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["wide"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["wide"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
winapi = { version="0.3", features=["sysinfoapi", "winsock2"] }

View file

@ -1,6 +1,6 @@
[package]
name = "uu_id"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "id ~ (uutils) display user and group information for USER"
@ -16,7 +16,7 @@ path = "src/id.rs"
[dependencies]
clap = "2.33"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["entries", "process"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries", "process"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -291,7 +291,7 @@ fn pretty(possible_pw: Option<Passwd>) {
}
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[cfg(any(target_vendor = "apple", target_os = "freebsd"))]
fn pline(possible_uid: Option<uid_t>) {
let uid = possible_uid.unwrap_or_else(getuid);
let pw = Passwd::locate(uid).unwrap();

View file

@ -1,6 +1,6 @@
[package]
name = "uu_install"
version = "0.0.3"
version = "0.0.4"
authors = [
"Ben Eills <ben@beneills.com>",
"uutils developers",
@ -19,8 +19,9 @@ path = "src/install.rs"
[dependencies]
clap = "2.33"
filetime = "0.2"
libc = ">= 0.2"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["mode", "perms", "entries"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["mode", "perms", "entries"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[dev-dependencies]

View file

@ -13,6 +13,7 @@ mod mode;
extern crate uucore;
use clap::{App, Arg, ArgMatches};
use filetime::{set_file_times, FileTime};
use uucore::entries::{grp2gid, usr2uid};
use uucore::perms::{wrap_chgrp, wrap_chown, Verbosity};
@ -32,6 +33,7 @@ pub struct Behavior {
owner: String,
group: String,
verbose: bool,
preserve_timestamps: bool,
}
#[derive(Clone, Eq, PartialEq)]
@ -154,11 +156,10 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.takes_value(true)
)
.arg(
// TODO implement flag
Arg::with_name(OPT_PRESERVE_TIMESTAMPS)
.short("p")
.long(OPT_PRESERVE_TIMESTAMPS)
.help("(unimplemented) apply access/modification times of SOURCE files to corresponding destination files")
.help("apply access/modification times of SOURCE files to corresponding destination files")
)
.arg(
// TODO implement flag
@ -265,8 +266,6 @@ fn check_unimplemented<'a>(matches: &ArgMatches) -> Result<(), &'a str> {
Err("--compare, -C")
} else if matches.is_present(OPT_CREATED) {
Err("-D")
} else if matches.is_present(OPT_PRESERVE_TIMESTAMPS) {
Err("--preserve-timestamps, -p")
} else if matches.is_present(OPT_STRIP) {
Err("--strip, -s")
} else if matches.is_present(OPT_STRIP_PROGRAM) {
@ -338,6 +337,7 @@ fn behavior(matches: &ArgMatches) -> Result<Behavior, i32> {
owner: matches.value_of(OPT_OWNER).unwrap_or("").to_string(),
group: matches.value_of(OPT_GROUP).unwrap_or("").to_string(),
verbose: matches.is_present(OPT_VERBOSE),
preserve_timestamps: matches.is_present(OPT_PRESERVE_TIMESTAMPS),
})
}
@ -555,6 +555,21 @@ fn copy(from: &PathBuf, to: &PathBuf, b: &Behavior) -> Result<(), ()> {
}
}
if b.preserve_timestamps {
let meta = match fs::metadata(from) {
Ok(meta) => meta,
Err(f) => crash!(1, "{}", f.to_string()),
};
let modified_time = FileTime::from_last_modification_time(&meta);
let accessed_time = FileTime::from_last_access_time(&meta);
match set_file_times(to.as_path(), accessed_time, modified_time) {
Ok(_) => {}
Err(e) => show_info!("{}", e),
}
}
if b.verbose {
show_info!("'{}' -> '{}'", from.display(), to.display());
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_join"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "join ~ (uutils) merge lines from inputs with matching join fields"
@ -16,7 +16,7 @@ path = "src/join.rs"
[dependencies]
clap = "2.33"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_kill"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "kill ~ (uutils) send a signal to a process"
@ -16,7 +16,7 @@ path = "src/kill.rs"
[dependencies]
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["signals"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["signals"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_link"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "link ~ (uutils) create a hard (file system) link to FILE"
@ -16,7 +16,7 @@ path = "src/link.rs"
[dependencies]
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_ln"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "ln ~ (uutils) create a (file system) link to TARGET"
@ -17,7 +17,7 @@ path = "src/ln.rs"
[dependencies]
clap = "2.33"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -207,7 +207,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let paths: Vec<PathBuf> = matches
.values_of(ARG_FILES)
.unwrap()
.map(|path| PathBuf::from(path))
.map(PathBuf::from)
.collect();
let overwrite_mode = if matches.is_present(OPT_FORCE) {
@ -316,9 +316,8 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &PathBuf, settings: &Setting
// We need to clean the target
if is_symlink(target_dir) {
if target_dir.is_file() {
match fs::remove_file(target_dir) {
Err(e) => show_error!("Could not update {}: {}", target_dir.display(), e),
_ => (),
if let Err(e) = fs::remove_file(target_dir) {
show_error!("Could not update {}: {}", target_dir.display(), e)
};
}
if target_dir.is_dir() {
@ -423,10 +422,8 @@ fn link(src: &PathBuf, dst: &PathBuf, settings: &Settings) -> Result<()> {
}
}
if settings.no_dereference && settings.force {
if dst.exists() {
fs::remove_file(dst)?;
}
if settings.no_dereference && settings.force && dst.exists() {
fs::remove_file(dst)?;
}
if settings.symbolic {

View file

@ -1,6 +1,6 @@
[package]
name = "uu_logname"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "logname ~ (uutils) display the login name of the current user"
@ -16,7 +16,7 @@ path = "src/logname.rs"
[dependencies]
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_ls"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "ls ~ (uutils) display directory contents"
@ -22,7 +22,7 @@ term_grid = "0.1.5"
termsize = "0.1.6"
time = "0.1.40"
unicode-width = "0.1.5"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["entries", "fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["entries", "fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[target.'cfg(unix)'.dependencies]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_mkdir"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "mkdir ~ (uutils) create DIRECTORY"
@ -17,7 +17,7 @@ path = "src/mkdir.rs"
[dependencies]
clap = "2.33"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs", "mode"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs", "mode"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_mkfifo"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "mkfifo ~ (uutils) create FIFOs (named pipes)"
@ -17,7 +17,7 @@ path = "src/mkfifo.rs"
[dependencies]
getopts = "0.2.18"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_mknod"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "mknod ~ (uutils) create special file NAME of TYPE"
@ -18,7 +18,7 @@ path = "src/mknod.rs"
[dependencies]
getopts = "0.2.18"
libc = "^0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["mode"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["mode"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_mktemp"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "mktemp ~ (uutils) create and display a temporary file or directory from TEMPLATE"
@ -18,7 +18,7 @@ path = "src/mktemp.rs"
clap = "2.33"
rand = "0.5"
tempfile = "3.1"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -25,6 +25,7 @@ mod tempdir;
static ABOUT: &str = "create a temporary file or directory.";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static DEFAULT_TEMPLATE: &str = "tmp.XXXXXXXXXX";
static OPT_DIRECTORY: &str = "directory";
@ -119,13 +120,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
// See https://github.com/clap-rs/clap/pull/1587
let tmp = env::temp_dir();
(tmpdir, tmp)
} else if !matches.is_present(OPT_TMPDIR) {
let tmp = env::temp_dir();
(template, tmp)
} else {
if !matches.is_present(OPT_TMPDIR) {
let tmp = env::temp_dir();
(template, tmp)
} else {
(template, PathBuf::from(tmpdir))
}
(template, PathBuf::from(tmpdir))
};
let make_dir = matches.is_present(OPT_DIRECTORY);
@ -157,14 +156,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
crash!(1, "suffix cannot contain any path separators");
}
if matches.is_present(OPT_TMPDIR) {
if PathBuf::from(prefix).is_absolute() {
show_info!(
"invalid template, {}; with --tmpdir, it may not be absolute",
template
);
return 1;
}
if matches.is_present(OPT_TMPDIR) && PathBuf::from(prefix).is_absolute() {
show_info!(
"invalid template, {}; with --tmpdir, it may not be absolute",
template
);
return 1;
};
if matches.is_present(OPT_T) {

View file

@ -1,6 +1,6 @@
[package]
name = "uu_more"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "more ~ (uutils) input perusal filter"
@ -16,15 +16,15 @@ path = "src/more.rs"
[dependencies]
getopts = "0.2.18"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
uucore = { version = ">=0.0.7", package = "uucore", path = "../../uucore" }
uucore_procs = { version = ">=0.0.5", package = "uucore_procs", path = "../../uucore_procs" }
[target.'cfg(target_os = "redox")'.dependencies]
redox_termios = "0.1"
redox_syscall = "0.1"
[target.'cfg(all(unix, not(target_os = "fuchsia")))'.dependencies]
nix = "0.8.1"
nix = "<=0.13"
[[bin]]
name = "more"

View file

@ -17,7 +17,7 @@ use std::io::{stdout, Read, Write};
#[cfg(all(unix, not(target_os = "fuchsia")))]
extern crate nix;
#[cfg(all(unix, not(target_os = "fuchsia")))]
use nix::sys::termios;
use nix::sys::termios::{self, LocalFlags, SetArg};
#[cfg(target_os = "redox")]
extern crate redox_termios;
@ -92,10 +92,10 @@ fn help(usage: &str) {
fn setup_term() -> termios::Termios {
let mut term = termios::tcgetattr(0).unwrap();
// Unset canonical mode, so we get characters immediately
term.c_lflag.remove(termios::ICANON);
term.local_flags.remove(LocalFlags::ICANON);
// Disable local echo
term.c_lflag.remove(termios::ECHO);
termios::tcsetattr(0, termios::TCSADRAIN, &term).unwrap();
term.local_flags.remove(LocalFlags::ECHO);
termios::tcsetattr(0, SetArg::TCSADRAIN, &term).unwrap();
term
}
@ -110,8 +110,8 @@ fn setup_term() -> redox_termios::Termios {
let mut term = redox_termios::Termios::default();
let fd = syscall::dup(0, b"termios").unwrap();
syscall::read(fd, &mut term).unwrap();
term.c_lflag &= !redox_termios::ICANON;
term.c_lflag &= !redox_termios::ECHO;
term.local_flags &= !redox_termios::ICANON;
term.local_flags &= !redox_termios::ECHO;
syscall::write(fd, &term).unwrap();
let _ = syscall::close(fd);
term
@ -119,9 +119,9 @@ fn setup_term() -> redox_termios::Termios {
#[cfg(all(unix, not(target_os = "fuchsia")))]
fn reset_term(term: &mut termios::Termios) {
term.c_lflag.insert(termios::ICANON);
term.c_lflag.insert(termios::ECHO);
termios::tcsetattr(0, termios::TCSADRAIN, &term).unwrap();
term.local_flags.insert(LocalFlags::ICANON);
term.local_flags.insert(LocalFlags::ECHO);
termios::tcsetattr(0, SetArg::TCSADRAIN, &term).unwrap();
}
#[cfg(any(windows, target_os = "fuchsia"))]
@ -132,8 +132,8 @@ fn reset_term(_: &mut usize) {}
fn reset_term(term: &mut redox_termios::Termios) {
let fd = syscall::dup(0, b"termios").unwrap();
syscall::read(fd, term).unwrap();
term.c_lflag |= redox_termios::ICANON;
term.c_lflag |= redox_termios::ECHO;
term.local_flags |= redox_termios::ICANON;
term.local_flags |= redox_termios::ECHO;
syscall::write(fd, &term).unwrap();
let _ = syscall::close(fd);
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_mv"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "mv ~ (uutils) move (rename) SOURCE to DESTINATION"
@ -17,7 +17,7 @@ path = "src/mv.rs"
[dependencies]
clap = "2.33"
fs_extra = "1.1.0"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_nice"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "nice ~ (uutils) run PROGRAM with modified scheduling priority"
@ -15,9 +15,10 @@ edition = "2018"
path = "src/nice.rs"
[dependencies]
getopts = "0.2.18"
clap = "2.33"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
nix = { version="<=0.13" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -15,7 +15,7 @@ use std::ffi::CString;
use std::io::Error;
use std::ptr;
const NAME: &str = "nice";
use clap::{App, AppSettings, Arg};
const VERSION: &str = env!("CARGO_PKG_VERSION");
// XXX: PRIO_PROCESS is 0 on at least FreeBSD and Linux. Don't know about Mac OS X.
@ -26,64 +26,57 @@ extern "C" {
fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int;
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let args = args.collect_str();
pub mod options {
pub static ADJUSTMENT: &str = "adjustment";
pub static COMMAND: &str = "COMMAND";
}
let mut opts = getopts::Options::new();
opts.optopt(
"n",
"adjustment",
"add N to the niceness (default is 10)",
"N",
);
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(err) => {
show_error!("{}", err);
return 125;
}
};
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
if matches.opt_present("help") {
let msg = format!(
"{0} {1}
Usage:
fn get_usage() -> String {
format!(
"
{0} [OPTIONS] [COMMAND [ARGS]]
Run COMMAND with an adjusted niceness, which affects process scheduling.
With no COMMAND, print the current niceness. Niceness values range from at
least -20 (most favorable to the process) to 19 (least favorable to the
process).",
NAME, VERSION
);
executable!()
)
}
print!("{}", opts.usage(&msg));
return 0;
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let usage = get_usage();
let mut niceness = unsafe { getpriority(PRIO_PROCESS, 0) };
let matches = App::new(executable!())
.setting(AppSettings::TrailingVarArg)
.version(VERSION)
.usage(&usage[..])
.arg(
Arg::with_name(options::ADJUSTMENT)
.short("n")
.long(options::ADJUSTMENT)
.help("add N to the niceness (default is 10)")
.takes_value(true)
.allow_hyphen_values(true),
)
.arg(Arg::with_name(options::COMMAND).multiple(true))
.get_matches_from(args);
let mut niceness = unsafe {
nix::errno::Errno::clear();
getpriority(PRIO_PROCESS, 0)
};
if Error::last_os_error().raw_os_error().unwrap() != 0 {
show_error!("{}", Error::last_os_error());
show_error!("getpriority: {}", Error::last_os_error());
return 125;
}
let adjustment = match matches.opt_str("adjustment") {
let adjustment = match matches.value_of(options::ADJUSTMENT) {
Some(nstr) => {
if matches.free.is_empty() {
if !matches.is_present(options::COMMAND) {
show_error!(
"A command must be given with an adjustment.
Try \"{} --help\" for more information.",
args[0]
"A command must be given with an adjustment.\nTry \"{} --help\" for more information.",
executable!()
);
return 125;
}
@ -96,7 +89,7 @@ process).",
}
}
None => {
if matches.free.is_empty() {
if !matches.is_present(options::COMMAND) {
println!("{}", niceness);
return 0;
}
@ -105,25 +98,23 @@ process).",
};
niceness += adjustment;
unsafe {
setpriority(PRIO_PROCESS, 0, niceness);
}
if Error::last_os_error().raw_os_error().unwrap() != 0 {
show_warning!("{}", Error::last_os_error());
if unsafe { setpriority(PRIO_PROCESS, 0, niceness) } == -1 {
show_warning!("setpriority: {}", Error::last_os_error());
}
let cstrs: Vec<CString> = matches
.free
.iter()
.values_of(options::COMMAND)
.unwrap()
.map(|x| CString::new(x.as_bytes()).unwrap())
.collect();
let mut args: Vec<*const c_char> = cstrs.iter().map(|s| s.as_ptr()).collect();
args.push(ptr::null::<c_char>());
unsafe {
execvp(args[0], args.as_mut_ptr());
}
show_error!("{}", Error::last_os_error());
show_error!("execvp: {}", Error::last_os_error());
if Error::last_os_error().raw_os_error().unwrap() as c_int == libc::ENOENT {
127
} else {

View file

@ -1,6 +1,6 @@
[package]
name = "uu_nl"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "nl ~ (uutils) display input with added line numbers"
@ -21,7 +21,7 @@ libc = "0.2.42"
memchr = "2.2.0"
regex = "1.0.1"
regex-syntax = "0.6.7"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -11,7 +11,9 @@ fn parse_style(chars: &[char]) -> Result<crate::NumberingStyle, String> {
} else if chars.len() > 1 && chars[0] == 'p' {
let s: String = chars[1..].iter().cloned().collect();
match regex::Regex::new(&s) {
Ok(re) => Ok(crate::NumberingStyle::NumberForRegularExpression(re)),
Ok(re) => Ok(crate::NumberingStyle::NumberForRegularExpression(Box::new(
re,
))),
Err(_) => Err(String::from("Illegal regular expression")),
}
} else {

View file

@ -55,7 +55,7 @@ enum NumberingStyle {
NumberForAll,
NumberForNonEmpty,
NumberForNone,
NumberForRegularExpression(regex::Regex),
NumberForRegularExpression(Box<regex::Regex>),
}
// NumberFormat specifies how line numbers are output within their allocated

View file

@ -1,6 +1,6 @@
[package]
name = "uu_nohup"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "nohup ~ (uutils) run COMMAND, ignoring hangup signals"
@ -17,7 +17,7 @@ path = "src/nohup.rs"
[dependencies]
getopts = "0.2.18"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -23,7 +23,7 @@ use uucore::fs::{is_stderr_interactive, is_stdin_interactive, is_stdout_interact
static NAME: &str = "nohup";
static VERSION: &str = env!("CARGO_PKG_VERSION");
#[cfg(target_os = "macos")]
#[cfg(target_vendor = "apple")]
extern "C" {
fn _vprocmgr_detach_from_console(flags: u32) -> *const libc::c_int;
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_nproc"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "nproc ~ (uutils) display the number of processing units available"
@ -18,7 +18,7 @@ path = "src/nproc.rs"
libc = "0.2.42"
num_cpus = "1.10"
clap = "2.33"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -15,7 +15,7 @@ use std::env;
#[cfg(target_os = "linux")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 83;
#[cfg(target_os = "macos")]
#[cfg(target_vendor = "apple")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = libc::_SC_NPROCESSORS_CONF;
#[cfg(target_os = "freebsd")]
pub const _SC_NPROCESSORS_CONF: libc::c_int = 57;
@ -89,7 +89,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
#[cfg(any(
target_os = "linux",
target_os = "macos",
target_vendor = "apple",
target_os = "freebsd",
target_os = "netbsd"
))]
@ -109,7 +109,7 @@ fn num_cpus_all() -> usize {
// Other platforms (e.g., windows), num_cpus::get() directly.
#[cfg(not(any(
target_os = "linux",
target_os = "macos",
target_vendor = "apple",
target_os = "freebsd",
target_os = "netbsd"
)))]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_numfmt"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "numfmt ~ (uutils) reformat NUMBER"
@ -16,7 +16,7 @@ path = "src/numfmt.rs"
[dependencies]
clap = "2.33"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

296
src/uu/numfmt/src/format.rs Normal file
View file

@ -0,0 +1,296 @@
use crate::options::NumfmtOptions;
use crate::units::{
DisplayableSuffix, RawSuffix, Result, Suffix, Transform, Unit, IEC_BASES, SI_BASES,
};
/// Iterate over a line's fields, where each field is a contiguous sequence of
/// non-whitespace, optionally prefixed with one or more characters of leading
/// whitespace. Fields are returned as tuples of `(prefix, field)`.
///
/// # Examples:
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some(" 1234 5") };
///
/// assert_eq!(Some((" ", "1234")), fields.next());
/// assert_eq!(Some((" ", "5")), fields.next());
/// assert_eq!(None, fields.next());
/// ```
///
/// Delimiters are included in the results; `prefix` will be empty only for
/// the first field of the line (including the case where the input line is
/// empty):
///
/// ```
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("first second") };
///
/// assert_eq!(Some(("", "first")), fields.next());
/// assert_eq!(Some((" ", "second")), fields.next());
///
/// let mut fields = uu_numfmt::format::WhitespaceSplitter { s: Some("") };
///
/// assert_eq!(Some(("", "")), fields.next());
/// ```
pub struct WhitespaceSplitter<'a> {
pub s: Option<&'a str>,
}
impl<'a> Iterator for WhitespaceSplitter<'a> {
type Item = (&'a str, &'a str);
/// Yield the next field in the input string as a tuple `(prefix, field)`.
fn next(&mut self) -> Option<Self::Item> {
let haystack = self.s?;
let (prefix, field) = haystack.split_at(
haystack
.find(|c: char| !c.is_whitespace())
.unwrap_or_else(|| haystack.len()),
);
let (field, rest) = field.split_at(
field
.find(|c: char| c.is_whitespace())
.unwrap_or_else(|| field.len()),
);
self.s = if !rest.is_empty() { Some(rest) } else { None };
Some((prefix, field))
}
}
fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
if s.is_empty() {
return Err("invalid number: ".to_string());
}
let with_i = s.ends_with('i');
let mut iter = s.chars();
if with_i {
iter.next_back();
}
let suffix: Option<Suffix> = match iter.next_back() {
Some('K') => Ok(Some((RawSuffix::K, with_i))),
Some('M') => Ok(Some((RawSuffix::M, with_i))),
Some('G') => Ok(Some((RawSuffix::G, with_i))),
Some('T') => Ok(Some((RawSuffix::T, with_i))),
Some('P') => Ok(Some((RawSuffix::P, with_i))),
Some('E') => Ok(Some((RawSuffix::E, with_i))),
Some('Z') => Ok(Some((RawSuffix::Z, with_i))),
Some('Y') => Ok(Some((RawSuffix::Y, with_i))),
Some('0'..='9') => Ok(None),
_ => Err(format!("invalid suffix in input: {}", s)),
}?;
let suffix_len = match suffix {
None => 0,
Some((_, false)) => 1,
Some((_, true)) => 2,
};
let number = s[..s.len() - suffix_len]
.parse::<f64>()
.map_err(|_| format!("invalid number: {}", s))?;
Ok((number, suffix))
}
fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
match (s, u) {
(None, _) => Ok(i),
(Some((raw_suffix, false)), &Unit::Auto) | (Some((raw_suffix, false)), &Unit::Si) => {
match raw_suffix {
RawSuffix::K => Ok(i * 1e3),
RawSuffix::M => Ok(i * 1e6),
RawSuffix::G => Ok(i * 1e9),
RawSuffix::T => Ok(i * 1e12),
RawSuffix::P => Ok(i * 1e15),
RawSuffix::E => Ok(i * 1e18),
RawSuffix::Z => Ok(i * 1e21),
RawSuffix::Y => Ok(i * 1e24),
}
}
(Some((raw_suffix, false)), &Unit::Iec(false))
| (Some((raw_suffix, true)), &Unit::Auto)
| (Some((raw_suffix, true)), &Unit::Iec(true)) => match raw_suffix {
RawSuffix::K => Ok(i * IEC_BASES[1]),
RawSuffix::M => Ok(i * IEC_BASES[2]),
RawSuffix::G => Ok(i * IEC_BASES[3]),
RawSuffix::T => Ok(i * IEC_BASES[4]),
RawSuffix::P => Ok(i * IEC_BASES[5]),
RawSuffix::E => Ok(i * IEC_BASES[6]),
RawSuffix::Z => Ok(i * IEC_BASES[7]),
RawSuffix::Y => Ok(i * IEC_BASES[8]),
},
(_, _) => Err("This suffix is unsupported for specified unit".to_owned()),
}
}
fn transform_from(s: &str, opts: &Transform) -> Result<f64> {
let (i, suffix) = parse_suffix(s)?;
remove_suffix(i, suffix, &opts.unit).map(|n| if n < 0.0 { -n.abs().ceil() } else { n.ceil() })
}
/// Divide numerator by denominator, with ceiling.
///
/// If the result of the division is less than 10.0, truncate the result
/// to the next highest tenth.
///
/// Otherwise, truncate the result to the next highest whole number.
///
/// # Examples:
///
/// ```
/// use uu_numfmt::format::div_ceil;
///
/// assert_eq!(div_ceil(1.01, 1.0), 1.1);
/// assert_eq!(div_ceil(999.1, 1000.), 1.0);
/// assert_eq!(div_ceil(1001., 10.), 101.);
/// assert_eq!(div_ceil(9991., 10.), 1000.);
/// assert_eq!(div_ceil(-12.34, 1.0), -13.0);
/// assert_eq!(div_ceil(1000.0, -3.14), -319.0);
/// assert_eq!(div_ceil(-271828.0, -271.0), 1004.0);
/// ```
pub fn div_ceil(n: f64, d: f64) -> f64 {
let v = n / (d / 10.0);
let (v, sign) = if v < 0.0 { (v.abs(), -1.0) } else { (v, 1.0) };
if v < 100.0 {
v.ceil() / 10.0 * sign
} else {
(v / 10.0).ceil() * sign
}
}
fn consider_suffix(n: f64, u: &Unit) -> Result<(f64, Option<Suffix>)> {
use crate::units::RawSuffix::*;
let abs_n = n.abs();
let suffixes = [K, M, G, T, P, E, Z, Y];
let (bases, with_i) = match *u {
Unit::Si => (&SI_BASES, false),
Unit::Iec(with_i) => (&IEC_BASES, with_i),
Unit::Auto => return Err("Unit 'auto' isn't supported with --to options".to_owned()),
Unit::None => return Ok((n, None)),
};
let i = match abs_n {
_ if abs_n <= bases[1] - 1.0 => return Ok((n, None)),
_ if abs_n < bases[2] => 1,
_ if abs_n < bases[3] => 2,
_ if abs_n < bases[4] => 3,
_ if abs_n < bases[5] => 4,
_ if abs_n < bases[6] => 5,
_ if abs_n < bases[7] => 6,
_ if abs_n < bases[8] => 7,
_ if abs_n < bases[9] => 8,
_ => return Err("Number is too big and unsupported".to_string()),
};
let v = div_ceil(n, bases[i]);
// check if rounding pushed us into the next base
if v.abs() >= bases[1] {
Ok((v / bases[1], Some((suffixes[i], with_i))))
} else {
Ok((v, Some((suffixes[i - 1], with_i))))
}
}
fn transform_to(s: f64, opts: &Transform) -> Result<String> {
let (i2, s) = consider_suffix(s, &opts.unit)?;
Ok(match s {
None => format!("{}", i2),
Some(s) if i2.abs() < 10.0 => format!("{:.1}{}", i2, DisplayableSuffix(s)),
Some(s) => format!("{:.0}{}", i2, DisplayableSuffix(s)),
})
}
fn format_string(
source: &str,
options: &NumfmtOptions,
implicit_padding: Option<isize>,
) -> Result<String> {
let number = transform_to(
transform_from(source, &options.transform.from)?,
&options.transform.to,
)?;
Ok(match implicit_padding.unwrap_or(options.padding) {
p if p == 0 => number,
p if p > 0 => format!("{:>padding$}", number, padding = p as usize),
p => format!("{:<padding$}", number, padding = p.abs() as usize),
})
}
fn format_and_print_delimited(s: &str, options: &NumfmtOptions) -> Result<()> {
let delimiter = options.delimiter.as_ref().unwrap();
for (n, field) in (1..).zip(s.split(delimiter)) {
let field_selected = uucore::ranges::contain(&options.fields, n);
// print delimiter before second and subsequent fields
if n > 1 {
print!("{}", delimiter);
}
if field_selected {
print!("{}", format_string(&field.trim_start(), options, None)?);
} else {
// print unselected field without conversion
print!("{}", field);
}
}
println!();
Ok(())
}
fn format_and_print_whitespace(s: &str, options: &NumfmtOptions) -> Result<()> {
for (n, (prefix, field)) in (1..).zip(WhitespaceSplitter { s: Some(s) }) {
let field_selected = uucore::ranges::contain(&options.fields, n);
if field_selected {
let empty_prefix = prefix.is_empty();
// print delimiter before second and subsequent fields
let prefix = if n > 1 {
print!(" ");
&prefix[1..]
} else {
&prefix
};
let implicit_padding = if !empty_prefix && options.padding == 0 {
Some((prefix.len() + field.len()) as isize)
} else {
None
};
print!("{}", format_string(&field, options, implicit_padding)?);
} else {
// print unselected field without conversion
print!("{}{}", prefix, field);
}
}
println!();
Ok(())
}
/// Format a line of text according to the selected options.
///
/// Given a line of text `s`, split the line into fields, transform and format
/// any selected numeric fields, and print the result to stdout. Fields not
/// selected for conversion are passed through unmodified.
pub fn format_and_print(s: &str, options: &NumfmtOptions) -> Result<()> {
match &options.delimiter {
Some(_) => format_and_print_delimited(s, options),
None => format_and_print_whitespace(s, options),
}
}

View file

@ -5,13 +5,19 @@
// * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code.
use std::fmt;
use std::io::BufRead;
#[macro_use]
extern crate uucore;
use clap::{App, Arg, ArgMatches};
use crate::format::format_and_print;
use crate::options::*;
use crate::units::{Result, Transform, Unit};
use clap::{App, AppSettings, Arg, ArgMatches};
use std::io::{BufRead, Write};
use uucore::ranges::Range;
pub mod format;
mod options;
mod units;
static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Convert numbers from/to human-readable strings";
@ -33,113 +39,43 @@ static LONG_HELP: &str = "UNIT options:
iec-i accept optional two-letter suffix:
1Ki = 1024, 1Mi = 1048576, ...
";
mod options {
pub const FROM: &str = "from";
pub const FROM_DEFAULT: &str = "none";
pub const HEADER: &str = "header";
pub const HEADER_DEFAULT: &str = "1";
pub const NUMBER: &str = "NUMBER";
pub const PADDING: &str = "padding";
pub const TO: &str = "to";
pub const TO_DEFAULT: &str = "none";
}
FIELDS supports cut(1) style field ranges:
N N'th field, counted from 1
N- from N'th field, to end of line
N-M from N'th to M'th field (inclusive)
-M from first to M'th field (inclusive)
- all fields
Multiple fields/ranges can be separated with commas
";
fn get_usage() -> String {
format!("{0} [OPTION]... [NUMBER]...", executable!())
}
const IEC_BASES: [f64; 10] = [
//premature optimization
1.,
1_024.,
1_048_576.,
1_073_741_824.,
1_099_511_627_776.,
1_125_899_906_842_624.,
1_152_921_504_606_846_976.,
1_180_591_620_717_411_303_424.,
1_208_925_819_614_629_174_706_176.,
1_237_940_039_285_380_274_899_124_224.,
];
type Result<T> = std::result::Result<T, String>;
type WithI = bool;
enum Unit {
Auto,
Si,
Iec(WithI),
None,
}
enum RawSuffix {
K,
M,
G,
T,
P,
E,
Z,
Y,
}
type Suffix = (RawSuffix, WithI);
struct DisplayableSuffix(Suffix);
impl fmt::Display for DisplayableSuffix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let DisplayableSuffix((ref raw_suffix, ref with_i)) = *self;
match raw_suffix {
RawSuffix::K => write!(f, "K"),
RawSuffix::M => write!(f, "M"),
RawSuffix::G => write!(f, "G"),
RawSuffix::T => write!(f, "T"),
RawSuffix::P => write!(f, "P"),
RawSuffix::E => write!(f, "E"),
RawSuffix::Z => write!(f, "Z"),
RawSuffix::Y => write!(f, "Y"),
}
.and_then(|()| match with_i {
true => write!(f, "i"),
false => Ok(()),
})
fn handle_args<'a>(args: impl Iterator<Item = &'a str>, options: NumfmtOptions) -> Result<()> {
for l in args {
format_and_print(l, &options)?;
}
Ok(())
}
fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
let with_i = s.ends_with('i');
let mut iter = s.chars();
if with_i {
iter.next_back();
fn handle_stdin(options: NumfmtOptions) -> Result<()> {
let stdin = std::io::stdin();
let locked_stdin = stdin.lock();
let mut lines = locked_stdin.lines();
for l in lines.by_ref().take(options.header) {
l.map(|s| println!("{}", s)).map_err(|e| e.to_string())?;
}
let suffix: Option<Suffix> = match iter.next_back() {
Some('K') => Ok(Some((RawSuffix::K, with_i))),
Some('M') => Ok(Some((RawSuffix::M, with_i))),
Some('G') => Ok(Some((RawSuffix::G, with_i))),
Some('T') => Ok(Some((RawSuffix::T, with_i))),
Some('P') => Ok(Some((RawSuffix::P, with_i))),
Some('E') => Ok(Some((RawSuffix::E, with_i))),
Some('Z') => Ok(Some((RawSuffix::Z, with_i))),
Some('Y') => Ok(Some((RawSuffix::Y, with_i))),
Some('0'..='9') => Ok(None),
_ => Err(format!("invalid suffix in input: {}", s)),
}?;
let suffix_len = match suffix {
None => 0,
Some((_, false)) => 1,
Some((_, true)) => 2,
};
for l in lines {
l.map_err(|e| e.to_string())
.and_then(|l| format_and_print(&l, &options))?;
}
let number = s[..s.len() - suffix_len]
.parse::<f64>()
.map_err(|_| format!("invalid number: {}", s))?;
Ok((number, suffix))
Ok(())
}
fn parse_unit(s: &str) -> Result<Unit> {
@ -153,128 +89,6 @@ fn parse_unit(s: &str) -> Result<Unit> {
}
}
struct TransformOptions {
from: Transform,
to: Transform,
}
struct Transform {
unit: Unit,
}
struct NumfmtOptions {
transform: TransformOptions,
padding: isize,
header: usize,
}
fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
match (s, u) {
(None, _) => Ok(i),
(Some((raw_suffix, false)), &Unit::Auto) | (Some((raw_suffix, false)), &Unit::Si) => {
match raw_suffix {
RawSuffix::K => Ok(i * 1e3),
RawSuffix::M => Ok(i * 1e6),
RawSuffix::G => Ok(i * 1e9),
RawSuffix::T => Ok(i * 1e12),
RawSuffix::P => Ok(i * 1e15),
RawSuffix::E => Ok(i * 1e18),
RawSuffix::Z => Ok(i * 1e21),
RawSuffix::Y => Ok(i * 1e24),
}
}
(Some((raw_suffix, false)), &Unit::Iec(false))
| (Some((raw_suffix, true)), &Unit::Auto)
| (Some((raw_suffix, true)), &Unit::Iec(true)) => match raw_suffix {
RawSuffix::K => Ok(i * IEC_BASES[1]),
RawSuffix::M => Ok(i * IEC_BASES[2]),
RawSuffix::G => Ok(i * IEC_BASES[3]),
RawSuffix::T => Ok(i * IEC_BASES[4]),
RawSuffix::P => Ok(i * IEC_BASES[5]),
RawSuffix::E => Ok(i * IEC_BASES[6]),
RawSuffix::Z => Ok(i * IEC_BASES[7]),
RawSuffix::Y => Ok(i * IEC_BASES[8]),
},
(_, _) => Err("This suffix is unsupported for specified unit".to_owned()),
}
}
fn transform_from(s: &str, opts: &Transform) -> Result<f64> {
let (i, suffix) = parse_suffix(s)?;
remove_suffix(i, suffix, &opts.unit).map(|n| n.round())
}
fn consider_suffix(i: f64, u: &Unit) -> Result<(f64, Option<Suffix>)> {
let j = i.abs();
match *u {
Unit::Si => match j {
_ if j < 1e3 => Ok((i, None)),
_ if j < 1e6 => Ok((i / 1e3, Some((RawSuffix::K, false)))),
_ if j < 1e9 => Ok((i / 1e6, Some((RawSuffix::M, false)))),
_ if j < 1e12 => Ok((i / 1e9, Some((RawSuffix::G, false)))),
_ if j < 1e15 => Ok((i / 1e12, Some((RawSuffix::T, false)))),
_ if j < 1e18 => Ok((i / 1e15, Some((RawSuffix::P, false)))),
_ if j < 1e21 => Ok((i / 1e18, Some((RawSuffix::E, false)))),
_ if j < 1e24 => Ok((i / 1e21, Some((RawSuffix::Z, false)))),
_ if j < 1e27 => Ok((i / 1e24, Some((RawSuffix::Y, false)))),
_ => Err("Number is too big and unsupported".to_owned()),
},
Unit::Iec(with_i) => match j {
_ if j < IEC_BASES[1] => Ok((i, None)),
_ if j < IEC_BASES[2] => Ok((i / IEC_BASES[1], Some((RawSuffix::K, with_i)))),
_ if j < IEC_BASES[3] => Ok((i / IEC_BASES[2], Some((RawSuffix::M, with_i)))),
_ if j < IEC_BASES[4] => Ok((i / IEC_BASES[3], Some((RawSuffix::G, with_i)))),
_ if j < IEC_BASES[5] => Ok((i / IEC_BASES[4], Some((RawSuffix::T, with_i)))),
_ if j < IEC_BASES[6] => Ok((i / IEC_BASES[5], Some((RawSuffix::P, with_i)))),
_ if j < IEC_BASES[7] => Ok((i / IEC_BASES[6], Some((RawSuffix::E, with_i)))),
_ if j < IEC_BASES[8] => Ok((i / IEC_BASES[7], Some((RawSuffix::Z, with_i)))),
_ if j < IEC_BASES[9] => Ok((i / IEC_BASES[8], Some((RawSuffix::Y, with_i)))),
_ => Err("Number is too big and unsupported".to_owned()),
},
Unit::Auto => Err("Unit 'auto' isn't supported with --to options".to_owned()),
Unit::None => Ok((i, None)),
}
}
fn transform_to(s: f64, opts: &Transform) -> Result<String> {
let (i2, s) = consider_suffix(s, &opts.unit)?;
Ok(match s {
None => format!("{}", i2),
Some(s) => format!("{:.1}{}", i2, DisplayableSuffix(s)),
})
}
fn format_string(
source: &str,
options: &NumfmtOptions,
implicit_padding: Option<isize>,
) -> Result<String> {
let number = transform_to(
transform_from(source, &options.transform.from)?,
&options.transform.to,
)?;
Ok(match implicit_padding.unwrap_or(options.padding) {
p if p == 0 => number,
p if p > 0 => format!("{:>padding$}", number, padding = p as usize),
p => format!("{:<padding$}", number, padding = p.abs() as usize),
})
}
fn format_and_print(s: &str, options: &NumfmtOptions) -> Result<()> {
let (prefix, field, suffix) = extract_field(&s)?;
let implicit_padding = match !prefix.is_empty() && options.padding == 0 {
true => Some((prefix.len() + field.len()) as isize),
false => None,
};
let field = format_string(field, options, implicit_padding)?;
println!("{}{}", field, suffix);
Ok(())
}
fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
let from = parse_unit(args.value_of(options::FROM).unwrap())?;
let to = parse_unit(args.value_of(options::TO).unwrap())?;
@ -305,84 +119,32 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
}
}?;
let fields = match args.value_of(options::FIELD) {
Some("-") => vec![Range {
low: 1,
high: std::usize::MAX,
}],
Some(v) => Range::from_list(v)?,
None => unreachable!(),
};
let delimiter = args.value_of(options::DELIMITER).map_or(Ok(None), |arg| {
if arg.len() == 1 {
Ok(Some(arg.to_string()))
} else {
Err("the delimiter must be a single character".to_string())
}
})?;
Ok(NumfmtOptions {
transform,
padding,
header,
fields,
delimiter,
})
}
/// Extract the field to convert from `line`.
///
/// The field is the first sequence of non-whitespace characters in `line`.
///
/// Returns a [`Result`] of `(prefix: &str, field: &str, suffix: &str)`, where
/// `prefix` contains any leading whitespace, `field` is the field to convert,
/// and `suffix` is everything after the field. `prefix` and `suffix` may be
/// empty.
///
/// Returns an [`Err`] if `line` is empty or consists only of whitespace.
///
/// Examples:
///
/// ```
/// use uu_numfmt::extract_field;
///
/// assert_eq!("1K", extract_field("1K").unwrap().1);
///
/// let (prefix, field, suffix) = extract_field(" 1K qux").unwrap();
/// assert_eq!(" ", prefix);
/// assert_eq!("1K", field);
/// assert_eq!(" qux", suffix);
///
/// assert!(extract_field("").is_err());
/// ```
pub fn extract_field(line: &str) -> Result<(&str, &str, &str)> {
let start = line
.find(|c: char| !c.is_whitespace())
.ok_or("invalid number: ")?;
let prefix = &line[..start];
let mut field = &line[start..];
let suffix = match field.find(|c: char| c.is_whitespace()) {
Some(i) => {
let suffix = &field[i..];
field = &field[..i];
suffix
}
None => "",
};
Ok((prefix, field, suffix))
}
fn handle_args<'a>(args: impl Iterator<Item = &'a str>, options: NumfmtOptions) -> Result<()> {
for l in args {
format_and_print(l, &options)?;
}
Ok(())
}
fn handle_stdin(options: NumfmtOptions) -> Result<()> {
let stdin = std::io::stdin();
let locked_stdin = stdin.lock();
let mut lines = locked_stdin.lines();
for l in lines.by_ref().take(options.header) {
l.map(|s| println!("{}", s)).map_err(|e| e.to_string())?;
}
for l in lines {
l.map_err(|e| e.to_string())
.and_then(|l| format_and_print(&l, &options))?;
}
Ok(())
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let usage = get_usage();
@ -391,6 +153,21 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.about(ABOUT)
.usage(&usage[..])
.after_help(LONG_HELP)
.setting(AppSettings::AllowNegativeNumbers)
.arg(
Arg::with_name(options::DELIMITER)
.short("d")
.long(options::DELIMITER)
.value_name("X")
.help("use X instead of whitespace for field delimiter"),
)
.arg(
Arg::with_name(options::FIELD)
.long(options::FIELD)
.help("replace the numbers in these input fields (default=1) see FIELDS below")
.value_name("FIELDS")
.default_value(options::FIELD_DEFAULT),
)
.arg(
Arg::with_name(options::FROM)
.long(options::FROM)
@ -438,6 +215,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
match result {
Err(e) => {
std::io::stdout().flush().expect("error flushing stdout");
show_info!("{}", e);
1
}

View file

@ -0,0 +1,27 @@
use crate::units::Transform;
use uucore::ranges::Range;
pub const DELIMITER: &str = "delimiter";
pub const FIELD: &str = "field";
pub const FIELD_DEFAULT: &str = "1";
pub const FROM: &str = "from";
pub const FROM_DEFAULT: &str = "none";
pub const HEADER: &str = "header";
pub const HEADER_DEFAULT: &str = "1";
pub const NUMBER: &str = "NUMBER";
pub const PADDING: &str = "padding";
pub const TO: &str = "to";
pub const TO_DEFAULT: &str = "none";
pub struct TransformOptions {
pub from: Transform,
pub to: Transform,
}
pub struct NumfmtOptions {
pub transform: TransformOptions,
pub padding: isize,
pub header: usize,
pub fields: Vec<Range>,
pub delimiter: Option<String>,
}

View file

@ -0,0 +1,67 @@
use std::fmt;
pub const SI_BASES: [f64; 10] = [1., 1e3, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24, 1e27];
pub const IEC_BASES: [f64; 10] = [
1.,
1_024.,
1_048_576.,
1_073_741_824.,
1_099_511_627_776.,
1_125_899_906_842_624.,
1_152_921_504_606_846_976.,
1_180_591_620_717_411_303_424.,
1_208_925_819_614_629_174_706_176.,
1_237_940_039_285_380_274_899_124_224.,
];
pub type WithI = bool;
pub enum Unit {
Auto,
Si,
Iec(WithI),
None,
}
pub struct Transform {
pub unit: Unit,
}
pub type Result<T> = std::result::Result<T, String>;
#[derive(Clone, Copy, Debug)]
pub enum RawSuffix {
K,
M,
G,
T,
P,
E,
Z,
Y,
}
pub type Suffix = (RawSuffix, WithI);
pub struct DisplayableSuffix(pub Suffix);
impl fmt::Display for DisplayableSuffix {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let DisplayableSuffix((ref raw_suffix, ref with_i)) = *self;
match raw_suffix {
RawSuffix::K => write!(f, "K"),
RawSuffix::M => write!(f, "M"),
RawSuffix::G => write!(f, "G"),
RawSuffix::T => write!(f, "T"),
RawSuffix::P => write!(f, "P"),
RawSuffix::E => write!(f, "E"),
RawSuffix::Z => write!(f, "Z"),
RawSuffix::Y => write!(f, "Y"),
}
.and_then(|()| match with_i {
true => write!(f, "i"),
false => Ok(()),
})
}
}

View file

@ -1,6 +1,6 @@
[package]
name = "uu_od"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "od ~ (uutils) display formatted representation of input"
@ -19,7 +19,7 @@ byteorder = "1.3.2"
getopts = "0.2.18"
half = "1.6"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -24,7 +24,7 @@ pub trait HasError {
}
impl<'b> MultifileReader<'b> {
pub fn new<'a>(fnames: Vec<InputSource<'a>>) -> MultifileReader<'a> {
pub fn new(fnames: Vec<InputSource>) -> MultifileReader {
let mut mf = MultifileReader {
ni: fnames,
curr_file: None, // normally this means done; call next_file()

View file

@ -472,11 +472,11 @@ fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &Output
///
/// `skip_bytes` is the number of bytes skipped from the input
/// `read_bytes` is an optional limit to the number of bytes to read
fn open_input_peek_reader<'a>(
input_strings: &'a [String],
fn open_input_peek_reader(
input_strings: &[String],
skip_bytes: usize,
read_bytes: Option<usize>,
) -> PeekReader<PartialReader<MultifileReader<'a>>> {
) -> PeekReader<PartialReader<MultifileReader>> {
// should return "impl PeekRead + Read + HasError" when supported in (stable) rust
let inputs = input_strings
.iter()

View file

@ -1,6 +1,6 @@
[package]
name = "uu_paste"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "paste ~ (uutils) merge lines from inputs"
@ -15,8 +15,8 @@ edition = "2018"
path = "src/paste.rs"
[dependencies]
getopts = "0.2.18"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
clap = "2.33.3"
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -10,73 +10,82 @@
#[macro_use]
extern crate uucore;
use clap::{App, Arg};
use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read};
use std::iter::repeat;
use std::path::Path;
static NAME: &str = "paste";
static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Write lines consisting of the sequentially corresponding lines from each
FILE, separated by TABs, to standard output.";
mod options {
pub const DELIMITER: &str = "delimiters";
pub const SERIAL: &str = "serial";
pub const FILE: &str = "file";
}
// Wraps BufReader and stdin
fn read_line<R: Read>(
reader: Option<&mut BufReader<R>>,
buf: &mut String,
) -> std::io::Result<usize> {
match reader {
Some(reader) => reader.read_line(buf),
None => stdin().read_line(buf),
}
}
pub fn uumain(args: impl uucore::Args) -> i32 {
let args = args.collect_str();
let matches = App::new(executable!())
.version(VERSION)
.about(ABOUT)
.arg(
Arg::with_name(options::SERIAL)
.long(options::SERIAL)
.short("s")
.help("paste one file at a time instead of in parallel"),
)
.arg(
Arg::with_name(options::DELIMITER)
.long(options::DELIMITER)
.short("d")
.help("reuse characters from LIST instead of TABs")
.value_name("LIST")
.default_value("\t")
.hide_default_value(true),
)
.arg(
Arg::with_name(options::FILE)
.value_name("FILE")
.multiple(true)
.default_value("-"),
)
.get_matches_from(args);
let mut opts = getopts::Options::new();
opts.optflag(
"s",
"serial",
"paste one file at a time instead of in parallel",
);
opts.optopt(
"d",
"delimiters",
"reuse characters from LIST instead of TABs",
"LIST",
);
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(e) => crash!(1, "{}", e),
};
if matches.opt_present("help") {
let msg = format!(
"{0} {1}
Usage:
{0} [OPTION]... [FILE]...
Write lines consisting of the sequentially corresponding lines from each
FILE, separated by TABs, to standard output.",
NAME, VERSION
);
print!("{}", opts.usage(&msg));
} else if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
} else {
let serial = matches.opt_present("serial");
let delimiters = matches
.opt_str("delimiters")
.unwrap_or_else(|| "\t".to_owned());
paste(matches.free, serial, delimiters);
}
let serial = matches.is_present(options::SERIAL);
let delimiters = matches.value_of(options::DELIMITER).unwrap().to_owned();
let files = matches
.values_of(options::FILE)
.unwrap()
.map(|s| s.to_owned())
.collect();
paste(files, serial, delimiters);
0
}
fn paste(filenames: Vec<String>, serial: bool, delimiters: String) {
let mut files: Vec<BufReader<Box<dyn Read>>> = filenames
let mut files: Vec<_> = filenames
.into_iter()
.map(|name| {
BufReader::new(if name == "-" {
Box::new(stdin()) as Box<dyn Read>
if name == "-" {
None
} else {
let r = crash_if_err!(1, File::open(Path::new(&name)));
Box::new(r) as Box<dyn Read>
})
Some(BufReader::new(r))
}
})
.collect();
@ -91,7 +100,7 @@ fn paste(filenames: Vec<String>, serial: bool, delimiters: String) {
let mut output = String::new();
loop {
let mut line = String::new();
match file.read_line(&mut line) {
match read_line(file.as_mut(), &mut line) {
Ok(0) => break,
Ok(_) => {
output.push_str(line.trim_end());
@ -113,7 +122,7 @@ fn paste(filenames: Vec<String>, serial: bool, delimiters: String) {
eof_count += 1;
} else {
let mut line = String::new();
match file.read_line(&mut line) {
match read_line(file.as_mut(), &mut line) {
Ok(0) => {
eof[i] = true;
eof_count += 1;

View file

@ -1,6 +1,6 @@
[package]
name = "uu_pathchk"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "pathchk ~ (uutils) diagnose invalid or non-portable PATHNAME"
@ -17,7 +17,7 @@ path = "src/pathchk.rs"
[dependencies]
getopts = "0.2.18"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_pinky"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "pinky ~ (uutils) display user information"
@ -15,7 +15,7 @@ edition = "2018"
path = "src/pinky.rs"
[dependencies]
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["utmpx", "entries"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["utmpx", "entries"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_printenv"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "printenv ~ (uutils) display value of environment VAR"
@ -16,7 +16,7 @@ path = "src/printenv.rs"
[dependencies]
clap = "2.33"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_printf"
version = "0.0.3"
version = "0.0.4"
authors = [
"Nathan Ross",
"uutils developers",
@ -19,7 +19,7 @@ path = "src/printf.rs"
[dependencies]
itertools = "0.8.0"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -52,8 +52,7 @@ fn get_primitive_hex(
last_dec_place: usize,
capitalized: bool,
) -> FormatPrimitive {
let mut f: FormatPrimitive = Default::default();
f.prefix = Some(String::from(if inprefix.sign == -1 { "-0x" } else { "0x" }));
let prefix = Some(String::from(if inprefix.sign == -1 { "-0x" } else { "0x" }));
// assign the digits before and after the decimal points
// to separate slices. If no digits after decimal point,
@ -97,7 +96,7 @@ fn get_primitive_hex(
// conversion. The best way to do it is to just convert the floatnum
// directly to base 2 and then at the end translate back to hex.
let mantissa = 0;
f.suffix = Some({
let suffix = Some({
let ind = if capitalized { "P" } else { "p" };
if mantissa >= 0 {
format!("{}+{}", ind, mantissa)
@ -105,7 +104,11 @@ fn get_primitive_hex(
format!("{}{}", ind, mantissa)
}
});
f
FormatPrimitive {
prefix,
suffix,
..Default::default()
}
}
fn to_hex(src: &str, before_decimal: bool) -> String {

View file

@ -198,9 +198,10 @@ impl Formatter for Intf {
// We always will have a format primitive to return
Some(if convert_hints.len_digits == 0 || convert_hints.is_zero {
// if non-digit or end is reached before a non-zero digit
let mut fmt_prim: FormatPrimitive = Default::default();
fmt_prim.pre_decimal = Some(String::from("0"));
fmt_prim
FormatPrimitive {
pre_decimal: Some(String::from("0")),
..Default::default()
}
} else if !convert_hints.past_max {
// if the number is or may be below the bounds limit
let radix_out = match *field.field_char {

View file

@ -1,6 +1,6 @@
[package]
name = "uu_ptx"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "ptx ~ (uutils) display a permuted index of input"
@ -21,7 +21,7 @@ libc = "0.2.42"
memchr = "2.2.0"
regex = "1.0.1"
regex-syntax = "0.6.7"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -95,12 +95,21 @@ impl WordFilter {
if matches.opt_present("b") {
crash!(1, "-b not implemented yet");
}
let reg = if matches.opt_present("W") {
matches.opt_str("W").expect("parsing options failed!")
} else if config.gnu_ext {
"\\w+".to_owned()
// Ignore empty string regex from cmd-line-args
let arg_reg: Option<String> = if matches.opt_present("W") {
matches.opt_str("W").filter(|reg| !reg.is_empty())
} else {
"[^ \t\n]+".to_owned()
None
};
let reg = match arg_reg {
Some(arg_reg) => arg_reg,
None => {
if config.gnu_ext {
"\\w+".to_owned()
} else {
"[^ \t\n]+".to_owned()
}
}
};
WordFilter {
only_specified: o,

View file

@ -1,6 +1,6 @@
[package]
name = "uu_pwd"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "pwd ~ (uutils) display current working directory"
@ -16,7 +16,7 @@ path = "src/pwd.rs"
[dependencies]
clap = "2.33"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_readlink"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "readlink ~ (uutils) display resolved path of PATHNAME"
@ -17,7 +17,7 @@ path = "src/readlink.rs"
[dependencies]
clap = "2.33"
libc = "0.2.42"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_realpath"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "realpath ~ (uutils) display resolved absolute path of PATHNAME"
@ -16,7 +16,7 @@ path = "src/realpath.rs"
[dependencies]
clap = "2.33"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -67,7 +67,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let paths: Vec<PathBuf> = matches
.values_of(ARG_FILES)
.unwrap()
.map(|path| PathBuf::from(path))
.map(PathBuf::from)
.collect();
let strip = matches.is_present(OPT_STRIP);

View file

@ -1,6 +1,6 @@
[package]
name = "uu_relpath"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "relpath ~ (uutils) display relative path of PATHNAME_TO from PATHNAME_FROM"
@ -16,7 +16,7 @@ path = "src/relpath.rs"
[dependencies]
getopts = "0.2.18"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore", features=["fs"] }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

View file

@ -1,6 +1,6 @@
[package]
name = "uu_rm"
version = "0.0.3"
version = "0.0.4"
authors = ["uutils developers"]
license = "MIT"
description = "rm ~ (uutils) remove PATHNAME"
@ -18,7 +18,7 @@ path = "src/rm.rs"
clap = "2.33"
walkdir = "2.2"
remove_dir_all = "0.5.1"
uucore = { version=">=0.0.6", package="uucore", path="../../uucore" }
uucore = { version=">=0.0.7", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[[bin]]

Some files were not shown because too many files have changed in this diff Show more