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