X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fdevtools%2Fexprefs.c;fp=src%2Fdevtools%2Fexprefs.c;h=4ea44b4d3c1c43482d163ed93a95bdc1eeb10d2c;hb=45c8372c2b4137691a38c2a04f4a5759a110f2f7;hp=0000000000000000000000000000000000000000;hpb=e1b255b4c6486b0d2df5cd8b2aad8b817876ddf2;p=src%2Fapp-framework-binder.git diff --git a/src/devtools/exprefs.c b/src/devtools/exprefs.c new file mode 100644 index 00000000..4ea44b4d --- /dev/null +++ b/src/devtools/exprefs.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author José Bollo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * This simple program expands the object { "$ref": "#/path/to/a/target" } + * + * For example: + * + * { + * "type":{ + * "a": "int", + * "b": { "$ref": "#/type/a" } + * } + * } + * + * will be exapanded to + * + * { + * "type":{ + * "a": "int", + * "b": "int" + * } + * } + * + * Invocation: program [file|-]... + * + * without arguments, it reads the input. + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include + +/** + * records path to the expanded node + */ +struct path +{ + struct json_object *object; /**< node being expanded */ + struct path *upper; /**< link to upper expanded nodes */ +}; + +/** + * root of the JSON being parsed + */ +struct json_object *root; + +/** + * Search for a reference of type "#/a/b/c" int the + * parsed JSON object + */ +struct json_object *search(const char *path) +{ + char *d; + struct json_object *i; + + /* does it match #/ at the beginning? */ + if (path[0] != '#' || (path[0] && path[1] != '/')) + return NULL; + + /* search from root to target */ + i = root; + d = strdupa(path+2); + d = strtok(d, "/"); + while(i && d) { + if (!json_object_object_get_ex(i, d, &i)) + return NULL; + d = strtok(NULL, "/"); + } + return i; +} + +/** + * Expands the node designated by path and returns its expanded form + */ +struct json_object *expand(struct path path) +{ + struct path *p; + struct json_object *o, *x; + int n, i; + struct json_object_iterator ji, jn; + + /* expansion depends of the type of the node */ + switch (json_object_get_type(path.object)) { + case json_type_object: + /* for object, look if it contains a property "$ref" */ + if (json_object_object_get_ex(path.object, "$ref", &o)) { + /* yes, reference, try to substitute its target */ + if (!json_object_is_type(o, json_type_string)) { + fprintf(stderr, "found a $ref not being string. Is: %s\n", json_object_get_string(o)); + exit(1); + } + x = search(json_object_get_string(o)); + if (!x) { + fprintf(stderr, "$ref not found. Was: %s\n", json_object_get_string(o)); + exit(1); + } + p = &path; + while(p) { + if (x == p->object) { + fprintf(stderr, "$ref recursive. Was: %s\n", json_object_get_string(o)); + exit(1); + } + p = p->upper; + } + /* cool found, return a new instance of the target */ + return json_object_get(x); + } + /* no, expand the values */ + ji = json_object_iter_begin(path.object); + jn = json_object_iter_end(path.object); + while (!json_object_iter_equal(&ji, &jn)) { + o = json_object_iter_peek_value(&ji); + x = expand((struct path){ .object = o, .upper = &path }); + if (x != o) + json_object_object_add(path.object, json_object_iter_peek_name(&ji), x); + json_object_iter_next(&ji); + } + break; + case json_type_array: + /* expand the values of arrays */ + i = 0; + n = json_object_array_length(path.object); + while (i != n) { + o = json_object_array_get_idx(path.object, i); + x = expand((struct path){ .object = o, .upper = &path }); + if (x != o) + json_object_array_put_idx(path.object, i, x); + i++; + } + break; + default: + /* otherwise no expansion */ + break; + } + /* return the given node */ + return path.object; +} + +/** + * process a file and prints its expansion on stdout + */ +void process(char *filename) +{ + /* translate - */ + if (!strcmp(filename, "-")) + filename = "/dev/stdin"; + + /* check access */ + if (access(filename, R_OK)) { + fprintf(stderr, "can't access file %s\n", filename); + exit(1); + } + + /* read the file */ + root = json_object_from_file(filename); + if (!root) { + fprintf(stderr, "reading file %s produced null\n", filename); + exit(1); + } + + /* expand */ + root = expand((struct path){ .object = root, .upper = NULL }); + + /* print the result */ + json_object_to_file_ext ("/dev/stdout", root, JSON_C_TO_STRING_PRETTY); + + /* clean up */ + json_object_put(root); +} + +/** process the list of files or stdin if none */ +int main(int ac, char **av) +{ + if (!*++av) + process("-"); + else { + do { process(*av); } while(*++av); + } + return 0; +} +