#!/usr/bin/env sh ########################################################################### ## Original @ https://github.com/fkalis/bash-json-parser ## ## Modifications by Wizardry and Steamworks: ## ## * dash compatibility ## ########################################################################### ## conversion from bash with the following changes: ## ## * parse "" "" <<< "${INPUT}" -> echo "${INPUT}" | parse "" "" ## ## * == -> = ## ## * read -r -s -n 1 c -> readc c ## ########################################################################### json_readc() { if [ -t 0 ]; then saved_tty_settings=$(stty -g); stty -icanon -echo min 1 time 0; fi; c=$(dd bs=1 count=1 conv=noerror,sync 2>/dev/null); if [ -t 0 ]; then stty "$saved_tty_settings"; fi; }; json_set_entry() { echo "$1=$2"; }; json_parse_array() { local current_path="${1:+$1.}$2"; local current_scope="root"; local current_index=0; while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do [ "$preserve_current_char" = "0" ] && chars_read=$((chars_read + 1)) && json_readc c; preserve_current_char=0; c=${c:-' '}; case "$current_scope" in "root") case "$c" in '{') json_parse_object "$current_path" "$current_index"; current_scope="entry_separator"; ;; ']') return; ;; [\"tfTF\-0-9]) preserve_current_char=1; json_parse_value "$current_path" "$current_index"; preserve_current_char=1; current_scope="entry_separator"; ;; esac ;; "entry_separator") [ "$c" = "," ] && current_index=$((current_index + 1)) && current_scope="root"; [ "$c" = "]" ] && return; ;; esac done }; json_parse_value() { local current_path="${1:+$1.}$2"; local current_scope="root"; while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do [ "$preserve_current_char" = "0" ] && chars_read=$((chars_read + 1)) && json_readc c; preserve_current_char=0; c=${c:-' '}; case "$current_scope" in "root") case "$c" in '"') current_scope="string"; current_varvalue=""; ;; [\-0-9]) current_scope="number"; current_varvalue="$c"; ;; [tfTF]) current_scope="boolean"; current_varvalue="$c"; ;; "[") json_parse_array "" "$current_path"; return; ;; "{") json_parse_object "" "$current_path"; return; ;; esac ;; "string") case "$c" in '"') [ "$current_escaping" = "0" ] && json_set_entry "$current_path" "$current_varvalue" && return; [ "$current_escaping" = "1" ] && current_varvalue="$current_varvalue$c" && current_escaping=0; ;; '\') [ "$current_escaping" = "1" ] && current_varvalue="$current_varvalue$c"; current_escaping=$((1 - current_escaping)); ;; *) current_escaping=0; current_varvalue="$current_varvalue$c"; ;; esac ;; "number") case "$c" in [,\]}]) json_set_entry "$current_path" "$current_varvalue"; preserve_current_char=1; return ;; [\-0-9.]) current_varvalue="$current_varvalue$c"; ;; esac ;; "boolean") case "$c" in [,\]}]) json_set_entry "$current_path" "$current_varvalue"; preserve_current_char=1; return; ;; [a-zA-Z]) current_varvalue="$current_varvalue$c"; ;; esac ;; esac done }; json_parse_object() { local current_path="${1:+$1.}$2"; local current_scope="root"; while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do [ "$preserve_current_char" = "0" ] && chars_read=$((chars_read + 1)) && json_readc c; preserve_current_char=0; c=${c:-' '}; case "$current_scope" in "root") [ "$c" = "}" ] && return; [ "$c" = "\"" ] && current_scope="varname" && current_varname="" && current_escaping=0; ;; "varname") case "$c" in '"') [ "$current_escaping" = "0" ] && current_scope="key_value_separator"; [ "$current_escaping" = "1" ] && current_varname="$current_varname$c" && current_escaping=0; ;; '\') current_escaping=$((1 - current_escaping)); current_varname="$current_varname$c"; ;; *) current_escaping=0; current_varname="$current_varname$c"; ;; esac ;; "key_value_separator") [ "$c" = ":" ] && json_parse_value "$current_path" "$current_varname" && current_scope="field_separator"; ;; "field_separator") [ "$c" = ',' ] && current_scope="root"; [ "$c" = '}' ] && return; ;; esac done }; json_read() { chars_read=0; preserve_current_char=0; while [ "$chars_read" -lt "$INPUT_LENGTH" ]; do json_readc c; c=${c:-' '}; chars_read=$((chars_read + 1)); [ "$c" = "{" ] && json_parse_object "" "" && return; [ "$c" = "[" ] && json_parse_array "" "" && return; done }; json() { if [ -z "$@" ]; then INPUT=$(cat -); else INPUT=$(echo "$@"); fi; INPUT_LENGTH="${#INPUT}"; echo "${INPUT}" | json_read; }; json "$@"