/src/emu/config.c

https://github.com/groovybits/groovymame · C · 328 lines · 170 code · 73 blank · 85 comment · 56 complexity · 09f33b54dcdda452bf1ce80bc6132380 MD5 · raw file

  1. /***************************************************************************
  2. config.c
  3. Configuration file I/O.
  4. Copyright Nicola Salmoria and the MAME Team.
  5. Visit http://mamedev.org for licensing and usage restrictions.
  6. ***************************************************************************/
  7. #include "emu.h"
  8. #include "emuopts.h"
  9. #include "config.h"
  10. #include "xmlfile.h"
  11. #define DEBUG_CONFIG 0
  12. /***************************************************************************
  13. TYPE DEFINITIONS
  14. ***************************************************************************/
  15. typedef struct _config_type config_type;
  16. struct _config_type
  17. {
  18. struct _config_type * next; /* next in line */
  19. const char * name; /* node name */
  20. config_saveload_delegate load; /* load callback */
  21. config_saveload_delegate save; /* save callback */
  22. };
  23. /***************************************************************************
  24. GLOBAL VARIABLES
  25. ***************************************************************************/
  26. static config_type *typelist;
  27. /***************************************************************************
  28. FUNCTION PROTOTYPES
  29. ***************************************************************************/
  30. static int config_load_xml(running_machine &machine, emu_file &file, int type);
  31. static int config_save_xml(running_machine &machine, emu_file &file, int type);
  32. /***************************************************************************
  33. CORE IMPLEMENTATION
  34. ***************************************************************************/
  35. /*************************************
  36. *
  37. * Reset the configuration callbacks
  38. *
  39. *************************************/
  40. void config_init(running_machine &machine)
  41. {
  42. typelist = NULL;
  43. }
  44. /*************************************
  45. *
  46. * Register to be involved in config
  47. * save/load
  48. *
  49. *************************************/
  50. void config_register(running_machine &machine, const char *nodename, config_saveload_delegate load, config_saveload_delegate save)
  51. {
  52. config_type *newtype;
  53. config_type **ptype;
  54. /* allocate a new type */
  55. newtype = auto_alloc(machine, config_type);
  56. newtype->next = NULL;
  57. newtype->name = nodename;
  58. newtype->load = load;
  59. newtype->save = save;
  60. /* add us to the end */
  61. for (ptype = &typelist; *ptype; ptype = &(*ptype)->next) ;
  62. *ptype = newtype;
  63. }
  64. /*************************************
  65. *
  66. * Settings save/load frontend
  67. *
  68. *************************************/
  69. int config_load_settings(running_machine &machine)
  70. {
  71. const char *controller = machine.options().ctrlr();
  72. config_type *type;
  73. int loaded = 0;
  74. /* loop over all registrants and call their init function */
  75. for (type = typelist; type; type = type->next)
  76. type->load(CONFIG_TYPE_INIT, NULL);
  77. /* now load the controller file */
  78. if (controller[0] != 0)
  79. {
  80. /* open the config file */
  81. emu_file file(machine.options().ctrlr_path(), OPEN_FLAG_READ);
  82. file_error filerr = file.open(controller, ".cfg");
  83. if (filerr != FILERR_NONE)
  84. throw emu_fatalerror("Could not load controller file %s.cfg", controller);
  85. /* load the XML */
  86. if (!config_load_xml(machine, file, CONFIG_TYPE_CONTROLLER))
  87. throw emu_fatalerror("Could not load controller file %s.cfg", controller);
  88. }
  89. /* next load the defaults file */
  90. emu_file file(machine.options().cfg_directory(), OPEN_FLAG_READ);
  91. file_error filerr = file.open("default.cfg");
  92. if (filerr == FILERR_NONE)
  93. config_load_xml(machine, file, CONFIG_TYPE_DEFAULT);
  94. /* finally, load the game-specific file */
  95. filerr = file.open(machine.basename(), ".cfg");
  96. if (filerr == FILERR_NONE)
  97. loaded = config_load_xml(machine, file, CONFIG_TYPE_GAME);
  98. /* loop over all registrants and call their final function */
  99. for (type = typelist; type; type = type->next)
  100. type->load(CONFIG_TYPE_FINAL, NULL);
  101. /* if we didn't find a saved config, return 0 so the main core knows that it */
  102. /* is the first time the game is run and it should diplay the disclaimer. */
  103. return loaded;
  104. }
  105. void config_save_settings(running_machine &machine)
  106. {
  107. config_type *type;
  108. /* loop over all registrants and call their init function */
  109. for (type = typelist; type; type = type->next)
  110. type->save(CONFIG_TYPE_INIT, NULL);
  111. /* save the defaults file */
  112. emu_file file(machine.options().cfg_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS);
  113. file_error filerr = file.open("default.cfg");
  114. if (filerr == FILERR_NONE)
  115. config_save_xml(machine, file, CONFIG_TYPE_DEFAULT);
  116. /* finally, save the game-specific file */
  117. filerr = file.open(machine.basename(), ".cfg");
  118. if (filerr == FILERR_NONE)
  119. config_save_xml(machine, file, CONFIG_TYPE_GAME);
  120. /* loop over all registrants and call their final function */
  121. for (type = typelist; type; type = type->next)
  122. type->save(CONFIG_TYPE_FINAL, NULL);
  123. }
  124. /*************************************
  125. *
  126. * XML file load
  127. *
  128. *************************************/
  129. static int config_load_xml(running_machine &machine, emu_file &file, int which_type)
  130. {
  131. xml_data_node *root, *confignode, *systemnode;
  132. config_type *type;
  133. const char *srcfile;
  134. int version, count;
  135. /* read the file */
  136. root = xml_file_read(file, NULL);
  137. if (!root)
  138. goto error;
  139. /* find the config node */
  140. confignode = xml_get_sibling(root->child, "mameconfig");
  141. if (!confignode)
  142. goto error;
  143. /* validate the config data version */
  144. version = xml_get_attribute_int(confignode, "version", 0);
  145. if (version != CONFIG_VERSION)
  146. goto error;
  147. /* strip off all the path crap from the source filename */
  148. srcfile = strrchr(machine.system().source_file, '/');
  149. if (!srcfile)
  150. srcfile = strrchr(machine.system().source_file, '\\');
  151. if (!srcfile)
  152. srcfile = strrchr(machine.system().source_file, ':');
  153. if (!srcfile)
  154. srcfile = machine.system().source_file;
  155. else
  156. srcfile++;
  157. /* loop over all system nodes in the file */
  158. count = 0;
  159. for (systemnode = xml_get_sibling(confignode->child, "system"); systemnode; systemnode = xml_get_sibling(systemnode->next, "system"))
  160. {
  161. /* look up the name of the system here; skip if none */
  162. const char *name = xml_get_attribute_string(systemnode, "name", "");
  163. /* based on the file type, determine whether we have a match */
  164. switch (which_type)
  165. {
  166. case CONFIG_TYPE_GAME:
  167. /* only match on the specific game name */
  168. if (strcmp(name, machine.system().name) != 0)
  169. continue;
  170. break;
  171. case CONFIG_TYPE_DEFAULT:
  172. /* only match on default */
  173. if (strcmp(name, "default") != 0)
  174. continue;
  175. break;
  176. case CONFIG_TYPE_CONTROLLER:
  177. {
  178. int clone_of;
  179. /* match on: default, game name, source file name, parent name, grandparent name */
  180. if (strcmp(name, "default") != 0 &&
  181. strcmp(name, machine.system().name) != 0 &&
  182. strcmp(name, srcfile) != 0 &&
  183. ((clone_of = driver_list::clone(machine.system())) == -1 || strcmp(name, driver_list::driver(clone_of).name) != 0) &&
  184. (clone_of == -1 || ((clone_of = driver_list::clone(clone_of)) == -1) || strcmp(name, driver_list::driver(clone_of).name) != 0))
  185. continue;
  186. break;
  187. }
  188. }
  189. /* log that we are processing this entry */
  190. if (DEBUG_CONFIG)
  191. mame_printf_debug("Entry: %s -- processing\n", name);
  192. /* loop over all registrants and call their load function */
  193. for (type = typelist; type; type = type->next)
  194. type->load(which_type, xml_get_sibling(systemnode->child, type->name));
  195. count++;
  196. }
  197. /* error if this isn't a valid game match */
  198. if (count == 0)
  199. goto error;
  200. /* free the parser */
  201. xml_file_free(root);
  202. return 1;
  203. error:
  204. if (root)
  205. xml_file_free(root);
  206. return 0;
  207. }
  208. /*************************************
  209. *
  210. * XML file save
  211. *
  212. *************************************/
  213. static int config_save_xml(running_machine &machine, emu_file &file, int which_type)
  214. {
  215. xml_data_node *root = xml_file_create();
  216. xml_data_node *confignode, *systemnode;
  217. config_type *type;
  218. /* if we don't have a root, bail */
  219. if (!root)
  220. return 0;
  221. /* create a config node */
  222. confignode = xml_add_child(root, "mameconfig", NULL);
  223. if (!confignode)
  224. goto error;
  225. xml_set_attribute_int(confignode, "version", CONFIG_VERSION);
  226. /* create a system node */
  227. systemnode = xml_add_child(confignode, "system", NULL);
  228. if (!systemnode)
  229. goto error;
  230. xml_set_attribute(systemnode, "name", (which_type == CONFIG_TYPE_DEFAULT) ? "default" : machine.system().name);
  231. /* create the input node and write it out */
  232. /* loop over all registrants and call their save function */
  233. for (type = typelist; type; type = type->next)
  234. {
  235. xml_data_node *curnode = xml_add_child(systemnode, type->name, NULL);
  236. if (!curnode)
  237. goto error;
  238. type->save(which_type, curnode);
  239. /* if nothing was added, just nuke the node */
  240. if (!curnode->value && !curnode->child)
  241. xml_delete_node(curnode);
  242. }
  243. /* flush the file */
  244. xml_file_write(root, file);
  245. /* free and get out of here */
  246. xml_file_free(root);
  247. return 1;
  248. error:
  249. xml_file_free(root);
  250. return 0;
  251. }