]> git.plutz.net Git - cgilite/blobdiff - json.sh
new function RXLITERAL() for escaping regex characters
[cgilite] / json.sh
diff --git a/json.sh b/json.sh
index 99e1e746140af0d635080941e04d089d28043af5..12afdc4d676b94b705b0c165fee2512c80891cb9 100755 (executable)
--- a/json.sh
+++ b/json.sh
@@ -1,10 +1,12 @@
 #!/bin/sh
 
-[ -n "$include_json" ] && return 0
-include_json="$0"
+[ -n "$include_json" ] && return 0
+include_json="$0"
 
 . "${_EXEC:-.}/cgilite/db23.sh"
 
+# debug(){ [ $# -gt 0 ] && printf '%s\n' "$@" >&2 || tee -a /dev/stderr; }
+
 json_except() {
   printf '%s\n' "$@" >&2;
   printf 'Exc: %s\n' "$json_document" >&2
@@ -89,53 +91,11 @@ json_number() {
     return 1
   fi
 
-  printf '%s   %s\n' "num:${number%.000000}" "$json_document"
-}
-
-json_value() {
-  local value json_document="$json_document"
-
-  json_space
-  case $json_document in
-    \"*)
-      value="$(json_string)" || return 1
-      json_document="${value#* }"
-      value="str:${value%%     *}"
-      ;;
-    [+-.0-9]*)
-      value="$(json_number)" || return 1
-      json_document="${value#* }"
-      value="${value%% *}"
-      ;;
-    "{"*)
-      value="$(json_object)" || return 1
-      json_document="${value#* }"
-      value="obj:${value%%     *}"
-      ;;
-    "["*)
-      value="$(json_array)" || return 1
-      json_document="${value#* }"
-      value="arr:${value%%     *}"
-      ;;
-    null*)
-      json_document="${json_document#null}"
-      value="null"
-      ;;
-    true*)
-      json_document="${json_document#true}"
-      value="true"
-      ;;
-    false*)
-      json_document="${json_document#false}"
-      value="false"
-      ;;
-  esac
-
-  printf "%s   %s\n" "$value" "$json_document"
+  printf '%s   %s\n' "${number%.000000}" "$json_document"
 }
 
 json_array() {
-  local struct="$(DB2 new)" value json_document="$json_document"
+  local struct="$(DB2 "" new)" value json_document="$json_document"
 
   json_space
   case $json_document in
@@ -181,7 +141,7 @@ json_array() {
 }
 
 json_object() {
-  local struct="$(DB2 new)" key value json_document="$json_document"
+  local struct="$(DB2 "" new)" key value json_document="$json_document"
 
   json_space
   case $json_document in
@@ -229,8 +189,172 @@ json_object() {
   printf "%s   %s\n" "$(STRING "$struct")" "$json_document"
 }
 
+json_value() {
+  local value json_document="$json_document"
+  json_type=""
+
+  json_space
+  case $json_document in
+    \"*)
+      value="$(json_string)" || return 1
+      json_document="${value#* }"
+      value="str:${value%%     *}"
+      json_type=string
+      ;;
+    [+-.0-9]*)
+      value="$(json_number)" || return 1
+      json_document="${value#* }"
+      value="num:${value%%     *}"
+      json_type=number
+      ;;
+    "{"*)
+      value="$(json_object)" || return 1
+      json_document="${value#* }"
+      value="obj:${value%%     *}"
+      json_type=object
+      ;;
+    "["*)
+      value="$(json_array)" || return 1
+      json_document="${value#* }"
+      value="arr:${value%%     *}"
+      json_type=array
+      ;;
+    null*)
+      json_document="${json_document#null}"
+      value="null"
+      json_type=null
+      ;;
+    true*)
+      json_document="${json_document#true}"
+      value="true"
+      json_type=boolean
+      ;;
+    false*)
+      json_document="${json_document#false}"
+      value="false"
+      json_type=boolean
+      ;;
+  esac
+
+  printf "%s   %s\n" "$value" "$json_document"
+}
+
 json_load() {
-  local json_document="$1"
+  local json_document="$1" json
+
+  json_value |UNSTRING
+}
+
+json_get() {
+  local json="$1" jpath="${2#.}" key idx
+  json_type=''
+
+  case $json in
+    str:*) json_type="string";;
+    arr:*) json_type="array";;
+    obj:*) json_type="object";;
+    num:*) json_type="number";;
+    true|false)
+           json_type="boolean";;
+    null)  json_type="null";;
+  esac
+
+  case $jpath in
+    "")
+      printf %s\\n "${json#???:}"
+      return 0
+      ;;
+    "["[0-9]*"]"*)
+      idx="${jpath%%"]"*}" idx="${idx#"["}"
+      jpath="${jpath#"["*"]"}"
+      ;;
+    "['"*"']"*)
+      key="${jpath%%"']"*}" key="${key#"['"}"
+      jpath="${jpath#"['"*"']"}"
+      ;;
+    "$"*)
+      jpath="${jpath#?}"
+      ;;
+    *) key="${jpath%%[".["]*}"
+      jpath="${jpath#"$key"}"
+      ;;
+  esac
+
+  if   [ "$key" -a "$json_type" = object ]; then
+    if ! json="$(DB2 "${json#obj:}" get "$key")"; then
+      debug "Key not found: \"$key\""
+      return 1
+    fi
+  elif [ "$idx" -a "$json_type" = array ]; then
+    if ! json="$(DB2 "${json#arr:}" get @ "$(( idx + 1 ))")"; then
+      debug "Array index not found: \"$idx\""
+      return 1
+    fi
+  elif [ "$key" ]; then
+    debug "Cannot select key (\"$key\") from value of type \"$json_type\""
+    return 1
+  elif [ "$idx" ]; then
+    debug "Cannot select index ($idx) from value of type \"$json_type\""
+    return 1
+  fi
+  json_get "$json" "$jpath"
+  return $?
+}
+
+json_dump_string() {
+  local in="$1" out=''
+  while [ "$in" ]; do case $in in
+    \\*) out="${out}\\\\"; in="${in#\\}" ;;
+    "$BR"*) out="${out}\\n"; in="${in#${BR}}" ;;
+    "$CR"*) out="${out}\\r"; in="${in#${CR}}" ;;
+    "   "*) out="${out}\\t"; in="${in#  }" ;;
+    \"*) out="${out}\\\""; in="${in#\"}" ;;
+    *) out="${out}${in%%[\\${CR}${BR}  \"]*}"; in="${in#"${in%%[\\${BR}${CR}   \"]*}"}" ;;
+  esac; done
+  printf '"%s"' "${out}"
+}
 
-  json_value
+json_dump_array() {
+  local json="$1" value out=''
+
+  for value in $(DB2 "$json" iterate @); do
+    out="${out},$(json_dump "$(UNSTRING "$value")")"
+  done
+  printf '[%s]' "${out#,}"
+}
+
+json_dump_object() {
+  local json="$1" key value out=''
+
+  while read -r key value; do
+    out="${out},$(json_dump_string "$(UNSTRING "$key")"):$(json_dump "$(UNSTRING "$value")")"
+  done <<-EOF
+       ${json}
+       EOF
+  printf '{%s}' "${out#,}"
+}
+
+json_dump() {
+  local json="$1"
+
+  case $json in
+    str:*)
+      json_dump_string "${json#str:}"
+      ;;
+    arr:*)
+      json_dump_array "${json#arr:}"
+      ;;
+    obj:*)
+      json_dump_object "${json#obj:}"
+      ;;
+    num:*)
+      printf "${json#num:}"
+      ;;
+    true|false|null)
+      printf %s\\n "$json"
+      ;;
+    *)
+      json_dump_string "${json}"
+      ;;
+  esac
 }