2 * Routines to search a file for a pattern.
12 extern int how_search;
15 extern int jump_sline;
18 * Search for the n-th occurrence of a specified pattern,
19 * either forward or backward.
20 * Return the number of matches not yet found in this file
21 * (that is, n minus the number of matches found).
22 * Return -1 if the search should be aborted.
23 * Caller may continue the search in another file
24 * if less than n matches are found in this file.
27 search(search_type, pattern, n)
32 POSITION pos, linepos, oldpos;
36 register int want_match;
40 static int is_caseless;
47 static char *cpattern = NULL;
50 static struct regexp *regpattern = NULL;
52 static char lpbuf[100];
53 static char *last_pattern = NULL;
59 * Extract flags and type of search.
61 goforw = (SRCH_DIR(search_type) == SRCH_FORW);
62 want_match = !(search_type & SRCH_NOMATCH);
64 if (pattern != NULL && *pattern != '\0' && (is_caseless = caseless))
67 * Search will ignore case, unless
68 * there are any uppercase letters in the pattern.
70 for (p = pattern; *p != '\0'; p++)
71 if (*p >= 'A' && *p <= 'Z')
80 * (re_comp handles a null pattern internally,
81 * so there is no need to check for a null pattern here.)
83 if ((parg.p_string = re_comp(pattern)) != NULL)
90 if (pattern == NULL || *pattern == '\0')
93 * A null pattern means use the previous pattern.
94 * The compiled previous pattern is in cpattern, so just use it.
98 error("No previous regular expression", NULL_PARG);
104 * Otherwise compile the given pattern.
107 if ((s = regcmp(pattern, 0)) == NULL)
109 error("Invalid pattern", NULL_PARG);
112 if (cpattern != NULL)
118 if (pattern == NULL || *pattern == '\0')
121 * A null pattern means use the previous pattern.
122 * The compiled previous pattern is in regpattern,
125 if (regpattern == NULL)
127 error("No previous regular expression", NULL_PARG);
133 * Otherwise compile the given pattern.
136 if ((s = regcomp(pattern)) == NULL)
138 error("Invalid pattern", NULL_PARG);
141 if (regpattern != NULL)
146 if (pattern == NULL || *pattern == '\0')
149 * Null pattern means use the previous pattern.
151 if (last_pattern == NULL)
153 error("No previous regular expression", NULL_PARG);
156 pattern = last_pattern;
159 strcpy(lpbuf, pattern);
160 last_pattern = lpbuf;
167 * Figure out where to start the search.
172 * Start at the beginning (or end) of the file.
173 * (The empty_screen() case is mainly for
174 * command line initiated searches;
175 * for example, "+/xyz" on the command line.)
182 if (pos == NULL_POSITION)
190 linenum = BOTTOM_PLUS_ONE;
193 pos = position(linenum);
196 linenum = adjsline(jump_sline);
197 pos = position(linenum);
199 pos = forw_raw_line(pos, (char **)NULL);
203 if (pos == NULL_POSITION)
206 * Can't find anyplace to start searching from.
208 error("Nothing to search", NULL_PARG);
212 linenum = find_linenum(pos);
217 * Get lines until we find a matching one or
218 * until we hit end-of-file (or beginning-of-file
219 * if we're going backwards).
223 * A signal aborts the search.
230 * Read the next line, and save the
231 * starting position of that line in linepos.
234 pos = forw_raw_line(pos, &line);
240 * Read the previous line and save the
241 * starting position of that line in linepos.
243 pos = back_raw_line(pos, &line);
249 if (pos == NULL_POSITION)
252 * We hit EOF/BOF without a match.
258 * If we're using line numbers, we might as well
259 * remember the information we have now (the position
260 * and line number of the current line).
261 * Don't do it for every line because it slows down
262 * the search. Remember the line number only if
263 * we're "far" from the last place we remembered it.
265 if (linenums && abs(pos - oldpos) > 1024)
267 add_lnum(linenum, pos);
274 * If this is a caseless search, convert
275 * uppercase in the input line to lowercase.
276 * While we're at it, remove any backspaces
277 * along with the preceding char.
278 * This allows us to match text which is
279 * underlined or overstruck.
281 for (p = q = line; *p != '\0'; p++, q++)
283 if (*p >= 'A' && *p <= 'Z')
284 /* Convert uppercase to lowercase. */
286 else if (q > line && *p == '\b')
287 /* Delete BS and preceding char. */
290 /* Otherwise, just copy. */
296 * Test the next line to see if we have a match.
297 * This is done in a variety of ways, depending
298 * on what pattern matching functions are available.
301 line_match = (regex(cpattern, line) != NULL);
304 line_match = (re_exec(line) == 1);
307 line_match = regexec(regpattern, line);
309 line_match = match(pattern, line);
314 * We are successful if want_match and line_match are
315 * both true (want a match and got it),
316 * or both false (want a non-match and got it).
318 if (((want_match && line_match) || (!want_match && !line_match)) &&
326 jump_loc(linepos, jump_sline);
330 #if (!REGCMP) && (!RECOMP) && (!REGCOMP)
332 * We have neither regcmp() nor re_comp().
333 * We use this function to do simple pattern matching.
334 * It supports no metacharacters like *, etc.
340 register char *pp, *lp;
342 for ( ; *buf != '\0'; buf++)
344 for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
345 if (*pp == '\0' || *lp == '\0')