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