search.c revision 172471
160812Sps/* $FreeBSD: head/contrib/less/search.c 172471 2007-10-08 16:17:42Z 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; 6960786Spsstatic int hide_hilite; 70170259Sdelphijstatic int oldbot; 7160786Spsstatic POSITION prep_startpos; 7260786Spsstatic POSITION prep_endpos; 7360786Sps 7460786Spsstruct hilite 7560786Sps{ 7660786Sps struct hilite *hl_next; 7760786Sps POSITION hl_startpos; 7860786Sps POSITION hl_endpos; 7960786Sps}; 8060786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 8160786Sps#define hl_first hl_next 8260786Sps#endif 8360786Sps 8460786Sps/* 8560786Sps * These are the static variables that represent the "remembered" 8660786Sps * search pattern. 8760786Sps */ 8860786Sps#if HAVE_POSIX_REGCOMP 8960786Spsstatic regex_t *regpattern = NULL; 9060786Sps#endif 9160786Sps#if HAVE_PCRE 9260786Spspcre *regpattern = NULL; 9360786Sps#endif 9460786Sps#if HAVE_RE_COMP 9560786Spsint re_pattern = 0; 9660786Sps#endif 9760786Sps#if HAVE_REGCMP 9860786Spsstatic char *cpattern = NULL; 9960786Sps#endif 10060786Sps#if HAVE_V8_REGCOMP 10160786Spsstatic struct regexp *regpattern = NULL; 10260786Sps#endif 10360786Sps 10460786Spsstatic int is_caseless; 10560786Spsstatic int is_ucase_pattern; 10660786Spsstatic int last_search_type; 10760786Spsstatic char *last_pattern = NULL; 10860786Sps 10960786Sps/* 11060786Sps * Convert text. Perform one or more of these transformations: 11160786Sps */ 11260786Sps#define CVT_TO_LC 01 /* Convert upper-case to lower-case */ 11360786Sps#define CVT_BS 02 /* Do backspace processing */ 11460786Sps#define CVT_CRLF 04 /* Remove CR after LF */ 115128348Stjr#define CVT_ANSI 010 /* Remove ANSI escape sequences */ 11660786Sps 11760786Sps static void 118170259Sdelphijcvt_text(odst, osrc, lenp, ops) 11960786Sps char *odst; 12060786Sps char *osrc; 121170259Sdelphij int *lenp; 12260786Sps int ops; 12360786Sps{ 124172471Sdelphij char *dst; 125172471Sdelphij char *src; 126170259Sdelphij register char *src_end; 127172471Sdelphij LWCHAR ch; 12860786Sps 129170259Sdelphij if (lenp != NULL) 130170259Sdelphij src_end = osrc + *lenp; 131170259Sdelphij else 132170259Sdelphij src_end = osrc + strlen(osrc); 133170259Sdelphij 134172471Sdelphij for (src = osrc, dst = odst; src < src_end; ) 13560786Sps { 136172471Sdelphij ch = step_char(&src, +1, src_end); 137172471Sdelphij if ((ops & CVT_TO_LC) && IS_UPPER(ch)) 138172471Sdelphij { 13960786Sps /* Convert uppercase to lowercase. */ 140172471Sdelphij put_wchar(&dst, TO_LOWER(ch)); 141172471Sdelphij } else if ((ops & CVT_BS) && ch == '\b' && dst > odst) 142172471Sdelphij { 14360786Sps /* Delete BS and preceding char. */ 144172471Sdelphij do { 145172471Sdelphij dst--; 146172471Sdelphij } while (dst > odst && 147172471Sdelphij !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst)); 148172471Sdelphij } else if ((ops & CVT_ANSI) && IS_CSI_START(ch)) 149128348Stjr { 150128348Stjr /* Skip to end of ANSI escape sequence. */ 151170259Sdelphij while (src + 1 != src_end) 152161478Sdelphij if (!is_ansi_middle(*++src)) 153128348Stjr break; 154128348Stjr } else 15560786Sps /* Just copy. */ 156172471Sdelphij put_wchar(&dst, ch); 15760786Sps } 15860786Sps if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r') 15960786Sps dst--; 16060786Sps *dst = '\0'; 161170259Sdelphij if (lenp != NULL) 162170259Sdelphij *lenp = dst - odst; 16360786Sps} 16460786Sps 16560786Sps/* 166128348Stjr * Determine which conversions to perform. 167128348Stjr */ 168128348Stjr static int 169128348Stjrget_cvt_ops() 170128348Stjr{ 171128348Stjr int ops = 0; 172128348Stjr if (is_caseless || bs_mode == BS_SPECIAL) 173128348Stjr { 174128348Stjr if (is_caseless) 175128348Stjr ops |= CVT_TO_LC; 176128348Stjr if (bs_mode == BS_SPECIAL) 177128348Stjr ops |= CVT_BS; 178128348Stjr if (bs_mode != BS_CONTROL) 179128348Stjr ops |= CVT_CRLF; 180128348Stjr } else if (bs_mode != BS_CONTROL) 181128348Stjr { 182128348Stjr ops |= CVT_CRLF; 183128348Stjr } 184128348Stjr if (ctldisp == OPT_ONPLUS) 185128348Stjr ops |= CVT_ANSI; 186128348Stjr return (ops); 187128348Stjr} 188128348Stjr 189128348Stjr/* 19060786Sps * Are there any uppercase letters in this string? 19160786Sps */ 19260786Sps static int 193172471Sdelphijis_ucase(str) 194172471Sdelphij char *str; 19560786Sps{ 196172471Sdelphij char *str_end = str + strlen(str); 197172471Sdelphij LWCHAR ch; 19860786Sps 199172471Sdelphij while (str < str_end) 200172471Sdelphij { 201172471Sdelphij ch = step_char(&str, +1, str_end); 202172471Sdelphij if (IS_UPPER(ch)) 20360786Sps return (1); 204172471Sdelphij } 20560786Sps return (0); 20660786Sps} 20760786Sps 20860786Sps/* 20960786Sps * Is there a previous (remembered) search pattern? 21060786Sps */ 21160786Sps static int 21260786Spsprev_pattern() 21360786Sps{ 21460786Sps if (last_search_type & SRCH_NO_REGEX) 21560786Sps return (last_pattern != NULL); 21660786Sps#if HAVE_POSIX_REGCOMP 21760786Sps return (regpattern != NULL); 21860786Sps#endif 21960786Sps#if HAVE_PCRE 22060786Sps return (regpattern != NULL); 22160786Sps#endif 22260786Sps#if HAVE_RE_COMP 22360786Sps return (re_pattern != 0); 22460786Sps#endif 22560786Sps#if HAVE_REGCMP 22660786Sps return (cpattern != NULL); 22760786Sps#endif 22860786Sps#if HAVE_V8_REGCOMP 22960786Sps return (regpattern != NULL); 23060786Sps#endif 23160786Sps#if NO_REGEX 23260786Sps return (last_pattern != NULL); 23360786Sps#endif 23460786Sps} 23560786Sps 23660786Sps#if HILITE_SEARCH 23760786Sps/* 23860786Sps * Repaint the hilites currently displayed on the screen. 23960786Sps * Repaint each line which contains highlighted text. 24060786Sps * If on==0, force all hilites off. 24160786Sps */ 24260786Sps public void 24360786Spsrepaint_hilite(on) 24460786Sps int on; 24560786Sps{ 24660786Sps int slinenum; 24760786Sps POSITION pos; 24860786Sps POSITION epos; 24960786Sps int save_hide_hilite; 25060786Sps 25160786Sps if (squished) 25260786Sps repaint(); 25360786Sps 25460786Sps save_hide_hilite = hide_hilite; 25560786Sps if (!on) 25660786Sps { 25760786Sps if (hide_hilite) 25860786Sps return; 25960786Sps hide_hilite = 1; 26060786Sps } 26160786Sps 26260786Sps if (!can_goto_line) 26360786Sps { 26460786Sps repaint(); 26560786Sps hide_hilite = save_hide_hilite; 26660786Sps return; 26760786Sps } 26860786Sps 26960786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 27060786Sps { 27160786Sps pos = position(slinenum); 27260786Sps if (pos == NULL_POSITION) 27360786Sps continue; 27460786Sps epos = position(slinenum+1); 275161478Sdelphij#if 0 27660786Sps /* 27760786Sps * If any character in the line is highlighted, 27860786Sps * repaint the line. 279161478Sdelphij * 280161478Sdelphij * {{ This doesn't work -- if line is drawn with highlights 281161478Sdelphij * which should be erased (e.g. toggle -i with status column), 282161478Sdelphij * we must redraw the line even if it has no highlights. 283161478Sdelphij * For now, just repaint every line. }} 28460786Sps */ 285161478Sdelphij if (is_hilited(pos, epos, 1, NULL)) 286161478Sdelphij#endif 28760786Sps { 28860786Sps (void) forw_line(pos); 28960786Sps goto_line(slinenum); 29060786Sps put_line(); 29160786Sps } 29260786Sps } 293170259Sdelphij if (!oldbot) 294170259Sdelphij lower_left(); 29560786Sps hide_hilite = save_hide_hilite; 29660786Sps} 29760786Sps 29860786Sps/* 29960786Sps * Clear the attn hilite. 30060786Sps */ 30160786Sps public void 30260786Spsclear_attn() 30360786Sps{ 30460786Sps int slinenum; 30560786Sps POSITION old_start_attnpos; 30660786Sps POSITION old_end_attnpos; 30760786Sps POSITION pos; 30860786Sps POSITION epos; 309170898Sdelphij int moved = 0; 31060786Sps 31160786Sps if (start_attnpos == NULL_POSITION) 31260786Sps return; 31360786Sps old_start_attnpos = start_attnpos; 31460786Sps old_end_attnpos = end_attnpos; 31560786Sps start_attnpos = end_attnpos = NULL_POSITION; 31660786Sps 31760786Sps if (!can_goto_line) 31860786Sps { 31960786Sps repaint(); 32060786Sps return; 32160786Sps } 32260786Sps if (squished) 32360786Sps repaint(); 32460786Sps 32560786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 32660786Sps { 32760786Sps pos = position(slinenum); 32860786Sps if (pos == NULL_POSITION) 32960786Sps continue; 33060786Sps epos = position(slinenum+1); 33160786Sps if (pos < old_end_attnpos && 33260786Sps (epos == NULL_POSITION || epos > old_start_attnpos)) 33360786Sps { 33460786Sps (void) forw_line(pos); 33560786Sps goto_line(slinenum); 33660786Sps put_line(); 337170898Sdelphij moved = 1; 33860786Sps } 33960786Sps } 340170898Sdelphij if (moved) 341170898Sdelphij lower_left(); 34260786Sps} 34360786Sps#endif 34460786Sps 34560786Sps/* 34660786Sps * Hide search string highlighting. 34760786Sps */ 34860786Sps public void 34960786Spsundo_search() 35060786Sps{ 35160786Sps if (!prev_pattern()) 35260786Sps { 35360786Sps error("No previous regular expression", NULL_PARG); 35460786Sps return; 35560786Sps } 35660786Sps#if HILITE_SEARCH 35760786Sps hide_hilite = !hide_hilite; 35860786Sps repaint_hilite(1); 35960786Sps#endif 36060786Sps} 36160786Sps 36260786Sps/* 36360786Sps * Compile a search pattern, for future use by match_pattern. 36460786Sps */ 36560786Sps static int 36660786Spscompile_pattern(pattern, search_type) 36760786Sps char *pattern; 36860786Sps int search_type; 36960786Sps{ 37060786Sps if ((search_type & SRCH_NO_REGEX) == 0) 37160786Sps { 37260786Sps#if HAVE_POSIX_REGCOMP 37360786Sps regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t)); 37460786Sps if (regcomp(s, pattern, REGCOMP_FLAG)) 37560786Sps { 37660786Sps free(s); 37760786Sps error("Invalid pattern", NULL_PARG); 37860786Sps return (-1); 37960786Sps } 38060786Sps if (regpattern != NULL) 38160786Sps regfree(regpattern); 38260786Sps regpattern = s; 38360786Sps#endif 38460786Sps#if HAVE_PCRE 38560786Sps pcre *comp; 38660786Sps const char *errstring; 38760786Sps int erroffset; 38860786Sps PARG parg; 38960786Sps comp = pcre_compile(pattern, 0, 39060786Sps &errstring, &erroffset, NULL); 39160786Sps if (comp == NULL) 39260786Sps { 39360786Sps parg.p_string = (char *) errstring; 39460786Sps error("%s", &parg); 39560786Sps return (-1); 39660786Sps } 39760786Sps regpattern = comp; 39860786Sps#endif 39960786Sps#if HAVE_RE_COMP 40060786Sps PARG parg; 40160786Sps if ((parg.p_string = re_comp(pattern)) != NULL) 40260786Sps { 40360786Sps error("%s", &parg); 40460786Sps return (-1); 40560786Sps } 40660786Sps re_pattern = 1; 40760786Sps#endif 40860786Sps#if HAVE_REGCMP 40960786Sps char *s; 41060786Sps if ((s = regcmp(pattern, 0)) == NULL) 41160786Sps { 41260786Sps error("Invalid pattern", NULL_PARG); 41360786Sps return (-1); 41460786Sps } 41560786Sps if (cpattern != NULL) 41660786Sps free(cpattern); 41760786Sps cpattern = s; 41860786Sps#endif 41960786Sps#if HAVE_V8_REGCOMP 42060786Sps struct regexp *s; 42160786Sps if ((s = regcomp(pattern)) == NULL) 42260786Sps { 42360786Sps /* 42460786Sps * regcomp has already printed an error message 42560786Sps * via regerror(). 42660786Sps */ 42760786Sps return (-1); 42860786Sps } 42960786Sps if (regpattern != NULL) 43060786Sps free(regpattern); 43160786Sps regpattern = s; 43260786Sps#endif 43360786Sps } 43460786Sps 43560786Sps if (last_pattern != NULL) 43660786Sps free(last_pattern); 43760786Sps last_pattern = (char *) calloc(1, strlen(pattern)+1); 43860786Sps if (last_pattern != NULL) 43960786Sps strcpy(last_pattern, pattern); 44060786Sps 44160786Sps last_search_type = search_type; 44260786Sps return (0); 44360786Sps} 44460786Sps 44560786Sps/* 44660786Sps * Forget that we have a compiled pattern. 44760786Sps */ 44860786Sps static void 44960786Spsuncompile_pattern() 45060786Sps{ 45160786Sps#if HAVE_POSIX_REGCOMP 45260786Sps if (regpattern != NULL) 45360786Sps regfree(regpattern); 45460786Sps regpattern = NULL; 45560786Sps#endif 45660786Sps#if HAVE_PCRE 45760786Sps if (regpattern != NULL) 45860786Sps pcre_free(regpattern); 45960786Sps regpattern = NULL; 46060786Sps#endif 46160786Sps#if HAVE_RE_COMP 46260786Sps re_pattern = 0; 46360786Sps#endif 46460786Sps#if HAVE_REGCMP 46560786Sps if (cpattern != NULL) 46660786Sps free(cpattern); 46760786Sps cpattern = NULL; 46860786Sps#endif 46960786Sps#if HAVE_V8_REGCOMP 47060786Sps if (regpattern != NULL) 47160786Sps free(regpattern); 47260786Sps regpattern = NULL; 47360786Sps#endif 47460786Sps last_pattern = NULL; 47560786Sps} 47660786Sps 47760786Sps/* 47860786Sps * Perform a pattern match with the previously compiled pattern. 47960786Sps * Set sp and ep to the start and end of the matched string. 48060786Sps */ 48160786Sps static int 482170259Sdelphijmatch_pattern(line, line_len, sp, ep, notbol) 48360786Sps char *line; 484170259Sdelphij int line_len; 48560786Sps char **sp; 48660786Sps char **ep; 48760786Sps int notbol; 48860786Sps{ 48960786Sps int matched; 49060786Sps 49160786Sps if (last_search_type & SRCH_NO_REGEX) 492170259Sdelphij return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep)); 49360786Sps 49460786Sps#if HAVE_POSIX_REGCOMP 49560786Sps { 49660786Sps regmatch_t rm; 49760786Sps int flags = (notbol) ? REG_NOTBOL : 0; 49860786Sps matched = !regexec(regpattern, line, 1, &rm, flags); 49960786Sps if (!matched) 50060786Sps return (0); 50160786Sps#ifndef __WATCOMC__ 50260786Sps *sp = line + rm.rm_so; 50360786Sps *ep = line + rm.rm_eo; 50460786Sps#else 50560786Sps *sp = rm.rm_sp; 50660786Sps *ep = rm.rm_ep; 50760786Sps#endif 50860786Sps } 50960786Sps#endif 51060786Sps#if HAVE_PCRE 51160786Sps { 51260786Sps int flags = (notbol) ? PCRE_NOTBOL : 0; 51360786Sps int ovector[3]; 514170259Sdelphij matched = pcre_exec(regpattern, NULL, line, line_len, 51560786Sps 0, flags, ovector, 3) >= 0; 51660786Sps if (!matched) 51760786Sps return (0); 51860786Sps *sp = line + ovector[0]; 51960786Sps *ep = line + ovector[1]; 52060786Sps } 52160786Sps#endif 52260786Sps#if HAVE_RE_COMP 52360786Sps matched = (re_exec(line) == 1); 52460786Sps /* 52560786Sps * re_exec doesn't seem to provide a way to get the matched string. 52660786Sps */ 52760786Sps *sp = *ep = NULL; 52860786Sps#endif 52960786Sps#if HAVE_REGCMP 53060786Sps *ep = regex(cpattern, line); 53160786Sps matched = (*ep != NULL); 53260786Sps if (!matched) 53360786Sps return (0); 53460786Sps *sp = __loc1; 53560786Sps#endif 53660786Sps#if HAVE_V8_REGCOMP 53760786Sps#if HAVE_REGEXEC2 53860786Sps matched = regexec2(regpattern, line, notbol); 53960786Sps#else 54060786Sps matched = regexec(regpattern, line); 54160786Sps#endif 54260786Sps if (!matched) 54360786Sps return (0); 54460786Sps *sp = regpattern->startp[0]; 54560786Sps *ep = regpattern->endp[0]; 54660786Sps#endif 54760786Sps#if NO_REGEX 548170259Sdelphij matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep); 54960786Sps#endif 55060786Sps return (matched); 55160786Sps} 55260786Sps 55360786Sps#if HILITE_SEARCH 55460786Sps/* 55560786Sps * Clear the hilite list. 55660786Sps */ 55760786Sps public void 55860786Spsclr_hilite() 55960786Sps{ 56060786Sps struct hilite *hl; 56160786Sps struct hilite *nexthl; 56260786Sps 56360786Sps for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl) 56460786Sps { 56560786Sps nexthl = hl->hl_next; 56660786Sps free((void*)hl); 56760786Sps } 56860786Sps hilite_anchor.hl_first = NULL; 56960786Sps prep_startpos = prep_endpos = NULL_POSITION; 57060786Sps} 57160786Sps 57260786Sps/* 57360786Sps * Should any characters in a specified range be highlighted? 574161478Sdelphij */ 575161478Sdelphij static int 576161478Sdelphijis_hilited_range(pos, epos) 577161478Sdelphij POSITION pos; 578161478Sdelphij POSITION epos; 579161478Sdelphij{ 580161478Sdelphij struct hilite *hl; 581161478Sdelphij 582161478Sdelphij /* 583161478Sdelphij * Look at each highlight and see if any part of it falls in the range. 584161478Sdelphij */ 585161478Sdelphij for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) 586161478Sdelphij { 587161478Sdelphij if (hl->hl_endpos > pos && 588161478Sdelphij (epos == NULL_POSITION || epos > hl->hl_startpos)) 589161478Sdelphij return (1); 590161478Sdelphij } 591161478Sdelphij return (0); 592161478Sdelphij} 593161478Sdelphij 594161478Sdelphij/* 595161478Sdelphij * Should any characters in a specified range be highlighted? 59660786Sps * If nohide is nonzero, don't consider hide_hilite. 59760786Sps */ 59860786Sps public int 599161478Sdelphijis_hilited(pos, epos, nohide, p_matches) 60060786Sps POSITION pos; 60160786Sps POSITION epos; 60260786Sps int nohide; 603161478Sdelphij int *p_matches; 60460786Sps{ 605161478Sdelphij int match; 60660786Sps 607161478Sdelphij if (p_matches != NULL) 608161478Sdelphij *p_matches = 0; 609161478Sdelphij 61063131Sps if (!status_col && 61163131Sps start_attnpos != NULL_POSITION && 61260786Sps pos < end_attnpos && 61360786Sps (epos == NULL_POSITION || epos > start_attnpos)) 61460786Sps /* 61560786Sps * The attn line overlaps this range. 61660786Sps */ 61760786Sps return (1); 61860786Sps 619161478Sdelphij match = is_hilited_range(pos, epos); 620161478Sdelphij if (!match) 621161478Sdelphij return (0); 622161478Sdelphij 623161478Sdelphij if (p_matches != NULL) 624161478Sdelphij /* 625161478Sdelphij * Report matches, even if we're hiding highlights. 626161478Sdelphij */ 627161478Sdelphij *p_matches = 1; 628161478Sdelphij 62960786Sps if (hilite_search == 0) 63060786Sps /* 63160786Sps * Not doing highlighting. 63260786Sps */ 63360786Sps return (0); 63460786Sps 63560786Sps if (!nohide && hide_hilite) 63660786Sps /* 63760786Sps * Highlighting is hidden. 63860786Sps */ 63960786Sps return (0); 64060786Sps 641161478Sdelphij return (1); 64260786Sps} 64360786Sps 64460786Sps/* 64560786Sps * Add a new hilite to a hilite list. 64660786Sps */ 64760786Sps static void 64860786Spsadd_hilite(anchor, hl) 64960786Sps struct hilite *anchor; 65060786Sps struct hilite *hl; 65160786Sps{ 65260786Sps struct hilite *ihl; 65360786Sps 65460786Sps /* 65560786Sps * Hilites are sorted in the list; find where new one belongs. 65660786Sps * Insert new one after ihl. 65760786Sps */ 65860786Sps for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next) 65960786Sps { 66060786Sps if (ihl->hl_next->hl_startpos > hl->hl_startpos) 66160786Sps break; 66260786Sps } 66360786Sps 66460786Sps /* 66560786Sps * Truncate hilite so it doesn't overlap any existing ones 66660786Sps * above and below it. 66760786Sps */ 66860786Sps if (ihl != anchor) 66960786Sps hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos); 67060786Sps if (ihl->hl_next != NULL) 67160786Sps hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos); 67260786Sps if (hl->hl_startpos >= hl->hl_endpos) 67360786Sps { 67460786Sps /* 67560786Sps * Hilite was truncated out of existence. 67660786Sps */ 67760786Sps free(hl); 67860786Sps return; 67960786Sps } 68060786Sps hl->hl_next = ihl->hl_next; 68160786Sps ihl->hl_next = hl; 68260786Sps} 68360786Sps 684161478Sdelphij static void 685170259Sdelphijadj_hilite_ansi(cvt_ops, line, line_len, npos) 686161478Sdelphij int cvt_ops; 687161478Sdelphij char **line; 688170259Sdelphij int line_len; 689161478Sdelphij POSITION *npos; 690161478Sdelphij{ 691170259Sdelphij char *line_end = *line + line_len; 692170259Sdelphij 693161478Sdelphij if (cvt_ops & CVT_ANSI) 694172471Sdelphij while (IS_CSI_START(**line)) 695161478Sdelphij { 696161478Sdelphij /* 697161478Sdelphij * Found an ESC. The file position moves 698161478Sdelphij * forward past the entire ANSI escape sequence. 699161478Sdelphij */ 700161478Sdelphij (*line)++; 701161478Sdelphij (*npos)++; 702170259Sdelphij while (*line < line_end) 703161478Sdelphij { 704161478Sdelphij (*npos)++; 705161478Sdelphij if (!is_ansi_middle(*(*line)++)) 706161478Sdelphij break; 707161478Sdelphij } 708161478Sdelphij } 709161478Sdelphij} 710161478Sdelphij 71160786Sps/* 71260786Sps * Adjust hl_startpos & hl_endpos to account for backspace processing. 71360786Sps */ 71460786Sps static void 715128348Stjradj_hilite(anchor, linepos, cvt_ops) 71660786Sps struct hilite *anchor; 71760786Sps POSITION linepos; 718128348Stjr int cvt_ops; 71960786Sps{ 72060786Sps char *line; 721170259Sdelphij int line_len; 722170259Sdelphij char *line_end; 72360786Sps struct hilite *hl; 72460786Sps int checkstart; 72560786Sps POSITION opos; 72660786Sps POSITION npos; 72760786Sps 72860786Sps /* 72960786Sps * The line was already scanned and hilites were added (in hilite_line). 73060786Sps * But it was assumed that each char position in the line 73160786Sps * correponds to one char position in the file. 73260786Sps * This may not be true if there are backspaces in the line. 73360786Sps * Get the raw line again. Look at each character. 73460786Sps */ 735170259Sdelphij (void) forw_raw_line(linepos, &line, &line_len); 736170259Sdelphij line_end = line + line_len; 73760786Sps opos = npos = linepos; 73860786Sps hl = anchor->hl_first; 73960786Sps checkstart = TRUE; 74060786Sps while (hl != NULL) 74160786Sps { 74260786Sps /* 74360786Sps * See if we need to adjust the current hl_startpos or 74460786Sps * hl_endpos. After adjusting startpos[i], move to endpos[i]. 74560786Sps * After adjusting endpos[i], move to startpos[i+1]. 74660786Sps * The hilite list must be sorted thus: 74760786Sps * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc. 74860786Sps */ 74960786Sps if (checkstart && hl->hl_startpos == opos) 75060786Sps { 75160786Sps hl->hl_startpos = npos; 75260786Sps checkstart = FALSE; 75360786Sps continue; /* {{ not really necessary }} */ 75460786Sps } else if (!checkstart && hl->hl_endpos == opos) 75560786Sps { 75660786Sps hl->hl_endpos = npos; 75760786Sps checkstart = TRUE; 75860786Sps hl = hl->hl_next; 75960786Sps continue; /* {{ necessary }} */ 76060786Sps } 761170259Sdelphij if (line == line_end) 76260786Sps break; 763170259Sdelphij adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos); 76460786Sps opos++; 76560786Sps npos++; 76660786Sps line++; 767128348Stjr if (cvt_ops & CVT_BS) 76860786Sps { 769161478Sdelphij while (*line == '\b') 770128348Stjr { 771161478Sdelphij npos++; 772161478Sdelphij line++; 773170259Sdelphij adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos); 774170259Sdelphij if (line == line_end) 775161478Sdelphij { 776161478Sdelphij --npos; 777161478Sdelphij --line; 778161478Sdelphij break; 779161478Sdelphij } 780128348Stjr /* 781128348Stjr * Found a backspace. The file position moves 782128348Stjr * forward by 2 relative to the processed line 783128348Stjr * which was searched in hilite_line. 784128348Stjr */ 785161478Sdelphij npos++; 786161478Sdelphij line++; 787128348Stjr } 78860786Sps } 78960786Sps } 79060786Sps} 79160786Sps 79260786Sps/* 79360786Sps * Make a hilite for each string in a physical line which matches 79460786Sps * the current pattern. 79560786Sps * sp,ep delimit the first match already found. 79660786Sps */ 79760786Sps static void 798170259Sdelphijhilite_line(linepos, line, line_len, sp, ep, cvt_ops) 79960786Sps POSITION linepos; 80060786Sps char *line; 801170259Sdelphij int line_len; 80260786Sps char *sp; 80360786Sps char *ep; 804128348Stjr int cvt_ops; 80560786Sps{ 80660786Sps char *searchp; 807170259Sdelphij char *line_end = line + line_len; 80860786Sps struct hilite *hl; 80960786Sps struct hilite hilites; 81060786Sps 81160786Sps if (sp == NULL || ep == NULL) 81260786Sps return; 81360786Sps /* 81460786Sps * sp and ep delimit the first match in the line. 81560786Sps * Mark the corresponding file positions, then 81660786Sps * look for further matches and mark them. 81760786Sps * {{ This technique, of calling match_pattern on subsequent 81860786Sps * substrings of the line, may mark more than is correct 81960786Sps * if the pattern starts with "^". This bug is fixed 82060786Sps * for those regex functions that accept a notbol parameter 821170259Sdelphij * (currently POSIX, PCRE and V8-with-regexec2). }} 82260786Sps */ 82360786Sps searchp = line; 82460786Sps /* 82560786Sps * Put the hilites into a temporary list until they're adjusted. 82660786Sps */ 82760786Sps hilites.hl_first = NULL; 82860786Sps do { 82960786Sps if (ep > sp) 83060786Sps { 83160786Sps /* 83260786Sps * Assume that each char position in the "line" 83360786Sps * buffer corresponds to one char position in the file. 83460786Sps * This is not quite true; we need to adjust later. 83560786Sps */ 83660786Sps hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); 83760786Sps hl->hl_startpos = linepos + (sp-line); 83860786Sps hl->hl_endpos = linepos + (ep-line); 83960786Sps add_hilite(&hilites, hl); 84060786Sps } 84160786Sps /* 84260786Sps * If we matched more than zero characters, 84360786Sps * move to the first char after the string we matched. 84460786Sps * If we matched zero, just move to the next char. 84560786Sps */ 84660786Sps if (ep > searchp) 84760786Sps searchp = ep; 848170259Sdelphij else if (searchp != line_end) 84960786Sps searchp++; 85060786Sps else /* end of line */ 85160786Sps break; 852170259Sdelphij } while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1)); 85360786Sps 85460786Sps /* 855128348Stjr * If there were backspaces in the original line, they 856128348Stjr * were removed, and hl_startpos/hl_endpos are not correct. 857128348Stjr * {{ This is very ugly. }} 858128348Stjr */ 859128348Stjr adj_hilite(&hilites, linepos, cvt_ops); 860128348Stjr 861128348Stjr /* 86260786Sps * Now put the hilites into the real list. 86360786Sps */ 86460786Sps while ((hl = hilites.hl_next) != NULL) 86560786Sps { 86660786Sps hilites.hl_next = hl->hl_next; 86760786Sps add_hilite(&hilite_anchor, hl); 86860786Sps } 86960786Sps} 87060786Sps#endif 87160786Sps 87260786Sps/* 87360786Sps * Change the caseless-ness of searches. 87460786Sps * Updates the internal search state to reflect a change in the -i flag. 87560786Sps */ 87660786Sps public void 87760786Spschg_caseless() 87860786Sps{ 87960786Sps if (!is_ucase_pattern) 88060786Sps /* 88160786Sps * Pattern did not have uppercase. 88260786Sps * Just set the search caselessness to the global caselessness. 88360786Sps */ 88460786Sps is_caseless = caseless; 88560786Sps else 88660786Sps /* 88760786Sps * Pattern did have uppercase. 88860786Sps * Discard the pattern; we can't change search caselessness now. 88960786Sps */ 89060786Sps uncompile_pattern(); 89160786Sps} 89260786Sps 89360786Sps#if HILITE_SEARCH 89460786Sps/* 89560786Sps * Find matching text which is currently on screen and highlight it. 89660786Sps */ 89760786Sps static void 89860786Spshilite_screen() 89960786Sps{ 90060786Sps struct scrpos scrpos; 90160786Sps 90260786Sps get_scrpos(&scrpos); 90360786Sps if (scrpos.pos == NULL_POSITION) 90460786Sps return; 90560786Sps prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); 90660786Sps repaint_hilite(1); 90760786Sps} 90860786Sps 90960786Sps/* 91060786Sps * Change highlighting parameters. 91160786Sps */ 91260786Sps public void 91360786Spschg_hilite() 91460786Sps{ 91560786Sps /* 91660786Sps * Erase any highlights currently on screen. 91760786Sps */ 91860786Sps clr_hilite(); 91960786Sps hide_hilite = 0; 92060786Sps 92160786Sps if (hilite_search == OPT_ONPLUS) 92260786Sps /* 92360786Sps * Display highlights. 92460786Sps */ 92560786Sps hilite_screen(); 92660786Sps} 92760786Sps#endif 92860786Sps 92960786Sps/* 93060786Sps * Figure out where to start a search. 93160786Sps */ 93260786Sps static POSITION 93360786Spssearch_pos(search_type) 93460786Sps int search_type; 93560786Sps{ 93660786Sps POSITION pos; 93760786Sps int linenum; 93860786Sps 93960786Sps if (empty_screen()) 94060786Sps { 94160786Sps /* 94260786Sps * Start at the beginning (or end) of the file. 94360786Sps * The empty_screen() case is mainly for 94460786Sps * command line initiated searches; 94560786Sps * for example, "+/xyz" on the command line. 94660786Sps * Also for multi-file (SRCH_PAST_EOF) searches. 94760786Sps */ 94860786Sps if (search_type & SRCH_FORW) 94960786Sps { 95060786Sps return (ch_zero()); 95160786Sps } else 95260786Sps { 95360786Sps pos = ch_length(); 95460786Sps if (pos == NULL_POSITION) 95560786Sps { 95660786Sps (void) ch_end_seek(); 95760786Sps pos = ch_length(); 95860786Sps } 95960786Sps return (pos); 96060786Sps } 96160786Sps } 96260786Sps if (how_search) 96360786Sps { 96460786Sps /* 96560786Sps * Search does not include current screen. 96660786Sps */ 96760786Sps if (search_type & SRCH_FORW) 96860786Sps linenum = BOTTOM_PLUS_ONE; 96960786Sps else 97060786Sps linenum = TOP; 97160786Sps pos = position(linenum); 97260786Sps } else 97360786Sps { 97460786Sps /* 97560786Sps * Search includes current screen. 97660786Sps * It starts at the jump target (if searching backwards), 97760786Sps * or at the jump target plus one (if forwards). 97860786Sps */ 97960786Sps linenum = adjsline(jump_sline); 98060786Sps pos = position(linenum); 98160786Sps if (search_type & SRCH_FORW) 98260786Sps { 983170259Sdelphij pos = forw_raw_line(pos, (char **)NULL, (int *)NULL); 98460786Sps while (pos == NULL_POSITION) 98560786Sps { 98660786Sps if (++linenum >= sc_height) 98760786Sps break; 98860786Sps pos = position(linenum); 98960786Sps } 99060786Sps } else 99160786Sps { 99260786Sps while (pos == NULL_POSITION) 99360786Sps { 99460786Sps if (--linenum < 0) 99560786Sps break; 99660786Sps pos = position(linenum); 99760786Sps } 99860786Sps } 99960786Sps } 100060786Sps return (pos); 100160786Sps} 100260786Sps 100360786Sps/* 100460786Sps * Search a subset of the file, specified by start/end position. 100560786Sps */ 100660786Sps static int 100760786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) 100860786Sps POSITION pos; 100960786Sps POSITION endpos; 101060786Sps int search_type; 101160786Sps int matches; 101260786Sps int maxlines; 101360786Sps POSITION *plinepos; 101460786Sps POSITION *pendpos; 101560786Sps{ 101660786Sps char *line; 1017170259Sdelphij int line_len; 1018128348Stjr LINENUM linenum; 101960786Sps char *sp, *ep; 102060786Sps int line_match; 1021128348Stjr int cvt_ops; 102260786Sps POSITION linepos, oldpos; 102360786Sps 102460786Sps linenum = find_linenum(pos); 102560786Sps oldpos = pos; 102660786Sps for (;;) 102760786Sps { 102860786Sps /* 102960786Sps * Get lines until we find a matching one or until 103060786Sps * we hit end-of-file (or beginning-of-file if we're 103160786Sps * going backwards), or until we hit the end position. 103260786Sps */ 103360786Sps if (ABORT_SIGS()) 103460786Sps { 103560786Sps /* 103660786Sps * A signal aborts the search. 103760786Sps */ 103860786Sps return (-1); 103960786Sps } 104060786Sps 104160786Sps if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) 104260786Sps { 104360786Sps /* 104460786Sps * Reached end position without a match. 104560786Sps */ 104660786Sps if (pendpos != NULL) 104760786Sps *pendpos = pos; 104860786Sps return (matches); 104960786Sps } 105060786Sps if (maxlines > 0) 105160786Sps maxlines--; 105260786Sps 105360786Sps if (search_type & SRCH_FORW) 105460786Sps { 105560786Sps /* 105660786Sps * Read the next line, and save the 105760786Sps * starting position of that line in linepos. 105860786Sps */ 105960786Sps linepos = pos; 1060170259Sdelphij pos = forw_raw_line(pos, &line, &line_len); 106160786Sps if (linenum != 0) 106260786Sps linenum++; 106360786Sps } else 106460786Sps { 106560786Sps /* 106660786Sps * Read the previous line and save the 106760786Sps * starting position of that line in linepos. 106860786Sps */ 1069170259Sdelphij pos = back_raw_line(pos, &line, &line_len); 107060786Sps linepos = pos; 107160786Sps if (linenum != 0) 107260786Sps linenum--; 107360786Sps } 107460786Sps 107560786Sps if (pos == NULL_POSITION) 107660786Sps { 107760786Sps /* 107860786Sps * Reached EOF/BOF without a match. 107960786Sps */ 108060786Sps if (pendpos != NULL) 108160786Sps *pendpos = oldpos; 108260786Sps return (matches); 108360786Sps } 108460786Sps 108560786Sps /* 108660786Sps * If we're using line numbers, we might as well 108760786Sps * remember the information we have now (the position 108860786Sps * and line number of the current line). 108960786Sps * Don't do it for every line because it slows down 109060786Sps * the search. Remember the line number only if 109160786Sps * we're "far" from the last place we remembered it. 109260786Sps */ 109360786Sps if (linenums && abs((int)(pos - oldpos)) > 1024) 109460786Sps add_lnum(linenum, pos); 109560786Sps oldpos = pos; 109660786Sps 109760786Sps /* 109860786Sps * If it's a caseless search, convert the line to lowercase. 109960786Sps * If we're doing backspace processing, delete backspaces. 110060786Sps */ 1101128348Stjr cvt_ops = get_cvt_ops(); 1102170259Sdelphij cvt_text(line, line, &line_len, cvt_ops); 110360786Sps 110460786Sps /* 110560786Sps * Test the next line to see if we have a match. 110660786Sps * We are successful if we either want a match and got one, 110760786Sps * or if we want a non-match and got one. 110860786Sps */ 1109170259Sdelphij line_match = match_pattern(line, line_len, &sp, &ep, 0); 111060786Sps line_match = (!(search_type & SRCH_NO_MATCH) && line_match) || 111160786Sps ((search_type & SRCH_NO_MATCH) && !line_match); 111260786Sps if (!line_match) 111360786Sps continue; 111460786Sps /* 111560786Sps * Got a match. 111660786Sps */ 111760786Sps if (search_type & SRCH_FIND_ALL) 111860786Sps { 111960786Sps#if HILITE_SEARCH 112060786Sps /* 112160786Sps * We are supposed to find all matches in the range. 112260786Sps * Just add the matches in this line to the 112360786Sps * hilite list and keep searching. 112460786Sps */ 112560786Sps if (line_match) 1126170259Sdelphij hilite_line(linepos, line, line_len, sp, ep, cvt_ops); 112760786Sps#endif 112860786Sps } else if (--matches <= 0) 112960786Sps { 113060786Sps /* 113160786Sps * Found the one match we're looking for. 113260786Sps * Return it. 113360786Sps */ 113460786Sps#if HILITE_SEARCH 1135161478Sdelphij if (hilite_search == OPT_ON) 113660786Sps { 113760786Sps /* 113860786Sps * Clear the hilite list and add only 113960786Sps * the matches in this one line. 114060786Sps */ 114160786Sps clr_hilite(); 114260786Sps if (line_match) 1143170259Sdelphij hilite_line(linepos, line, line_len, sp, ep, cvt_ops); 114460786Sps } 114560786Sps#endif 114660786Sps if (plinepos != NULL) 114760786Sps *plinepos = linepos; 114860786Sps return (0); 114960786Sps } 115060786Sps } 115160786Sps} 115260786Sps 1153170259Sdelphij /* 1154170259Sdelphij * search for a pattern in history. If found, compile that pattern. 1155170259Sdelphij */ 1156170259Sdelphij static int 1157170259Sdelphijhist_pattern(search_type) 1158170259Sdelphij int search_type; 1159170259Sdelphij{ 1160170259Sdelphij#if CMD_HISTORY 1161170259Sdelphij char *pattern; 1162170259Sdelphij 1163170259Sdelphij set_mlist(ml_search, 0); 1164170259Sdelphij pattern = cmd_lastpattern(); 1165170259Sdelphij if (pattern == NULL) 1166170259Sdelphij return (0); 1167170259Sdelphij 1168170259Sdelphij if (caseless == OPT_ONPLUS) 1169170259Sdelphij cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC); 1170170259Sdelphij 1171170259Sdelphij if (compile_pattern(pattern, search_type) < 0) 1172170259Sdelphij return (0); 1173170259Sdelphij 1174170259Sdelphij is_ucase_pattern = is_ucase(pattern); 1175170259Sdelphij if (is_ucase_pattern && caseless != OPT_ONPLUS) 1176170259Sdelphij is_caseless = 0; 1177170259Sdelphij else 1178170259Sdelphij is_caseless = caseless; 1179170259Sdelphij 1180170259Sdelphij#if HILITE_SEARCH 1181170259Sdelphij if (hilite_search == OPT_ONPLUS && !hide_hilite) 1182170259Sdelphij hilite_screen(); 1183170259Sdelphij#endif 1184170259Sdelphij 1185170259Sdelphij return (1); 1186170259Sdelphij#else /* CMD_HISTORY */ 1187170259Sdelphij return (0); 1188170259Sdelphij#endif /* CMD_HISTORY */ 1189170259Sdelphij} 1190170259Sdelphij 119160786Sps/* 119260786Sps * Search for the n-th occurrence of a specified pattern, 119360786Sps * either forward or backward. 119460786Sps * Return the number of matches not yet found in this file 119560786Sps * (that is, n minus the number of matches found). 119660786Sps * Return -1 if the search should be aborted. 119760786Sps * Caller may continue the search in another file 119860786Sps * if less than n matches are found in this file. 119960786Sps */ 120060786Sps public int 120160786Spssearch(search_type, pattern, n) 120260786Sps int search_type; 120360786Sps char *pattern; 120460786Sps int n; 120560786Sps{ 120660786Sps POSITION pos; 120760786Sps int ucase; 120860786Sps 120960786Sps if (pattern == NULL || *pattern == '\0') 121060786Sps { 121160786Sps /* 121260786Sps * A null pattern means use the previously compiled pattern. 121360786Sps */ 1214170259Sdelphij if (!prev_pattern() && !hist_pattern(search_type)) 121560786Sps { 121660786Sps error("No previous regular expression", NULL_PARG); 121760786Sps return (-1); 121860786Sps } 121960786Sps if ((search_type & SRCH_NO_REGEX) != 122060786Sps (last_search_type & SRCH_NO_REGEX)) 122160786Sps { 122260786Sps error("Please re-enter search pattern", NULL_PARG); 122360786Sps return -1; 122460786Sps } 122560786Sps#if HILITE_SEARCH 122660786Sps if (hilite_search == OPT_ON) 122760786Sps { 122860786Sps /* 122960786Sps * Erase the highlights currently on screen. 123060786Sps * If the search fails, we'll redisplay them later. 123160786Sps */ 123260786Sps repaint_hilite(0); 123360786Sps } 123460786Sps if (hilite_search == OPT_ONPLUS && hide_hilite) 123560786Sps { 123660786Sps /* 123760786Sps * Highlight any matches currently on screen, 123860786Sps * before we actually start the search. 123960786Sps */ 124060786Sps hide_hilite = 0; 124160786Sps hilite_screen(); 124260786Sps } 124360786Sps hide_hilite = 0; 124460786Sps#endif 124560786Sps } else 124660786Sps { 124760786Sps /* 124860786Sps * Compile the pattern. 124960786Sps */ 125060786Sps ucase = is_ucase(pattern); 125160786Sps if (caseless == OPT_ONPLUS) 1252170259Sdelphij cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC); 125360786Sps if (compile_pattern(pattern, search_type) < 0) 125460786Sps return (-1); 125560786Sps /* 125660786Sps * Ignore case if -I is set OR 125760786Sps * -i is set AND the pattern is all lowercase. 125860786Sps */ 125960786Sps is_ucase_pattern = ucase; 126060786Sps if (is_ucase_pattern && caseless != OPT_ONPLUS) 126160786Sps is_caseless = 0; 126260786Sps else 126360786Sps is_caseless = caseless; 126460786Sps#if HILITE_SEARCH 126560786Sps if (hilite_search) 126660786Sps { 126760786Sps /* 126860786Sps * Erase the highlights currently on screen. 126960786Sps * Also permanently delete them from the hilite list. 127060786Sps */ 127160786Sps repaint_hilite(0); 127260786Sps hide_hilite = 0; 127360786Sps clr_hilite(); 127460786Sps } 127560786Sps if (hilite_search == OPT_ONPLUS) 127660786Sps { 127760786Sps /* 127860786Sps * Highlight any matches currently on screen, 127960786Sps * before we actually start the search. 128060786Sps */ 128160786Sps hilite_screen(); 128260786Sps } 128360786Sps#endif 128460786Sps } 128560786Sps 128660786Sps /* 128760786Sps * Figure out where to start the search. 128860786Sps */ 128960786Sps pos = search_pos(search_type); 129060786Sps if (pos == NULL_POSITION) 129160786Sps { 129260786Sps /* 129360786Sps * Can't find anyplace to start searching from. 129460786Sps */ 129560786Sps if (search_type & SRCH_PAST_EOF) 129660786Sps return (n); 129760786Sps /* repaint(); -- why was this here? */ 129860786Sps error("Nothing to search", NULL_PARG); 129960786Sps return (-1); 130060786Sps } 130160786Sps 130260786Sps n = search_range(pos, NULL_POSITION, search_type, n, -1, 130360786Sps &pos, (POSITION*)NULL); 130460786Sps if (n != 0) 130560786Sps { 130660786Sps /* 130760786Sps * Search was unsuccessful. 130860786Sps */ 130960786Sps#if HILITE_SEARCH 131060786Sps if (hilite_search == OPT_ON && n > 0) 131160786Sps /* 131260786Sps * Redisplay old hilites. 131360786Sps */ 131460786Sps repaint_hilite(1); 131560786Sps#endif 131660786Sps return (n); 131760786Sps } 131860786Sps 131960786Sps if (!(search_type & SRCH_NO_MOVE)) 132060786Sps { 132160786Sps /* 132260786Sps * Go to the matching line. 132360786Sps */ 132460786Sps jump_loc(pos, jump_sline); 132560786Sps } 132660786Sps 132760786Sps#if HILITE_SEARCH 132860786Sps if (hilite_search == OPT_ON) 132960786Sps /* 133060786Sps * Display new hilites in the matching line. 133160786Sps */ 133260786Sps repaint_hilite(1); 133360786Sps#endif 133460786Sps return (0); 133560786Sps} 133660786Sps 133760786Sps 133860786Sps#if HILITE_SEARCH 133960786Sps/* 134060786Sps * Prepare hilites in a given range of the file. 134160786Sps * 134260786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region 134360786Sps * of the file that has been "prepared"; that is, scanned for matches for 134460786Sps * the current search pattern, and hilites have been created for such matches. 134560786Sps * If prep_startpos == NULL_POSITION, the prep region is empty. 134660786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF. 134760786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region. 134860786Sps */ 134960786Sps public void 135060786Spsprep_hilite(spos, epos, maxlines) 135160786Sps POSITION spos; 135260786Sps POSITION epos; 135360786Sps int maxlines; 135460786Sps{ 135560786Sps POSITION nprep_startpos = prep_startpos; 135660786Sps POSITION nprep_endpos = prep_endpos; 135760786Sps POSITION new_epos; 135860786Sps POSITION max_epos; 135960786Sps int result; 136060786Sps int i; 136160786Sps/* 136260786Sps * Search beyond where we're asked to search, so the prep region covers 136360786Sps * more than we need. Do one big search instead of a bunch of small ones. 136460786Sps */ 136560786Sps#define SEARCH_MORE (3*size_linebuf) 136660786Sps 136760786Sps if (!prev_pattern()) 136860786Sps return; 136960786Sps 137060786Sps /* 137160786Sps * If we're limited to a max number of lines, figure out the 137260786Sps * file position we should stop at. 137360786Sps */ 137460786Sps if (maxlines < 0) 137560786Sps max_epos = NULL_POSITION; 137660786Sps else 137760786Sps { 137860786Sps max_epos = spos; 137960786Sps for (i = 0; i < maxlines; i++) 1380170259Sdelphij max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); 138160786Sps } 138260786Sps 138360786Sps /* 138460786Sps * Find two ranges: 138560786Sps * The range that we need to search (spos,epos); and the range that 138660786Sps * the "prep" region will then cover (nprep_startpos,nprep_endpos). 138760786Sps */ 138860786Sps 138960786Sps if (prep_startpos == NULL_POSITION || 139060786Sps (epos != NULL_POSITION && epos < prep_startpos) || 139160786Sps spos > prep_endpos) 139260786Sps { 139360786Sps /* 139460786Sps * New range is not contiguous with old prep region. 139560786Sps * Discard the old prep region and start a new one. 139660786Sps */ 139760786Sps clr_hilite(); 139860786Sps if (epos != NULL_POSITION) 139960786Sps epos += SEARCH_MORE; 140060786Sps nprep_startpos = spos; 140160786Sps } else 140260786Sps { 140360786Sps /* 140460786Sps * New range partially or completely overlaps old prep region. 140560786Sps */ 140660786Sps if (epos == NULL_POSITION) 140760786Sps { 140860786Sps /* 140960786Sps * New range goes to end of file. 141060786Sps */ 141160786Sps ; 141260786Sps } else if (epos > prep_endpos) 141360786Sps { 141460786Sps /* 141560786Sps * New range ends after old prep region. 141660786Sps * Extend prep region to end at end of new range. 141760786Sps */ 141860786Sps epos += SEARCH_MORE; 141960786Sps } else /* (epos <= prep_endpos) */ 142060786Sps { 142160786Sps /* 142260786Sps * New range ends within old prep region. 142360786Sps * Truncate search to end at start of old prep region. 142460786Sps */ 142560786Sps epos = prep_startpos; 142660786Sps } 142760786Sps 142860786Sps if (spos < prep_startpos) 142960786Sps { 143060786Sps /* 143160786Sps * New range starts before old prep region. 143260786Sps * Extend old prep region backwards to start at 143360786Sps * start of new range. 143460786Sps */ 143560786Sps if (spos < SEARCH_MORE) 143660786Sps spos = 0; 143760786Sps else 143860786Sps spos -= SEARCH_MORE; 143960786Sps nprep_startpos = spos; 144060786Sps } else /* (spos >= prep_startpos) */ 144160786Sps { 144260786Sps /* 144360786Sps * New range starts within or after old prep region. 144460786Sps * Trim search to start at end of old prep region. 144560786Sps */ 144660786Sps spos = prep_endpos; 144760786Sps } 144860786Sps } 144960786Sps 145060786Sps if (epos != NULL_POSITION && max_epos != NULL_POSITION && 145160786Sps epos > max_epos) 145260786Sps /* 145360786Sps * Don't go past the max position we're allowed. 145460786Sps */ 145560786Sps epos = max_epos; 145660786Sps 145760786Sps if (epos == NULL_POSITION || epos > spos) 145860786Sps { 145960786Sps result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, 146060786Sps maxlines, (POSITION*)NULL, &new_epos); 146160786Sps if (result < 0) 146260786Sps return; 146360786Sps if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 146460786Sps nprep_endpos = new_epos; 146560786Sps } 146660786Sps prep_startpos = nprep_startpos; 146760786Sps prep_endpos = nprep_endpos; 146860786Sps} 146960786Sps#endif 147060786Sps 147160786Sps/* 147260786Sps * Simple pattern matching function. 147360786Sps * It supports no metacharacters like *, etc. 147460786Sps */ 147560786Sps static int 1476170259Sdelphijmatch(pattern, pattern_len, buf, buf_len, pfound, pend) 1477170259Sdelphij char *pattern; 1478170259Sdelphij int pattern_len; 1479170259Sdelphij char *buf; 1480170259Sdelphij int buf_len; 148160786Sps char **pfound, **pend; 148260786Sps{ 148360786Sps register char *pp, *lp; 1484170259Sdelphij register char *pattern_end = pattern + pattern_len; 1485170259Sdelphij register char *buf_end = buf + buf_len; 148660786Sps 1487170259Sdelphij for ( ; buf < buf_end; buf++) 148860786Sps { 148960786Sps for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) 1490170259Sdelphij if (pp == pattern_end || lp == buf_end) 149160786Sps break; 1492170259Sdelphij if (pp == pattern_end) 149360786Sps { 149460786Sps if (pfound != NULL) 149560786Sps *pfound = buf; 149660786Sps if (pend != NULL) 149760786Sps *pend = lp; 149860786Sps return (1); 149960786Sps } 150060786Sps } 150160786Sps return (0); 150260786Sps} 150360786Sps 150460786Sps#if HAVE_V8_REGCOMP 150560786Sps/* 150660786Sps * This function is called by the V8 regcomp to report 150760786Sps * errors in regular expressions. 150860786Sps */ 150960786Sps void 151060786Spsregerror(s) 151160786Sps char *s; 151260786Sps{ 151360786Sps PARG parg; 151460786Sps 151560786Sps parg.p_string = s; 151660786Sps error("%s", &parg); 151760786Sps} 151860786Sps#endif 151960786Sps 1520