Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
6.2 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. // CTextConsoleUnix.cpp: Unix implementation of the TextConsole class.
  9. //
  10. //////////////////////////////////////////////////////////////////////
  11. #ifndef _WIN32
  12. #include "TextConsoleUnix.h"
  13. // un-needed include...
  14. //#include "resource.h"
  15. #include "tier0/icommandline.h"
  16. //#include "../ifilesystem.h"
  17. #include "filesystem.h"
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include <stdio.h>
  21. #include <termios.h>
  22. #include <string.h>
  23. #include <sys/ioctl.h>
  24. #include <sys/time.h>
  25. #include <signal.h>
  26. #define CONSOLE_LOG_FILE "console.log"
  27. bool CTextConsoleUnix::Init( )
  28. {
  29. static struct termios termNew;
  30. sigset_t block_ttou;
  31. sigemptyset (&block_ttou);
  32. sigaddset (&block_ttou, SIGTTOU);
  33. sigprocmask (SIG_BLOCK, &block_ttou, NULL);
  34. tty = stdout;
  35. // this code is for echo-ing key presses to the connected tty
  36. // (which is != STDOUT)
  37. if ( isatty(STDIN_FILENO) )
  38. {
  39. tty = fopen( ctermid( NULL ), "w+" );
  40. if ( !tty )
  41. {
  42. printf("Unable to open tty(%s) for output\n", ctermid( NULL ) );
  43. tty = stdout;
  44. }
  45. else
  46. {
  47. setbuf( tty, NULL ); // turn buffering off
  48. }
  49. }
  50. else
  51. {
  52. tty = fopen( "/dev/null", "w+" );
  53. if ( !tty )
  54. {
  55. tty = stdout;
  56. }
  57. }
  58. tcgetattr( STDIN_FILENO, &termStored );
  59. memcpy( &termNew, &termStored, sizeof( struct termios ) );
  60. /* Disable canonical mode, and set buffer size to 1 byte */
  61. termNew.c_lflag &= ( ~ICANON );
  62. termNew.c_cc[ VMIN ] = 1;
  63. termNew.c_cc[ VTIME ] = 0;
  64. /* disable echo */
  65. termNew.c_lflag &= ( ~ECHO );
  66. tcsetattr( STDIN_FILENO, TCSANOW, &termNew );
  67. sigprocmask (SIG_UNBLOCK, &block_ttou, NULL);
  68. m_bConDebug = CommandLine()->FindParm( "-condebug" ) != 0;
  69. if ( m_bConDebug && CommandLine()->FindParm( "-conclearlog" ) )
  70. {
  71. g_pFullFileSystem->RemoveFile( CONSOLE_LOG_FILE, "GAME" );
  72. }
  73. return CTextConsole::Init();
  74. }
  75. void CTextConsoleUnix::ShutDown( void )
  76. {
  77. sigset_t block_ttou;
  78. sigemptyset (&block_ttou);
  79. sigaddset (&block_ttou, SIGTTOU);
  80. sigprocmask (SIG_BLOCK, &block_ttou, NULL);
  81. tcsetattr( STDIN_FILENO, TCSANOW, &termStored );
  82. sigprocmask (SIG_UNBLOCK, &block_ttou, NULL);
  83. CTextConsole::ShutDown();
  84. }
  85. // return 0 if the kb isn't hit
  86. int CTextConsoleUnix::kbhit( void )
  87. {
  88. fd_set rfds;
  89. struct timeval tv;
  90. /* Watch stdin (fd 0) to see when it has input. */
  91. FD_ZERO( &rfds );
  92. FD_SET( STDIN_FILENO, &rfds );
  93. /* Return immediately. */
  94. tv.tv_sec = 0;
  95. tv.tv_usec = 0;
  96. /* Must be in raw or cbreak mode for this to work correctly. */
  97. return select( STDIN_FILENO + 1, &rfds, NULL, NULL, &tv )!=-1 && FD_ISSET( STDIN_FILENO, &rfds );
  98. }
  99. char * CTextConsoleUnix::GetLine( void )
  100. {
  101. if ( !kbhit() ) // early return for 99.999% case :)
  102. return NULL;
  103. escape_sequence_t es;
  104. es = ESCAPE_CLEAR;
  105. sigset_t block_ttou;
  106. sigemptyset (&block_ttou);
  107. sigaddset (&block_ttou, SIGTTOU);
  108. sigaddset (&block_ttou, SIGTTIN);
  109. sigprocmask (SIG_BLOCK, &block_ttou, NULL);
  110. while ( 1 )
  111. {
  112. char ch;
  113. int nLen;
  114. if ( !kbhit() )
  115. break;
  116. ch = 0;
  117. int numRead = read( STDIN_FILENO, &ch, 1 );
  118. if ( !numRead )
  119. break;
  120. switch (ch)
  121. {
  122. case '\n': // Enter
  123. es = ESCAPE_CLEAR;
  124. nLen = ReceiveNewline();
  125. if ( nLen )
  126. {
  127. sigprocmask (SIG_UNBLOCK, &block_ttou, NULL);
  128. return m_szConsoleText;
  129. }
  130. break;
  131. case 127: // Backspace
  132. case '\b': // Backspace
  133. es = ESCAPE_CLEAR;
  134. ReceiveBackspace();
  135. break;
  136. case '\t': // TAB
  137. es = ESCAPE_CLEAR;
  138. ReceiveTab();
  139. break;
  140. case 27: // Escape character
  141. es = ESCAPE_RECEIVED;
  142. break;
  143. case '[': // 2nd part of escape sequence
  144. case 'O':
  145. case 'o':
  146. switch( es )
  147. {
  148. case ESCAPE_CLEAR:
  149. case ESCAPE_BRACKET_RECEIVED:
  150. es = ESCAPE_CLEAR;
  151. ReceiveStandardChar( ch );
  152. break;
  153. case ESCAPE_RECEIVED:
  154. es = ESCAPE_BRACKET_RECEIVED;
  155. break;
  156. }
  157. break;
  158. case 'A':
  159. if ( es == ESCAPE_BRACKET_RECEIVED )
  160. {
  161. es = ESCAPE_CLEAR;
  162. ReceiveUpArrow();
  163. }
  164. else
  165. {
  166. es = ESCAPE_CLEAR;
  167. ReceiveStandardChar( ch );
  168. }
  169. break;
  170. case 'B':
  171. if ( es == ESCAPE_BRACKET_RECEIVED )
  172. {
  173. es = ESCAPE_CLEAR;
  174. ReceiveDownArrow();
  175. }
  176. else
  177. {
  178. es = ESCAPE_CLEAR;
  179. ReceiveStandardChar( ch );
  180. }
  181. break;
  182. case 'C':
  183. if ( es == ESCAPE_BRACKET_RECEIVED )
  184. {
  185. es = ESCAPE_CLEAR;
  186. ReceiveRightArrow();
  187. }
  188. else
  189. {
  190. es = ESCAPE_CLEAR;
  191. ReceiveStandardChar( ch );
  192. }
  193. break;
  194. case 'D':
  195. if ( es == ESCAPE_BRACKET_RECEIVED )
  196. {
  197. es = ESCAPE_CLEAR;
  198. ReceiveLeftArrow();
  199. }
  200. else
  201. {
  202. es = ESCAPE_CLEAR;
  203. ReceiveStandardChar( ch );
  204. }
  205. break;
  206. default:
  207. if ( es != ESCAPE_BRACKET_RECEIVED ) // Just eat this char if it's an unsupported escape
  208. {
  209. if ( ( ch >= ' ') && ( ch <= '~' ) ) // dont' accept nonprintable chars
  210. {
  211. es = ESCAPE_CLEAR;
  212. ReceiveStandardChar( ch );
  213. }
  214. }
  215. break;
  216. }
  217. fflush( stdout );
  218. }
  219. sigprocmask (SIG_UNBLOCK, &block_ttou, NULL);
  220. return NULL;
  221. }
  222. void CTextConsoleUnix::PrintRaw( char * pszMsg, int nChars )
  223. {
  224. if ( m_bConDebug )
  225. {
  226. FileHandle_t fh = g_pFullFileSystem->Open( CONSOLE_LOG_FILE, "a" );
  227. if ( fh != FILESYSTEM_INVALID_HANDLE )
  228. {
  229. if ( nChars == 0 )
  230. {
  231. g_pFullFileSystem->Write( pszMsg, strlen( pszMsg ), fh );
  232. }
  233. else
  234. {
  235. g_pFullFileSystem->Write( pszMsg, nChars, fh );
  236. }
  237. g_pFullFileSystem->Close( fh );
  238. }
  239. }
  240. if ( nChars == 0 )
  241. {
  242. printf( "%s", pszMsg );
  243. }
  244. else
  245. {
  246. int nCount;
  247. for ( nCount = 0; nCount < nChars; nCount++ )
  248. {
  249. printf( "%c", pszMsg[ nCount ] );
  250. }
  251. }
  252. }
  253. void CTextConsoleUnix::Echo( char * pszMsg, int nChars )
  254. {
  255. if ( nChars == 0 )
  256. {
  257. fprintf( tty, "%s", pszMsg );
  258. }
  259. else
  260. {
  261. int nCount;
  262. for ( nCount = 0; nCount < nChars; nCount++ )
  263. {
  264. fprintf( tty, "%c", pszMsg[ nCount ] );
  265. }
  266. }
  267. }
  268. int CTextConsoleUnix::GetWidth( void )
  269. {
  270. struct winsize ws;
  271. int nWidth;
  272. nWidth = 0;
  273. if ( ioctl( STDOUT_FILENO, TIOCGWINSZ, &ws ) == 0 )
  274. {
  275. nWidth = (int)ws.ws_col;
  276. }
  277. /* if ( nWidth <= 0 )
  278. {
  279. char * ss;
  280. ss = getenv( "COLUMNS" );
  281. if ( ss )
  282. {
  283. nWidth = atoi( ss );
  284. }
  285. }
  286. */
  287. if ( nWidth <= 1 )
  288. {
  289. nWidth = 80;
  290. }
  291. return nWidth;
  292. }
  293. #endif // ndef _WIN32