database_info_handle_t *database_info_dir_init(const char *dir, enum database_type type) { database_info_handle_t *db = (database_info_handle_t*) calloc(1, sizeof(*db)); if (!db) return NULL; db->list = dir_list_new_special(dir, DIR_LIST_CORE_INFO, NULL); if (!db->list) goto error; db->list_ptr = 0; db->status = DATABASE_STATUS_ITERATE; db->type = type; return db; error: if (db) free(db); return NULL; }
static bool shader_dir_init(rarch_dir_list_t *dir_list) { unsigned i; settings_t *settings = config_get_ptr(); if (!*settings->video.shader_dir) return false; dir_list->list = dir_list_new_special(NULL, DIR_LIST_SHADERS, NULL); if (!dir_list->list || dir_list->list->size == 0) { event_command(EVENT_CMD_SHADER_DIR_DEINIT); return false; } dir_list->ptr = 0; dir_list_sort(dir_list->list, false); for (i = 0; i < dir_list->list->size; i++) RARCH_LOG("%s \"%s\"\n", msg_hash_to_str(MSG_FOUND_SHADER), dir_list->list->elems[i].data); return true; }
bool dir_init_shader(void) { unsigned i; struct rarch_dir_list *dir_list = (struct rarch_dir_list*)&dir_shader_list; settings_t *settings = config_get_ptr(); if (!*settings->paths.directory_video_shader) return false; dir_list->list = dir_list_new_special( settings->paths.directory_video_shader, DIR_LIST_SHADERS, NULL); if (!dir_list->list || dir_list->list->size == 0) { command_event(CMD_EVENT_SHADER_DIR_DEINIT, NULL); return false; } dir_list->ptr = 0; dir_list_sort(dir_list->list, false); for (i = 0; i < dir_list->list->size; i++) RARCH_LOG("%s \"%s\"\n", msg_hash_to_str(MSG_FOUND_SHADER), dir_list->list->elems[i].data); return true; }
void core_info_get_name(const char *path, char *s, size_t len) { size_t i; settings_t *settings = config_get_ptr(); struct string_list *contents = dir_list_new_special( settings->paths.directory_libretro, DIR_LIST_CORES, NULL); const char *path_basedir = !string_is_empty(settings->paths.path_libretro_info) ? settings->paths.path_libretro_info : settings->paths.directory_libretro; if (!contents) return; for (i = 0; i < contents->size; i++) { size_t path_size = PATH_MAX_LENGTH * sizeof(char); char *info_path = NULL; config_file_t *conf = NULL; char *new_core_name = NULL; const char *current_path = contents->elems[i].data; if (!string_is_equal(current_path, path)) continue; info_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); info_path[0] = '\0'; if (!core_info_list_iterate(info_path, path_size, path_basedir, contents, i) && path_is_valid(info_path)) { free(info_path); continue; } conf = config_file_new(info_path); if (!conf) { free(info_path); continue; } if (config_get_string(conf, "corename", &new_core_name)) { strlcpy(s, new_core_name, len); free(new_core_name); } config_file_free(conf); free(info_path); break; } if (contents) dir_list_free(contents); contents = NULL; }
void core_info_get_name(const char *path, char *s, size_t len) { size_t i; core_info_t *core_info = NULL; core_info_list_t *core_info_list = NULL; struct string_list *contents = NULL; settings_t *settings = config_get_ptr(); if (!settings) return; contents = dir_list_new_special( settings->directory.libretro, DIR_LIST_CORES, NULL); if (!contents) return; core_info_list = (core_info_list_t*)calloc(1, sizeof(*core_info_list)); if (!core_info_list) goto error; core_info = (core_info_t*)calloc(contents->size, sizeof(*core_info)); if (!core_info) goto error; core_info_list->list = core_info; core_info_list->count = contents->size; for (i = 0; i < contents->size; i++) { config_file_t *conf = NULL; if (!string_is_equal(contents->elems[i].data, path)) continue; conf = core_info_list_iterate(contents, i); if (conf) { config_get_string(conf, "corename", &core_info[i].core_name); core_info[i].config_data = (void*)conf; } core_info[i].path = strdup(contents->elems[i].data); strlcpy(s, core_info[i].core_name, len); } error: if (contents) dir_list_free(contents); contents = NULL; core_info_list_free(core_info_list); }
static void event_set_savestate_auto_index(void) { size_t i; char state_dir[PATH_MAX_LENGTH] = {0}; char state_base[PATH_MAX_LENGTH] = {0}; struct string_list *dir_list = NULL; unsigned max_idx = 0; settings_t *settings = config_get_ptr(); global_t *global = global_get_ptr(); if (!settings->savestate_auto_index) return; /* Find the file in the same directory as global->savestate_name * with the largest numeral suffix. * * E.g. /foo/path/content.state, will try to find * /foo/path/content.state%d, where %d is the largest number available. */ fill_pathname_basedir(state_dir, global->savestate_name, sizeof(state_dir)); fill_pathname_base(state_base, global->savestate_name, sizeof(state_base)); if (!(dir_list = dir_list_new_special(state_dir, DIR_LIST_PLAIN))) return; for (i = 0; i < dir_list->size; i++) { unsigned idx; char elem_base[PATH_MAX_LENGTH] = {0}; const char *end = NULL; const char *dir_elem = dir_list->elems[i].data; fill_pathname_base(elem_base, dir_elem, sizeof(elem_base)); if (strstr(elem_base, state_base) != elem_base) continue; end = dir_elem + strlen(dir_elem); while ((end > dir_elem) && isdigit(end[-1])) end--; idx = strtoul(end, NULL, 0); if (idx > max_idx) max_idx = idx; } dir_list_free(dir_list); settings->state_slot = max_idx; RARCH_LOG("Found last state slot: #%d\n", settings->state_slot); }
void core_info_get_name(const char *path, char *s, size_t len) { size_t i; settings_t *settings = config_get_ptr(); struct string_list *contents = dir_list_new_special( settings->paths.directory_libretro, DIR_LIST_CORES, NULL); if (!contents) return; for (i = 0; i < contents->size; i++) { char info_path[PATH_MAX_LENGTH]; config_file_t *conf = NULL; char *new_core_name = NULL; info_path[0] = '\0'; if (!string_is_equal(contents->elems[i].data, path)) continue; if (!core_info_list_iterate(info_path, sizeof(info_path), contents, i) && path_is_valid(info_path)) continue; conf = config_file_new(info_path); if (!conf) continue; if (config_get_string(conf, "corename", &new_core_name)) { strlcpy(s, new_core_name, len); free(new_core_name); } config_file_free(conf); break; } if (contents) dir_list_free(contents); contents = NULL; }
void rarch_main_data_db_iterate(bool is_thread) { database_info_handle_t *db = (db_ptr) ? db_ptr->handle : NULL; database_state_handle_t *db_state = (db_ptr) ? &db_ptr->state : NULL; const char *name = db ? db->list->elems[db->list_ptr].data : NULL; if (!db) goto do_poll; switch (db->status) { case DATABASE_STATUS_ITERATE_BEGIN: if (db_state && !db_state->list) db_state->list = dir_list_new_special(NULL, DIR_LIST_DATABASES, NULL); db->status = DATABASE_STATUS_ITERATE_START; break; case DATABASE_STATUS_ITERATE_START: rarch_main_data_db_cleanup_state(db_state); db_state->list_index = 0; db_state->entry_index = 0; database_info_iterate_start(db, name); break; case DATABASE_STATUS_ITERATE: if (database_info_iterate(&db_ptr->state, db) == 0) { db->status = DATABASE_STATUS_ITERATE_NEXT; db->type = DATABASE_TYPE_ITERATE; } break; case DATABASE_STATUS_ITERATE_NEXT: if (database_info_iterate_next(db) == 0) { db->status = DATABASE_STATUS_ITERATE_START; db->type = DATABASE_TYPE_ITERATE; } else { rarch_main_msg_queue_push_new(MSG_SCANNING_OF_DIRECTORY_FINISHED, 0, 180, true); pending_scan_finished = true; db->status = DATABASE_STATUS_FREE; } break; case DATABASE_STATUS_FREE: if (db_state->list) dir_list_free(db_state->list); db_state->list = NULL; rarch_main_data_db_cleanup_state(db_state); database_info_free(db); if (db_ptr->handle) free(db_ptr->handle); db_ptr->handle = NULL; break; default: case DATABASE_STATUS_NONE: goto do_poll; } return; do_poll: if (database_info_poll(db_ptr) != -1) { if (db_ptr->handle) db_ptr->handle->status = DATABASE_STATUS_ITERATE_BEGIN; } }
/** * event_command: * @cmd : Event command index. * * Performs RetroArch 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; runloop_t *runloop = rarch_main_get_ptr(); 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_main_set_state(RARCH_ACTION_STATE_LOAD_CONTENT); break; #ifdef HAVE_FFMPEG case EVENT_CMD_LOAD_CONTENT_FFMPEG: rarch_main_set_state(RARCH_ACTION_STATE_LOAD_CONTENT_FFMPEG); break; #endif case EVENT_CMD_LOAD_CONTENT_IMAGEVIEWER: rarch_main_set_state(RARCH_ACTION_STATE_LOAD_CONTENT_IMAGEVIEWER); 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->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: if (menu_driver_alive()) rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); else rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING); break; case EVENT_CMD_CONTROLLERS_INIT: event_init_controllers(); break; case EVENT_CMD_RESET: RARCH_LOG(RETRO_LOG_RESETTING_CONTENT); rarch_main_msg_queue_push("Reset.", 1, 120, true); pretro_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_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->fullpath = '\0'; rarch_main_set_state(RARCH_ACTION_STATE_LOAD_CONTENT); } 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_main_set_state(RARCH_ACTION_STATE_QUIT); break; case EVENT_CMD_REINIT: { const struct retro_hw_render_callback *hw_render = (const struct retro_hw_render_callback*)video_driver_callback(); 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_driver_poll(); #ifdef HAVE_MENU menu_display_fb_set_dirty(); 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_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: 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 ? "Audio muted." : "Audio unmuted."; if (!audio_driver_mute_toggle()) { RARCH_ERR("Failed to unmute audio.\n"); 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 if (driver->overlay) input_overlay_free(driver->overlay); driver->overlay = NULL; memset(&driver->overlay_state, 0, sizeof(driver->overlay_state)); #endif break; case EVENT_CMD_OVERLAY_INIT: event_command(EVENT_CMD_OVERLAY_DEINIT); #ifdef HAVE_OVERLAY if (driver->osk_enable) { if (!*settings->osk.overlay) break; } else { if (!*settings->input.overlay) break; } driver->overlay = input_overlay_new(driver->osk_enable ? settings->osk.overlay : settings->input.overlay, driver->osk_enable ? settings->osk.enable : settings->input.overlay_enable, settings->input.overlay_opacity, settings->input.overlay_scale); if (!driver->overlay) RARCH_ERR("Failed to load overlay.\n"); #endif break; case EVENT_CMD_OVERLAY_NEXT: #ifdef HAVE_OVERLAY input_overlay_next(driver->overlay, 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("Loading history file: [%s].\n", 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) core_info_list_free(global->core_info); global->core_info = 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 = 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(driver->overlay, settings->input.overlay_scale); #endif break; case EVENT_CMD_OVERLAY_SET_ALPHA_MOD: #ifdef HAVE_OVERLAY input_overlay_set_alpha_mod(driver->overlay, 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_main_set_state(RARCH_ACTION_STATE_FORCE_QUIT); break; case EVENT_CMD_RESUME: rarch_main_set_state(RARCH_ACTION_STATE_MENU_RUNNING_FINISHED); break; case EVENT_CMD_RESTART_RETROARCH: #if defined(GEKKO) && defined(HW_RVL) fill_pathname_join(global->fullpath, g_defaults.core_dir, SALAMANDER_FILE, sizeof(global->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: if (runloop->is_paused) { RARCH_LOG("Paused.\n"); event_command(EVENT_CMD_AUDIO_STOP); if (settings->video.black_frame_insertion) video_driver_cached_frame(); } else { RARCH_LOG("Unpaused.\n"); event_command(EVENT_CMD_AUDIO_START); } break; case EVENT_CMD_PAUSE_TOGGLE: runloop->is_paused = !runloop->is_paused; event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_UNPAUSE: runloop->is_paused = false; event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_PAUSE: runloop->is_paused = true; event_command(EVENT_CMD_PAUSE_CHECKS); break; case EVENT_CMD_MENU_PAUSE_LIBRETRO: 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); } 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("Found shader \"%s\"\n", 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->use_sram = global->use_sram && !global->sram_save_disable #ifdef HAVE_NETPLAY && (!driver->netplay_data || !global->netplay_is_client) #endif ; if (!global->use_sram) RARCH_LOG("SRAM will not be saved.\n"); if (global->use_sram) 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("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("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("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("Grab mouse state: %s.\n", 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_NONE: default: goto error; } return true; error: return false; }
static bool input_autoconfigure_joypad_from_conf_dir( autoconfig_params_t *params, retro_task_t *task) { size_t i; char path[PATH_MAX_LENGTH]; int ret = 0; int index = -1; int current_best = 0; config_file_t *conf = NULL; struct string_list *list = NULL; path[0] = '\0'; fill_pathname_application_special(path, sizeof(path), APPLICATION_SPECIAL_DIRECTORY_AUTOCONFIG); list = dir_list_new_special(path, DIR_LIST_AUTOCONFIG, "cfg"); if (!list || !list->size) { if (list) { string_list_free(list); list = NULL; } if (!string_is_empty(params->autoconfig_directory)) list = dir_list_new_special(params->autoconfig_directory, DIR_LIST_AUTOCONFIG, "cfg"); } if (!list) { RARCH_LOG("[Autoconf]: No profiles found.\n"); return false; } RARCH_LOG("[Autoconf]: %d profiles found.\n", (int)list->size); for (i = 0; i < list->size; i++) { conf = config_file_new(list->elems[i].data); if (conf) ret = input_autoconfigure_joypad_try_from_conf(conf, params); if (ret >= current_best) { index = (int)i; current_best = ret; } config_file_free(conf); } if (index >= 0 && current_best > 0) { conf = config_file_new(list->elems[index].data); if (conf) { char conf_path[PATH_MAX_LENGTH]; conf_path[0] = '\0'; config_get_config_path(conf, conf_path, sizeof(conf_path)); RARCH_LOG("[Autoconf]: selected configuration: %s\n", conf_path); input_autoconfigure_joypad_add(conf, params, task); config_file_free(conf); ret = 1; } } else ret = 0; string_list_free(list); if (ret == 0) return false; return true; }
static core_info_list_t *core_info_list_new(const char *path) { size_t i; core_info_t *core_info = NULL; core_info_list_t *core_info_list = NULL; struct string_list *contents = dir_list_new_special( path, DIR_LIST_CORES, NULL); settings_t *settings = config_get_ptr(); const char *path_basedir = !string_is_empty(settings->paths.path_libretro_info) ? settings->paths.path_libretro_info : settings->paths.directory_libretro; if (!contents) return NULL; core_info_list = (core_info_list_t*)calloc(1, sizeof(*core_info_list)); if (!core_info_list) goto error; core_info = (core_info_t*)calloc(contents->size, sizeof(*core_info)); if (!core_info) goto error; core_info_list->list = core_info; core_info_list->count = contents->size; for (i = 0; i < contents->size; i++) { size_t info_path_size = PATH_MAX_LENGTH * sizeof(char); char *info_path = (char*)malloc(PATH_MAX_LENGTH * sizeof(char)); info_path[0] = '\0'; if ( core_info_list_iterate(info_path, info_path_size, path_basedir, contents, i) && path_is_valid(info_path)) { char *tmp = NULL; bool tmp_bool = false; unsigned count = 0; config_file_t *conf = config_file_new(info_path); free(info_path); if (!conf) continue; if (config_get_string(conf, "display_name", &tmp) && !string_is_empty(tmp)) { core_info[i].display_name = strdup(tmp); free(tmp); tmp = NULL; } if (config_get_string(conf, "corename", &tmp) && !string_is_empty(tmp)) { core_info[i].core_name = strdup(tmp); free(tmp); tmp = NULL; } if (config_get_string(conf, "systemname", &tmp) && !string_is_empty(tmp)) { core_info[i].systemname = strdup(tmp); free(tmp); tmp = NULL; } if (config_get_string(conf, "manufacturer", &tmp) && !string_is_empty(tmp)) { core_info[i].system_manufacturer = strdup(tmp); free(tmp); tmp = NULL; } config_get_uint(conf, "firmware_count", &count); core_info[i].firmware_count = count; if (config_get_string(conf, "supported_extensions", &tmp) && !string_is_empty(tmp)) { core_info[i].supported_extensions = strdup(tmp); core_info[i].supported_extensions_list = string_split(core_info[i].supported_extensions, "|"); free(tmp); tmp = NULL; } if (config_get_string(conf, "authors", &tmp) && !string_is_empty(tmp)) { core_info[i].authors = strdup(tmp); core_info[i].authors_list = string_split(core_info[i].authors, "|"); free(tmp); tmp = NULL; } if (config_get_string(conf, "permissions", &tmp) && !string_is_empty(tmp)) { core_info[i].permissions = strdup(tmp); core_info[i].permissions_list = string_split(core_info[i].permissions, "|"); free(tmp); tmp = NULL; } if (config_get_string(conf, "license", &tmp) && !string_is_empty(tmp)) { core_info[i].licenses = strdup(tmp); core_info[i].licenses_list = string_split(core_info[i].licenses, "|"); free(tmp); tmp = NULL; } if (config_get_string(conf, "categories", &tmp) && !string_is_empty(tmp)) { core_info[i].categories = strdup(tmp); core_info[i].categories_list = string_split(core_info[i].categories, "|"); free(tmp); tmp = NULL; } if (config_get_string(conf, "database", &tmp) && !string_is_empty(tmp)) { core_info[i].databases = strdup(tmp); core_info[i].databases_list = string_split(core_info[i].databases, "|"); free(tmp); tmp = NULL; } if (config_get_string(conf, "notes", &tmp) && !string_is_empty(tmp)) { core_info[i].notes = strdup(tmp); core_info[i].note_list = string_split(core_info[i].notes, "|"); free(tmp); tmp = NULL; } if (tmp) free(tmp); tmp = NULL; if (config_get_bool(conf, "supports_no_game", &tmp_bool)) core_info[i].supports_no_game = tmp_bool; if (config_get_bool(conf, "database_match_archive_member", &tmp_bool)) core_info[i].database_match_archive_member = tmp_bool; core_info[i].config_data = conf; } else free(info_path); if (!string_is_empty(contents->elems[i].data)) core_info[i].path = strdup(contents->elems[i].data); if (!core_info[i].display_name) core_info[i].display_name = strdup(path_basename(core_info[i].path)); } if (core_info_list) { core_info_list_resolve_all_extensions(core_info_list); core_info_list_resolve_all_firmware(core_info_list); } dir_list_free(contents); return core_info_list; error: if (contents) dir_list_free(contents); core_info_list_free(core_info_list); return NULL; }
database_info_handle_t *database_info_dir_init(const char *dir, enum database_type type) { database_info_handle_t *db = (database_info_handle_t*) calloc(1, sizeof(*db)); unsigned i = 0; if (!db) return NULL; db->list = dir_list_new_special(dir, DIR_LIST_RECURSIVE, NULL); if (!db->list) goto error; db->list_ptr = 0; db->status = DATABASE_STATUS_ITERATE; db->type = type; if (db->list->size > 0) { for (i = 0; i < db->list->size; i++) { const char *path = db->list->elems[i].data; if (path_is_compressed_file(path) && !path_contains_compressed_file(path)) { struct string_list *archive_list = path_is_compressed_file(path) ? file_archive_get_file_list(path, NULL) : NULL; if (archive_list && archive_list->size > 0) { unsigned i; for (i = 0; i < archive_list->size; i++) { char new_path[PATH_MAX_LENGTH]; size_t path_len = strlen(path); new_path[0] = '\0'; strlcpy(new_path, path, sizeof(new_path)); if (path_len + strlen(archive_list->elems[i].data) + 1 < PATH_MAX_LENGTH) { new_path[path_len] = '#'; strlcpy(new_path + path_len + 1, archive_list->elems[i].data, sizeof(new_path) - path_len); } string_list_append(db->list, new_path, archive_list->elems[i].attr); } string_list_free(archive_list); } } } } return db; error: if (db) free(db); return NULL; }
static bool input_autoconfigure_joypad_from_conf_dir( autoconfig_params_t *params) { size_t i; char path[PATH_MAX_LENGTH] = {0}; int ret = 0; int index = -1; int current_best = 0; config_file_t *conf = NULL; struct string_list *list = NULL; settings_t *settings = config_get_ptr(); if (!settings) return false; fill_pathname_join(path, settings->directory.autoconfig, settings->input.joypad_driver, sizeof(path)); list = dir_list_new_special(path, DIR_LIST_AUTOCONFIG, "cfg"); if (!list || !list->size) { if (list) string_list_free(list); list = dir_list_new_special(settings->directory.autoconfig, DIR_LIST_AUTOCONFIG, "cfg"); } if(!list) return false; RARCH_LOG("Autodetect: %d profiles found\n", list->size); for (i = 0; i < list->size; i++) { conf = config_file_new(list->elems[i].data); ret = input_try_autoconfigure_joypad_from_conf(conf, params); if(ret >= current_best) { index = i; current_best = ret; } config_file_free(conf); } if(index >= 0 && current_best > 0) { conf = config_file_new(list->elems[index].data); if (conf) { char conf_path[PATH_MAX_LENGTH]; config_get_config_path(conf, conf_path, sizeof(conf_path)); RARCH_LOG("Autodetect: selected configuration: %s\n", conf_path); input_autoconfigure_joypad_add(conf, params); config_file_free(conf); ret = 1; } } else ret = 0; string_list_free(list); if (ret == 0) return false; return true; }
core_info_list_t *core_info_list_new(void) { size_t i; core_info_t *core_info = NULL; core_info_list_t *core_info_list = NULL; settings_t *settings = config_get_ptr(); struct string_list *contents = dir_list_new_special(NULL, DIR_LIST_CORES); if (!contents) return NULL; core_info_list = (core_info_list_t*)calloc(1, sizeof(*core_info_list)); if (!core_info_list) goto error; core_info = (core_info_t*)calloc(contents->size, sizeof(*core_info)); if (!core_info) goto error; core_info_list->list = core_info; core_info_list->count = contents->size; for (i = 0; i < contents->size; i++) { char info_path_base[PATH_MAX_LENGTH] = {0}; char info_path[PATH_MAX_LENGTH] = {0}; core_info[i].path = strdup(contents->elems[i].data); if (!core_info[i].path) break; fill_pathname_base(info_path_base, contents->elems[i].data, sizeof(info_path_base)); path_remove_extension(info_path_base); #if defined(RARCH_MOBILE) || (defined(RARCH_CONSOLE) && !defined(PSP)) char *substr = strrchr(info_path_base, '_'); if (substr) *substr = '\0'; #endif strlcat(info_path_base, ".info", sizeof(info_path_base)); fill_pathname_join(info_path, (*settings->libretro_info_path) ? settings->libretro_info_path : settings->libretro_directory, info_path_base, sizeof(info_path)); core_info[i].data = config_file_new(info_path); if (core_info[i].data) { unsigned count = 0; config_get_string(core_info[i].data, "display_name", &core_info[i].display_name); config_get_string(core_info[i].data, "corename", &core_info[i].core_name); config_get_string(core_info[i].data, "systemname", &core_info[i].systemname); config_get_string(core_info[i].data, "manufacturer", &core_info[i].system_manufacturer); config_get_uint(core_info[i].data, "firmware_count", &count); core_info[i].firmware_count = count; if (config_get_string(core_info[i].data, "supported_extensions", &core_info[i].supported_extensions) && core_info[i].supported_extensions) core_info[i].supported_extensions_list = string_split(core_info[i].supported_extensions, "|"); if (config_get_string(core_info[i].data, "authors", &core_info[i].authors) && core_info[i].authors) core_info[i].authors_list = string_split(core_info[i].authors, "|"); if (config_get_string(core_info[i].data, "permissions", &core_info[i].permissions) && core_info[i].permissions) core_info[i].permissions_list = string_split(core_info[i].permissions, "|"); if (config_get_string(core_info[i].data, "license", &core_info[i].licenses) && core_info[i].licenses) core_info[i].licenses_list = string_split(core_info[i].licenses, "|"); if (config_get_string(core_info[i].data, "categories", &core_info[i].categories) && core_info[i].categories) core_info[i].categories_list = string_split(core_info[i].categories, "|"); if (config_get_string(core_info[i].data, "database", &core_info[i].databases) && core_info[i].databases) core_info[i].databases_list = string_split(core_info[i].databases, "|"); if (config_get_string(core_info[i].data, "notes", &core_info[i].notes) && core_info[i].notes) core_info[i].note_list = string_split(core_info[i].notes, "|"); config_get_bool(core_info[i].data, "supports_no_game", &core_info[i].supports_no_game); } if (!core_info[i].display_name) core_info[i].display_name = strdup(path_basename(core_info[i].path)); } core_info_list_resolve_all_extensions(core_info_list); core_info_list_resolve_all_firmware(core_info_list); dir_list_free(contents); return core_info_list; error: if (contents) dir_list_free(contents); core_info_list_free(core_info_list); return NULL; }
void core_info_get_name(const char *path, char *s, size_t len) { size_t i; core_info_t *core_info = NULL; core_info_list_t *core_info_list = NULL; settings_t *settings = config_get_ptr(); struct string_list *contents = dir_list_new_special(NULL, DIR_LIST_CORES); if (!contents) return; core_info_list = (core_info_list_t*)calloc(1, sizeof(*core_info_list)); if (!core_info_list) goto error; core_info = (core_info_t*)calloc(contents->size, sizeof(*core_info)); if (!core_info) goto error; core_info_list->list = core_info; core_info_list->count = contents->size; for (i = 0; i < contents->size; i++) { char info_path_base[PATH_MAX_LENGTH] = {0}; char info_path[PATH_MAX_LENGTH] = {0}; core_info[i].path = strdup(contents->elems[i].data); if (!core_info[i].path) break; if (strcmp(core_info[i].path, path) != 0) continue; fill_pathname_base(info_path_base, contents->elems[i].data, sizeof(info_path_base)); path_remove_extension(info_path_base); #if defined(RARCH_MOBILE) || (defined(RARCH_CONSOLE) && !defined(PSP)) char *substr = strrchr(info_path_base, '_'); if (substr) *substr = '\0'; #endif strlcat(info_path_base, ".info", sizeof(info_path_base)); fill_pathname_join(info_path, (*settings->libretro_info_path) ? settings->libretro_info_path : settings->libretro_directory, info_path_base, sizeof(info_path)); core_info[i].data = config_file_new(info_path); if (core_info[i].data) config_get_string(core_info[i].data, "corename", &core_info[i].core_name); strlcpy(s, core_info[i].core_name, len); } error: if (contents) dir_list_free(contents); contents = NULL; core_info_list_free(core_info_list); }
static core_info_list_t *core_info_list_new(void) { size_t i; core_info_t *core_info = NULL; core_info_list_t *core_info_list = NULL; struct string_list *contents = NULL; settings_t *settings = config_get_ptr(); if (!settings) return NULL; contents = dir_list_new_special( settings->directory.libretro, DIR_LIST_CORES, NULL); if (!contents) return NULL; core_info_list = (core_info_list_t*)calloc(1, sizeof(*core_info_list)); if (!core_info_list) goto error; core_info = (core_info_t*)calloc(contents->size, sizeof(*core_info)); if (!core_info) goto error; core_info_list->list = core_info; core_info_list->count = contents->size; for (i = 0; i < contents->size; i++) { config_file_t *conf = core_info_list_iterate(contents, i); if (conf) { bool tmp_bool = false; unsigned count = 0; config_get_string(conf, "display_name", &core_info[i].display_name); config_get_string(conf, "corename", &core_info[i].core_name); config_get_string(conf, "systemname", &core_info[i].systemname); config_get_string(conf, "manufacturer", &core_info[i].system_manufacturer); config_get_uint(conf, "firmware_count", &count); core_info[i].firmware_count = count; if (config_get_string(conf, "supported_extensions", &core_info[i].supported_extensions) && core_info[i].supported_extensions) core_info[i].supported_extensions_list = string_split(core_info[i].supported_extensions, "|"); if (config_get_string(conf, "authors", &core_info[i].authors) && core_info[i].authors) core_info[i].authors_list = string_split(core_info[i].authors, "|"); if (config_get_string(conf, "permissions", &core_info[i].permissions) && core_info[i].permissions) core_info[i].permissions_list = string_split(core_info[i].permissions, "|"); if (config_get_string(conf, "license", &core_info[i].licenses) && core_info[i].licenses) core_info[i].licenses_list = string_split(core_info[i].licenses, "|"); if (config_get_string(conf, "categories", &core_info[i].categories) && core_info[i].categories) core_info[i].categories_list = string_split(core_info[i].categories, "|"); if (config_get_string(conf, "database", &core_info[i].databases) && core_info[i].databases) core_info[i].databases_list = string_split(core_info[i].databases, "|"); if (config_get_string(conf, "notes", &core_info[i].notes) && core_info[i].notes) core_info[i].note_list = string_split(core_info[i].notes, "|"); if (config_get_bool(conf, "supports_no_game", &tmp_bool)) core_info[i].supports_no_game = tmp_bool; core_info[i].config_data = conf; } core_info[i].path = strdup(contents->elems[i].data); if (!core_info[i].display_name) core_info[i].display_name = strdup(path_basename(core_info[i].path)); } core_info_list_resolve_all_extensions(core_info_list); core_info_list_resolve_all_firmware(core_info_list); dir_list_free(contents); return core_info_list; error: if (contents) dir_list_free(contents); core_info_list_free(core_info_list); return NULL; }
static void task_database_handler(retro_task_t *task) { db_handle_t *db = (db_handle_t*)task->state; database_info_handle_t *dbinfo = db->handle; database_state_handle_t *dbstate = &db->state; const char *name = dbinfo ? dbinfo->list->elems[dbinfo->list_ptr].data : NULL; if (!dbinfo || task->cancelled) goto task_finished; switch (dbinfo->status) { case DATABASE_STATUS_ITERATE_BEGIN: if (dbstate && !dbstate->list) dbstate->list = dir_list_new_special( NULL, DIR_LIST_DATABASES, NULL); dbinfo->status = DATABASE_STATUS_ITERATE_START; break; case DATABASE_STATUS_ITERATE_START: task_database_cleanup_state(dbstate); dbstate->list_index = 0; dbstate->entry_index = 0; task_database_iterate_start(dbinfo, name); break; case DATABASE_STATUS_ITERATE: if (task_database_iterate(&db->state, dbinfo) == 0) { dbinfo->status = DATABASE_STATUS_ITERATE_NEXT; dbinfo->type = DATABASE_TYPE_ITERATE; } break; case DATABASE_STATUS_ITERATE_NEXT: if (task_database_iterate_next(dbinfo) == 0) { dbinfo->status = DATABASE_STATUS_ITERATE_START; dbinfo->type = DATABASE_TYPE_ITERATE; } else { runloop_msg_queue_push( msg_hash_to_str(MSG_SCANNING_OF_DIRECTORY_FINISHED), 0, 180, true); goto task_finished; } break; default: case DATABASE_STATUS_FREE: case DATABASE_STATUS_NONE: goto task_finished; } return; task_finished: task->finished = true; if (dbstate->list) dir_list_free(dbstate->list); if (db->state.buf) free(db->state.buf); if (db->handle) database_info_free(db->handle); free(dbinfo); free(db); }
static void task_database_handler(retro_task_t *task) { const char *name = NULL; database_info_handle_t *dbinfo = NULL; database_state_handle_t *dbstate = NULL; db_handle_t *db = NULL; if (!task) goto task_finished; db = (db_handle_t*)task->state; if (!db) goto task_finished; if (!db->scan_started) { db->scan_started = true; if (db->is_directory) db->handle = database_info_dir_init(db->fullpath, DATABASE_TYPE_ITERATE, task); else db->handle = database_info_file_init(db->fullpath, DATABASE_TYPE_ITERATE, task); task_free_title(task); if (db->handle) db->handle->status = DATABASE_STATUS_ITERATE_BEGIN; } dbinfo = db->handle; dbstate = &db->state; if (!dbinfo || task_get_cancelled(task)) goto task_finished; switch (dbinfo->status) { case DATABASE_STATUS_ITERATE_BEGIN: if (dbstate && !dbstate->list) { dbstate->list = dir_list_new_special( db->content_database_path, DIR_LIST_DATABASES, NULL); } dbinfo->status = DATABASE_STATUS_ITERATE_START; break; case DATABASE_STATUS_ITERATE_START: name = database_info_get_current_element_name(dbinfo); task_database_cleanup_state(dbstate); dbstate->list_index = 0; dbstate->entry_index = 0; task_database_iterate_start(dbinfo, name); break; case DATABASE_STATUS_ITERATE: if (task_database_iterate(db, dbstate, dbinfo) == 0) { dbinfo->status = DATABASE_STATUS_ITERATE_NEXT; dbinfo->type = DATABASE_TYPE_ITERATE; } break; case DATABASE_STATUS_ITERATE_NEXT: if (task_database_iterate_next(dbinfo) == 0) { dbinfo->status = DATABASE_STATUS_ITERATE_START; dbinfo->type = DATABASE_TYPE_ITERATE; } else { runloop_msg_queue_push( msg_hash_to_str(MSG_SCANNING_OF_DIRECTORY_FINISHED), 0, 180, true); goto task_finished; } break; default: case DATABASE_STATUS_FREE: case DATABASE_STATUS_NONE: goto task_finished; } return; task_finished: if (task) task_set_finished(task, true); if (dbstate) { if (dbstate->list) dir_list_free(dbstate->list); } if (db) { if (db->state.buf) free(db->state.buf); if (db->handle) database_info_free(db->handle); free(db); } if (dbinfo) free(dbinfo); }