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