]> Shamusworld >> Repos - apple2/blob - src/settings.cpp
First steps towards making config window/settings stick.
[apple2] / src / settings.cpp
1 //
2 // settings.cpp: Apple2 configuration loading/saving support
3 //
4 // by James Hammons
5 // (C) 2019 Underground Software
6 //
7
8 #include "settings.h"
9
10 #include <stdlib.h>
11 #include <map>
12 #include <string>
13 #include <SDL2/SDL.h>
14 #include "fileio.h"
15 #include "log.h"
16 #include "video.h"
17
18 // Global variables
19
20 Settings settings;
21
22 // Private variables
23
24 static const char configPath[5][32] = {
25         "./apple2.cfg",                 // CWD
26         "~/apple2.cfg",                 // Home directory
27         "~/.apple2/apple2.cfg", // Home under .apple2 directory
28         "/etc/apple2.cfg",              // /etc
29         "apple2.cfg"                    // Somewhere in the path
30 };
31
32 static int8_t configLoc = -1;
33 static std::map<std::string, std::string> keystore;
34
35 // Private function prototypes
36
37 static int8_t FindConfig(void);
38 static void ParseConfigFile(void);
39 static bool GetValue(const char *, bool);
40 static int GetValue(const char *, int);
41 static const char * GetValue(const char *, const char *);
42 static void SetValue(const char * key, bool value);
43 static void SetValue(const char * key, int value);
44 static void SetValue(const char * key, unsigned int value);
45 static void SetValue(const char * key, const char * value);
46 static void CheckForTrailingSlash(char * path);
47 static void UpdateConfigFile(void);
48
49
50 //
51 // Load Apple2's settings
52 //
53 void LoadSettings(void)
54 {
55         ParseConfigFile();
56
57         settings.useJoystick = GetValue("useJoystick", false);
58         settings.joyport = GetValue("joyport", 0);
59         settings.hardwareTypeNTSC = GetValue("hardwareTypeNTSC", true);
60         settings.fullscreen = GetValue("fullscreen", false);
61         settings.useOpenGL = GetValue("useOpenGL", true);
62         settings.glFilter = GetValue("glFilterType", 0);
63         settings.renderType = GetValue("renderType", 0);
64         settings.autoStateSaving = GetValue("autoSaveState", true);
65
66         settings.winX = GetValue("windowX", 250);
67         settings.winY = GetValue("windowY", 100);
68
69 //      strcpy(settings.BIOSPath, sdlemu_getval_string("BIOSROM", "./ROMs/apple2e-enhanced.rom"));
70         strcpy(settings.disksPath, GetValue("disks", "./disks/"));
71         strcpy(settings.hd[0], GetValue("harddrive1", ""));
72         strcpy(settings.hd[1], GetValue("harddrive2", ""));
73         strcpy(settings.hd[2], GetValue("harddrive3", ""));
74         strcpy(settings.hd[3], GetValue("harddrive4", ""));
75         strcpy(settings.hd[4], GetValue("harddrive5", ""));
76         strcpy(settings.hd[5], GetValue("harddrive6", ""));
77         strcpy(settings.hd[6], GetValue("harddrive7", ""));
78         strcpy(settings.autoStatePath, GetValue("autoStateFilename", "./apple2auto.state"));
79
80         settings.cardSlot[0] = GetValue("card1", 6);    // Disk ][
81         settings.cardSlot[1] = GetValue("card2", 0);    // Disk ][
82         settings.cardSlot[2] = GetValue("card3", 4);    // Mockingboard
83         settings.cardSlot[3] = GetValue("card4", 0);    // Mockingboard
84         settings.cardSlot[4] = GetValue("card5", 0);    // AHSSCSI
85
86         CheckForTrailingSlash(settings.disksPath);
87 }
88
89
90 //
91 // Save Apple2's settings
92 //
93 void SaveSettings(void)
94 {
95         SDL_GetWindowPosition(sdlWindow, &settings.winX, &settings.winY);
96
97         SetValue("autoSaveState", settings.autoStateSaving);
98         SetValue("autoStateFilename", settings.autoStatePath);
99         SetValue("useJoystick", settings.useJoystick);
100         SetValue("joyport", settings.joyport);
101         SetValue("hardwareTypeNTSC", settings.hardwareTypeNTSC);
102         SetValue("fullscreen", settings.fullscreen);
103         SetValue("useOpenGL", settings.useOpenGL);
104         SetValue("glFilterType", settings.glFilter);
105         SetValue("renderType", settings.renderType);
106         SetValue("windowX", settings.winX);
107         SetValue("windowY", settings.winY);
108         SetValue("disks", settings.disksPath);
109         SetValue("harddrive1", settings.hd[0]);
110         SetValue("harddrive2", settings.hd[1]);
111         SetValue("harddrive3", settings.hd[2]);
112         SetValue("harddrive4", settings.hd[3]);
113         SetValue("harddrive5", settings.hd[4]);
114         SetValue("harddrive6", settings.hd[5]);
115         SetValue("harddrive7", settings.hd[6]);
116         SetValue("card1", settings.cardSlot[0]);
117         SetValue("card2", settings.cardSlot[1]);
118         SetValue("card3", settings.cardSlot[2]);
119         SetValue("card4", settings.cardSlot[3]);
120         SetValue("card5", settings.cardSlot[4]);
121
122         UpdateConfigFile();
123 }
124
125
126 static int8_t FindConfig()
127 {
128         for(uint8_t i=0; i<5; i++)
129         {
130                 FILE * f = fopen(configPath[i], "r");
131
132                 if (f != NULL)
133                 {
134                         fclose(f);
135                         return i;
136                 }
137         }
138
139         return -1;
140 }
141
142
143 //
144 // Read & parse the configuration file into our keystore
145 //
146 static void ParseConfigFile(void)
147 {
148         configLoc = FindConfig();
149
150         if (configLoc == -1)
151         {
152                 WriteLog("Settings: Couldn't find configuration file. Using defaults...\n");
153                 return;
154         }
155
156         char * buf = (char *)ReadFile(configPath[configLoc]);
157         std::string s(buf);
158
159         const std::string delim = "\n\r";
160         std::string::size_type start = s.find_first_not_of(delim, 0);
161         std::string::size_type end   = s.find_first_of(delim, start);
162
163         while ((start != std::string::npos) || (end != std::string::npos))
164         {
165                 std::string sub = s.substr(start, end - start);
166
167                 if ((sub[0] != '#') && (sub[0] != '['))
168                 {
169                         std::string::size_type kStart = sub.find_first_not_of(" ", 0);
170                         std::string::size_type kEnd   = sub.find_first_of(" ", kStart);
171                         std::string::size_type vStart = sub.find_first_of(" =\t\n\r", 0);
172                         std::string::size_type vEnd   = sub.find_first_not_of(" =\t\n\r", vStart);
173
174                         if ((kStart != std::string::npos) && (kEnd != std::string::npos)
175                                 && (vStart != std::string::npos) && (vEnd != std::string::npos))
176                         {
177                                 keystore[sub.substr(kStart, kEnd - kStart)] = sub.substr(vEnd);
178                         }
179                 }
180
181                 start = s.find_first_not_of(delim, end);
182                 end   = s.find_first_of(delim, start);
183         }
184
185         free(buf);
186 }
187
188
189 static bool GetValue(const char * key, bool def)
190 {
191         if (keystore.find(key) == keystore.end())
192                 return def;
193
194         return (atoi(keystore[key].c_str()) == 0 ? false : true);
195 }
196
197
198 static int GetValue(const char * key, int def)
199 {
200         if (keystore.find(key) == keystore.end())
201                 return def;
202
203         return atoi(keystore[key].c_str());
204 }
205
206
207 static const char * GetValue(const char * key, const char * def)
208 {
209         if (keystore.find(key) == keystore.end())
210                 return def;
211
212         return keystore[key].c_str();
213 }
214
215
216 static void SetValue(const char * key, bool value)
217 {
218         keystore[key] = (value ? "1" : "0");
219 }
220
221
222 static void SetValue(const char * key, int value)
223 {
224         char buf[64];
225
226         sprintf(buf, "%i", value);
227         keystore[key] = buf;
228 }
229
230
231 static void SetValue(const char * key, unsigned int value)
232 {
233         char buf[64];
234
235         sprintf(buf, "%u", value);
236         keystore[key] = buf;
237 }
238
239
240 static void SetValue(const char * key, const char * value)
241 {
242         keystore[key] = value;
243 }
244
245
246 //
247 // Check path for a trailing slash, and append if not present
248 //
249 static void CheckForTrailingSlash(char * path)
250 {
251         uint32_t len = strlen(path);
252
253         // If the length is greater than zero, and the last char in the string is
254         // not a forward slash, and there's room for one more character, then add a
255         // trailing slash.
256         if ((len > 0) && (path[len - 1] != '/') && (len < MAX_PATH))
257                 strcat(path, "/");
258 }
259
260
261 //
262 // Update the values in the config file (if one exists) with updated values in
263 // the keystore.
264 //
265 static void UpdateConfigFile(void)
266 {
267         // Sanity check
268         if (configLoc == -1)
269         {
270                 WriteLog("Settings: Creating default config...\n");
271                 configLoc = 0;
272         }
273
274         char * buf = (char *)ReadFile(configPath[configLoc]);
275
276         FILE * f = fopen(configPath[configLoc], "w");
277
278         if (f == NULL)
279         {
280                 WriteLog("Settings: Could not open config file for writing!\n");
281                 free(buf);
282                 return;
283         }
284
285         std::string s(buf);
286
287         const std::string delim = "\n\r";
288         std::string::size_type start = 0;
289         std::string::size_type end   = s.find_first_of(delim, start);
290
291         while (end != std::string::npos)
292         {
293                 if (end > start)
294                 {
295                         std::string sub = s.substr(start, end - start);
296
297                         if ((sub[0] != '#') && (sub[0] != '['))
298                         {
299                                 std::string::size_type kStart = sub.find_first_not_of(" ", 0);
300                                 std::string::size_type kEnd   = sub.find_first_of(" ", kStart);
301
302                                 if ((kStart != std::string::npos)
303                                         && (kEnd != std::string::npos))
304                                 {
305                                         std::string key = sub.substr(kStart, kEnd - kStart);
306
307                                         if (keystore.find(key) != keystore.end())
308                                         {
309                                                 sub = key + " = " + keystore[key];
310                                                 keystore.erase(key);
311                                         }
312                                 }
313                         }
314
315                         fprintf(f, "%s\n", sub.c_str());
316                 }
317                 else
318                         fprintf(f, "\n");
319
320                 start = end + 1;
321                 end   = s.find_first_of(delim, start);
322         }
323
324         std::map<std::string, std::string>::iterator i;
325
326         for(i=keystore.begin(); i!=keystore.end(); i++)
327                 fprintf(f, "%s = %s\n", i->first.c_str(), i->second.c_str());
328
329         fclose(f);
330         free(buf);
331 }
332