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_graph.c
22 * @brief functions for creating .dot graphs from regexes
23 * @author Maximilian Szengel
26 #include "gnunet_regex_lib.h"
27 #include "regex_internal.h"
30 * Recursive function doing DFS with 'v' as a start, detecting all SCCs inside
31 * the subgraph reachable from 'v'. Used with scc_tarjan function to detect all
32 * SCCs inside an automaton.
34 * @param scc_counter counter for numbering the sccs
35 * @param v start vertex
36 * @param index current index
37 * @param stack stack for saving all SCCs
38 * @param stack_size current size of the stack
41 scc_tarjan_strongconnect (unsigned int *scc_counter,
42 struct GNUNET_REGEX_State *v, unsigned int *index,
43 struct GNUNET_REGEX_State **stack,
44 unsigned int *stack_size)
46 struct GNUNET_REGEX_State *w;
47 struct GNUNET_REGEX_Transition *t;
52 stack[(*stack_size)++] = v;
55 for (t = v->transitions_head; NULL != t; t = t->next)
64 scc_tarjan_strongconnect (scc_counter, w, index, stack, stack_size);
65 v->lowlink = (v->lowlink > w->lowlink) ? w->lowlink : v->lowlink;
67 else if (0 != w->contained)
68 v->lowlink = (v->lowlink > w->index) ? w->index : v->lowlink;
71 if (v->lowlink == v->index)
73 w = stack[--(*stack_size)];
81 w->scc_id = *scc_counter;
82 w = stack[--(*stack_size)];
85 w->scc_id = *scc_counter;
92 * Detect all SCCs (Strongly Connected Components) inside the given automaton.
93 * SCCs will be marked using the scc_id on each state.
95 * @param a the automaton for which SCCs should be computed and assigned.
98 scc_tarjan (struct GNUNET_REGEX_Automaton *a)
101 unsigned int scc_counter;
102 struct GNUNET_REGEX_State *v;
103 struct GNUNET_REGEX_State *stack[a->state_count];
104 unsigned int stack_size;
106 for (v = a->states_head; NULL != v; v = v->next)
117 for (v = a->states_head; NULL != v; v = v->next)
120 scc_tarjan_strongconnect (&scc_counter, v, &index, stack, &stack_size);
126 * Save a state to an open file pointer. cls is expected to be a file pointer to
127 * an open file. Used only in conjunction with
128 * GNUNET_REGEX_automaton_save_graph.
130 * @param cls file pointer.
131 * @param count current count of the state, not used.
135 GNUNET_REGEX_automaton_save_graph_step (void *cls, unsigned int count,
136 struct GNUNET_REGEX_State *s)
139 struct GNUNET_REGEX_Transition *ctran;
147 GNUNET_asprintf (&s_acc,
148 "\"%s(%i)\" [shape=doublecircle, color=\"0.%i 0.8 0.95\"];\n",
149 s->name, s->proof_id, s->scc_id);
153 GNUNET_asprintf (&s_acc, "\"%s(%i)\" [color=\"0.%i 0.8 0.95\"];\n", s->name,
154 s->proof_id, s->scc_id);
159 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print state %s\n", s->name);
162 fwrite (s_acc, strlen (s_acc), 1, p);
166 for (ctran = s->transitions_head; NULL != ctran; ctran = ctran->next)
168 if (NULL == ctran->to_state)
170 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
171 "Transition from State %i has no state for transitioning\n",
176 if (ctran->label == 0)
178 GNUNET_asprintf (&s_tran,
179 "\"%s(%i)\" -> \"%s(%i)\" [label = \"epsilon\", color=\"0.%i 0.8 0.95\"];\n",
180 s->name, s->proof_id, ctran->to_state->name,
181 ctran->to_state->proof_id, s->scc_id);
185 GNUNET_asprintf (&s_tran,
186 "\"%s(%i)\" -> \"%s(%i)\" [label = \"%c\", color=\"0.%i 0.8 0.95\"];\n",
187 s->name, s->proof_id, ctran->to_state->name,
188 ctran->to_state->proof_id, ctran->label, s->scc_id);
193 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print state %s\n",
198 fwrite (s_tran, strlen (s_tran), 1, p);
199 GNUNET_free (s_tran);
206 * Save the given automaton as a GraphViz dot file
208 * @param a the automaton to be saved
209 * @param filename where to save the file
212 GNUNET_REGEX_automaton_save_graph (struct GNUNET_REGEX_Automaton *a,
213 const char *filename)
221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not print NFA, was NULL!");
225 if (NULL == filename || strlen (filename) < 1)
227 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No Filename given!");
231 p = fopen (filename, "w");
235 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not open file for writing: %s",
240 /* First add the SCCs to the automaton, so we can color them nicely */
243 start = "digraph G {\nrankdir=LR\n";
244 fwrite (start, strlen (start), 1, p);
246 GNUNET_REGEX_automaton_traverse (a, &GNUNET_REGEX_automaton_save_graph_step,
250 fwrite (end, strlen (end), 1, p);