Skip to content

Commit

Permalink
cmdinterface: Fix handling of extremely long lines
Browse files Browse the repository at this point in the history
  • Loading branch information
past-due committed Sep 10, 2023
1 parent 2f8f091 commit 668e81b
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 24 deletions.
20 changes: 7 additions & 13 deletions src/gamehistorylogger.cpp
Expand Up @@ -367,7 +367,7 @@ void GameStoryLogger::logGameFrame()
// output frame
auto reportJSON = genFrameReport(gameFrames.back(), outputKey, outputNaming);
std::string reportJSONStr = std::string("__REPORT__") + reportJSON.dump(-1, ' ', false, nlohmann::ordered_json::error_handler_t::replace) + "__ENDREPORT__";
outputLine(reportJSONStr);
outputLine(std::move(reportJSONStr));
}
}

Expand Down Expand Up @@ -402,7 +402,7 @@ void GameStoryLogger::logDebugModeChange(bool enabled)
if (outputModes.anyEnabled())
{
std::string reportJSONStr = std::string("__DEBUGMODE__") + ((enabled) ? "true" : "false") + "__ENDDEBUGMODE__";
outputLine(reportJSONStr);
outputLine(std::move(reportJSONStr));
}
}

Expand All @@ -421,7 +421,7 @@ void GameStoryLogger::logGameOver()
bool hitTimeout = (game.gameTimeLimitMinutes > 0) ? (gameTime >= (game.gameTimeLimitMinutes * 60 * 1000)) : false;
auto reportJSON = genEndOfGameReport(outputKey, outputNaming, hitTimeout);
std::string reportJSONStr = std::string("__REPORTextended__") + reportJSON.dump(-1, ' ', false, nlohmann::ordered_json::error_handler_t::replace) + "__ENDREPORTextended__";
outputLine(reportJSONStr);
outputLine(std::move(reportJSONStr));
}

if (fileHandle)
Expand Down Expand Up @@ -643,30 +643,24 @@ inline void from_json(const nlohmann::json& j, GameStoryLogger::DebugModeEvent&
p.gameTime = j.at("gameTime").get<uint32_t>();
}

void GameStoryLogger::outputLine(const std::string &line)
void GameStoryLogger::outputLine(std::string &&line)
{
line.append("\n");
if (outputModes.cmdInterface)
{
wz_command_interface_output("%s\n", line.c_str());
wz_command_interface_output_str(line.c_str());
}
if (outputModes.logFile)
{
if (fileHandle)
{
if (WZ_PHYSFS_writeBytes(fileHandle, line.c_str(), line.size()) != line.size())
{
// Failed to write data to file
// Failed to write line to file
debug(LOG_ERROR, "Could not write to output file; PHYSFS error: %s", WZ_PHYSFS_getLastError());
PHYSFS_close(fileHandle);
fileHandle = nullptr;
}
if (WZ_PHYSFS_writeBytes(fileHandle, "\n", 1) != 1)
{
// Failed to write newline to file
debug(LOG_ERROR, "Could not write newline to output file; PHYSFS error: %s", WZ_PHYSFS_getLastError());
PHYSFS_close(fileHandle);
fileHandle = nullptr;
}
PHYSFS_flush(fileHandle);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/gamehistorylogger.h
Expand Up @@ -150,7 +150,7 @@ class GameStoryLogger
nlohmann::json genEndOfGameReport(OutputKey key, OutputNaming naming, bool timeout) const;
std::string getLogOutputFilename() const;

void outputLine(const std::string& line);
void outputLine(std::string&& line);

private:
OutputModes outputModes;
Expand Down
60 changes: 50 additions & 10 deletions src/stdinreader.cpp
Expand Up @@ -1097,38 +1097,78 @@ bool wz_command_interface_enabled()
return wz_command_interface() != WZ_Command_Interface::None;
}

void wz_command_interface_output(const char *str, ...)
void wz_command_interface_output_str(const char *str)
{
if (wz_command_interface() == WZ_Command_Interface::None)
{
return;
}
va_list ap;
static char outputBuffer[maxReserveMessageBufferSize];
va_start(ap, str);
vssprintf(outputBuffer, str, ap);
va_end(ap);

size_t outputBufferLen = strlen(outputBuffer);
if (outputBufferLen == 0)
size_t bufferLen = strlen(str);
if (bufferLen == 0)
{
return;
}

if (wz_command_interface() == WZ_Command_Interface::StdIn_Interface)
{
fwrite(outputBuffer, sizeof(char), outputBufferLen, stderr);
fwrite(str, sizeof(char), bufferLen, stderr);
fflush(stderr);
}
else
{
latestWriteBuffer.insert(latestWriteBuffer.end(), outputBuffer, outputBuffer + outputBufferLen);
latestWriteBuffer.insert(latestWriteBuffer.end(), str, str + bufferLen);
cmdInterfaceOutputQueue->enqueue(std::move(latestWriteBuffer));
latestWriteBuffer = std::vector<char>();
latestWriteBuffer.reserve(maxReserveMessageBufferSize);
}
}

void wz_command_interface_output(const char *str, ...)
{
if (wz_command_interface() == WZ_Command_Interface::None)
{
return;
}
va_list ap;
static char outputBuffer[maxReserveMessageBufferSize];
int ret = -1;
va_start(ap, str);
ret = vssprintf(outputBuffer, str, ap);
va_end(ap);
if (ret >= 0 && ret < maxReserveMessageBufferSize)
{
// string was completely written
wz_command_interface_output_str(outputBuffer);
}
else
{
// string was truncated - try again but use a heap-allocated string
if (ret < 0)
{
// some ancient implementations of vsnprintf return -1 instead of the needed buffer length...
errlog("WZCMD ERROR: Failed to output truncated string - check vsnprintf implementation");
return;
}
size_t neededBufferSize = static_cast<size_t>(ret);
char* tmpBuffer = (char *)malloc(neededBufferSize + 1);
va_start(ap, str);
ret = vsnprintf(tmpBuffer, neededBufferSize + 1, str, ap);
va_end(ap);
if (ret < 0 || ret >= neededBufferSize + 1)
{
errlog("WZCMD ERROR: Failed to output truncated string");
free(tmpBuffer);
return;
}
if (tmpBuffer)
{
wz_command_interface_output_str(tmpBuffer);
free(tmpBuffer);
}
}
}

void configSetCmdInterface(WZ_Command_Interface mode, std::string value)
{
if (cmdInputThread || cmdOutputThread)
Expand Down
2 changes: 2 additions & 0 deletions src/stdinreader.h
Expand Up @@ -43,3 +43,5 @@ void wz_command_interface_output(const char *str, ...) WZ_DECL_FORMAT(__MINGW_PR
#else
void wz_command_interface_output(const char *str, ...) WZ_DECL_FORMAT(printf, 1, 2);
#endif

void wz_command_interface_output_str(const char *str);

0 comments on commit 668e81b

Please sign in to comment.