int sdcard_init ( const char *fn, const char *extd81fn ) { char fnbuf[PATH_MAX + 1]; atexit(sdcard_shutdown); sd_status = 0; sd_is_read_only = 1; d81_is_read_only = 1; mounted = 0; memset(sd_sector_bytes, 0, sizeof sd_sector_bytes); memset(sd_d81_img1_start, 0, sizeof sd_d81_img1_start); sdfd = emu_load_file(fn, fnbuf, -1); // get the file descriptor only ... if (sdfd < 0) { ERROR_WINDOW("Cannot open SD-card image %s, SD-card access won't work! ERROR: %s", fn, strerror(errno)); DEBUG("SDCARD: cannot open image %s" NL, fn); } else { // try to open in R/W mode ... int tryfd = open(fnbuf, O_RDWR | O_BINARY); if (tryfd >= 0) { // use R/W mode descriptor if it was OK! close(sdfd); sdfd = tryfd; DEBUG("SDCARD: image file re-opened in RD/WR mode, good" NL); sd_is_read_only = 0; } else INFO_WINDOW("Image file %s could be open only in R/O mode", fnbuf); // Check size! DEBUG("SDCARD: cool, SD-card image %s (as %s) is open" NL, fn, fnbuf); sd_card_size = lseek(sdfd, 0, SEEK_END); if (sd_card_size == (off_t)-1) { ERROR_WINDOW("Cannot query the size of the SD-card image %s, SD-card access won't work! ERROR: %s", fn, strerror(errno)); close(sdfd); sdfd = -1; return sdfd; } if (sd_card_size > 2147483648UL) { ERROR_WINDOW("SD-card image is too large! Max allowed size is 2Gbytes!"); close(sdfd); sdfd = -1; return sdfd; } if (sd_card_size < 67108864) { ERROR_WINDOW("SD-card image is too small! Min required size is 64Mbytes!"); close(sdfd); sdfd = -1; return sdfd; } DEBUG("SDCARD: detected size in Mbytes: %d" NL, (int)(sd_card_size >> 20)); if (sd_card_size & (off_t)511) { ERROR_WINDOW("SD-card image size is not multiple of 512 bytes!!"); close(sdfd); sdfd = -1; return sdfd; } } if (sdfd >= 0) open_external_d81(extd81fn); return sdfd; }
static void save_sample_config ( const char *name ) { #ifdef __EMSCRIPTEN__ DEBUGPRINT("CONFIG: no configuration is saved in case of emscripten." NL); #else char path[PATH_MAX + 1]; FILE *f = open_emu_file(name, "r", path); if (f) { fclose(f); DEBUGPRINT("CONFIG: sample configuration %s (%s) already exists, skipping to create." NL, name, path); return; } f = open_emu_file(name, "w", path); if (f) { dump_config(f); fclose(f); INFO_WINDOW("Note: created sample config file %s", path); } else INFO_WINDOW("Note: cannot create sample config file %s", path); #endif }
int geos_load_kernal ( void ) { Uint8 buffer[0xB000]; int len = emu_load_file(GEOS_KERNAL_NAME, buffer, sizeof buffer); int addr; if (len < 0) { INFO_WINDOW("Cannot open GEOS kernal (%s), or I/O error", GEOS_KERNAL_NAME); return 1; // file not found, or I/O error } if (len < 0x1000) { INFO_WINDOW("Abnormally short GEOS kernal (%s)", GEOS_KERNAL_NAME); return 1; } if (len == sizeof buffer) { INFO_WINDOW("Abnormally large GEOS kernal (%s)", GEOS_KERNAL_NAME); return 1; } addr = buffer[0] | (buffer[1] << 8); // load address if (addr == 0x5000) { cpu_pc = 0x5000; } else if (addr == 0x801) { int sys = check_basic_stub(buffer + 6, addr); if (sys < 0) { INFO_WINDOW("Invalid BASIC stub for the GEOS kernal (%s)", GEOS_KERNAL_NAME); return 1; } cpu_pc = sys; inject_screencoded_message(6 * 40, "*** Basic stub, you need to wait now ***"); } else { INFO_WINDOW("Invalid GEOS kernal load address ($%04X) in (%s)", addr, GEOS_KERNAL_NAME); return 1; } // OK. Everything seems to be so okey ... memcpy(memory + addr, buffer + 2, len - 2); return 0; }
static int open_external_d81 ( const char *fn ) { char fnbuf[PATH_MAX + 1]; if (!fn) return -1; d81_is_read_only = 1; d81fd = emu_load_file(fn, fnbuf, -1); // get the file descriptor only ... if (d81fd < 0) { ERROR_WINDOW("External D81 image was specified (%s) but it cannot be opened: %s", fn, strerror(errno)); DEBUG("SDCARD: cannot open external D81 image %s" NL, fn); } else { off_t d81_size; // try to open in R/W mode int tryfd = open(fnbuf, O_RDWR | O_BINARY); if (tryfd >= 0) { close(d81fd); d81fd = tryfd; DEBUG("SDCARD: exernal D81 image file re-opened in RD/WR mode, good" NL); d81_is_read_only = 0; } else { INFO_WINDOW("External D81 image file %s could be open only in R/O mode", fnbuf); } d81_size = lseek(d81fd, 0, SEEK_END); if (d81_size == (off_t)-1) { ERROR_WINDOW("Cannot query the size of external D81 image %s, using on-SD images! ERROR: %s", fn, strerror(errno)); close(d81fd); d81fd = -1; return d81fd; } if (d81_size != D81_SIZE) { ERROR_WINDOW("Bad external D81 image size " PRINTF_LLD " for %s, should be %d bytes!", (long long)d81_size, fnbuf, D81_SIZE); close(d81fd); d81fd = -1; return d81fd; } } return d81fd; }
int config_init ( int argc, char **argv ) { const char *config_name = DEFAULT_CONFIG_FILE; // name of the used config file, can be overwritten via CLI const struct configOption_st *opt; const char *exe = argv[0]; int default_config = 1; int testparsing = 0; argc--; argv++; #ifdef __EMSCRIPTEN__ exe = strdup("/files/emscripten-virtual-executable"); #endif #ifdef _WIN32 console_open_window(); #endif SDL_VERSION(&sdlver_compiled); SDL_GetVersion(&sdlver_linked); if (sdlver_linked.major < 2 || (sdlver_linked.minor == 0 && sdlver_linked.patch < 4)) { ERROR_WINDOW("Too old SDL library linked, at least version 2.0.4 is required."); return 1; } /* SDL info on paths */ if (get_path_info()) return 1; /* ugly hack: pre-parse comand line to find debug statement (to be worse, it does not handle single argument options too well ... */ #ifdef DISABLE_DEBUG printf("DEBUG: disabled at compilation time." NL); #else while (testparsing < argc) { if (!strcmp(argv[testparsing], "-" DEBUGFILE_OPT) && testparsing != argc - 1 && strcmp(argv[testparsing + 1], "none")) { debug_fp = fopen(argv[testparsing + 1], "w"); DEBUGPRINT("DEBUG: enable logging into file: %s" NL, argv[testparsing + 1]); if (debug_fp == NULL) fprintf(stderr, "Cannot open debug logging file: %s" NL, argv[testparsing + 1]); break; } testparsing++; } testparsing = 0; #endif /* end of ugly hack */ /* let's continue with the info block ... */ DEBUGPRINT("%s %s v%s %s %s" NL "GIT %s compiled by (%s) at (%s) with (%s)-(%s)" NL "Platform: (%s) (%d-bit), video: (%s), audio: (%s), " "SDL version compiled: (%d.%d.%d) and linked: (%d.%d.%d) rev (%s)" NL NL, WINDOW_TITLE, DESCRIPTION, VERSION, COPYRIGHT, PROJECT_PAGE, XEMU_BUILDINFO_GIT, XEMU_BUILDINFO_ON, XEMU_BUILDINFO_AT, CC_TYPE, XEMU_BUILDINFO_CC, SDL_GetPlatform(), ARCH_BITS, SDL_GetCurrentVideoDriver(), SDL_GetCurrentAudioDriver(), sdlver_compiled.major, sdlver_compiled.minor, sdlver_compiled.patch, sdlver_linked.major, sdlver_linked.minor, sdlver_linked.patch, SDL_GetRevision() ); DEBUGPRINT("PATH: executable: %s" NL, exe); /* SDL path info block printout */ DEBUGPRINT("PATH: SDL base path: %s" NL, app_base_path); DEBUGPRINT("PATH: SDL pref path: %s" NL, app_pref_path); #ifndef _WIN32 DEBUGPRINT("PATH: data directory: %s/" NL, DATADIR); #endif DEBUGPRINT("PATH: Current directory: %s" NL NL, current_directory); /* Look the very basic command line switches first */ if (argc && is_help_request_option(argv[0])) { opt = configOptions; printf("USAGE:" NL NL "\t%s -optname optval -optname2 optval2 ..." NL NL "OPTIONS:" NL NL "-config" NL "\tUse config file (or do not use the default one, if \"none\" is specified). This must be the first option if used! [default: @config]" NL, exe ); while (opt->name) { printf("-%s" NL "\t%s [default: %s]" NL, opt->name, opt->help, opt->defval ? opt->defval : "-"); opt++; } printf(NL "%s" NL, disclaimer); #ifdef _WIN32 if (!console_is_open) ERROR_WINDOW("Could not dump help, since console couldn't be allocated."); #endif XEMUEXIT(0); } DEBUGPRINT("%s" NL NL, disclaimer); if (argc && !strcasecmp(argv[0], "-testparsing")) { testparsing = 1; argc--; argv++; } if (argc & 1) { fprintf(stderr, "FATAL: Bad command line: should be even number of parameters (two for an option as key and its value)" NL); return 1; } if (argc > 1 && !strcmp(argv[0], "-config")) { default_config = 0; config_name = argv[1]; argc -= 2; argv += 2; } /* Set default (built-in) values */ opt = configOptions; while (opt->name) { if (opt->defval) config_set_internal(opt->name, -1, opt->defval); opt++; } config_set_internal("rom", 0, COMBINED_ROM_FN); // set default "combined" ROM image set (from segment 0, starting with EXOS) /* Default values for the keyboard follows ... */ keymap_preinit_config_internal(); /* check if we have written sample config file, if there is not, let's create one */ save_sample_config(DEFAULT_CONFIG_SAMPLE_FILE); /* now parse config file (not the sample one!) if there is any */ if (strcasecmp(config_name, "none")) { char path[PATH_MAX + 1]; FILE *f = open_emu_file(config_name, "r", path); DEBUGPRINT("CONFIG: config file: %s (%s)" NL, config_name, f ? path : "*** CANNOT OPEN, NOT USING CONFIG FILE ***"); if (f) { if (load_config_file_stream(f, path)) { fclose(f); return 1; } fclose(f); } else if (!default_config) { fprintf(stderr, "FATAL: Cannot open requested config file: %s" NL, config_name); return 1; } else DEBUGPRINT("CONFIG: Skipping default config file (cannot open), using built-in defaults." NL); } else DEBUGPRINT("CONFIG: Using config file: DISABLED in command line" NL); /* parse command line ... */ if (parse_command_line(argc, argv)) return -1; /* open debug file, if it was not requested via command line at the beginning ... */ if (!debug_fp && strcmp(config_getopt_str(DEBUGFILE_OPT), "none")) { debug_fp = fopen(config_getopt_str(DEBUGFILE_OPT), "w"); DEBUGPRINT("DEBUG: enable logging into file: %s" NL, config_getopt_str(DEBUGFILE_OPT)); if (!debug_fp) ERROR_WINDOW("Cannot open debug messages log file requested: %s", config_getopt_str(DEBUGFILE_OPT)); } if (debug_fp) INFO_WINDOW("DEBUG: Debug messages logging is active"); else printf("DEBUG: No debug messages logging is active." NL); /* test parsing mode? */ if (testparsing) { printf(NL "--- TEST DUMP OF *PARSED* CONFIGURATION (requested)" NL NL); dump_config(stdout); printf(NL "--- END OF TEST PARSING MODE (requested)" NL); XEMUEXIT(0); } DEBUG("CONFIG: End of configuration step." NL NL); /* Close console, unless user requested it with the -console option */ #ifdef _WIN32 if (!config_getopt_int("console")) console_close_window(); #else if (config_getopt_int("console")) console_open_window(); // on non-windows, it only will mark console as open for monitor to be used .. #endif return 0; }
static int download_file_by_db ( const char *filename, const char *storepath ) { char *p; int i; if (!xemu_installer_db) return -1; strcpy(installer_store_to, storepath); p = xemu_installer_db; i = strlen(filename); while (*p) { while (*p && *p <= 32) p++; if (!strncmp(filename, p, i) && (p[i] == '\t' || p[i] == ' ')) { p += i + 1; while (*p == ' ' || *p == '\t') p++; if (*p > 32) { long int sizereq; char *q; if (strncasecmp(p, "http://", 7) && strncasecmp(p, "https://", 8) && strncasecmp(p, "ftp://", 6)) { ERROR_WINDOW("Bad download descriptor file at URL field (bar protocol) for record \"%s\"", filename); return -1; } q = installer_fetch_url; sizereq = 0; while (*p > 32) { if (sizereq == sizeof(installer_fetch_url) - 2) { ERROR_WINDOW("Bad download descriptor file at URL field (too long) for record \"%s\"", filename); return -1; } *q++ = *p++; sizereq++; } *q = 0; sizereq = strtol(p, &p, 0); if (*p > 32) sizereq = -1; if (sizereq > 0 && sizereq <= 4194304) { int ret; char msgbuffer[sizeof(installer_fetch_url) + 256]; if (legal_warning) { INFO_WINDOW("Legal-warning blah-blah ..."); legal_warning = 0; } sprintf(msgbuffer, "Downloading file \"%s\". Do you agree?\nSource: %s", filename, installer_fetch_url); if (QUESTION_WINDOW("YES|NO", msgbuffer)) return -1; ret = download_file(sizereq); if (!ret) INFO_WINDOW("File %s seems to be downloaded nicely with %s", filename, *downloader_utility_spec_start_p); return ret; } else { ERROR_WINDOW("Bad download descriptor file at size field for record \"%s\" (or this file is not auto-installable)", filename); return -1; } } } while (*p && *p != '\n' && *p != '\r') p++; } DEBUGPRINT("INSTALLER: file-key %s cannot be found in the download description file" NL, filename); return -1; }
/* This function also re-initializes the whole memory! Do not call it after you defined RAM for the system, but only before! */ int roms_load ( void ) { int seg, last = 0; char path[PATH_MAX + 1]; if (reloading) // in case of already defined (reloading) memory model, we want to back our SRAM segments up - if any at all ... sram_save_all_segments(); for (seg = 0; seg < 0x100; seg++ ) { memory_segment_map[seg] = (seg >= 0xFC ? VRAM_SEGMENT : UNUSED_SEGMENT); // 64K VRAM is default, you cannot override that! if (reloading && rom_name_tab[seg]) free((void*)rom_name_tab[seg]); // already defined (reloading) situation, we want to free used memory as well rom_name_tab[seg] = NULL; } reloading = 1; // set reloading flag, in next invocation of roms_load(), it will be done in config reload mode! memset(memory, 0xFF, 0x400000); xep_rom_seg = -1; for (seg = 0; seg < 0x100; seg++ ) { void *option = config_getopt("rom", seg, NULL); if (option) { const char *name; int lseg = seg; FILE *f; config_getopt_pointed(option, &name); if (!strcasecmp(name, "XEP") && seg) { if (memory_segment_map[seg] == UNUSED_SEGMENT) { DEBUG("CONFIG: ROM: segment %02Xh assigned to internal XEP ROM" NL, seg); xep_rom_seg = seg; memory_segment_map[seg] = XEPROM_SEGMENT; } else ERROR_WINDOW("XEP ROM forced segment assignment cannot be done since segment %02X is not unused", seg); continue; } DEBUG("CONFIG: ROM: segment %02Xh file %s" NL, seg, name); f = open_emu_file(name, "rb", path); if (f == NULL) { ERROR_WINDOW("Cannot open ROM image \"%s\" (to be used from segment %02Xh): %s", name, seg, ERRSTR()); if (!strcmp(name, COMBINED_ROM_FN)) { // this should be the auto-install functionality, with downloading stuff? } return -1; } DEBUG("CONFIG: ROM: ... file path is %s" NL, path); rom_name_tab[seg] = SDL_strdup(path); CHECK_MALLOC(rom_name_tab[seg]); for (;;) { int ret; // Note: lseg overflow is not needed to be tested, as VRAM marks will stop reading of ROM image in the worst case ... if (memory_segment_map[lseg] != UNUSED_SEGMENT) { fclose(f); forget_emu_file(path); ERROR_WINDOW("While reading ROM image \"%s\" into segment %02Xh: already used segment (\"%s\")!", path, lseg, memory_segment_map[lseg]); return -1; } ret = fread(memory + (lseg << 14), 1, 0x4000, f); if (ret) DEBUG("CONFIG: ROM: ... trying read 0x4000 bytes in segment %02Xh, result is %d" NL, lseg, ret); if (ret < 0) { ERROR_WINDOW("Cannot read ROM image \"%s\" (to be used in segment %02Xh): %s", path, lseg, ERRSTR()); fclose(f); forget_emu_file(path); return -1; } else if (ret == 0) { if (lseg == seg) { fclose(f); forget_emu_file(path); ERROR_WINDOW("Null-sized ROM image \"%s\" (to be used in segment %02Xh).", path, lseg); return -1; } break; } else if (ret != 0x4000) { fclose(f); forget_emu_file(path); ERROR_WINDOW("Bad ROM image \"%s\": not multiple of 16K bytes!", path); return -1; } // check if ROM image contains XEP128_ROM segment signature, if so, try to use XEP ROM from here if (!memcmp(memory + (lseg << 14), "XEP__ROM", 8) && xep_rom_seg == -1) { xep_rom_seg = lseg; memory_segment_map[lseg] = XEPROM_SEGMENT; } else memory_segment_map[lseg] = ROM_SEGMENT; if (lseg > last) last = lseg; if (ret != 0x4000) break; lseg++; } fclose(f); forget_emu_file(path); } else if (!seg) { ERROR_WINDOW("Fatal ROM image error: No ROM defined for segment 00h, no EXOS is requested!"); return -1; } } /* XEP ROM: guess where to place it, or disable it ... */ if (config_getopt_int("xeprom")) { // XEP ROM is enabled with 'xeprom' directive if (xep_rom_seg == -1) { // not assigned manually, try to find a place for it ... xep_rom_seg = last + 1; // ... with simply using the segment after the last used ROM segment DEBUGPRINT("CONFIG: ROM: automatic XEP ROM image placer selected segment is %02Xh" NL, xep_rom_seg); } } else { // XEP ROM is disabled (with 'xeprom' directive), _IF_ it was not assigned manually if (xep_rom_seg == -1) { DEBUGPRINT("CONFIG: ROM: XEP ROM is disabled by configuration!" NL); INFO_WINDOW("XEP internal ROM image is disabled by configuration.\nXep128 will work, but no XEP feature will be available."); } } /* XEP ROM: now install our internal ROM, if it's allowed/OK to do so */ if (xep_rom_seg > 0) { if (memory_segment_map[xep_rom_seg] == UNUSED_SEGMENT || memory_segment_map[xep_rom_seg] == XEPROM_SEGMENT) { xep_rom_addr = xep_rom_seg << 14; memset(memory + xep_rom_addr, 0, 0x4000); memcpy(memory + xep_rom_addr, xep_rom_image, sizeof xep_rom_image); memory_segment_map[xep_rom_seg] = XEPROM_SEGMENT; xep_set_default_device_name(NULL); DEBUGPRINT("CONFIG: ROM: XEP internal ROM image has been installed in segment %02Xh" NL, xep_rom_seg); } else { DEBUGPRINT("CONFIG: ROM: XEP internal ROM image CANNOT be installed because segment %02Xh is used!!" NL, xep_rom_seg); ERROR_WINDOW("XEP internal ROM image cannot be installed.\nXep128 will work, but no XEP feature will be available."); xep_rom_seg = -1; } } else xep_rom_seg = -1; return 0; }