gcsx_config.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /* GCSx
  2. ** CONFIG.CPP
  3. **
  4. ** Configuration loading and saving
  5. */
  6. /*****************************************************************************
  7. ** Copyright (C) 2003-2006 Janson
  8. **
  9. ** This program is free software; you can redistribute it and/or modify
  10. ** it under the terms of the GNU General Public License as published by
  11. ** the Free Software Foundation; either version 2 of the License, or
  12. ** (at your option) any later version.
  13. **
  14. ** This program is distributed in the hope that it will be useful,
  15. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ** GNU General Public License for more details.
  18. **
  19. ** You should have received a copy of the GNU General Public License
  20. ** along with this program; if not, write to the Free Software
  21. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  22. *****************************************************************************/
  23. #include "all.h"
  24. Config* config = NULL;
  25. Config::Config() : configS(), configN(), configK(), configFile() { start_func
  26. configLoaded = 0;
  27. needsSaving = 0;
  28. }
  29. Config::~Config() { start_func
  30. }
  31. void Config::loadConfig() { start_func
  32. if (!configLoaded) {
  33. FILE* file = NULL;
  34. char* value = NULL;
  35. // Config filename
  36. createFilename(mainDir->c_str(), FILENAME_CFG, configFile);
  37. initConfigDefaults(configN);
  38. defaultShortcuts();
  39. // Load from file
  40. file = fopen(configFile.c_str(), "rb");
  41. if (file) {
  42. while (!feof(file)) {
  43. // We manually break it into 8bits for cross-compatibility
  44. int setting = fgetc(file) | (fgetc(file) << 8);
  45. if (setting == CONFIG_NO_SETTING) break;
  46. if ((setting >= CONFIG_FIRST_STRING_SETTING) &&
  47. (setting <= CONFIG_LAST_STRING_SETTING)) {
  48. unsigned int len = fgetc(file);
  49. value = new char[len];
  50. if (fread(value, 1, len, file) == len) {
  51. configS[setting] = value;
  52. }
  53. delete[] value;
  54. value = NULL;
  55. }
  56. else if (setting <= CONFIG_MAX_SETTING) {
  57. // We manually break it into 8bits for cross-compatibility
  58. Sint32 result = fgetc(file) | (fgetc(file) << 8) | (fgetc(file) << 16) | (fgetc(file) << 24);
  59. // This handles shortcut key reverses, etc.
  60. write(setting, result);
  61. }
  62. }
  63. fclose(file);
  64. }
  65. configLoaded = 1;
  66. needsSaving = 0;
  67. }
  68. }
  69. // Just marks us as needing saving
  70. void Config::saveConfig() { start_func
  71. needsSaving = 1;
  72. }
  73. void Config::performSave() { start_func
  74. if (needsSaving) {
  75. FILE* file = NULL;
  76. needsSaving = 0;
  77. // Save to file
  78. file = fopen(configFile.c_str(), "wb");
  79. if (file) {
  80. map<Uint16, string>::iterator endS = configS.end();
  81. for (map<Uint16, string>::iterator pos = configS.begin(); pos != endS; ++pos) {
  82. int code = (*pos).first;
  83. // We manually break it into 8bits for cross-compatibility
  84. fputc(code & 0xFF, file);
  85. fputc((code >> 8) & 0xFF, file);
  86. fputc((*pos).second.size(), file);
  87. fwrite((*pos).second.c_str(), 1, (*pos).second.size(), file);
  88. }
  89. map<Uint16, Sint32>::iterator endN = configN.end();
  90. for (map<Uint16, Sint32>::iterator pos = configN.begin(); pos != endN; ++pos) {
  91. int code = (*pos).first;
  92. if ((code < CONFIG_FIRST_VOLATILE_SETTING) || (code >= CONFIG_ADD_SHORTCUT)) {
  93. Sint32 value = (*pos).second;
  94. // We manually break it into 8bits for cross-compatibility
  95. fputc(code & 0xFF, file);
  96. fputc((code >> 8) & 0xFF, file);
  97. fputc(value & 0xFF, file);
  98. fputc((value >> 8) & 0xFF, file);
  99. fputc((value >> 16) & 0xFF, file);
  100. fputc((value >> 24) & 0xFF, file);
  101. }
  102. }
  103. fputc(CONFIG_NO_SETTING & 0xFF, file);
  104. fputc((CONFIG_NO_SETTING >> 8) & 0xFF, file);
  105. fclose(file);
  106. }
  107. }
  108. }
  109. Sint32 Config::readNum(Uint16 key) { start_func
  110. assert(key <= CONFIG_MAX_SETTING);
  111. assert(key > CONFIG_NO_SETTING);
  112. assert((key < CONFIG_FIRST_STRING_SETTING) || (key > CONFIG_LAST_STRING_SETTING));
  113. loadConfig();
  114. map<Uint16, Sint32>::iterator found = configN.find(key);
  115. if (found == configN.end()) return 0;
  116. return (*found).second;
  117. }
  118. const string& Config::readStr(Uint16 key) { start_func
  119. assert(key <= CONFIG_MAX_SETTING);
  120. assert(key > CONFIG_NO_SETTING);
  121. assert((key >= CONFIG_FIRST_STRING_SETTING) && (key <= CONFIG_LAST_STRING_SETTING));
  122. loadConfig();
  123. map<Uint16, string>::iterator found = configS.find(key);
  124. if (found == configS.end()) return blankString;
  125. return (*found).second;
  126. }
  127. void Config::addKey(Sint32 key, Uint16 cmd) { start_func
  128. configK[key].push_back(cmd);
  129. }
  130. void Config::delKey(Sint32 key, Uint16 cmd) { start_func
  131. SKeyMap::iterator pos = configK.find(key);
  132. if (pos != configK.end()) {
  133. vector<Uint16>::iterator end2 = (*pos).second.end();
  134. for (vector<Uint16>::iterator pos2 = (*pos).second.begin(); pos2 != end2; ++pos2) {
  135. if (*pos2 == cmd) {
  136. (*pos).second.erase(pos2);
  137. break;
  138. }
  139. }
  140. if ((*pos).second.empty()) {
  141. configK.erase(pos);
  142. }
  143. }
  144. }
  145. void Config::write(Uint16 key, Sint32 value) { start_func
  146. assert(key <= CONFIG_MAX_SETTING);
  147. assert(key > CONFIG_NO_SETTING);
  148. assert((key < CONFIG_FIRST_STRING_SETTING) || (key > CONFIG_LAST_STRING_SETTING));
  149. // If this is a shortcut key, update shortcut reverse lookup
  150. if (key >= CONFIG_ADD_SHORTCUT) {
  151. Uint16 shortkey = (key - CONFIG_ADD_SHORTCUT) % CONFIG_ADD_SHORTCUT_ALTERNATE;
  152. // Previous key? Erase
  153. map<Uint16, Sint32>::iterator found = configN.find(key);
  154. if (found != configN.end()) {
  155. delKey((*found).second, shortkey);
  156. }
  157. // Add new key
  158. addKey(value, shortkey);
  159. // If this was a "first" (non alternate) shortcut key, we need
  160. // to delete any alternates that may be there also!
  161. if (key < CONFIG_ADD_SHORTCUT + CONFIG_ADD_SHORTCUT_ALTERNATE) {
  162. int altKey = key + CONFIG_ADD_SHORTCUT_ALTERNATE;
  163. map<Uint16, Sint32>::iterator endN = configN.end();
  164. while ((found = configN.find(altKey)) != endN) {
  165. delKey((*found).second, shortkey);
  166. configN.erase(found);
  167. altKey += CONFIG_ADD_SHORTCUT_ALTERNATE;
  168. }
  169. }
  170. }
  171. // Skip saving if no change
  172. else if (configN[key] == value) return;
  173. // Store setting
  174. configN[key] = value;
  175. if ((key < CONFIG_FIRST_VOLATILE_SETTING) || (key >= CONFIG_ADD_SHORTCUT))
  176. saveConfig();
  177. }
  178. void Config::write(Uint16 key, const string& value) { start_func
  179. assert(key <= CONFIG_MAX_SETTING);
  180. assert(key > CONFIG_NO_SETTING);
  181. assert((key >= CONFIG_FIRST_STRING_SETTING) && (key <= CONFIG_LAST_STRING_SETTING));
  182. if (value.size() > 255) return;
  183. configS[key] = value;
  184. saveConfig();
  185. }
  186. void Config::clearShortcuts() { start_func
  187. map<Uint16, Sint32>::iterator end = configN.end();
  188. map<Uint16, Sint32>::iterator next;
  189. for (map<Uint16, Sint32>::iterator pos = configN.begin(); pos != end; pos = next) {
  190. // Get next element in case we delete
  191. next = pos;
  192. ++next;
  193. // Is this in the shortcuts range?
  194. if ((*pos).first >= CONFIG_ADD_SHORTCUT) {
  195. // Remove
  196. configN.erase(pos);
  197. }
  198. }
  199. configK.clear();
  200. }
  201. void Config::defaultShortcuts() { start_func
  202. clearShortcuts();
  203. map<Uint16, Sint32>::iterator end = configN.end();
  204. for (int pos = 0; shortcutDefault[pos].cmd; ++pos) {
  205. int addAlt = 0;
  206. while (configN.find(shortcutDefault[pos].cmd + CONFIG_ADD_SHORTCUT + addAlt) != end) {
  207. addAlt += CONFIG_ADD_SHORTCUT_ALTERNATE;
  208. }
  209. // Found an empty position; make sure we're within the max alternates
  210. if (addAlt / CONFIG_ADD_SHORTCUT_ALTERNATE <= CONFIG_MAX_SHORTCUT_ALTERNATE) {
  211. // Add to config, update reverse lookups
  212. write(shortcutDefault[pos].cmd + CONFIG_ADD_SHORTCUT + addAlt,
  213. combineKey(shortcutDefault[pos].key, shortcutDefault[pos].mod));
  214. }
  215. }
  216. }
  217. int Config::readShortcut(Uint16 key, Uint16 mod, int pos) { start_func
  218. SKeyMap::iterator posK = configK.find(combineKey(key, mod));
  219. if (posK != configK.end()) {
  220. int size = (*posK).second.size();
  221. if (pos == 0) return size;
  222. if (pos <= size) return (*posK).second[pos - 1];
  223. }
  224. return 0;
  225. }
  226. Sint32 Config::readShortcut(Uint16 cmd) { start_func
  227. return readNum(cmd + CONFIG_ADD_SHORTCUT);
  228. }