mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 19:47:45 +00:00
Merge branch 'main' into cp-lb
This commit is contained in:
commit
63cf0d20b4
130 changed files with 2194 additions and 1531 deletions
15
.github/workflows/CICD.yml
vendored
15
.github/workflows/CICD.yml
vendored
|
@ -5,7 +5,7 @@ name: CICD
|
||||||
# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain
|
# spell-checker:ignore (jargon) SHAs deps dequote softprops subshell toolchain
|
||||||
# spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy
|
# spell-checker:ignore (names) CodeCOV MacOS MinGW Peltoche rivy
|
||||||
# spell-checker:ignore (shell/tools) choco clippy dmake dpkg esac fakeroot gmake grcov halium lcov libssl mkdir popd printf pushd rsync rustc rustfmt rustup shopt xargs
|
# spell-checker:ignore (shell/tools) choco clippy dmake dpkg esac fakeroot gmake grcov halium lcov libssl mkdir popd printf pushd rsync rustc rustfmt rustup shopt xargs
|
||||||
# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend pell runtest tempfile testsuite uutils DESTDIR sizemulti
|
# spell-checker:ignore (misc) aarch alnum armhf bindir busytest coreutils gnueabihf issuecomment maint nullglob onexitbegin onexitend pell runtest tempfile testsuite uutils DESTDIR sizemulti Swatinem
|
||||||
|
|
||||||
# ToDO: [2021-06; rivy] change from `cargo-tree` to `cargo tree` once MSRV is >= 1.45
|
# ToDO: [2021-06; rivy] change from `cargo-tree` to `cargo tree` once MSRV is >= 1.45
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ jobs:
|
||||||
- { os: windows-latest , features: feat_os_windows }
|
- { os: windows-latest , features: feat_os_windows }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize workflow variables
|
- name: Initialize workflow variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -94,6 +95,7 @@ jobs:
|
||||||
- { os: ubuntu-latest , features: feat_os_unix }
|
- { os: ubuntu-latest , features: feat_os_unix }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize workflow variables
|
- name: Initialize workflow variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -157,6 +159,7 @@ jobs:
|
||||||
- { os: windows-latest , features: feat_os_windows }
|
- { os: windows-latest , features: feat_os_windows }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize workflow variables
|
- name: Initialize workflow variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -214,6 +217,7 @@ jobs:
|
||||||
- { os: ubuntu-latest , features: feat_os_unix }
|
- { os: ubuntu-latest , features: feat_os_unix }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize workflow variables
|
- name: Initialize workflow variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -265,6 +269,7 @@ jobs:
|
||||||
# - { os: windows-latest , features: feat_os_windows }
|
# - { os: windows-latest , features: feat_os_windows }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize workflow variables
|
- name: Initialize workflow variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -309,6 +314,7 @@ jobs:
|
||||||
- { os: ubuntu-latest , features: feat_os_unix }
|
- { os: ubuntu-latest , features: feat_os_unix }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize workflow variables
|
- name: Initialize workflow variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -385,6 +391,7 @@ jobs:
|
||||||
- { os: ubuntu-latest , features: feat_os_unix }
|
- { os: ubuntu-latest , features: feat_os_unix }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Install `rust` toolchain
|
- name: Install `rust` toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
|
@ -409,6 +416,7 @@ jobs:
|
||||||
- { os: ubuntu-latest , features: feat_os_unix }
|
- { os: ubuntu-latest , features: feat_os_unix }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Install `rust` toolchain
|
- name: Install `rust` toolchain
|
||||||
uses: actions-rs/toolchain@v1
|
uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
|
@ -436,6 +444,7 @@ jobs:
|
||||||
- { os: ubuntu-latest , features: feat_os_unix }
|
- { os: ubuntu-latest , features: feat_os_unix }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
@ -497,6 +506,7 @@ jobs:
|
||||||
- { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows }
|
- { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize workflow variables
|
- name: Initialize workflow variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -745,6 +755,7 @@ jobs:
|
||||||
- { os: ubuntu-latest }
|
- { os: ubuntu-latest }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Install/setup prerequisites
|
- name: Install/setup prerequisites
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
@ -780,6 +791,7 @@ jobs:
|
||||||
mem: 2048
|
mem: 2048
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Prepare, build and test
|
- name: Prepare, build and test
|
||||||
## spell-checker:ignore (ToDO) sshfs usesh vmactions
|
## spell-checker:ignore (ToDO) sshfs usesh vmactions
|
||||||
uses: vmactions/freebsd-vm@v0.1.5
|
uses: vmactions/freebsd-vm@v0.1.5
|
||||||
|
@ -848,6 +860,7 @@ jobs:
|
||||||
- { os: windows-latest , features: windows }
|
- { os: windows-latest , features: windows }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
# - name: Reattach HEAD ## may be needed for accurate code coverage info
|
# - name: Reattach HEAD ## may be needed for accurate code coverage info
|
||||||
# run: git checkout ${{ github.head_ref }}
|
# run: git checkout ${{ github.head_ref }}
|
||||||
- name: Initialize workflow variables
|
- name: Initialize workflow variables
|
||||||
|
|
4
.github/workflows/FixPR.yml
vendored
4
.github/workflows/FixPR.yml
vendored
|
@ -1,5 +1,7 @@
|
||||||
name: FixPR
|
name: FixPR
|
||||||
|
|
||||||
|
# spell-checker:ignore Swatinem
|
||||||
|
|
||||||
# Trigger automated fixes for PRs being merged (with associated commits)
|
# Trigger automated fixes for PRs being merged (with associated commits)
|
||||||
|
|
||||||
# ToDO: [2021-06; rivy] change from `cargo-tree` to `cargo tree` once MSRV is >= 1.45
|
# ToDO: [2021-06; rivy] change from `cargo-tree` to `cargo tree` once MSRV is >= 1.45
|
||||||
|
@ -27,6 +29,7 @@ jobs:
|
||||||
- { os: ubuntu-latest , features: feat_os_unix }
|
- { os: ubuntu-latest , features: feat_os_unix }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize job variables
|
- name: Initialize job variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
@ -98,6 +101,7 @@ jobs:
|
||||||
- { os: ubuntu-latest , features: feat_os_unix }
|
- { os: ubuntu-latest , features: feat_os_unix }
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
- uses: Swatinem/rust-cache@v1
|
||||||
- name: Initialize job variables
|
- name: Initialize job variables
|
||||||
id: vars
|
id: vars
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
79
.github/workflows/GnuTests.yml
vendored
79
.github/workflows/GnuTests.yml
vendored
|
@ -67,7 +67,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
## Install dependencies
|
## Install dependencies
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install autoconf autopoint bison texinfo gperf gcc g++ gdb python-pyinotify jq
|
sudo apt-get install autoconf autopoint bison texinfo gperf gcc g++ gdb python-pyinotify jq valgrind libexpect-perl
|
||||||
- name: Add various locales
|
- name: Add various locales
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
|
@ -197,3 +197,80 @@ jobs:
|
||||||
else
|
else
|
||||||
echo "::warning ::Skipping test summary comparison; no prior reference summary is available."
|
echo "::warning ::Skipping test summary comparison; no prior reference summary is available."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
gnu_coverage:
|
||||||
|
name: Run GNU tests with coverage
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout code uutil
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
path: 'uutils'
|
||||||
|
- name: Checkout GNU coreutils
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: 'coreutils/coreutils'
|
||||||
|
path: 'gnu'
|
||||||
|
ref: 'v9.0'
|
||||||
|
submodules: recursive
|
||||||
|
- name: Install `rust` toolchain
|
||||||
|
uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly
|
||||||
|
default: true
|
||||||
|
profile: minimal # minimal component installation (ie, no documentation)
|
||||||
|
components: rustfmt
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install autoconf autopoint bison texinfo gperf gcc g++ gdb python-pyinotify jq valgrind libexpect-perl -y
|
||||||
|
- name: Add various locales
|
||||||
|
run: |
|
||||||
|
echo "Before:"
|
||||||
|
locale -a
|
||||||
|
## Some tests fail with 'cannot change locale (en_US.ISO-8859-1): No such file or directory'
|
||||||
|
## Some others need a French locale
|
||||||
|
sudo locale-gen
|
||||||
|
sudo locale-gen fr_FR
|
||||||
|
sudo locale-gen fr_FR.UTF-8
|
||||||
|
sudo update-locale
|
||||||
|
echo "After:"
|
||||||
|
locale -a
|
||||||
|
- name: Build binaries
|
||||||
|
env:
|
||||||
|
CARGO_INCREMENTAL: "0"
|
||||||
|
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
|
||||||
|
RUSTDOCFLAGS: "-Cpanic=abort"
|
||||||
|
run: |
|
||||||
|
cd uutils
|
||||||
|
UU_MAKE_PROFILE=debug bash util/build-gnu.sh
|
||||||
|
- name: Run GNU tests
|
||||||
|
run: bash uutils/util/run-gnu-test.sh
|
||||||
|
- name: "`grcov` ~ install"
|
||||||
|
uses: actions-rs/install@v0.1
|
||||||
|
with:
|
||||||
|
crate: grcov
|
||||||
|
version: latest
|
||||||
|
use-tool-cache: false
|
||||||
|
- name: Generate coverage data (via `grcov`)
|
||||||
|
id: coverage
|
||||||
|
run: |
|
||||||
|
## Generate coverage data
|
||||||
|
cd uutils
|
||||||
|
COVERAGE_REPORT_DIR="target/debug"
|
||||||
|
COVERAGE_REPORT_FILE="${COVERAGE_REPORT_DIR}/lcov.info"
|
||||||
|
mkdir -p "${COVERAGE_REPORT_DIR}"
|
||||||
|
sudo chown -R "$(whoami)" "${COVERAGE_REPORT_DIR}"
|
||||||
|
# display coverage files
|
||||||
|
grcov . --output-type files --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()" | sort --unique
|
||||||
|
# generate coverage report
|
||||||
|
grcov . --output-type lcov --output-path "${COVERAGE_REPORT_FILE}" --branch --ignore build.rs --ignore "vendor/*" --ignore "/*" --ignore "[a-zA-Z]:/*" --excl-br-line "^\s*((debug_)?assert(_eq|_ne)?!|#\[derive\()"
|
||||||
|
echo ::set-output name=report::${COVERAGE_REPORT_FILE}
|
||||||
|
- name: Upload coverage results (to Codecov.io)
|
||||||
|
uses: codecov/codecov-action@v2
|
||||||
|
with:
|
||||||
|
file: ${{ steps.coverage.outputs.report }}
|
||||||
|
flags: gnutests
|
||||||
|
name: gnutests
|
||||||
|
working-directory: uutils
|
||||||
|
|
60
Cargo.lock
generated
60
Cargo.lock
generated
|
@ -652,11 +652,12 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.1"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "683d6b536309245c849479fba3da410962a43ed8e51c26b729208ec0ac2798d0"
|
checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -719,13 +720,12 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.1"
|
version = "0.10.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b697d66081d42af4fba142d56918a3cb21dc8eb63372c6b85d14f44fb9c5979b"
|
checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer",
|
"block-buffer",
|
||||||
"crypto-common",
|
"crypto-common",
|
||||||
"generic-array",
|
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -957,9 +957,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
version = "0.2.0"
|
version = "0.4.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa"
|
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex-literal"
|
name = "hex-literal"
|
||||||
|
@ -1128,10 +1128,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md5"
|
name = "md-5"
|
||||||
version = "0.3.8"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79c56d6a0b07f9e19282511c83fc5b086364cbae4ba8c7d5f190c3d9b0425a48"
|
checksum = "658646b21e0b72f7866c7038ab086d3d5e1cd6271f060fd37defb241949d0582"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
|
@ -1331,9 +1334,9 @@ checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "onig"
|
name = "onig"
|
||||||
version = "4.3.3"
|
version = "6.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8518fcb2b1b8c2f45f0ad499df4fda6087fc3475ca69a185c173b8315d2fb383"
|
checksum = "67ddfe2c93bb389eea6e6d713306880c7f6dcc99a75b659ce145d962c861b225"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -1343,9 +1346,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "onig_sys"
|
name = "onig_sys"
|
||||||
version = "69.1.0"
|
version = "69.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "388410bf5fa341f10e58e6db3975f4bea1ac30247dd79d37a9e5ced3cb4cc3b0"
|
checksum = "5dd3eee045c84695b53b20255bb7317063df090b68e18bfac0abb6c39cf7f33e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
|
@ -1807,6 +1810,12 @@ dependencies = [
|
||||||
"webpki",
|
"webpki",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -1880,9 +1889,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04cc229fb94bcb689ffc39bd4ded842f6ff76885efede7c6d1ffb62582878bea"
|
checksum = "c77f4e7f65455545c2153c1253d25056825e77ee2533f0e41deb65a93a34852f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
|
@ -1891,9 +1900,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.1"
|
version = "0.10.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99c3bd8169c58782adad9290a9af5939994036b76187f7b4f0e6de91dbbfc0ec"
|
checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
|
@ -1902,9 +1911,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha3"
|
name = "sha3"
|
||||||
version = "0.10.0"
|
version = "0.10.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "31f935e31cf406e8c0e96c2815a5516181b7004ae8c5f296293221e9b1e356bd"
|
checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
"keccak",
|
"keccak",
|
||||||
|
@ -2000,19 +2009,20 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum"
|
name = "strum"
|
||||||
version = "0.21.0"
|
version = "0.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2"
|
checksum = "cae14b91c7d11c9a851d3fbc80a963198998c2a64eec840477fa92d8ce9b70bb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "strum_macros"
|
name = "strum_macros"
|
||||||
version = "0.21.1"
|
version = "0.23.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec"
|
checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote 1.0.14",
|
"quote 1.0.14",
|
||||||
|
"rustversion",
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2617,7 +2627,7 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
"hex",
|
"hex",
|
||||||
"libc",
|
"libc",
|
||||||
"md5",
|
"md-5",
|
||||||
"memchr 2.4.1",
|
"memchr 2.4.1",
|
||||||
"regex",
|
"regex",
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
|
|
|
@ -21,7 +21,7 @@ Running GNU tests
|
||||||
At the end you should have uutils, gnu and gnulib checked out next to each other.
|
At the end you should have uutils, gnu and gnulib checked out next to each other.
|
||||||
|
|
||||||
- Run `cd uutils && ./util/build-gnu.sh && cd ..` to get everything ready (this may take a while)
|
- Run `cd uutils && ./util/build-gnu.sh && cd ..` to get everything ready (this may take a while)
|
||||||
- Finally, you can run `tests with bash uutils/util/run-gnu-test.sh <test>`. Instead of `<test>` insert the test you want to run, e.g. `tests/misc/wc-proc`.
|
- Finally, you can run tests with `bash uutils/util/run-gnu-test.sh <test>`. Instead of `<test>` insert the test you want to run, e.g. `tests/misc/wc-proc.sh`.
|
||||||
|
|
||||||
|
|
||||||
Code Coverage Report Generation
|
Code Coverage Report Generation
|
||||||
|
@ -33,7 +33,7 @@ Code coverage report can be generated using [grcov](https://github.com/mozilla/g
|
||||||
|
|
||||||
### Using Nightly Rust
|
### Using Nightly Rust
|
||||||
|
|
||||||
To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-cc) coverage report
|
To generate [gcov-based](https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project) coverage report
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ export CARGO_INCREMENTAL=0
|
$ export CARGO_INCREMENTAL=0
|
||||||
|
|
|
@ -94,7 +94,7 @@ fn write_usage(w: &mut impl Write, app: &mut App, name: &str) -> io::Result<()>
|
||||||
.filter(|l| !l.is_empty())
|
.filter(|l| !l.is_empty())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("\n");
|
.join("\n");
|
||||||
usage = usage.replace(app.get_name(), name);
|
usage = usage.replace(uucore::execution_phrase(), name);
|
||||||
writeln!(w, "{}", usage)?;
|
writeln!(w, "{}", usage)?;
|
||||||
writeln!(w, "```")
|
writeln!(w, "```")
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ fn write_options(w: &mut impl Write, app: &App) -> io::Result<()> {
|
||||||
writeln!(
|
writeln!(
|
||||||
w,
|
w,
|
||||||
"<dd>\n\n{}\n\n</dd>",
|
"<dd>\n\n{}\n\n</dd>",
|
||||||
arg.get_help().unwrap_or_default().replace("\n", "<br />")
|
arg.get_help().unwrap_or_default().replace('\n', "<br />")
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
writeln!(w, "</dl>\n")
|
writeln!(w, "</dl>\n")
|
||||||
|
|
|
@ -22,16 +22,13 @@ to attempt to recover from any other non-alphabet bytes in the
|
||||||
encoded stream.
|
encoded stream.
|
||||||
";
|
";
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "{} [OPTION]... [FILE]";
|
||||||
format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let format = Format::Base32;
|
let format = Format::Base32;
|
||||||
let usage = usage();
|
|
||||||
|
|
||||||
let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?;
|
let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, USAGE)?;
|
||||||
|
|
||||||
// Create a reference to stdin so we can return a locked stdin from
|
// Create a reference to stdin so we can return a locked stdin from
|
||||||
// parse_base_cmd_args
|
// parse_base_cmd_args
|
||||||
|
@ -48,5 +45,5 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
base_common::base_app(ABOUT)
|
base_common::base_app(ABOUT, USAGE)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::io::{stdout, Read, Write};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::encoding::{wrap_print, Data, Format};
|
use uucore::encoding::{wrap_print, Data, Format};
|
||||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, Stdin};
|
use std::io::{BufReader, Stdin};
|
||||||
|
@ -86,17 +86,18 @@ impl Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_base_cmd_args(args: impl uucore::Args, about: &str, usage: &str) -> UResult<Config> {
|
pub fn parse_base_cmd_args(args: impl uucore::Args, about: &str, usage: &str) -> UResult<Config> {
|
||||||
let app = base_app(about).override_usage(usage);
|
let app = base_app(about, usage);
|
||||||
let arg_list = args
|
let arg_list = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
Config::from(&app.get_matches_from(arg_list))
|
Config::from(&app.get_matches_from(arg_list))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn base_app(about: &str) -> App {
|
pub fn base_app<'a>(about: &'a str, usage: &'a str) -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(about)
|
.about(about)
|
||||||
|
.override_usage(format_usage(usage))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
// Format arguments.
|
// Format arguments.
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -23,16 +23,13 @@ to attempt to recover from any other non-alphabet bytes in the
|
||||||
encoded stream.
|
encoded stream.
|
||||||
";
|
";
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "{0} [OPTION]... [FILE]";
|
||||||
format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let format = Format::Base64;
|
let format = Format::Base64;
|
||||||
let usage = usage();
|
|
||||||
|
|
||||||
let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, &usage)?;
|
let config: base_common::Config = base_common::parse_base_cmd_args(args, ABOUT, USAGE)?;
|
||||||
|
|
||||||
// Create a reference to stdin so we can return a locked stdin from
|
// Create a reference to stdin so we can return a locked stdin from
|
||||||
// parse_base_cmd_args
|
// parse_base_cmd_args
|
||||||
|
|
|
@ -11,18 +11,13 @@ use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use std::path::{is_separator, PathBuf};
|
use std::path::{is_separator, PathBuf};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, UUsageError};
|
use uucore::error::{UResult, UUsageError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static SUMMARY: &str = "Print NAME with any leading directory components removed
|
static SUMMARY: &str = "Print NAME with any leading directory components removed
|
||||||
If specified, also remove a trailing SUFFIX";
|
If specified, also remove a trailing SUFFIX";
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "{} NAME [SUFFIX]
|
||||||
format!(
|
{} OPTION... NAME...";
|
||||||
"{0} NAME [SUFFIX]
|
|
||||||
{0} OPTION... NAME...",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static MULTIPLE: &str = "multiple";
|
pub static MULTIPLE: &str = "multiple";
|
||||||
|
@ -36,11 +31,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
let usage = usage();
|
|
||||||
//
|
//
|
||||||
// Argument parsing
|
// Argument parsing
|
||||||
//
|
//
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
// too few arguments
|
// too few arguments
|
||||||
if !matches.is_present(options::NAME) {
|
if !matches.is_present(options::NAME) {
|
||||||
|
@ -97,6 +91,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::MULTIPLE)
|
Arg::new(options::MULTIPLE)
|
||||||
|
|
|
@ -38,12 +38,10 @@ const ENCODINGS: &[(&str, Format)] = &[
|
||||||
("z85", Format::Z85),
|
("z85", Format::Z85),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "{} [OPTION]... [FILE]";
|
||||||
format!("{0} [OPTION]... [FILE]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
let mut app = base_common::base_app(ABOUT);
|
let mut app = base_common::base_app(ABOUT, USAGE);
|
||||||
for encoding in ENCODINGS {
|
for encoding in ENCODINGS {
|
||||||
app = app.arg(Arg::new(encoding.0).long(encoding.0));
|
app = app.arg(Arg::new(encoding.0).long(encoding.0));
|
||||||
}
|
}
|
||||||
|
@ -51,8 +49,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cmd_args(args: impl uucore::Args) -> UResult<(Config, Format)> {
|
fn parse_cmd_args(args: impl uucore::Args) -> UResult<(Config, Format)> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(
|
|
||||||
args.collect_str(InvalidEncodingHandling::ConvertLossy)
|
args.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any(),
|
.accept_any(),
|
||||||
);
|
);
|
||||||
|
|
|
@ -36,10 +36,10 @@ use std::net::Shutdown;
|
||||||
use std::os::unix::fs::FileTypeExt;
|
use std::os::unix::fs::FileTypeExt;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use unix_socket::UnixStream;
|
use unix_socket::UnixStream;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static NAME: &str = "cat";
|
static NAME: &str = "cat";
|
||||||
static SYNTAX: &str = "[OPTION]... [FILE]...";
|
static USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
static SUMMARY: &str = "Concatenate FILE(s), or standard input, to standard output
|
static SUMMARY: &str = "Concatenate FILE(s), or standard input, to standard output
|
||||||
With no FILE, or when FILE is -, read standard input.";
|
With no FILE, or when FILE is -, read standard input.";
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(SYNTAX)
|
.override_usage(format_usage(USAGE))
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#![allow(clippy::upper_case_acronyms)]
|
#![allow(clippy::upper_case_acronyms)]
|
||||||
|
|
||||||
use uucore::error::{UResult, USimpleError, UUsageError};
|
use uucore::error::{UResult, USimpleError, UUsageError};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::{display::Quotable, show_error, show_warning};
|
use uucore::{display::Quotable, show_error, show_warning};
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg};
|
use clap::{App, AppSettings, Arg};
|
||||||
|
@ -22,6 +23,10 @@ use errors::*;
|
||||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
static ABOUT: &str = "Change the SELinux security context of each FILE to CONTEXT. \n\
|
static ABOUT: &str = "Change the SELinux security context of each FILE to CONTEXT. \n\
|
||||||
With --reference, change the security context of each FILE to that of RFILE.";
|
With --reference, change the security context of each FILE to that of RFILE.";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} [OPTION]... CONTEXT FILE... \n \
|
||||||
|
{} [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE... \n \
|
||||||
|
{} [OPTION]... --reference=RFILE FILE...";
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static VERBOSE: &str = "verbose";
|
pub static VERBOSE: &str = "verbose";
|
||||||
|
@ -52,20 +57,9 @@ pub mod options {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [OPTION]... CONTEXT FILE... \n \
|
|
||||||
{0} [OPTION]... [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE... \n \
|
|
||||||
{0} [OPTION]... --reference=RFILE FILE...",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = get_usage();
|
let config = uu_app();
|
||||||
|
|
||||||
let config = uu_app().override_usage(usage.as_ref());
|
|
||||||
|
|
||||||
let options = match parse_command_line(config, args) {
|
let options = match parse_command_line(config, args) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
|
@ -164,6 +158,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(VERSION)
|
.version(VERSION)
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::dereference::DEREFERENCE)
|
Arg::new(options::dereference::DEREFERENCE)
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
pub use uucore::entries;
|
pub use uucore::entries;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::perms::{chown_base, options, IfFrom};
|
use uucore::perms::{chown_base, options, IfFrom};
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches};
|
use clap::{App, AppSettings, Arg, ArgMatches};
|
||||||
|
@ -20,12 +21,9 @@ use std::os::unix::fs::MetadataExt;
|
||||||
static ABOUT: &str = "Change the group of each FILE to GROUP.";
|
static ABOUT: &str = "Change the group of each FILE to GROUP.";
|
||||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
fn get_usage() -> String {
|
const USAGE: &str = "\
|
||||||
format!(
|
{} [OPTION]... GROUP FILE...\n \
|
||||||
"{0} [OPTION]... GROUP FILE...\n {0} [OPTION]... --reference=RFILE FILE...",
|
{} [OPTION]... --reference=RFILE FILE...";
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>, IfFrom)> {
|
fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>, IfFrom)> {
|
||||||
let dest_gid = if let Some(file) = matches.value_of(options::REFERENCE) {
|
let dest_gid = if let Some(file) = matches.value_of(options::REFERENCE) {
|
||||||
|
@ -53,21 +51,14 @@ fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>,
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = get_usage();
|
chown_base(uu_app(), args, options::ARG_GROUP, parse_gid_and_uid, true)
|
||||||
|
|
||||||
chown_base(
|
|
||||||
uu_app().override_usage(&usage[..]),
|
|
||||||
args,
|
|
||||||
options::ARG_GROUP,
|
|
||||||
parse_gid_and_uid,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(VERSION)
|
.version(VERSION)
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::verbosity::CHANGES)
|
Arg::new(options::verbosity::CHANGES)
|
||||||
|
|
|
@ -17,7 +17,7 @@ use uucore::fs::display_permissions_unix;
|
||||||
use uucore::libc::mode_t;
|
use uucore::libc::mode_t;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
use uucore::mode;
|
use uucore::mode;
|
||||||
use uucore::{show_error, InvalidEncodingHandling};
|
use uucore::{format_usage, show_error, InvalidEncodingHandling};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
static ABOUT: &str = "Change the mode of each FILE to MODE.
|
static ABOUT: &str = "Change the mode of each FILE to MODE.
|
||||||
|
@ -35,14 +35,10 @@ mod options {
|
||||||
pub const FILE: &str = "FILE";
|
pub const FILE: &str = "FILE";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "\
|
||||||
format!(
|
{} [OPTION]... MODE[,MODE]... FILE...
|
||||||
"{0} [OPTION]... MODE[,MODE]... FILE...
|
{} [OPTION]... OCTAL-MODE FILE...
|
||||||
or: {0} [OPTION]... OCTAL-MODE FILE...
|
{} [OPTION]... --reference=RFILE FILE...";
|
||||||
or: {0} [OPTION]... --reference=RFILE FILE...",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_long_usage() -> String {
|
fn get_long_usage() -> String {
|
||||||
String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
|
String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
|
||||||
|
@ -58,13 +54,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
// a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
|
// a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
|
||||||
let mode_had_minus_prefix = mode::strip_minus_from_mode(&mut args);
|
let mode_had_minus_prefix = mode::strip_minus_from_mode(&mut args);
|
||||||
|
|
||||||
let usage = usage();
|
|
||||||
let after_help = get_long_usage();
|
let after_help = get_long_usage();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&after_help[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let changes = matches.is_present(options::CHANGES);
|
let changes = matches.is_present(options::CHANGES);
|
||||||
let quiet = matches.is_present(options::QUIET);
|
let quiet = matches.is_present(options::QUIET);
|
||||||
|
@ -125,6 +117,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::CHANGES)
|
Arg::new(options::CHANGES)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
pub use uucore::entries::{self, Group, Locate, Passwd};
|
pub use uucore::entries::{self, Group, Locate, Passwd};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::perms::{chown_base, options, IfFrom};
|
use uucore::perms::{chown_base, options, IfFrom};
|
||||||
|
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
|
@ -20,12 +21,9 @@ use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
static ABOUT: &str = "change file owner and group";
|
static ABOUT: &str = "change file owner and group";
|
||||||
|
|
||||||
fn get_usage() -> String {
|
const USAGE: &str = "\
|
||||||
format!(
|
{} [OPTION]... [OWNER][:[GROUP]] FILE...
|
||||||
"{0} [OPTION]... [OWNER][:[GROUP]] FILE...\n{0} [OPTION]... --reference=RFILE FILE...",
|
{} [OPTION]... --reference=RFILE FILE...";
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>, IfFrom)> {
|
fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>, IfFrom)> {
|
||||||
let filter = if let Some(spec) = matches.value_of(options::FROM) {
|
let filter = if let Some(spec) = matches.value_of(options::FROM) {
|
||||||
|
@ -56,10 +54,8 @@ fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<(Option<u32>, Optio
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = get_usage();
|
|
||||||
|
|
||||||
chown_base(
|
chown_base(
|
||||||
uu_app().override_usage(&usage[..]),
|
uu_app(),
|
||||||
args,
|
args,
|
||||||
options::ARG_OWNER,
|
options::ARG_OWNER,
|
||||||
parse_gid_uid_and_filter,
|
parse_gid_uid_and_filter,
|
||||||
|
@ -71,6 +67,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::verbosity::CHANGES)
|
Arg::new(options::verbosity::CHANGES)
|
||||||
|
|
|
@ -17,10 +17,10 @@ use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use uucore::error::{set_exit_code, UResult};
|
use uucore::error::{set_exit_code, UResult};
|
||||||
use uucore::libc::{self, chroot, setgid, setgroups, setuid};
|
use uucore::libc::{self, chroot, setgid, setgroups, setuid};
|
||||||
use uucore::{entries, InvalidEncodingHandling};
|
use uucore::{entries, format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str = "Run COMMAND with root directory set to NEWROOT.";
|
static ABOUT: &str = "Run COMMAND with root directory set to NEWROOT.";
|
||||||
static SYNTAX: &str = "[OPTION]... NEWROOT [COMMAND [ARG]...]";
|
static USAGE: &str = "{} [OPTION]... NEWROOT [COMMAND [ARG]...]";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const NEWROOT: &str = "newroot";
|
pub const NEWROOT: &str = "newroot";
|
||||||
|
@ -95,7 +95,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.override_usage(SYNTAX)
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::NEWROOT)
|
Arg::new(options::NEWROOT)
|
||||||
|
|
|
@ -12,15 +12,15 @@ use std::io::{self, stdin, BufReader, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult};
|
use uucore::error::{FromIo, UResult};
|
||||||
use uucore::show;
|
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
use uucore::{format_usage, show};
|
||||||
|
|
||||||
// NOTE: CRC_TABLE_LEN *must* be <= 256 as we cast 0..CRC_TABLE_LEN to u8
|
// NOTE: CRC_TABLE_LEN *must* be <= 256 as we cast 0..CRC_TABLE_LEN to u8
|
||||||
const CRC_TABLE_LEN: usize = 256;
|
const CRC_TABLE_LEN: usize = 256;
|
||||||
const CRC_TABLE: [u32; CRC_TABLE_LEN] = generate_crc_table();
|
const CRC_TABLE: [u32; CRC_TABLE_LEN] = generate_crc_table();
|
||||||
|
|
||||||
const NAME: &str = "cksum";
|
const NAME: &str = "cksum";
|
||||||
const SYNTAX: &str = "[OPTIONS] [FILE]...";
|
const USAGE: &str = "{} [OPTIONS] [FILE]...";
|
||||||
const SUMMARY: &str = "Print CRC and size for each file";
|
const SUMMARY: &str = "Print CRC and size for each file";
|
||||||
|
|
||||||
const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] {
|
const fn generate_crc_table() -> [u32; CRC_TABLE_LEN] {
|
||||||
|
@ -145,7 +145,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.override_usage(SYNTAX)
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::FILE)
|
Arg::new(options::FILE)
|
||||||
|
|
|
@ -13,12 +13,13 @@ use std::io::{self, stdin, BufRead, BufReader, Stdin};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::error::FromIo;
|
use uucore::error::FromIo;
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
|
|
||||||
static ABOUT: &str = "compare two sorted files line by line";
|
static ABOUT: &str = "compare two sorted files line by line";
|
||||||
static LONG_HELP: &str = "";
|
static LONG_HELP: &str = "";
|
||||||
|
const USAGE: &str = "{} [OPTION]... FILE1 FILE2";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const COLUMN_1: &str = "1";
|
pub const COLUMN_1: &str = "1";
|
||||||
|
@ -30,10 +31,6 @@ mod options {
|
||||||
pub const FILE_2: &str = "FILE2";
|
pub const FILE_2: &str = "FILE2";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{} [OPTION]... FILE1 FILE2", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mkdelim(col: usize, opts: &ArgMatches) -> String {
|
fn mkdelim(col: usize, opts: &ArgMatches) -> String {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
let delim = opts.value_of(options::DELIMITER).unwrap();
|
let delim = opts.value_of(options::DELIMITER).unwrap();
|
||||||
|
@ -132,12 +129,11 @@ fn open_file(name: &str) -> io::Result<LineReader> {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
let filename1 = matches.value_of(options::FILE_1).unwrap();
|
let filename1 = matches.value_of(options::FILE_1).unwrap();
|
||||||
let filename2 = matches.value_of(options::FILE_2).unwrap();
|
let filename2 = matches.value_of(options::FILE_2).unwrap();
|
||||||
let mut f1 = open_file(filename1).map_err_context(|| filename1.to_string())?;
|
let mut f1 = open_file(filename1).map_err_context(|| filename1.to_string())?;
|
||||||
|
@ -152,6 +148,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::COLUMN_1)
|
Arg::new(options::COLUMN_1)
|
||||||
|
|
|
@ -19,6 +19,7 @@ extern crate quick_error;
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::fs::FileInformation;
|
use uucore::fs::FileInformation;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use winapi::um::fileapi::CreateFileW;
|
use winapi::um::fileapi::CreateFileW;
|
||||||
|
@ -29,6 +30,8 @@ use std::borrow::Cow;
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
use filetime::FileTime;
|
use filetime::FileTime;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use libc::mkfifo;
|
||||||
use quick_error::ResultExt;
|
use quick_error::ResultExt;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -42,6 +45,10 @@ use std::fs::OpenOptions;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{stdin, stdout, Write};
|
use std::io::{stdin, stdout, Write};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::fs::{FileTypeExt, PermissionsExt};
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::AsRawFd;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -54,9 +61,6 @@ use uucore::error::{set_exit_code, ExitCode, UError, UResult};
|
||||||
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
|
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
ioctl!(write ficlone with 0x94, 9; std::os::raw::c_int);
|
ioctl!(write ficlone with 0x94, 9; std::os::raw::c_int);
|
||||||
|
|
||||||
|
@ -149,7 +153,7 @@ pub type Target = PathBuf;
|
||||||
pub type TargetSlice = Path;
|
pub type TargetSlice = Path;
|
||||||
|
|
||||||
/// Specifies whether when overwrite files
|
/// Specifies whether when overwrite files
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum ClobberMode {
|
pub enum ClobberMode {
|
||||||
Force,
|
Force,
|
||||||
RemoveDestination,
|
RemoveDestination,
|
||||||
|
@ -157,7 +161,7 @@ pub enum ClobberMode {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies whether when overwrite files
|
/// Specifies whether when overwrite files
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||||
pub enum OverwriteMode {
|
pub enum OverwriteMode {
|
||||||
/// [Default] Always overwrite existing files
|
/// [Default] Always overwrite existing files
|
||||||
Clobber(ClobberMode),
|
Clobber(ClobberMode),
|
||||||
|
@ -230,14 +234,10 @@ static ABOUT: &str = "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.";
|
||||||
static LONG_HELP: &str = "";
|
static LONG_HELP: &str = "";
|
||||||
static EXIT_ERR: i32 = 1;
|
static EXIT_ERR: i32 = 1;
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "\
|
||||||
format!(
|
{} [OPTION]... [-T] SOURCE DEST
|
||||||
"{0} [OPTION]... [-T] SOURCE DEST
|
{} [OPTION]... SOURCE... DIRECTORY
|
||||||
{0} [OPTION]... SOURCE... DIRECTORY
|
{} [OPTION]... -t DIRECTORY SOURCE...";
|
||||||
{0} [OPTION]... -t DIRECTORY SOURCE...",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Argument constants
|
// Argument constants
|
||||||
mod options {
|
mod options {
|
||||||
|
@ -297,9 +297,17 @@ static DEFAULT_ATTRIBUTES: &[Attribute] = &[
|
||||||
];
|
];
|
||||||
|
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
|
const MODE_ARGS: &[&str] = &[
|
||||||
|
options::LINK,
|
||||||
|
options::REFLINK,
|
||||||
|
options::SYMBOLIC_LINK,
|
||||||
|
options::ATTRIBUTES_ONLY,
|
||||||
|
options::COPY_CONTENTS,
|
||||||
|
];
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(Arg::new(options::TARGET_DIRECTORY)
|
.arg(Arg::new(options::TARGET_DIRECTORY)
|
||||||
.short('t')
|
.short('t')
|
||||||
|
@ -316,17 +324,17 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.arg(Arg::new(options::INTERACTIVE)
|
.arg(Arg::new(options::INTERACTIVE)
|
||||||
.short('i')
|
.short('i')
|
||||||
.long(options::INTERACTIVE)
|
.long(options::INTERACTIVE)
|
||||||
.conflicts_with(options::NO_CLOBBER)
|
.overrides_with(options::NO_CLOBBER)
|
||||||
.help("ask before overwriting files"))
|
.help("ask before overwriting files"))
|
||||||
.arg(Arg::new(options::LINK)
|
.arg(Arg::new(options::LINK)
|
||||||
.short('l')
|
.short('l')
|
||||||
.long(options::LINK)
|
.long(options::LINK)
|
||||||
.overrides_with(options::REFLINK)
|
.overrides_with_all(MODE_ARGS)
|
||||||
.help("hard-link files instead of copying"))
|
.help("hard-link files instead of copying"))
|
||||||
.arg(Arg::new(options::NO_CLOBBER)
|
.arg(Arg::new(options::NO_CLOBBER)
|
||||||
.short('n')
|
.short('n')
|
||||||
.long(options::NO_CLOBBER)
|
.long(options::NO_CLOBBER)
|
||||||
.conflicts_with(options::INTERACTIVE)
|
.overrides_with(options::INTERACTIVE)
|
||||||
.help("don't overwrite a file that already exists"))
|
.help("don't overwrite a file that already exists"))
|
||||||
.arg(Arg::new(options::RECURSIVE)
|
.arg(Arg::new(options::RECURSIVE)
|
||||||
.short('r')
|
.short('r')
|
||||||
|
@ -346,8 +354,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.arg(Arg::new(options::SYMBOLIC_LINK)
|
.arg(Arg::new(options::SYMBOLIC_LINK)
|
||||||
.short('s')
|
.short('s')
|
||||||
.long(options::SYMBOLIC_LINK)
|
.long(options::SYMBOLIC_LINK)
|
||||||
.conflicts_with(options::LINK)
|
.overrides_with_all(MODE_ARGS)
|
||||||
.overrides_with(options::REFLINK)
|
|
||||||
.help("make symbolic links instead of copying"))
|
.help("make symbolic links instead of copying"))
|
||||||
.arg(Arg::new(options::FORCE)
|
.arg(Arg::new(options::FORCE)
|
||||||
.short('f')
|
.short('f')
|
||||||
|
@ -357,9 +364,9 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
Currently not implemented for Windows."))
|
Currently not implemented for Windows."))
|
||||||
.arg(Arg::new(options::REMOVE_DESTINATION)
|
.arg(Arg::new(options::REMOVE_DESTINATION)
|
||||||
.long(options::REMOVE_DESTINATION)
|
.long(options::REMOVE_DESTINATION)
|
||||||
.conflicts_with(options::FORCE)
|
.overrides_with(options::FORCE)
|
||||||
.help("remove each existing destination file before attempting to open it \
|
.help("remove each existing destination file before attempting to open it \
|
||||||
(contrast with --force). On Windows, current only works for writeable files."))
|
(contrast with --force). On Windows, currently only works for writeable files."))
|
||||||
.arg(backup_control::arguments::backup())
|
.arg(backup_control::arguments::backup())
|
||||||
.arg(backup_control::arguments::backup_no_args())
|
.arg(backup_control::arguments::backup_no_args())
|
||||||
.arg(backup_control::arguments::suffix())
|
.arg(backup_control::arguments::suffix())
|
||||||
|
@ -372,11 +379,11 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.long(options::REFLINK)
|
.long(options::REFLINK)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("WHEN")
|
.value_name("WHEN")
|
||||||
|
.overrides_with_all(MODE_ARGS)
|
||||||
.help("control clone/CoW copies. See below"))
|
.help("control clone/CoW copies. See below"))
|
||||||
.arg(Arg::new(options::ATTRIBUTES_ONLY)
|
.arg(Arg::new(options::ATTRIBUTES_ONLY)
|
||||||
.long(options::ATTRIBUTES_ONLY)
|
.long(options::ATTRIBUTES_ONLY)
|
||||||
.conflicts_with(options::COPY_CONTENTS)
|
.overrides_with_all(MODE_ARGS)
|
||||||
.overrides_with(options::REFLINK)
|
|
||||||
.help("Don't copy the file data, just the attributes"))
|
.help("Don't copy the file data, just the attributes"))
|
||||||
.arg(Arg::new(options::PRESERVE)
|
.arg(Arg::new(options::PRESERVE)
|
||||||
.long(options::PRESERVE)
|
.long(options::PRESERVE)
|
||||||
|
@ -386,7 +393,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.possible_values(PRESERVABLE_ATTRIBUTES)
|
.possible_values(PRESERVABLE_ATTRIBUTES)
|
||||||
.min_values(0)
|
.min_values(0)
|
||||||
.value_name("ATTR_LIST")
|
.value_name("ATTR_LIST")
|
||||||
.conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::NO_PRESERVE])
|
.overrides_with_all(&[options::ARCHIVE, options::PRESERVE_DEFAULT_ATTRIBUTES, options::NO_PRESERVE])
|
||||||
// -d sets this option
|
// -d sets this option
|
||||||
// --archive sets this option
|
// --archive sets this option
|
||||||
.help("Preserve the specified attributes (default: mode, ownership (unix only), timestamps), \
|
.help("Preserve the specified attributes (default: mode, ownership (unix only), timestamps), \
|
||||||
|
@ -394,13 +401,13 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.arg(Arg::new(options::PRESERVE_DEFAULT_ATTRIBUTES)
|
.arg(Arg::new(options::PRESERVE_DEFAULT_ATTRIBUTES)
|
||||||
.short('p')
|
.short('p')
|
||||||
.long(options::PRESERVE_DEFAULT_ATTRIBUTES)
|
.long(options::PRESERVE_DEFAULT_ATTRIBUTES)
|
||||||
.conflicts_with_all(&[options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE])
|
.overrides_with_all(&[options::PRESERVE, options::NO_PRESERVE, options::ARCHIVE])
|
||||||
.help("same as --preserve=mode,ownership(unix only),timestamps"))
|
.help("same as --preserve=mode,ownership(unix only),timestamps"))
|
||||||
.arg(Arg::new(options::NO_PRESERVE)
|
.arg(Arg::new(options::NO_PRESERVE)
|
||||||
.long(options::NO_PRESERVE)
|
.long(options::NO_PRESERVE)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("ATTR_LIST")
|
.value_name("ATTR_LIST")
|
||||||
.conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::ARCHIVE])
|
.overrides_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::ARCHIVE])
|
||||||
.help("don't preserve the specified attributes"))
|
.help("don't preserve the specified attributes"))
|
||||||
.arg(Arg::new(options::PARENTS)
|
.arg(Arg::new(options::PARENTS)
|
||||||
.long(options::PARENTS)
|
.long(options::PARENTS)
|
||||||
|
@ -409,18 +416,18 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.arg(Arg::new(options::NO_DEREFERENCE)
|
.arg(Arg::new(options::NO_DEREFERENCE)
|
||||||
.short('P')
|
.short('P')
|
||||||
.long(options::NO_DEREFERENCE)
|
.long(options::NO_DEREFERENCE)
|
||||||
.conflicts_with(options::DEREFERENCE)
|
.overrides_with(options::DEREFERENCE)
|
||||||
// -d sets this option
|
// -d sets this option
|
||||||
.help("never follow symbolic links in SOURCE"))
|
.help("never follow symbolic links in SOURCE"))
|
||||||
.arg(Arg::new(options::DEREFERENCE)
|
.arg(Arg::new(options::DEREFERENCE)
|
||||||
.short('L')
|
.short('L')
|
||||||
.long(options::DEREFERENCE)
|
.long(options::DEREFERENCE)
|
||||||
.conflicts_with(options::NO_DEREFERENCE)
|
.overrides_with(options::NO_DEREFERENCE)
|
||||||
.help("always follow symbolic links in SOURCE"))
|
.help("always follow symbolic links in SOURCE"))
|
||||||
.arg(Arg::new(options::ARCHIVE)
|
.arg(Arg::new(options::ARCHIVE)
|
||||||
.short('a')
|
.short('a')
|
||||||
.long(options::ARCHIVE)
|
.long(options::ARCHIVE)
|
||||||
.conflicts_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::NO_PRESERVE])
|
.overrides_with_all(&[options::PRESERVE_DEFAULT_ATTRIBUTES, options::PRESERVE, options::NO_PRESERVE])
|
||||||
.help("Same as -dR --preserve=all"))
|
.help("Same as -dR --preserve=all"))
|
||||||
.arg(Arg::new(options::NO_DEREFERENCE_PRESERVE_LINKS)
|
.arg(Arg::new(options::NO_DEREFERENCE_PRESERVE_LINKS)
|
||||||
.short('d')
|
.short('d')
|
||||||
|
@ -433,7 +440,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
// TODO: implement the following args
|
// TODO: implement the following args
|
||||||
.arg(Arg::new(options::COPY_CONTENTS)
|
.arg(Arg::new(options::COPY_CONTENTS)
|
||||||
.long(options::COPY_CONTENTS)
|
.long(options::COPY_CONTENTS)
|
||||||
.conflicts_with(options::ATTRIBUTES_ONLY)
|
.overrides_with(options::ATTRIBUTES_ONLY)
|
||||||
.help("NotImplemented: copy contents of special files when recursive"))
|
.help("NotImplemented: copy contents of special files when recursive"))
|
||||||
.arg(Arg::new(options::SPARSE)
|
.arg(Arg::new(options::SPARSE)
|
||||||
.long(options::SPARSE)
|
.long(options::SPARSE)
|
||||||
|
@ -456,14 +463,12 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let matches = uu_app()
|
let matches = uu_app()
|
||||||
.after_help(&*format!(
|
.after_help(&*format!(
|
||||||
"{}\n{}",
|
"{}\n{}",
|
||||||
LONG_HELP,
|
LONG_HELP,
|
||||||
backup_control::BACKUP_CONTROL_LONG_HELP
|
backup_control::BACKUP_CONTROL_LONG_HELP
|
||||||
))
|
))
|
||||||
.override_usage(&usage[..])
|
|
||||||
.get_matches_from(args);
|
.get_matches_from(args);
|
||||||
|
|
||||||
let options = Options::from_matches(&matches)?;
|
let options = Options::from_matches(&matches)?;
|
||||||
|
@ -969,6 +974,16 @@ fn copy_directory(
|
||||||
return copy_file(root, target, options, symlinked_files);
|
return copy_file(root, target, options, symlinked_files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if root is a prefix of target
|
||||||
|
if path_has_prefix(target, root)? {
|
||||||
|
return Err(format!(
|
||||||
|
"cannot copy a directory, {}, into itself, {}",
|
||||||
|
root.quote(),
|
||||||
|
target.quote()
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
|
||||||
let current_dir =
|
let current_dir =
|
||||||
env::current_dir().unwrap_or_else(|e| crash!(1, "failed to get current directory {}", e));
|
env::current_dir().unwrap_or_else(|e| crash!(1, "failed to get current directory {}", e));
|
||||||
|
|
||||||
|
@ -1388,12 +1403,23 @@ fn copy_helper(
|
||||||
let parent = dest.parent().unwrap_or(dest);
|
let parent = dest.parent().unwrap_or(dest);
|
||||||
fs::create_dir_all(parent)?;
|
fs::create_dir_all(parent)?;
|
||||||
}
|
}
|
||||||
let is_symlink = fs::symlink_metadata(&source)?.file_type().is_symlink();
|
|
||||||
|
let file_type = fs::symlink_metadata(&source)?.file_type();
|
||||||
|
let is_symlink = file_type.is_symlink();
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
let is_fifo = file_type.is_fifo();
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
let is_fifo = false;
|
||||||
|
|
||||||
if source.as_os_str() == "/dev/null" {
|
if source.as_os_str() == "/dev/null" {
|
||||||
/* workaround a limitation of fs::copy
|
/* workaround a limitation of fs::copy
|
||||||
* https://github.com/rust-lang/rust/issues/79390
|
* https://github.com/rust-lang/rust/issues/79390
|
||||||
*/
|
*/
|
||||||
File::create(dest).context(dest.display().to_string())?;
|
File::create(dest).context(dest.display().to_string())?;
|
||||||
|
} else if is_fifo && options.recursive {
|
||||||
|
#[cfg(unix)]
|
||||||
|
copy_fifo(dest, options.overwrite)?;
|
||||||
} else if is_symlink {
|
} else if is_symlink {
|
||||||
copy_link(source, dest, symlinked_files)?;
|
copy_link(source, dest, symlinked_files)?;
|
||||||
} else if options.reflink_mode != ReflinkMode::Never {
|
} else if options.reflink_mode != ReflinkMode::Never {
|
||||||
|
@ -1413,6 +1439,23 @@ fn copy_helper(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "Copies" a FIFO by creating a new one. This workaround is because Rust's
|
||||||
|
// built-in fs::copy does not handle FIFOs (see rust-lang/rust/issues/79390).
|
||||||
|
#[cfg(unix)]
|
||||||
|
fn copy_fifo(dest: &Path, overwrite: OverwriteMode) -> CopyResult<()> {
|
||||||
|
if dest.exists() {
|
||||||
|
overwrite.verify(dest)?;
|
||||||
|
fs::remove_file(&dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = CString::new(dest.as_os_str().as_bytes()).unwrap();
|
||||||
|
let err = unsafe { mkfifo(name.as_ptr(), 0o666) };
|
||||||
|
if err == -1 {
|
||||||
|
return Err(format!("cannot create fifo {}: File exists", dest.quote()).into());
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn copy_link(
|
fn copy_link(
|
||||||
source: &Path,
|
source: &Path,
|
||||||
dest: &Path,
|
dest: &Path,
|
||||||
|
@ -1496,7 +1539,6 @@ fn copy_on_write_macos(
|
||||||
// Extract paths in a form suitable to be passed to a syscall.
|
// Extract paths in a form suitable to be passed to a syscall.
|
||||||
// The unwrap() is safe because they come from the command-line and so contain non nul
|
// The unwrap() is safe because they come from the command-line and so contain non nul
|
||||||
// character.
|
// character.
|
||||||
use std::os::unix::ffi::OsStrExt;
|
|
||||||
let src = CString::new(source.as_os_str().as_bytes()).unwrap();
|
let src = CString::new(source.as_os_str().as_bytes()).unwrap();
|
||||||
let dst = CString::new(dest.as_os_str().as_bytes()).unwrap();
|
let dst = CString::new(dest.as_os_str().as_bytes()).unwrap();
|
||||||
|
|
||||||
|
@ -1582,6 +1624,13 @@ pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> io::Result<bool> {
|
||||||
Ok(pathbuf1 == pathbuf2)
|
Ok(pathbuf1 == pathbuf2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn path_has_prefix(p1: &Path, p2: &Path) -> io::Result<bool> {
|
||||||
|
let pathbuf1 = canonicalize(p1, MissingHandling::Normal, ResolveMode::Logical)?;
|
||||||
|
let pathbuf2 = canonicalize(p2, MissingHandling::Normal, ResolveMode::Logical)?;
|
||||||
|
|
||||||
|
Ok(pathbuf1.starts_with(pathbuf2))
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cp_localize_to_target() {
|
fn test_cp_localize_to_target() {
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
@ -16,7 +16,7 @@ use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult};
|
use uucore::error::{FromIo, UResult};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
mod csplit_error;
|
mod csplit_error;
|
||||||
mod patterns;
|
mod patterns;
|
||||||
|
@ -27,6 +27,7 @@ use crate::split_name::SplitName;
|
||||||
|
|
||||||
static SUMMARY: &str = "split a file into sections determined by context lines";
|
static SUMMARY: &str = "split a file into sections determined by context lines";
|
||||||
static LONG_HELP: &str = "Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output.";
|
static LONG_HELP: &str = "Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... FILE PATTERN...";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const SUFFIX_FORMAT: &str = "suffix-format";
|
pub const SUFFIX_FORMAT: &str = "suffix-format";
|
||||||
|
@ -40,13 +41,6 @@ mod options {
|
||||||
pub const PATTERN: &str = "pattern";
|
pub const PATTERN: &str = "pattern";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [OPTION]... FILE PATTERN...",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Command line options for csplit.
|
/// Command line options for csplit.
|
||||||
pub struct CsplitOptions {
|
pub struct CsplitOptions {
|
||||||
split_name: crate::SplitName,
|
split_name: crate::SplitName,
|
||||||
|
@ -719,12 +713,11 @@ mod tests {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
// get the file to split
|
// get the file to split
|
||||||
let file_name = matches.value_of(options::FILE).unwrap();
|
let file_name = matches.value_of(options::FILE).unwrap();
|
||||||
|
@ -757,6 +750,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::SUFFIX_FORMAT)
|
Arg::new(options::SUFFIX_FORMAT)
|
||||||
|
|
|
@ -20,13 +20,13 @@ use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
|
|
||||||
use self::searcher::Searcher;
|
use self::searcher::Searcher;
|
||||||
use uucore::ranges::Range;
|
use uucore::ranges::Range;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
mod searcher;
|
mod searcher;
|
||||||
|
|
||||||
static NAME: &str = "cut";
|
static NAME: &str = "cut";
|
||||||
static SYNTAX: &str =
|
static USAGE: &str =
|
||||||
"[-d] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+";
|
"{} [-d] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+";
|
||||||
static SUMMARY: &str =
|
static SUMMARY: &str =
|
||||||
"Prints specified byte or field columns from each line of stdin or the input files";
|
"Prints specified byte or field columns from each line of stdin or the input files";
|
||||||
static LONG_HELP: &str = "
|
static LONG_HELP: &str = "
|
||||||
|
@ -537,7 +537,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(SYNTAX)
|
.override_usage(format_usage(USAGE))
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
|
|
|
@ -21,7 +21,7 @@ use uucore::display::Quotable;
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "redox")))]
|
#[cfg(not(any(target_os = "macos", target_os = "redox")))]
|
||||||
use uucore::error::FromIo;
|
use uucore::error::FromIo;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
use uucore::show_error;
|
use uucore::{format_usage, show_error};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use winapi::{
|
use winapi::{
|
||||||
shared::minwindef::WORD,
|
shared::minwindef::WORD,
|
||||||
|
@ -38,8 +38,10 @@ const MINUTE: &str = "minute";
|
||||||
const SECOND: &str = "second";
|
const SECOND: &str = "second";
|
||||||
const NS: &str = "ns";
|
const NS: &str = "ns";
|
||||||
|
|
||||||
const NAME: &str = "date";
|
|
||||||
const ABOUT: &str = "print or set the system date and time";
|
const ABOUT: &str = "print or set the system date and time";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} [OPTION]... [+FORMAT]...
|
||||||
|
{} [OPTION]... [MMDDhhmm[[CC]YY][.ss]]";
|
||||||
|
|
||||||
const OPT_DATE: &str = "date";
|
const OPT_DATE: &str = "date";
|
||||||
const OPT_FORMAT: &str = "format";
|
const OPT_FORMAT: &str = "format";
|
||||||
|
@ -142,12 +144,7 @@ impl<'a> From<&'a str> for Rfc3339Format {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let syntax = format!(
|
let matches = uu_app().get_matches_from(args);
|
||||||
"{0} [OPTION]... [+FORMAT]...
|
|
||||||
{0} [OPTION]... [MMDDhhmm[[CC]YY][.ss]]",
|
|
||||||
NAME
|
|
||||||
);
|
|
||||||
let matches = uu_app().override_usage(&syntax[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let format = if let Some(form) = matches.value_of(OPT_FORMAT) {
|
let format = if let Some(form) = matches.value_of(OPT_FORMAT) {
|
||||||
if !form.starts_with('+') {
|
if !form.starts_with('+') {
|
||||||
|
@ -261,6 +258,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_DATE)
|
Arg::new(OPT_DATE)
|
||||||
|
|
423
src/uu/dd/src/blocks.rs
Normal file
423
src/uu/dd/src/blocks.rs
Normal file
|
@ -0,0 +1,423 @@
|
||||||
|
// * This file is part of the uutils coreutils package.
|
||||||
|
// *
|
||||||
|
// * For the full copyright and license information, please view the LICENSE
|
||||||
|
// * file that was distributed with this source code.
|
||||||
|
|
||||||
|
// spell-checker:ignore datastructures rstat rposition cflags ctable
|
||||||
|
|
||||||
|
use crate::conversion_tables::ConversionTable;
|
||||||
|
use crate::datastructures::InternalError;
|
||||||
|
use crate::progress::ReadStat;
|
||||||
|
use crate::Input;
|
||||||
|
use std::io::Read;
|
||||||
|
|
||||||
|
const NEWLINE: u8 = b'\n';
|
||||||
|
const SPACE: u8 = b' ';
|
||||||
|
|
||||||
|
/// Split a slice into chunks, padding or truncating as necessary.
|
||||||
|
///
|
||||||
|
/// The slice `buf` is split on newlines, then each block is resized
|
||||||
|
/// to `cbs` bytes, padding with spaces if necessary. This function
|
||||||
|
/// expects the input bytes to be ASCII-encoded.
|
||||||
|
///
|
||||||
|
/// If `sync` is true and there has been at least one partial record
|
||||||
|
/// read from the input (as indicated in `rstat`), then leave an
|
||||||
|
/// all-spaces block at the end. Otherwise, remove the last block if
|
||||||
|
/// it is all spaces.
|
||||||
|
fn block(buf: &[u8], cbs: usize, sync: bool, rstat: &mut ReadStat) -> Vec<Vec<u8>> {
|
||||||
|
let mut blocks = buf
|
||||||
|
.split(|&e| e == NEWLINE)
|
||||||
|
.map(|split| split.to_vec())
|
||||||
|
.fold(Vec::new(), |mut blocks, mut split| {
|
||||||
|
if split.len() > cbs {
|
||||||
|
rstat.records_truncated += 1;
|
||||||
|
}
|
||||||
|
split.resize(cbs, SPACE);
|
||||||
|
blocks.push(split);
|
||||||
|
|
||||||
|
blocks
|
||||||
|
});
|
||||||
|
|
||||||
|
// If `sync` is true and there has been at least one partial
|
||||||
|
// record read from the input, then leave the all-spaces block at
|
||||||
|
// the end. Otherwise, remove it.
|
||||||
|
if let Some(last) = blocks.last() {
|
||||||
|
if (!sync || rstat.reads_partial == 0) && last.iter().all(|&e| e == SPACE) {
|
||||||
|
blocks.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Trims padding from each cbs-length partition of buf
|
||||||
|
/// as specified by conv=unblock and cbs=N
|
||||||
|
/// Expects ascii encoded data
|
||||||
|
fn unblock(buf: &[u8], cbs: usize) -> Vec<u8> {
|
||||||
|
buf.chunks(cbs).fold(Vec::new(), |mut acc, block| {
|
||||||
|
if let Some(last_char_idx) = block.iter().rposition(|&e| e != SPACE) {
|
||||||
|
// Include text up to last space.
|
||||||
|
acc.extend(&block[..=last_char_idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
acc.push(NEWLINE);
|
||||||
|
acc
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A helper for teasing out which options must be applied and in which order.
|
||||||
|
/// Some user options, such as the presence of conversion tables, will determine whether the input is assumed to be ascii. The parser sets the Input::non_ascii flag accordingly.
|
||||||
|
/// Examples:
|
||||||
|
/// - If conv=ebcdic or conv=ibm is specified then block, unblock or swab must be performed before the conversion happens since the source will start in ascii.
|
||||||
|
/// - If conv=ascii is specified then block, unblock or swab must be performed after the conversion since the source starts in ebcdic.
|
||||||
|
/// - If no conversion is specified then the source is assumed to be in ascii.
|
||||||
|
/// For more info see `info dd`
|
||||||
|
pub(crate) fn conv_block_unblock_helper<R: Read>(
|
||||||
|
mut buf: Vec<u8>,
|
||||||
|
i: &mut Input<R>,
|
||||||
|
rstat: &mut ReadStat,
|
||||||
|
) -> Result<Vec<u8>, InternalError> {
|
||||||
|
// Local Predicate Fns -------------------------------------------------
|
||||||
|
fn should_block_then_conv<R: Read>(i: &Input<R>) -> bool {
|
||||||
|
!i.non_ascii && i.cflags.block.is_some()
|
||||||
|
}
|
||||||
|
fn should_conv_then_block<R: Read>(i: &Input<R>) -> bool {
|
||||||
|
i.non_ascii && i.cflags.block.is_some()
|
||||||
|
}
|
||||||
|
fn should_unblock_then_conv<R: Read>(i: &Input<R>) -> bool {
|
||||||
|
!i.non_ascii && i.cflags.unblock.is_some()
|
||||||
|
}
|
||||||
|
fn should_conv_then_unblock<R: Read>(i: &Input<R>) -> bool {
|
||||||
|
i.non_ascii && i.cflags.unblock.is_some()
|
||||||
|
}
|
||||||
|
fn conv_only<R: Read>(i: &Input<R>) -> bool {
|
||||||
|
i.cflags.ctable.is_some() && i.cflags.block.is_none() && i.cflags.unblock.is_none()
|
||||||
|
}
|
||||||
|
// Local Helper Fns ----------------------------------------------------
|
||||||
|
fn apply_conversion(buf: &mut [u8], ct: &ConversionTable) {
|
||||||
|
for idx in 0..buf.len() {
|
||||||
|
buf[idx] = ct[buf[idx] as usize];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --------------------------------------------------------------------
|
||||||
|
if conv_only(i) {
|
||||||
|
// no block/unblock
|
||||||
|
let ct = i.cflags.ctable.unwrap();
|
||||||
|
apply_conversion(&mut buf, ct);
|
||||||
|
|
||||||
|
Ok(buf)
|
||||||
|
} else if should_block_then_conv(i) {
|
||||||
|
// ascii input so perform the block first
|
||||||
|
let cbs = i.cflags.block.unwrap();
|
||||||
|
|
||||||
|
let mut blocks = block(&buf, cbs, i.cflags.sync.is_some(), rstat);
|
||||||
|
|
||||||
|
if let Some(ct) = i.cflags.ctable {
|
||||||
|
for buf in &mut blocks {
|
||||||
|
apply_conversion(buf, ct);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let blocks = blocks.into_iter().flatten().collect();
|
||||||
|
|
||||||
|
Ok(blocks)
|
||||||
|
} else if should_conv_then_block(i) {
|
||||||
|
// Non-ascii so perform the conversion first
|
||||||
|
let cbs = i.cflags.block.unwrap();
|
||||||
|
|
||||||
|
if let Some(ct) = i.cflags.ctable {
|
||||||
|
apply_conversion(&mut buf, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
let blocks = block(&buf, cbs, i.cflags.sync.is_some(), rstat)
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(blocks)
|
||||||
|
} else if should_unblock_then_conv(i) {
|
||||||
|
// ascii input so perform the unblock first
|
||||||
|
let cbs = i.cflags.unblock.unwrap();
|
||||||
|
|
||||||
|
let mut buf = unblock(&buf, cbs);
|
||||||
|
|
||||||
|
if let Some(ct) = i.cflags.ctable {
|
||||||
|
apply_conversion(&mut buf, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(buf)
|
||||||
|
} else if should_conv_then_unblock(i) {
|
||||||
|
// Non-ascii input so perform the conversion first
|
||||||
|
let cbs = i.cflags.unblock.unwrap();
|
||||||
|
|
||||||
|
if let Some(ct) = i.cflags.ctable {
|
||||||
|
apply_conversion(&mut buf, ct);
|
||||||
|
}
|
||||||
|
|
||||||
|
let buf = unblock(&buf, cbs);
|
||||||
|
|
||||||
|
Ok(buf)
|
||||||
|
} else {
|
||||||
|
// The following error should not happen, as it results from
|
||||||
|
// insufficient command line data. This case should be caught
|
||||||
|
// by the parser before making it this far.
|
||||||
|
// Producing this error is an alternative to risking an unwrap call
|
||||||
|
// on 'cbs' if the required data is not provided.
|
||||||
|
Err(InternalError::InvalidConvBlockUnblockCase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use crate::blocks::{block, unblock};
|
||||||
|
use crate::progress::ReadStat;
|
||||||
|
|
||||||
|
const NEWLINE: u8 = b'\n';
|
||||||
|
const SPACE: u8 = b' ';
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_no_nl() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [0u8, 1u8, 2u8, 3u8];
|
||||||
|
let res = block(&buf, 4, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8],]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_no_nl_short_record() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [0u8, 1u8, 2u8, 3u8];
|
||||||
|
let res = block(&buf, 8, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_no_nl_trunc() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [0u8, 1u8, 2u8, 3u8, 4u8];
|
||||||
|
let res = block(&buf, 4, false, &mut rs);
|
||||||
|
|
||||||
|
// Commented section(s) should be truncated and appear for reference only.
|
||||||
|
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8 /*, 4u8*/],]);
|
||||||
|
assert_eq!(rs.records_truncated, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_nl_gt_cbs_trunc() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [
|
||||||
|
0u8, 1u8, 2u8, 3u8, 4u8, NEWLINE, 0u8, 1u8, 2u8, 3u8, 4u8, NEWLINE, 5u8, 6u8, 7u8, 8u8,
|
||||||
|
];
|
||||||
|
let res = block(&buf, 4, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![
|
||||||
|
// Commented section(s) should be truncated and appear for reference only.
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8],
|
||||||
|
// vec![4u8, SPACE, SPACE, SPACE],
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8],
|
||||||
|
// vec![4u8, SPACE, SPACE, SPACE],
|
||||||
|
vec![5u8, 6u8, 7u8, 8u8],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(rs.records_truncated, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_surrounded_nl() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, 5u8, 6u8, 7u8, 8u8];
|
||||||
|
let res = block(&buf, 8, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![4u8, 5u8, 6u8, 7u8, 8u8, SPACE, SPACE, SPACE],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_multiple_nl_same_cbs_block() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [
|
||||||
|
0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, NEWLINE, 5u8, 6u8, 7u8, 8u8, 9u8,
|
||||||
|
];
|
||||||
|
let res = block(&buf, 8, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![4u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![5u8, 6u8, 7u8, 8u8, 9u8, SPACE, SPACE, SPACE],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_multiple_nl_diff_cbs_block() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [
|
||||||
|
0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, 5u8, 6u8, 7u8, NEWLINE, 8u8, 9u8,
|
||||||
|
];
|
||||||
|
let res = block(&buf, 8, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![4u8, 5u8, 6u8, 7u8, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![8u8, 9u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_end_nl_diff_cbs_block() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE];
|
||||||
|
let res = block(&buf, 4, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8],]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_end_nl_same_cbs_block() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [0u8, 1u8, 2u8, NEWLINE];
|
||||||
|
let res = block(&buf, 4, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, SPACE]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_double_end_nl() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [0u8, 1u8, 2u8, NEWLINE, NEWLINE];
|
||||||
|
let res = block(&buf, 4, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![vec![0u8, 1u8, 2u8, SPACE], vec![SPACE, SPACE, SPACE, SPACE],]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_start_nl() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [NEWLINE, 0u8, 1u8, 2u8, 3u8];
|
||||||
|
let res = block(&buf, 4, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![vec![SPACE, SPACE, SPACE, SPACE], vec![0u8, 1u8, 2u8, 3u8],]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_double_surrounded_nl_no_trunc() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE, NEWLINE, 4u8, 5u8, 6u8, 7u8];
|
||||||
|
let res = block(&buf, 8, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![4u8, 5u8, 6u8, 7u8, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn block_test_double_surrounded_nl_double_trunc() {
|
||||||
|
let mut rs = ReadStat::default();
|
||||||
|
let buf = [
|
||||||
|
0u8, 1u8, 2u8, 3u8, NEWLINE, NEWLINE, 4u8, 5u8, 6u8, 7u8, 8u8,
|
||||||
|
];
|
||||||
|
let res = block(&buf, 4, false, &mut rs);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![
|
||||||
|
// Commented section(s) should be truncated and appear for reference only.
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8],
|
||||||
|
vec![SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![4u8, 5u8, 6u8, 7u8 /*, 8u8*/],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
assert_eq!(rs.records_truncated, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unblock_test_full_cbs() {
|
||||||
|
let buf = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8];
|
||||||
|
let res = unblock(&buf, 8);
|
||||||
|
|
||||||
|
assert_eq!(res, vec![0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, NEWLINE],);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unblock_test_all_space() {
|
||||||
|
let buf = [SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE];
|
||||||
|
let res = unblock(&buf, 8);
|
||||||
|
|
||||||
|
assert_eq!(res, vec![NEWLINE],);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unblock_test_decoy_spaces() {
|
||||||
|
let buf = [0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, 7u8];
|
||||||
|
let res = unblock(&buf, 8);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
vec![0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, 7u8, NEWLINE],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unblock_test_strip_single_cbs() {
|
||||||
|
let buf = [0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE];
|
||||||
|
let res = unblock(&buf, 8);
|
||||||
|
|
||||||
|
assert_eq!(res, vec![0u8, 1u8, 2u8, 3u8, NEWLINE],);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn unblock_test_strip_multi_cbs() {
|
||||||
|
let buf = vec![
|
||||||
|
vec![0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![0u8, 1u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![0u8, 1u8, 2u8, SPACE, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let res = unblock(&buf, 8);
|
||||||
|
|
||||||
|
let exp = vec![
|
||||||
|
vec![0u8, NEWLINE],
|
||||||
|
vec![0u8, 1u8, NEWLINE],
|
||||||
|
vec![0u8, 1u8, 2u8, NEWLINE],
|
||||||
|
vec![0u8, 1u8, 2u8, 3u8, NEWLINE],
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
assert_eq!(res, exp);
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,8 +83,8 @@ pub struct OFlags {
|
||||||
/// then becomes Bytes(N)
|
/// then becomes Bytes(N)
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum CountType {
|
pub enum CountType {
|
||||||
Reads(usize),
|
Reads(u64),
|
||||||
Bytes(usize),
|
Bytes(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// For the full copyright and license information, please view the LICENSE
|
// For the full copyright and license information, please view the LICENSE
|
||||||
// file that was distributed with this source code.
|
// file that was distributed with this source code.
|
||||||
|
|
||||||
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rposition, rremain, rsofar, rstat, sigusr, wlen, wstat seekable
|
// spell-checker:ignore fname, tname, fpath, specfile, testfile, unspec, ifile, ofile, outfile, fullblock, urand, fileio, atoe, atoibm, behaviour, bmax, bremain, cflags, creat, ctable, ctty, datastructures, doesnt, etoa, fileout, fname, gnudd, iconvflags, nocache, noctty, noerror, nofollow, nolinks, nonblock, oconvflags, outfile, parseargs, rlen, rmax, rremain, rsofar, rstat, sigusr, wlen, wstat seekable
|
||||||
|
|
||||||
mod datastructures;
|
mod datastructures;
|
||||||
use datastructures::*;
|
use datastructures::*;
|
||||||
|
@ -19,6 +19,9 @@ use conversion_tables::*;
|
||||||
mod progress;
|
mod progress;
|
||||||
use progress::{gen_prog_updater, ProgUpdate, ReadStat, StatusLevel, WriteStat};
|
use progress::{gen_prog_updater, ProgUpdate, ReadStat, StatusLevel, WriteStat};
|
||||||
|
|
||||||
|
mod blocks;
|
||||||
|
use blocks::conv_block_unblock_helper;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
@ -34,14 +37,11 @@ use std::time;
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
use gcd::Gcd;
|
use gcd::Gcd;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult};
|
||||||
use uucore::show_error;
|
use uucore::{show_error, InvalidEncodingHandling};
|
||||||
use uucore::InvalidEncodingHandling;
|
|
||||||
|
|
||||||
const ABOUT: &str = "copy, and optionally convert, a file system resource";
|
const ABOUT: &str = "copy, and optionally convert, a file system resource";
|
||||||
const BUF_INIT_BYTE: u8 = 0xDD;
|
const BUF_INIT_BYTE: u8 = 0xDD;
|
||||||
const NEWLINE: u8 = b'\n';
|
|
||||||
const SPACE: u8 = b' ';
|
|
||||||
|
|
||||||
struct Input<R: Read> {
|
struct Input<R: Read> {
|
||||||
src: R,
|
src: R,
|
||||||
|
@ -74,11 +74,13 @@ impl Input<io::Stdin> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(amt) = skip {
|
if let Some(amt) = skip {
|
||||||
let num_bytes_read = i
|
if let Err(e) = i.read_skip(amt) {
|
||||||
.force_fill(amt.try_into().unwrap())
|
if let io::ErrorKind::UnexpectedEof = e.kind() {
|
||||||
.map_err_context(|| "failed to read input".to_string())?;
|
show_error!("'standard input': cannot skip to specified offset");
|
||||||
if num_bytes_read < amt {
|
} else {
|
||||||
show_error!("'standard input': cannot skip to specified offset");
|
return io::Result::Err(e)
|
||||||
|
.map_err_context(|| "I/O error while skipping".to_string());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,9 +149,6 @@ impl Input<File> {
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(amt) = skip {
|
if let Some(amt) = skip {
|
||||||
let amt: u64 = amt
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| USimpleError::new(1, "failed to parse seek amount"))?;
|
|
||||||
src.seek(io::SeekFrom::Start(amt))
|
src.seek(io::SeekFrom::Start(amt))
|
||||||
.map_err_context(|| "failed to seek in input file".to_string())?;
|
.map_err_context(|| "failed to seek in input file".to_string())?;
|
||||||
}
|
}
|
||||||
|
@ -261,19 +260,18 @@ impl<R: Read> Input<R> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read the specified number of bytes from this reader.
|
/// Skips amount_to_read bytes from the Input by copying into a sink
|
||||||
///
|
fn read_skip(&mut self, amount_to_read: u64) -> std::io::Result<()> {
|
||||||
/// On success, this method returns the number of bytes read. If
|
let copy_result = io::copy(&mut self.src.by_ref().take(amount_to_read), &mut io::sink());
|
||||||
/// this reader has fewer than `n` bytes available, then it reads
|
if let Ok(n) = copy_result {
|
||||||
/// as many as possible. In that case, this method returns a
|
if n != amount_to_read {
|
||||||
/// number less than `n`.
|
io::Result::Err(io::Error::new(io::ErrorKind::UnexpectedEof, ""))
|
||||||
///
|
} else {
|
||||||
/// # Errors
|
Ok(())
|
||||||
///
|
}
|
||||||
/// If there is a problem reading.
|
} else {
|
||||||
fn force_fill(&mut self, n: u64) -> std::io::Result<usize> {
|
io::Result::Err(copy_result.unwrap_err())
|
||||||
let mut buf = vec![];
|
}
|
||||||
self.take(n).read_to_end(&mut buf)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,8 +298,7 @@ impl OutputTrait for Output<io::Stdout> {
|
||||||
|
|
||||||
// stdout is not seekable, so we just write null bytes.
|
// stdout is not seekable, so we just write null bytes.
|
||||||
if let Some(amt) = seek {
|
if let Some(amt) = seek {
|
||||||
let bytes = vec![b'\0'; amt];
|
io::copy(&mut io::repeat(0u8).take(amt as u64), &mut dst)
|
||||||
dst.write_all(&bytes)
|
|
||||||
.map_err_context(|| String::from("write error"))?;
|
.map_err_context(|| String::from("write error"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,10 +514,17 @@ impl OutputTrait for Output<File> {
|
||||||
let mut dst = open_dst(Path::new(&fname), &cflags, &oflags)
|
let mut dst = open_dst(Path::new(&fname), &cflags, &oflags)
|
||||||
.map_err_context(|| format!("failed to open {}", fname.quote()))?;
|
.map_err_context(|| format!("failed to open {}", fname.quote()))?;
|
||||||
|
|
||||||
let i = seek.unwrap_or(0).try_into().unwrap();
|
// Seek to the index in the output file, truncating if requested.
|
||||||
|
//
|
||||||
|
// Calling `set_len()` may result in an error (for
|
||||||
|
// example, when calling it on `/dev/null`), but we don't
|
||||||
|
// want to terminate the process when that happens.
|
||||||
|
// Instead, we suppress the error by calling
|
||||||
|
// `Result::ok()`. This matches the behavior of GNU `dd`
|
||||||
|
// when given the command-line argument `of=/dev/null`.
|
||||||
|
let i = seek.unwrap_or(0);
|
||||||
if !cflags.notrunc {
|
if !cflags.notrunc {
|
||||||
dst.set_len(i)
|
dst.set_len(i).ok();
|
||||||
.map_err_context(|| "failed to truncate output file".to_string())?;
|
|
||||||
}
|
}
|
||||||
dst.seek(io::SeekFrom::Start(i))
|
dst.seek(io::SeekFrom::Start(i))
|
||||||
.map_err_context(|| "failed to seek in output file".to_string())?;
|
.map_err_context(|| "failed to seek in output file".to_string())?;
|
||||||
|
@ -585,146 +589,6 @@ impl Write for Output<io::Stdout> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Splits the content of buf into cbs-length blocks
|
|
||||||
/// Appends padding as specified by conv=block and cbs=N
|
|
||||||
/// Expects ascii encoded data
|
|
||||||
fn block(buf: &[u8], cbs: usize, rstat: &mut ReadStat) -> Vec<Vec<u8>> {
|
|
||||||
let mut blocks = buf
|
|
||||||
.split(|&e| e == NEWLINE)
|
|
||||||
.map(|split| split.to_vec())
|
|
||||||
.fold(Vec::new(), |mut blocks, mut split| {
|
|
||||||
if split.len() > cbs {
|
|
||||||
rstat.records_truncated += 1;
|
|
||||||
}
|
|
||||||
split.resize(cbs, SPACE);
|
|
||||||
blocks.push(split);
|
|
||||||
|
|
||||||
blocks
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(last) = blocks.last() {
|
|
||||||
if last.iter().all(|&e| e == SPACE) {
|
|
||||||
blocks.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blocks
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Trims padding from each cbs-length partition of buf
|
|
||||||
/// as specified by conv=unblock and cbs=N
|
|
||||||
/// Expects ascii encoded data
|
|
||||||
fn unblock(buf: &[u8], cbs: usize) -> Vec<u8> {
|
|
||||||
buf.chunks(cbs).fold(Vec::new(), |mut acc, block| {
|
|
||||||
if let Some(last_char_idx) = block.iter().rposition(|&e| e != SPACE) {
|
|
||||||
// Include text up to last space.
|
|
||||||
acc.extend(&block[..=last_char_idx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
acc.push(NEWLINE);
|
|
||||||
acc
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A helper for teasing out which options must be applied and in which order.
|
|
||||||
/// Some user options, such as the presence of conversion tables, will determine whether the input is assumed to be ascii. The parser sets the Input::non_ascii flag accordingly.
|
|
||||||
/// Examples:
|
|
||||||
/// - If conv=ebcdic or conv=ibm is specified then block, unblock or swab must be performed before the conversion happens since the source will start in ascii.
|
|
||||||
/// - If conv=ascii is specified then block, unblock or swab must be performed after the conversion since the source starts in ebcdic.
|
|
||||||
/// - If no conversion is specified then the source is assumed to be in ascii.
|
|
||||||
/// For more info see `info dd`
|
|
||||||
fn conv_block_unblock_helper<R: Read>(
|
|
||||||
mut buf: Vec<u8>,
|
|
||||||
i: &mut Input<R>,
|
|
||||||
rstat: &mut ReadStat,
|
|
||||||
) -> Result<Vec<u8>, InternalError> {
|
|
||||||
// Local Predicate Fns -------------------------------------------------
|
|
||||||
fn should_block_then_conv<R: Read>(i: &Input<R>) -> bool {
|
|
||||||
!i.non_ascii && i.cflags.block.is_some()
|
|
||||||
}
|
|
||||||
fn should_conv_then_block<R: Read>(i: &Input<R>) -> bool {
|
|
||||||
i.non_ascii && i.cflags.block.is_some()
|
|
||||||
}
|
|
||||||
fn should_unblock_then_conv<R: Read>(i: &Input<R>) -> bool {
|
|
||||||
!i.non_ascii && i.cflags.unblock.is_some()
|
|
||||||
}
|
|
||||||
fn should_conv_then_unblock<R: Read>(i: &Input<R>) -> bool {
|
|
||||||
i.non_ascii && i.cflags.unblock.is_some()
|
|
||||||
}
|
|
||||||
fn conv_only<R: Read>(i: &Input<R>) -> bool {
|
|
||||||
i.cflags.ctable.is_some() && i.cflags.block.is_none() && i.cflags.unblock.is_none()
|
|
||||||
}
|
|
||||||
// Local Helper Fns ----------------------------------------------------
|
|
||||||
fn apply_conversion(buf: &mut [u8], ct: &ConversionTable) {
|
|
||||||
for idx in 0..buf.len() {
|
|
||||||
buf[idx] = ct[buf[idx] as usize];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// --------------------------------------------------------------------
|
|
||||||
if conv_only(i) {
|
|
||||||
// no block/unblock
|
|
||||||
let ct = i.cflags.ctable.unwrap();
|
|
||||||
apply_conversion(&mut buf, ct);
|
|
||||||
|
|
||||||
Ok(buf)
|
|
||||||
} else if should_block_then_conv(i) {
|
|
||||||
// ascii input so perform the block first
|
|
||||||
let cbs = i.cflags.block.unwrap();
|
|
||||||
|
|
||||||
let mut blocks = block(&buf, cbs, rstat);
|
|
||||||
|
|
||||||
if let Some(ct) = i.cflags.ctable {
|
|
||||||
for buf in &mut blocks {
|
|
||||||
apply_conversion(buf, ct);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let blocks = blocks.into_iter().flatten().collect();
|
|
||||||
|
|
||||||
Ok(blocks)
|
|
||||||
} else if should_conv_then_block(i) {
|
|
||||||
// Non-ascii so perform the conversion first
|
|
||||||
let cbs = i.cflags.block.unwrap();
|
|
||||||
|
|
||||||
if let Some(ct) = i.cflags.ctable {
|
|
||||||
apply_conversion(&mut buf, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
let blocks = block(&buf, cbs, rstat).into_iter().flatten().collect();
|
|
||||||
|
|
||||||
Ok(blocks)
|
|
||||||
} else if should_unblock_then_conv(i) {
|
|
||||||
// ascii input so perform the unblock first
|
|
||||||
let cbs = i.cflags.unblock.unwrap();
|
|
||||||
|
|
||||||
let mut buf = unblock(&buf, cbs);
|
|
||||||
|
|
||||||
if let Some(ct) = i.cflags.ctable {
|
|
||||||
apply_conversion(&mut buf, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(buf)
|
|
||||||
} else if should_conv_then_unblock(i) {
|
|
||||||
// Non-ascii input so perform the conversion first
|
|
||||||
let cbs = i.cflags.unblock.unwrap();
|
|
||||||
|
|
||||||
if let Some(ct) = i.cflags.ctable {
|
|
||||||
apply_conversion(&mut buf, ct);
|
|
||||||
}
|
|
||||||
|
|
||||||
let buf = unblock(&buf, cbs);
|
|
||||||
|
|
||||||
Ok(buf)
|
|
||||||
} else {
|
|
||||||
// The following error should not happen, as it results from
|
|
||||||
// insufficient command line data. This case should be caught
|
|
||||||
// by the parser before making it this far.
|
|
||||||
// Producing this error is an alternative to risking an unwrap call
|
|
||||||
// on 'cbs' if the required data is not provided.
|
|
||||||
Err(InternalError::InvalidConvBlockUnblockCase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read helper performs read operations common to all dd reads, and dispatches the buffer to relevant helper functions as dictated by the operations requested by the user.
|
/// Read helper performs read operations common to all dd reads, and dispatches the buffer to relevant helper functions as dictated by the operations requested by the user.
|
||||||
fn read_helper<R: Read>(i: &mut Input<R>, bsize: usize) -> std::io::Result<(ReadStat, Vec<u8>)> {
|
fn read_helper<R: Read>(i: &mut Input<R>, bsize: usize) -> std::io::Result<(ReadStat, Vec<u8>)> {
|
||||||
// Local Predicate Fns -----------------------------------------------
|
// Local Predicate Fns -----------------------------------------------
|
||||||
|
@ -790,15 +654,14 @@ fn calc_loop_bsize(
|
||||||
) -> usize {
|
) -> usize {
|
||||||
match count {
|
match count {
|
||||||
Some(CountType::Reads(rmax)) => {
|
Some(CountType::Reads(rmax)) => {
|
||||||
let rmax: u64 = (*rmax).try_into().unwrap();
|
|
||||||
let rsofar = rstat.reads_complete + rstat.reads_partial;
|
let rsofar = rstat.reads_complete + rstat.reads_partial;
|
||||||
let rremain: usize = (rmax - rsofar).try_into().unwrap();
|
let rremain = rmax - rsofar;
|
||||||
cmp::min(ideal_bsize, rremain * ibs)
|
cmp::min(ideal_bsize as u64, rremain * ibs as u64) as usize
|
||||||
}
|
}
|
||||||
Some(CountType::Bytes(bmax)) => {
|
Some(CountType::Bytes(bmax)) => {
|
||||||
let bmax: u128 = (*bmax).try_into().unwrap();
|
let bmax: u128 = (*bmax).try_into().unwrap();
|
||||||
let bremain: usize = (bmax - wstat.bytes_total).try_into().unwrap();
|
let bremain: u128 = bmax - wstat.bytes_total;
|
||||||
cmp::min(ideal_bsize, bremain)
|
cmp::min(ideal_bsize as u128, bremain as u128) as usize
|
||||||
}
|
}
|
||||||
None => ideal_bsize,
|
None => ideal_bsize,
|
||||||
}
|
}
|
||||||
|
@ -809,7 +672,7 @@ fn calc_loop_bsize(
|
||||||
fn below_count_limit(count: &Option<CountType>, rstat: &ReadStat, wstat: &WriteStat) -> bool {
|
fn below_count_limit(count: &Option<CountType>, rstat: &ReadStat, wstat: &WriteStat) -> bool {
|
||||||
match count {
|
match count {
|
||||||
Some(CountType::Reads(n)) => {
|
Some(CountType::Reads(n)) => {
|
||||||
let n = (*n).try_into().unwrap();
|
let n = *n;
|
||||||
rstat.reads_complete + rstat.reads_partial <= n
|
rstat.reads_complete + rstat.reads_partial <= n
|
||||||
}
|
}
|
||||||
Some(CountType::Bytes(n)) => {
|
Some(CountType::Bytes(n)) => {
|
||||||
|
@ -1084,8 +947,7 @@ General-Flags
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::datastructures::{IConvFlags, IFlags, OConvFlags};
|
use crate::datastructures::{IConvFlags, IFlags, OConvFlags};
|
||||||
use crate::ReadStat;
|
use crate::{calc_bsize, uu_app, Input, Output, OutputTrait};
|
||||||
use crate::{block, calc_bsize, unblock, uu_app, Input, Output, OutputTrait};
|
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
@ -1104,254 +966,6 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const NEWLINE: u8 = b'\n';
|
|
||||||
const SPACE: u8 = b' ';
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_no_nl() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [0u8, 1u8, 2u8, 3u8];
|
|
||||||
let res = block(&buf, 4, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8],]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_no_nl_short_record() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [0u8, 1u8, 2u8, 3u8];
|
|
||||||
let res = block(&buf, 8, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_no_nl_trunc() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [0u8, 1u8, 2u8, 3u8, 4u8];
|
|
||||||
let res = block(&buf, 4, &mut rs);
|
|
||||||
|
|
||||||
// Commented section(s) should be truncated and appear for reference only.
|
|
||||||
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8 /*, 4u8*/],]);
|
|
||||||
assert_eq!(rs.records_truncated, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_nl_gt_cbs_trunc() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [
|
|
||||||
0u8, 1u8, 2u8, 3u8, 4u8, NEWLINE, 0u8, 1u8, 2u8, 3u8, 4u8, NEWLINE, 5u8, 6u8, 7u8, 8u8,
|
|
||||||
];
|
|
||||||
let res = block(&buf, 4, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![
|
|
||||||
// Commented section(s) should be truncated and appear for reference only.
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8],
|
|
||||||
// vec![4u8, SPACE, SPACE, SPACE],
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8],
|
|
||||||
// vec![4u8, SPACE, SPACE, SPACE],
|
|
||||||
vec![5u8, 6u8, 7u8, 8u8],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(rs.records_truncated, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_surrounded_nl() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, 5u8, 6u8, 7u8, 8u8];
|
|
||||||
let res = block(&buf, 8, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![4u8, 5u8, 6u8, 7u8, 8u8, SPACE, SPACE, SPACE],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_multiple_nl_same_cbs_block() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [
|
|
||||||
0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, NEWLINE, 5u8, 6u8, 7u8, 8u8, 9u8,
|
|
||||||
];
|
|
||||||
let res = block(&buf, 8, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![4u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![5u8, 6u8, 7u8, 8u8, 9u8, SPACE, SPACE, SPACE],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_multiple_nl_diff_cbs_block() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [
|
|
||||||
0u8, 1u8, 2u8, 3u8, NEWLINE, 4u8, 5u8, 6u8, 7u8, NEWLINE, 8u8, 9u8,
|
|
||||||
];
|
|
||||||
let res = block(&buf, 8, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![4u8, 5u8, 6u8, 7u8, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![8u8, 9u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_end_nl_diff_cbs_block() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE];
|
|
||||||
let res = block(&buf, 4, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, 3u8],]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_end_nl_same_cbs_block() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [0u8, 1u8, 2u8, NEWLINE];
|
|
||||||
let res = block(&buf, 4, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(res, vec![vec![0u8, 1u8, 2u8, SPACE]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_double_end_nl() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [0u8, 1u8, 2u8, NEWLINE, NEWLINE];
|
|
||||||
let res = block(&buf, 4, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![vec![0u8, 1u8, 2u8, SPACE], vec![SPACE, SPACE, SPACE, SPACE],]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_start_nl() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [NEWLINE, 0u8, 1u8, 2u8, 3u8];
|
|
||||||
let res = block(&buf, 4, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![vec![SPACE, SPACE, SPACE, SPACE], vec![0u8, 1u8, 2u8, 3u8],]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_double_surrounded_nl_no_trunc() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [0u8, 1u8, 2u8, 3u8, NEWLINE, NEWLINE, 4u8, 5u8, 6u8, 7u8];
|
|
||||||
let res = block(&buf, 8, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![4u8, 5u8, 6u8, 7u8, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn block_test_double_surrounded_nl_double_trunc() {
|
|
||||||
let mut rs = ReadStat::default();
|
|
||||||
let buf = [
|
|
||||||
0u8, 1u8, 2u8, 3u8, NEWLINE, NEWLINE, 4u8, 5u8, 6u8, 7u8, 8u8,
|
|
||||||
];
|
|
||||||
let res = block(&buf, 4, &mut rs);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![
|
|
||||||
// Commented section(s) should be truncated and appear for reference only.
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8],
|
|
||||||
vec![SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![4u8, 5u8, 6u8, 7u8 /*, 8u8*/],
|
|
||||||
]
|
|
||||||
);
|
|
||||||
assert_eq!(rs.records_truncated, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unblock_test_full_cbs() {
|
|
||||||
let buf = [0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8];
|
|
||||||
let res = unblock(&buf, 8);
|
|
||||||
|
|
||||||
assert_eq!(res, vec![0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, NEWLINE],);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unblock_test_all_space() {
|
|
||||||
let buf = [SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE];
|
|
||||||
let res = unblock(&buf, 8);
|
|
||||||
|
|
||||||
assert_eq!(res, vec![NEWLINE],);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unblock_test_decoy_spaces() {
|
|
||||||
let buf = [0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, 7u8];
|
|
||||||
let res = unblock(&buf, 8);
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
res,
|
|
||||||
vec![0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, 7u8, NEWLINE],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unblock_test_strip_single_cbs() {
|
|
||||||
let buf = [0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE];
|
|
||||||
let res = unblock(&buf, 8);
|
|
||||||
|
|
||||||
assert_eq!(res, vec![0u8, 1u8, 2u8, 3u8, NEWLINE],);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn unblock_test_strip_multi_cbs() {
|
|
||||||
let buf = vec![
|
|
||||||
vec![0u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![0u8, 1u8, SPACE, SPACE, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![0u8, 1u8, 2u8, SPACE, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8, SPACE, SPACE, SPACE, SPACE],
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
let res = unblock(&buf, 8);
|
|
||||||
|
|
||||||
let exp = vec![
|
|
||||||
vec![0u8, NEWLINE],
|
|
||||||
vec![0u8, 1u8, NEWLINE],
|
|
||||||
vec![0u8, 1u8, 2u8, NEWLINE],
|
|
||||||
vec![0u8, 1u8, 2u8, 3u8, NEWLINE],
|
|
||||||
]
|
|
||||||
.into_iter()
|
|
||||||
.flatten()
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
assert_eq!(res, exp);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bsize_test_primes() {
|
fn bsize_test_primes() {
|
||||||
let (n, m) = (7901, 7919);
|
let (n, m) = (7901, 7919);
|
||||||
|
|
|
@ -31,6 +31,10 @@ pub enum ParseError {
|
||||||
BlockUnblockWithoutCBS,
|
BlockUnblockWithoutCBS,
|
||||||
StatusLevelNotRecognized(String),
|
StatusLevelNotRecognized(String),
|
||||||
Unimplemented(String),
|
Unimplemented(String),
|
||||||
|
BsOutOfRange,
|
||||||
|
IbsOutOfRange,
|
||||||
|
ObsOutOfRange,
|
||||||
|
CbsOutOfRange,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParseError {
|
impl ParseError {
|
||||||
|
@ -48,6 +52,10 @@ impl ParseError {
|
||||||
Self::BlockUnblockWithoutCBS => Self::BlockUnblockWithoutCBS,
|
Self::BlockUnblockWithoutCBS => Self::BlockUnblockWithoutCBS,
|
||||||
Self::StatusLevelNotRecognized(_) => Self::StatusLevelNotRecognized(s),
|
Self::StatusLevelNotRecognized(_) => Self::StatusLevelNotRecognized(s),
|
||||||
Self::Unimplemented(_) => Self::Unimplemented(s),
|
Self::Unimplemented(_) => Self::Unimplemented(s),
|
||||||
|
Self::BsOutOfRange => Self::BsOutOfRange,
|
||||||
|
Self::IbsOutOfRange => Self::IbsOutOfRange,
|
||||||
|
Self::ObsOutOfRange => Self::ObsOutOfRange,
|
||||||
|
Self::CbsOutOfRange => Self::CbsOutOfRange,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,6 +100,18 @@ impl std::fmt::Display for ParseError {
|
||||||
Self::StatusLevelNotRecognized(arg) => {
|
Self::StatusLevelNotRecognized(arg) => {
|
||||||
write!(f, "status=LEVEL not recognized -> {}", arg)
|
write!(f, "status=LEVEL not recognized -> {}", arg)
|
||||||
}
|
}
|
||||||
|
ParseError::BsOutOfRange => {
|
||||||
|
write!(f, "bs=N cannot fit into memory")
|
||||||
|
}
|
||||||
|
ParseError::IbsOutOfRange => {
|
||||||
|
write!(f, "ibs=N cannot fit into memory")
|
||||||
|
}
|
||||||
|
ParseError::ObsOutOfRange => {
|
||||||
|
write!(f, "obs=N cannot fit into memory")
|
||||||
|
}
|
||||||
|
ParseError::CbsOutOfRange => {
|
||||||
|
write!(f, "cbs=N cannot fit into memory")
|
||||||
|
}
|
||||||
Self::Unimplemented(arg) => {
|
Self::Unimplemented(arg) => {
|
||||||
write!(f, "feature not implemented on this system -> {}", arg)
|
write!(f, "feature not implemented on this system -> {}", arg)
|
||||||
}
|
}
|
||||||
|
@ -334,7 +354,7 @@ fn show_zero_multiplier_warning() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse bytes using str::parse, then map error if needed.
|
/// Parse bytes using str::parse, then map error if needed.
|
||||||
fn parse_bytes_only(s: &str) -> Result<usize, ParseError> {
|
fn parse_bytes_only(s: &str) -> Result<u64, ParseError> {
|
||||||
s.parse()
|
s.parse()
|
||||||
.map_err(|_| ParseError::MultiplierStringParseFailure(s.to_string()))
|
.map_err(|_| ParseError::MultiplierStringParseFailure(s.to_string()))
|
||||||
}
|
}
|
||||||
|
@ -364,7 +384,7 @@ fn parse_bytes_only(s: &str) -> Result<usize, ParseError> {
|
||||||
/// assert_eq!(parse_bytes_no_x("2b").unwrap(), 2 * 512);
|
/// assert_eq!(parse_bytes_no_x("2b").unwrap(), 2 * 512);
|
||||||
/// assert_eq!(parse_bytes_no_x("2k").unwrap(), 2 * 1024);
|
/// assert_eq!(parse_bytes_no_x("2k").unwrap(), 2 * 1024);
|
||||||
/// ```
|
/// ```
|
||||||
fn parse_bytes_no_x(s: &str) -> Result<usize, ParseError> {
|
fn parse_bytes_no_x(s: &str) -> Result<u64, ParseError> {
|
||||||
let (num, multiplier) = match (s.find('c'), s.rfind('w'), s.rfind('b')) {
|
let (num, multiplier) = match (s.find('c'), s.rfind('w'), s.rfind('b')) {
|
||||||
(None, None, None) => match uucore::parse_size::parse_size(s) {
|
(None, None, None) => match uucore::parse_size::parse_size(s) {
|
||||||
Ok(n) => (n, 1),
|
Ok(n) => (n, 1),
|
||||||
|
@ -387,7 +407,7 @@ fn parse_bytes_no_x(s: &str) -> Result<usize, ParseError> {
|
||||||
/// Parse byte and multiplier like 512, 5KiB, or 1G.
|
/// Parse byte and multiplier like 512, 5KiB, or 1G.
|
||||||
/// Uses uucore::parse_size, and adds the 'w' and 'c' suffixes which are mentioned
|
/// Uses uucore::parse_size, and adds the 'w' and 'c' suffixes which are mentioned
|
||||||
/// in dd's info page.
|
/// in dd's info page.
|
||||||
fn parse_bytes_with_opt_multiplier(s: &str) -> Result<usize, ParseError> {
|
fn parse_bytes_with_opt_multiplier(s: &str) -> Result<u64, ParseError> {
|
||||||
// TODO On my Linux system, there seems to be a maximum block size of 4096 bytes:
|
// TODO On my Linux system, there seems to be a maximum block size of 4096 bytes:
|
||||||
//
|
//
|
||||||
// $ printf "%0.sa" {1..10000} | dd bs=4095 count=1 status=none | wc -c
|
// $ printf "%0.sa" {1..10000} | dd bs=4095 count=1 status=none | wc -c
|
||||||
|
@ -420,9 +440,27 @@ fn parse_bytes_with_opt_multiplier(s: &str) -> Result<usize, ParseError> {
|
||||||
|
|
||||||
pub fn parse_ibs(matches: &Matches) -> Result<usize, ParseError> {
|
pub fn parse_ibs(matches: &Matches) -> Result<usize, ParseError> {
|
||||||
if let Some(mixed_str) = matches.value_of(options::BS) {
|
if let Some(mixed_str) = matches.value_of(options::BS) {
|
||||||
parse_bytes_with_opt_multiplier(mixed_str)
|
parse_bytes_with_opt_multiplier(mixed_str)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| ParseError::BsOutOfRange)
|
||||||
} else if let Some(mixed_str) = matches.value_of(options::IBS) {
|
} else if let Some(mixed_str) = matches.value_of(options::IBS) {
|
||||||
parse_bytes_with_opt_multiplier(mixed_str)
|
parse_bytes_with_opt_multiplier(mixed_str)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| ParseError::IbsOutOfRange)
|
||||||
|
} else {
|
||||||
|
Ok(512)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_obs(matches: &Matches) -> Result<usize, ParseError> {
|
||||||
|
if let Some(mixed_str) = matches.value_of("bs") {
|
||||||
|
parse_bytes_with_opt_multiplier(mixed_str)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| ParseError::BsOutOfRange)
|
||||||
|
} else if let Some(mixed_str) = matches.value_of("obs") {
|
||||||
|
parse_bytes_with_opt_multiplier(mixed_str)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| ParseError::ObsOutOfRange)
|
||||||
} else {
|
} else {
|
||||||
Ok(512)
|
Ok(512)
|
||||||
}
|
}
|
||||||
|
@ -430,7 +468,9 @@ pub fn parse_ibs(matches: &Matches) -> Result<usize, ParseError> {
|
||||||
|
|
||||||
fn parse_cbs(matches: &Matches) -> Result<Option<usize>, ParseError> {
|
fn parse_cbs(matches: &Matches) -> Result<Option<usize>, ParseError> {
|
||||||
if let Some(s) = matches.value_of(options::CBS) {
|
if let Some(s) = matches.value_of(options::CBS) {
|
||||||
let bytes = parse_bytes_with_opt_multiplier(s)?;
|
let bytes = parse_bytes_with_opt_multiplier(s)?
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| ParseError::CbsOutOfRange)?;
|
||||||
Ok(Some(bytes))
|
Ok(Some(bytes))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -447,16 +487,6 @@ pub(crate) fn parse_status_level(matches: &Matches) -> Result<Option<StatusLevel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_obs(matches: &Matches) -> Result<usize, ParseError> {
|
|
||||||
if let Some(mixed_str) = matches.value_of("bs") {
|
|
||||||
parse_bytes_with_opt_multiplier(mixed_str)
|
|
||||||
} else if let Some(mixed_str) = matches.value_of("obs") {
|
|
||||||
parse_bytes_with_opt_multiplier(mixed_str)
|
|
||||||
} else {
|
|
||||||
Ok(512)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_ctable(fmt: Option<ConvFlag>, case: Option<ConvFlag>) -> Option<&'static ConversionTable> {
|
fn parse_ctable(fmt: Option<ConvFlag>, case: Option<ConvFlag>) -> Option<&'static ConversionTable> {
|
||||||
fn parse_conv_and_case_table(
|
fn parse_conv_and_case_table(
|
||||||
fmt: &ConvFlag,
|
fmt: &ConvFlag,
|
||||||
|
@ -715,13 +745,13 @@ pub fn parse_skip_amt(
|
||||||
ibs: &usize,
|
ibs: &usize,
|
||||||
iflags: &IFlags,
|
iflags: &IFlags,
|
||||||
matches: &Matches,
|
matches: &Matches,
|
||||||
) -> Result<Option<usize>, ParseError> {
|
) -> Result<Option<u64>, ParseError> {
|
||||||
if let Some(amt) = matches.value_of(options::SKIP) {
|
if let Some(amt) = matches.value_of(options::SKIP) {
|
||||||
let n = parse_bytes_with_opt_multiplier(amt)?;
|
let n = parse_bytes_with_opt_multiplier(amt)?;
|
||||||
if iflags.skip_bytes {
|
if iflags.skip_bytes {
|
||||||
Ok(Some(n))
|
Ok(Some(n))
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(ibs * n))
|
Ok(Some(*ibs as u64 * n))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
@ -733,13 +763,13 @@ pub fn parse_seek_amt(
|
||||||
obs: &usize,
|
obs: &usize,
|
||||||
oflags: &OFlags,
|
oflags: &OFlags,
|
||||||
matches: &Matches,
|
matches: &Matches,
|
||||||
) -> Result<Option<usize>, ParseError> {
|
) -> Result<Option<u64>, ParseError> {
|
||||||
if let Some(amt) = matches.value_of(options::SEEK) {
|
if let Some(amt) = matches.value_of(options::SEEK) {
|
||||||
let n = parse_bytes_with_opt_multiplier(amt)?;
|
let n = parse_bytes_with_opt_multiplier(amt)?;
|
||||||
if oflags.seek_bytes {
|
if oflags.seek_bytes {
|
||||||
Ok(Some(n))
|
Ok(Some(n))
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(obs * n))
|
Ok(Some(*obs as u64 * n))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|
|
@ -5,21 +5,18 @@
|
||||||
//
|
//
|
||||||
// For the full copyright and license information, please view the LICENSE file
|
// For the full copyright and license information, please view the LICENSE file
|
||||||
// that was distributed with this source code.
|
// that was distributed with this source code.
|
||||||
|
// spell-checker:ignore itotal iused iavail ipcent pcent
|
||||||
mod table;
|
mod table;
|
||||||
|
|
||||||
use uucore::error::UResult;
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use uucore::fsext::statfs_fn;
|
use uucore::fsext::statfs;
|
||||||
use uucore::fsext::{read_fs_list, FsUsage, MountInfo};
|
use uucore::fsext::{read_fs_list, FsUsage, MountInfo};
|
||||||
|
use uucore::{error::UResult, format_usage};
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
#[cfg(unix)]
|
|
||||||
use std::ffi::CString;
|
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
#[cfg(unix)]
|
|
||||||
use std::mem;
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
@ -28,6 +25,7 @@ use crate::table::{DisplayRow, Header, Row};
|
||||||
|
|
||||||
static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
|
static ABOUT: &str = "Show information about the file system on which each FILE resides,\n\
|
||||||
or all file systems by default.";
|
or all file systems by default.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
|
|
||||||
static OPT_ALL: &str = "all";
|
static OPT_ALL: &str = "all";
|
||||||
static OPT_BLOCKSIZE: &str = "blocksize";
|
static OPT_BLOCKSIZE: &str = "blocksize";
|
||||||
|
@ -46,6 +44,10 @@ static OPT_SYNC: &str = "sync";
|
||||||
static OPT_TYPE: &str = "type";
|
static OPT_TYPE: &str = "type";
|
||||||
static OPT_PRINT_TYPE: &str = "print-type";
|
static OPT_PRINT_TYPE: &str = "print-type";
|
||||||
static OPT_EXCLUDE_TYPE: &str = "exclude-type";
|
static OPT_EXCLUDE_TYPE: &str = "exclude-type";
|
||||||
|
static OUTPUT_FIELD_LIST: [&str; 12] = [
|
||||||
|
"source", "fstype", "itotal", "iused", "iavail", "ipcent", "size", "used", "avail", "pcent",
|
||||||
|
"file", "target",
|
||||||
|
];
|
||||||
|
|
||||||
/// Store names of file systems as a selector.
|
/// Store names of file systems as a selector.
|
||||||
/// Note: `exclude` takes priority over `include`.
|
/// Note: `exclude` takes priority over `include`.
|
||||||
|
@ -55,6 +57,55 @@ struct FsSelector {
|
||||||
exclude: HashSet<String>,
|
exclude: HashSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A block size to use in condensing the display of a large number of bytes.
|
||||||
|
///
|
||||||
|
/// The [`BlockSize::Bytes`] variant represents a static block
|
||||||
|
/// size. The [`BlockSize::HumanReadableDecimal`] and
|
||||||
|
/// [`BlockSize::HumanReadableBinary`] variants represent dynamic
|
||||||
|
/// block sizes: as the number of bytes increases, the divisor
|
||||||
|
/// increases as well (for example, from 1 to 1,000 to 1,000,000 and
|
||||||
|
/// so on in the case of [`BlockSize::HumanReadableDecimal`]).
|
||||||
|
///
|
||||||
|
/// The default variant is `Bytes(1024)`.
|
||||||
|
enum BlockSize {
|
||||||
|
/// A fixed number of bytes.
|
||||||
|
///
|
||||||
|
/// The number must be positive.
|
||||||
|
Bytes(u64),
|
||||||
|
|
||||||
|
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||||
|
///
|
||||||
|
/// This variant represents powers of 1,000. Contrast with
|
||||||
|
/// [`BlockSize::HumanReadableBinary`], which represents powers of
|
||||||
|
/// 1,024.
|
||||||
|
HumanReadableDecimal,
|
||||||
|
|
||||||
|
/// Use the largest divisor corresponding to a unit, like B, K, M, G, etc.
|
||||||
|
///
|
||||||
|
/// This variant represents powers of 1,024. Contrast with
|
||||||
|
/// [`BlockSize::HumanReadableDecimal`], which represents powers
|
||||||
|
/// of 1,000.
|
||||||
|
HumanReadableBinary,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BlockSize {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Bytes(1024)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ArgMatches> for BlockSize {
|
||||||
|
fn from(matches: &ArgMatches) -> Self {
|
||||||
|
if matches.is_present(OPT_HUMAN_READABLE) {
|
||||||
|
Self::HumanReadableBinary
|
||||||
|
} else if matches.is_present(OPT_HUMAN_READABLE_2) {
|
||||||
|
Self::HumanReadableDecimal
|
||||||
|
} else {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Options {
|
struct Options {
|
||||||
show_local_fs: bool,
|
show_local_fs: bool,
|
||||||
|
@ -62,8 +113,7 @@ struct Options {
|
||||||
show_listed_fs: bool,
|
show_listed_fs: bool,
|
||||||
show_fs_type: bool,
|
show_fs_type: bool,
|
||||||
show_inode_instead: bool,
|
show_inode_instead: bool,
|
||||||
// block_size: usize,
|
block_size: BlockSize,
|
||||||
human_readable_base: i64,
|
|
||||||
fs_selector: FsSelector,
|
fs_selector: FsSelector,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,13 +126,7 @@ impl Options {
|
||||||
show_listed_fs: false,
|
show_listed_fs: false,
|
||||||
show_fs_type: matches.is_present(OPT_PRINT_TYPE),
|
show_fs_type: matches.is_present(OPT_PRINT_TYPE),
|
||||||
show_inode_instead: matches.is_present(OPT_INODES),
|
show_inode_instead: matches.is_present(OPT_INODES),
|
||||||
human_readable_base: if matches.is_present(OPT_HUMAN_READABLE) {
|
block_size: BlockSize::from(matches),
|
||||||
1024
|
|
||||||
} else if matches.is_present(OPT_HUMAN_READABLE_2) {
|
|
||||||
1000
|
|
||||||
} else {
|
|
||||||
-1
|
|
||||||
},
|
|
||||||
fs_selector: FsSelector::from(matches),
|
fs_selector: FsSelector::from(matches),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,10 +138,6 @@ struct Filesystem {
|
||||||
usage: FsUsage,
|
usage: FsUsage,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FsSelector {
|
impl FsSelector {
|
||||||
/// Convert command-line arguments into a [`FsSelector`].
|
/// Convert command-line arguments into a [`FsSelector`].
|
||||||
///
|
///
|
||||||
|
@ -139,23 +179,10 @@ impl Filesystem {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
unsafe {
|
let usage = FsUsage::new(statfs(_stat_path).ok()?);
|
||||||
let path = CString::new(_stat_path).unwrap();
|
|
||||||
let mut statvfs = mem::zeroed();
|
|
||||||
if statfs_fn(path.as_ptr(), &mut statvfs) < 0 {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(Self {
|
|
||||||
mount_info,
|
|
||||||
usage: FsUsage::new(statvfs),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
Some(Self {
|
let usage = FsUsage::new(Path::new(&_stat_path));
|
||||||
mount_info,
|
Some(Self { mount_info, usage })
|
||||||
usage: FsUsage::new(Path::new(&_stat_path)),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,8 +283,7 @@ fn filter_mount_list(vmi: Vec<MountInfo>, paths: &[String], opt: &Options) -> Ve
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let paths: Vec<String> = matches
|
let paths: Vec<String> = matches
|
||||||
.values_of(OPT_PATHS)
|
.values_of(OPT_PATHS)
|
||||||
|
@ -293,6 +319,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_ALL)
|
Arg::new(OPT_ALL)
|
||||||
|
@ -358,6 +385,10 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.long("output")
|
.long("output")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.use_delimiter(true)
|
.use_delimiter(true)
|
||||||
|
.possible_values(OUTPUT_FIELD_LIST)
|
||||||
|
.default_missing_values(&OUTPUT_FIELD_LIST)
|
||||||
|
.default_values(&["source", "size", "used", "avail", "pcent", "target"])
|
||||||
|
.conflicts_with_all(&[OPT_INODES, OPT_PORTABILITY, OPT_PRINT_TYPE])
|
||||||
.help(
|
.help(
|
||||||
"use the output format defined by FIELD_LIST,\
|
"use the output format defined by FIELD_LIST,\
|
||||||
or print all fields if FIELD_LIST is omitted.",
|
or print all fields if FIELD_LIST is omitted.",
|
||||||
|
@ -381,7 +412,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.long("type")
|
.long("type")
|
||||||
.allow_invalid_utf8(true)
|
.allow_invalid_utf8(true)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.use_delimiter(true)
|
.multiple_occurrences(true)
|
||||||
.help("limit listing to file systems of type TYPE"),
|
.help("limit listing to file systems of type TYPE"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
//! [`DisplayRow`] implements [`std::fmt::Display`].
|
//! [`DisplayRow`] implements [`std::fmt::Display`].
|
||||||
use number_prefix::NumberPrefix;
|
use number_prefix::NumberPrefix;
|
||||||
|
|
||||||
use crate::{Filesystem, Options};
|
use crate::{BlockSize, Filesystem, Options};
|
||||||
use uucore::fsext::{FsUsage, MountInfo};
|
use uucore::fsext::{FsUsage, MountInfo};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -147,23 +147,10 @@ impl<'a> DisplayRow<'a> {
|
||||||
///
|
///
|
||||||
/// If the scaling factor is not 1000, 1024, or a negative number.
|
/// If the scaling factor is not 1000, 1024, or a negative number.
|
||||||
fn scaled(&self, size: u64) -> Result<String, fmt::Error> {
|
fn scaled(&self, size: u64) -> Result<String, fmt::Error> {
|
||||||
// TODO The argument-parsing code should be responsible for
|
let number_prefix = match self.options.block_size {
|
||||||
// ensuring that the `human_readable_base` number is
|
BlockSize::HumanReadableDecimal => NumberPrefix::decimal(size as f64),
|
||||||
// positive. Then we could remove the `Err` case from this
|
BlockSize::HumanReadableBinary => NumberPrefix::binary(size as f64),
|
||||||
// function.
|
BlockSize::Bytes(d) => return Ok((size / d).to_string()),
|
||||||
//
|
|
||||||
// TODO We should not be using a negative number to indicate
|
|
||||||
// default behavior. The default behavior for `df` is to show
|
|
||||||
// sizes in blocks of 1K bytes each, so we should just do
|
|
||||||
// that.
|
|
||||||
//
|
|
||||||
// TODO Support arbitrary positive scaling factors (from the
|
|
||||||
// `--block-size` command-line argument).
|
|
||||||
let number_prefix = match self.options.human_readable_base {
|
|
||||||
1000 => NumberPrefix::decimal(size as f64),
|
|
||||||
1024 => NumberPrefix::binary(size as f64),
|
|
||||||
d if d < 0 => return Ok(size.to_string()),
|
|
||||||
_ => return Err(fmt::Error {}),
|
|
||||||
};
|
};
|
||||||
match number_prefix {
|
match number_prefix {
|
||||||
NumberPrefix::Standalone(bytes) => Ok(bytes.to_string()),
|
NumberPrefix::Standalone(bytes) => Ok(bytes.to_string()),
|
||||||
|
@ -261,7 +248,9 @@ impl fmt::Display for Header<'_> {
|
||||||
write!(f, "{0: >12} ", "IFree")?;
|
write!(f, "{0: >12} ", "IFree")?;
|
||||||
write!(f, "{0: >5} ", "IUse%")?;
|
write!(f, "{0: >5} ", "IUse%")?;
|
||||||
} else {
|
} else {
|
||||||
if self.options.human_readable_base == -1 {
|
// TODO Support arbitrary positive scaling factors (from
|
||||||
|
// the `--block-size` command-line argument).
|
||||||
|
if let BlockSize::Bytes(_) = self.options.block_size {
|
||||||
write!(f, "{0: >12} ", "1k-blocks")?;
|
write!(f, "{0: >12} ", "1k-blocks")?;
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{0: >12} ", "Size")?;
|
write!(f, "{0: >12} ", "Size")?;
|
||||||
|
@ -281,14 +270,11 @@ impl fmt::Display for Header<'_> {
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use crate::table::{DisplayRow, Header, Row};
|
use crate::table::{DisplayRow, Header, Row};
|
||||||
use crate::Options;
|
use crate::{BlockSize, Options};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display() {
|
fn test_header_display() {
|
||||||
let options = Options {
|
let options = Default::default();
|
||||||
human_readable_base: -1,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Header::new(&options).to_string(),
|
Header::new(&options).to_string(),
|
||||||
"Filesystem 1k-blocks Used Available Use% Mounted on "
|
"Filesystem 1k-blocks Used Available Use% Mounted on "
|
||||||
|
@ -298,7 +284,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_fs_type() {
|
fn test_header_display_fs_type() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: -1,
|
|
||||||
show_fs_type: true,
|
show_fs_type: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -311,7 +296,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_inode() {
|
fn test_header_display_inode() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: -1,
|
|
||||||
show_inode_instead: true,
|
show_inode_instead: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -324,7 +308,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_human_readable_binary() {
|
fn test_header_display_human_readable_binary() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: 1024,
|
block_size: BlockSize::HumanReadableBinary,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -336,7 +320,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_header_display_human_readable_si() {
|
fn test_header_display_human_readable_si() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: 1000,
|
block_size: BlockSize::HumanReadableDecimal,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
|
@ -348,7 +332,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display() {
|
fn test_row_display() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: -1,
|
block_size: BlockSize::Bytes(1),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
let row = Row {
|
let row = Row {
|
||||||
|
@ -378,7 +362,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_fs_type() {
|
fn test_row_display_fs_type() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: -1,
|
block_size: BlockSize::Bytes(1),
|
||||||
show_fs_type: true,
|
show_fs_type: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -409,7 +393,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_inodes() {
|
fn test_row_display_inodes() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: -1,
|
block_size: BlockSize::Bytes(1),
|
||||||
show_inode_instead: true,
|
show_inode_instead: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -440,7 +424,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_human_readable_si() {
|
fn test_row_display_human_readable_si() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: 1000,
|
block_size: BlockSize::HumanReadableDecimal,
|
||||||
show_fs_type: true,
|
show_fs_type: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
@ -471,7 +455,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_row_display_human_readable_binary() {
|
fn test_row_display_human_readable_binary() {
|
||||||
let options = Options {
|
let options = Options {
|
||||||
human_readable_base: 1024,
|
block_size: BlockSize::HumanReadableBinary,
|
||||||
show_fs_type: true,
|
show_fs_type: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -24,7 +24,7 @@ mod options {
|
||||||
pub const FILE: &str = "FILE";
|
pub const FILE: &str = "FILE";
|
||||||
}
|
}
|
||||||
|
|
||||||
static SYNTAX: &str = "[OPTION]... [FILE]";
|
static USAGE: &str = "{} [OPTION]... [FILE]";
|
||||||
static SUMMARY: &str = "Output commands to set the LS_COLORS environment variable.";
|
static SUMMARY: &str = "Output commands to set the LS_COLORS environment variable.";
|
||||||
static LONG_HELP: &str = "
|
static LONG_HELP: &str = "
|
||||||
If FILE is specified, read it to determine which colors to use for which
|
If FILE is specified, read it to determine which colors to use for which
|
||||||
|
@ -61,19 +61,13 @@ pub fn guess_syntax() -> OutputFmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} {1}", uucore::execution_phrase(), SYNTAX)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(&args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(&args);
|
|
||||||
|
|
||||||
let files = matches
|
let files = matches
|
||||||
.values_of(options::FILE)
|
.values_of(options::FILE)
|
||||||
|
@ -165,6 +159,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::BOURNE_SHELL)
|
Arg::new(options::BOURNE_SHELL)
|
||||||
|
@ -257,7 +252,7 @@ enum ParseState {
|
||||||
Pass,
|
Pass,
|
||||||
}
|
}
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
fn parse<T>(lines: T, fmt: &OutputFmt, fp: &str) -> Result<String, String>
|
fn parse<T>(lines: T, fmt: &OutputFmt, fp: &str) -> Result<String, String>
|
||||||
where
|
where
|
||||||
|
|
|
@ -9,19 +9,16 @@ use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::print_verbatim;
|
use uucore::display::print_verbatim;
|
||||||
use uucore::error::{UResult, UUsageError};
|
use uucore::error::{UResult, UUsageError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str = "strip last component from file name";
|
static ABOUT: &str = "strip last component from file name";
|
||||||
|
const USAGE: &str = "{} [OPTION] NAME...";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const ZERO: &str = "zero";
|
pub const ZERO: &str = "zero";
|
||||||
pub const DIR: &str = "dir";
|
pub const DIR: &str = "dir";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION] NAME...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_long_usage() -> String {
|
fn get_long_usage() -> String {
|
||||||
String::from(
|
String::from(
|
||||||
"Output each NAME with its last non-slash component and trailing slashes
|
"Output each NAME with its last non-slash component and trailing slashes
|
||||||
|
@ -35,13 +32,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let usage = usage();
|
|
||||||
let after_help = get_long_usage();
|
let after_help = get_long_usage();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&after_help[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let separator = if matches.is_present(options::ZERO) {
|
let separator = if matches.is_present(options::ZERO) {
|
||||||
"\0"
|
"\0"
|
||||||
|
@ -87,6 +80,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::ZERO)
|
Arg::new(options::ZERO)
|
||||||
|
|
|
@ -12,7 +12,6 @@ use chrono::prelude::DateTime;
|
||||||
use chrono::Local;
|
use chrono::Local;
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::convert::TryFrom;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
|
@ -33,6 +32,7 @@ use std::time::{Duration, UNIX_EPOCH};
|
||||||
use std::{error::Error, fmt::Display};
|
use std::{error::Error, fmt::Display};
|
||||||
use uucore::display::{print_verbatim, Quotable};
|
use uucore::display::{print_verbatim, Quotable};
|
||||||
use uucore::error::{UError, UResult};
|
use uucore::error::{UError, UResult};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -80,6 +80,9 @@ SIZE is an integer and optional unit (example: 10M is 10*1024*1024).
|
||||||
Units are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB,... (powers
|
Units are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB,... (powers
|
||||||
of 1000).
|
of 1000).
|
||||||
";
|
";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} [OPTION]... [FILE]...
|
||||||
|
{} [OPTION]... --files0-from=F";
|
||||||
|
|
||||||
// TODO: Support Z & Y (currently limited by size of u64)
|
// TODO: Support Z & Y (currently limited by size of u64)
|
||||||
const UNITS: [(char, u32); 6] = [('E', 6), ('P', 5), ('T', 4), ('G', 3), ('M', 2), ('K', 1)];
|
const UNITS: [(char, u32); 6] = [('E', 6), ('P', 5), ('T', 4), ('G', 3), ('M', 2), ('K', 1)];
|
||||||
|
@ -244,7 +247,7 @@ fn get_file_info(path: &Path) -> Option<FileInfo> {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_block_size(s: Option<&str>) -> usize {
|
fn read_block_size(s: Option<&str>) -> u64 {
|
||||||
if let Some(s) = s {
|
if let Some(s) = s {
|
||||||
parse_size(s)
|
parse_size(s)
|
||||||
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::BLOCK_SIZE)))
|
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::BLOCK_SIZE)))
|
||||||
|
@ -391,14 +394,6 @@ fn convert_size_other(size: u64, _multiplier: u64, block_size: u64) -> String {
|
||||||
format!("{}", ((size as f64) / (block_size as f64)).ceil())
|
format!("{}", ((size as f64) / (block_size as f64)).ceil())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [OPTION]... [FILE]...
|
|
||||||
{0} [OPTION]... --files0-from=F",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum DuError {
|
enum DuError {
|
||||||
InvalidMaxDepthArg(String),
|
InvalidMaxDepthArg(String),
|
||||||
|
@ -459,9 +454,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let summarize = matches.is_present(options::SUMMARIZE);
|
let summarize = matches.is_present(options::SUMMARIZE);
|
||||||
|
|
||||||
|
@ -489,7 +482,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
show_warning!("options --apparent-size and -b are ineffective with --inodes");
|
show_warning!("options --apparent-size and -b are ineffective with --inodes");
|
||||||
}
|
}
|
||||||
|
|
||||||
let block_size = u64::try_from(read_block_size(matches.value_of(options::BLOCK_SIZE))).unwrap();
|
let block_size = read_block_size(matches.value_of(options::BLOCK_SIZE));
|
||||||
|
|
||||||
let threshold = matches.value_of(options::THRESHOLD).map(|s| {
|
let threshold = matches.value_of(options::THRESHOLD).map(|s| {
|
||||||
Threshold::from_str(s)
|
Threshold::from_str(s)
|
||||||
|
@ -629,6 +622,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::ALL)
|
Arg::new(options::ALL)
|
||||||
|
@ -812,7 +806,7 @@ impl FromStr for Threshold {
|
||||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||||
let offset = if s.starts_with(&['-', '+'][..]) { 1 } else { 0 };
|
let offset = if s.starts_with(&['-', '+'][..]) { 1 } else { 0 };
|
||||||
|
|
||||||
let size = u64::try_from(parse_size(&s[offset..])?).unwrap();
|
let size = parse_size(&s[offset..])?;
|
||||||
|
|
||||||
if s.starts_with('-') {
|
if s.starts_with('-') {
|
||||||
Ok(Self::Upper(size))
|
Ok(Self::Upper(size))
|
||||||
|
|
|
@ -11,11 +11,11 @@ use std::io::{self, Write};
|
||||||
use std::iter::Peekable;
|
use std::iter::Peekable;
|
||||||
use std::str::Chars;
|
use std::str::Chars;
|
||||||
use uucore::error::{FromIo, UResult};
|
use uucore::error::{FromIo, UResult};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
const NAME: &str = "echo";
|
const NAME: &str = "echo";
|
||||||
const SUMMARY: &str = "display a line of text";
|
const SUMMARY: &str = "display a line of text";
|
||||||
const USAGE: &str = "[OPTIONS]... [STRING]...";
|
const USAGE: &str = "{} [OPTIONS]... [STRING]...";
|
||||||
const AFTER_HELP: &str = r#"
|
const AFTER_HELP: &str = r#"
|
||||||
Echo the STRING(s) to standard output.
|
Echo the STRING(s) to standard output.
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.after_help(AFTER_HELP)
|
.after_help(AFTER_HELP)
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::NO_NEWLINE)
|
Arg::new(options::NO_NEWLINE)
|
||||||
.short('n')
|
.short('n')
|
||||||
|
|
5
src/uu/env/src/env.rs
vendored
5
src/uu/env/src/env.rs
vendored
|
@ -25,8 +25,9 @@ use std::iter::Iterator;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError, UUsageError};
|
use uucore::error::{UResult, USimpleError, UUsageError};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
const USAGE: &str = "env [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]";
|
const USAGE: &str = "{} [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]";
|
||||||
const AFTER_HELP: &str = "\
|
const AFTER_HELP: &str = "\
|
||||||
A mere - implies -i. If no COMMAND, print the resulting environment.
|
A mere - implies -i. If no COMMAND, print the resulting environment.
|
||||||
";
|
";
|
||||||
|
@ -125,7 +126,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.author(crate_authors!())
|
.author(crate_authors!())
|
||||||
.about(crate_description!())
|
.about(crate_description!())
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.after_help(AFTER_HELP)
|
.after_help(AFTER_HELP)
|
||||||
.setting(AppSettings::AllowExternalSubcommands)
|
.setting(AppSettings::AllowExternalSubcommands)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
|
|
|
@ -19,9 +19,11 @@ use std::str::from_utf8;
|
||||||
use unicode_width::UnicodeWidthChar;
|
use unicode_width::UnicodeWidthChar;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult};
|
use uucore::error::{FromIo, UResult};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
static ABOUT: &str = "Convert tabs in each FILE to spaces, writing to standard output.
|
static ABOUT: &str = "Convert tabs in each FILE to spaces, writing to standard output.
|
||||||
With no FILE, or when FILE is -, read standard input.";
|
With no FILE, or when FILE is -, read standard input.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static TABS: &str = "tabs";
|
pub static TABS: &str = "tabs";
|
||||||
|
@ -34,10 +36,6 @@ static LONG_HELP: &str = "";
|
||||||
|
|
||||||
static DEFAULT_TABSTOP: usize = 8;
|
static DEFAULT_TABSTOP: usize = 8;
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The mode to use when replacing tabs beyond the last one specified in
|
/// The mode to use when replacing tabs beyond the last one specified in
|
||||||
/// the `--tabs` argument.
|
/// the `--tabs` argument.
|
||||||
enum RemainingMode {
|
enum RemainingMode {
|
||||||
|
@ -173,8 +171,7 @@ impl Options {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
expand(&Options::new(&matches)).map_err_context(|| "failed to write output".to_string())
|
expand(&Options::new(&matches)).map_err_context(|| "failed to write output".to_string())
|
||||||
}
|
}
|
||||||
|
@ -184,6 +181,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::INITIAL)
|
Arg::new(options::INITIAL)
|
||||||
|
|
|
@ -19,7 +19,7 @@ clap = { version = "3.0", features = ["wrap_help", "cargo"] }
|
||||||
libc = "0.2.42"
|
libc = "0.2.42"
|
||||||
num-bigint = "0.4.0"
|
num-bigint = "0.4.0"
|
||||||
num-traits = "0.2.14"
|
num-traits = "0.2.14"
|
||||||
onig = "~4.3.2"
|
onig = { version = "~6.3", default-features = false }
|
||||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
|
|
|
@ -17,6 +17,7 @@ use std::io::{stdin, stdout, Write};
|
||||||
use std::io::{BufReader, BufWriter, Read};
|
use std::io::{BufReader, BufWriter, Read};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
use self::linebreak::break_lines;
|
use self::linebreak::break_lines;
|
||||||
use self::parasplit::ParagraphStream;
|
use self::parasplit::ParagraphStream;
|
||||||
|
@ -25,6 +26,7 @@ mod linebreak;
|
||||||
mod parasplit;
|
mod parasplit;
|
||||||
|
|
||||||
static ABOUT: &str = "Reformat paragraphs from input files (or stdin) to stdout.";
|
static ABOUT: &str = "Reformat paragraphs from input files (or stdin) to stdout.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
static MAX_WIDTH: usize = 2500;
|
static MAX_WIDTH: usize = 2500;
|
||||||
|
|
||||||
static OPT_CROWN_MARGIN: &str = "crown-margin";
|
static OPT_CROWN_MARGIN: &str = "crown-margin";
|
||||||
|
@ -43,10 +45,6 @@ static OPT_TAB_WIDTH: &str = "tab-width";
|
||||||
|
|
||||||
static ARG_FILES: &str = "files";
|
static ARG_FILES: &str = "files";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{} [OPTION]... [FILE]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type FileOrStdReader = BufReader<Box<dyn Read + 'static>>;
|
pub type FileOrStdReader = BufReader<Box<dyn Read + 'static>>;
|
||||||
pub struct FmtOptions {
|
pub struct FmtOptions {
|
||||||
crown: bool,
|
crown: bool,
|
||||||
|
@ -69,9 +67,7 @@ pub struct FmtOptions {
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let mut files: Vec<String> = matches
|
let mut files: Vec<String> = matches
|
||||||
.values_of(ARG_FILES)
|
.values_of(ARG_FILES)
|
||||||
|
@ -226,6 +222,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_CROWN_MARGIN)
|
Arg::new(OPT_CROWN_MARGIN)
|
||||||
|
|
|
@ -13,12 +13,12 @@ use std::io::{stdin, BufRead, BufReader, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
const TAB_WIDTH: usize = 8;
|
const TAB_WIDTH: usize = 8;
|
||||||
|
|
||||||
static NAME: &str = "fold";
|
static NAME: &str = "fold";
|
||||||
static SYNTAX: &str = "[OPTION]... [FILE]...";
|
static USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
static SUMMARY: &str = "Writes each file (or standard input if no files are given)
|
static SUMMARY: &str = "Writes each file (or standard input if no files are given)
|
||||||
to standard output whilst breaking long lines";
|
to standard output whilst breaking long lines";
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(SYNTAX)
|
.override_usage(format_usage(USAGE))
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -23,6 +23,7 @@ use uucore::{
|
||||||
display::Quotable,
|
display::Quotable,
|
||||||
entries::{get_groups_gnu, gid2grp, Locate, Passwd},
|
entries::{get_groups_gnu, gid2grp, Locate, Passwd},
|
||||||
error::{UError, UResult},
|
error::{UError, UResult},
|
||||||
|
format_usage,
|
||||||
};
|
};
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg};
|
use clap::{crate_version, App, AppSettings, Arg};
|
||||||
|
@ -34,9 +35,7 @@ static ABOUT: &str = "Print group memberships for each USERNAME or, \
|
||||||
if no USERNAME is specified, for\nthe current process \
|
if no USERNAME is specified, for\nthe current process \
|
||||||
(which may differ if the groups data‐base has changed).";
|
(which may differ if the groups data‐base has changed).";
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "{} [OPTION]... [USERNAME]...";
|
||||||
format!("{0} [OPTION]... [USERNAME]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum GroupsError {
|
enum GroupsError {
|
||||||
|
@ -71,9 +70,7 @@ fn infallible_gid2grp(gid: &u32) -> String {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let users: Vec<String> = matches
|
let users: Vec<String> = matches
|
||||||
.values_of(options::USERS)
|
.values_of(options::USERS)
|
||||||
|
@ -109,6 +106,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::USERS)
|
Arg::new(options::USERS)
|
||||||
|
|
|
@ -17,15 +17,15 @@ path = "src/hashsum.rs"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
digest = "0.10.1"
|
digest = "0.10.1"
|
||||||
clap = { version = "3.0", features = ["wrap_help", "cargo"] }
|
clap = { version = "3.0", features = ["wrap_help", "cargo"] }
|
||||||
hex = "0.2.0"
|
hex = "0.4.3"
|
||||||
libc = "0.2.42"
|
libc = "0.2.42"
|
||||||
memchr = "2"
|
memchr = "2"
|
||||||
md5 = "0.3.5"
|
md-5 = "0.10.1"
|
||||||
regex = "1.0.1"
|
regex = "1.0.1"
|
||||||
regex-syntax = "0.6.7"
|
regex-syntax = "0.6.7"
|
||||||
sha1 = "0.10.0"
|
sha1 = "0.10.1"
|
||||||
sha2 = "0.10.1"
|
sha2 = "0.10.2"
|
||||||
sha3 = "0.10.0"
|
sha3 = "0.10.1"
|
||||||
blake2b_simd = "0.5.11"
|
blake2b_simd = "0.5.11"
|
||||||
blake3 = "1.3.1"
|
blake3 = "1.3.1"
|
||||||
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
uucore = { version=">=0.0.11", package="uucore", path="../../uucore" }
|
||||||
|
|
|
@ -14,7 +14,7 @@ extern crate sha3;
|
||||||
|
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use hex::ToHex;
|
use hex::encode;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use memchr::memmem;
|
use memchr::memmem;
|
||||||
|
|
||||||
|
@ -32,29 +32,7 @@ pub trait Digest {
|
||||||
fn result_str(&mut self) -> String {
|
fn result_str(&mut self) -> String {
|
||||||
let mut buf: Vec<u8> = vec![0; self.output_bytes()];
|
let mut buf: Vec<u8> = vec![0; self.output_bytes()];
|
||||||
self.result(&mut buf);
|
self.result(&mut buf);
|
||||||
buf.to_hex()
|
encode(buf)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Digest for md5::Context {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input(&mut self, input: &[u8]) {
|
|
||||||
self.consume(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result(&mut self, out: &mut [u8]) {
|
|
||||||
out.copy_from_slice(&*self.compute());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
*self = Self::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_bits(&self) -> usize {
|
|
||||||
128
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,30 +82,8 @@ impl Digest for blake3::Hasher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Digest for sha1::Sha1 {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn input(&mut self, input: &[u8]) {
|
|
||||||
digest::Digest::update(self, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result(&mut self, out: &mut [u8]) {
|
|
||||||
digest::Digest::finalize_into_reset(self, out.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
*self = Self::new();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn output_bits(&self) -> usize {
|
|
||||||
160
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Implements the Digest trait for sha2 / sha3 algorithms with fixed output
|
// Implements the Digest trait for sha2 / sha3 algorithms with fixed output
|
||||||
macro_rules! impl_digest_sha {
|
macro_rules! impl_digest_common {
|
||||||
($type: ty, $size: expr) => {
|
($type: ty, $size: expr) => {
|
||||||
impl Digest for $type {
|
impl Digest for $type {
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
|
@ -180,15 +136,17 @@ macro_rules! impl_digest_shake {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_digest_sha!(sha2::Sha224, 224);
|
impl_digest_common!(md5::Md5, 128);
|
||||||
impl_digest_sha!(sha2::Sha256, 256);
|
impl_digest_common!(sha1::Sha1, 160);
|
||||||
impl_digest_sha!(sha2::Sha384, 384);
|
impl_digest_common!(sha2::Sha224, 224);
|
||||||
impl_digest_sha!(sha2::Sha512, 512);
|
impl_digest_common!(sha2::Sha256, 256);
|
||||||
|
impl_digest_common!(sha2::Sha384, 384);
|
||||||
|
impl_digest_common!(sha2::Sha512, 512);
|
||||||
|
|
||||||
impl_digest_sha!(sha3::Sha3_224, 224);
|
impl_digest_common!(sha3::Sha3_224, 224);
|
||||||
impl_digest_sha!(sha3::Sha3_256, 256);
|
impl_digest_common!(sha3::Sha3_256, 256);
|
||||||
impl_digest_sha!(sha3::Sha3_384, 384);
|
impl_digest_common!(sha3::Sha3_384, 384);
|
||||||
impl_digest_sha!(sha3::Sha3_512, 512);
|
impl_digest_common!(sha3::Sha3_512, 512);
|
||||||
impl_digest_shake!(sha3::Shake128);
|
impl_digest_shake!(sha3::Shake128);
|
||||||
impl_digest_shake!(sha3::Shake256);
|
impl_digest_shake!(sha3::Shake256);
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,8 @@ use self::digest::Digest;
|
||||||
use self::digest::DigestWriter;
|
use self::digest::DigestWriter;
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg, ArgMatches};
|
use clap::{App, AppSettings, Arg, ArgMatches};
|
||||||
use hex::ToHex;
|
use hex::encode;
|
||||||
use md5::Context as Md5;
|
use md5::Md5;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use sha1::Sha1;
|
use sha1::Sha1;
|
||||||
use sha2::{Sha224, Sha256, Sha384, Sha512};
|
use sha2::{Sha224, Sha256, Sha384, Sha512};
|
||||||
|
@ -652,6 +652,6 @@ fn digest_reader<T: Read>(
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
bytes.resize((output_bits + 7) / 8, 0);
|
bytes.resize((output_bits + 7) / 8, 0);
|
||||||
digest.result(&mut bytes);
|
digest.result(&mut bytes);
|
||||||
Ok(bytes.to_hex())
|
Ok(encode(bytes))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use std::io::{self, BufWriter, ErrorKind, Read, Seek, SeekFrom, Write};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UError, UResult, USimpleError};
|
use uucore::error::{FromIo, UError, UResult, USimpleError};
|
||||||
use uucore::lines::lines;
|
use uucore::lines::lines;
|
||||||
use uucore::show;
|
use uucore::{format_usage, show};
|
||||||
|
|
||||||
const BUF_SIZE: usize = 65536;
|
const BUF_SIZE: usize = 65536;
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ const ABOUT: &str = "\
|
||||||
\n\
|
\n\
|
||||||
Mandatory arguments to long flags are mandatory for short flags too.\
|
Mandatory arguments to long flags are mandatory for short flags too.\
|
||||||
";
|
";
|
||||||
const USAGE: &str = "head [FLAG]... [FILE]...";
|
const USAGE: &str = "{} [FLAG]... [FILE]...";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const BYTES_NAME: &str = "BYTES";
|
pub const BYTES_NAME: &str = "BYTES";
|
||||||
|
@ -45,7 +45,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::BYTES_NAME)
|
Arg::new(options::BYTES_NAME)
|
||||||
|
@ -106,10 +106,10 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
enum Mode {
|
enum Mode {
|
||||||
FirstLines(usize),
|
FirstLines(u64),
|
||||||
AllButLastLines(usize),
|
AllButLastLines(u64),
|
||||||
FirstBytes(usize),
|
FirstBytes(u64),
|
||||||
AllButLastBytes(usize),
|
AllButLastBytes(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Mode {
|
impl Default for Mode {
|
||||||
|
@ -199,12 +199,12 @@ impl HeadOptions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_n_bytes<R>(input: R, n: usize) -> std::io::Result<()>
|
fn read_n_bytes<R>(input: R, n: u64) -> std::io::Result<()>
|
||||||
where
|
where
|
||||||
R: Read,
|
R: Read,
|
||||||
{
|
{
|
||||||
// Read the first `n` bytes from the `input` reader.
|
// Read the first `n` bytes from the `input` reader.
|
||||||
let mut reader = input.take(n as u64);
|
let mut reader = input.take(n);
|
||||||
|
|
||||||
// Write those bytes to `stdout`.
|
// Write those bytes to `stdout`.
|
||||||
let stdout = std::io::stdout();
|
let stdout = std::io::stdout();
|
||||||
|
@ -215,7 +215,7 @@ where
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_n_lines(input: &mut impl std::io::BufRead, n: usize, zero: bool) -> std::io::Result<()> {
|
fn read_n_lines(input: &mut impl std::io::BufRead, n: u64, zero: bool) -> std::io::Result<()> {
|
||||||
// Read the first `n` lines from the `input` reader.
|
// Read the first `n` lines from the `input` reader.
|
||||||
let separator = if zero { b'\0' } else { b'\n' };
|
let separator = if zero { b'\0' } else { b'\n' };
|
||||||
let mut reader = take_lines(input, n, separator);
|
let mut reader = take_lines(input, n, separator);
|
||||||
|
@ -233,8 +233,9 @@ fn read_n_lines(input: &mut impl std::io::BufRead, n: usize, zero: bool) -> std:
|
||||||
fn read_but_last_n_bytes(input: &mut impl std::io::BufRead, n: usize) -> std::io::Result<()> {
|
fn read_but_last_n_bytes(input: &mut impl std::io::BufRead, n: usize) -> std::io::Result<()> {
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
//prints everything
|
//prints everything
|
||||||
return read_n_bytes(input, std::usize::MAX);
|
return read_n_bytes(input, std::u64::MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
let stdout = std::io::stdout();
|
let stdout = std::io::stdout();
|
||||||
let mut stdout = stdout.lock();
|
let mut stdout = stdout.lock();
|
||||||
|
|
||||||
|
@ -337,17 +338,18 @@ fn read_but_last_n_lines(
|
||||||
/// assert_eq!(find_nth_line_from_end(&mut input, 4, false).unwrap(), 0);
|
/// assert_eq!(find_nth_line_from_end(&mut input, 4, false).unwrap(), 0);
|
||||||
/// assert_eq!(find_nth_line_from_end(&mut input, 1000, false).unwrap(), 0);
|
/// assert_eq!(find_nth_line_from_end(&mut input, 1000, false).unwrap(), 0);
|
||||||
/// ```
|
/// ```
|
||||||
fn find_nth_line_from_end<R>(input: &mut R, n: usize, zeroed: bool) -> std::io::Result<usize>
|
fn find_nth_line_from_end<R>(input: &mut R, n: u64, zeroed: bool) -> std::io::Result<u64>
|
||||||
where
|
where
|
||||||
R: Read + Seek,
|
R: Read + Seek,
|
||||||
{
|
{
|
||||||
let size = input.seek(SeekFrom::End(0))?;
|
let size = input.seek(SeekFrom::End(0))?;
|
||||||
let size = usize::try_from(size).unwrap();
|
|
||||||
|
|
||||||
let mut buffer = [0u8; BUF_SIZE];
|
let mut buffer = [0u8; BUF_SIZE];
|
||||||
let buffer = &mut buffer[..BUF_SIZE.min(size)];
|
let buf_size: usize = (BUF_SIZE as u64).min(size).try_into().unwrap();
|
||||||
let mut i = 0usize;
|
let buffer = &mut buffer[..buf_size];
|
||||||
let mut lines = 0usize;
|
|
||||||
|
let mut i = 0u64;
|
||||||
|
let mut lines = 0u64;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// the casts here are ok, `buffer.len()` should never be above a few k
|
// the casts here are ok, `buffer.len()` should never be above a few k
|
||||||
|
@ -382,7 +384,7 @@ where
|
||||||
fn head_backwards_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<()> {
|
fn head_backwards_file(input: &mut std::fs::File, options: &HeadOptions) -> std::io::Result<()> {
|
||||||
match options.mode {
|
match options.mode {
|
||||||
Mode::AllButLastBytes(n) => {
|
Mode::AllButLastBytes(n) => {
|
||||||
let size = input.metadata()?.len().try_into().unwrap();
|
let size = input.metadata()?.len();
|
||||||
if n >= size {
|
if n >= size {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
|
@ -431,12 +433,30 @@ fn uu_head(options: &HeadOptions) -> UResult<()> {
|
||||||
}
|
}
|
||||||
let stdin = std::io::stdin();
|
let stdin = std::io::stdin();
|
||||||
let mut stdin = stdin.lock();
|
let mut stdin = stdin.lock();
|
||||||
|
|
||||||
|
// Outputting "all-but-last" requires us to use a ring buffer with size n, so n
|
||||||
|
// must be converted from u64 to usize to fit in memory. If such conversion fails,
|
||||||
|
// it means the platform doesn't have enough memory to hold the buffer, so we fail.
|
||||||
|
if let Mode::AllButLastLines(n) | Mode::AllButLastBytes(n) = options.mode {
|
||||||
|
if let Err(e) = usize::try_from(n) {
|
||||||
|
show!(USimpleError::new(
|
||||||
|
1,
|
||||||
|
format!("{}: number of bytes is too large", e)
|
||||||
|
));
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
match options.mode {
|
match options.mode {
|
||||||
Mode::FirstBytes(n) => read_n_bytes(&mut stdin, n),
|
Mode::FirstBytes(n) => read_n_bytes(&mut stdin, n),
|
||||||
Mode::AllButLastBytes(n) => read_but_last_n_bytes(&mut stdin, n),
|
// unwrap is guaranteed to succeed because we checked the value of n above
|
||||||
|
Mode::AllButLastBytes(n) => {
|
||||||
|
read_but_last_n_bytes(&mut stdin, n.try_into().unwrap())
|
||||||
|
}
|
||||||
Mode::FirstLines(n) => read_n_lines(&mut stdin, n, options.zeroed),
|
Mode::FirstLines(n) => read_n_lines(&mut stdin, n, options.zeroed),
|
||||||
|
// unwrap is guaranteed to succeed because we checked the value of n above
|
||||||
Mode::AllButLastLines(n) => {
|
Mode::AllButLastLines(n) => {
|
||||||
read_but_last_n_lines(&mut stdin, n, options.zeroed)
|
read_but_last_n_lines(&mut stdin, n.try_into().unwrap(), options.zeroed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ pub fn parse_obsolete(src: &str) -> Option<Result<impl Iterator<Item = OsString>
|
||||||
}
|
}
|
||||||
/// Parses an -c or -n argument,
|
/// Parses an -c or -n argument,
|
||||||
/// the bool specifies whether to read from the end
|
/// the bool specifies whether to read from the end
|
||||||
pub fn parse_num(src: &str) -> Result<(usize, bool), ParseSizeError> {
|
pub fn parse_num(src: &str) -> Result<(u64, bool), ParseSizeError> {
|
||||||
let mut size_string = src.trim();
|
let mut size_string = src.trim();
|
||||||
let mut all_but_last = false;
|
let mut all_but_last = false;
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ where
|
||||||
/// details.
|
/// details.
|
||||||
pub struct TakeLines<T> {
|
pub struct TakeLines<T> {
|
||||||
inner: T,
|
inner: T,
|
||||||
limit: usize,
|
limit: u64,
|
||||||
separator: u8,
|
separator: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ impl<T: Read> Read for TakeLines<T> {
|
||||||
///
|
///
|
||||||
/// The `separator` defines the character to interpret as the line
|
/// The `separator` defines the character to interpret as the line
|
||||||
/// ending. For the usual notion of "line", set this to `b'\n'`.
|
/// ending. For the usual notion of "line", set this to `b'\n'`.
|
||||||
pub fn take_lines<R>(reader: R, limit: usize, separator: u8) -> TakeLines<R> {
|
pub fn take_lines<R>(reader: R, limit: u64, separator: u8) -> TakeLines<R> {
|
||||||
TakeLines {
|
TakeLines {
|
||||||
inner: reader,
|
inner: reader,
|
||||||
limit,
|
limit,
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings};
|
use clap::{crate_version, App, AppSettings};
|
||||||
use libc::c_long;
|
use libc::c_long;
|
||||||
use uucore::error::UResult;
|
use uucore::{error::UResult, format_usage};
|
||||||
|
|
||||||
static SYNTAX: &str = "[options]";
|
const USAGE: &str = "{} [options]";
|
||||||
const SUMMARY: &str = "Print the numeric identifier (in hexadecimal) for the current host";
|
const SUMMARY: &str = "Print the numeric identifier (in hexadecimal) for the current host";
|
||||||
|
|
||||||
// currently rust libc interface doesn't include gethostid
|
// currently rust libc interface doesn't include gethostid
|
||||||
|
@ -30,7 +30,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.override_usage(SYNTAX)
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,13 @@ use std::str;
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
|
|
||||||
use uucore::error::{FromIo, UResult};
|
use uucore::{
|
||||||
|
error::{FromIo, UResult},
|
||||||
|
format_usage,
|
||||||
|
};
|
||||||
|
|
||||||
static ABOUT: &str = "Display or set the system's host name.";
|
static ABOUT: &str = "Display or set the system's host name.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [HOSTNAME]";
|
||||||
|
|
||||||
static OPT_DOMAIN: &str = "domain";
|
static OPT_DOMAIN: &str = "domain";
|
||||||
static OPT_IP_ADDRESS: &str = "ip-address";
|
static OPT_IP_ADDRESS: &str = "ip-address";
|
||||||
|
@ -54,14 +58,9 @@ mod wsa {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [HOSTNAME]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _handle = wsa::start().map_err_context(|| "failed to start Winsock".to_owned())?;
|
let _handle = wsa::start().map_err_context(|| "failed to start Winsock".to_owned())?;
|
||||||
|
@ -76,6 +75,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_DOMAIN)
|
Arg::new(OPT_DOMAIN)
|
||||||
|
|
|
@ -45,6 +45,7 @@ use uucore::display::Quotable;
|
||||||
use uucore::entries::{self, Group, Locate, Passwd};
|
use uucore::entries::{self, Group, Locate, Passwd};
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
use uucore::error::{set_exit_code, USimpleError};
|
use uucore::error::{set_exit_code, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
pub use uucore::libc;
|
pub use uucore::libc;
|
||||||
use uucore::libc::{getlogin, uid_t};
|
use uucore::libc::{getlogin, uid_t};
|
||||||
use uucore::process::{getegid, geteuid, getgid, getuid};
|
use uucore::process::{getegid, geteuid, getgid, getuid};
|
||||||
|
@ -57,6 +58,7 @@ macro_rules! cstr2cow {
|
||||||
|
|
||||||
static ABOUT: &str = "Print user and group information for each specified USER,
|
static ABOUT: &str = "Print user and group information for each specified USER,
|
||||||
or (when USER omitted) for the current user.";
|
or (when USER omitted) for the current user.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [USER]...";
|
||||||
|
|
||||||
#[cfg(not(feature = "selinux"))]
|
#[cfg(not(feature = "selinux"))]
|
||||||
static CONTEXT_HELP_TEXT: &str = "print only the security context of the process (not enabled)";
|
static CONTEXT_HELP_TEXT: &str = "print only the security context of the process (not enabled)";
|
||||||
|
@ -77,10 +79,6 @@ mod options {
|
||||||
pub const ARG_USERS: &str = "USER";
|
pub const ARG_USERS: &str = "USER";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [USER]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_description() -> String {
|
fn get_description() -> String {
|
||||||
String::from(
|
String::from(
|
||||||
"The id utility displays the user and group names and numeric IDs, of the \
|
"The id utility displays the user and group names and numeric IDs, of the \
|
||||||
|
@ -128,13 +126,9 @@ struct State {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let after_help = get_description();
|
let after_help = get_description();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&after_help[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let users: Vec<String> = matches
|
let users: Vec<String> = matches
|
||||||
.values_of(options::ARG_USERS)
|
.values_of(options::ARG_USERS)
|
||||||
|
@ -351,6 +345,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::OPT_AUDIT)
|
Arg::new(options::OPT_AUDIT)
|
||||||
|
|
|
@ -18,7 +18,8 @@ use filetime::{set_file_times, FileTime};
|
||||||
use uucore::backup_control::{self, BackupMode};
|
use uucore::backup_control::{self, BackupMode};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::entries::{grp2gid, usr2uid};
|
use uucore::entries::{grp2gid, usr2uid};
|
||||||
use uucore::error::{FromIo, UError, UIoError, UResult};
|
use uucore::error::{FromIo, UError, UIoError, UResult, UUsageError};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::mode::get_umask;
|
use uucore::mode::get_umask;
|
||||||
use uucore::perms::{wrap_chown, Verbosity, VerbosityLevel};
|
use uucore::perms::{wrap_chown, Verbosity, VerbosityLevel};
|
||||||
|
|
||||||
|
@ -144,6 +145,7 @@ impl Behavior {
|
||||||
|
|
||||||
static ABOUT: &str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
|
static ABOUT: &str = "Copy SOURCE to DEST or multiple SOURCE(s) to the existing
|
||||||
DIRECTORY, while setting permission modes and owner/group";
|
DIRECTORY, while setting permission modes and owner/group";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
|
|
||||||
static OPT_COMPARE: &str = "compare";
|
static OPT_COMPARE: &str = "compare";
|
||||||
static OPT_DIRECTORY: &str = "directory";
|
static OPT_DIRECTORY: &str = "directory";
|
||||||
|
@ -163,19 +165,13 @@ static OPT_CONTEXT: &str = "context";
|
||||||
|
|
||||||
static ARG_FILES: &str = "files";
|
static ARG_FILES: &str = "files";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Main install utility function, called from main.rs.
|
/// Main install utility function, called from main.rs.
|
||||||
///
|
///
|
||||||
/// Returns a program return code.
|
/// Returns a program return code.
|
||||||
///
|
///
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let paths: Vec<String> = matches
|
let paths: Vec<String> = matches
|
||||||
.values_of(ARG_FILES)
|
.values_of(ARG_FILES)
|
||||||
|
@ -196,6 +192,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
backup_control::arguments::backup()
|
backup_control::arguments::backup()
|
||||||
|
@ -445,11 +442,14 @@ fn is_new_file_path(path: &Path) -> bool {
|
||||||
/// Returns a Result type with the Err variant containing the error message.
|
/// Returns a Result type with the Err variant containing the error message.
|
||||||
///
|
///
|
||||||
fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
|
fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
|
||||||
let target: PathBuf = b
|
let target: PathBuf = if let Some(path) = &b.target_dir {
|
||||||
.target_dir
|
path.into()
|
||||||
.clone()
|
} else {
|
||||||
.unwrap_or_else(|| paths.pop().unwrap())
|
paths
|
||||||
.into();
|
.pop()
|
||||||
|
.ok_or_else(|| UUsageError::new(1, "missing file operand"))?
|
||||||
|
.into()
|
||||||
|
};
|
||||||
|
|
||||||
let sources = &paths.iter().map(PathBuf::from).collect::<Vec<_>>();
|
let sources = &paths.iter().map(PathBuf::from).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -471,7 +471,19 @@ fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if target.is_file() || is_new_file_path(&target) {
|
if target.is_file() || is_new_file_path(&target) {
|
||||||
copy(&sources[0], &target, b)
|
copy(
|
||||||
|
sources.get(0).ok_or_else(|| {
|
||||||
|
UUsageError::new(
|
||||||
|
1,
|
||||||
|
format!(
|
||||||
|
"missing destination file operand after '{}'",
|
||||||
|
target.to_str().unwrap()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})?,
|
||||||
|
&target,
|
||||||
|
b,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Err(InstallError::InvalidTarget(target).into())
|
Err(InstallError::InvalidTarget(target).into())
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,9 +16,10 @@ use std::io::Error;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
use uucore::signals::{signal_by_name_or_value, ALL_SIGNALS};
|
use uucore::signals::{signal_by_name_or_value, ALL_SIGNALS};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str = "Send signal to processes or list information about signals.";
|
static ABOUT: &str = "Send signal to processes or list information about signals.";
|
||||||
|
const USAGE: &str = "{} [OPTIONS]... PID...";
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static PIDS_OR_SIGNALS: &str = "pids_of_signals";
|
pub static PIDS_OR_SIGNALS: &str = "pids_of_signals";
|
||||||
|
@ -42,8 +43,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.accept_any();
|
.accept_any();
|
||||||
let obs_signal = handle_obsolete(&mut args);
|
let obs_signal = handle_obsolete(&mut args);
|
||||||
|
|
||||||
let usage = format!("{} [OPTIONS]... PID...", uucore::execution_phrase());
|
let matches = uu_app().get_matches_from(args);
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let mode = if matches.is_present(options::TABLE) || matches.is_present(options::TABLE_OLD) {
|
let mode = if matches.is_present(options::TABLE) || matches.is_present(options::TABLE_OLD) {
|
||||||
Mode::Table
|
Mode::Table
|
||||||
|
@ -82,6 +82,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::LIST)
|
Arg::new(options::LIST)
|
||||||
|
|
|
@ -9,21 +9,18 @@ use std::fs::hard_link;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult};
|
use uucore::error::{FromIo, UResult};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
static ABOUT: &str = "Call the link function to create a link named FILE2 to an existing FILE1.";
|
static ABOUT: &str = "Call the link function to create a link named FILE2 to an existing FILE1.";
|
||||||
|
const USAGE: &str = "{} FILE1 FILE2";
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static FILES: &str = "FILES";
|
pub static FILES: &str = "FILES";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} FILE1 FILE2", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let files: Vec<_> = matches
|
let files: Vec<_> = matches
|
||||||
.values_of_os(options::FILES)
|
.values_of_os(options::FILES)
|
||||||
|
@ -40,6 +37,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::FILES)
|
Arg::new(options::FILES)
|
||||||
|
|
|
@ -13,6 +13,7 @@ extern crate uucore;
|
||||||
use clap::{crate_version, App, AppSettings, Arg};
|
use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UError, UResult};
|
use uucore::error::{UError, UResult};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -90,16 +91,6 @@ impl UError for LnError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [OPTION]... [-T] TARGET LINK_NAME (1st form)
|
|
||||||
{0} [OPTION]... TARGET (2nd form)
|
|
||||||
{0} [OPTION]... TARGET... DIRECTORY (3rd form)
|
|
||||||
{0} [OPTION]... -t DIRECTORY TARGET... (4th form)",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn long_usage() -> String {
|
fn long_usage() -> String {
|
||||||
String::from(
|
String::from(
|
||||||
" In the 1st form, create a link to TARGET with the name LINK_NAME.
|
" In the 1st form, create a link to TARGET with the name LINK_NAME.
|
||||||
|
@ -115,6 +106,11 @@ fn long_usage() -> String {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ABOUT: &str = "change file owner and group";
|
static ABOUT: &str = "change file owner and group";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} [OPTION]... [-T] TARGET LINK_NAME
|
||||||
|
{} [OPTION]... TARGET
|
||||||
|
{} [OPTION]... TARGET... DIRECTORY
|
||||||
|
{} [OPTION]... -t DIRECTORY TARGET...";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const FORCE: &str = "force";
|
pub const FORCE: &str = "force";
|
||||||
|
@ -131,11 +127,9 @@ static ARG_FILES: &str = "files";
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let long_usage = long_usage();
|
let long_usage = long_usage();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app()
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&*format!(
|
.after_help(&*format!(
|
||||||
"{}\n{}",
|
"{}\n{}",
|
||||||
long_usage,
|
long_usage,
|
||||||
|
@ -183,6 +177,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(backup_control::arguments::backup())
|
.arg(backup_control::arguments::backup())
|
||||||
.arg(backup_control::arguments::backup_no_args())
|
.arg(backup_control::arguments::backup_no_args())
|
||||||
|
|
|
@ -35,17 +35,13 @@ fn get_userlogin() -> Option<String> {
|
||||||
|
|
||||||
static SUMMARY: &str = "Print user's login name";
|
static SUMMARY: &str = "Print user's login name";
|
||||||
|
|
||||||
fn usage() -> &'static str {
|
|
||||||
uucore::execution_phrase()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let _ = uu_app().override_usage(usage()).get_matches_from(args);
|
let _ = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
match get_userlogin() {
|
match get_userlogin() {
|
||||||
Some(userlogin) => println!("{}", userlogin),
|
Some(userlogin) => println!("{}", userlogin),
|
||||||
|
@ -58,6 +54,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
|
.override_usage(uucore::execution_phrase())
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,16 +48,14 @@ use uucore::{
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR};
|
use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR};
|
||||||
use uucore::{fs::display_permissions, version_cmp::version_cmp};
|
use uucore::{format_usage, fs::display_permissions, version_cmp::version_cmp};
|
||||||
|
|
||||||
#[cfg(not(feature = "selinux"))]
|
#[cfg(not(feature = "selinux"))]
|
||||||
static CONTEXT_HELP_TEXT: &str = "print any security context of each file (not enabled)";
|
static CONTEXT_HELP_TEXT: &str = "print any security context of each file (not enabled)";
|
||||||
#[cfg(feature = "selinux")]
|
#[cfg(feature = "selinux")]
|
||||||
static CONTEXT_HELP_TEXT: &str = "print any security context of each file";
|
static CONTEXT_HELP_TEXT: &str = "print any security context of each file";
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
|
|
||||||
|
@ -707,9 +705,7 @@ impl Config {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let app = uu_app();
|
||||||
|
|
||||||
let app = uu_app().override_usage(&usage[..]);
|
|
||||||
|
|
||||||
let matches = app.get_matches_from(args);
|
let matches = app.get_matches_from(args);
|
||||||
|
|
||||||
|
@ -726,6 +722,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.about(
|
.about(
|
||||||
"By default, ls will list the files and contents of any directories on \
|
"By default, ls will list the files and contents of any directories on \
|
||||||
the command line, expect that it will ignore files and directories \
|
the command line, expect that it will ignore files and directories \
|
||||||
|
|
|
@ -17,11 +17,13 @@ use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
use uucore::mode;
|
use uucore::mode;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static DEFAULT_PERM: u32 = 0o755;
|
static DEFAULT_PERM: u32 = 0o755;
|
||||||
|
|
||||||
static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist";
|
static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [USER]";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const MODE: &str = "mode";
|
pub const MODE: &str = "mode";
|
||||||
pub const PARENTS: &str = "parents";
|
pub const PARENTS: &str = "parents";
|
||||||
|
@ -29,9 +31,6 @@ mod options {
|
||||||
pub const DIRS: &str = "dirs";
|
pub const DIRS: &str = "dirs";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [USER]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
fn get_long_usage() -> String {
|
fn get_long_usage() -> String {
|
||||||
String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
|
String::from("Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.")
|
||||||
}
|
}
|
||||||
|
@ -87,17 +86,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
// Before we can parse 'args' with clap (and previously getopts),
|
// Before we can parse 'args' with clap (and previously getopts),
|
||||||
// a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
|
// a possible MODE prefix '-' needs to be removed (e.g. "chmod -x FILE").
|
||||||
let mode_had_minus_prefix = strip_minus_from_mode(&mut args);
|
let mode_had_minus_prefix = strip_minus_from_mode(&mut args);
|
||||||
|
|
||||||
let usage = usage();
|
|
||||||
let after_help = get_long_usage();
|
let after_help = get_long_usage();
|
||||||
|
|
||||||
// Linux-specific options, not implemented
|
// Linux-specific options, not implemented
|
||||||
// opts.optflag("Z", "context", "set SELinux security context" +
|
// opts.optflag("Z", "context", "set SELinux security context" +
|
||||||
// " of each created directory to CTX"),
|
// " of each created directory to CTX"),
|
||||||
let matches = uu_app()
|
let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&after_help[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let dirs = matches.values_of_os(options::DIRS).unwrap_or_default();
|
let dirs = matches.values_of_os(options::DIRS).unwrap_or_default();
|
||||||
let verbose = matches.is_present(options::VERBOSE);
|
let verbose = matches.is_present(options::VERBOSE);
|
||||||
|
@ -113,6 +107,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::MODE)
|
Arg::new(options::MODE)
|
||||||
|
|
|
@ -12,10 +12,11 @@ use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use libc::mkfifo;
|
use libc::mkfifo;
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::{display::Quotable, InvalidEncodingHandling};
|
use uucore::{display::Quotable, InvalidEncodingHandling};
|
||||||
|
|
||||||
static NAME: &str = "mkfifo";
|
static NAME: &str = "mkfifo";
|
||||||
static USAGE: &str = "mkfifo [OPTION]... NAME...";
|
static USAGE: &str = "{} [OPTION]... NAME...";
|
||||||
static SUMMARY: &str = "Create a FIFO with the given name.";
|
static SUMMARY: &str = "Create a FIFO with the given name.";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
|
@ -73,7 +74,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -15,10 +15,10 @@ use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOT
|
||||||
|
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{set_exit_code, UResult, USimpleError, UUsageError};
|
use uucore::error::{set_exit_code, UResult, USimpleError, UUsageError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str = "Create the special file NAME of the given TYPE.";
|
static ABOUT: &str = "Create the special file NAME of the given TYPE.";
|
||||||
static USAGE: &str = "mknod [OPTION]... NAME TYPE [MAJOR MINOR]";
|
static USAGE: &str = "{} [OPTION]... NAME TYPE [MAJOR MINOR]";
|
||||||
static LONG_HELP: &str = "Mandatory arguments to long options are mandatory for short options too.
|
static LONG_HELP: &str = "Mandatory arguments to long options are mandatory for short options too.
|
||||||
-m, --mode=MODE set file permission bits to MODE, not a=rw - umask
|
-m, --mode=MODE set file permission bits to MODE, not a=rw - umask
|
||||||
--help display this help and exit
|
--help display this help and exit
|
||||||
|
@ -146,7 +146,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
use clap::{crate_version, App, AppSettings, Arg};
|
use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use uucore::display::{println_verbatim, Quotable};
|
use uucore::display::{println_verbatim, Quotable};
|
||||||
use uucore::error::{FromIo, UError, UResult};
|
use uucore::error::{FromIo, UError, UResult};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -22,6 +23,7 @@ use rand::Rng;
|
||||||
use tempfile::Builder;
|
use tempfile::Builder;
|
||||||
|
|
||||||
static ABOUT: &str = "create a temporary file or directory.";
|
static ABOUT: &str = "create a temporary file or directory.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [TEMPLATE]";
|
||||||
|
|
||||||
static DEFAULT_TEMPLATE: &str = "tmp.XXXXXXXXXX";
|
static DEFAULT_TEMPLATE: &str = "tmp.XXXXXXXXXX";
|
||||||
|
|
||||||
|
@ -34,10 +36,6 @@ static OPT_T: &str = "t";
|
||||||
|
|
||||||
static ARG_TEMPLATE: &str = "template";
|
static ARG_TEMPLATE: &str = "template";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [TEMPLATE]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum MkTempError {
|
enum MkTempError {
|
||||||
PersistError(PathBuf),
|
PersistError(PathBuf),
|
||||||
|
@ -76,9 +74,7 @@ impl Display for MkTempError {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let template = matches.value_of(ARG_TEMPLATE).unwrap();
|
let template = matches.value_of(ARG_TEMPLATE).unwrap();
|
||||||
let tmpdir = matches.value_of(OPT_TMPDIR).unwrap_or_default();
|
let tmpdir = matches.value_of(OPT_TMPDIR).unwrap_or_default();
|
||||||
|
@ -139,6 +135,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_DIRECTORY)
|
Arg::new(OPT_DIRECTORY)
|
||||||
|
|
|
@ -26,6 +26,7 @@ use std::path::{Path, PathBuf};
|
||||||
use uucore::backup_control::{self, BackupMode};
|
use uucore::backup_control::{self, BackupMode};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UError, UResult, USimpleError, UUsageError};
|
use uucore::error::{FromIo, UError, UResult, USimpleError, UUsageError};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
use fs_extra::dir::{move_dir, CopyOptions as DirCopyOptions};
|
use fs_extra::dir::{move_dir, CopyOptions as DirCopyOptions};
|
||||||
|
|
||||||
|
@ -51,6 +52,10 @@ pub enum OverwriteMode {
|
||||||
|
|
||||||
static ABOUT: &str = "Move SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.";
|
static ABOUT: &str = "Move SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.";
|
||||||
static LONG_HELP: &str = "";
|
static LONG_HELP: &str = "";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} [OPTION]... [-T] SOURCE DEST
|
||||||
|
{} [OPTION]... SOURCE... DIRECTORY
|
||||||
|
{} [OPTION]... -t DIRECTORY SOURCE...";
|
||||||
|
|
||||||
static OPT_FORCE: &str = "force";
|
static OPT_FORCE: &str = "force";
|
||||||
static OPT_INTERACTIVE: &str = "interactive";
|
static OPT_INTERACTIVE: &str = "interactive";
|
||||||
|
@ -63,26 +68,14 @@ static OPT_VERBOSE: &str = "verbose";
|
||||||
|
|
||||||
static ARG_FILES: &str = "files";
|
static ARG_FILES: &str = "files";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [OPTION]... [-T] SOURCE DEST
|
|
||||||
{0} [OPTION]... SOURCE... DIRECTORY
|
|
||||||
{0} [OPTION]... -t DIRECTORY SOURCE...",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app()
|
||||||
.after_help(&*format!(
|
.after_help(&*format!(
|
||||||
"{}\n{}",
|
"{}\n{}",
|
||||||
LONG_HELP,
|
LONG_HELP,
|
||||||
backup_control::BACKUP_CONTROL_LONG_HELP
|
backup_control::BACKUP_CONTROL_LONG_HELP
|
||||||
))
|
))
|
||||||
.override_usage(&usage[..])
|
|
||||||
.get_matches_from(args);
|
.get_matches_from(args);
|
||||||
|
|
||||||
let files: Vec<OsString> = matches
|
let files: Vec<OsString> = matches
|
||||||
|
@ -123,6 +116,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
backup_control::arguments::backup()
|
backup_control::arguments::backup()
|
||||||
|
|
|
@ -16,31 +16,26 @@ use std::io::Error;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg};
|
use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use uucore::error::{set_exit_code, UResult, USimpleError, UUsageError};
|
use uucore::{
|
||||||
|
error::{set_exit_code, UResult, USimpleError, UUsageError},
|
||||||
|
format_usage,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static ADJUSTMENT: &str = "adjustment";
|
pub static ADJUSTMENT: &str = "adjustment";
|
||||||
pub static COMMAND: &str = "COMMAND";
|
pub static COMMAND: &str = "COMMAND";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
const ABOUT: &str = "\
|
||||||
format!(
|
Run COMMAND with an adjusted niceness, which affects process scheduling. \
|
||||||
"
|
With no COMMAND, print the current niceness. Niceness values range from at \
|
||||||
{0} [OPTIONS] [COMMAND [ARGS]]
|
least -20 (most favorable to the process) to 19 (least favorable to the \
|
||||||
|
process).";
|
||||||
Run COMMAND with an adjusted niceness, which affects process scheduling.
|
const USAGE: &str = "{} [OPTIONS] [COMMAND [ARGS]]";
|
||||||
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).",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let mut niceness = unsafe {
|
let mut niceness = unsafe {
|
||||||
nix::errno::Errno::clear();
|
nix::errno::Errno::clear();
|
||||||
|
@ -109,6 +104,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
|
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::TrailingVarArg)
|
.setting(AppSettings::TrailingVarArg)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
|
|
|
@ -14,13 +14,12 @@ use std::io::{stdin, BufRead, BufReader, Read};
|
||||||
use std::iter::repeat;
|
use std::iter::repeat;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
mod helper;
|
mod helper;
|
||||||
|
|
||||||
static NAME: &str = "nl";
|
static NAME: &str = "nl";
|
||||||
static USAGE: &str = "nl [OPTION]... [FILE]...";
|
static USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
// A regular expression matching everything.
|
|
||||||
|
|
||||||
// Settings store options used by nl to produce its output.
|
// Settings store options used by nl to produce its output.
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
|
@ -144,7 +143,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::FILE)
|
Arg::new(options::FILE)
|
||||||
|
|
|
@ -22,7 +22,7 @@ use std::os::unix::prelude::*;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{set_exit_code, UError, UResult};
|
use uucore::error::{set_exit_code, UError, UResult};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str = "Run COMMAND ignoring hangup signals.";
|
static ABOUT: &str = "Run COMMAND ignoring hangup signals.";
|
||||||
static LONG_HELP: &str = "
|
static LONG_HELP: &str = "
|
||||||
|
@ -31,6 +31,9 @@ If standard output is terminal, it'll be appended to nohup.out instead,
|
||||||
or $HOME/nohup.out, if nohup.out open failed.
|
or $HOME/nohup.out, if nohup.out open failed.
|
||||||
If standard error is terminal, it'll be redirected to stdout.
|
If standard error is terminal, it'll be redirected to stdout.
|
||||||
";
|
";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} COMMAND [ARG]...
|
||||||
|
{} FLAG";
|
||||||
static NOHUP_OUT: &str = "nohup.out";
|
static NOHUP_OUT: &str = "nohup.out";
|
||||||
// exit codes that match the GNU implementation
|
// exit codes that match the GNU implementation
|
||||||
static EXIT_CANCELED: i32 = 125;
|
static EXIT_CANCELED: i32 = 125;
|
||||||
|
@ -83,12 +86,11 @@ impl Display for NohupError {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
replace_fds()?;
|
replace_fds()?;
|
||||||
|
|
||||||
|
@ -119,6 +121,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::CMD)
|
Arg::new(options::CMD)
|
||||||
.hide(true)
|
.hide(true)
|
||||||
|
@ -205,13 +208,6 @@ fn find_stdout() -> UResult<File> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} COMMAND [ARG]...\n {0} FLAG",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_vendor = "apple")]
|
#[cfg(target_vendor = "apple")]
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn _vprocmgr_detach_from_console(flags: u32) -> *const libc::c_int;
|
fn _vprocmgr_detach_from_console(flags: u32) -> *const libc::c_int;
|
||||||
|
|
|
@ -11,6 +11,7 @@ use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use std::env;
|
use std::env;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub const _SC_NPROCESSORS_CONF: libc::c_int = 83;
|
pub const _SC_NPROCESSORS_CONF: libc::c_int = 83;
|
||||||
|
@ -25,15 +26,11 @@ static OPT_ALL: &str = "all";
|
||||||
static OPT_IGNORE: &str = "ignore";
|
static OPT_IGNORE: &str = "ignore";
|
||||||
|
|
||||||
static ABOUT: &str = "Print the number of cores available to the current process.";
|
static ABOUT: &str = "Print the number of cores available to the current process.";
|
||||||
|
const USAGE: &str = "{} [OPTIONS]...";
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTIONS]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let mut ignore = match matches.value_of(OPT_IGNORE) {
|
let mut ignore = match matches.value_of(OPT_IGNORE) {
|
||||||
Some(numstr) => match numstr.parse() {
|
Some(numstr) => match numstr.parse() {
|
||||||
|
@ -75,6 +72,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_ALL)
|
Arg::new(OPT_ALL)
|
||||||
|
|
|
@ -15,6 +15,7 @@ use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
use std::io::{BufRead, Write};
|
use std::io::{BufRead, Write};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::ranges::Range;
|
use uucore::ranges::Range;
|
||||||
|
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
@ -50,10 +51,7 @@ FIELDS supports cut(1) style field ranges:
|
||||||
- all fields
|
- all fields
|
||||||
Multiple fields/ranges can be separated with commas
|
Multiple fields/ranges can be separated with commas
|
||||||
";
|
";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [NUMBER]...";
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [NUMBER]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_args<'a>(args: impl Iterator<Item = &'a str>, options: &NumfmtOptions) -> UResult<()> {
|
fn handle_args<'a>(args: impl Iterator<Item = &'a str>, options: &NumfmtOptions) -> UResult<()> {
|
||||||
for l in args {
|
for l in args {
|
||||||
|
@ -166,9 +164,7 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let options = parse_options(&matches).map_err(NumfmtError::IllegalArgument)?;
|
let options = parse_options(&matches).map_err(NumfmtError::IllegalArgument)?;
|
||||||
|
|
||||||
|
@ -195,6 +191,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::AllowNegativeNumbers)
|
.setting(AppSettings::AllowNegativeNumbers)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -11,15 +11,15 @@ pub struct InputOffset {
|
||||||
/// The radix to print the byte offset. NoPrefix will not print a byte offset.
|
/// The radix to print the byte offset. NoPrefix will not print a byte offset.
|
||||||
radix: Radix,
|
radix: Radix,
|
||||||
/// The current position. Initialize at `new`, increase using `increase_position`.
|
/// The current position. Initialize at `new`, increase using `increase_position`.
|
||||||
byte_pos: usize,
|
byte_pos: u64,
|
||||||
/// An optional label printed in parentheses, typically different from `byte_pos`,
|
/// An optional label printed in parentheses, typically different from `byte_pos`,
|
||||||
/// but will increase with the same value if `byte_pos` in increased.
|
/// but will increase with the same value if `byte_pos` in increased.
|
||||||
label: Option<usize>,
|
label: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputOffset {
|
impl InputOffset {
|
||||||
/// creates a new `InputOffset` using the provided values.
|
/// creates a new `InputOffset` using the provided values.
|
||||||
pub fn new(radix: Radix, byte_pos: usize, label: Option<usize>) -> Self {
|
pub fn new(radix: Radix, byte_pos: u64, label: Option<u64>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
radix,
|
radix,
|
||||||
byte_pos,
|
byte_pos,
|
||||||
|
@ -28,7 +28,7 @@ impl InputOffset {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Increase `byte_pos` and `label` if a label is used.
|
/// Increase `byte_pos` and `label` if a label is used.
|
||||||
pub fn increase_position(&mut self, n: usize) {
|
pub fn increase_position(&mut self, n: u64) {
|
||||||
self.byte_pos += n;
|
self.byte_pos += n;
|
||||||
if let Some(l) = self.label {
|
if let Some(l) = self.label {
|
||||||
self.label = Some(l + n);
|
self.label = Some(l + n);
|
||||||
|
|
|
@ -29,6 +29,7 @@ mod prn_float;
|
||||||
mod prn_int;
|
mod prn_int;
|
||||||
|
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use crate::byteorder_io::*;
|
use crate::byteorder_io::*;
|
||||||
use crate::formatteriteminfo::*;
|
use crate::formatteriteminfo::*;
|
||||||
|
@ -45,15 +46,17 @@ use crate::prn_char::format_ascii_dump;
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::parse_size::ParseSizeError;
|
use uucore::parse_size::ParseSizeError;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
|
||||||
const PEEK_BUFFER_SIZE: usize = 4; // utf-8 can be 4 bytes
|
const PEEK_BUFFER_SIZE: usize = 4; // utf-8 can be 4 bytes
|
||||||
static ABOUT: &str = "dump files in octal and other formats";
|
static ABOUT: &str = "dump files in octal and other formats";
|
||||||
|
|
||||||
static USAGE: &str = r#"od [OPTION]... [--] [FILENAME]...
|
static USAGE: &str = "\
|
||||||
od [-abcdDefFhHiIlLoOsxX] [FILENAME] [[+][0x]OFFSET[.][b]]
|
{} [OPTION]... [--] [FILENAME]...
|
||||||
od --traditional [OPTION]... [FILENAME] [[+][0x]OFFSET[.][b] [[+][0x]LABEL[.][b]]]"#;
|
{} [-abcdDefFhHiIlLoOsxX] [FILENAME] [[+][0x]OFFSET[.][b]]
|
||||||
|
{} --traditional [OPTION]... [FILENAME] [[+][0x]OFFSET[.][b] [[+][0x]LABEL[.][b]]]";
|
||||||
|
|
||||||
static LONG_HELP: &str = r#"
|
static LONG_HELP: &str = r#"
|
||||||
Displays data in various human-readable formats. If multiple formats are
|
Displays data in various human-readable formats. If multiple formats are
|
||||||
|
@ -109,9 +112,9 @@ pub(crate) mod options {
|
||||||
|
|
||||||
struct OdOptions {
|
struct OdOptions {
|
||||||
byte_order: ByteOrder,
|
byte_order: ByteOrder,
|
||||||
skip_bytes: usize,
|
skip_bytes: u64,
|
||||||
read_bytes: Option<usize>,
|
read_bytes: Option<u64>,
|
||||||
label: Option<usize>,
|
label: Option<u64>,
|
||||||
input_strings: Vec<String>,
|
input_strings: Vec<String>,
|
||||||
formats: Vec<ParsedFormatterItemInfo>,
|
formats: Vec<ParsedFormatterItemInfo>,
|
||||||
line_bytes: usize,
|
line_bytes: usize,
|
||||||
|
@ -146,7 +149,7 @@ impl OdOptions {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut label: Option<usize> = None;
|
let mut label: Option<u64> = None;
|
||||||
|
|
||||||
let parsed_input = parse_inputs(matches)
|
let parsed_input = parse_inputs(matches)
|
||||||
.map_err(|e| USimpleError::new(1, format!("Invalid inputs: {}", e)))?;
|
.map_err(|e| USimpleError::new(1, format!("Invalid inputs: {}", e)))?;
|
||||||
|
@ -168,7 +171,8 @@ impl OdOptions {
|
||||||
16
|
16
|
||||||
} else {
|
} else {
|
||||||
match parse_number_of_bytes(s) {
|
match parse_number_of_bytes(s) {
|
||||||
Ok(n) => n,
|
Ok(n) => usize::try_from(n)
|
||||||
|
.map_err(|_| USimpleError::new(1, format!("‘{}‘ is too large", s)))?,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
return Err(USimpleError::new(
|
return Err(USimpleError::new(
|
||||||
1,
|
1,
|
||||||
|
@ -289,7 +293,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
.setting(
|
.setting(
|
||||||
AppSettings::TrailingVarArg |
|
AppSettings::TrailingVarArg |
|
||||||
|
@ -567,7 +571,7 @@ where
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_offset.increase_position(length);
|
input_offset.increase_position(length as u64);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
show_error!("{}", e);
|
show_error!("{}", e);
|
||||||
|
@ -646,8 +650,8 @@ fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &Output
|
||||||
/// `read_bytes` is an optional limit to the number of bytes to read
|
/// `read_bytes` is an optional limit to the number of bytes to read
|
||||||
fn open_input_peek_reader(
|
fn open_input_peek_reader(
|
||||||
input_strings: &[String],
|
input_strings: &[String],
|
||||||
skip_bytes: usize,
|
skip_bytes: u64,
|
||||||
read_bytes: Option<usize>,
|
read_bytes: Option<u64>,
|
||||||
) -> PeekReader<PartialReader<MultifileReader>> {
|
) -> PeekReader<PartialReader<MultifileReader>> {
|
||||||
// should return "impl PeekRead + Read + HasError" when supported in (stable) rust
|
// should return "impl PeekRead + Read + HasError" when supported in (stable) rust
|
||||||
let inputs = input_strings
|
let inputs = input_strings
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl<'a> CommandLineOpts for ArgMatches {
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
pub enum CommandLineInputs {
|
pub enum CommandLineInputs {
|
||||||
FileNames(Vec<String>),
|
FileNames(Vec<String>),
|
||||||
FileAndOffset((String, usize, Option<usize>)),
|
FileAndOffset((String, u64, Option<u64>)),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interprets the command line inputs of od.
|
/// Interprets the command line inputs of od.
|
||||||
|
@ -141,7 +141,7 @@ pub fn parse_inputs_traditional(input_strings: &[&str]) -> Result<CommandLineInp
|
||||||
}
|
}
|
||||||
|
|
||||||
/// parses format used by offset and label on the command line
|
/// parses format used by offset and label on the command line
|
||||||
pub fn parse_offset_operand(s: &str) -> Result<usize, &'static str> {
|
pub fn parse_offset_operand(s: &str) -> Result<u64, &'static str> {
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
let mut len = s.len();
|
let mut len = s.len();
|
||||||
let mut radix = 8;
|
let mut radix = 8;
|
||||||
|
@ -164,7 +164,7 @@ pub fn parse_offset_operand(s: &str) -> Result<usize, &'static str> {
|
||||||
radix = 10;
|
radix = 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match usize::from_str_radix(&s[start..len], radix) {
|
match u64::from_str_radix(&s[start..len], radix) {
|
||||||
Ok(i) => Ok(i * multiply),
|
Ok(i) => Ok(i * multiply),
|
||||||
Err(_) => Err("parse failed"),
|
Err(_) => Err("parse failed"),
|
||||||
}
|
}
|
||||||
|
@ -332,7 +332,7 @@ mod tests {
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_offset_operand_str(s: &str) -> Result<usize, &'static str> {
|
fn parse_offset_operand_str(s: &str) -> Result<u64, &'static str> {
|
||||||
parse_offset_operand(&String::from(s))
|
parse_offset_operand(&String::from(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
|
|
||||||
pub fn parse_number_of_bytes(s: &str) -> Result<usize, ParseSizeError> {
|
pub fn parse_number_of_bytes(s: &str) -> Result<u64, ParseSizeError> {
|
||||||
let mut start = 0;
|
let mut start = 0;
|
||||||
let mut len = s.len();
|
let mut len = s.len();
|
||||||
let mut radix = 16;
|
let mut radix = 16;
|
||||||
|
@ -65,7 +65,7 @@ pub fn parse_number_of_bytes(s: &str) -> Result<usize, ParseSizeError> {
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
let factor = match usize::from_str_radix(&s[start..len], radix) {
|
let factor = match u64::from_str_radix(&s[start..len], radix) {
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(e) => return Err(ParseSizeError::ParseFailure(e.to_string())),
|
Err(e) => return Err(ParseSizeError::ParseFailure(e.to_string())),
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,15 +15,15 @@ const MAX_SKIP_BUFFER: usize = 16 * 1024;
|
||||||
/// number of bytes.
|
/// number of bytes.
|
||||||
pub struct PartialReader<R> {
|
pub struct PartialReader<R> {
|
||||||
inner: R,
|
inner: R,
|
||||||
skip: usize,
|
skip: u64,
|
||||||
limit: Option<usize>,
|
limit: Option<u64>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R> PartialReader<R> {
|
impl<R> PartialReader<R> {
|
||||||
/// Create a new `PartialReader` wrapping `inner`, which will skip
|
/// Create a new `PartialReader` wrapping `inner`, which will skip
|
||||||
/// `skip` bytes, and limits the output to `limit` bytes. Set `limit`
|
/// `skip` bytes, and limits the output to `limit` bytes. Set `limit`
|
||||||
/// to `None` if there should be no limit.
|
/// to `None` if there should be no limit.
|
||||||
pub fn new(inner: R, skip: usize, limit: Option<usize>) -> Self {
|
pub fn new(inner: R, skip: u64, limit: Option<u64>) -> Self {
|
||||||
Self { inner, skip, limit }
|
Self { inner, skip, limit }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ impl<R: Read> Read for PartialReader<R> {
|
||||||
let mut bytes = [0; MAX_SKIP_BUFFER];
|
let mut bytes = [0; MAX_SKIP_BUFFER];
|
||||||
|
|
||||||
while self.skip > 0 {
|
while self.skip > 0 {
|
||||||
let skip_count = cmp::min(self.skip, MAX_SKIP_BUFFER);
|
let skip_count: usize = cmp::min(self.skip as usize, MAX_SKIP_BUFFER);
|
||||||
|
|
||||||
match self.inner.read(&mut bytes[..skip_count])? {
|
match self.inner.read(&mut bytes[..skip_count])? {
|
||||||
0 => {
|
0 => {
|
||||||
|
@ -44,7 +44,7 @@ impl<R: Read> Read for PartialReader<R> {
|
||||||
"tried to skip past end of input",
|
"tried to skip past end of input",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
n => self.skip -= n,
|
n => self.skip -= n as u64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,15 +53,15 @@ impl<R: Read> Read for PartialReader<R> {
|
||||||
None => self.inner.read(out),
|
None => self.inner.read(out),
|
||||||
Some(0) => Ok(0),
|
Some(0) => Ok(0),
|
||||||
Some(ref mut limit) => {
|
Some(ref mut limit) => {
|
||||||
let slice = if *limit > out.len() {
|
let slice = if *limit > (out.len() as u64) {
|
||||||
out
|
out
|
||||||
} else {
|
} else {
|
||||||
&mut out[0..*limit]
|
&mut out[0..(*limit as usize)]
|
||||||
};
|
};
|
||||||
match self.inner.read(slice) {
|
match self.inner.read(slice) {
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
Ok(r) => {
|
Ok(r) => {
|
||||||
*limit -= r;
|
*limit -= r as u64;
|
||||||
Ok(r)
|
Ok(r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,11 @@ mod tests {
|
||||||
fn test_read_skipping_huge_number() {
|
fn test_read_skipping_huge_number() {
|
||||||
let mut v = [0; 10];
|
let mut v = [0; 10];
|
||||||
// test if it does not eat all memory....
|
// test if it does not eat all memory....
|
||||||
let mut sut = PartialReader::new(Cursor::new(&b"abcdefgh"[..]), usize::max_value(), None);
|
let mut sut = PartialReader::new(
|
||||||
|
Cursor::new(&b"abcdefgh"[..]),
|
||||||
|
usize::max_value() as u64,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
sut.read(v.as_mut()).unwrap_err();
|
sut.read(v.as_mut()).unwrap_err();
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::fs;
|
||||||
use std::io::{ErrorKind, Write};
|
use std::io::{ErrorKind, Write};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{set_exit_code, UResult, UUsageError};
|
use uucore::error::{set_exit_code, UResult, UUsageError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
// operating mode
|
// operating mode
|
||||||
enum Mode {
|
enum Mode {
|
||||||
|
@ -24,6 +24,7 @@ enum Mode {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ABOUT: &str = "Check whether file names are valid or portable";
|
static ABOUT: &str = "Check whether file names are valid or portable";
|
||||||
|
const USAGE: &str = "{} [OPTION]... NAME...";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const POSIX: &str = "posix";
|
pub const POSIX: &str = "posix";
|
||||||
|
@ -36,18 +37,13 @@ mod options {
|
||||||
const POSIX_PATH_MAX: usize = 256;
|
const POSIX_PATH_MAX: usize = 256;
|
||||||
const POSIX_NAME_MAX: usize = 14;
|
const POSIX_NAME_MAX: usize = 14;
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... NAME...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
// set working mode
|
// set working mode
|
||||||
let is_posix = matches.values_of(options::POSIX).is_some();
|
let is_posix = matches.values_of(options::POSIX).is_some();
|
||||||
|
@ -92,6 +88,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::POSIX)
|
Arg::new(options::POSIX)
|
||||||
|
|
|
@ -20,11 +20,12 @@ use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg};
|
use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
const BUFSIZE: usize = 1024;
|
const BUFSIZE: usize = 1024;
|
||||||
|
|
||||||
static ABOUT: &str = "pinky - lightweight finger";
|
static ABOUT: &str = "pinky - lightweight finger";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [USER]...";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const LONG_FORMAT: &str = "long_format";
|
pub const LONG_FORMAT: &str = "long_format";
|
||||||
|
@ -39,10 +40,6 @@ mod options {
|
||||||
pub const USER: &str = "user";
|
pub const USER: &str = "user";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [USER]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_long_usage() -> String {
|
fn get_long_usage() -> String {
|
||||||
format!(
|
format!(
|
||||||
"A lightweight 'finger' program; print user information.\n\
|
"A lightweight 'finger' program; print user information.\n\
|
||||||
|
@ -57,13 +54,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let usage = usage();
|
|
||||||
let after_help = get_long_usage();
|
let after_help = get_long_usage();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&after_help[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let users: Vec<String> = matches
|
let users: Vec<String> = matches
|
||||||
.values_of(options::USER)
|
.values_of(options::USER)
|
||||||
|
@ -136,6 +129,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::LONG_FORMAT)
|
Arg::new(options::LONG_FORMAT)
|
||||||
|
|
|
@ -9,23 +9,18 @@
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg};
|
use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use std::env;
|
use std::env;
|
||||||
use uucore::error::UResult;
|
use uucore::{error::UResult, format_usage};
|
||||||
|
|
||||||
static ABOUT: &str = "Display the values of the specified environment VARIABLE(s), or (with no VARIABLE) display name and value pairs for them all.";
|
static ABOUT: &str = "Display the values of the specified environment VARIABLE(s), or (with no VARIABLE) display name and value pairs for them all.";
|
||||||
|
const USAGE: &str = "{} [VARIABLE]... [OPTION]...";
|
||||||
|
|
||||||
static OPT_NULL: &str = "null";
|
static OPT_NULL: &str = "null";
|
||||||
|
|
||||||
static ARG_VARIABLES: &str = "variables";
|
static ARG_VARIABLES: &str = "variables";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [VARIABLE]... [OPTION]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let variables: Vec<String> = matches
|
let variables: Vec<String> = matches
|
||||||
.values_of(ARG_VARIABLES)
|
.values_of(ARG_VARIABLES)
|
||||||
|
@ -65,6 +60,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_NULL)
|
Arg::new(OPT_NULL)
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg};
|
use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use uucore::error::{UResult, UUsageError};
|
use uucore::error::{UResult, UUsageError};
|
||||||
use uucore::memo;
|
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
use uucore::{format_usage, memo};
|
||||||
|
|
||||||
const VERSION: &str = "version";
|
const VERSION: &str = "version";
|
||||||
const HELP: &str = "help";
|
const HELP: &str = "help";
|
||||||
const USAGE: &str = "printf FORMATSTRING [ARGUMENT]...";
|
const USAGE: &str = "{} FORMATSTRING [ARGUMENT]...";
|
||||||
const ABOUT: &str = "Print output based off of the format string and proceeding arguments.";
|
const ABOUT: &str = "Print output based off of the format string and proceeding arguments.";
|
||||||
const AFTER_HELP: &str = "
|
const AFTER_HELP: &str = "
|
||||||
basic anonymous string templating:
|
basic anonymous string templating:
|
||||||
|
@ -294,7 +294,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(AFTER_HELP)
|
.after_help(AFTER_HELP)
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.arg(Arg::new(HELP).long(HELP).help("Print help information"))
|
.arg(Arg::new(HELP).long(HELP).help("Print help information"))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(VERSION)
|
Arg::new(VERSION)
|
||||||
|
|
|
@ -19,15 +19,17 @@ use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
|
||||||
use std::num::ParseIntError;
|
use std::num::ParseIntError;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UError, UResult};
|
use uucore::error::{FromIo, UError, UResult};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static NAME: &str = "ptx";
|
static NAME: &str = "ptx";
|
||||||
static BRIEF: &str = "Usage: ptx [OPTION]... [INPUT]... (without -G) or: \
|
const USAGE: &str = "\
|
||||||
ptx -G [OPTION]... [INPUT [OUTPUT]] \n Output a permuted index, \
|
{} [OPTION]... [INPUT]...
|
||||||
including context, of the words in the input files. \n\n Mandatory \
|
{} -G [OPTION]... [INPUT [OUTPUT]]";
|
||||||
arguments to long options are mandatory for short options too.\n
|
|
||||||
With no FILE, or when FILE is -, read standard input. \
|
const ABOUT: &str = "\
|
||||||
Default is '-F /'.";
|
Output a permuted index, including context, of the words in the input files. \n\n\
|
||||||
|
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||||
|
With no FILE, or when FILE is -, read standard input. Default is '-F /'.";
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum OutFormat {
|
enum OutFormat {
|
||||||
|
@ -703,8 +705,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
|
.about(ABOUT)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(BRIEF)
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::FILE)
|
Arg::new(options::FILE)
|
||||||
|
|
|
@ -9,11 +9,13 @@ use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
use uucore::display::println_verbatim;
|
use uucore::display::println_verbatim;
|
||||||
use uucore::error::{FromIo, UResult};
|
use uucore::error::{FromIo, UResult};
|
||||||
|
|
||||||
static ABOUT: &str = "Display the full filename of the current working directory.";
|
static ABOUT: &str = "Display the full filename of the current working directory.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... FILE...";
|
||||||
static OPT_LOGICAL: &str = "logical";
|
static OPT_LOGICAL: &str = "logical";
|
||||||
static OPT_PHYSICAL: &str = "physical";
|
static OPT_PHYSICAL: &str = "physical";
|
||||||
|
|
||||||
|
@ -120,15 +122,9 @@ fn logical_path() -> io::Result<PathBuf> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
let cwd = if matches.is_present(OPT_LOGICAL) {
|
let cwd = if matches.is_present(OPT_LOGICAL) {
|
||||||
logical_path()
|
logical_path()
|
||||||
} else {
|
} else {
|
||||||
|
@ -156,6 +152,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_LOGICAL)
|
Arg::new(OPT_LOGICAL)
|
||||||
|
|
|
@ -16,9 +16,11 @@ use std::io::{stdout, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
|
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
|
||||||
|
|
||||||
const ABOUT: &str = "Print value of a symbolic link or canonical file name.";
|
const ABOUT: &str = "Print value of a symbolic link or canonical file name.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
const OPT_CANONICALIZE: &str = "canonicalize";
|
const OPT_CANONICALIZE: &str = "canonicalize";
|
||||||
const OPT_CANONICALIZE_MISSING: &str = "canonicalize-missing";
|
const OPT_CANONICALIZE_MISSING: &str = "canonicalize-missing";
|
||||||
const OPT_CANONICALIZE_EXISTING: &str = "canonicalize-existing";
|
const OPT_CANONICALIZE_EXISTING: &str = "canonicalize-existing";
|
||||||
|
@ -30,14 +32,9 @@ const OPT_ZERO: &str = "zero";
|
||||||
|
|
||||||
const ARG_FILES: &str = "files";
|
const ARG_FILES: &str = "files";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let mut no_newline = matches.is_present(OPT_NO_NEWLINE);
|
let mut no_newline = matches.is_present(OPT_NO_NEWLINE);
|
||||||
let use_zero = matches.is_present(OPT_ZERO);
|
let use_zero = matches.is_present(OPT_ZERO);
|
||||||
|
@ -102,6 +99,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_help(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_CANONICALIZE)
|
Arg::new(OPT_CANONICALIZE)
|
||||||
|
|
|
@ -18,10 +18,12 @@ use std::{
|
||||||
use uucore::{
|
use uucore::{
|
||||||
display::{print_verbatim, Quotable},
|
display::{print_verbatim, Quotable},
|
||||||
error::{FromIo, UResult},
|
error::{FromIo, UResult},
|
||||||
|
format_usage,
|
||||||
fs::{canonicalize, MissingHandling, ResolveMode},
|
fs::{canonicalize, MissingHandling, ResolveMode},
|
||||||
};
|
};
|
||||||
|
|
||||||
static ABOUT: &str = "print the resolved path";
|
static ABOUT: &str = "print the resolved path";
|
||||||
|
const USAGE: &str = "{} [OPTION]... FILE...";
|
||||||
|
|
||||||
static OPT_QUIET: &str = "quiet";
|
static OPT_QUIET: &str = "quiet";
|
||||||
static OPT_STRIP: &str = "strip";
|
static OPT_STRIP: &str = "strip";
|
||||||
|
@ -33,15 +35,9 @@ const OPT_CANONICALIZE_EXISTING: &str = "canonicalize-existing";
|
||||||
|
|
||||||
static ARG_FILES: &str = "files";
|
static ARG_FILES: &str = "files";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
/* the list of files */
|
/* the list of files */
|
||||||
|
|
||||||
|
@ -78,6 +74,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_QUIET)
|
Arg::new(OPT_QUIET)
|
||||||
|
|
|
@ -13,10 +13,11 @@ use std::path::{Path, PathBuf};
|
||||||
use uucore::display::println_verbatim;
|
use uucore::display::println_verbatim;
|
||||||
use uucore::error::{FromIo, UResult};
|
use uucore::error::{FromIo, UResult};
|
||||||
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
|
use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str = "Convert TO destination to the relative path from the FROM dir.
|
static ABOUT: &str = "Convert TO destination to the relative path from the FROM dir.
|
||||||
If FROM path is omitted, current working dir will be used.";
|
If FROM path is omitted, current working dir will be used.";
|
||||||
|
const USAGE: &str = "{} [-d DIR] TO [FROM]";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const DIR: &str = "DIR";
|
pub const DIR: &str = "DIR";
|
||||||
|
@ -24,18 +25,13 @@ mod options {
|
||||||
pub const FROM: &str = "FROM";
|
pub const FROM: &str = "FROM";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{} [-d DIR] TO [FROM]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
let usage = usage();
|
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let to = Path::new(matches.value_of(options::TO).unwrap()).to_path_buf(); // required
|
let to = Path::new(matches.value_of(options::TO).unwrap()).to_path_buf(); // required
|
||||||
let from = match matches.value_of(options::FROM) {
|
let from = match matches.value_of(options::FROM) {
|
||||||
|
@ -86,6 +82,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(Arg::new(options::DIR).short('d').takes_value(true).help(
|
.arg(Arg::new(options::DIR).short('d').takes_value(true).help(
|
||||||
"If any of FROM and TO is not subpath of DIR, output absolute path instead of relative",
|
"If any of FROM and TO is not subpath of DIR, output absolute path instead of relative",
|
||||||
|
|
|
@ -19,6 +19,7 @@ use std::ops::BitOr;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError, UUsageError};
|
use uucore::error::{UResult, USimpleError, UUsageError};
|
||||||
|
use uucore::format_usage;
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Clone, Copy)]
|
#[derive(Eq, PartialEq, Clone, Copy)]
|
||||||
|
@ -40,6 +41,7 @@ struct Options {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ABOUT: &str = "Remove (unlink) the FILE(s)";
|
static ABOUT: &str = "Remove (unlink) the FILE(s)";
|
||||||
|
const USAGE: &str = "{} [OPTION]... FILE...";
|
||||||
static OPT_DIR: &str = "dir";
|
static OPT_DIR: &str = "dir";
|
||||||
static OPT_INTERACTIVE: &str = "interactive";
|
static OPT_INTERACTIVE: &str = "interactive";
|
||||||
static OPT_FORCE: &str = "force";
|
static OPT_FORCE: &str = "force";
|
||||||
|
@ -55,10 +57,6 @@ static PRESUME_INPUT_TTY: &str = "-presume-input-tty";
|
||||||
|
|
||||||
static ARG_FILES: &str = "files";
|
static ARG_FILES: &str = "files";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_long_usage() -> String {
|
fn get_long_usage() -> String {
|
||||||
String::from(
|
String::from(
|
||||||
"By default, rm does not remove directories. Use the --recursive (-r or -R)
|
"By default, rm does not remove directories. Use the --recursive (-r or -R)
|
||||||
|
@ -78,13 +76,9 @@ fn get_long_usage() -> String {
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let long_usage = get_long_usage();
|
let long_usage = get_long_usage();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app().after_help(&long_usage[..]).get_matches_from(args);
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&long_usage[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let files: Vec<String> = matches
|
let files: Vec<String> = matches
|
||||||
.values_of(ARG_FILES)
|
.values_of(ARG_FILES)
|
||||||
|
@ -149,6 +143,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_FORCE)
|
Arg::new(OPT_FORCE)
|
||||||
|
|
|
@ -16,24 +16,19 @@ use std::io;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{set_exit_code, strip_errno, UResult};
|
use uucore::error::{set_exit_code, strip_errno, UResult};
|
||||||
use uucore::util_name;
|
use uucore::{format_usage, util_name};
|
||||||
|
|
||||||
static ABOUT: &str = "Remove the DIRECTORY(ies), if they are empty.";
|
static ABOUT: &str = "Remove the DIRECTORY(ies), if they are empty.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... DIRECTORY...";
|
||||||
static OPT_IGNORE_FAIL_NON_EMPTY: &str = "ignore-fail-on-non-empty";
|
static OPT_IGNORE_FAIL_NON_EMPTY: &str = "ignore-fail-on-non-empty";
|
||||||
static OPT_PARENTS: &str = "parents";
|
static OPT_PARENTS: &str = "parents";
|
||||||
static OPT_VERBOSE: &str = "verbose";
|
static OPT_VERBOSE: &str = "verbose";
|
||||||
|
|
||||||
static ARG_DIRS: &str = "dirs";
|
static ARG_DIRS: &str = "dirs";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... DIRECTORY...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let opts = Opts {
|
let opts = Opts {
|
||||||
ignore: matches.is_present(OPT_IGNORE_FAIL_NON_EMPTY),
|
ignore: matches.is_present(OPT_IGNORE_FAIL_NON_EMPTY),
|
||||||
|
@ -179,6 +174,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_IGNORE_FAIL_NON_EMPTY)
|
Arg::new(OPT_IGNORE_FAIL_NON_EMPTY)
|
||||||
|
|
|
@ -4,6 +4,7 @@ use uucore::error::{UResult, UUsageError};
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg};
|
use clap::{App, AppSettings, Arg};
|
||||||
use selinux::{OpaqueSecurityContext, SecurityClass, SecurityContext};
|
use selinux::{OpaqueSecurityContext, SecurityClass, SecurityContext};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::ffi::{CStr, CString, OsStr, OsString};
|
use std::ffi::{CStr, CString, OsStr, OsString};
|
||||||
|
@ -18,6 +19,9 @@ use errors::{Error, Result, RunconError};
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
const ABOUT: &str = "Run command with specified security context.";
|
const ABOUT: &str = "Run command with specified security context.";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} [CONTEXT COMMAND [ARG...]]
|
||||||
|
{} [-c] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [ARG...]";
|
||||||
const DESCRIPTION: &str = "Run COMMAND with completely-specified CONTEXT, or with current or \
|
const DESCRIPTION: &str = "Run COMMAND with completely-specified CONTEXT, or with current or \
|
||||||
transitioned security context modified by one or more of \
|
transitioned security context modified by one or more of \
|
||||||
LEVEL, ROLE, TYPE, and USER.\n\n\
|
LEVEL, ROLE, TYPE, and USER.\n\n\
|
||||||
|
@ -36,19 +40,9 @@ pub mod options {
|
||||||
pub const RANGE: &str = "range";
|
pub const RANGE: &str = "range";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [CONTEXT COMMAND [ARG...]]\n \
|
|
||||||
{0} [-c] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [ARG...]",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = get_usage();
|
let config = uu_app();
|
||||||
|
|
||||||
let config = uu_app().override_usage(usage.as_ref());
|
|
||||||
|
|
||||||
let options = match parse_command_line(config, args) {
|
let options = match parse_command_line(config, args) {
|
||||||
Ok(r) => r,
|
Ok(r) => r,
|
||||||
|
@ -114,6 +108,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(VERSION)
|
.version(VERSION)
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(DESCRIPTION)
|
.after_help(DESCRIPTION)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::COMPUTE)
|
Arg::new(options::COMPUTE)
|
||||||
|
|
|
@ -12,6 +12,7 @@ use num_traits::Zero;
|
||||||
|
|
||||||
use uucore::error::FromIo;
|
use uucore::error::FromIo;
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::memo::Memo;
|
use uucore::memo::Memo;
|
||||||
use uucore::show;
|
use uucore::show;
|
||||||
|
|
||||||
|
@ -27,6 +28,10 @@ use crate::number::Number;
|
||||||
use crate::number::PreciseNumber;
|
use crate::number::PreciseNumber;
|
||||||
|
|
||||||
static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT.";
|
static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT.";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} [OPTION]... LAST
|
||||||
|
{} [OPTION]... FIRST LAST
|
||||||
|
{} [OPTION]... FIRST INCREMENT LAST";
|
||||||
static OPT_SEPARATOR: &str = "separator";
|
static OPT_SEPARATOR: &str = "separator";
|
||||||
static OPT_TERMINATOR: &str = "terminator";
|
static OPT_TERMINATOR: &str = "terminator";
|
||||||
static OPT_WIDTHS: &str = "widths";
|
static OPT_WIDTHS: &str = "widths";
|
||||||
|
@ -34,14 +39,6 @@ static OPT_FORMAT: &str = "format";
|
||||||
|
|
||||||
static ARG_NUMBERS: &str = "numbers";
|
static ARG_NUMBERS: &str = "numbers";
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [OPTION]... LAST
|
|
||||||
{0} [OPTION]... FIRST LAST
|
|
||||||
{0} [OPTION]... FIRST INCREMENT LAST",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct SeqOptions<'a> {
|
struct SeqOptions<'a> {
|
||||||
separator: String,
|
separator: String,
|
||||||
|
@ -62,8 +59,7 @@ type RangeFloat = (ExtendedBigDecimal, ExtendedBigDecimal, ExtendedBigDecimal);
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let numbers = matches.values_of(ARG_NUMBERS).unwrap().collect::<Vec<_>>();
|
let numbers = matches.values_of(ARG_NUMBERS).unwrap().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
@ -148,10 +144,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
pub fn uu_app<'a>() -> App<'a> {
|
pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.setting(AppSettings::TrailingVarArg)
|
.setting(AppSettings::TrailingVarArg)
|
||||||
.setting(AppSettings::AllowHyphenValues)
|
.setting(AppSettings::AllowNegativeNumbers)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_SEPARATOR)
|
Arg::new(OPT_SEPARATOR)
|
||||||
.short('s')
|
.short('s')
|
||||||
|
|
|
@ -20,7 +20,7 @@ use std::io::SeekFrom;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
||||||
use uucore::{util_name, InvalidEncodingHandling};
|
use uucore::{format_usage, util_name, InvalidEncodingHandling};
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
@ -214,10 +214,7 @@ impl<'a> BytesGenerator<'a> {
|
||||||
static ABOUT: &str = "Overwrite the specified FILE(s) repeatedly, in order to make it harder\n\
|
static ABOUT: &str = "Overwrite the specified FILE(s) repeatedly, in order to make it harder\n\
|
||||||
for even very expensive hardware probing to recover the data.
|
for even very expensive hardware probing to recover the data.
|
||||||
";
|
";
|
||||||
|
const USAGE: &str = "{} [OPTION]... FILE...";
|
||||||
fn usage() -> String {
|
|
||||||
format!("{} [OPTION]... FILE...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
static AFTER_HELP: &str =
|
static AFTER_HELP: &str =
|
||||||
"Delete FILE(s) if --remove (-u) is specified. The default is not to remove\n\
|
"Delete FILE(s) if --remove (-u) is specified. The default is not to remove\n\
|
||||||
|
@ -273,11 +270,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let app = uu_app().override_usage(&usage[..]);
|
|
||||||
|
|
||||||
let matches = app.get_matches_from(args);
|
|
||||||
|
|
||||||
if !matches.is_present(options::FILE) {
|
if !matches.is_present(options::FILE) {
|
||||||
return Err(UUsageError::new(1, "missing file operand"));
|
return Err(UUsageError::new(1, "missing file operand"));
|
||||||
|
@ -326,6 +319,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(AFTER_HELP)
|
.after_help(AFTER_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::FORCE)
|
Arg::new(options::FORCE)
|
||||||
|
|
|
@ -14,7 +14,7 @@ use std::fs::File;
|
||||||
use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write};
|
use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
use uucore::{execution_phrase, InvalidEncodingHandling};
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
mod rand_read_adapter;
|
mod rand_read_adapter;
|
||||||
|
|
||||||
|
@ -25,10 +25,14 @@ enum Mode {
|
||||||
}
|
}
|
||||||
|
|
||||||
static NAME: &str = "shuf";
|
static NAME: &str = "shuf";
|
||||||
static USAGE: &str = r#"shuf [OPTION]... [FILE]
|
static USAGE: &str = "\
|
||||||
or: shuf -e [OPTION]... [ARG]...
|
{} [OPTION]... [FILE]
|
||||||
or: shuf -i LO-HI [OPTION]..."#;
|
{} -e [OPTION]... [ARG]...
|
||||||
static ABOUT: &str = "Shuffle the input by outputting a random permutation of input lines. Each output permutation is equally likely.";
|
{} -i LO-HI [OPTION]...";
|
||||||
|
static ABOUT: &str = "\
|
||||||
|
Shuffle the input by outputting a random permutation of input lines.\
|
||||||
|
Each output permutation is equally likely.\
|
||||||
|
With no FILE, or when FILE is -, read standard input.";
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
head_count: usize,
|
head_count: usize,
|
||||||
|
@ -55,9 +59,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app().get_matches_from(args);
|
||||||
.override_usage(&USAGE.replace(NAME, execution_phrase())[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let mode = if let Some(args) = matches.values_of(options::ECHO) {
|
let mode = if let Some(args) = matches.values_of(options::ECHO) {
|
||||||
Mode::Echo(args.map(String::from).collect())
|
Mode::Echo(args.map(String::from).collect())
|
||||||
|
@ -122,7 +124,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::ECHO)
|
Arg::new(options::ECHO)
|
||||||
|
|
|
@ -8,11 +8,17 @@
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::{
|
||||||
|
error::{UResult, USimpleError},
|
||||||
|
format_usage,
|
||||||
|
};
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg};
|
use clap::{crate_version, App, AppSettings, Arg};
|
||||||
|
|
||||||
static ABOUT: &str = "Pause for NUMBER seconds.";
|
static ABOUT: &str = "Pause for NUMBER seconds.";
|
||||||
|
const USAGE: &str = "\
|
||||||
|
{} NUMBER[SUFFIX]...
|
||||||
|
{} OPTION";
|
||||||
static LONG_HELP: &str = "Pause for NUMBER seconds. SUFFIX may be 's' for seconds (the default),
|
static LONG_HELP: &str = "Pause for NUMBER seconds. SUFFIX may be 's' for seconds (the default),
|
||||||
'm' for minutes, 'h' for hours or 'd' for days. Unlike most implementations
|
'm' for minutes, 'h' for hours or 'd' for days. Unlike most implementations
|
||||||
that require NUMBER be an integer, here NUMBER may be an arbitrary floating
|
that require NUMBER be an integer, here NUMBER may be an arbitrary floating
|
||||||
|
@ -23,19 +29,9 @@ mod options {
|
||||||
pub const NUMBER: &str = "NUMBER";
|
pub const NUMBER: &str = "NUMBER";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} {1}[SUFFIX]... \n {0} OPTION",
|
|
||||||
uucore::execution_phrase(),
|
|
||||||
options::NUMBER
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
if let Some(values) = matches.values_of(options::NUMBER) {
|
if let Some(values) = matches.values_of(options::NUMBER) {
|
||||||
let numbers = values.collect::<Vec<_>>();
|
let numbers = values.collect::<Vec<_>>();
|
||||||
|
@ -50,6 +46,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::NUMBER)
|
Arg::new(options::NUMBER)
|
||||||
|
|
|
@ -33,6 +33,7 @@ use numeric_str_cmp::{human_numeric_str_cmp, numeric_str_cmp, NumInfo, NumInfoPa
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
use std::convert::TryFrom;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
|
@ -49,11 +50,14 @@ use uucore::display::Quotable;
|
||||||
use uucore::error::{set_exit_code, strip_errno, UError, UResult, USimpleError, UUsageError};
|
use uucore::error::{set_exit_code, strip_errno, UError, UResult, USimpleError, UUsageError};
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
use uucore::version_cmp::version_cmp;
|
use uucore::version_cmp::version_cmp;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
use crate::tmp_dir::TmpDirWrapper;
|
use crate::tmp_dir::TmpDirWrapper;
|
||||||
|
|
||||||
const ABOUT: &str = "Display sorted concatenation of all FILE(s).";
|
const ABOUT: &str = "\
|
||||||
|
Display sorted concatenation of all FILE(s).\
|
||||||
|
With no FILE, or when FILE is -, read standard input.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
|
|
||||||
const LONG_HELP_KEYS: &str = "The key format is FIELD[.CHAR][OPTIONS][,FIELD[.CHAR]][OPTIONS].
|
const LONG_HELP_KEYS: &str = "The key format is FIELD[.CHAR][OPTIONS][,FIELD[.CHAR]][OPTIONS].
|
||||||
|
|
||||||
|
@ -351,7 +355,13 @@ impl GlobalSettings {
|
||||||
} else if size_string.ends_with('b') {
|
} else if size_string.ends_with('b') {
|
||||||
size_string.pop();
|
size_string.pop();
|
||||||
}
|
}
|
||||||
parse_size(&size_string)
|
let size = parse_size(&size_string)?;
|
||||||
|
usize::try_from(size).map_err(|_| {
|
||||||
|
ParseSizeError::SizeTooBig(format!(
|
||||||
|
"Buffer size {} does not fit in address space",
|
||||||
|
size
|
||||||
|
))
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(ParseSizeError::ParseFailure("invalid suffix".to_string()))
|
Err(ParseSizeError::ParseFailure("invalid suffix".to_string()))
|
||||||
}
|
}
|
||||||
|
@ -1030,16 +1040,6 @@ impl FieldSelector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [OPTION]... [FILE]...
|
|
||||||
Write the sorted concatenation of all FILE(s) to standard output.
|
|
||||||
Mandatory arguments for long options are mandatory for short options too.
|
|
||||||
With no FILE, or when FILE is -, read standard input.",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an `Arg` that conflicts with all other sort modes.
|
/// Creates an `Arg` that conflicts with all other sort modes.
|
||||||
fn make_sort_mode_arg<'a>(mode: &'a str, short: char, help: &'a str) -> Arg<'a> {
|
fn make_sort_mode_arg<'a>(mode: &'a str, short: char, help: &'a str) -> Arg<'a> {
|
||||||
let mut arg = Arg::new(mode).short(short).long(mode).help(help);
|
let mut arg = Arg::new(mode).short(short).long(mode).help(help);
|
||||||
|
@ -1056,13 +1056,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
let usage = usage();
|
|
||||||
let mut settings: GlobalSettings = Default::default();
|
let mut settings: GlobalSettings = Default::default();
|
||||||
|
|
||||||
let matches = match uu_app()
|
let matches = match uu_app().try_get_matches_from(args) {
|
||||||
.override_usage(&usage[..])
|
|
||||||
.try_get_matches_from(args)
|
|
||||||
{
|
|
||||||
Ok(t) => t,
|
Ok(t) => t,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
// not all clap "Errors" are because of a failure to parse arguments.
|
// not all clap "Errors" are because of a failure to parse arguments.
|
||||||
|
@ -1276,6 +1272,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::modes::SORT)
|
Arg::new(options::modes::SORT)
|
||||||
|
|
|
@ -36,19 +36,19 @@ pub enum SuffixType {
|
||||||
Alphabetic,
|
Alphabetic,
|
||||||
|
|
||||||
/// Decimal numbers.
|
/// Decimal numbers.
|
||||||
NumericDecimal,
|
Decimal,
|
||||||
|
|
||||||
/// Hexadecimal numbers.
|
/// Hexadecimal numbers.
|
||||||
NumericHexadecimal,
|
Hexadecimal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SuffixType {
|
impl SuffixType {
|
||||||
/// The radix to use when representing the suffix string as digits.
|
/// The radix to use when representing the suffix string as digits.
|
||||||
fn radix(&self) -> u8 {
|
pub fn radix(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
SuffixType::Alphabetic => 26,
|
SuffixType::Alphabetic => 26,
|
||||||
SuffixType::NumericDecimal => 10,
|
SuffixType::Decimal => 10,
|
||||||
SuffixType::NumericHexadecimal => 16,
|
SuffixType::Hexadecimal => 16,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,7 +90,7 @@ impl SuffixType {
|
||||||
/// assert_eq!(it.next().unwrap(), "chunk_ac.txt");
|
/// assert_eq!(it.next().unwrap(), "chunk_ac.txt");
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// For decimal numeric filenames, use `SuffixType::NumericDecimal`:
|
/// For decimal numeric filenames, use `SuffixType::Decimal`:
|
||||||
///
|
///
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
/// use crate::filenames::FilenameIterator;
|
/// use crate::filenames::FilenameIterator;
|
||||||
|
@ -99,7 +99,7 @@ impl SuffixType {
|
||||||
/// let prefix = "chunk_".to_string();
|
/// let prefix = "chunk_".to_string();
|
||||||
/// let suffix = ".txt".to_string();
|
/// let suffix = ".txt".to_string();
|
||||||
/// let width = 2;
|
/// let width = 2;
|
||||||
/// let suffix_type = SuffixType::NumericDecimal;
|
/// let suffix_type = SuffixType::Decimal;
|
||||||
/// let it = FilenameIterator::new(prefix, suffix, width, suffix_type);
|
/// let it = FilenameIterator::new(prefix, suffix, width, suffix_type);
|
||||||
///
|
///
|
||||||
/// assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
/// assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
||||||
|
@ -173,12 +173,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_filename_iterator_numeric_fixed_width() {
|
fn test_filename_iterator_numeric_fixed_width() {
|
||||||
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::NumericDecimal);
|
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::Decimal);
|
||||||
assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
||||||
assert_eq!(it.next().unwrap(), "chunk_01.txt");
|
assert_eq!(it.next().unwrap(), "chunk_01.txt");
|
||||||
assert_eq!(it.next().unwrap(), "chunk_02.txt");
|
assert_eq!(it.next().unwrap(), "chunk_02.txt");
|
||||||
|
|
||||||
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::NumericDecimal);
|
let mut it = FilenameIterator::new("chunk_", ".txt", 2, SuffixType::Decimal);
|
||||||
assert_eq!(it.nth(10 * 10 - 1).unwrap(), "chunk_99.txt");
|
assert_eq!(it.nth(10 * 10 - 1).unwrap(), "chunk_99.txt");
|
||||||
assert_eq!(it.next(), None);
|
assert_eq!(it.next(), None);
|
||||||
}
|
}
|
||||||
|
@ -198,12 +198,12 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_filename_iterator_numeric_dynamic_width() {
|
fn test_filename_iterator_numeric_dynamic_width() {
|
||||||
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::NumericDecimal);
|
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::Decimal);
|
||||||
assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
assert_eq!(it.next().unwrap(), "chunk_00.txt");
|
||||||
assert_eq!(it.next().unwrap(), "chunk_01.txt");
|
assert_eq!(it.next().unwrap(), "chunk_01.txt");
|
||||||
assert_eq!(it.next().unwrap(), "chunk_02.txt");
|
assert_eq!(it.next().unwrap(), "chunk_02.txt");
|
||||||
|
|
||||||
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::NumericDecimal);
|
let mut it = FilenameIterator::new("chunk_", ".txt", 0, SuffixType::Decimal);
|
||||||
assert_eq!(it.nth(10 * 9 - 1).unwrap(), "chunk_89.txt");
|
assert_eq!(it.nth(10 * 9 - 1).unwrap(), "chunk_89.txt");
|
||||||
assert_eq!(it.next().unwrap(), "chunk_9000.txt");
|
assert_eq!(it.next().unwrap(), "chunk_9000.txt");
|
||||||
assert_eq!(it.next().unwrap(), "chunk_9001.txt");
|
assert_eq!(it.next().unwrap(), "chunk_9001.txt");
|
||||||
|
|
|
@ -14,14 +14,16 @@ mod platform;
|
||||||
use crate::filenames::FilenameIterator;
|
use crate::filenames::FilenameIterator;
|
||||||
use crate::filenames::SuffixType;
|
use crate::filenames::SuffixType;
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::{metadata, File};
|
use std::fs::{metadata, File};
|
||||||
use std::io::{stdin, BufReader, BufWriter, ErrorKind, Read, Write};
|
use std::io;
|
||||||
use std::num::ParseIntError;
|
use std::io::{stdin, BufRead, BufReader, BufWriter, ErrorKind, Read, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UIoError, UResult, USimpleError, UUsageError};
|
use uucore::error::{FromIo, UIoError, UResult, USimpleError, UUsageError};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
use uucore::uio_error;
|
use uucore::uio_error;
|
||||||
|
|
||||||
|
@ -39,36 +41,20 @@ static OPT_VERBOSE: &str = "verbose";
|
||||||
//The ---io-blksize parameter is consumed and ignored.
|
//The ---io-blksize parameter is consumed and ignored.
|
||||||
//The parameter is included to make GNU coreutils tests pass.
|
//The parameter is included to make GNU coreutils tests pass.
|
||||||
static OPT_IO_BLKSIZE: &str = "-io-blksize";
|
static OPT_IO_BLKSIZE: &str = "-io-blksize";
|
||||||
|
static OPT_ELIDE_EMPTY_FILES: &str = "elide-empty-files";
|
||||||
|
|
||||||
static ARG_INPUT: &str = "input";
|
static ARG_INPUT: &str = "input";
|
||||||
static ARG_PREFIX: &str = "prefix";
|
static ARG_PREFIX: &str = "prefix";
|
||||||
|
|
||||||
fn usage() -> String {
|
const USAGE: &str = "{} [OPTION]... [INPUT [PREFIX]]";
|
||||||
format!(
|
const AFTER_HELP: &str = "\
|
||||||
"{0} [OPTION]... [INPUT [PREFIX]]",
|
Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default \
|
||||||
uucore::execution_phrase()
|
size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is \
|
||||||
)
|
-, read standard input.";
|
||||||
}
|
|
||||||
fn get_long_usage() -> String {
|
|
||||||
format!(
|
|
||||||
"Usage:
|
|
||||||
{0}
|
|
||||||
|
|
||||||
Output fixed-size pieces of INPUT to PREFIXaa, PREFIX ab, ...; default
|
|
||||||
size is 1000, and default PREFIX is 'x'. With no INPUT, or when INPUT is
|
|
||||||
-, read standard input.",
|
|
||||||
usage()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
let long_usage = get_long_usage();
|
|
||||||
let matches = uu_app()
|
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&long_usage[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
match Settings::from(&matches) {
|
match Settings::from(&matches) {
|
||||||
Ok(settings) => split(&settings),
|
Ok(settings) => split(&settings),
|
||||||
Err(e) if e.requires_usage() => Err(UUsageError::new(1, format!("{}", e))),
|
Err(e) if e.requires_usage() => Err(UUsageError::new(1, format!("{}", e))),
|
||||||
|
@ -80,6 +66,8 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about("Create output files containing consecutive or interleaved sections of input")
|
.about("Create output files containing consecutive or interleaved sections of input")
|
||||||
|
.after_help(AFTER_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
// strategy (mutually exclusive)
|
// strategy (mutually exclusive)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -128,6 +116,13 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
"write to shell COMMAND file name is $FILE (Currently not implemented for Windows)",
|
"write to shell COMMAND file name is $FILE (Currently not implemented for Windows)",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(OPT_ELIDE_EMPTY_FILES)
|
||||||
|
.long(OPT_ELIDE_EMPTY_FILES)
|
||||||
|
.short('e')
|
||||||
|
.takes_value(false)
|
||||||
|
.help("do not generate empty output files with '-n'"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_NUMERIC_SUFFIXES)
|
Arg::new(OPT_NUMERIC_SUFFIXES)
|
||||||
.short('d')
|
.short('d')
|
||||||
|
@ -150,7 +145,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.long(OPT_HEX_SUFFIXES)
|
.long(OPT_HEX_SUFFIXES)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.default_missing_value("0")
|
.default_missing_value("0")
|
||||||
.help("use hex suffixes starting at 0, not alphabetic"),
|
.help("use hex suffixes instead of alphabetic"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(OPT_VERBOSE)
|
Arg::new(OPT_VERBOSE)
|
||||||
|
@ -178,20 +173,151 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sub-strategy to use when splitting a file into a specific number of chunks.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum NumberType {
|
||||||
|
/// Split into a specific number of chunks by byte.
|
||||||
|
Bytes(u64),
|
||||||
|
|
||||||
|
/// Split into a specific number of chunks by line (approximately).
|
||||||
|
Lines(u64),
|
||||||
|
|
||||||
|
/// Split into a specific number of chunks by line
|
||||||
|
/// (approximately), but output only the *k*th chunk.
|
||||||
|
KthLines(u64, u64),
|
||||||
|
|
||||||
|
/// Assign lines via round-robin to the specified number of output chunks.
|
||||||
|
RoundRobin(u64),
|
||||||
|
|
||||||
|
/// Assign lines via round-robin to the specified number of output
|
||||||
|
/// chunks, but output only the *k*th chunk.
|
||||||
|
KthRoundRobin(u64, u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NumberType {
|
||||||
|
/// The number of chunks for this number type.
|
||||||
|
fn num_chunks(&self) -> u64 {
|
||||||
|
match self {
|
||||||
|
Self::Bytes(n) => *n,
|
||||||
|
Self::Lines(n) => *n,
|
||||||
|
Self::KthLines(_, n) => *n,
|
||||||
|
Self::RoundRobin(n) => *n,
|
||||||
|
Self::KthRoundRobin(_, n) => *n,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An error due to an invalid parameter to the `-n` command-line option.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum NumberTypeError {
|
||||||
|
/// The number of chunks was invalid.
|
||||||
|
///
|
||||||
|
/// This can happen if the value of `N` in any of the following
|
||||||
|
/// command-line options is not a positive integer:
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// -n N
|
||||||
|
/// -n l/N
|
||||||
|
/// -n l/K/N
|
||||||
|
/// -n r/N
|
||||||
|
/// -n r/K/N
|
||||||
|
/// ```
|
||||||
|
NumberOfChunks(String),
|
||||||
|
|
||||||
|
/// The chunk number was invalid.
|
||||||
|
///
|
||||||
|
/// This can happen if the value of `K` in any of the following
|
||||||
|
/// command-line options is not a positive integer:
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// -n l/K/N
|
||||||
|
/// -n r/K/N
|
||||||
|
/// ```
|
||||||
|
ChunkNumber(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NumberType {
|
||||||
|
/// Parse a `NumberType` from a string.
|
||||||
|
///
|
||||||
|
/// The following strings are valid arguments:
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// "N"
|
||||||
|
/// "l/N"
|
||||||
|
/// "l/K/N"
|
||||||
|
/// "r/N"
|
||||||
|
/// "r/K/N"
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `N` represents the number of chunks and the `K` represents
|
||||||
|
/// a chunk number.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If the string is not one of the valid number types, if `K` is
|
||||||
|
/// not a nonnegative integer, or if `N` is not a positive
|
||||||
|
/// integer, then this function returns [`NumberTypeError`].
|
||||||
|
fn from(s: &str) -> Result<Self, NumberTypeError> {
|
||||||
|
let parts: Vec<&str> = s.split('/').collect();
|
||||||
|
match &parts[..] {
|
||||||
|
[n_str] => {
|
||||||
|
let num_chunks = n_str
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
|
||||||
|
Ok(Self::Bytes(num_chunks))
|
||||||
|
}
|
||||||
|
["l", n_str] => {
|
||||||
|
let num_chunks = n_str
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
|
||||||
|
Ok(Self::Lines(num_chunks))
|
||||||
|
}
|
||||||
|
["l", k_str, n_str] => {
|
||||||
|
let num_chunks = n_str
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
|
||||||
|
let chunk_number = k_str
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| NumberTypeError::ChunkNumber(k_str.to_string()))?;
|
||||||
|
Ok(Self::KthLines(chunk_number, num_chunks))
|
||||||
|
}
|
||||||
|
["r", n_str] => {
|
||||||
|
let num_chunks = n_str
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
|
||||||
|
Ok(Self::RoundRobin(num_chunks))
|
||||||
|
}
|
||||||
|
["r", k_str, n_str] => {
|
||||||
|
let num_chunks = n_str
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| NumberTypeError::NumberOfChunks(n_str.to_string()))?;
|
||||||
|
let chunk_number = k_str
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| NumberTypeError::ChunkNumber(k_str.to_string()))?;
|
||||||
|
Ok(Self::KthRoundRobin(chunk_number, num_chunks))
|
||||||
|
}
|
||||||
|
_ => Err(NumberTypeError::NumberOfChunks(s.to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The strategy for breaking up the input file into chunks.
|
/// The strategy for breaking up the input file into chunks.
|
||||||
enum Strategy {
|
enum Strategy {
|
||||||
/// Each chunk has the specified number of lines.
|
/// Each chunk has the specified number of lines.
|
||||||
Lines(usize),
|
Lines(u64),
|
||||||
|
|
||||||
/// Each chunk has the specified number of bytes.
|
/// Each chunk has the specified number of bytes.
|
||||||
Bytes(usize),
|
Bytes(u64),
|
||||||
|
|
||||||
/// Each chunk has as many lines as possible without exceeding the
|
/// Each chunk has as many lines as possible without exceeding the
|
||||||
/// specified number of bytes.
|
/// specified number of bytes.
|
||||||
LineBytes(usize),
|
LineBytes(u64),
|
||||||
|
|
||||||
/// Split the file into this many chunks.
|
/// Split the file into this many chunks.
|
||||||
Number(usize),
|
///
|
||||||
|
/// There are several sub-strategies available, as defined by
|
||||||
|
/// [`NumberType`].
|
||||||
|
Number(NumberType),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error when parsing a chunking strategy from command-line arguments.
|
/// An error when parsing a chunking strategy from command-line arguments.
|
||||||
|
@ -202,8 +328,8 @@ enum StrategyError {
|
||||||
/// Invalid number of bytes.
|
/// Invalid number of bytes.
|
||||||
Bytes(ParseSizeError),
|
Bytes(ParseSizeError),
|
||||||
|
|
||||||
/// Invalid number of chunks.
|
/// Invalid number type.
|
||||||
NumberOfChunks(ParseIntError),
|
NumberType(NumberTypeError),
|
||||||
|
|
||||||
/// Multiple chunking strategies were specified (but only one should be).
|
/// Multiple chunking strategies were specified (but only one should be).
|
||||||
MultipleWays,
|
MultipleWays,
|
||||||
|
@ -214,7 +340,12 @@ impl fmt::Display for StrategyError {
|
||||||
match self {
|
match self {
|
||||||
Self::Lines(e) => write!(f, "invalid number of lines: {}", e),
|
Self::Lines(e) => write!(f, "invalid number of lines: {}", e),
|
||||||
Self::Bytes(e) => write!(f, "invalid number of bytes: {}", e),
|
Self::Bytes(e) => write!(f, "invalid number of bytes: {}", e),
|
||||||
Self::NumberOfChunks(e) => write!(f, "invalid number of chunks: {}", e),
|
Self::NumberType(NumberTypeError::NumberOfChunks(s)) => {
|
||||||
|
write!(f, "invalid number of chunks: {}", s)
|
||||||
|
}
|
||||||
|
Self::NumberType(NumberTypeError::ChunkNumber(s)) => {
|
||||||
|
write!(f, "invalid chunk number: {}", s)
|
||||||
|
}
|
||||||
Self::MultipleWays => write!(f, "cannot split in more than one way"),
|
Self::MultipleWays => write!(f, "cannot split in more than one way"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,8 +383,8 @@ impl Strategy {
|
||||||
}
|
}
|
||||||
(0, 0, 0, 1) => {
|
(0, 0, 0, 1) => {
|
||||||
let s = matches.value_of(OPT_NUMBER).unwrap();
|
let s = matches.value_of(OPT_NUMBER).unwrap();
|
||||||
let n = s.parse::<usize>().map_err(StrategyError::NumberOfChunks)?;
|
let number_type = NumberType::from(s).map_err(StrategyError::NumberType)?;
|
||||||
Ok(Self::Number(n))
|
Ok(Self::Number(number_type))
|
||||||
}
|
}
|
||||||
_ => Err(StrategyError::MultipleWays),
|
_ => Err(StrategyError::MultipleWays),
|
||||||
}
|
}
|
||||||
|
@ -263,9 +394,9 @@ impl Strategy {
|
||||||
/// Parse the suffix type from the command-line arguments.
|
/// Parse the suffix type from the command-line arguments.
|
||||||
fn suffix_type_from(matches: &ArgMatches) -> SuffixType {
|
fn suffix_type_from(matches: &ArgMatches) -> SuffixType {
|
||||||
if matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0 {
|
if matches.occurrences_of(OPT_NUMERIC_SUFFIXES) > 0 {
|
||||||
SuffixType::NumericDecimal
|
SuffixType::Decimal
|
||||||
} else if matches.occurrences_of(OPT_HEX_SUFFIXES) > 0 {
|
} else if matches.occurrences_of(OPT_HEX_SUFFIXES) > 0 {
|
||||||
SuffixType::NumericHexadecimal
|
SuffixType::Hexadecimal
|
||||||
} else {
|
} else {
|
||||||
SuffixType::Alphabetic
|
SuffixType::Alphabetic
|
||||||
}
|
}
|
||||||
|
@ -285,6 +416,16 @@ struct Settings {
|
||||||
filter: Option<String>,
|
filter: Option<String>,
|
||||||
strategy: Strategy,
|
strategy: Strategy,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
|
|
||||||
|
/// Whether to *not* produce empty files when using `-n`.
|
||||||
|
///
|
||||||
|
/// The `-n` command-line argument gives a specific number of
|
||||||
|
/// chunks into which the input files will be split. If the number
|
||||||
|
/// of chunks is greater than the number of bytes, and this is
|
||||||
|
/// `false`, then empty files will be created for the excess
|
||||||
|
/// chunks. If this is `false`, then empty files will not be
|
||||||
|
/// created.
|
||||||
|
elide_empty_files: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An error when parsing settings from command-line arguments.
|
/// An error when parsing settings from command-line arguments.
|
||||||
|
@ -293,11 +434,14 @@ enum SettingsError {
|
||||||
Strategy(StrategyError),
|
Strategy(StrategyError),
|
||||||
|
|
||||||
/// Invalid suffix length parameter.
|
/// Invalid suffix length parameter.
|
||||||
SuffixLength(String),
|
SuffixNotParsable(String),
|
||||||
|
|
||||||
/// Suffix contains a directory separator, which is not allowed.
|
/// Suffix contains a directory separator, which is not allowed.
|
||||||
SuffixContainsSeparator(String),
|
SuffixContainsSeparator(String),
|
||||||
|
|
||||||
|
/// Suffix is not large enough to split into specified chunks
|
||||||
|
SuffixTooSmall(usize),
|
||||||
|
|
||||||
/// The `--filter` option is not supported on Windows.
|
/// The `--filter` option is not supported on Windows.
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
NotSupported,
|
NotSupported,
|
||||||
|
@ -317,7 +461,8 @@ impl fmt::Display for SettingsError {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Strategy(e) => e.fmt(f),
|
Self::Strategy(e) => e.fmt(f),
|
||||||
Self::SuffixLength(s) => write!(f, "invalid suffix length: {}", s.quote()),
|
Self::SuffixNotParsable(s) => write!(f, "invalid suffix length: {}", s.quote()),
|
||||||
|
Self::SuffixTooSmall(i) => write!(f, "the suffix length needs to be at least {}", i),
|
||||||
Self::SuffixContainsSeparator(s) => write!(
|
Self::SuffixContainsSeparator(s) => write!(
|
||||||
f,
|
f,
|
||||||
"invalid suffix {}, contains directory separator",
|
"invalid suffix {}, contains directory separator",
|
||||||
|
@ -340,18 +485,34 @@ impl Settings {
|
||||||
if additional_suffix.contains('/') {
|
if additional_suffix.contains('/') {
|
||||||
return Err(SettingsError::SuffixContainsSeparator(additional_suffix));
|
return Err(SettingsError::SuffixContainsSeparator(additional_suffix));
|
||||||
}
|
}
|
||||||
|
let strategy = Strategy::from(matches).map_err(SettingsError::Strategy)?;
|
||||||
|
let suffix_type = suffix_type_from(matches);
|
||||||
let suffix_length_str = matches.value_of(OPT_SUFFIX_LENGTH).unwrap();
|
let suffix_length_str = matches.value_of(OPT_SUFFIX_LENGTH).unwrap();
|
||||||
|
let suffix_length: usize = suffix_length_str
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| SettingsError::SuffixNotParsable(suffix_length_str.to_string()))?;
|
||||||
|
if let Strategy::Number(ref number_type) = strategy {
|
||||||
|
let chunks = number_type.num_chunks();
|
||||||
|
if suffix_length != 0 {
|
||||||
|
let required_suffix_length =
|
||||||
|
(chunks as f64).log(suffix_type.radix() as f64).ceil() as usize;
|
||||||
|
if suffix_length < required_suffix_length {
|
||||||
|
return Err(SettingsError::SuffixTooSmall(required_suffix_length));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let result = Self {
|
let result = Self {
|
||||||
suffix_length: suffix_length_str
|
suffix_length: suffix_length_str
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| SettingsError::SuffixLength(suffix_length_str.to_string()))?,
|
.map_err(|_| SettingsError::SuffixNotParsable(suffix_length_str.to_string()))?,
|
||||||
suffix_type: suffix_type_from(matches),
|
suffix_type,
|
||||||
additional_suffix,
|
additional_suffix,
|
||||||
verbose: matches.occurrences_of("verbose") > 0,
|
verbose: matches.occurrences_of("verbose") > 0,
|
||||||
strategy: Strategy::from(matches).map_err(SettingsError::Strategy)?,
|
strategy,
|
||||||
input: matches.value_of(ARG_INPUT).unwrap().to_owned(),
|
input: matches.value_of(ARG_INPUT).unwrap().to_owned(),
|
||||||
prefix: matches.value_of(ARG_PREFIX).unwrap().to_owned(),
|
prefix: matches.value_of(ARG_PREFIX).unwrap().to_owned(),
|
||||||
filter: matches.value_of(OPT_FILTER).map(|s| s.to_owned()),
|
filter: matches.value_of(OPT_FILTER).map(|s| s.to_owned()),
|
||||||
|
elide_empty_files: matches.is_present(OPT_ELIDE_EMPTY_FILES),
|
||||||
};
|
};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
if result.filter.is_some() {
|
if result.filter.is_some() {
|
||||||
|
@ -376,17 +537,17 @@ struct ByteChunkWriter<'a> {
|
||||||
settings: &'a Settings,
|
settings: &'a Settings,
|
||||||
|
|
||||||
/// The maximum number of bytes allowed for a single chunk of output.
|
/// The maximum number of bytes allowed for a single chunk of output.
|
||||||
chunk_size: usize,
|
chunk_size: u64,
|
||||||
|
|
||||||
/// Running total of number of chunks that have been completed.
|
/// Running total of number of chunks that have been completed.
|
||||||
num_chunks_written: usize,
|
num_chunks_written: u64,
|
||||||
|
|
||||||
/// Remaining capacity in number of bytes in the current chunk.
|
/// Remaining capacity in number of bytes in the current chunk.
|
||||||
///
|
///
|
||||||
/// This number starts at `chunk_size` and decreases as bytes are
|
/// This number starts at `chunk_size` and decreases as bytes are
|
||||||
/// written. Once it reaches zero, a writer for a new chunk is
|
/// written. Once it reaches zero, a writer for a new chunk is
|
||||||
/// initialized and this number gets reset to `chunk_size`.
|
/// initialized and this number gets reset to `chunk_size`.
|
||||||
num_bytes_remaining_in_current_chunk: usize,
|
num_bytes_remaining_in_current_chunk: u64,
|
||||||
|
|
||||||
/// The underlying writer for the current chunk.
|
/// The underlying writer for the current chunk.
|
||||||
///
|
///
|
||||||
|
@ -400,7 +561,7 @@ struct ByteChunkWriter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ByteChunkWriter<'a> {
|
impl<'a> ByteChunkWriter<'a> {
|
||||||
fn new(chunk_size: usize, settings: &'a Settings) -> Option<ByteChunkWriter<'a>> {
|
fn new(chunk_size: u64, settings: &'a Settings) -> Option<ByteChunkWriter<'a>> {
|
||||||
let mut filename_iterator = FilenameIterator::new(
|
let mut filename_iterator = FilenameIterator::new(
|
||||||
&settings.prefix,
|
&settings.prefix,
|
||||||
&settings.additional_suffix,
|
&settings.additional_suffix,
|
||||||
|
@ -430,7 +591,7 @@ impl<'a> Write for ByteChunkWriter<'a> {
|
||||||
// different underlying writers. In that case, each iteration of
|
// different underlying writers. In that case, each iteration of
|
||||||
// this loop writes to the underlying writer that corresponds to
|
// this loop writes to the underlying writer that corresponds to
|
||||||
// the current chunk number.
|
// the current chunk number.
|
||||||
let mut carryover_bytes_written = 0;
|
let mut carryover_bytes_written: usize = 0;
|
||||||
loop {
|
loop {
|
||||||
if buf.is_empty() {
|
if buf.is_empty() {
|
||||||
return Ok(carryover_bytes_written);
|
return Ok(carryover_bytes_written);
|
||||||
|
@ -441,19 +602,23 @@ impl<'a> Write for ByteChunkWriter<'a> {
|
||||||
// write enough bytes to fill the current chunk, then increment
|
// write enough bytes to fill the current chunk, then increment
|
||||||
// the chunk number and repeat.
|
// the chunk number and repeat.
|
||||||
let n = buf.len();
|
let n = buf.len();
|
||||||
if n < self.num_bytes_remaining_in_current_chunk {
|
if (n as u64) < self.num_bytes_remaining_in_current_chunk {
|
||||||
let num_bytes_written = self.inner.write(buf)?;
|
let num_bytes_written = self.inner.write(buf)?;
|
||||||
self.num_bytes_remaining_in_current_chunk -= num_bytes_written;
|
self.num_bytes_remaining_in_current_chunk -= num_bytes_written as u64;
|
||||||
return Ok(carryover_bytes_written + num_bytes_written);
|
return Ok(carryover_bytes_written + num_bytes_written);
|
||||||
} else {
|
} else {
|
||||||
// Write enough bytes to fill the current chunk.
|
// Write enough bytes to fill the current chunk.
|
||||||
let i = self.num_bytes_remaining_in_current_chunk;
|
//
|
||||||
|
// Conversion to usize is safe because we checked that
|
||||||
|
// self.num_bytes_remaining_in_current_chunk is lower than
|
||||||
|
// n, which is already usize.
|
||||||
|
let i = self.num_bytes_remaining_in_current_chunk as usize;
|
||||||
let num_bytes_written = self.inner.write(&buf[..i])?;
|
let num_bytes_written = self.inner.write(&buf[..i])?;
|
||||||
|
|
||||||
// It's possible that the underlying writer did not
|
// It's possible that the underlying writer did not
|
||||||
// write all the bytes.
|
// write all the bytes.
|
||||||
if num_bytes_written < i {
|
if num_bytes_written < i {
|
||||||
self.num_bytes_remaining_in_current_chunk -= num_bytes_written;
|
self.num_bytes_remaining_in_current_chunk -= num_bytes_written as u64;
|
||||||
return Ok(carryover_bytes_written + num_bytes_written);
|
return Ok(carryover_bytes_written + num_bytes_written);
|
||||||
} else {
|
} else {
|
||||||
// Move the window to look at only the remaining bytes.
|
// Move the window to look at only the remaining bytes.
|
||||||
|
@ -504,17 +669,17 @@ struct LineChunkWriter<'a> {
|
||||||
settings: &'a Settings,
|
settings: &'a Settings,
|
||||||
|
|
||||||
/// The maximum number of lines allowed for a single chunk of output.
|
/// The maximum number of lines allowed for a single chunk of output.
|
||||||
chunk_size: usize,
|
chunk_size: u64,
|
||||||
|
|
||||||
/// Running total of number of chunks that have been completed.
|
/// Running total of number of chunks that have been completed.
|
||||||
num_chunks_written: usize,
|
num_chunks_written: u64,
|
||||||
|
|
||||||
/// Remaining capacity in number of lines in the current chunk.
|
/// Remaining capacity in number of lines in the current chunk.
|
||||||
///
|
///
|
||||||
/// This number starts at `chunk_size` and decreases as lines are
|
/// This number starts at `chunk_size` and decreases as lines are
|
||||||
/// written. Once it reaches zero, a writer for a new chunk is
|
/// written. Once it reaches zero, a writer for a new chunk is
|
||||||
/// initialized and this number gets reset to `chunk_size`.
|
/// initialized and this number gets reset to `chunk_size`.
|
||||||
num_lines_remaining_in_current_chunk: usize,
|
num_lines_remaining_in_current_chunk: u64,
|
||||||
|
|
||||||
/// The underlying writer for the current chunk.
|
/// The underlying writer for the current chunk.
|
||||||
///
|
///
|
||||||
|
@ -528,7 +693,7 @@ struct LineChunkWriter<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> LineChunkWriter<'a> {
|
impl<'a> LineChunkWriter<'a> {
|
||||||
fn new(chunk_size: usize, settings: &'a Settings) -> Option<LineChunkWriter<'a>> {
|
fn new(chunk_size: u64, settings: &'a Settings) -> Option<LineChunkWriter<'a>> {
|
||||||
let mut filename_iterator = FilenameIterator::new(
|
let mut filename_iterator = FilenameIterator::new(
|
||||||
&settings.prefix,
|
&settings.prefix,
|
||||||
&settings.additional_suffix,
|
&settings.additional_suffix,
|
||||||
|
@ -609,10 +774,98 @@ impl<'a> Write for LineChunkWriter<'a> {
|
||||||
fn split_into_n_chunks_by_byte<R>(
|
fn split_into_n_chunks_by_byte<R>(
|
||||||
settings: &Settings,
|
settings: &Settings,
|
||||||
reader: &mut R,
|
reader: &mut R,
|
||||||
num_chunks: usize,
|
num_chunks: u64,
|
||||||
) -> UResult<()>
|
) -> UResult<()>
|
||||||
where
|
where
|
||||||
R: Read,
|
R: Read,
|
||||||
|
{
|
||||||
|
// Get the size of the input file in bytes and compute the number
|
||||||
|
// of bytes per chunk.
|
||||||
|
//
|
||||||
|
// If the requested number of chunks exceeds the number of bytes
|
||||||
|
// in the file *and* the `elide_empty_files` parameter is enabled,
|
||||||
|
// then behave as if the number of chunks was set to the number of
|
||||||
|
// bytes in the file. This ensures that we don't write empty
|
||||||
|
// files. Otherwise, just write the `num_chunks - num_bytes` empty
|
||||||
|
// files.
|
||||||
|
let metadata = metadata(&settings.input).map_err(|_| {
|
||||||
|
USimpleError::new(1, format!("{}: cannot determine file size", settings.input))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let num_bytes = metadata.len();
|
||||||
|
let will_have_empty_files = settings.elide_empty_files && num_chunks > num_bytes;
|
||||||
|
let (num_chunks, chunk_size) = if will_have_empty_files {
|
||||||
|
let num_chunks = num_bytes;
|
||||||
|
let chunk_size = 1;
|
||||||
|
(num_chunks, chunk_size)
|
||||||
|
} else {
|
||||||
|
let chunk_size = (num_bytes / (num_chunks)).max(1);
|
||||||
|
(num_chunks, chunk_size)
|
||||||
|
};
|
||||||
|
|
||||||
|
let num_chunks: usize = num_chunks
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| USimpleError::new(1, "Number of chunks too big"))?;
|
||||||
|
|
||||||
|
// This object is responsible for creating the filename for each chunk.
|
||||||
|
let mut filename_iterator = FilenameIterator::new(
|
||||||
|
&settings.prefix,
|
||||||
|
&settings.additional_suffix,
|
||||||
|
settings.suffix_length,
|
||||||
|
settings.suffix_type,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create one writer for each chunk. This will create each
|
||||||
|
// of the underlying files (if not in `--filter` mode).
|
||||||
|
let mut writers = vec![];
|
||||||
|
for _ in 0..num_chunks {
|
||||||
|
let filename = filename_iterator
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| USimpleError::new(1, "output file suffixes exhausted"))?;
|
||||||
|
let writer = platform::instantiate_current_writer(&settings.filter, filename.as_str());
|
||||||
|
writers.push(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This block evaluates to an object of type `std::io::Result<()>`.
|
||||||
|
{
|
||||||
|
// Write `chunk_size` bytes from the reader into each writer
|
||||||
|
// except the last.
|
||||||
|
//
|
||||||
|
// The last writer gets all remaining bytes so that if the number
|
||||||
|
// of bytes in the input file was not evenly divisible by
|
||||||
|
// `num_chunks`, we don't leave any bytes behind.
|
||||||
|
for writer in writers.iter_mut().take(num_chunks - 1) {
|
||||||
|
io::copy(&mut reader.by_ref().take(chunk_size), writer)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write all the remaining bytes to the last chunk.
|
||||||
|
let i = num_chunks - 1;
|
||||||
|
let last_chunk_size = num_bytes - (chunk_size * (num_chunks as u64 - 1));
|
||||||
|
io::copy(&mut reader.by_ref().take(last_chunk_size), &mut writers[i])?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
.map_err_context(|| "I/O error".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Split a file into a specific number of chunks by line.
|
||||||
|
///
|
||||||
|
/// This function always creates one output file for each chunk, even
|
||||||
|
/// if there is an error reading or writing one of the chunks or if
|
||||||
|
/// the input file is truncated. However, if the `filter` option is
|
||||||
|
/// being used, then no files are created.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// This function returns an error if there is a problem reading from
|
||||||
|
/// `reader` or writing to one of the output files.
|
||||||
|
fn split_into_n_chunks_by_line<R>(
|
||||||
|
settings: &Settings,
|
||||||
|
reader: &mut R,
|
||||||
|
num_chunks: u64,
|
||||||
|
) -> UResult<()>
|
||||||
|
where
|
||||||
|
R: BufRead,
|
||||||
{
|
{
|
||||||
// Get the size of the input file in bytes and compute the number
|
// Get the size of the input file in bytes and compute the number
|
||||||
// of bytes per chunk.
|
// of bytes per chunk.
|
||||||
|
@ -639,38 +892,27 @@ where
|
||||||
writers.push(writer);
|
writers.push(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This block evaluates to an object of type `std::io::Result<()>`.
|
let mut num_bytes_remaining_in_current_chunk = chunk_size;
|
||||||
{
|
let mut i = 0;
|
||||||
// Write `chunk_size` bytes from the reader into each writer
|
for line_result in reader.lines() {
|
||||||
// except the last.
|
let line = line_result.unwrap();
|
||||||
//
|
let maybe_writer = writers.get_mut(i);
|
||||||
// Re-use the buffer to avoid re-allocating a `Vec` on each
|
let writer = maybe_writer.unwrap();
|
||||||
// iteration. The contents will be completely overwritten each
|
let bytes = line.as_bytes();
|
||||||
// time we call `read_exact()`.
|
writer.write_all(bytes)?;
|
||||||
//
|
writer.write_all(b"\n")?;
|
||||||
// The last writer gets all remaining bytes so that if the number
|
|
||||||
// of bytes in the input file was not evenly divisible by
|
// Add one byte for the newline character.
|
||||||
// `num_chunks`, we don't leave any bytes behind.
|
let num_bytes = bytes.len() + 1;
|
||||||
let mut buf = vec![0u8; chunk_size];
|
if num_bytes > num_bytes_remaining_in_current_chunk {
|
||||||
for writer in writers.iter_mut().take(num_chunks - 1) {
|
num_bytes_remaining_in_current_chunk = chunk_size;
|
||||||
reader.read_exact(&mut buf)?;
|
i += 1;
|
||||||
writer.write_all(&buf)?;
|
} else {
|
||||||
|
num_bytes_remaining_in_current_chunk -= num_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write all the remaining bytes to the last chunk.
|
|
||||||
//
|
|
||||||
// To do this, we resize our buffer to have the necessary number
|
|
||||||
// of bytes.
|
|
||||||
let i = num_chunks - 1;
|
|
||||||
let last_chunk_size = num_bytes as usize - (chunk_size * (num_chunks - 1));
|
|
||||||
buf.resize(last_chunk_size, 0);
|
|
||||||
|
|
||||||
reader.read_exact(&mut buf)?;
|
|
||||||
writers[i].write_all(&buf)?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
.map_err_context(|| "I/O error".to_string())
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn split(settings: &Settings) -> UResult<()> {
|
fn split(settings: &Settings) -> UResult<()> {
|
||||||
|
@ -687,9 +929,13 @@ fn split(settings: &Settings) -> UResult<()> {
|
||||||
});
|
});
|
||||||
|
|
||||||
match settings.strategy {
|
match settings.strategy {
|
||||||
Strategy::Number(num_chunks) => {
|
Strategy::Number(NumberType::Bytes(num_chunks)) => {
|
||||||
split_into_n_chunks_by_byte(settings, &mut reader, num_chunks)
|
split_into_n_chunks_by_byte(settings, &mut reader, num_chunks)
|
||||||
}
|
}
|
||||||
|
Strategy::Number(NumberType::Lines(num_chunks)) => {
|
||||||
|
split_into_n_chunks_by_line(settings, &mut reader, num_chunks)
|
||||||
|
}
|
||||||
|
Strategy::Number(_) => Err(USimpleError::new(1, "-n mode not yet fully implemented")),
|
||||||
Strategy::Lines(chunk_size) => {
|
Strategy::Lines(chunk_size) => {
|
||||||
let mut writer = LineChunkWriter::new(chunk_size, settings)
|
let mut writer = LineChunkWriter::new(chunk_size, settings)
|
||||||
.ok_or_else(|| USimpleError::new(1, "output file suffixes exhausted"))?;
|
.ok_or_else(|| USimpleError::new(1, "output file suffixes exhausted"))?;
|
||||||
|
@ -730,3 +976,87 @@ fn split(settings: &Settings) -> UResult<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
|
||||||
|
use crate::NumberType;
|
||||||
|
use crate::NumberTypeError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_number_type_from() {
|
||||||
|
assert_eq!(NumberType::from("123").unwrap(), NumberType::Bytes(123));
|
||||||
|
assert_eq!(NumberType::from("l/123").unwrap(), NumberType::Lines(123));
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("l/123/456").unwrap(),
|
||||||
|
NumberType::KthLines(123, 456)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("r/123").unwrap(),
|
||||||
|
NumberType::RoundRobin(123)
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("r/123/456").unwrap(),
|
||||||
|
NumberType::KthRoundRobin(123, 456)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_number_type_from_error() {
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("xyz").unwrap_err(),
|
||||||
|
NumberTypeError::NumberOfChunks("xyz".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("l/xyz").unwrap_err(),
|
||||||
|
NumberTypeError::NumberOfChunks("xyz".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("l/123/xyz").unwrap_err(),
|
||||||
|
NumberTypeError::NumberOfChunks("xyz".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("l/abc/456").unwrap_err(),
|
||||||
|
NumberTypeError::ChunkNumber("abc".to_string())
|
||||||
|
);
|
||||||
|
// In GNU split, the number of chunks get precedence:
|
||||||
|
//
|
||||||
|
// $ split -n l/abc/xyz
|
||||||
|
// split: invalid number of chunks: ‘xyz’
|
||||||
|
//
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("l/abc/xyz").unwrap_err(),
|
||||||
|
NumberTypeError::NumberOfChunks("xyz".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("r/xyz").unwrap_err(),
|
||||||
|
NumberTypeError::NumberOfChunks("xyz".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("r/123/xyz").unwrap_err(),
|
||||||
|
NumberTypeError::NumberOfChunks("xyz".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("r/abc/456").unwrap_err(),
|
||||||
|
NumberTypeError::ChunkNumber("abc".to_string())
|
||||||
|
);
|
||||||
|
// In GNU split, the number of chunks get precedence:
|
||||||
|
//
|
||||||
|
// $ split -n r/abc/xyz
|
||||||
|
// split: invalid number of chunks: ‘xyz’
|
||||||
|
//
|
||||||
|
assert_eq!(
|
||||||
|
NumberType::from("r/abc/xyz").unwrap_err(),
|
||||||
|
NumberTypeError::NumberOfChunks("xyz".to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_number_type_num_chunks() {
|
||||||
|
assert_eq!(NumberType::from("123").unwrap().num_chunks(), 123);
|
||||||
|
assert_eq!(NumberType::from("l/123").unwrap().num_chunks(), 123);
|
||||||
|
assert_eq!(NumberType::from("l/123/456").unwrap().num_chunks(), 456);
|
||||||
|
assert_eq!(NumberType::from("r/123").unwrap().num_chunks(), 123);
|
||||||
|
assert_eq!(NumberType::from("r/123/456").unwrap().num_chunks(), 456);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,13 +8,13 @@
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::entries;
|
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
use uucore::fs::display_permissions;
|
use uucore::fs::display_permissions;
|
||||||
use uucore::fsext::{
|
use uucore::fsext::{
|
||||||
pretty_filetype, pretty_fstype, pretty_time, read_fs_list, statfs, BirthTime, FsMeta,
|
pretty_filetype, pretty_fstype, pretty_time, read_fs_list, statfs, BirthTime, FsMeta,
|
||||||
};
|
};
|
||||||
use uucore::libc::mode_t;
|
use uucore::libc::mode_t;
|
||||||
|
use uucore::{entries, format_usage};
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
@ -87,6 +87,7 @@ macro_rules! print_adjusted {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ABOUT: &str = "Display file or file system status.";
|
static ABOUT: &str = "Display file or file system status.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... FILE...";
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static DEREFERENCE: &str = "dereference";
|
pub static DEREFERENCE: &str = "dereference";
|
||||||
|
@ -893,10 +894,6 @@ impl Stater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_long_usage() -> String {
|
fn get_long_usage() -> String {
|
||||||
String::from(
|
String::from(
|
||||||
"
|
"
|
||||||
|
@ -957,13 +954,9 @@ for details about the options it supports.
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
|
||||||
let long_usage = get_long_usage();
|
let long_usage = get_long_usage();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app().after_help(&long_usage[..]).get_matches_from(args);
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&long_usage[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let stater = Stater::new(&matches)?;
|
let stater = Stater::new(&matches)?;
|
||||||
let exit_status = stater.exec();
|
let exit_status = stater.exec();
|
||||||
|
@ -978,6 +971,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::DEREFERENCE)
|
Arg::new(options::DEREFERENCE)
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
|
||||||
use std::convert::TryFrom;
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::os::unix::process::ExitStatusExt;
|
use std::os::unix::process::ExitStatusExt;
|
||||||
|
@ -21,11 +21,12 @@ use tempfile::tempdir;
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
use uucore::error::{FromIo, UResult, USimpleError, UUsageError};
|
||||||
use uucore::parse_size::parse_size;
|
use uucore::parse_size::parse_size;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str =
|
static ABOUT: &str =
|
||||||
"Run COMMAND, with modified buffering operations for its standard streams.\n\n\
|
"Run COMMAND, with modified buffering operations for its standard streams.\n\n\
|
||||||
Mandatory arguments to long options are mandatory for short options too.";
|
Mandatory arguments to long options are mandatory for short options too.";
|
||||||
|
const USAGE: &str = "{} OPTION... COMMAND";
|
||||||
static LONG_HELP: &str = "If MODE is 'L' the corresponding stream will be line buffered.\n\
|
static LONG_HELP: &str = "If MODE is 'L' the corresponding stream will be line buffered.\n\
|
||||||
This option is invalid with standard input.\n\n\
|
This option is invalid with standard input.\n\n\
|
||||||
If MODE is '0' the corresponding stream will be unbuffered.\n\n\
|
If MODE is '0' the corresponding stream will be unbuffered.\n\n\
|
||||||
|
@ -48,10 +49,6 @@ mod options {
|
||||||
pub const COMMAND: &str = "command";
|
pub const COMMAND: &str = "command";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} OPTION... COMMAND", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
const STDBUF_INJECT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libstdbuf.so"));
|
const STDBUF_INJECT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/libstdbuf.so"));
|
||||||
|
|
||||||
enum BufferType {
|
enum BufferType {
|
||||||
|
@ -120,7 +117,14 @@ fn check_option(matches: &ArgMatches, name: &str) -> Result<BufferType, ProgramO
|
||||||
}
|
}
|
||||||
x => parse_size(x).map_or_else(
|
x => parse_size(x).map_or_else(
|
||||||
|e| crash!(125, "invalid mode {}", e),
|
|e| crash!(125, "invalid mode {}", e),
|
||||||
|m| Ok(BufferType::Size(m)),
|
|m| {
|
||||||
|
Ok(BufferType::Size(m.try_into().map_err(|_| {
|
||||||
|
ProgramOptionsError(format!(
|
||||||
|
"invalid mode '{}': Value too large for defined data type",
|
||||||
|
x
|
||||||
|
))
|
||||||
|
})?))
|
||||||
|
},
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
None => Ok(BufferType::Default),
|
None => Ok(BufferType::Default),
|
||||||
|
@ -154,9 +158,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let args = args
|
let args = args
|
||||||
.collect_str(InvalidEncodingHandling::Ignore)
|
.collect_str(InvalidEncodingHandling::Ignore)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
let usage = usage();
|
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let options = ProgramOptions::try_from(&matches).map_err(|e| UUsageError::new(125, e.0))?;
|
let options = ProgramOptions::try_from(&matches).map_err(|e| UUsageError::new(125, e.0))?;
|
||||||
|
|
||||||
|
@ -196,6 +199,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.after_help(LONG_HELP)
|
.after_help(LONG_HELP)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::TrailingVarArg)
|
.setting(AppSettings::TrailingVarArg)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -16,10 +16,10 @@ use std::io::{stdin, Read};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static NAME: &str = "sum";
|
static NAME: &str = "sum";
|
||||||
static USAGE: &str = "sum [OPTION]... [FILE]...";
|
static USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
static SUMMARY: &str = "Checksum and count the blocks in a file.\n\
|
static SUMMARY: &str = "Checksum and count the blocks in a file.\n\
|
||||||
With no FILE, or when FILE is -, read standard input.";
|
With no FILE, or when FILE is -, read standard input.";
|
||||||
|
|
||||||
|
@ -144,7 +144,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -13,8 +13,10 @@ use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
static ABOUT: &str = "Synchronize cached writes to persistent storage";
|
static ABOUT: &str = "Synchronize cached writes to persistent storage";
|
||||||
|
const USAGE: &str = "{} [OPTION]... FILE...";
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub static FILE_SYSTEM: &str = "file-system";
|
pub static FILE_SYSTEM: &str = "file-system";
|
||||||
pub static DATA: &str = "data";
|
pub static DATA: &str = "data";
|
||||||
|
@ -157,15 +159,9 @@ mod platform {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... FILE...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let files: Vec<String> = matches
|
let files: Vec<String> = matches
|
||||||
.values_of(ARG_FILES)
|
.values_of(ARG_FILES)
|
||||||
|
@ -198,6 +194,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::FILE_SYSTEM)
|
Arg::new(options::FILE_SYSTEM)
|
||||||
|
|
|
@ -19,13 +19,13 @@ use std::{
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::UError;
|
use uucore::error::UError;
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
use uucore::show;
|
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
use uucore::{format_usage, show};
|
||||||
|
|
||||||
use crate::error::TacError;
|
use crate::error::TacError;
|
||||||
|
|
||||||
static NAME: &str = "tac";
|
static NAME: &str = "tac";
|
||||||
static USAGE: &str = "[OPTION]... [FILE]...";
|
static USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
static SUMMARY: &str = "Write each file to standard output, last line first.";
|
static SUMMARY: &str = "Write each file to standard output, last line first.";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
|
@ -64,7 +64,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.name(NAME)
|
.name(NAME)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.about(SUMMARY)
|
.about(SUMMARY)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -22,6 +22,7 @@ use chunks::ReverseChunks;
|
||||||
|
|
||||||
use clap::{App, AppSettings, Arg};
|
use clap::{App, AppSettings, Arg};
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::fs::{File, Metadata};
|
use std::fs::{File, Metadata};
|
||||||
|
@ -31,6 +32,7 @@ use std::thread::sleep;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
use uucore::lines::lines;
|
use uucore::lines::lines;
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
use uucore::ringbuffer::RingBuffer;
|
use uucore::ringbuffer::RingBuffer;
|
||||||
|
@ -47,7 +49,7 @@ const ABOUT: &str = "\
|
||||||
\n\
|
\n\
|
||||||
Mandatory arguments to long flags are mandatory for short flags too.\
|
Mandatory arguments to long flags are mandatory for short flags too.\
|
||||||
";
|
";
|
||||||
const USAGE: &str = "tail [FLAG]... [FILE]...";
|
const USAGE: &str = "{} [FLAG]... [FILE]...";
|
||||||
|
|
||||||
pub mod options {
|
pub mod options {
|
||||||
pub mod verbosity {
|
pub mod verbosity {
|
||||||
|
@ -65,8 +67,8 @@ pub mod options {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum FilterMode {
|
enum FilterMode {
|
||||||
Bytes(usize),
|
Bytes(u64),
|
||||||
Lines(usize, u8), // (number of lines, delimiter)
|
Lines(u64, u8), // (number of lines, delimiter)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FilterMode {
|
impl Default for FilterMode {
|
||||||
|
@ -277,7 +279,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::BYTES)
|
Arg::new(options::BYTES)
|
||||||
|
@ -439,7 +441,7 @@ fn follow<T: BufRead>(readers: &mut [(T, &String)], settings: &Settings) -> URes
|
||||||
/// ```
|
/// ```
|
||||||
fn forwards_thru_file<R>(
|
fn forwards_thru_file<R>(
|
||||||
reader: &mut R,
|
reader: &mut R,
|
||||||
num_delimiters: usize,
|
num_delimiters: u64,
|
||||||
delimiter: u8,
|
delimiter: u8,
|
||||||
) -> std::io::Result<usize>
|
) -> std::io::Result<usize>
|
||||||
where
|
where
|
||||||
|
@ -470,7 +472,7 @@ where
|
||||||
/// Iterate over bytes in the file, in reverse, until we find the
|
/// Iterate over bytes in the file, in reverse, until we find the
|
||||||
/// `num_delimiters` instance of `delimiter`. The `file` is left seek'd to the
|
/// `num_delimiters` instance of `delimiter`. The `file` is left seek'd to the
|
||||||
/// position just after that delimiter.
|
/// position just after that delimiter.
|
||||||
fn backwards_thru_file(file: &mut File, num_delimiters: usize, delimiter: u8) {
|
fn backwards_thru_file(file: &mut File, num_delimiters: u64, delimiter: u8) {
|
||||||
// This variable counts the number of delimiters found in the file
|
// This variable counts the number of delimiters found in the file
|
||||||
// so far (reading from the end of the file toward the beginning).
|
// so far (reading from the end of the file toward the beginning).
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
|
@ -540,6 +542,18 @@ fn bounded_tail(file: &mut File, mode: &FilterMode, beginning: bool) {
|
||||||
std::io::copy(file, &mut stdout).unwrap();
|
std::io::copy(file, &mut stdout).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An alternative to [`Iterator::skip`] with u64 instead of usize. This is
|
||||||
|
/// necessary because the usize limit doesn't make sense when iterating over
|
||||||
|
/// something that's not in memory. For example, a very large file. This allows
|
||||||
|
/// us to skip data larger than 4 GiB even on 32-bit platforms.
|
||||||
|
fn skip_u64(iter: &mut impl Iterator, num: u64) {
|
||||||
|
for _ in 0..num {
|
||||||
|
if iter.next().is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Collect the last elements of an iterator into a `VecDeque`.
|
/// Collect the last elements of an iterator into a `VecDeque`.
|
||||||
///
|
///
|
||||||
/// This function returns a [`VecDeque`] containing either the last
|
/// This function returns a [`VecDeque`] containing either the last
|
||||||
|
@ -552,10 +566,10 @@ fn bounded_tail(file: &mut File, mode: &FilterMode, beginning: bool) {
|
||||||
///
|
///
|
||||||
/// If any element of `iter` is an [`Err`], then this function panics.
|
/// If any element of `iter` is an [`Err`], then this function panics.
|
||||||
fn unbounded_tail_collect<T, E>(
|
fn unbounded_tail_collect<T, E>(
|
||||||
iter: impl Iterator<Item = Result<T, E>>,
|
mut iter: impl Iterator<Item = Result<T, E>>,
|
||||||
count: usize,
|
count: u64,
|
||||||
beginning: bool,
|
beginning: bool,
|
||||||
) -> VecDeque<T>
|
) -> UResult<VecDeque<T>>
|
||||||
where
|
where
|
||||||
E: fmt::Debug,
|
E: fmt::Debug,
|
||||||
{
|
{
|
||||||
|
@ -563,9 +577,13 @@ where
|
||||||
// GNU `tail` seems to index bytes and lines starting at 1, not
|
// GNU `tail` seems to index bytes and lines starting at 1, not
|
||||||
// at 0. It seems to treat `+0` and `+1` as the same thing.
|
// at 0. It seems to treat `+0` and `+1` as the same thing.
|
||||||
let i = count.max(1) - 1;
|
let i = count.max(1) - 1;
|
||||||
iter.skip(i as usize).map(|r| r.unwrap()).collect()
|
skip_u64(&mut iter, i);
|
||||||
|
Ok(iter.map(|r| r.unwrap()).collect())
|
||||||
} else {
|
} else {
|
||||||
RingBuffer::from_iter(iter.map(|r| r.unwrap()), count as usize).data
|
let count: usize = count
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| USimpleError::new(1, "Insufficient addressable memory"))?;
|
||||||
|
Ok(RingBuffer::from_iter(iter.map(|r| r.unwrap()), count).data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -576,14 +594,14 @@ fn unbounded_tail<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> UR
|
||||||
match settings.mode {
|
match settings.mode {
|
||||||
FilterMode::Lines(count, sep) => {
|
FilterMode::Lines(count, sep) => {
|
||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
for line in unbounded_tail_collect(lines(reader, sep), count, settings.beginning) {
|
for line in unbounded_tail_collect(lines(reader, sep), count, settings.beginning)? {
|
||||||
stdout
|
stdout
|
||||||
.write_all(&line)
|
.write_all(&line)
|
||||||
.map_err_context(|| String::from("IO error"))?;
|
.map_err_context(|| String::from("IO error"))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FilterMode::Bytes(count) => {
|
FilterMode::Bytes(count) => {
|
||||||
for byte in unbounded_tail_collect(reader.bytes(), count, settings.beginning) {
|
for byte in unbounded_tail_collect(reader.bytes(), count, settings.beginning)? {
|
||||||
if let Err(err) = stdout().write(&[byte]) {
|
if let Err(err) = stdout().write(&[byte]) {
|
||||||
return Err(USimpleError::new(1, err.to_string()));
|
return Err(USimpleError::new(1, err.to_string()));
|
||||||
}
|
}
|
||||||
|
@ -599,7 +617,7 @@ fn is_seekable<T: Seek>(file: &mut T) -> bool {
|
||||||
&& file.seek(SeekFrom::Start(0)).is_ok()
|
&& file.seek(SeekFrom::Start(0)).is_ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_num(src: &str) -> Result<(usize, bool), ParseSizeError> {
|
fn parse_num(src: &str) -> Result<(u64, bool), ParseSizeError> {
|
||||||
let mut size_string = src.trim();
|
let mut size_string = src.trim();
|
||||||
let mut starting_with = false;
|
let mut starting_with = false;
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,13 @@ use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use uucore::libc;
|
use uucore::libc;
|
||||||
|
|
||||||
static ABOUT: &str = "Copy standard input to each FILE, and also to standard output.";
|
static ABOUT: &str = "Copy standard input to each FILE, and also to standard output.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [FILE]...";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const APPEND: &str = "append";
|
pub const APPEND: &str = "append";
|
||||||
|
@ -34,15 +36,9 @@ struct Options {
|
||||||
files: Vec<String>,
|
files: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [FILE]...", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let options = Options {
|
let options = Options {
|
||||||
append: matches.is_present(options::APPEND),
|
append: matches.is_present(options::APPEND),
|
||||||
|
@ -63,6 +59,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.after_help("If a FILE is -, it refers to a file named - .")
|
.after_help("If a FILE is -, it refers to a file named - .")
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
|
@ -15,12 +15,14 @@ use parser::{parse, Operator, Symbol, UnaryOperator};
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
const USAGE: &str = "test EXPRESSION
|
const USAGE: &str = "\
|
||||||
or: test
|
{} EXPRESSION
|
||||||
or: [ EXPRESSION ]
|
{}
|
||||||
or: [ ]
|
[ EXPRESSION ]
|
||||||
or: [ OPTION";
|
[ ]
|
||||||
|
[ OPTION";
|
||||||
|
|
||||||
// We use after_help so that this comes after the usage string (it would come before if we used about)
|
// We use after_help so that this comes after the usage string (it would come before if we used about)
|
||||||
const AFTER_HELP: &str = "
|
const AFTER_HELP: &str = "
|
||||||
|
@ -92,7 +94,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.after_help(AFTER_HELP)
|
.after_help(AFTER_HELP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +111,7 @@ pub fn uumain(mut args: impl uucore::Args) -> UResult<()> {
|
||||||
App::new(binary_name)
|
App::new(binary_name)
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.override_usage(USAGE)
|
.override_usage(format_usage(USAGE))
|
||||||
.after_help(AFTER_HELP)
|
.after_help(AFTER_HELP)
|
||||||
// Disable printing of -h and -v as valid alternatives for --help and --version,
|
// Disable printing of -h and -v as valid alternatives for --help and --version,
|
||||||
// since we don't recognize -h and -v as help/version flags.
|
// since we don't recognize -h and -v as help/version flags.
|
||||||
|
|
|
@ -20,16 +20,10 @@ use uucore::display::Quotable;
|
||||||
use uucore::error::{UResult, USimpleError};
|
use uucore::error::{UResult, USimpleError};
|
||||||
use uucore::process::ChildExt;
|
use uucore::process::ChildExt;
|
||||||
use uucore::signals::{signal_by_name_or_value, signal_name_by_value};
|
use uucore::signals::{signal_by_name_or_value, signal_name_by_value};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::{format_usage, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION.";
|
static ABOUT: &str = "Start COMMAND, and kill it if still running after DURATION.";
|
||||||
|
const USAGE: &str = "{} [OPTION] DURATION COMMAND...";
|
||||||
fn usage() -> String {
|
|
||||||
format!(
|
|
||||||
"{0} [OPTION] DURATION COMMAND...",
|
|
||||||
uucore::execution_phrase()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ERR_EXIT_STATUS: i32 = 125;
|
const ERR_EXIT_STATUS: i32 = 125;
|
||||||
|
|
||||||
|
@ -106,9 +100,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let usage = usage();
|
let app = uu_app();
|
||||||
|
|
||||||
let app = uu_app().override_usage(&usage[..]);
|
|
||||||
|
|
||||||
let matches = app.get_matches_from(args);
|
let matches = app.get_matches_from(args);
|
||||||
|
|
||||||
|
@ -128,6 +120,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new("timeout")
|
App::new("timeout")
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::FOREGROUND)
|
Arg::new(options::FOREGROUND)
|
||||||
.long(options::FOREGROUND)
|
.long(options::FOREGROUND)
|
||||||
|
|
|
@ -19,8 +19,10 @@ use std::fs::{self, File};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::display::Quotable;
|
use uucore::display::Quotable;
|
||||||
use uucore::error::{FromIo, UError, UResult, USimpleError};
|
use uucore::error::{FromIo, UError, UResult, USimpleError};
|
||||||
|
use uucore::format_usage;
|
||||||
|
|
||||||
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
|
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
|
||||||
|
const USAGE: &str = "{} [OPTION]... [USER]";
|
||||||
pub mod options {
|
pub mod options {
|
||||||
// Both SOURCES and sources are needed as we need to be able to refer to the ArgGroup.
|
// Both SOURCES and sources are needed as we need to be able to refer to the ArgGroup.
|
||||||
pub static SOURCES: &str = "sources";
|
pub static SOURCES: &str = "sources";
|
||||||
|
@ -48,15 +50,9 @@ fn local_tm_to_filetime(tm: time::Tm) -> FileTime {
|
||||||
FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
|
FileTime::from_unix_time(ts.sec as i64, ts.nsec as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usage() -> String {
|
|
||||||
format!("{0} [OPTION]... [USER]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[uucore::main]
|
#[uucore::main]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let usage = usage();
|
let matches = uu_app().get_matches_from(args);
|
||||||
|
|
||||||
let matches = uu_app().override_usage(&usage[..]).get_matches_from(args);
|
|
||||||
|
|
||||||
let files = matches.values_of_os(ARG_FILES).ok_or_else(|| {
|
let files = matches.values_of_os(ARG_FILES).ok_or_else(|| {
|
||||||
USimpleError::new(
|
USimpleError::new(
|
||||||
|
@ -149,6 +145,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(options::ACCESS)
|
Arg::new(options::ACCESS)
|
||||||
|
|
|
@ -277,15 +277,21 @@ impl Sequence {
|
||||||
separated_pair(Self::parse_backslash_or_char, tag("*"), digit1),
|
separated_pair(Self::parse_backslash_or_char, tag("*"), digit1),
|
||||||
tag("]"),
|
tag("]"),
|
||||||
)(input)
|
)(input)
|
||||||
.map(|(l, (c, str))| {
|
.map(|(l, (c, cnt_str))| {
|
||||||
(
|
let result = if cnt_str.starts_with('0') {
|
||||||
l,
|
match usize::from_str_radix(cnt_str, 8) {
|
||||||
match usize::from_str_radix(str, 8) {
|
|
||||||
Ok(0) => Ok(Self::CharStar(c)),
|
Ok(0) => Ok(Self::CharStar(c)),
|
||||||
Ok(count) => Ok(Self::CharRepeat(c, count)),
|
Ok(count) => Ok(Self::CharRepeat(c, count)),
|
||||||
Err(_) => Err(BadSequence::InvalidRepeatCount(str.to_string())),
|
Err(_) => Err(BadSequence::InvalidRepeatCount(cnt_str.to_string())),
|
||||||
},
|
}
|
||||||
)
|
} else {
|
||||||
|
match cnt_str.parse::<usize>() {
|
||||||
|
Ok(0) => Ok(Self::CharStar(c)),
|
||||||
|
Ok(count) => Ok(Self::CharRepeat(c, count)),
|
||||||
|
Err(_) => Err(BadSequence::InvalidRepeatCount(cnt_str.to_string())),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
(l, result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,13 +15,14 @@ use clap::{crate_version, App, AppSettings, Arg};
|
||||||
use nom::AsBytes;
|
use nom::AsBytes;
|
||||||
use operation::{translate_input, Sequence, SqueezeOperation, TranslateOperation};
|
use operation::{translate_input, Sequence, SqueezeOperation, TranslateOperation};
|
||||||
use std::io::{stdin, stdout, BufReader, BufWriter};
|
use std::io::{stdin, stdout, BufReader, BufWriter};
|
||||||
use uucore::show;
|
use uucore::{format_usage, show};
|
||||||
|
|
||||||
use crate::operation::DeleteOperation;
|
use crate::operation::DeleteOperation;
|
||||||
use uucore::error::{UResult, USimpleError, UUsageError};
|
use uucore::error::{UResult, USimpleError, UUsageError};
|
||||||
use uucore::{display::Quotable, InvalidEncodingHandling};
|
use uucore::{display::Quotable, InvalidEncodingHandling};
|
||||||
|
|
||||||
static ABOUT: &str = "translate or delete characters";
|
static ABOUT: &str = "translate or delete characters";
|
||||||
|
const USAGE: &str = "{} [OPTION]... SET1 [SET2]";
|
||||||
|
|
||||||
mod options {
|
mod options {
|
||||||
pub const COMPLEMENT: &str = "complement";
|
pub const COMPLEMENT: &str = "complement";
|
||||||
|
@ -31,10 +32,6 @@ mod options {
|
||||||
pub const SETS: &str = "sets";
|
pub const SETS: &str = "sets";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_usage() -> String {
|
|
||||||
format!("{} [OPTION]... SET1 [SET2]", uucore::execution_phrase())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_long_usage() -> String {
|
fn get_long_usage() -> String {
|
||||||
"Translate, squeeze, and/or delete characters from standard input, \
|
"Translate, squeeze, and/or delete characters from standard input, \
|
||||||
writing to standard output."
|
writing to standard output."
|
||||||
|
@ -47,13 +44,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
.collect_str(InvalidEncodingHandling::ConvertLossy)
|
||||||
.accept_any();
|
.accept_any();
|
||||||
|
|
||||||
let usage = get_usage();
|
|
||||||
let after_help = get_long_usage();
|
let after_help = get_long_usage();
|
||||||
|
|
||||||
let matches = uu_app()
|
let matches = uu_app().after_help(&after_help[..]).get_matches_from(args);
|
||||||
.override_usage(&usage[..])
|
|
||||||
.after_help(&after_help[..])
|
|
||||||
.get_matches_from(args);
|
|
||||||
|
|
||||||
let delete_flag = matches.is_present(options::DELETE);
|
let delete_flag = matches.is_present(options::DELETE);
|
||||||
let complement_flag = matches.is_present(options::COMPLEMENT);
|
let complement_flag = matches.is_present(options::COMPLEMENT);
|
||||||
|
@ -148,6 +141,7 @@ pub fn uu_app<'a>() -> App<'a> {
|
||||||
App::new(uucore::util_name())
|
App::new(uucore::util_name())
|
||||||
.version(crate_version!())
|
.version(crate_version!())
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
|
.override_usage(format_usage(USAGE))
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.setting(AppSettings::InferLongArgs)
|
.setting(AppSettings::InferLongArgs)
|
||||||
.arg(
|
.arg(
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue