// $Id: stringx.cpp,v 1.131 2018/01/03 21:33:02 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


#include <cassert>
#include <cctype>
#include <functional>
#include <stdexcept>
#include <string>
#include <cstring>
#include <cstdio>
#include <climits>

// NOTE: older versions required including <direct.h> here and
// using _getcwd() below for MSWINDOWS compiles
#include <unistd.h>       // unistd.h -- provides getcwd()

#include "arranger_types.h"
#include "errhandling.h"
#include "mathx.h"
#include "stringx.h"
#include "xml_strings.h"  // for xmlstr::XML_ATTRTYPE_NAME in MakeTagWithName()
#include "ui_strings.h"
#include "paramstat.h"

#ifdef DMALLOC_FUNC_CHECK
#include "/usr/local/include/dmalloc.h"
#endif

using namespace std;

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

void UpperCase(string &s)
{
    long int length, i;
    length = s.size();
    for (i = 0; i < length; i++)
        s[i] = toupper(s[i]);
}

//------------------------------------------------------------------------------------

void LowerCase(string &s)
{
    long int length, i;
    length = s.size();
    for (i = 0; i < length; i++)
        s[i] = tolower(s[i]);
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

string ToString(char character)
{
    ostringstream ostr;
    ostr << character;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToString(int number)
{
    ostringstream ostr;
    ostr << number;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToString(bool tag)
{
    string s;
    if(tag)
        s="Yes";
    else
        s="No";
    return s;
}

//------------------------------------------------------------------------------------

string ToString(noval val)
{
    return "";
}

//------------------------------------------------------------------------------------

string ToString(unsigned int number)
{
    ostringstream ostr;
    ostr << number;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToString(unsigned long int number)
{
    ostringstream ostr;
    ostr << number;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToString(unsigned long long number)
{
    ostringstream ostr;
    ostr << number;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToString(long int number)
{
    ostringstream ostr;
    ostr << number;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToString(long long number)
{
    ostringstream ostr;
    ostr << number;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToString(double number)
{
    if (numeric_limits<double>::has_infinity)
    {
        if (number == numeric_limits<double>::infinity())
        {
            return "inf";
        }
        if (number == -numeric_limits<double>::infinity())
        {
            return "-inf";
        }
    }
    if (systemSpecificIsnan(number))
    {
        return "nan";
    }
    ostringstream ostr;
    ostr << number;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToDecimalString(double number)
{
    ostringstream ostr;
    ostr.setf(ios_base::fixed);
    ostr << number;
    string s(ostr.str());
    return s;
}

//------------------------------------------------------------------------------------

string ToString(force_type ftype)
{
    switch(ftype)
    {
        case force_COAL:
            return uistr::coalescence;
            break;
        case force_MIG:
            return uistr::migration;
            break;
        case force_DIVMIG:
            return uistr::divmigration;
            break;
        case force_DISEASE:
            return uistr::disease;
            break;
        case force_REC:
            return uistr::recombination;
            break;
        case force_GROW:
            return uistr::growth;
            break;
        case force_REGION_GAMMA:
            return uistr::regionGamma;
            break;
        case force_EXPGROWSTICK:
            return uistr::expGrowStick;
            break;
        case force_LOGISTICSELECTION:
            return uistr::logisticSelection;
            break;
        case force_LOGSELECTSTICK:
            return uistr::logSelectStick;
            break;
        case force_DIVERGENCE:
            return uistr::divergence;
            break;
        case force_NONE:
            return "NO_force";
            break;
    }
    assert(false);
    return "";
}

//------------------------------------------------------------------------------------

string ToShortString(force_type ftype)
{
    switch(ftype)
    {
        case force_COAL:
            return lamarcstrings::COAL;
            break;
        case force_MIG:
            return lamarcstrings::MIG;
            break;
        case force_DIVMIG:
            return lamarcstrings::DIVMIG;
            break;
        case force_DISEASE:
            return lamarcstrings::DISEASE;
            break;
        case force_REC:
            return lamarcstrings::REC;
            break;
        case force_GROW:
            return lamarcstrings::GROW;
            break;
        case force_REGION_GAMMA:
            //GAMMA DEBUG
            assert(false);
            throw implementation_error("The 'Gamma' force not fully supported.");
            break;
        case force_EXPGROWSTICK:
            return lamarcstrings::EXPGROWSTICK;
            break;
        case force_LOGISTICSELECTION:
            return lamarcstrings::LOGISTICSELECTION;
            break;
        case force_LOGSELECTSTICK:
            return lamarcstrings::LOGSELECTSTICK;
            break;
        case force_DIVERGENCE:
            return lamarcstrings::DIVERGENCE;
            break;
        case force_NONE:
            return "NO_force";
            break;
    }
    assert(false);
    return "";
}

//------------------------------------------------------------------------------------

string ToString(method_type method, bool getLongName)
{
    switch(method)
    {
        case method_FST:
            if(getLongName) return lamarcstrings::longNameFST;
            return lamarcstrings::shortNameFST;
            break;
        case method_PROGRAMDEFAULT:
            if(getLongName) return lamarcstrings::longNamePROGRAMDEFAULT;
            return lamarcstrings::shortNamePROGRAMDEFAULT;
            break;
        case method_USER:
            if(getLongName) return lamarcstrings::longNameUSER;
            return lamarcstrings::shortNameUSER;
            break;
        case method_WATTERSON:
            if(getLongName) return lamarcstrings::longNameWATTERSON;
            return lamarcstrings::shortNameWATTERSON;
            break;
    }
    assert(false);
    return lamarcstrings::longNameUSER;
}

//------------------------------------------------------------------------------------

string ToString(growth_type gtype, bool getLongName )
{
    switch(gtype)
    {
        case growth_CURVE:
            if(getLongName) return lamarcstrings::longCurveName;
            return lamarcstrings::shortCurveName;
            break;
        case growth_STICK:
            if(getLongName) return lamarcstrings::longStickName;
            return lamarcstrings::shortStickName;
            break;
        case growth_STICKEXP:
            if(getLongName) return lamarcstrings::longStickExpName;
            return lamarcstrings::shortStickExpName;
            break;
        default:
            assert(false);
            return "";
            break;
    }
}

//------------------------------------------------------------------------------------

string ToString(growth_scheme gscheme, bool getLongName )
{
    switch(gscheme)
    {
        case growth_EXP:
            if(getLongName) return lamarcstrings::longExpName;
            return lamarcstrings::shortExpName;
            break;
        case growth_STAIRSTEP:
            if(getLongName) return lamarcstrings::longStairStepName;
            return lamarcstrings::shortStairStepName;
            break;
        default:
            assert(false);
            return "";
            break;
    }
}

//------------------------------------------------------------------------------------

string ToString(model_type model, bool getLongName )
{
    switch(model)
    {
        case F84:
            if(getLongName) return lamarcstrings::longF84Name;
            return lamarcstrings::shortF84Name;
            break;
        case Brownian:
            if(getLongName) return lamarcstrings::longBrownianName;
            return lamarcstrings::shortBrownianName;
            break;
        case Stepwise:
            if(getLongName) return lamarcstrings::longStepwiseName;
            return lamarcstrings::shortStepwiseName;
            break;
        case KAllele:
            if(getLongName) return lamarcstrings::longKAlleleName;
            return lamarcstrings::shortKAlleleName;
            break;
        case GTR:
            if(getLongName) return lamarcstrings::longGTRName;
            return lamarcstrings::shortGTRName;
            break;
        case MixedKS:
            if(getLongName) return lamarcstrings::longMixedKSName;
            return lamarcstrings::shortMixedKSName;
            break;
        default:
            assert(false);
            return "";
            break;
    }
}

string ToString(paramlistcondition par)
{
    switch (par)
    {
        case paramlist_YES: return "all "; break; // extra space for alignment
        case paramlist_NO: return "none"; break;
        case paramlist_MIX: return "some"; break;
        default: assert(false); return ""; break;
    }
}

string ToString(proftype prof)
{
    switch(prof)
    {
        case profile_PERCENTILE: return "percentile"; break;
        case profile_FIX: return "fixed"; break;
        case profile_NONE: return "none"; break;
    }
    assert(false);
    return "";
}

string ToString(priortype ptype)
{
    switch(ptype)
    {
        case LINEAR: return "linear"; break;
        case LOGARITHMIC: return "log"; break;
    }
    assert(false);
    return "";
}

string ToString(pstatus pstat)
{
    switch(pstat)
    {
        case pstat_unconstrained: return "unconstrained"; break;
        case pstat_invalid: return "invalid"; break;
        case pstat_constant: return "constant"; break;
        case pstat_identical: return "identical"; break;
        case pstat_identical_head: return "identical_head"; break;
        case pstat_multiplicative: return "multiplicative"; break;
        case pstat_multiplicative_head: return "multiplicative_head"; break;
    }
    assert(false);
    return "";
}

string ToString(const ParamStatus& pstat)
{
    return ToString(pstat.Status());
}

string ToString(selection_type stype, bool getLongName )
{
    switch(stype)
    {
        case selection_DETERMINISTIC:
            if(getLongName) return lamarcstrings::longDSelectionName;
            return lamarcstrings::shortDSelectionName;
            break;
        case selection_STOCHASTIC:
            if(getLongName) return lamarcstrings::longSSelectionName;
            return lamarcstrings::shortSSelectionName;
            break;
    }
    assert(false);
    return "";
}

// because we have some template code that might want this
string ToString(string str)
{
    return str;
}

string ToString(UIId id)
{
    string toReturn = "";
    if(id.HasForce())
    {
        force_type ft = id.GetForceType();
        toReturn += ToString(ft);
    }
    if(id.HasIndex1())
    {
        toReturn += ":";
        toReturn += ToString(id.GetIndex1());
    }
    if(id.HasIndex2())
    {
        toReturn += ":";
        toReturn += ToString(id.GetIndex2());
    }
    if(id.HasIndex3())
    {
        toReturn += ":";
        toReturn += ToString(id.GetIndex3());
    }
    return toReturn;
}

string ToString (verbosity_type verbosity)
{
    switch (verbosity)
    {
        case CONCISE:
            return string ("concise");
            break;
        case NORMAL:
            return string ("normal");
            break;
        case NONE:
            return string ("none");
            break;
        case VERBOSE:
            return string("verbose");
            break;
        default:
            throw implementation_error("Unknown verbosity type");
            return string ("");
            break;
    }
}

string ToString (vector<method_type> meths)
{
    string methstring("");
    vector<method_type>::iterator meth;
    for (meth = meths.begin(); meth != meths.end(); ++meth)
    {
        methstring += " " + ToString(*meth,true);   // true => longer name
    }
    return methstring;
}

string ToString (vector<proftype> profs)
{
    string profstring("");
    vector<proftype>::iterator prof;
    for (prof = profs.begin(); prof != profs.end(); ++prof)
    {
        profstring += ToString(*prof) + " ";
    }
    return profstring;
}

string ToString (vector<ParamStatus> pstats)
{
    string pstatstring("");
    vector<ParamStatus>::iterator pstat;
    for (pstat = pstats.begin(); pstat != pstats.end(); ++pstat)
    {
        pstatstring += ToString((*pstat).Status()) + " ";
    }
    return pstatstring;
}

string ToString (ParamVector & pvec)
{
    throw implementation_error("No ToString(ParamVector&) exists");
    return "";
}

string ToString (vector<UIId> ids)
{
    string idstring("");
    vector<UIId>::iterator iditer;
    for (iditer = ids.begin(); iditer != ids.end(); ++iditer)
    {
        idstring += " " + ToString(*iditer);
    }
    return idstring;
}

string ToString (vector<vector<UIId> > ids)
{
    string idstring("");
    vector<vector<UIId> >::iterator iditer;
    for (iditer = ids.begin(); iditer != ids.end(); ++iditer)
    {
        idstring += ", " + ToString(*iditer);
    }
    return idstring;
}

string ToStringTF(bool tag)
{
    string s;
    if(tag)
        s="true";
    else
        s="false";
    return s;
}

//------------------------------------------------------------------------------------

bool CaselessStrCmp(const string& lhs, const string& rhs)
{

    if (lhs.size() != rhs.size()) return false;

    size_t i;
    for (i = 0; i < lhs.size(); ++i)
    {
        if (toupper(lhs[i]) != toupper(rhs[i])) return false;
    }
    return true;

} // CaselessStrCmp

// char* overloads of the preceeding

bool CaselessStrCmp(const string& lhs, const char* rhs)
{
    return CaselessStrCmp(lhs, string(rhs));
} // CaselessStrCmp

bool CaselessStrCmp(const char* lhs, const string& rhs)
{
    return CaselessStrCmp(string(lhs), rhs);
} // CaselessStrCmp

bool CaselessStrCmp(const char* lhs, const char* rhs)
{
    return CaselessStrCmp(string(lhs), string(rhs));
} // CaselessStrCmp

//------------------------------------------------------------------------------------
// Case insensitive string comparison taken from Scott Meyers'
// _Effective STL_ items 19 and 35.

long int ciCharCompare(char c1, char c2)
{
    long int lc1 = toupper(static_cast<unsigned char>(c1));
    long int lc2 = toupper(static_cast<unsigned char>(c2));
    if (lc1 < lc2) return -1;
    if (lc1 > lc2) return 1;
    return 0;
} // ciCharCompare

long int ciStringCompareImpl(const string& s1, const string& s2)
{
    typedef pair<string::const_iterator, string::const_iterator> PSCI;

    PSCI p = mismatch(s1.begin(),s1.end(), s2.begin(),
                      not2(ptr_fun(ciCharCompare)));
    if (p.first == s1.end())
    {
        if (p.second == s2.end()) return 0;
        else return -1;
    }
    return ciCharCompare(*p.first, *p.second);

} // ciStringCompareImpl

long int ciStringCompare(const string& s1, const string& s2)
{
    if (s1.size() <= s2.size()) return ciStringCompareImpl(s1,s2);
    else return -ciStringCompareImpl(s2,s1);
} // ciStringCompare

bool ciCharLess(char c1, char c2)
{
    return
        toupper(static_cast<unsigned char>(c1)) <
        toupper(static_cast<unsigned char>(c2));
} // ciCharLess

bool ciStringLess(const string& s1, const string& s2)
{
    return lexicographical_compare(s1.begin(), s1.end(),
                                   s2.begin(), s2.end(),
                                   ciCharLess);
} // ciStringLess

bool ciStringEqual(const string& s1, const string& s2)
{
    return !ciStringCompare(s1, s2);
} // ciStringEqual

//------------------------------------------------------------------------------------
// Careful: was not able to link this function
// when its name was DoubleVecFromString(..)

bool FromString(const string & in, DoubleVec1d & out)
{
    if (in.empty()) return false;

    string whitespace(" \t"), input = in;
    while (!input.empty())
    {
        double value;
        string::size_type start = input.find_first_not_of(whitespace);
        if (start == string::npos) break;

        string::size_type end = input.find_first_of(whitespace,start);
        if (end != string::npos)
        {
            FromString(input.substr(start,end-start),value);
            input = input.substr(end,input.size()-end);
        }
        else
        {
            FromString(input,value);
            input.erase();
        }

        out.push_back(value);
    }

    return true;
}

bool FromString(const string& input, ProftypeVec1d & out)
{
    StringVec1d vectorize;
    bool parsed = FromString(input,vectorize);
    if(parsed)
    {
        StringVec1d::iterator i;
        for(i=vectorize.begin(); i != vectorize.end(); i++)
        {
            out.push_back(ProduceProftypeOrBarf(*i));
        }
    }
    return false;
}

bool FromString(const string & in, MethodTypeVec1d & out)
{
    if (in.empty()) return false;

    string whitespace(" \t"), input = in;
    while (!input.empty())
    {
        method_type value;
        string::size_type start = input.find_first_not_of(whitespace);
        if (start == string::npos) break;

        string::size_type end = input.find_first_of(whitespace,start);
        if (end != string::npos)
        {
            FromString(input.substr(start,end-start),value);
            input = input.substr(end,input.size()-end);
        }
        else
        {
            FromString(input,value);
            input.erase();
        }

        out.push_back(value);
    }

    return true;
}

bool FromString(const string & in, ParamVector & out)
{
    throw implementation_error("FromString should never be called for ParamVector");
    return false;
}

bool FromString(const string & in, StringVec1d & out)
{
    if (in.empty()) return false;

    string whitespace(" \t"), input = in;
    while (!input.empty())
    {

        string::size_type start = input.find_first_not_of(whitespace);
        if (start == string::npos) break;

        string::size_type end = input.find_first_of(whitespace,start);
        if (end != string::npos)
        {
            string thisTerm = input.substr(start,end-start);
            out.push_back(thisTerm);
            input = input.substr(end,input.size()-end);
        }
        else
        {
            string thisTerm = input.substr(start,input.size()-start);
            out.push_back(thisTerm);
            input.erase();
        }

    }

    return true;
}

bool FromString(const string & in, LongVec1d & out)
{
    if (in.empty()) return false;

    string whitespace(" \t"), input = in;
    while (!input.empty())
    {
        long int value;
        string::size_type start = input.find_first_not_of(whitespace);
        if (start == string::npos) break;

        string::size_type end = input.find_first_of(whitespace,start);
        if (end != string::npos)
        {
            FromString(input.substr(start,end-start),value);
            input = input.substr(end,input.size()-end);
        }
        else
        {
            FromString(input,value);
            input.erase();
        }

        out.push_back(value);
    }

    return true;

}

bool FromString(const string & in, long int & out)
{
    if(in.empty())
        return false;
    else
    {
        istringstream mystream(in);
        mystream >> out;
    }
    return true;
}

bool FromString(const string & in, double& out)
{
    if(in.empty())
        return false;
    else
    {
        istringstream mystream(in);
        mystream >> out;
    }
    return true;
}

bool FromString(const string & in, method_type& out)
{
    try
    {
        out = ProduceMethodTypeOrBarf(in);
    }
    catch(const data_error& e)
    {
        return false;
    }
    return true;
}

//------------------------------------------------------------------------------------

DoubleVec1d StringToDoubleVecOrBarf(const string & in)
{
    DoubleVec1d out;
    if (in.empty()) return out;

    string whitespace(" \t"), input = in;
    while (!input.empty())
    {
        double value;
        string::size_type start = input.find_first_not_of(whitespace);
        if (start == string::npos) break;

        string::size_type end = input.find_first_of(whitespace,start);
        if (end != string::npos)
        {
            value = ProduceDoubleOrBarf(input.substr(start,end-start));
            input = input.substr(end,input.size()-end);
        }
        else
        {
            value = ProduceDoubleOrBarf(input);
            input.erase();
        }

        out.push_back(value);
    }

    return out;
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

string MakeTag(const string& tagname)
{
    return (string("<") + tagname + string(">"));
} // MakeTag

//------------------------------------------------------------------------------------

string MakeCloseTag(const string& tagname)
{
    if (tagname[0] == '<') // we're already some form of xml tag
        if (tagname[1] == '/') // we're already a "closing" tag
            return tagname;
        else
        {
            string nutag(tagname);
            return nutag.insert(1L, "/");
        }
    else
        return (string("</") + tagname + string(">"));
} // MakeCloseTag

//------------------------------------------------------------------------------------

string MakeTagWithName(const string& tag, const string& name)
{
    //Replace quote marks with '&quot;'
    string safename = name;
    string::size_type quotpos = safename.find("\"");
    while (quotpos != string::npos)
    {
        safename.replace(quotpos, 1, "&quot;");
        quotpos = safename.find("\"");
    }
    return MakeTag(tag + " " + xmlstr::XML_ATTRTYPE_NAME + "=" + "\"" + safename + "\"");
} // MakeTagWithName

//------------------------------------------------------------------------------------

string MakeTagWithType(const string& tag, const string& type)
{
    return MakeTag(tag + " " + xmlstr::XML_ATTRTYPE_TYPE + "=" + "\"" + type + "\"");
} // MakeTagWithType

//------------------------------------------------------------------------------------

string MakeTagWithTypePlusPanel(const string& tag, const string& type)
{
    return MakeTag(tag + " " + xmlstr::XML_ATTRTYPE_TYPE + "=" + "\"" + type + "\""+" source=\"panel\"");
} // MakeTagWithTypePlusPanel

//------------------------------------------------------------------------------------

string MakeTagWithConstraint(const string& tag, const string& constraint)
{
    return MakeTag(tag + " " + xmlstr::XML_ATTRTYPE_CONSTRAINT + "=" + "\"" + constraint + "\"");
} // MakeTagWithType

//------------------------------------------------------------------------------------
// MakeJustified will fill out a string with spaces to a width of |width|.
//  Positive values of width are used to make strings right-justified,
//  and negative values are used to make strings left-justified.

string MakeJustified(const string &instr, long int width)
{
    string stuff = instr;
    string::size_type tabpos = stuff.find("\t");
    while (tabpos != string::npos)
    {
        stuff.replace(tabpos, 1, "    ");
        tabpos = stuff.find("\t");
    }
    long int xtraspc = static_cast<long int>(abs(width)) - stuff.size();

    if (xtraspc <= 0)
        return(stuff.substr(0,abs(width)));

    string str;
    if (width < 0)
    {
        str = stuff + str.assign(xtraspc,' ');
    }
    else
    {
        str = str.assign(xtraspc,' ') + stuff;
    }

    return(str);

} // MakeJustified

//------------------------------------------------------------------------------------

string MakeJustified(const char *stuff, long int width)
{
    string str(stuff);

    return(MakeJustified(str,width));

} // MakeJustified

//------------------------------------------------------------------------------------
// MakeCentered used to push stuff to the right, but now it pushes stuff
//  off to the left instead.

string MakeCentered(const string &instr, long int width, long int indent, bool trunc)
{
    string str = instr;
    string::size_type tabpos = str.find("\t");
    while (tabpos != string::npos)
    {
        str.replace(tabpos, 1, "    ");
        tabpos = str.find("\t");
    }

    string line;
    long int strsize = str.size(), numchar = 0, truewidth = width-indent;
    long int halfsize = strsize/2;

    if (trunc && (strsize > truewidth))
    {
        line.assign(indent,' ');
        numchar += indent;
        if (width - indent >= 0)
        {
            line.append(str.substr(0,truewidth));
            numchar += (str.substr(0,truewidth)).size();
        }
        return(line);
    }

    char lastchar = str[strsize-1];
    if (halfsize < truewidth/2 && static_cast<long int>(lastchar) != LINEFEED)
    {
        line.assign(truewidth/2-halfsize,' ');
    }
    numchar += truewidth/2-halfsize;

    line.insert(0,str);
    numchar += strsize;

    string indstr;
    indstr.assign(width-numchar, ' ');
    line.insert(0, indstr);

    indstr.assign(indent,' ');
    line.insert(0, indstr);
    numchar += indent;

    return(line);
} // MakeCentered

//------------------------------------------------------------------------------------

string MakeCentered(const char *str, long int width, long int indent, bool trunc)
{
    const string pstr(str);

    return (MakeCentered(pstr,width,indent,trunc));
} // MakeCentered

//------------------------------------------------------------------------------------

string MakeIndent(const string& str, unsigned long int indent)
{
    string line;
    line.assign(indent,' ');
    line += str;

    return line;

} // MakeIndent

//------------------------------------------------------------------------------------

string MakeIndent(const char* str, unsigned long int indent)
{
    const string pstr(str);

    return (MakeIndent(pstr,indent));

} // MakeIndent

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

/******************************************
 * function to format a double-precision  *
 * number into a fixed-width field, going *
 * to scientific notation as necessary.   *
 * The width must be greater than 5.  If  *
 * the number is greater than e+99 the    *
 * returned string may be longer than     *
 * the given field width.  Also, if the   *
 * number is negative, it will always be  *
 * one character greater than the given   *
 * width.                                 *
 ******************************************/

string Pretty(double p, int w)
{
    ostringstream ost;
    if (w < 6)
    {
        ost << "*";
        return(string(ost.str()));
    }
    ost.width(w);
    ost.setf(ios::showpoint);

    if (fabs(p) >= 1.0 || p == 0.0)     //greater than one, or zero
    {
        ost.setf(ios::fixed);
        ost.setf(ios::scientific);
        if (fabs(p) >= pow(10.0,w)) ost.precision(w-5);
        else if (fabs(p) >= pow(10.0,w-1))
        {
            /* The following would print numbers exactly the width we want with no
               decimal point.  Uncomment this and comment the next line if you want
               to change this behavior. */
            //ost.unsetf(ios::showpoint);
            //ost.precision(0);
            ost.precision(w-5);
        }
        else ost.precision(w-1);
    }
    else
    {              //less than one
        if (fabs(p) <= pow(0.1,w-4))
        {
            ost.setf(ios::scientific);
            ost.unsetf(ios::fixed);
            ost.precision(w-6);
        }
        else
        {
            ost.setf(ios::fixed);
            ost.unsetf(ios::scientific);
            ost.precision(w-2);
        }
    }
    ost << p;
    return(string(ost.str()));
} // Pretty(double)

//  Overload of Pretty for long int (much simpler!)

string Pretty(long int p, int w)
{
    ostringstream ost;
    ost.width(w);
    ost << p;
    return(string(ost.str()));
} // Pretty(long int)

string Pretty(unsigned long int p, int w)
{
    ostringstream ost;
    ost.width(w);
    ost << p;
    return(string(ost.str()));
} // Pretty(unsigned long int)

//  Overload of Pretty for string (much simpler!)

string Pretty(string str, int w)
{
    if ((long int)str.size() == w) return(str);
    if ((long int)str.size() > w) return(str.substr(0,w));

#if 0 // WARNING warning -- doesn't do padding anymore
    long int i;
    for (i = (long int)str.size(); i < w; ++i)
    {
        str += " ";
    }
#endif

    return(str);
} // Pretty(string)

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

bool StringCompare(const string &s1, const char *s2, long int pos, long int n)
{
    string temp = s1.substr(pos, n);
    return (temp == s2);
}

//------------------------------------------------------------------------------------

bool StringCompare(const string &s1, const string &s2, long int pos, long int n)
{
    string temp = s1.substr(pos, n);
    return (temp == s2);
}

//------------------------------------------------------------------------------------

bool CompareWOCase(const string& s1, const string& s2)
{
    string str1, str2(s2);

    //transform(s1.begin(),s1.end(),str1.begin(),tolower);
    //transform(s2.begin(),s2.end(),str2.begin(),tolower);
    // To conform to gcc3.1's C++ standard we do:
    transform(s1.begin(),s1.end(),str1.begin(),
              static_cast<int(*)(int)>(tolower));
    transform(s2.begin(),s2.end(),str2.begin(),
              static_cast<int(*)(int)>(tolower));

    return (str1 == str2);
} // CompareWOCase(string,string)

//------------------------------------------------------------------------------------

bool CompareWOCase(const char* s1, const string& s2)
{
    return CompareWOCase(string(s1),s2);
} // CompareWOCase(char*,string)

//------------------------------------------------------------------------------------

bool CompareWOCase(const string& s1, const char* s2)
{
    return CompareWOCase(s1,string(s2));
} // CompareWOCase(string,char*)

//------------------------------------------------------------------------------------

bool CompareWOCase(const char* s1, const char* s2)
{
    return CompareWOCase(string(s1),string(s2));
} // CompareWOCase(char*,char*)

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

int StringType(const string &s)
{
    long int i = 0;
    while(isspace(s[i]))
        i++;

    // Alpha type _______________________________________________

    if (isalpha(s[i]))
        return 1;                                  // Alpha type

    if (s[i] == '_')
    {
        i++;
        while (s[i] == ' ')
            i++;

        if (isalnum(s[i]))
            return 1;                                // Alphanumeric type

        return 3;                                  // Punctuation type
    }

    // Numeric type _____________________________________________

    if (isdigit(s[i]))
        return 2;                                  // Numeric type

    if (s[i] == '.')
    {
        i++;
        if (isdigit(s[i]))
            return 2;                                // Numeric type

        return 3;                                  // Punctuation
    }

    if (s[i] == '-' || s[i] == '+')
    {
        i++;
        if (isdigit(s[i]))
            return 2;                                // Numeric type

        if (s[i] == '.')
        {
            i++;
            if (isdigit(s[i]))
                return 2;                              // Numeric type
        }
    }

    return 3;                                    // Punctuation
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

string::size_type GetCharacter(const string &s, char &ch, long int posn)
{
    long int len = s.size();
    if (posn < 0 || len <= posn)
        return string::npos;

    while(isspace(s[posn]))
        posn++;

    ch = s[posn];
    posn++;

    return posn;
}

//------------------------------------------------------------------------------------

/**********************************************************************
 Linewrap wraps a table (contained in a vector of strings) so that
 it is no longer than the given linelength.  It uses the following
 rules:
 (1) Break at a column in which all entries have spaces or nothing.
 (2) Lines which consist only of dash and space may be broken anywhere.
 (3) If no acceptable break can be found, the original vector will be
 returned.

 It uses the function IsSeparator(const string) as a helper function.
***********************************************************************/

vector<string> Linewrap(vector<string> invec, long int linelength)
{

    // find a suitable location to wrap
    string::size_type site, line;
    string::size_type oldsize = invec.size();
    bool found = false;
    string::size_type breakpoint = string::npos;

    for (line = 0; line < oldsize; ++line)
    {
        if (static_cast<long int>(invec[line].size()) > linelength)
        {
            found = true;
        }
    }
    if (!found) return(invec);          // didn't need wrapping at all

    for (site = linelength; true; site--)
    {
        found = true;
        for (line = 0; line < oldsize; line++)
        {
            if (static_cast<string::size_type>(invec[line].size()) <= site)
            {
                continue; // skip short lines
            }
            if (IsSeparator(invec[line])) continue;         // skip separators
            if (invec[line][site] != ' ')
            {
                found = false;
                break;
            }
        }
        if (found)
        {
            breakpoint = site;
            break;
        }

        // since we're counting down using an unsigned index,
        // we need to make sure we stop.
        // WARNING -- you probably don't want to add any code
        // after this statement in this for loop
        if (site == 0) break;
    }

    if (breakpoint == string::npos)    // never found a breakpoint
        breakpoint = static_cast<string::size_type>(linelength);
    // Give up and break at the line length anyway.

    // cut each line at that location
    vector<string> firstpart;
    vector<string> secondpart;
    for (line = 0; line < oldsize; ++line)
    {
        if (static_cast<string::size_type>(invec[line].size()) <= breakpoint)
        {
            // line does not need cutting
            firstpart.push_back(invec[line]);
            secondpart.push_back(string(""));
        }
        else
        {                            // line does need cutting
            firstpart.push_back(invec[line].substr(0, breakpoint));
            secondpart.push_back(invec[line].substr(breakpoint+1,
                                                    invec[line].size() - breakpoint));
        }
    }

    //wrap the second part recursively, in case it's very long
    secondpart = Linewrap(secondpart, linelength);

    //catenate first and second parts
    for (line = 0; line < static_cast<string::size_type>(secondpart.size()); ++line)
    {
        firstpart.push_back(secondpart[line]);
    }

    return(firstpart);

} // Linewrap

//------------------------------------------------------------------------------------

vector<string> Linewrap(string instring, long int linelength, long int indent)
{
    StringVec1d returnVec;
    StringVec1d firstLine;
    firstLine.push_back(instring);
    firstLine = Linewrap(firstLine, linelength);
    if (firstLine.size() == 1)
    {
        return firstLine;
    }
    returnVec.push_back(firstLine[0]);
    instring.erase(0,firstLine[0].size());
    while (instring.find(" ") == 0)
    {
        instring.erase(0,1);
    }
    StringVec1d otherLines;
    otherLines.push_back(instring);
    otherLines = Linewrap(otherLines, linelength - indent);
    for (unsigned long int i = 0; i<otherLines.size(); i++)
    {
        returnVec.push_back(MakeJustified("",indent) + otherLines[i]);
    }
    return returnVec;
}

//------------------------------------------------------------------------------------

//LinewrapCopy takes a vector of strings, cuts out the beginning of each
// according to the repeat_length, calls Linewrap on the rest, then prepends
// the cut-out bit back to the beginning of each set of strings.
//
// The vector of strings returned therefore has the dimensionality of n times
// the dimensionality of the original vector, where n is how many times it had
// to be wrapped.
//
// If you want a blank line between wrapped lines, include one at the bottom
// of the original vector of strings.

vector<string> LinewrapCopy(vector<string> original, long int repeat_length, long int total_length)
{
    assert (total_length > repeat_length);

    vector<string> repeated;
    vector<string> wrapped;

    for (unsigned long int iter = 0; iter < original.size(); iter++)
    {
        string begin;
        begin.assign(original[iter], 0, repeat_length);
        repeated.push_back(begin);

        string end("");
        if (static_cast<long int>(original[iter].size()) > repeat_length)
        {
            end.assign(original[iter], repeat_length, original[iter].size());
        }
        wrapped.push_back(end);
    }
    wrapped = Linewrap(wrapped, (total_length - repeat_length));

    for (unsigned long int wrap_iter = 0, repeat_iter = 0; wrap_iter < wrapped.size(); wrap_iter++, repeat_iter++)
    {
        if (repeat_iter >= repeated.size())
            repeat_iter = repeat_iter - repeated.size();
        wrapped[wrap_iter].insert(0, repeated[repeat_iter]);
    }
    return wrapped;
} // LinewrapCopy

//------------------------------------------------------------------------------------
// Is a string composed solely of dash, underscore and/or space?

bool IsSeparator(const string s)
{
    long int i;
    for (i = 0; i < (long int)s.size(); ++i)
    {
        if (s[i] != ' ' && s[i] != '-' && s[i] != '_') return (false);
    }
    return(true);
} // IsSeparator

//------------------------------------------------------------------------------------

bool ProduceBoolOrBarf(const string& src)
{
    string st = src;
    LowerCase(st);
    if (st == "true" || st == "yes" || st == "on" )
    {
        return true;
    }
    if (st == "false" || st == "no"|| st == "off" )
    {
        return false;
    }

    invalid_argument e("Invalid argument to ProduceBoolOrBarf:"+src);
    throw e;
} // ProduceBoolOrBarf

//------------------------------------------------------------------------------------

bool IsInteger(const string& src)
{
    if (src.empty()) return false;

    long int i;
    long int end = src.size();
    bool minusfound = false;
    for (i = 0; i < end; ++i)
    {
        if (isspace(src[i])) continue;  // whitespace is okay
        if (src[i] == '-')
        {
            if (minusfound) return false;
            else
            {
                minusfound = true;
                continue;
            }
        }
        if (!isdigit(src[i])) return false;
    }
    return true;
} // IsInteger

//------------------------------------------------------------------------------------

bool IsReal(const string& src)
{
    if (src.empty()) return false;

    long int i;
    long int end = src.size();
    bool pointfound = false;
    for (i = 0; i < end; ++i)
    {
        if (!isdigit(src[i]))
        {
            if (isspace(src[i])) continue; // whitespace is okay
            if (src[i] == '-') continue; // minus is okay
            if (src[i] == '+') continue; // plus is okay
            if (src[i] == 'e') continue; // e is okay
            if (src[i] != '.') return false;  // neither digit nor point
            if (pointfound) return false;   // a second decimal point?!
            pointfound = true;              // okay, first decimal point
        }
    }
    return true;
} // IsReal

//------------------------------------------------------------------------------------

long int ProduceLongOrBarf(const string& in)
{
    //  if (in == "") return 0;
    long int myLong;
    myLong = atol(in.c_str());
    if (! IsInteger(in))
    {
        //Don't assert here--the menu will catch it.
        throw data_error("Expected an integer, but got \""+in+"\"");
    }
    if (myLong == LONG_MAX)
    {
        throw data_error("The value \""+in+"\" is greater than LONG_MAX (" + Pretty(LONG_MAX) + ").");
    }
    if (myLong == LONG_MIN)
    {
        throw data_error("The value \""+in+"\" is greater than LONG_MIN (" + Pretty(LONG_MIN) + ").");
    }

    return myLong;
} // ProduceLongOrBarf

//------------------------------------------------------------------------------------

double ProduceDoubleOrBarf(const string& in)
{
    double myDouble;
    myDouble = atof(in.c_str());
    if (! IsReal(in))
    {
        if (in == "inf")
        {
            if (numeric_limits<double>::has_infinity)
            {
                return numeric_limits<double>::infinity();
            }
            else
            {
                return DBL_BIG;
            }
        }
        if (in == "-inf")
        {
            if (numeric_limits<double>::has_infinity)
            {
                return -numeric_limits<double>::infinity();
            }
            else
            {
                return -DBL_BIG;
            }
        }
        if (in == "nan")
        {
            if (numeric_limits<double>::has_quiet_NaN)
            {
                return numeric_limits<double>::quiet_NaN();
            }
            else
            {
                return 0.0;
            }
        }
        data_error e("Expected a real number, but got \""+in+"\"");
        throw e;
    }
    if (myDouble == DBL_MAX)
    {
        data_error e("The value \""+in+"\" is greater than DBL_MAX ("+Pretty(DBL_MAX) + ").");
        throw e;
    }
    if (myDouble == NEGMAX)
    {
        data_error e("The value \""+in+"\" is less than NEGMAX  (" + Pretty(NEGMAX) + ").");
        throw e;
    }
    return myDouble;
} // ProduceDoubleOrBarf

//------------------------------------------------------------------------------------

verbosity_type ProduceVerbosityTypeOrBarf(const string& s)
{
    string st = s;
    LowerCase(st);
    if (st == "concise") { return CONCISE; };
    if (st == "normal") { return NORMAL; };
    if (st == "verbose") { return VERBOSE; };
    if (st == "none") { return NONE; };
    data_error e("Illegal verbosity setting \""+s+"\"");
    throw e;
    return NONE;
}

//------------------------------------------------------------------------------------

bool StringMatchesGrowthType(const string& input, growth_type type)
{
    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseGrowthType = ToString(type,false);
    LowerCase(lowerCaseGrowthType);

    if(lowerCaseGrowthType == lowerCaseInput)
    {
        return true;
    }
    else
    {
        lowerCaseGrowthType = ToString(type,true);
        LowerCase(lowerCaseGrowthType);
        if(lowerCaseGrowthType == lowerCaseInput)
        {
            return true;
        }
    }

    return false;

}

growth_type ProduceGrowthTypeOrBarf(const string& input)
{

    if(StringMatchesGrowthType(input,growth_CURVE)) return growth_CURVE;
    if(StringMatchesGrowthType(input,growth_STICK)) return growth_STICK;
    if(StringMatchesGrowthType(input,growth_STICKEXP)) return growth_STICKEXP;

    data_error e("Illegal growth-type setting \""+input+"\"");
    throw e;
    return growth_CURVE;
}

//------------------------------------------------------------------------------------

bool StringMatchesGrowthScheme(const string& input, growth_scheme scheme)
{
    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseGrowthScheme = ToString(scheme,false);
    LowerCase(lowerCaseGrowthScheme);

    if(lowerCaseGrowthScheme == lowerCaseInput)
    {
        return true;
    }
    else
    {
        lowerCaseGrowthScheme = ToString(scheme,true);
        LowerCase(lowerCaseGrowthScheme);
        if(lowerCaseGrowthScheme == lowerCaseInput)
        {
            return true;
        }
    }

    return false;

}

growth_scheme ProduceGrowthSchemeOrBarf(const string& input)
{

    if(StringMatchesGrowthScheme(input,growth_EXP)) return growth_EXP;
    if(StringMatchesGrowthScheme(input,growth_STAIRSTEP)) return growth_STAIRSTEP;

    data_error e("Illegal growth-scheme setting \""+input+"\"");
    throw e;
    return growth_EXP;
}

//------------------------------------------------------------------------------------

bool StringMatchesModelType(const string& input, model_type type)
{
    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseModel = ToString(type,false);
    LowerCase(lowerCaseModel);

    if(lowerCaseModel == lowerCaseInput)
    {
        return true;
    }
    else
    {
        lowerCaseModel = ToString(type,true);
        LowerCase(lowerCaseModel);
        if(lowerCaseModel == lowerCaseInput)
        {
            return true;
        }
    }

    return false;

}

model_type ProduceModelTypeOrBarf(const string& input)
{

    if(StringMatchesModelType(input,Brownian)) return Brownian;
    if(StringMatchesModelType(input,F84)) return F84;
    if(StringMatchesModelType(input,GTR)) return GTR;
    if(StringMatchesModelType(input,KAllele)) return KAllele;
    if(StringMatchesModelType(input,Stepwise)) return Stepwise;
    if(StringMatchesModelType(input,MixedKS)) return MixedKS;

    data_error e("Illegal model-type setting \""+input+"\"");
    throw e;
    return F84;
}

//------------------------------------------------------------------------------------

bool StringMatchesForceType(const string& input, force_type type)
{
    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseForce = ToString(type);
    LowerCase(lowerCaseForce);

    string lowerCaseShortForce = ToShortString(type);
    LowerCase(lowerCaseShortForce);

    if((lowerCaseForce == lowerCaseInput) ||
       (lowerCaseShortForce == lowerCaseInput))
    {
        return true;
    }
    return false;

}

force_type ProduceForceTypeOrBarf(const string& input)
{
    if(StringMatchesForceType(input,force_COAL)) return force_COAL;
    if(StringMatchesForceType(input,force_DISEASE)) return force_DISEASE;
    if(StringMatchesForceType(input,force_GROW)) return force_GROW;
    if(StringMatchesForceType(input,force_MIG)) return force_MIG;
    if(StringMatchesForceType(input,force_DIVMIG)) return force_DIVMIG;
    if(StringMatchesForceType(input,force_REC)) return force_REC;
    if(StringMatchesForceType(input,force_REGION_GAMMA)) return force_REGION_GAMMA;
    if(StringMatchesForceType(input,force_DIVERGENCE)) return force_DIVERGENCE;

    data_error e("Illegal force-type setting \""+input+"\"");
    throw e;
    return force_COAL;
}

bool StringMatchesMethodType(const string& input, method_type type)
{
    if (input == "-" && type == method_PROGRAMDEFAULT)
    {
        return true;
    }

    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseMethod = ToString(type,false);
    LowerCase(lowerCaseMethod);
    if(lowerCaseMethod == lowerCaseInput)
    {
        return true;
    }

    lowerCaseMethod = ToString(type,true);
    LowerCase(lowerCaseMethod);
    if(lowerCaseMethod == lowerCaseInput)
    {
        return true;
    }

    return false;
}

method_type ProduceMethodTypeOrBarf(const string & input)
{
    if(StringMatchesMethodType(input,method_FST)) return method_FST;
    if(StringMatchesMethodType(input,method_PROGRAMDEFAULT)) return method_PROGRAMDEFAULT;
    if(StringMatchesMethodType(input,method_USER)) return method_USER;
    if(StringMatchesMethodType(input,method_WATTERSON)) return method_WATTERSON;

    data_error e("Illegal method-type setting \""+input+"\"");
    throw e;
    return method_USER;
}

//------------------------------------------------------------------------------------

bool StringMatchesProftype(const string& input, proftype type)
{
    if(input == "-" && type == profile_NONE) return true;

    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseMethod = ToString(type);
    LowerCase(lowerCaseMethod);

    if(lowerCaseMethod == lowerCaseInput)
    {
        return true;
    }
    return false;
}

proftype ProduceProftypeOrBarf(const string& input)
{
    if(StringMatchesProftype(input,profile_PERCENTILE)) return profile_PERCENTILE;
    if(StringMatchesProftype(input,profile_FIX)) return profile_FIX;
    if(StringMatchesProftype(input,profile_NONE)) return profile_NONE;

    data_error e("Illegal profile type setting \""+input+"\"");
    throw e;
    return profile_NONE;
}

ProftypeVec1d ProduceProftypeVec1dOrBarf(const string& input)
{
    StringVec1d stringVec;
    ProftypeVec1d returnVal;
    bool divided = FromString(input,stringVec);
    if(divided)
    {
        StringVec1d::iterator i;
        for(i=stringVec.begin(); i != stringVec.end(); i++)
        {
            proftype p = ProduceProftypeOrBarf(*i);
            returnVal.push_back(p);
        }

        return returnVal;
    }

    data_error e("Error:  empty vector for the '<profiles>' tag.");
    throw e;
}

//------------------------------------------------------------------------------------

bool StringMatchesParamstatus(const string& input, pstatus type)
{
    if(input == "-" && type == pstat_invalid) return true;

    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseMethod = ToString(type);
    LowerCase(lowerCaseMethod);

    if(lowerCaseMethod == lowerCaseInput)
    {
        return true;
    }
    return false;
}

ParamStatus ProduceParamstatusOrBarf(const string& input)
{
    if(StringMatchesParamstatus(input,pstat_invalid)) return ParamStatus(pstat_invalid);
    if(StringMatchesParamstatus(input,pstat_unconstrained)) return ParamStatus(pstat_unconstrained);
    if(StringMatchesParamstatus(input,pstat_constant)) return ParamStatus(pstat_constant);
    if(StringMatchesParamstatus(input,pstat_identical)) return ParamStatus(pstat_identical);
    if(StringMatchesParamstatus(input,pstat_identical_head)) return ParamStatus(pstat_identical_head);
    if(StringMatchesParamstatus(input,pstat_multiplicative)) return ParamStatus(pstat_multiplicative);
    if(StringMatchesParamstatus(input,pstat_multiplicative_head)) return ParamStatus(pstat_multiplicative_head);

    data_error e("Illegal parameter constraint type \""+input+"\"");
    throw e;
}

vector <ParamStatus> ProduceParamstatusVec1dOrBarf(const string& input)
{
    StringVec1d stringVec;
    vector <ParamStatus> returnVal;
    bool divided = FromString(input,stringVec);
    if(divided)
    {
        StringVec1d::iterator i;
        for(i=stringVec.begin(); i != stringVec.end(); i++)
        {
            ParamStatus p = ProduceParamstatusOrBarf(*i);
            returnVal.push_back(p);
        }

        return returnVal;
    }

    throw data_error("Error:  empty vector for the '<constraints>' tag.");
}

MethodTypeVec1d ProduceMethodTypeVec1dOrBarf(const string& input)
{
    StringVec1d stringVec;
    MethodTypeVec1d returnVal;
    bool divided = FromString(input,stringVec);
    if(divided)
    {
        StringVec1d::iterator i;
        for(i=stringVec.begin(); i != stringVec.end(); i++)
        {
            method_type p = ProduceMethodTypeOrBarf(*i);
            returnVal.push_back(p);
        }

        return returnVal;
    }

    throw data_error("Error:  empty vector for the '<method>' tag.");
    return returnVal;
}

DoubleVec1d ProduceDoubleVec1dOrBarf(const string& input)
{
    StringVec1d stringVec;
    DoubleVec1d returnVal;
    bool divided = FromString(input,stringVec);
    if(divided)
    {
        StringVec1d::iterator i;
        for(i=stringVec.begin(); i != stringVec.end(); i++)
        {
            double p = ProduceDoubleOrBarf(*i);
            returnVal.push_back(p);
        }

        return returnVal;
    }

    data_error e("Error:  empty vector for input that required numbers.");
    throw e;
}

LongVec1d ProduceLongVec1dOrBarf(const string& input)
{
    StringVec1d stringVec;
    LongVec1d returnVal;
    bool divided = FromString(input,stringVec);
    if(divided)
    {
        StringVec1d::iterator i;
        for(i=stringVec.begin(); i != stringVec.end(); i++)
        {
            long int p = ProduceLongOrBarf(*i);
            returnVal.push_back(p);
        }

        return returnVal;
    }

    //An empty vector here is fine.
    return returnVal;

}

//------------------------------------------------------------------------------------

bool StringMatchesPriorType(const string& input, priortype type)
{
    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseMethod = ToString(type);
    LowerCase(lowerCaseMethod);

    if(lowerCaseMethod == lowerCaseInput)
    {
        return true;
    }
    return false;
}

priortype ProducePriorTypeOrBarf(const string& input)
{
    if(StringMatchesPriorType(input,LINEAR)) return LINEAR;
    if(StringMatchesPriorType(input,LOGARITHMIC)) return LOGARITHMIC;
    data_error e("Illegal parameter constraint type \""+input+"\"");
    throw e;
} // ProducePriorTypeOrBarf

//------------------------------------------------------------------------------------

bool StringMatchesSelectionType(const string& input, selection_type type)
{
    string lowerCaseInput = input;
    LowerCase(lowerCaseInput);

    string lowerCaseSelectionType = ToString(type,false);
    LowerCase(lowerCaseSelectionType);

    if(lowerCaseSelectionType == lowerCaseInput)
    {
        return true;
    }
    else
    {
        lowerCaseSelectionType = ToString(type,true);
        LowerCase(lowerCaseSelectionType);
        if(lowerCaseSelectionType == lowerCaseInput)
        {
            return true;
        }
    }

    return false;

}

selection_type ProduceSelectionTypeOrBarf(const string& input)
{

    if(StringMatchesSelectionType(input,selection_DETERMINISTIC))
    {
        return selection_DETERMINISTIC;
    }
    if(StringMatchesSelectionType(input,selection_STOCHASTIC))
    {
        return selection_STOCHASTIC;
    }

    data_error e("Illegal selection-type setting \""+input+"\"");
    throw e;
    return selection_DETERMINISTIC;

}

//------------------------------------------------------------------------------------

// this replaces the cin.getline() function which is broken
// in macosx gcc 3.1 and other 3.1 version and which is
// is fixed in gcc >= 3.1.1, but macosx might not fix this for
// quite a while
// PB Sep 2002
void MyCinGetline(string & sline)
{
    char ch=cin.get();
    // this while loop should be capable to work with
    // windows, mac, and unix EOL style characters
    while(!strchr("\r\n",ch))
    {
        sline += ch;
        ch = cin.get();

    }
}

//------------------------------------------------------------------------------------

char getFirstInterestingChar(const string & input)
{
    const char * str = input.c_str();
    int length = input.length();
    for(int i = 0; i < length; i++)
    {
        if (isalnum(str[i]))
        {
            return toupper(str[i]);
        }
    }
    return '\0';
}

//------------------------------------------------------------------------------------

string cwdString()
{
    for(int bufSize=100;;bufSize*=2)
    {
#ifdef LAMARC_COMPILE_MSWINDOWS
        // NOTE: used to be _getcwd for older mingw cross-compiles
        char * shouldNotBeNull = getcwd(NULL,bufSize);
#else
        char * cwdBuf = new char[bufSize];
        char * shouldNotBeNull = getcwd(cwdBuf,bufSize);
        free(cwdBuf);
#endif
        if(shouldNotBeNull != NULL)
        {
#ifdef LAMARC_COMPILE_MSWINDOWS
            string thepath(shouldNotBeNull);
            free(shouldNotBeNull);
            return thepath;
#else
            return string(cwdBuf);
#endif
        }
    }
}

//------------------------------------------------------------------------------------

void StripLeadingSpaces(string & st)
{
    while(isspace(st[0]))
    {
        st.erase(0,1);
    }
}
void StripTrailingSpaces(string & st)
{
    while(isspace(st[st.length()-1]))
    {
        st.erase(st.length()-1,1);
    }
}

//------------------------------------------------------------------------------------

string SpacesToUnderscores(const string& st)
{
    string newstring(st);
    char underscore('_');
    replace_if(newstring.begin(),newstring.end(),ptr_fun<int,int>(isspace),underscore);
    return newstring;
}

//------------------------------------------------------------------------------------

string indexToKey(long int index)
{
    return ToString(index+1);
}

long int keyToIndex(string key)
{
    return -1+ProduceLongOrBarf(key);
}

//------------------------------------------------------------------------------------

string buildName(const string& prefix, const string & delim, size_t digits, size_t value)
{
    assert(digits < 10);        // EWFIX.P3.CONSTANTS
    assert((10^digits) > value);  // EWFIX.P3
    char fmtString[8];          // EWFIX.P3.CONSTANTS
    sprintf (fmtString, "%%s%%s%%0%dd", (int)digits);

    size_t sizeNeeded = prefix.length()+delim.length()+digits+1;
    char * spaceToBuild = new char[sizeNeeded];

    sprintf(spaceToBuild,fmtString,prefix.c_str(),delim.c_str(),value);

    string retVal(spaceToBuild);
    free(spaceToBuild);
    return retVal;
}

//____________________________________________________________________________________
