| 1 | cycrow | 1 | #include "settings.h"
 | 
        
           |  |  | 2 | #include "../common/strutils.h"
 | 
        
           |  |  | 3 |   | 
        
           |  |  | 4 | #include <stdio.h>
 | 
        
           |  |  | 5 | #include <windows.h>
 | 
        
           |  |  | 6 |   | 
        
           |  |  | 7 | static Settings *g_settings;
 | 
        
           |  |  | 8 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 9 | #ifdef X2BC_USE_INI_FORMATS 
 | 
        
           |  |  | 10 | bool settings_parse_pair_const(const char *pszSectionName, Settings::conststringpair &p)
 | 
        
           |  |  | 11 | {
 | 
        
           |  |  | 12 | 	return g_settings->parseConstant(pszSectionName, p);
 | 
        
           |  |  | 13 | }
 | 
        
           |  |  | 14 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 15 | bool settings_parse_pair_format(const char *pszSectionName, Settings::conststringpair &p)
 | 
        
           |  |  | 16 | {
 | 
        
           |  |  | 17 | 	return g_settings->parseFormat(pszSectionName, p);
 | 
        
           |  |  | 18 | }
 | 
        
           |  |  | 19 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 20 | int CompareStatFormats(const void *a, const void *b)
 | 
        
           |  |  | 21 | {
 | 
        
           |  |  | 22 | 	int ida, idb;
 | 
        
           |  |  | 23 | 	ida=((Settings::StatFormat*)a)->id;
 | 
        
           |  |  | 24 | 	idb=((Settings::StatFormat*)b)->id;
 | 
        
           |  |  | 25 |   | 
        
           |  |  | 26 | 	return ((Settings::StatFormat*)a)->id - ((Settings::StatFormat*)b)->id;
 | 
        
           |  |  | 27 | }
 | 
        
           |  |  | 28 | #endif // defined(X2BC_USE_INI_FORMATS )
 | 
        
           |  |  | 29 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 30 | bool Settings::loadINI(const char *pszFileName)
 | 
        
           |  |  | 31 | {
 | 
        
           |  |  | 32 | 	bool bRes;
 | 
        
           |  |  | 33 | 	char szSectionName[50];
 | 
        
           |  |  | 34 |   | 
        
           |  |  | 35 | 	g_settings=this;
 | 
        
           |  |  | 36 | 	clearErrors();
 | 
        
           |  |  | 37 |   | 
        
           |  |  | 38 | 	GetPrivateProfileString(L"library", L"WriteWarnings", L"off", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
 | 
        
           |  |  | 39 | 	m_bOutputWarnings=(_stricmp(szSectionName, "on")==0);
 | 
        
           |  |  | 40 |   | 
        
           |  |  | 41 | 	GetPrivateProfileString(L"library", L"Convert", L"on", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
 | 
        
           |  |  | 42 | 	m_bConvert=(_stricmp(szSectionName, "on")==0);
 | 
        
           |  |  | 43 |   | 
        
           |  |  | 44 | 	GetPrivateProfileString(L"library", L"FrameWarnings", L"on", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
 | 
        
           |  |  | 45 | 	m_bStatFormatWarnings=(_stricmp(szSectionName, "on")==0);
 | 
        
           |  |  | 46 |   | 
        
           |  |  | 47 | 	GetPrivateProfileString(L"library", L"XtraPointInfo", L"on", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
 | 
        
           |  |  | 48 | 	m_bXtraPntInfo=(_stricmp(szSectionName, "on")==0);
 | 
        
           |  |  | 49 |   | 
        
           |  |  | 50 | 	GetPrivateProfileString(L"library", L"XtraX3BobInfo", L"off", (LPWSTR)szSectionName, sizeof(szSectionName), (LPCWSTR)pszFileName);
 | 
        
           |  |  | 51 | 	m_bXtraX3BobInfo=(_stricmp(szSectionName, "on")==0);
 | 
        
           |  |  | 52 |   | 
        
           |  |  | 53 | #ifdef X2BC_USE_INI_FORMATS
 | 
        
           |  |  | 54 | 	size_t size;
 | 
        
           |  |  | 55 |   | 
        
           |  |  | 56 | 	GetPrivateProfileString("library", "Constants", "Const", szSectionName, sizeof(szSectionName), pszFileName);
 | 
        
           |  |  | 57 |   | 
        
           |  |  | 58 | 	char *pszConstants=readSection(szSectionName, pszFileName, &size);
 | 
        
           |  |  | 59 | 	if(size==0){
 | 
        
           |  |  | 60 | 		error(Error, E_SectionEmpty, "Section with constants '%s' not defined or empty.", szSectionName);
 | 
        
           |  |  | 61 | 		bRes=false;
 | 
        
           |  |  | 62 | 	}
 | 
        
           |  |  | 63 | 	else
 | 
        
           |  |  | 64 | 		bRes=parseLines(szSectionName, pszConstants, size, settings_parse_pair_const);
 | 
        
           |  |  | 65 |   | 
        
           |  |  | 66 | 	delete[] pszConstants;
 | 
        
           |  |  | 67 |   | 
        
           |  |  | 68 | 	if(bRes){
 | 
        
           |  |  | 69 | 		GetPrivateProfileString("library", "Default", "Format", szSectionName, sizeof(szSectionName), pszFileName);
 | 
        
           |  |  | 70 | 		char *pszFormat=readSection(szSectionName, pszFileName, &size);
 | 
        
           |  |  | 71 | 		if(size==0){
 | 
        
           |  |  | 72 | 			error(Error, E_SectionEmpty, "Section with frame formats '%s' not defined or empty.", szSectionName);
 | 
        
           |  |  | 73 | 			bRes=false;
 | 
        
           |  |  | 74 | 		}
 | 
        
           |  |  | 75 | 		else
 | 
        
           |  |  | 76 | 			bRes=parseLines(szSectionName, pszFormat, size, settings_parse_pair_format);
 | 
        
           |  |  | 77 |   | 
        
           |  |  | 78 | 		delete[] pszFormat;
 | 
        
           |  |  | 79 | 	}
 | 
        
           |  |  | 80 | #else
 | 
        
           |  |  | 81 | 	bRes=true;
 | 
        
           |  |  | 82 | #endif // !defined(X2BC_USE_INI_FORMATS)
 | 
        
           |  |  | 83 | 	return bRes;
 | 
        
           |  |  | 84 | }
 | 
        
           |  |  | 85 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 86 | void Settings::error(ErrorType type, ErrorCodes code, const char *format, ...)
 | 
        
           |  |  | 87 | {
 | 
        
           |  |  | 88 | 	va_list ap;
 | 
        
           |  |  | 89 | 	va_start(ap, format);
 | 
        
           |  |  | 90 |   | 
        
           |  |  | 91 | 	ErrorMsg *e=new ErrorMsg();
 | 
        
           |  |  | 92 | 	e->type=type;
 | 
        
           |  |  | 93 | 	e->code=code;
 | 
        
           |  |  | 94 |   | 
        
           |  |  | 95 | 	_vsnprintf(e->message, sizeof(e->message), format, ap);
 | 
        
           |  |  | 96 | 	va_end(ap);
 | 
        
           |  |  | 97 |   | 
        
           |  |  | 98 | 	errors.push_back(e);
 | 
        
           |  |  | 99 | }
 | 
        
           |  |  | 100 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 101 |   | 
        
           |  |  | 102 | #ifdef X2BC_USE_INI_FORMATS
 | 
        
           |  |  | 103 | char * Settings::readSection(const char *pszSection, const char *pszFileName, size_t *size)
 | 
        
           |  |  | 104 | {
 | 
        
           |  |  | 105 | 	char *data;
 | 
        
           |  |  | 106 | 	int _size=0, res;
 | 
        
           |  |  | 107 |   | 
        
           |  |  | 108 | 	do{
 | 
        
           |  |  | 109 | 		_size+=1500;
 | 
        
           |  |  | 110 | 		data=new char[_size];
 | 
        
           |  |  | 111 | 		if(data==NULL) break;
 | 
        
           |  |  | 112 | 		res=GetPrivateProfileSection(pszSection, data, _size, pszFileName);
 | 
        
           |  |  | 113 | 		if(res==_size - 2){
 | 
        
           |  |  | 114 | 			delete[] data;
 | 
        
           |  |  | 115 | 		}
 | 
        
           |  |  | 116 | 	}
 | 
        
           |  |  | 117 | 	while(res==_size - 2);
 | 
        
           |  |  | 118 | 	if(size) *size=res;
 | 
        
           |  |  | 119 | 	return data;
 | 
        
           |  |  | 120 | }
 | 
        
           |  |  | 121 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 122 | bool Settings::parseLines(const char *pszSectionName, char *pszData, size_t size, ParsePairCallback *callback)
 | 
        
           |  |  | 123 | {
 | 
        
           |  |  | 124 | 	size_t count;
 | 
        
           |  |  | 125 | 	char **lines=lineexplode(pszData, size, &count);
 | 
        
           |  |  | 126 | 	bool bRes=true;
 | 
        
           |  |  | 127 |   | 
        
           |  |  | 128 | 	for(size_t i=0; i < count; i++){
 | 
        
           |  |  | 129 | 		char *line=lines[i];
 | 
        
           |  |  | 130 |   | 
        
           |  |  | 131 | 		int j=0;
 | 
        
           |  |  | 132 | 		bool bComment=false;
 | 
        
           |  |  | 133 | 		char *equal, *left, *right;
 | 
        
           |  |  | 134 |   | 
        
           |  |  | 135 | 		left=right=equal=0;
 | 
        
           |  |  | 136 |   | 
        
           |  |  | 137 | 		while(line[j]!=0){
 | 
        
           |  |  | 138 | 			switch(line[j]){
 | 
        
           |  |  | 139 | 				case '=':
 | 
        
           |  |  | 140 | 					line[j]=0;
 | 
        
           |  |  | 141 | 					equal=line + j;
 | 
        
           |  |  | 142 | 					left=line;
 | 
        
           |  |  | 143 | 					break;
 | 
        
           |  |  | 144 | 				case ';':
 | 
        
           |  |  | 145 | 					line[j]=0;
 | 
        
           |  |  | 146 | 					j--; // so the main while(...) will encouter this added 0 and terminate
 | 
        
           |  |  | 147 | 					break;
 | 
        
           |  |  | 148 | 			}
 | 
        
           |  |  | 149 | 			j++;
 | 
        
           |  |  | 150 | 		}
 | 
        
           |  |  | 151 | 		if(equal){
 | 
        
           |  |  | 152 | 			right=equal + 1;
 | 
        
           |  |  | 153 |   | 
        
           |  |  | 154 | 			conststringpair p=parsePair(left, right);
 | 
        
           |  |  | 155 | 			if(callback(pszSectionName, p)==false) {
 | 
        
           |  |  | 156 | 				bRes=false;
 | 
        
           |  |  | 157 | 				break; // break if parsing fails
 | 
        
           |  |  | 158 | 			}
 | 
        
           |  |  | 159 | 		}
 | 
        
           |  |  | 160 | 		else
 | 
        
           |  |  | 161 | 			error(Warning, W_LineIgnored, "Section \"%s\": line '%s' ignored.", pszSectionName, line);
 | 
        
           |  |  | 162 | 	}
 | 
        
           |  |  | 163 |   | 
        
           |  |  | 164 | 	delete[] lines;
 | 
        
           |  |  | 165 | 	return bRes;
 | 
        
           |  |  | 166 | }
 | 
        
           |  |  | 167 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 168 | // trim white spaces from left and right
 | 
        
           |  |  | 169 | Settings::conststringpair Settings::parsePair(const char *left, const char *right)
 | 
        
           |  |  | 170 | {
 | 
        
           |  |  | 171 | 	conststringpair p;
 | 
        
           |  |  | 172 | 	p.left=trim((char*)left);
 | 
        
           |  |  | 173 | 	p.right=trim((char*)right);
 | 
        
           |  |  | 174 | 	return p;
 | 
        
           |  |  | 175 | }
 | 
        
           |  |  | 176 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 177 | bool Settings::parseConstant(const char *pszSectionName, Settings::conststringpair &p)
 | 
        
           |  |  | 178 | {
 | 
        
           |  |  | 179 | 	bool res=true;
 | 
        
           |  |  | 180 | 	NumberFormat *f=new NumberFormat();
 | 
        
           |  |  | 181 | 	const char *pszMultiplier=0, *pszFormat=0;
 | 
        
           |  |  | 182 | 	char *left, *right;
 | 
        
           |  |  | 183 |   | 
        
           |  |  | 184 | 	// backup the original strings for error reporting
 | 
        
           |  |  | 185 | 	size_t len=strlen(p.left);
 | 
        
           |  |  | 186 | 	left=new char[len + 1];
 | 
        
           |  |  | 187 | 	memcpy(left, p.left, len + 1);
 | 
        
           |  |  | 188 | 	len=strlen(p.right);
 | 
        
           |  |  | 189 | 	right=new char[len + 1];
 | 
        
           |  |  | 190 | 	memcpy(right, p.right, len + 1);
 | 
        
           |  |  | 191 |   | 
        
           |  |  | 192 | 	// the left operand (constant name)
 | 
        
           |  |  | 193 | 	if(*p.left==0){
 | 
        
           |  |  | 194 | 		error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nMissing constant name.", pszSectionName, left, right);
 | 
        
           |  |  | 195 | 		res=false;
 | 
        
           |  |  | 196 | 	}
 | 
        
           |  |  | 197 | 	else if(strlen(p.left) > 1){
 | 
        
           |  |  | 198 | 		error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nConstant name must be exactly 1 character.", pszSectionName, left, right);
 | 
        
           |  |  | 199 | 		res=false;
 | 
        
           |  |  | 200 | 	}
 | 
        
           |  |  | 201 | 	else if(!((*p.left | 0x20) > 'a') && ((*p.left | 0x20) < 'z')){
 | 
        
           |  |  | 202 | 		error(Error, E_BadConstantDeclaration, "Section \"%s\": Constant \"%c\": constant name must be a upper or lowercase character (A - Z).", pszSectionName, *p.left);
 | 
        
           |  |  | 203 | 		res=false;
 | 
        
           |  |  | 204 | 	}
 | 
        
           |  |  | 205 | 	if(res==false){
 | 
        
           |  |  | 206 | 		delete[] left; delete[] right;
 | 
        
           |  |  | 207 | 		return res;
 | 
        
           |  |  | 208 | 	}
 | 
        
           |  |  | 209 | 	f->type=*p.left;
 | 
        
           |  |  | 210 |   | 
        
           |  |  | 211 | 	// the right operand (constant multiplier and format)
 | 
        
           |  |  | 212 | 	pszMultiplier=p.right;
 | 
        
           |  |  | 213 | 	char *pos=strchr(p.right, ',');
 | 
        
           |  |  | 214 | 	if(pos){
 | 
        
           |  |  | 215 | 		*pos=0;
 | 
        
           |  |  | 216 | 		pszFormat=trim(++pos);
 | 
        
           |  |  | 217 | 	}	
 | 
        
           |  |  | 218 | 	if(pszMultiplier==0 || *pszMultiplier==0){
 | 
        
           |  |  | 219 | 		error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nMissing constant multiplier.", pszSectionName, left, right);
 | 
        
           |  |  | 220 | 		res=false;
 | 
        
           |  |  | 221 | 	}
 | 
        
           |  |  | 222 | 	else if(pszFormat==0 || *pszFormat==0){	
 | 
        
           |  |  | 223 | 		error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nMissing output format specifier.", pszSectionName, left, right);
 | 
        
           |  |  | 224 | 		res=false;
 | 
        
           |  |  | 225 | 	}
 | 
        
           |  |  | 226 | 	else{
 | 
        
           |  |  | 227 | 		f->multiplier=atof(pszMultiplier);
 | 
        
           |  |  | 228 | 		if(f->multiplier==0){
 | 
        
           |  |  | 229 | 			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);
 | 
        
           |  |  | 230 | 		}
 | 
        
           |  |  | 231 | 	}
 | 
        
           |  |  | 232 | 	if(res==true){
 | 
        
           |  |  | 233 | 		if(stricmp(pszFormat, "integer")==0)
 | 
        
           |  |  | 234 | 			f->outformat=NumberFormat::Integer;
 | 
        
           |  |  | 235 | 		else if(stricmp(pszFormat, "float")==0)
 | 
        
           |  |  | 236 | 			f->outformat=NumberFormat::Float;
 | 
        
           |  |  | 237 | 		else{
 | 
        
           |  |  | 238 | 			error(ErrorType::Error, E_BadConstantDeclaration, "Section \"%s\": line: '%s = %s':\nUnknown output format '%s'.", pszSectionName, left, right, pszFormat);
 | 
        
           |  |  | 239 | 			res=false;
 | 
        
           |  |  | 240 | 		}
 | 
        
           |  |  | 241 | 	}
 | 
        
           |  |  | 242 | 	delete[] left;
 | 
        
           |  |  | 243 | 	delete[] right;
 | 
        
           |  |  | 244 |   | 
        
           |  |  | 245 | 	if(res)
 | 
        
           |  |  | 246 | 		m_constants.push_back(f);
 | 
        
           |  |  | 247 |   | 
        
           |  |  | 248 | 	return res;
 | 
        
           |  |  | 249 | }
 | 
        
           |  |  | 250 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 251 | bool Settings::parseFormat(const char *pszSectionName, conststringpair &p)
 | 
        
           |  |  | 252 | {
 | 
        
           |  |  | 253 | 	bool bRes;
 | 
        
           |  |  | 254 | 	switch(p.left[0]){
 | 
        
           |  |  | 255 | 		case 0:
 | 
        
           |  |  | 256 | 			error(ErrorType::Error, E_BadFormatDeclaration, "Section \"%s\": invalid line format: '%s = %s':\nID expected.", pszSectionName, p.left, p.right);
 | 
        
           |  |  | 257 | 			bRes=false;
 | 
        
           |  |  | 258 | 			break;
 | 
        
           |  |  | 259 | 		case '$':
 | 
        
           |  |  | 260 | 			bRes=parseStatFormat(pszSectionName, p);
 | 
        
           |  |  | 261 | 			break;
 | 
        
           |  |  | 262 | 		case 'N': // don't read the N constants - we use algorithm instead if INI
 | 
        
           |  |  | 263 | 			bRes=true;
 | 
        
           |  |  | 264 | 			break;
 | 
        
           |  |  | 265 | 		default:
 | 
        
           |  |  | 266 | 			error(Warning, W_LineIgnored, "Section \"%s\": ignoring line '%s = %s':\nUnknown ID type.", pszSectionName, p.left, p.right);
 | 
        
           |  |  | 267 | 			bRes=true;
 | 
        
           |  |  | 268 |   | 
        
           |  |  | 269 | 	}
 | 
        
           |  |  | 270 | 	return bRes;
 | 
        
           |  |  | 271 | }
 | 
        
           |  |  | 272 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 273 | bool Settings::parseStatFormat(const char *pszSectionName, conststringpair &p)
 | 
        
           |  |  | 274 | {
 | 
        
           |  |  | 275 | 	char *left, *right;
 | 
        
           |  |  | 276 | 	bool bRes=true;
 | 
        
           |  |  | 277 | 	// backup the original strings for error reporting
 | 
        
           |  |  | 278 | 	size_t len=strlen(p.left);
 | 
        
           |  |  | 279 | 	left=new char[len + 1];
 | 
        
           |  |  | 280 | 	memcpy(left, p.left, len + 1);
 | 
        
           |  |  | 281 | 	len=strlen(p.right);
 | 
        
           |  |  | 282 | 	right=new char[len + 1];
 | 
        
           |  |  | 283 | 	memcpy(right, p.right, len + 1);
 | 
        
           |  |  | 284 |   | 
        
           |  |  | 285 | 	StatFormat *f=new StatFormat();
 | 
        
           |  |  | 286 |   | 
        
           |  |  | 287 | 	if(p.left[0]==0){
 | 
        
           |  |  | 288 | 		error(ErrorType::Error, E_BadFormatDeclaration, "Section \"%s\": line '%s = %s':\nMissing ID.", pszSectionName, left, right);
 | 
        
           |  |  | 289 | 		bRes=false;
 | 
        
           |  |  | 290 | 	}
 | 
        
           |  |  | 291 | 	else{
 | 
        
           |  |  | 292 | 		if(p.left[0]=='$') p.left++;
 | 
        
           |  |  | 293 | 		f->id=hextoi(p.left);
 | 
        
           |  |  | 294 | 	}
 | 
        
           |  |  | 295 | 	if(bRes){
 | 
        
           |  |  | 296 | 		char *ch=(char*)p.right;
 | 
        
           |  |  | 297 | 		if(*ch!='"'){
 | 
        
           |  |  | 298 | 			error(ErrorType::Error, E_BadFormatDeclaration, "Section \"%s\": line '%s = %s':\nExpected begining of string after \"%s =\".", pszSectionName, left, right, left);
 | 
        
           |  |  | 299 | 			bRes=false;
 | 
        
           |  |  | 300 | 		}
 | 
        
           |  |  | 301 | 		else{
 | 
        
           |  |  | 302 | 			ch++;
 | 
        
           |  |  | 303 | 			while(*ch!=0 && *ch!='"') ch++;
 | 
        
           |  |  | 304 | 			if(*ch==0){
 | 
        
           |  |  | 305 | 				error(ErrorType::Error, E_BadFormatDeclaration, "Section \"%s\": line '%s = %s':\nExpected end of string after \"%s\".", pszSectionName, left, right, right);
 | 
        
           |  |  | 306 | 				bRes=false;
 | 
        
           |  |  | 307 | 			}
 | 
        
           |  |  | 308 | 			else{
 | 
        
           |  |  | 309 | 				*ch=0;
 | 
        
           |  |  | 310 | 				bRes=parseFormatString(pszSectionName, f, (char*)p.right + 1);
 | 
        
           |  |  | 311 | 				if(bRes) formats.push_back(f);
 | 
        
           |  |  | 312 | 			}
 | 
        
           |  |  | 313 | 		}
 | 
        
           |  |  | 314 | 	}
 | 
        
           |  |  | 315 |   | 
        
           |  |  | 316 | 	return bRes;
 | 
        
           |  |  | 317 | }
 | 
        
           |  |  | 318 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 319 | bool isnum(char c)
 | 
        
           |  |  | 320 | {
 | 
        
           |  |  | 321 | 	return (c >= '0' && c <= '9');
 | 
        
           |  |  | 322 | }
 | 
        
           |  |  | 323 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 324 | bool Settings::parseFormatString(const char *pszSectionName, Settings::StatFormat *f, char *format)
 | 
        
           |  |  | 325 | {
 | 
        
           |  |  | 326 | 	bool bRes=true;
 | 
        
           |  |  | 327 |   | 
        
           |  |  | 328 | 	char *ch, *start;
 | 
        
           |  |  | 329 | 	start=format;
 | 
        
           |  |  | 330 |   | 
        
           |  |  | 331 | 	// if format begins with - a warning will be issued if such format is used in bob file
 | 
        
           |  |  | 332 | 	if(*start!=0 && *start=='-') {
 | 
        
           |  |  | 333 | 		start++;
 | 
        
           |  |  | 334 | 		f->issueWarning=true;
 | 
        
           |  |  | 335 | 	}
 | 
        
           |  |  | 336 | 	// skip any spaces after the '-'
 | 
        
           |  |  | 337 | 	while(*start==' ') start++;
 | 
        
           |  |  | 338 |   | 
        
           |  |  | 339 | 	while(*start!=0){
 | 
        
           |  |  | 340 | 		ch=start;
 | 
        
           |  |  | 341 | 		if(isnum(*ch)==false){
 | 
        
           |  |  | 342 | 			error(Error, E_BadFormatDeclaration, "Section \"%s\": line id $%x:\nMissing number at start of '%s'.", pszSectionName, f->id, format);
 | 
        
           |  |  | 343 | 			return false;
 | 
        
           |  |  | 344 | 		}
 | 
        
           |  |  | 345 | 		else{
 | 
        
           |  |  | 346 | 			while(isnum(*ch)) ch++;
 | 
        
           |  |  | 347 | 			if(*ch==0){
 | 
        
           |  |  | 348 | 				error(Error, E_BadFormatDeclaration, "Section \"%s\": line id $%x:\nMissing constant after '%s'.", pszSectionName, f->id, ch);
 | 
        
           |  |  | 349 | 				return false;
 | 
        
           |  |  | 350 | 			}
 | 
        
           |  |  | 351 | 			else{
 | 
        
           |  |  | 352 | 				StatFormat::token *t=new StatFormat::token();
 | 
        
           |  |  | 353 | 				char old=*ch;
 | 
        
           |  |  | 354 | 				*ch=0;
 | 
        
           |  |  | 355 | 				t->count=atoi(start);
 | 
        
           |  |  | 356 | 				t->type=old;
 | 
        
           |  |  | 357 | 				*ch=old;
 | 
        
           |  |  | 358 |   | 
        
           |  |  | 359 | 				t->numFormat=findNumberFormat(t->type);
 | 
        
           |  |  | 360 | 				if(t->numFormat==0){
 | 
        
           |  |  | 361 | 					error(Error, E_BadFormatDeclaration, "Section \"%s\": line id $%x:\nConstant \"%c\" not defined in '%s'.", pszSectionName, f->id, t->type, format);
 | 
        
           |  |  | 362 | 					delete t;
 | 
        
           |  |  | 363 | 					return false;
 | 
        
           |  |  | 364 | 				}
 | 
        
           |  |  | 365 | 				f->tokens.push_back(t);
 | 
        
           |  |  | 366 | 				// increase the cumulative count so it's easy to tell how many numbers is needed 
 | 
        
           |  |  | 367 | 				// to match the format
 | 
        
           |  |  | 368 | 				f->cumulativeTokenCount+=t->count; 
 | 
        
           |  |  | 369 |   | 
        
           |  |  | 370 | 				start=ch+1;
 | 
        
           |  |  | 371 | 				while(*ch!=0 && isnum(*ch)==false) ch++;
 | 
        
           |  |  | 372 | 				old=*ch;
 | 
        
           |  |  | 373 | 				*ch=0;
 | 
        
           |  |  | 374 | 				size_t size=ch-start;
 | 
        
           |  |  | 375 | 				if(size){
 | 
        
           |  |  | 376 | 					t->data=new char[size + 1];
 | 
        
           |  |  | 377 | 					memcpy(t->data, start, size + 1);
 | 
        
           |  |  | 378 | 				}
 | 
        
           |  |  | 379 | 				*ch=old;
 | 
        
           |  |  | 380 | 				start=ch;
 | 
        
           |  |  | 381 | 			}
 | 
        
           |  |  | 382 | 		}
 | 
        
           |  |  | 383 | 	}
 | 
        
           |  |  | 384 | 	return bRes;
 | 
        
           |  |  | 385 | }
 | 
        
           |  |  | 386 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 387 | Settings::NumberFormat * Settings::findNumberFormat(char ch)
 | 
        
           |  |  | 388 | {
 | 
        
           |  |  | 389 | 	char c;
 | 
        
           |  |  | 390 | 	for(NumberFormatList::iterator &it=m_constants.begin(); it!=m_constants.end(); ++it){
 | 
        
           |  |  | 391 | 		c=it->type;
 | 
        
           |  |  | 392 | 		if(c==ch) return *it;
 | 
        
           |  |  | 393 | 	}
 | 
        
           |  |  | 394 | 	return NULL;
 | 
        
           |  |  | 395 | }
 | 
        
           |  |  | 396 | //---------------------------------------------------------------------------------
 | 
        
           |  |  | 397 | #endif // defined(X2BC_USE_INI_FORMATS)
 |