/var/lib/sorcery/modules/libhash
1 #!/bin/bash
2 #---------------------------------------------------------------------
3 ##
4 ## Set of functions for working with an associative array type data
5 ## structure. Values can be stored and retrieved using strings as
6 ## the index into the data structure instead of numbers.
7 ##
8 ## The hash data structure provided in this file allows you to store
9 ## values into fields of a table. The 'hash_put' function takes the
10 ## name of the table, a field name in the table, and the value to be
11 ## stored in the table. The 'hash_get' function retrieves a value from
12 ## the table given the table and field name.
13 ##
14 ## <pre>
15 ## To store a value into a field of a table, use hash_put:
16 ##
17 ## hash_put "myTable" "aField" "theValue"
18 ##
19 ## The value stored in the table can be retrieved with hash_get:
20 ##
21 ## hash_get "myTable" "aField"
22 ##
23 ## In this example, the hash_get function would echo "theValue".
24 ## hash_get_ref can also be used here and has the benefit of being forkless.
25 ## </pre>
26 ## <br />
27 ## <p>IMPLEMENTATION NOTE</p>
28 ## <br />
29 ## Bash does not provide direct support for hash tables. These
30 ## functions are implemented by first building a variable using the
31 ## table name and field name, then using the eval function to store
32 ## (retrieve) value into (from) the variable.<br />
33 ##
34 ## The idea for the hash data structure in bash was inspired by a
35 ## short example by Phil Howard which shows the use of hashes in bash.
36 ## Phil Howard's original example can be found here:
37 ##
38 ## http://www.codebits.com/bit.cfm?BitID=92
39 ##
40 ## @Copyright Copyright 2002 by the Source Mage Team
41 ##
42 ##
43 #---------------------------------------------------------------------
44
45
46 #---------------------------------------------------------------------
47 ## @param table name
48 ## @param field name
49 ## @param returning variable
50 ## @Type Private
51 ## Given a table and field name, bulds the name of
52 ## the variable into which a value will be stored. Also changes '+',
53 ## '-', and '.' in the table name into text since bash doesn't like
54 ## variable names with those characters.
55 ##
56 #---------------------------------------------------------------------
57 function hash_build_variable_name() {
58 local ___TABLE="$1"
59 local ___FIELD="$2"
60
61 # debug "libhash" "hash_build_variable_name() - TABLE=$___TABLE:FIELD=$___FIELD"
62
63 ___TABLE=${___TABLE//\+/_P_}
64 ___TABLE=${___TABLE//\-/_M_}
65 ___TABLE=${___TABLE//\./_D_}
66 ___TABLE=${___TABLE//\:/_CLN_}
67 ___TABLE=${___TABLE// /_SPC_}
68 ___TABLE=${___TABLE//[/_OSB_}
69 ___TABLE=${___TABLE//]/_CSB_}
70
71 if [[ $___FIELD ]] ; then
72 ___FIELD=${___FIELD//\+/_P_}
73 ___FIELD=${___FIELD//\-/_M_}
74 ___FIELD=${___FIELD//\./_D_}
75 ___FIELD=${___FIELD//\:/_CLN_}
76 ___FIELD=${___FIELD// /_SPC_}
77 ___FIELD=${___FIELD//]/_CSB_}
78 ___FIELD=${___FIELD//]/_OSB_}
79 fi
80
81 # If this format is changed, modify hash_get_table_fields to suite
82 if [[ $___FIELD ]] ; then ___FIELD="HASH_${___TABLE}_${___FIELD}_"
83 else ___FIELD="HASH_${___TABLE}_" ; fi
84
85 eval $3=\"\$___FIELD\"
86 }
87
88
89 #---------------------------------------------------------------------
90 ## @param field name
91 ## @param table name
92 ## @param returning variable
93 ## @Type Private
94 ## most likely reverses hash_build_field_name
95 ##
96 #---------------------------------------------------------------------
97 function hash_unbuild_field_name() {
98 local ___TABLE="$2"
99 local ___FIELD=${1#$___TABLE}
100 ___FIELD=${___FIELD%_*}
101 # `echo "$1" | sed -n "s/^$2\(.*\)_$/\1/p"`
102
103 # debug "libhash" "hash_unbuild_field_name() - TABLE=$___TABLE:FIELD=$___FIELD"
104
105 ___FIELD=${___FIELD//_P_/\+}
106 ___FIELD=${___FIELD//_M_/\-}
107 ___FIELD=${___FIELD//_D_/\.}
108 ___FIELD=${___FIELD//_CLN_/\:}
109 ___FIELD=${___FIELD//_SPC_/ }
110 ___FIELD=${___FIELD//_CSB_/]}
111 ___FIELD=${___FIELD//_OSB_/[}
112
113 eval $3=\"\$___FIELD\"
114 }
115
116
117 #---------------------------------------------------------------------
118 ## @param table name
119 ## @param field name
120 ## @param value
121 ##
122 ## Saves the value in the specified table/field.
123 ##
124 #---------------------------------------------------------------------
125 function hash_put() {
126 local VARIABLE_NAME
127 hash_build_variable_name "$1" "$2" VARIABLE_NAME
128 eval "${VARIABLE_NAME}=\"\${3}\""
129 debug "libhash" "hash_put() - VARIABLE_NAME=$VARIABLE_NAME, data=$3"
130 }
131
132
133 #---------------------------------------------------------------------
134 ## @param table name
135 ## @param field name
136 ##
137 ## @Stdout Value stored in table/field
138 ## Echos the value stored in the table/field. If no value was
139 ## previously stored in the table/field, this function echos an empty
140 ## string.
141 ##
142 #---------------------------------------------------------------------
143 function hash_get() {
144 local VARIABLE_NAME
145 hash_build_variable_name "$1" "$2" VARIABLE_NAME
146 echo "${!VARIABLE_NAME}"
147 }
148
149 #---------------------------------------------------------------------
150 ## @param table name
151 ## @param field name
152 ## @param upvar name
153 ##
154 ## @Stdout none
155 ## Returns the value stored in the table/field through the upvar variable
156 ## name. If no value was previously stored in the table/field, then an
157 ## empty string is returned.
158 ##
159 #---------------------------------------------------------------------
160 function hash_get_ref() {
161 local VARIABLE_NAME
162 hash_build_variable_name "$1" "$2" VARIABLE_NAME
163 eval "$3=\${!VARIABLE_NAME}"
164 }
165
166 #---------------------------------------------------------------------
167 ## @param table name
168 ## @param field name
169 ## @param value
170 ##
171 ## Appends the value to the specified table/field.
172 ##
173 #---------------------------------------------------------------------
174 function hash_append() {
175 local VARIABLE_NAME
176 local old_value
177 local sep=${4:-" "}
178 hash_build_variable_name "$1" "$2" VARIABLE_NAME
179 old_value=${!VARIABLE_NAME}
180 if [[ -n $old_value ]] ; then
181 eval "${VARIABLE_NAME}=\"\$old_value\${sep}\${3}\""
182 else
183 eval "${VARIABLE_NAME}=\"\$3\""
184 fi
185 }
186
187 #---------------------------------------------------------------------
188 ## @param table name
189 ##
190 ## 'export' all the values in the table. This is useful for getting
191 ## hash table data from cast's pass_one/two into pass_three/pass_four
192 ## which are run through make. Essentially exporting lets us pass
193 ## the variables through make.
194 ##
195 #---------------------------------------------------------------------
196 function hash_export() {
197 local VARIABLE_NAME
198 hash_build_variable_name $1 "" VARIABLE_NAME
199 # make sure the hash has something in it before trying to export it
200 [[ $(eval echo '${!'$VARIABLE_NAME'*}') ]] &&
201 eval 'export ${!'$VARIABLE_NAME'*}'
202 }
203
204 #---------------------------------------------------------------------
205 ## @param table name
206 ## @param field name
207 ##
208 ## Unsets field. Deletes value.
209 ##
210 #---------------------------------------------------------------------
211 function hash_unset() {
212 local VARIABLE_NAME
213 hash_build_variable_name "$1" "$2" VARIABLE_NAME
214 unset ${VARIABLE_NAME}
215 }
216
217 #---------------------------------------------------------------------
218 ## @param table name
219 ## @param field name
220 ## @param item
221 ##
222 ## The reverse of hash_append, it removes an item from the field's value.
223 ##
224 #---------------------------------------------------------------------
225 function hash_unset_part() {
226 local VARIABLE_NAME
227 local old_value
228 local item=$3
229 hash_build_variable_name "$1" "$2" VARIABLE_NAME
230 old_value=${!VARIABLE_NAME}
231 if [[ -n $old_value ]] && real_list_find "$old_value" "$item"; then
232 real_list_remove old_value "$item"
233 if [[ -n $old_value ]]; then
234 upvar $VARIABLE_NAME "$old_value"
235 else
236 unset $VARIABLE_NAME
237 fi
238 fi
239 }
240
241 #---------------------------------------------------------------------
242 ## @param table name
243 ##
244 ## Unsets all fields in a table.
245 ##
246 #---------------------------------------------------------------------
247 function hash_reset() {
248 local TABLE_NAME
249 hash_build_variable_name "$1" '' TABLE_NAME
250 eval "local VARIABLES=\"\${!${TABLE_NAME}*}\""
251 unset $VARIABLES
252
253 }
254
255 #---------------------------------------------------------------------
256 ## @param table name
257 ## @param opt delimiter
258 ## @Stdout table data
259 ## Outputs the entire table data, with fields separated by the
260 ## optional delimiter. If no delimiter is give, \n will be used.
261 ##
262 #---------------------------------------------------------------------
263 function hash_get_table() {
264
265 local TABLE_NAME
266 hash_build_variable_name "$1" '' TABLE_NAME
267 local VARIABLES i
268 local separator="$2"
269 separator=${separator:-$'\n'}
270 eval "VARIABLES=\"\${!${TABLE_NAME}*}\""
271
272 for i in $VARIABLES; do
273 echo -n "${!i}${separator}"
274 done
275
276 }
277
278
279 #---------------------------------------------------------------------
280 ## @param table name
281 ## @param opt delimiter
282 ## @Stdout Fields in table
283 ## Outputs all of the fields in the table , with fields separated
284 ## by the optional delimiter. If no delimiter is give, \n wil be
285 ## used.
286 ##
287 #---------------------------------------------------------------------
288 function hash_get_table_fields() {
289
290 local TABLE_NAME
291 hash_build_variable_name "$1" '' TABLE_NAME
292 local VARIABLES i
293 local separator="$2"
294 separator=${separator:-$'\n'}
295 eval "VARIABLES=\"\${!${TABLE_NAME}*}\""
296
297 local FIELD
298 for i in $VARIABLES ; do
299 hash_unbuild_field_name "$i" "$TABLE_NAME" FIELD
300 echo -n "${FIELD}${separator}"
301 done
302
303 }
304
305 #---------------------------------------------------------------------
306 ## @param table name
307 ## @Stdout Print the table in some reasonably readable form
308 ## As the name would imply, this is mainly for development use
309 ## and is not intended for regular use.
310 ##
311 #---------------------------------------------------------------------
312 function hash_debug_dump() {
313 local TABLE_NAME
314 local FIELD
315 local value
316 for FIELD in $(hash_get_table_fields $1); do
317 hash_get_ref $1 $FIELD value
318 echo "$FIELD : $value"
319 done
320 }
321
322
323 #---------------------------------------------------------------------
324 ## @License
325 ##
326 ## This software is free software; you can redistribute it and/or modify
327 ## it under the terms of the GNU General Public License as published by
328 ## the Free Software Foundation; either version 2 of the License, or
329 ## (at your option) any later version.
330 ##
331 ## This software is distributed in the hope that it will be useful,
332 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
333 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
334 ## GNU General Public License for more details.
335 ##
336 ## You should have received a copy of the GNU General Public License
337 ## along with this software; if not, write to the Free Software
338 ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
339 ##
340 #---------------------------------------------------------------------