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", ""));
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 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
86 CheckForTrailingSlash(settings.disksPath);
91 // Save Apple2's settings
93 void SaveSettings(void)
95 SDL_GetWindowPosition(sdlWindow, &settings.winX, &settings.winY);
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]);
126 static int8_t FindConfig()
128 for(uint8_t i=0; i<5; i++)
130 FILE * f = fopen(configPath[i], "r");
144 // Read & parse the configuration file into our keystore
146 static void ParseConfigFile(void)
148 configLoc = FindConfig();
152 WriteLog("Settings: Couldn't find configuration file. Using defaults...\n");
156 char * buf = (char *)ReadFile(configPath[configLoc]);
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);
163 while ((start != std::string::npos) || (end != std::string::npos))
165 std::string sub = s.substr(start, end - start);
167 if ((sub[0] != '#') && (sub[0] != '['))
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);
174 if ((kStart != std::string::npos) && (kEnd != std::string::npos)
175 && (vStart != std::string::npos) && (vEnd != std::string::npos))
177 keystore[sub.substr(kStart, kEnd - kStart)] = sub.substr(vEnd);
181 start = s.find_first_not_of(delim, end);
182 end = s.find_first_of(delim, start);
189 static bool GetValue(const char * key, bool def)
191 if (keystore.find(key) == keystore.end())
194 return (atoi(keystore[key].c_str()) == 0 ? false : true);
198 static int GetValue(const char * key, int def)
200 if (keystore.find(key) == keystore.end())
203 return atoi(keystore[key].c_str());
207 static const char * GetValue(const char * key, const char * def)
209 if (keystore.find(key) == keystore.end())
212 return keystore[key].c_str();
216 static void SetValue(const char * key, bool value)
218 keystore[key] = (value ? "1" : "0");
222 static void SetValue(const char * key, int value)
226 sprintf(buf, "%i", value);
231 static void SetValue(const char * key, unsigned int value)
235 sprintf(buf, "%u", value);
240 static void SetValue(const char * key, const char * value)
242 keystore[key] = value;
247 // Check path for a trailing slash, and append if not present
249 static void CheckForTrailingSlash(char * path)
251 uint32_t len = strlen(path);
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
256 if ((len > 0) && (path[len - 1] != '/') && (len < MAX_PATH))
262 // Update the values in the config file (if one exists) with updated values in
265 static void UpdateConfigFile(void)
270 WriteLog("Settings: Creating default config...\n");
274 char * buf = (char *)ReadFile(configPath[configLoc]);
276 FILE * f = fopen(configPath[configLoc], "w");
280 WriteLog("Settings: Could not open config file for writing!\n");
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);
291 while (end != std::string::npos)
295 std::string sub = s.substr(start, end - start);
297 if ((sub[0] != '#') && (sub[0] != '['))
299 std::string::size_type kStart = sub.find_first_not_of(" ", 0);
300 std::string::size_type kEnd = sub.find_first_of(" ", kStart);
302 if ((kStart != std::string::npos)
303 && (kEnd != std::string::npos))
305 std::string key = sub.substr(kStart, kEnd - kStart);
307 if (keystore.find(key) != keystore.end())
309 sub = key + " = " + keystore[key];
315 fprintf(f, "%s\n", sub.c_str());
321 end = s.find_first_of(delim, start);
324 std::map<std::string, std::string>::iterator i;
326 for(i=keystore.begin(); i!=keystore.end(); i++)
327 fprintf(f, "%s = %s\n", i->first.c_str(), i->second.c_str());