diff options
Diffstat (limited to 'lib/hash.sh')
-rw-r--r-- | lib/hash.sh | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/lib/hash.sh b/lib/hash.sh new file mode 100644 index 0000000..307ff90 --- /dev/null +++ b/lib/hash.sh @@ -0,0 +1,312 @@ +#!/bin/bash +# -*- coding: utf-8 -*- +########################################################################### +# # +# envbot - an IRC bot in bash # +# Copyright (C) 2007-2008 Arvid Norlander # +# # +# 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 # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see <http://www.gnu.org/licenses/>. # +# # +########################################################################### +#--------------------------------------------------------------------- +## Functions for working with associative arrays. +#--------------------------------------------------------------------- + +#--------------------------------------------------------------------- +## Convert a string to hex +## @Type Private +## @param String to convert +## @param Name of variable to return result in. +#--------------------------------------------------------------------- +hash_hexify() { + # Res will contain full output string, hex current char. + local hex i res= + for ((i=0;i<${#1};i++)); do + # The ' is not documented in bash but it works. + # See http://www.opengroup.org/onlinepubs/009695399/utilities/printf.html + # for documentation of the ' syntax for printf. + printf -v hex '%x' "'${1:i:1}" + # Add to string + res+=$hex + done + # Print to variable. + printf -v "$2" '%s' "$res" +} + +#--------------------------------------------------------------------- +## Convert a string from hex to normal +## @Type Private +## @param String to convert +## @param Name of variable to return result in. +#--------------------------------------------------------------------- +hash_unhexify() { + # Res will contain full output string, unhex current char. + local unhex i=0 res= + for ((i=0;i<${#1};i+=2)); do + # Convert back from hex. 2 chars at a time + # FIXME: This will break if output would be multibyte chars. + printf -v unhex \\"x${1:i:2}" + res+=$unhex + done + printf -v "$2" '%s' "$res" +} + +#--------------------------------------------------------------------- +## Generate variable name for a item in the hash array. +## @Type Private +## @param Table name +## @param Index +## @param Name of variable to return result in. +#--------------------------------------------------------------------- +hash_name_create() { + local hexindex + hash_hexify "$2" 'hexindex' + printf -v "$3" '%s' "hsh_${1}_${hexindex}" +} + +#--------------------------------------------------------------------- +## Translate a variable name to an entry index name. +## @param Variable name +## @param Return value for index +#--------------------------------------------------------------------- +hash_name_getindex() { + local unhexindex tablename indexname + local IFS="_" + read -r tablename indexname <<< "${1/hsh_//}" + unset IFS + hash_unhexify "$indexname" "$2" +} + + +#--------------------------------------------------------------------- +## Sets (overwrites any older) a value in a hash array +## @Type API +## @param Table name +## @param Index +## @param Value +#--------------------------------------------------------------------- +hash_set() { + local varname + # Get variable name + hash_name_create "$1" "$2" 'varname' + # Set it using the printf to variable + printf -v "$varname" '%s' "$3" +} + +#--------------------------------------------------------------------- +## Append a value to the end of an entry in a hash array +## @Type API +## @param Table name +## @param Index +## @param Value to append +## @param Separator (optional, defaults to space) +#--------------------------------------------------------------------- +hash_append() { + local varname + # Get variable name + hash_name_create "$1" "$2" 'varname' + # Append to end, or if empty just set. + if [[ "${!varname}" ]]; then + local sep=${4:-" "} + printf -v "$varname" '%s' "${!varname}${sep}${3}" + else + printf -v "$varname" '%s' "$3" + fi +} + +#--------------------------------------------------------------------- +## Opposite of <@function hash_append>, removes a value from a list +## in a hash entry +## @Type API +## @param Table name +## @param Index +## @param Value to remove +## @param Separator (optional, defaults to space) +#--------------------------------------------------------------------- +hash_substract() { + local varname + # Get variable name + hash_name_create "$1" "$2" 'varname' + # If not empty try to remove value + if [[ "${!varname}" ]]; then + local sep=${4:-" "} + # FIXME: substrings of the entries in the list may match :/ + local list="${!varname}" + list="${list//$3}" + # Remove any double $sep caused by this. + list="${list//$sep$sep/$sep}" + printf -v "$varname" '%s' "$list" + fi +} + +#--------------------------------------------------------------------- +## Replace a value in list style hash entry. +## @Type API +## @param Table name +## @param Index +## @param Value to replace +## @param Value to replace with +## @param Separator (optional, defaults to space) +#--------------------------------------------------------------------- +hash_replace() { + local varname + # Get variable name + hash_name_create "$1" "$2" 'varname' + # Append to end, or if empty just set. + local sep=${5:-" "} + if [[ "${!varname}" =~ (^|$sep)${3}($sep|$) ]]; then + # FIXME: substrings of the entries in the list may match :/ + local list="${!varname}" + list="${list//$3/$4}" + printf -v "$varname" '%s' "$list" + fi +} + +#--------------------------------------------------------------------- +## Removes an entry (if it exists) from a hash array +## @Note If the entry does not exist, nothing will happen +## @Type API +## @param Table name +## @param Index +#--------------------------------------------------------------------- +hash_unset() { + local varname + # Get variable name + hash_name_create "$1" "$2" 'varname' + unset "${varname}" +} + +#--------------------------------------------------------------------- +## Gets a value (if it exists) from a hash array +## @Note If value does not exist, the variable will be empty. +## @Type API +## @param Table name +## @param Index +## @param Name of variable to return result in. +#--------------------------------------------------------------------- +hash_get() { + local varname + # Get variable name + hash_name_create "$1" "$2" 'varname' + # Now print out to variable using indirect ref to get the value. + printf -v "$3" '%s' "${!varname}" +} + +#--------------------------------------------------------------------- +## Check if a list style hash entry contains a specific value. +## @Type API +## @param Table name +## @param Index +## @param Value to check for +## @param Separator (optional, defaults to space) +## @return 0 Found +## @return 1 Not found (or hash doesn't exist). +#--------------------------------------------------------------------- +hash_contains() { + local varname + # Get variable name + hash_name_create "$1" "$2" 'varname' + + local sep=${4:-" "} + if [[ "${sep}${!varname}${sep}" =~ ${sep}${3}${sep} ]]; then + return 0 + else + return 1 + fi +} + +#--------------------------------------------------------------------- +## Check if a any space separated entry in a hash array contains +## a specific value. +## @Type API +## @param Table name +## @param Value to check for +## @return 0 Found +## @return 1 Not found (or hash doesn't exist). +#--------------------------------------------------------------------- +hash_search() { + # Get variable names + eval "local vars=\"\${!hsh_${1}_*}\"" + # Append to end, or if empty just set. + if [[ $vars ]]; then + local var + # Extract index. + for var in $vars; do + [[ "${!varname}" =~ (^| )${2}( |$) ]] && return 0 + done + fi + return 1 +} + +#--------------------------------------------------------------------- +## Check if an entry exists in a hash array +## @Type API +## @param Table name +## @param Index +## @return 0 If the entry exists +## @return 1 If the entry doesn't exist +#--------------------------------------------------------------------- +hash_exists() { + local varname + hash_name_create "$1" "$2" 'varname' + # This will return the return code we want. + [[ "${!varname}" ]] +} + +#--------------------------------------------------------------------- +## Removes an entire hash array +## @Type API +## @param Table name +## @return 0 Ok +## @return 1 Other error +## @return 2 Table not found +#--------------------------------------------------------------------- +hash_reset() { + # Get all variables with a prefix + eval "local vars=\"\${!hsh_${1}_*}\"" + # If any variable, unset them. + if [[ $vars ]]; then + unset ${vars} || return 1 + else + return 2 + fi +} + +#--------------------------------------------------------------------- +## Returns a space separated list of the indices of a hash array +## @Type API +## @param Table name +## @param Name of variable to return result in. +## @return 0 Ok +## @return 1 Other error +## @return 2 Table not found +#--------------------------------------------------------------------- +hash_get_indices() { + # Get all variables with a prefix + eval "local vars=\"\${!hsh_${1}_*}\"" + # If any variable loop through and get the "normal" index. + if [[ $vars ]]; then + local var unhexname returnlist + # Extract index. + for var in $vars; do + hash_name_getindex "$var" 'unhexname' + returnlist+=" $unhexname" + done + # Return them in variable. + printf -v "$2" '%s' "${returnlist}" + return 0 + else + return 2 + fi +} |