]> rtime.felk.cvut.cz Git - boost-statechart-viewer.git/blob - src/iooper.h
Add simple support for deffering events (not written as custom_reaction). In transiti...
[boost-statechart-viewer.git] / src / iooper.h
1 /** @file */ 
2 ////////////////////////////////////////////////////////////////////////////////////////  
3 //    
4 //    This file is part of Boost Statechart Viewer.
5 //
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.
10 //
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.
15 //
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/>.
18 //
19 ////////////////////////////////////////////////////////////////////////////////////////
20
21 #include <fstream>
22 #include <list>
23 #include <string>
24
25 #include "stringoper.h"
26
27 using namespace std;
28
29 /**
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.
31 */
32 class IO_operations
33 {       
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. */
41         int nState;
42         int cols, rows;
43         /** This function finds place in the transition table to put a transition there. */
44         int find_place(string model, int type)
45         {
46                 if(type == 1)
47                 {
48                         for(int i = 3;i<cols;i++)
49                         {
50                                 if(model.compare(0,model.size(),table[i])==0) return i;
51                         }
52                 }
53                 else 
54                 {
55                         for(int i = 1;i<rows;i++)
56                         if(model.compare(0,model.size(),table[i*cols+2])==0) return i;
57                 }
58                 return -1;
59         }
60         public:
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 )
64         {
65                 outputFilename = outputFile;
66                 name_of_machine = FSM_name;
67                 name_of_first_state = firstState;
68                 transitions = trans;
69                 states = state;
70                 events = ev;
71         }
72
73         ~IO_operations() /** destructor. It deallocates the transition table.*/
74         {
75                 delete [] table;
76         }
77         
78         void setEvents(list<string> events) /** Set list of events to an attribute */
79         {
80                 this->events = events;
81         }
82         
83         void setTransitions(list<string> transitions) /** Set list of transitions to an attribute */
84         {
85                 this->transitions = transitions;
86         }
87
88         void setStates(list<string> states) /** Set list of states to an attribute */
89         {
90                 this->states = states;
91         }
92
93         void setNameOfStateMachine(string name_of_FSM) /** Set name of FSM to an attribute */
94         {
95                 name_of_machine = name_of_FSM;
96         }
97
98         void setNameOfFirstState(string first_state) /** Set name of start state to an attribute */ 
99         {
100                 name_of_first_state = first_state;
101         }
102
103         void setOutputFilename(string outputFilename) /** Set name of an output file to an attribute */
104         {
105                 this->outputFilename = outputFilename;
106         }
107
108         bool test_start(const string *sState, const string state, const int num)
109         {
110                 for(int i = 0; i<num;i++)
111                 {
112                         if (state.compare(0,sState[i].length(), sState[i])==0 && sState[i].length()==state.length()) return true;
113                 }
114                 return false;
115         }
116         
117         bool write_states(ofstream& filestr) /** This method write states to the output file and also to transition table. */
118         {
119                 int pos1, pos2, cnt, subs, num_start, orto = 0;
120                 nState = 1;
121                 string context, state, ctx, *sState, str;
122                 list<string> nstates = states;
123                 context = name_of_machine;
124                 table[0] = "S";
125                 table[1] = "Context";
126                 table[2] = "State";
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);
131                 num_start = cnt+1;
132                 for(int i = 0;i<=cnt;i++)
133                 {
134                         if(i == cnt) sState[i] = str;
135                         else 
136                         {
137                                 sState[i] = str.substr(0,str.find(','));
138                                 str = str.substr(str.find(',')+1);
139                         }
140                 }               
141                 for(list<string>::iterator i = nstates.begin();i!=nstates.end();i++) // write all states in the context of the automaton
142                 {
143                         state = *i;
144                         cnt = count(state,',');
145                         if(count(state,'>')==1) //ortho states
146                         {
147                                 orto = 1;
148                                 if(cnt>1)cnt = 2;
149                         }
150                         if(cnt==1) 
151                         {
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())
156                                 {
157                                         str = cut_namespaces(state.substr(0,pos1));
158                                         if(test_start(sState,str,num_start)) 
159                                         {
160                                                 filestr<<str<<" [peripheries=2];\n";
161                                                 table[cols*nState] = "*";
162                                         }                       
163                                         else filestr<<str<<"\n";
164                                         table[cols*nState+2] = str;
165                                         table[cols*nState+1] = context;
166                                         nState+=1;
167                                         nstates.erase(i);
168                                         i--;
169                                 }
170                         }
171                         if(cnt==2) //ORTHO OK
172                         {
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())
177                                 {                               
178                                         str = cut_namespaces(state.substr(0,pos1));
179                                         if(test_start(sState,str,num_start)) 
180                                         {
181                                                 filestr<<str<<" [peripheries=2];\n";
182                                                 table[cols*nState] = "*";
183                                         }
184                                         else filestr<<str<<"\n";
185                                         table[cols*nState+2] = str;
186                                         table[cols*nState+1] = context;                 
187                                         nState+=1;                                      
188                                 }
189                         }
190                 }
191                 delete [] sState;
192                 subs = 0;
193                 while(!nstates.empty()) // substates ?
194                 {
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);
206                         num_start = cnt+1;
207                         for(int i = 0;i<=cnt;i++)
208                         {
209                                 if(i == cnt) sState[i] = str;
210                                 else 
211                                 {
212                                         sState[i] = str.substr(0,str.find(','));
213                                         str = str.substr(str.find(',')+1);
214                                 }
215                         }       
216                         nstates.pop_front();
217                         for(list<string>::iterator i = nstates.begin();i!=nstates.end();i++)
218                         {
219                                 state = *i;
220                                 cnt = count(state,',');
221                                 if(count(state,'>')==1) //ortho states
222                                 {
223                                         orto = 1;
224                                         if(cnt>1)cnt = 2;
225                                 }                               
226                                 if(cnt==1)
227                                 {
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())
232                                         {
233                                                 str = cut_namespaces(state.substr(0,pos1));
234                                                 if(test_start(sState,str,num_start))
235                                                 {
236                                                         filestr<<str<<" [peripheries=2];\n";
237                                                         table[cols*nState]="*";
238                                                 }
239                                                 else filestr<<str<<"\n";
240                                                 table[cols*nState+2] = str;
241                                                 table[cols*nState+1] = context;
242                                                 nState+=1;
243                                                 nstates.erase(i);
244                                                 i--;
245                                         }
246                                 }
247                                 if(cnt==2)
248                                 {
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())
253                                         {
254                                                 str = cut_namespaces(state.substr(0,pos1));
255                                                 if(test_start(sState,str,num_start))
256                                                 {
257                                                         filestr<<str<<" [peripheries=2];\n";
258                                                         table[cols*nState]="*";
259                                                 }                                       
260                                                 else filestr<<str<<"\n";
261                                                 table[cols*nState+2] = str;
262                                                 table[cols*nState+1] = context;
263                                                 nState+=1;
264                                         }
265                                 }
266                         }
267                         filestr<<"}\n";
268                         subs+=1;
269                         delete [] sState;       
270                 }
271                 return true;
272         }
273
274         void write_transitions(ofstream& filestr) /** Write transitions to the output file nad the transition table. */
275         {
276                 int pos1, pos2;
277                 string params, state, event, dest;
278                 for(list<string>::iterator i = transitions.begin();i!=transitions.end();i++) // write all transitions
279                 {
280                         params = *i;
281                         if(count(params,',')==2)
282                         {                       
283                                 pos1 = params.find(",");
284                                 if(pos1==0) 
285                                 {
286                                         dest = "(deferred)";
287                                         pos2 = params.rfind(",");
288                                         event = cut_namespaces(params.substr(pos2+1));
289                                         state = cut_namespaces(params.substr(1,pos2-1));
290                                 }
291                                 else
292                                 {
293                                         state = cut_namespaces(params.substr(0,pos1));
294                                         filestr<<state<<"->";
295                                         pos2 = params.rfind(",");
296                                         dest = cut_namespaces(params.substr(pos2+1));
297                                         filestr<<dest;
298                                         event = cut_namespaces(params.substr(pos1+1,pos2-pos1-1));
299                                         filestr<<"[label=\""<<event<<"\"];\n";
300                                 }
301                                 dest.append(",");
302                                 table[find_place(state,2)*cols+find_place(event,1)]+=dest;
303                         }
304                 }               
305                 return;
306         }
307
308         void fill_table_with_events() /** Fill the first row of the transition table with events. */
309         {
310                 int j = 3;
311                 for(list<string>::iterator i = events.begin();i!=events.end();i++)
312                 {
313                         table[j] = *i;
314                         j++;
315                 }
316         }
317
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. */
319         {
320                 if(!name_of_first_state.empty())        
321                 {       
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)) 
329                         {
330                                 cerr<<"Error during writing states.\n";
331                                 filestr<<"}";           
332                                 filestr.close();
333                                 return;                 
334                         }
335                         write_transitions(filestr);
336                         filestr<<"}";           
337                         filestr.close();
338                         // call write_reactions();
339                         print_table();
340                 }
341                 else cout<<"No state machine was found. So no output file was created.\n";
342                 return;
343         }
344
345         void print_table() /** This function prints the transition table. At first it counts the size of all columns. */
346         {
347                 cout<<"\nTRANSITION TABLE\n";
348                 unsigned * len = new unsigned[cols];
349                 len[0] = 1;
350                 int nbr, multiline;
351                 string line = "-|---|-", str;
352                 for(int i = 1; i<cols; i++)
353                 {
354                         len[i] = 0;
355                         for(int j = 0;j<rows;j++)
356                         {
357                                 nbr = count(table[j*cols+i],',');
358                                 if(nbr>1)
359                                 {
360                                         str = table[j*cols+i];
361                                         for(int k = 1; k<nbr;k++)
362                                         {
363                                                 if(len[i]<str.find(",")) len[i] = str.find(",");
364                                                 str.substr(str.find(",")+1);
365                                         }
366                                 }
367                                 else if(len[i]<table[j*cols+i].length()) len[i] = table[j*cols+i].length();
368                         }
369                         for(unsigned k = 0; k<len[i]; k++)
370                         {
371                                 line.append("-");
372                         }
373                         line.append("-|-");
374                 }
375                 cout<<line<<"\n";
376                 for(int i = 0; i<rows; i++)
377                 {
378                         cout<<" | ";
379                         multiline = 0;
380                         for(int j = 0;j<cols;j++)
381                         {
382                                 cout.width(len[j]);
383                                 str = table[i*cols+j];
384                                 nbr = count(str,',');
385                                 if(nbr>0)
386                                 {                               
387                                         cout<<left<<str.substr(0,str.find(","))<<" | ";
388                                         if(nbr>1) 
389                                         {
390                                                 table[i*cols+j] = str.substr(str.find(",")+1);
391                                                 multiline = 1;
392                                         }
393                                         else table[i*cols+j]="";
394                                                 
395                                 }
396                                 else 
397                                 {
398                                         cout<<left<<str<<" | ";
399                                         table [i*cols+j]="";
400                                 }
401                         }
402                         cout<<"\n";
403                         if(multiline == 0)      cout<<line<<"\n";
404                         else i--;
405                 }
406                 delete [] len;
407         }
408
409         void print_stats() /** Print short statistics about the state machine */
410         {
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";
415                 return;
416         }
417
418 };