1 /**************************************************************************/
2 /* File:   flags.cpp                                                      */
3 /* Author: Joachim Schoeberl                                              */
4 /* Date:   10. Oct. 96                                                    */
5 /**************************************************************************/
6 
7 #include "flags.hpp"
8 
9 #ifdef WIN32
10 #include <float.h>
11 #endif
12 
13 #include <algorithm>
14 
15 namespace ngcore
16 {
17   using std::string;
18   using std::endl;
Flags()19   Flags :: Flags () { ; }
20 
Flags(const Flags & flags)21   Flags :: Flags (const Flags & flags)
22   {
23     string name;
24     for (int i = 0; i < flags.GetNStringFlags(); i++)
25       {
26 	string str = flags.GetStringFlag (i, name);
27 	SetFlag (name, str);
28       }
29     for (int i = 0; i < flags.GetNNumFlags(); i++)
30       {
31 	double val = flags.GetNumFlag (i, name);
32 	SetFlag (name, val);
33       }
34     for (int i = 0; i < flags.GetNDefineFlags(); i++)
35       {
36 	bool val = flags.GetDefineFlag (i, name);
37 	SetFlag (name, val);
38       }
39     for (int i = 0; i < flags.GetNNumListFlags(); i++)
40       {
41 	auto numa = flags.GetNumListFlag (i, name);
42 	SetFlag (name, *numa);
43       }
44     for (int i = 0; i < flags.GetNStringListFlags(); i++)
45       {
46 	auto stra = flags.GetStringListFlag (i, name);
47 	SetFlag (name, *stra);
48       }
49     for (int i = 0; i < flags.GetNFlagsFlags(); i++)
50       {
51 	auto lflags = flags.GetFlagsFlag (i, name);
52 	SetFlag (name, lflags);
53       }
54     for(auto i : Range(flags.anyflags.Size()))
55       {
56         SetFlag(flags.anyflags.GetName(i), flags.anyflags[i]);
57       }
58   }
59 
Flags(Flags && flags)60   Flags :: Flags (Flags && flags)
61     : strflags(flags.strflags), numflags(flags.numflags),
62       defflags(flags.defflags), strlistflags(flags.strlistflags),
63       numlistflags(flags.numlistflags) { ; }
64 
Flags(std::initializer_list<string> list)65   Flags :: Flags (std::initializer_list<string> list)
66   {
67     for (auto i = list.begin(); i < list.end(); i++)
68       SetCommandLineFlag ((string("-")+*i).c_str());
69   }
70 
71 
Flags(string f1,string f2,string f3,string f4,string f5)72   Flags :: Flags (string f1, string f2, string f3, string f4, string f5)
73   {
74     SetCommandLineFlag ((string("-")+f1).c_str());
75     if (f2.length()) SetCommandLineFlag ( (string("-")+f2).c_str() );
76     if (f3.length()) SetCommandLineFlag ( (string("-")+f3).c_str() );
77     if (f4.length()) SetCommandLineFlag ( (string("-")+f4).c_str() );
78     if (f5.length()) SetCommandLineFlag ( (string("-")+f5).c_str() );
79   }
80 
~Flags()81   Flags :: ~Flags ()
82   {
83     DeleteFlags ();
84   }
85 
DeleteFlags()86   void Flags :: DeleteFlags ()
87   {
88     strflags.DeleteAll();
89     numflags.DeleteAll();
90     defflags.DeleteAll();
91     strlistflags.DeleteAll();
92     numlistflags.DeleteAll();
93   }
94 
95 
SetFlag(const char * name,bool b)96   Flags Flags :: SetFlag (const char * name, bool b) &&
97   {
98     this -> SetFlag (name, b);
99     return std::move(*this);
100   }
101 
SetFlag(const char * name,double val)102   Flags Flags :: SetFlag (const char * name, double val) &&
103   {
104     this -> SetFlag (name, val);
105     return std::move(*this);
106   }
107 
108 
109 
SetFlag(const char * name,const string & val)110   Flags & Flags :: SetFlag (const char * name, const string & val)
111   {
112     strflags.Set (name, val);
113     return *this;
114   }
115 
SetFlag(const char * name,double val)116   Flags & Flags :: SetFlag (const char * name, double val) &
117   {
118     numflags.Set (name, val);
119     return *this;
120   }
121 
SetFlag(const char * name,bool b)122   Flags & Flags :: SetFlag (const char * name, bool b) &
123   {
124     defflags.Set (name, b);
125     return *this;
126   }
127 
SetFlag(const char * name,Flags & val)128   Flags & Flags :: SetFlag (const char * name, Flags & val) &
129   {
130     flaglistflags.Set (name, val);
131     return *this;
132   }
133 
134 
135 
SetFlag(const string & name,const string & val)136   Flags & Flags :: SetFlag (const string & name, const string & val)
137   {
138     // char * hval = new char[strlen (val) + 1];
139     // strcpy (hval, val);
140     strflags.Set (name, val);
141     return *this;
142   }
143 
SetFlag(const string & name,double val)144   Flags & Flags :: SetFlag (const string & name, double val)
145   {
146     numflags.Set (name, val);
147     return *this;
148   }
149 
SetFlag(const string & name,bool b)150   Flags & Flags :: SetFlag (const string & name, bool b)
151   {
152     defflags.Set (name, b);
153     return *this;
154   }
155 
SetFlag(const string & name,Flags & val)156   Flags & Flags :: SetFlag (const string & name, Flags & val)
157   {
158     flaglistflags.Set (name, val);
159     return *this;
160   }
161 
SetFlag(const string & name,const Array<string> & val)162   Flags & Flags :: SetFlag (const string & name, const Array<string> & val)
163   {
164     auto strarray = std::make_shared<Array<string>>(val);
165       /*
166     for (int i = 0; i < val.Size(); i++)
167       {
168 	strarray->Append (new char[strlen(val[i])+1]);
169 	strcpy (strarray->Last(), val[i]);
170       }
171       */
172     strlistflags.Set (name, strarray);
173     return *this;
174   }
175 
SetFlag(const string & name,const Array<double> & val)176   Flags & Flags :: SetFlag (const string & name, const Array<double> & val)
177   {
178     // Array<double> * numarray = new Array<double>(val);
179     auto numarray = std::make_shared<Array<double>> (val);
180 
181     numlistflags.Set (name, numarray);
182     return *this;
183   }
184 
SetFlag(const string & name,const std::any & val)185   Flags & Flags :: SetFlag (const string & name, const std::any & val)
186   {
187     anyflags.Set(name, val);
188     return *this;
189   }
190 
GetStringFlag(const string & name,const char * def) const191   string Flags :: GetStringFlag (const string & name, const char * def) const
192   {
193     if (strflags.Used (name))
194       return strflags[name];
195     else
196       {
197         if (!def) return string("");
198         return def;
199       }
200   }
201 
GetStringFlag(const string & name,string def) const202   string Flags :: GetStringFlag (const string & name, string def) const
203   {
204     if (strflags.Used (name))
205       return strflags[name];
206     else
207       return def;
208   }
209 
210 
GetNumFlag(const string & name,double def) const211   double Flags :: GetNumFlag (const string & name, double def) const
212   {
213     if (numflags.Used (name))
214       return numflags[name];
215     else
216       return def;
217   }
218 
GetNumFlagPtr(const string & name) const219   const double * Flags :: GetNumFlagPtr (const string & name) const
220   {
221     if (numflags.Used (name))
222       return & ((SymbolTable<double>&)numflags)[name];
223     else
224       return NULL;
225   }
226 
GetNumFlagPtr(const string & name)227   double * Flags :: GetNumFlagPtr (const string & name)
228   {
229     if (numflags.Used (name))
230       return & ((SymbolTable<double>&)numflags)[name];
231     else
232       return NULL;
233   }
234 
235   /*
236   int Flags :: GetDefineFlag (const char * name) const
237   {
238     return defflags.Used (name);
239   }
240   */
GetDefineFlag(const string & name) const241   bool Flags :: GetDefineFlag (const string & name) const throw()
242   {
243     if (!defflags.Used (name)) return false;
244     return defflags[name];
245   }
246 
GetDefineFlagX(const string & name) const247   xbool Flags :: GetDefineFlagX (const string & name) const throw()
248   {
249     if (!defflags.Used (name)) return maybe;
250     return bool(defflags[name]);
251   }
252 
253 
254   const Array<string> &
GetStringListFlag(const string & name) const255   Flags :: GetStringListFlag (const string & name) const
256   {
257     if (strlistflags.Used (name))
258       return *strlistflags[name];
259     else
260       {
261 	static Array<string> hstra(0);
262 	return hstra;
263       }
264   }
265 
266   const Array<double> &
GetNumListFlag(const string & name) const267   Flags ::GetNumListFlag (const string & name) const
268   {
269     if (numlistflags.Used (name))
270       return *numlistflags[name];
271     else
272       {
273 	static Array<double> hnuma(0);
274 	return hnuma;
275       }
276   }
277 
278   const Flags &
GetFlagsFlag(const string & name) const279   Flags ::GetFlagsFlag (const string & name) const
280   {
281     if (flaglistflags.Used (name))
282       return flaglistflags[name];
283     else
284       {
285 	static Flags empty;
286 	return empty;
287       }
288   }
289 
GetAnyFlag(const std::string & name) const290   const std::any& Flags:: GetAnyFlag(const std::string& name) const
291   {
292     if(anyflags.Used(name))
293       return anyflags[name];
294     static std::any empty;
295     return empty;
296   }
297 
StringFlagDefined(const string & name) const298   bool Flags :: StringFlagDefined (const string & name) const
299   {
300     return strflags.Used (name);
301   }
302 
NumFlagDefined(const string & name) const303   bool Flags :: NumFlagDefined (const string &name) const
304   {
305     return numflags.Used (name);
306   }
307 
FlagsFlagDefined(const string & name) const308   bool Flags :: FlagsFlagDefined (const string &name) const
309   {
310     return flaglistflags.Used (name);
311   }
312 
StringListFlagDefined(const string & name) const313   bool Flags :: StringListFlagDefined (const string & name) const
314   {
315     return strlistflags.Used (name);
316   }
317 
NumListFlagDefined(const string & name) const318   bool Flags :: NumListFlagDefined (const string & name) const
319   {
320     return numlistflags.Used (name);
321   }
322 
AnyFlagDefined(const string & name) const323   bool Flags :: AnyFlagDefined (const string& name) const
324   {
325     return anyflags.Used(name);
326   }
327 
SaveFlags(ostream & str) const328   void Flags :: SaveFlags (ostream & str) const
329   {
330     for (int i = 0; i < strflags.Size(); i++)
331       str << strflags.GetName(i) << " = " << strflags[i] << endl;
332     for (int i = 0; i < numflags.Size(); i++)
333       str << numflags.GetName(i) << " = " << numflags[i] << endl;
334     for (int i = 0; i < defflags.Size(); i++)
335       str << defflags.GetName(i) << " = " << (defflags[i] ? "_TRUE" : "_FALSE") << endl;
336     for (int i = 0; i < flaglistflags.Size(); i++)
337       str << flaglistflags.GetName(i) << " =*" << flaglistflags[i] << endl;
338     for (int i = 0; i < numlistflags.Size(); i++)
339       {
340         str << numlistflags.GetName(i) << " = [";
341         int j = 0;
342         for (j = 0; j + 1 < numlistflags[i]->Size(); ++j)
343           str << (*numlistflags[i])[j] << ", ";
344 	if (numlistflags[i]->Size())
345 	  str << (*numlistflags[i])[j];
346 	str << "]" << endl;
347       }
348   }
349 
SaveFlags(const char * filename) const350   void Flags :: SaveFlags (const char * filename) const
351   {
352     std::ofstream outfile (filename);
353     SaveFlags(outfile);
354   }
355 
356 
357 
PrintFlags(ostream & ost) const358   void Flags :: PrintFlags (ostream & ost) const
359   {
360     for (int i = 0; i < strflags.Size(); i++)
361       ost << strflags.GetName(i) << " = " << strflags[i] << endl;
362     for (int i = 0; i < numflags.Size(); i++)
363       ost << numflags.GetName(i) << " = " << numflags[i] << endl;
364     for (int i = 0; i < defflags.Size(); i++)
365       ost << defflags.GetName(i) << endl;
366     for (int i = 0; i < strlistflags.Size(); i++)
367       ost << strlistflags.GetName(i) << " = " << *strlistflags[i] << endl;
368     for (int i = 0; i < numlistflags.Size(); i++)
369       ost << numlistflags.GetName(i) << " = " << *numlistflags[i] << endl;
370     for (int i = 0; i < flaglistflags.Size(); i++)
371       ost << flaglistflags.GetName(i) << " = " << flaglistflags[i] << endl;
372   }
373 
LoadFlags(const char * filename,SymbolTable<Flags> * sf)374   void Flags :: LoadFlags (const char * filename, SymbolTable<Flags> * sf)
375   {
376     std::ifstream str(filename);
377     LoadFlags(str,sf);
378   }
379 
LoadFlags(std::istream & istr,SymbolTable<Flags> * sf)380   void Flags :: LoadFlags (std::istream & istr, SymbolTable<Flags> * sf )
381   {
382     char str[100];
383     char ch;
384     // double val;
385 
386     while (istr.good())
387       {
388         string name;
389         string content;
390         string line;
391         getline(istr, line);
392         std::istringstream line_stream(line);
393 
394         getline(line_stream, name, '=');
395         name.erase(std::remove(name.begin(), name.end(), ' '), name.end());
396 
397         getline(line_stream, content);
398         content.erase(std::remove(content.begin(), content.end(), ' '), content.end());
399 
400 	// if (name[0] == '/' && name[1] == '/')
401 	//   {
402 	//     ch = 0;
403 	//     while (ch != '\n' && istr.good())
404 	//       {
405 	// 	ch = istr.get();
406 	//       }
407 	//     continue;
408 	//   }
409 
410         if (strlen(content.c_str())==0)
411         {
412           SetFlag (name);
413           continue;
414         }
415 	else
416 	  {
417             std::istringstream content_stream(content);
418 
419             content_stream >> ch;
420             if (ch != '*')
421               {
422                 if (ch == '[')
423                   {
424                     // content_stream.putback (ch);
425                     // content_stream >> ch;
426                     string inner_string;
427                     getline(content_stream, inner_string, ']');
428                     std::istringstream inner_string_stream(inner_string);
429 
430                     Array<double> values;
431                     Array<string> strings;
432 
433                     string cur;
434                     while (getline(inner_string_stream, cur, ','))
435                     {
436                       char* endptr;
437                       double vald = strtod (cur.c_str(), &endptr);
438 
439                       if (endptr != cur.c_str() && strings.Size() == 0)
440                         values.Append(vald);
441                       else
442                         strings.Append(cur);
443                     }
444                     if (strings.Size() > 0)
445                       SetFlag(name, strings);
446                     else
447                       SetFlag(name, values);
448                   }
449                 else
450                   {
451                     if(content == "_TRUE" || content == "_FALSE")
452                       {
453                         SetFlag(name, (content =="_TRUE") ? true : false);
454                         continue;
455                       }
456                     char* endptr;
457                     double vald = strtod (content.c_str(), &endptr);
458                     if (endptr != content.c_str())
459                       SetFlag (name, vald);
460                     else
461                       SetFlag (name, content);
462                   }
463               }
464             else
465               {
466                 content_stream.clear();
467                 content_stream >> str;
468                 if (sf)
469                   SetFlag (name, (*sf)[str]);
470                 else
471                   throw Exception (" no symboltable of flags ");
472               }
473 	  }
474       }
475   }
476 
DoArchive(Archive & archive)477   void Flags :: DoArchive(Archive & archive)
478   {
479     archive & strflags & numflags & defflags & numlistflags & strlistflags & flaglistflags;
480   }
481 
Update(const Flags & other)482   void Flags :: Update(const Flags& other)
483   {
484     strflags.Update(other.strflags);
485     numflags.Update(other.numflags);
486     defflags.Update(other.defflags);
487     numlistflags.Update(other.numlistflags);
488     strlistflags.Update(other.strlistflags);
489     flaglistflags.Update(other.flaglistflags);
490   }
491 
SetCommandLineFlag(const char * st,SymbolTable<Flags> * sf)492   void Flags :: SetCommandLineFlag (const char * st, SymbolTable<Flags> * sf )
493   {
494     //cout << "SetCommandLineFlag: flag = " << st << endl;
495     std::istringstream inst( (char *)st);
496 
497     char name[100];
498     double val;
499 
500 
501     if (st[0] != '-')
502       {
503         std::cerr << "flag must start with '-'" << endl;
504 	return;
505       }
506 
507     // flag with double --
508     if (st[1] == '-') st++;
509 
510     const char * pos = strchr (st, '=');
511     const char * posstar = strchr (st, '*');
512     const char * posbrack = strchr (st, '[');
513 
514     if (!pos)
515       {
516 	//      (cout) << "Add def flag: " << st+1 << endl;
517 	SetFlag (st+1);
518       }
519     else
520       {
521 	//cout << "pos = " << pos << endl;
522 
523 	strncpy (name, st+1, (pos-st)-1);
524 	name[pos-st-1] = 0;
525 
526 	//cout << "name = " << name << endl;
527 
528 	pos++;
529 	char * endptr = NULL;
530 	val = strtod (pos, &endptr);
531 
532         /*
533         cout << "val = " << val << endl;
534         cout << "isfinite = " << std::isfinite (val) << endl;
535         cout << "isinf = " << std::isinf (val) << endl;
536         cout << "pos = " << pos << ", endpos = " << endptr << endl;
537         */
538         if (endptr != pos && !std::isfinite (val))
539           endptr = const_cast<char *>(pos);
540 
541         /*
542 #ifdef WIN32
543 	if(endptr != pos && !_finite(val))
544 	  endptr = const_cast<char *>(pos);
545 #else
546 #ifdef MACOS
547 	if(endptr != pos && (__isnand(val) || __isinfd(val)))
548 	  endptr = const_cast<char *>(pos);
549 #else
550 #ifdef SUN
551 #else
552 	if(endptr != pos && (std::isnan(val) || std::isinf(val)))
553 	  endptr = const_cast<char *>(pos);
554 #endif
555 #endif
556 #endif
557         */
558 
559 	//cout << "val = " << val << endl;
560 
561 	if (!posbrack)
562 	  {
563             if (posstar)
564               {
565                 pos++;
566                 if (sf)
567                   SetFlag (name, (*sf)[pos]);
568                 else
569                   throw Exception (" no symboltable of flags ");
570               }
571 	    else if (endptr == pos)
572 	      {
573 		// string-flag
574 		//(cout) << "Add String Flag: " << name << " = " << pos << endl;
575 		SetFlag (name, pos);
576 	      }
577 	    else
578 	      {
579 		// num-flag
580 		//(cout) << "Add Num Flag: " << name << " = " << val << endl;
581 		SetFlag (name, val);
582 	      }
583 	  }
584 	else
585 	  {
586 	    // list-flag
587 	    char hc;
588 	    double val;
589 
590 	    val = strtod (posbrack+1, &endptr);
591 	    if (endptr != posbrack+1)
592 	      {
593 		Array<double> values;
594 
595                 std::istringstream ist(posbrack);
596 		ist >> hc;   // '['
597 		ist >> val;
598 		while (ist.good())
599 		  {
600 		    values.Append (val);
601 		    ist >> hc;  // ','
602 		    ist >> val;
603 		  }
604 		SetFlag (name, values);
605 	      }
606 	    else
607 	      {
608                 // to be cleand up ...
609 		Array<char *> strs;
610 
611 		posbrack++;
612 		char * hstr = new char[strlen(posbrack)+1];
613 		strcpy (hstr, posbrack);
614 
615 		char * chp = hstr;
616 
617 		bool start = 1;
618 		while (*chp && *chp != ']')
619 		  {
620 		    if (start)
621 		      strs.Append (chp);
622 		    start = 0;
623 		    if (*chp == ',')
624 		      {
625 			*chp = 0;
626 			start = 1;
627 		      }
628 		    chp++;
629 		  }
630 		*chp = 0;
631 
632                 Array<string> strings;
633                 for (int i = 0; i < strs.Size(); i++)
634                   strings.Append (string (strs[i]));
635 		SetFlag (name, strings);
636                 delete [] hstr;
637 	      }
638 	  }
639       }
640   }
641 } // namespace ngcore
642