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.
24 #include <json-c/json.h>
30 #define TEST(x) ((x) && *(x))
31 #define OOM(x) do{if(!(x)){fprintf(stderr,"out of memory\n");exit(1);}}while(0)
34 * root of the JSON being parsed
37 struct json_object *root = NULL;
38 struct json_object *d_perms = NULL;
39 struct json_object *a_perms = NULL;
40 const char *preinit = NULL;
41 const char *init = NULL;
42 const char *onevent = NULL;
43 const char *api = NULL;
44 const char *scope = NULL;
45 const char *prefix = NULL;
46 const char *postfix = NULL;
47 const char *provideclass = NULL;
48 const char *requireclass = NULL;
49 const char *requireapi = NULL;
50 const char *info = NULL;
62 /* create c name by replacing non alpha numeric characters with underscores */
63 char *cify(const char *str)
65 char *r = strdup(str);
75 /* get the permission odescription if set */
76 struct json_object *permissions_of_verb(struct json_object *obj)
78 struct json_object *x, *y;
80 if (idl == idl_afbidl)
81 return json_object_object_get_ex(obj, "permissions", &x) ? x : NULL;
83 if (json_object_object_get_ex(obj, "x-permissions", &x))
86 if (json_object_object_get_ex(obj, "get", &x))
87 if (json_object_object_get_ex(x, "x-permissions", &y))
93 /* output the array of permissions */
97 const char *fmtstr = cpp ? "\t%s" : "\t{ %s }";
99 n = a_perms ? (int)json_object_array_length(a_perms) : 0;
101 printf("static const struct afb_auth _afb_auths_%s[] = {\n" , capi);
104 printf(fmtstr, json_object_get_string(json_object_array_get_idx(a_perms, i)));
105 printf(",\n"+(++i == n));
112 * search in the global object 'd_perm' the computed representation
113 * of the permission described either by 'obj' or 'desc'
115 struct json_object *new_perm(struct json_object *obj, const char *desc)
119 struct json_object *x, *y;
121 tag = obj ? json_object_to_json_string_ext(obj, 0) : desc;
122 if (!json_object_object_get_ex(d_perms, tag, &y)) {
124 /* creates the d_perms dico and the a_perms array */
126 d_perms = json_object_new_object();
127 a_perms = json_object_new_array();
130 /* creates the reference in the structure */
131 asprintf(&b, "&_afb_auths_%s[%d]", capi, (int)json_object_array_length(a_perms));
132 x = json_object_new_string(desc);
133 y = json_object_new_string(b);
134 json_object_array_add(a_perms, x);
135 json_object_object_add(d_perms, tag, y);
141 struct json_object *decl_perm(struct json_object *obj);
143 enum optype { And, Or };
145 /* recursive declare and/or permissions */
146 struct json_object *decl_perm_a(enum optype op, struct json_object *obj)
150 const char *opstr, *fmtstr;
151 struct json_object *x, *y;
154 fmtstr = "afb::auth_%s(%s, %s)";
155 opstr = op==And ? "and" : "or";
157 fmtstr = ".type = afb_auth_%s, .first = %s, .next = %s";
158 opstr = op==And ? "And" : "Or";
161 i = n = obj ? (int)json_object_array_length(obj) : 0;
163 y = decl_perm(json_object_array_get_idx(obj, --i));
169 asprintf(&a, fmtstr, opstr, json_object_get_string(y), json_object_get_string(x));
170 x = new_perm(NULL, a);
177 /* declare the permission for obj */
178 struct json_object *decl_perm(struct json_object *obj)
182 struct json_object *x, *y;
184 if (json_object_object_get_ex(d_perms, json_object_to_json_string_ext(obj, 0), &x))
187 if (json_object_object_get_ex(obj, "permission", &x)) {
189 fmt = "afb::auth_permission(\"%s\")";
191 fmt = ".type = afb_auth_Permission, .text = \"%s\"";
192 asprintf(&a, fmt, json_object_get_string(x));
193 y = new_perm(obj, a);
196 else if (json_object_object_get_ex(obj, "anyOf", &x)) {
197 y = decl_perm_a(Or, x);
199 else if (json_object_object_get_ex(obj, "allOf", &x)) {
200 y = decl_perm_a(And, x);
202 else if (json_object_object_get_ex(obj, "not", &x)) {
205 fmt = "afb::auth_not(%s)";
207 fmt = ".type = afb_auth_Not, .first = %s";
208 asprintf(&a, fmt, json_object_get_string(x));
209 y = new_perm(obj, a);
212 else if (json_object_object_get_ex(obj, "LOA", &x))
214 else if (json_object_object_get_ex(obj, "session", &x))
222 void declare_permissions(const char *name, struct json_object *obj)
224 struct json_object *p;
226 p = permissions_of_verb(obj);
232 #define SESSION_CLOSE 0x000001
233 #define SESSION_RENEW 0x000010
234 #define SESSION_CHECK 0x000100
235 #define SESSION_LOA_1 0x001000
236 #define SESSION_LOA_2 0x011000
237 #define SESSION_LOA_3 0x111000
238 #define SESSION_MASK 0x111111
241 int get_session(struct json_object *obj);
243 int get_session_a(int and, struct json_object *obj)
247 n = obj ? (int)json_object_array_length(obj) : 0;
252 x = get_session(json_object_array_get_idx(obj, --i));
254 y = get_session(json_object_array_get_idx(obj, --i));
263 int get_session(struct json_object *obj)
267 struct json_object *x;
270 if (json_object_object_get_ex(obj, "anyOf", &x)) {
271 y = get_session_a(1, x);
273 else if (json_object_object_get_ex(obj, "allOf", &x)) {
274 y = get_session_a(0, x);
276 else if (json_object_object_get_ex(obj, "not", &x)) {
277 y = ~get_session(x) & SESSION_MASK;
279 else if (json_object_object_get_ex(obj, "LOA", &x)) {
280 switch (json_object_get_int(x)) {
281 case 3: y = SESSION_LOA_3; break;
282 case 2: y = SESSION_LOA_2; break;
283 case 1: y = SESSION_LOA_1; break;
287 else if (json_object_object_get_ex(obj, "session", &x)) {
288 a = json_object_get_string(x);
289 if (!strcmp(a, "check"))
291 else if (!strcmp(a, "close"))
294 else if (json_object_object_get_ex(obj, "token", &x)) {
295 a = json_object_get_string(x);
296 if (!strcmp(a, "refresh"))
303 void print_session(struct json_object *p)
307 s = p ? get_session(p) : 0;
309 if (s & SESSION_CHECK) {
310 printf("%s", "|AFB_SESSION_CHECK" + c);
313 if (s & SESSION_LOA_3 & ~SESSION_LOA_2)
315 else if (s & SESSION_LOA_2 & ~SESSION_LOA_1)
317 else if (s & SESSION_LOA_1)
322 printf("%s%d", "|AFB_SESSION_LOA_" + c, l);
325 if (s & SESSION_CLOSE) {
326 printf("%s", "|AFB_SESSION_CLOSE" + c);
329 if (s & SESSION_RENEW) {
330 printf("%s", "|AFB_SESSION_REFRESH" + c);
334 printf("AFB_SESSION_NONE");
337 void print_verb(const char *name)
339 printf("%s%s%s" , prefix, name, postfix);
342 void print_declare_verb(const char *name, struct json_object *obj)
345 printf("%s ", scope);
348 printf("(afb_req_t req);\n");
351 void print_struct_verb(const char *name, struct json_object *obj)
353 struct json_object *p, *i;
357 if (json_object_object_get_ex(obj, "description", &i))
358 info = json_object_get_string(i);
360 p = permissions_of_verb(obj);
372 , p && decl_perm(p) ? json_object_get_string(decl_perm(p)) : "NULL"
373 , info ? str2c_inl(info) : "NULL"
377 " .vcbdata = NULL,\n"
394 void getvarbool(int *var, const char *path, int defval)
396 struct json_object *o;
398 if (*var != 0 && *var != 1) {
399 o = get$ref(root, path);
400 if (o && json_object_is_type(o, json_type_boolean))
401 *var = json_object_get_boolean(o);
407 void getvar(const char **var, const char *path, const char *defval)
409 struct json_object *o;
412 o = get$ref(root, path);
413 if (o && json_object_is_type(o, json_type_string))
414 *var = json_object_get_string(o);
420 /******************************************************************************/
422 void openapi_getvars()
424 getvar(&api, "#/info/x-binding-c-generator/api", NULL);
425 getvar(&preinit, "#/info/x-binding-c-generator/preinit", NULL);
426 getvar(&init, "#/info/x-binding-c-generator/init", NULL);
427 getvar(&onevent, "#/info/x-binding-c-generator/onevent", NULL);
428 getvar(&scope, "#/info/x-binding-c-generator/scope", "static");
429 getvar(&prefix, "#/info/x-binding-c-generator/prefix", "afb_verb_");
430 getvar(&postfix, "#/info/x-binding-c-generator/postfix", "_cb");
431 getvar(&provideclass, "#/info/x-binding-c-generator/provide-class", NULL);
432 getvar(&requireclass, "#/info/x-binding-c-generator/require-class", NULL);
433 getvar(&requireapi, "#/info/x-binding-c-generator/require-api", NULL);
434 getvarbool(&priv, "#/info/x-binding-c-generator/private", 0);
435 getvarbool(&noconc, "#/info/x-binding-c-generator/noconcurrency", 0);
436 getvar(&api, "#/info/title", "?");
437 getvar(&info, "#/info/description", NULL);
440 void openapi_enum_verbs(void (*func)(const char *name, struct json_object *obj))
442 struct json_object_iterator ji, jn;
443 struct json_object *paths, *obj;
446 /* search the verbs */
447 paths = get$ref(root, "#/paths");
451 /* list the verbs and sort it */
452 ji = json_object_iter_begin(paths);
453 jn = json_object_iter_end(paths);
454 while (!json_object_iter_equal(&ji, &jn)) {
455 name = json_object_iter_peek_name(&ji);
456 obj = json_object_iter_peek_value(&ji);
457 name += (*name == '/');
459 json_object_iter_next(&ji);
463 /******************************************************************************/
465 void afbidl_getvars()
467 getvar(&preinit, "#/generator/genskel/preinit", NULL);
468 getvar(&init, "#/generator/genskel/init", NULL);
469 getvar(&onevent, "#/generator/genskel/onevent", NULL);
470 getvar(&scope, "#/generator/genskel/scope", "static");
471 getvar(&prefix, "#/generator/genskel/prefix", "afb_verb_");
472 getvar(&postfix, "#/generator/genskel/postfix", "_cb");
473 getvar(&provideclass, "#/generator/genskel/provide-class", NULL);
474 getvar(&requireclass, "#/generator/genskel/require-class", NULL);
475 getvar(&requireapi, "#/generator/genskel/require-api", NULL);
476 getvarbool(&priv, "#/generator/genskel/private", 0);
477 getvarbool(&noconc, "#/generator/genskel/noconcurrency", 0);
478 getvar(&api, "#/api/name", NULL);
479 getvar(&api, "#/info/title", "?");
480 getvar(&info, "#/info/description", NULL);
483 void afbidl_enum_verbs(void (*func)(const char *name, struct json_object *obj))
485 struct json_object_iterator ji, jn;
486 struct json_object *verbs, *obj;
489 /* search the verbs */
490 verbs = get$ref(root, "#/api/verbs");
494 /* list the verbs and sort it */
495 ji = json_object_iter_begin(verbs);
496 jn = json_object_iter_end(verbs);
497 while (!json_object_iter_equal(&ji, &jn)) {
498 name = json_object_iter_peek_name(&ji);
499 obj = json_object_iter_peek_value(&ji);
501 json_object_iter_next(&ji);
505 /******************************************************************************/
509 struct json_object *o;
511 o = get$ref(root, "#/openapi");
516 o = get$ref(root, "#/afbidl");
524 * process a file and prints its expansion on stdout
526 void process(char *filename)
531 void (*enum_verbs)(void (*)(const char*, struct json_object*));
534 if (!strcmp(filename, "-"))
535 filename = "/dev/stdin";
538 if (access(filename, R_OK)) {
539 fprintf(stderr, "can't access file %s\n", filename);
544 root = json_object_from_file(filename);
546 fprintf(stderr, "reading file %s produced null\n", filename);
550 /* create the description (before expanding $ref ) */
551 desc = json2c_std(root);
553 /* expand references */
554 root = exp$refs(root);
561 getvars = afbidl_getvars;
562 enum_verbs = afbidl_enum_verbs;
565 getvars = openapi_getvars;
566 enum_verbs = openapi_enum_verbs;
574 /* get the API name */
577 "static const char _afb_description_%s[] =\n"
583 enum_verbs(declare_permissions);
585 enum_verbs(print_declare_verb);
588 "static const struct afb_verb_v%d _afb_verbs_%s[] = {\n"
591 enum_verbs(print_struct_verb);
595 " .callback = NULL,\n"
601 " .vcbdata = NULL,\n"
617 if (TEST(preinit) || TEST(init) || TEST(onevent)) {
620 if (TEST(scope)) printf("%s ", scope);
621 printf("int %s(%s);\n", preinit, version==3 ? "afb_api_t api" : "");
624 if (TEST(scope)) printf("%s ", scope);
625 printf("int %s(%s);\n", init, version==3 ? "afb_api_t api" : "");
628 if (TEST(scope)) printf("%s ", scope);
629 printf("void %s(%sconst char *event, struct json_object *object);\n",
630 onevent, version==3 ? "afb_api_t api, " : "");
636 "%sconst struct afb_binding_v%d %s%s = {\n"
638 " .specification = _afb_description_%s,\n"
640 " .verbs = _afb_verbs_%s,\n"
644 , priv ? "static " : ""
646 , priv ? "_afb_binding_" : version==3 ? "afbBindingV3" : "afbBindingV2"
650 , info ? str2c_inl(info) : "NULL"
652 , TEST(preinit) ? preinit : "NULL"
653 , TEST(init) ? init : "NULL"
654 , TEST(onevent) ? onevent : "NULL"
660 " .userdata = NULL,\n"
661 " .provide_class = %s%s%s,\n"
662 " .require_class = %s%s%s,\n"
663 " .require_api = %s%s%s,\n"
664 , TEST(provideclass) ? "\"" : "", TEST(provideclass) ? provideclass : "NULL", TEST(provideclass) ? "\"" : ""
665 , TEST(requireclass) ? "\"" : "", TEST(requireclass) ? requireclass : "NULL", TEST(requireclass) ? "\"" : ""
666 , TEST(requireapi) ? "\"" : "", TEST(requireapi) ? requireapi : "NULL", TEST(requireapi) ? "\"" : ""
671 " .noconcurrency = %d\n"
678 json_object_put(root);
682 /** process the list of files or stdin if none */
683 int main(int ac, char **av)
690 if (!(strcmp(av[r], "-x") && strcmp(av[r], "--cpp"))) {
693 } else if (!strcmp(av[r], "-2")) {
696 } else if (!strcmp(av[r], "-3")) {
707 do { process(*av++); } while(*av);