mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #5142
5142: Handle file/pipe stdout and add fallback on Windows r=def- a=Robyt3 The `CWindowsConsoleLogger` uses `WriteConsoleW` which only works when the standard output handle is a console (`GetFileType` returns `FILE_TYPE_CHAR`). When redirecting output into a file, `GetFileType` returns `FILE_TYPE_DISK`. For this case a `CWindowsFileLogger` is added that uses `WriteFile` instead. This works on raw bytes, so the UTF-8 encoded lines are written directly. When pipeing output or when using custom terminals like Git Bash, `GetFileType` returns `FILE_TYPE_PIPE`. I can't find any documentation how to correctly interact with a pipe stdout handle. So in this case, `WriteFile` is also used, because it works for me with cmd, PowerShell and Git Bash. Lastly, if the output device is unknown, the default `CLoggerAsync` without ANSI colors is used as fallback. This fixes output not working in Git Bash. Closes #4422. It also fixes output redirected with Git Bash containing additional line breaks. For consistency, the `CWindowsConsoleLogger` now writes windows line endings also. ## Checklist - [X] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [ ] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Robert Müller <robytemueller@gmail.com>
This commit is contained in:
commit
5a8cb4f398
|
@ -298,14 +298,20 @@ static int color_hsv_to_windows_console_color(const ColorHSVA &Hsv)
|
|||
|
||||
class CWindowsConsoleLogger : public ILogger
|
||||
{
|
||||
HANDLE m_pConsole;
|
||||
|
||||
public:
|
||||
CWindowsConsoleLogger(HANDLE pConsole) :
|
||||
m_pConsole(pConsole)
|
||||
{
|
||||
}
|
||||
void Log(const CLogMessage *pMessage) override
|
||||
{
|
||||
wchar_t *pWide = (wchar_t *)malloc((pMessage->m_LineLength + 1) * sizeof(*pWide));
|
||||
wchar_t *pWide = (wchar_t *)malloc((pMessage->m_LineLength + 2) * sizeof(*pWide));
|
||||
const char *p = pMessage->m_aLine;
|
||||
int WLen = 0;
|
||||
|
||||
mem_zero(pWide, pMessage->m_LineLength * sizeof(*pWide));
|
||||
mem_zero(pWide, (pMessage->m_LineLength + 2) * sizeof(*pWide));
|
||||
|
||||
for(int Codepoint = 0; (Codepoint = str_utf8_decode(&p)); WLen++)
|
||||
{
|
||||
|
@ -325,8 +331,8 @@ public:
|
|||
|
||||
mem_copy(&pWide[WLen], aU16, 2);
|
||||
}
|
||||
pWide[WLen] = '\n';
|
||||
HANDLE pConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
pWide[WLen++] = '\r';
|
||||
pWide[WLen++] = '\n';
|
||||
int Color = 15;
|
||||
if(pMessage->m_HaveColor)
|
||||
{
|
||||
|
@ -336,11 +342,26 @@ public:
|
|||
Rgba.b = pMessage->m_Color.b / 255.0;
|
||||
Color = color_hsv_to_windows_console_color(color_cast<ColorHSVA>(Rgba));
|
||||
}
|
||||
SetConsoleTextAttribute(pConsole, Color);
|
||||
WriteConsoleW(pConsole, pWide, WLen + 1, NULL, NULL);
|
||||
SetConsoleTextAttribute(m_pConsole, Color);
|
||||
WriteConsoleW(m_pConsole, pWide, WLen, NULL, NULL);
|
||||
free(pWide);
|
||||
}
|
||||
};
|
||||
class CWindowsFileLogger : public ILogger
|
||||
{
|
||||
HANDLE m_pFile;
|
||||
|
||||
public:
|
||||
CWindowsFileLogger(HANDLE pFile) :
|
||||
m_pFile(pFile)
|
||||
{
|
||||
}
|
||||
void Log(const CLogMessage *pMessage) override
|
||||
{
|
||||
WriteFile(m_pFile, pMessage->m_aLine, pMessage->m_LineLength, NULL, NULL);
|
||||
WriteFile(m_pFile, "\r\n", 2, NULL, NULL);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
std::unique_ptr<ILogger> log_logger_stdout()
|
||||
|
@ -350,7 +371,14 @@ std::unique_ptr<ILogger> log_logger_stdout()
|
|||
// https://github.com/termstandard/colors/tree/65bf0cd1ece7c15fa33a17c17528b02c99f1ae0b#checking-for-colorterm
|
||||
return std::unique_ptr<ILogger>(new CLoggerAsync(io_stdout(), getenv("NO_COLOR") == nullptr, false));
|
||||
#else
|
||||
return std::unique_ptr<ILogger>(new CWindowsConsoleLogger());
|
||||
HANDLE pOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
switch(GetFileType(pOutput))
|
||||
{
|
||||
case FILE_TYPE_CHAR: return std::unique_ptr<ILogger>(new CWindowsConsoleLogger(pOutput));
|
||||
case FILE_TYPE_PIPE: // fall through, writing to pipe works the same as writing to a file
|
||||
case FILE_TYPE_DISK: return std::unique_ptr<ILogger>(new CWindowsFileLogger(pOutput));
|
||||
default: return std::unique_ptr<ILogger>(new CLoggerAsync(io_stdout(), false, false));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue