search.c (most-5.0.0a) | : | search.c (most-5.1.0) | ||
---|---|---|---|---|
/* -*- mode: C; mode: fold -*- */ | /* -*- mode: C; mode: fold -*- */ | |||
/* | /* | |||
This file is part of MOST. | This file is part of MOST. | |||
Copyright (c) 1991, 1999, 2002, 2005, 2006, 2007 John E. Davis | Copyright (c) 1991, 1999, 2002, 2005-2018, 2019 John E. Davis | |||
This program is free software; you can redistribute it and/or modify it | This program is free software; you can redistribute it and/or modify it | |||
under the terms of the GNU General Public License as published by the Free | under the terms of the GNU General Public License as published by the Free | |||
Software Foundation; either version 2 of the License, or (at your option) | Software Foundation; either version 2 of the License, or (at your option) | |||
any later version. | any later version. | |||
This program is distributed in the hope that it will be useful, but WITHOUT | This program is distributed in the hope that it will be useful, but WITHOUT | |||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |||
more details. | more details. | |||
You should have received a copy of the GNU General Public License along | You should have received a copy of the GNU General Public License along | |||
with this program; if not, write to the Free Software Foundation, Inc., 675 | with this program; if not, write to the Free Software Foundation, Inc., 675 | |||
Mass Ave, Cambridge, MA 02139, USA. | Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | */ | |||
#include "config.h" | #include "config.h" | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <string.h> | #include <string.h> | |||
#include <ctype.h> | ||||
#include <slang.h> | #include <slang.h> | |||
#include "most.h" | #include "most.h" | |||
#include "window.h" | #include "window.h" | |||
#include "line.h" | #include "line.h" | |||
#include "file.h" | #include "file.h" | |||
#include "display.h" | #include "display.h" | |||
#include "search.h" | #include "search.h" | |||
/* Note!!! The regular expression searches may not work. I have not | /* Note!!! The regular expression searches may not work. I have not | |||
* tested them. | * tested them. | |||
* FIXME!!! This whole thing needs to be rewritten. It is a mess. | * FIXME!!! This whole thing needs to be rewritten. It is a mess. | |||
*/ | */ | |||
int Most_Case_Sensitive = 0; | int Most_Case_Sensitive = 0; | |||
char Most_Search_Str[256]; | char Most_Search_Str[256]; | |||
int Most_Search_Dir = 1; | int Most_Search_Dir = 1; | |||
#include "jdmacros.h" | #include "jdmacros.h" | |||
#undef SLANG_REGEXP | typedef struct Search_Type_ Search_Type; | |||
#undef HAVE_V8_REGCOMP | struct Search_Type_ | |||
{ | ||||
#define UPCASE(ch) ((!Most_Case_Sensitive && (ch <= 'z') && (ch >= 'a')) ? (ch - | void *cd; | |||
32) : ch) | unsigned char *(*fsearch_method) (Search_Type *, unsigned char *, unsigned ch | |||
#if defined(HAVE_V8_REGCOMP) || defined(SLANG_REGEXP) | ar *, unsigned char *); | |||
unsigned char *(*bsearch_method) (Search_Type *, unsigned char *, unsigned ch | ||||
/* | ar *, unsigned char *); | |||
* Regular expression stuff | void (*close_method)(Search_Type *); | |||
* ************************ | }; | |||
*/ | ||||
# ifdef HAVE_V8_REGCOMP | ||||
# include "regexp.h" | ||||
/* pointer to area malloced by regcomp() */ | ||||
static struct regexp *regpattern = NULL; | ||||
# else | ||||
/* slang regular expression structure */ | ||||
#if SLANG_VERSION < 20000 | ||||
static SLRegexp_Type regdata; | ||||
/* buffer for compiled regular expression */ | ||||
static unsigned char regbuf[sizeof(Most_Search_Str) * 3]; | ||||
#else | ||||
static SLRegexp_Type *Regexp; | ||||
#endif | ||||
# endif /* HAVE_V8_REGCOMP */ | ||||
/* set if regexp compiled OK, 0 if regular expression error */ | static unsigned char Ascii_Upper[256]; | |||
static int regcompOK = 1; | ||||
/* uncompiled search pattern */ | static void bs_search_init (void) | |||
static char savepattern[sizeof(Most_Search_Str)]; | ||||
/* | ||||
* This function is called by the V8 regcomp to report | ||||
* errors in regular expressions. | ||||
*/ | ||||
static void regerror(char *s) | ||||
{ | { | |||
char string[256]; | static int inited = 0; | |||
unsigned int i; | ||||
regcompOK = 0; /* clear flag, ie regexp error */ | if (inited) return; | |||
sprintf(string, "Regular expression error: %s", s); | for (i = 0; i < 256; i++) Ascii_Upper[i] = i; | |||
most_message(string, 1); | for (i = 'a'; i <= 'z'; i++) Ascii_Upper[i] = (i - 32); | |||
inited = 1; | ||||
} | } | |||
/* | ||||
* Compiles the search pattern "key" into a regular expression for use by | ||||
* do_regexec() | ||||
* | ||||
* Returns: 1 success | ||||
* 0 error | ||||
* | ||||
*/ | ||||
static int do_regcomp(unsigned char *key) | ||||
{ | ||||
static int old_Most_Case_Sensitive; | ||||
unsigned char UpCaseKey[sizeof(savepattern)]; | ||||
# ifndef HAVE_V8_REGCOMP | ||||
int posn; /* reg exp error at this offset */ | ||||
# endif | ||||
/* | #define UPCASE(ch) (Ascii_Upper[(ch)]) | |||
* Only recompile search string if it has changed | ||||
*/ | ||||
if ((0 == strcmp ((char *)key, (char *) savepattern)) | ||||
&& (Most_Case_Sensitive == old_Most_Case_Sensitive)) | ||||
return 1; | ||||
# ifdef HAVE_V8_REGCOMP | #define CHAR_EQS(a,b) \ | |||
if (regpattern != NULL) | (((a) == (b)) || (!Most_Case_Sensitive && (UPCASE(a) == UPCASE(b)))) | |||
free(regpattern); | ||||
# endif | ||||
if ( strlen((char *)key) >= sizeof(savepattern) ) | static int is_ansi_escape (unsigned char **begp, unsigned char *end) | |||
{ | { | |||
regerror("Search string too long"); | unsigned char *p, ch; | |||
savepattern[0] = '\0'; | ||||
return 0; | ||||
} | ||||
old_Most_Case_Sensitive = Most_Case_Sensitive; | p = *begp; | |||
if ((p == end) || (*p++ != '[')) return 0; | ||||
if ( Most_Case_Sensitive == 0 ) | /* Look for "ESC X m", where X is one of: | |||
* X = "" | ||||
* X = digit | ||||
* X = digit ; digit ... | ||||
*/ | ||||
ch = *p++; | ||||
while (isdigit (ch)) | ||||
{ | { | |||
register unsigned char *p; /* ptr to UpCaseKey */ | while ((p < end) && isdigit (*p)) | |||
register unsigned char *keyp; /* ptr to key */ | p++; | |||
register unsigned char c; /* source character */ | ||||
/* | ||||
* Make a upper case copy of every character from "key" | ||||
* into "UpCaseKey" | ||||
*/ | ||||
p = UpCaseKey; | ||||
keyp = key; | ||||
while ( (c = *keyp++) != '\0' ) | ||||
*p++ = UPCASE(c); | ||||
*p = '\0'; | ||||
} | ||||
strcpy((char *)savepattern, (char *)key); | if (p == end) | |||
return 0; | ||||
# ifdef HAVE_V8_REGCOMP | ch = *p++; | |||
regpattern = regcomp((char *)(Most_Case_Sensitive ? key : UpCaseKey)); | if (ch == 'm') | |||
if (regpattern == NULL) | break; | |||
{ | ||||
regcompOK = 1; | ||||
return 1; | ||||
} | ||||
# else | ||||
# if SLANG_VERSION < 20000 | if ((ch != ';') || (p == end)) | |||
regdata.case_sensitive = 1; | return 0; | |||
regdata.buf = regbuf; | ||||
regdata.pat = Most_Case_Sensitive ? key : UpCaseKey; | ||||
regdata.buf_len = sizeof (regbuf); | ||||
posn = SLang_regexp_compile(®data); | ||||
# else | ||||
if (Regexp != NULL) | ||||
SLregexp_free (Regexp); | ||||
if (NULL == (Regexp = SLregexp_compile ((char *)key, Most_Case_Sensitive ? 0 | ||||
: SLREGEXP_CASELESS))) | ||||
posn = -1; | ||||
else | ||||
posn = 0; | ||||
# endif | ||||
if (posn == 0) | ch = *p++; | |||
{ | ||||
regcompOK = 1; | ||||
return 1; | ||||
} | } | |||
regerror ("Unable to compile pattern"); | if (ch != 'm') | |||
# endif /* HAVE_V8_REGCOMP */ | return 0; | |||
/* | ||||
* regcomp has already printed error message via regerror(). | ||||
*/ | ||||
savepattern[0] = '\0'; | ||||
return 0; /* failure */ | ||||
} | ||||
/* | *begp = p; | |||
* Call the appropriate regular expression execute function | return 1; | |||
*/ | ||||
static unsigned char *do_regexec(unsigned char *string, unsigned int len) | ||||
{ | ||||
# ifdef HAVE_V8_REGCOMP | ||||
if ( regexec(regpattern, (char *)string) ) | ||||
return( (unsigned char *)regpattern->startp[0] ); | ||||
else | ||||
return( NULL ); | ||||
# else | ||||
# if SLANG_VERSION < 20000 | ||||
return ( SLang_regexp_match(string, len, ®data) ); | ||||
# else | ||||
return (unsigned char *)SLregexp_match (Regexp, (char *)string, len)); | ||||
# endif | ||||
# endif /* HAVE_V8_REGCOMP */ | ||||
} | } | |||
/* | ||||
* Make a upper case copy of a string. Also changes any "c\b" character | ||||
* strings into just "" so that highlighted and underlined characters | ||||
* can be searched. | ||||
* | ||||
* Reuses malloced memory, so a copy cannot be retained between calls. | ||||
*/ | ||||
static unsigned char *StrUpCaseCopy(unsigned char *input) | static int is_rev_ansi_escape (unsigned char *beg, unsigned char **endp) | |||
{ | { | |||
static unsigned char *uppercase; /* ptr to malloced area */ | unsigned char *p, ch; | |||
static size_t bufsize; /* size of malloced area */ | ||||
unsigned char *src; /* ptr to source */ | ||||
register unsigned char *dest; /* ptr to destination */ | ||||
register int idx; /* index into uppercase[] */ | ||||
register unsigned char c; /* source character */ | ||||
size_t length; /* size of string to copy */ | ||||
src = input; | p = *endp; | |||
length = strlen((char *)src) + 1; /* len of line plus terminator */ | if (p == beg) | |||
return 0; | ||||
if ( length > bufsize ) | ch = *p--; | |||
while (isdigit (ch)) | ||||
{ | { | |||
if ( uppercase != (unsigned char *)NULL ) | while ((p > beg) && isdigit (*p)) | |||
free(uppercase); | p--; | |||
bufsize = (length > 256 ) ? length : 256; /* 256 byte default */ | if (p == beg) | |||
return 0; | ||||
uppercase = (unsigned char *)malloc(bufsize); | ch = *p--; | |||
if ( uppercase == (unsigned char *)NULL ) | ||||
return(NULL); | ||||
} | ||||
/* | if (ch == '[') | |||
* Make the copy converting to upper case as we go | break; | |||
*/ | ||||
dest = uppercase; | if ((ch != ';') || (p == beg)) | |||
return 0; | ||||
for ( idx = 0 ; (c = *src) != '\0' ; src++ ) | ch = *p--; | |||
{ | ||||
if ( c == '\b' ) /* backspace */ | ||||
{ | ||||
if ( idx-- > 0 ) | ||||
dest--; /* back up dest pointer */ | ||||
} | ||||
else | ||||
{ | ||||
if ( idx++ >= 0 ) | ||||
*dest++ = UPCASE(c); | ||||
} | ||||
} | } | |||
*dest = '\0'; /* add termination */ | if ((ch != '[') || (p < beg) || (*p != 033)) | |||
return 0; | ||||
return(uppercase); | *endp = p-1; | |||
return 1; | ||||
} | } | |||
/* | ||||
* Given an offset into a copy made by StrUpCaseCopy() and a pointer to the | ||||
* original string, returns a pointer into the original string corresponding | ||||
* to this offset. | ||||
*/ | ||||
static unsigned char *GetOrigPtr(unsigned char *original, int offset) | ||||
{ | ||||
register unsigned char *p = original; | ||||
register int j = offset; | ||||
/* | /* These routines have special processing for ANSI escape sequence and backspace | |||
* Step through, adjusting offset according to backspaces found | handling. | |||
*/ | * For example, "hello world" may occur as: | |||
while ( *p != '\0' ) | * plain: hello world | |||
{ | * underlined: h_e_l_l_o_ world | |||
if ( *p == '\b' ) | * underlined: _h_e_l_l_o world | |||
j++; | * bold: hheelllloo world | |||
else | * ansi: [5mhello[m world | |||
j--; | * ansi: [5mh[32;43mello[m world | |||
*/ | ||||
if ( j < 0 ) | ||||
break; | ||||
else | ||||
p++; | ||||
} | ||||
return(p); | ||||
} | ||||
#endif /* HAVE_V8_REGCOMP || SLANG_REGEXP */ | ||||
/* This routine returns the 1 + position of first match of key in str. | /* This routine returns the 1 + position of first match of key in str. | |||
key is modified to match the case of str. */ | * searches from beg up to but not including end. Handles backspace, etc | |||
/* We should try to optimize this routine */ | */ | |||
/* searches from beg up to but not including end */ | ||||
#if defined(SLANG_REGEXP) | ||||
static unsigned char * | static unsigned char * | |||
forw_search_region_regexp (unsigned char *beg, unsigned char *end, | bs_fsearch (Search_Type *st, | |||
unsigned char *key) | unsigned char *beg, unsigned char *end, | |||
unsigned char *key) | ||||
{ | { | |||
if (Regexp != NULL) | unsigned char ch, ch1, ch1up; | |||
SLregexp_free (Regexp); | ||||
if (NULL == (Regexp = SLregexp_compile ((char *)key, Most_Case_Sensitive ? 0 | ||||
: SLREGEXP_CASELESS))) | ||||
return NULL; | ||||
if ( do_regcomp(key) == 0 ) | ||||
return(Most_Eob); | ||||
/* | ||||
* For regular expression searches we need to do a line by line | ||||
* search, so it is necessary to temporarily replace '\n' with '\0' | ||||
* characters. | ||||
* | ||||
* ***** THIS IS NOT ALLOWED FOR MMAPPED FILES!!!!!!!!! ***** | ||||
*/ | ||||
p = beg; | ||||
linebeg = beg; | ||||
while (linebeg < end) | ||||
{ | ||||
while ((p < end) && (*p != '\n')) p++; | ||||
if (p == end) break; | ||||
/* *p = 0; -- not allow for mmapped files */ | ||||
if ( Most_Case_Sensitive == 0 ) /* i.e. case insensitive */ | ||||
{ | ||||
copy = StrUpCaseCopy(linebeg); | ||||
if ( copy == (unsigned char *)NULL ) | ||||
return(Most_Eob); | ||||
} | ||||
/* | ||||
* Quick sanity check for beginning of line archored tests. | ||||
* If 1st char of key is "^", then the character before linebeg (which | ||||
* must be beyond the start of the window), must be a "\n", | ||||
* otherwise do_regexec() isn't called. | ||||
*/ | ||||
if ( | ||||
# if 0 | ||||
((*key != '^') | ||||
|| (linebeg > Most_Win->beg_pos && linebeg[-1] == '\n')) | ||||
&& | ||||
#endif | ||||
(match = do_regexec(Most_Case_Sensitive ? linebeg : copy))) | ||||
{ | ||||
/* *p = '\n'; --- NOT ALLOWED */ | ||||
if ( Most_Case_Sensitive == 0 ) | ||||
{ | ||||
/* | ||||
* Use offset into "copy" as idx to find point in | ||||
* real line. | ||||
*/ | ||||
return( GetOrigPtr(linebeg, match - copy) ); | ||||
} | ||||
else | ||||
{ | ||||
return( match ); | ||||
} | ||||
} | ||||
/* *p++ = '\n'; */ | ||||
linebeg = p; | ||||
} | ||||
return(Most_Eob); | ||||
} | ||||
#endif | ||||
static unsigned char *forw_search_region(unsigned char *beg, | ||||
unsigned char *end, | ||||
unsigned char *key) | ||||
{ | ||||
#if defined(HAVE_V8_REGCOMP) || defined(SLANG_REGEXP) | ||||
return forw_search_region_regexp (beg, end, key); | ||||
#else | ||||
char ch, char1, work[256]; | ||||
unsigned char *pos; | unsigned char *pos; | |||
int key_len,j, str_len; | int cis, key_len, j, str_len; | |||
if (Most_Case_Sensitive) | ||||
{ | ||||
strcpy(work, (char *) key); | ||||
key_len = strlen((char *) key); | ||||
} | ||||
else | ||||
{ | ||||
/* upcase key */ | ||||
key_len = 0; | ||||
while (0 != (ch = key[key_len])) | ||||
{ | ||||
ch = UPCASE(ch); | ||||
work[key_len++] = ch; /* null char is ok */ | ||||
} | ||||
} | ||||
(void) st; | ||||
key_len = strlen ((char *)key); | ||||
if (key_len == 0) | if (key_len == 0) | |||
return Most_Eob; | return Most_Eob; | |||
str_len = (int) (end - beg); | str_len = (int) (end - beg); | |||
if (str_len < key_len) return (Most_Eob); | if (str_len < key_len) return (Most_Eob); | |||
# if 0 | cis = (Most_Case_Sensitive == 0); | |||
str_len -= key_len; /* effective length */ | ch1 = key[0]; | |||
end -= (key_len - 1); | ch1up = UPCASE(ch1); | |||
# endif | ||||
char1 = work[0]; | ||||
while (1) | while (1) | |||
{ | { | |||
/* Find first character that matches */ | /* Find first character that matches */ | |||
while (1) | while (1) | |||
{ | { | |||
if (beg == end) return Most_Eob; | if (beg == end) return Most_Eob; | |||
ch = *beg++; | ch = *beg++; | |||
ch = UPCASE(ch); | if ((ch == ch1) | |||
if (ch == char1) | || (cis && (ch1up == UPCASE(ch)))) | |||
break; | break; | |||
} | } | |||
/* so we have a position of possible match */ | /* so we have a position of possible match */ | |||
j = 1; | j = 1; | |||
pos = beg; /* save this position so we start from here again */ | pos = beg; /* save this position so we start from here again */ | |||
while (1) | while (1) | |||
{ | { | |||
skipping to change at line 445 | skipping to change at line 213 | |||
break; | break; | |||
ch = *beg++; | ch = *beg++; | |||
/* FIXME: This only works for x^Hx but not x^Hx^Hx... | /* FIXME: This only works for x^Hx but not x^Hx^Hx... | |||
* It is probably better to skip all the ^H characters | * It is probably better to skip all the ^H characters | |||
* until the end. That is, regard "a^Hb^Hc" as 'c'. | * until the end. That is, regard "a^Hb^Hc" as 'c'. | |||
*/ | */ | |||
if ((ch == 8) | if ((ch == 8) | |||
&& (beg + 1 < end) | && (beg + 1 < end) | |||
&& (Most_V_Opt == 0) | && (CHAR_EQS(key[j - 1], *beg) | |||
&& ((work[j - 1] == UPCASE(*beg)) | ||||
|| (*beg == '_'))) | || (*beg == '_'))) | |||
{ | { | |||
ch = *(beg + 1); | ch = *(beg + 1); | |||
beg += 2; | beg += 2; | |||
} | } | |||
else if ((ch == '_') && (beg + 1 < end)) | else if ((ch == '_') && (beg + 1 < end)) | |||
{ | { | |||
ch = *beg++; | ch = *beg++; | |||
if (ch == 8) ch = *beg++; | if (ch == 8) ch = *beg++; | |||
else | else | |||
{ | { | |||
ch = '_'; | ch = '_'; | |||
beg--; | beg--; | |||
} | } | |||
} | } | |||
else if ((ch == 033) && is_ansi_escape (&beg, end)) | ||||
continue; | ||||
if (UPCASE(ch) != work[j]) | if (!CHAR_EQS(ch, key[j])) | |||
break; | break; | |||
j++; | j++; | |||
} | } | |||
beg = pos; | beg = pos; | |||
} | } | |||
#endif /* HAVE_V8_REGCOMP || SLANG_REGEXP */ | ||||
} | } | |||
/* | /* | |||
* Search backwards in the buffer "beg" up to, but not including "end" for | * Search backwards in the buffer "beg" up to, but not including "end" for | |||
* pattern "key". | * pattern "key". It handles backspaces, etc | |||
*/ | */ | |||
static unsigned char * | ||||
static unsigned char *back_search_region(unsigned char *beg, | bs_bsearch (Search_Type *st, | |||
unsigned char *end, | unsigned char *beg, unsigned char *end, | |||
unsigned char *key) | unsigned char *key) | |||
{ | { | |||
#if defined(HAVE_V8_REGCOMP) || defined(SLANG_REGEXP) | unsigned char ch, ch1, ch1up; | |||
register unsigned char *p; | ||||
unsigned char *endp, /* end of line */ | ||||
*lastmatch, /* last match in line */ | ||||
*endprevline, /* end of line before this one */ | ||||
*match; /* ptr to matching string */ | ||||
unsigned char savec; /* last char on line */ | ||||
/* | ||||
* Compile "key" into an executable regular expression | ||||
*/ | ||||
if ( do_regcomp(key) == 0 ) | ||||
return(Most_Eob); | ||||
/* | ||||
* Starting from the end of the buffer, break the buffer into lines | ||||
* then for each line do forward search to find a match. If one is | ||||
* found, move pointer forward one character and try again until | ||||
* unsuccessful. In this way we find the last match on the line | ||||
* and isn't that what we want to do in a reverse search. | ||||
*/ | ||||
endp = end; | ||||
lastmatch = Most_Eob; | ||||
while ( 1 ) /* forever loop */ | ||||
{ | ||||
if ( (endp < beg) ) | ||||
return(Most_Eob); /* Reach start of buffer, no match */ | ||||
/* Find the real end of current line */ | ||||
if ( (p = (unsigned char *)strchr((char *)endp, '\n')) != NULL ) | ||||
endp = p; | ||||
savec = *endp; | ||||
*endp = '\0'; /* terminate line with NULL */ | ||||
/* Find the beginning of line */ | ||||
for ( p = endp - 1 ; (p >= beg) && (*p != '\n') ; p-- ) | ||||
{ | ||||
} | ||||
endprevline = p; | ||||
p++; /* point to 1st char after newline */ | ||||
/* | ||||
* Keep searching forward in this line till no more matches | ||||
*/ | ||||
if ( Most_Case_Sensitive == 0 ) /* i.e. case insensitive */ | ||||
{ | ||||
unsigned char *copy; /* ptr to upper case copy */ | ||||
unsigned char *savecopy; /* copy of "copy" */ | ||||
copy = StrUpCaseCopy(p); | ||||
if ( copy == (unsigned char *)NULL ) | ||||
return(Most_Eob); | ||||
savecopy = copy; | ||||
/* | ||||
* Quick sanity check for beginning of line archored tests. | ||||
* Must be at start of line. | ||||
*/ | ||||
while ( ((*key != '^') || (copy == savecopy)) | ||||
&& (match = do_regexec(copy)) ) | ||||
{ | ||||
if ( GetOrigPtr(p, match - savecopy) > end ) | ||||
break; | ||||
lastmatch = match; | ||||
if ( *lastmatch == '\0' ) /* key must be "$" or "^" */ | ||||
break; | ||||
copy = lastmatch + 1; /* character after match */ | ||||
} | ||||
if ( lastmatch != Most_Eob ) /* found a match */ | ||||
lastmatch = GetOrigPtr(p, lastmatch - savecopy); | ||||
} | ||||
else | ||||
{ | ||||
/* | ||||
* Quick sanity check for beginning of line archored tests. | ||||
* Must be at start of buffer or start of line | ||||
*/ | ||||
while ( ( (*key != '^') || (p == endprevline + 1) ) | ||||
&& (match = do_regexec(p)) ) | ||||
{ | ||||
if ( match > end ) | ||||
break; | ||||
lastmatch = match; | ||||
if ( *lastmatch == '\0' ) /* key must be "$" or "^" */ | ||||
break; | ||||
p = lastmatch + 1; /* character after match */ | ||||
} | ||||
} | ||||
*endp = savec; | ||||
if ( lastmatch != Most_Eob ) /* found a match */ | ||||
return(lastmatch); | ||||
endp = endprevline; | ||||
} | ||||
#else | ||||
char ch, char1, work[256]; | ||||
unsigned char *pos; | unsigned char *pos; | |||
int key_len,j, str_len; | int key_len,j, str_len; | |||
int cis; | ||||
if (Most_Case_Sensitive) | (void) st; | |||
{ | key_len = strlen ((char *)key); | |||
strcpy(work, (char *) key); | ||||
key_len = strlen((char *) key); | ||||
} | ||||
else | ||||
{ | ||||
/* upcase key */ | ||||
key_len = 0; | ||||
while (0 != (ch = key[key_len])) | ||||
{ | ||||
ch = UPCASE(ch); | ||||
work[key_len++] = ch; /* null char is ok */ | ||||
} | ||||
} | ||||
if (key_len == 0) return Most_Eob; | if (key_len == 0) return Most_Eob; | |||
str_len = (int) (end - beg); | str_len = (int) (end - beg); | |||
if (str_len < key_len) return Most_Eob; | if (str_len < key_len) return Most_Eob; | |||
# if 0 | ch1 = key[key_len-1]; | |||
str_len = str_len - key_len; /* effective length */ | ch1up = UPCASE(ch1); | |||
beg += key_len; | cis = (Most_Case_Sensitive == 0); | |||
# endif | ||||
char1 = work [key_len - 1]; | ||||
while (1) | while (1) | |||
{ | { | |||
while (1) | while (1) | |||
{ | { | |||
if (end < beg) | if (end < beg) | |||
return Most_Eob; | return Most_Eob; | |||
ch = *end--; | ch = *end--; | |||
ch = UPCASE (ch); | if ((ch == ch1) | |||
if (ch == char1) | || (cis && (ch1up == UPCASE(ch)))) | |||
break; | break; | |||
} | } | |||
pos = end; /* save this position so we start from here again */ | pos = end; /* save this position so we start from here again */ | |||
j = key_len - 2; | j = key_len - 2; | |||
while (1) | while (1) | |||
{ | { | |||
if (j < 0) | if (j < 0) | |||
return end + 1; | return end + 1; | |||
if (end < beg) | if (end < beg) | |||
break; | break; | |||
ch = *end--; | ch = *end--; | |||
if ((ch == 8) | if ((ch == 8) | |||
&& (end >= beg + 1) | && (end >= beg + 1) | |||
&& (Most_V_Opt == 0) | && (CHAR_EQS(key[j + 1], *end) | |||
&& ((work[j + 1] == UPCASE(*end)) | ||||
|| (*end == '_'))) | || (*end == '_'))) | |||
{ | { | |||
ch = *(end - 1); | ch = *(end - 1); | |||
end -= 2; | end -= 2; | |||
} | } | |||
else if ((ch == '_') | else if ((ch == '_') | |||
&& (end >= beg + 1) | && (end >= beg + 1)) | |||
&& (Most_V_Opt == 0)) | ||||
{ | { | |||
ch = *end--; | ch = *end--; | |||
if (ch == 8) ch = *end--; | if (ch == 8) ch = *end--; | |||
else | else | |||
{ | { | |||
ch = '_'; | ch = '_'; | |||
end++; | end++; | |||
} | } | |||
} | } | |||
else if ((ch == 'm') && is_rev_ansi_escape (beg, &end)) | ||||
continue; | ||||
if (UPCASE (ch) != work[j]) | if (!CHAR_EQS(ch, key[j])) | |||
break; | break; | |||
j--; | j--; | |||
} | } | |||
end = pos; | end = pos; | |||
} | } | |||
#endif /* HAVE_V8_REGCOMP || SLANG_REGEXP */ | ||||
} | } | |||
int most_search(unsigned char *from, int repeat, MOST_INT *col) | static int bs_open_search (Search_Type *st, char *key) | |||
{ | { | |||
/* return the line match was found as well as line number, | (void) key; | |||
* search from i on; assume that line_array match the i so we need | ||||
* no initial lookup */ | bs_search_init (); | |||
st->fsearch_method = bs_fsearch; | ||||
st->bsearch_method = bs_bsearch; | ||||
st->close_method = NULL; | ||||
st->cd = NULL; | ||||
return 0; | ||||
} | ||||
static unsigned char *sl_fsearch (Search_Type *st, | ||||
unsigned char *beg, unsigned char *end, | ||||
unsigned char *key) | ||||
{ | ||||
unsigned char *p; | ||||
(void) key; | ||||
if (NULL == (p = SLsearch_forward ((SLsearch_Type *)st->cd, beg, end))) | ||||
p = Most_Eob; | ||||
return p; | ||||
} | ||||
static unsigned char *sl_bsearch (Search_Type *st, | ||||
unsigned char *beg, unsigned char *end, | ||||
unsigned char *key) | ||||
{ | ||||
unsigned char *p; | ||||
(void) key; | ||||
if (NULL == (p = SLsearch_backward ((SLsearch_Type *)st->cd, beg, end, end))) | ||||
p = Most_Eob; | ||||
return p; | ||||
} | ||||
static void sl_search_close (Search_Type *st) | ||||
{ | ||||
if (st->cd != NULL) | ||||
SLsearch_delete ((SLsearch_Type *) st->cd); | ||||
} | ||||
static int sl_open_search (Search_Type *st, char *key) | ||||
{ | ||||
unsigned int flags = 0; | ||||
if (Most_Case_Sensitive == 0) flags |= SLSEARCH_CASELESS; | ||||
if (Most_UTF8_Mode) flags |= SLSEARCH_UTF8; | ||||
if (NULL == (st->cd = SLsearch_new ((SLuchar_Type *) key, flags))) | ||||
return -1; | ||||
st->fsearch_method = sl_fsearch; | ||||
st->bsearch_method = sl_bsearch; | ||||
st->close_method = sl_search_close; | ||||
return 0; | ||||
} | ||||
static int | ||||
do_search_internal (Search_Type *st, | ||||
unsigned char *from, int repeat, MOST_INT *col) | ||||
{ | ||||
/* return the line match was found as well as line number, | ||||
* search from i on; assume that line_array match the i so we need | ||||
* no initial lookup */ | ||||
int test; | int test; | |||
MOST_INT save_line, the_col, row, s_len; | MOST_INT save_line, the_col, row, s_len; | |||
char string[300]; | char string[300]; | |||
unsigned char *pos; | unsigned char *pos, *eob; | |||
unsigned int save_ofs; | unsigned int save_ofs; | |||
unsigned int found_ofs; | unsigned int found_ofs; | |||
if ((from < Most_Beg) || (from > Most_Eob)) return(-1); | if (*Most_Search_Str == 0) | |||
{ | ||||
most_message("Search string not specified.",1); | ||||
return -1; | ||||
} | ||||
if ((from < Most_Beg) || (from > Most_Eob)) return -1; | ||||
save_ofs = Most_C_Offset; | save_ofs = Most_C_Offset; | |||
save_line = Most_C_Line; | save_line = Most_C_Line; | |||
found_ofs = Most_Eob - Most_Beg; | found_ofs = Most_Eob - Most_Beg; | |||
*col = 0; | *col = 0; | |||
s_len = strlen (Most_Search_Str); | s_len = strlen (Most_Search_Str); | |||
pos = from; | pos = from; | |||
if (*Most_Search_Str) | eob = Most_Eob; | |||
test = repeat && (pos < Most_Eob) && (pos >= Most_Beg); | ||||
while(test) | ||||
{ | { | |||
test = repeat && (pos < Most_Eob) && (pos >= Most_Beg); | if (Most_Search_Dir == 1) | |||
while(test) | ||||
{ | { | |||
if (Most_Search_Dir == 1) | while (1) | |||
{ | { | |||
while (1) | unsigned int pos_ofs; | |||
{ | ||||
unsigned int pos_ofs; | ||||
pos = forw_search_region(pos, Most_Eob, (unsigned char*) M | pos = (*st->fsearch_method)(st, pos, Most_Eob, (unsigned char*) | |||
ost_Search_Str); | Most_Search_Str); | |||
pos_ofs = (unsigned int) (Most_Eob - Most_Beg); | pos_ofs = (unsigned int) (Most_Eob - Most_Beg); | |||
if (pos < Most_Eob) | if (pos < Most_Eob) | |||
break; | break; | |||
if (0 == most_read_file_dsc (10)) | if (0 == most_read_file_dsc (10, 0)) | |||
{ | { | |||
/* Pointer may be invalid after this call */ | /* Pointer may be invalid after this call */ | |||
pos = Most_Beg + pos_ofs; | pos = Most_Beg + pos_ofs; | |||
break; | break; | |||
} | ||||
/* This might need an adjustment */ | ||||
pos = Most_Beg + (pos_ofs - s_len); | ||||
if (pos < Most_Beg) pos = Most_Beg; | ||||
} | } | |||
} | ||||
else | ||||
pos = back_search_region(Most_Beg, pos, | ||||
(unsigned char *) Most_Search_Str); | ||||
if (pos < Most_Eob) | /* This might need an adjustment */ | |||
{ | pos = Most_Beg + (pos_ofs - s_len); | |||
repeat--; | if (pos < Most_Beg) pos = Most_Beg; | |||
found_ofs = pos - Most_Beg; | ||||
if (Most_Search_Dir == 1) | ||||
pos += s_len; | ||||
else pos--; | ||||
} | } | |||
test = repeat && (pos < Most_Eob) && (pos >= Most_Beg); | } | |||
else | ||||
pos = (*st->bsearch_method)(st, Most_Beg, pos, (unsigned char *) Most_S | ||||
earch_Str); | ||||
if (pos < Most_Eob) | ||||
{ | ||||
repeat--; | ||||
found_ofs = pos - Most_Beg; | ||||
if (Most_Search_Dir == 1) | ||||
pos += s_len; | ||||
else pos--; | ||||
} | ||||
test = repeat && (pos < Most_Eob) && (pos >= Most_Beg); | ||||
if (SLKeyBoard_Quit) | ||||
{ | ||||
most_message ("Search Interrupted.", 1); | ||||
break; | ||||
} | } | |||
} | } | |||
if (eob != Most_Eob) | ||||
Most_Num_Lines = most_count_lines (Most_Beg, Most_Eob); | ||||
if (repeat) /* not found */ | if (repeat) /* not found */ | |||
{ | { | |||
*col = 0; | *col = 0; | |||
#if defined(HAVE_V8_REGCOMP) || defined(SLANG_REGEXP) | ||||
if ( regcompOK ) /* don't print error msg if regerr msg */ | ||||
{ | ||||
#endif | ||||
if (Most_Search_Str[0] == '\0') | ||||
most_message("Search string not specified.",1); | ||||
else | ||||
{ | ||||
(void) sprintf(string,"Search failed: %s",Most_Search_Str); | ||||
most_message(string,1); | ||||
} | ||||
#if defined(HAVE_V8_REGCOMP) || defined(SLANG_REGEXP) | ||||
} | ||||
#endif | ||||
(void) sprintf(string,"Search failed: %s",Most_Search_Str); | ||||
most_message(string,1); | ||||
row = -1; | row = -1; | |||
} | } | |||
else /* if ( !Most_T_Opt && !Most_B_Opt) */ /* expand tabs to get col corre ct */ | else /* if ( !Most_T_Opt && !Most_B_Opt) */ /* expand tabs to get col corre ct */ | |||
{ | { | |||
most_find_row_column(Most_Beg + found_ofs, &row, &the_col); | most_find_row_column(Most_Beg + found_ofs, &row, &the_col); | |||
if (Most_B_Opt) *col = the_col + 52; | if (Most_B_Opt) *col = the_col + 52; | |||
else | else | |||
*col = 1 + most_apparant_distance(Most_Beg + found_ofs); | *col = 1 + most_apparant_distance(Most_Beg + found_ofs); | |||
} | } | |||
Most_C_Offset = save_ofs; | Most_C_Offset = save_ofs; | |||
Most_C_Line = save_line; | Most_C_Line = save_line; | |||
if (row > 0) Most_Curs_Offset = found_ofs; | if (row > 0) Most_Curs_Offset = found_ofs; | |||
return row; | return row; | |||
} | } | |||
static int search_internal (Search_Type *st, unsigned char *from, int repeat, MO | ||||
ST_INT *colp) | ||||
{ | ||||
int status; | ||||
status = do_search_internal (st, from, repeat, colp); | ||||
if (st->close_method != NULL) | ||||
(st->close_method)(st); | ||||
return status; | ||||
} | ||||
static int simple_search (unsigned char *from, int repeat, MOST_INT *colp) | ||||
{ | ||||
Search_Type st; | ||||
if (Most_V_Opt || Most_B_Opt) | ||||
{ | ||||
/* Nothing special about the ^H and _ chars. User faster SLsearch */ | ||||
if (-1 == sl_open_search (&st, Most_Search_Str)) | ||||
return -1; | ||||
} | ||||
else if (-1 == bs_open_search (&st, Most_Search_Str)) | ||||
return -1; | ||||
return search_internal (&st, from, repeat, colp); | ||||
} | ||||
static void re_search_close (Search_Type *st) | ||||
{ | ||||
if (st->cd != NULL) | ||||
SLregexp_free ((SLRegexp_Type *) st->cd); | ||||
} | ||||
static unsigned char * | ||||
re_fsearch (Search_Type *st, | ||||
unsigned char *beg, unsigned char *end, | ||||
unsigned char *key) | ||||
{ | ||||
SLRegexp_Type *re; | ||||
unsigned char *p; | ||||
unsigned int flags; | ||||
(void) key; | ||||
re = (SLRegexp_Type *)st->cd; | ||||
(void) SLregexp_get_hints (re, &flags); | ||||
while (beg < end) | ||||
{ | ||||
unsigned char *line_end = beg; | ||||
while (line_end < end) | ||||
{ | ||||
unsigned char ch = *line_end++; | ||||
if (ch == '\n') break; | ||||
} | ||||
p = (unsigned char *)SLregexp_match (re, (char *)beg, (line_end - beg)); | ||||
if (p != NULL) | ||||
{ | ||||
if ((0 == (flags & SLREGEXP_HINT_BOL)) | ||||
|| (p != beg) | ||||
|| (beg == Most_Beg) | ||||
|| (*(beg - 1) == '\n')) | ||||
return p; | ||||
} | ||||
beg = line_end; | ||||
} | ||||
return Most_Eob; | ||||
} | ||||
static unsigned char * | ||||
re_bsearch (Search_Type *st, | ||||
unsigned char *beg, unsigned char *end, | ||||
unsigned char *key) | ||||
{ | ||||
SLRegexp_Type *re; | ||||
unsigned char *line_end, *eob; | ||||
unsigned int flags; | ||||
(void) key; | ||||
re = (SLRegexp_Type *)st->cd; | ||||
(void) SLregexp_get_hints (re, &flags); | ||||
line_end = end; | ||||
eob = Most_Eob; | ||||
while (line_end < eob) | ||||
{ | ||||
if (*line_end == '\n') | ||||
break; | ||||
line_end++; | ||||
} | ||||
while (end > beg) | ||||
{ | ||||
unsigned char *p, *match; | ||||
unsigned char *line = end; | ||||
while (line > beg) | ||||
{ | ||||
line--; | ||||
if (*line == '\n') | ||||
{ | ||||
line++; | ||||
break; | ||||
} | ||||
} | ||||
/* line is now at the start of a line */ | ||||
if (NULL != (match = (unsigned char *)SLregexp_match (re, (char *)line, l | ||||
ine_end-line))) | ||||
{ | ||||
if (match >= end) | ||||
{ | ||||
/* Match occurs to right of boundary. Try previous line */ | ||||
end = line_end = line-1; | ||||
continue; | ||||
} | ||||
if (flags & SLREGEXP_HINT_BOL) | ||||
return match; | ||||
/* t tt z t t t z */ | ||||
/* Find match closest to end */ | ||||
while ((line < end) | ||||
&& (NULL != (p = (unsigned char *)SLregexp_match (re, (char * | ||||
)line, (line_end - line)))) | ||||
&& (p < end)) | ||||
{ | ||||
match = p; | ||||
line++; | ||||
} | ||||
return match; | ||||
} | ||||
end = line-1; | ||||
line_end = end; | ||||
} | ||||
return Most_Eob; | ||||
} | ||||
static int regexp_search (unsigned char *from, int repeat, MOST_INT *colp) | ||||
{ | ||||
Search_Type st; | ||||
SLRegexp_Type *re; | ||||
char *pattern; | ||||
unsigned int flags; | ||||
pattern = Most_Search_Str; | ||||
flags = 0; | ||||
if (Most_Case_Sensitive == 0) flags |= SLREGEXP_CASELESS; | ||||
re = SLregexp_compile (pattern, flags); | ||||
if (re == NULL) | ||||
return -1; | ||||
(void) SLregexp_get_hints (re, &flags); | ||||
if (flags & SLREGEXP_HINT_OSEARCH) | ||||
{ | ||||
SLregexp_free (re); | ||||
return simple_search (from, repeat, colp); | ||||
} | ||||
st.cd = (void *)re; | ||||
st.fsearch_method = re_fsearch; | ||||
st.bsearch_method = re_bsearch; | ||||
st.close_method = re_search_close; | ||||
return search_internal (&st, from, repeat, colp); | ||||
} | ||||
int most_search (unsigned char *from, int repeat, MOST_INT *colp) | ||||
{ | ||||
if (Most_Do_Regexp_Search) | ||||
return regexp_search (from, repeat, colp); | ||||
return simple_search (from, repeat, colp); | ||||
} | ||||
End of changes. 79 change blocks. | ||||
523 lines changed or deleted | 237 lines changed or added |