mirror of
				https://github.com/Tiiffi/mcrcon.git
				synced 2025-10-30 21:01:07 -04:00 
			
		
		
		
	Compare commits
	
		
			6 Commits
		
	
	
		
			dba07aacf7
			...
			b1b46ca08c
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| b1b46ca08c | |||
| 2bb1fafdaa | |||
| 0fb17971c0 | |||
| ec11d77e89 | |||
| 2d29741691 | |||
| cc77044df1 | 
| @ -2,10 +2,11 @@ | |||||||
|  |  | ||||||
| ###### 0.8.0 | ###### 0.8.0 | ||||||
|  - Implement support for multipacket responses |  - Implement support for multipacket responses | ||||||
|  - Add support to Valve style rcon authentication |  - Add support for Valve style rcon authentication | ||||||
|  |  - Add experimental UTF-8 support for Windows | ||||||
|  - Change maximum packet size to correct value (4096 -> 4106) |  - Change maximum packet size to correct value (4096 -> 4106) | ||||||
|  - Attempt to add missing newlines in Minecraft servers |  - Attempt to add missing newlines in bugged Minecraft servers | ||||||
|     * Currently implemented only for the 'help' command |     * Implemented for responses to the 'help' command and unknown commands | ||||||
|  - Print auth failed message to stderr instead of stdout |  - Print auth failed message to stderr instead of stdout | ||||||
|  - Fail immediately if received packet size is out of spec |  - Fail immediately if received packet size is out of spec | ||||||
|  - Return proper exit code from run_terminal_mode() |  - Return proper exit code from run_terminal_mode() | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							| @ -15,7 +15,7 @@ RM = rm -v -f | |||||||
|  |  | ||||||
| CC ?= gcc | CC ?= gcc | ||||||
| CFLAGS = -std=gnu99 -Wall -Wextra -Wpedantic -Wno-gnu-zero-variadic-macro-arguments -O2 | CFLAGS = -std=gnu99 -Wall -Wextra -Wpedantic -Wno-gnu-zero-variadic-macro-arguments -O2 | ||||||
| EXTRAFLAGS ?= -fstack-protector-all | EXTRAFLAGS ?= -fstack-protector-strong -D_FORTIFY_SOURCE=2 -fPIE -pie -Wl,-z,relro -Wl,-z,now -fno-common | ||||||
|  |  | ||||||
| ifeq ($(OS), Windows_NT) | ifeq ($(OS), Windows_NT) | ||||||
| 	LINKER = -lws2_32 | 	LINKER = -lws2_32 | ||||||
|  | |||||||
							
								
								
									
										201
									
								
								mcrcon.c
									
									
									
									
									
								
							
							
						
						
									
										201
									
								
								mcrcon.c
									
									
									
									
									
								
							| @ -31,14 +31,17 @@ | |||||||
