6fc29d1c42
If a JSON file might be read by a human, say for debugging, it could be useful to pretty-print it. We do this in places by calling "json_dump -i" but it shouldn't be necessary to know the arguments to "jshn" (and indeed, that's not portable if we retool the underlying implementation). Conversely output that's ephemeral doesn't need to be pretty (say being piped as input to another command). Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
348 lines
5.9 KiB
Bash
348 lines
5.9 KiB
Bash
# functions for parsing and generating json
|
|
|
|
_json_get_var() {
|
|
# dest=$1
|
|
# var=$2
|
|
eval "$1=\"\$${JSON_PREFIX}$2\""
|
|
}
|
|
|
|
_json_set_var() {
|
|
# var=$1
|
|
local ___val="$2"
|
|
eval "${JSON_PREFIX}$1=\"\$___val\""
|
|
}
|
|
|
|
__jshn_raw_append() {
|
|
# var=$1
|
|
local value="$2"
|
|
local sep="${3:- }"
|
|
|
|
eval "export -- \"$1=\${$1:+\${$1}\${value:+\$sep}}\$value\""
|
|
}
|
|
|
|
_jshn_append() {
|
|
# var=$1
|
|
local _a_value="$2"
|
|
eval "${JSON_PREFIX}$1=\"\${${JSON_PREFIX}$1} \$_a_value\""
|
|
}
|
|
|
|
_get_var() {
|
|
# var=$1
|
|
# value=$2
|
|
eval "$1=\"\$$2\""
|
|
}
|
|
|
|
_set_var() {
|
|
# var=$1
|
|
local __val="$2"
|
|
eval "$1=\"\$__val\""
|
|
}
|
|
|
|
_json_inc() {
|
|
# var=$1
|
|
# dest=$2
|
|
|
|
let "${JSON_PREFIX}$1 += 1" "$2 = ${JSON_PREFIX}$1"
|
|
}
|
|
|
|
_json_add_generic() {
|
|
# type=$1
|
|
# name=$2
|
|
# value=$3
|
|
# cur=$4
|
|
|
|
local var
|
|
if [ "${4%%[0-9]*}" = "J_A" ]; then
|
|
_json_inc "S_$4" var
|
|
else
|
|
var="${2//[^a-zA-Z0-9_]/_}"
|
|
[[ "$var" == "$2" ]] || export -- "${JSON_PREFIX}N_${4}_${var}=$2"
|
|
fi
|
|
|
|
export -- \
|
|
"${JSON_PREFIX}${4}_$var=$3" \
|
|
"${JSON_PREFIX}T_${4}_$var=$1"
|
|
_jshn_append "JSON_UNSET" "${4}_$var"
|
|
_jshn_append "K_$4" "$var"
|
|
}
|
|
|
|
_json_add_table() {
|
|
# name=$1
|
|
# type=$2
|
|
# itype=$3
|
|
local cur seq
|
|
|
|
_json_get_var cur JSON_CUR
|
|
_json_inc JSON_SEQ seq
|
|
|
|
local table="J_$3$seq"
|
|
_json_set_var "U_$table" "$cur"
|
|
export -- "${JSON_PREFIX}K_$table="
|
|
unset "${JSON_PREFIX}S_$table"
|
|
_json_set_var JSON_CUR "$table"
|
|
_jshn_append "JSON_UNSET" "$table"
|
|
|
|
_json_add_generic "$2" "$1" "$table" "$cur"
|
|
}
|
|
|
|
_json_close_table() {
|
|
local _s_cur
|
|
|
|
_json_get_var _s_cur JSON_CUR
|
|
_json_get_var "${JSON_PREFIX}JSON_CUR" "U_$_s_cur"
|
|
}
|
|
|
|
json_set_namespace() {
|
|
local _new="$1"
|
|
local _old="$2"
|
|
|
|
[ -n "$_old" ] && _set_var "$_old" "$JSON_PREFIX"
|
|
JSON_PREFIX="$_new"
|
|
}
|
|
|
|
json_cleanup() {
|
|
local unset tmp
|
|
|
|
_json_get_var unset JSON_UNSET
|
|
for tmp in $unset J_V; do
|
|
unset \
|
|
${JSON_PREFIX}U_$tmp \
|
|
${JSON_PREFIX}K_$tmp \
|
|
${JSON_PREFIX}S_$tmp \
|
|
${JSON_PREFIX}T_$tmp \
|
|
${JSON_PREFIX}N_$tmp \
|
|
${JSON_PREFIX}$tmp
|
|
done
|
|
|
|
unset \
|
|
${JSON_PREFIX}JSON_SEQ \
|
|
${JSON_PREFIX}JSON_CUR \
|
|
${JSON_PREFIX}JSON_UNSET
|
|
}
|
|
|
|
json_init() {
|
|
json_cleanup
|
|
export -n ${JSON_PREFIX}JSON_SEQ=0
|
|
export -- \
|
|
${JSON_PREFIX}JSON_CUR="J_V" \
|
|
${JSON_PREFIX}K_J_V=
|
|
}
|
|
|
|
json_add_object() {
|
|
_json_add_table "$1" object T
|
|
}
|
|
|
|
json_close_object() {
|
|
_json_close_table
|
|
}
|
|
|
|
json_add_array() {
|
|
_json_add_table "$1" array A
|
|
}
|
|
|
|
json_close_array() {
|
|
_json_close_table
|
|
}
|
|
|
|
json_add_string() {
|
|
local cur
|
|
_json_get_var cur JSON_CUR
|
|
_json_add_generic string "$1" "$2" "$cur"
|
|
}
|
|
|
|
json_add_int() {
|
|
local cur
|
|
_json_get_var cur JSON_CUR
|
|
_json_add_generic int "$1" "$2" "$cur"
|
|
}
|
|
|
|
json_add_boolean() {
|
|
local cur
|
|
_json_get_var cur JSON_CUR
|
|
_json_add_generic boolean "$1" "$2" "$cur"
|
|
}
|
|
|
|
json_add_double() {
|
|
local cur
|
|
_json_get_var cur JSON_CUR
|
|
_json_add_generic double "$1" "$2" "$cur"
|
|
}
|
|
|
|
json_add_null() {
|
|
local cur
|
|
_json_get_var cur JSON_CUR
|
|
_json_add_generic null "$1" "" "$cur"
|
|
}
|
|
|
|
json_add_fields() {
|
|
while [ "$#" -gt 0 ]; do
|
|
local field="$1"
|
|
shift
|
|
|
|
local name="${field%%=*}"
|
|
local val="${field#*=}"
|
|
[ "$name" != "$val" ] || val=""
|
|
|
|
local type="${name#*:}"
|
|
[ "$type" != "$name" ] || type=string
|
|
name="${name%%:*}"
|
|
|
|
case "$type" in
|
|
string|int|boolean|double)
|
|
local cur
|
|
_json_get_var cur JSON_CUR
|
|
_json_add_generic "$type" "$name" "$val" "$cur"
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# functions read access to json variables
|
|
|
|
json_compact() {
|
|
JSON_NONEWLINE=1
|
|
JSON_INDENT=
|
|
}
|
|
|
|
json_pretty() {
|
|
JSON_NONEWLINE=
|
|
JSON_INDENT=1
|
|
}
|
|
|
|
json_load() {
|
|
eval "`jshn -r "$1"`"
|
|
}
|
|
|
|
json_load_file() {
|
|
eval "`jshn -R "$1"`"
|
|
}
|
|
|
|
json_dump() {
|
|
jshn "$@" ${JSON_PREFIX:+-p "$JSON_PREFIX"} ${JSON_NONEWLINE:+-n} ${JSON_INDENT:+-i} -w
|
|
}
|
|
|
|
json_get_type() {
|
|
local __dest="$1"
|
|
local __cur
|
|
|
|
_json_get_var __cur JSON_CUR
|
|
local __var="${JSON_PREFIX}T_${__cur}_${2//[^a-zA-Z0-9_]/_}"
|
|
eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
|
|
}
|
|
|
|
json_get_keys() {
|
|
local __dest="$1"
|
|
local _tbl_cur
|
|
|
|
if [ -n "$2" ]; then
|
|
json_get_var _tbl_cur "$2"
|
|
else
|
|
_json_get_var _tbl_cur JSON_CUR
|
|
fi
|
|
local __var="${JSON_PREFIX}K_${_tbl_cur}"
|
|
eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
|
|
}
|
|
|
|
json_get_values() {
|
|
local _v_dest="$1"
|
|
local _v_keys _v_val _select=
|
|
local _json_no_warning=1
|
|
|
|
unset "$_v_dest"
|
|
[ -n "$2" ] && {
|
|
json_select "$2" || return 1
|
|
_select=1
|
|
}
|
|
|
|
json_get_keys _v_keys
|
|
set -- $_v_keys
|
|
while [ "$#" -gt 0 ]; do
|
|
json_get_var _v_val "$1"
|
|
__jshn_raw_append "$_v_dest" "$_v_val"
|
|
shift
|
|
done
|
|
[ -n "$_select" ] && json_select ..
|
|
|
|
return 0
|
|
}
|
|
|
|
json_get_var() {
|
|
local __dest="$1"
|
|
local __cur
|
|
|
|
_json_get_var __cur JSON_CUR
|
|
local __var="${JSON_PREFIX}${__cur}_${2//[^a-zA-Z0-9_]/_}"
|
|
eval "export -- \"$__dest=\${$__var:-$3}\"; [ -n \"\${$__var+x}\${3+x}\" ]"
|
|
}
|
|
|
|
json_get_vars() {
|
|
while [ "$#" -gt 0 ]; do
|
|
local _var="$1"; shift
|
|
if [ "$_var" != "${_var#*:}" ]; then
|
|
json_get_var "${_var%%:*}" "${_var%%:*}" "${_var#*:}"
|
|
else
|
|
json_get_var "$_var" "$_var"
|
|
fi
|
|
done
|
|
}
|
|
|
|
json_select() {
|
|
local target="$1"
|
|
local type
|
|
local cur
|
|
|
|
[ -z "$1" ] && {
|
|
_json_set_var JSON_CUR "J_V"
|
|
return 0
|
|
}
|
|
[[ "$1" == ".." ]] && {
|
|
_json_get_var cur JSON_CUR
|
|
_json_get_var cur "U_$cur"
|
|
_json_set_var JSON_CUR "$cur"
|
|
return 0
|
|
}
|
|
json_get_type type "$target"
|
|
case "$type" in
|
|
object|array)
|
|
json_get_var cur "$target"
|
|
_json_set_var JSON_CUR "$cur"
|
|
;;
|
|
*)
|
|
[ -n "$_json_no_warning" ] || \
|
|
echo "WARNING: Variable '$target' does not exist or is not an array/object"
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
json_is_a() {
|
|
local type
|
|
|
|
json_get_type type "$1"
|
|
[ "$type" = "$2" ]
|
|
}
|
|
|
|
json_for_each_item() {
|
|
[ "$#" -ge 2 ] || return 0
|
|
local function="$1"; shift
|
|
local target="$1"; shift
|
|
local type val
|
|
|
|
json_get_type type "$target"
|
|
case "$type" in
|
|
object|array)
|
|
local keys key
|
|
json_select "$target"
|
|
json_get_keys keys
|
|
for key in $keys; do
|
|
json_get_var val "$key"
|
|
eval "$function \"\$val\" \"\$key\" \"\$@\""
|
|
done
|
|
json_select ..
|
|
;;
|
|
*)
|
|
json_get_var val "$target"
|
|
eval "$function \"\$val\" \"\" \"\$@\""
|
|
;;
|
|
esac
|
|
}
|