Skip to content

Commit

Permalink
Fix: windows terminal wide strings output
Browse files Browse the repository at this point in the history
  • Loading branch information
dnzbk committed Oct 17, 2024
1 parent c2b1f88 commit 5d90350
Show file tree
Hide file tree
Showing 8 changed files with 302 additions and 51 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ if(CMAKE_BUILD_TYPE STREQUAL "Debug")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "-O0 -pthread -g -DDEBUG -Wall -Wextra" CACHE STRING "" FORCE)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(CMAKE_CXX_FLAGS "/Od /Zi /MTd /MP /W4 /EHs /DDEBUG /D_DEBUG /DWIN32 /wd4800 /wd4267" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS "/Od /Zi /MTd /MP /utf-8 /W4 /EHs /DDEBUG /D_DEBUG /DWIN32 /wd4800 /wd4267" CACHE STRING "" FORCE)
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} winmm.lib Dbghelp.lib libcpmtd.lib" CACHE STRING "" FORCE)
endif()
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
Expand All @@ -74,7 +74,7 @@ elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(CMAKE_CXX_FLAGS "-O2 -g0 -pthread -DNDEBUG" CACHE STRING "" FORCE)
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
set(CMAKE_CXX_FLAGS "/O2 /MT /MP /EHs /DNDEBUG /DWIN32 /wd4800 /wd4267" CACHE STRING "" FORCE)
set(CMAKE_CXX_FLAGS "/O2 /MT /MP /utf-8 /EHs /DNDEBUG /DWIN32 /wd4800 /wd4267" CACHE STRING "" FORCE)
set(CMAKE_CXX_STANDARD_LIBRARIES "${CMAKE_CXX_STANDARD_LIBRARIES} winmm.lib" CACHE STRING "" FORCE)
endif()
endif()
Expand Down
2 changes: 2 additions & 0 deletions cmake/windows.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ find_package(Threads REQUIRED)
find_package(LibXml2 REQUIRED)
find_package(Boost REQUIRED COMPONENTS json)

#add_compile_definitions(UNICODE)

set(LIBS ${LIBS} Threads::Threads Boost::json LibXml2::LibXml2)
set(INCLUDES ${INCLUDES} ${Boost_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})

Expand Down
114 changes: 72 additions & 42 deletions daemon/frontend/NCursesFrontend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,25 @@ void curses_clear()

extern void ExitProc();

static const int NCURSES_COLORPAIR_TEXT = 1;
static const int NCURSES_COLORPAIR_INFO = 2;
static const int NCURSES_COLORPAIR_WARNING = 3;
static const int NCURSES_COLORPAIR_ERROR = 4;
static const int NCURSES_COLORPAIR_DEBUG = 5;
static const int NCURSES_COLORPAIR_DETAIL = 6;
static const int NCURSES_COLORPAIR_STATUS = 7;
static const int NCURSES_COLORPAIR_KEYBAR = 8;
static const int NCURSES_COLORPAIR_INFOLINE = 9;
static const int NCURSES_COLORPAIR_TEXTHIGHL = 10;
static const int NCURSES_COLORPAIR_CURSOR = 11;
static const int NCURSES_COLORPAIR_HINT = 12;

static const int MAX_SCREEN_WIDTH = 512;
const int NCURSES_COLORPAIR_TEXT = 1;
const int NCURSES_COLORPAIR_INFO = 2;
const int NCURSES_COLORPAIR_WARNING = 3;
const int NCURSES_COLORPAIR_ERROR = 4;
const int NCURSES_COLORPAIR_DEBUG = 5;
const int NCURSES_COLORPAIR_DETAIL = 6;
const int NCURSES_COLORPAIR_STATUS = 7;
const int NCURSES_COLORPAIR_KEYBAR = 8;
const int NCURSES_COLORPAIR_INFOLINE = 9;
const int NCURSES_COLORPAIR_TEXTHIGHL = 10;
const int NCURSES_COLORPAIR_CURSOR = 11;
const int NCURSES_COLORPAIR_HINT = 12;

