regex: iterating over the initial states
[oweals/gnunet.git] / src / regex / regex.c
index a1619ef28bd9ca8bff8ec29eacbf7343b1e25c65..77c90418c655f94136dd736a8c4851cefe8e2cb2 100644 (file)
@@ -32,7 +32,7 @@
 /**
  * Constant for how many bits the initial string regex should have.
  */
-#define INITIAL_BITS 10
+#define INITIAL_BITS 8
 
 
 /**
@@ -287,7 +287,8 @@ state_compare (const void *a, const void *b)
  * Get all edges leaving state 's'.
  *
  * @param s state.
- * @param edges all edges leaving 's'.
+ * @param edges all edges leaving 's', expected to be allocated and have enough
+ *        space for s->transitions_count elements.
  *
  * @return number of edges.
  */
@@ -1815,8 +1816,10 @@ nfa_add_concatenation (struct GNUNET_REGEX_Context *ctx)
   struct GNUNET_REGEX_Automaton *new;
 
   b = ctx->stack_tail;
+  GNUNET_assert (NULL != b);
   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, b);
   a = ctx->stack_tail;
+  GNUNET_assert (NULL != a);
   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a);
 
   state_add_transition (ctx, a->end, 0, b->start);
@@ -1952,8 +1955,10 @@ nfa_add_alternation (struct GNUNET_REGEX_Context *ctx)
   struct GNUNET_REGEX_State *end;
 
   b = ctx->stack_tail;
+  GNUNET_assert (NULL != b);
   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, b);
   a = ctx->stack_tail;
+  GNUNET_assert (NULL != a);
   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a);
 
   start = nfa_state_create (ctx, 0);
@@ -2390,7 +2395,6 @@ evaluate_nfa (struct GNUNET_REGEX_Automaton *a, const char *string)
     return 0;
 
   result = 1;
-  strp = string;
   sset = nfa_closure_create (a, a->start, 0);
 
   for (strp = string; NULL != strp && *strp; strp++)
@@ -2471,7 +2475,7 @@ GNUNET_REGEX_get_canonical_regex (struct GNUNET_REGEX_Automaton *a)
 
 /**
  * Get the first key for the given 'input_string'. This hashes the first x bits
- * of the 'input_strings'.
+ * of the 'input_string'.
  *
  * @param input_string string.
  * @param string_len length of the 'input_string'.
@@ -2480,9 +2484,9 @@ GNUNET_REGEX_get_canonical_regex (struct GNUNET_REGEX_Automaton *a)
  * @return number of bits of 'input_string' that have been consumed
  *         to construct the key
  */
-unsigned int
-GNUNET_REGEX_get_first_key (const char *input_string, unsigned int string_len,
-                            struct GNUNET_HashCode *key)
+size_t
+GNUNET_REGEX_get_first_key (const char *input_string, size_t string_len,
+                            struct GNUNET_HashCode * key)
 {
   unsigned int size;
 
@@ -2503,15 +2507,96 @@ GNUNET_REGEX_get_first_key (const char *input_string, unsigned int string_len,
 /**
  * Check if the given 'proof' matches the given 'key'.
  *
- * @param proof partial regex
- * @param key hash
+ * @param proof partial regex of a state.
+ * @param key hash of a state.
  *
- * @return GNUNET_OK if the proof is valid for the given key
+ * @return GNUNET_OK if the proof is valid for the given key.
  */
 int
 GNUNET_REGEX_check_proof (const char *proof, const struct GNUNET_HashCode *key)
 {
-  return GNUNET_OK;
+  struct GNUNET_HashCode key_check;
+
+  GNUNET_CRYPTO_hash (proof, strlen (proof), &key_check);
+  return (0 ==
+          GNUNET_CRYPTO_hash_cmp (key, &key_check)) ? GNUNET_OK : GNUNET_NO;
+}
+
+/**
+ * Recursive helper function for iterate_initial_edges. Will call iterator
+ * function for each initial state.
+ *
+ * @param max_len maximum length of the path in the graph.
+ * @param cur_len current length of the path already traversed.
+ * @param consumed_string string consumed by traversing the graph till this state.
+ * @param next_state next state in the graph that is reachable with 'label' transition.
+ * @param label label of the transition to the next state.
+ * @param iterator iterator function called for each edge.
+ * @param iterator_cls closure for the iterator function.
+ */
+static void
+iterate_initial_edge (const unsigned int max_len, unsigned int cur_len,
+                      char *consumed_string,
+                      struct GNUNET_REGEX_State *next_state, const char label,
+                      GNUNET_REGEX_KeyIterator iterator, void *iterator_cls)
+{
+  char *temp;
+  struct GNUNET_REGEX_Transition *t;
+  struct GNUNET_REGEX_Edge edge;
+  struct GNUNET_HashCode hash;
+  size_t constr_len;
+
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "max_len: %u, cur_len: %u, consumed_string: %s\n", max_len,
+              cur_len, consumed_string);
+
+  if (max_len == cur_len)
+  {
+    constr_len = strlen (consumed_string);
+    GNUNET_CRYPTO_hash (consumed_string, constr_len - 1, &hash);
+    GNUNET_asprintf (&temp, "%c", label);
+    edge.label = temp;
+    edge.destination = next_state->hash;
+    consumed_string[constr_len - 1] = '\0';
+    iterator (iterator_cls, &hash, consumed_string, 0, 1, &edge);
+    GNUNET_free (temp);
+
+    return;
+  }
+  else if (cur_len <= max_len)
+  {
+    cur_len++;
+    for (t = next_state->transitions_head; NULL != t; t = t->next)
+    {
+      if (NULL != consumed_string)
+        GNUNET_asprintf (&temp, "%s%c", consumed_string, t->label);
+      else
+        GNUNET_asprintf (&temp, "%c", t->label);
+
+      iterate_initial_edge (max_len, cur_len, temp, t->to_state, t->label,
+                            iterator, iterator_cls);
+      GNUNET_free (temp);
+    }
+  }
+}
+
+/**
+ * Iterate over all initial edges that aren't actually part of the automaton.
+ * This is needed to find the initial states returned by
+ * GNUNET_REGEX_get_first_key.
+ *
+ * @param a the automaton for which the initial states should be computed.
+ * @param initial_len length of the initial state string.
+ * @param iterator iterator function called for each edge.
+ * @param iterator_cls closure for the iterator function.
+ */
+void
+iterate_initial_edges (struct GNUNET_REGEX_Automaton *a,
+                       const unsigned int initial_len,
+                       GNUNET_REGEX_KeyIterator iterator, void *iterator_cls)
+{
+  iterate_initial_edge (initial_len + 1, 0, NULL, a->start, 0, iterator,
+                        iterator_cls);
 }
 
 
@@ -2563,5 +2648,6 @@ GNUNET_REGEX_iterate_all_edges (struct GNUNET_REGEX_Automaton *a,
   for (s = a->states_head; NULL != s; s = s->next)
     s->marked = GNUNET_NO;
 
+  iterate_initial_edges (a, INITIAL_BITS, iterator, iterator_cls);
   iterate_edge (a->start, iterator, iterator_cls);
 }