search.c revision 128348
160812Sps/* $FreeBSD: head/contrib/less/search.c 128348 2004-04-17 07:24:09Z tjr $ */ 260786Sps/* 3128348Stjr * Copyright (C) 1984-2002 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 { 12560786Sps if ((ops & CVT_TO_LC) && isupper((unsigned char) *src)) 12660786Sps /* Convert uppercase to lowercase. */ 127128348Stjr *dst++ = tolower((unsigned char) *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') 135128348Stjr if (is_ansi_end(*++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++) 18060786Sps if (isupper((unsigned char) *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); 25260786Sps /* 25360786Sps * If any character in the line is highlighted, 25460786Sps * repaint the line. 25560786Sps */ 25660786Sps if (is_hilited(pos, epos, 1)) 25760786Sps { 25860786Sps (void) forw_line(pos); 25960786Sps goto_line(slinenum); 26060786Sps put_line(); 26160786Sps } 26260786Sps } 26360786Sps hide_hilite = save_hide_hilite; 26460786Sps} 26560786Sps 26660786Sps/* 26760786Sps * Clear the attn hilite. 26860786Sps */ 26960786Sps public void 27060786Spsclear_attn() 27160786Sps{ 27260786Sps int slinenum; 27360786Sps POSITION old_start_attnpos; 27460786Sps POSITION old_end_attnpos; 27560786Sps POSITION pos; 27660786Sps POSITION epos; 27760786Sps 27860786Sps if (start_attnpos == NULL_POSITION) 27960786Sps return; 28060786Sps old_start_attnpos = start_attnpos; 28160786Sps old_end_attnpos = end_attnpos; 28260786Sps start_attnpos = end_attnpos = NULL_POSITION; 28360786Sps 28460786Sps if (!can_goto_line) 28560786Sps { 28660786Sps repaint(); 28760786Sps return; 28860786Sps } 28960786Sps if (squished) 29060786Sps repaint(); 29160786Sps 29260786Sps for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) 29360786Sps { 29460786Sps pos = position(slinenum); 29560786Sps if (pos == NULL_POSITION) 29660786Sps continue; 29760786Sps epos = position(slinenum+1); 29860786Sps if (pos < old_end_attnpos && 29960786Sps (epos == NULL_POSITION || epos > old_start_attnpos)) 30060786Sps { 30160786Sps (void) forw_line(pos); 30260786Sps goto_line(slinenum); 30360786Sps put_line(); 30460786Sps } 30560786Sps } 30660786Sps} 30760786Sps#endif 30860786Sps 30960786Sps/* 31060786Sps * Hide search string highlighting. 31160786Sps */ 31260786Sps public void 31360786Spsundo_search() 31460786Sps{ 31560786Sps if (!prev_pattern()) 31660786Sps { 31760786Sps error("No previous regular expression", NULL_PARG); 31860786Sps return; 31960786Sps } 32060786Sps#if HILITE_SEARCH 32160786Sps hide_hilite = !hide_hilite; 32260786Sps repaint_hilite(1); 32360786Sps#endif 32460786Sps} 32560786Sps 32660786Sps/* 32760786Sps * Compile a search pattern, for future use by match_pattern. 32860786Sps */ 32960786Sps static int 33060786Spscompile_pattern(pattern, search_type) 33160786Sps char *pattern; 33260786Sps int search_type; 33360786Sps{ 33460786Sps if ((search_type & SRCH_NO_REGEX) == 0) 33560786Sps { 33660786Sps#if HAVE_POSIX_REGCOMP 33760786Sps regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t)); 33860786Sps if (regcomp(s, pattern, REGCOMP_FLAG)) 33960786Sps { 34060786Sps free(s); 34160786Sps error("Invalid pattern", NULL_PARG); 34260786Sps return (-1); 34360786Sps } 34460786Sps if (regpattern != NULL) 34560786Sps regfree(regpattern); 34660786Sps regpattern = s; 34760786Sps#endif 34860786Sps#if HAVE_PCRE 34960786Sps pcre *comp; 35060786Sps const char *errstring; 35160786Sps int erroffset; 35260786Sps PARG parg; 35360786Sps comp = pcre_compile(pattern, 0, 35460786Sps &errstring, &erroffset, NULL); 35560786Sps if (comp == NULL) 35660786Sps { 35760786Sps parg.p_string = (char *) errstring; 35860786Sps error("%s", &parg); 35960786Sps return (-1); 36060786Sps } 36160786Sps regpattern = comp; 36260786Sps#endif 36360786Sps#if HAVE_RE_COMP 36460786Sps PARG parg; 36560786Sps if ((parg.p_string = re_comp(pattern)) != NULL) 36660786Sps { 36760786Sps error("%s", &parg); 36860786Sps return (-1); 36960786Sps } 37060786Sps re_pattern = 1; 37160786Sps#endif 37260786Sps#if HAVE_REGCMP 37360786Sps char *s; 37460786Sps if ((s = regcmp(pattern, 0)) == NULL) 37560786Sps { 37660786Sps error("Invalid pattern", NULL_PARG); 37760786Sps return (-1); 37860786Sps } 37960786Sps if (cpattern != NULL) 38060786Sps free(cpattern); 38160786Sps cpattern = s; 38260786Sps#endif 38360786Sps#if HAVE_V8_REGCOMP 38460786Sps struct regexp *s; 38560786Sps if ((s = regcomp(pattern)) == NULL) 38660786Sps { 38760786Sps /* 38860786Sps * regcomp has already printed an error message 38960786Sps * via regerror(). 39060786Sps */ 39160786Sps return (-1); 39260786Sps } 39360786Sps if (regpattern != NULL) 39460786Sps free(regpattern); 39560786Sps regpattern = s; 39660786Sps#endif 39760786Sps } 39860786Sps 39960786Sps if (last_pattern != NULL) 40060786Sps free(last_pattern); 40160786Sps last_pattern = (char *) calloc(1, strlen(pattern)+1); 40260786Sps if (last_pattern != NULL) 40360786Sps strcpy(last_pattern, pattern); 40460786Sps 40560786Sps last_search_type = search_type; 40660786Sps return (0); 40760786Sps} 40860786Sps 40960786Sps/* 41060786Sps * Forget that we have a compiled pattern. 41160786Sps */ 41260786Sps static void 41360786Spsuncompile_pattern() 41460786Sps{ 41560786Sps#if HAVE_POSIX_REGCOMP 41660786Sps if (regpattern != NULL) 41760786Sps regfree(regpattern); 41860786Sps regpattern = NULL; 41960786Sps#endif 42060786Sps#if HAVE_PCRE 42160786Sps if (regpattern != NULL) 42260786Sps pcre_free(regpattern); 42360786Sps regpattern = NULL; 42460786Sps#endif 42560786Sps#if HAVE_RE_COMP 42660786Sps re_pattern = 0; 42760786Sps#endif 42860786Sps#if HAVE_REGCMP 42960786Sps if (cpattern != NULL) 43060786Sps free(cpattern); 43160786Sps cpattern = NULL; 43260786Sps#endif 43360786Sps#if HAVE_V8_REGCOMP 43460786Sps if (regpattern != NULL) 43560786Sps free(regpattern); 43660786Sps regpattern = NULL; 43760786Sps#endif 43860786Sps last_pattern = NULL; 43960786Sps} 44060786Sps 44160786Sps/* 44260786Sps * Perform a pattern match with the previously compiled pattern. 44360786Sps * Set sp and ep to the start and end of the matched string. 44460786Sps */ 44560786Sps static int 44660786Spsmatch_pattern(line, sp, ep, notbol) 44760786Sps char *line; 44860786Sps char **sp; 44960786Sps char **ep; 45060786Sps int notbol; 45160786Sps{ 45260786Sps int matched; 45360786Sps 45460786Sps if (last_search_type & SRCH_NO_REGEX) 45560786Sps return (match(last_pattern, line, sp, ep)); 45660786Sps 45760786Sps#if HAVE_POSIX_REGCOMP 45860786Sps { 45960786Sps regmatch_t rm; 46060786Sps int flags = (notbol) ? REG_NOTBOL : 0; 46160786Sps matched = !regexec(regpattern, line, 1, &rm, flags); 46260786Sps if (!matched) 46360786Sps return (0); 46460786Sps#ifndef __WATCOMC__ 46560786Sps *sp = line + rm.rm_so; 46660786Sps *ep = line + rm.rm_eo; 46760786Sps#else 46860786Sps *sp = rm.rm_sp; 46960786Sps *ep = rm.rm_ep; 47060786Sps#endif 47160786Sps } 47260786Sps#endif 47360786Sps#if HAVE_PCRE 47460786Sps { 47560786Sps int flags = (notbol) ? PCRE_NOTBOL : 0; 47660786Sps int ovector[3]; 47760786Sps matched = pcre_exec(regpattern, NULL, line, strlen(line), 47860786Sps 0, flags, ovector, 3) >= 0; 47960786Sps if (!matched) 48060786Sps return (0); 48160786Sps *sp = line + ovector[0]; 48260786Sps *ep = line + ovector[1]; 48360786Sps } 48460786Sps#endif 48560786Sps#if HAVE_RE_COMP 48660786Sps matched = (re_exec(line) == 1); 48760786Sps /* 48860786Sps * re_exec doesn't seem to provide a way to get the matched string. 48960786Sps */ 49060786Sps *sp = *ep = NULL; 49160786Sps#endif 49260786Sps#if HAVE_REGCMP 49360786Sps *ep = regex(cpattern, line); 49460786Sps matched = (*ep != NULL); 49560786Sps if (!matched) 49660786Sps return (0); 49760786Sps *sp = __loc1; 49860786Sps#endif 49960786Sps#if HAVE_V8_REGCOMP 50060786Sps#if HAVE_REGEXEC2 50160786Sps matched = regexec2(regpattern, line, notbol); 50260786Sps#else 50360786Sps matched = regexec(regpattern, line); 50460786Sps#endif 50560786Sps if (!matched) 50660786Sps return (0); 50760786Sps *sp = regpattern->startp[0]; 50860786Sps *ep = regpattern->endp[0]; 50960786Sps#endif 51060786Sps#if NO_REGEX 51160786Sps matched = match(last_pattern, line, sp, ep); 51260786Sps#endif 51360786Sps return (matched); 51460786Sps} 51560786Sps 51660786Sps#if HILITE_SEARCH 51760786Sps/* 51860786Sps * Clear the hilite list. 51960786Sps */ 52060786Sps public void 52160786Spsclr_hilite() 52260786Sps{ 52360786Sps struct hilite *hl; 52460786Sps struct hilite *nexthl; 52560786Sps 52660786Sps for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl) 52760786Sps { 52860786Sps nexthl = hl->hl_next; 52960786Sps free((void*)hl); 53060786Sps } 53160786Sps hilite_anchor.hl_first = NULL; 53260786Sps prep_startpos = prep_endpos = NULL_POSITION; 53360786Sps} 53460786Sps 53560786Sps/* 53660786Sps * Should any characters in a specified range be highlighted? 53760786Sps * If nohide is nonzero, don't consider hide_hilite. 53860786Sps */ 53960786Sps public int 54060786Spsis_hilited(pos, epos, nohide) 54160786Sps POSITION pos; 54260786Sps POSITION epos; 54360786Sps int nohide; 54460786Sps{ 54560786Sps struct hilite *hl; 54660786Sps 54763131Sps if (!status_col && 54863131Sps start_attnpos != NULL_POSITION && 54960786Sps pos < end_attnpos && 55060786Sps (epos == NULL_POSITION || epos > start_attnpos)) 55160786Sps /* 55260786Sps * The attn line overlaps this range. 55360786Sps */ 55460786Sps return (1); 55560786Sps 55660786Sps if (hilite_search == 0) 55760786Sps /* 55860786Sps * Not doing highlighting. 55960786Sps */ 56060786Sps return (0); 56160786Sps 56260786Sps if (!nohide && hide_hilite) 56360786Sps /* 56460786Sps * Highlighting is hidden. 56560786Sps */ 56660786Sps return (0); 56760786Sps 56860786Sps /* 56960786Sps * Look at each highlight and see if any part of it falls in the range. 57060786Sps */ 57160786Sps for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next) 57260786Sps { 57360786Sps if (hl->hl_endpos > pos && 57460786Sps (epos == NULL_POSITION || epos > hl->hl_startpos)) 57560786Sps return (1); 57660786Sps } 57760786Sps return (0); 57860786Sps} 57960786Sps 58060786Sps/* 58160786Sps * Add a new hilite to a hilite list. 58260786Sps */ 58360786Sps static void 58460786Spsadd_hilite(anchor, hl) 58560786Sps struct hilite *anchor; 58660786Sps struct hilite *hl; 58760786Sps{ 58860786Sps struct hilite *ihl; 58960786Sps 59060786Sps /* 59160786Sps * Hilites are sorted in the list; find where new one belongs. 59260786Sps * Insert new one after ihl. 59360786Sps */ 59460786Sps for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next) 59560786Sps { 59660786Sps if (ihl->hl_next->hl_startpos > hl->hl_startpos) 59760786Sps break; 59860786Sps } 59960786Sps 60060786Sps /* 60160786Sps * Truncate hilite so it doesn't overlap any existing ones 60260786Sps * above and below it. 60360786Sps */ 60460786Sps if (ihl != anchor) 60560786Sps hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos); 60660786Sps if (ihl->hl_next != NULL) 60760786Sps hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos); 60860786Sps if (hl->hl_startpos >= hl->hl_endpos) 60960786Sps { 61060786Sps /* 61160786Sps * Hilite was truncated out of existence. 61260786Sps */ 61360786Sps free(hl); 61460786Sps return; 61560786Sps } 61660786Sps hl->hl_next = ihl->hl_next; 61760786Sps ihl->hl_next = hl; 61860786Sps} 61960786Sps 62060786Sps/* 62160786Sps * Adjust hl_startpos & hl_endpos to account for backspace processing. 62260786Sps */ 62360786Sps static void 624128348Stjradj_hilite(anchor, linepos, cvt_ops) 62560786Sps struct hilite *anchor; 62660786Sps POSITION linepos; 627128348Stjr int cvt_ops; 62860786Sps{ 62960786Sps char *line; 63060786Sps struct hilite *hl; 63160786Sps int checkstart; 63260786Sps POSITION opos; 63360786Sps POSITION npos; 63460786Sps 63560786Sps /* 63660786Sps * The line was already scanned and hilites were added (in hilite_line). 63760786Sps * But it was assumed that each char position in the line 63860786Sps * correponds to one char position in the file. 63960786Sps * This may not be true if there are backspaces in the line. 64060786Sps * Get the raw line again. Look at each character. 64160786Sps */ 64260786Sps (void) forw_raw_line(linepos, &line); 64360786Sps opos = npos = linepos; 64460786Sps hl = anchor->hl_first; 64560786Sps checkstart = TRUE; 64660786Sps while (hl != NULL) 64760786Sps { 64860786Sps /* 64960786Sps * See if we need to adjust the current hl_startpos or 65060786Sps * hl_endpos. After adjusting startpos[i], move to endpos[i]. 65160786Sps * After adjusting endpos[i], move to startpos[i+1]. 65260786Sps * The hilite list must be sorted thus: 65360786Sps * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc. 65460786Sps */ 65560786Sps if (checkstart && hl->hl_startpos == opos) 65660786Sps { 65760786Sps hl->hl_startpos = npos; 65860786Sps checkstart = FALSE; 65960786Sps continue; /* {{ not really necessary }} */ 66060786Sps } else if (!checkstart && hl->hl_endpos == opos) 66160786Sps { 66260786Sps hl->hl_endpos = npos; 66360786Sps checkstart = TRUE; 66460786Sps hl = hl->hl_next; 66560786Sps continue; /* {{ necessary }} */ 66660786Sps } 66760786Sps if (*line == '\0') 66860786Sps break; 669128348Stjr if (cvt_ops & CVT_ANSI) 670128348Stjr { 671128348Stjr while (line[0] == ESC) 672128348Stjr { 673128348Stjr /* 674128348Stjr * Found an ESC. The file position moves 675128348Stjr * forward past the entire ANSI escape sequence. 676128348Stjr */ 677128348Stjr line++; 678128348Stjr npos++; 679128348Stjr while (*line != '\0') 680128348Stjr { 681128348Stjr npos++; 682128348Stjr if (is_ansi_end(*line++)) 683128348Stjr break; 684128348Stjr } 685128348Stjr } 686128348Stjr } 68760786Sps opos++; 68860786Sps npos++; 68960786Sps line++; 690128348Stjr if (cvt_ops & CVT_BS) 69160786Sps { 692128348Stjr while (line[0] == '\b' && line[1] != '\0') 693128348Stjr { 694128348Stjr /* 695128348Stjr * Found a backspace. The file position moves 696128348Stjr * forward by 2 relative to the processed line 697128348Stjr * which was searched in hilite_line. 698128348Stjr */ 699128348Stjr npos += 2; 700128348Stjr line += 2; 701128348Stjr } 70260786Sps } 70360786Sps } 70460786Sps} 70560786Sps 70660786Sps/* 70760786Sps * Make a hilite for each string in a physical line which matches 70860786Sps * the current pattern. 70960786Sps * sp,ep delimit the first match already found. 71060786Sps */ 71160786Sps static void 712128348Stjrhilite_line(linepos, line, sp, ep, cvt_ops) 71360786Sps POSITION linepos; 71460786Sps char *line; 71560786Sps char *sp; 71660786Sps char *ep; 717128348Stjr int cvt_ops; 71860786Sps{ 71960786Sps char *searchp; 72060786Sps struct hilite *hl; 72160786Sps struct hilite hilites; 72260786Sps 72360786Sps if (sp == NULL || ep == NULL) 72460786Sps return; 72560786Sps /* 72660786Sps * sp and ep delimit the first match in the line. 72760786Sps * Mark the corresponding file positions, then 72860786Sps * look for further matches and mark them. 72960786Sps * {{ This technique, of calling match_pattern on subsequent 73060786Sps * substrings of the line, may mark more than is correct 73160786Sps * if the pattern starts with "^". This bug is fixed 73260786Sps * for those regex functions that accept a notbol parameter 73360786Sps * (currently POSIX and V8-with-regexec2). }} 73460786Sps */ 73560786Sps searchp = line; 73660786Sps /* 73760786Sps * Put the hilites into a temporary list until they're adjusted. 73860786Sps */ 73960786Sps hilites.hl_first = NULL; 74060786Sps do { 74160786Sps if (ep > sp) 74260786Sps { 74360786Sps /* 74460786Sps * Assume that each char position in the "line" 74560786Sps * buffer corresponds to one char position in the file. 74660786Sps * This is not quite true; we need to adjust later. 74760786Sps */ 74860786Sps hl = (struct hilite *) ecalloc(1, sizeof(struct hilite)); 74960786Sps hl->hl_startpos = linepos + (sp-line); 75060786Sps hl->hl_endpos = linepos + (ep-line); 75160786Sps add_hilite(&hilites, hl); 75260786Sps } 75360786Sps /* 75460786Sps * If we matched more than zero characters, 75560786Sps * move to the first char after the string we matched. 75660786Sps * If we matched zero, just move to the next char. 75760786Sps */ 75860786Sps if (ep > searchp) 75960786Sps searchp = ep; 76060786Sps else if (*searchp != '\0') 76160786Sps searchp++; 76260786Sps else /* end of line */ 76360786Sps break; 76460786Sps } while (match_pattern(searchp, &sp, &ep, 1)); 76560786Sps 76660786Sps /* 767128348Stjr * If there were backspaces in the original line, they 768128348Stjr * were removed, and hl_startpos/hl_endpos are not correct. 769128348Stjr * {{ This is very ugly. }} 770128348Stjr */ 771128348Stjr adj_hilite(&hilites, linepos, cvt_ops); 772128348Stjr 773128348Stjr /* 77460786Sps * Now put the hilites into the real list. 77560786Sps */ 77660786Sps while ((hl = hilites.hl_next) != NULL) 77760786Sps { 77860786Sps hilites.hl_next = hl->hl_next; 77960786Sps add_hilite(&hilite_anchor, hl); 78060786Sps } 78160786Sps} 78260786Sps#endif 78360786Sps 78460786Sps/* 78560786Sps * Change the caseless-ness of searches. 78660786Sps * Updates the internal search state to reflect a change in the -i flag. 78760786Sps */ 78860786Sps public void 78960786Spschg_caseless() 79060786Sps{ 79160786Sps if (!is_ucase_pattern) 79260786Sps /* 79360786Sps * Pattern did not have uppercase. 79460786Sps * Just set the search caselessness to the global caselessness. 79560786Sps */ 79660786Sps is_caseless = caseless; 79760786Sps else 79860786Sps /* 79960786Sps * Pattern did have uppercase. 80060786Sps * Discard the pattern; we can't change search caselessness now. 80160786Sps */ 80260786Sps uncompile_pattern(); 80360786Sps} 80460786Sps 80560786Sps#if HILITE_SEARCH 80660786Sps/* 80760786Sps * Find matching text which is currently on screen and highlight it. 80860786Sps */ 80960786Sps static void 81060786Spshilite_screen() 81160786Sps{ 81260786Sps struct scrpos scrpos; 81360786Sps 81460786Sps get_scrpos(&scrpos); 81560786Sps if (scrpos.pos == NULL_POSITION) 81660786Sps return; 81760786Sps prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); 81860786Sps repaint_hilite(1); 81960786Sps} 82060786Sps 82160786Sps/* 82260786Sps * Change highlighting parameters. 82360786Sps */ 82460786Sps public void 82560786Spschg_hilite() 82660786Sps{ 82760786Sps /* 82860786Sps * Erase any highlights currently on screen. 82960786Sps */ 83060786Sps clr_hilite(); 83160786Sps hide_hilite = 0; 83260786Sps 83360786Sps if (hilite_search == OPT_ONPLUS) 83460786Sps /* 83560786Sps * Display highlights. 83660786Sps */ 83760786Sps hilite_screen(); 83860786Sps} 83960786Sps#endif 84060786Sps 84160786Sps/* 84260786Sps * Figure out where to start a search. 84360786Sps */ 84460786Sps static POSITION 84560786Spssearch_pos(search_type) 84660786Sps int search_type; 84760786Sps{ 84860786Sps POSITION pos; 84960786Sps int linenum; 85060786Sps 85160786Sps if (empty_screen()) 85260786Sps { 85360786Sps /* 85460786Sps * Start at the beginning (or end) of the file. 85560786Sps * The empty_screen() case is mainly for 85660786Sps * command line initiated searches; 85760786Sps * for example, "+/xyz" on the command line. 85860786Sps * Also for multi-file (SRCH_PAST_EOF) searches. 85960786Sps */ 86060786Sps if (search_type & SRCH_FORW) 86160786Sps { 86260786Sps return (ch_zero()); 86360786Sps } else 86460786Sps { 86560786Sps pos = ch_length(); 86660786Sps if (pos == NULL_POSITION) 86760786Sps { 86860786Sps (void) ch_end_seek(); 86960786Sps pos = ch_length(); 87060786Sps } 87160786Sps return (pos); 87260786Sps } 87360786Sps } 87460786Sps if (how_search) 87560786Sps { 87660786Sps /* 87760786Sps * Search does not include current screen. 87860786Sps */ 87960786Sps if (search_type & SRCH_FORW) 88060786Sps linenum = BOTTOM_PLUS_ONE; 88160786Sps else 88260786Sps linenum = TOP; 88360786Sps pos = position(linenum); 88460786Sps } else 88560786Sps { 88660786Sps /* 88760786Sps * Search includes current screen. 88860786Sps * It starts at the jump target (if searching backwards), 88960786Sps * or at the jump target plus one (if forwards). 89060786Sps */ 89160786Sps linenum = adjsline(jump_sline); 89260786Sps pos = position(linenum); 89360786Sps if (search_type & SRCH_FORW) 89460786Sps { 89560786Sps pos = forw_raw_line(pos, (char **)NULL); 89660786Sps while (pos == NULL_POSITION) 89760786Sps { 89860786Sps if (++linenum >= sc_height) 89960786Sps break; 90060786Sps pos = position(linenum); 90160786Sps } 90260786Sps } else 90360786Sps { 90460786Sps while (pos == NULL_POSITION) 90560786Sps { 90660786Sps if (--linenum < 0) 90760786Sps break; 90860786Sps pos = position(linenum); 90960786Sps } 91060786Sps } 91160786Sps } 91260786Sps return (pos); 91360786Sps} 91460786Sps 91560786Sps/* 91660786Sps * Search a subset of the file, specified by start/end position. 91760786Sps */ 91860786Sps static int 91960786Spssearch_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) 92060786Sps POSITION pos; 92160786Sps POSITION endpos; 92260786Sps int search_type; 92360786Sps int matches; 92460786Sps int maxlines; 92560786Sps POSITION *plinepos; 92660786Sps POSITION *pendpos; 92760786Sps{ 92860786Sps char *line; 929128348Stjr LINENUM linenum; 93060786Sps char *sp, *ep; 93160786Sps int line_match; 932128348Stjr int cvt_ops; 93360786Sps POSITION linepos, oldpos; 93460786Sps 93560786Sps linenum = find_linenum(pos); 93660786Sps oldpos = pos; 93760786Sps for (;;) 93860786Sps { 93960786Sps /* 94060786Sps * Get lines until we find a matching one or until 94160786Sps * we hit end-of-file (or beginning-of-file if we're 94260786Sps * going backwards), or until we hit the end position. 94360786Sps */ 94460786Sps if (ABORT_SIGS()) 94560786Sps { 94660786Sps /* 94760786Sps * A signal aborts the search. 94860786Sps */ 94960786Sps return (-1); 95060786Sps } 95160786Sps 95260786Sps if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) 95360786Sps { 95460786Sps /* 95560786Sps * Reached end position without a match. 95660786Sps */ 95760786Sps if (pendpos != NULL) 95860786Sps *pendpos = pos; 95960786Sps return (matches); 96060786Sps } 96160786Sps if (maxlines > 0) 96260786Sps maxlines--; 96360786Sps 96460786Sps if (search_type & SRCH_FORW) 96560786Sps { 96660786Sps /* 96760786Sps * Read the next line, and save the 96860786Sps * starting position of that line in linepos. 96960786Sps */ 97060786Sps linepos = pos; 97160786Sps pos = forw_raw_line(pos, &line); 97260786Sps if (linenum != 0) 97360786Sps linenum++; 97460786Sps } else 97560786Sps { 97660786Sps /* 97760786Sps * Read the previous line and save the 97860786Sps * starting position of that line in linepos. 97960786Sps */ 98060786Sps pos = back_raw_line(pos, &line); 98160786Sps linepos = pos; 98260786Sps if (linenum != 0) 98360786Sps linenum--; 98460786Sps } 98560786Sps 98660786Sps if (pos == NULL_POSITION) 98760786Sps { 98860786Sps /* 98960786Sps * Reached EOF/BOF without a match. 99060786Sps */ 99160786Sps if (pendpos != NULL) 99260786Sps *pendpos = oldpos; 99360786Sps return (matches); 99460786Sps } 99560786Sps 99660786Sps /* 99760786Sps * If we're using line numbers, we might as well 99860786Sps * remember the information we have now (the position 99960786Sps * and line number of the current line). 100060786Sps * Don't do it for every line because it slows down 100160786Sps * the search. Remember the line number only if 100260786Sps * we're "far" from the last place we remembered it. 100360786Sps */ 100460786Sps if (linenums && abs((int)(pos - oldpos)) > 1024) 100560786Sps add_lnum(linenum, pos); 100660786Sps oldpos = pos; 100760786Sps 100860786Sps /* 100960786Sps * If it's a caseless search, convert the line to lowercase. 101060786Sps * If we're doing backspace processing, delete backspaces. 101160786Sps */ 1012128348Stjr cvt_ops = get_cvt_ops(); 1013128348Stjr cvt_text(line, line, cvt_ops); 101460786Sps 101560786Sps /* 101660786Sps * Test the next line to see if we have a match. 101760786Sps * We are successful if we either want a match and got one, 101860786Sps * or if we want a non-match and got one. 101960786Sps */ 102060786Sps line_match = match_pattern(line, &sp, &ep, 0); 102160786Sps line_match = (!(search_type & SRCH_NO_MATCH) && line_match) || 102260786Sps ((search_type & SRCH_NO_MATCH) && !line_match); 102360786Sps if (!line_match) 102460786Sps continue; 102560786Sps /* 102660786Sps * Got a match. 102760786Sps */ 102860786Sps if (search_type & SRCH_FIND_ALL) 102960786Sps { 103060786Sps#if HILITE_SEARCH 103160786Sps /* 103260786Sps * We are supposed to find all matches in the range. 103360786Sps * Just add the matches in this line to the 103460786Sps * hilite list and keep searching. 103560786Sps */ 103660786Sps if (line_match) 1037128348Stjr hilite_line(linepos, line, sp, ep, cvt_ops); 103860786Sps#endif 103960786Sps } else if (--matches <= 0) 104060786Sps { 104160786Sps /* 104260786Sps * Found the one match we're looking for. 104360786Sps * Return it. 104460786Sps */ 104560786Sps#if HILITE_SEARCH 104660786Sps if (hilite_search == 1) 104760786Sps { 104860786Sps /* 104960786Sps * Clear the hilite list and add only 105060786Sps * the matches in this one line. 105160786Sps */ 105260786Sps clr_hilite(); 105360786Sps if (line_match) 1054128348Stjr hilite_line(linepos, line, sp, ep, cvt_ops); 105560786Sps } 105660786Sps#endif 105760786Sps if (plinepos != NULL) 105860786Sps *plinepos = linepos; 105960786Sps return (0); 106060786Sps } 106160786Sps } 106260786Sps} 106360786Sps 106460786Sps/* 106560786Sps * Search for the n-th occurrence of a specified pattern, 106660786Sps * either forward or backward. 106760786Sps * Return the number of matches not yet found in this file 106860786Sps * (that is, n minus the number of matches found). 106960786Sps * Return -1 if the search should be aborted. 107060786Sps * Caller may continue the search in another file 107160786Sps * if less than n matches are found in this file. 107260786Sps */ 107360786Sps public int 107460786Spssearch(search_type, pattern, n) 107560786Sps int search_type; 107660786Sps char *pattern; 107760786Sps int n; 107860786Sps{ 107960786Sps POSITION pos; 108060786Sps int ucase; 108160786Sps 108260786Sps if (pattern == NULL || *pattern == '\0') 108360786Sps { 108460786Sps /* 108560786Sps * A null pattern means use the previously compiled pattern. 108660786Sps */ 108760786Sps if (!prev_pattern()) 108860786Sps { 108960786Sps error("No previous regular expression", NULL_PARG); 109060786Sps return (-1); 109160786Sps } 109260786Sps if ((search_type & SRCH_NO_REGEX) != 109360786Sps (last_search_type & SRCH_NO_REGEX)) 109460786Sps { 109560786Sps error("Please re-enter search pattern", NULL_PARG); 109660786Sps return -1; 109760786Sps } 109860786Sps#if HILITE_SEARCH 109960786Sps if (hilite_search == OPT_ON) 110060786Sps { 110160786Sps /* 110260786Sps * Erase the highlights currently on screen. 110360786Sps * If the search fails, we'll redisplay them later. 110460786Sps */ 110560786Sps repaint_hilite(0); 110660786Sps } 110760786Sps if (hilite_search == OPT_ONPLUS && hide_hilite) 110860786Sps { 110960786Sps /* 111060786Sps * Highlight any matches currently on screen, 111160786Sps * before we actually start the search. 111260786Sps */ 111360786Sps hide_hilite = 0; 111460786Sps hilite_screen(); 111560786Sps } 111660786Sps hide_hilite = 0; 111760786Sps#endif 111860786Sps } else 111960786Sps { 112060786Sps /* 112160786Sps * Compile the pattern. 112260786Sps */ 112360786Sps ucase = is_ucase(pattern); 112460786Sps if (caseless == OPT_ONPLUS) 112560786Sps cvt_text(pattern, pattern, CVT_TO_LC); 112660786Sps if (compile_pattern(pattern, search_type) < 0) 112760786Sps return (-1); 112860786Sps /* 112960786Sps * Ignore case if -I is set OR 113060786Sps * -i is set AND the pattern is all lowercase. 113160786Sps */ 113260786Sps is_ucase_pattern = ucase; 113360786Sps if (is_ucase_pattern && caseless != OPT_ONPLUS) 113460786Sps is_caseless = 0; 113560786Sps else 113660786Sps is_caseless = caseless; 113760786Sps#if HILITE_SEARCH 113860786Sps if (hilite_search) 113960786Sps { 114060786Sps /* 114160786Sps * Erase the highlights currently on screen. 114260786Sps * Also permanently delete them from the hilite list. 114360786Sps */ 114460786Sps repaint_hilite(0); 114560786Sps hide_hilite = 0; 114660786Sps clr_hilite(); 114760786Sps } 114860786Sps if (hilite_search == OPT_ONPLUS) 114960786Sps { 115060786Sps /* 115160786Sps * Highlight any matches currently on screen, 115260786Sps * before we actually start the search. 115360786Sps */ 115460786Sps hilite_screen(); 115560786Sps } 115660786Sps#endif 115760786Sps } 115860786Sps 115960786Sps /* 116060786Sps * Figure out where to start the search. 116160786Sps */ 116260786Sps pos = search_pos(search_type); 116360786Sps if (pos == NULL_POSITION) 116460786Sps { 116560786Sps /* 116660786Sps * Can't find anyplace to start searching from. 116760786Sps */ 116860786Sps if (search_type & SRCH_PAST_EOF) 116960786Sps return (n); 117060786Sps /* repaint(); -- why was this here? */ 117160786Sps error("Nothing to search", NULL_PARG); 117260786Sps return (-1); 117360786Sps } 117460786Sps 117560786Sps n = search_range(pos, NULL_POSITION, search_type, n, -1, 117660786Sps &pos, (POSITION*)NULL); 117760786Sps if (n != 0) 117860786Sps { 117960786Sps /* 118060786Sps * Search was unsuccessful. 118160786Sps */ 118260786Sps#if HILITE_SEARCH 118360786Sps if (hilite_search == OPT_ON && n > 0) 118460786Sps /* 118560786Sps * Redisplay old hilites. 118660786Sps */ 118760786Sps repaint_hilite(1); 118860786Sps#endif 118960786Sps return (n); 119060786Sps } 119160786Sps 119260786Sps if (!(search_type & SRCH_NO_MOVE)) 119360786Sps { 119460786Sps /* 119560786Sps * Go to the matching line. 119660786Sps */ 119760786Sps jump_loc(pos, jump_sline); 119860786Sps } 119960786Sps 120060786Sps#if HILITE_SEARCH 120160786Sps if (hilite_search == OPT_ON) 120260786Sps /* 120360786Sps * Display new hilites in the matching line. 120460786Sps */ 120560786Sps repaint_hilite(1); 120660786Sps#endif 120760786Sps return (0); 120860786Sps} 120960786Sps 121060786Sps 121160786Sps#if HILITE_SEARCH 121260786Sps/* 121360786Sps * Prepare hilites in a given range of the file. 121460786Sps * 121560786Sps * The pair (prep_startpos,prep_endpos) delimits a contiguous region 121660786Sps * of the file that has been "prepared"; that is, scanned for matches for 121760786Sps * the current search pattern, and hilites have been created for such matches. 121860786Sps * If prep_startpos == NULL_POSITION, the prep region is empty. 121960786Sps * If prep_endpos == NULL_POSITION, the prep region extends to EOF. 122060786Sps * prep_hilite asks that the range (spos,epos) be covered by the prep region. 122160786Sps */ 122260786Sps public void 122360786Spsprep_hilite(spos, epos, maxlines) 122460786Sps POSITION spos; 122560786Sps POSITION epos; 122660786Sps int maxlines; 122760786Sps{ 122860786Sps POSITION nprep_startpos = prep_startpos; 122960786Sps POSITION nprep_endpos = prep_endpos; 123060786Sps POSITION new_epos; 123160786Sps POSITION max_epos; 123260786Sps int result; 123360786Sps int i; 123460786Sps/* 123560786Sps * Search beyond where we're asked to search, so the prep region covers 123660786Sps * more than we need. Do one big search instead of a bunch of small ones. 123760786Sps */ 123860786Sps#define SEARCH_MORE (3*size_linebuf) 123960786Sps 124060786Sps if (!prev_pattern()) 124160786Sps return; 124260786Sps 124360786Sps /* 124460786Sps * If we're limited to a max number of lines, figure out the 124560786Sps * file position we should stop at. 124660786Sps */ 124760786Sps if (maxlines < 0) 124860786Sps max_epos = NULL_POSITION; 124960786Sps else 125060786Sps { 125160786Sps max_epos = spos; 125260786Sps for (i = 0; i < maxlines; i++) 125360786Sps max_epos = forw_raw_line(max_epos, (char **)NULL); 125460786Sps } 125560786Sps 125660786Sps /* 125760786Sps * Find two ranges: 125860786Sps * The range that we need to search (spos,epos); and the range that 125960786Sps * the "prep" region will then cover (nprep_startpos,nprep_endpos). 126060786Sps */ 126160786Sps 126260786Sps if (prep_startpos == NULL_POSITION || 126360786Sps (epos != NULL_POSITION && epos < prep_startpos) || 126460786Sps spos > prep_endpos) 126560786Sps { 126660786Sps /* 126760786Sps * New range is not contiguous with old prep region. 126860786Sps * Discard the old prep region and start a new one. 126960786Sps */ 127060786Sps clr_hilite(); 127160786Sps if (epos != NULL_POSITION) 127260786Sps epos += SEARCH_MORE; 127360786Sps nprep_startpos = spos; 127460786Sps } else 127560786Sps { 127660786Sps /* 127760786Sps * New range partially or completely overlaps old prep region. 127860786Sps */ 127960786Sps if (epos == NULL_POSITION) 128060786Sps { 128160786Sps /* 128260786Sps * New range goes to end of file. 128360786Sps */ 128460786Sps ; 128560786Sps } else if (epos > prep_endpos) 128660786Sps { 128760786Sps /* 128860786Sps * New range ends after old prep region. 128960786Sps * Extend prep region to end at end of new range. 129060786Sps */ 129160786Sps epos += SEARCH_MORE; 129260786Sps } else /* (epos <= prep_endpos) */ 129360786Sps { 129460786Sps /* 129560786Sps * New range ends within old prep region. 129660786Sps * Truncate search to end at start of old prep region. 129760786Sps */ 129860786Sps epos = prep_startpos; 129960786Sps } 130060786Sps 130160786Sps if (spos < prep_startpos) 130260786Sps { 130360786Sps /* 130460786Sps * New range starts before old prep region. 130560786Sps * Extend old prep region backwards to start at 130660786Sps * start of new range. 130760786Sps */ 130860786Sps if (spos < SEARCH_MORE) 130960786Sps spos = 0; 131060786Sps else 131160786Sps spos -= SEARCH_MORE; 131260786Sps nprep_startpos = spos; 131360786Sps } else /* (spos >= prep_startpos) */ 131460786Sps { 131560786Sps /* 131660786Sps * New range starts within or after old prep region. 131760786Sps * Trim search to start at end of old prep region. 131860786Sps */ 131960786Sps spos = prep_endpos; 132060786Sps } 132160786Sps } 132260786Sps 132360786Sps if (epos != NULL_POSITION && max_epos != NULL_POSITION && 132460786Sps epos > max_epos) 132560786Sps /* 132660786Sps * Don't go past the max position we're allowed. 132760786Sps */ 132860786Sps epos = max_epos; 132960786Sps 133060786Sps if (epos == NULL_POSITION || epos > spos) 133160786Sps { 133260786Sps result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0, 133360786Sps maxlines, (POSITION*)NULL, &new_epos); 133460786Sps if (result < 0) 133560786Sps return; 133660786Sps if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) 133760786Sps nprep_endpos = new_epos; 133860786Sps } 133960786Sps prep_startpos = nprep_startpos; 134060786Sps prep_endpos = nprep_endpos; 134160786Sps} 134260786Sps#endif 134360786Sps 134460786Sps/* 134560786Sps * Simple pattern matching function. 134660786Sps * It supports no metacharacters like *, etc. 134760786Sps */ 134860786Sps static int 134960786Spsmatch(pattern, buf, pfound, pend) 135060786Sps char *pattern, *buf; 135160786Sps char **pfound, **pend; 135260786Sps{ 135360786Sps register char *pp, *lp; 135460786Sps 135560786Sps for ( ; *buf != '\0'; buf++) 135660786Sps { 135760786Sps for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) 135860786Sps if (*pp == '\0' || *lp == '\0') 135960786Sps break; 136060786Sps if (*pp == '\0') 136160786Sps { 136260786Sps if (pfound != NULL) 136360786Sps *pfound = buf; 136460786Sps if (pend != NULL) 136560786Sps *pend = lp; 136660786Sps return (1); 136760786Sps } 136860786Sps } 136960786Sps return (0); 137060786Sps} 137160786Sps 137260786Sps#if HAVE_V8_REGCOMP 137360786Sps/* 137460786Sps * This function is called by the V8 regcomp to report 137560786Sps * errors in regular expressions. 137660786Sps */ 137760786Sps void 137860786Spsregerror(s) 137960786Sps char *s; 138060786Sps{ 138160786Sps PARG parg; 138260786Sps 138360786Sps parg.p_string = s; 138460786Sps error("%s", &parg); 138560786Sps} 138660786Sps#endif 138760786Sps 1388