xconfig is used to parse x-file file as a configuration file.
e.g.
# This is a comment line
# '#' or '!' must be the first of character of a line
OTFChart.backgroundColor: black
OTFChart.foregroundColor: white
OTFChart.width: 640
OTFChart.height: 480
//////////////////////////////////////////////////////////////////////////////////////////////
e.g.
# This is a comment line
# '#' or '!' must be the first of character of a line
OTFChart.backgroundColor: black
OTFChart.foregroundColor: white
OTFChart.width: 640
OTFChart.height: 480
//////////////////////////////////////////////////////////////////////////////////////////////
// xcnf.h
// Author: Seree Rakwong
// Date: 25-OCT-10
// Purpose: Read a X file
#define xcnf_h
#include <fstream>
#include <string>
#include <map>
#include <iostream>
class xconfig_parser;
class xconfig_interface {
private:
friend class xconfig_parser;
protected:
virtual void found_comment(const std::string& comment)=0;
virtual int found_key(const std::string& key)=0;
virtual int found_value(const std::string& value)=0;
virtual void found_error(const std::string& filename, unsigned int errline, int errcode)=0;
};
class xconfig : public xconfig_interface {
friend std::ostream& operator<<(std::ostream& os, const xconfig& xcnf);
private:
std::map<std::string, std::string> keys_map_;
std::string cur_key_;
protected:
void found_comment(const std::string& comment);
int found_key(const std::string& key);
int found_value(const std::string& value);
void found_error(const std::string& filename, unsigned int errline, int errcode);
public:
int get_int(const std::string& key, int def_value = 0);
double get_double(const std::string& key, double def_value = 0.0);
std::string get_string(const std::string& key, const std::string& def_value = "");
};
// dump pairs of keys and values
std::ostream& operator<<(std::ostream& os, const xconfig& xcnf);
class xconfig_parser : public std::ifstream {
private:
std::string filename_;
public:
xconfig_parser();
xconfig_parser(const std::string& filename);
virtual ~xconfig_parser();
public:
void open(const std::string& filename);
void open(const char *filename, ios_base::openmode mode = ios_base::in);
int parse(xconfig_interface *xcnf_ptr);
public:
enum xconfig_error {
none_error = 0,
missing_object = 1,
file_not_opened = 2,
not_allowed_2_separators = 3,
missing_key = 1000,
missing_value = 1001
};
};
#endif // xcnf_h
//////////////////////////////////////////////////////////////////////////////////////////////
//xcnf.cpp
// Author: Seree Rakwong
// Date: 25-OCT-10
// Purpose: Read a X file
//#include <iostream>
#include <iomanip>
using std::string;
using std::ifstream;
using std::map;
using std::cout;
using std::cerr;
using std::endl;
using std::ostream;
/////////////////////////////////////////////////////////////////////////
// xconfig
void xconfig::found_comment(const string& comment) {
}
int xconfig::found_key(const string& key) {
keys_map_[key] = ":invalid:";
cur_key_ = key;
return 0;
}
int xconfig::found_value(const string& value) {
keys_map_[cur_key_] = value;
return 0;
}
void xconfig::found_error(const std::string& filename, unsigned int errline, int errcode) {
cerr << "Filename: " << filename
<< ", Line: " << errline
<< ", Code: " << errcode
<< endl;
}
int xconfig::get_int(const string& key, int def_value) {
map<string, string>::iterator it;
it = keys_map_.find(key);
if(it != keys_map_.end())
return atoi(it->second.c_str());
return def_value;
}
double xconfig::get_double(const string& key, double def_value) {
map<string, string>::iterator it;
it = keys_map_.find(key);
if(it != keys_map_.end())
return atof(it->second.c_str());
return def_value;
}
string xconfig::get_string(const string& key, const string& def_value) {
map<string, string>::iterator it;
it = keys_map_.find(key);
if(it != keys_map_.end())
return it->second;
return def_value;
}
ostream& operator<<(ostream& os, const xconfig& xcnf) {
map<string, string>::const_iterator it;
// find the max of length of a key
int len = 0;
for(it=xcnf.keys_map_.begin(); it!=xcnf.keys_map_.end(); it++) {
if(it->first.length() > len) len = it->first.length();
}
// print output
for(it=xcnf.keys_map_.begin(); it!=xcnf.keys_map_.end(); it++) {
string key("\"");
key += it->first;
key += "\"";
os << "key[" << std::right << std::setw(len+2) << key << "] = " << std::left << it->second << endl;
}
return os;
}
/////////////////////////////////////////////////////////////////////////
// xconfig_parser
xconfig_parser::xconfig_parser()
: filename_("") {
}
xconfig_parser::xconfig_parser(const string& filename)
: ifstream(filename.c_str()),
filename_(filename) {
}
xconfig_parser::~xconfig_parser() {
close();
}
void xconfig_parser::open(const string& filename) {
if(is_open()) close();
ifstream::open(filename.c_str());
filename_ = filename;
}
void xconfig_parser::open(const char *filename, ios_base::openmode mode) {
if(is_open()) close();
ifstream::open(filename, mode);
filename_ = filename;
}
int xconfig_parser::parse(xconfig_interface *xcnf_ptr) {
if(!xcnf_ptr) return missing_object; // no need parsing
if(!is_open()) return file_not_opened; // cannot read a file
unsigned int line_no = 1;
bool reading_key = false;
bool reading_value = false;
string key;
string value;
while(good()) {
char ch = get();
// comments
switch(ch) {
case '!':
case '#': {
// reset
if(reading_value) {
if(!value.empty()) { xcnf_ptr->found_value(value); }
else if(!reading_key) {
xcnf_ptr->found_error(filename_, line_no, missing_value);
return missing_value;
}
}
reading_value = false;
string comment("");
while(good()) {
ch = get();
if('\n' == ch) {
xcnf_ptr->found_comment(comment);
comment = "";
line_no++;
break;
}
else { comment += ch; }
}
if(comment.length() > 0) { xcnf_ptr->found_comment(comment); }
reading_key = true;
break;
}
case '\n': {
if(reading_value && !value.empty()) {
xcnf_ptr->found_value(value);
reading_value = false;
value = "";
}
else if((reading_key && !key.empty()) || (value.empty() && !reading_key)) {
xcnf_ptr->found_error(filename_, line_no, missing_value);
return missing_value;
}
line_no++;
reading_key = true;
break;
}
// separator between a key and a value
case ':':
case '=': {
if(reading_key) {
if(!key.empty()) {
xcnf_ptr->found_key(key);
reading_key = false;
key = "";
reading_value = true;
}
else {
xcnf_ptr->found_error(filename_, line_no, missing_key);
return missing_key;
}
}
else {
if(reading_value) {
xcnf_ptr->found_error(filename_, line_no, not_allowed_2_separators);
return not_allowed_2_separators;
}
//else { reading_value = true; }
}
reading_value = true;
value = "";
break;
}
// white spaces
case ' ':
case '\t':
case '\r': {
//no action
break;
}
default: {
//a-z, A-Z, 0-9, ., _
if(reading_key) { key += ch; }
else if(reading_value) { value += ch; }
break;
}
}
}
if(!value.empty()) { xcnf_ptr->found_value(value); }
return 0;
}
/////////////////////////////////////////////////////////////////////////
#include "xcnf.h"
// Author: Seree Rakwong
// Date: 25-OCT-10
// Purpose: Read a X file
using namespace std;
class myconfig : public xconfig {
protected:
void found_comment(const string& comment) {
cout << comment << endl;
}
public:
string get_service() { return get_string("OTFChart.Service"); }
int get_downloadBuffer() { return get_int("OTFChart.downloadBuffer"); }
double get_imageWidth() { return get_double("OTFChart.imageWidth"); }
double get_imageHeight() { return get_double("OTFChart.imageHeight"); }
string get_unknown() { return get_string("OTFChart.unknown", ":invalid:"); }
};
int main(int argc, char *argv[]) {
if(argc < 2) {
cerr << "USAGE: " << argv[0] << " config_filename" << endl;
return 1;
}
myconfig xcnf;
xconfig_parser parser(argv[1]);
int rc = 0;
if((rc = parser.parse(&xcnf)) != 0) {
switch(rc) {
case xconfig_parser::missing_key: {
cerr << "errcode(" << rc << ") - missing key" << endl;
break;
}
case xconfig_parser::missing_value: {
cerr << "errcode(" << rc << ") - missing value" << endl;
break;
}
}
return 1;
}
cout << "service : " << xcnf.get_service() << endl;
cout << "buffer : " << xcnf.get_downloadBuffer() << endl;
cout << "width : " << xcnf.get_imageWidth() << endl;
cout << "height : " << xcnf.get_imageHeight() << endl;
cout << "unknown : " << xcnf.get_unknown() << endl;
cout << "dump all keys and values" << endl;
cout << xcnf << endl;
return 0;
}
###########################################
# xtest.cnf
# this is a test comment line
OTFChart.Service: RI2APICHART
OTFChart.imageHeight: 50.01 # this is an image height
# test failed missing value
OTFChart.colorBG: blue
OTFChart.colorFG: yellow
# yep, this is a second comment line
# also this is too
OTFChart.downloadBuffer: 51200
OTFChart.imageWidth : 101.23