diff options
author | bill-auger <mr.j.spam.me@gmail.com> | 2020-07-29 20:27:12 -0400 |
---|---|---|
committer | bill-auger <mr.j.spam.me@gmail.com> | 2024-03-28 23:12:19 -0400 |
commit | 4bb529ce94359977977bcf80de6076cbb7cd8ff1 (patch) | |
tree | 3081941e12c5cc3692ac94545e23f4f7ee48f204 | |
parent | 5c18bd40ab32a73fbebba018ee1b6b3f8af87fab (diff) |
update docs
-rw-r--r-- | HACKING/licensing.md | 8 | ||||
-rw-r--r-- | HACKING/translations.md | 98 | ||||
-rw-r--r-- | INSTALL | 106 | ||||
-rw-r--r-- | INSTALL-VCS | 6 | ||||
-rw-r--r-- | po/HACKING | 50 | ||||
-rwxr-xr-x | src/abslibre-tools/librerelease | 2 | ||||
-rwxr-xr-x | src/chroot-tools/librechroot | 10 | ||||
-rw-r--r-- | src/lib/conf.sh.in | 55 | ||||
-rw-r--r-- | src/lib/messages.sh | 48 |
9 files changed, 249 insertions, 134 deletions
diff --git a/HACKING/licensing.md b/HACKING/licensing.md index 6d17e31..ec83689 100644 --- a/HACKING/licensing.md +++ b/HACKING/licensing.md @@ -6,14 +6,12 @@ New code should (please) be licensed GPLv2+. I say v2 instead of v3 because some code from Arch is GPLv2 (no "or any later version"), and having to worry about which programs can be combined is a huge pain. -Copyright statements should look like +Copyright statements for most code, should be of the form: # Copyright (C) YEARS NAME <EMAIL> -for most code, for 3rd-party code that has been imported, indent it a -bit: +For 3rd-party code, which has been imported, indent it a bit: # Copyright (C) YEARS NAME <EMAIL> -Always put a line with `# License:` specifying the license of that -file. +Always put a `# License:` line specifying the license of that file. diff --git a/HACKING/translations.md b/HACKING/translations.md new file mode 100644 index 0000000..2229d2a --- /dev/null +++ b/HACKING/translations.md @@ -0,0 +1,98 @@ +Translations for programs are provided in files with the `.po` suffix. These are +created by copying PO-template (`.pot`) files, and filling in the missing +"msgstr" values. + +To add a translation, you'll first (1) need to create the `.pot` files if you +don't already have them, and then (2) copy them and (3) fill them in. + +## 1. Create the `.pot` files + +If you are working from a release source tarball, you can skip this step (the +`.pot` files are included in the tarball); if you are working from git, read on. + +libretools' .pot files are not tracked in git; they are created by running +`make`. You'll need a checkout of both 'devtools-par' and 'libretools' to run +`make` if building from git. The 'devtools-par' and 'libretools' source root +directories should have the same parent directory. + + $ git clone https://git.parabola.nu/packages/libretools.git/ + $ git clone https://git.parabola.nu/packages/devtools-par.git/ + $ cd libretools + $ make po/files.generate + $ cd po/ + $ ls + gitget.pot + librelib.pot + libretools.pot + +NOTE: If you have modified the libretools source code, that may cause errors +during translation; especially if you have modified any of the translatable +strings. The failure will be evident by the error message: + + msgcmp: found N fatal errors + +If you see this error, refer to the "Updating translations" section below. + +## 2. Create the `.po` Files + +Create a folder under `po/` with the two-letter language code[^1] you want to +add. Then, copy the `.pot` files to that folder, changing the file extension to +`.po`. Finally, link the `subdir.mk` file as the Makefile for that directory. +For example: + + $ mkdir es + $ for file in *.pot; do cp $file es/${file%t}; done + $ ln -s ../subdir.mk es/Makefile + +[^1]: See the langauge code table: <http://www.lingoes.net/en/translator/langcode.htm> + +## 3. Fill the `.po` Files + +From there you can open each .po file in your favorite text editor, and fill in +the `msgstr` values with translations of the associated `msgid` keys. + +## 4. Synchronizing/Updating Translations + +If you have modified the libretools source code, it is likely that the program +will fail to compile, due to the translation files being mis-aligned with the +latest changes. You will need to run `msgmerge` to merge the newly generated +.pot templates into the existing .po files, as indicated by the `msgcmp` command +trace in the build log. + +e.g. if the following error message appeers after this log trace: + + msgcmp --use-untranslated --use-fuzzy po/es/libretools.po po/libretools.pot + .... + msgcmp: found 42 fatal errors + +then run: + + $ msgmerge po/es/libretools.po po/libretools.pot + +Notice any red (fuzzy) lines. Those are relatively minor mis-matches, which the +tool was able to reconcile, but may need correction. Also notice any green, +commented-out, 'msgid'/'msgstr' line pairs. Those are unresolved mis-matches, +which definitely need correction. They may correspond to a new 'msgid'/'msgstr' +line pair in the `msgmerge` output, with the new text as 'msgid', and an empty +'msgstr'; but the changes were too significant for the tool to determine the +correlation. The standard output of `msgmerge` is the raw text for a new +replacemnt .po file. Next, direct the output to a file, make the corrections +to the replacemnt .po file, using the `msgmerge` output as a guide; then replace +the failed .po file with the new corrected file. + + $ msgmerge po/es/libretools.po po/libretools.pot > po/es/libretools.po-merged + $ mv po/es/libretools.po{-merged,} + +Alternatively, a merge tool such as `meld`, is especially helpful for this task. +A merge tool should highlight the same merge conflicts, shown in the the +`msgmerge` output, as a side-by-side comparison, allowing you to merge the +changes from the generated '-merged' file, into the tracked .po file, in-place. +In order to minimize the possible merge conflict next time, it is best to merge +all of the changes, especially the comments with line numbers. + + $ meld po/es/libretools.po{-merged,} + +Once `make clean && make` is able to complete successfully, commit the new .po +file to the VCS. + + $ git commit -m 'sync translations' po/es/libretools.po @@ -1,13 +1,14 @@ Installation of libretools is pretty straight-forward: - $ make - # make install + $ make + # make install As a caveat, by default, if the directory `devtools-par` exists in the same directory as the `libretools-${version}` directory, and contains newer files than the libretools directory, they will be copied into the libretools directory. See INSTALL-VCS for more details. + Dependencies ------------ @@ -23,10 +24,14 @@ to cause issues. The "unusual" build-time dependencies are: - - GNU Make -- other `make`s will not work. - - GNU sed -- must support `-r` for ERE; BSD sed uses `-E` for this - purpose. - - ronn -- A markdown-to-manpage converter +------------------------------------------------------------------------------------------- +| build dependency | parabola package | notes | +|------------------|------------------|---------------------------------------------------| +| devtools-par | n/a | https://git.parabola.nu/packages/devtools-par.git | +| GNU Make | 'make' | strict requirement of the AutoThing build system | +| sed | 'sed' | must support Extended Regular Expressions | +| ronn | 'ruby-ronn' | a markdown-to-manpage converter | +------------------------------------------------------------------------------------------- Whether or not to build the manpages is controlled by whether config.mk:enable_manpages is empty (disable) or non-empty (enable). @@ -53,27 +58,47 @@ your operating system doesn't have it, it is available at ## Run-time dependencies -Being mostly shell scripts, many external program are used. Anything -that is included when installing the `base` package group on Parabola -GNU/Linux, I consider an implicit dependency. If something isn't used -now, that doesn't mean it won't be in the future. - -On top of that, the following dependencies are also needed: - -librelib subpackage: - - wget -gitget subpackage: - - librelib (provided) - - git -main libretools subpackage: - - librelib (provided) - - pacman 5.0 - - arch-install-scripts - - GNU Make (only needed for `librefetch`) - - ssh client (OpenSSH, only needed for `librerelease`) - - rsync - - systemd-nspawn (for the chroot tools) - - tokyocabinet +Being mostly shell scripts, many external program are used. The +dependencies of the Parabola GNU/Linux 'parabola-base' meta-package, +are assumed to be implicit dependencies of this script. If something +isn't used now, that doesn't mean it won't be in the future. + +Additionally, the following per-subpackage dependencies are needed: + +---------------------------------------------------------------------------------------------- +| librelib dependency | parabola package | usage | +|-----------------------|-------------------|------------------------------------------------| +| wget | 'wget' | (optional) used by `blacklist.sh` | +---------------------------------------------------------------------------------------------- + +---------------------------------------------------------------------------------------------- +| gitget dependency | parabola package | usage | +|-----------------------|-------------------|------------------------------------------------| +| git | 'git' | core functionality | +| librelib | provided | ubiquitous use of `librelib` confs and helpers | +---------------------------------------------------------------------------------------------- + +---------------------------------------------------------------------------------------------- +| libretools dependency | parabola package | usage | +|-----------------------|-------------------|------------------------------------------------| +| arch-install-scripts | 'base' | used by `mkarchroot`->`pacstrap` | +| binutils | 'binutils' | used by `libremakepkg`->`makepkg`->`strip` | +| expac | 'expac' | used by `libredbdiff` | +| fakeroot | 'fakeroot' | used by `libremakepkg`->`makepkg`->`fakeroot` | +| gitget | provided | used by `createworkdir` | +| librelib | provided | ubiquitous use of `librelib` confs and helpers | +| GNU Make | 'make' | used by `librefetch` | +| pacman >= v5.0 | 'base' | used by `libremakepkg`->`makepkg` | +| pacman-contrib | 'pacman-contrib' | used by `librefetch`->`updpkgsums` | +| namcap | 'namcap' | used by `libremakepkg` (currently dissabled) | +| rsync | 'rsync' | used by `librerelease`,`makechrootpkg.sh` | +| ssh client | 'openssh' | used by `librerelease` | +| subversion | 'subversion' | used by `diff-unfree` | +| systemd | 'libre/base' | used by arch-nspawn->systemd-nspawn | +| chroot-nspawn | 'nonsystemd/base' | used by arch-nspawn->systemd-nspawn | +| tokyocabinet | 'tokyocabinet' | used by `toru` | +---------------------------------------------------------------------------------------------- + Configuration ------------- @@ -88,25 +113,24 @@ The configuration variables mostly match GNU packages, but default values differ; libretools installs to `prefix=/usr` by default instead of GNU's `prefix=/usr/local`. + Building and installing subpackages ----------------------------------- -There are several subpackages you can build and install. This is done -by running: +There are several sub-packages you can build and install. - $ make build-${package} - # make install-${package} + - gitget -- A git downloader + - librelib -- Generic libraries included + - libretools -- The main libretools package -respectively. In addition to `build` and `install`, the activities -you can do are: +This is done by running: - - `copy` -- copy necessary files from the devtools-par source code - - `build` -- build all programs and files - - `install` -- install everything - - `clean` -- remove generated files + $ make build-<SUBPACKAGE> + # make install-<SUBPACKAGE> -The subpackages you can run these on are: +In addition to `build-*` and `install-*`, there are these general activities: - - libretools -- The main libretools package - - librelib -- Generic libraries included - - gitget -- A git downloader + - `copy` -- copy necessary files from the devtools-par source code + - `build` -- build all programs and files + - `clean` -- remove generated files + - `install` -- install everything diff --git a/INSTALL-VCS b/INSTALL-VCS index e0cf2f0..771a85c 100644 --- a/INSTALL-VCS +++ b/INSTALL-VCS @@ -9,9 +9,9 @@ INSTALL file. If the `$(devtoolsdir)` directory does not exist, but all of the copied files exist in the libretools directory, they will simply be used. -The distribution tarball includes the copies of the devtools files, so -it is not necessary to download the devtools source separately when -using the tarball. +The distribution tarball includes the copies of the devtools files, +so it is not necessary to download the devtools source separately +when using the tarball. Once you have the devtools source taken care of, you can build and install like normal. diff --git a/po/HACKING b/po/HACKING deleted file mode 100644 index 074e8bb..0000000 --- a/po/HACKING +++ /dev/null @@ -1,50 +0,0 @@ -Translations for programs are provided in files with the `.po` suffix. -These are created by copying PO-template (`.pot`) files, and filling -in the missing "msgstr" values. - -To add a translation, you'll first (1) need to create the `.pot` files -if you don't already have them, and then (2) copy them and (3) fill -them in. - -# 1. Create `.pot` files - - If you are working from a release source tarball, you can skip this - step (the `.pot` files are included in the tarball); if you are - working from git, read on. - - libretools' .pot files are not tracked in git; they are created by - running `make`. You'll need a checkout of both "devtools-par" and - "libretools" to run `make` if building from git. - - $ git clone https://git.parabola.nu/packages/devtools-par.git/ - $ git clone https://git.parabola.nu/packages/libretools.git/ - $ cd libretools - $ make po/files.generate - ... - $ cd po/ - $ ls - HACKING - gitget.pot - librelib.pot - libretools.pot - ... - -# 2. Create `.po` files from them - - Create a folder under `po/` with the two-letter language code[^1] - you want to add. Then, copy the `.pot` files to that folder, - changing the file extension to `.po`. Finally, link the `subdir.mk` - file to be the Makefile for that directory. For example: - - $ mkdir es - $ for file in *.pot; do cp $file es/${file%t}; done - $ ln -s ../subdir.mk es/Makefile - - [^1]: See the langauge code table - here: <http://www.lingoes.net/en/translator/langcode.htm> - -# 3. Fill the `.po` files in with translations - - From there you can open each .po file in your favorite text editor, - and fill in the `msgstr` values with translations of the associated - `msgid` keys. diff --git a/src/abslibre-tools/librerelease b/src/abslibre-tools/librerelease index ec168c4..c8217c7 100755 --- a/src/abslibre-tools/librerelease +++ b/src/abslibre-tools/librerelease @@ -294,6 +294,7 @@ release_packages() { local dbupdate_cmd="STAGING=${REPODEST_path@Q} DBSCRIPTS_CONFIG=${DBSCRIPTS_CONFIG@Q} db-update" msg "Running db-update on repos" + # eg: ssh -p 1863 autobuilder@repo.parabola.nu STAGING='staging/' DBSCRIPTS_CONFIG='/etc/dbscripts/config.local.parabola' db-update ssh ${tier0_port} "${tier0_host}" "${dbupdate_cmd}" if [[ -n $HOOKPOSTRELEASE ]]; then @@ -322,6 +323,7 @@ release_packages() { done < ${file_list} | sort -u | xargs || : ) ) + if (( ${#packages[@]} )); then local pbotsay_cmd="$(printf "${pbotsay_fmt}" "${login}" "${packages[@]}")" diff --git a/src/chroot-tools/librechroot b/src/chroot-tools/librechroot index e3c390a..bef2208 100755 --- a/src/chroot-tools/librechroot +++ b/src/chroot-tools/librechroot @@ -73,8 +73,8 @@ hack_arch_nspawn_flags() { local setarch interpreter case $CARCH in - armv7h) setarch=armv7l; interpreter=/usr/bin/qemu-arm-static ;; - *) setarch=$CARCH; interpreter=/usr/bin/qemu-$CARCH-static ;; + armv7h|armv7l) setarch=armv7l; interpreter=/usr/bin/qemu-arm-static ;; + *) setarch=$CARCH; interpreter=/usr/bin/qemu-$CARCH-static ;; esac if ! setarch $setarch /bin/true 2>/dev/null; then # We're running a cross-arch chroot @@ -241,8 +241,8 @@ usage() { prose 'This command will make the following configuration changes in the chroot:' bullet 'overwrite `/etc/libretools.d/chroot.conf`' # libretools/librechroot - bullet 'overwrite `/etc/pacman.d/mirrorlist`' # devtools/arch-nspawn - bullet 'set `CacheDir` in `/etc/pacman.conf`' # devtools/arch-nspawn + bullet 'overwrite `/etc/pacman.d/mirrorlist`' # devtools/arch-nspawn + bullet 'set `CacheDir` in `/etc/pacman.conf`' # devtools/arch-nspawn prose 'If a new `pacman.conf` is inserted with the `-C` flag, the change is made after the file is copied in; the `-C` flag doesn'"'"'t stop the change from being effective.' @@ -326,7 +326,7 @@ main() { trap 'rm -f -- "$tmppacmanconf"' EXIT tmppacmanconf="$(mktemp --tmpdir librechroot-pacman.conf.XXXXXXXXXX)" sed -r \ - -e "s|^#?\\s*Architecture.+|Architecture = ${OPTARG}|g" \ + -e "s|^#?\\s*Architecture.+|Architecture = $OPTARG|g" \ -e "s|^.*Include\s*=\s*/etc/pacman.d/.*\.conf|#&|" \ < "/usr/share/pacman/defaults/pacman.conf.$OPTARG" \ > "$tmppacmanconf" diff --git a/src/lib/conf.sh.in b/src/lib/conf.sh.in index bd9bde3..ec3c090 100644 --- a/src/lib/conf.sh.in +++ b/src/lib/conf.sh.in @@ -1,10 +1,24 @@ #!/hint/bash -# This may be included with or without `set -euE` -# Copyright (C) 2012-2015, 2017-2018 Luke Shumaker <lukeshu@parabola.nu> +# conf.sh - implicit libretools configuration +# +# This may be included with or without `set -euE`. +# In order to be used inside librechroots, this script assumes nothing +# of the environment, other than the optional $SUDO_USER (invalid in-chroot). +# Its main purpose it to canonicalize the in-chroot environment and paths, +# so that libretools needs not be installed in every librechroot, +# unlike the host environment, where libretools can re-configure itself. +# However, some functions expect `librelib messages` to be pre-sourced, +# namely, the getters and setters (load_conf(), set_var(), set_var()), +# which are useful and meaningful only for the host environment. +# This is also where $LIBREUSER is defined, which most other scripts depend on. +# $LIBREUSER is $SUDO_USER unless UID->0, or $USER otherwise. +# +# Copyright (C) 2012-2015,2017-2018 Luke Shumaker <lukeshu@parabola.nu> +# Copyright (C) 2020,2023 bill-auger <bill-auger@programmer.net> # Copyright (C) 2024 Denis 'GNUtoo' Carikli <GNUtoo@cyberdimension.org> # -# License: GNU GPLv2+ +# SPDX-License-Identifier: GPL-2.0-or-later # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -19,15 +33,26 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. + +## prepare environment ## + +# define $LIBREUSER if [[ "$(id -u "${SUDO_USER:-root}")" == 0 ]]; then unset SUDO_USER fi LIBREUSER="${SUDO_USER:-$USER}" + +# define $LIBREHOME +# $LIBREHOME is the default parent directory of $WORKDIR (per /etc/libretools.conf) +# default: ~$LIBREUSER/ unless SUDO_USER != $USER, $HOME/$LIBREUSER/ otherwise +# NOTE: $WORKDIR and $LIBREHOME/.cache must be writable by $LIBREUSER if [[ $LIBREUSER == "$USER" ]]; then LIBREHOME=$HOME else eval "LIBREHOME=~$LIBREUSER" fi + +# define $XDG_CONFIG_HOME and $XDG_CACHE_HOME, if not set already if [[ -z ${XDG_CONFIG_HOME:-} ]]; then export XDG_CONFIG_HOME="${LIBREHOME}/.config" fi @@ -35,7 +60,8 @@ if [[ -z ${XDG_CACHE_HOME:-} ]]; then export XDG_CACHE_HOME="${LIBREHOME}/.cache" fi -# Low-level generic functions ################################################## + +## Low-level generic functions ## # Usage: list_files $slug # Lists the configuration files to be considered for $slug. @@ -79,8 +105,7 @@ list_files() { } # Usage: list_envvars $slug -# Lists the environmental variables that take precedence over the configuration -# files for $slug. +# Lists which env-vars shall over-ride the config files for $slug. list_envvars() { local slug=$1 case $slug in @@ -99,12 +124,13 @@ list_envvars() { esac } -# High-level generic functions ################################################# + +## High-level generic functions ## # Usage: load_conf {$slug.conf|$abspath} [VAR1 VAR2...] # -# Loads the configuration files for $slug in the proper order, and -# optionally verify that certain variables are set. +# Loads the configuration files for $slug in the proper order; +# and optionally, verify that specified variables are set. load_conf() { [[ $1 = /* || $1 = *.conf ]] || libremessages panic || exit 1 # $EXIT_FAILURE local files envvars @@ -153,7 +179,7 @@ load_conf() { return $ret } -# Usage: get_var <slug> <var_name> <default_value> +# Usage: get_var <slug> <var_name> [ <default_value> ] # Does not work with arrays get_var() ( set +euE @@ -181,7 +207,8 @@ set_var() { return 1 # $EXIT_FAILURE } -# PKGBUILD (not configuration, per se) ######################################### + +## PKGBUILD loading (not configuration, per se) ## unset_PKGBUILD() { # This routine is based primarily off of the PKGBUILD(5) man-page, @@ -223,7 +250,11 @@ unset_PKGBUILD() { unset -f $(declare -f|sed -n 's/^\(package_\S*\) ()\s*$/\1/p') unset -v pkgbase - # These are used by the `librefetch` program + # Parabola makepkg extensions (aka: mksource) + # These are used by `librefetch` to generate an FSDG-fit source-ball, + # before the prepare() funtion runs, + # instead of the standard --allsource source-ball, + # which is rolled before the prepare() funtions runs. unset -v mksource mknoextract "${sums[@]/#/mk}" unset -v mkdepends unset -f mksource diff --git a/src/lib/messages.sh b/src/lib/messages.sh index 67cdab5..504a53a 100644 --- a/src/lib/messages.sh +++ b/src/lib/messages.sh @@ -1,20 +1,25 @@ #!/usr/bin/env bash -# This may be included with or without `set -euE` -# Copyright (C) 2011 Joshua Ismael Haase Hernández (xihh) <hahj87@gmail.com> -# Copyright (C) 2012 Nicolás Reynolds <fauno@parabola.nu> -# Copyright (C) 2012-2014, 2016-2018 Luke Shumaker <lukeshu@parabola.nu> +# message.sh - library for log messages and --help/USAGE reports +# - extends pacman's makepkg::util/message.sh +# +# This may be included with or without `set -euE` +# +# Copyright (C) 2011 Joshua Ismael Haase Hernández (xihh) <hahj87@gmail.com> +# Copyright (C) 2012 Nicolás Reynolds <fauno@parabola.nu> +# Copyright (C) 2012-2014,2016-2018 Luke Shumaker <lukeshu@parabola.nu> +# Copyright (C) 2020,2023 bill-auger <bill-auger@programmer.net> # # For just the setup_traps() function: # Copyright (C) 2002-2006 Judd Vinet <jvinet@zeroflux.org> # Copyright (C) 2006-2010 Pacman Development Team <pacman-dev@archlinux.org> -# Copyright (C) 2005 Aurelien Foret <orelien@chez.com> -# Copyright (C) 2005 Christian Hamar <krics@linuxforum.hu> -# Copyright (C) 2006 Alex Smith <alex@alex-smith.me.uk> -# Copyright (C) 2006 Andras Voroskoi <voroskoi@frugalware.org> -# Copyright (C) 2006 Miklos Vajna <vmiklos@frugalware.org> +# Copyright (C) 2005 Aurelien Foret <orelien@chez.com> +# Copyright (C) 2005 Christian Hamar <krics@linuxforum.hu> +# Copyright (C) 2006 Alex Smith <alex@alex-smith.me.uk> +# Copyright (C) 2006 Andras Voroskoi <voroskoi@frugalware.org> +# Copyright (C) 2006 Miklos Vajna <vmiklos@frugalware.org> # -# License: GNU GPLv2+ +# SPDX-License-Identifier: GPL-2.0-or-later # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -29,17 +34,13 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. + [[ -z ${_INCLUDE_MESSAGES_SH:-} ]] || return 0 _INCLUDE_MESSAGES_SH=true -################################################################################ -# Inherit most functions from devtools # -################################################################################ - -. "$(librelib common)" ################################################################################ -# Own functions # +# Libretools constants # ################################################################################ declare -rgi EXIT_TRUE=0 @@ -53,11 +54,23 @@ declare -rgi EXIT_NOPERMISSION=4 declare -rgi EXIT_NOTINSTALLED=5 declare -rgi EXIT_NOTCONFIGURED=6 + +################################################################################ +# Inherit most message functions from devtools # +################################################################################ + +. "$(librelib common)" + + +################################################################################ +# Libretools message functions # +################################################################################ + # Usage: panic # # For programming errors, bails immediately with little fanfare. panic() { - _l _ 'panic: malformed call to internal function' >&2 + _l _ "General error. This is a bug. Please report it to Parabola." >&2 exit $EXIT_FAILURE } @@ -84,7 +97,6 @@ whitespace_collapse() { -e 's/\s+$//' } - # Usage: prose MESG [ARGS...] # # Do HTML-style whitespace collapsing on the first argument, translate |