/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /*************************************************************************** * configfile.cc * * Thu May 14 14:51:39 CEST 2015 * Copyright 2015 Bent Bisballe Nyeng * deva@aasimon.org ****************************************************************************/ /* * This file is part of DrumGizmo. * * DrumGizmo is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * DrumGizmo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with DrumGizmo; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include "configfile.h" #include #include #include #include #include #include #include #ifdef WIN32 #include #include #include #include #else #endif #include #ifdef WIN32 #define SEP "\\" #else #define SEP "/" #endif #define CONFIGDIRNAME ".drumgizmo" /** * Return the path containing the config files. */ static std::string configPath() { #ifdef WIN32 std::string configpath; TCHAR szPath[256]; if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, szPath))) { configpath = szPath; } #else std::string configpath = getenv("HOME"); #endif configpath += SEP; configpath += CONFIGDIRNAME; return configpath; } /** * Calling this makes sure that the config path exists */ static bool createConfigPath() { std::string configpath = configPath(); struct stat st; if(stat(configpath.c_str(), &st) == 0) { DEBUG(configfile, "No configuration exists, creating directory '%s'\n", configpath.c_str()); #ifdef WIN32 if(mkdir(configpath.c_str()) < 0) { #else if(mkdir(configpath.c_str(), 0755) < 0) { #endif DEBUG(configfile, "Could not create config directory\n"); } return false; } return true; } ConfigFile::ConfigFile(std::string filename) : filename(filename) , fp(NULL) { } ConfigFile::~ConfigFile() { } bool ConfigFile::load() { DEBUG(configfile, "Loading config file...\n"); if(!open("r")) { return false; } values.clear(); std::string line; while(true) { line = readLine(); if(line == "") break; if(!parseLine(line)) { return false; } } close(); return true; } bool ConfigFile::save() { DEBUG(configfile, "Saving configuration...\n"); createConfigPath(); if(!open("w")) { return false; } std::map::iterator v = values.begin(); for(; v != values.end(); ++v) { fprintf(fp, "%s:%s\n", v->first.c_str(), v->second.c_str()); } close(); return true; } std::string ConfigFile::getValue(const std::string& key) { if(values.find(key) != values.end()) { return values[key]; } return ""; } void ConfigFile::setValue(const std::string& key, const std::string& value) { values[key] = value; } bool ConfigFile::open(std::string mode) { if(fp) close(); std::string configpath = configPath(); std::string configfile = configpath; configfile += SEP; configfile += filename; DEBUG(configfile, "Opening config file '%s'\n", configfile.c_str()); fp = fopen(configfile.c_str(), mode.c_str()); if(!fp) return false; return true; } void ConfigFile::close() { fclose(fp); fp = NULL; } std::string ConfigFile::readLine() { if(!fp) return ""; std::string line; char buf[1024]; while(!feof(fp)) { char *s = fgets(buf, sizeof(buf), fp); if(s) { line += buf; if(buf[strlen(buf) - 1] == '\n') break; } } return line; } bool ConfigFile::parseLine(const std::string& line) { std::string key; std::string value; enum { before_key, in_key, after_key, before_value, in_value, in_value_single_quoted, in_value_double_quoted, after_value, } state = before_key; for(std::size_t p = 0; p < line.size(); ++p) { switch(state) { case before_key: if(line[p] == '#') { // Comment: Ignore line. p = line.size(); continue; } if(std::isspace(line[p])) { continue; } key += line[p]; state = in_key; break; case in_key: if(std::isspace(line[p])) { state = after_key; continue; } if(line[p] == ':' || line[p] == '=') { state = before_value; continue; } key += line[p]; break; case after_key: if(std::isspace(line[p])) { continue; } if(line[p] == ':' || line[p] == '=') { state = before_value; continue; } ERR(configfile, "Bad symbol." " Expecting only whitespace or key/value seperator: '%s'", line.c_str()); return false; case before_value: if(std::isspace(line[p])) { continue; } if(line[p] == '\'') { state = in_value_single_quoted; continue; } if(line[p] == '"') { state = in_value_double_quoted; continue; } value += line[p]; state = in_value; break; case in_value: if(std::isspace(line[p])) { state = after_value; continue; } if(line[p] == '#') { // Comment: Ignore the rest of the line. p = line.size(); state = after_value; continue; } value += line[p]; break; case in_value_single_quoted: if(line[p] == '\'') { state = after_value; continue; } value += line[p]; break; case in_value_double_quoted: if(line[p] == '"') { state = after_value; continue; } value += line[p]; break; case after_value: if(std::isspace(line[p])) { continue; } if(line[p] == '#') { // Comment: Ignore the rest of the line. p = line.size(); continue; } ERR(configfile, "Bad symbol." " Expecting only whitespace or key/value seperator: '%s'", line.c_str()); return false; } } if(state == before_key) { // Line did not contain any data (empty or comment) return true; } // If state == in_value_XXX_quoted here, the string was not terminated. if(state != after_value && state != in_value) { ERR(configfile,"Malformed line: '%s'", line.c_str()); return false; } DEBUG(configfile, "key['%s'] value['%s']\n", key.c_str(), value.c_str()); if(key != "") { values[key] = value; } return true; }