------------
Less
-Copyright (C) 1984-2008 Mark Nudelman
+Copyright (C) 1984-2009 Mark Nudelman
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
======================================================================
+ Major changes between "less" versions 429 and 436
+
+* Don't pass "-" to non-pipe LESSOPEN unless it starts with "-".
+
+* Allow a fraction as the argument to the -# (--shift) option.
+
+* Fix highlight bug when underlined/overstruck text matches at end of line.
+
+* Fix non-regex searches with ctrl-R.
+
+======================================================================
+
Major changes between "less" versions 424 and 429
* LESSOPEN pipe will now be used on standard input, if the LESSOPEN
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
c &= 0377;
if ((c < 128 || !utf_mode) && !control_char(c))
- SNPRINTF1(buf, sizeof(buf), "%c", c);
+ SNPRINTF1(buf, sizeof(buf), "%c", (int) c);
else if (c == ESC)
strcpy(buf, "ESC");
#if IS_EBCDIC_HOST
"..V....D....TU.Z"[c]);
#else
else if (c < 128 && !control_char(c ^ 0100))
- SNPRINTF1(buf, sizeof(buf), "^%c", c ^ 0100);
+ SNPRINTF1(buf, sizeof(buf), "^%c", (int) (c ^ 0100));
#endif
else
SNPRINTF1(buf, sizeof(buf), binfmt, c);
/*
- * Copyright (C) 2005-2008 Mark Nudelman
+ * Copyright (C) 2005-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
--- /dev/null
+/*
+ * Copyright (C) 1984-2009 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.
+ *
+ * For more information about less, or for information on how to
+ * contact the author, see the README file.
+ */
+
+/*
+ * Routines to convert text in various ways. Used by search.
+ */
+
+#include "less.h"
+#include "charset.h"
+
+extern int utf_mode;
+
+/*
+ * Get the length of a buffer needed to convert a string.
+ */
+ public int
+cvt_length(len, ops)
+ int len;
+ int ops;
+{
+ if (utf_mode)
+ /*
+ * Just copying a string in UTF-8 mode can cause it to grow
+ * in length.
+ * Four output bytes for one input byte is the worst case.
+ */
+ len *= 4;
+ return (len + 1);
+}
+
+/*
+ * Allocate a chpos array for use by cvt_text.
+ */
+ public int *
+cvt_alloc_chpos(len)
+ int len;
+{
+ int i;
+ int *chpos = (int *) ecalloc(sizeof(int), len);
+ /* Initialize all entries to an invalid position. */
+ for (i = 0; i < len; i++)
+ chpos[i] = -1;
+ return (chpos);
+}
+
+/*
+ * Convert text. Perform the transformations specified by ops.
+ * Returns converted text in odst. The original offset of each
+ * odst character (when it was in osrc) is returned in the chpos array.
+ */
+ public void
+cvt_text(odst, osrc, chpos, lenp, ops)
+ char *odst;
+ char *osrc;
+ int *chpos;
+ int *lenp;
+ int ops;
+{
+ char *dst;
+ char *src;
+ register char *src_end;
+ LWCHAR ch;
+
+ if (lenp != NULL)
+ src_end = osrc + *lenp;
+ else
+ src_end = osrc + strlen(osrc);
+
+ for (src = osrc, dst = odst; src < src_end; )
+ {
+ int src_pos = src - osrc;
+ int dst_pos = dst - odst;
+ ch = step_char(&src, +1, src_end);
+ if ((ops & CVT_BS) && ch == '\b' && dst > odst)
+ {
+ /* Delete backspace and preceding char. */
+ do {
+ dst--;
+ } while (dst > odst &&
+ !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
+ } else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
+ {
+ /* Skip to end of ANSI escape sequence. */
+ src++; /* skip the CSI start char */
+ while (src < src_end)
+ if (!is_ansi_middle(*src++))
+ break;
+ } else
+ {
+ /* Just copy the char to the destination buffer. */
+ if ((ops & CVT_TO_LC) && IS_UPPER(ch))
+ ch = TO_LOWER(ch);
+ put_wchar(&dst, ch);
+ /*
+ * Record the original position of the char.
+ * But if we've already recorded a position
+ * for this char (due to a backspace), leave
+ * it alone; if multiple source chars map to
+ * one destination char, we want the position
+ * of the first one.
+ */
+ if (chpos != NULL && chpos[dst_pos] < 0)
+ chpos[dst_pos] = src_pos;
+ }
+ }
+ if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
+ dst--;
+ *dst = '\0';
+ if (lenp != NULL)
+ *lenp = dst - odst;
+ if (chpos != NULL)
+ chpos[dst - odst] = src - osrc;
+}
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
#else
lessopen++;
returnfd = 1;
- if (*lessopen == '-') {
- /*
- * Lessopen preprocessor will accept "-" as a filename.
- */
- lessopen++;
- } else {
- if (strcmp(filename, "-") == 0)
- return (NULL);
- }
#endif
}
+ if (*lessopen == '-') {
+ /*
+ * Lessopen preprocessor will accept "-" as a filename.
+ */
+ lessopen++;
+ } else {
+ if (strcmp(filename, "-") == 0)
+ return (NULL);
+ }
len = strlen(lessopen) + strlen(filename) + 2;
cmd = (char *) ecalloc(len, sizeof(char));
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
public void ungetcc ();
public void ungetsc ();
public void commands ();
+ public int cvt_length ();
+ public int * cvt_alloc_chpos ();
+ public void cvt_text ();
public void init_cmds ();
public void add_fcmd_table ();
public void add_ecmd_table ();
public void opt_l ();
public void opt_j ();
public void calc_jump_sline ();
+ public void opt_shift ();
+ public void calc_shift_count ();
public void opt_k ();
public void opt_t ();
public void opt__T ();
public void error ();
public void ierror ();
public int query ();
+ public int compile_pattern ();
+ public void uncompile_pattern ();
+ public int is_null_pattern ();
+ public int match_pattern ();
public POSITION position ();
public void add_forw_pos ();
public void add_back_pos ();
public char * eq_message ();
public char * pr_string ();
public char * wait_message ();
+ public void init_search ();
public void repaint_hilite ();
public void clear_attn ();
public void undo_search ();
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
c = ch_forw_get();
}
- pdone(endline, c);
+ pdone(endline, 1);
#if HILITE_SEARCH
if (is_filtered(base_pos))
}
} while (new_pos < curr_pos);
- pdone(endline, ch_forw_get());
+ pdone(endline, 0);
#if HILITE_SEARCH
if (is_filtered(base_pos))
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
#define FAKE_HELPFILE "@/\\less/\\help/\\file/\\@"
+/* Flags for cvt_text */
+#define CVT_TO_LC 01 /* Convert upper-case to lower-case */
+#define CVT_BS 02 /* Do backspace processing */
+#define CVT_CRLF 04 /* Remove CR after LF */
+#define CVT_ANSI 010 /* Remove ANSI escape sequences */
+
#include "funcs.h"
/* Functions not included in funcs.h */
-.TH LESS 1 "Version 429: 11 Apr 2009"
+.TH LESS 1 "Version 436: 07 Jul 2009"
.SH NAME
less \- opposite of more
.SH SYNOPSIS
in the RIGHTARROW and LEFTARROW commands.
If the number specified is zero, it sets the default number of
positions to one half of the screen width.
+Alternately, the number may be specified as a fraction of the width
+of the screen, starting with a decimal point: .5 is half of the
+screen width, .3 is three tenths of the screen width, and so on.
+If the number is specified as a fraction, the actual number of
+scroll positions is recalculated if the terminal window is resized,
+so that the actual scroll remains at the specified fraction
+of the screen width.
.IP "\-\-no-keypad"
Disables sending the keypad initialization and deinitialization strings
to the terminal.
.PP
For compatibility with previous versions of
.I less,
-the input pipe is not used if
+the input preprocessor or pipe is not used if
.I less
is viewing standard input.
-However, if the character after the vertical bar is a dash (\-),
-the input pipe is used on standard input as well as other files.
+However, if the first character of LESSOPEN is a dash (\-),
+the input preprocessor is used on standard input as well as other files.
+In this case, the dash is not considered to be part of
+the preprocessor command.
+If standard input is being viewed, the input preprocessor is passed
+a file name consisting of a single dash.
+Similarly, if the first two characters of LESSOPEN are vertical bar and dash
+(|\-), the input pipe is used on standard input as well as other files.
+Again, in this case the dash is not considered to be part of
+the input pipe command.
.SH "NATIONAL CHARACTER SETS"
There are three types of characters in the input file:
lesskey(1)
.SH COPYRIGHT
-Copyright (C) 1984-2008 Mark Nudelman
+Copyright (C) 1984-2009 Mark Nudelman
.PP
less is part of the GNU project and is free software.
You can redistribute it and/or modify it
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
#include "less.h"
-static char *version = "$Revision: 1.12 $";
+static char *version = "$Revision: 1.13 $";
static int quote_all = 0;
static char openquote = '"';
-.TH LESSECHO 1 "Version 429: 11 Apr 2009"
+.TH LESSECHO 1 "Version 436: 07 Jul 2009"
.SH NAME
lessecho \- expand metacharacters
.SH SYNOPSIS
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
-.TH LESSKEY 1 "Version 429: 11 Apr 2009"
+.TH LESSKEY 1 "Version 436: 07 Jul 2009"
.SH NAME
lesskey \- specify key bindings for less
.SH SYNOPSIS
This NUL character should be represented as \e340 in a lesskey file.
.SH COPYRIGHT
-Copyright (C) 2000-2008 Mark Nudelman
+Copyright (C) 2000-2009 Mark Nudelman
.PP
lesskey is part of the GNU project and is free software;
you can redistribute it and/or modify it
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
* Terminate the line in the line buffer.
*/
public void
-pdone(endline, nextc)
+pdone(endline, forw)
int endline;
- int nextc;
+ int forw;
{
- int nl;
-
(void) pflushmbc();
if (pendc && (pendc != '\r' || !endline))
attr[curr] = AT_NORMAL;
curr++;
}
- else if (ignaw && column >= sc_width)
+ else if (ignaw && column >= sc_width && forw)
{
/*
* Terminals with "ignaw" don't wrap until they *really* need
* get in the state where a full screen width of characters
* have been output but the cursor is sitting on the right edge
* instead of at the start of the next line.
- * So we nudge them into wrapping by outputting the next
- * character plus a backspace. (This wouldn't be right for
- * "!auto_wrap" terminals, but they always end up in the
- * branch above.)
+ * So we nudge them into wrapping by outputting a space
+ * character plus a backspace. But do this only if moving
+ * forward; if we're moving backward and drawing this line at
+ * the top of the screen, the space would overwrite the first
+ * char on the next line. We don't need to do this "nudge"
+ * at the top of the screen anyway.
*/
- linebuf[curr] = nextc;
+ linebuf[curr] = ' ';
attr[curr++] = AT_NORMAL;
linebuf[curr] = '\b';
attr[curr++] = AT_NORMAL;
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
init_line();
init_cmdhist();
init_option();
+ init_search();
/*
* If the name of the executable program is "more",
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
extern int pr_type;
extern int plusoption;
extern int swindow;
+extern int sc_width;
extern int sc_height;
extern int secure;
extern int dohelp;
extern char version[];
extern int jump_sline;
extern int jump_sline_fraction;
+extern int shift_count;
+extern int shift_count_fraction;
extern int less_is_more;
#if LOGFILE
extern char *namelogfile;
jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM;
}
+/*
+ * Handlers for -# option.
+ */
+ public void
+opt_shift(type, s)
+ int type;
+ char *s;
+{
+ PARG parg;
+ char buf[16];
+ int len;
+ int err;
+
+ switch (type)
+ {
+ case INIT:
+ case TOGGLE:
+ if (*s == '.')
+ {
+ s++;
+ shift_count_fraction = getfraction(&s, "#", &err);
+ if (err)
+ error("Invalid column fraction", NULL_PARG);
+ else
+ calc_shift_count();
+ } else
+ {
+ int hs = getnum(&s, "#", &err);
+ if (err)
+ error("Invalid column number", NULL_PARG);
+ else
+ {
+ shift_count = hs;
+ shift_count_fraction = -1;
+ }
+ }
+ break;
+ case QUERY:
+ if (shift_count_fraction < 0)
+ {
+ parg.p_int = shift_count;
+ error("Horizontal shift %d columns", &parg);
+ } else
+ {
+
+ sprintf(buf, ".%06d", shift_count_fraction);
+ len = strlen(buf);
+ while (len > 2 && buf[len-1] == '0')
+ len--;
+ buf[len] = '\0';
+ parg.p_string = buf;
+ error("Horizontal shift %s of screen width", &parg);
+ }
+ break;
+ }
+}
+ public void
+calc_shift_count()
+{
+ if (shift_count_fraction < 0)
+ return;
+ shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM;
+}
+
#if USERFILE
public void
opt_k(type, s)
any_display = 1;
putstr("less ");
putstr(version);
- putstr("\nCopyright (C) 1984-2008 Mark Nudelman\n\n");
+ putstr("\nCopyright (C) 1984-2009 Mark Nudelman\n\n");
putstr("less comes with NO WARRANTY, to the extent permitted by law.\n");
putstr("For information about the terms of redistribution,\n");
putstr("see the file named README in the less distribution.\n");
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
public int swindow; /* Size of scrolling window */
public int jump_sline; /* Screen line of "jump target" */
public long jump_sline_fraction = -1;
+public long shift_count_fraction = -1;
public int chopline; /* Truncate displayed lines at screen width */
public int no_init; /* Disable sending ti/te termcap strings */
public int no_keypad; /* Disable sending ks/ke termcap strings */
{ NULL, NULL, NULL }
},
{ '#', £_optname,
- NUMBER, 0, &shift_count, NULL,
+ STRING, 0, NULL, opt_shift,
{
"Horizontal shift: ",
- "Horizontal shift %d positions",
+ "0123456789.",
NULL
}
},
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
--- /dev/null
+/*
+ * Copyright (C) 1984-2009 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.
+ *
+ * For more information about less, or for information on how to
+ * contact the author, see the README file.
+ */
+
+/*
+ * Routines to do pattern matching.
+ */
+
+#include "less.h"
+#include "pattern.h"
+
+extern int caseless;
+
+/*
+ * Compile a search pattern, for future use by match_pattern.
+ */
+ static int
+compile_pattern2(pattern, search_type, comp_pattern)
+ char *pattern;
+ int search_type;
+ void **comp_pattern;
+{
+ if ((search_type & SRCH_NO_REGEX) == 0)
+ {
+#if HAVE_POSIX_REGCOMP
+ regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
+ regex_t **pcomp = (regex_t **) comp_pattern;
+ if (regcomp(comp, pattern, REGCOMP_FLAG))
+ {
+ free(comp);
+ error("Invalid pattern", NULL_PARG);
+ return (-1);
+ }
+ if (*pcomp != NULL)
+ regfree(*pcomp);
+ *pcomp = comp;
+#endif
+#if HAVE_PCRE
+ pcre *comp;
+ pcre **pcomp = (pcre **) comp_pattern;
+ const char *errstring;
+ int erroffset;
+ PARG parg;
+ comp = pcre_compile(pattern, 0,
+ &errstring, &erroffset, NULL);
+ if (comp == NULL)
+ {
+ parg.p_string = (char *) errstring;
+ error("%s", &parg);
+ return (-1);
+ }
+ *pcomp = comp;
+#endif
+#if HAVE_RE_COMP
+ PARG parg;
+ int *pcomp = (int *) comp_pattern;
+ if ((parg.p_string = re_comp(pattern)) != NULL)
+ {
+ error("%s", &parg);
+ return (-1);
+ }
+ *pcomp = 1;
+#endif
+#if HAVE_REGCMP
+ char *comp;
+ char **pcomp = (char **) comp_pattern;
+ if ((comp = regcmp(pattern, 0)) == NULL)
+ {
+ error("Invalid pattern", NULL_PARG);
+ return (-1);
+ }
+ if (pcomp != NULL)
+ free(*pcomp);
+ *pcomp = comp;
+#endif
+#if HAVE_V8_REGCOMP
+ struct regexp *comp;
+ struct regexp **pcomp = (struct regexp **) comp_pattern;
+ if ((comp = regcomp(pattern)) == NULL)
+ {
+ /*
+ * regcomp has already printed an error message
+ * via regerror().
+ */
+ return (-1);
+ }
+ if (*pcomp != NULL)
+ free(*pcomp);
+ *pcomp = comp;
+#endif
+ }
+ return (0);
+}
+
+/*
+ * Like compile_pattern2, but convert the pattern to lowercase if necessary.
+ */
+ public int
+compile_pattern(pattern, search_type, comp_pattern)
+ char *pattern;
+ int search_type;
+ void **comp_pattern;
+{
+ char *cvt_pattern;
+ int result;
+
+ if (caseless != OPT_ONPLUS)
+ cvt_pattern = pattern;
+ else
+ {
+ cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
+ cvt_text(cvt_pattern, pattern, (int *)NULL, (int *)NULL, CVT_TO_LC);
+ }
+ result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
+ if (cvt_pattern != pattern)
+ free(cvt_pattern);
+ return (result);
+}
+
+/*
+ * Forget that we have a compiled pattern.
+ */
+ public void
+uncompile_pattern(pattern)
+ void **pattern;
+{
+#if HAVE_POSIX_REGCOMP
+ regex_t **pcomp = (regex_t **) pattern;
+ if (*pcomp != NULL)
+ regfree(*pcomp);
+ *pcomp = NULL;
+#endif
+#if HAVE_PCRE
+ pcre **pcomp = (pcre **) pattern;
+ if (*pcomp != NULL)
+ pcre_free(*pcomp);
+ *pcomp = NULL;
+#endif
+#if HAVE_RE_COMP
+ int *pcomp = (int *) pattern;
+ *pcomp = 0;
+#endif
+#if HAVE_REGCMP
+ char **pcomp = (char **) pattern;
+ if (*pcomp != NULL)
+ free(*pcomp);
+ *pcomp = NULL;
+#endif
+#if HAVE_V8_REGCOMP
+ struct regexp **pcomp = (struct regexp **) pattern;
+ if (*pcomp != NULL)
+ free(*pcomp);
+ *pcomp = NULL;
+#endif
+}
+
+/*
+ * Is a compiled pattern null?
+ */
+ public int
+is_null_pattern(pattern)
+ void *pattern;
+{
+#if HAVE_POSIX_REGCOMP
+ return (pattern == NULL);
+#endif
+#if HAVE_PCRE
+ return (pattern == NULL);
+#endif
+#if HAVE_RE_COMP
+ return (pattern == 0);
+#endif
+#if HAVE_REGCMP
+ return (pattern == NULL);
+#endif
+#if HAVE_V8_REGCOMP
+ return (pattern == NULL);
+#endif
+#if NO_REGEX
+ return (search_pattern != NULL);
+#endif
+}
+
+/*
+ * Simple pattern matching function.
+ * It supports no metacharacters like *, etc.
+ */
+ static int
+match(pattern, pattern_len, buf, buf_len, pfound, pend)
+ char *pattern;
+ int pattern_len;
+ char *buf;
+ int buf_len;
+ char **pfound, **pend;
+{
+ register char *pp, *lp;
+ register char *pattern_end = pattern + pattern_len;
+ register char *buf_end = buf + buf_len;
+
+ for ( ; buf < buf_end; buf++)
+ {
+ for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
+ if (pp == pattern_end || lp == buf_end)
+ break;
+ if (pp == pattern_end)
+ {
+ if (pfound != NULL)
+ *pfound = buf;
+ if (pend != NULL)
+ *pend = lp;
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Perform a pattern match with the previously compiled pattern.
+ * Set sp and ep to the start and end of the matched string.
+ */
+ public int
+match_pattern(pattern, tpattern, line, line_len, sp, ep, notbol, search_type)
+ void *pattern;
+ char *tpattern;
+ char *line;
+ int line_len;
+ char **sp;
+ char **ep;
+ int notbol;
+ int search_type;
+{
+ int matched;
+#if HAVE_POSIX_REGCOMP
+ regex_t *spattern = (regex_t *) pattern;
+#endif
+#if HAVE_PCRE
+ pcre *spattern = (pcre *) pattern;
+#endif
+#if HAVE_RE_COMP
+ int spattern = (int) pattern;
+#endif
+#if HAVE_REGCMP
+ char *spattern = (char *) pattern;
+#endif
+#if HAVE_V8_REGCOMP
+ struct regexp *spattern = (struct regexp *) pattern;
+#endif
+
+ if (search_type & SRCH_NO_REGEX)
+ matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
+ else
+ {
+#if HAVE_POSIX_REGCOMP
+ {
+ regmatch_t rm;
+ int flags = (notbol) ? REG_NOTBOL : 0;
+ matched = !regexec(spattern, line, 1, &rm, flags);
+ if (matched)
+ {
+#ifndef __WATCOMC__
+ *sp = line + rm.rm_so;
+ *ep = line + rm.rm_eo;
+#else
+ *sp = rm.rm_sp;
+ *ep = rm.rm_ep;
+#endif
+ }
+ }
+#endif
+#if HAVE_PCRE
+ {
+ int flags = (notbol) ? PCRE_NOTBOL : 0;
+ int ovector[3];
+ matched = pcre_exec(spattern, NULL, line, line_len,
+ 0, flags, ovector, 3) >= 0;
+ if (matched)
+ {
+ *sp = line + ovector[0];
+ *ep = line + ovector[1];
+ }
+ }
+#endif
+#if HAVE_RE_COMP
+ matched = (re_exec(line) == 1);
+ /*
+ * re_exec doesn't seem to provide a way to get the matched string.
+ */
+ *sp = *ep = NULL;
+#endif
+#if HAVE_REGCMP
+ *ep = regex(spattern, line);
+ matched = (*ep != NULL);
+ if (matched)
+ *sp = __loc1;
+#endif
+#if HAVE_V8_REGCOMP
+#if HAVE_REGEXEC2
+ matched = regexec2(spattern, line, notbol);
+#else
+ matched = regexec(spattern, line);
+#endif
+ if (matched)
+ {
+ *sp = spattern->startp[0];
+ *ep = spattern->endp[0];
+ }
+#endif
+#if NO_REGEX
+ matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep);
+#endif
+ }
+ matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
+ ((search_type & SRCH_NO_MATCH) && !matched);
+ return (matched);
+}
+
--- /dev/null
+/*
+ * Copyright (C) 1984-2009 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.
+ *
+ * For more information about less, or for information on how to
+ * contact the author, see the README file.
+ */
+
+#if HAVE_POSIX_REGCOMP
+#include <regex.h>
+#ifdef REG_EXTENDED
+#define REGCOMP_FLAG REG_EXTENDED
+#else
+#define REGCOMP_FLAG 0
+#endif
+#define DEFINE_PATTERN(name) regex_t *name
+#define CLEAR_PATTERN(name) name = NULL
+#endif
+
+#if HAVE_PCRE
+#include <pcre.h>
+#define DEFINE_PATTERN(name) pcre *name
+#define CLEAR_PATTERN(name) name = NULL
+#endif
+
+#if HAVE_RE_COMP
+char *re_comp();
+int re_exec();
+#define DEFINE_PATTERN(name) int name
+#define CLEAR_PATTERN(name) name = 0
+#endif
+
+#if HAVE_REGCMP
+char *regcmp();
+char *regex();
+extern char *__loc1;
+#define DEFINE_PATTERN(name) char *name
+#define CLEAR_PATTERN(name) name = NULL
+#endif
+
+#if HAVE_V8_REGCOMP
+#include "regexp.h"
+#define DEFINE_PATTERN(name) struct regexp *name
+#define CLEAR_PATTERN(name) name = NULL
+#endif
+
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
*/
#include "less.h"
+#include "pattern.h"
#include "position.h"
#include "charset.h"
#define MINPOS(a,b) (((a) < (b)) ? (a) : (b))
#define MAXPOS(a,b) (((a) > (b)) ? (a) : (b))
-#if HAVE_POSIX_REGCOMP
-#include <regex.h>
-#ifdef REG_EXTENDED
-#define REGCOMP_FLAG REG_EXTENDED
-#else
-#define REGCOMP_FLAG 0
-#endif
-#endif
-#if HAVE_PCRE
-#include <pcre.h>
-#endif
-#if HAVE_RE_COMP
-char *re_comp();
-int re_exec();
-#endif
-#if HAVE_REGCMP
-char *regcmp();
-char *regex();
-extern char *__loc1;
-#endif
-#if HAVE_V8_REGCOMP
-#include "regexp.h"
-#endif
-
-static int match();
-
extern int sigs;
extern int how_search;
extern int caseless;
extern int squished;
extern int can_goto_line;
static int hide_hilite;
-static int oldbot;
static POSITION prep_startpos;
static POSITION prep_endpos;
+static int is_caseless;
+static int is_ucase_pattern;
struct hilite
{
/*
* These are the static variables that represent the "remembered"
- * search pattern.
+ * search pattern and filter pattern.
*/
-#if HAVE_POSIX_REGCOMP
-#define DEFINE_PATTERN(name) static regex_t *name = NULL
-#endif
-#if HAVE_PCRE
-#define DEFINE_PATTERN(name) pcre *name = NULL;
-#endif
-#if HAVE_RE_COMP
-#define DEFINE_PATTERN(name) int name = 0;
-#endif
-#if HAVE_REGCMP
-#define DEFINE_PATTERN(name) static char *name = NULL;
-#endif
-#if HAVE_V8_REGCOMP
-#define DEFINE_PATTERN(name) static struct regexp *name = NULL;
-#endif
-
-DEFINE_PATTERN(search_pattern);
-DEFINE_PATTERN(filter_pattern);
-
-static int is_caseless;
-static int is_ucase_pattern;
-static int last_search_type;
-static int last_filter_type;
-static char *last_pattern = NULL;
-
-#define CVT_TO_LC 01 /* Convert upper-case to lower-case */
-#define CVT_BS 02 /* Do backspace processing */
-#define CVT_CRLF 04 /* Remove CR after LF */
-#define CVT_ANSI 010 /* Remove ANSI escape sequences */
+struct pattern_info {
+ DEFINE_PATTERN(compiled);
+ char* text;
+ int search_type;
+};
+
+static struct pattern_info search_info;
+static struct pattern_info filter_info;
/*
- * Get the length of a buffer needed to convert a string.
+ * Compile and save a search pattern.
*/
static int
-cvt_length(len, ops)
- int len;
- int ops;
+set_pattern(info, pattern, search_type)
+ struct pattern_info *info;
+ char *pattern;
+ int search_type;
{
- if (utf_mode)
- /*
- * Just copying a string in UTF-8 mode can cause it to grow
- * in length.
- * Six output bytes for one input byte is the worst case
- * (and unfortunately is far more than is needed in any
- * non-pathological situation, so this is very wasteful).
- */
- len *= 6;
- return len + 1;
+ if (pattern == NULL)
+ CLEAR_PATTERN(search_info.compiled);
+ else if (compile_pattern(pattern, search_type, &info->compiled) < 0)
+ return -1;
+ /* Pattern compiled successfully; save the text too. */
+ if (info->text != NULL)
+ free(info->text);
+ info->text = NULL;
+ if (pattern != NULL)
+ {
+ info->text = (char *) ecalloc(1, strlen(pattern)+1);
+ strcpy(info->text, pattern);
+ }
+ info->search_type = search_type;
+ return 0;
}
/*
- * Convert text. Perform the transformations specified by ops.
+ * Discard a saved pattern.
*/
static void
-cvt_text(odst, osrc, lenp, ops)
- char *odst;
- char *osrc;
- int *lenp;
- int ops;
+clear_pattern(info)
+ struct pattern_info *info;
{
- char *dst;
- char *src;
- register char *src_end;
- LWCHAR ch;
+ if (info->text != NULL)
+ free(info->text);
+ info->text = NULL;
+ uncompile_pattern(&info->compiled);
+}
- if (lenp != NULL)
- src_end = osrc + *lenp;
- else
- src_end = osrc + strlen(osrc);
+/*
+ * Initialize saved pattern to nothing.
+ */
+ static void
+init_pattern(info)
+ struct pattern_info *info;
+{
+ CLEAR_PATTERN(info->compiled);
+ info->text = NULL;
+ info->search_type = 0;
+}
- for (src = osrc, dst = odst; src < src_end; )
- {
- ch = step_char(&src, +1, src_end);
- if ((ops & CVT_TO_LC) && IS_UPPER(ch))
- {
- /* Convert uppercase to lowercase. */
- put_wchar(&dst, TO_LOWER(ch));
- } else if ((ops & CVT_BS) && ch == '\b' && dst > odst)
- {
- /* Delete backspace and preceding char. */
- do {
- dst--;
- } while (dst > odst &&
- !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
- } else if ((ops & CVT_ANSI) && IS_CSI_START(ch))
- {
- /* Skip to end of ANSI escape sequence. */
- src++; /* skip the CSI start char */
- while (src < src_end)
- if (!is_ansi_middle(*src++))
- break;
- } else
- /* Just copy. */
- put_wchar(&dst, ch);
- }
- if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
- dst--;
- *dst = '\0';
- if (lenp != NULL)
- *lenp = dst - odst;
+/*
+ * Initialize search variables.
+ */
+ public void
+init_search()
+{
+ init_pattern(&search_info);
+ init_pattern(&filter_info);
}
/*
- * Determine which conversions to perform.
+ * Determine which text conversions to perform before pattern matching.
*/
static int
get_cvt_ops()
* Is there a previous (remembered) search pattern?
*/
static int
-prev_pattern()
+prev_pattern(info)
+ struct pattern_info *info;
{
- if (last_search_type & SRCH_NO_REGEX)
- return (last_pattern != NULL);
-#if HAVE_POSIX_REGCOMP
- return (search_pattern != NULL);
-#endif
-#if HAVE_PCRE
- return (search_pattern != NULL);
-#endif
-#if HAVE_RE_COMP
- return (search_pattern != 0);
-#endif
-#if HAVE_REGCMP
- return (search_pattern != NULL);
-#endif
-#if HAVE_V8_REGCOMP
- return (search_pattern != NULL);
-#endif
-#if NO_REGEX
- return (search_pattern != NULL);
-#endif
+ if (info->search_type & SRCH_NO_REGEX)
+ return (info->text != NULL);
+ return (!is_null_pattern(info->compiled));
}
#if HILITE_SEARCH
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, NULL))
-#endif
- {
- (void) forw_line(pos);
- goto_line(slinenum);
- put_line();
- }
+ (void) forw_line(pos);
+ goto_line(slinenum);
+ put_line();
}
- if (!oldbot)
- lower_left();
+ lower_left(); // if !oldbot
hide_hilite = save_hide_hilite;
}
public void
undo_search()
{
- if (!prev_pattern())
+ if (!prev_pattern(&search_info))
{
error("No previous regular expression", NULL_PARG);
return;
#endif
}
-/*
- * Compile a search pattern, for future use by match_pattern.
- */
- static int
-compile_pattern2(pattern, search_type, comp_pattern)
- char *pattern;
- int search_type;
- void **comp_pattern;
-{
- if ((search_type & SRCH_NO_REGEX) == 0)
- {
-#if HAVE_POSIX_REGCOMP
- regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
- regex_t **pcomp = (regex_t **) comp_pattern;
- if (regcomp(comp, pattern, REGCOMP_FLAG))
- {
- free(comp);
- error("Invalid pattern", NULL_PARG);
- return (-1);
- }
- if (*pcomp != NULL)
- regfree(*pcomp);
- *pcomp = comp;
-#endif
-#if HAVE_PCRE
- pcre *comp;
- pcre **pcomp = (pcre **) comp_pattern;
- const char *errstring;
- int erroffset;
- PARG parg;
- comp = pcre_compile(pattern, 0,
- &errstring, &erroffset, NULL);
- if (comp == NULL)
- {
- parg.p_string = (char *) errstring;
- error("%s", &parg);
- return (-1);
- }
- *pcomp = comp;
-#endif
-#if HAVE_RE_COMP
- PARG parg;
- int *pcomp = (int *) comp_pattern;
- if ((parg.p_string = re_comp(pattern)) != NULL)
- {
- error("%s", &parg);
- return (-1);
- }
- *pcomp = 1;
-#endif
-#if HAVE_REGCMP
- char *comp;
- char **pcomp = (char **) comp_pattern;
- if ((comp = regcmp(pattern, 0)) == NULL)
- {
- error("Invalid pattern", NULL_PARG);
- return (-1);
- }
- if (pcomp != NULL)
- free(*pcomp);
- *pcomp = comp;
-#endif
-#if HAVE_V8_REGCOMP
- struct regexp *comp;
- struct regexp **pcomp = (struct regexp **) comp_pattern;
- if ((comp = regcomp(pattern)) == NULL)
- {
- /*
- * regcomp has already printed an error message
- * via regerror().
- */
- return (-1);
- }
- if (*pcomp != NULL)
- free(*pcomp);
- *pcomp = comp;
-#endif
- }
-
- if (comp_pattern == (void **) &search_pattern)
- {
- if (last_pattern != NULL)
- free(last_pattern);
- last_pattern = (char *) calloc(1, strlen(pattern)+1);
- if (last_pattern != NULL)
- strcpy(last_pattern, pattern);
- last_search_type = search_type;
- } else
- {
- last_filter_type = search_type;
- }
- return (0);
-}
-
-/*
- * Like compile_pattern2, but convert the pattern to lowercase if necessary.
- */
- static int
-compile_pattern(pattern, search_type, comp_pattern)
- char *pattern;
- int search_type;
- void **comp_pattern;
-{
- char *cvt_pattern;
- int result;
-
- if (caseless != OPT_ONPLUS)
- cvt_pattern = pattern;
- else
- {
- cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC));
- cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC);
- }
- result = compile_pattern2(cvt_pattern, search_type, comp_pattern);
- if (cvt_pattern != pattern)
- free(cvt_pattern);
- return (result);
-}
-
-/*
- * Forget that we have a compiled pattern.
- */
- static void
-uncompile_pattern(pattern)
- void **pattern;
-{
-#if HAVE_POSIX_REGCOMP
- regex_t **pcomp = (regex_t **) pattern;
- if (*pcomp != NULL)
- regfree(*pcomp);
- *pcomp = NULL;
-#endif
-#if HAVE_PCRE
- pcre **pcomp = (pcre **) pattern;
- if (*pcomp != NULL)
- pcre_free(*pcomp);
- *pcomp = NULL;
-#endif
-#if HAVE_RE_COMP
- int *pcomp = (int *) pattern;
- *pcomp = 0;
-#endif
-#if HAVE_REGCMP
- char **pcomp = (char **) pattern;
- if (*pcomp != NULL)
- free(*pcomp);
- *pcomp = NULL;
-#endif
-#if HAVE_V8_REGCOMP
- struct regexp **pcomp = (struct regexp **) pattern;
- if (*pcomp != NULL)
- free(*pcomp);
- *pcomp = NULL;
-#endif
-}
-
- static void
-uncompile_search_pattern()
-{
- uncompile_pattern(&search_pattern);
- last_pattern = NULL;
-}
-
- static void
-uncompile_filter_pattern()
-{
- uncompile_pattern(&filter_pattern);
-}
-
-/*
- * Is a compiled pattern null?
- */
- static int
-is_null_pattern(pattern)
- void *pattern;
-{
-#if HAVE_POSIX_REGCOMP
- return (pattern == NULL);
-#endif
-#if HAVE_PCRE
- return (pattern == NULL);
-#endif
-#if HAVE_RE_COMP
- return (pattern == 0);
-#endif
-#if HAVE_REGCMP
- return (pattern == NULL);
-#endif
-#if HAVE_V8_REGCOMP
- return (pattern == NULL);
-#endif
-}
-
-/*
- * Perform a pattern match with the previously compiled pattern.
- * Set sp and ep to the start and end of the matched string.
- */
- static int
-match_pattern(pattern, line, line_len, sp, ep, notbol, search_type)
- void *pattern;
- char *line;
- int line_len;
- char **sp;
- char **ep;
- int notbol;
- int search_type;
-{
- int matched;
-#if HAVE_POSIX_REGCOMP
- regex_t *spattern = (regex_t *) pattern;
-#endif
-#if HAVE_PCRE
- pcre *spattern = (pcre *) pattern;
-#endif
-#if HAVE_RE_COMP
- int spattern = (int) pattern;
-#endif
-#if HAVE_REGCMP
- char *spattern = (char *) pattern;
-#endif
-#if HAVE_V8_REGCOMP
- struct regexp *spattern = (struct regexp *) pattern;
-#endif
-
- if (search_type & SRCH_NO_REGEX)
- return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep));
-
-#if HAVE_POSIX_REGCOMP
- {
- regmatch_t rm;
- int flags = (notbol) ? REG_NOTBOL : 0;
- matched = !regexec(spattern, line, 1, &rm, flags);
- if (matched)
- {
-#ifndef __WATCOMC__
- *sp = line + rm.rm_so;
- *ep = line + rm.rm_eo;
-#else
- *sp = rm.rm_sp;
- *ep = rm.rm_ep;
-#endif
- }
- }
-#endif
-#if HAVE_PCRE
- {
- int flags = (notbol) ? PCRE_NOTBOL : 0;
- int ovector[3];
- matched = pcre_exec(spattern, NULL, line, line_len,
- 0, flags, ovector, 3) >= 0;
- if (matched)
- {
- *sp = line + ovector[0];
- *ep = line + ovector[1];
- }
- }
-#endif
-#if HAVE_RE_COMP
- matched = (re_exec(line) == 1);
- /*
- * re_exec doesn't seem to provide a way to get the matched string.
- */
- *sp = *ep = NULL;
-#endif
-#if HAVE_REGCMP
- *ep = regex(spattern, line);
- matched = (*ep != NULL);
- if (matched)
- *sp = __loc1;
-#endif
-#if HAVE_V8_REGCOMP
-#if HAVE_REGEXEC2
- matched = regexec2(spattern, line, notbol);
-#else
- matched = regexec(spattern, line);
-#endif
- if (matched)
- {
- *sp = spattern->startp[0];
- *ep = spattern->endp[0];
- }
-#endif
-#if NO_REGEX
- matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep);
-#endif
- matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
- ((search_type & SRCH_NO_MATCH) && !matched);
- return (matched);
-}
-
#if HILITE_SEARCH
/*
* Clear the hilite list.
}
/*
- * Adjust hl_startpos & hl_endpos to account for processing by cvt_text.
- */
- static void
-adj_hilite(anchor, linepos, cvt_ops)
- struct hilite *anchor;
- POSITION linepos;
- int cvt_ops;
-{
- char *line;
- char *oline;
- int line_len;
- char *line_end;
- struct hilite *hl;
- int checkstart;
- POSITION opos;
- POSITION npos;
- POSITION hl_opos;
- POSITION hl_npos;
- LWCHAR ch;
- int ncwidth;
-
- /*
- * The line was already scanned and hilites were added (in hilite_line).
- * But it was assumed that each char position in the line
- * correponds to one char position in the file.
- * This may not be true if cvt_text modified the line.
- * Get the raw line again. Look at each character.
- */
- (void) forw_raw_line(linepos, &line, &line_len);
- line_end = line + line_len;
- opos = npos = linepos;
- hl = anchor->hl_first;
- if (hl == NULL)
- return;
- hl_opos = hl_npos = hl->hl_startpos;
- checkstart = TRUE;
-
- while (hl != NULL && line < line_end)
- {
- /*
- * See if we need to adjust the current hl_startpos or
- * hl_endpos. After adjusting startpos[i], move to endpos[i].
- * After adjusting endpos[i], move to startpos[i+1].
- * The hilite list must be sorted thus:
- * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
- */
- oline = line;
- ch = step_char(&line, +1, line_end);
- ncwidth = line - oline;
- npos += ncwidth;
-
- /* Figure out how this char was processed by cvt_text. */
- if ((cvt_ops & CVT_BS) && ch == '\b')
- {
- /* Skip the backspace and the following char. */
- oline = line;
- ch = step_char(&line, +1, line_end);
- ncwidth = line - oline;
- npos += ncwidth;
- } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch))
- {
- /* Converted uppercase to lower.
- * Note that this may have changed the number of bytes
- * that the character occupies. */
- char dbuf[6];
- char *dst = dbuf;
- put_wchar(&dst, TO_LOWER(ch));
- opos += dst - dbuf;
- } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch))
- {
- /* Skip to end of ANSI escape sequence. */
- line++; /* skip the CSI start char */
- npos++;
- while (line < line_end)
- {
- npos++;
- if (!is_ansi_middle(*line++))
- break;
- }
- } else
- {
- /* Ordinary unprocessed character. */
- opos += ncwidth;
- }
-
- if (opos == hl_opos) {
- /* Adjust highlight position. */
- hl_npos = npos;
- }
- if (opos > hl_opos)
- {
- /*
- * We've moved past the highlight position; store the
- * adjusted highlight position and move to the next highlight.
- */
- if (checkstart)
- {
- hl->hl_startpos = hl_npos;
- hl_opos = hl->hl_endpos;
- checkstart = FALSE;
- } else
- {
- hl->hl_endpos = hl_npos;
- hl = hl->hl_next;
- if (hl != NULL)
- hl_opos = hl->hl_startpos;
- checkstart = TRUE;
- }
- hl_npos = npos;
- }
- }
-}
-
-/*
* Make a hilite for each string in a physical line which matches
* the current pattern.
* sp,ep delimit the first match already found.
*/
static void
-hilite_line(linepos, line, line_len, sp, ep, cvt_ops)
+hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops)
POSITION linepos;
char *line;
int line_len;
+ int *chpos;
char *sp;
char *ep;
int cvt_ops;
char *searchp;
char *line_end = line + line_len;
struct hilite *hl;
- struct hilite hilites;
if (sp == NULL || ep == NULL)
return;
* (currently POSIX, PCRE and V8-with-regexec2). }}
*/
searchp = line;
- /*
- * Put the hilites into a temporary list until they're adjusted.
- */
- hilites.hl_first = NULL;
do {
if (ep > sp)
{
- /*
- * Assume that each char position in the "line"
- * buffer corresponds to one char position in the file.
- * This is not quite true; we need to adjust later.
- */
hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
- hl->hl_startpos = linepos + (sp-line);
- hl->hl_endpos = linepos + (ep-line);
- add_hilite(&hilites, hl);
+ hl->hl_startpos = linepos + chpos[sp-line];
+ hl->hl_endpos = linepos + chpos[ep-line];
+ add_hilite(&hilite_anchor, hl);
}
/*
* If we matched more than zero characters,
searchp++;
else /* end of line */
break;
- } while (match_pattern(search_pattern, searchp, line_end - searchp, &sp, &ep, 1, last_search_type));
-
- /*
- * If there were backspaces in the original line, they
- * were removed, and hl_startpos/hl_endpos are not correct.
- * {{ This is very ugly. }}
- */
- adj_hilite(&hilites, linepos, cvt_ops);
-
- /*
- * Now put the hilites into the real list.
- */
- while ((hl = hilites.hl_next) != NULL)
- {
- hilites.hl_next = hl->hl_next;
- add_hilite(&hilite_anchor, hl);
- }
+ } while (match_pattern(search_info.compiled, search_info.text,
+ searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type));
}
#endif
* Pattern did have uppercase.
* Discard the pattern; we can't change search caselessness now.
*/
- uncompile_search_pattern();
+ clear_pattern(&search_info);
}
#if HILITE_SEARCH
char *sp, *ep;
int line_match;
int cvt_ops;
+ int cvt_len;
+ int *chpos;
POSITION linepos, oldpos;
linenum = find_linenum(pos);
* the search. Remember the line number only if
* we're "far" from the last place we remembered it.
*/
- if (linenums && abs((int)(pos - oldpos)) > 1024)
+ if (linenums && abs((int)(pos - oldpos)) > 2048)
add_lnum(linenum, pos);
oldpos = pos;
* If we're doing backspace processing, delete backspaces.
*/
cvt_ops = get_cvt_ops();
- cline = calloc(1, cvt_length(line_len, cvt_ops));
- cvt_text(cline, line, &line_len, cvt_ops);
+ cvt_len = cvt_length(line_len, cvt_ops);
+ cline = (char *) ecalloc(1, cvt_len);
+ chpos = cvt_alloc_chpos(cvt_len);
+ cvt_text(cline, line, chpos, &line_len, cvt_ops);
#if HILITE_SEARCH
/*
* Check to see if the line matches the filter pattern.
* If so, add an entry to the filter list.
*/
- if ((search_type & SRCH_FIND_ALL) &&
- !is_null_pattern(filter_pattern))
- {
- int line_filter = match_pattern(filter_pattern,
- cline, line_len, &sp, &ep, 0, last_filter_type);
+ if ((search_type & SRCH_FIND_ALL) && prev_pattern(&filter_info)) {
+ int line_filter = match_pattern(filter_info.compiled, filter_info.text,
+ cline, line_len, &sp, &ep, 0, filter_info.search_type);
if (line_filter)
{
struct hilite *hl = (struct hilite *)
* We are successful if we either want a match and got one,
* or if we want a non-match and got one.
*/
- if (!is_null_pattern(search_pattern))
+ if (prev_pattern(&search_info))
{
- line_match = match_pattern(search_pattern,
- cline, line_len, &sp, &ep, 0, search_type);
+ line_match = match_pattern(search_info.compiled, search_info.text,
+ cline, line_len, &sp, &ep, 0, search_type); //FIXME search_info.search_type
if (line_match)
{
/*
* Just add the matches in this line to the
* hilite list and keep searching.
*/
- hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
+ hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
#endif
} else if (--matches <= 0)
{
* the matches in this one line.
*/
clr_hilite();
- hilite_line(linepos, cline, line_len, sp, ep, cvt_ops);
+ hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
}
#endif
free(cline);
+ free(chpos);
if (plinepos != NULL)
*plinepos = linepos;
return (0);
}
}
free(cline);
+ free(chpos);
}
}
if (pattern == NULL)
return (0);
- if (compile_pattern(pattern, search_type, &search_pattern) < 0)
+ if (set_pattern(&search_info, pattern, search_type) < 0)
return (0);
is_ucase_pattern = is_ucase(pattern);
/*
* A null pattern means use the previously compiled pattern.
*/
- if (!prev_pattern() && !hist_pattern(search_type))
+ if (!prev_pattern(&search_info) && !hist_pattern(search_type))
{
error("No previous regular expression", NULL_PARG);
return (-1);
}
if ((search_type & SRCH_NO_REGEX) !=
- (last_search_type & SRCH_NO_REGEX))
+ (search_info.search_type & SRCH_NO_REGEX))
{
error("Please re-enter search pattern", NULL_PARG);
return -1;
/*
* Compile the pattern.
*/
- if (compile_pattern(pattern, search_type, &search_pattern) < 0)
+ if (set_pattern(&search_info, pattern, search_type) < 0)
return (-1);
/*
* Ignore case if -I is set OR
POSITION max_epos;
int result;
int i;
+
/*
* Search beyond where we're asked to search, so the prep region covers
* more than we need. Do one big search instead of a bunch of small ones.
*/
#define SEARCH_MORE (3*size_linebuf)
- if (!prev_pattern() && !is_filtering())
+ if (!prev_pattern(&search_info) && !is_filtering())
return;
/*
if (epos == NULL_POSITION || epos > spos)
{
- result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
+ int search_type = SRCH_FORW | SRCH_FIND_ALL;
+ search_type |= (search_info.search_type & SRCH_NO_REGEX);
+ result = search_range(spos, epos, search_type, 0,
maxlines, (POSITION*)NULL, &new_epos);
if (result < 0)
return;
{
clr_filter();
if (pattern == NULL || *pattern == '\0')
- uncompile_filter_pattern();
+ clear_pattern(&filter_info);
else
- compile_pattern(pattern, search_type, &filter_pattern);
+ set_pattern(&filter_info, pattern, search_type);
screen_trashed = 1;
}
{
if (ch_getflags() & CH_HELPFILE)
return (0);
- return !is_null_pattern(filter_pattern);
+ return prev_pattern(&filter_info);
}
#endif
-/*
- * Simple pattern matching function.
- * It supports no metacharacters like *, etc.
- */
- static int
-match(pattern, pattern_len, buf, buf_len, pfound, pend)
- char *pattern;
- int pattern_len;
- char *buf;
- int buf_len;
- char **pfound, **pend;
-{
- register char *pp, *lp;
- register char *pattern_end = pattern + pattern_len;
- register char *buf_end = buf + buf_len;
-
- for ( ; buf < buf_end; buf++)
- {
- for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
- if (pp == pattern_end || lp == buf_end)
- break;
- if (pp == pattern_end)
- {
- if (pfound != NULL)
- *pfound = buf;
- if (pend != NULL)
- *pend = lp;
- return (1);
- }
- }
- return (0);
-}
-
#if HAVE_V8_REGCOMP
/*
* This function is called by the V8 regcomp to report
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
{
wscroll = (sc_height + 1) / 2;
calc_jump_sline();
+ calc_shift_count();
screen_trashed = 1;
}
}
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
/*
- * Copyright (C) 1984-2008 Mark Nudelman
+ * Copyright (C) 1984-2009 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.
v427 3/16/09 A few Win32 fixes (thanks to Jason Hood).
v428 3/30/09 Add "|-" syntax to LESSOPEN.
v429 4/10/09 Fix search highlighting bug with underlined text.
+-----------------------------------------------------------------
+v430 4/22/09 Don't pass "-" to non-pipe LESSOPEN unless it starts with "-".
+v431 4/29/09 Fix highlight bug when match is at end of line.
+v432 6/27/09 Better fix for highlight bugs;
+ fix new problems with ignaw terminals.
+v433 6/28/09 Cleanup search code.
+v434 6/29/09 More cleanup.
+v435 7/04/09 Fix bugs with non-regex filtering.
+v436 7/05/09 Fix memory leak.
*/
-char version[] = "429";
+char version[] = "436";