aboutsummaryrefslogtreecommitdiff
path: root/contrib/less/line.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/less/line.c')
-rw-r--r--contrib/less/line.c869
1 files changed, 575 insertions, 294 deletions
diff --git a/contrib/less/line.c b/contrib/less/line.c
index 14659f399c1f..0c4943e20904 100644
--- a/contrib/less/line.c
+++ b/contrib/less/line.c
@@ -1,5 +1,5 @@
/*
- * 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.
@@ -16,14 +16,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 */
@@ -36,13 +35,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;
@@ -59,6 +62,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.
*/
@@ -68,6 +76,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;
@@ -76,12 +89,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)
@@ -90,10 +111,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;
@@ -101,6 +135,16 @@ expand_linebuf()
}
/*
+ * Is a character ASCII?
+ */
+ public int
+is_ascii_char(ch)
+ LWCHAR ch;
+{
+ return (ch <= 0x7F);
+}
+
+/*
* Rewind the line buffer.
*/
public void
@@ -108,14 +152,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
}
@@ -150,9 +197,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++;
}
@@ -190,92 +237,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);
}
/*
@@ -286,14 +372,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;
}
/*
@@ -304,14 +396,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;
}
/*
@@ -321,49 +419,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;
}
/*
@@ -372,17 +513,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);
@@ -392,50 +534,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.
@@ -445,41 +644,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);
}
@@ -510,12 +680,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.
@@ -523,14 +738,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.
@@ -541,6 +756,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,
@@ -551,7 +776,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,
@@ -563,42 +831,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
@@ -607,29 +881,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.
@@ -638,40 +894,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.
@@ -682,43 +935,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;
}
/*
@@ -728,13 +994,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.
@@ -742,6 +1010,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.
@@ -756,17 +1035,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;
}
/*
@@ -779,21 +1053,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);
}
/*
@@ -827,7 +1108,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;
@@ -875,7 +1156,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.
@@ -911,8 +1192,8 @@ back_raw_line(curr_pos, linep)
/*
* Shift the data to the end of the new linebuf.
*/
- for (fm = linebuf + old_size_linebuf,
- to = linebuf + size_linebuf;
+ for (fm = linebuf + old_size_linebuf - 1,
+ to = linebuf + size_linebuf - 1;
fm >= linebuf; fm--, to--)
*to = *fm;
n = size_linebuf - old_size_linebuf;