mc/slang/sldisply.c

2857 lines
63 KiB
C
Raw Normal View History

/*
Copyright (C) 2004, 2005 John E. Davis
This file is part of the S-Lang Library.
The S-Lang Library 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 of the
License, or (at your option) any later version.
The S-Lang Library 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 library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
USA.
*/
#include "slinclud.h"
1998-02-27 07:54:42 +03:00
#include <time.h>
#include <ctype.h>
#if !defined(VMS) || (__VMS_VER >= 70000000)
1998-02-27 07:54:42 +03:00
# include <sys/time.h>
# ifdef __QNX__
# include <sys/select.h>
1998-02-27 07:54:42 +03:00
# endif
# include <sys/types.h>
#endif
#ifdef __BEOS__
/* Prototype for select */
# include <net/socket.h>
#endif
#ifdef HAVE_TERMIOS_H
# include <termios.h>
#endif
#ifdef VMS
# include <unixlib.h>
# include <unixio.h>
# include <dvidef.h>
# include <descrip.h>
# include <lib$routines.h>
# include <starlet.h>
#else
# if !defined(sun)
# include <sys/ioctl.h>
# endif
#endif
#ifdef SYSV
# include <sys/termio.h>
# include <sys/stream.h>
# include <sys/ptem.h>
# include <sys/tty.h>
#endif
#if defined (_AIX) && !defined (FD_SET)
# include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
#endif
#include <errno.h>
#if defined(__DECC) && defined(VMS)
/* These get prototypes for write an sleep */
# include <unixio.h>
#endif
#include <signal.h>
#include "slang.h"
#include "_slang.h"
1998-02-27 07:54:42 +03:00
/* Colors: These definitions are used for the display. However, the
1998-02-27 07:54:42 +03:00
* application only uses object handles which get mapped to this
* internal representation. The mapping is performed by the Color_Map
* structure below. */
#define CHAR_MASK 0x000000FF
#define FG_MASK 0x0000FF00
#define BG_MASK 0x00FF0000
#define ATTR_MASK 0x1F000000
#define BGALL_MASK 0x0FFF0000
/* The 0x10000000 bit represents the alternate character set. BGALL_MASK does
* not include this attribute.
*/
#define GET_FG(fgbg) (((fgbg) & FG_MASK) >> 8)
#define GET_BG(fgbg) (((fgbg) & BG_MASK) >> 16)
1998-02-27 07:54:42 +03:00
#define MAKE_COLOR(fg, bg) (((fg) | ((bg) << 8)) << 8)
int SLtt_Screen_Cols = 80;
int SLtt_Screen_Rows = 24;
1998-02-27 07:54:42 +03:00
int SLtt_Term_Cannot_Insert;
int SLtt_Term_Cannot_Scroll;
int SLtt_Use_Ansi_Colors;
int SLtt_Blink_Mode = 0;
1998-02-27 07:54:42 +03:00
int SLtt_Use_Blink_For_ACS = 0;
int SLtt_Newline_Ok = 0;
int SLtt_Has_Alt_Charset = 0;
int SLtt_Force_Keypad_Init = 0;
/* static int UTF8_Mode = -1; */
void (*_pSLtt_color_changed_hook)(void);
#if SLTT_HAS_NON_BCE_SUPPORT
static int Bce_Color_Offset = 0;
#endif
static int Can_Background_Color_Erase = 1;
1998-02-27 07:54:42 +03:00
/* -1 means unknown */
int SLtt_Has_Status_Line = -1; /* hs */
int SLang_TT_Write_FD = -1;
1998-02-27 07:54:42 +03:00
static int Automatic_Margins;
/* static int No_Move_In_Standout; */
static int Worthless_Highlight;
#define HP_GLITCH_CODE
#ifdef HP_GLITCH_CODE
/* This glitch is exclusive to HP term. Basically it means that to clear
1998-02-27 07:54:42 +03:00
* attributes, one has to erase to the end of the line.
*/
static int Has_HP_Glitch;
#endif
static char *Reset_Color_String;
static int Is_Color_Terminal = 0;
1998-02-27 07:54:42 +03:00
static int Linux_Console;
static int QANSI_Console;
static int Mouse_Mode = -1;
1998-02-27 07:54:42 +03:00
/* The following comment is nolonger valid, but is here in case there are
* some apps that use SLtt_Use_Blink_For_ACS and still need porting to v2.
* -------
* It is crucial that JMAX_COLORS must be less than 128 since the high bit
1998-02-27 07:54:42 +03:00
* is used to indicate a character from the ACS (alt char set). The exception
* to this rule is if SLtt_Use_Blink_For_ACS is true. This means that of
* the highbit is set, we interpret that as a blink character. This is
1998-02-27 07:54:42 +03:00
* exploited by DOSemu.
*/
#define JMAX_COLORS 512
1998-02-27 07:54:42 +03:00
#define JNORMAL_COLOR 0
typedef struct
1998-02-27 07:54:42 +03:00
{
SLtt_Char_Type fgbg;
SLtt_Char_Type mono;
}
Brush_Info_Type;
static Brush_Info_Type Brush_Table[JMAX_COLORS];
1998-02-27 07:54:42 +03:00
/* 0 if least significant bit is blue, not red */
static int Is_Fg_BGR = 0;
static int Is_Bg_BGR = 0;
#define COLOR_ARG(color, is_bgr) ((is_bgr) ? RGB_to_BGR[(color)&0x7] : (color))
static SLCONST int RGB_to_BGR[] =
{
0, 4, 2, 6, 1, 5, 3, 7
};
static char *Color_Fg_Str = "\033[3%dm";
static char *Color_Bg_Str = "\033[4%dm";
static char *Default_Color_Fg_Str = "\033[39m";
static char *Default_Color_Bg_Str = "\033[49m";
1998-02-27 07:54:42 +03:00
static int Max_Terminfo_Colors = 8; /* termcap Co */
1998-02-27 07:54:42 +03:00
char *SLtt_Graphics_Char_Pairs; /* ac termcap string -- def is vt100 */
/* 1 if terminal lacks the ability to go into insert mode or into delete
1998-02-27 07:54:42 +03:00
mode. Currently controlled by S-Lang but later perhaps termcap. */
static char *UnderLine_Vid_Str;
static char *Blink_Vid_Str;
static char *Bold_Vid_Str;
static char *Ins_Mode_Str; /* = "\033[4h"; */ /* ins mode (im) */
static char *Eins_Mode_Str; /* = "\033[4l"; */ /* end ins mode (ei) */
static char *Scroll_R_Str; /* = "\033[%d;%dr"; */ /* scroll region */
static char *Cls_Str; /* = "\033[2J\033[H"; */ /* cl termcap STR for ansi terminals */
static char *Rev_Vid_Str; /* = "\033[7m"; */ /* mr,so termcap string */
static char *Norm_Vid_Str; /* = "\033[m"; */ /* me,se termcap string */
static char *Del_Eol_Str; /* = "\033[K"; */ /* ce */
static char *Del_Bol_Str; /* = "\033[1K"; */ /* cb */
1998-02-27 07:54:42 +03:00
static char *Del_Char_Str; /* = "\033[P"; */ /* dc */
static char *Del_N_Lines_Str; /* = "\033[%dM"; */ /* DL */
static char *Add_N_Lines_Str; /* = "\033[%dL"; */ /* AL */
static char *Rev_Scroll_Str;
static char *Curs_Up_Str;
static char *Curs_F_Str; /* RI termcap string */
static char *Cursor_Visible_Str; /* ve termcap string */
static char *Cursor_Invisible_Str; /* vi termcap string */
#if 0
static char *Start_Mouse_Rpt_Str; /* Start mouse reporting mode */
static char *End_Mouse_Rpt_Str; /* End mouse reporting mode */
#endif
1998-02-27 07:54:42 +03:00
static char *Start_Alt_Chars_Str; /* as */
static char *End_Alt_Chars_Str; /* ae */
static char *Enable_Alt_Char_Set; /* eA */
static char *Term_Init_Str;
static char *Keypad_Init_Str;
static char *Term_Reset_Str;
static char *Keypad_Reset_Str;
/* status line functions */
static char *Disable_Status_line_Str; /* ds */
static char *Return_From_Status_Line_Str; /* fs */
static char *Goto_Status_Line_Str; /* ts */
static int Num_Status_Line_Columns; /* ws */
/* static int Status_Line_Esc_Ok; */ /* es */
1998-02-27 07:54:42 +03:00
/* static int Len_Curs_F_Str = 5; */
/* cm string has %i%d since termcap numbers columns from 0 */
/* char *CURS_POS_STR = "\033[%d;%df"; ansi-- hor and vert pos */
static char *Curs_Pos_Str; /* = "\033[%i%d;%dH";*/ /* cm termcap string */
/* scrolling region */
static int Scroll_r1 = 0, Scroll_r2 = 23;
static int Cursor_r, Cursor_c; /* 0 based */
/* current attributes --- initialized to impossible value */
static SLtt_Char_Type Current_Fgbg = 0xFFFFFFFFU;
static int Cursor_Set; /* 1 if cursor position known, 0
* if not. -1 if only row is known
*/
#define MAX_OUTPUT_BUFFER_SIZE 4096
static unsigned char Output_Buffer[MAX_OUTPUT_BUFFER_SIZE];
static unsigned char *Output_Bufferp = Output_Buffer;
unsigned long SLtt_Num_Chars_Output;
int _pSLusleep (unsigned long usecs)
1998-02-27 07:54:42 +03:00
{
#if !defined(VMS) || (__VMS_VER >= 70000000)
1998-02-27 07:54:42 +03:00
struct timeval tv;
tv.tv_sec = usecs / 1000000;
tv.tv_usec = usecs % 1000000;
return select(0, NULL, NULL, NULL, &tv);
#else
return 0;
#endif
}
int SLtt_flush_output (void)
{
int nwrite = 0;
unsigned int total;
int n = (int) (Output_Bufferp - Output_Buffer);
1998-02-27 07:54:42 +03:00
SLtt_Num_Chars_Output += n;
1998-02-27 07:54:42 +03:00
total = 0;
while (n > 0)
{
nwrite = write (SLang_TT_Write_FD, (char *) Output_Buffer + total, n);
1998-02-27 07:54:42 +03:00
if (nwrite == -1)
{
nwrite = 0;
#ifdef EAGAIN
if (errno == EAGAIN)
1998-02-27 07:54:42 +03:00
{
_pSLusleep (100000); /* 1/10 sec */
1998-02-27 07:54:42 +03:00
continue;
}
#endif
#ifdef EWOULDBLOCK
if (errno == EWOULDBLOCK)
{
_pSLusleep (100000);
1998-02-27 07:54:42 +03:00
continue;
}
#endif
#ifdef EINTR
if (errno == EINTR) continue;
#endif
break;
}
n -= nwrite;
total += nwrite;
}
Output_Bufferp = Output_Buffer;
return n;
}
int SLtt_Baud_Rate;
static void tt_write(char *str, unsigned int n)
{
static unsigned long last_time;
static int total;
unsigned long now;
unsigned int ndiff;
1998-02-27 07:54:42 +03:00
if ((str == NULL) || (n == 0)) return;
total += n;
1998-02-27 07:54:42 +03:00
while (1)
{
ndiff = MAX_OUTPUT_BUFFER_SIZE - (int) (Output_Bufferp - Output_Buffer);
if (ndiff < n)
{
SLMEMCPY ((char *) Output_Bufferp, str, ndiff);
1998-02-27 07:54:42 +03:00
Output_Bufferp += ndiff;
SLtt_flush_output ();
n -= ndiff;
str += ndiff;
}
else
1998-02-27 07:54:42 +03:00
{
SLMEMCPY ((char *) Output_Bufferp, str, n);
Output_Bufferp += n;
break;
}
}
1998-02-27 07:54:42 +03:00
if (((SLtt_Baud_Rate > 150) && (SLtt_Baud_Rate <= 9600))
&& (10 * total > SLtt_Baud_Rate))
{
total = 0;
if ((now = (unsigned long) time(NULL)) - last_time <= 1)
{
SLtt_flush_output ();
sleep((unsigned) 1);
}
last_time = now;
}
}
static void tt_write_string (char *str)
1998-02-27 07:54:42 +03:00
{
if (str != NULL) tt_write(str, strlen(str));
}
void SLtt_write_string (char *str)
{
tt_write_string (str);
Cursor_Set = 0;
}
1998-02-27 07:54:42 +03:00
void SLtt_putchar (char ch)
{
SLtt_normal_video ();
if (Cursor_Set == 1)
{
if (ch >= ' ') Cursor_c++;
else if (ch == '\b') Cursor_c--;
else if (ch == '\r') Cursor_c = 0;
else Cursor_Set = 0;
if ((Cursor_c + 1 == SLtt_Screen_Cols)
1998-02-27 07:54:42 +03:00
&& Automatic_Margins) Cursor_Set = 0;
}
1998-02-27 07:54:42 +03:00
if (Output_Bufferp < Output_Buffer + MAX_OUTPUT_BUFFER_SIZE)
{
*Output_Bufferp++ = (unsigned char) ch;
}
else tt_write (&ch, 1);
}
static unsigned int tt_sprintf(char *buf, unsigned int buflen, char *fmt, int x, int y)
1998-02-27 07:54:42 +03:00
{
char *fmt_max;
unsigned char *b, *bmax, ch;
int offset;
int z, z1, parse_level;
int zero_pad;
int field_width;
int variables [26];
int stack [64];
unsigned int stack_len;
int parms [10];
#define STACK_POP (stack_len ? stack[--stack_len] : 0)
if (fmt == NULL)
{
*buf = 0;
return 0;
}
stack [0] = y; /* pushed for termcap */
stack [1] = x;
stack_len = 2;
parms [1] = x; /* p1 */
parms [2] = y; /* p2 */
offset = 0;
zero_pad = 0;
field_width = 0;
1998-02-27 07:54:42 +03:00
b = (unsigned char *) buf;
bmax = b + buflen;
fmt_max = fmt + strlen (fmt);
while ((fmt < fmt_max) && (b < bmax))
1998-02-27 07:54:42 +03:00
{
ch = *fmt++;
if (ch != '%')
{
*b++ = ch;
continue;
}
if (fmt == fmt_max) break;
ch = *fmt++;
switch (ch)
1998-02-27 07:54:42 +03:00
{
default:
*b++ = ch;
break;
case 'p':
if (fmt == fmt_max) break;
ch = *fmt++;
if ((ch >= '0') && (ch <= '9'))
stack [stack_len++] = parms [ch - '0'];
break;
case '\'': /* 'x' */
if (fmt == fmt_max) break;
stack [stack_len++] = *fmt++;
if (fmt < fmt_max) fmt++; /* skip ' */
break;
case '{': /* literal constant, e.g. {30} */
z = 0;
while ((fmt < fmt_max) && ((ch = *fmt) <= '9') && (ch >= '0'))
1998-02-27 07:54:42 +03:00
{
z = z * 10 + (ch - '0');
fmt++;
1998-02-27 07:54:42 +03:00
}
stack [stack_len++] = z;
if ((ch == '}') && (fmt < fmt_max)) fmt++;
break;
case '0':
if (fmt == fmt_max) break;
ch = *fmt;
if ((ch != '2') && (ch != '3'))
break;
zero_pad = 1;
fmt++;
/* drop */
case '2':
case '3':
if (fmt == fmt_max) break;
if (*fmt == 'x')
1998-02-27 07:54:42 +03:00
{
char x_fmt_buf [4];
char *x_fmt_buf_ptr;
x_fmt_buf_ptr = x_fmt_buf;
if (zero_pad) *x_fmt_buf_ptr++ = '0';
*x_fmt_buf_ptr++ = ch;
*x_fmt_buf_ptr++ = 'X';
*x_fmt_buf_ptr = 0;
z = STACK_POP;
1998-02-27 07:54:42 +03:00
z += offset;
sprintf ((char *)b, x_fmt_buf, z);
b += strlen ((char *)b);
zero_pad = 0;
1998-02-27 07:54:42 +03:00
break;
}
field_width = (ch - '0');
/* drop */
case 'd':
z = STACK_POP;
z += offset;
if (z >= 100)
{
*b++ = z / 100 + '0';
z = z % 100;
zero_pad = 1;
field_width = 2;
}
else if (zero_pad && (field_width == 3))
*b++ = '0';
if (b == bmax) break;
if (z >= 10)
{
*b++ = z / 10 + '0';
z = z % 10;
}
else if (zero_pad && (field_width >= 2))
*b++ = '0';
if (b == bmax) break;
*b++ = z + '0';
field_width = zero_pad = 0;
break;
case 'x':
z = STACK_POP;
z += offset;
if (b + 16 >= bmax)
break;
sprintf ((char *) b, "%X", z);
b += strlen ((char *)b);
break;
case 'i':
offset = 1;
break;
case '+':
/* Handling this depends upon whether or not we are parsing
* terminfo. Terminfo requires the stack so use it as an
* indicator.
*/
if (stack_len > 2)
{
z = STACK_POP;
stack [stack_len - 1] += z;
}
else if (fmt < fmt_max)
{
ch = *fmt++;
if ((unsigned char) ch == 128) ch = 0;
ch = ch + (unsigned char) STACK_POP;
if (ch == '\n') ch++;
*b++ = ch;
}
break;
/* Binary operators */
case '-':
case '*':
case '/':
case 'm':
case '&':
case '|':
case '^':
case '=':
case '>':
case '<':
case 'A':
case 'O':
z1 = STACK_POP;
z = STACK_POP;
switch (ch)
{
case '-': z = (z - z1); break;
case '*': z = (z * z1); break;
case '/': z = (z / z1); break;
case 'm': z = (z % z1); break;
case '&': z = (z & z1); break;
case '|': z = (z | z1); break;
case '^': z = (z ^ z1); break;
case '=': z = (z == z1); break;
case '>': z = (z > z1); break;
case '<': z = (z < z1); break;
case 'A': z = (z && z1); break;
case 'O': z = (z || z1); break;
}
stack [stack_len++] = z;
break;
/* unary */
case '!':
z = STACK_POP;
stack [stack_len++] = !z;
break;
case '~':
z = STACK_POP;
stack [stack_len++] = ~z;
break;
case 'r': /* termcap -- swap parameters */
z = stack [0];
stack [0] = stack [1];
stack [1] = z;
break;
case '.': /* termcap */
case 'c':
ch = (unsigned char) STACK_POP;
if (ch == '\n') ch++;
*b++ = ch;
break;
case 'g':
if (fmt == fmt_max) break;
ch = *fmt++;
if ((ch >= 'a') && (ch <= 'z'))
stack [stack_len++] = variables [ch - 'a'];
break;
case 'P':
if (fmt == fmt_max) break;
ch = *fmt++;
if ((ch >= 'a') && (ch <= 'z'))
variables [ch - 'a'] = STACK_POP;
break;
/* If then else parsing. Actually, this is rather easy. The
* key is to notice that 'then' does all the work. 'if' simply
* there to indicate the start of a test and endif indicates
* the end of tests. If 'else' is seen, then skip to
* endif.
*/
case '?': /* if */
case ';': /* endif */
break;
case 't': /* then */
z = STACK_POP;
if (z != 0)
break; /* good. Continue parsing. */
/* z == 0 and test has failed. So, skip past this entire if
* expression to the matching else or matching endif.
*/
/* drop */
case 'e': /* else */
parse_level = 0;
while (fmt < fmt_max)
{
unsigned char ch1;
ch1 = *fmt++;
if ((ch1 != '%') || (fmt == fmt_max))
continue;
ch1 = *fmt++;
if (ch1 == '?') parse_level++; /* new if */
else if (ch1 == 'e')
1998-02-27 07:54:42 +03:00
{
if ((ch != 'e') && (parse_level == 0))
break;
1998-02-27 07:54:42 +03:00
}
else if (ch1 == ';')
1998-02-27 07:54:42 +03:00
{
if (parse_level == 0)
break;
parse_level--;
1998-02-27 07:54:42 +03:00
}
}
break;
1998-02-27 07:54:42 +03:00
}
}
if (b >= bmax)
b = bmax - 1;
1998-02-27 07:54:42 +03:00
*b = 0;
return (unsigned int) (b - (unsigned char *) buf);
1998-02-27 07:54:42 +03:00
}
static void tt_printf(char *fmt, int x, int y)
{
char buf[1024];
1998-02-27 07:54:42 +03:00
unsigned int n;
if (fmt == NULL) return;
n = tt_sprintf(buf, sizeof (buf), fmt, x, y);
1998-02-27 07:54:42 +03:00
tt_write(buf, n);
}
void SLtt_set_scroll_region (int r1, int r2)
{
Scroll_r1 = r1;
Scroll_r2 = r2;
tt_printf (Scroll_R_Str, Scroll_r1, Scroll_r2);
Cursor_Set = 0;
}
void SLtt_reset_scroll_region (void)
{
SLtt_set_scroll_region(0, SLtt_Screen_Rows - 1);
1998-02-27 07:54:42 +03:00
}
int SLtt_set_cursor_visibility (int show)
{
if ((Cursor_Visible_Str == NULL) || (Cursor_Invisible_Str == NULL))
return -1;
tt_write_string (show ? Cursor_Visible_Str : Cursor_Invisible_Str);
1998-02-27 07:54:42 +03:00
return 0;
}
/* the goto_rc function moves to row relative to scrolling region */
void SLtt_goto_rc(int r, int c)
{
char *s = NULL;
int n;
char buf[6];
if ((c < 0) || (r < 0))
1998-02-27 07:54:42 +03:00
{
Cursor_Set = 0;
return;
1998-02-27 07:54:42 +03:00
}
1998-02-27 07:54:42 +03:00
/* if (No_Move_In_Standout && Current_Fgbg) SLtt_normal_video (); */
r += Scroll_r1;
1998-02-27 07:54:42 +03:00
if ((Cursor_Set > 0) || ((Cursor_Set < 0) && !Automatic_Margins))
{
n = r - Cursor_r;
if ((n == -1) && (Cursor_Set > 0) && (Cursor_c == c)
1998-02-27 07:54:42 +03:00
&& (Curs_Up_Str != NULL))
{
s = Curs_Up_Str;
}
else if ((n >= 0) && (n <= 4))
{
if ((n == 0) && (Cursor_Set == 1)
1998-02-27 07:54:42 +03:00
&& ((c > 1) || (c == Cursor_c)))
{
if (Cursor_c == c) return;
if (Cursor_c == c + 1)
1998-02-27 07:54:42 +03:00
{
/* cursor movement optimizations, like backspace
doesn't work as needed on qansi-m consoles when
current table is not a G0, so we'll disable it. */
if (!QANSI_Console)
{
s = buf;
*s++ = '\b'; *s = 0;
s = buf;
}
else
{
/* do the generic cursor positioning,
without an optimization */
s = NULL;
}
1998-02-27 07:54:42 +03:00
}
}
else if ((c == 0) && (!QANSI_Console)) /* the same things
for the qansi-m console limitation */
1998-02-27 07:54:42 +03:00
{
s = buf;
if ((Cursor_Set != 1) || (Cursor_c != 0)) *s++ = '\r';
while (n--) *s++ = '\n';
#ifdef VMS
/* Need to add this after \n to start a new record. Sheesh. */
*s++ = '\r';
#endif
*s = 0;
s = buf;
}
/* Will fail on VMS */
#ifndef VMS
else if ((SLtt_Newline_Ok && (Cursor_Set == 1) &&
(Cursor_c >= c) && (c + 3 > Cursor_c)) &&
(!QANSI_Console))
1998-02-27 07:54:42 +03:00
{
s = buf;
while (n--) *s++ = '\n';
n = Cursor_c - c;
while (n--) *s++ = '\b';
*s = 0;
s = buf;
}
#endif
}
}
if (s != NULL) tt_write_string(s);
1998-02-27 07:54:42 +03:00
else tt_printf(Curs_Pos_Str, r, c);
Cursor_c = c; Cursor_r = r;
Cursor_Set = 1;
}
void SLtt_begin_insert (void)
{
tt_write_string(Ins_Mode_Str);
1998-02-27 07:54:42 +03:00
}
void SLtt_end_insert (void)
{
tt_write_string(Eins_Mode_Str);
1998-02-27 07:54:42 +03:00
}
void SLtt_delete_char (void)
{
SLtt_normal_video ();
tt_write_string(Del_Char_Str);
1998-02-27 07:54:42 +03:00
}
void SLtt_erase_line (void)
{
tt_write ("\r", 1);
1998-02-27 07:54:42 +03:00
Cursor_Set = 1; Cursor_c = 0;
SLtt_del_eol();
/* Put the cursor back at the beginning of the line */
tt_write ("\r", 1);
Cursor_Set = 1; Cursor_c = 0;
1998-02-27 07:54:42 +03:00
}
/* It appears that the Linux console, and most likely others do not
* like scrolling regions that consist of one line. So I have to
* resort to this stupidity to make up for that stupidity.
*/
static void delete_line_in_scroll_region (void)
{
SLtt_goto_rc (Cursor_r - Scroll_r1, 0);
SLtt_del_eol ();
}
void SLtt_delete_nlines (int nn)
1998-02-27 07:54:42 +03:00
{
int r1, curs;
unsigned int n;
if (nn <= 0) return;
n = (unsigned int) nn;
1998-02-27 07:54:42 +03:00
SLtt_normal_video ();
if (Scroll_r1 == Scroll_r2)
{
delete_line_in_scroll_region ();
return;
}
if (Del_N_Lines_Str != NULL) tt_printf(Del_N_Lines_Str, n, 0);
1998-02-27 07:54:42 +03:00
else
/* get a new terminal */
{
char buf[80];
unsigned int dn = n;
if (dn > sizeof (buf))
dn = sizeof (buf);
SLMEMSET (buf, '\n', dn);
while (n > dn)
{
tt_write (buf, dn);
n -= dn;
}
tt_write (buf, n);
1998-02-27 07:54:42 +03:00
r1 = Scroll_r1;
curs = Cursor_r;
SLtt_set_scroll_region(curs, Scroll_r2);
SLtt_goto_rc(Scroll_r2 - Scroll_r1, 0);
SLMEMSET(buf, '\n', (unsigned int) n);
tt_write(buf, (unsigned int) n);
1998-02-27 07:54:42 +03:00
/* while (n--) tt_putchar('\n'); */
SLtt_set_scroll_region(r1, Scroll_r2);
SLtt_goto_rc(curs, 0);
}
}
void SLtt_cls (void)
{
/* If the terminal is a color terminal but the user wants black and
* white, then make sure that the colors are reset. This appears to be
* necessary.
*/
if ((SLtt_Use_Ansi_Colors == 0) && Is_Color_Terminal)
{
if (Reset_Color_String != NULL)
tt_write_string (Reset_Color_String);
else
tt_write ("\033[0m\033[m", 7);
}
1998-02-27 07:54:42 +03:00
SLtt_normal_video();
SLtt_reset_scroll_region ();
tt_write_string(Cls_Str);
1998-02-27 07:54:42 +03:00
}
void SLtt_reverse_index (int n)
{
if (!n) return;
1998-02-27 07:54:42 +03:00
SLtt_normal_video();
if (Scroll_r1 == Scroll_r2)
{
delete_line_in_scroll_region ();
return;
}
1998-02-27 07:54:42 +03:00
if (Add_N_Lines_Str != NULL) tt_printf(Add_N_Lines_Str,n, 0);
else
{
while(n--) tt_write_string(Rev_Scroll_Str);
1998-02-27 07:54:42 +03:00
}
}
int SLtt_Ignore_Beep = 1;
static char *Visible_Bell_Str;
void SLtt_beep (void)
{
if (SLtt_Ignore_Beep & 0x1) SLtt_putchar('\007');
1998-02-27 07:54:42 +03:00
if (SLtt_Ignore_Beep & 0x2)
{
if (Visible_Bell_Str != NULL) tt_write_string (Visible_Bell_Str);
1998-02-27 07:54:42 +03:00
#ifdef __linux__
else if (Linux_Console)
{
tt_write ("\033[?5h", 5);
1998-02-27 07:54:42 +03:00
SLtt_flush_output ();
_pSLusleep (50000);
tt_write ("\033[?5l", 5);
1998-02-27 07:54:42 +03:00
}
#endif
}
SLtt_flush_output ();
}
static void write_string_with_care (char *);
static void del_eol (void)
{
#if 0
int c;
#endif
if ((Del_Eol_Str != NULL)
&& (Can_Background_Color_Erase || ((Current_Fgbg & ~0xFF) == 0)))
{
tt_write_string(Del_Eol_Str);
return;
}
#if 0
c = Cursor_c;
/* Avoid writing to the lower right corner. If the terminal does not
* have Del_Eol_Str, then it probably does not have what it takes to play
* games with insert-mode to "push" the desired character into that corner.
*/
if (Cursor_r + 1 < SLtt_Screen_Rows)
c++;
while (c < SLtt_Screen_Cols)
{
tt_write (" ", 1);
c++;
}
Cursor_c = (SLtt_Screen_Cols-1);
#else
while (Cursor_c < SLtt_Screen_Cols)
{
write_string_with_care (" ");
Cursor_c++;
}
Cursor_c = SLtt_Screen_Cols - 1;
Cursor_Set = 0;
#endif
}
1998-02-27 07:54:42 +03:00
void SLtt_del_eol (void)
{
if (Current_Fgbg != 0xFFFFFFFFU) SLtt_normal_video ();
del_eol ();
1998-02-27 07:54:42 +03:00
}
typedef SLCONST struct
1998-02-27 07:54:42 +03:00
{
char *name;
SLtt_Char_Type color;
}
Color_Def_Type;
#define MAX_COLOR_NAMES 17
static Color_Def_Type Color_Defs [MAX_COLOR_NAMES] =
{
{"black", SLSMG_COLOR_BLACK},
{"red", SLSMG_COLOR_RED},
{"green", SLSMG_COLOR_GREEN},
{"brown", SLSMG_COLOR_BROWN},
{"blue", SLSMG_COLOR_BLUE},
{"magenta", SLSMG_COLOR_MAGENTA},
{"cyan", SLSMG_COLOR_CYAN},
{"lightgray", SLSMG_COLOR_LGRAY},
{"gray", SLSMG_COLOR_GRAY},
{"brightred", SLSMG_COLOR_BRIGHT_RED},
{"brightgreen", SLSMG_COLOR_BRIGHT_GREEN},
{"yellow", SLSMG_COLOR_BRIGHT_BROWN},
{"brightblue", SLSMG_COLOR_BRIGHT_BLUE},
{"brightmagenta", SLSMG_COLOR_BRIGHT_CYAN},
{"brightcyan", SLSMG_COLOR_BRIGHT_MAGENTA},
{"white", SLSMG_COLOR_BRIGHT_WHITE},
#define SLSMG_COLOR_DEFAULT 0xFF
{"default", SLSMG_COLOR_DEFAULT}
1998-02-27 07:54:42 +03:00
};
static int Brushes_Initialized = 0;
static int initialize_brushes (void)
1998-02-27 07:54:42 +03:00
{
int fg, bg;
Brush_Info_Type *b, *bmax;
b = Brush_Table;
bmax = b + JMAX_COLORS;
bg = 0;
while (b < bmax)
1998-02-27 07:54:42 +03:00
{
fg = 7;
while (b < bmax)
{
if (fg != bg)
{
b->fgbg = MAKE_COLOR(fg,bg);
b->mono = SLTT_REV_MASK;
b++;
}
if (fg == 0)
break;
fg--;
}
bg++;
if (bg == 8)
bg = 0;
}
Brush_Table[0].mono = 0;
Brushes_Initialized = 1;
return 0;
}
static Brush_Info_Type *get_brush_info (unsigned int color)
{
if (Brushes_Initialized == 0)
initialize_brushes ();
color &= SLSMG_COLOR_MASK;
if (color >= JMAX_COLORS)
color = 0;
return Brush_Table + color;
}
static SLtt_Char_Type get_brush_attr (unsigned int color)
{
Brush_Info_Type *b;
if (NULL == (b = get_brush_info (color)))
return (SLtt_Char_Type)-1;
if (SLtt_Use_Ansi_Colors)
return b->fgbg;
return b->mono;
}
static SLtt_Char_Type get_brush_fgbg (unsigned int color)
{
return get_brush_info(color)->fgbg;
}
int SLtt_set_mono (int obj, char *what, SLtt_Char_Type mask)
{
Brush_Info_Type *b;
(void) what;
if (NULL == (b = get_brush_info (obj)))
return -1;
b->mono = mask & ATTR_MASK;
return 0;
1998-02-27 07:54:42 +03:00
}
static char *check_color_for_digit_form (char *color)
{
unsigned int i, ich;
unsigned char *s = (unsigned char *) color;
1998-02-27 07:54:42 +03:00
i = 0;
while ((ich = (unsigned int) *s) != 0)
1998-02-27 07:54:42 +03:00
{
if ((ich < '0') || (ich > '9'))
return color;
1998-02-27 07:54:42 +03:00
i = i * 10 + (ich - '0');
s++;
}
1998-02-27 07:54:42 +03:00
if (i < MAX_COLOR_NAMES)
color = Color_Defs[i].name;
1998-02-27 07:54:42 +03:00
return color;
}
static int get_default_colors (char **fgp, char **bgp)
{
static char fg_buf[16], bg_buf[16], *bg, *fg;
static int already_parsed;
char *p, *pmax;
1998-02-27 07:54:42 +03:00
if (already_parsed == -1)
return -1;
if (already_parsed)
{
*fgp = fg;
*bgp = bg;
return 0;
}
1998-02-27 07:54:42 +03:00
already_parsed = -1;
1998-02-27 07:54:42 +03:00
bg = getenv ("COLORFGBG");
if (bg == NULL)
{
bg = getenv ("DEFAULT_COLORS");
if (bg == NULL)
return -1;
}
1998-02-27 07:54:42 +03:00
p = fg_buf;
pmax = p + (sizeof (fg_buf) - 1);
1998-02-27 07:54:42 +03:00
while ((*bg != 0) && (*bg != ';'))
{
if (p < pmax) *p++ = *bg;
bg++;
}
*p = 0;
1998-02-27 07:54:42 +03:00
if (*bg) bg++;
1998-02-27 07:54:42 +03:00
p = bg_buf;
pmax = p + (sizeof (bg_buf) - 1);
/* Mark suggested allowing for extra application specific stuff following
1998-02-27 07:54:42 +03:00
* the background color. That is what the check for the semi-colon is for.
*/
while ((*bg != 0) && (*bg != ';'))
{
if (p < pmax) *p++ = *bg;
bg++;
}
*p = 0;
if (!strcmp (fg_buf, "default") || !strcmp(bg_buf, "default"))
{
*fgp = *bgp = fg = bg = "default";
}
else
{
*fgp = fg = check_color_for_digit_form (fg_buf);
*bgp = bg = check_color_for_digit_form (bg_buf);
}
already_parsed = 1;
return 0;
}
static int Color_0_Modified = 0;
int SLtt_set_color_object (int obj, SLtt_Char_Type attr)
1998-02-27 07:54:42 +03:00
{
Brush_Info_Type *b;
if (NULL == (b = get_brush_info (obj)))
return -1;
b->fgbg = attr;
1998-02-27 07:54:42 +03:00
if (obj == 0) Color_0_Modified = 1;
if (_pSLtt_color_changed_hook != NULL)
(*_pSLtt_color_changed_hook)();
return 0;
1998-02-27 07:54:42 +03:00
}
SLtt_Char_Type SLtt_get_color_object (int obj)
{
return get_brush_fgbg (obj);
1998-02-27 07:54:42 +03:00
}
int SLtt_add_color_attribute (int obj, SLtt_Char_Type attr)
1998-02-27 07:54:42 +03:00
{
Brush_Info_Type *b;
if (NULL == (b = get_brush_info (obj)))
return -1;
b->fgbg |= (attr & ATTR_MASK);
1998-02-27 07:54:42 +03:00
if (obj == 0) Color_0_Modified = 1;
if (_pSLtt_color_changed_hook != NULL)
(*_pSLtt_color_changed_hook)();
return 0;
1998-02-27 07:54:42 +03:00
}
static SLtt_Char_Type fb_to_fgbg (SLtt_Char_Type f, SLtt_Char_Type b)
{
SLtt_Char_Type attr;
1998-02-27 07:54:42 +03:00
if (Max_Terminfo_Colors != 8)
{
if (f != SLSMG_COLOR_DEFAULT) f %= Max_Terminfo_Colors;
if (b != SLSMG_COLOR_DEFAULT) b %= Max_Terminfo_Colors;
return ((f << 8) | (b << 16));
}
/* Otherwise we have 8 ansi colors. Try to get bright versions
* by using the BOLD and BLINK attributes.
*/
attr = 0;
/* Note: If f represents default, it will have the value 0xFF */
if (f != SLSMG_COLOR_DEFAULT)
1998-02-27 07:54:42 +03:00
{
if (f & 0x8) attr = SLTT_BOLD_MASK;
f &= 0x7;
}
if (b != SLSMG_COLOR_DEFAULT)
1998-02-27 07:54:42 +03:00
{
if (b & 0x8) attr |= SLTT_BLINK_MASK;
b &= 0x7;
}
1998-02-27 07:54:42 +03:00
return ((f << 8) | (b << 16) | attr);
}
/* This looks for colors with name form 'colorN'. If color is of this
* form, N is passed back via parameter list.
*/
static int parse_color_digit_name (char *color, SLtt_Char_Type *f)
{
unsigned int i;
unsigned char ch;
if (strncmp (color, "color", 5))
return -1;
color += 5;
if (*color == 0)
return -1;
i = 0;
while (1)
{
unsigned int j;
ch = (unsigned char) *color++;
if (ch == 0)
break;
if ((ch > '9') || (ch < '0'))
return -1;
if (i > 0xFFFFFFFFU / 10)
return -1;
j = (i *= 10);
i += (ch - '0');
if (i < j)
return -1;
}
*f = (SLtt_Char_Type) i;
return 0;
}
1998-02-27 07:54:42 +03:00
static int make_color_fgbg (char *fg, char *bg, SLtt_Char_Type *fgbg)
{
SLtt_Char_Type f = 0xFFFFFFFFU, b = 0xFFFFFFFFU;
char *dfg, *dbg;
unsigned int i;
1998-02-27 07:54:42 +03:00
if ((fg != NULL) && (*fg == 0)) fg = NULL;
if ((bg != NULL) && (*bg == 0)) bg = NULL;
1998-02-27 07:54:42 +03:00
if ((fg == NULL) || (bg == NULL))
{
if (-1 == get_default_colors (&dfg, &dbg))
return -1;
1998-02-27 07:54:42 +03:00
if (fg == NULL) fg = dfg;
if (bg == NULL) bg = dbg;
}
if (-1 == parse_color_digit_name (fg, &f))
1998-02-27 07:54:42 +03:00
{
for (i = 0; i < MAX_COLOR_NAMES; i++)
{
if (strcmp(fg, Color_Defs[i].name)) continue;
f = Color_Defs[i].color;
break;
}
1998-02-27 07:54:42 +03:00
}
if (-1 == parse_color_digit_name (bg, &b))
1998-02-27 07:54:42 +03:00
{
for (i = 0; i < MAX_COLOR_NAMES; i++)
{
if (strcmp(bg, Color_Defs[i].name)) continue;
b = Color_Defs[i].color;
break;
}
1998-02-27 07:54:42 +03:00
}
1998-02-27 07:54:42 +03:00
if ((f == 0xFFFFFFFFU) || (b == 0xFFFFFFFFU))
return -1;
1998-02-27 07:54:42 +03:00
*fgbg = fb_to_fgbg (f, b);
return 0;
}
int SLtt_set_color (int obj, char *what, char *fg, char *bg)
1998-02-27 07:54:42 +03:00
{
SLtt_Char_Type fgbg;
(void) what;
if (-1 == make_color_fgbg (fg, bg, &fgbg))
return -1;
1998-02-27 07:54:42 +03:00
return SLtt_set_color_object (obj, fgbg);
1998-02-27 07:54:42 +03:00
}
int SLtt_set_color_fgbg (int obj, SLtt_Char_Type f, SLtt_Char_Type b)
1998-02-27 07:54:42 +03:00
{
return SLtt_set_color_object (obj, fb_to_fgbg (f, b));
1998-02-27 07:54:42 +03:00
}
void SLtt_set_alt_char_set (int i)
{
static int last_i;
if (SLtt_Has_Alt_Charset == 0) return;
i = (i != 0);
1998-02-27 07:54:42 +03:00
if (i == last_i) return;
tt_write_string (i ? Start_Alt_Chars_Str : End_Alt_Chars_Str );
1998-02-27 07:54:42 +03:00
last_i = i;
}
static void write_attributes (SLtt_Char_Type fgbg)
{
int bg0, fg0;
int unknown_attributes;
1998-02-27 07:54:42 +03:00
if (Worthless_Highlight) return;
if (fgbg == Current_Fgbg) return;
unknown_attributes = 0;
1998-02-27 07:54:42 +03:00
/* Before spitting out colors, fix attributes */
if ((fgbg & ATTR_MASK) != (Current_Fgbg & ATTR_MASK))
{
if (Current_Fgbg & ATTR_MASK)
{
tt_write_string(Norm_Vid_Str);
1998-02-27 07:54:42 +03:00
/* In case normal video turns off ALL attributes: */
if (fgbg & SLTT_ALTC_MASK)
1998-02-27 07:54:42 +03:00
Current_Fgbg &= ~SLTT_ALTC_MASK;
SLtt_set_alt_char_set (0);
}
if ((fgbg & SLTT_ALTC_MASK)
1998-02-27 07:54:42 +03:00
!= (Current_Fgbg & SLTT_ALTC_MASK))
{
SLtt_set_alt_char_set ((int) (fgbg & SLTT_ALTC_MASK));
}
if (fgbg & SLTT_ULINE_MASK) tt_write_string (UnderLine_Vid_Str);
1998-02-27 07:54:42 +03:00
if (fgbg & SLTT_BOLD_MASK) SLtt_bold_video ();
if (fgbg & SLTT_REV_MASK) tt_write_string (Rev_Vid_Str);
1998-02-27 07:54:42 +03:00
if (fgbg & SLTT_BLINK_MASK)
{
/* Someday Linux will have a blink mode that set high intensity
* background. Lets be prepared.
*/
if (SLtt_Blink_Mode) tt_write_string (Blink_Vid_Str);
1998-02-27 07:54:42 +03:00
}
unknown_attributes = 1;
1998-02-27 07:54:42 +03:00
}
1998-02-27 07:54:42 +03:00
if (SLtt_Use_Ansi_Colors)
{
fg0 = (int) GET_FG(fgbg);
bg0 = (int) GET_BG(fgbg);
if (unknown_attributes
|| (fg0 != (int)GET_FG(Current_Fgbg)))
{
if (fg0 == SLSMG_COLOR_DEFAULT)
tt_write_string (Default_Color_Fg_Str);
else
tt_printf (Color_Fg_Str, COLOR_ARG(fg0, Is_Bg_BGR), 0);
}
if (unknown_attributes
|| (bg0 != (int)GET_BG(Current_Fgbg)))
{
if (bg0 == SLSMG_COLOR_DEFAULT)
tt_write_string (Default_Color_Bg_Str);
else
tt_printf (Color_Bg_Str, COLOR_ARG(bg0, Is_Bg_BGR), 0);
}
1998-02-27 07:54:42 +03:00
}
1998-02-27 07:54:42 +03:00
Current_Fgbg = fgbg;
}
static int Video_Initialized;
void SLtt_reverse_video (int color)
{
SLtt_Char_Type fgbg;
1998-02-27 07:54:42 +03:00
if (Worthless_Highlight) return;
1998-02-27 07:54:42 +03:00
if (Video_Initialized == 0)
{
if (color == JNORMAL_COLOR)
{
tt_write_string (Norm_Vid_Str);
1998-02-27 07:54:42 +03:00
}
else tt_write_string (Rev_Vid_Str);
1998-02-27 07:54:42 +03:00
Current_Fgbg = 0xFFFFFFFFU;
return;
}
fgbg = get_brush_attr (color);
1998-02-27 07:54:42 +03:00
if (fgbg == Current_Fgbg) return;
write_attributes (fgbg);
}
void SLtt_normal_video (void)
{
SLtt_reverse_video(JNORMAL_COLOR);
}
void SLtt_narrow_width (void)
{
tt_write ("\033[?3l", 5);
1998-02-27 07:54:42 +03:00
}
void SLtt_wide_width (void)
{
tt_write ("\033[?3h", 5);
1998-02-27 07:54:42 +03:00
}
/* Highest bit represents the character set. */
#define COLOR_OF(a) ((a)->color & SLSMG_COLOR_MASK)
1998-02-27 07:54:42 +03:00
static int bce_color_eqs (SLsmg_Char_Type *a, SLsmg_Char_Type *b)
{
SLsmg_Color_Type ca, cb;
Brush_Info_Type *ba, *bb;
ca = COLOR_OF(a);
cb = COLOR_OF(b);
if (ca == cb)
return 1;
1998-02-27 07:54:42 +03:00
ba = get_brush_info (ca);
bb = get_brush_info (cb);
if (SLtt_Use_Ansi_Colors == 0)
return ba->mono == bb->mono;
if (Bce_Color_Offset == 0)
return ba->fgbg == bb->fgbg;
/* If either are color 0, then we do not know what that means since the
* terminal does not support BCE */
if ((ca == 0) || (cb == 0))
return 0;
return get_brush_fgbg (ca-1) == get_brush_fgbg(cb-1);
}
1998-02-27 07:54:42 +03:00
/* The whole point of this routine is to prevent writing to the last column
* and last row on terminals with automatic margins.
*/
static void write_string_with_care (char *str)
{
unsigned int len;
1998-02-27 07:54:42 +03:00
if (str == NULL) return;
1998-02-27 07:54:42 +03:00
len = strlen (str);
if (Automatic_Margins && (Cursor_r + 1 == SLtt_Screen_Rows))
{
if (len + (unsigned int) Cursor_c >= (unsigned int) SLtt_Screen_Cols)
{
/* For now, just do not write there. Later, something more
* sophisticated will be implemented.
*/
if (SLtt_Screen_Cols > Cursor_c)
len = SLtt_Screen_Cols - Cursor_c - 1;
else
len = 0;
1998-02-27 07:54:42 +03:00
}
}
tt_write (str, len);
}
static void send_attr_str (SLsmg_Char_Type *s, SLsmg_Char_Type *smax)
1998-02-27 07:54:42 +03:00
{
unsigned char out[1+SLUTF8_MAX_MBLEN*SLSMG_MAX_CHARS_PER_CELL*SLTT_MAX_SCREEN_COLS];
unsigned char *p, *pmax;
1998-02-27 07:54:42 +03:00
register SLtt_Char_Type attr;
SLsmg_Color_Type color, last_color = (SLsmg_Color_Type)-1;
int dcursor_c;
1998-02-27 07:54:42 +03:00
p = out;
pmax = p + (sizeof (out)-1);
dcursor_c = 0;
while (s < smax)
1998-02-27 07:54:42 +03:00
{
SLwchar_Type wch;
unsigned int nchars;
if (0 == (nchars = s->nchars))
{
/* 2nd element of a char that occupies two columns */
s++;
if (_pSLtt_UTF8_Mode == 0)
*p++ = ' ';
dcursor_c++;
continue;
}
color = s->color;
#if SLTT_HAS_NON_BCE_SUPPORT
if (Bce_Color_Offset
&& (color >= Bce_Color_Offset))
color -= Bce_Color_Offset;
#endif
wch = s->wchars[0];
1998-02-27 07:54:42 +03:00
if (color != last_color)
{
attr = get_brush_attr (color);
if (color & SLSMG_ACS_MASK) /* alternate char set */
1998-02-27 07:54:42 +03:00
{
if (SLtt_Use_Blink_For_ACS)
{
if (SLtt_Blink_Mode) attr |= SLTT_BLINK_MASK;
}
else attr |= SLTT_ALTC_MASK;
1998-02-27 07:54:42 +03:00
}
1998-02-27 07:54:42 +03:00
if (attr != Current_Fgbg)
{
if ((wch != ' ')
|| (nchars > 1)
1998-02-27 07:54:42 +03:00
/* it is a space so only consider it different if it
* has different attributes.
*/
|| (attr != Current_Fgbg)
)
1998-02-27 07:54:42 +03:00
{
if (p != out)
{
*p = 0;
write_string_with_care ((char *) out);
p = out;
Cursor_c += dcursor_c;
dcursor_c = 0;
1998-02-27 07:54:42 +03:00
}
write_attributes (attr);
1998-02-27 07:54:42 +03:00
last_color = color;
}
}
}
if ((wch < 0x80) && (nchars == 1))
*p++ = (unsigned char) wch;
else if (_pSLtt_UTF8_Mode == 0)
{
if (wch > 255)
wch = '?';
else if (wch < (SLwchar_Type)SLsmg_Display_Eight_Bit)
wch = '?';
*p++ = (unsigned char) wch;
}
else
{
unsigned int i;
for (i = 0; i < nchars; i++)
{
if (NULL == (p = SLutf8_encode (s->wchars[i], p, pmax-p)))
{
fprintf (stderr, "*** send_attr_str: buffer too small\n");
return;
}
}
}
dcursor_c++;
s++;
1998-02-27 07:54:42 +03:00
}
*p = 0;
if (p != out) write_string_with_care ((char *) out);
Cursor_c += dcursor_c;
1998-02-27 07:54:42 +03:00
}
static void forward_cursor (unsigned int n, int row)
{
char buf [1024];
/* if (Current_Fgbg & ~0xFF) */
/* { */
/* unsigned int num = 0; */
/* while (num < n) */
/* { */
/* write_string_with_care (" "); */
/* num++; */
/* } */
/* Cursor_c += n; */
/* return; */
/* } */
if (n <= 4)
1998-02-27 07:54:42 +03:00
{
SLtt_normal_video ();
#if 0
if (n >= sizeof (buf))
n = sizeof (buf) - 1;
#endif
1998-02-27 07:54:42 +03:00
SLMEMSET (buf, ' ', n);
buf[n] = 0;
write_string_with_care (buf);
Cursor_c += n;
}
else if (Curs_F_Str != NULL)
{
Cursor_c += n;
n = tt_sprintf(buf, sizeof (buf), Curs_F_Str, (int) n, 0);
1998-02-27 07:54:42 +03:00
tt_write(buf, n);
}
else SLtt_goto_rc (row, (int) (Cursor_c + n));
}
/* FIXME!! If the terminal does not support color, then this route has
* problems of color object 0 has been assigned some monochrome attribute
* such as reverse video. In such a case, space_char=' ' is not a simple
* space character as is assumed below.
*/
#define COLOR_EQS(a,b) ((COLOR_OF(a)==COLOR_OF(b)) || bce_color_eqs (a,b))
#define CHARSET(a) ((a)->color&SLSMG_ACS_MASK)
#define CHAR_EQS(a, b) (((a)->nchars==(b)->nchars) \
&& (((a)->nchars == 0) \
|| ((((a)->wchars[0]==(b)->wchars[0]) \
&& (0 == memcmp((a)->wchars, (b)->wchars, (a)->nchars*sizeof(SLwchar_Type)))) \
&& (COLOR_EQS(a,b)) \
&& (CHARSET(a)==CHARSET(b)))))
#define CHAR_EQS_SPACE(a) (((a)->wchars[0]==' ') && ((a)->color==0) && ((a)->nchars==1))
void SLtt_smart_puts(SLsmg_Char_Type *neww, SLsmg_Char_Type *oldd, int len, int row)
1998-02-27 07:54:42 +03:00
{
register SLsmg_Char_Type *p, *q, *qmax, *pmax, *buf;
SLsmg_Char_Type buffer[SLTT_MAX_SCREEN_COLS+1];
1998-02-27 07:54:42 +03:00
unsigned int n_spaces;
SLsmg_Char_Type *space_match, *last_buffered_match;
1998-02-27 07:54:42 +03:00
#ifdef HP_GLITCH_CODE
int handle_hp_glitch = 0;
#endif
SLsmg_Char_Type *space_char;
SLsmg_Char_Type space_char_buf;
#define SLTT_USE_INSERT_HACK 1
#if SLTT_USE_INSERT_HACK
SLsmg_Char_Type *insert_hack_prev = NULL;
SLsmg_Char_Type *insert_hack_char = NULL;
if ((row + 1 == SLtt_Screen_Rows)
&& (len == SLtt_Screen_Cols)
&& (len > 1)
&& (SLtt_Term_Cannot_Insert == 0)
&& Automatic_Margins)
{
SLsmg_Char_Type *a, *b;
insert_hack_char = &neww[len-1];
a = oldd+(len-1);
b = neww+(len-1);
if (CHAR_EQS(a,b))
insert_hack_char = NULL;
else
insert_hack_prev = &neww[len-2];
}
#endif
memset ((char *) &space_char_buf, 0, sizeof (SLsmg_Char_Type));
space_char = &space_char_buf;
space_char->nchars = 1;
space_char->wchars[0] = ' ';
if (len > SLTT_MAX_SCREEN_COLS)
len = SLTT_MAX_SCREEN_COLS;
1998-02-27 07:54:42 +03:00
q = oldd; p = neww;
qmax = oldd + len;
pmax = p + len;
1998-02-27 07:54:42 +03:00
/* Find out where to begin --- while they match, we are ok */
while (1)
{
if (q == qmax) return;
1998-02-27 07:54:42 +03:00
#if SLANG_HAS_KANJI_SUPPORT
if (*p & 0x80)
1998-02-27 07:54:42 +03:00
{ /* new is kanji */
if ((*q & 0x80) && ((q + 1) < qmax))
{ /* old is also kanji */
if (((0xFF & *q) != (0xFF & *p))
|| ((0xFF & q[1]) != (0xFF & p[1])))
break; /* both kanji, but not match */
else
1998-02-27 07:54:42 +03:00
{ /* kanji match ! */
if (!COLOR_EQS(*q, *p)) break;
q++; p++;
if (!COLOR_EQS(*q, *p)) break;
/* really match! */
q++; p++;
continue;
}
}
else break; /* old is not kanji */
}
else
1998-02-27 07:54:42 +03:00
{ /* new is not kanji */
if (*q & 0x80) break; /* old is kanji */
}
#endif
if (!CHAR_EQS(q, p)) break;
1998-02-27 07:54:42 +03:00
q++; p++;
}
#ifdef HP_GLITCH_CODE
if (Has_HP_Glitch)
{
SLsmg_Char_Type *qq = q;
SLtt_goto_rc (row, (int) (p - neww));
1998-02-27 07:54:42 +03:00
while (qq < qmax)
{
if (qq->color)
1998-02-27 07:54:42 +03:00
{
SLtt_normal_video ();
SLtt_del_eol ();
qmax = q;
handle_hp_glitch = 1;
break;
}
qq++;
}
}
#endif
/* Find where the last non-blank character on old/new screen is */
if (CHAR_EQS_SPACE(pmax-1))
1998-02-27 07:54:42 +03:00
{
/* If we get here, then we can erase to the end of the line to create
* the final space. However, this will only work _if_ erasing will
* get us the correct color. If the terminal supports BCE, then this
* is easy. If it does not, then we can only perform this operation
* if the color is known via something like COLORFGBG. For now,
* I just will not perform the optimization for such terminals.
*/
if ((Can_Background_Color_Erase)
&& SLtt_Use_Ansi_Colors)
space_char = pmax - 1;
while (pmax > p)
1998-02-27 07:54:42 +03:00
{
pmax--;
if (!CHAR_EQS(pmax, space_char))
{
pmax++;
break;
}
1998-02-27 07:54:42 +03:00
}
}
while (qmax > q)
1998-02-27 07:54:42 +03:00
{
qmax--;
if (!CHAR_EQS(qmax, space_char))
1998-02-27 07:54:42 +03:00
{
qmax++;
1998-02-27 07:54:42 +03:00
break;
}
}
1998-02-27 07:54:42 +03:00
last_buffered_match = buf = buffer; /* buffer is empty */
#ifdef HP_GLITCH_CODE
if (handle_hp_glitch)
{
while (p < pmax)
{
*buf++ = *p++;
}
}
#endif
#ifdef HP_GLITCH_CODE
if (Has_HP_Glitch == 0)
{
#endif
/* Try use use erase to bol if possible */
if ((Del_Bol_Str != NULL) && (CHAR_EQS_SPACE(neww)))
{
SLsmg_Char_Type *p1;
SLsmg_Color_Type blank_color = 0;
p1 = neww;
if ((Can_Background_Color_Erase)
&& SLtt_Use_Ansi_Colors)
{
SLsmg_Char_Type *blank = p1;
blank_color = COLOR_OF(blank);
while ((p1 < pmax) && (CHAR_EQS (p1, blank)))
p1++;
}
else
{
/* black+white attributes do not support bce */
while ((p1 < pmax) && (CHAR_EQS_SPACE (p1)))
p1++;
}
/* Is this optimization worth it? Assume Del_Bol_Str is ESC [ 1 K
* It costs 4 chars + the space needed to properly position the
* cursor, e.g., ESC [ 10;10H. So, it costs at least 13 characters.
*/
if ((p1 > neww + 13)
&& (p1 >= p)
/* Avoid erasing from the end of the line */
&& ((p1 != pmax) || (pmax < neww + len)))
{
int ofs = (int) (p1 - neww);
q = oldd + ofs;
p = p1;
SLtt_goto_rc (row, ofs - 1);
SLtt_reverse_video (blank_color);
tt_write_string (Del_Bol_Str);
tt_write (" ", 1);
Cursor_c += 1;
}
else
SLtt_goto_rc (row, (int) (p - neww));
}
else
SLtt_goto_rc (row, (int) (p - neww));
#ifdef HP_GLITCH_CODE
}
#endif
1998-02-27 07:54:42 +03:00
/* loop using overwrite then skip algorithm until done */
while (1)
{
/* while they do not match and we do not hit a space, buffer them up */
n_spaces = 0;
while (p < pmax)
{
if (CHAR_EQS_SPACE(q) && CHAR_EQS_SPACE(p))
1998-02-27 07:54:42 +03:00
{
/* If *q is not a space, we would have to overwrite it.
* However, if *q is a space, then while *p is also one,
1998-02-27 07:54:42 +03:00
* we only need to skip over the blank field.
*/
space_match = p;
p++; q++;
while ((p < pmax)
&& CHAR_EQS_SPACE(q)
&& CHAR_EQS_SPACE(p))
1998-02-27 07:54:42 +03:00
{
p++;
q++;
}
n_spaces = (unsigned int) (p - space_match);
break;
}
#if SLANG_HAS_KANJI_SUPPORT
if ((*p & 0x80) && ((p + 1) < pmax))
{ /* new is kanji */
if (*q & 0x80)
1998-02-27 07:54:42 +03:00
{ /* old is also kanji */
if (((0xFF & *q) != (0xFF & *p))
|| ((0xFF & q[1]) != (0xFF & p[1])))
1998-02-27 07:54:42 +03:00
{
/* both kanji, but not match */
*buf++ = *p++;
*buf++ = *p++;
q += 2;
continue;
}
else
1998-02-27 07:54:42 +03:00
{ /* kanji match ? */
if (!COLOR_EQS(*q, *p) || !COLOR_EQS(*(q+1), *(p+1)))
1998-02-27 07:54:42 +03:00
{
/* code is match, but color is diff */
1998-02-27 07:54:42 +03:00
*buf++ = *p++;
*buf++ = *p++;
q += 2;
1998-02-27 07:54:42 +03:00
continue;
}
/* really match ! */
break;
}
}
else
1998-02-27 07:54:42 +03:00
{ /* old is not kanji */
*buf++ = *p++;
*buf++ = *p++;
q += 2;
continue;
}
}
else
1998-02-27 07:54:42 +03:00
{ /* new is not kanji */
if (*q & 0x80)
1998-02-27 07:54:42 +03:00
{ /* old is kanji */
*buf++ = *p++;
q++;
continue;
}
}
#endif
if (CHAR_EQS(q, p))
{
/* Could be the second half of a double width character */
if (p->nchars || q->nchars)
break;
}
1998-02-27 07:54:42 +03:00
*buf++ = *p++;
q++;
}
/* At this point, the buffer contains characters that do not match */
if (buf != buffer) send_attr_str (buffer, buf);
1998-02-27 07:54:42 +03:00
buf = buffer;
if (n_spaces
&& ((p < pmax) /* erase to eol will achieve this effect*/
|| (!CHAR_EQS_SPACE(space_char))))/* unless space_char is not a simple space */
1998-02-27 07:54:42 +03:00
{
forward_cursor (n_spaces, row);
}
/* Now we overwrote what we could and cursor is placed at position
* of a possible match of new and old. If this is the case, skip
1998-02-27 07:54:42 +03:00
* some more.
*/
/* Note that from here on, the buffer will contain matched characters */
#if !SLANG_HAS_KANJI_SUPPORT
while ((p < pmax) && CHAR_EQS(p, q))
1998-02-27 07:54:42 +03:00
{
*buf++ = *p++;
q++;
}
#else
/* Kanji */
while (p < pmax)
1998-02-27 07:54:42 +03:00
{
if ((*p & 0x80) && ((p + 1) < pmax))
{ /* new is kanji */
if (*q & 0x80)
1998-02-27 07:54:42 +03:00
{ /* old is also kanji */
if (((0xFF & *q) == (0xFF & *p))
1998-02-27 07:54:42 +03:00
&& ((0xFF & q[1]) == (0xFF & p[1])))
{
/* kanji match ? */
if (!COLOR_EQS(*q, *p)
1998-02-27 07:54:42 +03:00
|| !COLOR_EQS(q[1], p[1]))
break;
1998-02-27 07:54:42 +03:00
*buf++ = *p++;
q++;
if (p >= pmax)
1998-02-27 07:54:42 +03:00
{
*buf++ = 32;
1998-02-27 07:54:42 +03:00
p++;
break;
}
else
1998-02-27 07:54:42 +03:00
{
*buf++ = *p++;
q++;
continue;
}
}
else break; /* both kanji, but not match */
}
else break; /* old is not kanji */
}
else
1998-02-27 07:54:42 +03:00
{ /* new is not kanji */
if (*q & 0x80) break; /* old is kanji */
if (!CHAR_EQS(*q, *p)) break;
*buf++ = *p++;
q++;
}
}
#endif
last_buffered_match = buf;
if (p >= pmax) break;
1998-02-27 07:54:42 +03:00
/* jump to new position is it is greater than 5 otherwise
* let it sit in the buffer and output it later.
*/
if ((int) (buf - buffer) >= 5)
1998-02-27 07:54:42 +03:00
{
forward_cursor ((unsigned int) (buf - buffer), row);
last_buffered_match = buf = buffer;
}
}
/* At this point we have reached the end of the new string with the
* exception of space_chars hanging off the end of it, but we may not have
* reached the end of the old string if they did not match.
*/
/* Here the buffer will consist only of characters that have matched */
1998-02-27 07:54:42 +03:00
if (buf != buffer)
{
if (q < qmax)
{
if ((buf == last_buffered_match)
1998-02-27 07:54:42 +03:00
&& ((int) (buf - buffer) >= 5))
{
forward_cursor ((unsigned int) (buf - buffer), row);
}
else
{
send_attr_str (buffer, buf);
1998-02-27 07:54:42 +03:00
}
}
}
if (q < qmax)
{
SLtt_reverse_video (COLOR_OF(space_char));
del_eol ();
}
#if SLTT_USE_INSERT_HACK
else if (insert_hack_char != NULL)
{
SLtt_goto_rc (SLtt_Screen_Rows-1, SLtt_Screen_Cols-2);
send_attr_str (insert_hack_char, insert_hack_char+1);
SLtt_goto_rc (SLtt_Screen_Rows-1, SLtt_Screen_Cols-2);
SLtt_begin_insert ();
send_attr_str (insert_hack_prev, insert_hack_prev+1);
SLtt_end_insert ();
}
#endif
if (Automatic_Margins && (Cursor_c + 1 >= SLtt_Screen_Cols)) Cursor_Set = 0;
}
1998-02-27 07:54:42 +03:00
static void get_color_info (void)
{
char *fg, *bg;
/* Allow easy mechanism to override inadequate termcap/terminfo files. */
if (SLtt_Use_Ansi_Colors == 0)
SLtt_Use_Ansi_Colors = (NULL != getenv ("COLORTERM"));
if (SLtt_Use_Ansi_Colors)
Is_Color_Terminal = 1;
#if SLTT_HAS_NON_BCE_SUPPORT
if (Can_Background_Color_Erase == 0)
Can_Background_Color_Erase = (NULL != getenv ("COLORTERM_BCE"));
#endif
1998-02-27 07:54:42 +03:00
if (-1 == get_default_colors (&fg, &bg))
return;
1998-02-27 07:54:42 +03:00
/* Check to see if application has already set them. */
if (Color_0_Modified)
return;
1998-02-27 07:54:42 +03:00
SLtt_set_color (0, NULL, fg, bg);
SLtt_set_color (1, NULL, bg, fg);
}
/* termcap stuff */
#ifdef __unix__
static int Termcap_Initalized = 0;
1998-02-27 07:54:42 +03:00
#ifdef USE_TERMCAP
/* Termcap based system */
static char Termcap_Buf[4096];
static char Termcap_String_Buf[4096];
/* static char *Termcap_String_Ptr; */
1998-02-27 07:54:42 +03:00
extern char *tgetstr(char *, char **);
extern int tgetent(char *, char *);
extern int tgetnum(char *);
extern int tgetflag(char *);
#else
/* Terminfo */
static SLterminfo_Type *Terminfo;
1998-02-27 07:54:42 +03:00
#endif
#define TGETFLAG(x) (SLtt_tgetflag(x) > 0)
static char *fixup_tgetstr (char *what)
1998-02-27 07:54:42 +03:00
{
register char *w, *w1;
char *wsave;
if (what == NULL)
return NULL;
/* Check for AIX brain-damage */
if (*what == '@')
return NULL;
/* lose pad info --- with today's technology, term is a loser if
it is really needed */
while ((*what == '.') ||
((*what >= '0') && (*what <= '9'))) what++;
if (*what == '*') what++;
/* lose terminfo padding--- looks like $<...> */
w = what;
while (*w) if ((*w++ == '$') && (*w == '<'))
{
w1 = w - 1;
while (*w && (*w != '>')) w++;
if (*w == 0) break;
w++;
wsave = w1;
while ((*w1++ = *w++) != 0);
w = wsave;
1998-02-27 07:54:42 +03:00
}
if (*what == 0) what = NULL;
return what;
1998-02-27 07:54:42 +03:00
}
char *SLtt_tgetstr (char *cap)
1998-02-27 07:54:42 +03:00
{
char *s;
#ifdef USE_TERMCAP
char *tmp_area;
#endif
if (Termcap_Initalized == 0)
return NULL;
1998-02-27 07:54:42 +03:00
#ifdef USE_TERMCAP
tmp_area = (char*) &Termcap_String_Buf;
s = tgetstr (cap, &tmp_area);
#else
s = _pSLtt_tigetstr (Terminfo, cap);
1998-02-27 07:54:42 +03:00
#endif
/* Do not strip pad info for alternate character set. I need to make
* this more general.
*/
/* FIXME: Priority=low; */
if (0 == strcmp (cap, "ac"))
return s;
return fixup_tgetstr (s);
1998-02-27 07:54:42 +03:00
}
int SLtt_tgetnum (char *s)
1998-02-27 07:54:42 +03:00
{
if (Termcap_Initalized == 0)
return -1;
#ifdef USE_TERMCAP
return tgetnum (s);
#else
return _pSLtt_tigetnum (Terminfo, s);
#endif
1998-02-27 07:54:42 +03:00
}
int SLtt_tgetflag (char *s)
1998-02-27 07:54:42 +03:00
{
if (Termcap_Initalized == 0)
return -1;
#ifdef USE_TERMCAP
return tgetflag (s);
#else
return _pSLtt_tigetflag (Terminfo, s);
#endif
1998-02-27 07:54:42 +03:00
}
#if 0
int SLtt_tgetent(char *term)
{
return SLtt_initialize(term) == 0;
}
int SLtt_tputs(char *str, int affcnt, int (*p)(int))
{
while (*str) (*p)(*str++);
return 0;
}
char *SLtt_tgoto(char *cap, int col, int row)
{
static char buf[64];
/* beware of overflows. 2^64 is 20 bytes printed */
if (strlen(cap) > 23)
strcpy(buf, "capability too long");
else
tt_sprintf(buf, cap, row, col);
return buf;
}
#endif
1998-02-27 07:54:42 +03:00
static int Vt100_Like = 0;
void SLtt_get_terminfo (void)
{
char *term;
int status;
term = getenv ("TERM");
if (term == NULL)
SLang_exit_error("TERM environment variable needs set.");
if (0 == (status = SLtt_initialize (term)))
return;
if (status == -1)
{
SLang_exit_error ("Unknown terminal: %s\n\
Check the TERM environment variable.\n\
Also make sure that the terminal is defined in the terminfo database.\n\
Alternatively, set the TERMCAP environment variable to the desired\n\
termcap entry.",
term);
}
if (status == -2)
{
SLang_exit_error ("\
Your terminal lacks the ability to clear the screen or position the cursor.\n");
}
}
/* Returns 0 if all goes well, -1 if terminal capabilities cannot be deduced,
* or -2 if terminal cannot position the cursor.
*/
int SLtt_initialize (char *term)
{
char *t, ch;
1998-02-27 07:54:42 +03:00
int is_xterm;
int almost_vtxxx;
if (_pSLtt_UTF8_Mode == -1)
_pSLtt_UTF8_Mode = _pSLutf8_mode;
if (SLang_TT_Write_FD == -1)
1998-02-27 07:54:42 +03:00
{
/* Apparantly, this cannot fail according to the man pages. */
SLang_TT_Write_FD = fileno (stdout);
1998-02-27 07:54:42 +03:00
}
if (term == NULL)
{
term = getenv ("TERM");
if (term == NULL)
return -1;
}
if (_pSLsecure_issetugid ()
&& ((term[0] == '.') || (NULL != strchr(term, '/'))))
return -1;
1998-02-27 07:54:42 +03:00
Linux_Console = (!strncmp (term, "linux", 5)
# ifdef linux
1998-02-27 07:54:42 +03:00
|| !strncmp(term, "con", 3)
# endif
1998-02-27 07:54:42 +03:00
);
QANSI_Console = !strncmp (term, "qansi-m", 7);
1998-02-27 07:54:42 +03:00
t = term;
1998-02-27 07:54:42 +03:00
if (strcmp(t, "vt52") && (*t++ == 'v') && (*t++ == 't')
&& (ch = *t, (ch >= '1') && (ch <= '9'))) Vt100_Like = 1;
is_xterm = ((0 == strncmp (term, "xterm", 5))
|| (0 == strncmp (term, "rxvt", 4))
|| (0 == strncmp (term, "Eterm", 5)));
1998-02-27 07:54:42 +03:00
almost_vtxxx = (Vt100_Like
|| Linux_Console
|| is_xterm
|| !strcmp (term, "screen"));
# ifndef USE_TERMCAP
if (NULL == (Terminfo = _pSLtt_tigetent (term)))
1998-02-27 07:54:42 +03:00
{
if (almost_vtxxx) /* Special cases. */
{
int vt102 = 1;
if (!strcmp (term, "vt100")) vt102 = 0;
get_color_info ();
1998-02-27 07:54:42 +03:00
SLtt_set_term_vtxxx (&vt102);
(void) SLtt_get_screen_size ();
return 0;
1998-02-27 07:54:42 +03:00
}
return -1;
1998-02-27 07:54:42 +03:00
}
# else /* USE_TERMCAP */
if (1 != tgetent(Termcap_Buf, term))
return -1;
/* Termcap_String_Ptr = Termcap_String_Buf; */
# endif /* NOT USE_TERMCAP */
Termcap_Initalized = 1;
Cls_Str = SLtt_tgetstr ("cl");
Curs_Pos_Str = SLtt_tgetstr ("cm");
1998-02-27 07:54:42 +03:00
if ((NULL == (Ins_Mode_Str = SLtt_tgetstr("im")))
|| ( NULL == (Eins_Mode_Str = SLtt_tgetstr("ei")))
|| ( NULL == (Del_Char_Str = SLtt_tgetstr("dc"))))
SLtt_Term_Cannot_Insert = 1;
1998-02-27 07:54:42 +03:00
Visible_Bell_Str = SLtt_tgetstr ("vb");
Curs_Up_Str = SLtt_tgetstr ("up");
Rev_Scroll_Str = SLtt_tgetstr("sr");
Del_N_Lines_Str = SLtt_tgetstr("DL");
Add_N_Lines_Str = SLtt_tgetstr("AL");
/* Actually these are used to initialize terminals that use cursor
1998-02-27 07:54:42 +03:00
* addressing. Hard to believe.
*/
Term_Init_Str = SLtt_tgetstr ("ti");
Term_Reset_Str = SLtt_tgetstr ("te");
/* If I do this for vtxxx terminals, arrow keys start sending ESC O A,
1998-02-27 07:54:42 +03:00
* which I do not want. This is mainly for HP terminals.
*/
if ((almost_vtxxx == 0) || SLtt_Force_Keypad_Init)
{
Keypad_Init_Str = SLtt_tgetstr ("ks");
Keypad_Reset_Str = SLtt_tgetstr ("ke");
}
/* Make up for defective termcap/terminfo databases */
if ((Vt100_Like && (term[2] != '1'))
|| Linux_Console
|| is_xterm
)
{
if (Del_N_Lines_Str == NULL) Del_N_Lines_Str = "\033[%dM";
if (Add_N_Lines_Str == NULL) Add_N_Lines_Str = "\033[%dL";
}
1998-02-27 07:54:42 +03:00
Scroll_R_Str = SLtt_tgetstr("cs");
1998-02-27 07:54:42 +03:00
SLtt_get_screen_size ();
if ((Scroll_R_Str == NULL)
1998-02-27 07:54:42 +03:00
|| (((NULL == Del_N_Lines_Str) || (NULL == Add_N_Lines_Str))
&& (NULL == Rev_Scroll_Str)))
{
if (is_xterm
|| Linux_Console
)
{
/* Defective termcap mode!!!! */
SLtt_set_term_vtxxx (NULL);
}
else SLtt_Term_Cannot_Scroll = 1;
}
1998-02-27 07:54:42 +03:00
Del_Eol_Str = SLtt_tgetstr("ce");
Del_Bol_Str = SLtt_tgetstr("cb");
if (is_xterm && (Del_Bol_Str == NULL))
Del_Bol_Str = "\033[1K";
if (is_xterm && (Del_Eol_Str == NULL))
Del_Eol_Str = "\033[K";
1998-02-27 07:54:42 +03:00
Rev_Vid_Str = SLtt_tgetstr("mr");
if (Rev_Vid_Str == NULL) Rev_Vid_Str = SLtt_tgetstr("so");
1998-02-27 07:54:42 +03:00
Bold_Vid_Str = SLtt_tgetstr("md");
/* Although xterm cannot blink, it does display the blinking characters
* as bold ones. Some Rxvt will display the background as high intensity.
*/
if ((NULL == (Blink_Vid_Str = SLtt_tgetstr("mb")))
&& is_xterm)
Blink_Vid_Str = "\033[5m";
1998-02-27 07:54:42 +03:00
UnderLine_Vid_Str = SLtt_tgetstr("us");
1998-02-27 07:54:42 +03:00
Start_Alt_Chars_Str = SLtt_tgetstr ("as"); /* smacs */
End_Alt_Chars_Str = SLtt_tgetstr ("ae"); /* rmacs */
Enable_Alt_Char_Set = SLtt_tgetstr ("eA"); /* enacs */
SLtt_Graphics_Char_Pairs = SLtt_tgetstr ("ac");
if (NULL == SLtt_Graphics_Char_Pairs)
{
/* make up for defective termcap/terminfo */
if (Vt100_Like)
{
Start_Alt_Chars_Str = "\016";
End_Alt_Chars_Str = "\017";
Enable_Alt_Char_Set = "\033)0";
}
}
1998-02-27 07:54:42 +03:00
/* aixterm added by willi */
if (is_xterm || !strncmp (term, "aixterm", 7))
{
#if 0
1998-02-27 07:54:42 +03:00
Start_Alt_Chars_Str = "\016";
End_Alt_Chars_Str = "\017";
Enable_Alt_Char_Set = "\033(B\033)0";
#else
Start_Alt_Chars_Str = "\033(0";
End_Alt_Chars_Str = "\033(B";
Enable_Alt_Char_Set = "";
#endif
1998-02-27 07:54:42 +03:00
}
if ((SLtt_Graphics_Char_Pairs == NULL) &&
1998-02-27 07:54:42 +03:00
((Start_Alt_Chars_Str == NULL) || (End_Alt_Chars_Str == NULL)))
{
SLtt_Has_Alt_Charset = 0;
Enable_Alt_Char_Set = NULL;
}
else SLtt_Has_Alt_Charset = 1;
#ifdef AMIGA
Enable_Alt_Char_Set = Start_Alt_Chars_Str = End_Alt_Chars_Str = NULL;
#endif
1998-02-27 07:54:42 +03:00
/* status line capabilities */
if ((SLtt_Has_Status_Line == -1)
&& (0 != (SLtt_Has_Status_Line = TGETFLAG ("hs"))))
{
Disable_Status_line_Str = SLtt_tgetstr ("ds");
Return_From_Status_Line_Str = SLtt_tgetstr ("fs");
Goto_Status_Line_Str = SLtt_tgetstr ("ts");
/* Status_Line_Esc_Ok = TGETFLAG("es"); */
Num_Status_Line_Columns = SLtt_tgetnum ("ws");
1998-02-27 07:54:42 +03:00
if (Num_Status_Line_Columns < 0) Num_Status_Line_Columns = 0;
}
if (NULL == (Norm_Vid_Str = SLtt_tgetstr("me")))
1998-02-27 07:54:42 +03:00
{
Norm_Vid_Str = SLtt_tgetstr("se");
}
1998-02-27 07:54:42 +03:00
Cursor_Invisible_Str = SLtt_tgetstr("vi");
Cursor_Visible_Str = SLtt_tgetstr("ve");
1998-02-27 07:54:42 +03:00
Curs_F_Str = SLtt_tgetstr("RI");
# if 0
1998-02-27 07:54:42 +03:00
if (NULL != Curs_F_Str)
{
Len_Curs_F_Str = strlen(Curs_F_Str);
1998-02-27 07:54:42 +03:00
}
else Len_Curs_F_Str = strlen(Curs_Pos_Str);
# endif
1998-02-27 07:54:42 +03:00
Automatic_Margins = TGETFLAG ("am");
/* No_Move_In_Standout = !TGETFLAG ("ms"); */
# ifdef HP_GLITCH_CODE
1998-02-27 07:54:42 +03:00
Has_HP_Glitch = TGETFLAG ("xs");
# else
1998-02-27 07:54:42 +03:00
Worthless_Highlight = TGETFLAG ("xs");
# endif
1998-02-27 07:54:42 +03:00
if (Worthless_Highlight == 0)
{ /* Magic cookie glitch */
Worthless_Highlight = (SLtt_tgetnum ("sg") > 0);
1998-02-27 07:54:42 +03:00
}
if (Worthless_Highlight)
SLtt_Has_Alt_Charset = 0;
Reset_Color_String = SLtt_tgetstr ("op");
/* Apparantly the difference between "AF" and "Sf" is that AF uses RGB,
* but Sf uses BGR.
*/
Color_Fg_Str = SLtt_tgetstr ("AF"); /* ANSI setaf */
if (Color_Fg_Str == NULL)
1998-02-27 07:54:42 +03:00
{
Color_Fg_Str = SLtt_tgetstr ("Sf"); /* setf */
Is_Fg_BGR = (Color_Fg_Str != NULL);
}
Color_Bg_Str = SLtt_tgetstr ("AB"); /* ANSI setbf */
if (Color_Bg_Str == NULL)
{
Color_Bg_Str = SLtt_tgetstr ("Sb"); /* setb */
Is_Bg_BGR = (Color_Bg_Str != NULL);
1998-02-27 07:54:42 +03:00
}
if ((Max_Terminfo_Colors = SLtt_tgetnum ("Co")) < 0)
Max_Terminfo_Colors = 8;
if ((Color_Bg_Str != NULL) && (Color_Fg_Str != NULL))
SLtt_Use_Ansi_Colors = 1;
else
{
#if 0
Color_Fg_Str = "%?%p1%{7}%>%t\033[1;3%p1%{8}%m%dm%e\033[3%p1%dm%;";
Color_Bg_Str = "%?%p1%{7}%>%t\033[5;4%p1%{8}%m%dm%e\033[4%p1%dm%;";
Max_Terminfo_Colors = 16;
#else
Color_Fg_Str = "\033[3%dm";
Color_Bg_Str = "\033[4%dm";
Max_Terminfo_Colors = 8;
#endif
}
#if SLTT_HAS_NON_BCE_SUPPORT
Can_Background_Color_Erase = TGETFLAG ("ut"); /* bce */
/* Modern xterms have the BCE capability as well as the linux console */
if (Can_Background_Color_Erase == 0)
{
Can_Background_Color_Erase = (Linux_Console
# if SLTT_XTERM_ALWAYS_BCE
|| is_xterm
# endif
);
}
#endif
get_color_info ();
if ((Cls_Str == NULL)
|| (Curs_Pos_Str == NULL))
return -2;
return 0;
1998-02-27 07:54:42 +03:00
}
#endif
/* Unix */
/* specific to vtxxx only */
void SLtt_enable_cursor_keys (void)
{
#ifdef __unix__
if (Vt100_Like)
#endif
tt_write_string("\033=\033[?1l");
1998-02-27 07:54:42 +03:00
}
#ifdef VMS
int SLtt_initialize (char *term)
{
SLtt_get_terminfo ();
return 0;
}
1998-02-27 07:54:42 +03:00
void SLtt_get_terminfo ()
{
int zero = 0;
/* Apparantly, this cannot fail according to the man pages. */
if (SLang_TT_Write_FD == -1)
SLang_TT_Write_FD = fileno (stdout);
Can_Background_Color_Erase = 0;
Color_Fg_Str = "\033[3%dm";
Color_Bg_Str = "\033[4%dm";
Max_Terminfo_Colors = 8;
1998-02-27 07:54:42 +03:00
get_color_info ();
SLtt_set_term_vtxxx(&zero);
Start_Alt_Chars_Str = "\016";
End_Alt_Chars_Str = "\017";
SLtt_Has_Alt_Charset = 1;
SLtt_Graphics_Char_Pairs = "aaffgghhjjkkllmmnnooqqssttuuvvwwxx";
Enable_Alt_Char_Set = "\033(B\033)0";
1998-02-27 07:54:42 +03:00
SLtt_get_screen_size ();
}
#endif
/* This sets term for vt102 terminals it parameter vt100 is 0. If vt100
* is non-zero, set terminal appropriate for a only vt100
1998-02-27 07:54:42 +03:00
* (no add line capability). */
1998-02-27 07:54:42 +03:00
void SLtt_set_term_vtxxx(int *vt100)
{
Norm_Vid_Str = "\033[m";
Scroll_R_Str = "\033[%i%d;%dr";
1998-02-27 07:54:42 +03:00
Cls_Str = "\033[2J\033[H";
Rev_Vid_Str = "\033[7m";
Bold_Vid_Str = "\033[1m";
Blink_Vid_Str = "\033[5m";
UnderLine_Vid_Str = "\033[4m";
Del_Eol_Str = "\033[K";
Del_Bol_Str = "\033[1K";
1998-02-27 07:54:42 +03:00
Rev_Scroll_Str = "\033M";
Curs_F_Str = "\033[%dC";
/* Len_Curs_F_Str = 5; */
Curs_Pos_Str = "\033[%i%d;%dH";
if ((vt100 == NULL) || (*vt100 == 0))
{
Ins_Mode_Str = "\033[4h";
Eins_Mode_Str = "\033[4l";
Del_Char_Str = "\033[P";
Del_N_Lines_Str = "\033[%dM";
Add_N_Lines_Str = "\033[%dL";
SLtt_Term_Cannot_Insert = 0;
}
else
{
Del_N_Lines_Str = NULL;
Add_N_Lines_Str = NULL;
SLtt_Term_Cannot_Insert = 1;
}
SLtt_Term_Cannot_Scroll = 0;
/* No_Move_In_Standout = 0; */
}
int SLtt_init_video (void)
1998-02-27 07:54:42 +03:00
{
/* send_string_to_term("\033[?6h"); */
/* relative origin mode */
tt_write_string (Term_Init_Str);
tt_write_string (Keypad_Init_Str);
1998-02-27 07:54:42 +03:00
SLtt_reset_scroll_region();
SLtt_end_insert();
tt_write_string (Enable_Alt_Char_Set);
1998-02-27 07:54:42 +03:00
Video_Initialized = 1;
return 0;
1998-02-27 07:54:42 +03:00
}
int SLtt_reset_video (void)
1998-02-27 07:54:42 +03:00
{
SLtt_goto_rc (SLtt_Screen_Rows - 1, 0);
Cursor_Set = 0;
SLtt_normal_video (); /* MSKermit requires this */
tt_write_string(Norm_Vid_Str);
1998-02-27 07:54:42 +03:00
Current_Fgbg = 0xFFFFFFFFU;
SLtt_set_alt_char_set (0);
if (SLtt_Use_Ansi_Colors)
1998-02-27 07:54:42 +03:00
{
if (Reset_Color_String == NULL)
{
SLtt_Char_Type attr;
if (-1 != make_color_fgbg (NULL, NULL, &attr))
write_attributes (attr);
else tt_write_string ("\033[0m\033[m");
1998-02-27 07:54:42 +03:00
}
else tt_write_string (Reset_Color_String);
1998-02-27 07:54:42 +03:00
Current_Fgbg = 0xFFFFFFFFU;
}
SLtt_erase_line ();
tt_write_string (Keypad_Reset_Str);
tt_write_string (Term_Reset_Str);
if (Mouse_Mode == 1)
SLtt_set_mouse_mode (0, 1);
1998-02-27 07:54:42 +03:00
SLtt_flush_output ();
Video_Initialized = 0;
return 0;
1998-02-27 07:54:42 +03:00
}
void SLtt_bold_video (void)
{
tt_write_string (Bold_Vid_Str);
1998-02-27 07:54:42 +03:00
}
int SLtt_set_mouse_mode (int mode, int force)
{
char *term;
1998-02-27 07:54:42 +03:00
if (force == 0)
{
if (NULL == (term = (char *) getenv("TERM"))) return -1;
if (strncmp ("xterm", term, 5))
return -1;
}
Mouse_Mode = (mode != 0);
1998-02-27 07:54:42 +03:00
if (mode)
tt_write_string ("\033[?9h");
1998-02-27 07:54:42 +03:00
else
tt_write_string ("\033[?9l");
1998-02-27 07:54:42 +03:00
return 0;
}
void SLtt_disable_status_line (void)
{
if (SLtt_Has_Status_Line > 0)
{
tt_write_string (Disable_Status_line_Str);
SLtt_flush_output ();
}
1998-02-27 07:54:42 +03:00
}
int SLtt_write_to_status_line (char *s, int col)
{
if ((SLtt_Has_Status_Line <= 0)
|| (Goto_Status_Line_Str == NULL)
|| (Return_From_Status_Line_Str == NULL))
return -1;
1998-02-27 07:54:42 +03:00
tt_printf (Goto_Status_Line_Str, col, 0);
tt_write_string (s);
tt_write_string (Return_From_Status_Line_Str);
1998-02-27 07:54:42 +03:00
return 0;
}
void SLtt_get_screen_size (void)
{
1998-02-27 07:54:42 +03:00
#ifdef VMS
int status, code;
unsigned short chan;
$DESCRIPTOR(dev_dsc, "SYS$INPUT:");
#endif
int r = 0, c = 0;
#ifdef TIOCGWINSZ
1998-02-27 07:54:42 +03:00
struct winsize wind_struct;
1998-02-27 07:54:42 +03:00
do
{
if ((ioctl(1,TIOCGWINSZ,&wind_struct) == 0)
|| (ioctl(0, TIOCGWINSZ, &wind_struct) == 0)
|| (ioctl(2, TIOCGWINSZ, &wind_struct) == 0))
{
c = (int) wind_struct.ws_col;
r = (int) wind_struct.ws_row;
break;
}
}
while (errno == EINTR);
1998-02-27 07:54:42 +03:00
#endif
#ifdef VMS
status = sys$assign(&dev_dsc,&chan,0,0,0);
if (status & 1)
{
code = DVI$_DEVBUFSIZ;
status = lib$getdvi(&code, &chan,0, &c, 0,0);
if (!(status & 1))
c = 80;
code = DVI$_TT_PAGE;
status = lib$getdvi(&code, &chan,0, &r, 0,0);
if (!(status & 1))
r = 24;
sys$dassgn(chan);
}
#endif
if (r <= 0)
{
char *s = getenv ("LINES");
if (s != NULL) r = atoi (s);
}
1998-02-27 07:54:42 +03:00
if (c <= 0)
{
char *s = getenv ("COLUMNS");
if (s != NULL) c = atoi (s);
}
if ((r <= 0) || (r > SLTT_MAX_SCREEN_ROWS)) r = 24;
if ((c <= 0) || (c > SLTT_MAX_SCREEN_COLS)) c = 80;
1998-02-27 07:54:42 +03:00
SLtt_Screen_Rows = r;
SLtt_Screen_Cols = c;
}
#if SLTT_HAS_NON_BCE_SUPPORT
int _pSLtt_get_bce_color_offset (void)
{
if ((SLtt_Use_Ansi_Colors == 0)
|| Can_Background_Color_Erase
|| SLtt_Use_Blink_For_ACS) /* in this case, we cannot lose a color */
Bce_Color_Offset = 0;
else
{
SLtt_Char_Type fgbg = get_brush_fgbg (0);
if (GET_BG(fgbg) == SLSMG_COLOR_DEFAULT)
Bce_Color_Offset = 0;
else
Bce_Color_Offset = 1;
}
return Bce_Color_Offset;
}
#endif
int SLtt_utf8_enable (int mode)
{
if (mode == -1)
mode = _pSLutf8_mode;
return _pSLtt_UTF8_Mode = mode;
}
int SLtt_is_utf8_mode (void)
{
int mode = _pSLtt_UTF8_Mode;
if (mode == -1)
mode = _pSLutf8_mode;
return mode;
}