Logo Search packages:      
Sourcecode: passepartout version File versions  Download package

configfile.cc

///
// Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING
///
#include "configfile.h"

#include <sstream>
#include <fstream>
#include <stdexcept>
#include "stringutil.h"

namespace Config{

// BoolVar

void BoolVar::print(std::ostream &out) const {
  for(Bools::const_iterator i = values.begin(); i != values.end(); i++)
    out << (i == values.begin() ? "" : " ") << (*i ? "true" : "false");
}

void BoolVar::parse(const std::string &input) {
  Bools tmp;
  std::istringstream in(input.c_str());
  while(in) {
    std::string word;
    in >> word;
    if(word == "true")
      tmp.push_back(true);
    else if(word == "false")
      tmp.push_back(false);
    else if(word.empty())
      break;
    else
      throw(std::runtime_error("\"" + word + "\" is not a truth value"));
  }
  values = tmp;
}

// StringVar

// replace " with \"
static std::string escape(const std::string s) {
  std::string tmp;
  for(std::string::const_iterator i = s.begin(); i != s.end(); i++) {
    if(*i == '"')
      tmp += "\\\"";
    else
      tmp += *i;
  }
  return tmp;
}

// replace \" with "
static std::string unescape(const std::string s) {
  std::string tmp;
  for(std::string::const_iterator i = s.begin(); i != s.end(); i++) {
    if(*i == '\\') {
      i++;
      if(i == s.end())
        tmp += '\\';
      else if(*i == '"')
        tmp += '"';
      else
        tmp += "\\" + *i;
      }
    else
      tmp += *i;
  }
  return tmp;
}

void StringVar::print(std::ostream &out) const {
  for(Strings::const_iterator i = values.begin(); i != values.end(); i++)
    out << (i == values.begin() ? "" : " ") << '"' << escape(*i) << '"';
}

void StringVar::parse(const std::string &input) {
  Strings tmp;
  bool quote = false; // true if we are inside a quoted string
  int i = 0;
  while(i < int(input.length())) {
    if(whitespace(input[i]))
      i++;
    else {
      if(input[i] == '"') {
      quote = true;
      i++;
      }
      int j = i; // save start pos of string
      while(i < int(input.length())) {
      if(input[i] == '"') {
        if(input[i - 1] == '\\')
          i++;
        else if(quote) {
          quote = false;
          break;
        } else {
          throw std::runtime_error("quotation mark is not escaped");
        }
      } else if(!quote && whitespace(input[i])) {
        break;
      } else {
        i++;
      }
      }
      if(quote)
      throw std::runtime_error("unmatched quotation mark");
      tmp.push_back(unescape(input.substr(j, i-j)));
      i++;
    }
    // No check is performed to see if there is whitespace after an
    // ending quotation mark. 
    // Hence, stuff like "foo""bar" or "foo"bar is allowed.
  }
  values = tmp;
}

// FloatVar

void FloatVar::print(std::ostream &out) const {
  for(Floats::const_iterator i = values.begin(); i != values.end(); i++)
    out << (i == values.begin() ? "" : " ") << *i;
}

void FloatVar::parse(const std::string &input) {
  Floats tmp;
  std::istringstream in(input.c_str());
  float value;
  while(in >> value)
    tmp.push_back(value);
  values = tmp;
}

// File

void File::declare_var(Var *var) {
  vars.push_back(var);
}

void File::read(const std::string &filename) {
  int line_number = 0;
  std::ifstream in(filename.c_str());
  if(!in) {
    error("Could not read " + filename);
    return;
  }
  while(in) {
    std::string line;
    std::getline(in, line);
    line_number++;
    line = strip_whitespace(line);
    // A comment start with # and can only occur on a line of its own.
    if(line.empty() || line[0] == '#')
      continue;
    int pos = line.find_first_of('=');
    if(pos >= int(line.length())) { // no equality sign found
      error("line " + tostr(line_number) + ": \"=\" missing");
      continue;
    }
    std::string name = strip_whitespace(line.substr(0, pos));
    try {
      Vars::iterator i;
      for(i = vars.begin(); i != vars.end(); i++) {
      if(name == (*i)->name) {
        (*i)->parse(line.substr(pos + 1));
        break;
      }
      }
      if(i == vars.end() && !ignore_unknown)
      error("line " + tostr(line_number) + ": variable \"" 
            + name + "\" is unknown");
    }
    catch (const std::runtime_error &e) {
      error("line " + tostr(line_number) + ": " + e.what());
    }
  }
}

void File::write(const std::string &filename) {
  std::ofstream out(filename.c_str());
  if(!out) {
    error("Could not write to \"" + filename + '"');
    return;
  }
  for(Vars::const_iterator i = vars.begin(); i != vars.end(); i++) {
    out << (*i)->name << " = "; 
    (*i)->print(out);
    out << std::endl;
  }
}

}

#ifdef TEST
// test program
int main() {
  using namespace Config;
  File file;
  BoolVar a("Pippilotta");
  a.values.push_back(true);
  StringVar b("Rullgardina");
  b.values.push_back("foobar");
  FloatVar c("Krusmynta");
  c.values.push_back(3.6);
  c.values.push_back(2.1);
  file.declare_var(&a);
  file.declare_var(&b);
  file.declare_var(&c);
  file.read("/tmp/config_test");
  file.write("/tmp/config_test2");
  return 0;
}
#endif

Generated by  Doxygen 1.6.0   Back to index