Mercurial > hgrepos > FreeBSD > ports > sysutils > local-bsdtools
changeset 483:1aa14a7d96dc
Provide a simple implementation of arrays for the FreeBSD POSIX/Bourne shell /bin/sh
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Thu, 29 Aug 2024 14:01:38 +0200 |
| parents | 26a97b2351e0 |
| children | 5d43c68bd1e9 |
| files | Makefile pkg-plist share/local-bsdtools/array.sh |
| diffstat | 3 files changed, 275 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/Makefile Wed Aug 28 09:51:05 2024 +0200 +++ b/Makefile Thu Aug 29 14:01:38 2024 +0200 @@ -80,7 +80,7 @@ ${SED} -i "" -e "s|@@SIMPLEVERSIONTAG@@|${SIMPLEVERSIONTAG}|" ${WRKSRC}/${_ef} .endfor ${MKDIR} ${WRKSRC}/share/${PORTNAME} -.for _df in share/local-bsdtools/common.subr +.for _df in share/local-bsdtools/array.sh share/local-bsdtools/common.subr ${CP} -v ${SRC}/${_df} ${WRKSRC}/${_df} ${SED} -i "" -e "s|@@SIMPLEVERSIONTAG@@|${SIMPLEVERSIONTAG}|" ${WRKSRC}/${_df} .endfor @@ -116,7 +116,7 @@ ${INSTALL_SCRIPT} ${WRKSRC}/etc/periodic/daily/${_ps} ${STAGEDIR}${PREFIX}/etc/periodic/daily .endfor ${MKDIR} ${STAGEDIR}${DATADIR} -.for _df in common.subr +.for _df in array.sh common.subr ${INSTALL_DATA} ${WRKSRC}/share/${PORTNAME}/${_df} ${STAGEDIR}${DATADIR} .endfor ${MKDIR} ${STAGEDIR}${EXAMPLESDIR}
--- a/pkg-plist Wed Aug 28 09:51:05 2024 +0200 +++ b/pkg-plist Thu Aug 29 14:01:38 2024 +0200 @@ -9,6 +9,7 @@ sbin/fpkg sbin/fzfs share/local-bsdtools/common.subr +share/local-bsdtools/array.sh share/examples/local-bsdtools/freebsd-update-ftjail-template.sh share/examples/local-bsdtools/freebsd-update-ftjail.sh %%DOCS%%share/man/man5/bsmtp2dma.conf.5.gz
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/share/local-bsdtools/array.sh Thu Aug 29 14:01:38 2024 +0200 @@ -0,0 +1,272 @@ +#!/bin/sh +# -*- indent-tabs-mode: nil; -*- +#: +#: A simple library to emulate simple array (one-dimensional) in a POSIX shell. +#: +#: :Author: Franz Glasner +#: :Copyright: (c) 2024 Franz Glasner. +#: All rights reserved. +#: :License: BSD 3-Clause "New" or "Revised" License. +#: See LICENSE for details. +#: If you cannot find LICENSE see +#: <https://opensource.org/licenses/BSD-3-Clause> +#: :ID: @(#)@@SIMPLEVERSIONTAG@@ +#: +#: This implementation is inspired by +#: https://unix.stackexchange.com/questions/137566/arrays-in-unix-bourne-shell +#: +#: Is implements one-dimensional array with one-base indexing. +#: +#: Implementation hints: +#: +#: - Every array has a NAME +#: - One-based indexing is used +#: - Array elements are stored in a variable named <NAME>_<index-number> +#: - The number of elements in the array ist stored in variable <NAME>__ +#: - An array name must conform to shell variable naming conventions +#: - Currently the number of of elements of an array must be >= 0 +#: - An unset <NAME>__ variable is a severe error and forces an immediate +#: error ``exit`` +#: + + +#: +#: Internal error for fatal errors +#: +#: Args: +#: $1 (str): The error message +#: +_array_fatal() { + echo "ERROR: ${1}" 1>&2 + exit 70 # EX_SOFTWARE +} + + +#: +#: Create a new array +#: +#: Args: +#: $1 (str): The name of the array. +#: Must conform to shell variable naming conventions +#: $2... (optional): Optional initialization values +#: +#: It is assumed that the array does not exist already. +#: +array_new() { + local _name + + local _el _l + + [ $# -lt 1 ] && _array_fatal "missing array name" + _name=$1 + shift + + # Check whether the variable already exists + eval _l=\${${_name}__:-__UNSET__} + + [ "${_l}" != "__UNSET__" ] && _array_fatal "array \`${_name}' already exists" + # Really create + eval ${_name}__=0 + + for _el in "$@"; do + array_append ${_name} "${_el}" + done +} + + +#: +#: Get the length of an array +#: +#: Args: +#: $1 (str): The name of the array. +#: +#: Output (stdout): +#: The number of elements of the array. +#: If the array does not exist the output is -1. +#: +array_length() { + local _name + + local _l + + [ $# -lt 1 ] && _array_fatal "missing array name" + _name=$1 + + # Check whether the variable already exists + eval _l=\${${_name}__:-__UNSET__} + + if [ "${_l}" = "__UNSET__" ]; then + printf "%s" "-1" + else + printf "%s" "${_l}" + fi +} + + +#: +#: Append a value to an existing array +#: +#: Args: +#: $1 (str): The name of the existing array +#: $2 (optional): The value to append. If the value is not given the null +#: will be appended. +#: +array_append() { + local _name _value + + local _l _l1 + + [ $# -lt 1 ] && _array_fatal "missing array name" + _name=$1 + _value="${2-}" + + # Check whether the variable already exists + eval _l=\${${_name}__:-__UNSET__} + if [ "${_l}" = "__UNSET__" ]; then + _array_fatal "array \`${_name}' does not exist" + fi + + _l1=$((${_l} + 1)) + # Set value + eval ${_name}_${_l1}="\"${_value}\"" + # Set new array length + eval ${_name}__=${_l1} +} + + +#: +#: Get an array value from a given index +#: +#: Args: +#: $1 (str): The name of the existing array +#: $2 (int): The index +#: +#: Output (stdout): +#: The value at index $2. +#: +array_get() { + local _name _index + + local _l _value + + [ $# -lt 1 ] && _array_fatal "missing array name" + _name=$1 + [ $# -lt 2 ] && _array_fatal "missing array index" + _index=$2 + + # Check whether the variable already exists + eval _l=\${${_name}__:-__UNSET__} + if [ "${_l}" = "__UNSET__" ]; then + _array_fatal "array \`${_name}' does not exist" + fi + + # check index range + if [ \( "${_index}" -lt 1 \) -o \( "${_index}" -gt ${_l} \) ]; then + _array_fatal "array index out of bounds" + fi + + eval _value=\"\${${_name}_${_index}}\" + printf "%s" "${_value}" +} + + +#: +#: Destroy and unset an array and all its elements +#: +#: Args: +#: $1 (str): The name of an array. The array may exist or not. +#: +array_destroy() { + local _name + + local _l _idx + + [ $# -lt 1 ] && _array_fatal "missing array name" + _name=$1 + + # Handle non-existing array names + eval _l=\${${_name}__:-__UNSET__} + if [ "${_l}" = "__UNSET__" ]; then + return 0 + fi + _idx=1 + while [ ${_idx} -le ${_l} ]; do + eval unset ${_name}_${_idx} + _idx=$((${_idx} + 1)) + done + + # Remove + eval unset ${_name}__ +} + + +#: +#: Call a function for every element in an array starting at the first index +#: +#: The function to be called must accept three arguments: +#: - the array name +#: - the current index +#: - the element value at the current index +#: +#: The iteration stops if the called function returns a falsy value. +#: +#: Args: +#: $1 (str): The name of an existing array. +#: $2 (str): The name of a function to be called with three arguments. +#: +array_for_each() { + local _name _cb + + local _l _idx _value _rv + + [ $# -lt 1 ] && _array_fatal "missing array name" + _name=$1 + [ $# -lt 2 ] && _array_fatal "missing callback function name" + _cb="$2" + + # Check whether the variable already exists + eval _l=\${${_name}__:-__UNSET__} + if [ "${_l}" = "__UNSET__" ]; then + _array_fatal "array \`${_name}' does not exist" + fi + + _idx=1 + while [ ${_idx} -le ${_l} ]; do + eval "${_cb} ${_name} ${_idx} \"\${${_name}_${_idx}}\"" + _rv=$? + [ ${_rv} -ne 0 ] && return ${_rv} + _idx=$((${_idx} + 1)) + done + return 0 +} + + +#: +#: Like `array_for_each`, but the function is called in reversed order -- +#: beginning with the last index +#: +array_reversed_for_each() { + local _name _cb + + local _l _idx _value _rv + + [ $# -lt 1 ] && _array_fatal "missing array name" + _name=$1 + [ $# -lt 2 ] && _array_fatal "missing callback function name" + _cb="$2" + + # Check whether the variable already exists + eval _l=\${${_name}__:-__UNSET__} + if [ "${_l}" = "__UNSET__" ]; then + _array_fatal "array \`${_name}' does not exist" + fi + + _idx=${_l} + while [ ${_idx} -gt 0 ]; do + eval "${_cb} ${_name} ${_idx} \"\${${_name}_${_idx}}\"" + _rv=$? + [ ${_rv} -ne 0 ] && return ${_rv} + _idx=$((${_idx} - 1)) + done + return 0 +}
