#include "less.h"
#if MSDOS_COMPILER==WIN32C
#include "windows.h"
#ifndef COMMON_LVB_UNDERSCORE
#define COMMON_LVB_UNDERSCORE 0x8000
#endif
#endif
public int errmsgs;
public int need_clr;
public int final_attr;
public int at_prompt;
extern int sigs;
extern int sc_width;
extern int so_s_width, so_e_width;
extern int is_tty;
extern int oldbot;
extern int utf_mode;
extern char intr_char;
#if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
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;
extern int sgr_mode;
#if MSDOS_COMPILER==WIN32C
extern int vt_enabled;
#endif
#endif
public void put_line(lbool forw_scroll)
{
int c;
size_t i;
int a;
if (ABORT_SIGS())
{
screen_trashed();
return;
}
final_attr = AT_NORMAL;
for (i = 0; (c = gline(i, &a)) != '\0'; i++)
{
at_switch(a);
final_attr = a;
if (c == '\b')
putbs();
else
putchr(c);
}
at_exit();
if (forw_scroll && should_clear_after_line())
clear_eol();
}
static char obuf[OUTBUF_SIZE];
static char *ob = obuf;
static int outfd = 2;
#if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
typedef unsigned t_attr;
#define A_BOLD (1u<<0)
#define A_ITALIC (1u<<1)
#define A_UNDERLINE (1u<<2)
#define A_BLINK (1u<<3)
#define A_INVERSE (1u<<4)
#define A_CONCEAL (1u<<5)
typedef unsigned long t_color;
#define T_DEFAULT 0ul
#define T_ANSI 1ul
#define CGET_ANSI(c) ((c) & 0x7)
#define C_DEFAULT (T_DEFAULT <<24)
#define C_ANSI(c) ((T_ANSI <<24) | (c))
typedef struct t_sgr {
t_attr attr;
t_color fg;
t_color bg;
} t_sgr;
static constant t_sgr SGR_DEFAULT;
static int update_sgr(t_sgr *sgr, long code)
{
switch (code)
{
case 0: *sgr = SGR_DEFAULT; break;
case 1: sgr->attr |= A_BOLD; break;
case 22: sgr->attr &= ~A_BOLD; break;
case 3: sgr->attr |= A_ITALIC; break;
case 23: sgr->attr &= ~A_ITALIC; break;
case 4: sgr->attr |= A_UNDERLINE; break;
case 24: sgr->attr &= ~A_UNDERLINE; break;
case 6:
case 5: sgr->attr |= A_BLINK; break;
case 25: sgr->attr &= ~A_BLINK; break;
case 7: sgr->attr |= A_INVERSE; break;
case 27: sgr->attr &= ~A_INVERSE; break;
case 8: sgr->attr |= A_CONCEAL; break;
case 28: sgr->attr &= ~A_CONCEAL; break;
case 39: sgr->fg = C_DEFAULT; break;
case 49: sgr->bg = C_DEFAULT; break;
case 30: case 31: case 32: case 33:
case 34: case 35: case 36: case 37:
sgr->fg = C_ANSI(code - 30);
break;
case 40: case 41: case 42: case 43:
case 44: case 45: case 46: case 47:
sgr->bg = C_ANSI(code - 40);
break;
default:
return 1;
}
return 0;
}
static void set_win_colors(t_sgr *sgr)
{
#if MSDOS_COMPILER==WIN32C
static unsigned char screen_color[] = {
0,
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
int fg, bg, tmp;
if (!sgr_mode && sgr->fg == C_DEFAULT && sgr->bg == C_DEFAULT)
{
switch (sgr->attr)
{
case A_BOLD:
WIN32setcolors(bo_fg_color, bo_bg_color);
return;
case A_UNDERLINE:
WIN32setcolors(ul_fg_color, ul_bg_color);
return;
case A_BLINK:
WIN32setcolors(bl_fg_color, bl_bg_color);
return;
case A_INVERSE:
WIN32setcolors(so_fg_color, so_bg_color);
return;
case A_ITALIC:
WIN32setcolors(so_fg_color, so_bg_color);
return;
}
}
fg = sgr->fg == C_DEFAULT ? nm_fg_color
: screen_color[CGET_ANSI(sgr->fg)];
bg = sgr->bg == C_DEFAULT ? nm_bg_color
: screen_color[CGET_ANSI(sgr->bg)];
if (sgr->attr & A_BOLD)
fg |= 8;
if (sgr->attr & (A_BLINK | A_UNDERLINE))
bg |= 8;
if (sgr->attr & (A_INVERSE | A_ITALIC))
{
tmp = fg;
fg = bg;
bg = tmp;
}
if (sgr->attr & A_CONCEAL)
fg = bg ^ 8;
WIN32setcolors(fg, bg);
}
static lbool is_ansi_end_0(char c)
{
return c != '\0' && is_ansi_end((unsigned char)c);
}
static void win_flush(void)
{
#if MSDOS_COMPILER != WIN32C
static constant int vt_enabled = 0;
#endif
if (ctldisp != OPT_ONPLUS || (vt_enabled && sgr_mode))
WIN32textout(obuf, ptr_diff(ob, obuf));
else
{
char *anchor, *p, *p_next;
static t_sgr sgr;
static int sgr_bad_sync;
for (anchor = p_next = obuf;
(p_next = memchr(p_next, ESC, ob - p_next)) != NULL; )
{
p = p_next;
if (p[1] == '[')
{
int bad_code = 0;
if (p > anchor)
{
WIN32textout(anchor, ptr_diff(p, anchor));
anchor = p;
}
p += 2;
if (is_ansi_end_0(*p))
{
p++;
anchor = p_next = p;
update_sgr(&sgr, 0);
set_win_colors(&sgr);
sgr_bad_sync = 0;
continue;
}
p_next = p;
while (!is_ansi_end_0(*p))
{
char *q;
long code = strtol(p, &q, 10);
if (*q == '\0')
{
size_t slop = ptr_diff(q, anchor);
memmove(obuf, anchor, slop);
ob = &obuf[slop];
return;
}
if (q == p ||
(!is_ansi_end_0(*q) && *q != ';'))
{
p_next = q;
break;
}
if (*q == ';')
q++;
if (!bad_code)
bad_code = update_sgr(&sgr, code);
if (bad_code)
sgr_bad_sync = 1;
else if (code == 0)
sgr_bad_sync = 0;
p = q;
}
if (!is_ansi_end_0(*p) || p == p_next)
break;
if (sgr_bad_sync && vt_enabled) {
WIN32textout(anchor, ptr_diff(p+1, anchor));
} else {
set_win_colors(&sgr);
}
p_next = anchor = p + 1;
} else
p_next++;
}
WIN32textout(anchor, ptr_diff(ob, anchor));
}
ob = obuf;
}
#endif
public void flush(void)
{
size_t n;
n = ptr_diff(ob, obuf);
if (n == 0)
return;
ob = obuf;
#if MSDOS_COMPILER==MSOFTC
if (interactive())
{
obuf[n] = '\0';
_outtext(obuf);
return;
}
#else
#if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
if (interactive())
{
ob = obuf + n;
*ob = '\0';
win_flush();
return;
}
#endif
#endif
if (write(outfd, obuf, n) != n)
screen_trashed();
}
public void set_output(int fd)
{
flush();
outfd = fd;
}
public int putchr(int ch)
{
char c = (char) ch;
#if 0
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
clear_bot_if_needed();
#if MSDOS_COMPILER
if (c == '\n' && is_tty)
{
putchr('\r');
}
#else
#ifdef _OSK
if (c == '\n' && is_tty)
putchr(0x0A);
#endif
#endif
if (ob >= &obuf[sizeof(obuf)-1])
flush();
*ob++ = c;
at_prompt = 0;
return (c);
}
public void clear_bot_if_needed(void)
{
if (!need_clr)
return;
need_clr = 0;
clear_bot();
}
public void putstr(constant char *s)
{
while (*s != '\0')
putchr(*s++);
}
#define TYPE_TO_A_FUNC(funcname, type) \
void funcname(type num, char *buf, int radix) \
{ \
int neg = (num < 0); \
char tbuf[INT_STRLEN_BOUND(num)+2]; \
char *s = tbuf + sizeof(tbuf); \
if (neg) num = -num; \
*--s = '\0'; \
do { \
*--s = "0123456789ABCDEF"[num % radix]; \
} while ((num /= radix) != 0); \
if (neg) *--s = '-'; \
strcpy(buf, s); \
}
TYPE_TO_A_FUNC(postoa, POSITION)
TYPE_TO_A_FUNC(linenumtoa, LINENUM)
TYPE_TO_A_FUNC(inttoa, int)
#define STR_TO_TYPE_FUNC(funcname, cfuncname, type) \
type cfuncname(constant char *buf, constant char **ebuf, int radix) \
{ \
type val = 0; \
lbool v = 0; \
for (;; buf++) { \
char c = *buf; \
int digit = (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : (c >= 'A' && c <= 'F') ? c - 'A' + 10 : -1; \
if (digit < 0 || digit >= radix) break; \
v = v || ckd_mul(&val, val, radix); \
v = v || ckd_add(&val, val, digit); \
} \
if (ebuf != NULL) *ebuf = buf; \
return v ? (type)(-1) : val; \
} \
type funcname(char *buf, char **ebuf, int radix) \
{ \
constant char *cbuf = buf; \
type r = cfuncname(cbuf, &cbuf, radix); \
if (ebuf != NULL) *ebuf = (char *) cbuf; \
return r; \
}
STR_TO_TYPE_FUNC(lstrtopos, lstrtoposc, POSITION)
STR_TO_TYPE_FUNC(lstrtoi, lstrtoic, int)
STR_TO_TYPE_FUNC(lstrtoul, lstrtoulc, unsigned long)
#define IPRINT_FUNC(funcname, type, typetoa) \
static int funcname(type num, int radix) \
{ \
char buf[INT_STRLEN_BOUND(num)]; \
typetoa(num, buf, radix); \
putstr(buf); \
return (int) strlen(buf); \
}
IPRINT_FUNC(iprint_int, int, inttoa)
IPRINT_FUNC(iprint_linenum, LINENUM, linenumtoa)
public int less_printf(constant char *fmt, PARG *parg)
{
constant char *s;
constant char *es;
int col;
col = 0;
while (*fmt != '\0')
{
if (*fmt != '%')
{
putchr(*fmt++);
col++;
} else
{
++fmt;
switch (*fmt++)
{
case 's':
s = parg->p_string;
es = s + strlen(s);
parg++;
while (*s != '\0')
{
LWCHAR ch = step_charc(&s, +1, es);
constant char *ps = utf_mode ? prutfchar(ch) : prchar(ch);
while (*ps != '\0')
{
putchr(*ps++);
col++;
}
}
break;
case 'd':
col += iprint_int(parg->p_int, 10);
parg++;
break;
case 'x':
col += iprint_int(parg->p_int, 16);
parg++;
break;
case 'n':
col += iprint_linenum(parg->p_linenum, 10);
parg++;
break;
case 'c':
s = prchar((LWCHAR) parg->p_char);
parg++;
while (*s != '\0')
{
putchr(*s++);
col++;
}
break;
case '%':
putchr('%');
break;
}
}
}
return (col);
}
public void get_return(void)
{
int c;
#if ONLY_RETURN
while ((c = getchr()) != '\n' && c != '\r')
bell();
#else
c = getchr();
if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR)
ungetcc((char) c);
#endif
}
public void error(constant char *fmt, PARG *parg)
{
int col = 0;
static char return_to_continue[] = " (press RETURN)";
errmsgs++;
if (!interactive())
{
less_printf(fmt, parg);
putchr('\n');
return;
}
if (!oldbot)
squish_check();
at_exit();
clear_bot();
at_enter(AT_STANDOUT|AT_COLOR_ERROR);
col += so_s_width;
col += less_printf(fmt, parg);
putstr(return_to_continue);
at_exit();
col += (int) sizeof(return_to_continue) + so_e_width;
get_return();
lower_left();
clear_eol();
if (col >= sc_width)
screen_trashed();
flush();
}
static void ierror_suffix(constant char *fmt, PARG *parg, constant char *suffix1, constant char *suffix2, constant char *suffix3)
{
at_exit();
clear_bot();
at_enter(AT_STANDOUT|AT_COLOR_ERROR);
(void) less_printf(fmt, parg);
putstr(suffix1);
putstr(suffix2);
putstr(suffix3);
at_exit();
flush();
need_clr = 1;
}
public void ierror(constant char *fmt, PARG *parg)
{
ierror_suffix(fmt, parg, "... (interrupt to abort)", "", "");
}
public void ixerror(constant char *fmt, PARG *parg)
{
if (!supports_ctrl_x())
ierror(fmt, parg);
else
{
char ichar[MAX_PRCHAR_LEN+1];
strcpy(ichar, prchar((LWCHAR) intr_char));
ierror_suffix(fmt, parg, "... (", ichar, " or interrupt to abort)");
}
}
public int query(constant char *fmt, PARG *parg)
{
int c;
int col = 0;
if (interactive())
clear_bot();
(void) less_printf(fmt, parg);
c = getchr();
if (interactive())
{
lower_left();
if (col >= sc_width)
screen_trashed();
flush();
} else
{
putchr('\n');
}
if (c == 'Q')
quit(QUIT_OK);
return (c);
}