1 /***************************************************************************
2 IniConfig.cpp - Sidplay2 config file reader.
3 -------------------
4 begin : Sun Mar 25 2001
5 copyright : (C) 2000 by Simon White
6 email : s_a_white@email.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17 /***************************************************************************
18 * $Log: IniConfig.cpp,v $
19 * Revision 1.12 2004/02/26 18:17:27 s_a_white
20 * Use ini_readBool for boolean parameters rather than ini_readInt.
21 *
22 * Revision 1.11 2002/02/18 20:05:52 s_a_white
23 * Fixed for new libini ini_open call.
24 *
25 * Revision 1.10 2001/11/16 19:30:45 s_a_white
26 * Libsidutils support update.
27 *
28 * Revision 1.9 2001/08/30 21:40:51 s_a_white
29 * libini-1.1.7 update.
30 *
31 * Revision 1.8 2001/08/20 18:28:55 s_a_white
32 * MOS8580 fixed so that nothing means correct revision, 0 is 6581 and
33 * 1 is 8580.
34 *
35 * Revision 1.7 2001/07/14 16:52:56 s_a_white
36 * Removed warning.
37 *
38 * Revision 1.6 2001/07/03 17:50:14 s_a_white
39 * External filter no longer supported. This filter is needed internally by the
40 * library.
41 *
42 * Revision 1.5 2001/04/09 17:11:03 s_a_white
43 * Added INI file version number so theres a possibility for automated updates
44 * should the keys/sections change names (or meaning).
45 *
46 * Revision 1.4 2001/03/27 19:35:33 s_a_white
47 * Moved default record length for wav files from main.cpp to IniConfig.cpp.
48 *
49 * Revision 1.3 2001/03/27 19:00:49 s_a_white
50 * Default record and play lengths can now be set in the sidplay2.ini file.
51 *
52 * Revision 1.2 2001/03/26 18:13:07 s_a_white
53 * Support individual filters for 6581 and 8580.
54 *
55 ***************************************************************************/
56
57 #include <stdlib.h>
58 #include <string.h>
59 #include <sidplay/sidplay2.h>
60 #include "config.h"
61 #include "IniConfig.h"
62
63 #ifdef HAVE_UNIX
64 # include <sys/types.h>
65 # include <sys/stat.h> /* mkdir */
66 # include <dirent.h> /* opendir */
67 #endif
68
69 #define SAFE_FREE(p) { if(p) { free (p); (p)=NULL; } }
70 const char *IniConfig::DIR_NAME = ".sidplay";
71 const char *IniConfig::FILE_NAME = "sidplay2.ini";
72
73
IniConfig()74 IniConfig::IniConfig ()
75 :status(true)
76 { // Initialise everything else
77 sidplay2_s.database = NULL;
78 emulation_s.filter6581 = NULL;
79 emulation_s.filter8580 = NULL;
80 clear ();
81 }
82
83
~IniConfig()84 IniConfig::~IniConfig ()
85 {
86 clear ();
87 }
88
89
clear()90 void IniConfig::clear ()
91 {
92 sidplay2_s.version = 1; // INI File Version
93 SAFE_FREE (sidplay2_s.database);
94 sidplay2_s.playLength = 0; // INFINITE
95 sidplay2_s.recordLength = 3 * 60 + 30; // 3.5 minutes
96
97 console_s.ansi = false;
98 console_s.topLeft = '+';
99 console_s.topRight = '+';
100 console_s.bottomLeft = '+';
101 console_s.bottomRight = '+';
102 console_s.vertical = '|';
103 console_s.horizontal = '-';
104 console_s.junctionLeft = '+';
105 console_s.junctionRight = '+';
106
107 audio_s.frequency = SID2_DEFAULT_SAMPLING_FREQ;
108 audio_s.playback = sid2_mono;
109 audio_s.precision = SID2_DEFAULT_PRECISION;
110
111 emulation_s.clockSpeed = SID2_CLOCK_CORRECT;
112 emulation_s.clockForced = false;
113 emulation_s.sidModel = SID2_MODEL_CORRECT;
114 emulation_s.filter = true;
115 emulation_s.optimiseLevel = SID2_DEFAULT_OPTIMISATION;
116 emulation_s.sidSamples = true;
117
118 SAFE_FREE (emulation_s.filter6581);
119 SAFE_FREE (emulation_s.filter8580);
120 }
121
122
readInt(ini_fd_t ini,char * key,int & value)123 bool IniConfig::readInt (ini_fd_t ini, char *key, int &value)
124 {
125 int i = value;
126 if (ini_locateKey (ini, key) < 0)
127 { // Dosen't exist, add it
128 (void) ini_writeString (ini, "");
129 }
130 if (ini_readInt (ini, &i) < 0)
131 return false;
132 value = i;
133 return true;
134 }
135
136
readString(ini_fd_t ini,char * key,char * & str)137 bool IniConfig::readString (ini_fd_t ini, char *key, char *&str)
138 {
139 char *ret;
140 size_t length;
141
142 if (ini_locateKey (ini, key) < 0)
143 { // Dosen't exist, add it
144 (void) ini_writeString (ini, "");
145 }
146
147 length = (size_t) ini_dataLength (ini);
148 if (!length)
149 return 0;
150
151 ret = (char *) malloc (++length);
152 if (!ret)
153 return false;
154
155 if (ini_readString (ini, ret, (uint) length) < 0)
156 goto IniCofig_readString_error;
157
158 str = ret;
159 return true;
160
161 IniCofig_readString_error:
162 if (str)
163 free (str);
164 return false;
165 }
166
167
readBool(ini_fd_t ini,char * key,bool & boolean)168 bool IniConfig::readBool (ini_fd_t ini, char *key, bool &boolean)
169 {
170 int b = boolean;
171 if (ini_locateKey (ini, key) < 0)
172 { // Dosen't exist, add it
173 (void) ini_writeString (ini, "");
174 }
175 if (ini_readBool (ini, &b) < 0)
176 return false;
177 boolean = (b != 0);
178 return true;
179 }
180
181
readChar(ini_fd_t ini,char * key,char & ch)182 bool IniConfig::readChar (ini_fd_t ini, char *key, char &ch)
183 {
184 char *str, c = 0;
185 bool ret = readString (ini, key, str);
186 if (!ret)
187 return false;
188
189 // Check if we have an actual chanracter
190 if (str[0] == '\'')
191 {
192 if (str[2] != '\'')
193 ret = false;
194 else
195 c = str[1];
196 } // Nope is number
197 else
198 c = (char) atoi (str);
199
200 // Clip off special characters
201 if ((unsigned) c >= 32)
202 ch = c;
203
204 free (str);
205 return ret;
206 }
207
208
readTime(ini_fd_t ini,char * key,int & value)209 bool IniConfig::readTime (ini_fd_t ini, char *key, int &value)
210 {
211 char *str, *sep;
212 int time;
213 bool ret = readString (ini, key, str);
214 if (!ret)
215 return false;
216
217 if (!*str)
218 return false;
219
220 sep = strstr (str, ":");
221 if (!sep)
222 { // User gave seconds
223 time = atoi (str);
224 }
225 else
226 { // Read in MM:SS format
227 int val;
228 *sep = '\0';
229 val = atoi (str);
230 if (val < 0 || val > 99)
231 goto IniCofig_readTime_error;
232 time = val * 60;
233 val = atoi (sep + 1);
234 if (val < 0 || val > 59)
235 goto IniCofig_readTime_error;
236 time += val;
237 }
238
239 value = time;
240 free (str);
241 return ret;
242
243 IniCofig_readTime_error:
244 free (str);
245 return false;
246 }
247
248
readSidplay2(ini_fd_t ini)249 bool IniConfig::readSidplay2 (ini_fd_t ini)
250 {
251 bool ret = true;
252 int time, version = sidplay2_s.version;
253
254 (void) ini_locateHeading (ini, "SIDPlay2");
255 ret &= readInt (ini, "Version", version);
256 if (version > 0)
257 sidplay2_s.version = version;
258
259 ret &= readString (ini, "Songlength Database", sidplay2_s.database);
260 if (readTime (ini, "Default Play Length", time))
261 sidplay2_s.playLength = (uint_least32_t) time;
262 if (readTime (ini, "Default Record Length", time))
263 sidplay2_s.recordLength = (uint_least32_t) time;
264
265 return ret;
266 }
267
268
readConsole(ini_fd_t ini)269 bool IniConfig::readConsole (ini_fd_t ini)
270 {
271 bool ret = true;
272 (void) ini_locateHeading (ini, "Console");
273 ret &= readBool (ini, "Ansi", console_s.ansi);
274 ret &= readChar (ini, "Char Top Left", console_s.topLeft);
275 ret &= readChar (ini, "Char Top Right", console_s.topRight);
276 ret &= readChar (ini, "Char Bottom Left", console_s.bottomLeft);
277 ret &= readChar (ini, "Char Bottom Right", console_s.bottomRight);
278 ret &= readChar (ini, "Char Vertical", console_s.vertical);
279 ret &= readChar (ini, "Char Horizontal", console_s.horizontal);
280 ret &= readChar (ini, "Char Junction Left", console_s.junctionLeft);
281 ret &= readChar (ini, "Char Junction Right", console_s.junctionRight);
282 return ret;
283 }
284
285
readAudio(ini_fd_t ini)286 bool IniConfig::readAudio (ini_fd_t ini)
287 {
288 bool ret = true;
289 (void) ini_locateHeading (ini, "Audio");
290
291 {
292 int frequency = (int) audio_s.frequency;
293 ret &= readInt (ini, "Frequency", frequency);
294 audio_s.frequency = (unsigned long) frequency;
295 }
296
297 {
298 int channels = 0;
299 ret &= readInt (ini, "Channels", channels);
300 if (channels)
301 {
302 audio_s.playback = sid2_mono;
303 if (channels != 1)
304 audio_s.playback = sid2_stereo;
305 }
306 }
307
308 ret &= readInt (ini, "BitsPerSample", audio_s.precision);
309 return ret;
310 }
311
312
readEmulation(ini_fd_t ini)313 bool IniConfig::readEmulation (ini_fd_t ini)
314 {
315 bool ret = true;
316 (void) ini_locateHeading (ini, "Emulation");
317
318 {
319 int clockSpeed = -1;
320 ret &= readInt (ini, "ClockSpeed", clockSpeed);
321 if (clockSpeed != -1)
322 {
323 if (clockSpeed < 0 || clockSpeed > 1)
324 ret = false;
325 emulation_s.clockSpeed = SID2_CLOCK_PAL;
326 if (clockSpeed)
327 emulation_s.clockSpeed = SID2_CLOCK_NTSC;
328 }
329 }
330
331 ret &= readBool (ini, "ForceSongSpeed", emulation_s.clockForced);
332
333 {
334 int mos8580 = -1;
335 ret &= readInt (ini, "MOS8580", mos8580);
336 if (mos8580 != -1)
337 {
338 if (mos8580 < 0 || mos8580 > 1)
339 ret = false;
340 emulation_s.sidModel = SID2_MOS6581;
341 if (mos8580)
342 emulation_s.sidModel = SID2_MOS8580;
343 }
344 }
345
346 ret &= readBool (ini, "UseFilter", emulation_s.filter);
347
348 {
349 int optimiseLevel = -1;
350 ret &= readInt (ini, "OptimiseLevel", optimiseLevel);
351 if (optimiseLevel != -1)
352 emulation_s.optimiseLevel = optimiseLevel;
353 }
354
355 ret &= readString (ini, "Filter6581", emulation_s.filter6581);
356 ret &= readString (ini, "Filter8580", emulation_s.filter8580);
357 ret &= readBool (ini, "SidSamples", emulation_s.sidSamples);
358
359 // These next two change the ini section!
360 if (emulation_s.filter6581)
361 { // Try to load the filter
362 filter6581.read (ini, emulation_s.filter6581);
363 if (!filter6581)
364 {
365 filter6581.read (emulation_s.filter6581);
366 if (!filter6581)
367 ret = false;
368 }
369 }
370
371 if (emulation_s.filter8580)
372 { // Try to load the filter
373 filter8580.read (ini, emulation_s.filter8580);
374 if (!filter8580)
375 {
376 filter8580.read (emulation_s.filter8580);
377 if (!filter8580)
378 ret = false;
379 }
380 }
381
382 return ret;
383 }
384
385
read()386 void IniConfig::read ()
387 {
388 char *path = (char *) getenv ("HOME");
389 ini_fd_t ini = 0;
390 char *configPath;
391 size_t length;
392
393 if (!path)
394 path = (char *) getenv ("windir");
395
396 if (!path)
397 path = "";
398
399 length = strlen (path) + strlen (DIR_NAME) + strlen (FILE_NAME) + 3;
400 configPath = (char *) malloc (length);
401 if (!configPath)
402 goto IniConfig_read_error;
403
404 { // Format path from system
405 char *s = path;
406 while (*s != '\0')
407 {
408 if (*s == '\\')
409 *s = '/';
410 s++;
411 }
412 }
413
414 #ifdef HAVE_UNIX
415 sprintf (configPath, "%s/%s", path, DIR_NAME);
416
417 // Make sure the config path exists
418 if (!opendir (configPath))
419 mkdir (configPath, 0755);
420
421 sprintf (configPath, "%s/%s", configPath, FILE_NAME);
422 #else
423 sprintf (configPath, "%s/%s", path, FILE_NAME);
424 #endif
425
426 // Opens an existing file or creates a new one
427 ini = ini_open (configPath, "w", ";");
428
429 // Unable to open file?
430 if (!ini)
431 goto IniConfig_read_error;
432
433 clear ();
434
435 // This may not exist here...
436 status &= readSidplay2 (ini);
437 status &= readConsole (ini);
438 status &= readAudio (ini);
439 status &= readEmulation (ini);
440 ini_close (ini);
441 return;
442
443 IniConfig_read_error:
444 if (ini)
445 ini_close (ini);
446 clear ();
447 status = false;
448 }
449
filter(sid2_model_t model)450 const sid_filter_t* IniConfig::filter (sid2_model_t model)
451 {
452 if (model == SID2_MOS8580)
453 return filter8580.provide ();
454 return filter6581.provide ();
455 }
456