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/command.c | 51 +-- contrib/less/forwback.c | 13 +- contrib/less/less.h | 95 ++++-- contrib/less/line.c | 865 ++++++++++++++++++++++++++++++++---------------- contrib/less/main.c | 14 +- contrib/less/prompt.c | 30 +- contrib/less/screen.c | 229 ++++++------- contrib/less/search.c | 130 +++++--- contrib/less/signal.c | 5 +- 9 files changed, 905 insertions(+), 527 deletions(-) (limited to 'contrib/less') 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 #endif + +/* OS-specific includes */ #ifdef _OSK #include #include #endif + +#ifdef __TANDEM +#include +#endif + #if MSDOS_COMPILER==WIN32C || OS2 #include #endif + #if MSDOS_COMPILER==DJGPPC #include #include @@ -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 -#if HAVE_SYS_IOCTL_H && !defined(TIOCGWINSZ) +#if HAVE_SYS_IOCTL_H #include #endif + +#if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS +#include #else #if HAVE_TERMIO_H #include @@ -53,9 +54,6 @@ extern int fd0; #else #include #endif -#if HAVE_SYS_IOCTL_H && (defined(TIOCGWINSZ) || defined(TCGETA) || defined(TIOCGETP) || defined(WIOCGETD)) -#include -#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 -- cgit v1.1