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