aboutsummaryrefslogtreecommitdiffstats
path: root/cursor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cursor.cpp')
-rw-r--r--cursor.cpp1477
1 files changed, 1477 insertions, 0 deletions
diff --git a/cursor.cpp b/cursor.cpp
new file mode 100644
index 0000000..1dde81a
--- /dev/null
+++ b/cursor.cpp
@@ -0,0 +1,1477 @@
+// cursor.cpp
+// Revision 24-apr-2009
+
+#include "cursor.h"
+
+#include "blassic.h"
+
+#include "key.h"
+#include "util.h"
+#include "error.h"
+#include "showerror.h"
+
+#include "trace.h"
+
+#include <iostream>
+using std::cerr;
+using std::endl;
+
+#include <map>
+#include <queue>
+#include <sstream>
+
+#include <string.h>
+
+#ifdef BLASSIC_USE_WINDOWS
+
+
+#include <windows.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if defined HAVE_IO_H || ! defined BLASSIC_CONFIG
+#include <io.h>
+#endif
+
+
+#else
+
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <cassert>
+#define ASSERT assert
+
+#include <termios.h>
+
+// We check for terminfo only if not in windows,
+// use windows console functions even in Cygwin.
+
+// Now curses can be disabled from configure.
+#ifndef BLASSIC_CONFIG_NO_CURSES
+
+#ifdef BLASSIC_CONFIG_USE_NCURSES
+
+#include <ncurses.h>
+
+#elif defined BLASSIC_CONFIG_USE_CURSES
+
+#include <curses.h>
+
+#else
+
+#error Bad configuration of curses options.
+
+#endif
+
+#ifdef HAVE_TERM_H
+// I suppose that if this is not availabe, then is not required.
+#include <term.h>
+#endif
+
+#define BLASSIC_USE_TERMINFO
+
+// curses can define erase as macro, invalidating string::erase.
+#ifdef erase
+#undef erase
+#endif
+// curses can define bool as macro.
+#ifdef bool
+#undef bool
+#endif
+
+#endif
+
+
+// Stuff needed by getwidth
+
+#include <sys/ioctl.h>
+#include <termios.h>
+
+// This is from ncurses.
+#ifdef TIOCGSIZE
+# define IOCTL_WINSIZE TIOCGSIZE
+# define STRUCT_WINSIZE struct ttysize
+# define WINSIZE_ROWS(n) (int)n.ts_lines
+# define WINSIZE_COLS(n) (int)n.ts_cols
+#else
+# ifdef TIOCGWINSZ
+# define IOCTL_WINSIZE TIOCGWINSZ
+# define STRUCT_WINSIZE struct winsize
+# define WINSIZE_ROWS(n) (int)n.ws_row
+# define WINSIZE_COLS(n) (int)n.ws_col
+# endif
+#endif
+
+#endif
+
+#include <iostream>
+#include <map>
+
+using util::touch;
+
+
+namespace {
+
+using namespace cursor;
+
+
+#ifndef BLASSIC_USE_WINDOWS
+
+#ifdef BLASSIC_USE_TERMINFO
+
+bool fInit= true;
+
+int background= 8;
+
+const char
+ * strKeypadXmit= NULL, * strKeypadLocal= NULL,
+ * strCls= NULL, * strCup= NULL,
+ * strCursorNormal= NULL, * strCursorInvisible= NULL,
+ * strForeground= NULL, * strBackground= NULL,
+ * strEnterBold= NULL, * strExitBold= NULL,
+ * strMoveForward= NULL, * strMoveBack= NULL,
+ * strMoveForwardN= NULL, * strMoveBackN= NULL,
+ * strMoveUp= NULL, * strMoveDown= NULL,
+ * strMoveUpN= NULL, * strMoveDownN= NULL,
+ * strSaveCursorPos= NULL, * strRestoreCursorPos= NULL,
+ * strBell= NULL;
+
+const char * newstr (const char * str)
+{
+ if (str == NULL)
+ return NULL;
+ size_t l= strlen (str);
+ char *n= new char [l + 1];
+ strcpy (n, str);
+ return n;
+}
+
+inline const char * calltigetstr (const char * id)
+{
+ #ifdef BLASSIC_CONFIG_USE_NCURSES
+ const char * str= tigetstr ( (char *) id);
+ #else
+ char buffer [128];
+ char * area= buffer;
+ const char * str= tgetstr (const_cast <char *> (id), & area);
+ #endif
+ if (str == (char *) -1)
+ return NULL;
+ return str;
+}
+
+inline const char * mytigetstr (const char * id)
+{
+ return newstr (calltigetstr (id) );
+}
+
+int putfunc (int ic)
+{
+ char c= ic;
+ write (STDOUT_FILENO, & c, 1);
+ return c;
+}
+
+inline void calltputs (const char * str)
+{
+ if (str != NULL)
+ tputs (str, 1, putfunc);
+}
+
+inline void calltparm (const char * str, int n)
+{
+ if (str != NULL)
+ {
+ #ifdef BLASSIC_CONFIG_USE_NCURSES
+ calltputs (tparm ( (char *) str, n) );
+ #else
+ calltputs (tgoto ( (char *) str, n, 0) );
+ #endif
+ }
+}
+
+void initkeytable ();
+
+struct str_terminfo {
+ const char * & str;
+ const char * tinfoname;
+ str_terminfo (const char * & str, const char * tinfoname) :
+ str (str), tinfoname (tinfoname)
+ { }
+};
+
+#ifdef BLASSIC_CONFIG_USE_NCURSES
+
+const str_terminfo strinfo []= {
+ str_terminfo (strKeypadXmit, "smkx"),
+ str_terminfo (strKeypadLocal, "rmkx"),
+
+ str_terminfo (strCls, "clear" ),
+ str_terminfo (strCup, "cup" ),
+
+ str_terminfo (strCursorNormal, "cnorm" ),
+ str_terminfo (strCursorInvisible, "civis" ),
+
+ str_terminfo (strForeground, "setaf" ),
+ str_terminfo (strBackground, "setab" ),
+
+ str_terminfo (strEnterBold, "bold" ),
+ str_terminfo (strExitBold, "sgr0" ),
+
+ str_terminfo (strMoveForward, "cuf1" ),
+ str_terminfo (strMoveBack, "cub1" ),
+ str_terminfo (strMoveForwardN, "cuf" ),
+ str_terminfo (strMoveBackN, "cub" ),
+ str_terminfo (strMoveUp, "cuu1" ),
+ str_terminfo (strMoveDown, "cud1" ),
+ str_terminfo (strMoveUpN, "cuu" ),
+ str_terminfo (strMoveDownN, "cud" ),
+
+ str_terminfo (strSaveCursorPos, "sc" ),
+ str_terminfo (strRestoreCursorPos, "rc" ),
+
+ str_terminfo (strBell, "bel"),
+};
+
+#else
+
+const str_terminfo strinfo []= {
+ str_terminfo (strKeypadXmit, "ks"),
+ str_terminfo (strKeypadLocal, "ke"),
+
+ str_terminfo (strCls, "cl" ),
+ str_terminfo (strCup, "cm" ),
+
+ str_terminfo (strCursorNormal, "ve" ),
+ str_terminfo (strCursorInvisible, "vi" ),
+
+ str_terminfo (strForeground, "AF" ),
+ str_terminfo (strBackground, "AB" ),
+
+ str_terminfo (strEnterBold, "md" ),
+ str_terminfo (strExitBold, "me" ),
+
+ str_terminfo (strMoveForward, "nd" ),
+ str_terminfo (strMoveBack, "le" ),
+ str_terminfo (strMoveForwardN, "RI" ),
+ str_terminfo (strMoveBackN, "LE" ),
+ str_terminfo (strMoveUp, "up" ),
+ str_terminfo (strMoveDown, "do" ),
+ str_terminfo (strMoveUpN, "UP" ),
+ str_terminfo (strMoveDownN, "DO" ),
+
+ str_terminfo (strSaveCursorPos, "sc" ),
+ str_terminfo (strRestoreCursorPos, "rc" ),
+
+ str_terminfo (strBell, "bl"),
+};
+
+#endif
+
+#ifndef BLASSIC_CONFIG_USE_NCURSES
+
+char tgetent_buffer [1024];
+
+#endif
+
+void init ()
+{
+ TRACEFUNC (tr, "init");
+
+ fInit= false;
+ #ifdef BLASSIC_CONFIG_USE_NCURSES
+ {
+ int errret;
+ setupterm (0, 1, & errret);
+ }
+ #else
+ {
+ char * strterm= getenv ("TERM");
+ if (strterm != NULL && strterm [0] != '\0')
+ tgetent (tgetent_buffer, strterm);
+ }
+ #endif
+
+ for (size_t i= 0; i < util::dim_array (strinfo); ++i)
+ strinfo [i].str= mytigetstr (strinfo [i].tinfoname);
+
+ initkeytable ();
+
+ if (isatty (STDOUT_FILENO) )
+ {
+ #if 0
+ const char * str_keypad_xmit= calltigetstr ("smkx");
+ calltputs (str_keypad_xmit);
+ #else
+ calltputs (strKeypadXmit);
+ #endif
+ }
+
+}
+
+inline void checkinit ()
+{
+ if (fInit)
+ init ();
+}
+
+#else
+
+inline void checkinit () { }
+
+#endif
+
+#endif
+
+} // namespace
+
+void cursor::initconsole ()
+{
+ TRACEFUNC (tr, "initconsole");
+
+ cursorinvisible ();
+}
+
+void cursor::quitconsole ()
+{
+ TRACEFUNC (tr, "quitconsole");
+
+ cursorvisible ();
+
+ #ifdef BLASSIC_USE_TERMINFO
+
+ if (! fInit)
+ {
+ if (isatty (STDOUT_FILENO) )
+ {
+ #if 0
+ const char * str_keypad_local= calltigetstr ("rmkx");
+ calltputs (str_keypad_local);
+ #else
+ calltputs (strKeypadLocal);
+ #endif
+ }
+
+ }
+
+ #endif
+}
+
+size_t cursor::getwidth ()
+{
+ const size_t default_value= 80;
+ size_t width;
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ width= info.dwSize.X;
+ else
+ width= default_value;
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ STRUCT_WINSIZE win;
+ if (ioctl (0, IOCTL_WINSIZE, & win) == 0)
+ width= WINSIZE_COLS (win);
+ else
+ {
+ const char * aux= getenv ("COLUMNS");
+ if (aux)
+ width= atoi (aux);
+ else
+ width= default_value;
+ }
+
+ #else
+
+ width= default_value;
+
+ #endif
+
+ return width;
+}
+
+void cursor::cursorvisible ()
+{
+ TRACEFUNC (tr, "cursorvisible");
+
+ // checkinit not needed, is done by showcursor
+ showcursor ();
+
+ #ifndef BLASSIC_USE_WINDOWS
+
+ struct termios ter;
+ tcgetattr (STDIN_FILENO, & ter);
+ //ter.c_lflag|= (ECHO | ICANON | PENDIN);
+ ter.c_lflag|= (ECHO | ICANON);
+ tcsetattr (STDIN_FILENO, TCSANOW, & ter);
+
+ #endif
+}
+
+void cursor::cursorinvisible ()
+{
+ TRACEFUNC (tr, "cursorinvisible");
+
+ // checkinit not needed, is done by hidecursor
+ hidecursor ();
+
+ #ifndef BLASSIC_USE_WINDOWS
+
+ struct termios ter;
+ tcgetattr (STDIN_FILENO, & ter);
+ ter.c_lflag&= ~ (ECHO | ICANON);
+ ter.c_cc [VMIN]= 1;
+ tcsetattr (STDIN_FILENO, TCSANOW, & ter);
+
+ #endif
+}
+
+void cursor::showcursor ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_CURSOR_INFO info;
+ GetConsoleCursorInfo (h, & info);
+ info.bVisible= TRUE;
+ SetConsoleCursorInfo (h, & info);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ checkinit ();
+
+ if (isatty (STDOUT_FILENO) )
+ calltputs (strCursorNormal );
+
+ #endif
+}
+
+void cursor::hidecursor ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_CURSOR_INFO info;
+ GetConsoleCursorInfo (h, & info);
+ info.bVisible= FALSE;
+ SetConsoleCursorInfo (h, & info);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ checkinit ();
+
+ if (isatty (STDOUT_FILENO) )
+ calltputs (strCursorInvisible);
+
+ #endif
+}
+
+#ifdef BLASSIC_USE_WINDOWS
+
+const WORD init_attributes=
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+WORD attributes= init_attributes;
+
+#endif
+
+void cursor::cls ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ DWORD l= info.dwSize.X * info.dwSize.Y;
+ COORD coord= {0, 0};
+ DWORD notused;
+ FillConsoleOutputAttribute (h,
+ attributes,
+ l, coord, & notused);
+ FillConsoleOutputCharacter (h,
+ ' ', l, coord, & notused);
+ SetConsoleCursorPosition (h, coord);
+ }
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ checkinit ();
+
+ calltputs (strCls);
+
+ #endif
+}
+
+void cursor::gotoxy (int x, int y)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ COORD coord= { SHORT (x), SHORT (y) };
+ SetConsoleCursorPosition (GetStdHandle (STD_OUTPUT_HANDLE), coord);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ checkinit ();
+
+ if (strCup)
+ calltputs (tgoto (const_cast <char *> (strCup), x, y) );
+
+ #else
+
+ touch (x, y);
+
+ #endif
+}
+
+int cursor::getcursorx ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) == 0)
+ return 0;
+ return info.dwCursorPosition.X;
+
+ #else
+
+ return 0;
+
+ #endif
+}
+
+void cursor::movecharforward ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ movecharforward (1);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strMoveForward);
+
+ #endif
+}
+
+void cursor::movecharback ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ movecharback (1);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strMoveBack);
+
+ #endif
+}
+
+void cursor::movecharup ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ movecharup (1);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strMoveUp);
+
+ #endif
+}
+
+void cursor::movechardown ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ movechardown (1);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strMoveDown);
+
+ #endif
+}
+
+namespace {
+
+#ifdef BLASSIC_USE_TERMINFO
+
+inline void auxmovechar (const char * strN, const char * str, size_t n)
+{
+ if (n != 0)
+ {
+ if (strN)
+ //calltputs (tparm ( (char *) strN, n) );
+ calltparm (strN, n);
+ else
+ if (str)
+ for (size_t i= 0; i < n; ++i)
+ calltputs (str);
+ }
+}
+
+#endif
+
+} // namespace
+
+void cursor::movecharforward (size_t n)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ info.dwCursorPosition.X+= SHORT (n);
+ SetConsoleCursorPosition (h, info.dwCursorPosition);
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ auxmovechar (strMoveForwardN, strMoveForward, n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+
+void cursor::movecharback (size_t n)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ info.dwCursorPosition.X-= SHORT (n);
+ SetConsoleCursorPosition (h, info.dwCursorPosition);
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ auxmovechar (strMoveBackN, strMoveBack, n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+
+void cursor::movecharup (size_t n)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ info.dwCursorPosition.Y-= SHORT (n);
+ SetConsoleCursorPosition (h, info.dwCursorPosition);
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ auxmovechar (strMoveUpN, strMoveUp, n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+
+void cursor::movechardown (size_t n)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (GetConsoleScreenBufferInfo (h, & info) )
+ {
+ info.dwCursorPosition.Y+= SHORT (n);
+ SetConsoleCursorPosition (h, info.dwCursorPosition);
+ }
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ auxmovechar (strMoveDownN, strMoveDown, n);
+
+ #else
+
+ touch (n);
+
+ #endif
+}
+
+void cursor::savecursorpos ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strSaveCursorPos);
+
+ #endif
+}
+
+void cursor::restorecursorpos ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strRestoreCursorPos);
+
+ #endif
+}
+
+
+#ifndef BLASSIC_USE_WINDOWS
+
+namespace {
+
+static const int newcolor []=
+ { 0, 4, 2, 6, 1, 5, 3, 7};
+
+inline int mapcolor (int n)
+{
+ // Intensity bit unchanged
+ return newcolor [n & 7] | (n & 8);
+}
+
+} // namespace
+
+#endif
+
+void cursor::textcolor (int color)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ attributes= (attributes & WORD (0xF0) ) | WORD (color & 0x0F);
+ SetConsoleTextAttribute (h, attributes);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ color= mapcolor (color & 0xF);
+ bool intensity= color > 7;
+ if (intensity)
+ {
+ color&= 7;
+ calltputs (strEnterBold);
+ }
+ else
+ {
+ if (strExitBold)
+ {
+ calltputs (strExitBold);
+ // sgr0 reset the background, then we need to set it.
+ textbackground (background);
+ }
+ }
+ //if (strForeground)
+ // calltputs (tparm ( (char *) strForeground, color) );
+ calltparm (strForeground, color);
+
+ #else
+
+ touch (color);
+
+ #endif
+}
+
+void cursor::textbackground (int color)
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ HANDLE h= GetStdHandle (STD_OUTPUT_HANDLE);
+ attributes= (attributes & WORD (0xF) ) | WORD ( (color & 0xF) << 4);
+ SetConsoleTextAttribute (h, attributes);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ background= color;
+ color= mapcolor (color & 0xF);
+ //if (strBackground)
+ // calltputs (tparm ( (char *) strBackground, color) );
+ calltparm (strBackground, color);
+
+ #else
+
+ touch (color);
+
+ #endif
+}
+
+namespace {
+
+enum ReadType { ReadWait, ReadNoWait };
+
+#ifdef BLASSIC_USE_WINDOWS
+
+std::string string_from_key_event (const KEY_EVENT_RECORD & kr)
+{
+
+ char c= kr.uChar.AsciiChar;
+ if (c != '\0')
+ return std::string (1, c);
+ WORD k= kr.wVirtualKeyCode;
+ std::string str= string_from_key (k);
+ if (! str.empty () )
+ return str;
+
+ if (k != VK_SHIFT &&
+ k != VK_CONTROL &&
+ k != VK_MENU &&
+ k != VK_CAPITAL &&
+ k != VK_NUMLOCK &&
+ k != VK_SCROLL)
+ {
+ std::string str (1, '\0');
+ str+= char (kr.wVirtualScanCode);
+ return str;
+ }
+ return std::string ();
+}
+
+std::string string_from_input (const INPUT_RECORD & input)
+{
+ std::string str;
+ if (input.EventType == KEY_EVENT && input.Event.KeyEvent.bKeyDown)
+ {
+ str= string_from_key_event (input.Event.KeyEvent);
+ }
+ return str;
+}
+
+std::string readkey (ReadType type)
+{
+ std::string str;
+
+ HANDLE h= GetStdHandle (STD_INPUT_HANDLE);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ showlasterror ();
+ throw ErrFileRead;
+ }
+
+ DWORD mode, orgmode;
+ GetConsoleMode (h, & mode);
+ orgmode= mode;
+ //mode&= ~ (ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
+ mode= 0;
+ SetConsoleMode (h, mode);
+ DWORD n= 0;
+ INPUT_RECORD input;
+ if (type == ReadNoWait)
+ {
+ if (PeekConsoleInput (h, & input, 1, & n) == 0)
+ {
+ showlasterror ();
+ throw ErrFileRead;
+ }
+ }
+ else
+ n= 1;
+ if (n)
+ {
+ do
+ {
+ if (ReadConsoleInput (h, & input, 1, & n) == 0)
+ {
+ showlasterror ();
+ throw ErrFileRead;
+ }
+ str= string_from_input (input);
+ } while (type == ReadWait && str.empty () );
+ }
+ SetConsoleMode (h, orgmode);
+
+ return str;
+}
+
+#else
+
+#if defined BLASSIC_USE_TERMINFO
+
+class MapSpecial {
+public:
+ enum Result { NoMapped, Found, MoreNeeded };
+ void addkey (const std::string & str, std::string::size_type pos,
+ const std::string & keyname)
+ {
+ //TRACEFUNC (tr, "MapSpecial::addkey");
+
+ ASSERT (pos < str.size () );
+ char c= str [pos];
+ if (pos == str.size () - 1)
+ kname [c]= keyname;
+ else
+ {
+ //if (kmap.find (c) == kmap.end () )
+ // kmap [c]= MapSpecial ();
+ kmap [c].addkey (str, pos + 1, keyname);
+ }
+ }
+ Result findkey (const std::string & str, std::string::size_type pos,
+ std::string & keyname, std::string::size_type & consumed)
+ {
+ if (pos >= str.size () )
+ return MoreNeeded;
+ char c= str [pos];
+ //cout << "Buscando: " << c << endl;
+ {
+ kname_t::iterator it= kname.find (c);
+ if (it != kname.end () )
+ {
+ keyname= it->second;
+ consumed= pos;
+ return Found;
+ }
+ }
+ std::map <char, MapSpecial>::iterator it= kmap.find (c);
+ if (it != kmap.end () )
+ return it->second.findkey
+ (str, pos + 1, keyname, consumed);
+ else
+ return NoMapped;
+ }
+private:
+ typedef std::map <char, std::string> kname_t;
+ kname_t kname;
+ std::map <char, MapSpecial> kmap;
+};
+
+struct KeyDescription {
+ const char * tiId;
+ //const char * blName;
+ const std::string & blName;
+ KeyDescription (const char * tiId, const std::string & blName) :
+ tiId (tiId),
+ blName (blName)
+ { }
+};
+
+const std::string
+ strMULT ("*"),
+ strMINUS ("-"),
+ strPLUS ("+"),
+ strDIV ("/");
+
+#ifdef BLASSIC_CONFIG_USE_NCURSES
+
+const KeyDescription keyname [] = {
+ KeyDescription ("kpp", strPAGEUP), // previous-page key
+ KeyDescription ("knp", strPAGEDOWN), // next-page key
+ KeyDescription ("kend", strEND), // end key
+ KeyDescription ("kslt", strEND), // select key
+ KeyDescription ("kc1", strEND), // lower left of keypad
+ KeyDescription ("khome", strHOME), // home key
+ KeyDescription ("kfnd", strHOME), // find key
+ KeyDescription ("ka1", strHOME), // upper left of keypad
+ KeyDescription ("kcub1", strLEFT), // left-arrow key
+ KeyDescription ("kcuu1", strUP), // up-arrow key
+ KeyDescription ("kcuf1", strRIGHT), // right-arrow key
+ KeyDescription ("kcud1", strDOWN), // down-arrow key
+ KeyDescription ("kich1", strINSERT), // insert-character key
+ KeyDescription ("kdch1", strDELETE), // delete-character key
+ KeyDescription ("kent", strENTER), // enter/send key
+ KeyDescription ("kf1", strF1), // F1 function key
+ KeyDescription ("kf2", strF2), // F2 function key
+ KeyDescription ("kf3", strF3), // F3 function key
+ KeyDescription ("kf4", strF4), // F4 function key
+ KeyDescription ("kf5", strF5), // F5 function key
+ KeyDescription ("kf6", strF6), // F6 function key
+ KeyDescription ("kf7", strF7), // F7 function key
+ KeyDescription ("kf8", strF8), // F8 function key
+ KeyDescription ("kf9", strF9), // F9 function key
+ KeyDescription ("kf10", strF10), // F10 function key
+ KeyDescription ("kf11", strF11), // F11 function key
+ KeyDescription ("kf12", strF12), // F12 function key
+ KeyDescription ("kf54", strDIV), // F54 function key, / in xterm
+ KeyDescription ("kf55", strMULT), // F55 function key, * in xterm
+ KeyDescription ("kf56", strMINUS), // F56 function key, - in xterm
+ KeyDescription ("kf57", strPLUS), // f57 function key, + in xterm
+};
+
+#else
+
+const KeyDescription keyname [] = {
+ KeyDescription ("kP", strPAGEUP), // previous-page key
+ KeyDescription ("kN", strPAGEDOWN), // next-page key
+ KeyDescription ("@7", strEND), // end key
+ KeyDescription ("*6", strEND), // select key
+ KeyDescription ("K4", strEND), // lower left of keypad
+ KeyDescription ("kh", strHOME), // home key
+ KeyDescription ("@0", strHOME), // find key
+ KeyDescription ("K1", strHOME), // upper left of keypad
+ KeyDescription ("kl", strLEFT), // left-arrow key
+ KeyDescription ("ku", strUP), // up-arrow key
+ KeyDescription ("kr", strRIGHT), // right-arrow key
+ KeyDescription ("kd", strDOWN), // down-arrow key
+ KeyDescription ("kI", strINSERT), // insert-character key
+ KeyDescription ("kD", strDELETE), // delete-character key
+ KeyDescription ("@8", strENTER), // enter/send key
+ KeyDescription ("k1", strF1), // F1 function key
+ KeyDescription ("k2", strF2), // F2 function key
+ KeyDescription ("k3", strF3), // F3 function key
+ KeyDescription ("k4", strF4), // F4 function key
+ KeyDescription ("k5", strF5), // F5 function key
+ KeyDescription ("k6", strF6), // F6 function key
+ KeyDescription ("k7", strF7), // F7 function key
+ KeyDescription ("k8", strF8), // F8 function key
+ KeyDescription ("k9", strF9), // F9 function key
+ KeyDescription ("k;", strF10), // F10 function key
+ KeyDescription ("F1", strF11), // F11 function key
+ KeyDescription ("F2", strF12), // F12 function key
+ KeyDescription ("Fi", strDIV), // F54 function key, / in xterm
+ KeyDescription ("Fj", strMULT), // F55 function key, * in xterm
+ KeyDescription ("Fk", strMINUS), // F56 function key, - in xterm
+ KeyDescription ("Fl", strPLUS), // f57 function key, + in xterm
+};
+
+#endif
+
+#ifndef NDEBUG
+
+bool checktable ()
+{
+ const size_t nkeys= util::dim_array (keyname);
+
+ for (size_t i= 0; i < nkeys - 1; ++i)
+ for (size_t j= i + 1; j < nkeys; ++j)
+ if (strcmp (keyname [i].tiId, keyname [j].tiId) == 0)
+ {
+ std::cerr << "Code repeated in keyname: " <<
+ keyname [i].tiId << std::endl;
+ throw 1;
+ }
+ return true;
+}
+
+bool tablechecked= checktable ();
+
+#endif
+
+MapSpecial ms;
+
+void initkeytable ()
+{
+ TRACEFUNC (tr, "initkeytable");
+
+ const size_t nkeys= util::dim_array (keyname);
+
+ for (size_t i= 0; i < nkeys; ++i)
+ {
+ const KeyDescription & keydesc= keyname [i];
+ const char * const strkey= keydesc.tiId;
+ const char * str= calltigetstr (strkey);
+ if (str != NULL)
+ {
+ #if 0
+ cerr << keydesc.blName << "=";
+ for (size_t i= 0, l= strlen (str); i < l; ++i)
+ {
+ char c= str [i];
+ if (c >= 32) cerr << c;
+ else cerr << "\\(" << hex << int (c) << ')';
+ }
+ cerr << endl;
+ #endif
+ TRMESSAGE (tr, std::string ("Adding ") + keydesc.blName);
+ ms.addkey (str, 0, keydesc.blName);
+ }
+ }
+
+}
+
+#endif // BLASSIC_USE_TERMINFO
+
+class PollInput {
+public:
+ PollInput ()
+ {
+ pfd.fd= STDIN_FILENO;
+ pfd.events= POLLIN;
+ }
+ int poll ()
+ {
+ int r= ::poll (& pfd, 1, 100);
+ if (r == 1 && pfd.revents != POLLIN)
+ throw ErrFileRead;
+ return r;
+ }
+private:
+ struct pollfd pfd;
+};
+
+void wait_event ()
+{
+ PollInput pi;
+ int r;
+ do {
+ blassic::idle ();
+ } while ( (r= pi.poll () ) == 0);
+ if (r < 0)
+ {
+ std::cerr << "Error in poll: " << strerror (errno) <<
+ std::endl;
+ }
+}
+
+void do_poll ()
+{
+ PollInput ().poll ();
+}
+
+std::string readkey (ReadType type)
+{
+ checkinit ();
+
+ static std::string charpending;
+ std::string str;
+ bool reset_blocking_mode= false;
+ int l;
+ //char c;
+ const int lbuf= 32;
+ char buffer [lbuf + 1];
+
+ if (! charpending.empty () )
+ goto check_it;
+
+ #if 0
+
+ if (type == ReadWait)
+ {
+ //fcntl (STDIN_FILENO, F_SETFL, 0);
+ wait_event ();
+ }
+ else
+ {
+ fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
+ reset_blocking_mode= true;
+ }
+
+ //read_another:
+
+ l= read (STDIN_FILENO, & c, 1);
+ if (l == 1)
+ str+= c;
+
+ #else
+
+ fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
+ reset_blocking_mode= true;
+ //l= read (STDIN_FILENO, & c, 1);
+ l= read (STDIN_FILENO, buffer, lbuf);
+ //if (l != 1 && type == ReadWait)
+ if (l < 1 && type == ReadWait)
+ {
+ do {
+ //wait_event ();
+ //l= read (STDIN_FILENO, & c, 1);
+ do_poll ();
+ l= read (STDIN_FILENO, buffer, lbuf);
+ //} while (l != 1);
+ } while (l < 1);
+ }
+ //if (l == 1)
+ // str+= c;
+ if (l >= 1)
+ {
+ buffer [l]= '\0';
+ str+= buffer;
+ }
+
+ #endif
+
+ #ifdef BLASSIC_USE_TERMINFO
+ read_another:
+ #endif
+
+ //std::cerr << "Adding: >" << str << '<' << std::endl;
+ charpending+= str;
+ str.erase ();
+
+ check_it:
+
+ std::string keyname;
+ //std::string::size_type pos;
+ if (! charpending.empty () )
+ {
+ #ifdef BLASSIC_USE_TERMINFO
+ std::string::size_type pos;
+ MapSpecial::Result r=
+ ms.findkey (charpending, 0, keyname, pos);
+ switch (r)
+ {
+ case MapSpecial::NoMapped:
+ str= charpending [0];
+ charpending.erase (0, 1);
+ break;
+ case MapSpecial::Found:
+ str= keyname;
+ charpending.erase (0, pos + 1);
+ break;
+ case MapSpecial::MoreNeeded:
+ fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
+ reset_blocking_mode= true;
+ do_poll ();
+ //l= read (STDIN_FILENO, & c, 1);
+ //if (l == 1)
+ //{
+ // str= c;
+ // goto read_another;
+ //}
+ l= read (STDIN_FILENO, buffer, lbuf);
+ if (l >= 1)
+ {
+ buffer [l]= '\0';
+ str= buffer;
+ goto read_another;
+ }
+ str= charpending [0];
+ charpending.erase (0, 1);
+ break;
+ }
+ #else
+ str= charpending [0];
+ charpending.erase (0, 1);
+ #endif
+ }
+
+ //if (type == ReadWait)
+ // cursorinvisible ();
+
+ if (reset_blocking_mode)
+ fcntl (STDIN_FILENO, F_SETFL, 0);
+
+ return str;
+}
+
+#endif // ! BLASSIC_USE_WINDOWS
+
+// A provisional solution to pollin
+
+std::queue <std::string> keypending;
+
+} // namespace
+
+std::string cursor::inkey ()
+{
+ if (! keypending.empty () )
+ {
+ std::string r= keypending.front ();
+ keypending.pop ();
+ return r;
+ }
+ else
+ return readkey (ReadNoWait);
+}
+
+std::string cursor::getkey ()
+{
+ if (! keypending.empty () )
+ {
+ std::string r= keypending.front ();
+ keypending.pop ();
+ return r;
+ }
+ return readkey (ReadWait);
+}
+
+bool cursor::pollin ()
+{
+ if (! keypending.empty () )
+ return true;
+ else
+ {
+ std::string key= readkey (ReadNoWait);
+ if (key.empty () )
+ return false;
+ else
+ {
+ keypending.push (key);
+ return true;
+ }
+ }
+}
+
+void cursor::clean_input ()
+{
+ TRACEFUNC (tr, "clean_input");
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ Sleep (100);
+ HANDLE h= GetStdHandle (STD_INPUT_HANDLE);
+ INPUT_RECORD input;
+ DWORD n= 0;
+ PeekConsoleInput (h, & input, 1, & n);
+ if (n && input.EventType == KEY_EVENT &&
+ ! input.Event.KeyEvent.bKeyDown)
+ ReadConsoleInput (h, & input, 1, & n);
+
+ #else
+
+ fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK);
+ int l;
+ const int lbuf= 32;
+ char buffer [lbuf + 1];
+ do
+ {
+ l= read (STDIN_FILENO, buffer, lbuf);
+ } while (l > 0);
+ fcntl (STDIN_FILENO, F_SETFL, 0);
+
+ #endif
+}
+
+void cursor::ring ()
+{
+ #ifdef BLASSIC_USE_WINDOWS
+
+ MessageBeep (MB_ICONEXCLAMATION);
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ calltputs (strBell);
+
+ #else
+
+ // Last resource
+ char c= '\a';
+ write (STDOUT_FILENO, & c, 1);
+
+ #endif
+}
+
+//************************************************
+// set_title
+//************************************************
+
+#ifdef BLASSIC_USE_TERMINFO
+
+// Escape sequences from the "How to change the title of an xterm",
+// by Ric Lister, http://www.tldp.org/HOWTO/mini/Xterm-Title.html
+
+namespace
+{
+
+void write_it (std::ostringstream & oss)
+{
+ const std::string & str (oss.str () );
+ write (STDOUT_FILENO, str.c_str (), str.size () );
+}
+
+void set_title_xterm (const std::string & title)
+{
+ std::ostringstream oss;
+ oss << "\x1B]0;" << title << "\x07";
+ write_it (oss);
+}
+
+void set_title_iris_ansi (const std::string & title)
+{
+ std::ostringstream oss;
+ oss << "\x1BP1.y" << title << "\x1B\\"; // Set window title
+ oss << "\x1BP3.y" << title << "\x1B\\"; // Set icon title
+ write_it (oss);
+}
+
+void set_title_sun_cmd (const std::string & title)
+{
+ std::ostringstream oss;
+ oss << "\x1B]l;" << title << "\x1B\\"; // Set window title
+ oss << "\x1B]L;" << title << "\x1B\\"; // Set icon title
+ write_it (oss);
+}
+
+void set_title_hpterm (const std::string & title)
+{
+ std::ostringstream oss;
+ const std::string::size_type l= title.size ();
+ oss << "\x1B&f0k" << l << 'D' << title; // Set window title
+ oss << "\x1B&f-1k" << l << 'D' << title; // Set icon title
+ write_it (oss);
+}
+
+typedef void (* set_title_t) (const std::string &);
+
+struct Cstring_less {
+ bool operator () (const char * p, const char * q)
+ { return strcmp (p, q) < 0; }
+};
+
+typedef std::map <const char *, set_title_t, Cstring_less> maptitle_t;
+maptitle_t maptitle;
+
+bool initmaptitle ()
+{
+ maptitle ["xterm"]= set_title_xterm;
+ maptitle ["aixterm"]= set_title_xterm;
+ maptitle ["dtterm"]= set_title_xterm;
+ maptitle ["iris-ansi"]= set_title_iris_ansi;
+ maptitle ["sun-cmd"]= set_title_sun_cmd;
+ maptitle ["hpterm"]= set_title_hpterm;
+ return true;
+}
+
+bool maptitle_inited= initmaptitle ();
+
+void set_title_terminfo (const std::string & title)
+{
+ TRACEFUNC (tr, "set_title_terminfo");
+
+ if (! isatty (STDOUT_FILENO) )
+ return;
+
+ if (const char * term= getenv ("TERM") )
+ {
+ maptitle_t::iterator it= maptitle.find (term);
+ if (it != maptitle.end () )
+ (* it->second) (title);
+ else
+ {
+ TRMESSAGE (tr, "TERM not found");
+ }
+ }
+}
+
+} // namespace
+
+#endif
+
+void cursor::set_title (const std::string & title)
+{
+ TRACEFUNC (tr, "set_title");
+
+ #ifdef BLASSIC_USE_WINDOWS
+
+ SetConsoleTitle (title.c_str () );
+
+ #elif defined BLASSIC_USE_TERMINFO
+
+ set_title_terminfo (title);
+
+ #else
+
+ touch (title);
+
+ #endif
+}
+
+// Fin de cursor.cpp
Un proyecto texto-plano.xyz