version 1.1.1.1, 1996/09/21 05:39:43 |
version 1.1.1.2, 2003/04/13 18:21:21 |
|
|
/* |
/* |
* Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman |
* Copyright (C) 1984-2002 Mark Nudelman |
* All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* You may distribute under the terms of either the GNU General Public |
* modification, are permitted provided that the following conditions |
* License or the Less License, as specified in the README file. |
* are met: |
|
* 1. Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* 2. Redistributions in binary form must reproduce the above copyright |
|
* notice in the documentation and/or other materials provided with |
|
* the distribution. |
|
* |
* |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY |
* For more information about less, or for information on how to |
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
* contact the author, see the README file. |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
|
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
|
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
|
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
*/ |
|
|
|
|
|
|
*/ |
*/ |
|
|
#include "less.h" |
#include "less.h" |
|
#if MSDOS_COMPILER==WIN32C |
|
#include "windows.h" |
|
#endif |
|
|
public int errmsgs; /* Count of messages displayed by error() */ |
public int errmsgs; /* Count of messages displayed by error() */ |
public int need_clr; |
public int need_clr; |
|
public int final_attr; |
|
|
extern int sigs; |
extern int sigs; |
extern int sc_width; |
extern int sc_width; |
extern int so_s_width, so_e_width; |
extern int so_s_width, so_e_width; |
extern int screen_trashed; |
extern int screen_trashed; |
extern int any_display; |
extern int any_display; |
|
extern int is_tty; |
|
|
|
#if 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; |
|
#endif |
|
|
/* |
/* |
* Display the line which is in the line buffer. |
* Display the line which is in the line buffer. |
*/ |
*/ |
|
|
case AT_BLINK: bl_exit(); break; |
case AT_BLINK: bl_exit(); break; |
case AT_STANDOUT: so_exit(); break; |
case AT_STANDOUT: so_exit(); break; |
} |
} |
|
final_attr = curr_attr; |
} |
} |
|
|
static char obuf[1024]; |
static char obuf[OUTBUF_SIZE]; |
static char *ob = obuf; |
static char *ob = obuf; |
|
|
/* |
/* |
|
|
register int n; |
register int n; |
register int fd; |
register int fd; |
|
|
#if MSOFTC |
|
*ob = '\0'; |
|
_outtext(obuf); |
|
ob = obuf; |
|
#else |
|
n = ob - obuf; |
n = ob - obuf; |
if (n == 0) |
if (n == 0) |
return; |
return; |
|
#if MSDOS_COMPILER==WIN32C |
|
if (is_tty && any_display) |
|
{ |
|
char *op; |
|
DWORD nwritten = 0; |
|
CONSOLE_SCREEN_BUFFER_INFO scr; |
|
int row; |
|
int col; |
|
int olen; |
|
extern HANDLE con_out; |
|
|
|
olen = ob - obuf; |
|
/* |
|
* There is a bug in Win32 WriteConsole() if we're |
|
* writing in the last cell with a different color. |
|
* To avoid color problems in the bottom line, |
|
* we scroll the screen manually, before writing. |
|
*/ |
|
GetConsoleScreenBufferInfo(con_out, &scr); |
|
col = scr.dwCursorPosition.X; |
|
row = scr.dwCursorPosition.Y; |
|
for (op = obuf; op < obuf + olen; op++) |
|
{ |
|
if (*op == '\n') |
|
{ |
|
col = 0; |
|
row++; |
|
} else if (*op == '\r') |
|
{ |
|
col = 0; |
|
} else |
|
{ |
|
col++; |
|
if (col >= sc_width) |
|
{ |
|
col = 0; |
|
row++; |
|
} |
|
} |
|
} |
|
if (row > scr.srWindow.Bottom) |
|
win32_scroll_up(row - scr.srWindow.Bottom); |
|
WriteConsole(con_out, obuf, olen, &nwritten, NULL); |
|
ob = obuf; |
|
return; |
|
} |
|
#else |
|
#if MSDOS_COMPILER==MSOFTC |
|
if (is_tty && any_display) |
|
{ |
|
*ob = '\0'; |
|
_outtext(obuf); |
|
ob = obuf; |
|
return; |
|
} |
|
#else |
|
#if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC |
|
if (is_tty && any_display) |
|
{ |
|
*ob = '\0'; |
|
if (ctldisp != OPT_ONPLUS) |
|
cputs(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; |
|
int buflen = ob - obuf; |
|
unsigned char fg, bg, norm_attr; |
|
/* |
|
* Only dark colors mentioned here, so that |
|
* bold has visible effect. |
|
*/ |
|
static enum COLORS screen_color[] = { |
|
BLACK, RED, GREEN, BROWN, |
|
BLUE, MAGENTA, CYAN, LIGHTGRAY |
|
}; |
|
|
|
/* Normal text colors are used as baseline. */ |
|
bg = nm_bg_color & 0xf; |
|
fg = nm_fg_color & 0xf; |
|
norm_attr = (bg << 4) | fg; |
|
for (anchor = p_next = obuf; |
|
(p_next = memchr (p_next, ESC, |
|
buflen - (p_next - obuf))) |
|
!= NULL; ) |
|
{ |
|
p = p_next; |
|
|
|
/* |
|
* Handle the null escape sequence |
|
* (ESC-[m), which is used to restore |
|
* the original color. |
|
*/ |
|
if (p[1] == '[' && is_ansi_end(p[2])) |
|
{ |
|
textattr(norm_attr); |
|
p += 3; |
|
anchor = p_next = p; |
|
continue; |
|
} |
|
|
|
if (p[1] == '[') /* "Esc-[" sequence */ |
|
{ |
|
/* |
|
* If some chars seen since |
|
* the last escape sequence, |
|
* write it out to the screen |
|
* using current text attributes. |
|
*/ |
|
if (p > anchor) |
|
{ |
|
*p = '\0'; |
|
cputs (anchor); |
|
*p = ESC; |
|
anchor = p; |
|
} |
|
p += 2; |
|
p_next = p; |
|
while (!is_ansi_end(*p)) |
|
{ |
|
char *q; |
|
long code = strtol(p, &q, 10); |
|
|
|
if (!*q) |
|
{ |
|
/* |
|
* Incomplete sequence. |
|
* Leave it unprocessed |
|
* in the buffer. |
|
*/ |
|
int slop = q - anchor; |
|
strcpy(obuf, anchor); |
|
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) |
|
{ |
|
case 1: /* bold on */ |
|
fg = bo_fg_color; |
|
bg = bo_bg_color; |
|
break; |
|
case 3: /* italic on */ |
|
fg = so_fg_color; |
|
bg = so_bg_color; |
|
break; |
|
case 4: /* underline on */ |
|
fg = ul_fg_color; |
|
bg = ul_bg_color; |
|
break; |
|
case 8: /* concealed on */ |
|
fg = (bg & 7) | 8; |
|
break; |
|
case 0: /* all attrs off */ |
|
case 22:/* bold off */ |
|
case 23:/* italic off */ |
|
case 24:/* underline off */ |
|
fg = nm_fg_color; |
|
bg = nm_bg_color; |
|
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) |
|
{ |
|
bg &= 15; |
|
fg &= 15; |
|
textattr ((bg << 4)| fg); |
|
p_next = anchor = p + 1; |
|
} else |
|
break; |
|
} else |
|
p_next++; |
|
} |
|
|
|
/* Output what's left in the buffer. */ |
|
cputs (anchor); |
|
} |
|
ob = obuf; |
|
return; |
|
} |
|
#endif |
|
#endif |
|
#endif |
fd = (any_display) ? 1 : 2; |
fd = (any_display) ? 1 : 2; |
if (write(fd, obuf, n) != n) |
if (write(fd, obuf, n) != n) |
screen_trashed = 1; |
screen_trashed = 1; |
ob = obuf; |
ob = obuf; |
#endif |
|
} |
} |
|
|
/* |
/* |
|
|
putchr(c) |
putchr(c) |
int c; |
int c; |
{ |
{ |
if (ob >= &obuf[sizeof(obuf)]) |
|
flush(); |
|
if (need_clr) |
if (need_clr) |
{ |
{ |
need_clr = 0; |
need_clr = 0; |
clear_bot(); |
clear_bot(); |
} |
} |
#if MSOFTC |
#if MSDOS_COMPILER |
if (c == '\n') |
if (c == '\n' && is_tty) |
|
{ |
|
/* remove_top(1); */ |
putchr('\r'); |
putchr('\r'); |
|
} |
|
#else |
|
#ifdef _OSK |
|
if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */ |
|
putchr(0x0A); |
#endif |
#endif |
|
#endif |
|
/* |
|
* Some versions of flush() write to *ob, so we must flush |
|
* when we are still one char from the end of obuf. |
|
*/ |
|
if (ob >= &obuf[sizeof(obuf)-1]) |
|
flush(); |
*ob++ = c; |
*ob++ = c; |
return (c); |
return (c); |
} |
} |
|
|
|
|
|
|
/* |
/* |
|
* Convert an integral type to a string. |
|
*/ |
|
#define TYPE_TO_A_FUNC(funcname, type) \ |
|
void funcname(num, buf) \ |
|
type num; \ |
|
char *buf; \ |
|
{ \ |
|
int neg = (num < 0); \ |
|
char tbuf[INT_STRLEN_BOUND(num)+2]; \ |
|
register char *s = tbuf + sizeof(tbuf); \ |
|
if (neg) num = -num; \ |
|
*--s = '\0'; \ |
|
do { \ |
|
*--s = (num % 10) + '0'; \ |
|
} while ((num /= 10) != 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) |
|
|
|
/* |
* Output an integer in a given radix. |
* Output an integer in a given radix. |
*/ |
*/ |
static int |
static int |
iprintnum(num, radix) |
iprint_int(num) |
int num; |
int num; |
int radix; |
|
{ |
{ |
register char *s; |
char buf[INT_STRLEN_BOUND(num)]; |
int r; |
|
int neg; |
|
char buf[10]; |
|
|
|
if (neg = (num < 0)) |
inttoa(num, buf); |
num = -num; |
putstr(buf); |
|
return (strlen(buf)); |
|
} |
|
|
s = buf; |
/* |
do |
* Output a line number in a given radix. |
{ |
*/ |
*s++ = (num % radix) + '0'; |
static int |
} while ((num /= radix) != 0); |
iprint_linenum(num) |
|
LINENUM num; |
|
{ |
|
char buf[INT_STRLEN_BOUND(num)]; |
|
|
if (neg) |
linenumtoa(num, buf); |
*s++ = '-'; |
putstr(buf); |
r = s - buf; |
return (strlen(buf)); |
|
|
while (s > buf) |
|
putchr(*--s); |
|
return (r); |
|
} |
} |
|
|
/* |
/* |
|
|
* using a more portable argument list mechanism than printf's. |
* using a more portable argument list mechanism than printf's. |
*/ |
*/ |
static int |
static int |
iprintf(fmt, parg) |
less_printf(fmt, parg) |
register char *fmt; |
register char *fmt; |
PARG *parg; |
PARG *parg; |
{ |
{ |
register char *s; |
register char *s; |
register int n; |
|
register int col; |
register int col; |
|
|
col = 0; |
col = 0; |
|
|
} else |
} else |
{ |
{ |
++fmt; |
++fmt; |
switch (*fmt++) { |
switch (*fmt++) |
|
{ |
case 's': |
case 's': |
s = parg->p_string; |
s = parg->p_string; |
parg++; |
parg++; |
|
|
} |
} |
break; |
break; |
case 'd': |
case 'd': |
n = parg->p_int; |
col += iprint_int(parg->p_int); |
parg++; |
parg++; |
col += iprintnum(n, 10); |
|
break; |
break; |
|
case 'n': |
|
col += iprint_linenum(parg->p_linenum); |
|
parg++; |
|
break; |
} |
} |
} |
} |
} |
} |
|
|
} |
} |
|
|
/* |
/* |
|
* Get a RETURN. |
|
* If some other non-trivial char is pressed, unget it, so it will |
|
* become the next command. |
|
*/ |
|
public void |
|
get_return() |
|
{ |
|
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(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. |
*/ |
*/ |
|
|
char *fmt; |
char *fmt; |
PARG *parg; |
PARG *parg; |
{ |
{ |
int c; |
|
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) |
if (any_display && is_tty) |
{ |
{ |
clear_bot(); |
clear_bot(); |
so_enter(); |
so_enter(); |
col += so_s_width; |
col += so_s_width; |
} |
} |
|
|
col += iprintf(fmt, parg); |
col += less_printf(fmt, parg); |
|
|
if (!any_display) |
if (!(any_display && is_tty)) |
{ |
{ |
putchr('\n'); |
putchr('\n'); |
return; |
return; |
|
|
so_exit(); |
so_exit(); |
col += sizeof(return_to_continue) + so_e_width; |
col += sizeof(return_to_continue) + so_e_width; |
|
|
#if ONLY_RETURN |
get_return(); |
while ((c = getchr()) != '\n' && c != '\r') |
|
bell(); |
|
#else |
|
c = getchr(); |
|
if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR) |
|
ungetcc(c); |
|
#endif |
|
lower_left(); |
lower_left(); |
|
|
if (col >= sc_width) |
if (col >= sc_width) |
|
|
{ |
{ |
clear_bot(); |
clear_bot(); |
so_enter(); |
so_enter(); |
(void) iprintf(fmt, parg); |
(void) less_printf(fmt, parg); |
putstr(intr_to_abort); |
putstr(intr_to_abort); |
so_exit(); |
so_exit(); |
flush(); |
flush(); |
|
|
register int c; |
register int c; |
int col = 0; |
int col = 0; |
|
|
if (any_display) |
if (any_display && is_tty) |
clear_bot(); |
clear_bot(); |
|
|
(void) iprintf(fmt, parg); |
(void) less_printf(fmt, parg); |
c = getchr(); |
c = getchr(); |
|
|
if (!any_display) |
if (!(any_display && is_tty)) |
{ |
{ |
putchr('\n'); |
putchr('\n'); |
return (c); |
return (c); |