]>
diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/miscellany/less-177/search.c
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')