]> Shamusworld >> Repos - apple2/blob - src/settings.cpp
Added initial emulator configuration window, cleanup of settings code.
[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", "./disks/Pitch-Dark-20180731.2mg"));
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         CheckForTrailingSlash(settings.disksPath);
81 }
82
83
84 //
85 // Save Apple2's settings
86 //
87 void SaveSettings(void)
88 {
89         SDL_GetWindowPosition(sdlWindow, &settings.winX, &settings.winY);
90
91         SetValue("autoSaveState", settings.autoStateSaving);
92         SetValue("autoStateFilename", settings.autoStatePath);
93         SetValue("useJoystick", settings.useJoystick);
94         SetValue("joyport", settings.joyport);
95         SetValue("hardwareTypeNTSC", settings.hardwareTypeNTSC);
96         SetValue("fullscreen", settings.fullscreen);
97         SetValue("useOpenGL", settings.useOpenGL);
98         SetValue("glFilterType", settings.glFilter);
99         SetValue("renderType", settings.renderType);
100         SetValue("windowX", settings.winX);
101         SetValue("windowY", settings.winY);
102         SetValue("disks", settings.disksPath);
103         SetValue("harddrive1", settings.hd[0]);
104         SetValue("harddrive2", settings.hd[1]);
105         SetValue("harddrive3", settings.hd[2]);
106         SetValue("harddrive4", settings.hd[3]);
107         SetValue("harddrive5", settings.hd[4]);
108         SetValue("harddrive6", settings.hd[5]);
109         SetValue("harddrive7", settings.hd[6]);
110
111         UpdateConfigFile();
112 }
113
114
115 static int8_t FindConfig()
116 {
117         for(uint8_t i=0; i<5; i++)
118         {
119                 FILE * f = fopen(configPath[i], "r");
120
121                 if (f != NULL)
122                 {
123                         fclose(f);
124                         return i;
125                 }
126         }
127
128         return -1;
129 }
130
131
132 //
133 // Read & parse the configuration file into our keystore
134 //
135 static void ParseConfigFile(void)
136 {
137         configLoc = FindConfig();
138
139         if (configLoc == -1)
140         {
141                 WriteLog("Settings: Couldn't find configuration file. Using defaults...\n");
142                 return;
143         }
144
145         char * buf = (char *)ReadFile(configPath[configLoc]);
146         std::string s(buf);
147
148         const std::string delim = "\n\r";
149         std::string::size_type start = s.find_first_not_of(delim, 0);
150         std::string::size_type end   = s.find_first_of(delim, start);
151
152         while ((start != std::string::npos) || (end != std::string::npos))
153         {
154                 std::string sub = s.substr(start, end - start);
155
156                 if ((sub[0] != '#') && (sub[0] != '['))
157                 {
158                         std::string::size_type kStart = sub.find_first_not_of(" ", 0);
159                         std::string::size_type kEnd   = sub.find_first_of(" ", kStart);
160                         std::string::size_type vStart = sub.find_first_of(" =\t\n\r", 0);
161                         std::string::size_type vEnd   = sub.find_first_not_of(" =\t\n\r", vStart);
162
163                         if ((kStart != std::string::npos) && (kEnd != std::string::npos)
164                                 && (vStart != std::string::npos) && (vEnd != std::string::npos))
165                         {
166                                 keystore[sub.substr(kStart, kEnd - kStart)] = sub.substr(vEnd);
167                         }
168                 }
169
170                 start = s.find_first_not_of(delim, end);
171                 end   = s.find_first_of(delim, start);
172         }
173
174         free(buf);
175 }
176
177
178 static bool GetValue(const char * key, bool def)
179 {
180         if (keystore.find(key) == keystore.end())
181                 return def;
182
183         return (atoi(keystore[key].c_str()) == 0 ? false : true);
184 }
185
186
187 static int GetValue(const char * key, int def)
188 {
189         if (keystore.find(key) == keystore.end())
190                 return def;
191
192         return atoi(keystore[key].c_str());
193 }
194
195
196 static const char * GetValue(const char * key, const char * def)
197 {
198         if (keystore.find(key) == keystore.end())
199                 return def;
200
201         return keystore[key].c_str();
202 }
203
204
205 static void SetValue(const char * key, bool value)
206 {
207         keystore[key] = (value ? "1" : "0");
208 }
209
210
211 static void SetValue(const char * key, int value)
212 {
213         char buf[64];
214
215         sprintf(buf, "%i", value);
216         keystore[key] = buf;
217 }
218
219
220 static void SetValue(const char * key, unsigned int value)
221 {
222         char buf[64];
223
224         sprintf(buf, "%u", value);
225         keystore[key] = buf;
226 }
227
228
229 static void SetValue(const char * key, const char * value)
230 {
231         keystore[key] = value;
232 }
233
234
235 //
236 // Check path for a trailing slash, and append if not present
237 //
238 static void CheckForTrailingSlash(char * path)
239 {
240         uint32_t len = strlen(path);
241
242         // If the length is greater than zero, and the last char in the string is
243         // not a forward slash, and there's room for one more character, then add a
244         // trailing slash.
245         if ((len > 0) && (path[len - 1] != '/') && (len < MAX_PATH))
246                 strcat(path, "/");
247 }
248
249
250 //
251 // Update the values in the config file (if one exists) with updated values in
252 // the keystore.
253 //
254 static void UpdateConfigFile(void)
255 {
256         // Sanity check
257         if (configLoc == -1)
258         {
259                 WriteLog("Settings: Creating default config...\n");
260                 configLoc = 0;
261         }
262
263         char * buf = (char *)ReadFile(configPath[configLoc]);
264
265         FILE * f = fopen(configPath[configLoc], "w");
266
267         if (f == NULL)
268         {
269                 WriteLog("Settings: Could not open config file for writing!\n");
270                 free(buf);
271                 return;
272         }
273
274         std::string s(buf);
275
276         const std::string delim = "\n\r";
277         std::string::size_type start = 0;
278         std::string::size_type end   = s.find_first_of(delim, start);
279
280         while (end != std::string::npos)
281         {
282                 if (end > start)
283                 {
284                         std::string sub = s.substr(start, end - start);
285
286                         if ((sub[0] != '#') && (sub[0] != '['))
287                         {
288                                 std::string::size_type kStart = sub.find_first_not_of(" ", 0);
289                                 std::string::size_type kEnd   = sub.find_first_of(" ", kStart);
290
291                                 if ((kStart != std::string::npos)
292                                         && (kEnd != std::string::npos))
293                                 {
294                                         std::string key = sub.substr(kStart, kEnd - kStart);
295
296                                         if (keystore.find(key) != keystore.end())
297                                         {
298                                                 sub = key + " = " + keystore[key];
299                                                 keystore.erase(key);
300                                         }
301                                 }
302                         }
303
304                         fprintf(f, "%s\n", sub.c_str());
305                 }
306                 else
307                         fprintf(f, "\n");
308
309                 start = end + 1;
310                 end   = s.find_first_of(delim, start);
311         }
312
313         std::map<std::string, std::string>::iterator i;
314
315         for(i=keystore.begin(); i!=keystore.end(); i++)
316                 fprintf(f, "%s = %s\n", i->first.c_str(), i->second.c_str());
317
318         fclose(f);
319         free(buf);
320 }
321