devtools: Refactoring, bug fix, new IDL
[src/app-framework-binder.git] / src / devtools / exprefs.c
1 /*
2  * Copyright (C) 2016-2019 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 /*
18  * This simple program expands the object { "$ref": "#/path/to/a/target" }
19  *
20  * For example:
21  *
22  *  {
23  *    "type":{
24  *      "a": "int",
25  *      "b": { "$ref": "#/type/a" }
26  *    }
27  *  }
28  *
29  * will be exapanded to
30  *
31  *  {
32  *    "type":{
33  *      "a": "int",
34  *      "b": "int"
35  *    }
36  *  }
37  *
38  * Invocation:   program  [file|-]...
39  *
40  * without arguments, it reads the input.
41  */
42
43 #define _GNU_SOURCE
44 #include <string.h>
45 #include <stdio.h>
46
47 #include <json-c/json.h>
48
49 #include "getref.h"
50 #include "exprefs.h"
51
52 /**
53  * records path to the expanded node
54  */
55 struct path
56 {
57         struct json_object *object;     /**< node being expanded */
58         const struct path *upper;       /**< link to upper expanded nodes */
59 };
60
61 /**
62  * Returns the top object
63  */
64 static inline struct json_object *top(const struct path *path)
65 {
66         while (path->upper)
67                 path = path->upper;
68         return path->object;
69 }
70
71 /**
72  * Expands the node designated by path and returns its expanded form
73  */
74 static struct json_object *expand(const struct path *upper)
75 {
76         struct path here;
77         struct json_object *object, *x;
78         int n, i;
79         struct json_object_iterator ji, jn;
80
81         /* expansion depends of the type of the node */
82         here.upper = upper;
83         object = upper->object;
84         switch (json_object_get_type(object)) {
85         case json_type_object:
86                 /* for object, look if it contains a property "$ref" */
87                 if (json_object_object_get_ex(object, "$ref", &here.object)) {
88                         /* check that "$ref" value is a string */
89                         if (!json_object_is_type(here.object, json_type_string)) {
90                                 fprintf(stderr, "found a $ref not being string. Is: %s\n", json_object_get_string(here.object));
91                                 exit(1);
92                         }
93                         /* yes, reference, try to substitute its target */
94                         i = search$ref(top(upper), json_object_get_string(here.object), &x);
95                         if (!i) {
96                                 fprintf(stderr, "$ref not found. Was: %s\n", json_object_get_string(here.object));
97                                 exit(1);
98                         }
99                         /* check not recursive */
100                         upper = &here;
101                         while(upper) {
102                                 if (x == upper->object) {
103                                         fprintf(stderr, "$ref recursive. Was: %s\n", json_object_get_string(here.object));
104                                         exit(1);
105                                 }
106                                 upper = upper->upper;
107                         }
108                         /* found. return a new instance of the target */
109                         return x;
110                 }
111                 /* no, expand the values */
112                 ji = json_object_iter_begin(object);
113                 jn = json_object_iter_end(object);
114                 while (!json_object_iter_equal(&ji, &jn)) {
115                         here.object = json_object_iter_peek_value(&ji);
116                         x = expand(&here);
117                         if (x != here.object)
118                                 json_object_object_add(object, json_object_iter_peek_name(&ji), json_object_get(x));
119                         json_object_iter_next(&ji);
120                 }
121                 break;
122         case json_type_array:
123                 /* expand the values of arrays */
124                 i = 0;
125                 n = (int)json_object_array_length(object);
126                 while (i != n) {
127                         here.object = json_object_array_get_idx(object, i);
128                         x = expand(&here);
129                         if (x != here.object)
130                                 json_object_array_put_idx(object, i, json_object_get(x));
131                         i++;
132                 }
133                 break;
134         default:
135                 /* otherwise no expansion */
136                 break;
137         }
138         /* return the given node */
139         return object;
140 }
141
142 struct json_object *exp$refs(struct json_object *root)
143 {
144         struct path top = { .object = root, .upper = NULL };
145         return expand(&top);
146 }
147
148 static int is_tree(struct json_object *object, const struct path *upper)
149 {
150         struct path here;
151         int n, i;
152         struct json_object_iterator ji, jn;
153
154         switch (json_object_get_type(object)) {
155         case json_type_object:
156         case json_type_array:
157                 /* check recursive */
158                 here.upper = upper;
159                 while (upper) {
160                         if (upper->object == object)
161                                 return 0;
162                         upper = upper->upper;
163                 }
164                 here.object = object;
165                 switch (json_object_get_type(object)) {
166                 case json_type_object:
167                         ji = json_object_iter_begin(object);
168                         jn = json_object_iter_end(object);
169                         while (!json_object_iter_equal(&ji, &jn)) {
170                                 if (!is_tree(json_object_iter_peek_value(&ji), &here))
171                                         return 0;
172                                 json_object_iter_next(&ji);
173                         }
174                         break;
175                 case json_type_array:
176                         i = 0;
177                         n = (int)json_object_array_length(object);
178                         while (i != n) {
179                                 if (!is_tree(json_object_array_get_idx(object, i), &here))
180                                         return 0;
181                                 i++;
182                         }
183                         break;
184                 default:
185                         break;
186                 }
187                 break;
188         default:
189                 break;
190         }
191         return 1;
192 }
193
194 int exp$refs_is_tree(struct json_object *root)
195 {
196         return is_tree(root, NULL);
197 }