1 // $Id: stringx.cpp,v 1.126 2012/02/15 18:13:42 jmcgill Exp $
2 
3 /*
4   Copyright 2002  Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein
5 
6   This software is distributed free of charge for non-commercial use
7   and is copyrighted.  Of course, we do not guarantee that the software
8   works, and are not responsible for any damage you may cause or have.
9 */
10 
11 #include <cassert>
12 #include <cctype>
13 #include <functional>
14 #include <stdexcept>
15 #include <string>
16 #include <cstring>
17 #include <cstdio>
18 
19 #include "arranger_types.h"
20 #include "errhandling.h"
21 #include "mathx.h"
22 #include "stringx.h"
23 #include "xml_strings.h"  // for xmlstr::XML_ATTRTYPE_NAME in MakeTagWithName()
24 #include "ui_strings.h"
25 #include "paramstat.h"
26 
27 #ifdef LAMARC_COMPILE_MSWINDOWS    // used in cwdString
28 #include <direct.h>       // direct.h -- provides _getcwd()
29 #else
30 #include <unistd.h>       // unistd.h -- provides getcwd()
31 #endif
32 
33 #ifdef DMALLOC_FUNC_CHECK
34 #include "/usr/local/include/dmalloc.h"
35 #endif
36 
37 using namespace std;
38 
39 //------------------------------------------------------------------------------------
40 //------------------------------------------------------------------------------------
41 
UpperCase(string & s)42 void UpperCase(string &s)
43 {
44     long int length, i;
45     length = s.size();
46     for (i = 0; i < length; i++)
47         s[i] = toupper(s[i]);
48 }
49 
50 //------------------------------------------------------------------------------------
51 
LowerCase(string & s)52 void LowerCase(string &s)
53 {
54     long int length, i;
55     length = s.size();
56     for (i = 0; i < length; i++)
57         s[i] = tolower(s[i]);
58 }
59 
60 //------------------------------------------------------------------------------------
61 //------------------------------------------------------------------------------------
62 
ToString(char character)63 string ToString(char character)
64 {
65     ostringstream ostr;
66     ostr << character;
67     string s(ostr.str());
68     return s;
69 }
70 
71 //------------------------------------------------------------------------------------
72 
ToString(int number)73 string ToString(int number)
74 {
75     ostringstream ostr;
76     ostr << number;
77     string s(ostr.str());
78     return s;
79 }
80 
81 //------------------------------------------------------------------------------------
82 
ToString(bool tag)83 string ToString(bool tag)
84 {
85     string s;
86     if(tag)
87         s="Yes";
88     else
89         s="No";
90     return s;
91 }
92 
93 //------------------------------------------------------------------------------------
94 
ToString(noval val)95 string ToString(noval val)
96 {
97     return "";
98 }
99 
100 //------------------------------------------------------------------------------------
101 
ToString(unsigned int number)102 string ToString(unsigned int number)
103 {
104     ostringstream ostr;
105     ostr << number;
106     string s(ostr.str());
107     return s;
108 }
109 
110 //------------------------------------------------------------------------------------
111 
ToString(unsigned long int number)112 string ToString(unsigned long int number)
113 {
114     ostringstream ostr;
115     ostr << number;
116     string s(ostr.str());
117     return s;
118 }
119 
120 //------------------------------------------------------------------------------------
121 
ToString(unsigned long long number)122 string ToString(unsigned long long number)
123 {
124     ostringstream ostr;
125     ostr << number;
126     string s(ostr.str());
127     return s;
128 }
129 
130 //------------------------------------------------------------------------------------
131 
ToString(long int number)132 string ToString(long int number)
133 {
134     ostringstream ostr;
135     ostr << number;
136     string s(ostr.str());
137     return s;
138 }
139 
140 //------------------------------------------------------------------------------------
141 
ToString(long long number)142 string ToString(long long number)
143 {
144     ostringstream ostr;
145     ostr << number;
146     string s(ostr.str());
147     return s;
148 }
149 
150 //------------------------------------------------------------------------------------
151 
ToString(double number)152 string ToString(double number)
153 {
154     if (numeric_limits<double>::has_infinity)
155     {
156         if (number == numeric_limits<double>::infinity())
157         {
158             return "inf";
159         }
160         if (number == -numeric_limits<double>::infinity())
161         {
162             return "-inf";
163         }
164     }
165     if (systemSpecificIsnan(number))
166     {
167         return "nan";
168     }
169     ostringstream ostr;
170     ostr << number;
171     string s(ostr.str());
172     return s;
173 }
174 
175 //------------------------------------------------------------------------------------
176 
ToDecimalString(double number)177 string ToDecimalString(double number)
178 {
179     ostringstream ostr;
180     ostr.setf(ios_base::fixed);
181     ostr << number;
182     string s(ostr.str());
183     return s;
184 }
185 
186 //------------------------------------------------------------------------------------
187 
ToString(force_type ftype)188 string ToString(force_type ftype)
189 {
190     switch(ftype)
191     {
192         case force_COAL:
193             return uistr::coalescence;
194             break;
195         case force_MIG:
196             return uistr::migration;
197             break;
198         case force_DIVMIG:
199             return uistr::divmigration;
200             break;
201         case force_DISEASE:
202             return uistr::disease;
203             break;
204         case force_REC:
205             return uistr::recombination;
206             break;
207         case force_GROW:
208             return uistr::growth;
209             break;
210         case force_REGION_GAMMA:
211             return uistr::regionGamma;
212             break;
213         case force_EXPGROWSTICK:
214             return uistr::expGrowStick;
215             break;
216         case force_LOGISTICSELECTION:
217             return uistr::logisticSelection;
218             break;
219         case force_LOGSELECTSTICK:
220             return uistr::logSelectStick;
221             break;
222         case force_DIVERGENCE:
223             return uistr::divergence;
224             break;
225         case force_NONE:
226             return "NO_force";
227             break;
228     }
229     assert(false);
230     return "";
231 }
232 
233 //------------------------------------------------------------------------------------
234 
ToShortString(force_type ftype)235 string ToShortString(force_type ftype)
236 {
237     switch(ftype)
238     {
239         case force_COAL:
240             return lamarcstrings::COAL;
241             break;
242         case force_MIG:
243             return lamarcstrings::MIG;
244             break;
245         case force_DIVMIG:
246             return lamarcstrings::DIVMIG;
247             break;
248         case force_DISEASE:
249             return lamarcstrings::DISEASE;
250             break;
251         case force_REC:
252             return lamarcstrings::REC;
253             break;
254         case force_GROW:
255             return lamarcstrings::GROW;
256             break;
257         case force_REGION_GAMMA:
258             //GAMMA DEBUG
259             assert(false);
260             throw implementation_error("The 'Gamma' force not fully supported.");
261             break;
262         case force_EXPGROWSTICK:
263             return lamarcstrings::EXPGROWSTICK;
264             break;
265         case force_LOGISTICSELECTION:
266             return lamarcstrings::LOGISTICSELECTION;
267             break;
268         case force_LOGSELECTSTICK:
269             return lamarcstrings::LOGSELECTSTICK;
270             break;
271         case force_DIVERGENCE:
272             return lamarcstrings::DIVERGENCE;
273             break;
274         case force_NONE:
275             return "NO_force";
276             break;
277     }
278     assert(false);
279     return "";
280 }
281 
282 //------------------------------------------------------------------------------------
283 
ToString(method_type method,bool getLongName)284 string ToString(method_type method, bool getLongName)
285 {
286     switch(method)
287     {
288         case method_FST:
289             if(getLongName) return lamarcstrings::longNameFST;
290             return lamarcstrings::shortNameFST;
291             break;
292         case method_PROGRAMDEFAULT:
293             if(getLongName) return lamarcstrings::longNamePROGRAMDEFAULT;
294             return lamarcstrings::shortNamePROGRAMDEFAULT;
295             break;
296         case method_USER:
297             if(getLongName) return lamarcstrings::longNameUSER;
298             return lamarcstrings::shortNameUSER;
299             break;
300         case method_WATTERSON:
301             if(getLongName) return lamarcstrings::longNameWATTERSON;
302             return lamarcstrings::shortNameWATTERSON;
303             break;
304     }
305     assert(false);
306     return lamarcstrings::longNameUSER;
307 }
308 
309 //------------------------------------------------------------------------------------
310 
ToString(growth_type gtype,bool getLongName)311 string ToString(growth_type gtype, bool getLongName )
312 {
313     switch(gtype)
314     {
315         case growth_CURVE:
316             if(getLongName) return lamarcstrings::longCurveName;
317             return lamarcstrings::shortCurveName;
318             break;
319         case growth_STICK:
320             if(getLongName) return lamarcstrings::longStickName;
321             return lamarcstrings::shortStickName;
322             break;
323         case growth_STICKEXP:
324             if(getLongName) return lamarcstrings::longStickExpName;
325             return lamarcstrings::shortStickExpName;
326             break;
327         default:
328             assert(false);
329             return "";
330             break;
331     }
332 }
333 
334 //------------------------------------------------------------------------------------
335 
ToString(growth_scheme gscheme,bool getLongName)336 string ToString(growth_scheme gscheme, bool getLongName )
337 {
338     switch(gscheme)
339     {
340         case growth_EXP:
341             if(getLongName) return lamarcstrings::longExpName;
342             return lamarcstrings::shortExpName;
343             break;
344         case growth_STAIRSTEP:
345             if(getLongName) return lamarcstrings::longStairStepName;
346             return lamarcstrings::shortStairStepName;
347             break;
348         default:
349             assert(false);
350             return "";
351             break;
352     }
353 }
354 
355 //------------------------------------------------------------------------------------
356 
ToString(model_type model,bool getLongName)357 string ToString(model_type model, bool getLongName )
358 {
359     switch(model)
360     {
361         case F84:
362             if(getLongName) return lamarcstrings::longF84Name;
363             return lamarcstrings::shortF84Name;
364             break;
365         case Brownian:
366             if(getLongName) return lamarcstrings::longBrownianName;
367             return lamarcstrings::shortBrownianName;
368             break;
369         case Stepwise:
370             if(getLongName) return lamarcstrings::longStepwiseName;
371             return lamarcstrings::shortStepwiseName;
372             break;
373         case KAllele:
374             if(getLongName) return lamarcstrings::longKAlleleName;
375             return lamarcstrings::shortKAlleleName;
376             break;
377         case GTR:
378             if(getLongName) return lamarcstrings::longGTRName;
379             return lamarcstrings::shortGTRName;
380             break;
381         case MixedKS:
382             if(getLongName) return lamarcstrings::longMixedKSName;
383             return lamarcstrings::shortMixedKSName;
384             break;
385         default:
386             assert(false);
387             return "";
388             break;
389     }
390 }
391 
ToString(paramlistcondition par)392 string ToString(paramlistcondition par)
393 {
394     switch (par)
395     {
396         case paramlist_YES: return "all "; break; // extra space for alignment
397         case paramlist_NO: return "none"; break;
398         case paramlist_MIX: return "some"; break;
399         default: assert(false); return ""; break;
400     }
401 }
402 
ToString(proftype prof)403 string ToString(proftype prof)
404 {
405     switch(prof)
406     {
407         case profile_PERCENTILE: return "percentile"; break;
408         case profile_FIX: return "fixed"; break;
409         case profile_NONE: return "none"; break;
410     }
411     assert(false);
412     return "";
413 }
414 
ToString(priortype ptype)415 string ToString(priortype ptype)
416 {
417     switch(ptype)
418     {
419         case LINEAR: return "linear"; break;
420         case LOGARITHMIC: return "log"; break;
421     }
422     assert(false);
423     return "";
424 }
425 
ToString(pstatus pstat)426 string ToString(pstatus pstat)
427 {
428     switch(pstat)
429     {
430         case pstat_unconstrained: return "unconstrained"; break;
431         case pstat_invalid: return "invalid"; break;
432         case pstat_constant: return "constant"; break;
433         case pstat_identical: return "identical"; break;
434         case pstat_identical_head: return "identical_head"; break;
435         case pstat_multiplicative: return "multiplicative"; break;
436         case pstat_multiplicative_head: return "multiplicative_head"; break;
437     }
438     assert(false);
439     return "";
440 }
441 
ToString(const ParamStatus & pstat)442 string ToString(const ParamStatus& pstat)
443 {
444     return ToString(pstat.Status());
445 }
446 
ToString(selection_type stype,bool getLongName)447 string ToString(selection_type stype, bool getLongName )
448 {
449     switch(stype)
450     {
451         case selection_DETERMINISTIC:
452             if(getLongName) return lamarcstrings::longDSelectionName;
453             return lamarcstrings::shortDSelectionName;
454             break;
455         case selection_STOCHASTIC:
456             if(getLongName) return lamarcstrings::longSSelectionName;
457             return lamarcstrings::shortSSelectionName;
458             break;
459     }
460     assert(false);
461     return "";
462 }
463 
464 // because we have some template code that might want this
ToString(string str)465 string ToString(string str)
466 {
467     return str;
468 }
469 
ToString(UIId id)470 string ToString(UIId id)
471 {
472     string toReturn = "";
473     if(id.HasForce())
474     {
475         force_type ft = id.GetForceType();
476         toReturn += ToString(ft);
477     }
478     if(id.HasIndex1())
479     {
480         toReturn += ":";
481         toReturn += ToString(id.GetIndex1());
482     }
483     if(id.HasIndex2())
484     {
485         toReturn += ":";
486         toReturn += ToString(id.GetIndex2());
487     }
488     if(id.HasIndex3())
489     {
490         toReturn += ":";
491         toReturn += ToString(id.GetIndex3());
492     }
493     return toReturn;
494 }
495 
ToString(verbosity_type verbosity)496 string ToString (verbosity_type verbosity)
497 {
498     switch (verbosity)
499     {
500         case CONCISE:
501             return string ("concise");
502             break;
503         case NORMAL:
504             return string ("normal");
505             break;
506         case NONE:
507             return string ("none");
508             break;
509         case VERBOSE:
510             return string("verbose");
511             break;
512         default:
513             throw implementation_error("Unknown verbosity type");
514             return string ("");
515             break;
516     }
517 }
518 
ToString(vector<method_type> meths)519 string ToString (vector<method_type> meths)
520 {
521     string methstring("");
522     vector<method_type>::iterator meth;
523     for (meth = meths.begin(); meth != meths.end(); ++meth)
524     {
525         methstring += " " + ToString(*meth,true);   // true => longer name
526     }
527     return methstring;
528 }
529 
ToString(vector<proftype> profs)530 string ToString (vector<proftype> profs)
531 {
532     string profstring("");
533     vector<proftype>::iterator prof;
534     for (prof = profs.begin(); prof != profs.end(); ++prof)
535     {
536         profstring += ToString(*prof) + " ";
537     }
538     return profstring;
539 }
540 
ToString(vector<ParamStatus> pstats)541 string ToString (vector<ParamStatus> pstats)
542 {
543     string pstatstring("");
544     vector<ParamStatus>::iterator pstat;
545     for (pstat = pstats.begin(); pstat != pstats.end(); ++pstat)
546     {
547         pstatstring += ToString((*pstat).Status()) + " ";
548     }
549     return pstatstring;
550 }
551 
ToString(ParamVector & pvec)552 string ToString (ParamVector & pvec)
553 {
554     throw implementation_error("No ToString(ParamVector&) exists");
555     return "";
556 }
557 
ToString(vector<UIId> ids)558 string ToString (vector<UIId> ids)
559 {
560     string idstring("");
561     vector<UIId>::iterator iditer;
562     for (iditer = ids.begin(); iditer != ids.end(); ++iditer)
563     {
564         idstring += " " + ToString(*iditer);
565     }
566     return idstring;
567 }
568 
ToString(vector<vector<UIId>> ids)569 string ToString (vector<vector<UIId> > ids)
570 {
571     string idstring("");
572     vector<vector<UIId> >::iterator iditer;
573     for (iditer = ids.begin(); iditer != ids.end(); ++iditer)
574     {
575         idstring += ", " + ToString(*iditer);
576     }
577     return idstring;
578 }
579 
ToStringTF(bool tag)580 string ToStringTF(bool tag)
581 {
582     string s;
583     if(tag)
584         s="true";
585     else
586         s="false";
587     return s;
588 }
589 
590 //------------------------------------------------------------------------------------
591 
CaselessStrCmp(const string & lhs,const string & rhs)592 bool CaselessStrCmp(const string& lhs, const string& rhs)
593 {
594 
595     if (lhs.size() != rhs.size()) return false;
596 
597     size_t i;
598     for (i = 0; i < lhs.size(); ++i)
599     {
600         if (toupper(lhs[i]) != toupper(rhs[i])) return false;
601     }
602     return true;
603 
604 } // CaselessStrCmp
605 
606 // char* overloads of the preceeding
607 
CaselessStrCmp(const string & lhs,const char * rhs)608 bool CaselessStrCmp(const string& lhs, const char* rhs)
609 {
610     return CaselessStrCmp(lhs, string(rhs));
611 } // CaselessStrCmp
612 
CaselessStrCmp(const char * lhs,const string & rhs)613 bool CaselessStrCmp(const char* lhs, const string& rhs)
614 {
615     return CaselessStrCmp(string(lhs), rhs);
616 } // CaselessStrCmp
617 
CaselessStrCmp(const char * lhs,const char * rhs)618 bool CaselessStrCmp(const char* lhs, const char* rhs)
619 {
620     return CaselessStrCmp(string(lhs), string(rhs));
621 } // CaselessStrCmp
622 
623 //------------------------------------------------------------------------------------
624 
625 // case insensitive string comparison taken from Scott Meyers'
626 // _Effective STL_ items 19 and 35.
627 
ciCharCompare(char c1,char c2)628 long int ciCharCompare(char c1, char c2)
629 {
630     long int lc1 = toupper(static_cast<unsigned char>(c1));
631     long int lc2 = toupper(static_cast<unsigned char>(c2));
632     if (lc1 < lc2) return -1;
633     if (lc1 > lc2) return 1;
634     return 0;
635 } // ciCharCompare
636 
ciStringCompareImpl(const string & s1,const string & s2)637 long int ciStringCompareImpl(const string& s1, const string& s2)
638 {
639     typedef pair<string::const_iterator, string::const_iterator> PSCI;
640 
641     PSCI p = mismatch(s1.begin(),s1.end(), s2.begin(),
642                       not2(ptr_fun(ciCharCompare)));
643     if (p.first == s1.end())
644     {
645         if (p.second == s2.end()) return 0;
646         else return -1;
647     }
648     return ciCharCompare(*p.first, *p.second);
649 
650 } // ciStringCompareImpl
651 
ciStringCompare(const string & s1,const string & s2)652 long int ciStringCompare(const string& s1, const string& s2)
653 {
654     if (s1.size() <= s2.size()) return ciStringCompareImpl(s1,s2);
655     else return -ciStringCompareImpl(s2,s1);
656 } // ciStringCompare
657 
ciCharLess(char c1,char c2)658 bool ciCharLess(char c1, char c2)
659 {
660     return
661         toupper(static_cast<unsigned char>(c1)) <
662         toupper(static_cast<unsigned char>(c2));
663 } // ciCharLess
664 
ciStringLess(const string & s1,const string & s2)665 bool ciStringLess(const string& s1, const string& s2)
666 {
667     return lexicographical_compare(s1.begin(), s1.end(),
668                                    s2.begin(), s2.end(),
669                                    ciCharLess);
670 } // ciStringLess
671 
ciStringEqual(const string & s1,const string & s2)672 bool ciStringEqual(const string& s1, const string& s2)
673 {
674     return !ciStringCompare(s1, s2);
675 } // ciStringEqual
676 
677 //------------------------------------------------------------------------------------
678 
679 // careful: was not able to link this function
680 // when its name was DoubleVecFromString(..)
FromString(const string & in,DoubleVec1d & out)681 bool FromString(const string & in, DoubleVec1d & out)
682 {
683     if (in.empty()) return false;
684 
685     string whitespace(" \t"), input = in;
686     while (!input.empty())
687     {
688         double value;
689         string::size_type start = input.find_first_not_of(whitespace);
690         if (start == string::npos) break;
691 
692         string::size_type end = input.find_first_of(whitespace,start);
693         if (end != string::npos)
694         {
695             FromString(input.substr(start,end-start),value);
696             input = input.substr(end,input.size()-end);
697         }
698         else
699         {
700             FromString(input,value);
701             input.erase();
702         }
703 
704         out.push_back(value);
705     }
706 
707     return true;
708 }
709 
FromString(const string & input,ProftypeVec1d & out)710 bool FromString(const string& input, ProftypeVec1d & out)
711 {
712     StringVec1d vectorize;
713     bool parsed = FromString(input,vectorize);
714     if(parsed)
715     {
716         StringVec1d::iterator i;
717         for(i=vectorize.begin(); i != vectorize.end(); i++)
718         {
719             out.push_back(ProduceProftypeOrBarf(*i));
720         }
721     }
722     return false;
723 }
724 
FromString(const string & in,MethodTypeVec1d & out)725 bool FromString(const string & in, MethodTypeVec1d & out)
726 {
727     if (in.empty()) return false;
728 
729     string whitespace(" \t"), input = in;
730     while (!input.empty())
731     {
732         method_type value;
733         string::size_type start = input.find_first_not_of(whitespace);
734         if (start == string::npos) break;
735 
736         string::size_type end = input.find_first_of(whitespace,start);
737         if (end != string::npos)
738         {
739             FromString(input.substr(start,end-start),value);
740             input = input.substr(end,input.size()-end);
741         }
742         else
743         {
744             FromString(input,value);
745             input.erase();
746         }
747 
748         out.push_back(value);
749     }
750 
751     return true;
752 }
753 
FromString(const string & in,ParamVector & out)754 bool FromString(const string & in, ParamVector & out)
755 {
756     throw implementation_error("FromString should never be called for ParamVector");
757     return false;
758 }
759 
FromString(const string & in,StringVec1d & out)760 bool FromString(const string & in, StringVec1d & out)
761 {
762     if (in.empty()) return false;
763 
764     string whitespace(" \t"), input = in;
765     while (!input.empty())
766     {
767 
768         string::size_type start = input.find_first_not_of(whitespace);
769         if (start == string::npos) break;
770 
771         string::size_type end = input.find_first_of(whitespace,start);
772         if (end != string::npos)
773         {
774             string thisTerm = input.substr(start,end-start);
775             out.push_back(thisTerm);
776             input = input.substr(end,input.size()-end);
777         }
778         else
779         {
780             string thisTerm = input.substr(start,input.size()-start);
781             out.push_back(thisTerm);
782             input.erase();
783         }
784 
785     }
786 
787     return true;
788 }
789 
FromString(const string & in,LongVec1d & out)790 bool FromString(const string & in, LongVec1d & out)
791 {
792     if (in.empty()) return false;
793 
794     string whitespace(" \t"), input = in;
795     while (!input.empty())
796     {
797         long int value;
798         string::size_type start = input.find_first_not_of(whitespace);
799         if (start == string::npos) break;
800 
801         string::size_type end = input.find_first_of(whitespace,start);
802         if (end != string::npos)
803         {
804             FromString(input.substr(start,end-start),value);
805             input = input.substr(end,input.size()-end);
806         }
807         else
808         {
809             FromString(input,value);
810             input.erase();
811         }
812 
813         out.push_back(value);
814     }
815 
816     return true;
817 
818 }
819 
FromString(const string & in,long int & out)820 bool FromString(const string & in, long int & out)
821 {
822     if(in.empty())
823         return false;
824     else
825     {
826         istringstream mystream(in);
827         mystream >> out;
828     }
829     return true;
830 }
831 
FromString(const string & in,double & out)832 bool FromString(const string & in, double& out)
833 {
834     if(in.empty())
835         return false;
836     else
837     {
838         istringstream mystream(in);
839         mystream >> out;
840     }
841     return true;
842 }
843 
FromString(const string & in,method_type & out)844 bool FromString(const string & in, method_type& out)
845 {
846     try
847     {
848         out = ProduceMethodTypeOrBarf(in);
849     }
850     catch(const data_error& e)
851     {
852         return false;
853     }
854     return true;
855 }
856 
857 //------------------------------------------------------------------------------------
858 
StringToDoubleVecOrBarf(const string & in)859 DoubleVec1d StringToDoubleVecOrBarf(const string & in)
860 {
861     DoubleVec1d out;
862     if (in.empty()) return out;
863 
864     string whitespace(" \t"), input = in;
865     while (!input.empty())
866     {
867         double value;
868         string::size_type start = input.find_first_not_of(whitespace);
869         if (start == string::npos) break;
870 
871         string::size_type end = input.find_first_of(whitespace,start);
872         if (end != string::npos)
873         {
874             value = ProduceDoubleOrBarf(input.substr(start,end-start));
875             input = input.substr(end,input.size()-end);
876         }
877         else
878         {
879             value = ProduceDoubleOrBarf(input);
880             input.erase();
881         }
882 
883         out.push_back(value);
884     }
885 
886     return out;
887 }
888 
889 //------------------------------------------------------------------------------------
890 //------------------------------------------------------------------------------------
891 
MakeTag(const string & tagname)892 string MakeTag(const string& tagname)
893 {
894     return (string("<") + tagname + string(">"));
895 } // MakeTag
896 
897 //------------------------------------------------------------------------------------
898 
MakeCloseTag(const string & tagname)899 string MakeCloseTag(const string& tagname)
900 {
901     if (tagname[0] == '<') // we're already some form of xml tag
902         if (tagname[1] == '/') // we're already a "closing" tag
903             return tagname;
904         else
905         {
906             string nutag(tagname);
907             return nutag.insert(1L,"/");
908         }
909     else
910         return (string("</") + tagname + string(">"));
911 } // MakeCloseTag
912 
913 //------------------------------------------------------------------------------------
914 
MakeTagWithName(const string & tag,const string & name)915 string MakeTagWithName(const string& tag, const string& name)
916 {
917     //Replace quote marks with '&quot;'
918     string safename = name;
919     string::size_type quotpos = safename.find("\"");
920     while (quotpos != string::npos)
921     {
922         safename.replace(quotpos, 1, "&quot;");
923         quotpos = safename.find("\"");
924     }
925     return MakeTag(tag + " " + xmlstr::XML_ATTRTYPE_NAME + "=" + "\"" + safename + "\"");
926 } // MakeTagWithName
927 
928 //------------------------------------------------------------------------------------
929 
MakeTagWithType(const string & tag,const string & type)930 string MakeTagWithType(const string& tag, const string& type)
931 {
932     return MakeTag(tag + " " + xmlstr::XML_ATTRTYPE_TYPE + "=" + "\"" + type + "\"");
933 } // MakeTagWithType
934 
935 //------------------------------------------------------------------------------------
936 
MakeTagWithTypePlusPanel(const string & tag,const string & type)937 string MakeTagWithTypePlusPanel(const string& tag, const string& type)
938 {
939     return MakeTag(tag + " " + xmlstr::XML_ATTRTYPE_TYPE + "=" + "\"" + type + "\""+" source=\"panel\"");
940 } // MakeTagWithTypePlusPanel
941 
942 //------------------------------------------------------------------------------------
943 
MakeTagWithConstraint(const string & tag,const string & constraint)944 string MakeTagWithConstraint(const string& tag, const string& constraint)
945 {
946     return MakeTag(tag + " " + xmlstr::XML_ATTRTYPE_CONSTRAINT + "=" + "\"" + constraint + "\"");
947 } // MakeTagWithType
948 
949 //------------------------------------------------------------------------------------
950 // MakeJustified will fill out a string with spaces to a width of |width|.
951 //  Positive values of width are used to make strings right-justified,
952 //  and negative values are used to make strings left-justified.
MakeJustified(const string & instr,long int width)953 string MakeJustified(const string &instr, long int width)
954 {
955     string stuff = instr;
956     string::size_type tabpos = stuff.find("\t");
957     while (tabpos != string::npos)
958     {
959         stuff.replace(tabpos,1,"    ");
960         tabpos = stuff.find("\t");
961     }
962     long int xtraspc = static_cast<long int>(abs(width)) - stuff.size();
963 
964     if (xtraspc <= 0)
965         return(stuff.substr(0,abs(width)));
966 
967     string str;
968     if (width < 0)
969     {
970         str = stuff + str.assign(xtraspc,' ');
971     }
972     else
973     {
974         str = str.assign(xtraspc,' ') + stuff;
975     }
976 
977     return(str);
978 
979 } // MakeJustified
980 
981 //------------------------------------------------------------------------------------
982 
MakeJustified(const char * stuff,long int width)983 string MakeJustified(const char *stuff, long int width)
984 {
985     string str(stuff);
986 
987     return(MakeJustified(str,width));
988 
989 } // MakeJustified
990 
991 //------------------------------------------------------------------------------------
992 // MakeCentered used to push stuff to the right, but now it pushes stuff
993 //  off to the left instead.
994 
MakeCentered(const string & instr,long int width,long int indent,bool trunc)995 string MakeCentered(const string &instr, long int width, long int indent, bool trunc)
996 {
997     string str = instr;
998     string::size_type tabpos = str.find("\t");
999     while (tabpos != string::npos)
1000     {
1001         str.replace(tabpos,1,"    ");
1002         tabpos = str.find("\t");
1003     }
1004 
1005     string line;
1006     long int strsize = str.size(), numchar = 0, truewidth = width-indent;
1007     long int halfsize = strsize/2;
1008 
1009     if (trunc && (strsize > truewidth))
1010     {
1011         line.assign(indent,' ');
1012         numchar += indent;
1013         if (width - indent >= 0)
1014         {
1015             line.append(str.substr(0,truewidth));
1016             numchar += (str.substr(0,truewidth)).size();
1017         }
1018         return(line);
1019     }
1020 
1021     char lastchar = str[strsize-1];
1022     if (halfsize < truewidth/2 && static_cast<long int>(lastchar) != LINEFEED)
1023     {
1024         line.assign(truewidth/2-halfsize,' ');
1025     }
1026     numchar += truewidth/2-halfsize;
1027 
1028     line.insert(0,str);
1029     numchar += strsize;
1030 
1031     string indstr;
1032     indstr.assign(width-numchar, ' ');
1033     line.insert(0, indstr);
1034 
1035     indstr.assign(indent,' ');
1036     line.insert(0, indstr);
1037     numchar += indent;
1038 
1039     return(line);
1040 } // MakeCentered
1041 
1042 //------------------------------------------------------------------------------------
1043 
MakeCentered(const char * str,long int width,long int indent,bool trunc)1044 string MakeCentered(const char *str, long int width, long int indent, bool trunc)
1045 {
1046     const string pstr(str);
1047 
1048     return (MakeCentered(pstr,width,indent,trunc));
1049 } // MakeCentered
1050 
1051 //------------------------------------------------------------------------------------
1052 
MakeIndent(const string & str,unsigned long int indent)1053 string MakeIndent(const string& str, unsigned long int indent)
1054 {
1055     string line;
1056     line.assign(indent,' ');
1057     line += str;
1058 
1059     return line;
1060 
1061 } // MakeIndent
1062 
1063 //------------------------------------------------------------------------------------
1064 
MakeIndent(const char * str,unsigned long int indent)1065 string MakeIndent(const char* str, unsigned long int indent)
1066 {
1067     const string pstr(str);
1068 
1069     return (MakeIndent(pstr,indent));
1070 
1071 } // MakeIndent
1072 
1073 //------------------------------------------------------------------------------------
1074 //------------------------------------------------------------------------------------
1075 
1076 /******************************************
1077  * function to format a double-precision  *
1078  * number into a fixed-width field, going *
1079  * to scientific notation as necessary.   *
1080  * The width must be greater than 5.  If  *
1081  * the number is greater than e+99 the    *
1082  * returned string may be longer than     *
1083  * the given field width.  Also, if the   *
1084  * number is negative, it will always be  *
1085  * one character greater than the given   *
1086  * width.                                 *
1087  ******************************************/
1088 
Pretty(double p,int w)1089 string Pretty(double p, int w)
1090 {
1091     ostringstream ost;
1092     if (w < 6)
1093     {
1094         ost << "*";
1095         return(string(ost.str()));
1096     }
1097     ost.width(w);
1098     ost.setf(ios::showpoint);
1099 
1100     if (fabs(p) >= 1.0 || p == 0.0)     //greater than one, or zero
1101     {
1102         ost.setf(ios::fixed);
1103         ost.setf(ios::scientific);
1104         if (fabs(p) >= pow(10.0,w)) ost.precision(w-5);
1105         else if (fabs(p) >= pow(10.0,w-1))
1106         {
1107             /* The following would print numbers exactly the width we want with no
1108                decimal point.  Uncomment this and comment the next line if you want
1109                to change this behavior. */
1110             //ost.unsetf(ios::showpoint);
1111             //ost.precision(0);
1112             ost.precision(w-5);
1113         }
1114         else ost.precision(w-1);
1115     }
1116     else
1117     {              //less than one
1118         if (fabs(p) <= pow(0.1,w-4))
1119         {
1120             ost.setf(ios::scientific);
1121             ost.unsetf(ios::fixed);
1122             ost.precision(w-6);
1123         }
1124         else
1125         {
1126             ost.setf(ios::fixed);
1127             ost.unsetf(ios::scientific);
1128             ost.precision(w-2);
1129         }
1130     }
1131     ost << p;
1132     return(string(ost.str()));
1133 } // Pretty(double)
1134 
1135 //  Overload of Pretty for long int (much simpler!)
1136 
Pretty(long int p,int w)1137 string Pretty(long int p, int w)
1138 {
1139     ostringstream ost;
1140     ost.width(w);
1141     ost << p;
1142     return(string(ost.str()));
1143 } // Pretty(long int)
1144 
Pretty(unsigned long int p,int w)1145 string Pretty(unsigned long int p, int w)
1146 {
1147     ostringstream ost;
1148     ost.width(w);
1149     ost << p;
1150     return(string(ost.str()));
1151 } // Pretty(unsigned long int)
1152 
1153 //  Overload of Pretty for string (much simpler!)
1154 
Pretty(string str,int w)1155 string Pretty(string str, int w)
1156 {
1157     if ((long int)str.size() == w) return(str);
1158     if ((long int)str.size() > w) return(str.substr(0,w));
1159 
1160 #if 0 // WARNING warning -- doesn't do padding anymore
1161     long int i;
1162     for (i = (long int)str.size(); i < w; ++i)
1163     {
1164         str += " ";
1165     }
1166 #endif
1167 
1168     return(str);
1169 } // Pretty(string)
1170 
1171 //------------------------------------------------------------------------------------
1172 //------------------------------------------------------------------------------------
1173 
StringCompare(const string & s1,const char * s2,long int pos,long int n)1174 bool StringCompare(const string &s1, const char *s2, long int pos, long int n)
1175 {
1176     string temp = s1.substr(pos, n);
1177     return (temp == s2);
1178 }
1179 
1180 //------------------------------------------------------------------------------------
1181 
StringCompare(const string & s1,const string & s2,long int pos,long int n)1182 bool StringCompare(const string &s1, const string &s2, long int pos, long int n)
1183 {
1184     string temp = s1.substr(pos, n);
1185     return (temp == s2);
1186 }
1187 
1188 //------------------------------------------------------------------------------------
1189 
CompareWOCase(const string & s1,const string & s2)1190 bool CompareWOCase(const string& s1, const string& s2)
1191 {
1192     string str1, str2(s2);
1193 
1194     //transform(s1.begin(),s1.end(),str1.begin(),tolower);
1195     //transform(s2.begin(),s2.end(),str2.begin(),tolower);
1196     // To conform to gcc3.1's C++ standard we do:
1197     transform(s1.begin(),s1.end(),str1.begin(),
1198               static_cast<int(*)(int)>(tolower));
1199     transform(s2.begin(),s2.end(),str2.begin(),
1200               static_cast<int(*)(int)>(tolower));
1201 
1202     return (str1 == str2);
1203 } // CompareWOCase(string,string)
1204 
1205 //------------------------------------------------------------------------------------
1206 
CompareWOCase(const char * s1,const string & s2)1207 bool CompareWOCase(const char* s1, const string& s2)
1208 {
1209     return CompareWOCase(string(s1),s2);
1210 } // CompareWOCase(char*,string)
1211 
1212 //------------------------------------------------------------------------------------
1213 
CompareWOCase(const string & s1,const char * s2)1214 bool CompareWOCase(const string& s1, const char* s2)
1215 {
1216     return CompareWOCase(s1,string(s2));
1217 } // CompareWOCase(string,char*)
1218 
1219 //------------------------------------------------------------------------------------
1220 
CompareWOCase(const char * s1,const char * s2)1221 bool CompareWOCase(const char* s1, const char* s2)
1222 {
1223     return CompareWOCase(string(s1),string(s2));
1224 } // CompareWOCase(char*,char*)
1225 
1226 //------------------------------------------------------------------------------------
1227 //------------------------------------------------------------------------------------
1228 
StringType(const string & s)1229 int StringType(const string &s)
1230 {
1231     long int i = 0;
1232     while(isspace(s[i]))
1233         i++;
1234 
1235     // Alpha type _______________________________________________
1236 
1237     if (isalpha(s[i]))
1238         return 1;                                  // Alpha type
1239 
1240     if (s[i] == '_')
1241     {
1242         i++;
1243         while (s[i] == ' ')
1244             i++;
1245 
1246         if (isalnum(s[i]))
1247             return 1;                                // Alphanumeric type
1248 
1249         return 3;                                  // Punctuation type
1250     }
1251 
1252     // Numeric type _____________________________________________
1253 
1254     if (isdigit(s[i]))
1255         return 2;                                  // Numeric type
1256 
1257     if (s[i] == '.')
1258     {
1259         i++;
1260         if (isdigit(s[i]))
1261             return 2;                                // Numeric type
1262 
1263         return 3;                                  // Punctuation
1264     }
1265 
1266     if (s[i] == '-' || s[i] == '+')
1267     {
1268         i++;
1269         if (isdigit(s[i]))
1270             return 2;                                // Numeric type
1271 
1272         if (s[i] == '.')
1273         {
1274             i++;
1275             if (isdigit(s[i]))
1276                 return 2;                              // Numeric type
1277         }
1278     }
1279 
1280     return 3;                                    // Punctuation
1281 }
1282 
1283 //------------------------------------------------------------------------------------
1284 //------------------------------------------------------------------------------------
1285 
GetCharacter(const string & s,char & ch,long int posn)1286 string::size_type GetCharacter(const string &s, char &ch, long int posn)
1287 {
1288     long int len = s.size();
1289     if (posn < 0 || len <= posn)
1290         return string::npos;
1291 
1292     while(isspace(s[posn]))
1293         posn++;
1294 
1295     ch = s[posn];
1296     posn++;
1297 
1298     return posn;
1299 }
1300 
1301 //------------------------------------------------------------------------------------
1302 
1303 /**********************************************************************
1304  Linewrap wraps a table (contained in a vector of strings) so that
1305  it is no longer than the given linelength.  It uses the following
1306  rules:
1307  (1) Break at a column in which all entries have spaces or nothing.
1308  (2) Lines which consist only of dash and space may be broken anywhere.
1309  (3) If no acceptable break can be found, the original vector will be
1310  returned.
1311 
1312  It uses the function IsSeparator(const string) as a helper function.
1313 ***********************************************************************/
1314 
Linewrap(vector<string> invec,long int linelength)1315 vector<string> Linewrap(vector<string> invec, long int linelength)
1316 {
1317 
1318     // find a suitable location to wrap
1319     string::size_type site, line;
1320     string::size_type oldsize = invec.size();
1321     bool found = false;
1322     string::size_type breakpoint = string::npos;
1323 
1324     for (line = 0; line < oldsize; ++line)
1325     {
1326         if (static_cast<long int>(invec[line].size()) > linelength)
1327         {
1328             found = true;
1329         }
1330     }
1331     if (!found) return(invec);          // didn't need wrapping at all
1332 
1333     for (site = linelength; true; site--)
1334     {
1335         found = true;
1336         for (line = 0; line < oldsize; line++)
1337         {
1338             if (static_cast<string::size_type>(invec[line].size()) <= site)
1339             {
1340                 continue; // skip short lines
1341             }
1342             if (IsSeparator(invec[line])) continue;         // skip separators
1343             if (invec[line][site] != ' ')
1344             {
1345                 found = false;
1346                 break;
1347             }
1348         }
1349         if (found)
1350         {
1351             breakpoint = site;
1352             break;
1353         }
1354 
1355         // since we're counting down using an unsigned index,
1356         // we need to make sure we stop.
1357         // WARNING -- you probably don't want to add any code
1358         // after this statement in this for loop
1359         if (site == 0) break;
1360     }
1361 
1362     if (breakpoint == string::npos)    // never found a breakpoint
1363         breakpoint = static_cast<string::size_type>(linelength);
1364     // Give up and break at the line length anyway.
1365 
1366     // cut each line at that location
1367     vector<string> firstpart;
1368     vector<string> secondpart;
1369     for (line = 0; line < oldsize; ++line)
1370     {
1371         if (static_cast<string::size_type>(invec[line].size()) <= breakpoint)
1372         {
1373             // line does not need cutting
1374             firstpart.push_back(invec[line]);
1375             secondpart.push_back(string(""));
1376         }
1377         else
1378         {                            // line does need cutting
1379             firstpart.push_back(invec[line].substr(0, breakpoint));
1380             secondpart.push_back(invec[line].substr(breakpoint+1,
1381                                                     invec[line].size() - breakpoint));
1382         }
1383     }
1384 
1385     //wrap the second part recursively, in case it's very long
1386     secondpart = Linewrap(secondpart, linelength);
1387 
1388     //catenate first and second parts
1389     for (line = 0; line < static_cast<string::size_type>(secondpart.size()); ++line)
1390     {
1391         firstpart.push_back(secondpart[line]);
1392     }
1393 
1394     return(firstpart);
1395 
1396 } // Linewrap
1397 
Linewrap(string instring,long int linelength,long int indent)1398 vector<string> Linewrap(string instring, long int linelength, long int indent)
1399 {
1400     StringVec1d returnVec;
1401     StringVec1d firstLine;
1402     firstLine.push_back(instring);
1403     firstLine = Linewrap(firstLine, linelength);
1404     if (firstLine.size() == 1)
1405     {
1406         return firstLine;
1407     }
1408     returnVec.push_back(firstLine[0]);
1409     instring.erase(0,firstLine[0].size());
1410     while (instring.find(" ") == 0)
1411     {
1412         instring.erase(0,1);
1413     }
1414     StringVec1d otherLines;
1415     otherLines.push_back(instring);
1416     otherLines = Linewrap(otherLines, linelength - indent);
1417     for (unsigned long int i = 0; i<otherLines.size(); i++)
1418     {
1419         returnVec.push_back(MakeJustified("",indent) + otherLines[i]);
1420     }
1421     return returnVec;
1422 }
1423 
1424 //LinewrapCopy takes a vector of strings, cuts out the beginning of each
1425 // according to the repeat_length, calls Linewrap on the rest, then prepends
1426 // the cut-out bit back to the beginning of each set of strings.
1427 //
1428 // The vector of strings returned therefore has the dimensionality of n times
1429 // the dimensionality of the original vector, where n is how many times it had
1430 // to be wrapped.
1431 //
1432 // If you want a blank line between wrapped lines, include one at the bottom
1433 // of the original vector of strings.
1434 
LinewrapCopy(vector<string> original,long int repeat_length,long int total_length)1435 vector<string> LinewrapCopy(vector<string> original, long int repeat_length, long int total_length)
1436 {
1437     assert (total_length > repeat_length);
1438 
1439     vector<string> repeated;
1440     vector<string> wrapped;
1441 
1442     for (unsigned long int iter = 0; iter < original.size(); iter++)
1443     {
1444         string begin;
1445         begin.assign(original[iter], 0, repeat_length);
1446         repeated.push_back(begin);
1447 
1448         string end("");
1449         if (static_cast<long int>(original[iter].size()) > repeat_length)
1450         {
1451             end.assign(original[iter], repeat_length, original[iter].size());
1452         }
1453         wrapped.push_back(end);
1454     }
1455     wrapped = Linewrap(wrapped, (total_length - repeat_length));
1456 
1457     for (unsigned long int wrap_iter = 0, repeat_iter = 0; wrap_iter < wrapped.size(); wrap_iter++, repeat_iter++)
1458     {
1459         if (repeat_iter >= repeated.size())
1460             repeat_iter = repeat_iter - repeated.size();
1461         wrapped[wrap_iter].insert(0, repeated[repeat_iter]);
1462     }
1463     return wrapped;
1464 } // LinewrapCopy
1465 
1466 //------------------------------------------------------------------------------------
1467 // Is a string composed solely of dash, underscore and/or space?
IsSeparator(const string s)1468 bool IsSeparator(const string s)
1469 {
1470     long int i;
1471     for (i = 0; i < (long int)s.size(); ++i)
1472     {
1473         if (s[i] != ' ' && s[i] != '-' && s[i] != '_') return (false);
1474     }
1475     return(true);
1476 } // IsSeparator
1477 
1478 //------------------------------------------------------------------------------------
1479 
ProduceBoolOrBarf(const string & src)1480 bool ProduceBoolOrBarf(const string& src)
1481 {
1482     string st = src;
1483     LowerCase(st);
1484     if (st == "true" || st == "yes" || st == "on" )
1485     {
1486         return true;
1487     }
1488     if (st == "false" || st == "no"|| st == "off" )
1489     {
1490         return false;
1491     }
1492 
1493     invalid_argument e("Invalid argument to ProduceBoolOrBarf:"+src);
1494     throw e;
1495 } // ProduceBoolOrBarf
1496 
1497 //------------------------------------------------------------------------------------
1498 
IsInteger(const string & src)1499 bool IsInteger(const string& src)
1500 {
1501     if (src.empty()) return false;
1502 
1503     long int i;
1504     long int end = src.size();
1505     bool minusfound = false;
1506     for (i = 0; i < end; ++i)
1507     {
1508         if (isspace(src[i])) continue;  // whitespace is okay
1509         if (src[i] == '-')
1510         {
1511             if (minusfound) return false;
1512             else
1513             {
1514                 minusfound = true;
1515                 continue;
1516             }
1517         }
1518         if (!isdigit(src[i])) return false;
1519     }
1520     return true;
1521 } // IsInteger
1522 
1523 //------------------------------------------------------------------------------------
1524 
IsReal(const string & src)1525 bool IsReal(const string& src)
1526 {
1527     if (src.empty()) return false;
1528 
1529     long int i;
1530     long int end = src.size();
1531     bool pointfound = false;
1532     for (i = 0; i < end; ++i)
1533     {
1534         if (!isdigit(src[i]))
1535         {
1536             if (isspace(src[i])) continue; // whitespace is okay
1537             if (src[i] == '-') continue; // minus is okay
1538             if (src[i] == '+') continue; // plus is okay
1539             if (src[i] == 'e') continue; // e is okay
1540             if (src[i] != '.') return false;  // neither digit nor point
1541             if (pointfound) return false;   // a second decimal point?!
1542             pointfound = true;              // okay, first decimal point
1543         }
1544     }
1545     return true;
1546 } // IsReal
1547 
1548 //------------------------------------------------------------------------------------
1549 
ProduceLongOrBarf(const string & in)1550 long int ProduceLongOrBarf(const string& in)
1551 {
1552     //  if (in == "") return 0;
1553     long int myLong;
1554     myLong = atol(in.c_str());
1555     if (! IsInteger(in))
1556     {
1557         //Don't assert here--the menu will catch it.
1558         throw data_error("Expected an integer, but got \""+in+"\"");
1559     }
1560     if (myLong == LONG_MAX)
1561     {
1562         throw data_error("The value \""+in+"\" is greater than LONG_MAX (" + Pretty(LONG_MAX) + ").");
1563     }
1564     if (myLong == LONG_MIN)
1565     {
1566         throw data_error("The value \""+in+"\" is greater than LONG_MIN (" + Pretty(LONG_MIN) + ").");
1567     }
1568 
1569     return myLong;
1570 } // ProduceLongOrBarf
1571 
1572 //------------------------------------------------------------------------------------
1573 
ProduceDoubleOrBarf(const string & in)1574 double ProduceDoubleOrBarf(const string& in)
1575 {
1576     double myDouble;
1577     myDouble = atof(in.c_str());
1578     if (! IsReal(in))
1579     {
1580         if (in == "inf")
1581         {
1582             if (numeric_limits<double>::has_infinity)
1583             {
1584                 return numeric_limits<double>::infinity();
1585             }
1586             else
1587             {
1588                 return DBL_BIG;
1589             }
1590         }
1591         if (in == "-inf")
1592         {
1593             if (numeric_limits<double>::has_infinity)
1594             {
1595                 return -numeric_limits<double>::infinity();
1596             }
1597             else
1598             {
1599                 return -DBL_BIG;
1600             }
1601         }
1602         if (in == "nan")
1603         {
1604             if (numeric_limits<double>::has_quiet_NaN)
1605             {
1606                 return numeric_limits<double>::quiet_NaN();
1607             }
1608             else
1609             {
1610                 return 0.0;
1611             }
1612         }
1613         data_error e("Expected a real number, but got \""+in+"\"");
1614         throw e;
1615     }
1616     if (myDouble == DBL_MAX)
1617     {
1618         data_error e("The value \""+in+"\" is greater than DBL_MAX ("+Pretty(DBL_MAX) + ").");
1619         throw e;
1620     }
1621     if (myDouble == NEGMAX)
1622     {
1623         data_error e("The value \""+in+"\" is less than NEGMAX  (" + Pretty(NEGMAX) + ").");
1624         throw e;
1625     }
1626     return myDouble;
1627 } // ProduceDoubleOrBarf
1628 
1629 //------------------------------------------------------------------------------------
1630 
ProduceVerbosityTypeOrBarf(const string & s)1631 verbosity_type ProduceVerbosityTypeOrBarf(const string& s)
1632 {
1633     string st = s;
1634     LowerCase(st);
1635     if (st == "concise") { return CONCISE; };
1636     if (st == "normal") { return NORMAL; };
1637     if (st == "verbose") { return VERBOSE; };
1638     if (st == "none") { return NONE; };
1639     data_error e("Illegal verbosity setting \""+s+"\"");
1640     throw e;
1641     return NONE;
1642 }
1643 
1644 //------------------------------------------------------------------------------------
1645 
StringMatchesGrowthType(const string & input,growth_type type)1646 bool StringMatchesGrowthType(const string& input, growth_type type)
1647 {
1648     string lowerCaseInput = input;
1649     LowerCase(lowerCaseInput);
1650 
1651     string lowerCaseGrowthType = ToString(type,false);
1652     LowerCase(lowerCaseGrowthType);
1653 
1654     if(lowerCaseGrowthType == lowerCaseInput)
1655     {
1656         return true;
1657     }
1658     else
1659     {
1660         lowerCaseGrowthType = ToString(type,true);
1661         LowerCase(lowerCaseGrowthType);
1662         if(lowerCaseGrowthType == lowerCaseInput)
1663         {
1664             return true;
1665         }
1666     }
1667 
1668     return false;
1669 
1670 }
1671 
ProduceGrowthTypeOrBarf(const string & input)1672 growth_type ProduceGrowthTypeOrBarf(const string& input)
1673 {
1674 
1675     if(StringMatchesGrowthType(input,growth_CURVE)) return growth_CURVE;
1676     if(StringMatchesGrowthType(input,growth_STICK)) return growth_STICK;
1677     if(StringMatchesGrowthType(input,growth_STICKEXP)) return growth_STICKEXP;
1678 
1679     data_error e("Illegal growth-type setting \""+input+"\"");
1680     throw e;
1681     return growth_CURVE;
1682 }
1683 
StringMatchesGrowthScheme(const string & input,growth_scheme scheme)1684 bool StringMatchesGrowthScheme(const string& input, growth_scheme scheme)
1685 {
1686     string lowerCaseInput = input;
1687     LowerCase(lowerCaseInput);
1688 
1689     string lowerCaseGrowthScheme = ToString(scheme,false);
1690     LowerCase(lowerCaseGrowthScheme);
1691 
1692     if(lowerCaseGrowthScheme == lowerCaseInput)
1693     {
1694         return true;
1695     }
1696     else
1697     {
1698         lowerCaseGrowthScheme = ToString(scheme,true);
1699         LowerCase(lowerCaseGrowthScheme);
1700         if(lowerCaseGrowthScheme == lowerCaseInput)
1701         {
1702             return true;
1703         }
1704     }
1705 
1706     return false;
1707 
1708 }
1709 
ProduceGrowthSchemeOrBarf(const string & input)1710 growth_scheme ProduceGrowthSchemeOrBarf(const string& input)
1711 {
1712 
1713     if(StringMatchesGrowthScheme(input,growth_EXP)) return growth_EXP;
1714     if(StringMatchesGrowthScheme(input,growth_STAIRSTEP)) return growth_STAIRSTEP;
1715 
1716     data_error e("Illegal growth-scheme setting \""+input+"\"");
1717     throw e;
1718     return growth_EXP;
1719 }
1720 
StringMatchesModelType(const string & input,model_type type)1721 bool StringMatchesModelType(const string& input, model_type type)
1722 {
1723     string lowerCaseInput = input;
1724     LowerCase(lowerCaseInput);
1725 
1726     string lowerCaseModel = ToString(type,false);
1727     LowerCase(lowerCaseModel);
1728 
1729     if(lowerCaseModel == lowerCaseInput)
1730     {
1731         return true;
1732     }
1733     else
1734     {
1735         lowerCaseModel = ToString(type,true);
1736         LowerCase(lowerCaseModel);
1737         if(lowerCaseModel == lowerCaseInput)
1738         {
1739             return true;
1740         }
1741     }
1742 
1743     return false;
1744 
1745 }
1746 
ProduceModelTypeOrBarf(const string & input)1747 model_type ProduceModelTypeOrBarf(const string& input)
1748 {
1749 
1750     if(StringMatchesModelType(input,Brownian)) return Brownian;
1751     if(StringMatchesModelType(input,F84)) return F84;
1752     if(StringMatchesModelType(input,GTR)) return GTR;
1753     if(StringMatchesModelType(input,KAllele)) return KAllele;
1754     if(StringMatchesModelType(input,Stepwise)) return Stepwise;
1755     if(StringMatchesModelType(input,MixedKS)) return MixedKS;
1756 
1757     data_error e("Illegal model-type setting \""+input+"\"");
1758     throw e;
1759     return F84;
1760 }
1761 
StringMatchesForceType(const string & input,force_type type)1762 bool StringMatchesForceType(const string& input, force_type type)
1763 {
1764     string lowerCaseInput = input;
1765     LowerCase(lowerCaseInput);
1766 
1767     string lowerCaseForce = ToString(type);
1768     LowerCase(lowerCaseForce);
1769 
1770     string lowerCaseShortForce = ToShortString(type);
1771     LowerCase(lowerCaseShortForce);
1772 
1773     if((lowerCaseForce == lowerCaseInput) ||
1774        (lowerCaseShortForce == lowerCaseInput))
1775     {
1776         return true;
1777     }
1778     return false;
1779 
1780 }
1781 
ProduceForceTypeOrBarf(const string & input)1782 force_type ProduceForceTypeOrBarf(const string& input)
1783 {
1784     if(StringMatchesForceType(input,force_COAL)) return force_COAL;
1785     if(StringMatchesForceType(input,force_DISEASE)) return force_DISEASE;
1786     if(StringMatchesForceType(input,force_GROW)) return force_GROW;
1787     if(StringMatchesForceType(input,force_MIG)) return force_MIG;
1788     if(StringMatchesForceType(input,force_DIVMIG)) return force_DIVMIG;
1789     if(StringMatchesForceType(input,force_REC)) return force_REC;
1790     if(StringMatchesForceType(input,force_REGION_GAMMA)) return force_REGION_GAMMA;
1791     if(StringMatchesForceType(input,force_DIVERGENCE)) return force_DIVERGENCE;
1792 
1793     data_error e("Illegal force-type setting \""+input+"\"");
1794     throw e;
1795     return force_COAL;
1796 }
1797 
StringMatchesMethodType(const string & input,method_type type)1798 bool StringMatchesMethodType(const string& input, method_type type)
1799 {
1800     if (input == "-" && type == method_PROGRAMDEFAULT)
1801     {
1802         return true;
1803     }
1804 
1805     string lowerCaseInput = input;
1806     LowerCase(lowerCaseInput);
1807 
1808     string lowerCaseMethod = ToString(type,false);
1809     LowerCase(lowerCaseMethod);
1810     if(lowerCaseMethod == lowerCaseInput)
1811     {
1812         return true;
1813     }
1814 
1815     lowerCaseMethod = ToString(type,true);
1816     LowerCase(lowerCaseMethod);
1817     if(lowerCaseMethod == lowerCaseInput)
1818     {
1819         return true;
1820     }
1821 
1822     return false;
1823 }
1824 
ProduceMethodTypeOrBarf(const string & input)1825 method_type ProduceMethodTypeOrBarf(const string & input)
1826 {
1827     if(StringMatchesMethodType(input,method_FST)) return method_FST;
1828     if(StringMatchesMethodType(input,method_PROGRAMDEFAULT)) return method_PROGRAMDEFAULT;
1829     if(StringMatchesMethodType(input,method_USER)) return method_USER;
1830     if(StringMatchesMethodType(input,method_WATTERSON)) return method_WATTERSON;
1831 
1832     data_error e("Illegal method-type setting \""+input+"\"");
1833     throw e;
1834     return method_USER;
1835 }
1836 
1837 //------------------------------------------------------------------------------------
1838 
StringMatchesProftype(const string & input,proftype type)1839 bool StringMatchesProftype(const string& input, proftype type)
1840 {
1841     if(input == "-" && type == profile_NONE) return true;
1842 
1843     string lowerCaseInput = input;
1844     LowerCase(lowerCaseInput);
1845 
1846     string lowerCaseMethod = ToString(type);
1847     LowerCase(lowerCaseMethod);
1848 
1849     if(lowerCaseMethod == lowerCaseInput)
1850     {
1851         return true;
1852     }
1853     return false;
1854 }
1855 
ProduceProftypeOrBarf(const string & input)1856 proftype ProduceProftypeOrBarf(const string& input)
1857 {
1858     if(StringMatchesProftype(input,profile_PERCENTILE)) return profile_PERCENTILE;
1859     if(StringMatchesProftype(input,profile_FIX)) return profile_FIX;
1860     if(StringMatchesProftype(input,profile_NONE)) return profile_NONE;
1861 
1862     data_error e("Illegal profile type setting \""+input+"\"");
1863     throw e;
1864     return profile_NONE;
1865 }
1866 
ProduceProftypeVec1dOrBarf(const string & input)1867 ProftypeVec1d ProduceProftypeVec1dOrBarf(const string& input)
1868 {
1869     StringVec1d stringVec;
1870     ProftypeVec1d returnVal;
1871     bool divided = FromString(input,stringVec);
1872     if(divided)
1873     {
1874         StringVec1d::iterator i;
1875         for(i=stringVec.begin(); i != stringVec.end(); i++)
1876         {
1877             proftype p = ProduceProftypeOrBarf(*i);
1878             returnVal.push_back(p);
1879         }
1880 
1881         return returnVal;
1882     }
1883 
1884     data_error e("Error:  empty vector for the '<profiles>' tag.");
1885     throw e;
1886 }
1887 
StringMatchesParamstatus(const string & input,pstatus type)1888 bool StringMatchesParamstatus(const string& input, pstatus type)
1889 {
1890     if(input == "-" && type == pstat_invalid) return true;
1891 
1892     string lowerCaseInput = input;
1893     LowerCase(lowerCaseInput);
1894 
1895     string lowerCaseMethod = ToString(type);
1896     LowerCase(lowerCaseMethod);
1897 
1898     if(lowerCaseMethod == lowerCaseInput)
1899     {
1900         return true;
1901     }
1902     return false;
1903 }
1904 
ProduceParamstatusOrBarf(const string & input)1905 ParamStatus ProduceParamstatusOrBarf(const string& input)
1906 {
1907     if(StringMatchesParamstatus(input,pstat_invalid)) return ParamStatus(pstat_invalid);
1908     if(StringMatchesParamstatus(input,pstat_unconstrained)) return ParamStatus(pstat_unconstrained);
1909     if(StringMatchesParamstatus(input,pstat_constant)) return ParamStatus(pstat_constant);
1910     if(StringMatchesParamstatus(input,pstat_identical)) return ParamStatus(pstat_identical);
1911     if(StringMatchesParamstatus(input,pstat_identical_head)) return ParamStatus(pstat_identical_head);
1912     if(StringMatchesParamstatus(input,pstat_multiplicative)) return ParamStatus(pstat_multiplicative);
1913     if(StringMatchesParamstatus(input,pstat_multiplicative_head)) return ParamStatus(pstat_multiplicative_head);
1914 
1915     data_error e("Illegal parameter constraint type \""+input+"\"");
1916     throw e;
1917 }
1918 
ProduceParamstatusVec1dOrBarf(const string & input)1919 vector <ParamStatus> ProduceParamstatusVec1dOrBarf(const string& input)
1920 {
1921     StringVec1d stringVec;
1922     vector <ParamStatus> returnVal;
1923     bool divided = FromString(input,stringVec);
1924     if(divided)
1925     {
1926         StringVec1d::iterator i;
1927         for(i=stringVec.begin(); i != stringVec.end(); i++)
1928         {
1929             ParamStatus p = ProduceParamstatusOrBarf(*i);
1930             returnVal.push_back(p);
1931         }
1932 
1933         return returnVal;
1934     }
1935 
1936     throw data_error("Error:  empty vector for the '<constraints>' tag.");
1937 }
1938 
ProduceMethodTypeVec1dOrBarf(const string & input)1939 MethodTypeVec1d ProduceMethodTypeVec1dOrBarf(const string& input)
1940 {
1941     StringVec1d stringVec;
1942     MethodTypeVec1d returnVal;
1943     bool divided = FromString(input,stringVec);
1944     if(divided)
1945     {
1946         StringVec1d::iterator i;
1947         for(i=stringVec.begin(); i != stringVec.end(); i++)
1948         {
1949             method_type p = ProduceMethodTypeOrBarf(*i);
1950             returnVal.push_back(p);
1951         }
1952 
1953         return returnVal;
1954     }
1955 
1956     throw data_error("Error:  empty vector for the '<method>' tag.");
1957     return returnVal;
1958 }
1959 
ProduceDoubleVec1dOrBarf(const string & input)1960 DoubleVec1d ProduceDoubleVec1dOrBarf(const string& input)
1961 {
1962     StringVec1d stringVec;
1963     DoubleVec1d returnVal;
1964     bool divided = FromString(input,stringVec);
1965     if(divided)
1966     {
1967         StringVec1d::iterator i;
1968         for(i=stringVec.begin(); i != stringVec.end(); i++)
1969         {
1970             double p = ProduceDoubleOrBarf(*i);
1971             returnVal.push_back(p);
1972         }
1973 
1974         return returnVal;
1975     }
1976 
1977     data_error e("Error:  empty vector for input that required numbers.");
1978     throw e;
1979 }
1980 
ProduceLongVec1dOrBarf(const string & input)1981 LongVec1d ProduceLongVec1dOrBarf(const string& input)
1982 {
1983     StringVec1d stringVec;
1984     LongVec1d returnVal;
1985     bool divided = FromString(input,stringVec);
1986     if(divided)
1987     {
1988         StringVec1d::iterator i;
1989         for(i=stringVec.begin(); i != stringVec.end(); i++)
1990         {
1991             long int p = ProduceLongOrBarf(*i);
1992             returnVal.push_back(p);
1993         }
1994 
1995         return returnVal;
1996     }
1997 
1998     //An empty vector here is fine.
1999     return returnVal;
2000 
2001 }
2002 
2003 //------------------------------------------------------------------------------------
2004 
StringMatchesPriorType(const string & input,priortype type)2005 bool StringMatchesPriorType(const string& input, priortype type)
2006 {
2007     string lowerCaseInput = input;
2008     LowerCase(lowerCaseInput);
2009 
2010     string lowerCaseMethod = ToString(type);
2011     LowerCase(lowerCaseMethod);
2012 
2013     if(lowerCaseMethod == lowerCaseInput)
2014     {
2015         return true;
2016     }
2017     return false;
2018 }
2019 
ProducePriorTypeOrBarf(const string & input)2020 priortype ProducePriorTypeOrBarf(const string& input)
2021 {
2022     if(StringMatchesPriorType(input,LINEAR)) return LINEAR;
2023     if(StringMatchesPriorType(input,LOGARITHMIC)) return LOGARITHMIC;
2024     data_error e("Illegal parameter constraint type \""+input+"\"");
2025     throw e;
2026 } // ProducePriorTypeOrBarf
2027 
StringMatchesSelectionType(const string & input,selection_type type)2028 bool StringMatchesSelectionType(const string& input, selection_type type)
2029 {
2030     string lowerCaseInput = input;
2031     LowerCase(lowerCaseInput);
2032 
2033     string lowerCaseSelectionType = ToString(type,false);
2034     LowerCase(lowerCaseSelectionType);
2035 
2036     if(lowerCaseSelectionType == lowerCaseInput)
2037     {
2038         return true;
2039     }
2040     else
2041     {
2042         lowerCaseSelectionType = ToString(type,true);
2043         LowerCase(lowerCaseSelectionType);
2044         if(lowerCaseSelectionType == lowerCaseInput)
2045         {
2046             return true;
2047         }
2048     }
2049 
2050     return false;
2051 
2052 }
2053 
ProduceSelectionTypeOrBarf(const string & input)2054 selection_type ProduceSelectionTypeOrBarf(const string& input)
2055 {
2056 
2057     if(StringMatchesSelectionType(input,selection_DETERMINISTIC))
2058     {
2059         return selection_DETERMINISTIC;
2060     }
2061     if(StringMatchesSelectionType(input,selection_STOCHASTIC))
2062     {
2063         return selection_STOCHASTIC;
2064     }
2065 
2066     data_error e("Illegal selection-type setting \""+input+"\"");
2067     throw e;
2068     return selection_DETERMINISTIC;
2069 
2070 }
2071 
2072 //------------------------------------------------------------------------------------
2073 
2074 // this replaces the cin.getline() function which is broken
2075 // in macosx gcc 3.1 and other 3.1 version and which is
2076 // is fixed in gcc >= 3.1.1, but macosx might not fix this for
2077 // quite a while
2078 // PB Sep 2002
MyCinGetline(string & sline)2079 void MyCinGetline(string & sline)
2080 {
2081     char ch=cin.get();
2082     // this while loop should be capable to work with
2083     // windows, mac, and unix EOL style characters
2084     while(!strchr("\r\n",ch))
2085     {
2086         sline += ch;
2087         ch = cin.get();
2088 
2089     }
2090 }
2091 
2092 //------------------------------------------------------------------------------------
2093 
getFirstInterestingChar(const string & input)2094 char getFirstInterestingChar(const string & input)
2095 {
2096     const char * str = input.c_str();
2097     int length = input.length();
2098     for(int i = 0; i < length; i++)
2099     {
2100         if (isalnum(str[i]))
2101         {
2102             return toupper(str[i]);
2103         }
2104     }
2105     return '\0';
2106 }
2107 
2108 //------------------------------------------------------------------------------------
2109 
cwdString()2110 string cwdString()
2111 {
2112     for(int bufSize=100;;bufSize*=2)
2113     {
2114 #ifdef LAMARC_COMPILE_MSWINDOWS
2115         char * shouldNotBeNull = _getcwd(NULL,bufSize);
2116 #else
2117         char * cwdBuf = new char[bufSize];
2118         char * shouldNotBeNull = getcwd(cwdBuf,bufSize);
2119         free(cwdBuf);
2120 #endif
2121         if(shouldNotBeNull != NULL)
2122         {
2123 #ifdef LAMARC_COMPILE_MSWINDOWS
2124             string thepath(shouldNotBeNull);
2125             free(shouldNotBeNull);
2126             return thepath;
2127 #else
2128             return string(cwdBuf);
2129 #endif
2130         }
2131     }
2132 }
2133 
StripLeadingSpaces(string & st)2134 void StripLeadingSpaces(string & st)
2135 {
2136     while(isspace(st[0]))
2137     {
2138         st.erase(0,1);
2139     }
2140 }
StripTrailingSpaces(string & st)2141 void StripTrailingSpaces(string & st)
2142 {
2143     while(isspace(st[st.length()-1]))
2144     {
2145         st.erase(st.length()-1,1);
2146     }
2147 }
2148 
2149 //------------------------------------------------------------------------------------
2150 
SpacesToUnderscores(const string & st)2151 string SpacesToUnderscores(const string& st)
2152 {
2153     string newstring(st);
2154     char underscore('_');
2155     replace_if(newstring.begin(),newstring.end(),ptr_fun<int,int>(isspace),underscore);
2156     return newstring;
2157 }
2158 
2159 //------------------------------------------------------------------------------------
2160 
indexToKey(long int index)2161 string indexToKey(long int index)
2162 {
2163     return ToString(index+1);
2164 }
2165 
keyToIndex(string key)2166 long int keyToIndex(string key)
2167 {
2168     return -1+ProduceLongOrBarf(key);
2169 }
2170 
buildName(const string & prefix,const string & delim,size_t digits,size_t value)2171 string buildName(const string& prefix, const string & delim, size_t digits, size_t value)
2172 {
2173     assert(digits < 10);        // EWFIX.P3.CONSTANTS
2174     assert((10^digits) > value);  // EWFIX.P3
2175     char fmtString[8];          // EWFIX.P3.CONSTANTS
2176     sprintf (fmtString,"%%s%%s%%0%dd",(int)digits);
2177 
2178     size_t sizeNeeded = prefix.length()+delim.length()+digits+1;
2179     char * spaceToBuild = new char[sizeNeeded];
2180 
2181     sprintf(spaceToBuild,fmtString,prefix.c_str(),delim.c_str(),value);
2182 
2183     string retVal(spaceToBuild);
2184     free(spaceToBuild);
2185     return retVal;
2186 }
2187 
2188 //____________________________________________________________________________________
2189