const int MAX_SCREEN_WIDTH = 512;

#ifdef WIN32

#include "Utf8.h"

static const int COLOR_BLACK = 0;
static const int COLOR_BLUE = FOREGROUND_BLUE;
static const int COLOR_RED = FOREGROUND_RED;
Expand Down Expand Up @@ -350,31 +353,23 @@ int NCursesFrontend::CalcQueueSize()
return queueSize;
}

#ifndef WIN32

void NCursesFrontend::PlotLine(const char * string, int row, int pos, int colorPair)
{
BString<1024> buffer("%-*s", m_screenWidth, string);
int len = buffer.Length();
if (len > m_screenWidth - pos && m_screenWidth - pos < MAX_SCREEN_WIDTH)
std::string buffer(m_screenWidth, '\0');
sprintf(buffer.data(), "%-*s", m_screenWidth, string);
buffer.shrink_to_fit();
if (buffer.size() > m_screenWidth - pos && m_screenWidth - pos < MAX_SCREEN_WIDTH)
{
buffer[m_screenWidth - pos] = '\0';
}

PlotText(buffer, row, pos, colorPair, false);
PlotText(buffer.data(), row, pos, colorPair, false);
}

void NCursesFrontend::PlotText(const char * string, int row, int pos, int colorPair, bool blink)
{
#ifdef WIN32
int bufPos = row * m_screenWidth + pos;
int len = strlen(string);
for (int i = 0; i < len; i++)
{
char c = string[i];
CharToOemBuff(&c, &c, 1);
m_screenBuffer[bufPos + i].Char.AsciiChar = c;
m_screenBuffer[bufPos + i].Attributes = m_colorAttr[colorPair];
}
#else
if( m_useColor )
{
attron(COLOR_PAIR(colorPair));
Expand All @@ -392,16 +387,44 @@ void NCursesFrontend::PlotText(const char * string, int row, int pos, int colorP
attroff(A_BLINK);
}
}
#endif
}

#else

void NCursesFrontend::PlotLine(const char * string, int row, int pos, int colorPair)
{
std::wstring wstr = Utf8::Utf8ToWide(string).value();
std::wstring buffer(m_screenWidth + 1, '\0');
swprintf(buffer.data(), buffer.size(), L"%-*s", m_screenWidth, wstr.c_str());
buffer.shrink_to_fit();
if (buffer.size() > m_screenWidth - pos && m_screenWidth - pos < MAX_SCREEN_WIDTH)
{
buffer[m_screenWidth - pos] = '\0';
}

PlotText(buffer.data(), row, pos, colorPair, false);
}

void NCursesFrontend::PlotText(const wchar_t* wstr, int row, int pos, int colorPair, bool blink)
{
int bufPos = row * m_screenWidth + pos;
size_t len = wcslen(wstr);
for (size_t i = 0; i < len; ++i)
{
m_screenBuffer[bufPos + i].Char.UnicodeChar = wstr[i];
m_screenBuffer[bufPos + i].Attributes = m_colorAttr[colorPair];
}
}

#endif

