search.c revision 170259
160812Sps/* $FreeBSD: head/contrib/less/search.c 170259 2007-06-04 01:43:11Z 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" 1960786Sps 2060786Sps#define MINPOS(a,b) (((a) < (b)) ? (a) : (b)) 2160786Sps#define MAXPOS(a,b) (((a) > (b)) ? (a) : (b)) 2260786Sps 2360786Sps#if HAVE_POSIX_REGCOMP 2460786Sps#include <regex.h> 2560786Sps#ifdef REG_EXTENDED 26170259Sdelphij#define REGCOMP_FLAG (less_is_more ? 0 : REG_EXTENDED) 2760786Sps#else 2860786Sps#define REGCOMP_FLAG 0 2960786Sps#endif 3060786Sps#endif 3160786Sps#if HAVE_PCRE 3260786Sps#include <pcre.h> 3360786Sps#endif 3460786Sps#if HAVE_RE_COMP 3560786Spschar *re_comp(); 3660786Spsint re_exec(); 3760786Sps#endif 3860786Sps#if HAVE_REGCMP 3960786Spschar *regcmp(); 4060786Spschar *regex(); 4160786Spsextern char *__loc1; 4260786Sps#endif 4360786Sps#if HAVE_V8_REGCOMP 4460786Sps#include "regexp.h" 4560786Sps#endif 4660786Sps 4760786Spsstatic int match(); 4860786Sps 4960786Spsextern int sigs; 5060786Spsextern int how_search; 5160786Spsextern int caseless; 5260786Spsextern int linenums; 5360786Spsextern int sc_height; 5460786Spsextern int jump_sline; 5560786Spsextern int bs_mode; 56170259Sdelphijextern int less_is_more; 57128348Stjrextern int ctldisp; 5863131Spsextern int status_col; 59170259Sdelphijextern void * constant ml_search; 6060786Spsextern POSITION start_attnpos; 6160786Spsextern POSITION end_attnpos; 6260786Sps#if HILITE_SEARCH 6360786Spsextern int hilite_search; 6460786Spsextern int screen_trashed; 6560786Spsextern int size_linebuf; 6660786Spsextern int squished; 6760786Spsextern int can_goto_line; 6860786Spsstatic int hide_hilite; 69170259Sdelphijstatic int oldbot; 7060786Spsstatic POSITION prep_startpos; 7160786Spsstatic POSITION prep_endpos; 7260786Sps 7360786Spsstruct hilite 7460786Sps{ 7560786Sps struct hilite *hl_next; 7660786Sps POSITION hl_startpos; 7760786Sps POSITION hl_endpos; 7860786Sps}; 7960786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 8060786Sps#define hl_first hl_next 8160786Sps#endif 8260786Sps 8360786Sps/* 8460786Sps * These are the static variables that represent the "remembered" 8560786Sps * search pattern. 8660786Sps */ 8760786Sps#if HAVE_POSIX_REGCOMP 8860786Spsstatic regex_t *regpattern = NULL; 8960786Sps#endif 9060786Sps#if HAVE_PCRE 9160786Spspcre *regpattern = NULL; 9260786Sps#endif 9360786Sps#if HAVE_RE_COMP 9460786Spsint re_pattern = 0; 9560786Sps#endif 9660786Sps#if HAVE_REGCMP 9760786Spsstatic char *cpattern = NULL; 9860786Sps#endif 9960786Sps#if HAVE_V8_REGCOMP 10060786Spsstatic struct regexp *regpattern = NULL; 10160786Sps#endif 10260786Sps 10360786Spsstatic int is_caseless; 10460786Spsstatic int is_ucase_pattern; 10560786Spsstatic int last_search_type; 10660786Spsstatic char *last_pattern = NULL; 10760786Sps 10860786Sps/* 10960786Sps * Convert text. Perform one or more of these transformations: 11060786Sps */ 11160786Sps#define CVT_TO_LC 01 /* Convert upper-case to lower-case */ 11260786Sps#define CVT_BS 02 /* Do backspace processing */ 11360786Sps#define CVT_CRLF 04 /* Remove CR after LF */ 114128348Stjr#define CVT_ANSI 010 /* Remove ANSI escape sequences */ 11560786Sps 11660786Sps static void 117170259Sdelphijcvt_text(odst, osrc, lenp, ops) 11860786Sps char *odst; 11960786Sps char *osrc; 120170259Sdelphij int *lenp; 12160786Sps int ops; 12260786Sps{ 12360786Sps register char *dst; 12460786Sps register char *src; 125170259Sdelphij register char *src_end; 12660786Sps 127170259Sdelphij if (lenp != NULL) 128170259Sdelphij src_end = osrc + *lenp; 129170259Sdelphij else 130170259Sdelphij src_end = osrc + strlen(osrc); 131170259Sdelphij 132170259Sdelphij for (src = osrc, dst = odst; src < src_end; src++) 13360786Sps { 134161478Sdelphij if ((ops & CVT_TO_LC) && IS_UPPER(*src)) 13560786Sps /* Convert uppercase to lowercase. */ 136161478Sdelphij *dst++ = TO_LOWER(*src); 13760786Sps else if ((ops & CVT_BS) && *src == '\b' && dst > odst) 13860786Sps /* Delete BS and preceding char. */ 139128348Stjr dst--; 140128348Stjr else if ((ops & CVT_ANSI) && *src == ESC) 141128348Stjr { 142128348Stjr /* Skip to end of ANSI escape sequence. */ 143170259Sdelphij while (src + 1 != src_end) 144161478Sdelphij if (!is_ansi_middle(*++src)) 145128348Stjr break; 146128348Stjr } else 14760786Sps /* Just copy. */ 148128348Stjr *dst++ = *src; 14960786Sps } 15060786Sps if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r') 15160786Sps dst--; 15260786Sps *dst = '\0'; 153170259Sdelphij if (lenp != NULL) 154170259Sdelphij *lenp = dst - odst; 15560786Sps} 15660786Sps 15760786Sps/* 158128348Stjr * Determine which conversions to perform. 159128348Stjr */ 160128348Stjr static int 161128348Stjrget_cvt_ops() 162128348Stjr{ 163128348Stjr int ops = 0; 164128348Stjr if (is_caseless || bs_mode == BS_SPECIAL) 165128348Stjr { 166128348Stjr if (is_caseless) 167128348Stjr ops |= CVT_TO_LC; 168128348Stjr if (bs_mode == BS_SPECIAL) 169128348Stjr ops |= CVT_BS; 170128348Stjr if (bs_mode != BS_CONTROL) 171128348Stjr ops |= CVT_CRLF; 172128348Stjr } else if (bs_mode != BS_CONTROL) 173128348Stjr { 174128348Stjr ops |= CVT_CRLF; 175128348Stjr } 176128348Stjr if (ctldisp == OPT_ONPLUS) 177128348Stjr ops |= CVT_ANSI; 178128348Stjr return (ops); 179128348Stjr} 180128348Stjr 181128348Stjr/* 18260786Sps * Are there any uppercase letters in this string? 18360786Sps */ 18460786Sps static int 18560786Spsis_ucase(s) 18660786Sps char *s; 18760786Sps{ 18860786Sps register char *p; 18960786Sps 19060786Sps for (p = s; *p != '\0'; p++) 191161478Sdelphij if (IS_UPPER(*p)) 19260786Sps return (1); 19360786Sps return (0); 19460786Sps} 19560786Sps 19660786Sps/* 19760786Sps * Is there a previous (remembered) search pattern? 19860786Sps */ 19960786Sps static int 20060786Spsprev_pattern() 20160786Sps{ 20260786Sps if (last_search_type & SRCH_NO_REGEX) 20360786Sps return (last_pattern != NULL); 20460786Sps#if HAVE_POSIX_REGCOMP 20560786Sps return (regpattern != NULL); 20660786Sps#endif 20760786Sps#if HAVE_PCRE 20860786Sps return (regpattern != NULL); 20960786Sps#endif 21060786Sps#if HAVE_RE_COMP 21160786Sps return (re_pattern != 0); 21260786Sps#endif 21360786Sps#if HAVE_REGCMP 21460786Sps return (cpattern != NULL); 21560786Sps#endif 21660786Sps#if HAVE_V8_REGCOMP 21760786Sps return (regpattern != NULL); 21860786Sps#endif 21960786Sps#if NO_REGEX 22060786Sps return (last_pattern != NULL); 22160786Sps#endif 22260786Sps} 22360786Sps 22460786Sps#if HILITE_SEARCH 22560786Sps/* 22660786Sps * Repaint the hilites currently displayed on the screen. 22760786Sps * Repaint each line which contains highlighted text. 22860786Sps * If on==0, force all hilites off. 22960786Sps */ 23060786Sps public void 23160786Spsrepaint_hilite(on) 23260786Sps int on; 23360786Sps{ 23460786Sps int slinenum; 23560786Sps POSITION pos; 23660786Sps POSITION epos; 23760786Sps int save_hide_hilite; 23860786Sps 23960786Sps if (squished) 24060786Sps repaint(); 24160786Sps 24260786Sps save_hide_hilite = hide_hilite; 24360786Sps if (!on) 24460786Sps { 24560786Sps if (hide_hilite) 24660786Sps return; 24760786Sps hide_hilite = 1; 24860786Sps } 24960786Sps 25060786Sps if (!can_goto_line) 25160786Sps { 25260786Sps repaint(); 25360786Sps hide_hilite = save_hide_hilite; 25460786Sps return; 25560786Sps } 25660786Sps 25760786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 25860786Sps { 25960786Sps pos = position(slinenum); 26060786Sps if (pos == NULL_POSITION) 26160786Sps continue; 26260786Sps epos = position(slinenum+1); 263161478Sdelphij#if 0 26460786Sps /* 26560786Sps * If any character in the line is highlighted, 26660786Sps * repaint the line. 267161478Sdelphij * 268161478Sdelphij * {{ This doesn't work -- if line is drawn with highlights 269161478Sdelphij * which should be erased (e.g. toggle -i with status column), 270161478Sdelphij * we must redraw the line even if it has no highlights. 271161478Sdelphij * For now, just repaint every line. }} 27260786Sps */ 273161478Sdelphij if (is_hilited(pos, epos, 1, NULL)) 274161478Sdelphij#endif 27560786Sps { 27660786Sps (void) forw_line(pos); 27760786Sps goto_line(slinenum); 27860786Sps put_line(); 27960786Sps } 28060786Sps } 281170259Sdelphij if (!oldbot) 282170259Sdelphij lower_left(); 28360786Sps hide_hilite = save_hide_hilite; 28460786Sps} 28560786Sps 28660786Sps/* 28760786Sps * Clear the attn hilite. 28860786Sps */ 28960786Sps public void 29060786Spsclear_attn() 29160786Sps{ 29260786Sps int slinenum; 29360786Sps POSITION old_start_attnpos; 29460786Sps POSITION old_end_attnpos; 29560786Sps POSITION pos; 29660786Sps POSITION epos; 29760786Sps 29860786Sps if (start_attnpos == NULL_POSITION) 29960786Sps return; 30060786Sps old_start_attnpos = start_attnpos; 30160786Sps old_end_attnpos = end_attnpos; 30260786Sps start_attnpos = end_attnpos = NULL_POSITION; 30360786Sps 30460786Sps if (!can_goto_line) 30560786Sps { 30660786Sps repaint(); 30760786Sps return; 30860786Sps } 30960786Sps if (squished) 31060786Sps repaint(); 31160786Sps 31260786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 31360786Sps { 31460786Sps pos = position(slinenum); 31560786Sps if (pos == NULL_POSITION) 31660786Sps continue; 31760786Sps epos = position(slinenum+1); 31860786Sps if (pos < old_end_attnpos && 31960786Sps (epos == NULL_POSITION || epos > old_start_attnpos)) 32060786Sps { 32160786Sps (void) forw_line(pos); 32260786Sps goto_line(slinenum); 32360786Sps put_line(); 32460786Sps } 32560786Sps } 32660786Sps} 32760786Sps#endif 32860786Sps 32960786Sps/* 33060786Sps * Hide search string highlighting. 33160786Sps */ 33260786Sps public void 33360786Spsundo_search() 33460786Sps{ 33560786Sps if (!prev_pattern()) 33660786Sps { 33760786Sps error("No previous regular expression", NULL_PARG); 33860786Sps return; 33960786Sps } 34060786Sps#if HILITE_SEARCH 34160786Sps hide_hilite = !hide_hilite; 34260786Sps repaint_hilite(1); 34360786Sps#endif 34460786Sps} 34560786Sps 34660786Sps/* 34760786Sps * Compile a search pattern, for future use by match_pattern. 34860786Sps */ 34960786Sps static int 35060786Spscompile_pattern(pattern, search_type) 35160786Sps char *pattern; 35260786Sps int search_type; 35360786Sps{ 35460786Sps if ((search_type & SRCH_NO_REGEX) == 0) 35560786Sps { 35660786Sps#if HAVE_POSIX_REGCOMP 35760786Sps regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t)); 35860786Sps if (regcomp(s, pattern, REGCOMP_FLAG)) 35960786Sps { 36060786Sps free(s); 36160786Sps error("Invalid pattern", NULL_PARG); 36260786Sps return (-1); 36360786Sps } 36460786Sps if (regpattern != NULL) 36560786Sps regfree(regpattern); 36660786Sps regpattern = s; 36760786Sps#endif 36860786Sps#if HAVE_PCRE 36960786Sps pcre *comp; 37060786Sps const char *errstring; 37160786Sps int erroffset; 37260786Sps PARG parg; 37360786Sps comp = pcre_compile(pattern, 0, 37460786Sps &errstring, &erroffset, NULL); 37560786Sps if (comp == NULL) 37660786Sps { 37760786Sps parg.p_string = (char *) errstring; 37860786Sps error("%s", &parg); 37960786Sps return (-1); 38060786Sps } 38160786Sps regpattern = comp; 38260786Sps#endif 38360786Sps#if HAVE_RE_COMP 38460786Sps PARG parg; 38560786Sps if ((parg.p_string = re_comp(pattern)) != NULL) 38660786Sps { 38760786Sps error("%s", &parg); 38860786Sps return (-1); 38960786Sps } 39060786Sps re_pattern = 1; 39160786Sps#endif 39260786Sps#if HAVE_REGCMP 39360786Sps char *s; 39460786Sps if ((s = regcmp(pattern, 0)) == NULL) 39560786Sps { 39660786Sps error("Invalid pattern", NULL_PARG); 39760786Sps return (-1); 39860786Sps } 39960786Sps if (cpattern != NULL) 40060786Sps free(cpattern); 40160786Sps cpattern = s; 40260786Sps#endif 40360786Sps#if HAVE_V8_REGCOMP 40460786Sps struct regexp *s; 40560786Sps if ((s = regcomp(pattern)) == NULL) 40660786Sps { 40760786Sps /* 40860786Sps * regcomp has already printed an error message 40960786Sps * via regerror(). 41060786Sps */ 41160786Sps return (-1); 41260786Sps } 41360786Sps if (regpattern != NULL) 41460786Sps free(regpattern); 41560786Sps regpattern = s; 41660786Sps#endif 41760786Sps } 41860786Sps 41960786Sps if (last_pattern != NULL) 42060786Sps free(last_pattern); 42160786Sps last_pattern = (char *) calloc(1, strlen(pattern)+1); 42260786Sps if (last_pattern != NULL) 42360786Sps strcpy(last_pattern, pattern); 42460786Sps 42560786Sps last_search_type = search_type; 42660786Sps return (0); 42760786Sps} 42860786Sps 42960786Sps/* 43060786Sps * Forget that we have a compiled pattern. 43160786Sps */ 43260786Sps static void 43360786Spsuncompile_pattern() 43460786Sps{ 43560786Sps#if HAVE_POSIX_REGCOMP 43660786Sps if (regpattern != NULL) 43760786Sps regfree(regpattern); 43860786Sps regpattern = NULL; 43960786Sps#endif 44060786Sps#if HAVE_PCRE 44160786Sps if (regpattern != NULL) 44260786Sps pcre_free(regpattern); 44360786Sps regpattern = NULL; 44460786Sps#endif 44560786Sps#if HAVE_RE_COMP 44660786Sps re_pattern = 0; 44760786Sps#endif 44860786Sps#if HAVE_REGCMP 44960786Sps if (cpattern != NULL) 45060786Sps free(cpattern); 45160786Sps cpattern = NULL; 45260786Sps#endif 45360786Sps#if HAVE_V8_REGCOMP 45460786Sps if (regpattern != NULL) 45560786Sps free(regpattern); 45660786Sps regpattern = NULL; 45760786Sps#endif 45860786Sps last_pattern = NULL; 45960786Sps} 46060786Sps 46160786Sps/* 46260786Sps * Perform a pattern match with the previously compiled pattern. 46360786Sps * Set sp and ep to the start and end of the matched string. 46460786Sps */ 46560786Sps static int 466170259Sdelphijmatch_pattern(line, line_len, sp, ep, notbol) 46760786Sps char *line; 468170259Sdelphij int line_len; 46960786Sps char **sp; 47060786Sps char **ep; 47160786Sps int notbol; 47260786Sps{ 47360786Sps int matched; 47460786Sps 47560786Sps if (last_search_type & SRCH_NO_REGEX) 476170259Sdelphij return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep)); 47760786Sps 47860786Sps#if HAVE_POSIX_REGCOMP 47960786Sps { 48060786Sps regmatch_t rm; 48160786Sps int flags = (notbol) ? REG_NOTBOL : 0; 48260786Sps matched = !regexec(regpattern, line, 1, &rm, flags); 48360786Sps if (!matched) 48460786Sps return (0); 48560786Sps#ifndef __WATCOMC__ 48660786Sps *sp = line + rm.rm_so; 48760786Sps *ep = line + rm.rm_eo; 48860786Sps#else 48960786Sps *sp = rm.rm_sp; 49060786Sps *ep = rm.rm_ep; 49160786Sps#endif 49260786Sps } 49360786Sps#endif 49460786Sps#if HAVE_PCRE 49560786Sps { 49660786Sps int flags = (notbol) ? PCRE_NOTBOL : 0; 49760786Sps int ovector[3]; 498170259Sdelphij matched = pcre_exec(regpattern, NULL, line, line_len, 49960786Sps 0, flags, ovector, 3) >= 0; 50060786Sps if (!matched) 50160786Sps return (0); 50260786Sps *sp = line + ovector[0]; 50360786Sps *ep = line + ovector[1]; 50460786Sps } 50560786Sps#endif 50660786Sps#if HAVE_RE_COMP 50760786Sps matched = (re_exec(line) == 1); 50860786Sps /* 50960786Sps * re_exec doesn't seem to provide a way to get the matched string. 51060786Sps */ 51160786Sps *sp = *ep = NULL; 51260786Sps#endif 51360786Sps#if HAVE_REGCMP 51460786Sps *ep = regex(cpattern, line); 51560786Sps matched = (*ep != NULL); 51660786Sps if (!matched) 51760786Sps return (0); 51860786Sps *sp = __loc1; 51960786Sps#endif 52060786Sps#if HAVE_V8_REGCOMP 52160786Sps#if HAVE_REGEXEC2 52260786Sps matched = regexec2(regpattern, line, notbol); 52360786Sps#else 52460786Sps matched = regexec(regpattern, line); 52560786Sps#endif 52660786Sps if (!matched) 52760786Sps return (0); 52860786Sps *sp = regpattern->startp[0]; 52960786Sps *ep = regpattern->endp[0]; 53060786Sps#endif 53160786Sps#if NO_REGEX 532170259Sdelphij matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep); 53360786Sps#endif 53460786Sps return (matched); 53560786Sps} 53660786Sps 53760786Sps#if HILITE_SEARCH 53860786Sps/* 53960786Sps * Clear the hilite list. 54060786Sps */ 54160786Sps public void 54260786Spsclr_hilite() 54360786Sps{ 54460786Sps struct hilite *hl; 54560786Sps struct hilite *nexthl; 54660786Sps 54760786Sps for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl) 54860786Sps { 54960786Sps nexthl = hl->hl_next; 55060786Sps free((void*)hl); 55160786Sps } 55260786Sps hilite_anchor.hl_first = NULL; 55360786Sps prep_startpos = prep_endpos = NULL_POSITION; 55460786Sps} 55560786Sps 55660786Sps/* 55760786Sps * Should any characters in a specified range be highlighted? 558161478Sdelphij */ 559161478Sdelphij static int 560161478Sdelphijis_hilited_range(pos, epos) 561161478Sdelphij POSITION pos; 562161478Sdelphij POSITION epos; 563161478Sdelphij{ 564161478Sdelphij struct hilite *hl; 565161478Sdelphij 566161478Sdelphij /* 567161478Sdelphij * Look at each highlight and see if any part of it falls in the range. 568161478Sdelphij */ 569161478Sdelphij for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) 570161478Sdelphij { 571161478Sdelphij if (hl->hl_endpos > pos && 572161478Sdelphij (epos == NULL_POSITION || epos > hl->hl_startpos)) 573161478Sdelphij return (1); 574161478Sdelphij } 575161478Sdelphij return (0); 576161478Sdelphij} 577161478Sdelphij 578161478Sdelphij/* 579161478Sdelphij * Should any characters in a specified range be highlighted? 58060786Sps * If nohide is nonzero, don't consider hide_hilite. 58160786Sps */ 58260786Sps public int 583161478Sdelphijis_hilited(pos, epos, nohide, p_matches) 58460786Sps POSITION pos; 58560786Sps POSITION epos; 58660786Sps int nohide; 587161478Sdelphij int *p_matches; 58860786Sps{ 589161478Sdelphij int match; 59060786Sps 591161478Sdelphij if (p_matches != NULL) 592161478Sdelphij *p_matches = 0; 593161478Sdelphij 59463131Sps if (!status_col && 59563131Sps start_attnpos != NULL_POSITION && 59660786Sps pos < end_attnpos && 59760786Sps (epos == NULL_POSITION || epos > start_attnpos)) 59860786Sps /* 59960786Sps * The attn line overlaps this range. 60060786Sps */ 60160786Sps return (1); 60260786Sps 603161478Sdelphij match = is_hilited_range(pos, epos); 604161478Sdelphij if (!match) 605161478Sdelphij return (0); 606161478Sdelphij 607161478Sdelphij if (p_matches != NULL) 608161478Sdelphij /* 609161478Sdelphij * Report matches, even if we're hiding highlights. 610161478Sdelphij */ 611161478Sdelphij *p_matches = 1; 612161478Sdelphij 61360786Sps if (hilite_search == 0) 61460786Sps /* 61560786Sps * Not doing highlighting. 61660786Sps */ 61760786Sps return (0); 61860786Sps 61960786Sps if (!nohide && hide_hilite) 62060786Sps /* 62160786Sps * Highlighting is hidden. 62260786Sps */ 62360786Sps return (0); 62460786Sps 625161478Sdelphij return (1); 62660786Sps} 62760786Sps 62860786Sps/* 62960786Sps * Add a new hilite to a hilite list. 63060786Sps */ 63160786Sps static void 63260786Spsadd_hilite(anchor, hl) 63360786Sps struct hilite *anchor; 63460786Sps struct hilite *hl; 63560786Sps{ 63660786Sps struct hilite *ihl; 63760786Sps 63860786Sps /* 63960786Sps * Hilites are sorted in the list; find where new one belongs. 64060786Sps * Insert new one after ihl. 64160786Sps */ 64260786Sps for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next) 64360786Sps { 64460786Sps if (ihl->hl_next->hl_startpos > hl->hl_startpos) 64560786Sps break; 64660786Sps } 64760786Sps 64860786Sps /* 64960786Sps * Truncate hilite so it doesn't overlap any existing ones 65060786Sps * above and below it. 65160786Sps */ 65260786Sps if (ihl != anchor) 65360786Sps hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos); 65460786Sps if (ihl->hl_next != NULL) 65560786Sps hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos); 65660786Sps if (hl->hl_startpos >= hl->hl_endpos) 65760786Sps { 65860786Sps /* 65960786Sps * Hilite was truncated out of existence. 66060786Sps */ 66160786Sps free(hl); 66260786Sps return; 66360786Sps } 66460786Sps hl->hl_next = ihl->hl_next; 66560786Sps ihl->hl_next = hl; 66660786Sps} 66760786Sps 668161478Sdelphij static void 669170259Sdelphijadj_hilite_ansi(cvt_ops, line, line_len, npos) 670161478Sdelphij int cvt_ops; 671161478Sdelphij char **line; 672170259Sdelphij int line_len; 673161478Sdelphij POSITION *npos; 674161478Sdelphij{ 675170259Sdelphij char *line_end = *line + line_len; 676170259Sdelphij 677161478Sdelphij if (cvt_ops & CVT_ANSI) 678161478Sdelphij while (**line == ESC) 679161478Sdelphij { 680161478Sdelphij /* 681161478Sdelphij * Found an ESC. The file position moves 682161478Sdelphij * forward past the entire ANSI escape sequence. 683161478Sdelphij */ 684161478Sdelphij (*line)++; 685161478Sdelphij (*npos)++; 686170259Sdelphij while (*line < line_end) 687161478Sdelphij { 688161478Sdelphij (*npos)++; 689161478Sdelphij if (!is_ansi_middle(*(*line)++)) 690161478Sdelphij break; 691161478Sdelphij } 692161478Sdelphij } 693161478Sdelphij} 694161478Sdelphij 69560786Sps/* 69660786Sps * Adjust hl_startpos & hl_endpos to account for backspace processing. 69760786Sps */ 69860786Sps static void 699128348Stjradj_hilite(anchor, linepos, cvt_ops) 70060786Sps struct hilite *anchor; 70160786Sps POSITION linepos; 702128348Stjr int cvt_ops; 70360786Sps{ 70460786Sps char *line; 705170259Sdelphij int line_len; 706170259Sdelphij char *line_end; 70760786Sps struct hilite *hl; 70860786Sps int checkstart; 70960786Sps POSITION opos; 71060786Sps POSITION npos; 71160786Sps 71260786Sps /* 71360786Sps * The line was already scanned and hilites were added (in hilite_line). 71460786Sps * But it was assumed that each char position in the line 71560786Sps * correponds to one char position in the file. 71660786Sps * This may not be true if there are backspaces in the line. 71760786Sps * Get the raw line again. Look at each character. 71860786Sps */ 719170259Sdelphij (void) forw_raw_line(linepos, &line, &line_len); 720170259Sdelphij line_end = line + line_len; 72160786Sps opos = npos = linepos; 72260786Sps hl = anchor->hl_first; 72360786Sps checkstart = TRUE; 72460786Sps while (hl != NULL) 72560786Sps { 72660786Sps /* 72760786Sps * See if we need to adjust the current hl_startpos or 72860786Sps * hl_endpos. After adjusting startpos[i], move to endpos[i]. 72960786Sps * After adjusting endpos[i], move to startpos[i+1]. 73060786Sps * The hilite list must be sorted thus: 73160786Sps * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc. 73260786Sps */ 73360786Sps if (checkstart && hl->hl_startpos == opos) 73460786Sps { 73560786Sps hl->hl_startpos = npos; 73660786Sps checkstart = FALSE; 73760786Sps continue; /* {{ not really necessary }} */ 73860786Sps } else if (!checkstart && hl->hl_endpos == opos) 73960786Sps { 74060786Sps hl->hl_endpos = npos; 74160786Sps checkstart = TRUE; 74260786Sps hl = hl->hl_next; 74360786Sps continue; /* {{ necessary }} */ 74460786Sps } 745170259Sdelphij if (line == line_end) 74660786Sps break; 747170259Sdelphij adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos); 74860786Sps opos++; 74960786Sps npos++; 75060786Sps line++; 751128348Stjr if (cvt_ops & CVT_BS) 75260786Sps { 753161478Sdelphij while (*line == '\b') 754128348Stjr { 755161478Sdelphij npos++; 756161478Sdelphij line++; 757170259Sdelphij adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos); 758170259Sdelphij if (line == line_end) 759161478Sdelphij { 760161478Sdelphij --npos; 761161478Sdelphij --line; 762161478Sdelphij break; 763161478Sdelphij } 764128348Stjr /* 765128348Stjr * Found a backspace. The file position moves 766128348Stjr * forward by 2 relative to the processed line 767128348Stjr * which was searched in hilite_line. 768128348Stjr */ 769161478Sdelphij npos++; 770161478Sdelphij line++; 771128348Stjr } 77260786Sps } 77360786Sps } 77460786Sps} 77560786Sps 77660786Sps/* 77760786Sps * Make a hilite for each string in a physical line which matches 77860786Sps * the current pattern. 77960786Sps * sp,ep delimit the first match already found. 78060786Sps */ 78160786Sps static void 782170259Sdelphijhilite_line(linepos, line, line_len, sp, ep, cvt_ops) 78360786Sps POSITION linepos; 78460786Sps char *line; 785170259Sdelphij int line_len; 78660786Sps char *sp; 78760786Sps char *ep; 788128348Stjr int cvt_ops; 78960786Sps{ 79060786Sps char *searchp; 791170259Sdelphij char *line_end = line + line_len; 79260786Sps struct hilite *hl; 79360786Sps struct hilite hilites; 79460786Sps 79560786Sps if (sp == NULL || ep == NULL) 79660786Sps return; 79760786Sps /* 79860786Sps * sp and ep delimit the first match in the line. 79960786Sps * Mark the corresponding file positions, then 80060786Sps * look for further matches and mark them. 80160786Sps * {{ This technique, of calling match_pattern on subsequent 80260786Sps * substrings of the line, may mark more than is correct 80360786Sps * if the pattern starts with "^". This bug is fixed 80460786Sps * for those regex functions that accept a notbol parameter 805170259Sdelphij * (currently POSIX, PCRE and V8-with-regexec2). }} 80660786Sps */ 80760786Sps searchp = line; 80860786Sps /* 80960786Sps * Put the hilites into a temporary list until they're adjusted. 81060786Sps */ 81160786Sps hilites.hl_first = NULL; 81260786Sps do { 81360786Sps if (ep > sp) 81460786Sps { 81560786Sps /* 81660786Sps * Assume that each char position in the "line" 81760786Sps * buffer corresponds to one char position in the file. 81860786Sps * This is not quite true; we need to adjust later. 81960786Sps */ 82060786Sps hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); 82160786Sps hl->hl_startpos = linepos + (sp-line); 82260786Sps hl->hl_endpos = linepos + (ep-line); 82360786Sps add_hilite(&hilites, hl); 82460786Sps } 82560786Sps /* 82660786Sps * If we matched more than zero characters, 82760786Sps * move to the first char after the string we matched. 82860786Sps * If we matched zero, just move to the next char. 82960786Sps */ 83060786Sps if (ep > searchp) 83160786Sps searchp = ep; 832170259Sdelphij else if (searchp != line_end) 83360786Sps searchp++; 83460786Sps else /* end of line */ 83560786Sps break; 836170259Sdelphij } while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1)); 83760786Sps 83860786Sps /* 839128348Stjr * If there were backspaces in the original line, they 840128348Stjr * were removed, and hl_startpos/hl_endpos are not correct. 841128348Stjr * {{ This is very ugly. }} 842128348Stjr */ 843128348Stjr adj_hilite(&hilites, linepos, cvt_ops); 844128348Stjr 845128348Stjr /* 84660786Sps * Now put the hilites into the real list. 84760786Sps */ 84860786Sps while ((hl = hilites.hl_next) != NULL) 84960786Sps { 85060786Sps hilites.hl_next = hl->hl_next; 85160786Sps add_hilite(&hilite_anchor, hl); 85260786Sps } 85360786Sps} 85460786Sps#endif 85560786Sps 85660786Sps/* 85760786Sps * Change the caseless-ness of searches. 85860786Sps * Updates the internal search state to reflect a change in the -i flag. 85960786Sps */ 86060786Sps public void 86160786Spschg_caseless() 86260786Sps{ 86360786Sps if (!is_ucase_pattern) 86460786Sps /* 86560786Sps * Pattern did not have uppercase. 86660786Sps * Just set the search caselessness to the global caselessness. 86760786Sps */ 86860786Sps is_caseless = caseless; 86960786Sps else 87060786Sps /* 87160786Sps * Pattern did have uppercase. 87260786Sps * Discard the pattern; we can't change search caselessness now. 87360786Sps */ 87460786Sps uncompile_pattern(); 87560786Sps} 87660786Sps 87760786Sps#if HILITE_SEARCH 87860786Sps/* 87960786Sps * Find matching text which is currently on screen and highlight it. 88060786Sps */ 88160786Sps static void 88260786Spshilite_screen() 88360786Sps{ 88460786Sps struct scrpos scrpos; 88560786Sps 88660786Sps get_scrpos(&scrpos); 88760786Sps if (scrpos.pos == NULL_POSITION) 88860786Sps return; 88960786Sps prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); 89060786Sps repaint_hilite(1); 89160786Sps} 89260786Sps 89360786Sps/* 89460786Sps * Change highlighting parameters. 89560786Sps */ 89660786Sps public void 89760786Spschg_hilite() 89860786Sps{ 89960786Sps /* 90060786Sps * Erase any highlights currently on screen. 90160786Sps */ 90260786Sps clr_hilite(); 90360786Sps hide_hilite = 0; 90460786Sps 90560786Sps if (hilite_search == OPT_ONPLUS) 90660786Sps /* 90760786Sps * Display highlights. 90860786Sps */ 90960786Sps hilite_screen(); 91060786Sps} 91160786Sps#endif 91260786Sps 91360786Sps/* 91460786Sps * Figure out where to start a search. 91560786Sps */ 91660786Sps static POSITION 91760786Spssearch_pos(search_type) 91860786Sps int search_type; 91960786Sps{ 92060786Sps POSITION pos; 92160786Sps int linenum; 92260786Sps 92360786Sps if (empty_screen()) 92460786Sps { 92560786Sps /* 92660786Sps * Start at the beginning (or end) of the file. 92760786Sps * The empty_screen() case is mainly for 92860786Sps * command line initiated searches; 92960786Sps * for example, "+/xyz" on the command line. 93060786Sps * Also for multi-file (SRCH_PAST_EOF) searches. 93160786Sps */ 93260786Sps if (search_type & SRCH_FORW) 93360786Sps { 93460786Sps return (ch_zero()); 93560786Sps } else 93660786Sps { 93760786Sps pos = ch_length(); 93860786Sps if (pos == NULL_POSITION) 93960786Sps { 94060786Sps (void) ch_end_seek(); 94160786Sps pos = ch_length(); 94260786Sps } 94360786Sps return (pos); 94460786Sps } 94560786Sps } 94660786Sps if (how_search) 94760786Sps { 94860786Sps /* 94960786Sps * Search does not include current screen. 95060786Sps */ 95160786Sps if (search_type & SRCH_FORW) 95260786Sps linenum = BOTTOM_PLUS_ONE; 95360786Sps else 95460786Sps linenum = TOP; 95560786Sps pos = position(linenum); 95660786Sps } else 95760786Sps { 95860786Sps /* 95960786Sps * Search includes current screen. 96060786Sps * It starts at the jump target (if searching backwards), 96160786Sps * or at the jump target plus one (if forwards). 96260786Sps */ 96360786Sps linenum = adjsline(jump_sline); 96460786Sps pos = position(linenum); 96560786Sps if (search_type & SRCH_FORW) 96660786Sps { 967170259Sdelphij pos = forw_raw_line(pos, (char **)NULL, (int *)NULL); 96860786Sps while (pos == NULL_POSITION) 96960786Sps { 97060786Sps if (++linenum >= sc_height) 97160786Sps break; 97260786Sps pos = position(linenum); 97360786Sps } 97460786Sps } else 97560786Sps { 97660786Sps while (pos == NULL_POSITION) 97760786Sps { 97860786Sps if (--linenum < 0) 97960786Sps break; 98060786Sps pos = position(linenum); 98160786Sps } 98260786Sps } 98360786Sps } 98460786Sps return (pos); 98560786Sps} 98660786Sps 98760786Sps/* 98860786Sps * Search a subset of the file, specified by start/end position. 98960786Sps */ 99060786Sps static int 99160786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) 99260786Sps POSITION pos; 99360786Sps POSITION endpos; 99460786Sps int search_type; 99560786Sps int matches; 99660786Sps int maxlines; 99760786Sps POSITION *plinepos; 99860786Sps POSITION *pendpos; 99960786Sps{ 100060786Sps char *line; 1001170259Sdelphij int line_len; 1002128348Stjr LINENUM linenum; 100360786Sps char *sp, *ep; 100460786Sps int line_match; 1005128348Stjr int cvt_ops; 100660786Sps POSITION linepos, oldpos; 100760786Sps 100860786Sps linenum = find_linenum(pos); 100960786Sps oldpos = pos; 101060786Sps for (;;) 101160786Sps { 101260786Sps /* 101360786Sps * Get lines until we find a matching one or until 101460786Sps * we hit end-of-file (or beginning-of-file if we're 101560786Sps * going backwards), or until we hit the end position. 101660786Sps */ 101760786Sps if (ABORT_SIGS()) 101860786Sps { 101960786Sps /* 102060786Sps * A signal aborts the search. 102160786Sps */ 102260786Sps return (-1); 102360786Sps } 102460786Sps 102560786Sps if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) 102660786Sps { 102760786Sps /* 102860786Sps * Reached end position without a match. 102960786Sps */ 103060786Sps if (pendpos != NULL) 103160786Sps *pendpos = pos; 103260786Sps return (matches); 103360786Sps } 103460786Sps if (maxlines > 0) 103560786Sps maxlines--; 103660786Sps 103760786Sps if (search_type & SRCH_FORW) 103860786Sps { 103960786Sps /* 104060786Sps * Read the next line, and save the 104160786Sps * starting position of that line in linepos. 104260786Sps */ 104360786Sps linepos = pos; 1044170259Sdelphij pos = forw_raw_line(pos, &line, &line_len); 104560786Sps if (linenum != 0) 104660786Sps linenum++; 104760786Sps } else 104860786Sps { 104960786Sps /* 105060786Sps * Read the previous line and save the 105160786Sps * starting position of that line in linepos. 105260786Sps */ 1053170259Sdelphij pos = back_raw_line(pos, &line, &line_len); 105460786Sps linepos = pos; 105560786Sps if (linenum != 0) 105660786Sps linenum--; 105760786Sps } 105860786Sps 105960786Sps if (pos == NULL_POSITION) 106060786Sps { 106160786Sps /* 106260786Sps * Reached EOF/BOF without a match. 106360786Sps */ 106460786Sps if (pendpos != NULL) 106560786Sps *pendpos = oldpos; 106660786Sps return (matches); 106760786Sps } 106860786Sps 106960786Sps /* 107060786Sps * If we're using line numbers, we might as well 107160786Sps * remember the information we have now (the position 107260786Sps * and line number of the current line). 107360786Sps * Don't do it for every line because it slows down 107460786Sps * the search. Remember the line number only if 107560786Sps * we're "far" from the last place we remembered it. 107660786Sps */ 107760786Sps if (linenums && abs((int)(pos - oldpos)) > 1024) 107860786Sps add_lnum(linenum, pos); 107960786Sps oldpos = pos; 108060786Sps 108160786Sps /* 108260786Sps * If it's a caseless search, convert the line to lowercase. 108360786Sps * If we're doing backspace processing, delete backspaces. 108460786Sps */ 1085128348Stjr cvt_ops = get_cvt_ops(); 1086170259Sdelphij cvt_text(line, line, &line_len, cvt_ops); 108760786Sps 108860786Sps /* 108960786Sps * Test the next line to see if we have a match. 109060786Sps * We are successful if we either want a match and got one, 109160786Sps * or if we want a non-match and got one. 109260786Sps */ 1093170259Sdelphij line_match = match_pattern(line, line_len, &sp, &ep, 0); 109460786Sps line_match = (!(search_type & SRCH_NO_MATCH) && line_match) || 109560786Sps ((search_type & SRCH_NO_MATCH) && !line_match); 109660786Sps if (!line_match) 109760786Sps continue; 109860786Sps /* 109960786Sps * Got a match. 110060786Sps */ 110160786Sps if (search_type & SRCH_FIND_ALL) 110260786Sps { 110360786Sps#if HILITE_SEARCH 110460786Sps /* 110560786Sps * We are supposed to find all matches in the range. 110660786Sps * Just add the matches in this line to the 110760786Sps * hilite list and keep searching. 110860786Sps */ 110960786Sps if (line_match) 1110170259Sdelphij hilite_line(linepos, line, line_len, sp, ep, cvt_ops); 111160786Sps#endif 111260786Sps } else if (--matches <= 0) 111360786Sps { 111460786Sps /* 111560786Sps * Found the one match we're looking for. 111660786Sps * Return it. 111760786Sps */ 111860786Sps#if HILITE_SEARCH 1119161478Sdelphij if (hilite_search == OPT_ON) 112060786Sps { 112160786Sps /* 112260786Sps * Clear the hilite list and add only 112360786Sps * the matches in this one line. 112460786Sps */ 112560786Sps clr_hilite(); 112660786Sps if (line_match) 1127170259Sdelphij hilite_line(linepos, line, line_len, sp, ep, cvt_ops); 112860786Sps } 112960786Sps#endif 113060786Sps if (plinepos != NULL) 113160786Sps *plinepos = linepos; 113260786Sps return (0); 113360786Sps } 113460786Sps } 113560786Sps} 113660786Sps 1137170259Sdelphij /* 1138170259Sdelphij * search for a pattern in history. If found, compile that pattern. 1139170259Sdelphij */ 1140170259Sdelphij static int 1141170259Sdelphijhist_pattern(search_type) 1142170259Sdelphij int search_type; 1143170259Sdelphij{ 1144170259Sdelphij#if CMD_HISTORY 1145170259Sdelphij char *pattern; 1146170259Sdelphij 1147170259Sdelphij set_mlist(ml_search, 0); 1148170259Sdelphij pattern = cmd_lastpattern(); 1149170259Sdelphij if (pattern == NULL) 1150170259Sdelphij return (0); 1151170259Sdelphij 1152170259Sdelphij if (caseless == OPT_ONPLUS) 1153170259Sdelphij cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC); 1154170259Sdelphij 1155170259Sdelphij if (compile_pattern(pattern, search_type) < 0) 1156170259Sdelphij return (0); 1157170259Sdelphij 1158170259Sdelphij is_ucase_pattern = is_ucase(pattern); 1159170259Sdelphij if (is_ucase_pattern && caseless != OPT_ONPLUS) 1160170259Sdelphij is_caseless = 0; 1161170259Sdelphij else 1162170259Sdelphij is_caseless = caseless; 1163170259Sdelphij 1164170259Sdelphij#if HILITE_SEARCH 1165170259Sdelphij if (hilite_search == OPT_ONPLUS && !hide_hilite) 1166170259Sdelphij hilite_screen(); 1167170259Sdelphij#endif 1168170259Sdelphij 1169170259Sdelphij return (1); 1170170259Sdelphij#else /* CMD_HISTORY */ 1171170259Sdelphij return (0); 1172170259Sdelphij#endif /* CMD_HISTORY */ 1173170259Sdelphij} 1174170259Sdelphij 117560786Sps/* 117660786Sps * Search for the n-th occurrence of a specified pattern, 117760786Sps * either forward or backward. 117860786Sps * Return the number of matches not yet found in this file 117960786Sps * (that is, n minus the number of matches found). 118060786Sps * Return -1 if the search should be aborted. 118160786Sps * Caller may continue the search in another file 118260786Sps * if less than n matches are found in this file. 118360786Sps */ 118460786Sps public int 118560786Spssearch(search_type, pattern, n) 118660786Sps int search_type; 118760786Sps char *pattern; 118860786Sps int n; 118960786Sps{ 119060786Sps POSITION pos; 119160786Sps int ucase; 119260786Sps 119360786Sps if (pattern == NULL || *pattern == '\0') 119460786Sps { 119560786Sps /* 119660786Sps * A null pattern means use the previously compiled pattern. 119760786Sps */ 1198170259Sdelphij if (!prev_pattern() && !hist_pattern(search_type)) 119960786Sps { 120060786Sps error("No previous regular expression", NULL_PARG); 120160786Sps return (-1); 120260786Sps } 120360786Sps if ((search_type & SRCH_NO_REGEX) != 120460786Sps (last_search_type & SRCH_NO_REGEX)) 120560786Sps { 120660786Sps error("Please re-enter search pattern", NULL_PARG); 120760786Sps return -1; 120860786Sps } 120960786Sps#if HILITE_SEARCH 121060786Sps if (hilite_search == OPT_ON) 121160786Sps { 121260786Sps /* 121360786Sps * Erase the highlights currently on screen. 121460786Sps * If the search fails, we'll redisplay them later. 121560786Sps */ 121660786Sps repaint_hilite(0); 121760786Sps } 121860786Sps if (hilite_search == OPT_ONPLUS && hide_hilite) 121960786Sps { 122060786Sps /* 122160786Sps * Highlight any matches currently on screen, 122260786Sps * before we actually start the search. 122360786Sps */ 122460786Sps hide_hilite = 0; 122560786Sps hilite_screen(); 122660786Sps } 122760786Sps hide_hilite = 0; 122860786Sps#endif 122960786Sps } else 123060786Sps { 123160786Sps /* 123260786Sps * Compile the pattern. 123360786Sps */ 123460786Sps ucase = is_ucase(pattern); 123560786Sps if (caseless == OPT_ONPLUS) 1236170259Sdelphij cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC); 123760786Sps if (compile_pattern(pattern, search_type) < 0) 123860786Sps return (-1); 123960786Sps /* 124060786Sps * Ignore case if -I is set OR 124160786Sps * -i is set AND the pattern is all lowercase. 124260786Sps */ 124360786Sps is_ucase_pattern = ucase; 124460786Sps if (is_ucase_pattern && caseless != OPT_ONPLUS) 124560786Sps is_caseless = 0; 124660786Sps else 124760786Sps is_caseless = caseless; 124860786Sps#if HILITE_SEARCH 124960786Sps if (hilite_search) 125060786Sps { 125160786Sps /* 125260786Sps * Erase the highlights currently on screen. 125360786Sps * Also permanently delete them from the hilite list. 125460786Sps */ 125560786Sps repaint_hilite(0); 125660786Sps hide_hilite = 0; 125760786Sps clr_hilite(); 125860786Sps } 125960786Sps if (hilite_search == OPT_ONPLUS) 126060786Sps { 126160786Sps /* 126260786Sps * Highlight any matches currently on screen, 126360786Sps * before we actually start the search. 126460786Sps */ 126560786Sps hilite_screen(); 126660786Sps } 126760786Sps#endif 126860786Sps } 126960786Sps 127060786Sps /* 127160786Sps * Figure out where to start the search. 127260786Sps */ 127360786Sps pos = search_pos(search_type); 127460786Sps if (pos == NULL_POSITION) 127560786Sps { 127660786Sps /* 127760786Sps * Can't find anyplace to start searching from. 127860786Sps */ 127960786Sps if (search_type & SRCH_PAST_EOF) 128060786Sps return (n); 128160786Sps /* repaint(); -- why was this here? */ 128260786Sps error("Nothing to search", NULL_PARG); 128360786Sps return (-1); 128460786Sps } 128560786Sps 128660786Sps n = search_range(pos, NULL_POSITION, search_type, n, -1, 128760786Sps &pos, (POSITION*)NULL); 128860786Sps if (n != 0) 128960786Sps { 129060786Sps /* 129160786Sps * Search was unsuccessful. 129260786Sps */ 129360786Sps#if HILITE_SEARCH 129460786Sps if (hilite_search == OPT_ON && n > 0) 129560786Sps /* 129660786Sps * Redisplay old hilites. 129760786Sps */ 129860786Sps repaint_hilite(1); 129960786Sps#endif 130060786Sps return (n); 130160786Sps } 130260786Sps 130360786Sps if (!(search_type & SRCH_NO_MOVE)) 130460786Sps { 130560786Sps /* 130660786Sps * Go to the matching line. 130760786Sps */ 130860786Sps jump_loc(pos, jump_sline); 130960786Sps } 131060786Sps 131160786Sps#if HILITE_SEARCH 131260786Sps if (hilite_search == OPT_ON) 131360786Sps /* 131460786Sps * Display new hilites in the matching line. 131560786Sps */ 131660786Sps repaint_hilite(1); 131760786Sps#endif 131860786Sps return (0); 131960786Sps} 132060786Sps 132160786Sps 132260786Sps#if HILITE_SEARCH 132360786Sps/* 132460786Sps * Prepare hilites in a given range of the file. 132560786Sps * 132660786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region 132760786Sps * of the file that has been "prepared"; that is, scanned for matches for 132860786Sps * the current search pattern, and hilites have been created for such matches. 132960786Sps * If prep_startpos == NULL_POSITION, the prep region is empty. 133060786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF. 133160786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region. 133260786Sps */ 133360786Sps public void 133460786Spsprep_hilite(spos, epos, maxlines) 133560786Sps POSITION spos; 133660786Sps POSITION epos; 133760786Sps int maxlines; 133860786Sps{ 133960786Sps POSITION nprep_startpos = prep_startpos; 134060786Sps POSITION nprep_endpos = prep_endpos; 134160786Sps POSITION new_epos; 134260786Sps POSITION max_epos; 134360786Sps int result; 134460786Sps int i; 134560786Sps/* 134660786Sps * Search beyond where we're asked to search, so the prep region covers 134760786Sps * more than we need. Do one big search instead of a bunch of small ones. 134860786Sps */ 134960786Sps#define SEARCH_MORE (3*size_linebuf) 135060786Sps 135160786Sps if (!prev_pattern()) 135260786Sps return; 135360786Sps 135460786Sps /* 135560786Sps * If we're limited to a max number of lines, figure out the 135660786Sps * file position we should stop at. 135760786Sps */ 135860786Sps if (maxlines < 0) 135960786Sps max_epos = NULL_POSITION; 136060786Sps else 136160786Sps { 136260786Sps max_epos = spos; 136360786Sps for (i = 0; i < maxlines; i++) 1364170259Sdelphij max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); 136560786Sps } 136660786Sps 136760786Sps /* 136860786Sps * Find two ranges: 136960786Sps * The range that we need to search (spos,epos); and the range that 137060786Sps * the "prep" region will then cover (nprep_startpos,nprep_endpos). 137160786Sps */ 137260786Sps 137360786Sps if (prep_startpos == NULL_POSITION || 137460786Sps (epos != NULL_POSITION && epos < prep_startpos) || 137560786Sps spos > prep_endpos) 137660786Sps { 137760786Sps /* 137860786Sps * New range is not contiguous with old prep region. 137960786Sps * Discard the old prep region and start a new one. 138060786Sps */ 138160786Sps clr_hilite(); 138260786Sps if (epos != NULL_POSITION) 138360786Sps epos += SEARCH_MORE; 138460786Sps nprep_startpos = spos; 138560786Sps } else 138660786Sps { 138760786Sps /* 138860786Sps * New range partially or completely overlaps old prep region. 138960786Sps */ 139060786Sps if (epos == NULL_POSITION) 139160786Sps { 139260786Sps /* 139360786Sps * New range goes to end of file. 139460786Sps */ 139560786Sps ; 139660786Sps } else if (epos > prep_endpos) 139760786Sps { 139860786Sps /* 139960786Sps * New range ends after old prep region. 140060786Sps * Extend prep region to end at end of new range. 140160786Sps */ 140260786Sps epos += SEARCH_MORE; 140360786Sps } else /* (epos <= prep_endpos) */ 140460786Sps { 140560786Sps /* 140660786Sps * New range ends within old prep region. 140760786Sps * Truncate search to end at start of old prep region. 140860786Sps */ 140960786Sps epos = prep_startpos; 141060786Sps } 141160786Sps 141260786Sps if (spos < prep_startpos) 141360786Sps { 141460786Sps /* 141560786Sps * New range starts before old prep region. 141660786Sps * Extend old prep region backwards to start at 141760786Sps * start of new range. 141860786Sps */ 141960786Sps if (spos < SEARCH_MORE) 142060786Sps spos = 0; 142160786Sps else 142260786Sps spos -= SEARCH_MORE; 142360786Sps nprep_startpos = spos; 142460786Sps } else /* (spos >= prep_startpos) */ 142560786Sps { 142660786Sps /* 142760786Sps * New range starts within or after old prep region. 142860786Sps * Trim search to start at end of old prep region. 142960786Sps */ 143060786Sps spos = prep_endpos; 143160786Sps } 143260786Sps } 143360786Sps 143460786Sps if (epos != NULL_POSITION && max_epos != NULL_POSITION && 143560786Sps epos > max_epos) 143660786Sps /* 143760786Sps * Don't go past the max position we're allowed. 143860786Sps */ 143960786Sps epos = max_epos; 144060786Sps 144160786Sps if (epos == NULL_POSITION || epos > spos) 144260786Sps { 144360786Sps result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, 144460786Sps maxlines, (POSITION*)NULL, &new_epos); 144560786Sps if (result < 0) 144660786Sps return; 144760786Sps if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 144860786Sps nprep_endpos = new_epos; 144960786Sps } 145060786Sps prep_startpos = nprep_startpos; 145160786Sps prep_endpos = nprep_endpos; 145260786Sps} 145360786Sps#endif 145460786Sps 145560786Sps/* 145660786Sps * Simple pattern matching function. 145760786Sps * It supports no metacharacters like *, etc. 145860786Sps */ 145960786Sps static int 1460170259Sdelphijmatch(pattern, pattern_len, buf, buf_len, pfound, pend) 1461170259Sdelphij char *pattern; 1462170259Sdelphij int pattern_len; 1463170259Sdelphij char *buf; 1464170259Sdelphij int buf_len; 146560786Sps char **pfound, **pend; 146660786Sps{ 146760786Sps register char *pp, *lp; 1468170259Sdelphij register char *pattern_end = pattern + pattern_len; 1469170259Sdelphij register char *buf_end = buf + buf_len; 147060786Sps 1471170259Sdelphij for ( ; buf < buf_end; buf++) 147260786Sps { 147360786Sps for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) 1474170259Sdelphij if (pp == pattern_end || lp == buf_end) 147560786Sps break; 1476170259Sdelphij if (pp == pattern_end) 147760786Sps { 147860786Sps if (pfound != NULL) 147960786Sps *pfound = buf; 148060786Sps if (pend != NULL) 148160786Sps *pend = lp; 148260786Sps return (1); 148360786Sps } 148460786Sps } 148560786Sps return (0); 148660786Sps} 148760786Sps 148860786Sps#if HAVE_V8_REGCOMP 148960786Sps/* 149060786Sps * This function is called by the V8 regcomp to report 149160786Sps * errors in regular expressions. 149260786Sps */ 149360786Sps void 149460786Spsregerror(s) 149560786Sps char *s; 149660786Sps{ 149760786Sps PARG parg; 149860786Sps 149960786Sps parg.p_string = s; 150060786Sps error("%s", &parg); 150160786Sps} 150260786Sps#endif 150360786Sps 1504