Rev 1 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#include "settings.h"
#include "../common/strutils.h"
#include <stdio.h>
#include <windows.h>
static Settings *g_settings;
//---------------------------------------------------------------------------------
#ifdef X2BC_USE_INI_FORMATS
bool settings_parse_pair_const(const char *pszSectionName, Settings::conststringpair &p)
{
return g_settings->parseConstant(pszSectionName, p);
}
//---------------------------------------------------------------------------------
bool settings_parse_pair_format(const char *pszSectionName, Settings::conststringpair &p)
{
return g_settings->parseFormat(pszSectionName, p);
}
//---------------------------------------------------------------------------------
int CompareStatFormats(const void *a, const void *b)
{
int ida, idb;
ida=((Settings::StatFormat*)a)->id;
idb=((Settings::StatFormat*)b)->id;
return ((Settings::StatFormat*)a)->id - ((Settings::StatFormat*)b)->id;
}
#endif // defined(X2BC_USE_INI_FORMATS )
//---------------------------------------------------------------------------------
bool Settings::loadINI(const char *pszFileName)
{
bool bRes;
char szSectionName[50];
g_settings=this;
clearErrors();
GetPrivateProfileString(L"library", L"WriteWarnings", L"off", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
m_bOutputWarnings=(_stricmp(szSectionName, "on")==0);
GetPrivateProfileString(L"library", L"Convert", L"on", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
m_bConvert=(_stricmp(szSectionName, "on")==0);
GetPrivateProfileString(L"library", L"FrameWarnings", L"on", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
m_bStatFormatWarnings=(_stricmp(szSectionName, "on")==0);
GetPrivateProfileString(L"library", L"XtraPointInfo", L"on", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
m_bXtraPntInfo=(_stricmp(szSectionName, "on")==0);
GetPrivateProfileString(L"library", L"XtraX3BobInfo", L"off", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
m_bXtraX3BobInfo=(_stricmp(szSectionName, "on")==0);
#ifdef X2BC_USE_INI_FORMATS
size_t size;
GetPrivateProfileString("library", "Constants", "Const", szSectionName, sizeof(szSectionName), pszFileName);
char *pszConstants=readSection(szSectionName, pszFileName, &size);
if(size==0){
error(Error, E_SectionEmpty, "Section with constants '%s' not defined or empty.", szSectionName);
bRes=false;
}
else
bRes=parseLines(szSectionName, pszConstants, size, settings_parse_pair_const);
delete[] pszConstants;
if(bRes){
GetPrivateProfileString("library", "Default", "Format", szSectionName, sizeof(szSectionName), pszFileName);
char *pszFormat=readSection(szSectionName, pszFileName, &size);
if(size==0){
error(Error, E_SectionEmpty, "Section with frame formats '%s' not defined or empty.", szSectionName);
bRes=false;
}
else
bRes=parseLines(szSectionName, pszFormat, size, settings_parse_pair_format);
delete[] pszFormat;
}
#else
bRes=true;
#endif // !defined(X2BC_USE_INI_FORMATS)
return bRes;
}
//---------------------------------------------------------------------------------
void Settings::error(ErrorType type, ErrorCodes code, const char *format, ...)
{
va_list ap;
va_start(ap, format);
ErrorMsg *e=new ErrorMsg();
e->type=type;
e->code=code;
_vsnprintf(e->message, sizeof(e->message), format, ap);
va_end(ap);
errors.push_back(e);
}
//---------------------------------------------------------------------------------
#ifdef X2BC_USE_INI_FORMATS
char * Settings::readSection(const char *pszSection, const char *pszFileName, size_t *size)
{
char *data;
int _size=0, res;
do{
_size+=1500;
data=new char[_size];
if(data==NULL) break;
res=GetPrivateProfileSection(pszSection, data, _size, pszFileName);
if(res==_size - 2){
delete[] data;
}
}
while(res==_size - 2);
if(size) *size=res;
return data;
}
//---------------------------------------------------------------------------------
bool Settings::parseLines(const char *pszSectionName, char *pszData, size_t size, ParsePairCallback *callback)
{
size_t count;
char **lines=lineexplode(pszData, size, &count);
bool bRes=true;
for(size_t i=0; i < count; i++){
char *line=lines[i];
int j=0;
bool bComment=false;
char *equal, *left, *right;
left=right=equal=0;
while(line[j]!=0){
switch(line[j]){
case '=':
line[j]=0;
equal=line + j;
left=line;
break;
case ';':
line[j]=0;
j--; // so the main while(...) will encouter this added 0 and terminate
break;
}
j++;
}
if(equal){
right=equal + 1;
conststringpair p=parsePair(left, right);
if(callback(pszSectionName, p)==false) {
bRes=false;
break; // break if parsing fails
}
}
else
error(Warning, W_LineIgnored, "Section \"%s\": line '%s' ignored.", pszSectionName, line);
}
delete[] lines;
return bRes;
}
//---------------------------------------------------------------------------------
// trim white spaces from left and right
Settings::conststringpair Settings::parsePair(const char *left, const char *right)
{
conststringpair p;
p.left=trim((char*)left);
p.right=trim((char*)right);
return p;
}
//---------------------------------------------------------------------------------
bool Settings::parseConstant(const char *pszSectionName, Settings::conststringpair &p)
{
bool res=true;
NumberFormat *f=new NumberFormat();
const char *pszMultiplier=0, *pszFormat=0;
char *left, *right;
// backup the original strings for error reporting
size_t len=strlen(p.left);
left=new char[len + 1];
memcpy(left, p.left, len + 1);
len=strlen(p.right);
right=new char[len + 1];
memcpy(right, p.right, len + 1);
// the left operand (constant name)
if(*p.left==0){
error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nMissing constant name.", pszSectionName, left, right);
res=false;
}
else if(strlen(p.left) > 1){
error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nConstant name must be exactly 1 character.", pszSectionName, left, right);
res=false;
}
else if(!((*p.left | 0x20) > 'a') && ((*p.left | 0x20) < 'z')){
error(Error, E_BadConstantDeclaration, "Section \"%s\": Constant \"%c\": constant name must be a upper or lowercase character (A - Z).", pszSectionName, *p.left);
res=false;
}
if(res==false){
delete[] left; delete[] right;
return res;
}
f->type=*p.left;
// the right operand (constant multiplier and format)
pszMultiplier=p.right;
char *pos=strchr(p.right, ',');
if(pos){
*pos=0;
pszFormat=trim(++pos);
}
if(pszMultiplier==0 || *pszMultiplier==0){
error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nMissing constant multiplier.", pszSectionName, left, right);
res=false;
}
else if(pszFormat==0 || *pszFormat==0){
error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nMissing output format specifier.", pszSectionName, left, right);
res=false;
}
else{
f->multiplier=atof(pszMultiplier);
if(f->multiplier==0){
error(ErrorType::Warning, W_ConstantAlwaysZero, "Section \"%s\": line: '%s = %s':\nMultiplier is 0. Result will be always zero. Is this the intent?", pszSectionName, left, right);
}
}
if(res==true){
if(stricmp(pszFormat, "integer")==0)
f->outformat=NumberFormat::Integer;
else if(stricmp(pszFormat, "float")==0)
f->outformat=NumberFormat::Float;
else{
error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nUnknown output format '%s'.", pszSectionName, left, right, pszFormat);
res=false;
}
}
delete[] left;
delete[] right;
if(res)
m_constants.push_back(f);
return res;
}
//---------------------------------------------------------------------------------
bool Settings::parseFormat(const char *pszSectionName, conststringpair &p)
{
bool bRes;
switch(p.left[0]){
case 0:
error(ErrorType::Error, E_BadFormatDeclaration, "Section \"%s\": invalid line format: '%s = %s':\nID expected.", pszSectionName, p.left, p.right);
bRes=false;
break;
case '$':
bRes=parseStatFormat(pszSectionName, p);
break;
case 'N': // don't read the N constants - we use algorithm instead if INI
bRes=true;
break;
default:
error(Warning, W_LineIgnored, "Section \"%s\": ignoring line '%s = %s':\nUnknown ID type.", pszSectionName, p.left, p.right);
bRes=true;
}
return bRes;
}
//---------------------------------------------------------------------------------
bool Settings::parseStatFormat(const char *pszSectionName, conststringpair &p)
{
char *left, *right;
bool bRes=true;
// backup the original strings for error reporting
size_t len=strlen(p.left);
left=new char[len + 1];
memcpy(left, p.left, len + 1);
len=strlen(p.right);
right=new char[len + 1];
memcpy(right, p.right, len + 1);
StatFormat *f=new StatFormat();
if(p.left[0]==0){
error(ErrorType::Error, E_BadFormatDeclaration, "Section \"%s\": line '%s = %s':\nMissing ID.", pszSectionName, left, right);
bRes=false;
}
else{
if(p.left[0]=='$') p.left++;
f->id=hextoi(p.left);
}
if(bRes){
char *ch=(char*)p.right;
if(*ch!='"'){
error(ErrorType::Error, E_BadFormatDeclaration, "Section \"%s\": line '%s = %s':\nExpected begining of string after \"%s =\".", pszSectionName, left, right, left);
bRes=false;
}
else{
ch++;
while(*ch!=0 && *ch!='"') ch++;
if(*ch==0){
error(ErrorType::Error, E_BadFormatDeclaration, "Section \"%s\": line '%s = %s':\nExpected end of string after \"%s\".", pszSectionName, left, right, right);
bRes=false;
}
else{
*ch=0;
bRes=parseFormatString(pszSectionName, f, (char*)p.right + 1);
if(bRes) formats.push_back(f);
}
}
}
return bRes;
}
//---------------------------------------------------------------------------------
bool isnum(char c)
{
return (c >= '0' && c <= '9');
}
//---------------------------------------------------------------------------------
bool Settings::parseFormatString(const char *pszSectionName, Settings::StatFormat *f, char *format)
{
bool bRes=true;
char *ch, *start;
start=format;
// if format begins with - a warning will be issued if such format is used in bob file
if(*start!=0 && *start=='-') {
start++;
f->issueWarning=true;
}
// skip any spaces after the '-'
while(*start==' ') start++;
while(*start!=0){
ch=start;
if(isnum(*ch)==false){
error(Error, E_BadFormatDeclaration, "Section \"%s\": line id $%x:\nMissing number at start of '%s'.", pszSectionName, f->id, format);
return false;
}
else{
while(isnum(*ch)) ch++;
if(*ch==0){
error(Error, E_BadFormatDeclaration, "Section \"%s\": line id $%x:\nMissing constant after '%s'.", pszSectionName, f->id, ch);
return false;
}
else{
StatFormat::token *t=new StatFormat::token();
char old=*ch;
*ch=0;
t->count=atoi(start);
t->type=old;
*ch=old;
t->numFormat=findNumberFormat(t->type);
if(t->numFormat==0){
error(Error, E_BadFormatDeclaration, "Section \"%s\": line id $%x:\nConstant \"%c\" not defined in '%s'.", pszSectionName, f->id, t->type, format);
delete t;
return false;
}
f->tokens.push_back(t);
// increase the cumulative count so it's easy to tell how many numbers is needed
// to match the format
f->cumulativeTokenCount+=t->count;
start=ch+1;
while(*ch!=0 && isnum(*ch)==false) ch++;
old=*ch;
*ch=0;
size_t size=ch-start;
if(size){
t->data=new char[size + 1];
memcpy(t->data, start, size + 1);
}
*ch=old;
start=ch;
}
}
}
return bRes;
}
//---------------------------------------------------------------------------------
Settings::NumberFormat * Settings::findNumberFormat(char ch)
{
char c;
for(NumberFormatList::iterator &it=m_constants.begin(); it!=m_constants.end(); ++it){
c=it->type;
if(c==ch) return *it;
}
return NULL;
}
//---------------------------------------------------------------------------------
#endif // defined(X2BC_USE_INI_FORMATS)