[BACK]Return to search.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / less

Diff for /src/usr.bin/less/search.c between version 1.5 and 1.6

version 1.5, 2003/04/13 18:26:26 version 1.6, 2011/09/16 18:12:09
Line 1 
Line 1 
 /*  /*
  * Copyright (C) 1984-2002  Mark Nudelman   * Copyright (C) 1984-2011  Mark Nudelman
  *   *
  * You may distribute under the terms of either the GNU General Public   * You may distribute under the terms of either the GNU General Public
  * License or the Less License, as specified in the README file.   * License or the Less License, as specified in the README file.
Line 14 
Line 14 
  */   */
   
 #include "less.h"  #include "less.h"
   #include "pattern.h"
 #include "position.h"  #include "position.h"
   #include "charset.h"
   
 #define MINPOS(a,b)     (((a) < (b)) ? (a) : (b))  #define MINPOS(a,b)     (((a) < (b)) ? (a) : (b))
 #define MAXPOS(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 sigs;
 extern int how_search;  extern int how_search;
 extern int caseless;  extern int caseless;
Line 54 
Line 30 
 extern int bs_mode;  extern int bs_mode;
 extern int ctldisp;  extern int ctldisp;
 extern int status_col;  extern int status_col;
   extern void * constant ml_search;
 extern POSITION start_attnpos;  extern POSITION start_attnpos;
 extern POSITION end_attnpos;  extern POSITION end_attnpos;
   extern int utf_mode;
   extern int screen_trashed;
 #if HILITE_SEARCH  #if HILITE_SEARCH
 extern int hilite_search;  extern int hilite_search;
 extern int screen_trashed;  
 extern int size_linebuf;  extern int size_linebuf;
 extern int squished;  extern int squished;
 extern int can_goto_line;  extern int can_goto_line;
 static int hide_hilite;  static int hide_hilite;
 static POSITION prep_startpos;  static POSITION prep_startpos;
 static POSITION prep_endpos;  static POSITION prep_endpos;
   static int is_caseless;
   static int is_ucase_pattern;
   
 struct hilite  struct hilite
 {  {
Line 73 
Line 53 
         POSITION hl_endpos;          POSITION hl_endpos;
 };  };
 static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };  static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
   static struct hilite filter_anchor = { NULL, NULL_POSITION, NULL_POSITION };
 #define hl_first        hl_next  #define hl_first        hl_next
 #endif  #endif
   
 /*  /*
  * These are the static variables that represent the "remembered"   * These are the static variables that represent the "remembered"
  * search pattern.   * search pattern and filter pattern.
  */   */
 #if HAVE_POSIX_REGCOMP  struct pattern_info {
 static regex_t *regpattern = NULL;          DEFINE_PATTERN(compiled);
 #endif          char* text;
 #if HAVE_PCRE          int search_type;
 pcre *regpattern = NULL;  };
 #endif  
 #if HAVE_RE_COMP  static struct pattern_info search_info;
 int re_pattern = 0;  static struct pattern_info filter_info;
 #endif  
 #if HAVE_REGCMP  
 static char *cpattern = NULL;  
 #endif  
 #if HAVE_V8_REGCOMP  
 static struct regexp *regpattern = NULL;  
 #endif  
   
 static int is_caseless;  /*
 static int is_ucase_pattern;   * Are there any uppercase letters in this string?
 static int last_search_type;   */
 static char *last_pattern = NULL;          static int
   is_ucase(str)
           char *str;
   {
           char *str_end = str + strlen(str);
           LWCHAR ch;
   
           while (str < str_end)
           {
                   ch = step_char(&str, +1, str_end);
                   if (IS_UPPER(ch))
                           return (1);
           }
           return (0);
   }
   
 /*  /*
  * Convert text.  Perform one or more of these transformations:   * Compile and save a search pattern.
  */   */
 #define CVT_TO_LC       01      /* Convert upper-case to lower-case */          static int
 #define CVT_BS          02      /* Do backspace processing */  set_pattern(info, pattern, search_type)
 #define CVT_CRLF        04      /* Remove CR after LF */          struct pattern_info *info;
 #define CVT_ANSI        010     /* Remove ANSI escape sequences */          char *pattern;
           int search_type;
   {
           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 = save(pattern);
           info->search_type = search_type;
   
           /*
            * Ignore case if -I is set OR
            * -i is set AND the pattern is all lowercase.
            */
           is_ucase_pattern = is_ucase(pattern);
           if (is_ucase_pattern && caseless != OPT_ONPLUS)
                   is_caseless = 0;
           else
                   is_caseless = caseless;
           return 0;
   }
   
   /*
    * Discard a saved pattern.
    */
         static void          static void
 cvt_text(odst, osrc, ops)  clear_pattern(info)
         char *odst;          struct pattern_info *info;
         char *osrc;  
         int ops;  
 {  {
         register char *dst;          if (info->text != NULL)
         register char *src;                  free(info->text);
           info->text = NULL;
           uncompile_pattern(&info->compiled);
   }
   
         for (src = osrc, dst = odst;  *src != '\0';  src++)  /*
         {   * Initialize saved pattern to nothing.
                 if ((ops & CVT_TO_LC) && isupper((unsigned char) *src))   */
                         /* Convert uppercase to lowercase. */          static void
                         *dst++ = tolower((unsigned char) *src);  init_pattern(info)
                 else if ((ops & CVT_BS) && *src == '\b' && dst > odst)          struct pattern_info *info;
                         /* Delete BS and preceding char. */  {
                         dst--;          CLEAR_PATTERN(info->compiled);
                 else if ((ops & CVT_ANSI) && *src == ESC)          info->text = NULL;
                 {          info->search_type = 0;
                         /* Skip to end of ANSI escape sequence. */  
                         while (src[1] != '\0')  
                                 if (is_ansi_end(*++src))  
                                         break;  
                 } else  
                         /* Just copy. */  
                         *dst++ = *src;  
         }  
         if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')  
                 dst--;  
         *dst = '\0';  
 }  }
   
 /*  /*
  * Determine which conversions to perform.   * Initialize search variables.
  */   */
           public void
   init_search()
   {
           init_pattern(&search_info);
           init_pattern(&filter_info);
   }
   
   /*
    * Determine which text conversions to perform before pattern matching.
    */
         static int          static int
 get_cvt_ops()  get_cvt_ops()
 {  {
Line 166 
Line 182 
 }  }
   
 /*  /*
  * Are there any uppercase letters in this string?  
  */  
         static int  
 is_ucase(s)  
         char *s;  
 {  
         register char *p;  
   
         for (p = s;  *p != '\0';  p++)  
                 if (isupper((unsigned char) *p))  
                         return (1);  
         return (0);  
 }  
   
 /*  
  * Is there a previous (remembered) search pattern?   * Is there a previous (remembered) search pattern?
  */   */
         static int          static int
 prev_pattern()  prev_pattern(info)
           struct pattern_info *info;
 {  {
         if (last_search_type & SRCH_NO_REGEX)          if (info->search_type & SRCH_NO_REGEX)
                 return (last_pattern != NULL);                  return (info->text != NULL);
 #if HAVE_POSIX_REGCOMP          return (!is_null_pattern(info->compiled));
         return (regpattern != NULL);  
 #endif  
 #if HAVE_PCRE  
         return (regpattern != NULL);  
 #endif  
 #if HAVE_RE_COMP  
         return (re_pattern != 0);  
 #endif  
 #if HAVE_REGCMP  
         return (cpattern != NULL);  
 #endif  
 #if HAVE_V8_REGCOMP  
         return (regpattern != NULL);  
 #endif  
 #if NO_REGEX  
         return (last_pattern != NULL);  
 #endif  
 }  }
   
 #if HILITE_SEARCH  #if HILITE_SEARCH
