diff options
author | Tatsuya Kinoshita <tats@vega.ocn.ne.jp> | 2011-05-04 07:05:14 +0000 |
---|---|---|
committer | Tatsuya Kinoshita <tats@vega.ocn.ne.jp> | 2011-05-04 07:05:14 +0000 |
commit | 72f72d64a422d6628c4796f5c0bf2e508f134214 (patch) | |
tree | 0c9ea90cc53310832c977265521fb44db24a515e /terms.c | |
parent | Adding upstream version 0.3 (diff) | |
download | w3m-72f72d64a422d6628c4796f5c0bf2e508f134214.tar.gz w3m-72f72d64a422d6628c4796f5c0bf2e508f134214.zip |
Adding upstream version 0.5.1upstream/0.5.1
Diffstat (limited to '')
-rw-r--r-- | terms.c | 2169 |
1 files changed, 2169 insertions, 0 deletions
@@ -0,0 +1,2169 @@ +/* $Id: terms.c,v 1.51 2003/12/08 16:06:34 ukai Exp $ */ +/* + * An original curses library for EUC-kanji by Akinori ITO, December 1989 + * revised by Akinori ITO, January 1995 + */ +#include <stdio.h> +#include <signal.h> +#include <sys/types.h> +#include <fcntl.h> +#include <errno.h> +#include <sys/time.h> +#include <unistd.h> +#include "config.h" +#include <string.h> +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#include <sys/ioctl.h> +#ifdef USE_MOUSE +#ifdef USE_GPM +#include <gpm.h> +#endif /* USE_GPM */ +#ifdef USE_SYSMOUSE +#include <osreldate.h> +#if (__FreeBSD_version >= 400017) +#include <sys/consio.h> +#include <sys/fbio.h> +#else +#include <machine/console.h> +#endif +int (*sysm_handler) (int x, int y, int nbs, int obs); +static int cwidth = 8, cheight = 16; +static int xpix, ypix, nbs, obs = 0; +#endif /* use_SYSMOUSE */ + +static int is_xterm = 0; + +void mouse_init(), mouse_end(); +int mouseActive = 0; +#endif /* USE_MOUSE */ + +static char *title_str = NULL; + +static int tty; + +#include "terms.h" +#include "fm.h" +#include "myctype.h" + +#ifdef __EMX__ +#define INCL_DOSNLS +#include <os2.h> +#endif /* __EMX__ */ + +#if defined(__CYGWIN__) +#include <windows.h> +#include <sys/cygwin.h> +static int isWinConsole = 0; +static int isLocalConsole = 0; +#ifdef USE_MOUSE +int cygwin_mouse_btn_swapped = 0; +#endif + +#if defined(SUPPORT_WIN9X_CONSOLE_MBCS) +static HANDLE hConIn = INVALID_HANDLE_VALUE; +static int isWin95 = 0; +static char *ConInV; +static int iConIn, nConIn, nConInMax; + +static void +check_win9x(void) +{ + OSVERSIONINFO winVersionInfo; + + winVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx(&winVersionInfo) == 0) { + fprintf(stderr, "can't get Windows version information.\n"); + exit(1); + } + if (winVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { + isWin95 = 1; + if (ttyslot() != -1) { + isLocalConsole = 0; + } + } + else { + isWin95 = 0; + } +} + +void +enable_win9x_console_input(void) +{ + if (isWin95 && isWinConsole && isLocalConsole && + hConIn == INVALID_HANDLE_VALUE) { + hConIn = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (hConIn != INVALID_HANDLE_VALUE) { + getch(); + } + } +} + +void +disable_win9x_console_input(void) +{ + if (hConIn != INVALID_HANDLE_VALUE) { + CloseHandle(hConIn); + hConIn = INVALID_HANDLE_VALUE; + } +} + +static void +expand_win32_console_input_buffer(int n) +{ + if (nConIn + n >= nConInMax) { + char *oldv; + + nConInMax = ((nConIn + n) / 2 + 1) * 3; + oldv = ConInV; + ConInV = GC_MALLOC_ATOMIC(nConInMax); + memcpy(ConInV, oldv, nConIn); + } +} + +static int +read_win32_console_input(void) +{ + INPUT_RECORD rec; + DWORD nevents; + + if (PeekConsoleInput(hConIn, &rec, 1, &nevents) && nevents) { + switch (rec.EventType) { + case KEY_EVENT: + expand_win32_console_input_buffer(3); + + if (ReadConsole(hConIn, &ConInV[nConIn], 1, &nevents, NULL)) { + nConIn += nevents; + return nevents; + } + + break; + default: + break; + } + + ReadConsoleInput(hConIn, &rec, 1, &nevents); + } + return 0; +} + +static int +read_win32_console(char *s, int n) +{ + KEY_EVENT_RECORD *ker; + + if (hConIn == INVALID_HANDLE_VALUE) + return read(tty, s, n); + + if (n > 0) + for (;;) { + if (iConIn < nConIn) { + if (n > nConIn - iConIn) + n = nConIn - iConIn; + + memcpy(s, ConInV, n); + + if ((iConIn += n) >= nConIn) + iConIn = nConIn = 0; + + break; + } + + iConIn = nConIn = 0; + + while (!read_win32_console_input()) ; + } + + return n; +} + +#endif /* SUPPORT_WIN9X_CONSOLE_MBCS */ + +static HWND +GetConsoleHwnd(void) +{ +#define MY_BUFSIZE 1024 + HWND hwndFound; + char pszNewWindowTitle[MY_BUFSIZE]; + char pszOldWindowTitle[MY_BUFSIZE]; + + GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE); + wsprintf(pszNewWindowTitle, "%d/%d", + GetTickCount(), GetCurrentProcessId()); + SetConsoleTitle(pszNewWindowTitle); + Sleep(40); + hwndFound = FindWindow(NULL, pszNewWindowTitle); + SetConsoleTitle(pszOldWindowTitle); + return (hwndFound); +} + +#ifdef USE_MOUSE +static unsigned long +cygwin_version(void) +{ + struct per_process *p; + + p = (struct per_process *)cygwin_internal(CW_USER_DATA); + if (p != NULL) { + return (p->dll_major * 1000) + p->dll_minor; + } + return 0; +} +#endif + +static void +check_cygwin_console(void) +{ + char *term = getenv("TERM"); + HANDLE hWnd; + + if (term == NULL) + term = DEFAULT_TERM; + if (term && strncmp(term, "cygwin", 6) == 0) { + isWinConsole = 1; + } + if (isWinConsole) { + hWnd = GetConsoleHwnd(); + if (hWnd != INVALID_HANDLE_VALUE) { + if (IsWindowVisible(hWnd)) { + isLocalConsole = 1; + } + } +#ifdef SUPPORT_WIN9X_CONSOLE_MBCS + check_win9x(); +#endif + } +#ifdef USE_MOUSE + if (cygwin_version() <= 1003015) { + /* cygwin DLL 1.3.15 or earler */ + cygwin_mouse_btn_swapped = 1; + } +#endif +} +#endif /* __CYGWIN__ */ + +char *getenv(const char *); +MySignalHandler reset_exit(SIGNAL_ARG), error_dump(SIGNAL_ARG); +void setlinescols(void); +void flush_tty(); + +#ifndef SIGIOT +#define SIGIOT SIGABRT +#endif /* not SIGIOT */ + +#ifdef HAVE_TERMIO_H +#include <termio.h> +typedef struct termio TerminalMode; +#define TerminalSet(fd,x) ioctl(fd,TCSETA,x) +#define TerminalGet(fd,x) ioctl(fd,TCGETA,x) +#define MODEFLAG(d) ((d).c_lflag) +#define IMODEFLAG(d) ((d).c_iflag) +#endif /* HAVE_TERMIO_H */ + +#ifdef HAVE_TERMIOS_H +#include <termios.h> +#include <unistd.h> +typedef struct termios TerminalMode; +#define TerminalSet(fd,x) tcsetattr(fd,TCSANOW,x) +#define TerminalGet(fd,x) tcgetattr(fd,x) +#define MODEFLAG(d) ((d).c_lflag) +#define IMODEFLAG(d) ((d).c_iflag) +#endif /* HAVE_TERMIOS_H */ + +#ifdef HAVE_SGTTY_H +#include <sgtty.h> +typedef struct sgttyb TerminalMode; +#define TerminalSet(fd,x) ioctl(fd,TIOCSETP,x) +#define TerminalGet(fd,x) ioctl(fd,TIOCGETP,x) +#define MODEFLAG(d) ((d).sg_flags) +#endif /* HAVE_SGTTY_H */ + +#define MAX_LINE 200 +#define MAX_COLUMN 400 + +/* Screen properties */ +#define S_SCREENPROP 0x0f +#define S_NORMAL 0x00 +#define S_STANDOUT 0x01 +#define S_UNDERLINE 0x02 +#define S_BOLD 0x04 +#define S_EOL 0x08 + +/* Sort of Character */ +#define C_WHICHCHAR 0xc0 +#define C_ASCII 0x00 +#ifdef USE_M17N +#define C_WCHAR1 0x40 +#define C_WCHAR2 0x80 +#endif +#define C_CTRL 0xc0 + +#define CHMODE(c) ((c)&C_WHICHCHAR) +#define SETCHMODE(var,mode) ((var) = (((var)&~C_WHICHCHAR) | mode)) +#ifdef USE_M17N +#define SETCH(var,ch,len) ((var) = New_Reuse(char, (var), (len) + 1), \ + strncpy((var), (ch), (len)), (var)[len] = '\0') +#else +#define SETCH(var,ch,len) ((var) = (ch)) +#endif + +/* Charactor Color */ +#define COL_FCOLOR 0xf00 +#define COL_FBLACK 0x800 +#define COL_FRED 0x900 +#define COL_FGREEN 0xa00 +#define COL_FYELLOW 0xb00 +#define COL_FBLUE 0xc00 +#define COL_FMAGENTA 0xd00 +#define COL_FCYAN 0xe00 +#define COL_FWHITE 0xf00 +#define COL_FTERM 0x000 + +#define S_COLORED 0xf00 + +#ifdef USE_BG_COLOR +/* Background Color */ +#define COL_BCOLOR 0xf000 +#define COL_BBLACK 0x8000 +#define COL_BRED 0x9000 +#define COL_BGREEN 0xa000 +#define COL_BYELLOW 0xb000 +#define COL_BBLUE 0xc000 +#define COL_BMAGENTA 0xd000 +#define COL_BCYAN 0xe000 +#define COL_BWHITE 0xf000 +#define COL_BTERM 0x0000 + +#define S_BCOLORED 0xf000 +#endif /* USE_BG_COLOR */ + + +#define S_GRAPHICS 0x10 + +#define S_DIRTY 0x20 + +#define SETPROP(var,prop) (var = (((var)&S_DIRTY) | prop)) + +/* Line status */ +#define L_DIRTY 0x01 +#define L_UNUSED 0x02 +#define L_NEED_CE 0x04 +#define L_CLRTOEOL 0x08 + +#define ISDIRTY(d) ((d) & L_DIRTY) +#define ISUNUSED(d) ((d) & L_UNUSED) +#define NEED_CE(d) ((d) & L_NEED_CE) + +typedef unsigned short l_prop; + +typedef struct scline { +#ifdef USE_M17N + char **lineimage; +#else + char *lineimage; +#endif + l_prop *lineprop; + short isdirty; + short eol; +} Screen; + +static TerminalMode d_ioval; +static int tty = -1; +static FILE *ttyf = NULL; + +static +char bp[1024], funcstr[256]; + +char *T_cd, *T_ce, *T_kr, *T_kl, *T_cr, *T_bt, *T_ta, *T_sc, *T_rc, + *T_so, *T_se, *T_us, *T_ue, *T_cl, *T_cm, *T_al, *T_sr, *T_md, *T_me, + *T_ti, *T_te, *T_nd, *T_as, *T_ae, *T_eA, *T_ac, *T_op; + +int LINES, COLS; +#if defined(__CYGWIN__) && LANG == JA +int LASTLINE; +#endif /* defined(__CYGWIN__) && LANG == JA */ +static int max_LINES = 0, max_COLS = 0; +static int tab_step = 8; +static int CurLine, CurColumn; +static Screen *ScreenElem = NULL, **ScreenImage = NULL; +static l_prop CurrentMode = 0; +static int graph_enabled = 0; + +static char gcmap[96]; + +extern int tgetent(char *, char *); +extern int tgetnum(char *); +extern int tgetflag(char *); +extern char *tgetstr(char *, char **); +extern char *tgoto(char *, int, int); +extern int tputs(char *, int, int (*)(char)); +void clear(), wrap(), touch_line(), touch_column(int); +#if 0 +void need_clrtoeol(void); +#endif +void clrtoeol(void); /* conflicts with curs_clear(3)? */ + +static int write1(char); + +static void +writestr(char *s) +{ + tputs(s, 1, write1); +} + +#define MOVE(line,column) writestr(tgoto(T_cm,column,line)); + +#ifdef USE_MOUSE +#define W3M_TERM_INFO(name, title, mouse) name, title, mouse +#define NEED_XTERM_ON (1) +#define NEED_XTERM_OFF (1<<1) +#ifdef __CYGWIN__ +#define NEED_CYGWIN_ON (1<<2) +#define NEED_CYGWIN_OFF (1<<3) +#endif +#else +#define W3M_TERM_INFO(name, title, mouse) name, title +#endif + +static char XTERM_TITLE[] = "\033]0;w3m: %s\007"; +static char SCREEN_TITLE[] = "\033k%s\033\134"; +#ifdef __CYGWIN__ +static char CYGWIN_TITLE[] = "w3m: %s"; +#endif + +/* *INDENT-OFF* */ +static struct w3m_term_info { + char *term; + char *title_str; +#ifdef USE_MOUSE + int mouse_flag; +#endif +} w3m_term_info_list[] = { + {W3M_TERM_INFO("xterm", XTERM_TITLE, (NEED_XTERM_ON|NEED_XTERM_OFF))}, + {W3M_TERM_INFO("kterm", XTERM_TITLE, (NEED_XTERM_ON|NEED_XTERM_OFF))}, + {W3M_TERM_INFO("rxvt", XTERM_TITLE, (NEED_XTERM_ON|NEED_XTERM_OFF))}, + {W3M_TERM_INFO("Eterm", XTERM_TITLE, (NEED_XTERM_ON|NEED_XTERM_OFF))}, + {W3M_TERM_INFO("mlterm", XTERM_TITLE, (NEED_XTERM_ON|NEED_XTERM_OFF))}, + {W3M_TERM_INFO("screen", SCREEN_TITLE, 0)}, +#ifdef __CYGWIN__ + {W3M_TERM_INFO("cygwin", CYGWIN_TITLE, (NEED_CYGWIN_ON|NEED_CYGWIN_OFF))}, +#endif + {W3M_TERM_INFO(NULL, NULL, 0)} +}; +#undef W3M_TERM_INFO +/* *INDENT-ON * */ + +int +set_tty(void) +{ + char *ttyn; + + if (isatty(0)) /* stdin */ + ttyn = ttyname(0); + else + ttyn = DEV_TTY_PATH; + tty = open(ttyn, O_RDWR); + if (tty < 0) { + /* use stderr instead of stdin... is it OK???? */ + tty = 2; + } + ttyf = fdopen(tty, "w"); +#ifdef __CYGWIN__ + check_cygwin_console(); +#endif + TerminalGet(tty, &d_ioval); + if (displayTitleTerm != NULL) { + struct w3m_term_info *p; + for (p = w3m_term_info_list; p->term != NULL; p++) { + if (!strncmp(displayTitleTerm, p->term, strlen(p->term))) { + title_str = p->title_str; + break; + } + } + } +#ifdef USE_MOUSE + { + char *term = getenv("TERM"); + if (term != NULL) { + struct w3m_term_info *p; + for (p = w3m_term_info_list; p->term != NULL; p++) { + if (!strncmp(term, p->term, strlen(p->term))) { + is_xterm = p->mouse_flag; + break; + } + } + } + } +#endif + return 0; +} + +void +ttymode_set(int mode, int imode) +{ + TerminalMode ioval; + + TerminalGet(tty, &ioval); + MODEFLAG(ioval) |= mode; +#ifndef HAVE_SGTTY_H + IMODEFLAG(ioval) |= imode; +#endif /* not HAVE_SGTTY_H */ + + while (TerminalSet(tty, &ioval) == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + printf("Error occured while set %x: errno=%d\n", mode, errno); + reset_exit(SIGNAL_ARGLIST); + } +} + +void +ttymode_reset(int mode, int imode) +{ + TerminalMode ioval; + + TerminalGet(tty, &ioval); + MODEFLAG(ioval) &= ~mode; +#ifndef HAVE_SGTTY_H + IMODEFLAG(ioval) &= ~imode; +#endif /* not HAVE_SGTTY_H */ + + while (TerminalSet(tty, &ioval) == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + printf("Error occured while reset %x: errno=%d\n", mode, errno); + reset_exit(SIGNAL_ARGLIST); + } +} + +#ifndef HAVE_SGTTY_H +void +set_cc(int spec, int val) +{ + TerminalMode ioval; + + TerminalGet(tty, &ioval); + ioval.c_cc[spec] = val; + while (TerminalSet(tty, &ioval) == -1) { + if (errno == EINTR || errno == EAGAIN) + continue; + printf("Error occured: errno=%d\n", errno); + reset_exit(SIGNAL_ARGLIST); + } +} +#endif /* not HAVE_SGTTY_H */ + +void +close_tty(void) +{ + if (tty > 2) + close(tty); +} + +char * +ttyname_tty(void) +{ + return ttyname(tty); +} + +void +reset_tty(void) +{ + writestr(T_op); /* turn off */ + writestr(T_me); + if (!Do_not_use_ti_te) { + if (T_te && *T_te) + writestr(T_te); + else + writestr(T_cl); + } + writestr(T_se); /* reset terminal */ + flush_tty(); + TerminalSet(tty, &d_ioval); + close_tty(); +} + +MySignalHandler +reset_exit(SIGNAL_ARG) +{ + reset_tty(); +#ifdef USE_MOUSE + if (mouseActive) + mouse_end(); +#endif /* USE_MOUSE */ + w3m_exit(0); + SIGNAL_RETURN; +} + +MySignalHandler +error_dump(SIGNAL_ARG) +{ + mySignal(SIGIOT, SIG_DFL); + reset_tty(); + abort(); + SIGNAL_RETURN; +} + +void +set_int(void) +{ + mySignal(SIGHUP, reset_exit); + mySignal(SIGINT, reset_exit); + mySignal(SIGQUIT, reset_exit); + mySignal(SIGTERM, reset_exit); + mySignal(SIGILL, error_dump); + mySignal(SIGIOT, error_dump); + mySignal(SIGFPE, error_dump); +#ifdef SIGBUS + mySignal(SIGBUS, error_dump); +#endif /* SIGBUS */ + /* mySignal(SIGSEGV, error_dump); */ +} + + +static void +setgraphchar(void) +{ + int c, i, n; + + for (c = 0; c < 96; c++) + gcmap[c] = (char)(c + ' '); + + if (!T_ac) + return; + + n = strlen(T_ac); + for (i = 0; i < n - 1; i += 2) { + c = (unsigned)T_ac[i] - ' '; + if (c >= 0 && c < 96) + gcmap[c] = T_ac[i + 1]; + } +} + +#define graphchar(c) (((unsigned)(c)>=' ' && (unsigned)(c)<128)? gcmap[(c)-' '] : (c)) +#define GETSTR(v,s) {v = pt; suc = tgetstr(s,&pt); if (!suc) v = ""; else v = allocStr(suc, -1); } + +void +getTCstr(void) +{ + char *ent; + char *suc; + char *pt = funcstr; + int r; + + ent = getenv("TERM") ? getenv("TERM") : DEFAULT_TERM; + if (ent == NULL) { + fprintf(stderr, "TERM is not set\n"); + reset_exit(SIGNAL_ARGLIST); + } + + r = tgetent(bp, ent); + if (r != 1) { + /* Can't find termcap entry */ + fprintf(stderr, "Can't find termcap entry %s\n", ent); + reset_exit(SIGNAL_ARGLIST); + } + + GETSTR(T_ce, "ce"); /* clear to the end of line */ + GETSTR(T_cd, "cd"); /* clear to the end of display */ + GETSTR(T_kr, "nd"); /* cursor right */ + if (suc == NULL) + GETSTR(T_kr, "kr"); + if (tgetflag("bs")) + T_kl = "\b"; /* cursor left */ + else { + GETSTR(T_kl, "le"); + if (suc == NULL) + GETSTR(T_kl, "kb"); + if (suc == NULL) + GETSTR(T_kl, "kl"); + } + GETSTR(T_cr, "cr"); /* carriage return */ + GETSTR(T_ta, "ta"); /* tab */ + GETSTR(T_sc, "sc"); /* save cursor */ + GETSTR(T_rc, "rc"); /* restore cursor */ + GETSTR(T_so, "so"); /* standout mode */ + GETSTR(T_se, "se"); /* standout mode end */ + GETSTR(T_us, "us"); /* underline mode */ + GETSTR(T_ue, "ue"); /* underline mode end */ + GETSTR(T_md, "md"); /* bold mode */ + GETSTR(T_me, "me"); /* bold mode end */ + GETSTR(T_cl, "cl"); /* clear screen */ + GETSTR(T_cm, "cm"); /* cursor move */ + GETSTR(T_al, "al"); /* append line */ + GETSTR(T_sr, "sr"); /* scroll reverse */ + GETSTR(T_ti, "ti"); /* terminal init */ + GETSTR(T_te, "te"); /* terminal end */ + GETSTR(T_nd, "nd"); /* move right one space */ + GETSTR(T_eA, "eA"); /* enable alternative charset */ + GETSTR(T_as, "as"); /* alternative (graphic) charset start */ + GETSTR(T_ae, "ae"); /* alternative (graphic) charset end */ + GETSTR(T_ac, "ac"); /* graphics charset pairs */ + GETSTR(T_op, "op"); /* set default color pair to its original value */ +#if defined( CYGWIN ) && CYGWIN < 1 + /* for TERM=pcansi on MS-DOS prompt. */ +#if 0 + T_eA = ""; + T_as = "\033[12m"; + T_ae = "\033[10m"; + T_ac = "l\001k\002m\003j\004x\005q\006n\020a\024v\025w\026u\027t\031"; +#endif + T_eA = ""; + T_as = ""; + T_ae = ""; + T_ac = ""; +#endif /* CYGWIN */ + + LINES = COLS = 0; + setlinescols(); + setgraphchar(); +} + +void +setlinescols(void) +{ + char *p; + int i; +#ifdef __EMX__ + { + int s[2]; + _scrsize(s); + COLS = s[0]; + LINES = s[1]; + + if (getenv("WINDOWID")) { + FILE *fd = popen("scrsize", "rt"); + if (fd) { + fscanf(fd, "%i %i", &COLS, &LINES); + pclose(fd); + } + } + } +#elif defined(HAVE_TERMIOS_H) && defined(TIOCGWINSZ) + struct winsize wins; + + i = ioctl(tty, TIOCGWINSZ, &wins); + if (i >= 0 && wins.ws_row != 0 && wins.ws_col != 0) { + LINES = wins.ws_row; + COLS = wins.ws_col; + } +#endif /* defined(HAVE-TERMIOS_H) && defined(TIOCGWINSZ) */ + if (LINES <= 0 && (p = getenv("LINES")) != NULL && (i = atoi(p)) >= 0) + LINES = i; + if (COLS <= 0 && (p = getenv("COLUMNS")) != NULL && (i = atoi(p)) >= 0) + COLS = i; + if (LINES <= 0) + LINES = tgetnum("li"); /* number of line */ + if (COLS <= 0) + COLS = tgetnum("co"); /* number of column */ + if (COLS > MAX_COLUMN) + COLS = MAX_COLUMN; + if (LINES > MAX_LINE) + LINES = MAX_LINE; +#if defined(__CYGWIN__) && LANG == JA + LASTLINE = LINES - (isWinConsole ? 2 : 1); +#endif /* defined(__CYGWIN__) && LANG == JA */ +} + +void +setupscreen(void) +{ + int i; + + if (LINES + 1 > max_LINES) { + max_LINES = LINES + 1; + max_COLS = 0; + ScreenElem = New_N(Screen, max_LINES); + ScreenImage = New_N(Screen *, max_LINES); + } + if (COLS + 1 > max_COLS) { + max_COLS = COLS + 1; + for (i = 0; i < max_LINES; i++) { +#ifdef USE_M17N + ScreenElem[i].lineimage = New_N(char *, max_COLS); + bzero((void *)ScreenElem[i].lineimage, max_COLS * sizeof(char *)); +#else + ScreenElem[i].lineimage = New_N(char, max_COLS); +#endif + ScreenElem[i].lineprop = New_N(l_prop, max_COLS); + } + } + for (i = 0; i < LINES; i++) { + ScreenImage[i] = &ScreenElem[i]; + ScreenImage[i]->lineprop[0] = S_EOL; + ScreenImage[i]->isdirty = 0; + } + for (; i < max_LINES; i++) { + ScreenElem[i].isdirty = L_UNUSED; + } + + clear(); +} + +/* + * Screen initialize + */ +int +initscr(void) +{ + if (set_tty() < 0) + return -1; + set_int(); + getTCstr(); + if (T_ti && !Do_not_use_ti_te) + writestr(T_ti); + setupscreen(); + return 0; +} + +static int +write1(char c) +{ + putc(c, ttyf); +#ifdef SCREEN_DEBUG + flush_tty(); +#endif /* SCREEN_DEBUG */ + return 0; +} + +void +move(int line, int column) +{ + if (line >= 0 && line < LINES) + CurLine = line; + if (column >= 0 && column < COLS) + CurColumn = column; +} + +#ifdef USE_BG_COLOR +#define M_SPACE (S_SCREENPROP|S_COLORED|S_BCOLORED|S_GRAPHICS) +#else /* not USE_BG_COLOR */ +#define M_SPACE (S_SCREENPROP|S_COLORED|S_GRAPHICS) +#endif /* not USE_BG_COLOR */ + +static int +#ifdef USE_M17N +need_redraw(char *c1, l_prop pr1, char *c2, l_prop pr2) +{ + if (!c1 || !c2 || strcmp(c1, c2)) + return 1; + if (*c1 == ' ') +#else +need_redraw(char c1, l_prop pr1, char c2, l_prop pr2) +{ + if (c1 != c2) + return 1; + if (c1 == ' ') +#endif + return (pr1 ^ pr2) & M_SPACE & ~S_DIRTY; + + if ((pr1 ^ pr2) & ~S_DIRTY) + return 1; + + return 0; +} + +#define M_CEOL (~(M_SPACE|C_WHICHCHAR)) + +#ifdef USE_M17N +#define SPACE " " +#else +#define SPACE ' ' +#endif + +#ifdef USE_M17N +void +addch(char c) +{ + addmch(&c, 1); +} + +void +addmch(char *pc, size_t len) +#else +void +addch(char pc) +#endif +{ + l_prop *pr; + int dest, i; + short *dirty; +#ifdef USE_M17N + static Str tmp = NULL; + char **p; + char c = *pc; + int width = wtf_width((wc_uchar *) pc); + + if (tmp == NULL) + tmp = Strnew(); + Strcopy_charp_n(tmp, pc, len); + pc = tmp->ptr; +#else + char *p; + char c = pc; +#endif + + if (CurColumn == COLS) + wrap(); + if (CurColumn >= COLS) + return; + p = ScreenImage[CurLine]->lineimage; + pr = ScreenImage[CurLine]->lineprop; + dirty = &ScreenImage[CurLine]->isdirty; + +#ifndef USE_M17N + /* Eliminate unprintables according to * iso-8859-*. + * Particularly 0x96 messes up T.Dickey's * (xfree-)xterm */ + if (IS_INTSPACE(c)) + c = ' '; +#endif + + if (pr[CurColumn] & S_EOL) { + if (c == ' ' && !(CurrentMode & M_SPACE)) { + CurColumn++; + return; + } + for (i = CurColumn; i >= 0 && (pr[i] & S_EOL); i--) { + SETCH(p[i], SPACE, 1); + SETPROP(pr[i], (pr[i] & M_CEOL) | C_ASCII); + } + } + + if (c == '\t' || c == '\n' || c == '\r' || c == '\b') + SETCHMODE(CurrentMode, C_CTRL); +#ifdef USE_M17N + else if (len > 1) + SETCHMODE(CurrentMode, C_WCHAR1); +#endif + else if (!IS_CNTRL(c)) + SETCHMODE(CurrentMode, C_ASCII); + else + return; + + /* Required to erase bold or underlined character for some * terminal + * emulators. */ +#ifdef USE_M17N + i = CurColumn + width - 1; +#else + i = CurColumn; +#endif + if (i < COLS && + (((pr[i] & S_BOLD) && need_redraw(p[i], pr[i], pc, CurrentMode)) || + ((pr[i] & S_UNDERLINE) && !(CurrentMode & S_UNDERLINE)))) { + touch_line(); + i++; + if (i < COLS) { + touch_column(i); + if (pr[i] & S_EOL) { + SETCH(p[i], SPACE, 1); + SETPROP(pr[i], (pr[i] & M_CEOL) | C_ASCII); + } +#ifdef USE_M17N + else { + for (i++; i < COLS && CHMODE(pr[i]) == C_WCHAR2; i++) + touch_column(i); + } +#endif + } + } + +#ifdef USE_M17N + if (CurColumn + width > COLS) { + touch_line(); + for (i = CurColumn; i < COLS; i++) { + SETCH(p[i], SPACE, 1); + SETPROP(pr[i], (pr[i] & ~C_WHICHCHAR) | C_ASCII); + touch_column(i); + } + wrap(); + if (CurColumn + width > COLS) + return; + p = ScreenImage[CurLine]->lineimage; + pr = ScreenImage[CurLine]->lineprop; + } + if (CHMODE(pr[CurColumn]) == C_WCHAR2) { + touch_line(); + for (i = CurColumn - 1; i >= 0; i--) { + l_prop l = CHMODE(pr[i]); + SETCH(p[i], SPACE, 1); + SETPROP(pr[i], (pr[i] & ~C_WHICHCHAR) | C_ASCII); + touch_column(i); + if (l != C_WCHAR2) + break; + } + } +#endif + if (CHMODE(CurrentMode) != C_CTRL) { + if (need_redraw(p[CurColumn], pr[CurColumn], pc, CurrentMode)) { + SETCH(p[CurColumn], pc, len); + SETPROP(pr[CurColumn], CurrentMode); + touch_line(); + touch_column(CurColumn); +#ifdef USE_M17N + SETCHMODE(CurrentMode, C_WCHAR2); + for (i = CurColumn + 1; i < CurColumn + width; i++) { + SETCH(p[i], SPACE, 1); + SETPROP(pr[i], (pr[CurColumn] & ~C_WHICHCHAR) | C_WCHAR2); + touch_column(i); + } + for (; i < COLS && CHMODE(pr[i]) == C_WCHAR2; i++) { + SETCH(p[i], SPACE, 1); + SETPROP(pr[i], (pr[i] & ~C_WHICHCHAR) | C_ASCII); + touch_column(i); + } + } + CurColumn += width; +#else + } + CurColumn++; +#endif + } + else if (c == '\t') { + dest = (CurColumn + tab_step) / tab_step * tab_step; + if (dest >= COLS) { + wrap(); + touch_line(); + dest = tab_step; + p = ScreenImage[CurLine]->lineimage; + pr = ScreenImage[CurLine]->lineprop; + } + for (i = CurColumn; i < dest; i++) { + if (need_redraw(p[i], pr[i], SPACE, CurrentMode)) { + SETCH(p[i], SPACE, 1); + SETPROP(pr[i], CurrentMode); + touch_line(); + touch_column(i); + } + } + CurColumn = i; + } + else if (c == '\n') { + wrap(); + } + else if (c == '\r') { /* Carriage return */ + CurColumn = 0; + } + else if (c == '\b' && CurColumn > 0) { /* Backspace */ + CurColumn--; +#ifdef USE_M17N + while (CurColumn > 0 && CHMODE(pr[CurColumn]) == C_WCHAR2) + CurColumn--; +#endif + } +} + +void +wrap(void) +{ + if (CurLine == LASTLINE) + return; + CurLine++; + CurColumn = 0; +} + +void +touch_column(int col) +{ + if (col >= 0 && col < COLS) + ScreenImage[CurLine]->lineprop[col] |= S_DIRTY; +} + +void +touch_line(void) +{ + if (!(ScreenImage[CurLine]->isdirty & L_DIRTY)) { + int i; + for (i = 0; i < COLS; i++) + ScreenImage[CurLine]->lineprop[i] &= ~S_DIRTY; + ScreenImage[CurLine]->isdirty |= L_DIRTY; + } + +} + +void +standout(void) +{ + CurrentMode |= S_STANDOUT; +} + +void +standend(void) +{ + CurrentMode &= ~S_STANDOUT; +} + +void +toggle_stand(void) +{ +#ifdef USE_M17N + int i; +#endif + l_prop *pr = ScreenImage[CurLine]->lineprop; + pr[CurColumn] ^= S_STANDOUT; +#ifdef USE_M17N + if (CHMODE(pr[CurColumn]) != C_WCHAR2) { + for (i = CurColumn + 1; CHMODE(pr[i]) == C_WCHAR2; i++) + pr[i] ^= S_STANDOUT; + } +#endif +} + +void +bold(void) +{ + CurrentMode |= S_BOLD; +} + +void +boldend(void) +{ + CurrentMode &= ~S_BOLD; +} + +void +underline(void) +{ + CurrentMode |= S_UNDERLINE; +} + +void +underlineend(void) +{ + CurrentMode &= ~S_UNDERLINE; +} + +void +graphstart(void) +{ + CurrentMode |= S_GRAPHICS; +} + +void +graphend(void) +{ + CurrentMode &= ~S_GRAPHICS; +} + +int +graph_ok(void) +{ + if (!UseGraphicChar) + return 0; + return T_as[0] != 0 && T_ae[0] != 0 && T_ac[0] != 0; +} + +void +setfcolor(int color) +{ + CurrentMode &= ~COL_FCOLOR; + if ((color & 0xf) <= 7) + CurrentMode |= (((color & 7) | 8) << 8); +} + +static char * +color_seq(int colmode) +{ + static char seqbuf[32]; + sprintf(seqbuf, "\033[%dm", ((colmode >> 8) & 7) + 30); + return seqbuf; +} + +#ifdef USE_BG_COLOR +void +setbcolor(int color) +{ + CurrentMode &= ~COL_BCOLOR; + if ((color & 0xf) <= 7) + CurrentMode |= (((color & 7) | 8) << 12); +} + +static char * +bcolor_seq(int colmode) +{ + static char seqbuf[32]; + sprintf(seqbuf, "\033[%dm", ((colmode >> 12) & 7) + 40); + return seqbuf; +} +#endif /* USE_BG_COLOR */ + +#define RF_NEED_TO_MOVE 0 +#define RF_CR_OK 1 +#define RF_NONEED_TO_MOVE 2 +#ifdef USE_BG_COLOR +#define M_MEND (S_STANDOUT|S_UNDERLINE|S_BOLD|S_COLORED|S_BCOLORED|S_GRAPHICS) +#else /* not USE_BG_COLOR */ +#define M_MEND (S_STANDOUT|S_UNDERLINE|S_BOLD|S_COLORED|S_GRAPHICS) +#endif /* not USE_BG_COLOR */ +void +refresh(void) +{ + int line, col, pcol; + int pline = CurLine; + int moved = RF_NEED_TO_MOVE; +#ifdef USE_M17N + char **pc; +#else + char *pc; +#endif + l_prop *pr, mode = 0; + l_prop color = COL_FTERM; +#ifdef USE_BG_COLOR + l_prop bcolor = COL_BTERM; +#endif /* USE_BG_COLOR */ + short *dirty; + +#ifdef USE_M17N + wc_putc_init(InnerCharset, DisplayCharset); +#endif + for (line = 0; line <= LASTLINE; line++) { + dirty = &ScreenImage[line]->isdirty; + if (*dirty & L_DIRTY) { + *dirty &= ~L_DIRTY; + pc = ScreenImage[line]->lineimage; + pr = ScreenImage[line]->lineprop; + for (col = 0; col < COLS && !(pr[col] & S_EOL); col++) { + if (*dirty & L_NEED_CE && col >= ScreenImage[line]->eol) { + if (need_redraw(pc[col], pr[col], SPACE, 0)) + break; + } + else { + if (pr[col] & S_DIRTY) + break; + } + } + if (*dirty & (L_NEED_CE | L_CLRTOEOL)) { + pcol = ScreenImage[line]->eol; + if (pcol >= COLS) { + *dirty &= ~(L_NEED_CE | L_CLRTOEOL); + pcol = col; + } + } + else { + pcol = col; + } + if (line < LINES - 2 && pline == line - 1 && pcol == 0) { + switch (moved) { + case RF_NEED_TO_MOVE: + MOVE(line, 0); + moved = RF_CR_OK; + break; + case RF_CR_OK: + write1('\n'); + write1('\r'); + break; + case RF_NONEED_TO_MOVE: + moved = RF_CR_OK; + break; + } + } + else { + MOVE(line, pcol); + moved = RF_CR_OK; + } + if (*dirty & (L_NEED_CE | L_CLRTOEOL)) { + writestr(T_ce); + if (col != pcol) + MOVE(line, col); + } + pline = line; + pcol = col; + for (; col < COLS; col++) { + if (pr[col] & S_EOL) + break; + + /* + * some terminal emulators do linefeed when a + * character is put on COLS-th column. this behavior + * is different from one of vt100, but such terminal + * emulators are used as vt100-compatible + * emulators. This behaviour causes scroll when a + * character is drawn on (COLS-1,LINES-1) point. To + * avoid the scroll, I prohibit to draw character on + * (COLS-1,LINES-1). + */ +#if !defined(USE_BG_COLOR) || defined(__CYGWIN__) +#if defined(__CYGWIN__) && LANG == JA + if (isWinConsole) +#endif /* defined(__CYGWIN__) && LANG == JA */ + if (line == LINES - 1 && col == COLS - 1) + break; +#endif /* !defined(USE_BG_COLOR) || defined(__CYGWIN__) */ + if ((!(pr[col] & S_STANDOUT) && (mode & S_STANDOUT)) || + (!(pr[col] & S_UNDERLINE) && (mode & S_UNDERLINE)) || + (!(pr[col] & S_BOLD) && (mode & S_BOLD)) || + (!(pr[col] & S_COLORED) && (mode & S_COLORED)) +#ifdef USE_BG_COLOR + || (!(pr[col] & S_BCOLORED) && (mode & S_BCOLORED)) +#endif /* USE_BG_COLOR */ + || (!(pr[col] & S_GRAPHICS) && (mode & S_GRAPHICS))) { + if ((mode & S_COLORED) +#ifdef USE_BG_COLOR + || (mode & S_BCOLORED) +#endif /* USE_BG_COLOR */ + ) + writestr(T_op); + if (mode & S_GRAPHICS) + writestr(T_ae); + writestr(T_me); + mode &= ~M_MEND; + } + if ((*dirty & L_NEED_CE && col >= ScreenImage[line]->eol) ? + need_redraw(pc[col], pr[col], SPACE, + 0) : (pr[col] & S_DIRTY)) { + if (pcol == col - 1) + writestr(T_nd); + else if (pcol != col) + MOVE(line, col); + + if ((pr[col] & S_STANDOUT) && !(mode & S_STANDOUT)) { + writestr(T_so); + mode |= S_STANDOUT; + } + if ((pr[col] & S_UNDERLINE) && !(mode & S_UNDERLINE)) { + writestr(T_us); + mode |= S_UNDERLINE; + } + if ((pr[col] & S_BOLD) && !(mode & S_BOLD)) { + writestr(T_md); + mode |= S_BOLD; + } + if ((pr[col] & S_COLORED) && (pr[col] ^ mode) & COL_FCOLOR) { + color = (pr[col] & COL_FCOLOR); + mode = ((mode & ~COL_FCOLOR) | color); + writestr(color_seq(color)); + } +#ifdef USE_BG_COLOR + if ((pr[col] & S_BCOLORED) + && (pr[col] ^ mode) & COL_BCOLOR) { + bcolor = (pr[col] & COL_BCOLOR); + mode = ((mode & ~COL_BCOLOR) | bcolor); + writestr(bcolor_seq(bcolor)); + } +#endif /* USE_BG_COLOR */ + if ((pr[col] & S_GRAPHICS) && !(mode & S_GRAPHICS)) { +#ifdef USE_M17N + wc_putc_end(ttyf); +#endif + if (!graph_enabled) { + graph_enabled = 1; + writestr(T_eA); + } + writestr(T_as); + mode |= S_GRAPHICS; + } +#ifdef USE_M17N + if (pr[col] & S_GRAPHICS) + write1(graphchar(*pc[col])); + else if (CHMODE(pr[col]) != C_WCHAR2) + wc_putc(pc[col], ttyf); +#else + write1((pr[col] & S_GRAPHICS) ? graphchar(pc[col]) : + pc[col]); +#endif + pcol = col + 1; + } + } + if (col == COLS) + moved = RF_NEED_TO_MOVE; + for (; col < COLS && !(pr[col] & S_EOL); col++) + pr[col] |= S_EOL; + } + *dirty &= ~(L_NEED_CE | L_CLRTOEOL); + if (mode & M_MEND) { + if (mode & (S_COLORED +#ifdef USE_BG_COLOR + | S_BCOLORED +#endif /* USE_BG_COLOR */ + )) + writestr(T_op); + if (mode & S_GRAPHICS) { + writestr(T_ae); +#ifdef USE_M17N + wc_putc_clear_status(); +#endif + } + writestr(T_me); + mode &= ~M_MEND; + } + } +#ifdef USE_M17N + wc_putc_end(ttyf); +#endif + MOVE(CurLine, CurColumn); + flush_tty(); +} + +void +clear(void) +{ + int i, j; + l_prop *p; + writestr(T_cl); + move(0, 0); + for (i = 0; i < LINES; i++) { + ScreenImage[i]->isdirty = 0; + p = ScreenImage[i]->lineprop; + for (j = 0; j < COLS; j++) { + p[j] = S_EOL; + } + } + CurrentMode = C_ASCII; +} + +#ifdef USE_RAW_SCROLL +static void +scroll_raw(void) +{ /* raw scroll */ + MOVE(LINES - 1, 0); + write1('\n'); +} + +void +scroll(int n) +{ /* scroll up */ + int cli = CurLine, cco = CurColumn; + Screen *t; + int i, j, k; + + i = LINES; + j = n; + do { + k = j; + j = i % k; + i = k; + } while (j); + do { + k--; + i = k; + j = (i + n) % LINES; + t = ScreenImage[k]; + while (j != k) { + ScreenImage[i] = ScreenImage[j]; + i = j; + j = (i + n) % LINES; + } + ScreenImage[i] = t; + } while (k); + + for (i = 0; i < n; i++) { + t = ScreenImage[LINES - 1 - i]; + t->isdirty = 0; + for (j = 0; j < COLS; j++) + t->lineprop[j] = S_EOL; + scroll_raw(); + } + move(cli, cco); +} + +void +rscroll(int n) +{ /* scroll down */ + int cli = CurLine, cco = CurColumn; + Screen *t; + int i, j, k; + + i = LINES; + j = n; + do { + k = j; + j = i % k; + i = k; + } while (j); + do { + k--; + i = k; + j = (LINES + i - n) % LINES; + t = ScreenImage[k]; + while (j != k) { + ScreenImage[i] = ScreenImage[j]; + i = j; + j = (LINES + i - n) % LINES; + } + ScreenImage[i] = t; + } while (k); + if (T_sr && *T_sr) { + MOVE(0, 0); + for (i = 0; i < n; i++) { + t = ScreenImage[i]; + t->isdirty = 0; + for (j = 0; j < COLS; j++) + t->lineprop[j] = S_EOL; + writestr(T_sr); + } + move(cli, cco); + } + else { + for (i = 0; i < LINES; i++) { + t = ScreenImage[i]; + t->isdirty |= L_DIRTY | L_NEED_CE; + for (j = 0; j < COLS; j++) { + t->lineprop[j] |= S_DIRTY; + } + } + } +} +#endif + +#if 0 +void +need_clrtoeol(void) +{ + /* Clear to the end of line as the need arises */ + l_prop *lprop = ScreenImage[CurLine]->lineprop; + + if (lprop[CurColumn] & S_EOL) + return; + + if (!(ScreenImage[CurLine]->isdirty & (L_NEED_CE | L_CLRTOEOL)) || + ScreenImage[CurLine]->eol > CurColumn) + ScreenImage[CurLine]->eol = CurColumn; + + ScreenImage[CurLine]->isdirty |= L_NEED_CE; +} +#endif /* 0 */ + +/* XXX: conflicts with curses's clrtoeol(3) ? */ +void +clrtoeol(void) +{ /* Clear to the end of line */ + int i; + l_prop *lprop = ScreenImage[CurLine]->lineprop; + + if (lprop[CurColumn] & S_EOL) + return; + + if (!(ScreenImage[CurLine]->isdirty & (L_NEED_CE | L_CLRTOEOL)) || + ScreenImage[CurLine]->eol > CurColumn) + ScreenImage[CurLine]->eol = CurColumn; + + ScreenImage[CurLine]->isdirty |= L_CLRTOEOL; + touch_line(); + for (i = CurColumn; i < COLS && !(lprop[i] & S_EOL); i++) { + lprop[i] = S_EOL | S_DIRTY; + } +} + +#ifdef USE_BG_COLOR +void +clrtoeol_with_bcolor(void) +{ + int i, cli, cco; + l_prop pr; + + if (!(CurrentMode & S_BCOLORED)) { + clrtoeol(); + return; + } + cli = CurLine; + cco = CurColumn; + pr = CurrentMode; + CurrentMode = (CurrentMode & (M_CEOL | S_BCOLORED)) | C_ASCII; + for (i = CurColumn; i < COLS; i++) + addch(' '); + move(cli, cco); + CurrentMode = pr; +} + +void +clrtoeolx(void) +{ + clrtoeol_with_bcolor(); +} +#else /* not USE_BG_COLOR */ + +void +clrtoeolx(void) +{ + clrtoeol(); +} +#endif /* not USE_BG_COLOR */ + +void +clrtobot_eol(void (*clrtoeol) ()) +{ + int l, c; + + l = CurLine; + c = CurColumn; + (*clrtoeol) (); + CurColumn = 0; + CurLine++; + for (; CurLine < LINES; CurLine++) + (*clrtoeol) (); + CurLine = l; + CurColumn = c; +} + +void +clrtobot(void) +{ + clrtobot_eol(clrtoeol); +} + +void +clrtobotx(void) +{ + clrtobot_eol(clrtoeolx); +} + +#if 0 +void +no_clrtoeol(void) +{ + int i; + l_prop *lprop = ScreenImage[CurLine]->lineprop; + + ScreenImage[CurLine]->isdirty &= ~L_CLRTOEOL; +} +#endif /* 0 */ + +void +addstr(char *s) +{ +#ifdef USE_M17N + int len; + + while (*s != '\0') { + len = wtf_len((wc_uchar *) s); + addmch(s, len); + s += len; + } +#else + while (*s != '\0') + addch(*(s++)); +#endif +} + +void +addnstr(char *s, int n) +{ + int i; +#ifdef USE_M17N + int len, width; + + for (i = 0; *s != '\0';) { + width = wtf_width((wc_uchar *) s); + if (i + width > n) + break; + len = wtf_len((wc_uchar *) s); + addmch(s, len); + s += len; + i += width; + } +#else + for (i = 0; i < n && *s != '\0'; i++) + addch(*(s++)); +#endif +} + +void +addnstr_sup(char *s, int n) +{ + int i; +#ifdef USE_M17N + int len, width; + + for (i = 0; *s != '\0';) { + width = wtf_width((wc_uchar *) s); + if (i + width > n) + break; + len = wtf_len((wc_uchar *) s); + addmch(s, len); + s += len; + i += width; + } +#else + for (i = 0; i < n && *s != '\0'; i++) + addch(*(s++)); +#endif + for (; i < n; i++) + addch(' '); +} + +void +crmode(void) +#ifndef HAVE_SGTTY_H +{ + ttymode_reset(ICANON, IXON); + ttymode_set(ISIG, 0); +#ifdef HAVE_TERMIOS_H + set_cc(VMIN, 1); +#else /* not HAVE_TERMIOS_H */ + set_cc(VEOF, 1); +#endif /* not HAVE_TERMIOS_H */ +} +#else /* HAVE_SGTTY_H */ +{ + ttymode_set(CBREAK, 0); +} +#endif /* HAVE_SGTTY_H */ + +void +nocrmode(void) +#ifndef HAVE_SGTTY_H +{ + ttymode_set(ICANON, 0); +#ifdef HAVE_TERMIOS_H + set_cc(VMIN, 4); +#else /* not HAVE_TERMIOS_H */ + set_cc(VEOF, 4); +#endif /* not HAVE_TERMIOS_H */ +} +#else /* HAVE_SGTTY_H */ +{ + ttymode_reset(CBREAK, 0); +} +#endif /* HAVE_SGTTY_H */ + +void +term_echo(void) +{ + ttymode_set(ECHO, 0); +} + +void +term_noecho(void) +{ + ttymode_reset(ECHO, 0); +} + +void +term_raw(void) +#ifndef HAVE_SGTTY_H +#ifdef IEXTEN +#define TTY_MODE ISIG|ICANON|ECHO|IEXTEN +#else /* not IEXTEN */ +#define TTY_MODE ISIG|ICANON|ECHO +#endif /* not IEXTEN */ +{ + ttymode_reset(TTY_MODE, IXON | IXOFF); +#ifdef HAVE_TERMIOS_H + set_cc(VMIN, 1); +#else /* not HAVE_TERMIOS_H */ + set_cc(VEOF, 1); +#endif /* not HAVE_TERMIOS_H */ +} +#else /* HAVE_SGTTY_H */ +{ + ttymode_set(RAW, 0); +} +#endif /* HAVE_SGTTY_H */ + +void +term_cooked(void) +#ifndef HAVE_SGTTY_H +{ +#ifdef __EMX__ + /* On XFree86/OS2, some scrambled characters + * will appear when asserting IEXTEN flag. + */ + ttymode_set((TTY_MODE) & ~IEXTEN, 0); +#else + ttymode_set(TTY_MODE, 0); +#endif +#ifdef HAVE_TERMIOS_H + set_cc(VMIN, 4); +#else /* not HAVE_TERMIOS_H */ + set_cc(VEOF, 4); +#endif /* not HAVE_TERMIOS_H */ +} +#else /* HAVE_SGTTY_H */ +{ + ttymode_reset(RAW, 0); +} +#endif /* HAVE_SGTTY_H */ + +void +term_cbreak(void) +{ + term_cooked(); + term_noecho(); +} + +void +term_title(char *s) +{ + if (!fmInitialized) + return; + if (title_str != NULL) { +#ifdef __CYGWIN__ + if (isLocalConsole && title_str == CYGWIN_TITLE) { + Str buff; + buff = Sprintf(title_str, s); + if (buff->length > 1024) { + Strtruncate(buff, 1024); + } + SetConsoleTitle(buff->ptr); + } + else if (isLocalConsole || !isWinConsole) +#endif + fprintf(ttyf, title_str, s); + } +} + +char +getch(void) +{ + char c; + + while ( +#ifdef SUPPORT_WIN9X_CONSOLE_MBCS + read_win32_console(&c, 1) +#else + read(tty, &c, 1) +#endif + < (int)1) { + if (errno == EINTR || errno == EAGAIN) + continue; + /* error happend on read(2) */ + quitfm(); + break; /* unreachable */ + } + return c; +} + +#ifdef USE_MOUSE +#ifdef USE_GPM +char +wgetch(void *p) +{ + char c; + + /* read(tty, &c, 1); */ + while (read(tty, &c, 1) < (ssize_t) 1) { + if (errno == EINTR || errno == EAGAIN) + continue; + /* error happend on read(2) */ + quitfm(); + break; /* unreachable */ + } + return c; +} + +int +do_getch() +{ + if (is_xterm) + return getch(); + else + return Gpm_Getch(); +} +#endif /* USE_GPM */ + +#ifdef USE_SYSMOUSE +int +sysm_getch() +{ + fd_set rfd; + int key, x, y; + + FD_ZERO(&rfd); + FD_SET(tty, &rfd); + while (select(tty + 1, &rfd, NULL, NULL, NULL) <= 0) { + if (errno == EINTR) { + x = xpix / cwidth; + y = ypix / cheight; + key = (*sysm_handler) (x, y, nbs, obs); + if (key != 0) + return key; + } + } + return getch(); +} + +int +do_getch() +{ + if (is_xterm || !sysm_handler) + return getch(); + else + return sysm_getch(); +} + +MySignalHandler +sysmouse(SIGNAL_ARG) +{ + struct mouse_info mi; + + mi.operation = MOUSE_GETINFO; + if (ioctl(tty, CONS_MOUSECTL, &mi) == -1) + return; + xpix = mi.u.data.x; + ypix = mi.u.data.y; + obs = nbs; + nbs = mi.u.data.buttons & 0x7; + /* for cosmetic bug in syscons.c on FreeBSD 3.[34] */ + mi.operation = MOUSE_HIDE; + ioctl(tty, CONS_MOUSECTL, &mi); + mi.operation = MOUSE_SHOW; + ioctl(tty, CONS_MOUSECTL, &mi); +} +#endif /* USE_SYSMOUSE */ +#endif /* USE_MOUSE */ + +void +bell(void) +{ + write1(7); +} + +void +skip_escseq(void) +{ + int c; + + c = getch(); + if (c == '[' || c == 'O') { + c = getch(); +#ifdef USE_MOUSE + if (is_xterm && c == 'M') { + getch(); + getch(); + getch(); + } + else +#endif + while (IS_DIGIT(c)) + c = getch(); + } +} + +int +sleep_till_anykey(int sec, int purge) +{ + fd_set rfd; + struct timeval tim; + int er, c, ret; + TerminalMode ioval; + + TerminalGet(tty, &ioval); + term_raw(); + + tim.tv_sec = sec; + tim.tv_usec = 0; + + FD_ZERO(&rfd); + FD_SET(tty, &rfd); + + ret = select(tty + 1, &rfd, 0, 0, &tim); + if (ret > 0 && purge) { + c = getch(); + if (c == ESC_CODE) + skip_escseq(); + } + er = TerminalSet(tty, &ioval); + if (er == -1) { + printf("Error occured: errno=%d\n", errno); + reset_exit(SIGNAL_ARGLIST); + } + return ret; +} + +#ifdef USE_MOUSE + +#define XTERM_ON {fputs("\033[?1001s\033[?1000h",ttyf); flush_tty();} +#define XTERM_OFF {fputs("\033[?1000l\033[?1001r",ttyf); flush_tty();} +#define CYGWIN_ON {fputs("\033[?1000h",ttyf); flush_tty();} +#define CYGWIN_OFF {fputs("\033[?1000l",ttyf); flush_tty();} + +#ifdef USE_GPM +/* Linux console with GPM support */ + +void +mouse_init() +{ + Gpm_Connect conn; + extern int gpm_process_mouse(Gpm_Event *, void *); + int r; + + if (mouseActive) + return; + conn.eventMask = ~0; + conn.defaultMask = 0; + conn.maxMod = 0; + conn.minMod = 0; + + r = Gpm_Open(&conn, 0); + if (r == -2) { + /* + * If Gpm_Open() success, returns >= 0 + * Gpm_Open() returns -2 in case of xterm. + * Gpm_Close() is necessary here. Otherwise, + * xterm is being left in the mode where the mouse clicks are + * passed through to the application. + */ + Gpm_Close(); + is_xterm = (NEED_XTERM_ON | NEED_XTERM_OFF); + } + else if (r >= 0) { + gpm_handler = gpm_process_mouse; + is_xterm = 0; + } + if (is_xterm) { + XTERM_ON; + } + mouseActive = 1; +} + +void +mouse_end() +{ + if (mouseActive == 0) + return; + if (is_xterm) { + XTERM_OFF; + } + else + Gpm_Close(); + mouseActive = 0; +} + +#elif defined(USE_SYSMOUSE) +/* *BSD console with sysmouse support */ +void +mouse_init() +{ + mouse_info_t mi; + extern int sysm_process_mouse(); + + if (mouseActive) + return; + if (is_xterm) { + XTERM_ON; + } + else { +#if defined(FBIO_MODEINFO) || defined(CONS_MODEINFO) /* FreeBSD > 2.x */ +#ifndef FBIO_GETMODE /* FreeBSD 3.x */ +#define FBIO_GETMODE CONS_GET +#define FBIO_MODEINFO CONS_MODEINFO +#endif /* FBIO_GETMODE */ + video_info_t vi; + + if (ioctl(tty, FBIO_GETMODE, &vi.vi_mode) != -1 && + ioctl(tty, FBIO_MODEINFO, &vi) != -1) { + cwidth = vi.vi_cwidth; + cheight = vi.vi_cheight; + } +#endif /* defined(FBIO_MODEINFO) || + * defined(CONS_MODEINFO) */ + mySignal(SIGUSR2, SIG_IGN); + mi.operation = MOUSE_MODE; + mi.u.mode.mode = 0; + mi.u.mode.signal = SIGUSR2; + sysm_handler = NULL; + if (ioctl(tty, CONS_MOUSECTL, &mi) != -1) { + mySignal(SIGUSR2, sysmouse); + mi.operation = MOUSE_SHOW; + ioctl(tty, CONS_MOUSECTL, &mi); + sysm_handler = sysm_process_mouse; + } + } + mouseActive = 1; +} + +void +mouse_end() +{ + if (mouseActive == 0) + return; + if (is_xterm) { + XTERM_OFF; + } + else { + mouse_info_t mi; + mi.operation = MOUSE_MODE; + mi.u.mode.mode = 0; + mi.u.mode.signal = 0; + ioctl(tty, CONS_MOUSECTL, &mi); + } + mouseActive = 0; +} + +#else +/* not GPM nor SYSMOUSE, but use mouse with xterm */ + +void +mouse_init() +{ + if (mouseActive) + return; + if (is_xterm & NEED_XTERM_ON) { + XTERM_ON; + } +#ifdef __CYGWIN__ + else if (is_xterm & NEED_CYGWIN_ON) { + CYGWIN_ON; + } +#endif + mouseActive = 1; +} + +void +mouse_end() +{ + if (mouseActive == 0) + return; + if (is_xterm & NEED_XTERM_OFF) { + XTERM_OFF; + } +#ifdef __CYGWIN__ + else if (is_xterm & NEED_CYGWIN_OFF) { + CYGWIN_OFF; + } +#endif + mouseActive = 0; +} + +#endif /* not USE_GPM nor USE_SYSMOUSE */ + + +void +mouse_active() +{ + if (!mouseActive) + mouse_init(); +} + +void +mouse_inactive() +{ + if (mouseActive && is_xterm) + mouse_end(); +} + +#endif /* USE_MOUSE */ + +void +flush_tty() +{ + if (ttyf) + fflush(ttyf); +} + +#ifdef USE_IMAGE +void +touch_cursor() +{ +#ifdef USE_M17N + int i; +#endif + touch_line(); +#ifdef USE_M17N + for (i = CurColumn; i >= 0; i--) { + touch_column(i); + if (CHMODE(ScreenImage[CurLine]->lineprop[i]) != C_WCHAR2) + break; + } + for (i = CurColumn + 1; i < COLS; i++) { + if (CHMODE(ScreenImage[CurLine]->lineprop[i]) != C_WCHAR2) + break; + touch_column(i); + } +#else + touch_column(CurColumn); +#endif +} +#endif |