1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-08-03 06:27:45 +00:00

create empty repository for 'uucore'

This commit is contained in:
Roy Ivy III 2015-11-23 00:00:01 -05:00
parent fa34096bb8
commit 67b07eaaa9
334 changed files with 0 additions and 25603 deletions

View file

@ -1,2 +0,0 @@
CONFIG_FEATURE_FANCY_HEAD=y
CONFIG_UNICODE_SUPPORT=y

14
.gitignore vendored
View file

@ -1,14 +0,0 @@
/src/*/gen_table
/build/
/target/
/tmp/
/busybox/
/deps/regex/
/deps/rust-crypto/
/deps/target/
/deps/time/
*~
.*.swp
.*.swo
Cargo.lock
lib*.a

View file

@ -1,15 +0,0 @@
language: rust
rust:
- stable
- beta
- nightly
sudo: false
script:
- make
- make test
- make build-check
- make test-check
matrix:
allow_failures:
- rust: stable
- rust: beta

View file

@ -1,164 +0,0 @@
[package]
name = "uutils"
version = "0.0.1"
authors = []
build = "build.rs"
[features]
default = ["all"]
all = [
"base64",
"basename",
"cat",
"chmod",
"chroot",
"cksum",
"comm",
"cp",
"cut",
"dirname",
"du",
"echo",
"env",
"expand",
"expr",
"factor",
"false",
"fmt",
"fold",
"groups",
"hashsum",
"head",
"hostid",
"hostname",
"id",
"kill",
"link",
"ln",
"logname",
"mkdir",
"mkfifo",
"mv",
"nice",
"nl",
"nohup",
"nproc",
"od",
"paste",
"printenv",
"ptx",
"pwd",
"readlink",
"realpath",
"relpath",
"rm",
"rmdir",
"seq",
"shuf",
"sleep",
"sort",
"split",
"sum",
"sync",
"tac",
"tail",
"tee",
"test",
"timeout",
"touch",
"tr",
"true",
"truncate",
"tsort",
"tty",
"uname",
"unexpand",
"uniq",
"unlink",
"uptime",
"users",
"wc",
"whoami",
"yes",
]
[dependencies]
base64 = { optional=true, path="src/base64" }
basename = { optional=true, path="src/basename" }
cat = { optional=true, path="src/cat" }
chmod = { optional=true, path="src/chmod" }
chroot = { optional=true, path="src/chroot" }
cksum = { optional=true, path="src/cksum" }
comm = { optional=true, path="src/comm" }
cp = { optional=true, path="src/cp" }
cut = { optional=true, path="src/cut" }
dirname = { optional=true, path="src/dirname" }
du = { optional=true, path="src/du" }
echo = { optional=true, path="src/echo" }
env = { optional=true, path="src/env" }
expand = { optional=true, path="src/expand" }
expr = { optional=true, path="src/expr" }
factor = { optional=true, path="src/factor" }
false = { optional=true, path="src/false" }
fmt = { optional=true, path="src/fmt" }
fold = { optional=true, path="src/fold" }
groups = { optional=true, path="src/groups" }
hashsum = { optional=true, path="src/hashsum" }
head = { optional=true, path="src/head" }
hostid = { optional=true, path="src/hostid" }
hostname = { optional=true, path="src/hostname" }
id = { optional=true, path="src/id" }
kill = { optional=true, path="src/kill" }
link = { optional=true, path="src/link" }
ln = { optional=true, path="src/ln" }
logname = { optional=true, path="src/logname" }
mkdir = { optional=true, path="src/mkdir" }
mkfifo = { optional=true, path="src/mkfifo" }
mv = { optional=true, path="src/mv" }
nice = { optional=true, path="src/nice" }
nl = { optional=true, path="src/nl" }
nohup = { optional=true, path="src/nohup" }
nproc = { optional=true, path="src/nproc" }
od = { optional=true, path="src/od" }
paste = { optional=true, path="src/paste" }
printenv = { optional=true, path="src/printenv" }
ptx = { optional=true, path="src/ptx" }
pwd = { optional=true, path="src/pwd" }
readlink = { optional=true, path="src/readlink" }
realpath = { optional=true, path="src/realpath" }
relpath = { optional=true, path="src/relpath" }
rm = { optional=true, path="src/rm" }
rmdir = { optional=true, path="src/rmdir" }
seq = { optional=true, path="src/seq" }
shuf = { optional=true, path="src/shuf" }
sleep = { optional=true, path="src/sleep" }
sort = { optional=true, path="src/sort" }
split = { optional=true, path="src/split" }
sum = { optional=true, path="src/sum" }
sync = { optional=true, path="src/sync" }
tac = { optional=true, path="src/tac" }
tail = { optional=true, path="src/tail" }
tee = { optional=true, path="src/tee" }
test = { optional=true, path="src/test" }
timeout = { optional=true, path="src/timeout" }
touch = { optional=true, path="src/touch" }
tr = { optional=true, path="src/tr" }
true = { optional=true, path="src/true" }
truncate = { optional=true, path="src/truncate" }
tsort = { optional=true, path="src/tsort" }
tty = { optional=true, path="src/tty" }
uname = { optional=true, path="src/uname" }
unexpand = { optional=true, path="src/unexpand" }
uniq = { optional=true, path="src/uniq" }
unlink = { optional=true, path="src/unlink" }
uptime = { optional=true, path="src/uptime" }
users = { optional=true, path="src/users" }
wc = { optional=true, path="src/wc" }
whoami = { optional=true, path="src/whoami" }
yes = { optional=true, path="src/yes" }
[[bin]]
name="uutils"
path="src/uutils/uutils_cargo.rs"

18
LICENSE
View file

@ -1,18 +0,0 @@
Copyright (c) Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

442
Makefile
View file

@ -1,442 +0,0 @@
# Config options
ENABLE_LTO ?= n
ENABLE_STRIP ?= n
# Binaries
RUSTC ?= rustc
CARGO ?= cargo
CC ?= gcc
RM := rm
# Install directories
PREFIX ?= /usr/local
BINDIR ?= /bin
LIBDIR ?= /lib
# This won't support any directory with spaces in its name, but you can just
# make a symlink without spaces that points to the directory.
BASEDIR ?= $(shell pwd)
SRCDIR := $(BASEDIR)/src
BUILDDIR := $(BASEDIR)/build
TESTDIR := $(BASEDIR)/test
TEMPDIR := $(BASEDIR)/tmp
# Flags
RUSTCFLAGS := -O
RMFLAGS :=
RUSTCLIBFLAGS := $(RUSTCFLAGS) -L $(BUILDDIR)/
RUSTCTESTFLAGS := $(RUSTCFLAGS)
# Handle config setup
ifeq ($(ENABLE_LTO),y)
RUSTCBINFLAGS := $(RUSTCLIBFLAGS) -C lto
else
RUSTCBINFLAGS := $(RUSTCLIBFLAGS)
endif
ifneq ($(ENABLE_STRIP),y)
ENABLE_STRIP :=
endif
# Possible programs
PROGS := \
base64 \
basename \
cat \
chmod \
cksum \
comm \
cp \
cut \
dirname \
echo \
env \
expand \
expr \
factor \
false \
fmt \
fold \
link \
hashsum \
ln \
mkdir \
nl \
nproc \
od \
paste \
printenv \
ptx \
pwd \
readlink \
realpath \
relpath \
rm \
rmdir \
sleep \
split \
seq \
shuf \
sort \
sum \
sync \
tac \
tee \
test \
tr \
true \
truncate \
tsort \
unexpand \
uniq \
wc \
yes \
head \
tail \
whoami
UNIX_PROGS := \
chroot \
du \
groups \
hostid \
hostname \
id \
kill \
logname \
mkfifo \
mv \
nice \
nohup \
stdbuf \
timeout \
touch \
tty \
uname \
unlink \
uptime \
users
ifneq ($(OS),Windows_NT)
PROGS := $(PROGS) $(UNIX_PROGS)
endif
ALIASES := \
hashsum:md5sum \
hashsum:sha1sum \
hashsum:sha224sum \
hashsum:sha256sum \
hashsum:sha384sum \
hashsum:sha512sum
BUILD ?= $(PROGS)
# Output names
EXES := \
$(sort $(filter $(BUILD),$(filter-out $(DONT_BUILD),$(PROGS))))
CRATE_RLIBS :=
INSTALL ?= $(EXES)
INSTALLEES := \
$(filter $(INSTALL),$(filter-out $(DONT_INSTALL),$(EXES) uutils))
# Shared library extension
SYSTEM := $(shell uname)
DYLIB_EXT :=
ifeq ($(SYSTEM),Linux)
DYLIB_EXT := so
DYLIB_FLAGS := -shared
endif
ifeq ($(SYSTEM),Darwin)
DYLIB_EXT := dylib
DYLIB_FLAGS := -dynamiclib -undefined dynamic_lookup
endif
# Libaries to install
LIBS :=
ifneq (,$(findstring stdbuf, $(INSTALLEES)))
LIBS += libstdbuf.$(DYLIB_EXT)
endif
# Programs with usable tests
TEST_PROGS := \
base64 \
basename \
cat \
cksum \
cp \
cut \
env \
dirname \
echo \
factor \
false \
fold \
hashsum \
head \
link \
ln \
mkdir \
mv \
nl \
paste \
ptx \
pwd \
readlink \
realpath \
rm \
rmdir \
seq \
sort \
split \
stdbuf \
sum \
tac \
test \
touch \
tr \
true \
truncate \
tsort \
unlink \
unexpand \
wc
TEST ?= $(TEST_PROGS)
TESTS := \
$(filter $(TEST),$(filter-out $(DONT_TEST),$(filter $(BUILD),$(filter-out $(DONT_BUILD),$(TEST_PROGS)))))
# figure out what dependencies we need based on which programs we're building
define DEP_INCLUDE
-include $(SRCDIR)/$(1)/deps.mk
endef
# we always depend on libc because common/util does
# we also depend on getopts since all utilities support command-line arguments
DEPLIBS := libc getopts
DEPPLUGS :=
# now, add in deps in src/utilname/deps.mk
# if we're testing, only consider the TESTS variable,
# otherwise consider the EXES variable
ifeq ($(MAKECMDGOALS),test)
$(foreach build,$(TESTS),$(eval $(call DEP_INCLUDE,$(build))))
else
$(foreach build,$(sort $(TESTS) $(EXES)),$(eval $(call DEP_INCLUDE,$(build))))
endif
# uniqify deps
DEPLIBS := $(sort $(DEPLIBS))
DEPPLUGS := $(sort $(DEPPLUGS))
# build --extern commandline for rustc
DEP_EXTERN := $(foreach lib,$(subst -,_,$(DEPLIBS)),--extern $(lib)=$(BUILDDIR)/lib$(lib).rlib)
DEP_EXTERN += $(foreach plug,$(subst -,_,$(DEPPLUGS)),--extern $(plug)=$(BUILDDIR)/lib$(plug).$(DYLIB_EXT))
# Setup for building crates
define BUILD_SETUP
X := $(shell $(RUSTC) --print file-names --crate-type rlib $(SRCDIR)/$(1)/$(1).rs)
$(1)_RLIB := $$(X)
CRATE_RLIBS += $$(X)
endef
$(foreach crate,$(EXES),$(eval $(call BUILD_SETUP,$(crate))))
# Utils stuff
EXES_PATHS := $(addprefix $(BUILDDIR)/,$(EXES))
RLIB_PATHS := $(addprefix $(BUILDDIR)/,$(CRATE_RLIBS))
command = sh -c '$(1)'
RESERVED_EXTERNS := --extern uufalse=$(BUILDDIR)/libfalse.rlib --extern uutrue=$(BUILDDIR)/libtrue.rlib --extern uutest=$(BUILDDIR)/libtest.rlib
# Main exe build rule
define EXE_BUILD
$(BUILDDIR)/gen/$(1).rs: $(BUILDDIR)/mkmain
$(BUILDDIR)/mkmain $(1) $$@
$(BUILDDIR)/$(1): $(BUILDDIR)/gen/$(1).rs $(BUILDDIR)/$($(1)_RLIB) | $(BUILDDIR) deps
$(RUSTC) $(RUSTCBINFLAGS) $(RESERVED_EXTERNS) -o $$@ $$<
$(if $(ENABLE_STRIP),strip $$@,)
endef
# GRRR rust-crypto makes a crate called "crypto".
# This should NOT be allowed by crates.io. GRRRR.
define DEP_BUILD
DEP_$(1):
ifeq ($(1),crypto)
cd $(BASEDIR)/deps && $(CARGO) build --package rust-crypto --release
else ifeq ($(1),kernel32)
cd $(BASEDIR)/deps && $(CARGO) build --package kernel32-sys --release
else ifeq ($(1),advapi32)
cd $(BASEDIR)/deps && $(CARGO) build --package advapi32-sys --release
else
cd $(BASEDIR)/deps && $(CARGO) build --package $(1) --release
endif
endef
define CRATE_BUILD
-include $(BUILDDIR)/$(1).d
$(BUILDDIR)/$($(1)_RLIB): $(SRCDIR)/$(1)/$(1).rs | $(BUILDDIR) deps
$(RUSTC) $(RUSTCLIBFLAGS) $(DEP_EXTERN) --crate-type rlib --emit link,dep-info $$< --out-dir $(BUILDDIR)
endef
# Aliases build rule
ALIAS_SOURCE = $(firstword $(subst :, ,$(1)))
ALIAS_TARGET = $(word 2,$(subst :, ,$(1)))
define MAKE_ALIAS
ifneq ($(ALIAS_TARGET,$(1)),)
all: $(BUILDDIR)/$(call ALIAS_TARGET,$(1))
$(BUILDDIR)/$(call ALIAS_TARGET,$(1)): $(BUILDDIR)/$(call ALIAS_SOURCE,$(1))
$(call command,install $$@ $$<)
endif
endef
# Test exe built rules
define TEST_BUILD
test_$(1): $(BUILDDIR)/$(1) $(TEMPDIR)/$(1)/$(1)_test
$(call command,cp $(BUILDDIR)/$(1) $(TEMPDIR)/$(1) && cd $(TEMPDIR)/$(1) && $(TEMPDIR)/$(1)/$(1)_test)
$(TEMPDIR)/$(1)/$(1)_test: $(TESTDIR)/$(1).rs | $(TEMPDIR)/$(1)
$(call command,$(RUSTC) $(RUSTCTESTFLAGS) $(DEP_EXTERN) --test -o $$@ $$<)
$(TEMPDIR)/$(1): | $(TEMPDIR)
$(call command,cp -r $(TESTDIR)/fixtures/$(1) $$@ || mkdir $$@)
endef
# Main rules
all: $(EXES_PATHS) $(BUILDDIR)/uutils
# Creating necessary rules for each targets
$(foreach crate,$(EXES),$(eval $(call CRATE_BUILD,$(crate))))
$(foreach exe,$(EXES),$(eval $(call EXE_BUILD,$(exe))))
$(foreach alias,$(ALIASES),$(eval $(call MAKE_ALIAS,$(alias))))
$(foreach test,$(TESTS),$(eval $(call TEST_BUILD,$(test))))
$(foreach dep,$(sort $(DEPLIBS) $(DEPPLUGS)),$(eval $(call DEP_BUILD,$(dep))))
-include $(BUILDDIR)/uutils.d
$(BUILDDIR)/uutils: $(SRCDIR)/uutils/uutils.rs $(BUILDDIR)/mkuutils $(RLIB_PATHS)
$(BUILDDIR)/mkuutils $(BUILDDIR)/gen/uutils.rs $(EXES)
$(RUSTC) $(RUSTCBINFLAGS) $(RESERVED_EXTERNS) --emit link,dep-info $(BUILDDIR)/gen/uutils.rs --out-dir $(BUILDDIR)
$(if $(ENABLE_STRIP),strip $@)
# Library for stdbuf
$(BUILDDIR)/libstdbuf.$(DYLIB_EXT): $(SRCDIR)/stdbuf/libstdbuf.rs $(SRCDIR)/stdbuf/libstdbuf.c $(SRCDIR)/stdbuf/libstdbuf.h | $(BUILDDIR)
cd $(SRCDIR)/stdbuf && \
$(RUSTC) libstdbuf.rs --extern libc=$(BUILDDIR)/liblibc.rlib && \
$(CC) -c -Wall -Werror -fPIC libstdbuf.c && \
$(CC) $(DYLIB_FLAGS) -o libstdbuf.$(DYLIB_EXT) liblibstdbuf.a libstdbuf.o && \
mv *.$(DYLIB_EXT) $(BUILDDIR) && $(RM) *.o && $(RM) *.a
$(BUILDDIR)/stdbuf: $(BUILDDIR)/libstdbuf.$(DYLIB_EXT)
deps: $(BUILDDIR) $(SRCDIR)/cksum/crc_table.rs $(addprefix DEP_,$(DEPLIBS) $(DEPPLUGS))
$(foreach lib,$(subst -,_,$(DEPLIBS)),$(shell cp $(BASEDIR)/deps/target/release/deps/lib$(lib)-*.rlib $(BUILDDIR)/lib$(lib).rlib))
$(foreach plug,$(subst -,_,$(DEPPLUGS)),$(shell cp $(BASEDIR)/deps/target/release/deps/lib$(plug)-*.$(DYLIB_EXT) $(BUILDDIR)/lib$(plug).$(DYLIB_EXT)))
$(BUILDDIR)/mkmain: mkmain.rs | $(BUILDDIR)
$(RUSTC) $(RUSTCFLAGS) $< -o $@
$(BUILDDIR)/mkuutils: mkuutils.rs | $(BUILDDIR)
$(RUSTC) $(RUSTCFLAGS) $< -o $@
$(SRCDIR)/cksum/crc_table.rs: $(SRCDIR)/cksum/gen_table.rs
cd $(SRCDIR)/cksum && $(RUSTC) $(RUSTCBINFLAGS) gen_table.rs && ./gen_table && $(RM) gen_table
$(SRCDIR)/factor/prime_table.rs: $(SRCDIR)/factor/gen_table.rs
cd $(SRCDIR)/factor && $(RUSTC) $(RUSTCBINFLAGS) gen_table.rs && ./gen_table > $@ && $(RM) gen_table
crates:
echo $(EXES)
test: $(TEMPDIR) $(addprefix test_,$(TESTS))
$(RM) -rf $(TEMPDIR)
clean:
$(RM) -rf $(BUILDDIR) $(TEMPDIR)
distclean: clean
cd $(BASEDIR)/deps && $(CARGO) clean && $(CARGO) update
$(BUILDDIR):
mkdir -p $(BUILDDIR)/gen
$(TEMPDIR):
$(RM) -rf $(TEMPDIR)
mkdir $(TEMPDIR)
install: $(addprefix $(BUILDDIR)/,$(INSTALLEES))
mkdir -p $(DESTDIR)$(PREFIX)$(BINDIR)
for prog in $(INSTALLEES); do \
install $(BUILDDIR)/$$prog $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX)$$prog; \
done
mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR)
for lib in $(LIBS); do \
install $(BUILDDIR)/$$lib $(DESTDIR)$(PREFIX)$(LIBDIR)/$$lib; \
done
# TODO: figure out if there is way for prefixes to work with the symlinks
install-multicall: $(BUILDDIR)/uutils
mkdir -p $(DESTDIR)$(PREFIX)$(BINDIR)
install $(BUILDDIR)/uutils $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX)uutils
cd $(DESTDIR)$(PREFIX)$(BINDIR)
for prog in $(INSTALLEES); do \
ln -s $(PROG_PREFIX)uutils $$prog; \
done
mkdir -p $(DESTDIR)$(PREFIX)$(LIBDIR)
for lib in $(LIBS); do \
install $(BUILDDIR)/$$lib $(DESTDIR)$(PREFIX)$(LIBDIR)/$$lib; \
done
uninstall:
rm -f $(addprefix $(DESTDIR)$(PREFIX)$(BINDIR)/$(PROG_PREFIX),$(PROGS))
rm -f $(addprefix $(DESTDIR)$(PREFIX)$(LIBDIR)/,$(LIBS))
uninstall-multicall:
rm -f $(addprefix $(DESTDIR)$(PREFIX)$(BINDIR)/,$(PROGS) $(PROG_PREFIX)uutils)
rm -f $(addprefix $(DESTDIR)$(PREFIX)$(LIBDIR)/,$(LIBS))
# Test under the busybox testsuite
$(BUILDDIR)/busybox: $(BUILDDIR)/uutils
rm -f $(BUILDDIR)/busybox
ln -s $(BUILDDIR)/uutils $(BUILDDIR)/busybox
# This is a busybox-specific config file their test suite wants to parse.
$(BUILDDIR)/.config: $(BASEDIR)/.busybox-config $(BUILDDIR)/uutils
cp $< $@
ifeq ($(BUSYBOX_SRC),)
busytest:
@echo
@echo "To run \`busytest\` set BUSYBOX_SRC to the directory of the compiled busybox source code."
@echo "Optionally set RUNTEST_ARGS to arguments to pass to the busybox \`runtest\` program."
@echo
@false
else
busytest: $(BUILDDIR)/busybox $(BUILDDIR)/.config
(cd $(BUSYBOX_SRC)/testsuite && bindir=$(BUILDDIR) ./runtest $(RUNTEST_ARGS))
endif
# This rule will build each program, ignore all output, and return pass
# or fail depending on whether the build has errors.
build-check:
@for prog in $(sort $(PROGS)); do \
make BUILD="$$prog" >/dev/null 2>&1; status=$$?; \
if [ $$status -eq 0 ]; \
then printf "%-10s\t\033[1;32mpass\033[00;m\n" $$prog; \
else printf "%-10s\t\033[1;31mfail\033[00;m\n" $$prog; \
fi; \
done
# This rule will test each program, ignore all output, and return pass
# or fail depending on whether the test has errors.
test-check:
@for prog in $(sort $(TEST_PROGS)); do \
make TEST="$$prog" test >/dev/null 2>&1; status=$$?; \
if [ $$status -eq 0 ]; \
then printf "%-10s\t\033[1;32mpass\033[00;m\n" $$prog; \
else printf "%-10s\t\033[1;31mfail\033[00;m\n" $$prog; \
fi; \
done
.PHONY: $(TEMPDIR) all deps test distclean clean busytest install uninstall

183
README.md
View file

@ -1,183 +0,0 @@
uutils coreutils
================
[![Build Status](https://api.travis-ci.org/uutils/coreutils.svg?branch=master)](https://travis-ci.org/uutils/coreutils)
[![Build status](https://ci.appveyor.com/api/projects/status/xhlsa439de5ogodp?svg=true)](https://ci.appveyor.com/project/jbcrail/coreutils-o0l0r)
uutils is an attempt at writing universal (as in cross-platform) CLI
utils in [Rust](http://www.rust-lang.org). This repo is to aggregate the GNU
coreutils rewrites.
Why?
----
Many GNU, Linux and other utils are pretty awesome, and obviously
[some](http://gnuwin32.sourceforge.net) [effort](http://unxutils.sourceforge.net)
has been spent in the past to port them to Windows. However, those projects
are either old, abandoned, hosted on CVS, written in platform-specific C, etc.
Rust provides a good, platform-agnostic way of writing systems utils that are easy
to compile anywhere, and this is as good a way as any to try and learn it.
Build Instructions
------------------
NOTE: This currently requires the most current nightly build.
To simply build all available utilities:
```
make
```
(on Windows use [MinGW/MSYS](http://www.mingw.org/wiki/MSYS) or `Cygwin` make and make sure you have `rustc` in `PATH`)
To build all but a few of the available utilities:
```
make DONT_BUILD='UTILITY_1 UTILITY_2'
```
To build only a few of the available utilities:
```
make BUILD='UTILITY_1 UTILITY_2'
```
To build with LTO and stripping:
```
make ENABLE_LTO=y ENABLE_STRIP=y
```
To check all available utilities for build errors:
```
make build-check
```
To check all available tests for errors:
```
make test-check
```
Installation Instructions
-------------------------
To install all available utilities:
```
make install
```
To install all but a few of the available utilities:
```
make DONT_INSTALL='UTILITY_1 UTILITY_2' install
```
To install only a few of the available utilities:
```
make INSTALL='UTILITY_1 UTILITY_2' install
```
To install every program with a prefix:
```
make PROG_PREFIX=PREFIX_GOES_HERE install
```
To install the multicall binary:
```
make install-multicall
```
Uninstallation Instructions
---------------------------
To uninstall all utilities:
```
make uninstall
```
To uninstall every program with a set prefix:
```
make PROG_PREFIX=PREFIX_GOES_HERE uninstall
```
To uninstall the multicall binary:
```
make uninstall-multicall
```
Test Instructions
-----------------
To simply test all available utilities:
```
make test
```
To test all but a few of the available utilities:
```
make DONT_TEST='UTILITY_1 UTILITY_2' test
```
To test only a few of the available utilities:
```
make TEST='UTILITY_1 UTILITY_2' test
```
Contribute
----------
Contributions are very welcome, and should target Rust's master branch until
Rust 1.0 is released. You may *claim* an item on the to-do list by following
these steps:
1. Open an issue named "Implement [the utility of your choice]", e.g. "Implement ls"
2. State that you are working on this utility.
3. Develop the utility.
4. Add the reference to your utility into uutils/uutils.rs (required for multibinary).
5. Remove utility from the to-do list on this README.
6. Submit a pull request and close the issue.
The steps above imply that, before starting to work on a utility, you should search the issues to make sure no one else is working on it.
To do
-----
- chcon
- chgrp
- chmod (mostly done, just needs verbosity options)
- chown
- copy
- cp (not much done)
- csplit
- date
- dd
- df
- dircolors
- expr
- getlimits
- install
- join
- ls
- mknod
- mktemp
- mv (almost done, one more option)
- numfmt
- od (in progress, needs lots of work)
- pathchk
- pinky
- pr
- printf
- remove
- runcon
- setuidgid
- shred
- sort (a couple of options implemented)
- split (a couple of missing options)
- stat
- stty
- tail (not all features implemented)
- test (not all features implemented)
- uniq (a couple of missing options)
- who
License
-------
uutils is licensed under the MIT License - see the `LICENSE` file for details

View file

@ -1,33 +0,0 @@
platform:
- x64
environment:
global:
MSYS2_BASEVER: 20150512
MSYS2_ARCH: x86_64
MBASH: msys64\usr\bin\sh --login -c
matrix:
- TARGET: i686-pc-windows-gnu
install:
- appveyor DownloadFile "http://kent.dl.sourceforge.net/project/msys2/Base/%MSYS2_ARCH%/msys2-base-%MSYS2_ARCH%-%MSYS2_BASEVER%.tar.xz" -FileName "msys2.tar.xz"
- 7z x msys2.tar.xz
- 7z x msys2.tar > NUL
- call %MBASH% ""
- call %MBASH% "for i in {1..3}; do pacman --noconfirm -Suy mingw-w64-%MSYS2_ARCH%-{ragel,freetype,icu,gettext} libtool pkg-config gcc make autoconf automake perl && break || sleep 15; done"
- ps: Start-FileDownload "https://static.rust-lang.org/dist/rust-nightly-${env:TARGET}.exe"
- rust-nightly-%TARGET%.exe /VERYSILENT /NORESTART /DIR="C:\Program Files (x86)\Rust"
- call "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" amd64
- SET PATH=%PATH%;C:\Program Files (x86)\Rust\bin
- SET PATH=%PATH%;C:\MinGW\bin
- rustc -V
- cargo -V
build_script:
- call %MBASH% "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; exec 0</dev/null; make"
- call %MBASH% "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; exec 0</dev/null; make build-check"
test_script:
- call %MBASH% "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; exec 0</dev/null; make test"
- call %MBASH% "cd $APPVEYOR_BUILD_FOLDER; PATH=$PATH:/mingw64/bin:/mingw32/bin; exec 0</dev/null; make test-check"

View file

@ -1,61 +0,0 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
pub fn main() {
let feature_prefix = "CARGO_FEATURE_";
let out_dir = env::var("OUT_DIR").unwrap();
let mut crates = Vec::new();
for (key, val) in env::vars() {
if val == "1" && key.starts_with(feature_prefix) {
let krate = key[feature_prefix.len()..].to_lowercase();
match krate.as_ref() {
"default" => continue,
"all" => continue,
_ => {},
}
crates.push(krate.to_string());
}
}
crates.sort();
let mut cf = File::create(Path::new(&out_dir).join("uutils_crates.rs")).unwrap();
let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap();
mf.write_all("
type UtilityMap = HashMap<&'static str, fn(Vec<String>) -> i32>;
fn util_map() -> UtilityMap {
let mut map: UtilityMap = HashMap::new();\n".as_bytes()).unwrap();
for krate in crates {
match krate.as_ref() {
"false" => continue,
"true" => continue,
_ => cf.write_all(format!("extern crate {krate} as uu{krate};\n", krate=krate).as_bytes()).unwrap(),
}
match krate.as_ref() {
"hashsum" => {
mf.write_all("map.insert(\"hashsum\", uuhashsum::uumain);
map.insert(\"md5sum\", uuhashsum::uumain);
map.insert(\"sha1sum\", uuhashsum::uumain);
map.insert(\"sha224sum\", uuhashsum::uumain);
map.insert(\"sha256sum\", uuhashsum::uumain);
map.insert(\"sha384sum\", uuhashsum::uumain);
map.insert(\"sha512sum\", uuhashsum::uumain);\n".as_bytes()).unwrap();
},
"false" =>
mf.write_all("fn uufalse(_: Vec<String>) -> i32 { 1 }
map.insert(\"false\", uufalse as fn(Vec<String>) -> i32);\n".as_bytes()).unwrap(),
"true" =>
mf.write_all("fn uutrue(_: Vec<String>) -> i32 { 0 }
map.insert(\"true\", uutrue as fn(Vec<String>) -> i32);\n".as_bytes()).unwrap(),
_ =>
mf.write_all(format!("map.insert(\"{krate}\", uu{krate}::uumain as fn(Vec<String>) -> i32);\n", krate= krate).as_bytes()).unwrap(),
}
}
mf.write_all("map
}\n".as_bytes()).unwrap();
cf.flush().unwrap();
mf.flush().unwrap();
}

25
deps/Cargo.toml vendored
View file

@ -1,25 +0,0 @@
[project]
name = "deps"
version = "0.0.0"
[lib]
name = "null"
[dependencies]
libc = "0.1"
getopts = "0.2"
bit-vec = "0.4"
bit-set = "0.2"
vec_map = "0.3"
num_cpus = "0.2"
rand = "0.3"
regex = "0.1"
rust-crypto = "0.2"
rustc-serialize = "0.3"
time = "0.1"
unicode-width = "0.1"
winapi = "0.2"
advapi32-sys = "0.1"
kernel32-sys = "0.1"
walker = "^1.0"
filetime = "0.1"

View file

@ -1,49 +0,0 @@
use std::env;
use std::io::Write;
use std::fs::File;
static TEMPLATE: &'static str = "\
extern crate @UTIL_CRATE@ as uu@UTIL_CRATE@;
use std::io::Write;
use uu@UTIL_CRATE@::uumain;
fn main() {
let code = uumain(std::env::args().collect());
// Since stdout is line-buffered by default, we need to ensure any pending
// writes are flushed before exiting. Ideally, this should be enforced by
// each utility.
//
// See: https://github.com/rust-lang/rust/issues/23818
//
std::io::stdout().flush().unwrap();
std::process::exit(code);
}
";
fn main() {
let args : Vec<String> = env::args().collect();
if args.len() != 3 {
println!("usage: mkbuild <crate> <outfile>");
std::process::exit(1);
}
let crat = match &args[1][..] {
"false" => "uufalse",
"test" => "uutest",
"true" => "uutrue",
_ => &args[1][..],
};
let outfile = &args[2][..];
let main = TEMPLATE.replace("@UTIL_CRATE@", crat);
match File::create(outfile) {
Ok(mut out) => match out.write_all(main.as_bytes()) {
Err(e) => panic!("{}", e),
_ => (),
},
Err(e) => panic!("{}", e),
}
}

View file

@ -1,63 +0,0 @@
use std::env;
use std::fs::File;
use std::io::{Read, Write};
fn main() {
let args : Vec<String> = env::args().collect();
if args.len() < 3 {
println!("usage: mkuutils <outfile> <crates>");
std::process::exit(1);
}
let mut crates = String::new();
let mut util_map = String::new();
let mut hashsum = false;
for prog in args[2..].iter() {
match &prog[..] {
"hashsum" | "md5sum" | "sha1sum" | "sha224sum" | "sha256sum" | "sha384sum" | "sha512sum" => {
if !hashsum {
crates.push_str("extern crate hashsum;\n");
util_map.push_str("map.insert(\"hashsum\", hashsum::uumain);\n");
util_map.push_str("map.insert(\"md5sum\", hashsum::uumain);\n");
util_map.push_str("map.insert(\"sha1sum\", hashsum::uumain);\n");
util_map.push_str("map.insert(\"sha224sum\", hashsum::uumain);\n");
util_map.push_str("map.insert(\"sha256sum\", hashsum::uumain);\n");
util_map.push_str("map.insert(\"sha384sum\", hashsum::uumain);\n");
util_map.push_str("map.insert(\"sha512sum\", hashsum::uumain);\n");
hashsum = true;
}
},
"true" => {
util_map.push_str("fn uutrue(_: Vec<String>) -> i32 { 0 }\n");
util_map.push_str("map.insert(\"true\", uutrue as fn(Vec<String>) -> i32);\n");
},
"false" => {
util_map.push_str("fn uufalse(_: Vec<String>) -> i32 { 1 }\n");
util_map.push_str("map.insert(\"false\", uufalse as fn(Vec<String>) -> i32);\n");
},
_ => {
if prog == "test" {
crates.push_str(&(format!("extern crate uu{0} as uu{0};\n", prog))[..]);
} else {
crates.push_str(&(format!("extern crate {0} as uu{0};\n", prog))[..]);
}
util_map.push_str(&(format!("map.insert(\"{prog}\", uu{prog}::uumain as fn(Vec<String>) -> i32);\n", prog = prog))[..]);
}
}
}
let outfile = &(args[1])[..];
// XXX: this all just assumes that the IO works correctly
let mut out = File::create(outfile).unwrap();
let mut input = File::open("src/uutils/uutils.rs").unwrap();
let mut template = String::new();
input.read_to_string(&mut template).unwrap();
let template = template;
let main = template.replace("@CRATES@", &crates[..]).replace("@UTIL_MAP@", &util_map[..]);
match out.write_all(main.as_bytes()) {
Err(e) => panic!("{}", e),
_ => (),
}
}

View file

@ -1,13 +0,0 @@
[package]
name = "base64"
version = "0.0.1"
authors = []
[lib]
name = "base64"
path = "base64.rs"
[dependencies]
getopts = "*"
libc = "*"
rustc-serialize = "*"

View file

@ -1,162 +0,0 @@
#![crate_name = "base64"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordy Dickinson <jordy.dickinson@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
extern crate rustc_serialize as serialize;
extern crate getopts;
extern crate libc;
use getopts::Options;
use serialize::base64::{self, FromBase64, ToBase64};
use std::ascii::AsciiExt;
use std::error::Error;
use std::fs::File;
use std::io::{BufReader, Read, stdin, stdout, Write};
use std::path::Path;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
enum Mode {
Decode,
Encode,
Help,
Version
}
static NAME: &'static str = "base64";
static VERSION: &'static str = "1.0.0";
pub type FileOrStdReader = BufReader<Box<Read+'static>>;
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new();
opts.optflag("d", "decode", "decode data");
opts.optflag("i", "ignore-garbage", "when decoding, ignore non-alphabetic characters");
opts.optopt("w", "wrap", "wrap encoded lines after COLS character (default 76, 0 to disable wrapping)", "COLS");
opts.optflag("h", "help", "display this help text and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(e) => { crash!(1, "{}", e) }
};
let mode = if matches.opt_present("help") {
Mode::Help
} else if matches.opt_present("version") {
Mode::Version
} else if matches.opt_present("decode") {
Mode::Decode
} else {
Mode::Encode
};
let ignore_garbage = matches.opt_present("ignore-garbage");
let line_wrap = match matches.opt_str("wrap") {
Some(s) => match s.parse() {
Ok(s) => s,
Err(e)=> {
crash!(1, "Argument to option 'wrap' improperly formatted: {}", e);
}
},
None => 76
};
let stdin_buf;
let file_buf;
let mut input = if matches.free.is_empty() || &matches.free[0][..] == "-" {
stdin_buf = stdin();
BufReader::new(Box::new(stdin_buf) as Box<Read+'static>)
} else {
let path = Path::new(&matches.free[0][..]);
file_buf = safe_unwrap!(File::open(&path));
BufReader::new(Box::new(file_buf) as Box<Read+'static>)
};
match mode {
Mode::Decode => decode(&mut input, ignore_garbage),
Mode::Encode => encode(&mut input, line_wrap),
Mode::Help => help(opts),
Mode::Version => version()
}
0
}
fn decode(input: &mut FileOrStdReader, ignore_garbage: bool) {
let mut to_decode = String::new();
input.read_to_string(&mut to_decode).unwrap();
if ignore_garbage {
let mut clean = String::new();
clean.extend(to_decode.chars().filter(|&c| {
if !c.is_ascii() {
false
} else {
c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9' ||
c == '+' || c == '/'
}
}));
to_decode = clean;
}
match to_decode[..].from_base64() {
Ok(bytes) => {
let mut out = stdout();
match out.write_all(&bytes[..]) {
Ok(_) => {}
Err(f) => { crash!(1, "{}", f); }
}
match out.flush() {
Ok(_) => {}
Err(f) => { crash!(1, "{}", f); }
}
}
Err(s) => {
crash!(1, "{} ({:?})", s.description(), s);
}
}
}
fn encode(input: &mut FileOrStdReader, line_wrap: usize) {
let b64_conf = base64::Config {
char_set: base64::Standard,
newline: base64::Newline::LF,
pad: true,
line_length: match line_wrap {
0 => None,
_ => Some(line_wrap)
}
};
let mut to_encode: Vec<u8> = vec!();
input.read_to_end(&mut to_encode).unwrap();
let encoded = to_encode.to_base64(b64_conf);
println!("{}", &encoded[..]);
}
fn help(opts: Options) {
let msg = format!("Usage: {} [OPTION]... [FILE]\n\n\
Base64 encode or decode FILE, or standard input, to standard output.\n\
With no FILE, or when FILE is -, read standard input.\n\n\
The data are encoded as described for the base64 alphabet in RFC \
3548. When\ndecoding, the input may contain newlines in addition \
to the bytes of the formal\nbase64 alphabet. Use --ignore-garbage \
to attempt to recover from any other\nnon-alphabet bytes in the \
encoded stream.", NAME);
print!("{}", opts.usage(&msg));
}
fn version() {
println!("{} {}", NAME, VERSION);
}

View file

@ -1 +0,0 @@
DEPLIBS += rustc-serialize

View file

@ -1,12 +0,0 @@
[package]
name = "basename"
version = "0.0.1"
authors = []
[lib]
name = "basename"
path = "basename.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,108 +0,0 @@
#![crate_name = "basename"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Jimmy Lu <jimmy.lu.2011@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
use getopts::Options;
use std::io::Write;
use std::path::{is_separator, PathBuf};
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "basename";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
//
// Argument parsing
//
let mut opts = Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "Invalid options\n{}", f)
};
if matches.opt_present("help") {
let msg = format!("Usage: {0} NAME [SUFFIX]\n or: {0} OPTION\n\n\
Print NAME with any leading directory components removed.\n\
If specified, also remove a trailing SUFFIX.", NAME);
print!("{}", opts.usage(&msg));
return 0;
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
// too few arguments
if args.len() < 2 {
println!("{}: {}", NAME, "missing operand");
println!("Try '{} --help' for more information.", NAME);
return 1;
}
// too many arguments
else if args.len() > 3 {
println!("{}: extra operand '{}'", NAME, args[3]);
println!("Try '{} --help' for more information.", NAME);
return 1;
}
//
// Main Program Processing
//
let mut name = strip_dir(&args[1]);
if args.len() > 2 {
let suffix = args[2].clone();
name = strip_suffix(name.as_ref(), suffix.as_ref());
}
println!("{}", name);
0
}
fn strip_dir(fullname: &str) -> String {
// Remove all platform-specific path separators from the end
let mut path: String = fullname.chars().rev().skip_while(|&ch| is_separator(ch)).collect();
// Undo reverse
path = path.chars().rev().collect();
// Convert to path buffer and get last path component
let pb = PathBuf::from(path);
match pb.components().last() {
Some(c) => c.as_os_str().to_str().unwrap().to_string(),
None => "".to_string()
}
}
fn strip_suffix(name: &str, suffix: &str) -> String {
if name == suffix {
return name.to_string();
}
if name.ends_with(suffix) {
return name[..name.len() - suffix.len()].to_string();
}
name.to_string()
}

View file

@ -1,12 +0,0 @@
[package]
name = "cat"
version = "0.0.1"
authors = []
[lib]
name = "cat"
path = "cat.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,347 +0,0 @@
#![crate_name = "cat"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* last synced with: cat (GNU coreutils) 8.13 */
extern crate getopts;
extern crate libc;
use getopts::Options;
use std::fs::File;
use std::intrinsics::{copy_nonoverlapping};
use std::io::{stdout, stdin, stderr, Write, Read, Result};
use libc::consts::os::posix88::STDIN_FILENO;
use libc::funcs::posix88::unistd::isatty;
use libc::types::os::arch::c95::c_int;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "cat";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new();
opts.optflag("A", "show-all", "equivalent to -vET");
opts.optflag("b", "number-nonblank",
"number nonempty output lines, overrides -n");
opts.optflag("e", "", "equivalent to -vE");
opts.optflag("E", "show-ends", "display $ at end of each line");
opts.optflag("n", "number", "number all output lines");
opts.optflag("s", "squeeze-blank", "suppress repeated empty output lines");
opts.optflag("t", "", "equivalent to -vT");
opts.optflag("T", "show-tabs", "display TAB characters as ^I");
opts.optflag("v", "show-nonprinting",
"use ^ and M- notation, except for LF (\\n) and TAB (\\t)");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => panic!("Invalid options\n{}", f)
};
if matches.opt_present("help") {
let msg = format!("{} {}\n\n\
Usage:\n {0} [OPTION]... [FILE]...\n\n\
Concatenate FILE(s), or standard input, to standard output.\n\n\
With no FILE, or when FILE is -, read standard input.", NAME, VERSION);
print!("{}", opts.usage(&msg));
return 0;
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
let number_mode = if matches.opt_present("b") {
NumberingMode::NumberNonEmpty
} else if matches.opt_present("n") {
NumberingMode::NumberAll
} else {
NumberingMode::NumberNone
};
let show_nonprint = matches.opts_present(&["A".to_string(), "e".to_string(),
"t".to_string(), "v".to_string()]);
let show_ends = matches.opts_present(&["E".to_string(), "A".to_string(),
"e".to_string()]);
let show_tabs = matches.opts_present(&["A".to_string(), "T".to_string(),
"t".to_string()]);
let squeeze_blank = matches.opt_present("s");
let mut files = matches.free;
if files.is_empty() {
files.push("-".to_string());
}
exec(files, number_mode, show_nonprint, show_ends, show_tabs, squeeze_blank);
0
}
#[derive(Eq, PartialEq)]
enum NumberingMode {
NumberNone,
NumberNonEmpty,
NumberAll,
}
fn write_lines(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
show_ends: bool) {
let mut line_counter: usize = 1;
for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[..])) {
let mut in_buf = [0; 1024 * 31];
let mut out_buf = [0; 1024 * 64];
let mut writer = UnsafeWriter::new(&mut out_buf[..], stdout());
let mut at_line_start = true;
while let Ok(n) = reader.read(&mut in_buf) {
if n == 0 { break }
let in_buf = &in_buf[..n];
let mut buf_pos = 0..n;
loop {
writer.possibly_flush();
let pos = match buf_pos.next() {
Some(p) => p,
None => break,
};
if in_buf[pos] == '\n' as u8 {
if !at_line_start || !squeeze_blank {
if at_line_start && number == NumberingMode::NumberAll {
(write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
line_counter += 1;
}
if show_ends {
writer.write_all(&['$' as u8]).unwrap();
}
writer.write_all(&['\n' as u8]).unwrap();
if interactive {
writer.flush().unwrap();
}
}
at_line_start = true;
continue;
}
if at_line_start && number != NumberingMode::NumberNone {
(write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
line_counter += 1;
}
match in_buf[pos..].iter().position(|c| *c == '\n' as u8) {
Some(p) => {
writer.write_all(&in_buf[pos..pos + p]).unwrap();
if show_ends {
writer.write_all(&['$' as u8]).unwrap();
}
writer.write_all(&['\n' as u8]).unwrap();
if interactive {
writer.flush().unwrap();
}
buf_pos = pos + p + 1..n;
at_line_start = true;
},
None => {
writer.write_all(&in_buf[pos..]).unwrap();
at_line_start = false;
break;
}
};
}
}
}
}
fn write_bytes(files: Vec<String>, number: NumberingMode, squeeze_blank: bool,
show_ends: bool, show_nonprint: bool, show_tabs: bool) {
let mut line_counter: usize = 1;
for (mut reader, interactive) in files.iter().filter_map(|p| open(&p[..])) {
// Flush all 1024 iterations.
let mut flush_counter = 0usize..1024;
let mut in_buf = [0; 1024 * 32];
let mut out_buf = [0; 1024 * 64];
let mut writer = UnsafeWriter::new(&mut out_buf[..], stdout());
let mut at_line_start = true;
while let Ok(n) = reader.read(&mut in_buf) {
if n == 0 { break }
for &byte in in_buf[..n].iter() {
if flush_counter.next().is_none() {
writer.possibly_flush();
flush_counter = 0usize..1024;
}
if byte == '\n' as u8 {
if !at_line_start || !squeeze_blank {
if at_line_start && number == NumberingMode::NumberAll {
(write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
line_counter += 1;
}
if show_ends {
writer.write_all(&['$' as u8]).unwrap();
}
writer.write_all(&['\n' as u8]).unwrap();
if interactive {
writer.flush().unwrap();
}
}
at_line_start = true;
continue;
}
if at_line_start && number != NumberingMode::NumberNone {
(write!(&mut writer, "{0:6}\t", line_counter)).unwrap();
line_counter += 1;
at_line_start = false;
}
// This code is slow because of the many branches. cat in glibc avoids
// this by having the whole loop inside show_nonprint.
if byte == '\t' as u8 {
if show_tabs {
writer.write_all("^I".as_bytes())
} else {
writer.write_all(&[byte])
}
} else if show_nonprint {
let byte = match byte {
128 ... 255 => {
writer.write_all("M-".as_bytes()).unwrap();
byte - 128
},
_ => byte,
};
match byte {
0 ... 31 => writer.write_all(&['^' as u8, byte + 64]),
127 => writer.write_all(&['^' as u8, byte - 64]),
_ => writer.write_all(&[byte]),
}
} else {
writer.write_all(&[byte])
}.unwrap();
}
}
}
}
fn write_fast(files: Vec<String>) {
let mut writer = stdout();
let mut in_buf = [0; 1024 * 64];
for (mut reader, _) in files.iter().filter_map(|p| open(&p[..])) {
while let Ok(n) = reader.read(&mut in_buf) {
if n == 0 { break }
// This interface is completely broken.
writer.write_all(&in_buf[..n]).unwrap();
}
}
}
fn exec(files: Vec<String>, number: NumberingMode, show_nonprint: bool,
show_ends: bool, show_tabs: bool, squeeze_blank: bool) {
if show_nonprint || show_tabs {
write_bytes(files, number, squeeze_blank, show_ends, show_nonprint, show_tabs);
} else if number != NumberingMode::NumberNone || squeeze_blank || show_ends {
write_lines(files, number, squeeze_blank, show_ends);
} else {
write_fast(files);
}
pipe_flush!();
}
fn open(path: &str) -> Option<(Box<Read>, bool)> {
if path == "-" {
let stdin = stdin();
let interactive = unsafe { isatty(STDIN_FILENO) } != 0 as c_int;
return Some((Box::new(stdin) as Box<Read>, interactive));
}
match File::open(path) {
Ok(f) => Some((Box::new(f) as Box<Read>, false)),
Err(e) => {
(writeln!(&mut stderr(), "cat: {0}: {1}", path, e.to_string())).unwrap();
None
},
}
}
struct UnsafeWriter<'a, W: Write> {
inner: W,
buf: &'a mut [u8],
pos: usize,
threshold: usize,
}
impl<'a, W: Write> UnsafeWriter<'a, W> {
fn new(buf: &'a mut [u8], inner: W) -> UnsafeWriter<'a, W> {
let threshold = buf.len()/2;
UnsafeWriter {
inner: inner,
buf: buf,
pos: 0,
threshold: threshold,
}
}
fn flush_buf(&mut self) -> Result<()> {
if self.pos != 0 {
let ret = self.inner.write(&self.buf[..self.pos]);
self.pos = 0;
match ret {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
} else {
Ok(())
}
}
fn possibly_flush(&mut self) {
if self.pos > self.threshold {
self.inner.write_all(&self.buf[..self.pos]).unwrap();
self.pos = 0;
}
}
}
#[inline(never)]
fn fail() -> ! {
panic!("assertion failed");
}
impl<'a, W: Write> Write for UnsafeWriter<'a, W> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
let dst = &mut self.buf[self.pos..];
let len = buf.len();
if len > dst.len() {
fail();
}
unsafe {
copy_nonoverlapping(buf.as_ptr(), dst.as_mut_ptr(), len)
}
self.pos += len;
Ok(len)
}
fn flush(&mut self) -> Result<()> {
self.flush_buf().and_then(|()| self.inner.flush())
}
}
impl<'a, W: Write> Drop for UnsafeWriter<'a, W> {
fn drop(&mut self) {
let _ = self.flush_buf();
}
}
/* vim: set ai ts=4 sw=4 sts=4 et : */

View file

@ -1,17 +0,0 @@
[package]
name = "chmod"
version = "0.0.1"
authors = []
[lib]
name = "chmod"
path = "chmod.rs"
[dependencies]
getopts = "*"
libc = "*"
aho-corasick = "*"
memchr = "*"
regex = "*"
regex-syntax = "*"
walker = "*"

View file

@ -1,326 +0,0 @@
#![crate_name = "chmod"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Arcterus <arcterus@mail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#![allow(unused_variables)] // only necessary while the TODOs still exist
extern crate aho_corasick;
extern crate getopts;
extern crate libc;
extern crate memchr;
extern crate regex;
extern crate regex_syntax;
extern crate walker;
use getopts::Options;
use regex::Regex;
use std::ffi::CString;
use std::io::{Error, Write};
use std::mem;
use std::path::Path;
use walker::Walker;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
#[path = "../common/filesystem.rs"]
mod filesystem;
use filesystem::UUPathExt;
const NAME: &'static str = "chmod";
const VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new();
opts.optflag("c", "changes", "like verbose but report only when a change is made (unimplemented)");
opts.optflag("f", "quiet", "suppress most error messages (unimplemented)"); // TODO: support --silent
opts.optflag("v", "verbose", "output a diagnostic for every file processed (unimplemented)");
opts.optflag("", "no-preserve-root", "do not treat '/' specially (the default)");
opts.optflag("", "preserve-root", "fail to operate recursively on '/'");
opts.optflagopt("", "reference", "use RFILE's mode instead of MODE values", "RFILE");
opts.optflag("R", "recursive", "change files and directories recursively");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
// TODO: sanitize input for - at beginning (e.g. chmod -x testfile). Solution is to add a to -x, making a-x
let mut matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => { crash!(1, "{}", f) }
};
if matches.opt_present("help") {
let msg = format!("{name} {version}
Usage:
{program} [OPTION]... MODE[,MODE]... FILE...
{program} [OPTION]... OCTAL-MODE FILE...
{program} [OPTION]... --reference=RFILE FILE...
Change the mode of each FILE to MODE.
With --reference, change the mode of each FILE to that of RFILE.
Each MODE is of the form '[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+'.",
name = NAME, version = VERSION, program = NAME);
print!("{}", opts.usage(&msg));
return 0;
} else if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
} else if matches.free.is_empty() && matches.opt_present("reference") || matches.free.len() < 2 {
show_error!("missing an argument");
show_error!("for help, try '{} --help'", NAME);
return 1;
} else {
let changes = matches.opt_present("changes");
let quiet = matches.opt_present("quiet");
let verbose = matches.opt_present("verbose");
let preserve_root = matches.opt_present("preserve-root");
let recursive = matches.opt_present("recursive");
let fmode = matches.opt_str("reference").and_then(|fref| {
let mut stat : libc::stat = unsafe { mem::uninitialized() };
let statres = unsafe { libc::stat(fref.as_ptr() as *const i8, &mut stat as *mut libc::stat) };
if statres == 0 {
Some(stat.st_mode)
} else {
crash!(1, "{}", Error::last_os_error())
}
});
let cmode =
if fmode.is_none() {
let mode = matches.free.remove(0);
match verify_mode(&mode[..]) {
Ok(_) => Some(mode),
Err(f) => {
show_error!("{}", f);
return 1;
}
}
} else {
None
};
match chmod(matches.free, changes, quiet, verbose, preserve_root,
recursive, fmode, cmode.as_ref()) {
Ok(()) => {}
Err(e) => return e
}
}
0
}
#[cfg(unix)]
#[inline]
fn verify_mode(modes: &str) -> Result<(), String> {
let re: regex::Regex = Regex::new(r"^[ugoa]*([-+=]([rwxXst]*|[ugo]))+|[-+=]?[0-7]+$").unwrap();
for mode in modes.split(',') {
if !re.is_match(mode) {
return Err(format!("invalid mode '{}'", mode));
}
}
Ok(())
}
#[cfg(windows)]
#[inline]
// XXX: THIS IS NOT TESTED!!!
fn verify_mode(modes: &str) -> Result<(), String> {
let re: regex::Regex = Regex::new(r"^[ugoa]*(?:[-+=](?:([rwxXst]*)|[ugo]))+|[-+=]?([0-7]+)$").unwrap();
for mode in modes.split(',') {
match re.captures(mode) {
Some(cap) => {
let symbols = cap.at(1).unwrap();
let numbers = cap.at(2).unwrap();
if symbols.contains("s") || symbols.contains("t") {
return Err("The 's' and 't' modes are not supported on Windows".into());
} else if numbers.len() >= 4 && numbers[..numbers.len() - 3].find(|ch| ch != '0').is_some() {
return Err("Setuid, setgid, and sticky modes are not supported on Windows".into());
}
}
None => return Err(format!("invalid mode '{}'", mode))
}
}
Ok(())
}
fn chmod(files: Vec<String>, changes: bool, quiet: bool, verbose: bool, preserve_root: bool, recursive: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), i32> {
let mut r = Ok(());
for filename in files.iter() {
let filename = &filename[..];
let file = Path::new(filename);
if file.uu_exists() {
if file.uu_is_dir() {
if !preserve_root || filename != "/" {
if recursive {
let walk_dir = match Walker::new(&file) {
Ok(m) => m,
Err(f) => {
crash!(1, "{}", f.to_string());
}
};
// XXX: here (and elsewhere) we see that this impl will have issues
// with non-UTF-8 filenames. Using OsString won't fix this because
// on Windows OsStrings cannot be built out of non-UTF-8 chars. One
// possible fix is to use CStrings rather than Strings in the args
// to chmod() and chmod_file().
r = chmod(walk_dir.filter_map(|x| match x {
Ok(o) => match o.path().into_os_string().to_str() {
Some(s) => Some(s.to_string()),
None => None,
},
Err(e) => None,
}).collect(),
changes, quiet, verbose, preserve_root, recursive, fmode, cmode).and(r);
r = chmod_file(&file, filename, changes, quiet, verbose, fmode, cmode).and(r);
}
} else {
show_error!("could not change permissions of directory '{}'",
filename);
r = Err(1);
}
} else {
r = chmod_file(&file, filename, changes, quiet, verbose, fmode, cmode).and(r);
}
} else {
show_error!("no such file or directory '{}'", filename);
r = Err(1);
}
}
r
}
#[cfg(windows)]
fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), i32> {
// chmod is useless on Windows
// it doesn't set any permissions at all
// instead it just sets the readonly attribute on the file
Err(0)
}
#[cfg(unix)]
fn chmod_file(file: &Path, name: &str, changes: bool, quiet: bool, verbose: bool, fmode: Option<libc::mode_t>, cmode: Option<&String>) -> Result<(), i32> {
let path = CString::new(name).unwrap_or_else(|e| panic!("{}", e));
match fmode {
Some(mode) => {
if unsafe { libc::chmod(path.as_ptr(), mode) } == 0 {
// TODO: handle changes, quiet, and verbose
} else {
show_error!("{}", Error::last_os_error());
return Err(1);
}
}
None => {
// TODO: make the regex processing occur earlier (i.e. once in the main function)
let re: regex::Regex = Regex::new(r"^(([ugoa]*)((?:[-+=](?:[rwxXst]*|[ugo]))+))|([-+=]?[0-7]+)$").unwrap();
let mut stat: libc::stat = unsafe { mem::uninitialized() };
let statres = unsafe { libc::stat(path.as_ptr(), &mut stat as *mut libc::stat) };
let mut fperm =
if statres == 0 {
stat.st_mode
} else {
show_error!("{}", Error::last_os_error());
return Err(1);
};
for mode in cmode.unwrap().split(',') { // cmode is guaranteed to be Some in this case
let cap = re.captures(mode).unwrap(); // mode was verified earlier, so this is safe
if match cap.at(1) {
Some("") | None => false,
_ => true,
} {
// symbolic
let mut levels = cap.at(2).unwrap();
if levels.len() == 0 {
levels = "a";
}
let change = cap.at(3).unwrap().to_string() + "+";
let mut action = change.chars().next().unwrap();
let mut rwx = 0;
let mut special = 0;
let mut special_changed = false;
for ch in change[1..].chars() {
match ch {
'+' | '-' | '=' => {
for level in levels.chars() {
let (rwx, mask) = match level {
'u' => (rwx << 6, 0o7077),
'g' => (rwx << 3, 0o7707),
'o' => (rwx, 0o7770),
'a' => ((rwx << 6) | (rwx << 3) | rwx, 0o7000),
_ => unreachable!()
};
match action {
'+' => fperm |= rwx,
'-' => fperm &= !rwx,
'=' => fperm = (fperm & mask) | rwx,
_ => unreachable!()
}
}
if special_changed {
match action {
'+' => fperm |= special,
'-' => fperm &= !special,
'=' => fperm &= special | 0o0777,
_ => unreachable!()
}
}
action = ch;
rwx = 0;
special = 0;
special_changed = false;
}
'r' => rwx |= 0o004,
'w' => rwx |= 0o002,
'x' => rwx |= 0o001,
'X' => {
if file.uu_is_dir() || (fperm & 0o0111) != 0 {
rwx |= 0o001;
}
}
's' => {
special |= 0o4000 | 0o2000;
special_changed = true;
}
't' => {
special |= 0o1000;
special_changed = true;
}
'u' => rwx = (fperm >> 6) & 0o007,
'g' => rwx = (fperm >> 3) & 0o007,
'o' => rwx = (fperm >> 0) & 0o007,
_ => unreachable!()
}
}
} else {
// numeric
let change = cap.at(4).unwrap();
let ch = change.chars().next().unwrap();
let (action, slice) = match ch {
'+' | '-' | '=' => (ch, &change[1..]),
_ => ('=', change)
};
let mode = u32::from_str_radix(slice, 8).unwrap() as libc::mode_t; // already verified
match action {
'+' => fperm |= mode,
'-' => fperm &= !mode,
'=' => fperm = mode,
_ => unreachable!()
}
}
if unsafe { libc::chmod(path.as_ptr(), fperm) } == 0 {
// TODO: see above
} else {
show_error!("{}", Error::last_os_error());
return Err(1);
}
}
}
}
Ok(())
}

View file

@ -1 +0,0 @@
DEPLIBS += aho-corasick memchr regex regex-syntax walker

View file

@ -1,12 +0,0 @@
[package]
name = "chroot"
version = "0.0.1"
authors = []
[lib]
name = "chroot"
path = "chroot.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,220 +0,0 @@
#![crate_name = "chroot"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Vsevolod Velichko <torkvemada@sorokdva.net>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
use c_types::{get_pw_from_args, get_group};
use getopts::Options;
use libc::funcs::posix88::unistd::{setgid, setuid};
use std::ffi::CString;
use std::io::{Error, Write};
use std::iter::FromIterator;
use std::path::Path;
use std::process::Command;
#[path = "../common/util.rs"] #[macro_use] mod util;
#[path = "../common/c_types.rs"] mod c_types;
#[path = "../common/filesystem.rs"] mod filesystem;
use filesystem::UUPathExt;
extern {
fn chroot(path: *const libc::c_char) -> libc::c_int;
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
extern {
fn setgroups(size: libc::c_int, list: *const libc::gid_t) -> libc::c_int;
}
#[cfg(target_os = "linux")]
extern {
fn setgroups(size: libc::size_t, list: *const libc::gid_t) -> libc::c_int;
}
static NAME: &'static str = "chroot";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new();
opts.optopt("u", "user", "User (ID or name) to switch before running the program", "USER");
opts.optopt("g", "group", "Group (ID or name) to switch to", "GROUP");
opts.optopt("G", "groups", "Comma-separated list of groups to switch to", "GROUP1,GROUP2...");
opts.optopt("", "userspec", "Colon-separated user and group to switch to. \
Same as -u USER -g GROUP. \
Userspec has higher preference than -u and/or -g", "USER:GROUP");
opts.optflag("h", "help", "Show help");
opts.optflag("V", "version", "Show program's version");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
show_error!("{}", f);
help_menu(opts);
return 1
}
};
if matches.opt_present("V") { version(); return 0 }
if matches.opt_present("h") { help_menu(opts); return 0 }
if matches.free.len() == 0 {
println!("Missing operand: NEWROOT");
println!("Try `{} --help` for more information.", NAME);
return 1
}
let default_shell: &'static str = "/bin/sh";
let default_option: &'static str = "-i";
let user_shell = std::env::var("SHELL");
let newroot = Path::new(&matches.free[0][..]);
if !newroot.uu_is_dir() {
crash!(1, "cannot change root directory to `{}`: no such directory", newroot.display());
}
let command: Vec<&str> = match matches.free.len() {
1 => {
let shell: &str = match user_shell {
Err(_) => default_shell,
Ok(ref s) => s.as_ref(),
};
vec!(shell, default_option)
},
_ => matches.free[1..].iter().map(|x| &x[..]).collect()
};
set_context(&newroot, &matches);
let pstatus = Command::new(command[0])
.args(&command[1..])
.status()
.unwrap_or_else(|e| crash!(1, "Cannot exec: {}", e));
if pstatus.success() {
0
} else {
match pstatus.code() {
Some(i) => i,
None => -1,
}
}
}
fn set_context(root: &Path, options: &getopts::Matches) {
let userspec_str = options.opt_str("userspec");
let user_str = options.opt_str("user").unwrap_or_default();
let group_str = options.opt_str("group").unwrap_or_default();
let groups_str = options.opt_str("groups").unwrap_or_default();
let userspec = match userspec_str {
Some(ref u) => {
let s: Vec<&str> = u.split(':').collect();
if s.len() != 2 {
crash!(1, "invalid userspec: `{}`", u)
};
s
}
None => Vec::new()
};
let user = if userspec.is_empty() { &user_str[..] } else { &userspec[0][..] };
let group = if userspec.is_empty() { &group_str[..] } else { &userspec[1][..] };
enter_chroot(root);
set_groups_from_str(&groups_str[..]);
set_main_group(&group[..]);
set_user(&user[..]);
}
fn enter_chroot(root: &Path) {
let root_str = root.display();
std::env::set_current_dir(root).unwrap();
let err = unsafe {
chroot(CString::new(".".as_bytes()).unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char)
};
if err != 0 {
crash!(1, "cannot chroot to {}: {}", root_str, Error::last_os_error())
};
}
fn set_main_group(group: &str) {
if !group.is_empty() {
let group_id = match get_group(group) {
None => crash!(1, "no such group: {}", group),
Some(g) => g.gr_gid
};
let err = unsafe { setgid(group_id) };
if err != 0 {
crash!(1, "cannot set gid to {}: {}", group_id, Error::last_os_error())
}
}
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
unsafe {
setgroups(groups.len() as libc::c_int,
groups.as_ptr())
}
}
#[cfg(target_os = "linux")]
fn set_groups(groups: Vec<libc::gid_t>) -> libc::c_int {
unsafe {
setgroups(groups.len() as libc::size_t,
groups.as_ptr())
}
}
fn set_groups_from_str(groups: &str) {
if !groups.is_empty() {
let groups_vec: Vec<libc::gid_t> = FromIterator::from_iter(
groups.split(',').map(
|x| match get_group(x) {
None => crash!(1, "no such group: {}", x),
Some(g) => g.gr_gid
})
);
let err = set_groups(groups_vec);
if err != 0 {
crash!(1, "cannot set groups: {}", Error::last_os_error())
}
}
}
fn set_user(user: &str) {
if !user.is_empty() {
let user_id = get_pw_from_args(&vec!(user.to_string())).unwrap().pw_uid;
let err = unsafe { setuid(user_id as libc::uid_t) };
if err != 0 {
crash!(1, "cannot set user to {}: {}", user, Error::last_os_error())
}
}
}
fn version() {
println!("{} {}", NAME, VERSION)
}
fn help_menu(options: Options) {
let msg = format!("{0} {1}
Usage:
{0} [OPTION]... NEWROOT [COMMAND [ARG]...]
Run COMMAND with root directory set to NEWROOT.
If COMMAND is not specified, it defaults to '$(SHELL) -i'.
If $(SHELL) is not set, /bin/sh is used.", NAME, VERSION);
print!("{}", options.usage(&msg));
}

View file

@ -1,12 +0,0 @@
[package]
name = "cksum"
version = "0.0.1"
authors = []
[lib]
name = "cksum"
path = "cksum.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,131 +0,0 @@
#![crate_name = "cksum"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Michael Gehring <mg@ebfe.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
use getopts::Options;
use std::fs::File;
use std::io::{self, stdin, Read, Write, BufReader};
use std::mem;
use std::path::Path;
use crc_table::CRC_TABLE;
#[path="../common/util.rs"]
#[macro_use]
mod util;
mod crc_table;
static NAME: &'static str = "cksum";
static VERSION: &'static str = "1.0.0";
#[inline]
fn crc_update(crc: u32, input: u8) -> u32 {
(crc << 8) ^ CRC_TABLE[((crc >> 24) as usize ^ input as usize) & 0xFF]
}
#[inline]
fn crc_final(mut crc: u32, mut length: usize) -> u32 {
while length != 0 {
crc = crc_update(crc, length as u8);
length >>= 8;
}
!crc
}
#[inline]
fn cksum(fname: &str) -> io::Result<(u32, usize)> {
let mut crc = 0u32;
let mut size = 0usize;
let file;
let mut rd : Box<Read> = match fname {
"-" => {
Box::new(stdin())
}
_ => {
file = try!(File::open(&Path::new(fname)));
Box::new(BufReader::new(file))
}
};
let mut bytes: [u8; 1024 * 1024] = unsafe { mem::uninitialized() };
loop {
match rd.read(&mut bytes) {
Ok(num_bytes) => {
if num_bytes == 0 {
return Ok((crc_final(crc, size), size));
}
for &b in bytes[..num_bytes].iter() {
crc = crc_update(crc, b);
}
size += num_bytes;
}
Err(err) => return Err(err)
}
}
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(err) => panic!("{}", err),
};
if matches.opt_present("help") {
let msg = format!("{0} {1}
Usage:
{0} [OPTIONS] [FILE]...
Print CRC and size for each file.", NAME, VERSION);
print!("{}", opts.usage(&msg));
return 0;
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
let files = matches.free;
if files.is_empty() {
match cksum("-") {
Ok((crc, size)) => println!("{} {}", crc, size),
Err(err) => {
show_error!("{}", err);
return 2;
}
}
return 0;
}
let mut exit_code = 0;
for fname in files.iter() {
match cksum(fname.as_ref()) {
Ok((crc, size)) => println!("{} {} {}", crc, size, fname),
Err(err) => {
show_error!("'{}' {}", fname, err);
exit_code = 2;
}
}
}
exit_code
}

View file

@ -1,3 +0,0 @@
/* auto-generated (DO NOT EDIT) */
pub static CRC_TABLE: [u32; 256] = [0, 79764919, 159529838, 222504665, 319059676, 398814059, 445009330, 507990021, 638119352, 583659535, 797628118, 726387553, 890018660, 835552979, 1015980042, 944750013, 1276238704, 1221641927, 1167319070, 1095957929, 1595256236, 1540665371, 1452775106, 1381403509, 1780037320, 1859660671, 1671105958, 1733955601, 2031960084, 2111593891, 1889500026, 1952343757, 2552477408, 2632100695, 2443283854, 2506133561, 2334638140, 2414271883, 2191915858, 2254759653, 3190512472, 3135915759, 3081330742, 3009969537, 2905550212, 2850959411, 2762807018, 2691435357, 3560074640, 3505614887, 3719321342, 3648080713, 3342211916, 3287746299, 3467911202, 3396681109, 4063920168, 4143685023, 4223187782, 4286162673, 3779000052, 3858754371, 3904687514, 3967668269, 881225847, 809987520, 1023691545, 969234094, 662832811, 591600412, 771767749, 717299826, 311336399, 374308984, 453813921, 533576470, 25881363, 88864420, 134795389, 214552010, 2023205639, 2086057648, 1897238633, 1976864222, 1804852699, 1867694188, 1645340341, 1724971778, 1587496639, 1516133128, 1461550545, 1406951526, 1302016099, 1230646740, 1142491917, 1087903418, 2896545431, 2825181984, 2770861561, 2716262478, 3215044683, 3143675388, 3055782693, 3001194130, 2326604591, 2389456536, 2200899649, 2280525302, 2578013683, 2640855108, 2418763421, 2498394922, 3769900519, 3832873040, 3912640137, 3992402750, 4088425275, 4151408268, 4197601365, 4277358050, 3334271071, 3263032808, 3476998961, 3422541446, 3585640067, 3514407732, 3694837229, 3640369242, 1762451694, 1842216281, 1619975040, 1682949687, 2047383090, 2127137669, 1938468188, 2001449195, 1325665622, 1271206113, 1183200824, 1111960463, 1543535498, 1489069629, 1434599652, 1363369299, 622672798, 568075817, 748617968, 677256519, 907627842, 853037301, 1067152940, 995781531, 51762726, 131386257, 177728840, 240578815, 269590778, 349224269, 429104020, 491947555, 4046411278, 4126034873, 4172115296, 4234965207, 3794477266, 3874110821, 3953728444, 4016571915, 3609705398, 3555108353, 3735388376, 3664026991, 3290680682, 3236090077, 3449943556, 3378572211, 3174993278, 3120533705, 3032266256, 2961025959, 2923101090, 2868635157, 2813903052, 2742672763, 2604032198, 2683796849, 2461293480, 2524268063, 2284983834, 2364738477, 2175806836, 2238787779, 1569362073, 1498123566, 1409854455, 1355396672, 1317987909, 1246755826, 1192025387, 1137557660, 2072149281, 2135122070, 1912620623, 1992383480, 1753615357, 1816598090, 1627664531, 1707420964, 295390185, 358241886, 404320391, 483945776, 43990325, 106832002, 186451547, 266083308, 932423249, 861060070, 1041341759, 986742920, 613929101, 542559546, 756411363, 701822548, 3316196985, 3244833742, 3425377559, 3370778784, 3601682597, 3530312978, 3744426955, 3689838204, 3819031489, 3881883254, 3928223919, 4007849240, 4037393693, 4100235434, 4180117107, 4259748804, 2310601993, 2373574846, 2151335527, 2231098320, 2596047829, 2659030626, 2470359227, 2550115596, 2947551409, 2876312838, 2788305887, 2733848168, 3165939309, 3094707162, 3040238851, 2985771188];

View file

@ -1,41 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Arcterus <arcterus@mail.com>
* (c) Michael Gehring <mg@ebfe.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use std::fs::File;
use std::io::Write;
static CRC_TABLE_LEN: usize = 256;
fn main() {
let mut table = Vec::with_capacity(CRC_TABLE_LEN);
for num in (0 .. CRC_TABLE_LEN) {
table.push(crc_entry(num as u8) as u32);
}
let file = File::create("crc_table.rs").unwrap_or_else(|e| panic!("{}", e));
write!(&file, "/* auto-generated (DO NOT EDIT) */
pub static CRC_TABLE: [u32; {}] = {:?};", CRC_TABLE_LEN, table).unwrap();
}
#[inline]
fn crc_entry(input: u8) -> u32 {
let mut crc = (input as u32) << 24;
for _ in (0 .. 8) {
if crc & 0x80000000 != 0 {
crc <<= 1;
crc ^= 0x04c11db7;
} else {
crc <<= 1;
}
}
crc
}

View file

@ -1,12 +0,0 @@
[package]
name = "comm"
version = "0.0.1"
authors = []
[lib]
name = "comm"
path = "comm.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,160 +0,0 @@
#![crate_name = "comm"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Michael Gehring <mg@ebfe.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
use getopts::Options;
use std::cmp::Ordering;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Read, stdin, Stdin};
use std::path::Path;
static NAME: &'static str = "comm";
static VERSION: &'static str = "1.0.0";
fn mkdelim(col: usize, opts: &getopts::Matches) -> String {
let mut s = String::new();
let delim = match opts.opt_str("output-delimiter") {
Some(d) => d.clone(),
None => "\t".to_string(),
};
if col > 1 && !opts.opt_present("1") {
s.push_str(delim.as_ref());
}
if col > 2 && !opts.opt_present("2") {
s.push_str(delim.as_ref());
}
s
}
fn ensure_nl(line: &mut String) {
match line.chars().last() {
Some('\n') => (),
_ => line.push_str("\n")
}
}
enum LineReader {
Stdin(Stdin),
FileIn(BufReader<File>)
}
impl LineReader {
fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
match self {
&mut LineReader::Stdin(ref mut r) => r.read_line(buf),
&mut LineReader::FileIn(ref mut r) => r.read_line(buf),
}
}
}
fn comm(a: &mut LineReader, b: &mut LineReader, opts: &getopts::Matches) {
let delim : Vec<String> = (0 .. 4).map(|col| mkdelim(col, opts)).collect();
let mut ra = &mut String::new();
let mut na = a.read_line(ra);
let mut rb = &mut String::new();
let mut nb = b.read_line(rb);
while na.is_ok() || nb.is_ok() {
let ord = match (na.is_ok(), nb.is_ok()) {
(false, true) => Ordering::Greater,
(true , false) => Ordering::Less,
(true , true) => match(&na, &nb) {
(&Ok(0), _) => Ordering::Greater,
(_, &Ok(0)) => Ordering::Less,
_ => ra.cmp(&rb),
},
_ => unreachable!(),
};
match ord {
Ordering::Less => {
if !opts.opt_present("1") {
ensure_nl(ra);
print!("{}{}", delim[1], ra);
}
na = a.read_line(ra);
},
Ordering::Greater => {
if !opts.opt_present("2") {
ensure_nl(rb);
print!("{}{}", delim[2], rb);
}
nb = b.read_line(rb);
},
Ordering::Equal => {
if !opts.opt_present("3") {
ensure_nl(ra);
print!("{}{}", delim[3], ra);
}
na = a.read_line(ra);
nb = b.read_line(rb);
}
}
}
}
fn open_file(name: &str) -> io::Result<LineReader> {
match name {
"-" => Ok(LineReader::Stdin(stdin())),
_ => {
let f = try!(File::open(&Path::new(name)));
Ok(LineReader::FileIn(BufReader::new(f)))
}
}
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new();
opts.optflag("1", "", "suppress column 1 (lines uniq to FILE1)");
opts.optflag("2", "", "suppress column 2 (lines uniq to FILE2)");
opts.optflag("3", "", "suppress column 3 (lines that appear in both files)");
opts.optopt("", "output-delimiter", "separate columns with STR", "STR");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(err) => panic!("{}", err),
};
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
if matches.opt_present("help") || matches.free.len() != 2 {
let msg = format!("{0} {1}
Usage:
{0} [OPTIONS] FILE1 FILE2
Compare sorted files line by line.", NAME, VERSION);
print!("{}", opts.usage(&msg));
if matches.free.len() != 2 {
return 1;
}
return 0;
}
let mut f1 = open_file(matches.free[0].as_ref()).unwrap();
let mut f2 = open_file(matches.free[1].as_ref()).unwrap();
comm(&mut f1, &mut f2, &matches);
0
}

View file

@ -1,240 +0,0 @@
#![allow(dead_code, non_camel_case_types, raw_pointer_derive)]
extern crate libc;
use self::libc::{
c_char,
c_int,
uid_t,
gid_t,
};
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
use self::libc::time_t;
#[cfg(target_os = "macos")]
use self::libc::int32_t;
use self::libc::funcs::posix88::unistd::getgroups;
use std::ffi::{CStr, CString};
use std::io::{Error, Write};
use std::iter::repeat;
use std::vec::Vec;
use std::ptr::{null_mut, read};
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct c_passwd {
pub pw_name: *const c_char, /* user name */
pub pw_passwd: *const c_char, /* user name */
pub pw_uid: uid_t, /* user uid */
pub pw_gid: gid_t, /* user gid */
pub pw_change: time_t,
pub pw_class: *const c_char,
pub pw_gecos: *const c_char,
pub pw_dir: *const c_char,
pub pw_shell: *const c_char,
pub pw_expire: time_t
}
#[cfg(target_os = "linux")]
#[repr(C)]
#[derive(Clone, Copy)]
pub struct c_passwd {
pub pw_name: *const c_char, /* user name */
pub pw_passwd: *const c_char, /* user name */
pub pw_uid: uid_t, /* user uid */
pub pw_gid: gid_t, /* user gid */
pub pw_gecos: *const c_char,
pub pw_dir: *const c_char,
pub pw_shell: *const c_char,
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
#[repr(C)]
pub struct utsname {
pub sysname: [c_char; 256],
pub nodename: [c_char; 256],
pub release: [c_char; 256],
pub version: [c_char; 256],
pub machine: [c_char; 256]
}
#[cfg(target_os = "linux")]
#[repr(C)]
pub struct utsname {
pub sysname: [c_char; 65],
pub nodename: [c_char; 65],
pub release: [c_char; 65],
pub version: [c_char; 65],
pub machine: [c_char; 65],
pub domainame: [c_char; 65]
}
#[repr(C)]
pub struct c_group {
pub gr_name: *const c_char, // group name
pub gr_passwd: *const c_char, // password
pub gr_gid: gid_t, // group id
pub gr_mem: *const *const c_char, // member list
}
#[repr(C)]
pub struct c_tm {
pub tm_sec: c_int, /* seconds */
pub tm_min: c_int, /* minutes */
pub tm_hour: c_int, /* hours */
pub tm_mday: c_int, /* day of the month */
pub tm_mon: c_int, /* month */
pub tm_year: c_int, /* year */
pub tm_wday: c_int, /* day of the week */
pub tm_yday: c_int, /* day in the year */
pub tm_isdst: c_int /* daylight saving time */
}
extern {
pub fn getpwuid(uid: uid_t) -> *const c_passwd;
pub fn getpwnam(login: *const c_char) -> *const c_passwd;
pub fn getgrgid(gid: gid_t) -> *const c_group;
pub fn getgrnam(name: *const c_char) -> *const c_group;
pub fn getgrouplist(name: *const c_char,
gid: gid_t,
groups: *mut gid_t,
ngroups: *mut c_int) -> c_int;
}
#[cfg(target_os = "macos")]
extern {
pub fn getgroupcount(name: *const c_char, gid: gid_t) -> int32_t;
}
pub fn get_pw_from_args(free: &Vec<String>) -> Option<c_passwd> {
if free.len() == 1 {
let username = &free[0][..];
// Passed user as id
if username.chars().all(|c| c.is_digit(10)) {
let id = username.parse::<u32>().unwrap();
let pw_pointer = unsafe { getpwuid(id as uid_t) };
if !pw_pointer.is_null() {
Some(unsafe { read(pw_pointer) })
} else {
crash!(1, "{}: no such user", username);
}
// Passed the username as a string
} else {
let pw_pointer = unsafe {
let cstr = CString::new(username).unwrap();
getpwnam(cstr.as_bytes_with_nul().as_ptr() as *const i8)
};
if !pw_pointer.is_null() {
Some(unsafe { read(pw_pointer) })
} else {
crash!(1, "{}: no such user", username);
}
}
} else {
None
}
}
pub fn get_group(groupname: &str) -> Option<c_group> {
let group = if groupname.chars().all(|c| c.is_digit(10)) {
unsafe { getgrgid(groupname.parse().unwrap()) }
} else {
unsafe {
let cstr = CString::new(groupname).unwrap();
getgrnam(cstr.as_bytes_with_nul().as_ptr() as *const c_char)
}
};
if !group.is_null() {
Some(unsafe { read(group) })
}
else {
None
}
}
pub fn get_group_list(name: *const c_char, gid: gid_t) -> Vec<gid_t> {
let mut ngroups: c_int = 32;
let mut groups: Vec<gid_t> = Vec::with_capacity(ngroups as usize);
if unsafe { get_group_list_internal(name, gid, groups.as_mut_ptr(), &mut ngroups) } == -1 {
groups.reserve(ngroups as usize);
unsafe { get_group_list_internal(name, gid, groups.as_mut_ptr(), &mut ngroups); }
} else {
groups.truncate(ngroups as usize);
}
unsafe { groups.set_len(ngroups as usize); }
groups
}
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
#[inline(always)]
unsafe fn get_group_list_internal(name: *const c_char, gid: gid_t, groups: *mut gid_t, grcnt: *mut c_int) -> c_int {
getgrouplist(name, gid, groups, grcnt)
}
#[cfg(target_os = "macos")]
unsafe fn get_group_list_internal(name: *const c_char, gid: gid_t, groups: *mut gid_t, grcnt: *mut c_int) -> c_int {
let ngroups = getgroupcount(name, gid);
let oldsize = *grcnt;
*grcnt = ngroups;
if oldsize >= ngroups {
getgrouplist(name, gid, groups, grcnt);
0
} else {
-1
}
}
pub fn get_groups() -> Result<Vec<gid_t>, i32> {
let ngroups = unsafe { getgroups(0, null_mut()) };
if ngroups == -1 {
return Err(Error::last_os_error().raw_os_error().unwrap())
}
let mut groups : Vec<gid_t>= repeat(0).take(ngroups as usize).collect();
let ngroups = unsafe { getgroups(ngroups, groups.as_mut_ptr()) };
if ngroups == -1 {
Err(Error::last_os_error().raw_os_error().unwrap())
} else {
groups.truncate(ngroups as usize);
Ok(groups)
}
}
pub fn group(possible_pw: Option<c_passwd>, nflag: bool) {
let groups = match possible_pw {
Some(pw) => Ok(get_group_list(pw.pw_name, pw.pw_gid)),
None => get_groups(),
};
match groups {
Err(errno) =>
crash!(1, "failed to get group list (errno={})", errno),
Ok(groups) => {
for &g in groups.iter() {
if nflag {
let group = unsafe { getgrgid(g) };
if !group.is_null() {
let name = unsafe {
let gname = read(group).gr_name;
let bytes= CStr::from_ptr(gname).to_bytes();
String::from_utf8_lossy(bytes).to_string()
};
print!("{} ", name);
}
} else {
print!("{} ", g);
}
}
println!("");
}
}
}

View file

@ -1,147 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Joseph Crail <jbcrail@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
// Based on the pattern using by Cargo, I created a shim over the
// standard PathExt trait, so that the unstable path methods could
// be backported to stable (<= 1.1). This will likely be dropped
// when the path trait stabilizes.
use std::env;
use std::fs;
use std::io::{Error, ErrorKind, Result};
use std::path::{Component, Path, PathBuf};
pub trait UUPathExt {
fn uu_exists(&self) -> bool;
fn uu_is_file(&self) -> bool;
fn uu_is_dir(&self) -> bool;
fn uu_metadata(&self) -> Result<fs::Metadata>;
}
impl UUPathExt for Path {
fn uu_exists(&self) -> bool {
fs::metadata(self).is_ok()
}
fn uu_is_file(&self) -> bool {
fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
}
fn uu_is_dir(&self) -> bool {
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
}
fn uu_metadata(&self) -> Result<fs::Metadata> {
fs::metadata(self)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[allow(dead_code)]
pub enum CanonicalizeMode {
None,
Normal,
Existing,
Missing,
}
#[allow(dead_code)]
fn resolve<P: AsRef<Path>>(original: P) -> Result<PathBuf> {
const MAX_LINKS_FOLLOWED: u32 = 255;
let mut followed = 0;
let mut result = original.as_ref().to_path_buf();
loop {
if followed == MAX_LINKS_FOLLOWED {
return Err(Error::new(ErrorKind::InvalidInput, "maximum links followed"));
}
match fs::metadata(&result) {
Err(e) => return Err(e),
Ok(ref m) if !m.file_type().is_symlink() => break,
Ok(..) => {
followed += 1;
match fs::read_link(&result) {
Ok(path) => {
result.pop();
result.push(path);
},
Err(e) => {
return Err(e);
}
}
}
}
}
Ok(result)
}
#[allow(dead_code)]
pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> Result<PathBuf> {
// Create an absolute path
let original = original.as_ref();
let original = if original.is_absolute() {
original.to_path_buf()
} else {
env::current_dir().unwrap().join(original)
};
let mut result = PathBuf::new();
let mut parts = vec!();
// Split path by directory separator; add prefix (Windows-only) and root
// directory to final path buffer; add remaining parts to temporary
// vector for canonicalization.
for part in original.components() {
match part {
Component::Prefix(_) | Component::RootDir => {
result.push(part.as_os_str());
},
Component::CurDir => {},
Component::ParentDir => {
parts.pop();
},
Component::Normal(_) => {
parts.push(part.as_os_str());
}
}
}
// Resolve the symlinks where possible
if parts.len() > 0 {
for part in parts[..parts.len()-1].iter() {
result.push(part);
if can_mode == CanonicalizeMode::None {
continue;
}
match resolve(&result) {
Err(e) => match can_mode {
CanonicalizeMode::Missing => continue,
_ => return Err(e)
},
Ok(path) => {
result.pop();
result.push(path);
}
}
}
result.push(parts.last().unwrap());
match resolve(&result) {
Err(e) => { if can_mode == CanonicalizeMode::Existing { return Err(e); } },
Ok(path) => {
result.pop();
result.push(path);
}
}
}
Ok(result)
}

View file

@ -1,35 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Arcterus <arcterus@mail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
pub fn from_str(string: &str) -> Result<f64, String> {
let len = string.len();
if len == 0 {
return Err("empty string".to_string())
}
let slice = &string[..len - 1];
let (numstr, times) = match string.chars().next_back().unwrap() {
's' | 'S' => (slice, 1),
'm' | 'M' => (slice, 60),
'h' | 'H' => (slice, 60 * 60),
'd' | 'D' => (slice, 60 * 60 * 24),
val => {
if !val.is_alphabetic() {
(string, 1)
} else if string == "inf" || string == "infinity" {
("inf", 1)
} else {
return Err(format!("invalid time interval '{}'", string))
}
}
};
match numstr.parse::<f64>() {
Ok(m) => Ok(m * times as f64),
Err(e) => Err(format!("invalid time interval '{}': {}", string, e))
}
}

View file

@ -1,140 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Maciej Dziardziel <fiedzia@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
extern crate libc;
extern crate time;
use libc::{c_int, pid_t};
use std::fmt;
use std::io;
use std::process::Child;
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use time::{Duration, get_time};
// This is basically sys::unix::process::ExitStatus
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum ExitStatus {
Code(i32),
Signal(i32),
}
impl ExitStatus {
fn from_status(status: c_int) -> ExitStatus {
if status & 0x7F != 0 { // WIFSIGNALED(status)
ExitStatus::Signal(status & 0x7F)
} else {
ExitStatus::Code(status & 0xFF00 >> 8)
}
}
pub fn success(&self) -> bool {
match *self {
ExitStatus::Code(code) => code == 0,
_ => false,
}
}
pub fn code(&self) -> Option<i32> {
match *self {
ExitStatus::Code(code) => Some(code),
_ => None,
}
}
pub fn signal(&self) -> Option<i32> {
match *self {
ExitStatus::Signal(code) => Some(code),
_ => None,
}
}
}
impl fmt::Display for ExitStatus {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ExitStatus::Code(code) => write!(f, "exit code: {}", code),
ExitStatus::Signal(code) => write!(f, "exit code: {}", code),
}
}
}
/// Missing methods for Child objects
pub trait ChildExt {
/// Send a signal to a Child process.
fn send_signal(&mut self, signal: usize) -> io::Result<()>;
/// Wait for a process to finish or return after the specified duration.
fn wait_or_timeout(&mut self, timeout: f64) -> io::Result<Option<ExitStatus>>;
}
impl ChildExt for Child {
fn send_signal(&mut self, signal: usize) -> io::Result<()> {
if unsafe { libc::funcs::posix88::signal::kill(self.id() as pid_t,
signal as i32) } != 0 {
Err(io::Error::last_os_error())
} else {
Ok(())
}
}
fn wait_or_timeout(&mut self, timeout: f64) -> io::Result<Option<ExitStatus>> {
// The result will be written to that Option, protected by a Mutex
// Then the Condvar will be signaled
let state = Arc::new((
Mutex::new(Option::None::<io::Result<ExitStatus>>),
Condvar::new(),
));
// Start the waiting thread
let state_th = state.clone();
let pid_th = self.id();
thread::spawn(move || {
let &(ref lock_th, ref cvar_th) = &*state_th;
// Child::wait() would need a &mut to self, can't use that...
// use waitpid() directly, with our own ExitStatus
let mut status: c_int = 0;
let r = unsafe { libc::waitpid(pid_th as i32, &mut status, 0) };
// Fill the Option and notify on the Condvar
let mut exitstatus_th = lock_th.lock().unwrap();
if r != pid_th as c_int {
*exitstatus_th = Some(Err(io::Error::last_os_error()));
} else {
let s = ExitStatus::from_status(status);
*exitstatus_th = Some(Ok(s));
}
cvar_th.notify_one();
});
// Main thread waits
let &(ref lock, ref cvar) = &*state;
let mut exitstatus = lock.lock().unwrap();
// Condvar::wait_timeout_ms() can wake too soon, in this case wait again
let target = get_time() +
Duration::seconds(timeout as i64) +
Duration::nanoseconds((timeout * 1.0e-6) as i64);
while exitstatus.is_none() {
let now = get_time();
if now >= target {
return Ok(None)
}
let ms = (target - get_time()).num_milliseconds() as u32;
exitstatus = cvar.wait_timeout_ms(exitstatus, ms).unwrap().0;
}
// Turn Option<Result<ExitStatus>> into Result<Option<ExitStatus>>
match exitstatus.take() {
Some(r) => match r {
Ok(s) => Ok(Some(s)),
Err(e) => Err(e),
},
None => panic!(),
}
}
}

View file

@ -1,158 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Maciej Dziardziel <fiedzia@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
#![allow(dead_code)]
pub static DEFAULT_SIGNAL:usize= 15;
pub struct Signal<'a> { pub name:&'a str, pub value: usize}
/*
Linux Programmer's Manual
1 HUP 2 INT 3 QUIT 4 ILL 5 TRAP 6 ABRT 7 BUS
8 FPE 9 KILL 10 USR1 11 SEGV 12 USR2 13 PIPE 14 ALRM
15 TERM 16 STKFLT 17 CHLD 18 CONT 19 STOP 20 TSTP 21 TTIN
22 TTOU 23 URG 24 XCPU 25 XFSZ 26 VTALRM 27 PROF 28 WINCH
29 POLL 30 PWR 31 SYS
*/
#[cfg(target_os = "linux")]
pub static ALL_SIGNALS:[Signal<'static>; 31] = [
Signal{ name: "HUP", value:1 },
Signal{ name: "INT", value:2 },
Signal{ name: "QUIT", value:3 },
Signal{ name: "ILL", value:4 },
Signal{ name: "TRAP", value:5 },
Signal{ name: "ABRT", value:6 },
Signal{ name: "BUS", value:7 },
Signal{ name: "FPE", value:8 },
Signal{ name: "KILL", value:9 },
Signal{ name: "USR1", value:10 },
Signal{ name: "SEGV", value:11 },
Signal{ name: "USR2", value:12 },
Signal{ name: "PIPE", value:13 },
Signal{ name: "ALRM", value:14 },
Signal{ name: "TERM", value:15 },
Signal{ name: "STKFLT", value:16 },
Signal{ name: "CHLD", value:17 },
Signal{ name: "CONT", value:18 },
Signal{ name: "STOP", value:19 },
Signal{ name: "TSTP", value:20 },
Signal{ name: "TTIN", value:21 },
Signal{ name: "TTOU", value:22 },
Signal{ name: "URG", value:23 },
Signal{ name: "XCPU", value:24 },
Signal{ name: "XFSZ", value:25 },
Signal{ name: "VTALRM", value:26 },
Signal{ name: "PROF", value:27 },
Signal{ name: "WINCH", value:28 },
Signal{ name: "POLL", value:29 },
Signal{ name: "PWR", value:30 },
Signal{ name: "SYS", value:31 },
];
/*
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/signal.3.html
No Name Default Action Description
1 SIGHUP terminate process terminal line hangup
2 SIGINT terminate process interrupt program
3 SIGQUIT create core image quit program
4 SIGILL create core image illegal instruction
5 SIGTRAP create core image trace trap
6 SIGABRT create core image abort program (formerly SIGIOT)
7 SIGEMT create core image emulate instruction executed
8 SIGFPE create core image floating-point exception
9 SIGKILL terminate process kill program
10 SIGBUS create core image bus error
11 SIGSEGV create core image segmentation violation
12 SIGSYS create core image non-existent system call invoked
13 SIGPIPE terminate process write on a pipe with no reader
14 SIGALRM terminate process real-time timer expired
15 SIGTERM terminate process software termination signal
16 SIGURG discard signal urgent condition present on socket
17 SIGSTOP stop process stop (cannot be caught or ignored)
18 SIGTSTP stop process stop signal generated from keyboard
19 SIGCONT discard signal continue after stop
20 SIGCHLD discard signal child status has changed
21 SIGTTIN stop process background read attempted from control terminal
22 SIGTTOU stop process background write attempted to control terminal
23 SIGIO discard signal I/O is possible on a descriptor (see fcntl(2))
24 SIGXCPU terminate process cpu time limit exceeded (see setrlimit(2))
25 SIGXFSZ terminate process file size limit exceeded (see setrlimit(2))
26 SIGVTALRM terminate process virtual time alarm (see setitimer(2))
27 SIGPROF terminate process profiling timer alarm (see setitimer(2))
28 SIGWINCH discard signal Window size change
29 SIGINFO discard signal status request from keyboard
30 SIGUSR1 terminate process User defined signal 1
31 SIGUSR2 terminate process User defined signal 2
*/
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
pub static ALL_SIGNALS:[Signal<'static>; 31] = [
Signal{ name: "HUP", value:1 },
Signal{ name: "INT", value:2 },
Signal{ name: "QUIT", value:3 },
Signal{ name: "ILL", value:4 },
Signal{ name: "TRAP", value:5 },
Signal{ name: "ABRT", value:6 },
Signal{ name: "EMT", value:7 },
Signal{ name: "FPE", value:8 },
Signal{ name: "KILL", value:9 },
Signal{ name: "BUS", value:10 },
Signal{ name: "SEGV", value:11 },
Signal{ name: "SYS", value:12 },
Signal{ name: "PIPE", value:13 },
Signal{ name: "ALRM", value:14 },
Signal{ name: "TERM", value:15 },
Signal{ name: "URG", value:16 },
Signal{ name: "STOP", value:17 },
Signal{ name: "TSTP", value:18 },
Signal{ name: "CONT", value:19 },
Signal{ name: "CHLD", value:20 },
Signal{ name: "TTIN", value:21 },
Signal{ name: "TTOU", value:22 },
Signal{ name: "IO", value:23 },
Signal{ name: "XCPU", value:24 },
Signal{ name: "XFSZ", value:25 },
Signal{ name: "VTALRM", value:26 },
Signal{ name: "PROF", value:27 },
Signal{ name: "WINCH", value:28 },
Signal{ name: "INFO", value:29 },
Signal{ name: "USR1", value:30 },
Signal{ name: "USR2", value:31 },
];
pub fn signal_by_name_or_value(signal_name_or_value: &str) -> Option<usize> {
if signal_name_or_value == "0" {
return Some(0);
}
for signal in ALL_SIGNALS.iter() {
let long_name = format!("SIG{}", signal.name);
if signal.name == signal_name_or_value || (signal_name_or_value == signal.value.to_string()) || (long_name == signal_name_or_value) {
return Some(signal.value);
}
}
None
}
#[inline(always)]
pub fn is_signal(num: usize) -> bool {
num < ALL_SIGNALS.len()
}

View file

@ -1,219 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Arcterus <arcterus@mail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
macro_rules! show_error(
($($args:tt)+) => ({
pipe_write!(&mut ::std::io::stderr(), "{}: error: ", ::NAME);
pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
})
);
#[macro_export]
macro_rules! show_warning(
($($args:tt)+) => ({
pipe_write!(&mut ::std::io::stderr(), "{}: warning: ", ::NAME);
pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
})
);
#[macro_export]
macro_rules! show_info(
($($args:tt)+) => ({
pipe_write!(&mut ::std::io::stderr(), "{}: ", ::NAME);
pipe_writeln!(&mut ::std::io::stderr(), $($args)+);
})
);
#[macro_export]
macro_rules! eprint(
($($args:tt)+) => (pipe_write!(&mut ::std::io::stderr(), $($args)+))
);
#[macro_export]
macro_rules! eprintln(
($($args:tt)+) => (pipe_writeln!(&mut ::std::io::stderr(), $($args)+))
);
#[macro_export]
macro_rules! crash(
($exitcode:expr, $($args:tt)+) => ({
show_error!($($args)+);
::std::process::exit($exitcode)
})
);
#[macro_export]
macro_rules! exit(
($exitcode:expr) => ({
::std::process::exit($exitcode)
})
);
#[macro_export]
macro_rules! crash_if_err(
($exitcode:expr, $exp:expr) => (
match $exp {
Ok(m) => m,
Err(f) => crash!($exitcode, "{}", f),
}
)
);
#[macro_export]
macro_rules! pipe_crash_if_err(
($exitcode:expr, $exp:expr) => (
match $exp {
Ok(_) => (),
Err(f) => {
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
()
} else {
crash!($exitcode, "{}", f)
}
},
}
)
);
#[macro_export]
macro_rules! return_if_err(
($exitcode:expr, $exp:expr) => (
match $exp {
Ok(m) => m,
Err(f) => {
show_error!("{}", f);
return $exitcode;
}
}
)
);
// XXX: should the pipe_* macros return an Err just to show the write failed?
#[macro_export]
macro_rules! pipe_print(
($($args:tt)+) => (
match write!(&mut ::std::io::stdout(), $($args)+) {
Ok(_) => true,
Err(f) => {
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
false
} else {
panic!("{}", f)
}
}
}
)
);
#[macro_export]
macro_rules! pipe_println(
($($args:tt)+) => (
match writeln!(&mut ::std::io::stdout(), $($args)+) {
Ok(_) => true,
Err(f) => {
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
false
} else {
panic!("{}", f)
}
}
}
)
);
#[macro_export]
macro_rules! pipe_write(
($fd:expr, $($args:tt)+) => (
match write!($fd, $($args)+) {
Ok(_) => true,
Err(f) => {
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
false
} else {
panic!("{}", f)
}
}
}
)
);
#[macro_export]
macro_rules! pipe_writeln(
($fd:expr, $($args:tt)+) => (
match writeln!($fd, $($args)+) {
Ok(_) => true,
Err(f) => {
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
false
} else {
panic!("{}", f)
}
}
}
)
);
#[macro_export]
macro_rules! pipe_flush(
() => (
match ::std::io::stdout().flush() {
Ok(_) => true,
Err(f) => {
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
false
} else {
panic!("{}", f)
}
}
}
);
($fd:expr) => (
match $fd.flush() {
Ok(_) => true,
Err(f) => {
if f.kind() == ::std::io::ErrorKind::BrokenPipe {
false
} else {
panic!("{}", f)
}
}
}
)
);
#[macro_export]
macro_rules! safe_write(
($fd:expr, $($args:tt)+) => (
match write!($fd, $($args)+) {
Ok(_) => {}
Err(f) => panic!(f.to_string())
}
)
);
#[macro_export]
macro_rules! safe_writeln(
($fd:expr, $($args:tt)+) => (
match writeln!($fd, $($args)+) {
Ok(_) => {}
Err(f) => panic!(f.to_string())
}
)
);
#[macro_export]
macro_rules! safe_unwrap(
($exp:expr) => (
match $exp {
Ok(m) => m,
Err(f) => crash!(1, "{}", f.to_string())
}
)
);

View file

@ -1,126 +0,0 @@
#![allow(non_camel_case_types)]
#![allow(dead_code)]
extern crate libc;
pub use self::utmpx::{DEFAULT_FILE,USER_PROCESS,BOOT_TIME,c_utmp};
#[cfg(target_os = "linux")]
mod utmpx {
use super::libc;
pub static DEFAULT_FILE: &'static str = "/var/run/utmp";
pub const UT_LINESIZE: usize = 32;
pub const UT_NAMESIZE: usize = 32;
pub const UT_IDSIZE: usize = 4;
pub const UT_HOSTSIZE: usize = 256;
pub const EMPTY: libc::c_short = 0;
pub const RUN_LVL: libc::c_short = 1;
pub const BOOT_TIME: libc::c_short = 2;
pub const NEW_TIME: libc::c_short = 3;
pub const OLD_TIME: libc::c_short = 4;
pub const INIT_PROCESS: libc::c_short = 5;
pub const LOGIN_PROCESS: libc::c_short = 6;
pub const USER_PROCESS: libc::c_short = 7;
pub const DEAD_PROCESS: libc::c_short = 8;
pub const ACCOUNTING: libc::c_short = 9;
#[repr(C)]
pub struct c_exit_status {
pub e_termination: libc::c_short,
pub e_exit: libc::c_short,
}
#[repr(C)]
pub struct c_utmp {
pub ut_type: libc::c_short,
pub ut_pid: libc::pid_t,
pub ut_line: [libc::c_char; UT_LINESIZE],
pub ut_id: [libc::c_char; UT_IDSIZE],
pub ut_user: [libc::c_char; UT_NAMESIZE],
pub ut_host: [libc::c_char; UT_HOSTSIZE],
pub ut_exit: c_exit_status,
pub ut_session: libc::c_long,
pub ut_tv: libc::timeval,
pub ut_addr_v6: [libc::int32_t; 4],
pub __unused: [libc::c_char; 20],
}
}
#[cfg(target_os = "macos")]
mod utmpx {
use super::libc;
pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";
pub const UT_LINESIZE: usize = 32;
pub const UT_NAMESIZE: usize = 256;
pub const UT_IDSIZE: usize = 4;
pub const UT_HOSTSIZE: usize = 256;
pub const EMPTY: libc::c_short = 0;
pub const RUN_LVL: libc::c_short = 1;
pub const BOOT_TIME: libc::c_short = 2;
pub const OLD_TIME: libc::c_short = 3;
pub const NEW_TIME: libc::c_short = 4;
pub const INIT_PROCESS: libc::c_short = 5;
pub const LOGIN_PROCESS: libc::c_short = 6;
pub const USER_PROCESS: libc::c_short = 7;
pub const DEAD_PROCESS: libc::c_short = 8;
pub const ACCOUNTING: libc::c_short = 9;
#[repr(C)]
pub struct c_exit_status {
pub e_termination: libc::c_short,
pub e_exit: libc::c_short,
}
#[repr(C)]
pub struct c_utmp {
pub ut_user: [libc::c_char; UT_NAMESIZE],
pub ut_id: [libc::c_char; UT_IDSIZE],
pub ut_line: [libc::c_char; UT_LINESIZE],
pub ut_pid: libc::pid_t,
pub ut_type: libc::c_short,
pub ut_tv: libc::timeval,
pub ut_host: [libc::c_char; UT_HOSTSIZE],
pub __unused: [libc::c_char; 16]
}
}
#[cfg(target_os = "freebsd")]
mod utmpx {
use super::libc;
pub static DEFAULT_FILE : &'static str = "";
pub const UT_LINESIZE : usize = 16;
pub const UT_NAMESIZE : usize = 32;
pub const UT_IDSIZE : usize = 8;
pub const UT_HOSTSIZE : usize = 128;
pub const EMPTY : libc::c_short = 0;
pub const BOOT_TIME : libc::c_short = 1;
pub const OLD_TIME : libc::c_short = 2;
pub const NEW_TIME : libc::c_short = 3;
pub const USER_PROCESS : libc::c_short = 4;
pub const INIT_PROCESS : libc::c_short = 5;
pub const LOGIN_PROCESS : libc::c_short = 6;
pub const DEAD_PROCESS : libc::c_short = 7;
pub const SHUTDOWN_TIME : libc::c_short = 8;
#[repr(C)]
pub struct c_utmp {
pub ut_type : libc::c_short,
pub ut_tv : libc::timeval,
pub ut_id : [libc::c_char; UT_IDSIZE],
pub ut_pid : libc::pid_t,
pub ut_user : [libc::c_char; UT_NAMESIZE],
pub ut_line : [libc::c_char; UT_LINESIZE],
pub ut_host : [libc::c_char; UT_HOSTSIZE],
pub ut_spare : [libc::c_char; 64],
}
}

View file

@ -1,35 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Peter Atashian <retep998@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use std::ffi::{OsStr, OsString};
use std::os::windows::ffi::{OsStrExt, OsStringExt};
pub trait ToWide {
fn to_wide(&self) -> Vec<u16>;
fn to_wide_null(&self) -> Vec<u16>;
}
impl<T> ToWide for T where T: AsRef<OsStr> {
fn to_wide(&self) -> Vec<u16> {
self.as_ref().encode_wide().collect()
}
fn to_wide_null(&self) -> Vec<u16> {
self.as_ref().encode_wide().chain(Some(0)).collect()
}
}
pub trait FromWide {
fn from_wide(wide: &[u16]) -> Self;
fn from_wide_null(wide: &[u16]) -> Self;
}
impl FromWide for String {
fn from_wide(wide: &[u16]) -> String {
OsString::from_wide(wide).to_string_lossy().into_owned()
}
fn from_wide_null(wide: &[u16]) -> String {
let len = wide.iter().take_while(|&&c| c != 0).count();
OsString::from_wide(&wide[..len]).to_string_lossy().into_owned()
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "cp"
version = "0.0.1"
authors = []
[lib]
name = "cp"
path = "cp.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,161 +0,0 @@
#![crate_name = "cp"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordy Dickinson <jordy.dickinson@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
extern crate getopts;
use getopts::Options;
use std::fs;
use std::io::{ErrorKind, Result, Write};
use std::path::Path;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
#[path = "../common/filesystem.rs"]
mod filesystem;
use filesystem::{canonicalize, CanonicalizeMode, UUPathExt};
#[derive(Clone, Eq, PartialEq)]
pub enum Mode {
Copy,
Help,
Version,
}
static NAME: &'static str = "cp";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(e) => {
show_error!("{}", e);
panic!()
},
};
let usage = opts.usage("Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.");
let mode = if matches.opt_present("version") {
Mode::Version
} else if matches.opt_present("help") {
Mode::Help
} else {
Mode::Copy
};
match mode {
Mode::Copy => copy(matches),
Mode::Help => help(&usage),
Mode::Version => version(),
}
0
}
fn version() {
println!("{} {}", NAME, VERSION);
}
fn help(usage: &String) {
let msg = format!("{0} {1}\n\n\
Usage: {0} SOURCE DEST\n \
or: {0} SOURCE... DIRECTORY\n \
or: {0} -t DIRECTORY SOURCE\n\
\n\
{2}", NAME, VERSION, usage);
println!("{}", msg);
}
fn copy(matches: getopts::Matches) {
let sources: Vec<String> = if matches.free.is_empty() {
show_error!("Missing SOURCE argument. Try --help.");
panic!()
} else {
// All but the last argument:
matches.free[..matches.free.len() - 1].iter().map(|arg| arg.clone()).collect()
};
let dest = if matches.free.len() < 2 {
show_error!("Missing DEST argument. Try --help.");
panic!()
} else {
// Only the last argument:
Path::new(&matches.free[matches.free.len() - 1])
};
assert!(sources.len() >= 1);
if sources.len() == 1 {
let source = Path::new(&sources[0]);
let same_file = paths_refer_to_same_file(source, dest).unwrap_or_else(|err| {
match err.kind() {
ErrorKind::NotFound => false,
_ => {
show_error!("{}", err);
panic!()
}
}
});
if same_file {
show_error!("\"{}\" and \"{}\" are the same file",
source.display(),
dest.display());
panic!();
}
if let Err(err) = fs::copy(source, dest) {
show_error!("{}", err);
panic!();
}
} else {
if !dest.uu_is_dir() {
show_error!("TARGET must be a directory");
panic!();
}
for src in sources.iter() {
let source = Path::new(&src);
if !source.uu_is_file() {
show_error!("\"{}\" is not a file", source.display());
continue;
}
let mut full_dest = dest.to_path_buf();
full_dest.push(source.to_str().unwrap());
println!("{}", full_dest.display());
let io_result = fs::copy(source, full_dest);
if let Err(err) = io_result {
show_error!("{}", err);
panic!()
}
}
}
}
pub fn paths_refer_to_same_file(p1: &Path, p2: &Path) -> Result<bool> {
// We have to take symlinks and relative paths into account.
let pathbuf1 = try!(canonicalize(p1, CanonicalizeMode::Normal));
let pathbuf2 = try!(canonicalize(p2, CanonicalizeMode::Normal));
Ok(pathbuf1 == pathbuf2)
}

View file

@ -1,12 +0,0 @@
[package]
name = "cut"
version = "0.0.1"
authors = []
[lib]
name = "cut"
path = "cut.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,151 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Rolf Morel <rolfmorel@gmail.com>
* (c) kwantam <kwantam@gmail.com>
* substantially rewritten to use the stdlib BufReader trait
* rather than re-implementing it here.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use std::io::{BufRead, BufReader, Read, Write};
use std::io::Result as IoResult;
#[allow(non_snake_case)]
pub mod Bytes {
use std::io::Write;
pub trait Select {
fn select<W: Write>(&mut self, bytes: usize, out: Option<&mut W>) -> Selected;
}
#[derive(PartialEq, Eq, Debug)]
pub enum Selected {
NewlineFound,
Complete(usize),
Partial(usize),
EndOfFile,
}
}
#[derive(Debug)]
pub struct ByteReader<R> where R: Read {
inner: BufReader<R>,
}
impl<R: Read> ByteReader<R> {
pub fn new(read: R) -> ByteReader<R> {
ByteReader {
inner: BufReader::with_capacity(4096, read),
}
}
}
impl<R: Read> Read for ByteReader<R> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
self.inner.read(buf)
}
}
impl<R: Read> BufRead for ByteReader<R> {
fn fill_buf(&mut self) -> IoResult<&[u8]> {
self.inner.fill_buf()
}
fn consume(&mut self, amt: usize) {
self.inner.consume(amt)
}
}
impl<R: Read> ByteReader<R> {
pub fn consume_line(&mut self) -> usize {
let mut bytes_consumed = 0;
let mut consume_val;
loop {
{ // need filled_buf to go out of scope
let filled_buf = match self.fill_buf() {
Ok(b) => {
if b.len() == 0 {
return bytes_consumed
} else {
b
}
},
Err(e) => crash!(1, "read error: {}", e),
};
match filled_buf.iter().position(|byte| *byte == b'\n') {
Some(idx) => {
consume_val = idx + 1;
bytes_consumed += consume_val;
break;
}
_ => ()
}
consume_val = filled_buf.len();
}
bytes_consumed += consume_val;
self.consume(consume_val);
}
self.consume(consume_val);
return bytes_consumed;
}
}
impl<R: Read> self::Bytes::Select for ByteReader<R> {
fn select<W: Write>(&mut self, bytes: usize, out: Option<&mut W>) -> Bytes::Selected {
enum SRes {
Comp,
Part,
Newl,
};
use self::Bytes::Selected::*;
let (res, consume_val) = {
let buffer = match self.fill_buf() {
Err(e) => crash!(1, "read error: {}", e),
Ok(b) => b,
};
let (res, consume_val) = match buffer.len() {
0 => return EndOfFile,
buf_used if bytes < buf_used => {
// because the output delimiter should only be placed between
// segments check if the byte after bytes is a newline
let buf_slice = &buffer[0..bytes + 1];
match buf_slice.iter().position(|byte| *byte == b'\n') {
Some(idx) => (SRes::Newl, idx+1),
None => (SRes::Comp, bytes),
}
},
_ => {
match buffer.iter().position(|byte| *byte == b'\n') {
Some(idx) => (SRes::Newl, idx+1),
None => (SRes::Part, buffer.len()),
}
},
};
match out {
Some(out) => pipe_crash_if_err!(1, out.write_all(&buffer[0..consume_val])),
None => (),
}
(res, consume_val)
};
self.consume(consume_val);
match res {
SRes::Comp => Complete(consume_val),
SRes::Part => Partial(consume_val),
SRes::Newl => NewlineFound,
}
}
}

View file

@ -1,546 +0,0 @@
#![crate_name = "cut"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Rolf Morel <rolfmorel@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
use std::fs::File;
use std::io::{stdout, stdin, BufRead, BufReader, Read, Stdout, Write};
use std::path::Path;
use ranges::Range;
use searcher::Searcher;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
#[path = "../common/filesystem.rs"]
mod filesystem;
use filesystem::UUPathExt;
mod buffer;
mod ranges;
mod searcher;
static NAME: &'static str = "cut";
static VERSION: &'static str = "1.0.0";
struct Options {
out_delim: Option<String>,
}
struct FieldOptions {
delimiter: String, // one char long, String because of UTF8 representation
out_delimeter: Option<String>,
only_delimited: bool,
}
enum Mode {
Bytes(Vec<Range>, Options),
Characters(Vec<Range>, Options),
Fields(Vec<Range>, FieldOptions),
}
fn list_to_ranges(list: &str, complement: bool) -> Result<Vec<Range>, String> {
if complement {
Range::from_list(list).map(|r| ranges::complement(&r))
} else {
Range::from_list(list)
}
}
fn cut_bytes<R: Read>(reader: R, ranges: &Vec<Range>, opts: &Options) -> i32 {
use buffer::Bytes::Select;
use buffer::Bytes::Selected::*;
let mut buf_read = buffer::ByteReader::new(reader);
let mut out = stdout();
'newline: loop {
let mut cur_pos = 1;
let mut print_delim = false;
for &Range { low, high } in ranges.iter() {
// skip upto low
let orig_pos = cur_pos;
loop {
match buf_read.select(low - cur_pos, None::<&mut Stdout>) {
NewlineFound => {
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
continue 'newline
}
Complete(len) => {
cur_pos += len;
break
}
Partial(len) => cur_pos += len,
EndOfFile => {
if orig_pos != cur_pos {
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
}
break 'newline
}
}
}
match opts.out_delim {
Some(ref delim) => {
if print_delim {
pipe_crash_if_err!(1, out.write_all(delim.as_bytes()));
}
print_delim = true;
}
None => ()
}
// write out from low to high
loop {
match buf_read.select(high - cur_pos + 1, Some(&mut out)) {
NewlineFound => continue 'newline,
Partial(len) => cur_pos += len,
Complete(_) => {
cur_pos = high + 1;
break
}
EndOfFile => {
if cur_pos != low || low == high {
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
}
break 'newline
}
}
}
}
buf_read.consume_line();
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
}
0
}
fn cut_characters<R: Read>(reader: R, ranges: &Vec<Range>, opts: &Options) -> i32 {
let mut buf_in = BufReader::new(reader);
let mut out = stdout();
let mut buffer = String::new();
'newline: loop {
buffer.clear();
match buf_in.read_line(&mut buffer) {
Ok(n) if n == 0 => break,
Err(e) => {
if buffer.len() == 0 {
crash!(1, "read error: {}", e);
}
},
_ => (),
};
let line = &buffer[..];
let mut char_pos = 0;
let mut char_indices = line.char_indices();
let mut print_delim = false;
let mut low_idx = 0;
for &Range { low, high } in ranges.iter() {
low_idx = if low - char_pos > 0 {
match char_indices.nth(low - char_pos - 1) {
Some((low_idx, _)) => low_idx,
None => break,
}
} else {
low_idx
};
match opts.out_delim {
Some(ref delim) => {
if print_delim {
pipe_crash_if_err!(1, out.write_all(delim.as_bytes()));
}
print_delim = true;
}
None => ()
}
match char_indices.nth(high - low) {
Some((high_idx, _)) => {
let segment = &line.as_bytes()[low_idx..high_idx];
low_idx = high_idx;
pipe_crash_if_err!(1, out.write_all(segment));
}
None => {
let bytes = line.as_bytes();
let segment = &bytes[low_idx..];
pipe_crash_if_err!(1, out.write_all(segment));
if line.as_bytes()[bytes.len() - 1] == b'\n' {
continue 'newline
}
}
}
char_pos = high + 1;
}
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
}
0
}
fn cut_fields_delimiter<R: Read>(reader: R, ranges: &Vec<Range>, delim: &String, only_delimited: bool, out_delim: &String) -> i32 {
let mut buf_in = BufReader::new(reader);
let mut out = stdout();
let mut buffer = Vec::new();
'newline: loop {
buffer.clear();
match buf_in.read_until(b'\n', &mut buffer) {
Ok(n) if n == 0 => break,
Err(e) => {
if buffer.len() == 0 {
crash!(1, "read error: {}", e);
}
},
_ => (),
}
let line = &buffer[..];
let mut fields_pos = 1;
let mut low_idx = 0;
let mut delim_search = Searcher::new(line, delim.as_bytes()).peekable();
let mut print_delim = false;
if delim_search.peek().is_none() {
if ! only_delimited {
pipe_crash_if_err!(1, out.write_all(line));
if line[line.len() - 1] != b'\n' {
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
}
}
continue
}
for &Range { low, high } in ranges.iter() {
if low - fields_pos > 0 {
low_idx = match delim_search.nth(low - fields_pos - 1) {
Some((_, beyond_delim)) => beyond_delim,
None => break
};
}
for _ in 0..high - low + 1 {
if print_delim {
pipe_crash_if_err!(1, out.write_all(out_delim.as_bytes()));
}
match delim_search.next() {
Some((high_idx, next_low_idx)) => {
let segment = &line[low_idx..high_idx];
pipe_crash_if_err!(1, out.write_all(segment));
print_delim = true;
low_idx = next_low_idx;
fields_pos = high + 1;
}
None => {
let segment = &line[low_idx..];
pipe_crash_if_err!(1, out.write_all(segment));
if line[line.len() - 1] == b'\n' {
continue 'newline
}
break
}
}
}
}
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
}
0
}
fn cut_fields<R: Read>(reader: R, ranges: &Vec<Range>, opts: &FieldOptions) -> i32 {
match opts.out_delimeter {
Some(ref o_delim) => {
return cut_fields_delimiter(reader, ranges, &opts.delimiter,
opts.only_delimited, o_delim);
}
None => ()
}
let mut buf_in = BufReader::new(reader);
let mut out = stdout();
let mut buffer = Vec::new();
'newline: loop {
buffer.clear();
match buf_in.read_until(b'\n', &mut buffer) {
Ok(n) if n == 0 => break,
Err(e) => {
if buffer.len() == 0 {
crash!(1, "read error: {}", e);
}
},
_ => (),
}
let line = &buffer[..];
let mut fields_pos = 1;
let mut low_idx = 0;
let mut delim_search = Searcher::new(line, opts.delimiter.as_bytes()).peekable();
let mut print_delim = false;
if delim_search.peek().is_none() {
if ! opts.only_delimited {
pipe_crash_if_err!(1, out.write_all(line));
if line[line.len() - 1] != b'\n' {
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
}
}
continue
}
for &Range { low, high } in ranges.iter() {
if low - fields_pos > 0 {
low_idx = match delim_search.nth(low - fields_pos - 1) {
Some((_, beyond_delim)) => beyond_delim,
None => break
};
}
if print_delim {
if low_idx >= opts.delimiter.as_bytes().len() {
low_idx -= opts.delimiter.as_bytes().len();
}
}
match delim_search.nth(high - low) {
Some((high_idx, next_low_idx)) => {
let segment = &line[low_idx..high_idx];
pipe_crash_if_err!(1, out.write_all(segment));
print_delim = true;
low_idx = next_low_idx;
fields_pos = high + 1;
}
None => {
let segment = &line[low_idx..line.len()];
pipe_crash_if_err!(1, out.write_all(segment));
if line[line.len() - 1] == b'\n' {
continue 'newline
}
break
}
}
}
pipe_crash_if_err!(1, out.write_all(&[b'\n']));
}
0
}
fn cut_files(mut filenames: Vec<String>, mode: Mode) -> i32 {
let mut stdin_read = false;
let mut exit_code = 0;
if filenames.len() == 0 { filenames.push("-".to_string()); }
for filename in filenames.iter() {
if filename == "-" {
if stdin_read { continue }
exit_code |= match mode {
Mode::Bytes(ref ranges, ref opts) => cut_bytes(stdin(), ranges, opts),
Mode::Characters(ref ranges, ref opts) => cut_characters(stdin(), ranges, opts),
Mode::Fields(ref ranges, ref opts) => cut_fields(stdin(), ranges, opts),
};
stdin_read = true;
} else {
let path = Path::new(&filename[..]);
if !path.uu_exists() {
show_error!("{}: No such file or directory", filename);
continue
}
let file = match File::open(&path) {
Ok(f) => f,
Err(e) => {
show_error!("opening '{}': {}", &filename[..], e);
continue
}
};
exit_code |= match mode {
Mode::Bytes(ref ranges, ref opts) => cut_bytes(file, ranges, opts),
Mode::Characters(ref ranges, ref opts) => cut_characters(file, ranges, opts),
Mode::Fields(ref ranges, ref opts) => cut_fields(file, ranges, opts),
};
}
}
exit_code
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optopt("b", "bytes", "select only these bytes", "LIST");
opts.optopt("c", "characters", "select only these characters", "LIST");
opts.optopt("d", "delimiter", "use DELIM instead of TAB for field delimiter", "DELIM");
opts.optopt("f", "fields", "select only these fields; also print any line that contains no delimiter character, unless the -s option is specified", "LIST");
opts.optflag("n", "", "(ignored)");
opts.optflag("", "complement", "complement the set of selected bytes, characters or fields");
opts.optflag("s", "only-delimited", "do not print lines not containing delimiters");
opts.optopt("", "output-delimiter", "use STRING as the output delimiter the default is to use the input delimiter", "STRING");
opts.optflag("", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
show_error!("Invalid options\n{}", f);
return 1;
}
};
if matches.opt_present("help") {
println!("{} {}", NAME, VERSION);
println!("");
println!("Usage:");
println!(" {0} OPTION... [FILE]...", NAME);
println!("");
println!("{}", opts.usage("Print selected parts of lines from each FILE to standard output."));
println!("");
println!("Use one, and only one of -b, -c or -f. Each LIST is made up of one");
println!("range, or many ranges separated by commas. Selected input is written");
println!("in the same order that it is read, and is written exactly once.");
println!("Each range is one of:");
println!("");
println!(" N N'th byte, character or field, counted from 1");
println!(" N- from N'th byte, character or field, to end of line");
println!(" N-M from N'th to M'th (included) byte, character or field");
println!(" -M from first to M'th (included) byte, character or field");
println!("");
println!("With no FILE, or when FILE is -, read standard input.");
return 0;
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
let complement = matches.opt_present("complement");
let mode_parse = match (matches.opt_str("bytes"),
matches.opt_str("characters"),
matches.opt_str("fields")) {
(Some(byte_ranges), None, None) => {
list_to_ranges(&byte_ranges[..], complement)
.map(|ranges| Mode::Bytes(ranges, Options { out_delim: matches.opt_str("output-delimiter") }))
}
(None, Some(char_ranges), None) => {
list_to_ranges(&char_ranges[..], complement)
.map(|ranges| Mode::Characters(ranges, Options { out_delim: matches.opt_str("output-delimiter") }))
}
(None, None, Some(field_ranges)) => {
list_to_ranges(&field_ranges[..], complement).and_then(|ranges|
{
let out_delim = match matches.opt_str("output-delimiter") {
Some(s) => {
if s.len() == 0 {
Some("\0".to_string())
} else {
Some(s)
}
},
None => None,
};
let only_delimited = matches.opt_present("only-delimited");
match matches.opt_str("delimiter") {
Some(delim) => {
if delim.chars().count() > 1 {
Err("the delimiter must be a single character, or the empty string for null".to_string())
} else {
let delim = if delim.len() == 0 {
"\0".to_string()
} else {
delim
};
Ok(Mode::Fields(ranges,
FieldOptions {
delimiter: delim,
out_delimeter: out_delim,
only_delimited: only_delimited
}))
}
}
None => Ok(Mode::Fields(ranges,
FieldOptions {
delimiter: "\t".to_string(),
out_delimeter: out_delim,
only_delimited: only_delimited
}))
}
}
)
}
(ref b, ref c, ref f) if b.is_some() || c.is_some() || f.is_some() => {
Err("only one type of list may be specified".to_string())
}
_ => Err("you must specify a list of bytes, characters, or fields".to_string())
};
let mode_parse = match mode_parse {
Err(_) => mode_parse,
Ok(mode) => {
match mode {
Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.opt_present("delimiter") =>
Err("an input delimiter may be specified only when operating on fields".to_string()),
Mode::Bytes(_, _) | Mode::Characters(_, _) if matches.opt_present("only-delimited") =>
Err("suppressing non-delimited lines makes sense only when operating on fields".to_string()),
_ => Ok(mode),
}
}
};
match mode_parse {
Ok(mode) => cut_files(matches.free, mode),
Err(err_msg) => {
show_error!("{}\n\
Try '{} --help' for more information",
err_msg, args[0]);
1
}
}
}

View file

@ -1,133 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Rolf Morel <rolfmorel@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use std::str::FromStr;
#[derive(PartialEq,Eq,PartialOrd,Ord,Debug)]
pub struct Range {
pub low: usize,
pub high: usize,
}
impl FromStr for Range {
type Err = &'static str;
fn from_str(s: &str) -> Result<Range, &'static str> {
use std::usize::MAX;
let mut parts = s.splitn(2, '-');
let field = "fields and positions are numbered from 1";
let order = "high end of range less than low end";
let inval = "failed to parse range";
match (parts.next(), parts.next()) {
(Some(nm), None) => {
if let Ok(nm) = nm.parse::<usize>() {
if nm > 0 { Ok(Range{ low: nm, high: nm}) } else { Err(field) }
} else {
Err(inval)
}
}
(Some(n), Some(m)) if m.len() == 0 => {
if let Ok(low) = n.parse::<usize>() {
if low > 0 { Ok(Range{ low: low, high: MAX}) } else { Err(field) }
} else {
Err(inval)
}
}
(Some(n), Some(m)) if n.len() == 0 => {
if let Ok(high) = m.parse::<usize>() {
if high > 0 { Ok(Range{ low: 1, high: high}) } else { Err(field) }
} else {
Err(inval)
}
}
(Some(n), Some(m)) => {
match (n.parse::<usize>(), m.parse::<usize>()) {
(Ok(low), Ok(high)) => {
if low > 0 && low <= high {
Ok(Range { low: low, high: high })
} else if low == 0 {
Err(field)
} else {
Err(order)
}
},
_ => Err(inval),
}
}
_ => unreachable!()
}
}
}
impl Range {
pub fn from_list(list: &str) -> Result<Vec<Range>, String> {
use std::cmp::max;
let mut ranges : Vec<Range> = vec!();
for item in list.split(',') {
match FromStr::from_str(item) {
Ok(range_item) => ranges.push(range_item),
Err(e)=> return Err(format!("range '{}' was invalid: {}", item, e))
}
}
ranges.sort();
// merge overlapping ranges
for i in 0..ranges.len() {
let j = i + 1;
while j < ranges.len() && ranges[j].low <= ranges[i].high {
let j_high = ranges.remove(j).high;
ranges[i].high = max(ranges[i].high, j_high);
}
}
Ok(ranges)
}
}
pub fn complement(ranges: &Vec<Range>) -> Vec<Range> {
use std::usize;
let mut complements = Vec::with_capacity(ranges.len() + 1);
if ranges.len() > 0 && ranges[0].low > 1 {
complements.push(Range { low: 1, high: ranges[0].low - 1 });
}
let mut ranges_iter = ranges.iter().peekable();
loop {
match (ranges_iter.next(), ranges_iter.peek()) {
(Some(left), Some(right)) => {
if left.high + 1 != right.low {
complements.push(Range {
low: left.high + 1,
high: right.low - 1
});
}
}
(Some(last), None) => {
if last.high < usize::MAX {
complements.push(Range {
low: last.high + 1,
high: usize::MAX
});
}
}
_ => break
}
}
complements
}

View file

@ -1,54 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Rolf Morel <rolfmorel@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#[derive(Clone)]
pub struct Searcher<'a> {
haystack: &'a [u8],
needle: &'a [u8],
position: usize
}
impl<'a> Searcher<'a> {
pub fn new(haystack: &'a [u8], needle: &'a [u8]) -> Searcher<'a> {
Searcher {
haystack: haystack,
needle: needle,
position: 0
}
}
}
impl<'a> Iterator for Searcher<'a> {
type Item = (usize, usize);
fn next(&mut self) -> Option<(usize, usize)> {
if self.needle.len() == 1 {
for offset in self.position..self.haystack.len() {
if self.haystack[offset] == self.needle[0] {
self.position = offset + 1;
return Some((offset, offset + 1));
}
}
self.position = self.haystack.len();
return None;
}
while self.position + self.needle.len() <= self.haystack.len() {
if &self.haystack[self.position..self.position + self.needle.len()] == self.needle {
let match_pos = self.position;
self.position += self.needle.len();
return Some((match_pos, match_pos + self.needle.len()));
} else {
self.position += 1;
}
}
None
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "dirname"
version = "0.0.1"
authors = []
[lib]
name = "dirname"
path = "dirname.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,70 +0,0 @@
#![crate_name = "dirname"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Derek Chiang <derekchiang93@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
use std::path::Path;
static NAME: &'static str = "dirname";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("z", "zero", "separate output with NUL rather than newline");
opts.optflag("", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => panic!("Invalid options\n{}", f)
};
if matches.opt_present("help") {
let msg = format!("{0} {1} - strip last component from file name
Usage:
{0} [OPTION] NAME...
Output each NAME with its last non-slash component and trailing slashes
removed; if NAME contains no /'s, output '.' (meaning the current
directory).", NAME, VERSION);
print!("{}", opts.usage(&msg));
return 0;
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
let separator = match matches.opt_present("zero") {
true => "\0",
false => "\n"
};
if !matches.free.is_empty() {
for path in matches.free.iter() {
let p = Path::new(path);
let d = p.parent().unwrap().to_str();
if d.is_some() {
print!("{}", d.unwrap());
}
print!("{}", separator);
}
} else {
println!("{0}: missing operand", NAME);
println!("Try '{0} --help' for more information.", NAME);
return 1;
}
0
}

View file

@ -1,13 +0,0 @@
[package]
name = "du"
version = "0.0.1"
authors = []
[lib]
name = "du"
path = "du.rs"
[dependencies]
getopts = "*"
libc = "*"
time = "*"

View file

@ -1 +0,0 @@
DEPLIBS += time kernel32 winapi

View file

@ -1,398 +0,0 @@
#![crate_name = "du"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Derek Chiang <derekchiang93@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
#![allow(non_snake_case)]
extern crate getopts;
extern crate libc;
extern crate time;
use std::fs;
use std::io::{stderr, Write};
use std::os::unix::fs::MetadataExt;
use std::path::PathBuf;
use std::sync::Arc;
use time::Timespec;
use std::sync::mpsc::channel;
use std::thread;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "du";
static VERSION: &'static str = "1.0.0";
struct Options {
all: bool,
program_name: String,
max_depth: Option<usize>,
total: bool,
separate_dirs: bool,
}
struct Stat {
path: PathBuf,
is_dir: bool,
size: u64,
blocks: u64,
nlink: u64,
created: u64,
accessed: u64,
modified: u64,
}
impl Stat {
fn new(path: &PathBuf) -> Stat {
let metadata = safe_unwrap!(fs::metadata(path));
Stat {
path: path.clone(),
is_dir: metadata.is_dir(),
size: metadata.len(),
blocks: metadata.blocks() as u64,
nlink: metadata.nlink() as u64,
created: metadata.mtime() as u64,
accessed: metadata.atime() as u64,
modified: metadata.mtime() as u64
}
}
}
// this takes `my_stat` to avoid having to stat files multiple times.
fn du(path: &PathBuf, mut my_stat: Stat, options: Arc<Options>, depth: usize) -> Vec<Arc<Stat>> {
let mut stats = vec!();
let mut futures = vec!();
if my_stat.is_dir {
let read = match fs::read_dir(path) {
Ok(read) => read,
Err(e) => {
safe_writeln!(stderr(), "{}: cannot read directory {}: {}",
options.program_name, path.display(), e);
return vec!(Arc::new(my_stat))
}
};
for f in read.into_iter() {
let entry = f.unwrap();
let this_stat = Stat::new(&entry.path());
if this_stat.is_dir {
let oa_clone = options.clone();
let (tx, rx) = channel();
thread::spawn(move || {
let result = du(&entry.path(), this_stat, oa_clone, depth + 1);
tx.send(result)
});
futures.push(rx);
} else {
my_stat.size += this_stat.size;
my_stat.blocks += this_stat.blocks;
if options.all {
stats.push(Arc::new(this_stat))
}
}
}
}
for rx in futures.iter_mut() {
for stat in rx.recv().unwrap().into_iter().rev() {
if !options.separate_dirs && stat.path.parent().unwrap().to_path_buf() == my_stat.path {
my_stat.size += stat.size;
my_stat.blocks += stat.blocks;
}
if options.max_depth == None || depth < options.max_depth.unwrap() {
stats.push(stat.clone());
}
}
}
stats.push(Arc::new(my_stat));
stats
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
// In task
opts.optflag("a", "all", " write counts for all files, not just directories");
// In main
opts.optflag("", "apparent-size", "print apparent sizes, rather than disk usage;
although the apparent size is usually smaller, it may be larger due to holes
in ('sparse') files, internal fragmentation, indirect blocks, and the like");
// In main
opts.optopt("B", "block-size", "scale sizes by SIZE before printing them.
E.g., '-BM' prints sizes in units of 1,048,576 bytes. See SIZE format below.",
"SIZE");
// In main
opts.optflag("b", "bytes", "equivalent to '--apparent-size --block-size=1'");
// In main
opts.optflag("c", "total", "produce a grand total");
// In task
// opts.optflag("D", "dereference-args", "dereference only symlinks that are listed
// on the command line"),
// In main
// opts.optopt("", "files0-from", "summarize disk usage of the NUL-terminated file
// names specified in file F;
// If F is - then read names from standard input", "F"),
// // In task
// opts.optflag("H", "", "equivalent to --dereference-args (-D)"),
// In main
opts.optflag("h", "human-readable", "print sizes in human readable format (e.g., 1K 234M 2G)");
// In main
opts.optflag("", "si", "like -h, but use powers of 1000 not 1024");
// In main
opts.optflag("k", "", "like --block-size=1K");
// In task
opts.optflag("l", "count-links", "count sizes many times if hard linked");
// // In main
opts.optflag("m", "", "like --block-size=1M");
// // In task
// opts.optflag("L", "dereference", "dereference all symbolic links"),
// // In task
// opts.optflag("P", "no-dereference", "don't follow any symbolic links (this is the default)"),
// // In main
opts.optflag("0", "null", "end each output line with 0 byte rather than newline");
// In main
opts.optflag("S", "separate-dirs", "do not include size of subdirectories");
// In main
opts.optflag("s", "summarize", "display only a total for each argument");
// // In task
// opts.optflag("x", "one-file-system", "skip directories on different file systems"),
// // In task
// opts.optopt("X", "exclude-from", "exclude files that match any pattern in FILE", "FILE"),
// // In task
// opts.optopt("", "exclude", "exclude files that match PATTERN", "PATTERN"),
// In main
opts.optopt("d", "max-depth", "print the total for a directory (or file, with --all)
only if it is N or fewer levels below the command
line argument; --max-depth=0 is the same as --summarize", "N");
// In main
opts.optflagopt("", "time", "show time of the last modification of any file in the
directory, or any of its subdirectories. If WORD is given, show time as WORD instead of modification time:
atime, access, use, ctime or status", "WORD");
// In main
opts.optopt("", "time-style", "show times using style STYLE:
full-iso, long-iso, iso, +FORMAT FORMAT is interpreted like 'date'", "STYLE");
opts.optflag("", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
show_error!("Invalid options\n{}", f);
return 1;
}
};
if matches.opt_present("help") {
println!("{program} {version} - estimate file space usage
Usage
{program} [OPTION]... [FILE]...
{program} [OPTION]... --files0-from=F
{usage}
Display values are in units of the first available SIZE from
--block-size, and the DU_BLOCK_SIZE, BLOCK_SIZE and BLOCKSIZE environ
ment variables. Otherwise, units default to 1024 bytes (or 512 if
POSIXLY_CORRECT is set).
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, ... (pow
ers of 1000).",
program = NAME,
version = VERSION,
usage = opts.usage("Summarize disk usage of each FILE, recursively for directories."));
return 0;
} else if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
let summarize = matches.opt_present("summarize");
let max_depth_str = matches.opt_str("max-depth");
let max_depth = max_depth_str.as_ref().and_then(|s| s.parse::<usize>().ok());
match (max_depth_str, max_depth) {
(Some(ref s), _) if summarize => {
show_error!("summarizing conflicts with --max-depth={}", *s);
return 1;
}
(Some(ref s), None) => {
show_error!("invalid maximum depth '{}'", *s);
return 1;
}
(Some(_), Some(_)) | (None, _) => { /* valid */ }
}
let options = Options {
all: matches.opt_present("all"),
program_name: NAME.to_string(),
max_depth: max_depth,
total: matches.opt_present("total"),
separate_dirs: matches.opt_present("S"),
};
let strs = if matches.free.is_empty() {vec!("./".to_string())} else {matches.free.clone()};
let options_arc = Arc::new(options);
let MB = match matches.opt_present("si") {
true => 1000 * 1000,
false => 1024 * 1024,
};
let KB = match matches.opt_present("si") {
true => 1000,
false => 1024,
};
let block_size = match matches.opt_str("block-size") {
Some(s) => {
let mut found_number = false;
let mut found_letter = false;
let mut numbers = String::new();
let mut letters = String::new();
for c in s.chars() {
if found_letter && c.is_digit(10) || !found_number && !c.is_digit(10) {
show_error!("invalid --block-size argument '{}'", s);
return 1;
} else if c.is_digit(10) {
found_number = true;
numbers.push(c);
} else if c.is_alphabetic() {
found_letter = true;
letters.push(c);
}
}
let number = numbers.parse::<u64>().unwrap();
let multiple = match &letters[..] {
"K" => 1024u64.pow(1), "M" => 1024u64.pow(2),
"G" => 1024u64.pow(3), "T" => 1024u64.pow(4),
"P" => 1024u64.pow(5), "E" => 1024u64.pow(6),
"Z" => 1024u64.pow(7), "Y" => 1024u64.pow(8),
"KB" => 1000u64.pow(1), "MB" => 1000u64.pow(2),
"GB" => 1000u64.pow(3), "TB" => 1000u64.pow(4),
"PB" => 1000u64.pow(5), "EB" => 1000u64.pow(6),
"ZB" => 1000u64.pow(7), "YB" => 1000u64.pow(8),
_ => {
show_error!("invalid --block-size argument '{}'", s);
return 1;
}
};
number * multiple
},
None => 1024
};
let convert_size = |size: u64| -> String {
if matches.opt_present("human-readable") || matches.opt_present("si") {
if size >= MB {
format!("{:.1}M", (size as f64) / (MB as f64))
} else if size >= KB {
format!("{:.1}K", (size as f64) / (KB as f64))
} else {
format!("{}B", size)
}
} else if matches.opt_present("k") {
format!("{}", ((size as f64) / (KB as f64)).ceil())
} else if matches.opt_present("m") {
format!("{}", ((size as f64) / (MB as f64)).ceil())
} else {
format!("{}", ((size as f64) / (block_size as f64)).ceil())
}
};
let time_format_str = match matches.opt_str("time-style") {
Some(s) => {
match &s[..] {
"full-iso" => "%Y-%m-%d %H:%M:%S.%f %z",
"long-iso" => "%Y-%m-%d %H:%M",
"iso" => "%Y-%m-%d",
_ => {
show_error!("invalid argument '{}' for 'time style'
Valid arguments are:
- 'full-iso'
- 'long-iso'
- 'iso'
Try '{} --help' for more information.", s, NAME);
return 1;
}
}
},
None => "%Y-%m-%d %H:%M"
};
let line_separator = match matches.opt_present("0") {
true => "\0",
false => "\n",
};
let mut grand_total = 0;
for path_str in strs.into_iter() {
let path = PathBuf::from(path_str);
let iter = du(&path, Stat::new(&path), options_arc.clone(), 0).into_iter();
let (_, len) = iter.size_hint();
let len = len.unwrap();
for (index, stat) in iter.enumerate() {
let size = match matches.opt_present("apparent-size") {
true => stat.nlink * stat.size,
// C's stat is such that each block is assume to be 512 bytes
// See: http://linux.die.net/man/2/stat
false => stat.blocks * 512,
};
if matches.opt_present("time") {
let tm = {
let (secs, nsecs) = {
let time = match matches.opt_str("time") {
Some(s) => match &s[..] {
"accessed" => stat.accessed,
"created" => stat.created,
"modified" => stat.modified,
_ => {
show_error!("invalid argument 'modified' for '--time'
Valid arguments are:
- 'accessed', 'created', 'modified'
Try '{} --help' for more information.", NAME);
return 1;
}
},
None => stat.modified
};
((time / 1000) as i64, (time % 1000 * 1000000) as i32)
};
time::at(Timespec::new(secs, nsecs))
};
if !summarize || (summarize && index == len-1) {
let time_str = tm.strftime(time_format_str).unwrap();
print!("{}\t{}\t{}{}", convert_size(size), time_str, stat.path.display(), line_separator);
}
} else {
if !summarize || (summarize && index == len-1) {
print!("{}\t{}{}", convert_size(size), stat.path.display(), line_separator);
}
}
if options_arc.total && index == (len - 1) {
// The last element will be the total size of the the path under
// path_str. We add it to the grand total.
grand_total += size;
}
}
}
if options_arc.total {
print!("{}\ttotal", convert_size(grand_total));
print!("{}", line_separator);
}
0
}

View file

@ -1,12 +0,0 @@
[package]
name = "echo"
version = "0.0.1"
authors = []
[lib]
name = "echo"
path = "echo.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,254 +0,0 @@
#![crate_name = "echo"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Derek Chiang <derekchiang93@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
use std::io::Write;
use std::str::from_utf8;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
#[allow(dead_code)]
static NAME: &'static str = "echo";
static VERSION: &'static str = "1.0.0";
#[derive(Clone)]
struct EchoOptions {
newline: bool,
escape: bool
}
#[inline(always)]
fn to_char(bytes: &Vec<u8>, base: u32) -> char {
usize::from_str_radix(from_utf8(bytes.as_ref()).unwrap(), base).unwrap() as u8 as char
}
#[inline(always)]
fn isxdigit(c: u8) -> bool {
match c as char {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
'8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' => true,
_ => false
}
}
#[inline(always)]
fn isodigit(c: u8) -> bool {
match c as char {
'0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => true,
_ => false
}
}
fn convert_str(string: &[u8], index: usize, base: u32) -> (char, usize) {
let (max_digits, is_legal_digit) : (usize, fn(u8) -> bool) = match base {
8 => (3, isodigit),
16 => (2, isxdigit),
_ => panic!(),
};
let mut bytes = vec!();
for offset in 0usize .. max_digits {
if string.len() <= index + offset as usize {
break;
}
let c = string[index + offset as usize];
if is_legal_digit(c) {
bytes.push(c as u8);
} else {
break;
}
}
if bytes.len() == 0 {
(' ', 0)
} else {
(to_char(&bytes, base), bytes.len())
}
}
fn parse_options(args: Vec<String>, options: &mut EchoOptions) -> Option<Vec<String>> {
let mut echo_args = vec!();
'argloop: for arg in args.into_iter().skip(1) {
match arg.as_ref() {
"--help" | "-h" => {
print_help();
return None;
}
"--version" | "-V" => {
print_version();
return None;
}
"-n" => options.newline = true,
"-e" => options.escape = true,
"-E" => options.escape = false,
_ => {
if arg.len() > 1 && arg.chars().next().unwrap_or('_') == '-' {
let mut newopts = options.clone();
for ch in arg.chars().skip(1) {
match ch {
'h' => {
print_help();
return None;
}
'V' => {
print_version();
return None;
}
'n' => newopts.newline = true,
'e' => newopts.escape = true,
'E' => newopts.escape = false,
_ => {
echo_args.push(arg.clone());
continue 'argloop;
}
}
}
*options = newopts;
} else {
echo_args.push(arg);
}
}
}
}
Some(echo_args)
}
fn print_help() {
let mut opts = getopts::Options::new();
opts.optflag("n", "", "do not output the trailing newline");
opts.optflag("e", "", "enable interpretation of backslash escapes");
opts.optflag("E", "", "disable interpretation of backslash escapes (default)");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let msg = format!("{0} {1} - display a line of text
Usage:
{0} [SHORT-OPTION]... [STRING]...
{0} LONG-OPTION
Echo the STRING(s) to standard output.
If -e is in effect, the following sequences are recognized:
\\\\ backslash
\\a alert (BEL)
\\b backspace
\\c produce no further output
\\e escape
\\f form feed
\\n new line
\\r carriage return
\\t horizontal tab
\\v vertical tab
\\0NNN byte with octal value NNN (1 to 3 digits)
\\xHH byte with hexadecimal value HH (1 to 2 digits)", NAME, VERSION);
print!("{}", opts.usage(&msg));
}
fn print_version() {
println!("{} {}", NAME, VERSION);
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut options = EchoOptions {
newline: false,
escape: false
};
let free = match parse_options(args, &mut options) {
Some(vec) => vec,
None => return 0
};
if !free.is_empty() {
let string = free.join(" ");
if options.escape {
let mut prev_was_slash = false;
let mut iter = string.chars().enumerate();
loop {
match iter.next() {
Some((index, c)) => {
if !prev_was_slash {
if c != '\\' {
print!("{}", c);
} else {
prev_was_slash = true;
}
} else {
prev_was_slash = false;
match c {
'\\' => print!("\\"),
'a' => print!("\x07"),
'b' => print!("\x08"),
'c' => break,
'e' => print!("\x1B"),
'f' => print!("\x0C"),
'n' => print!("\n"),
'r' => print!("\r"),
't' => print!("\t"),
'v' => print!("\x0B"),
'x' => {
let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 16);
if num_char_used == 0 {
print!("\\x");
} else {
print!("{}", c);
for _ in 0 .. num_char_used {
iter.next(); // consume used characters
}
}
},
'0' => {
let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 8);
if num_char_used == 0 {
print!("\0");
} else {
print!("{}", c);
for _ in 0 .. num_char_used {
iter.next(); // consume used characters
}
}
}
_ => {
let (esc_c, num_char_used) = convert_str(string.as_bytes(), index, 8);
if num_char_used == 0 {
print!("\\{}", c);
} else {
print!("{}", esc_c);
for _ in 1 .. num_char_used {
iter.next(); // consume used characters
}
}
}
}
}
}
None => break
}
}
} else {
print!("{}", string);
}
}
if options.newline {
pipe_flush!();
} else {
println!("")
}
0
}

12
src/env/Cargo.toml vendored
View file

@ -1,12 +0,0 @@
[package]
name = "env"
version = "0.0.1"
authors = []
[lib]
name = "env"
path = "env.rs"
[dependencies]
getopts = "*"
libc = "*"

207
src/env/env.rs vendored
View file

@ -1,207 +0,0 @@
#![crate_name = "env"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* last synced with: env (GNU coreutils) 8.13 */
#![allow(non_camel_case_types)]
use std::env;
use std::io::Write;
use std::process::Command;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "env";
static VERSION: &'static str = "1.0.0";
struct options {
ignore_env: bool,
null: bool,
unsets: Vec<String>,
sets: Vec<(String, String)>,
program: Vec<String>
}
fn usage() {
println!("Usage: {} [OPTION]... [-] [NAME=VALUE]... [COMMAND [ARG]...]", NAME);
println!("Set each NAME to VALUE in the environment and run COMMAND\n");
println!("Possible options are:");
println!(" -i --ignore-environment\t start with an empty environment");
println!(" -0 --null \t end each output line with a 0 byte rather than newline");
println!(" -u --unset NAME \t remove variable from the environment");
println!(" -h --help \t display this help and exit");
println!(" -V --version \t output version information and exit\n");
println!("A mere - implies -i. If no COMMAND, print the resulting environment");
}
fn version() {
println!("{} {}", NAME, VERSION);
}
// print name=value env pairs on screen
// if null is true, separate pairs with a \0, \n otherwise
fn print_env(null: bool) {
for (n, v) in env::vars() {
print!("{}={}{}", n, v, if null { '\0' } else { '\n' });
}
}
pub fn uumain(args: Vec<String>) -> i32 {
// to handle arguments the same way than GNU env, we can't use getopts
let mut opts = Box::new(options {
ignore_env: false,
null: false,
unsets: vec!(),
sets: vec!(),
program: vec!()
});
let mut wait_cmd = false;
let mut iter = args.iter();
iter.next(); // skip program
let mut item = iter.next();
// the for loop doesn't work here,
// because we need sometines to read 2 items forward,
// and the iter can't be borrowed twice
while item != None {
let opt = item.unwrap();
if wait_cmd {
// we still accept NAME=VAL here but not other options
let mut sp = opt.splitn(2, '=');
let name = sp.next();
let value = sp.next();
match (name, value) {
(Some(n), Some(v)) => {
opts.sets.push((n.to_string(), v.to_string()));
}
_ => {
// read the program now
opts.program.push(opt.to_string());
break;
}
}
} else if opt.starts_with("--") {
match opt.as_ref() {
"--help" => { usage(); return 0; }
"--version" => { version(); return 0; }
"--ignore-environment" => opts.ignore_env = true,
"--null" => opts.null = true,
"--unset" => {
let var = iter.next();
match var {
None => println!("{}: this option requires an argument: {}", NAME, opt),
Some(s) => opts.unsets.push(s.to_string())
}
}
_ => {
println!("{}: invalid option \"{}\"", NAME, *opt);
println!("Type \"{} --help\" for detailed informations", NAME);
return 1;
}
}
} else if opt.starts_with("-") {
if opt.len() == 1 {
// implies -i and stop parsing opts
wait_cmd = true;
opts.ignore_env = true;
continue;
}
let mut chars = opt.chars();
chars.next();
for c in chars {
// short versions of options
match c {
'h' => { usage(); return 0; }
'V' => { version(); return 0; }
'i' => opts.ignore_env = true,
'0' => opts.null = true,
'u' => {
let var = iter.next();
match var {
None => println!("{}: this option requires an argument: {}", NAME, opt),
Some(s) => opts.unsets.push(s.to_string())
}
}
_ => {
println!("{}: illegal option -- {}", NAME, c);
println!("Type \"{} --help\" for detailed informations", NAME);
return 1;
}
}
}
} else {
// is it a NAME=VALUE like opt ?
let mut sp = opt.splitn(2, "=");
let name = sp.next();
let value = sp.next();
match (name, value) {
(Some(n), Some(v)) => {
// yes
opts.sets.push((n.to_string(), v.to_string()));
wait_cmd = true;
}
// no, its a program-like opt
_ => {
opts.program.push(opt.to_string());
break;
}
}
}
item = iter.next();
}
// read program arguments
for opt in iter {
opts.program.push(opt.to_string());
}
if opts.ignore_env {
for (ref name, _) in env::vars() {
env::remove_var(name);
}
}
for name in opts.unsets.iter() {
env::remove_var(name);
}
for &(ref name, ref val) in opts.sets.iter() {
env::set_var(name, val);
}
if opts.program.len() >= 1 {
let prog = opts.program[0].clone();
let args = &opts.program[1..];
match Command::new(prog).args(args).status() {
Ok(exit) => return if exit.success() { 0 } else { exit.code().unwrap() },
Err(_) => return 1
}
} else {
// no program provided
print_env(opts.null);
pipe_flush!();
}
0
}

View file

@ -1,13 +0,0 @@
[package]
name = "expand"
version = "0.0.1"
authors = []
[lib]
name = "expand"
path = "expand.rs"
[dependencies]
getopts = "*"
libc = "*"
unicode-width = "*"

View file

@ -1 +0,0 @@
DEPLIBS += unicode-width

View file

@ -1,244 +0,0 @@
#![crate_name = "expand"]
#![feature(unicode)]
/*
* This file is part of the uutils coreutils package.
*
* (c) Virgile Andreani <virgile.andreani@anbuco.fr>
* (c) kwantam <kwantam@gmail.com>
* 20150428 updated to work with both UTF-8 and non-UTF-8 encodings
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
extern crate rustc_unicode;
extern crate unicode_width;
use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::iter::repeat;
use std::str::from_utf8;
use rustc_unicode::str::utf8_char_width;
use unicode_width::UnicodeWidthChar;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "expand";
static VERSION: &'static str = "0.0.1";
static DEFAULT_TABSTOP: usize = 8;
fn tabstops_parse(s: String) -> Vec<usize> {
let words = s.split(',').collect::<Vec<&str>>();
let nums = words.into_iter()
.map(|sn| sn.parse::<usize>()
.unwrap_or_else(
|_| crash!(1, "{}\n", "tab size contains invalid character(s)"))
)
.collect::<Vec<usize>>();
if nums.iter().any(|&n| n == 0) {
crash!(1, "{}\n", "tab size cannot be 0");
}
match nums.iter().fold((true, 0), |(acc, last), &n| (acc && last <= n, n)) {
(false, _) => crash!(1, "{}\n", "tab sizes must be ascending"),
_ => {}
}
nums
}
struct Options {
files: Vec<String>,
tabstops: Vec<usize>,
tspaces: String,
iflag: bool,
uflag: bool,
}
impl Options {
fn new(matches: getopts::Matches) -> Options {
let tabstops = match matches.opt_str("t") {
None => vec!(DEFAULT_TABSTOP),
Some(s) => tabstops_parse(s)
};
let iflag = matches.opt_present("i");
let uflag = !matches.opt_present("U");
// avoid allocations when dumping out long sequences of spaces
// by precomputing the longest string of spaces we will ever need
let nspaces = tabstops.iter().scan(0, |pr,&it| {
let ret = Some(it - *pr);
*pr = it;
ret
}).max().unwrap(); // length of tabstops is guaranteed >= 1
let tspaces = repeat(' ').take(nspaces).collect();
let files =
if matches.free.is_empty() {
vec!("-".to_string())
} else {
matches.free
};
Options { files: files, tabstops: tabstops, tspaces: tspaces, iflag: iflag, uflag: uflag }
}
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("i", "initial", "do not convert tabs after non blanks");
opts.optopt("t", "tabs", "have tabs NUMBER characters apart, not 8", "NUMBER");
opts.optopt("t", "tabs", "use comma separated list of explicit tab positions", "LIST");
opts.optflag("U", "no-utf8", "interpret input file as 8-bit ASCII rather than UTF-8");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "{}", f)
};
if matches.opt_present("help") {
println!("Usage: {} [OPTION]... [FILE]...", NAME);
println!("{}", opts.usage(
"Convert tabs in each FILE to spaces, writing to standard output.\n\
With no FILE, or when FILE is -, read standard input."));
return 0;
}
if matches.opt_present("V") {
println!("{} {}", NAME, VERSION);
return 0;
}
expand(Options::new(matches));
0
}
fn open(path: String) -> BufReader<Box<Read+'static>> {
let file_buf;
if path == "-" {
BufReader::new(Box::new(stdin()) as Box<Read>)
} else {
file_buf = match File::open(&path[..]) {
Ok(a) => a,
Err(e) => crash!(1, "{}: {}\n", &path[..], e),
};
BufReader::new(Box::new(file_buf) as Box<Read>)
}
}
fn next_tabstop(tabstops: &[usize], col: usize) -> usize {
if tabstops.len() == 1 {
tabstops[0] - col % tabstops[0]
} else {
match tabstops.iter().skip_while(|&&t| t <= col).next() {
Some(t) => t - col,
None => 1,
}
}
}
#[derive(PartialEq, Eq, Debug)]
enum CharType {
Backspace,
Tab,
Other,
}
fn expand(options: Options) {
use self::CharType::*;
let mut output = BufWriter::new(stdout());
let ts = options.tabstops.as_ref();
let mut buf = Vec::new();
for file in options.files.into_iter() {
let mut fh = open(file);
while match fh.read_until('\n' as u8, &mut buf) {
Ok(s) => s > 0,
Err(_) => buf.len() > 0,
} {
let mut col = 0;
let mut byte = 0;
let mut init = true;
while byte < buf.len() {
let (ctype, cwidth, nbytes) = if options.uflag {
let nbytes = utf8_char_width(buf[byte]);
if byte + nbytes > buf.len() {
// don't overrun buffer because of invalid UTF-8
(Other, 1, 1)
} else if let Ok(t) = from_utf8(&buf[byte..byte+nbytes]) {
match t.chars().next() {
Some('\t') => (Tab, 0, nbytes),
Some('\x08') => (Backspace, 0, nbytes),
Some(c) => (Other, UnicodeWidthChar::width(c).unwrap_or(0), nbytes),
None => { // no valid char at start of t, so take 1 byte
(Other, 1, 1)
},
}
} else {
(Other, 1, 1) // implicit assumption: non-UTF-8 char is 1 col wide
}
} else {
(match buf[byte] { // always take exactly 1 byte in strict ASCII mode
0x09 => Tab,
0x08 => Backspace,
_ => Other,
}, 1, 1)
};
// figure out how many columns this char takes up
match ctype {
Tab => {
// figure out how many spaces to the next tabstop
let nts = next_tabstop(ts, col);
col += nts;
// now dump out either spaces if we're expanding, or a literal tab if we're not
if init || !options.iflag {
safe_unwrap!(output.write_all(&options.tspaces[..nts].as_bytes()));
} else {
safe_unwrap!(output.write_all(&buf[byte..byte+nbytes]));
}
},
_ => {
col = if ctype == Other {
col + cwidth
} else if col > 0 {
col - 1
} else {
0
};
// if we're writing anything other than a space, then we're
// done with the line's leading spaces
if buf[byte] != 0x20 {
init = false;
}
safe_unwrap!(output.write_all(&buf[byte..byte+nbytes]));
},
}
byte += nbytes; // advance the pointer
}
buf.truncate(0); // clear the buffer
}
}
}

View file

@ -1,13 +0,0 @@
[package]
name = "expr"
version = "0.0.1"
authors = []
[lib]
name = "expr"
path = "expr.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,135 +0,0 @@
#![crate_name = "expr"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Roman Gafiyatullin <r.gafiyatullin@me.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
#[path="../common/util.rs"]
#[macro_use]
mod util;
mod tokens;
mod syntax_tree;
use std::io::{Write};
static NAME: &'static str = "expr";
static VERSION: &'static str = "0.0.1";
pub fn uumain(args: Vec<String>) -> i32 {
// For expr utility we do not want getopts.
// The following usage should work without escaping hyphens: `expr -15 = 1 + 2 \* \( 3 - -4 \)`
if maybe_handle_help_or_version( &args ) { 0 }
else {
let token_strings = args[1..].to_vec();
match process_expr( &token_strings ) {
Ok( expr_result ) => print_expr_ok( &expr_result ),
Err( expr_error ) => print_expr_error( &expr_error )
}
}
}
fn process_expr( token_strings: &Vec<String> ) -> Result< String, String > {
let maybe_tokens = tokens::strings_to_tokens( &token_strings );
let maybe_ast = syntax_tree::tokens_to_ast( maybe_tokens );
let maybe_result = evaluate_ast( maybe_ast );
maybe_result
}
fn print_expr_ok( expr_result: &String ) -> i32 {
println!("{}", expr_result);
if expr_result == "0" || expr_result == "" { 1 }
else { 0 }
}
fn print_expr_error( expr_error: &String ) -> ! {
crash!(2, "{}", expr_error)
}
fn evaluate_ast( maybe_ast: Result<Box<syntax_tree::ASTNode>, String> ) -> Result<String, String> {
if maybe_ast.is_err() { Err( maybe_ast.err().unwrap() ) }
else { maybe_ast.ok().unwrap().evaluate() }
}
fn maybe_handle_help_or_version( args: &Vec<String> ) -> bool {
if args.len() == 2 {
if args[1] == "--help" { print_help(); true }
else if args[1] == "--version" { print_version(); true }
else { false }
}
else { false }
}
fn print_help() {
//! The following is taken from GNU coreutils' "expr --help" output.
print!(
r#"Usage: expr EXPRESSION
or: expr OPTION
--help display this help and exit
--version output version information and exit
Print the value of EXPRESSION to standard output. A blank line below
separates increasing precedence groups. EXPRESSION may be:
ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2
ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0
ARG1 < ARG2 ARG1 is less than ARG2
ARG1 <= ARG2 ARG1 is less than or equal to ARG2
ARG1 = ARG2 ARG1 is equal to ARG2
ARG1 != ARG2 ARG1 is unequal to ARG2
ARG1 >= ARG2 ARG1 is greater than or equal to ARG2
ARG1 > ARG2 ARG1 is greater than ARG2
ARG1 + ARG2 arithmetic sum of ARG1 and ARG2
ARG1 - ARG2 arithmetic difference of ARG1 and ARG2
ARG1 * ARG2 arithmetic product of ARG1 and ARG2
ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2
ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2
STRING : REGEXP [NOT IMPLEMENTED] anchored pattern match of REGEXP in STRING
match STRING REGEXP [NOT IMPLEMENTED] same as STRING : REGEXP
substr STRING POS LENGTH substring of STRING, POS counted from 1
index STRING CHARS index in STRING where any CHARS is found, or 0
length STRING length of STRING
+ TOKEN interpret TOKEN as a string, even if it is a
keyword like 'match' or an operator like '/'
( EXPRESSION ) value of EXPRESSION
Beware that many operators need to be escaped or quoted for shells.
Comparisons are arithmetic if both ARGs are numbers, else lexicographical.
Pattern matches return the string matched between \( and \) or null; if
\( and \) are not used, they return the number of characters matched or 0.
Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null
or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.
Environment variables:
* EXPR_DEBUG_TOKENS=1 dump expression's tokens
* EXPR_DEBUG_RPN=1 dump expression represented in reverse polish notation
* EXPR_DEBUG_SYA_STEP=1 dump each parser step
* EXPR_DEBUG_AST=1 dump expression represented abstract syntax tree
"#
);
}
fn print_version() {
println!("{} {}", NAME, VERSION);
}

View file

@ -1,386 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Roman Gafiyatullin <r.gafiyatullin@me.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//!
//! Here we employ shunting-yard algorithm for building AST from tokens according to operators' precedence and associativeness.
//! * https://en.wikipedia.org/wiki/Shunting-yard_algorithm
//!
use tokens::{Token};
type TokenStack = Vec<(usize, Token)>;
type OperandsList = Vec< Box<ASTNode> >;
#[derive(Debug)]
pub enum ASTNode {
Leaf { token_idx: usize, value: String },
Node { token_idx: usize, op_type: String, operands: OperandsList }
}
impl ASTNode {
fn debug_dump( &self ) {
self.debug_dump_impl( 1 );
}
fn debug_dump_impl( &self, depth: usize ) {
for _ in 0..depth {
print!("\t", );
}
match self {
&ASTNode::Leaf{ ref token_idx, ref value } => println!("Leaf( {} ) at #{} ( evaluate -> {:?} )", value, token_idx, self.evaluate()),
&ASTNode::Node{ ref token_idx, ref op_type, ref operands } => {
println!("Node( {} ) at #{} (evaluate -> {:?})", op_type, token_idx, self.evaluate());
for operand in operands {
operand.debug_dump_impl( depth + 1 );
}
}
}
}
fn new_node( token_idx: usize, op_type: &String, operands: OperandsList ) -> Box<ASTNode> {
Box::new( ASTNode::Node{
token_idx: token_idx,
op_type: op_type.clone(),
operands: operands
} )
}
fn new_leaf( token_idx: usize, value: &String ) -> Box<ASTNode> {
Box::new( ASTNode::Leaf{ token_idx: token_idx, value: value.clone() } )
}
pub fn evaluate( &self ) -> Result<String, String> {
match self {
&ASTNode::Leaf{ ref value, .. } => Ok( value.clone() ),
&ASTNode::Node{ ref op_type, .. } =>
match self.operand_values() {
Err( reason ) => Err( reason ),
Ok( operand_values ) =>
match op_type.as_ref() {
"+" => infix_operator_two_ints( |a: i64, b: i64| Ok( a + b ), &operand_values ),
"-" => infix_operator_two_ints( |a: i64, b: i64| Ok( a - b ), &operand_values ),
"*" => infix_operator_two_ints( |a: i64, b: i64| Ok( a * b ), &operand_values ),
"/" => infix_operator_two_ints(
|a: i64, b: i64|
if b == 0 { Err("division by zero".to_string()) }
else { Ok( a / b ) },
&operand_values ),
"%" => infix_operator_two_ints(
|a: i64, b: i64|
if b == 0 { Err("division by zero".to_string()) }
else { Ok( a % b ) },
&operand_values ),
"=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok( bool_as_int(a == b) ),
|a: &String, b: &String| Ok( bool_as_string(a == b) ),
&operand_values
),
"!=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok( bool_as_int(a != b) ),
|a: &String, b: &String| Ok( bool_as_string(a != b) ),
&operand_values
),
"<" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok( bool_as_int(a < b) ),
|a: &String, b: &String| Ok( bool_as_string(a < b) ),
&operand_values
),
">" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok( bool_as_int(a > b) ),
|a: &String, b: &String| Ok( bool_as_string(a > b) ),
&operand_values
),
"<=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok( bool_as_int(a <= b) ),
|a: &String, b: &String| Ok( bool_as_string(a <= b) ),
&operand_values
),
">=" => infix_operator_two_ints_or_two_strings(
|a: i64, b: i64| Ok( bool_as_int(a >= b) ),
|a: &String, b: &String| Ok( bool_as_string(a >= b) ),
&operand_values
),
"length" => prefix_operator_length( &operand_values ),
"index" => prefix_operator_index( &operand_values ),
"substr" => prefix_operator_substr( &operand_values ),
_ => Err(format!("operation not implemented: {}", op_type))
}
}
}
}
pub fn operand_values( &self ) -> Result<Vec<String>, String> {
if let &ASTNode::Node{ ref operands, .. } = self {
let mut out = Vec::with_capacity( operands.len() );
for operand in operands {
match operand.evaluate() {
Ok( value ) => out.push( value ),
Err( reason ) => return Err( reason ),
}
}
Ok( out )
}
else { panic!("Invoked .operand_values(&self) not with ASTNode::Node") }
}
}
pub fn tokens_to_ast( maybe_tokens: Result< Vec<(usize, Token)>, String > ) -> Result<Box<ASTNode>, String> {
if maybe_tokens.is_err() { Err( maybe_tokens.err().unwrap() ) }
else {
let tokens = maybe_tokens.ok().unwrap();
let mut out_stack: TokenStack = Vec::new();
let mut op_stack: TokenStack = Vec::new();
for (token_idx, token) in tokens {
if let Err( reason ) = push_token_to_either_stack( token_idx, &token, &mut out_stack, &mut op_stack ) {
return Err( reason )
}
}
if let Err( reason ) = move_rest_of_ops_to_out( &mut out_stack, &mut op_stack ) {
return Err( reason )
}
assert!( op_stack.is_empty() );
maybe_dump_rpn( &out_stack );
let result = ast_from_rpn( &mut out_stack );
if !out_stack.is_empty() {
Err( "syntax error (fist RPN token does not represent expression AST's root)".to_string() )
}
else {
maybe_dump_ast( &result );
result
}
}
}
fn maybe_dump_ast( result: &Result< Box<ASTNode>, String > ) {
use std::env;
if let Ok( debug_var ) = env::var( "EXPR_DEBUG_AST" ) {
if debug_var == "1" {
println!("EXPR_DEBUG_AST");
match result {
&Ok( ref ast ) => ast.debug_dump(),
&Err( ref reason ) => println!("\terr: {:?}", reason),
}
}
}
}
fn maybe_dump_rpn( rpn: &TokenStack ) {
use std::env;
if let Ok( debug_var ) = env::var( "EXPR_DEBUG_RPN" ) {
if debug_var == "1" {
println!("EXPR_DEBUG_RPN");
for token in rpn {
println!("\t{:?}", token);
}
}
}
}
fn ast_from_rpn( rpn: &mut TokenStack ) -> Result<Box<ASTNode>, String> {
match rpn.pop() {
None => Err( "syntax error (premature end of expression)".to_string() ),
Some( (token_idx, Token::Value{ value }) ) =>
Ok( ASTNode::new_leaf( token_idx, &value ) ),
Some( (token_idx, Token::InfixOp{ value, .. }) ) =>
maybe_ast_node( token_idx, &value, 2, rpn ),
Some( (token_idx, Token::PrefixOp{ value, arity }) ) =>
maybe_ast_node( token_idx, &value, arity, rpn ),
Some( (token_idx, unexpected_token) ) =>
panic!("unexpected token at #{} {:?}", token_idx, unexpected_token),
}
}
fn maybe_ast_node( token_idx: usize, op_type: &String, arity: usize, rpn: &mut TokenStack ) -> Result< Box<ASTNode>, String > {
let mut operands = Vec::with_capacity( arity );
for _ in 0..arity {
match ast_from_rpn( rpn ) {
Err( reason ) => return Err( reason ),
Ok( operand ) => operands.push( operand ),
}
}
operands.reverse();
Ok( ASTNode::new_node( token_idx, op_type, operands ) )
}
fn move_rest_of_ops_to_out( out_stack: &mut TokenStack, op_stack: &mut TokenStack ) -> Result<(), String> {
loop {
match op_stack.pop() {
None => return Ok( () ),
Some( (token_idx, Token::ParOpen) ) => return Err( format!( "syntax error (Mismatched open-parenthesis at #{})", token_idx ) ),
Some( (token_idx, Token::ParClose) ) => return Err( format!( "syntax error (Mismatched close-parenthesis at #{})", token_idx ) ),
Some( other ) => out_stack.push( other )
}
}
}
fn push_token_to_either_stack( token_idx: usize, token: &Token, out_stack: &mut TokenStack, op_stack: &mut TokenStack ) -> Result<(), String> {
let result =
match token {
&Token::Value{ .. } => Ok( out_stack.push( (token_idx, token.clone()) ) ),
&Token::InfixOp{ .. } =>
if op_stack.is_empty() { Ok( op_stack.push( (token_idx, token.clone()) ) ) }
else { push_op_to_stack( token_idx, token, out_stack, op_stack ) },
&Token::PrefixOp{ .. } => Ok( op_stack.push( (token_idx, token.clone()) ) ),
&Token::ParOpen => Ok( op_stack.push( (token_idx, token.clone()) ) ),
&Token::ParClose => move_till_match_paren( out_stack, op_stack )
};
maybe_dump_shunting_yard_step( token_idx, token, out_stack, op_stack, &result );
result
}
fn maybe_dump_shunting_yard_step( token_idx: usize, token: &Token, out_stack: &TokenStack, op_stack: &TokenStack, result: &Result<(), String> ) {
use std::env;
if let Ok( debug_var ) = env::var( "EXPR_DEBUG_SYA_STEP" ) {
if debug_var == "1" {
println!("EXPR_DEBUG_SYA_STEP");
println!("\t{} => {:?}", token_idx, token);
println!("\t\tout: {:?}", out_stack);
println!("\t\top : {:?}", op_stack);
println!("\t\tresult: {:?}", result);
}
}
}
fn push_op_to_stack( token_idx: usize, token: &Token, out_stack: &mut TokenStack, op_stack: &mut TokenStack ) -> Result<(), String> {
if let &Token::InfixOp{ precedence: prec, left_assoc: la, .. } = token {
loop {
match op_stack.last() {
None =>
return Ok( op_stack.push( (token_idx, token.clone()) ) ),
Some( &(_, Token::ParOpen) ) =>
return Ok( op_stack.push( (token_idx, token.clone()) ) ),
Some( &(_, Token::InfixOp{ precedence: prev_prec, .. }) ) =>
if la && prev_prec >= prec
|| !la && prev_prec > prec {
out_stack.push( op_stack.pop().unwrap() )
}
else {
return Ok( op_stack.push( (token_idx, token.clone()) ) )
},
Some( &(_, Token::PrefixOp{ .. }) ) =>
return Ok( op_stack.push( (token_idx, token.clone()) ) ),
Some( _ ) => panic!("Non-operator on op_stack")
}
}
}
else {
panic!("Expected infix-op")
}
}
fn move_till_match_paren( out_stack: &mut TokenStack, op_stack: &mut TokenStack ) -> Result<(), String> {
loop {
match op_stack.pop() {
None => return Err( "syntax error (Mismatched close-parenthesis)".to_string() ),
Some( (_, Token::ParOpen) ) => return Ok( () ),
Some( other ) => out_stack.push( other )
}
}
}
fn infix_operator_two_ints<F>( f: F, values: &Vec<String> ) -> Result<String, String>
where F : Fn( i64, i64 ) -> Result<i64, String>
{
assert!( values.len() == 2 );
if let Some( left ) = values[0].parse::<i64>().ok() {
if let Some( right ) = values[1].parse::<i64>().ok() {
return match f( left, right ) {
Ok(result) => Ok(result.to_string()),
Err(reason) => Err(reason),
}
}
}
Err( "Expected an integer operand".to_string() )
}
fn infix_operator_two_ints_or_two_strings<FI, FS>( fi: FI, fs: FS, values: &Vec<String> ) -> Result<String, String>
where FI : Fn( i64, i64 ) -> Result<i64, String>,
FS : Fn( &String, &String ) -> Result<String, String>
{
assert!( values.len() == 2 );
if let ( Some( a_int ), Some( b_int ) ) =
(
values[0].parse::<i64>().ok(),
values[1].parse::<i64>().ok()
) {
match fi( a_int, b_int ) {
Ok( result ) => Ok(result.to_string()),
Err( reason ) => Err(reason)
}
}
else {
fs( &values[0], &values[1] )
}
}
fn prefix_operator_length( values: &Vec<String> ) -> Result<String, String> {
assert!( values.len() == 1 );
Ok( values[0].len().to_string() )
}
fn prefix_operator_index( values: &Vec<String> ) -> Result<String, String> {
assert!( values.len() == 2 );
let haystack = &values[0];
let needles = &values[1];
let mut current_idx = 0;
for ch_h in haystack.chars() {
current_idx += 1;
for ch_n in needles.chars() {
if ch_n == ch_h {
return Ok( current_idx.to_string() )
}
}
}
Ok( "0".to_string() )
}
fn prefix_operator_substr( values: &Vec<String> ) -> Result<String, String> {
assert!( values.len() == 3 );
let subj = &values[0];
let mut idx = match values[1].parse::<i64>() {
Ok( i ) => i,
Err( _ ) => return Err( "expected integer as POS arg to 'substr'".to_string() ),
};
let mut len = match values[2].parse::<i64>() {
Ok( i ) => i,
Err( _ ) => return Err( "expected integer as LENGTH arg to 'substr'".to_string() ),
};
if idx <= 0 || len <= 0 { return Ok( "".to_string() ) }
let mut out_str = String::new();
for ch in subj.chars() {
idx -= 1;
if idx <= 0 {
if len <= 0 { break; }
len -= 1;
out_str.push( ch );
}
}
Ok( out_str )
}
fn bool_as_int( b: bool ) -> i64 { if b { 1 } else { 0 } }
fn bool_as_string( b: bool ) -> String { if b { "1".to_string() } else { "0".to_string() } }

View file

@ -1,160 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Roman Gafiyatullin <r.gafiyatullin@me.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
//!
//! The following tokens are present in the expr grammar:
//! * integer literal;
//! * string literal;
//! * infix binary operators;
//! * prefix operators.
//!
//! According to the man-page of expr we have expression split into tokens (each token -- separate CLI-argument).
//! Hence all we need is to map the strings into the Token structures, except for some ugly fiddling with +-escaping.
//!
#[derive(Debug)]
#[derive(Clone)]
pub enum Token {
Value{ value: String },
ParOpen,
ParClose,
InfixOp {
precedence: u8,
left_assoc: bool,
value: String
},
PrefixOp {
arity: usize,
value: String
},
}
impl Token {
fn new_infix_op( v: &String, left_assoc: bool, precedence: u8 ) -> Self {
Token::InfixOp{
left_assoc: left_assoc,
precedence: precedence,
value: v.clone()
}
}
fn new_value( v: &String ) -> Self {
Token::Value{
value: v.clone()
}
}
fn is_infix_plus( &self ) -> bool {
match self {
&Token::InfixOp{ ref value, .. } => value == "+",
_ => false
}
}
fn is_a_number( &self ) -> bool {
match self {
&Token::Value{ ref value, .. } =>
match value.parse::<i64>() {
Ok( _ ) => true,
Err( _ ) => false
},
_ => false,
}
}
fn is_a_close_paren( &self ) -> bool {
match self {
&Token::ParClose => true,
_ => false,
}
}
}
pub fn strings_to_tokens( strings: &Vec<String> ) -> Result< Vec<(usize, Token)>, String > {
let mut tokens_acc = Vec::with_capacity( strings.len() );
let mut tok_idx = 1;
for s in strings {
let token_if_not_escaped =
match s.as_ref() {
"(" => Token::ParOpen,
")" => Token::ParClose,
"^" => Token::new_infix_op( &s, false, 7 ),
":" => Token::new_infix_op( &s, true, 6 ),
"*" => Token::new_infix_op( &s, true, 5 ),
"/" => Token::new_infix_op( &s, true, 5 ),
"%" => Token::new_infix_op( &s, true, 5 ),
"+" => Token::new_infix_op( &s, true, 4 ),
"-" => Token::new_infix_op( &s, true, 4 ),
"=" => Token::new_infix_op( &s, true, 3 ),
"!=" => Token::new_infix_op( &s, true, 3 ),
"<" => Token::new_infix_op( &s, true, 3 ),
">" => Token::new_infix_op( &s, true, 3 ),
"<=" => Token::new_infix_op( &s, true, 3 ),
">=" => Token::new_infix_op( &s, true, 3 ),
"&" => Token::new_infix_op( &s, true, 2 ),
"|" => Token::new_infix_op( &s, true, 1 ),
"match" => Token::PrefixOp{ arity: 2, value: s.clone() },
"substr" => Token::PrefixOp{ arity: 3, value: s.clone() },
"index" => Token::PrefixOp{ arity: 2, value: s.clone() },
"length" => Token::PrefixOp{ arity: 1, value: s.clone() },
_ => Token::new_value( &s ),
};
push_token_if_not_escaped( &mut tokens_acc, tok_idx, token_if_not_escaped, &s );
tok_idx += 1;
}
maybe_dump_tokens_acc( &tokens_acc );
Ok( tokens_acc )
}
fn maybe_dump_tokens_acc( tokens_acc: &Vec<(usize, Token)> ) {
use std::env;
if let Ok(debug_var) = env::var( "EXPR_DEBUG_TOKENS" ) {
if debug_var == "1" {
println!("EXPR_DEBUG_TOKENS");
for token in tokens_acc {
println!("\t{:?}", token);
}
}
}
}
fn push_token_if_not_escaped( acc: &mut Vec<(usize, Token)>, tok_idx: usize, token: Token, s: &String ) {
// Smells heuristics... :(
let prev_is_plus =
match acc.last() {
None => false,
Some( ref t ) => t.1.is_infix_plus(),
};
let should_use_as_escaped =
if prev_is_plus && acc.len() >= 2 {
let pre_prev = &acc[acc.len() - 2];
! ( pre_prev.1.is_a_number() || pre_prev.1.is_a_close_paren() )
}
else if prev_is_plus { true }
else { false };
if should_use_as_escaped {
acc.pop();
acc.push( (tok_idx, Token::new_value( s )) )
}
else {
acc.push( (tok_idx, token) )
}
}

View file

@ -1,13 +0,0 @@
[package]
name = "factor"
version = "0.0.1"
authors = []
[lib]
name = "factor"
path = "factor.rs"
[dependencies]
getopts = "*"
libc = "*"
rand = "*"

View file

@ -1 +0,0 @@
DEPLIBS += rand

View file

@ -1,202 +0,0 @@
#![crate_name = "factor"]
/*
* This file is part of the uutils coreutils package.
*
* (c) T. Jameson Little <t.jameson.little@gmail.com>
* (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
* 20150223 added Pollard rho method implementation
* (c) kwantam <kwantam@gmail.com>
* 20150429 sped up trial division by adding table of prime inverses
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
extern crate rand;
use numeric::*;
use prime_table::P_INVS_U64;
use rand::weak_rng;
use rand::distributions::{Range, IndependentSample};
use std::cmp::{max, min};
use std::io::{stdin, BufRead, BufReader, Write};
use std::num::Wrapping;
use std::mem::swap;
#[path="../common/util.rs"]
#[macro_use]
mod util;
mod numeric;
mod prime_table;
static NAME: &'static str = "factor";
static VERSION: &'static str = "1.0.0";
fn rho_pollard_pseudorandom_function(x: u64, a: u64, b: u64, num: u64) -> u64 {
if num < 1 << 63 {
(sm_mul(a, sm_mul(x, x, num), num) + b) % num
} else {
big_add(big_mul(a, big_mul(x, x, num), num), b, num)
}
}
fn gcd(mut a: u64, mut b: u64) -> u64 {
while b > 0 {
a %= b;
swap(&mut a, &mut b);
}
a
}
fn rho_pollard_find_divisor(num: u64) -> u64 {
let range = Range::new(1, num);
let mut rng = rand::weak_rng();
let mut x = range.ind_sample(&mut rng);
let mut y = x;
let mut a = range.ind_sample(&mut rng);
let mut b = range.ind_sample(&mut rng);
loop {
x = rho_pollard_pseudorandom_function(x, a, b, num);
y = rho_pollard_pseudorandom_function(y, a, b, num);
y = rho_pollard_pseudorandom_function(y, a, b, num);
let d = gcd(num, max(x, y) - min(x, y));
if d == num {
// Failure, retry with diffrent function
x = range.ind_sample(&mut rng);
y = x;
a = range.ind_sample(&mut rng);
b = range.ind_sample(&mut rng);
} else if d > 1 {
return d;
}
}
}
fn rho_pollard_factor(num: u64, factors: &mut Vec<u64>) {
if is_prime(num) {
factors.push(num);
return;
}
let divisor = rho_pollard_find_divisor(num);
rho_pollard_factor(divisor, factors);
rho_pollard_factor(num / divisor, factors);
}
fn table_division(mut num: u64, factors: &mut Vec<u64>) {
if num < 2 {
return;
}
while num % 2 == 0 {
num /= 2;
factors.push(2);
}
if num == 1 {
return;
}
if is_prime(num) {
factors.push(num);
return;
}
for &(prime, inv, ceil) in P_INVS_U64 {
if num == 1 {
break;
}
// inv = prime^-1 mod 2^64
// ceil = floor((2^64-1) / prime)
// if (num * inv) mod 2^64 <= ceil, then prime divides num
// See http://math.stackexchange.com/questions/1251327/
// for a nice explanation.
loop {
let Wrapping(x) = Wrapping(num) * Wrapping(inv); // x = num * inv mod 2^64
if x <= ceil {
num = x;
factors.push(prime);
if is_prime(num) {
factors.push(num);
return;
}
} else {
break;
}
}
}
// do we still have more factoring to do?
// Decide whether to use Pollard Rho or slow divisibility based on
// number's size:
//if num >= 1 << 63 {
// number is too big to use rho pollard without overflowing
//trial_division_slow(num, factors);
//} else if num > 1 {
// number is still greater than 1, but not so big that we have to worry
rho_pollard_factor(num, factors);
//}
}
fn print_factors(num: u64) {
print!("{}:", num);
let mut factors = Vec::new();
// we always start with table division, and go from there
table_division(num, &mut factors);
factors.sort();
for fac in factors.iter() {
print!(" {}", fac);
}
println!("");
}
fn print_factors_str(num_str: &str) {
if let Err(e) = num_str.parse::<u64>().and_then(|x| Ok(print_factors(x))) {
show_warning!("{}: {}", num_str, e);
}
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("h", "help", "show this help message");
opts.optflag("v", "version", "print the version and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "Invalid options\n{}", f)
};
if matches.opt_present("help") {
let msg = format!("{0} {1}
Usage:
\t{0} [NUMBER]...
\t{0} [OPTION]
Print the prime factors of the given number(s). If none are specified,
read from standard input.", NAME, VERSION);
print!("{}", opts.usage(&msg));
return 1;
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
if matches.free.is_empty() {
for line in BufReader::new(stdin()).lines() {
for number in line.unwrap().split_whitespace() {
print_factors_str(number);
}
}
} else {
for num_str in matches.free.iter() {
print_factors_str(num_str);
}
}
0
}

View file

@ -1,134 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) kwantam <kwantam@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
//! Generate a table of the multiplicative inverses of p_i mod 2^64
//! for the first 1027 odd primes (all 13 bit and smaller primes).
//! You can supply a commandline argument to override the default
//! value of 1027 for the number of entries in the table.
//!
//! 2 has no multiplicative inverse mode 2^64 because 2 | 2^64,
//! and in any case divisibility by two is trivial by checking the LSB.
#![cfg_attr(test, allow(dead_code))]
use sieve::Sieve;
use std::env::args;
use std::num::Wrapping;
use std::u64::MAX as MAX_U64;
#[cfg(test)]
use numeric::is_prime;
#[cfg(test)]
mod numeric;
mod sieve;
// extended Euclid algorithm
// precondition: a does not divide 2^64
fn inv_mod_u64(a: u64) -> Option<u64> {
let mut t = 0u64;
let mut newt = 1u64;
let mut r = 0u64;
let mut newr = a;
while newr != 0 {
let quot = if r == 0 {
// special case when we're just starting out
// This works because we know that
// a does not divide 2^64, so floor(2^64 / a) == floor((2^64-1) / a);
MAX_U64
} else {
r
} / newr;
let (tp, Wrapping(newtp)) =
(newt, Wrapping(t) - (Wrapping(quot) * Wrapping(newt)));
t = tp;
newt = newtp;
let (rp, Wrapping(newrp)) =
(newr, Wrapping(r) - (Wrapping(quot) * Wrapping(newr)));
r = rp;
newr = newrp;
}
if r > 1 { // not invertible
return None;
}
Some(t)
}
#[cfg_attr(test, allow(dead_code))]
fn main() {
// By default, we print the multiplicative inverses mod 2^64 of the first 1k primes
let n = args().skip(1).next().unwrap_or("1027".to_string()).parse::<usize>().ok().unwrap_or(1027);
print!("{}", PREAMBLE);
let mut cols = 3;
// we want a total of n + 1 values
let mut primes = Sieve::odd_primes().take(n + 1);
// in each iteration of the for loop, we use the value yielded
// by the previous iteration. This leaves one value left at the
// end, which we call NEXT_PRIME.
let mut x = primes.next().unwrap();
for next in primes {
// format the table
let outstr = format!("({}, {}, {}),", x, inv_mod_u64(x).unwrap(), MAX_U64 / x);
if cols + outstr.len() > MAX_WIDTH {
print!("\n {}", outstr);
cols = 4 + outstr.len();
} else {
print!(" {}", outstr);
cols += 1 + outstr.len();
}
x = next;
}
print!("\n];\n\n#[allow(dead_code)]\npub const NEXT_PRIME: u64 = {};\n", x);
}
#[test]
fn test_inverter() {
let num = 10000;
let invs = Sieve::odd_primes().map(|x| inv_mod_u64(x).unwrap());
assert!(Sieve::odd_primes().zip(invs).take(num).all(|(x, y)| {
let Wrapping(z) = Wrapping(x) * Wrapping(y);
is_prime(x) && z == 1
}));
}
#[test]
fn test_generator() {
let prime_10001 = Sieve::primes().skip(10000).next();
assert_eq!(prime_10001, Some(104743));
}
const MAX_WIDTH: usize = 102;
const PREAMBLE: &'static str =
r##"/*
* This file is part of the uutils coreutils package.
*
* (c) kwantam <kwantam@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
// *** NOTE: this file was automatically generated.
// Please do not edit by hand. Instead, modify and
// re-run src/factor/gen_tables.rs.
pub const P_INVS_U64: &'static [(u64, u64, u64)] = &[
"##;

View file

@ -1,132 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) Wiktor Kuropatwa <wiktor.kuropatwa@gmail.com>
* (c) kwantam <kwantam@gmail.com>
* 20150507 added big_ routines to prevent overflow when num > 2^63
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
use std::u64::MAX as MAX_U64;
use std::num::Wrapping;
pub fn big_add(a: u64, b: u64, m: u64) -> u64 {
let Wrapping(msb_mod_m) = Wrapping(MAX_U64) - Wrapping(m) + Wrapping(1);
let msb_mod_m = msb_mod_m % m;
let Wrapping(res) = Wrapping(a) + Wrapping(b);
let res = if b <= MAX_U64 - a {
res
} else {
(res + msb_mod_m) % m
};
res
}
// computes (a + b) % m using the russian peasant algorithm
// CAUTION: Will overflow if m >= 2^63
pub fn sm_mul(mut a: u64, mut b: u64, m: u64) -> u64 {
let mut result = 0;
while b > 0 {
if b & 1 != 0 {
result = (result + a) % m;
}
a = (a << 1) % m;
b >>= 1;
}
result
}
// computes (a + b) % m using the russian peasant algorithm
// Only necessary when m >= 2^63; otherwise, just wastes time.
pub fn big_mul(mut a: u64, mut b: u64, m: u64) -> u64 {
// precompute 2^64 mod m, since we expect to wrap
let Wrapping(msb_mod_m) = Wrapping(MAX_U64) - Wrapping(m) + Wrapping(1);
let msb_mod_m = msb_mod_m % m;
let mut result = 0;
while b > 0 {
if b & 1 != 0 {
let Wrapping(next_res) = Wrapping(result) + Wrapping(a);
let next_res = next_res % m;
result = if result <= MAX_U64 - a {
next_res
} else {
(next_res + msb_mod_m) % m
};
}
let Wrapping(next_a) = Wrapping(a) << 1;
let next_a = next_a % m;
a = if a < 1 << 63 {
next_a
} else {
(next_a + msb_mod_m) % m
};
b >>= 1;
}
result
}
// computes a.pow(b) % m
fn pow(mut a: u64, mut b: u64, m: u64, mul: fn(u64, u64, u64) -> u64) -> u64 {
let mut result = 1;
while b > 0 {
if b & 1 != 0 {
result = mul(result, a, m);
}
a = mul(a, a, m);
b >>= 1;
}
result
}
fn witness(mut a: u64, exponent: u64, m: u64) -> bool {
if a == 0 {
return false;
}
let mul = if m < 1 << 63 {
sm_mul as fn(u64, u64, u64) -> u64
} else {
big_mul as fn(u64, u64, u64) -> u64
};
if pow(a, m-1, m, mul) != 1 {
return true;
}
a = pow(a, exponent, m, mul);
if a == 1 {
return false;
}
loop {
if a == 1 {
return true;
}
if a == m-1 {
return false;
}
a = mul(a, a, m);
}
}
// uses deterministic (i.e., fixed witness set) Miller-Rabin test
pub fn is_prime(num: u64) -> bool {
if num < 2 {
return false;
}
if num % 2 == 0 {
return num == 2;
}
let mut exponent = num - 1;
while exponent & 1 == 0 {
exponent >>= 1;
}
// These witnesses detect all composites up to at least 2^64.
// Discovered by Jim Sinclair, according to http://miller-rabin.appspot.com
let witnesses = [2, 325, 9375, 28178, 450775, 9780504, 1795265022];
! witnesses.iter().any(|&wit| witness(wit % num, exponent, num))
}

View file

@ -1,532 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) kwantam <kwantam@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
// *** NOTE: this file was automatically generated.
// Please do not edit by hand. Instead, modify and
// re-run src/factor/gen_tables.rs.
pub const P_INVS_U64: &'static [(u64, u64, u64)] = &[
(3, 12297829382473034411, 6148914691236517205), (5, 14757395258967641293, 3689348814741910323),
(7, 7905747460161236407, 2635249153387078802), (11, 3353953467947191203, 1676976733973595601),
(13, 5675921253449092805, 1418980313362273201), (17, 17361641481138401521, 1085102592571150095),
(19, 9708812670373448219, 970881267037344821), (23, 15238614669586151335, 802032351030850070),
(29, 3816567739388183093, 636094623231363848), (31, 17256631552825064415, 595056260442243600),
(37, 1495681951922396077, 498560650640798692), (41, 10348173504763894809, 449920587163647600),
(43, 9437869060967677571, 428994048225803525), (47, 5887258746928580303, 392483916461905353),
(53, 2436362424829563421, 348051774975651917), (59, 14694863923124558067, 312656679215416129),
(61, 5745707170499696405, 302405640552615600), (67, 17345445920055250027, 275324538413575397),
(71, 1818693077689674103, 259813296812810586), (73, 9097024474706080249, 252695124297391118),
(79, 11208148297950107311, 233503089540627235), (83, 11779246215742243803, 222249928598910260),
(89, 17617676924329347049, 207266787345051141), (97, 11790702397628785569, 190172619316593315),
(101, 4200743699953660269, 182641030432767837), (103, 15760325033848937303, 179094602657374287),
(107, 8619973866219416643, 172399477324388332), (109, 12015769075535579493, 169236184162472950),
(113, 10447713457676206225, 163245522776190722), (127, 9150747060186627967, 145249953336295682),
(131, 281629680514649643, 140814840257324821), (137, 16292379802327414201, 134647766961383588),
(139, 4246732448623781667, 132710389019493177), (149, 16094474695182830269, 123803651501406386),
(151, 8062815290495565607, 122163868037811600), (157, 6579730370240349621, 117495185182863386),
(163, 2263404180823257867, 113170209041162893), (167, 10162278172342986519, 110459545351554201),
(173, 9809829218388894501, 106628578460748853), (179, 17107036403551874683, 103054436165975148),
(181, 3770881385233444253, 101915713114417412), (191, 2124755861893246783, 96579811904238490),
(193, 8124213711219232577, 95578984837873324), (197, 14513935692512591373, 93638294790403815),
(199, 2780916192016515319, 92697206400550510), (211, 13900627050804827995, 87425327363552377),
(223, 7527595115280579359, 82720825442643729), (227, 1950316554048586955, 81263189752024456),
(229, 2094390156840385773, 80553467570784068), (233, 7204522363551799129, 79170575423646144),
(239, 7255204782128442895, 77183029597111094), (241, 17298606475760824337, 76542506529915151),
(251, 2939720171109091891, 73493004277727297), (257, 18374966859414961921, 71777214294589695),
(263, 15430736487513693367, 70139711306880424), (269, 10354863773718001093, 68575256779589411),
(271, 15383631589145234927, 68069166323651481), (277, 17181443938689762877, 66594743948409933),
(281, 14245350405676059433, 65646776063023315), (283, 5149444458738708755, 65182841249857072),
(293, 2707201348701401773, 62958170900032599), (307, 17305088903023944187, 60087114246610917),
(311, 9134400602415662215, 59314289626075728), (313, 6365010734698503433, 58935284580541698),
(317, 17050145153302519317, 58191621683626345), (331, 3455281367280943203, 55730344633563600),
(337, 9196002980365592497, 54738112978366622), (347, 9941040754419844819, 53160645745560667),
(349, 15751088062938241781, 52856000211202153), (353, 8779186981255537313, 52257065364616293),
(359, 5600822016808749655, 51383688227603207), (367, 9751139919072624015, 50263607830271257),
(373, 3511310534137743069, 49455077945602015), (379, 17181268226964305331, 48672147951740241),
(383, 14834457375202459263, 48163822646761231), (389, 12661389891209383757, 47420935922132523),
(397, 185861401246443845, 46465350311610961), (401, 3220129888178724721, 46001855545410353),
(409, 2074694932495450793, 45102063749901104), (419, 1849076971589024267, 44025642180691053),
(421, 14897608040525528621, 43816494236839790), (431, 8046375605237577039, 42799870240625409),
(433, 7540585914657253201, 42602180308798040), (439, 15379290047785184263, 42019918163347497),
(443, 15615189678648040307, 41640505809728107), (449, 205420312624827969, 41084062524965593),
(457, 686202733595322489, 40364866682077793), (461, 3041111821262312197, 40014629227135686),
(463, 8127723090792113455, 39841779856824085), (467, 15247201739725667931, 39500522641776341),
(479, 8010277176057592351, 38510947961815347), (487, 2386334448960373207, 37878324586672590),
(491, 1051952818867347139, 37569743530976683), (499, 12494988971771199291, 36967422993405915),
(503, 17969989256695189447, 36673447462643243), (509, 5436172123882971989, 36241147492553146),
(521, 1805727346946616377, 35406418567580713), (523, 7195288319381928355, 35271021173440825),
(541, 13911777416032342069, 34097493666745936), (547, 13219604528142859659, 33723480939139948),
(557, 5133295029488295333, 33118032448311582), (563, 18151858289227516155, 32765087164670606),
(569, 6386658317259721737, 32419585366800617), (571, 1873749835858413299, 32306031652731263),
(577, 8184343991108570561, 31970093715267853), (587, 8107768264083584867, 31425458387920871),
(593, 13407330009728190129, 31107494222107169), (599, 16999336775772408167, 30795899956109435),
(601, 10926856722530117097, 30693417759916059), (607, 7810235958720518559, 30390023185682951),
(613, 10111102787547160429, 30092567820080834), (617, 5112468778937331161, 29897478239399597),
(619, 10400506755613301315, 29800878955912038), (631, 14909412801254946631, 29234142747558718),
(641, 18417966001831689601, 28778071877862015), (643, 12450835035754191915, 28688559990217032),
(647, 16650538700226241335, 28511196404496988), (653, 18023005695293558853, 28249225227732850),
(659, 13744083976011213723, 27992024391061535), (661, 3544230707051608253, 27907328401981167),
(673, 7016889276180750689, 27409723735081057), (677, 7711120491668837677, 27247775588935822),
(683, 18338710433453565955, 27008410063996415), (691, 16604739238563445883, 26695722248494285),
(701, 4578792394900801685, 26314898821268975), (709, 17796294705807240205, 26017974716092456),
(719, 7799457855921701935, 25656111368163493), (727, 3501582781529460967, 25373788271952615),
(733, 8027982755134170485, 25166090141486427), (739, 12755461734324196043, 24961764646426998),
(743, 8416482154761154775, 24827380987496031), (751, 73688724661955599, 24562908220651866),
(757, 11233750354002778461, 24368222026036395), (761, 8193166224591101769, 24240136759145271),
(769, 8635666926574042369, 23987963684927895), (773, 11955781087876436429, 23863834506739394),
(787, 1757948926973591323, 23439319026314550), (797, 3332912354597459765, 23145224684704581),
(809, 12062209660064712985, 22801908620160137), (811, 2229076349227541379, 22745677032934095),
(821, 4044353146489304861, 22468628591607249), (823, 5536264624794968711, 22414026821032261),
(827, 9502192231439261171, 22305615566758829), (829, 9813044796750195733, 22251802260204525),
(839, 17941052639030982263, 21986584116459537), (853, 13018686907823153661, 21625725760503577),
(857, 12247604875076703465, 21524788884141833), (859, 858986918449804499, 21474672961245112),
(863, 13637338028999645343, 21375137976488472), (877, 4964004106494246501, 21033915705484095),
(881, 14447506709261737361, 20938415520669184), (883, 17047047751015848379, 20890989890950794),
(887, 15763959422628906567, 20796780240935232), (907, 11979197639928253475, 20338196332645591),
(911, 16462352285319281519, 20248895799900715), (919, 16098246732442938407, 20072626848432591),
(929, 13264181960428396641, 19856559821000593), (937, 11792529028977610905, 19687026759561954),
(941, 1725094026021722149, 19603341204792297), (947, 18271431828024877947, 19479138409408185),
(953, 18137040080866579081, 19356499552685783), (967, 9614435380713147895, 19076260676018150),
(971, 10828675717831559651, 18997676697950104), (977, 12064963626510136625, 18881007240234955),
(983, 9326583728009813991, 18765762028188760), (991, 13160290676198438943, 18614272526447579),
(997, 11785933776281829869, 18502250826188115), (1009, 6965519813759503633, 18282204235589248),
(1013, 7775675932353384541, 18210013893099261), (1019, 10372899268140896051, 18102791043875909),
(1021, 7497942008412795221, 18067330140753723), (1031, 13544311604071901623, 17892089305246897),
(1033, 15464550210873641529, 17857448280454551), (1039, 1881958490676816623, 17754325383743553),
(1049, 8370495880920635433, 17585075380085368), (1051, 15691141010367591955, 17551611868420125),
(1061, 10466484384894580653, 17386186685871396), (1063, 5917535022704569239, 17353475139896097),
(1069, 13511506650808773541, 17256074905247475), (1087, 4836542834413267903, 16970325734783396),
(1091, 12613447368457676907, 16908106392034419), (1093, 12235946434985750157, 16877167496532069),
(1097, 14007418243755748857, 16815628143764404), (1103, 13546566364192871087, 16724156005176384),
(1109, 14687533829653321981, 16633673646266502), (1117, 17043007953507839989, 16514542590608372),
(1123, 10923494932339137867, 16426308168931034), (1129, 8610659102608444377, 16339011579902171),
(1151, 2852754513571068799, 16026710750399262), (1153, 16894849732729650049, 15998910731751562),
(1163, 14877941479913636643, 15861344861315177), (1171, 10554499171123313051, 15752983837497482),
(1181, 9918444103984390581, 15619597014148646), (1187, 6884505159775342347, 15540643701524474),
(1193, 17503532515875282841, 15462484554660143), (1201, 10275496907003905105, 15359487155461741),
(1213, 12439766407497455253, 15207538395473661), (1217, 6745111842892974913, 15157554703130280),
(1223, 5399782811437464823, 15083192210719175), (1229, 11572367518982965253, 15009555796346258),
(1231, 1168843247562424879, 14985169840543908), (1237, 12988774525627339901, 14912485104049758),
(1249, 2171073962238033697, 14769210627469616), (1259, 2754557494723904451, 14651901567680342),
(1277, 8710561218830743637, 14445375155606540), (1279, 10802667170608642815, 14422786609624356),
(1283, 17756608675784330667, 14377820790108769), (1289, 715544766241642809, 14310895324832856),
(1291, 10173572254439349923, 14288725076459761), (1297, 9401154844041645041, 14222624574949538),
(1301, 4069343235322552893, 14178896290322483), (1303, 17455744775812645543, 14157132827098658),
(1307, 11545093077501463827, 14113805718216948), (1319, 7286393982109686423, 13985401117293064),
(1321, 10375420777264342809, 13964227156479600), (1327, 17848997280062595535, 13901088224347815),
(1361, 8864195903163884465, 13553816365694012), (1367, 11915490136858474087, 13494326315808011),
(1373, 7241656996161287925, 13435356208091443), (1381, 10365440551193781357, 13357526483497140),
(1399, 11511084757933122631, 13185664098434275), (1409, 11062809611273648769, 13092082380205501),
(1423, 11991031811792927087, 12963277634370731), (1427, 10910337770294927515, 12926940486131430),
(1429, 4001742941112638909, 12908848197137544), (1433, 6539390083352723113, 12872815124710084),
(1439, 3589359513994909279, 12819141121410390), (1447, 15973580044476895767, 12748268191920906),
(1451, 6496406768894266627, 12713124792356686), (1453, 16301183338364118565, 12695625652931556),
(1459, 12921571242858918267, 12643416088903051), (1471, 15612641993044453951, 12540274693208396),
(1481, 7535638193514030201, 12455600319857901), (1483, 10846635760131307491, 12438802477214802),
(1487, 7517637463798243631, 12405342349502052), (1489, 9155234298503263025, 12388679700275051),
(1493, 17211195240909179773, 12355488328003718), (1499, 11419998999601376851, 12306033404742862),
(1511, 5310611298519956951, 12208301835678061), (1523, 3355054568888736571, 12112110356999048),
(1531, 13325995392242171187, 12048820426982071), (1543, 7651274275550300087, 11955116055547343),
(1549, 15826806245293734085, 11908808310980988), (1553, 14028077753413380849, 11878135269613362),
(1559, 9773579605442007463, 11832420829832938), (1567, 5579934072072959455, 11772012810280505),
(1571, 4004035473669609867, 11742039512227594), (1579, 17874299197451307139, 11682548495066213),
(1583, 11163601277709254863, 11653028473600474), (1597, 8663154699613126933, 11550872932817502),
(1601, 13918592655241185729, 11522013787451312), (1607, 1503748272343466871, 11478994445369976),
(1609, 4574425659049167865, 11464725962529242), (1613, 2904818967589724805, 11436295147991042),
(1619, 3999263230310100443, 11393912337065813), (1621, 9707015851248764669, 11379854456329149),
(1627, 10045368930120874451, 11337888182980670), (1637, 13127951646836669293, 11268628023035767),
(1657, 2237655738573095881, 11132615614791521), (1663, 5291098570751326591, 11092449833860223),
(1667, 12747839935760889899, 11065833277570216), (1669, 12312566146262696525, 11052572842246585),
(1693, 14633182097455361973, 10895891360726256), (1697, 3782832609104846177, 10870208646853006),
(1699, 15080946155610692875, 10857412639028576), (1709, 5137887758388383013, 10793881845353745),
(1721, 4062356771607158665, 10718619450150814), (1723, 2141235527998787187, 10706177639993935),
(1733, 18372233278258907149, 10644399350092066), (1741, 3401151549489239557, 10595487693112895),
(1747, 8806287668845887835, 10559097924275644), (1753, 5387754116223211881, 10522957258248460),
(1759, 4184338195230307615, 10487063145940620), (1777, 7816768873102584337, 10380835156842741),
(1783, 6114428349726497479, 10345902453005917), (1787, 17001559870956704819, 10322744305377477),
(1789, 18085851931406681685, 10311204065796283), (1801, 15916846357881534265, 10242500873797641),
(1811, 13751024019606788891, 10185943718227251), (1823, 16463440816196072671, 10118894170987137),
(1831, 11374316799136037015, 10074682727312698), (1847, 10307005892836089479, 9987408810887683),
(1861, 10526836220461872013, 9912275160510237), (1867, 12903828473628641891, 9880419964493600),
(1871, 5176130752911552431, 9859296672212480), (1873, 10567728986166763953, 9848768859428484),
(1877, 8451891264459357693, 9827780540069020), (1879, 13538084128603231335, 9817319890212640),
(1889, 13896091485912489121, 9765348900852065), (1901, 9383483176894863973, 9703705456975040),
(1907, 2843913349591299515, 9673174658473807), (1913, 12053544219622027977, 9642835375697622),
(1931, 10661090826649331747, 9552948769399042), (1933, 6680145293117788997, 9543064704453984),
(1949, 13790100623599187637, 9464722459573910), (1951, 7043989920509285471, 9455020027529242),
(1973, 17128451669050125981, 9349591522407274), (1979, 736378363730699635, 9321245110515185),
(1987, 11864589293508206827, 9283716192103448), (1993, 11727057070441546361, 9255767222132238),
(1997, 13994400236189269253, 9237227878672784), (1999, 2768395808960913199, 9227986029869710),
(2003, 16319336244939253851, 9209557700304319), (2011, 15043590393278798931, 9172920971511462),
(2017, 493864243916864545, 9145634146608602), (2027, 11384744369122175171, 9100515083231155),
(2029, 5309462069515218405, 9091544639580853), (2039, 9698337247188150727, 9046956387302379),
(2053, 11797649765601871053, 8985262578523892), (2063, 3818109413220542191, 8941708227682768),
(2069, 3798121302755084093, 8915777705997849), (2081, 15698790847928695777, 8864365244454373),
(2083, 13345772116697212811, 8855854092035310), (2087, 12993154666196952983, 8838880725304049),
(2089, 7205621428505023513, 8830418417285568), (2099, 9913257415504704251, 8788348772610553),
(2111, 6859637185154901951, 8738391318668664), (2113, 34920480972474305, 8730120243118576),
(2129, 5588609641870672049, 8664511072667708), (2131, 16317274790681607131, 8656379199300587),
(2137, 13327923654566002665, 8632074905806996), (2141, 15749952436590873589, 8615947722423891),
(2143, 11310789413371138975, 8607906707283971), (2153, 15473673849103321049, 8567925719326312),
(2161, 6700922766248032401, 8536207345538894), (2179, 4893170295825663531, 8465692553331597),
(2203, 10433337773872946579, 8373465308084226), (2207, 10364278500860826463, 8358289113597440),
(2213, 8552354007964753709, 8335627688074808), (2221, 17059708386942556965, 8305602914772423),
(2237, 16393440866577822357, 8246197619002928), (2239, 15110017253766555455, 8238831654180237),
(2243, 14104398611864414187, 8224139132282457), (2251, 6883725020842302691, 8194910739097979),
(2267, 13865572078341894995, 8137072815928342), (2269, 4089339915855400821, 8129900429135985),
(2273, 15021963607759076129, 8115593521209657), (2281, 16036779262676914009, 8087130238364555),
(2287, 14583171528319575567, 8065913455928968), (2293, 13072812524979512157, 8044807707679699),
(2297, 4946971854333950281, 8030798464827841), (2309, 9770622781354171341, 7989061963494825),
(2311, 191571552474698935, 7982148019779122), (2333, 13362622153694445877, 7906877014020382),
(2339, 9984428387052711563, 7886594302569282), (2341, 12907204952044530349, 7879856503079688),
(2347, 10532014085543587203, 7859712004137005), (2351, 17214868778272546255, 7846339461382199),
(2357, 1017427547552923933, 7826365750407107), (2371, 18298921156206185323, 7780153552808752),
(2377, 18058718325419489529, 7760514965801241), (2381, 17276874961937127301, 7747477561406783),
(2383, 10241310285152218543, 7740975272223899), (2389, 13551291690816351229, 7721533726960883),
(2393, 2227793162265800425, 7708626859051212), (2399, 3252593890445660831, 7689347258736786),
(2411, 9357265865676806979, 7651075932687495), (2417, 5975920814941902737, 7632082777703579),
(2423, 2047946411815051335, 7613183687044800), (2437, 499583548980234061, 7569447711821728),
(2441, 15590181492856536249, 7557043864690516), (2447, 5435268687022716271, 7538514129019023),
(2459, 7749282890663670931, 7501725934814783), (2467, 14722999222186504715, 7477399300247082),
(2473, 12524093530027633305, 7459257611690073), (2477, 11342103845078581797, 7447211979697033),
(2503, 16596910768675153911, 7369853804917919), (2521, 18227227087509120617, 7317232873347699),
(2531, 6646950057377760203, 7288322431335263), (2539, 3465575786986788547, 7265358043997460),
(2543, 3358569605240866063, 7253930032917637), (2549, 10949362017858984541, 7236855266265026),
(2551, 16769109959597197255, 7231181526346355), (2557, 13101011825520745301, 7214213560308780),
(2579, 13311124746480603163, 7152673157700485), (2591, 17656474451099840991, 7119546149637032),
(2593, 8330558160552983009, 7114054791249345), (2609, 14154994877564784337, 7070427011770621),
(2617, 2283815468048106505, 7048813172987983), (2621, 15624483725156506901, 7038055732052480),
(2633, 11910165182417864697, 7005979519069332), (2647, 13603341304072929639, 6968924848398017),
(2657, 5963776123190253985, 6942696301734870), (2659, 7978095406079723339, 6937474266156281),
(2663, 4419460277516595543, 6927053726515040), (2671, 3549841427887199375, 6906306279936185),
(2677, 15855793094361478621, 6890827072734236), (2683, 3417082297664423091, 6875417097916344),
(2687, 14849388697965671807, 6865182014778396), (2689, 8472193726675826049, 6860075892045203),
(2693, 575390457553509965, 6849886399446547), (2699, 12705630690265304355, 6834658789814580),
(2707, 16695427772659180443, 6814460315371094), (2711, 10390327628386014503, 6804405781523257),
(2713, 8540033378761222569, 6799389632771674), (2719, 7639218031260373343, 6784385462931059),
(2729, 2142769465506019737, 6759525127779242), (2731, 13509149815971843, 6754574907985921),
(2741, 5155128041029374877, 6729932168445659), (2749, 7414933503619154069, 6710347062098781),
(2753, 8831387101034939713, 6700597193501471), (2767, 16100067559815167023, 6666694641745410),
(2777, 11511777990543267177, 6642687819124793), (2789, 14842055826964587245, 6614106874761402),
(2791, 10931893478292941015, 6609367278290774), (2797, 5111271597112943333, 6595189157565088),
(2801, 3839504389493990929, 6585770822459675), (2803, 14017682795933408827, 6581071735180004),
(2819, 9318255963448883115, 6543719075455676), (2833, 8647114765226362353, 6511381600321055),
(2837, 12601265426453687357, 6502200942442563), (2843, 10822781960938280723, 6488478393847890),
(2851, 1067594799074737291, 6470271509543862), (2857, 17813989114233340185, 6456683259961341),
(2861, 1972982763563482277, 6447656090076739), (2879, 12129102650757964991, 6407344242344408),
(2887, 9181839706934750839, 6389589218465379), (2897, 7144372402727689649, 6367533335764429),
(2903, 2923011461903683687, 6354372743268877), (2909, 16893133795930644725, 6341266439913905),
(2917, 9106380344923467373, 6323875239530185), (2927, 5123745449923425167, 6302269926105074),
(2939, 12345949504248617907, 6276537622902195), (2953, 12487315070553807545, 6246780925739773),
(2957, 386776507463642949, 6238330765542628), (2963, 273930725360519835, 6225698303648178),
(2969, 15172431467833858217, 6213116899194864), (2971, 13150523038746829459, 6208934390343167),
(2999, 8051613201895899655, 6150965012907486), (3001, 12760893267917703817, 6146865735991186),
(3011, 3394053874737659115, 6126451037432597), (3019, 6091886002480431587, 6110216652437744),
(3023, 14938018356745280303, 6102131681676993), (3037, 15847071217750484085, 6074001999904363),
(3041, 16426761904506894369, 6066012520128099), (3049, 3817610859465636953, 6050096449232388),
(3061, 17295705812331399261, 6026378331822787), (3067, 4559058365788014387, 6014588873071259),
(3079, 17218558774875365815, 5991147799191150), (3083, 1352242672934920099, 5983374659004071),
(3089, 13579765627586766065, 5971752694629184), (3109, 5684136642847780781, 5933336787941316),
(3119, 3761503440487103183, 5914313585671545), (3121, 4604297863960186065, 5910523573761471),
(3137, 12819222850075493313, 5880377454163070), (3163, 17274503934975558611, 5832040491213895),
(3167, 14584984894401236895, 5824674478594743), (3169, 10111074299789678497, 5820998445474771),
(3181, 3635997653007195493, 5799039318990742), (3187, 11414176125935122619, 5788121767715579),
(3191, 11781405334446902599, 5780866209247744), (3203, 8730959730172863019, 5759208265285529),
(3209, 1965966492118624697, 5748440035434575), (3217, 17322851677549442161, 5734144878367905),
(3221, 10663718554873388733, 5727023928503431), (3229, 5541449907555981749, 5712834956243280),
(3251, 15479150363912536699, 5674175353340372), (3253, 9611814080829292957, 5670686773350615),
(3257, 10279656276875295113, 5663722466597958), (3259, 3792365305119791219, 5660246724059389),
(3271, 2227595203031266551, 5639481526661434), (3299, 7162861218072729803, 5591616875934995),
(3301, 14054396045252808941, 5588229043838095), (3307, 9131333549640924099, 5578090134172830),
(3313, 11926630185899746321, 5567987948599321), (3319, 17407412605862704327, 5557922287951055),
(3323, 9281659973289909811, 5551232041441333), (3329, 4327698144057422593, 5541226816974932),
(3331, 1030049353860695467, 5537899751939222), (3343, 7432774234904805871, 5518020961325022),
(3347, 16142967849386099995, 5511426373979549), (3359, 15481206175584169695, 5491736848380336),
(3361, 18139389813629892321, 5488468929993915), (3371, 2670427501622741379, 5472187503325289),
(3373, 306260796954561189, 5468942802760021), (3389, 6221489665461793301, 5443123066895707),
(3391, 9770083266405884607, 5439912731851828), (3407, 3021216082515388847, 5414365739274890),
(3413, 12685176777320925181, 5404847369970568), (3433, 445988860506231513, 5373359765135319),
(3449, 8824913807370472649, 5348432610527559), (3457, 1371366279127380609, 5336055560806928),
(3461, 4130663581948830541, 5329888492837200), (3463, 3861937468506908727, 5326810301388839),
(3467, 10822231740964876835, 5320664572745760), (3469, 13655589155746938181, 5317597023265941),
(3491, 1976248147684724235, 5284085956376268), (3499, 13986628187353941251, 5272004593800957),
(3511, 2553437089097932807, 5253985780036898), (3517, 14135335592450168213, 5245022483283921),
(3527, 8849416210013201399, 5230151424357684), (3529, 17944934090406599801, 5227187326072414),
(3533, 13136713300156589829, 5221269197200552), (3539, 10956500718546899547, 5212417087795860),
(3541, 16279603284479624061, 5209473051033479), (3547, 10453328330464110163, 5200660860927417),
(3557, 9894964209344341997, 5186039942004372), (3559, 14139566685327242711, 5183125617788578),
(3571, 16742060359253054267, 5165708225625749), (3581, 13120317552565827413, 5151282902460081),
(3583, 10631461488197104127, 5148407500337580), (3593, 16916788678784573497, 5134078506459658),
(3607, 1493332206687881639, 5114151392766717), (3613, 8536660971835696181, 5105658475978287),
(3617, 17268641258938496481, 5100012185156082), (3623, 12876570732103631255, 5091566125782376),
(3631, 2667182770227902671, 5080348133767433), (3637, 15180397308939424797, 5071967026040569),
(3643, 4501552424245893875, 5063613525585932), (3659, 720930418841340771, 5041471460428956),
(3671, 13738326967453531495, 5024991575513361), (3673, 8708590858647525865, 5022255397143901),
(3677, 10826237071271474677, 5016791970005317), (3691, 11394900159322074691, 4997763227772839),
(3697, 419130782307709585, 4989652170329876), (3701, 3982423268007006685, 4984259409270346),
(3709, 10165851951108741845, 4973508782342828), (3719, 3625859079828363063, 4960135540120879),
(3727, 11992610917788635247, 4949488616503770), (3733, 1319389410040302781, 4941533370937463),
(3739, 17015999013165082515, 4933603657049893), (3761, 13002477675991497297, 4904744502448697),
(3767, 783509172230827783, 4896932326442673), (3769, 9925708936450774921, 4894333795094070),
(3779, 10304598237523382763, 4881382395795065), (3793, 9454381882228148785, 4863365165755220),
(3797, 10522951715474029181, 4858241789230853), (3803, 6330002896710745427, 4850576932345398),
(3821, 16868077412599103205, 4827726792386692), (3823, 14620359545733701647, 4825201170209142),
(3833, 3157073861819323209, 4812612594236773), (3847, 15996448721054084791, 4795098537486236),
(3851, 15850500166165906595, 4790117910597131), (3853, 15722581764355610565, 4787631475138736),
(3863, 16379066055610603687, 4775237917087639), (3877, 7550937024755496109, 4757994344521421),
(3881, 4515435936620477721, 4753090459600502), (3889, 6147333586918894033, 4743312952869517),
(3907, 8753586770580370795, 4721459962556834), (3911, 10055857418856753783, 4716631059501291),
(3917, 18117085639918469509, 4709406197015458), (3919, 5671938404904314799, 4707002825646734),
(3923, 15126988448922668251, 4702203434542327), (3929, 10653006440123943145, 4695022670834703),
(3931, 4368842211300837587, 4692633954136238), (3943, 9408166962269822039, 4678352542153069),
(3947, 15553778636256748867, 4673611369067532), (3967, 9128046033953075327, 4650048922034169),
(3989, 3838254595432170429, 4624403127026711), (4001, 9935699444849808481, 4610533385081117),
(4003, 16838471857440594955, 4608229846042855), (4007, 10680420826305505303, 4603629666510993),
(4013, 14433784298890603557, 4596746592003376), (4019, 8147044222651021179, 4589884069099166),
(4021, 13845380157785482909, 4587601112586309), (4027, 1575783452037766515, 4580765848946995),
(4049, 715272615355001137, 4555876530923574), (4051, 9325828650446102619, 4553627270725636),
(4057, 2259805719653351529, 4546892796083202), (4073, 17463944303516825689, 4529031199044819),
(4079, 10862730881355808527, 4522369226209745), (4091, 1848732600885093171, 4509103904597788),
(4093, 7918624318961075541, 4506900579943696), (4099, 5944900932268923563, 4500303506638095),
(4111, 12196120260847132399, 4487167130554500), (4127, 250307164557241311, 4469770795665023),
(4129, 15189859493972505569, 4467605733521325), (4133, 14023631715363031981, 4463281895405166),
(4139, 13931993712108252803, 4456811808096050), (4153, 1159306574341004809, 4441787641153275),
(4157, 4406451013998937877, 4437513609263784), (4159, 7069995204013711295, 4435379676294674),
(4177, 13182554718703138993, 4416266237421487), (4201, 10204768680623898585, 4391036437445739),
(4211, 6965168149417759931, 4380608899004880), (4217, 12773178253552736713, 4374376114230389),
(4219, 7913867450441879219, 4372302458807668), (4229, 14778332684258207821, 4361963602201360),
(4231, 248514396644160823, 4359901695511593), (4241, 13549070452630335601, 4349621333107651),
(4243, 12334059141436247451, 4347571075585564), (4253, 17570599633810814389, 4337348712369986),
(4259, 15835007357004489483, 4331238336160965), (4261, 15078622297284761389, 4329205368155257),
(4271, 15401800366857471567, 4319069087733446), (4273, 14306695497372678225, 4317047524855968),
(4283, 11396237408133428339, 4306968030284742), (4289, 6829897316169449281, 4300942894313255),
(4297, 10826783466114845049, 4292935553574482), (4327, 3465958616114135767, 4263171729537682),
(4337, 4249088616471257105, 4253341958429686), (4339, 3804986389944698939, 4251381441278993),
(4349, 8788607431760448597, 4241605903359289), (4357, 1752800561513829325, 4233817781434370),
(4363, 4879106729557832355, 4227995432892402), (4373, 14042810661188908605, 4218327023487205),
(4391, 17963625064719208087, 4201034860785595), (4397, 15606524438071305893, 4195302268298738),
(4409, 3782231037113502985, 4183883890612282), (4421, 1969432979595319693, 4172527499142626),
(4423, 1259533508989438071, 4170640758243172), (4441, 1013511721230608105, 4153736562420525),
(4447, 10581885345633700511, 4148132240546334), (4451, 14928144721074321483, 4144404420065053),
(4457, 15160516836885368537, 4138825235294940), (4463, 8303721452852899215, 4133261051693827),
(4481, 14552385695283031681, 4116657905313446), (4483, 8295479824358343979, 4114821341447591),
(4493, 15778063092647631173, 4105663047787569), (4507, 8402743639522012307, 4092909712382860),
(4513, 662169851526910561, 4087468219301917), (4517, 3695882972483317293, 4083848588379356),
(4519, 2249204687898641943, 4082041175859604), (4523, 3597176270840553731, 4078431146077725),
(4547, 4819602366300186347, 4056904348737530), (4549, 1184095245003998477, 4055120702068487),
(4561, 12804733991967647537, 4044451671499572), (4567, 8667990536934683111, 4039138181237037),
(4583, 4512066355362951639, 4025036891492374), (4591, 9422264180537769231, 4018023104706937),
(4597, 13996572401370223197, 4012778784796508), (4603, 5570491910157783347, 4007548136804160),
(4621, 14482749945773264069, 3991937691778738), (4637, 16867413170698403893, 3978163483655283),
(4639, 13106373888110946783, 3976448388383175), (4643, 1326989558608440715, 3973022630564193),
(4649, 5773287293449644569, 3967895047044429), (4651, 16011504155142003843, 3966188792455289),
(4657, 2150865800305837777, 3961078821926036), (4663, 636913102266188679, 3955982001653345),
(4673, 5542313006524333505, 3947516386413342), (4679, 13912921529412482935, 3942454386345277),
(4691, 2355489170784911835, 3932369233363792), (4703, 18325151671777806751, 3922335546185318),
(4721, 2961794536723541649, 3907380655308102), (4723, 13908290418479719099, 3905726037202953),
(4729, 3237639581556127689, 3900770580188105), (4733, 18244075429755844309, 3897473922186678),
(4751, 1615206384900689007, 3882707656011271), (4759, 17136594988415618343, 3876180725721696),
(4783, 3089241480878392399, 3856730937426207), (4787, 11117371350042209403, 3853508266912377),
(4789, 7965727029532543901, 3851898950450939), (4793, 16872632175911261065, 3848684346695086),
(4799, 7976035414241991999, 3843872488791321), (4801, 15891633719821434177, 3842271208854311),
(4813, 13560062441883314693, 3832691475942146), (4817, 4702636853335131697, 3829508838220791),
(4831, 8923626764698659103, 3818411110269002), (4861, 4770120818895886933, 3794845520203569),
(4871, 11845907506171931319, 3787054829338852), (4877, 9005884281218462661, 3782395750196750),
(4889, 14832102874565810473, 3773111898897433), (4903, 17190123123144797335, 3762338175343575),
(4909, 5264593287281947813, 3757739676860776), (4919, 7211443149775049351, 3750100441900701),
(4931, 13205639136117363051, 3740974259523332), (4933, 8869993298771347341, 3739457545856385),
(4937, 15565958235988250361, 3736427805085993), (4943, 8564693030379004847, 3731892387964707),
(4951, 3968043312159295591, 3725862264938305), (4957, 9638302834558753013, 3721352445775580),
(4967, 16541533743568017495, 3713860292673555), (4969, 10357499691215465689, 3712365480722389),
(4973, 5515847262740016741, 3709379463846682), (4987, 7294361201795716019, 3698966126671255),
(4993, 964270018673781889, 3694521144343991), (4999, 13125638861809336887, 3690086832108331),
(5003, 9487002298951564323, 3687136532822216), (5009, 2938810495272553841, 3682719918887912),
(5011, 17154625301035025051, 3681250064599790), (5021, 14901412858587122357, 3673918357639823),
(5023, 8751461502617929823, 3672455519352887), (5039, 7526593731999769423, 3660794616731405),
(5051, 3031240859469199731, 3652097421047228), (5059, 14629044717082965227, 3646322212632842),
(5077, 14050336681708653949, 3633394538843717), (5081, 10953321564727753833, 3630534161328390),
(5087, 4587208817228736543, 3626252029429831), (5099, 15849222550876945603, 3617717998374103),
(5101, 7395332607476187621, 3616299563558037), (5107, 10818092520219327803, 3612050924948022),
(5113, 14341053724427042377, 3607812257717494), (5119, 4551325994353421311, 3603583526803975),
(5147, 12293050742728533523, 3583979808375665), (5153, 2233799398795800545, 3579806728839423),
(5167, 11445763789493482191, 3570107233154548), (5171, 5586463202364950267, 3567345595379917),
(5179, 3344563175364601075, 3561835117534186), (5189, 16850562133240176269, 3554970914185691),
(5197, 4678239116634440837, 3549498571042823), (5209, 4228337958151123945, 3541321572990891),
(5227, 12210777596142155843, 3529126472873455), (5231, 818131260772436623, 3526427848157054),
(5233, 5062014999015271569, 3525080082879715), (5237, 16544654747797167069, 3522387640578489),
(5261, 7296649765707959877, 3506318964780374), (5273, 10047230984201371561, 3498339479178750),
(5279, 6384201822820108127, 3494363340350360), (5281, 2997028292982919009, 3493039968511560),
(5297, 8566922866023314513, 3482488969928176), (5303, 12933244289280051463, 3478548759892429),
(5309, 6038885138464343701, 3474617455963373), (5323, 4168971091616116963, 3465478879148891),
(5333, 15983949815228171389, 3458980700114298), (5347, 6623854240045322443, 3449924083356938),
(5351, 13155069217954709207, 3447345182902177), (5381, 15004905930240978893, 3428125640904952),
(5387, 14803280978401037987, 3424307420402738), (5393, 17827633990761020401, 3420497695848238),
(5399, 7250229843380564647, 3416696438916382), (5407, 17075264303479989983, 3411641219476521),
(5413, 8267467416002100909, 3407859610882976), (5417, 6194319267136362265, 3405343192488379),
(5419, 9225074080042975619, 3404086376399621), (5431, 9948538647007047815, 3396564918746004),
(5437, 11023261264572803605, 3392816640373285), (5441, 6736570570568071873, 3390322380758969),
(5443, 1633534933589565291, 3389076625704492), (5449, 8693565568230157561, 3385344847441650),
(5471, 7279568717810075295, 3371731689583175), (5477, 14122183293968258157, 3368037990452720),
(5479, 17918155130549778007, 3366808555157793), (5483, 9891195983349641027, 3364352375288993),
(5501, 10026497869549456341, 3353343769080085), (5503, 305043378285947519, 3352125036109313),
(5507, 2599359615253061931, 3349690225841574), (5519, 8001722288903907695, 3342406971137806),
(5521, 12486050100244990833, 3341196173466682), (5527, 15569759562846943783, 3337569038123674),
(5531, 2498031334516082835, 3335155319781151), (5557, 15827618453022699677, 3319550850046707),
(5563, 1369495830027331443, 3315970532753829), (5569, 14359245027748411969, 3312397930276450),
(5573, 15080453256741560589, 3310020468995074), (5581, 13835884374224723717, 3305275770240019),
(5591, 16546310414890610151, 3299363991005106), (5623, 13912972010777557959, 3280587599806073),
(5639, 843990064021469111, 3271279317912670), (5641, 4133431042221037625, 3270119495428036),
(5647, 7993480210442229999, 3266644957271038), (5651, 5957407172981761051, 3264332697524252),
(5653, 3899497464723671357, 3263177794747842), (5657, 3759783616225404457, 3260870439050654),
(5659, 6816070305376687123, 3259717984398224), (5669, 14714442882574456237, 3253967908574625),
(5683, 2054687488766170363, 3245951798998689), (5689, 17999275154361350153, 3242528401073923),
(5693, 14694534406160691477, 3240250144688134), (5701, 11150233306087197837, 3235703222892396),
(5711, 16615312820024852655, 3230037484452731), (5717, 10486604554758797053, 3226647555310399),
(5737, 2205763715280591321, 3215399001866751), (5741, 2609084861148259173, 3213158695995393),
(5743, 346900289040681103, 3212039713339639), (5749, 2717758258902763997, 3208687436721090),
(5779, 4197520065223751579, 3192030467850761), (5783, 10344594679412082983, 3189822596180105),
(5791, 8043175407721743711, 3185416003058116), (5801, 10566890287353359769, 3179924853251086),
(5807, 10819633255563067471, 3176639241210530), (5813, 13007604327909074845, 3173360411785575),
(5821, 1191543681792611477, 3168999153703753), (5827, 819925641855289835, 3165736068939342),
(5839, 14295515830370906159, 3159230017761526), (5843, 14490938781161533787, 3157067272584212),
(5849, 649688712460962153, 3153828701266806), (5851, 1588986329370981715, 3152750653513852),
(5857, 16739703730880359713, 3149520927729136), (5861, 13656444725443737325, 3147371450897381),
(5867, 5499123126797001155, 3144152731158948), (5869, 2618186712114509541, 3143081287052232),
(5879, 15525512787330304711, 3137735001481468), (5881, 9798950601303968585, 3136667926153639),
(5897, 6043600059421206329, 3128157380652798), (5903, 9878054890224613359, 3124977820381086),
(5923, 2229928880090501259, 3114425810182264), (5927, 13031300394233489559, 3112323953721874),
(5939, 8684474899830258683, 3106035371899234), (5953, 167331459764877505, 3098730736386620),
(5981, 1761091935477036277, 3084224055126158), (5987, 4159529731001819723, 3081133134075422),
(6007, 5008596568040665671, 3070874658516655), (6011, 1224463630911680435, 3068831155167118),
(6029, 6296798690279359301, 3059668945713974), (6037, 9414347936243022781, 3055614390211951),
(6043, 12027167243159959187, 3052580518568517), (6047, 9465891658792911967, 3050561282240706),
(6053, 5250906994713622573, 3047537431638782), (6067, 12578569347772608379, 3040505039345566),
(6073, 2019938219828231817, 3037501082448468), (6079, 12930017519012403263, 3034503055388970),
(6089, 13023904216271532665, 3029519473429060), (6091, 3534288349042693603, 3028524720687826),
(6101, 4934451127404358013, 3023560739831101), (6113, 14047046239672495137, 3017625400574112),
(6121, 12365134934558126169, 3013681436645899), (6131, 13226535140764506427, 3008765955587922),
(6133, 12392073305671507037, 3007784782929977), (6143, 9690321199065720831, 3002888502964276),
(6151, 17867940365983012279, 2998982941588286), (6163, 5827650610337903131, 2993143610856652),
(6173, 16486422655865154101, 2988294844274996), (6197, 10207178542641609245, 2976721651397378),
(6199, 14244969169357577607, 2975761263705364), (6203, 16347211377266065651, 2973842346237232),
(6211, 13388813763368645739, 2970011926213097), (6217, 2222392039763302905, 2967145580458348),
(6221, 5610229832415764613, 2965237754976619), (6229, 9361078506501186813, 2961429454761526),
(6247, 17153375432076002135, 2952896442085729), (6257, 17739181571281823889, 2948177093448865),
(6263, 3572712847103574343, 2945352718139797), (6269, 15030462390893027541, 2942533749195972),
(6271, 15458083257430026111, 2941595291613706), (6277, 13198076730130571341, 2938783507043102),
(6287, 11343265880222860911, 2934109125768975), (6299, 12282210612023790995, 2928519459233140),
(6301, 3940536029711642037, 2927589918062141), (6311, 14059394548335120151, 2922951049549921),
(6317, 17115144374863334181, 2920174778171529), (6323, 9411544580387001979, 2917403775693429),
(6329, 17248827844558876041, 2914638027130597), (6337, 14927395235913299777, 2910958509343467),
(6343, 6293355537680509175, 2908204961959569), (6353, 3205604510841389105, 2903627274312852),
(6359, 12865436384164469479, 2900887572528628), (6361, 17086655570240005993, 2899975487141888),
(6367, 14680328603971461919, 2897242669029299), (6373, 10177114728254006509, 2894514996659273),
(6379, 9323138876569931715, 2891792455511765), (6389, 11153509525237125981, 2887266250384966),
(6397, 15969684020666483797, 2883655475021033), (6421, 14505156646653095485, 2872877133423072),
(6427, 10054293525782567187, 2870195125830022), (6449, 12242528242437103569, 2860403794961940),
(6451, 8564253371688126971, 2859516985538606), (6469, 15991550589791801741, 2851560376211091),
(6473, 5639750737196230905, 2849798250225483), (6481, 5610018912094048177, 2846280523639801),
(6491, 9128168535627034323, 2841895559037059), (6521, 8557184607111086281, 2828821357722673),
(6529, 14697497728815605377, 2825355195850750), (6547, 518436063779220635, 2817587303147938),
(6551, 13597821268805285415, 2815866901802709), (6553, 17436156385252092585, 2815007488739440),
(6563, 17465803393879499275, 2810718280315336), (6569, 10626043473118730905, 2808151023551461),
(6571, 18101446627192084739, 2807296313150137), (6577, 7505471665082371921, 2804735300852904),
(6581, 1345454665762131101, 2803030553671106), (6599, 7161775771608406007, 2795384766435755),
(6607, 3696608014770916655, 2792000011156281), (6619, 15353242650259241555, 2786938219324603),
(6637, 8357595213145189349, 2779379851395141), (6653, 1186713732684155733, 2772695637112513),
(6659, 12391092692852203691, 2770197337995127), (6661, 4536220806596043469, 2769365571792456),
(6673, 10526779774117484273, 2764385444883793), (6679, 13467034601498394023, 2761902092185888),
(6689, 17961376013166438881, 2757773071267685), (6691, 8973868175149393291, 2756948748125773),
(6701, 16605097784303240613, 2752834513312871), (6703, 14324228390818770127, 2752013139446449),
(6709, 9246743228481923101, 2749551956134975), (6719, 4530008590805292479, 2745459752003207),
(6733, 3843870776090078853, 2739751087733484), (6737, 5292794462591741617, 2738124398650668),
(6761, 3486901187132200409, 2728404684766979), (6763, 8150062293692760643, 2727597822521004),
(6779, 5891311538513228979, 2721160063978396), (6781, 6999479796734209749, 2720357480269805),
(6791, 11036536765054028599, 2716351652732962), (6793, 12073343758532705209, 2715551902503982),
(6803, 4238168600206971803, 2711560204866904), (6823, 627237963520535831, 2703611911726447),
(6827, 1680661317393780739, 2702027841469100), (6829, 6950281520230586661, 2701236502227200),
(6833, 3018214528670756433, 2699655213480104), (6841, 9284043245984795529, 2696498183556432),
(6857, 14225810509227958137, 2690206223378963), (6863, 14941782064075680815, 2687854301866465),
(6869, 9963229074605100669, 2685506489111886), (6871, 15958004187764455655, 2684724796057277),
(6883, 2355758832019569355, 2680044177496665), (6899, 17246194995713379899, 2673828681505950),
(6907, 17672231871396569139, 2670731732113732), (6911, 16193951135175206143, 2669185946130741),
(6917, 370695016082930125, 2666870619301655), (6947, 6718045560167722123, 2655353976350878),
(6949, 5802933162344089773, 2654589735747525), (6959, 7962928466363485135, 2650775121958550),
(6961, 12534563923092397521, 2650013514395855), (6967, 977012855346465415, 2647731315302074),
(6971, 3191331710356293107, 2646212031804554), (6977, 14766384642635494593, 2643936372898029),
(6983, 2826581148341575287, 2641664624618294), (6991, 16045580133346843567, 2638641692706272),
(6997, 9506782782592059901, 2636379030114270), (7001, 5401489123140205801, 2634872742995222),
(7013, 5523764801766727277, 2630364191317489), (7019, 1952689962496964931, 2628115696496588),
(7027, 4502087104939786683, 2625123676349729), (7039, 9670192588718318719, 2620648398026644),
(7043, 12207904888195402539, 2619160027503840), (7057, 13242341714242962801, 2613964017813454),
(7069, 10281535104033899189, 2609526676150735), (7079, 16080641005630970903, 2605840383346454),
(7103, 17083300368416363583, 2597035629129881), (7109, 12639483806870055693, 2594843729597629),
(7121, 11885081001289063729, 2590471011614878), (7127, 16831651004817344487, 2588290174506742),
(7129, 16953719619995087977, 2587564044565794), (7151, 7261583634106053391, 2579603422417780),
(7159, 5158595004269663687, 2576720781353478), (7177, 17238722656035942969, 2570258335475763),
(7187, 10628630472969424411, 2566682075095248), (7193, 9324671409983029289, 2564541091854518),
(7207, 6974799167595189143, 2559559327557867), (7211, 12552790621230449283, 2558139519305165),
(7213, 5431981756905460645, 2557430205699369), (7219, 9740821223019921147, 2555304623037754),
(7229, 13549897777202617109, 2551769826215182), (7237, 779978400795235981, 2548949022206653),
(7243, 1319261829377543523, 2546837508450856), (7247, 6600304592676813487, 2545431775039264),
(7253, 4702609925863637245, 2543326082132848), (7283, 11559925848195852475, 2532849659990327),
(7297, 1266523061659378561, 2527990143032691), (7307, 7389300657417251619, 2524530460340707),
(7309, 9509827838245668421, 2523839659831652), (7321, 7339894206626953129, 2519702782913475),
(7331, 7936302115465819915, 2516265730965700), (7333, 4512949525192272685, 2515579445480642),
(7349, 8313459841083961757, 2510102609022935), (7351, 7613579311608594695, 2509419680820235),
(7369, 10356110765766917497, 2503290008645616), (7393, 13329163646930396961, 2495163543042006),
(7411, 12017390418009676859, 2489103234881871), (7417, 16529197939041887561, 2487089668829655),
(7433, 16411720511158518073, 2481736051891504), (7451, 4867306247337669907, 2475740715838082),
(7457, 13959363927577175777, 2473748702388299), (7459, 7204097799532903051, 2473085410069654),
(7477, 16714817587184995613, 2467131747185977), (7481, 8879391178910318857, 2465812601752379),
(7487, 8327767459481539263, 2463836526473828), (7489, 2943498353329271489, 2463178538350854),
(7499, 7741285984793166947, 2459893862342919), (7507, 6275873766385266395, 2457272422233855),
(7517, 15651634122937278197, 2454003468632373), (7523, 10828236319221238859, 2452046267939592),
(7529, 4687026353168597721, 2450092186706010), (7537, 14956621073960338321, 2447491584676867),
(7541, 1223096676416228061, 2446193352832456), (7547, 11989039311189260723, 2444248585359686),
(7549, 8528167547654833109, 2443601016520009), (7559, 8011729169729919031, 2440368312436770),
(7561, 7380161463162464441, 2439722797739657), (7573, 10532645104281011645, 2435856869630206),
(7577, 8104686686205503145, 2434570948094173), (7583, 11637771811766648415, 2432644609482995),
(7589, 3417594171516092973, 2430721316867775), (7591, 14242704125413210647, 2430080894968983),
(7603, 2938183226787092859, 2426245439130547), (7607, 6697766153751252999, 2424969642922249),
(7621, 10459044894698723597, 2420514902730553), (7639, 12602900552518673895, 2414811372392924),
(7643, 8312257829367486035, 2413547569502754), (7649, 8303325904795657761, 2411654343536351),
(7669, 1820861294014621277, 2405364985488271), (7673, 17468270877045953609, 2404111048313508),
(7681, 13079152223072805377, 2401607092007492), (7687, 12399418060212989879, 2399732545038318),
(7691, 16966879154521046435, 2398484471942471), (7699, 12504683377151597595, 2395992216354013),
(7703, 16902131594475141543, 2394748029820790), (7717, 12155201971596873133, 2390403534237339),
(7723, 5099546626617880707, 2388546429329218), (7727, 11158286760776296655, 2387309961655176),
(7741, 15213023403508820245, 2382992387767672), (7753, 6999912429363278841, 2379304020857674),
(7757, 9407673012194790021, 2378077101161473), (7759, 4426838183431780527, 2377464115699130),
(7789, 8521168978971237221, 2368307109219354), (7793, 10912291823405752977, 2367091501823373),
(7817, 15223224513176451001, 2359823982820717), (7823, 5647443698905071727, 2358014070524038),
(7829, 13225389511525317821, 2356206932393607), (7841, 3761808924099167585, 2352600953157703),
(7853, 14765851680547337509, 2349005994360060), (7867, 16228538926419703411, 2344825737092862),
(7873, 17809437533883691329, 2343038749359780), (7877, 3187256402731839501, 2341848936614136),
(7879, 15749618908978823927, 2341254483273201), (7883, 13069271299209418467, 2340066481505715),
(7901, 7641588830939294069, 2334735359284843), (7907, 12420698804657854155, 2332963712369995),
(7919, 12818844884155027471, 2329428472497733), (7927, 7937661667140567751, 2327077592242910),
(7933, 17988656517612138069, 2325317543641693), (7937, 12066964247284867329, 2324145656256715),
(7949, 10178314191381317573, 2320637070538376), (7951, 5681810619609444335, 2320053335896057),
(7963, 6180574304741565203, 2316557085735219), (7993, 7117447607071219465, 2307862388803897),
(8009, 15818733711853814521, 2303251850881452), (8011, 6594866437037093475, 2302676828574404),
(8017, 12876135691215997361, 2300953483062186), (8039, 16092426444697734231, 2294656558491050),
(8053, 7540876877021214941, 2290667338098789), (8059, 6493784953110063027, 2288961915089905),
(8069, 14763796409470353741, 2286125179540160), (8081, 12739918163021037937, 2282730364275405),
(8087, 10456272391972868135, 2281036734723575), (8089, 11422888004105716905, 2280472749871374),
(8093, 18241602968231501493, 2279345616422779), (8101, 4561020661602299949, 2277094688767997),
(8111, 16802434375116035919, 2274287273296702), (8117, 16051417197561976477, 2272606144352538),
(8123, 11545395404498259315, 2270927498917832), (8147, 11443457045357563995, 2264237642532165),
(8161, 12755174219819017249, 2260353397097114), (8167, 10672323466178233303, 2258692797074758),
(8171, 17536936478347301059, 2257587085266130), (8179, 16031233265182478651, 2255378906187743),
(8191, 18442239924259250175, 2252074725150720),
];
#[allow(dead_code)]
pub const NEXT_PRIME: u64 = 8209;

View file

@ -1,212 +0,0 @@
/*
* This file is part of the uutils coreutils package.
*
* (c) kwantam <kwantam@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
use std::iter::{Chain, Cycle, Map};
use std::slice::Iter;
/// A lazy Sieve of Eratosthenes.
///
/// This is a reasonably efficient implementation based on
/// O'Neill, M. E. "[The Genuine Sieve of Eratosthenes.](http://dx.doi.org/10.1017%2FS0956796808007004)"
/// Journal of Functional Programming, Volume 19, Issue 1, 2009, pp. 95--106.
pub struct Sieve {
inner: Wheel,
filts: PrimeHeap,
}
impl Iterator for Sieve {
type Item = u64;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
#[inline]
fn next(&mut self) -> Option<u64> {
while let Some(n) = self.inner.next() {
let mut prime = true;
while let Some((next, inc)) = self.filts.peek() {
// need to keep checking the min element of the heap
// until we've found an element that's greater than n
if next > n {
break; // next heap element is bigger than n
}
if next == n {
// n == next, and is composite.
prime = false;
}
// Increment the element in the prime heap.
self.filts.replace((next + inc, inc));
}
if prime {
// this is a prime; add it to the heap
self.filts.insert(n);
return Some(n);
}
}
None
}
}
impl Sieve {
fn new() -> Sieve {
Sieve { inner: Wheel::new(), filts: PrimeHeap::new() }
}
#[allow(dead_code)]
#[inline]
pub fn primes() -> PrimeSieve {
fn deref(x: &u64) -> u64 { *x }
let deref = deref as fn(&u64) -> u64;
INIT_PRIMES.iter().map(deref).chain(Sieve::new())
}
#[allow(dead_code)]
#[inline]
pub fn odd_primes() -> PrimeSieve {
fn deref(x: &u64) -> u64 { *x }
let deref = deref as fn(&u64) -> u64;
(&INIT_PRIMES[1..]).iter().map(deref).chain(Sieve::new())
}
}
pub type PrimeSieve = Chain<Map<Iter<'static, u64>, fn(&u64) -> u64>, Sieve>;
/// An iterator that generates an infinite list of numbers that are
/// not divisible by any of 2, 3, 5, or 7.
struct Wheel {
next: u64,
increment: Cycle<Iter<'static, u64>>,
}
impl Iterator for Wheel {
type Item = u64;
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(1, None)
}
#[inline]
fn next (&mut self) -> Option<u64> {
let increment = self.increment.next().unwrap(); // infinite iterator, no check necessary
let ret = self.next;
self.next = ret + increment;
Some(ret)
}
}
impl Wheel {
#[inline]
fn new() -> Wheel {
Wheel { next: 11u64, increment: WHEEL_INCS.iter().cycle() }
}
}
/// The increments of a wheel of circumference 210
/// (i.e., a wheel that skips all multiples of 2, 3, 5, 7)
const WHEEL_INCS: &'static [u64] = &[2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10];
const INIT_PRIMES: &'static [u64] = &[2, 3, 5, 7];
/// A min-heap of "infinite lists" of prime multiples, where a list is
/// represented as (head, increment).
#[derive(Debug)]
struct PrimeHeap {
data: Vec<(u64, u64)>,
}
impl PrimeHeap {
fn new() -> PrimeHeap {
PrimeHeap { data: Vec::new() }
}
fn peek(&self) -> Option<(u64, u64)> {
if let Some(&(x, y)) = self.data.get(0) {
Some((x, y))
} else {
None
}
}
fn insert(&mut self, next: u64) {
let mut idx = self.data.len();
let key = next * next;
let item = (key, next);
self.data.push(item);
loop {
// break if we've bubbled to the top
if idx == 0 {
break;
}
let paridx = (idx - 1) / 2;
let (k, _) = self.data[paridx];
if key < k {
// bubble up, found a smaller key
self.data.swap(idx, paridx);
idx = paridx;
} else {
// otherwise, parent is smaller, so we're done
break;
}
}
}
fn remove(&mut self) -> (u64, u64) {
let ret = self.data.swap_remove(0);
let mut idx = 0;
let len = self.data.len();
let (key, _) = self.data[0];
loop {
let child1 = 2*idx + 1;
let child2 = 2*idx + 2;
// no more children
if child1 >= len {
break;
}
// find lesser child
let (c1key, _) = self.data[child1];
let (minidx, minkey) = if child2 >= len {
(child1, c1key)
} else {
let (c2key, _) = self.data[child2];
if c1key < c2key {
(child1, c1key)
} else {
(child2, c2key)
}
};
if minkey < key {
self.data.swap(minidx, idx);
idx = minidx;
continue;
}
// smaller than both children, so done
break;
}
ret
}
/// More efficient than inserting and removing in two steps
/// because we save one traversal of the heap.
fn replace(&mut self, next: (u64, u64)) -> (u64, u64) {
self.data.push(next);
self.remove()
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "false"
version = "0.0.1"
authors = []
[lib]
name = "false"
path = "false.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,14 +0,0 @@
#![crate_name = "false"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
pub fn uumain(_: Vec<String>) -> i32 {
1
}

View file

@ -1,13 +0,0 @@
[package]
name = "fmt"
version = "0.0.1"
authors = []
[lib]
name = "fmt"
path = "fmt.rs"
[dependencies]
getopts = "*"
libc = "*"
unicode-width = "*"

View file

@ -1 +0,0 @@
DEPLIBS += unicode-width

View file

@ -1,221 +0,0 @@
#![crate_name = "fmt"]
#![feature(iter_cmp, str_char, unicode)]
/*
* This file is part of `fmt` from the uutils coreutils package.
*
* (c) kwantam <kwantam@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate rustc_unicode;
extern crate unicode_width;
use std::cmp;
use std::io::{Read, BufReader, BufWriter};
use std::fs::File;
use std::io::{stdin, stdout, Write};
use linebreak::break_lines;
use parasplit::ParagraphStream;
macro_rules! silent_unwrap(
($exp:expr) => (
match $exp {
Ok(_) => (),
Err(_) => ::std::process::exit(1),
}
)
);
#[path = "../common/util.rs"]
#[macro_use]
mod util;
mod linebreak;
mod parasplit;
// program's NAME and VERSION are used for -V and -h
static NAME: &'static str = "fmt";
static VERSION: &'static str = "0.0.3";
pub type FileOrStdReader = BufReader<Box<Read+'static>>;
pub struct FmtOptions {
crown : bool,
tagged : bool,
mail : bool,
split_only : bool,
use_prefix : bool,
prefix : String,
xprefix : bool,
use_anti_prefix : bool,
anti_prefix : String,
xanti_prefix : bool,
uniform : bool,
quick : bool,
width : usize,
goal : usize,
tabwidth : usize,
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("c", "crown-margin", "First and second line of paragraph may have different indentations, in which case the first line's indentation is preserved, and each subsequent line's indentation matches the second line.");
opts.optflag("t", "tagged-paragraph", "Like -c, except that the first and second line of a paragraph *must* have different indentation or they are treated as separate paragraphs.");
opts.optflag("m", "preserve-headers", "Attempt to detect and preserve mail headers in the input. Be careful when combining this flag with -p.");
opts.optflag("s", "split-only", "Split lines only, do not reflow.");
opts.optflag("u", "uniform-spacing", "Insert exactly one space between words, and two between sentences. Sentence breaks in the input are detected as [?!.] followed by two spaces or a newline; other punctuation is not interpreted as a sentence break.");
opts.optopt("p", "prefix", "Reformat only lines beginning with PREFIX, reattaching PREFIX to reformatted lines. Unless -x is specified, leading whitespace will be ignored when matching PREFIX.", "PREFIX");
opts.optopt("P", "skip-prefix", "Do not reformat lines beginning with PSKIP. Unless -X is specified, leading whitespace will be ignored when matching PSKIP", "PSKIP");
opts.optflag("x", "exact-prefix", "PREFIX must match at the beginning of the line with no preceding whitespace.");
opts.optflag("X", "exact-skip-prefix", "PSKIP must match at the beginning of the line with no preceding whitespace.");
opts.optopt("w", "width", "Fill output lines up to a maximum of WIDTH columns, default 79.", "WIDTH");
opts.optopt("g", "goal", "Goal width, default ~0.94*WIDTH. Must be less than WIDTH.", "GOAL");
opts.optflag("q", "quick", "Break lines more quickly at the expense of a potentially more ragged appearance.");
opts.optopt("T", "tab-width", "Treat tabs as TABWIDTH spaces for determining line length, default 8. Note that this is used only for calculating line lengths; tabs are preserved in the output.", "TABWIDTH");
opts.optflag("V", "version", "Output version information and exit.");
opts.optflag("h", "help", "Display this help message and exit.");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "{}\nTry `{} --help' for more information.", f, NAME)
};
if matches.opt_present("h") {
println!("Usage: {} [OPTION]... [FILE]...\n\n{}", NAME, opts.usage("Reformat paragraphs from input files (or stdin) to stdout."));
}
if matches.opt_present("V") || matches.opt_present("h") {
println!("{} {}", NAME, VERSION);
return 0
}
let mut fmt_opts = FmtOptions {
crown : false,
tagged : false,
mail : false,
uniform : false,
quick : false,
split_only : false,
use_prefix : false,
prefix : String::new(),
xprefix : false,
use_anti_prefix : false,
anti_prefix : String::new(),
xanti_prefix : false,
width : 79,
goal : 74,
tabwidth : 8,
};
if matches.opt_present("t") { fmt_opts.tagged = true; }
if matches.opt_present("c") { fmt_opts.crown = true; fmt_opts.tagged = false; }
if matches.opt_present("m") { fmt_opts.mail = true; }
if matches.opt_present("u") { fmt_opts.uniform = true; }
if matches.opt_present("q") { fmt_opts.quick = true; }
if matches.opt_present("s") { fmt_opts.split_only = true; fmt_opts.crown = false; fmt_opts.tagged = false; }
if matches.opt_present("x") { fmt_opts.xprefix = true; }
if matches.opt_present("X") { fmt_opts.xanti_prefix = true; }
match matches.opt_str("p") {
Some(s) => {
fmt_opts.prefix = s;
fmt_opts.use_prefix = true;
}
None => ()
};
match matches.opt_str("P") {
Some(s) => {
fmt_opts.anti_prefix = s;
fmt_opts.use_anti_prefix = true;
}
None => ()
};
match matches.opt_str("w") {
Some(s) => {
fmt_opts.width =
match s.parse::<usize>() {
Ok(t) => t,
Err(e) => { crash!(1, "Invalid WIDTH specification: `{}': {}", s, e); }
};
fmt_opts.goal = cmp::min(fmt_opts.width * 94 / 100, fmt_opts.width - 3);
}
None => ()
};
match matches.opt_str("g") {
Some(s) => {
fmt_opts.goal =
match s.parse::<usize>() {
Ok(t) => t,
Err(e) => { crash!(1, "Invalid GOAL specification: `{}': {}", s, e); }
};
if !matches.opt_present("w") {
fmt_opts.width = cmp::max(fmt_opts.goal * 100 / 94, fmt_opts.goal + 3);
} else if fmt_opts.goal > fmt_opts.width {
crash!(1, "GOAL cannot be greater than WIDTH.");
}
}
None => ()
};
match matches.opt_str("T") {
Some(s) => {
fmt_opts.tabwidth =
match s.parse::<usize>() {
Ok(t) => t,
Err(e) => { crash!(1, "Invalid TABWIDTH specification: `{}': {}", s, e); }
};
}
None => ()
};
if fmt_opts.tabwidth < 1 {
fmt_opts.tabwidth = 1;
}
// immutable now
let fmt_opts = fmt_opts;
let mut files = matches.free;
if files.is_empty() {
files.push("-".to_string());
}
let mut ostream = BufWriter::new(stdout());
for i in files.iter().map(|x| &x[..]) {
let mut fp = match i {
"-" => BufReader::new(Box::new(stdin()) as Box<Read+'static>),
_ => match File::open(i) {
Ok(f) => BufReader::new(Box::new(f) as Box<Read+'static>),
Err(e) => {
show_warning!("{}: {}", i, e);
continue;
},
},
};
let p_stream = ParagraphStream::new(&fmt_opts, &mut fp);
for para_result in p_stream {
match para_result {
Err(s) => silent_unwrap!(ostream.write_all(s.as_bytes())),
Ok(para) => break_lines(&para, &fmt_opts, &mut ostream)
}
}
// flush the output after each file
silent_unwrap!(ostream.flush());
}
0
}

View file

@ -1,452 +0,0 @@
/*
* This file is part of `fmt` from the uutils coreutils package.
*
* (c) kwantam <kwantam@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use FmtOptions;
use parasplit::{Paragraph, ParaWords, WordInfo};
use std::io::{Write, BufWriter, Stdout};
use std::i64;
use std::cmp;
use std::mem;
struct BreakArgs<'a> {
opts : &'a FmtOptions,
init_len : usize,
indent_str : &'a str,
indent_len : usize,
uniform : bool,
ostream : &'a mut BufWriter<Stdout>
}
impl<'a> BreakArgs<'a> {
#[inline(always)]
fn compute_width<'b>(&self, winfo: &WordInfo<'b>, posn: usize, fresh: bool) -> usize {
if fresh {
0
} else {
let post = winfo.after_tab;
match winfo.before_tab {
None => post,
Some(pre) => post + ((pre + posn) / self.opts.tabwidth + 1) * self.opts.tabwidth - posn
}
}
}
}
pub fn break_lines(para: &Paragraph, opts: &FmtOptions, ostream: &mut BufWriter<Stdout>) {
// indent
let p_indent = &para.indent_str[..];
let p_indent_len = para.indent_len;
// words
let p_words = ParaWords::new(opts, para);
let mut p_words_words = p_words.words();
// the first word will *always* appear on the first line
// make sure of this here
let (w, w_len) = match p_words_words.next() {
Some(winfo) => (winfo.word, winfo.word_nchars),
None => {
silent_unwrap!(ostream.write_all("\n".as_bytes()));
return;
}
};
// print the init, if it exists, and get its length
let p_init_len = w_len +
if opts.crown || opts.tagged {
// handle "init" portion
silent_unwrap!(ostream.write_all(para.init_str.as_bytes()));
para.init_len
} else if !para.mail_header {
// for non-(crown, tagged) that's the same as a normal indent
silent_unwrap!(ostream.write_all(p_indent.as_bytes()));
p_indent_len
} else {
// except that mail headers get no indent at all
0
};
// write first word after writing init
silent_unwrap!(ostream.write_all(w.as_bytes()));
// does this paragraph require uniform spacing?
let uniform = para.mail_header || opts.uniform;
let mut break_args = BreakArgs {
opts : opts,
init_len : p_init_len,
indent_str : &p_indent[..],
indent_len : p_indent_len,
uniform : uniform,
ostream : ostream
};
if opts.quick || para.mail_header {
break_simple(p_words_words, &mut break_args);
} else {
break_knuth_plass(p_words_words, &mut break_args);
}
}
// break_simple implements a "greedy" breaking algorithm: print words until
// maxlength would be exceeded, then print a linebreak and indent and continue.
fn break_simple<'a, T: Iterator<Item=&'a WordInfo<'a>>>(iter: T, args: &mut BreakArgs<'a>) {
iter.fold((args.init_len, false), |l, winfo| accum_words_simple(args, l, winfo));
silent_unwrap!(args.ostream.write_all("\n".as_bytes()));
}
#[inline(always)]
fn accum_words_simple<'a>(args: &mut BreakArgs<'a>, (l, prev_punct): (usize, bool), winfo: &'a WordInfo<'a>) -> (usize, bool) {
// compute the length of this word, considering how tabs will expand at this position on the line
let wlen = winfo.word_nchars + args.compute_width(winfo, l, false);
let slen = compute_slen(args.uniform, winfo.new_line, winfo.sentence_start, prev_punct);
if l + wlen + slen > args.opts.width {
write_newline(args.indent_str, args.ostream);
write_with_spaces(&winfo.word[winfo.word_start..], 0, args.ostream);
(args.indent_len + winfo.word_nchars, winfo.ends_punct)
} else {
write_with_spaces(winfo.word, slen, args.ostream);
(l + wlen + slen, winfo.ends_punct)
}
}
// break_knuth_plass implements an "optimal" breaking algorithm in the style of
// Knuth, D.E., and Plass, M.F. "Breaking Paragraphs into Lines." in Software,
// Practice and Experience. Vol. 11, No. 11, November 1981.
// http://onlinelibrary.wiley.com/doi/10.1002/spe.4380111102/pdf
fn break_knuth_plass<'a, T: Clone + Iterator<Item=&'a WordInfo<'a>>>(mut iter: T, args: &mut BreakArgs<'a>) {
// run the algorithm to get the breakpoints
let breakpoints = find_kp_breakpoints(iter.clone(), args);
// iterate through the breakpoints (note that breakpoints is in reverse break order, so we .rev() it
let (mut prev_punct, mut fresh) =
breakpoints.iter().rev().fold((false, false), |(mut prev_punct, mut fresh), &(next_break, break_before)| {
if fresh {
write_newline(args.indent_str, args.ostream);
}
// at each breakpoint, keep emitting words until we find the word matching this breakpoint
for winfo in &mut iter {
let (slen, word) = slice_if_fresh(fresh, winfo.word, winfo.word_start, args.uniform,
winfo.new_line, winfo.sentence_start, prev_punct);
fresh = false;
prev_punct = winfo.ends_punct;
// We find identical breakpoints here by comparing addresses of the references.
// This is OK because the backing vector is not mutating once we are linebreaking.
let winfo_ptr = winfo as *const _;
let next_break_ptr = next_break as *const _;
if winfo_ptr == next_break_ptr {
// OK, we found the matching word
if break_before {
write_newline(args.indent_str, args.ostream);
write_with_spaces(&winfo.word[winfo.word_start..], 0, args.ostream);
} else {
// breaking after this word, so that means "fresh" is true for the next iteration
write_with_spaces(word, slen, args.ostream);
fresh = true;
}
break;
} else {
write_with_spaces(word, slen, args.ostream);
}
}
(prev_punct, fresh)
});
// after the last linebreak, write out the rest of the final line.
for winfo in iter {
if fresh {
write_newline(args.indent_str, args.ostream);
}
let (slen, word) = slice_if_fresh(fresh, winfo.word, winfo.word_start, args.uniform,
winfo.new_line, winfo.sentence_start, prev_punct);
prev_punct = winfo.ends_punct;
fresh = false;
write_with_spaces(word, slen, args.ostream);
}
silent_unwrap!(args.ostream.write_all("\n".as_bytes()));
}
struct LineBreak<'a> {
prev : usize,
linebreak : Option<&'a WordInfo<'a>>,
break_before : bool,
demerits : i64,
prev_rat : f32,
length : usize,
fresh : bool
}
fn find_kp_breakpoints<'a, T: Iterator<Item=&'a WordInfo<'a>>>(iter: T, args: &BreakArgs<'a>) -> Vec<(&'a WordInfo<'a>, bool)> {
let mut iter = iter.peekable();
// set up the initial null linebreak
let mut linebreaks = vec!(LineBreak {
prev : 0,
linebreak : None,
break_before : false,
demerits : 0,
prev_rat : 0.0f32,
length : args.init_len,
fresh : false
});
// this vec holds the current active linebreaks; next_ holds the breaks that will be active for the next word
let active_breaks = &mut vec!(0);
let next_active_breaks = &mut vec!();
let stretch = (args.opts.width - args.opts.goal) as isize;
let minlength = args.opts.goal - stretch as usize;
let mut new_linebreaks = vec!();
let mut is_sentence_start = false;
let mut least_demerits = 0;
loop {
let w =
match iter.next() {
None => break,
Some(w) => w
};
// if this is the last word, we don't add additional demerits for this break
let (is_last_word, is_sentence_end) =
match iter.peek() {
None => (true, true),
Some(&&WordInfo { sentence_start: st, new_line: nl, .. }) => (false, st || (nl && w.ends_punct))
};
// should we be adding extra space at the beginning of the next sentence?
let slen = compute_slen(args.uniform, w.new_line, is_sentence_start, false);
let mut ld_new = i64::MAX;
let mut ld_next = i64::MAX;
let mut ld_idx = 0;
new_linebreaks.clear();
next_active_breaks.clear();
// go through each active break, extending it and possibly adding a new active
// break if we are above the minimum required length
for &i in active_breaks.iter() {
let active = &mut linebreaks[i];
// normalize demerits to avoid overflow, and record if this is the least
active.demerits -= least_demerits;
if active.demerits < ld_next {
ld_next = active.demerits;
ld_idx = i;
}
// get the new length
let tlen = w.word_nchars + args.compute_width(w, active.length, active.fresh) + slen + active.length;
// if tlen is longer than args.opts.width, we drop this break from the active list
// otherwise, we extend the break, and possibly add a new break at this point
if tlen <= args.opts.width {
// this break will still be active next time
next_active_breaks.push(i);
// we can put this word on this line
active.fresh = false;
active.length = tlen;
// if we're above the minlength, we can also consider breaking here
if tlen >= minlength {
let (new_demerits, new_ratio) =
if is_last_word {
// there is no penalty for the final line's length
(0, 0.0)
} else {
compute_demerits((args.opts.goal - tlen) as isize, stretch, w.word_nchars as isize, active.prev_rat)
};
// do not even consider adding a line that has too many demerits
// also, try to detect overflow by checking signum
let total_demerits = new_demerits + active.demerits;
if new_demerits < BAD_INFTY_SQ && total_demerits < ld_new && active.demerits.signum() <= new_demerits.signum() {
ld_new = total_demerits;
new_linebreaks.push(LineBreak {
prev : i,
linebreak : Some(w),
break_before : false,
demerits : total_demerits,
prev_rat : new_ratio,
length : args.indent_len,
fresh : true
});
}
}
}
}
// if we generated any new linebreaks, add the last one to the list
// the last one is always the best because we don't add to new_linebreaks unless
// it's better than the best one so far
match new_linebreaks.pop() {
None => (),
Some(lb) => {
next_active_breaks.push(linebreaks.len());
linebreaks.push(lb);
}
}
if next_active_breaks.is_empty() {
// every potential linebreak is too long! choose the linebreak with the least demerits, ld_idx
let new_break = restart_active_breaks(args, &linebreaks[ld_idx], ld_idx, w, slen, minlength);
next_active_breaks.push(linebreaks.len());
linebreaks.push(new_break);
least_demerits = 0;
} else {
// next time around, normalize out the demerits fields
// on active linebreaks to make overflow less likely
least_demerits = cmp::max(ld_next, 0);
}
// swap in new list of active breaks
mem::swap(active_breaks, next_active_breaks);
// If this was the last word in a sentence, the next one must be the first in the next.
is_sentence_start = is_sentence_end;
}
// return the best path
build_best_path(&linebreaks, active_breaks)
}
#[inline(always)]
fn build_best_path<'a>(paths: &Vec<LineBreak<'a>>, active: &Vec<usize>) -> Vec<(&'a WordInfo<'a>, bool)> {
let mut breakwords = vec!();
// of the active paths, we select the one with the fewest demerits
let mut best_idx = match active.iter().min_by(|&&a| paths[a].demerits) {
None => crash!(1, "Failed to find a k-p linebreak solution. This should never happen."),
Some(&s) => s
};
// now, chase the pointers back through the break list, recording
// the words at which we should break
loop {
let ref next_best = paths[best_idx];
match next_best.linebreak {
None => return breakwords,
Some(prev) => {
breakwords.push((prev, next_best.break_before));
best_idx = next_best.prev
}
}
}
}
// "infinite" badness is more like (1+BAD_INFTY)^2 because of how demerits are computed
const BAD_INFTY: i64 = 10000000;
const BAD_INFTY_SQ: i64 = BAD_INFTY * BAD_INFTY;
// badness = BAD_MULT * abs(r) ^ 3
const BAD_MULT: f32 = 100.0;
// DR_MULT is multiplier for delta-R between lines
const DR_MULT: f32 = 600.0;
// DL_MULT is penalty multiplier for short words at end of line
const DL_MULT: f32 = 300.0;
#[inline(always)]
fn compute_demerits(delta_len: isize, stretch: isize, wlen: isize, prev_rat: f32) -> (i64, f32) {
// how much stretch are we using?
let ratio =
if delta_len == 0 {
0.0f32
} else {
delta_len as f32 / stretch as f32
};
// compute badness given the stretch ratio
let bad_linelen =
if ratio.abs() > 1.0f32 {
BAD_INFTY
} else {
(BAD_MULT * ratio.powf(3f32).abs()) as i64
};
// we penalize lines ending in really short words
let bad_wordlen =
if wlen >= stretch {
0
} else {
(DL_MULT * ((stretch - wlen) as f32 / (stretch - 1) as f32).powf(3f32).abs()) as i64
};
// we penalize lines that have very different ratios from previous lines
let bad_delta_r = (DR_MULT * (((ratio - prev_rat) / 2.0).powf(3f32)).abs()) as i64;
let demerits = i64::pow(1 + bad_linelen + bad_wordlen + bad_delta_r, 2);
(demerits, ratio)
}
#[inline(always)]
fn restart_active_breaks<'a>(args: &BreakArgs<'a>, active: &LineBreak<'a>, act_idx: usize, w: &'a WordInfo<'a>, slen: usize, min: usize) -> LineBreak<'a> {
let (break_before, line_length) =
if active.fresh {
// never break before a word if that word would be the first on a line
(false, args.indent_len)
} else {
// choose the lesser evil: breaking too early, or breaking too late
let wlen = w.word_nchars + args.compute_width(w, active.length, active.fresh);
let underlen = (min - active.length) as isize;
let overlen = ((wlen + slen + active.length) - args.opts.width) as isize;
if overlen > underlen {
// break early, put this word on the next line
(true, args.indent_len + w.word_nchars)
} else {
(false, args.indent_len)
}
};
// restart the linebreak. This will be our only active path.
LineBreak {
prev : act_idx,
linebreak : Some(w),
break_before : break_before,
demerits : 0, // this is the only active break, so we can reset the demerit count
prev_rat : if break_before { 1.0 } else { -1.0 },
length : line_length,
fresh : !break_before
}
}
// Number of spaces to add before a word, based on mode, newline, sentence start.
#[inline(always)]
fn compute_slen(uniform: bool, newline: bool, start: bool, punct: bool) -> usize {
if uniform || newline {
if start || (newline && punct) {
2
} else {
1
}
} else {
0
}
}
// If we're on a fresh line, slen=0 and we slice off leading whitespace.
// Otherwise, compute slen and leave whitespace alone.
#[inline(always)]
fn slice_if_fresh<'a>(fresh: bool, word: &'a str, start: usize, uniform: bool, newline: bool, sstart: bool, punct: bool) -> (usize, &'a str) {
if fresh {
(0, &word[start..])
} else {
(compute_slen(uniform, newline, sstart, punct), word)
}
}
// Write a newline and add the indent.
#[inline(always)]
fn write_newline(indent: &str, ostream: &mut BufWriter<Stdout>) {
silent_unwrap!(ostream.write_all("\n".as_bytes()));
silent_unwrap!(ostream.write_all(indent.as_bytes()));
}
// Write the word, along with slen spaces.
#[inline(always)]
fn write_with_spaces(word: &str, slen: usize, ostream: &mut BufWriter<Stdout>) {
if slen == 2 {
silent_unwrap!(ostream.write_all(" ".as_bytes()));
} else if slen == 1 {
silent_unwrap!(ostream.write_all(" ".as_bytes()));
}
silent_unwrap!(ostream.write_all(word.as_bytes()));
}

View file

@ -1,570 +0,0 @@
/*
* This file is part of `fmt` from the uutils coreutils package.
*
* (c) kwantam <kwantam@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use std::iter::Peekable;
use std::io::{BufRead, Lines};
use std::slice::Iter;
use std::str::CharRange;
use unicode_width::UnicodeWidthChar;
use FileOrStdReader;
use FmtOptions;
#[inline(always)]
fn char_width(c: char) -> usize {
if (c as usize) < 0xA0 {
// if it is ASCII, call it exactly 1 wide (including control chars)
// calling control chars' widths 1 is consistent with OpenBSD fmt
1
} else {
// otherwise, get the unicode width
// note that we shouldn't actually get None here because only c < 0xA0
// can return None, but for safety and future-proofing we do it this way
UnicodeWidthChar::width(c).unwrap_or(1)
}
}
// lines with PSKIP, lacking PREFIX, or which are entirely blank are
// NoFormatLines; otherwise, they are FormatLines
#[derive(Debug)]
pub enum Line {
FormatLine(FileLine),
NoFormatLine(String, bool)
}
impl Line {
// when we know that it's a FormatLine, as in the ParagraphStream iterator
fn get_formatline(self) -> FileLine {
match self {
Line::FormatLine(fl) => fl,
Line::NoFormatLine(..) => panic!("Found NoFormatLine when expecting FormatLine")
}
}
// when we know that it's a NoFormatLine, as in the ParagraphStream iterator
fn get_noformatline(self) -> (String, bool) {
match self {
Line::NoFormatLine(s, b) => (s, b),
Line::FormatLine(..) => panic!("Found FormatLine when expecting NoFormatLine")
}
}
}
// each line's prefix has to be considered to know whether to merge it with
// the next line or not
#[derive(Debug)]
struct FileLine {
line : String,
indent_end : usize, // the end of the indent, always the start of the text
pfxind_end : usize, // the end of the PREFIX's indent, that is, the spaces before the prefix
indent_len : usize, // display length of indent taking into account tabs
prefix_len : usize, // PREFIX indent length taking into account tabs
}
// iterator that produces a stream of Lines from a file
pub struct FileLines<'a> {
opts : &'a FmtOptions,
lines : Lines<&'a mut FileOrStdReader>,
}
impl<'a> FileLines<'a> {
fn new<'b>(opts: &'b FmtOptions, lines: Lines<&'b mut FileOrStdReader>) -> FileLines<'b> {
FileLines { opts: opts, lines: lines }
}
// returns true if this line should be formatted
fn match_prefix(&self, line: &str) -> (bool, usize) {
if !self.opts.use_prefix { return (true, 0); }
FileLines::match_prefix_generic(&self.opts.prefix[..], line, self.opts.xprefix)
}
// returns true if this line should be formatted
fn match_anti_prefix(&self, line: &str) -> bool {
if !self.opts.use_anti_prefix { return true; }
match FileLines::match_prefix_generic(&self.opts.anti_prefix[..], line, self.opts.xanti_prefix) {
(true, _) => false,
(_ , _) => true
}
}
fn match_prefix_generic(pfx: &str, line: &str, exact: bool) -> (bool, usize) {
if line.starts_with(pfx) {
return (true, 0);
}
if !exact {
// we do it this way rather than byte indexing to support unicode whitespace chars
let mut i = 0;
while (i < line.len()) && line.char_at(i).is_whitespace() {
i = match line.char_range_at(i) { CharRange { ch: _ , next: nxi } => nxi };
if line[i..].starts_with(pfx) {
return (true, i);
}
}
}
(false, 0)
}
fn compute_indent(&self, string: &str, prefix_end: usize) -> (usize, usize, usize) {
let mut prefix_len = 0;
let mut indent_len = 0;
let mut indent_end = 0;
for (os, c) in string.char_indices() {
if os == prefix_end {
// we found the end of the prefix, so this is the printed length of the prefix here
prefix_len = indent_len;
}
if (os >= prefix_end) && !c.is_whitespace() {
// found first non-whitespace after prefix, this is indent_end
indent_end = os;
break;
} else if c == '\t' {
// compute tab length
indent_len = (indent_len / self.opts.tabwidth + 1) * self.opts.tabwidth;
} else {
// non-tab character
indent_len += char_width(c);
}
}
(indent_end, prefix_len, indent_len)
}
}
impl<'a> Iterator for FileLines<'a> {
type Item = Line;
fn next(&mut self) -> Option<Line> {
let n =
match self.lines.next() {
Some(t) => match t {
Ok(tt) => tt,
Err(_) => return None
},
None => return None
};
// if this line is entirely whitespace,
// emit a blank line
// Err(true) indicates that this was a linebreak,
// which is important to know when detecting mail headers
if n.chars().all(|c| c.is_whitespace()) {
return Some(Line::NoFormatLine("\n".to_string(), true));
}
// if this line does not match the prefix,
// emit the line unprocessed and iterate again
let (pmatch, poffset) = self.match_prefix(&n[..]);
if !pmatch {
return Some(Line::NoFormatLine(n, false));
} else if n[poffset + self.opts.prefix.len()..].chars().all(|c| c.is_whitespace()) {
// if the line matches the prefix, but is blank after,
// don't allow lines to be combined through it (that is,
// treat it like a blank line, except that since it's
// not truly blank we will not allow mail headers on the
// following line)
return Some(Line::NoFormatLine(n, false));
}
// skip if this line matches the anti_prefix
// (NOTE definition of match_anti_prefix is TRUE if we should process)
if !self.match_anti_prefix(&n[..]) {
return Some(Line::NoFormatLine(n, false));
}
// figure out the indent, prefix, and prefixindent ending points
let prefix_end = poffset + self.opts.prefix.len();
let (indent_end, prefix_len, indent_len) = self.compute_indent(&n[..], prefix_end);
Some(Line::FormatLine(FileLine {
line : n,
indent_end : indent_end,
pfxind_end : poffset,
indent_len : indent_len,
prefix_len : prefix_len
}))
}
}
// a paragraph : a collection of FileLines that are to be formatted
// plus info about the paragraph's indentation
// (but we only retain the String from the FileLine; the other info
// is only there to help us in deciding how to merge lines into Paragraphs
#[derive(Debug)]
pub struct Paragraph {
lines : Vec<String>, // the lines of the file
pub init_str : String, // string representing the init, that is, the first line's indent
pub init_len : usize, // printable length of the init string considering TABWIDTH
init_end : usize, // byte location of end of init in first line String
pub indent_str : String, // string representing indent
pub indent_len : usize, // length of above
indent_end : usize, // byte location of end of indent (in crown and tagged mode, only applies to 2nd line and onward)
pub mail_header : bool // we need to know if this is a mail header because we do word splitting differently in that case
}
// an iterator producing a stream of paragraphs from a stream of lines
// given a set of options.
pub struct ParagraphStream<'a> {
lines : Peekable<FileLines<'a>>,
next_mail : bool,
opts : &'a FmtOptions,
}
impl<'a> ParagraphStream<'a> {
pub fn new<'b>(opts: &'b FmtOptions, reader: &'b mut FileOrStdReader) -> ParagraphStream<'b> {
let lines = FileLines::new(opts, reader.lines()).peekable();
// at the beginning of the file, we might find mail headers
ParagraphStream { lines: lines, next_mail: true, opts: opts }
}
// detect RFC822 mail header
fn is_mail_header(line: &FileLine) -> bool {
// a mail header begins with either "From " (envelope sender line)
// or with a sequence of printable ASCII chars (33 to 126, inclusive,
// except colon) followed by a colon.
if line.indent_end > 0 {
false
} else {
let l_slice = &line.line[..];
if l_slice.starts_with("From ") {
true
} else {
let colon_posn =
match l_slice.find(':') {
Some(n) => n,
None => return false
};
// header field must be nonzero length
if colon_posn == 0 { return false; }
return l_slice[..colon_posn].chars().all(|x| match x as usize {
y if y < 33 || y > 126 => false,
_ => true
});
}
}
}
}
impl<'a> Iterator for ParagraphStream<'a> {
type Item = Result<Paragraph, String>;
fn next(&mut self) -> Option<Result<Paragraph, String>> {
// return a NoFormatLine in an Err; it should immediately be output
let noformat =
match self.lines.peek() {
None => return None,
Some(l) => match l {
&Line::FormatLine(_) => false,
&Line::NoFormatLine(_, _) => true
}
};
// found a NoFormatLine, immediately dump it out
if noformat {
let (s, nm) = self.lines.next().unwrap().get_noformatline();
self.next_mail = nm;
return Some(Err(s));
}
// found a FormatLine, now build a paragraph
let mut init_str = String::new();
let mut init_end = 0;
let mut init_len = 0;
let mut indent_str = String::new();
let mut indent_end = 0;
let mut indent_len = 0;
let mut prefix_len = 0;
let mut pfxind_end = 0;
let mut p_lines = Vec::new();
let mut in_mail = false;
let mut second_done = false; // for when we use crown or tagged mode
loop {
{ // peek ahead
// need to explicitly force fl out of scope before we can call self.lines.next()
let fl =
match self.lines.peek() {
None => break,
Some(l) => {
match l {
&Line::FormatLine(ref x) => x,
&Line::NoFormatLine(..) => break
}
}
};
if p_lines.len() == 0 {
// first time through the loop, get things set up
// detect mail header
if self.opts.mail && self.next_mail && ParagraphStream::is_mail_header(fl) {
in_mail = true;
// there can't be any indent or pfxind because otherwise is_mail_header would fail
// since there cannot be any whitespace before the colon in a valid header field
indent_str.push_str(" ");
indent_len = 2;
} else {
if self.opts.crown || self.opts.tagged {
init_str.push_str(&fl.line[..fl.indent_end]);
init_len = fl.indent_len;
init_end = fl.indent_end;
} else {
second_done = true;
}
// these will be overwritten in the 2nd line of crown or tagged mode, but
// we are not guaranteed to get to the 2nd line, e.g., if the next line
// is a NoFormatLine or None. Thus, we set sane defaults the 1st time around
indent_str.push_str(&fl.line[..fl.indent_end]);
indent_len = fl.indent_len;
indent_end = fl.indent_end;
// save these to check for matching lines
prefix_len = fl.prefix_len;
pfxind_end = fl.pfxind_end;
// in tagged mode, add 4 spaces of additional indenting by default
// (gnu fmt's behavior is different: it seems to find the closest column to
// indent_end that is divisible by 3. But honesly that behavior seems
// pretty arbitrary.
// Perhaps a better default would be 1 TABWIDTH? But ugh that's so big.
if self.opts.tagged {
indent_str.push_str(" ");
indent_len += 4;
}
}
} else if in_mail {
// lines following mail headers must begin with spaces
if fl.indent_end == 0 || (self.opts.use_prefix && fl.pfxind_end == 0) {
break; // this line does not begin with spaces
}
} else if !second_done {
// now we have enough info to handle crown margin and tagged mode
if prefix_len != fl.prefix_len || pfxind_end != fl.pfxind_end {
// in both crown and tagged modes we require that prefix_len is the same
break;
} else if self.opts.tagged && indent_len - 4 == fl.indent_len && indent_end == fl.indent_end {
// in tagged mode, indent has to be *different* on following lines
break;
} else {
// this is part of the same paragraph, get the indent info from this line
indent_str.clear();
indent_str.push_str(&fl.line[..fl.indent_end]);
indent_len = fl.indent_len;
indent_end = fl.indent_end;
}
second_done = true;
} else {
// detect mismatch
if indent_end != fl.indent_end || pfxind_end != fl.pfxind_end || indent_len != fl.indent_len || prefix_len != fl.prefix_len {
break;
}
}
}
p_lines.push(self.lines.next().unwrap().get_formatline().line);
// when we're in split-only mode, we never join lines, so stop here
if self.opts.split_only {
break;
}
}
// if this was a mail header, then the next line can be detected as one. Otherwise, it cannot.
// NOTE next_mail is true at ParagraphStream instantiation, and is set to true after a blank
// NoFormatLine.
self.next_mail = in_mail;
Some(Ok(Paragraph {
lines : p_lines,
init_str : init_str,
init_len : init_len,
init_end : init_end,
indent_str : indent_str,
indent_len : indent_len,
indent_end : indent_end,
mail_header : in_mail
}))
}
}
pub struct ParaWords<'a> {
opts : &'a FmtOptions,
para : &'a Paragraph,
words : Vec<WordInfo<'a>>
}
impl<'a> ParaWords<'a> {
pub fn new<'b>(opts: &'b FmtOptions, para: &'b Paragraph) -> ParaWords<'b> {
let mut pw = ParaWords { opts: opts, para: para, words: Vec::new() };
pw.create_words();
pw
}
fn create_words<'r>(&'r mut self) {
if self.para.mail_header {
// no extra spacing for mail headers; always exactly 1 space
// safe to trim_left on every line of a mail header, since the
// first line is guaranteed not to have any spaces
self.words.extend(self.para.lines.iter().flat_map(|x| x.split_whitespace()).map(|x| WordInfo {
word : x,
word_start : 0,
word_nchars : x.len(), // OK for mail headers; only ASCII allowed (unicode is escaped)
before_tab : None,
after_tab : 0,
sentence_start : false,
ends_punct : false,
new_line : false
}));
} else {
// first line
self.words.extend(
if self.opts.crown || self.opts.tagged {
// crown and tagged mode has the "init" in the first line, so slice from there
WordSplit::new(self.opts, &self.para.lines[0][self.para.init_end..])
} else {
// otherwise we slice from the indent
WordSplit::new(self.opts, &self.para.lines[0][self.para.indent_end..])
});
if self.para.lines.len() > 1 {
let indent_end = self.para.indent_end;
let opts = self.opts;
self.words.extend(
self.para.lines.iter().skip(1).flat_map(|x| WordSplit::new(opts, &x[indent_end..])));
}
}
}
pub fn words(&'a self) -> Iter<'a, WordInfo<'a>> { return self.words.iter() }
}
struct WordSplit<'a> {
opts : &'a FmtOptions,
string : &'a str,
length : usize,
position : usize,
prev_punct : bool
}
impl<'a> WordSplit<'a> {
fn analyze_tabs(&self, string: &str) -> (Option<usize>, usize, Option<usize>) {
// given a string, determine (length before tab) and (printed length after first tab)
// if there are no tabs, beforetab = -1 and aftertab is the printed length
let mut beforetab = None;
let mut aftertab = 0;
let mut word_start = None;
for (os, c) in string.char_indices() {
if !c.is_whitespace() {
word_start = Some(os);
break;
} else if c == '\t' {
if beforetab == None {
beforetab = Some(aftertab);
aftertab = 0;
} else {
aftertab = (aftertab / self.opts.tabwidth + 1) * self.opts.tabwidth;
}
} else {
aftertab += 1;
}
}
(beforetab, aftertab, word_start)
}
}
impl<'a> WordSplit<'a> {
fn new<'b>(opts: &'b FmtOptions, string: &'b str) -> WordSplit<'b> {
// wordsplits *must* start at a non-whitespace character
let trim_string = string.trim_left();
WordSplit { opts: opts, string: trim_string, length: string.len(), position: 0, prev_punct: false }
}
fn is_punctuation(c: char) -> bool {
match c {
'!' | '.' | '?' => true,
_ => false
}
}
}
pub struct WordInfo<'a> {
pub word : &'a str,
pub word_start : usize,
pub word_nchars : usize,
pub before_tab : Option<usize>,
pub after_tab : usize,
pub sentence_start : bool,
pub ends_punct : bool,
pub new_line : bool
}
// returns (&str, is_start_of_sentence)
impl<'a> Iterator for WordSplit<'a> {
type Item = WordInfo<'a>;
fn next(&mut self) -> Option<WordInfo<'a>> {
if self.position >= self.length {
return None
}
let old_position = self.position;
let new_line = old_position == 0;
// find the start of the next word, and record if we find a tab character
let (before_tab, after_tab, word_start) = match self.analyze_tabs(&self.string[old_position..]) {
(b, a, Some(s)) => (b, a, s + old_position),
(_, _, None) => {
self.position = self.length;
return None;
}
};
// find the beginning of the next whitespace
// note that this preserves the invariant that self.position
// points to whitespace character OR end of string
let mut word_nchars = 0;
self.position =
match self.string[word_start..]
.find(|x: char| if !x.is_whitespace() { word_nchars += char_width(x); false } else { true }) {
None => self.length,
Some(s) => s + word_start
};
let word_start_relative = word_start - old_position;
// if the previous sentence was punctuation and this sentence has >2 whitespace or one tab, is a new sentence.
let is_start_of_sentence = self.prev_punct && (before_tab.is_some() || word_start_relative > 1);
// now record whether this word ends in punctuation
self.prev_punct = match self.string.char_range_at_reverse(self.position) {
CharRange { ch, next: _ } => WordSplit::is_punctuation(ch)
};
let (word, word_start_relative, before_tab, after_tab) =
if self.opts.uniform {
(&self.string[word_start..self.position], 0, None, 0)
} else {
(&self.string[old_position..self.position], word_start_relative, before_tab, after_tab)
};
Some(WordInfo {
word : word,
word_start : word_start_relative,
word_nchars : word_nchars,
before_tab : before_tab,
after_tab : after_tab,
sentence_start : is_start_of_sentence,
ends_punct : self.prev_punct,
new_line : new_line
})
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "fold"
version = "0.0.1"
authors = []
[lib]
name = "fold"
path = "fold.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,222 +0,0 @@
#![crate_name = "fold"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Arcterus <arcterus@mail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
use std::fs::File;
use std::io::{BufRead, BufReader, Read, stdin, Write};
use std::path::Path;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "fold";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
let (args, obs_width) = handle_obsolete(&args[..]);
let mut opts = getopts::Options::new();
opts.optflag("b", "bytes", "count using bytes rather than columns (meaning control characters such as newline are not treated specially)");
opts.optflag("s", "spaces", "break lines at word boundaries rather than a hard cut-off");
opts.optopt("w", "width", "set WIDTH as the maximum line width rather than 80", "WIDTH");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "{}", f)
};
if matches.opt_present("h") {
println!("{} {}", NAME, VERSION);
println!("");
println!("Usage:");
println!(" {} [OPTION]... [FILE]...", NAME);
println!("");
print!("{}", opts.usage("Writes each file (or standard input if no files are given) to standard output whilst breaking long lines"));
} else if matches.opt_present("V") {
println!("{} {}", NAME, VERSION);
} else {
let bytes = matches.opt_present("b");
let spaces = matches.opt_present("s");
let poss_width =
if matches.opt_present("w") {
matches.opt_str("w")
} else {
match obs_width {
Some(v) => Some(v.to_string()),
None => None,
}
};
let width = match poss_width {
Some(inp_width) => match inp_width.parse::<usize>() {
Ok(width) => width,
Err(e) => crash!(1, "illegal width value (\"{}\"): {}", inp_width, e)
},
None => 80
};
let files = if matches.free.is_empty() {
vec!("-".to_string())
} else {
matches.free
};
fold(files, bytes, spaces, width);
}
0
}
fn handle_obsolete(args: &[String]) -> (Vec<String>, Option<String>) {
for (i, arg) in args.iter().enumerate() {
let slice = &arg;
if slice.chars().next().unwrap() == '-' && slice.len() > 1 && slice.chars().nth(1).unwrap().is_digit(10) {
let mut v = args.to_vec();
v.remove(i);
return (v, Some(slice[1..].to_string()));
}
}
(args.to_vec(), None)
}
#[inline]
fn fold(filenames: Vec<String>, bytes: bool, spaces: bool, width: usize) {
for filename in filenames.iter() {
let filename: &str = &filename;
let mut stdin_buf;
let mut file_buf;
let buffer = BufReader::new(
if filename == "-" {
stdin_buf = stdin();
&mut stdin_buf as &mut Read
} else {
file_buf = safe_unwrap!(File::open(Path::new(filename)));
&mut file_buf as &mut Read
}
);
fold_file(buffer, bytes, spaces, width);
}
}
#[inline]
fn fold_file<T: Read>(mut file: BufReader<T>, bytes: bool, spaces: bool, width: usize) {
let mut line = String::new();
while safe_unwrap!(file.read_line(&mut line)) > 0 {
if bytes {
let len = line.len();
let mut i = 0;
while i < len {
let width = if len - i >= width { width } else { len - i };
let slice = {
let slice = &line[i..i + width];
if spaces && i + width < len {
match slice.rfind(|ch: char| ch.is_whitespace()) {
Some(m) => &slice[..m + 1],
None => slice
}
} else {
slice
}
};
print!("{}", slice);
i += slice.len();
}
} else {
let mut len = line.chars().count();
let newline = line.ends_with("\n");
if newline {
if len == 1 {
println!("");
continue;
}
len -= 1;
line.truncate(len);
}
let mut output = String::new();
let mut count = 0;
for (i, ch) in line.chars().enumerate() {
if count >= width {
let (val, ncount) = {
let slice = &output[..];
let (out, val, ncount) =
if spaces && i + 1 < len {
match rfind_whitespace(slice) {
Some(m) => {
let routput = &slice[m + 1 .. slice.chars().count()];
let ncount = routput.chars().fold(0, |out, ch: char| {
out + match ch {
'\t' => 8,
'\x08' => if out > 0 { !0 } else { 0 },
'\r' => return 0,
_ => 1
}
});
(&slice[0 .. m + 1], routput, ncount)
},
None => (slice, "", 0)
}
} else {
(slice, "", 0)
};
println!("{}", out);
(val.to_string(), ncount)
};
output = val;
count = ncount;
}
match ch {
'\t' => {
count += 8;
if count > width {
println!("{}", output);
output.truncate(0);
count = 8;
}
}
'\x08' => {
if count > 0 {
count -= 1;
let len = output.len() - 1;
output.truncate(len);
}
continue;
}
'\r' => {
output.truncate(0);
count = 0;
continue;
}
_ => count += 1
};
output.push(ch);
}
if count > 0 {
if newline {
println!("{}", output);
} else {
print!("{}", output);
}
}
}
}
}
#[inline]
fn rfind_whitespace(slice: &str) -> Option<usize> {
for (i, ch) in slice.chars().rev().enumerate() {
if ch.is_whitespace() {
return Some(slice.chars().count() - (i + 1));
}
}
None
}

View file

@ -1,12 +0,0 @@
[package]
name = "groups"
version = "0.0.1"
authors = []
[lib]
name = "groups"
path = "groups.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,52 +0,0 @@
#![crate_name = "groups"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Alan Andrade <alan.andradec@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
*/
extern crate getopts;
use c_types::{get_pw_from_args, group};
use std::io::Write;
#[path = "../common/util.rs"] #[macro_use] mod util;
#[path = "../common/c_types.rs"] mod c_types;
static NAME: &'static str = "groups";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("h", "help", "display this help menu and exit");
opts.optflag("V", "version", "display version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m },
Err(f) => {
show_error!("{}", f);
return 1;
}
};
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
} else if matches.opt_present("help") {
let msg = format!("{0} {1}
Usage:
{0} [OPTION]... [USER]...
Prints the groups a user is in to standard output.", NAME, VERSION);
print!("{}", opts.usage(&msg));
} else {
group(get_pw_from_args(&matches.free), true);
}
0
}

View file

@ -1,15 +0,0 @@
[package]
name = "hashsum"
version = "0.0.1"
authors = []
[lib]
name = "hashsum"
path = "hashsum.rs"
[dependencies]
getopts = "*"
libc = "*"
regex = "*"
regex-syntax = "*"
rust-crypto = "*"

View file

@ -1 +0,0 @@
DEPLIBS += regex regex-syntax crypto rand rustc-serialize time winapi kernel32

View file

@ -1,309 +0,0 @@
#![crate_name = "hashsum"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Arcterus <arcterus@mail.com>
* (c) Vsevolod Velichko <torkvemada@sorokdva.net>
* (c) Gil Cottle <gcottle@redtown.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate crypto;
extern crate getopts;
extern crate regex_syntax;
extern crate regex;
use crypto::digest::Digest;
use crypto::md5::Md5;
use crypto::sha1::Sha1;
use crypto::sha2::{Sha224, Sha256, Sha384, Sha512};
use regex::Regex;
use std::ascii::AsciiExt;
use std::fs::File;
use std::io::{self, BufRead, BufReader, Read, stdin, Write};
use std::path::Path;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "hashsum";
static VERSION: &'static str = "1.0.0";
fn is_custom_binary(program: &str) -> bool {
match program {
"md5sum" | "sha1sum"
| "sha224sum" | "sha256sum"
| "sha384sum" | "sha512sum" => true,
_ => false
}
}
fn detect_algo(program: &str, matches: &getopts::Matches) -> (&'static str, Box<Digest+'static>) {
let mut alg: Option<Box<Digest>> = None;
let mut name: &'static str = "";
match program {
"md5sum" => ("MD5", Box::new(Md5::new()) as Box<Digest>),
"sha1sum" => ("SHA1", Box::new(Sha1::new()) as Box<Digest>),
"sha224sum" => ("SHA224", Box::new(Sha224::new()) as Box<Digest>),
"sha256sum" => ("SHA256", Box::new(Sha256::new()) as Box<Digest>),
"sha384sum" => ("SHA384", Box::new(Sha384::new()) as Box<Digest>),
"sha512sum" => ("SHA512", Box::new(Sha512::new()) as Box<Digest>),
_ => {
{
let mut set_or_crash = |n, val| -> () {
if alg.is_some() { crash!(1, "You cannot combine multiple hash algorithms!") };
name = n;
alg = Some(val);
};
if matches.opt_present("md5") { set_or_crash("MD5", Box::new(Md5::new())) };
if matches.opt_present("sha1") { set_or_crash("SHA1", Box::new(Sha1::new())) };
if matches.opt_present("sha224") { set_or_crash("SHA224", Box::new(Sha224::new())) };
if matches.opt_present("sha256") { set_or_crash("SHA256", Box::new(Sha256::new())) };
if matches.opt_present("sha384") { set_or_crash("SHA384", Box::new(Sha384::new())) };
if matches.opt_present("sha512") { set_or_crash("SHA512", Box::new(Sha512::new())) };
}
if alg.is_none() { crash!(1, "You must specify hash algorithm!") };
(name, alg.unwrap())
}
}
}
pub fn uumain(args: Vec<String>) -> i32 {
let program = &args[0];
let binary_name = Path::new(program).file_name().unwrap().to_str().unwrap();
// Default binary in Windows, text mode otherwise
let binary_flag_default = cfg!(windows);
let mut opts = getopts::Options::new();
opts.optflag("b", "binary", &format!("read in binary mode{}", if binary_flag_default { " (default)" } else { "" }));
opts.optflag("c", "check", "read hashsums from the FILEs and check them");
opts.optflag("", "tag", "create a BSD-style checksum");
opts.optflag("t", "text", &format!("read in text mode{}", if binary_flag_default { "" } else { " (default)" }));
opts.optflag("q", "quiet", "don't print OK for each successfully verified file");
opts.optflag("s", "status", "don't output anything, status code shows success");
opts.optflag("", "strict", "exit non-zero for improperly formatted checksum lines");
opts.optflag("w", "warn", "warn about improperly formatted checksum lines");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
if !is_custom_binary(program) {
opts.optflag("", "md5", "work with MD5");
opts.optflag("", "sha1", "work with SHA1");
opts.optflag("", "sha224", "work with SHA224");
opts.optflag("", "sha256", "work with SHA256");
opts.optflag("", "sha384", "work with SHA384");
opts.optflag("", "sha512", "work with SHA512");
}
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "{}", f)
};
if matches.opt_present("help") {
usage(program, binary_name, &opts);
} else if matches.opt_present("version") {
version();
} else {
let (name, algo) = detect_algo(binary_name, &matches);
let binary_flag = matches.opt_present("binary");
let text_flag = matches.opt_present("text");
if binary_flag && text_flag {
crash!(1, "cannot set binary and text mode at the same time");
}
let binary = if binary_flag { true } else if text_flag { false } else { binary_flag_default };
let check = matches.opt_present("check");
let tag = matches.opt_present("tag");
let status = matches.opt_present("status");
let quiet = matches.opt_present("quiet") || status;
let strict = matches.opt_present("strict");
let warn = matches.opt_present("warn") && !status;
let files = if matches.free.is_empty() {
vec!("-".to_string())
} else {
matches.free
};
match hashsum(name, algo, files, binary, check, tag, status, quiet, strict, warn) {
Ok(()) => return 0,
Err(e) => return e
}
}
0
}
fn version() {
pipe_println!("{} {}", NAME, VERSION);
}
fn usage(program: &str, binary_name: &str, opts: &getopts::Options) {
let spec = if is_custom_binary(binary_name) {
format!(" {} [OPTION]... [FILE]...", program)
} else {
format!(" {} {{--md5|--sha1|--sha224|--sha256|--sha384|--sha512}} [OPTION]... [FILE]...", program)
};
let msg = format!("{} {}
Usage:
{}
Compute and check message digests.", NAME, VERSION, spec);
pipe_print!("{}", opts.usage(&msg));
}
fn hashsum<'a>(algoname: &str, mut digest: Box<Digest+'a>, files: Vec<String>, binary: bool, check: bool, tag: bool, status: bool, quiet: bool, strict: bool, warn: bool) -> Result<(), i32> {
let mut bad_format = 0;
let mut failed = 0;
let binary_marker = if binary {
"*"
} else {
" "
};
for filename in files.iter() {
let filename: &str = filename;
let stdin_buf;
let file_buf;
let mut file = BufReader::new(
if filename == "-" {
stdin_buf = stdin();
Box::new(stdin_buf) as Box<Read>
} else {
file_buf = safe_unwrap!(File::open(filename));
Box::new(file_buf) as Box<Read>
}
);
if check {
// Set up Regexes for line validation and parsing
let bytes = digest.output_bits() / 4;
let gnu_re = safe_unwrap!(
Regex::new(
&format!(
r"^(?P<digest>[a-fA-F0-9]{{{}}}) (?P<binary>[ \*])(?P<fileName>.*)",
bytes
)
)
);
let bsd_re = safe_unwrap!(
Regex::new(
&format!(
r"^{algorithm} \((?P<fileName>.*)\) = (?P<digest>[a-fA-F0-9]{{{digest_size}}})",
algorithm = algoname,
digest_size = bytes
)
)
);
let buffer = file;
for (i, line) in buffer.lines().enumerate() {
let line = safe_unwrap!(line);
let (ck_filename, sum, binary_check) = match gnu_re.captures(&line) {
Some(caps) => (caps.name("fileName").unwrap(),
caps.name("digest").unwrap().to_ascii_lowercase(),
caps.name("binary").unwrap() == "*"),
None => match bsd_re.captures(&line) {
Some(caps) => (caps.name("fileName").unwrap(),
caps.name("digest").unwrap().to_ascii_lowercase(),
true),
None => {
bad_format += 1;
if strict {
return Err(1);
}
if warn {
show_warning!("{}: {}: improperly formatted {} checksum line", filename, i + 1, algoname);
}
continue;
}
}
};
let f = safe_unwrap!(File::open(ck_filename));
let mut ckf = BufReader::new(Box::new(f) as Box<Read>);
let real_sum = safe_unwrap!(digest_reader(&mut digest, &mut ckf, binary_check))
.to_ascii_lowercase();
if sum == real_sum {
if !quiet {
pipe_println!("{}: OK", ck_filename);
}
} else {
if !status {
pipe_println!("{}: FAILED", ck_filename);
}
failed += 1;
}
}
} else {
let sum = safe_unwrap!(digest_reader(&mut digest, &mut file, binary));
if tag {
pipe_println!("{} ({}) = {}", algoname, filename, sum);
} else {
pipe_println!("{} {}{}", sum, binary_marker, filename);
}
}
}
if !status {
if bad_format == 1 {
show_warning!("{} line is improperly formatted", bad_format);
} else if bad_format > 1 {
show_warning!("{} lines are improperly formatted", bad_format);
}
if failed > 0 {
show_warning!("{} computed checksum did NOT match", failed);
}
}
Ok(())
}
fn digest_reader<'a, T: Read>(digest: &mut Box<Digest+'a>, reader: &mut BufReader<T>, binary: bool) -> io::Result<String> {
digest.reset();
// Digest file, do not hold too much in memory at any given moment
let windows = cfg!(windows);
let mut buffer = Vec::with_capacity(524288);
let mut vec = Vec::with_capacity(524288);
let mut looking_for_newline = false;
loop {
match reader.read_to_end(&mut buffer) {
Ok(0) => { break; },
Ok(nread) => {
if windows && !binary {
// Windows text mode returns '\n' when reading '\r\n'
for i in 0 .. nread {
if looking_for_newline {
if buffer[i] != ('\n' as u8) {
vec.push('\r' as u8);
}
if buffer[i] != ('\r' as u8) {
vec.push(buffer[i]);
looking_for_newline = false;
}
} else if buffer[i] != ('\r' as u8) {
vec.push(buffer[i]);
} else {
looking_for_newline = true;
}
}
digest.input(&vec);
vec.clear();
} else {
digest.input(&buffer[..nread]);
}
},
Err(e) => return Err(e)
}
}
if windows && looking_for_newline {
vec.push('\r' as u8);
digest.input(&vec);
}
Ok(digest.result_str())
}

View file

@ -1,12 +0,0 @@
[package]
name = "head"
version = "0.0.1"
authors = []
[lib]
name = "head"
path = "head.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,210 +0,0 @@
#![crate_name = "head"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Alan Andrade <alan.andradec@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Synced with: https://raw.github.com/avsm/src/master/usr.bin/head/head.c
*/
extern crate getopts;
use std::io::{BufRead, BufReader, Read, stdin, Write};
use std::fs::File;
use std::path::Path;
use std::str::from_utf8;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "head";
static VERSION: &'static str = "1.0.0";
enum FilterMode {
Bytes(usize),
Lines(usize),
}
struct Settings {
mode: FilterMode,
verbose: bool,
}
impl Default for Settings {
fn default() -> Settings {
Settings {
mode: FilterMode::Lines(10),
verbose: false,
}
}
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut settings: Settings = Default::default();
// handle obsolete -number syntax
let options = match obsolete(&args[1..]) {
(args, Some(n)) => { settings.mode = FilterMode::Lines(n); args },
(args, None) => args
};
let args = options;
let mut opts = getopts::Options::new();
opts.optopt("c", "bytes", "Print the first K bytes. With the leading '-', print all but the last K bytes", "[-]K");
opts.optopt("n", "lines", "Print the first K lines. With the leading '-', print all but the last K lines", "[-]K");
opts.optflag("q", "quiet", "never print headers giving file names");
opts.optflag("v", "verbose", "always print headers giving file names");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args) {
Ok (m) => { m }
Err(_) => {
println!("{}", opts.usage(""));
return 1;
}
};
if matches.opt_present("h") {
println!("{}", opts.usage(""));
return 0;
}
if matches.opt_present("V") { version(); return 0 }
let use_bytes = matches.opt_present("c");
// TODO: suffixes (e.g. b, kB, etc.)
match matches.opt_str("n") {
Some(n) => {
if use_bytes {
show_error!("cannot specify both --bytes and --lines.");
return 1;
}
match n.parse::<usize>() {
Ok(m) => { settings.mode = FilterMode::Lines(m) }
Err(e) => {
show_error!("invalid line count '{}': {}", n, e);
return 1;
}
}
}
None => match matches.opt_str("c") {
Some(count) => match count.parse::<usize>() {
Ok(m) => settings.mode = FilterMode::Bytes(m),
Err(e)=> {
show_error!("invalid byte count '{}': {}", count, e);
return 1;
}
},
None => {}
}
};
let quiet = matches.opt_present("q");
let verbose = matches.opt_present("v");
let files = matches.free;
// GNU implementation allows multiple declarations of "-q" and "-v" with the
// last flag winning. This can't be simulated with the getopts cargo unless
// we manually parse the arguments. Given the declaration of both flags,
// verbose mode always wins. This is a potential future improvement.
if files.len() > 1 && !quiet && !verbose {
settings.verbose = true;
}
if quiet {
settings.verbose = false;
}
if verbose {
settings.verbose = true;
}
if files.is_empty() {
let mut buffer = BufReader::new(stdin());
head(&mut buffer, &settings);
} else {
let mut firstime = true;
for file in files.iter() {
if settings.verbose {
if !firstime { pipe_println!(""); }
pipe_println!("==> {} <==", file);
}
firstime = false;
let path = Path::new(file);
let reader = File::open(&path).unwrap();
let mut buffer = BufReader::new(reader);
if !head(&mut buffer, &settings) {
break;
}
}
}
0
}
// It searches for an option in the form of -123123
//
// In case is found, the options vector will get rid of that object so that
// getopts works correctly.
fn obsolete(options: &[String]) -> (Vec<String>, Option<usize>) {
let mut options: Vec<String> = options.to_vec();
let mut a = 0;
let b = options.len();
while a < b {
let current = options[a].clone();
let current = current.as_bytes();
if current.len() > 1 && current[0] == '-' as u8 {
let len = current.len();
for pos in 1 .. len {
// Ensure that the argument is only made out of digits
if !(current[pos] as char).is_numeric() { break; }
// If this is the last number
if pos == len - 1 {
options.remove(a);
let number: Option<usize> = from_utf8(&current[1..len]).unwrap().parse::<usize>().ok();
return (options, Some(number.unwrap()));
}
}
}
a += 1;
};
(options, None)
}
// TODO: handle errors on read
fn head<T: Read>(reader: &mut BufReader<T>, settings: &Settings) -> bool {
match settings.mode {
FilterMode::Bytes(count) => {
for byte in reader.bytes().take(count) {
if !pipe_print!("{}", byte.unwrap() as char) {
return false;
}
}
},
FilterMode::Lines(count) => {
for line in reader.lines().take(count) {
if !pipe_println!("{}", line.unwrap()) {
return false;
}
}
}
}
true
}
fn version() {
println!("{} {}", NAME, VERSION);
}

View file

@ -1,12 +0,0 @@
[package]
name = "hostid"
version = "0.0.1"
authors = []
[lib]
name = "hostid"
path = "hostid.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,90 +0,0 @@
#![crate_name = "hostid"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Maciej Dziardziel <fiedzia@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
use libc::c_long;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "hostid";
static VERSION: &'static str = "0.0.1";
static EXIT_ERR: i32 = 1;
pub enum Mode {
HostId,
Help,
Version,
}
// currently rust libc interface doesn't include gethostid
extern {
pub fn gethostid() -> c_long;
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(_) => {
help(&opts);
return EXIT_ERR;
},
};
let mode = if matches.opt_present("version") {
Mode::Version
} else if matches.opt_present("help") {
Mode::Help
} else {
Mode::HostId
};
match mode {
Mode::HostId => hostid(),
Mode::Help => help(&opts),
Mode::Version => version(),
}
0
}
fn version() {
println!("{} {}", NAME, VERSION);
}
fn help(opts: &getopts::Options) {
let msg = format!("Usage:\n {} [options]", NAME);
print!("{}", opts.usage(&msg));
}
fn hostid() {
/*
* POSIX says gethostid returns a "32-bit identifier" but is silent
* whether it's sign-extended. Turn off any sign-extension. This
* is a no-op unless unsigned int is wider than 32 bits.
*/
let mut result:c_long;
unsafe {
result = gethostid();
}
result &= 0xffffffff;
println!("{:0>8x}", result);
}

View file

@ -1,12 +0,0 @@
[package]
name = "hostname"
version = "0.0.1"
authors = []
[lib]
name = "hostname"
path = "hostname.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,176 +0,0 @@
#![crate_name = "hostname"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Alan Andrade <alan.andradec@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Synced with:
*
* https://www.opensource.apple.com/source/shell_cmds/shell_cmds-170/hostname/hostname.c?txt
*/
extern crate getopts;
extern crate libc;
use std::collections::hash_set::HashSet;
use std::iter::repeat;
use std::str;
use std::io::Write;
use std::net::ToSocketAddrs;
use getopts::Options;
#[path = "../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "hostname";
extern {
fn gethostname(name: *mut libc::c_char, namelen: libc::size_t) -> libc::c_int;
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
extern {
fn sethostname(name: *const libc::c_char, namelen: libc::c_int) -> libc::c_int;
}
#[cfg(target_os = "linux")]
extern {
fn sethostname(name: *const libc::c_char, namelen: libc::size_t) -> libc::c_int;
}
pub fn uumain(args: Vec<String>) -> i32 {
let program = &args[0];
let mut opts = Options::new();
opts.optflag("d", "domain", "Display the name of the DNS domain if possible");
opts.optflag("i", "ip-address", "Display the network address(es) of the host");
opts.optflag("f", "fqdn", "Display the FQDN (Fully Qualified Domain Name) (default)"); // TODO: support --long
opts.optflag("s", "short", "Display the short hostname (the portion before the first dot) if possible");
opts.optflag("h", "help", "Show help");
opts.optflag("V", "version", "Show program's version");
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m }
_ => { help_menu(program, opts); return 0; }
};
if matches.opt_present("h") {
help_menu(program, opts);
return 0
}
if matches.opt_present("V") { version(); return 0 }
match matches.free.len() {
0 => {
let hostname = xgethostname();
if matches.opt_present("i") {
match hostname.to_socket_addrs() {
Ok(addresses) => {
let mut hashset = HashSet::new();
let mut output = String::new();
for addr in addresses {
// XXX: not sure why this is necessary...
if !hashset.contains(&addr) {
output.push_str(&format!("{}", addr));
output.push_str(" ");
hashset.insert(addr.clone());
}
}
let len = output.len();
if len > 0 {
println!("{}", &output[0 .. len - 1]);
}
}
Err(f) => {
show_error!("{}", f);
return 1;
}
}
} else {
if matches.opt_present("s") {
let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.');
let ci = it.next();
if ci.is_some() {
println!("{}", &hostname[0 .. ci.unwrap().0]);
return 0;
}
} else if matches.opt_present("d") {
let mut it = hostname.char_indices().filter(|&ci| ci.1 == '.');
let ci = it.next();
if ci.is_some() {
println!("{}", &hostname[ci.unwrap().0 + 1 .. ]);
return 0;
}
}
println!("{}", hostname);
}
}
1 => xsethostname(matches.free.last().unwrap()),
_ => help_menu(program, opts)
};
0
}
fn version() {
println!("hostname 1.0.0");
}
fn help_menu(program: &str, options: Options) {
version();
println!("");
println!("Usage:");
println!(" {} [OPTION]... [HOSTNAME]", program);
println!("");
print!("{}", options.usage("Print or set the system's host name."));
}
fn xgethostname() -> String {
let namelen = 256usize;
let mut name : Vec<u8> = repeat(0).take(namelen).collect();
let err = unsafe {
gethostname (name.as_mut_ptr() as *mut libc::c_char,
namelen as libc::size_t)
};
if err != 0 {
panic!("Cannot determine hostname");
}
let last_char = name.iter().position(|byte| *byte == 0).unwrap_or(namelen);
str::from_utf8(&name[..last_char]).unwrap().to_string()
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
fn xsethostname(name: &str) {
let vec_name: Vec<libc::c_char> = name.bytes().map(|c| c as libc::c_char).collect();
let err = unsafe {
sethostname (vec_name.as_ptr(), vec_name.len() as libc::c_int)
};
if err != 0 {
println!("Cannot set hostname to {}", name);
}
}
#[cfg(target_os = "linux")]
fn xsethostname(name: &str) {
let vec_name: Vec<libc::c_char> = name.bytes().map(|c| c as libc::c_char).collect();
let err = unsafe {
sethostname (vec_name.as_ptr(), vec_name.len() as libc::size_t)
};
if err != 0 {
println!("Cannot set hostname to {}", name);
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "id"
version = "0.0.1"
authors = []
[lib]
name = "id"
path = "id.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,397 +0,0 @@
#![crate_name = "id"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Alan Andrade <alan.andradec@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* Synced with:
* http://ftp-archive.freebsd.org/mirror/FreeBSD-Archive/old-releases/i386/1.0-RELEASE/ports/shellutils/src/id.c
* http://www.opensource.apple.com/source/shell_cmds/shell_cmds-118/id/id.c
*/
#![allow(non_camel_case_types)]
extern crate getopts;
extern crate libc;
use libc::{getgid, getuid, uid_t};
use libc::funcs::posix88::unistd::{getegid, geteuid, getlogin};
use std::ffi::CStr;
use std::io::Write;
use std::ptr::read;
use c_types::{
c_passwd,
c_group,
get_groups,
get_group_list,
get_pw_from_args,
getpwuid,
group
};
#[path = "../common/util.rs"] #[macro_use] mod util;
#[path = "../common/c_types.rs"] mod c_types;
#[cfg(not(target_os = "linux"))]
mod audit {
pub use std::mem::uninitialized;
use libc::{uid_t, pid_t, c_int, c_uint, uint64_t, dev_t};
pub type au_id_t = uid_t;
pub type au_asid_t = pid_t;
pub type au_event_t = c_uint;
pub type au_emod_t = c_uint;
pub type au_class_t = c_int;
#[repr(C)]
pub struct au_mask {
pub am_success: c_uint,
pub am_failure: c_uint
}
pub type au_mask_t = au_mask;
#[repr(C)]
pub struct au_tid_addr {
pub port: dev_t,
}
pub type au_tid_addr_t = au_tid_addr;
#[repr(C)]
pub struct c_auditinfo_addr {
pub ai_auid: au_id_t, /* Audit user ID */
pub ai_mask: au_mask_t, /* Audit masks. */
pub ai_termid: au_tid_addr_t, /* Terminal ID. */
pub ai_asid: au_asid_t, /* Audit session ID. */
pub ai_flags: uint64_t /* Audit session flags */
}
pub type c_auditinfo_addr_t = c_auditinfo_addr;
extern {
pub fn getaudit(auditinfo_addr: *mut c_auditinfo_addr_t) -> c_int;
}
}
extern {
fn getgrgid(gid: uid_t) -> *const c_group;
}
static NAME: &'static str = "id";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("h", "", "Show help");
opts.optflag("A", "", "Display the process audit (not available on Linux)");
opts.optflag("G", "", "Display the different group IDs");
opts.optflag("g", "", "Display the effective group ID as a number");
opts.optflag("n", "", "Display the name of the user or group ID for the -G, -g and -u options");
opts.optflag("P", "", "Display the id as a password file entry");
opts.optflag("p", "", "Make the output human-readable");
opts.optflag("r", "", "Display the real ID for the -g and -u options");
opts.optflag("u", "", "Display the effective user ID as a number");
let matches = match opts.parse(&args[1..]) {
Ok(m) => { m },
Err(_) => {
println!("{}", opts.usage(NAME));
return 1;
}
};
if matches.opt_present("h") {
println!("{}", opts.usage(NAME));
return 0;
}
if matches.opt_present("A") {
auditid();
return 0;
}
let possible_pw = get_pw_from_args(&matches.free);
let nflag = matches.opt_present("n");
let uflag = matches.opt_present("u");
let gflag = matches.opt_present("g");
let rflag = matches.opt_present("r");
if gflag {
let id = if possible_pw.is_some() {
possible_pw.unwrap().pw_gid
} else {
if rflag {
unsafe { getgid() }
} else {
unsafe { getegid() }
}
};
let gr = unsafe { getgrgid(id) };
if nflag && !gr.is_null() {
let gr_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(read(gr).gr_name).to_bytes()).to_string() };
println!("{}", gr_name);
} else {
println!("{}", id);
}
return 0;
}
if uflag {
let id = if possible_pw.is_some() {
possible_pw.unwrap().pw_uid
} else if rflag {
unsafe { getgid() }
} else {
unsafe { getegid() }
};
let pw = unsafe { getpwuid(id) };
if nflag && !pw.is_null() {
let pw_name = unsafe {
String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string()
};
println!("{}", pw_name);
} else {
println!("{}", id);
}
return 0;
}
if matches.opt_present("G") {
group(possible_pw, nflag);
return 0;
}
if matches.opt_present("P") {
pline(possible_pw);
return 0;
};
if matches.opt_present("p") {
pretty(possible_pw);
return 0;
}
if possible_pw.is_some() {
id_print(possible_pw, false, false)
} else {
id_print(possible_pw, true, true)
}
0
}
fn pretty(possible_pw: Option<c_passwd>) {
if possible_pw.is_some() {
let pw = possible_pw.unwrap();
let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name).to_bytes()).to_string() };
print!("uid\t{}\ngroups\t", pw_name);
group(possible_pw, true);
} else {
let login = unsafe { String::from_utf8_lossy(CStr::from_ptr((getlogin() as *const i8)).to_bytes()).to_string() };
let rid = unsafe { getuid() };
let pw = unsafe { getpwuid(rid) };
let is_same_user = unsafe {
String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() == login
};
if pw.is_null() || is_same_user {
println!("login\t{}", login);
}
if !pw.is_null() {
println!(
"uid\t{}",
unsafe { String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() })
} else {
println!("uid\t{}\n", rid);
}
let eid = unsafe { getegid() };
if eid == rid {
let pw = unsafe { getpwuid(eid) };
if !pw.is_null() {
println!(
"euid\t{}",
unsafe { String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() });
} else {
println!("euid\t{}", eid);
}
}
let rid = unsafe { getgid() };
if rid != eid {
let gr = unsafe { getgrgid(rid) };
if !gr.is_null() {
println!(
"rgid\t{}",
unsafe { String::from_utf8_lossy(CStr::from_ptr(read(gr).gr_name).to_bytes()).to_string() });
} else {
println!("rgid\t{}", rid);
}
}
print!("groups\t");
group(None, true);
}
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
fn pline(possible_pw: Option<c_passwd>) {
let pw = if possible_pw.is_none() {
unsafe { read(getpwuid(getuid())) }
} else {
possible_pw.unwrap()
};
let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name ).to_bytes()).to_string()};
let pw_passwd = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_passwd).to_bytes()).to_string()};
let pw_class = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_class ).to_bytes()).to_string()};
let pw_gecos = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_gecos ).to_bytes()).to_string()};
let pw_dir = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_dir ).to_bytes()).to_string()};
let pw_shell = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_shell ).to_bytes()).to_string()};
println!(
"{}:{}:{}:{}:{}:{}:{}:{}:{}:{}",
pw_name,
pw_passwd,
pw.pw_uid,
pw.pw_gid,
pw_class,
pw.pw_change,
pw.pw_expire,
pw_gecos,
pw_dir,
pw_shell);
}
#[cfg(target_os = "linux")]
fn pline(possible_pw: Option<c_passwd>) {
let pw = if possible_pw.is_none() {
unsafe { read(getpwuid(getuid())) }
} else {
possible_pw.unwrap()
};
let pw_name = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_name ).to_bytes()).to_string()};
let pw_passwd = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_passwd).to_bytes()).to_string()};
let pw_gecos = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_gecos ).to_bytes()).to_string()};
let pw_dir = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_dir ).to_bytes()).to_string()};
let pw_shell = unsafe { String::from_utf8_lossy(CStr::from_ptr(pw.pw_shell ).to_bytes()).to_string()};
println!(
"{}:{}:{}:{}:{}:{}:{}",
pw_name,
pw_passwd,
pw.pw_uid,
pw.pw_gid,
pw_gecos,
pw_dir,
pw_shell);
}
#[cfg(target_os = "linux")]
fn auditid() { }
#[cfg(not(target_os = "linux"))]
fn auditid() {
let mut auditinfo: audit::c_auditinfo_addr_t = unsafe { audit::uninitialized() };
let address = &mut auditinfo as *mut audit::c_auditinfo_addr_t;
if unsafe { audit::getaudit(address) } < 0 {
println!("couldn't retrieve information");
return;
}
println!("auid={}", auditinfo.ai_auid);
println!("mask.success=0x{:x}", auditinfo.ai_mask.am_success);
println!("mask.failure=0x{:x}", auditinfo.ai_mask.am_failure);
println!("termid.port=0x{:x}", auditinfo.ai_termid.port);
println!("asid={}", auditinfo.ai_asid);
}
fn id_print(possible_pw: Option<c_passwd>, p_euid: bool, p_egid: bool) {
let uid;
let gid;
if possible_pw.is_some() {
uid = possible_pw.unwrap().pw_uid;
gid = possible_pw.unwrap().pw_gid;
} else {
uid = unsafe { getuid() };
gid = unsafe { getgid() };
}
let groups = match possible_pw {
Some(pw) => Ok(get_group_list(pw.pw_name, pw.pw_gid)),
None => get_groups(),
};
let groups = groups.unwrap_or_else(|errno| {
crash!(1, "failed to get group list (errno={})", errno);
});
if possible_pw.is_some() {
print!(
"uid={}({})",
uid,
unsafe { String::from_utf8_lossy(CStr::from_ptr(possible_pw.unwrap().pw_name).to_bytes()).to_string() });
} else {
print!("uid={}", unsafe { getuid() });
}
print!(" gid={}", gid);
let gr = unsafe { getgrgid(gid) };
if !gr.is_null() {
print!(
"({})",
unsafe { String::from_utf8_lossy(CStr::from_ptr(read(gr).gr_name).to_bytes()).to_string() });
}
let euid = unsafe { geteuid() };
if p_euid && (euid != uid) {
print!(" euid={}", euid);
let pw = unsafe { getpwuid(euid) };
if !pw.is_null() {
print!(
"({})",
unsafe { String::from_utf8_lossy(CStr::from_ptr(read(pw).pw_name).to_bytes()).to_string() });
}
}
let egid = unsafe { getegid() };
if p_egid && (egid != gid) {
print!(" egid={}", egid);
unsafe {
let grp = getgrgid(egid);
if !grp.is_null() {
print!("({})", String::from_utf8_lossy(CStr::from_ptr(read(grp).gr_name).to_bytes()).to_string());
}
}
}
if groups.len() > 0 {
print!(" groups=");
let mut first = true;
for &gr in groups.iter() {
if !first { print!(",") }
print!("{}", gr);
let group = unsafe { getgrgid(gr) };
if !group.is_null() {
let name = unsafe {
String::from_utf8_lossy(CStr::from_ptr(read(group).gr_name).to_bytes()).to_string()
};
print!("({})", name);
}
first = false
}
}
println!("");
}

View file

@ -1,12 +0,0 @@
[package]
name = "kill"
version = "0.0.1"
authors = []
[lib]
name = "kill"
path = "kill.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,194 +0,0 @@
#![crate_name = "kill"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Maciej Dziardziel <fiedzia@gmail.com>
*
* For the full copyright and license information, please view the LICENSE file
* that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
use libc::{c_int, pid_t};
use signals::ALL_SIGNALS;
use std::io::{Error, Write};
#[path = "../common/util.rs"]
#[macro_use]
mod util;
#[path = "../common/c_types.rs"]
mod c_types;
#[path = "../common/signals.rs"]
mod signals;
static NAME: &'static str = "kill";
static VERSION: &'static str = "0.0.1";
static EXIT_OK: i32 = 0;
static EXIT_ERR: i32 = 1;
#[derive(Clone, Copy)]
pub enum Mode {
Kill,
Table,
List,
Help,
Version,
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
opts.optopt("s", "signal", "specify the <signal> to be sent", "SIGNAL");
opts.optflagopt("l", "list", "list all signal names, or convert one to a name", "LIST");
opts.optflag("L", "table", "list all signal names in a nice table");
let (args, obs_signal) = handle_obsolete(args);
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(_) => {
help(&opts);
return EXIT_ERR;
},
};
let mode = if matches.opt_present("version") {
Mode::Version
} else if matches.opt_present("help") {
Mode::Help
} else if matches.opt_present("table") {
Mode::Table
} else if matches.opt_present("list") {
Mode::List
} else {
Mode::Kill
};
match mode {
Mode::Kill => return kill(&matches.opt_str("signal").unwrap_or(obs_signal.unwrap_or("9".to_string())), matches.free),
Mode::Table => table(),
Mode::List => list(matches.opt_str("list")),
Mode::Help => help(&opts),
Mode::Version => version(),
}
0
}
fn version() {
println!("{} {}", NAME, VERSION);
}
fn handle_obsolete(mut args: Vec<String>) -> (Vec<String>, Option<String>) {
let mut i = 0;
while i < args.len() {
// this is safe because slice is valid when it is referenced
let slice = &args[i].clone();
if slice.chars().next().unwrap() == '-' && slice.len() > 1 && slice.chars().nth(1).unwrap().is_digit(10) {
let val = &slice[1..];
match val.parse() {
Ok(num) => {
if signals::is_signal(num) {
args.remove(i);
return (args, Some(val.to_string()));
}
}
Err(_)=> break /* getopts will error out for us */
}
}
i += 1;
}
(args, None)
}
fn table() {
let mut name_width = 0;
/* Compute the maximum width of a signal name. */
for s in ALL_SIGNALS.iter() {
if s.name.len() > name_width {
name_width = s.name.len()
}
}
for (idx, signal) in ALL_SIGNALS.iter().enumerate() {
print!("{0: >#2} {1: <#8}", idx+1, signal.name);
//TODO: obtain max signal width here
if (idx+1) % 7 == 0 {
println!("");
}
}
}
fn print_signal(signal_name_or_value: &str) {
for signal in ALL_SIGNALS.iter() {
if signal.name == signal_name_or_value || (format!("SIG{}", signal.name)) == signal_name_or_value {
println!("{}", signal.value);
exit!(EXIT_OK as i32)
} else if signal_name_or_value == signal.value.to_string() {
println!("{}", signal.name);
exit!(EXIT_OK as i32)
}
}
crash!(EXIT_ERR, "unknown signal name {}", signal_name_or_value)
}
fn print_signals() {
let mut pos = 0;
for (idx, signal) in ALL_SIGNALS.iter().enumerate() {
pos += signal.name.len();
print!("{}", signal.name);
if idx > 0 && pos > 73 {
println!("");
pos = 0;
} else {
pos += 1;
print!(" ");
}
}
}
fn list(arg: Option<String>) {
match arg {
Some(ref x) => print_signal(x),
None => print_signals(),
};
}
fn help(opts: &getopts::Options) {
let msg = format!("{0} {1}
Usage:
{0} [options] <pid> [...]", NAME, VERSION);
println!("{}", opts.usage(&msg));
}
fn kill(signalname: &str, pids: std::vec::Vec<String>) -> i32 {
let mut status = 0;
let optional_signal_value = signals::signal_by_name_or_value(signalname);
let signal_value = match optional_signal_value {
Some(x) => x,
None => crash!(EXIT_ERR, "unknown signal name {}", signalname)
};
for pid in pids.iter() {
match pid.parse::<usize>() {
Ok(x) => {
if unsafe { libc::funcs::posix88::signal::kill(x as pid_t, signal_value as c_int) } != 0 {
show_error!("{}", Error::last_os_error());
status = 1;
}
},
Err(e) => crash!(EXIT_ERR, "failed to parse argument {}: {}", pid, e)
};
}
status
}

View file

@ -1,12 +0,0 @@
[package]
name = "link"
version = "0.0.1"
authors = []
[lib]
name = "link"
path = "link.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,66 +0,0 @@
#![crate_name = "link"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Michael Gehring <mg@ebfe.org>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
use std::fs::hard_link;
use std::io::Write;
use std::path::Path;
#[path="../common/util.rs"]
#[macro_use]
mod util;
static NAME: &'static str = "link";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(err) => panic!("{}", err),
};
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
if matches.opt_present("help") || matches.free.len() != 2 {
let msg = format!("{0} {1}
Usage:
{0} [OPTIONS] FILE1 FILE2
Create a link named FILE2 to FILE1.", NAME, VERSION);
println!("{}", opts.usage(&msg));
if matches.free.len() != 2 {
return 1;
}
return 0;
}
let old = Path::new(&matches.free[0]);
let new = Path::new(&matches.free[1]);
match hard_link(old, new) {
Ok(_) => 0,
Err(err) => {
show_error!("{}", err);
1
}
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "ln"
version = "0.0.1"
authors = []
[lib]
name = "ln"
path = "ln.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,333 +0,0 @@
#![crate_name = "ln"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Joseph Crail <jbcrail@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
use std::fs;
use std::io::{BufRead, BufReader, Result, stdin, Write};
#[cfg(unix)] use std::os::unix::fs::symlink as symlink_file;
#[cfg(windows)] use std::os::windows::fs::symlink_file;
use std::path::{Path, PathBuf};
#[path="../common/util.rs"]
#[macro_use]
mod util;
#[path="../common/filesystem.rs"]
mod filesystem;
use filesystem::UUPathExt;
static NAME: &'static str = "ln";
static VERSION: &'static str = "1.0.0";
pub struct Settings {
overwrite: OverwriteMode,
backup: BackupMode,
suffix: String,
symbolic: bool,
target_dir: Option<String>,
no_target_dir: bool,
verbose: bool,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum OverwriteMode {
NoClobber,
Interactive,
Force,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BackupMode {
NoBackup,
SimpleBackup,
NumberedBackup,
ExistingBackup,
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
opts.optflag("b", "", "make a backup of each file that would otherwise be overwritten or removed");
opts.optflagopt("", "backup", "make a backup of each file that would otherwise be overwritten or removed", "METHOD");
// TODO: opts.optflag("d", "directory", "allow users with appropriate privileges to attempt to make hard links to directories");
opts.optflag("f", "force", "remove existing destination files");
opts.optflag("i", "interactive", "prompt whether to remove existing destination files");
// TODO: opts.optflag("L", "logical", "dereference TARGETs that are symbolic links");
// TODO: opts.optflag("n", "no-dereference", "treat LINK_NAME as a normal file if it is a symbolic link to a directory");
// TODO: opts.optflag("P", "physical", "make hard links directly to symbolic links");
// TODO: opts.optflag("r", "relative", "create symbolic links relative to link location");
opts.optflag("s", "symbolic", "make symbolic links instead of hard links");
opts.optopt("S", "suffix", "override the usual backup suffix", "SUFFIX");
opts.optopt("t", "target-directory", "specify the DIRECTORY in which to create the links", "DIRECTORY");
opts.optflag("T", "no-target-directory", "treat LINK_NAME as a normal file always");
opts.optflag("v", "verbose", "print name of each linked file");
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(e) => crash!(1, "{}", e),
};
let overwrite_mode = if matches.opt_present("force") {
OverwriteMode::Force
} else if matches.opt_present("interactive") {
OverwriteMode::Interactive
} else {
OverwriteMode::NoClobber
};
let backup_mode = if matches.opt_present("b") {
BackupMode::ExistingBackup
} else if matches.opt_present("backup") {
match matches.opt_str("backup") {
None => BackupMode::ExistingBackup,
Some(mode) => match &mode[..] {
"simple" | "never" => BackupMode::SimpleBackup,
"numbered" | "t" => BackupMode::NumberedBackup,
"existing" | "nil" => BackupMode::ExistingBackup,
"none" | "off" => BackupMode::NoBackup,
x => {
show_error!("invalid argument '{}' for 'backup method'\n\
Try '{} --help' for more information.", x, NAME);
return 1;
}
}
}
} else {
BackupMode::NoBackup
};
let backup_suffix = if matches.opt_present("suffix") {
match matches.opt_str("suffix") {
Some(x) => x,
None => {
show_error!("option '--suffix' requires an argument\n\
Try '{} --help' for more information.", NAME);
return 1;
}
}
} else {
"~".to_string()
};
if matches.opt_present("T") && matches.opt_present("t") {
show_error!("cannot combine --target-directory (-t) and --no-target-directory (-T)");
return 1;
}
let settings = Settings {
overwrite: overwrite_mode,
backup: backup_mode,
suffix: backup_suffix,
symbolic: matches.opt_present("s"),
target_dir: matches.opt_str("t"),
no_target_dir: matches.opt_present("T"),
verbose: matches.opt_present("v"),
};
let string_to_path = |s: &String| { PathBuf::from(s) };
let paths: Vec<PathBuf> = matches.free.iter().map(string_to_path).collect();
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
0
} else if matches.opt_present("help") {
let msg = format!("{0} {1}
Usage: {0} [OPTION]... [-T] TARGET LINK_NAME (1st form)
or: {0} [OPTION]... TARGET (2nd form)
or: {0} [OPTION]... TARGET... DIRECTORY (3rd form)
or: {0} [OPTION]... -t DIRECTORY TARGET... (4th form)
In the 1st form, create a link to TARGET with the name LINK_NAME.
In the 2nd form, create a link to TARGET in the current directory.
In the 3rd and 4th forms, create links to each TARGET in DIRECTORY.
Create hard links by default, symbolic links with --symbolic.
By default, each destination (name of new link) should not already exist.
When creating hard links, each TARGET must exist. Symbolic links
can hold arbitrary text; if later resolved, a relative link is
interpreted in relation to its parent directory.", NAME, VERSION);
print!("{}", opts.usage(&msg));
0
} else {
exec(&paths[..], &settings)
}
}
fn exec(files: &[PathBuf], settings: &Settings) -> i32 {
match settings.target_dir {
Some(ref name) => return link_files_in_dir(files, &PathBuf::from(name), &settings),
None => {}
}
match files.len() {
0 => {
show_error!("missing file operand\nTry '{} --help' for more information.", NAME);
1
},
1 => match link(&files[0], &files[0], settings) {
Ok(_) => 0,
Err(e) => {
show_error!("{}", e);
1
}
},
2 => match link(&files[0], &files[1], settings) {
Ok(_) => 0,
Err(e) => {
show_error!("{}", e);
1
}
},
_ => {
if settings.no_target_dir {
show_error!("extra operand '{}'\nTry '{} --help' for more information.", files[2].display(), NAME);
return 1;
}
let (targets, dir) = match settings.target_dir {
Some(ref dir) => (files, PathBuf::from(dir.clone())),
None => (&files[0..files.len()-1], files[files.len()-1].clone())
};
link_files_in_dir(targets, &dir, settings)
}
}
}
fn link_files_in_dir(files: &[PathBuf], target_dir: &PathBuf, settings: &Settings) -> i32 {
if !target_dir.uu_is_dir() {
show_error!("target '{}' is not a directory", target_dir.display());
return 1;
}
let mut all_successful = true;
for srcpath in files.iter() {
let targetpath = match srcpath.as_os_str().to_str() {
Some(name) => target_dir.join(name),
None => {
show_error!("cannot stat '{}': No such file or directory",
srcpath.display());
all_successful = false;
continue;
}
};
match link(srcpath, &targetpath, settings) {
Err(e) => {
show_error!("cannot link '{}' to '{}': {}",
targetpath.display(), srcpath.display(), e);
all_successful = false;
},
_ => {}
}
}
if all_successful { 0 } else { 1 }
}
fn link(src: &PathBuf, dst: &PathBuf, settings: &Settings) -> Result<()> {
let mut backup_path = None;
if dst.uu_is_dir() {
if settings.no_target_dir {
try!(fs::remove_dir(dst));
}
}
if is_symlink(dst) || dst.uu_exists() {
match settings.overwrite {
OverwriteMode::NoClobber => {},
OverwriteMode::Interactive => {
print!("{}: overwrite '{}'? ", NAME, dst.display());
if !read_yes() {
return Ok(());
}
try!(fs::remove_file(dst))
},
OverwriteMode::Force => {
try!(fs::remove_file(dst))
}
};
backup_path = match settings.backup {
BackupMode::NoBackup => None,
BackupMode::SimpleBackup => Some(simple_backup_path(dst, &settings.suffix)),
BackupMode::NumberedBackup => Some(numbered_backup_path(dst)),
BackupMode::ExistingBackup => Some(existing_backup_path(dst, &settings.suffix))
};
if let Some(ref p) = backup_path {
try!(fs::rename(dst, p));
}
}
if settings.symbolic {
try!(symlink(src, dst));
} else {
try!(fs::hard_link(src, dst));
}
if settings.verbose {
print!("'{}' -> '{}'", dst.display(), src.display());
match backup_path {
Some(path) => println!(" (backup: '{}')", path.display()),
None => println!("")
}
}
Ok(())
}
fn read_yes() -> bool {
let mut s = String::new();
match BufReader::new(stdin()).read_line(&mut s) {
Ok(_) => match s.char_indices().nth(0) {
Some((_, x)) => x == 'y' || x == 'Y',
_ => false
},
_ => false
}
}
fn simple_backup_path(path: &PathBuf, suffix: &String) -> PathBuf {
let mut p = path.as_os_str().to_str().unwrap().to_string();
p.push_str(suffix);
PathBuf::from(p)
}
fn numbered_backup_path(path: &PathBuf) -> PathBuf {
let mut i: u64 = 1;
loop {
let new_path = simple_backup_path(path, &format!(".~{}~", i));
if !new_path.uu_exists() {
return new_path;
}
i += 1;
}
}
fn existing_backup_path(path: &PathBuf, suffix: &String) -> PathBuf {
let test_path = simple_backup_path(path, &".~1~".to_string());
if test_path.uu_exists() {
return numbered_backup_path(path);
}
simple_backup_path(path, suffix)
}
pub fn symlink<P: AsRef<Path>>(src: P, dst: P) -> Result<()> {
symlink_file(src, dst)
}
pub fn is_symlink<P: AsRef<Path>>(path: P) -> bool {
match fs::symlink_metadata(path) {
Ok(m) => m.file_type().is_symlink(),
Err(_) => false
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "logname"
version = "0.0.1"
authors = []
[lib]
name = "logname"
path = "logname.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,81 +0,0 @@
#![crate_name = "logname"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Benoit Benedetti <benoit.benedetti@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/* last synced with: logname (GNU coreutils) 8.22 */
extern crate getopts;
extern crate libc;
use std::ffi::CStr;
use std::io::Write;
#[path = "../common/util.rs"] #[macro_use] mod util;
extern {
// POSIX requires using getlogin (or equivalent code)
pub fn getlogin() -> *const libc::c_char;
}
fn get_userlogin() -> Option<String> {
unsafe {
let login: *const libc::c_char = getlogin();
if login.is_null() {
None
} else {
Some(String::from_utf8_lossy(CStr::from_ptr(login).to_bytes()).to_string())
}
}
}
static NAME: &'static str = "logname";
static VERSION: &'static str = "1.0.0";
pub fn uumain(args: Vec<String>) -> i32 {
//
// Argument parsing
//
let mut opts = getopts::Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "Invalid options\n{}", f)
};
if matches.opt_present("help") {
let msg = format!("{0} {1}
Usage:
{0}
Print user's login name.", NAME, VERSION);
print!("{}", opts.usage(&msg));
return 0;
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
exec();
0
}
fn exec() {
match get_userlogin() {
Some(userlogin) => println!("{}", userlogin),
None => println!("{}: no login name", NAME)
}
}

View file

@ -1,12 +0,0 @@
[package]
name = "mkdir"
version = "0.0.1"
authors = []
[lib]
name = "mkdir"
path = "mkdir.rs"
[dependencies]
getopts = "*"
libc = "*"

View file

@ -1,160 +0,0 @@
#![crate_name = "mkdir"]
/*
* This file is part of the uutils coreutils package.
*
* (c) Nicholas Juszczak <juszczakn@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
extern crate getopts;
extern crate libc;
use std::ffi::CString;
use std::fs;
use std::io::{Error, Write};
use std::path::{Path, PathBuf};
#[path = "../common/util.rs"]
#[macro_use]
mod util;
#[path = "../common/filesystem.rs"]
mod filesystem;
use filesystem::UUPathExt;
static NAME: &'static str = "mkdir";
static VERSION: &'static str = "1.0.0";
/**
* Handles option parsing
*/
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new();
// Linux-specific options, not implemented
// opts.optflag("Z", "context", "set SELinux secutiry context" +
// " of each created directory to CTX"),
opts.optopt("m", "mode", "set file mode", "755");
opts.optflag("p", "parents", "make parent directories as needed");
opts.optflag("v", "verbose", "print a message for each printed directory");
opts.optflag("h", "help", "display this help");
opts.optflag("V", "version", "display this version");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => crash!(1, "Invalid options\n{}", f)
};
if args.len() == 1 || matches.opt_present("help") {
print_help(&opts);
return 0;
}
if matches.opt_present("version") {
println!("{} {}", NAME, VERSION);
return 0;
}
let verbose = matches.opt_present("verbose");
let recursive = matches.opt_present("parents");
// Translate a ~str in octal form to u16, default to 755
// Not tested on Windows
let mode_match = matches.opts_str(&["mode".to_string()]);
let mode: u16 = if mode_match.is_some() {
let m = mode_match.unwrap();
let res: Option<u16> = u16::from_str_radix(&m, 8).ok();
if res.is_some() {
unsafe { std::mem::transmute(res.unwrap()) }
} else {
crash!(1, "no mode given");
}
} else {
unsafe { std::mem::transmute(0o755 as u16) }
};
let dirs = matches.free;
if dirs.is_empty() {
crash!(1, "missing operand");
}
exec(dirs, recursive, mode, verbose)
}
fn print_help(opts: &getopts::Options) {
println!("{} {}", NAME, VERSION);
println!("");
println!("Usage:");
print!("{}", opts.usage("Create the given DIRECTORY(ies) if they do not exist"));
}
/**
* Create the list of new directories
*/
fn exec(dirs: Vec<String>, recursive: bool, mode: u16, verbose: bool) -> i32 {
let mut status = 0;
let empty = Path::new("");
for dir in dirs.iter() {
let path = Path::new(dir);
if recursive {
let mut pathbuf = PathBuf::new();
for component in path.components() {
pathbuf.push(component.as_os_str());
status |= mkdir(pathbuf.as_path(), mode, verbose);
}
} else {
match path.parent() {
Some(parent) => {
if parent != empty && !parent.uu_exists() {
show_info!("cannot create directory '{}': No such file or directory", path.display());
status = 1;
} else {
status |= mkdir(path, mode, verbose);
}
},
None => {
status |= mkdir(path, mode, verbose);
}
}
}
}
status
}
/**
* Wrapper to catch errors, return 1 if failed
*/
fn mkdir(path: &Path, mode: u16, verbose: bool) -> i32 {
if path.uu_exists() {
show_info!("cannot create directory '{}': File exists", path.display());
return 1;
}
if let Err(e) = fs::create_dir(path) {
show_info!("{}: {}", path.display(), e.to_string());
return 1;
}
if verbose {
show_info!("created directory '{}'", path.display());
}
#[cfg(unix)]
fn chmod(path: &Path, mode: u16) -> i32 {
let directory = CString::new(path.as_os_str().to_str().unwrap()).unwrap_or_else(|e| crash!(1, "{}", e));
let mode = mode as libc::mode_t;
if unsafe { libc::chmod(directory.as_ptr(), mode) } != 0 {
show_info!("{}: errno {}", path.display(), Error::last_os_error().raw_os_error().unwrap());
return 1;
}
0
}
#[cfg(windows)]
fn chmod(path: &Path, mode: u16) -> i32 {
// chmod on Windows only sets the readonly flag, which isn't even honored on directories
0
}
chmod(path, mode)
}

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