Line 247 
Line 232 
                 if (pos == NULL_POSITION)                  if (pos == NULL_POSITION)
                         continue;                          continue;
                 epos = position(slinenum+1);                  epos = position(slinenum+1);
                 /*                  (void) forw_line(pos);
                  * If any character in the line is highlighted,                  goto_line(slinenum);
                  * repaint the line.                  put_line();
                  */  
                 if (is_hilited(pos, epos, 1))  
                 {  
                         (void) forw_line(pos);  
                         goto_line(slinenum);  
                         put_line();  
                 }  
         }          }
           lower_left();
         hide_hilite = save_hide_hilite;          hide_hilite = save_hide_hilite;
 }  }
   
Line 272 
Line 251 
         POSITION old_end_attnpos;          POSITION old_end_attnpos;
         POSITION pos;          POSITION pos;
         POSITION epos;          POSITION epos;
           int moved = 0;
   
         if (start_attnpos == NULL_POSITION)          if (start_attnpos == NULL_POSITION)
                 return;                  return;
Line 299 
Line 279 
                         (void) forw_line(pos);                          (void) forw_line(pos);
                         goto_line(slinenum);                          goto_line(slinenum);
                         put_line();                          put_line();
                           moved = 1;
                 }                  }
         }          }
           if (moved)
                   lower_left();
 }  }
 #endif  #endif
   
