/* * Copyright (c) 1988 Mark Nudleman * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static char sccsid[] = "@(#)prim.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #ifndef lint static const char rcsid[] = "$FreeBSD: src/usr.bin/more/prim.c,v 1.10 2000/05/14 03:30:59 hoek Exp $"; #endif /* not lint */ /* * Primitives for displaying the file on the screen. */ #include #include #include #include #include #include #include "less.h" extern int sigs; extern int top_scroll; extern int sc_width, sc_height; extern int horiz_off; extern int wraplines; extern int caseless; extern int linenums; extern int tagoption; extern char *line; extern int retain_below; /* * Search for the n-th occurence of a specified pattern, * either forward or backward. */ search(search_forward, pattern, n, wantmatch) register int search_forward; register char *pattern; register int n; int wantmatch; { off_t pos, linepos; register char *p; register char *q; int linenum; int linematch; static regex_t rx; static int oncethru; int regerr; char errbuf[_POSIX2_LINE_MAX]; if (pattern && pattern[0]) { if (oncethru) { regfree(&rx); } regerr = regcomp(&rx, pattern, (REG_EXTENDED | REG_NOSUB | (caseless ? REG_ICASE : 0))); if (regerr) { regerror(regerr, &rx, errbuf, sizeof errbuf); error(errbuf); oncethru = 0; regfree(&rx); return (0); } oncethru = 1; } else if (!oncethru) { error("No previous regular expression"); return (0); } /* * Figure out where to start the search. * * XXX This should probably be adapted to handle horizontal * scrolling. Consider a long line at the top of the screen * that might be hiding more matches to its right (when doing * successive searches). */ if (position(TOP) == NULL_POSITION) { /* * Nothing is currently displayed. Start at the beginning * of the file. (This case is mainly for searches from the * command line. */ pos = (off_t)0; } else if (!search_forward) { /* * Backward search: start just before the top line * displayed on the screen. */ pos = position(TOP); } else { /* * Start at the second screen line displayed on the screen. */ pos = position(TOP_PLUS_ONE); } if (pos == NULL_POSITION) { /* * Can't find anyplace to start searching from. */ error("Nothing to search"); return(0); } linenum = find_linenum(pos); for (;;) { /* * Get lines until we find a matching one or * until we hit end-of-file (or beginning-of-file * if we're going backwards). */ if (sigs) /* * A signal aborts the search. */ return(0); if (search_forward) { /* * Read the next line, and save the * starting position of that line in linepos. */ linepos = pos; pos = forw_raw_line(pos); if (linenum != 0) linenum++; } else { /* * Read the previous line and save the * starting position of that line in linepos. */ pos = back_raw_line(pos); linepos = pos; if (linenum != 0) linenum--; } if (pos == NULL_POSITION) { /* * We hit EOF/BOF without a match. */ error("Pattern not found"); return(0); } /* * If we're using line numbers, we might as well * remember the information we have now (the position * and line number of the current line). */ if (linenums) add_lnum(linenum, pos); /* * Remove any backspaces along with the preceeding char. * This allows us to match text which is underlined or * overstruck. */ for (p = q = line; *p; p++, q++) if (q > line && *p == '\b') /* Delete BS and preceeding char. */ q -= 2; else /* Otherwise, just copy. */ *q = *p; /* * Test the next line to see if we have a match. */ linematch = !regexec(&rx, line, 0, 0, 0); /* * We are successful if wantmatch and linematch are * both true (want a match and got it), * or both false (want a non-match and got it). */ if (((wantmatch && linematch) || (!wantmatch && !linematch)) && --n <= 0) /* * Found the line. */ break; } jump_loc(linepos); return(1); }