| @@ -8,8 +8,8 @@ neercs_SOURCES = \ | |||||
| \ | \ | ||||
| $(old_sources) \ | $(old_sources) \ | ||||
| \ | \ | ||||
| term/term.cpp term/term.h \ | |||||
| term/pty.cpp term/pty.h \ | |||||
| term/term.h term/term.cpp term/ansi.cpp \ | |||||
| term/pty.h term/pty.cpp \ | |||||
| \ | \ | ||||
| video/render.cpp video/render.h \ | video/render.cpp video/render.h \ | ||||
| video/text-render.cpp video/text-render.h \ | video/text-render.cpp video/text-render.h \ | ||||
| @@ -70,6 +70,7 @@ | |||||
| <ClCompile Include="old\server.c" /> | <ClCompile Include="old\server.c" /> | ||||
| <ClCompile Include="old\widgets.c" /> | <ClCompile Include="old\widgets.c" /> | ||||
| <ClCompile Include="old\wm.cpp" /> | <ClCompile Include="old\wm.cpp" /> | ||||
| <ClInclude Include="term\ansi.cpp" /> | |||||
| <ClInclude Include="term\pty.cpp" /> | <ClInclude Include="term\pty.cpp" /> | ||||
| <ClInclude Include="term\term.cpp" /> | <ClInclude Include="term\term.cpp" /> | ||||
| <ClCompile Include="video\render.cpp" /> | <ClCompile Include="video\render.cpp" /> | ||||
| @@ -74,6 +74,9 @@ | |||||
| <ClCompile Include="old\python\py_module.c"> | <ClCompile Include="old\python\py_module.c"> | ||||
| <Filter>old\python</Filter> | <Filter>old\python</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| <ClCompile Include="term\ansi.cpp"> | |||||
| <Filter>term</Filter> | |||||
| </ClCompile> | |||||
| <ClCompile Include="term\pty.cpp"> | <ClCompile Include="term\pty.cpp"> | ||||
| <Filter>term</Filter> | <Filter>term</Filter> | ||||
| </ClCompile> | </ClCompile> | ||||
| @@ -42,14 +42,19 @@ using namespace lol; | |||||
| #include "neercs.h" | #include "neercs.h" | ||||
| Pty::Pty(ivec2 size) | Pty::Pty(ivec2 size) | ||||
| : m_size(size) | |||||
| : m_fd(-1), | |||||
| m_pid(-1), | |||||
| m_size(size) | |||||
| { | { | ||||
| ; | ; | ||||
| } | } | ||||
| Pty::~Pty() | Pty::~Pty() | ||||
| { | { | ||||
| if (m_fd >= 0) | |||||
| { | |||||
| close((int)m_fd); | |||||
| } | |||||
| } | } | ||||
| void Pty::Run(char const *command) | void Pty::Run(char const *command) | ||||
| @@ -58,8 +63,8 @@ void Pty::Run(char const *command) | |||||
| int fd; | int fd; | ||||
| pid_t pid; | pid_t pid; | ||||
| m_pid = 0; | |||||
| m_fd = 0; | |||||
| m_pid = -1; | |||||
| m_fd = -1; | |||||
| pid = forkpty(&fd, NULL, NULL, NULL); | pid = forkpty(&fd, NULL, NULL, NULL); | ||||
| if (pid < 0) | if (pid < 0) | ||||
| @@ -94,6 +99,45 @@ void Pty::Run(char const *command) | |||||
| #endif | #endif | ||||
| } | } | ||||
| size_t Pty::ReadData(char *data, size_t maxlen) | |||||
| { | |||||
| fd_set fdset; | |||||
| int maxfd = -1; | |||||
| FD_ZERO(&fdset); | |||||
| if (m_fd >= 0) | |||||
| { | |||||
| FD_SET((int)m_fd, &fdset); | |||||
| maxfd = std::max(maxfd, (int)m_fd); | |||||
| } | |||||
| if (maxfd >= 0) | |||||
| { | |||||
| struct timeval tv; | |||||
| tv.tv_sec = 0; | |||||
| tv.tv_usec = 50000; | |||||
| int ret = select(maxfd + 1, &fdset, NULL, NULL, &tv); | |||||
| if (ret < 0) | |||||
| { | |||||
| Log::Error("cannot read from PTY\n"); | |||||
| return 0; | |||||
| } | |||||
| if (ret) | |||||
| { | |||||
| if (FD_ISSET((int)m_fd, &fdset)) | |||||
| { | |||||
| ssize_t nr = read((int)m_fd, data, maxlen); | |||||
| if (nr >= 0) | |||||
| return nr; | |||||
| } | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| void Pty::SetWindowSize(ivec2 size) | void Pty::SetWindowSize(ivec2 size) | ||||
| { | { | ||||
| #if defined HAVE_PTY_H || defined HAVE_UTIL_H || defined HAVE_LIBUTIL_H | #if defined HAVE_PTY_H || defined HAVE_UTIL_H || defined HAVE_LIBUTIL_H | ||||
| @@ -12,11 +12,12 @@ public: | |||||
| ~Pty(); | ~Pty(); | ||||
| void Run(char const *command); | void Run(char const *command); | ||||
| size_t ReadData(char *data, size_t maxlen); | |||||
| void SetWindowSize(ivec2 size); | void SetWindowSize(ivec2 size); | ||||
| private: | private: | ||||
| uint64_t m_fd; | |||||
| uint64_t m_pid; | |||||
| int64_t m_fd; | |||||
| int64_t m_pid; | |||||
| char const *m_argv[2]; | char const *m_argv[2]; | ||||
| ivec2 m_size; | ivec2 m_size; | ||||
| }; | }; | ||||
| @@ -7,7 +7,6 @@ | |||||
| #endif | #endif | ||||
| #include "core.h" | #include "core.h" | ||||
| #include "lolgl.h" | |||||
| using namespace std; | using namespace std; | ||||
| using namespace lol; | using namespace lol; | ||||
| @@ -19,6 +18,14 @@ Term::Term(ivec2 size) | |||||
| : m_time(0.f) | : m_time(0.f) | ||||
| { | { | ||||
| m_caca = caca_create_canvas(size.x, size.y); | m_caca = caca_create_canvas(size.x, size.y); | ||||
| #if defined HAVE_PTY_H || defined HAVE_UTIL_H || defined HAVE_LIBUTIL_H | |||||
| m_pty = new Pty(size); | |||||
| char const *shell = getenv("SHELL"); | |||||
| if (!shell) | |||||
| shell = "/bin/sh"; | |||||
| m_pty->Run(shell); | |||||
| #endif | |||||
| } | } | ||||
| void Term::TickGame(float seconds) | void Term::TickGame(float seconds) | ||||
| @@ -29,7 +36,15 @@ void Term::TickGame(float seconds) | |||||
| /* This is the real terminal code */ | /* This is the real terminal code */ | ||||
| /* XXX: for now we draw fancy shit */ | /* XXX: for now we draw fancy shit */ | ||||
| m_time += seconds; | m_time += seconds; | ||||
| DrawFancyShit(); | |||||
| for (;;) | |||||
| { | |||||
| char buf[BUFSIZ]; | |||||
| size_t bytes = m_pty->ReadData(buf, BUFSIZ); | |||||
| if (bytes <= 0) | |||||
| break; | |||||
| ReadAnsi(buf, bytes); | |||||
| } | |||||
| #else | #else | ||||
| /* Unsupported platform - draw some fancy shit instead */ | /* Unsupported platform - draw some fancy shit instead */ | ||||
| m_time += seconds; | m_time += seconds; | ||||
| @@ -44,6 +59,10 @@ void Term::TickDraw(float seconds) | |||||
| Term::~Term() | Term::~Term() | ||||
| { | { | ||||
| #if defined HAVE_PTY_H || defined HAVE_UTIL_H || defined HAVE_LIBUTIL_H | |||||
| delete m_pty; | |||||
| #endif | |||||
| caca_free_canvas(m_caca); | |||||
| } | } | ||||
| /* | /* | ||||
| @@ -7,6 +7,80 @@ | |||||
| #include "term/pty.h" | #include "term/pty.h" | ||||
| struct Iso2022Conversion | |||||
| { | |||||
| Iso2022Conversion() { Reset(); } | |||||
| void Reset(); | |||||
| /* cs = coding system/coding method: */ | |||||
| /* (with standard return) */ | |||||
| /* '@' = ISO-2022, */ | |||||
| /* 'G' = UTF-8 without implementation level, */ | |||||
| /* '8' = UTF-8 (Linux console and imitators), */ | |||||
| /* and many others that are rarely used; */ | |||||
| /* (without standard return) */ | |||||
| /* '/G' = UTF-8 Level 1, */ | |||||
| /* '/H' = UTF-8 Level 2, */ | |||||
| /* '/I' = UTF-8 Level 3, */ | |||||
| /* and many others that are rarely used */ | |||||
| uint32_t cs; | |||||
| /* ctrl8bit = allow 8-bit controls */ | |||||
| uint8_t ctrl8bit; | |||||
| /* cn[0] = C0 control charset (0x00 ... 0x1f): | |||||
| * '@' = ISO 646, | |||||
| * '~' = empty, | |||||
| * and many others that are rarely used */ | |||||
| /* cn[1] = C1 control charset (0x80 ... 0x9f): | |||||
| * 'C' = ISO 6429-1983, | |||||
| * '~' = empty, | |||||
| * and many others that are rarely used */ | |||||
| uint32_t cn[2]; | |||||
| /* glr[0] = GL graphic charset (94-char. 0x21 ... 0x7e, | |||||
| * 94x94-char. 0x21/0x21 ... 0x7e/0x7e), | |||||
| * and | |||||
| * glr[1] = GR graphic charset (94-char. 0xa1 ... 0xfe, | |||||
| * 96-char. 0xa0 ... 0xff, | |||||
| * 94x94-char. 0xa1/0xa1 ... 0xfe/0xfe, | |||||
| * 96x96-char. 0xa0/0xa0 ... 0xff/0xff): | |||||
| * 0 = G0, 1 = G1, 2 = G2, 3 = G3 */ | |||||
| uint8_t glr[2]; | |||||
| /* gn[i] = G0/G1/G2/G3 graphic charset state: | |||||
| * (94-char. sets) | |||||
| * '0' = DEC ACS (VT100 and imitators), | |||||
| * 'B' = US-ASCII, | |||||
| * and many others that are rarely used for e.g. various national ASCII variations; | |||||
| * (96-char. sets) | |||||
| * '.A' = ISO 8859-1 "Latin 1" GR, | |||||
| * '.~' = empty 96-char. set, | |||||
| * and many others that are rarely used for e.g. ISO 8859-n GR; | |||||
| * (double-byte 94x94-charsets) | |||||
| * '$@' = Japanese Character Set ("old JIS") (JIS C 6226:1978), | |||||
| * '$A' = Chinese Character Set (GB 2312), | |||||
| * '$B' = Japanese Character Set (JIS X0208/JIS C 6226:1983), | |||||
| * '$C' = Korean Graphic Character Set (KSC 5601:1987), | |||||
| * '$D' = Supplementary Japanese Graphic Character Set (JIS X0212), | |||||
| * '$E' = CCITT Chinese Set (GB 2312 + GB 8565), | |||||
| * '$G' = CNS 11643 plane 1, | |||||
| * '$H' = CNS 11643 plane 2, | |||||
| * '$I' = CNS 11643 plane 3, | |||||
| * '$J' = CNS 11643 plane 4, | |||||
| * '$K' = CNS 11643 plane 5, | |||||
| * '$L' = CNS 11643 plane 6, | |||||
| * '$M' = CNS 11643 plane 7, | |||||
| * '$O' = JIS X 0213 plane 1, | |||||
| * '$P' = JIS X 0213 plane 2, | |||||
| * '$Q' = JIS X 0213-2004 Plane 1, | |||||
| * and many others that are rarely used for e.g. traditional | |||||
| * ideographic Vietnamese and BlissSymbolics; | |||||
| * (double-byte 96x96-charsets) | |||||
| * none standardized or in use on terminals AFAIK (Mule does use | |||||
| * some internally) | |||||
| */ | |||||
| uint32_t gn[4]; | |||||
| /* ss = single-shift state: 0 = GL, 2 = G2, 3 = G3 */ | |||||
| uint8_t ss; | |||||
| }; | |||||
| class Term : public Entity | class Term : public Entity | ||||
| { | { | ||||
| public: | public: | ||||
| @@ -20,11 +94,35 @@ protected: | |||||
| virtual void TickGame(float seconds); | virtual void TickGame(float seconds); | ||||
| virtual void TickDraw(float seconds); | virtual void TickDraw(float seconds); | ||||
| private: | |||||
| /* Terminal emulation main entry point */ | |||||
| size_t ReadAnsi(void const *data, size_t size); | |||||
| size_t SendAnsi(char const *str); | |||||
| /* Utility functions for terminal emulation */ | |||||
| void ReadGrcm(unsigned int argc, unsigned int const *argv); | |||||
| inline int ReadChar(unsigned char c, int *x, int *y); | |||||
| inline int ReadDuplet(unsigned char const *buffer, unsigned int *skip, | |||||
| int top, int bottom, int width, int height); | |||||
| private: | private: | ||||
| Pty *m_pty; | Pty *m_pty; | ||||
| caca_canvas_t *m_caca; | caca_canvas_t *m_caca; | ||||
| ivec2 m_size; | ivec2 m_size; | ||||
| /* Terminal attributes */ | |||||
| char *m_title; | |||||
| int m_bell, m_init, m_report_mouse; | |||||
| int m_changed; /* content was updated */ | |||||
| Iso2022Conversion m_conv_state; /* charset mess */ | |||||
| uint8_t m_fg, m_bg; /* ANSI-context fg/bg */ | |||||
| uint8_t m_dfg, m_dbg; /* Default fg/bg */ | |||||
| uint8_t m_bold, m_blink, m_italics, m_negative, m_concealed, m_underline; | |||||
| uint8_t m_faint, m_strike, m_proportional; /* unsupported */ | |||||
| uint32_t m_clearattr; | |||||
| /* Mostly for fancy shit */ | /* Mostly for fancy shit */ | ||||
| void DrawFancyShit(); | void DrawFancyShit(); | ||||
| float m_time; | float m_time; | ||||