// --------------------------------------------------------------------------- // - ctrm.cxx - // - standard system library : c terminal function implementation - // --------------------------------------------------------------------------- // - This program is free software; you can redistribute it and/or modify - // - it provided that this copyright notice is kept intact. - // - - // - 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. In no event shall - // - the copyright holder be liable for any direct, indirect, incidental or - // - special damages arising in any way out of the use of this software. - // --------------------------------------------------------------------------- // - copyright (c) 1999-2007 amaury darsch - // --------------------------------------------------------------------------- #include "csio.hpp" #include "cstr.hpp" #include "ccnv.hpp" #include "ctrm.hpp" #include "ctrm.hxx" #ifdef AFNIX_HAVE_NONCONST_TIGET namespace afnix { // get capability flag static bool c_tigetflag (const char* capname) { char* buf = const_cast (capname); int val = tigetflag (buf); return (val <= 0) ? false : true; } // get capability string static char* c_tigetstr (const char* capname) { char* buf = const_cast (capname); char* ptr = tigetstr (buf); return (ptr == (char*)-1) ? nilp : ptr; } } #else namespace afnix { // get capability flag static bool c_tigetflag (const char* capname) { int val = tigetflag (capname); return (val <= 0) ? false : true; } // get capability string static char* c_tigetstr (const char* capname) { char* ptr = tigetstr (capname); return (ptr == (char*)-1) ? nilp : ptr; } } #endif #ifdef AFNIX_HAVE_COMPLEX_TPARM namespace afnix { static char* c_tparm_0 (char* data) { return tparm (data,0,0,0,0,0,0,0,0,0); } static char* c_tparm_1 (char* data, long p0) { return tparm (data,p0,0,0,0,0,0,0,0,0); } } #else namespace afnix { static char* c_tparm_0 (char* data) { return tparm (data); } static char* c_tparm_1 (char* data, long p0) { return tparm (data, p0); } } #endif #ifdef AFNIX_DELETE_ISBS namespace afnix { // change the backspace setting static void set_delete_isbs (char** tinfo) { tinfo[ITERM_BACKSPACE] = c_strmak (delc); } } #else namespace afnix { // change the backspace setting static void set_delete_isbs (char** tinfo) { if (tinfo[ITERM_BACKSPACE] == nilp) tinfo[ITERM_BACKSPACE] = c_strmak (bspc); } } #endif namespace afnix { // check if the stream id is a terminal bool c_istty (const int sid) { return (isatty (sid) == 1) ? true : false; } // get the terminal attributes void* c_gtattr (const int sid) { struct termios* tattr = new struct termios; // check for terminal first if (c_istty (sid) == false) return nilp; // get the terminal attributes if (tcgetattr (sid, tattr) != 0) return nilp; return tattr; } // set the terminal attributes void c_stattr (const int sid, void* tattr) { // check for structure and tty if (tattr == nilp) return; if (c_istty (sid) == false) return; // set terminal attributes tcsetattr (sid, TCSANOW, (struct termios*) tattr); } // reset terminal mode - put in non canonical mode bool c_stcanon (const int sid) { // check for terminal first if (c_istty (sid) == false) return false; // reset canonical mode and echo struct termios tattr; tcgetattr (STDIN_FILENO, &tattr); tattr.c_lflag &= ~(ICANON|ECHO); tattr.c_cc[VMIN] = 1; tattr.c_cc[VTIME] = 0; if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &tattr) != 0) return false; return true; } // this function checks if a string is bounded in the tinfo array static bool check_tinfo (char** tinfo, long size, const char* name) { for (long i = 0; i < size; i++) if (c_strcmp (tinfo[i], name) == true) return true; return false; } // these functions fix some inconsistencies in the terminfo/termcap world // this is only coming from various experiments static char** fix_tinfo_input (char** tinfo) { // fix delete character set_delete_isbs (tinfo); // fix arrows and delete if (check_tinfo (tinfo, ITERM_PARMS_MAX, XTERM_ARROW_UP) == false) tinfo[ITERM_STD_UP] = c_strdup (XTERM_ARROW_UP); if (check_tinfo (tinfo, ITERM_PARMS_MAX, XTERM_ARROW_DOWN) == false) tinfo[ITERM_STD_DOWN] = c_strdup (XTERM_ARROW_DOWN); if (check_tinfo (tinfo, ITERM_PARMS_MAX, XTERM_ARROW_RIGHT) == false) tinfo[ITERM_STD_RIGHT] = c_strdup (XTERM_ARROW_RIGHT); if (check_tinfo (tinfo, ITERM_PARMS_MAX, XTERM_ARROW_LEFT) == false) tinfo[ITERM_STD_LEFT ] = c_strdup (XTERM_ARROW_LEFT); if (check_tinfo (tinfo, ITERM_PARMS_MAX, XTERM_DELETE_KEY) == false) tinfo[ITERM_STD_DELETE] = c_strdup (XTERM_DELETE_KEY); if (check_tinfo (tinfo, ITERM_PARMS_MAX, XTERM_INSERT_KEY) == false) tinfo[ITERM_STD_INSERT] = c_strdup (XTERM_INSERT_KEY); // and hopefully, it is working return tinfo; } static char** fix_tinfo_output (char** tinfo) { // check for cub1 - if not set we use arrow left if (c_strlen (tinfo[OTERM_MOVE_LEFT]) == 0) tinfo[OTERM_MOVE_LEFT] = c_strdup (XTERM_ARROW_LEFT); // check for cuf1 - if not set we use the standard right arrow if (c_strlen (tinfo[OTERM_MOVE_RIGHT]) == 0) tinfo[OTERM_MOVE_RIGHT] = c_strdup (XTERM_ARROW_RIGHT); // check for cuu1 - if not set we use the standard up arrow if (c_strlen (tinfo[OTERM_MOVE_UP]) == 0) tinfo[OTERM_MOVE_UP] = c_strdup (XTERM_ARROW_UP); // check for cud1 - if not set we use the standard up arrow if (c_strlen (tinfo[OTERM_MOVE_DOWN]) == 0) tinfo[OTERM_MOVE_DOWN] = c_strdup (XTERM_ARROW_DOWN); // check that we can fix background colors if (c_strlen (tinfo[OTERM_RESET_COLOR]) == 0) { delete [] tinfo[OTERM_SETFG_MODE]; delete [] tinfo[OTERM_RESET_COLOR]; tinfo[OTERM_SETFG_MODE] = nilp; tinfo[OTERM_RESET_COLOR] = nilp; } // hopefully, we are set return tinfo; } // return an array of terminal capabilities char** c_tinfo (bool imode) { int status = 0; // read terminfo database if (setupterm (getenv ("TERM"),STDOUT_FILENO,&status) != OK) return nilp; // create an array of capabilities and initialize it long len = imode ? ITERM_PARMS_MAX : OTERM_PARMS_MAX; char** result = new char*[len]; for (long i = 0; i < len; i++) result[i] = nilp; // query input capabilities if (imode == true) { result[ITERM_BACKSPACE] = c_strdup (c_tigetstr ("kbs")); result[ITERM_DELETE] = c_strdup (c_tigetstr ("kdch1")); result[ITERM_ARROW_UP] = c_strdup (c_tigetstr ("kcuu1")); result[ITERM_ARROW_DOWN] = c_strdup (c_tigetstr ("kcud1")); result[ITERM_ARROW_LEFT] = c_strdup (c_tigetstr ("kcub1")); result[ITERM_ARROW_RIGHT] = c_strdup (c_tigetstr ("kcuf1")); result[ITERM_INSERT_KEY] = c_strdup (c_tigetstr ("kich1")); result[ITERM_STD_UP] = nilp; result[ITERM_STD_DOWN] = nilp; result[ITERM_STD_RIGHT] = nilp; result[ITERM_STD_LEFT] = nilp; result[ITERM_STD_DELETE] = nilp; result[ITERM_STD_INSERT] = nilp; } else { result[OTERM_DELETE_CHAR] = c_strdup (c_tigetstr ("dch1")); result[OTERM_MOVE_LEFT] = c_strdup (c_tigetstr ("cub1")); result[OTERM_MOVE_RIGHT] = c_strdup (c_tigetstr ("cuf1")); result[OTERM_MOVE_UP] = c_strdup (c_tigetstr ("cuu1")); result[OTERM_MOVE_DOWN] = c_strdup (c_tigetstr ("cud1")); result[OTERM_MOVE_BOL] = c_strdup (c_tigetstr ("cr")); result[OTERM_INSERT_CHAR] = c_strdup (c_tigetstr ("ich1")); result[OTERM_IMODE_START] = c_strdup (c_tigetstr ("smir")); result[OTERM_IMODE_END] = c_strdup (c_tigetstr ("rmir")); result[OTERM_SETFG_MODE] = c_strdup (c_tigetstr ("setaf")); result[OTERM_RESET_COLOR] = c_strdup (c_tigetstr ("oc")); result[OTERM_CLEAR_SCREEN] = c_strdup (c_tigetstr ("clear")); // local fix for color if (c_strlen (result[OTERM_RESET_COLOR]) == 0) result[OTERM_RESET_COLOR] = c_strdup (c_tigetstr ("op")); } // here is our array return imode ? fix_tinfo_input (result) : fix_tinfo_output (result); } // return an array of terminal capabilities flag bool* c_tbool (void) { int status = 0; // read terminfo database if (setupterm (getenv ("TERM"),STDOUT_FILENO,&status) != OK) return nilp; // create an array of capabilities and initialize it bool* result = new bool [BTERM_PARMS_MAX]; // query capabilities result[BTERM_AUTO_WRAP] = c_tigetflag ("am") && c_tigetflag ("xn"); // the array of capabilities return result; } // return true if a parameter is valid bool c_tpvld (char** tinfo, const long index, const bool mode) { // check terminal info and index if ((tinfo == nilp) || (index < 0)) return false; // check bound based on mode if ((mode == true) && (index >= OTERM_PARMS_MAX)) return false; if ((mode == false) && (index >= ITERM_PARMS_MAX)) return false; // check parameter if (c_strlen (tinfo[index]) == 0) return false; return true; } // send a character to the standard output void c_tparm (const int sid, char** tinfo, const long index) { if ((tinfo == nilp) || (index < 0) || (index >= OTERM_PARMS_MAX)) return; char* data = tinfo[index]; if (data == nilp) return; char* buffer = c_tparm_0 (data); long length = c_strlen (buffer); c_write (sid,buffer,length); } // turn on/off the terminal error mode void c_temode (const int sid, char** tinfo, const bool mode) { if (tinfo == nilp) return; char* setaf = tinfo[OTERM_SETFG_MODE]; char* rstaf = tinfo[OTERM_RESET_COLOR]; if ((setaf == nilp) || (rstaf == nilp)) return; char* buffer = mode ? c_tparm_1 (setaf,1) : c_tparm_0 (rstaf); long length = c_strlen (buffer); c_write (sid,buffer,length); } } #ifdef AFNIX_HAVE_WINSIZE namespace afnix { // get the number of columns for a tty long c_getcols (const int sid) { // try ioctl first if (c_istty (sid) == true) { struct winsize size; if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) == 0) { long cols = (long) size.ws_col; if (cols != 0) return cols; } } // may be the environment will help us !!! bool status = true; long cols = c_atoll (getenv ("COLUMNS"), status); if ((status == true) && (cols != 0)) return cols; // nothing match so we return 0 return 0; } } #endif #ifdef AFNIX_HAVE_DELTERM namespace afnix { // free the terminal attributes structure void c_ftattr (void* ptr) { struct termios* tattr = (struct termios*) ptr; delete tattr; del_curterm (cur_term); } } #else namespace afnix { // free the terminal attributes structure void c_ftattr (void* ptr) { struct termios* tattr = (struct termios*) ptr; delete tattr; } } #endif