From 5d6048735154d14b6086c89e5252e985c9d0a527 Mon Sep 17 00:00:00 2001 From: delphij Date: Sun, 20 Aug 2006 15:50:51 +0000 Subject: Resolve conflicts. --- contrib/less/line.c | 865 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 573 insertions(+), 292 deletions(-) (limited to 'contrib/less/line.c') 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. -- cgit v1.1