2 * Copyright (C) 2016-2019 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * This simple program expands the object { "$ref": "#/path/to/a/target" }
25 * "b": { "$ref": "#/type/a" }
29 * will be exapanded to
38 * Invocation: program [file|-]...
40 * without arguments, it reads the input.
48 #include <json-c/json.h>
51 * records path to the expanded node
55 struct json_object *object; /**< node being expanded */
56 struct path *upper; /**< link to upper expanded nodes */
60 * root of the JSON being parsed
62 struct json_object *root;
65 * Search for a reference of type "#/a/b/c" int the
68 struct json_object *search(const char *path)
71 struct json_object *i;
73 /* does it match #/ at the beginning? */
74 if (path[0] != '#' || (path[0] && path[1] != '/'))
77 /* search from root to target */
82 if (!json_object_object_get_ex(i, d, &i))
84 d = strtok(NULL, "/");
90 * Expands the node designated by path and returns its expanded form
92 struct json_object *expand(struct path path)
95 struct json_object *o, *x;
97 struct json_object_iterator ji, jn;
99 /* expansion depends of the type of the node */
100 switch (json_object_get_type(path.object)) {
101 case json_type_object:
102 /* for object, look if it contains a property "$ref" */
103 if (json_object_object_get_ex(path.object, "$ref", &o)) {
104 /* yes, reference, try to substitute its target */
105 if (!json_object_is_type(o, json_type_string)) {
106 fprintf(stderr, "found a $ref not being string. Is: %s\n", json_object_get_string(o));
109 x = search(json_object_get_string(o));
111 fprintf(stderr, "$ref not found. Was: %s\n", json_object_get_string(o));
116 if (x == p->object) {
117 fprintf(stderr, "$ref recursive. Was: %s\n", json_object_get_string(o));
122 /* cool found, return a new instance of the target */
123 return json_object_get(x);
125 /* no, expand the values */
126 ji = json_object_iter_begin(path.object);
127 jn = json_object_iter_end(path.object);
128 while (!json_object_iter_equal(&ji, &jn)) {
129 o = json_object_iter_peek_value(&ji);
130 x = expand((struct path){ .object = o, .upper = &path });
132 json_object_object_add(path.object, json_object_iter_peek_name(&ji), x);
133 json_object_iter_next(&ji);
136 case json_type_array:
137 /* expand the values of arrays */
139 n = (int)json_object_array_length(path.object);
141 o = json_object_array_get_idx(path.object, i);
142 x = expand((struct path){ .object = o, .upper = &path });
144 json_object_array_put_idx(path.object, i, x);
149 /* otherwise no expansion */
152 /* return the given node */
157 * process a file and prints its expansion on stdout
159 void process(char *filename)
162 if (!strcmp(filename, "-"))
163 filename = "/dev/stdin";
166 if (access(filename, R_OK)) {
167 fprintf(stderr, "can't access file %s\n", filename);
172 root = json_object_from_file(filename);
174 fprintf(stderr, "reading file %s produced null\n", filename);
179 root = expand((struct path){ .object = root, .upper = NULL });
181 /* print the result */
182 json_object_to_file_ext ("/dev/stdout", root, JSON_C_TO_STRING_PRETTY);
185 json_object_put(root);
188 /** process the list of files or stdin if none */
189 int main(int ac, char **av)
194 do { process(*av); } while(*++av);