/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * * This file is part of the 86Box distribution. * * Configuration file handler. * * * * Authors: Sarah Walker, * Miran Grca, * Fred N. van Kempen, * Overdoze, * David Hrdlička, * * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. * Copyright 2017-2019 Fred N. van Kempen. * Copyright 2018,2019 David Hrdlička. * * NOTE: Forcing config files to be in Unicode encoding breaks * it on Windows XP, and possibly also Vista. Use the * -DANSI_CFG for use on these systems. */ #include #include #include #include #include #include #include #define HAVE_STDARG_H #include <86box/86box.h> #include "cpu.h" #include <86box/device.h> #include <86box/timer.h> #include <86box/nvr.h> #include <86box/config.h> #include <86box/isamem.h> #include <86box/isartc.h> #include <86box/lpt.h> #include <86box/hdd.h> #include <86box/hdc.h> #include <86box/hdc_ide.h> #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> #include <86box/gameport.h> #include <86box/machine.h> #include <86box/mouse.h> #include <86box/network.h> #include <86box/scsi.h> #include <86box/scsi_device.h> #include <86box/cdrom.h> #include <86box/zip.h> #include <86box/mo.h> #include <86box/sound.h> #include <86box/midi.h> #include <86box/snd_mpu401.h> #include <86box/video.h> #include <86box/plat.h> #include <86box/plat_midi.h> #include <86box/ui.h> typedef struct _list_ { struct _list_ *next; } list_t; typedef struct { list_t list; char name[128]; list_t entry_head; } section_t; typedef struct { list_t list; char name[128]; char data[512]; wchar_t wdata[512]; } entry_t; #define list_add(new, head) { \ list_t *next = head; \ \ while (next->next != NULL) \ next = next->next; \ \ (next)->next = new; \ (new)->next = NULL; \ } #define list_delete(old, head) { \ list_t *next = head; \ \ while ((next)->next != old) { \ next = (next)->next; \ } \ \ (next)->next = (old)->next; \ if ((next) == (head)) \ (head)->next = (old)->next; \ } static list_t config_head; /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ static int backwards_compat = 0; #ifdef ENABLE_CONFIG_LOG int config_do_log = ENABLE_CONFIG_LOG; static void config_log(const char *fmt, ...) { va_list ap; if (config_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else #define config_log(fmt, ...) #endif static section_t * find_section(char *name) { section_t *sec; char blank[] = ""; sec = (section_t *)config_head.next; if (name == NULL) name = blank; while (sec != NULL) { if (! strncmp(sec->name, name, sizeof(sec->name))) return(sec); sec = (section_t *)sec->list.next; } return(NULL); } static entry_t * find_entry(section_t *section, char *name) { entry_t *ent; ent = (entry_t *)section->entry_head.next; while (ent != NULL) { if (! strncmp(ent->name, name, sizeof(ent->name))) return(ent); ent = (entry_t *)ent->list.next; } return(NULL); } static int entries_num(section_t *section) { entry_t *ent; int i = 0; ent = (entry_t *)section->entry_head.next; while (ent != NULL) { if (strlen(ent->name) > 0) i++; ent = (entry_t *)ent->list.next; } return(i); } static void delete_section_if_empty(char *head) { section_t *section; section = find_section(head); if (section == NULL) return; if (entries_num(section) == 0) { list_delete(§ion->list, &config_head); free(section); } } static section_t * create_section(char *name) { section_t *ns = malloc(sizeof(section_t)); memset(ns, 0x00, sizeof(section_t)); memcpy(ns->name, name, strlen(name) + 1); list_add(&ns->list, &config_head); return(ns); } static entry_t * create_entry(section_t *section, char *name) { entry_t *ne = malloc(sizeof(entry_t)); memset(ne, 0x00, sizeof(entry_t)); memcpy(ne->name, name, strlen(name) + 1); list_add(&ne->list, §ion->entry_head); return(ne); } #if 0 static void config_free(void) { section_t *sec, *ns; entry_t *ent; sec = (section_t *)config_head.next; while (sec != NULL) { ns = (section_t *)sec->list.next; ent = (entry_t *)sec->entry_head.next; while (ent != NULL) { entry_t *nent = (entry_t *)ent->list.next; free(ent); ent = nent; } free(sec); sec = ns; } } #endif /* Read and parse the configuration file into memory. */ static int config_read(wchar_t *fn) { char sname[128], ename[128]; wchar_t buff[1024]; section_t *sec, *ns; entry_t *ne; int c, d; FILE *f; #if defined(ANSI_CFG) || !defined(_WIN32) f = plat_fopen(fn, L"rt"); #else f = plat_fopen(fn, L"rt, ccs=UNICODE"); #endif if (f == NULL) return(0); sec = malloc(sizeof(section_t)); memset(sec, 0x00, sizeof(section_t)); memset(&config_head, 0x00, sizeof(list_t)); list_add(&sec->list, &config_head); while (1) { memset(buff, 0x00, sizeof(buff)); fgetws(buff, sizeof_w(buff), f); if (feof(f)) break; /* Make sure there are no stray newlines or hard-returns in there. */ if (wcslen(buff) > 0) if (buff[wcslen(buff)-1] == L'\n') buff[wcslen(buff)-1] = L'\0'; if (wcslen(buff) > 0) if (buff[wcslen(buff)-1] == L'\r') buff[wcslen(buff)-1] = L'\0'; /* Skip any leading whitespace. */ c = 0; while ((buff[c] == L' ') || (buff[c] == L'\t')) c++; /* Skip empty lines. */ if (buff[c] == L'\0') continue; /* Skip lines that (only) have a comment. */ if ((buff[c] == L'#') || (buff[c] == L';')) continue; if (buff[c] == L'[') { /*Section*/ c++; d = 0; while (buff[c] != L']' && buff[c]) wctomb(&(sname[d++]), buff[c++]); sname[d] = L'\0'; /* Is the section name properly terminated? */ if (buff[c] != L']') continue; /* Create a new section and insert it. */ ns = malloc(sizeof(section_t)); memset(ns, 0x00, sizeof(section_t)); memcpy(ns->name, sname, 128); list_add(&ns->list, &config_head); /* New section is now the current one. */ sec = ns; continue; } /* Get the variable name. */ d = 0; while ((buff[c] != L'=') && (buff[c] != L' ') && buff[c]) wctomb(&(ename[d++]), buff[c++]); ename[d] = L'\0'; /* Skip incomplete lines. */ if (buff[c] == L'\0') continue; /* Look for =, skip whitespace. */ while ((buff[c] == L'=' || buff[c] == L' ') && buff[c]) c++; /* Skip incomplete lines. */ if (buff[c] == L'\0') continue; /* This is where the value part starts. */ d = c; /* Allocate a new variable entry.. */ ne = malloc(sizeof(entry_t)); memset(ne, 0x00, sizeof(entry_t)); memcpy(ne->name, ename, 128); wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata)-1); ne->wdata[sizeof_w(ne->wdata)-1] = L'\0'; wcstombs(ne->data, ne->wdata, sizeof(ne->data)); ne->data[sizeof(ne->data)-1] = '\0'; /* .. and insert it. */ list_add(&ne->list, &sec->entry_head); } (void)fclose(f); if (do_dump_config) config_dump(); return(1); } /* * Write the in-memory configuration to disk. * This is a public function, because the Settings UI * want to directly write the configuration after it * has changed it. */ void config_write(wchar_t *fn) { wchar_t wtemp[512]; section_t *sec; FILE *f; int fl = 0; #if defined(ANSI_CFG) || !defined(_WIN32) f = plat_fopen(fn, L"wt"); #else f = plat_fopen(fn, L"wt, ccs=UNICODE"); #endif if (f == NULL) return; sec = (section_t *)config_head.next; while (sec != NULL) { entry_t *ent; if (sec->name[0]) { mbstowcs(wtemp, sec->name, strlen(sec->name)+1); if (fl) fwprintf(f, L"\n[%ls]\n", wtemp); else fwprintf(f, L"[%ls]\n", wtemp); fl++; } ent = (entry_t *)sec->entry_head.next; while (ent != NULL) { if (ent->name[0] != '\0') { mbstowcs(wtemp, ent->name, 128); if (ent->wdata[0] == L'\0') fwprintf(f, L"%ls = \n", wtemp); else fwprintf(f, L"%ls = %ls\n", wtemp, ent->wdata); fl++; } ent = (entry_t *)ent->list.next; } sec = (section_t *)sec->list.next; } (void)fclose(f); } #if NOT_USED static void config_new(void) { #if defined(ANSI_CFG) || !defined(_WIN32) FILE *f = _wfopen(config_file, L"wt"); #else FILE *f = _wfopen(config_file, L"wt, ccs=UNICODE"); #endif if (file != NULL) (void)fclose(f); } #endif /* Load "General" section. */ static void load_general(void) { char *cat = "General"; char temp[512]; char *p; vid_resize = !!config_get_int(cat, "vid_resize", 0); memset(temp, '\0', sizeof(temp)); p = config_get_string(cat, "vid_renderer", "default"); vid_api = plat_vidapi(p); config_delete_var(cat, "vid_api"); video_fullscreen_scale = config_get_int(cat, "video_fullscreen_scale", 0); video_fullscreen_first = config_get_int(cat, "video_fullscreen_first", 1); force_43 = !!config_get_int(cat, "force_43", 0); scale = config_get_int(cat, "scale", 1); if (scale > 3) scale = 3; dpi_scale = config_get_int(cat, "dpi_scale", 1); enable_overscan = !!config_get_int(cat, "enable_overscan", 0); vid_cga_contrast = !!config_get_int(cat, "vid_cga_contrast", 0); video_grayscale = config_get_int(cat, "video_grayscale", 0); video_graytype = config_get_int(cat, "video_graytype", 0); rctrl_is_lalt = config_get_int(cat, "rctrl_is_lalt", 0); update_icons = config_get_int(cat, "update_icons", 1); window_remember = config_get_int(cat, "window_remember", 0); if (window_remember) { p = config_get_string(cat, "window_coordinates", NULL); if (p == NULL) p = "0, 0, 0, 0"; sscanf(p, "%i, %i, %i, %i", &window_w, &window_h, &window_x, &window_y); } else { config_delete_var(cat, "window_remember"); config_delete_var(cat, "window_coordinates"); window_w = window_h = window_x = window_y = 0; } sound_gain = config_get_int(cat, "sound_gain", 0); confirm_reset = config_get_int(cat, "confirm_reset", 1); confirm_exit = config_get_int(cat, "confirm_exit", 1); #ifdef USE_LANGUAGE /* * Currently, 86Box is English (US) only, but in the future * (version 3.0 at the earliest) other languages will be * added, therefore it is better to future-proof the code. */ plat_langid = config_get_hex16(cat, "language", 0x0409); #endif #if USE_DISCORD enable_discord = !!config_get_int(cat, "enable_discord", 0); #endif } /* Load "Machine" section. */ static void load_machine(void) { char *cat = "Machine"; char *p; int c, i, speed, legacy_mfg, legacy_cpu; double multi; cpu_family_t *legacy_family; p = config_get_string(cat, "machine", NULL); if (p != NULL) { if (! strcmp(p, "8500ttc")) /* correct typo */ machine = machine_get_machine_from_internal_name("8600ttc"); else if (! strcmp(p, "president")) /* migrate from removed machine */ machine = machine_get_machine_from_internal_name("mb500n"); else machine = machine_get_machine_from_internal_name(p); } else machine = 0; if (machine >= machine_count()) machine = machine_count() - 1; /* This is for backwards compatibility. */ p = config_get_string(cat, "model", NULL); if (p != NULL) { if (! strcmp(p, "p55r2p4")) /* correct typo */ machine = machine_get_machine_from_internal_name("p55t2p4"); else machine = machine_get_machine_from_internal_name(p); config_delete_var(cat, "model"); } if (machine >= machine_count()) machine = machine_count() - 1; /* Backwards compatibility for the previous CPU model system. */ legacy_mfg = config_get_int(cat, "cpu_manufacturer", 0); legacy_cpu = config_get_int(cat, "cpu", 0); if (legacy_mfg || legacy_cpu) { /* Look for a machine entry on the legacy table. */ p = machine_get_internal_name(); c = 0; while (cpu_legacy_table[c].machine) { if (!strcmp(p, cpu_legacy_table[c].machine)) break; c++; } if (cpu_legacy_table[c].machine) { /* Look for a corresponding CPU entry. */ i = -1; cpu_legacy_table_t *legacy_table_entry; do { i++; legacy_table_entry = (cpu_legacy_table_t *) &cpu_legacy_table[c].tables[legacy_mfg][i]; if (legacy_cpu >= legacy_table_entry->old_offset) { /* Found CPU entry. */ if (!(legacy_family = cpu_get_family((char *) legacy_table_entry->family))) /* check if the family exists */ break; config_set_string(cat, "cpu_family", (char *) legacy_family->internal_name); legacy_cpu -= legacy_table_entry->old_offset; legacy_cpu += legacy_table_entry->new_offset; while (!cpu_is_eligible(legacy_family, legacy_cpu, machine) && (legacy_family->cpus[legacy_cpu].cpu_type != 0)) /* if the legacy CPU is no longer eligible, bump it up until one is eligible or we're out of CPUs */ legacy_cpu++; if (legacy_family->cpus[legacy_cpu].cpu_type != 0) { /* store only if an eligible CPU was found; if none are, reset to the first one */ config_set_int(cat, "cpu_speed", legacy_family->cpus[legacy_cpu].rspeed); config_set_double(cat, "cpu_multi", legacy_family->cpus[legacy_cpu].multi); } break; } } while (cpu_legacy_table[c].tables[legacy_mfg][i].old_offset); } } /* Current CPU model system. */ cpu_f = NULL; p = config_get_string(cat, "cpu_family", NULL); if (p) cpu_f = cpu_get_family(p); if (cpu_f) { speed = config_get_int(cat, "cpu_speed", 0); multi = config_get_double(cat, "cpu_multi", 0); /* Find the configured CPU. */ c = 0; i = -1; while (cpu_f->cpus[c].cpu_type != -1) { if (cpu_is_eligible(cpu_f, c, machine)) { /* skip ineligible CPUs */ if (i == -1) /* store the first eligible CPU */ i = c; if ((cpu_f->cpus[c].rspeed == speed) && (cpu_f->cpus[c].multi == multi)) /* check if clock speed and multiplier match */ break; } c++; } if (cpu_f->cpus[c].cpu_type == -1) /* use first eligible CPU if no match was found */ c = MAX(i, 0); cpu = c; cpu_s = (CPU *) &cpu_f->cpus[cpu]; } else { /* default */ /* Find first eligible family. */ c = 0; while (!cpu_family_is_eligible(&cpu_families[c], machine)) { if (cpu_families[c++].package == 0) { fatal("No eligible CPU families for the selected machine\n"); return; } } cpu_f = &cpu_families[c]; /* Find first eligible CPU in that family. */ c = 0; while (!cpu_is_eligible(cpu_f, c, machine)) { if (cpu_f->cpus[c++].cpu_type == 0) { fatal("No eligible CPUs for the default CPU family for the selected machine\n"); return; } } cpu = c; cpu_s = (CPU *) &cpu_f->cpus[cpu]; } cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); p = (char *)config_get_string(cat, "fpu_type", "none"); fpu_type = fpu_get_type(cpu_f, cpu, p); mem_size = config_get_int(cat, "mem_size", 4096); #if 0 if (mem_size < (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram)) mem_size = (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram); #endif if (mem_size > 2097152) mem_size = 2097152; cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0); p = config_get_string(cat, "time_sync", NULL); if (p != NULL) { if (!strcmp(p, "disabled")) time_sync = TIME_SYNC_DISABLED; else if (!strcmp(p, "local")) time_sync = TIME_SYNC_ENABLED; else if (!strcmp(p, "utc") || !strcmp(p, "gmt")) time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; else time_sync = TIME_SYNC_ENABLED; } else time_sync = !!config_get_int(cat, "enable_sync", 1); /* Remove this after a while.. */ config_delete_var(cat, "nvr_path"); config_delete_var(cat, "enable_sync"); } /* Load "Video" section. */ static void load_video(void) { char *cat = "Video"; char *p; int free_p = 0; if (machines[machine].flags & MACHINE_VIDEO_ONLY) { config_delete_var(cat, "gfxcard"); gfxcard = VID_INTERNAL; } else { p = config_get_string(cat, "gfxcard", NULL); if (p == NULL) { if (machines[machine].flags & MACHINE_VIDEO) { p = (char *)malloc((strlen("internal")+1)*sizeof(char)); strcpy(p, "internal"); } else { p = (char *)malloc((strlen("none")+1)*sizeof(char)); strcpy(p, "none"); } free_p = 1; } gfxcard = video_get_video_from_internal_name(p); if (free_p) free(p); } voodoo_enabled = !!config_get_int(cat, "voodoo", 0); } /* Load "Input Devices" section. */ static void load_input_devices(void) { char *cat = "Input devices"; char temp[512]; int c, d; char *p; p = config_get_string(cat, "mouse_type", NULL); if (p != NULL) mouse_type = mouse_get_from_internal_name(p); else mouse_type = 0; joystick_type = config_get_int(cat, "joystick_type", JOYSTICK_TYPE_NONE); for (c=0; c= 2) ? 0 : 1); } for (c = 0; c < 3; c++) { sprintf(temp, "lpt%d_enabled", c + 1); lpt_ports[c].enabled = !!config_get_int(cat, temp, (c == 0) ? 1 : 0); sprintf(temp, "lpt%d_device", c + 1); p = (char *) config_get_string(cat, temp, "none"); lpt_ports[c].device = lpt_device_get_from_internal_name(p); } /* Legacy config compatibility. */ d = config_get_int(cat, "lpt_enabled", 2); if (d < 2) { for (c = 0; c < 3; c++) lpt_ports[c].enabled = d; } config_delete_var(cat, "lpt_enabled"); } /* Load "Other Peripherals" section. */ static void load_other_peripherals(void) { char *cat = "Other peripherals"; char *p; char temp[512]; int c, free_p = 0; p = config_get_string(cat, "scsicard", NULL); if (p != NULL) scsi_card_current = scsi_card_get_from_internal_name(p); else scsi_card_current = 0; p = config_get_string(cat, "fdc", NULL); if (p != NULL) fdc_type = fdc_card_get_from_internal_name(p); else fdc_type = FDC_INTERNAL; p = config_get_string(cat, "hdc", NULL); if (p == NULL) { if (machines[machine].flags & MACHINE_HDC) { p = (char *)malloc((strlen("internal")+1)*sizeof(char)); strcpy(p, "internal"); } else { p = (char *)malloc((strlen("none")+1)*sizeof(char)); strcpy(p, "none"); } free_p = 1; } if (!strcmp(p, "mfm_xt")) hdc_current = hdc_get_from_internal_name("st506_xt"); else if (!strcmp(p, "mfm_xt_dtc5150x")) hdc_current = hdc_get_from_internal_name("st506_xt_dtc5150x"); else if (!strcmp(p, "mfm_at")) hdc_current = hdc_get_from_internal_name("st506_at"); else hdc_current = hdc_get_from_internal_name(p); if (free_p) { free(p); p = NULL; } ide_ter_enabled = !!config_get_int(cat, "ide_ter", 0); ide_qua_enabled = !!config_get_int(cat, "ide_qua", 0); bugger_enabled = !!config_get_int(cat, "bugger_enabled", 0); postcard_enabled = !!config_get_int(cat, "postcard_enabled", 0); for (c = 0; c < ISAMEM_MAX; c++) { sprintf(temp, "isamem%d_type", c); p = config_get_string(cat, temp, "none"); isamem_type[c] = isamem_get_from_internal_name(p); } p = config_get_string(cat, "isartc_type", "none"); isartc_type = isartc_get_from_internal_name(p); } /* Load "Hard Disks" section. */ static void load_hard_disks(void) { char *cat = "Hard disks"; char temp[512], tmp2[512]; char s[512]; int c; char *p; wchar_t *wp; uint32_t max_spt, max_hpc, max_tracks; uint32_t board = 0, dev = 0; memset(temp, '\0', sizeof(temp)); for (c=0; c max_spt) hdd[c].spt = max_spt; if (hdd[c].hpc > max_hpc) hdd[c].hpc = max_hpc; if (hdd[c].tracks > max_tracks) hdd[c].tracks = max_tracks; /* MFM/RLL */ sprintf(temp, "hdd_%02i_mfm_channel", c+1); if (hdd[c].bus == HDD_BUS_MFM) hdd[c].mfm_channel = !!config_get_int(cat, temp, c & 1); else config_delete_var(cat, temp); /* XTA */ sprintf(temp, "hdd_%02i_xta_channel", c+1); if (hdd[c].bus == HDD_BUS_XTA) hdd[c].xta_channel = !!config_get_int(cat, temp, c & 1); else config_delete_var(cat, temp); /* ESDI */ sprintf(temp, "hdd_%02i_esdi_channel", c+1); if (hdd[c].bus == HDD_BUS_ESDI) hdd[c].esdi_channel = !!config_get_int(cat, temp, c & 1); else config_delete_var(cat, temp); /* IDE */ sprintf(temp, "hdd_%02i_ide_channel", c+1); if (hdd[c].bus == HDD_BUS_IDE) { sprintf(tmp2, "%01u:%01u", c>>1, c&1); p = config_get_string(cat, temp, tmp2); sscanf(p, "%01u:%01u", &board, &dev); board &= 3; dev &= 1; hdd[c].ide_channel = (board<<1) + dev; if (hdd[c].ide_channel > 7) hdd[c].ide_channel = 7; } else { config_delete_var(cat, temp); } /* SCSI */ sprintf(temp, "hdd_%02i_scsi_id", c+1); if (hdd[c].bus == HDD_BUS_SCSI) { hdd[c].scsi_id = config_get_int(cat, temp, c); if (hdd[c].scsi_id > 15) hdd[c].scsi_id = 15; } else config_delete_var(cat, temp); memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); sprintf(temp, "hdd_%02i_fn", c+1); wp = config_get_wstring(cat, temp, L""); #if 0 /* * NOTE: * Temporary hack to remove the absolute * path currently saved in most config * files. We should remove this before * finalizing this release! --FvK */ if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { /* * Yep, its absolute and prefixed * with the CFG path. Just strip * that off for now... */ wcsncpy(hdd[c].fn, &wp[wcslen(usr_path)], sizeof_w(hdd[c].fn)); } else #endif if (plat_path_abs(wp)) { wcsncpy(hdd[c].fn, wp, sizeof_w(hdd[c].fn)); } else { wcsncpy(hdd[c].fn, usr_path, sizeof_w(hdd[c].fn)); wcsncat(hdd[c].fn, wp, sizeof_w(hdd[c].fn)-wcslen(usr_path)); } /* If disk is empty or invalid, mark it for deletion. */ if (! hdd_is_valid(c)) { sprintf(temp, "hdd_%02i_parameters", c+1); config_delete_var(cat, temp); sprintf(temp, "hdd_%02i_preide_channels", c+1); config_delete_var(cat, temp); sprintf(temp, "hdd_%02i_ide_channels", c+1); config_delete_var(cat, temp); sprintf(temp, "hdd_%02i_scsi_id", c+1); config_delete_var(cat, temp); sprintf(temp, "hdd_%02i_fn", c+1); config_delete_var(cat, temp); } sprintf(temp, "hdd_%02i_mfm_channel", c+1); config_delete_var(cat, temp); sprintf(temp, "hdd_%02i_ide_channel", c+1); config_delete_var(cat, temp); } } /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ /* Load "Floppy Drives" section. */ static void load_floppy_drives(void) { char *cat = "Floppy drives"; char temp[512], *p; wchar_t *wp; int c; if (!backwards_compat) return; for (c=0; c 13) fdd_set_type(c, 13); config_delete_var(cat, temp); sprintf(temp, "fdd_%02i_fn", c + 1); wp = config_get_wstring(cat, temp, L""); config_delete_var(cat, temp); #if 0 /* * NOTE: * Temporary hack to remove the absolute * path currently saved in most config * files. We should remove this before * finalizing this release! --FvK */ if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { /* * Yep, its absolute and prefixed * with the EXE path. Just strip * that off for now... */ wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); } else #endif wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); /* if (*wp != L'\0') config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ sprintf(temp, "fdd_%02i_writeprot", c+1); ui_writeprot[c] = !!config_get_int(cat, temp, 0); config_delete_var(cat, temp); sprintf(temp, "fdd_%02i_turbo", c + 1); fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); config_delete_var(cat, temp); sprintf(temp, "fdd_%02i_check_bpb", c+1); fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); config_delete_var(cat, temp); } delete_section_if_empty(cat); } /* Load "Floppy and CD-ROM Drives" section. */ static void load_floppy_and_cdrom_drives(void) { char *cat = "Floppy and CD-ROM drives"; char temp[512], tmp2[512], *p; char s[512]; unsigned int board = 0, dev = 0; wchar_t *wp; int c, d = 0; /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ backwards_compat = (find_section(cat) == NULL); memset(temp, 0x00, sizeof(temp)); for (c=0; c 13) fdd_set_type(c, 13); sprintf(temp, "fdd_%02i_fn", c + 1); wp = config_get_wstring(cat, temp, L""); #if 0 /* * NOTE: * Temporary hack to remove the absolute * path currently saved in most config * files. We should remove this before * finalizing this release! --FvK */ if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { /* * Yep, its absolute and prefixed * with the EXE path. Just strip * that off for now... */ wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); } else #endif wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); /* if (*wp != L'\0') config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ sprintf(temp, "fdd_%02i_writeprot", c+1); ui_writeprot[c] = !!config_get_int(cat, temp, 0); sprintf(temp, "fdd_%02i_turbo", c + 1); fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); sprintf(temp, "fdd_%02i_check_bpb", c+1); fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); /* Check whether each value is default, if yes, delete it so that only non-default values will later be saved. */ if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) { sprintf(temp, "fdd_%02i_type", c+1); config_delete_var(cat, temp); } if (wcslen(floppyfns[c]) == 0) { sprintf(temp, "fdd_%02i_fn", c+1); config_delete_var(cat, temp); } if (ui_writeprot[c] == 0) { sprintf(temp, "fdd_%02i_writeprot", c+1); config_delete_var(cat, temp); } if (fdd_get_turbo(c) == 0) { sprintf(temp, "fdd_%02i_turbo", c+1); config_delete_var(cat, temp); } if (fdd_get_check_bpb(c) == 1) { sprintf(temp, "fdd_%02i_check_bpb", c+1); config_delete_var(cat, temp); } } memset(temp, 0x00, sizeof(temp)); for (c=0; c>1, (c+2)&1); p = config_get_string(cat, temp, tmp2); sscanf(p, "%01u:%01u", &board, &dev); board &= 3; dev &= 1; cdrom[c].ide_channel = (board<<1)+dev; if (cdrom[c].ide_channel > 7) cdrom[c].ide_channel = 7; } else { sprintf(temp, "cdrom_%02i_scsi_id", c+1); if (cdrom[c].bus_type == CDROM_BUS_SCSI) { cdrom[c].scsi_device_id = config_get_int(cat, temp, c+2); if (cdrom[c].scsi_device_id > 15) cdrom[c].scsi_device_id = 15; } else config_delete_var(cat, temp); } sprintf(temp, "cdrom_%02i_image_path", c+1); wp = config_get_wstring(cat, temp, L""); #if 0 /* * NOTE: * Temporary hack to remove the absolute * path currently saved in most config * files. We should remove this before * finalizing this release! --FvK */ if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { /* * Yep, its absolute and prefixed * with the EXE path. Just strip * that off for now... */ wcsncpy(cdrom[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom[c].image_path)); } else #endif wcsncpy(cdrom[c].image_path, wp, sizeof_w(cdrom[c].image_path)); if (cdrom[c].host_drive && (cdrom[c].host_drive != 200)) cdrom[c].host_drive = 0; if ((cdrom[c].host_drive == 0x200) && (wcslen(cdrom[c].image_path) == 0)) cdrom[c].host_drive = 0; /* If the CD-ROM is disabled, delete all its variables. */ if (cdrom[c].bus_type == CDROM_BUS_DISABLED) { sprintf(temp, "cdrom_%02i_host_drive", c+1); config_delete_var(cat, temp); sprintf(temp, "cdrom_%02i_parameters", c+1); config_delete_var(cat, temp); sprintf(temp, "cdrom_%02i_ide_channel", c+1); config_delete_var(cat, temp); sprintf(temp, "cdrom_%02i_scsi_id", c+1); config_delete_var(cat, temp); sprintf(temp, "cdrom_%02i_image_path", c+1); config_delete_var(cat, temp); } sprintf(temp, "cdrom_%02i_iso_path", c+1); config_delete_var(cat, temp); } } /* Load "Other Removable Devices" section. */ static void load_other_removable_devices(void) { char *cat = "Other removable devices"; char temp[512], tmp2[512], *p; char s[512]; unsigned int board = 0, dev = 0; wchar_t *wp; int c, d = 0; /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ if (backwards_compat) { memset(temp, 0x00, sizeof(temp)); for (c=0; c>1, (c+2)&1); p = config_get_string(cat, temp, tmp2); sscanf(p, "%01u:%01u", &board, &dev); board &= 3; dev &= 1; cdrom[c].ide_channel = (board<<1)+dev; if (cdrom[c].ide_channel > 7) cdrom[c].ide_channel = 7; } else { sprintf(temp, "cdrom_%02i_scsi_id", c+1); if (cdrom[c].bus_type == CDROM_BUS_SCSI) { cdrom[c].scsi_device_id = config_get_int(cat, temp, c+2); if (cdrom[c].scsi_device_id > 15) cdrom[c].scsi_device_id = 15; } else config_delete_var(cat, temp); } config_delete_var(cat, temp); sprintf(temp, "cdrom_%02i_image_path", c+1); wp = config_get_wstring(cat, temp, L""); config_delete_var(cat, temp); #if 0 /* * NOTE: * Temporary hack to remove the absolute * path currently saved in most config * files. We should remove this before * finalizing this release! --FvK */ if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { /* * Yep, its absolute and prefixed * with the EXE path. Just strip * that off for now... */ wcsncpy(cdrom[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom[c].image_path)); } else #endif wcsncpy(cdrom[c].image_path, wp, sizeof_w(cdrom[c].image_path)); if (cdrom[c].host_drive && (cdrom[c].host_drive != 200)) cdrom[c].host_drive = 0; if ((cdrom[c].host_drive == 0x200) && (wcslen(cdrom[c].image_path) == 0)) cdrom[c].host_drive = 0; } } backwards_compat = 0; memset(temp, 0x00, sizeof(temp)); for (c=0; c>1, (c+2)&1); p = config_get_string(cat, temp, tmp2); sscanf(p, "%01u:%01u", &board, &dev); board &= 3; dev &= 1; zip_drives[c].ide_channel = (board<<1)+dev; if (zip_drives[c].ide_channel > 7) zip_drives[c].ide_channel = 7; } else { sprintf(temp, "zip_%02i_scsi_id", c+1); if (zip_drives[c].bus_type == ZIP_BUS_SCSI) { zip_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); if (zip_drives[c].scsi_device_id > 15) zip_drives[c].scsi_device_id = 15; } else config_delete_var(cat, temp); } sprintf(temp, "zip_%02i_image_path", c+1); wp = config_get_wstring(cat, temp, L""); #if 0 /* * NOTE: * Temporary hack to remove the absolute * path currently saved in most config * files. We should remove this before * finalizing this release! --FvK */ if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { /* * Yep, its absolute and prefixed * with the EXE path. Just strip * that off for now... */ wcsncpy(zip_drives[c].image_path, &wp[wcslen(usr_path)], sizeof_w(zip_drives[c].image_path)); } else #endif wcsncpy(zip_drives[c].image_path, wp, sizeof_w(zip_drives[c].image_path)); /* If the CD-ROM is disabled, delete all its variables. */ if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) { sprintf(temp, "zip_%02i_host_drive", c+1); config_delete_var(cat, temp); sprintf(temp, "zip_%02i_parameters", c+1); config_delete_var(cat, temp); sprintf(temp, "zip_%02i_ide_channel", c+1); config_delete_var(cat, temp); sprintf(temp, "zip_%02i_scsi_id", c+1); config_delete_var(cat, temp); sprintf(temp, "zip_%02i_image_path", c+1); config_delete_var(cat, temp); } sprintf(temp, "zip_%02i_iso_path", c+1); config_delete_var(cat, temp); } memset(temp, 0x00, sizeof(temp)); for (c=0; c>1, (c+2)&1); p = config_get_string(cat, temp, tmp2); sscanf(p, "%01u:%01u", &board, &dev); board &= 3; dev &= 1; mo_drives[c].ide_channel = (board<<1)+dev; if (mo_drives[c].ide_channel > 7) mo_drives[c].ide_channel = 7; } else { sprintf(temp, "mo_%02i_scsi_id", c+1); if (mo_drives[c].bus_type == MO_BUS_SCSI) { mo_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); if (mo_drives[c].scsi_device_id > 15) mo_drives[c].scsi_device_id = 15; } else config_delete_var(cat, temp); } sprintf(temp, "mo_%02i_image_path", c+1); wp = config_get_wstring(cat, temp, L""); wcsncpy(mo_drives[c].image_path, wp, sizeof_w(mo_drives[c].image_path)); /* If the CD-ROM is disabled, delete all its variables. */ if (mo_drives[c].bus_type == MO_BUS_DISABLED) { sprintf(temp, "mo_%02i_host_drive", c+1); config_delete_var(cat, temp); sprintf(temp, "mo_%02i_parameters", c+1); config_delete_var(cat, temp); sprintf(temp, "mo_%02i_ide_channel", c+1); config_delete_var(cat, temp); sprintf(temp, "mo_%02i_scsi_id", c+1); config_delete_var(cat, temp); sprintf(temp, "mo_%02i_image_path", c+1); config_delete_var(cat, temp); } sprintf(temp, "mo_%02i_iso_path", c+1); config_delete_var(cat, temp); } } /* Load the specified or a default configuration file. */ void config_load(void) { int i; config_log("Loading config file '%ls'..\n", cfg_path); memset(hdd, 0, sizeof(hard_disk_t)); memset(cdrom, 0, sizeof(cdrom_t) * CDROM_NUM); #ifdef USE_IOCTL memset(cdrom_ioctl, 0, sizeof(cdrom_ioctl_t) * CDROM_NUM); #endif memset(zip_drives, 0, sizeof(zip_drive_t)); if (! config_read(cfg_path)) { cpu_f = &cpu_families[0]; cpu = 0; #ifdef USE_LANGUAGE plat_langid = 0x0409; #endif scale = 1; machine = machine_get_machine_from_internal_name("ibmpc"); fpu_type = fpu_get_type(cpu_f, cpu, "none"); gfxcard = video_get_video_from_internal_name("cga"); vid_api = plat_vidapi("default"); time_sync = TIME_SYNC_ENABLED; joystick_type = JOYSTICK_TYPE_NONE; hdc_current = hdc_get_from_internal_name("none"); serial_enabled[0] = 1; serial_enabled[1] = 1; serial_enabled[2] = 0; serial_enabled[3] = 0; lpt_ports[0].enabled = 1; lpt_ports[1].enabled = 0; lpt_ports[2].enabled = 0; for (i = 0; i < FDD_NUM; i++) { if (i < 2) fdd_set_type(i, 2); else fdd_set_type(i, 0); fdd_set_turbo(i, 0); fdd_set_check_bpb(i, 1); } /* Unmute the CD audio on the first CD-ROM drive. */ cdrom[0].sound_on = 1; mem_size = 640; isartc_type = 0; for (i = 0; i < ISAMEM_MAX; i++) isamem_type[i] = 0; config_log("Config file not present or invalid!\n"); return; } load_general(); /* General */ load_machine(); /* Machine */ load_video(); /* Video */ load_input_devices(); /* Input devices */ load_sound(); /* Sound */ load_network(); /* Network */ load_ports(); /* Ports (COM & LPT) */ load_other_peripherals(); /* Other peripherals */ load_hard_disks(); /* Hard disks */ load_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ /* TODO: Backwards compatibility, get rid of this when enough time has passed. */ load_floppy_drives(); /* Floppy drives */ load_other_removable_devices(); /* Other removable devices */ /* Mark the configuration as changed. */ config_changed = 1; config_log("Config loaded.\n\n"); } /* Save "General" section. */ static void save_general(void) { char *cat = "General"; char temp[512]; char *va_name; config_set_int(cat, "vid_resize", vid_resize); if (vid_resize == 0) config_delete_var(cat, "vid_resize"); va_name = plat_vidapi_name(vid_api); if (!strcmp(va_name, "default")) { config_delete_var(cat, "vid_renderer"); } else { config_set_string(cat, "vid_renderer", va_name); } if (video_fullscreen_scale == 0) config_delete_var(cat, "video_fullscreen_scale"); else config_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); if (video_fullscreen_first == 1) config_delete_var(cat, "video_fullscreen_first"); else config_set_int(cat, "video_fullscreen_first", video_fullscreen_first); if (force_43 == 0) config_delete_var(cat, "force_43"); else config_set_int(cat, "force_43", force_43); if (scale == 1) config_delete_var(cat, "scale"); else config_set_int(cat, "scale", scale); if (dpi_scale == 1) config_delete_var(cat, "dpi_scale"); else config_set_int(cat, "dpi_scale", dpi_scale); if (enable_overscan == 0) config_delete_var(cat, "enable_overscan"); else config_set_int(cat, "enable_overscan", enable_overscan); if (vid_cga_contrast == 0) config_delete_var(cat, "vid_cga_contrast"); else config_set_int(cat, "vid_cga_contrast", vid_cga_contrast); if (video_grayscale == 0) config_delete_var(cat, "video_grayscale"); else config_set_int(cat, "video_grayscale", video_grayscale); if (video_graytype == 0) config_delete_var(cat, "video_graytype"); else config_set_int(cat, "video_graytype", video_graytype); if (rctrl_is_lalt == 0) config_delete_var(cat, "rctrl_is_lalt"); else config_set_int(cat, "rctrl_is_lalt", rctrl_is_lalt); if (update_icons == 1) config_delete_var(cat, "update_icons"); else config_set_int(cat, "update_icons", update_icons); if (window_remember) { config_set_int(cat, "window_remember", window_remember); sprintf(temp, "%i, %i, %i, %i", window_w, window_h, window_x, window_y); config_set_string(cat, "window_coordinates", temp); } else { config_delete_var(cat, "window_remember"); config_delete_var(cat, "window_coordinates"); } if (sound_gain != 0) config_set_int(cat, "sound_gain", sound_gain); else config_delete_var(cat, "sound_gain"); if (confirm_reset != 1) config_set_int(cat, "confirm_reset", confirm_reset); else config_delete_var(cat, "confirm_reset"); if (confirm_exit != 1) config_set_int(cat, "confirm_exit", confirm_exit); else config_delete_var(cat, "confirm_exit"); #ifdef USE_LANGUAGE if (plat_langid == 0x0409) config_delete_var(cat, "language"); else config_set_hex16(cat, "language", plat_langid); #endif #if USE_DISCORD if (enable_discord) config_set_int(cat, "enable_discord", enable_discord); else config_delete_var(cat, "enable_discord"); #endif delete_section_if_empty(cat); } /* Save "Machine" section. */ static void save_machine(void) { char *cat = "Machine"; config_set_string(cat, "machine", machine_get_internal_name()); config_set_string(cat, "cpu_family", (char *) cpu_f->internal_name); config_set_int(cat, "cpu_speed", cpu_f->cpus[cpu].rspeed); config_set_double(cat, "cpu_multi", cpu_f->cpus[cpu].multi); config_delete_var(cat, "cpu_manufacturer"); config_delete_var(cat, "cpu"); if (cpu_waitstates == 0) config_delete_var(cat, "cpu_waitstates"); else config_set_int(cat, "cpu_waitstates", cpu_waitstates); if (fpu_type == 0) config_delete_var(cat, "fpu_type"); else config_set_string(cat, "fpu_type", (char *) fpu_get_internal_name(cpu_f, cpu, fpu_type)); if (mem_size == 4096) config_delete_var(cat, "mem_size"); else config_set_int(cat, "mem_size", mem_size); config_set_int(cat, "cpu_use_dynarec", cpu_use_dynarec); if (time_sync & TIME_SYNC_ENABLED) if (time_sync & TIME_SYNC_UTC) config_set_string(cat, "time_sync", "utc"); else config_set_string(cat, "time_sync", "local"); else config_set_string(cat, "time_sync", "disabled"); delete_section_if_empty(cat); } /* Save "Video" section. */ static void save_video(void) { char *cat = "Video"; config_set_string(cat, "gfxcard", video_get_internal_name(gfxcard)); if (voodoo_enabled == 0) config_delete_var(cat, "voodoo"); else config_set_int(cat, "voodoo", voodoo_enabled); delete_section_if_empty(cat); } /* Save "Input Devices" section. */ static void save_input_devices(void) { char *cat = "Input devices"; char temp[512], tmp2[512]; int c, d; config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); if (joystick_type == JOYSTICK_TYPE_NONE) { config_delete_var(cat, "joystick_type"); for (c = 0; c < 16; c++) { sprintf(tmp2, "joystick_%i_nr", c); config_delete_var(cat, tmp2); for (d=0; d<16; d++) { sprintf(tmp2, "joystick_%i_axis_%i", c, d); config_delete_var(cat, tmp2); } for (d=0; d<16; d++) { sprintf(tmp2, "joystick_%i_button_%i", c, d); config_delete_var(cat, tmp2); } for (d=0; d<16; d++) { sprintf(tmp2, "joystick_%i_pov_%i", c, d); config_delete_var(cat, tmp2); } } } else { config_set_int(cat, "joystick_type", joystick_type); for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) { sprintf(tmp2, "joystick_%i_nr", c); config_set_int(cat, tmp2, joystick_state[c].plat_joystick_nr); if (joystick_state[c].plat_joystick_nr) { for (d=0; d= 2) && !serial_enabled[c])) config_delete_var(cat, temp); else config_set_int(cat, temp, serial_enabled[c]); } for (c = 0; c < 3; c++) { sprintf(temp, "lpt%d_enabled", c + 1); d = (c == 0) ? 1 : 0; if (lpt_ports[c].enabled == d) config_delete_var(cat, temp); else config_set_int(cat, temp, lpt_ports[c].enabled); sprintf(temp, "lpt%d_device", c + 1); if (lpt_ports[c].device == 0) config_delete_var(cat, temp); else config_set_string(cat, temp, (char *) lpt_device_get_internal_name(lpt_ports[c].device)); } delete_section_if_empty(cat); } /* Save "Other Peripherals" section. */ static void save_other_peripherals(void) { char *cat = "Other peripherals"; char temp[512]; int c; if (scsi_card_current == 0) config_delete_var(cat, "scsicard"); else config_set_string(cat, "scsicard", scsi_card_get_internal_name(scsi_card_current)); if (fdc_type == FDC_INTERNAL) config_delete_var(cat, "fdc"); else config_set_string(cat, "fdc", fdc_card_get_internal_name(fdc_type)); config_set_string(cat, "hdc", hdc_get_internal_name(hdc_current)); if (ide_ter_enabled == 0) config_delete_var(cat, "ide_ter"); else config_set_int(cat, "ide_ter", ide_ter_enabled); if (ide_qua_enabled == 0) config_delete_var(cat, "ide_qua"); else config_set_int(cat, "ide_qua", ide_qua_enabled); if (bugger_enabled == 0) config_delete_var(cat, "bugger_enabled"); else config_set_int(cat, "bugger_enabled", bugger_enabled); if (postcard_enabled == 0) config_delete_var(cat, "postcard_enabled"); else config_set_int(cat, "postcard_enabled", postcard_enabled); for (c = 0; c < ISAMEM_MAX; c++) { sprintf(temp, "isamem%d_type", c); if (isamem_type[c] == 0) config_delete_var(cat, temp); else config_set_string(cat, temp, (char *) isamem_get_internal_name(isamem_type[c])); } if (isartc_type == 0) config_delete_var(cat, "isartc_type"); else config_set_string(cat, "isartc_type", isartc_get_internal_name(isartc_type)); delete_section_if_empty(cat); } /* Save "Hard Disks" section. */ static void save_hard_disks(void) { char *cat = "Hard disks"; char temp[32], tmp2[512]; char *p; int c; memset(temp, 0x00, sizeof(temp)); for (c=0; c> 1, hdd[c].ide_channel & 1); config_set_string(cat, temp, tmp2); } sprintf(temp, "hdd_%02i_scsi_id", c+1); if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_SCSI)) config_set_int(cat, temp, hdd[c].scsi_id); else config_delete_var(cat, temp); sprintf(temp, "hdd_%02i_fn", c+1); if (hdd_is_valid(c) && (wcslen(hdd[c].fn) != 0)) if (!wcsnicmp(hdd[c].fn, usr_path, wcslen(usr_path))) config_set_wstring(cat, temp, &hdd[c].fn[wcslen(usr_path)]); else config_set_wstring(cat, temp, hdd[c].fn); else config_delete_var(cat, temp); } delete_section_if_empty(cat); } /* Save "Floppy Drives" section. */ static void save_floppy_and_cdrom_drives(void) { char *cat = "Floppy and CD-ROM drives"; char temp[512], tmp2[512]; int c; for (c=0; c>1, cdrom[c].ide_channel & 1); config_set_string(cat, temp, tmp2); } sprintf(temp, "cdrom_%02i_scsi_id", c + 1); if (cdrom[c].bus_type != CDROM_BUS_SCSI) { config_delete_var(cat, temp); } else { config_set_int(cat, temp, cdrom[c].scsi_device_id); } sprintf(temp, "cdrom_%02i_image_path", c + 1); if ((cdrom[c].bus_type == 0) || (wcslen(cdrom[c].image_path) == 0)) { config_delete_var(cat, temp); } else { config_set_wstring(cat, temp, cdrom[c].image_path); } } delete_section_if_empty(cat); } /* Save "Other Removable Devices" section. */ static void save_other_removable_devices(void) { char *cat = "Other removable devices"; char temp[512], tmp2[512]; int c; for (c=0; c>1, zip_drives[c].ide_channel & 1); config_set_string(cat, temp, tmp2); } sprintf(temp, "zip_%02i_scsi_id", c + 1); if (zip_drives[c].bus_type != ZIP_BUS_SCSI) { config_delete_var(cat, temp); } else { config_set_int(cat, temp, zip_drives[c].scsi_device_id); } sprintf(temp, "zip_%02i_image_path", c + 1); if ((zip_drives[c].bus_type == 0) || (wcslen(zip_drives[c].image_path) == 0)) { config_delete_var(cat, temp); } else { config_set_wstring(cat, temp, zip_drives[c].image_path); } } for (c=0; c>1, mo_drives[c].ide_channel & 1); config_set_string(cat, temp, tmp2); } sprintf(temp, "mo_%02i_scsi_id", c + 1); if (mo_drives[c].bus_type != MO_BUS_SCSI) { config_delete_var(cat, temp); } else { config_set_int(cat, temp, mo_drives[c].scsi_device_id); } sprintf(temp, "mo_%02i_image_path", c + 1); if ((mo_drives[c].bus_type == 0) || (wcslen(mo_drives[c].image_path) == 0)) { config_delete_var(cat, temp); } else { config_set_wstring(cat, temp, mo_drives[c].image_path); } } delete_section_if_empty(cat); } void config_save(void) { save_general(); /* General */ save_machine(); /* Machine */ save_video(); /* Video */ save_input_devices(); /* Input devices */ save_sound(); /* Sound */ save_network(); /* Network */ save_ports(); /* Ports (COM & LPT) */ save_other_peripherals(); /* Other peripherals */ save_hard_disks(); /* Hard disks */ save_floppy_and_cdrom_drives(); /* Floppy and CD-ROM drives */ save_other_removable_devices(); /* Other removable devices */ config_write(cfg_path); } void config_dump(void) { section_t *sec; sec = (section_t *)config_head.next; while (sec != NULL) { entry_t *ent; if (sec->name[0]) config_log("[%s]\n", sec->name); ent = (entry_t *)sec->entry_head.next; while (ent != NULL) { config_log("%s = %ls\n", ent->name, ent->wdata); ent = (entry_t *)ent->list.next; } sec = (section_t *)sec->list.next; } } void config_delete_var(char *head, char *name) { section_t *section; entry_t *entry; section = find_section(head); if (section == NULL) return; entry = find_entry(section, name); if (entry != NULL) { list_delete(&entry->list, §ion->entry_head); free(entry); } } int config_get_int(char *head, char *name, int def) { section_t *section; entry_t *entry; int value; section = find_section(head); if (section == NULL) return(def); entry = find_entry(section, name); if (entry == NULL) return(def); sscanf(entry->data, "%i", &value); return(value); } double config_get_double(char *head, char *name, double def) { section_t *section; entry_t *entry; double value; section = find_section(head); if (section == NULL) return(def); entry = find_entry(section, name); if (entry == NULL) return(def); sscanf(entry->data, "%lg", &value); return(value); } int config_get_hex16(char *head, char *name, int def) { section_t *section; entry_t *entry; unsigned int value; section = find_section(head); if (section == NULL) return(def); entry = find_entry(section, name); if (entry == NULL) return(def); sscanf(entry->data, "%04X", &value); return(value); } int config_get_hex20(char *head, char *name, int def) { section_t *section; entry_t *entry; unsigned int value; section = find_section(head); if (section == NULL) return(def); entry = find_entry(section, name); if (entry == NULL) return(def); sscanf(entry->data, "%05X", &value); return(value); } int config_get_mac(char *head, char *name, int def) { section_t *section; entry_t *entry; unsigned int val0 = 0, val1 = 0, val2 = 0; section = find_section(head); if (section == NULL) return(def); entry = find_entry(section, name); if (entry == NULL) return(def); sscanf(entry->data, "%02x:%02x:%02x", &val0, &val1, &val2); return((val0 << 16) + (val1 << 8) + val2); } char * config_get_string(char *head, char *name, char *def) { section_t *section; entry_t *entry; section = find_section(head); if (section == NULL) return(def); entry = find_entry(section, name); if (entry == NULL) return(def); return(entry->data); } wchar_t * config_get_wstring(char *head, char *name, wchar_t *def) { section_t *section; entry_t *entry; section = find_section(head); if (section == NULL) return(def); entry = find_entry(section, name); if (entry == NULL) return(def); return(entry->wdata); } void config_set_int(char *head, char *name, int val) { section_t *section; entry_t *ent; section = find_section(head); if (section == NULL) section = create_section(head); ent = find_entry(section, name); if (ent == NULL) ent = create_entry(section, name); sprintf(ent->data, "%i", val); mbstowcs(ent->wdata, ent->data, 512); } void config_set_double(char *head, char *name, double val) { section_t *section; entry_t *ent; section = find_section(head); if (section == NULL) section = create_section(head); ent = find_entry(section, name); if (ent == NULL) ent = create_entry(section, name); sprintf(ent->data, "%lg", val); mbstowcs(ent->wdata, ent->data, 512); } void config_set_hex16(char *head, char *name, int val) { section_t *section; entry_t *ent; section = find_section(head); if (section == NULL) section = create_section(head); ent = find_entry(section, name); if (ent == NULL) ent = create_entry(section, name); sprintf(ent->data, "%04X", val); mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); } void config_set_hex20(char *head, char *name, int val) { section_t *section; entry_t *ent; section = find_section(head); if (section == NULL) section = create_section(head); ent = find_entry(section, name); if (ent == NULL) ent = create_entry(section, name); sprintf(ent->data, "%05X", val); mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); } void config_set_mac(char *head, char *name, int val) { section_t *section; entry_t *ent; section = find_section(head); if (section == NULL) section = create_section(head); ent = find_entry(section, name); if (ent == NULL) ent = create_entry(section, name); sprintf(ent->data, "%02x:%02x:%02x", (val>>16)&0xff, (val>>8)&0xff, val&0xff); mbstowcs(ent->wdata, ent->data, 512); } void config_set_string(char *head, char *name, char *val) { section_t *section; entry_t *ent; section = find_section(head); if (section == NULL) section = create_section(head); ent = find_entry(section, name); if (ent == NULL) ent = create_entry(section, name); if ((strlen(val) + 1) <= sizeof(ent->data)) memcpy(ent->data, val, strlen(val) + 1); else memcpy(ent->data, val, sizeof(ent->data)); mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); } void config_set_wstring(char *head, char *name, wchar_t *val) { section_t *section; entry_t *ent; section = find_section(head); if (section == NULL) section = create_section(head); ent = find_entry(section, name); if (ent == NULL) ent = create_entry(section, name); memcpy(ent->wdata, val, sizeof_w(ent->wdata)); wcstombs(ent->data, ent->wdata, sizeof(ent->data)); }