/*************************************************************************** cterm.c (c) 2000-2017 BenoƮt Minisini This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ***************************************************************************/ #define __CTERM_C #include "main.h" #include #include "cterm.h" #define STREAM_FD (GB.Stream.Handle(GB.Stream.Get(_object))) #define THIS_SETTINGS ((CTERMINALSETTINGS *)_object) #define SETTINGS THIS_SETTINGS->settings static bool check_error(int ret) { if (ret) { GB.Error(strerror(errno)); return TRUE; } else return FALSE; } /*static bool _convert(CTERMINAL *_object, GB_TYPE type, GB_VALUE *conv) { if (!THIS && type >= GB_T_OBJECT && GB.Is(conv->_object.value, GB.FindClass("Stream"))) { } return TRUE; switch(type) { case GB_T_FLOAT: conv->_object.value = COMPLEX_create(conv->_float.value, 0); return FALSE; case GB_T_SINGLE: conv->_object.value = COMPLEX_create(conv->_single.value, 0); return FALSE; case GB_T_LONG: conv->_object.value = COMPLEX_create((double)conv->_long.value, 0); return FALSE; case GB_T_INTEGER: case GB_T_SHORT: case GB_T_BYTE: conv->_object.value = COMPLEX_create(conv->_integer.value, 0); return FALSE; default: return TRUE; } }*/ //--------------------------------------------------------------------------- static CTERMINALSETTINGS *TERMINALSETTINGS_copy(CTERMINALSETTINGS *_object) { CTERMINALSETTINGS *settings; settings = (CTERMINALSETTINGS *)GB.New(GB.FindClass("TerminalSettings"), NULL, NULL); settings->settings = SETTINGS; return settings; } BEGIN_METHOD_VOID(TerminalSettings_MakeRaw) CTERMINALSETTINGS *settings = TERMINALSETTINGS_copy(THIS_SETTINGS); cfmakeraw(&SETTINGS); GB.ReturnObject(settings); END_METHOD BEGIN_METHOD_VOID(TerminalSettings_Copy) GB.ReturnObject(TERMINALSETTINGS_copy(THIS_SETTINGS)); END_METHOD static void handle_settings(tcflag_t *pflag, void *_param, int cst) { if (READ_PROPERTY) GB.ReturnBoolean(*pflag & cst); else { if (VPROP(GB_BOOLEAN)) *pflag |= cst; else *pflag &= ~cst; } } static void handle_settings_int(tcflag_t *pflag, void *_param, int mask) { if (READ_PROPERTY) GB.ReturnInteger(*pflag & mask); else { *pflag &= ~mask; *pflag |= VPROP(GB_INTEGER) & mask; } } static void handle_settings_char(cc_t pcc[], void *_param, int pos) { if (READ_PROPERTY) GB.ReturnInteger(pcc[pos]); else pcc[pos] = (cc_t)VPROP(GB_INTEGER); } #define IMPLEMENT_TSP(_name, _field) \ BEGIN_PROPERTY(TerminalSettings_##_name) \ handle_settings(&SETTINGS._field, _param, _name); \ END_PROPERTY #define IMPLEMENT_TSP_I(_name, _field) \ BEGIN_PROPERTY(TerminalSettings_##_name) \ handle_settings_int(&SETTINGS._field, _param, _name); \ END_PROPERTY #define IMPLEMENT_TSP_C(_name) \ BEGIN_PROPERTY(TerminalSettings_##_name) \ handle_settings_char(SETTINGS.c_cc, _param, _name); \ END_PROPERTY IMPLEMENT_TSP(IGNBRK, c_iflag) IMPLEMENT_TSP(BRKINT, c_iflag) IMPLEMENT_TSP(IGNPAR, c_iflag) IMPLEMENT_TSP(PARMRK, c_iflag) IMPLEMENT_TSP(INPCK, c_iflag) IMPLEMENT_TSP(ISTRIP, c_iflag) IMPLEMENT_TSP(INLCR, c_iflag) IMPLEMENT_TSP(IGNCR, c_iflag) IMPLEMENT_TSP(ICRNL, c_iflag) IMPLEMENT_TSP(IXON, c_iflag) IMPLEMENT_TSP(IXANY, c_iflag) IMPLEMENT_TSP(IXOFF, c_iflag) #ifndef OS_BSD IMPLEMENT_TSP(IUCLC, c_iflag) IMPLEMENT_TSP(IUTF8, c_iflag) IMPLEMENT_TSP(OLCUC, c_oflag) IMPLEMENT_TSP(OFILL, c_oflag) #endif IMPLEMENT_TSP(OPOST, c_oflag) IMPLEMENT_TSP(ONLCR, c_oflag) IMPLEMENT_TSP(OCRNL, c_oflag) IMPLEMENT_TSP(ONOCR, c_oflag) IMPLEMENT_TSP(ONLRET, c_oflag) #ifndef OS_BSD IMPLEMENT_TSP_I(NLDLY, c_oflag) IMPLEMENT_TSP_I(CRDLY, c_oflag) IMPLEMENT_TSP_I(TABDLY, c_oflag) IMPLEMENT_TSP_I(BSDLY, c_oflag) IMPLEMENT_TSP_I(VTDLY, c_oflag) IMPLEMENT_TSP_I(FFDLY, c_oflag) #endif IMPLEMENT_TSP_I(CSIZE, c_cflag) IMPLEMENT_TSP(CSTOPB, c_cflag) IMPLEMENT_TSP(CREAD, c_cflag) IMPLEMENT_TSP(PARENB, c_cflag) IMPLEMENT_TSP(PARODD, c_cflag) IMPLEMENT_TSP(HUPCL, c_cflag) IMPLEMENT_TSP(CLOCAL, c_cflag) IMPLEMENT_TSP(CRTSCTS, c_cflag) IMPLEMENT_TSP(ISIG, c_lflag) IMPLEMENT_TSP(ICANON, c_lflag) IMPLEMENT_TSP(ECHO, c_lflag) IMPLEMENT_TSP(ECHOE, c_lflag) IMPLEMENT_TSP(ECHOK, c_lflag) IMPLEMENT_TSP(ECHONL, c_lflag) IMPLEMENT_TSP(ECHOCTL, c_lflag) IMPLEMENT_TSP(ECHOKE, c_lflag) IMPLEMENT_TSP(FLUSHO, c_lflag) IMPLEMENT_TSP(NOFLSH, c_lflag) IMPLEMENT_TSP(TOSTOP, c_lflag) IMPLEMENT_TSP(IEXTEN, c_lflag) #ifdef OS_LINUX #ifndef CMSPAR // This is a MIPS fix #define CMSPAR 010000000000 #endif IMPLEMENT_TSP(CMSPAR, c_cflag) IMPLEMENT_TSP(XCASE, c_lflag) #endif #ifndef OS_CYGWIN IMPLEMENT_TSP(ECHOPRT, c_lflag) IMPLEMENT_TSP(PENDIN, c_lflag) #endif IMPLEMENT_TSP_C(VDISCARD) IMPLEMENT_TSP_C(VEOF) IMPLEMENT_TSP_C(VEOL) IMPLEMENT_TSP_C(VEOL2) IMPLEMENT_TSP_C(VERASE) IMPLEMENT_TSP_C(VINTR) IMPLEMENT_TSP_C(VKILL) IMPLEMENT_TSP_C(VLNEXT) IMPLEMENT_TSP_C(VMIN) IMPLEMENT_TSP_C(VQUIT) IMPLEMENT_TSP_C(VREPRINT) IMPLEMENT_TSP_C(VSTART) IMPLEMENT_TSP_C(VSTOP) IMPLEMENT_TSP_C(VSUSP) IMPLEMENT_TSP_C(VTIME) IMPLEMENT_TSP_C(VWERASE) BEGIN_PROPERTY(TerminalSettings_InputSpeed) if (READ_PROPERTY) GB.ReturnInteger(cfgetispeed(&SETTINGS)); else cfsetispeed(&SETTINGS, VPROP(GB_INTEGER)); END_PROPERTY BEGIN_PROPERTY(TerminalSettings_OutputSpeed) if (READ_PROPERTY) GB.ReturnInteger(cfgetospeed(&SETTINGS)); else cfsetospeed(&SETTINGS, VPROP(GB_INTEGER)); END_PROPERTY //--------------------------------------------------------------------------- BEGIN_PROPERTY(StreamTerm_Name) GB.ReturnNewZeroString(ttyname(STREAM_FD)); END_PROPERTY BEGIN_METHOD_VOID(StreamTerm_GetAttr) CTERMINALSETTINGS *settings; //fprintf(stderr, "fd = %d\n", STREAM_FD); settings = (CTERMINALSETTINGS *)GB.New(GB.FindClass("TerminalSettings"), NULL, NULL); if (check_error(tcgetattr(STREAM_FD, &settings->settings))) { GB.Unref(POINTER(&settings)); return; } GB.ReturnObject(settings); END_PROPERTY BEGIN_METHOD(StreamTerm_SetAttr, GB_INTEGER mode; GB_OBJECT settings) CTERMINALSETTINGS *settings; struct termios check; settings = (CTERMINALSETTINGS *)VARG(settings); if (GB.CheckObject(settings)) return; check_error(tcsetattr(STREAM_FD, VARG(mode), &settings->settings)); tcgetattr(STREAM_FD, &check); if (check.c_iflag != settings->settings.c_iflag || check.c_oflag != settings->settings.c_oflag || check.c_lflag != settings->settings.c_lflag) GB.Error("Unable to set terminal attributes"); END_PROPERTY BEGIN_METHOD(StreamTerm_Flush, GB_INTEGER mode) check_error(tcflush(STREAM_FD, VARG(mode))); END_METHOD BEGIN_METHOD_VOID(StreamTerm_Drain) check_error(tcdrain(STREAM_FD)); END_METHOD BEGIN_METHOD(StreamTerm_Flow, GB_INTEGER mode) check_error(tcflow(STREAM_FD, VARG(mode))); END_METHOD BEGIN_METHOD_VOID(StreamTerm_SendBreak) check_error(tcsendbreak(STREAM_FD, 0)); END_METHOD /*BEGIN_PROPERTY(Terminal_Control) GB.ReturnNewZeroString(ctermid(NULL)); END_PROPERTY*/ //--------------------------------------------------------------------------- #define __TC(_name) GB_CONSTANT(#_name, "i", _name) GB_DESC TermDesc[] = { GB_DECLARE_STATIC("Term"), __TC(TCSANOW), __TC(TCSADRAIN), __TC(TCSAFLUSH), __TC(TCIFLUSH), __TC(TCOFLUSH), __TC(TCIOFLUSH), __TC(TCIOFF), __TC(TCION), __TC(TCOOFF), __TC(TCOON), #ifndef OS_BSD __TC(NL0), __TC(NL1), __TC(CR0), __TC(CR1), __TC(CR2), __TC(CR3), __TC(TAB0), __TC(TAB1), __TC(TAB2), __TC(TAB3), __TC(XTABS), __TC(BS0), __TC(BS1), __TC(VT0), __TC(VT1), __TC(FF0), __TC(FF1), #endif __TC(CS5), __TC(CS6), __TC(CS7), __TC(CS8), GB_CONSTANT("VDISABLE", "i", _POSIX_VDISABLE), __TC(B0), __TC(B50), __TC(B75), __TC(B110), __TC(B134), __TC(B150), __TC(B200), __TC(B300), __TC(B600), __TC(B1200), __TC(B1800), __TC(B2400), __TC(B4800), __TC(B9600), __TC(B19200), __TC(B38400), __TC(B57600), __TC(B115200), __TC(B230400), #ifndef OS_BSD __TC(B460800), __TC(B500000), __TC(B576000), __TC(B921600), __TC(B1000000), __TC(B1152000), __TC(B1500000), __TC(B2000000), __TC(B2500000), __TC(B3000000), #endif #ifdef OS_LINUX __TC(B3500000), __TC(B4000000), #endif GB_END_DECLARE }; #define __TSP(_name) GB_PROPERTY(#_name, "b", TerminalSettings_##_name) #define __TSP_I(_name) GB_PROPERTY(#_name, "i", TerminalSettings_##_name) GB_DESC TerminalSettingsDesc[] = { GB_DECLARE("TerminalSettings", sizeof(CTERMINALSETTINGS)), GB_NOT_CREATABLE(), __TSP(IGNBRK), __TSP(BRKINT), __TSP(IGNPAR), __TSP(PARMRK), __TSP(INPCK), __TSP(ISTRIP), __TSP(INLCR), __TSP(IGNCR), __TSP(ICRNL), __TSP(IXON), __TSP(IXANY), __TSP(IXOFF), #ifndef OS_BSD __TSP(IUCLC), __TSP(IUTF8), __TSP(OLCUC), __TSP(OFILL), #endif __TSP(OPOST), __TSP(ONLCR), __TSP(OCRNL), __TSP(ONOCR), __TSP(ONLRET), #ifndef OS_BSD __TSP_I(NLDLY), __TSP_I(CRDLY), __TSP_I(TABDLY), __TSP_I(BSDLY), __TSP_I(VTDLY), __TSP_I(FFDLY), #endif __TSP_I(CSIZE), __TSP(CSTOPB), __TSP(CREAD), __TSP(PARENB), __TSP(PARODD), __TSP(HUPCL), __TSP(CLOCAL), __TSP(CRTSCTS), __TSP(ISIG), __TSP(ICANON), __TSP(ECHO), __TSP(ECHOE), __TSP(ECHOK), __TSP(ECHONL), __TSP(ECHOCTL), __TSP(ECHOKE), __TSP(FLUSHO), __TSP(NOFLSH), __TSP(TOSTOP), __TSP(IEXTEN), #ifdef OS_LINUX __TSP(CMSPAR), __TSP(XCASE), #endif #ifndef OS_CYGWIN __TSP(ECHOPRT), __TSP(PENDIN), #endif __TSP_I(VDISCARD), __TSP_I(VEOF), __TSP_I(VEOL), __TSP_I(VEOL2), __TSP_I(VERASE), __TSP_I(VINTR), __TSP_I(VKILL), __TSP_I(VLNEXT), __TSP_I(VMIN), __TSP_I(VQUIT), __TSP_I(VREPRINT), __TSP_I(VSTART), __TSP_I(VSTOP), __TSP_I(VSUSP), __TSP_I(VTIME), __TSP_I(VWERASE), GB_PROPERTY("InputSpeed", "i", TerminalSettings_InputSpeed), GB_PROPERTY("OutputSpeed", "i", TerminalSettings_OutputSpeed), GB_METHOD("MakeRaw", "TerminalSettings", TerminalSettings_MakeRaw, NULL), GB_METHOD("Copy", "TerminalSettings", TerminalSettings_Copy, NULL), GB_END_DECLARE }; GB_DESC StreamTermDesc[] = { GB_DECLARE_VIRTUAL(".Stream.Term"), //GB_STATIC_PROPERTY_READ("Control", "s", Terminal_Control), GB_METHOD("Flush", NULL, StreamTerm_Flush, "(Mode)i"), GB_METHOD("Drain", NULL, StreamTerm_Drain, NULL), GB_METHOD("Flow", NULL, StreamTerm_Flow, "(Mode)i"), GB_METHOD("SendBreak", NULL, StreamTerm_SendBreak, NULL), GB_METHOD("GetAttr", "TerminalSettings", StreamTerm_GetAttr, NULL), GB_METHOD("SetAttr", NULL, StreamTerm_SetAttr, "(Mode)i(Settings)TerminalSettings;"), //GB_INTERFACE("_convert", &_convert), GB_END_DECLARE };