search.c revision 173685
160812Sps/* $FreeBSD: head/contrib/less/search.c 173685 2007-11-16 22:24:31Z delphij $ */ 260786Sps/* 3170259Sdelphij * Copyright (C) 1984-2007 Mark Nudelman 460786Sps * 560786Sps * You may distribute under the terms of either the GNU General Public 660786Sps * License or the Less License, as specified in the README file. 760786Sps * 860786Sps * For more information about less, or for information on how to 960786Sps * contact the author, see the README file. 1060786Sps */ 1160786Sps 1260786Sps 1360786Sps/* 1460786Sps * Routines to search a file for a pattern. 1560786Sps */ 1660786Sps 1760786Sps#include "less.h" 1860786Sps#include "position.h" 19172471Sdelphij#include "charset.h" 2060786Sps 2160786Sps#define MINPOS(a,b) (((a) < (b)) ? (a) : (b)) 2260786Sps#define MAXPOS(a,b) (((a) > (b)) ? (a) : (b)) 2360786Sps 2460786Sps#if HAVE_POSIX_REGCOMP 2560786Sps#include <regex.h> 2660786Sps#ifdef REG_EXTENDED 27170259Sdelphij#define REGCOMP_FLAG (less_is_more ? 0 : REG_EXTENDED) 2860786Sps#else 2960786Sps#define REGCOMP_FLAG 0 3060786Sps#endif 3160786Sps#endif 3260786Sps#if HAVE_PCRE 3360786Sps#include <pcre.h> 3460786Sps#endif 3560786Sps#if HAVE_RE_COMP 3660786Spschar *re_comp(); 3760786Spsint re_exec(); 3860786Sps#endif 3960786Sps#if HAVE_REGCMP 4060786Spschar *regcmp(); 4160786Spschar *regex(); 4260786Spsextern char *__loc1; 4360786Sps#endif 4460786Sps#if HAVE_V8_REGCOMP 4560786Sps#include "regexp.h" 4660786Sps#endif 4760786Sps 4860786Spsstatic int match(); 4960786Sps 5060786Spsextern int sigs; 5160786Spsextern int how_search; 5260786Spsextern int caseless; 5360786Spsextern int linenums; 5460786Spsextern int sc_height; 5560786Spsextern int jump_sline; 5660786Spsextern int bs_mode; 57170259Sdelphijextern int less_is_more; 58128348Stjrextern int ctldisp; 5963131Spsextern int status_col; 60170259Sdelphijextern void * constant ml_search; 6160786Spsextern POSITION start_attnpos; 6260786Spsextern POSITION end_attnpos; 6360786Sps#if HILITE_SEARCH 6460786Spsextern int hilite_search; 6560786Spsextern int screen_trashed; 6660786Spsextern int size_linebuf; 6760786Spsextern int squished; 6860786Spsextern int can_goto_line; 69173685Sdelphijextern int utf_mode; 7060786Spsstatic int hide_hilite; 71170259Sdelphijstatic int oldbot; 7260786Spsstatic POSITION prep_startpos; 7360786Spsstatic POSITION prep_endpos; 7460786Sps 7560786Spsstruct hilite 7660786Sps{ 7760786Sps struct hilite *hl_next; 7860786Sps POSITION hl_startpos; 7960786Sps POSITION hl_endpos; 8060786Sps}; 8160786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 8260786Sps#define hl_first hl_next 8360786Sps#endif 8460786Sps 8560786Sps/* 8660786Sps * These are the static variables that represent the "remembered" 8760786Sps * search pattern. 8860786Sps */ 8960786Sps#if HAVE_POSIX_REGCOMP 9060786Spsstatic regex_t *regpattern = NULL; 9160786Sps#endif 9260786Sps#if HAVE_PCRE 9360786Spspcre *regpattern = NULL; 9460786Sps#endif 9560786Sps#if HAVE_RE_COMP 9660786Spsint re_pattern = 0; 9760786Sps#endif 9860786Sps#if HAVE_REGCMP 9960786Spsstatic char *cpattern = NULL; 10060786Sps#endif 10160786Sps#if HAVE_V8_REGCOMP 10260786Spsstatic struct regexp *regpattern = NULL; 10360786Sps#endif 10460786Sps 10560786Spsstatic int is_caseless; 10660786Spsstatic int is_ucase_pattern; 10760786Spsstatic int last_search_type; 10860786Spsstatic char *last_pattern = NULL; 10960786Sps 11060786Sps#define CVT_TO_LC 01 /* Convert upper-case to lower-case */ 11160786Sps#define CVT_BS 02 /* Do backspace processing */ 11260786Sps#define CVT_CRLF 04 /* Remove CR after LF */ 113128348Stjr#define CVT_ANSI 010 /* Remove ANSI escape sequences */ 11460786Sps 115173685Sdelphij/* 116173685Sdelphij * Get the length of a buffer needed to convert a string. 117173685Sdelphij */ 118173685Sdelphij static int 119173685Sdelphijcvt_length(len, ops) 120173685Sdelphij int len; 121173685Sdelphij int ops; 122173685Sdelphij{ 123173685Sdelphij if (utf_mode && (ops & CVT_TO_LC)) 124173685Sdelphij /* 125173685Sdelphij * Converting case can cause a UTF-8 string to increase in length. 126173685Sdelphij * Multiplying by 3 is the worst case. 127173685Sdelphij */ 128173685Sdelphij len *= 3; 129173685Sdelphij return len+1; 130173685Sdelphij} 131173685Sdelphij 132173685Sdelphij/* 133173685Sdelphij * Convert text. Perform one or more of these transformations: 134173685Sdelphij */ 13560786Sps static void 136170259Sdelphijcvt_text(odst, osrc, lenp, ops) 13760786Sps char *odst; 13860786Sps char *osrc; 139170259Sdelphij int *lenp; 14060786Sps int ops; 14160786Sps{ 142172471Sdelphij char *dst; 143172471Sdelphij char *src; 144170259Sdelphij register char *src_end; 145172471Sdelphij LWCHAR ch; 14660786Sps 147170259Sdelphij if (lenp != NULL) 148170259Sdelphij src_end = osrc + *lenp; 149170259Sdelphij else 150170259Sdelphij src_end = osrc + strlen(osrc); 151170259Sdelphij 152172471Sdelphij for (src = osrc, dst = odst; src < src_end; ) 15360786Sps { 154172471Sdelphij ch = step_char(&src, +1, src_end); 155172471Sdelphij if ((ops & CVT_TO_LC) && IS_UPPER(ch)) 156172471Sdelphij { 15760786Sps /* Convert uppercase to lowercase. */ 158172471Sdelphij put_wchar(&dst, TO_LOWER(ch)); 159172471Sdelphij } else if ((ops & CVT_BS) && ch == '\b' && dst > odst) 160172471Sdelphij { 161173685Sdelphij /* Delete backspace and preceding char. */ 162172471Sdelphij do { 163172471Sdelphij dst--; 164172471Sdelphij } while (dst > odst && 165172471Sdelphij !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst)); 166172471Sdelphij } else if ((ops & CVT_ANSI) && IS_CSI_START(ch)) 167128348Stjr { 168128348Stjr /* Skip to end of ANSI escape sequence. */ 169170259Sdelphij while (src + 1 != src_end) 170161478Sdelphij if (!is_ansi_middle(*++src)) 171128348Stjr break; 172128348Stjr } else 17360786Sps /* Just copy. */ 174172471Sdelphij put_wchar(&dst, ch); 17560786Sps } 17660786Sps if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r') 17760786Sps dst--; 17860786Sps *dst = '\0'; 179170259Sdelphij if (lenp != NULL) 180170259Sdelphij *lenp = dst - odst; 18160786Sps} 18260786Sps 18360786Sps/* 184128348Stjr * Determine which conversions to perform. 185128348Stjr */ 186128348Stjr static int 187128348Stjrget_cvt_ops() 188128348Stjr{ 189128348Stjr int ops = 0; 190128348Stjr if (is_caseless || bs_mode == BS_SPECIAL) 191128348Stjr { 192128348Stjr if (is_caseless) 193128348Stjr ops |= CVT_TO_LC; 194128348Stjr if (bs_mode == BS_SPECIAL) 195128348Stjr ops |= CVT_BS; 196128348Stjr if (bs_mode != BS_CONTROL) 197128348Stjr ops |= CVT_CRLF; 198128348Stjr } else if (bs_mode != BS_CONTROL) 199128348Stjr { 200128348Stjr ops |= CVT_CRLF; 201128348Stjr } 202128348Stjr if (ctldisp == OPT_ONPLUS) 203128348Stjr ops |= CVT_ANSI; 204128348Stjr return (ops); 205128348Stjr} 206128348Stjr 207128348Stjr/* 20860786Sps * Are there any uppercase letters in this string? 20960786Sps */ 21060786Sps static int 211172471Sdelphijis_ucase(str) 212172471Sdelphij char *str; 21360786Sps{ 214172471Sdelphij char *str_end = str + strlen(str); 215172471Sdelphij LWCHAR ch; 21660786Sps 217172471Sdelphij while (str < str_end) 218172471Sdelphij { 219172471Sdelphij ch = step_char(&str, +1, str_end); 220172471Sdelphij if (IS_UPPER(ch)) 22160786Sps return (1); 222172471Sdelphij } 22360786Sps return (0); 22460786Sps} 22560786Sps 22660786Sps/* 22760786Sps * Is there a previous (remembered) search pattern? 22860786Sps */ 22960786Sps static int 23060786Spsprev_pattern() 23160786Sps{ 23260786Sps if (last_search_type & SRCH_NO_REGEX) 23360786Sps return (last_pattern != NULL); 23460786Sps#if HAVE_POSIX_REGCOMP 23560786Sps return (regpattern != NULL); 23660786Sps#endif 23760786Sps#if HAVE_PCRE 23860786Sps return (regpattern != NULL); 23960786Sps#endif 24060786Sps#if HAVE_RE_COMP 24160786Sps return (re_pattern != 0); 24260786Sps#endif 24360786Sps#if HAVE_REGCMP 24460786Sps return (cpattern != NULL); 24560786Sps#endif 24660786Sps#if HAVE_V8_REGCOMP 24760786Sps return (regpattern != NULL); 24860786Sps#endif 24960786Sps#if NO_REGEX 25060786Sps return (last_pattern != NULL); 25160786Sps#endif 25260786Sps} 25360786Sps 25460786Sps#if HILITE_SEARCH 25560786Sps/* 25660786Sps * Repaint the hilites currently displayed on the screen. 25760786Sps * Repaint each line which contains highlighted text. 25860786Sps * If on==0, force all hilites off. 25960786Sps */ 26060786Sps public void 26160786Spsrepaint_hilite(on) 26260786Sps int on; 26360786Sps{ 26460786Sps int slinenum; 26560786Sps POSITION pos; 26660786Sps POSITION epos; 26760786Sps int save_hide_hilite; 26860786Sps 26960786Sps if (squished) 27060786Sps repaint(); 27160786Sps 27260786Sps save_hide_hilite = hide_hilite; 27360786Sps if (!on) 27460786Sps { 27560786Sps if (hide_hilite) 27660786Sps return; 27760786Sps hide_hilite = 1; 27860786Sps } 27960786Sps 28060786Sps if (!can_goto_line) 28160786Sps { 28260786Sps repaint(); 28360786Sps hide_hilite = save_hide_hilite; 28460786Sps return; 28560786Sps } 28660786Sps 28760786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 28860786Sps { 28960786Sps pos = position(slinenum); 29060786Sps if (pos == NULL_POSITION) 29160786Sps continue; 29260786Sps epos = position(slinenum+1); 293161478Sdelphij#if 0 29460786Sps /* 29560786Sps * If any character in the line is highlighted, 29660786Sps * repaint the line. 297161478Sdelphij * 298161478Sdelphij * {{ This doesn't work -- if line is drawn with highlights 299161478Sdelphij * which should be erased (e.g. toggle -i with status column), 300161478Sdelphij * we must redraw the line even if it has no highlights. 301161478Sdelphij * For now, just repaint every line. }} 30260786Sps */ 303161478Sdelphij if (is_hilited(pos, epos, 1, NULL)) 304161478Sdelphij#endif 30560786Sps { 30660786Sps (void) forw_line(pos); 30760786Sps goto_line(slinenum); 30860786Sps put_line(); 30960786Sps } 31060786Sps } 311170259Sdelphij if (!oldbot) 312170259Sdelphij lower_left(); 31360786Sps hide_hilite = save_hide_hilite; 31460786Sps} 31560786Sps 31660786Sps/* 31760786Sps * Clear the attn hilite. 31860786Sps */ 31960786Sps public void 32060786Spsclear_attn() 32160786Sps{ 32260786Sps int slinenum; 32360786Sps POSITION old_start_attnpos; 32460786Sps POSITION old_end_attnpos; 32560786Sps POSITION pos; 32660786Sps POSITION epos; 327170898Sdelphij int moved = 0; 32860786Sps 32960786Sps if (start_attnpos == NULL_POSITION) 33060786Sps return; 33160786Sps old_start_attnpos = start_attnpos; 33260786Sps old_end_attnpos = end_attnpos; 33360786Sps start_attnpos = end_attnpos = NULL_POSITION; 33460786Sps 33560786Sps if (!can_goto_line) 33660786Sps { 33760786Sps repaint(); 33860786Sps return; 33960786Sps } 34060786Sps if (squished) 34160786Sps repaint(); 34260786Sps 34360786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 34460786Sps { 34560786Sps pos = position(slinenum); 34660786Sps if (pos == NULL_POSITION) 34760786Sps continue; 34860786Sps epos = position(slinenum+1); 34960786Sps if (pos < old_end_attnpos && 35060786Sps (epos == NULL_POSITION || epos > old_start_attnpos)) 35160786Sps { 35260786Sps (void) forw_line(pos); 35360786Sps goto_line(slinenum); 35460786Sps put_line(); 355170898Sdelphij moved = 1; 35660786Sps } 35760786Sps } 358170898Sdelphij if (moved) 359170898Sdelphij lower_left(); 36060786Sps} 36160786Sps#endif 36260786Sps 36360786Sps/* 36460786Sps * Hide search string highlighting. 36560786Sps */ 36660786Sps public void 36760786Spsundo_search() 36860786Sps{ 36960786Sps if (!prev_pattern()) 37060786Sps { 37160786Sps error("No previous regular expression", NULL_PARG); 37260786Sps return; 37360786Sps } 37460786Sps#if HILITE_SEARCH 37560786Sps hide_hilite = !hide_hilite; 37660786Sps repaint_hilite(1); 37760786Sps#endif 37860786Sps} 37960786Sps 38060786Sps/* 38160786Sps * Compile a search pattern, for future use by match_pattern. 38260786Sps */ 38360786Sps static int 384173685Sdelphijcompile_pattern2(pattern, search_type) 38560786Sps char *pattern; 38660786Sps int search_type; 38760786Sps{ 38860786Sps if ((search_type & SRCH_NO_REGEX) == 0) 38960786Sps { 39060786Sps#if HAVE_POSIX_REGCOMP 39160786Sps regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t)); 39260786Sps if (regcomp(s, pattern, REGCOMP_FLAG)) 39360786Sps { 39460786Sps free(s); 39560786Sps error("Invalid pattern", NULL_PARG); 39660786Sps return (-1); 39760786Sps } 39860786Sps if (regpattern != NULL) 39960786Sps regfree(regpattern); 40060786Sps regpattern = s; 40160786Sps#endif 40260786Sps#if HAVE_PCRE 40360786Sps pcre *comp; 40460786Sps const char *errstring; 40560786Sps int erroffset; 40660786Sps PARG parg; 40760786Sps comp = pcre_compile(pattern, 0, 40860786Sps &errstring, &erroffset, NULL); 40960786Sps if (comp == NULL) 41060786Sps { 41160786Sps parg.p_string = (char *) errstring; 41260786Sps error("%s", &parg); 41360786Sps return (-1); 41460786Sps } 41560786Sps regpattern = comp; 41660786Sps#endif 41760786Sps#if HAVE_RE_COMP 41860786Sps PARG parg; 41960786Sps if ((parg.p_string = re_comp(pattern)) != NULL) 42060786Sps { 42160786Sps error("%s", &parg); 42260786Sps return (-1); 42360786Sps } 42460786Sps re_pattern = 1; 42560786Sps#endif 42660786Sps#if HAVE_REGCMP 42760786Sps char *s; 42860786Sps if ((s = regcmp(pattern, 0)) == NULL) 42960786Sps { 43060786Sps error("Invalid pattern", NULL_PARG); 43160786Sps return (-1); 43260786Sps } 43360786Sps if (cpattern != NULL) 43460786Sps free(cpattern); 43560786Sps cpattern = s; 43660786Sps#endif 43760786Sps#if HAVE_V8_REGCOMP 43860786Sps struct regexp *s; 43960786Sps if ((s = regcomp(pattern)) == NULL) 44060786Sps { 44160786Sps /* 44260786Sps * regcomp has already printed an error message 44360786Sps * via regerror(). 44460786Sps */ 44560786Sps return (-1); 44660786Sps } 44760786Sps if (regpattern != NULL) 44860786Sps free(regpattern); 44960786Sps regpattern = s; 45060786Sps#endif 45160786Sps } 45260786Sps 45360786Sps if (last_pattern != NULL) 45460786Sps free(last_pattern); 45560786Sps last_pattern = (char *) calloc(1, strlen(pattern)+1); 45660786Sps if (last_pattern != NULL) 45760786Sps strcpy(last_pattern, pattern); 45860786Sps 45960786Sps last_search_type = search_type; 46060786Sps return (0); 46160786Sps} 46260786Sps 46360786Sps/* 464173685Sdelphij * Like compile_pattern, but convert the pattern to lowercase if necessary. 465173685Sdelphij */ 466173685Sdelphij static int 467173685Sdelphijcompile_pattern(pattern, search_type) 468173685Sdelphij char *pattern; 469173685Sdelphij int search_type; 470173685Sdelphij{ 471173685Sdelphij char *cvt_pattern; 472173685Sdelphij int result; 473173685Sdelphij 474173685Sdelphij if (caseless != OPT_ONPLUS) 475173685Sdelphij cvt_pattern = pattern; 476173685Sdelphij else 477173685Sdelphij { 478173685Sdelphij cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC)); 479173685Sdelphij cvt_text(cvt_pattern, pattern, (int *)NULL, CVT_TO_LC); 480173685Sdelphij } 481173685Sdelphij result = compile_pattern2(cvt_pattern, search_type); 482173685Sdelphij if (cvt_pattern != pattern) 483173685Sdelphij free(cvt_pattern); 484173685Sdelphij return (result); 485173685Sdelphij} 486173685Sdelphij 487173685Sdelphij/* 48860786Sps * Forget that we have a compiled pattern. 48960786Sps */ 49060786Sps static void 49160786Spsuncompile_pattern() 49260786Sps{ 49360786Sps#if HAVE_POSIX_REGCOMP 49460786Sps if (regpattern != NULL) 49560786Sps regfree(regpattern); 49660786Sps regpattern = NULL; 49760786Sps#endif 49860786Sps#if HAVE_PCRE 49960786Sps if (regpattern != NULL) 50060786Sps pcre_free(regpattern); 50160786Sps regpattern = NULL; 50260786Sps#endif 50360786Sps#if HAVE_RE_COMP 50460786Sps re_pattern = 0; 50560786Sps#endif 50660786Sps#if HAVE_REGCMP 50760786Sps if (cpattern != NULL) 50860786Sps free(cpattern); 50960786Sps cpattern = NULL; 51060786Sps#endif 51160786Sps#if HAVE_V8_REGCOMP 51260786Sps if (regpattern != NULL) 51360786Sps free(regpattern); 51460786Sps regpattern = NULL; 51560786Sps#endif 51660786Sps last_pattern = NULL; 51760786Sps} 51860786Sps 51960786Sps/* 52060786Sps * Perform a pattern match with the previously compiled pattern. 52160786Sps * Set sp and ep to the start and end of the matched string. 52260786Sps */ 52360786Sps static int 524170259Sdelphijmatch_pattern(line, line_len, sp, ep, notbol) 52560786Sps char *line; 526170259Sdelphij int line_len; 52760786Sps char **sp; 52860786Sps char **ep; 52960786Sps int notbol; 53060786Sps{ 53160786Sps int matched; 53260786Sps 53360786Sps if (last_search_type & SRCH_NO_REGEX) 534170259Sdelphij return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep)); 53560786Sps 53660786Sps#if HAVE_POSIX_REGCOMP 53760786Sps { 53860786Sps regmatch_t rm; 53960786Sps int flags = (notbol) ? REG_NOTBOL : 0; 54060786Sps matched = !regexec(regpattern, line, 1, &rm, flags); 54160786Sps if (!matched) 54260786Sps return (0); 54360786Sps#ifndef __WATCOMC__ 54460786Sps *sp = line + rm.rm_so; 54560786Sps *ep = line + rm.rm_eo; 54660786Sps#else 54760786Sps *sp = rm.rm_sp; 54860786Sps *ep = rm.rm_ep; 54960786Sps#endif 55060786Sps } 55160786Sps#endif 55260786Sps#if HAVE_PCRE 55360786Sps { 55460786Sps int flags = (notbol) ? PCRE_NOTBOL : 0; 55560786Sps int ovector[3]; 556170259Sdelphij matched = pcre_exec(regpattern, NULL, line, line_len, 55760786Sps 0, flags, ovector, 3) >= 0; 55860786Sps if (!matched) 55960786Sps return (0); 56060786Sps *sp = line + ovector[0]; 56160786Sps *ep = line + ovector[1]; 56260786Sps } 56360786Sps#endif 56460786Sps#if HAVE_RE_COMP 56560786Sps matched = (re_exec(line) == 1); 56660786Sps /* 56760786Sps * re_exec doesn't seem to provide a way to get the matched string. 56860786Sps */ 56960786Sps *sp = *ep = NULL; 57060786Sps#endif 57160786Sps#if HAVE_REGCMP 57260786Sps *ep = regex(cpattern, line); 57360786Sps matched = (*ep != NULL); 57460786Sps if (!matched) 57560786Sps return (0); 57660786Sps *sp = __loc1; 57760786Sps#endif 57860786Sps#if HAVE_V8_REGCOMP 57960786Sps#if HAVE_REGEXEC2 58060786Sps matched = regexec2(regpattern, line, notbol); 58160786Sps#else 58260786Sps matched = regexec(regpattern, line); 58360786Sps#endif 58460786Sps if (!matched) 58560786Sps return (0); 58660786Sps *sp = regpattern->startp[0]; 58760786Sps *ep = regpattern->endp[0]; 58860786Sps#endif 58960786Sps#if NO_REGEX 590170259Sdelphij matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep); 59160786Sps#endif 59260786Sps return (matched); 59360786Sps} 59460786Sps 59560786Sps#if HILITE_SEARCH 59660786Sps/* 59760786Sps * Clear the hilite list. 59860786Sps */ 59960786Sps public void 60060786Spsclr_hilite() 60160786Sps{ 60260786Sps struct hilite *hl; 60360786Sps struct hilite *nexthl; 60460786Sps 60560786Sps for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl) 60660786Sps { 60760786Sps nexthl = hl->hl_next; 60860786Sps free((void*)hl); 60960786Sps } 61060786Sps hilite_anchor.hl_first = NULL; 61160786Sps prep_startpos = prep_endpos = NULL_POSITION; 61260786Sps} 61360786Sps 61460786Sps/* 61560786Sps * Should any characters in a specified range be highlighted? 616161478Sdelphij */ 617161478Sdelphij static int 618161478Sdelphijis_hilited_range(pos, epos) 619161478Sdelphij POSITION pos; 620161478Sdelphij POSITION epos; 621161478Sdelphij{ 622161478Sdelphij struct hilite *hl; 623161478Sdelphij 624161478Sdelphij /* 625161478Sdelphij * Look at each highlight and see if any part of it falls in the range. 626161478Sdelphij */ 627161478Sdelphij for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) 628161478Sdelphij { 629161478Sdelphij if (hl->hl_endpos > pos && 630161478Sdelphij (epos == NULL_POSITION || epos > hl->hl_startpos)) 631161478Sdelphij return (1); 632161478Sdelphij } 633161478Sdelphij return (0); 634161478Sdelphij} 635161478Sdelphij 636161478Sdelphij/* 637161478Sdelphij * Should any characters in a specified range be highlighted? 63860786Sps * If nohide is nonzero, don't consider hide_hilite. 63960786Sps */ 64060786Sps public int 641161478Sdelphijis_hilited(pos, epos, nohide, p_matches) 64260786Sps POSITION pos; 64360786Sps POSITION epos; 64460786Sps int nohide; 645161478Sdelphij int *p_matches; 64660786Sps{ 647161478Sdelphij int match; 64860786Sps 649161478Sdelphij if (p_matches != NULL) 650161478Sdelphij *p_matches = 0; 651161478Sdelphij 65263131Sps if (!status_col && 65363131Sps start_attnpos != NULL_POSITION && 65460786Sps pos < end_attnpos && 65560786Sps (epos == NULL_POSITION || epos > start_attnpos)) 65660786Sps /* 65760786Sps * The attn line overlaps this range. 65860786Sps */ 65960786Sps return (1); 66060786Sps 661161478Sdelphij match = is_hilited_range(pos, epos); 662161478Sdelphij if (!match) 663161478Sdelphij return (0); 664161478Sdelphij 665161478Sdelphij if (p_matches != NULL) 666161478Sdelphij /* 667161478Sdelphij * Report matches, even if we're hiding highlights. 668161478Sdelphij */ 669161478Sdelphij *p_matches = 1; 670161478Sdelphij 67160786Sps if (hilite_search == 0) 67260786Sps /* 67360786Sps * Not doing highlighting. 67460786Sps */ 67560786Sps return (0); 67660786Sps 67760786Sps if (!nohide && hide_hilite) 67860786Sps /* 67960786Sps * Highlighting is hidden. 68060786Sps */ 68160786Sps return (0); 68260786Sps 683161478Sdelphij return (1); 68460786Sps} 68560786Sps 68660786Sps/* 68760786Sps * Add a new hilite to a hilite list. 68860786Sps */ 68960786Sps static void 69060786Spsadd_hilite(anchor, hl) 69160786Sps struct hilite *anchor; 69260786Sps struct hilite *hl; 69360786Sps{ 69460786Sps struct hilite *ihl; 69560786Sps 69660786Sps /* 69760786Sps * Hilites are sorted in the list; find where new one belongs. 69860786Sps * Insert new one after ihl. 69960786Sps */ 70060786Sps for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next) 70160786Sps { 70260786Sps if (ihl->hl_next->hl_startpos > hl->hl_startpos) 70360786Sps break; 70460786Sps } 70560786Sps 70660786Sps /* 70760786Sps * Truncate hilite so it doesn't overlap any existing ones 70860786Sps * above and below it. 70960786Sps */ 71060786Sps if (ihl != anchor) 71160786Sps hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos); 71260786Sps if (ihl->hl_next != NULL) 71360786Sps hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos); 71460786Sps if (hl->hl_startpos >= hl->hl_endpos) 71560786Sps { 71660786Sps /* 71760786Sps * Hilite was truncated out of existence. 71860786Sps */ 71960786Sps free(hl); 72060786Sps return; 72160786Sps } 72260786Sps hl->hl_next = ihl->hl_next; 72360786Sps ihl->hl_next = hl; 72460786Sps} 72560786Sps 72660786Sps/* 727173685Sdelphij * Adjust hl_startpos & hl_endpos to account for processing by cvt_text. 72860786Sps */ 72960786Sps static void 730128348Stjradj_hilite(anchor, linepos, cvt_ops) 73160786Sps struct hilite *anchor; 73260786Sps POSITION linepos; 733128348Stjr int cvt_ops; 73460786Sps{ 73560786Sps char *line; 736173685Sdelphij char *oline; 737170259Sdelphij int line_len; 738170259Sdelphij char *line_end; 73960786Sps struct hilite *hl; 74060786Sps int checkstart; 74160786Sps POSITION opos; 74260786Sps POSITION npos; 743173685Sdelphij LWCHAR ch; 744173685Sdelphij int ncwidth; 74560786Sps 74660786Sps /* 74760786Sps * The line was already scanned and hilites were added (in hilite_line). 74860786Sps * But it was assumed that each char position in the line 74960786Sps * correponds to one char position in the file. 750173685Sdelphij * This may not be true if cvt_text modified the line. 75160786Sps * Get the raw line again. Look at each character. 75260786Sps */ 753170259Sdelphij (void) forw_raw_line(linepos, &line, &line_len); 754170259Sdelphij line_end = line + line_len; 75560786Sps opos = npos = linepos; 75660786Sps hl = anchor->hl_first; 75760786Sps checkstart = TRUE; 75860786Sps while (hl != NULL) 75960786Sps { 76060786Sps /* 76160786Sps * See if we need to adjust the current hl_startpos or 76260786Sps * hl_endpos. After adjusting startpos[i], move to endpos[i]. 76360786Sps * After adjusting endpos[i], move to startpos[i+1]. 76460786Sps * The hilite list must be sorted thus: 76560786Sps * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc. 76660786Sps */ 76760786Sps if (checkstart && hl->hl_startpos == opos) 76860786Sps { 76960786Sps hl->hl_startpos = npos; 77060786Sps checkstart = FALSE; 77160786Sps continue; /* {{ not really necessary }} */ 77260786Sps } else if (!checkstart && hl->hl_endpos == opos) 77360786Sps { 77460786Sps hl->hl_endpos = npos; 77560786Sps checkstart = TRUE; 77660786Sps hl = hl->hl_next; 77760786Sps continue; /* {{ necessary }} */ 77860786Sps } 779170259Sdelphij if (line == line_end) 78060786Sps break; 781173685Sdelphij 782173685Sdelphij /* Get the next char from the line. */ 783173685Sdelphij oline = line; 784173685Sdelphij ch = step_char(&line, +1, line_end); 785173685Sdelphij ncwidth = line - oline; 786173685Sdelphij npos += ncwidth; 787173685Sdelphij 788173685Sdelphij /* Figure out how this char was processed by cvt_text. */ 789173685Sdelphij if ((cvt_ops & CVT_BS) && ch == '\b') 79060786Sps { 791173685Sdelphij /* Skip the backspace and the following char. */ 792173685Sdelphij oline = line; 793173685Sdelphij ch = step_char(&line, +1, line_end); 794173685Sdelphij ncwidth = line - oline; 795173685Sdelphij npos += ncwidth; 796173685Sdelphij } else if ((cvt_ops & CVT_TO_LC) && IS_UPPER(ch)) 797173685Sdelphij { 798173685Sdelphij /* Converted uppercase to lower. 799173685Sdelphij * Note that this may have changed the number of bytes 800173685Sdelphij * that the character occupies. */ 801173685Sdelphij char dbuf[6]; 802173685Sdelphij char *dst = dbuf; 803173685Sdelphij put_wchar(&dst, TO_LOWER(ch)); 804173685Sdelphij opos += dst - dbuf; 805173685Sdelphij } else if ((cvt_ops & CVT_ANSI) && IS_CSI_START(ch)) 806173685Sdelphij { 807173685Sdelphij /* Skip to end of ANSI escape sequence. */ 808173685Sdelphij while (line < line_end) 809128348Stjr { 810161478Sdelphij npos++; 811173685Sdelphij if (!is_ansi_middle(*++line)) 812161478Sdelphij break; 813128348Stjr } 814173685Sdelphij } else 815173685Sdelphij { 816173685Sdelphij /* Ordinary unprocessed character. */ 817173685Sdelphij opos += ncwidth; 81860786Sps } 81960786Sps } 82060786Sps} 82160786Sps 82260786Sps/* 82360786Sps * Make a hilite for each string in a physical line which matches 82460786Sps * the current pattern. 82560786Sps * sp,ep delimit the first match already found. 82660786Sps */ 82760786Sps static void 828170259Sdelphijhilite_line(linepos, line, line_len, sp, ep, cvt_ops) 82960786Sps POSITION linepos; 83060786Sps char *line; 831170259Sdelphij int line_len; 83260786Sps char *sp; 83360786Sps char *ep; 834128348Stjr int cvt_ops; 83560786Sps{ 83660786Sps char *searchp; 837170259Sdelphij char *line_end = line + line_len; 83860786Sps struct hilite *hl; 83960786Sps struct hilite hilites; 84060786Sps 84160786Sps if (sp == NULL || ep == NULL) 84260786Sps return; 84360786Sps /* 84460786Sps * sp and ep delimit the first match in the line. 84560786Sps * Mark the corresponding file positions, then 84660786Sps * look for further matches and mark them. 84760786Sps * {{ This technique, of calling match_pattern on subsequent 84860786Sps * substrings of the line, may mark more than is correct 84960786Sps * if the pattern starts with "^". This bug is fixed 85060786Sps * for those regex functions that accept a notbol parameter 851170259Sdelphij * (currently POSIX, PCRE and V8-with-regexec2). }} 85260786Sps */ 85360786Sps searchp = line; 85460786Sps /* 85560786Sps * Put the hilites into a temporary list until they're adjusted. 85660786Sps */ 85760786Sps hilites.hl_first = NULL; 85860786Sps do { 85960786Sps if (ep > sp) 86060786Sps { 86160786Sps /* 86260786Sps * Assume that each char position in the "line" 86360786Sps * buffer corresponds to one char position in the file. 86460786Sps * This is not quite true; we need to adjust later. 86560786Sps */ 86660786Sps hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); 86760786Sps hl->hl_startpos = linepos + (sp-line); 86860786Sps hl->hl_endpos = linepos + (ep-line); 86960786Sps add_hilite(&hilites, hl); 87060786Sps } 87160786Sps /* 87260786Sps * If we matched more than zero characters, 87360786Sps * move to the first char after the string we matched. 87460786Sps * If we matched zero, just move to the next char. 87560786Sps */ 87660786Sps if (ep > searchp) 87760786Sps searchp = ep; 878170259Sdelphij else if (searchp != line_end) 87960786Sps searchp++; 88060786Sps else /* end of line */ 88160786Sps break; 882170259Sdelphij } while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1)); 88360786Sps 88460786Sps /* 885128348Stjr * If there were backspaces in the original line, they 886128348Stjr * were removed, and hl_startpos/hl_endpos are not correct. 887128348Stjr * {{ This is very ugly. }} 888128348Stjr */ 889128348Stjr adj_hilite(&hilites, linepos, cvt_ops); 890128348Stjr 891128348Stjr /* 89260786Sps * Now put the hilites into the real list. 89360786Sps */ 89460786Sps while ((hl = hilites.hl_next) != NULL) 89560786Sps { 89660786Sps hilites.hl_next = hl->hl_next; 89760786Sps add_hilite(&hilite_anchor, hl); 89860786Sps } 89960786Sps} 90060786Sps#endif 90160786Sps 90260786Sps/* 90360786Sps * Change the caseless-ness of searches. 90460786Sps * Updates the internal search state to reflect a change in the -i flag. 90560786Sps */ 90660786Sps public void 90760786Spschg_caseless() 90860786Sps{ 90960786Sps if (!is_ucase_pattern) 91060786Sps /* 91160786Sps * Pattern did not have uppercase. 91260786Sps * Just set the search caselessness to the global caselessness. 91360786Sps */ 91460786Sps is_caseless = caseless; 91560786Sps else 91660786Sps /* 91760786Sps * Pattern did have uppercase. 91860786Sps * Discard the pattern; we can't change search caselessness now. 91960786Sps */ 92060786Sps uncompile_pattern(); 92160786Sps} 92260786Sps 92360786Sps#if HILITE_SEARCH 92460786Sps/* 92560786Sps * Find matching text which is currently on screen and highlight it. 92660786Sps */ 92760786Sps static void 92860786Spshilite_screen() 92960786Sps{ 93060786Sps struct scrpos scrpos; 93160786Sps 93260786Sps get_scrpos(&scrpos); 93360786Sps if (scrpos.pos == NULL_POSITION) 93460786Sps return; 93560786Sps prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); 93660786Sps repaint_hilite(1); 93760786Sps} 93860786Sps 93960786Sps/* 94060786Sps * Change highlighting parameters. 94160786Sps */ 94260786Sps public void 94360786Spschg_hilite() 94460786Sps{ 94560786Sps /* 94660786Sps * Erase any highlights currently on screen. 94760786Sps */ 94860786Sps clr_hilite(); 94960786Sps hide_hilite = 0; 95060786Sps 95160786Sps if (hilite_search == OPT_ONPLUS) 95260786Sps /* 95360786Sps * Display highlights. 95460786Sps */ 95560786Sps hilite_screen(); 95660786Sps} 95760786Sps#endif 95860786Sps 95960786Sps/* 96060786Sps * Figure out where to start a search. 96160786Sps */ 96260786Sps static POSITION 96360786Spssearch_pos(search_type) 96460786Sps int search_type; 96560786Sps{ 96660786Sps POSITION pos; 96760786Sps int linenum; 96860786Sps 96960786Sps if (empty_screen()) 97060786Sps { 97160786Sps /* 97260786Sps * Start at the beginning (or end) of the file. 97360786Sps * The empty_screen() case is mainly for 97460786Sps * command line initiated searches; 97560786Sps * for example, "+/xyz" on the command line. 97660786Sps * Also for multi-file (SRCH_PAST_EOF) searches. 97760786Sps */ 97860786Sps if (search_type & SRCH_FORW) 97960786Sps { 98060786Sps return (ch_zero()); 98160786Sps } else 98260786Sps { 98360786Sps pos = ch_length(); 98460786Sps if (pos == NULL_POSITION) 98560786Sps { 98660786Sps (void) ch_end_seek(); 98760786Sps pos = ch_length(); 98860786Sps } 98960786Sps return (pos); 99060786Sps } 99160786Sps } 99260786Sps if (how_search) 99360786Sps { 99460786Sps /* 99560786Sps * Search does not include current screen. 99660786Sps */ 99760786Sps if (search_type & SRCH_FORW) 99860786Sps linenum = BOTTOM_PLUS_ONE; 99960786Sps else 100060786Sps linenum = TOP; 100160786Sps pos = position(linenum); 100260786Sps } else 100360786Sps { 100460786Sps /* 100560786Sps * Search includes current screen. 100660786Sps * It starts at the jump target (if searching backwards), 100760786Sps * or at the jump target plus one (if forwards). 100860786Sps */ 100960786Sps linenum = adjsline(jump_sline); 101060786Sps pos = position(linenum); 101160786Sps if (search_type & SRCH_FORW) 101260786Sps { 1013170259Sdelphij pos = forw_raw_line(pos, (char **)NULL, (int *)NULL); 101460786Sps while (pos == NULL_POSITION) 101560786Sps { 101660786Sps if (++linenum >= sc_height) 101760786Sps break; 101860786Sps pos = position(linenum); 101960786Sps } 102060786Sps } else 102160786Sps { 102260786Sps while (pos == NULL_POSITION) 102360786Sps { 102460786Sps if (--linenum < 0) 102560786Sps break; 102660786Sps pos = position(linenum); 102760786Sps } 102860786Sps } 102960786Sps } 103060786Sps return (pos); 103160786Sps} 103260786Sps 103360786Sps/* 103460786Sps * Search a subset of the file, specified by start/end position. 103560786Sps */ 103660786Sps static int 103760786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) 103860786Sps POSITION pos; 103960786Sps POSITION endpos; 104060786Sps int search_type; 104160786Sps int matches; 104260786Sps int maxlines; 104360786Sps POSITION *plinepos; 104460786Sps POSITION *pendpos; 104560786Sps{ 104660786Sps char *line; 1047173685Sdelphij char *cline; 1048170259Sdelphij int line_len; 1049128348Stjr LINENUM linenum; 105060786Sps char *sp, *ep; 105160786Sps int line_match; 1052128348Stjr int cvt_ops; 105360786Sps POSITION linepos, oldpos; 105460786Sps 105560786Sps linenum = find_linenum(pos); 105660786Sps oldpos = pos; 105760786Sps for (;;) 105860786Sps { 105960786Sps /* 106060786Sps * Get lines until we find a matching one or until 106160786Sps * we hit end-of-file (or beginning-of-file if we're 106260786Sps * going backwards), or until we hit the end position. 106360786Sps */ 106460786Sps if (ABORT_SIGS()) 106560786Sps { 106660786Sps /* 106760786Sps * A signal aborts the search. 106860786Sps */ 106960786Sps return (-1); 107060786Sps } 107160786Sps 107260786Sps if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) 107360786Sps { 107460786Sps /* 107560786Sps * Reached end position without a match. 107660786Sps */ 107760786Sps if (pendpos != NULL) 107860786Sps *pendpos = pos; 107960786Sps return (matches); 108060786Sps } 108160786Sps if (maxlines > 0) 108260786Sps maxlines--; 108360786Sps 108460786Sps if (search_type & SRCH_FORW) 108560786Sps { 108660786Sps /* 108760786Sps * Read the next line, and save the 108860786Sps * starting position of that line in linepos. 108960786Sps */ 109060786Sps linepos = pos; 1091170259Sdelphij pos = forw_raw_line(pos, &line, &line_len); 109260786Sps if (linenum != 0) 109360786Sps linenum++; 109460786Sps } else 109560786Sps { 109660786Sps /* 109760786Sps * Read the previous line and save the 109860786Sps * starting position of that line in linepos. 109960786Sps */ 1100170259Sdelphij pos = back_raw_line(pos, &line, &line_len); 110160786Sps linepos = pos; 110260786Sps if (linenum != 0) 110360786Sps linenum--; 110460786Sps } 110560786Sps 110660786Sps if (pos == NULL_POSITION) 110760786Sps { 110860786Sps /* 110960786Sps * Reached EOF/BOF without a match. 111060786Sps */ 111160786Sps if (pendpos != NULL) 111260786Sps *pendpos = oldpos; 111360786Sps return (matches); 111460786Sps } 111560786Sps 111660786Sps /* 111760786Sps * If we're using line numbers, we might as well 111860786Sps * remember the information we have now (the position 111960786Sps * and line number of the current line). 112060786Sps * Don't do it for every line because it slows down 112160786Sps * the search. Remember the line number only if 112260786Sps * we're "far" from the last place we remembered it. 112360786Sps */ 112460786Sps if (linenums && abs((int)(pos - oldpos)) > 1024) 112560786Sps add_lnum(linenum, pos); 112660786Sps oldpos = pos; 112760786Sps 112860786Sps /* 112960786Sps * If it's a caseless search, convert the line to lowercase. 113060786Sps * If we're doing backspace processing, delete backspaces. 113160786Sps */ 1132128348Stjr cvt_ops = get_cvt_ops(); 1133173685Sdelphij cline = calloc(1, cvt_length(line_len, cvt_ops)); 1134173685Sdelphij cvt_text(cline, line, &line_len, cvt_ops); 113560786Sps 113660786Sps /* 113760786Sps * Test the next line to see if we have a match. 113860786Sps * We are successful if we either want a match and got one, 113960786Sps * or if we want a non-match and got one. 114060786Sps */ 1141173685Sdelphij line_match = match_pattern(cline, line_len, &sp, &ep, 0); 114260786Sps line_match = (!(search_type & SRCH_NO_MATCH) && line_match) || 114360786Sps ((search_type & SRCH_NO_MATCH) && !line_match); 114460786Sps if (!line_match) 1145173685Sdelphij { 1146173685Sdelphij free(cline); 114760786Sps continue; 1148173685Sdelphij } 114960786Sps /* 115060786Sps * Got a match. 115160786Sps */ 115260786Sps if (search_type & SRCH_FIND_ALL) 115360786Sps { 115460786Sps#if HILITE_SEARCH 115560786Sps /* 115660786Sps * We are supposed to find all matches in the range. 115760786Sps * Just add the matches in this line to the 115860786Sps * hilite list and keep searching. 115960786Sps */ 116060786Sps if (line_match) 1161173685Sdelphij hilite_line(linepos, cline, line_len, sp, ep, cvt_ops); 116260786Sps#endif 1163173685Sdelphij free(cline); 116460786Sps } else if (--matches <= 0) 116560786Sps { 116660786Sps /* 116760786Sps * Found the one match we're looking for. 116860786Sps * Return it. 116960786Sps */ 117060786Sps#if HILITE_SEARCH 1171161478Sdelphij if (hilite_search == OPT_ON) 117260786Sps { 117360786Sps /* 117460786Sps * Clear the hilite list and add only 117560786Sps * the matches in this one line. 117660786Sps */ 117760786Sps clr_hilite(); 117860786Sps if (line_match) 1179173685Sdelphij hilite_line(linepos, cline, line_len, sp, ep, cvt_ops); 118060786Sps } 118160786Sps#endif 1182173685Sdelphij free(cline); 118360786Sps if (plinepos != NULL) 118460786Sps *plinepos = linepos; 118560786Sps return (0); 118660786Sps } 118760786Sps } 118860786Sps} 118960786Sps 1190170259Sdelphij /* 1191170259Sdelphij * search for a pattern in history. If found, compile that pattern. 1192170259Sdelphij */ 1193170259Sdelphij static int 1194170259Sdelphijhist_pattern(search_type) 1195170259Sdelphij int search_type; 1196170259Sdelphij{ 1197170259Sdelphij#if CMD_HISTORY 1198170259Sdelphij char *pattern; 1199170259Sdelphij 1200170259Sdelphij set_mlist(ml_search, 0); 1201170259Sdelphij pattern = cmd_lastpattern(); 1202170259Sdelphij if (pattern == NULL) 1203170259Sdelphij return (0); 1204170259Sdelphij 1205170259Sdelphij if (compile_pattern(pattern, search_type) < 0) 1206170259Sdelphij return (0); 1207170259Sdelphij 1208170259Sdelphij is_ucase_pattern = is_ucase(pattern); 1209170259Sdelphij if (is_ucase_pattern && caseless != OPT_ONPLUS) 1210170259Sdelphij is_caseless = 0; 1211170259Sdelphij else 1212170259Sdelphij is_caseless = caseless; 1213170259Sdelphij 1214170259Sdelphij#if HILITE_SEARCH 1215170259Sdelphij if (hilite_search == OPT_ONPLUS && !hide_hilite) 1216170259Sdelphij hilite_screen(); 1217170259Sdelphij#endif 1218170259Sdelphij 1219170259Sdelphij return (1); 1220170259Sdelphij#else /* CMD_HISTORY */ 1221170259Sdelphij return (0); 1222170259Sdelphij#endif /* CMD_HISTORY */ 1223170259Sdelphij} 1224170259Sdelphij 122560786Sps/* 122660786Sps * Search for the n-th occurrence of a specified pattern, 122760786Sps * either forward or backward. 122860786Sps * Return the number of matches not yet found in this file 122960786Sps * (that is, n minus the number of matches found). 123060786Sps * Return -1 if the search should be aborted. 123160786Sps * Caller may continue the search in another file 123260786Sps * if less than n matches are found in this file. 123360786Sps */ 123460786Sps public int 123560786Spssearch(search_type, pattern, n) 123660786Sps int search_type; 123760786Sps char *pattern; 123860786Sps int n; 123960786Sps{ 124060786Sps POSITION pos; 1241173685Sdelphij int result; 124260786Sps 124360786Sps if (pattern == NULL || *pattern == '\0') 124460786Sps { 124560786Sps /* 124660786Sps * A null pattern means use the previously compiled pattern. 124760786Sps */ 1248170259Sdelphij if (!prev_pattern() && !hist_pattern(search_type)) 124960786Sps { 125060786Sps error("No previous regular expression", NULL_PARG); 125160786Sps return (-1); 125260786Sps } 125360786Sps if ((search_type & SRCH_NO_REGEX) != 125460786Sps (last_search_type & SRCH_NO_REGEX)) 125560786Sps { 125660786Sps error("Please re-enter search pattern", NULL_PARG); 125760786Sps return -1; 125860786Sps } 125960786Sps#if HILITE_SEARCH 126060786Sps if (hilite_search == OPT_ON) 126160786Sps { 126260786Sps /* 126360786Sps * Erase the highlights currently on screen. 126460786Sps * If the search fails, we'll redisplay them later. 126560786Sps */ 126660786Sps repaint_hilite(0); 126760786Sps } 126860786Sps if (hilite_search == OPT_ONPLUS && hide_hilite) 126960786Sps { 127060786Sps /* 127160786Sps * Highlight any matches currently on screen, 127260786Sps * before we actually start the search. 127360786Sps */ 127460786Sps hide_hilite = 0; 127560786Sps hilite_screen(); 127660786Sps } 127760786Sps hide_hilite = 0; 127860786Sps#endif 127960786Sps } else 128060786Sps { 128160786Sps /* 128260786Sps * Compile the pattern. 128360786Sps */ 128460786Sps if (compile_pattern(pattern, search_type) < 0) 128560786Sps return (-1); 128660786Sps /* 128760786Sps * Ignore case if -I is set OR 128860786Sps * -i is set AND the pattern is all lowercase. 128960786Sps */ 1290173685Sdelphij is_ucase_pattern = is_ucase(pattern); 129160786Sps if (is_ucase_pattern && caseless != OPT_ONPLUS) 129260786Sps is_caseless = 0; 129360786Sps else 129460786Sps is_caseless = caseless; 129560786Sps#if HILITE_SEARCH 129660786Sps if (hilite_search) 129760786Sps { 129860786Sps /* 129960786Sps * Erase the highlights currently on screen. 130060786Sps * Also permanently delete them from the hilite list. 130160786Sps */ 130260786Sps repaint_hilite(0); 130360786Sps hide_hilite = 0; 130460786Sps clr_hilite(); 130560786Sps } 130660786Sps if (hilite_search == OPT_ONPLUS) 130760786Sps { 130860786Sps /* 130960786Sps * Highlight any matches currently on screen, 131060786Sps * before we actually start the search. 131160786Sps */ 131260786Sps hilite_screen(); 131360786Sps } 131460786Sps#endif 131560786Sps } 131660786Sps 131760786Sps /* 131860786Sps * Figure out where to start the search. 131960786Sps */ 132060786Sps pos = search_pos(search_type); 132160786Sps if (pos == NULL_POSITION) 132260786Sps { 132360786Sps /* 132460786Sps * Can't find anyplace to start searching from. 132560786Sps */ 132660786Sps if (search_type & SRCH_PAST_EOF) 132760786Sps return (n); 132860786Sps /* repaint(); -- why was this here? */ 132960786Sps error("Nothing to search", NULL_PARG); 133060786Sps return (-1); 133160786Sps } 133260786Sps 133360786Sps n = search_range(pos, NULL_POSITION, search_type, n, -1, 133460786Sps &pos, (POSITION*)NULL); 133560786Sps if (n != 0) 133660786Sps { 133760786Sps /* 133860786Sps * Search was unsuccessful. 133960786Sps */ 134060786Sps#if HILITE_SEARCH 134160786Sps if (hilite_search == OPT_ON && n > 0) 134260786Sps /* 134360786Sps * Redisplay old hilites. 134460786Sps */ 134560786Sps repaint_hilite(1); 134660786Sps#endif 134760786Sps return (n); 134860786Sps } 134960786Sps 135060786Sps if (!(search_type & SRCH_NO_MOVE)) 135160786Sps { 135260786Sps /* 135360786Sps * Go to the matching line. 135460786Sps */ 135560786Sps jump_loc(pos, jump_sline); 135660786Sps } 135760786Sps 135860786Sps#if HILITE_SEARCH 135960786Sps if (hilite_search == OPT_ON) 136060786Sps /* 136160786Sps * Display new hilites in the matching line. 136260786Sps */ 136360786Sps repaint_hilite(1); 136460786Sps#endif 136560786Sps return (0); 136660786Sps} 136760786Sps 136860786Sps 136960786Sps#if HILITE_SEARCH 137060786Sps/* 137160786Sps * Prepare hilites in a given range of the file. 137260786Sps * 137360786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region 137460786Sps * of the file that has been "prepared"; that is, scanned for matches for 137560786Sps * the current search pattern, and hilites have been created for such matches. 137660786Sps * If prep_startpos == NULL_POSITION, the prep region is empty. 137760786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF. 137860786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region. 137960786Sps */ 138060786Sps public void 138160786Spsprep_hilite(spos, epos, maxlines) 138260786Sps POSITION spos; 138360786Sps POSITION epos; 138460786Sps int maxlines; 138560786Sps{ 138660786Sps POSITION nprep_startpos = prep_startpos; 138760786Sps POSITION nprep_endpos = prep_endpos; 138860786Sps POSITION new_epos; 138960786Sps POSITION max_epos; 139060786Sps int result; 139160786Sps int i; 139260786Sps/* 139360786Sps * Search beyond where we're asked to search, so the prep region covers 139460786Sps * more than we need. Do one big search instead of a bunch of small ones. 139560786Sps */ 139660786Sps#define SEARCH_MORE (3*size_linebuf) 139760786Sps 139860786Sps if (!prev_pattern()) 139960786Sps return; 140060786Sps 140160786Sps /* 140260786Sps * If we're limited to a max number of lines, figure out the 140360786Sps * file position we should stop at. 140460786Sps */ 140560786Sps if (maxlines < 0) 140660786Sps max_epos = NULL_POSITION; 140760786Sps else 140860786Sps { 140960786Sps max_epos = spos; 141060786Sps for (i = 0; i < maxlines; i++) 1411170259Sdelphij max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); 141260786Sps } 141360786Sps 141460786Sps /* 141560786Sps * Find two ranges: 141660786Sps * The range that we need to search (spos,epos); and the range that 141760786Sps * the "prep" region will then cover (nprep_startpos,nprep_endpos). 141860786Sps */ 141960786Sps 142060786Sps if (prep_startpos == NULL_POSITION || 142160786Sps (epos != NULL_POSITION && epos < prep_startpos) || 142260786Sps spos > prep_endpos) 142360786Sps { 142460786Sps /* 142560786Sps * New range is not contiguous with old prep region. 142660786Sps * Discard the old prep region and start a new one. 142760786Sps */ 142860786Sps clr_hilite(); 142960786Sps if (epos != NULL_POSITION) 143060786Sps epos += SEARCH_MORE; 143160786Sps nprep_startpos = spos; 143260786Sps } else 143360786Sps { 143460786Sps /* 143560786Sps * New range partially or completely overlaps old prep region. 143660786Sps */ 143760786Sps if (epos == NULL_POSITION) 143860786Sps { 143960786Sps /* 144060786Sps * New range goes to end of file. 144160786Sps */ 144260786Sps ; 144360786Sps } else if (epos > prep_endpos) 144460786Sps { 144560786Sps /* 144660786Sps * New range ends after old prep region. 144760786Sps * Extend prep region to end at end of new range. 144860786Sps */ 144960786Sps epos += SEARCH_MORE; 145060786Sps } else /* (epos <= prep_endpos) */ 145160786Sps { 145260786Sps /* 145360786Sps * New range ends within old prep region. 145460786Sps * Truncate search to end at start of old prep region. 145560786Sps */ 145660786Sps epos = prep_startpos; 145760786Sps } 145860786Sps 145960786Sps if (spos < prep_startpos) 146060786Sps { 146160786Sps /* 146260786Sps * New range starts before old prep region. 146360786Sps * Extend old prep region backwards to start at 146460786Sps * start of new range. 146560786Sps */ 146660786Sps if (spos < SEARCH_MORE) 146760786Sps spos = 0; 146860786Sps else 146960786Sps spos -= SEARCH_MORE; 147060786Sps nprep_startpos = spos; 147160786Sps } else /* (spos >= prep_startpos) */ 147260786Sps { 147360786Sps /* 147460786Sps * New range starts within or after old prep region. 147560786Sps * Trim search to start at end of old prep region. 147660786Sps */ 147760786Sps spos = prep_endpos; 147860786Sps } 147960786Sps } 148060786Sps 148160786Sps if (epos != NULL_POSITION && max_epos != NULL_POSITION && 148260786Sps epos > max_epos) 148360786Sps /* 148460786Sps * Don't go past the max position we're allowed. 148560786Sps */ 148660786Sps epos = max_epos; 148760786Sps 148860786Sps if (epos == NULL_POSITION || epos > spos) 148960786Sps { 149060786Sps result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, 149160786Sps maxlines, (POSITION*)NULL, &new_epos); 149260786Sps if (result < 0) 149360786Sps return; 149460786Sps if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 149560786Sps nprep_endpos = new_epos; 149660786Sps } 149760786Sps prep_startpos = nprep_startpos; 149860786Sps prep_endpos = nprep_endpos; 149960786Sps} 150060786Sps#endif 150160786Sps 150260786Sps/* 150360786Sps * Simple pattern matching function. 150460786Sps * It supports no metacharacters like *, etc. 150560786Sps */ 150660786Sps static int 1507170259Sdelphijmatch(pattern, pattern_len, buf, buf_len, pfound, pend) 1508170259Sdelphij char *pattern; 1509170259Sdelphij int pattern_len; 1510170259Sdelphij char *buf; 1511170259Sdelphij int buf_len; 151260786Sps char **pfound, **pend; 151360786Sps{ 151460786Sps register char *pp, *lp; 1515170259Sdelphij register char *pattern_end = pattern + pattern_len; 1516170259Sdelphij register char *buf_end = buf + buf_len; 151760786Sps 1518170259Sdelphij for ( ; buf < buf_end; buf++) 151960786Sps { 152060786Sps for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) 1521170259Sdelphij if (pp == pattern_end || lp == buf_end) 152260786Sps break; 1523170259Sdelphij if (pp == pattern_end) 152460786Sps { 152560786Sps if (pfound != NULL) 152660786Sps *pfound = buf; 152760786Sps if (pend != NULL) 152860786Sps *pend = lp; 152960786Sps return (1); 153060786Sps } 153160786Sps } 153260786Sps return (0); 153360786Sps} 153460786Sps 153560786Sps#if HAVE_V8_REGCOMP 153660786Sps/* 153760786Sps * This function is called by the V8 regcomp to report 153860786Sps * errors in regular expressions. 153960786Sps */ 154060786Sps void 154160786Spsregerror(s) 154260786Sps char *s; 154360786Sps{ 154460786Sps PARG parg; 154560786Sps 154660786Sps parg.p_string = s; 154760786Sps error("%s", &parg); 154860786Sps} 154960786Sps#endif 155060786Sps 1551