2 // settings.cpp: Apple2 configuration loading/saving support
5 // (C) 2019 Underground Software
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
32 static int8_t configLoc = -1;
33 static std::map<std::string, std::string> keystore;
35 // Private function prototypes
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);
51 // Load Apple2's settings
53 void LoadSettings(void)
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);
66 settings.winX = GetValue("windowX", 250);
67 settings.winY = GetValue("windowY", 100);
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"));
80 CheckForTrailingSlash(settings.disksPath);
85 // Save Apple2's settings
87 void SaveSettings(void)
89 SDL_GetWindowPosition(sdlWindow, &settings.winX, &settings.winY);
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]);
115 static int8_t FindConfig()
117 for(uint8_t i=0; i<5; i++)
119 FILE * f = fopen(configPath[i], "r");
133 // Read & parse the configuration file into our keystore
135 static void ParseConfigFile(void)
137 configLoc = FindConfig();
141 WriteLog("Settings: Couldn't find configuration file. Using defaults...\n");
145 char * buf = (char *)ReadFile(configPath[configLoc]);
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);
152 while ((start != std::string::npos) || (end != std::string::npos))
154 std::string sub = s.substr(start, end - start);
156 if ((sub[0] != '#') && (sub[0] != '['))
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);
163 if ((kStart != std::string::npos) && (kEnd != std::string::npos)
164 && (vStart != std::string::npos) && (vEnd != std::string::npos))
166 keystore[sub.substr(kStart, kEnd - kStart)] = sub.substr(vEnd);
170 start = s.find_first_not_of(delim, end);
171 end = s.find_first_of(delim, start);
178 static bool GetValue(const char * key, bool def)
180 if (keystore.find(key) == keystore.end())
183 return (atoi(keystore[key].c_str()) == 0 ? false : true);
187 static int GetValue(const char * key, int def)
189 if (keystore.find(key) == keystore.end())
192 return atoi(keystore[key].c_str());
196 static const char * GetValue(const char * key, const char * def)
198 if (keystore.find(key) == keystore.end())
201 return keystore[key].c_str();
205 static void SetValue(const char * key, bool value)
207 keystore[key] = (value ? "1" : "0");
211 static void SetValue(const char * key, int value)
215 sprintf(buf, "%i", value);
220 static void SetValue(const char * key, unsigned int value)
224 sprintf(buf, "%u", value);
229 static void SetValue(const char * key, const char * value)
231 keystore[key] = value;
236 // Check path for a trailing slash, and append if not present
238 static void CheckForTrailingSlash(char * path)
240 uint32_t len = strlen(path);
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
245 if ((len > 0) && (path[len - 1] != '/') && (len < MAX_PATH))
251 // Update the values in the config file (if one exists) with updated values in
254 static void UpdateConfigFile(void)
259 WriteLog("Settings: Creating default config...\n");
263 char * buf = (char *)ReadFile(configPath[configLoc]);
265 FILE * f = fopen(configPath[configLoc], "w");
269 WriteLog("Settings: Could not open config file for writing!\n");
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);
280 while (end != std::string::npos)
284 std::string sub = s.substr(start, end - start);
286 if ((sub[0] != '#') && (sub[0] != '['))
288 std::string::size_type kStart = sub.find_first_not_of(" ", 0);
289 std::string::size_type kEnd = sub.find_first_of(" ", kStart);
291 if ((kStart != std::string::npos)
292 && (kEnd != std::string::npos))
294 std::string key = sub.substr(kStart, kEnd - kStart);
296 if (keystore.find(key) != keystore.end())
298 sub = key + " = " + keystore[key];
304 fprintf(f, "%s\n", sub.c_str());
310 end = s.find_first_of(delim, start);
313 std::map<std::string, std::string>::iterator i;
315 for(i=keystore.begin(); i!=keystore.end(); i++)
316 fprintf(f, "%s = %s\n", i->first.c_str(), i->second.c_str());