#include "global_config.h"
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
namespace cppcms {
bool cppcms_config::get_tocken(FILE *f,tocken_t &T)
{
int c;
while((c=fgetc(f))!=EOF) {
if(c=='.') {
T.first='.';
return true;
}
else if(c=='{') {
T.first='{';
return true;
}
else if(c=='}') {
T.first='}';
return true;
}
else if(c=='=') {
T.first='=';
return true;
}
else if(c=='\n') {
line_counter++;
continue;
}
else if(c==' ' || c=='\r' || c=='\t') {
continue;
}
else if(isalpha(c)) {
T.second="";
T.second.reserve(32);
T.second+=(char)c;
while((c=fgetc(f))!=EOF && (isalnum(c) || c=='_')) {
T.second+=(char)c;
}
if(c!=EOF){
ungetc(c,f);
}
T.first=WORD;
return true;
}
else if(isdigit(c) || c=='-') {
T.second="";
T.second.reserve(32);
T.second+=(char)c;
T.first=INT;
while((c=fgetc(f))!=EOF && isdigit(c)) {
T.second+=(char)c;
}
if(c=='.') {
T.second+='.';
T.first=DOUBLE;
while((c=fgetc(f))!=EOF && isdigit(c)) {
T.second+=(char)c;
}
}
if(T.second=="-" || T.second=="." || T.second=="-.") {
throw cppcms_error("Illegal charrecters");
}
if(c!=EOF) {
ungetc(c,f);
}
return true;
}
else if(c=='\"') {
T.first=STR;
T.second="";
T.second.reserve(128);
for(;;){
c=fgetc(f);
if(c=='\\'){
if((c=fgetc(f))=='\"' ) {
T.second+='"';
continue;
}
else {
T.second+='\\';
}
}
if(c==EOF){
throw cppcms_error("Unexpected EOF ");
}
if(c=='\n') line_counter++;
if(c=='\"') {
return true;
}
T.second+=(char)c;
}
}
else if(c=='#' || c==';'){
while((c=fgetc(f))!=EOF) {
if(c=='\n'){
line_counter++;
break;
}
}
if(c==EOF) {
return false;
}
}
else {
throw cppcms_error(string("Unexpected charrecter")+(char)c);
}
}
return false;
}
void cppcms_config::load(char const *fname)
{
if(loaded){
return;
}
FILE *f=fopen(fname,"r");
line_counter=1;
if(!f) {
throw cppcms_error(string("Failed to open file:")+fname);
}
tocken_t T;
string key;
int state=0;
try{
while(get_tocken(f,T) && state != -1) {
switch(state) {
case 0: if(T.first != WORD) {
state=-1;
}else{
key=T.second;
state=1;
}
break;
case 1: if(T.first != '.')
state=-1;
else
state=2;
break;
case 2: if(T.first!=WORD){
state=-1;
}else{
state=3;
key+='.';
key+=T.second;
}
break;
case 3: if(T.first!= '=')
state=-1;
else
state=4;
break;
case 4: if(T.first=='{') {
state=5;
break;
}
if(T.first==INT) {
int val=atol(T.second.c_str());
data[key]=val;
}
else if(T.first==DOUBLE) {
double val=atof(T.second.c_str());
data[key]=val;
}
else if(T.first==STR){
data[key]=T.second;
}
else {
state=-1;
break;
}
state=0;
break;
case 5:
if(T.first==INT || T.first==DOUBLE || T.first==STR) {
int fp=T.first;
vector<int> vl;
vector<double> vd;
vector<string> vs;
do {
if(T.first=='}') {
state=0;
}
else if(T.first==fp){
switch(T.first) {
case INT: vl.push_back(atol(T.second.c_str())); break;
case DOUBLE: vd.push_back(atof(T.second.c_str())); break;
case STR: vs.push_back(T.second); break;
}
}
else {
state=-1;
}
}while(state==5 && get_tocken(f,T));
if(state==0) {
switch(fp) {
case INT: data[key]=vl; break;
case DOUBLE: data[key]=vd; break;
case STR: data[key]=vs; break;
};
}
}
else
state=-1;
break;
}
}
if(state!=0) {
throw cppcms_error("Parsing error");
}
}
catch (cppcms_error &err){
fclose(f);
char stmp[32];
snprintf(stmp,32," at line %d",line_counter);
throw cppcms_error(string(err.what())+stmp);
}
fclose(f);
loaded=true;
}
void cppcms_config::load(int argc,char *argv[],char const *def)
{
if(loaded) {
return;
}
char const *def_file=def;
int i;
for(i=1;i<argc;i++) {
if(strncmp(argv[i],"--config=",9)==0) {
def_file=argv[i]+9;
break;
}
else if(strcmp(argv[i],"-c")==0 && i+1<argc) {
def_file=argv[i+1];
break;
}
}
if(def_file==NULL) {
def_file=getenv("CPPCMS_CONFIG");
}
if(def_file==NULL) {
throw cppcms_error("Configuration file not defined");
}
load(def_file);
}
}