| #include <errno.h> | #include <errno.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
|  |  | ||||||
|  |  | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
| 	#include <winsock2.h> | 	#include <winsock2.h> | ||||||
|     #include <windows.h> | 	#include <windows.h> | ||||||
|     #include <ws2tcpip.h> | 	#include <ws2tcpip.h> | ||||||
|  | 	#include <fcntl.h> | ||||||
|  | 	#include <wchar.h> | ||||||
| #else | #else | ||||||
|     #include <sys/socket.h> | 	#include <sys/socket.h> | ||||||
|     #include <netdb.h> | 	#include <sys/select.h> | ||||||
|  | 	#include <netdb.h> | ||||||
|  | 	#include <termios.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #define VERSION "0.8.0" | #define VERSION "0.8.0" | ||||||
| @ -56,15 +59,17 @@ | |||||||
| #define MAX_PACKET_SIZE		4106 // id (4) + cmd (4) + DATA_BUFFSIZE | #define MAX_PACKET_SIZE		4106 // id (4) + cmd (4) + DATA_BUFFSIZE | ||||||
| #define MIN_PACKET_SIZE		10   // id (4) + cmd (4) + two empty strings (2) | #define MIN_PACKET_SIZE		10   // id (4) + cmd (4) + two empty strings (2) | ||||||
|  |  | ||||||
|  | #define MAX_WAIT_TIME 600 | ||||||
|  |  | ||||||
| #define log_error(fmt, ...) fprintf(stderr, fmt,  ##__VA_ARGS__); | #define log_error(fmt, ...) fprintf(stderr, fmt,  ##__VA_ARGS__); | ||||||
|  |  | ||||||
| // rcon packet structure | // rcon packet structure | ||||||
| typedef struct { | typedef struct { | ||||||
|     int32_t size; | 	int32_t size; | ||||||
|     int32_t id; | 	int32_t id; | ||||||
|     int32_t cmd; | 	int32_t cmd; | ||||||
|     uint8_t data[DATA_BUFFSIZE]; | 	uint8_t data[DATA_BUFFSIZE]; | ||||||
|     // ignoring string2 for now | 	// ignoring string2 for now | ||||||
| } rc_packet; | } rc_packet; | ||||||
|  |  | ||||||
| // =================================== | // =================================== | ||||||
| @ -108,8 +113,12 @@ static bool global_minecraft_newline_fix = false; | |||||||
| static int  global_rsock; | static int  global_rsock; | ||||||
|  |  | ||||||
| #ifdef _WIN32 | #ifdef _WIN32 | ||||||
|   // console coloring on windows | // console coloring on windows | ||||||
|   HANDLE console_handle; | HANDLE console_handle; | ||||||
|  |  | ||||||
|  | // console code pages | ||||||
|  | UINT old_output_codepage; | ||||||
|  | UINT old_input_codepage; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // safety stuff (windows is still misbehaving) | // safety stuff (windows is still misbehaving) | ||||||
| @ -117,6 +126,15 @@ void exit_proc(void) | |||||||
| { | { | ||||||
| 	if (global_rsock != -1) | 	if (global_rsock != -1) | ||||||
| 		net_close(global_rsock); | 		net_close(global_rsock); | ||||||
|  |  | ||||||
|  | 	#ifdef _WIN32 | ||||||
|  | 	// Restore previous code pages | ||||||
|  | 	SetConsoleOutputCP(old_output_codepage); | ||||||
|  | 	SetConsoleCP(old_input_codepage); | ||||||
|  |  | ||||||
|  | 	// Set back to binary mode | ||||||
|  | 	_setmode(_fileno(stdin), _O_BINARY); | ||||||
|  | 	#endif | ||||||
| } | } | ||||||
|  |  | ||||||
| // TODO: check exact windows and linux behaviour | // TODO: check exact windows and linux behaviour | ||||||
| @ -126,13 +144,9 @@ void sighandler(int sig) | |||||||
| 		putchar('\n'); | 		putchar('\n'); | ||||||
|  |  | ||||||
| 	global_connection_alive = 0; | 	global_connection_alive = 0; | ||||||
| 	#ifndef _WIN32 | 	exit(EXIT_SUCCESS); | ||||||
| 	    exit(EXIT_SUCCESS); |  | ||||||
| 	#endif |  | ||||||
| } | } | ||||||
|  |  | ||||||
| #define MAX_WAIT_TIME 600 |  | ||||||
|  |  | ||||||
| unsigned int mcrcon_parse_seconds(char *str) | unsigned int mcrcon_parse_seconds(char *str) | ||||||
| { | { | ||||||
| 	char *end; | 	char *end; | ||||||
| @ -185,7 +199,7 @@ int main(int argc, char *argv[]) | |||||||
| 			case 'r': flag_raw_output = 1;           break; | 			case 'r': flag_raw_output = 1;           break; | ||||||
| 			case 'w': | 			case 'w': | ||||||
| 				flag_wait_seconds = mcrcon_parse_seconds(optarg); | 				flag_wait_seconds = mcrcon_parse_seconds(optarg); | ||||||
| 			break; | 				break; | ||||||
|  |  | ||||||
| 			case 'v': | 			case 'v': | ||||||
| 				puts(VER_STR); | 				puts(VER_STR); | ||||||
| @ -216,10 +230,20 @@ int main(int argc, char *argv[]) | |||||||
| 	signal(SIGINT, &sighandler); | 	signal(SIGINT, &sighandler); | ||||||
|  |  | ||||||
| 	#ifdef _WIN32 | 	#ifdef _WIN32 | ||||||
| 		net_init_WSA(); | 	net_init_WSA(); | ||||||
| 		console_handle = GetStdHandle(STD_OUTPUT_HANDLE); | 	console_handle = GetStdHandle(STD_OUTPUT_HANDLE); | ||||||
| 		if (console_handle == INVALID_HANDLE_VALUE) | 	if (console_handle == INVALID_HANDLE_VALUE) | ||||||
| 			console_handle = NULL; | 		console_handle = NULL; | ||||||
|  |  | ||||||
|  | 	// Set the output and input code pages to utf-8 | ||||||
|  | 	old_output_codepage = GetConsoleOutputCP(); | ||||||
|  | 	old_input_codepage = GetConsoleCP(); | ||||||
|  |  | ||||||
|  | 	SetConsoleOutputCP(CP_UTF8); | ||||||
|  | 	SetConsoleCP(CP_UTF8); | ||||||
|  |  | ||||||
|  | 	// Set the file translation mode to UTF16 | ||||||
|  | 	_setmode(_fileno(stdin), _O_U16TEXT); | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| 	// open socket | 	// open socket | ||||||
| @ -270,8 +294,8 @@ void usage(void) | |||||||
| 	puts("Example:\n\t"IN_NAME" -H my.minecraft.server -p password -w 5 \"say Server is restarting!\" save-all stop\n"); | 	puts("Example:\n\t"IN_NAME" -H my.minecraft.server -p password -w 5 \"say Server is restarting!\" save-all stop\n"); | ||||||
|  |  | ||||||
| 	#ifdef _WIN32 | 	#ifdef _WIN32 | ||||||
| 	    puts("Press enter to exit."); | 	puts("Press enter to exit."); | ||||||
| 	    getchar(); | 	getchar(); | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| 	exit(EXIT_SUCCESS); | 	exit(EXIT_SUCCESS); | ||||||
| @ -298,10 +322,10 @@ void net_init_WSA(void) | |||||||
| void net_close(int sd) | void net_close(int sd) | ||||||
| { | { | ||||||
| 	#ifdef _WIN32 | 	#ifdef _WIN32 | ||||||
| 		closesocket(sd); | 	closesocket(sd); | ||||||
| 		WSACleanup(); | 	WSACleanup(); | ||||||
| 	#else | 	#else | ||||||
| 		close(sd); | 	close(sd); | ||||||
| 	#endif | 	#endif | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -320,16 +344,16 @@ int net_connect(const char *host, const char *port) | |||||||
| 	hints.ai_protocol = IPPROTO_TCP; | 	hints.ai_protocol = IPPROTO_TCP; | ||||||
|  |  | ||||||
| 	#ifdef _WIN32 | 	#ifdef _WIN32 | ||||||
| 	  net_init_WSA(); | 	net_init_WSA(); | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| 	int ret = getaddrinfo(host, port, &hints, &server_info); | 	int ret = getaddrinfo(host, port, &hints, &server_info); | ||||||
| 	if (ret != 0) { | 	if (ret != 0) { | ||||||
| 		log_error("Name resolution failed.\n"); | 		log_error("Name resolution failed.\n"); | ||||||
| 		#ifdef _WIN32 | 		#ifdef _WIN32 | ||||||
| 			log_error("Error %d: %s", ret, gai_strerror(ret)); | 		log_error("Error %d: %s", ret, gai_strerror(ret)); | ||||||
| 		#else | 		#else | ||||||
| 			log_error("Error %d: %s\n", ret, gai_strerror(ret)); | 		log_error("Error %d: %s\n", ret, gai_strerror(ret)); | ||||||
| 		#endif | 		#endif | ||||||
|  |  | ||||||
| 		exit(EXIT_FAILURE); | 		exit(EXIT_FAILURE); | ||||||
| @ -355,7 +379,7 @@ int net_connect(const char *host, const char *port) | |||||||
| 		/* TODO (Tiiffi): Check why windows does not report errors */ | 		/* TODO (Tiiffi): Check why windows does not report errors */ | ||||||
| 		log_error("Connection failed.\n"); | 		log_error("Connection failed.\n"); | ||||||
| 		#ifndef _WIN32 | 		#ifndef _WIN32 | ||||||
| 			log_error("Error %d: %s\n", errno, strerror(errno)); | 		log_error("Error %d: %s\n", errno, strerror(errno)); | ||||||
| 		#endif | 		#endif | ||||||
|  |  | ||||||
| 		freeaddrinfo(server_info); | 		freeaddrinfo(server_info); | ||||||
| @ -386,6 +410,9 @@ bool net_send_packet(int sd, rc_packet *packet) | |||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // TODO: Fix the wonky behaviour when server quit/exit/stop/close | ||||||
|  | //       command is issued. Client should close gracefully without errors. | ||||||
| rc_packet *net_recv_packet(int sd) | rc_packet *net_recv_packet(int sd) | ||||||
| { | { | ||||||
| 	int32_t psize; | 	int32_t psize; | ||||||
| @ -467,9 +494,9 @@ void print_color(int color) | |||||||
| 		else return; | 		else return; | ||||||
|  |  | ||||||
| 		#ifndef _WIN32 | 		#ifndef _WIN32 | ||||||
| 			fputs(colors[color], stdout); | 		fputs(colors[color], stdout); | ||||||
| 		#else | 		#else | ||||||
| 			SetConsoleTextAttribute(console_handle, color); | 		SetConsoleTextAttribute(console_handle, color); | ||||||
| 		#endif | 		#endif | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -478,20 +505,32 @@ void print_color(int color) | |||||||
| void packet_print(rc_packet *packet) | void packet_print(rc_packet *packet) | ||||||
| { | { | ||||||
| 	uint8_t *data = packet->data; | 	uint8_t *data = packet->data; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
| 	if (flag_raw_output == 1) { | 	if (flag_raw_output == 1) { | ||||||
| 		fputs((char *) data, stdout); | 		fputs((char *) data, stdout); | ||||||
| 		return; | 		return; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	int i; | 	// Newline fix for Minecraft | ||||||
|  | 	if (global_valve_protocol == false) { | ||||||
|  | 		const char test[] = "Unknown or incomplete command, see below for error"; | ||||||
|  | 		size_t test_size = sizeof test - 1; | ||||||
|  | 		if (strncmp((char *) data, test, test_size) == 0) { | ||||||
|  | 			fwrite(data, test_size, 1, stdout); | ||||||
|  | 			putchar('\n'); | ||||||
|  | 			data = &data[test_size]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	int default_color = 0; | 	int default_color = 0; | ||||||
|  |  | ||||||
| 	#ifdef _WIN32 | 	#ifdef _WIN32 | ||||||
| 		CONSOLE_SCREEN_BUFFER_INFO console_info; | 	CONSOLE_SCREEN_BUFFER_INFO console_info; | ||||||
| 		if (GetConsoleScreenBufferInfo(console_handle, &console_info) != 0) { | 	if (GetConsoleScreenBufferInfo(console_handle, &console_info) != 0) { | ||||||
| 			default_color = console_info.wAttributes + 0x30; | 		default_color = console_info.wAttributes + 0x30; | ||||||
| 		} else default_color = 0x37; | 	} | ||||||
|  | 	else default_color = 0x37; | ||||||
| 	#endif | 	#endif | ||||||
|  |  | ||||||
| 	bool slash = false; | 	bool slash = false; | ||||||
| @ -512,6 +551,7 @@ void packet_print(rc_packet *packet) | |||||||
| 			continue; | 			continue; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		// Add missing newlines | ||||||
| 		if (colors_detected == false && global_minecraft_newline_fix && data[i] == '/') { | 		if (colors_detected == false && global_minecraft_newline_fix && data[i] == '/') { | ||||||
| 			slash ? putchar('\n') : (slash = true); | 			slash ? putchar('\n') : (slash = true); | ||||||
| 		} | 		} | ||||||
| @ -563,7 +603,7 @@ bool rcon_auth(int sock, char *passwd) | |||||||
| 		return 0; // send failed | 		return 0; // send failed | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| receive: | 	receive: | ||||||
| 	packet = net_recv_packet(sock); | 	packet = net_recv_packet(sock); | ||||||
| 	if (packet == NULL) | 	if (packet == NULL) | ||||||
| 		return 0; | 		return 0; | ||||||
| @ -638,7 +678,7 @@ int rcon_command(int sock, char *command) | |||||||
|  |  | ||||||
| 		if (flag_silent_mode == false) { | 		if (flag_silent_mode == false) { | ||||||
| 			if (packet->size > 10) | 			if (packet->size > 10) | ||||||
| 			packet_print(packet); | 				packet_print(packet); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		int result = select(sock + 1, &read_fds, NULL, NULL, &timeout); | 		int result = select(sock + 1, &read_fds, NULL, NULL, &timeout); | ||||||
| @ -669,9 +709,9 @@ int run_commands(int argc, char *argv[]) | |||||||
|  |  | ||||||
| 		if (flag_wait_seconds > 0) { | 		if (flag_wait_seconds > 0) { | ||||||
| 			#ifdef _WIN32 | 			#ifdef _WIN32 | ||||||
| 				Sleep(flag_wait_seconds * 1000); | 			Sleep(flag_wait_seconds * 1000); | ||||||
| 			#else | 			#else | ||||||
| 				sleep(flag_wait_seconds); | 			sleep(flag_wait_seconds); | ||||||
| 			#endif | 			#endif | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -682,7 +722,7 @@ int run_terminal_mode(int sock) | |||||||
| { | { | ||||||
| 	char command[MAX_COMMAND_LENGTH] = {0}; | 	char command[MAX_COMMAND_LENGTH] = {0}; | ||||||
|  |  | ||||||
| 	puts("Logged in.\nType 'Q' or press Ctrl-D / Ctrl-C to disconnect."); | 	puts("Logged in. Press Ctrl-D or Ctrl-C to disconnect."); | ||||||
|  |  | ||||||
| 	while (global_connection_alive) { | 	while (global_connection_alive) { | ||||||
| 		putchar('>'); | 		putchar('>'); | ||||||
| @ -691,8 +731,6 @@ int run_terminal_mode(int sock) | |||||||
| 		int len = get_line(command, MAX_COMMAND_LENGTH); | 		int len = get_line(command, MAX_COMMAND_LENGTH); | ||||||
| 		if (len < 1) continue; | 		if (len < 1) continue; | ||||||
|  |  | ||||||
| 		if (strcasecmp(command, "Q") == 0) break; |  | ||||||
|  |  | ||||||
| 		if (len > 0 && global_connection_alive) { | 		if (len > 0 && global_connection_alive) { | ||||||
| 			if (!rcon_command(sock, command)) { | 			if (!rcon_command(sock, command)) { | ||||||
| 				return EXIT_FAILURE; | 				return EXIT_FAILURE; | ||||||
| @ -702,22 +740,80 @@ int run_terminal_mode(int sock) | |||||||
| 		/* Special case for "stop" command to prevent server-side bug. | 		/* Special case for "stop" command to prevent server-side bug. | ||||||
| 		 * https://bugs.mojang.com/browse/MC-154617 | 		 * https://bugs.mojang.com/browse/MC-154617 | ||||||
| 		 * | 		 * | ||||||
| 		 * NOTE: This is hacky workaround which should be handled better to | 		 * NOTE: Not sure if this still a problem?! | ||||||
| 		 *       ensure compatibility with other servers using source RCON. |  | ||||||
| 		 * NOTE: strcasecmp() is POSIX function. |  | ||||||
| 		 */ | 		 */ | ||||||
| 		if (strcasecmp(command, "stop") == 0) { | 		if (global_valve_protocol == false && strcasecmp(command, "stop") == 0) { | ||||||
| 			break; | 			// Timeout to before checking if connection was closed | ||||||
|  | 			#ifdef _WIN32 | ||||||
|  | 			Sleep(2 * 1000); | ||||||
|  | 			#else | ||||||
|  | 			sleep(2); | ||||||
|  | 			#endif | ||||||
|  |  | ||||||
|  | 			char tmp[1]; | ||||||
|  | 			#ifdef _WIN32 | ||||||
|  | 			// TODO: More Windows side testing! | ||||||
|  | 			int result = recv(sock, tmp, sizeof(tmp), MSG_PEEK | 0); | ||||||
|  | 			#else | ||||||
|  | 			int result = recv(sock, tmp, sizeof(tmp), MSG_PEEK | MSG_DONTWAIT); | ||||||
|  | 			#endif | ||||||
|  | 			if (result == 0) { | ||||||
|  | 				break; // Connection closed | ||||||
|  | 			} | ||||||
|  | 			// TODO: Check for return values and errors! | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return EXIT_SUCCESS; | 	return EXIT_SUCCESS; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #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); | ||||||
|  | 	if (result == NULL) { | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// Calculates 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 (WideCharToMultiByte(CP_UTF8, 0, in, -1, buf, size, NULL, NULL) == 0) { | ||||||
|  | 		// TODO: Proper error handling & reporting | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	return buf; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | void flush_input(void) | ||||||
|  | { | ||||||
|  | 	#ifdef _WIN32 | ||||||
|  | 	FlushConsoleInputBuffer(console_handle); | ||||||
|  | 	#else | ||||||
|  | 	tcflush(STDIN_FILENO, TCIFLUSH); | ||||||
|  | 	#endif | ||||||
|  | } | ||||||
|  |  | ||||||
| // gets line from stdin and deals with rubbish left in the input buffer | // gets line from stdin and deals with rubbish left in the input buffer | ||||||
| int get_line(char *buffer, int bsize) | int get_line(char *buffer, int bsize) | ||||||
| { | { | ||||||
|  | 	#ifdef _WIN32 | ||||||
|  | 	char *ret = utf8_getline(buffer, bsize, stdin); | ||||||
|  | 	#else | ||||||
| 	char *ret = fgets(buffer, bsize, stdin); | 	char *ret = fgets(buffer, bsize, stdin); | ||||||
|  | 	#endif | ||||||
|  |  | ||||||
|  | 	flush_input(); | ||||||
|  |  | ||||||
| 	if (ret == NULL) { | 	if (ret == NULL) { | ||||||
| 		if (ferror(stdin)) { | 		if (ferror(stdin)) { | ||||||
| 			log_error("Error %d: %s\n", errno, strerror(errno)); | 			log_error("Error %d: %s\n", errno, strerror(errno)); | ||||||
| @ -729,14 +825,17 @@ int get_line(char *buffer, int bsize) | |||||||
|  |  | ||||||
| 	// remove unwanted characters from the buffer | 	// remove unwanted characters from the buffer | ||||||
| 	buffer[strcspn(buffer, "\r\n")] = '\0'; | 	buffer[strcspn(buffer, "\r\n")] = '\0'; | ||||||
|  |  | ||||||
| 	int len = strlen(buffer); | 	int len = strlen(buffer); | ||||||
|  |  | ||||||
|  | #if 0 | ||||||
| 	// clean input buffer if needed | 	// clean input buffer if needed | ||||||
|  | 	#ifndef _WIN32 | ||||||
| 	if (len == bsize - 1) { | 	if (len == bsize - 1) { | ||||||
| 		int ch; | 		int ch; | ||||||
| 		while ((ch = getchar()) != '\n' && ch != EOF); | 		while ((ch = getchar()) != '\n' && ch != EOF); | ||||||
| 	} | 	} | ||||||
|  | 	#endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
| 	return len; | 	return len; | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	