Home | History | Annotate | Line # | Download | only in more
prim.c revision 1.8
      1 /*	$NetBSD: prim.c,v 1.8 2003/08/07 09:28:01 agc Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1988, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the University nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Copyright (c) 1988 Mark Nudleman
     34  *
     35  * Redistribution and use in source and binary forms, with or without
     36  * modification, are permitted provided that the following conditions
     37  * are met:
     38  * 1. Redistributions of source code must retain the above copyright
     39  *    notice, this list of conditions and the following disclaimer.
     40  * 2. Redistributions in binary form must reproduce the above copyright
     41  *    notice, this list of conditions and the following disclaimer in the
     42  *    documentation and/or other materials provided with the distribution.
     43  * 3. All advertising materials mentioning features or use of this software
     44  *    must display the following acknowledgement:
     45  *	This product includes software developed by the University of
     46  *	California, Berkeley and its contributors.
     47  * 4. Neither the name of the University nor the names of its contributors
     48  *    may be used to endorse or promote products derived from this software
     49  *    without specific prior written permission.
     50  *
     51  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     52  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     53  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     54  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     55  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     56  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     57  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     58  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     59  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     60  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     61  * SUCH DAMAGE.
     62  */
     63 
     64 #include <sys/cdefs.h>
     65 #ifndef lint
     66 #if 0
     67 static char sccsid[] = "@(#)prim.c	8.1 (Berkeley) 6/6/93";
     68 #else
     69 __RCSID("$NetBSD: prim.c,v 1.8 2003/08/07 09:28:01 agc Exp $");
     70 #endif
     71 #endif /* not lint */
     72 
     73 /*
     74  * Primitives for displaying the file on the screen.
     75  */
     76 
     77 #include <sys/types.h>
     78 #include <stdio.h>
     79 #include <ctype.h>
     80 #include <string.h>
     81 
     82 #include "less.h"
     83 #include "extern.h"
     84 
     85 int back_scroll = -1;
     86 int hit_eof;		/* keeps track of how many times we hit end of file */
     87 int screen_trashed;
     88 
     89 static int squished;
     90 
     91 
     92 static int match(char *, char *);
     93 static int badmark __P((int));
     94 
     95 /*
     96  * Check to see if the end of file is currently "displayed".
     97  */
     98 void
     99 eof_check()
    100 /*###72 [cc] conflicting types for `eof_check'%%%*/
    101 {
    102 	off_t pos;
    103 
    104 	if (sigs)
    105 		return;
    106 	/*
    107 	 * If the bottom line is empty, we are at EOF.
    108 	 * If the bottom line ends at the file length,
    109 	 * we must be just at EOF.
    110 	 */
    111 	pos = position(BOTTOM_PLUS_ONE);
    112 	if (pos == NULL_POSITION || pos == ch_length())
    113 		hit_eof++;
    114 }
    115 
    116 /*
    117  * If the screen is "squished", repaint it.
    118  * "Squished" means the first displayed line is not at the top
    119  * of the screen; this can happen when we display a short file
    120  * for the first time.
    121  */
    122 void
    123 squish_check()
    124 /*###95 [cc] conflicting types for `squish_check'%%%*/
    125 {
    126 	if (squished) {
    127 		squished = 0;
    128 		repaint();
    129 	}
    130 }
    131 
    132 /*
    133  * Display n lines, scrolling forward, starting at position pos in the
    134  * input file.  "only_last" means display only the last screenful if
    135  * n > screen size.
    136  */
    137 void
    138 forw(n, pos, only_last)
    139 /*###109 [cc] conflicting types for `forw'%%%*/
    140 	int n;
    141 	off_t pos;
    142 	int only_last;
    143 {
    144 	static int first_time = 1;
    145 	int eof = 0, do_repaint;
    146 
    147 	squish_check();
    148 
    149 	/*
    150 	 * do_repaint tells us not to display anything till the end,
    151 	 * then just repaint the entire screen.
    152 	 */
    153 	do_repaint = (only_last && n > sc_height-1);
    154 
    155 	if (!do_repaint) {
    156 		if (top_scroll && n >= sc_height - 1) {
    157 			/*
    158 			 * Start a new screen.
    159 			 * {{ This is not really desirable if we happen
    160 			 *    to hit eof in the middle of this screen,
    161 			 *    but we don't yet know if that will happen. }}
    162 			 */
    163 			clear();
    164 			home();
    165 		} else {
    166 			lower_left();
    167 			clear_eol();
    168 		}
    169 
    170 		/*
    171 		 * This is not contiguous with what is currently displayed.
    172 		 * Clear the screen image (position table) and start a new
    173 		 * screen.
    174 		 */
    175 		if (pos != position(BOTTOM_PLUS_ONE)) {
    176 			pos_clear();
    177 			add_forw_pos(pos);
    178 			if (top_scroll) {
    179 				clear();
    180 				home();
    181 			} else if (!first_time)
    182 				putstr("...skipping...\n");
    183 		}
    184 	}
    185 
    186 	for (short_file = 0; --n >= 0;) {
    187 		/*
    188 		 * Read the next line of input.
    189 		 */
    190 		pos = forw_line(pos);
    191 		if (pos == NULL_POSITION) {
    192 			/*
    193 			 * end of file; copy the table if the file was
    194 			 * too small for an entire screen.
    195 			 */
    196 			eof = 1;
    197 			if (position(TOP) == NULL_POSITION) {
    198 				copytable();
    199 				if (!position(TOP))
    200 					short_file = 1;
    201 			}
    202 			break;
    203 		}
    204 		/*
    205 		 * Add the position of the next line to the position table.
    206 		 * Display the current line on the screen.
    207 		 */
    208 		add_forw_pos(pos);
    209 		if (do_repaint)
    210 			continue;
    211 		/*
    212 		 * If this is the first screen displayed and we hit an early
    213 		 * EOF (i.e. before the requested number of lines), we
    214 		 * "squish" the display down at the bottom of the screen.
    215 		 */
    216 		if (first_time && line == NULL && !top_scroll) {
    217 			squished = 1;
    218 			continue;
    219 		}
    220 		put_line();
    221 	}
    222 
    223 	if (eof && !sigs)
    224 		hit_eof++;
    225 	else
    226 		eof_check();
    227 	if (do_repaint)
    228 		repaint();
    229 	first_time = 0;
    230 	(void) currline(BOTTOM);
    231 }
    232 
    233 /*
    234  * Display n lines, scrolling backward.
    235  */
    236 void
    237 back(n, pos, only_last)
    238 /*###207 [cc] conflicting types for `back'%%%*/
    239 	int n;
    240 	off_t pos;
    241 	int only_last;
    242 {
    243 	int do_repaint;
    244 
    245 	squish_check();
    246 	do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
    247 	hit_eof = 0;
    248 	while (--n >= 0)
    249 	{
    250 		/*
    251 		 * Get the previous line of input.
    252 		 */
    253 		pos = back_line(pos);
    254 		if (pos == NULL_POSITION)
    255 			break;
    256 		/*
    257 		 * Add the position of the previous line to the position table.
    258 		 * Display the line on the screen.
    259 		 */
    260 		add_back_pos(pos);
    261 		if (!do_repaint)
    262 		{
    263 			if (retain_below)
    264 			{
    265 				lower_left();
    266 				clear_eol();
    267 			}
    268 			home();
    269 			add_line();
    270 			put_line();
    271 		}
    272 	}
    273 
    274 	eof_check();
    275 	if (do_repaint)
    276 		repaint();
    277 	(void) currline(BOTTOM);
    278 }
    279 
    280 /*
    281  * Display n more lines, forward.
    282  * Start just after the line currently displayed at the bottom of the screen.
    283  */
    284 void
    285 forward(n, only_last)
    286 /*###254 [cc] conflicting types for `forward'%%%*/
    287 	int n;
    288 	int only_last;
    289 {
    290 	off_t pos;
    291 
    292 	if (hit_eof) {
    293 		/*
    294 		 * If we're trying to go forward from end-of-file,
    295 		 * go on to the next file.
    296 		 */
    297 		next_file(1);
    298 		return;
    299 	}
    300 
    301 	pos = position(BOTTOM_PLUS_ONE);
    302 	if (pos == NULL_POSITION)
    303 	{
    304 		hit_eof++;
    305 		return;
    306 	}
    307 	forw(n, pos, only_last);
    308 }
    309 
    310 /*
    311  * Display n more lines, backward.
    312  * Start just before the line currently displayed at the top of the screen.
    313  */
    314 void
    315 backward(n, only_last)
    316 /*###283 [cc] conflicting types for `backward'%%%*/
    317 	int n;
    318 	int only_last;
    319 {
    320 	off_t pos;
    321 
    322 	pos = position(TOP);
    323 	/*
    324 	 * This will almost never happen, because the top line is almost
    325 	 * never empty.
    326 	 */
    327 	if (pos == NULL_POSITION)
    328 		return;
    329 	back(n, pos, only_last);
    330 }
    331 
    332 /*
    333  * Repaint the screen, starting from a specified position.
    334  */
    335 void
    336 prepaint(pos)
    337 /*###303 [cc] conflicting types for `prepaint'%%%*/
    338 	off_t pos;
    339 {
    340 	hit_eof = 0;
    341 	forw(sc_height-1, pos, 0);
    342 	screen_trashed = 0;
    343 }
    344 
    345 /*
    346  * Repaint the screen.
    347  */
    348 void
    349 repaint()
    350 /*###315 [cc] conflicting types for `repaint'%%%*/
    351 {
    352 	/*
    353 	 * Start at the line currently at the top of the screen
    354 	 * and redisplay the screen.
    355 	 */
    356 	prepaint(position(TOP));
    357 }
    358 
    359 /*
    360  * Jump to the end of the file.
    361  * It is more convenient to paint the screen backward,
    362  * from the end of the file toward the beginning.
    363  */
    364 void
    365 jump_forw()
    366 /*###330 [cc] conflicting types for `jump_forw'%%%*/
    367 {
    368 	off_t pos;
    369 
    370 	if (ch_end_seek())
    371 	{
    372 		error("Cannot seek to end of file");
    373 		return;
    374 	}
    375 	lastmark();
    376 	pos = ch_tell();
    377 	clear();
    378 	pos_clear();
    379 	add_back_pos(pos);
    380 	back(sc_height - 1, pos, 0);
    381 }
    382 
    383 /*
    384  * Jump to line n in the file.
    385  */
    386 void
    387 jump_back(n)
    388 /*###351 [cc] conflicting types for `jump_back'%%%*/
    389 	int n;
    390 {
    391 	int c, nlines;
    392 
    393 	/*
    394 	 * This is done the slow way, by starting at the beginning
    395 	 * of the file and counting newlines.
    396 	 *
    397 	 * {{ Now that we have line numbering (in linenum.c),
    398 	 *    we could improve on this by starting at the
    399 	 *    nearest known line rather than at the beginning. }}
    400 	 */
    401 	if (ch_seek((off_t)0)) {
    402 		/*
    403 		 * Probably a pipe with beginning of file no longer buffered.
    404 		 * If he wants to go to line 1, we do the best we can,
    405 		 * by going to the first line which is still buffered.
    406 		 */
    407 		if (n <= 1 && ch_beg_seek() == 0)
    408 			jump_loc(ch_tell());
    409 		error("Cannot get to beginning of file");
    410 		return;
    411 	}
    412 
    413 	/*
    414 	 * Start counting lines.
    415 	 */
    416 	for (nlines = 1;  nlines < n;  nlines++)
    417 		while ((c = ch_forw_get()) != '\n')
    418 			if (c == EOI) {
    419 				char message[40];
    420 				(void)sprintf(message, "File has only %d lines",
    421 				    nlines - 1);
    422 				error(message);
    423 				return;
    424 			}
    425 	jump_loc(ch_tell());
    426 }
    427 
    428 /*
    429  * Jump to a specified percentage into the file.
    430  * This is a poor compensation for not being able to
    431  * quickly jump to a specific line number.
    432  */
    433 void
    434 jump_percent(percent)
    435 /*###397 [cc] conflicting types for `jump_percent'%%%*/
    436 	int percent;
    437 {
    438 	off_t pos, len;
    439 	int c;
    440 
    441 	/*
    442 	 * Determine the position in the file
    443 	 * (the specified percentage of the file's length).
    444 	 */
    445 	if ((len = ch_length()) == NULL_POSITION)
    446 	{
    447 		error("Don't know length of file");
    448 		return;
    449 	}
    450 	pos = (percent * len) / 100;
    451 
    452 	/*
    453 	 * Back up to the beginning of the line.
    454 	 */
    455 	if (ch_seek(pos) == 0)
    456 	{
    457 		while ((c = ch_back_get()) != '\n' && c != EOI)
    458 			;
    459 		if (c == '\n')
    460 			(void) ch_forw_get();
    461 		pos = ch_tell();
    462 	}
    463 	jump_loc(pos);
    464 }
    465 
    466 /*
    467  * Jump to a specified position in the file.
    468  */
    469 void
    470 jump_loc(pos)
    471 /*###432 [cc] conflicting types for `jump_loc'%%%*/
    472 	off_t pos;
    473 {
    474 	int nline;
    475 	off_t tpos;
    476 
    477 	if ((nline = onscreen(pos)) >= 0) {
    478 		/*
    479 		 * The line is currently displayed.
    480 		 * Just scroll there.
    481 		 */
    482 		forw(nline, position(BOTTOM_PLUS_ONE), 0);
    483 		return;
    484 	}
    485 
    486 	/*
    487 	 * Line is not on screen.
    488 	 * Seek to the desired location.
    489 	 */
    490 	if (ch_seek(pos)) {
    491 		error("Cannot seek to that position");
    492 		return;
    493 	}
    494 
    495 	/*
    496 	 * See if the desired line is BEFORE the currently displayed screen.
    497 	 * If so, then move forward far enough so the line we're on will be
    498 	 * at the bottom of the screen, in order to be able to call back()
    499 	 * to make the screen scroll backwards & put the line at the top of
    500 	 * the screen.
    501 	 * {{ This seems inefficient, but it's not so bad,
    502 	 *    since we can never move forward more than a
    503 	 *    screenful before we stop to redraw the screen. }}
    504 	 */
    505 	tpos = position(TOP);
    506 	if (tpos != NULL_POSITION && pos < tpos) {
    507 		off_t npos = pos;
    508 		/*
    509 		 * Note that we can't forw_line() past tpos here,
    510 		 * so there should be no EOI at this stage.
    511 		 */
    512 		for (nline = 0;  npos < tpos && nline < sc_height - 1;  nline++)
    513 			npos = forw_line(npos);
    514 
    515 		if (npos < tpos) {
    516 			/*
    517 			 * More than a screenful back.
    518 			 */
    519 			lastmark();
    520 			clear();
    521 			pos_clear();
    522 			add_back_pos(npos);
    523 		}
    524 
    525 		/*
    526 		 * Note that back() will repaint() if nline > back_scroll.
    527 		 */
    528 		back(nline, npos, 0);
    529 		return;
    530 	}
    531 	/*
    532 	 * Remember where we were; clear and paint the screen.
    533 	 */
    534 	lastmark();
    535 	prepaint(pos);
    536 }
    537 
    538 /*
    539  * The table of marks.
    540  * A mark is simply a position in the file.
    541  */
    542 #define	NMARKS		(27)		/* 26 for a-z plus one for quote */
    543 #define	LASTMARK	(NMARKS-1)	/* For quote */
    544 static off_t marks[NMARKS];
    545 
    546 /*
    547  * Initialize the mark table to show no marks are set.
    548  */
    549 void
    550 init_mark()
    551 /*###511 [cc] conflicting types for `init_mark'%%%*/
    552 {
    553 	int i;
    554 
    555 	for (i = 0;  i < NMARKS;  i++)
    556 		marks[i] = NULL_POSITION;
    557 }
    558 
    559 /*
    560  * See if a mark letter is valid (between a and z).
    561  */
    562 static int
    563 badmark(c)
    564 	int c;
    565 {
    566 	if (c < 'a' || c > 'z')
    567 	{
    568 		error("Choose a letter between 'a' and 'z'");
    569 		return (1);
    570 	}
    571 	return (0);
    572 }
    573 
    574 /*
    575  * Set a mark.
    576  */
    577 void
    578 setmark(c)
    579 /*###538 [cc] conflicting types for `setmark'%%%*/
    580 	int c;
    581 {
    582 	if (badmark(c))
    583 		return;
    584 	marks[c-'a'] = position(TOP);
    585 }
    586 
    587 void
    588 lastmark()
    589 /*###547 [cc] conflicting types for `lastmark'%%%*/
    590 {
    591 	marks[LASTMARK] = position(TOP);
    592 }
    593 
    594 /*
    595  * Go to a previously set mark.
    596  */
    597 void
    598 gomark(c)
    599 /*###556 [cc] conflicting types for `gomark'%%%*/
    600 	int c;
    601 {
    602 	off_t pos;
    603 
    604 	if (c == '\'') {
    605 		pos = marks[LASTMARK];
    606 		if (pos == NULL_POSITION)
    607 			pos = 0;
    608 	}
    609 	else {
    610 		if (badmark(c))
    611 			return;
    612 		pos = marks[c-'a'];
    613 		if (pos == NULL_POSITION) {
    614 			error("mark not set");
    615 			return;
    616 		}
    617 	}
    618 	jump_loc(pos);
    619 }
    620 
    621 /*
    622  * Get the backwards scroll limit.
    623  * Must call this function instead of just using the value of
    624  * back_scroll, because the default case depends on sc_height and
    625  * top_scroll, as well as back_scroll.
    626  */
    627 int
    628 get_back_scroll()
    629 {
    630 	if (back_scroll >= 0)
    631 		return (back_scroll);
    632 	if (top_scroll)
    633 		return (sc_height - 2);
    634 	return (sc_height - 1);
    635 }
    636 
    637 /*
    638  * Search for the n-th occurence of a specified pattern,
    639  * either forward or backward.
    640  */
    641 int
    642 search(search_forward, pattern, n, wantmatch)
    643 	int search_forward;
    644 	char *pattern;
    645 	int n;
    646 	int wantmatch;
    647 {
    648 	off_t pos, linepos;
    649 	char *p;
    650 	char *q;
    651 	int linenum;
    652 	int linematch;
    653 #ifdef RECOMP
    654 	char *re_comp();
    655 	char *errmsg;
    656 #else
    657 #ifdef REGCMP
    658 	char *regcmp();
    659 	static char *cpattern = NULL;
    660 #else
    661 	static char lpbuf[100];
    662 	static char *last_pattern = NULL;
    663 #endif
    664 #endif
    665 
    666 	/*
    667 	 * For a caseless search, convert any uppercase in the pattern to
    668 	 * lowercase.
    669 	 */
    670 	if (caseless && pattern != NULL)
    671 		for (p = pattern;  *p;  p++)
    672 			if (isupper(*p))
    673 				*p = tolower(*p);
    674 #ifdef RECOMP
    675 
    676 	/*
    677 	 * (re_comp handles a null pattern internally,
    678 	 *  so there is no need to check for a null pattern here.)
    679 	 */
    680 	if ((errmsg = re_comp(pattern)) != NULL)
    681 	{
    682 		error(errmsg);
    683 		return(0);
    684 	}
    685 #else
    686 #ifdef REGCMP
    687 	if (pattern == NULL || *pattern == '\0')
    688 	{
    689 		/*
    690 		 * A null pattern means use the previous pattern.
    691 		 * The compiled previous pattern is in cpattern, so just use it.
    692 		 */
    693 		if (cpattern == NULL)
    694 		{
    695 			error("No previous regular expression");
    696 			return(0);
    697 		}
    698 	} else
    699 	{
    700 		/*
    701 		 * Otherwise compile the given pattern.
    702 		 */
    703 		char *s;
    704 		if ((s = regcmp(pattern, 0)) == NULL)
    705 		{
    706 			error("Invalid pattern");
    707 			return(0);
    708 		}
    709 		if (cpattern != NULL)
    710 			free(cpattern);
    711 		cpattern = s;
    712 	}
    713 #else
    714 	if (pattern == NULL || *pattern == '\0')
    715 	{
    716 		/*
    717 		 * Null pattern means use the previous pattern.
    718 		 */
    719 		if (last_pattern == NULL)
    720 		{
    721 			error("No previous regular expression");
    722 			return(0);
    723 		}
    724 		pattern = last_pattern;
    725 	} else
    726 	{
    727 		(void)strlcpy(lpbuf, pattern, sizeof(lpbuf));
    728 		last_pattern = lpbuf;
    729 	}
    730 #endif
    731 #endif
    732 
    733 	/*
    734 	 * Figure out where to start the search.
    735 	 */
    736 
    737 	if (position(TOP) == NULL_POSITION) {
    738 		/*
    739 		 * Nothing is currently displayed.  Start at the beginning
    740 		 * of the file.  (This case is mainly for searches from the
    741 		 * command line.
    742 		 */
    743 		pos = (off_t)0;
    744 	} else if (!search_forward) {
    745 		/*
    746 		 * Backward search: start just before the top line
    747 		 * displayed on the screen.
    748 		 */
    749 		pos = position(TOP);
    750 	} else {
    751 		/*
    752 		 * Start at the second screen line displayed on the screen.
    753 		 */
    754 		pos = position(TOP_PLUS_ONE);
    755 	}
    756 
    757 	if (pos == NULL_POSITION)
    758 	{
    759 		/*
    760 		 * Can't find anyplace to start searching from.
    761 		 */
    762 		error("Nothing to search");
    763 		return(0);
    764 	}
    765 
    766 	linenum = find_linenum(pos);
    767 	for (;;)
    768 	{
    769 		/*
    770 		 * Get lines until we find a matching one or
    771 		 * until we hit end-of-file (or beginning-of-file
    772 		 * if we're going backwards).
    773 		 */
    774 		if (sigs)
    775 			/*
    776 			 * A signal aborts the search.
    777 			 */
    778 			return(0);
    779 
    780 		if (search_forward)
    781 		{
    782 			/*
    783 			 * Read the next line, and save the
    784 			 * starting position of that line in linepos.
    785 			 */
    786 			linepos = pos;
    787 			pos = forw_raw_line(pos);
    788 			if (linenum != 0)
    789 				linenum++;
    790 		} else
    791 		{
    792 			/*
    793 			 * Read the previous line and save the
    794 			 * starting position of that line in linepos.
    795 			 */
    796 			pos = back_raw_line(pos);
    797 			linepos = pos;
    798 			if (linenum != 0)
    799 				linenum--;
    800 		}
    801 
    802 		if (pos == NULL_POSITION)
    803 		{
    804 			/*
    805 			 * We hit EOF/BOF without a match.
    806 			 */
    807 			error("Pattern not found");
    808 			return(0);
    809 		}
    810 
    811 		/*
    812 		 * If we're using line numbers, we might as well
    813 		 * remember the information we have now (the position
    814 		 * and line number of the current line).
    815 		 */
    816 		if (linenums)
    817 			add_lnum(linenum, pos);
    818 
    819 		/*
    820 		 * If this is a caseless search, convert uppercase in the
    821 		 * input line to lowercase.
    822 		 */
    823 		if (caseless)
    824 			for (p = q = line;  *p;  p++, q++)
    825 				*q = isupper(*p) ? tolower(*p) : *p;
    826 
    827 		/*
    828 		 * Remove any backspaces along with the preceding char.
    829 		 * This allows us to match text which is underlined or
    830 		 * overstruck.
    831 		 */
    832 		for (p = q = line;  *p;  p++, q++)
    833 			if (q > line && *p == '\b')
    834 				/* Delete BS and preceding char. */
    835 				q -= 2;
    836 			else
    837 				/* Otherwise, just copy. */
    838 				*q = *p;
    839 
    840 		/*
    841 		 * Test the next line to see if we have a match.
    842 		 * This is done in a variety of ways, depending
    843 		 * on what pattern matching functions are available.
    844 		 */
    845 #ifdef REGCMP
    846 		linematch = (regex(cpattern, line) != NULL);
    847 #else
    848 #ifdef RECOMP
    849 		linematch = (re_exec(line) == 1);
    850 #else
    851 		linematch = match(pattern, line);
    852 #endif
    853 #endif
    854 		/*
    855 		 * We are successful if wantmatch and linematch are
    856 		 * both true (want a match and got it),
    857 		 * or both false (want a non-match and got it).
    858 		 */
    859 		if (((wantmatch && linematch) || (!wantmatch && !linematch)) &&
    860 		      --n <= 0)
    861 			/*
    862 			 * Found the line.
    863 			 */
    864 			break;
    865 	}
    866 	jump_loc(linepos);
    867 	return(1);
    868 }
    869 
    870 #if !defined(REGCMP) && !defined(RECOMP)
    871 /*
    872  * We have neither regcmp() nor re_comp().
    873  * We use this function to do simple pattern matching.
    874  * It supports no metacharacters like *, etc.
    875  */
    876 static int
    877 match(pattern, buf)
    878 	char *pattern, *buf;
    879 {
    880 	char *pp, *lp;
    881 
    882 	for ( ;  *buf != '\0';  buf++)
    883 	{
    884 		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
    885 			if (*pp == '\0' || *lp == '\0')
    886 				break;
    887 		if (*pp == '\0')
    888 			return (1);
    889 	}
    890 	return (0);
    891 }
    892 #endif
    893