string_utils.cc

00001 /*
00002  *  This file is part of libcxxsupport.
00003  *
00004  *  libcxxsupport is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  libcxxsupport is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with libcxxsupport; if not, write to the Free Software
00016  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00017  */
00018 
00019 /*
00020  *  libcxxsupport is being developed at the Max-Planck-Institut fuer Astrophysik
00021  *  and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
00022  *  (DLR).
00023  */
00024 
00025 /*
00026  *  This file contains the implementation of various convenience functions
00027  *  used by the Planck LevelS package.
00028  *
00029  *  Copyright (C) 2002-2012 Max-Planck-Society
00030  *  Author: Martin Reinecke
00031  */
00032 
00033 #include <sstream>
00034 #include <fstream>
00035 #include <iostream>
00036 #include <iomanip>
00037 #include <string>
00038 #include <cstring>
00039 #include <cctype>
00040 #include "string_utils.h"
00041 
00042 using namespace std;
00043 
00044 string trim (const string &orig)
00045   {
00046   string::size_type p1=orig.find_first_not_of(" \t");
00047   if (p1==string::npos) return "";
00048   string::size_type p2=orig.find_last_not_of(" \t");
00049   return orig.substr(p1,p2-p1+1);
00050   }
00051 
00052 template<typename T> string dataToString (const T &x)
00053   {
00054   ostringstream strstrm;
00055   strstrm << x;
00056   return trim(strstrm.str());
00057   }
00058 
00059 template<> string dataToString (const bool &x)
00060   { return x ? "T" : "F"; }
00061 template<> string dataToString (const string &x)
00062   { return trim(x); }
00063 template<> string dataToString (const float &x)
00064   {
00065   ostringstream strstrm;
00066   strstrm << setprecision(8) << x;
00067   return trim(strstrm.str());
00068   }
00069 template<> string dataToString (const double &x)
00070   {
00071   ostringstream strstrm;
00072   strstrm << setprecision(16) << x;
00073   return trim(strstrm.str());
00074   }
00075 template<> string dataToString (const long double &x)
00076   {
00077   ostringstream strstrm;
00078   strstrm << setprecision(25) << x;
00079   return trim(strstrm.str());
00080   }
00081 
00082 template string dataToString (const signed char &x);
00083 template string dataToString (const unsigned char &x);
00084 template string dataToString (const short &x);
00085 template string dataToString (const unsigned short &x);
00086 template string dataToString (const int &x);
00087 template string dataToString (const unsigned int &x);
00088 template string dataToString (const long &x);
00089 template string dataToString (const unsigned long &x);
00090 template string dataToString (const long long &x);
00091 template string dataToString (const unsigned long long &x);
00092 
00093 string intToString(int64 x, tsize width)
00094   {
00095   ostringstream strstrm;
00096   (x>=0) ? strstrm << setw(width) << setfill('0') << x
00097          : strstrm << "-" << setw(width-1) << setfill('0') << -x;
00098   string res = strstrm.str();
00099   planck_assert(res.size()==width,"number too large");
00100   return trim(res);
00101   }
00102 
00103 namespace {
00104 
00105 void end_stringToData (const string &x, const char *tn, istringstream &strstrm)
00106   {
00107   string error = string("conversion error in stringToData<")+tn+">(\""+x+"\")";
00108   planck_assert (strstrm,error);
00109   string rest;
00110   strstrm >> rest;
00111 //  rest=trim(rest);
00112   planck_assert (rest.length()==0,error);
00113   }
00114 
00115 } // unnamed namespace
00116 
00117 template<typename T> void stringToData (const string &x, T &value)
00118   {
00119   istringstream strstrm(x);
00120   strstrm >> value;
00121   end_stringToData (x,type2typename<T>(),strstrm);
00122   }
00123 
00124 template<> void stringToData (const string &x, string &value)
00125   { value = trim(x); }
00126 
00127 template<> void stringToData (const string &x, bool &value)
00128   {
00129   const char *x2 = x.c_str();
00130   const char *fval[] = {"F","f","n","N","false",".false.","FALSE",".FALSE." };
00131   const char *tval[] = {"T","t","y","Y","true",".true.","TRUE",".TRUE." };
00132   for (tsize i=0; i< sizeof(fval)/sizeof(fval[0]); ++i)
00133     if (strcmp(x2,fval[i])==0) { value=false; return; }
00134   for (tsize i=0; i< sizeof(tval)/sizeof(tval[0]); ++i)
00135     if (strcmp(x2,tval[i])==0) { value=true; return; }
00136   planck_fail("conversion error in stringToData<bool>(\""+x+"\")");
00137   }
00138 
00139 template void stringToData (const string &x, signed char &value);
00140 template void stringToData (const string &x, unsigned char &value);
00141 template void stringToData (const string &x, short &value);
00142 template void stringToData (const string &x, unsigned short &value);
00143 template void stringToData (const string &x, int &value);
00144 template void stringToData (const string &x, unsigned int &value);
00145 template void stringToData (const string &x, long &value);
00146 template void stringToData (const string &x, unsigned long &value);
00147 template void stringToData (const string &x, long long &value);
00148 template void stringToData (const string &x, unsigned long long &value);
00149 template void stringToData (const string &x, float &value);
00150 template void stringToData (const string &x, double &value);
00151 template void stringToData (const string &x, long double &value);
00152 
00153 bool equal_nocase (const string &a, const string &b)
00154   {
00155   if (a.size()!=b.size()) return false;
00156   for (tsize m=0; m<a.size(); ++m)
00157     if (tolower(a[m])!=tolower(b[m])) return false;
00158   return true;
00159   }
00160 
00161 string tolower(const string &input)
00162   {
00163   string result=input;
00164   for (tsize m=0; m<result.size(); ++m)
00165     result[m]=char(tolower(result[m]));
00166   return result;
00167   }
00168 
00169 void parse_file (const string &filename, map<string,string> &dict)
00170   {
00171   int lineno=0;
00172   dict.clear();
00173   ifstream inp(filename.c_str());
00174   planck_assert (inp,"Could not open parameter file '"+filename+"'.");
00175   while (inp)
00176     {
00177     string line;
00178     getline(inp, line);
00179     ++lineno;
00180     // remove potential carriage returns at the end of the line
00181     line=line.substr(0,line.find("\r"));
00182     line=line.substr(0,line.find("#"));
00183     line=trim(line);
00184     if (line.size()>0)
00185       {
00186       string::size_type eqpos=line.find("=");
00187       if (eqpos!=string::npos)
00188         {
00189         string key=trim(line.substr(0,eqpos)),
00190                value=trim(line.substr(eqpos+1,string::npos));
00191         if (key=="")
00192           cerr << "Warning: empty key in '" << filename << "', line "
00193                << lineno << endl;
00194         else
00195           {
00196           if (dict.find(key)!=dict.end())
00197             cerr << "Warning: key '" << key << "' multiply defined in '"
00198                  << filename << "', line " << lineno << endl;
00199           dict[key]=value;
00200           }
00201         }
00202       else
00203         cerr << "Warning: unrecognized format in '" << filename << "', line "
00204              << lineno << ":\n" << line << endl;
00205       }
00206     }
00207   }
00208 
00209 namespace {
00210 
00211 bool isParam (const string &s)
00212   {
00213   if (s.size()<2) return false;
00214   if (s[0]!='-') return false;
00215   return !(isdigit(s[1]) || (s[1]=='.'));
00216   }
00217 
00218 } // unnamed namespace
00219 
00220 void parse_cmdline_classic (int argc, const char **argv,
00221   const vector<string> &leading_args, map<string,string> &dict)
00222   {
00223   dict.clear();
00224   planck_assert(tsize(argc)>leading_args.size(),"not enough arguments");
00225   for (tsize i=0; i<leading_args.size(); ++i)
00226     dict[leading_args[i]] = argv[i+1];
00227   int curarg=leading_args.size()+1;
00228   while (curarg<argc)
00229     {
00230     string param=argv[curarg];
00231     planck_assert(isParam(param),"unrecognized command line format");
00232     if ((curarg==argc-1) || isParam(argv[curarg+1]))
00233       {
00234       dict[param.substr(1)]="true";
00235       ++curarg;
00236       }
00237     else
00238       {
00239       dict[param.substr(1)]=argv[curarg+1];
00240       curarg+=2;
00241       }
00242     }
00243   }
00244 
00245 void parse_cmdline_classic (int argc, const char **argv,
00246   map<string,string> &dict)
00247   { parse_cmdline_classic (argc, argv, vector<string>(), dict); }
00248 
00249 void parse_cmdline_equalsign (int argc, const char **argv,
00250   const vector<string> &leading_args, map<string,string> &dict)
00251   {
00252   dict.clear();
00253   planck_assert(tsize(argc)>leading_args.size(),"not enough arguments");
00254   for (tsize i=0; i<leading_args.size(); ++i)
00255     dict[leading_args[i]] = argv[i+1];
00256   for (int i=leading_args.size()+1; i<argc; ++i)
00257     {
00258     string arg=trim(argv[i]);
00259     if (arg.size()>0)
00260       {
00261       string::size_type eqpos=arg.find("=");
00262       if (eqpos!=string::npos)
00263         {
00264         string key=trim(arg.substr(0,eqpos)),
00265                value=trim(arg.substr(eqpos+1,string::npos));
00266         if (key=="")
00267           cerr << "Warning: empty key in argument'" << arg << "'" << endl;
00268         else
00269           {
00270           if (dict.find(key)!=dict.end())
00271             cerr << "Warning: key '" << key << "' multiply defined" << endl;
00272           dict[key]=value;
00273           }
00274         }
00275       else
00276         cerr << "Warning: unrecognized format in argument '" << arg << "'"
00277              << endl;
00278       }
00279     }
00280   }
00281 
00282 void parse_cmdline_equalsign (int argc, const char **argv,
00283   map<string,string> &dict)
00284   { parse_cmdline_equalsign (argc, argv, vector<string>(), dict); }
00285 
00286 namespace {
00287 
00288 template<typename T> void split (istream &stream, vector<T> &list)
00289   {
00290   list.clear();
00291   while (stream)
00292     {
00293     string word;
00294     stream >> word;
00295     planck_assert (stream||stream.eof(),
00296       string("error while splitting stream into ") + type2typename<T>()
00297       + "components");
00298     if (stream) list.push_back(stringToData<T>(word));
00299     }
00300   }
00301 
00302 } // unnamed namespace
00303 
00304 template<typename T> void split (const string &inp, vector<T> &list)
00305   {
00306   istringstream stream(inp);
00307   split (stream,list);
00308   }
00309 
00310 template void split (const string &inp, vector<string> &list);
00311 template void split (const string &inp, vector<float> &list);
00312 template void split (const string &inp, vector<double> &list);
00313 template void split (const string &inp, vector<int> &list);
00314 template void split (const string &inp, vector<long> &list);
00315 
00316 void tokenize (const string &inp, char delim, vector<string> &list)
00317   {
00318   istringstream stream(inp);
00319   string token;
00320   list.clear();
00321   while (getline(stream,token,delim))
00322     list.push_back(token);
00323   }
00324 
00325 void parse_words_from_file (const string &filename, vector<string> &words)
00326   {
00327   words.clear();
00328   ifstream inp(filename.c_str());
00329   planck_assert (inp,"Could not open file '"+filename+"'.");
00330   while (inp)
00331     {
00332     string word;
00333     inp>>word;
00334     word=trim(word);
00335     if (word!="") words.push_back(word);
00336     }
00337   }

Generated on Wed Apr 24 11:31:17 2013 for LevelS C++ support library