Line 310 
Line 293 
         public void          public void
 undo_search()  undo_search()
 {  {
         if (!prev_pattern())          if (!prev_pattern(&search_info))
         {          {
                 error("No previous regular expression", NULL_PARG);                  error("No previous regular expression", NULL_PARG);
                 return;                  return;
Line 321 
Line 304 
 #endif  #endif
 }  }
   
   #if HILITE_SEARCH
 /*  /*
  * Compile a search pattern, for future use by match_pattern.   * Clear the hilite list.
  */   */
         static int          public void
 compile_pattern(pattern, search_type)  clr_hlist(anchor)
         char *pattern;          struct hilite *anchor;
         int search_type;  
 {  {
         if ((search_type & SRCH_NO_REGEX) == 0)          struct hilite *hl;
           struct hilite *nexthl;
   
           for (hl = anchor->hl_first;  hl != NULL;  hl = nexthl)
         {          {
 #if HAVE_POSIX_REGCOMP                  nexthl = hl->hl_next;
                 regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));                  free((void*)hl);
                 if (regcomp(s, pattern, REGCOMP_FLAG))  
                 {  
                         free(s);  
                         error("Invalid pattern", NULL_PARG);  
                         return (-1);  
                 }  
                 if (regpattern != NULL)  
                         regfree(regpattern);  
                 regpattern = s;  
 #endif  
 #if HAVE_PCRE  
                 pcre *comp;  
                 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);  
                 }  
                 regpattern = comp;  
 #endif  
 #if HAVE_RE_COMP  
                 PARG parg;  
                 if ((parg.p_string = re_comp(pattern)) != NULL)  
                 {  
                         error("%s", &parg);  
                         return (-1);  
                 }  
                 re_pattern = 1;  
 #endif  
 #if HAVE_REGCMP  
                 char *s;  
                 if ((s = regcmp(pattern, 0)) == NULL)  
                 {  
                         error("Invalid pattern", NULL_PARG);  
                         return (-1);  
                 }  
                 if (cpattern != NULL)  
                         free(cpattern);  
                 cpattern = s;  
 #endif  
 #if HAVE_V8_REGCOMP  
                 struct regexp *s;  
                 if ((s = regcomp(pattern)) == NULL)  
                 {  
                         /*  
                          * regcomp has already printed an error message  
                          * via regerror().  
                          */  
                         return (-1);  
                 }  
                 if (regpattern != NULL)  
                         free(regpattern);  
                 regpattern = s;  
 #endif  
         }          }
           anchor->hl_first = NULL;
           prep_startpos = prep_endpos = NULL_POSITION;
   }
   
         if (last_pattern != NULL)          public void
                 free(last_pattern);  clr_hilite()
         last_pattern = save(pattern);  {
           clr_hlist(&hilite_anchor);
         last_search_type = search_type;  
         return (0);  
 }  }
   
 /*          public void
  * Forget that we have a compiled pattern.  clr_filter()
  */  
         static void  
 uncompile_pattern()  
 {  {
 #if HAVE_POSIX_REGCOMP          clr_hlist(&filter_anchor);
         if (regpattern != NULL)  
                 regfree(regpattern);  
         regpattern = NULL;  
 #endif  
 #if HAVE_PCRE  
         if (regpattern != NULL)  
                 pcre_free(regpattern);  
         regpattern = NULL;  
 #endif  
 #if HAVE_RE_COMP  
         re_pattern = 0;  
 #endif  
 #if HAVE_REGCMP  
         if (cpattern != NULL)  
                 free(cpattern);  
         cpattern = NULL;  
 #endif  
 #if HAVE_V8_REGCOMP  
         if (regpattern != NULL)  
                 free(regpattern);  
         regpattern = NULL;  
 #endif  
         last_pattern = NULL;  
 }  }
   
 /*  /*
  * Perform a pattern match with the previously compiled pattern.   * Should any characters in a specified range be highlighted?
  * Set sp and ep to the start and end of the matched string.  
  */   */
         static int          static int
 match_pattern(line, sp, ep, notbol)  is_hilited_range(pos, epos)
         char *line;          POSITION pos;
         char **sp;          POSITION epos;
         char **ep;  
         int notbol;  
 {  {
         int matched;          struct hilite *hl;
   
         if (last_search_type & SRCH_NO_REGEX)  
                 return (match(last_pattern, line, sp, ep));  
   
 #if HAVE_POSIX_REGCOMP  
         {  
                 regmatch_t rm;  
                 int flags = (notbol) ? REG_NOTBOL : 0;  
                 matched = !regexec(regpattern, line, 1, &rm, flags);  
                 if (!matched)  
                         return (0);  
 #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(regpattern, NULL, line, strlen(line),  
                         0, flags, ovector, 3) >= 0;  
                 if (!matched)  
                         return (0);  
                 *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.           * Look at each highlight and see if any part of it falls in the range.
          */           */
         *sp = *ep = NULL;          for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
 #endif          {
 #if HAVE_REGCMP                  if (hl->hl_endpos > pos &&
         *ep = regex(cpattern, line);                      (epos == NULL_POSITION || epos > hl->hl_startpos))
         matched = (*ep != NULL);                          return (1);
         if (!matched)          }
                 return (0);          return (0);
         *sp = __loc1;  
 #endif  
 #if HAVE_V8_REGCOMP  
 #if HAVE_REGEXEC2  
         matched = regexec2(regpattern, line, notbol);  
 #else  
         matched = regexec(regpattern, line);  
 #endif  
         if (!matched)  
                 return (0);  
         *sp = regpattern->startp[0];  
         *ep = regpattern->endp[0];  
 #endif  
 #if NO_REGEX  
         matched = match(last_pattern, line, sp, ep);  
 #endif  
         return (matched);  
 }  }
   
 #if HILITE_SEARCH  /*
 /*   * Is a line "filtered" -- that is, should it be hidden?
  * Clear the hilite list.  
  */   */
         public void          public int
 clr_hilite()  is_filtered(pos)
           POSITION pos;
 {  {
         struct hilite *hl;          struct hilite *hl;
         struct hilite *nexthl;  
   
         for (hl = hilite_anchor.hl_first;  hl != NULL;  hl = nexthl)          if (ch_getflags() & CH_HELPFILE)
                   return (0);
   
           /*
            * Look at each filter and see if the start position
            * equals the start position of the line.
            */
           for (hl = filter_anchor.hl_first;  hl != NULL;  hl = hl->hl_next)
         {          {
                 nexthl = hl->hl_next;                  if (hl->hl_startpos == pos)
                 free((void*)hl);                          return (1);
         }          }
         hilite_anchor.hl_first = NULL;          return (0);
         prep_startpos = prep_endpos = NULL_POSITION;  
 }  }
   
 /*  /*
Line 533 
Line 387 
  * If nohide is nonzero, don't consider hide_hilite.   * If nohide is nonzero, don't consider hide_hilite.
  */   */
         public int          public int
 is_hilited(pos, epos, nohide)  is_hilited(pos, epos, nohide, p_matches)
         POSITION pos;          POSITION pos;
         POSITION epos;          POSITION epos;
         int nohide;          int nohide;
           int *p_matches;
 {  {
         struct hilite *hl;          int match;
   
           if (p_matches != NULL)
                   *p_matches = 0;
   
         if (!status_col &&          if (!status_col &&
             start_attnpos != NULL_POSITION &&              start_attnpos != NULL_POSITION &&
             pos < end_attnpos &&              pos < end_attnpos &&
Line 549 
Line 407 
                  */                   */
                 return (1);                  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)          if (hilite_search == 0)
                 /*                  /*
                  * Not doing highlighting.                   * Not doing highlighting.
Line 561 
Line 429 
                  */                   */
                 return (0);                  return (0);
   
         /*          return (1);
          * 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);  
 }  }
   
 /*  /*
Line 614 
Line 473 
 }  }
   
 /*  /*
  * Adjust hl_startpos & hl_endpos to account for backspace processing.  
  */  
         static void  
 adj_hilite(anchor, linepos, cvt_ops)  
         struct hilite *anchor;  
         POSITION linepos;  
         int cvt_ops;  
 {  
         char *line;  
         struct hilite *hl;  
         int checkstart;  
         POSITION opos;  
         POSITION npos;  
   
         /*  
          * 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 there are backspaces in the line.  
          * Get the raw line again.  Look at each character.  
          */  
         (void) forw_raw_line(linepos, &line);  
         opos = npos = linepos;  
         hl = anchor->hl_first;  
         checkstart = TRUE;  
         while (hl != NULL)  
         {  
                 /*  
                  * 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.  
                  */  
                 if (checkstart && hl->hl_startpos == opos)  
                 {  
                         hl->hl_startpos = npos;  
                         checkstart = FALSE;  
                         continue; /* {{ not really necessary }} */  
                 } else if (!checkstart && hl->hl_endpos == opos)  
                 {  
                         hl->hl_endpos = npos;  
                         checkstart = TRUE;  
                         hl = hl->hl_next;  
                         continue; /* {{ necessary }} */  
                 }  
                 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;  
                                 }  
                         }  
                 }  
                 opos++;  
                 npos++;  
                 line++;  
                 if (cvt_ops & CVT_BS)  
                 {  
                         while (line[0] == '\b' && line[1] != '\0')  
                         {  
                                 /*  
                                  * 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;  
                         }  
                 }  
         }  
 }  
   
 /*  
  * Make a hilite for each string in a physical line which matches   * Make a hilite for each string in a physical line which matches
  * the current pattern.   * the current pattern.
  * sp,ep delimit the first match already found.   * sp,ep delimit the first match already found.
  */   */
         static void          static void
 hilite_line(linepos, line, sp, ep, cvt_ops)  hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops)
         POSITION linepos;          POSITION linepos;
         char *line;          char *line;
           int line_len;
           int *chpos;
         char *sp;          char *sp;
         char *ep;          char *ep;
         int cvt_ops;          int cvt_ops;
 {  {
         char *searchp;          char *searchp;
           char *line_end = line + line_len;
         struct hilite *hl;          struct hilite *hl;
         struct hilite hilites;  
   
         if (sp == NULL || ep == NULL)          if (sp == NULL || ep == NULL)
                 return;                  return;
Line 726 
Line 501 
          *    substrings of the line, may mark more than is correct           *    substrings of the line, may mark more than is correct
          *    if the pattern starts with "^".  This bug is fixed           *    if the pattern starts with "^".  This bug is fixed
          *    for those regex functions that accept a notbol parameter           *    for those regex functions that accept a notbol parameter
          *    (currently POSIX and V8-with-regexec2). }}           *    (currently POSIX, PCRE and V8-with-regexec2). }}
          */           */
         searchp = line;          searchp = line;
         /*  
          * Put the hilites into a temporary list until they're adjusted.  
          */  
         hilites.hl_first = NULL;  
         do {          do {
                 if (ep > sp)                  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 = (struct hilite *) ecalloc(1, sizeof(struct hilite));
                         hl->hl_startpos = linepos + (sp-line);                          hl->hl_startpos = linepos + chpos[sp-line];
                         hl->hl_endpos = linepos + (ep-line);                          hl->hl_endpos = linepos + chpos[ep-line];
                         add_hilite(&hilites, hl);                          add_hilite(&hilite_anchor, hl);
                 }                  }
                 /*                  /*
                  * If we matched more than zero characters,                   * If we matched more than zero characters,
Line 753 
Line 519 
                  */                   */
                 if (ep > searchp)                  if (ep > searchp)
                         searchp = ep;                          searchp = ep;
                 else if (*searchp != '\0')                  else if (searchp != line_end)
                         searchp++;                          searchp++;
                 else /* end of line */                  else /* end of line */
                         break;                          break;
         } while (match_pattern(searchp, &sp, &ep, 1));          } while (match_pattern(search_info.compiled, search_info.text,
                           searchp, line_end - searchp, &sp, &ep, 1, search_info.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);  
         }  
 }  }
 #endif  #endif
   
