summaryrefslogtreecommitdiff
path: root/lib/hash.sh
blob: 307ff90498c59860a46faa276563c09a6e3d7cb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
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
}