PageRenderTime 82ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 2ms

/cfgfile.cpp

https://github.com/tonioni/WinUAE
C++ | 9417 lines | 8976 code | 382 blank | 59 comment | 2086 complexity | 1b238f847b3d1b80686f2250433573d4 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * UAE - The Un*x Amiga Emulator
  3. *
  4. * Config file handling
  5. * This still needs some thought before it's complete...
  6. *
  7. * Copyright 1998 Brian King, Bernd Schmidt
  8. */
  9. #include "sysconfig.h"
  10. #include "sysdeps.h"
  11. #include <ctype.h>
  12. #include "options.h"
  13. #include "uae.h"
  14. #include "audio.h"
  15. #include "events.h"
  16. #include "custom.h"
  17. #include "inputdevice.h"
  18. #include "gfxfilter.h"
  19. #include "savestate.h"
  20. #include "memory.h"
  21. #include "autoconf.h"
  22. #include "rommgr.h"
  23. #include "gui.h"
  24. #include "newcpu.h"
  25. #include "zfile.h"
  26. #include "filesys.h"
  27. #include "fsdb.h"
  28. #include "disk.h"
  29. #include "blkdev.h"
  30. #include "statusline.h"
  31. #include "debug.h"
  32. #include "calc.h"
  33. #include "gfxboard.h"
  34. #include "cpuboard.h"
  35. #include "luascript.h"
  36. #include "ethernet.h"
  37. #include "native2amiga_api.h"
  38. #include "ini.h"
  39. #include "specialmonitors.h"
  40. #define cfgfile_warning write_log
  41. #define cfgfile_warning_obsolete write_log
  42. #if SIZEOF_TCHAR != 1
  43. /* FIXME: replace strcasecmp with _tcsicmp in source code instead */
  44. #undef strcasecmp
  45. #define strcasecmp _tcsicmp
  46. #endif
  47. static int config_newfilesystem;
  48. static struct strlist *temp_lines;
  49. static struct strlist *error_lines;
  50. static struct zfile *default_file, *configstore;
  51. static int uaeconfig;
  52. static int unicode_config = 0;
  53. /* @@@ need to get rid of this... just cut part of the manual and print that
  54. * as a help text. */
  55. struct cfg_lines
  56. {
  57. const TCHAR *config_label, *config_help;
  58. };
  59. static const struct cfg_lines opttable[] =
  60. {
  61. {_T("help"), _T("Prints this help") },
  62. {_T("config_description"), _T("") },
  63. {_T("config_info"), _T("") },
  64. {_T("use_gui"), _T("Enable the GUI? If no, then goes straight to emulator") },
  65. {_T("use_debugger"), _T("Enable the debugger?") },
  66. {_T("cpu_speed"), _T("can be max, real, or a number between 1 and 20") },
  67. {_T("cpu_model"), _T("Can be 68000, 68010, 68020, 68030, 68040, 68060") },
  68. {_T("fpu_model"), _T("Can be 68881, 68882, 68040, 68060") },
  69. {_T("cpu_compatible"), _T("yes enables compatibility-mode") },
  70. {_T("cpu_24bit_addressing"), _T("must be set to 'no' in order for Z3mem or P96mem to work") },
  71. {_T("autoconfig"), _T("yes = add filesystems and extra ram") },
  72. {_T("log_illegal_mem"), _T("print illegal memory access by Amiga software?") },
  73. {_T("fastmem_size"), _T("Size in megabytes of fast-memory") },
  74. {_T("chipmem_size"), _T("Size in megabytes of chip-memory") },
  75. {_T("bogomem_size"), _T("Size in megabytes of bogo-memory at 0xC00000") },
  76. {_T("a3000mem_size"), _T("Size in megabytes of A3000 memory") },
  77. {_T("gfxcard_size"), _T("Size in megabytes of Picasso96 graphics-card memory") },
  78. {_T("z3mem_size"), _T("Size in megabytes of Zorro-III expansion memory") },
  79. {_T("gfx_test_speed"), _T("Test graphics speed?") },
  80. {_T("gfx_framerate"), _T("Print every nth frame") },
  81. {_T("gfx_width"), _T("Screen width") },
  82. {_T("gfx_height"), _T("Screen height") },
  83. {_T("gfx_refreshrate"), _T("Fullscreen refresh rate") },
  84. {_T("gfx_vsync"), _T("Sync screen refresh to refresh rate") },
  85. {_T("gfx_lores"), _T("Treat display as lo-res?") },
  86. {_T("gfx_linemode"), _T("Can be none, double, or scanlines") },
  87. {_T("gfx_fullscreen_amiga"), _T("Amiga screens are fullscreen?") },
  88. {_T("gfx_fullscreen_picasso"), _T("Picasso screens are fullscreen?") },
  89. {_T("gfx_center_horizontal"), _T("Center display horizontally?") },
  90. {_T("gfx_center_vertical"), _T("Center display vertically?") },
  91. {_T("gfx_colour_mode"), _T("") },
  92. {_T("32bit_blits"), _T("Enable 32 bit blitter emulation") },
  93. {_T("immediate_blits"), _T("Perform blits immediately") },
  94. {_T("show_leds"), _T("LED display") },
  95. {_T("keyboard_leds"), _T("Keyboard LEDs") },
  96. {_T("gfxlib_replacement"), _T("Use graphics.library replacement?") },
  97. {_T("sound_output"), _T("") },
  98. {_T("sound_frequency"), _T("") },
  99. {_T("sound_bits"), _T("") },
  100. {_T("sound_channels"), _T("") },
  101. {_T("sound_max_buff"), _T("") },
  102. {_T("comp_trustbyte"), _T("How to access bytes in compiler (direct/indirect/indirectKS/afterPic") },
  103. {_T("comp_trustword"), _T("How to access words in compiler (direct/indirect/indirectKS/afterPic") },
  104. {_T("comp_trustlong"), _T("How to access longs in compiler (direct/indirect/indirectKS/afterPic") },
  105. {_T("comp_nf"), _T("Whether to optimize away flag generation where possible") },
  106. {_T("comp_fpu"), _T("Whether to provide JIT FPU emulation") },
  107. {_T("cachesize"), _T("How many MB to use to buffer translated instructions")},
  108. {_T("override_dga_address"),_T("Address from which to map the frame buffer (upper 16 bits) (DANGEROUS!)")},
  109. {_T("avoid_dga"), _T("Set to yes if the use of DGA extension creates problems") },
  110. {_T("avoid_vid"), _T("Set to yes if the use of the Vidmode extension creates problems") },
  111. {_T("parallel_on_demand"), _T("") },
  112. {_T("serial_on_demand"), _T("") },
  113. {_T("scsi"), _T("scsi.device emulation") },
  114. {_T("joyport0"), _T("") },
  115. {_T("joyport1"), _T("") },
  116. {_T("pci_devices"), _T("List of PCI devices to make visible to the emulated Amiga") },
  117. {_T("kickstart_rom_file"), _T("Kickstart ROM image, (C) Copyright Amiga, Inc.") },
  118. {_T("kickstart_ext_rom_file"), _T("Extended Kickstart ROM image, (C) Copyright Amiga, Inc.") },
  119. {_T("kickstart_key_file"), _T("Key-file for encrypted ROM images (from Cloanto's Amiga Forever)") },
  120. {_T("flash_ram_file"), _T("Flash/battery backed RAM image file.") },
  121. {_T("cart_file"), _T("Freezer cartridge ROM image file.") },
  122. {_T("floppy0"), _T("Diskfile for drive 0") },
  123. {_T("floppy1"), _T("Diskfile for drive 1") },
  124. {_T("floppy2"), _T("Diskfile for drive 2") },
  125. {_T("floppy3"), _T("Diskfile for drive 3") },
  126. {_T("hardfile"), _T("access,sectors, surfaces, reserved, blocksize, path format") },
  127. {_T("filesystem"), _T("access,'Amiga volume-name':'host directory path' - where 'access' can be 'read-only' or 'read-write'") },
  128. {_T("catweasel"), _T("Catweasel board io base address") }
  129. };
  130. static const TCHAR *guimode1[] = { _T("no"), _T("yes"), _T("nowait"), 0 };
  131. static const TCHAR *guimode2[] = { _T("false"), _T("true"), _T("nowait"), 0 };
  132. static const TCHAR *guimode3[] = { _T("0"), _T("1"), _T("nowait"), 0 };
  133. static const TCHAR *csmode[] = { _T("ocs"), _T("ecs_agnus"), _T("ecs_denise"), _T("ecs"), _T("aga"), 0 };
  134. static const TCHAR *linemode[] = {
  135. _T("none"),
  136. _T("double"), _T("scanlines"), _T("scanlines2p"), _T("scanlines3p"),
  137. _T("double2"), _T("scanlines2"), _T("scanlines2p2"), _T("scanlines2p3"),
  138. _T("double3"), _T("scanlines3"), _T("scanlines3p2"), _T("scanlines3p3"),
  139. 0 };
  140. static const TCHAR *speedmode[] = { _T("max"), _T("real"), 0 };
  141. static const TCHAR *colormode1[] = { _T("8bit"), _T("15bit"), _T("16bit"), _T("8bit_dither"), _T("4bit_dither"), _T("32bit"), 0 };
  142. static const TCHAR *colormode2[] = { _T("8"), _T("15"), _T("16"), _T("8d"), _T("4d"), _T("32"), 0 };
  143. static const TCHAR *soundmode1[] = { _T("none"), _T("interrupts"), _T("normal"), _T("exact"), 0 };
  144. static const TCHAR *soundmode2[] = { _T("none"), _T("interrupts"), _T("good"), _T("best"), 0 };
  145. static const TCHAR *centermode1[] = { _T("none"), _T("simple"), _T("smart"), 0 };
  146. static const TCHAR *centermode2[] = { _T("false"), _T("true"), _T("smart"), 0 };
  147. static const TCHAR *stereomode[] = { _T("mono"), _T("stereo"), _T("clonedstereo"), _T("4ch"), _T("clonedstereo6ch"), _T("6ch"), _T("mixed"), 0 };
  148. static const TCHAR *interpolmode[] = { _T("none"), _T("anti"), _T("sinc"), _T("rh"), _T("crux"), 0 };
  149. static const TCHAR *collmode[] = { _T("none"), _T("sprites"), _T("playfields"), _T("full"), 0 };
  150. static const TCHAR *compmode[] = { _T("direct"), _T("indirect"), _T("indirectKS"), _T("afterPic"), 0 };
  151. static const TCHAR *flushmode[] = { _T("soft"), _T("hard"), 0 };
  152. static const TCHAR *kbleds[] = { _T("none"), _T("POWER"), _T("DF0"), _T("DF1"), _T("DF2"), _T("DF3"), _T("HD"), _T("CD"), _T("DFx"), 0 };
  153. static const TCHAR *onscreenleds[] = { _T("false"), _T("true"), _T("rtg"), _T("both"), 0 };
  154. static const TCHAR *soundfiltermode1[] = { _T("off"), _T("emulated"), _T("on"), 0 };
  155. static const TCHAR *soundfiltermode2[] = { _T("standard"), _T("enhanced"), 0 };
  156. static const TCHAR *lorestype1[] = { _T("lores"), _T("hires"), _T("superhires"), 0 };
  157. static const TCHAR *lorestype2[] = { _T("true"), _T("false"), 0 };
  158. static const TCHAR *loresmode[] = { _T("normal"), _T("filtered"), 0 };
  159. static const TCHAR *horizmode[] = { _T("vertical"), _T("lores"), _T("hires"), _T("superhires"), 0 };
  160. static const TCHAR *vertmode[] = { _T("horizontal"), _T("single"), _T("double"), _T("quadruple"), 0 };
  161. #ifdef GFXFILTER
  162. static const TCHAR *filtermode2[] = { _T("1x"), _T("2x"), _T("3x"), _T("4x"), 0 };
  163. static const TCHAR *filtermode2v[] = { _T("-"), _T("1x"), _T("2x"), _T("3x"), _T("4x"), 0 };
  164. #endif
  165. static const TCHAR *cartsmode[] = { _T("none"), _T("hrtmon"), 0 };
  166. static const TCHAR *idemode[] = { _T("none"), _T("a600/a1200"), _T("a4000"), 0 };
  167. static const TCHAR *rtctype[] = { _T("none"), _T("MSM6242B"), _T("RP5C01A"), _T("MSM6242B_A2000"), 0 };
  168. static const TCHAR *ciaatodmode[] = { _T("vblank"), _T("50hz"), _T("60hz"), 0 };
  169. static const TCHAR *ksmirrortype[] = { _T("none"), _T("e0"), _T("a8+e0"), 0 };
  170. static const TCHAR *cscompa[] = {
  171. _T("-"), _T("Generic"), _T("CDTV"), _T("CDTV-CR"), _T("CD32"), _T("A500"), _T("A500+"), _T("A600"),
  172. _T("A1000"), _T("A1200"), _T("A2000"), _T("A3000"), _T("A3000T"), _T("A4000"), _T("A4000T"),
  173. _T("Velvet"), _T("Casablanca"), _T("DraCo"),
  174. NULL
  175. };
  176. static const TCHAR *qsmodes[] = {
  177. _T("A500"), _T("A500+"), _T("A600"), _T("A1000"), _T("A1200"), _T("A3000"), _T("A4000"), _T(""), _T("CD32"), _T("CDTV"), _T("CDTV-CR"), _T("ARCADIA"), NULL };
  178. /* 3-state boolean! */
  179. static const TCHAR *fullmodes[] = { _T("false"), _T("true"), /* "FILE_NOT_FOUND", */ _T("fullwindow"), 0 };
  180. /* bleh for compatibility */
  181. static const TCHAR *scsimode[] = { _T("false"), _T("true"), _T("scsi"), 0 };
  182. static const TCHAR *maxhoriz[] = { _T("lores"), _T("hires"), _T("superhires"), 0 };
  183. static const TCHAR *maxvert[] = { _T("nointerlace"), _T("interlace"), 0 };
  184. static const TCHAR *abspointers[] = { _T("none"), _T("mousehack"), _T("tablet"), 0 };
  185. static const TCHAR *magiccursors[] = { _T("both"), _T("native"), _T("host"), 0 };
  186. static const TCHAR *autoscale[] = { _T("none"), _T("auto"), _T("standard"), _T("max"), _T("scale"), _T("resize"), _T("center"), _T("manual"),
  187. _T("integer"), _T("integer_auto"), _T("separator"), _T("overscan_blanking"), 0 };
  188. static const TCHAR *autoscale_rtg[] = { _T("resize"), _T("scale"), _T("center"), _T("integer"), 0 };
  189. static const TCHAR *autoscalelimit[] = { _T("1/1"), _T("1/2"), _T("1/4"), _T("1/8"), 0 };
  190. static const TCHAR *joyportmodes[] = { _T(""), _T("mouse"), _T("mousenowheel"), _T("djoy"), _T("gamepad"), _T("ajoy"), _T("cdtvjoy"), _T("cd32joy"), _T("lightpen"), 0 };
  191. static const TCHAR *joyportsubmodes_lightpen[] = { _T(""), _T("trojan"), 0 };
  192. static const TCHAR *joyaf[] = { _T("none"), _T("normal"), _T("toggle"), _T("always"), 0 };
  193. static const TCHAR *epsonprinter[] = { _T("none"), _T("ascii"), _T("epson_matrix_9pin"), _T("epson_matrix_24pin"), _T("epson_matrix_48pin"), 0 };
  194. static const TCHAR *aspects[] = { _T("none"), _T("vga"), _T("tv"), 0 };
  195. static const TCHAR *vsyncmodes[] = { _T("false"), _T("true"), _T("autoswitch"), 0 };
  196. static const TCHAR *vsyncmodes2[] = { _T("normal"), _T("busywait"), 0 };
  197. static const TCHAR *filterapi[] = { _T("directdraw"), _T("direct3d"), _T("direct3d11"), _T("direct3d11"), 0};
  198. static const TCHAR *filterapiopts[] = { _T("hardware"), _T("software"), 0 };
  199. static const TCHAR *overscanmodes[] = { _T("tv_narrow"), _T("tv_standard"), _T("tv_wide"), _T("overscan"), _T("broadcast"), _T("extreme"), NULL };
  200. static const TCHAR *dongles[] =
  201. {
  202. _T("none"),
  203. _T("robocop 3"), _T("leaderboard"), _T("b.a.t. ii"), _T("italy'90 soccer"), _T("dames grand maitre"),
  204. _T("rugby coach"), _T("cricket captain"), _T("leviathan"), _T("musicmaster"),
  205. _T("logistics"), _T("scala red"), _T("scala green"),
  206. NULL
  207. };
  208. static const TCHAR *cdmodes[] = { _T("disabled"), _T(""), _T("image"), _T("ioctl"), _T("spti"), _T("aspi"), 0 };
  209. static const TCHAR *cdconmodes[] = { _T(""), _T("uae"), _T("ide"), _T("scsi"), _T("cdtv"), _T("cd32"), 0 };
  210. static const TCHAR *genlockmodes[] = { _T("none"), _T("noise"), _T("testcard"), _T("image"), _T("video"), _T("stream"), _T("ld"), _T("sony_ld"), _T("pioneer_ld"), NULL };
  211. static const TCHAR *ppc_implementations[] = {
  212. _T("auto"),
  213. _T("dummy"),
  214. _T("pearpc"),
  215. _T("qemu"),
  216. NULL
  217. };
  218. static const TCHAR *ppc_cpu_idle[] = {
  219. _T("disabled"),
  220. _T("1"),
  221. _T("2"),
  222. _T("3"),
  223. _T("4"),
  224. _T("5"),
  225. _T("6"),
  226. _T("7"),
  227. _T("8"),
  228. _T("9"),
  229. _T("max"),
  230. NULL
  231. };
  232. static const TCHAR *waitblits[] = { _T("disabled"), _T("automatic"), _T("noidleonly"), _T("always"), 0 };
  233. static const TCHAR *autoext2[] = { _T("disabled"), _T("copy"), _T("replace"), 0 };
  234. static const TCHAR *leds[] = { _T("power"), _T("df0"), _T("df1"), _T("df2"), _T("df3"), _T("hd"), _T("cd"), _T("fps"), _T("cpu"), _T("snd"), _T("md"), _T("net"), 0 };
  235. static const int leds_order[] = { 3, 6, 7, 8, 9, 4, 5, 2, 1, 0, 9, 10 };
  236. static const TCHAR *lacer[] = { _T("off"), _T("i"), _T("p"), 0 };
  237. /* another boolean to choice update.. */
  238. static const TCHAR *cycleexact[] = { _T("false"), _T("memory"), _T("true"), 0 };
  239. static const TCHAR *unmapped[] = { _T("floating"), _T("zero"), _T("one"), 0 };
  240. static const TCHAR *ciatype[] = { _T("default"), _T("391078-01"), 0 };
  241. static const TCHAR *debugfeatures[] = { _T("segtracker"), _T("fsdebug"), 0 };
  242. struct hdcontrollerconfig
  243. {
  244. const TCHAR *label;
  245. int romtype;
  246. };
  247. static const struct hdcontrollerconfig hdcontrollers[] = {
  248. { _T("uae"), 0 },
  249. { _T("ide%d"), 0 },
  250. { _T("ide%d_mainboard"), ROMTYPE_MB_IDE },
  251. { _T("scsi%d"), 0 },
  252. { _T("scsi%d_a3000"), ROMTYPE_SCSI_A3000 },
  253. { _T("scsi%d_a4000t"), ROMTYPE_SCSI_A4000T },
  254. { _T("scsi%d_cdtv"), ROMTYPE_CDTVSCSI },
  255. { NULL }
  256. };
  257. static const TCHAR *z3mapping[] = {
  258. _T("auto"),
  259. _T("uae"),
  260. _T("real"),
  261. NULL
  262. };
  263. static const TCHAR *uaescsidevmodes[] = {
  264. _T("original"),
  265. _T("rename_scsi"),
  266. NULL
  267. };
  268. static const TCHAR *uaebootrom[] = {
  269. _T("automatic"),
  270. _T("disabled"),
  271. _T("min"),
  272. _T("full"),
  273. NULL
  274. };
  275. static const TCHAR *uaeboard[] = {
  276. _T("disabled"),
  277. _T("min"),
  278. _T("full"),
  279. _T("full+indirect"),
  280. NULL
  281. };
  282. static const TCHAR *uaeboard_off[] = {
  283. _T("disabled_off"),
  284. _T("min_off"),
  285. _T("full_off"),
  286. _T("full+indirect_off"),
  287. NULL
  288. };
  289. static const TCHAR *serialcrlf[] = {
  290. _T("disabled"),
  291. _T("crlf_cr"),
  292. NULL
  293. };
  294. static const TCHAR *threebitcolors[] = {
  295. _T("disabled"),
  296. _T("3to4to8bit"),
  297. _T("3to4bit"),
  298. _T("3to8bit"),
  299. NULL
  300. };
  301. static const TCHAR *obsolete[] = {
  302. _T("accuracy"), _T("gfx_opengl"), _T("gfx_32bit_blits"), _T("32bit_blits"),
  303. _T("gfx_immediate_blits"), _T("gfx_ntsc"), _T("win32"), _T("gfx_filter_bits"),
  304. _T("sound_pri_cutoff"), _T("sound_pri_time"), _T("sound_min_buff"), _T("sound_bits"),
  305. _T("gfx_test_speed"), _T("gfxlib_replacement"), _T("enforcer"), _T("catweasel_io"),
  306. _T("kickstart_key_file"), _T("fast_copper"), _T("sound_adjust"), _T("sound_latency"),
  307. _T("serial_hardware_dtrdsr"), _T("gfx_filter_upscale"),
  308. _T("gfx_correct_aspect"), _T("gfx_autoscale"), _T("parallel_sampler"), _T("parallel_ascii_emulation"),
  309. _T("avoid_vid"), _T("avoid_dga"), _T("z3chipmem_size"), _T("state_replay_buffer"), _T("state_replay"),
  310. _T("z3realmapping"), _T("force_0x10000000_z3"),
  311. _T("fpu_arithmetic_exceptions"),
  312. _T("gfx_filter_vert_zoom"),_T("gfx_filter_horiz_zoom"),
  313. _T("gfx_filter_vert_zoom_mult"), _T("gfx_filter_horiz_zoom_mult"),
  314. _T("gfx_filter_vert_offset"), _T("gfx_filter_horiz_offset"),
  315. _T("gfx_tearing"), _T("gfx_tearing_rtg"),
  316. // created by some buggy beta
  317. _T("uaehf0%s,%s"),
  318. _T("uaehf1%s,%s"),
  319. _T("uaehf2%s,%s"),
  320. _T("uaehf3%s,%s"),
  321. _T("uaehf4%s,%s"),
  322. _T("uaehf5%s,%s"),
  323. _T("uaehf6%s,%s"),
  324. _T("uaehf7%s,%s"),
  325. _T("pcibridge_rom_file"),
  326. _T("pcibridge_rom_options"),
  327. _T("cpuboard_ext_rom_file"),
  328. _T("uaeboard_mode"),
  329. _T("comp_oldsegv"),
  330. _T("comp_midopt"),
  331. _T("comp_lowopt"),
  332. _T("avoid_cmov"),
  333. _T("compforcesettings"),
  334. _T("comp_catchdetect"),
  335. _T("hblank_glitch"),
  336. _T("gfx_hdr"),
  337. NULL
  338. };
  339. #define UNEXPANDED _T("$(FILE_PATH)")
  340. static TCHAR *cfgfile_unescape(const TCHAR *s, const TCHAR **endpos, TCHAR separator, bool min)
  341. {
  342. bool quoted = false;
  343. TCHAR *s2 = xmalloc(TCHAR, _tcslen(s) + 1);
  344. TCHAR *p = s2;
  345. if (s[0] == '\"') {
  346. s++;
  347. quoted = true;
  348. }
  349. int i;
  350. for (i = 0; s[i]; i++) {
  351. TCHAR c = s[i];
  352. if (quoted && c == '\"') {
  353. i++;
  354. break;
  355. }
  356. if (c == separator) {
  357. i++;
  358. break;
  359. }
  360. if (c == '\\' && !min) {
  361. char v = 0;
  362. TCHAR c2;
  363. c = s[i + 1];
  364. switch (c)
  365. {
  366. case 'X':
  367. case 'x':
  368. c2 = _totupper(s[i + 2]);
  369. v = ((c2 >= 'A') ? c2 - 'A' : c2 - '0') << 4;
  370. c2 = _totupper(s[i + 3]);
  371. v |= (c2 >= 'A') ? c2 - 'A' : c2 - '0';
  372. *p++ = c2;
  373. i += 2;
  374. break;
  375. case 'r':
  376. *p++ = '\r';
  377. break;
  378. case '\n':
  379. *p++ = '\n';
  380. break;
  381. default:
  382. *p++ = c;
  383. break;
  384. }
  385. i++;
  386. }
  387. else {
  388. *p++ = c;
  389. }
  390. }
  391. *p = 0;
  392. if (endpos)
  393. *endpos = &s[i];
  394. return s2;
  395. }
  396. static TCHAR *cfgfile_unescape(const TCHAR *s, const TCHAR **endpos)
  397. {
  398. return cfgfile_unescape(s, endpos, 0, false);
  399. }
  400. static TCHAR *cfgfile_unescape_min(const TCHAR *s)
  401. {
  402. return cfgfile_unescape(s, NULL, 0, true);
  403. }
  404. static TCHAR *cfgfile_option_find_it(const TCHAR *s, const TCHAR *option, bool checkequals)
  405. {
  406. TCHAR buf[MAX_DPATH];
  407. if (!s)
  408. return NULL;
  409. _tcscpy(buf, s);
  410. _tcscat(buf, _T(","));
  411. TCHAR *p = buf;
  412. for (;;) {
  413. TCHAR *tmpp = _tcschr(p, ',');
  414. TCHAR *tmpp2 = NULL;
  415. if (tmpp == NULL)
  416. return NULL;
  417. *tmpp++ = 0;
  418. if (checkequals) {
  419. tmpp2 = _tcschr(p, '=');
  420. if (tmpp2)
  421. *tmpp2++ = 0;
  422. }
  423. if (!strcasecmp(p, option)) {
  424. if (checkequals && tmpp2) {
  425. if (tmpp2[0] == '"') {
  426. TCHAR *n = cfgfile_unescape_min(tmpp2);
  427. return n;
  428. }
  429. return my_strdup(tmpp2);
  430. }
  431. return my_strdup(p);
  432. }
  433. p = tmpp;
  434. }
  435. }
  436. bool cfgfile_option_find(const TCHAR *s, const TCHAR *option)
  437. {
  438. TCHAR *ss = cfgfile_option_find_it(s, option, false);
  439. xfree(ss);
  440. return ss != NULL;
  441. }
  442. TCHAR *cfgfile_option_get(const TCHAR *s, const TCHAR *option)
  443. {
  444. return cfgfile_option_find_it(s, option, true);
  445. }
  446. bool cfgfile_option_get_bool(const TCHAR* s, const TCHAR* option)
  447. {
  448. TCHAR *d = cfgfile_option_find_it(s, option, true);
  449. bool ret = d && (!_tcsicmp(d, _T("true")) || !_tcsicmp(d, _T("1")));
  450. xfree(d);
  451. return ret;
  452. }
  453. static void trimwsa (char *s)
  454. {
  455. /* Delete trailing whitespace. */
  456. int len = strlen (s);
  457. while (len > 0 && strcspn (s + len - 1, "\t \r\n") == 0)
  458. s[--len] = '\0';
  459. }
  460. static int match_string (const TCHAR *table[], const TCHAR *str)
  461. {
  462. int i;
  463. for (i = 0; table[i] != 0; i++)
  464. if (strcasecmp (table[i], str) == 0)
  465. return i;
  466. return -1;
  467. }
  468. // escape config file separators and control characters
  469. static TCHAR *cfgfile_escape (const TCHAR *s, const TCHAR *escstr, bool quote)
  470. {
  471. bool doquote = false;
  472. int cnt = 0;
  473. for (int i = 0; s[i]; i++) {
  474. TCHAR c = s[i];
  475. if (c == 0)
  476. break;
  477. if (c < 32 || c == '\\' || c == '\"' || c == '\'') {
  478. cnt++;
  479. }
  480. for (int j = 0; escstr && escstr[j]; j++) {
  481. if (c == escstr[j]) {
  482. cnt++;
  483. if (quote) {
  484. doquote = true;
  485. cnt++;
  486. }
  487. }
  488. }
  489. // always quote if starts or ends with space
  490. if (c == ' ' && (s[i + 1] == 0 || i == 0)) {
  491. doquote = true;
  492. }
  493. }
  494. if (escstr == NULL && quote)
  495. doquote = true;
  496. TCHAR *s2 = xmalloc (TCHAR, _tcslen (s) + cnt * 4 + 2 + 1);
  497. TCHAR *p = s2;
  498. if (doquote)
  499. *p++ = '\"';
  500. for (int i = 0; s[i]; i++) {
  501. TCHAR c = s[i];
  502. if (c == 0)
  503. break;
  504. if (c == '\\' || c == '\"' || c == '\'') {
  505. *p++ = '\\';
  506. *p++ = c;
  507. } else if (c >= 32 && !quote) {
  508. bool escaped = false;
  509. for (int j = 0; escstr && escstr[j]; j++) {
  510. if (c == escstr[j]) {
  511. *p++ = '\\';
  512. *p++ = c;
  513. escaped = true;
  514. break;
  515. }
  516. }
  517. if (!escaped)
  518. *p++ = c;
  519. } else if (c < 32) {
  520. *p++ = '\\';
  521. switch (c)
  522. {
  523. case '\t':
  524. *p++ = 't';
  525. break;
  526. case '\n':
  527. *p++ = 'n';
  528. break;
  529. case '\r':
  530. *p++ = 'r';
  531. break;
  532. default:
  533. *p++ = 'x';
  534. *p++ = (c >> 4) >= 10 ? (c >> 4) + 'a' : (c >> 4) + '0';
  535. *p++ = (c & 15) >= 10 ? (c & 15) + 'a' : (c & 15) + '0';
  536. break;
  537. }
  538. } else {
  539. *p++ = c;
  540. }
  541. }
  542. if (doquote)
  543. *p++ = '\"';
  544. *p = 0;
  545. return s2;
  546. }
  547. // escapy only , and " or if starts or ends with a space
  548. static TCHAR *cfgfile_escape_min(const TCHAR *s)
  549. {
  550. for (int i = 0; s[i]; i++) {
  551. TCHAR c = s[i];
  552. if (c == ',' || c == '\"' || (c == ' ' && (i == 0 || s[i + 1] == 0))) {
  553. return cfgfile_escape(s, _T(","), true);
  554. }
  555. }
  556. return my_strdup(s);
  557. }
  558. static TCHAR *getnextentry (const TCHAR **valuep, const TCHAR separator)
  559. {
  560. TCHAR *s;
  561. const TCHAR *value = *valuep;
  562. if (value[0] == '\"') {
  563. s = cfgfile_unescape (value, valuep);
  564. value = *valuep;
  565. if (*value != 0 && *value != separator) {
  566. xfree (s);
  567. return NULL;
  568. }
  569. value++;
  570. *valuep = value;
  571. } else {
  572. s = cfgfile_unescape (value, valuep, separator, false);
  573. }
  574. return s;
  575. }
  576. static TCHAR *cfgfile_subst_path2 (const TCHAR *path, const TCHAR *subst, const TCHAR *file)
  577. {
  578. /* @@@ use strcasecmp for some targets. */
  579. if (path != NULL && subst != NULL && _tcslen (path) > 0 && _tcsncmp (file, path, _tcslen (path)) == 0) {
  580. int l;
  581. TCHAR *p2, *p = xmalloc (TCHAR, _tcslen (file) + _tcslen (subst) + 2);
  582. _tcscpy (p, subst);
  583. l = _tcslen (p);
  584. while (l > 0 && p[l - 1] == '/')
  585. p[--l] = '\0';
  586. l = _tcslen (path);
  587. while (file[l] == '/')
  588. l++;
  589. _tcscat (p, _T("/"));
  590. _tcscat (p, file + l);
  591. p2 = target_expand_environment (p, NULL, 0);
  592. xfree (p);
  593. if (p2 && p2[0] == '$') {
  594. xfree(p2);
  595. return NULL;
  596. }
  597. return p2;
  598. }
  599. return NULL;
  600. }
  601. TCHAR *cfgfile_subst_path (const TCHAR *path, const TCHAR *subst, const TCHAR *file)
  602. {
  603. TCHAR *s = cfgfile_subst_path2 (path, subst, file);
  604. if (s)
  605. return s;
  606. s = target_expand_environment (file, NULL, 0);
  607. if (s) {
  608. TCHAR tmp[MAX_DPATH];
  609. _tcscpy (tmp, s);
  610. xfree (s);
  611. fullpath (tmp, sizeof tmp / sizeof (TCHAR));
  612. s = my_strdup (tmp);
  613. }
  614. return s;
  615. }
  616. static TCHAR *cfgfile_get_multipath2 (struct multipath *mp, const TCHAR *path, const TCHAR *file, bool dir)
  617. {
  618. for (int i = 0; i < MAX_PATHS; i++) {
  619. if (mp->path[i][0] && _tcscmp (mp->path[i], _T(".\\")) != 0 && _tcscmp (mp->path[i], _T("./")) != 0 && (file[0] != '/' && file[0] != '\\' && !_tcschr(file, ':'))) {
  620. TCHAR *s = NULL;
  621. if (path)
  622. s = cfgfile_subst_path2 (path, mp->path[i], file);
  623. if (!s) {
  624. TCHAR np[MAX_DPATH];
  625. _tcscpy (np, mp->path[i]);
  626. fixtrailing (np);
  627. _tcscat (np, file);
  628. fullpath (np, sizeof np / sizeof (TCHAR));
  629. s = my_strdup (np);
  630. }
  631. if (dir) {
  632. if (my_existsdir (s))
  633. return s;
  634. } else {
  635. if (zfile_exists (s))
  636. return s;
  637. }
  638. xfree (s);
  639. }
  640. }
  641. return NULL;
  642. }
  643. static TCHAR *cfgfile_get_multipath (struct multipath *mp, const TCHAR *path, const TCHAR *file, bool dir)
  644. {
  645. TCHAR *s = cfgfile_get_multipath2 (mp, path, file, dir);
  646. if (s)
  647. return s;
  648. return my_strdup (file);
  649. }
  650. static TCHAR *cfgfile_put_multipath (struct multipath *mp, const TCHAR *s)
  651. {
  652. for (int i = 0; i < MAX_PATHS; i++) {
  653. if (mp->path[i][0] && _tcscmp (mp->path[i], _T(".\\")) != 0 && _tcscmp (mp->path[i], _T("./")) != 0) {
  654. if (_tcsnicmp (mp->path[i], s, _tcslen (mp->path[i])) == 0) {
  655. return my_strdup (s + _tcslen (mp->path[i]));
  656. }
  657. }
  658. }
  659. return my_strdup (s);
  660. }
  661. static TCHAR *cfgfile_subst_path_load (const TCHAR *path, struct multipath *mp, const TCHAR *file, bool dir)
  662. {
  663. TCHAR *s = cfgfile_get_multipath2 (mp, path, file, dir);
  664. if (s)
  665. return s;
  666. return cfgfile_subst_path (path, mp->path[0], file);
  667. }
  668. static bool isdefault (const TCHAR *s)
  669. {
  670. TCHAR tmp[MAX_DPATH];
  671. if (!default_file || uaeconfig)
  672. return false;
  673. zfile_fseek (default_file, 0, SEEK_SET);
  674. while (zfile_fgets (tmp, sizeof tmp / sizeof (TCHAR), default_file)) {
  675. if (tmp[0] && tmp[_tcslen (tmp) - 1] == '\n')
  676. tmp[_tcslen (tmp) - 1] = 0;
  677. if (!_tcscmp (tmp, s))
  678. return true;
  679. }
  680. return false;
  681. }
  682. static size_t cfg_write (const void *b, struct zfile *z)
  683. {
  684. size_t v;
  685. if (unicode_config) {
  686. TCHAR lf = 10;
  687. v = zfile_fwrite (b, _tcslen ((TCHAR*)b), sizeof (TCHAR), z);
  688. zfile_fwrite (&lf, 1, 1, z);
  689. } else {
  690. char lf = 10;
  691. char *s = ua ((TCHAR*)b);
  692. v = zfile_fwrite (s, strlen (s), 1, z);
  693. zfile_fwrite (&lf, 1, 1, z);
  694. xfree (s);
  695. }
  696. return v;
  697. }
  698. #define UTF8NAME _T(".utf8")
  699. static void cfg_dowrite(struct zfile *f, const TCHAR *option, const TCHAR *optionext, const TCHAR *value, int d, int target, int escape)
  700. {
  701. char lf = 10;
  702. TCHAR tmp[CONFIG_BLEN], tmpext[CONFIG_BLEN];
  703. const TCHAR *optionp;
  704. const TCHAR *new_value = NULL;
  705. bool free_value = false;
  706. char tmpa[CONFIG_BLEN];
  707. char *tmp1, *tmp2;
  708. int utf8;
  709. if (value == NULL)
  710. return;
  711. if (optionext) {
  712. _tcscpy(tmpext, option);
  713. _tcscat(tmpext, optionext);
  714. optionp = tmpext;
  715. } else {
  716. optionp = option;
  717. }
  718. utf8 = 0;
  719. tmp1 = ua(value);
  720. tmp2 = uutf8(value);
  721. if (strcmp(tmp1, tmp2) && tmp2[0] != 0)
  722. utf8 = 1;
  723. if (escape) {
  724. new_value = cfgfile_escape_min(value);
  725. free_value = true;
  726. } else {
  727. new_value = value;
  728. }
  729. if (target)
  730. _stprintf(tmp, _T("%s.%s=%s"), TARGET_NAME, optionp, new_value);
  731. else
  732. _stprintf(tmp, _T("%s=%s"), optionp, new_value);
  733. if (d && isdefault (tmp))
  734. goto end;
  735. cfg_write(tmp, f);
  736. if (utf8 && !unicode_config) {
  737. char *opt = ua(optionp);
  738. if (target) {
  739. char *tna = ua(TARGET_NAME);
  740. sprintf(tmpa, "%s.%s.utf8=%s", tna, opt, tmp2);
  741. xfree(tna);
  742. } else {
  743. sprintf(tmpa, "%s.utf8=%s", opt, tmp2);
  744. }
  745. xfree(opt);
  746. zfile_fwrite(tmpa, strlen (tmpa), 1, f);
  747. zfile_fwrite(&lf, 1, 1, f);
  748. }
  749. end:
  750. if (free_value) {
  751. xfree((void*)new_value);
  752. }
  753. xfree(tmp2);
  754. xfree(tmp1);
  755. }
  756. static void cfgfile_dwrite_coords(struct zfile *f, const TCHAR *option, int x, int y)
  757. {
  758. if (x || y)
  759. cfgfile_dwrite(f, option, _T("%d,%d"), x, y);
  760. }
  761. static void cfg_dowrite(struct zfile *f, const TCHAR *option, const TCHAR *value, int d, int target, int escape)
  762. {
  763. cfg_dowrite(f, option, NULL, value, d, target, escape);
  764. }
  765. void cfgfile_write_bool(struct zfile *f, const TCHAR *option, bool b)
  766. {
  767. cfg_dowrite(f, option, b ? _T("true") : _T("false"), 0, 0, 0);
  768. }
  769. void cfgfile_dwrite_bool(struct zfile *f, const TCHAR *option, bool b)
  770. {
  771. cfg_dowrite(f, option, b ? _T("true") : _T("false"), 1, 0, 0);
  772. }
  773. static void cfgfile_dwrite_bool(struct zfile *f, const TCHAR *option, const TCHAR *optionext, bool b)
  774. {
  775. cfg_dowrite(f, option, optionext, b ? _T("true") : _T("false"), 1, 0, 0);
  776. }
  777. static void cfgfile_dwrite_bool(struct zfile *f, const TCHAR *option, int b)
  778. {
  779. cfgfile_dwrite_bool (f, option, b != 0);
  780. }
  781. void cfgfile_write_str(struct zfile *f, const TCHAR *option, const TCHAR *value)
  782. {
  783. cfg_dowrite(f, option, value, 0, 0, 0);
  784. }
  785. static void cfgfile_write_str(struct zfile *f, const TCHAR *option, const TCHAR *optionext, const TCHAR *value)
  786. {
  787. cfg_dowrite(f, option, optionext, value, 0, 0, 0);
  788. }
  789. static void cfgfile_write_str_escape(struct zfile *f, const TCHAR *option, const TCHAR *value)
  790. {
  791. cfg_dowrite(f, option, value, 0, 0, 1);
  792. }
  793. void cfgfile_dwrite_str(struct zfile *f, const TCHAR *option, const TCHAR *value)
  794. {
  795. cfg_dowrite(f, option, value, 1, 0, 0);
  796. }
  797. static void cfgfile_dwrite_str(struct zfile *f, const TCHAR *option, const TCHAR *optionext, const TCHAR *value)
  798. {
  799. cfg_dowrite(f, option, optionext, value, 1, 0, 0);
  800. }
  801. void cfgfile_target_write_bool(struct zfile *f, const TCHAR *option, bool b)
  802. {
  803. cfg_dowrite(f, option, b ? _T("true") : _T("false"), 0, 1, 0);
  804. }
  805. void cfgfile_target_dwrite_bool(struct zfile *f, const TCHAR *option, bool b)
  806. {
  807. cfg_dowrite(f, option, b ? _T("true") : _T("false"), 1, 1, 0);
  808. }
  809. void cfgfile_target_write_str(struct zfile *f, const TCHAR *option, const TCHAR *value)
  810. {
  811. cfg_dowrite(f, option, value, 0, 1, 0);
  812. }
  813. void cfgfile_target_dwrite_str(struct zfile *f, const TCHAR *option, const TCHAR *value)
  814. {
  815. cfg_dowrite(f, option, value, 1, 1, 0);
  816. }
  817. void cfgfile_target_dwrite_str_escape(struct zfile *f, const TCHAR *option, const TCHAR *value)
  818. {
  819. cfg_dowrite(f, option, value, 1, 1, 1);
  820. }
  821. static void cfgfile_write_ext(struct zfile *f, const TCHAR *option, const TCHAR *optionext, const TCHAR *format,...)
  822. {
  823. va_list parms;
  824. TCHAR tmp[CONFIG_BLEN], tmp2[CONFIG_BLEN];
  825. if (optionext) {
  826. _tcscpy(tmp2, option);
  827. _tcscat(tmp2, optionext);
  828. }
  829. va_start(parms, format);
  830. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  831. cfg_dowrite(f, optionext ? tmp2 : option, tmp, 0, 0, 0);
  832. va_end(parms);
  833. }
  834. void cfgfile_write(struct zfile *f, const TCHAR *option, const TCHAR *format,...)
  835. {
  836. va_list parms;
  837. TCHAR tmp[CONFIG_BLEN];
  838. va_start(parms, format);
  839. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  840. cfg_dowrite(f, option, tmp, 0, 0, 0);
  841. va_end(parms);
  842. }
  843. void cfgfile_write_escape(struct zfile *f, const TCHAR *option, const TCHAR *format,...)
  844. {
  845. va_list parms;
  846. TCHAR tmp[CONFIG_BLEN];
  847. va_start(parms, format);
  848. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  849. cfg_dowrite(f, option, tmp, 0, 0, 1);
  850. va_end(parms);
  851. }
  852. static void cfgfile_dwrite_ext(struct zfile *f, const TCHAR *option, const TCHAR *optionext, const TCHAR *format,...)
  853. {
  854. va_list parms;
  855. TCHAR tmp[CONFIG_BLEN], tmp2[CONFIG_BLEN];
  856. if (optionext) {
  857. _tcscpy(tmp2, option);
  858. _tcscat(tmp2, optionext);
  859. }
  860. va_start(parms, format);
  861. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  862. cfg_dowrite(f, optionext ? tmp2 : option, tmp, 1, 0, 0);
  863. va_end(parms);
  864. }
  865. void cfgfile_dwrite(struct zfile *f, const TCHAR *option, const TCHAR *format,...)
  866. {
  867. va_list parms;
  868. TCHAR tmp[CONFIG_BLEN];
  869. va_start(parms, format);
  870. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  871. cfg_dowrite(f, option, tmp, 1, 0, 0);
  872. va_end(parms);
  873. }
  874. void cfgfile_dwrite_escape(struct zfile *f, const TCHAR *option, const TCHAR *format,...)
  875. {
  876. va_list parms;
  877. TCHAR tmp[CONFIG_BLEN];
  878. va_start(parms, format);
  879. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  880. cfg_dowrite(f, option, tmp, 1, 0, 1);
  881. va_end(parms);
  882. }
  883. void cfgfile_target_write(struct zfile *f, const TCHAR *option, const TCHAR *format,...)
  884. {
  885. va_list parms;
  886. TCHAR tmp[CONFIG_BLEN];
  887. va_start(parms, format);
  888. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  889. cfg_dowrite(f, option, tmp, 0, 1, 0);
  890. va_end(parms);
  891. }
  892. void cfgfile_target_write_escape(struct zfile *f, const TCHAR *option, const TCHAR *format,...)
  893. {
  894. va_list parms;
  895. TCHAR tmp[CONFIG_BLEN];
  896. va_start(parms, format);
  897. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  898. cfg_dowrite(f, option, tmp, 0, 1, 1);
  899. va_end(parms);
  900. }
  901. void cfgfile_target_dwrite(struct zfile *f, const TCHAR *option, const TCHAR *format,...)
  902. {
  903. va_list parms;
  904. TCHAR tmp[CONFIG_BLEN];
  905. va_start(parms, format);
  906. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  907. cfg_dowrite(f, option, tmp, 1, 1, 0);
  908. va_end(parms);
  909. }
  910. void cfgfile_target_dwrite_escape(struct zfile *f, const TCHAR *option, const TCHAR *format,...)
  911. {
  912. va_list parms;
  913. TCHAR tmp[CONFIG_BLEN];
  914. va_start(parms, format);
  915. _vsntprintf(tmp, CONFIG_BLEN, format, parms);
  916. cfg_dowrite(f, option, tmp, 1, 1, 1);
  917. va_end(parms);
  918. }
  919. static void cfgfile_write_rom (struct zfile *f, struct multipath *mp, const TCHAR *romfile, const TCHAR *name)
  920. {
  921. TCHAR *str = cfgfile_subst_path (mp->path[0], UNEXPANDED, romfile);
  922. str = cfgfile_put_multipath (mp, str);
  923. cfgfile_write_str (f, name, str);
  924. struct zfile *zf = zfile_fopen (str, _T("rb"), ZFD_ALL);
  925. if (zf) {
  926. struct romdata *rd = getromdatabyzfile (zf);
  927. if (rd) {
  928. TCHAR name2[MAX_DPATH], str2[MAX_DPATH];
  929. _tcscpy (name2, name);
  930. _tcscat (name2, _T("_id"));
  931. _stprintf (str2, _T("%08X,%s"), rd->crc32, rd->name);
  932. cfgfile_write_str (f, name2, str2);
  933. }
  934. zfile_fclose (zf);
  935. }
  936. xfree (str);
  937. }
  938. static void cfgfile_to_path_save(const TCHAR *in, TCHAR *out, int type)
  939. {
  940. if (_tcschr(in, '%')) {
  941. _tcscpy(out, in);
  942. } else {
  943. cfgfile_resolve_path_out_save(in, out, MAX_DPATH, type);
  944. }
  945. }
  946. static void cfgfile_write_path2(struct zfile *f, const TCHAR *option, const TCHAR *value, int type)
  947. {
  948. if (_tcschr(value, '%')) {
  949. cfgfile_write_str(f, option, value);
  950. } else {
  951. TCHAR path[MAX_DPATH];
  952. cfgfile_resolve_path_out_save(value, path, MAX_DPATH, type);
  953. cfgfile_write_str(f, option, path);
  954. }
  955. }
  956. static void cfgfile_dwrite_path2(struct zfile *f, const TCHAR *option, const TCHAR *value, int type)
  957. {
  958. if (_tcschr(value, '%')) {
  959. cfgfile_dwrite_str(f, option, value);
  960. } else {
  961. TCHAR path[MAX_DPATH];
  962. cfgfile_resolve_path_out_save(value, path, MAX_DPATH, type);
  963. cfgfile_dwrite_str(f, option, path);
  964. }
  965. }
  966. static void cfgfile_write_path (struct zfile *f, struct multipath *mp, const TCHAR *option, const TCHAR *value)
  967. {
  968. TCHAR *s = cfgfile_put_multipath (mp, value);
  969. cfgfile_write_str (f, option, s);
  970. xfree (s);
  971. }
  972. static void cfgfile_dwrite_path (struct zfile *f, struct multipath *mp, const TCHAR *option, const TCHAR *value)
  973. {
  974. TCHAR *s = cfgfile_put_multipath (mp, value);
  975. cfgfile_dwrite_str (f, option, s);
  976. xfree (s);
  977. }
  978. static void cfgfile_write_multichoice(struct zfile *f, const TCHAR *option, const TCHAR *table[], int value)
  979. {
  980. TCHAR tmp[MAX_DPATH];
  981. if (!value)
  982. return;
  983. tmp[0] = 0;
  984. int i = 0;
  985. while (value && table[i]) {
  986. if (value & (1 << i) && table[i][0] && table[i][0] != '|') {
  987. if (tmp[0])
  988. _tcscat(tmp, _T(","));
  989. _tcscat(tmp, table[i]);
  990. }
  991. i++;
  992. }
  993. if (tmp[0])
  994. cfgfile_write(f, option, tmp);
  995. }
  996. static void cfgfile_adjust_path(TCHAR *path, int maxsz, struct multipath *mp)
  997. {
  998. if (path[0] == 0)
  999. return;
  1000. TCHAR *s = target_expand_environment(path, NULL, 0);
  1001. _tcsncpy(path, s, maxsz - 1);
  1002. path[maxsz - 1] = 0;
  1003. if (mp) {
  1004. for (int i = 0; i < MAX_PATHS; i++) {
  1005. if (mp->path[i][0] && _tcscmp(mp->path[i], _T(".\\")) != 0 && _tcscmp(mp->path[i], _T("./")) != 0 && (path[0] != '/' && path[0] != '\\' && !_tcschr(path, ':'))) {
  1006. TCHAR np[MAX_DPATH];
  1007. _tcscpy(np, mp->path[i]);
  1008. fixtrailing(np);
  1009. _tcscat(np, s);
  1010. fullpath(np, sizeof np / sizeof(TCHAR));
  1011. if (zfile_exists(np)) {
  1012. _tcsncpy(path, np, maxsz - 1);
  1013. path[maxsz - 1] = 0;
  1014. xfree(s);
  1015. return;
  1016. }
  1017. }
  1018. }
  1019. }
  1020. fullpath(path, maxsz);
  1021. xfree(s);
  1022. }
  1023. static void cfgfile_resolve_path_out_all(const TCHAR *path, TCHAR *out, int size, int type, bool save)
  1024. {
  1025. struct uae_prefs *p = &currprefs;
  1026. TCHAR *s = NULL;
  1027. switch (type)
  1028. {
  1029. case PATH_DIR:
  1030. s = cfgfile_subst_path_load(UNEXPANDED, &p->path_hardfile, path, true);
  1031. break;
  1032. case PATH_HDF:
  1033. s = cfgfile_subst_path_load(UNEXPANDED, &p->path_hardfile, path, false);
  1034. break;
  1035. case PATH_CD:
  1036. s = cfgfile_subst_path_load(UNEXPANDED, &p->path_cd, path, false);
  1037. break;
  1038. case PATH_ROM:
  1039. s = cfgfile_subst_path_load(UNEXPANDED, &p->path_rom, path, false);
  1040. break;
  1041. case PATH_FLOPPY:
  1042. _tcscpy(out, path);
  1043. cfgfile_adjust_path(out, MAX_DPATH, &p->path_floppy);
  1044. break;
  1045. default:
  1046. s = cfgfile_subst_path(NULL, NULL, path);
  1047. break;
  1048. }
  1049. if (s) {
  1050. _tcscpy(out, s);
  1051. xfree(s);
  1052. }
  1053. if (!save) {
  1054. my_resolvesoftlink(out, size, true);
  1055. }
  1056. }
  1057. void cfgfile_resolve_path_out_load(const TCHAR *path, TCHAR *out, int size, int type)
  1058. {
  1059. cfgfile_resolve_path_out_all(path, out, size, type, false);
  1060. }
  1061. void cfgfile_resolve_path_load(TCHAR *path, int size, int type)
  1062. {
  1063. cfgfile_resolve_path_out_all(path, path, size, type, false);
  1064. }
  1065. void cfgfile_resolve_path_out_save(const TCHAR *path, TCHAR *out, int size, int type)
  1066. {
  1067. cfgfile_resolve_path_out_all(path, out, size, type, true);
  1068. }
  1069. void cfgfile_resolve_path_save(TCHAR *path, int size, int type)
  1070. {
  1071. cfgfile_resolve_path_out_all(path, path, size, type, true);
  1072. }
  1073. static void write_filesys_config (struct uae_prefs *p, struct zfile *f)
  1074. {
  1075. TCHAR tmp[MAX_DPATH], tmp2[MAX_DPATH], tmp3[MAX_DPATH], str1[MAX_DPATH], hdcs[MAX_DPATH];
  1076. for (int i = 0; i < p->mountitems; i++) {
  1077. struct uaedev_config_data *uci = &p->mountconfig[i];
  1078. struct uaedev_config_info *ci = &uci->ci;
  1079. TCHAR *str1b, *str1c, *str2b;
  1080. const TCHAR *str2;
  1081. int bp = ci->bootpri;
  1082. str2 = _T("");
  1083. if (ci->rootdir[0] == ':') {
  1084. TCHAR *ptr;
  1085. // separate harddrive names
  1086. _tcscpy(str1, ci->rootdir);
  1087. ptr = _tcschr (str1 + 1, ':');
  1088. if (ptr) {
  1089. *ptr++ = 0;
  1090. str2 = ptr;
  1091. ptr = (TCHAR *) _tcschr (str2, ',');
  1092. if (ptr)
  1093. *ptr = 0;
  1094. }
  1095. } else {
  1096. cfgfile_to_path_save(ci->rootdir, str1, ci->type == UAEDEV_DIR ? PATH_DIR : (ci->type == UAEDEV_CD ? PATH_CD : (ci->type == UAEDEV_HDF ? PATH_HDF : PATH_TAPE)));
  1097. }
  1098. int ct = ci->controller_type;
  1099. int romtype = 0;
  1100. if (ct >= HD_CONTROLLER_TYPE_SCSI_EXPANSION_FIRST && ct <= HD_CONTROLLER_TYPE_SCSI_LAST) {
  1101. _stprintf(hdcs, _T("scsi%d_%s"), ci->controller_unit, expansionroms[ct - HD_CONTROLLER_TYPE_SCSI_EXPANSION_FIRST].name);
  1102. romtype = expansionroms[ct - HD_CONTROLLER_TYPE_SCSI_EXPANSION_FIRST].romtype;
  1103. } else if (ct >= HD_CONTROLLER_TYPE_IDE_EXPANSION_FIRST && ct <= HD_CONTROLLER_TYPE_IDE_LAST) {
  1104. _stprintf(hdcs, _T("ide%d_%s"), ci->controller_unit, expansionroms[ct - HD_CONTROLLER_TYPE_IDE_EXPANSION_FIRST].name);
  1105. romtype = expansionroms[ct - HD_CONTROLLER_TYPE_IDE_EXPANSION_FIRST].romtype;
  1106. } else if (ct >= HD_CONTROLLER_TYPE_CUSTOM_FIRST && ct <= HD_CONTROLLER_TYPE_CUSTOM_LAST) {
  1107. _stprintf(hdcs, _T("custom%d_%s"), ci->controller_unit, expansionroms[ct - HD_CONTROLLER_TYPE_CUSTOM_FIRST].name);
  1108. romtype = expansionroms[ct - HD_CONTROLLER_TYPE_CUSTOM_FIRST].romtype;
  1109. } else if (ct == HD_CONTROLLER_TYPE_SCSI_AUTO) {
  1110. _stprintf(hdcs, _T("scsi%d"), ci->controller_unit);
  1111. } else if (ct == HD_CONTROLLER_TYPE_IDE_AUTO) {
  1112. _stprintf(hdcs, _T("ide%d"), ci->controller_unit);
  1113. } else if (ct == HD_CONTROLLER_TYPE_UAE) {
  1114. _stprintf(hdcs, _T("uae%d"), ci->controller_unit);
  1115. }
  1116. if (romtype) {
  1117. for (int j = 0; hdcontrollers[j].label; j++) {
  1118. if (hdcontrollers[j].romtype == (romtype & ROMTYPE_MASK)) {
  1119. _stprintf(hdcs, hdcontrollers[j].label, ci->controller_unit);
  1120. break;
  1121. }
  1122. }
  1123. }
  1124. if (ci->controller_type_unit > 0)
  1125. _stprintf(hdcs + _tcslen(hdcs), _T("-%d"), ci->controller_type_unit + 1);
  1126. str1b = cfgfile_escape (str1, _T(":,"), true);
  1127. str1c = cfgfile_escape_min(str1);
  1128. str2b = cfgfile_escape (str2, _T(":,"), true);
  1129. if (ci->type == UAEDEV_DIR) {
  1130. _stprintf (tmp, _T("%s,%s:%s:%s,%d"), ci->readonly ? _T("ro") : _T("rw"),
  1131. ci->devname ? ci->devname : _T(""), ci->volname, str1c, bp);
  1132. cfgfile_write_str (f, _T("filesystem2"), tmp);
  1133. _tcscpy (tmp3, tmp);
  1134. #if 0
  1135. _stprintf (tmp2, _T("filesystem=%s,%s:%s"), uci->readonly ? _T("ro") : _T("rw"),
  1136. uci->volname, str);
  1137. zfile_fputs (f, tmp2);
  1138. #endif
  1139. } else if (ci->type == UAEDEV_HDF || ci->type == UAEDEV_CD || ci->type == UAEDEV_TAPE) {
  1140. TCHAR filesyspath[MAX_DPATH];
  1141. cfgfile_to_path_save(ci->filesys, filesyspath, PATH_HDF);
  1142. TCHAR *sfilesys = cfgfile_escape_min(filesyspath);
  1143. TCHAR *sgeometry = cfgfile_escape(ci->geometry, NULL, true);
  1144. _stprintf (tmp, _T("%s,%s:%s,%d,%d,%d,%d,%d,%s,%s"),
  1145. ci->readonly ? _T("ro") : _T("rw"),
  1146. ci->devname ? ci->devname : _T(""), str1c,
  1147. ci->sectors, ci->surfaces, ci->reserved, ci->blocksize,
  1148. bp, ci->filesys[0] ? sfilesys : _T(""), hdcs);
  1149. _stprintf (tmp3, _T("%s,%s:%s%s%s,%d,%d,%d,%d,%d,%s,%s"),
  1150. ci->readonly ? _T("ro") : _T("rw"),
  1151. ci->devname ? ci->devname : _T(""), str1b, str2b[0] ? _T(":") : _T(""), str2b,
  1152. ci->sectors, ci->surfaces, ci->reserved, ci->blocksize,
  1153. bp, ci->filesys[0] ? sfilesys : _T(""), hdcs);
  1154. if (ci->highcyl || ci->physical_geometry || ci->geometry[0]) {
  1155. TCHAR *s = tmp + _tcslen (tmp);
  1156. TCHAR *s2 = s;
  1157. _stprintf (s2, _T(",%d"), ci->highcyl);
  1158. if ((ci->physical_geometry && ci->pheads && ci->psecs) || ci->geometry[0]) {
  1159. s = tmp + _tcslen (tmp);
  1160. _stprintf (s, _T(",%d/%d/%d"), ci->pcyls, ci->pheads, ci->psecs);
  1161. if (ci->geometry[0]) {
  1162. s = tmp + _tcslen (tmp);
  1163. _stprintf (s, _T(",%s"), sgeometry);
  1164. }
  1165. }
  1166. _tcscat (tmp3, s2);
  1167. xfree(sfilesys);
  1168. xfree(sgeometry);
  1169. }
  1170. if (ci->controller_media_type) {
  1171. _tcscat(tmp, _T(",CF"));
  1172. _tcscat(tmp3, _T(",CF"));
  1173. }
  1174. const TCHAR *extras = NULL;
  1175. if (ct >= HD_CONTROLLER_TYPE_SCSI_FIRST && ct <= HD_CONTROLLER_TYPE_SCSI_LAST) {
  1176. if (ci->unit_feature_level == HD_LEVEL_SCSI_1){
  1177. extras = _T("SCSI1");
  1178. } else if (ci->unit_feature_level == HD_LEVEL_SASI) {
  1179. extras = _T("SASI");
  1180. } else if (ci->unit_feature_level == HD_LEVEL_SASI_ENHANCED) {
  1181. extras = _T("SASIE");
  1182. } else if (ci->unit_feature_level == HD_LEVEL_SASI_CHS) {
  1183. extras = _T("SASI_CHS");
  1184. }
  1185. } else if (ct >= HD_CONTROLLER_TYPE_IDE_FIRST && ct <= HD_CONTROLLER_TYPE_IDE_LAST) {
  1186. if (ci->unit_feature_level == HD_LEVEL_ATA_1) {
  1187. extras = _T("ATA1");
  1188. } else if (ci->unit_feature_level == HD_LEVEL_ATA_2S) {
  1189. extras = _T("ATA2+S");
  1190. }
  1191. }
  1192. if (extras) {
  1193. _tcscat(tmp, _T(","));
  1194. _tcscat(tmp3, _T(","));
  1195. _tcscat(tmp, extras);
  1196. _tcscat(tmp3, extras);
  1197. }
  1198. if (ci->unit_special_flags) {
  1199. TCHAR tmpx[32];
  1200. _stprintf(tmpx, _T(",flags=0x%x"), ci->unit_special_flags);
  1201. _tcscat(tmp, tmpx);
  1202. _tcscat(tmp3, tmpx);
  1203. }
  1204. if (ci->lock) {
  1205. _tcscat(tmp, _T(",lock"));
  1206. _tcscat(tmp3, _T(",lock"));
  1207. }
  1208. if (ci->loadidentity) {
  1209. _tcscat(tmp, _T(",identity"));
  1210. _tcscat(tmp3, _T(",identity"));
  1211. }
  1212. if (ci->type == UAEDEV_HDF)
  1213. cfgfile_write_str (f, _T("hardfile2"), tmp);
  1214. #if 0
  1215. _stprintf (tmp2, _T("hardfile=%s,%d,%d,%d,%d,%s"),
  1216. uci->readonly ? "ro" : "rw", uci->sectors,
  1217. uci->surfaces, uci->reserved, uci->blocksize, str);
  1218. zfile_fputs (f, tmp2);
  1219. #endif
  1220. }
  1221. _stprintf (tmp2, _T("uaehf%d"), i);
  1222. if (ci->type == UAEDEV_CD) {
  1223. cfgfile_write (f, tmp2, _T("cd%d,%s"), ci->device_emu_unit, tmp);
  1224. } else if (ci->type == UAEDEV_TAPE) {
  1225. cfgfile_write (f, tmp2, _T("tape%d,%s"), ci->device_emu_unit, tmp);
  1226. } else {
  1227. cfgfile_write (f, tmp2, _T("%s,%s"), ci->type == UAEDEV_HDF ? _T("hdf") : _T("dir"), tmp3);
  1228. }
  1229. if (ci->type == UAEDEV_DIR) {
  1230. bool add_extra = false;
  1231. if (ci->inject_icons) {
  1232. add_extra = true;
  1233. }
  1234. if (add_extra) {
  1235. _stprintf(tmp2, _T("%s,inject_icons=%s"), ci->devname, ci->inject_icons ? _T("true") : _T("false"));
  1236. cfgfile_write(f, _T("filesystem_extra"), tmp2);
  1237. }
  1238. }
  1239. xfree (str1b);
  1240. xfree (str1c);
  1241. xfree (str2b);
  1242. }
  1243. }
  1244. static void write_compatibility_cpu (struct zfile *f, struct uae_prefs *p)
  1245. {
  1246. TCHAR tmp[100];
  1247. int model;
  1248. model = p->cpu_model;
  1249. if (model == 68030)
  1250. model = 68020;
  1251. if (model == 68060)
  1252. model = 68040;
  1253. if (p->address_space_24 && model == 68020)
  1254. _tcscpy (tmp, _T("68ec020"));
  1255. else
  1256. _stprintf (tmp, _T("%d"), model);
  1257. if (model == 68020 && (p->fpu_model == 68881 || p->fpu_model == 68882))
  1258. _tcscat (tmp, _T("/68881"));
  1259. cfgfile_write (f, _T("cpu_type"), tmp);
  1260. }
  1261. static void write_leds (struct zfile *f, const TCHAR *name, int mask)
  1262. {
  1263. TCHAR tmp[MAX_DPATH];
  1264. tmp[0] = 0;
  1265. for (int i = 0; leds[i]; i++) {
  1266. bool got = false;
  1267. for (int j = 0; leds[j]; j++) {
  1268. if (leds_order[j] == i) {
  1269. if (mask & (1 << j)) {
  1270. if (got)
  1271. _tcscat (tmp, _T(":"));
  1272. _tcscat (tmp, leds[j]);
  1273. got = true;
  1274. }
  1275. }
  1276. }
  1277. if (leds[i + 1] && got)
  1278. _tcscat (tmp, _T(","));
  1279. }
  1280. while (tmp[0] && tmp[_tcslen (tmp) - 1] == ',')
  1281. tmp[_tcslen (tmp) - 1] = 0;
  1282. cfgfile_dwrite_str (f, name, tmp);
  1283. }
  1284. static void write_resolution (struct zfile *f, const TCHAR *ws, const TCHAR *hs, struct wh *wh)
  1285. {
  1286. if (wh->width <= 0 || wh->height <= 0 || wh->special == WH_NATIVE) {
  1287. cfgfile_write_str (f, ws, _T("native"));
  1288. cfgfile_write_str (f, hs, _T("native"));
  1289. } else {
  1290. cfgfile_write (f, ws, _T("%d"), wh->width);
  1291. cfgfile_write (f, hs, _T("%d"), wh->height);
  1292. }
  1293. }
  1294. static int cfgfile_read_rom_settings(const struct expansionboardsettings *ebs, const TCHAR *buf, TCHAR *configtext)
  1295. {
  1296. int settings = 0;
  1297. int bitcnt = 0;
  1298. int sstr = 0;
  1299. if (configtext)
  1300. configtext[0] = 0;
  1301. TCHAR *ct = configtext;
  1302. for (int i = 0; ebs[i].name; i++) {
  1303. const struct expansionboardsettings *eb = &ebs[i];
  1304. bitcnt += eb->bitshift;
  1305. if (eb->type == EXPANSIONBOARD_STRING) {
  1306. TCHAR *p = cfgfile_option_get(buf, eb->configname);
  1307. if (p) {
  1308. _tcscpy(ct, p);
  1309. ct += _tcslen(ct);
  1310. xfree(p);
  1311. }
  1312. *ct++ = 0;
  1313. } else if (eb->type == EXPANSIONBOARD_MULTI) {
  1314. int itemcnt = -1;
  1315. int itemfound = 0;
  1316. const TCHAR *p = eb->configname;
  1317. while (p[0]) {
  1318. if (itemcnt >= 0) {
  1319. if (cfgfile_option_find(buf, p)) {
  1320. itemfound = itemcnt;
  1321. }
  1322. }
  1323. itemcnt++;
  1324. p += _tcslen(p) + 1;
  1325. }
  1326. int cnt = 1;
  1327. int bits = 1;
  1328. for (int i = 0; i < 8; i++) {
  1329. if ((1 << i) >= itemcnt) {
  1330. cnt = 1 << i;
  1331. bits = i;
  1332. break;
  1333. }
  1334. }
  1335. int multimask = cnt - 1;
  1336. if (eb->invert)
  1337. itemfound ^= 0x7fffffff;
  1338. itemfound &= multimask;
  1339. settings |= itemfound << bitcnt;
  1340. bitcnt += bits;
  1341. } else {
  1342. int mask = 1 << bitcnt;
  1343. if (cfgfile_option_find(buf, eb->configname)) {
  1344. settings |= mask;
  1345. }
  1346. if (eb->invert)
  1347. settings ^= mask;
  1348. bitcnt++;
  1349. }
  1350. }
  1351. return settings;
  1352. }
  1353. static void cfgfile_write_rom_settings(const struct expansionboardsettings *ebs, TCHAR *buf, int settings, const TCHAR *settingstring)
  1354. {
  1355. int bitcnt = 0;
  1356. int sstr = 0;
  1357. for (int j = 0; ebs[j].name; j++) {
  1358. const struct expansionboardsettings *eb = &ebs[j];
  1359. bitcnt += eb->bitshift;
  1360. if (eb->type == EXPANSIONBOARD_STRING) {
  1361. if (settingstring) {
  1362. TCHAR tmp[MAX_DPATH];
  1363. const TCHAR *p = settingstring;
  1364. for (int i = 0; i < sstr; i++) {
  1365. p += _tcslen(p) + 1;
  1366. }
  1367. if (buf[0])
  1368. _tcscat(buf, _T(","));
  1369. TCHAR *cs = cfgfile_escape_min(p);
  1370. _stprintf(tmp, _T("%s=%s"), eb->configname, cs);
  1371. _tcscat(buf, tmp);
  1372. xfree(cs);
  1373. sstr++;
  1374. }
  1375. } else if (eb->type == EXPANSIONBOARD_MULTI) {
  1376. int itemcnt = -1;
  1377. const TCHAR *p = eb->configname;
  1378. while (p[0]) {
  1379. itemcnt++;
  1380. p += _tcslen(p) + 1;
  1381. }
  1382. int cnt = 1;
  1383. int bits = 1;
  1384. for (int i = 0; i < 8; i++) {
  1385. if ((1 << i) >= itemcnt) {
  1386. cnt = 1 << i;
  1387. bits = i;
  1388. break;
  1389. }
  1390. }
  1391. int multimask = cnt - 1;
  1392. int multivalue = settings;
  1393. if (eb->invert)
  1394. multivalue ^= 0x7fffffff;
  1395. multivalue = (multivalue >> bitcnt) & multimask;
  1396. p = eb->configname;
  1397. while (multivalue >= 0) {
  1398. multivalue--;
  1399. p += _tcslen(p) + 1;
  1400. }
  1401. if (buf[0])
  1402. _tcscat(buf, _T(","));
  1403. _tcscat(buf, p);
  1404. bitcnt += bits;
  1405. } else {
  1406. int value = settings;
  1407. if (eb->invert)
  1408. value ^= 0x7fffffff;
  1409. if (value & (1 << bitcnt)) {
  1410. if (buf[0])
  1411. _tcscat(buf, _T(","));
  1412. _tcscat(buf, eb->configname);
  1413. }
  1414. bitcnt++;
  1415. }
  1416. }
  1417. }
  1418. static bool is_custom_romboard(struct boardromconfig *br)
  1419. {
  1420. return ((br->device_type & ROMTYPE_MASK) == ROMTYPE_UAEBOARDZ2 || (br->device_type & ROMTYPE_MASK) == ROMTYPE_UAEBOARDZ3);
  1421. }
  1422. static void cfgfile_write_board_rom(struct uae_prefs *prefs, struct zfile *f, struct multipath *mp, struct boardromconfig *br)
  1423. {
  1424. TCHAR buf[MAX_DPATH];
  1425. TCHAR name[256];
  1426. const struct expansionromtype *ert;
  1427. if (br->device_type == 0)
  1428. return;
  1429. ert = get_device_expansion_rom(br->device_type);
  1430. if (!ert)
  1431. return;
  1432. for (int i = 0; i < MAX_BOARD_ROMS; i++) {
  1433. struct romconfig *rc = &br->roms[i];
  1434. if (br->device_num == 0)
  1435. _tcscpy(name, ert->name);
  1436. else
  1437. _stprintf(name, _T("%s-%d"), ert->name, br->device_num + 1);
  1438. if (i == 0 || _tcslen(br->roms[i].romfile)) {
  1439. _stprintf(buf, _T("%s%s_rom_file"), name, i ? _T("_ext") : _T(""));
  1440. cfgfile_write_rom (f, mp, br->roms[i].romfile, buf);
  1441. if (rc->romident[0]) {
  1442. _stprintf(buf, _T("%s%s_rom"), name, i ? _T("_ext") : _T(""));
  1443. cfgfile_dwrite_str (f, buf, rc->romident);
  1444. }
  1445. if (rc->autoboot_disabled || rc->dma24bit || rc->inserted || ert->subtypes || ert->settings || ert->id_jumper || br->device_order > 0 || is_custom_romboard(br)) {
  1446. TCHAR buf2[256], *p;
  1447. buf2[0] = 0;
  1448. p = buf2;
  1449. _stprintf(buf, _T("%s%s_rom_options"), name, i ? _T("_ext") : _T(""));
  1450. if (ert->subtypes) {
  1451. const struct expansionsubromtype *srt = ert->subtypes;
  1452. int k = rc->subtype;
  1453. while (k && srt[1].name) {
  1454. srt++;
  1455. k--;
  1456. }
  1457. _stprintf(p, _T("subtype=%s"), srt->configname);
  1458. }
  1459. if (br->device_order > 0 && prefs->autoconfig_custom_sort) {
  1460. if (buf2[0])
  1461. _tcscat(buf2, _T(","));
  1462. TCHAR *p2 = buf2 + _tcslen(buf2);
  1463. _stprintf(p2, _T("order=%d"), br->device_order);
  1464. }
  1465. if (rc->autoboot_disabled) {
  1466. if (buf2[0])
  1467. _tcscat(buf2, _T(","));
  1468. _tcscat(buf2, _T("autoboot_disabled=true"));
  1469. }
  1470. if (rc->dma24bit) {
  1471. if (buf2[0])
  1472. _tcscat(buf2, _T(","));
  1473. _tcscat(buf2, _T("dma24bit=true"));
  1474. }
  1475. if (rc->inserted) {
  1476. if (buf2[0])
  1477. _tcscat(buf2, _T(","));
  1478. _tcscat(buf2, _T("inserted=true"));
  1479. }
  1480. if (ert->id_jumper) {
  1481. TCHAR tmp[256];
  1482. _stprintf(tmp, _T("id=%d"), rc->device_id);
  1483. if (buf2[0])
  1484. _tcscat(buf2, _T(","));
  1485. _tcscat(buf2, tmp);
  1486. }
  1487. if ((rc->device_settings || rc->configtext[0]) && ert->settings) {
  1488. cfgfile_write_rom_settings(ert->settings, buf2, rc->device_settings, rc->configtext);
  1489. }
  1490. if (is_custom_romboard(br)) {
  1491. if (rc->manufacturer) {
  1492. if (buf2[0])
  1493. _tcscat(buf2, _T(","));
  1494. TCHAR *p2 = buf2 + _tcslen(buf2);
  1495. _stprintf(p2, _T("mid=%u,pid=%u"), rc->manufacturer, rc->product);
  1496. }
  1497. if (rc->autoconfig[0]) {
  1498. uae_u8 *ac = rc->autoconfig;
  1499. if (buf2[0])
  1500. _tcscat(buf2, _T(","));
  1501. TCHAR *p2 = buf2 + _tcslen(buf2);
  1502. _stprintf(p2, _T("data=%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x"),
  1503. ac[0], ac[1], ac[2], ac[3], ac[4], ac[5], ac[6], ac[7],
  1504. ac[8], ac[9], ac[10], ac[11], ac[12], ac[13], ac[14], ac[15]);
  1505. }
  1506. }
  1507. if (buf2[0])
  1508. cfgfile_dwrite_str (f, buf, buf2);
  1509. }
  1510. if (rc->board_ram_size) {
  1511. _stprintf(buf, _T("%s%s_mem_size"), name, i ? _T("_ext") : _T(""));
  1512. cfgfile_write(f, buf, _T("%d"), rc->board_ram_size / 0x40000);
  1513. }
  1514. }
  1515. }
  1516. }
  1517. static bool cfgfile_readromboard(const TCHAR *option, const TCHAR *value, struct romboard *rbp)
  1518. {
  1519. TCHAR tmp1[MAX_DPATH];
  1520. for (int i = 0; i < MAX_ROM_BOARDS; i++) {
  1521. struct romboard *rb = &rbp[i];
  1522. if (i > 0)
  1523. _stprintf(tmp1, _T("romboard%d_options"), i + 1);
  1524. else
  1525. _tcscpy(tmp1, _T("romboard_options"));
  1526. if (!_tcsicmp(option, tmp1)) {
  1527. TCHAR *endptr;
  1528. TCHAR *s1, *s2;
  1529. s1 = cfgfile_option_get(value, _T("start"));
  1530. s2 = cfgfile_option_get(value, _T("…

Large files files are truncated, but you can click here to view the full file