Line 795 
Line 546 
                  * Pattern did have uppercase.                   * Pattern did have uppercase.
                  * Discard the pattern; we can't change search caselessness now.                   * Discard the pattern; we can't change search caselessness now.
                  */                   */
                 uncompile_pattern();                  clear_pattern(&search_info);
 }  }
   
 #if HILITE_SEARCH  #if HILITE_SEARCH
Line 855 
Line 606 
                  */                   */
                 if (search_type & SRCH_FORW)                  if (search_type & SRCH_FORW)
                 {                  {
                         return (ch_zero());                          pos = ch_zero();
                 } else                  } else
                 {                  {
                         pos = ch_length();                          pos = ch_length();
Line 864 
Line 615 
                                 (void) ch_end_seek();                                  (void) ch_end_seek();
                                 pos = ch_length();                                  pos = ch_length();
                         }                          }
                         return (pos);  
                 }                  }
         }                  linenum = 0;
         if (how_search)          } else
         {          {
                 /*                  int add_one = 0;
                  * Search does not include current screen.  
                  */                  if (how_search == OPT_ON)
                 if (search_type & SRCH_FORW)  
                         linenum = BOTTOM_PLUS_ONE;  
                 else  
                         linenum = TOP;  
                 pos = position(linenum);  
         } else  
         {  
                 /*  
                  * Search includes current screen.  
                  * It starts at the jump target (if searching backwards),  
                  * or at the jump target plus one (if forwards).  
                  */  
                 linenum = adjsline(jump_sline);  
                 pos = position(linenum);  
                 if (search_type & SRCH_FORW)  
                 {                  {
                         pos = forw_raw_line(pos, (char **)NULL);                          /*
                         while (pos == NULL_POSITION)                           * Search does not include current screen.
                         {                           */
                                 if (++linenum >= sc_height)                          if (search_type & SRCH_FORW)
                                         break;                                  linenum = BOTTOM_PLUS_ONE;
                                 pos = position(linenum);                          else
                         }                                  linenum = TOP;
                   } else if (how_search == OPT_ONPLUS && !(search_type & SRCH_AFTER_TARGET))
                   {
                           /*
                            * Search includes all of displayed screen.
                            */
                           if (search_type & SRCH_FORW)
                                   linenum = TOP;
                           else
                                   linenum = BOTTOM_PLUS_ONE;
                 } else                  } else
                 {                  {
                         while (pos == NULL_POSITION)                          /*
                         {                           * Search includes the part of current screen beyond the jump target.
                                 if (--linenum < 0)                           * It starts at the jump target (if searching backwards),
                                         break;                           * or at the jump target plus one (if forwards).
                                 pos = position(linenum);                           */
                         }                          linenum = jump_sline;
                           if (search_type & SRCH_FORW)
                               add_one = 1;
                 }                  }
                   linenum = adjsline(linenum);
                   pos = position(linenum);
                   if (add_one)
                           pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
         }          }
   
           /*
            * If the line is empty, look around for a plausible starting place.
            */
           if (search_type & SRCH_FORW)
           {
               while (pos == NULL_POSITION)
               {
                   if (++linenum >= sc_height)
                       break;
                   pos = position(linenum);
               }
           } else
           {
               while (pos == NULL_POSITION)
               {
                   if (--linenum < 0)
                       break;
                   pos = position(linenum);
               }
           }
         return (pos);          return (pos);
 }  }
   
