Subversion Repositories spk

Rev

Rev 1 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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)