чување 3d3422956bf187bda11c79044b3c299fee705622
родитељ 6a1ac0ee692f3b642f5f89be7586d20ad4e1d391
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Thu, 2 May 2024 23:50:16 +0200
Migrate to POSIX make from redo; switch manpage to mdoc(7)
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
измењених датотека: 35, додавања: 432(+), брисања: 765(-)
diff --git a/INSTALL b/INSTALL
@@ -1,13 +1,15 @@
Prerequisites
=============
-* C compiler - defaults in config.redo
+* C compiler - defaults in config.mk
-Optional
---------
+Testing
+-------
+
+* Perl ≥ 5.010
-* gzip (autodetected, for manpage compression)
+ $ make test
Install
@@ -16,33 +18,31 @@ Install
$ git clone https://git.sr.ht/~strahinja/ufold
$ cd ufold
$ su
-
-If you have djb redo:
-
- # redo install
-
-if you don't:
-
- # ./do install
+ # make install
Persistent build configuration file
-----------------------------------
-The file config.redo will be sourced when building targets which also accept
-configuration through environment variables. For example, CC and PREFIX
-are specified in config.redo.
+The file config.mk will be sourced when building targets which also accept
+configuration through environment variables. For example, CPPFLAGS and PREFIX
+are specified in config.mk.
OpenBSD
-------
-Replace gcc in CC with cc and add -D_BSD_SOURCE, eg:
+Before running make(1), comment the CPPFLAGS definition in config.mk above the
+line with the "OpenBSD" comment and uncomment the one below it:
- # CC='cc -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L
- -D_XOPEN_SOURCE=700 -D_BSD_SOURCE}' \
- ./do install
+ #CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \
+ # -D_XOPEN_SOURCE=700
+ # OpenBSD
+ CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \
+ -D_XOPEN_SOURCE=700 -D_BSD_SOURCE
-and change MANPREFIX to
+Also, do the same for MANPREFIX:
- MANPREFIX=$PREFIX/man
+ #MANPREFIX = $(DESTDIR)$(PREFIX)/share/man
+ # OpenBSD
+ MANPREFIX = $(DESTDIR)$(PREFIX)/man
diff --git a/Makefile b/Makefile
@@ -0,0 +1,66 @@
+.POSIX:
+
+include config.mk
+
+.SUFFIXES:
+.SUFFIXES: .1.in .1 .h.in .h .c .o
+
+.1.in.1:
+ sh lib/replacepat $< $@
+
+.h.in.h:
+ sh lib/replacepat $< $@
+
+all: makedate makeversion $(PROG) $(MANPAGE)
+ if [ -f .rebuild ]; then rm .rebuild; make -e all; else true; fi
+
+date:
+ sh lib/makedate
+
+version:
+ sh lib/makeversion
+
+makedate:
+ sh lib/makedate -l
+
+makeversion:
+ sh lib/makeversion -l
+
+ufold.o: ufold.c defs.h utf8.h version.h
+
+utf8.o: utf8.c defs.h utf8.h
+
+$(MANPAGE): $(MANPAGE).in date version
+
+version.h: version.h.in date version
+
+$(PROG): $(OBJS) $(SRC) $(HEADERS)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
+
+clean:
+ rm -f version date version.h *.o *.xz *~ $(PROG) $(MANPAGE)
+
+install: all
+ $(INSTALL) -Dm 0644 $(MANPAGE) $(MANPREFIX)/man1/$(MANPAGE)
+ $(INSTALL) -Dm 0644 README $(DOCDIR)/README
+ $(INSTALL) -Dm 0644 LICENSE $(DOCDIR)/LICENSE
+ $(INSTALL) -Dm 0755 $(PROG) $(BINDIR)/$(PROG)
+
+uninstall:
+ rm -f $(MANPREFIX)/man1/$(MANPAGE)
+ rmdir $(MANPREFIX)/man1 2>/dev/null || true
+ rmdir $(MANPREFIX) 2>/dev/null || true
+ rm -f $(DOCDIR)/README
+ rm -f $(DOCDIR)/LICENSE
+ rmdir $(DOCDIR) 2>/dev/null || true
+ rm -f $(PROG) $(BINDIR)/$(PROG)
+ rmdir $(BINDIR) 2>/dev/null || true
+
+test: all
+ command -v perl >/dev/null || { echo Test suite requires perl; exit 1; }
+ perl lib/runtests
+
+pack: all
+ sh -x lib/mkpack
+
+.PHONY: all clean install makedate makeversion pack uninstall
diff --git a/all.do b/all.do
@@ -1,2 +0,0 @@
-. ./config.redo
-redo-ifchange ufold ufold.1"$MANSUFFIX"
diff --git a/clean.do b/clean.do
@@ -1,2 +0,0 @@
-. ./config.redo
-rm -f *~ *.o ufold $MANPAGES *.1 version.h version date
diff --git a/config.mk b/config.mk
@@ -0,0 +1,22 @@
+#CC = cc
+CFLAGS = -Os -Wall -pedantic -std=c99
+CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \
+ -D_XOPEN_SOURCE=700
+# OpenBSD
+#CPPFLAGS = -D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L \
+# -D_XOPEN_SOURCE=700 -D_BSD_SOURCE
+INSTALL = install
+LIBS =
+SRC = ufold.c utf8.c
+HEADERS = defs.h utf8.h version.h
+OBJS = ufold.o utf8.o
+PREFIX = /usr/local
+PROG = ufold
+
+# Derived macros
+BINDIR = $(DESTDIR)$(PREFIX)/bin
+DOCDIR = $(DESTDIR)$(PREFIX)/share/doc/$(PROG)
+MANPREFIX = $(DESTDIR)$(PREFIX)/share/man
+# OpenBSD
+#MANPREFIX = $(DESTDIR)$(PREFIX)/man
+MANPAGE = $(PROG).1
diff --git a/config.redo b/config.redo
@@ -1,21 +0,0 @@
-PREFIX=${PREFIX:-/usr/local}
-
-BINDIR=$PREFIX/bin
-DOCDIR=$PREFIX/share/doc/ufold
-MANPREFIX=$PREFIX/share/man
-
-# OpenBSD
-#MANPREFIX=$PREFIX/man
-
-PROGS="ufold"
-DOCS="README LICENSE"
-MANSUFFIX=${MANSUFFIX-$(command -v gzip >/dev/null && printf ".gz")}
-MANPAGES="ufold.1${MANSUFFIX}"
-
-CC=${CC:-gcc -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L \
--D_XOPEN_SOURCE=700}
-STRIP=${STRIP:-:}
-
-# OpenBSD
-#CC=${CC:-cc -g -Wall -pedantic -std=c99 -D_POSIX_C_SOURCE=200809L \
-#-D_XOPEN_SOURCE=700 -D_BSD_SOURCE}
diff --git a/date.do b/date.do
@@ -1,20 +0,0 @@
-FALLBACKDATE=${FALLBACKDATE:-unknown}
-LC_ALL=C
-export LC_ALL
-user=$(unalias ls >/dev/null 2>&1 || true; \
- command ls -ld . | awk '{print $3}')
-e_user=$(id -un)
-if [ -d .git ] && command -v git >/dev/null 2>&1; then
- if [ "$e_user" = "$user" ]; then
- git log --format=format:%cd \
- --date=format:"%B %d, %Y" -1 @ >$3
- else
- su "${user}" -c 'env LC_ALL=C git log --format=format:%cd \
- --date=format:"%B %d, %Y" -1 @' >$3
- fi
- echo >>$3
-else
- printf "%s\n" "$FALLBACKDATE" >$3
-fi
-redo-always
-redo-stamp <$3
diff --git a/default.do b/default.do
@@ -1,10 +0,0 @@
-if [ -r $1.in ]; then
- redo-ifchange $1.in version date
- read VERSION <version
- read DATE <date
- sed -e "s/%VERSION%/$VERSION/g" \
- -e "s/%DATE%/$DATE/g" <$1.in
-else
- echo "$0: don't know how to build '$1'" >&2
- exit 99
-fi
diff --git a/default.gz.do b/default.gz.do
@@ -1,3 +0,0 @@
-redo-ifchange $2
-gzip -cf $2 >$3
-
diff --git a/default.o.do b/default.o.do
@@ -1,5 +0,0 @@
-. ./config.redo
-sed -n 's/^#include "\([^"]*\)"/\1/p' ${2%.o}.c |
- xargs redo-ifchange
-redo-ifchange $2.c
-${CC} -c $2.c -o $3
diff --git a/defs.h b/defs.h
@@ -1,5 +1,5 @@
/* This program is licensed under the terms of GNU GPL v3 or (at your option)
- * any later version. Copyright (C) 2021-2023 Страхиња Радић.
+ * any later version. Copyright (C) 2021-2024 Страхиња Радић.
* See the file LICENSE for exact copyright and license details. */
#define MAXBUF 1024
diff --git a/do b/do
@@ -1,446 +0,0 @@
-#!/usr/bin/env sh
-#
-# A minimal alternative to djb redo that doesn't support incremental builds.
-# For the full version, visit http://github.com/apenwarr/redo
-#
-# The author disclaims copyright to this source file and hereby places it in
-# the public domain. (2010 12 14; updated 2019 02 24)
-#
-USAGE="
-usage: do [-d] [-x] [-v] [-c] <targets...>
- -d print extra debug messages (mostly about dependency checks)
- -v run .do files with 'set -v'
- -x run .do files with 'set -x'
- -c clean up all old targets before starting
-
- Note: do is an implementation of redo that does *not* check dependencies.
- It will never rebuild a target it has already built, unless you use -c.
-"
-
-# CDPATH apparently causes unexpected 'cd' output on some platforms.
-unset CDPATH
-
-# By default, no output coloring.
-green=""
-bold=""
-plain=""
-
-if [ -n "$TERM" -a "$TERM" != "dumb" ] && tty <&2 >/dev/null 2>&1; then
- green="$(printf '\033[32m')"
- bold="$(printf '\033[1m')"
- plain="$(printf '\033[m')"
-fi
-
-# The 'seq' command is not available on all platforms.
-_seq() {
- local x=0 max="$1"
- while [ "$x" -lt "$max" ]; do
- x=$((x + 1))
- echo "$x"
- done
-}
-
-# Split $1 into a dir part ($_dirsplit_dir) and base filename ($_dirsplit_base)
-_dirsplit() {
- _dirsplit_base=${1##*/}
- _dirsplit_dir=${1%$_dirsplit_base}
-}
-
-# Like /usr/bin/dirname, but avoids a fork and uses _dirsplit semantics.
-qdirname() (
- _dirsplit "$1"
- dir=${_dirsplit_dir%/}
- echo "${dir:-.}"
-)
-
-_dirsplit "$0"
-REDO=$(cd "$(pwd -P)" &&
- cd "${_dirsplit_dir:-.}" &&
- echo "$PWD/$_dirsplit_base")
-export REDO
-_cmd=$_dirsplit_base
-
-DO_TOP=
-if [ -z "$DO_BUILT" ]; then
- export _do_opt_debug=
- export _do_opt_exec=
- export _do_opt_verbose=
- export _do_opt_clean=
-fi
-while getopts 'dxvcj:h?' _opt; do
- case $_opt in
- d) _do_opt_debug=1 ;;
- x) _do_opt_exec=x ;;
- v) _do_opt_verbose=v ;;
- c) _do_opt_clean=1 ;;
- j) ;; # silently ignore, for compat with real redo
- \?|h|*) printf "%s" "$USAGE" >&2
- exit 99
- ;;
- esac
-done
-shift "$((OPTIND - 1))"
-_debug() {
- [ -z "$_do_opt_debug" ] || echo "$@" >&2
-}
-
-if [ -z "$DO_BUILT" -a "$_cmd" != "redo-whichdo" ]; then
- DO_TOP=1
- if [ "$#" -eq 0 ] && [ "$_cmd" = "do" -o "$_cmd" = "redo" ]; then
- set all # only toplevel redo has a default target
- fi
- export DO_STARTDIR="$(pwd -P)"
- # If starting /bin/pwd != $PWD, this will fix it.
- # That can happen when $PWD contains symlinks that the shell is
- # trying helpfully (but unsuccessfully) to hide from the user.
- cd "$DO_STARTDIR" || exit 99
- export DO_BUILT="$PWD/.do_built"
- if [ -z "$_do_opt_clean" -a -e "$DO_BUILT" ]; then
- echo "do: Incremental mode. Use -c for clean rebuild." >&2
- fi
- : >>"$DO_BUILT"
- sort -u "$DO_BUILT" >"$DO_BUILT.new"
- while read f; do
- [ -n "$_do_opt_clean" ] && printf "%s\0%s.did\0" "$f" "$f"
- printf "%s.did.tmp\0" "$f"
- done <"$DO_BUILT.new" |
- xargs -0 rm -f 2>/dev/null
- mv "$DO_BUILT.new" "$DO_BUILT"
- export DO_PATH="$DO_BUILT.dir"
- export PATH="$DO_PATH:$PATH"
- rm -rf "$DO_PATH"
- mkdir "$DO_PATH"
- for d in redo redo-ifchange redo-whichdo; do
- ln -s "$REDO" "$DO_PATH/$d"
- done
- for d in redo-ifcreate redo-stamp redo-always redo-ood \
- redo-targets redo-sources; do
- echo "#!/bin/sh" >"$DO_PATH/$d"
- chmod a+rx "$DO_PATH/$d"
- done
-fi
-
-
-# Chop the "file" part off a /path/to/file pathname.
-# Note that if the filename already ends in a /, we just remove the slash.
-_updir()
-{
- local v="${1%/*}"
- [ "$v" != "$1" ] && echo "$v"
- # else "empty" which means we went past the root
-}
-
-
-# Returns true if $1 starts with $2.
-_startswith()
-{
- [ "${1#"$2"}" != "$1" ]
-}
-
-
-# Returns true if $1 ends with $2.
-_endswith()
-{
- [ "${1%"$2"}" != "$1" ]
-}
-
-
-# Prints $1 if it's absolute, or $2/$1 if $1 is not absolute.
-_abspath()
-{
- local here="$2" there="$1"
- if _startswith "$1" "/"; then
- echo "$1"
- else
- echo "$2/$1"
- fi
-}
-
-
-# Prints $1 as a path relative to $PWD (not starting with /).
-# If it already doesn't start with a /, doesn't change the string.
-_relpath()
-{
- local here="$2" there="$1" out= hadslash=
- #echo "RP start '$there' hs='$hadslash'" >&2
- _startswith "$there" "/" || { echo "$there" && return; }
- [ "$there" != "/" ] && _endswith "$there" "/" && hadslash=/
- here=${here%/}/
- while [ -n "$here" ]; do
- #echo "RP out='$out' here='$here' there='$there'" >&2
- [ "${here%/}" = "${there%/}" ] && there= && break;
- [ "${there#$here}" != "$there" ] && break
- out=../$out
- _dirsplit "${here%/}"
- here=$_dirsplit_dir
- done
- there=${there#$here}
- if [ -n "$there" ]; then
- echo "$out${there%/}$hadslash"
- else
- echo "${out%/}$hadslash"
- fi
-}
-
-
-# Prints a "normalized relative" path, with ".." resolved where possible.
-# For example, a/b/../c will be reduced to just a/c.
-_normpath()
-(
- local path="$1" relto="$2" out= isabs=
- #echo "NP start '$path'" >&2
- if _startswith "$path" "/"; then
- isabs=1
- else
- path="${relto%/}/$path"
- fi
- set -f
- IFS=/
- for d in ${path%/}; do
- #echo "NP out='$out' d='$d'" >&2
- if [ "$d" = ".." ]; then
- out=$(_updir "${out%/}")/
- else
- out=$out$d/
- fi
- done
- #echo "NP out='$out' (done)" >&2
- out=${out%/}
- if [ -n "$isabs" ]; then
- echo "${out:-/}"
- else
- _relpath "${out:-/}" "$relto"
- fi
-)
-
-
-# Prints a "real" path, with all symlinks resolved where possible.
-_realpath()
-{
- local path="$1" relto="$2" isabs= rest=
- if _startswith "$path" "/"; then
- isabs=1
- else
- path="${relto%/}/$path"
- fi
- (
- for d in $(_seq 100); do
- #echo "Trying: $PWD--$path" >&2
- if cd -P "$path" 2>/dev/null; then
- # success
- pwd=$(pwd -P)
- #echo " chdir ok: $pwd--$rest" >&2
- np=$(_normpath "${pwd%/}/$rest" "$relto")
- if [ -n "$isabs" ]; then
- echo "$np"
- else
- _relpath "$np" "$relto"
- fi
- break
- fi
- _dirsplit "${path%/}"
- path=$_dirsplit_dir
- rest="$_dirsplit_base/$rest"
- done
- )
-}
-
-
-# List the possible names for default*.do files in dir $1 matching the target
-# pattern in $2. We stop searching when we find the first one that exists.
-_find_dofiles_pwd()
-{
- local dodir="$1" dofile="$2"
- _startswith "$dofile" "default." || dofile=${dofile#*.}
- while :; do
- dofile=default.${dofile#default.*.}
- echo "$dodir$dofile"
- [ -e "$dodir$dofile" ] && return 0
- [ "$dofile" = default.do ] && break
- done
- return 1
-}
-
-
-# List the possible names for default*.do files in $PWD matching the target
-# pattern in $1. We stop searching when we find the first name that works.
-# If there are no matches in $PWD, we'll search in .., and so on, to the root.
-_find_dofiles()
-{
- local target="$1" dodir= dofile= newdir=
- _debug "find_dofile: '$PWD' '$target'"
- dofile="$target.do"
- echo "$dofile"
- [ -e "$dofile" ] && return 0
-
- # Try default.*.do files, walking up the tree
- _dirsplit "$dofile"
- dodir=$_dirsplit_dir
- dofile=$_dirsplit_base
- [ -n "$dodir" ] && dodir=${dodir%/}/
- [ -e "$dodir$dofile" ] && return 0
- for i in $(_seq 100); do
- [ -n "$dodir" ] && dodir=${dodir%/}/
- #echo "_find_dofiles: '$dodir' '$dofile'" >&2
- _find_dofiles_pwd "$dodir" "$dofile" && return 0
- newdir=$(_realpath "${dodir}.." "$PWD")
- [ "$newdir" = "$dodir" ] && break
- dodir=$newdir
- done
- return 1
-}
-
-
-# Print the last .do file returned by _find_dofiles.
-# If that file exists, returns 0, else 1.
-_find_dofile()
-{
- local files="$(_find_dofiles "$1")"
- rv=$?
- #echo "files='$files'" >&2
- [ "$rv" -ne 0 ] && return $rv
- echo "$files" | {
- while read -r linex; do line=$linex; done
- printf "%s\n" "$line"
- }
-}
-
-
-# Actually run the given $dofile with the arguments in $@.
-# Note: you should always run this in a subshell.
-_run_dofile()
-{
- export DO_DEPTH="$DO_DEPTH "
- export REDO_TARGET="$PWD/$target"
- local line1
- set -e
- read line1 <"$PWD/$dofile" || true
- cmd=${line1#"#!/"}
- if [ "$cmd" != "$line1" ]; then
- set -$_do_opt_verbose$_do_opt_exec
- exec /$cmd "$PWD/$dofile" "$@"
- else
- set -$_do_opt_verbose$_do_opt_exec
- # If $dofile is empty, "." might not change $? at
- # all, so we clear it first with ":".
- :; . "$PWD/$dofile"
- fi
-}
-
-
-# Find and run the right .do file, starting in dir $1, for target $2,
-# providing a temporary output file as $3. Renames the temp file to $2 when
-# done.
-_do()
-{
- local dir="$1" target="$1$2" tmp="$1$2.redo.tmp" tdir=
- local dopath= dodir= dofile= ext=
- if [ "$_cmd" = "redo" ] ||
- ( [ ! -e "$target" -o -d "$target" ] &&
- [ ! -e "$target.did" ] ); then
- printf '%sdo %s%s%s%s\n' \
- "$green" "$DO_DEPTH" "$bold" "$target" "$plain" >&2
- dopath=$(_find_dofile "$target")
- if [ ! -e "$dopath" ]; then
- echo "do: $target: no .do file ($PWD)" >&2
- return 1
- fi
- _dirsplit "$dopath"
- dodir=$_dirsplit_dir dofile=$_dirsplit_base
- if _startswith "$dofile" "default."; then
- ext=${dofile#default}
- ext=${ext%.do}
- else
- ext=
- fi
- target=$PWD/$target
- tmp=$PWD/$tmp
- cd "$dodir" || return 99
- target=$(_relpath "$target" "$PWD") || return 98
- tmp=$(_relpath "$tmp" "$PWD") || return 97
- base=${target%$ext}
- tdir=$(qdirname "$target")
- [ ! -e "$DO_BUILT" ] || [ ! -w "$tdir/." ] ||
- : >>"$target.did.tmp"
- # $qtmp is a temporary file used to capture stdout.
- # Since it might be accidentally deleted as a .do file
- # does its work, we create it, then open two fds to it,
- # then immediately delete the name. We use one fd to
- # redirect to stdout, and the other to read from after,
- # because there's no way to fseek(fd, 0) in sh.
- qtmp=$DO_PATH/do.$$.tmp
- (
- rm -f "$qtmp"
- ( _run_dofile "$target" "$base" "$tmp" >&3 3>&- 4<&- )
- rv=$?
- if [ $rv != 0 ]; then
- printf "do: %s%s\n" "$DO_DEPTH" \
- "$target: got exit code $rv" >&2
- rm -f "$tmp.tmp" "$tmp.tmp2" "$target.did"
- return $rv
- fi
- echo "$PWD/$target" >>"$DO_BUILT"
- if [ ! -e "$tmp" ]; then
- # if $3 wasn't created, copy from stdout file
- cat <&4 >$tmp
- # if that's zero length too, forget it
- [ -s "$tmp" ] || rm -f "$tmp"
- fi
- ) 3>$qtmp 4<$qtmp # can't use "|| return" here...
- # ...because "|| return" would mess up "set -e" inside the ()
- # on some shells. Running commands in "||" context, even
- # deep inside, will stop "set -e" from functioning.
- rv=$?
- [ "$rv" = 0 ] || return "$rv"
- mv "$tmp" "$target" 2>/dev/null
- [ -e "$target.did.tmp" ] &&
- mv "$target.did.tmp" "$target.did" ||
- : >>"$target.did"
- else
- _debug "do $DO_DEPTH$target exists." >&2
- fi
-}
-
-
-# Implementation of the "redo" command.
-_redo()
-{
- local i startdir="$PWD" dir base
- set +e
- for i in "$@"; do
- i=$(_abspath "$i" "$startdir")
- (
- cd "$DO_STARTDIR" || return 99
- i=$(_realpath "$(_relpath "$i" "$PWD")" "$PWD")
- _dirsplit "$i"
- dir=$_dirsplit_dir base=$_dirsplit_base
- _do "$dir" "$base"
- )
- [ "$?" = 0 ] || return 1
- done
-}
-
-
-# Implementation of the "redo-whichdo" command.
-_whichdo()
-{
- _find_dofiles "$1"
-}
-
-
-case $_cmd in
- do|redo|redo-ifchange) _redo "$@" ;;
- redo-whichdo) _whichdo "$1" ;;
- do.test) ;;
- *) printf "do: '%s': unexpected redo command" "$_cmd" >&2; exit 99 ;;
-esac
-[ "$?" = 0 ] || exit 1
-
-if [ -n "$DO_TOP" ]; then
- if [ -n "$_do_opt_clean" ]; then
- echo "do: Removing stamp files..." >&2
- [ ! -e "$DO_BUILT" ] ||
- while read f; do printf "%s.did\0" "$f"; done <"$DO_BUILT" |
- xargs -0 rm -f 2>/dev/null
- fi
-fi
diff --git a/do-test b/do-test
@@ -1,41 +0,0 @@
-#!/bin/sh
-
-printf "Test 1 - normal:\t"
-fold -w 20 test1.txt > f.out
-ufold -w 20 test1.txt > uf.out
-if diff f.out uf.out 2>/dev/null >/dev/null; then
- echo PASS
-else
- echo FAIL
-fi
-rm -f f.out uf.out
-
-printf "Test 1 - spaces:\t"
-fold -w 20 -s test1.txt > f.out
-ufold -w 20 -s test1.txt > uf.out
-if diff f.out uf.out 2>/dev/null >/dev/null; then
- echo PASS
-else
- echo FAIL
-fi
-rm -f f.out uf.out
-
-printf "Test 2 - normal:\t"
-fold -w 20 test2.txt > f.out
-ufold -w 20 test2.txt > uf.out
-if diff f.out uf.out 2>/dev/null >/dev/null; then
- echo PASS
-else
- echo FAIL
-fi
-rm -f f.out uf.out
-
-printf "Test 2 - spaces:\t"
-fold -w 20 -s test2.txt > f.out
-ufold -w 20 -s test2.txt > uf.out
-if diff f.out uf.out 2>/dev/null >/dev/null; then
- echo PASS
-else
- echo FAIL
-fi
-rm -f f.out uf.out
diff --git a/install.do b/install.do
@@ -1,12 +0,0 @@
-redo-ifchange all
-. ./config.redo
-install -d "$DOCDIR" "$BINDIR" "${MANPREFIX}/man1"
-for docfile in $DOCS; do
- install -Dm 0644 "${docfile}" "${DOCDIR}/${docfile}"
-done
-for binfile in $PROGS; do
- install -Dm 0755 "${binfile}" "${BINDIR}/${binfile}"
-done
-for manfile in $MANPAGES; do
- install -Dm 0644 "${manfile}" "${MANPREFIX}/man1/${manfile}"
-done
diff --git a/lib/makedate b/lib/makedate
@@ -0,0 +1,35 @@
+#!/bin/sh -x
+# vim: set ft=bash:
+FALLBACKDATE=${FALLBACKDATE:-unknown}
+LC_ALL=C
+export LC_ALL
+user=$(unalias ls >/dev/null 2>&1 || true; \
+ command ls -ld . | awk '{print $3}')
+e_user=$(id -un)
+if [ -d .git ] && command -v git >/dev/null 2>&1; then
+ if [ "$e_user" = "$user" ]; then
+ git log --format=format:%cd \
+ --date=format:"%B %d, %Y" -1 @ >date.new
+ else
+ su "${user}" -c 'env LC_ALL=C git log --format=format:%cd \
+ --date=format:"%B %d, %Y" -1 @' >date.new
+ fi
+ echo >>date.new
+else
+ printf "%s\n" "$FALLBACKDATE" >date.new
+fi
+
+if [ -f date ]; then
+ if diff date date.new >/dev/null; then
+ rm date.new
+ else
+ mv date.new date
+ touch .rebuild
+ fi
+else
+ mv date.new date
+ touch .rebuild
+fi
+if [ "$1" = "-l" ]; then
+ printf "DATE=\"%s\"\n" "$(cat date)"
+fi
diff --git a/lib/makeversion b/lib/makeversion
@@ -0,0 +1,33 @@
+#!/bin/sh -x
+# vim: set ft=bash:
+FALLBACKVER=${FALLBACKVER:-unknown}
+LC_ALL=C
+export LC_ALL
+user=$(unalias ls >/dev/null 2>&1 || true; \
+ command ls -ld . | awk '{print $3}')
+e_user=$(id -un)
+if [ -d .git ] && command -v git >/dev/null 2>&1; then
+ if [ "$e_user" = "$user" ]; then
+ git describe 2>/dev/null | sed 's/^v//' >version.new
+ else
+ su "${user}" -c 'git describe' 2>/dev/null |
+ sed 's/^v//' >version.new
+ fi
+else
+ printf "%s\n" "$FALLBACKVER" >version.new
+fi
+
+if [ -f version ]; then
+ if diff version version.new >/dev/null; then
+ rm version.new
+ else
+ mv version.new version
+ touch .rebuild
+ fi
+else
+ mv version.new version
+ touch .rebuild
+fi
+if [ "$1" = "-l" ]; then
+ printf "VERSION=\"%s\"\n" "$(cat version)"
+fi
diff --git a/lib/mkpack b/lib/mkpack
@@ -0,0 +1,12 @@
+#!/bin/sh -x
+# vim: set ft=bash:
+DISTDIR=$(grep ^PROG config.mk |
+ sed -E 's,.*=[[:space:]]+([[:alpha:]]+),\1,')-$(cat version)
+mkdir "$DISTDIR"
+for f in $(git ls-files); do
+ d="$DISTDIR"/"$(dirname "$f")"
+ mkdir -p "$d"
+ cp "$f" "$d"/
+done
+tar -cf - "$DISTDIR" | xz -9v - > "$DISTDIR".tar.xz
+rm -fr "$DISTDIR"
diff --git a/lib/replacepat b/lib/replacepat
@@ -0,0 +1,5 @@
+#!/bin/sh -x
+# vim: set ft=bash:
+DATE=$(cat date)
+VERSION=$(cat version)
+sed -e 's|%VERSION%|'"$VERSION"'|g' -e 's|%DATE%|'"$DATE"'|g' "$1" > "$2"
diff --git a/lib/runtests b/lib/runtests
@@ -0,0 +1,57 @@
+#!/usr/bin/perl
+# This program is licensed under the terms of GNU GPL v3 or (at your option)
+# any later version. Copyright (C) 2021-2024 Страхиња Радић.
+# See the file LICENSE for exact copyright and license details.
+
+
+use 5.010;
+use File::Find;
+
+my $errors = 0;
+my @files;
+my $maxlen = 60;
+my $testdir = 'tests';
+
+#system("sh -c 'command -v expect' >/dev/null") == 0 ||
+# die "Test suite requires expect";
+
+find(sub {
+ push @files, $File::Find::name if (/\.test$/);
+}, $testdir . "/");
+
+for (@files)
+{
+ system $_;
+ $results{$_} = $?>>8;
+}
+
+# Clear the screen
+#print "\033[0m\033[2J\033[2K\033[1;1H";
+
+print <<"!";
+TEST RESULTS
+============================================================
+!
+
+for (@files)
+{
+ printf "%s:%*s%s\t%s\n", $_, $maxlen-5-length($_), " ",
+ $results{$_} == 0 ? " OK" : "FAIL";
+ if ($results{$_})
+ {
+ $errors = 1;
+ }
+}
+
+if ($errors == 1)
+{
+ printf "Some tests were unsuccessful - please report\n";
+}
+else
+{
+ printf "All tests passed\n";
+}
+
+print <<"!";
+============================================================
+!
diff --git a/pack.do b/pack.do
@@ -1,10 +0,0 @@
-redo all
-redo-ifchange version
-read VERSION <version
-VERSION=$(echo $VERSION | sed 's/^v//')
-DISTDIR=ufold-$VERSION
-mkdir $DISTDIR
-cp *.c *.h *.do README LICENSE $DISTDIR
-tar cvf $DISTDIR.tar.xz $DISTDIR >/dev/null
-rm -fr $DISTDIR
-
diff --git a/rebuild.do b/rebuild.do
@@ -1,2 +0,0 @@
-redo clean all
-
diff --git a/test.do b/test.do
@@ -1 +0,0 @@
-./do-test >&2
diff --git a/tests/001-generic.test b/tests/001-generic.test
@@ -0,0 +1,16 @@
+#!/bin/sh
+# vim: set ft=bash:
+exec 2>/dev/null
+testfile=tests/test1.txt
+outfile1=tests/t001.out
+outfile2=tests/t001-u.out
+
+fold -w 20 "$testfile" > "$outfile1"
+./ufold -w 20 "$testfile" > "$outfile2"
+if diff "$outfile1" "$outfile2" 2>/dev/null >&2; then
+ result=0
+else
+ result=1
+fi
+rm -f "$outfile1" "$outfile2"
+exit "$result"
diff --git a/tests/002-spaces.test b/tests/002-spaces.test
@@ -0,0 +1,16 @@
+#!/bin/sh
+# vim: set ft=bash:
+exec 2>/dev/null
+testfile=tests/test1.txt
+outfile1=tests/t002.out
+outfile2=tests/t002-u.out
+
+fold -w 20 -s "$testfile" > "$outfile1"
+./ufold -w 20 -s "$testfile" > "$outfile2"
+if diff "$outfile1" "$outfile2" 2>/dev/null >&2; then
+ result=0
+else
+ result=1
+fi
+rm -f "$outfile1" "$outfile2"
+exit "$result"
diff --git a/tests/003-generic.test b/tests/003-generic.test
@@ -0,0 +1,16 @@
+#!/bin/sh
+# vim: set ft=bash:
+exec 2>/dev/null
+testfile=tests/test2.txt
+outfile1=tests/t003.out
+outfile2=tests/t003-u.out
+
+fold -w 20 "$testfile" > "$outfile1"
+./ufold -w 20 "$testfile" > "$outfile2"
+if diff "$outfile1" "$outfile2" 2>/dev/null >&2; then
+ result=0
+else
+ result=1
+fi
+rm -f "$outfile1" "$outfile2"
+exit "$result"
diff --git a/tests/004-spaces.test b/tests/004-spaces.test
@@ -0,0 +1,16 @@
+#!/bin/sh
+# vim: set ft=bash:
+exec 2>/dev/null
+testfile=tests/test2.txt
+outfile1=tests/t004.out
+outfile2=tests/t004-u.out
+
+fold -w 20 -s "$testfile" > "$outfile1"
+./ufold -w 20 -s "$testfile" > "$outfile2"
+if diff "$outfile1" "$outfile2" 2>/dev/null >&2; then
+ result=0
+else
+ result=1
+fi
+rm -f "$outfile1" "$outfile2"
+exit "$result"
diff --git a/test1.txt b/tests/test1.txt
diff --git a/test2.txt b/tests/test2.txt
diff --git a/ufold.1.in b/ufold.1.in
@@ -1,85 +1,55 @@
-'\" t
-.\" Manpage for ufold(1)
-.\" vim: set filetype=groff:
-.
-.mso an-ext.tmac
-.de CDS
-.EX
-.RS \\$1
-.sp 1
-..
-.de CDE
-.sp 1
-.RE
-.EE
-..
-.de RDS
-.RS \\$1
-.sp 1
-..
-.de RDE
-.sp 1
-.RE
-..
-.
-.TH UFOLD "1" "%DATE%" "text-tools" "General Commands Manual"
-.SH NAME
-ufold \- wrap each UTF-8 input line to fit specified width
-.
-.SH SYNOPSIS
-.
-.SY ufold
-.OP "\-h \fR|\fP \-\-help"
-.YS
-.
-.SY ufold
-.OP "\-v \fR|\fP \-\-version"
-.YS
-.
-.SY ufold
-.OP "\-s \fR|\fP \-\-spaces"
-.OP "\-w \fR|\fP \-\-width=\fIwidth\fP"
-.RI [ file ]
-.YS
-.
-.SH COPYRIGHT
-.
-.LP
-ufold Copyright \(co 2021\-2023 Strahinya Radich.
-.br
-This program is licensed under GNU GPL v3 or later. See the file
-.I LICENSE
-in the ufold repository for details.
-.SH DESCRIPTION
-.
-.LP
-.B ufold
-wraps input lines in
-.IR file ,
-writing to standard output. It is a version of a program
-.BR fold (1)
-from the GNU coreutils which supports input encoded in UTF-8.
-.
-.LP
-If a special filename of \[lq]\-\[rq] is given,
-.B ufold
-will instead read from the standard input. This also happens when no filename is
-given.
-.
-.SH AUTHOR
-.
-Strahinya Radich,
-.UR https://\:strahinja.org
-.UE
-.
-.SH BUGS
-.
-.LP
+.\" This program is licensed under the terms of GNU GPL v3 or (at your option)
+.\" any later version. Copyright (C) 2021-2024 Страхиња Радић.
+.\" See the file LICENSE for exact copyright and license details.
+.Dd %DATE%
+.Dt UFOLD 1
+.Os
+.Sh NAME
+.Nm ufold
+.Nd wrap each UTF-8 input line to fit specified width
+.Sh SYNOPSIS
+.Nm
+.Fl h | Fl \-help | Fl V | Fl \-full\-version | Fl v | Fl \-version
+.Nm
+.Oo Fl s | Fl \-spaces Oc
+.Oo Fl w Ar width | Fl \-width= Ns Ar width Oc
+.Op Ar file
+.Sh DESCRIPTION
+.Nm
+wraps input lines in
+.Ar file ,
+writing to standard output.
+It emulates the program
+.Xr fold 1
+from the GNU coreutils, but adding support for input encoded in UTF-8.
+.Pp
+If a special
+.Ar file
+of
+.Dq \-
+is given,
+.Nm
+will instead read from the standard input.
+This also happens when no filename is given.
+.Bl -tag -width Ds
+.It Fl h | Fl \-help
+Print usage information.
+.It Fl s | Fl \-spaces
+Don't break words in the middle of a word.
+.It Fl V | Fl \-full\-version
+Print full version (like
+.Fl v Ns
+), followed by copyright notice.
+.It Fl v | Fl \-version
+Print program version and commit date.
+.It Fl w Ar width | Fl \-width= Ns Ar width
+Set output width in glyphs.
+.El
+.Sh "SEE ALSO"
+.Xr fold 1
+.Sh AUTHORS
+.An "Strahinya Radich" Aq contact@strahinja.org ,
+2021\-2024
+.Sh BUGS
Bugs can be reported using the ticket tracker at:
-.UR https://\:todo.sr.ht/\:~strahinja/\:text-tools
-.UE
-.
-.SH "SEE ALSO"
-.
-.BR fold (1)
-
+.Lk https://\:todo.sr.ht/\:~strahinja/\:text-tools
diff --git a/ufold.c b/ufold.c
@@ -1,5 +1,5 @@
/* This program is licensed under the terms of GNU GPL v3 or (at your option)
- * any later version. Copyright (C) 2021-2023 Страхиња Радић.
+ * any later version. Copyright (C) 2021-2024 Страхиња Радић.
* See the file LICENSE for exact copyright and license details. */
#include <errno.h>
@@ -13,13 +13,21 @@
#include "utf8.h"
#include "version.h"
+#define COPYRIGHT \
+ (" This program is licensed under the terms of GNU GPL v3" \
+ " or (at your option)\n" \
+ " any later version. Copyright (C) 2021-2024 Strahinya Radich.\n" \
+ " See the file LICENSE for exact copyright and license " \
+ "details.")
+
char filename[MAXPATH];
int
-usage()
+usage(void)
{
- printf("Usage: %s [-h|--help] [-s|--spaces] [-v|--version] "
- "[-w|--width=<COLS>] [FILE]\n", PROGRAMNAME);
+ printf("Usage:\t%s -h | --help | -V | --full-version | -v | --version\n"
+ "\t%s [-s | --spaces] [-w | --width=<cols>] [file]\n",
+ PROGRAMNAME, PROGRAMNAME);
return 0;
}
@@ -31,19 +39,21 @@ error(const int code, const char* fmt, ...)
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
- fprintf(stderr, "%s:%s: %s\n", PROGRAMNAME,
- *filename ? filename : "(stdin)", buf);
+ fprintf(stderr, "%s:%s: %s\n", PROGRAMNAME,
+ *filename ? filename : "(stdin)", buf);
return code;
}
int
-version()
+version(const int full)
{
printf("%s %s, built on %s\n", PROGRAMNAME, VERSION, DATE);
+ if (full)
+ puts(COPYRIGHT);
return 0;
}
-int
+int
starts_with(const char* s, const char* with)
{
while (*s && *s == *with)
@@ -63,7 +73,7 @@ fold_line_spaces(const u8* line, const int width)
return;
/*
- * Idea:
+ * Idea:
* 1. store characters in token until line is exhausted
* 2. when ' ' or end of line is encountered:
* 2,1, if token length > width, see if current column is 0:
@@ -77,14 +87,14 @@ fold_line_spaces(const u8* line, const int width)
* 3. go to 1. unless line is exhausted
*/
const u8* pline = line;
- u32 uch = 0;
+ u32 uch = 0;
u32 token[MAXINPUTBUF];
u32* ptoken = NULL;
u8 u8ch[7];
size_t u8ch_len = 0;
- size_t delta = 0;
- size_t len = 0;
- size_t col = 0;
+ size_t delta = 0;
+ size_t len = 0;
+ size_t col = 0;
*token = 0;
ptoken = token;
@@ -100,7 +110,6 @@ fold_line_spaces(const u8* line, const int width)
/* 2. */
if (uch == (u32)L' ' || !uch)
{
-
if (ptoken - token > width)
{
/* 2.1. */
@@ -113,11 +122,11 @@ fold_line_spaces(const u8* line, const int width)
/* 2.1.2. */
*ptoken = 0;
- ptoken = token;
+ ptoken = token;
while (*ptoken)
{
- u8ch_len = u32_char_to_u8(u8ch,
- *ptoken);
+ u8ch_len
+ = u32_char_to_u8(u8ch, *ptoken);
if (!u8ch_len)
return;
u8ch[u8ch_len] = 0;
@@ -155,11 +164,11 @@ fold_line_spaces(const u8* line, const int width)
/* 2.2.2. */
*ptoken = 0;
- ptoken = token;
+ ptoken = token;
while (*ptoken)
{
- u8ch_len = u32_char_to_u8(u8ch,
- *ptoken);
+ u8ch_len
+ = u32_char_to_u8(u8ch, *ptoken);
if (!u8ch_len)
return;
u8ch[u8ch_len] = 0;
@@ -190,14 +199,14 @@ fold_line_normal(const u8* line, const int width)
if (!line)
return;
- const u8* pline = line;
+ const u8* pline = line;
const u8* pline_inner = NULL;
u32 uch;
u8 u8_char[7];
u8* pu8_char = NULL;
size_t uch_len;
size_t delta = 0;
- size_t col = 0;
+ size_t col = 0;
while (*pline)
{
@@ -207,7 +216,7 @@ fold_line_normal(const u8* line, const int width)
return;
pline_inner = pline;
- pu8_char = u8_char;
+ pu8_char = u8_char;
while (*pline_inner && pline_inner < pline + uch_len)
*pu8_char++ = *pline_inner++;
*pu8_char = 0;
@@ -236,12 +245,12 @@ fold_line_normal(const u8* line, const int width)
int
main(int argc, char** argv)
{
- int argn = 1;
- char* carg = NULL;
- char** earg = NULL;
- int spaces = 0;
- int in_width = 0;
- long width = 80;
+ int argn = 1;
+ char* carg = NULL;
+ char** earg = NULL;
+ int spaces = 0;
+ int in_width = 0;
+ long width = 80;
char width_buf[MAXBUF];
*filename = 0;
@@ -252,8 +261,10 @@ main(int argc, char** argv)
spaces = 1;
else if (!strcmp(carg, "-h") || !strcmp(carg, "--help"))
return usage();
+ else if (!strcmp(carg, "-V") || !strcmp(carg, "--full-version"))
+ return version(1);
else if (!strcmp(carg, "-v") || !strcmp(carg, "--version"))
- return version();
+ return version(0);
else if (!strcmp(carg, "-w"))
in_width = 1;
else if (starts_with(carg, "--width="))
@@ -261,29 +272,34 @@ main(int argc, char** argv)
char* pcarg = carg + strlen("--width=");
strncpy(width_buf, pcarg, MAXBUF);
errno = 0;
- earg = &pcarg;
+ earg = &pcarg;
width = strtol(width_buf, earg, 10);
- if (errno == ERANGE || errno == EINVAL ||
- (**earg && *pcarg))
- return error(EINVAL, "Invalid numerical value "
- "for --width: %s", pcarg);
+ if (errno == ERANGE || errno == EINVAL
+ || (**earg && *pcarg))
+ return error(EINVAL,
+ "Invalid numerical value "
+ "for --width: %s",
+ pcarg);
in_width = 0;
}
else if (in_width)
{
errno = 0;
- earg = &carg;
+ earg = &carg;
width = strtol(carg, earg, 10);
- if (errno == ERANGE || errno == EINVAL ||
- (**earg && *carg))
- return error(EINVAL, "Invalid numerical value "
- "for -w: %s", carg);
+ if (errno == ERANGE || errno == EINVAL
+ || (**earg && *carg))
+ return error(EINVAL,
+ "Invalid numerical value "
+ "for -w: %s",
+ carg);
in_width = 0;
}
else if (starts_with(carg, "--width"))
- return error(EINVAL, "Parameter --width requires an "
- "argument");
- else if (*carg == '-' && *(carg+1) != 0)
+ return error(EINVAL,
+ "Parameter --width requires an "
+ "argument");
+ else if (*carg == '-' && *(carg + 1) != 0)
return usage();
else
strncpy(filename, carg, MAXPATH);
@@ -300,7 +316,7 @@ main(int argc, char** argv)
}
FILE* input = NULL;
- if (!*filename || (*filename == '-' && !*(filename+1)))
+ if (!*filename || (*filename == '-' && !*(filename + 1)))
input = stdin;
else
input = fopen(filename, "rt");
@@ -330,4 +346,3 @@ main(int argc, char** argv)
fclose(input);
return 0;
}
-
diff --git a/ufold.do b/ufold.do
@@ -1,10 +0,0 @@
-. ./config.redo
-for f in *.h.in; do
- echo $f | sed -e's/\.in$//g'
-done | xargs redo-ifchange
-for f in *.h *.c; do
- echo $f
- echo $f | sed -e's/\.c$/.o/g'
-done | xargs redo-ifchange
-${CC} -o $3 ufold.o utf8.o
-${STRIP} $3
diff --git a/uninstall.do b/uninstall.do
@@ -1,10 +0,0 @@
-. ./config.redo
-for docfile in $DOCS; do
- rm -f "${DOCDIR}/${docfile}"
-done
-for binfile in $PROGS; do
- rm -f "${BINDIR}/${binfile}"
-done
-for manfile in $MANPAGES; do
- rm -f "${MANPREFIX}/man1/${manfile}"
-done
diff --git a/utf8.c b/utf8.c
@@ -1,5 +1,5 @@
/* This program is licensed under the terms of GNU GPL v3 or (at your option)
- * any later version. Copyright (C) 2021-2023 Страхиња Радић.
+ * any later version. Copyright (C) 2021-2024 Страхиња Радић.
* See the file LICENSE for exact copyright and license details. */
#include "utf8.h"
diff --git a/utf8.h b/utf8.h
@@ -1,5 +1,5 @@
/* This program is licensed under the terms of GNU GPL v3 or (at your option)
- * any later version. Copyright (C) 2021-2023 Страхиња Радић.
+ * any later version. Copyright (C) 2021-2024 Страхиња Радић.
* See the file LICENSE for exact copyright and license details. */
#include <stdint.h>
diff --git a/version.do b/version.do
@@ -1,17 +0,0 @@
-FALLBACKVER=${FALLBACKVER:-unknown}
-LC_ALL=C
-export LC_ALL
-user=$(unalias ls >/dev/null 2>&1 || true; \
- command ls -ld . | awk '{print $3}')
-e_user=$(id -un)
-if [ -d .git ] && command -v git >/dev/null 2>&1; then
- if [ "$e_user" = "$user" ]; then
- git describe 2>/dev/null | sed 's/^v//' >$3
- else
- su "${user}" -c 'git describe' 2>/dev/null | sed 's/^v//' >$3
- fi
-else
- printf "%s\n" "$FALLBACKVER" >$3
-fi
-redo-always
-redo-stamp <$3