jshn: improve performance by getting rid of unnecessary variables in parser related...
[project/libubox.git] / sh / jshn.sh
1 # functions for parsing and generating json
2
3 _json_get_var() {
4         # dest=$1
5         # var=$2
6         eval "$1=\"\$${JSON_PREFIX}$2\""
7 }
8
9 _json_set_var() {
10         # var=$1
11         local ___val="$2"
12         eval "${JSON_PREFIX}$1=\"\$___val\""
13 }
14
15 __jshn_raw_append() {
16         # var=$1
17         local value="$2"
18         local sep="${3:- }"
19
20         eval "export -- \"$1=\${$1:+\${$1}\${value:+\$sep}}\$value\""
21 }
22
23 _jshn_append() {
24         # var=$1
25         # value=$2
26         # sep=$3
27         local __old_val
28
29         _json_get_var __old_val "$1"
30         _json_set_var "$1" "${__old_val:+$__old_val${3:- }}$2"
31 }
32
33 _json_export() {
34         # var=$1
35         # value=$2
36         export -- "${JSON_PREFIX}$1=$2"
37 }
38
39 _json_add_key() {
40         # var=$1
41         # value=$2
42         _jshn_append "KEYS_$1" "$2"
43 }
44
45 _get_var() {
46         # var=$1
47         # value=$2
48         eval "$1=\"\$$2\""
49 }
50
51 _set_var() {
52         # var=$1
53         local __val="$2"
54         eval "$1=\"\$__val\""
55 }
56
57 _json_inc() {
58         # var=$1
59         # dest=$2
60         local _seq
61
62         _json_get_var _seq "$1"
63         _seq="$((${_seq:-0} + 1))"
64         _json_set_var "$1" "$_seq"
65         [ -n "$2" ] && _set_var "$2" "$_seq"
66 }
67
68 _json_add_generic() {
69         # type=$1
70         local var="$2"
71         # value=$3
72         local cur="$4"
73
74         [ -n "$cur" ] || _json_get_var cur JSON_CUR
75
76         if [ "${cur%%[0-9]*}" = "JSON_ARRAY" ]; then
77                 _json_inc "SEQ_$cur" var
78         else
79                 local name="${var//[^a-zA-Z0-9_]/_}"
80                 [[ "$name" == "$var" ]] || _json_export "NAME_${cur}_${name}" "$var"
81                 var="$name"
82         fi
83
84         local cur_var=
85         _json_export "${cur}_$var" "$3"
86         _json_export "TYPE_${cur}_$var" "$1"
87         _jshn_append "JSON_UNSET" "${cur}_$var"
88         _json_add_key "$cur" "$var"
89 }
90
91 _json_add_table() {
92         # name=$1
93         # type=$2
94         # itype=$3
95         local cur new_cur seq
96
97         _json_get_var cur JSON_CUR
98         _json_inc JSON_SEQ seq
99
100         local table="JSON_$3$seq"
101         _json_set_var "UP_$table" "$cur"
102         _json_export "KEYS_$table" ""
103         [ "$itype" = "ARRAY" ] && _json_set_var "SEQ_$table" ""
104         _json_set_var JSON_CUR "$table"
105         _jshn_append "JSON_UNSET" "$table"
106
107         _json_get_var new_cur JSON_CUR
108         _json_add_generic "$2" "$1" "$new_cur" "$cur"
109 }
110
111 _json_close_table() {
112         local _s_cur _s_new
113
114         _json_get_var _s_cur JSON_CUR
115         _json_get_var _s_new "UP_$_s_cur"
116         _json_set_var JSON_CUR "$_s_new"
117 }
118
119 json_set_namespace() {
120         local _new="$1"
121         local _old="$2"
122
123         [ -n "$_old" ] && _set_var "$_old" "$JSON_PREFIX"
124         JSON_PREFIX="$_new"
125 }
126
127 json_cleanup() {
128         local unset
129
130         _json_get_var unset JSON_UNSET
131         for tmp in $unset JSON_VAR; do
132                 unset \
133                         ${JSON_PREFIX}UP_$tmp \
134                         ${JSON_PREFIX}KEYS_$tmp \
135                         ${JSON_PREFIX}SEQ_$tmp \
136                         ${JSON_PREFIX}TYPE_$tmp \
137                         ${JSON_PREFIX}NAME_$tmp \
138                         ${JSON_PREFIX}$tmp
139         done
140
141         unset \
142                 ${JSON_PREFIX}JSON_SEQ \
143                 ${JSON_PREFIX}JSON_CUR \
144                 ${JSON_PREFIX}JSON_UNSET
145 }
146
147 json_init() {
148         json_cleanup
149         export -- \
150                 ${JSON_PREFIX}JSON_SEQ=0 \
151                 ${JSON_PREFIX}JSON_CUR="JSON_VAR" \
152                 ${JSON_PREFIX}KEYS_JSON_VAR= \
153                 ${JSON_PREFIX}TYPE_JSON_VAR=
154 }
155
156 json_add_object() {
157         _json_add_table "$1" object TABLE
158 }
159
160 json_close_object() {
161         _json_close_table
162 }
163
164 json_add_array() {
165         _json_add_table "$1" array ARRAY 
166 }
167
168 json_close_array() {
169         _json_close_table
170 }
171
172 json_add_string() {
173         _json_add_generic string "$1" "$2"
174 }
175
176 json_add_int() {
177         _json_add_generic int "$1" "$2"
178 }
179
180 json_add_boolean() {
181         _json_add_generic boolean "$1" "$2"
182 }
183
184 json_add_double() {
185         _json_add_generic double "$1" "$2"
186 }
187
188 # functions read access to json variables
189
190 json_load() {
191         eval `jshn -r "$1"`
192 }
193
194 json_dump() {
195         jshn "$@" ${JSON_PREFIX:+-p "$JSON_PREFIX"} -w 
196 }
197
198 json_get_type() {
199         local __dest="$1"
200         local __cur
201
202         _json_get_var __cur JSON_CUR
203         local __var="${JSON_PREFIX}TYPE_${__cur}_${2//[^a-zA-Z0-9_]/_}"
204         eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
205 }
206
207 json_get_keys() {
208         local __dest="$1"
209         local _tbl_cur
210
211         if [ -n "$2" ]; then
212                 json_get_var _tbl_cur "$2"
213         else
214                 _json_get_var _tbl_cur JSON_CUR
215         fi
216         local __var="${JSON_PREFIX}KEYS_${_tbl_cur}"
217         eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
218 }
219
220 json_get_values() {
221         local _v_dest="$1"
222         local _v_keys _v_val _select=
223
224         unset "$_v_dest"
225         [ -n "$2" ] && {
226                 json_select "$2"
227                 _select=1
228         }
229
230         json_get_keys _v_keys
231         set -- $_v_keys
232         while [ "$#" -gt 0 ]; do
233                 json_get_var _v_val "$1"
234                 __jshn_raw_append "$_v_dest" "$_v_val"
235                 shift
236         done
237         [ -n "$_select" ] && json_select ..
238
239         return 0
240 }
241
242 json_get_var() {
243         local __dest="$1"
244         local __cur
245
246         _json_get_var __cur JSON_CUR
247         local __var="${JSON_PREFIX}${__cur}_${2//[^a-zA-Z0-9_]/_}"
248         eval "export -- \"$__dest=\${$__var}\"; [ -n \"\${$__var+x}\" ]"
249 }
250
251 json_get_vars() {
252         while [ "$#" -gt 0 ]; do
253                 local _var="$1"; shift
254                 json_get_var "$_var" "$_var"
255         done
256 }
257
258 json_select() {
259         local target="$1"
260         local type
261         local cur
262
263         [ -z "$1" ] && {
264                 _json_set_var JSON_CUR "JSON_VAR"
265                 return 0
266         }
267         [[ "$1" == ".." ]] && {
268                 _json_get_var cur JSON_CUR
269                 _json_get_var cur "UP_$cur"
270                 _json_set_var JSON_CUR "$cur"
271                 return 0
272         }
273         json_get_type type "$target"
274         case "$type" in
275                 object|array)
276                         json_get_var cur "$target"
277                         _json_set_var JSON_CUR "$cur"
278                 ;;
279                 *)
280                         echo "WARNING: Variable '$target' does not exist or is not an array/object"
281                         return 1
282                 ;;
283         esac
284 }
285
286 json_is_a() {
287         local type
288
289         json_get_type type "$1"
290         [ "$type" = "$2" ]
291 }