Line 922 
Line 693 
         POSITION *pendpos;          POSITION *pendpos;
 {  {
         char *line;          char *line;
           char *cline;
           int line_len;
         LINENUM linenum;          LINENUM linenum;
         char *sp, *ep;          char *sp, *ep;
         int line_match;          int line_match;
         int cvt_ops;          int cvt_ops;
           int cvt_len;
           int *chpos;
         POSITION linepos, oldpos;          POSITION linepos, oldpos;
   
         linenum = find_linenum(pos);          linenum = find_linenum(pos);
Line 964 
Line 739 
                          * starting position of that line in linepos.                           * starting position of that line in linepos.
                          */                           */
                         linepos = pos;                          linepos = pos;
                         pos = forw_raw_line(pos, &line);                          pos = forw_raw_line(pos, &line, &line_len);
                         if (linenum != 0)                          if (linenum != 0)
                                 linenum++;                                  linenum++;
                 } else                  } else
Line 973 
Line 748 
                          * Read the previous line and save the                           * Read the previous line and save the
                          * starting position of that line in linepos.                           * starting position of that line in linepos.
                          */                           */
                         pos = back_raw_line(pos, &line);                          pos = back_raw_line(pos, &line, &line_len);
                         linepos = pos;                          linepos = pos;
                         if (linenum != 0)                          if (linenum != 0)
                                 linenum--;                                  linenum--;
