Initfile.cc 8.24 KB
Newer Older
Praetorius, Simon's avatar
Praetorius, Simon committed
1 2 3 4 5 6 7 8
#include "Initfile.h"

#include <string>
#include <stdexcept>
#include <iostream>
#include <sstream>
using namespace std;

9 10
namespace AMDiS {

11 12
  /// the small parser for the initfile. see description of 
  /// read(Initfile&,istream&)
13 14 15 16
  struct Parser {
    Parser(const string& line) 
    {
      size_t pos = line.find(':');
17
      if (pos == string::npos) {
18 19
	throw runtime_error("cannot find the delimiter ':' in line "
			    "'" + line + "'");
20
      }
21 22 23 24 25 26
      name = line.substr(0, pos);
      value = line.substr(pos + 1, line.length() - (pos + 1));

      // remove everything after the %
      pos = value.find('%');
      if (pos != string::npos)
27
        value = value.substr(0, pos);      
28 29 30 31 32
    }
    string name;
    string value;
  };

33

34
  Initfile* Initfile::singlett = NULL;
35 36 37 38 39 40 41 42 43 44
  std::set<std::string> Initfile::fn_include_list;


  /// initialize singleton object an global parameters
  void Initfile::init(std::string in)
  {
    initIntern();
    fn_include_list.clear();
    singlett->read(in);	
    singlett->getInternalParameters();
45

46 47
    // initialize global strcutures using parameters
    Global::init();
48
  }
49 50 51


  /// Fill an initfile from a file with filename fn
52
  void Initfile::read(std::string fn, bool force)
53 54
  {
    // read file if its not parsed already
55
    if (fn_include_list.find(fn) == fn_include_list.end() || force) {
56 57 58
      std::ifstream inputFile;
      inputFile.open(fn.c_str(), std::ios::in);
      if (!inputFile.is_open())
59
	throw runtime_error("init-file '" + fn + "' cannot be opened for reading");
60

61 62 63
      fn_include_list.insert(fn);
      read(inputFile);
    }
64
  }
65 66 67 68 69


  /// Fill an initfile from an input stream
  void Initfile::read(istream& in) 
  {
70
    unsigned line_length = 512;
71 72
    char swap[line_length];
    in.getline(swap, line_length);
73
    while (in.good() || in.gcount() > 0) {
74
      std::string whitespaces = " \t\r\f\n";
75 76
      std::string sw(swap);
      size_t pos0 = sw.find_first_not_of(whitespaces);
77

78 79 80 81
      if (pos0 != std::string::npos
          && sw[pos0] != '%' 
          && sw[pos0] != '#'
          && sw[pos0] != 0) {
82 83
        // parse line and extract map: tag->value
        Parser parser(sw);
84
        
85
        // add parameter to map after variable replacement
Praetorius, Simon's avatar
Praetorius, Simon committed
86 87
        std::string paramName = variableReplacement(trim(parser.name));
        std::string paramValue = variableReplacement(trim(parser.value));
Praetorius, Simon's avatar
Praetorius, Simon committed
88 89
        paramValue = variableEvaluation(paramValue);
      
90 91 92 93
        operator[](paramName) = paramValue;
        int info = 0;
        get("parameter information", info, 0);
        if (info >= 2)
94
          std::cout << "read [" << paramName << " => " << paramValue << "]\n";
95 96 97
      } else if (pos0 != std::string::npos &&
		 sw[pos0] == '#'  &&
		 static_cast<size_t>(sw.find("#include")) == pos0) {
98
        // include file by '#include "filename"' or '#include <filename>'
99 100 101 102 103 104
        bool forceRead = false;
        int posAdd = 1;
        if (sw[pos0 + std::string("#include").size()] == '!') {
          forceRead = true;
          posAdd++;
        }
105
        size_t pos = sw.find_first_not_of(whitespaces, 
106
          pos0 + std::string("#include").size() + posAdd);
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
        size_t epos = 0;
        std::string fn =  "";
        std::stringstream errorMsg;
        switch (char c= swap[pos++]) {
          case '<':
            c= '>';
          case '\"':
            whitespaces += c;
            epos = sw.find_first_of(whitespaces, pos);
            fn = sw.substr(pos, epos - pos);

            if (sw[epos]!=c) {
              errorMsg << "filename in #include not terminated by " << c;
              throw std::runtime_error(errorMsg.str());
            }
            break;
          default:
            throw std::runtime_error("no filename given for #include");
        }
126
        read(fn, forceRead);
127
      }
128

129 130
      in.getline(swap, line_length);
    }
131
  }
132 133 134 135 136


