afb-config: Rewrite the config as JSON object
[src/app-framework-binder.git] / src / afb-hook-flags.c
diff --git a/src/afb-hook-flags.c b/src/afb-hook-flags.c
new file mode 100644 (file)
index 0000000..738e54c
--- /dev/null
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "afb-hook.h"
+#include "afb-hook-flags.h"
+
+/* structure for searching flags by names */
+struct flag
+{
+       const char *name;       /** the name */
+       int value;              /** the value */
+};
+
+struct flags
+{
+       struct flag *flags;
+       int count;
+};
+
+#define FLAGS(x)   ((struct flags){ .flags = x, .count = (int)(sizeof x / sizeof * x) })
+
+static struct flag xreq_flags[] = { /* must be sorted by names */
+               { "addref",             afb_hook_flag_req_addref },
+               { "all",                afb_hook_flags_req_all },
+               { "args",               afb_hook_flags_req_args },
+               { "begin",              afb_hook_flag_req_begin },
+               { "common",             afb_hook_flags_req_common },
+               { "context",            afb_hook_flags_req_context },
+               { "context_get",        afb_hook_flag_req_legacy_context_get },
+               { "context_make",       afb_hook_flag_req_context_make },
+               { "context_set",        afb_hook_flag_req_legacy_context_set },
+               { "end",                afb_hook_flag_req_end },
+               { "event",              afb_hook_flags_req_event },
+               { "extra",              afb_hook_flags_req_extra },
+               { "get",                afb_hook_flag_req_get },
+               { "get_application_id", afb_hook_flag_req_get_application_id },
+               { "get_client_info",    afb_hook_flag_req_get_client_info },
+               { "get_uid",            afb_hook_flag_req_get_uid },
+               { "has_permission",     afb_hook_flag_req_has_permission },
+               { "json",               afb_hook_flag_req_json },
+               { "life",               afb_hook_flags_req_life },
+               { "ref",                afb_hook_flags_req_ref },
+               { "reply",              afb_hook_flag_req_reply },
+               { "security",           afb_hook_flags_req_security },
+               { "session",            afb_hook_flags_req_session },
+               { "session_close",      afb_hook_flag_req_session_close },
+               { "session_set_LOA",    afb_hook_flag_req_session_set_LOA },
+               { "store",              afb_hook_flag_req_legacy_store },
+               { "stores",             afb_hook_flags_req_stores },
+               { "subcall",            afb_hook_flag_req_subcall },
+               { "subcall_result",     afb_hook_flag_req_subcall_result },
+               { "subcalls",           afb_hook_flags_req_subcalls },
+               { "subcallsync",        afb_hook_flag_req_subcallsync },
+               { "subcallsync_result", afb_hook_flag_req_subcallsync_result },
+               { "subscribe",          afb_hook_flag_req_subscribe },
+               { "unref",              afb_hook_flag_req_unref },
+               { "unstore",            afb_hook_flag_req_legacy_unstore },
+               { "unsubscribe",        afb_hook_flag_req_unsubscribe },
+               { "vverbose",           afb_hook_flag_req_vverbose },
+};
+
+static struct flag api_flags[] = { /* must be sorted by names */
+               { "add_alias",          afb_hook_flag_api_add_alias },
+               { "all",                afb_hook_flags_api_all },
+               { "api_add_verb",       afb_hook_flag_api_api_add_verb },
+               { "api",                afb_hook_flags_api_api },
+               { "api_del_verb",       afb_hook_flag_api_api_del_verb },
+               { "api_seal",           afb_hook_flag_api_api_seal },
+               { "api_set_on_event",   afb_hook_flag_api_api_set_on_event },
+               { "api_set_on_init",    afb_hook_flag_api_api_set_on_init },
+               { "api_set_verbs",      afb_hook_flag_api_api_set_verbs },
+               { "call",               afb_hook_flag_api_call },
+               { "callsync",           afb_hook_flag_api_callsync },
+               { "class_provide",      afb_hook_flag_api_class_provide },
+               { "class_require",      afb_hook_flag_api_class_require },
+               { "common",             afb_hook_flags_api_common },
+               { "delete_api",         afb_hook_flag_api_delete_api },
+               { "event",              afb_hook_flags_api_event },
+               { "event_broadcast",    afb_hook_flag_api_event_broadcast },
+               { "event_handler_add",  afb_hook_flag_api_event_handler_add },
+               { "event_handler_del",  afb_hook_flag_api_event_handler_del },
+               { "event_make",         afb_hook_flag_api_event_make },
+               { "extra",              afb_hook_flags_api_extra },
+               { "get_event_loop",     afb_hook_flag_api_get_event_loop },
+               { "get_system_bus",     afb_hook_flag_api_get_system_bus },
+               { "get_user_bus",       afb_hook_flag_api_get_user_bus },
+               { "legacy_unstore_req", afb_hook_flag_api_legacy_unstore_req },
+               { "new_api",            afb_hook_flag_api_new_api },
+               { "on_event",           afb_hook_flag_api_on_event },
+               { "on_event_handler",   afb_hook_flag_api_on_event_handler },
+               { "queue_job",          afb_hook_flag_api_queue_job },
+               { "require_api",        afb_hook_flag_api_require_api },
+               { "rootdir_get_fd",     afb_hook_flag_api_rootdir_get_fd },
+               { "rootdir_open_locale",afb_hook_flag_api_rootdir_open_locale },
+               { "start",              afb_hook_flag_api_start },
+               { "vverbose",           afb_hook_flag_api_vverbose },
+};
+
+static struct flag evt_flags[] = { /* must be sorted by names */
+               { "addref",             afb_hook_flag_evt_addref },
+               { "all",                afb_hook_flags_evt_all },
+               { "broadcast_after",    afb_hook_flag_evt_broadcast_after },
+               { "broadcast_before",   afb_hook_flag_evt_broadcast_before },
+               { "common",             afb_hook_flags_evt_common },
+               { "create",             afb_hook_flag_evt_create },
+               { "extra",              afb_hook_flags_evt_extra },
+               { "name",               afb_hook_flag_evt_name },
+               { "push_after",         afb_hook_flag_evt_push_after },
+               { "push_before",        afb_hook_flag_evt_push_before },
+               { "unref",              afb_hook_flag_evt_unref },
+};
+
+static struct flag session_flags[] = { /* must be sorted by names */
+               { "addref",             afb_hook_flag_session_addref },
+               { "all",                afb_hook_flags_session_all },
+               { "close",              afb_hook_flag_session_close },
+               { "common",             afb_hook_flags_session_common },
+               { "create",             afb_hook_flag_session_create },
+               { "destroy",            afb_hook_flag_session_destroy },
+               { "renew",              afb_hook_flag_session_renew },
+               { "unref",              afb_hook_flag_session_unref },
+};
+
+static struct flag global_flags[] = { /* must be sorted by names */
+               { "all",                afb_hook_flags_global_all },
+               { "vverbose",           afb_hook_flag_global_vverbose },
+};
+
+static int compare(const char *query, const char *value, size_t query_length)
+{
+       size_t i;
+       char q, v;
+
+       for (i = 0 ; i < query_length ; i++) {
+               v = value[i];
+               q = query[i];
+               if (!v)
+                       return -1;
+               v = v == '_' ? '-' : (char)toupper(v);
+               q = q == '_' ? '-' : (char)toupper(q);
+               if (q != v)
+                       return (int)((unsigned)q - (unsigned)v);
+       }
+       return !!value[i];
+}
+
+/* get the value of the flag of 'name' in the array 'flags' of 'count elements */
+static int get_flag(const char *name, struct flags flags, size_t length)
+{
+       /* replace "*" by "all" */
+       if (length == 1 && *name == '*') {
+               name = "all";
+               length = 3;
+       }
+
+       /* dichotomic search */
+       int lower = 0, upper = flags.count;
+       while (lower < upper) {
+               int mid = (lower + upper) >> 1;
+               int cmp = compare(name, flags.flags[mid].name, length);
+               if (!cmp)
+                       return flags.flags[mid].value;
+               if (cmp < 0)
+                       upper = mid;
+               else
+                       lower = mid + 1;
+       }
+
+       return -(compare(name, "no", length) && compare(name, "none", length));
+}
+
+static int from_text(const char *text, struct flags flags)
+{
+       static const char sep[] = " \t,";
+       size_t s;
+       int result = 0, val;
+
+       if (text) {
+               for (;;) {
+                       text += strspn(text, sep);
+                       if (!*text)
+                               break;
+                       s = strcspn(text, sep);
+                       val = get_flag(text, flags, s);
+                       if (val == -1)
+                               return val;
+                       result |= val;
+                       text += s;
+               }
+       }
+       return result;
+}
+
+static char *to_text(int value, struct flags flags)
+{
+       int borrow = 0, mask = 0, i, v, imask;
+       size_t s = 0;
+       char *result;
+
+       if (!value)
+               return strdup("none");
+
+       do {
+               if (s) {
+                       result = malloc(s + 1);
+                       if (!result)
+                               break;
+               }
+               borrow = 0;
+               while (borrow != value) {
+                       mask = 0;
+                       i = flags.count;
+                       while (i) {
+                               v = flags.flags[--i].value;
+                               if ((mask & v) == mask && (borrow & v) == 0 && (value & v) == v) {
+                                       mask = v;
+                                       imask = i;
+                               }
+                       }
+                       if (mask == 0)
+                               borrow = value;
+                       else {
+                               if (!result)
+                                       s += strlen(flags.flags[imask].name) + !!s;
+                               else {
+                                       if (s)
+                                               result[s++] = ',';
+                                       strcpy(&result[s], flags.flags[imask].name);
+                                       s += strlen(flags.flags[imask].name);
+                               }
+                       }
+               }
+       } while (!result);
+       return result;
+}
+
+int afb_hook_flags_xreq_from_text(const char *text)
+{
+       return from_text(text, FLAGS(xreq_flags));
+}
+
+int afb_hook_flags_api_from_text(const char *text)
+{
+       return from_text(text, FLAGS(api_flags));
+}
+
+int afb_hook_flags_evt_from_text(const char *text)
+{
+       return from_text(text, FLAGS(evt_flags));
+}
+
+int afb_hook_flags_session_from_text(const char *text)
+{
+       return from_text(text, FLAGS(session_flags));
+}
+
+int afb_hook_flags_global_from_text(const char *text)
+{
+       return from_text(text, FLAGS(global_flags));
+}
+
+char *afb_hook_flags_xreq_to_text(int value)
+{
+       return to_text(value, FLAGS(xreq_flags));
+}
+
+char *afb_hook_flags_api_to_text(int value)
+{
+       return to_text(value, FLAGS(api_flags));
+}
+
+char *afb_hook_flags_evt_to_text(int value)
+{
+       return to_text(value, FLAGS(evt_flags));
+}
+
+char *afb_hook_flags_session_to_text(int value)
+{
+       return to_text(value, FLAGS(session_flags));
+}
+
+char *afb_hook_flags_global_to_text(int value)
+{
+       return to_text(value, FLAGS(global_flags));
+}
+
+#if !defined(REMOVE_LEGACY_TRACE)
+static struct flag legacy_ditf_flags[] = { /* must be sorted by names */
+               { "all",                        afb_hook_flags_api_ditf_all },
+               { "common",                     afb_hook_flags_api_ditf_common },
+               { "event_broadcast_after",      afb_hook_flag_api_event_broadcast },
+               { "event_broadcast_before",     afb_hook_flag_api_event_broadcast },
+               { "event_make",                 afb_hook_flag_api_event_make },
+               { "extra",                      afb_hook_flags_api_ditf_extra },
+               { "get_event_loop",             afb_hook_flag_api_get_event_loop },
+               { "get_system_bus",             afb_hook_flag_api_get_system_bus },
+               { "get_user_bus",               afb_hook_flag_api_get_user_bus },
+               { "queue_job",                  afb_hook_flag_api_queue_job },
+               { "require_api",                afb_hook_flag_api_require_api },
+               { "require_api_result",         afb_hook_flag_api_require_api },
+               { "rootdir_get_fd",             afb_hook_flag_api_rootdir_get_fd },
+               { "rootdir_open_locale",        afb_hook_flag_api_rootdir_open_locale },
+               { "unstore_req",                afb_hook_flag_api_legacy_unstore_req },
+               { "vverbose",                   afb_hook_flag_api_vverbose },
+};
+
+static struct flag legacy_svc_flags[] = { /* must be sorted by names */
+               { "all",                afb_hook_flags_api_svc_all },
+               { "call",               afb_hook_flag_api_call },
+               { "call_result",        afb_hook_flag_api_call },
+               { "callsync",           afb_hook_flag_api_callsync },
+               { "callsync_result",    afb_hook_flag_api_callsync },
+               { "on_event_after",     afb_hook_flag_api_on_event },
+               { "on_event_before",    afb_hook_flag_api_on_event },
+               { "start_after",        afb_hook_flag_api_start },
+               { "start_before",       afb_hook_flag_api_start },
+};
+
+int afb_hook_flags_legacy_ditf_from_text(const char *text)
+{
+       return from_text(text, FLAGS(legacy_ditf_flags));
+}
+
+int afb_hook_flags_legacy_svc_from_text(const char *text)
+{
+       return from_text(text, FLAGS(legacy_svc_flags));
+}
+
+char *afb_hook_flags_legacy_ditf_to_text(int value)
+{
+       return to_text(value, FLAGS(legacy_ditf_flags));
+}
+
+char *afb_hook_flags_legacy_svc_to_text(int value)
+{
+       return to_text(value, FLAGS(legacy_svc_flags));
+}
+#endif
+