Line 997 
Line 772 
                  * the search.  Remember the line number only if                   * the search.  Remember the line number only if
                  * we're "far" from the last place we remembered it.                   * 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);                          add_lnum(linenum, pos);
                 oldpos = pos;                  oldpos = pos;
   
                   if (is_filtered(linepos))
                           continue;
   
                 /*                  /*
                  * If it's a caseless search, convert the line to lowercase.                   * If it's a caseless search, convert the line to lowercase.
                  * If we're doing backspace processing, delete backspaces.                   * If we're doing backspace processing, delete backspaces.
                  */                   */
                 cvt_ops = get_cvt_ops();                  cvt_ops = get_cvt_ops();
                 cvt_text(line, line, 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) && 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 *)
                                           ecalloc(1, sizeof(struct hilite));
                                   hl->hl_startpos = linepos;
                                   hl->hl_endpos = pos;
                                   add_hilite(&filter_anchor, hl);
                           }
                   }
   #endif
   
                   /*
                  * Test the next line to see if we have a match.                   * Test the next line to see if we have a match.
                  * We are successful if we either want a match and got one,                   * We are successful if we either want a match and got one,
                  * or if we want a non-match and got one.                   * or if we want a non-match and got one.
                  */                   */
                 line_match = match_pattern(line, &sp, &ep, 0);                  if (prev_pattern(&search_info))
                 line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||  
                                 ((search_type & SRCH_NO_MATCH) && !line_match);  
                 if (!line_match)  
                         continue;  
                 /*  
                  * Got a match.  
                  */  
                 if (search_type & SRCH_FIND_ALL)  
                 {                  {
 #if HILITE_SEARCH                          line_match = match_pattern(search_info.compiled, search_info.text,
                         /*                                  cline, line_len, &sp, &ep, 0, search_type);
                          * We are supposed to find all matches in the range.  
                          * Just add the matches in this line to the  
                          * hilite list and keep searching.  
                          */  
                         if (line_match)                          if (line_match)
                                 hilite_line(linepos, line, sp, ep, cvt_ops);  
 #endif  
                 } else if (--matches <= 0)  
                 {  
                         /*  
                          * Found the one match we're looking for.  
                          * Return it.  
                          */  
 #if HILITE_SEARCH  
                         if (hilite_search == 1)  
                         {                          {
                                 /*                                  /*
                                  * Clear the hilite list and add only                                   * Got a match.
                                  * the matches in this one line.  
                                  */                                   */
                                 clr_hilite();                                  if (search_type & SRCH_FIND_ALL)
                                 if (line_match)                                  {
                                         hilite_line(linepos, line, sp, ep, cvt_ops);  #if HILITE_SEARCH
                         }                                          /*
                                            * We are supposed to find all matches in the range.
                                            * Just add the matches in this line to the
                                            * hilite list and keep searching.
                                            */
                                           hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops);
 #endif  #endif
                         if (plinepos != NULL)                                  } else if (--matches <= 0)
                                 *plinepos = linepos;                                  {
                         return (0);                                          /*
                                            * Found the one match we're looking for.
                                            * Return it.
                                            */
   #if HILITE_SEARCH
                                           if (hilite_search == OPT_ON)
                                           {
                                                   /*
                                                    * Clear the hilite list and add only
                                                    * the matches in this one line.
                                                    */
                                                   clr_hilite();
                                                   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);
         }          }
 }  }
   
 /*  /*
    * search for a pattern in history. If found, compile that pattern.
    */
           static int
   hist_pattern(search_type)
           int search_type;
   {
   #if CMD_HISTORY
           char *pattern;
   
           set_mlist(ml_search, 0);
           pattern = cmd_lastpattern();
           if (pattern == NULL)
                   return (0);
   
           if (set_pattern(&search_info, pattern, search_type) < 0)
                   return (0);
   
   #if HILITE_SEARCH
           if (hilite_search == OPT_ONPLUS && !hide_hilite)
                   hilite_screen();
   #endif
   
           return (1);
   #else /* CMD_HISTORY */
           return (0);
   #endif /* CMD_HISTORY */
   }
   
   /*
  * Search for the n-th occurrence of a specified pattern,   * Search for the n-th occurrence of a specified pattern,
  * either forward or backward.   * either forward or backward.
  * Return the number of matches not yet found in this file   * Return the number of matches not yet found in this file
Line 1073 
Line 907 
         int n;          int n;
 {  {
         POSITION pos;          POSITION pos;
         int ucase;  
   
         if (pattern == NULL || *pattern == '\0')          if (pattern == NULL || *pattern == '\0')
         {          {
                 /*                  /*
                  * A null pattern means use the previously compiled pattern.                   * A null pattern means use the previously compiled pattern.
                  */                   */
                 if (!prev_pattern())                  search_type |= SRCH_AFTER_TARGET;
                   if (!prev_pattern(&search_info) && !hist_pattern(search_type))
                 {                  {
                         error("No previous regular expression", NULL_PARG);                          error("No previous regular expression", NULL_PARG);
                         return (-1);                          return (-1);
                 }                  }
                 if ((search_type & SRCH_NO_REGEX) !=                  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);                          error("Please re-enter search pattern", NULL_PARG);
                         return -1;                          return -1;
