Changeset 577


Ignore:
Timestamp:
12/22/2011 02:33:53 (5 months ago)
Author:
blee
Message:

Create a simpler library for dumping/loading Bash associative arrays
to/from files.

See #153

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/libfiledb.sh.in

    r576 r577  
    2525# $Id$ 
    2626# 
    27 # libfiledb.sh is a command-line tool for file-backed key-value stores. 
     27# libfiledb.sh is a shell library for file-backed key-value stores. 
    2828# 
    29 # libfiledb.sh uses the null character as its internal delimiter, so null 
    30 # characters are stripped from keys and values before being inserted into 
    31 # the database. 
     29# libfiledb.sh does not do any locking -- locking must be managed by the 
     30# caller as appropriate. 
     31# 
     32# The on-disk storage format uses the tab character as the field delimiter 
     33# and the new line character as the record delimiter.  Tab characters are 
     34# accepted in keys and values. 
    3235 
    33 FILEDB_VERSION="1.0" 
    34 OS_UNAME=`/usr/bin/uname` 
    35 CONFLOCK="@pkglibexecdir@/conflock" 
    36  
    37 # Purpose: Runs sed differently based on the running OS 
    38 # Inputs: Arguments to sed 
    39 # Prints: Output of sed 
    40 # Returns: 0 on success, 2 on error 
    41 os_sed() 
     36# Purpose: Load a filedb into an array 
     37# Inputs: filedb, array 
     38# Prints: N/A 
     39# Returns: 0 if the filedb was loaded into the array, 1 on error 
     40filedb_load() 
    4241{ 
    43         case ${OS_UNAME} in 
    44                 FreeBSD) 
    45                         /usr/bin/sed -i '' "$@" || return 2;; 
    46                 Linux) 
    47                         /bin/sed -i "$@" || return 2;; 
    48                 *) 
    49                         return 2;; 
    50         esac 
    51  
    52         return 0 
    53 } 
    54  
    55 # Purpose: Create a filedb 
    56 # Inputs: filedb 
    57 # Prints: N/A 
    58 # Returns: 0 if the filedb was created, 2 on error 
    59 filedb_create() 
    60 { 
    61         if [ $# -ne 1 ]; then 
    62                 return 2 
     42        if [ -z "${1-}" -o -z "${2-}" ]; then 
     43                return 1 
    6344        fi 
    6445 
    6546        local filedb="$1" 
     47        local array="$2" 
    6648 
    67         local lock_type 
     49        local key 
     50        local value 
    6851 
    69         lock_type=`filedb_lock "${filedb}"` || return 2 
     52        [ -r "${filedb}" ] && 
     53        [ -v "${array}" ] && 
     54        local IFS="     " 
     55        while read -r key value; do 
     56                eval "`echo "${array}"`[`echo -e "${key}"`]=`echo -e "${value}"`" 
     57        done <"${filedb}" && 
     58        return 0 
    7059 
    71         ! [ -f "${filedb}" ] && 
    72                 touch "${filedb}" && 
    73                 filedb_set_value "${filedb}" "filedb:version" "${FILEDB_VERSION}" && 
    74                 filedb_unlock "${filedb}" "${lock_type}" && 
    75                 return 0 
    76  
    77         filedb_unlock "${filedb}" "${lock_type}" 
    78         return 2 
     60        return 1 
    7961} 
    8062 
    81 # Purpose: Recursively lock a filedb 
    82 # Inputs: filedb 
    83 # Prints: "recursive" or "original" depending on the type of lock acquired 
    84 # Returns: 0 if the filedb was locked, 2 on error 
    85 filedb_lock() 
     63# Purpose: Write an array into a filedb 
     64# Inputs: array, filedb 
     65# Prints: N/A 
     66# Returns: 0 if the array was written into the filedb, 1 on error 
     67filedb_write() 
    8668{ 
    87         if [ $# -ne 1 ]; then 
    88                 return 2 
     69        if [ -z "${1-}" -o -z "${2-}" ]; then 
     70                return 1 
    8971        fi 
    9072 
    91         local filedb="$1" 
     73        local array="$1" 
     74        local filedb="$2" 
    9275 
    93         local lock_type 
    94  
    95         # If this process already has the lock, this is a recursive lock 
    96         if filedb_is_locked "${filedb}"; then 
    97                 lock_type="recursive" 
    98         else 
    99                 lock_type="original" 
    100         fi 
    101  
    102         "${CONFLOCK}" lock $$ "${filedb}.lock" || return 2 
    103  
    104         echo "${lock_type}" 
    105         return 0 
    106 } 
    107  
    108 # Purpose: Recursively lock a filedb if it exists 
    109 # Inputs: filedb 
    110 # Prints: "recursive" or "original" depending on the type of lock acquired 
    111 # Returns: 0 if the filedb was locked, 2 on error 
    112 filedb_lock_if_exists() 
    113 { 
    114         if [ $# -ne 1 ]; then 
    115                 return 2 
    116         fi 
    117  
    118         local filedb="$1" 
    119  
    120         local lock_type 
    121  
    122         lock_type=`filedb_lock "${filedb}"` || return 2 
    123  
    124         [ -f "${filedb}" ] && 
    125                 echo "${lock_type}" && 
    126                 return 0 
    127  
    128         filedb_unlock "${filedb}" "${lock_type}" 
    129         return 2 
    130 } 
    131  
    132 # Purpose: Unlock a filedb 
    133 # Inputs: filedb, lock type 
    134 # Prints: N/A 
    135 # Returns: 0 if the filedb was unlocked, 2 on error 
    136 filedb_unlock() 
    137 { 
    138         if [ $# -ne 2 ]; then 
    139                 return 2 
    140         fi 
    141  
    142         local filedb="$1" 
    143         local lock_type="$2" 
    144  
    145         case "${lock_type}" in 
    146                 recursive) 
    147                         return 0;; 
    148                 original) 
    149                         "${CONFLOCK}" unlock $$ "${filedb}.lock" || return 2;; 
    150                 *) 
    151                         return 2;; 
    152         esac 
    153  
    154         return 0 
    155 } 
    156  
    157 # Purpose: Test whether a filedb is locked 
    158 # Inputs: filedb 
    159 # Prints: N/A 
    160 # Returns: 0 if the filedb is locked, 1 if the filedb is not locked, 2 on error 
    161 filedb_is_locked() 
    162 { 
    163         if [ $# -ne 1 ]; then 
    164                 return 2 
    165         fi 
    166  
    167         local filedb="$1" 
    168  
    169         local rv 
    170  
    171         "${CONFLOCK}" haslock $$ "${filedb}.lock" 
    172         rv=$? 
    173          
    174         case ${rv} in 
    175                 0|1) 
    176                         return ${rv};; 
    177                 *) 
    178                         return 2;; 
    179         esac 
    180 } 
    181  
    182 # Purpose: Get the list of keys 
    183 # Inputs: filedb 
    184 # Prints: The list of keys 
    185 # Returns: 0 on success, 2 on error 
    186 filedb_get_keys() 
    187 { 
    188         if [ $# -ne 1 ]; then 
    189                 return 2 
    190         fi 
    191  
    192         local filedb="$1" 
    193  
    194         local lock_type 
    195  
    196         lock_type=`filedb_lock_if_exists "${filedb}"` || return 2 
    197  
    198         awk -F '\0' '{print $1}' "${filedb}" && 
    199                 filedb_unlock "${filedb}" "${lock_type}" && 
    200                 return 0 
    201  
    202         filedb_unlock "${filedb}" "${lock_type}" 
    203         return 2 
    204 } 
    205  
    206 # Purpose: Get the list of values 
    207 # Inputs: filedb 
    208 # Prints: The list of values 
    209 # Returns: 0 on success, 2 on error 
    210 filedb_get_values() 
    211 { 
    212         if [ $# -ne 1 ]; then 
    213                 return 2 
    214         fi 
    215  
    216         local filedb="$1" 
    217  
    218         local lock_type 
    219  
    220         lock_type=`filedb_lock_if_exists "${filedb}"` || return 2 
    221  
    222         awk -F '\0' '{print $2}' "${filedb}" && 
    223                 filedb_unlock "${filedb}" "${lock_type}" && 
    224                 return 0 
    225  
    226         filedb_unlock "${filedb}" "${lock_type}" 
    227         return 2 
    228 } 
    229  
    230 # Purpose: Test whether a key exists 
    231 # Inputs: filedb, key 
    232 # Prints: N/A 
    233 # Returns: 0 if the key exists, 1 if the key does not exist, 2 on error 
    234 filedb_key_exists() 
    235 { 
    236         if [ $# -ne 2 ]; then 
    237                 return 2 
    238         fi 
    239  
    240         local filedb="$1" 
    241         local key=`echo "$2" | tr -d '\0'` 
    242  
    243         local lock_type 
    244         local rv 
    245  
    246         lock_type=`filedb_lock_if_exists "${filedb}"` || return 2 
    247  
    248         awk -F '\0' '{if ($1 == "'"${key}"'") {_assert_exit = 1; exit}}; END {if (_assert_exit) exit 0; exit 1}' "${filedb}" 
    249         rv=$? 
    250  
    251         case ${rv} in 
    252                 0|1) 
    253                         filedb_unlock "${filedb}" "${lock_type}" || return 2 
    254                         return ${rv};; 
    255         esac 
    256  
    257         filedb_unlock "${filedb}" "${lock_type}" 
    258         return 2 
    259 } 
    260  
    261 # Purpose: Get the value for a key 
    262 # Inputs: filedb, key 
    263 # Prints: The value for the key 
    264 # Returns: 0 if the value was retrieved, 2 on error 
    265 filedb_get_value() 
    266 { 
    267         if [ $# -ne 2 ]; then 
    268                 return 2 
    269         fi 
    270  
    271         local filedb="$1" 
    272         local key=`echo "$2" | tr -d '\0'` 
    273  
    274         local lock_type 
     76        local i 
     77        local key 
    27578        local value 
    27679 
    277         lock_type=`filedb_lock_if_exists "${filedb}"` || return 2 
     80        [ -w "${filedb}" -o -w "`dirname "${filedb}"`" ] && 
     81        [ -v "${array}" ] && 
     82        eval 'for i in "'"\${!${array}"'[@]}"; do 
     83                echo "${i}" 
     84        done' | while read key; do 
     85                eval 'value="'"\${${array}[${key}]}"'"' 
     86                echo -nE "${key%%       *}" 
     87                while [ "${key}" != "${key#*    }" ]; do 
     88                        key="${key#*    }" 
     89                        echo -nE "\\t${key%%    *}" 
     90                done 
     91                echo -n "       " 
     92                echo -nE "${value%%     *}" 
     93                while [ "${value}" != "${value#*        }" ]; do 
     94                        value="${value#*        }" 
     95                        echo -nE "\\t${value%%  *}" 
     96                done 
     97                echo 
     98        done > "${filedb}" && 
     99        return 0 
    278100 
    279         filedb_key_exists "${filedb}" "${key}" && 
    280                 value=`awk -F '\0' '{if ($1 == "'"${key}"'") print $2}' "${filedb}"` && 
    281                 echo "${value}" && 
    282                 filedb_unlock "${filedb}" "${lock_type}" && 
    283                 return 0 
    284  
    285         filedb_unlock "${filedb}" "${lock_type}" 
    286         return 2 
     101        return 1 
    287102} 
    288  
    289 # Purpose: Delete a key 
    290 # Inputs: filedb, key 
    291 # Prints: N/A 
    292 # Returns: 0 if the key was deleted, 2 on error 
    293 filedb_delete_key() 
    294 { 
    295         if [ $# -ne 2 ]; then 
    296                 return 2 
    297         fi 
    298  
    299         local filedb="$1" 
    300         local key=`echo "$2" | tr -d '\0'` 
    301  
    302         local lock_type 
    303         local line 
    304  
    305         lock_type=`filedb_lock_if_exists "${filedb}"` || return 2 
    306  
    307         line=`awk -F '\0' '{if ($1 == "'"${key}"'") print NR}' "${filedb}"` && 
    308                 [ -n "${line}" ] && 
    309                 os_sed "${line} d" "${filedb}" && 
    310                 filedb_unlock "${filedb}" "${lock_type}" && 
    311                 return 0 
    312  
    313         filedb_unlock "${filedb}" "${lock_type}" 
    314         return 2 
    315 } 
    316  
    317 # Purpose: Set a value for a key 
    318 # Inputs: filedb, key, value 
    319 # Prints: N/A 
    320 # Returns: 0 if the value was set, 2 on error 
    321 filedb_set_value() 
    322 { 
    323         if [ $# -ne 3 ]; then 
    324                 return 2 
    325         fi 
    326  
    327         local filedb="$1" 
    328         local key=`echo "$2" | tr -d '\0'` 
    329         local value=`echo "$3" | tr -d '\0'` 
    330  
    331         local lock_type 
    332         local rv 
    333  
    334         lock_type=`filedb_lock_if_exists "${filedb}"` || return 2 
    335  
    336         filedb_key_exists "${filedb}" "${key}" 
    337         rv=$? 
    338          
    339         case ${rv} in 
    340                 0) 
    341                         if ! filedb_delete_key "${filedb}" "${key}"; then 
    342                                 filedb_unlock "${filedb}" "${lock_type}" 
    343                                 return 2 
    344                         fi;; 
    345                 1) 
    346                         :;; 
    347                 *) 
    348                         filedb_unlock "${filedb}" "${lock_type}" 
    349                         return 2;; 
    350         esac 
    351  
    352         printf "${key}\\000${value}\\n" >> "${filedb}" && 
    353                 filedb_unlock "${filedb}" "${lock_type}" && 
    354                 return 0 
    355  
    356         filedb_unlock "${filedb}" "${lock_type}" 
    357         return 2 
    358 } 
Note: See TracChangeset for help on using the changeset viewer.