From 89dbcd9f595d184a81d3991aee7d6394b2b4431f Mon Sep 17 00:00:00 2001
From: Zack Middleton <zturtleman@gmail.com>
Date: Mon, 6 Feb 2012 21:05:57 +0000
Subject: Unix clients can now enter commands from tty console. Patch by
 Rambetter with some edits by me. (#4799)

---
 src/sys/con_tty.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 78 insertions(+), 6 deletions(-)

(limited to 'src/sys')

diff --git a/src/sys/con_tty.c b/src/sys/con_tty.c
index 0d8da734..212f038a 100644
--- a/src/sys/con_tty.c
+++ b/src/sys/con_tty.c
@@ -26,6 +26,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 #include "../qcommon/qcommon.h"
 #include "sys_local.h"
 
+#ifndef DEDICATED
+#include "../client/client.h"
+#endif
+
 #include <unistd.h>
 #include <signal.h>
 #include <termios.h>
@@ -47,6 +51,7 @@ static qboolean stdin_active;
 // general flag to tell about tty console mode
 static qboolean ttycon_on = qfalse;
 static int ttycon_hide = 0;
+static int ttycon_show_overdue = 0;
 
 // some key codes that the terminal may be using, initialised on start up
 static int TTY_erase;
@@ -62,6 +67,14 @@ static field_t TTY_con;
 static field_t ttyEditLines[ CON_HISTORY ];
 static int hist_current = -1, hist_count = 0;
 
+#ifndef DEDICATED
+// Don't use "]" as it would be the same as in-game console,
+//   this makes it clear where input came from.
+#define TTY_CONSOLE_PROMPT "tty]"
+#else
+#define TTY_CONSOLE_PROMPT "]"
+#endif
+
 /*
 ==================
 CON_FlushIn
@@ -125,7 +138,10 @@ static void CON_Hide( void )
 				CON_Back();
 			}
 		}
-		CON_Back(); // Delete "]"
+		// Delete prompt
+		for (i = strlen(TTY_CONSOLE_PROMPT); i > 0; i--) {
+			CON_Back();
+		}
 		ttycon_hide++;
 	}
 }
@@ -149,7 +165,7 @@ static void CON_Show( void )
 		if (ttycon_hide == 0)
 		{
 			size_t UNUSED_VAR size;
-			size = write(STDOUT_FILENO, "]", 1);
+			size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT));
 			if (TTY_con.cursor)
 			{
 				for (i=0; i<TTY_con.cursor; i++)
@@ -172,7 +188,7 @@ void CON_Shutdown( void )
 {
 	if (ttycon_on)
 	{
-		CON_Back(); // Delete "]"
+		CON_Hide();
 		tcsetattr (STDIN_FILENO, TCSADRAIN, &TTY_tc);
 	}
 
@@ -188,6 +204,11 @@ Hist_Add
 void Hist_Add(field_t *field)
 {
 	int i;
+
+	// Don't save blank lines in history.
+	if (!field->cursor)
+		return;
+
 	assert(hist_count <= CON_HISTORY);
 	assert(hist_count >= 0);
 	assert(hist_current >= -1);
@@ -317,6 +338,8 @@ void CON_Init( void )
 	tc.c_cc[VTIME] = 0;
 	tcsetattr (STDIN_FILENO, TCSADRAIN, &tc);
 	ttycon_on = qtrue;
+	ttycon_hide = 1; // Mark as hidden, so prompt is shown in CON_Show
+	CON_Show();
 }
 
 /*
@@ -356,13 +379,39 @@ char *CON_Input( void )
 			{
 				if (key == '\n')
 				{
+#ifndef DEDICATED
+					// if not in the game explicitly prepend a slash if needed
+					if (clc.state != CA_ACTIVE && TTY_con.cursor &&
+						TTY_con.buffer[0] != '/' && TTY_con.buffer[0] != '\\')
+					{
+						memmove(TTY_con.buffer + 1, TTY_con.buffer, sizeof(TTY_con.buffer) - 1);
+						TTY_con.buffer[0] = '\\';
+						TTY_con.cursor++;
+					}
+
+					if (TTY_con.buffer[0] == '/' || TTY_con.buffer[0] == '\\') {
+						Q_strncpyz(text, TTY_con.buffer + 1, sizeof(text));
+					} else if (TTY_con.cursor) {
+						Com_sprintf(text, sizeof(text), "cmd say %s", TTY_con.buffer);
+					} else {
+						text[0] = '\0';
+					}
+
+					// push it in history
+					Hist_Add(&TTY_con);
+					CON_Hide();
+					Com_Printf("%s%s\n", TTY_CONSOLE_PROMPT, TTY_con.buffer);
+					Field_Clear(&TTY_con);
+					CON_Show();
+#else
 					// push it in history
 					Hist_Add(&TTY_con);
 					Q_strncpyz(text, TTY_con.buffer, sizeof(text));
 					Field_Clear(&TTY_con);
 					key = '\n';
 					size = write(STDOUT_FILENO, &key, 1);
-					size = write(STDOUT_FILENO, "]", 1);
+					size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT));
+#endif
 					return text;
 				}
 				if (key == '\t')
@@ -424,7 +473,7 @@ char *CON_Input( void )
 				return NULL;
 			// push regular character
 			TTY_con.buffer[TTY_con.cursor] = key;
-			TTY_con.cursor++;
+			TTY_con.cursor++; // next char will always be '\0'
 			// print the current line (this is differential)
 			size = write(STDOUT_FILENO, &key, 1);
 		}
@@ -467,6 +516,9 @@ CON_Print
 */
 void CON_Print( const char *msg )
 {
+	if (!msg[0])
+		return;
+
 	CON_Hide( );
 
 	if( com_ansiColor && com_ansiColor->integer )
@@ -474,5 +526,25 @@ void CON_Print( const char *msg )
 	else
 		fputs( msg, stderr );
 
-	CON_Show( );
+	if (!ttycon_on) {
+		// CON_Hide didn't do anything.
+		return;
+	}
+
+	// Only print prompt when msg ends with a newline, otherwise the console
+	//   might get garbled when output does not fit on one line.
+	if (msg[strlen(msg) - 1] == '\n') {
+		CON_Show();
+
+		// Run CON_Show the number of times it was deferred.
+		while (ttycon_show_overdue > 0) {
+			CON_Show();
+			ttycon_show_overdue--;
+		}
+	}
+	else
+	{
+		// Defer calling CON_Show
+		ttycon_show_overdue++;
+	}
 }
-- 
cgit