123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- #include "il2cpp-config.h"
- #if IL2CPP_TARGET_POSIX && !IL2CPP_USE_PLATFORM_SPECIFIC_CONSOLE
- #include "os/Console.h"
- #include "os/File.h"
- #include <stdlib.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <stdio.h>
- #include <termios.h>
- #include <unistd.h>
- #include <sys/ioctl.h>
- #include <sys/time.h>
- #include <sys/types.h>
- namespace il2cpp
- {
- namespace os
- {
- namespace Console
- {
- #if !RUNTIME_TINY
- static bool setupComplete = false;
- static int32_t s_terminalSize;
- static struct termios s_initialAttr;
- static struct termios s_il2cppAttr;
- static std::string s_keypadXmit;
- static std::string s_teardown;
- static struct sigaction s_saveSigcont, s_saveSigint, s_saveSigwinch;
- static int32_t GetTerminalSize()
- {
- struct winsize ws;
- if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0)
- return (ws.ws_col << 16) | ws.ws_row;
- return -1;
- }
- static bool SetProperty(int32_t property, bool value)
- {
- struct termios attr;
- bool callset = false;
- bool check;
- if (tcgetattr(STDIN_FILENO, &attr) == -1)
- return false;
- check = (attr.c_lflag & property) != 0;
- if ((value || check) && !(value && check))
- {
- callset = true;
- if (value)
- attr.c_lflag |= property;
- else
- attr.c_lflag &= ~property;
- }
- if (!callset)
- return true;
- if (tcsetattr(STDIN_FILENO, TCSANOW, &attr) == -1)
- return true;
- s_il2cppAttr = attr;
- return true;
- }
- static void SetControlChars(uint8_t* control_chars, const uint8_t *cc)
- {
- // The index into the array comes from corlib/System/ControlCharacters.cs
- #ifdef VINTR
- control_chars[0] = cc[VINTR];
- #endif
- #ifdef VQUIT
- control_chars[1] = cc[VQUIT];
- #endif
- #ifdef VERASE
- control_chars[2] = cc[VERASE];
- #endif
- #ifdef VKILL
- control_chars[3] = cc[VKILL];
- #endif
- #ifdef VEOF
- control_chars[4] = cc[VEOF];
- #endif
- #ifdef VTIME
- control_chars[5] = cc[VTIME];
- #endif
- #ifdef VMIN
- control_chars[6] = cc[VMIN];
- #endif
- #ifdef VSWTC
- control_chars[7] = cc[VSWTC];
- #endif
- #ifdef VSTART
- control_chars[8] = cc[VSTART];
- #endif
- #ifdef VSTOP
- control_chars[9] = cc[VSTOP];
- #endif
- #ifdef VSUSP
- control_chars[10] = cc[VSUSP];
- #endif
- #ifdef VEOL
- control_chars[11] = cc[VEOL];
- #endif
- #ifdef VREPRINT
- control_chars[12] = cc[VREPRINT];
- #endif
- #ifdef VDISCARD
- control_chars[13] = cc[VDISCARD];
- #endif
- #ifdef VWERASE
- control_chars[14] = cc[VWERASE];
- #endif
- #ifdef VLNEXT
- control_chars[15] = cc[VLNEXT];
- #endif
- #ifdef VEOL2
- control_chars[16] = cc[VEOL2];
- #endif
- }
- static void CallDoConsoleCancelEvent()
- {
- // TODO: Call Console.cancel_handler delegate from another thread.
- }
- static void SigintHandler(int signo)
- {
- static bool insideSigint = false;
- if (insideSigint)
- return;
- insideSigint = true;
- CallDoConsoleCancelEvent();
- insideSigint = false;
- }
- static void SigcontHandler(int signo, siginfo_t *the_siginfo, void *data)
- {
- // Ignore error, there is not much we can do in the sigcont handler.
- tcsetattr(STDIN_FILENO, TCSANOW, &s_il2cppAttr);
- if (!s_keypadXmit.empty())
- write(STDOUT_FILENO, s_keypadXmit.c_str(), s_keypadXmit.length());
- // Call previous handler
- if (s_saveSigcont.sa_sigaction != NULL &&
- s_saveSigcont.sa_sigaction != (void*)SIG_DFL &&
- s_saveSigcont.sa_sigaction != (void*)SIG_IGN)
- (*s_saveSigcont.sa_sigaction)(signo, the_siginfo, data);
- }
- static void SigwinchHandler(int signo, siginfo_t *the_siginfo, void *data)
- {
- const int32_t size = GetTerminalSize();
- if (size != -1)
- s_terminalSize = size;
- // Call previous handler
- if (s_saveSigwinch.sa_sigaction != NULL &&
- s_saveSigwinch.sa_sigaction != (void*)SIG_DFL &&
- s_saveSigwinch.sa_sigaction != (void*)SIG_IGN)
- (*s_saveSigwinch.sa_sigaction)(signo, the_siginfo, data);
- }
- static void ConsoleSetupSignalHandler()
- {
- struct sigaction sigcont, sigint, sigwinch;
- memset(&sigcont, 0, sizeof(struct sigaction));
- memset(&sigint, 0, sizeof(struct sigaction));
- memset(&sigwinch, 0, sizeof(struct sigaction));
- // Continuing
- sigcont.sa_sigaction = SigcontHandler;
- sigcont.sa_flags = SA_SIGINFO;
- sigemptyset(&sigcont.sa_mask);
- sigaction(SIGCONT, &sigcont, &s_saveSigcont);
- // Interrupt handler
- sigint.sa_handler = SigintHandler;
- sigint.sa_flags = 0;
- sigemptyset(&sigint.sa_mask);
- sigaction(SIGINT, &sigint, &s_saveSigint);
- // Window size changed
- sigwinch.sa_sigaction = SigwinchHandler;
- sigwinch.sa_flags = SA_SIGINFO;
- sigemptyset(&sigwinch.sa_mask);
- sigaction(SIGWINCH, &sigwinch, &s_saveSigwinch);
- }
- // Exists in Mono, but is unused.
- static void ConsoleRestoreSignalHandlers()
- {
- sigaction(SIGCONT, &s_saveSigcont, NULL);
- sigaction(SIGINT, &s_saveSigint, NULL);
- sigaction(SIGWINCH, &s_saveSigwinch, NULL);
- }
- int32_t InternalKeyAvailable(int32_t ms_timeout)
- {
- fd_set rfds;
- struct timeval tv;
- struct timeval *tvptr;
- div_t divvy;
- int32_t ret, nbytes;
- do
- {
- FD_ZERO(&rfds);
- FD_SET(STDIN_FILENO, &rfds);
- if (ms_timeout >= 0)
- {
- divvy = div(ms_timeout, 1000);
- tv.tv_sec = divvy.quot;
- tv.tv_usec = divvy.rem;
- tvptr = &tv;
- }
- else
- {
- tvptr = NULL;
- }
- ret = select(STDIN_FILENO + 1, &rfds, NULL, NULL, tvptr);
- }
- while (ret == -1 && errno == EINTR);
- if (ret > 0)
- {
- nbytes = 0;
- ret = ioctl(STDIN_FILENO, FIONREAD, &nbytes);
- if (ret >= 0)
- ret = nbytes;
- }
- return (ret > 0) ? ret : 0;
- }
- bool SetBreak(bool wantBreak)
- {
- return SetProperty(IGNBRK, !wantBreak);
- }
- bool SetEcho(bool wantEcho)
- {
- return SetProperty(ECHO, wantEcho);
- }
- static void TtyShutdown()
- {
- if (!setupComplete)
- return;
- if (!s_teardown.empty())
- write(STDOUT_FILENO, s_teardown.c_str(), s_teardown.length());
- tcflush(STDIN_FILENO, TCIFLUSH);
- tcsetattr(STDIN_FILENO, TCSANOW, &s_initialAttr);
- SetProperty(ECHO, true);
- setupComplete = false;
- }
- bool TtySetup(const std::string& keypadXmit, const std::string& teardown, uint8_t* control_characters, int32_t** size)
- {
- s_terminalSize = GetTerminalSize();
- if (s_terminalSize == -1)
- {
- int32_t cols = 0, rows = 0;
- const char *colsValue = getenv("COLUMNS");
- if (colsValue != NULL)
- cols = atoi(colsValue);
- const char *linesValue = getenv("LINES");
- if (linesValue != NULL)
- rows = atoi(linesValue);
- if (cols != 0 && rows != 0)
- s_terminalSize = (cols << 16) | rows;
- else
- s_terminalSize = -1;
- }
- *size = &s_terminalSize;
- if (tcgetattr(STDIN_FILENO, &s_initialAttr) == -1)
- return false;
- s_il2cppAttr = s_initialAttr;
- s_il2cppAttr.c_lflag &= ~(ICANON);
- s_il2cppAttr.c_iflag &= ~(IXON | IXOFF);
- s_il2cppAttr.c_cc[VMIN] = 1;
- s_il2cppAttr.c_cc[VTIME] = 0;
- if (tcsetattr(STDIN_FILENO, TCSANOW, &s_il2cppAttr) == -1)
- return false;
- s_keypadXmit = keypadXmit;
- SetControlChars(control_characters, s_il2cppAttr.c_cc);
- if (setupComplete)
- return true;
- ConsoleSetupSignalHandler();
- setupComplete = true;
- s_teardown = teardown;
- atexit(TtyShutdown);
- return true;
- }
- #endif
- const char* NewLine()
- {
- return "\n";
- }
- }
- }
- }
- #endif
|