2 ////////////////////////////////////////////////////////////////////////////////////////
4 // This file is part of Boost Statechart Viewer.
6 // Boost Statechart Viewer is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
11 // Boost Statechart Viewer is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with Boost Statechart Viewer. If not, see <http://www.gnu.org/licenses/>.
19 ////////////////////////////////////////////////////////////////////////////////////////
25 #include "stringoper.h"
30 * This class provides saving information about state machine to a specified output file. It saves states and transitions and also it creates the transition table.
34 list<string> transitions; /** list of transitions */
35 list<string> states; /** list of states */
36 list<string> events; /** list of events */
37 string outputFilename;
38 string name_of_machine;
39 string name_of_first_state;
40 string *table; /** transition table. It is being allocated when starting the creation of output file. */
43 /** This function finds place in the transition table to put a transition there. */
44 int find_place(string model, int type)
48 for(int i = 3;i<cols;i++)
50 if(model.compare(0,model.size(),table[i])==0) return i;
55 for(int i = 1;i<rows;i++)
56 if(model.compare(0,model.size(),table[i*cols+2])==0) return i;
61 IO_operations() {} /** Implicit constructor */
62 /** Constructor that fill in all private variables in this class */
63 IO_operations( const string outputFile, const string FSM_name, const string firstState, const list<string> trans, const list<string> state, const list<string> ev )
65 outputFilename = outputFile;
66 name_of_machine = FSM_name;
67 name_of_first_state = firstState;
73 ~IO_operations() /** destructor. It deallocates the transition table.*/
78 void setEvents(list<string> events) /** Set list of events to an attribute */
80 this->events = events;
83 void setTransitions(list<string> transitions) /** Set list of transitions to an attribute */
85 this->transitions = transitions;
88 void setStates(list<string> states) /** Set list of states to an attribute */
90 this->states = states;
93 void setNameOfStateMachine(string name_of_FSM) /** Set name of FSM to an attribute */
95 name_of_machine = name_of_FSM;
98 void setNameOfFirstState(string first_state) /** Set name of start state to an attribute */
100 name_of_first_state = first_state;
103 void setOutputFilename(string outputFilename) /** Set name of an output file to an attribute */
105 this->outputFilename = outputFilename;
108 bool test_start(const string *sState, const string state, const int num)
110 for(int i = 0; i<num;i++)
112 if (state.compare(0,sState[i].length(), sState[i])==0 && sState[i].length()==state.length()) return true;
117 bool write_states(ofstream& filestr) /** This method write states to the output file and also to transition table. */
119 int pos1, pos2, cnt, subs, num_start, orto = 0;
121 string context, state, ctx, *sState, str;
122 list<string> nstates = states;
123 context = name_of_machine;
125 table[1] = "Context";
127 cnt = count(name_of_first_state,',');
128 sState = new string [cnt+1];
129 str = name_of_first_state;
130 if(cnt>0) str = get_params(str);
132 for(int i = 0;i<=cnt;i++)
134 if(i == cnt) sState[i] = str;
137 sState[i] = str.substr(0,str.find(','));
138 str = str.substr(str.find(',')+1);
141 for(list<string>::iterator i = nstates.begin();i!=nstates.end();i++) // write all states in the context of the automaton
144 cnt = count(state,',');
145 if(count(state,'>')==1) //ortho states
152 pos1 = state.find(",");
153 if(orto == 1) ctx = cut_namespaces(cut_namespaces(state.substr(pos1+1),1));
154 else ctx = cut_namespaces(state.substr(pos1+1));
155 if(ctx.compare(0,context.length(),context)==0 && context.length()==ctx.length())
157 str = cut_namespaces(state.substr(0,pos1));
158 if(test_start(sState,str,num_start))
160 filestr<<str<<" [peripheries=2];\n";
161 table[cols*nState] = "*";
163 else filestr<<str<<"\n";
164 table[cols*nState+2] = str;
165 table[cols*nState+1] = context;
171 if(cnt==2) //ORTHO OK
173 pos1 = state.find(",");
174 pos2 = state.substr(pos1+1).find(",")+pos1+1;
175 ctx = cut_namespaces(state.substr(pos1+1,pos2-pos1-1));
176 if(ctx.compare(0,context.length(),context)==0 && context.length()==ctx.length())
178 str = cut_namespaces(state.substr(0,pos1));
179 if(test_start(sState,str,num_start))
181 filestr<<str<<" [peripheries=2];\n";
182 table[cols*nState] = "*";
184 else filestr<<str<<"\n";
185 table[cols*nState+2] = str;
186 table[cols*nState+1] = context;
193 while(!nstates.empty()) // substates ?
195 state = nstates.front();
196 filestr<<"subgraph cluster"<<subs<<" {\n";
197 pos1 = state.find(",");
198 pos2 = state.substr(pos1+1).find(",")+pos1+1;
199 if(pos1 == pos2) return false;
200 context = cut_namespaces(state.substr(0,pos1));
201 filestr<<"label=\""<<context<<"\";\n";
202 cnt = count(state.substr(pos2+1),',');
203 sState = new string [cnt+1];
204 str = state.substr(pos2+1);
205 if(cnt>0) str = get_params(str);
207 for(int i = 0;i<=cnt;i++)
209 if(i == cnt) sState[i] = str;
212 sState[i] = str.substr(0,str.find(','));
213 str = str.substr(str.find(',')+1);
217 for(list<string>::iterator i = nstates.begin();i!=nstates.end();i++)
220 cnt = count(state,',');
221 if(count(state,'>')==1) //ortho states
228 pos1 = state.find(",");
229 if(orto == 1) ctx = cut_namespaces(cut_namespaces(state.substr(pos1+1),1));
230 else ctx = cut_namespaces(state.substr(pos1+1));
231 if(ctx.compare(0,context.length(),context)==0 && context.length()==ctx.length())
233 str = cut_namespaces(state.substr(0,pos1));
234 if(test_start(sState,str,num_start))
236 filestr<<str<<" [peripheries=2];\n";
237 table[cols*nState]="*";
239 else filestr<<str<<"\n";
240 table[cols*nState+2] = str;
241 table[cols*nState+1] = context;
249 pos1 = state.find(",");
250 pos2 = state.rfind(",");
251 ctx = cut_namespaces(state.substr(pos1+1,pos2-pos1-1));
252 if(ctx.compare(0,context.length(),context)==0 && context.length()==ctx.length())
254 str = cut_namespaces(state.substr(0,pos1));
255 if(test_start(sState,str,num_start))
257 filestr<<str<<" [peripheries=2];\n";
258 table[cols*nState]="*";
260 else filestr<<str<<"\n";
261 table[cols*nState+2] = str;
262 table[cols*nState+1] = context;
274 void write_transitions(ofstream& filestr) /** Write transitions to the output file nad the transition table. */
277 string params, state, event, dest;
278 for(list<string>::iterator i = transitions.begin();i!=transitions.end();i++) // write all transitions
281 if(count(params,',')==2)
283 pos1 = params.find(",");
287 pos2 = params.rfind(",");
288 event = cut_namespaces(params.substr(pos2+1));
289 state = cut_namespaces(params.substr(1,pos2-1));
293 state = cut_namespaces(params.substr(0,pos1));
294 filestr<<state<<"->";
295 pos2 = params.rfind(",");
296 dest = cut_namespaces(params.substr(pos2+1));
298 event = cut_namespaces(params.substr(pos1+1,pos2-pos1-1));
299 filestr<<"[label=\""<<event<<"\"];\n";
302 table[find_place(state,2)*cols+find_place(event,1)]+=dest;
308 void fill_table_with_events() /** Fill the first row of the transition table with events. */
311 for(list<string>::iterator i = events.begin();i!=events.end();i++)
318 void save_to_file() /** Create output file stream and write there the name of state machine. It controls the whole process of writing into output files. */
320 if(!name_of_first_state.empty())
322 ofstream filestr(outputFilename.c_str());
323 filestr<<"digraph "<< name_of_machine<< " {\n";
324 cols = events.size()+3;
325 rows = states.size()+1;
326 table = new string [cols*rows];
327 fill_table_with_events();
328 if(!write_states(filestr))
330 cerr<<"Error during writing states.\n";
335 write_transitions(filestr);
338 // call write_reactions();
341 else cout<<"No state machine was found. So no output file was created.\n";
345 void print_table() /** This function prints the transition table. At first it counts the size of all columns. */
347 cout<<"\nTRANSITION TABLE\n";
348 unsigned * len = new unsigned[cols];
351 string line = "-|---|-", str;
352 for(int i = 1; i<cols; i++)
355 for(int j = 0;j<rows;j++)
357 nbr = count(table[j*cols+i],',');
360 str = table[j*cols+i];
361 for(int k = 1; k<nbr;k++)
363 if(len[i]<str.find(",")) len[i] = str.find(",");
364 str.substr(str.find(",")+1);
367 else if(len[i]<table[j*cols+i].length()) len[i] = table[j*cols+i].length();
369 for(unsigned k = 0; k<len[i]; k++)
376 for(int i = 0; i<rows; i++)
380 for(int j = 0;j<cols;j++)
383 str = table[i*cols+j];
384 nbr = count(str,',');
387 cout<<left<<str.substr(0,str.find(","))<<" | ";
390 table[i*cols+j] = str.substr(str.find(",")+1);
393 else table[i*cols+j]="";
398 cout<<left<<str<<" | ";
403 if(multiline == 0) cout<<line<<"\n";
409 void print_stats() /** Print short statistics about the state machine */
411 cout<<"\n"<<"Statistics: \n";
412 cout<<"Number of states: "<<states.size()<<"\n";
413 cout<<"Number of events: "<<events.size()<<"\n";
414 cout<<"Number of transitions: "<<transitions.size()<<"\n\n";