00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "../../common/common.h"
00027 #include "../system.h"
00028 #include <unistd.h>
00029 #include <signal.h>
00030 #include <termios.h>
00031 #include <fcntl.h>
00032 #include <sys/time.h>
00033
00034 typedef struct {
00035 int cursor;
00036 char buffer[256];
00037 } consoleHistory_t;
00038
00039 static qboolean stdinActive;
00040
00041 static qboolean ttyConsoleActivated = qfalse;
00042
00043
00044 static int TTY_erase;
00045 static int TTY_eof;
00046
00047 static struct termios TTY_tc;
00048
00049 static consoleHistory_t ttyConsoleHistory;
00050
00051
00052
00053 #define CON_HISTORY 32
00054 static consoleHistory_t ttyEditLines[CON_HISTORY];
00055 static int histCurrent = -1, histCount = 0;
00056
00061 static void CON_FlushIn (void)
00062 {
00063 char key;
00064 while (read(STDIN_FILENO, &key, 1) != -1)
00065 ;
00066 }
00067
00074 static void Sys_TTYDeleteCharacter (void)
00075 {
00076 char key;
00077 size_t size;
00078
00079 key = '\b';
00080 size = write(STDOUT_FILENO, &key, 1);
00081 key = ' ';
00082 size = write(STDOUT_FILENO, &key, 1);
00083 key = '\b';
00084 size = write(STDOUT_FILENO, &key, 1);
00085 }
00086
00091 static void Sys_TTYConsoleHide (void)
00092 {
00093 if (ttyConsoleHistory.cursor > 0) {
00094 int i;
00095 for (i = 0; i < ttyConsoleHistory.cursor; i++)
00096 Sys_TTYDeleteCharacter();
00097 }
00098 Sys_TTYDeleteCharacter();
00099 }
00100
00105 static void Sys_TTYConsoleShow (void)
00106 {
00107 size_t size = write(STDOUT_FILENO, "]", 1);
00108 if (ttyConsoleHistory.cursor) {
00109 int i;
00110 for (i = 0; i < ttyConsoleHistory.cursor; i++) {
00111 size = write(STDOUT_FILENO, ttyConsoleHistory.buffer + i, 1);
00112 }
00113 }
00114 }
00115
00116 static void Sys_TTYConsoleHistoryAdd (consoleHistory_t *field)
00117 {
00118 int i;
00119 const size_t size = lengthof(ttyEditLines);
00120
00121 assert(histCount <= size);
00122 assert(histCount >= 0);
00123 assert(histCurrent >= -1);
00124 assert(histCurrent <= histCount);
00125
00126 for (i = size - 1; i > 0; i--)
00127 ttyEditLines[i] = ttyEditLines[i - 1];
00128
00129 ttyEditLines[0] = *field;
00130 if (histCount < size)
00131 histCount++;
00132
00133 histCurrent = -1;
00134 }
00135
00136 static consoleHistory_t *Sys_TTYConsoleHistoryPrevious (void)
00137 {
00138 int histPrev;
00139
00140 assert(histCount <= lengthof(ttyEditLines));
00141 assert(histCount >= 0);
00142 assert(histCurrent >= -1);
00143 assert(histCurrent <= histCount);
00144
00145 histPrev = histCurrent + 1;
00146 if (histPrev >= histCount)
00147 return NULL;
00148
00149 histCurrent++;
00150 return &(ttyEditLines[histCurrent]);
00151 }
00152
00153 static consoleHistory_t *Sys_TTYConsoleHistoryNext (void)
00154 {
00155 assert(histCount <= CON_HISTORY);
00156 assert(histCount >= 0);
00157 assert(histCurrent >= -1);
00158 assert(histCurrent <= histCount);
00159 if (histCurrent >= 0)
00160 histCurrent--;
00161
00162 if (histCurrent == -1)
00163 return NULL;
00164
00165 return &(ttyEditLines[histCurrent]);
00166 }
00167
00172 static void Sys_TTYConsoleSigCont (int signum)
00173 {
00174 Sys_ConsoleInit();
00175 }
00176
00177 void Sys_ShowConsole (qboolean show)
00178 {
00179 static int ttyConsoleHide = 0;
00180
00181 if (!ttyConsoleActivated)
00182 return;
00183
00184 if (show) {
00185 assert(ttyConsoleHide > 0);
00186 ttyConsoleHide--;
00187 if (ttyConsoleHide == 0)
00188 Sys_TTYConsoleShow();
00189 } else {
00190 if (ttyConsoleHide == 0)
00191 Sys_TTYConsoleHide();
00192 ttyConsoleHide++;
00193 }
00194 }
00195
00200 void Sys_ConsoleShutdown (void)
00201 {
00202 if (ttyConsoleActivated) {
00203 Sys_TTYDeleteCharacter();
00204 tcsetattr(STDIN_FILENO, TCSADRAIN, &TTY_tc);
00205 }
00206
00207
00208 fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) & ~O_NONBLOCK);
00209 }
00210
00211 static void Sys_TTYConsoleHistoryClear (consoleHistory_t *edit)
00212 {
00213 memset(edit, 0, sizeof(*edit));
00214 }
00215
00216 static qboolean Sys_IsATTY (void)
00217 {
00218 const char* term = getenv("TERM");
00219 return isatty(STDIN_FILENO) && !(term && (!strcmp(term, "raw") || !strcmp(term, "dumb")));
00220 }
00221
00225 void Sys_ConsoleInit (void)
00226 {
00227 struct termios tc;
00228
00229
00230
00231 signal(SIGTTIN, SIG_IGN);
00232 signal(SIGTTOU, SIG_IGN);
00233
00234
00235 signal(SIGCONT, Sys_TTYConsoleSigCont);
00236
00237
00238 fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL, 0) | O_NONBLOCK);
00239
00240 if (!Sys_IsATTY()) {
00241 Com_Printf("tty console mode disabled\n");
00242 ttyConsoleActivated = qfalse;
00243 stdinActive = qtrue;
00244 return;
00245 }
00246
00247 Sys_TTYConsoleHistoryClear(&ttyConsoleHistory);
00248 tcgetattr(STDIN_FILENO, &TTY_tc);
00249 TTY_erase = TTY_tc.c_cc[VERASE];
00250 TTY_eof = TTY_tc.c_cc[VEOF];
00251 tc = TTY_tc;
00252
00253
00254
00255
00256
00257
00258
00259
00260 tc.c_lflag &= ~(ECHO | ICANON);
00261
00262
00263
00264
00265
00266 tc.c_iflag &= ~(ISTRIP | INPCK);
00267 tc.c_cc[VMIN] = 1;
00268 tc.c_cc[VTIME] = 0;
00269 tcsetattr(STDIN_FILENO, TCSADRAIN, &tc);
00270 ttyConsoleActivated = qtrue;
00271 }
00272
00273 const char *Sys_ConsoleInput (void)
00274 {
00275
00276 static char text[256];
00277
00278 if (ttyConsoleActivated) {
00279 char key;
00280 int avail = read(STDIN_FILENO, &key, 1);
00281 if (avail != -1) {
00282 size_t size;
00283
00284
00285
00286 if (key == TTY_erase || key == 127 || key == 8) {
00287 if (ttyConsoleHistory.cursor > 0) {
00288 ttyConsoleHistory.cursor--;
00289 ttyConsoleHistory.buffer[ttyConsoleHistory.cursor] = '\0';
00290 Sys_TTYDeleteCharacter();
00291 }
00292 return NULL;
00293 }
00294
00295 if (key && key < ' ') {
00296 if (key == '\n') {
00297
00298 Sys_TTYConsoleHistoryAdd(&ttyConsoleHistory);
00299 Q_strncpyz(text, ttyConsoleHistory.buffer, sizeof(text));
00300 Sys_TTYConsoleHistoryClear(&ttyConsoleHistory);
00301 key = '\n';
00302 size = write(1, &key, 1);
00303 size = write(1, "]", 1);
00304 return text;
00305 }
00306 if (key == '\t') {
00307 const size_t size = sizeof(ttyConsoleHistory.buffer);
00308 const char *s = ttyConsoleHistory.buffer;
00309 char *target = ttyConsoleHistory.buffer;
00310 Sys_ShowConsole(qfalse);
00311 Com_ConsoleCompleteCommand(s, target, size, &ttyConsoleHistory.cursor, 0);
00312 Sys_ShowConsole(qtrue);
00313 return NULL;
00314 }
00315 avail = read(STDIN_FILENO, &key, 1);
00316 if (avail != -1) {
00317
00318 if (key == '[' || key == 'O') {
00319 consoleHistory_t *history;
00320 avail = read(STDIN_FILENO, &key, 1);
00321 if (avail != -1) {
00322 switch (key) {
00323 case 'A':
00324 history = Sys_TTYConsoleHistoryPrevious();
00325 if (history) {
00326 Sys_ShowConsole(qfalse);
00327 ttyConsoleHistory = *history;
00328 Sys_ShowConsole(qtrue);
00329 }
00330 CON_FlushIn();
00331 return NULL;
00332 break;
00333 case 'B':
00334 history = Sys_TTYConsoleHistoryNext();
00335 Sys_ShowConsole(qfalse);
00336 if (history) {
00337 ttyConsoleHistory = *history;
00338 } else {
00339 Sys_TTYConsoleHistoryClear(&ttyConsoleHistory);
00340 }
00341 Sys_ShowConsole(qtrue);
00342 CON_FlushIn();
00343 return NULL;
00344 break;
00345 case 'C':
00346 return NULL;
00347 case 'D':
00348 return NULL;
00349 }
00350 }
00351 }
00352 }
00353 CON_FlushIn();
00354 return NULL;
00355 }
00356 if (ttyConsoleHistory.cursor >= sizeof(text) - 1)
00357 return NULL;
00358
00359 ttyConsoleHistory.buffer[ttyConsoleHistory.cursor] = key;
00360 ttyConsoleHistory.cursor++;
00361
00362 size = write(STDOUT_FILENO, &key, 1);
00363 }
00364
00365 return NULL;
00366 } else if (stdinActive) {
00367 int len;
00368 fd_set fdset;
00369 struct timeval timeout;
00370
00371 FD_ZERO(&fdset);
00372 FD_SET(STDIN_FILENO, &fdset);
00373 timeout.tv_sec = 0;
00374 timeout.tv_usec = 0;
00375 if (select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout) == -1
00376 || !FD_ISSET(STDIN_FILENO, &fdset))
00377 return NULL;
00378
00379 len = read(STDIN_FILENO, text, sizeof(text));
00380 if (len == 0) {
00381 stdinActive = qfalse;
00382 return NULL;
00383 }
00384
00385 if (len < 1)
00386 return NULL;
00387 text[len - 1] = 0;
00388
00389 return text;
00390 }
00391 return NULL;
00392 }
00393
00399 void Sys_ConsoleOutput (const char *string)
00400 {
00401
00402 const int origflags = fcntl(STDOUT_FILENO, F_GETFL, 0);
00403
00404 Sys_ShowConsole(qfalse);
00405
00406
00407 if (!strncmp(string, COLORED_GREEN, strlen(COLORED_GREEN)))
00408 string += strlen(COLORED_GREEN);
00409
00410 fcntl(STDOUT_FILENO, F_SETFL, origflags & ~FNDELAY);
00411 while (*string) {
00412 const ssize_t written = write(STDOUT_FILENO, string, strlen(string));
00413 if (written <= 0)
00414 break;
00415 string += written;
00416 }
00417 fcntl(STDOUT_FILENO, F_SETFL, origflags);
00418
00419
00420 Sys_ShowConsole(qtrue);
00421 }