version 1.9, 2014/04/25 13:38:21 |
version 1.10, 2015/11/05 22:08:44 |
|
|
* |
* |
* For more information, see the README file. |
* For more information, see the README file. |
*/ |
*/ |
|
/* |
|
* Modified for use with illumos. |
|
* Copyright 2014 Garrett D'Amore <garrett@damore.org> |
|
*/ |
|
|
|
|
/* |
/* |
* High level routines dealing with the output to the screen. |
* High level routines dealing with the output to the screen. |
*/ |
*/ |
|
|
#include "less.h" |
#include "less.h" |
#if MSDOS_COMPILER==WIN32C |
|
#include "windows.h" |
|
#endif |
|
|
|
public int errmsgs; /* Count of messages displayed by error() */ |
int errmsgs; /* Count of messages displayed by error() */ |
public int need_clr; |
|
public int final_attr; |
|
public int at_prompt; |
|
|
|
extern volatile sig_atomic_t sigs; |
extern volatile sig_atomic_t sigs; |
extern int sc_width; |
extern int sc_width; |
|
|
extern int is_tty; |
extern int is_tty; |
extern int oldbot; |
extern int oldbot; |
|
|
#if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC |
static int need_clr; |
extern int ctldisp; |
|
extern int nm_fg_color, nm_bg_color; |
|
extern int bo_fg_color, bo_bg_color; |
|
extern int ul_fg_color, ul_bg_color; |
|
extern int so_fg_color, so_bg_color; |
|
extern int bl_fg_color, bl_bg_color; |
|
#endif |
|
|
|
/* |
/* |
* Display the line which is in the line buffer. |
* Display the line which is in the line buffer. |
*/ |
*/ |
public void |
void |
put_line() |
put_line(void) |
{ |
{ |
register int c; |
int c; |
register int i; |
int i; |
int a; |
int a; |
|
|
if (ABORT_SIGS()) |
if (ABORT_SIGS()) { |
{ |
|
/* |
/* |
* Don't output if a signal is pending. |
* Don't output if a signal is pending. |
*/ |
*/ |
|
|
return; |
return; |
} |
} |
|
|
final_attr = AT_NORMAL; |
for (i = 0; (c = gline(i, &a)) != '\0'; i++) { |
|
|
for (i = 0; (c = gline(i, &a)) != '\0'; i++) |
|
{ |
|
at_switch(a); |
at_switch(a); |
final_attr = a; |
|
if (c == '\b') |
if (c == '\b') |
putbs(); |
putbs(); |
else |
else |
putchr(c); |
(void) putchr(c); |
} |
} |
|
|
at_exit(); |
at_exit(); |
|
|
* sure these messages can be seen before they are |
* sure these messages can be seen before they are |
* overwritten or scrolled away. |
* overwritten or scrolled away. |
*/ |
*/ |
public void |
void |
flush() |
flush(void) |
{ |
{ |
register int n; |
int n; |
register int fd; |
int fd; |
ssize_t nwritten; |
ssize_t nwritten; |
|
|
n = ob - obuf; |
n = (intptr_t)ob - (intptr_t)obuf; |
if (n == 0) |
if (n == 0) |
return; |
return; |
|
|
#if MSDOS_COMPILER==MSOFTC |
|
if (is_tty && any_display) |
|
{ |
|
*ob = '\0'; |
|
_outtext(obuf); |
|
ob = obuf; |
|
return; |
|
} |
|
#else |
|
#if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC |
|
if (is_tty && any_display) |
|
{ |
|
*ob = '\0'; |
|
if (ctldisp != OPT_ONPLUS) |
|
WIN32textout(obuf, ob - obuf); |
|
else |
|
{ |
|
/* |
|
* Look for SGR escape sequences, and convert them |
|
* to color commands. Replace bold, underline, |
|
* and italic escapes into colors specified via |
|
* the -D command-line option. |
|
*/ |
|
char *anchor, *p, *p_next; |
|
unsigned char fg, bg; |
|
static unsigned char at; |
|
#if MSDOS_COMPILER==WIN32C |
|
/* Screen colors used by 3x and 4x SGR commands. */ |
|
static unsigned char screen_color[] = { |
|
0, /* BLACK */ |
|
FOREGROUND_RED, |
|
FOREGROUND_GREEN, |
|
FOREGROUND_RED|FOREGROUND_GREEN, |
|
FOREGROUND_BLUE, |
|
FOREGROUND_BLUE|FOREGROUND_RED, |
|
FOREGROUND_BLUE|FOREGROUND_GREEN, |
|
FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED |
|
}; |
|
#else |
|
static enum COLORS screen_color[] = { |
|
BLACK, RED, GREEN, BROWN, |
|
BLUE, MAGENTA, CYAN, LIGHTGRAY |
|
}; |
|
#endif |
|
|
|
for (anchor = p_next = obuf; |
|
(p_next = memchr(p_next, ESC, ob - p_next)) != NULL; ) |
|
{ |
|
p = p_next; |
|
if (p[1] == '[') /* "ESC-[" sequence */ |
|
{ |
|
if (p > anchor) |
|
{ |
|
/* |
|
* If some chars seen since |
|
* the last escape sequence, |
|
* write them out to the screen. |
|
*/ |
|
WIN32textout(anchor, p-anchor); |
|
anchor = p; |
|
} |
|
p += 2; /* Skip the "ESC-[" */ |
|
if (is_ansi_end(*p)) |
|
{ |
|
/* |
|
* Handle null escape sequence |
|
* "ESC[m", which restores |
|
* the normal color. |
|
*/ |
|
p++; |
|
anchor = p_next = p; |
|
at = 0; |
|
WIN32setcolors(nm_fg_color, nm_bg_color); |
|
continue; |
|
} |
|
p_next = p; |
|
|
|
/* |
|
* Select foreground/background colors |
|
* based on the escape sequence. |
|
*/ |
|
fg = nm_fg_color; |
|
bg = nm_bg_color; |
|
while (!is_ansi_end(*p)) |
|
{ |
|
char *q; |
|
long code = strtol(p, &q, 10); |
|
|
|
if (*q == '\0') |
|
{ |
|
/* |
|
* Incomplete sequence. |
|
* Leave it unprocessed |
|
* in the buffer. |
|
*/ |
|
int slop = q - anchor; |
|
/* {{ strlcpy args overlap! }} */ |
|
strlcpy(obuf, anchor, |
|
sizeof(obuf)); |
|
ob = &obuf[slop]; |
|
return; |
|
} |
|
|
|
if (q == p || |
|
code > 49 || code < 0 || |
|
(!is_ansi_end(*q) && *q != ';')) |
|
{ |
|
p_next = q; |
|
break; |
|
} |
|
if (*q == ';') |
|
q++; |
|
|
|
switch (code) |
|
{ |
|
default: |
|
/* case 0: all attrs off */ |
|
fg = nm_fg_color; |
|
bg = nm_bg_color; |
|
at = 0; |
|
break; |
|
case 1: /* bold on */ |
|
at |= 1; |
|
break; |
|
case 3: /* italic on */ |
|
case 7: /* inverse on */ |
|
at |= 2; |
|
break; |
|
case 4: /* underline on */ |
|
at |= 4; |
|
break; |
|
case 5: /* slow blink on */ |
|
case 6: /* fast blink on */ |
|
at |= 8; |
|
break; |
|
case 8: /* concealed on */ |
|
fg = (bg & 7) | 8; |
|
break; |
|
case 22: /* bold off */ |
|
at &= ~1; |
|
break; |
|
case 23: /* italic off */ |
|
case 27: /* inverse off */ |
|
at &= ~2; |
|
break; |
|
case 24: /* underline off */ |
|
at &= ~4; |
|
break; |
|
case 30: case 31: case 32: |
|
case 33: case 34: case 35: |
|
case 36: case 37: |
|
fg = (fg & 8) | (screen_color[code - 30]); |
|
break; |
|
case 39: /* default fg */ |
|
fg = nm_fg_color; |
|
break; |
|
case 40: case 41: case 42: |
|
case 43: case 44: case 45: |
|
case 46: case 47: |
|
bg = (bg & 8) | (screen_color[code - 40]); |
|
break; |
|
case 49: /* default fg */ |
|
bg = nm_bg_color; |
|
break; |
|
} |
|
p = q; |
|
} |
|
if (!is_ansi_end(*p) || p == p_next) |
|
break; |
|
if (at & 1) |
|
{ |
|
/* |
|
* If \e[1m use defined bold |
|
* color, else set intensity. |
|
*/ |
|
if (p[-2] == '[') |
|
{ |
|
#if MSDOS_COMPILER==WIN32C |
|
fg |= FOREGROUND_INTENSITY; |
|
bg |= BACKGROUND_INTENSITY; |
|
#else |
|
fg = bo_fg_color; |
|
bg = bo_bg_color; |
|
#endif |
|
} else |
|
fg |= 8; |
|
} else if (at & 2) |
|
{ |
|
fg = so_fg_color; |
|
bg = so_bg_color; |
|
} else if (at & 4) |
|
{ |
|
fg = ul_fg_color; |
|
bg = ul_bg_color; |
|
} else if (at & 8) |
|
{ |
|
fg = bl_fg_color; |
|
bg = bl_bg_color; |
|
} |
|
fg &= 0xf; |
|
bg &= 0xf; |
|
WIN32setcolors(fg, bg); |
|
p_next = anchor = p + 1; |
|
} else |
|
p_next++; |
|
} |
|
|
|
/* Output what's left in the buffer. */ |
|
WIN32textout(anchor, ob - anchor); |
|
} |
|
ob = obuf; |
|
return; |
|
} |
|
#endif |
|
#endif |
|
fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO; |
fd = (any_display) ? STDOUT_FILENO : STDERR_FILENO; |
nwritten = write(fd, obuf, n); |
nwritten = write(fd, obuf, n); |
if (nwritten != n) { |
if (nwritten != n) { |
|
|
/* |
/* |
* Output a character. |
* Output a character. |
*/ |
*/ |
public int |
int |
putchr(c) |
putchr(int c) |
int c; |
|
{ |
{ |
#if 0 /* fake UTF-8 output for testing */ |
if (need_clr) { |
extern int utf_mode; |
|
if (utf_mode) |
|
{ |
|
static char ubuf[MAX_UTF_CHAR_LEN]; |
|
static int ubuf_len = 0; |
|
static int ubuf_index = 0; |
|
if (ubuf_len == 0) |
|
{ |
|
ubuf_len = utf_len(c); |
|
ubuf_index = 0; |
|
} |
|
ubuf[ubuf_index++] = c; |
|
if (ubuf_index < ubuf_len) |
|
return c; |
|
c = get_wchar(ubuf) & 0xFF; |
|
ubuf_len = 0; |
|
} |
|
#endif |
|
if (need_clr) |
|
{ |
|
need_clr = 0; |
need_clr = 0; |
clear_bot(); |
clear_bot(); |
} |
} |
#if MSDOS_COMPILER |
|
if (c == '\n' && is_tty) |
|
{ |
|
/* remove_top(1); */ |
|
putchr('\r'); |
|
} |
|
#else |
|
#ifdef _OSK |
|
if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */ |
|
putchr(0x0A); |
|
#endif |
|
#endif |
|
/* |
/* |
* Some versions of flush() write to *ob, so we must flush |
* Some versions of flush() write to *ob, so we must flush |
* when we are still one char from the end of obuf. |
* when we are still one char from the end of obuf. |
*/ |
*/ |
if (ob >= &obuf[sizeof(obuf)-1]) |
if (ob >= &obuf[sizeof (obuf)-1]) |
flush(); |
flush(); |
*ob++ = c; |
*ob++ = (char)c; |
at_prompt = 0; |
|
return (c); |
return (c); |
} |
} |
|
|
/* |
/* |
* Output a string. |
* Output a string. |
*/ |
*/ |
public void |
void |
putstr(s) |
putstr(const char *s) |
register char *s; |
|
{ |
{ |
while (*s != '\0') |
while (*s != '\0') |
putchr(*s++); |
(void) putchr(*s++); |
} |
} |
|
|
|
|
/* |
/* |
* Convert an integral type to a string. |
* Convert an integral type to a string. |
*/ |
*/ |
#define TYPE_TO_A_FUNC(funcname, type) \ |
#define TYPE_TO_A_FUNC(funcname, type) \ |
void funcname(num, buf, len) \ |
void \ |
type num; \ |
funcname(type num, char *buf, size_t len) \ |
char *buf; \ |
{ \ |
size_t len; \ |
int neg = (num < 0); \ |
{ \ |
char tbuf[INT_STRLEN_BOUND(num)+2]; \ |
int neg = (num < 0); \ |
char *s = tbuf + sizeof (tbuf); \ |
char tbuf[INT_STRLEN_BOUND(num)+2]; \ |
if (neg) \ |
register char *s = tbuf + sizeof(tbuf); \ |
num = -num; \ |
if (neg) num = -num; \ |
*--s = '\0'; \ |
*--s = '\0'; \ |
do { \ |
do { \ |
*--s = (num % 10) + '0'; \ |
*--s = (num % 10) + '0'; \ |
} while ((num /= 10) != 0); \ |
} while ((num /= 10) != 0); \ |
if (neg) \ |
if (neg) *--s = '-'; \ |
*--s = '-'; \ |
strlcpy(buf, s, len); \ |
(void) strlcpy(buf, s, len); \ |
} |
} |
|
|
TYPE_TO_A_FUNC(postoa, POSITION) |
TYPE_TO_A_FUNC(postoa, off_t) |
TYPE_TO_A_FUNC(linenumtoa, LINENUM) |
TYPE_TO_A_FUNC(linenumtoa, LINENUM) |
TYPE_TO_A_FUNC(inttoa, int) |
TYPE_TO_A_FUNC(inttoa, int) |
|
|
/* |
/* |
* Output an integer in a given radix. |
* Output an integer in a given radix. |
*/ |
*/ |
static int |
static int |
iprint_int(num) |
iprint_int(int num) |
int num; |
|
{ |
{ |
char buf[INT_STRLEN_BOUND(num)]; |
char buf[INT_STRLEN_BOUND(num)]; |
|
|
inttoa(num, buf, sizeof(buf)); |
inttoa(num, buf, sizeof (buf)); |
putstr(buf); |
putstr(buf); |
return (strlen(buf)); |
return (strlen(buf)); |
} |
} |
|
|
/* |
/* |
* Output a line number in a given radix. |
* Output a line number in a given radix. |
*/ |
*/ |
static int |
static int |
iprint_linenum(num) |
iprint_linenum(LINENUM num) |
LINENUM num; |
|
{ |
{ |
char buf[INT_STRLEN_BOUND(num)]; |
char buf[INT_STRLEN_BOUND(num)]; |
|
|
linenumtoa(num, buf, sizeof(buf)); |
linenumtoa(num, buf, sizeof (buf)); |
putstr(buf); |
putstr(buf); |
return (strlen(buf)); |
return (strlen(buf)); |
} |
} |
|
|
* This function implements printf-like functionality |
* This function implements printf-like functionality |
* using a more portable argument list mechanism than printf's. |
* using a more portable argument list mechanism than printf's. |
*/ |
*/ |
static int |
static int |
less_printf(fmt, parg) |
less_printf(const char *fmt, PARG *parg) |
register char *fmt; |
|
PARG *parg; |
|
{ |
{ |
register char *s; |
register char *s; |
register int col; |
register int col; |
|
|
col = 0; |
col = 0; |
while (*fmt != '\0') |
while (*fmt != '\0') { |
{ |
if (*fmt != '%') { |
if (*fmt != '%') |
(void) putchr(*fmt++); |
{ |
|
putchr(*fmt++); |
|
col++; |
col++; |
} else |
} else { |
{ |
|
++fmt; |
++fmt; |
switch (*fmt++) |
switch (*fmt++) { |
{ |
|
case 's': |
case 's': |
s = parg->p_string; |
s = parg->p_string; |
parg++; |
parg++; |
while (*s != '\0') |
while (*s != '\0') { |
{ |
(void) putchr(*s++); |
putchr(*s++); |
|
col++; |
col++; |
} |
} |
break; |
break; |
|
|
* If some other non-trivial char is pressed, unget it, so it will |
* If some other non-trivial char is pressed, unget it, so it will |
* become the next command. |
* become the next command. |
*/ |
*/ |
public void |
void |
get_return() |
get_return(void) |
{ |
{ |
int c; |
int c; |
|
|
#if ONLY_RETURN |
|
while ((c = getchr()) != '\n' && c != '\r') |
|
bell(); |
|
#else |
|
c = getchr(); |
c = getchr(); |
if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR) |
if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR) |
ungetcc(c); |
ungetcc(c); |
#endif |
|
} |
} |
|
|
/* |
/* |
* Output a message in the lower left corner of the screen |
* Output a message in the lower left corner of the screen |
* and wait for carriage return. |
* and wait for carriage return. |
*/ |
*/ |
public void |
void |
error(fmt, parg) |
error(const char *fmt, PARG *parg) |
char *fmt; |
|
PARG *parg; |
|
{ |
{ |
int col = 0; |
int col = 0; |
static char return_to_continue[] = " (press RETURN)"; |
static char return_to_continue[] = " (press RETURN)"; |
|
|
errmsgs++; |
errmsgs++; |
|
|
if (any_display && is_tty) |
if (any_display && is_tty) { |
{ |
|
if (!oldbot) |
if (!oldbot) |
squish_check(); |
squish_check(); |
at_exit(); |
at_exit(); |
|
|
|
|
col += less_printf(fmt, parg); |
col += less_printf(fmt, parg); |
|
|
if (!(any_display && is_tty)) |
if (!(any_display && is_tty)) { |
{ |
(void) putchr('\n'); |
putchr('\n'); |
|
return; |
return; |
} |
} |
|
|
putstr(return_to_continue); |
putstr(return_to_continue); |
at_exit(); |
at_exit(); |
col += sizeof(return_to_continue) + so_e_width; |
col += sizeof (return_to_continue) + so_e_width; |
|
|
get_return(); |
get_return(); |
lower_left(); |
lower_left(); |
clear_eol(); |
clear_eol(); |
|
|
if (col >= sc_width) |
if (col >= sc_width) |
/* |
/* |
|
|
* Usually used to warn that we are beginning a potentially |
* Usually used to warn that we are beginning a potentially |
* time-consuming operation. |
* time-consuming operation. |
*/ |
*/ |
public void |
void |
ierror(fmt, parg) |
ierror(const char *fmt, PARG *parg) |
char *fmt; |
|
PARG *parg; |
|
{ |
{ |
at_exit(); |
at_exit(); |
clear_bot(); |
clear_bot(); |
|
|
* Output a message in the lower left corner of the screen |
* Output a message in the lower left corner of the screen |
* and return a single-character response. |
* and return a single-character response. |
*/ |
*/ |
public int |
int |
query(fmt, parg) |
query(const char *fmt, PARG *parg) |
char *fmt; |
|
PARG *parg; |
|
{ |
{ |
register int c; |
register int c; |
int col = 0; |
int col = 0; |
|
|
(void) less_printf(fmt, parg); |
(void) less_printf(fmt, parg); |
c = getchr(); |
c = getchr(); |
|
|
if (!(any_display && is_tty)) |
if (!(any_display && is_tty)) { |
{ |
(void) putchr('\n'); |
putchr('\n'); |
|
return (c); |
return (c); |
} |
} |
|
|