7aebd21914d80e1cf7a64c001bdb1fb36e788e2a
[oweals/gnunet.git] / src / regex / regex.c
1 /*
2      This file is part of GNUnet
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file src/regex/regex.c
22  * @brief library to create automatons from regular expressions
23  * @author Maximilian Szengel
24  */
25 #include "platform.h"
26 #include "gnunet_container_lib.h"
27 #include "gnunet_crypto_lib.h"
28 #include "gnunet_regex_lib.h"
29 #include "regex.h"
30
31 #define initial_bits 10
32
33 /**
34  * Context that contains an id counter for states and transitions
35  * as well as a DLL of automatons used as a stack for NFA construction.
36  */
37 struct GNUNET_REGEX_Context
38 {
39   /**
40    * Unique state id.
41    */
42   unsigned int state_id;
43
44   /**
45    * Unique transition id.
46    */
47   unsigned int transition_id;
48
49   /**
50    * Unique SCC (Strongly Connected Component) id.
51    */
52   unsigned int scc_id;
53
54   /**
55    * DLL of GNUNET_REGEX_Automaton's used as a stack.
56    */
57   struct GNUNET_REGEX_Automaton *stack_head;
58
59   /**
60    * DLL of GNUNET_REGEX_Automaton's used as a stack.
61    */
62   struct GNUNET_REGEX_Automaton *stack_tail;
63 };
64
65 /**
66  * Type of an automaton.
67  */
68 enum GNUNET_REGEX_automaton_type
69 {
70   NFA,
71   DFA
72 };
73
74 /**
75  * Automaton representation.
76  */
77 struct GNUNET_REGEX_Automaton
78 {
79   /**
80    * This is a linked list.
81    */
82   struct GNUNET_REGEX_Automaton *prev;
83
84   /**
85    * This is a linked list.
86    */
87   struct GNUNET_REGEX_Automaton *next;
88
89   /**
90    * First state of the automaton. This is mainly
91    * used for constructing an NFA, where each NFA
92    * itself consists of one or more NFAs linked
93    * together.
94    */
95   struct GNUNET_REGEX_State *start;
96
97   /**
98    * End state of the automaton.
99    */
100   struct GNUNET_REGEX_State *end;
101
102   /**
103    * Number of states in the automaton.
104    */
105   unsigned int state_count;
106
107   /**
108    * DLL of states.
109    */
110   struct GNUNET_REGEX_State *states_head;
111
112   /**
113    * DLL of states
114    */
115   struct GNUNET_REGEX_State *states_tail;
116
117   /**
118    * Type of the automaton.
119    */
120   enum GNUNET_REGEX_automaton_type type;
121 };
122
123 /**
124  * A state. Can be used in DFA and NFA automatons.
125  */
126 struct GNUNET_REGEX_State
127 {
128   /**
129    * This is a linked list.
130    */
131   struct GNUNET_REGEX_State *prev;
132
133   /**
134    * This is a linked list.
135    */
136   struct GNUNET_REGEX_State *next;
137
138   /**
139    * Unique state id.
140    */
141   unsigned int id;
142
143   /**
144    * If this is an accepting state or not.
145    */
146   int accepting;
147
148   /**
149    * Marking of the state. This is used for marking all visited
150    * states when traversing all states of an automaton and for
151    * cases where the state id cannot be used (dfa minimization).
152    */
153   int marked;
154
155   /**
156    * Marking the state as contained. This is used for checking,
157    * if the state is contained in a set in constant time
158    */
159   int contained;
160
161   /**
162    * Marking the state as part of an SCC (Strongly Connected Component).
163    * All states with the same scc_id are part of the same SCC.
164    */
165   unsigned int scc_id;
166
167   /**
168    * Used for SCC detection.
169    */
170   int index;
171
172   /**
173    * Used for SCC detection.
174    */
175   int lowlink;
176
177   /**
178    * Human readable name of the automaton. Used for debugging
179    * and graph creation.
180    */
181   char *name;
182
183   GNUNET_HashCode hash;
184
185   /**
186    * Number of transitions from this state to other states.
187    */
188   unsigned int transition_count;
189
190   /**
191    * DLL of transitions.
192    */
193   struct Transition *transitions_head;
194
195   /**
196    * DLL of transitions.
197    */
198   struct Transition *transitions_tail;
199
200   /**
201    * Set of states on which this state is based on. Used when
202    * creating a DFA out of several NFA states.
203    */
204   struct GNUNET_REGEX_StateSet *nfa_set;
205 };
206
207 /**
208  * Transition between two states. Each state can have 0-n transitions.
209  * If label is 0, this is considered to be an epsilon transition.
210  */
211 struct Transition
212 {
213   /**
214    * This is a linked list.
215    */
216   struct Transition *prev;
217
218   /**
219    * This is a linked list.
220    */
221   struct Transition *next;
222
223   /**
224    * Unique id of this transition.
225    */
226   unsigned int id;
227
228   /**
229    * label for this transition. This is basically the edge label for
230    * the graph.
231    */
232   char label;
233
234   /**
235    * State to which this transition leads.
236    */
237   struct GNUNET_REGEX_State *to_state;
238
239   /**
240    * State from which this transition origins.
241    */
242   struct GNUNET_REGEX_State *from_state;
243 };
244
245 /**
246  * Set of states.
247  */
248 struct GNUNET_REGEX_StateSet
249 {
250   /**
251    * Array of states.
252    */
253   struct GNUNET_REGEX_State **states;
254
255   /**
256    * Length of the 'states' array.
257    */
258   unsigned int len;
259 };
260
261 static void
262 debug_print_state (struct GNUNET_REGEX_State *s)
263 {
264   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265               "State %i: %s marked: %i accepting: %i scc_id: %i transitions: %i\n", s->id,
266               s->name, s->marked, s->accepting, s->scc_id, s->transition_count);
267 }
268
269 static void
270 debug_print_states (struct GNUNET_REGEX_StateSet *sset)
271 {
272   struct GNUNET_REGEX_State *s;
273   int i;
274
275   for (i = 0; i < sset->len; i++)
276   {
277     s = sset->states[i];
278     debug_print_state (s);
279   }
280 }
281
282 static void
283 debug_print_transitions (struct GNUNET_REGEX_State *s)
284 {
285   struct Transition *t;
286   char *state;
287   char label;
288
289   for (t = s->transitions_head; NULL != t; t = t->next)
290   {
291     if (0 == t->label)
292       label = '0';
293     else
294       label = t->label;
295
296     if (NULL == t->to_state)
297       state = "NULL";
298     else
299       state = t->to_state->name;
300
301     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transition %i: On %c to %s\n", t->id,
302                 label, state);
303   }
304 }
305
306 /**
307  * Recursive function doing DFS with 'v' as a start, detecting all SCCs
308  * inside the subgraph reachable from 'v'. Used with scc_tarjan function
309  * to detect all SCCs inside an automaton.
310  *
311  * @param ctx context
312  * @param v start vertex
313  * @param index current index
314  * @param stack stack for saving all SCCs
315  * @param stack_size current size of the stack
316  */
317 static void
318 scc_tarjan_strongconnect (struct GNUNET_REGEX_Context *ctx,
319                           struct GNUNET_REGEX_State *v, int *index,
320                           struct GNUNET_REGEX_State **stack,
321                           unsigned int *stack_size)
322 {
323   struct GNUNET_REGEX_State *w;
324   struct Transition *t;
325
326   v->index = *index;
327   v->lowlink = *index;
328   (*index)++;
329   stack[(*stack_size)++] = v;
330   v->contained = 1;
331
332   for (t = v->transitions_head; NULL != t; t = t->next)
333   {
334     w = t->to_state;
335     if (NULL != w && w->index < 0)
336     {
337       scc_tarjan_strongconnect (ctx, w, index, stack, stack_size);
338       v->lowlink = (v->lowlink > w->lowlink) ? w->lowlink : v->lowlink;
339     }
340     else if (0 != w->contained)
341       v->lowlink = (v->lowlink > w->index) ? w->index : v->lowlink;
342   }
343
344   if (v->lowlink == v->index)
345   {
346     w = stack[--(*stack_size)];
347     w->contained = 0;
348
349     if (v != w)
350     {
351       ctx->scc_id++;
352       while (v != w)
353       {
354         w->scc_id = ctx->scc_id;
355         w = stack[--(*stack_size)];
356         w->contained = 0;
357       }
358       w->scc_id = ctx->scc_id;
359     }
360   }
361 }
362
363 /**
364  * Detect all SCCs (Strongly Connected Components) inside the given automaton.
365  * SCCs will be marked using the scc_id on each state.
366  *
367  * @param ctx context
368  * @param a automaton
369  */
370 static void
371 scc_tarjan (struct GNUNET_REGEX_Context *ctx, struct GNUNET_REGEX_Automaton *a)
372 {
373   unsigned int i;
374   int index;
375   struct GNUNET_REGEX_State *v;
376   struct GNUNET_REGEX_State *stack[a->state_count];
377   unsigned int stack_size;
378
379   for (v = a->states_head; NULL != v; v = v->next)
380   {
381     v->contained = 0;
382     v->index = -1;
383     v->lowlink = -1;
384   }
385
386   stack_size = 0;
387   index = 0;
388
389   for (i = 0, v = a->states_head; NULL != v; v = v->next)
390   {
391     if (v->index < 0)
392       scc_tarjan_strongconnect (ctx, v, &index, stack, &stack_size);
393   }
394 }
395
396 /**
397  * Compare two states. Used for sorting.
398  *
399  * @param a first state
400  * @param b second state
401  *
402  * @return an integer less than, equal to, or greater than zero
403  *         if the first argument is considered to be respectively
404  *         less than, equal to, or greater than the second.
405  */
406 static int
407 state_compare (const void *a, const void *b)
408 {
409   struct GNUNET_REGEX_State **s1;
410   struct GNUNET_REGEX_State **s2;
411
412   s1 = (struct GNUNET_REGEX_State **) a;
413   s2 = (struct GNUNET_REGEX_State **) b;
414
415   return (*s1)->id - (*s2)->id;
416 }
417
418 /**
419  * Compare to state sets by comparing the id's of the states that are
420  * contained in each set. Both sets are expected to be sorted by id!
421  *
422  * @param sset1 first state set
423  * @param sset2 second state set
424  *
425  * @return an integer less than, equal to, or greater than zero
426  *         if the first argument is considered to be respectively
427  *         less than, equal to, or greater than the second.
428  */
429 static int
430 state_set_compare (struct GNUNET_REGEX_StateSet *sset1,
431                    struct GNUNET_REGEX_StateSet *sset2)
432 {
433   int result;
434   int i;
435
436   if (NULL == sset1 || NULL == sset2)
437     return 1;
438
439   result = sset1->len - sset2->len;
440
441   for (i = 0; i < sset1->len; i++)
442   {
443     if (0 != result)
444       break;
445
446     result = state_compare (&sset1->states[i], &sset2->states[i]);
447   }
448   return result;
449 }
450
451 /**
452  * Clears the given StateSet 'set'
453  *
454  * @param set set to be cleared
455  */
456 static void
457 state_set_clear (struct GNUNET_REGEX_StateSet *set)
458 {
459   if (NULL != set)
460   {
461     if (NULL != set->states)
462       GNUNET_free (set->states);
463     GNUNET_free (set);
464   }
465 }
466
467 /**
468  * Adds a transition from one state to another on 'label'. Does not add
469  * duplicate states.
470  *
471  * @param ctx context
472  * @param from_state starting state for the transition
473  * @param label transition label
474  * @param to_state state to where the transition should point to
475  */
476 static void
477 state_add_transition (struct GNUNET_REGEX_Context *ctx,
478                       struct GNUNET_REGEX_State *from_state, const char label,
479                       struct GNUNET_REGEX_State *to_state)
480 {
481   int is_dup;
482   struct Transition *t;
483
484   if (NULL == from_state)
485   {
486     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not create Transition.\n");
487     return;
488   }
489
490   // Do not add duplicate states
491   is_dup = GNUNET_NO;
492   for (t = from_state->transitions_head; NULL != t; t = t->next)
493   {
494     if (t->to_state == to_state
495         && t->label == label
496         && t->from_state == from_state)
497     {
498       is_dup = GNUNET_YES;
499       break;
500     }
501   }
502
503   if (is_dup)
504     return;
505
506   t = GNUNET_malloc (sizeof (struct Transition));
507
508   t->id = ctx->transition_id++;
509   t->label = label;
510   t->to_state = to_state;
511   t->from_state = from_state;
512
513   from_state->transition_count++;
514
515   GNUNET_CONTAINER_DLL_insert (from_state->transitions_head,
516                                from_state->transitions_tail, t);
517 }
518
519 /**
520  * Clears an automaton fragment. Does not destroy the states inside
521  * the automaton.
522  *
523  * @param a automaton to be cleared
524  */
525 static void
526 automaton_fragment_clear (struct GNUNET_REGEX_Automaton *a)
527 {
528   if (NULL == a)
529     return;
530
531   a->start = NULL;
532   a->end = NULL;
533   a->states_head = NULL;
534   a->states_tail = NULL;
535   a->state_count = 0;
536   GNUNET_free (a);
537 }
538
539 /**
540  * Frees the memory used by State 's'
541  *
542  * @param s state that should be destroyed
543  */
544 static void
545 automaton_destroy_state (struct GNUNET_REGEX_State *s)
546 {
547   struct Transition *t;
548   struct Transition *next_t;
549
550   if (NULL == s)
551     return;
552
553   if (NULL != s->name)
554     GNUNET_free (s->name);
555
556   for (t = s->transitions_head; NULL != t; t = next_t)
557   {
558     next_t = t->next;
559     GNUNET_CONTAINER_DLL_remove (s->transitions_head, s->transitions_tail, t);
560     GNUNET_free (t);
561   }
562
563   state_set_clear (s->nfa_set);
564
565   GNUNET_free (s);
566 }
567
568 /**
569  * Remove a state from the given automaton 'a'. Always use this function
570  * when altering the states of an automaton. Will also remove all transitions
571  * leading to this state, before destroying it.
572  *
573  * @param a automaton
574  * @param s state to remove
575  */
576 static void
577 automaton_remove_state (struct GNUNET_REGEX_Automaton *a,
578                         struct GNUNET_REGEX_State *s)
579 {
580   struct GNUNET_REGEX_State *ss;
581   struct GNUNET_REGEX_State *s_check;
582   struct Transition *t_check;
583
584   if (NULL == a || NULL == s)
585     return;
586
587   // remove state
588   ss = s;
589   GNUNET_CONTAINER_DLL_remove (a->states_head, a->states_tail, s);
590   a->state_count--;
591
592   // remove all transitions leading to this state
593   for (s_check = a->states_head; NULL != s_check; s_check = s_check->next)
594   {
595     for (t_check = s_check->transitions_head; NULL != t_check;
596          t_check = t_check->next)
597     {
598       if (t_check->to_state == ss)
599       {
600         GNUNET_CONTAINER_DLL_remove (s_check->transitions_head,
601                                      s_check->transitions_tail, t_check);
602         s_check->transition_count--;
603       }
604     }
605   }
606
607   automaton_destroy_state (ss);
608 }
609
610 /**
611  * Merge two states into one. Will merge 's1' and 's2' into 's1' and destroy 's2'.
612  *
613  * @param ctx context
614  * @param a automaton
615  * @param s1 first state
616  * @param s2 second state, will be destroyed
617  */
618 static void
619 automaton_merge_states (struct GNUNET_REGEX_Context *ctx,
620                         struct GNUNET_REGEX_Automaton *a,
621                         struct GNUNET_REGEX_State *s1,
622                         struct GNUNET_REGEX_State *s2)
623 {
624   struct GNUNET_REGEX_State *s_check;
625   struct Transition *t_check;
626   char *new_name;
627
628   GNUNET_assert (NULL != ctx && NULL != a && NULL != s1 && NULL != s2);
629
630   // 1. Make all transitions pointing to s2 point to s1
631   for (s_check = a->states_head; NULL != s_check; s_check = s_check->next)
632   {
633     for (t_check = s_check->transitions_head; NULL != t_check;
634          t_check = t_check->next)
635     {
636       if (s2 == t_check->to_state)
637         t_check->to_state = s1;
638     }
639   }
640
641   // 2. Add all transitions from s2 to sX to s1
642   for (t_check = s2->transitions_head; NULL != t_check; t_check = t_check->next)
643   {
644     if (t_check->to_state != s1)
645         state_add_transition (ctx, s1, t_check->label, t_check->to_state);
646   }
647
648   // 3. Rename s1 to {s1,s2}
649   new_name = GNUNET_strdup (s1->name);
650   if (NULL != s1->name)
651   {
652     GNUNET_free (s1->name);
653     s1->name = NULL;
654   }
655   GNUNET_asprintf (&s1->name, "{%s,%s}", new_name, s2->name);
656   GNUNET_free (new_name);
657
658   // remove state
659   GNUNET_CONTAINER_DLL_remove (a->states_head, a->states_tail, s2);
660   a->state_count--;
661   automaton_destroy_state (s2);
662 }
663
664 /**
665  * Add a state to the automaton 'a', always use this function to
666  * alter the states DLL of the automaton.
667  *
668  * @param a automaton to add the state to
669  * @param s state that should be added
670  */
671 static void
672 automaton_add_state (struct GNUNET_REGEX_Automaton *a,
673                      struct GNUNET_REGEX_State *s)
674 {
675   GNUNET_CONTAINER_DLL_insert (a->states_head, a->states_tail, s);
676   a->state_count++;
677 }
678
679 typedef void (*GNUNET_REGEX_traverse_action) (void *cls,
680                                               struct GNUNET_REGEX_State * s);
681
682 /**
683  * Traverses all states that are reachable from state 's'. Expects
684  * the states to be unmarked (s->marked == GNUNET_NO). Performs
685  * 'action' on each visited state.
686  *
687  * @param cls closure.
688  * @param s start state.
689  * @param action action to be performed on each state.
690  */
691 static void
692 automaton_state_traverse (void *cls, struct GNUNET_REGEX_State *s,
693                           GNUNET_REGEX_traverse_action action)
694 {
695   struct Transition *t;
696
697   if (GNUNET_NO == s->marked)
698   {
699     s->marked = GNUNET_YES;
700
701     if (NULL != action)
702       action (cls, s);
703
704     for (t = s->transitions_head; NULL != t; t = t->next)
705       automaton_state_traverse (cls, t->to_state, action);
706   }
707 }
708
709 /**
710  * Traverses the given automaton from it's start state, visiting all
711  * reachable states and calling 'action' on each one of them.
712  *
713  * @param cls closure.
714  * @param a automaton.
715  * @param action action to be performed on each state.
716  */
717 static void
718 automaton_traverse (void *cls, struct GNUNET_REGEX_Automaton *a,
719                     GNUNET_REGEX_traverse_action action)
720 {
721   struct GNUNET_REGEX_State *s;
722
723   for (s = a->start; NULL != s; s = s->next)
724     s->marked = GNUNET_NO;
725
726   automaton_state_traverse (cls, a->start, action);
727 }
728
729 /**
730  * Creates a new DFA state based on a set of NFA states. Needs to be freed
731  * using automaton_destroy_state.
732  *
733  * @param ctx context
734  * @param nfa_states set of NFA states on which the DFA should be based on
735  *
736  * @return new DFA state
737  */
738 static struct GNUNET_REGEX_State *
739 dfa_state_create (struct GNUNET_REGEX_Context *ctx,
740                   struct GNUNET_REGEX_StateSet *nfa_states)
741 {
742   struct GNUNET_REGEX_State *s;
743   char *name;
744   int len = 0;
745   struct GNUNET_REGEX_State *cstate;
746   struct Transition *ctran;
747   int insert = 1;
748   struct Transition *t;
749   int i;
750
751   s = GNUNET_malloc (sizeof (struct GNUNET_REGEX_State));
752   s->id = ctx->state_id++;
753   s->accepting = 0;
754   s->marked = 0;
755   s->name = NULL;
756   s->scc_id = 0;
757   s->index = -1;
758   s->lowlink = -1;
759   s->contained = 0;
760
761   if (NULL == nfa_states)
762   {
763     GNUNET_asprintf (&s->name, "s%i", s->id);
764     return s;
765   }
766
767   s->nfa_set = nfa_states;
768
769   if (nfa_states->len < 1)
770     return s;
771
772   // Create a name based on 'sset'
773   s->name = GNUNET_malloc (sizeof (char) * 2);
774   strcat (s->name, "{");
775   name = NULL;
776
777   for (i = 0; i < nfa_states->len; i++)
778   {
779     cstate = nfa_states->states[i];
780     GNUNET_asprintf (&name, "%i,", cstate->id);
781
782     if (NULL != name)
783     {
784       len = strlen (s->name) + strlen (name) + 1;
785       s->name = GNUNET_realloc (s->name, len);
786       strcat (s->name, name);
787       GNUNET_free (name);
788       name = NULL;
789     }
790
791     // Add a transition for each distinct label to NULL state
792     for (ctran = cstate->transitions_head; NULL != ctran; ctran = ctran->next)
793     {
794       if (0 != ctran->label)
795       {
796         insert = 1;
797
798         for (t = s->transitions_head; NULL != t; t = t->next)
799         {
800           if (t->label == ctran->label)
801           {
802             insert = 0;
803             break;
804           }
805         }
806
807         if (insert)
808           state_add_transition (ctx, s, ctran->label, NULL);
809       }
810     }
811
812     // If the nfa_states contain an accepting state, the new dfa state is also accepting
813     if (cstate->accepting)
814       s->accepting = 1;
815   }
816
817   s->name[strlen (s->name) - 1] = '}';
818
819   return s;
820 }
821
822 /**
823  * Move from the given state 's' to the next state on
824  * transition 'label'
825  *
826  * @param s starting state
827  * @param label edge label to follow
828  *
829  * @return new state or NULL, if transition on label not possible
830  */
831 static struct GNUNET_REGEX_State *
832 dfa_move (struct GNUNET_REGEX_State *s, const char label)
833 {
834   struct Transition *t;
835   struct GNUNET_REGEX_State *new_s;
836
837   if (NULL == s)
838     return NULL;
839
840   new_s = NULL;
841
842   for (t = s->transitions_head; NULL != t; t = t->next)
843   {
844     if (label == t->label)
845     {
846       new_s = t->to_state;
847       break;
848     }
849   }
850
851   return new_s;
852 }
853
854
855 /**
856  * Remove all unreachable states from DFA 'a'. Unreachable states
857  * are those states that are not reachable from the starting state.
858  *
859  * @param a DFA automaton
860  */
861 static void
862 dfa_remove_unreachable_states (struct GNUNET_REGEX_Automaton *a)
863 {
864   struct GNUNET_REGEX_State *s;
865   struct GNUNET_REGEX_State *s_next;
866
867   // 1. unmark all states
868   for (s = a->states_head; NULL != s; s = s->next)
869     s->marked = GNUNET_NO;
870
871   // 2. traverse dfa from start state and mark all visited states
872   automaton_traverse (NULL, a, NULL);
873
874   // 3. delete all states that were not visited
875   for (s = a->states_head; NULL != s; s = s_next)
876   {
877     s_next = s->next;
878     if (GNUNET_NO == s->marked)
879     {
880       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Removed state %s\n", s->name);
881       automaton_remove_state (a, s);
882     }
883   }
884 }
885
886 /**
887  * Remove all dead states from the DFA 'a'. Dead states are those
888  * states that do not transition to any other state but themselfes.
889  *
890  * @param a DFA automaton
891  */
892 static void
893 dfa_remove_dead_states (struct GNUNET_REGEX_Automaton *a)
894 {
895   struct GNUNET_REGEX_State *s;
896   struct Transition *t;
897   int dead;
898
899   GNUNET_assert (DFA == a->type);
900
901   for (s = a->states_head; NULL != s; s = s->next)
902   {
903     if (s->accepting)
904       continue;
905
906     dead = 1;
907     for (t = s->transitions_head; NULL != t; t = t->next)
908     {
909       if (NULL != t->to_state && t->to_state != s)
910       {
911         dead = 0;
912         break;
913       }
914     }
915
916     if (0 == dead)
917       continue;
918
919     // state s is dead, remove it
920     automaton_remove_state (a, s);
921   }
922 }
923
924 /**
925  * Merge all non distinguishable states in the DFA 'a'
926  *
927  * @param ctx context
928  * @param a DFA automaton
929  */
930 static void
931 dfa_merge_nondistinguishable_states (struct GNUNET_REGEX_Context *ctx,
932                                      struct GNUNET_REGEX_Automaton *a)
933 {
934   int i;
935   int table[a->state_count][a->state_count];
936   struct GNUNET_REGEX_State *s1;
937   struct GNUNET_REGEX_State *s2;
938   struct Transition *t1;
939   struct Transition *t2;
940   int change;
941   int common_labels;
942
943   for (i = 0, s1 = a->states_head; 
944        i < a->state_count && NULL != s1;
945        i++, s1 = s1->next)
946   {
947     s1->marked = i;
948   }
949
950   // Mark all pairs of accepting/!accepting states
951   for (s1 = a->states_head; NULL != s1; s1 = s1->next)
952   {
953     for (s2 = a->states_head; NULL != s2 && s1 != s2; s2 = s2->next)
954     {
955       if ((s1->accepting && !s2->accepting) ||
956           (!s1->accepting && s2->accepting))
957       {
958         table[s1->marked][s2->marked] = 1;
959       }
960       else
961         table[s1->marked][s2->marked] = 0;
962     }
963   }
964
965   change = 1;
966   while (0 != change)
967   {
968     change = 0;
969     for (s1 = a->states_head; NULL != s1; s1 = s1->next)
970     {
971       for (s2 = a->states_head; NULL != s2 && s1 != s2; s2 = s2->next)
972       {
973         if (0 != table[s1->marked][s2->marked])
974           continue;
975
976         common_labels = GNUNET_NO;
977         for (t1 = s1->transitions_head; NULL != t1; t1 = t1->next)
978         {
979           for (t2 = s2->transitions_head; NULL != t2; t2 = t2->next)
980           {
981             if (t1->label == t2->label)
982             {
983               common_labels = GNUNET_YES;
984
985               if (0 != table[t1->to_state->marked][t2->to_state->marked] ||
986                   0 != table[t2->to_state->marked][t1->to_state->marked])
987               {
988                 table[s1->marked][s2->marked] = t1->label != 0 ? t1->label : 1;
989                 change = 1;
990               }
991             }
992           }
993         }
994         if (GNUNET_NO == common_labels)
995           table[s1->marked][s2->marked] = -2;
996       }
997     }
998   }
999
1000   struct GNUNET_REGEX_State *s2_next;
1001
1002   for (s1 = a->states_head; NULL != s1; s1 = s1->next)
1003   {
1004     for (s2 = a->states_head; NULL != s2 && s1 != s2; s2 = s2_next)
1005     {
1006       s2_next = s2->next;
1007       if (table[s1->marked][s2->marked] == 0)
1008         automaton_merge_states (ctx, a, s1, s2);
1009     }
1010   }
1011 }
1012
1013 /**
1014  * Minimize the given DFA 'a' by removing all unreachable states,
1015  * removing all dead states and merging all non distinguishable states
1016  *
1017  * @param ctx context
1018  * @param a DFA automaton
1019  */
1020 static void
1021 dfa_minimize (struct GNUNET_REGEX_Context *ctx,
1022               struct GNUNET_REGEX_Automaton *a)
1023 {
1024   if (NULL == a)
1025     return;
1026
1027   GNUNET_assert (DFA == a->type);
1028
1029   // 1. remove unreachable states
1030   dfa_remove_unreachable_states (a);
1031
1032   // 2. remove dead states
1033   dfa_remove_dead_states (a);
1034
1035   // 3. Merge nondistinguishable states
1036   dfa_merge_nondistinguishable_states (ctx, a);
1037 }
1038
1039 /**
1040  * Creates a new NFA fragment. Needs to be cleared using automaton_fragment_clear.
1041  *
1042  * @param start starting state
1043  * @param end end state
1044  *
1045  * @return new NFA fragment
1046  */
1047 static struct GNUNET_REGEX_Automaton *
1048 nfa_fragment_create (struct GNUNET_REGEX_State *start,
1049                      struct GNUNET_REGEX_State *end)
1050 {
1051   struct GNUNET_REGEX_Automaton *n;
1052
1053   n = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Automaton));
1054
1055   n->type = NFA;
1056   n->start = NULL;
1057   n->end = NULL;
1058
1059   if (NULL == start && NULL == end)
1060     return n;
1061
1062   automaton_add_state (n, end);
1063   automaton_add_state (n, start);
1064
1065   n->start = start;
1066   n->end = end;
1067
1068   return n;
1069 }
1070
1071 /**
1072  * Adds a list of states to the given automaton 'n'.
1073  *
1074  * @param n automaton to which the states should be added
1075  * @param states_head head of the DLL of states
1076  * @param states_tail tail of the DLL of states
1077  */
1078 static void
1079 nfa_add_states (struct GNUNET_REGEX_Automaton *n,
1080                 struct GNUNET_REGEX_State *states_head,
1081                 struct GNUNET_REGEX_State *states_tail)
1082 {
1083   struct GNUNET_REGEX_State *s;
1084
1085   if (NULL == n || NULL == states_head)
1086   {
1087     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not add states\n");
1088     return;
1089   }
1090
1091   if (NULL == n->states_head)
1092   {
1093     n->states_head = states_head;
1094     n->states_tail = states_tail;
1095     return;
1096   }
1097
1098   if (NULL != states_head)
1099   {
1100     n->states_tail->next = states_head;
1101     n->states_tail = states_tail;
1102   }
1103
1104   for (s = states_head; NULL != s; s = s->next)
1105     n->state_count++;
1106 }
1107
1108 /**
1109  * Creates a new NFA state. Needs to be freed using automaton_destroy_state.
1110  *
1111  * @param ctx context
1112  * @param accepting is it an accepting state or not
1113  *
1114  * @return new NFA state
1115  */
1116 static struct GNUNET_REGEX_State *
1117 nfa_state_create (struct GNUNET_REGEX_Context *ctx, int accepting)
1118 {
1119   struct GNUNET_REGEX_State *s;
1120
1121   s = GNUNET_malloc (sizeof (struct GNUNET_REGEX_State));
1122   s->id = ctx->state_id++;
1123   s->accepting = accepting;
1124   s->marked = 0;
1125   s->contained = 0;
1126   s->index = -1;
1127   s->lowlink = -1;
1128   s->scc_id = 0;
1129   s->name = NULL;
1130   GNUNET_asprintf (&s->name, "s%i", s->id);
1131
1132   return s;
1133 }
1134
1135 /**
1136  * Calculates the NFA closure set for the given state.
1137  *
1138  * @param nfa the NFA containing 's'
1139  * @param s starting point state
1140  * @param label transitioning label on which to base the closure on,
1141  *                pass 0 for epsilon transition
1142  *
1143  * @return sorted nfa closure on 'label' (epsilon closure if 'label' is 0)
1144  */
1145 static struct GNUNET_REGEX_StateSet *
1146 nfa_closure_create (struct GNUNET_REGEX_Automaton *nfa,
1147                     struct GNUNET_REGEX_State *s, const char label)
1148 {
1149   struct GNUNET_REGEX_StateSet *cls;
1150   struct GNUNET_REGEX_StateSet *cls_check;
1151   struct GNUNET_REGEX_State *clsstate;
1152   struct GNUNET_REGEX_State *currentstate;
1153   struct Transition *ctran;
1154
1155   if (NULL == s)
1156     return NULL;
1157
1158   cls = GNUNET_malloc (sizeof (struct GNUNET_REGEX_StateSet));
1159   cls_check = GNUNET_malloc (sizeof (struct GNUNET_REGEX_StateSet));
1160
1161   for (clsstate = nfa->states_head; NULL != clsstate; clsstate = clsstate->next)
1162     clsstate->contained = 0;
1163
1164   // Add start state to closure only for epsilon closure
1165   if (0 == label)
1166     GNUNET_array_append (cls->states, cls->len, s);
1167
1168   GNUNET_array_append (cls_check->states, cls_check->len, s);
1169   while (cls_check->len > 0)
1170   {
1171     currentstate = cls_check->states[cls_check->len - 1];
1172     GNUNET_array_grow (cls_check->states, cls_check->len, cls_check->len - 1);
1173
1174     for (ctran = currentstate->transitions_head; NULL != ctran;
1175          ctran = ctran->next)
1176     {
1177       if (NULL != ctran->to_state && label == ctran->label)
1178       {
1179         clsstate = ctran->to_state;
1180
1181         if (NULL != clsstate && 0 == clsstate->contained)
1182         {
1183           GNUNET_array_append (cls->states, cls->len, clsstate);
1184           GNUNET_array_append (cls_check->states, cls_check->len, clsstate);
1185           clsstate->contained = 1;
1186         }
1187       }
1188     }
1189   }
1190   GNUNET_assert (0 == cls_check->len);
1191   GNUNET_free (cls_check);
1192
1193   if (cls->len > 1)
1194     qsort (cls->states, cls->len, sizeof (struct GNUNET_REGEX_State *),
1195            state_compare);
1196
1197   return cls;
1198 }
1199
1200 /**
1201  * Calculates the closure set for the given set of states.
1202  *
1203  * @param nfa the NFA containing 's'
1204  * @param states list of states on which to base the closure on
1205  * @param label transitioning label for which to base the closure on,
1206  *                pass 0 for epsilon transition
1207  *
1208  * @return sorted nfa closure on 'label' (epsilon closure if 'label' is 0)
1209  */
1210 static struct GNUNET_REGEX_StateSet *
1211 nfa_closure_set_create (struct GNUNET_REGEX_Automaton *nfa,
1212                         struct GNUNET_REGEX_StateSet *states, const char label)
1213 {
1214   struct GNUNET_REGEX_State *s;
1215   struct GNUNET_REGEX_StateSet *sset;
1216   struct GNUNET_REGEX_StateSet *cls;
1217   int i;
1218   int j;
1219   int k;
1220   int contains;
1221
1222   if (NULL == states)
1223     return NULL;
1224
1225   cls = GNUNET_malloc (sizeof (struct GNUNET_REGEX_StateSet));
1226
1227   for (i = 0; i < states->len; i++)
1228   {
1229     s = states->states[i];
1230     sset = nfa_closure_create (nfa, s, label);
1231
1232     for (j = 0; j < sset->len; j++)
1233     {
1234       contains = 0;
1235       for (k = 0; k < cls->len; k++)
1236       {
1237         if (sset->states[j]->id == cls->states[k]->id)
1238         {
1239           contains = 1;
1240           break;
1241         }
1242       }
1243       if (!contains)
1244         GNUNET_array_append (cls->states, cls->len, sset->states[j]);
1245     }
1246     state_set_clear (sset);
1247   }
1248
1249   if (cls->len > 1)
1250     qsort (cls->states, cls->len, sizeof (struct GNUNET_REGEX_State *),
1251            state_compare);
1252
1253   return cls;
1254 }
1255
1256 /**
1257  * Pops two NFA fragments (a, b) from the stack and concatenates them (ab)
1258  *
1259  * @param ctx context
1260  */
1261 static void
1262 nfa_add_concatenation (struct GNUNET_REGEX_Context *ctx)
1263 {
1264   struct GNUNET_REGEX_Automaton *a;
1265   struct GNUNET_REGEX_Automaton *b;
1266   struct GNUNET_REGEX_Automaton *new;
1267
1268   b = ctx->stack_tail;
1269   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, b);
1270   a = ctx->stack_tail;
1271   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a);
1272
1273   state_add_transition (ctx, a->end, 0, b->start);
1274   a->end->accepting = 0;
1275   b->end->accepting = 1;
1276
1277   new = nfa_fragment_create (NULL, NULL);
1278   nfa_add_states (new, a->states_head, a->states_tail);
1279   nfa_add_states (new, b->states_head, b->states_tail);
1280   new->start = a->start;
1281   new->end = b->end;
1282   automaton_fragment_clear (a);
1283   automaton_fragment_clear (b);
1284
1285   GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new);
1286 }
1287
1288 /**
1289  * Pops a NFA fragment from the stack (a) and adds a new fragment (a*)
1290  *
1291  * @param ctx context
1292  */
1293 static void
1294 nfa_add_star_op (struct GNUNET_REGEX_Context *ctx)
1295 {
1296   struct GNUNET_REGEX_Automaton *a;
1297   struct GNUNET_REGEX_Automaton *new;
1298   struct GNUNET_REGEX_State *start;
1299   struct GNUNET_REGEX_State *end;
1300
1301   a = ctx->stack_tail;
1302   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a);
1303
1304   if (NULL == a)
1305   {
1306     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1307                 "nfa_add_star_op failed, because there was no element on the stack");
1308     return;
1309   }
1310
1311   start = nfa_state_create (ctx, 0);
1312   end = nfa_state_create (ctx, 1);
1313
1314   state_add_transition (ctx, start, 0, a->start);
1315   state_add_transition (ctx, start, 0, end);
1316   state_add_transition (ctx, a->end, 0, a->start);
1317   state_add_transition (ctx, a->end, 0, end);
1318
1319   a->end->accepting = 0;
1320   end->accepting = 1;
1321
1322   new = nfa_fragment_create (start, end);
1323   nfa_add_states (new, a->states_head, a->states_tail);
1324   automaton_fragment_clear (a);
1325
1326   GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new);
1327 }
1328
1329 /**
1330  * Pops an NFA fragment (a) from the stack and adds a new fragment (a+)
1331  *
1332  * @param ctx context
1333  */
1334 static void
1335 nfa_add_plus_op (struct GNUNET_REGEX_Context *ctx)
1336 {
1337   struct GNUNET_REGEX_Automaton *a;
1338
1339   a = ctx->stack_tail;
1340   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a);
1341
1342   state_add_transition (ctx, a->end, 0, a->start);
1343
1344   GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, a);
1345 }
1346
1347 /**
1348  * Pops an NFA fragment (a) from the stack and adds a new fragment (a?)
1349  *
1350  * @param ctx context
1351  */
1352 static void
1353 nfa_add_question_op (struct GNUNET_REGEX_Context *ctx)
1354 {
1355   struct GNUNET_REGEX_Automaton *a;
1356   struct GNUNET_REGEX_Automaton *new;
1357   struct GNUNET_REGEX_State *start;
1358   struct GNUNET_REGEX_State *end;
1359
1360   a = ctx->stack_tail;
1361   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a);
1362
1363   if (NULL == a)
1364   {
1365     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1366                 "nfa_add_question_op failed, because there was no element on the stack");
1367     return;
1368   }
1369
1370   start = nfa_state_create (ctx, 0);
1371   end = nfa_state_create (ctx, 1);
1372
1373   state_add_transition (ctx, start, 0, a->start);
1374   state_add_transition (ctx, start, 0, end);
1375   state_add_transition (ctx, a->end, 0, end);
1376
1377   a->end->accepting = 0;
1378
1379   new = nfa_fragment_create (start, end);
1380   nfa_add_states (new, a->states_head, a->states_tail);
1381   automaton_fragment_clear (a);
1382
1383   GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new);
1384 }
1385
1386 /**
1387  * Pops two NFA fragments (a, b) from the stack and adds a new NFA fragment
1388  * that alternates between a and b (a|b)
1389  *
1390  * @param ctx context
1391  */
1392 static void
1393 nfa_add_alternation (struct GNUNET_REGEX_Context *ctx)
1394 {
1395   struct GNUNET_REGEX_Automaton *a;
1396   struct GNUNET_REGEX_Automaton *b;
1397   struct GNUNET_REGEX_Automaton *new;
1398   struct GNUNET_REGEX_State *start;
1399   struct GNUNET_REGEX_State *end;
1400
1401   b = ctx->stack_tail;
1402   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, b);
1403   a = ctx->stack_tail;
1404   GNUNET_CONTAINER_DLL_remove (ctx->stack_head, ctx->stack_tail, a);
1405
1406   start = nfa_state_create (ctx, 0);
1407   end = nfa_state_create (ctx, 1);
1408   state_add_transition (ctx, start, 0, a->start);
1409   state_add_transition (ctx, start, 0, b->start);
1410
1411   state_add_transition (ctx, a->end, 0, end);
1412   state_add_transition (ctx, b->end, 0, end);
1413
1414   a->end->accepting = 0;
1415   b->end->accepting = 0;
1416   end->accepting = 1;
1417
1418   new = nfa_fragment_create (start, end);
1419   nfa_add_states (new, a->states_head, a->states_tail);
1420   nfa_add_states (new, b->states_head, b->states_tail);
1421   automaton_fragment_clear (a);
1422   automaton_fragment_clear (b);
1423
1424   GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, new);
1425 }
1426
1427 /**
1428  * Adds a new nfa fragment to the stack
1429  *
1430  * @param ctx context
1431  * @param lit label for nfa transition
1432  */
1433 static void
1434 nfa_add_label (struct GNUNET_REGEX_Context *ctx, const char lit)
1435 {
1436   struct GNUNET_REGEX_Automaton *n;
1437   struct GNUNET_REGEX_State *start;
1438   struct GNUNET_REGEX_State *end;
1439
1440   GNUNET_assert (NULL != ctx);
1441
1442   start = nfa_state_create (ctx, 0);
1443   end = nfa_state_create (ctx, 1);
1444   state_add_transition (ctx, start, lit, end);
1445   n = nfa_fragment_create (start, end);
1446   GNUNET_assert (NULL != n);
1447   GNUNET_CONTAINER_DLL_insert_tail (ctx->stack_head, ctx->stack_tail, n);
1448 }
1449
1450 /**
1451  * Initialize a new context
1452  *
1453  * @param ctx context
1454  */
1455 static void
1456 GNUNET_REGEX_context_init (struct GNUNET_REGEX_Context *ctx)
1457 {
1458   if (NULL == ctx)
1459   {
1460     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Context was NULL!");
1461     return;
1462   }
1463   ctx->state_id = 0;
1464   ctx->transition_id = 0;
1465   ctx->scc_id = 0;
1466   ctx->stack_head = NULL;
1467   ctx->stack_tail = NULL;
1468 }
1469
1470 /**
1471  * Construct an NFA by parsing the regex string of length 'len'.
1472  *
1473  * @param regex regular expression string
1474  * @param len length of the string
1475  *
1476  * @return NFA, needs to be freed using GNUNET_REGEX_destroy_automaton
1477  */
1478 struct GNUNET_REGEX_Automaton *
1479 GNUNET_REGEX_construct_nfa (const char *regex, const size_t len)
1480 {
1481   struct GNUNET_REGEX_Context ctx;
1482   struct GNUNET_REGEX_Automaton *nfa;
1483   const char *regexp;
1484   char *error_msg;
1485   unsigned int count;
1486   unsigned int altcount;
1487   unsigned int atomcount;
1488   unsigned int pcount;
1489   struct
1490   {
1491     int altcount;
1492     int atomcount;
1493   }     *p;
1494
1495   GNUNET_REGEX_context_init (&ctx);
1496
1497   regexp = regex;
1498   p = NULL;
1499   error_msg = NULL;
1500   altcount = 0;
1501   atomcount = 0;
1502   pcount = 0;
1503
1504   for (count = 0; count < len && *regexp; count++, regexp++)
1505   {
1506     switch (*regexp)
1507     {
1508     case '(':
1509       if (atomcount > 1)
1510       {
1511         --atomcount;
1512         nfa_add_concatenation (&ctx);
1513       }
1514       GNUNET_array_grow (p, pcount, pcount + 1);
1515       p[pcount - 1].altcount = altcount;
1516       p[pcount - 1].atomcount = atomcount;
1517       altcount = 0;
1518       atomcount = 0;
1519       break;
1520     case '|':
1521       if (0 == atomcount)
1522       {
1523         error_msg = "Cannot append '|' to nothing";
1524         goto error;
1525       }
1526       while (--atomcount > 0)
1527         nfa_add_concatenation (&ctx);
1528       altcount++;
1529       break;
1530     case ')':
1531       if (0 == pcount)
1532       {
1533         error_msg = "Missing opening '('";
1534         goto error;
1535       }
1536       if (0 == atomcount)
1537       {
1538         // Ignore this: "()"
1539         pcount--;
1540         altcount = p[pcount].altcount;
1541         atomcount = p[pcount].atomcount;
1542         break;
1543       }
1544       while (--atomcount > 0)
1545         nfa_add_concatenation (&ctx);
1546       for (; altcount > 0; altcount--)
1547         nfa_add_alternation (&ctx);
1548       pcount--;
1549       altcount = p[pcount].altcount;
1550       atomcount = p[pcount].atomcount;
1551       atomcount++;
1552       break;
1553     case '*':
1554       if (atomcount == 0)
1555       {
1556         error_msg = "Cannot append '+' to nothing";
1557         goto error;
1558       }
1559       nfa_add_star_op (&ctx);
1560       break;
1561     case '+':
1562       if (atomcount == 0)
1563       {
1564         error_msg = "Cannot append '+' to nothing";
1565         goto error;
1566       }
1567       nfa_add_plus_op (&ctx);
1568       break;
1569     case '?':
1570       if (atomcount == 0)
1571       {
1572         error_msg = "Cannot append '?' to nothing";
1573         goto error;
1574       }
1575       nfa_add_question_op (&ctx);
1576       break;
1577     case 92:                   /* escape: \ */
1578       regexp++;
1579       count++;
1580     default:
1581       if (atomcount > 1)
1582       {
1583         --atomcount;
1584         nfa_add_concatenation (&ctx);
1585       }
1586       nfa_add_label (&ctx, *regexp);
1587       atomcount++;
1588       break;
1589     }
1590   }
1591   if (0 != pcount)
1592   {
1593     error_msg = "Unbalanced parenthesis";
1594     goto error;
1595   }
1596   while (--atomcount > 0)
1597     nfa_add_concatenation (&ctx);
1598   for (; altcount > 0; altcount--)
1599     nfa_add_alternation (&ctx);
1600
1601   if (NULL != p)
1602     GNUNET_free (p);
1603
1604   nfa = ctx.stack_tail;
1605   GNUNET_CONTAINER_DLL_remove (ctx.stack_head, ctx.stack_tail, nfa);
1606
1607
1608   if (NULL != ctx.stack_head)
1609   {
1610     error_msg = "Creating the NFA failed. NFA stack was not empty!";
1611     goto error;
1612   }
1613
1614   return nfa;
1615
1616 error:
1617   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse regex\n");
1618   if (NULL != error_msg)
1619     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", error_msg);
1620   if (NULL != p)
1621     GNUNET_free (p);
1622   while (NULL != ctx.stack_tail)
1623   {
1624     GNUNET_REGEX_automaton_destroy (ctx.stack_tail);
1625     GNUNET_CONTAINER_DLL_remove (ctx.stack_head, ctx.stack_tail,
1626                                  ctx.stack_tail);
1627   }
1628   return NULL;
1629 }
1630
1631 /**
1632  * Construct DFA for the given 'regex' of length 'len'
1633  *
1634  * @param regex regular expression string
1635  * @param len length of the regular expression
1636  *
1637  * @return DFA, needs to be freed using GNUNET_REGEX_destroy_automaton
1638  */
1639 struct GNUNET_REGEX_Automaton *
1640 GNUNET_REGEX_construct_dfa (const char *regex, const size_t len)
1641 {
1642   struct GNUNET_REGEX_Context ctx;
1643   struct GNUNET_REGEX_Automaton *dfa;
1644   struct GNUNET_REGEX_Automaton *nfa;
1645   struct GNUNET_REGEX_StateSet *tmp;
1646   struct GNUNET_REGEX_StateSet *nfa_set;
1647   struct GNUNET_REGEX_StateSet *dfa_stack;
1648   struct Transition *ctran;
1649   struct GNUNET_REGEX_State *dfa_state;
1650   struct GNUNET_REGEX_State *new_dfa_state;
1651   struct GNUNET_REGEX_State *state_contains;
1652   struct GNUNET_REGEX_State *state_iter;
1653
1654   GNUNET_REGEX_context_init (&ctx);
1655
1656   // Create NFA
1657   nfa = GNUNET_REGEX_construct_nfa (regex, len);
1658
1659   if (NULL == nfa)
1660   {
1661     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1662                 "Could not create DFA, because NFA creation failed\n");
1663     return NULL;
1664   }
1665
1666   dfa = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Automaton));
1667   dfa->type = DFA;
1668
1669   // Create DFA start state from epsilon closure
1670   dfa_stack = GNUNET_malloc (sizeof (struct GNUNET_REGEX_StateSet));
1671   nfa_set = nfa_closure_create (nfa, nfa->start, 0);
1672   dfa->start = dfa_state_create (&ctx, nfa_set);
1673   automaton_add_state (dfa, dfa->start);
1674   GNUNET_array_append (dfa_stack->states, dfa_stack->len, dfa->start);
1675
1676   // Create dfa states by combining nfa states
1677   while (dfa_stack->len > 0)
1678   {
1679     dfa_state = dfa_stack->states[dfa_stack->len - 1];
1680     GNUNET_array_grow (dfa_stack->states, dfa_stack->len, dfa_stack->len - 1);
1681
1682     for (ctran = dfa_state->transitions_head; NULL != ctran;
1683          ctran = ctran->next)
1684     {
1685       if (0 != ctran->label && NULL == ctran->to_state)
1686       {
1687         tmp = nfa_closure_set_create (nfa, dfa_state->nfa_set, ctran->label);
1688         nfa_set = nfa_closure_set_create (nfa, tmp, 0);
1689         state_set_clear (tmp);
1690         new_dfa_state = dfa_state_create (&ctx, nfa_set);
1691         state_contains = NULL;
1692         for (state_iter = dfa->states_head; NULL != state_iter;
1693              state_iter = state_iter->next)
1694         {
1695           if (0 ==
1696               state_set_compare (state_iter->nfa_set, new_dfa_state->nfa_set))
1697             state_contains = state_iter;
1698         }
1699
1700         if (NULL == state_contains)
1701         {
1702           automaton_add_state (dfa, new_dfa_state);
1703           GNUNET_array_append (dfa_stack->states, dfa_stack->len,
1704                                new_dfa_state);
1705           ctran->to_state = new_dfa_state;
1706         }
1707         else
1708         {
1709           ctran->to_state = state_contains;
1710           automaton_destroy_state (new_dfa_state);
1711         }
1712       }
1713     }
1714   }
1715
1716   GNUNET_free (dfa_stack);
1717   GNUNET_REGEX_automaton_destroy (nfa);
1718
1719   dfa_minimize (&ctx, dfa);
1720   scc_tarjan (&ctx, dfa);
1721
1722   return dfa;
1723 }
1724
1725 /**
1726  * Free the memory allocated by constructing the GNUNET_REGEX_Automaton
1727  * data structure.
1728  *
1729  * @param a automaton to be destroyed
1730  */
1731 void
1732 GNUNET_REGEX_automaton_destroy (struct GNUNET_REGEX_Automaton *a)
1733 {
1734   struct GNUNET_REGEX_State *s;
1735   struct GNUNET_REGEX_State *next_state;
1736
1737   if (NULL == a)
1738     return;
1739
1740   for (s = a->states_head; NULL != s;)
1741   {
1742     next_state = s->next;
1743     automaton_destroy_state (s);
1744     s = next_state;
1745   }
1746
1747   GNUNET_free (a);
1748 }
1749
1750 /**
1751  * Save the given automaton as a GraphViz dot file
1752  *
1753  * @param a the automaton to be saved
1754  * @param filename where to save the file
1755  */
1756 void
1757 GNUNET_REGEX_automaton_save_graph (struct GNUNET_REGEX_Automaton *a,
1758                                    const char *filename)
1759 {
1760   struct GNUNET_REGEX_State *s;
1761   struct Transition *ctran;
1762   char *s_acc = NULL;
1763   char *s_tran = NULL;
1764   char *start;
1765   char *end;
1766   FILE *p;
1767
1768   if (NULL == a)
1769   {
1770     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print NFA, was NULL!");
1771     return;
1772   }
1773
1774   if (NULL == filename || strlen (filename) < 1)
1775   {
1776     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No Filename given!");
1777     return;
1778   }
1779
1780   p = fopen (filename, "w");
1781
1782   if (NULL == p)
1783   {
1784     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not open file for writing: %s",
1785                 filename);
1786     return;
1787   }
1788
1789   start = "digraph G {\nrankdir=LR\n";
1790   fwrite (start, strlen (start), 1, p);
1791
1792   for (s = a->states_head; NULL != s; s = s->next)
1793   {
1794     if (s->accepting)
1795     {
1796       GNUNET_asprintf (&s_acc,
1797                        "\"%s\" [shape=doublecircle, color=\"0.%i 0.8 0.95\"];\n",
1798                        s->name, s->scc_id);
1799     }
1800     else
1801     {
1802       GNUNET_asprintf (&s_acc, "\"%s\" [color=\"0.%i 0.8 0.95\"];\n", s->name,
1803                        s->scc_id);
1804     }
1805
1806     if (NULL == s_acc)
1807     {
1808       GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print state %s\n", s->name);
1809       return;
1810     }
1811     fwrite (s_acc, strlen (s_acc), 1, p);
1812     GNUNET_free (s_acc);
1813     s_acc = NULL;
1814
1815     for (ctran = s->transitions_head; NULL != ctran; ctran = ctran->next)
1816     {
1817       if (NULL == ctran->to_state)
1818       {
1819         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1820                     "Transition from State %i has has no state for transitioning\n",
1821                     s->id);
1822         continue;
1823       }
1824
1825       if (ctran->label == 0)
1826       {
1827         GNUNET_asprintf (&s_tran,
1828                          "\"%s\" -> \"%s\" [label = \"epsilon\", color=\"0.%i 0.8 0.95\"];\n",
1829                          s->name, ctran->to_state->name, s->scc_id);
1830       }
1831       else
1832       {
1833         GNUNET_asprintf (&s_tran,
1834                          "\"%s\" -> \"%s\" [label = \"%c\", color=\"0.%i 0.8 0.95\"];\n",
1835                          s->name, ctran->to_state->name, ctran->label,
1836                          s->scc_id);
1837       }
1838
1839       if (NULL == s_tran)
1840       {
1841         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print state %s\n", s->name);
1842         return;
1843       }
1844
1845       fwrite (s_tran, strlen (s_tran), 1, p);
1846       GNUNET_free (s_tran);
1847       s_tran = NULL;
1848     }
1849   }
1850
1851   end = "\n}\n";
1852   fwrite (end, strlen (end), 1, p);
1853   fclose (p);
1854 }
1855
1856 /**
1857  * Evaluates the given string using the given DFA automaton
1858  *
1859  * @param a automaton, type must be DFA
1860  * @param string string that should be evaluated
1861  *
1862  * @return 0 if string matches, non 0 otherwise
1863  */
1864 static int
1865 evaluate_dfa (struct GNUNET_REGEX_Automaton *a, const char *string)
1866 {
1867   const char *strp;
1868   struct GNUNET_REGEX_State *s;
1869
1870   if (DFA != a->type)
1871   {
1872     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1873                 "Tried to evaluate DFA, but NFA automaton given");
1874     return -1;
1875   }
1876
1877   s = a->start;
1878
1879   for (strp = string; NULL != strp && *strp; strp++)
1880   {
1881     s = dfa_move (s, *strp);
1882     if (NULL == s)
1883       break;
1884   }
1885
1886   if (NULL != s && s->accepting)
1887     return 0;
1888
1889   return 1;
1890 }
1891
1892 /**
1893  * Evaluates the given string using the given NFA automaton
1894  *
1895  * @param a automaton, type must be NFA
1896  * @param string string that should be evaluated
1897  *
1898  * @return 0 if string matches, non 0 otherwise
1899  */
1900 static int
1901 evaluate_nfa (struct GNUNET_REGEX_Automaton *a, const char *string)
1902 {
1903   const char *strp;
1904   struct GNUNET_REGEX_State *s;
1905   struct GNUNET_REGEX_StateSet *sset;
1906   struct GNUNET_REGEX_StateSet *new_sset;
1907   int i;
1908   int result;
1909
1910   if (NFA != a->type)
1911   {
1912     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1913                 "Tried to evaluate NFA, but DFA automaton given");
1914     return -1;
1915   }
1916
1917   result = 1;
1918   strp = string;
1919   sset = nfa_closure_create (a, a->start, 0);
1920
1921   for (strp = string; NULL != strp && *strp; strp++)
1922   {
1923     new_sset = nfa_closure_set_create (a, sset, *strp);
1924     state_set_clear (sset);
1925     sset = nfa_closure_set_create (a, new_sset, 0);
1926     state_set_clear (new_sset);
1927   }
1928
1929   for (i = 0; i < sset->len; i++)
1930   {
1931     s = sset->states[i];
1932     if (NULL != s && s->accepting)
1933     {
1934       result = 0;
1935       break;
1936     }
1937   }
1938
1939   state_set_clear (sset);
1940   return result;
1941 }
1942
1943 /**
1944  * Evaluates the given 'string' against the given compiled regex
1945  *
1946  * @param a automaton
1947  * @param string string to check
1948  *
1949  * @return 0 if string matches, non 0 otherwise
1950  */
1951 int
1952 GNUNET_REGEX_eval (struct GNUNET_REGEX_Automaton *a, const char *string)
1953 {
1954   int result;
1955
1956   switch (a->type)
1957   {
1958   case DFA:
1959     result = evaluate_dfa (a, string);
1960     break;
1961   case NFA:
1962     result = evaluate_nfa (a, string);
1963     break;
1964   default:
1965     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1966                 "Evaluating regex failed, automaton has no type!\n");
1967     result = GNUNET_SYSERR;
1968     break;
1969   }
1970
1971   return result;
1972 }
1973
1974 /**
1975  * Get the first key for the given 'input_string'. This hashes
1976  * the first x bits of the 'input_strings'.
1977  *
1978  * @param input_string string.
1979  * @param string_len length of the 'input_string'.
1980  * @param key pointer to where to write the hash code.
1981  *
1982  * @return number of bits of 'input_string' that have been consumed
1983  *         to construct the key
1984  */
1985 unsigned int
1986 GNUNET_REGEX_get_first_key (const char *input_string, unsigned int string_len,
1987                             GNUNET_HashCode * key)
1988 {
1989   unsigned int size;
1990
1991   size = string_len < initial_bits ? string_len : initial_bits;
1992
1993   if (NULL == input_string)
1994   {
1995     GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Given input string was NULL!\n");
1996     return 0;
1997   }
1998
1999   GNUNET_CRYPTO_hash (input_string, size, key);
2000
2001   return size;
2002 }
2003
2004 /**
2005  * Check if the given 'proof' matches the given 'key'.
2006  *
2007  * @param proof partial regex
2008  * @param key hash
2009  *
2010  * @return GNUNET_OK if the proof is valid for the given key
2011  */
2012 int
2013 GNUNET_REGEX_check_proof (const char *proof, const GNUNET_HashCode * key)
2014 {
2015   return GNUNET_OK;
2016 }
2017
2018 /**
2019  * Get all edges leaving state 's'.
2020  *
2021  * @param s state.
2022  * @param edges all edges leaving 's'.
2023  *
2024  * @return number of edges.
2025  */
2026 static unsigned int
2027 state_get_edges (struct GNUNET_REGEX_State *s, struct GNUNET_REGEX_Edge *edges)
2028 {
2029   struct Transition *t;
2030   unsigned int count;
2031
2032   if (NULL == s)
2033     return 0;
2034
2035   count = 0;
2036
2037   for (t = s->transitions_head; NULL != t; t = t->next)
2038   {
2039     if (NULL != t->to_state)
2040     {
2041       edges[count].label = &t->label;
2042       edges[count].destination = t->to_state->hash;
2043       count++;
2044     }
2045   }
2046   return count;
2047 }
2048
2049 /**
2050  * Iterate over all edges helper function starting from state 's', calling
2051  * iterator on for each edge.
2052  *
2053  * @param s state.
2054  * @param iterator iterator function called for each edge.
2055  * @param iterator_cls closure.
2056  */
2057 static void
2058 iterate_edge (struct GNUNET_REGEX_State *s, GNUNET_REGEX_KeyIterator iterator,
2059               void *iterator_cls)
2060 {
2061   struct Transition *t;
2062   struct GNUNET_REGEX_Edge edges[s->transition_count];
2063   unsigned int num_edges;
2064
2065   if (GNUNET_YES != s->marked)
2066   {
2067     s->marked = GNUNET_YES;
2068
2069     num_edges = state_get_edges (s, edges);
2070
2071     iterator (iterator_cls, &s->hash, NULL, s->accepting, num_edges, edges);
2072
2073     for (t = s->transitions_head; NULL != t; t = t->next)
2074       iterate_edge (t->to_state, iterator, iterator_cls);
2075   }
2076 }
2077
2078 /**
2079  * Iterate over all edges starting from start state of automaton 'a'. Calling
2080  * iterator for each edge.
2081  *
2082  * @param a automaton.
2083  * @param iterator iterator called for each edge.
2084  * @param iterator_cls closure.
2085  */
2086 void
2087 GNUNET_REGEX_iterate_all_edges (struct GNUNET_REGEX_Automaton *a,
2088                                 GNUNET_REGEX_KeyIterator iterator,
2089                                 void *iterator_cls)
2090 {
2091   struct GNUNET_REGEX_State *s;
2092
2093   for (s = a->states_head; NULL != s; s = s->next)
2094     s->marked = GNUNET_NO;
2095
2096   iterate_edge (a->start, iterator, iterator_cls);
2097 }