devtools: Refactoring, bug fix, new IDL
authorJosé Bollo <jose.bollo@iot.bzh>
Fri, 9 Nov 2018 17:56:05 +0000 (18:56 +0100)
committerJose Bollo <jose.bollo@iot.bzh>
Wed, 27 Nov 2019 08:07:23 +0000 (09:07 +0100)
The programs from devtools are rewritten to
use common improved code with bug fixes.

At the same time, the tool afb-genskel accept
a new JSON format for describing apis.

Change-Id: I38fd25be448bdc0339df63a570bddf53d37b9c3f
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
12 files changed:
src/devtools/CMakeLists.txt
src/devtools/exprefs.c
src/devtools/exprefs.h [new file with mode: 0644]
src/devtools/genskel.md [new file with mode: 0644]
src/devtools/getref.c [new file with mode: 0644]
src/devtools/getref.h [new file with mode: 0644]
src/devtools/idl-monitor.json [new file with mode: 0644]
src/devtools/json2c.c
src/devtools/json2c.h [new file with mode: 0644]
src/devtools/main-exprefs.c [new file with mode: 0644]
src/devtools/main-genskel.c [moved from src/devtools/genskel.c with 70% similarity]
src/devtools/main-json2c.c [new file with mode: 0644]

index 6dfe788..05edaff 100644 (file)
@@ -16,9 +16,9 @@
 # limitations under the License.
 ###########################################################################
 
-ADD_EXECUTABLE(afb-genskel genskel.c)
-ADD_EXECUTABLE(afb-exprefs exprefs.c)
-ADD_EXECUTABLE(afb-json2c json2c.c)
+ADD_EXECUTABLE(afb-genskel main-genskel.c exprefs.c getref.c json2c.c)
+ADD_EXECUTABLE(afb-exprefs main-exprefs.c exprefs.c getref.c)
+ADD_EXECUTABLE(afb-json2c main-json2c.c json2c.c)
 
 TARGET_LINK_LIBRARIES(afb-genskel ${link_libraries})
 TARGET_LINK_LIBRARIES(afb-exprefs ${link_libraries})
index 4459f2c..cfd3941 100644 (file)
 #define _GNU_SOURCE
 #include <string.h>
 #include <stdio.h>
-#include <unistd.h>
 
 #include <json-c/json.h>
 
+#include "getref.h"
+#include "exprefs.h"
+
 /**
  * records path to the expanded node
  */
 struct path
 {
        struct json_object *object;     /**< node being expanded */
-       struct path *upper;             /**< link to upper expanded nodes */
+       const 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
+ * Returns the top object
  */
-struct json_object *search(const char *path)
+static inline struct json_object *top(const struct path *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;
+       while (path->upper)
+               path = path->upper;
+       return path->object;
 }
 
 /**
  * Expands the node designated by path and returns its expanded form
  */
-struct json_object *expand(struct path path)
+static struct json_object *expand(const struct path *upper)
 {
-       struct path *p;
-       struct json_object *o, *x;
+       struct path here;
+       struct json_object *object, *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)) {
+       here.upper = upper;
+       object = upper->object;
+       switch (json_object_get_type(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));
+               if (json_object_object_get_ex(object, "$ref", &here.object)) {
+                       /* check that "$ref" value is a string */
+                       if (!json_object_is_type(here.object, json_type_string)) {
+                               fprintf(stderr, "found a $ref not being string. Is: %s\n", json_object_get_string(here.object));
                                exit(1);
                        }
-                       x = search(json_object_get_string(o));
-                       if (!x) {
-                               fprintf(stderr, "$ref not found. Was: %s\n", json_object_get_string(o));
+                       /* yes, reference, try to substitute its target */
+                       i = search$ref(top(upper), json_object_get_string(here.object), &x);
+                       if (!i) {
+                               fprintf(stderr, "$ref not found. Was: %s\n", json_object_get_string(here.object));
                                exit(1);
                        }
-                       p = &path;
-                       while(p) {
-                               if (x == p->object) {
-                                       fprintf(stderr, "$ref recursive. Was: %s\n", json_object_get_string(o));
+                       /* check not recursive */
+                       upper = &here;
+                       while(upper) {
+                               if (x == upper->object) {
+                                       fprintf(stderr, "$ref recursive. Was: %s\n", json_object_get_string(here.object));
                                        exit(1);
                                }
-                               p = p->upper;
+                               upper = upper->upper;
                        }
-                       /* cool found, return a new instance of the target */
-                       return json_object_get(x);
+                       /* found. return a new instance of the target */
+                       return x;
                }
                /* no, expand the values */
-               ji = json_object_iter_begin(path.object);
-               jn = json_object_iter_end(path.object);
+               ji = json_object_iter_begin(object);
+               jn = json_object_iter_end(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);
+                       here.object = json_object_iter_peek_value(&ji);
+                       x = expand(&here);
+                       if (x != here.object)
+                               json_object_object_add(object, json_object_iter_peek_name(&ji), json_object_get(x));
                        json_object_iter_next(&ji);
                }
                break;
        case json_type_array:
                /* expand the values of arrays */
                i = 0;
-               n = (int)json_object_array_length(path.object);
+               n = (int)json_object_array_length(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);
+                       here.object = json_object_array_get_idx(object, i);
+                       x = expand(&here);
+                       if (x != here.object)
+                               json_object_array_put_idx(object, i, json_object_get(x));
                        i++;
                }
                break;
@@ -150,49 +136,62 @@ struct json_object *expand(struct path path)
                break;
        }
        /* return the given node */
-       return path.object;
+       return object;
 }
 
