mirror of
https://github.com/Tiiffi/mcrcon.git
synced 2025-12-16 02:02:53 -05:00
Refactor color handling and add error handling to UTF-8 code
This commit is contained in:
123
mcrcon.c
123
mcrcon.c
@@ -30,6 +30,7 @@
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
@@ -456,6 +457,69 @@ rc_packet *net_recv_packet(int sd)
|
||||
return &packet;
|
||||
}
|
||||
|
||||
/* NOTE: At least Bukkit/Spigot servers are sending formatting via rcon but not sure how common this
|
||||
* behaviour is. This implementation tries to print colors but is omitting "bold" in "bright" colors
|
||||
* because bold tag should be manually reset and Bukkit/Spigot is not doing this.
|
||||
* References: https://minecraft.fandom.com/wiki/Formatting_codes
|
||||
* https://en.wikipedia.org/wiki/ANSI_escape_code
|
||||
*/
|
||||
void set_color(int c)
|
||||
{
|
||||
c = tolower(c);
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
// Map color Minecraft color codes to WinAPI colors
|
||||
if (c >= '0' && c <= '9') {
|
||||
c -= '0';
|
||||
}
|
||||
else if (c >= 'a' && c <= 'f') {
|
||||
c -= 87;
|
||||
}
|
||||
else return;
|
||||
|
||||
SetConsoleTextAttribute(console_handle, c);
|
||||
|
||||
#else
|
||||
|
||||
/* NOTE: Using "bold" for bright colors for now. This is not correct exactly
|
||||
* because it resets other formattings and must be reseted manually.
|
||||
* This should match Bukkit/Spigot server console output though
|
||||
*/
|
||||
const char *ansi_escape;
|
||||
switch (c)
|
||||
{
|
||||
case '0': ansi_escape = "\033[30m"; break; // Black
|
||||
case '1': ansi_escape = "\033[34m"; break; // Blue
|
||||
case '2': ansi_escape = "\033[32m"; break; // Green
|
||||
case '3': ansi_escape = "\033[36m"; break; // Cyan
|
||||
case '4': ansi_escape = "\033[31m"; break; // Red
|
||||
case '5': ansi_escape = "\033[35m"; break; // Magenta
|
||||
case '6': ansi_escape = "\033[33m"; break; // Yellow
|
||||
case '7': ansi_escape = "\033[37m"; break; // White
|
||||
case '8': ansi_escape = "\033[1;90m"; break; // Bright black (gray)
|
||||
case '9': ansi_escape = "\033[1;94m"; break; // Bright blue
|
||||
case 'a': ansi_escape = "\033[1;92m"; break; // Bright green
|
||||
case 'b': ansi_escape = "\033[1;96m"; break; // Bright cyan
|
||||
case 'c': ansi_escape = "\033[1;91m"; break; // Bright red
|
||||
case 'd': ansi_escape = "\033[1;95m"; break; // Bright magenta
|
||||
case 'e': ansi_escape = "\033[1;93m"; break; // Bright yellow
|
||||
case 'f': ansi_escape = "\033[1;97m"; break; // Bright white
|
||||
case 'k': ansi_escape = "\033[08m"; break; // Concealed text
|
||||
case 'l': ansi_escape = "\033[01m"; break; // Bold text
|
||||
case 'm': ansi_escape = "\033[09m"; break; // Strikethrough text
|
||||
case 'n': ansi_escape = "\033[03m"; break; // Italic text
|
||||
case 'o': ansi_escape = "\033[04m"; break; // Underlined text
|
||||
case 0: // fallthrough
|
||||
case 'r': ansi_escape = "\033[00m"; break; // Reset all attributes
|
||||
default: return;
|
||||
|
||||
}
|
||||
fputs(ansi_escape, stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
// NOTE: Old version!
|
||||
void print_color(int color)
|
||||
{
|
||||
// sh compatible color array
|
||||
@@ -480,11 +544,11 @@ void print_color(int color)
|
||||
"\033[4m" /* 16 UNDERLINE 0x6e */
|
||||
};
|
||||
|
||||
if (color == 0 || color == 0x72) {
|
||||
if (color == 0 || color == 'r') {
|
||||
fputs("\033[0m", stdout); // cancel color
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
if (color >= 0x61 && color <= 0x66) color -= 0x57;
|
||||
else if (color >= 0x30 && color <= 0x39)
|
||||
@@ -497,7 +561,7 @@ void print_color(int color)
|
||||
fputs(colors[color], stdout);
|
||||
#else
|
||||
SetConsoleTextAttribute(console_handle, color);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,7 +587,7 @@ void packet_print(rc_packet *packet)
|
||||
}
|
||||
}
|
||||
|
||||
int default_color = 0;
|
||||
int default_color = 'r';
|
||||
|
||||
#ifdef _WIN32
|
||||
CONSOLE_SCREEN_BUFFER_INFO console_info;
|
||||
@@ -538,15 +602,14 @@ void packet_print(rc_packet *packet)
|
||||
|
||||
for (i = 0; data[i] != 0; ++i)
|
||||
{
|
||||
if (data[i] == 0x0A) {
|
||||
print_color(default_color);
|
||||
}
|
||||
else if(data[i] == 0xc2 && data[i + 1] == 0xa7) {
|
||||
// Check for '§' (utf-8 section sign). Bukkit is using this for colors.
|
||||
if(data[i] == 0xc2 && data[i + 1] == 0xa7) {
|
||||
// Disable new line fixes if Bukkit colors are detected
|
||||
colors_detected = true;
|
||||
i += 2;
|
||||
if (flag_disable_colors == 0) {
|
||||
print_color(data[i]);
|
||||
//print_color(data[i]);
|
||||
set_color(data[i]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -558,7 +621,9 @@ void packet_print(rc_packet *packet)
|
||||
|
||||
putchar(data[i]);
|
||||
}
|
||||
print_color(default_color); // cancel coloring
|
||||
|
||||
set_color(default_color); // reset color
|
||||
//print_color(default_color); // cancel coloring
|
||||
|
||||
// print newline if string has no newline
|
||||
if (data[i - 1] != '\n') {
|
||||
@@ -770,7 +835,6 @@ int run_terminal_mode(int sock)
|
||||
#ifdef _WIN32
|
||||
char *utf8_getline(char *buf, int size, FILE *stream)
|
||||
{
|
||||
// Widechar fgets
|
||||
wchar_t in[MAX_COMMAND_LENGTH] = {0};
|
||||
|
||||
wchar_t *result = fgetws(in, MAX_COMMAND_LENGTH, stream);
|
||||
@@ -778,34 +842,27 @@ char *utf8_getline(char *buf, int size, FILE *stream)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Calculates UTF-8 buffer size
|
||||
size_t length = wcslen(in);
|
||||
if (length > 0 && in[length - 1] == L'\n') {
|
||||
in[length - 1] = L'\0';
|
||||
}
|
||||
|
||||
// Calculate UTF-8 buffer size
|
||||
int required_size = WideCharToMultiByte(CP_UTF8, 0, in, -1, NULL, 0, NULL, NULL);
|
||||
if (size < required_size) {
|
||||
// TODO: Proper error handling & reporting
|
||||
return NULL;
|
||||
if (required_size > size || required_size == 0) {
|
||||
log_error("Widechar to UTF-8 conversion failed.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, in, -1, buf, size, NULL, NULL) == 0) {
|
||||
// TODO: Proper error handling & reporting
|
||||
return NULL;
|
||||
log_error("Widechar to UTF-8 conversion failed.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
void flush_input(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// NOTE: Undefined behaviour in C standard but Windows allows it
|
||||
fflush(stdin);
|
||||
#else
|
||||
__fpurge(stdin);
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
|
||||
// gets line from stdin and deals with rubbish left in the input buffer
|
||||
int get_line(char *buffer, int bsize)
|
||||
{
|
||||
@@ -820,23 +877,19 @@ int get_line(char *buffer, int bsize)
|
||||
log_error("Error %d: %s\n", errno, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
// EOF
|
||||
putchar('\n');
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// remove unwanted characters from the buffer
|
||||
buffer[strcspn(buffer, "\r\n")] = '\0';
|
||||
|
||||
#ifdef _WIN32
|
||||
// NOTE: Undefined behaviour in C standard but Windows allows it
|
||||
fflush(stdin);
|
||||
#else
|
||||
int len = strlen(buffer);
|
||||
|
||||
if (len == bsize - 1) {
|
||||
int ch;
|
||||
while ((ch = getchar()) != '\n' && ch != EOF);
|
||||
}
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user