diff options
Diffstat (limited to 'contrib/less/screen.c')
-rw-r--r-- | contrib/less/screen.c | 780 |
1 files changed, 563 insertions, 217 deletions
diff --git a/contrib/less/screen.c b/contrib/less/screen.c index c9635f438106..7e8f8af4f463 100644 --- a/contrib/less/screen.c +++ b/contrib/less/screen.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1984-2020 Mark Nudelman + * Copyright (C) 1984-2021 Mark Nudelman * * You may distribute under the terms of either the GNU General Public * License or the Less License, as specified in the README file. @@ -35,6 +35,19 @@ extern int fd0; #endif #include <time.h> +#ifndef FOREGROUND_BLUE +#define FOREGROUND_BLUE 0x0001 +#endif +#ifndef FOREGROUND_GREEN +#define FOREGROUND_GREEN 0x0002 +#endif +#ifndef FOREGROUND_RED +#define FOREGROUND_RED 0x0004 +#endif +#ifndef FOREGROUND_INTENSITY +#define FOREGROUND_INTENSITY 0x0008 +#endif + #else #if HAVE_SYS_IOCTL_H @@ -85,17 +98,19 @@ extern int fd0; #endif #if OS2 -#define DEFAULT_TERM "ansi" +#define DEFAULT_TERM "ansi" static char *windowid; #else -#define DEFAULT_TERM "unknown" +#define DEFAULT_TERM "unknown" #endif #if MSDOS_COMPILER==MSOFTC static int videopages; static long msec_loops; static int flash_created = 0; -#define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); } +#define SET_FG_COLOR(fg) _settextcolor(fg) +#define SET_BG_COLOR(bg) _setbkcolor(bg) +#define SETCOLORS(fg,bg) { SET_FG_COLOR(fg); SET_BG_COLOR(bg); } #endif #if MSDOS_COMPILER==BORLANDC @@ -106,7 +121,9 @@ static int flash_created = 0; #define _settextposition(y,x) gotoxy(x,y) #define _clearscreen(m) clrscr() #define _outtext(s) cputs(s) -#define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); } +#define SET_FG_COLOR(fg) textcolor(fg) +#define SET_BG_COLOR(bg) textbackground(bg) +#define SETCOLORS(fg,bg) { SET_FG_COLOR(fg); SET_BG_COLOR(bg); } extern int sc_height; #endif @@ -138,28 +155,31 @@ static void win32_deinit_term(); #define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) #define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) -#define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) -#define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ - if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ - error("SETCOLORS failed", NULL_PARG); } +#define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) +#define APPLY_COLORS() { if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ + error("SETCOLORS failed", NULL_PARG); } +#define SET_FG_COLOR(fg) { curr_attr |= (fg); APPLY_COLORS(); } +#define SET_BG_COLOR(bg) { curr_attr |= ((bg)<<4); APPLY_COLORS(); } +#define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); APPLY_COLORS(); } #endif #if MSDOS_COMPILER -public int nm_fg_color; /* Color of normal text */ +public int nm_fg_color; /* Color of normal text */ public int nm_bg_color; -public int bo_fg_color; /* Color of bold text */ +public int bo_fg_color; /* Color of bold text */ public int bo_bg_color; -public int ul_fg_color; /* Color of underlined text */ +public int ul_fg_color; /* Color of underlined text */ public int ul_bg_color; -public int so_fg_color; /* Color of standout text */ +public int so_fg_color; /* Color of standout text */ public int so_bg_color; -public int bl_fg_color; /* Color of blinking text */ +public int bl_fg_color; /* Color of blinking text */ public int bl_bg_color; -static int sy_fg_color; /* Color of system text (before less) */ +static int sy_fg_color; /* Color of system text (before less) */ static int sy_bg_color; -public int sgr_mode; /* Honor ANSI sequences rather than using above */ +public int sgr_mode; /* Honor ANSI sequences rather than using above */ #if MSDOS_COMPILER==WIN32C -public int have_ul; /* Is underline available? */ +static DWORD init_output_mode; /* The initial console output mode */ +public int vt_enabled = -1; /* Is virtual terminal processing available? */ #endif #else @@ -167,56 +187,61 @@ public int have_ul; /* Is underline available? */ * Strings passed to tputs() to do various terminal functions. */ static char - *sc_pad, /* Pad string */ - *sc_home, /* Cursor home */ - *sc_addline, /* Add line, scroll down following lines */ - *sc_lower_left, /* Cursor to last line, first column */ - *sc_return, /* Cursor to beginning of current line */ - *sc_move, /* General cursor positioning */ - *sc_clear, /* Clear screen */ - *sc_eol_clear, /* Clear to end of line */ - *sc_eos_clear, /* Clear to end of screen */ - *sc_s_in, /* Enter standout (highlighted) mode */ - *sc_s_out, /* Exit standout mode */ - *sc_u_in, /* Enter underline mode */ - *sc_u_out, /* Exit underline mode */ - *sc_b_in, /* Enter bold mode */ - *sc_b_out, /* Exit bold mode */ - *sc_bl_in, /* Enter blink mode */ - *sc_bl_out, /* Exit blink mode */ - *sc_visual_bell, /* Visual bell (flash screen) sequence */ - *sc_backspace, /* Backspace cursor */ - *sc_s_keypad, /* Start keypad mode */ - *sc_e_keypad, /* End keypad mode */ - *sc_s_mousecap, /* Start mouse capture mode */ - *sc_e_mousecap, /* End mouse capture mode */ - *sc_init, /* Startup terminal initialization */ - *sc_deinit; /* Exit terminal de-initialization */ + *sc_pad, /* Pad string */ + *sc_home, /* Cursor home */ + *sc_addline, /* Add line, scroll down following lines */ + *sc_lower_left, /* Cursor to last line, first column */ + *sc_return, /* Cursor to beginning of current line */ + *sc_move, /* General cursor positioning */ + *sc_clear, /* Clear screen */ + *sc_eol_clear, /* Clear to end of line */ + *sc_eos_clear, /* Clear to end of screen */ + *sc_s_in, /* Enter standout (highlighted) mode */ + *sc_s_out, /* Exit standout mode */ + *sc_u_in, /* Enter underline mode */ + *sc_u_out, /* Exit underline mode */ + *sc_b_in, /* Enter bold mode */ + *sc_b_out, /* Exit bold mode */ + *sc_bl_in, /* Enter blink mode */ + *sc_bl_out, /* Exit blink mode */ + *sc_visual_bell, /* Visual bell (flash screen) sequence */ + *sc_backspace, /* Backspace cursor */ + *sc_s_keypad, /* Start keypad mode */ + *sc_e_keypad, /* End keypad mode */ + *sc_s_mousecap, /* Start mouse capture mode */ + *sc_e_mousecap, /* End mouse capture mode */ + *sc_init, /* Startup terminal initialization */ + *sc_deinit; /* Exit terminal de-initialization */ + +static int attrcolor = -1; #endif static int init_done = 0; -public int auto_wrap; /* Terminal does \r\n when write past margin */ -public int ignaw; /* Terminal ignores \n immediately after wrap */ -public int erase_char; /* The user's erase char */ -public int erase2_char; /* The user's other erase char */ -public int kill_char; /* The user's line-kill char */ -public int werase_char; /* The user's word-erase char */ -public int sc_width, sc_height; /* Height & width of screen */ -public int bo_s_width, bo_e_width; /* Printing width of boldface seq */ -public int ul_s_width, ul_e_width; /* Printing width of underline seq */ -public int so_s_width, so_e_width; /* Printing width of standout seq */ -public int bl_s_width, bl_e_width; /* Printing width of blink seq */ -public int above_mem, below_mem; /* Memory retained above/below screen */ -public int can_goto_line; /* Can move cursor to any line */ -public int clear_bg; /* Clear fills with background color */ -public int missing_cap = 0; /* Some capability is missing */ -public char *kent = NULL; /* Keypad ENTER sequence */ +public int auto_wrap; /* Terminal does \r\n when write past margin */ +public int ignaw; /* Terminal ignores \n immediately after wrap */ +public int erase_char; /* The user's erase char */ +public int erase2_char; /* The user's other erase char */ +public int kill_char; /* The user's line-kill char */ +public int werase_char; /* The user's word-erase char */ +public int sc_width, sc_height; /* Height & width of screen */ +public int bo_s_width, bo_e_width; /* Printing width of boldface seq */ +public int ul_s_width, ul_e_width; /* Printing width of underline seq */ +public int so_s_width, so_e_width; /* Printing width of standout seq */ +public int bl_s_width, bl_e_width; /* Printing width of blink seq */ +public int above_mem, below_mem; /* Memory retained above/below screen */ +public int can_goto_line; /* Can move cursor to any line */ +public int clear_bg; /* Clear fills with background color */ +public int missing_cap = 0; /* Some capability is missing */ +public char *kent = NULL; /* Keypad ENTER sequence */ static int attrmode = AT_NORMAL; static int termcap_debug = -1; extern int binattr; extern int one_screen; +#if LESSTEST +extern char *ttyin_name; +#endif /*LESSTEST*/ #if !MSDOS_COMPILER static char *cheaper LESSPARAMS((char *t1, char *t2, char *def)); @@ -229,15 +254,15 @@ static void tmodes LESSPARAMS((char *incap, char *outcap, char **instr, * and needed by, the termcap library. */ #if MUST_DEFINE_OSPEED -extern short ospeed; /* Terminal output baud rate */ -extern char PC; /* Pad character */ +extern short ospeed; /* Terminal output baud rate */ +extern char PC; /* Pad character */ #endif #ifdef _OSK short ospeed; char PC_, *UP, *BC; #endif -extern int quiet; /* If VERY_QUIET, use visual bell for bell */ +extern int quiet; /* If VERY_QUIET, use visual bell for bell */ extern int no_back_scroll; extern int swindow; extern int no_init; @@ -249,6 +274,8 @@ extern int top_scroll; extern int quit_if_one_screen; extern int oldbot; extern int mousecap; +extern int is_tty; +extern int use_color; #if HILITE_SEARCH extern int hilite_search; #endif @@ -270,12 +297,12 @@ extern char *tgoto(); /* * Change terminal to "raw mode", or restore to "normal" mode. * "Raw mode" means - * 1. An outstanding read will complete on receipt of a single keystroke. - * 2. Input is not echoed. - * 3. On output, \n is mapped to \r\n. - * 4. \t is NOT expanded into spaces. - * 5. Signal-causing characters such as ctrl-C (interrupt), - * etc. are NOT disabled. + * 1. An outstanding read will complete on receipt of a single keystroke. + * 2. Input is not echoed. + * 3. On output, \n is mapped to \r\n. + * 4. \t is NOT expanded into spaces. + * 5. Signal-causing characters such as ctrl-C (interrupt), + * etc. are NOT disabled. * It doesn't matter whether an input \n is mapped to \r, or vice versa. */ public void @@ -285,7 +312,7 @@ raw_mode(on) static int curr_on = 0; if (on == curr_on) - return; + return; erase2_char = '\b'; /* in case OS doesn't know about erase2 */ #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS { @@ -723,11 +750,11 @@ scrsize(VOID_PARAM) int n; #endif -#define DEF_SC_WIDTH 80 +#define DEF_SC_WIDTH 80 #if MSDOS_COMPILER -#define DEF_SC_HEIGHT 25 +#define DEF_SC_HEIGHT 25 #else -#define DEF_SC_HEIGHT 24 +#define DEF_SC_HEIGHT 24 #endif @@ -816,24 +843,24 @@ scrsize(VOID_PARAM) #endif #endif - if (sys_height > 0) - sc_height = sys_height; - else if ((s = lgetenv("LINES")) != NULL) + if ((s = lgetenv("LINES")) != NULL) sc_height = atoi(s); + else if (sys_height > 0) + sc_height = sys_height; #if !MSDOS_COMPILER else if ((n = ltgetnum("li")) > 0) - sc_height = n; + sc_height = n; #endif if (sc_height <= 0) sc_height = DEF_SC_HEIGHT; - if (sys_width > 0) - sc_width = sys_width; - else if ((s = lgetenv("COLUMNS")) != NULL) + if ((s = lgetenv("COLUMNS")) != NULL) sc_width = atoi(s); + else if (sys_width > 0) + sc_width = sys_width; #if !MSDOS_COMPILER else if ((n = ltgetnum("co")) > 0) - sc_width = n; + sc_width = n; #endif if (sc_width <= 0) sc_width = DEF_SC_WIDTH; @@ -895,22 +922,22 @@ special_key_str(key) static char tbuf[40]; char *s; #if MSDOS_COMPILER || OS2 - static char k_right[] = { '\340', PCK_RIGHT, 0 }; - static char k_left[] = { '\340', PCK_LEFT, 0 }; - static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; - static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; - static char k_insert[] = { '\340', PCK_INSERT, 0 }; - static char k_delete[] = { '\340', PCK_DELETE, 0 }; - static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; - static char k_ctl_backspace[] = { '\177', 0 }; - static char k_home[] = { '\340', PCK_HOME, 0 }; - static char k_end[] = { '\340', PCK_END, 0 }; - static char k_up[] = { '\340', PCK_UP, 0 }; - static char k_down[] = { '\340', PCK_DOWN, 0 }; - static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; - static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; - static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; - static char k_f1[] = { '\340', PCK_F1, 0 }; + static char k_right[] = { '\340', PCK_RIGHT, 0 }; + static char k_left[] = { '\340', PCK_LEFT, 0 }; + static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; + static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; + static char k_insert[] = { '\340', PCK_INSERT, 0 }; + static char k_delete[] = { '\340', PCK_DELETE, 0 }; + static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; + static char k_ctl_backspace[] = { '\177', 0 }; + static char k_home[] = { '\340', PCK_HOME, 0 }; + static char k_end[] = { '\340', PCK_END, 0 }; + static char k_up[] = { '\340', PCK_UP, 0 }; + static char k_down[] = { '\340', PCK_DOWN, 0 }; + static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; + static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; + static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; + static char k_f1[] = { '\340', PCK_F1, 0 }; #endif #if !MSDOS_COMPILER char *sp = tbuf; @@ -951,9 +978,9 @@ special_key_str(key) s = windowid ? ltgetstr("kD", &sp) : k_delete; if (s == NULL) { - tbuf[0] = '\177'; - tbuf[1] = '\0'; - s = tbuf; + tbuf[0] = '\177'; + tbuf[1] = '\0'; + s = tbuf; } break; #endif @@ -1037,9 +1064,9 @@ special_key_str(key) s = ltgetstr("kD", &sp); if (s == NULL) { - tbuf[0] = '\177'; - tbuf[1] = '\0'; - s = tbuf; + tbuf[0] = '\177'; + tbuf[1] = '\0'; + s = tbuf; } break; #endif @@ -1093,6 +1120,7 @@ get_term(VOID_PARAM) * before any file operations have been done on fd0. */ SET_BINARY(0); + GetConsoleMode(con_out, &init_output_mode); GetConsoleScreenBufferInfo(con_out, &scr); curr_attr = scr.wAttributes; sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ @@ -1498,6 +1526,34 @@ initcolor(VOID_PARAM) #if MSDOS_COMPILER==WIN32C /* + * Enable virtual terminal processing, if available. + */ + static void +win32_init_vt_term(VOID_PARAM) +{ + DWORD output_mode; + + if (vt_enabled == 0 || (vt_enabled == 1 && con_out == con_out_ours)) + return; + + GetConsoleMode(con_out, &output_mode); + vt_enabled = SetConsoleMode(con_out, + output_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + if (vt_enabled) + { + auto_wrap = 0; + ignaw = 1; + } +} + + static void +win32_deinit_vt_term(VOID_PARAM) +{ + if (vt_enabled == 1 && con_out == con_out_save) + SetConsoleMode(con_out, init_output_mode); +} + +/* * Termcap-like init with a private win32 console. */ static void @@ -1513,8 +1569,6 @@ win32_init_term(VOID_PARAM) if (con_out_ours == INVALID_HANDLE_VALUE) { - DWORD output_mode; - /* * Create our own screen buffer, so that we * may restore the original when done. @@ -1525,12 +1579,6 @@ win32_init_term(VOID_PARAM) (LPSECURITY_ATTRIBUTES) NULL, CONSOLE_TEXTMODE_BUFFER, (LPVOID) NULL); - /* - * Enable underline, if available. - */ - GetConsoleMode(con_out_ours, &output_mode); - have_ul = SetConsoleMode(con_out_ours, - output_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); } size.X = scr.srWindow.Right - scr.srWindow.Left + 1; @@ -1556,6 +1604,68 @@ win32_deinit_term(VOID_PARAM) #endif +#if !MSDOS_COMPILER + static void +do_tputs(str, affcnt, f_putc) + char *str; + int affcnt; + int (*f_putc)(int); +{ +#if LESSTEST + if (ttyin_name != NULL) + putstr(str); + else +#endif /*LESSTEST*/ + tputs(str, affcnt, f_putc); +} + +/* + * Like tputs but we handle $<...> delay strings here because + * some implementations of tputs don't perform delays correctly. + */ + static void +ltputs(str, affcnt, f_putc) + char *str; + int affcnt; + int (*f_putc)(int); +{ + while (str != NULL && *str != '\0') + { +#if HAVE_STRSTR + char *obrac = strstr(str, "$<"); + if (obrac != NULL) + { + char str2[64]; + int slen = obrac - str; + if (slen < sizeof(str2)) + { + int delay; + /* Output first part of string (before "$<"). */ + memcpy(str2, str, slen); + str2[slen] = '\0'; + do_tputs(str2, affcnt, f_putc); + str += slen + 2; + /* Perform the delay. */ + delay = lstrtoi(str, &str); + if (*str == '*') + delay *= affcnt; + flush(); + sleep_ms(delay); + /* Skip past closing ">" at end of delay string. */ + str = strstr(str, ">"); + if (str != NULL) + str++; + continue; + } + } +#endif + /* Pass the rest of the string to tputs and we're done. */ + do_tputs(str, affcnt, f_putc); + break; + } +} +#endif /* MSDOS_COMPILER */ + /* * Configure the termimal so mouse clicks and wheel moves * produce input to less. @@ -1566,7 +1676,7 @@ init_mouse(VOID_PARAM) if (!mousecap) return; #if !MSDOS_COMPILER - tputs(sc_s_mousecap, sc_height, putchr); + ltputs(sc_s_mousecap, sc_height, putchr); #else #if MSDOS_COMPILER==WIN32C SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT @@ -1586,7 +1696,7 @@ deinit_mouse(VOID_PARAM) if (!mousecap) return; #if !MSDOS_COMPILER - tputs(sc_e_mousecap, sc_height, putchr); + ltputs(sc_e_mousecap, sc_height, putchr); #else #if MSDOS_COMPILER==WIN32C SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_EXTENDED_FLAGS @@ -1605,11 +1715,12 @@ init(VOID_PARAM) if (!(quit_if_one_screen && one_screen)) { if (!no_init) - tputs(sc_init, sc_height, putchr); + ltputs(sc_init, sc_height, putchr); if (!no_keypad) - tputs(sc_s_keypad, sc_height, putchr); + ltputs(sc_s_keypad, sc_height, putchr); init_mouse(); } + init_done = 1; if (top_scroll) { int i; @@ -1633,11 +1744,12 @@ init(VOID_PARAM) init_mouse(); } + win32_init_vt_term(); #endif + init_done = 1; initcolor(); flush(); #endif - init_done = 1; } /* @@ -1653,14 +1765,15 @@ deinit(VOID_PARAM) { deinit_mouse(); if (!no_keypad) - tputs(sc_e_keypad, sc_height, putchr); + ltputs(sc_e_keypad, sc_height, putchr); if (!no_init) - tputs(sc_deinit, sc_height, putchr); + ltputs(sc_deinit, sc_height, putchr); } #else /* Restore system colors. */ SETCOLORS(sy_fg_color, sy_bg_color); #if MSDOS_COMPILER==WIN32C + win32_deinit_vt_term(); if (!(quit_if_one_screen && one_screen)) { deinit_mouse(); @@ -1676,13 +1789,30 @@ deinit(VOID_PARAM) } /* + * Are we interactive (ie. writing to an initialized tty)? + */ + public int +interactive(VOID_PARAM) +{ + return (is_tty && init_done); +} + + static void +assert_interactive(VOID_PARAM) +{ + if (interactive()) return; + /* abort(); */ +} + +/* * Home cursor (move to upper left corner of screen). */ public void home(VOID_PARAM) { + assert_interactive(); #if !MSDOS_COMPILER - tputs(sc_home, 1, putchr); + ltputs(sc_home, 1, putchr); #else flush(); _settextposition(1,1); @@ -1696,8 +1826,9 @@ home(VOID_PARAM) public void add_line(VOID_PARAM) { + assert_interactive(); #if !MSDOS_COMPILER - tputs(sc_addline, sc_height, putchr); + ltputs(sc_addline, sc_height, putchr); #else flush(); #if MSDOS_COMPILER==MSOFTC @@ -1905,10 +2036,9 @@ win32_scroll_up(n) public void lower_left(VOID_PARAM) { - if (!init_done) - return; + assert_interactive(); #if !MSDOS_COMPILER - tputs(sc_lower_left, 1, putchr); + ltputs(sc_lower_left, 1, putchr); #else flush(); _settextposition(sc_height, 1); @@ -1921,28 +2051,31 @@ lower_left(VOID_PARAM) public void line_left(VOID_PARAM) { + assert_interactive(); #if !MSDOS_COMPILER - tputs(sc_return, 1, putchr); + ltputs(sc_return, 1, putchr); #else - int row; - flush(); -#if MSDOS_COMPILER==WIN32C { - CONSOLE_SCREEN_BUFFER_INFO scr; - GetConsoleScreenBufferInfo(con_out, &scr); - row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; - } + int row; + flush(); +#if MSDOS_COMPILER==WIN32C + { + CONSOLE_SCREEN_BUFFER_INFO scr; + GetConsoleScreenBufferInfo(con_out, &scr); + row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; + } #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC - row = wherey(); + row = wherey(); #else - { - struct rccoord tpos = _gettextposition(); - row = tpos.row; - } + { + struct rccoord tpos = _gettextposition(); + row = tpos.row; + } #endif #endif - _settextposition(row, 1); + _settextposition(row, 1); + } #endif } @@ -1984,8 +2117,9 @@ check_winch(VOID_PARAM) goto_line(sindex) int sindex; { + assert_interactive(); #if !MSDOS_COMPILER - tputs(tgoto(sc_move, 0, sindex), 1, putchr); + ltputs(tgoto(sc_move, 0, sindex), 1, putchr); #else flush(); _settextposition(sindex+1, 1); @@ -2052,7 +2186,7 @@ vbell(VOID_PARAM) #if !MSDOS_COMPILER if (*sc_visual_bell == '\0') return; - tputs(sc_visual_bell, sc_height, putchr); + ltputs(sc_visual_bell, sc_height, putchr); #else #if MSDOS_COMPILER==DJGPPC ScreenVisualBell(); @@ -2142,8 +2276,9 @@ bell(VOID_PARAM) public void clear(VOID_PARAM) { + assert_interactive(); #if !MSDOS_COMPILER - tputs(sc_clear, sc_height, putchr); + ltputs(sc_clear, sc_height, putchr); #else flush(); #if MSDOS_COMPILER==WIN32C @@ -2161,8 +2296,9 @@ clear(VOID_PARAM) public void clear_eol(VOID_PARAM) { + /* assert_interactive();*/ #if !MSDOS_COMPILER - tputs(sc_eol_clear, 1, putchr); + ltputs(sc_eol_clear, 1, putchr); #else #if MSDOS_COMPILER==MSOFTC short top, left; @@ -2220,13 +2356,14 @@ clear_eol(VOID_PARAM) static void clear_eol_bot(VOID_PARAM) { + assert_interactive(); #if MSDOS_COMPILER clear_eol(); #else if (below_mem) - tputs(sc_eos_clear, 1, putchr); + ltputs(sc_eos_clear, 1, putchr); else - tputs(sc_eol_clear, 1, putchr); + ltputs(sc_eol_clear, 1, putchr); #endif } @@ -2259,42 +2396,305 @@ clear_bot(VOID_PARAM) } } +/* + * Color string may be "x[y]" where x and y are 4-bit color chars, + * or "N[.M]" where N and M are decimal integers> + * Any of x,y,N,M may also be "-" to mean "unchanged". + */ + +/* + * Parse a 4-bit color char. + */ + static int +parse_color4(ch) + char ch; +{ + switch (ch) + { + case 'k': return 0; + case 'r': return CV_RED; + case 'g': return CV_GREEN; + case 'y': return CV_RED|CV_GREEN; + case 'b': return CV_BLUE; + case 'm': return CV_RED|CV_BLUE; + case 'c': return CV_GREEN|CV_BLUE; + case 'w': return CV_RED|CV_GREEN|CV_BLUE; + case 'K': return 0|CV_BRIGHT; + case 'R': return CV_RED|CV_BRIGHT; + case 'G': return CV_GREEN|CV_BRIGHT; + case 'Y': return CV_RED|CV_GREEN|CV_BRIGHT; + case 'B': return CV_BLUE|CV_BRIGHT; + case 'M': return CV_RED|CV_BLUE|CV_BRIGHT; + case 'C': return CV_GREEN|CV_BLUE|CV_BRIGHT; + case 'W': return CV_RED|CV_GREEN|CV_BLUE|CV_BRIGHT; + case '-': return CV_NOCHANGE; + default: return CV_ERROR; + } +} + +/* + * Parse a color as a decimal integer. + */ + static int +parse_color6(ps) + char **ps; +{ + if (**ps == '-') + { + (*ps)++; + return CV_NOCHANGE; + } else + { + char *ops = *ps; + int color = lstrtoi(ops, ps); + if (*ps == ops) + return CV_ERROR; + return color; + } +} + +/* + * Parse a color pair and return the foreground/background values. + * Return type of color specifier: + * CV_4BIT: fg/bg values are OR of CV_{RGB} bits. + * CV_6BIT: fg/bg values are integers entered by user. + */ + public COLOR_TYPE +parse_color(str, p_fg, p_bg) + char *str; + int *p_fg; + int *p_bg; +{ + int fg; + int bg; + COLOR_TYPE type = CT_NULL; + + if (str == NULL || *str == '\0') + return CT_NULL; + if (*str == '+') + str++; /* ignore leading + */ + + fg = parse_color4(str[0]); + bg = parse_color4((strlen(str) < 2) ? '-' : str[1]); + if (fg != CV_ERROR && bg != CV_ERROR) + type = CT_4BIT; + else + { + fg = parse_color6(&str); + bg = (fg != CV_ERROR && *str++ == '.') ? parse_color6(&str) : CV_NOCHANGE; + if (fg != CV_ERROR && bg != CV_ERROR) + type = CT_6BIT; + } + if (p_fg != NULL) *p_fg = fg; + if (p_bg != NULL) *p_bg = bg; + return type; +} + +#if !MSDOS_COMPILER + + static int +sgr_color(color) + int color; +{ + switch (color) + { + case 0: return 30; + case CV_RED: return 31; + case CV_GREEN: return 32; + case CV_RED|CV_GREEN: return 33; + case CV_BLUE: return 34; + case CV_RED|CV_BLUE: return 35; + case CV_GREEN|CV_BLUE: return 36; + case CV_RED|CV_GREEN|CV_BLUE: return 37; + + case CV_BRIGHT: return 90; + case CV_RED|CV_BRIGHT: return 91; + case CV_GREEN|CV_BRIGHT: return 92; + case CV_RED|CV_GREEN|CV_BRIGHT: return 93; + case CV_BLUE|CV_BRIGHT: return 94; + case CV_RED|CV_BLUE|CV_BRIGHT: return 95; + case CV_GREEN|CV_BLUE|CV_BRIGHT: return 96; + case CV_RED|CV_GREEN|CV_BLUE|CV_BRIGHT: return 97; + + default: return color; + } +} + + static void +tput_fmt(fmt, color, f_putc) + char *fmt; + int color; + int (*f_putc)(int); +{ + char buf[16]; + if (color == attrcolor) + return; + SNPRINTF1(buf, sizeof(buf), fmt, color); + ltputs(buf, 1, f_putc); + attrcolor = color; +} + + static void +tput_color(str, f_putc) + char *str; + int (*f_putc)(int); +{ + int fg; + int bg; + + if (str != NULL && strcmp(str, "*") == 0) + { + /* Special case: reset to normal */ + tput_fmt(ESCS"[m", -1, f_putc); + return; + } + switch (parse_color(str, &fg, &bg)) + { + case CT_4BIT: + if (fg >= 0) + tput_fmt(ESCS"[%dm", sgr_color(fg), f_putc); + if (bg >= 0) + tput_fmt(ESCS"[%dm", sgr_color(bg)+10, f_putc); + break; + case CT_6BIT: + if (fg >= 0) + tput_fmt(ESCS"[38;5;%dm", fg, f_putc); + if (bg >= 0) + tput_fmt(ESCS"[48;5;%dm", bg, f_putc); + break; + default: + break; + } +} + + static void +tput_inmode(mode_str, attr, attr_bit, f_putc) + char *mode_str; + int attr; + int attr_bit; + int (*f_putc)(int); +{ + char *color_str; + if ((attr & attr_bit) == 0) + return; + color_str = get_color_map(attr_bit); + if (color_str == NULL || *color_str == '\0' || *color_str == '+') + { + ltputs(mode_str, 1, f_putc); + if (color_str == NULL || *color_str++ != '+') + return; + } + /* Color overrides mode string */ + tput_color(color_str, f_putc); +} + + static void +tput_outmode(mode_str, attr_bit, f_putc) + char *mode_str; + int attr_bit; + int (*f_putc)(int); +{ + if ((attrmode & attr_bit) == 0) + return; + ltputs(mode_str, 1, f_putc); +} + +#else /* MSDOS_COMPILER */ + +#if MSDOS_COMPILER==WIN32C + static int +WIN32put_fmt(fmt, color) + char *fmt; + int color; +{ + char buf[16]; + int len = SNPRINTF1(buf, sizeof(buf), fmt, color); + WIN32textout(buf, len); + return TRUE; +} +#endif + + static int +win_set_color(attr) + int attr; +{ + int fg; + int bg; + int out = FALSE; + char *str = get_color_map(attr); + if (str == NULL || str[0] == '\0') + return FALSE; + switch (parse_color(str, &fg, &bg)) + { + case CT_4BIT: + if (fg >= 0 && bg >= 0) + { + SETCOLORS(fg, bg); + out = TRUE; + } else if (fg >= 0) + { + SET_FG_COLOR(fg); + out = TRUE; + } else if (bg >= 0) + { + SET_BG_COLOR(bg); + out = TRUE; + } + break; +#if MSDOS_COMPILER==WIN32C + case CT_6BIT: + if (vt_enabled) + { + if (fg > 0) + out = WIN32put_fmt(ESCS"[38;5;%dm", fg); + if (bg > 0) + out = WIN32put_fmt(ESCS"[48;5;%dm", bg); + } + break; +#endif + default: + break; + } + return out; +} + +#endif /* MSDOS_COMPILER */ + public void at_enter(attr) int attr; { attr = apply_at_specials(attr); - #if !MSDOS_COMPILER /* The one with the most priority is last. */ - if (attr & AT_UNDERLINE) - tputs(sc_u_in, 1, putchr); - if (attr & AT_BOLD) - tputs(sc_b_in, 1, putchr); - if (attr & AT_BLINK) - tputs(sc_bl_in, 1, putchr); - if (attr & AT_STANDOUT) - tputs(sc_s_in, 1, putchr); + tput_inmode(sc_u_in, attr, AT_UNDERLINE, putchr); + tput_inmode(sc_b_in, attr, AT_BOLD, putchr); + tput_inmode(sc_bl_in, attr, AT_BLINK, putchr); + /* Don't use standout and color at the same time. */ + if (use_color && (attr & AT_COLOR)) + tput_color(get_color_map(attr), putchr); + else + tput_inmode(sc_s_in, attr, AT_STANDOUT, putchr); #else flush(); /* The one with the most priority is first. */ - if (attr & AT_STANDOUT) + if ((attr & AT_COLOR) && use_color) + { + win_set_color(attr); + } else if (attr & AT_STANDOUT) { SETCOLORS(so_fg_color, so_bg_color); } else if (attr & AT_BLINK) { SETCOLORS(bl_fg_color, bl_bg_color); - } - else if (attr & AT_BOLD) + } else if (attr & AT_BOLD) { SETCOLORS(bo_fg_color, bo_bg_color); - } - else if (attr & AT_UNDERLINE) + } else if (attr & AT_UNDERLINE) { SETCOLORS(ul_fg_color, ul_bg_color); } #endif - attrmode = attr; } @@ -2303,19 +2703,15 @@ at_exit(VOID_PARAM) { #if !MSDOS_COMPILER /* Undo things in the reverse order we did them. */ - if (attrmode & AT_STANDOUT) - tputs(sc_s_out, 1, putchr); - if (attrmode & AT_BLINK) - tputs(sc_bl_out, 1, putchr); - if (attrmode & AT_BOLD) - tputs(sc_b_out, 1, putchr); - if (attrmode & AT_UNDERLINE) - tputs(sc_u_out, 1, putchr); + tput_color("*", putchr); + tput_outmode(sc_s_out, AT_STANDOUT, putchr); + tput_outmode(sc_bl_out, AT_BLINK, putchr); + tput_outmode(sc_b_out, AT_BOLD, putchr); + tput_outmode(sc_u_out, AT_UNDERLINE, putchr); #else flush(); SETCOLORS(nm_fg_color, nm_bg_color); #endif - attrmode = AT_NORMAL; } @@ -2357,57 +2753,6 @@ apply_at_specials(attr) return attr; } -#if 0 /* No longer used */ -/* - * Erase the character to the left of the cursor - * and move the cursor left. - */ - public void -backspace(VOID_PARAM) -{ -#if !MSDOS_COMPILER - /* - * Erase the previous character by overstriking with a space. - */ - tputs(sc_backspace, 1, putchr); - putchr(' '); - tputs(sc_backspace, 1, putchr); -#else -#if MSDOS_COMPILER==MSOFTC - struct rccoord tpos; - - flush(); - tpos = _gettextposition(); - if (tpos.col <= 1) - return; - _settextposition(tpos.row, tpos.col-1); - _outtext(" "); - _settextposition(tpos.row, tpos.col-1); -#else -#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC - cputs("\b"); -#else -#if MSDOS_COMPILER==WIN32C - COORD cpos; - DWORD cChars; - CONSOLE_SCREEN_BUFFER_INFO scr; - - flush(); - GetConsoleScreenBufferInfo(con_out, &scr); - cpos = scr.dwCursorPosition; - if (cpos.X <= 0) - return; - cpos.X--; - SetConsoleCursorPosition(con_out, cpos); - FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars); - SetConsoleCursorPosition(con_out, cpos); -#endif -#endif -#endif -#endif -} -#endif /* 0 */ - /* * Output a plain backspace, without erasing the previous char. */ @@ -2419,7 +2764,7 @@ putbs(VOID_PARAM) else { #if !MSDOS_COMPILER - tputs(sc_backspace, 1, putchr); + ltputs(sc_backspace, 1, putchr); #else int row, col; @@ -2638,3 +2983,4 @@ WIN32textout(text, len) #endif } #endif + |