sldisply.c
来自「这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统」· C语言 代码 · 共 2,241 行 · 第 1/4 页
C
2,241 行
/* Copyright (c) 1992, 1995 John E. Davis
* All rights reserved.
*
* You may distribute under the terms of either the GNU General Public
* License or the Perl Artistic License.
*/
/*
* SLTT_TRANSP_ACS_PATCH (#define/#undef):
*
* The problem: some terminals (e.g. QNX/qansi*) map the whole upper half of
* the ASCII table to the lower half, when alt-char-set is activated with
* the smacs/as string-sequence. This means, that if 0 <= ch < 128 written
* to the terminal, it will be translated to (ch+128) automatically by the
* terminal: so not only the line-drawing characters can be written, when
* the alt-char-set is activated. It implicitly means, that space, NL, CR,
* etc. characters (exactly: anything besides the "standard" line drawing
* characters) can not be written directly to the terminal, when the
* alt-char-set is activated, because writing these characters doesn't cause
* an implicit/temporary switching-back to the standard char-set!
*
* The original code in SLang assumes that space, NL, CR, etc. can be
* printed when alt-char-set is activated. If SLTT_TRANSP_ACS_PATCH is
* defined, the modified code will not use this assumption.
* [Remark: the patch-code is not the most exact solution, but works...]
*/
/*#define SLTT_TRANSP_ACS_PATCH 1*/
/*
* QNX_QANSI_SLANG_COMPAT_ACS (#define/#undef):
*
* A more OS/terminal-specific solution for the problem mentioned above
* (->SLTT_TRANSP_ACS_PATCH).
*
* If QNX_QANSI_SLANG_COMPAT_ACS is defined, the default smacs/sa, rmacs/ae,
* acsc/ac [and sgr/sa, if it would be used!] command sequences will be
* replaced internally with the "old style" (pre-QNX 4.23) sequences in case
* of QNX/qansi terminals. Using these optional command sequences the terminal
* remains compatible with the original SLang code (without using the
* workaround-code enabled by defining SLTT_TRANSP_ACS_PATCH).
*/
/*#define QNX_QANSI_SLANG_COMPAT_ACS 1*/
/* auto-configuration */
#ifdef SLTT_TRANSP_ACS_PATCH
# if defined(__QNX__) && defined(QNX_QANSI_SLANG_COMPAT_ACS)
# undef SLTT_TRANSP_ACS_PATCH
# endif
#else
# if defined(__QNX__) && !defined(QNX_QANSI_SLANG_COMPAT_ACS)
# define QNX_QANSI_SLANG_COMPAT_ACS 1
# endif
#endif
#include "sl-feat.h"
#include "config.h"
#include <stdio.h>
#include <string.h>
#ifdef SCO_FLAVOR
# include <sys/types.h>
# include <sys/timeb.h> /* for struct timeb, used in time.h */
#endif
#include <time.h>
#include <ctype.h>
#ifndef VMS
# include <sys/time.h>
# ifdef __QNX__
# include <sys/select.h>
# 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>
#include "slang.h"
#include "_slang.h"
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if defined(__DECC) && defined(VMS)
/* These get prototypes for write an sleep */
# include <unixio.h>
#endif
#include <signal.h>
/* Colors: These definitions are used for the display. However, the
* 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(color) ((color & FG_MASK) >> 8)
#define GET_BG(color) ((color & BG_MASK) >> 16)
#define MAKE_COLOR(fg, bg) (((fg) | ((bg) << 8)) << 8)
int SLtt_Screen_Cols;
int SLtt_Screen_Rows;
int SLtt_Term_Cannot_Insert;
int SLtt_Term_Cannot_Scroll;
int SLtt_Use_Ansi_Colors;
int SLtt_Blink_Mode = 1;
int SLtt_Use_Blink_For_ACS = 0;
int SLtt_Newline_Ok = 0;
int SLtt_Has_Alt_Charset = 0;
int SLtt_Force_Keypad_Init = 0;
/* -1 means unknown */
int SLtt_Has_Status_Line = -1; /* hs */
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
* attributes, one has to erase to the end of the line.
*/
static int Has_HP_Glitch;
#endif
static char *Reset_Color_String;
static int Linux_Console;
/* It is crucial that JMAX_COLORS must be less than 128 since the high bit
* 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
* exploited by DOSemu.
*/
#define JMAX_COLORS 256
#define JNORMAL_COLOR 0
typedef struct
{
SLtt_Char_Type fgbg;
SLtt_Char_Type mono;
char *custom_esc;
} Ansi_Color_Type;
#define RGB1(r, g, b) ((r) | ((g) << 1) | ((b) << 2))
#define RGB(r, g, b, br, bg, bb) ((RGB1(r, g, b) << 8) | (RGB1(br, bg, bb) << 16))
static Ansi_Color_Type Ansi_Color_Map[JMAX_COLORS] =
{
{RGB(1, 1, 1, 0, 0, 0), 0x00000000, NULL}, /* white/black */
{RGB(0, 1, 0, 0, 0, 0), SLTT_REV_MASK, NULL}, /* green/black */
{RGB(1, 0, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* magenta/black */
{RGB(0, 1, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* cyan/black */
{RGB(1, 0, 0, 0, 0, 0), SLTT_REV_MASK, NULL},
{RGB(0, 1, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
{RGB(1, 0, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
{RGB(1, 0, 0, 0, 1, 0), SLTT_REV_MASK, NULL},
{RGB(0, 0, 1, 1, 0, 0), SLTT_REV_MASK, NULL},
{RGB(0, 1, 0, 1, 0, 0), SLTT_REV_MASK, NULL},
{RGB(0, 1, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
{RGB(1, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
{RGB(1, 0, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
{RGB(0, 0, 0, 0, 1, 1), SLTT_REV_MASK, NULL},
{RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
{RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
{RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
{RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL}
};
/* This is the string to use to use when outputting color information.
*/
#ifdef M_UNIX
/* work around for sco console bug that can't handle combined sequences */
static char *Color_Escape_Sequence = "\033[3%dm\033[4%dm";
#else
/* Believe it or not, this is what is in the linux terminfo database. It
* produces the same escape sequence but it is much more CPU intensive.
* Why not just encode it as "\033[3%p1%dm\033[4%p2%dm" ???
*/
/* static char *Color_Escape_Sequence = "\033[%p1%{30}%+%dm\033[%p2%{40}%+%dm"; */
static char *Color_Escape_Sequence = "\033[3%d;4%dm";
#endif
char *SLtt_Graphics_Char_Pairs; /* ac termcap string -- def is vt100 */
/* 1 if terminal lacks the ability to do into insert mode or into delete
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_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 */
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 */
/* 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;
#ifdef SLTT_TRANSP_ACS_PATCH
static int SLtt_ACS_Active = 0;
#endif
static int sl_usleep (unsigned long usecs)
{
#ifndef VMS
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);
SLtt_Num_Chars_Output += n;
total = 0;
while (n > 0)
{
nwrite = write (fileno(stdout), (char *) Output_Buffer + total, n);
if (nwrite == -1)
{
nwrite = 0;
#ifdef EAGAIN
if (errno == EAGAIN)
{
sl_usleep (100000); /* 1/10 sec */
continue;
}
#endif
#ifdef EWOULDBLOCK
if (errno == EWOULDBLOCK)
{
sl_usleep (100000);
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;
if ((str == NULL) || (n == 0)) return;
total += n;
while (1)
{
ndiff = MAX_OUTPUT_BUFFER_SIZE - (int) (Output_Bufferp - Output_Buffer);
if (ndiff < n)
{
SLMEMCPY ((char *) Output_Bufferp, (char *) str, ndiff);
Output_Bufferp += ndiff;
SLtt_flush_output ();
n -= ndiff;
str += ndiff;
}
else
{
SLMEMCPY ((char *) Output_Bufferp, str, n);
Output_Bufferp += n;
break;
}
}
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;
}
}
void SLtt_write_string (char *str)
{
if (str != NULL) tt_write(str, strlen(str));
}
void SLtt_putchar (char ch)
{
#ifdef SLTT_TRANSP_ACS_PATCH
int restore_acs = 0;
#endif
SLtt_normal_video ();
if (Cursor_Set == 1)
{
if (ch >= ' ') Cursor_c++;
#ifndef SLTT_TRANSP_ACS_PATCH
else if (ch == '\b') Cursor_c--;
#else
if (ch <= ' ' && SLtt_ACS_Active)
{
SLtt_set_alt_char_set (0);
restore_acs = 1;
}
if (ch == '\b') Cursor_c--;
#endif
else if (ch == '\r') Cursor_c = 0;
else Cursor_Set = 0;
if ((Cursor_c + 1 == SLtt_Screen_Cols)
&& Automatic_Margins) Cursor_Set = 0;
}
if (Output_Bufferp < Output_Buffer + MAX_OUTPUT_BUFFER_SIZE)
{
*Output_Bufferp++ = (unsigned char) ch;
}
else tt_write (&ch, 1);
#ifdef SLTT_TRANSP_ACS_PATCH
if (restore_acs)
{
SLtt_set_alt_char_set (1);
}
#endif
}
/* this is supposed to be fast--- also handles
termcap: %d, &i, %., %+, %r strings as well as terminfo stuff */
static unsigned int tt_sprintf(char *buf, char *fmt, int x, int y)
{
register unsigned char *f = (unsigned char *) fmt, *b, ch;
int offset = 0, tinfo = 0;
int stack[10];
int i = 0, z;
stack[0] = y; stack[1] = x; i = 2;
b = (unsigned char *) buf;
if (fmt != NULL) while ((ch = *f++) != 0)
{
if (ch != '%') *b++ = ch;
else
{
ch = *f++;
if (tinfo)
{
if ((ch <= '3') && (ch >= '0'))
{
/* map it to termcap. Since this is terminfo,
* it must be one of:
* %2d, %3d, %02d, %03d
*
* I am assuming that a terminal that understands
* %2d form will also understand the %02d form. These
* only differ by a space padding the field.
*/
/* skip the 'd'-- hope it is there */
if (ch == '0')
{
ch = *f;
f += 2;
}
else f++;
}
}
switch (ch)
{
case 'p':
tinfo = 1;
ch = *f++;
if (ch == '1') stack[i++] = x; else stack[i++] = y;
break;
case '\'': /* 'x' */
stack[i++] = *f++;
f++;
break;
case '{': /* literal constant, e.g. {30} */
z = 0;
while (((ch = *f) <= '9') && (ch >= '0'))
{
z = z * 10 + (ch - '0');
f++;
}
stack[i++] = z;
if (ch == '}') f++;
break;
case 'd':
case '2':
case '3':
z = stack[--i];
z += offset;
if (z >= 100)
{
*b++ = z / 100 + '0';
z = z % 100;
goto ten;
}
else if (ch == 3)
{
*b++ = '0';
ch = '2';
}
if (z >= 10)
{
ten:
*b++ = z / 10 + '0';
z = z % 10;
}
else if (ch == 2) *b++ = '0';
*b++ = z + '0';
break;
case 'i':
offset = 1;
break;
case '+':
if (tinfo)
{
z = stack[--i];
stack[i-1] += z;
}
else
{
ch = *f++;
if ((unsigned char) ch == 128) ch = 0;
ch = ch + (unsigned char) stack[--i];
if (ch == '\n') ch++;
*b++ = ch;
}
break;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?