/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	#---------------------------------------------------------------------