/* =============== Q_scnprintf Returns number of characters actually written into the buffer, excluding trailing '\0'. If buffer size is 0, this function does nothing and returns 0. =============== */ size_t Q_scnprintf( char *dest, size_t size, const char *fmt, ... ) { va_list argptr; size_t ret; va_start( argptr, fmt ); ret = Q_vscnprintf( dest, size, fmt, argptr ); va_end( argptr ); return ret; }
/* ============= Com_Error Both client and server can use this, and it will do the apropriate things. ============= */ void Com_Error(error_type_t code, const char *fmt, ...) { char msg[MAXERRORMSG]; va_list argptr; size_t len; // may not be entered recursively if (com_errorEntered) { #ifdef _DEBUG if (com_debug_break && com_debug_break->integer) { Sys_DebugBreak(); } #endif Sys_Error("recursive error after: %s", com_errorMsg); } com_errorEntered = qtrue; va_start(argptr, fmt); len = Q_vscnprintf(msg, sizeof(msg), fmt, argptr); va_end(argptr); // save error msg // can't print into it directly since it may // overlap with one of the arguments! memcpy(com_errorMsg, msg, len + 1); // fix up drity message buffers MSG_Init(); // abort any console redirects Com_AbortRedirect(); // reset Com_Printf recursion level com_printEntered = 0; X86_POP_FPCW; if (code == ERR_DISCONNECT || code == ERR_RECONNECT) { Com_WPrintf("%s\n", com_errorMsg); SV_Shutdown(va("Server was killed: %s\n", com_errorMsg), code); CL_Disconnect(code); goto abort; } #ifdef _DEBUG if (com_debug_break && com_debug_break->integer) { Sys_DebugBreak(); } #endif // make otherwise non-fatal errors fatal if (com_fatal_error && com_fatal_error->integer) { code = ERR_FATAL; } if (code == ERR_DROP) { Com_EPrintf("********************\n" "ERROR: %s\n" "********************\n", com_errorMsg); SV_Shutdown(va("Server crashed: %s\n", com_errorMsg), ERR_DROP); CL_Disconnect(ERR_DROP); goto abort; } if (com_logFile) { FS_FPrintf(com_logFile, "FATAL: %s\n", com_errorMsg); } SV_Shutdown(va("Server fatal crashed: %s\n", com_errorMsg), ERR_FATAL); CL_Shutdown(); NET_Shutdown(); logfile_close(); FS_Shutdown(); Sys_Error("%s", com_errorMsg); // doesn't get there abort: if (com_logFile) { FS_Flush(com_logFile); } com_errorEntered = qfalse; longjmp(abortframe, -1); }
/* ============= Com_Printf Both client and server can use this, and it will output to the apropriate place. ============= */ void Com_LPrintf(print_type_t type, const char *fmt, ...) { va_list argptr; char msg[MAXPRINTMSG]; size_t len; // may be entered recursively only once if (com_printEntered >= 2) { return; } com_printEntered++; va_start(argptr, fmt); len = Q_vscnprintf(msg, sizeof(msg), fmt, argptr); va_end(argptr); if (type == PRINT_ERROR && !com_errorEntered && len) { size_t errlen = len; if (errlen >= sizeof(com_errorMsg)) { errlen = sizeof(com_errorMsg) - 1; } // save error msg memcpy(com_errorMsg, msg, errlen); com_errorMsg[errlen] = 0; // strip trailing '\n' if (com_errorMsg[errlen - 1] == '\n') { com_errorMsg[errlen - 1] = 0; } } if (rd_target) { Com_Redirect(msg, len); } else { switch (type) { case PRINT_TALK: Com_SetColor(COLOR_ALT); break; case PRINT_DEVELOPER: Com_SetColor(COLOR_BLUE); break; case PRINT_WARNING: Com_SetColor(COLOR_YELLOW); break; case PRINT_ERROR: Com_SetColor(COLOR_RED); break; case PRINT_NOTICE: Com_SetColor(COLOR_CYAN); break; default: break; } // graphical console Con_Print(msg); // debugging console Sys_ConsoleOutput(msg); // remote console //SV_ConsoleOutput(msg); // logfile if (com_logFile) { logfile_write(type, msg); } if (type) { Com_SetColor(COLOR_NONE); } } com_printEntered--; }