2 This file is part of GNUnet
3 (C) 2012 Christian Grothoff (and other contributing authors)
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.
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.
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.
21 * @file src/regex/regex.c
22 * @brief library to create automatons from regular expressions
23 * @author Maximilian Szengel
26 #include "gnunet_container_lib.h"
27 #include "gnunet_regex_lib.h"
31 stack_push (struct GNUNET_CONTAINER_SList *stack, const void *buf, size_t len)
33 GNUNET_CONTAINER_slist_add (stack, GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
38 stack_empty (struct GNUNET_CONTAINER_SList *stack)
40 return 0 == GNUNET_CONTAINER_slist_count (stack);
44 stack_pop (struct GNUNET_CONTAINER_SList *stack, size_t length)
46 struct GNUNET_CONTAINER_SList_Iterator it;
50 it = GNUNET_CONTAINER_slist_begin (stack);
51 val = GNUNET_CONTAINER_slist_get (&it, &len);
52 GNUNET_assert (length == len);
53 GNUNET_CONTAINER_slist_erase (&it);
54 GNUNET_CONTAINER_slist_iter_destroy (&it);
60 stack_top (struct GNUNET_CONTAINER_SList *stack, size_t *len)
62 struct GNUNET_CONTAINER_SList_Iterator it;
64 if (stack_empty (stack))
67 return GNUNET_CONTAINER_slist_get (&it, len);
76 struct GNUNET_CONTAINER_SList *transitions;
77 struct GNUNET_CONTAINER_SList *nfa_set;
80 struct GNUNET_REGEX_Automaton
84 struct GNUNET_CONTAINER_SList *states;
94 struct GNUNET_REGEX_Context
96 unsigned int state_id;
97 unsigned int transition_id;
98 struct GNUNET_CONTAINER_SList *stack;
102 GNUNET_REGEX_context_init (struct GNUNET_REGEX_Context *ctx)
106 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Context was NULL!");
110 ctx->transition_id = 0;
111 ctx->stack = GNUNET_CONTAINER_slist_create();
115 GNUNET_REGEX_context_destroy (struct GNUNET_REGEX_Context *ctx)
117 if (NULL != ctx->stack)
118 GNUNET_CONTAINER_slist_destroy(ctx->stack);
122 debug_print_state (struct State *s)
124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "State %i: %s marked: %i accepting: %i\n",
125 s->id, s->name, s->marked, s->accepting);
129 debug_print_states (struct GNUNET_CONTAINER_SList *states)
131 struct GNUNET_CONTAINER_SList_Iterator it;
134 for (it = GNUNET_CONTAINER_slist_begin (states);
135 GNUNET_YES != GNUNET_CONTAINER_slist_end (&it);
136 GNUNET_CONTAINER_slist_next (&it))
138 s = GNUNET_CONTAINER_slist_get (&it, NULL);
139 debug_print_state (s);
141 GNUNET_CONTAINER_slist_iter_destroy (&it);
145 debug_print_transitions (struct State *s)
147 struct GNUNET_CONTAINER_SList_Iterator it;
148 struct Transition *t;
152 for (it = GNUNET_CONTAINER_slist_begin (s->transitions);
153 GNUNET_YES != GNUNET_CONTAINER_slist_end (&it);
154 GNUNET_CONTAINER_slist_next (&it))
156 t = GNUNET_CONTAINER_slist_get(&it, NULL);
161 literal = t->literal;
163 if (NULL == t->state)
166 state = t->state->name;
168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transition %i: On %c to %s\n", t->id, literal, state);
171 GNUNET_CONTAINER_slist_iter_destroy (&it);
175 set_compare (const void *buf1, const size_t len1, const void *buf2, const size_t len2)
179 struct GNUNET_CONTAINER_SList_Iterator it1;
180 struct GNUNET_CONTAINER_SList_Iterator it2;
183 struct GNUNET_CONTAINER_SList *l1;
184 struct GNUNET_CONTAINER_SList *l2;
193 && len1 != sizeof (struct State)
194 && len2 != sizeof (struct State))
197 s1 = (struct State *)buf1;
198 s2 = (struct State *)buf2;
203 c1 = GNUNET_CONTAINER_slist_count (l1);
204 c2 = GNUNET_CONTAINER_slist_count (l2);
207 return ((c1 > c2) ? 1 : -1);
211 for (it1 = GNUNET_CONTAINER_slist_begin (l1);
212 GNUNET_YES != GNUNET_CONTAINER_slist_end (&it1);
213 GNUNET_CONTAINER_slist_next (&it1))
215 el1 = GNUNET_CONTAINER_slist_get (&it1, &length1);
218 for (it2 = GNUNET_CONTAINER_slist_begin (l2);
219 GNUNET_YES != GNUNET_CONTAINER_slist_end (&it2);
220 GNUNET_CONTAINER_slist_next (&it2))
222 el2 = GNUNET_CONTAINER_slist_get (&it2, &length2);
224 if (length1 != length2)
226 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing lists failed, element size mismatch\n");
229 if (((struct State*)el1)->id == ((struct State*)el2)->id)
235 GNUNET_CONTAINER_slist_iter_destroy (&it2);
243 GNUNET_CONTAINER_slist_iter_destroy (&it1);
249 transition_literal_compare (const void *buf1, const size_t len1, const void *buf2, const size_t len2)
251 struct Transition *t1;
252 struct Transition *t2;
255 && len1 != sizeof (struct Transition)
256 && len2 != sizeof (struct Transition))
261 t1 = (struct Transition *)buf1;
262 t2 = (struct Transition *)buf2;
264 if (t1->literal == t2->literal)
266 else if (t1->literal > t2->literal)
273 add_transition (struct GNUNET_REGEX_Context *ctx, struct State *from_state, const char literal,
274 struct State *to_state)
278 if (NULL == from_state)
280 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not create Transition.\n");
284 t.id = ctx->transition_id++;
288 GNUNET_CONTAINER_slist_add (from_state->transitions,
289 GNUNET_CONTAINER_SLIST_DISPOSITION_TRANSIENT,
294 dfa_create_state (struct GNUNET_REGEX_Context *ctx, struct GNUNET_CONTAINER_SList *states)
298 struct GNUNET_CONTAINER_SList_Iterator stateit;
299 struct GNUNET_CONTAINER_SList_Iterator tranit;
301 struct State *cstate;
302 struct Transition *ctran;
304 s = GNUNET_malloc (sizeof (struct State));
305 s->id = ctx->state_id++;
307 s->transitions = GNUNET_CONTAINER_slist_create();
316 if (0 == GNUNET_CONTAINER_slist_count (states))
320 // Create a name based on 'sset'
321 s->name = GNUNET_malloc (sizeof (char) * 2);
322 strcat (s->name, "{");
325 for (stateit = GNUNET_CONTAINER_slist_begin(states);
326 GNUNET_NO == GNUNET_CONTAINER_slist_end (&stateit);
327 GNUNET_CONTAINER_slist_next (&stateit))
329 cstate = GNUNET_CONTAINER_slist_get (&stateit, NULL);
330 GNUNET_CONTAINER_slist_iter_destroy (&tranit);
331 GNUNET_asprintf (&name, "%i,", cstate->id);
335 len = strlen (s->name) + strlen (name) + 1;
336 s->name = GNUNET_realloc (s->name, len);
337 strcat (s->name, name);
342 // Add a transition for each distinct literal to NULL state
343 for (tranit = GNUNET_CONTAINER_slist_begin(cstate->transitions);
344 GNUNET_NO == GNUNET_CONTAINER_slist_end (&tranit);
345 GNUNET_CONTAINER_slist_next (&tranit))
347 ctran = GNUNET_CONTAINER_slist_get(&tranit, NULL);
348 if (0 != ctran->literal
349 && NULL == GNUNET_CONTAINER_slist_contains2 (s->transitions, ctran, sizeof *ctran, &transition_literal_compare))
351 add_transition (ctx, s, ctran->literal, NULL);
355 if (cstate->accepting)
358 GNUNET_CONTAINER_slist_iter_destroy (&stateit);
360 s->name[strlen (s->name)-1] = '}';
365 struct GNUNET_REGEX_Automaton *
366 nfa_create (struct State *start, struct State *end)
368 struct GNUNET_REGEX_Automaton *n;
370 n = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Automaton));
374 n->states = GNUNET_CONTAINER_slist_create ();
376 if (NULL == start && NULL == end)
379 GNUNET_CONTAINER_slist_add (n->states,
380 GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
384 GNUNET_CONTAINER_slist_add (n->states,
385 GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
396 nfa_add_states (struct GNUNET_REGEX_Automaton *n, struct GNUNET_CONTAINER_SList *states)
398 // This isn't very pretty. Would be better to use GNUNET_CONTAINER_slist_append, but
399 // this function adds to the beginning of dst, which currently breaks "pretty"
400 // printing of the graph...
401 struct GNUNET_CONTAINER_SList_Iterator i;
404 for (i = GNUNET_CONTAINER_slist_begin (states);
405 GNUNET_CONTAINER_slist_end (&i) != GNUNET_YES;
406 GNUNET_CONTAINER_slist_next (&i))
409 s = GNUNET_CONTAINER_slist_get (&i, NULL);
410 GNUNET_CONTAINER_slist_add_end (n->states,
411 GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
414 GNUNET_CONTAINER_slist_iter_destroy (&i);
418 nfa_create_state (struct GNUNET_REGEX_Context *ctx, int accepting)
422 s = GNUNET_malloc (sizeof (struct State));
423 s->id = ctx->state_id++;
424 s->accepting = accepting;
425 s->transitions = GNUNET_CONTAINER_slist_create();
428 GNUNET_asprintf (&s->name, "s%i", s->id);
434 automaton_fragment_clear (struct GNUNET_REGEX_Automaton *a)
436 GNUNET_CONTAINER_slist_destroy (a->states);
443 automaton_destroy_state (struct State *s)
445 if (NULL != s->transitions)
446 GNUNET_CONTAINER_slist_destroy (s->transitions);
448 GNUNET_free (s->name);
449 if (NULL != s->nfa_set)
450 GNUNET_CONTAINER_slist_destroy(s->nfa_set);
455 mark_all_states (struct GNUNET_REGEX_Automaton *n, int marked)
457 struct GNUNET_CONTAINER_SList_Iterator it;
460 for (it = GNUNET_CONTAINER_slist_begin (n->states);
461 GNUNET_YES != GNUNET_CONTAINER_slist_end (&it);
462 GNUNET_CONTAINER_slist_next (&it))
464 s = GNUNET_CONTAINER_slist_get (&it, NULL);
468 GNUNET_CONTAINER_slist_iter_destroy (&it);
472 nfa_add_concatenation (struct GNUNET_REGEX_Context *ctx)
474 struct GNUNET_REGEX_Automaton *a;
475 struct GNUNET_REGEX_Automaton *b;
476 struct GNUNET_REGEX_Automaton *new;
478 b = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton));
479 a = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton));
481 add_transition (ctx, a->end, 0, b->start);
482 a->end->accepting = 0;
483 b->end->accepting = 1;
485 new = nfa_create (NULL, NULL);
486 nfa_add_states (new, a->states);
487 nfa_add_states (new, b->states);
488 new->start = a->start;
490 automaton_fragment_clear (a);
491 automaton_fragment_clear (b);
493 stack_push (ctx->stack, new, sizeof *new);
497 nfa_add_star_op (struct GNUNET_REGEX_Context *ctx)
499 struct GNUNET_REGEX_Automaton *a;
500 struct GNUNET_REGEX_Automaton *new;
504 a = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton));
508 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
509 "nfa_add_star_op failed, because there was no element on the stack");
513 start = nfa_create_state (ctx, 0);
514 end = nfa_create_state (ctx, 1);
516 add_transition (ctx, start, 0, a->start);
517 add_transition (ctx, start, 0, end);
518 add_transition (ctx, a->end, 0, a->start);
519 add_transition (ctx, a->end, 0, end);
521 a->end->accepting = 0;
524 new = nfa_create (start, end);
525 nfa_add_states (new, a->states);
526 automaton_fragment_clear (a);
528 stack_push (ctx->stack, new, sizeof *new);
532 nfa_add_plus_op (struct GNUNET_REGEX_Context *ctx)
534 struct GNUNET_REGEX_Automaton *a;
536 a = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton));
538 add_transition (ctx, a->end, 0, a->start);
540 stack_push (ctx->stack, a, sizeof *a);
544 nfa_add_alternation (struct GNUNET_REGEX_Context *ctx)
546 struct GNUNET_REGEX_Automaton *a;
547 struct GNUNET_REGEX_Automaton *b;
548 struct GNUNET_REGEX_Automaton *new;
552 b = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton));
553 a = stack_pop (ctx->stack, sizeof (struct GNUNET_REGEX_Automaton));
555 start = nfa_create_state (ctx, 0);
556 end = nfa_create_state (ctx, 1);
557 add_transition (ctx, start, 0, a->start);
558 add_transition (ctx, start, 0, b->start);
560 add_transition (ctx, a->end, 0, end);
561 add_transition (ctx, b->end, 0, end);
563 a->end->accepting = 0;
564 b->end->accepting = 0;
567 new = nfa_create (start, end);
568 nfa_add_states (new, a->states);
569 nfa_add_states (new, b->states);
570 automaton_fragment_clear (a);
571 automaton_fragment_clear (b);
573 stack_push (ctx->stack, new, sizeof *new);
577 nfa_add_literal (struct GNUNET_REGEX_Context *ctx, const char lit)
579 struct GNUNET_REGEX_Automaton *n;
583 start = nfa_create_state (ctx, 0);
584 end = nfa_create_state (ctx, 1);
585 add_transition (ctx, start, lit, end);
586 n = nfa_create (start, end);
587 stack_push (ctx->stack, n, sizeof *n);
591 * Calculates the closure set for the given set of states.
593 * @param states set of states for which to calculate the closure
594 * @param count number of states in 'states'
595 * @param literal for the transition
597 * @return set of states that can be reached from the given 'states' when
598 * using only 'literal' transitions
600 struct GNUNET_CONTAINER_SList *
601 create_nfa_closure (struct GNUNET_CONTAINER_SList *states, const char literal)
603 struct GNUNET_CONTAINER_SList_Iterator stateit;
604 struct GNUNET_CONTAINER_SList_Iterator tranit;
605 struct GNUNET_CONTAINER_SList *cls;
606 struct GNUNET_CONTAINER_SList *cls_check;
608 struct State *currentstate;
609 struct Transition *currenttransition;
610 struct State *clsstate;
612 cls = GNUNET_CONTAINER_slist_create ();
614 for (stateit = GNUNET_CONTAINER_slist_begin (states);
615 GNUNET_YES != GNUNET_CONTAINER_slist_end (&stateit);
616 GNUNET_CONTAINER_slist_next (&stateit))
618 s = GNUNET_CONTAINER_slist_get (&stateit, NULL);
619 cls_check = GNUNET_CONTAINER_slist_create ();
621 // Add start state to closure only for epsilon closure
624 GNUNET_CONTAINER_slist_add (cls,
625 GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
629 stack_push (cls_check, s, sizeof *s);
631 while (!stack_empty(cls_check))
633 currentstate = stack_pop(cls_check, sizeof (struct State));
635 for (tranit = GNUNET_CONTAINER_slist_begin (currentstate->transitions);
636 GNUNET_CONTAINER_slist_end (&tranit) != GNUNET_YES;
637 GNUNET_CONTAINER_slist_next (&tranit))
639 currenttransition = GNUNET_CONTAINER_slist_get (&tranit, NULL);
641 if (NULL != currenttransition->state
642 && literal == currenttransition->literal)
644 clsstate = currenttransition->state;
646 if (NULL == clsstate)
649 if (GNUNET_YES != GNUNET_CONTAINER_slist_contains (cls, clsstate, sizeof *clsstate))
651 GNUNET_CONTAINER_slist_add (cls,
652 GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
653 clsstate, sizeof *clsstate);
654 stack_push (cls_check, clsstate, sizeof *clsstate);
658 GNUNET_CONTAINER_slist_iter_destroy (&tranit);
661 GNUNET_assert (stack_empty (cls_check));
662 GNUNET_CONTAINER_slist_destroy (cls_check);
664 GNUNET_CONTAINER_slist_iter_destroy (&stateit);
669 struct GNUNET_CONTAINER_SList *
670 GNUNET_REGEX_move (struct GNUNET_REGEX_Automaton *a, struct State *s, const char literal)
672 struct GNUNET_CONTAINER_SList *l;
673 struct GNUNET_CONTAINER_SList_Iterator it;
674 struct Transition *ctran;
676 if (!GNUNET_CONTAINER_slist_contains (a->states, s, sizeof *s))
678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
679 "State %s is not part of the given automaton", s->name);
683 l = GNUNET_CONTAINER_slist_create ();
685 for (it = GNUNET_CONTAINER_slist_begin (s->transitions);
686 GNUNET_YES != GNUNET_CONTAINER_slist_end (&it);
687 GNUNET_CONTAINER_slist_next (&it))
689 ctran = GNUNET_CONTAINER_slist_get (&it, NULL);
690 if (literal == ctran->literal)
691 GNUNET_CONTAINER_slist_add (l, GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
692 ctran->state, sizeof *(ctran->state));
694 GNUNET_CONTAINER_slist_iter_destroy (&it);
699 struct GNUNET_REGEX_Automaton *
700 GNUNET_REGEX_construct_nfa (const char *regex, const size_t len)
702 struct GNUNET_REGEX_Context ctx;
703 struct GNUNET_REGEX_Automaton *nfa;
706 unsigned int altcount;
707 unsigned int atomcount;
715 GNUNET_REGEX_context_init (&ctx);
723 for (count = 0; count < len && *regex; count++, regex++)
731 nfa_add_concatenation (&ctx);
733 GNUNET_array_grow (p, pcount, pcount + 1);
734 p[pcount - 1].altcount = altcount;
735 p[pcount - 1].atomcount = atomcount;
742 error_msg = "Cannot append '|' to nothing";
745 while (--atomcount > 0)
746 nfa_add_concatenation (&ctx);
752 error_msg = "Missing opening '('";
759 altcount = p[pcount].altcount;
760 atomcount = p[pcount].atomcount;
763 while (--atomcount > 0)
764 nfa_add_concatenation (&ctx);
765 for (; altcount > 0; altcount--)
766 nfa_add_alternation (&ctx);
768 altcount = p[pcount].altcount;
769 atomcount = p[pcount].atomcount;
775 error_msg = "Cannot append '+' to nothing";
778 nfa_add_star_op (&ctx);
783 error_msg = "Cannot append '+' to nothing";
786 nfa_add_plus_op (&ctx);
788 case 92: /* escape: \ */
795 nfa_add_concatenation (&ctx);
797 nfa_add_literal (&ctx, *regex);
804 error_msg = "Unbalanced parenthesis";
807 while (--atomcount > 0)
808 nfa_add_concatenation (&ctx);
809 for (; altcount > 0; altcount--)
810 nfa_add_alternation (&ctx);
815 nfa = stack_pop (ctx.stack, sizeof (struct GNUNET_REGEX_Automaton));
817 if (!stack_empty (ctx.stack))
819 error_msg = "Creating the NFA failed. NFA stack was not empty!";
823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
824 "Created NFA with %i States and a total of %i Transitions\n",
825 GNUNET_CONTAINER_slist_count (nfa->states),
828 GNUNET_REGEX_context_destroy (&ctx);
833 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not parse regex\n");
834 if (NULL != error_msg)
835 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", error_msg);
837 while (!stack_empty (ctx.stack))
838 GNUNET_REGEX_destroy_automaton (stack_pop (ctx.stack, sizeof (struct GNUNET_REGEX_Automaton)));
839 GNUNET_REGEX_context_destroy (&ctx);
844 GNUNET_REGEX_destroy_automaton (struct GNUNET_REGEX_Automaton *a)
846 struct GNUNET_CONTAINER_SList_Iterator it;
851 for (it = GNUNET_CONTAINER_slist_begin (a->states);
852 GNUNET_YES != GNUNET_CONTAINER_slist_end (&it);
853 GNUNET_CONTAINER_slist_next (&it))
855 automaton_destroy_state (GNUNET_CONTAINER_slist_get (&it, NULL));
857 GNUNET_CONTAINER_slist_iter_destroy (&it);
858 GNUNET_CONTAINER_slist_destroy (a->states);
863 struct GNUNET_REGEX_Automaton *
864 GNUNET_REGEX_construct_dfa (const char *regex, const size_t len)
866 struct GNUNET_REGEX_Context ctx;
867 struct GNUNET_REGEX_Automaton *dfa;
868 struct GNUNET_REGEX_Automaton *nfa;
869 struct GNUNET_CONTAINER_SList *tmp;
870 struct GNUNET_CONTAINER_SList *nfa_set;
871 struct GNUNET_CONTAINER_SList *sset;
872 struct GNUNET_CONTAINER_SList *dfa_stack;
873 struct GNUNET_CONTAINER_SList_Iterator tranit;
874 struct Transition *currenttransition;
875 struct State *dfa_state;
876 struct State *new_dfa_state;
877 struct State *state_contains;
879 GNUNET_REGEX_context_init (&ctx);
882 nfa = GNUNET_REGEX_construct_nfa (regex, len);
884 dfa_stack = GNUNET_CONTAINER_slist_create ();
886 // Initialize new dfa
887 dfa = GNUNET_malloc (sizeof (struct GNUNET_REGEX_Automaton));
888 dfa->states = GNUNET_CONTAINER_slist_create ();
890 // Create DFA start state from epsilon closure
891 sset = GNUNET_CONTAINER_slist_create ();
892 GNUNET_CONTAINER_slist_add (sset, GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
893 nfa->start, sizeof *(nfa->start));
894 nfa_set = create_nfa_closure (sset, 0);
895 GNUNET_CONTAINER_slist_destroy (sset);
896 dfa->start = dfa_create_state (&ctx, nfa_set);
897 GNUNET_CONTAINER_slist_add (dfa->states, GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
898 dfa->start, sizeof *(dfa->start));
899 stack_push (dfa_stack, dfa->start, sizeof *(dfa->start));
901 while (!stack_empty(dfa_stack))
903 dfa_state = stack_pop (dfa_stack, sizeof (struct State));
905 for (tranit = GNUNET_CONTAINER_slist_begin(dfa_state->transitions);
906 GNUNET_YES != GNUNET_CONTAINER_slist_end (&tranit);
907 GNUNET_CONTAINER_slist_next (&tranit))
909 currenttransition = GNUNET_CONTAINER_slist_get (&tranit, NULL);
911 if (0 != currenttransition->literal
912 && NULL == currenttransition->state)
914 tmp = create_nfa_closure (dfa_state->nfa_set, currenttransition->literal);
915 nfa_set = create_nfa_closure (tmp, 0);
916 new_dfa_state = dfa_create_state (&ctx, nfa_set);
917 GNUNET_CONTAINER_slist_destroy (tmp);
919 state_contains = GNUNET_CONTAINER_slist_contains2 (dfa->states,
921 sizeof *new_dfa_state,
923 if (NULL == state_contains)
925 GNUNET_CONTAINER_slist_add_end (dfa->states, GNUNET_CONTAINER_SLIST_DISPOSITION_STATIC,
926 new_dfa_state, sizeof *new_dfa_state);
927 stack_push (dfa_stack, new_dfa_state, sizeof *new_dfa_state);
928 currenttransition->state = new_dfa_state;
931 currenttransition->state = state_contains;
935 GNUNET_CONTAINER_slist_iter_destroy (&tranit);
937 GNUNET_CONTAINER_slist_destroy (dfa_stack);
938 GNUNET_REGEX_destroy_automaton (nfa);
939 GNUNET_REGEX_context_destroy (&ctx);
941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
942 "Created DFA with %i States\n",
943 GNUNET_CONTAINER_slist_count (dfa->states));
949 GNUNET_REGEX_save_nfa_graph (struct GNUNET_REGEX_Automaton *n, const char *filename)
951 struct GNUNET_CONTAINER_SList_Iterator stateit;
952 struct GNUNET_CONTAINER_SList_Iterator tranit;
954 struct Transition *ctran;
963 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print NFA, was NULL!");
967 if (NULL == filename || strlen (filename) < 1)
969 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No Filename given!");
973 p = fopen (filename, "w");
977 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not open file for writing: %s",
982 start = "digraph G {\nrankdir=LR\n";
983 fwrite (start, strlen (start), 1, p);
985 for (stateit = GNUNET_CONTAINER_slist_begin (n->states);
986 GNUNET_YES != GNUNET_CONTAINER_slist_end (&stateit);
987 GNUNET_CONTAINER_slist_next (&stateit))
990 s = GNUNET_CONTAINER_slist_get (&stateit, NULL);
994 GNUNET_asprintf (&s_acc, "\"%s\" [shape=doublecircle];\n", s->name);
995 fwrite (s_acc, strlen (s_acc), 1, p);
1001 for (tranit = GNUNET_CONTAINER_slist_begin(s->transitions);
1002 GNUNET_YES != GNUNET_CONTAINER_slist_end (&tranit);
1003 GNUNET_CONTAINER_slist_next (&tranit))
1005 ctran = GNUNET_CONTAINER_slist_get (&tranit, NULL);
1007 if (NULL == ctran->state)
1009 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1010 "Transition from State %i has has no state for transitioning\n",
1015 if (ctran->literal == 0)
1017 GNUNET_asprintf (&s_tran, "\"%s\" -> \"%s\" [label = \"epsilon\"];\n", s->name,
1018 ctran->state->name);
1022 GNUNET_asprintf (&s_tran, "\"%s\" -> \"%s\" [label = \"%c\"];\n", s->name,
1023 ctran->state->name, ctran->literal);
1026 fwrite (s_tran, strlen (s_tran), 1, p);
1027 GNUNET_free (s_tran);
1029 GNUNET_CONTAINER_slist_iter_destroy (&tranit);
1031 GNUNET_CONTAINER_slist_iter_destroy (&stateit);
1034 fwrite (end, strlen (end), 1, p);