search.c revision 170898
160812Sps/* $FreeBSD: head/contrib/less/search.c 170898 2007-06-17 23:20:43Z 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; 297170898Sdelphij int moved = 0; 29860786Sps 29960786Sps if (start_attnpos == NULL_POSITION) 30060786Sps return; 30160786Sps old_start_attnpos = start_attnpos; 30260786Sps old_end_attnpos = end_attnpos; 30360786Sps start_attnpos = end_attnpos = NULL_POSITION; 30460786Sps 30560786Sps if (!can_goto_line) 30660786Sps { 30760786Sps repaint(); 30860786Sps return; 30960786Sps } 31060786Sps if (squished) 31160786Sps repaint(); 31260786Sps 31360786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 31460786Sps { 31560786Sps pos = position(slinenum); 31660786Sps if (pos == NULL_POSITION) 31760786Sps continue; 31860786Sps epos = position(slinenum+1); 31960786Sps if (pos < old_end_attnpos && 32060786Sps (epos == NULL_POSITION || epos > old_start_attnpos)) 32160786Sps { 32260786Sps (void) forw_line(pos); 32360786Sps goto_line(slinenum); 32460786Sps put_line(); 325170898Sdelphij moved = 1; 32660786Sps } 32760786Sps } 328170898Sdelphij if (moved) 329170898Sdelphij lower_left(); 33060786Sps} 33160786Sps#endif 33260786Sps 33360786Sps/* 33460786Sps * Hide search string highlighting. 33560786Sps */ 33660786Sps public void 33760786Spsundo_search() 33860786Sps{ 33960786Sps if (!prev_pattern()) 34060786Sps { 34160786Sps error("No previous regular expression", NULL_PARG); 34260786Sps return; 34360786Sps } 34460786Sps#if HILITE_SEARCH 34560786Sps hide_hilite = !hide_hilite; 34660786Sps repaint_hilite(1); 34760786Sps#endif 34860786Sps} 34960786Sps 35060786Sps/* 35160786Sps * Compile a search pattern, for future use by match_pattern. 35260786Sps */ 35360786Sps static int 35460786Spscompile_pattern(pattern, search_type) 35560786Sps char *pattern; 35660786Sps int search_type; 35760786Sps{ 35860786Sps if ((search_type & SRCH_NO_REGEX) == 0) 35960786Sps { 36060786Sps#if HAVE_POSIX_REGCOMP 36160786Sps regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t)); 36260786Sps if (regcomp(s, pattern, REGCOMP_FLAG)) 36360786Sps { 36460786Sps free(s); 36560786Sps error("Invalid pattern", NULL_PARG); 36660786Sps return (-1); 36760786Sps } 36860786Sps if (regpattern != NULL) 36960786Sps regfree(regpattern); 37060786Sps regpattern = s; 37160786Sps#endif 37260786Sps#if HAVE_PCRE 37360786Sps pcre *comp; 37460786Sps const char *errstring; 37560786Sps int erroffset; 37660786Sps PARG parg; 37760786Sps comp = pcre_compile(pattern, 0, 37860786Sps &errstring, &erroffset, NULL); 37960786Sps if (comp == NULL) 38060786Sps { 38160786Sps parg.p_string = (char *) errstring; 38260786Sps error("%s", &parg); 38360786Sps return (-1); 38460786Sps } 38560786Sps regpattern = comp; 38660786Sps#endif 38760786Sps#if HAVE_RE_COMP 38860786Sps PARG parg; 38960786Sps if ((parg.p_string = re_comp(pattern)) != NULL) 39060786Sps { 39160786Sps error("%s", &parg); 39260786Sps return (-1); 39360786Sps } 39460786Sps re_pattern = 1; 39560786Sps#endif 39660786Sps#if HAVE_REGCMP 39760786Sps char *s; 39860786Sps if ((s = regcmp(pattern, 0)) == NULL) 39960786Sps { 40060786Sps error("Invalid pattern", NULL_PARG); 40160786Sps return (-1); 40260786Sps } 40360786Sps if (cpattern != NULL) 40460786Sps free(cpattern); 40560786Sps cpattern = s; 40660786Sps#endif 40760786Sps#if HAVE_V8_REGCOMP 40860786Sps struct regexp *s; 40960786Sps if ((s = regcomp(pattern)) == NULL) 41060786Sps { 41160786Sps /* 41260786Sps * regcomp has already printed an error message 41360786Sps * via regerror(). 41460786Sps */ 41560786Sps return (-1); 41660786Sps } 41760786Sps if (regpattern != NULL) 41860786Sps free(regpattern); 41960786Sps regpattern = s; 42060786Sps#endif 42160786Sps } 42260786Sps 42360786Sps if (last_pattern != NULL) 42460786Sps free(last_pattern); 42560786Sps last_pattern = (char *) calloc(1, strlen(pattern)+1); 42660786Sps if (last_pattern != NULL) 42760786Sps strcpy(last_pattern, pattern); 42860786Sps 42960786Sps last_search_type = search_type; 43060786Sps return (0); 43160786Sps} 43260786Sps 43360786Sps/* 43460786Sps * Forget that we have a compiled pattern. 43560786Sps */ 43660786Sps static void 43760786Spsuncompile_pattern() 43860786Sps{ 43960786Sps#if HAVE_POSIX_REGCOMP 44060786Sps if (regpattern != NULL) 44160786Sps regfree(regpattern); 44260786Sps regpattern = NULL; 44360786Sps#endif 44460786Sps#if HAVE_PCRE 44560786Sps if (regpattern != NULL) 44660786Sps pcre_free(regpattern); 44760786Sps regpattern = NULL; 44860786Sps#endif 44960786Sps#if HAVE_RE_COMP 45060786Sps re_pattern = 0; 45160786Sps#endif 45260786Sps#if HAVE_REGCMP 45360786Sps if (cpattern != NULL) 45460786Sps free(cpattern); 45560786Sps cpattern = NULL; 45660786Sps#endif 45760786Sps#if HAVE_V8_REGCOMP 45860786Sps if (regpattern != NULL) 45960786Sps free(regpattern); 46060786Sps regpattern = NULL; 46160786Sps#endif 46260786Sps last_pattern = NULL; 46360786Sps} 46460786Sps 46560786Sps/* 46660786Sps * Perform a pattern match with the previously compiled pattern. 46760786Sps * Set sp and ep to the start and end of the matched string. 46860786Sps */ 46960786Sps static int 470170259Sdelphijmatch_pattern(line, line_len, sp, ep, notbol) 47160786Sps char *line; 472170259Sdelphij int line_len; 47360786Sps char **sp; 47460786Sps char **ep; 47560786Sps int notbol; 47660786Sps{ 47760786Sps int matched; 47860786Sps 47960786Sps if (last_search_type & SRCH_NO_REGEX) 480170259Sdelphij return (match(last_pattern, strlen(last_pattern), line, line_len, sp, ep)); 48160786Sps 48260786Sps#if HAVE_POSIX_REGCOMP 48360786Sps { 48460786Sps regmatch_t rm; 48560786Sps int flags = (notbol) ? REG_NOTBOL : 0; 48660786Sps matched = !regexec(regpattern, line, 1, &rm, flags); 48760786Sps if (!matched) 48860786Sps return (0); 48960786Sps#ifndef __WATCOMC__ 49060786Sps *sp = line + rm.rm_so; 49160786Sps *ep = line + rm.rm_eo; 49260786Sps#else 49360786Sps *sp = rm.rm_sp; 49460786Sps *ep = rm.rm_ep; 49560786Sps#endif 49660786Sps } 49760786Sps#endif 49860786Sps#if HAVE_PCRE 49960786Sps { 50060786Sps int flags = (notbol) ? PCRE_NOTBOL : 0; 50160786Sps int ovector[3]; 502170259Sdelphij matched = pcre_exec(regpattern, NULL, line, line_len, 50360786Sps 0, flags, ovector, 3) >= 0; 50460786Sps if (!matched) 50560786Sps return (0); 50660786Sps *sp = line + ovector[0]; 50760786Sps *ep = line + ovector[1]; 50860786Sps } 50960786Sps#endif 51060786Sps#if HAVE_RE_COMP 51160786Sps matched = (re_exec(line) == 1); 51260786Sps /* 51360786Sps * re_exec doesn't seem to provide a way to get the matched string. 51460786Sps */ 51560786Sps *sp = *ep = NULL; 51660786Sps#endif 51760786Sps#if HAVE_REGCMP 51860786Sps *ep = regex(cpattern, line); 51960786Sps matched = (*ep != NULL); 52060786Sps if (!matched) 52160786Sps return (0); 52260786Sps *sp = __loc1; 52360786Sps#endif 52460786Sps#if HAVE_V8_REGCOMP 52560786Sps#if HAVE_REGEXEC2 52660786Sps matched = regexec2(regpattern, line, notbol); 52760786Sps#else 52860786Sps matched = regexec(regpattern, line); 52960786Sps#endif 53060786Sps if (!matched) 53160786Sps return (0); 53260786Sps *sp = regpattern->startp[0]; 53360786Sps *ep = regpattern->endp[0]; 53460786Sps#endif 53560786Sps#if NO_REGEX 536170259Sdelphij matched = match(last_pattern, strlen(last_pattern), line, line_len, sp, ep); 53760786Sps#endif 53860786Sps return (matched); 53960786Sps} 54060786Sps 54160786Sps#if HILITE_SEARCH 54260786Sps/* 54360786Sps * Clear the hilite list. 54460786Sps */ 54560786Sps public void 54660786Spsclr_hilite() 54760786Sps{ 54860786Sps struct hilite *hl; 54960786Sps struct hilite *nexthl; 55060786Sps 55160786Sps for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl) 55260786Sps { 55360786Sps nexthl = hl->hl_next; 55460786Sps free((void*)hl); 55560786Sps } 55660786Sps hilite_anchor.hl_first = NULL; 55760786Sps prep_startpos = prep_endpos = NULL_POSITION; 55860786Sps} 55960786Sps 56060786Sps/* 56160786Sps * Should any characters in a specified range be highlighted? 562161478Sdelphij */ 563161478Sdelphij static int 564161478Sdelphijis_hilited_range(pos, epos) 565161478Sdelphij POSITION pos; 566161478Sdelphij POSITION epos; 567161478Sdelphij{ 568161478Sdelphij struct hilite *hl; 569161478Sdelphij 570161478Sdelphij /* 571161478Sdelphij * Look at each highlight and see if any part of it falls in the range. 572161478Sdelphij */ 573161478Sdelphij for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) 574161478Sdelphij { 575161478Sdelphij if (hl->hl_endpos > pos && 576161478Sdelphij (epos == NULL_POSITION || epos > hl->hl_startpos)) 577161478Sdelphij return (1); 578161478Sdelphij } 579161478Sdelphij return (0); 580161478Sdelphij} 581161478Sdelphij 582161478Sdelphij/* 583161478Sdelphij * Should any characters in a specified range be highlighted? 58460786Sps * If nohide is nonzero, don't consider hide_hilite. 58560786Sps */ 58660786Sps public int 587161478Sdelphijis_hilited(pos, epos, nohide, p_matches) 58860786Sps POSITION pos; 58960786Sps POSITION epos; 59060786Sps int nohide; 591161478Sdelphij int *p_matches; 59260786Sps{ 593161478Sdelphij int match; 59460786Sps 595161478Sdelphij if (p_matches != NULL) 596161478Sdelphij *p_matches = 0; 597161478Sdelphij 59863131Sps if (!status_col && 59963131Sps start_attnpos != NULL_POSITION && 60060786Sps pos < end_attnpos && 60160786Sps (epos == NULL_POSITION || epos > start_attnpos)) 60260786Sps /* 60360786Sps * The attn line overlaps this range. 60460786Sps */ 60560786Sps return (1); 60660786Sps 607161478Sdelphij match = is_hilited_range(pos, epos); 608161478Sdelphij if (!match) 609161478Sdelphij return (0); 610161478Sdelphij 611161478Sdelphij if (p_matches != NULL) 612161478Sdelphij /* 613161478Sdelphij * Report matches, even if we're hiding highlights. 614161478Sdelphij */ 615161478Sdelphij *p_matches = 1; 616161478Sdelphij 61760786Sps if (hilite_search == 0) 61860786Sps /* 61960786Sps * Not doing highlighting. 62060786Sps */ 62160786Sps return (0); 62260786Sps 62360786Sps if (!nohide && hide_hilite) 62460786Sps /* 62560786Sps * Highlighting is hidden. 62660786Sps */ 62760786Sps return (0); 62860786Sps 629161478Sdelphij return (1); 63060786Sps} 63160786Sps 63260786Sps/* 63360786Sps * Add a new hilite to a hilite list. 63460786Sps */ 63560786Sps static void 63660786Spsadd_hilite(anchor, hl) 63760786Sps struct hilite *anchor; 63860786Sps struct hilite *hl; 63960786Sps{ 64060786Sps struct hilite *ihl; 64160786Sps 64260786Sps /* 64360786Sps * Hilites are sorted in the list; find where new one belongs. 64460786Sps * Insert new one after ihl. 64560786Sps */ 64660786Sps for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next) 64760786Sps { 64860786Sps if (ihl->hl_next->hl_startpos > hl->hl_startpos) 64960786Sps break; 65060786Sps } 65160786Sps 65260786Sps /* 65360786Sps * Truncate hilite so it doesn't overlap any existing ones 65460786Sps * above and below it. 65560786Sps */ 65660786Sps if (ihl != anchor) 65760786Sps hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos); 65860786Sps if (ihl->hl_next != NULL) 65960786Sps hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos); 66060786Sps if (hl->hl_startpos >= hl->hl_endpos) 66160786Sps { 66260786Sps /* 66360786Sps * Hilite was truncated out of existence. 66460786Sps */ 66560786Sps free(hl); 66660786Sps return; 66760786Sps } 66860786Sps hl->hl_next = ihl->hl_next; 66960786Sps ihl->hl_next = hl; 67060786Sps} 67160786Sps 672161478Sdelphij static void 673170259Sdelphijadj_hilite_ansi(cvt_ops, line, line_len, npos) 674161478Sdelphij int cvt_ops; 675161478Sdelphij char **line; 676170259Sdelphij int line_len; 677161478Sdelphij POSITION *npos; 678161478Sdelphij{ 679170259Sdelphij char *line_end = *line + line_len; 680170259Sdelphij 681161478Sdelphij if (cvt_ops & CVT_ANSI) 682161478Sdelphij while (**line == ESC) 683161478Sdelphij { 684161478Sdelphij /* 685161478Sdelphij * Found an ESC. The file position moves 686161478Sdelphij * forward past the entire ANSI escape sequence. 687161478Sdelphij */ 688161478Sdelphij (*line)++; 689161478Sdelphij (*npos)++; 690170259Sdelphij while (*line < line_end) 691161478Sdelphij { 692161478Sdelphij (*npos)++; 693161478Sdelphij if (!is_ansi_middle(*(*line)++)) 694161478Sdelphij break; 695161478Sdelphij } 696161478Sdelphij } 697161478Sdelphij} 698161478Sdelphij 69960786Sps/* 70060786Sps * Adjust hl_startpos & hl_endpos to account for backspace processing. 70160786Sps */ 70260786Sps static void 703128348Stjradj_hilite(anchor, linepos, cvt_ops) 70460786Sps struct hilite *anchor; 70560786Sps POSITION linepos; 706128348Stjr int cvt_ops; 70760786Sps{ 70860786Sps char *line; 709170259Sdelphij int line_len; 710170259Sdelphij char *line_end; 71160786Sps struct hilite *hl; 71260786Sps int checkstart; 71360786Sps POSITION opos; 71460786Sps POSITION npos; 71560786Sps 71660786Sps /* 71760786Sps * The line was already scanned and hilites were added (in hilite_line). 71860786Sps * But it was assumed that each char position in the line 71960786Sps * correponds to one char position in the file. 72060786Sps * This may not be true if there are backspaces in the line. 72160786Sps * Get the raw line again. Look at each character. 72260786Sps */ 723170259Sdelphij (void) forw_raw_line(linepos, &line, &line_len); 724170259Sdelphij line_end = line + line_len; 72560786Sps opos = npos = linepos; 72660786Sps hl = anchor->hl_first; 72760786Sps checkstart = TRUE; 72860786Sps while (hl != NULL) 72960786Sps { 73060786Sps /* 73160786Sps * See if we need to adjust the current hl_startpos or 73260786Sps * hl_endpos. After adjusting startpos[i], move to endpos[i]. 73360786Sps * After adjusting endpos[i], move to startpos[i+1]. 73460786Sps * The hilite list must be sorted thus: 73560786Sps * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc. 73660786Sps */ 73760786Sps if (checkstart && hl->hl_startpos == opos) 73860786Sps { 73960786Sps hl->hl_startpos = npos; 74060786Sps checkstart = FALSE; 74160786Sps continue; /* {{ not really necessary }} */ 74260786Sps } else if (!checkstart && hl->hl_endpos == opos) 74360786Sps { 74460786Sps hl->hl_endpos = npos; 74560786Sps checkstart = TRUE; 74660786Sps hl = hl->hl_next; 74760786Sps continue; /* {{ necessary }} */ 74860786Sps } 749170259Sdelphij if (line == line_end) 75060786Sps break; 751170259Sdelphij adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos); 75260786Sps opos++; 75360786Sps npos++; 75460786Sps line++; 755128348Stjr if (cvt_ops & CVT_BS) 75660786Sps { 757161478Sdelphij while (*line == '\b') 758128348Stjr { 759161478Sdelphij npos++; 760161478Sdelphij line++; 761170259Sdelphij adj_hilite_ansi(cvt_ops, &line, line_end - line, &npos); 762170259Sdelphij if (line == line_end) 763161478Sdelphij { 764161478Sdelphij --npos; 765161478Sdelphij --line; 766161478Sdelphij break; 767161478Sdelphij } 768128348Stjr /* 769128348Stjr * Found a backspace. The file position moves 770128348Stjr * forward by 2 relative to the processed line 771128348Stjr * which was searched in hilite_line. 772128348Stjr */ 773161478Sdelphij npos++; 774161478Sdelphij line++; 775128348Stjr } 77660786Sps } 77760786Sps } 77860786Sps} 77960786Sps 78060786Sps/* 78160786Sps * Make a hilite for each string in a physical line which matches 78260786Sps * the current pattern. 78360786Sps * sp,ep delimit the first match already found. 78460786Sps */ 78560786Sps static void 786170259Sdelphijhilite_line(linepos, line, line_len, sp, ep, cvt_ops) 78760786Sps POSITION linepos; 78860786Sps char *line; 789170259Sdelphij int line_len; 79060786Sps char *sp; 79160786Sps char *ep; 792128348Stjr int cvt_ops; 79360786Sps{ 79460786Sps char *searchp; 795170259Sdelphij char *line_end = line + line_len; 79660786Sps struct hilite *hl; 79760786Sps struct hilite hilites; 79860786Sps 79960786Sps if (sp == NULL || ep == NULL) 80060786Sps return; 80160786Sps /* 80260786Sps * sp and ep delimit the first match in the line. 80360786Sps * Mark the corresponding file positions, then 80460786Sps * look for further matches and mark them. 80560786Sps * {{ This technique, of calling match_pattern on subsequent 80660786Sps * substrings of the line, may mark more than is correct 80760786Sps * if the pattern starts with "^". This bug is fixed 80860786Sps * for those regex functions that accept a notbol parameter 809170259Sdelphij * (currently POSIX, PCRE and V8-with-regexec2). }} 81060786Sps */ 81160786Sps searchp = line; 81260786Sps /* 81360786Sps * Put the hilites into a temporary list until they're adjusted. 81460786Sps */ 81560786Sps hilites.hl_first = NULL; 81660786Sps do { 81760786Sps if (ep > sp) 81860786Sps { 81960786Sps /* 82060786Sps * Assume that each char position in the "line" 82160786Sps * buffer corresponds to one char position in the file. 82260786Sps * This is not quite true; we need to adjust later. 82360786Sps */ 82460786Sps hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); 82560786Sps hl->hl_startpos = linepos + (sp-line); 82660786Sps hl->hl_endpos = linepos + (ep-line); 82760786Sps add_hilite(&hilites, hl); 82860786Sps } 82960786Sps /* 83060786Sps * If we matched more than zero characters, 83160786Sps * move to the first char after the string we matched. 83260786Sps * If we matched zero, just move to the next char. 83360786Sps */ 83460786Sps if (ep > searchp) 83560786Sps searchp = ep; 836170259Sdelphij else if (searchp != line_end) 83760786Sps searchp++; 83860786Sps else /* end of line */ 83960786Sps break; 840170259Sdelphij } while (match_pattern(searchp, line_end - searchp, &sp, &ep, 1)); 84160786Sps 84260786Sps /* 843128348Stjr * If there were backspaces in the original line, they 844128348Stjr * were removed, and hl_startpos/hl_endpos are not correct. 845128348Stjr * {{ This is very ugly. }} 846128348Stjr */ 847128348Stjr adj_hilite(&hilites, linepos, cvt_ops); 848128348Stjr 849128348Stjr /* 85060786Sps * Now put the hilites into the real list. 85160786Sps */ 85260786Sps while ((hl = hilites.hl_next) != NULL) 85360786Sps { 85460786Sps hilites.hl_next = hl->hl_next; 85560786Sps add_hilite(&hilite_anchor, hl); 85660786Sps } 85760786Sps} 85860786Sps#endif 85960786Sps 86060786Sps/* 86160786Sps * Change the caseless-ness of searches. 86260786Sps * Updates the internal search state to reflect a change in the -i flag. 86360786Sps */ 86460786Sps public void 86560786Spschg_caseless() 86660786Sps{ 86760786Sps if (!is_ucase_pattern) 86860786Sps /* 86960786Sps * Pattern did not have uppercase. 87060786Sps * Just set the search caselessness to the global caselessness. 87160786Sps */ 87260786Sps is_caseless = caseless; 87360786Sps else 87460786Sps /* 87560786Sps * Pattern did have uppercase. 87660786Sps * Discard the pattern; we can't change search caselessness now. 87760786Sps */ 87860786Sps uncompile_pattern(); 87960786Sps} 88060786Sps 88160786Sps#if HILITE_SEARCH 88260786Sps/* 88360786Sps * Find matching text which is currently on screen and highlight it. 88460786Sps */ 88560786Sps static void 88660786Spshilite_screen() 88760786Sps{ 88860786Sps struct scrpos scrpos; 88960786Sps 89060786Sps get_scrpos(&scrpos); 89160786Sps if (scrpos.pos == NULL_POSITION) 89260786Sps return; 89360786Sps prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); 89460786Sps repaint_hilite(1); 89560786Sps} 89660786Sps 89760786Sps/* 89860786Sps * Change highlighting parameters. 89960786Sps */ 90060786Sps public void 90160786Spschg_hilite() 90260786Sps{ 90360786Sps /* 90460786Sps * Erase any highlights currently on screen. 90560786Sps */ 90660786Sps clr_hilite(); 90760786Sps hide_hilite = 0; 90860786Sps 90960786Sps if (hilite_search == OPT_ONPLUS) 91060786Sps /* 91160786Sps * Display highlights. 91260786Sps */ 91360786Sps hilite_screen(); 91460786Sps} 91560786Sps#endif 91660786Sps 91760786Sps/* 91860786Sps * Figure out where to start a search. 91960786Sps */ 92060786Sps static POSITION 92160786Spssearch_pos(search_type) 92260786Sps int search_type; 92360786Sps{ 92460786Sps POSITION pos; 92560786Sps int linenum; 92660786Sps 92760786Sps if (empty_screen()) 92860786Sps { 92960786Sps /* 93060786Sps * Start at the beginning (or end) of the file. 93160786Sps * The empty_screen() case is mainly for 93260786Sps * command line initiated searches; 93360786Sps * for example, "+/xyz" on the command line. 93460786Sps * Also for multi-file (SRCH_PAST_EOF) searches. 93560786Sps */ 93660786Sps if (search_type & SRCH_FORW) 93760786Sps { 93860786Sps return (ch_zero()); 93960786Sps } else 94060786Sps { 94160786Sps pos = ch_length(); 94260786Sps if (pos == NULL_POSITION) 94360786Sps { 94460786Sps (void) ch_end_seek(); 94560786Sps pos = ch_length(); 94660786Sps } 94760786Sps return (pos); 94860786Sps } 94960786Sps } 95060786Sps if (how_search) 95160786Sps { 95260786Sps /* 95360786Sps * Search does not include current screen. 95460786Sps */ 95560786Sps if (search_type & SRCH_FORW) 95660786Sps linenum = BOTTOM_PLUS_ONE; 95760786Sps else 95860786Sps linenum = TOP; 95960786Sps pos = position(linenum); 96060786Sps } else 96160786Sps { 96260786Sps /* 96360786Sps * Search includes current screen. 96460786Sps * It starts at the jump target (if searching backwards), 96560786Sps * or at the jump target plus one (if forwards). 96660786Sps */ 96760786Sps linenum = adjsline(jump_sline); 96860786Sps pos = position(linenum); 96960786Sps if (search_type & SRCH_FORW) 97060786Sps { 971170259Sdelphij pos = forw_raw_line(pos, (char **)NULL, (int *)NULL); 97260786Sps while (pos == NULL_POSITION) 97360786Sps { 97460786Sps if (++linenum >= sc_height) 97560786Sps break; 97660786Sps pos = position(linenum); 97760786Sps } 97860786Sps } else 97960786Sps { 98060786Sps while (pos == NULL_POSITION) 98160786Sps { 98260786Sps if (--linenum < 0) 98360786Sps break; 98460786Sps pos = position(linenum); 98560786Sps } 98660786Sps } 98760786Sps } 98860786Sps return (pos); 98960786Sps} 99060786Sps 99160786Sps/* 99260786Sps * Search a subset of the file, specified by start/end position. 99360786Sps */ 99460786Sps static int 99560786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) 99660786Sps POSITION pos; 99760786Sps POSITION endpos; 99860786Sps int search_type; 99960786Sps int matches; 100060786Sps int maxlines; 100160786Sps POSITION *plinepos; 100260786Sps POSITION *pendpos; 100360786Sps{ 100460786Sps char *line; 1005170259Sdelphij int line_len; 1006128348Stjr LINENUM linenum; 100760786Sps char *sp, *ep; 100860786Sps int line_match; 1009128348Stjr int cvt_ops; 101060786Sps POSITION linepos, oldpos; 101160786Sps 101260786Sps linenum = find_linenum(pos); 101360786Sps oldpos = pos; 101460786Sps for (;;) 101560786Sps { 101660786Sps /* 101760786Sps * Get lines until we find a matching one or until 101860786Sps * we hit end-of-file (or beginning-of-file if we're 101960786Sps * going backwards), or until we hit the end position. 102060786Sps */ 102160786Sps if (ABORT_SIGS()) 102260786Sps { 102360786Sps /* 102460786Sps * A signal aborts the search. 102560786Sps */ 102660786Sps return (-1); 102760786Sps } 102860786Sps 102960786Sps if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) 103060786Sps { 103160786Sps /* 103260786Sps * Reached end position without a match. 103360786Sps */ 103460786Sps if (pendpos != NULL) 103560786Sps *pendpos = pos; 103660786Sps return (matches); 103760786Sps } 103860786Sps if (maxlines > 0) 103960786Sps maxlines--; 104060786Sps 104160786Sps if (search_type & SRCH_FORW) 104260786Sps { 104360786Sps /* 104460786Sps * Read the next line, and save the 104560786Sps * starting position of that line in linepos. 104660786Sps */ 104760786Sps linepos = pos; 1048170259Sdelphij pos = forw_raw_line(pos, &line, &line_len); 104960786Sps if (linenum != 0) 105060786Sps linenum++; 105160786Sps } else 105260786Sps { 105360786Sps /* 105460786Sps * Read the previous line and save the 105560786Sps * starting position of that line in linepos. 105660786Sps */ 1057170259Sdelphij pos = back_raw_line(pos, &line, &line_len); 105860786Sps linepos = pos; 105960786Sps if (linenum != 0) 106060786Sps linenum--; 106160786Sps } 106260786Sps 106360786Sps if (pos == NULL_POSITION) 106460786Sps { 106560786Sps /* 106660786Sps * Reached EOF/BOF without a match. 106760786Sps */ 106860786Sps if (pendpos != NULL) 106960786Sps *pendpos = oldpos; 107060786Sps return (matches); 107160786Sps } 107260786Sps 107360786Sps /* 107460786Sps * If we're using line numbers, we might as well 107560786Sps * remember the information we have now (the position 107660786Sps * and line number of the current line). 107760786Sps * Don't do it for every line because it slows down 107860786Sps * the search. Remember the line number only if 107960786Sps * we're "far" from the last place we remembered it. 108060786Sps */ 108160786Sps if (linenums && abs((int)(pos - oldpos)) > 1024) 108260786Sps add_lnum(linenum, pos); 108360786Sps oldpos = pos; 108460786Sps 108560786Sps /* 108660786Sps * If it's a caseless search, convert the line to lowercase. 108760786Sps * If we're doing backspace processing, delete backspaces. 108860786Sps */ 1089128348Stjr cvt_ops = get_cvt_ops(); 1090170259Sdelphij cvt_text(line, line, &line_len, cvt_ops); 109160786Sps 109260786Sps /* 109360786Sps * Test the next line to see if we have a match. 109460786Sps * We are successful if we either want a match and got one, 109560786Sps * or if we want a non-match and got one. 109660786Sps */ 1097170259Sdelphij line_match = match_pattern(line, line_len, &sp, &ep, 0); 109860786Sps line_match = (!(search_type & SRCH_NO_MATCH) && line_match) || 109960786Sps ((search_type & SRCH_NO_MATCH) && !line_match); 110060786Sps if (!line_match) 110160786Sps continue; 110260786Sps /* 110360786Sps * Got a match. 110460786Sps */ 110560786Sps if (search_type & SRCH_FIND_ALL) 110660786Sps { 110760786Sps#if HILITE_SEARCH 110860786Sps /* 110960786Sps * We are supposed to find all matches in the range. 111060786Sps * Just add the matches in this line to the 111160786Sps * hilite list and keep searching. 111260786Sps */ 111360786Sps if (line_match) 1114170259Sdelphij hilite_line(linepos, line, line_len, sp, ep, cvt_ops); 111560786Sps#endif 111660786Sps } else if (--matches <= 0) 111760786Sps { 111860786Sps /* 111960786Sps * Found the one match we're looking for. 112060786Sps * Return it. 112160786Sps */ 112260786Sps#if HILITE_SEARCH 1123161478Sdelphij if (hilite_search == OPT_ON) 112460786Sps { 112560786Sps /* 112660786Sps * Clear the hilite list and add only 112760786Sps * the matches in this one line. 112860786Sps */ 112960786Sps clr_hilite(); 113060786Sps if (line_match) 1131170259Sdelphij hilite_line(linepos, line, line_len, sp, ep, cvt_ops); 113260786Sps } 113360786Sps#endif 113460786Sps if (plinepos != NULL) 113560786Sps *plinepos = linepos; 113660786Sps return (0); 113760786Sps } 113860786Sps } 113960786Sps} 114060786Sps 1141170259Sdelphij /* 1142170259Sdelphij * search for a pattern in history. If found, compile that pattern. 1143170259Sdelphij */ 1144170259Sdelphij static int 1145170259Sdelphijhist_pattern(search_type) 1146170259Sdelphij int search_type; 1147170259Sdelphij{ 1148170259Sdelphij#if CMD_HISTORY 1149170259Sdelphij char *pattern; 1150170259Sdelphij 1151170259Sdelphij set_mlist(ml_search, 0); 1152170259Sdelphij pattern = cmd_lastpattern(); 1153170259Sdelphij if (pattern == NULL) 1154170259Sdelphij return (0); 1155170259Sdelphij 1156170259Sdelphij if (caseless == OPT_ONPLUS) 1157170259Sdelphij cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC); 1158170259Sdelphij 1159170259Sdelphij if (compile_pattern(pattern, search_type) < 0) 1160170259Sdelphij return (0); 1161170259Sdelphij 1162170259Sdelphij is_ucase_pattern = is_ucase(pattern); 1163170259Sdelphij if (is_ucase_pattern && caseless != OPT_ONPLUS) 1164170259Sdelphij is_caseless = 0; 1165170259Sdelphij else 1166170259Sdelphij is_caseless = caseless; 1167170259Sdelphij 1168170259Sdelphij#if HILITE_SEARCH 1169170259Sdelphij if (hilite_search == OPT_ONPLUS && !hide_hilite) 1170170259Sdelphij hilite_screen(); 1171170259Sdelphij#endif 1172170259Sdelphij 1173170259Sdelphij return (1); 1174170259Sdelphij#else /* CMD_HISTORY */ 1175170259Sdelphij return (0); 1176170259Sdelphij#endif /* CMD_HISTORY */ 1177170259Sdelphij} 1178170259Sdelphij 117960786Sps/* 118060786Sps * Search for the n-th occurrence of a specified pattern, 118160786Sps * either forward or backward. 118260786Sps * Return the number of matches not yet found in this file 118360786Sps * (that is, n minus the number of matches found). 118460786Sps * Return -1 if the search should be aborted. 118560786Sps * Caller may continue the search in another file 118660786Sps * if less than n matches are found in this file. 118760786Sps */ 118860786Sps public int 118960786Spssearch(search_type, pattern, n) 119060786Sps int search_type; 119160786Sps char *pattern; 119260786Sps int n; 119360786Sps{ 119460786Sps POSITION pos; 119560786Sps int ucase; 119660786Sps 119760786Sps if (pattern == NULL || *pattern == '\0') 119860786Sps { 119960786Sps /* 120060786Sps * A null pattern means use the previously compiled pattern. 120160786Sps */ 1202170259Sdelphij if (!prev_pattern() && !hist_pattern(search_type)) 120360786Sps { 120460786Sps error("No previous regular expression", NULL_PARG); 120560786Sps return (-1); 120660786Sps } 120760786Sps if ((search_type & SRCH_NO_REGEX) != 120860786Sps (last_search_type & SRCH_NO_REGEX)) 120960786Sps { 121060786Sps error("Please re-enter search pattern", NULL_PARG); 121160786Sps return -1; 121260786Sps } 121360786Sps#if HILITE_SEARCH 121460786Sps if (hilite_search == OPT_ON) 121560786Sps { 121660786Sps /* 121760786Sps * Erase the highlights currently on screen. 121860786Sps * If the search fails, we'll redisplay them later. 121960786Sps */ 122060786Sps repaint_hilite(0); 122160786Sps } 122260786Sps if (hilite_search == OPT_ONPLUS && hide_hilite) 122360786Sps { 122460786Sps /* 122560786Sps * Highlight any matches currently on screen, 122660786Sps * before we actually start the search. 122760786Sps */ 122860786Sps hide_hilite = 0; 122960786Sps hilite_screen(); 123060786Sps } 123160786Sps hide_hilite = 0; 123260786Sps#endif 123360786Sps } else 123460786Sps { 123560786Sps /* 123660786Sps * Compile the pattern. 123760786Sps */ 123860786Sps ucase = is_ucase(pattern); 123960786Sps if (caseless == OPT_ONPLUS) 1240170259Sdelphij cvt_text(pattern, pattern, (int *)NULL, CVT_TO_LC); 124160786Sps if (compile_pattern(pattern, search_type) < 0) 124260786Sps return (-1); 124360786Sps /* 124460786Sps * Ignore case if -I is set OR 124560786Sps * -i is set AND the pattern is all lowercase. 124660786Sps */ 124760786Sps is_ucase_pattern = ucase; 124860786Sps if (is_ucase_pattern && caseless != OPT_ONPLUS) 124960786Sps is_caseless = 0; 125060786Sps else 125160786Sps is_caseless = caseless; 125260786Sps#if HILITE_SEARCH 125360786Sps if (hilite_search) 125460786Sps { 125560786Sps /* 125660786Sps * Erase the highlights currently on screen. 125760786Sps * Also permanently delete them from the hilite list. 125860786Sps */ 125960786Sps repaint_hilite(0); 126060786Sps hide_hilite = 0; 126160786Sps clr_hilite(); 126260786Sps } 126360786Sps if (hilite_search == OPT_ONPLUS) 126460786Sps { 126560786Sps /* 126660786Sps * Highlight any matches currently on screen, 126760786Sps * before we actually start the search. 126860786Sps */ 126960786Sps hilite_screen(); 127060786Sps } 127160786Sps#endif 127260786Sps } 127360786Sps 127460786Sps /* 127560786Sps * Figure out where to start the search. 127660786Sps */ 127760786Sps pos = search_pos(search_type); 127860786Sps if (pos == NULL_POSITION) 127960786Sps { 128060786Sps /* 128160786Sps * Can't find anyplace to start searching from. 128260786Sps */ 128360786Sps if (search_type & SRCH_PAST_EOF) 128460786Sps return (n); 128560786Sps /* repaint(); -- why was this here? */ 128660786Sps error("Nothing to search", NULL_PARG); 128760786Sps return (-1); 128860786Sps } 128960786Sps 129060786Sps n = search_range(pos, NULL_POSITION, search_type, n, -1, 129160786Sps &pos, (POSITION*)NULL); 129260786Sps if (n != 0) 129360786Sps { 129460786Sps /* 129560786Sps * Search was unsuccessful. 129660786Sps */ 129760786Sps#if HILITE_SEARCH 129860786Sps if (hilite_search == OPT_ON && n > 0) 129960786Sps /* 130060786Sps * Redisplay old hilites. 130160786Sps */ 130260786Sps repaint_hilite(1); 130360786Sps#endif 130460786Sps return (n); 130560786Sps } 130660786Sps 130760786Sps if (!(search_type & SRCH_NO_MOVE)) 130860786Sps { 130960786Sps /* 131060786Sps * Go to the matching line. 131160786Sps */ 131260786Sps jump_loc(pos, jump_sline); 131360786Sps } 131460786Sps 131560786Sps#if HILITE_SEARCH 131660786Sps if (hilite_search == OPT_ON) 131760786Sps /* 131860786Sps * Display new hilites in the matching line. 131960786Sps */ 132060786Sps repaint_hilite(1); 132160786Sps#endif 132260786Sps return (0); 132360786Sps} 132460786Sps 132560786Sps 132660786Sps#if HILITE_SEARCH 132760786Sps/* 132860786Sps * Prepare hilites in a given range of the file. 132960786Sps * 133060786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region 133160786Sps * of the file that has been "prepared"; that is, scanned for matches for 133260786Sps * the current search pattern, and hilites have been created for such matches. 133360786Sps * If prep_startpos == NULL_POSITION, the prep region is empty. 133460786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF. 133560786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region. 133660786Sps */ 133760786Sps public void 133860786Spsprep_hilite(spos, epos, maxlines) 133960786Sps POSITION spos; 134060786Sps POSITION epos; 134160786Sps int maxlines; 134260786Sps{ 134360786Sps POSITION nprep_startpos = prep_startpos; 134460786Sps POSITION nprep_endpos = prep_endpos; 134560786Sps POSITION new_epos; 134660786Sps POSITION max_epos; 134760786Sps int result; 134860786Sps int i; 134960786Sps/* 135060786Sps * Search beyond where we're asked to search, so the prep region covers 135160786Sps * more than we need. Do one big search instead of a bunch of small ones. 135260786Sps */ 135360786Sps#define SEARCH_MORE (3*size_linebuf) 135460786Sps 135560786Sps if (!prev_pattern()) 135660786Sps return; 135760786Sps 135860786Sps /* 135960786Sps * If we're limited to a max number of lines, figure out the 136060786Sps * file position we should stop at. 136160786Sps */ 136260786Sps if (maxlines < 0) 136360786Sps max_epos = NULL_POSITION; 136460786Sps else 136560786Sps { 136660786Sps max_epos = spos; 136760786Sps for (i = 0; i < maxlines; i++) 1368170259Sdelphij max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); 136960786Sps } 137060786Sps 137160786Sps /* 137260786Sps * Find two ranges: 137360786Sps * The range that we need to search (spos,epos); and the range that 137460786Sps * the "prep" region will then cover (nprep_startpos,nprep_endpos). 137560786Sps */ 137660786Sps 137760786Sps if (prep_startpos == NULL_POSITION || 137860786Sps (epos != NULL_POSITION && epos < prep_startpos) || 137960786Sps spos > prep_endpos) 138060786Sps { 138160786Sps /* 138260786Sps * New range is not contiguous with old prep region. 138360786Sps * Discard the old prep region and start a new one. 138460786Sps */ 138560786Sps clr_hilite(); 138660786Sps if (epos != NULL_POSITION) 138760786Sps epos += SEARCH_MORE; 138860786Sps nprep_startpos = spos; 138960786Sps } else 139060786Sps { 139160786Sps /* 139260786Sps * New range partially or completely overlaps old prep region. 139360786Sps */ 139460786Sps if (epos == NULL_POSITION) 139560786Sps { 139660786Sps /* 139760786Sps * New range goes to end of file. 139860786Sps */ 139960786Sps ; 140060786Sps } else if (epos > prep_endpos) 140160786Sps { 140260786Sps /* 140360786Sps * New range ends after old prep region. 140460786Sps * Extend prep region to end at end of new range. 140560786Sps */ 140660786Sps epos += SEARCH_MORE; 140760786Sps } else /* (epos <= prep_endpos) */ 140860786Sps { 140960786Sps /* 141060786Sps * New range ends within old prep region. 141160786Sps * Truncate search to end at start of old prep region. 141260786Sps */ 141360786Sps epos = prep_startpos; 141460786Sps } 141560786Sps 141660786Sps if (spos < prep_startpos) 141760786Sps { 141860786Sps /* 141960786Sps * New range starts before old prep region. 142060786Sps * Extend old prep region backwards to start at 142160786Sps * start of new range. 142260786Sps */ 142360786Sps if (spos < SEARCH_MORE) 142460786Sps spos = 0; 142560786Sps else 142660786Sps spos -= SEARCH_MORE; 142760786Sps nprep_startpos = spos; 142860786Sps } else /* (spos >= prep_startpos) */ 142960786Sps { 143060786Sps /* 143160786Sps * New range starts within or after old prep region. 143260786Sps * Trim search to start at end of old prep region. 143360786Sps */ 143460786Sps spos = prep_endpos; 143560786Sps } 143660786Sps } 143760786Sps 143860786Sps if (epos != NULL_POSITION && max_epos != NULL_POSITION && 143960786Sps epos > max_epos) 144060786Sps /* 144160786Sps * Don't go past the max position we're allowed. 144260786Sps */ 144360786Sps epos = max_epos; 144460786Sps 144560786Sps if (epos == NULL_POSITION || epos > spos) 144660786Sps { 144760786Sps result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, 144860786Sps maxlines, (POSITION*)NULL, &new_epos); 144960786Sps if (result < 0) 145060786Sps return; 145160786Sps if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 145260786Sps nprep_endpos = new_epos; 145360786Sps } 145460786Sps prep_startpos = nprep_startpos; 145560786Sps prep_endpos = nprep_endpos; 145660786Sps} 145760786Sps#endif 145860786Sps 145960786Sps/* 146060786Sps * Simple pattern matching function. 146160786Sps * It supports no metacharacters like *, etc. 146260786Sps */ 146360786Sps static int 1464170259Sdelphijmatch(pattern, pattern_len, buf, buf_len, pfound, pend) 1465170259Sdelphij char *pattern; 1466170259Sdelphij int pattern_len; 1467170259Sdelphij char *buf; 1468170259Sdelphij int buf_len; 146960786Sps char **pfound, **pend; 147060786Sps{ 147160786Sps register char *pp, *lp; 1472170259Sdelphij register char *pattern_end = pattern + pattern_len; 1473170259Sdelphij register char *buf_end = buf + buf_len; 147460786Sps 1475170259Sdelphij for ( ; buf < buf_end; buf++) 147660786Sps { 147760786Sps for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) 1478170259Sdelphij if (pp == pattern_end || lp == buf_end) 147960786Sps break; 1480170259Sdelphij if (pp == pattern_end) 148160786Sps { 148260786Sps if (pfound != NULL) 148360786Sps *pfound = buf; 148460786Sps if (pend != NULL) 148560786Sps *pend = lp; 148660786Sps return (1); 148760786Sps } 148860786Sps } 148960786Sps return (0); 149060786Sps} 149160786Sps 149260786Sps#if HAVE_V8_REGCOMP 149360786Sps/* 149460786Sps * This function is called by the V8 regcomp to report 149560786Sps * errors in regular expressions. 149660786Sps */ 149760786Sps void 149860786Spsregerror(s) 149960786Sps char *s; 150060786Sps{ 150160786Sps PARG parg; 150260786Sps 150360786Sps parg.p_string = s; 150460786Sps error("%s", &parg); 150560786Sps} 150660786Sps#endif 150760786Sps 1508