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 '"'
918 string safename = name;
919 string::size_type quotpos = safename.find("\"");
920 while (quotpos != string::npos)
921 {
922 safename.replace(quotpos, 1, """);
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