diff --git a/code/globalincs/memory/memory.h b/code/globalincs/memory/memory.h index a25c2974a58..f3b7214a336 100644 --- a/code/globalincs/memory/memory.h +++ b/code/globalincs/memory/memory.h @@ -4,8 +4,6 @@ #include #include -#include "globalincs/pstypes.h" - namespace memory { struct quiet_alloc_t { quiet_alloc_t(){} }; diff --git a/code/globalincs/memory/utils.h b/code/globalincs/memory/utils.h index adc3386b48b..967b81f2579 100644 --- a/code/globalincs/memory/utils.h +++ b/code/globalincs/memory/utils.h @@ -1,19 +1,18 @@ -#pragma once +#ifndef MEMORY_UTILS_H +#define MEMORY_UTILS_H #include -#include "globalincs/pstypes.h" - -inline char *vm_strndup(const char *ptr, size_t size) +inline char *vm_strndup(const char *ptr, size_t len) { - char *dst = (char *) vm_malloc(size + 1); + char *dst = static_cast(vm_malloc(len + 1)); if (!dst) - return NULL; + return nullptr; - std::strncpy(dst, ptr, size); + std::strncpy(dst, ptr, len); // make sure it has a NULL terminiator - dst[size] = '\0'; + dst[len] = '\0'; return dst; } @@ -24,3 +23,5 @@ inline char *vm_strdup(const char *ptr) return vm_strndup(ptr, len); } + +#endif // MEMORY_UTILS_H diff --git a/code/globalincs/toolchain/clang.h b/code/globalincs/toolchain/clang.h index 2f4ae40242c..1056c893bd2 100644 --- a/code/globalincs/toolchain/clang.h +++ b/code/globalincs/toolchain/clang.h @@ -21,6 +21,7 @@ #if defined(__clang__) #define SCP_FORMAT_STRING +// from gcc: Since non-static C++ methods have an implicit this argument, the arguments of such methods should be counted from two, not one, when giving values for string-index and first-to-check. #define SCP_FORMAT_STRING_ARGS(x,y) __attribute__((format(printf, x, y))) #define __UNUSED __attribute__((__unused__)) diff --git a/code/globalincs/toolchain/gcc.h b/code/globalincs/toolchain/gcc.h index 8e884653719..80c603ccd39 100644 --- a/code/globalincs/toolchain/gcc.h +++ b/code/globalincs/toolchain/gcc.h @@ -22,6 +22,7 @@ #if defined(__GNUC__) && !defined(__clang__) #define SCP_FORMAT_STRING +// from gcc: Since non-static C++ methods have an implicit this argument, the arguments of such methods should be counted from two, not one, when giving values for string-index and first-to-check. #define SCP_FORMAT_STRING_ARGS(x,y) __attribute__((format(printf, x, y))) #define __UNUSED __attribute__((__unused__)) diff --git a/code/globalincs/toolchain/mingw.h b/code/globalincs/toolchain/mingw.h index 5b7924b3dea..6f454689f47 100644 --- a/code/globalincs/toolchain/mingw.h +++ b/code/globalincs/toolchain/mingw.h @@ -23,6 +23,7 @@ #include #define SCP_FORMAT_STRING +// from gcc: Since non-static C++ methods have an implicit this argument, the arguments of such methods should be counted from two, not one, when giving values for string-index and first-to-check. #define SCP_FORMAT_STRING_ARGS(x,y) __attribute__((format(__MINGW_PRINTF_FORMAT, x, y))) #define __UNUSED __attribute__((__unused__)) diff --git a/code/graphics/2d.h b/code/graphics/2d.h index b701bdeefc6..6d12454a150 100644 --- a/code/graphics/2d.h +++ b/code/graphics/2d.h @@ -1043,13 +1043,17 @@ bool gr_resize_screen_posf(float *x, float *y, float *w = NULL, float *h = NULL, // Does formatted printing. This calls gr_string after formatting, // so if you don't need to format the string, then call gr_string // directly. -extern void gr_printf( int x, int y, const char * format, SCP_FORMAT_STRING ... ) SCP_FORMAT_STRING_ARGS(3, 4); +extern void gr_printf( int x, int y, SCP_FORMAT_STRING const char *format, ... ) SCP_FORMAT_STRING_ARGS(3, 4); +extern void gr_printf( int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ... ) SCP_FORMAT_STRING_ARGS(4, 5); // same as gr_printf but positions text correctly in menus -extern void gr_printf_menu( int x, int y, const char * format, SCP_FORMAT_STRING ... ) SCP_FORMAT_STRING_ARGS(3, 4); +extern void gr_printf_menu( int x, int y, SCP_FORMAT_STRING const char *format, ... ) SCP_FORMAT_STRING_ARGS(3, 4); +extern void gr_printf_menu( int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ... ) SCP_FORMAT_STRING_ARGS(4, 5); // same as gr_printf_menu but accounts for menu zooming -extern void gr_printf_menu_zoomed( int x, int y, const char * format, SCP_FORMAT_STRING ... ) SCP_FORMAT_STRING_ARGS(3, 4); +extern void gr_printf_menu_zoomed( int x, int y, SCP_FORMAT_STRING const char *format, ... ) SCP_FORMAT_STRING_ARGS(3, 4); +extern void gr_printf_menu_zoomed( int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ... ) SCP_FORMAT_STRING_ARGS(4, 5); // same as gr_printf but doesn't resize for non-standard resolutions -extern void gr_printf_no_resize( int x, int y, const char * format, SCP_FORMAT_STRING ... ) SCP_FORMAT_STRING_ARGS(3, 4); +extern void gr_printf_no_resize( int x, int y, SCP_FORMAT_STRING const char *format, ... ) SCP_FORMAT_STRING_ARGS(3, 4); +extern void gr_printf_no_resize( int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ... ) SCP_FORMAT_STRING_ARGS(4, 5); // Returns the size of the string in pixels in w and h extern void gr_get_string_size( int *w, int *h, const char * text, float scaleMultiplier = 1.0f, size_t len = std::string::npos); diff --git a/code/graphics/paths/nanovg/stb_truetype.h b/code/graphics/paths/nanovg/stb_truetype.h index be7315e4a0d..71250dd8f41 100644 --- a/code/graphics/paths/nanovg/stb_truetype.h +++ b/code/graphics/paths/nanovg/stb_truetype.h @@ -407,6 +407,7 @@ int main(int arg, char **argv) } #endif +#include "globalincs/toolchain.h" ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -432,7 +433,7 @@ typedef char stbtt__check_size32[sizeof(stbtt_int32) == 4 ? 1 : -1]; typedef char stbtt__check_size16[sizeof(stbtt_int16) == 2 ? 1 : -1]; // Function from NanoVGRenderer.cpp to provide log printing capabilities here. -extern void nvgOldCPrintf(const char *string, ...); +extern void nvgOldCPrintf(SCP_FORMAT_STRING const char *string, ...) SCP_FORMAT_STRING_ARGS(2, 3); // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h #ifndef STBTT_ifloor #include diff --git a/code/graphics/software/font.cpp b/code/graphics/software/font.cpp index 1d8b542a38d..f4b8bfdd085 100644 --- a/code/graphics/software/font.cpp +++ b/code/graphics/software/font.cpp @@ -803,7 +803,7 @@ void gr_string_win(int x, int y, char *s) char grx_printf_text[2048]; -void gr_printf(int x, int y, const char * format, ...) +void gr_printf(int x, int y, SCP_FORMAT_STRING const char *format, ... ) { va_list args; @@ -817,7 +817,21 @@ void gr_printf(int x, int y, const char * format, ...) gr_string(x, y, grx_printf_text); } -void gr_printf_menu(int x, int y, const char * format, ...) +void gr_printf(int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ... ) +{ + va_list args; + + if (!FontManager::isReady()) return; + + va_start(args, format); + vsnprintf(grx_printf_text, len+1, format, args); + va_end(args); + grx_printf_text[len] = '\0'; + + gr_string(x, y, grx_printf_text, GR_RESIZE_FULL, 1.0f, len); +} + +void gr_printf_menu(int x, int y, SCP_FORMAT_STRING const char *format, ... ) { va_list args; @@ -831,7 +845,21 @@ void gr_printf_menu(int x, int y, const char * format, ...) gr_string(x, y, grx_printf_text, GR_RESIZE_MENU); } -void gr_printf_menu_zoomed(int x, int y, const char * format, ...) +void gr_printf_menu(int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ... ) +{ + va_list args; + + if (!FontManager::isReady()) return; + + va_start(args, format); + vsnprintf(grx_printf_text, len+1, format, args); + va_end(args); + grx_printf_text[len] = '\0'; + + gr_string(x, y, grx_printf_text, GR_RESIZE_MENU, 1.0f, len); +} + +void gr_printf_menu_zoomed(int x, int y, SCP_FORMAT_STRING const char *format, ... ) { va_list args; @@ -845,7 +873,21 @@ void gr_printf_menu_zoomed(int x, int y, const char * format, ...) gr_string(x, y, grx_printf_text, GR_RESIZE_MENU_ZOOMED); } -void gr_printf_no_resize(int x, int y, const char * format, ...) +void gr_printf_menu_zoomed(int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ... ) +{ + va_list args; + + if (!FontManager::isReady()) return; + + va_start(args, format); + vsnprintf(grx_printf_text, len+1, format, args); + va_end(args); + grx_printf_text[len] = '\0'; + + gr_string(x, y, grx_printf_text, GR_RESIZE_MENU_ZOOMED, 1.0f, len); +} + +void gr_printf_no_resize(int x, int y, SCP_FORMAT_STRING const char *format, ... ) { va_list args; @@ -858,3 +900,17 @@ void gr_printf_no_resize(int x, int y, const char * format, ...) gr_string(x, y, grx_printf_text, GR_RESIZE_NONE); } + +void gr_printf_no_resize(int x, int y, size_t len, SCP_FORMAT_STRING const char *format, ... ) +{ + va_list args; + + if (!FontManager::isReady()) return; + + va_start(args, format); + vsnprintf(grx_printf_text, len+1, format, args); + va_end(args); + grx_printf_text[len] = '\0'; + + gr_string(x, y, grx_printf_text, GR_RESIZE_NONE, 1.0f, len); +} diff --git a/code/hud/hud.cpp b/code/hud/hud.cpp index ee3da79cfbb..2761a3e1545 100644 --- a/code/hud/hud.cpp +++ b/code/hud/hud.cpp @@ -896,7 +896,12 @@ void HudGauge::render(float /*frametime*/, bool config) } } -void HudGauge::renderString(int x, int y, const char *str, float scale, bool config) +void HudGauge::renderString(int x, int y, const char *str, float scale, bool config) const +{ + renderString(x, y, str, std::string::npos, scale, config); +} + +void HudGauge::renderString(int x, int y, const char *str, size_t len, float scale, bool config) const { int nx = 0, ny = 0; int resize = GR_RESIZE_FULL; @@ -923,15 +928,20 @@ void HudGauge::renderString(int x, int y, const char *str, float scale, bool con if (HUD_shadows) { color cur = gr_screen.current_color; gr_set_color_fast(&Color_black); - gr_string(x + nx + 1, y + ny + 1, str, resize, scale); + gr_string(x + nx + 1, y + ny + 1, str, resize, scale, len); gr_set_color_fast(&cur); } - gr_string(x + nx, y + ny, str, resize, scale); + gr_string(x + nx, y + ny, str, resize, scale, len); gr_reset_screen_scale(); } -void HudGauge::renderString(int x, int y, int gauge_id, const char *str, float scale, bool config) +void HudGauge::renderString(int x, int y, int gauge_id, const char *str, float scale, bool config) const +{ + renderString(x, y, gauge_id, str, std::string::npos, scale, config); +} + +void HudGauge::renderString(int x, int y, int gauge_id, const char *str, size_t len, float scale, bool config) const { int nx = 0, ny = 0; int resize = GR_RESIZE_FULL; @@ -960,32 +970,37 @@ void HudGauge::renderString(int x, int y, int gauge_id, const char *str, float s if (HUD_shadows) { color cur = gr_screen.current_color; gr_set_color_fast(&Color_black); - emp_hud_string(x + nx + 1, y + ny + 1, gauge_id, str, resize, scale); + emp_hud_string(x + nx + 1, y + ny + 1, gauge_id, str, len, resize, scale); gr_set_color_fast(&cur); } - emp_hud_string(x + nx, y + ny, gauge_id, str, resize, scale); + emp_hud_string(x + nx, y + ny, gauge_id, str, len, resize, scale); } else { if (HUD_shadows) { color cur = gr_screen.current_color; gr_set_color_fast(&Color_black); - gr_string(x + nx + 1, y + ny + 1, str, resize, scale); + gr_string(x + nx + 1, y + ny + 1, str, resize, scale, len); gr_set_color_fast(&cur); } - gr_string(x + nx, y + ny, str, resize, scale); + gr_string(x + nx, y + ny, str, resize, scale, len); } gr_reset_screen_scale(); } -void HudGauge::renderStringAlignCenter(int x, int y, int area_width, const char *s, float scale, bool config) +void HudGauge::renderStringAlignCenter(int x, int y, int area_width, const char *s, float scale, bool config) const +{ + renderStringAlignCenter(x, y, area_width, s, std::string::npos, scale, config); +} + +void HudGauge::renderStringAlignCenter(int x, int y, int area_width, const char *s, size_t len, float scale, bool config) const { int w, h; - gr_get_string_size(&w, &h, s, scale); - renderString(x + ((area_width - w) / 2), y, s, scale, config); + gr_get_string_size(&w, &h, s, scale, len); + renderString(x + ((area_width - w) / 2), y, s, len, scale, config); } -void HudGauge::renderPrintf(int x, int y, float scale, bool config, const char* format, ...) +void HudGauge::renderPrintf(int x, int y, float scale, bool config, SCP_FORMAT_STRING const char* format, ...) const { SCP_string tmp; va_list args; @@ -998,7 +1013,7 @@ void HudGauge::renderPrintf(int x, int y, float scale, bool config, const char* renderString(x, y, tmp.c_str(), scale, config); } -void HudGauge::renderPrintfWithGauge(int x, int y, int gauge_id, float scale, bool config, const char* format, ...) +void HudGauge::renderPrintfWithGauge(int x, int y, int gauge_id, float scale, bool config, SCP_FORMAT_STRING const char* format, ...) const { SCP_string tmp; va_list args; diff --git a/code/hud/hud.h b/code/hud/hud.h index ccefec7d3fa..9c8979e89d9 100644 --- a/code/hud/hud.h +++ b/code/hud/hud.h @@ -366,11 +366,14 @@ class HudGauge void renderBitmap(int frame, int x, int y, float scale = 1.0f, bool config = false) const; void renderBitmapColor(int frame, int x, int y, float scale = 1.0f, bool config = false) const; void renderBitmapEx(int frame, int x, int y, int w, int h, int sx, int sy, float scale = 1.0f, bool config = false) const; - void renderString(int x, int y, const char *str, float scale = 1.0f, bool config = false); - void renderString(int x, int y, int gauge_id, const char *str, float scale = 1.0f, bool config = false); - void renderStringAlignCenter(int x, int y, int area_width, const char *s, float scale = 1.0f, bool config = false); - void renderPrintf(int x, int y, float scale, bool config, SCP_FORMAT_STRING const char* format, ...) SCP_FORMAT_STRING_ARGS(6, 7); - void renderPrintfWithGauge(int x, int y, int gauge_id, float scale, bool config, SCP_FORMAT_STRING const char* format, ...) SCP_FORMAT_STRING_ARGS(7, 8); + void renderString(int x, int y, const char *str, float scale = 1.0f, bool config = false) const; + void renderString(int x, int y, const char *str, size_t len, float scale = 1.0f, bool config = false) const; + void renderString(int x, int y, int gauge_id, const char *str, float scale = 1.0f, bool config = false) const; + void renderString(int x, int y, int gauge_id, const char *str, size_t len, float scale = 1.0f, bool config = false) const; + void renderStringAlignCenter(int x, int y, int area_width, const char *s, float scale = 1.0f, bool config = false) const; + void renderStringAlignCenter(int x, int y, int area_width, const char *s, size_t len, float scale = 1.0f, bool config = false) const; + void renderPrintf(int x, int y, float scale, bool config, SCP_FORMAT_STRING const char* format, ...) const SCP_FORMAT_STRING_ARGS(6, 7); + void renderPrintfWithGauge(int x, int y, int gauge_id, float scale, bool config, SCP_FORMAT_STRING const char* format, ...) const SCP_FORMAT_STRING_ARGS(7, 8); void renderLine(int x1, int y1, int x2, int y2, bool config = false) const; void renderGradientLine(int x1, int y1, int x2, int y2, bool config = false) const; void renderRect(int x, int y, int w, int h, bool config = false) const; diff --git a/code/hud/hudmessage.cpp b/code/hud/hudmessage.cpp index 348b0a207d3..4cbaac87c6c 100644 --- a/code/hud/hudmessage.cpp +++ b/code/hud/hudmessage.cpp @@ -331,15 +331,9 @@ void HudGaugeMessages::processMessageBuffer() void HudGaugeMessages::addPending(const char *text, int source, int x) { - Assert(text != NULL); + Assert(text != nullptr); - HUD_message_data new_message; - - new_message.text = text; - new_message.source = source; - new_message.x = x; - - pending_messages.push(new_message); + pending_messages.emplace(text, source, x); } void HudGaugeMessages::scrollMessages() @@ -484,7 +478,7 @@ void HudGaugeMessages::render(float /*frametime*/, bool config) } // Similar to HUD printf, but shows only one message at a time, at a fixed location. -void HUD_fixed_printf(float duration, color col, const char *format, ...) +void HUD_fixed_printf(float duration, color col, SCP_FORMAT_STRING const char *format, ...) { va_list args; @@ -525,8 +519,7 @@ int HUD_source_get_team(int source) return source - HUD_SOURCE_TEAM_OFFSET; } - -void HUD_printf(const char *format, ...) +void HUD_printf(SCP_FORMAT_STRING const char *format, ...) { va_list args; SCP_string tmp; @@ -551,7 +544,7 @@ void HUD_printf(const char *format, ...) // message on the HUD. Text is split into multiple lines if width exceeds msg display area // width. 'source' is used to indicate who send the message, and is used to color code text. // -void HUD_sourced_printf(int source, const char *format, ...) +void HUD_sourced_printf(int source, SCP_FORMAT_STRING const char *format, ...) { va_list args; SCP_string tmp; @@ -579,13 +572,7 @@ void hud_sourced_print(int source, const SCP_string &msg) // add message to the scrollback log first hud_add_msg_to_scrollback(msg.c_str(), source, Missiontime); - HUD_message_data new_msg; - - new_msg.text = msg; - new_msg.source = source; - new_msg.x = 0; - - HUD_msg_buffer.push_back(new_msg); + HUD_msg_buffer.emplace_back(msg, source, 0); // Invoke the scripting hook if (OnHudMessageReceivedHook->isActive()) { @@ -604,13 +591,7 @@ void hud_sourced_print(int source, const char *msg) // add message to the scrollback log first hud_add_msg_to_scrollback(msg, source, Missiontime); - HUD_message_data new_msg; - - new_msg.text = SCP_string(msg); - new_msg.source = source; - new_msg.x = 0; - - HUD_msg_buffer.push_back(new_msg); + HUD_msg_buffer.emplace_back(msg, source, 0); // Invoke the scripting hook if (OnHudMessageReceivedHook->isActive()) { @@ -663,10 +644,7 @@ void hud_add_msg_to_scrollback(const char *text, int source, int t) } // create the new node for the vector - line_node newLine = {t, The_mission.HUD_timer_padding, source, 0, 1, w, ""}; - newLine.text = text; - - Msg_scrollback_vec.push_back(newLine); + Msg_scrollback_vec.emplace_back(t, The_mission.HUD_timer_padding, source, 0, 1, w, text); } // how many lines to skip diff --git a/code/hud/hudmessage.h b/code/hud/hudmessage.h index ebfbef29d46..6ce2cdfb053 100644 --- a/code/hud/hudmessage.h +++ b/code/hud/hudmessage.h @@ -30,13 +30,20 @@ #define HUD_SOURCE_TEAM_OFFSET 8 // must be higher than any previous hud source -typedef struct HUD_message_data { +struct HUD_message_data +{ SCP_string text; int source; // where this message came from so we can color code it int x; -} HUD_message_data; -typedef struct line_node { + HUD_message_data() = default; + HUD_message_data(SCP_string _text, int _source, int _x) + : text(std::move(_text)), source(_source), x(_x) + {} +}; + +struct line_node +{ fix time; // timestamp when message was added int timer_padding; // the mission timer padding, in seconds, at the time the message was added int source; // who/what the source of the message was (for color coding) @@ -44,7 +51,11 @@ typedef struct line_node { int y; int underline_width; SCP_string text; -} line_node; + + line_node(fix _time, int _timer_padding, int _source, int _x, int _y, int _underline_width, SCP_string _text) + : time(_time), timer_padding(_timer_padding), source(_source), x(_x), y(_y), underline_width(_underline_width), text(std::move(_text)) + {} +}; extern SCP_vector Msg_scrollback_vec; diff --git a/code/weapon/emp.cpp b/code/weapon/emp.cpp index 32fbf1fb887..36f406a156f 100644 --- a/code/weapon/emp.cpp +++ b/code/weapon/emp.cpp @@ -78,7 +78,7 @@ char Emp_random_char[NUM_RANDOM_CHARS] = // // maybe reformat a string -void emp_maybe_reformat_text(char *text, int max_len, int gauge_id); +void emp_maybe_reformat_text(char *text, size_t max_len, int gauge_id); // randomize the chars in a string void emp_randomize_chars(char *str); @@ -487,7 +487,7 @@ int emp_should_blit_gauge() } // emp hud string -void emp_hud_string(int x, int y, int gauge_id, const char *str, int resize_mode, float scale) +void emp_hud_string(int x, int y, int gauge_id, const char *str, size_t len, int resize_mode, float scale) { // maybe bail if (!*str) @@ -495,25 +495,28 @@ void emp_hud_string(int x, int y, int gauge_id, const char *str, int resize_mode // if the emp effect is not active, don't even bother messing with the text if(emp_active_local()){ + auto tmp_len = std::min(len, i2sz(255)); + // use a copied string rather than the original char tmp[256] = ""; - strcpy_s(tmp, str); + strncpy(tmp, str, tmp_len); + tmp[tmp_len] = '\0'; - emp_maybe_reformat_text(tmp, 256, gauge_id); + emp_maybe_reformat_text(tmp, tmp_len, gauge_id); // jitter the coords emp_hud_jitter(&x, &y); // print the string out - gr_string(x, y, tmp, resize_mode, scale); + gr_string(x, y, tmp, resize_mode, scale, len); } else { // print the original string out - gr_string(x, y, str, resize_mode, scale); + gr_string(x, y, str, resize_mode, scale, len); } } // maybe reformat a string -void emp_maybe_reformat_text(char *text, int /*max_len*/, int gauge_id) +void emp_maybe_reformat_text(char *text, size_t /*max_len*/, int gauge_id) { wacky_text *wt; diff --git a/code/weapon/emp.h b/code/weapon/emp.h index 71c48d44d0d..6af24faf3fe 100644 --- a/code/weapon/emp.h +++ b/code/weapon/emp.h @@ -103,7 +103,7 @@ void emp_process_local(); int emp_should_blit_gauge(); // emp hud string -void emp_hud_string(int x, int y, int gauge_id, const char *str, int resize_mode, float scale = 1.0f); +void emp_hud_string(int x, int y, int gauge_id, const char *str, size_t len, int resize_mode, float scale = 1.0f); // throw some jitter into HUD x and y coords void emp_hud_jitter(int *x, int *y); diff --git a/qtfred/src/mission/Editor.h b/qtfred/src/mission/Editor.h index 463fdec0e3a..e6c4e468013 100644 --- a/qtfred/src/mission/Editor.h +++ b/qtfred/src/mission/Editor.h @@ -314,8 +314,8 @@ class Editor : public QObject { int global_error_check_impl(); - int error(SCP_FORMAT_STRING const char* msg, ...) SCP_FORMAT_STRING_ARGS(2, 3); - int internal_error(SCP_FORMAT_STRING const char* msg, ...) SCP_FORMAT_STRING_ARGS(2, 3); + int error(SCP_FORMAT_STRING const char* msg, ...) SCP_FORMAT_STRING_ARGS(1, 2); + int internal_error(SCP_FORMAT_STRING const char* msg, ...) SCP_FORMAT_STRING_ARGS(1, 2); int fred_check_sexp(int sexp, int type, const char* location, ...);