std::string PATH_INFO::find_translated_file( const std::string &pathid, const std::string &extension, const std::string &fallbackid ) { const std::string base_path = FILENAMES[pathid]; #if defined LOCALIZE && ! defined __CYGWIN__ std::string loc_name; if( get_option<std::string>( "USE_LANG" ).empty() ) { #if (defined _WIN32 || defined WINDOWS) loc_name = getLangFromLCID( GetUserDefaultLCID() ); if( !loc_name.empty() ) { const std::string local_path = base_path + loc_name + extension; if( file_exist( local_path ) ) { return local_path; } } #endif const char *v = setlocale( LC_ALL, NULL ); if( v != NULL ) { loc_name = v; } } else { loc_name = get_option<std::string>( "USE_LANG" ); } if( loc_name == "C" ) { loc_name = "en"; } if( !loc_name.empty() ) { const size_t dotpos = loc_name.find( '.' ); if( dotpos != std::string::npos ) { loc_name.erase( dotpos ); } // complete locale: en_NZ const std::string local_path = base_path + loc_name + extension; if( file_exist( local_path ) ) { return local_path; } const size_t p = loc_name.find( '_' ); if( p != std::string::npos ) { // only the first part: en const std::string local_path = base_path + loc_name.substr( 0, p ) + extension; if( file_exist( local_path ) ) { return local_path; } } } #endif (void) extension; return FILENAMES[fallbackid]; }
int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int argc = __argc; char **argv = __argv; #else int main(int argc, char *argv[]) { #endif int seed = time(NULL); bool verifyexit = false; bool check_mods = false; std::string dump; dump_mode dmode = dump_mode::TSV; std::vector<std::string> opts; std::string world; /** if set try to load first save in this world on startup */ // Set default file paths #ifdef PREFIX #define Q(STR) #STR #define QUOTE(STR) Q(STR) PATH_INFO::init_base_path(std::string(QUOTE(PREFIX))); #else PATH_INFO::init_base_path(""); #endif #if (defined USE_HOME_DIR || defined USE_XDG_DIR) PATH_INFO::init_user_dir(); #else PATH_INFO::init_user_dir("./"); #endif PATH_INFO::set_standard_filenames(); MAP_SHARING::setDefaults(); { const char *section_default = nullptr; const char *section_map_sharing = "Map sharing"; const char *section_user_directory = "User directories"; const std::array<arg_handler, 12> first_pass_arguments = {{ { "--seed", "<string of letters and or numbers>", "Sets the random number generator's seed value", section_default, [&seed](int num_args, const char **params) -> int { if (num_args < 1) return -1; const unsigned char *hash_input = (const unsigned char *) params[0]; seed = djb2_hash(hash_input); return 1; } }, { "--jsonverify", nullptr, "Checks the cdda json files", section_default, [&verifyexit](int, const char **) -> int { verifyexit = true; return 0; } }, { "--check-mods", "[mods...]", "Checks the json files belonging to cdda mods", section_default, [&check_mods,&opts]( int n, const char *params[] ) -> int { check_mods = true; test_mode = true; for( int i = 0; i < n; ++i ) { opts.emplace_back( params[ i ] ); } return 0; } }, { "--dump-stats", "<what> [mode = TSV] [opts...]", "Dumps item stats", section_default, [&dump,&dmode,&opts](int n, const char *params[]) -> int { if( n < 1 ) { return -1; } test_mode = true; dump = params[ 0 ]; for( int i = 2; i < n; ++i ) { opts.emplace_back( params[ i ] ); } if( n >= 2 ) { if( !strcmp( params[ 1 ], "TSV" ) ) { dmode = dump_mode::TSV; return 0; } else if( !strcmp( params[ 1 ], "HTML" ) ) { dmode = dump_mode::HTML; return 0; } else { return -1; } } return 0; } }, { "--world", "<name>", "Load world", section_default, [&world](int n, const char *params[]) -> int { if( n < 1 ) { return -1; } world = params[0]; return 1; } }, { "--basepath", "<path>", "Base path for all game data subdirectories", section_default, [](int num_args, const char **params) { if (num_args < 1) return -1; PATH_INFO::init_base_path(params[0]); PATH_INFO::set_standard_filenames(); return 1; } }, { "--shared", nullptr, "Activates the map-sharing mode", section_map_sharing, [](int, const char **) -> int { MAP_SHARING::setSharing(true); MAP_SHARING::setCompetitive(true); MAP_SHARING::setWorldmenu(false); return 0; } }, { "--username", "<name>", "Instructs map-sharing code to use this name for your character.", section_map_sharing, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; MAP_SHARING::setUsername(params[0]); return 1; } }, { "--addadmin", "<username>", "Instructs map-sharing code to use this name for your character and give you " "access to the cheat functions.", section_map_sharing, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; MAP_SHARING::addAdmin(params[0]); return 1; } }, { "--adddebugger", "<username>", "Informs map-sharing code that you're running inside a debugger", section_map_sharing, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; MAP_SHARING::addDebugger(params[0]); return 1; } }, { "--competitive", nullptr, "Instructs map-sharing code to disable access to the in-game cheat functions", section_map_sharing, [](int, const char **) -> int { MAP_SHARING::setCompetitive(true); return 0; } }, { "--userdir", "<path>", "Base path for user-overrides to files from the ./data directory and named below", section_user_directory, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::init_user_dir(params[0]); PATH_INFO::set_standard_filenames(); return 1; } } }}; // The following arguments are dependent on one or more of the previous flags and are run // in a second pass. const std::array<arg_handler, 9> second_pass_arguments = {{ { "--worldmenu", nullptr, "Enables the world menu in the map-sharing code", section_map_sharing, [](int, const char **) -> int { MAP_SHARING::setWorldmenu(true); return true; } }, { "--datadir", "<directory name>", "Sub directory from which game data is loaded", nullptr, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::update_pathname("datadir", params[0]); PATH_INFO::update_datadir(); return 1; } }, { "--savedir", "<directory name>", "Subdirectory for game saves", section_user_directory, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::update_pathname("savedir", params[0]); return 1; } }, { "--configdir", "<directory name>", "Subdirectory for game configuration", section_user_directory, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::update_pathname("config_dir", params[0]); PATH_INFO::update_config_dir(); return 1; } }, { "--memorialdir", "<directory name>", "Subdirectory for memorials", section_user_directory, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::update_pathname("memorialdir", params[0]); return 1; } }, { "--optionfile", "<filename>", "Name of the options file within the configdir", section_user_directory, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::update_pathname("options", params[0]); return 1; } }, { "--keymapfile", "<filename>", "Name of the keymap file within the configdir", section_user_directory, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::update_pathname("keymap", params[0]); return 1; } }, { "--autopickupfile", "<filename>", "Name of the autopickup options file within the configdir", nullptr, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::update_pathname("autopickup", params[0]); return 1; } }, { "--motdfile", "<filename>", "Name of the message of the day file within the motd directory", nullptr, [](int num_args, const char **params) -> int { if (num_args < 1) return -1; PATH_INFO::update_pathname("motd", params[0]); return 1; } }, }}; // Process CLI arguments. const size_t num_first_pass_arguments = sizeof(first_pass_arguments) / sizeof(first_pass_arguments[0]); const size_t num_second_pass_arguments = sizeof(second_pass_arguments) / sizeof(second_pass_arguments[0]); int saved_argc = --argc; // skip program name const char **saved_argv = (const char **)++argv; while (argc) { if(!strcmp(argv[0], "--help")) { printHelpMessage(first_pass_arguments.data(), num_first_pass_arguments, second_pass_arguments.data(), num_second_pass_arguments); return 0; } else { bool arg_handled = false; for (size_t i = 0; i < num_first_pass_arguments; ++i) { auto &arg_handler = first_pass_arguments[i]; if (!strcmp(argv[0], arg_handler.flag)) { argc--; argv++; int args_consumed = arg_handler.handler(argc, (const char **)argv); if (args_consumed < 0) { printf("Failed parsing parameter '%s'\n", *(argv - 1)); exit(1); } argc -= args_consumed; argv += args_consumed; arg_handled = true; break; } } // Skip other options. if (!arg_handled) { --argc; ++argv; } } } while (saved_argc) { bool arg_handled = false; for (size_t i = 0; i < num_second_pass_arguments; ++i) { auto &arg_handler = second_pass_arguments[i]; if (!strcmp(saved_argv[0], arg_handler.flag)) { --saved_argc; ++saved_argv; int args_consumed = arg_handler.handler(saved_argc, saved_argv); if (args_consumed < 0) { printf("Failed parsing parameter '%s'\n", *(argv - 1)); exit(1); } saved_argc -= args_consumed; saved_argv += args_consumed; arg_handled = true; break; } } // Ingore unknown options. if (!arg_handled) { --saved_argc; ++saved_argv; } } } if (!assure_dir_exist(FILENAMES["user_dir"].c_str())) { printf("Can't open or create %s. Check permissions.\n", FILENAMES["user_dir"].c_str()); exit(1); } setupDebug(); /** * OS X does not populate locale env vars correctly (they usually default to * "C") so don't bother trying to set the locale based on them. */ #if (!defined MACOSX) if (setlocale(LC_ALL, "") == NULL) { DebugLog(D_WARNING, D_MAIN) << "Error while setlocale(LC_ALL, '')."; } else { #endif try { std::locale::global( std::locale( "" ) ); } catch( const std::exception& ) { // if user default locale retrieval isn't implemented by system try{ // default to basic C locale std::locale::global( std::locale::classic() ); } catch( const std::exception &err ) { debugmsg( "%s", err.what() ); exit_handler(-999); } } #if (!defined MACOSX) } #endif get_options().init(); get_options().load(); set_language(); // in test mode don't initialize curses to avoid escape sequences being inserted into output stream if( !test_mode ) { try { catacurses::init_interface(); } catch( const std::exception &err ) { // can't use any curses function as it has not been initialized std::cerr << "Error while initializing the interface: " << err.what() << std::endl; DebugLog( D_ERROR, DC_ALL ) << "Error while initializing the interface: " << err.what() << "\n"; return 1; } } srand(seed); g = new game; // First load and initialize everything that does not // depend on the mods. try { g->load_static_data(); if (verifyexit) { exit_handler(0); } if( !dump.empty() ) { init_colors(); exit( g->dump_stats( dump, dmode, opts ) ? 0 : 1 ); } if( check_mods ) { init_colors(); loading_ui ui( false ); exit( g->check_mod_data( opts, ui ) && !test_dirty ? 0 : 1 ); } } catch( const std::exception &err ) { debugmsg( "%s", err.what() ); exit_handler(-999); } // Now we do the actual game. g->init_ui(); curs_set(0); // Invisible cursor here, because MAPBUFFER.load() is crash-prone #if (!(defined _WIN32 || defined WINDOWS)) struct sigaction sigIntHandler; sigIntHandler.sa_handler = exit_handler; sigemptyset(&sigIntHandler.sa_mask); sigIntHandler.sa_flags = 0; sigaction(SIGINT, &sigIntHandler, NULL); #endif #ifdef LOCALIZE std::string lang = ""; #if (defined _WIN32 || defined WINDOWS) lang = getLangFromLCID( GetUserDefaultLCID() ); #else const char *v = setlocale( LC_ALL, NULL ); if( v != NULL ) { lang = v; if( lang == "C" ) { lang = "en"; } } #endif if( get_option<std::string>( "USE_LANG" ).empty() && ( lang.empty() || !isValidLanguage( lang ) ) ) { select_language(); set_language(); } #endif while( true ) { if( !world.empty() ) { if( !g->load( world ) ) { break; } world.clear(); // ensure quit returns to opening screen } else { main_menu menu; if( !menu.opening_screen() ) { break; } } while( !g->do_turn() ); }; exit_handler(-999); return 0; }
void set_language() { std::string win_or_mac_lang; #if (defined _WIN32 || defined WINDOWS) win_or_mac_lang = getLangFromLCID( GetUserDefaultLCID() ); #endif #if (defined MACOSX) win_or_mac_lang = getOSXSystemLang(); #endif // Step 1. Setup locale settings. std::string lang_opt = get_option<std::string>( "USE_LANG" ).empty() ? win_or_mac_lang : get_option<std::string>( "USE_LANG" ); if( !lang_opt.empty() ) { // Not 'System Language' // Overwrite all system locale settings. Use CDDA settings. User wants this. #if (defined _WIN32 || defined WINDOWS) std::string lang_env = "LANGUAGE=" + lang_opt; if( _putenv( lang_env.c_str() ) != 0 ) { DebugLog( D_WARNING, D_MAIN ) << "Can't set 'LANGUAGE' environment variable"; } #else if( setenv( "LANGUAGE", lang_opt.c_str(), true ) != 0 ) { DebugLog( D_WARNING, D_MAIN ) << "Can't set 'LANGUAGE' environment variable"; } #endif else { auto env = getenv( "LANGUAGE" ); if( env != NULL ) { DebugLog( D_INFO, D_MAIN ) << "Language is set to: '" << env << '\''; } else { DebugLog( D_WARNING, D_MAIN ) << "Can't get 'LANGUAGE' environment variable"; } } } #if (defined _WIN32 || defined WINDOWS) // Use the ANSI code page 1252 to work around some language output bugs. if( setlocale( LC_ALL, ".1252" ) == NULL ) { DebugLog( D_WARNING, D_MAIN ) << "Error while setlocale(LC_ALL, '.1252')."; } #endif // Step 2. Bind to gettext domain. std::string locale_dir; #if defined __ANDROID__ // Since we're using libintl-lite instead of libintl on Android, we hack the locale_dir to point directly to the .mo file. // This is because of our hacky libintl-lite bindtextdomain() implementation. auto env = getenv( "LANGUAGE" ); locale_dir = std::string( FILENAMES["base_path"] + "lang/mo/" + ( env ? env : "none" ) + "/LC_MESSAGES/cataclysm-dda.mo" ); #elif (defined __linux__ || (defined MACOSX && !defined TILES)) if( !FILENAMES["base_path"].empty() ) { locale_dir = FILENAMES["base_path"] + "share/locale"; } else { locale_dir = "lang/mo"; } #else locale_dir = "lang/mo"; #endif const char *locale_dir_char = locale_dir.c_str(); bindtextdomain( "cataclysm-dda", locale_dir_char ); bind_textdomain_codeset( "cataclysm-dda", "UTF-8" ); textdomain( "cataclysm-dda" ); reload_names(); }