diff --git a/file.c b/file.c index f22f176a7c..394930f6fe 100644 --- a/file.c +++ b/file.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "dynamic.h" #include "movie.h" #include "ups.h" @@ -37,6 +38,7 @@ #include #else #include +#include #include #endif @@ -784,3 +786,50 @@ void dir_list_free(char **dir_list) free(*dir_list++); free(orig); } + +bool path_is_directory(const char *path) +{ +#ifdef _WIN32 + return false; +#else + struct stat buf; + if (stat(path, &buf) < 0) + return false; + + return S_ISDIR(buf.st_mode); +#endif +} + +void fill_pathname(char *out_path, const char *in_path, const char *replace, size_t size) +{ + char tmp_path[strlen(in_path) + 1]; + strlcpy(tmp_path, in_path, sizeof(tmp_path)); + char *tok = strrchr(tmp_path, '.'); + if (tok != NULL) + *tok = '\0'; + assert(strlcpy(out_path, tmp_path, size) < size); + assert(strlcat(out_path, replace, size) < size); +} + +void fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size) +{ + assert(strlcpy(out_path, in_path, size) < size); + assert(strlcat(out_path, replace, size) < size); +} + +void fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size) +{ + assert(strlcat(in_dir, "/", size) < size); + + const char *base = strrchr(in_basename, '/'); + if (!base) + base = strrchr(in_basename, '\\'); + + if (base) + base++; + else + base = in_basename; + + assert(strlcat(in_dir, base, size) < size); + assert(strlcat(in_dir, replace, size) < size); +} diff --git a/file.h b/file.h index ca94bace5e..6029999071 100644 --- a/file.h +++ b/file.h @@ -40,4 +40,15 @@ bool init_rom_file(enum ssnes_game_type type); char** dir_list_new(const char *dir, const char *ext); void dir_list_free(char **dir_list); +bool path_is_directory(const char *path); + +// Path-name operations. +// Replaces filename extension with replace. +void fill_pathname(char *out_path, const char *in_path, const char *replace, size_t size); +// Sets filename extension. Assumes in_path has no extension. +void fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size); +// Concatenates in_basename and replace to in_dir. +void fill_pathname_dir(char *in_dir, const char *in_basename, const char *replace, size_t size); + + #endif diff --git a/general.h b/general.h index e2406cd9e7..a033b11e18 100644 --- a/general.h +++ b/general.h @@ -42,6 +42,17 @@ #include "audio/hermite.h" #endif +#ifndef _WIN32 +#include // MAXPATHLEN +#endif + +#ifndef MAXPATHLEN +#ifdef PATH_MAX +#define MAXPATHLEN PATH_MAX +#else +#define MAXPATHLEN 512 +#endif +#endif #define MAX_PLAYERS 5 #define MAX_BINDS 34 // Needs to be increased every time there are new binds added. @@ -71,19 +82,19 @@ struct settings bool force_aspect; bool crop_overscan; float aspect_ratio; - char cg_shader_path[256]; - char bsnes_shader_path[256]; - char filter_path[256]; + char cg_shader_path[MAXPATHLEN]; + char bsnes_shader_path[MAXPATHLEN]; + char filter_path[MAXPATHLEN]; enum ssnes_shader_type shader_type; bool render_to_texture; double fbo_scale_x; double fbo_scale_y; - char second_pass_shader[256]; + char second_pass_shader[MAXPATHLEN]; bool second_pass_smooth; - char shader_dir[256]; + char shader_dir[MAXPATHLEN]; - char font_path[256]; + char font_path[MAXPATHLEN]; unsigned font_size; float msg_pos_x; float msg_pos_y; @@ -94,7 +105,7 @@ struct settings bool hires_record; bool post_filter_record; - char external_driver[256]; + char external_driver[MAXPATHLEN]; } video; struct @@ -104,13 +115,13 @@ struct settings unsigned out_rate; float in_rate; float rate_step; - char device[256]; + char device[MAXPATHLEN]; unsigned latency; bool sync; int src_quality; - char dsp_plugin[256]; - char external_driver[256]; + char dsp_plugin[MAXPATHLEN]; + char external_driver[MAXPATHLEN]; } audio; struct @@ -122,10 +133,10 @@ struct settings bool netplay_client_swap_input; } input; - char libsnes[256]; - char cheat_database[256]; + char libsnes[MAXPATHLEN]; + char cheat_database[MAXPATHLEN]; - char screenshot_directory[256]; + char screenshot_directory[MAXPATHLEN]; bool rewind_enable; unsigned rewind_buffer_size; @@ -164,29 +175,29 @@ struct global enum ssnes_game_type game_type; uint32_t cart_crc; - char gb_rom_path[256]; - char bsx_rom_path[256]; - char sufami_rom_path[2][256]; + char gb_rom_path[MAXPATHLEN]; + char bsx_rom_path[MAXPATHLEN]; + char sufami_rom_path[2][MAXPATHLEN]; bool has_set_save_path; bool has_set_state_path; #ifdef HAVE_CONFIGFILE - char config_path[256]; + char config_path[MAXPATHLEN]; #endif - char basename[256]; - char savefile_name_srm[256]; - char savefile_name_rtc[512]; // Make sure that fill_pathname has space. - char savefile_name_psrm[512]; - char savefile_name_asrm[512]; - char savefile_name_bsrm[512]; - char savestate_name[256]; - char xml_name[512]; + char basename[MAXPATHLEN]; + char savefile_name_srm[MAXPATHLEN]; + char savefile_name_rtc[MAXPATHLEN]; // Make sure that fill_pathname has space. + char savefile_name_psrm[MAXPATHLEN]; + char savefile_name_asrm[MAXPATHLEN]; + char savefile_name_bsrm[MAXPATHLEN]; + char savestate_name[MAXPATHLEN]; + char xml_name[MAXPATHLEN]; bool ups_pref; bool bps_pref; - char ups_name[512]; - char bps_name[512]; + char ups_name[MAXPATHLEN]; + char bps_name[MAXPATHLEN]; unsigned state_slot; @@ -237,7 +248,7 @@ struct global // Movie record support bsv_movie_t *bsv_movie; - char bsv_movie_path[256]; + char bsv_movie_path[MAXPATHLEN]; bool bsv_movie_end; bool bsv_movie_playback; @@ -249,7 +260,7 @@ struct global // Netplay. netplay_t *netplay; - char netplay_server[256]; + char netplay_server[MAXPATHLEN]; bool netplay_enable; bool netplay_is_client; unsigned netplay_sync_frames; @@ -258,7 +269,7 @@ struct global // FFmpeg record. #ifdef HAVE_FFMPEG ffemu_t *rec; - char record_path[256]; + char record_path[MAXPATHLEN]; bool recording; #endif diff --git a/ssnes.c b/ssnes.c index 0957b954b0..7f5236b1cb 100644 --- a/ssnes.c +++ b/ssnes.c @@ -329,24 +329,6 @@ static int16_t input_state(bool port, unsigned device, unsigned index, unsigned return res; } -static void fill_pathname(char *out_path, const char *in_path, const char *replace, size_t size) -{ - char tmp_path[strlen(in_path) + 1]; - strlcpy(tmp_path, in_path, sizeof(tmp_path)); - char *tok = NULL; - tok = strrchr(tmp_path, '.'); - if (tok != NULL) - *tok = '\0'; - assert(strlcpy(out_path, tmp_path, size) < size); - assert(strlcat(out_path, replace, size) < size); -} - -static void fill_pathname_noext(char *out_path, const char *in_path, const char *replace, size_t size) -{ - assert(strlcpy(out_path, in_path, size) < size); - assert(strlcat(out_path, replace, size) < size); -} - #ifdef _WIN32 #define SSNES_DEFAULT_CONF_PATH_STR "\n\t\tDefaults to ssnes.cfg in same directory as ssnes.exe." #elif defined(__APPLE__) @@ -438,12 +420,10 @@ static void print_help(void) static void set_basename(const char *path) { - char tmp[strlen(path) + 1]; - strlcpy(tmp, path, sizeof(tmp)); - char *dst = strrchr(tmp, '.'); + strlcpy(g_extern.basename, path, sizeof(g_extern.basename)); + char *dst = strrchr(g_extern.basename, '.'); if (dst) *dst = '\0'; - strlcpy(g_extern.basename, tmp, sizeof(g_extern.basename)); } static void parse_input(int argc, char *argv[]) @@ -686,23 +666,50 @@ static void parse_input(int argc, char *argv[]) SSNES_ERR("Could not open file: \"%s\"\n", argv[optind]); exit(1); } - // strl* would be nice :D + if (!g_extern.has_set_save_path) fill_pathname_noext(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm)); if (!g_extern.has_set_state_path) fill_pathname_noext(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name)); + + if (path_is_directory(g_extern.savefile_name_srm)) + { + fill_pathname_dir(g_extern.savefile_name_srm, g_extern.basename, ".srm", sizeof(g_extern.savefile_name_srm)); + SSNES_LOG("Redirecting save file to \"%s\".\n", g_extern.savefile_name_srm); + } + if (path_is_directory(g_extern.savestate_name)) + { + fill_pathname_dir(g_extern.savestate_name, g_extern.basename, ".state", sizeof(g_extern.savestate_name)); + SSNES_LOG("Redirecting save state to \"%s\".\n", g_extern.savestate_name); + } } - else if (strlen(g_extern.savefile_name_srm) == 0) + else // Read ROM from stdin. { - SSNES_ERR("Need savefile path argument (--save) when reading rom from stdin.\n"); - print_help(); - exit(1); - } - else if (strlen(g_extern.savestate_name) == 0) - { - SSNES_ERR("Need savestate path argument (--savefile) when reading rom from stdin.\n"); - print_help(); - exit(1); + if (strlen(g_extern.savefile_name_srm) == 0) + { + SSNES_ERR("Need savefile path argument (--save) when reading rom from stdin.\n"); + print_help(); + exit(1); + } + else if (strlen(g_extern.savestate_name) == 0) + { + SSNES_ERR("Need savestate path argument (--savestate) when reading rom from stdin.\n"); + print_help(); + exit(1); + } + + if (path_is_directory(g_extern.savefile_name_srm)) + { + SSNES_ERR("Cannot specify directory for path argument (--save) when reading from from stdin.\n"); + print_help(); + exit(1); + } + else if (path_is_directory(g_extern.savestate_name)) + { + SSNES_ERR("Cannot specify directory for path argument (--savestate) when reading from from stdin.\n"); + print_help(); + exit(1); + } } }