xref: /csrg-svn/usr.bin/more/prim.c (revision 62131)
135209Sbostic /*
235209Sbostic  * Copyright (c) 1988 Mark Nudleman
3*62131Sbostic  * Copyright (c) 1988, 1993
4*62131Sbostic  *	The Regents of the University of California.  All rights reserved.
535209Sbostic  *
642742Sbostic  * %sccs.include.redist.c%
735209Sbostic  */
835209Sbostic 
935209Sbostic #ifndef lint
10*62131Sbostic static char sccsid[] = "@(#)prim.c	8.1 (Berkeley) 06/06/93";
1135209Sbostic #endif /* not lint */
1235209Sbostic 
1335209Sbostic /*
1435209Sbostic  * Primitives for displaying the file on the screen.
1535209Sbostic  */
1635209Sbostic 
1736253Sbostic #include <sys/types.h>
1836253Sbostic #include <stdio.h>
1936253Sbostic #include <ctype.h>
2036253Sbostic #include <less.h>
2135209Sbostic 
2236253Sbostic int back_scroll = -1;
2336253Sbostic int hit_eof;		/* keeps track of how many times we hit end of file */
2436253Sbostic int screen_trashed;
2535209Sbostic 
2635209Sbostic static int squished;
2735209Sbostic 
2835209Sbostic extern int sigs;
2935209Sbostic extern int top_scroll;
3035209Sbostic extern int sc_width, sc_height;
3135209Sbostic extern int caseless;
3235209Sbostic extern int linenums;
3336253Sbostic extern int tagoption;
3435209Sbostic extern char *line;
3557940Sedward extern int retain_below;
3635209Sbostic 
3736253Sbostic off_t position(), forw_line(), back_line(), forw_raw_line(), back_raw_line();
3836253Sbostic off_t ch_length(), ch_tell();
3935209Sbostic 
4035209Sbostic /*
4135209Sbostic  * Check to see if the end of file is currently "displayed".
4235209Sbostic  */
eof_check()4335209Sbostic eof_check()
4435209Sbostic {
4536253Sbostic 	off_t pos;
4635209Sbostic 
4735209Sbostic 	if (sigs)
4835209Sbostic 		return;
4935209Sbostic 	/*
5035209Sbostic 	 * If the bottom line is empty, we are at EOF.
5135209Sbostic 	 * If the bottom line ends at the file length,
5235209Sbostic 	 * we must be just at EOF.
5335209Sbostic 	 */
5435209Sbostic 	pos = position(BOTTOM_PLUS_ONE);
5535209Sbostic 	if (pos == NULL_POSITION || pos == ch_length())
5635209Sbostic 		hit_eof++;
5735209Sbostic }
5835209Sbostic 
5935209Sbostic /*
6035209Sbostic  * If the screen is "squished", repaint it.
6135209Sbostic  * "Squished" means the first displayed line is not at the top
6235209Sbostic  * of the screen; this can happen when we display a short file
6335209Sbostic  * for the first time.
6435209Sbostic  */
squish_check()6535209Sbostic squish_check()
6635209Sbostic {
6736253Sbostic 	if (squished) {
6836253Sbostic 		squished = 0;
6936253Sbostic 		repaint();
7036253Sbostic 	}
7135209Sbostic }
7235209Sbostic 
7335209Sbostic /*
7436253Sbostic  * Display n lines, scrolling forward, starting at position pos in the
7536358Sbostic  * input file.  "only_last" means display only the last screenful if
7636358Sbostic  * n > screen size.
7735209Sbostic  */
forw(n,pos,only_last)7836358Sbostic forw(n, pos, only_last)
7935209Sbostic 	register int n;
8036253Sbostic 	off_t pos;
8135209Sbostic 	int only_last;
8235209Sbostic {
8336358Sbostic 	extern int short_file;
8435209Sbostic 	static int first_time = 1;
8536253Sbostic 	int eof = 0, do_repaint;
8635209Sbostic 
8735209Sbostic 	squish_check();
8835209Sbostic 
8935209Sbostic 	/*
9035209Sbostic 	 * do_repaint tells us not to display anything till the end,
9135209Sbostic 	 * then just repaint the entire screen.
9235209Sbostic 	 */
9335209Sbostic 	do_repaint = (only_last && n > sc_height-1);
9435209Sbostic 
9536253Sbostic 	if (!do_repaint) {
9636253Sbostic 		if (top_scroll && n >= sc_height - 1) {
9735209Sbostic 			/*
9835209Sbostic 			 * Start a new screen.
9935209Sbostic 			 * {{ This is not really desirable if we happen
10035209Sbostic 			 *    to hit eof in the middle of this screen,
10135209Sbostic 			 *    but we don't yet know if that will happen. }}
10235209Sbostic 			 */
10336253Sbostic 			clear();
10435209Sbostic 			home();
10536253Sbostic 		} else {
10635209Sbostic 			lower_left();
10735209Sbostic 			clear_eol();
10835209Sbostic 		}
10935209Sbostic 
11036253Sbostic 		/*
11136253Sbostic 		 * This is not contiguous with what is currently displayed.
11236253Sbostic 		 * Clear the screen image (position table) and start a new
11336253Sbostic 		 * screen.
11436253Sbostic 		 */
11536253Sbostic 		if (pos != position(BOTTOM_PLUS_ONE)) {
11635209Sbostic 			pos_clear();
11735209Sbostic 			add_forw_pos(pos);
11836253Sbostic 			if (top_scroll) {
11936253Sbostic 				clear();
12035209Sbostic 				home();
12135209Sbostic 			} else if (!first_time)
12235209Sbostic 				putstr("...skipping...\n");
12335209Sbostic 		}
12435209Sbostic 	}
12535209Sbostic 
12636358Sbostic 	for (short_file = 0; --n >= 0;) {
12735209Sbostic 		/*
12835209Sbostic 		 * Read the next line of input.
12935209Sbostic 		 */
13035209Sbostic 		pos = forw_line(pos);
13136253Sbostic 		if (pos == NULL_POSITION) {
13235209Sbostic 			/*
13336358Sbostic 			 * end of file; copy the table if the file was
13436358Sbostic 			 * too small for an entire screen.
13535209Sbostic 			 */
13635209Sbostic 			eof = 1;
13736358Sbostic 			if (position(TOP) == NULL_POSITION) {
13836358Sbostic 				copytable();
13936358Sbostic 				if (!position(TOP))
14036358Sbostic 					short_file = 1;
14136358Sbostic 			}
14236358Sbostic 			break;
14335209Sbostic 		}
14435209Sbostic 		/*
14535209Sbostic 		 * Add the position of the next line to the position table.
14635209Sbostic 		 * Display the current line on the screen.
14735209Sbostic 		 */
14835209Sbostic 		add_forw_pos(pos);
14935209Sbostic 		if (do_repaint)
15035209Sbostic 			continue;
15135209Sbostic 		/*
15236253Sbostic 		 * If this is the first screen displayed and we hit an early
15336253Sbostic 		 * EOF (i.e. before the requested number of lines), we
15436253Sbostic 		 * "squish" the display down at the bottom of the screen.
15536253Sbostic 		 * But don't do this if a -t option was given; it can cause
15636253Sbostic 		 * us to start the display after the beginning of the file,
15735209Sbostic 		 * and it is not appropriate to squish in that case.
15835209Sbostic 		 */
15936253Sbostic 		if (first_time && line == NULL && !top_scroll && !tagoption) {
16035209Sbostic 			squished = 1;
16135209Sbostic 			continue;
16235209Sbostic 		}
16335209Sbostic 		put_line();
16435209Sbostic 	}
16535209Sbostic 
16635209Sbostic 	if (eof && !sigs)
16735209Sbostic 		hit_eof++;
16835209Sbostic 	else
16935209Sbostic 		eof_check();
17036253Sbostic 	if (do_repaint)
17135209Sbostic 		repaint();
17235209Sbostic 	first_time = 0;
17335209Sbostic 	(void) currline(BOTTOM);
17435209Sbostic }
17535209Sbostic 
17635209Sbostic /*
17735209Sbostic  * Display n lines, scrolling backward.
17835209Sbostic  */
back(n,pos,only_last)17936358Sbostic back(n, pos, only_last)
18035209Sbostic 	register int n;
18136253Sbostic 	off_t pos;
18235209Sbostic 	int only_last;
18335209Sbostic {
18435209Sbostic 	int do_repaint;
18535209Sbostic 
18635209Sbostic 	squish_check();
18735209Sbostic 	do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
18835209Sbostic 	hit_eof = 0;
18935209Sbostic 	while (--n >= 0)
19035209Sbostic 	{
19135209Sbostic 		/*
19235209Sbostic 		 * Get the previous line of input.
19335209Sbostic 		 */
19435209Sbostic 		pos = back_line(pos);
19535209Sbostic 		if (pos == NULL_POSITION)
19636358Sbostic 			break;
19735209Sbostic 		/*
19835209Sbostic 		 * Add the position of the previous line to the position table.
19935209Sbostic 		 * Display the line on the screen.
20035209Sbostic 		 */
20135209Sbostic 		add_back_pos(pos);
20235209Sbostic 		if (!do_repaint)
20335209Sbostic 		{
20457940Sedward 			if (retain_below)
20557940Sedward 			{
20657940Sedward 				lower_left();
20757940Sedward 				clear_eol();
20857940Sedward 			}
20935209Sbostic 			home();
21035209Sbostic 			add_line();
21135209Sbostic 			put_line();
21235209Sbostic 		}
21335209Sbostic 	}
21435209Sbostic 
21535209Sbostic 	eof_check();
21636253Sbostic 	if (do_repaint)
21735209Sbostic 		repaint();
21835209Sbostic 	(void) currline(BOTTOM);
21935209Sbostic }
22035209Sbostic 
22135209Sbostic /*
22235209Sbostic  * Display n more lines, forward.
22335209Sbostic  * Start just after the line currently displayed at the bottom of the screen.
22435209Sbostic  */
forward(n,only_last)22535209Sbostic forward(n, only_last)
22635209Sbostic 	int n;
22735209Sbostic 	int only_last;
22835209Sbostic {
22936253Sbostic 	off_t pos;
23035209Sbostic 
23136253Sbostic 	if (hit_eof) {
23235209Sbostic 		/*
23336253Sbostic 		 * If we're trying to go forward from end-of-file,
23436253Sbostic 		 * go on to the next file.
23535209Sbostic 		 */
23635209Sbostic 		next_file(1);
23735209Sbostic 		return;
23835209Sbostic 	}
23935209Sbostic 
24035209Sbostic 	pos = position(BOTTOM_PLUS_ONE);
24135209Sbostic 	if (pos == NULL_POSITION)
24235209Sbostic 	{
24335209Sbostic 		hit_eof++;
24435209Sbostic 		return;
24535209Sbostic 	}
24636358Sbostic 	forw(n, pos, only_last);
24735209Sbostic }
24835209Sbostic 
24935209Sbostic /*
25035209Sbostic  * Display n more lines, backward.
25135209Sbostic  * Start just before the line currently displayed at the top of the screen.
25235209Sbostic  */
backward(n,only_last)25335209Sbostic backward(n, only_last)
25435209Sbostic 	int n;
25535209Sbostic 	int only_last;
25635209Sbostic {
25736253Sbostic 	off_t pos;
25835209Sbostic 
25935209Sbostic 	pos = position(TOP);
26036253Sbostic 	/*
26136253Sbostic 	 * This will almost never happen, because the top line is almost
26236253Sbostic 	 * never empty.
26336253Sbostic 	 */
26435209Sbostic 	if (pos == NULL_POSITION)
26535209Sbostic 		return;
26636358Sbostic 	back(n, pos, only_last);
26735209Sbostic }
26835209Sbostic 
26935209Sbostic /*
27035209Sbostic  * Repaint the screen, starting from a specified position.
27135209Sbostic  */
prepaint(pos)27236253Sbostic prepaint(pos)
27336253Sbostic 	off_t pos;
27435209Sbostic {
27535209Sbostic 	hit_eof = 0;
27636358Sbostic 	forw(sc_height-1, pos, 0);
27735209Sbostic 	screen_trashed = 0;
27835209Sbostic }
27935209Sbostic 
28035209Sbostic /*
28135209Sbostic  * Repaint the screen.
28235209Sbostic  */
repaint()28335209Sbostic repaint()
28435209Sbostic {
28535209Sbostic 	/*
28635209Sbostic 	 * Start at the line currently at the top of the screen
28735209Sbostic 	 * and redisplay the screen.
28835209Sbostic 	 */
28935209Sbostic 	prepaint(position(TOP));
29035209Sbostic }
29135209Sbostic 
29235209Sbostic /*
29335209Sbostic  * Jump to the end of the file.
29435209Sbostic  * It is more convenient to paint the screen backward,
29535209Sbostic  * from the end of the file toward the beginning.
29635209Sbostic  */
jump_forw()29735209Sbostic jump_forw()
29835209Sbostic {
29936253Sbostic 	off_t pos;
30035209Sbostic 
30135209Sbostic 	if (ch_end_seek())
30235209Sbostic 	{
30335209Sbostic 		error("Cannot seek to end of file");
30435209Sbostic 		return;
30535209Sbostic 	}
30635209Sbostic 	lastmark();
30735209Sbostic 	pos = ch_tell();
30835209Sbostic 	clear();
30935209Sbostic 	pos_clear();
31035209Sbostic 	add_back_pos(pos);
31136358Sbostic 	back(sc_height - 1, pos, 0);
31235209Sbostic }
31335209Sbostic 
31435209Sbostic /*
31535209Sbostic  * Jump to line n in the file.
31635209Sbostic  */
jump_back(n)31735209Sbostic jump_back(n)
31835209Sbostic 	register int n;
31935209Sbostic {
32036253Sbostic 	register int c, nlines;
32135209Sbostic 
32235209Sbostic 	/*
32335209Sbostic 	 * This is done the slow way, by starting at the beginning
32435209Sbostic 	 * of the file and counting newlines.
32535209Sbostic 	 *
32635209Sbostic 	 * {{ Now that we have line numbering (in linenum.c),
32735209Sbostic 	 *    we could improve on this by starting at the
32835209Sbostic 	 *    nearest known line rather than at the beginning. }}
32935209Sbostic 	 */
33036253Sbostic 	if (ch_seek((off_t)0)) {
33135209Sbostic 		/*
33235209Sbostic 		 * Probably a pipe with beginning of file no longer buffered.
33335209Sbostic 		 * If he wants to go to line 1, we do the best we can,
33435209Sbostic 		 * by going to the first line which is still buffered.
33535209Sbostic 		 */
33635209Sbostic 		if (n <= 1 && ch_beg_seek() == 0)
33735209Sbostic 			jump_loc(ch_tell());
33835209Sbostic 		error("Cannot get to beginning of file");
33935209Sbostic 		return;
34035209Sbostic 	}
34135209Sbostic 
34235209Sbostic 	/*
34335209Sbostic 	 * Start counting lines.
34435209Sbostic 	 */
34535209Sbostic 	for (nlines = 1;  nlines < n;  nlines++)
34635209Sbostic 		while ((c = ch_forw_get()) != '\n')
34736253Sbostic 			if (c == EOI) {
34835209Sbostic 				char message[40];
34935242Sbostic 				(void)sprintf(message, "File has only %d lines",
35036253Sbostic 				    nlines - 1);
35135209Sbostic 				error(message);
35235209Sbostic 				return;
35335209Sbostic 			}
35435209Sbostic 	jump_loc(ch_tell());
35535209Sbostic }
35635209Sbostic 
35735209Sbostic /*
35835209Sbostic  * Jump to a specified percentage into the file.
35935209Sbostic  * This is a poor compensation for not being able to
36035209Sbostic  * quickly jump to a specific line number.
36135209Sbostic  */
jump_percent(percent)36235209Sbostic jump_percent(percent)
36335209Sbostic 	int percent;
36435209Sbostic {
36536253Sbostic 	off_t pos, len, ch_length();
36635209Sbostic 	register int c;
36735209Sbostic 
36835209Sbostic 	/*
36935209Sbostic 	 * Determine the position in the file
37035209Sbostic 	 * (the specified percentage of the file's length).
37135209Sbostic 	 */
37235209Sbostic 	if ((len = ch_length()) == NULL_POSITION)
37335209Sbostic 	{
37435209Sbostic 		error("Don't know length of file");
37535209Sbostic 		return;
37635209Sbostic 	}
37735209Sbostic 	pos = (percent * len) / 100;
37835209Sbostic 
37935209Sbostic 	/*
38035209Sbostic 	 * Back up to the beginning of the line.
38135209Sbostic 	 */
38235209Sbostic 	if (ch_seek(pos) == 0)
38335209Sbostic 	{
38435209Sbostic 		while ((c = ch_back_get()) != '\n' && c != EOI)
38535209Sbostic 			;
38635209Sbostic 		if (c == '\n')
38735209Sbostic 			(void) ch_forw_get();
38835209Sbostic 		pos = ch_tell();
38935209Sbostic 	}
39035209Sbostic 	jump_loc(pos);
39135209Sbostic }
39235209Sbostic 
39335209Sbostic /*
39435209Sbostic  * Jump to a specified position in the file.
39535209Sbostic  */
jump_loc(pos)39635209Sbostic jump_loc(pos)
39736253Sbostic 	off_t pos;
39835209Sbostic {
39935209Sbostic 	register int nline;
40036253Sbostic 	off_t tpos;
40135209Sbostic 
40236253Sbostic 	if ((nline = onscreen(pos)) >= 0) {
40335209Sbostic 		/*
40435209Sbostic 		 * The line is currently displayed.
40535209Sbostic 		 * Just scroll there.
40635209Sbostic 		 */
40736358Sbostic 		forw(nline, position(BOTTOM_PLUS_ONE), 0);
40835209Sbostic 		return;
40935209Sbostic 	}
41035209Sbostic 
41135209Sbostic 	/*
41235209Sbostic 	 * Line is not on screen.
41335209Sbostic 	 * Seek to the desired location.
41435209Sbostic 	 */
41536253Sbostic 	if (ch_seek(pos)) {
41635209Sbostic 		error("Cannot seek to that position");
41735209Sbostic 		return;
41835209Sbostic 	}
41935209Sbostic 
42035209Sbostic 	/*
42136253Sbostic 	 * See if the desired line is BEFORE the currently displayed screen.
42236253Sbostic 	 * If so, then move forward far enough so the line we're on will be
42336253Sbostic 	 * at the bottom of the screen, in order to be able to call back()
42436253Sbostic 	 * to make the screen scroll backwards & put the line at the top of
42536253Sbostic 	 * the screen.
42635209Sbostic 	 * {{ This seems inefficient, but it's not so bad,
42735209Sbostic 	 *    since we can never move forward more than a
42835209Sbostic 	 *    screenful before we stop to redraw the screen. }}
42935209Sbostic 	 */
43035209Sbostic 	tpos = position(TOP);
43136253Sbostic 	if (tpos != NULL_POSITION && pos < tpos) {
43236253Sbostic 		off_t npos = pos;
43335209Sbostic 		/*
43435209Sbostic 		 * Note that we can't forw_line() past tpos here,
43535209Sbostic 		 * so there should be no EOI at this stage.
43635209Sbostic 		 */
43735209Sbostic 		for (nline = 0;  npos < tpos && nline < sc_height - 1;  nline++)
43835209Sbostic 			npos = forw_line(npos);
43935209Sbostic 
44036253Sbostic 		if (npos < tpos) {
44135209Sbostic 			/*
44235209Sbostic 			 * More than a screenful back.
44335209Sbostic 			 */
44435209Sbostic 			lastmark();
44535209Sbostic 			clear();
44635209Sbostic 			pos_clear();
44735209Sbostic 			add_back_pos(npos);
44835209Sbostic 		}
44935209Sbostic 
45035209Sbostic 		/*
45135209Sbostic 		 * Note that back() will repaint() if nline > back_scroll.
45235209Sbostic 		 */
45336358Sbostic 		back(nline, npos, 0);
45435209Sbostic 		return;
45535209Sbostic 	}
45635209Sbostic 	/*
45735209Sbostic 	 * Remember where we were; clear and paint the screen.
45835209Sbostic 	 */
45936253Sbostic 	lastmark();
46036253Sbostic 	prepaint(pos);
46135209Sbostic }
46235209Sbostic 
46335209Sbostic /*
46435209Sbostic  * The table of marks.
46535209Sbostic  * A mark is simply a position in the file.
46635209Sbostic  */
46735209Sbostic #define	NMARKS		(27)		/* 26 for a-z plus one for quote */
46835209Sbostic #define	LASTMARK	(NMARKS-1)	/* For quote */
46936253Sbostic static off_t marks[NMARKS];
47035209Sbostic 
47135209Sbostic /*
47235209Sbostic  * Initialize the mark table to show no marks are set.
47335209Sbostic  */
init_mark()47435209Sbostic init_mark()
47535209Sbostic {
47635209Sbostic 	int i;
47735209Sbostic 
47835209Sbostic 	for (i = 0;  i < NMARKS;  i++)
47935209Sbostic 		marks[i] = NULL_POSITION;
48035209Sbostic }
48135209Sbostic 
48235209Sbostic /*
48335209Sbostic  * See if a mark letter is valid (between a and z).
48435209Sbostic  */
48535209Sbostic 	static int
badmark(c)48635209Sbostic badmark(c)
48735209Sbostic 	int c;
48835209Sbostic {
48935209Sbostic 	if (c < 'a' || c > 'z')
49035209Sbostic 	{
49135209Sbostic 		error("Choose a letter between 'a' and 'z'");
49235209Sbostic 		return (1);
49335209Sbostic 	}
49435209Sbostic 	return (0);
49535209Sbostic }
49635209Sbostic 
49735209Sbostic /*
49835209Sbostic  * Set a mark.
49935209Sbostic  */
setmark(c)50035209Sbostic setmark(c)
50135209Sbostic 	int c;
50235209Sbostic {
50335209Sbostic 	if (badmark(c))
50435209Sbostic 		return;
50535209Sbostic 	marks[c-'a'] = position(TOP);
50635209Sbostic }
50735209Sbostic 
lastmark()50835209Sbostic lastmark()
50935209Sbostic {
51035209Sbostic 	marks[LASTMARK] = position(TOP);
51135209Sbostic }
51235209Sbostic 
51335209Sbostic /*
51435209Sbostic  * Go to a previously set mark.
51535209Sbostic  */
gomark(c)51635209Sbostic gomark(c)
51735209Sbostic 	int c;
51835209Sbostic {
51936253Sbostic 	off_t pos;
52035209Sbostic 
52136300Sbostic 	if (c == '\'') {
52235209Sbostic 		pos = marks[LASTMARK];
52336300Sbostic 		if (pos == NULL_POSITION)
52436300Sbostic 			pos = 0;
52536300Sbostic 	}
52636300Sbostic 	else {
52736300Sbostic 		if (badmark(c))
52836300Sbostic 			return;
52935209Sbostic 		pos = marks[c-'a'];
53036300Sbostic 		if (pos == NULL_POSITION) {
53136300Sbostic 			error("mark not set");
53236300Sbostic 			return;
53336300Sbostic 		}
53436300Sbostic 	}
53536300Sbostic 	jump_loc(pos);
53635209Sbostic }
53735209Sbostic 
53835209Sbostic /*
53935209Sbostic  * Get the backwards scroll limit.
54035209Sbostic  * Must call this function instead of just using the value of
54135209Sbostic  * back_scroll, because the default case depends on sc_height and
54235209Sbostic  * top_scroll, as well as back_scroll.
54335209Sbostic  */
get_back_scroll()54435209Sbostic get_back_scroll()
54535209Sbostic {
54635209Sbostic 	if (back_scroll >= 0)
54735209Sbostic 		return (back_scroll);
54835209Sbostic 	if (top_scroll)
54935209Sbostic 		return (sc_height - 2);
55035209Sbostic 	return (sc_height - 1);
55135209Sbostic }
55235209Sbostic 
55335209Sbostic /*
55435209Sbostic  * Search for the n-th occurence of a specified pattern,
55535209Sbostic  * either forward or backward.
55635209Sbostic  */
search(search_forward,pattern,n,wantmatch)55735209Sbostic search(search_forward, pattern, n, wantmatch)
55835209Sbostic 	register int search_forward;
55935209Sbostic 	register char *pattern;
56035209Sbostic 	register int n;
56135209Sbostic 	int wantmatch;
56235209Sbostic {
56336253Sbostic 	off_t pos, linepos;
56435209Sbostic 	register char *p;
56535209Sbostic 	register char *q;
56635209Sbostic 	int linenum;
56735209Sbostic 	int linematch;
56836253Sbostic #ifdef RECOMP
56935209Sbostic 	char *re_comp();
57035209Sbostic 	char *errmsg;
57135209Sbostic #else
57236253Sbostic #ifdef REGCMP
57335209Sbostic 	char *regcmp();
57435209Sbostic 	static char *cpattern = NULL;
57535209Sbostic #else
57635209Sbostic 	static char lpbuf[100];
57735209Sbostic 	static char *last_pattern = NULL;
57835242Sbostic 	char *strcpy();
57935209Sbostic #endif
58035209Sbostic #endif
58135209Sbostic 
58236253Sbostic 	/*
58336253Sbostic 	 * For a caseless search, convert any uppercase in the pattern to
58436253Sbostic 	 * lowercase.
58536253Sbostic 	 */
58635209Sbostic 	if (caseless && pattern != NULL)
58736253Sbostic 		for (p = pattern;  *p;  p++)
58836253Sbostic 			if (isupper(*p))
58936253Sbostic 				*p = tolower(*p);
59036253Sbostic #ifdef RECOMP
59135209Sbostic 
59235209Sbostic 	/*
59335209Sbostic 	 * (re_comp handles a null pattern internally,
59435209Sbostic 	 *  so there is no need to check for a null pattern here.)
59535209Sbostic 	 */
59635209Sbostic 	if ((errmsg = re_comp(pattern)) != NULL)
59735209Sbostic 	{
59835209Sbostic 		error(errmsg);
59936253Sbostic 		return(0);
60035209Sbostic 	}
60135209Sbostic #else
60236253Sbostic #ifdef REGCMP
60335209Sbostic 	if (pattern == NULL || *pattern == '\0')
60435209Sbostic 	{
60535209Sbostic 		/*
60635209Sbostic 		 * A null pattern means use the previous pattern.
60735209Sbostic 		 * The compiled previous pattern is in cpattern, so just use it.
60835209Sbostic 		 */
60935209Sbostic 		if (cpattern == NULL)
61035209Sbostic 		{
61135209Sbostic 			error("No previous regular expression");
61236253Sbostic 			return(0);
61335209Sbostic 		}
61435209Sbostic 	} else
61535209Sbostic 	{
61635209Sbostic 		/*
61735209Sbostic 		 * Otherwise compile the given pattern.
61835209Sbostic 		 */
61935209Sbostic 		char *s;
62035209Sbostic 		if ((s = regcmp(pattern, 0)) == NULL)
62135209Sbostic 		{
62235209Sbostic 			error("Invalid pattern");
62336253Sbostic 			return(0);
62435209Sbostic 		}
62535209Sbostic 		if (cpattern != NULL)
62635209Sbostic 			free(cpattern);
62735209Sbostic 		cpattern = s;
62835209Sbostic 	}
62935209Sbostic #else
63035209Sbostic 	if (pattern == NULL || *pattern == '\0')
63135209Sbostic 	{
63235209Sbostic 		/*
63335209Sbostic 		 * Null pattern means use the previous pattern.
63435209Sbostic 		 */
63535209Sbostic 		if (last_pattern == NULL)
63635209Sbostic 		{
63735209Sbostic 			error("No previous regular expression");
63836253Sbostic 			return(0);
63935209Sbostic 		}
64035209Sbostic 		pattern = last_pattern;
64135209Sbostic 	} else
64235209Sbostic 	{
64335242Sbostic 		(void)strcpy(lpbuf, pattern);
64435209Sbostic 		last_pattern = lpbuf;
64535209Sbostic 	}
64635209Sbostic #endif
64735209Sbostic #endif
64835209Sbostic 
64935209Sbostic 	/*
65035209Sbostic 	 * Figure out where to start the search.
65135209Sbostic 	 */
65235209Sbostic 
65336253Sbostic 	if (position(TOP) == NULL_POSITION) {
65435209Sbostic 		/*
65536253Sbostic 		 * Nothing is currently displayed.  Start at the beginning
65636253Sbostic 		 * of the file.  (This case is mainly for searches from the
65736253Sbostic 		 * command line.
65835209Sbostic 		 */
65936253Sbostic 		pos = (off_t)0;
66036253Sbostic 	} else if (!search_forward) {
66135209Sbostic 		/*
66235209Sbostic 		 * Backward search: start just before the top line
66335209Sbostic 		 * displayed on the screen.
66435209Sbostic 		 */
66535209Sbostic 		pos = position(TOP);
66636253Sbostic 	} else {
66735209Sbostic 		/*
66835209Sbostic 		 * Start at the second screen line displayed on the screen.
66935209Sbostic 		 */
67035209Sbostic 		pos = position(TOP_PLUS_ONE);
67135209Sbostic 	}
67235209Sbostic 
67335209Sbostic 	if (pos == NULL_POSITION)
67435209Sbostic 	{
67535209Sbostic 		/*
67635209Sbostic 		 * Can't find anyplace to start searching from.
67735209Sbostic 		 */
67835209Sbostic 		error("Nothing to search");
67936253Sbostic 		return(0);
68035209Sbostic 	}
68135209Sbostic 
68235209Sbostic 	linenum = find_linenum(pos);
68335209Sbostic 	for (;;)
68435209Sbostic 	{
68535209Sbostic 		/*
68635209Sbostic 		 * Get lines until we find a matching one or
68735209Sbostic 		 * until we hit end-of-file (or beginning-of-file
68835209Sbostic 		 * if we're going backwards).
68935209Sbostic 		 */
69035209Sbostic 		if (sigs)
69135209Sbostic 			/*
69235209Sbostic 			 * A signal aborts the search.
69335209Sbostic 			 */
69436253Sbostic 			return(0);
69535209Sbostic 
69635209Sbostic 		if (search_forward)
69735209Sbostic 		{
69835209Sbostic 			/*
69935209Sbostic 			 * Read the next line, and save the
70035209Sbostic 			 * starting position of that line in linepos.
70135209Sbostic 			 */
70235209Sbostic 			linepos = pos;
70335209Sbostic 			pos = forw_raw_line(pos);
70435209Sbostic 			if (linenum != 0)
70535209Sbostic 				linenum++;
70635209Sbostic 		} else
70735209Sbostic 		{
70835209Sbostic 			/*
70935209Sbostic 			 * Read the previous line and save the
71035209Sbostic 			 * starting position of that line in linepos.
71135209Sbostic 			 */
71235209Sbostic 			pos = back_raw_line(pos);
71335209Sbostic 			linepos = pos;
71435209Sbostic 			if (linenum != 0)
71535209Sbostic 				linenum--;
71635209Sbostic 		}
71735209Sbostic 
71835209Sbostic 		if (pos == NULL_POSITION)
71935209Sbostic 		{
72035209Sbostic 			/*
72135209Sbostic 			 * We hit EOF/BOF without a match.
72235209Sbostic 			 */
72335209Sbostic 			error("Pattern not found");
72436253Sbostic 			return(0);
72535209Sbostic 		}
72635209Sbostic 
72735209Sbostic 		/*
72835209Sbostic 		 * If we're using line numbers, we might as well
72935209Sbostic 		 * remember the information we have now (the position
73035209Sbostic 		 * and line number of the current line).
73135209Sbostic 		 */
73235209Sbostic 		if (linenums)
73335209Sbostic 			add_lnum(linenum, pos);
73435209Sbostic 
73536253Sbostic 		/*
73636253Sbostic 		 * If this is a caseless search, convert uppercase in the
73736253Sbostic 		 * input line to lowercase.
73836253Sbostic 		 */
73935209Sbostic 		if (caseless)
74036253Sbostic 			for (p = q = line;  *p;  p++, q++)
74136253Sbostic 				*q = isupper(*p) ? tolower(*p) : *p;
74235209Sbostic 
74335209Sbostic 		/*
74436253Sbostic 		 * Remove any backspaces along with the preceeding char.
74536253Sbostic 		 * This allows us to match text which is underlined or
74636253Sbostic 		 * overstruck.
74736253Sbostic 		 */
74836253Sbostic 		for (p = q = line;  *p;  p++, q++)
74936253Sbostic 			if (q > line && *p == '\b')
75036253Sbostic 				/* Delete BS and preceeding char. */
75136253Sbostic 				q -= 2;
75236253Sbostic 			else
75336253Sbostic 				/* Otherwise, just copy. */
75436253Sbostic 				*q = *p;
75536253Sbostic 
75636253Sbostic 		/*
75735209Sbostic 		 * Test the next line to see if we have a match.
75835209Sbostic 		 * This is done in a variety of ways, depending
75935209Sbostic 		 * on what pattern matching functions are available.
76035209Sbostic 		 */
76136253Sbostic #ifdef REGCMP
76235209Sbostic 		linematch = (regex(cpattern, line) != NULL);
76335209Sbostic #else
76436253Sbostic #ifdef RECOMP
76535209Sbostic 		linematch = (re_exec(line) == 1);
76635209Sbostic #else
76735209Sbostic 		linematch = match(pattern, line);
76835209Sbostic #endif
76935209Sbostic #endif
77035209Sbostic 		/*
77135209Sbostic 		 * We are successful if wantmatch and linematch are
77235209Sbostic 		 * both true (want a match and got it),
77335209Sbostic 		 * or both false (want a non-match and got it).
77435209Sbostic 		 */
77535209Sbostic 		if (((wantmatch && linematch) || (!wantmatch && !linematch)) &&
77635209Sbostic 		      --n <= 0)
77735209Sbostic 			/*
77835209Sbostic 			 * Found the line.
77935209Sbostic 			 */
78035209Sbostic 			break;
78135209Sbostic 	}
78235209Sbostic 	jump_loc(linepos);
78336253Sbostic 	return(1);
78435209Sbostic }
78535209Sbostic 
78636253Sbostic #if !defined(REGCMP) && !defined(RECOMP)
78735209Sbostic /*
78835209Sbostic  * We have neither regcmp() nor re_comp().
78935209Sbostic  * We use this function to do simple pattern matching.
79035209Sbostic  * It supports no metacharacters like *, etc.
79135209Sbostic  */
79236253Sbostic static
match(pattern,buf)79335209Sbostic match(pattern, buf)
79435209Sbostic 	char *pattern, *buf;
79535209Sbostic {
79635209Sbostic 	register char *pp, *lp;
79735209Sbostic 
79835209Sbostic 	for ( ;  *buf != '\0';  buf++)
79935209Sbostic 	{
80035209Sbostic 		for (pp = pattern, lp = buf;  *pp == *lp;  pp++, lp++)
80135209Sbostic 			if (*pp == '\0' || *lp == '\0')
80235209Sbostic 				break;
80335209Sbostic 		if (*pp == '\0')
80435209Sbostic 			return (1);
80535209Sbostic 	}
80635209Sbostic 	return (0);
80735209Sbostic }
80835209Sbostic #endif
809