The cirros image was rebuilt against the 3.13.0-83 kernel, drivers e1000e, igbvf...
[packages/trusty/cirros-testvm.git] / cirros-testvm / src-cirros / src / usr / bin / json2fstree
1 #!/usr/bin/awk -f
2
3 ### begin from awkenough (https://github.com/dubiousjim/awkenough) ####
4 function assert(test, msg) {
5         if (!test) die(msg ? msg : "assertion failed")
6 }
7
8 # if you call die, assert, or check*: start END blocks with
9 #       { if (EXITCODE) exit EXITCODE; ... }
10 function die(msg) {
11         EXITCODE=1
12         printf("%s: %s\n", ARGV[0], msg) > "/dev/stderr"
13         exit EXITCODE
14 }
15
16 function parse_json(str, T, V,  slack,  c,s,n,a,A,b,B,C,U,W,i,j,k,u,v,w,root) {
17         # use strings, numbers, booleans as separators
18         # c = "[^\"\\\\[:cntrl:]]|\\\\[\"\\\\/bfnrt]|\\u[[:xdigit:]][[:xdigit:]][[:xdigit:]][[:xdigit:]]"
19         c = "[^\"\\\\\001-\037]|\\\\[\"\\\\/bfnrt]|\\\\u[[:xdigit:]A-F][[:xdigit:]A-F][[:xdigit:]A-F][[:xdigit:]A-F]"
20         s ="\"(" c ")*\""
21         n = "-?(0|[1-9][[:digit:]]*)([.][[:digit:]]+)?([eE][+-]?[[:digit:]]+)?"
22
23         root = gsplit(str, A, s "|" n "|true|false|null", T)
24         assert(root > 0, "unexpected")
25
26         # rejoin string using value indices
27         str = ""
28         for (i=1; i<root; i++)
29                 str = str A[i] i
30         str = str A[root]
31
32         # cleanup types and values
33         for (i=1; i<root; i++) {
34                 if (T[i] ~ /^\"/) {
35                         b = split(substr(T[i], 2, length(T[i])-2), B, /\\/)
36                         if (b == 0) v = ""
37                         else {
38                                 v = B[1]
39                                 k = 0
40                                 for (j=2; j <= b; j++) {
41                                         u = B[j]
42                                         if (u == "") {
43                                                 if (++k % 2 == 1) v = v "\\"
44                                         } else {
45                                                 w = substr(u, 1, 1)  
46                                                 if (w == "b") v = v "\b" substr(u, 2)
47                                                 else if (w == "f") v = v "\f" substr(u, 2)
48                                                 else if (w == "n") v = v "\n" substr(u, 2)
49                                                 else if (w == "r") v = v "\r" substr(u, 2)
50                                                 else if (w == "t") v = v "\t" substr(u, 2)
51                                                 else v = v u
52                                         }
53                                 }
54                         }
55                         V[i] = v
56                         T[i] = "string"
57                 } else if (T[i] !~ /true|false|null/) {
58                         V[i] = T[i] + 0
59                         T[i] = "number"
60                 } else {
61                         V[i] = T[i]
62                 }
63         }
64
65         # sanitize string
66         gsub(/[[:space:]]+/, "", str)
67         if (str !~ /^[][{}[:digit:],:]+$/) {
68                 if (slack !~ /:/) return -1
69                 # handle ...unquoted:...
70                 a = gsplit(str, A, "[[:alpha:]_][[:alnum:]_]*:", B)
71                 str = ""
72                 for (i=1; i < a; i++) {
73                         T[root] = "string"
74                         V[root] = substr(B[i], 1, length(B[i])-1)
75                         str = str A[i] root ":"
76                         root++
77                 }
78                 str = str A[a]
79                 if (str !~ /^[][{}[:digit:],:]+$/) return -10
80         }
81
82         # atomic value?
83         a = gsplit(str, A, "[[{]", B)
84         if (A[1] != "") {
85                 if (a > 1) return -2
86                 else if (A[1] !~ /^[[:digit:]]+$/) return -3
87                 else return A[1]+0
88         }
89
90         # parse objects and arrays
91         k = root
92         C[0] = 0
93         for (i=2; i<=a; i++) {
94                 T[k] = (B[i-1] ~ /\{/) ? "object" : "array"
95                 C[k] = C[0]
96                 C[0] = k
97                 u = gsplit(A[i], U, "[]}]", W)
98                 assert(u > 0, "unexpected")
99                 V[k++] = U[1]
100                 if (i < a && A[i] != "" && U[u] !~ /[,:]$/)
101                         return -4
102                 for (j=1; j<u; j++) {
103                         if (C[0] == 0 || T[C[0]] != ((W[j] == "}") ? "object" : "array")) return -5
104                         v = C[0]
105                         w = C[v]
106                         C[0] = w
107                         delete C[v]
108                         if (w) V[w] = V[w] v U[j+1]
109                 }
110         }
111         if (C[0] != 0) return -6
112
113         # check contents
114         for (i=root; i<k; i++) {
115                 if (T[i] == "object") {
116                         # check object contents
117                         b = split(V[i], B, /,/) 
118                         for (j=1; j <= b; j++) {
119                                 if (B[j] !~ /^[[:digit:]]+:[[:digit:]]+$/)
120                                         return -7
121                                 if (T[substr(B[j], 1, index(B[j],":")-1)] != "string")
122                                         return -8
123                         }
124                 } else if (V[i] != "") {
125                         # check array contents
126                         if (slack ~ /,/ && V[i] ~ /,$/)
127                                 V[i] = substr(V[i], 1, length(V[i] -1))
128                         if (V[i] !~ /^[[:digit:]]+(,[[:digit:]]+)*$/)
129                                 return -9
130                 }
131         }
132         return root
133 }
134
135 # populate array from str="key key=value key=value"
136 # can optionally supply "re" for equals, space; if they're the same or equals is "", array will be setlike
137 function asplit(str, array,  equals, space,   aux, i, n) {
138         n = split(str, aux, (space == "") ? "[ \n]+" : space)
139         if (space && equals == space)
140                 equals = ""
141         else if (ismissing(equals))
142                 equals = "="
143         split("", array) # delete array
144         for (i=1; i<=n; i++) {
145                 if (equals && match(aux[i], equals))
146                         array[substr(aux[i], 1, RSTART-1)] = substr(aux[i], RSTART+RLENGTH)
147                 else
148                         array[aux[i]]
149         }
150         split("", aux) # does it help to delete the aux array?
151         return n
152 }
153
154 function query_json(str, X,  root, slack,   T, V, A, B, C, i, j, k) {
155         k = parse_json(str, T, V, slack)
156         if (k < 1) return k
157         split(root, C, ".")
158         j = 1
159         while (j in C) {
160                 if (T[k] == "array")
161                         split(V[k], A, ",")
162                 else {
163                         split("", A)
164                         asplit(V[k], B, ":", ",")
165                         for (i in B)
166                                 A[V[i]] = B[i]
167                 }
168                 if (C[j] in A) {
169                         k = A[C[j]]
170                         j++
171                 } else return -11 # can't find requested root
172         }
173         # split("", B)
174         # split("", C)
175         split("", X)
176         B[k] = ""
177         C[k] = 0
178         C[0] = k
179         do {
180                 C[0] = C[k]
181                 delete C[k]
182                 j = T[k]
183                 if (j == "array") {
184                         j = split(V[k], A, ",")
185                         k = B[k] ? B[k] SUBSEP : ""
186                         X[k 0] = j
187                         for (i=1; i<=j; i++) {
188                                 # push A[i] to C, (B[k],i) to B 
189                                 C[A[i]] = C[0]
190                                 B[A[i]] = k i
191                                 C[0] = A[i]
192                         }
193                 } else if (j == "object") {
194                         asplit(V[k], A, ":", ",")
195                         k = B[k] ? B[k] SUBSEP : ""
196                         for (i in A) {
197                                 # push A[i] to C, (B[k],V[i]) to B 
198                                 C[A[i]] = C[0]
199                                 B[A[i]] = k V[i]
200                                 C[0] = A[i]
201                         }
202                 } else if (j == "number") {
203                         X[B[k]] = V[k]
204                 } else if (j == "true") {
205                         X[B[k]] = 1
206                 } else if (j == "false") {
207                         X[B[k]] = 0
208                 } else if (j == "string") {
209                         X[B[k]] = V[k]
210                 } else {
211                         # null will satisfy ismissing()
212                         X[B[k]]
213                 }
214                 k = C[0]
215         } while (k)
216         return 0
217 }
218
219 # unitialized scalar
220 function ismissing(u) {
221         return u == 0 && u == ""
222 }
223
224 # behaves like gawk's split; special cases re == "" and " "
225 # unlike split, will honor 0-length matches
226 function gsplit(str, items, re,  seps,   n, i, start, stop, sep1, sep2, sepn) {
227         n = 0
228         # find separators that don't occur in str
229         i = 1
230         do
231                 sep1 = sprintf("%c", i++)
232         while (index(str, sep1))
233         do
234                 sep2 = sprintf("%c", i++)
235         while (index(str, sep2))
236         sepn = 1
237         split("", seps) # delete array
238         if (ismissing(re))
239                 re = FS
240         if (re == "") {
241                 split(str, items, "")
242                 n = length(str)
243                 for (i=1; i<n; i++)
244                         seps[i]
245                 return n
246         }
247         split("", items) # delete array
248         if (re == " ") {
249                 re = "[ \t\n]+"
250                 if (match(str, /^[ \t\n]+/)) {
251                         seps[0] = substr(str, 1, RLENGTH)
252                         str = substr(str, RLENGTH+1)
253                 }
254                 if (match(str, /[ \t\n]+$/)) {
255                         sepn = substr(str, RSTART, RLENGTH)
256                         str = substr(str, 1, RSTART-1)
257                 }
258         }
259         i = gsub(re, sep1 "&" sep2, str)
260         while (i--) {
261                 start = index(str, sep1)
262                 stop = index(str, sep2) - 1
263                 seps[++n] = substr(str, start + 1, stop - start)
264                 items[n] = substr(str, 1, start - 1)
265                 str = substr(str, stop + 2)
266         }
267         items[++n] = str
268         if (sepn != 1) seps[n] = sepn
269         return n
270 }
271
272 function basename(path, suffix) {
273         sub(/\/$/, "", path)
274         if (path == "")
275                 return "/"
276         sub(/^.*\//, "", path)
277         if(suffix != "" && has_suffix(path, suffix))
278                 path = substr(path, 1, length(path) - length(suffix))
279         return path
280 }
281
282 function dirname(path) {
283         if (!sub(/\/[^\/]*\/?$/, "", path))
284                 return "."
285         else if (path != "")
286                 return path
287         else
288                 return "/"
289 }
290
291 function has_suffix(str, suf, len1, len2) {
292         len1 = length(str)
293         len2 = length(suf)
294         return len2 <= len1 && substr(str, len1 - len2 + 1) == suf
295 }
296 ### end from awkenough ####
297
298 BEGIN {
299         EXITCODE = ""
300         USAGE = "json2fstree: basedir [file]\n\
301         read json data in file and create directory tree under basedir\n"
302
303         if (ARGC != 2 && ARGC != 3) {
304                 printf(USAGE) >"/dev/stderr"
305                 EXITCODE = 1
306                 exit(1)
307         }
308         if (ARGV[1] == "-h" || ARGV[1] == "--help") {
309                 EXITCODE = 0
310                 print USAGE
311                 exit(0)
312         }
313         outd = ARGV[1]
314         if (ARGC == 3) {
315                 ARGV[1] = ARGV[2]
316                 ARGC = 2
317         } else {
318                 ARGC = 1
319                 ARGV[1] = ""
320         }
321         RS = SUBSEP
322 }
323
324 END {
325         if (EXITCODE != "") {
326                 exit(EXITCODE)
327         }
328         ret = query_json($0, data)
329         assert(ret == 0, "failed to parse json\n")
330
331         for (key in data) {
332                 path = key
333                 gsub("/", "_", path)
334                 gsub(SUBSEP, "/", path)
335                 fpath = outd "/" path
336                 ret = system("mkdir -p " dirname(fpath))
337                 assert(ret == 0, "failed to mkdir " fpath)
338                 printf("%s", data[key]) > fpath
339         }
340 }
341
342 # vi: ts=4 noexpandtab