void NCursesFrontend::RefreshScreen()
{
#ifdef WIN32
bool bufChanged = !std::equal(m_screenBuffer.begin(), m_screenBuffer.end(), m_oldScreenBuffer.begin(), m_oldScreenBuffer.end(),
[](CHAR_INFO& a, CHAR_INFO& b)
{
return a.Char.AsciiChar == b.Char.AsciiChar && a.Attributes == b.Attributes;
return a.Char.UnicodeChar == b.Char.UnicodeChar && a.Attributes == b.Attributes;
});

if (bufChanged)
Expand All @@ -417,7 +440,7 @@ void NCursesFrontend::RefreshScreen()
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO BufInfo;
GetConsoleScreenBufferInfo(hConsole, &BufInfo);
WriteConsoleOutput(hConsole, m_screenBuffer.data(), BufSize, BufCoord, &BufInfo.srWindow);
WriteConsoleOutputW(hConsole, m_screenBuffer.data(), BufSize, BufCoord, &BufInfo.srWindow);

BufInfo.dwCursorPosition.X = BufInfo.srWindow.Right;
BufInfo.dwCursorPosition.Y = BufInfo.srWindow.Bottom;
Expand Down Expand Up @@ -446,8 +469,9 @@ void NCursesFrontend::PrintMessages()
{
int lineNr = m_messagesWinTop;

BString<1024> buffer("%s Messages", m_useColor ? "" : "*** ");
PlotLine(buffer, lineNr++, 0, NCURSES_COLORPAIR_INFOLINE);
std::string buffer = (m_useColor ? "" : "*** ");
buffer += " Messages";
PlotLine(buffer.c_str(), lineNr++, 0, NCURSES_COLORPAIR_INFOLINE);

int line = lineNr + m_messagesWinClientHeight - 1;
int linesToPrint = m_messagesWinClientHeight;
Expand Down Expand Up @@ -482,10 +506,6 @@ void NCursesFrontend::PrintMessages()

int NCursesFrontend::PrintMessage(Message& msg, int row, int maxLines)
{
const char* messageType[] = { "INFO ", "WARNING ", "ERROR ", "DEBUG ", "DETAIL "};
const int messageTypeColor[] = { NCURSES_COLORPAIR_INFO, NCURSES_COLORPAIR_WARNING,
NCURSES_COLORPAIR_ERROR, NCURSES_COLORPAIR_DEBUG, NCURSES_COLORPAIR_DETAIL };

CString text;

if (m_showTimestamp)
Expand Down Expand Up @@ -522,11 +542,15 @@ int NCursesFrontend::PrintMessage(Message& msg, int row, int maxLines)
PlotLine(text + winWidth * i, r, 8, NCURSES_COLORPAIR_TEXT);
if (i == 0)
{
PlotText(messageType[msg.GetKind()], r, 0, messageTypeColor[msg.GetKind()], false);
PlotText(m_messageTypes[msg.GetKind()], r, 0, m_messageColorTypes[msg.GetKind()], false);
}
else
{
PlotText(" ", r, 0, messageTypeColor[msg.GetKind()], false);
#ifdef WIN32
PlotText(L" ", r, 0, m_messageColorTypes[msg.GetKind()], false);
#else
PlotText(" ", r, 0, m_messageColorTypes[msg.GetKind()], false);
#endif
}
lines++;
}
Expand Down Expand Up @@ -627,10 +651,16 @@ void NCursesFrontend::PrintKeyInputBar()
break;
}
case downloadRate:
BString<100> hint("Download rate: %i", m_inputValue);
PlotLine(hint, inputBarRow, 0, NCURSES_COLORPAIR_KEYBAR);
std::string hint = "Download rate: " + std::to_string(m_inputValue);
PlotLine(hint.c_str(), inputBarRow, 0, NCURSES_COLORPAIR_KEYBAR);

// Print the cursor
#ifdef WIN32
PlotText(L" ", inputBarRow, 15 + m_inputNumberIndex, NCURSES_COLORPAIR_CURSOR, true);
#else

PlotText(" ", inputBarRow, 15 + m_inputNumberIndex, NCURSES_COLORPAIR_CURSOR, true);
#endif
break;
}
}
Expand Down
44 changes: 43 additions & 1 deletion daemon/frontend/NCursesFrontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,27 @@

#ifndef DISABLE_CURSES

#include <string>
#include "NString.h"
#include "Frontend.h"
#include "Log.h"
#include "DownloadInfo.h"

