aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanturysim <petershh@disroot.org>2022-06-18 13:08:06 +0300
committerSanturysim <petershh@disroot.org>2022-06-18 13:08:06 +0300
commit66bb9b9687948b847ee707759d940af7ae6e6748 (patch)
tree87875bbed315287d2ed571a75ae8df24635041c4
downloadshh-portable-utils-66bb9b9687948b847ee707759d940af7ae6e6748.tar.xz
Initial commit
-rw-r--r--COPYING22
-rw-r--r--Makefile149
-rw-r--r--README.md52
-rw-r--r--config.mak43
-rwxr-xr-xconfigure471
-rw-r--r--meson.build7
-rw-r--r--package/deps-build1
-rw-r--r--package/deps.mak22
-rw-r--r--package/info4
-rw-r--r--package/modes5
-rw-r--r--package/targets.mak8
-rw-r--r--src/include/shh-portable-utils/config.h13
-rw-r--r--src/meson.build1
-rw-r--r--src/shh-portable-utils/basename.c36
-rw-r--r--src/shh-portable-utils/cat.c70
-rw-r--r--src/shh-portable-utils/deps-exe/basename0
-rw-r--r--src/shh-portable-utils/deps-exe/cat1
-rw-r--r--src/shh-portable-utils/deps-exe/false0
-rw-r--r--src/shh-portable-utils/deps-exe/true0
-rw-r--r--src/shh-portable-utils/deps-exe/uniq1
-rw-r--r--src/shh-portable-utils/deps-exe/uniq.c0
-rw-r--r--src/shh-portable-utils/false.c4
-rw-r--r--src/shh-portable-utils/meson.build5
-rw-r--r--src/shh-portable-utils/true.c4
-rw-r--r--src/shh-portable-utils/uniq.c185
-rwxr-xr-xtools/gen-deps.sh93
-rwxr-xr-xtools/install.sh64
27 files changed, 1261 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..e7af91d
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+Copyright 2022, Peter Shkenev
+
+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.
+
+This software uses code from skalibs.
+
+Copyright (c) 2011-2022 Laurent Bercot <ska-skaware@skarnet.org>
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cd6c7f0
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,149 @@
+#
+# This Makefile requires GNU make.
+#
+# Do not make changes here.
+# Use the included .mak files.
+#
+
+it: all
+
+make_need := 3.81
+ifeq "" "$(strip $(filter $(make_need), $(firstword $(sort $(make_need) $(MAKE_VERSION)))))"
+fail := $(error Your make ($(MAKE_VERSION)) is too old. You need $(make_need) or newer)
+endif
+
+CC = $(error Please use ./configure first)
+
+STATIC_LIBS :=
+SHARED_LIBS :=
+INTERNAL_LIBS :=
+EXTRA_TARGETS :=
+LIB_DEFS :=
+
+define library_definition
+LIB$(firstword $(subst =, ,$(1))) := lib$(lastword $(subst =, ,$(1))).$(if $(DO_ALLSTATIC),a,so).xyzzy
+ifdef DO_SHARED
+SHARED_LIBS += lib$(lastword $(subst =, ,$(1))).so.xyzzy
+endif
+ifdef DO_STATIC
+STATIC_LIBS += lib$(lastword $(subst =, ,$(1))).a.xyzzy
+endif
+endef
+
+-include config.mak
+include package/targets.mak
+
+$(foreach var,$(LIB_DEFS),$(eval $(call library_definition,$(var))))
+
+include package/deps.mak
+
+version_m := $(basename $(version))
+version_M := $(basename $(version_m))
+version_l := $(basename $(version_M))
+CPPFLAGS_ALL := $(CPPFLAGS_AUTO) $(CPPFLAGS)
+CFLAGS_ALL := $(CFLAGS_AUTO) $(CFLAGS)
+ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)
+CFLAGS_SHARED := -fPIC
+else
+CFLAGS_SHARED :=
+endif
+LDFLAGS_ALL := $(LDFLAGS_AUTO) $(LDFLAGS)
+AR := $(CROSS_COMPILE)ar
+RANLIB := $(CROSS_COMPILE)ranlib
+STRIP := $(CROSS_COMPILE)strip
+INSTALL := ./tools/install.sh
+
+ALL_BINS := $(LIBEXEC_TARGETS) $(BIN_TARGETS)
+ALL_LIBS := $(SHARED_LIBS) $(STATIC_LIBS) $(INTERNAL_LIBS)
+ALL_INCLUDES := $(wildcard src/include/$(package)/*.h)
+
+all: $(ALL_LIBS) $(ALL_BINS) $(ALL_INCLUDES)
+
+clean:
+ @exec rm -f $(ALL_LIBS) $(ALL_BINS) $(wildcard src/*/*.o src/*/*.lo) $(EXTRA_TARGETS)
+
+distclean: clean
+ @exec rm -f config.mak src/include/$(package)/config.h
+
+tgz: distclean
+ @. package/info && \
+ rm -rf /tmp/$$package-$$version && \
+ cp -a . /tmp/$$package-$$version && \
+ cd /tmp && \
+ tar -zpcv --owner=0 --group=0 --numeric-owner --exclude=.git* -f /tmp/$$package-$$version.tar.gz $$package-$$version && \
+ exec rm -rf /tmp/$$package-$$version
+
+strip: $(ALL_LIBS) $(ALL_BINS)
+ifneq ($(strip $(STATIC_LIBS)),)
+ exec $(STRIP) -x -R .note -R .comment $(STATIC_LIBS)
+endif
+ifneq ($(strip $(ALL_BINS)$(SHARED_LIBS)),)
+ exec $(STRIP) -R .note -R .comment $(ALL_BINS) $(SHARED_LIBS)
+endif
+
+install: install-dynlib install-libexec install-bin install-lib install-include
+install-dynlib: $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(dynlibdir)/lib%.so)
+install-libexec: $(LIBEXEC_TARGETS:%=$(DESTDIR)$(libexecdir)/%)
+install-bin: $(BIN_TARGETS:%=$(DESTDIR)$(bindir)/%)
+install-lib: $(STATIC_LIBS:lib%.a.xyzzy=$(DESTDIR)$(libdir)/lib%.a)
+install-include: $(ALL_INCLUDES:src/include/$(package)/%.h=$(DESTDIR)$(includedir)/$(package)/%.h)
+install-data: $(ALL_DATA:src/etc/%=$(DESTDIR)$(datadir)/%)
+
+ifneq ($(exthome),)
+
+$(DESTDIR)$(exthome): $(DESTDIR)$(home)
+ exec $(INSTALL) -l $(notdir $(home)) $(DESTDIR)$(exthome)
+
+update: $(DESTDIR)$(exthome)
+
+global-links: $(DESTDIR)$(exthome) $(SHARED_LIBS:lib%.so.xyzzy=$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M)) $(BIN_TARGETS:%=$(DESTDIR)$(sproot)/command/%)
+
+$(DESTDIR)$(sproot)/command/%: $(DESTDIR)$(home)/command/%
+ exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/command/$(<F) $@
+
+$(DESTDIR)$(sproot)/library.so/lib%.so.$(version_M): $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M)
+ exec $(INSTALL) -D -l ..$(subst $(sproot),,$(exthome))/library.so/$(<F) $@
+
+.PHONY: update global-links
+
+endif
+
+$(DESTDIR)$(datadir)/%: src/etc/%
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(dynlibdir)/lib%.so $(DESTDIR)$(dynlibdir)/lib%.so.$(version_M): lib%.so.xyzzy
+ $(INSTALL) -D -m 755 $< $@.$(version) && \
+ $(INSTALL) -l $(@F).$(version) $@.$(version_M) && \
+ exec $(INSTALL) -l $(@F).$(version_M) $@
+
+$(DESTDIR)$(libexecdir)/% $(DESTDIR)$(bindir)/%: % package/modes
+ exec $(INSTALL) -D -m 600 $< $@
+ grep -- ^$(@F) < package/modes | { read name mode owner && \
+ if [ x$$owner != x ] ; then chown -- $$owner $@ ; fi && \
+ chmod $$mode $@ ; }
+
+$(DESTDIR)$(libdir)/lib%.a: lib%.a.xyzzy
+ exec $(INSTALL) -D -m 644 $< $@
+
+$(DESTDIR)$(includedir)/$(package)/%.h: src/include/$(package)/%.h
+ exec $(INSTALL) -D -m 644 $< $@
+
+%.o: %.c
+ exec $(CC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) -c -o $@ $<
+
+%.lo: %.c
+ exec $(CC) $(CPPFLAGS_ALL) $(CFLAGS_ALL) $(CFLAGS_SHARED) -c -o $@ $<
+
+$(ALL_BINS):
+ exec $(CC) -o $@ $(CFLAGS_ALL) $(LDFLAGS_ALL) $(LDFLAGS_NOSHARED) $^ $(EXTRA_LIBS) $(LDLIBS)
+
+lib%.a.xyzzy:
+ exec $(AR) rc $@ $^
+ exec $(RANLIB) $@
+
+lib%.so.xyzzy:
+ exec $(CC) -o $@ $(CFLAGS_ALL) $(CFLAGS_SHARED) $(LDFLAGS_ALL) $(LDFLAGS_SHARED) -Wl,-soname,$(patsubst lib%.so.xyzzy,lib%.so.$(version_M),$@) $^ $(EXTRA_LIBS) $(LDLIBS)
+
+.PHONY: it all clean distclean tgz strip install install-dynlib install-bin install-lib install-include install-data
+
+.DELETE_ON_ERROR:
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..aa442d2
--- /dev/null
+++ b/README.md
@@ -0,0 +1,52 @@
+# shh-portable-utils
+
+Shhh!
+
+This project aims to create a set of small, correct and POSIX-conformant set of
+default utilities for the UNIX system, like echo and chmod.
+
+Powered by skalibs.
+Works best with musl libc.
+
+## Dependencies
+- POSIX system with default C programming environment.
+- GNU Make, version 3.81 or later;
+- [skalibs](https://skarnet.org/software/skalibs). This is a build-time
+ dependency and a run-time dependency if you do not link binaries statically.
+
+## Compilation and installation
+```
+./configure && make && sudo make install
+```
+will do. Alternatively, it can be built with muon build system and samurai (not
+guaranteed to work!):
+```
+muon setup build && samu -C build && muon install -C build
+```
+
+## License
+This is free software licensed under MIT license. See COPYING for details.
+
+## TODO
+- Draw the rest of the freaking owl!
+- Create shh-linux-utils, a set of base utilities that cannot be implemented in
+ a nonportable fashion. This utilities are going to be Linux-specific, I
+ primarily use Linux distros and BSDs are unlikely to adopt them.
+- I18n. I believe that utilities should be able to display text in the user's
+ native language. But, since language support drastically increases size of
+ programs, there should be a possibility to disable this at compile-tume.
+- Documentation, obviously. For now, POSIX will do.
+- Move repository to another server.
+
+## Why
+- As far as the author knows, none of existing projects provide POSIX-conformant
+ set of utilities, while there is a demand for such set.
+- Existing projects do not satisfy the author for some reasons:
+ - [GNU Coreutils](https//www.gnu.prg/software/coreutils): well, this is GNU,
+ which is translated as 'bloated, inefficient, insecure'.
+ - [Busybox](https://busybox.net), [Toybox](https://landley.net/toybox):
+ these projects provide multicall binaries. This approach has its
+ advantages, but it also has its drawbacks. The goal of shh-utils is
+ provide standalone binaries.
+ - [sbase](https://core.suckless.org/sbase/): Idk, need to check this out.
+- Last but not least: NIH syndrome of course!
diff --git a/config.mak b/config.mak
new file mode 100644
index 0000000..92e0f53
--- /dev/null
+++ b/config.mak
@@ -0,0 +1,43 @@
+# This file was generated by:
+# ./configure
+# Any changes made here will be lost if configure is re-run.
+
+target := x86_64-alpine-linux-musl
+package := shh-portable-utils
+prefix :=
+exec_prefix :=
+dynlibdir := /lib
+libexecdir := /libexec
+bindir := /bin
+libdir := /usr/lib/shh-portable-utils
+includedir := /usr/include
+sysdeps := /usr/lib/skalibs/sysdeps
+slashpackage := false
+sproot :=
+version := 0.0.0.1
+home :=
+exthome :=
+SPAWN_LIB :=
+SOCKET_LIB :=
+SYSCLOCK_LIB :=
+TIMER_LIB :=
+UTIL_LIB :=
+
+CC := gcc
+CPPFLAGS_AUTO := -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -iquote src/include-local -Isrc/include -fPIC -Werror=implicit-function-declaration -Werror=implicit-int -Werror=pointer-sign -Werror=pointer-arith
+CPPFLAGS :=
+CFLAGS_AUTO := -pipe -Wall -std=c99 -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections
+CFLAGS := -O2 -fomit-frame-pointer
+LDFLAGS_AUTO := -Wl,--sort-section=alignment -Wl,--sort-common
+LDFLAGS :=
+LDFLAGS_SHARED := -shared
+LDFLAGS_NOSHARED := -L/usr/lib/skalibs -Wl,--gc-sections
+CROSS_COMPILE :=
+
+vpath lib%.a /usr/lib/skalibs
+vpath lib%.so
+.LIBPATTERNS := lib%.a
+DO_ALLSTATIC := 1
+DO_STATIC := 1
+DO_SHARED :=
+STATIC_LIBS_ARE_PIC := 1
diff --git a/configure b/configure
new file mode 100755
index 0000000..4c9874e
--- /dev/null
+++ b/configure
@@ -0,0 +1,471 @@
+#!/bin/sh
+
+cd `dirname "$0"`
+. package/info
+
+usage () {
+cat <<EOF
+Usage: $0 [OPTION]... [TARGET]
+
+Defaults for the options are specified in brackets.
+
+System types:
+ --target=TARGET configure to run on target TARGET [detected]
+ --host=TARGET same as --target
+
+Installation directories:
+ --prefix=PREFIX main installation prefix [/]
+ --exec-prefix=EPREFIX installation prefix for executable files [PREFIX]
+
+Fine tuning of the installation directories:
+ --dynlibdir=DIR shared library files [PREFIX/lib]
+ --bindir=BINDIR user executables [EPREFIX/bin]
+ --libexecdir=DIR package-scoped executables [EPREFIX/libexec]
+ --libdir=DIR static library files [PREFIX/lib/$package]
+ --includedir=DIR C header files [PREFIX/include]
+
+ If no --prefix option is given, by default libdir (but not dynlibdir) will be
+ /usr/lib/$package, and includedir will be /usr/include.
+
+Dependencies:
+ --with-sysdeps=DIR use sysdeps in DIR [PREFIX/lib/skalibs/sysdeps]
+ --with-include=DIR add DIR to the list of searched directories for headers
+ --with-lib=DIR add DIR to the list of searched directories for static libraries
+ --with-dynlib=DIR add DIR to the list of searched directories for shared libraries
+
+ If no --prefix option is given, by default sysdeps will be fetched from
+ /usr/lib/skalibs/sysdeps.
+
+Optional features:
+ --enable-shared build shared libraries [disabled]
+ --disable-static do not build static libraries [enabled]
+ --disable-allstatic do not prefer linking against static libraries [enabled]
+ --enable-static-libc make entirely static binaries [disabled]
+ --disable-all-pic do not build executables or static libs as PIC [enabled]
+ --enable-slashpackage[=ROOT] assume /package installation at ROOT [disabled]
+ --enable-absolute-paths do not rely on PATH to access this package's binaries,
+ hardcode absolute BINDIR/foobar paths instead [disabled]
+
+EOF
+exit 0
+}
+
+# Helper functions
+
+# If your system does not have printf, you can comment this, but it is
+# generally not a good idea to use echo.
+# See http://etalabs.net/sh_tricks.html
+echo () {
+ IFS=" "
+ printf %s\\n "$*"
+}
+
+quote () {
+ tr '\n' ' ' <<EOF | grep '^[-[:alnum:]_=,./:]* $' >/dev/null 2>&1 && { echo "$1" ; return 0 ; }
+$1
+EOF
+ echo "$1" | sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" -e "s#^'\([-[:alnum:]_,./:]*\)=\(.*\)\$#\1='\2#" -e "s|\*/|* /|g"
+}
+
+fail () {
+ echo "$*"
+ exit 1
+}
+
+fnmatch () {
+ eval "case \"\$2\" in $1) return 0 ;; *) return 1 ;; esac"
+}
+
+cmdexists () {
+ type "$1" >/dev/null 2>&1
+}
+
+trycc () {
+ test -z "$CC_AUTO" && cmdexists "$1" && CC_AUTO="$*"
+}
+
+stripdir () {
+ while eval "fnmatch '*/' \"\${$1}\"" ; do
+ eval "$1=\${$1%/}"
+ done
+}
+
+tryflag () {
+ echo "Checking whether compiler accepts $2 ..."
+ echo "typedef int x;" > "$tmpc"
+ if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST "$2" -c -o "$tmpo" "$tmpc" >/dev/null 2>&1 ; then
+ echo " ... yes"
+ eval "$1=\"\${$1} \$2\""
+ eval "$1=\${$1# }"
+ return 0
+ else
+ echo " ... no"
+ return 1
+ fi
+}
+
+tryldflag () {
+ echo "Checking whether linker accepts $2 ..."
+ echo "typedef int x;" > "$tmpc"
+ if $CC_AUTO $CFLAGS_AUTO $CFLAGS $CFLAGS_POST $LDFLAGS_AUTO $LDFLAGS $LDFLAGS_POST -nostdlib "$2" -o "$tmpe" "$tmpc" >/dev/null 2>&1 ; then
+ echo " ... yes"
+ eval "$1=\"\${$1} \$2\""
+ eval "$1=\${$1# }"
+ return 0
+ else
+ echo " ... no"
+ return 1
+ fi
+}
+
+
+# Actual script
+
+CC_AUTO=
+CPPFLAGS_AUTO="-D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -iquote src/include-local -Isrc/include"
+CPPFLAGS_POST="$CPPFLAGS"
+CPPFLAGS=
+CFLAGS_AUTO="-pipe -Wall"
+CFLAGS_POST="$CFLAGS"
+CFLAGS=-O2
+LDFLAGS_AUTO=
+LDFLAGS_POST="$LDFLAGS"
+LDFLAGS=
+LDFLAGS_NOSHARED=
+LDFLAGS_SHARED=-shared
+prefix=
+exec_prefix='$prefix'
+dynlibdir='$prefix/lib'
+libexecdir='$exec_prefix/libexec'
+bindir='$exec_prefix/bin'
+libdir='$prefix/lib/$package'
+includedir='$prefix/include'
+sysdeps='$prefix/lib/skalibs/sysdeps'
+manualsysdeps=false
+shared=false
+static=true
+allpic=true
+slashpackage=false
+abspath=false
+sproot=
+home=
+exthome=
+allstatic=true
+evenmorestatic=false
+addincpath=''
+addlibspath=''
+addlibdpath=''
+vpaths=''
+vpathd=''
+build=
+
+for arg ; do
+ case "$arg" in
+ --help) usage ;;
+ --prefix=*) prefix=${arg#*=} ;;
+ --exec-prefix=*) exec_prefix=${arg#*=} ;;
+ --dynlibdir=*) dynlibdir=${arg#*=} ;;
+ --libexecdir=*) libexecdir=${arg#*=} ;;
+ --bindir=*) bindir=${arg#*=} ;;
+ --libdir=*) libdir=${arg#*=} ;;
+ --includedir=*) includedir=${arg#*=} ;;
+ --with-sysdeps=*) sysdeps=${arg#*=} manualsysdeps=true ;;
+ --with-include=*) var=${arg#*=} ; stripdir var ; addincpath="$addincpath -I$var" ;;
+ --with-lib=*) var=${arg#*=} ; stripdir var ; addlibspath="$addlibspath -L$var" ; vpaths="$vpaths $var" ;;
+ --with-dynlib=*) var=${arg#*=} ; stripdir var ; addlibdpath="$addlibdpath -L$var" ; vpathd="$vpathd $var" ;;
+ --enable-shared|--enable-shared=yes) shared=true ;;
+ --disable-shared|--enable-shared=no) shared=false ;;
+ --enable-static|--enable-static=yes) static=true ;;
+ --disable-static|--enable-static=no) static=false ;;
+ --enable-allstatic|--enable-allstatic=yes) allstatic=true ;;
+ --disable-allstatic|--enable-allstatic=no) allstatic=false ; evenmorestatic=false ;;
+ --enable-static-libc|--enable-static-libc=yes) allstatic=true ; evenmorestatic=true ;;
+ --disable-static-libc|--enable-static-libc=no) evenmorestatic=false ;;
+ --enable-all-pic|--enable-all-pic=yes) allpic=true ;;
+ --disable-all-pic|--enable-all-pic=no) allpic=false ;;
+ --enable-slashpackage=*) sproot=${arg#*=} ; slashpackage=true ; ;;
+ --enable-slashpackage) sproot= ; slashpackage=true ;;
+ --disable-slashpackage) sproot= ; slashpackage=false ;;
+ --enable-absolute-paths|--enable-absolute-paths=yes) abspath=true ;;
+ --disable-absolute-paths|--enable-absolute-paths=no) abspath=false ;;
+ --enable-*|--disable-*|--with-*|--without-*|--*dir=*) ;;
+ --host=*|--target=*) target=${arg#*=} ;;
+ --build=*) build=${arg#*=} ;;
+ -* ) echo "$0: unknown option $arg" ;;
+ *=*) eval "$arg" ;;
+ *) target=$arg ;;
+ esac
+done
+
+# Add /usr in the default default case
+if test -z "$prefix" ; then
+ if test "$libdir" = '$prefix/lib/$package' ; then
+ libdir=/usr/lib/$package
+ fi
+ if test "$includedir" = '$prefix/include' ; then
+ includedir=/usr/include
+ fi
+ if test "$sysdeps" = '$prefix/lib/skalibs/sysdeps' ; then
+ sysdeps=/usr/lib/skalibs/sysdeps
+ fi
+fi
+
+# Expand installation directories
+stripdir prefix
+for i in exec_prefix dynlibdir libexecdir bindir libdir includedir sysdeps sproot ; do
+ eval tmp=\${$i}
+ eval $i=$tmp
+ stripdir $i
+done
+
+# Get usable temp filenames
+i=0
+set -C
+while : ; do
+ i=$(($i+1))
+ tmpc="./tmp-configure-$$-$PPID-$i.c"
+ tmpo="./tmp-configure-$$-$PPID-$i.o"
+ tmpe="./tmp-configure-$$-$PPID-$i.tmp"
+ 2>|/dev/null > "$tmpc" && break
+ 2>|/dev/null > "$tmpo" && break
+ 2>|/dev/null > "$tmpe" && break
+ test "$i" -gt 50 && fail "$0: cannot create temporary files"
+done
+set +C
+trap 'rm -f "$tmpc" "$tmpo" "$tmpe"' EXIT ABRT INT QUIT TERM HUP
+
+# Set slashpackage values
+if $slashpackage ; then
+ home=${sproot}/package/${category}/${package}-${version}
+ exthome=${sproot}/package/${category}/${package}
+ if $manualsysdeps ; then
+ :
+ else
+ sysdeps=${DESTDIR}${sproot}/package/prog/skalibs/sysdeps
+ fi
+ extbinprefix=${exthome}/command
+ dynlibdir=${home}/library.so
+ bindir=${home}/command
+ libdir=${home}/library
+ libexecdir=$bindir
+ includedir=${home}/include
+ while read dep condvar ; do
+ if test -n "$condvar" ; then
+ eval "cond=$condvar"
+ else
+ cond=true
+ fi
+ if $cond ; then
+ addincpath="$addincpath -I${DESTDIR}${sproot}${dep}/include"
+ vpaths="$vpaths ${DESTDIR}${sproot}${dep}/library"
+ addlibspath="$addlibspath -L${DESTDIR}${sproot}${dep}/library"
+ vpathd="$vpathd ${DESTDIR}${sproot}${dep}/library.so"
+ addlibdpath="$addlibdpath -L${DESTDIR}${sproot}${dep}/library.so"
+ fi
+ done < package/deps-build
+fi
+
+# Find a C compiler to use
+if test -n "$target" && test x${build} != x${target} ; then
+ cross=${target}-
+else
+ cross=
+fi
+echo "Checking for C compiler..."
+trycc ${CC}
+if test -n "$CC_AUTO" ; then
+ b=`basename "$CC"`
+ adjust_cross=false
+ if test "$b" != "$CC" ; then
+ adjust_cross=true
+ echo "$0: warning: compiler $CC is declared with its own path. If it's not accessible via PATH, you will need to pass AR, RANLIB and STRIP make variables to the make invocation." 1>&2
+ fi
+ if test -n "$cross" ; then
+ if test "$b" = "${b##$cross}" ; then
+ echo "$0: warning: compiler $CC is declared as a cross-compiler for target $target but does not start with prefix ${cross}" 1>&2
+ elif $adjust_cross ; then
+ cross=`dirname "$CC"`/"$cross"
+ fi
+ fi
+fi
+trycc ${cross}gcc
+trycc ${cross}clang
+trycc ${cross}cc
+test -n "$CC_AUTO" || { echo "$0: cannot find a C compiler" ; exit 1 ; }
+echo " ... $CC_AUTO"
+echo "Checking whether C compiler works... "
+echo "typedef int x;" > "$tmpc"
+if $CC_AUTO $CPPFLAGS_AUTO $CPPFLAGS $CPPFLAGS_POST $CFLAGS_AUTO $CFLAGS $CFLAGS_POST -c -o "$tmpo" "$tmpc" 2>"$tmpe" ; then
+ echo " ... yes"
+else
+ echo " ... no. Compiler output follows:"
+ cat < "$tmpe"
+ exit 1
+fi
+
+echo "Checking target system type..."
+if test -z "$target" ; then
+ if test -n "$build" ; then
+ target=$build ;
+ else
+ target=$($CC_AUTO -dumpmachine 2>/dev/null) || target=unknown
+ fi
+fi
+echo " ... $target"
+if test ! -d $sysdeps || test ! -f $sysdeps/target ; then
+ echo "$0: error: $sysdeps is not a valid sysdeps directory"
+ exit 1
+fi
+if [ "x$target" != "x$(cat $sysdeps/target)" ] ; then
+ echo "$0: error: target $target does not match the contents of $sysdeps/target"
+ exit 1
+fi
+
+spawn_lib=$(cat $sysdeps/spawn.lib)
+socket_lib=$(cat $sysdeps/socket.lib)
+sysclock_lib=$(cat $sysdeps/sysclock.lib)
+timer_lib=$(cat $sysdeps/timer.lib)
+util_lib=$(cat $sysdeps/util.lib)
+
+if $allpic ; then
+ tryflag CPPFLAGS_AUTO -fPIC
+fi
+tryflag CFLAGS_AUTO -std=c99
+tryflag CFLAGS -fomit-frame-pointer
+tryflag CFLAGS_AUTO -fno-exceptions
+tryflag CFLAGS_AUTO -fno-unwind-tables
+tryflag CFLAGS_AUTO -fno-asynchronous-unwind-tables
+tryflag CPPFLAGS_AUTO -Werror=implicit-function-declaration
+tryflag CPPFLAGS_AUTO -Werror=implicit-int
+tryflag CPPFLAGS_AUTO -Werror=pointer-sign
+tryflag CPPFLAGS_AUTO -Werror=pointer-arith
+tryflag CFLAGS_AUTO -ffunction-sections
+tryflag CFLAGS_AUTO -fdata-sections
+
+tryldflag LDFLAGS_AUTO -Wl,--sort-section=alignment
+tryldflag LDFLAGS_AUTO -Wl,--sort-common
+
+CPPFLAGS_AUTO="${CPPFLAGS_AUTO}${addincpath}"
+
+if $evenmorestatic ; then
+ LDFLAGS_NOSHARED=-static
+fi
+
+if $shared ; then
+ tryldflag LDFLAGS -Wl,--hash-style=both
+fi
+
+LDFLAGS_SHARED="${LDFLAGS_SHARED}${addlibdpath}"
+
+if test -z "$vpaths" ; then
+ while read dep ; do
+ base=$(basename $dep) ;
+ vpaths="$vpaths /usr/lib/$base"
+ addlibspath="$addlibspath -L/usr/lib/$base"
+ done < package/deps-build
+fi
+
+if $allstatic ; then
+ LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibspath}"
+ tryldflag LDFLAGS_NOSHARED -Wl,--gc-sections
+else
+ LDFLAGS_NOSHARED="${LDFLAGS_NOSHARED}${addlibdpath}"
+fi
+
+echo "Creating config.mak..."
+cmdline=$(quote "$0")
+for i ; do cmdline="$cmdline $(quote "$i")" ; done
+exec 3>&1 1>config.mak
+cat << EOF
+# This file was generated by:
+# $cmdline
+# Any changes made here will be lost if configure is re-run.
+
+target := $target
+package := $package
+prefix := $prefix
+exec_prefix := $exec_prefix
+dynlibdir := $dynlibdir
+libexecdir := $libexecdir
+bindir := $bindir
+libdir := $libdir
+includedir := $includedir
+sysdeps := $sysdeps
+slashpackage := $slashpackage
+sproot := $sproot
+version := $version
+home := $home
+exthome := $exthome
+SPAWN_LIB := ${spawn_lib}
+SOCKET_LIB := ${socket_lib}
+SYSCLOCK_LIB := ${sysclock_lib}
+TIMER_LIB := ${timer_lib}
+UTIL_LIB := ${util_lib}
+
+CC := $CC_AUTO
+CPPFLAGS_AUTO := $CPPFLAGS_AUTO
+CPPFLAGS := $CPPFLAGS $CPPFLAGS_POST
+CFLAGS_AUTO := $CFLAGS_AUTO
+CFLAGS := $CFLAGS $CFLAGS_POST
+LDFLAGS_AUTO := $LDFLAGS_AUTO
+LDFLAGS := $LDFLAGS $LDFLAGS_POST
+LDFLAGS_SHARED := $LDFLAGS_SHARED
+LDFLAGS_NOSHARED := $LDFLAGS_NOSHARED
+CROSS_COMPILE := $cross
+
+vpath lib%.a$vpaths
+vpath lib%.so$vpathd
+EOF
+if $allstatic ; then
+ echo ".LIBPATTERNS := lib%.a"
+ echo "DO_ALLSTATIC := 1"
+else
+ echo ".LIBPATTERNS := lib%.so"
+fi
+if $static ; then
+ echo "DO_STATIC := 1"
+else
+ echo "DO_STATIC :="
+fi
+if $shared ; then
+ echo "DO_SHARED := 1"
+else
+ echo "DO_SHARED :="
+fi
+if $allpic ; then
+ echo "STATIC_LIBS_ARE_PIC := 1"
+else
+ echo "STATIC_LIBS_ARE_PIC :="
+fi
+
+exec 1>&3 3>&-
+echo " ... done."
+
+echo "Creating src/include/${package}/config.h..."
+mkdir -p -m 0755 src/include/${package}
+exec 3>&1 1> src/include/${package}/config.h
+cat <<EOF
+/* ISC license. */
+
+/* Generated by: $cmdline */
+
+#ifndef ${package_macro_name}_CONFIG_H
+#define ${package_macro_name}_CONFIG_H
+
+#define ${package_macro_name}_VERSION "$version"
+EOF
+if $slashpackage ; then
+ echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"$extbinprefix/\""
+elif $abspath ; then
+ echo "#define ${package_macro_name}_BINPREFIX \"$bindir/\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"$bindir/\""
+else
+ echo "#define ${package_macro_name}_BINPREFIX \"\""
+ echo "#define ${package_macro_name}_EXTBINPREFIX \"\""
+fi
+echo "#define ${package_macro_name}_LIBEXECPREFIX \"$libexecdir/\""
+echo
+echo "#endif"
+exec 1>&3 3>&-
+echo " ... done."
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..de29623
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,7 @@
+project('shh-portable-utils', ['c'], version: '0.0.0.1', default_options: ['c_std=c99'])
+
+cc = meson.get_compiler('c')
+
+libskarnet = [cc.find_library('skarnet', required: true)]
+
+subdir('src')
diff --git a/package/deps-build b/package/deps-build
new file mode 100644
index 0000000..05d5af4
--- /dev/null
+++ b/package/deps-build
@@ -0,0 +1 @@
+/package/prog/skalibs
diff --git a/package/deps.mak b/package/deps.mak
new file mode 100644
index 0000000..08c9469
--- /dev/null
+++ b/package/deps.mak
@@ -0,0 +1,22 @@
+#
+# This file has been generated by tools/gen-deps.sh
+#
+
+src/shh-portable-utils/basename.o src/shh-portable-utils/basename.lo: src/shh-portable-utils/basename.c
+src/shh-portable-utils/cat.o src/shh-portable-utils/cat.lo: src/shh-portable-utils/cat.c
+src/shh-portable-utils/false.o src/shh-portable-utils/false.lo: src/shh-portable-utils/false.c
+src/shh-portable-utils/true.o src/shh-portable-utils/true.lo: src/shh-portable-utils/true.c
+src/shh-portable-utils/uniq.o src/shh-portable-utils/uniq.lo: src/shh-portable-utils/uniq.c
+
+basename: EXTRA_LIBS :=
+basename: src/shh-portable-utils/basename.o
+cat: EXTRA_LIBS := -lskarnet
+cat: src/shh-portable-utils/cat.o
+false: EXTRA_LIBS :=
+false: src/shh-portable-utils/false.o
+true: EXTRA_LIBS :=
+true: src/shh-portable-utils/true.o
+uniq: EXTRA_LIBS := -lskarnet
+uniq: src/shh-portable-utils/uniq.o
+uniq.c: EXTRA_LIBS :=
+uniq.c: src/shh-portable-utils/uniq.c.o
diff --git a/package/info b/package/info
new file mode 100644
index 0000000..5d4a623
--- /dev/null
+++ b/package/info
@@ -0,0 +1,4 @@
+package=shh-portable-utils
+version=0.0.0.1
+category=admin
+package_macro_name=SHH_PORTABLE_UTILS
diff --git a/package/modes b/package/modes
new file mode 100644
index 0000000..fd0cd24
--- /dev/null
+++ b/package/modes
@@ -0,0 +1,5 @@
+basename 0755
+cat 0755
+false 0755
+true 0755
+uniq 0755
diff --git a/package/targets.mak b/package/targets.mak
new file mode 100644
index 0000000..48946f2
--- /dev/null
+++ b/package/targets.mak
@@ -0,0 +1,8 @@
+BIN_TARGETS := \
+basename \
+cat \
+false \
+true \
+uniq
+
+LIBEXEC_TARGETS :=
diff --git a/src/include/shh-portable-utils/config.h b/src/include/shh-portable-utils/config.h
new file mode 100644
index 0000000..5b5a36b
--- /dev/null
+++ b/src/include/shh-portable-utils/config.h
@@ -0,0 +1,13 @@
+/* ISC license. */
+
+/* Generated by: ./configure */
+
+#ifndef SHH_PORTABLE_UTILS_CONFIG_H
+#define SHH_PORTABLE_UTILS_CONFIG_H
+
+#define SHH_PORTABLE_UTILS_VERSION "0.0.0.1"
+#define SHH_PORTABLE_UTILS_BINPREFIX ""
+#define SHH_PORTABLE_UTILS_EXTBINPREFIX ""
+#define SHH_PORTABLE_UTILS_LIBEXECPREFIX "/libexec/"
+
+#endif
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..54a6c8d
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1 @@
+subdir('shh-portable-utils')
diff --git a/src/shh-portable-utils/basename.c b/src/shh-portable-utils/basename.c
new file mode 100644
index 0000000..01ff546
--- /dev/null
+++ b/src/shh-portable-utils/basename.c
@@ -0,0 +1,36 @@
+#include <unistd.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+ size_t pathlen, sufflen, i;
+ char *basename_start;
+ if (argc < 2) { write(1, ".\n", 2); return 0; }
+ pathlen = strlen(argv[1]);
+ if(!pathlen) { write(1, ".\n", 2); return 0; }
+ for (i = 1; i < pathlen; i++)
+ if (argv[1][pathlen - i] != '/') break;
+ if (i == pathlen) {
+ write(1, "/\n", 2);
+ return 0;
+ }
+ i--;
+ argv[1][pathlen - i] = '\0';
+ pathlen = pathlen - i;
+ for(i = 1; i < pathlen; i++)
+ if (argv[1][pathlen - i] == '/') break;
+ if (i == pathlen)
+ basename_start = argv[1];
+ else {
+ basename_start = argv[1] + pathlen - i + 1;
+ pathlen = i - 1;
+ }
+ if (argc > 2) {
+ sufflen = strlen(argv[2]);
+ if (!strcmp(basename_start + pathlen - sufflen, argv[2]))
+ pathlen -= sufflen;
+ }
+ write(1, basename_start, pathlen);
+ write(1, "\n", 1);
+ return 0;
+}
diff --git a/src/shh-portable-utils/cat.c b/src/shh-portable-utils/cat.c
new file mode 100644
index 0000000..5913922
--- /dev/null
+++ b/src/shh-portable-utils/cat.c
@@ -0,0 +1,70 @@
+#include <stddef.h>
+#include <string.h>
+
+#include <skalibs/allreadwrite.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/djbunix.h>
+
+#define USAGE "cat [-u] [file...]"
+
+typedef off_t (*cat_func_t)(int, int);
+
+off_t fd_cat_slow(int from, int to);
+
+off_t fd_cat_slow(int from, int to)
+{
+ char c;
+ off_t transmitted = 0;
+ for (;;) {
+ ssize_t result = fd_read(from, &c, 1);
+ if (result < 0)
+ return result;
+ if (result == 0)
+ break;
+ if (fd_write(to, &c, 1) < 0)
+ return -1;
+ transmitted++;
+ }
+ return transmitted;
+}
+
+int main(int argc, char const *const *argv)
+{
+ cat_func_t cat = fd_cat;
+ subgetopt l = SUBGETOPT_ZERO;
+ PROG = "cat";
+ for (;;) {
+ int opt = subgetopt_r(argc, argv, "u", &l);
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 'u':
+ cat = fd_cat_slow;
+ break;
+ default:
+ strerr_dieusage(100, USAGE);
+ break;
+ }
+ }
+ argc -= l.ind;
+ argv += l.ind;
+ if (argc == 0)
+ if (cat(0, 1) < 0)
+ strerr_diefu1sys(111, "read from stdin");
+ for (char const *const *filename = argv; *filename; filename++) {
+ int fd;
+ if (!strcmp(*filename, "-"))
+ fd = 0;
+ else {
+ fd = openb_read(*filename);
+ if (fd < 0)
+ strerr_diefu3sys(111, "open file ", *filename, " for reading");
+ }
+ if (cat(fd, 1) < 0)
+ strerr_diefu2sys(111, "read from ", fd == 1 ? "stdin" : *filename);
+ fd_close(fd);
+ }
+
+ return 0;
+}
diff --git a/src/shh-portable-utils/deps-exe/basename b/src/shh-portable-utils/deps-exe/basename
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/shh-portable-utils/deps-exe/basename
diff --git a/src/shh-portable-utils/deps-exe/cat b/src/shh-portable-utils/deps-exe/cat
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/shh-portable-utils/deps-exe/cat
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/shh-portable-utils/deps-exe/false b/src/shh-portable-utils/deps-exe/false
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/shh-portable-utils/deps-exe/false
diff --git a/src/shh-portable-utils/deps-exe/true b/src/shh-portable-utils/deps-exe/true
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/shh-portable-utils/deps-exe/true
diff --git a/src/shh-portable-utils/deps-exe/uniq b/src/shh-portable-utils/deps-exe/uniq
new file mode 100644
index 0000000..e7187fe
--- /dev/null
+++ b/src/shh-portable-utils/deps-exe/uniq
@@ -0,0 +1 @@
+-lskarnet
diff --git a/src/shh-portable-utils/deps-exe/uniq.c b/src/shh-portable-utils/deps-exe/uniq.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/shh-portable-utils/deps-exe/uniq.c
diff --git a/src/shh-portable-utils/false.c b/src/shh-portable-utils/false.c
new file mode 100644
index 0000000..2cecef0
--- /dev/null
+++ b/src/shh-portable-utils/false.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 1;
+}
diff --git a/src/shh-portable-utils/meson.build b/src/shh-portable-utils/meson.build
new file mode 100644
index 0000000..6b205fa
--- /dev/null
+++ b/src/shh-portable-utils/meson.build
@@ -0,0 +1,5 @@
+executable('basename', 'basename.c', install: true)
+executable('cat', 'cat.c', dependencies: libskarnet, install: true)
+executable('false', 'false.c', install: true)
+executable('true', 'true.c', install: true,)
+executable('uniq', 'uniq.c', dependencies: libskarnet, install: true)
diff --git a/src/shh-portable-utils/true.c b/src/shh-portable-utils/true.c
new file mode 100644
index 0000000..58fe692
--- /dev/null
+++ b/src/shh-portable-utils/true.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/src/shh-portable-utils/uniq.c b/src/shh-portable-utils/uniq.c
new file mode 100644
index 0000000..e8d50db
--- /dev/null
+++ b/src/shh-portable-utils/uniq.c
@@ -0,0 +1,185 @@
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <skalibs/buffer.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/sgetopt.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/uint32.h>
+
+#define USAGE "uniq [-c|-d|-u] [-f fields] [-s char] [input_file [output_file]]"
+
+#define byte_cmp(s1, l1, s2, l2) memcmp((s1), (s2), (l1) < (l2) ? (l1) : (l2))
+
+char *prepare_string(stralloc const *sa, int fields, int chars);
+
+size_t byte_notin(char const *s, size_t n, char const *sep, size_t len);
+
+char *prepare_string(stralloc const *sa, int fields, int chars)
+{
+ size_t pos = 0;
+ for (int j = 0; j < fields; j++) {
+ pos += byte_notin(sa->s + pos, sa->len - pos, " \t", 2);
+ if (pos >= sa->len)
+ return sa->s + sa->len;
+ pos += byte_in(sa->s + pos, sa->len - pos, " \t", 2);
+ if (pos >= sa->len)
+ return sa->s + sa->len;
+ }
+ return sa->s + (pos + chars > sa->len ? sa->len : pos + chars);
+}
+
+size_t byte_notin(char const *s, size_t n, char const *sep, size_t len)
+{
+ char const *t = s;
+ while (n) {
+ n--;
+ if (!memchr(sep, *t, len))
+ break;
+ t++;
+ }
+ return t - s;
+}
+
+int main(int argc, char const *const *argv)
+{
+ char *prev_line_start, *curr_line_start;
+ int counter, result;
+ char buf_in[BUFFER_INSIZE];
+ char buf_out[BUFFER_OUTSIZE];
+ buffer buffer_in_, buffer_out_;
+ buffer *buffer_in, *buffer_out;
+ stralloc prev_line = STRALLOC_ZERO;
+ stralloc curr_line = STRALLOC_ZERO;
+ subgetopt l = SUBGETOPT_ZERO;
+ int chars = 0, fields = 0;
+ int do_count = 0, pr_repeated = 1, pr_unique = 1;
+
+ PROG = "uniq";
+ for (;;) {
+ int opt = subgetopt_r(argc, argv, "cdf:s:u", &l);
+ if (opt == -1)
+ break;
+ switch (opt) {
+ case 'c':
+ do_count = 1;
+ break;
+ case 'd':
+ pr_unique = 0;
+ break;
+ case 'f':
+ if (!int32_scan(l.arg, &fields))
+ strerr_dieusage(100, USAGE);
+ break;
+ case 's':
+ if (!int32_scan(l.arg, &chars))
+ strerr_dieusage(100, USAGE);
+ break;
+ case 'u':
+ pr_repeated = 0;
+ break;
+ default:
+ strerr_dieusage(100, USAGE);
+ break;
+ }
+ }
+ argc -= l.ind;
+ argv += l.ind;
+
+ if (argc >= 3)
+ strerr_dieusage(100, USAGE);
+
+ if (argc >= 2) {
+ int out = open_create(argv[1]);
+ if (out < 0)
+ strerr_diefu3sys(111, "open file ", argv[1], " for writing");
+ buffer_init(&buffer_out_, buffer_write, out, buf_out, BUFFER_OUTSIZE);
+ buffer_out = &buffer_out_;
+ } else
+ buffer_out = buffer_1;
+
+ if (argc >= 1) {
+ if (strcmp(argv[0], "-")) {
+ int in = openb_read(argv[0]);
+ if (in < 0)
+ strerr_diefu3sys(111, "open file ", argv[0], " for reading");
+ buffer_init(&buffer_in_, buffer_read, in, buf_in, BUFFER_INSIZE);
+ buffer_in = &buffer_in_;
+ } else
+ buffer_in = buffer_0;
+ } else
+ buffer_in = buffer_0;
+
+ result = skagetln(buffer_in, &prev_line, '\n');
+ if (result < 0) {
+ if (errno != EPIPE)
+ strerr_diefu1sys(111, "read line");
+ else {
+ if (!pr_unique)
+ if (do_count)
+ buffer_puts(buffer_out, "1 ");
+ buffer_putflush(buffer_out, prev_line.s, prev_line.len);
+ return 0;
+ }
+ }
+
+ prev_line.s[prev_line.len - 1] = '\0';
+ prev_line.len--;
+ counter = 1;
+ prev_line_start = prepare_string(&prev_line, fields, chars);
+
+
+ for (;;) {
+ curr_line.len = 0;
+ result = skagetln(buffer_in, &curr_line, '\n');
+ if (result > 0) {
+ curr_line.s[curr_line.len - 1] = '\0';
+ curr_line.len--;
+ }
+ if (!result)
+ break;
+ if (result < 0) {
+ if (errno != EPIPE)
+ strerr_diefu1sys(111, "read line");
+ else {
+ stralloc_0(&curr_line);
+ curr_line.len--;
+ }
+ }
+ curr_line_start = prepare_string(&curr_line, fields, chars);
+ if (!strcmp(prev_line_start, curr_line_start))
+ counter++;
+ else {
+ if ((counter > 1 && pr_repeated) || (counter == 1 && pr_unique)) {
+ if (do_count) {
+ char fmt[UINT32_FMT];
+ buffer_put(buffer_out, fmt, int32_fmt(fmt, counter));
+ buffer_puts(buffer_out, " ");
+ }
+ buffer_put(buffer_out, prev_line.s, prev_line.len);
+ buffer_putsflush(buffer_out, "\n");
+ }
+ prev_line_start = prev_line.s + (curr_line_start - curr_line.s);
+ stralloc_copy(&prev_line, &curr_line);
+ stralloc_0(&prev_line);
+ prev_line.len--;
+ counter = 1;
+ }
+ if (result < 0) // errno was EPIPE, we got EOF in the middle of a line
+ break;
+ }
+ if ((counter > 1 && pr_repeated) || (counter == 1 && pr_unique)) {
+ if (do_count) {
+ char fmt[UINT32_FMT];
+ buffer_put(buffer_out, fmt, int32_fmt(fmt, counter));
+ buffer_puts(buffer_out, " ");
+ }
+ buffer_put(buffer_out, prev_line.s, prev_line.len);
+ buffer_putsflush(buffer_out, "\n");
+ }
+ return 0;
+}
diff --git a/tools/gen-deps.sh b/tools/gen-deps.sh
new file mode 100755
index 0000000..27e5b3e
--- /dev/null
+++ b/tools/gen-deps.sh
@@ -0,0 +1,93 @@
+#!/bin/sh -e
+
+. package/info
+
+echo '#'
+echo '# This file has been generated by tools/gen-deps.sh'
+echo '#'
+echo
+
+for dir in src/include/${package} src/* ; do
+ for file in $(ls -1 $dir | grep -- \\.h$) ; do
+ {
+ grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ;
+ grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2
+ } | sort -u | {
+ deps=
+ while read dep ; do
+ if echo $dep | grep -q "^${package}/" ; then
+ deps="$deps src/include/$dep"
+ elif test -f "${dir}/$dep" ; then
+ deps="$deps ${dir}/$dep"
+ else
+ deps="$deps src/include-local/$dep"
+ fi
+ done
+ if test -n "$deps" ; then
+ echo "${dir}/${file}:${deps}"
+ fi
+ }
+ done
+done
+
+for dir in src/* ; do
+ for file in $(ls -1 $dir | grep -- \\.c$) ; do
+ {
+ grep -F -- "#include <${package}/" < ${dir}/$file | cut -d'<' -f2 | cut -d'>' -f1 ;
+ grep -- '#include ".*\.h"' < ${dir}/$file | cut -d'"' -f2
+ } | sort -u | {
+ deps=" ${dir}/$file"
+ while read dep ; do
+ if echo $dep | grep -q "^${package}/" ; then
+ deps="$deps src/include/$dep"
+ elif test -f "${dir}/$dep" ; then
+ deps="$deps ${dir}/$dep"
+ else
+ deps="$deps src/include-local/$dep"
+ fi
+ done
+ o=$(echo $file | sed s/\\.c$/.o/)
+ lo=$(echo $file | sed s/\\.c$/.lo/)
+ echo "${dir}/${o} ${dir}/${lo}:${deps}"
+ }
+ done
+done
+echo
+
+for dir in $(ls -1 src | grep -v ^include) ; do
+ for file in $(ls -1 src/$dir/deps-lib) ; do
+ deps=
+ libs=
+ while read dep ; do
+ if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then
+ libs="$libs $dep"
+ else
+ deps="$deps src/$dir/$dep"
+ fi
+ done < src/$dir/deps-lib/$file
+ echo 'ifeq ($(strip $(STATIC_LIBS_ARE_PIC)),)'
+ echo "lib${file}.a.xyzzy:$deps"
+ echo else
+ echo "lib${file}.a.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')"
+ echo endif
+ echo "lib${file}.so.xyzzy: EXTRA_LIBS :=$libs"
+ echo "lib${file}.so.xyzzy:$(echo "$deps" | sed 's/\.o/.lo/g')"
+ done
+
+ for file in $(ls -1 src/$dir/deps-exe) ; do
+ deps=
+ libs=
+ while read dep ; do
+ if echo $dep | grep -q -- \\.o$ ; then
+ dep="src/$dir/$dep"
+ fi
+ if echo $dep | grep -q -e ^-l -e '^\${.*_LIB}' ; then
+ libs="$libs $dep"
+ else
+ deps="$deps $dep"
+ fi
+ done < src/$dir/deps-exe/$file
+ echo "$file: EXTRA_LIBS :=$libs"
+ echo "$file: src/$dir/$file.o$deps"
+ done
+done
diff --git a/tools/install.sh b/tools/install.sh
new file mode 100755
index 0000000..89f9428
--- /dev/null
+++ b/tools/install.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+
+usage() {
+ echo "usage: $0 [-D] [-l] [-m mode] src dst" 1>&2
+ exit 1
+}
+
+mkdirp=false
+symlink=false
+mode=0755
+
+while getopts Dlm: name ; do
+ case "$name" in
+ D) mkdirp=true ;;
+ l) symlink=true ;;
+ m) mode=$OPTARG ;;
+ ?) usage ;;
+ esac
+done
+shift $(($OPTIND - 1))
+
+test "$#" -eq 2 || usage
+src=$1
+dst=$2
+tmp="$dst.tmp.$$"
+
+case "$dst" in
+ */) echo "$0: $dst ends in /" 1>&2 ; exit 1 ;;
+esac
+
+set -C
+set -e
+
+if $mkdirp ; then
+ umask 022
+ case "$2" in
+ */*) mkdir -p "${dst%/*}" ;;
+ esac
+fi
+
+trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP
+
+umask 077
+
+if $symlink ; then
+ ln -s "$src" "$tmp"
+else
+ cat < "$1" > "$tmp"
+ chmod "$mode" "$tmp"
+fi
+
+mv -f "$tmp" "$dst"
+if test -d "$dst" ; then
+ rm -f "$dst/$(basename $tmp)"
+ if $symlink ; then
+ mkdir "$tmp"
+ ln -s "$src" "$tmp/$(basename $dst)"
+ mv -f "$tmp/$(basename $dst)" "${dst%/*}"
+ rmdir "$tmp"
+ else
+ echo "$0: $dst is a directory" 1>&2
+ exit 1
+ fi
+fi