Line 1116 
Line 950 
                 /*                  /*
                  * Compile the pattern.                   * Compile the pattern.
                  */                   */
                 ucase = is_ucase(pattern);                  if (set_pattern(&search_info, pattern, search_type) < 0)
                 if (caseless == OPT_ONPLUS)  
                         cvt_text(pattern, pattern, CVT_TO_LC);  
                 if (compile_pattern(pattern, search_type) < 0)  
                         return (-1);                          return (-1);
                 /*  
                  * Ignore case if -I is set OR  
                  * -i is set AND the pattern is all lowercase.  
                  */  
                 is_ucase_pattern = ucase;  
                 if (is_ucase_pattern && caseless != OPT_ONPLUS)  
                         is_caseless = 0;  
                 else  
                         is_caseless = caseless;  
 #if HILITE_SEARCH  #if HILITE_SEARCH
                 if (hilite_search)                  if (hilite_search)
                 {                  {
Line 1227 
Line 1049 
         POSITION max_epos;          POSITION max_epos;
         int result;          int result;
         int i;          int i;
   
 /*  /*
  * Search beyond where we're asked to search, so the prep region covers   * 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.   * more than we need.  Do one big search instead of a bunch of small ones.
  */   */
 #define SEARCH_MORE (3*size_linebuf)  #define SEARCH_MORE (3*size_linebuf)
   
         if (!prev_pattern())          if (!prev_pattern(&search_info) && !is_filtering())
                 return;                  return;
   
         /*          /*
Line 1246 
Line 1069 
         {          {
                 max_epos = spos;                  max_epos = spos;
                 for (i = 0;  i < maxlines;  i++)                  for (i = 0;  i < maxlines;  i++)
                         max_epos = forw_raw_line(max_epos, (char **)NULL);                          max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL);
         }          }
   
         /*          /*
Line 1264 
Line 1087 
                  * Discard the old prep region and start a new one.                   * Discard the old prep region and start a new one.
                  */                   */
                 clr_hilite();                  clr_hilite();
                   clr_filter();
                 if (epos != NULL_POSITION)                  if (epos != NULL_POSITION)
                         epos += SEARCH_MORE;                          epos += SEARCH_MORE;
                 nprep_startpos = spos;                  nprep_startpos = spos;
Line 1325 
Line 1149 
   
         if (epos == NULL_POSITION || epos > spos)          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);                                  maxlines, (POSITION*)NULL, &new_epos);
                 if (result < 0)                  if (result < 0)
                         return;                          return;
