void rarch_main_free(void) { event_command(EVENT_CMD_MSG_QUEUE_DEINIT); event_command(EVENT_CMD_DRIVERS_DEINIT); event_command(EVENT_CMD_LOG_FILE_DEINIT); rarch_main_ctl(RARCH_MAIN_CTL_STATE_FREE, NULL); rarch_main_ctl(RARCH_MAIN_CTL_GLOBAL_FREE, NULL); config_free(); }
/** * video_driver_cached_frame: * * Renders the current video frame. **/ void video_driver_cached_frame(void) { bool is_idle; driver_t *driver = driver_get_ptr(); void *recording = driver ? driver->recording_data : NULL; rarch_main_ctl(RARCH_MAIN_CTL_IS_IDLE, &is_idle); if (is_idle) return; /* Cannot allow recording when pushing duped frames. */ driver->recording_data = NULL; /* Not 100% safe, since the library might have * freed the memory, but no known implementations do this. * It would be really stupid at any rate ... */ if (driver->retro_ctx.frame_cb) driver->retro_ctx.frame_cb( (video_state.frame_cache.data == RETRO_HW_FRAME_BUFFER_VALID) ? NULL : video_state.frame_cache.data, video_state.frame_cache.width, video_state.frame_cache.height, video_state.frame_cache.pitch); driver->recording_data = recording; }
static void frontend_psp_exec(const char *path, bool should_load_game) { #if defined(HAVE_KERNEL_PRX) || defined(IS_SALAMANDER) char argp[512] = {0}; SceSize args = 0; argp[0] = '\0'; strlcpy(argp, eboot_path, sizeof(argp)); args = strlen(argp) + 1; #ifndef IS_SALAMANDER char *fullpath = NULL; rarch_main_ctl(RARCH_MAIN_CTL_GET_CONTENT_PATH, &fullpath); if (should_load_game && fullpath[0] != '\0') { argp[args] = '\0'; strlcat(argp + args, fullpath, sizeof(argp) - args); args += strlen(argp + args) + 1; } #endif RARCH_LOG("Attempt to load executable: [%s].\n", path); exitspawn_kernel(path, args, argp); #endif }
void rarch_main_alloc(void) { settings_t *settings = config_get_ptr(); if (settings) config_free(); settings = config_init(); if (!settings) return; event_command(EVENT_CMD_HISTORY_DEINIT); rarch_main_ctl(RARCH_MAIN_CTL_CLEAR_STATE, NULL); rarch_main_data_clear_state(); }
static void frontend_ps3_exec(const char *path, bool should_load_game) { #ifndef IS_SALAMANDER char *fullpath = NULL; global_t *global = global_get_ptr(); bool original_verbose = global->verbosity; global->verbosity = true; #endif (void)should_load_game; RARCH_LOG("Attempt to load executable: [%s].\n", path); #ifndef IS_SALAMANDER rarch_main_ctl(RARCH_MAIN_CTL_GET_CONTENT_PATH, &fullpath); if (should_load_game && fullpath[0] != '\0') { char game_path[256]; strlcpy(game_path, fullpath, sizeof(game_path)); const char * const spawn_argv[] = { game_path, NULL }; frontend_ps3_exec_exitspawn(path, (const char** const)spawn_argv, NULL); } else #endif { frontend_ps3_exec_exitspawn(path, NULL, NULL); } sceNpTerm(); sys_net_finalize_network(); cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_NP); cellSysmoduleUnloadModule(CELL_SYSMODULE_NET); #ifndef IS_SALAMANDER global->verbosity = original_verbose; #endif }
int menu_iterate_render(void) { bool is_idle; const menu_ctx_driver_t *driver = menu_ctx_driver_get_ptr(); menu_handle_t *menu = menu_driver_get_ptr(); if (!menu) return -1; if (BIT64_GET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER) != BIT64_GET(menu->state, MENU_STATE_RENDER_MESSAGEBOX)) BIT64_SET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER); if (BIT64_GET(menu->state, MENU_STATE_RENDER_FRAMEBUFFER)) menu_display_ctl(MENU_DISPLAY_CTL_SET_FRAMEBUFFER_DIRTY_FLAG, NULL); if (BIT64_GET(menu->state, MENU_STATE_RENDER_MESSAGEBOX) && menu->menu_state.msg[0] != '\0') { if (driver->render_messagebox) driver->render_messagebox(menu->menu_state.msg); if (ui_companion_is_on_foreground()) { const ui_companion_driver_t *ui = ui_companion_get_ptr(); if (ui->render_messagebox) ui->render_messagebox(menu->menu_state.msg); } } if (BIT64_GET(menu->state, MENU_STATE_BLIT)) { menu_animation_ctl(MENU_ANIMATION_CTL_UPDATE_TIME, NULL); if (driver->render) driver->render(); } rarch_main_ctl(RARCH_MAIN_CTL_IS_IDLE, &is_idle); if (menu_driver_alive() && !is_idle) menu_display_ctl(MENU_DISPLAY_CTL_LIBRETRO, NULL); menu_driver_set_texture(); menu->state = 0; return 0; }
/** * rarch_main_iterate: * * Run Libretro core in RetroArch for one frame. * * Returns: 0 on success, 1 if we have to wait until button input in order * to wake up the loop, -1 if we forcibly quit out of the RetroArch iteration loop. **/ int rarch_main_iterate(unsigned *sleep_ms) { int ret; unsigned i; retro_input_t trigger_input; event_cmd_state_t cmd; retro_time_t current, target, to_sleep_ms; static retro_input_t last_input = 0; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); retro_input_t input = input_keys_pressed(driver, settings, global); rarch_system_info_t *system = rarch_system_info_get_ptr(); retro_input_t old_input = last_input; last_input = input; if (driver->flushing_input) { driver->flushing_input = false; if (input) { input = 0; /* If core was paused before entering menu, evoke * pause toggle to wake it up. */ if (main_is_paused) BIT64_SET(input, RARCH_PAUSE_TOGGLE); driver->flushing_input = true; } } trigger_input = input & ~old_input; rarch_main_cmd_get_state(driver, settings, &cmd, input, old_input, trigger_input); if (system->frame_time.callback) { /* Updates frame timing if frame timing callback is in use by the core. * Limits frame time if fast forward ratio throttle is enabled. */ retro_time_t current = retro_get_time_usec(); retro_time_t delta = current - system->frame_time_last; bool is_locked_fps = (main_is_paused || driver->nonblock_state) | !!driver->recording_data; if (!system->frame_time_last || is_locked_fps) delta = system->frame_time.reference; if (!is_locked_fps && main_is_slowmotion) delta /= settings->slowmotion_ratio; system->frame_time_last = current; if (is_locked_fps) system->frame_time_last = 0; system->frame_time.callback(delta); } if (cmd.overlay_next_pressed) event_command(EVENT_CMD_OVERLAY_NEXT); if (!main_is_paused || menu_driver_alive()) { if (cmd.fullscreen_toggle) event_command(EVENT_CMD_FULLSCREEN_TOGGLE); } if (cmd.grab_mouse_pressed) event_command(EVENT_CMD_GRAB_MOUSE_TOGGLE); #ifdef HAVE_MENU if (cmd.menu_pressed || (global->inited.core.type == CORE_TYPE_DUMMY)) { if (menu_driver_alive()) { if (global->inited.main && (global->inited.core.type != CORE_TYPE_DUMMY)) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); } else rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); } #endif #ifdef HAVE_OVERLAY rarch_main_iterate_linefeed_overlay(driver, settings); #endif ret = rarch_main_iterate_time_to_exit(&cmd); if (ret != 1) return -1; #ifdef HAVE_MENU if (menu_driver_alive()) { if (menu_driver_iterate((enum menu_action)menu_input_frame(input, trigger_input)) == -1) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); if (!input && settings->menu.pause_libretro) return 1; goto end; } #endif if (!rarch_main_ctl(RARCH_MAIN_CTL_CHECK_STATE, &cmd)) { /* RetroArch has been paused. */ driver->retro_ctx.poll_cb(); *sleep_ms = 10; return 1; } #if defined(HAVE_THREADS) lock_autosave(); #endif #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_pre_frame((netplay_t*)driver->netplay_data); #endif if (global->bsv.movie) bsv_movie_set_frame_start(global->bsv.movie); if (system->camera_callback.caps) driver_camera_poll(); /* Update binds for analog dpad modes. */ for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_push_analog_dpad(settings->input.binds[i], settings->input.analog_dpad_mode[i]); input_push_analog_dpad(settings->input.autoconf_binds[i], settings->input.analog_dpad_mode[i]); } if ((settings->video.frame_delay > 0) && !driver->nonblock_state) retro_sleep(settings->video.frame_delay); /* Run libretro for one frame. */ core.retro_run(); #ifdef HAVE_CHEEVOS /* Test the achievements. */ cheevos_test(); #endif for (i = 0; i < settings->input.max_users; i++) { if (!settings->input.analog_dpad_mode[i]) continue; input_pop_analog_dpad(settings->input.binds[i]); input_pop_analog_dpad(settings->input.autoconf_binds[i]); } if (global->bsv.movie) bsv_movie_set_frame_end(global->bsv.movie); #ifdef HAVE_NETPLAY if (driver->netplay_data) netplay_post_frame((netplay_t*)driver->netplay_data); #endif #if defined(HAVE_THREADS) unlock_autosave(); #endif #ifdef HAVE_MENU end: #endif if (!settings->fastforward_ratio) return 0; current = retro_get_time_usec(); target = frame_limit_last_time + frame_limit_minimum_time; to_sleep_ms = (target - current) / 1000; if (to_sleep_ms > 0) { *sleep_ms = (unsigned)to_sleep_ms; /* Combat jitter a bit. */ frame_limit_last_time += frame_limit_minimum_time; return 1; } frame_limit_last_time = retro_get_time_usec(); return 0; }
bool rarch_main_ctl(enum rarch_main_ctl_state state, void *data) { driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); switch (state) { case RARCH_MAIN_CTL_CHECK_STATE: { event_cmd_state_t *cmd = (event_cmd_state_t*)data; if (!cmd || main_is_idle) return false; if (cmd->screenshot_pressed) event_command(EVENT_CMD_TAKE_SCREENSHOT); if (cmd->mute_pressed) event_command(EVENT_CMD_AUDIO_MUTE_TOGGLE); if (cmd->osk_pressed) driver->keyboard_linefeed_enable = !driver->keyboard_linefeed_enable; if (cmd->volume_up_pressed) event_command(EVENT_CMD_VOLUME_UP); else if (cmd->volume_down_pressed) event_command(EVENT_CMD_VOLUME_DOWN); #ifdef HAVE_NETPLAY if (driver->netplay_data) { if (cmd->netplay_flip_pressed) event_command(EVENT_CMD_NETPLAY_FLIP_PLAYERS); if (cmd->fullscreen_toggle) event_command(EVENT_CMD_FULLSCREEN_TOGGLE); break; } #endif check_pause(driver, settings, cmd->pause_pressed, cmd->frameadvance_pressed); if (!rarch_main_ctl(RARCH_MAIN_CTL_CHECK_PAUSE_STATE, cmd)) return false; check_fast_forward_button(driver, cmd->fastforward_pressed, cmd->hold_pressed, cmd->old_hold_pressed); check_stateslots(settings, cmd->state_slot_increase, cmd->state_slot_decrease); if (cmd->save_state_pressed) event_command(EVENT_CMD_SAVE_STATE); else if (cmd->load_state_pressed) event_command(EVENT_CMD_LOAD_STATE); check_rewind(settings, global, cmd->rewind_pressed); rarch_main_ctl(RARCH_MAIN_CTL_CHECK_SLOWMOTION, &cmd->slowmotion_pressed); if (cmd->movie_record) rarch_main_ctl(RARCH_MAIN_CTL_CHECK_MOVIE, NULL); check_shader_dir(global, cmd->shader_next_pressed, cmd->shader_prev_pressed); if (cmd->disk_eject_pressed) event_command(EVENT_CMD_DISK_EJECT_TOGGLE); else if (cmd->disk_next_pressed) event_command(EVENT_CMD_DISK_NEXT); else if (cmd->disk_prev_pressed) event_command(EVENT_CMD_DISK_PREV); if (cmd->reset_pressed) event_command(EVENT_CMD_RESET); if (global->cheat) { if (cmd->cheat_index_plus_pressed) cheat_manager_index_next(global->cheat); else if (cmd->cheat_index_minus_pressed) cheat_manager_index_prev(global->cheat); else if (cmd->cheat_toggle_pressed) cheat_manager_toggle(global->cheat); } } break; case RARCH_MAIN_CTL_CHECK_PAUSE_STATE: { bool check_is_oneshot; event_cmd_state_t *cmd = (event_cmd_state_t*)data; if (!cmd) return false; check_is_oneshot = cmd->frameadvance_pressed || cmd->rewind_pressed; if (!main_is_paused) return true; if (cmd->fullscreen_toggle) { event_command(EVENT_CMD_FULLSCREEN_TOGGLE); video_driver_cached_frame(); } if (!check_is_oneshot) return false; } break; case RARCH_MAIN_CTL_CHECK_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; main_is_slowmotion = *ptr; if (!main_is_slowmotion) return false; if (settings->video.black_frame_insertion) video_driver_cached_frame(); if (state_manager_frame_is_reversed()) rarch_main_msg_queue_push_new(MSG_SLOW_MOTION_REWIND, 0, 30, true); else rarch_main_msg_queue_push_new(MSG_SLOW_MOTION, 0, 30, true); } break; case RARCH_MAIN_CTL_CHECK_MOVIE: if (global->bsv.movie_playback) return rarch_main_ctl(RARCH_MAIN_CTL_CHECK_MOVIE_PLAYBACK, NULL); if (!global->bsv.movie) return rarch_main_ctl(RARCH_MAIN_CTL_CHECK_MOVIE_INIT, NULL); return rarch_main_ctl(RARCH_MAIN_CTL_CHECK_MOVIE_RECORD, NULL); case RARCH_MAIN_CTL_CHECK_MOVIE_RECORD: if (!global->bsv.movie) return false; rarch_main_msg_queue_push_new( MSG_MOVIE_RECORD_STOPPED, 2, 180, true); RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_RECORD_STOPPED)); event_command(EVENT_CMD_BSV_MOVIE_DEINIT); break; case RARCH_MAIN_CTL_CHECK_MOVIE_INIT: if (global->bsv.movie) return false; { char path[PATH_MAX_LENGTH], msg[PATH_MAX_LENGTH]; settings->rewind_granularity = 1; if (settings->state_slot > 0) snprintf(path, sizeof(path), "%s%d", global->bsv.movie_path, settings->state_slot); else strlcpy(path, global->bsv.movie_path, sizeof(path)); strlcat(path, ".bsv", sizeof(path)); snprintf(msg, sizeof(msg), "%s \"%s\".", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), path); global->bsv.movie = bsv_movie_init(path, RARCH_MOVIE_RECORD); if (!global->bsv.movie) return false; else if (global->bsv.movie) { rarch_main_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s \"%s\".\n", msg_hash_to_str(MSG_STARTING_MOVIE_RECORD_TO), path); } else { rarch_main_msg_queue_push_new( MSG_FAILED_TO_START_MOVIE_RECORD, 1, 180, true); RARCH_ERR("%s\n", msg_hash_to_str(MSG_FAILED_TO_START_MOVIE_RECORD)); } } break; case RARCH_MAIN_CTL_CHECK_MOVIE_PLAYBACK: if (!global->bsv.movie_end) return false; rarch_main_msg_queue_push_new( MSG_MOVIE_PLAYBACK_ENDED, 1, 180, false); RARCH_LOG("%s\n", msg_hash_to_str(MSG_MOVIE_PLAYBACK_ENDED)); event_command(EVENT_CMD_BSV_MOVIE_DEINIT); global->bsv.movie_end = false; global->bsv.movie_playback = false; break; case RARCH_MAIN_CTL_STATE_FREE: main_is_idle = false; main_is_paused = false; main_is_slowmotion = false; frame_limit_last_time = 0.0; main_max_frames = 0; break; case RARCH_MAIN_CTL_GLOBAL_FREE: event_command(EVENT_CMD_TEMPORARY_CONTENT_DEINIT); event_command(EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT); event_command(EVENT_CMD_RECORD_DEINIT); event_command(EVENT_CMD_LOG_FILE_DEINIT); memset(&g_extern, 0, sizeof(g_extern)); break; case RARCH_MAIN_CTL_CLEAR_STATE: driver_clear_state(); rarch_main_ctl(RARCH_MAIN_CTL_STATE_FREE, NULL); rarch_main_ctl(RARCH_MAIN_CTL_GLOBAL_FREE, NULL); break; case RARCH_MAIN_CTL_SET_MAX_FRAMES: { unsigned *ptr = (unsigned*)data; if (!ptr) return false; main_max_frames = *ptr; } break; case RARCH_MAIN_CTL_SET_FRAME_LIMIT_LAST_TIME: { struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); float fastforward_ratio = settings->fastforward_ratio; if (fastforward_ratio == 0.0f) fastforward_ratio = 1.0f; frame_limit_last_time = retro_get_time_usec(); frame_limit_minimum_time = (retro_time_t)roundf(1000000.0f / (av_info->timing.fps * fastforward_ratio)); } break; case RARCH_MAIN_CTL_IS_IDLE: { bool *ptr = (bool*)data; if (!ptr) return false; *ptr = main_is_idle; } break; case RARCH_MAIN_CTL_SET_IDLE: { bool *ptr = (bool*)data; if (!ptr) return false; main_is_idle = *ptr; } break; case RARCH_MAIN_CTL_IS_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; *ptr = main_is_slowmotion; } break; case RARCH_MAIN_CTL_SET_SLOWMOTION: { bool *ptr = (bool*)data; if (!ptr) return false; main_is_slowmotion = *ptr; } break; case RARCH_MAIN_CTL_SET_PAUSED: { bool *ptr = (bool*)data; if (!ptr) return false; main_is_paused = *ptr; } break; case RARCH_MAIN_CTL_IS_PAUSED: { bool *ptr = (bool*)data; if (!ptr) return false; *ptr = main_is_paused; } break; default: return false; } return true; }
/** * event_command: * @cmd : Event command index. * * Performs program event command with index @cmd. * * Returns: true (1) on success, otherwise false (0). **/ bool event_command(enum event_command cmd) { unsigned i = 0; bool boolean = false; driver_t *driver = driver_get_ptr(); global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); (void)i; switch (cmd) { case EVENT_CMD_LOAD_CONTENT_PERSIST: #ifdef HAVE_DYNAMIC event_command(EVENT_CMD_LOAD_CORE); #endif rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT, NULL); break; #ifdef HAVE_FFMPEG case EVENT_CMD_LOAD_CONTENT_FFMPEG: rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT_FFMPEG, NULL); break; #endif case EVENT_CMD_LOAD_CONTENT_IMAGEVIEWER: rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT_IMAGEVIEWER, NULL); break; case EVENT_CMD_LOAD_CONTENT: #ifdef HAVE_DYNAMIC event_command(EVENT_CMD_LOAD_CONTENT_PERSIST); #else rarch_environment_cb(RETRO_ENVIRONMENT_SET_LIBRETRO_PATH, (void*)settings->libretro); rarch_environment_cb(RETRO_ENVIRONMENT_EXEC, (void*)global->path.fullpath); event_command(EVENT_CMD_QUIT); #endif break; case EVENT_CMD_LOAD_CORE_DEINIT: #ifdef HAVE_DYNAMIC libretro_free_system_info(&global->menu.info); #endif break; case EVENT_CMD_LOAD_CORE_PERSIST: event_command(EVENT_CMD_LOAD_CORE_DEINIT); { #ifdef HAVE_MENU menu_handle_t *menu = menu_driver_get_ptr(); if (menu) event_update_system_info(&global->menu.info, &menu->load_no_content); #endif } break; case EVENT_CMD_LOAD_CORE: event_command(EVENT_CMD_LOAD_CORE_PERSIST); #ifndef HAVE_DYNAMIC event_command(EVENT_CMD_QUIT); #endif break; case EVENT_CMD_LOAD_STATE: /* Immutable - disallow savestate load when * we absolutely cannot change game state. */ if (global->bsv.movie) return false; #ifdef HAVE_NETPLAY if (driver->netplay_data) return false; #endif event_main_state(cmd); break; case EVENT_CMD_RESIZE_WINDOWED_SCALE: if (global->pending.windowed_scale == 0) return false; settings->video.scale = global->pending.windowed_scale; if (!settings->video.fullscreen) event_command(EVENT_CMD_REINIT); global->pending.windowed_scale = 0; break; case EVENT_CMD_MENU_TOGGLE: #ifdef HAVE_MENU if (menu_driver_alive()) rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); else rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING, NULL); #endif break; case EVENT_CMD_CONTROLLERS_INIT: event_init_controllers(); break; case EVENT_CMD_RESET: RARCH_LOG("%s.\n", msg_hash_to_str(MSG_RESET)); rarch_main_msg_queue_push_new(MSG_RESET, 1, 120, true); core.retro_reset(); /* bSNES since v073r01 resets controllers to JOYPAD * after a reset, so just enforce it here. */ event_command(EVENT_CMD_CONTROLLERS_INIT); break; case EVENT_CMD_SAVE_STATE: if (settings->savestate_auto_index) settings->state_slot++; event_main_state(cmd); break; case EVENT_CMD_SAVE_STATE_DECREMENT: /* Slot -1 is (auto) slot. */ if (settings->state_slot >= 0) settings->state_slot--; break; case EVENT_CMD_SAVE_STATE_INCREMENT: settings->state_slot++; break; case EVENT_CMD_TAKE_SCREENSHOT: if (!take_screenshot()) return false; break; case EVENT_CMD_PREPARE_DUMMY: { #ifdef HAVE_MENU menu_handle_t *menu = menu_driver_get_ptr(); if (menu) menu->load_no_content = false; #endif rarch_main_data_deinit(); *global->path.fullpath = '\0'; rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT, NULL); } break; case EVENT_CMD_UNLOAD_CORE: event_command(EVENT_CMD_PREPARE_DUMMY); event_command(EVENT_CMD_LOAD_CORE_DEINIT); break; case EVENT_CMD_QUIT: rarch_ctl(RARCH_ACTION_STATE_QUIT, NULL); break; case EVENT_CMD_REINIT: { const struct retro_hw_render_callback *hw_render = (const struct retro_hw_render_callback*)video_driver_callback(); const input_driver_t *input = driver ? (const input_driver_t*)driver->input : NULL; driver->video_cache_context = hw_render->cache_context; driver->video_cache_context_ack = false; event_command(EVENT_CMD_RESET_CONTEXT); driver->video_cache_context = false; /* Poll input to avoid possibly stale data to corrupt things. */ input->poll(driver->input_data); #ifdef HAVE_MENU menu_display_ctl(MENU_DISPLAY_CTL_SET_FRAMEBUFFER_DIRTY_FLAG, NULL); if (menu_driver_alive()) event_command(EVENT_CMD_VIDEO_SET_BLOCKING_STATE); #endif } break; case EVENT_CMD_CHEATS_DEINIT: if (!global) break; if (global->cheat) cheat_manager_free(global->cheat); global->cheat = NULL; break; case EVENT_CMD_CHEATS_INIT: event_command(EVENT_CMD_CHEATS_DEINIT); event_init_cheats(); break; case EVENT_CMD_CHEATS_APPLY: if (!global->cheat) break; cheat_manager_apply_cheats(global->cheat); break; case EVENT_CMD_REMAPPING_DEINIT: break; case EVENT_CMD_REMAPPING_INIT: event_command(EVENT_CMD_REMAPPING_DEINIT); event_init_remapping(); break; case EVENT_CMD_REWIND_DEINIT: if (!global) break; #ifdef HAVE_NETPLAY if (driver->netplay_data) return false; #endif if (global->rewind.state) state_manager_free(global->rewind.state); global->rewind.state = NULL; break; case EVENT_CMD_REWIND_INIT: if (!driver->netplay_data) init_rewind(); break; case EVENT_CMD_REWIND_TOGGLE: if (settings->rewind_enable) event_command(EVENT_CMD_REWIND_INIT); else event_command(EVENT_CMD_REWIND_DEINIT); break; case EVENT_CMD_AUTOSAVE_DEINIT: #ifdef HAVE_THREADS event_deinit_autosave(); #endif break; case EVENT_CMD_AUTOSAVE_INIT: event_command(EVENT_CMD_AUTOSAVE_DEINIT); #ifdef HAVE_THREADS event_init_autosave(); #endif break; case EVENT_CMD_AUTOSAVE_STATE: event_save_auto_state(); break; case EVENT_CMD_AUDIO_STOP: if (!driver->audio_data) return false; if (!audio_driver_alive()) return false; if (!audio_driver_stop()) return false; break; case EVENT_CMD_AUDIO_START: if (!driver->audio_data || audio_driver_alive()) return false; if (!settings->audio.mute_enable && !audio_driver_start()) { RARCH_ERR("Failed to start audio driver. Will continue without audio.\n"); driver->audio_active = false; } break; case EVENT_CMD_AUDIO_MUTE_TOGGLE: { const char *msg = !settings->audio.mute_enable ? msg_hash_to_str(MSG_AUDIO_MUTED): msg_hash_to_str(MSG_AUDIO_UNMUTED); if (!audio_driver_mute_toggle()) { RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_UNMUTE_AUDIO)); return false; } rarch_main_msg_queue_push(msg, 1, 180, true); RARCH_LOG("%s\n", msg); } break; case EVENT_CMD_OVERLAY_DEINIT: #ifdef HAVE_OVERLAY input_overlay_free_ptr(); #endif break; case EVENT_CMD_OVERLAY_INIT: event_command(EVENT_CMD_OVERLAY_DEINIT); #ifdef HAVE_OVERLAY if (input_overlay_new_ptr() == -1) RARCH_ERR("%s.\n", msg_hash_to_str(MSG_FAILED_TO_LOAD_OVERLAY)); #endif break; case EVENT_CMD_OVERLAY_NEXT: #ifdef HAVE_OVERLAY input_overlay_next(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DSP_FILTER_DEINIT: if (!global) break; audio_driver_dsp_filter_free(); break; case EVENT_CMD_DSP_FILTER_INIT: event_command(EVENT_CMD_DSP_FILTER_DEINIT); if (!*settings->audio.dsp_plugin) break; audio_driver_dsp_filter_init(settings->audio.dsp_plugin); break; case EVENT_CMD_GPU_RECORD_DEINIT: if (!global) break; if (global->record.gpu_buffer) free(global->record.gpu_buffer); global->record.gpu_buffer = NULL; break; case EVENT_CMD_RECORD_DEINIT: if (!recording_deinit()) return false; break; case EVENT_CMD_RECORD_INIT: event_command(EVENT_CMD_HISTORY_DEINIT); if (!recording_init()) return false; break; case EVENT_CMD_HISTORY_DEINIT: if (g_defaults.history) { content_playlist_write_file(g_defaults.history); content_playlist_free(g_defaults.history); } g_defaults.history = NULL; break; case EVENT_CMD_HISTORY_INIT: event_command(EVENT_CMD_HISTORY_DEINIT); if (!settings->history_list_enable) return false; RARCH_LOG("%s: [%s].\n", msg_hash_to_str(MSG_LOADING_HISTORY_FILE), settings->content_history_path); g_defaults.history = content_playlist_init( settings->content_history_path, settings->content_history_size); break; case EVENT_CMD_CORE_INFO_DEINIT: if (!global) break; if (global->core_info.list) core_info_list_free(global->core_info.list); global->core_info.list = NULL; break; case EVENT_CMD_DATA_RUNLOOP_FREE: rarch_main_data_free(); break; case EVENT_CMD_CORE_INFO_INIT: event_command(EVENT_CMD_CORE_INFO_DEINIT); if (*settings->libretro_directory) global->core_info.list = core_info_list_new(); break; case EVENT_CMD_CORE_DEINIT: { struct retro_hw_render_callback *cb = video_driver_callback(); event_deinit_core(true); if (cb) memset(cb, 0, sizeof(*cb)); break; } case EVENT_CMD_CORE_INIT: if (!event_init_core()) return false; break; case EVENT_CMD_VIDEO_APPLY_STATE_CHANGES: video_driver_apply_state_changes(); break; case EVENT_CMD_VIDEO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_VIDEO_SET_BLOCKING_STATE: video_driver_set_nonblock_state(boolean); break; case EVENT_CMD_VIDEO_SET_ASPECT_RATIO: video_driver_set_aspect_ratio(settings->video.aspect_ratio_idx); break; case EVENT_CMD_AUDIO_SET_NONBLOCKING_STATE: boolean = true; /* fall-through */ case EVENT_CMD_AUDIO_SET_BLOCKING_STATE: audio_driver_set_nonblock_state(boolean); break; case EVENT_CMD_OVERLAY_SET_SCALE_FACTOR: #ifdef HAVE_OVERLAY input_overlay_set_scale_factor(settings->input.overlay_scale); #endif break; case EVENT_CMD_OVERLAY_SET_ALPHA_MOD: #ifdef HAVE_OVERLAY input_overlay_set_alpha_mod(settings->input.overlay_opacity); #endif break; case EVENT_CMD_DRIVERS_DEINIT: uninit_drivers(DRIVERS_CMD_ALL); break; case EVENT_CMD_DRIVERS_INIT: init_drivers(DRIVERS_CMD_ALL); break; case EVENT_CMD_AUDIO_REINIT: uninit_drivers(DRIVER_AUDIO); init_drivers(DRIVER_AUDIO); break; case EVENT_CMD_RESET_CONTEXT: event_command(EVENT_CMD_DRIVERS_DEINIT); event_command(EVENT_CMD_DRIVERS_INIT); break; case EVENT_CMD_QUIT_RETROARCH: rarch_ctl(RARCH_ACTION_STATE_FORCE_QUIT, NULL); break; case EVENT_CMD_RESUME: rarch_ctl(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED, NULL); break; case EVENT_CMD_RESTART_RETROARCH: #if defined(GEKKO) && defined(HW_RVL) fill_pathname_join(global->path.fullpath, g_defaults.dir.core, SALAMANDER_FILE, sizeof(global->path.fullpath)); #endif if (driver->frontend_ctx && driver->frontend_ctx->set_fork) driver->frontend_ctx->set_fork(true, false); break; case EVENT_CMD_MENU_SAVE_CONFIG: if (!event_save_core_config()) return false; break; case EVENT_CMD_SHADERS_APPLY_CHANGES: #ifdef HAVE_MENU menu_shader_manager_apply_changes(); #endif break; case EVENT_CMD_PAUSE_CHECKS: rarch_main_ctl(RARCH_MAIN_CTL_IS_PAUSED, &boolean); if (boolean) { RARCH_LOG("%s\n", msg_hash_to_str(MSG_PAUSED)); event_command(EVENT_CMD_AUDIO_STOP); if (settings->video.black_frame_insertion) video_driver_cached_frame(); } else { RARCH_LOG("%s\n", msg_hash_to_str(MSG_UNPAUSED)); event_command(EVENT_CMD_AUDIO_START); } break; case EVENT_CMD_PAUSE_TOGGLE: rarch_main_ctl(RARCH_MAIN_CTL_IS_PAUSED, &boolean); boolean = !boolean; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_UNPAUSE: boolean = false; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_PAUSE: boolean = true; rarch_main_ctl(RARCH_MAIN_CTL_SET_PAUSED, &boolean); event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_MENU_PAUSE_LIBRETRO: #ifdef HAVE_MENU if (menu_driver_alive()) { if (settings->menu.pause_libretro) event_command(EVENT_CMD_AUDIO_STOP); else event_command(EVENT_CMD_AUDIO_START); } else { if (settings->menu.pause_libretro) event_command(EVENT_CMD_AUDIO_START); } #endif break; case EVENT_CMD_SHADER_DIR_DEINIT: if (!global) break; dir_list_free(global->shader_dir.list); global->shader_dir.list = NULL; global->shader_dir.ptr = 0; break; case EVENT_CMD_SHADER_DIR_INIT: event_command(EVENT_CMD_SHADER_DIR_DEINIT); if (!*settings->video.shader_dir) return false; global->shader_dir.list = dir_list_new_special(NULL, DIR_LIST_SHADERS); if (!global->shader_dir.list || global->shader_dir.list->size == 0) { event_command(EVENT_CMD_SHADER_DIR_DEINIT); return false; } global->shader_dir.ptr = 0; dir_list_sort(global->shader_dir.list, false); for (i = 0; i < global->shader_dir.list->size; i++) RARCH_LOG("%s \"%s\"\n", msg_hash_to_str(MSG_FOUND_SHADER), global->shader_dir.list->elems[i].data); break; case EVENT_CMD_SAVEFILES: event_save_files(); break; case EVENT_CMD_SAVEFILES_DEINIT: if (!global) break; if (global->savefiles) string_list_free(global->savefiles); global->savefiles = NULL; break; case EVENT_CMD_SAVEFILES_INIT: global->sram.use = global->sram.use && !global->sram.save_disable #ifdef HAVE_NETPLAY && (!driver->netplay_data || !global->netplay.is_client) #endif ; if (!global->sram.use) RARCH_LOG("%s\n", msg_hash_to_str(MSG_SRAM_WILL_NOT_BE_SAVED)); if (global->sram.use) event_command(EVENT_CMD_AUTOSAVE_INIT); break; case EVENT_CMD_MSG_QUEUE_DEINIT: rarch_main_msg_queue_free(); break; case EVENT_CMD_MSG_QUEUE_INIT: event_command(EVENT_CMD_MSG_QUEUE_DEINIT); rarch_main_msg_queue_init(); rarch_main_data_init_queues(); break; case EVENT_CMD_BSV_MOVIE_DEINIT: if (!global) break; if (global->bsv.movie) bsv_movie_free(global->bsv.movie); global->bsv.movie = NULL; break; case EVENT_CMD_BSV_MOVIE_INIT: event_command(EVENT_CMD_BSV_MOVIE_DEINIT); event_init_movie(); break; case EVENT_CMD_NETPLAY_DEINIT: #ifdef HAVE_NETPLAY deinit_netplay(); #endif break; case EVENT_CMD_NETWORK_DEINIT: #ifdef HAVE_NETWORKING network_deinit(); #endif break; case EVENT_CMD_NETWORK_INIT: #ifdef HAVE_NETWORKING network_init(); #endif break; case EVENT_CMD_NETPLAY_INIT: event_command(EVENT_CMD_NETPLAY_DEINIT); #ifdef HAVE_NETPLAY if (!init_netplay()) return false; #endif break; case EVENT_CMD_NETPLAY_FLIP_PLAYERS: #ifdef HAVE_NETPLAY { netplay_t *netplay = (netplay_t*)driver->netplay_data; if (!netplay) return false; netplay_flip_users(netplay); } #endif break; case EVENT_CMD_FULLSCREEN_TOGGLE: if (!video_driver_has_windowed()) return false; /* If we go fullscreen we drop all drivers and * reinitialize to be safe. */ settings->video.fullscreen = !settings->video.fullscreen; event_command(EVENT_CMD_REINIT); break; case EVENT_CMD_COMMAND_DEINIT: #ifdef HAVE_COMMAND if (driver->command) rarch_cmd_free(driver->command); driver->command = NULL; #endif break; case EVENT_CMD_COMMAND_INIT: event_command(EVENT_CMD_COMMAND_DEINIT); #ifdef HAVE_COMMAND event_init_command(); #endif break; case EVENT_CMD_TEMPORARY_CONTENT_DEINIT: if (!global) break; if (global->temporary_content) event_free_temporary_content(); global->temporary_content = NULL; break; case EVENT_CMD_SUBSYSTEM_FULLPATHS_DEINIT: if (!global) break; if (global->subsystem_fullpaths) string_list_free(global->subsystem_fullpaths); global->subsystem_fullpaths = NULL; break; case EVENT_CMD_LOG_FILE_DEINIT: if (!global) break; if (global->log_file && global->log_file != stderr) fclose(global->log_file); global->log_file = NULL; break; case EVENT_CMD_DISK_EJECT_TOGGLE: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (control) event_check_disk_eject(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_DISK_NEXT: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_next(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_DISK_PREV: if (system && system->disk_control.get_num_images) { const struct retro_disk_control_callback *control = (const struct retro_disk_control_callback*) &system->disk_control; if (!control) return false; if (!control->get_eject_state()) return false; event_check_disk_prev(control); } else rarch_main_msg_queue_push_new( MSG_CORE_DOES_NOT_SUPPORT_DISK_OPTIONS, 1, 120, true); break; case EVENT_CMD_RUMBLE_STOP: for (i = 0; i < MAX_USERS; i++) { input_driver_set_rumble_state(i, RETRO_RUMBLE_STRONG, 0); input_driver_set_rumble_state(i, RETRO_RUMBLE_WEAK, 0); } break; case EVENT_CMD_GRAB_MOUSE_TOGGLE: { static bool grab_mouse_state = false; grab_mouse_state = !grab_mouse_state; if (!driver->input || !input_driver_grab_mouse(grab_mouse_state)) return false; RARCH_LOG("%s: %s.\n", msg_hash_to_str(MSG_GRAB_MOUSE_STATE), grab_mouse_state ? "yes" : "no"); video_driver_show_mouse(!grab_mouse_state); } break; case EVENT_CMD_PERFCNT_REPORT_FRONTEND_LOG: rarch_perf_log(); break; case EVENT_CMD_VOLUME_UP: event_set_volume(0.5f); break; case EVENT_CMD_VOLUME_DOWN: event_set_volume(-0.5f); break; case EVENT_CMD_SET_FRAME_LIMIT: rarch_main_ctl(RARCH_MAIN_CTL_SET_FRAME_LIMIT_LAST_TIME, NULL); break; case EVENT_CMD_NONE: default: return false; } return true; }
/** * parse_input: * @argc : Count of (commandline) arguments. * @argv : (Commandline) arguments. * * Parses (commandline) arguments passed to program. * **/ static void parse_input(int argc, char *argv[]) { const char *optstring = NULL; global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); const struct option opts[] = { #ifdef HAVE_DYNAMIC { "libretro", 1, NULL, 'L' }, #endif { "menu", 0, NULL, RA_OPT_MENU }, { "help", 0, NULL, 'h' }, { "save", 1, NULL, 's' }, { "fullscreen", 0, NULL, 'f' }, { "record", 1, NULL, 'r' }, { "recordconfig", 1, NULL, RA_OPT_RECORDCONFIG }, { "size", 1, NULL, RA_OPT_SIZE }, { "verbose", 0, NULL, 'v' }, { "config", 1, NULL, 'c' }, { "appendconfig", 1, NULL, RA_OPT_APPENDCONFIG }, { "nodevice", 1, NULL, 'N' }, { "dualanalog", 1, NULL, 'A' }, { "device", 1, NULL, 'd' }, { "savestate", 1, NULL, 'S' }, { "bsvplay", 1, NULL, 'P' }, { "bsvrecord", 1, NULL, 'R' }, { "sram-mode", 1, NULL, 'M' }, #ifdef HAVE_NETPLAY { "host", 0, NULL, 'H' }, { "connect", 1, NULL, 'C' }, { "frames", 1, NULL, 'F' }, { "port", 1, NULL, RA_OPT_PORT }, { "spectate", 0, NULL, RA_OPT_SPECTATE }, #endif { "nick", 1, NULL, RA_OPT_NICK }, #if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY) { "command", 1, NULL, RA_OPT_COMMAND }, #endif { "ups", 1, NULL, 'U' }, { "bps", 1, NULL, RA_OPT_BPS }, { "ips", 1, NULL, RA_OPT_IPS }, { "no-patch", 0, NULL, RA_OPT_NO_PATCH }, { "detach", 0, NULL, 'D' }, { "features", 0, NULL, RA_OPT_FEATURES }, { "subsystem", 1, NULL, RA_OPT_SUBSYSTEM }, { "max-frames", 1, NULL, RA_OPT_MAX_FRAMES }, { "eof-exit", 0, NULL, RA_OPT_EOF_EXIT }, { "version", 0, NULL, RA_OPT_VERSION }, #ifdef HAVE_FILE_LOGGER { "log-file", 1, NULL, RA_OPT_LOG_FILE }, #endif { NULL, 0, NULL, 0 } }; global->inited.core.no_content = false; global->inited.core.type = CORE_TYPE_PLAIN; *global->subsystem = '\0'; global->has_set.save_path = false; global->has_set.state_path = false; global->has_set.libretro = false; global->has_set.libretro_directory = false; global->has_set.verbosity = false; global->has_set.netplay_mode = false; global->has_set.username = false; global->has_set.netplay_ip_address = false; global->has_set.netplay_delay_frames = false; global->has_set.netplay_ip_port = false; global->has_set.ups_pref = false; global->has_set.bps_pref = false; global->has_set.ips_pref = false; global->patch.ups_pref = false; global->patch.bps_pref = false; global->patch.ips_pref = false; *global->name.ups = '\0'; *global->name.bps = '\0'; *global->name.ips = '\0'; global->overrides_active = false; if (argc < 2) { global->inited.core.type = CORE_TYPE_DUMMY; return; } /* Make sure we can call parse_input several times ... */ optind = 0; optstring = "hs:fvS:A:c:U:DN:d:" BSV_MOVIE_ARG NETPLAY_ARG DYNAMIC_ARG FFMPEG_RECORD_ARG; for (;;) { int port; int c = getopt_long(argc, argv, optstring, opts, NULL); if (c == -1) break; switch (c) { case 'h': print_help(argv[0]); exit(0); case 'd': { unsigned id = 0; struct string_list *list = string_split(optarg, ":"); port = 0; if (list && list->size == 2) { port = strtol(list->elems[0].data, NULL, 0); id = strtoul(list->elems[1].data, NULL, 0); } string_list_free(list); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Connect device to a valid port.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = id; global->has_set.libretro_device[port - 1] = true; break; } case 'A': port = strtol(optarg, NULL, 0); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Connect dualanalog to a valid port.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = RETRO_DEVICE_ANALOG; global->has_set.libretro_device[port - 1] = true; break; case 's': strlcpy(global->name.savefile, optarg, sizeof(global->name.savefile)); global->has_set.save_path = true; break; case 'f': global->force_fullscreen = true; break; case 'S': strlcpy(global->name.savestate, optarg, sizeof(global->name.savestate)); global->has_set.state_path = true; break; case 'v': global->verbosity = true; global->has_set.verbosity = true; break; case 'N': port = strtol(optarg, NULL, 0); if (port < 1 || port > MAX_USERS) { RARCH_ERR("Disconnect device from a valid port.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } settings->input.libretro_device[port - 1] = RETRO_DEVICE_NONE; global->has_set.libretro_device[port - 1] = true; break; case 'c': strlcpy(global->path.config, optarg, sizeof(global->path.config)); break; case 'r': strlcpy(global->record.path, optarg, sizeof(global->record.path)); global->record.enable = true; break; #ifdef HAVE_DYNAMIC case 'L': if (path_is_directory(optarg)) { *settings->libretro = '\0'; strlcpy(settings->libretro_directory, optarg, sizeof(settings->libretro_directory)); global->has_set.libretro = true; global->has_set.libretro_directory = true; RARCH_WARN("Using old --libretro behavior. Setting libretro_directory to \"%s\" instead.\n", optarg); } else { strlcpy(settings->libretro, optarg, sizeof(settings->libretro)); global->has_set.libretro = true; } break; #endif case 'P': case 'R': strlcpy(global->bsv.movie_start_path, optarg, sizeof(global->bsv.movie_start_path)); global->bsv.movie_start_playback = (c == 'P'); global->bsv.movie_start_recording = (c == 'R'); break; case 'M': if (!strcmp(optarg, "noload-nosave")) { global->sram.load_disable = true; global->sram.save_disable = true; } else if (!strcmp(optarg, "noload-save")) global->sram.load_disable = true; else if (!strcmp(optarg, "load-nosave")) global->sram.save_disable = true; else if (strcmp(optarg, "load-save") != 0) { RARCH_ERR("Invalid argument in --sram-mode.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } break; #ifdef HAVE_NETPLAY case 'H': global->has_set.netplay_ip_address = true; global->netplay.enable = true; *global->netplay.server = '\0'; break; case 'C': global->has_set.netplay_ip_address = true; global->netplay.enable = true; strlcpy(global->netplay.server, optarg, sizeof(global->netplay.server)); break; case 'F': global->netplay.sync_frames = strtol(optarg, NULL, 0); global->has_set.netplay_delay_frames = true; break; #endif case RA_OPT_BPS: strlcpy(global->name.bps, optarg, sizeof(global->name.bps)); global->patch.bps_pref = true; global->has_set.bps_pref = true; break; case 'U': strlcpy(global->name.ups, optarg, sizeof(global->name.ups)); global->patch.ups_pref = true; global->has_set.ups_pref = true; break; case RA_OPT_IPS: strlcpy(global->name.ips, optarg, sizeof(global->name.ips)); global->patch.ips_pref = true; global->has_set.ips_pref = true; break; case RA_OPT_NO_PATCH: global->patch.block_patch = true; break; case 'D': #if defined(_WIN32) && !defined(_XBOX) FreeConsole(); #endif break; case RA_OPT_MENU: global->inited.core.type = CORE_TYPE_DUMMY; break; #ifdef HAVE_NETPLAY case RA_OPT_PORT: global->has_set.netplay_ip_port = true; global->netplay.port = strtoul(optarg, NULL, 0); break; case RA_OPT_SPECTATE: global->has_set.netplay_mode = true; global->netplay.is_spectate = true; break; #endif case RA_OPT_NICK: global->has_set.username = true; strlcpy(settings->username, optarg, sizeof(settings->username)); break; #if defined(HAVE_NETWORK_CMD) && defined(HAVE_NETPLAY) case RA_OPT_COMMAND: if (network_cmd_send(optarg)) exit(0); else rarch_fail(1, "network_cmd_send()"); break; #endif case RA_OPT_APPENDCONFIG: strlcpy(global->path.append_config, optarg, sizeof(global->path.append_config)); break; case RA_OPT_SIZE: { if (sscanf(optarg, "%ux%u", &global->record.width, &global->record.height) != 2) { RARCH_ERR("Wrong format for --size.\n"); print_help(argv[0]); rarch_fail(1, "parse_input()"); } break; } case RA_OPT_RECORDCONFIG: strlcpy(global->record.config, optarg, sizeof(global->record.config)); break; case RA_OPT_MAX_FRAMES: { unsigned max_frames = strtoul(optarg, NULL, 10); rarch_main_ctl(RARCH_MAIN_CTL_SET_MAX_FRAMES, &max_frames); } break; case RA_OPT_SUBSYSTEM: strlcpy(global->subsystem, optarg, sizeof(global->subsystem)); break; case RA_OPT_FEATURES: print_features(); exit(0); case RA_OPT_EOF_EXIT: global->bsv.eof_exit = true; break; case RA_OPT_VERSION: print_version(); exit(0); #ifdef HAVE_FILE_LOGGER case RA_OPT_LOG_FILE: global->log_file = fopen(optarg, "wb"); break; #endif case '?': print_help(argv[0]); rarch_fail(1, "parse_input()"); default: RARCH_ERR("Error parsing arguments.\n"); rarch_fail(1, "parse_input()"); } } if (global->inited.core.type == CORE_TYPE_DUMMY) { if (optind < argc) { RARCH_ERR("--menu was used, but content file was passed as well.\n"); rarch_fail(1, "parse_input()"); } } else if (!*global->subsystem && optind < argc) rarch_set_paths(argv[optind]); else if (*global->subsystem && optind < argc) set_special_paths(argv + optind, argc - optind); else global->inited.core.no_content = true; /* Copy SRM/state dirs used, so they can be reused on reentrancy. */ if (global->has_set.save_path && path_is_directory(global->name.savefile)) strlcpy(global->dir.savefile, global->name.savefile, sizeof(global->dir.savefile)); if (global->has_set.state_path && path_is_directory(global->name.savestate)) strlcpy(global->dir.savestate, global->name.savestate, sizeof(global->dir.savestate)); }
/** * rarch_environment_cb: * @cmd : Identifier of command. * @data : Pointer to data. * * Environment callback function implementation. * * Returns: true (1) if environment callback command could * be performed, otherwise false (0). **/ bool rarch_environment_cb(unsigned cmd, void *data) { unsigned p; driver_t *driver = driver_get_ptr(); settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); if (ignore_environment_cb) return false; switch (cmd) { case RETRO_ENVIRONMENT_GET_OVERSCAN: *(bool*)data = !settings->video.crop_overscan; RARCH_LOG("Environ GET_OVERSCAN: %u\n", (unsigned)!settings->video.crop_overscan); break; case RETRO_ENVIRONMENT_GET_CAN_DUPE: *(bool*)data = true; RARCH_LOG("Environ GET_CAN_DUPE: true\n"); break; case RETRO_ENVIRONMENT_GET_VARIABLE: { struct retro_variable *var = (struct retro_variable*)data; RARCH_LOG("Environ GET_VARIABLE %s:\n", var->key); if (system && system->core_options) core_option_get(system->core_options, var); else var->value = NULL; RARCH_LOG("\t%s\n", var->value ? var->value : "N/A"); break; } case RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE: *(bool*)data = system->core_options ? core_option_updated(system->core_options) : false; break; case RETRO_ENVIRONMENT_SET_VARIABLES: { RARCH_LOG("Environ SET_VARIABLES.\n"); if (system && system->core_options) { core_option_flush(system->core_options); core_option_free(system->core_options); } { char *game_options_path = NULL; bool ret = false; const struct retro_variable *vars = (const struct retro_variable*)data; char buf[PATH_MAX_LENGTH] = {0}; const char *options_path = settings->core_options_path; if (!*options_path && *global->path.config) { fill_pathname_resolve_relative(buf, global->path.config, "retroarch-core-options.cfg", sizeof(buf)); options_path = buf; } if (settings->game_specific_options) ret = rarch_game_specific_options(&game_options_path); if(ret) { system->core_options = core_option_new(game_options_path, vars); free(game_options_path); } else system->core_options = core_option_new(options_path, vars); } break; } case RETRO_ENVIRONMENT_SET_MESSAGE: { const struct retro_message *msg = (const struct retro_message*)data; RARCH_LOG("Environ SET_MESSAGE: %s\n", msg->msg); rarch_main_msg_queue_push(msg->msg, 1, msg->frames, true); break; } case RETRO_ENVIRONMENT_SET_ROTATION: { unsigned rotation = *(const unsigned*)data; RARCH_LOG("Environ SET_ROTATION: %u\n", rotation); if (!settings->video.allow_rotate) break; system->rotation = rotation; if (!video_driver_set_rotation(rotation)) return false; break; } case RETRO_ENVIRONMENT_SHUTDOWN: RARCH_LOG("Environ SHUTDOWN.\n"); system->shutdown = true; global->core_shutdown_initiated = true; break; case RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL: system->performance_level = *(const unsigned*)data; RARCH_LOG("Environ PERFORMANCE_LEVEL: %u.\n", system->performance_level); break; case RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY: if (settings->system_directory[0] == '\0') { char *fullpath = NULL; rarch_main_ctl(RARCH_MAIN_CTL_GET_CONTENT_PATH, &fullpath); RARCH_WARN("SYSTEM DIR is empty, assume CONTENT DIR %s\n", fullpath); fill_pathname_basedir(global->dir.systemdir, fullpath, sizeof(global->dir.systemdir)); *(const char**)data = global->dir.systemdir; RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", global->dir.systemdir); } else { *(const char**)data = settings->system_directory; RARCH_LOG("Environ SYSTEM_DIRECTORY: \"%s\".\n", settings->system_directory); } break; case RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY: *(const char**)data = *current_savefile_dir ? current_savefile_dir : NULL; RARCH_LOG("Environ SAVE_DIRECTORY: \"%s\".\n", current_savefile_dir); break; case RETRO_ENVIRONMENT_GET_USERNAME: *(const char**)data = *settings->username ? settings->username : NULL; RARCH_LOG("Environ GET_USERNAME: \"%s\".\n", settings->username); break; case RETRO_ENVIRONMENT_GET_LANGUAGE: *(unsigned *)data = settings->user_language; RARCH_LOG("Environ GET_LANGUAGE: \"%u\".\n", settings->user_language); break; case RETRO_ENVIRONMENT_SET_PIXEL_FORMAT: { enum retro_pixel_format pix_fmt = *(const enum retro_pixel_format*)data; switch (pix_fmt) { case RETRO_PIXEL_FORMAT_0RGB1555: RARCH_LOG("Environ SET_PIXEL_FORMAT: 0RGB1555.\n"); break; case RETRO_PIXEL_FORMAT_RGB565: RARCH_LOG("Environ SET_PIXEL_FORMAT: RGB565.\n"); break; case RETRO_PIXEL_FORMAT_XRGB8888: RARCH_LOG("Environ SET_PIXEL_FORMAT: XRGB8888.\n"); break; default: return false; } video_driver_set_pixel_format(pix_fmt); break; } case RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS: { unsigned retro_id, retro_port; const struct retro_input_descriptor *desc = NULL; static const char *libretro_btn_desc[] = { "B (bottom)", "Y (left)", "Select", "Start", "D-Pad Up", "D-Pad Down", "D-Pad Left", "D-Pad Right", "A (right)", "X (up)", "L", "R", "L2", "R2", "L3", "R3", }; memset(system->input_desc_btn, 0, sizeof(system->input_desc_btn)); desc = (const struct retro_input_descriptor*)data; for (; desc->description; desc++) { retro_port = desc->port; retro_id = desc->id; if (desc->port >= MAX_USERS) continue; /* Ignore all others for now. */ if (desc->device != RETRO_DEVICE_JOYPAD && desc->device != RETRO_DEVICE_ANALOG) continue; if (desc->id >= RARCH_FIRST_CUSTOM_BIND) continue; if (desc->device == RETRO_DEVICE_ANALOG) { switch (retro_id) { case RETRO_DEVICE_ID_ANALOG_X: switch (desc->index) { case RETRO_DEVICE_INDEX_ANALOG_LEFT: system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_X_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_X_MINUS] = desc->description; break; case RETRO_DEVICE_INDEX_ANALOG_RIGHT: system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_X_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_X_MINUS] = desc->description; break; } break; case RETRO_DEVICE_ID_ANALOG_Y: switch (desc->index) { case RETRO_DEVICE_INDEX_ANALOG_LEFT: system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_Y_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_LEFT_Y_MINUS] = desc->description; break; case RETRO_DEVICE_INDEX_ANALOG_RIGHT: system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_Y_PLUS] = desc->description; system->input_desc_btn[retro_port][RARCH_ANALOG_RIGHT_Y_MINUS] = desc->description; break; } break; } } else system->input_desc_btn[retro_port][retro_id] = desc->description; } RARCH_LOG("Environ SET_INPUT_DESCRIPTORS:\n"); for (p = 0; p < settings->input.max_users; p++) { for (retro_id = 0; retro_id < RARCH_FIRST_CUSTOM_BIND; retro_id++) { const char *description = system->input_desc_btn[p][retro_id]; if (!description) continue; RARCH_LOG("\tRetroPad, User %u, Button \"%s\" => \"%s\"\n", p + 1, libretro_btn_desc[retro_id], description); } } global->has_set.input_descriptors = true; break; } case RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK: { const struct retro_keyboard_callback *info = (const struct retro_keyboard_callback*)data; RARCH_LOG("Environ SET_KEYBOARD_CALLBACK.\n"); system->key_event = info->callback; global->frontend_key_event = system->key_event; break; } case RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE: RARCH_LOG("Environ SET_DISK_CONTROL_INTERFACE.\n"); system->disk_control = *(const struct retro_disk_control_callback*)data; break; case RETRO_ENVIRONMENT_SET_HW_RENDER: case RETRO_ENVIRONMENT_SET_HW_RENDER | RETRO_ENVIRONMENT_EXPERIMENTAL: { struct retro_hw_render_callback *hw_render = video_driver_callback(); struct retro_hw_render_callback *cb = (struct retro_hw_render_callback*)data; RARCH_LOG("Environ SET_HW_RENDER.\n"); switch (cb->context_type) { case RETRO_HW_CONTEXT_NONE: RARCH_LOG("Requesting no HW context.\n"); break; #if defined(HAVE_OPENGLES2) case RETRO_HW_CONTEXT_OPENGLES2: #if defined(HAVE_OPENGLES3) case RETRO_HW_CONTEXT_OPENGLES3: #endif RARCH_LOG("Requesting OpenGLES%u context.\n", cb->context_type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); break; #if defined(HAVE_OPENGLES3) case RETRO_HW_CONTEXT_OPENGLES_VERSION: RARCH_LOG("Requesting OpenGLES%u.%u context.\n", cb->version_major, cb->version_minor); break; #endif case RETRO_HW_CONTEXT_OPENGL: case RETRO_HW_CONTEXT_OPENGL_CORE: RARCH_ERR("Requesting OpenGL context, but RetroArch is compiled against OpenGLES2. Cannot use HW context.\n"); return false; #elif defined(HAVE_OPENGL) case RETRO_HW_CONTEXT_OPENGLES2: case RETRO_HW_CONTEXT_OPENGLES3: RARCH_ERR("Requesting OpenGLES%u context, but RetroArch is compiled against OpenGL. Cannot use HW context.\n", cb->context_type == RETRO_HW_CONTEXT_OPENGLES2 ? 2 : 3); return false; case RETRO_HW_CONTEXT_OPENGLES_VERSION: RARCH_ERR("Requesting OpenGLES%u.%u context, but RetroArch is compiled against OpenGL. Cannot use HW context.\n", cb->version_major, cb->version_minor); return false; case RETRO_HW_CONTEXT_OPENGL: RARCH_LOG("Requesting OpenGL context.\n"); break; case RETRO_HW_CONTEXT_OPENGL_CORE: RARCH_LOG("Requesting core OpenGL context (%u.%u).\n", cb->version_major, cb->version_minor); break; #endif default: RARCH_LOG("Requesting unknown context.\n"); return false; } cb->get_current_framebuffer = video_driver_get_current_framebuffer; cb->get_proc_address = video_driver_get_proc_address; if (cmd & RETRO_ENVIRONMENT_EXPERIMENTAL) /* Old ABI. Don't copy garbage. */ memcpy(hw_render, cb, offsetof(struct retro_hw_render_callback, stencil)); else memcpy(hw_render, cb, sizeof(*cb)); break; } case RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME: { bool state = *(const bool*)data; RARCH_LOG("Environ SET_SUPPORT_NO_GAME: %s.\n", state ? "yes" : "no"); system->no_content = state; break; } case RETRO_ENVIRONMENT_GET_LIBRETRO_PATH: { const char **path = (const char**)data; #ifdef HAVE_DYNAMIC *path = settings->libretro; #else *path = NULL; #endif break; } /* FIXME - PS3 audio driver needs to be fixed so that threaded * audio works correctly (audio is already on a thread for PS3 * audio driver so that's probably the problem) */ #if defined(HAVE_THREADS) && !defined(__CELLOS_LV2__) case RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK: { const struct retro_audio_callback *info = (const struct retro_audio_callback*)data; RARCH_LOG("Environ SET_AUDIO_CALLBACK.\n"); if (driver->recording_data) /* A/V sync is a must. */ return false; #ifdef HAVE_NETPLAY if (global->netplay.enable) return false; #endif audio_driver_set_callback(info); break; } #endif case RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK: { const struct retro_frame_time_callback *info = (const struct retro_frame_time_callback*)data; RARCH_LOG("Environ SET_FRAME_TIME_CALLBACK.\n"); #ifdef HAVE_NETPLAY /* retro_run() will be called in very strange and * mysterious ways, have to disable it. */ if (global->netplay.enable) return false; #endif system->frame_time = *info; break; } case RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE: { struct retro_rumble_interface *iface = (struct retro_rumble_interface*)data; RARCH_LOG("Environ GET_RUMBLE_INTERFACE.\n"); iface->set_rumble_state = input_driver_set_rumble_state; break; } case RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES: { uint64_t *mask = (uint64_t*)data; RARCH_LOG("Environ GET_INPUT_DEVICE_CAPABILITIES.\n"); if (driver->input && driver->input->get_capabilities && driver->input_data) *mask = input_driver_get_capabilities(); else return false; break; } case RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE: { struct retro_sensor_interface *iface = (struct retro_sensor_interface*)data; RARCH_LOG("Environ GET_SENSOR_INTERFACE.\n"); iface->set_sensor_state = input_sensor_set_state; iface->get_sensor_input = input_sensor_get_input; break; } case RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE: { struct retro_camera_callback *cb = (struct retro_camera_callback*)data; RARCH_LOG("Environ GET_CAMERA_INTERFACE.\n"); cb->start = driver_camera_start; cb->stop = driver_camera_stop; system->camera_callback = *cb; driver->camera_active = cb->caps != 0; break; } case RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE: { struct retro_location_callback *cb = (struct retro_location_callback*)data; RARCH_LOG("Environ GET_LOCATION_INTERFACE.\n"); cb->start = driver_location_start; cb->stop = driver_location_stop; cb->get_position = driver_location_get_position; cb->set_interval = driver_location_set_interval; system->location_callback = *cb; driver->location_active = true; break; } case RETRO_ENVIRONMENT_GET_LOG_INTERFACE: { struct retro_log_callback *cb = (struct retro_log_callback*)data; RARCH_LOG("Environ GET_LOG_INTERFACE.\n"); cb->log = rarch_log_libretro; break; } case RETRO_ENVIRONMENT_GET_PERF_INTERFACE: { struct retro_perf_callback *cb = (struct retro_perf_callback*)data; RARCH_LOG("Environ GET_PERF_INTERFACE.\n"); cb->get_time_usec = retro_get_time_usec; cb->get_cpu_features = retro_get_cpu_features; cb->get_perf_counter = retro_get_perf_counter; cb->perf_register = retro_perf_register; /* libretro specific path. */ cb->perf_start = retro_perf_start; cb->perf_stop = retro_perf_stop; cb->perf_log = retro_perf_log; /* libretro specific path. */ break; } case RETRO_ENVIRONMENT_GET_CORE_ASSETS_DIRECTORY: { const char **dir = (const char**)data; *dir = *settings->core_assets_directory ? settings->core_assets_directory : NULL; RARCH_LOG("Environ CORE_ASSETS_DIRECTORY: \"%s\".\n", settings->core_assets_directory); break; } case RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO: { RARCH_LOG("Environ SET_SYSTEM_AV_INFO.\n"); return driver_update_system_av_info( (const struct retro_system_av_info*)data); } case RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO: { unsigned i, j; const struct retro_subsystem_info *info = (const struct retro_subsystem_info*)data; RARCH_LOG("Environ SET_SUBSYSTEM_INFO.\n"); for (i = 0; info[i].ident; i++) { RARCH_LOG("Special game type: %s\n", info[i].desc); RARCH_LOG(" Ident: %s\n", info[i].ident); RARCH_LOG(" ID: %u\n", info[i].id); RARCH_LOG(" Content:\n"); for (j = 0; j < info[i].num_roms; j++) { RARCH_LOG(" %s (%s)\n", info[i].roms[j].desc, info[i].roms[j].required ? "required" : "optional"); } } free(system->special); system->special = (struct retro_subsystem_info*) calloc(i, sizeof(*system->special)); if (!system->special) return false; memcpy(system->special, info, i * sizeof(*system->special)); system->num_special = i; break; } case RETRO_ENVIRONMENT_SET_CONTROLLER_INFO: { unsigned i, j; const struct retro_controller_info *info = (const struct retro_controller_info*)data; RARCH_LOG("Environ SET_CONTROLLER_INFO.\n"); for (i = 0; info[i].types; i++) { RARCH_LOG("Controller port: %u\n", i + 1); for (j = 0; j < info[i].num_types; j++) RARCH_LOG(" %s (ID: %u)\n", info[i].types[j].desc, info[i].types[j].id); } free(system->ports); system->ports = (struct retro_controller_info*) calloc(i, sizeof(*system->ports)); if (!system->ports) return false; memcpy(system->ports, info, i * sizeof(*system->ports)); system->num_ports = i; break; } case RETRO_ENVIRONMENT_SET_GEOMETRY: { struct retro_system_av_info *av_info = video_viewport_get_system_av_info(); const struct retro_game_geometry *in_geom = (const struct retro_game_geometry*)data; struct retro_game_geometry *geom = av_info ? (struct retro_game_geometry*)&av_info->geometry : NULL; if (!geom) return false; RARCH_LOG("Environ SET_GEOMETRY.\n"); /* Can potentially be called every frame, * don't do anything unless required. */ if (geom->base_width != in_geom->base_width || geom->base_height != in_geom->base_height || geom->aspect_ratio != in_geom->aspect_ratio) { geom->base_width = in_geom->base_width; geom->base_height = in_geom->base_height; geom->aspect_ratio = in_geom->aspect_ratio; RARCH_LOG("SET_GEOMETRY: %ux%u, aspect: %.3f.\n", geom->base_width, geom->base_height, geom->aspect_ratio); /* Forces recomputation of aspect ratios if * using core-dependent aspect ratios. */ event_command(EVENT_CMD_VIDEO_SET_ASPECT_RATIO); /* TODO: Figure out what to do, if anything, with recording. */ } break; } /* Private extensions for internal use, not part of libretro API. */ case RETRO_ENVIRONMENT_SET_LIBRETRO_PATH: RARCH_LOG("Environ (Private) SET_LIBRETRO_PATH.\n"); if (!path_file_exists((const char*)data)) return false; rarch_main_ctl(RARCH_MAIN_CTL_SET_LIBRETRO_PATH, data); break; case RETRO_ENVIRONMENT_EXEC: case RETRO_ENVIRONMENT_EXEC_ESCAPE: { char *fullpath = NULL; rarch_main_ctl(RARCH_MAIN_CTL_GET_CONTENT_PATH, &fullpath); if (fullpath != data) { rarch_main_ctl(RARCH_MAIN_CTL_CLEAR_CONTENT_PATH, NULL); if (data) rarch_main_ctl(RARCH_MAIN_CTL_SET_CONTENT_PATH, data); } #if defined(RARCH_CONSOLE) if (driver->frontend_ctx && driver->frontend_ctx->set_fork) driver->frontend_ctx->set_fork(true, true); #elif defined(HAVE_DYNAMIC) rarch_ctl(RARCH_ACTION_STATE_LOAD_CONTENT, NULL); #endif if (cmd == RETRO_ENVIRONMENT_EXEC_ESCAPE) { RARCH_LOG("Environ (Private) EXEC_ESCAPE.\n"); global->exec = true; } else RARCH_LOG("Environ (Private) EXEC.\n"); } break; default: RARCH_LOG("Environ UNSUPPORTED (#%u).\n", cmd); return false; } return true; }
/** * init_content_file: * * Initializes and loads a content file for the currently * selected libretro core. * * global->content_is_init will be set to the return value * on exit. * * Returns : true if successful, otherwise false. **/ bool init_content_file(void) { unsigned i; union string_list_elem_attr attr; bool ret = false; struct string_list *content = NULL; const struct retro_subsystem_info *special = NULL; settings_t *settings = config_get_ptr(); rarch_system_info_t *system = rarch_system_info_get_ptr(); global_t *global = global_get_ptr(); global->temporary_content = string_list_new(); if (!global->temporary_content) goto error; if (*global->subsystem) { special = libretro_find_subsystem_info(system->special, system->num_special, global->subsystem); if (!special) { RARCH_ERR( "Failed to find subsystem \"%s\" in libretro implementation.\n", global->subsystem); goto error; } if (special->num_roms && !global->subsystem_fullpaths) { RARCH_ERR("libretro core requires special content, but none were provided.\n"); goto error; } else if (special->num_roms && special->num_roms != global->subsystem_fullpaths->size) { RARCH_ERR("libretro core requires %u content files for subsystem \"%s\", but %u content files were provided.\n", special->num_roms, special->desc, (unsigned)global->subsystem_fullpaths->size); goto error; } else if (!special->num_roms && global->subsystem_fullpaths && global->subsystem_fullpaths->size) { RARCH_ERR("libretro core takes no content for subsystem \"%s\", but %u content files were provided.\n", special->desc, (unsigned)global->subsystem_fullpaths->size); goto error; } } content = string_list_new(); attr.i = 0; if (!content) goto error; if (*global->subsystem) { for (i = 0; i < global->subsystem_fullpaths->size; i++) { attr.i = special->roms[i].block_extract; attr.i |= special->roms[i].need_fullpath << 1; attr.i |= special->roms[i].required << 2; string_list_append(content, global->subsystem_fullpaths->elems[i].data, attr); } } else { char *fullpath = NULL; rarch_main_ctl(RARCH_MAIN_CTL_GET_CONTENT_PATH, &fullpath); attr.i = system->info.block_extract; attr.i |= system->info.need_fullpath << 1; attr.i |= (!system->no_content) << 2; string_list_append(content, (global->inited.core.no_content && settings->core.set_supports_no_game_enable) ? "" : fullpath, attr); } #ifdef HAVE_ZLIB /* Try to extract all content we're going to load if appropriate. */ for (i = 0; i < content->size; i++) { const char *ext = NULL; const char *valid_ext = NULL; /* Block extract check. */ if (content->elems[i].attr.i & 1) continue; ext = path_get_extension(content->elems[i].data); valid_ext = special ? special->roms[i].valid_extensions : system->info.valid_extensions; if (ext && !strcasecmp(ext, "zip")) { char temporary_content[PATH_MAX_LENGTH] = {0}; strlcpy(temporary_content, content->elems[i].data, sizeof(temporary_content)); if (!zlib_extract_first_content_file(temporary_content, sizeof(temporary_content), valid_ext, *settings->cache_directory ? settings->cache_directory : NULL)) { RARCH_ERR("Failed to extract content from zipped file: %s.\n", temporary_content); goto error; } string_list_set(content, i, temporary_content); string_list_append(global->temporary_content, temporary_content, attr); } } #endif /* Set attr to need_fullpath as appropriate. */ ret = load_content(special, content); error: global->inited.content = (ret) ? true : false; if (content) string_list_free(content); return ret; }