cfl_helper.cpp
Go to the documentation of this file.
1 /** @file cfl_helper.cpp Helper functions */
2 
3 /* FAU Discrete Event Systems Library (libfaudes)
4 
5  Copyright (C) 2006 Bernd Opitz
6  Copyright (C) 2008-2010 Thomas Moor
7  Exclusive copyright is granted to Klaus Schmidt
8 
9  This library is free software; you can redistribute it and/or
10  modify it under the terms of the GNU Lesser General Public
11  License as published by the Free Software Foundation; either
12  version 2.1 of the License, or (at your option) any later version.
13 
14  This library is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  Lesser General Public License for more details.
18 
19  You should have received a copy of the GNU Lesser General Public
20  License along with this library; if not, write to the Free Software
21  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 
23 */
24 
25 
26 #include "cfl_helper.h"
27 
28 
29 // Debug includes
30 #include "cfl_attributes.h"
31 #include "cfl_registry.h"
32 #include "cfl_types.h"
33 #include "cfl_elementary.h"
34 
35 
36 // c++ file io
37 #include <fstream>
38 
39 
40 namespace faudes {
41 
42 // ToStringInteger(number)
43 std::string ToStringInteger(Int number) {
44  if(number>= std::numeric_limits<Int>::max()) return "inf";
45  if(number<= std::numeric_limits<Int>::min()+1) return "-inf";
46  std::string res;
47  std::stringstream sstr;
48  sstr << number;
49  sstr >> res;
50  return res;
51 }
52 
53 // ToStringInteger16(number)
54 std::string ToStringInteger16(Int number) {
55  std::string res;
56  std::stringstream sstr;
57  sstr << "0x" << std::setbase(16) << number;
58  sstr >> res;
59  return res;
60 }
61 
62 // ToStringFloat(number)
63 // todo: check range, prevent sci notation
64 std::string ToStringFloat(Float number) {
65  if(number>= std::numeric_limits<Float>::max()) return "inf";
66  if(number<= -1*std::numeric_limits<Float>::max()) return "-inf";
67  std::stringstream sstr;
68  if(number == static_cast<Float>( static_cast<Int>(number) )) {
69  sstr << static_cast<Int>(number);
70  } else {
71  sstr << std::fixed;
72  sstr << number;
73  }
74  std::string res;
75  sstr >> res;
76  return res;
77 }
78 
79 // ExpandString(rString, len)
80 std::string ExpandString(const std::string& rString, unsigned int len) {
81  std::string res;
82  res = rString;
83  std::string::size_type xtra = (std::string::size_type) len - rString.length();
84  if ((xtra > 0) && (xtra < 10000)) {
85  res.append(xtra, ' ');
86  }
87  return res;
88 }
89 
90 // CollapseString(rString, len)
91 std::string CollapsString(const std::string& rString, unsigned int len) {
92  if(len <=1) return rString;
93  if(rString.length() <= len) return rString;
94  int chead = len/2;
95  int ctail = len-chead;
96  return rString.substr(0,chead) + "..." + rString.substr(rString.length()-ctail,ctail);
97 }
98 
99 // ToIdx(rString)
100 Idx ToIdx(const std::string& rString) {
101  char * end;
102  unsigned long ul = strtoul (rString.c_str(), &end, 0);
103  unsigned long idxmax = std::numeric_limits<Idx>::max();
104  if(ul > idxmax) {
105  throw Exception("atoidx", "Idx overflow", 600);
106  }
107  return (Idx) ul;
108 }
109 
110 // String Substitution
111 std::string StringSubstitute(const std::string& rString,const std::string& rFrom,const std::string& rTo) {
112  // prep result
113  std::string res;
114  std::size_t pos=0;
115  // loop over occurences of "from"
116  while(pos<rString.length()) {
117  std::size_t next=rString.find(rFrom,pos);
118  if(next==std::string::npos) break;
119  res.append(rString.substr(pos, next-pos));
120  res.append(rTo);
121  pos=next+rFrom.length();
122  }
123  // get end
124  if(pos<rString.length())
125  res.append(rString.substr(pos));
126  // done
127  return res;
128 }
129 
130 // VersionString()
131 std::string VersionString() {
132  return std::string(FAUDES_VERSION);
133 }
134 
135 // FDPluginsString()
136 std::string PluginsString() {
137  return std::string(FAUDES_PLUGINS);
138 }
139 
140 // FDContributorsString()
141 std::string ContributorsString() {
142  return
143  "Ramon Barakat, Ruediger Berndt, Christian Breindl, Christine Baier, Tobias Barthel, Christoph Doerr, Marc Duevel, Norman Franchi, Rainer Hartmann, Jochen Hellenschmidt, Stefan Jacobi, Matthias Leinfelder, Tomas Masopust, Michael Meyer, Andreas Mohr, Thomas Moor, Mihai Musunoi, Bernd Opitz, Katja Pelaic, Irmgard Petzoldt, Sebastian Perk, Thomas Rempel, Daniel Ritter, Berno Schlein, Ece Schmidt, Klaus Schmidt, Anne-Kathrin Schmuck, Sven Schneider, Matthias Singer, Ulas Turan, Christian Wamser, Zhengying Wang, Thomas Wittmann, Shi Xiaoxun, Jorgos Zaddach, Hao Zhou, Christian Zwick, et al";
144 }
145 
146 
147 // ProcessDot(infile,outfile,format)
148 void ProcessDot(const std::string& rDotFile,
149  const std::string& rOutFile, const std::string& rOutFormat, const std::string& rDotExec)
150 {
151  std::string format=rOutFormat;
152  // guess format from filename
153  if(format=="") {
154  if(rOutFile.rfind('.')+1 < rOutFile.size()) {
155  format=rOutFile.substr(rOutFile.rfind('.')+1);
156  }
157  }
158  // test format
159  if (format == "canon");
160  else if (format == "dot");
161  else if (format == "xdot");
162  else if (format == "cmap");
163  else if (format == "dia");
164  else if (format == "fig");
165  else if (format == "gd");
166  else if (format == "gd2");
167  else if (format == "gif");
168  else if (format == "hpgl");
169  else if (format == "imap");
170  else if (format == "cmapx");
171  else if (format == "ismap");
172  else if (format == "jpg");
173  else if (format == "jpeg");
174  else if (format == "mif");
175  else if (format == "mp");
176  else if (format == "pcl");
177  else if (format == "pic");
178  else if (format == "plain");
179  else if (format == "plain-ext");
180  else if (format == "png");
181  else if (format == "ps");
182  else if (format == "ps2");
183  else if (format == "svg");
184  else if (format == "svgz");
185  else if (format == "vrml");
186  else if (format == "vtx");
187  else if (format == "wbmp");
188  else if (format == "eps");
189  else if (format == "pdf");
190  else {
191  std::stringstream errstr;
192  errstr << "Dot output format \"" << format << "\" unknown";
193  throw Exception("faudes::ProcessDot", errstr.str(), 3);
194  }
195  std::string dotcommand = rDotExec + " -T"+format+" \""+rDotFile+"\" -o \""+rOutFile+"\"";
196  if(system(dotcommand.c_str()) != 0) {
197  throw Exception("faudes::ProcessDot",
198  "Error in running " + dotcommand, 3);
199  }
200 }
201 
202 
203 // CreateTempFile(void)
204 // todo: sys dependant, report, investigate threads
205 std::string CreateTempFile(void) {
206  char filename[]= "faudes_temp_XXXXXX";
207  std::string res;
208 #ifdef FAUDES_POSIX
209  // use mkstemp on recent Posix systems
210  int filedes = -1;
211  filedes= mkstemp(filename);
212  if(filedes==-1) {
213  FD_DF("faudes::CreateTempFile(): error");
214  return res;
215  }
216  close(filedes);
217  res=std::string(filename);
218 #endif
219 #ifdef FAUDES_WINDOWS
220  // mimique mkstemp on Windows/MinGW
221  /*
222  int filedes = -1;
223  #define _S_IREAD 256
224  #define _S_IWRITE 128
225  mktemp(filename);
226  filedes=open(filename,O_RDWR|O_BINARY|O_CREAT|O_EXCL|_O_SHORT_LIVED, _S_IREAD|_S_IWRITE);
227  if(filedes==-1) {
228  FD_DF("faudes::CreateTempFile(): error");
229  return "";
230  }
231  close(filedes);
232  res=std::string(filename);
233  */
234  // win32 API
235  char* tmpname = _mktemp(filename);
236  FILE* file;
237  if(tmpname==NULL) {
238  FD_DF("faudes::CreateTempFile(): error");
239  return res;
240  }
241  fopen_s(&file,tmpname,"w");
242  if(file==NULL) {
243  FD_DF("faudes::CreateTempFile(): error");
244  return "";
245  }
246  fclose(file);
247  res=std::string(tmpname);
248 #endif
249  FD_DF("faudes::CreateTempFile(): " << res);
250  return(res);
251 }
252 
253 
254 // RemoveFile(void)
255 // todo: sys dependant *
256 bool RemoveFile(const std::string& rFileName) {
257  return std::remove(rFileName.c_str()) == 0;
258 }
259 
260 
261 // ExtractPath
262 std::string ExtractDirectory(const std::string& rFullPath) {
263  std::string res="";
264  std::size_t seppos = rFullPath.find_last_of(faudes_pathseps());
265  if(seppos==std::string::npos) return res;
266  res=rFullPath.substr(0,seppos+1);
267  return res;
268 }
269 
270 // ExtractFilename
271 std::string ExtractFilename(const std::string& rFullPath) {
272  std::string res=rFullPath;
273  std::size_t seppos = rFullPath.find_last_of(faudes_pathseps());
274  if(seppos==std::string::npos) return res;
275  res=rFullPath.substr(seppos+1);
276  return res;
277 }
278 
279 // ExtractBasename
280 std::string ExtractBasename(const std::string& rFullPath) {
281  std::string res=rFullPath;
282  std::size_t seppos = res.find_last_of(faudes_pathseps());
283  if(seppos!=std::string::npos) {
284  res=res.substr(seppos+1);
285  }
286  std::size_t dotpos = res.find_last_of(".");
287  if(dotpos!=std::string::npos) {
288  res=res.substr(0,dotpos);
289  }
290  return res;
291 }
292 
293 // ExtractExtension
294 std::string ExtractExtension(const std::string& rFullPath) {
295  std::string res=rFullPath;
296  std::size_t seppos = res.find_last_of(faudes_pathseps());
297  if(seppos!=std::string::npos) {
298  res=res.substr(seppos+1);
299  }
300  std::size_t dotpos = res.find_last_of(".");
301  if(dotpos!=std::string::npos)
302  if(dotpos +1 < res.size()) {
303  return res.substr(dotpos+1,res.size()-dotpos-1);
304  }
305  return std::string();
306 }
307 
308 // PrependPath
309 std::string PrependDirectory(const std::string& rDirectory, const std::string& rFileName) {
310  std::string res=rDirectory;
311  char sepchar=faudes_pathsep().at(0);
312  if(res!="")
313  if(res.at(res.length()-1)!=sepchar)
314  res.append(1,sepchar);
315  res.append(rFileName);
316  return res;
317 }
318 
319 // Test directory
320 bool DirectoryExists(const std::string& rDirectory) {
321 #ifdef FAUDES_POSIX
322  DIR *thedir;
323  thedir=opendir(rDirectory.c_str());
324  if(thedir) closedir(thedir);
325  return thedir!= 0;
326 #endif
327 #ifdef FAUDES_WINDOWS
328  DWORD fattr = GetFileAttributesA(rDirectory.c_str());
329  return
330  (fattr!=INVALID_FILE_ATTRIBUTES) && (fattr & FILE_ATTRIBUTE_DIRECTORY);
331 #endif
332  return false;
333 }
334 
335 // scan directory
336 std::set< std::string > ReadDirectory(const std::string& rDirectory) {
337  std::set< std::string > res;
338 #ifdef FAUDES_POSIX
339  DIR *thedir;
340  struct dirent *theent;
341  thedir=opendir(rDirectory.c_str());
342  if(!thedir) return res;
343  while((theent=readdir(thedir))) {
344  std::string fname(theent->d_name);
345  if(fname==".") continue;
346  if(fname=="..") continue;
347  res.insert(fname);
348  }
349  closedir(thedir);
350 #endif
351 #ifdef FAUDES_WINDOWS
352  HANDLE hf;
353  WIN32_FIND_DATA data;
354  hf = FindFirstFile((rDirectory+"\\*.*").c_str(), &data);
355  if (hf != INVALID_HANDLE_VALUE) {
356  do {
357  std::string fname(data.cFileName);
358  if(fname==".") continue;
359  if(fname=="..") continue;
360  res.insert(fname);
361  } while (FindNextFile(hf, &data));
362  FindClose(hf);
363  }
364 #endif
365  return res;
366 }
367 
368 
369 
370 
371 
372 // Test file
373 bool FileExists(const std::string& rFilename) {
374  std::fstream fp;
375  fp.open(rFilename.c_str(), std::ios::in | std::ios::binary);
376  return fp.good();
377 }
378 
379 // Delete file
380 bool FileDelete(const std::string& rFilename) {
381  return remove(rFilename.c_str()) == 0;
382 }
383 
384 // Copy file
385 bool FileCopy(const std::string& rFromFile, const std::string& rToFile) {
386  std::ifstream froms(rFromFile.c_str(), std::ios::binary);
387  std::ofstream tos(rToFile.c_str(), std::ios::binary);
388  tos << froms.rdbuf();
389  tos.flush();
390  return !(froms.fail() || tos.fail());
391 }
392 
393 // ConsoleOut class
394 // Note: console-out is not re-entrant; for multithreaded applications
395 // you must derive a class that has built-in mutexes;
396 ConsoleOut::ConsoleOut(void) : pStream(NULL), mMute(false) {
397  pInstance=this;
398 }
400  if(pStream) { pStream->flush(); delete pStream; }
401  if(this==smpInstance) smpInstance=NULL;
402 }
404  if(!smpInstance) smpInstance= new ConsoleOut();
405  return smpInstance->pInstance;
406 }
408  std::string fname = smpInstance->pInstance->Filename();
410  smpInstance->pInstance=out;
412  smpInstance->pInstance->ToFile(fname);
413 }
414 void ConsoleOut::ToFile(const std::string& filename) {
415  if(pStream) { pStream->flush(); delete pStream; }
416  pStream=NULL;
417  mFilename=filename;
418  if(mFilename=="") return;
419  pStream = new std::ofstream();
420  pStream->open(mFilename.c_str(),std::ios::app);
421 }
422 void ConsoleOut::Write(const std::string& message,long int cntnow, long int cntdone) {
423  if(mMute) return;
424  DoWrite(message,cntnow,cntdone);
425 }
426 void ConsoleOut::DoWrite(const std::string& message,long int cntnow, long int cntdone) {
427  (void) cntnow; (void) cntdone;
428  std::ostream* sout=pStream;
429  if(!sout) sout=&std::cout; // tmoor: used to be std::cerr, using std::cout to facilitate emscripten/js
430  *sout << message;
431  sout->flush();
432 }
433 
434 // global instance
436 
437 
438 
439 // debugging: objectcount
440 std::map<std::string,long int>* ObjectCount::mspMax=NULL;
441 std::map<std::string,long int>* ObjectCount::mspCount=NULL;
442 bool ObjectCount::msDone=false;
444  mspCount= new std::map<std::string,long int>();
445  mspMax= new std::map<std::string,long int>();
446  msDone=true;
447 }
448 void ObjectCount::Init(void) {
449  if(!msDone) ObjectCount();
450 }
451 void ObjectCount::Inc(const std::string& rTypeName) {
452  if(!msDone) ObjectCount();
453  long int cnt = ((*mspCount)[rTypeName]+=1);
454  if((*mspMax)[rTypeName]<cnt) (*mspMax)[rTypeName]=cnt;
455 }
456 void ObjectCount::Dec(const std::string& rTypeName) {
457  if(!msDone) ObjectCount();
458  (*mspCount)[rTypeName]-=1;
459 }
460 
461 
462 // debugging: report on exit function
463 void ExitFunction(void){
464 #ifdef FAUDES_DEBUG_CODE
465  FAUDES_WRITE_CONSOLE("faudes::ExitFunction():");
466  // be sure its up and running
468  // get rid of all registry prototypes
469  //TypeRegistry::G()->ClearAll();
470  //FunctionRegistry::G()->Clear();
471  // prepare report
472  std::map<std::string,long int>::iterator cit;
473  cit=ObjectCount::mspCount->begin();
474  for(;cit!=ObjectCount::mspCount->end();cit++) {
475  FAUDES_WRITE_CONSOLE( cit->first << ": #" << ToStringInteger(cit->second) <<
476  " (max #" << (*ObjectCount::mspMax)[cit->first] << ")");
477  }
478 #endif
479 }
480 
481 
482 #ifdef FAUDES_DEBUG_CODE
483 // report on exit install
484 class ExitFunctionInstall {
485 private:
486  static bool mDone;
487  static ExitFunctionInstall mInstance;
488  ExitFunctionInstall(void) {
489  if(mDone) return;
490  FAUDES_WRITE_CONSOLE("ExitFunctionInstall()");
491  std::atexit(ExitFunction);
492  mDone=true;
493  }
494 };
495 // exit function: global data
496 bool ExitFunctionInstall::mDone=false;
497 ExitFunctionInstall ExitFunctionInstall::mInstance;
498 #endif
499 
500 // test protocol: token writer and file
502 std::string gTestProtocolFr;
503 
504 // test protocol: setup
505 std::string TestProtocol(const std::string& rSource) {
506  if(gTestProtocolTw) return gTestProtocolFr;
507  // set up filename
508  std::string filename=rSource;
509  // fix empty source
510  if(filename=="") filename="faudes_dump";
511  // remove directory
512  filename=ExtractFilename(filename);
513  // remove extension
514  std::string::size_type pos=0;
515  for(;pos<filename.length();pos++)
516  if(filename.at(pos)=='.') filename.at(pos)='_';
517  // append extension
518  filename.append(".prot");
519  // record nominal case
520  gTestProtocolFr=filename;
521  // prepend prefix
522  filename.insert(0,"tmp_");
523  // initialise token writer
524  gTestProtocolTw= new TokenWriter(filename);
525  // report filename
526  return gTestProtocolFr;
527 }
528 
529 // test protocol: dump
530 void TestProtocol(const std::string& rMessage, const Type& rData, bool full) {
531  if(!gTestProtocolTw) return;
532  gTestProtocolTw->WriteComment("%%% test mark: " + rMessage);
533  if(full) rData.Write(*gTestProtocolTw);
534  else rData.SWrite(*gTestProtocolTw);
538  *gTestProtocolTw << "\n";
539 }
540 void TestProtocol(const std::string& rMessage, bool data) {
541  Boolean fbool(data);
542  TestProtocol(rMessage,fbool,true);
543 }
544 void TestProtocol(const std::string& rMessage, long int data) {
545  Integer fint(data);
546  TestProtocol(rMessage,fint,true);
547 }
548 void TestProtocol(const std::string& rMessage, const std::string& rData) {
549  String fstr(rData);
550  TestProtocol(rMessage,fstr,true);
551 }
552 
553 // test protocol: compare
554 bool TestProtocol(void) {
555  // bail out on no protocol
556  if(!gTestProtocolTw) return true;
557  // close protocol file
558  std::string prot=gTestProtocolTw->FileName();
559  delete gTestProtocolTw;
560  gTestProtocolTw=NULL;
561  // open protocol
562  std::fstream fp;
563  fp.open(prot.c_str(), std::ios::in | std::ios::binary);
564  if(!fp.good()) {
565  FAUDES_WRITE_CONSOLE("TestProtocol(): could not open protocol \"" << prot << "\"");
566  return false;
567  }
568  // open reference
569  std::string ref=gTestProtocolFr;
570  std::fstream fr;
571  fr.open(ref.c_str(), std::ios::in | std::ios::binary);
572  if(!fr.good()) {
573  ref="data"+faudes_pathsep()+ref;
574  fr.clear(); // mingw's runtime will not clear on open
575  fr.open(ref.c_str(), std::ios::in | std::ios::binary);
576  }
577  if(!fr.good()) {
578  FAUDES_WRITE_CONSOLE("TestProtocol(): could not open/find reference \"" << gTestProtocolFr << "\"");
579  return true;
580  }
581  // perform comparision
582  int dline=-1;
583  int cline=1;
584  try{
585  while(true) {
586  // read next char
587  char cp = fp.get();
588  char cr= fr.get();
589  // eof
590  if(fp.eof() && fr.eof()) { break; }
591  if(!fp.good() || !fr.good()) { dline=cline; break;}
592  // cheap normalize cr/lf: ignore \r (assume no double \r
593  if( cp=='\r' && cr =='\r') continue;
594  if( cp=='\r' && fp.eof()){ dline=cline; break;}
595  if( cp=='\r') cp = fp.get();
596  if( cr=='\r' && fr.eof()){ dline=cline; break;}
597  if( cr=='\r') cr = fr.get();
598  // count lines
599  if( cr=='\n') cline++;
600  // sense mitmatch
601  if( cp!= cr ){dline=cline; break;}
602  }
603  } catch(std::ios::failure&) {
604  throw Exception("TestProtocol()", "io error at line " + ToStringInteger(cline), 1);
605  }
606  // done
607  if(dline>=0) {
608  FAUDES_WRITE_CONSOLE("TestProtocol(): using reference " << ref << "");
609  FAUDES_WRITE_CONSOLE("TestProtocol(): found difference at line " << dline << "");
610  }
611  return dline== -1;
612 }
613 
614 
615 
616 // declare loop callback
617 static bool (*gBreakFnct)(void)=0;
618 
619 // set loop callback
620 void LoopCallback( bool pBreak(void)) {
621  gBreakFnct=pBreak;
622 }
623 
624 // do loop callback
625 // note: this function is meant to be "quiet" during normal
626 // operation in order not to mess up console logging
627 void LoopCallback(void){
628  if(!gBreakFnct) return;
629  if(! (*gBreakFnct)() ) return;
630  throw Exception("LoopCallback", "break on application request", 110);
631 }
632 
633 } // namespace faudes

libFAUDES 2.28a --- 2016.09.13 --- c++ api documentaion by doxygen