+static int compare_paths(GArray *a, GArray *b, int len)
+{
+ int i;
+
+ assert(len <= a->len);
+ assert(len <= b->len);
+
+ for (i = 0; i < len; i++) {
+ GQuark qa, qb;
+
+ qa = g_array_index(a, GQuark, i);
+ qb = g_array_index(b, GQuark, i);
+ if (qa != qb)
+ return i;
+ }
+ return i;
+}
+
+static int is_path_child_of(GArray *path, GArray *maybe_parent)
+{
+ int i, ret;
+
+ if (babeltrace_debug) {
+ int need_dot = 0;
+
+ printf_debug("Is path \"");
+ for (i = 0; i < path->len; need_dot = 1, i++)
+ printf("%s%s", need_dot ? "." : "",
+ g_quark_to_string(g_array_index(path, GQuark, i)));
+ need_dot = 0;
+ printf("\" child of \"");
+ for (i = 0; i < maybe_parent->len; need_dot = 1, i++)
+ printf("%s%s", need_dot ? "." : "",
+ g_quark_to_string(g_array_index(maybe_parent, GQuark, i)));
+ printf("\" ? ");
+ }
+
+ if (path->len <= maybe_parent->len) {
+ ret = 0;
+ goto end;
+ }
+ if (compare_paths(path, maybe_parent, maybe_parent->len)
+ == maybe_parent->len)
+ ret = 1;
+ else
+ ret = 0;
+end:
+ if (babeltrace_debug)
+ printf("%s\n", ret ? "Yes" : "No");
+ return ret;
+}
+
+static struct definition_scope *
+ get_definition_scope(struct definition *definition)
+{
+ return definition->scope;
+}
+
+/*
+ * OK, here is the fun. We want to lookup a field that is:
+ * - either in the same dynamic scope:
+ * - either in the current scope, but prior to the current field.
+ * - or in a parent scope (or parent of parent ...) still in a field
+ * prior to the current field position within the parents.
+ * - or in a different dynamic scope:
+ * - either in a upper dynamic scope (walk down a targeted scope from
+ * the dynamic scope root)
+ * - or in a lower dynamic scope (failure)
+ * The dynamic scope roots are linked together, so we can access the
+ * parent dynamic scope from the child dynamic scope by walking up to
+ * the parent.
+ * If we cannot find such a field that is prior to our current path, we
+ * return NULL.
+ *
+ * cur_path: the path leading to the variant definition.
+ * lookup_path: the path leading to the enum we want to look for.
+ * scope: the definition scope containing the variant definition.
+ */
+struct definition *
+ lookup_path_definition(GArray *cur_path,
+ GArray *lookup_path,
+ struct definition_scope *scope)
+{
+ struct definition *definition, *lookup_definition;
+ GQuark last;
+ int index;
+
+ /* Going up in the hierarchy. Check where we come from. */
+ assert(is_path_child_of(cur_path, scope->scope_path));
+ assert(cur_path->len - scope->scope_path->len == 1);
+
+ /*
+ * First, check if the target name is size one, present in
+ * our parent path, located prior to us.
+ */
+ if (lookup_path->len == 1) {
+ last = g_array_index(lookup_path, GQuark, 0);
+ lookup_definition = lookup_field_definition_scope(last, scope);
+ last = g_array_index(cur_path, GQuark, cur_path->len - 1);
+ definition = lookup_field_definition_scope(last, scope);
+ assert(definition);
+ if (lookup_definition && lookup_definition->index < definition->index)
+ return lookup_definition;
+ else
+ return NULL;
+ }
+
+ while (scope) {
+ if (is_path_child_of(cur_path, scope->scope_path) &&
+ cur_path->len - scope->scope_path->len == 1) {
+ last = g_array_index(cur_path, GQuark, cur_path->len - 1);
+ definition = lookup_field_definition_scope(last, scope);
+ assert(definition);
+ index = definition->index;
+ } else {
+ /*
+ * Getting to a dynamic scope parent. We are
+ * guaranteed that the parent is entirely
+ * located before the child.
+ */
+ index = -1;
+ }
+lookup:
+ if (is_path_child_of(lookup_path, scope->scope_path)) {
+ /* Means we can lookup the field in this scope */
+ last = g_array_index(lookup_path, GQuark,
+ scope->scope_path->len);
+ lookup_definition = lookup_field_definition_scope(last, scope);
+ if (!lookup_definition || ((index != -1) && lookup_definition->index >= index))
+ return NULL;
+ /* Found it! And it is prior to the current field. */
+ if (lookup_path->len - scope->scope_path->len == 1) {
+ /* Direct child */
+ return lookup_definition;
+ } else {
+ scope = get_definition_scope(lookup_definition);
+ /* Check if the definition has a sub-scope */
+ if (!scope)
+ return NULL;
+ /*
+ * Don't compare index anymore, because we are
+ * going within a scope that has been validated
+ * to be entirely prior to the current scope.
+ */
+ cur_path = NULL;
+ index = -1;
+ goto lookup;
+ }
+ } else {
+ /* lookup_path is within an upper scope */
+ cur_path = scope->scope_path;
+ scope = scope->parent_scope;
+ }
+ }
+ return NULL;
+}
+
+int register_field_definition(GQuark field_name, struct definition *definition,
+ struct definition_scope *scope)
+{
+ if (!scope || !field_name)
+ return -EPERM;
+
+ /* Only lookup in local scope */
+ if (lookup_field_definition_scope(field_name, scope))
+ return -EEXIST;
+
+ g_hash_table_insert(scope->definitions,
+ (gpointer) (unsigned long) field_name,
+ definition);
+ /* Don't keep reference on definition */
+ return 0;
+}
+
+void declaration_ref(struct declaration *declaration)
+{
+ declaration->ref++;
+}
+
+void declaration_unref(struct declaration *declaration)
+{
+ if (!declaration)
+ return;
+ if (!--declaration->ref)
+ declaration->declaration_free(declaration);
+}
+
+void definition_ref(struct definition *definition)
+{
+ definition->ref++;
+}
+
+void definition_unref(struct definition *definition)
+{
+ if (!definition)
+ return;
+ if (!--definition->ref)
+ definition->declaration->definition_free(definition);
+}
+
+struct declaration_scope *
+ new_declaration_scope(struct declaration_scope *parent_scope)
+{
+ struct declaration_scope *scope = g_new(struct declaration_scope, 1);
+
+ scope->typedef_declarations = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL,
+ (GDestroyNotify) declaration_unref);
+ scope->struct_declarations = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL,
+ (GDestroyNotify) declaration_unref);
+ scope->variant_declarations = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL,
+ (GDestroyNotify) declaration_unref);
+ scope->enum_declarations = g_hash_table_new_full(g_direct_hash,
+ g_direct_equal, NULL,
+ (GDestroyNotify) declaration_unref);
+ scope->parent_scope = parent_scope;
+ return scope;
+}