You can download it here with an example ZIP/ 20KB
Alternatively, here is the code:
Code: Select all
/** settings.h Torleif West 17/dec/2007
*
* Loads settings from file, then map them for quick access.
* Allows comments in the settings file and trims wasted white space.
*
*/
#include <map> // map of properties
#include <string> // for std::string
#include <fstream> // opening file
#include <ostream> // saving file
#ifndef SETTINGS_H_
#define SETTINGS_H_
class Settings{
/**
Class stores strings in a map, with a value for each.
This allows quick access to the data
*/
private:
// Map of two strings
std::map<std::string, std::string> data;
// Use numbers char values as UNIX has different new line char
static const char CHAR_LINE1 = 59; // windows endline
static const char CHAR_LINE2 = 10; // UNIX endline
static const char CHAR_SPACE = 32; // ' ' char
static const char CHAR_ENDFILE = -1;// EOF
static const char CHAR_EQUALS = 61; // = char
static const char CHAR_COMMENT = 35;// # char
static const char NUMBER_POINT = 46;// ASCII value for .
static const char NUMBER_NINE = 57; // ASCII value for 9
static const char NUMBER_ZERO = 48; // ASCII value for 0
// file name of this settings file (used if saved)
std::string settingsFile;
public:
// --- Loads the settings file ---
// \param filename the string file name to load
Settings(std::string filename) {
settingsFile = filename;
std::ifstream ifs (filename.c_str(), std::ifstream::in);
bool swch = true;
bool stopReading = false;
char c;
std::string mproperty = "";
std::string value = "";
while (ifs.good()) {
c = (char) ifs.get();
//printf("%d ", int(c)); // debug
if(c == CHAR_EQUALS) {
swch = false;
}
if(c == CHAR_COMMENT) {
stopReading = true;
}
// ignore white space
if(c != CHAR_EQUALS && !stopReading) {
std::string tmpchar;
tmpchar = c;
if(swch) {
mproperty.append(tmpchar);
} else {
value.append(tmpchar);
}
}
// read to the end of the line
if(c == CHAR_LINE1 || c == CHAR_LINE2 || c == CHAR_ENDFILE) {
if(!swch) {
//printf("Inserting :%s=%s\n",
// trim(mproperty).c_str(), trim(value).c_str());
data.insert ( std::pair<std::string,
std::string>(trim(mproperty),trim(value)) );
}
mproperty = "";
value = "";
swch = true;
stopReading = false;
}
}
ifs.close();
}
// --- Deconstructor ---
~Settings(){
data.clear();
}
// --- Removes white space ---
// \param targ string of to trim
// \returns string with no white space at start or end
std::string trim(const std::string &targ) {
std::string retstr;
int startStr = 0;
int endStr = targ.size();
if(targ.size() == 0) return targ;
for(int i = 0; i < (int)targ.size(); i++) {
char c = targ.at(i);
if(c != CHAR_LINE1 && c != CHAR_LINE2 &&
c != CHAR_ENDFILE && c != CHAR_SPACE ) {
startStr = i;
break;
}
}
for(int i = (int)targ.size()-1; i > 0; i--) {
char c = targ.at(i);
if(c != CHAR_LINE1 && c != CHAR_LINE2 &&
c != CHAR_ENDFILE && c != CHAR_SPACE ) {
endStr = i;
break;
}
}
// rebuild string
for(int i = startStr; i <= endStr; i++) {
std::string tmpchar;
tmpchar = targ.at(i);
retstr.append(tmpchar);
}
return retstr;
}
// --- Returns value in map ---
// \param key the string key stored in the map
// \param roret return value if no string found
// \returns string in map, or noret if not found
std::string getValue(std::string key, std::string noret){
std::map<std::string, std::string>::iterator it;
it = data.find(key);
if(it != data.end()){
return (*it).second;
}
return noret;
}
// --- Returns the size of the map---
// \returns int how many items in data map
int size(){
return (int) data.size();
}
// --- Converts string to double ---
// \param s the string to convert
// \returns double floating point number of string
double strToDob(const std::string &s){
double retvalue = 0.0;
int digitPlacing = 0; // place in str where you've read to
int digitPoint = -1; // place where the point is
for(int i = 0; i < (int)s.size(); i++) {
// convert char to number for double
if(s.at(i) >= NUMBER_ZERO && s.at(i) <= NUMBER_NINE) {
if(digitPoint == -1) { //adding
retvalue *= 10;
retvalue += s.at(i) - NUMBER_ZERO;
} else {
int add = 10;// find power of 10 to decimal place
for(int m = 0; m < (digitPlacing-digitPoint); m++)
add *= 10;
retvalue+=(double)(s.at(i)-NUMBER_ZERO)/(double)add;
}
digitPlacing++;
}
// running into point
if(s.at(i) == NUMBER_POINT && digitPoint == -1) {
digitPoint = digitPlacing;
}
}
return retvalue;
}
// --- Saves a the value in file, and changes in map (slow atm) ---
// \param saveStr the value in the map to change
// \param newValue the value that will replace the old value
void saveParam(std::string saveStr, std::string newValue){
// bail out on failure
std::string oldValue = getValue(saveStr, "");
std::string saveFile;
// bail out if value dosn't exisit
if(oldValue.compare("")==0){ return; }
// save file in memory
std::ifstream ifs (settingsFile.c_str(), std::ifstream::in);
while (ifs.good()) {
char c = ifs.get();
if(c != CHAR_ENDFILE) {
std::string tmpchar;
tmpchar = c;
saveFile.append(tmpchar);
}
}
ifs.close();
// go through each character, and find the string your replacing
bool swch = true;
bool stopReading = false;
char c;
std::string mproperty = "";
std::string value = "";
for(int i = 0; i < (int)saveFile.size(); i++) {
c = saveFile.at(i);
//printf("%d ", int(c)); // debug
if(c == CHAR_EQUALS) {
swch = false;
}
if(c == CHAR_COMMENT) {
stopReading = true;
}
// ignore white space
if(c != CHAR_EQUALS && !stopReading) {
std::string tmpchar;
tmpchar = c;
if(swch) {
mproperty.append(tmpchar);
} else {
// found the value, save and bail.
if(trim(mproperty).compare(saveStr)==0) {
saveFile.replace(i+1, oldValue.size(), newValue);
// save the new value in the map
data.erase (saveStr);
data.insert(std::pair<std::string, std::string>
(saveStr, newValue));
// and finally in the map
std::ofstream savFil(settingsFile.c_str(),
std::ofstream::trunc);
savFil << saveFile;
savFil.close();
return;
}
value.append(tmpchar);
}
}
// read to the end of the line
if(c == CHAR_LINE1 || c == CHAR_LINE2 || c == CHAR_ENDFILE) {
mproperty = "";
value = "";
swch = true;
stopReading = false;
}
}
}
};
#endif
Please feel free to suggest improvements/ changes to it