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