search.c revision 161478
160812Sps/* $FreeBSD: head/contrib/less/search.c 161478 2006-08-20 15:50:51Z delphij $ */ 260786Sps/* 3161478Sdelphij * Copyright (C) 1984-2005 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 2660812Sps#define REGCOMP_FLAG (more_mode ? 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; 5660812Spsextern int more_mode; 57128348Stjrextern int ctldisp; 5863131Spsextern int status_col; 5960786Spsextern POSITION start_attnpos; 6060786Spsextern POSITION end_attnpos; 6160786Sps#if HILITE_SEARCH 6260786Spsextern int hilite_search; 6360786Spsextern int screen_trashed; 6460786Spsextern int size_linebuf; 6560786Spsextern int squished; 6660786Spsextern int can_goto_line; 6760786Spsstatic int hide_hilite; 6860786Spsstatic POSITION prep_startpos; 6960786Spsstatic POSITION prep_endpos; 7060786Sps 7160786Spsstruct hilite 7260786Sps{ 7360786Sps struct hilite *hl_next; 7460786Sps POSITION hl_startpos; 7560786Sps POSITION hl_endpos; 7660786Sps}; 7760786Spsstatic struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION }; 7860786Sps#define hl_first hl_next 7960786Sps#endif 8060786Sps 8160786Sps/* 8260786Sps * These are the static variables that represent the "remembered" 8360786Sps * search pattern. 8460786Sps */ 8560786Sps#if HAVE_POSIX_REGCOMP 8660786Spsstatic regex_t *regpattern = NULL; 8760786Sps#endif 8860786Sps#if HAVE_PCRE 8960786Spspcre *regpattern = NULL; 9060786Sps#endif 9160786Sps#if HAVE_RE_COMP 9260786Spsint re_pattern = 0; 9360786Sps#endif 9460786Sps#if HAVE_REGCMP 9560786Spsstatic char *cpattern = NULL; 9660786Sps#endif 9760786Sps#if HAVE_V8_REGCOMP 9860786Spsstatic struct regexp *regpattern = NULL; 9960786Sps#endif 10060786Sps 10160786Spsstatic int is_caseless; 10260786Spsstatic int is_ucase_pattern; 10360786Spsstatic int last_search_type; 10460786Spsstatic char *last_pattern = NULL; 10560786Sps 10660786Sps/* 10760786Sps * Convert text. Perform one or more of these transformations: 10860786Sps */ 10960786Sps#define CVT_TO_LC 01 /* Convert upper-case to lower-case */ 11060786Sps#define CVT_BS 02 /* Do backspace processing */ 11160786Sps#define CVT_CRLF 04 /* Remove CR after LF */ 112128348Stjr#define CVT_ANSI 010 /* Remove ANSI escape sequences */ 11360786Sps 11460786Sps static void 11560786Spscvt_text(odst, osrc, ops) 11660786Sps char *odst; 11760786Sps char *osrc; 11860786Sps int ops; 11960786Sps{ 12060786Sps register char *dst; 12160786Sps register char *src; 12260786Sps 123128348Stjr for (src = osrc, dst = odst; *src != '\0'; src++) 12460786Sps { 125161478Sdelphij if ((ops & CVT_TO_LC) && IS_UPPER(*src)) 12660786Sps /* Convert uppercase to lowercase. */ 127161478Sdelphij *dst++ = TO_LOWER(*src); 12860786Sps else if ((ops & CVT_BS) && *src == '\b' && dst > odst) 12960786Sps /* Delete BS and preceding char. */ 130128348Stjr dst--; 131128348Stjr else if ((ops & CVT_ANSI) && *src == ESC) 132128348Stjr { 133128348Stjr /* Skip to end of ANSI escape sequence. */ 134128348Stjr while (src[1] != '\0') 135161478Sdelphij if (!is_ansi_middle(*++src)) 136128348Stjr break; 137128348Stjr } else 13860786Sps /* Just copy. */ 139128348Stjr *dst++ = *src; 14060786Sps } 14160786Sps if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r') 14260786Sps dst--; 14360786Sps *dst = '\0'; 14460786Sps} 14560786Sps 14660786Sps/* 147128348Stjr * Determine which conversions to perform. 148128348Stjr */ 149128348Stjr static int 150128348Stjrget_cvt_ops() 151128348Stjr{ 152128348Stjr int ops = 0; 153128348Stjr if (is_caseless || bs_mode == BS_SPECIAL) 154128348Stjr { 155128348Stjr if (is_caseless) 156128348Stjr ops |= CVT_TO_LC; 157128348Stjr if (bs_mode == BS_SPECIAL) 158128348Stjr ops |= CVT_BS; 159128348Stjr if (bs_mode != BS_CONTROL) 160128348Stjr ops |= CVT_CRLF; 161128348Stjr } else if (bs_mode != BS_CONTROL) 162128348Stjr { 163128348Stjr ops |= CVT_CRLF; 164128348Stjr } 165128348Stjr if (ctldisp == OPT_ONPLUS) 166128348Stjr ops |= CVT_ANSI; 167128348Stjr return (ops); 168128348Stjr} 169128348Stjr 170128348Stjr/* 17160786Sps * Are there any uppercase letters in this string? 17260786Sps */ 17360786Sps static int 17460786Spsis_ucase(s) 17560786Sps char *s; 17660786Sps{ 17760786Sps register char *p; 17860786Sps 17960786Sps for (p = s; *p != '\0'; p++) 180161478Sdelphij if (IS_UPPER(*p)) 18160786Sps return (1); 18260786Sps return (0); 18360786Sps} 18460786Sps 18560786Sps/* 18660786Sps * Is there a previous (remembered) search pattern? 18760786Sps */ 18860786Sps static int 18960786Spsprev_pattern() 19060786Sps{ 19160786Sps if (last_search_type & SRCH_NO_REGEX) 19260786Sps return (last_pattern != NULL); 19360786Sps#if HAVE_POSIX_REGCOMP 19460786Sps return (regpattern != NULL); 19560786Sps#endif 19660786Sps#if HAVE_PCRE 19760786Sps return (regpattern != NULL); 19860786Sps#endif 19960786Sps#if HAVE_RE_COMP 20060786Sps return (re_pattern != 0); 20160786Sps#endif 20260786Sps#if HAVE_REGCMP 20360786Sps return (cpattern != NULL); 20460786Sps#endif 20560786Sps#if HAVE_V8_REGCOMP 20660786Sps return (regpattern != NULL); 20760786Sps#endif 20860786Sps#if NO_REGEX 20960786Sps return (last_pattern != NULL); 21060786Sps#endif 21160786Sps} 21260786Sps 21360786Sps#if HILITE_SEARCH 21460786Sps/* 21560786Sps * Repaint the hilites currently displayed on the screen. 21660786Sps * Repaint each line which contains highlighted text. 21760786Sps * If on==0, force all hilites off. 21860786Sps */ 21960786Sps public void 22060786Spsrepaint_hilite(on) 22160786Sps int on; 22260786Sps{ 22360786Sps int slinenum; 22460786Sps POSITION pos; 22560786Sps POSITION epos; 22660786Sps int save_hide_hilite; 22760786Sps 22860786Sps if (squished) 22960786Sps repaint(); 23060786Sps 23160786Sps save_hide_hilite = hide_hilite; 23260786Sps if (!on) 23360786Sps { 23460786Sps if (hide_hilite) 23560786Sps return; 23660786Sps hide_hilite = 1; 23760786Sps } 23860786Sps 23960786Sps if (!can_goto_line) 24060786Sps { 24160786Sps repaint(); 24260786Sps hide_hilite = save_hide_hilite; 24360786Sps return; 24460786Sps } 24560786Sps 24660786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 24760786Sps { 24860786Sps pos = position(slinenum); 24960786Sps if (pos == NULL_POSITION) 25060786Sps continue; 25160786Sps epos = position(slinenum+1); 252161478Sdelphij#if 0 25360786Sps /* 25460786Sps * If any character in the line is highlighted, 25560786Sps * repaint the line. 256161478Sdelphij * 257161478Sdelphij * {{ This doesn't work -- if line is drawn with highlights 258161478Sdelphij * which should be erased (e.g. toggle -i with status column), 259161478Sdelphij * we must redraw the line even if it has no highlights. 260161478Sdelphij * For now, just repaint every line. }} 26160786Sps */ 262161478Sdelphij if (is_hilited(pos, epos, 1, NULL)) 263161478Sdelphij#endif 26460786Sps { 26560786Sps (void) forw_line(pos); 26660786Sps goto_line(slinenum); 26760786Sps put_line(); 26860786Sps } 26960786Sps } 27060786Sps hide_hilite = save_hide_hilite; 27160786Sps} 27260786Sps 27360786Sps/* 27460786Sps * Clear the attn hilite. 27560786Sps */ 27660786Sps public void 27760786Spsclear_attn() 27860786Sps{ 27960786Sps int slinenum; 28060786Sps POSITION old_start_attnpos; 28160786Sps POSITION old_end_attnpos; 28260786Sps POSITION pos; 28360786Sps POSITION epos; 28460786Sps 28560786Sps if (start_attnpos == NULL_POSITION) 28660786Sps return; 28760786Sps old_start_attnpos = start_attnpos; 28860786Sps old_end_attnpos = end_attnpos; 28960786Sps start_attnpos = end_attnpos = NULL_POSITION; 29060786Sps 29160786Sps if (!can_goto_line) 29260786Sps { 29360786Sps repaint(); 29460786Sps return; 29560786Sps } 29660786Sps if (squished) 29760786Sps repaint(); 29860786Sps 29960786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 30060786Sps { 30160786Sps pos = position(slinenum); 30260786Sps if (pos == NULL_POSITION) 30360786Sps continue; 30460786Sps epos = position(slinenum+1); 30560786Sps if (pos < old_end_attnpos && 30660786Sps (epos == NULL_POSITION || epos > old_start_attnpos)) 30760786Sps { 30860786Sps (void) forw_line(pos); 30960786Sps goto_line(slinenum); 31060786Sps put_line(); 31160786Sps } 31260786Sps } 31360786Sps} 31460786Sps#endif 31560786Sps 31660786Sps/* 31760786Sps * Hide search string highlighting. 31860786Sps */ 31960786Sps public void 32060786Spsundo_search() 32160786Sps{ 32260786Sps if (!prev_pattern()) 32360786Sps { 32460786Sps error("No previous regular expression", NULL_PARG); 32560786Sps return; 32660786Sps } 32760786Sps#if HILITE_SEARCH 32860786Sps hide_hilite = !hide_hilite; 32960786Sps repaint_hilite(1); 33060786Sps#endif 33160786Sps} 33260786Sps 33360786Sps/* 33460786Sps * Compile a search pattern, for future use by match_pattern. 33560786Sps */ 33660786Sps static int 33760786Spscompile_pattern(pattern, search_type) 33860786Sps char *pattern; 33960786Sps int search_type; 34060786Sps{ 34160786Sps if ((search_type & SRCH_NO_REGEX) == 0) 34260786Sps { 34360786Sps#if HAVE_POSIX_REGCOMP 34460786Sps regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t)); 34560786Sps if (regcomp(s, pattern, REGCOMP_FLAG)) 34660786Sps { 34760786Sps free(s); 34860786Sps error("Invalid pattern", NULL_PARG); 34960786Sps return (-1); 35060786Sps } 35160786Sps if (regpattern != NULL) 35260786Sps regfree(regpattern); 35360786Sps regpattern = s; 35460786Sps#endif 35560786Sps#if HAVE_PCRE 35660786Sps pcre *comp; 35760786Sps const char *errstring; 35860786Sps int erroffset; 35960786Sps PARG parg; 36060786Sps comp = pcre_compile(pattern, 0, 36160786Sps &errstring, &erroffset, NULL); 36260786Sps if (comp == NULL) 36360786Sps { 36460786Sps parg.p_string = (char *) errstring; 36560786Sps error("%s", &parg); 36660786Sps return (-1); 36760786Sps } 36860786Sps regpattern = comp; 36960786Sps#endif 37060786Sps#if HAVE_RE_COMP 37160786Sps PARG parg; 37260786Sps if ((parg.p_string = re_comp(pattern)) != NULL) 37360786Sps { 37460786Sps error("%s", &parg); 37560786Sps return (-1); 37660786Sps } 37760786Sps re_pattern = 1; 37860786Sps#endif 37960786Sps#if HAVE_REGCMP 38060786Sps char *s; 38160786Sps if ((s = regcmp(pattern, 0)) == NULL) 38260786Sps { 38360786Sps error("Invalid pattern", NULL_PARG); 38460786Sps return (-1); 38560786Sps } 38660786Sps if (cpattern != NULL) 38760786Sps free(cpattern); 38860786Sps cpattern = s; 38960786Sps#endif 39060786Sps#if HAVE_V8_REGCOMP 39160786Sps struct regexp *s; 39260786Sps if ((s = regcomp(pattern)) == NULL) 39360786Sps { 39460786Sps /* 39560786Sps * regcomp has already printed an error message 39660786Sps * via regerror(). 39760786Sps */ 39860786Sps return (-1); 39960786Sps } 40060786Sps if (regpattern != NULL) 40160786Sps free(regpattern); 40260786Sps regpattern = s; 40360786Sps#endif 40460786Sps } 40560786Sps 40660786Sps if (last_pattern != NULL) 40760786Sps free(last_pattern); 40860786Sps last_pattern = (char *) calloc(1, strlen(pattern)+1); 40960786Sps if (last_pattern != NULL) 41060786Sps strcpy(last_pattern, pattern); 41160786Sps 41260786Sps last_search_type = search_type; 41360786Sps return (0); 41460786Sps} 41560786Sps 41660786Sps/* 41760786Sps * Forget that we have a compiled pattern. 41860786Sps */ 41960786Sps static void 42060786Spsuncompile_pattern() 42160786Sps{ 42260786Sps#if HAVE_POSIX_REGCOMP 42360786Sps if (regpattern != NULL) 42460786Sps regfree(regpattern); 42560786Sps regpattern = NULL; 42660786Sps#endif 42760786Sps#if HAVE_PCRE 42860786Sps if (regpattern != NULL) 42960786Sps pcre_free(regpattern); 43060786Sps regpattern = NULL; 43160786Sps#endif 43260786Sps#if HAVE_RE_COMP 43360786Sps re_pattern = 0; 43460786Sps#endif 43560786Sps#if HAVE_REGCMP 43660786Sps if (cpattern != NULL) 43760786Sps free(cpattern); 43860786Sps cpattern = NULL; 43960786Sps#endif 44060786Sps#if HAVE_V8_REGCOMP 44160786Sps if (regpattern != NULL) 44260786Sps free(regpattern); 44360786Sps regpattern = NULL; 44460786Sps#endif 44560786Sps last_pattern = NULL; 44660786Sps} 44760786Sps 44860786Sps/* 44960786Sps * Perform a pattern match with the previously compiled pattern. 45060786Sps * Set sp and ep to the start and end of the matched string. 45160786Sps */ 45260786Sps static int 45360786Spsmatch_pattern(line, sp, ep, notbol) 45460786Sps char *line; 45560786Sps char **sp; 45660786Sps char **ep; 45760786Sps int notbol; 45860786Sps{ 45960786Sps int matched; 46060786Sps 46160786Sps if (last_search_type & SRCH_NO_REGEX) 46260786Sps return (match(last_pattern, line, sp, ep)); 46360786Sps 46460786Sps#if HAVE_POSIX_REGCOMP 46560786Sps { 46660786Sps regmatch_t rm; 46760786Sps int flags = (notbol) ? REG_NOTBOL : 0; 46860786Sps matched = !regexec(regpattern, line, 1, &rm, flags); 46960786Sps if (!matched) 47060786Sps return (0); 47160786Sps#ifndef __WATCOMC__ 47260786Sps *sp = line + rm.rm_so; 47360786Sps *ep = line + rm.rm_eo; 47460786Sps#else 47560786Sps *sp = rm.rm_sp; 47660786Sps *ep = rm.rm_ep; 47760786Sps#endif 47860786Sps } 47960786Sps#endif 48060786Sps#if HAVE_PCRE 48160786Sps { 48260786Sps int flags = (notbol) ? PCRE_NOTBOL : 0; 48360786Sps int ovector[3]; 48460786Sps matched = pcre_exec(regpattern, NULL, line, strlen(line), 48560786Sps 0, flags, ovector, 3) >= 0; 48660786Sps if (!matched) 48760786Sps return (0); 48860786Sps *sp = line + ovector[0]; 48960786Sps *ep = line + ovector[1]; 49060786Sps } 49160786Sps#endif 49260786Sps#if HAVE_RE_COMP 49360786Sps matched = (re_exec(line) == 1); 49460786Sps /* 49560786Sps * re_exec doesn't seem to provide a way to get the matched string. 49660786Sps */ 49760786Sps *sp = *ep = NULL; 49860786Sps#endif 49960786Sps#if HAVE_REGCMP 50060786Sps *ep = regex(cpattern, line); 50160786Sps matched = (*ep != NULL); 50260786Sps if (!matched) 50360786Sps return (0); 50460786Sps *sp = __loc1; 50560786Sps#endif 50660786Sps#if HAVE_V8_REGCOMP 50760786Sps#if HAVE_REGEXEC2 50860786Sps matched = regexec2(regpattern, line, notbol); 50960786Sps#else 51060786Sps matched = regexec(regpattern, line); 51160786Sps#endif 51260786Sps if (!matched) 51360786Sps return (0); 51460786Sps *sp = regpattern->startp[0]; 51560786Sps *ep = regpattern->endp[0]; 51660786Sps#endif 51760786Sps#if NO_REGEX 51860786Sps matched = match(last_pattern, line, sp, ep); 51960786Sps#endif 52060786Sps return (matched); 52160786Sps} 52260786Sps 52360786Sps#if HILITE_SEARCH 52460786Sps/* 52560786Sps * Clear the hilite list. 52660786Sps */ 52760786Sps public void 52860786Spsclr_hilite() 52960786Sps{ 53060786Sps struct hilite *hl; 53160786Sps struct hilite *nexthl; 53260786Sps 53360786Sps for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl) 53460786Sps { 53560786Sps nexthl = hl->hl_next; 53660786Sps free((void*)hl); 53760786Sps } 53860786Sps hilite_anchor.hl_first = NULL; 53960786Sps prep_startpos = prep_endpos = NULL_POSITION; 54060786Sps} 54160786Sps 54260786Sps/* 54360786Sps * Should any characters in a specified range be highlighted? 544161478Sdelphij */ 545161478Sdelphij static int 546161478Sdelphijis_hilited_range(pos, epos) 547161478Sdelphij POSITION pos; 548161478Sdelphij POSITION epos; 549161478Sdelphij{ 550161478Sdelphij struct hilite *hl; 551161478Sdelphij 552161478Sdelphij /* 553161478Sdelphij * Look at each highlight and see if any part of it falls in the range. 554161478Sdelphij */ 555161478Sdelphij for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) 556161478Sdelphij { 557161478Sdelphij if (hl->hl_endpos > pos && 558161478Sdelphij (epos == NULL_POSITION || epos > hl->hl_startpos)) 559161478Sdelphij return (1); 560161478Sdelphij } 561161478Sdelphij return (0); 562161478Sdelphij} 563161478Sdelphij 564161478Sdelphij/* 565161478Sdelphij * Should any characters in a specified range be highlighted? 56660786Sps * If nohide is nonzero, don't consider hide_hilite. 56760786Sps */ 56860786Sps public int 569161478Sdelphijis_hilited(pos, epos, nohide, p_matches) 57060786Sps POSITION pos; 57160786Sps POSITION epos; 57260786Sps int nohide; 573161478Sdelphij int *p_matches; 57460786Sps{ 575161478Sdelphij int match; 57660786Sps 577161478Sdelphij if (p_matches != NULL) 578161478Sdelphij *p_matches = 0; 579161478Sdelphij 58063131Sps if (!status_col && 58163131Sps start_attnpos != NULL_POSITION && 58260786Sps pos < end_attnpos && 58360786Sps (epos == NULL_POSITION || epos > start_attnpos)) 58460786Sps /* 58560786Sps * The attn line overlaps this range. 58660786Sps */ 58760786Sps return (1); 58860786Sps 589161478Sdelphij match = is_hilited_range(pos, epos); 590161478Sdelphij if (!match) 591161478Sdelphij return (0); 592161478Sdelphij 593161478Sdelphij if (p_matches != NULL) 594161478Sdelphij /* 595161478Sdelphij * Report matches, even if we're hiding highlights. 596161478Sdelphij */ 597161478Sdelphij *p_matches = 1; 598161478Sdelphij 59960786Sps if (hilite_search == 0) 60060786Sps /* 60160786Sps * Not doing highlighting. 60260786Sps */ 60360786Sps return (0); 60460786Sps 60560786Sps if (!nohide && hide_hilite) 60660786Sps /* 60760786Sps * Highlighting is hidden. 60860786Sps */ 60960786Sps return (0); 61060786Sps 611161478Sdelphij return (1); 61260786Sps} 61360786Sps 61460786Sps/* 61560786Sps * Add a new hilite to a hilite list. 61660786Sps */ 61760786Sps static void 61860786Spsadd_hilite(anchor, hl) 61960786Sps struct hilite *anchor; 62060786Sps struct hilite *hl; 62160786Sps{ 62260786Sps struct hilite *ihl; 62360786Sps 62460786Sps /* 62560786Sps * Hilites are sorted in the list; find where new one belongs. 62660786Sps * Insert new one after ihl. 62760786Sps */ 62860786Sps for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next) 62960786Sps { 63060786Sps if (ihl->hl_next->hl_startpos > hl->hl_startpos) 63160786Sps break; 63260786Sps } 63360786Sps 63460786Sps /* 63560786Sps * Truncate hilite so it doesn't overlap any existing ones 63660786Sps * above and below it. 63760786Sps */ 63860786Sps if (ihl != anchor) 63960786Sps hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos); 64060786Sps if (ihl->hl_next != NULL) 64160786Sps hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos); 64260786Sps if (hl->hl_startpos >= hl->hl_endpos) 64360786Sps { 64460786Sps /* 64560786Sps * Hilite was truncated out of existence. 64660786Sps */ 64760786Sps free(hl); 64860786Sps return; 64960786Sps } 65060786Sps hl->hl_next = ihl->hl_next; 65160786Sps ihl->hl_next = hl; 65260786Sps} 65360786Sps 654161478Sdelphij static void 655161478Sdelphijadj_hilite_ansi(cvt_ops, line, npos) 656161478Sdelphij int cvt_ops; 657161478Sdelphij char **line; 658161478Sdelphij POSITION *npos; 659161478Sdelphij{ 660161478Sdelphij if (cvt_ops & CVT_ANSI) 661161478Sdelphij while (**line == ESC) 662161478Sdelphij { 663161478Sdelphij /* 664161478Sdelphij * Found an ESC. The file position moves 665161478Sdelphij * forward past the entire ANSI escape sequence. 666161478Sdelphij */ 667161478Sdelphij (*line)++; 668161478Sdelphij (*npos)++; 669161478Sdelphij while (**line != '\0') 670161478Sdelphij { 671161478Sdelphij (*npos)++; 672161478Sdelphij if (!is_ansi_middle(*(*line)++)) 673161478Sdelphij break; 674161478Sdelphij } 675161478Sdelphij } 676161478Sdelphij} 677161478Sdelphij 67860786Sps/* 67960786Sps * Adjust hl_startpos & hl_endpos to account for backspace processing. 68060786Sps */ 68160786Sps static void 682128348Stjradj_hilite(anchor, linepos, cvt_ops) 68360786Sps struct hilite *anchor; 68460786Sps POSITION linepos; 685128348Stjr int cvt_ops; 68660786Sps{ 68760786Sps char *line; 68860786Sps struct hilite *hl; 68960786Sps int checkstart; 69060786Sps POSITION opos; 69160786Sps POSITION npos; 69260786Sps 69360786Sps /* 69460786Sps * The line was already scanned and hilites were added (in hilite_line). 69560786Sps * But it was assumed that each char position in the line 69660786Sps * correponds to one char position in the file. 69760786Sps * This may not be true if there are backspaces in the line. 69860786Sps * Get the raw line again. Look at each character. 69960786Sps */ 70060786Sps (void) forw_raw_line(linepos, &line); 70160786Sps opos = npos = linepos; 70260786Sps hl = anchor->hl_first; 70360786Sps checkstart = TRUE; 70460786Sps while (hl != NULL) 70560786Sps { 70660786Sps /* 70760786Sps * See if we need to adjust the current hl_startpos or 70860786Sps * hl_endpos. After adjusting startpos[i], move to endpos[i]. 70960786Sps * After adjusting endpos[i], move to startpos[i+1]. 71060786Sps * The hilite list must be sorted thus: 71160786Sps * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc. 71260786Sps */ 71360786Sps if (checkstart && hl->hl_startpos == opos) 71460786Sps { 71560786Sps hl->hl_startpos = npos; 71660786Sps checkstart = FALSE; 71760786Sps continue; /* {{ not really necessary }} */ 71860786Sps } else if (!checkstart && hl->hl_endpos == opos) 71960786Sps { 72060786Sps hl->hl_endpos = npos; 72160786Sps checkstart = TRUE; 72260786Sps hl = hl->hl_next; 72360786Sps continue; /* {{ necessary }} */ 72460786Sps } 72560786Sps if (*line == '\0') 72660786Sps break; 727161478Sdelphij adj_hilite_ansi(cvt_ops, &line, &npos); 72860786Sps opos++; 72960786Sps npos++; 73060786Sps line++; 731128348Stjr if (cvt_ops & CVT_BS) 73260786Sps { 733161478Sdelphij while (*line == '\b') 734128348Stjr { 735161478Sdelphij npos++; 736161478Sdelphij line++; 737161478Sdelphij adj_hilite_ansi(cvt_ops, &line, &npos); 738161478Sdelphij if (*line == '\0') 739161478Sdelphij { 740161478Sdelphij --npos; 741161478Sdelphij --line; 742161478Sdelphij break; 743161478Sdelphij } 744128348Stjr /* 745128348Stjr * Found a backspace. The file position moves 746128348Stjr * forward by 2 relative to the processed line 747128348Stjr * which was searched in hilite_line. 748128348Stjr */ 749161478Sdelphij npos++; 750161478Sdelphij line++; 751128348Stjr } 75260786Sps } 75360786Sps } 75460786Sps} 75560786Sps 75660786Sps/* 75760786Sps * Make a hilite for each string in a physical line which matches 75860786Sps * the current pattern. 75960786Sps * sp,ep delimit the first match already found. 76060786Sps */ 76160786Sps static void 762128348Stjrhilite_line(linepos, line, sp, ep, cvt_ops) 76360786Sps POSITION linepos; 76460786Sps char *line; 76560786Sps char *sp; 76660786Sps char *ep; 767128348Stjr int cvt_ops; 76860786Sps{ 76960786Sps char *searchp; 77060786Sps struct hilite *hl; 77160786Sps struct hilite hilites; 77260786Sps 77360786Sps if (sp == NULL || ep == NULL) 77460786Sps return; 77560786Sps /* 77660786Sps * sp and ep delimit the first match in the line. 77760786Sps * Mark the corresponding file positions, then 77860786Sps * look for further matches and mark them. 77960786Sps * {{ This technique, of calling match_pattern on subsequent 78060786Sps * substrings of the line, may mark more than is correct 78160786Sps * if the pattern starts with "^". This bug is fixed 78260786Sps * for those regex functions that accept a notbol parameter 78360786Sps * (currently POSIX and V8-with-regexec2). }} 78460786Sps */ 78560786Sps searchp = line; 78660786Sps /* 78760786Sps * Put the hilites into a temporary list until they're adjusted. 78860786Sps */ 78960786Sps hilites.hl_first = NULL; 79060786Sps do { 79160786Sps if (ep > sp) 79260786Sps { 79360786Sps /* 79460786Sps * Assume that each char position in the "line" 79560786Sps * buffer corresponds to one char position in the file. 79660786Sps * This is not quite true; we need to adjust later. 79760786Sps */ 79860786Sps hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); 79960786Sps hl->hl_startpos = linepos + (sp-line); 80060786Sps hl->hl_endpos = linepos + (ep-line); 80160786Sps add_hilite(&hilites, hl); 80260786Sps } 80360786Sps /* 80460786Sps * If we matched more than zero characters, 80560786Sps * move to the first char after the string we matched. 80660786Sps * If we matched zero, just move to the next char. 80760786Sps */ 80860786Sps if (ep > searchp) 80960786Sps searchp = ep; 81060786Sps else if (*searchp != '\0') 81160786Sps searchp++; 81260786Sps else /* end of line */ 81360786Sps break; 81460786Sps } while (match_pattern(searchp, &sp, &ep, 1)); 81560786Sps 81660786Sps /* 817128348Stjr * If there were backspaces in the original line, they 818128348Stjr * were removed, and hl_startpos/hl_endpos are not correct. 819128348Stjr * {{ This is very ugly. }} 820128348Stjr */ 821128348Stjr adj_hilite(&hilites, linepos, cvt_ops); 822128348Stjr 823128348Stjr /* 82460786Sps * Now put the hilites into the real list. 82560786Sps */ 82660786Sps while ((hl = hilites.hl_next) != NULL) 82760786Sps { 82860786Sps hilites.hl_next = hl->hl_next; 82960786Sps add_hilite(&hilite_anchor, hl); 83060786Sps } 83160786Sps} 83260786Sps#endif 83360786Sps 83460786Sps/* 83560786Sps * Change the caseless-ness of searches. 83660786Sps * Updates the internal search state to reflect a change in the -i flag. 83760786Sps */ 83860786Sps public void 83960786Spschg_caseless() 84060786Sps{ 84160786Sps if (!is_ucase_pattern) 84260786Sps /* 84360786Sps * Pattern did not have uppercase. 84460786Sps * Just set the search caselessness to the global caselessness. 84560786Sps */ 84660786Sps is_caseless = caseless; 84760786Sps else 84860786Sps /* 84960786Sps * Pattern did have uppercase. 85060786Sps * Discard the pattern; we can't change search caselessness now. 85160786Sps */ 85260786Sps uncompile_pattern(); 85360786Sps} 85460786Sps 85560786Sps#if HILITE_SEARCH 85660786Sps/* 85760786Sps * Find matching text which is currently on screen and highlight it. 85860786Sps */ 85960786Sps static void 86060786Spshilite_screen() 86160786Sps{ 86260786Sps struct scrpos scrpos; 86360786Sps 86460786Sps get_scrpos(&scrpos); 86560786Sps if (scrpos.pos == NULL_POSITION) 86660786Sps return; 86760786Sps prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); 86860786Sps repaint_hilite(1); 86960786Sps} 87060786Sps 87160786Sps/* 87260786Sps * Change highlighting parameters. 87360786Sps */ 87460786Sps public void 87560786Spschg_hilite() 87660786Sps{ 87760786Sps /* 87860786Sps * Erase any highlights currently on screen. 87960786Sps */ 88060786Sps clr_hilite(); 88160786Sps hide_hilite = 0; 88260786Sps 88360786Sps if (hilite_search == OPT_ONPLUS) 88460786Sps /* 88560786Sps * Display highlights. 88660786Sps */ 88760786Sps hilite_screen(); 88860786Sps} 88960786Sps#endif 89060786Sps 89160786Sps/* 89260786Sps * Figure out where to start a search. 89360786Sps */ 89460786Sps static POSITION 89560786Spssearch_pos(search_type) 89660786Sps int search_type; 89760786Sps{ 89860786Sps POSITION pos; 89960786Sps int linenum; 90060786Sps 90160786Sps if (empty_screen()) 90260786Sps { 90360786Sps /* 90460786Sps * Start at the beginning (or end) of the file. 90560786Sps * The empty_screen() case is mainly for 90660786Sps * command line initiated searches; 90760786Sps * for example, "+/xyz" on the command line. 90860786Sps * Also for multi-file (SRCH_PAST_EOF) searches. 90960786Sps */ 91060786Sps if (search_type & SRCH_FORW) 91160786Sps { 91260786Sps return (ch_zero()); 91360786Sps } else 91460786Sps { 91560786Sps pos = ch_length(); 91660786Sps if (pos == NULL_POSITION) 91760786Sps { 91860786Sps (void) ch_end_seek(); 91960786Sps pos = ch_length(); 92060786Sps } 92160786Sps return (pos); 92260786Sps } 92360786Sps } 92460786Sps if (how_search) 92560786Sps { 92660786Sps /* 92760786Sps * Search does not include current screen. 92860786Sps */ 92960786Sps if (search_type & SRCH_FORW) 93060786Sps linenum = BOTTOM_PLUS_ONE; 93160786Sps else 93260786Sps linenum = TOP; 93360786Sps pos = position(linenum); 93460786Sps } else 93560786Sps { 93660786Sps /* 93760786Sps * Search includes current screen. 93860786Sps * It starts at the jump target (if searching backwards), 93960786Sps * or at the jump target plus one (if forwards). 94060786Sps */ 94160786Sps linenum = adjsline(jump_sline); 94260786Sps pos = position(linenum); 94360786Sps if (search_type & SRCH_FORW) 94460786Sps { 94560786Sps pos = forw_raw_line(pos, (char **)NULL); 94660786Sps while (pos == NULL_POSITION) 94760786Sps { 94860786Sps if (++linenum >= sc_height) 94960786Sps break; 95060786Sps pos = position(linenum); 95160786Sps } 95260786Sps } else 95360786Sps { 95460786Sps while (pos == NULL_POSITION) 95560786Sps { 95660786Sps if (--linenum < 0) 95760786Sps break; 95860786Sps pos = position(linenum); 95960786Sps } 96060786Sps } 96160786Sps } 96260786Sps return (pos); 96360786Sps} 96460786Sps 96560786Sps/* 96660786Sps * Search a subset of the file, specified by start/end position. 96760786Sps */ 96860786Sps static int 96960786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) 97060786Sps POSITION pos; 97160786Sps POSITION endpos; 97260786Sps int search_type; 97360786Sps int matches; 97460786Sps int maxlines; 97560786Sps POSITION *plinepos; 97660786Sps POSITION *pendpos; 97760786Sps{ 97860786Sps char *line; 979128348Stjr LINENUM linenum; 98060786Sps char *sp, *ep; 98160786Sps int line_match; 982128348Stjr int cvt_ops; 98360786Sps POSITION linepos, oldpos; 98460786Sps 98560786Sps linenum = find_linenum(pos); 98660786Sps oldpos = pos; 98760786Sps for (;;) 98860786Sps { 98960786Sps /* 99060786Sps * Get lines until we find a matching one or until 99160786Sps * we hit end-of-file (or beginning-of-file if we're 99260786Sps * going backwards), or until we hit the end position. 99360786Sps */ 99460786Sps if (ABORT_SIGS()) 99560786Sps { 99660786Sps /* 99760786Sps * A signal aborts the search. 99860786Sps */ 99960786Sps return (-1); 100060786Sps } 100160786Sps 100260786Sps if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) 100360786Sps { 100460786Sps /* 100560786Sps * Reached end position without a match. 100660786Sps */ 100760786Sps if (pendpos != NULL) 100860786Sps *pendpos = pos; 100960786Sps return (matches); 101060786Sps } 101160786Sps if (maxlines > 0) 101260786Sps maxlines--; 101360786Sps 101460786Sps if (search_type & SRCH_FORW) 101560786Sps { 101660786Sps /* 101760786Sps * Read the next line, and save the 101860786Sps * starting position of that line in linepos. 101960786Sps */ 102060786Sps linepos = pos; 102160786Sps pos = forw_raw_line(pos, &line); 102260786Sps if (linenum != 0) 102360786Sps linenum++; 102460786Sps } else 102560786Sps { 102660786Sps /* 102760786Sps * Read the previous line and save the 102860786Sps * starting position of that line in linepos. 102960786Sps */ 103060786Sps pos = back_raw_line(pos, &line); 103160786Sps linepos = pos; 103260786Sps if (linenum != 0) 103360786Sps linenum--; 103460786Sps } 103560786Sps 103660786Sps if (pos == NULL_POSITION) 103760786Sps { 103860786Sps /* 103960786Sps * Reached EOF/BOF without a match. 104060786Sps */ 104160786Sps if (pendpos != NULL) 104260786Sps *pendpos = oldpos; 104360786Sps return (matches); 104460786Sps } 104560786Sps 104660786Sps /* 104760786Sps * If we're using line numbers, we might as well 104860786Sps * remember the information we have now (the position 104960786Sps * and line number of the current line). 105060786Sps * Don't do it for every line because it slows down 105160786Sps * the search. Remember the line number only if 105260786Sps * we're "far" from the last place we remembered it. 105360786Sps */ 105460786Sps if (linenums && abs((int)(pos - oldpos)) > 1024) 105560786Sps add_lnum(linenum, pos); 105660786Sps oldpos = pos; 105760786Sps 105860786Sps /* 105960786Sps * If it's a caseless search, convert the line to lowercase. 106060786Sps * If we're doing backspace processing, delete backspaces. 106160786Sps */ 1062128348Stjr cvt_ops = get_cvt_ops(); 1063128348Stjr cvt_text(line, line, cvt_ops); 106460786Sps 106560786Sps /* 106660786Sps * Test the next line to see if we have a match. 106760786Sps * We are successful if we either want a match and got one, 106860786Sps * or if we want a non-match and got one. 106960786Sps */ 107060786Sps line_match = match_pattern(line, &sp, &ep, 0); 107160786Sps line_match = (!(search_type & SRCH_NO_MATCH) && line_match) || 107260786Sps ((search_type & SRCH_NO_MATCH) && !line_match); 107360786Sps if (!line_match) 107460786Sps continue; 107560786Sps /* 107660786Sps * Got a match. 107760786Sps */ 107860786Sps if (search_type & SRCH_FIND_ALL) 107960786Sps { 108060786Sps#if HILITE_SEARCH 108160786Sps /* 108260786Sps * We are supposed to find all matches in the range. 108360786Sps * Just add the matches in this line to the 108460786Sps * hilite list and keep searching. 108560786Sps */ 108660786Sps if (line_match) 1087128348Stjr hilite_line(linepos, line, sp, ep, cvt_ops); 108860786Sps#endif 108960786Sps } else if (--matches <= 0) 109060786Sps { 109160786Sps /* 109260786Sps * Found the one match we're looking for. 109360786Sps * Return it. 109460786Sps */ 109560786Sps#if HILITE_SEARCH 1096161478Sdelphij if (hilite_search == OPT_ON) 109760786Sps { 109860786Sps /* 109960786Sps * Clear the hilite list and add only 110060786Sps * the matches in this one line. 110160786Sps */ 110260786Sps clr_hilite(); 110360786Sps if (line_match) 1104128348Stjr hilite_line(linepos, line, sp, ep, cvt_ops); 110560786Sps } 110660786Sps#endif 110760786Sps if (plinepos != NULL) 110860786Sps *plinepos = linepos; 110960786Sps return (0); 111060786Sps } 111160786Sps } 111260786Sps} 111360786Sps 111460786Sps/* 111560786Sps * Search for the n-th occurrence of a specified pattern, 111660786Sps * either forward or backward. 111760786Sps * Return the number of matches not yet found in this file 111860786Sps * (that is, n minus the number of matches found). 111960786Sps * Return -1 if the search should be aborted. 112060786Sps * Caller may continue the search in another file 112160786Sps * if less than n matches are found in this file. 112260786Sps */ 112360786Sps public int 112460786Spssearch(search_type, pattern, n) 112560786Sps int search_type; 112660786Sps char *pattern; 112760786Sps int n; 112860786Sps{ 112960786Sps POSITION pos; 113060786Sps int ucase; 113160786Sps 113260786Sps if (pattern == NULL || *pattern == '\0') 113360786Sps { 113460786Sps /* 113560786Sps * A null pattern means use the previously compiled pattern. 113660786Sps */ 113760786Sps if (!prev_pattern()) 113860786Sps { 113960786Sps error("No previous regular expression", NULL_PARG); 114060786Sps return (-1); 114160786Sps } 114260786Sps if ((search_type & SRCH_NO_REGEX) != 114360786Sps (last_search_type & SRCH_NO_REGEX)) 114460786Sps { 114560786Sps error("Please re-enter search pattern", NULL_PARG); 114660786Sps return -1; 114760786Sps } 114860786Sps#if HILITE_SEARCH 114960786Sps if (hilite_search == OPT_ON) 115060786Sps { 115160786Sps /* 115260786Sps * Erase the highlights currently on screen. 115360786Sps * If the search fails, we'll redisplay them later. 115460786Sps */ 115560786Sps repaint_hilite(0); 115660786Sps } 115760786Sps if (hilite_search == OPT_ONPLUS && hide_hilite) 115860786Sps { 115960786Sps /* 116060786Sps * Highlight any matches currently on screen, 116160786Sps * before we actually start the search. 116260786Sps */ 116360786Sps hide_hilite = 0; 116460786Sps hilite_screen(); 116560786Sps } 116660786Sps hide_hilite = 0; 116760786Sps#endif 116860786Sps } else 116960786Sps { 117060786Sps /* 117160786Sps * Compile the pattern. 117260786Sps */ 117360786Sps ucase = is_ucase(pattern); 117460786Sps if (caseless == OPT_ONPLUS) 117560786Sps cvt_text(pattern, pattern, CVT_TO_LC); 117660786Sps if (compile_pattern(pattern, search_type) < 0) 117760786Sps return (-1); 117860786Sps /* 117960786Sps * Ignore case if -I is set OR 118060786Sps * -i is set AND the pattern is all lowercase. 118160786Sps */ 118260786Sps is_ucase_pattern = ucase; 118360786Sps if (is_ucase_pattern && caseless != OPT_ONPLUS) 118460786Sps is_caseless = 0; 118560786Sps else 118660786Sps is_caseless = caseless; 118760786Sps#if HILITE_SEARCH 118860786Sps if (hilite_search) 118960786Sps { 119060786Sps /* 119160786Sps * Erase the highlights currently on screen. 119260786Sps * Also permanently delete them from the hilite list. 119360786Sps */ 119460786Sps repaint_hilite(0); 119560786Sps hide_hilite = 0; 119660786Sps clr_hilite(); 119760786Sps } 119860786Sps if (hilite_search == OPT_ONPLUS) 119960786Sps { 120060786Sps /* 120160786Sps * Highlight any matches currently on screen, 120260786Sps * before we actually start the search. 120360786Sps */ 120460786Sps hilite_screen(); 120560786Sps } 120660786Sps#endif 120760786Sps } 120860786Sps 120960786Sps /* 121060786Sps * Figure out where to start the search. 121160786Sps */ 121260786Sps pos = search_pos(search_type); 121360786Sps if (pos == NULL_POSITION) 121460786Sps { 121560786Sps /* 121660786Sps * Can't find anyplace to start searching from. 121760786Sps */ 121860786Sps if (search_type & SRCH_PAST_EOF) 121960786Sps return (n); 122060786Sps /* repaint(); -- why was this here? */ 122160786Sps error("Nothing to search", NULL_PARG); 122260786Sps return (-1); 122360786Sps } 122460786Sps 122560786Sps n = search_range(pos, NULL_POSITION, search_type, n, -1, 122660786Sps &pos, (POSITION*)NULL); 122760786Sps if (n != 0) 122860786Sps { 122960786Sps /* 123060786Sps * Search was unsuccessful. 123160786Sps */ 123260786Sps#if HILITE_SEARCH 123360786Sps if (hilite_search == OPT_ON && n > 0) 123460786Sps /* 123560786Sps * Redisplay old hilites. 123660786Sps */ 123760786Sps repaint_hilite(1); 123860786Sps#endif 123960786Sps return (n); 124060786Sps } 124160786Sps 124260786Sps if (!(search_type & SRCH_NO_MOVE)) 124360786Sps { 124460786Sps /* 124560786Sps * Go to the matching line. 124660786Sps */ 124760786Sps jump_loc(pos, jump_sline); 124860786Sps } 124960786Sps 125060786Sps#if HILITE_SEARCH 125160786Sps if (hilite_search == OPT_ON) 125260786Sps /* 125360786Sps * Display new hilites in the matching line. 125460786Sps */ 125560786Sps repaint_hilite(1); 125660786Sps#endif 125760786Sps return (0); 125860786Sps} 125960786Sps 126060786Sps 126160786Sps#if HILITE_SEARCH 126260786Sps/* 126360786Sps * Prepare hilites in a given range of the file. 126460786Sps * 126560786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region 126660786Sps * of the file that has been "prepared"; that is, scanned for matches for 126760786Sps * the current search pattern, and hilites have been created for such matches. 126860786Sps * If prep_startpos == NULL_POSITION, the prep region is empty. 126960786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF. 127060786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region. 127160786Sps */ 127260786Sps public void 127360786Spsprep_hilite(spos, epos, maxlines) 127460786Sps POSITION spos; 127560786Sps POSITION epos; 127660786Sps int maxlines; 127760786Sps{ 127860786Sps POSITION nprep_startpos = prep_startpos; 127960786Sps POSITION nprep_endpos = prep_endpos; 128060786Sps POSITION new_epos; 128160786Sps POSITION max_epos; 128260786Sps int result; 128360786Sps int i; 128460786Sps/* 128560786Sps * Search beyond where we're asked to search, so the prep region covers 128660786Sps * more than we need. Do one big search instead of a bunch of small ones. 128760786Sps */ 128860786Sps#define SEARCH_MORE (3*size_linebuf) 128960786Sps 129060786Sps if (!prev_pattern()) 129160786Sps return; 129260786Sps 129360786Sps /* 129460786Sps * If we're limited to a max number of lines, figure out the 129560786Sps * file position we should stop at. 129660786Sps */ 129760786Sps if (maxlines < 0) 129860786Sps max_epos = NULL_POSITION; 129960786Sps else 130060786Sps { 130160786Sps max_epos = spos; 130260786Sps for (i = 0; i < maxlines; i++) 130360786Sps max_epos = forw_raw_line(max_epos, (char **)NULL); 130460786Sps } 130560786Sps 130660786Sps /* 130760786Sps * Find two ranges: 130860786Sps * The range that we need to search (spos,epos); and the range that 130960786Sps * the "prep" region will then cover (nprep_startpos,nprep_endpos). 131060786Sps */ 131160786Sps 131260786Sps if (prep_startpos == NULL_POSITION || 131360786Sps (epos != NULL_POSITION && epos < prep_startpos) || 131460786Sps spos > prep_endpos) 131560786Sps { 131660786Sps /* 131760786Sps * New range is not contiguous with old prep region. 131860786Sps * Discard the old prep region and start a new one. 131960786Sps */ 132060786Sps clr_hilite(); 132160786Sps if (epos != NULL_POSITION) 132260786Sps epos += SEARCH_MORE; 132360786Sps nprep_startpos = spos; 132460786Sps } else 132560786Sps { 132660786Sps /* 132760786Sps * New range partially or completely overlaps old prep region. 132860786Sps */ 132960786Sps if (epos == NULL_POSITION) 133060786Sps { 133160786Sps /* 133260786Sps * New range goes to end of file. 133360786Sps */ 133460786Sps ; 133560786Sps } else if (epos > prep_endpos) 133660786Sps { 133760786Sps /* 133860786Sps * New range ends after old prep region. 133960786Sps * Extend prep region to end at end of new range. 134060786Sps */ 134160786Sps epos += SEARCH_MORE; 134260786Sps } else /* (epos <= prep_endpos) */ 134360786Sps { 134460786Sps /* 134560786Sps * New range ends within old prep region. 134660786Sps * Truncate search to end at start of old prep region. 134760786Sps */ 134860786Sps epos = prep_startpos; 134960786Sps } 135060786Sps 135160786Sps if (spos < prep_startpos) 135260786Sps { 135360786Sps /* 135460786Sps * New range starts before old prep region. 135560786Sps * Extend old prep region backwards to start at 135660786Sps * start of new range. 135760786Sps */ 135860786Sps if (spos < SEARCH_MORE) 135960786Sps spos = 0; 136060786Sps else 136160786Sps spos -= SEARCH_MORE; 136260786Sps nprep_startpos = spos; 136360786Sps } else /* (spos >= prep_startpos) */ 136460786Sps { 136560786Sps /* 136660786Sps * New range starts within or after old prep region. 136760786Sps * Trim search to start at end of old prep region. 136860786Sps */ 136960786Sps spos = prep_endpos; 137060786Sps } 137160786Sps } 137260786Sps 137360786Sps if (epos != NULL_POSITION && max_epos != NULL_POSITION && 137460786Sps epos > max_epos) 137560786Sps /* 137660786Sps * Don't go past the max position we're allowed. 137760786Sps */ 137860786Sps epos = max_epos; 137960786Sps 138060786Sps if (epos == NULL_POSITION || epos > spos) 138160786Sps { 138260786Sps result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, 138360786Sps maxlines, (POSITION*)NULL, &new_epos); 138460786Sps if (result < 0) 138560786Sps return; 138660786Sps if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 138760786Sps nprep_endpos = new_epos; 138860786Sps } 138960786Sps prep_startpos = nprep_startpos; 139060786Sps prep_endpos = nprep_endpos; 139160786Sps} 139260786Sps#endif 139360786Sps 139460786Sps/* 139560786Sps * Simple pattern matching function. 139660786Sps * It supports no metacharacters like *, etc. 139760786Sps */ 139860786Sps static int 139960786Spsmatch(pattern, buf, pfound, pend) 140060786Sps char *pattern, *buf; 140160786Sps char **pfound, **pend; 140260786Sps{ 140360786Sps register char *pp, *lp; 140460786Sps 140560786Sps for ( ; *buf != '\0'; buf++) 140660786Sps { 140760786Sps for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) 140860786Sps if (*pp == '\0' || *lp == '\0') 140960786Sps break; 141060786Sps if (*pp == '\0') 141160786Sps { 141260786Sps if (pfound != NULL) 141360786Sps *pfound = buf; 141460786Sps if (pend != NULL) 141560786Sps *pend = lp; 141660786Sps return (1); 141760786Sps } 141860786Sps } 141960786Sps return (0); 142060786Sps} 142160786Sps 142260786Sps#if HAVE_V8_REGCOMP 142360786Sps/* 142460786Sps * This function is called by the V8 regcomp to report 142560786Sps * errors in regular expressions. 142660786Sps */ 142760786Sps void 142860786Spsregerror(s) 142960786Sps char *s; 143060786Sps{ 143160786Sps PARG parg; 143260786Sps 143360786Sps parg.p_string = s; 143460786Sps error("%s", &parg); 143560786Sps} 143660786Sps#endif 143760786Sps 1438