summaryrefslogtreecommitdiffstats
path: root/contrib/less/line.c
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2002-01-07 20:29:38 +0000
committerps <ps@FreeBSD.org>2002-01-07 20:29:38 +0000
commitc0c85bc41cb6c023adae56cf0a7e3495bd528cb2 (patch)
tree22ed5b4269586d3d5c21d37a27645897709341e3 /contrib/less/line.c
parent5d465776b9e058088e1f29636cf7cdcb0c13eb0d (diff)
downloadFreeBSD-src-c0c85bc41cb6c023adae56cf0a7e3495bd528cb2.zip
FreeBSD-src-c0c85bc41cb6c023adae56cf0a7e3495bd528cb2.tar.gz
Import less v371
Diffstat (limited to 'contrib/less/line.c')
-rw-r--r--contrib/less/line.c292
1 files changed, 227 insertions, 65 deletions
diff --git a/contrib/less/line.c b/contrib/less/line.c
index 6781a2c..981d84e 100644
--- a/contrib/less/line.c
+++ b/contrib/less/line.c
@@ -20,20 +20,23 @@
#define IS_CONT(c) (((c) & 0xC0) == 0x80)
#define LINENUM_WIDTH 8 /* Chars to use for line number */
-/* Buffer which holds the current output line */
-public char linebuf[LINEBUF_SIZE];
-public int size_linebuf = sizeof(linebuf);
+public 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 */
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 */
+public int tabdefault = 8; /* Default repeated tabstops */
-static char attr[LINEBUF_SIZE]; /* Extension of linebuf to hold attributes */
static int curr; /* Index into linebuf */
static int column; /* Printable length, accounting for
backspaces, etc. */
static int overstrike; /* Next char should overstrike previous char */
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 char pendc;
static POSITION pendpos;
static char *end_ansi_chars;
@@ -41,7 +44,6 @@ static char *end_ansi_chars;
static int do_append();
extern int bs_mode;
-extern int tabstop;
extern int linenums;
extern int ctldisp;
extern int twiddle;
@@ -66,6 +68,34 @@ init_line()
end_ansi_chars = lgetenv("LESSANSIENDCHARS");
if (end_ansi_chars == NULL || *end_ansi_chars == '\0')
end_ansi_chars = "m";
+ linebuf = (char *) ecalloc(LINEBUF_SIZE, sizeof(char));
+ attr = (char *) ecalloc(LINEBUF_SIZE, sizeof(char));
+ size_linebuf = LINEBUF_SIZE;
+}
+
+/*
+ * Expand the line buffer.
+ */
+ static int
+expand_linebuf()
+{
+ int new_size = size_linebuf + LINEBUF_SIZE;
+ char *new_buf = (char *) calloc(new_size, sizeof(char));
+ char *new_attr = (char *) calloc(new_size, sizeof(char));
+ if (new_buf == NULL || new_attr == NULL)
+ {
+ if (new_attr != NULL)
+ free(new_attr);
+ if (new_buf != NULL)
+ free(new_buf);
+ return 1;
+ }
+ memcpy(new_buf, linebuf, size_linebuf * sizeof(char));
+ memcpy(new_attr, attr, size_linebuf * sizeof(char));
+ linebuf = new_buf;
+ attr = new_attr;
+ size_linebuf = new_size;
+ return 0;
}
/*
@@ -80,6 +110,9 @@ prewind()
is_null_line = 0;
pendc = '\0';
lmargin = 0;
+#if HILITE_SEARCH
+ hilites = 0;
+#endif
if (status_col)
lmargin += 1;
if (linenums == OPT_ONPLUS)
@@ -146,10 +179,44 @@ plinenum(pos)
}
/*
- *
+ * Determine how many characters are required to shift N columns.
*/
static int
-utf_len(char *s, int len)
+shift_chars(s, len)
+ char *s;
+ int len;
+{
+ char *p = s;
+
+ /*
+ * Each char counts for one column, except ANSI color escape
+ * sequences use no columns since they don't move the cursor.
+ */
+ while (*p != '\0' && len > 0)
+ {
+ if (*p++ != ESC)
+ {
+ len--;
+ } else
+ {
+ while (*p != '\0')
+ {
+ if (is_ansi_end(*p++))
+ break;
+ }
+ }
+ }
+ 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;
@@ -177,28 +244,26 @@ pshift(shift)
int shift;
{
int i;
- int real_shift;
+ int nchars;
if (shift > column - lmargin)
shift = column - lmargin;
if (shift > curr - lmargin)
shift = curr - lmargin;
- if (!utf_mode)
- real_shift = shift;
+ 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++)
{
- real_shift = utf_len(linebuf + lmargin, shift);
- if (real_shift > curr)
- real_shift = curr;
- }
- for (i = 0; i < curr - real_shift; i++)
- {
- linebuf[lmargin + i] = linebuf[lmargin + i + real_shift];
- attr[lmargin + i] = attr[lmargin + i + real_shift];
+ linebuf[lmargin + i] = linebuf[lmargin + i + nchars];
+ attr[lmargin + i] = attr[lmargin + i + nchars];
}
+ curr -= nchars;
column -= shift;
- curr -= real_shift;
cshift += shift;
}
@@ -306,17 +371,30 @@ in_ansi_esc_seq()
{
if (linebuf[i] == ESC)
return (1);
- if (strchr(end_ansi_chars, linebuf[i]) != NULL)
+ if (is_ansi_end(linebuf[i]))
return (0);
}
return (0);
}
/*
+ * Is a character the end of an ANSI escape sequence?
+ */
+ public int
+is_ansi_end(c)
+ char c;
+{
+ return (strchr(end_ansi_chars, c) != 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)
+
static int
-storec(c, a, pos)
+store_char(c, a, pos)
int c;
int a;
POSITION pos;
@@ -325,11 +403,14 @@ storec(c, a, pos)
#if HILITE_SEARCH
if (is_hilited(pos, pos+1, 0))
+ {
/*
* This character should be highlighted.
* Override the attribute passed in.
*/
a = AT_STANDOUT;
+ hilites++;
+ }
#endif
if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq())
w = 0;
@@ -341,11 +422,15 @@ storec(c, a, pos)
*/
return (1);
- if (curr >= sizeof(linebuf)-2)
+ if (curr >= size_linebuf-2)
+ {
/*
* Won't fit in line buffer.
+ * Try to expand it.
*/
- return (1);
+ if (expand_linebuf())
+ return (1);
+ }
/*
* Special handling for "magic cookie" terminals.
@@ -387,6 +472,38 @@ storec(c, a, pos)
}
/*
+ * Append a tab to the line buffer.
+ * Store spaces to represent the tab.
+ */
+#define STORE_TAB(a,pos) \
+ do { if (store_tab((a),(pos))) return (1); } while (0)
+
+ static int
+store_tab(attr, pos)
+ int attr;
+ POSITION pos;
+{
+ int to_tab = column + cshift - lmargin;
+ int i;
+
+ if (ntabstops < 2 || to_tab >= tabstops[ntabstops-1])
+ to_tab = tabdefault -
+ ((to_tab - tabstops[ntabstops-1]) % tabdefault);
+ else
+ {
+ for (i = ntabstops - 2; i >= 0; i--)
+ if (to_tab >= tabstops[i])
+ break;
+ to_tab = tabstops[i+1] - to_tab;
+ }
+
+ do {
+ STORE_CHAR(' ', attr, pos);
+ } while (--to_tab > 0);
+ return 0;
+}
+
+/*
* Append a character to the line buffer.
* Expand tabs into spaces, handle underlining, boldfacing, etc.
* Returns 0 if ok, 1 if couldn't fit in buffer.
@@ -429,7 +546,10 @@ pappend(c, pos)
* pappending. (Bold & underline can get messed up otherwise.)
*/
if (cshift < hshift && column > sc_width / 2)
+ {
+ linebuf[curr] = '\0';
pshift(hshift - cshift);
+ }
return (r);
}
@@ -441,15 +561,15 @@ do_append(c, pos)
register char *s;
register int a;
-#define STOREC(c,a) \
- if (storec((c),(a),pos)) return (1); else curr++
+#define STOREC(c,a) \
+ if ((c) == '\t') STORE_TAB((a),pos); else STORE_CHAR((c),(a),pos)
if (c == '\b')
{
switch (bs_mode)
{
case BS_NORMAL:
- STOREC(c, AT_NORMAL);
+ STORE_CHAR(c, AT_NORMAL, pos);
break;
case BS_CONTROL:
goto do_control_char;
@@ -469,14 +589,40 @@ do_append(c, pos)
* bold (if an identical character is overstruck),
* or just deletion of the character in the buffer.
*/
- overstrike = 0;
- if ((char)c == linebuf[curr])
- STOREC(linebuf[curr], AT_BOLD);
- else if (c == '_')
+ overstrike--;
+ if (utf_mode && curr > 1 && (char)c == linebuf[curr-2])
+ {
+ backc();
+ backc();
+ overstrike = 2;
+ } else if (utf_mode && curr > 0 && (char)c == linebuf[curr-1])
+ {
+ backc();
+ STORE_CHAR(linebuf[curr], AT_BOLD, pos);
+ overstrike = 1;
+ } else if ((char)c == linebuf[curr])
+ {
+ STOREC(c, AT_BOLD);
+ } else if (c == '_')
+ {
+ if (utf_mode)
+ {
+ if (curr > 0 && IS_CONT(linebuf[curr]))
+ attr[curr-1] = AT_UNDERLINE;
+ if (curr > 1 && IS_CONT(linebuf[curr-1]))
+ attr[curr-2] = AT_UNDERLINE;
+ if (curr > 2 && IS_CONT(linebuf[curr-2]))
+ attr[curr-3] = AT_UNDERLINE;
+ if (curr > 3 && IS_CONT(linebuf[curr-3]))
+ attr[curr-4] = AT_UNDERLINE;
+ if (curr > 4 && IS_CONT(linebuf[curr-4]))
+ attr[curr-5] = AT_UNDERLINE;
+ }
STOREC(linebuf[curr], AT_UNDERLINE);
- else if (linebuf[curr] == '_')
+ } else if (linebuf[curr] == '_')
+ {
STOREC(c, AT_UNDERLINE);
- else if (control_char(c))
+ } else if (control_char(c))
goto do_control_char;
else
STOREC(c, AT_NORMAL);
@@ -485,18 +631,13 @@ do_append(c, pos)
/*
* Expand a tab into spaces.
*/
- if (tabstop == 0)
- tabstop = 1;
switch (bs_mode)
{
case BS_CONTROL:
goto do_control_char;
case BS_NORMAL:
case BS_SPECIAL:
- do
- {
- STOREC(' ', AT_NORMAL);
- } while (((column + cshift - lmargin) % tabstop) != 0);
+ STORE_TAB(AT_NORMAL, pos);
break;
}
} else if (control_char(c))
@@ -507,7 +648,7 @@ do_append(c, pos)
/*
* Output as a normal character.
*/
- STOREC(c, AT_NORMAL);
+ STORE_CHAR(c, AT_NORMAL, pos);
} else
{
/*
@@ -525,7 +666,7 @@ do_append(c, pos)
return (1);
for ( ; *s != 0; s++)
- STOREC(*s, a);
+ STORE_CHAR(*s, a, pos);
}
} else
{
@@ -568,6 +709,14 @@ pdone(endline)
}
linebuf[curr] = '\0';
attr[curr] = AT_NORMAL;
+
+#if HILITE_SEARCH
+ if (status_col && hilites > 0)
+ {
+ linebuf[0] = '*';
+ attr[0] = AT_STANDOUT;
+ }
+#endif
/*
* If we are done with this line, reset the current shift.
*/
@@ -622,7 +771,7 @@ forw_raw_line(curr_pos, linep)
POSITION curr_pos;
char **linep;
{
- register char *p;
+ register int n;
register int c;
POSITION new_pos;
@@ -630,8 +779,7 @@ forw_raw_line(curr_pos, linep)
(c = ch_forw_get()) == EOI)
return (NULL_POSITION);
- p = linebuf;
-
+ n = 0;
for (;;)
{
if (c == '\n' || c == EOI)
@@ -639,21 +787,22 @@ forw_raw_line(curr_pos, linep)
new_pos = ch_tell();
break;
}
- if (p >= &linebuf[sizeof(linebuf)-1])
+ if (n >= size_linebuf-1)
{
- /*
- * Overflowed the input buffer.
- * Pretend the line ended here.
- * {{ The line buffer is supposed to be big
- * enough that this never happens. }}
- */
- new_pos = ch_tell() - 1;
- break;
+ if (expand_linebuf())
+ {
+ /*
+ * Overflowed the input buffer.
+ * Pretend the line ended here.
+ */
+ new_pos = ch_tell() - 1;
+ break;
+ }
}
- *p++ = c;
+ linebuf[n++] = c;
c = ch_forw_get();
}
- *p = '\0';
+ linebuf[n] = '\0';
if (linep != NULL)
*linep = linebuf;
return (new_pos);
@@ -668,7 +817,7 @@ back_raw_line(curr_pos, linep)
POSITION curr_pos;
char **linep;
{
- register char *p;
+ register int n;
register int c;
POSITION new_pos;
@@ -676,9 +825,8 @@ back_raw_line(curr_pos, linep)
ch_seek(curr_pos-1))
return (NULL_POSITION);
- p = &linebuf[sizeof(linebuf)];
- *--p = '\0';
-
+ n = size_linebuf;
+ linebuf[--n] = '\0';
for (;;)
{
c = ch_back_get();
@@ -701,18 +849,32 @@ back_raw_line(curr_pos, linep)
new_pos = ch_zero();
break;
}
- if (p <= linebuf)
+ if (n <= 0)
{
+ int old_size_linebuf = size_linebuf;
+ char *fm;
+ char *to;
+ if (expand_linebuf())
+ {
+ /*
+ * Overflowed the input buffer.
+ * Pretend the line ended here.
+ */
+ new_pos = ch_tell() + 1;
+ break;
+ }
/*
- * Overflowed the input buffer.
- * Pretend the line ended here.
+ * Shift the data to the end of the new linebuf.
*/
- new_pos = ch_tell() + 1;
- break;
+ for (fm = linebuf + old_size_linebuf,
+ to = linebuf + size_linebuf;
+ fm >= linebuf; fm--, to--)
+ *to = *fm;
+ n = size_linebuf - old_size_linebuf;
}
- *--p = c;
+ linebuf[--n] = c;
}
if (linep != NULL)
- *linep = p;
+ *linep = &linebuf[n];
return (new_pos);
}
OpenPOWER on IntegriCloud