  std::string Initfile::variableReplacement(const std::string& input) const
  {
    std::string whitespaces = " \t\r\f";
Praetorius, Simon's avatar
Praetorius, Simon committed
137
    std::string allowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
138 139 140 141
    std::string inputSwap = input; 
    size_t posVar = inputSwap.find_first_of('$');
    while (posVar != string::npos) {
      size_t posVarBegin, posVarEnd;
Praetorius, Simon's avatar
Praetorius, Simon committed
142
      if(inputSwap[posVar+1] == '{') {						// ${var_name}
143 144
        posVarEnd = inputSwap.find_first_of('}',posVar + 2);
        posVarBegin = posVar + 1;
Praetorius, Simon's avatar
Praetorius, Simon committed
145 146
      } else if (inputSwap[posVar+1] != '(' && inputSwap[posVar+1] != '[') {
        posVarEnd = inputSwap.find_first_not_of(allowedChars, posVar + 1);
147
        posVarBegin = posVar;
Praetorius, Simon's avatar
Praetorius, Simon committed
148 149 150
      } else {
	posVar = inputSwap.find_first_of('$',posVar+1);
	continue;
151
      }
Praetorius, Simon's avatar
Praetorius, Simon committed
152
      
153
      std::string varName = inputSwap.substr(posVarBegin + 1 , posVarEnd - posVarBegin - 1);
154

Praetorius, Simon's avatar
Praetorius, Simon committed
155

156
      // if varname is found in parameter list then replace variable by value
157
      // otherwise throw tagNotFound exception
158 159 160 161 162
      std::string varParam;
      int error_code = checkedGet(varName, varParam);
      if (error_code != 0)
	throw TagNotFoundBreak("required tag '" + varName + "' for variable substitution not found");
      
163 164 165
      std::string replaceName = inputSwap.substr(posVar , posVarEnd - posVar + (posVarBegin - posVar));
      inputSwap.replace(inputSwap.find(replaceName), replaceName.length(), varParam);

Praetorius, Simon's avatar
Praetorius, Simon committed
166
      posVar = inputSwap.find_first_of('$',posVarBegin);
167 168 169
    }

    return inputSwap;
170
  }
171

Praetorius, Simon's avatar
Praetorius, Simon committed
172 173 174 175
  std::string Initfile::variableEvaluation(const std::string& input) const
  {
    std::string whitespaces = " \t\r\f";
    std::string inputSwap = input;
Praetorius, Simon's avatar
Praetorius, Simon committed
176
    size_t posVar = inputSwap.find("$(");
Praetorius, Simon's avatar
Praetorius, Simon committed
177 178
    while (posVar != string::npos) {
      size_t posVarBegin, posVarEnd;
Praetorius, Simon's avatar
Praetorius, Simon committed
179 180
      posVarEnd = inputSwap.find_first_of(')',posVar + 2);
      posVarBegin = posVar + 1;
Praetorius, Simon's avatar
Praetorius, Simon committed
181 182 183 184 185 186 187 188 189
      std::string varName = inputSwap.substr(posVarBegin + 1 , posVarEnd - posVarBegin - 1);

      double value = 0.0;
      InitfileInternal::convert(varName, value); // string -> double (using muparser)
      InitfileInternal::convert(value, varName); // double -> string

      std::string replaceName = inputSwap.substr(posVar , posVarEnd - posVar + (posVarBegin - posVar));
      inputSwap.replace(inputSwap.find(replaceName), replaceName.length(), varName);

Praetorius, Simon's avatar
Praetorius, Simon committed
190
      posVar = inputSwap.find("$(",posVarBegin);
Praetorius, Simon's avatar
Praetorius, Simon committed
191 192 193 194
    }

    return inputSwap;
  }
195 196 197

  void Initfile::readArgv(int argc, char **argv)
  {
Praetorius, Simon's avatar
Praetorius, Simon committed
198
    initIntern();
199 200
    for (int i = 0; i < argc; i++) {
      if (strcmp("-rs", argv[i]) == 0) {
201 202
        std::string input(argv[i + 1]);
        add("argv->rs", input, 0);
203
      }
Praetorius, Simon's avatar
Praetorius, Simon committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
      else if (strcmp("-parameters", argv[i]) == 0) {
        std::string input(argv[i + 1]);
	int found = input.find_first_of(';');

	std::vector<std::string> parameters;
	while (found != static_cast<int>(std::string::npos)) {
	  if (found > 2) {
	    parameters.push_back(input.substr(0, found).c_str());
	  }
	  input = input.substr(found + 1);
	  found = input.find_first_of(';');
	}
	if (input.length() > 2)
	  parameters.push_back(input.c_str());

	for (size_t i = 0; i < parameters.size(); i++) {
	  int found = input.find_first_of(':');
	  if (found != static_cast<int>(std::string::npos)) {
	    std::string value = input.substr(found+1);
	    set(input.substr(0, found), value, 0);
	  }
	}
	
      }
228 229 230 231 232 233 234 235 236 237
    }
  }


  /// read standard values for output and information of parameter-values
  void Initfile::getInternalParameters() 
  {
    int val = 0;
    get("level of information", val, 0);
    msgInfo = val;
238

239 240 241
    val = 1;
    get("WAIT", val, 0);
    msgWait = val;
242

243 244 245
    val = 1;
    get("parameter information", val, 0);
    paramInfo = val;
246

247 248 249 250 251 252
    val = 0;
    get("break on missing tag", val, 0);
    breakOnMissingTag = val;

    if (msgInfo == 0)
      paramInfo = 0;
253
  }
254 255 256 257 258 259 260


  /// print all parameters to std::cout
  void Initfile::printParameters() 
  {
    initIntern();
    for (Initfile::iterator it = singlett->begin(); it != singlett->end(); it++)
261
      std::cout << (*it).first << " => " << (*it).second << std::endl;
262
  }
263 264 265 266 267 268


  /// Write data-map to initfile
  void Initfile::write(ostream& out)
  {
    for (Initfile::iterator it = begin() ; it!=end(); it++)
269
      out << (*it).first << ": " << (*it).second << std::endl;	
270 271 272 273 274 275 276 277 278 279
  }


  /// Write data-map to initfile
  void Initfile::write(std::string fn) 
  {
    std::ofstream outFile;
    outFile.open(fn.c_str(), std::ios::out);
    if (!outFile.is_open())
      throw runtime_error("init-file cannot be opened for writing");
280

281 282
    write(outFile);
  }
283
} // end namespace AMDiS