extern const int NCURSES_COLORPAIR_TEXT;
extern const int NCURSES_COLORPAIR_INFO;
extern const int NCURSES_COLORPAIR_WARNING;
extern const int NCURSES_COLORPAIR_ERROR;
extern const int NCURSES_COLORPAIR_DEBUG;
extern const int NCURSES_COLORPAIR_DETAIL;
extern const int NCURSES_COLORPAIR_STATUS;
extern const int NCURSES_COLORPAIR_KEYBAR;
extern const int NCURSES_COLORPAIR_INFOLINE;
extern const int NCURSES_COLORPAIR_TEXTHIGHL;
extern const int NCURSES_COLORPAIR_CURSOR;
extern const int NCURSES_COLORPAIR_HINT;

extern const int MAX_SCREEN_WIDTH;

class NCursesFrontend : public Frontend
{
public:
Expand Down Expand Up @@ -70,6 +86,30 @@ class NCursesFrontend : public Frontend
// Inputting numbers
int m_inputNumberIndex = 0;
int m_inputValue;
#ifdef WIN32
const wchar_t* m_messageTypes[5] = {
L"INFO ",
L"WARNING ",
L"ERROR ",
L"DEBUG ",
L"DETAIL "
};
#else
const char* m_messageTypes[5] = {
"INFO ",
"WARNING ",
"ERROR ",
"DEBUG ",
"DETAIL "
};
#endif
const int m_messageColorTypes[5] = {
NCURSES_COLORPAIR_INFO,
NCURSES_COLORPAIR_WARNING,
NCURSES_COLORPAIR_ERROR,
NCURSES_COLORPAIR_DEBUG,
NCURSES_COLORPAIR_DETAIL
};

#ifdef WIN32
std::vector<CHAR_INFO> m_screenBuffer;
Expand All @@ -87,9 +127,11 @@ class NCursesFrontend : public Frontend

#ifdef WIN32
void init_pair(int colorNumber, WORD wForeColor, WORD wBackColor);
void PlotText(const wchar_t* string, int row, int pos, int colorPair, bool blink);
#else
void PlotText(const char * string, int row, int pos, int colorPair, bool blink);
#endif
void PlotLine(const char * string, int row, int pos, int colorPair);
void PlotText(const char * string, int row, int pos, int colorPair, bool blink);
void PrintMessages();
void PrintQueue();
void PrintFileQueue();
Expand Down
23 changes: 17 additions & 6 deletions daemon/main/nzbget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#include "WinService.h"
#include "WinConsole.h"
#include "WebDownloader.h"
#include "Utf8.h"
#endif
#ifndef DISABLE_NSERV
#include "NServMain.h"
Expand Down Expand Up @@ -106,13 +107,13 @@ int g_ArgumentCount;
char* (*g_EnvironmentVariables)[] = nullptr;
char* (*g_Arguments)[] = nullptr;

#ifdef WIN32

/*
* Main entry point
*/
int main(int argc, char *argv[], char *argp[])
#include "Utf8.h"

int wmain(int argc, wchar_t* wargv[], wchar_t* wargp[])
{
#ifdef WIN32

#ifdef _DEBUG
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
Expand All @@ -122,8 +123,18 @@ int main(int argc, char *argv[], char *argp[])
#endif
);
#endif
#endif
SetConsoleOutputCP(CP_UTF8);

Utf8::WideToUtf8ArgsAdapter wargvAdapter{ argc, wargv };
Utf8::WideToUtf8ArgsAdapter wargpAdapter{ argc, wargp };
auto argv = wargvAdapter.GetUtf8Args();
auto argp = wargpAdapter.GetUtf8Args();
#else

int main(int argc, char* argv[], char* argp[])
{

#endif
Util::Init();
YEncode::init();

Expand Down
1 change: 1 addition & 0 deletions daemon/sources.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ set(WIN32_SRC
${CMAKE_SOURCE_DIR}/daemon/windows/StdAfx.cpp
${CMAKE_SOURCE_DIR}/daemon/windows/WinConsole.cpp
${CMAKE_SOURCE_DIR}/daemon/windows/WinService.cpp
${CMAKE_SOURCE_DIR}/daemon/util/Utf8.cpp
)

if(WIN32)
Expand Down
Loading

0 comments on commit 5d90350

Please sign in to comment.