# HG changeset patch # User Franz Glasner # Date 1728158155 -7200 # Node ID a97ec3f07bdb389e57a489106672a67ca7737b4d # Parent 9c860f2abbdc6b3f61487d0afbbfb4c6ed2a6491 farray.sh: REFACTOR: More flexible metadata retrieval. Using an array or alist variable name or token value (with prefix) is now supported in every function. This is possible because the value prefixes contain questin marks (?) which are not allowed in shell variable names. This again is a major precondition for recursive data structures (arrays/alists in arrays/alists). diff -r 9c860f2abbdc -r a97ec3f07bdb share/local-bsdtools/farray.sh --- a/share/local-bsdtools/farray.sh Sat Oct 05 14:49:34 2024 +0200 +++ b/share/local-bsdtools/farray.sh Sat Oct 05 21:55:55 2024 +0200 @@ -92,9 +92,9 @@ #: -_farr_array_token_prefix='_farr_A*_' +_farr_array_token_prefix='_farr_A?_' _farr_array_prefix=_farr_A_ -_farr_alist_token_prefix='_farr_KV*_' +_farr_alist_token_prefix='_farr_KV??_' _farr_alist_prefix=_farr_KV_ _farr_alist_key_prefix=_farr_K_ _farr_alist_value_prefix=_farr_V_ @@ -457,7 +457,6 @@ __farr_token="$(/usr/bin/hexdump -v -e '/1 "%02x"' -n 16 '/dev/urandom')" __farr_gvrname=${_farr_array_prefix}${__farr_token} - shift # Check whether the variable already exists eval __farr_len=\$\{${__farr_gvrname}__+SET\} @@ -468,8 +467,13 @@ # And associate the token with the array name eval "${__farr_name}=\"\${_farr_array_token_prefix}\${__farr_token}\"" - if [ $# -gt 0 ]; then - farray_append "${__farr_name}" "$@" + # + # When there are values to populate the array with. + # Note that the array's name is not shifted away yet and must be taken + # into account. It is also needed for `farray_append`. + # + if [ $# -gt 1 ]; then + farray_append "$@" fi } @@ -478,10 +482,11 @@ #: Internal helper to get all the metadata for an array. #: #: Args: -#: $1 (str): The name of the array +#: $1 (str): The name of the array or a complete array value with prefix #: #: Output (Globals): -#: __farr_name (str): The name of the array. +#: __farr_name (str): The name of the array if the name is given, +#: empty if a token value is given. #: __farr_token (str): The token that is the value of the name without its #: token prefix. #: __farr_gvrname (str): The variable prefix for all items. @@ -491,25 +496,41 @@ #: Iff the array does not exist in some fashion (token and/or storage). #: _farr_array_get_meta() { - __farr_name="${1-}" - [ -z "${__farr_name}" ] && _farr_fatal "missing farray name" - eval __farr_token=\"\$\{"${__farr_name}"-\}\" - case "${__farr_token}" in + local __farr_gm_name_or_value + + __farr_gm_name_or_value="${1-}" + case "${__farr_gm_name_or_value}" in '') - _farr_fatal "object \`${__farr_name}' not created properly: token empty" + # ambiguous + _farr_fatal "missing farray name or token value" ;; - "${_farr_array_token_prefix}"*) - __farr_token="${__farr_token#"${_farr_array_token_prefix}"}" + # A prefixed token value + __farr_name='' + __farr_token="${__farr_gm_name_or_value#"${_farr_array_token_prefix}"}" ;; *) - _farr_fatal "object \`${__farr_name}' is not an array" + # A variable name: go through one indirection + __farr_name="${__farr_gm_name_or_value}" + eval __farr_token=\"\$\{"${__farr_name}"-\}\" + case "${__farr_token}" in + '') + _farr_fatal "object \`${__farr_name}' not created properly: token empty" + ;; + + "${_farr_array_token_prefix}"*) + __farr_token="${__farr_token#"${_farr_array_token_prefix}"}" + ;; + *) + _farr_fatal "object \`${__farr_name}' is not an array" + ;; + esac ;; esac __farr_gvrname="${_farr_array_prefix}${__farr_token}" eval __farr_len=\$\{${__farr_gvrname}__:+SET\} - [ -z "${__farr_len}" ] && _farr_fatal "farray \`${__farr_name}' not created properly: no storage for token \`${__farr_token}'" + [ -z "${__farr_len}" ] && _farr_fatal "farray \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no storage for token \`${__farr_token}'" # eval __farr_len="\$((\${${__farr_gvrname}__} + 0))" eval __farr_len=\"\$\{${__farr_gvrname}__\}\" return 0 @@ -520,10 +541,11 @@ #: Internal helper to try to get all the metadata for an array. #: #: Args: -#: $1 (str): The name of the array +#: $1 (str): The name of the array or a complete array value with prefix #: #: Output (Globals): -#: __farr_name (str): The name of the array. +#: __farr_name (str): The name of the array if the name is given, +#: empty if a token value is given. #: __farr_token (str): The token that is the value of the name without its #: token prefix. #: __farr_gvrname (str): The variable prefix for all items. @@ -532,38 +554,53 @@ #: Returns: #: 0 if the array exists, 1 if something is missing. #: -#: Exit: -#: Iff the array name is not given -#: _farr_array_tryget_meta() { - __farr_name="${1-}" - [ -z "${__farr_name}" ] && _farr_fatal "missing farray name" + local __farr_gm_name_or_value + __farr_token='' __farr_gvrname='' __farr_len='' - eval __farr_token=\"\$\{"${__farr_name}"-\}\" - case "${__farr_token}" in + __farr_name="${1-}" + + __farr_gm_name_or_value="${1-}" + case "${__farr_gm_name_or_value}" in '') - _farr_err "object \`${__farr_name}' not created properly: token empty" + # ambiguous + _farr_err "missing farray name or token value" return 1 ;; - "${_farr_array_token_prefix}"*) - __farr_token="${__farr_token#"${_farr_array_token_prefix}"}" + # A prefixed token value + __farr_name='' + __farr_token="${__farr_gm_name_or_value#"${_farr_array_token_prefix}"}" ;; *) - _farr_err "object \`${__farr_name}' is not an array" - return 1 + # A variable name: go through one indirection + __farr_name="${__farr_gm_name_or_value}" + eval __farr_token=\"\$\{"${__farr_name}"-\}\" + case "${__farr_token}" in + '') + _farr_err "object \`${__farr_name}' not created properly: token empty" + return 1 + ;; + + "${_farr_array_token_prefix}"*) + __farr_token="${__farr_token#"${_farr_array_token_prefix}"}" + ;; + *) + _farr_err "object \`${__farr_name}' is not an array" + return 1 + ;; + esac ;; esac __farr_gvrname="${_farr_array_prefix}${__farr_token}" eval __farr_len=\$\{${__farr_gvrname}__:+SET\} - if [ -z "${__farr_len}" ]; then - _farr_err "farray \`${__farr_name}' not created properly: no storage for token \`${__farr_token}'" + if [ -z "${__farr_len}" ] ; then + _farr_err "farray \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no storage for token \`${__farr_token}'" return 1 fi - # eval __farr_len="\$((\${${__farr_gvrname}__} + 0))" eval __farr_len=\"\$\{${__farr_gvrname}__\}\" return 0 } @@ -578,10 +615,11 @@ #: All output variables are properly initialized to the `null` value. #: #: Args: -#: $1 (str): The name of the array +#: $1 (str): The name of the array or a complete array value with prefix #: #: Output (Globals): -#: __farr_name (str): The name of the array. +#: __farr_name (str): The name of the array if the name is given, +#: empty if a token value is given. #: __farr_token (str): The token that is the value of the name without its #: token prefix. #: __farr_gvrname (str): The variable prefix for all items. @@ -594,79 +632,46 @@ #: No fatal error exits should happen. #: _farr_array_tryget_meta_nonfatal() { + local __farr_gm_name_or_value + __farr_token='' __farr_gvrname='' __farr_len='' __farr_name="${1-}" - [ -z "${__farr_name}" ] && return 1 - eval __farr_token=\"\$\{"${__farr_name}"-\}\" - case "${__farr_token}" in + + __farr_gm_name_or_value="${1-}" + case "${__farr_gm_name_or_value}" in '') - return 1 - ;; - - "${_farr_array_token_prefix}"*) - __farr_token="${__farr_token#"${_farr_array_token_prefix}"}" - ;; - *) + # ambiguous return 1 ;; - esac - __farr_gvrname="${_farr_array_prefix}${__farr_token}" - eval __farr_len=\$\{${__farr_gvrname}__:+SET\} - [ -z "${__farr_len}" ] && return 1 - # eval __farr_len="\$((\${${__farr_gvrname}__} + 0))" - eval __farr_len=\"\$\{${__farr_gvrname}__\}\" - return 0 -} - - -#: -#: Internal helper to try to get all the metadata for an array directoy from -#: a given array token with prefix. -#: -#: Args: -#: $1 (str): The token value with its prefix for an array. -#: -#: Output (Globals): -#: __farr_token (str): The token that is the value of the name without its -#: token prefix. -#: __farr_gvrname (str): The variable prefix for all items. -#: __farr_len (int): The length of the array -#: -#: Returns: -#: 0 if the array exists, 1 if something is missing or wrong. -#: -#: An error is printed only if the storage of an otherwise correct array -#: is missing. -#: -_farr_array_tryget_meta_from_value() { - local __farr_input_token_value - - __farr_input_token_value="${1-}" - __farr_token='' - __farr_gvrname='' - __farr_len='' - case "${__farr_input_token_value}" in - '') - return 1 - ;; - "${_farr_array_token_prefix}"*) - __farr_token="${__farr_input_token_value#"${_farr_array_token_prefix}"}" + # A prefixed token value + __farr_name='' + __farr_token="${__farr_gm_name_or_value#"${_farr_array_token_prefix}"}" ;; *) - return 1 + # A variable name: go through one indirection + __farr_name="${__farr_gm_name_or_value}" + eval __farr_token=\"\$\{"${__farr_name}"-\}\" + case "${__farr_token}" in + '') + return 1 + ;; + + "${_farr_array_token_prefix}"*) + __farr_token="${__farr_token#"${_farr_array_token_prefix}"}" + ;; + *) + return 1 + ;; + esac ;; esac __farr_gvrname="${_farr_array_prefix}${__farr_token}" eval __farr_len=\$\{${__farr_gvrname}__:+SET\} - if [ -z "${__farr_len}" ]; then - _farr_err "farray with token value \`${__farr_input_token_value}' not created properly: no storage for token \`${__farr_token}'" - return 1 - fi - # eval __farr_len="\$((\${${__farr_gvrname}__} + 0))" + [ -z "${__farr_len}" ] && return 1 eval __farr_len=\"\$\{${__farr_gvrname}__\}\" return 0 } @@ -1133,37 +1138,8 @@ # Remove length itself eval unset ${__farr_gvrname}__ # Clean out the array name from the token - eval ${__farr_name}=\"\" -} - - -#: -#: Destroy and unset an array and all its elements from its complete token -#: value -#: -#: Args: -#: $1 (str): An array token value including its prefix -#: -#: Returns: -#: - A truthy value if the array existed and has been deleted. -#: - A falsy value if the array does not exist. -#: -_farr_array_destroy_value() { - - local __farr_token __farr_gvrname __farr_len - local __farr_idx - - _farr_array_tryget_meta_from_value "$1" || return 1 - - # Remove "storage" - __farr_idx=1 - while [ ${__farr_idx} -le ${__farr_len} ]; do - eval unset ${__farr_gvrname}_${__farr_idx} - __farr_idx=$((__farr_idx + 1)) - done - - # Remove length itself - eval unset ${__farr_gvrname}__ + [ -n "${__farr_name}" ] && eval "${__farr_name}=''" + return 0 } @@ -1474,7 +1450,9 @@ local __farr_name __farr_callback local __farr_token __farr_gvrname __farr_len __farr_idx __farr_rv - + local __farr_gm_name_or_value + + __farr_gm_name_or_value="${1-}" _farr_array_get_meta "$@" __farr_callback="${2-}" @@ -1484,7 +1462,7 @@ __farr_idx=1 while [ ${__farr_idx} -le ${__farr_len} ]; do - eval "${__farr_callback} ${__farr_name} ${__farr_idx} \"\${${__farr_gvrname}_${__farr_idx}}\" \"\$@\"" + eval "${__farr_callback} \"\${__farr_name:-\"\${__farr_gm_name_or_value}\"}\" \"\${__farr_idx}\" \"\${${__farr_gvrname}_${__farr_idx}}\" \"\$@\"" __farr_rv=$? [ ${__farr_rv} -ne 0 ] && return ${__farr_rv} __farr_idx=$((__farr_idx + 1)) @@ -1501,7 +1479,10 @@ local __farr_name __farr_callback local __farr_token __farr_gvrname __farr_len __farr_idx __farr_rv - + local __farr_gm_name_or_value + + __farr_gm_name_or_value="${1-}" + _farr_array_get_meta "$@" __farr_callback="${2-}" [ -z "${__farr_callback}" ] && _farr_fatal "missing callback function name" @@ -1509,7 +1490,7 @@ __farr_idx=${__farr_len} while [ ${__farr_idx} -gt 0 ]; do - eval "${__farr_callback} ${__farr_name} ${__farr_idx} \"\${${__farr_gvrname}_${__farr_idx}}\" \"\$@\"" + eval "${__farr_callback} \"\${__farr_name:-\"\${__farr_gm_name_or_value}\"}\" \"\${__farr_idx}\" \"\${${__farr_gvrname}_${__farr_idx}}\" \"\$@\"" __farr_rv=$? [ ${__farr_rv} -ne 0 ] && return ${__farr_rv} __farr_idx=$((__farr_idx - 1)) @@ -1525,22 +1506,43 @@ #: $1 (str): The name of an array. The array may exist or not. #: #: Returns: -#: 0 +#: int: 0 #: farray_debug() { - local __farr_name - - local __farr_token __farr_gvrname __farr_len - + _farr_array_debug '' "$@" +} + + +#: +#: Internal implementation of `farray_debug`. +#: +#: Args: +#: $1 (str): The indent +#: $2 (str): The name or the complete prefixed token of an array +#: +#: Returns: +#: int: 0 +#: +_farr_array_debug() { + local __farr_debug_indent __farr_name + + local __farr_token __farr_gvrname __farr_len __farr_name_or_token + + __farr_debug_indent="${1}" + shift if ! _farr_array_tryget_meta "$@"; then - echo "DEBUG: no (meta-)data for farray \`${1-}'" 1>&2 + printf "%sDEBUG: no (meta-)data for farray \`%s'\\n" "${__farr_debug_indent}" "${1-}" 1>&2 return 0 fi - - echo "DEBUG: array \`${__farr_name}' has length ${__farr_len}" 1>&2 + __farr_name_or_token="${__farr_name:-"${1}"}" + if [ -n "${__farr_name}" ]; then + printf "%sDEBUG: array \`%s' has length %s\\n" "${__farr_debug_indent}" "${__farr_name}" "${__farr_len}" 1>&2 + else + printf "%sDEBUG: array with token \`%s' has length %s\\n" "${__farr_debug_indent}" "${__farr_token}" "${__farr_len}" 1>&2 + fi if [ ${__farr_len} -gt 0 ]; then - echo "DEBUG: its contents:" 1>&2 - farray_for_each "${__farr_name}" _farr_debug_print_value + printf '%sDEBUG: its contents:\n' "${__farr_debug_indent}" 1>&2 + farray_for_each "${__farr_name_or_token}" _farr_debug_print_value "${__farr_debug_indent}" || true fi return 0 } @@ -1549,8 +1551,11 @@ #: #: Debug output helper for `farray_debug`. #: +#: Args: +#: $4: The current indentation string +#: _farr_debug_print_value() { - printf "DEBUG: %s: \`%s'\\n" "$2" "$3" 1>&2 + printf "%sDEBUG: %s: \`%s'\\n" "$4" "$2" "$3" 1>&2 return 0 } @@ -1630,10 +1635,11 @@ #: Internal helper to get all the metadata for an alist. #: #: Args: -#: $1 (str): The name of the alist. +#: $1 (str): The name of the alist or a complete alist value with prefix #: #: Output (Globals): -#: __farr_name (str): The name of the alist. +#: __farr_name (str): The name of the alist if the name is given, +#: empty if a token value is given. #: __farr_token (str): The token that is the value of the name. #: __farr_objname (str): The variable prefix for the length ("object"). #: __farr_keyname (str): The variable prefix for all item keys. @@ -1644,19 +1650,34 @@ #: Iff the array does not exist in some fashion (token and/or storage). #: _farr_alist_get_meta() { - __farr_name="${1-}" - [ -z "${__farr_name}" ] && _farr_fatal "missing farray name" - eval __farr_token=\"\$\{"${__farr_name}"-\}\" - case "${__farr_token}" in + local __farr_gm_name_or_value + + __farr_gm_name_or_value="${1-}" + case "${__farr_gm_name_or_value}" in '') - _farr_fatal "object \`${__farr_name}' not created properly: token empty" + _farr_fatal "missing falist name or token value" ;; - "${_farr_alist_token_prefix}"*) - __farr_token="${__farr_token#"${_farr_alist_token_prefix}"}" + # A prefixed token value + __farr_name='' + __farr_token="${__farr_gm_name_or_value#"${_farr_alist_token_prefix}"}" ;; *) - _farr_fatal "object \`${__farr_name}' is not an alist" + # A variable name: go through one indirection + __farr_name="${__farr_gm_name_or_value}" + eval __farr_token=\"\$\{"${__farr_name}"-\}\" + case "${__farr_token}" in + '') + _farr_fatal "object \`${__farr_name}' not created properly: token empty" + ;; + + "${_farr_alist_token_prefix}"*) + __farr_token="${__farr_token#"${_farr_alist_token_prefix}"}" + ;; + *) + _farr_fatal "object \`${__farr_name}' is not an alist" + ;; + esac ;; esac @@ -1665,7 +1686,7 @@ __farr_valname=${_farr_alist_value_prefix}${__farr_token} eval __farr_len=\$\{${__farr_objname}__:+SET\} - [ -z "${__farr_len}" ] && _farr_fatal "falist \`${__farr_name}' not created properly: no object for token \`${__farr_token}'" + [ -z "${__farr_len}" ] && _farr_fatal "falist \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no object for token \`${__farr_token}'" # eval __farr_len="\$((\${${__farr_objname}__} + 0))" eval __farr_len="\${${__farr_objname}__}" return 0 @@ -1676,10 +1697,11 @@ #: Internal helper to try to get all the metadata for an alist. #: #: Args: -#: $1 (str): The name of the alist +#: $1 (str): The name of the alist or a complete alist value with prefix #: #: Output (Globals): -#: __farr_name (str): The name of the alist. +#: __farr_name (str): The name of the alist if the name is given, +#: empty if a token value is given. #: __farr_token (str): The token that is the value of the name without its #: token prefix. #: __farr_objname (str): The variable prefix for the length ("object"). @@ -1690,30 +1712,38 @@ #: Returns: #: 0 if the array exists, 1 if something is missing. #: -#: Exit: -#: Iff the array name is not given -#: _farr_alist_tryget_meta() { - __farr_name="${1-}" - [ -z "${__farr_name}" ] && _farr_fatal "missing farray name" - __farr_token="" - __farr_objname="" - __farr_keyname="" - __farr_valname="" - __farr_len="" - eval __farr_token=\"\$\{"${__farr_name}"-\}\" - case "${__farr_token}" in + local __farr_gm_name_or_value + + __farr_gm_name_or_value="${1-}" + case "${__farr_gm_name_or_value}" in '') - _farr_err "object \`${__farr_name}' not created properly: token empty" + _farr_err "missing falist name or token value" return 1 ;; - "${_farr_alist_token_prefix}"*) - __farr_token="${__farr_token#"${_farr_alist_token_prefix}"}" + # A prefixed token value + __farr_name='' + __farr_token="${__farr_gm_name_or_value#"${_farr_alist_token_prefix}"}" ;; *) - _farr_err "object \`${__farr_name}' not an alist" - return 1 + # A variable name: go through one indirection + __farr_name="${__farr_gm_name_or_value}" + eval __farr_token=\"\$\{"${__farr_name}"-\}\" + case "${__farr_token}" in + '') + _farr_err "object \`${__farr_name}' not created properly: token empty" + return 1 + ;; + + "${_farr_alist_token_prefix}"*) + __farr_token="${__farr_token#"${_farr_alist_token_prefix}"}" + ;; + *) + _farr_err "object \`${__farr_name}' is not an alist" + return 1 + ;; + esac ;; esac @@ -1722,68 +1752,7 @@ __farr_valname=${_farr_alist_value_prefix}${__farr_token} eval __farr_len=\$\{${__farr_objname}__:+SET\} - if [ -z "${__farr_len}" ]; then - _farr_err "falist \`${__farr_name}' not created properly: no object for token \`${__farr_token}'" - return 1 - fi - # eval __farr_len="\$((\${${__farr_objname}__} + 0))" - eval __farr_len="\${${__farr_objname}__}" - return 0 -} - - -#: -#: Internal helper to try to get all the metadata for an alist directly from -#: a given alist token with prefix. -#: -#: Args: -#: $1 (str): The token value with its prefix for an alist. -#: -#: Output (Globals): -#: __farr_token (str): The token that is the value of the name without its -#: token prefix. -#: __farr_objname (str): The variable prefix for the length ("object"). -#: __farr_keyname (str): The variable prefix for all item keys. -#: __farr_valname (str): The variable prefix for all item values. -#: __farr_len (int): The length of the alist. -#: -#: Returns: -#: 0 if the array exists, 1 if something is missing or wrong. -#: -#: An error is printed only if the storage of an otherwise correct alist -#: is missing. -#: -_farr_alist_tryget_meta_from_value() { - local __farr_input_token_value - - __farr_input_token_value="${1-}" - __farr_token="" - __farr_objname="" - __farr_keyname="" - __farr_valname="" - __farr_len="" - case "${__farr_input_token_value}" in - '') - return 1 - ;; - - "${_farr_alist_token_prefix}"*) - __farr_token="${__farr_input_token_value#"${_farr_alist_token_prefix}"}" - ;; - *) - return 1 - ;; - esac - - __farr_objname="${_farr_alist_prefix}${__farr_token}" - __farr_keyname=${_farr_alist_key_prefix}${__farr_token} - __farr_valname=${_farr_alist_value_prefix}${__farr_token} - - eval __farr_len=\$\{${__farr_objname}__:+SET\} - if [ -z "${__farr_len}" ]; then - _farr_err "falist with token value \`${__farr_input_token_value}' not created properly: no object for token \`${__farr_token}'" - return 1 - fi + [ -z "${__farr_len}" ] && _farr_fatal "falist \`${__farr_name:-"${__farr_gm_name_or_value}"}' not created properly: no object for token \`${__farr_token}'" # eval __farr_len="\$((\${${__farr_objname}__} + 0))" eval __farr_len="\${${__farr_objname}__}" return 0 @@ -1890,7 +1859,7 @@ # Remove object (length) itself eval unset ${__farr_objname}__ # Clean out the alist name from the token - eval ${__farr_name}=\"\" + [ -n "${__farr_name}" ] && eval "${__farr_name}=''" return 0 } @@ -1908,9 +1877,9 @@ _farr_alist_destroy_value() { local __farr_token __farr_objname __farr_keyname __farr_valname __farr_len - local __farr_idx - - _farr_alist_tryget_meta_from_value "$1" || return 1 + local __farr_idx __farr_del_value + + _farr_alist_tryget_meta "$1" || return 1 # Remove "storage" __farr_idx=1 @@ -2156,7 +2125,7 @@ fi __farr_idx=$((__farr_idx + 1)) done - _farr_fatal "alist \`${__farr_name}': key \`${__farr_key}' not found" + _farr_fatal "alist \`${__farr_name:-"${1}"}': key \`${__farr_key}' not found" } @@ -2803,7 +2772,9 @@ local __farr_token __farr_objname __farr_keyname __farr_valname __farr_len local __farr_feidx __farr_fekey __farr_feval __farr_rv - + local __farr_gm_name_or_value + + __farr_gm_name_or_value="${1-}" _farr_alist_get_meta "$@" __farr_callback="${2-}" [ -z "${__farr_callback}" ] && _farr_fatal "missing callback function name" @@ -2818,14 +2789,14 @@ eval __farr_feval=\"\$\{${__farr_valname}_${__farr_feidx}+SET\}\" if [ -n "${__farr_feval}" ]; then eval __farr_feval=\"\$\{${__farr_valname}_${__farr_feidx}\}\" - eval "${__farr_callback} ${__farr_name} \"\${__farr_fekey}\" \"\${__farr_feval}\" ${__farr_feidx} \"\$@\"" + eval "${__farr_callback} \"\${__farr_name:-\"\${__farr_gm_name_or_value}\"}\" \"\${__farr_fekey}\" \"\${__farr_feval}\" \"\${__farr_feidx}\" \"\$@\"" __farr_rv=$? [ ${__farr_rv} -ne 0 ] && return ${__farr_rv} else - _farr_fatal "alist \`${__farr_name}': missing value index" + _farr_fatal "alist \`${__farr_name:-"${__farr_gm_name_or_value}"}': missing value index" fi else - _farr_fatal "alist \`${__farr_name}': missing key index" + _farr_fatal "alist \`${__farr_name:-"${__farr_gm_name_or_value}"}': missing key index" fi __farr_feidx=$((__farr_feidx + 1)) done @@ -2843,31 +2814,52 @@ #: 0 #: falist_debug() { - local __farr_name + _farr_alist_debug '' "$@" +} + + +#: +#: Internal implementation of `falist_debug`. +#: +#: Args: +#: $1 (str): The indent +#: $2 (str): The name or the complete prefixed token of an alist. +#: +#: Returns: +#: 0 +#: +_farr_alist_debug() { + local __farr_debug_indent __farr_name local __farr_token __farr_objname __farr_keyname __farr_valname __farr_len local __farr_idx __farr_el_key __farr_el_val + __farr_debug_indent="${1}" + shift if ! _farr_alist_tryget_meta "$@"; then - echo "DEBUG: no (meta-)data for falist \`${1-}'" 1>&2 + printf "%sDEBUG: no (meta-)data for falist \`%s'\\n" "${__farr_debug_indent}" "${1-}" 1>&2 return 0 fi - echo "DEBUG: alist \`${__farr_name}' has length ${__farr_len}" 1>&2 + if [ -n "${__farr_name}" ]; then + printf "%sDEBUG: alist \`%s' has length %s\\n" "${__farr_debug_indent}" "${__farr_name}" "${__farr_len}" 1>&2 + else + printf "%sDEBUG: alist with token \`%s' has length %s\\n" "${__farr_debug_indent}" "${__farr_token}" "${__farr_len}" 1>&2 + fi __farr_idx=1 while [ ${__farr_idx} -le ${__farr_len} ]; do eval __farr_el_key=\"\$\{${__farr_keyname}_${__farr_idx}+SET\}\" if [ -z "${__farr_el_key}" ]; then - echo "DEBUG: key unexpectedly unset (index ${__farr_idx})" 1>&2 + printf "%sDEBqUG: key unexpectedly unset (index %s)\\n" "${__farr_debug_indent}" "${__farr_idx}" 1>&2 fi eval __farr_el_val=\"\$\{${__farr_valname}_${__farr_idx}+SET\}\" if [ -z "${__farr_el_val}" ]; then - echo "DEBUG: value unexpectedly unset (index ${__farr_idx})" 1>&2 + printf "%s DEBUG: value unexpectedly unset (index %s)\\n" "${__farr_debug_indent}" "${__farr_idx}" 1>&2 fi if [ \( -n "${__farr_el_key}" \) -a \( -n "${__farr_el_val}" \) ]; then eval __farr_el_key=\"\$\{${__farr_keyname}_${__farr_idx}\}\" eval __farr_el_val=\"\$\{${__farr_valname}_${__farr_idx}\}\" - printf "DEBUG: \`%s' -> \`%s'\\n" "${__farr_el_key}" "${__farr_el_val}" 1>&2 + printf "%sDEBUG: \`%s' -> \`%s'\\n" "${__farr_debug_indent}" "${__farr_el_key}" "${__farr_el_val}" 1>&2 fi __farr_idx=$((__farr_idx + 1)) done @@ -2893,11 +2885,11 @@ '') return 0;; "${_farr_array_token_prefix}"*) - _farr_array_destroy_value "$1" + farray_destroy "$1" # let the return value pass through ;; "${_farr_alist_token_prefix}"*) - _farr_alist_destroy_value "$1" + falist_destroy "$1" # let the return value pass through ;; *) diff -r 9c860f2abbdc -r a97ec3f07bdb tests/farray-alist.t --- a/tests/farray-alist.t Sat Oct 05 14:49:34 2024 +0200 +++ b/tests/farray-alist.t Sat Oct 05 21:55:55 2024 +0200 @@ -164,13 +164,20 @@ KEY: `K2', VAL: `V2 2' KEY: `K3', VAL: `" 111222333" \'444555 ' -ITERATE (for each) +ITERATE (for each, by name) $ falist_for_each LIST $'printf "EACH: %s key \\`%s\\\', value \\`%s\\\' at idx %d\\n"' # ` EACH: LIST key `K1', value `V1' at idx 1 EACH: LIST key `K2', value `V2 2' at idx 2 EACH: LIST key `K3', value `" 111222333" \'444555 ' at idx 3 +ITERATE (for each, by value) + + $ falist_for_each "$LIST" $'printf "EACH: %s key \\`%s\\\', value \\`%s\\\' at idx %d\\n"' # ` + EACH: _farr_KV\?\?_[a-f0-9]+ key `K1', value `V1' at idx 1 (re) + EACH: _farr_KV\?\?_[a-f0-9]+ key `K2', value `V2 2' at idx 2 (re) + EACH: _farr_KV\?\?_[a-f0-9]+ key `K3', value `" 111222333" \\'444555 ' at idx 3 (re) + $ falist_clear LIST $ falist_destroy LIST $ falist_destroy LIST @@ -416,8 +423,8 @@ $ _farr_destroy_object "$LIST" $ check_no_alist_artifacts $ (_farr_destroy_object "$LIST") - ERROR: falist with token value `_farr_KV\*_([a-f0-9]+)' not created properly: no object for token `\1' (re) - [1] + ERROR: falist `_farr_KV\?\?_([a-f0-9]+)' not created properly: no object for token `\1' (re) + [70] $ LIST='' $ _farr_destroy_object "$LIST" $ check_no_alist_artifacts diff -r 9c860f2abbdc -r a97ec3f07bdb tests/farray-array.t --- a/tests/farray-array.t Sat Oct 05 14:49:34 2024 +0200 +++ b/tests/farray-array.t Sat Oct 05 21:55:55 2024 +0200 @@ -45,6 +45,14 @@ DEBUG: 3: `2' DEBUG: 4: `3 4 5' DEBUG: 5: `" 678" \'90 ' +# $ farray_debug "$TEST" +# DEBUG: array with token `[a-f0-9]+' has length 5 (re) +# DEBUG: its contents: +# DEBUG: 1: `0' +# DEBUG: 2: `1' +# DEBUG: 3: `2' +# DEBUG: 4: `3 4 5' +# DEBUG: 5: `" 678" \'90 ' $ farray_destroy TEST $ check_no_array_artifacts @@ -915,6 +923,85 @@ $ check_no_array_artifacts +Iterating +========= + + $ farray_create TEST 0 1 2 '3 4 5' $'" 667788" \\\'910 ' 11 + +MANUAL (by name) + + $ _v='' + > _i=1 + > while farray_tryget _v TEST ${_i}; do + > printf " IDX: \`%d', VAL: \`%s'\\n" "${_i}" "${_v}" + > _i=$((_i + 1)) + > done + IDX: `1', VAL: `0' + IDX: `2', VAL: `1' + IDX: `3', VAL: `2' + IDX: `4', VAL: `3 4 5' + IDX: `5', VAL: `" 667788" \'910 ' + IDX: `6', VAL: `11' + +MANUAL (by value, reversed, using negative indexes) + + $ _v='' + > _i=0 + > while farray_tryget _v "$TEST" ${_i}; do + > printf " IDX: \`%d', VAL: \`%s'\\n" "${_i}" "${_v}" + > _i=$((_i - 1)) + > done + IDX: `0', VAL: `11' + IDX: `-1', VAL: `" 667788" \'910 ' + IDX: `-2', VAL: `3 4 5' + IDX: `-3', VAL: `2' + IDX: `-4', VAL: `1' + IDX: `-5', VAL: `0' + +ITERATE (for each, by name) + + $ farray_for_each TEST $'printf "EACH: %s at idx %d: value is \\`%s\\\'\\n"' + EACH: TEST at idx 1: value is `0' + EACH: TEST at idx 2: value is `1' + EACH: TEST at idx 3: value is `2' + EACH: TEST at idx 4: value is `3 4 5' + EACH: TEST at idx 5: value is `" 667788" \'910 ' + EACH: TEST at idx 6: value is `11' + +ITERATE (for each, by value) + + $ farray_for_each "$TEST" $'printf "EACH: %s at idx %d: value is \\`%s\\\'\\n"' + EACH: _farr_A\?_[a-f0-9]+ at idx 1: value is `0' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 2: value is `1' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 3: value is `2' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 4: value is `3 4 5' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 5: value is `" 667788" \\'910 ' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 6: value is `11' (re) + +REVERSE ITERATE (for each, by name) + + $ farray_reversed_for_each TEST $'printf "EACH: %s at idx %d: value is \\`%s\\\'\\n"' + EACH: TEST at idx 6: value is `11' + EACH: TEST at idx 5: value is `" 667788" \'910 ' + EACH: TEST at idx 4: value is `3 4 5' + EACH: TEST at idx 3: value is `2' + EACH: TEST at idx 2: value is `1' + EACH: TEST at idx 1: value is `0' + +ITERATE (for each, by value) + + $ farray_reversed_for_each "$TEST" $'printf "EACH: %s at idx %d: value is \\`%s\\\'\\n"' + EACH: _farr_A\?_[a-f0-9]+ at idx 6: value is `11' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 5: value is `" 667788" \\'910 ' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 4: value is `3 4 5' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 3: value is `2' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 2: value is `1' (re) + EACH: _farr_A\?_[a-f0-9]+ at idx 1: value is `0' (re) + + $ farray_destroy TEST + $ check_no_array_artifacts + + Eval / Quoting ============== @@ -990,7 +1077,7 @@ [70] $ ( farray_append ) - ERROR: missing farray name + ERROR: missing farray name or token value [70] $ TEST='' @@ -1002,7 +1089,7 @@ $ farray_create DUP $ (farray_create DUP) - ERROR: object `DUP' already created \(value `_farr_A\*_[a-f0-9]+'\) (re) + ERROR: object `DUP' already created \(value `_farr_A\?_[a-f0-9]+'\) (re) [70] $ check_no_array_artifacts @@ -1059,7 +1146,7 @@ $ _farr_destroy_object "$TEST" $ check_no_array_artifacts $ (_farr_destroy_object "$TEST") - ERROR: farray with token value `_farr_A\*_([a-f0-9]+)' not created properly: no storage for token `\1' (re) + ERROR: farray `_farr_A\?_([a-f0-9]+)' not created properly: no storage for token `\1' (re) [1] $ TEST='' $ _farr_destroy_object "$TEST"