summaryrefslogtreecommitdiffstats
path: root/contrib/less
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2006-08-20 15:50:51 +0000
committerdelphij <delphij@FreeBSD.org>2006-08-20 15:50:51 +0000
commit5d6048735154d14b6086c89e5252e985c9d0a527 (patch)
tree9d4d19c79f8dc39fae28cb5b1937b282caf97a1a /contrib/less
parenta77e94924db530f3a686499642a95d53c8cd845d (diff)
downloadFreeBSD-src-5d6048735154d14b6086c89e5252e985c9d0a527.zip
FreeBSD-src-5d6048735154d14b6086c89e5252e985c9d0a527.tar.gz
Resolve conflicts.
Diffstat (limited to 'contrib/less')
-rw-r--r--contrib/less/command.c51
-rw-r--r--contrib/less/forwback.c13
-rw-r--r--contrib/less/less.h95
-rw-r--r--contrib/less/line.c865
-rw-r--r--contrib/less/main.c14
-rw-r--r--contrib/less/prompt.c30
-rw-r--r--contrib/less/screen.c229
-rw-r--r--contrib/less/search.c130
-rw-r--r--contrib/less/signal.c5
9 files changed, 905 insertions, 527 deletions
diff --git a/contrib/less/command.c b/contrib/less/command.c
index 9bc966c..18ea4d4 100644
--- a/contrib/less/command.c
+++ b/contrib/less/command.c
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2005 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.
@@ -22,7 +22,7 @@
#include "option.h"
#include "cmd.h"
-extern int erase_char, kill_char;
+extern int erase_char, erase2_char, kill_char;
extern int sigs;
extern int quit_at_eof;
extern int quit_if_one_screen;
@@ -69,6 +69,7 @@ static char optchar;
static int optflag;
static int optgetname;
static POSITION bottompos;
+static int save_hshift;
#if PIPEC
static char pipec;
#endif
@@ -394,7 +395,9 @@ mca_char(c)
* Already have a match for the name.
* Don't accept anything but erase/kill.
*/
- if (c == erase_char || c == kill_char)
+ if (c == erase_char ||
+ c == erase2_char ||
+ c == kill_char)
return (MCA_DONE);
return (MCA_MORE);
}
@@ -405,7 +408,7 @@ mca_char(c)
if (cmd_char(c) == CC_QUIT)
return (MCA_DONE);
p = get_cmdbuf();
- lc = islower(p[0]);
+ lc = ASCII_IS_LOWER(p[0]);
o = findopt_name(&p, &oname, NULL);
if (o != NULL)
{
@@ -415,15 +418,15 @@ mca_char(c)
* display the full option name.
*/
optchar = o->oletter;
- if (!lc && islower(optchar))
- optchar = toupper(optchar);
+ if (!lc && ASCII_IS_LOWER(optchar))
+ optchar = ASCII_TO_UPPER(optchar);
cmd_reset();
mca_opt_toggle();
for (p = oname; *p != '\0'; p++)
{
c = *p;
- if (!lc && islower(c))
- c = toupper(c);
+ if (!lc && ASCII_IS_LOWER(c))
+ c = ASCII_TO_UPPER(c);
if (cmd_char(c) != CC_OK)
return (MCA_DONE);
}
@@ -432,7 +435,7 @@ mca_char(c)
}
} else
{
- if (c == erase_char || c == kill_char)
+ if (c == erase_char || c == erase2_char || c == kill_char)
break;
if (optchar != '\0')
/* We already have the option letter. */
@@ -604,7 +607,10 @@ prompt()
bottompos = position(BOTTOM_PLUS_ONE);
/*
- * If the -E flag is set and we've hit EOF on the last file, quit.
+ * If we've hit EOF on the last file, and the -E flag is set
+ * (or -F is set and this is the first prompt), then quit.
+ * {{ Relying on "first prompt" to detect a single-screen file
+ * fails if +G is used, for example. }}
*/
if ((quit_at_eof == OPT_ONPLUS || quit_if_one_screen) &&
hit_eof && !(ch_getflags() & CH_HELPFILE) &&
@@ -633,13 +639,13 @@ prompt()
*/
clear_cmd();
p = pr_string();
- if (p == NULL)
+ if (p == NULL || *p == '\0')
putchr(':');
else
{
- so_enter();
+ at_enter(AT_STANDOUT);
putstr(p);
- so_exit();
+ at_exit();
}
}
@@ -832,6 +838,9 @@ multi_search(pattern, n)
* Restore the file we were originally viewing.
*/
reedit_ifile(save_ifile);
+ } else
+ {
+ unsave_ifile(save_ifile);
}
}
@@ -1217,6 +1226,7 @@ commands()
* just means return to viewing the
* previous file.
*/
+ hshift = save_hshift;
if (edit_prev(1) == 0)
break;
}
@@ -1306,6 +1316,8 @@ commands()
if (ch_getflags() & CH_HELPFILE)
break;
cmd_exec();
+ save_hshift = hshift;
+ hshift = 0;
(void) edit(FAKE_HELPFILE);
break;
@@ -1346,9 +1358,8 @@ commands()
}
if (curr_altfilename != NULL)
{
- error("Cannot edit file processed with LESSOPEN",
+ error("WARNING: This file was viewed via LESSOPEN",
NULL_PARG);
- break;
}
start_mca(A_SHELL, "!", ml_shell, 0);
/*
@@ -1530,8 +1541,8 @@ commands()
break;
start_mca(A_SETMARK, "mark: ", (void*)NULL, 0);
c = getcc();
- if (c == erase_char || c == kill_char ||
- c == '\n' || c == '\r')
+ if (c == erase_char || c == erase2_char ||
+ c == kill_char || c == '\n' || c == '\r')
break;
setmark(c);
break;
@@ -1542,8 +1553,8 @@ commands()
*/
start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0);
c = getcc();
- if (c == erase_char || c == kill_char ||
- c == '\n' || c == '\r')
+ if (c == erase_char || c == erase2_char ||
+ c == kill_char || c == '\n' || c == '\r')
break;
gomark(c);
break;
@@ -1557,7 +1568,7 @@ commands()
}
start_mca(A_PIPE, "|mark: ", (void*)NULL, 0);
c = getcc();
- if (c == erase_char || c == kill_char)
+ if (c == erase_char || c == erase2_char || c == kill_char)
break;
if (c == '\n' || c == '\r')
c = '.';
diff --git a/contrib/less/forwback.c b/contrib/less/forwback.c
index ebad6ae..a514c9f 100644
--- a/contrib/less/forwback.c
+++ b/contrib/less/forwback.c
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2005 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.
@@ -126,13 +126,6 @@ forw(n, pos, force, only_last, nblank)
if (!do_repaint)
{
- /*
- * Forget any current line shift we might have
- * (from the last line of the previous screenful).
- */
- extern int cshift;
- cshift = 0;
-
if (top_scroll && n >= sc_height - 1 && pos != ch_length())
{
/*
@@ -146,7 +139,7 @@ forw(n, pos, force, only_last, nblank)
force = 1;
if (more_mode == 0)
{
- if (top_scroll == OPT_ONPLUS || first_time)
+ if (top_scroll == OPT_ONPLUS || (first_time && top_scroll != OPT_ON))
clear();
home();
}
@@ -246,7 +239,7 @@ forw(n, pos, force, only_last, nblank)
if (top_scroll == OPT_ON)
clear_eol();
put_line();
- if (clear_bg && final_attr != AT_NORMAL)
+ if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL)
{
/*
* Writing the last character on the last line
diff --git a/contrib/less/less.h b/contrib/less/less.h
index 9747520..3700b4f 100644
--- a/contrib/less/less.h
+++ b/contrib/less/less.h
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2005 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.
@@ -80,13 +80,21 @@
#if HAVE_STRING_H
#include <string.h>
#endif
+
+/* OS-specific includes */
#ifdef _OSK
#include <modes.h>
#include <strings.h>
#endif
+
+#ifdef __TANDEM
+#include <floss.h>
+#endif
+
#if MSDOS_COMPILER==WIN32C || OS2
#include <io.h>
#endif
+
#if MSDOS_COMPILER==DJGPPC
#include <io.h>
#include <sys/exceptn.h>
@@ -105,16 +113,40 @@ void free();
* Simple lowercase test which can be used during option processing
* (before options are parsed which might tell us what charset to use).
*/
-#define SIMPLE_IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')
-#define SIMPLE_IS_LOWER(c) ((c) >= 'a' && (c) <= 'z')
-#define SIMPLE_TO_UPPER(c) ((c) - 'a' + 'A')
-#define SIMPLE_TO_LOWER(c) ((c) - 'A' + 'a')
+#define ASCII_IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z')
+#define ASCII_IS_LOWER(c) ((c) >= 'a' && (c) <= 'z')
+#define ASCII_TO_UPPER(c) ((c) - 'a' + 'A')
+#define ASCII_TO_LOWER(c) ((c) - 'A' + 'a')
+
+#undef IS_UPPER
+#undef IS_LOWER
+#undef TO_UPPER
+#undef TO_LOWER
+#undef IS_SPACE
+#undef IS_DIGIT
#if !HAVE_UPPER_LOWER
-#define isupper(c) SIMPLE_IS_UPPER(c)
-#define islower(c) SIMPLE_IS_LOWER(c)
-#define toupper(c) SIMPLE_TO_UPPER(c)
-#define tolower(c) SIMPLE_TO_LOWER(c)
+#define IS_UPPER(c) ASCII_IS_UPPER(c)
+#define IS_LOWER(c) ASCII_IS_LOWER(c)
+#define TO_UPPER(c) ASCII_TO_UPPER(c)
+#define TO_LOWER(c) ASCII_TO_LOWER(c)
+#else
+#define IS_UPPER(c) isupper((unsigned char) (c))
+#define IS_LOWER(c) islower((unsigned char) (c))
+#define TO_UPPER(c) toupper((unsigned char) (c))
+#define TO_LOWER(c) tolower((unsigned char) (c))
+#endif
+
+#ifdef isspace
+#define IS_SPACE(c) isspace((unsigned char)(c))
+#else
+#define IS_SPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' || (c) == '\f')
+#endif
+
+#ifdef isdigit
+#define IS_DIGIT(c) isdigit((unsigned char)(c))
+#else
+#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
#endif
#ifndef NULL
@@ -138,6 +170,19 @@ void free();
#endif
#endif
+#if HAVE_SNPRINTF
+#define SNPRINTF1(str, size, fmt, v1) snprintf((str), (size), (fmt), (v1))
+#define SNPRINTF2(str, size, fmt, v1, v2) snprintf((str), (size), (fmt), (v1), (v2))
+#define SNPRINTF3(str, size, fmt, v1, v2, v3) snprintf((str), (size), (fmt), (v1), (v2), (v3))
+#define SNPRINTF4(str, size, fmt, v1, v2, v3, v4) snprintf((str), (size), (fmt), (v1), (v2), (v3), (v4))
+#else
+/* Use unsafe sprintf if we don't have snprintf. */
+#define SNPRINTF1(str, size, fmt, v1) sprintf((str), (fmt), (v1))
+#define SNPRINTF2(str, size, fmt, v1, v2) sprintf((str), (fmt), (v1), (v2))
+#define SNPRINTF3(str, size, fmt, v1, v2, v3) sprintf((str), (fmt), (v1), (v2), (v3))
+#define SNPRINTF4(str, size, fmt, v1, v2, v3, v4) sprintf((str), (fmt), (v1), (v2), (v3), (v4))
+#endif
+
#define BAD_LSEEK ((off_t)-1)
#ifndef CHAR_BIT
@@ -154,9 +199,11 @@ void free();
/*
* Special types and constants.
*/
+typedef unsigned long LWCHAR;
typedef off_t POSITION;
typedef off_t LINENUM;
#define MIN_LINENUM_WIDTH 7 /* Min printing width of a line number */
+#define MAX_UTF_CHAR_LEN 6 /* Max bytes in one UTF-8 char */
#define NULL_POSITION ((POSITION)(-1))
@@ -265,14 +312,14 @@ struct textlist
#define BS_CONTROL 2 /* \b treated as control char; prints as ^H */
/* How should we search? */
-#define SRCH_FORW 000001 /* Search forward from current position */
-#define SRCH_BACK 000002 /* Search backward from current position */
-#define SRCH_NO_MOVE 000004 /* Highlight, but don't move */
-#define SRCH_FIND_ALL 000010 /* Find and highlight all matches */
-#define SRCH_NO_MATCH 000100 /* Search for non-matching lines */
-#define SRCH_PAST_EOF 000200 /* Search past end-of-file, into next file */
-#define SRCH_FIRST_FILE 000400 /* Search starting at the first file */
-#define SRCH_NO_REGEX 001000 /* Don't use regular expressions */
+#define SRCH_FORW (1 << 0) /* Search forward from current position */
+#define SRCH_BACK (1 << 1) /* Search backward from current position */
+#define SRCH_NO_MOVE (1 << 2) /* Highlight, but don't move */
+#define SRCH_FIND_ALL (1 << 4) /* Find and highlight all matches */
+#define SRCH_NO_MATCH (1 << 8) /* Search for non-matching lines */
+#define SRCH_PAST_EOF (1 << 9) /* Search past end-of-file, into next file */
+#define SRCH_FIRST_FILE (1 << 10) /* Search starting at the first file */
+#define SRCH_NO_REGEX (1 << 12) /* Don't use regular expressions */
#define SRCH_REVERSE(t) (((t) & SRCH_FORW) ? \
(((t) & ~SRCH_FORW) | SRCH_BACK) : \
@@ -290,13 +337,15 @@ struct textlist
#define CF_QUIT_ON_ERASE 0001 /* Abort cmd if its entirely erased */
-/* Special chars used to tell put_line() to do something special */
+/* Special char bit-flags used to tell put_line() to do something special */
#define AT_NORMAL (0)
-#define AT_UNDERLINE (1)
-#define AT_BOLD (2)
-#define AT_BLINK (3)
-#define AT_INVIS (4)
-#define AT_STANDOUT (5)
+#define AT_UNDERLINE (1 << 0)
+#define AT_BOLD (1 << 1)
+#define AT_BLINK (1 << 2)
+#define AT_STANDOUT (1 << 3)
+#define AT_ANSI (1 << 4) /* Content-supplied "ANSI" escape sequence */
+#define AT_BINARY (1 << 5) /* LESS*BINFMT representation */
+#define AT_HILITE (1 << 6) /* Internal highlights (e.g., for search) */
#if '0' == 240
#define IS_EBCDIC_HOST 1
diff --git a/contrib/less/line.c b/contrib/less/line.c
index b537d35..42a2ea3 100644
--- a/contrib/less/line.c
+++ b/contrib/less/line.c
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2005 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.
@@ -17,14 +17,13 @@
*/
#include "less.h"
+#include "charset.h"
-#define IS_CONT(c) (((c) & 0xC0) == 0x80)
-
-public char *linebuf = NULL; /* Buffer which holds the current output line */
+static char *linebuf = NULL; /* Buffer which holds the current output line */
static char *attr = NULL; /* Extension of linebuf to hold attributes */
public int size_linebuf = 0; /* Size of line buffer (and attr buffer) */
-public int cshift; /* Current left-shift of output line buffer */
+static int cshift; /* Current left-shift of output line buffer */
public int hshift; /* Desired left-shift of output line buffer */
public int tabstops[TABSTOP_MAX] = { 0 }; /* Custom tabstops */
public int ntabstops = 1; /* Number of tabstops */
@@ -37,13 +36,17 @@ static int overstrike; /* Next char should overstrike previous char */
static int last_overstrike = AT_NORMAL;
static int is_null_line; /* There is no current line */
static int lmargin; /* Left margin */
-static int hilites; /* Number of hilites in this line */
+static int line_matches; /* Number of search matches in this line */
static char pendc;
static POSITION pendpos;
static char *end_ansi_chars;
+static char *mid_ansi_chars;
+static int attr_swidth();
+static int attr_ewidth();
static int do_append();
+extern int sigs;
extern int bs_mode;
extern int linenums;
extern int ctldisp;
@@ -60,6 +63,11 @@ extern int utf_mode;
extern POSITION start_attnpos;
extern POSITION end_attnpos;
+static char mbc_buf[MAX_UTF_CHAR_LEN];
+static int mbc_buf_len = 0;
+static int mbc_buf_index = 0;
+static POSITION mbc_pos;
+
/*
* Initialize from environment variables.
*/
@@ -69,6 +77,11 @@ init_line()
end_ansi_chars = lgetenv("LESSANSIENDCHARS");
if (end_ansi_chars == NULL || *end_ansi_chars == '\0')
end_ansi_chars = "m";
+
+ mid_ansi_chars = lgetenv("LESSANSIMIDCHARS");
+ if (mid_ansi_chars == NULL || *mid_ansi_chars == '\0')
+ mid_ansi_chars = "0123456789;[?!\"'#%()*+ ";
+
linebuf = (char *) ecalloc(LINEBUF_SIZE, sizeof(char));
attr = (char *) ecalloc(LINEBUF_SIZE, sizeof(char));
size_linebuf = LINEBUF_SIZE;
@@ -77,12 +90,20 @@ init_line()
/*
* Expand the line buffer.
*/
- static int
+ static int
expand_linebuf()
{
- int new_size = size_linebuf + LINEBUF_SIZE;
+ /* Double the size of the line buffer. */
+ int new_size = size_linebuf * 2;
+
+ /* Just realloc to expand the buffer, if we can. */
+#if HAVE_REALLOC
+ char *new_buf = (char *) realloc(linebuf, new_size);
+ char *new_attr = (char *) realloc(attr, new_size);
+#else
char *new_buf = (char *) calloc(new_size, sizeof(char));
char *new_attr = (char *) calloc(new_size, sizeof(char));
+#endif
if (new_buf == NULL || new_attr == NULL)
{
if (new_attr != NULL)
@@ -91,10 +112,23 @@ expand_linebuf()
free(new_buf);
return 1;
}
+#if HAVE_REALLOC
+ /*
+ * We realloc'd the buffers; they already have the old contents.
+ */
+ #if 0
+ memset(new_buf + size_linebuf, 0, new_size - size_linebuf);
+ memset(new_attr + size_linebuf, 0, new_size - size_linebuf);
+ #endif
+#else
+ /*
+ * We just calloc'd the buffers; copy the old contents.
+ */
memcpy(new_buf, linebuf, size_linebuf * sizeof(char));
memcpy(new_attr, attr, size_linebuf * sizeof(char));
free(attr);
free(linebuf);
+#endif
linebuf = new_buf;
attr = new_attr;
size_linebuf = new_size;
@@ -102,6 +136,16 @@ expand_linebuf()
}
/*
+ * Is a character ASCII?
+ */
+ public int
+is_ascii_char(ch)
+ LWCHAR ch;
+{
+ return (ch <= 0x7F);
+}
+
+/*
* Rewind the line buffer.
*/
public void
@@ -109,14 +153,17 @@ prewind()
{
curr = 0;
column = 0;
+ cshift = 0;
overstrike = 0;
+ last_overstrike = AT_NORMAL;
+ mbc_buf_len = 0;
is_null_line = 0;
pendc = '\0';
lmargin = 0;
if (status_col)
lmargin += 1;
#if HILITE_SEARCH
- hilites = 0;
+ line_matches = 0;
#endif
}
@@ -151,9 +198,9 @@ plinenum(pos)
linebuf[curr] = ' ';
if (start_attnpos != NULL_POSITION &&
pos >= start_attnpos && pos < end_attnpos)
- attr[curr] = AT_STANDOUT;
+ attr[curr] = AT_NORMAL|AT_HILITE;
else
- attr[curr] = 0;
+ attr[curr] = AT_NORMAL;
curr++;
column++;
}
@@ -191,92 +238,131 @@ plinenum(pos)
}
/*
- * Determine how many characters are required to shift N columns.
+ * Shift the input line left.
+ * This means discarding N printable chars at the start of the buffer.
*/
- static int
-shift_chars(s, len)
- char *s;
- int len;
+ static void
+pshift(shift)
+ int shift;
{
- char *p = s;
+ LWCHAR prev_ch = 0;
+ unsigned char c;
+ int shifted = 0;
+ int to;
+ int from;
+ int len;
+ int width;
+ int prev_attr;
+ int next_attr;
+
+ if (shift > column - lmargin)
+ shift = column - lmargin;
+ if (shift > curr - lmargin)
+ shift = curr - lmargin;
+ to = from = lmargin;
/*
- * Each char counts for one column, except ANSI color escape
- * sequences use no columns since they don't move the cursor.
+ * We keep on going when shifted == shift
+ * to get all combining chars.
*/
- while (*p != '\0' && len > 0)
+ while (shifted <= shift && from < curr)
{
- if (*p++ != ESC)
+ c = linebuf[from];
+ if (c == ESC && ctldisp == OPT_ONPLUS)
{
- len--;
+ /* Keep cumulative effect. */
+ linebuf[to] = c;
+ attr[to++] = attr[from++];
+ while (from < curr && linebuf[from])
+ {
+ linebuf[to] = linebuf[from];
+ attr[to++] = attr[from];
+ if (!is_ansi_middle(linebuf[from++]))
+ break;
+ }
+ continue;
+ }
+
+ width = 0;
+
+ if (!IS_ASCII_OCTET(c) && utf_mode)
+ {
+ /* Assumes well-formedness validation already done. */
+ LWCHAR ch;
+
+ len = utf_len(c);
+ if (from + len > curr)
+ break;
+ ch = get_wchar(linebuf + from);
+ if (!is_composing_char(ch) && !is_combining_char(prev_ch, ch))
+ width = is_wide_char(ch) ? 2 : 1;
+ prev_ch = ch;
} else
{
- while (*p != '\0')
+ len = 1;
+ if (c == '\b')
+ /* XXX - Incorrect if several '\b' in a row. */
+ width = (utf_mode && is_wide_char(prev_ch)) ? -2 : -1;
+ else if (!control_char(c))
+ width = 1;
+ prev_ch = 0;
+ }
+
+ if (width == 2 && shift - shifted == 1) {
+ /* Should never happen when called by pshift_all(). */
+ attr[to] = attr[from];
+ /*
+ * Assume a wide_char will never be the first half of a
+ * combining_char pair, so reset prev_ch in case we're
+ * followed by a '\b'.
+ */
+ prev_ch = linebuf[to++] = ' ';
+ from += len;
+ shifted++;
+ continue;
+ }
+
+ /* Adjust width for magic cookies. */
+ prev_attr = (to > 0) ? attr[to-1] : AT_NORMAL;
+ next_attr = (from + len < curr) ? attr[from + len] : prev_attr;
+ if (!is_at_equiv(attr[from], prev_attr) &&
+ !is_at_equiv(attr[from], next_attr))
+ {
+ width += attr_swidth(attr[from]);
+ if (from + len < curr)
+ width += attr_ewidth(attr[from]);
+ if (is_at_equiv(prev_attr, next_attr))
{
- if (is_ansi_end(*p++))
- break;
+ width += attr_ewidth(prev_attr);
+ if (from + len < curr)
+ width += attr_swidth(next_attr);
}
}
- }
- return (p - s);
-}
-/*
- * Determine how many characters are required to shift N columns (UTF version).
- * {{ FIXME: what about color escape sequences in UTF mode? }}
- */
- static int
-utf_shift_chars(s, len)
- char *s;
- int len;
-{
- int ulen = 0;
-
- while (*s != '\0' && len > 0)
- {
- if (!IS_CONT(*s))
- len--;
- s++;
- ulen++;
+ if (shift - shifted < width)
+ break;
+ from += len;
+ shifted += width;
+ if (shifted < 0)
+ shifted = 0;
}
- while (IS_CONT(*s))
+ while (from < curr)
{
- s++;
- ulen++;
+ linebuf[to] = linebuf[from];
+ attr[to++] = attr[from++];
}
- return (ulen);
+ curr = to;
+ column -= shifted;
+ cshift += shifted;
}
/*
- * Shift the input line left.
- * This means discarding N printable chars at the start of the buffer.
+ *
*/
- static void
-pshift(shift)
- int shift;
+ public void
+pshift_all()
{
- int i;
- int nchars;
-
- if (shift > column - lmargin)
- shift = column - lmargin;
- if (shift > curr - lmargin)
- shift = curr - lmargin;
-
- if (utf_mode)
- nchars = utf_shift_chars(linebuf + lmargin, shift);
- else
- nchars = shift_chars(linebuf + lmargin, shift);
- if (nchars > curr)
- nchars = curr;
- for (i = 0; i < curr - nchars; i++)
- {
- linebuf[lmargin + i] = linebuf[lmargin + i + nchars];
- attr[lmargin + i] = attr[lmargin + i + nchars];
- }
- curr -= nchars;
- column -= shift;
- cshift += shift;
+ pshift(column);
}
/*
@@ -287,14 +373,20 @@ pshift(shift)
attr_swidth(a)
int a;
{
- switch (a)
- {
- case AT_BOLD: return (bo_s_width);
- case AT_UNDERLINE: return (ul_s_width);
- case AT_BLINK: return (bl_s_width);
- case AT_STANDOUT: return (so_s_width);
- }
- return (0);
+ int w = 0;
+
+ a = apply_at_specials(a);
+
+ if (a & AT_UNDERLINE)
+ w += ul_s_width;
+ if (a & AT_BOLD)
+ w += bo_s_width;
+ if (a & AT_BLINK)
+ w += bl_s_width;
+ if (a & AT_STANDOUT)
+ w += so_s_width;
+
+ return w;
}
/*
@@ -305,14 +397,20 @@ attr_swidth(a)
attr_ewidth(a)
int a;
{
- switch (a)
- {
- case AT_BOLD: return (bo_e_width);
- case AT_UNDERLINE: return (ul_e_width);
- case AT_BLINK: return (bl_e_width);
- case AT_STANDOUT: return (so_e_width);
- }
- return (0);
+ int w = 0;
+
+ a = apply_at_specials(a);
+
+ if (a & AT_UNDERLINE)
+ w += ul_e_width;
+ if (a & AT_BOLD)
+ w += bo_e_width;
+ if (a & AT_BLINK)
+ w += bl_e_width;
+ if (a & AT_STANDOUT)
+ w += so_e_width;
+
+ return w;
}
/*
@@ -322,49 +420,92 @@ attr_ewidth(a)
* attribute sequence to be inserted, so this must be taken into account.
*/
static int
-pwidth(c, a)
- int c;
+pwidth(ch, a, prev_ch)
+ LWCHAR ch;
int a;
+ LWCHAR prev_ch;
{
- register int w;
+ int w;
- if (utf_mode && IS_CONT(c))
- return (0);
-
- if (c == '\b')
+ if (ch == '\b')
/*
- * Backspace moves backwards one position.
+ * Backspace moves backwards one or two positions.
+ * XXX - Incorrect if several '\b' in a row.
*/
- return (-1);
+ return (utf_mode && is_wide_char(prev_ch)) ? -2 : -1;
- if (control_char(c))
- /*
- * Control characters do unpredicatable things,
- * so we don't even try to guess; say it doesn't move.
- * This can only happen if the -r flag is in effect.
- */
- return (0);
+ if (!utf_mode || is_ascii_char(ch))
+ {
+ if (control_char((char)ch))
+ {
+ /*
+ * Control characters do unpredictable things,
+ * so we don't even try to guess; say it doesn't move.
+ * This can only happen if the -r flag is in effect.
+ */
+ return (0);
+ }
+ } else
+ {
+ if (is_composing_char(ch) || is_combining_char(prev_ch, ch))
+ {
+ /*
+ * Composing and combining chars take up no space.
+ *
+ * Some terminals, upon failure to compose a
+ * composing character with the character(s) that
+ * precede(s) it will actually take up one column
+ * for the composing character; there isn't much
+ * we could do short of testing the (complex)
+ * composition process ourselves and printing
+ * a binary representation when it fails.
+ */
+ return (0);
+ }
+ }
/*
- * Other characters take one space,
+ * Other characters take one or two columns,
* plus the width of any attribute enter/exit sequence.
*/
w = 1;
- if (curr > 0 && attr[curr-1] != a)
+ if (is_wide_char(ch))
+ w++;
+ if (curr > 0 && !is_at_equiv(attr[curr-1], a))
w += attr_ewidth(attr[curr-1]);
- if (a && (curr == 0 || attr[curr-1] != a))
+ if ((apply_at_specials(a) != AT_NORMAL) &&
+ (curr == 0 || !is_at_equiv(attr[curr-1], a)))
w += attr_swidth(a);
return (w);
}
/*
- * Delete the previous character in the line buffer.
+ * Delete to the previous base character in the line buffer.
+ * Return 1 if one is found.
*/
- static void
+ static int
backc()
{
- curr--;
- column -= pwidth(linebuf[curr], attr[curr]);
+ LWCHAR prev_ch;
+ char *p = linebuf + curr;
+ LWCHAR ch = step_char(&p, -1, linebuf + lmargin);
+ int width;
+
+ /* This assumes that there is no '\b' in linebuf. */
+ while ( curr > lmargin
+ && column > lmargin
+ && (!(attr[curr - 1] & (AT_ANSI|AT_BINARY))))
+ {
+ curr = p - linebuf;
+ prev_ch = step_char(&p, -1, linebuf + lmargin);
+ width = pwidth(ch, attr[curr], prev_ch);
+ column -= width;
+ if (width > 0)
+ return 1;
+ ch = prev_ch;
+ }
+
+ return 0;
}
/*
@@ -373,17 +514,18 @@ backc()
static int
in_ansi_esc_seq()
{
- int i;
+ char *p;
/*
* Search backwards for either an ESC (which means we ARE in a seq);
* or an end char (which means we're NOT in a seq).
*/
- for (i = curr-1; i >= 0; i--)
+ for (p = &linebuf[curr]; p > linebuf; )
{
- if (linebuf[i] == ESC)
+ LWCHAR ch = step_char(&p, -1, linebuf);
+ if (ch == ESC)
return (1);
- if (is_ansi_end(linebuf[i]))
+ if (!is_ansi_middle(ch))
return (0);
}
return (0);
@@ -393,50 +535,107 @@ in_ansi_esc_seq()
* Is a character the end of an ANSI escape sequence?
*/
public int
-is_ansi_end(c)
- char c;
+is_ansi_end(ch)
+ LWCHAR ch;
{
- return (strchr(end_ansi_chars, c) != NULL);
+ if (!is_ascii_char(ch))
+ return (0);
+ return (strchr(end_ansi_chars, (char) ch) != NULL);
+}
+
+/*
+ *
+ */
+ public int
+is_ansi_middle(ch)
+ LWCHAR ch;
+{
+ if (!is_ascii_char(ch))
+ return (0);
+ if (is_ansi_end(ch))
+ return (0);
+ return (strchr(mid_ansi_chars, (char) ch) != NULL);
}
/*
* Append a character and attribute to the line buffer.
*/
-#define STORE_CHAR(c,a,pos) \
- do { if (store_char((c),(a),(pos))) return (1); else curr++; } while (0)
+#define STORE_CHAR(ch,a,rep,pos) \
+ do { \
+ if (store_char((ch),(a),(rep),(pos))) return (1); \
+ } while (0)
static int
-store_char(c, a, pos)
- int c;
+store_char(ch, a, rep, pos)
+ LWCHAR ch;
int a;
+ char *rep;
POSITION pos;
{
- register int w;
+ int w;
+ int replen;
+ char cs;
+
+ w = (a & (AT_UNDERLINE|AT_BOLD)); /* Pre-use w. */
+ if (w != AT_NORMAL)
+ last_overstrike = w;
- if (a != AT_NORMAL)
- last_overstrike = a;
#if HILITE_SEARCH
- if (is_hilited(pos, pos+1, 0))
{
- /*
- * This character should be highlighted.
- * Override the attribute passed in.
- */
- a = AT_STANDOUT;
- hilites++;
+ int matches;
+ if (is_hilited(pos, pos+1, 0, &matches))
+ {
+ /*
+ * This character should be highlighted.
+ * Override the attribute passed in.
+ */
+ if (a != AT_ANSI)
+ a |= AT_HILITE;
+ }
+ line_matches += matches;
}
#endif
+
if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq())
+ {
+ if (!is_ansi_end(ch) && !is_ansi_middle(ch)) {
+ /* Remove whole unrecognized sequence. */
+ do {
+ --curr;
+ } while (linebuf[curr] != ESC);
+ return 0;
+ }
+ a = AT_ANSI; /* Will force re-AT_'ing around it. */
+ w = 0;
+ }
+ else if (ctldisp == OPT_ONPLUS && ch == ESC)
+ {
+ a = AT_ANSI; /* Will force re-AT_'ing around it. */
w = 0;
+ }
else
- w = pwidth(c, a);
+ {
+ char *p = &linebuf[curr];
+ LWCHAR prev_ch = step_char(&p, -1, linebuf);
+ w = pwidth(ch, a, prev_ch);
+ }
+
if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width)
/*
* Won't fit on screen.
*/
return (1);
- if (curr >= size_linebuf-2)
+ if (rep == NULL)
+ {
+ cs = (char) ch;
+ rep = &cs;
+ replen = 1;
+ } else
+ {
+ replen = utf_len(rep[0]);
+ }
+ if (curr + replen >= size_linebuf-6)
{
/*
* Won't fit in line buffer.
@@ -446,41 +645,12 @@ store_char(c, a, pos)
return (1);
}
- /*
- * Special handling for "magic cookie" terminals.
- * If an attribute enter/exit sequence has a printing width > 0,
- * and the sequence is adjacent to a space, delete the space.
- * We just mark the space as invisible, to avoid having too
- * many spaces deleted.
- * {{ Note that even if the attribute width is > 1, we
- * delete only one space. It's not worth trying to do more.
- * It's hardly worth doing this much. }}
- */
- if (curr > 0 && a != AT_NORMAL &&
- linebuf[curr-1] == ' ' && attr[curr-1] == AT_NORMAL &&
- attr_swidth(a) > 0)
+ while (replen-- > 0)
{
- /*
- * We are about to append an enter-attribute sequence
- * just after a space. Delete the space.
- */
- attr[curr-1] = AT_INVIS;
- column--;
- } else if (curr > 0 && attr[curr-1] != AT_NORMAL &&
- attr[curr-1] != AT_INVIS && c == ' ' && a == AT_NORMAL &&
- attr_ewidth(attr[curr-1]) > 0)
- {
- /*
- * We are about to append a space just after an
- * exit-attribute sequence. Delete the space.
- */
- a = AT_INVIS;
- column--;
+ linebuf[curr] = *rep++;
+ attr[curr] = a;
+ curr++;
}
- /* End of magic cookie handling. */
-
- linebuf[curr] = c;
- attr[curr] = a;
column += w;
return (0);
}
@@ -511,12 +681,57 @@ store_tab(attr, pos)
to_tab = tabstops[i+1] - to_tab;
}
+ if (column + to_tab - 1 + pwidth(' ', attr, 0) + attr_ewidth(attr) > sc_width)
+ return 1;
+
do {
- STORE_CHAR(' ', attr, pos);
+ STORE_CHAR(' ', attr, " ", pos);
} while (--to_tab > 0);
return 0;
}
+#define STORE_PRCHAR(c, pos) \
+ do { if (store_prchar((c), (pos))) return 1; } while (0)
+
+ static int
+store_prchar(c, pos)
+ char c;
+ POSITION pos;
+{
+ char *s;
+
+ /*
+ * Convert to printable representation.
+ */
+ s = prchar(c);
+
+ /*
+ * Make sure we can get the entire representation
+ * of the character on this line.
+ */
+ if (column + (int) strlen(s) - 1 +
+ pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width)
+ return 1;
+
+ for ( ; *s != 0; s++)
+ STORE_CHAR(*s, AT_BINARY, NULL, pos);
+
+ return 0;
+}
+
+ static int
+flush_mbc_buf(pos)
+ POSITION pos;
+{
+ int i;
+
+ for (i = 0; i < mbc_buf_index; i++)
+ if (store_prchar(mbc_buf[i], pos))
+ return mbc_buf_index - i;
+
+ return 0;
+}
+
/*
* Append a character to the line buffer.
* Expand tabs into spaces, handle underlining, boldfacing, etc.
@@ -524,14 +739,14 @@ store_tab(attr, pos)
*/
public int
pappend(c, pos)
- register int c;
+ char c;
POSITION pos;
{
int r;
if (pendc)
{
- if (do_append(pendc, pendpos))
+ if (do_append(pendc, NULL, pendpos))
/*
* Oops. We've probably lost the char which
* was in pendc, since caller won't back up.
@@ -542,6 +757,16 @@ pappend(c, pos)
if (c == '\r' && bs_mode == BS_SPECIAL)
{
+ if (mbc_buf_len > 0) /* utf_mode must be on. */
+ {
+ /* Flush incomplete (truncated) sequence. */
+ r = flush_mbc_buf(mbc_pos);
+ mbc_buf_index = r + 1;
+ mbc_buf_len = 0;
+ if (r)
+ return (mbc_buf_index);
+ }
+
/*
* Don't put the CR into the buffer until we see
* the next char. If the next char is a newline,
@@ -552,7 +777,50 @@ pappend(c, pos)
return (0);
}
- r = do_append(c, pos);
+ if (!utf_mode)
+ {
+ r = do_append((LWCHAR) c, NULL, pos);
+ } else
+ {
+ /* Perform strict validation in all possible cases. */
+ if (mbc_buf_len == 0)
+ {
+ retry:
+ mbc_buf_index = 1;
+ *mbc_buf = c;
+ if (IS_ASCII_OCTET(c))
+ r = do_append((LWCHAR) c, NULL, pos);
+ else if (IS_UTF8_LEAD(c))
+ {
+ mbc_buf_len = utf_len(c);
+ mbc_pos = pos;
+ return (0);
+ } else
+ /* UTF8_INVALID or stray UTF8_TRAIL */
+ r = flush_mbc_buf(pos);
+ } else if (IS_UTF8_TRAIL(c))
+ {
+ mbc_buf[mbc_buf_index++] = c;
+ if (mbc_buf_index < mbc_buf_len)
+ return (0);
+ if (is_utf8_well_formed(mbc_buf))
+ r = do_append(get_wchar(mbc_buf), mbc_buf, mbc_pos);
+ else
+ /* Complete, but not shortest form, sequence. */
+ mbc_buf_index = r = flush_mbc_buf(mbc_pos);
+ mbc_buf_len = 0;
+ } else
+ {
+ /* Flush incomplete (truncated) sequence. */
+ r = flush_mbc_buf(mbc_pos);
+ mbc_buf_index = r + 1;
+ mbc_buf_len = 0;
+ /* Handle new char. */
+ if (!r)
+ goto retry;
+ }
+ }
+
/*
* If we need to shift the line, do it.
* But wait until we get to at least the middle of the screen,
@@ -564,42 +832,48 @@ pappend(c, pos)
linebuf[curr] = '\0';
pshift(hshift - cshift);
}
+ if (r)
+ {
+ /* How many chars should caller back up? */
+ r = (!utf_mode) ? 1 : mbc_buf_index;
+ }
return (r);
}
-#define IS_UTF8_4BYTE(c) ( ((c) & 0xf8) == 0xf0 )
-#define IS_UTF8_3BYTE(c) ( ((c) & 0xf0) == 0xe0 )
-#define IS_UTF8_2BYTE(c) ( ((c) & 0xe0) == 0xc0 )
-#define IS_UTF8_TRAIL(c) ( ((c) & 0xc0) == 0x80 )
-
static int
-do_append(c, pos)
- int c;
+do_append(ch, rep, pos)
+ LWCHAR ch;
+ char *rep;
POSITION pos;
{
- register char *s;
register int a;
+ LWCHAR prev_ch;
-#define STOREC(c,a) \
- if ((c) == '\t') STORE_TAB((a),pos); else STORE_CHAR((c),(a),pos)
+ a = AT_NORMAL;
- if (c == '\b')
+ if (ch == '\b')
{
- switch (bs_mode)
- {
- case BS_NORMAL:
- STORE_CHAR(c, AT_NORMAL, pos);
- break;
- case BS_CONTROL:
+ if (bs_mode == BS_CONTROL)
goto do_control_char;
- case BS_SPECIAL:
- if (curr == 0)
- break;
- backc();
- overstrike = 1;
- break;
- }
- } else if (overstrike)
+
+ /*
+ * A better test is needed here so we don't
+ * backspace over part of the printed
+ * representation of a binary character.
+ */
+ if ( curr <= lmargin
+ || column <= lmargin
+ || (attr[curr - 1] & (AT_ANSI|AT_BINARY)))
+ STORE_PRCHAR('\b', pos);
+ else if (bs_mode == BS_NORMAL)
+ STORE_CHAR(ch, AT_NORMAL, NULL, pos);
+ else if (bs_mode == BS_SPECIAL)
+ overstrike = backc();
+
+ return 0;
+ }
+
+ if (overstrike > 0)
{
/*
* Overstrike the character at the current position
@@ -608,29 +882,11 @@ do_append(c, pos)
* bold (if an identical character is overstruck),
* or just deletion of the character in the buffer.
*/
- overstrike--;
- if (utf_mode && IS_UTF8_4BYTE(c) && curr > 2 && (char)c == linebuf[curr-3])
- {
- backc();
- backc();
- backc();
- STORE_CHAR(linebuf[curr], AT_BOLD, pos);
- overstrike = 3;
- } else if (utf_mode && (IS_UTF8_3BYTE(c) || (overstrike==2 && IS_UTF8_TRAIL(c))) && curr > 1 && (char)c == linebuf[curr-2])
- {
- backc();
- backc();
- STORE_CHAR(linebuf[curr], AT_BOLD, pos);
- overstrike = 2;
- } else if (utf_mode && curr > 0 && (IS_UTF8_2BYTE(c) || (overstrike==1 && IS_UTF8_TRAIL(c))) && (char)c == linebuf[curr-1])
- {
- backc();
- STORE_CHAR(linebuf[curr], AT_BOLD, pos);
- overstrike = 1;
- } else if (utf_mode && curr > 0 && IS_UTF8_TRAIL(c) && attr[curr-1] == AT_UNDERLINE)
- {
- STOREC(c, AT_UNDERLINE);
- } else if ((char)c == linebuf[curr])
+ overstrike = utf_mode ? -1 : 0;
+ /* To be correct, this must be a base character. */
+ prev_ch = get_wchar(linebuf + curr);
+ a = attr[curr];
+ if (ch == prev_ch)
{
/*
* Overstriking a char with itself means make it bold.
@@ -639,40 +895,37 @@ do_append(c, pos)
* it could mean make it underlined.
* Use the previous overstrike to resolve it.
*/
- if (c == '_' && last_overstrike != AT_NORMAL)
- STOREC(c, last_overstrike);
- else
- STOREC(c, AT_BOLD);
- } else if (c == '_')
- {
- if (utf_mode)
+ if (ch == '_')
{
- int i;
- for (i = 0; i < 5; i++)
- {
- if (curr <= i || !IS_CONT(linebuf[curr-i]))
- break;
- attr[curr-i-1] = AT_UNDERLINE;
- }
- }
- STOREC(linebuf[curr], AT_UNDERLINE);
- } else if (linebuf[curr] == '_')
+ if ((a & (AT_BOLD|AT_UNDERLINE)) != AT_NORMAL)
+ a |= (AT_BOLD|AT_UNDERLINE);
+ else if (last_overstrike != AT_NORMAL)
+ a |= last_overstrike;
+ else
+ a |= AT_BOLD;
+ } else
+ a |= AT_BOLD;
+ } else if (ch == '_')
{
- if (utf_mode)
- {
- if (IS_UTF8_2BYTE(c))
- overstrike = 1;
- else if (IS_UTF8_3BYTE(c))
- overstrike = 2;
- else if (IS_UTF8_4BYTE(c))
- overstrike = 3;
- }
- STOREC(c, AT_UNDERLINE);
- } else if (control_char(c))
- goto do_control_char;
+ a |= AT_UNDERLINE;
+ ch = prev_ch;
+ rep = linebuf + curr;
+ } else if (prev_ch == '_')
+ {
+ a |= AT_UNDERLINE;
+ }
+ /* Else we replace prev_ch, but we keep its attributes. */
+ } else if (overstrike < 0)
+ {
+ if ( is_composing_char(ch)
+ || is_combining_char(get_wchar(linebuf + curr), ch))
+ /* Continuation of the same overstrike. */
+ a = last_overstrike;
else
- STOREC(c, AT_NORMAL);
- } else if (c == '\t')
+ overstrike = 0;
+ }
+
+ if (ch == '\t')
{
/*
* Expand a tab into spaces.
@@ -683,43 +936,56 @@ do_append(c, pos)
goto do_control_char;
case BS_NORMAL:
case BS_SPECIAL:
- STORE_TAB(AT_NORMAL, pos);
+ STORE_TAB(a, pos);
break;
}
- } else if (control_char(c))
+ } else if ((!utf_mode || is_ascii_char(ch)) && control_char((char)ch))
{
do_control_char:
- if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && c == ESC))
+ if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && ch == ESC))
{
/*
* Output as a normal character.
*/
- STORE_CHAR(c, AT_NORMAL, pos);
+ STORE_CHAR(ch, AT_NORMAL, rep, pos);
} else
{
- /*
- * Convert to printable representation.
- */
- s = prchar(c);
- a = binattr;
+ STORE_PRCHAR((char) ch, pos);
+ }
+ } else if (utf_mode && ctldisp != OPT_ON && is_ubin_char(ch))
+ {
+ char *s;
- /*
- * Make sure we can get the entire representation
- * of the character on this line.
- */
- if (column + (int) strlen(s) +
- attr_swidth(a) + attr_ewidth(a) > sc_width)
- return (1);
+ s = prutfchar(ch);
- for ( ; *s != 0; s++)
- STORE_CHAR(*s, a, pos);
- }
- } else
+ if (column + (int) strlen(s) - 1 +
+ pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width)
+ return (1);
+
+ for ( ; *s != 0; s++)
+ STORE_CHAR(*s, AT_BINARY, NULL, pos);
+ } else
{
- STOREC(c, AT_NORMAL);
+ STORE_CHAR(ch, a, rep, pos);
}
+ return (0);
+}
- return (0);
+/*
+ *
+ */
+ public int
+pflushmbc()
+{
+ int r = 0;
+
+ if (mbc_buf_len > 0)
+ {
+ /* Flush incomplete (truncated) sequence. */
+ r = flush_mbc_buf(mbc_pos);
+ mbc_buf_len = 0;
+ }
+ return r;
}
/*
@@ -729,13 +995,15 @@ do_append(c, pos)
pdone(endline)
int endline;
{
+ (void) pflushmbc();
+
if (pendc && (pendc != '\r' || !endline))
/*
* If we had a pending character, put it in the buffer.
* But discard a pending CR if we are at end of line
* (that is, discard the CR in a CR/LF sequence).
*/
- (void) do_append(pendc, pendpos);
+ (void) do_append(pendc, NULL, pendpos);
/*
* Make sure we've shifted the line, if we need to.
@@ -743,6 +1011,17 @@ pdone(endline)
if (cshift < hshift)
pshift(hshift - cshift);
+ if (ctldisp == OPT_ONPLUS && is_ansi_end('m'))
+ {
+ /* Switch to normal attribute at end of line. */
+ char *p = "\033[m";
+ for ( ; *p != '\0'; p++)
+ {
+ linebuf[curr] = *p;
+ attr[curr++] = AT_ANSI;
+ }
+ }
+
/*
* Add a newline if necessary,
* and append a '\0' to the end of the line.
@@ -757,17 +1036,12 @@ pdone(endline)
attr[curr] = AT_NORMAL;
#if HILITE_SEARCH
- if (status_col && hilites > 0)
+ if (status_col && line_matches > 0)
{
linebuf[0] = '*';
- attr[0] = AT_STANDOUT;
+ attr[0] = AT_NORMAL|AT_HILITE;
}
#endif
- /*
- * If we are done with this line, reset the current shift.
- */
- if (endline)
- cshift = 0;
}
/*
@@ -780,21 +1054,28 @@ gline(i, ap)
register int i;
register int *ap;
{
- char *s;
-
if (is_null_line)
{
/*
* If there is no current line, we pretend the line is
* either "~" or "", depending on the "twiddle" flag.
*/
- *ap = AT_BOLD;
- s = (twiddle) ? "~\n" : "\n";
- return (s[i]);
+ if (twiddle)
+ {
+ if (i == 0)
+ {
+ *ap = AT_BOLD;
+ return '~';
+ }
+ --i;
+ }
+ /* Make sure we're back to AT_NORMAL before the '\n'. */
+ *ap = AT_NORMAL;
+ return i ? '\0' : '\n';
}
*ap = attr[i];
- return (linebuf[i] & 0377);
+ return (linebuf[i] & 0xFF);
}
/*
@@ -828,7 +1109,7 @@ forw_raw_line(curr_pos, linep)
n = 0;
for (;;)
{
- if (c == '\n' || c == EOI)
+ if (c == '\n' || c == EOI || ABORT_SIGS())
{
new_pos = ch_tell();
break;
@@ -876,7 +1157,7 @@ back_raw_line(curr_pos, linep)
for (;;)
{
c = ch_back_get();
- if (c == '\n')
+ if (c == '\n' || ABORT_SIGS())
{
/*
* This is the newline ending the previous line.
diff --git a/contrib/less/main.c b/contrib/less/main.c
index 18353db..c7dbdb8 100644
--- a/contrib/less/main.c
+++ b/contrib/less/main.c
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2004 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.
@@ -120,6 +120,7 @@ main(argc, argv)
init_prompt();
init_charset();
init_line();
+ init_cmdhist();
init_option();
if (more_mode) {
@@ -350,14 +351,14 @@ sprefix(ps, s, uppercase)
c = *ps;
if (uppercase)
{
- if (len == 0 && SIMPLE_IS_LOWER(c))
+ if (len == 0 && ASCII_IS_LOWER(c))
return (-1);
- if (SIMPLE_IS_UPPER(c))
- c = SIMPLE_TO_LOWER(c);
+ if (ASCII_IS_UPPER(c))
+ c = ASCII_TO_LOWER(c);
}
sc = *s;
- if (len > 0 && SIMPLE_IS_UPPER(sc))
- sc = SIMPLE_TO_LOWER(sc);
+ if (len > 0 && ASCII_IS_UPPER(sc))
+ sc = ASCII_TO_LOWER(sc);
if (c != sc)
break;
len++;
@@ -384,6 +385,7 @@ quit(status)
save_status = status;
quitting = 1;
edit((char*)NULL);
+ save_cmdhist();
if (any_display && is_tty)
clear_bot();
deinit();
diff --git a/contrib/less/prompt.c b/contrib/less/prompt.c
index c745603b..7e22f99 100644
--- a/contrib/less/prompt.c
+++ b/contrib/less/prompt.c
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2004 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.
@@ -165,7 +165,7 @@ curr_byte(where)
POSITION pos;
pos = position(where);
- while (pos == NULL_POSITION && where >= 0 && where < sc_height)
+ while (pos == NULL_POSITION && where >= 0 && where < sc_height-1)
pos = position(++where);
if (pos == NULL_POSITION)
pos = ch_length();
@@ -201,7 +201,7 @@ cond(c, where)
case 'd': /* Same as l */
return (linenums);
case 'L': /* Final line number known? */
- case 'D': /* Same as L */
+ case 'D': /* Final page number known? */
return (linenums && ch_length() != NULL_POSITION);
case 'm': /* More than one file? */
#if TAGS
@@ -255,6 +255,9 @@ protochar(c, where, iseditproto)
LINENUM last_linenum;
IFILE h;
+#undef PAGE_NUM
+#define PAGE_NUM(linenum) ((((linenum) - 1) / (sc_height - 1)) + 1)
+
switch (c)
{
case 'b': /* Current byte offset */
@@ -270,17 +273,26 @@ protochar(c, where, iseditproto)
case 'd': /* Current page number */
linenum = currline(where);
if (linenum > 0 && sc_height > 1)
- ap_linenum(((linenum - 1) / (sc_height - 1)) + 1);
+ ap_linenum(PAGE_NUM(linenum));
else
ap_quest();
break;
- case 'D': /* Last page number */
+ case 'D': /* Final page number */
+ /* Find the page number of the last byte in the file (len-1). */
len = ch_length();
- if (len == NULL_POSITION || len == ch_zero() ||
- (linenum = find_linenum(len)) <= 0)
+ if (len == NULL_POSITION)
ap_quest();
+ else if (len == 0)
+ /* An empty file has no pages. */
+ ap_linenum(0);
else
- ap_linenum(((linenum - 1) / (sc_height - 1)) + 1);
+ {
+ linenum = find_linenum(len - 1);
+ if (linenum <= 0)
+ ap_quest();
+ else
+ ap_linenum(PAGE_NUM(linenum));
+ }
break;
#if EDITOR
case 'E': /* Editor name */
@@ -519,7 +531,7 @@ pr_expand(proto, maxwidth)
}
if (mp == message)
- return (NULL);
+ return ("");
if (maxwidth > 0 && mp >= message + maxwidth)
{
/*
diff --git a/contrib/less/screen.c b/contrib/less/screen.c
index df478fb..03960c7 100644
--- a/contrib/less/screen.c
+++ b/contrib/less/screen.c
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2005 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.
@@ -39,11 +39,12 @@ extern int fd0;
#else
-#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
-#include <termios.h>
-#if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ)
+#if HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
+
+#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
+#include <termios.h>
#else
#if HAVE_TERMIO_H
#include <termio.h>
@@ -53,9 +54,6 @@ extern int fd0;
#else
#include <sgtty.h>
#endif
-#if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD))
-#include <sys/ioctl.h>
-#endif
#endif
#endif
@@ -190,7 +188,9 @@ 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, kill_char; /* The user's erase and line-kill chars */
+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 */
@@ -203,6 +203,7 @@ public int clear_bg; /* Clear fills with background color */
public int missing_cap = 0; /* Some capability is missing */
static int attrmode = AT_NORMAL;
+extern int binattr;
#if !MSDOS_COMPILER
static char *cheaper();
@@ -233,6 +234,7 @@ extern int sigs;
extern int wscroll;
extern int screen_trashed;
extern int tty;
+extern int top_scroll;
#if HILITE_SEARCH
extern int hilite_search;
#endif
@@ -260,6 +262,7 @@ raw_mode(on)
if (on == curr_on)
return;
+ erase2_char = '\b'; /* in case OS doesn't know about erase2 */
#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS
{
struct termios s;
@@ -342,6 +345,9 @@ raw_mode(on)
}
#endif
erase_char = s.c_cc[VERASE];
+#ifdef VERASE2
+ erase2_char = s.c_cc[VERASE2];
+#endif
kill_char = s.c_cc[VKILL];
#ifdef VWERASE
werase_char = s.c_cc[VWERASE];
@@ -1212,7 +1218,7 @@ get_term()
if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0'))
{
missing_cap = 1;
- sc_eol_clear = "";
+ sc_eos_clear = "";
}
sc_clear = ltgetstr("cl", &sp);
@@ -1516,6 +1522,19 @@ init()
tputs(sc_init, sc_height, putchr);
if (!no_keypad)
tputs(sc_s_keypad, sc_height, putchr);
+ if (top_scroll)
+ {
+ int i;
+
+ /*
+ * This is nice to terminals with no alternate screen,
+ * but with saved scrolled-off-the-top lines. This way,
+ * no previous line is lost, but we start with a whole
+ * screen to ourself.
+ */
+ for (i = 1; i < sc_height; i++)
+ putchr('\n');
+ }
#else
#if MSDOS_COMPILER==WIN32C
if (!no_init)
@@ -1857,12 +1876,12 @@ create_flash()
videopages = w.numvideopages;
if (videopages < 2)
{
- so_enter();
- so_exit();
+ at_enter(AT_STANDOUT);
+ at_exit();
} else
{
_setactivepage(1);
- so_enter();
+ at_enter(AT_STANDOUT);
blanks = (char *) ecalloc(w.numtextcols, sizeof(char));
for (col = 0; col < w.numtextcols; col++)
blanks[col] = ' ';
@@ -1871,7 +1890,7 @@ create_flash()
_setactivepage(0);
_setvisualpage(0);
free(blanks);
- so_exit();
+ at_exit();
}
#else
#if MSDOS_COMPILER==BORLANDC
@@ -2101,153 +2120,111 @@ clear_bot()
* cleared area with the current attribute.
*/
lower_left();
- switch (attrmode)
- {
- case AT_STANDOUT:
- so_exit();
- clear_eol_bot();
- so_enter();
- break;
- case AT_UNDERLINE:
- ul_exit();
- clear_eol_bot();
- ul_enter();
- break;
- case AT_BOLD:
- bo_exit();
- clear_eol_bot();
- bo_enter();
- break;
- case AT_BLINK:
- bl_exit();
+ if (attrmode == AT_NORMAL)
clear_eol_bot();
- bl_enter();
- break;
- default:
+ else
+ {
+ int saved_attrmode = attrmode;
+
+ at_exit();
clear_eol_bot();
- break;
+ at_enter(saved_attrmode);
}
}
-/*
- * Begin "standout" (bold, underline, or whatever).
- */
public void
-so_enter()
+at_enter(attr)
+ int attr;
{
-#if !MSDOS_COMPILER
- tputs(sc_s_in, 1, putchr);
-#else
- flush();
- SETCOLORS(so_fg_color, so_bg_color);
-#endif
- attrmode = AT_STANDOUT;
-}
+ attr = apply_at_specials(attr);
-/*
- * End "standout".
- */
- public void
-so_exit()
-{
#if !MSDOS_COMPILER
- tputs(sc_s_out, 1, putchr);
+ /* 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);
#else
flush();
- SETCOLORS(nm_fg_color, nm_bg_color);
+ /* The one with the most priority is first. */
+ 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)
+ {
+ SETCOLORS(bo_fg_color, bo_bg_color);
+ }
+ else if (attr & AT_UNDERLINE)
+ {
+ SETCOLORS(ul_fg_color, ul_bg_color);
+ }
#endif
- attrmode = AT_NORMAL;
-}
-/*
- * Begin "underline" (hopefully real underlining,
- * otherwise whatever the terminal provides).
- */
- public void
-ul_enter()
-{
-#if !MSDOS_COMPILER
- tputs(sc_u_in, 1, putchr);
-#else
- flush();
- SETCOLORS(ul_fg_color, ul_bg_color);
-#endif
- attrmode = AT_UNDERLINE;
+ attrmode = attr;
}
-/*
- * End "underline".
- */
public void
-ul_exit()
+at_exit()
{
#if !MSDOS_COMPILER
- tputs(sc_u_out, 1, putchr);
+ /* 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);
#else
flush();
SETCOLORS(nm_fg_color, nm_bg_color);
#endif
+
attrmode = AT_NORMAL;
}
-/*
- * Begin "bold"
- */
public void
-bo_enter()
+at_switch(attr)
+ int attr;
{
-#if !MSDOS_COMPILER
- tputs(sc_b_in, 1, putchr);
-#else
- flush();
- SETCOLORS(bo_fg_color, bo_bg_color);
-#endif
- attrmode = AT_BOLD;
+ if (apply_at_specials(attr) != attrmode)
+ {
+ at_exit();
+ at_enter(attr);
+ }
}
-/*
- * End "bold".
- */
- public void
-bo_exit()
+ public int
+is_at_equiv(attr1, attr2)
+ int attr1;
+ int attr2;
{
-#if !MSDOS_COMPILER
- tputs(sc_b_out, 1, putchr);
-#else
- flush();
- SETCOLORS(nm_fg_color, nm_bg_color);
-#endif
- attrmode = AT_NORMAL;
-}
+ attr1 = apply_at_specials(attr1);
+ attr2 = apply_at_specials(attr2);
-/*
- * Begin "blink"
- */
- public void
-bl_enter()
-{
-#if !MSDOS_COMPILER
- tputs(sc_bl_in, 1, putchr);
-#else
- flush();
- SETCOLORS(bl_fg_color, bl_bg_color);
-#endif
- attrmode = AT_BLINK;
+ return (attr1 == attr2);
}
-/*
- * End "blink".
- */
- public void
-bl_exit()
+ public int
+apply_at_specials(attr)
+ int attr;
{
-#if !MSDOS_COMPILER
- tputs(sc_bl_out, 1, putchr);
-#else
- flush();
- SETCOLORS(nm_fg_color, nm_bg_color);
-#endif
- attrmode = AT_NORMAL;
+ if (attr & AT_BINARY)
+ attr |= binattr;
+ if (attr & AT_HILITE)
+ attr |= AT_STANDOUT;
+ attr &= ~(AT_BINARY|AT_HILITE);
+
+ return attr;
}
#if 0 /* No longer used */
diff --git a/contrib/less/search.c b/contrib/less/search.c
index 1645a55..63e5875 100644
--- a/contrib/less/search.c
+++ b/contrib/less/search.c
@@ -1,6 +1,6 @@
/* $FreeBSD$ */
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2005 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.
@@ -122,9 +122,9 @@ cvt_text(odst, osrc, ops)
for (src = osrc, dst = odst; *src != '\0'; src++)
{
- if ((ops & CVT_TO_LC) && isupper((unsigned char) *src))
+ if ((ops & CVT_TO_LC) && IS_UPPER(*src))
/* Convert uppercase to lowercase. */
- *dst++ = tolower((unsigned char) *src);
+ *dst++ = TO_LOWER(*src);
else if ((ops & CVT_BS) && *src == '\b' && dst > odst)
/* Delete BS and preceding char. */
dst--;
@@ -132,7 +132,7 @@ cvt_text(odst, osrc, ops)
{
/* Skip to end of ANSI escape sequence. */
while (src[1] != '\0')
- if (is_ansi_end(*++src))
+ if (!is_ansi_middle(*++src))
break;
} else
/* Just copy. */
@@ -177,7 +177,7 @@ is_ucase(s)
register char *p;
for (p = s; *p != '\0'; p++)
- if (isupper((unsigned char) *p))
+ if (IS_UPPER(*p))
return (1);
return (0);
}
@@ -249,11 +249,18 @@ repaint_hilite(on)
if (pos == NULL_POSITION)
continue;
epos = position(slinenum+1);
+#if 0
/*
* If any character in the line is highlighted,
* repaint the line.
+ *
+ * {{ This doesn't work -- if line is drawn with highlights
+ * which should be erased (e.g. toggle -i with status column),
+ * we must redraw the line even if it has no highlights.
+ * For now, just repaint every line. }}
*/
- if (is_hilited(pos, epos, 1))
+ if (is_hilited(pos, epos, 1, NULL))
+#endif
{
(void) forw_line(pos);
goto_line(slinenum);
@@ -534,15 +541,41 @@ clr_hilite()
/*
* Should any characters in a specified range be highlighted?
+ */
+ static int
+is_hilited_range(pos, epos)
+ POSITION pos;
+ POSITION epos;
+{
+ struct hilite *hl;
+
+ /*
+ * Look at each highlight and see if any part of it falls in the range.
+ */
+ for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next)
+ {
+ if (hl->hl_endpos > pos &&
+ (epos == NULL_POSITION || epos > hl->hl_startpos))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Should any characters in a specified range be highlighted?
* If nohide is nonzero, don't consider hide_hilite.
*/
public int
-is_hilited(pos, epos, nohide)
+is_hilited(pos, epos, nohide, p_matches)
POSITION pos;
POSITION epos;
int nohide;
+ int *p_matches;
{
- struct hilite *hl;
+ int match;
+
+ if (p_matches != NULL)
+ *p_matches = 0;
if (!status_col &&
start_attnpos != NULL_POSITION &&
@@ -553,6 +586,16 @@ is_hilited(pos, epos, nohide)
*/
return (1);
+ match = is_hilited_range(pos, epos);
+ if (!match)
+ return (0);
+
+ if (p_matches != NULL)
+ /*
+ * Report matches, even if we're hiding highlights.
+ */
+ *p_matches = 1;
+
if (hilite_search == 0)
/*
* Not doing highlighting.
@@ -565,16 +608,7 @@ is_hilited(pos, epos, nohide)
*/
return (0);
- /*
- * Look at each highlight and see if any part of it falls in the range.
- */
- for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next)
- {
- if (hl->hl_endpos > pos &&
- (epos == NULL_POSITION || epos > hl->hl_startpos))
- return (1);
- }
- return (0);
+ return (1);
}
/*
@@ -617,6 +651,30 @@ add_hilite(anchor, hl)
ihl->hl_next = hl;
}
+ static void
+adj_hilite_ansi(cvt_ops, line, npos)
+ int cvt_ops;
+ char **line;
+ POSITION *npos;
+{
+ if (cvt_ops & CVT_ANSI)
+ while (**line == ESC)
+ {
+ /*
+ * Found an ESC. The file position moves
+ * forward past the entire ANSI escape sequence.
+ */
+ (*line)++;
+ (*npos)++;
+ while (**line != '\0')
+ {
+ (*npos)++;
+ if (!is_ansi_middle(*(*line)++))
+ break;
+ }
+ }
+}
+
/*
* Adjust hl_startpos & hl_endpos to account for backspace processing.
*/
@@ -666,38 +724,30 @@ adj_hilite(anchor, linepos, cvt_ops)
}
if (*line == '\0')
break;
- if (cvt_ops & CVT_ANSI)
- {
- while (line[0] == ESC)
- {
- /*
- * Found an ESC. The file position moves
- * forward past the entire ANSI escape sequence.
- */
- line++;
- npos++;
- while (*line != '\0')
- {
- npos++;
- if (is_ansi_end(*line++))
- break;
- }
- }
- }
+ adj_hilite_ansi(cvt_ops, &line, &npos);
opos++;
npos++;
line++;
if (cvt_ops & CVT_BS)
{
- while (line[0] == '\b' && line[1] != '\0')
+ while (*line == '\b')
{
+ npos++;
+ line++;
+ adj_hilite_ansi(cvt_ops, &line, &npos);
+ if (*line == '\0')
+ {
+ --npos;
+ --line;
+ break;
+ }
/*
* Found a backspace. The file position moves
* forward by 2 relative to the processed line
* which was searched in hilite_line.
*/
- npos += 2;
- line += 2;
+ npos++;
+ line++;
}
}
}
@@ -1043,7 +1093,7 @@ search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
* Return it.
*/
#if HILITE_SEARCH
- if (hilite_search == 1)
+ if (hilite_search == OPT_ON)
{
/*
* Clear the hilite list and add only
diff --git a/contrib/less/signal.c b/contrib/less/signal.c
index c32e7a1..8b0691f 100644
--- a/contrib/less/signal.c
+++ b/contrib/less/signal.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 1984-2002 Mark Nudelman
+ * Copyright (C) 1984-2004 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.
@@ -34,6 +34,7 @@ extern int lnloop;
extern int linenums;
extern int wscroll;
extern int reading;
+extern int quit_on_intr;
extern int more_mode;
/*
@@ -251,6 +252,8 @@ psignals()
#endif
if (tsignals & S_INTERRUPT)
{
+ if (quit_on_intr)
+ quit(QUIT_OK);
bell();
/*
* {{ You may wish to replace the bell() with
OpenPOWER on IntegriCloud