SCP_string os_get_config_path(const SCP_string& subpath) { // Make path platform compatible SCP_string compatiblePath(subpath); std::replace(compatiblePath.begin(), compatiblePath.end(), '/', DIR_SEPARATOR_CHAR); SCP_stringstream ss; if (Cmdline_portable_mode) { // Use the current directory ss << "." << DIR_SEPARATOR_CHAR << compatiblePath; return ss.str(); } // Avoid infinite recursion when checking legacy mode if (os_is_legacy_mode()) { #ifdef WIN32 // Use the current directory ss << "."; #else extern const char* Osreg_user_dir_legacy; // Use the home directory ss << getenv("HOME") << DIR_SEPARATOR_CHAR << Osreg_user_dir_legacy; #endif ss << DIR_SEPARATOR_CHAR << compatiblePath; return ss.str(); } ss << getPreferencesPath() << compatiblePath; return ss.str(); }
static SCP_string opengl_shader_get_header(shader_type type_id, int flags, bool has_geo_shader) { SCP_stringstream sflags; sflags << "#version " << GLSL_version << " core\n"; if (Detail.lighting < 3) { sflags << "#define FLAG_LIGHT_MODEL_BLINN_PHONG\n"; } if (has_geo_shader) { // If there is a geometry shader then we define a special preprocessor symbol to make writing shaders easier sflags << "#define HAS_GEOMETRY_SHADER\n"; } if (type_id == SDR_TYPE_POST_PROCESS_MAIN || type_id == SDR_TYPE_POST_PROCESS_LIGHTSHAFTS || type_id == SDR_TYPE_POST_PROCESS_FXAA) { // ignore looking for variants. main post process, lightshafts, and FXAA shaders need special headers to be hacked in opengl_post_shader_header(sflags, type_id, flags); } else { for (int i = 0; i < GL_num_shader_variants; ++i) { opengl_shader_variant_t &variant = GL_shader_variants[i]; if (type_id == variant.type_id && flags & variant.flag) { sflags << "#define " << variant.flag_text << "\n"; } } } return sflags.str(); }
static SCP_string opengl_shader_get_header(shader_type type_id, int flags, shader_stage stage) { SCP_stringstream sflags; sflags << "#version " << GLSL_version << " core\n"; if (GL_workaround_clipping_planes) { sflags << "#define WORKAROUND_CLIPPING_PLANES\n"; } if (type_id == SDR_TYPE_POST_PROCESS_MAIN || type_id == SDR_TYPE_POST_PROCESS_LIGHTSHAFTS || type_id == SDR_TYPE_POST_PROCESS_FXAA) { // ignore looking for variants. main post process, lightshafts, and FXAA shaders need special headers to be hacked in opengl_post_shader_header(sflags, type_id, flags); } else { for (int i = 0; i < GL_num_shader_variants; ++i) { opengl_shader_variant_t &variant = GL_shader_variants[i]; if (type_id == variant.type_id && flags & variant.flag) { sflags << "#define " << variant.flag_text << "\n"; } } } return sflags.str(); }
static SCP_string handle_includes(const char* filename, const SCP_string& original) { SCP_stringstream output; SCP_vector<SCP_string> include_stack; auto include_counter = 0; handle_includes_impl(include_stack, output, include_counter, filename, original); return output.str(); }
void AssertMessage(const char * text, const char * filename, int linenum, const char * format, ...) { // We only want to display the file name filename = clean_filename(filename); SCP_stringstream msgStream; msgStream << "Assert: \"" << text << "\"\n"; msgStream << "File: " << filename << "\n"; msgStream << "Line: " << linenum << "\n"; if (format != nullptr) { SCP_string buffer; va_list args; va_start(args, format); vsprintf(buffer, format, args); va_end(args); msgStream << buffer << "\n"; mprintf(("ASSERTION: \"%s\" at %s:%d\n %s\n", text, filename, linenum, buffer.c_str())); } else { // No additional message mprintf(("ASSERTION: \"%s\" at %s:%d\n", text, filename, linenum)); } if (running_unittests) { throw AssertException(msgStream.str()); } msgStream << "\n"; msgStream << dump_stacktrace(); SCP_string messageText = msgStream.str(); set_clipboard_text(messageText.c_str()); messageText = truncateLines(msgStream, Messagebox_lines); messageText += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; messageText += "\n\nUse Debug to break into Debugger, Exit will close the application.\n"; Error(messageText.c_str()); }
SCP_string format_version(int major, int minor, int build, int revision) { SCP_stringstream ss; ss << major << "." << minor << "." << build; if (revision != 0) { ss << "." << revision; } return ss.str(); }
void Error(const char * filename, int line, const char * format, ...) { SCP_string formatText; filename = clean_filename(filename); va_list args; va_start(args, format); vsprintf(formatText, format, args); va_end(args); SCP_stringstream messageStream; messageStream << "Error: " << formatText << "\n"; messageStream << "File: " << filename << "\n"; messageStream << "Line: " << line << "\n"; Error(messageStream.str().c_str()); }
SCP_string dump_stacktrace() { #if defined( SHOW_CALL_STACK ) && defined( PDB_DEBUGGING ) /* Dump the callstack */ SCP_DebugCallStack callStack; SCP_DumpStack(dynamic_cast< SCP_IDumpHandler* >(&callStack)); return callStack.DumpToString(); #elif defined( SHOW_CALL_STACK ) SCP_stringstream stream; DumpCallsStack(stream); return stream.str(); #else return "No stacktrace available!"; #endif }
void FrameProfiler::processFrame() { std::lock_guard<std::mutex> vectorGuard(_eventsMutex); std::sort(_bufferedEvents.begin(), _bufferedEvents.end(), event_sorter); SCP_stringstream stream; SCP_vector<profile_sample> samples; bool start_found = false; bool end_found = false; uint64_t start_profile_time = 0; uint64_t end_profile_time = 0; for (auto& event : _bufferedEvents) { if (!start_found) { start_profile_time = event.timestamp; start_found = true; } if (!end_found) { end_profile_time = event.timestamp; end_found = true; } switch (event.type) { case EventType::Begin: process_begin(samples, event); break; case EventType::End: process_end(samples, event); break; default: break; } } _bufferedEvents.clear(); dump_output(stream, start_profile_time, end_profile_time, samples); content = stream.str(); }
void HudGaugeThrottle::initMatchSpeedOffsets(int x, int y, bool custom) { Match_speed_offsets[0] = x; Match_speed_offsets[1] = y; Use_custom_match_speed = custom; font::FSFont* fsFont = font::get_font(font_num); if (fsFont->getType() == font::VFNT_FONT) { ubyte sc = lcl_get_font_index(font_num); // NOTE: default to normal m because either // a) the german font has no special m (its an a) // b) the font has no special characters if (sc == 0 || Lcl_gr) { Match_speed_icon = 'm'; } else { Match_speed_icon = sc + 3; } Match_speed_draw_background = false; } else { // Default version for other fonts, draw a black character on a rectangle Match_speed_icon = 'm'; Match_speed_draw_background = true; } SCP_stringstream stream; stream << static_cast<char>(Match_speed_icon); const SCP_string& iconStr = stream.str(); gr_get_string_size(&Match_speed_icon_width, nullptr, iconStr.c_str()); }
static SCP_string get_shader_header(shader_type type_id, int flags) { SCP_stringstream sflags; #ifdef __APPLE__ sflags << "#version 120\n"; sflags << "#define APPLE\n"; #endif if (type_id == SDR_TYPE_POST_PROCESS_MAIN || type_id == SDR_TYPE_POST_PROCESS_LIGHTSHAFTS || type_id == SDR_TYPE_POST_PROCESS_FXAA) { // ignore looking for variants. main post process, lightshafts, and FXAA shaders need special headers to be hacked in opengl_post_shader_header(sflags, type_id, flags); } else { for (int i = 0; i < GL_num_shader_variants; ++i) { opengl_shader_variant_t &variant = GL_shader_variants[i]; if (type_id == variant.type_id && flags & variant.flag) { sflags << "#define " << variant.flag_text << "\n"; } } } return sflags.str(); }
SCP_string dump_stacktrace() { #ifdef HAVE_EXECINFO_H // The following is adapted from here: https://panthema.net/2008/0901-stacktrace-demangled/ const int ADDR_SIZE = 64; void *addresses[ADDR_SIZE]; auto numstrings = backtrace(addresses, ADDR_SIZE); if (numstrings == 0) { return "No stacktrace available (possibly corrupt)"; } auto symbollist = backtrace_symbols(addresses, numstrings); if (symbollist == nullptr) { return "No stacktrace available (possibly corrupt)"; } // Demangle c++ function names to a more readable format using the ABI functions // TODO: Maybe add configure time checks to check if the required features are available SCP_stringstream stackstream; #ifdef HAVE_CXXAPI_H size_t funcnamesize = 256; char* funcname = reinterpret_cast<char*>(malloc(funcnamesize)); // iterate over the returned symbol lines. skip the first, it is the // address of this function. for (int i = 1; i < numstrings; i++) { char *begin_name = 0, *begin_offset = 0, *end_offset = 0; // find parentheses and +address offset surrounding the mangled name: // ./module(function+0x15c) [0x8048a6d] for (char *p = symbollist[i]; *p; ++p) { if (*p == '(') begin_name = p; else if (*p == '+') begin_offset = p; else if (*p == ')' && begin_offset) { end_offset = p; break; } } if (begin_name && begin_offset && end_offset && begin_name < begin_offset) { *begin_name++ = '\0'; *begin_offset++ = '\0'; *end_offset = '\0'; // mangled name is now in [begin_name, begin_offset) and caller // offset in [begin_offset, end_offset). now apply // __cxa_demangle(): int status; char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status); if (status == 0) { funcname = ret; // use possibly realloc()-ed string stackstream << " " << symbollist[i] << " : " << funcname << "+" << begin_offset << "\n"; } else { // demangling failed. Output function name as a C function with // no arguments. stackstream << " " << symbollist[i] << " : " << begin_name << "()+" << begin_offset << "\n"; } } else { // couldn't parse the line? print the whole line. stackstream << " " << symbollist[i] << "\n"; } } free(funcname); #else for (auto i = 0; i < numstrings; ++i) { stackstream << symbollist[i] << "\n"; } #endif free(symbollist); return stackstream.str(); #else return "No stacktrace available"; #endif }
void ReleaseWarning(const char* filename, int line, const char* format, ...) { Global_warning_count++; filename = clean_filename(filename); // output to the debug log before anything else (so that we have a complete record) SCP_string formatMessage; va_list args; va_start(args, format); vsprintf(formatMessage, format, args); va_end(args); SCP_string printfString = formatMessage; std::transform(printfString.begin(), printfString.end(), printfString.begin(), replaceNewline); mprintf(("WARNING: \"%s\" at %s:%d\n", printfString.c_str(), filename, line)); // now go for the additional popup window, if we want it ... if (Cmdline_noninteractive) { return; } if (running_unittests) { throw AssertException(printfString); } SCP_stringstream boxMsgStream; boxMsgStream << "Warning: " << formatMessage << "\n"; boxMsgStream << "File: " << filename << "\n"; boxMsgStream << "Line: " << line << "\n"; boxMsgStream << "\n"; boxMsgStream << dump_stacktrace(); set_clipboard_text(boxMsgStream.str().c_str()); SCP_string boxMessage = truncateLines(boxMsgStream, Messagebox_lines); boxMessage += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; boxMessage += "\n\nUse Debug to break into Debugger\n"; const SDL_MessageBoxButtonData buttons[] = { { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 2, "Exit" }, { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 1, "Continue" }, { /* .flags, .buttonid, .text */ 0, 0, "Debug" }, }; SDL_MessageBoxData boxData; memset(&boxData, 0, sizeof(boxData)); boxData.buttons = buttons; boxData.numbuttons = 3; boxData.colorScheme = nullptr; boxData.flags = SDL_MESSAGEBOX_WARNING; boxData.message = boxMessage.c_str(); boxData.title = "Warning!"; boxData.window = os::getSDLMainWindow(); gr_activate(0); int buttonId; if (SDL_ShowMessageBox(&boxData, &buttonId) < 0) { // Call failed exit(1); } switch (buttonId) { case 2: exit(1); case 0: Int3(); break; default: break; } gr_activate(1); }
void Error(const char* text) { mprintf(("\n%s\n", text)); if (Cmdline_noninteractive) { abort(); return; } if (running_unittests) { throw ErrorException(text); } SCP_stringstream messageStream; messageStream << text << "\n"; messageStream << dump_stacktrace(); SCP_string fullText = messageStream.str(); set_clipboard_text(fullText.c_str()); fullText = truncateLines(messageStream, Messagebox_lines); fullText += "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; fullText += "\n\nUse Debug to break into Debugger, Exit will close the application.\n"; const SDL_MessageBoxButtonData buttons[] = { { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 1, "Exit" }, { /* .flags, .buttonid, .text */ 0, 0, "Debug" }, }; SDL_MessageBoxData boxData; memset(&boxData, 0, sizeof(boxData)); boxData.buttons = buttons; boxData.numbuttons = 2; boxData.colorScheme = nullptr; boxData.flags = SDL_MESSAGEBOX_ERROR; boxData.message = text; boxData.title = "Error!"; boxData.window = os::getSDLMainWindow(); gr_activate(0); int buttonId; if (SDL_ShowMessageBox(&boxData, &buttonId) < 0) { // Call failed exit(1); } switch (buttonId) { case 1: exit(1); default: Int3(); break; } gr_activate(1); }
void LuaError(lua_State * L, const char * format, ...) { SCP_stringstream msgStream; //WMC - if format is set to NULL, assume this is acting as an //error handler for Lua. if (format == NULL) { msgStream << "LUA ERROR: " << lua_tostring(L, -1); lua_pop(L, -1); } else { SCP_string formatText; va_list args; va_start(args, format); vsprintf(formatText, format, args); va_end(args); msgStream << formatText; } msgStream << "\n"; msgStream << "\n"; msgStream << Separator; msgStream << "ADE Debug:"; msgStream << "\n"; msgStream << Separator; LuaDebugPrint(msgStream, Ade_debug_info); msgStream << Separator; msgStream << "\n"; msgStream << "\n"; msgStream << Separator; // Get the stack via the debug.traceback() function lua_getglobal(L, LUA_DBLIBNAME); if (!lua_isnil(L, -1)) { msgStream << "\n"; lua_getfield(L, -1, "traceback"); lua_remove(L, -2); if (lua_pcall(L, 0, 1, 0) != 0) msgStream << "Error while retrieving stack: " << lua_tostring(L, -1); else msgStream << lua_tostring(L, -1); lua_pop(L, 1); } msgStream << "\n"; msgStream << Separator; char stackText[1024]; stackText[0] = '\0'; scripting::ade_stackdump(L, stackText); msgStream << stackText; msgStream << "\n"; msgStream << Separator; mprintf(("Lua Error: %s\n", msgStream.str().c_str())); if (Cmdline_noninteractive) { exit(1); return; } if (running_unittests) { throw LuaErrorException(msgStream.str()); } set_clipboard_text(msgStream.str().c_str()); // truncate text auto truncatedText = truncateLines(msgStream, Messagebox_lines); SCP_stringstream boxTextStream; boxTextStream << truncatedText << "\n"; boxTextStream << "\n[ This info is in the clipboard so you can paste it somewhere now ]\n"; auto boxText = boxTextStream.str(); const SDL_MessageBoxButtonData buttons[] = { { SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, 2, "Exit" }, { SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, 1, "Continue" }, { /* .flags, .buttonid, .text */ 0, 0, "Debug" }, }; SDL_MessageBoxData boxData; memset(&boxData, 0, sizeof(boxData)); boxData.buttons = buttons; boxData.numbuttons = 3; boxData.colorScheme = nullptr; boxData.flags = SDL_MESSAGEBOX_ERROR; boxData.message = boxText.c_str(); boxData.title = "Error!"; boxData.window = os::getSDLMainWindow(); gr_activate(0); int buttonId; if (SDL_ShowMessageBox(&boxData, &buttonId) < 0) { // Call failed buttonId = 1; // No action } switch (buttonId) { case 2: exit(1); case 0: Int3(); break; default: break; } gr_activate(1); }