Line 1335 
Line 1161 
         prep_startpos = nprep_startpos;          prep_startpos = nprep_startpos;
         prep_endpos = nprep_endpos;          prep_endpos = nprep_endpos;
 }  }
 #endif  
   
 /*  /*
  * Simple pattern matching function.   * Set the pattern to be used for line filtering.
  * It supports no metacharacters like *, etc.  
  */   */
         static int          public void
 match(pattern, buf, pfound, pend)  set_filter_pattern(pattern, search_type)
         char *pattern, *buf;          char *pattern;
         char **pfound, **pend;          int search_type;
 {  {
         register char *pp, *lp;          clr_filter();
           if (pattern == NULL || *pattern == '\0')
                   clear_pattern(&filter_info);
           else
                   set_pattern(&filter_info, pattern, search_type);
           screen_trashed = 1;
   }
   
         for ( ;  *buf != '\0';  buf++)  /*
         {   * Is there a line filter in effect?
                 for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)   */
                         if (*pp == '\0' || *lp == '\0')          public int
                                 break;  is_filtering()
                 if (*pp == '\0')  {
                 {          if (ch_getflags() & CH_HELPFILE)
                         if (pfound != NULL)                  return (0);
                                 *pfound = buf;          return prev_pattern(&filter_info);
                         if (pend != NULL)  
                                 *pend = lp;  
                         return (1);  
                 }  
         }  
         return (0);  
 }  }
   #endif
   
 #if HAVE_V8_REGCOMP  #if HAVE_V8_REGCOMP
 /*  /*

Legend:
Removed from v.1.5  
changed lines
  Added in v.1.6