-/**
- * process a file and prints its expansion on stdout
- */
-void process(char *filename)
+struct json_object *exp$refs(struct json_object *root)
 {
-       /* translate - */
-       if (!strcmp(filename, "-"))
-               filename = "/dev/stdin";
+       struct path top = { .object = root, .upper = NULL };
+       return expand(&top);
+}
 
-       /* check access */
-       if (access(filename, R_OK)) {
-               fprintf(stderr, "can't access file %s\n", filename);
-               exit(1);
-       }
+static int is_tree(struct json_object *object, const struct path *upper)
+{
+       struct path here;
+       int n, i;
+       struct json_object_iterator ji, jn;
 
-       /* read the file */
-       root = json_object_from_file(filename);
-       if (!root) {
-               fprintf(stderr, "reading file %s produced null\n", filename);
-               exit(1);
+       switch (json_object_get_type(object)) {
+       case json_type_object:
+       case json_type_array:
+               /* check recursive */
+               here.upper = upper;
+               while (upper) {
+                       if (upper->object == object)
+                               return 0;
+                       upper = upper->upper;
+               }
+               here.object = object;
+               switch (json_object_get_type(object)) {
+               case json_type_object:
+                       ji = json_object_iter_begin(object);
+                       jn = json_object_iter_end(object);
+                       while (!json_object_iter_equal(&ji, &jn)) {
+                               if (!is_tree(json_object_iter_peek_value(&ji), &here))
+                                       return 0;
+                               json_object_iter_next(&ji);
+                       }
+                       break;
+               case json_type_array:
+                       i = 0;
+                       n = (int)json_object_array_length(object);
+                       while (i != n) {
+                               if (!is_tree(json_object_array_get_idx(object, i), &here))
+                                       return 0;
+                               i++;
+                       }
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
        }
-
-       /* 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);
+       return 1;
 }
 
-/** process the list of files or stdin if none */
-int main(int ac, char **av)
+int exp$refs_is_tree(struct json_object *root)
 {
-       if (!*++av)
-               process("-");
-       else {
-               do { process(*av); } while(*++av);
-       }
-       return 0;
+       return is_tree(root, NULL);
 }
-
diff --git a/src/devtools/exprefs.h b/src/devtools/exprefs.h
new file mode 100644 (file)
index 0000000..8def4b6
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "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.
+ */
+
+#pragma once
+
+struct json_object;
+
+extern struct json_object *exp$refs(struct json_object *root);
+extern int exp$refs_is_tree(struct json_object *root);
diff --git a/src/devtools/genskel.md b/src/devtools/genskel.md
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/src/devtools/getref.c b/src/devtools/getref.c
new file mode 100644 (file)
index 0000000..9e829dd
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "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 <stdio.h>
+#include <string.h>
+
+#include <json-c/json.h>
+
+#include "getref.h"
+
+/**
+ * Search for a reference of type "#/a/b/c" int the
+ * parsed JSON root object
+ */
+int search$ref(struct json_object *root, const char *ref, struct json_object **result)
+{
+       char *d;
+       struct json_object *i;
+
+       /* does it match #/ at the beginning? */
+       if (ref[0] != '#' || (ref[0] && ref[1] != '/')) {
+               fprintf(stderr, "$ref invalid. Was: %s", ref);
+               return 0;
+       }
+
+       /* search from root to target */
+       i = root;
+       d = strdupa(ref+2);
+       d = strtok(d, "/");
+       while(i && d) {
+               if (!json_object_object_get_ex(i, d, &i))
+                       return 0;
+               d = strtok(NULL, "/");
+       }
+       if (result)
+               *result = i;
+       return 1;
+}
+
+struct json_object *get$ref(struct json_object *root, const char *ref)
+{
+       struct json_object *result;
+       return search$ref(root, ref, &result) ? result : NULL;
+}
diff --git a/src/devtools/getref.h b/src/devtools/getref.h
new file mode 100644 (file)
index 0000000..afa3838
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "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.
+ */
+
+#pragma once
+
+struct json_object;
+
+extern int search$ref(struct json_object *root, const char *ref, struct json_object **result);
+extern struct json_object *get$ref(struct json_object *root, const char *ref);
diff --git a/src/devtools/idl-monitor.json b/src/devtools/idl-monitor.json
new file mode 100644 (file)
index 0000000..5afc29d
--- /dev/null
@@ -0,0 +1,296 @@
+{
+  "afbidl": "0.1",
+  "info": {
+    "description": "monitoring of bindings and internals",
+    "title": "monitor",
+    "version": "1.0"
+  },
+  "generator": {
+    "genskel": {
+      "version": 2,
+      "prefix": "f_",
+      "postfix": "",
+      "preinit": null,
+      "init": null,
+      "onevent": null,
+      "scope": "static",
+      "private": true
+    }
+  },
+  "api": {
+    "name": "monitor",
+    "verbs": {
+      "get": {
+        "description": "Get monitoring data.",
+        "permissions": { "session": "check" },
+        "request": { "$ref": "#/schemas/get-request" },
+        "reply": { "$ref": "#/schemas/get-reply" }
+      },
+      "set": {
+        "description": "Set monitoring actions.",
+        "permissions": { "session": "check" },
+        "request": { "$ref": "#/schemas/set-request" },
+        "reply": { "$ref": "#/schemas/any" }
+      },
+      "trace": {
+        "description": "Set monitoring actions.",
+        "permissions": { "session": "check" },
+        "request": { "$ref": "#/schemas/trace-request" },
+        "reply": { "$ref": "#/schemas/any" }
+      },
+      "session": {
+        "description": "describes the session.",
+        "permissions": { "session": "check" },
+        "request": { "$ref": "#/schemas/session-request" },
+        "reply": { "$ref": "#/schemas/any" }
+      }
+    }
+  },
+  "schemas": {
+    "any": {
+      "title": "Any value",
+      "type": [ "null", "boolean", "object", "array", "number", "string" ]
+    },
+    "set-request": {
+      "type": "object",
+      "properties": {
+        "verbosity": { "$ref": "#/schemas/set-verbosity" }
+      }
+    },
+    "set-verbosity": {
+      "anyOf": [
+        { "$ref": "#/schemas/verbosity-map" },
+        { "$ref": "#/schemas/verbosity-level" }
+      ]
+    },
+    "get-request": {
+      "type": "object",
+      "properties": {
+        "verbosity": { "$ref": "#/schemas/get-verbosity" },
+        "apis": { "$ref": "#/schemas/get-apis" }
+      }
+    },
+    "get-reply": {
+      "type": "object",
+      "properties": {
+        "verbosity": { "$ref": "#/schemas/verbosity-map" },
+        "apis": { "type": "object" }
+      }
+    },
+    "get-verbosity": {
+      "anyOf": [
+        { "type": "boolean" },
+        { "type": "array", "items": { "type": "string" } },
+        { "type": "object" }
+      ]
+    },
+    "get-apis": {
+      "anyOf": [
+        { "type": "boolean" },
+        { "type": "array", "items": { "type": "string" } },
+        { "type": "object" }
+      ]
+    },
+    "verbosity-map": {
+      "type": "object",
+      "patternProperties": { "^.*$": { "$ref": "#/schemas/verbosity-level" } }
+    },
+    "verbosity-level": {
+      "enum": [ "debug", 3, "info", 2, "notice", "warning", 1, "error", 0 ]
+    },
+    "trace-request": {
+      "type": "object",
+      "properties": {
+        "add": { "$ref": "#/schemas/trace-add" },
+        "drop": { "$ref": "#/schemas/trace-drop" }
+      }
+    },
+    "trace-add": {
+      "anyOf": [
+        { "type": "array", "items": { "$ref": "#/schemas/trace-add-object" } },
+        { "$ref": "#/schemas/trace-add-any" }
+      ]
+    },
+    "trace-add-any": {
+      "anyOf": [
+        { "$ref": "#/schemas/trace-add-request" },
+        { "$ref": "#/schemas/trace-add-object" }
+      ]
+    },
+    "trace-add-object": {
+      "type": "object",
+      "properties": {
+        "name": { "type": "string", "description": "name of the generated event", "default": "trace" },
+        "tag": { "type": "string", "description": "tag for grouping traces", "default": "trace" },
+        "api": { "type": "string", "description": "api for requests, daemons and services" },
+        "verb": { "type": "string", "description": "verb for requests" },
+        "uuid": { "type": "string", "description": "uuid of session for requests" },
+        "pattern": { "type": "string", "description": "pattern for events" },
+        "request": { "$ref": "#/schemas/trace-add-request" },
+        "daemon": { "$ref": "#/schemas/trace-add-daemon" },
+        "service": { "$ref": "#/schemas/trace-add-service" },
+        "event": { "$ref": "#/schemas/trace-add-event" },
+        "session": { "$ref": "#/schemas/trace-add-session" },
+        "for": { "$ref": "#/schemas/trace-add" }
+      },
+      "examples": [
+        { "tag": "1", "for": [ "common", { "api": "xxx", "request": "*", "daemon": "*", "service": "*" } ] }
+      ]
+    },
+    "trace-add-request": {
+      "anyOf": [
+        { "type": "array", "items": { "$ref": "#/schemas/trace-request-names" } },
+        { "$ref": "#/schemas/trace-request-names" }
+      ]
+    },
+    "trace-request-names": {
+      "title": "name of traceable items of requests",
+      "enum": [
+        "*",
+        "addref",
+        "all",
+        "args",
+        "begin",
+        "common",
+        "context",
+        "context_get",
+        "context_set",
+        "end",
+        "event",
+        "extra",
+        "get",
+        "json",
+        "life",
+        "ref",
+         "reply",
+        "result",
+        "session",
+        "session_close",
+        "session_set_LOA",
+        "simple",
+        "store",
+        "stores",
+        "subcall",
+        "subcall_result",
+        "subcalls",
+        "subcallsync",
+        "subcallsync_result",
+        "subscribe",
+        "unref",
+        "unstore",
+        "unsubscribe",
+        "vverbose"
+      ]
+    },
+    "trace-add-daemon": {
+      "anyOf": [
+        { "type": "array", "items": { "$ref": "#/schemas/trace-daemon-names" } },
+        { "$ref": "#/schemas/trace-daemon-names" }
+      ]
+    },
+    "trace-daemon-names": {
+      "title": "name of traceable items of daemons",
+      "enum": [
+        "*",
+        "all",
+        "common",
+        "event_broadcast_after",
+        "event_broadcast_before",
+        "event_make",
+        "extra",
+        "get_event_loop",
+        "get_system_bus",
+        "get_user_bus",
+        "queue_job",
+        "require_api",
+        "require_api_result",
+        "rootdir_get_fd",
+        "rootdir_open_locale",
+        "unstore_req",
+        "vverbose"
+      ]
+    },
+    "trace-add-service": {
+      "anyOf": [
+        { "type": "array", "items": { "$ref": "#/schemas/trace-service-names" } },
+        { "$ref": "#/schemas/trace-service-names" }
+      ]
+    },
+    "trace-service-names": {
+      "title": "name of traceable items of services",
+      "enum": [
+        "*",
+        "all",
+        "call",
+        "call_result",
+        "callsync",
+        "callsync_result",
+        "on_event_after",
+        "on_event_before",
+        "start_after",
+        "start_before"
+      ]
+    },
+    "trace-add-event": {
+      "anyOf": [
+        { "type": "array", "items": { "$ref": "#/schemas/trace-event-names" } },
+        { "$ref": "#/schemas/trace-event-names" }
+      ]
+    },
+    "trace-event-names": {
+      "title": "name of traceable items of events",
+      "enum": [
+        "*",
+        "all",
+        "broadcast_after",
+        "broadcast_before",
+        "common",
+        "create",
+        "drop",
+        "extra",
+        "name",
+        "push_after",
+        "push_before"
+      ]
+    },
+    "trace-add-session": {
+      "anyOf": [
+        { "type": "array", "items": { "$ref": "#/schemas/trace-session-names" } },
+        { "$ref": "#/schemas/trace-session-names" }
+      ]
+    },
+    "trace-session-names": {
+      "title": "name of traceable items for sessions",
+      "enum": [
+        "*",
+        "addref",
+        "all",
+        "close",
+        "common",
+        "create",
+        "destroy",
+        "renew",
+        "unref"
+      ]
+    },
+    "trace-drop": {
+      "anyOf": [
+        { "type": "boolean" },
+        {
+          "type": "object",
+          "properties": {
+            "event": { "anyOf": [  { "type": "string" }, { "type": "array", "items": "string" } ] },
+            "tag": { "anyOf": [  { "type": "string" }, { "type": "array", "items": "string" } ] },
+            "uuid": { "anyOf": [  { "type": "string" }, { "type": "array", "items": "string" } ] }
+          }
+        }
+      ]
+    },
+    "session-request": {
+      "type": "object",
+      "properties": {
+        "refresh-token": { "type": "boolean" }
+      }
+    }
+  }
+}
index 9bb9e9b..c26ef84 100644 (file)
 
 #define _GNU_SOURCE
 #include <string.h>
+#include <limits.h>
+#include <assert.h>
 #include <stdio.h>
-#include <unistd.h>
 
 #include <json-c/json.h>
 
-#define oom(x) do{if(!(x)){fprintf(stderr,"out of memory\n");exit(1);}}while(0)
-
-/**
- * root of the JSON being parsed
- */
-struct json_object *root = NULL;
-
-char *make_desc(struct json_object *o)
+static size_t s2c(const char *str, const char *prefix, int width, int lprf, char *out)
 {
-       const char *a, *b;
-       char *desc, c, buf[3];
+       char c, buf[4];
        size_t len;
-       int i, pos, e;
-
-       a = b = json_object_to_json_string_ext(root, 0);
-       len = 1;
-       while((c = *b++)) {
-               len += 1 + ('"' == c);
-       }
-
-       len += 7 * (1 + len / 72);
-       desc = malloc(len);
-       oom(desc);
+       int i, pos;
 
+#define P(x) do{ if (out) out[len] = (x); len++; pos++; }while(0)
+       /* translate the string */
        len = pos = 0;
-       b = a;
-       while((c = *b++)) {
-               if (c == '"') {
+       for(;;) {
+               /* get the char to convert */
+               c = *str++;
+
+               /* set buf with next char */
+               switch(c) {
+               case '\\':
+                       c = *str++;
+                       if (c) {
+                               if (c == '/') {
+                                       /* remove ugly \/ put by json-c */
+                                       buf[0] = '/';
+                                       buf[1] = 0;
+                               } else {
+                                       buf[0] = '\\';
+                                       buf[1] = c;
+                                       buf[2] = 0;
+                               }
+                               break;
+                       }
+                       /*@fallthrough@*/
+               case 0:
+                       if (!len) P('"');
+                       if (!len || pos) {
+                               P('"');
+                               if (prefix) P('\n');
+                       }
+                       P(0);
+                       return len;
+               case '"':
                        buf[0] = '\\';
                        buf[1] = '"';
                        buf[2] = 0;
-               }
-               else if (c == '\\') {
-                       switch ((c = *b++)) {
-                       case '/':
-                               buf[0] = '/';
-                               buf[1] = 0;
-                               break;
-                       case 0:
-                               b--;
-                               /*@fallthrough@*/
-                       default:
+                       break;
+               case '\n':
+                       buf[0] = '\\';
+                       buf[1] = 'n';
+                       buf[2] = 0;
+                       break;
+               case '\t':
+                       buf[0] = '\\';
+                       buf[1] = 't';
+                       buf[2] = 0;
+                       break;
+               default:
+                       if (0 < c && c < ' ') {
                                buf[0] = '\\';
-                               buf[1] = c;
-                               buf[2] = 0;
+                               buf[1] = (char)('0' + ((c >> 3) & 7));
+                               buf[2] = (char)('0' + ((c >> 0) & 7));
+                               buf[3] = 0;
+                       } else {
+                               buf[0] = c;
+                               buf[1] = 0;
                                break;
                        }
+                       break;
                }
-               else {
-                       buf[0] = c;
-                       buf[1] = 0;
+               /* add the char in the output */
+               if (pos == 0) {
+                       for(i = 0 ; i < lprf ; i++)
+                               P(prefix[i]);
+                       P('"');
                }
-               i = e = 0;
-               while (buf[i]) {
-                       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++;
+               for(i = 0 ; buf[i] ; i++)
+                       P(buf[i]);
+               if (pos >= width - 1) {
+                       P('"');
+                       P('\n');
+                       pos = 0;
                }
        }
-       desc[len++] = '"';
-       desc[len++] = '\n';
-       desc[len] = 0;
-       return desc;
+       while(c);
+#undef P
 }
 
-/**
- * process a file and prints its expansion on stdout
- */
-void process(char *filename)
+char *str2c(const char *str, const char *prefix, int width)
 {
-       char *desc;
+       size_t len;
+       int lprf;
+       char *out;
 
-       /* translate - */
-       if (!strcmp(filename, "-"))
-               filename = "/dev/stdin";
+       /* ensure defaults */
+       len = prefix ? strlen(prefix) : 0;
+       lprf = len > INT_MAX ? INT_MAX : (int)len;
+       width = width <= 0 || width - 2 <= lprf ? INT_MAX : width;
 
-       /* check access */
-       if (access(filename, R_OK)) {
-               fprintf(stderr, "can't access file %s\n", filename);
-               exit(1);
-       }
+       /* compute final size*/
+       len = s2c(str, prefix, width, lprf, NULL);
 
-       /* read the file */
-       root = json_object_from_file(filename);
-       if (!root) {
-               fprintf(stderr, "reading file %s produced null\n", filename);
-               exit(1);
-       }
+       /* allocate the memory */
+       out = malloc(len);
+       if (!out)
+               return NULL;
 
-       /* create the description */
-       desc = make_desc(root);
+       /* make the output */
+       s2c(str, prefix, width, lprf, out);
+       return out;
+}
 
-       printf("%s", desc);
+char *str2c_std(const char *str)
+{
+       return str2c(str, "\t", 71);
+}
 
-       /* clean up */
-       json_object_put(root);
-       free(desc);
+char *str2c_inl(const char *str)
+{
+       return str2c(str, 0, 0);
 }
 
-/** process the list of files or stdin if none */
-int main(int ac, char **av)
+char *json2c(struct json_object *object, const char *prefix, int width)
 {
-       if (!*++av)
-               process("-");
-       else {
-               do { process(*av); } while(*++av);
-       }
-       return 0;
+       return str2c(json_object_to_json_string_ext(object, 0), prefix, width);
 }
 
+char *json2c_std(struct json_object *object)
+{
+       return str2c_std(json_object_to_json_string_ext(object, 0));
+}
 
+char *json2c_inl(struct json_object *object)
+{
+       return str2c_inl(json_object_to_json_string_ext(object, 0));
+}
diff --git a/src/devtools/json2c.h b/src/devtools/json2c.h
new file mode 100644 (file)
index 0000000..9c4e7e2
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "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.
+ */
+
+#pragma once
+
+struct json_object;
+
+extern char *str2c(const char *str, const char *prefix, int width);
+extern char *str2c_std(const char *str);
+extern char *str2c_inl(const char *str);
+
+extern char *json2c(struct json_object *object, const char *prefix, int width);
+extern char *json2c_std(struct json_object *object);
+extern char *json2c_inl(struct json_object *object);
diff --git a/src/devtools/main-exprefs.c b/src/devtools/main-exprefs.c
new file mode 100644 (file)
index 0000000..5a114a2
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "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 <json-c/json.h>
+
+#include "exprefs.h"
+
+/**
+ * process a file and prints its expansion on stdout
+ */
+void process(char *filename)
+{
+       struct json_object *root;
+
+       /* 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 = exp$refs(root);
+
+       /* check if tree */
+       if (!exp$refs_is_tree(root)) {
+               fprintf(stderr, "expansion of %s doesn't produce a tree\n", filename);
+               exit(1);
+       }
+
+       /* 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;
+}
+
similarity index 70%
rename from src/devtools/genskel.c
rename to src/devtools/main-genskel.c
index 80dcd38..bad7ee9 100644 (file)
  * 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 <json-c/json.h>
 
-#define T(x)   ((x) && *(x))
-#define oom(x) do{if(!(x)){fprintf(stderr,"out of memory\n");exit(1);}}while(0)
+#include "getref.h"
+#include "exprefs.h"
+#include "json2c.h"
 
-/**
- * records path to the expanded node
- */
-struct path
-{
-       struct json_object *object;     /**< node being expanded */
-       struct path *upper;             /**< link to upper expanded nodes */
-};
+#define TEST(x)   ((x) && *(x))
+#define OOM(x) do{if(!(x)){fprintf(stderr,"out of memory\n");exit(1);}}while(0)
 
 /**
  * root of the JSON being parsed
@@ -77,103 +47,17 @@ const char *postfix = NULL;
 const char *provideclass = NULL;
 const char *requireclass = NULL;
 const char *requireapi = NULL;
+const char *info = NULL;
 char *capi = NULL;
 int priv = -1;
 int noconc = -1;
 int cpp = 0;
+enum idl {
+       idl_afbidl = 0,
+       idl_openapi = 1
+} idl = idl_openapi;
 
-/**
- * Search for a reference of type "#/a/b/c" in the
- * parsed JSON object (root)
- */
-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 = (int)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;
-}
 
 /* create c name by replacing non alpha numeric characters with underscores */
 char *cify(const char *str)
@@ -188,97 +72,14 @@ char *cify(const char *str)
        return r;
 }
 
-/* format the specification as a C string */
-char *make_info(const char *text, int split)
-{
-       const char *a, *b;
-       char *desc, c, buf[3] = {0};
-       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--;
-                               buf[0] = 0;
-                               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;
-}
-
-/* make the description of the object */
-char *make_desc(struct json_object *o)
-{
-       return make_info(json_object_to_json_string_ext(o, 0), 1);
-}
-
 /* get the permission odescription if set */
 struct json_object *permissions_of_verb(struct json_object *obj)
 {
        struct json_object *x, *y;
 
+       if (idl == idl_afbidl)
+               return json_object_object_get_ex(obj, "permissions", &x) ? x : NULL;
+
        if (json_object_object_get_ex(obj, "x-permissions", &x))
                return x;
 
@@ -540,7 +341,7 @@ void print_verb(const char *name)
 
 void print_declare_verb(const char *name, struct json_object *obj)
 {
-       if (T(scope))
+       if (TEST(scope))
                printf("%s ", scope);
        printf("void ");
        print_verb(name);
@@ -569,7 +370,7 @@ void print_struct_verb(const char *name, struct json_object *obj)
                "        .auth = %s,\n"
                "        .info = %s,\n"
                , p && decl_perm(p) ? json_object_get_string(decl_perm(p)) : "NULL"
-               , info ? make_info(info, 0) : "NULL"
+               , info ? str2c_inl(info) : "NULL"
        );
        if (version == 3)
                printf(
@@ -590,14 +391,60 @@ void print_struct_verb(const char *name, struct json_object *obj)
        );
 }
 
-void enum_verbs(void (*func)(const char *name, struct json_object *obj))
+void getvarbool(int *var, const char *path, int defval)
+{
+       struct json_object *o;
+
+       if (*var != 0 && *var != 1) {
+               o = get$ref(root, 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 = get$ref(root, path);
+               if (o && json_object_is_type(o, json_type_string))
+                       *var = json_object_get_string(o);
+               else
+                       *var = defval;
+       }
+}
+
+/******************************************************************************/
+
+void openapi_getvars()
+{
+       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");
+       getvar(&provideclass, "#/info/x-binding-c-generator/provide-class", NULL);
+       getvar(&requireclass, "#/info/x-binding-c-generator/require-class", NULL);
+       getvar(&requireapi, "#/info/x-binding-c-generator/require-api", NULL);
+       getvarbool(&priv, "#/info/x-binding-c-generator/private", 0);
+       getvarbool(&noconc, "#/info/x-binding-c-generator/noconcurrency", 0);
+       getvar(&api, "#/info/title", "?");
+       getvar(&info, "#/info/description", NULL);
+}
+
+void openapi_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");
+       paths = get$ref(root, "#/paths");
        if (!paths)
                return;
 
@@ -613,29 +460,63 @@ void enum_verbs(void (*func)(const char *name, struct json_object *obj))
        }
 }
 
-void getvarbool(int *var, const char *path, int defval)
+/******************************************************************************/
+
+void afbidl_getvars()
 {
-       struct json_object *o;
+       getvar(&preinit, "#/generator/genskel/preinit", NULL);
+       getvar(&init, "#/generator/genskel/init", NULL);
+       getvar(&onevent, "#/generator/genskel/onevent", NULL);
+       getvar(&scope, "#/generator/genskel/scope", "static");
+       getvar(&prefix, "#/generator/genskel/prefix", "afb_verb_");
+       getvar(&postfix, "#/generator/genskel/postfix", "_cb");
+       getvar(&provideclass, "#/generator/genskel/provide-class", NULL);
+       getvar(&requireclass, "#/generator/genskel/require-class", NULL);
+       getvar(&requireapi, "#/generator/genskel/require-api", NULL);
+       getvarbool(&priv, "#/generator/genskel/private", 0);
+       getvarbool(&noconc, "#/generator/genskel/noconcurrency", 0);
+       getvar(&api, "#/api/name", NULL);
+       getvar(&api, "#/info/title", "?");
+       getvar(&info, "#/info/description", NULL);
+}
 
-       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 afbidl_enum_verbs(void (*func)(const char *name, struct json_object *obj))
+{
+       struct json_object_iterator ji, jn;
+       struct json_object *verbs, *obj;
+       const char *name;
+
+       /* search the verbs */
+       verbs = get$ref(root, "#/api/verbs");
+       if (!verbs)
+               return;
+
+       /* list the verbs and sort it */
+       ji = json_object_iter_begin(verbs);
+       jn = json_object_iter_end(verbs);
+       while (!json_object_iter_equal(&ji, &jn)) {
+               name = json_object_iter_peek_name(&ji);
+               obj = json_object_iter_peek_value(&ji);
+               func(name, obj);
+               json_object_iter_next(&ji);
        }
 }
 
-void getvar(const char **var, const char *path, const char *defval)
+/******************************************************************************/
+
+void detectidl()
 {
        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;
+       o = get$ref(root, "#/openapi");
+       if (o) {
+               idl = idl_openapi;
+               return;
+       }
+       o = get$ref(root, "#/afbidl");
+       if (o) {
+               idl = idl_afbidl;
+               return;
        }
 }
 
@@ -645,7 +526,9 @@ void getvar(const char **var, const char *path, const char *defval)
 void process(char *filename)
 {
        char *desc;
-       const char *info;
+
+       void (*getvars)();
+       void (*enum_verbs)(void (*)(const char*, struct json_object*));
 
        /* translate - */
        if (!strcmp(filename, "-"))
@@ -664,28 +547,28 @@ void process(char *filename)
                exit(1);
        }
 
-       /* create the description */
-       desc = make_desc(root);
+       /* create the description (before expanding $ref ) */
+       desc = json2c_std(root);
 
        /* expand references */
-       root = expand_$ref((struct path){ .object = root, .upper = NULL });
+       root = exp$refs(root);
+
+       /* detect the idl */
+       detectidl();
+       switch(idl) {
+       default:
+       case idl_afbidl:
+               getvars = afbidl_getvars;
+               enum_verbs = afbidl_enum_verbs;
+               break;
+       case idl_openapi:
+               getvars = openapi_getvars;
+               enum_verbs = openapi_enum_verbs;
+               break;
+       }
 
        /* 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");
-       getvar(&provideclass, "#/info/x-binding-c-generator/provide-class", NULL);
-       getvar(&requireclass, "#/info/x-binding-c-generator/require-class", NULL);
-       getvar(&requireapi, "#/info/x-binding-c-generator/require-api", NULL);
-       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);
+       getvars();
        capi = cify(api);
 
        /* get the API name */
@@ -727,22 +610,22 @@ void process(char *filename)
                );
        printf(
                "\n"
-               "       }\n"
+               "    }\n"
                "};\n"
        );
 
-       if (T(preinit) || T(init) || T(onevent)) {
+       if (TEST(preinit) || TEST(init) || TEST(onevent)) {
                printf("\n");
-               if (T(preinit)) {
-                       if (T(scope)) printf("%s ", scope);
+               if (TEST(preinit)) {
+                       if (TEST(scope)) printf("%s ", scope);
                        printf("int %s(%s);\n", preinit, version==3 ? "afb_api_t api" : "");
                }
-               if (T(init)) {
-                       if (T(scope)) printf("%s ", scope);
+               if (TEST(init)) {
+                       if (TEST(scope)) printf("%s ", scope);
                        printf("int %s(%s);\n", init, version==3 ? "afb_api_t api" : "");
                }
-               if (T(onevent)) {
-                       if (T(scope)) printf("%s ", scope);
+               if (TEST(onevent)) {
+                       if (TEST(scope)) printf("%s ", scope);
                        printf("void %s(%sconst char *event, struct json_object *object);\n",
                                        onevent, version==3 ? "afb_api_t api, " : "");
                }
@@ -764,11 +647,11 @@ void process(char *filename)
                , priv ? capi : ""
                , api
                , capi
-               , info ? make_info(info, 0) : "NULL"
+               , info ? str2c_inl(info) : "NULL"
                , capi
-               , T(preinit) ? preinit : "NULL"
-               , T(init) ? init : "NULL"
-               , T(onevent) ? onevent : "NULL"
+               , TEST(preinit) ? preinit : "NULL"
+               , TEST(init) ? init : "NULL"
+               , TEST(onevent) ? onevent : "NULL"
        );
 
 
@@ -778,9 +661,9 @@ void process(char *filename)
                        "    .provide_class = %s%s%s,\n"
                        "    .require_class = %s%s%s,\n"
                        "    .require_api = %s%s%s,\n"
-                       , T(provideclass) ? "\"" : "", T(provideclass) ? provideclass : "NULL", T(provideclass) ? "\"" : ""
-                       , T(requireclass) ? "\"" : "", T(requireclass) ? requireclass : "NULL", T(requireclass) ? "\"" : ""
-                       , T(requireapi) ? "\"" : "", T(requireapi) ? requireapi : "NULL", T(requireapi) ? "\"" : ""
+                       , TEST(provideclass) ? "\"" : "", TEST(provideclass) ? provideclass : "NULL", TEST(provideclass) ? "\"" : ""
+                       , TEST(requireclass) ? "\"" : "", TEST(requireclass) ? requireclass : "NULL", TEST(requireclass) ? "\"" : ""
+                       , TEST(requireapi) ? "\"" : "", TEST(requireapi) ? requireapi : "NULL", TEST(requireapi) ? "\"" : ""
                );
 
 
diff --git a/src/devtools/main-json2c.c b/src/devtools/main-json2c.c
new file mode 100644 (file)
index 0000000..eb0c7a0
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2016, 2017, 2018 "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 <json-c/json.h>
+
+#include "json2c.h"
+
+/**
+ * process a file and prints its expansion on stdout
+ */
+void process(char *filename)
+{
+       char *desc;
+       struct json_object *root;
+
+       /* 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 = json2c_std(root);
+       if (!desc) {
+               fprintf(stderr, "out of memory\n");
+               exit(1);
+       }
+
+       /* print the description */
+       printf("%s", desc);
+
+       /* 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;
+}
+
+