+++ /dev/null
-/*
- * Copyright (C) 2016, 2017 "IoT.bzh"
- * Author José Bollo <jose.bollo@iot.bzh>
- *
- * 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 <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <json-c/json.h>
-
-#define oom(x) do{if(!(x)){fprintf(stderr,"out of memory\n");exit(1);}}while(0)
-
-/**
- * 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 = NULL;
-struct json_object *d_perms = NULL;
-struct json_object *a_perms = NULL;
-const char *preinit = NULL;
-const char *init = NULL;
-const char *onevent = NULL;
-const char *api = NULL;
-const char *scope = NULL;
-const char *prefix = NULL;
-const char *postfix = NULL;
-char *capi = NULL;
-int priv = -1;
-int noconc = -1;
-
-/**
- * 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_$ref(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_$ref((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_$ref((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;
-}
-
-char *cify(const char *str)
-{
- char *r = strdup(str);
- int i = 0;
- while (r && r[i]) {
- if (!isalnum(r[i]))
- r[i] = '_';
- i++;
- }
- return r;
-}
-
-char *make_info(const char *text, int split)
-{
- const char *a, *b;
- char *desc, c, buf[3];
- size_t len;
- int i, pos, e;
-
- /* estimated length */
- a = b = text;
- len = 1;
- while((c = *b++)) {
- len += 1 + ('"' == c);
- }
-
- len += 7 * (1 + len / 72);
- desc = malloc(len);
- oom(desc);
-
- len = pos = 0;
- if (!split)
- desc[len++] = '"';
- b = a;
- while((c = *b++)) {
- if (c == '"') {
- buf[0] = '\\';
- buf[1] = '"';
- buf[2] = 0;
- }
- else if (c == '\\') {
- switch ((c = *b++)) {
- case 0:
- b--;
- break;
- case '/':
- buf[0] = '/';
- buf[1] = 0;
- break;
- default:
- buf[0] = '\\';
- buf[1] = c;
- buf[2] = 0;
- break;
- }
- }
- else {
- buf[0] = c;
- buf[1] = 0;
- }
- i = e = 0;
- while (buf[i]) {
- if (split) {
- if (pos >= 77 && !e) {
- desc[len++] = '"';
- desc[len++] = '\n';
- pos = 0;
- }
- if (pos == 0) {
- desc[len++] = ' ';
- desc[len++] = ' ';
- desc[len++] = ' ';
- desc[len++] = ' ';
- desc[len++] = '"';
- pos = 5;
- }
- }
- c = buf[i++];
- desc[len++] = c;
- e = !e && c == '\\';
- pos++;
- }
- }
- desc[len++] = '"';
- if (split)
- desc[len++] = '\n';
- desc[len] = 0;
- return desc;
-}
-
-char *make_desc(struct json_object *o)
-{
- return make_info(json_object_to_json_string_ext(root, 0), 1);
-}
-
-struct json_object *permissions_of_verb(struct json_object *obj)
-{
- struct json_object *x, *y;
-
- if (json_object_object_get_ex(obj, "x-permissions", &x))
- return x;
-
- if (json_object_object_get_ex(obj, "get", &x))
- if (json_object_object_get_ex(x, "x-permissions", &y))
- return y;
-
- return NULL;
-}
-
-void print_perms()
-{
- int i, n;
-
- n = a_perms ? json_object_array_length(a_perms) : 0;
- if (n) {
- printf("static const struct afb_auth _afb_auths_v2_%s[] = {\n" , capi);
- i = 0;
- while (i < n) {
- printf("\t{ %s }", json_object_get_string(json_object_array_get_idx(a_perms, i)));
- printf(",\n"+(++i == n));
- }
- printf("};\n\n");
- }
-}
-
-struct json_object *new_perm(struct json_object *obj, const char *desc)
-{
- const char *tag;
- char *b;
- struct json_object *x, *y;
-
- tag = obj ? json_object_to_json_string_ext(obj, 0) : desc;
- if (!json_object_object_get_ex(d_perms, tag, &y)) {
- if (!d_perms) {
- d_perms = json_object_new_object();
- a_perms = json_object_new_array();
- }
-
- asprintf(&b, "&_afb_auths_v2_%s[%d]", capi, json_object_array_length(a_perms));
- x = json_object_new_string(desc);
- y = json_object_new_string(b);
- json_object_array_add(a_perms, x);
- json_object_object_add(d_perms, tag, y);
- free(b);
- }
- return y;
-}
-
-struct json_object *decl_perm(struct json_object *obj);
-
-struct json_object *decl_perm_a(const char *op, struct json_object *obj)
-{
- int i, n;
- char *a;
- struct json_object *x, *y;
-
- x = NULL;
- i = n = obj ? json_object_array_length(obj) : 0;
- while (i) {
- y = decl_perm(json_object_array_get_idx(obj, --i));
- if (!y)
- ;
- else if (!x)
- x = y;
- else if (x != y) {
- asprintf(&a, ".type = afb_auth_%s, .first = %s, .next = %s",
- op, json_object_get_string(y), json_object_get_string(x));
- x = new_perm(NULL, a);
- free(a);
- }
- }
- return x;
-}
-
-struct json_object *decl_perm(struct json_object *obj)
-{
- char *a;
- struct json_object *x, *y;
-
- if (json_object_object_get_ex(d_perms, json_object_to_json_string_ext(obj, 0), &x))
- return x;
-
- if (json_object_object_get_ex(obj, "permission", &x)) {
- asprintf(&a, ".type = afb_auth_Permission, .text = \"%s\"", json_object_get_string(x));
- y = new_perm(obj, a);
- free(a);
- }
- else if (json_object_object_get_ex(obj, "anyOf", &x)) {
- y = decl_perm_a("Or", x);
- }
- else if (json_object_object_get_ex(obj, "allOf", &x)) {
- y = decl_perm_a("And", x);
- }
- else if (json_object_object_get_ex(obj, "not", &x)) {
- x = decl_perm(x);
- asprintf(&a, ".type = afb_auth_Not, .first = %s", json_object_get_string(x));
- y = new_perm(obj, a);
- free(a);
- }
- else if (json_object_object_get_ex(obj, "LOA", &x))
- y = NULL;
- else if (json_object_object_get_ex(obj, "session", &x))
- y = NULL;
- else
- y = NULL;
-
- return y;
-}
-
-void declare_permissions(const char *name, struct json_object *obj)
-{
- struct json_object *p;
-
- p = permissions_of_verb(obj);
- if (p)
- decl_perm(p);
-}
-
-
-#define SESSION_CLOSE 0x000001
-#define SESSION_RENEW 0x000010
-#define SESSION_CHECK 0x000100
-#define SESSION_LOA_1 0x001000
-#define SESSION_LOA_2 0x011000
-#define SESSION_LOA_3 0x111000
-#define SESSION_MASK 0x111111
-
-
-int get_session(struct json_object *obj);
-
-int get_session_a(int and, struct json_object *obj)
-{
- int i, n, x, y;
-
- n = obj ? json_object_array_length(obj) : 0;
- if (n == 0)
- return 0;
-
- i = n;
- x = get_session(json_object_array_get_idx(obj, --i));
- while (i) {
- y = get_session(json_object_array_get_idx(obj, --i));
- if (and)
- x &= y;
- else
- x |= y;
- }
- return x;
-}
-
-int get_session(struct json_object *obj)
-{
- int y;
- const char *a;
- struct json_object *x;
-
- y = 0;
- if (json_object_object_get_ex(obj, "anyOf", &x)) {
- y = get_session_a(1, x);
- }
- else if (json_object_object_get_ex(obj, "allOf", &x)) {
- y = get_session_a(0, x);
- }
- else if (json_object_object_get_ex(obj, "not", &x)) {
- y = ~get_session(x) & SESSION_MASK;
- }
- else if (json_object_object_get_ex(obj, "LOA", &x)) {
- switch (json_object_get_int(x)) {
- case 3: y = SESSION_LOA_3; break;
- case 2: y = SESSION_LOA_2; break;
- case 1: y = SESSION_LOA_1; break;
- default: break;
- }
- }
- else if (json_object_object_get_ex(obj, "session", &x)) {
- a = json_object_get_string(x);
- if (!strcmp(a, "check"))
- y = SESSION_CHECK;
- else if (!strcmp(a, "close"))
- y = SESSION_CLOSE;
- }
- else if (json_object_object_get_ex(obj, "token", &x)) {
- a = json_object_get_string(x);
- if (!strcmp(a, "refresh"))
- y = SESSION_RENEW;
- }
-
- return y;
-}
-
-void print_session(struct json_object *p)
-{
- int s, c, l;
-
- s = p ? get_session(p) : 0;
- c = 1;
- if (s & SESSION_CHECK) {
- printf("%s", "|AFB_SESSION_CHECK_V2" + c);
- c = 0;
- }
- if (s & SESSION_LOA_3 & ~SESSION_LOA_2)
- l = 3;
- else if (s & SESSION_LOA_2 & ~SESSION_LOA_1)
- l = 2;
- else if (s & SESSION_LOA_1)
- l = 1;
- else
- l = 0;
- if (l) {
- printf("%s%d_V2", "|AFB_SESSION_LOA_" + c, l);
- c = 0;
- }
- if (s & SESSION_CLOSE) {
- printf("%s", "|AFB_SESSION_CLOSE_V2" + c);
- c = 0;
- }
- if (s & SESSION_RENEW) {
- printf("%s", "|AFB_SESSION_REFRESH_V2" + c);
- c = 0;
- }
- if (c)
- printf("AFB_SESSION_NONE_V2");
-}
-
-void print_verb(const char *name)
-{
- printf("%s%s%s" , prefix, name, postfix);
-}
-
-void print_declare_verb(const char *name, struct json_object *obj)
-{
- printf("%s void ", scope);
- print_verb(name);
- printf("(struct afb_req req);\n");
-}
-
-void print_struct_verb(const char *name, struct json_object *obj)
-{
- struct json_object *p, *i;
- const char *info;
-
- info = NULL;
- if (json_object_object_get_ex(obj, "description", &i))
- info = json_object_get_string(i);
-
- p = permissions_of_verb(obj);
- printf(
- " {\n"
- " .verb = \"%s\",\n"
- " .callback = "
- , name
- );
- print_verb(name);
- printf(
- ",\n"
- " .auth = %s,\n"
- " .info = %s,\n"
- " .session = "
- , p && decl_perm(p) ? json_object_get_string(decl_perm(p)) : "NULL"
- , info ? make_info(info, 0) : "NULL"
- );
- print_session(p);
- printf(
- "\n"
- " },\n"
- );
-}
-
-void enum_verbs(void (*func)(const char *name, struct json_object *obj))
-{
- struct json_object_iterator ji, jn;
- struct json_object *paths, *obj;
- const char *name;
-
- /* search the verbs */
- paths = search("#/paths");
- if (!paths)
- return;
-
- /* list the verbs and sort it */
- ji = json_object_iter_begin(paths);
- jn = json_object_iter_end(paths);
- while (!json_object_iter_equal(&ji, &jn)) {
- name = json_object_iter_peek_name(&ji);
- obj = json_object_iter_peek_value(&ji);
- name += (*name == '/');
- func(name, obj);
- json_object_iter_next(&ji);
- }
-}
-
-void getvarbool(int *var, const char *path, int defval)
-{
- struct json_object *o;
-
- if (*var != 0 && *var != 1) {
- o = search(path);
- if (o && json_object_is_type(o, json_type_boolean))
- *var = json_object_get_boolean(o);
- else
- *var = !!defval;
- }
-}
-
-void getvar(const char **var, const char *path, const char *defval)
-{
- struct json_object *o;
-
- if (!*var) {
- o = search(path);
- if (o && json_object_is_type(o, json_type_string))
- *var = json_object_get_string(o);
- else
- *var = defval;
- }
-}
-
-/**
- * process a file and prints its expansion on stdout
- */
-void process(char *filename)
-{
- char *desc;
- const char *info;
-
- /* 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);
- }
-
- /* create the description */
- desc = make_desc(root);
-
- /* expand references */
- root = expand_$ref((struct path){ .object = root, .upper = NULL });
-
- /* get some names */
- getvar(&api, "#/info/x-binding-c-generator/api", NULL);
- getvar(&preinit, "#/info/x-binding-c-generator/preinit", NULL);
- getvar(&init, "#/info/x-binding-c-generator/init", NULL);
- getvar(&onevent, "#/info/x-binding-c-generator/onevent", NULL);
- getvar(&scope, "#/info/x-binding-c-generator/scope", "static");
- getvar(&prefix, "#/info/x-binding-c-generator/prefix", "afb_verb_");
- getvar(&postfix, "#/info/x-binding-c-generator/postfix", "_cb");
- getvarbool(&priv, "#/info/x-binding-c-generator/private", 0);
- getvarbool(&noconc, "#/info/x-binding-c-generator/noconcurrency", 0);
- getvar(&api, "#/info/title", "?");
- info = NULL;
- getvar(&info, "#/info/description", NULL);
- capi = cify(api);
-
- /* get the API name */
- printf(
- "\n"
- "static const char _afb_description_v2_%s[] =\n"
- "%s"
- ";\n"
- "\n"
- , capi, desc
- );
- enum_verbs(declare_permissions);
- print_perms();
- enum_verbs(print_declare_verb);
- printf(
- "\n"
- "static const struct afb_verb_v2 _afb_verbs_v2_%s[] = {\n"
- , capi
- );
- enum_verbs(print_struct_verb);
- printf(
- " {\n"
- " .verb = NULL,\n"
- " .callback = NULL,\n"
- " .auth = NULL,\n"
- " .info = NULL,\n"
- " .session = 0\n"
- " }\n"
- "};\n"
- );
- printf(
- "\n"
- "%sconst struct afb_binding_v2 %s%s = {\n"
- " .api = \"%s\",\n"
- " .specification = _afb_description_v2_%s,\n"
- " .info = %s,\n"
- " .verbs = _afb_verbs_v2_%s,\n"
- " .preinit = %s,\n"
- " .init = %s,\n"
- " .onevent = %s,\n"
- " .noconcurrency = %d\n"
- "};\n"
- "\n"
- , priv ? "static " : ""
- , priv ? "_afb_binding_v2_" : "afbBindingV2"
- , priv ? capi : ""
- , api
- , capi
- , info ? make_info(info, 0) : "NULL"
- , capi
- , preinit ?: "NULL"
- , init ?: "NULL"
- , onevent ?: "NULL"
- , !!noconc
- );
-
- /* clean up */
- json_object_put(root);
- free(desc);
-}
-
-/** 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;
-}
-
-
-
-
-